2009-05-05 17:36:48 +02:00
|
|
|
/*
|
|
|
|
* UAE - The U*nix Amiga Emulator
|
|
|
|
*
|
|
|
|
* Picasso96 Support Module
|
|
|
|
*
|
|
|
|
* Copyright 1997-2001 Brian King <Brian_King@Mitel.com, Brian_King@Cloanto.com>
|
|
|
|
* Copyright 2000-2001 Bernd Roesch
|
|
|
|
* Copyright 2003-2005 Richard Drummond
|
|
|
|
*
|
|
|
|
* Theory of operation:
|
|
|
|
* On the Amiga side, a Picasso card consists mainly of a memory area that
|
|
|
|
* contains the frame buffer. On the UAE side, we allocate a block of memory
|
|
|
|
* that will hold the frame buffer. This block is in normal memory, it is
|
|
|
|
* never directly on the graphics card. All graphics operations, which are
|
|
|
|
* mainly reads and writes into this block and a few basic operations like
|
|
|
|
* filling a rectangle, operate on this block of memory.
|
|
|
|
* Since the memory is not on the graphics card, some work must be done to
|
|
|
|
* synchronize the display with the data in the Picasso frame buffer. There
|
|
|
|
* are various ways to do this. One possibility is to allocate a second
|
|
|
|
* buffer of the same size, and perform all write operations twice. Since
|
|
|
|
* we never read from the second buffer, it can actually be placed in video
|
|
|
|
* memory. The X11 driver could be made to use the Picasso frame buffer as
|
|
|
|
* the data buffer of an XImage, which could then be XPutImage()d from time
|
|
|
|
* to time. Another possibility is to translate all Picasso accesses into
|
|
|
|
* Xlib (or GDI, or whatever your graphics system is) calls. This possibility
|
|
|
|
* is a bit tricky, since there is a risk of generating very many single pixel
|
|
|
|
* accesses which may be rather slow.
|
|
|
|
*
|
|
|
|
* TODO:
|
|
|
|
* - we want to add a manual switch to override SetSwitch for hardware banging
|
|
|
|
* programs started from a Picasso workbench.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "sysconfig.h"
|
|
|
|
#include "sysdeps.h"
|
|
|
|
|
|
|
|
#include "options.h"
|
|
|
|
#include "uae.h"
|
|
|
|
#include "memory.h"
|
|
|
|
#include "custom.h"
|
|
|
|
#include "newcpu.h"
|
|
|
|
#include "xwin.h"
|
|
|
|
#include "picasso96.h"
|
|
|
|
#include "uae_endian.h"
|
|
|
|
|
|
|
|
#ifdef JIT
|
|
|
|
int have_done_picasso = 0; /* For the JIT compiler */
|
|
|
|
# ifdef PICASSO96
|
|
|
|
static int picasso_is_special = PIC_WRITE; /* ditto */
|
|
|
|
static int picasso_is_special_read = PIC_READ; /* ditto */
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef PICASSO96
|
|
|
|
|
|
|
|
static int p96syncrate;
|
|
|
|
int p96hsync_counter;
|
|
|
|
|
|
|
|
int p96hack_vpos, p96hack_vpos2, p96refresh_active;
|
|
|
|
|
|
|
|
#define P96TRACING_ENABLED 0
|
|
|
|
#if P96TRACING_ENABLED
|
|
|
|
#define P96TRACE(x) do { write_log x; } while(0)
|
|
|
|
#else
|
|
|
|
#define P96TRACE(x) do { ; } while(0)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static uae_u32 gfxmem_lget (uaecptr) REGPARAM;
|
|
|
|
static uae_u32 gfxmem_wget (uaecptr) REGPARAM;
|
|
|
|
static uae_u32 gfxmem_bget (uaecptr) REGPARAM;
|
|
|
|
static void gfxmem_lput (uaecptr, uae_u32) REGPARAM;
|
|
|
|
static void gfxmem_wput (uaecptr, uae_u32) REGPARAM;
|
|
|
|
static void gfxmem_bput (uaecptr, uae_u32) REGPARAM;
|
|
|
|
static int gfxmem_check (uaecptr addr, uae_u32 size) REGPARAM;
|
|
|
|
static uae_u8 *gfxmem_xlate (uaecptr addr) REGPARAM;
|
|
|
|
|
|
|
|
static uae_u8 all_ones_bitmap, all_zeros_bitmap;
|
|
|
|
|
|
|
|
struct picasso96_state_struct picasso96_state;
|
|
|
|
struct picasso_vidbuf_description picasso_vidinfo;
|
|
|
|
|
|
|
|
/* These are the maximum resolutions. They are filled in by
|
|
|
|
* GetSupportedResolutions() */
|
|
|
|
/* have to fill this in, otherwise problems occur
|
|
|
|
* @@@ ??? what problems?
|
|
|
|
*/
|
|
|
|
struct ScreenResolution planar = { 320, 240 };
|
|
|
|
struct ScreenResolution chunky = { 640, 480 };
|
|
|
|
struct ScreenResolution hicolour = { 640, 480 };
|
|
|
|
struct ScreenResolution truecolour = { 640, 480 };
|
|
|
|
struct ScreenResolution alphacolour = { 640, 480 };
|
|
|
|
|
|
|
|
uae_u16 picasso96_pixel_format = RGBFF_CHUNKY;
|
|
|
|
|
|
|
|
struct PicassoResolution DisplayModes[MAX_PICASSO_MODES];
|
|
|
|
|
|
|
|
static int mode_count = 0;
|
|
|
|
|
|
|
|
static int set_gc_called = 0;
|
|
|
|
static int set_panning_called = 0;
|
|
|
|
/* Address of the screen in the Amiga frame buffer at the time of the last
|
|
|
|
SetPanning call. */
|
|
|
|
//static uaecptr oldscr;
|
|
|
|
|
|
|
|
static uae_u32 p2ctab[256][2];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Picasso96 seems to have a bug which screws the palette emulation in
|
|
|
|
* ARGB32 modes. We work around this by using a BGRA32 framebuffer instead,
|
|
|
|
* and byte-swapping each pixel when output to the real screen
|
|
|
|
*/
|
|
|
|
static int need_argb32_hack = 0;
|
|
|
|
|
|
|
|
/* This stuff should probably be moved elsewhere */
|
|
|
|
#if (defined __powerpc__ || defined __ppc__ || defined __POWERPC__ \
|
|
|
|
|| defined __PPC__) && defined __GNUC__
|
|
|
|
STATIC_INLINE void memcpy_bswap32 (void *dst, void *src, int n)
|
|
|
|
{
|
|
|
|
int words = n / 4;
|
|
|
|
|
|
|
|
if (words > 1) {
|
|
|
|
uae_u32 tmp;
|
|
|
|
asm volatile (
|
|
|
|
"addi %2, %2, -1 \n\
|
|
|
|
mtctr %2 \n\
|
|
|
|
lwz %3, 0(%1) \n\
|
|
|
|
1: stwbrx %3, 0, %0 \n\
|
|
|
|
addi %0, %0, 4 \n\
|
|
|
|
lwzu %3, 4(%1) \n\
|
|
|
|
bdnz 1b \n\
|
|
|
|
stwbrx %3, 0, %0"
|
|
|
|
: "+r" (dst), "+r" (src), "+r" (words), "=r" (tmp)
|
|
|
|
:
|
|
|
|
: "ctr", "memory");
|
|
|
|
} else {
|
|
|
|
uae_u32 tmp;
|
|
|
|
asm volatile (
|
|
|
|
"lwz %2, 0(%1) \n\
|
|
|
|
stwbrx %2, 0, %0"
|
|
|
|
: "+r" (dst), "+r" (src), "=r" (tmp)
|
|
|
|
:
|
|
|
|
: "memory");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
STATIC_INLINE void memcpy_bswap32 (void *dst, void *src, int n)
|
|
|
|
{
|
|
|
|
int i = n / 4;
|
|
|
|
uae_u32 *dstp = (uae_u32 *)dst;
|
|
|
|
uae_u32 *srcp = (uae_u32 *)src;
|
|
|
|
for ( ; i; i--)
|
|
|
|
*dstp++ = bswap_32 (*srcp++);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Debugging dumps
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void DumpModeInfoStructure (uaecptr amigamodeinfoptr)
|
|
|
|
{
|
|
|
|
write_log ("ModeInfo Structure Dump:\n");
|
|
|
|
write_log (" Node.ln_Succ = 0x%x\n", get_long (amigamodeinfoptr));
|
|
|
|
write_log (" Node.ln_Pred = 0x%x\n", get_long (amigamodeinfoptr + 4));
|
|
|
|
write_log (" Node.ln_Type = 0x%x\n", get_byte (amigamodeinfoptr + 8));
|
|
|
|
write_log (" Node.ln_Pri = %d\n", get_byte (amigamodeinfoptr + 9));
|
|
|
|
/*write_log (" Node.ln_Name = %s\n", uaememptr->Node.ln_Name); */
|
|
|
|
write_log (" OpenCount = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_OpenCount));
|
|
|
|
write_log (" Active = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_Active));
|
|
|
|
write_log (" Width = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_Width));
|
|
|
|
write_log (" Height = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_Height));
|
|
|
|
write_log (" Depth = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_Depth));
|
|
|
|
write_log (" Flags = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_Flags));
|
|
|
|
write_log (" HorTotal = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorTotal));
|
|
|
|
write_log (" HorBlankSize = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorBlankSize));
|
|
|
|
write_log (" HorSyncStart = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorSyncStart));
|
|
|
|
write_log (" HorSyncSize = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorSyncSize));
|
|
|
|
write_log (" HorSyncSkew = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_HorSyncSkew));
|
|
|
|
write_log (" HorEnableSkew = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_HorEnableSkew));
|
|
|
|
write_log (" VerTotal = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerTotal));
|
|
|
|
write_log (" VerBlankSize = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerBlankSize));
|
|
|
|
write_log (" VerSyncStart = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerSyncStart));
|
|
|
|
write_log (" VerSyncSize = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerSyncSize));
|
|
|
|
write_log (" Clock = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_first_union));
|
|
|
|
write_log (" ClockDivide = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_second_union));
|
|
|
|
write_log (" PixelClock = %d\n", get_long (amigamodeinfoptr + PSSO_ModeInfo_PixelClock));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void DumpLibResolutionStructure (uaecptr amigalibresptr)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
uaecptr amigamodeinfoptr;
|
|
|
|
struct LibResolution *uaememptr = (struct LibResolution *)
|
|
|
|
get_mem_bank (amigalibresptr).xlateaddr (amigalibresptr);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
write_log ("LibResolution Structure Dump:\n");
|
|
|
|
|
|
|
|
if (get_long (amigalibresptr + PSSO_LibResolution_DisplayID) == 0xFFFFFFFF) {
|
|
|
|
write_log (" Finished With LibResolutions...\n");
|
|
|
|
} else {
|
|
|
|
write_log (" Name = %s\n", uaememptr->P96ID);
|
|
|
|
write_log (" DisplayID = 0x%x\n", get_long (amigalibresptr + PSSO_LibResolution_DisplayID));
|
|
|
|
write_log (" Width = %d\n", get_word (amigalibresptr + PSSO_LibResolution_Width));
|
|
|
|
write_log (" Height = %d\n", get_word (amigalibresptr + PSSO_LibResolution_Height));
|
|
|
|
write_log (" Flags = %d\n", get_word (amigalibresptr + PSSO_LibResolution_Flags));
|
|
|
|
for (i = 0; i < MAXMODES; i++) {
|
|
|
|
amigamodeinfoptr = get_long (amigalibresptr + PSSO_LibResolution_Modes + i * 4);
|
|
|
|
write_log (" ModeInfo[%d] = 0x%x\n", i, amigamodeinfoptr);
|
|
|
|
if (amigamodeinfoptr)
|
|
|
|
DumpModeInfoStructure (amigamodeinfoptr);
|
|
|
|
}
|
|
|
|
write_log (" BoardInfo = 0x%x\n", get_long (amigalibresptr + PSSO_LibResolution_BoardInfo));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static char binary_byte[9];
|
|
|
|
|
|
|
|
static char *BuildBinaryString (uae_u8 value)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
binary_byte[i] = (value & (1 << (7 - i))) ? '#' : '.';
|
|
|
|
}
|
|
|
|
binary_byte[8] = '\0';
|
|
|
|
return binary_byte;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void DumpPattern (struct Pattern *patt)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
uae_u8 *mem;
|
|
|
|
int row, col;
|
|
|
|
for (row = 0; row < (1 << patt->Size); row++) {
|
|
|
|
mem = patt->Memory + row * 2;
|
|
|
|
for (col = 0; col < 2; col++) {
|
|
|
|
write_log ("%s", BuildBinaryString (*mem++));
|
|
|
|
}
|
|
|
|
write_log ("\n");
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
static void DumpTemplate (struct Template *tmp, uae_u16 w, uae_u16 h)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
uae_u8 *mem = tmp->Memory;
|
|
|
|
int row, col, width;
|
|
|
|
width = (w + 7) >> 3;
|
|
|
|
write_log ("xoffset = %d, bpr = %d\n", tmp->XOffset, tmp->BytesPerRow);
|
|
|
|
for (row = 0; row < h; row++) {
|
|
|
|
mem = tmp->Memory + row * tmp->BytesPerRow;
|
|
|
|
for (col = 0; col < width; col++) {
|
|
|
|
write_log ("%s", BuildBinaryString (*mem++));
|
|
|
|
}
|
|
|
|
write_log ("\n");
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
int picasso_nr_resolutions (void)
|
|
|
|
{
|
|
|
|
return mode_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ShowSupportedResolutions (void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i = 0; i < mode_count; i++)
|
|
|
|
write_log ("%s\n", DisplayModes[i].name);
|
|
|
|
}
|
|
|
|
|
|
|
|
STATIC_INLINE uae_u8 GetBytesPerPixel (uae_u32 RGBfmt)
|
|
|
|
{
|
|
|
|
switch (RGBfmt) {
|
|
|
|
case RGBFB_CLUT:
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
case RGBFB_A8R8G8B8:
|
|
|
|
case RGBFB_A8B8G8R8:
|
|
|
|
case RGBFB_R8G8B8A8:
|
|
|
|
case RGBFB_B8G8R8A8:
|
|
|
|
return 4;
|
|
|
|
|
|
|
|
case RGBFB_B8G8R8:
|
|
|
|
case RGBFB_R8G8B8:
|
|
|
|
return 3;
|
|
|
|
|
|
|
|
case RGBFB_R5G5B5:
|
|
|
|
case RGBFB_R5G6B5:
|
|
|
|
case RGBFB_R5G6B5PC:
|
|
|
|
case RGBFB_R5G5B5PC:
|
|
|
|
case RGBFB_B5G6R5PC:
|
|
|
|
case RGBFB_B5G5R5PC:
|
|
|
|
return 2;
|
|
|
|
default:
|
|
|
|
P96TRACE (("P96: ERROR - GetBytesPerPixel() was unsuccessful with 0x%x?!\n", RGBfmt));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Amiga <-> native structure conversion functions
|
|
|
|
*/
|
|
|
|
static int CopyRenderInfoStructureA2U (uaecptr amigamemptr,
|
|
|
|
struct RenderInfo *ri)
|
|
|
|
{
|
|
|
|
uaecptr memp = get_long (amigamemptr + PSSO_RenderInfo_Memory);
|
|
|
|
|
|
|
|
if (valid_address (memp, PSSO_RenderInfo_sizeof)) {
|
|
|
|
ri->AMemory = memp;
|
|
|
|
ri->Memory = get_real_address (memp);
|
|
|
|
ri->BytesPerRow = get_word (amigamemptr + PSSO_RenderInfo_BytesPerRow);
|
|
|
|
ri->RGBFormat = get_long (amigamemptr + PSSO_RenderInfo_RGBFormat);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
write_log ("P96: ERROR - Invalid RenderInfo memory area.\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int CopyPatternStructureA2U (uaecptr amigamemptr,
|
|
|
|
struct Pattern *pattern)
|
|
|
|
{
|
|
|
|
uaecptr memp = get_long (amigamemptr + PSSO_Pattern_Memory);
|
|
|
|
|
|
|
|
if (valid_address (memp, PSSO_Pattern_sizeof)) {
|
|
|
|
pattern->Memory = get_real_address (memp);
|
|
|
|
pattern->XOffset = get_word (amigamemptr + PSSO_Pattern_XOffset);
|
|
|
|
pattern->YOffset = get_word (amigamemptr + PSSO_Pattern_YOffset);
|
|
|
|
pattern->FgPen = get_long (amigamemptr + PSSO_Pattern_FgPen);
|
|
|
|
pattern->BgPen = get_long (amigamemptr + PSSO_Pattern_BgPen);
|
|
|
|
pattern->Size = get_byte (amigamemptr + PSSO_Pattern_Size);
|
|
|
|
pattern->DrawMode = get_byte (amigamemptr + PSSO_Pattern_DrawMode);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
write_log ("P96: ERROR - Invalid Pattern memory area.\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void CopyColorIndexMappingA2U (uaecptr amigamemptr,
|
|
|
|
struct ColorIndexMapping *cim)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
cim->ColorMask = get_long (amigamemptr);
|
|
|
|
for (i = 0; i < 256; i++, amigamemptr += 4)
|
|
|
|
cim->Colors[i] = get_long (amigamemptr + 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int CopyBitMapStructureA2U (uaecptr amigamemptr, struct BitMap *bm)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
bm->BytesPerRow = get_word (amigamemptr + PSSO_BitMap_BytesPerRow);
|
|
|
|
bm->Rows = get_word (amigamemptr + PSSO_BitMap_Rows);
|
|
|
|
bm->Flags = get_byte (amigamemptr + PSSO_BitMap_Flags);
|
|
|
|
bm->Depth = get_byte (amigamemptr + PSSO_BitMap_Depth);
|
|
|
|
|
|
|
|
if (bm->Depth > 8) {
|
|
|
|
write_log ("P96: WARNING - Can't handle %d-bit deep bitmap\n",
|
|
|
|
bm->Depth);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < bm->Depth; i++) {
|
|
|
|
uaecptr plane = get_long (amigamemptr + PSSO_BitMap_Planes + i * 4);
|
|
|
|
switch (plane) {
|
|
|
|
case 0:
|
|
|
|
bm->Planes[i] = &all_zeros_bitmap;
|
|
|
|
break;
|
|
|
|
case 0xFFFFFFFF:
|
|
|
|
bm->Planes[i] = &all_ones_bitmap;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (valid_address (plane, bm->BytesPerRow * bm->Rows))
|
|
|
|
bm->Planes[i] = get_real_address (plane);
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int CopyTemplateStructureA2U (uaecptr amigamemptr,
|
|
|
|
struct Template *tmpl)
|
|
|
|
{
|
|
|
|
uaecptr memp = get_long (amigamemptr + PSSO_Template_Memory);
|
|
|
|
|
|
|
|
if (valid_address (memp, 1 /* FIXME */ )) {
|
|
|
|
tmpl->Memory = get_real_address (memp);
|
|
|
|
tmpl->BytesPerRow = get_word (amigamemptr + PSSO_Template_BytesPerRow);
|
|
|
|
tmpl->XOffset = get_byte (amigamemptr + PSSO_Template_XOffset);
|
|
|
|
tmpl->DrawMode = get_byte (amigamemptr + PSSO_Template_DrawMode);
|
|
|
|
tmpl->FgPen = get_long (amigamemptr + PSSO_Template_FgPen);
|
|
|
|
tmpl->BgPen = get_long (amigamemptr + PSSO_Template_BgPen);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
write_log ("P96: ERROR - Invalid Template memory area.\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void CopyLibResolutionStructureU2A (struct LibResolution *libres,
|
|
|
|
uaecptr amigamemptr)
|
|
|
|
{
|
|
|
|
uae_u8 *uaememptr = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* I know that amigamemptr is inside my gfxmem chunk, so I can just
|
|
|
|
* do the xlate() */
|
|
|
|
uaememptr = gfxmem_xlate (amigamemptr);
|
|
|
|
|
|
|
|
/* zero out our LibResolution structure */
|
|
|
|
memset (uaememptr, 0, PSSO_LibResolution_sizeof);
|
|
|
|
|
|
|
|
strcpy ((char*)uaememptr + PSSO_LibResolution_P96ID, libres->P96ID);
|
|
|
|
put_long (amigamemptr + PSSO_LibResolution_DisplayID, libres->DisplayID);
|
|
|
|
put_word (amigamemptr + PSSO_LibResolution_Width, libres->Width);
|
|
|
|
put_word (amigamemptr + PSSO_LibResolution_Height, libres->Height);
|
|
|
|
put_word (amigamemptr + PSSO_LibResolution_Flags, libres->Flags);
|
|
|
|
for (i = 0; i < MAXMODES; i++)
|
|
|
|
put_long (amigamemptr + PSSO_LibResolution_Modes + i * 4, libres->Modes[i]);
|
|
|
|
#if 0
|
|
|
|
put_long (amigamemptr, libres->Node.ln_Succ);
|
|
|
|
put_long (amigamemptr + 4, libres->Node.ln_Pred);
|
|
|
|
put_byte (amigamemptr + 8, libres->Node.ln_Type);
|
|
|
|
put_byte (amigamemptr + 9, libres->Node.ln_Pri);
|
|
|
|
#endif
|
|
|
|
put_long (amigamemptr + 10, amigamemptr + PSSO_LibResolution_P96ID);
|
|
|
|
put_long (amigamemptr + PSSO_LibResolution_BoardInfo, libres->BoardInfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* l is Amiga address of list, in correct endian format for UAE
|
|
|
|
* n is Amiga address of node, in correct endian format for UAE */
|
|
|
|
static void AmigaListAddTail (uaecptr l, uaecptr n)
|
|
|
|
{
|
|
|
|
put_long (n + 0, l + 4); // n->ln_Succ = (struct Node *)&l->lh_Tail;
|
|
|
|
put_long (n + 4, get_long (l + 8)); // n->ln_Pred = l->lh_TailPred;
|
|
|
|
put_long (get_long (l + 8) + 0, n); // l->lh_TailPred->ln_Succ = n;
|
|
|
|
put_long (l + 8, n); // l->lh_TailPred = n;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Functions to perform an action on the real screen
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fill a rectangle on the screen. src points to the start of a line of the
|
|
|
|
* filled rectangle in the frame buffer; it can be used as a memcpy source if
|
|
|
|
* there is no OS specific function to fill the rectangle.
|
|
|
|
*/
|
|
|
|
static void do_fillrect (uae_u8 *src, int x, int y, int width, int height,
|
|
|
|
uae_u32 pen, int Bpp, RGBFTYPE rgbtype)
|
|
|
|
{
|
|
|
|
uae_u8 *dst;
|
|
|
|
|
|
|
|
P96TRACE (("P96: do_fillrect (src:%08x x:%d y:%d w:%d h%d pen:%08x)\n",
|
|
|
|
src, x, y, width, height, pen));
|
|
|
|
|
|
|
|
/* Try OS specific fillrect function here; and return if successful. Make
|
|
|
|
* sure we adjust for the pen values if we're doing 8-bit
|
|
|
|
* display-emulation on a 16-bit or higher screen. */
|
|
|
|
if (picasso_vidinfo.rgbformat == picasso96_state.RGBFormat) {
|
|
|
|
# ifndef WORDS_BIGENDIAN
|
2014-01-25 12:19:44 +01:00
|
|
|
if (Bpp > 1)
|
|
|
|
if (!(Bpp == 4 && need_argb32_hack))
|
2009-05-05 17:36:48 +02:00
|
|
|
pen = bswap_32 (pen);
|
|
|
|
# else
|
|
|
|
if (Bpp == 4 && need_argb32_hack)
|
|
|
|
pen = bswap_32 (pen);
|
|
|
|
# endif
|
|
|
|
|
|
|
|
if (DX_Fill (x, y, width, height, pen, rgbtype))
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
if (DX_Fill (x, y, width, height, picasso_vidinfo.clut[src[0]], rgbtype))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
P96TRACE (("P96: WARNING - do_fillrect() using fall-back routine!\n"));
|
|
|
|
|
|
|
|
DX_Invalidate (y, y + height - 1);
|
|
|
|
if (!picasso_vidinfo.extra_mem)
|
|
|
|
return;
|
|
|
|
|
|
|
|
width *= picasso96_state.BytesPerPixel;
|
|
|
|
dst = gfx_lock_picasso ();
|
|
|
|
if (!dst)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
dst += y * picasso_vidinfo.rowbytes + x * picasso_vidinfo.pixbytes;
|
|
|
|
if (picasso_vidinfo.rgbformat == picasso96_state.RGBFormat) {
|
|
|
|
if (Bpp == 1) {
|
|
|
|
while (height-- > 0) {
|
|
|
|
memset (dst, pen, width);
|
|
|
|
dst += picasso_vidinfo.rowbytes;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (Bpp == 4 && need_argb32_hack) {
|
|
|
|
while (height-- > 0) {
|
|
|
|
memcpy_bswap32 (dst, src, width);
|
|
|
|
dst += picasso_vidinfo.rowbytes;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
while (height-- > 0) {
|
|
|
|
memcpy (dst, src, width);
|
|
|
|
dst += picasso_vidinfo.rowbytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
int psiz = GetBytesPerPixel (picasso_vidinfo.rgbformat);
|
|
|
|
if (picasso96_state.RGBFormat != RGBFB_CHUNKY)
|
|
|
|
abort ();
|
|
|
|
|
|
|
|
while (height-- > 0) {
|
|
|
|
int i;
|
|
|
|
switch (psiz) {
|
|
|
|
case 2:
|
|
|
|
for (i = 0; i < width; i++)
|
|
|
|
*((uae_u16 *) dst + i) = picasso_vidinfo.clut[src[i]];
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
for (i = 0; i < width; i++)
|
|
|
|
*((uae_u32 *) dst + i) = picasso_vidinfo.clut[src[i]];
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
abort ();
|
|
|
|
}
|
|
|
|
dst += picasso_vidinfo.rowbytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
gfx_unlock_picasso ();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This routine modifies the real screen buffer after a blit has been
|
|
|
|
* performed in the save area. If can_do_blit is nonzero, the blit can
|
|
|
|
* be performed within the real screen buffer; otherwise, this routine
|
|
|
|
* must do it by hand using the data in the save area, pointed to by
|
|
|
|
* srcp.
|
|
|
|
*/
|
|
|
|
static void do_blit (struct RenderInfo *ri, int Bpp, int srcx, int srcy,
|
|
|
|
int dstx, int dsty, int width, int height,
|
|
|
|
BLIT_OPCODE opcode, int can_do_blit)
|
|
|
|
{
|
|
|
|
int xoff = picasso96_state.XOffset;
|
|
|
|
int yoff = picasso96_state.YOffset;
|
|
|
|
uae_u8 *srcp, *dstp;
|
|
|
|
|
|
|
|
/* Clipping. */
|
|
|
|
dstx -= xoff;
|
|
|
|
dsty -= yoff;
|
|
|
|
if (srcy < yoff || srcx < xoff
|
|
|
|
|| srcx - xoff + width > picasso96_state.Width
|
|
|
|
|| srcy - yoff + height > picasso96_state.Height)
|
|
|
|
{
|
|
|
|
can_do_blit = 0;
|
|
|
|
}
|
|
|
|
if (dstx < 0) {
|
|
|
|
srcx -= dstx;
|
|
|
|
width += dstx;
|
|
|
|
dstx = 0;
|
|
|
|
}
|
|
|
|
if (dsty < 0) {
|
|
|
|
srcy -= dsty;
|
|
|
|
height += dsty;
|
|
|
|
dsty = 0;
|
|
|
|
}
|
|
|
|
if (dstx + width > picasso96_state.Width)
|
|
|
|
width = picasso96_state.Width - dstx;
|
|
|
|
if (dsty + height > picasso96_state.Height)
|
|
|
|
height = picasso96_state.Height - dsty;
|
|
|
|
if (width <= 0 || height <= 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* If this RenderInfo points at something else than the currently visible
|
|
|
|
* screen, we must ignore the blit. */
|
|
|
|
if (can_do_blit) {
|
|
|
|
/*
|
|
|
|
* Call OS blitting function that can do it in video memory.
|
|
|
|
* Should return if it was successful
|
|
|
|
*/
|
2014-01-25 12:19:44 +01:00
|
|
|
if (DX_Blit (srcx, srcy, dstx, dsty, width, height, opcode))
|
2009-05-05 17:36:48 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If no OS blit available, we do a copy from the P96 framebuffer in Amiga
|
|
|
|
memory to the host's frame buffer. */
|
|
|
|
|
|
|
|
DX_Invalidate (dsty, dsty + height - 1);
|
|
|
|
if (!picasso_vidinfo.extra_mem)
|
|
|
|
return;
|
|
|
|
|
|
|
|
dstp = gfx_lock_picasso ();
|
|
|
|
if (dstp == 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
/* Since the blit has already been performed in the framebuffer, we only need
|
|
|
|
* to blit the updated area to the screen. Therefore we use the destination
|
|
|
|
* coordinates for the source rectangle in the framebuffer - not the source
|
|
|
|
* coordinates.
|
|
|
|
*/
|
|
|
|
srcp = ri->Memory + (dstx + xoff) * Bpp + (dsty + yoff) * ri->BytesPerRow;
|
|
|
|
|
|
|
|
dstp += dsty * picasso_vidinfo.rowbytes + dstx * picasso_vidinfo.pixbytes;
|
|
|
|
|
|
|
|
P96TRACE (("P96: do_blit with srcp 0x%x, dstp 0x%x, dst_rowbytes %d, srcx"
|
|
|
|
" %d, srcy %d, dstx %d, dsty %d, w %d, h %d, dst_pixbytes %d\n",
|
|
|
|
srcp, dstp, picasso_vidinfo.rowbytes, srcx, srcy, dstx, dsty,
|
|
|
|
width,height, picasso_vidinfo.pixbytes));
|
|
|
|
P96TRACE (("P96: gfxmem is at 0x%x\n", gfxmemory));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (picasso_vidinfo.rgbformat == picasso96_state.RGBFormat) {
|
|
|
|
width *= Bpp;
|
|
|
|
if (Bpp == 4 && need_argb32_hack) {
|
|
|
|
while (height-- > 0) {
|
|
|
|
memcpy_bswap32 (dstp, srcp, width);
|
|
|
|
srcp += ri->BytesPerRow;
|
|
|
|
dstp += picasso_vidinfo.rowbytes;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
while (height-- > 0) {
|
|
|
|
memcpy (dstp, srcp, width);
|
|
|
|
srcp += ri->BytesPerRow;
|
|
|
|
dstp += picasso_vidinfo.rowbytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
int psiz = GetBytesPerPixel (picasso_vidinfo.rgbformat);
|
|
|
|
if (picasso96_state.RGBFormat != RGBFB_CHUNKY)
|
|
|
|
abort ();
|
|
|
|
|
|
|
|
while (height-- > 0) {
|
|
|
|
int i;
|
|
|
|
switch (psiz) {
|
|
|
|
case 2:
|
|
|
|
for (i = 0; i < width; i++)
|
|
|
|
*((uae_u16 *) dstp + i) = picasso_vidinfo.clut[srcp[i]];
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
for (i = 0; i < width; i++)
|
|
|
|
*((uae_u32 *) dstp + i) = picasso_vidinfo.clut[srcp[i]];
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
abort ();
|
|
|
|
}
|
|
|
|
srcp += ri->BytesPerRow;
|
|
|
|
dstp += picasso_vidinfo.rowbytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
gfx_unlock_picasso ();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Invert a rectangle on the screen.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void do_invertrect (struct RenderInfo *ri, int Bpp, int x, int y,
|
|
|
|
int width, int height)
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
/* Clipping. */
|
|
|
|
x -= picasso96_state.XOffset;
|
|
|
|
y -= picasso96_state.YOffset;
|
|
|
|
if (x < 0) {
|
|
|
|
width += x;
|
|
|
|
x = 0;
|
|
|
|
}
|
|
|
|
if (y < 0) {
|
|
|
|
height += y;
|
|
|
|
y = 0;
|
|
|
|
}
|
|
|
|
if (x + width > picasso96_state.Width)
|
|
|
|
width = picasso96_state.Width - x;
|
|
|
|
if (y + height > picasso96_state.Height)
|
|
|
|
height = picasso96_state.Height - y;
|
|
|
|
|
|
|
|
if (width <= 0 || height <= 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
/* TODO: Try OS specific invertrect function here; and return if successful. */
|
|
|
|
|
|
|
|
do_blit (ri, Bpp, x, y, x, y, width, height, BLIT_SRC, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Successive writes to the P96 framebuffer frequently occur in the same line. We
|
|
|
|
* optimize for this case by not flushing each write immediately to the screen.
|
|
|
|
* Instead, we delay until data is written to a different framebuffer line.
|
|
|
|
* Then we flush the line containing the previous data written.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* When successive writes to the framebuffer occur on the same line, we need to
|
|
|
|
* remember these details about that line. Note: these are address in Amiga
|
|
|
|
* memory space.
|
|
|
|
*/
|
|
|
|
static uaecptr currline_start; /* start address of the line in the framebuffer */
|
|
|
|
static uaecptr currline_end; /* end address of the line in the framebuffer plus one */
|
|
|
|
static uaecptr currline_min; /* address of the left-most byte modified */
|
|
|
|
static uaecptr currline_max; /* address of the right-most byte modfied plus one */
|
|
|
|
static int currline_y; /* row number of this line */
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write line from the framebuffer to the screen
|
|
|
|
*
|
|
|
|
* scrp = Pointer to first byte in the source line to write
|
|
|
|
* line_no = Number of line to write (relative to visible screen).
|
|
|
|
* first_byte = Offset in bytes from start of line to first byte to write.
|
|
|
|
* byte_count = Number of bytes to write from source line.
|
|
|
|
*/
|
|
|
|
STATIC_INLINE void write_currline (uae_u8 *srcp, int line_no, int first_byte, int byte_count)
|
|
|
|
{
|
|
|
|
uae_u8 *dstp;
|
|
|
|
|
|
|
|
if ((dstp = gfx_lock_picasso ()) != 0) {
|
|
|
|
int Bpp = GetBytesPerPixel (picasso_vidinfo.rgbformat);
|
|
|
|
|
|
|
|
if (picasso_vidinfo.rgbformat == picasso96_state.RGBFormat) {
|
|
|
|
dstp += line_no * picasso_vidinfo.rowbytes + first_byte;
|
|
|
|
|
|
|
|
if (need_argb32_hack && Bpp == 4)
|
2014-01-25 12:19:44 +01:00
|
|
|
memcpy_bswap32 (dstp, srcp, byte_count);
|
2009-05-05 17:36:48 +02:00
|
|
|
else
|
2014-01-25 12:19:44 +01:00
|
|
|
memcpy (dstp, srcp, byte_count);
|
2009-05-05 17:36:48 +02:00
|
|
|
} else {
|
|
|
|
dstp += line_no * picasso_vidinfo.rowbytes + first_byte * Bpp;
|
|
|
|
|
|
|
|
switch (Bpp) {
|
|
|
|
case 2: {
|
|
|
|
int i;
|
|
|
|
uae_u16 *dstp16 = (uae_u16*) dstp;
|
|
|
|
for (i = 0; i < byte_count; i++)
|
|
|
|
*dstp16++ = picasso_vidinfo.clut[srcp[i]];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 4: {
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < byte_count; i++)
|
|
|
|
*((uae_u32 *) dstp + i) = picasso_vidinfo.clut[srcp[i]];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-01-25 12:19:44 +01:00
|
|
|
gfx_unlock_picasso ();
|
2009-05-05 17:36:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void flush_currline (void)
|
|
|
|
{
|
|
|
|
int line_no = currline_y - picasso96_state.YOffset;
|
|
|
|
|
|
|
|
/* We only need to flush this line to the screen if the line
|
|
|
|
* is acutally visible on screen */
|
|
|
|
if (line_no >= 0 && line_no < picasso96_state.Height) {
|
|
|
|
|
|
|
|
/* Tell the graphics system that this line needs to be
|
|
|
|
* redrawn */
|
|
|
|
DX_Invalidate (line_no, line_no);
|
|
|
|
|
|
|
|
/* If our graphics system uses a separate buffer, then
|
|
|
|
* that must be updated too */
|
|
|
|
if (picasso_vidinfo.extra_mem) {
|
|
|
|
uae_u8 fb_bpp = picasso96_state.BytesPerPixel;
|
|
|
|
int byte_count = (currline_max - currline_min);
|
|
|
|
int first_byte = currline_min - currline_start
|
|
|
|
- (picasso96_state.XOffset * fb_bpp);
|
|
|
|
uae_u8 *srcp = (currline_min - gfxmem_start) + gfxmemory;
|
|
|
|
|
|
|
|
if (first_byte < 0) {
|
|
|
|
byte_count += first_byte;
|
|
|
|
srcp += first_byte;
|
|
|
|
first_byte = 0;
|
|
|
|
}
|
|
|
|
if ((first_byte + byte_count) > (picasso96_state.Width * fb_bpp))
|
|
|
|
byte_count = picasso96_state.Width * fb_bpp - first_byte;
|
|
|
|
|
|
|
|
if (byte_count > 0)
|
|
|
|
write_currline (srcp, line_no, first_byte, byte_count);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
currline_start = 0xFFFFFFFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
STATIC_INLINE void wgfx_flushline (void)
|
|
|
|
{
|
|
|
|
if (currline_start == 0xFFFFFFFF || !picasso_on)
|
|
|
|
return;
|
|
|
|
flush_currline ();
|
|
|
|
}
|
|
|
|
|
|
|
|
STATIC_INLINE int renderinfo_is_current_screen (struct RenderInfo *ri)
|
|
|
|
{
|
|
|
|
if (!picasso_on)
|
|
|
|
return 0;
|
|
|
|
if (ri->Memory != gfxmemory + (picasso96_state.Address - gfxmem_start))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Clear our screen, since we've got a new Picasso screen-mode, and refresh
|
|
|
|
* with the proper contents. This is called on several occasions:
|
|
|
|
* 1. Amiga-->Picasso transition, via SetSwitch()
|
|
|
|
* 2. Picasso-->Picasso transition, via SetPanning().
|
|
|
|
* 3. whenever the graphics code notifies us that the screen contents have
|
|
|
|
* been lost.
|
|
|
|
*/
|
|
|
|
extern unsigned int new_beamcon0;
|
|
|
|
|
|
|
|
void picasso_refresh (int call_setpalette)
|
|
|
|
{
|
|
|
|
struct RenderInfo ri;
|
|
|
|
|
|
|
|
if (!picasso_on)
|
|
|
|
return;
|
|
|
|
|
|
|
|
{ // for higher P96 mousedraw rate
|
|
|
|
extern uae_u16 vtotal;
|
|
|
|
if (p96hack_vpos2) {
|
|
|
|
vtotal = p96hack_vpos2;
|
|
|
|
new_beamcon0 |= 0x80;
|
|
|
|
p96refresh_active=1;
|
|
|
|
} else new_beamcon0 |= 0x20;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef JIT
|
|
|
|
have_done_picasso=1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Make sure that the first time we show a Picasso video mode, we don't
|
|
|
|
* blit any crap. We can do this by checking if we have an Address yet. */
|
|
|
|
if (picasso96_state.Address) {
|
|
|
|
unsigned int width, height;
|
|
|
|
/* blit the stuff from our static frame-buffer to the gfx-card */
|
|
|
|
ri.Memory = gfxmemory + (picasso96_state.Address - gfxmem_start);
|
|
|
|
ri.BytesPerRow = picasso96_state.BytesPerRow;
|
|
|
|
ri.RGBFormat = picasso96_state.RGBFormat;
|
|
|
|
|
2014-01-25 12:19:44 +01:00
|
|
|
if (set_panning_called) {
|
2009-05-05 17:36:48 +02:00
|
|
|
width = picasso96_state.VirtualWidth;
|
|
|
|
height = picasso96_state.VirtualHeight;
|
|
|
|
} else {
|
|
|
|
width = picasso96_state.Width;
|
|
|
|
height = picasso96_state.Height;
|
|
|
|
}
|
|
|
|
|
|
|
|
do_blit (&ri, picasso96_state.BytesPerPixel, 0, 0, 0, 0, width,
|
|
|
|
height, BLIT_SRC, 0);
|
|
|
|
} else
|
|
|
|
write_log ("P96: ERROR - picasso_refresh() can't refresh!\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Functions to perform an action on the frame-buffer
|
|
|
|
*/
|
|
|
|
STATIC_INLINE void do_blitrect_frame_buffer (struct RenderInfo *ri,
|
|
|
|
struct RenderInfo *dstri,
|
|
|
|
unsigned long srcx, unsigned long srcy,
|
|
|
|
unsigned long dstx, unsigned long dsty,
|
|
|
|
unsigned long width, unsigned long height,
|
|
|
|
uae_u8 mask, BLIT_OPCODE opcode)
|
|
|
|
{
|
|
|
|
uae_u8 *src, *dst, *tmp, *tmp2, *tmp3;
|
|
|
|
uae_u8 Bpp = GetBytesPerPixel (ri->RGBFormat);
|
|
|
|
unsigned long total_width = width * Bpp;
|
|
|
|
unsigned long linewidth = (total_width + 15) & ~15;
|
|
|
|
unsigned long lines;
|
|
|
|
/* int can_do_visible_blit = 0; */
|
|
|
|
|
|
|
|
src = ri->Memory + srcx*Bpp + srcy*ri->BytesPerRow;
|
|
|
|
dst = dstri->Memory + dstx*Bpp + dsty*dstri->BytesPerRow;
|
|
|
|
|
|
|
|
if (mask != 0xFF && Bpp > 1) {
|
|
|
|
P96TRACE (("P96: WARNING - BlitRect() has mask 0x%x with Bpp %d.\n", mask, Bpp));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mask == 0xFF || Bpp > 1) {
|
|
|
|
if( opcode == BLIT_SRC ) {
|
|
|
|
/* handle normal case efficiently */
|
|
|
|
if (ri->Memory == dstri->Memory && dsty == srcy) {
|
|
|
|
unsigned long i;
|
|
|
|
for (i = 0; i < height; i++, src += ri->BytesPerRow, dst += dstri->BytesPerRow)
|
|
|
|
memmove (dst, src, total_width);
|
|
|
|
} else if (dsty < srcy) {
|
|
|
|
unsigned long i;
|
|
|
|
for (i = 0; i < height; i++, src += ri->BytesPerRow, dst += dstri->BytesPerRow)
|
|
|
|
memcpy (dst, src, total_width);
|
|
|
|
} else {
|
|
|
|
unsigned long i;
|
|
|
|
src += (height-1) * ri->BytesPerRow;
|
|
|
|
dst += (height-1) * dstri->BytesPerRow;
|
|
|
|
for (i = 0; i < height; i++, src -= ri->BytesPerRow, dst -= dstri->BytesPerRow)
|
|
|
|
memcpy (dst, src, total_width);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
uae_u8 *src2 = src;
|
|
|
|
uae_u8 *dst2 = dst;
|
|
|
|
uae_u32 *src2_32 = (uae_u32*)src;
|
|
|
|
uae_u32 *dst2_32 = (uae_u32*)dst;
|
|
|
|
unsigned int y;
|
|
|
|
|
|
|
|
for (y = 0; y < height; y++) {
|
|
|
|
uae_u32 *bound = (uae_u32 *)(src + total_width - 4);
|
|
|
|
//copy now the longs
|
|
|
|
for (src2_32 = (uae_u32*)src, dst2_32 = (uae_u32*)dst; src2_32 < bound; src2_32++, dst2_32++ ) {
|
|
|
|
switch ((uae_u8) opcode) {
|
|
|
|
case BLIT_FALSE:
|
|
|
|
*dst2_32 = 0;
|
|
|
|
break;
|
|
|
|
case BLIT_NOR:
|
|
|
|
*dst2_32 = ~(*src2_32 | *dst2_32);
|
|
|
|
break;
|
|
|
|
case BLIT_ONLYDST:
|
|
|
|
*dst2_32 = *dst2_32 & ~(*src2_32);
|
|
|
|
break;
|
|
|
|
case BLIT_NOTSRC:
|
|
|
|
*dst2_32 = ~(*src2_32);
|
|
|
|
break;
|
|
|
|
case BLIT_ONLYSRC:
|
|
|
|
*dst2_32 = *src2_32 & ~(*dst2_32);
|
|
|
|
break;
|
|
|
|
case BLIT_NOTDST:
|
|
|
|
*dst2_32 = ~(*dst2_32);
|
|
|
|
break;
|
|
|
|
case BLIT_EOR:
|
|
|
|
*dst2_32 = *src2_32 ^ *dst2_32;
|
|
|
|
break;
|
|
|
|
case BLIT_NAND:
|
|
|
|
*dst2_32 = ~(*src2_32 & *dst2_32);
|
|
|
|
break;
|
|
|
|
case BLIT_AND:
|
|
|
|
*dst2_32 = *src2_32 & *dst2_32;
|
|
|
|
break;
|
|
|
|
case BLIT_NEOR:
|
|
|
|
*dst2_32 = ~(*src2_32 ^ *dst2_32);
|
|
|
|
break;
|
|
|
|
case BLIT_DST:
|
|
|
|
write_log ("P96: ERROR - do_blitrect_frame_buffer shouldn't get BLIT_DST!\n");
|
|
|
|
break;
|
|
|
|
case BLIT_NOTONLYSRC:
|
|
|
|
*dst2_32 = ~(*src2_32) | *dst2_32;
|
|
|
|
break;
|
|
|
|
case BLIT_SRC:
|
|
|
|
write_log ("P96: ERROR - do_blitrect_frame_buffer shouldn't get BLIT_SRC!\n");
|
|
|
|
break;
|
|
|
|
case BLIT_NOTONLYDST:
|
|
|
|
*dst2_32 = ~(*dst2_32) | *src2_32;
|
|
|
|
break;
|
|
|
|
case BLIT_OR:
|
|
|
|
*dst2_32 = *src2_32 | *dst2_32;
|
|
|
|
break;
|
|
|
|
case BLIT_TRUE:
|
|
|
|
*dst2_32 = 0xFFFFFFFF;
|
|
|
|
break;
|
|
|
|
case 30: {
|
|
|
|
/* code for swap source with dest in byte */
|
|
|
|
uae_u32 temp;
|
|
|
|
temp = *src2_32;
|
|
|
|
*src2_32 = *dst2_32;
|
|
|
|
*dst2_32 = temp;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case BLIT_LAST:
|
2014-01-25 12:19:44 +01:00
|
|
|
write_log ( "P96: ERROR - do_blitrect_frame_buffer shouldn't get BLIT_LAST!\n");
|
2009-05-05 17:36:48 +02:00
|
|
|
break;
|
|
|
|
} /* switch opcode */
|
|
|
|
} // for end
|
|
|
|
//now copy the rest few bytes
|
|
|
|
for (src2 = (uae_u8*)src2_32, dst2 = (uae_u8*)dst2_32; src2 < src + total_width; src2++, dst2++ ) {
|
|
|
|
switch ((uae_u8)opcode) {
|
|
|
|
case BLIT_FALSE:
|
|
|
|
*dst2 = 0;
|
|
|
|
break;
|
|
|
|
case BLIT_NOR:
|
|
|
|
*dst2 = ~(*src2 | *dst2);
|
|
|
|
break;
|
|
|
|
case BLIT_ONLYDST:
|
|
|
|
*dst2 = *dst2 & ~(*src2);
|
|
|
|
break;
|
|
|
|
case BLIT_NOTSRC:
|
|
|
|
*dst2 = ~(*src2);
|
|
|
|
break;
|
|
|
|
case BLIT_ONLYSRC:
|
|
|
|
*dst2 = *src2 & ~(*dst2);
|
|
|
|
break;
|
|
|
|
case BLIT_NOTDST:
|
|
|
|
*dst2 = ~(*dst2);
|
|
|
|
break;
|
|
|
|
case BLIT_EOR:
|
|
|
|
*dst2 = *src2 ^ *dst2;
|
|
|
|
break;
|
|
|
|
case BLIT_NAND:
|
|
|
|
*dst2 = ~(*src2 & *dst2);
|
|
|
|
break;
|
|
|
|
case BLIT_AND:
|
|
|
|
*dst2 = *src2 & *dst2;
|
|
|
|
break;
|
|
|
|
case BLIT_NEOR:
|
|
|
|
*dst2 = ~(*src2 ^ *dst2);
|
|
|
|
break;
|
|
|
|
case BLIT_DST:
|
|
|
|
write_log ("P96: ERROR - do_blitrect_frame_buffer shouldn't get BLIT_DST!\n");
|
|
|
|
break;
|
|
|
|
case BLIT_NOTONLYSRC:
|
|
|
|
*dst2 = ~(*src2) | *dst2;
|
|
|
|
break;
|
|
|
|
case BLIT_SRC:
|
|
|
|
write_log ("P96: ERROR - do_blitrect_frame_buffer shouldn't get BLIT_SRC!\n");
|
|
|
|
break;
|
|
|
|
case BLIT_NOTONLYDST:
|
|
|
|
*dst2 = ~(*dst2) | *src2;
|
|
|
|
break;
|
|
|
|
case BLIT_OR:
|
|
|
|
*dst2 = *src2 | *dst2;
|
|
|
|
break;
|
|
|
|
case BLIT_TRUE:
|
|
|
|
*dst2 = 0xFF;
|
|
|
|
break;
|
|
|
|
case BLIT_LAST:
|
|
|
|
write_log ("P96: ERROR - do_blitrect_frame_buffer shouldn't get BLIT_LAST!\n");
|
|
|
|
break;
|
|
|
|
case 30: {
|
|
|
|
/* code for swap source with dest in long */
|
|
|
|
uae_u8 temp;
|
|
|
|
temp = *src2;
|
|
|
|
*src2 = *dst2;
|
|
|
|
*dst2 = temp;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} /* switch opcode */
|
|
|
|
} /* for width */
|
|
|
|
src += ri->BytesPerRow;
|
|
|
|
dst += dstri->BytesPerRow;
|
|
|
|
} /* for height */
|
|
|
|
}
|
2014-01-25 12:19:44 +01:00
|
|
|
return;
|
2009-05-05 17:36:48 +02:00
|
|
|
}
|
|
|
|
// (mask != 0xFF && Bpp <= 1)
|
|
|
|
tmp3 = tmp2 = tmp = xmalloc (linewidth * height); /* allocate enough memory for the src-rect */
|
|
|
|
if (!tmp)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* copy the src-rect into our temporary buffer space */
|
|
|
|
for (lines = 0; lines < height; lines++, src += ri->BytesPerRow, tmp2 += linewidth)
|
|
|
|
memcpy (tmp2, src, total_width);
|
|
|
|
|
|
|
|
/* copy the temporary buffer to the destination */
|
|
|
|
for (lines = 0; lines < height; lines++, dst += dstri->BytesPerRow, tmp += linewidth) {
|
|
|
|
unsigned long cols;
|
|
|
|
for (cols = 0; cols < width; cols++) {
|
|
|
|
dst[cols] &= ~mask;
|
|
|
|
dst[cols] |= tmp[cols] & mask;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* free the temp-buf */
|
|
|
|
free (tmp3);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* BOOL FindCard(struct BoardInfo *bi); and
|
|
|
|
*
|
|
|
|
* FindCard is called in the first stage of the board initialisation and
|
|
|
|
* configuration and is used to look if there is a free and unconfigured
|
|
|
|
* board of the type the driver is capable of managing. If it finds one,
|
|
|
|
* it immediately reserves it for use by Picasso96, usually by clearing
|
|
|
|
* the CDB_CONFIGME bit in the flags field of the ConfigDev struct of
|
|
|
|
* this expansion card. But this is only a common example, a driver can
|
|
|
|
* do whatever it wants to mark this card as used by the driver. This
|
|
|
|
* mechanism is intended to ensure that a board is only configured and
|
|
|
|
* used by one driver. FindBoard also usually fills some fields of the
|
|
|
|
* BoardInfo struct supplied by the caller, the rtg.library, for example
|
|
|
|
* the MemoryBase, MemorySize and RegisterBase fields.
|
|
|
|
*/
|
|
|
|
uae_u32 REGPARAM2 picasso_FindCard (struct regstruct *regs)
|
|
|
|
{
|
|
|
|
uaecptr AmigaBoardInfo = m68k_areg (regs, 0);
|
|
|
|
/* NOTES: See BoardInfo struct definition in Picasso96 dev info */
|
|
|
|
|
|
|
|
if (allocated_gfxmem && !picasso96_state.CardFound) {
|
|
|
|
/* Fill in MemoryBase, MemorySize */
|
|
|
|
put_long (AmigaBoardInfo + PSSO_BoardInfo_MemoryBase, gfxmem_start);
|
|
|
|
/* size of memory, minus a 32K chunk: 16K for pattern bitmaps, 16K for
|
|
|
|
* resolution list */
|
|
|
|
put_long (AmigaBoardInfo + PSSO_BoardInfo_MemorySize,
|
|
|
|
allocated_gfxmem - 32768);
|
|
|
|
|
|
|
|
picasso96_state.CardFound = 1; /* mark our "card" as being found */
|
|
|
|
return -1;
|
|
|
|
} else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FillBoardInfo (uaecptr amigamemptr, struct LibResolution *res,
|
|
|
|
struct PicassoResolution *dm)
|
|
|
|
{
|
|
|
|
uae_u8 *uaememptr;
|
|
|
|
switch (dm->depth) {
|
|
|
|
case 1:
|
|
|
|
res->Modes[CHUNKY] = amigamemptr;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
res->Modes[HICOLOR] = amigamemptr;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
res->Modes[TRUECOLOR] = amigamemptr;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
res->Modes[TRUEALPHA] = amigamemptr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* I know that amigamemptr is inside my gfxmem chunk, so I can just do
|
|
|
|
* the xlate() */
|
|
|
|
uaememptr = gfxmem_xlate (amigamemptr);
|
|
|
|
|
|
|
|
/* zero out our ModeInfo struct */
|
|
|
|
memset (uaememptr, 0, PSSO_ModeInfo_sizeof);
|
|
|
|
|
|
|
|
put_word (amigamemptr + PSSO_ModeInfo_Width, dm->res.width);
|
|
|
|
put_word (amigamemptr + PSSO_ModeInfo_Height, dm->res.height);
|
|
|
|
put_byte (amigamemptr + PSSO_ModeInfo_Depth, dm->depth * 8);
|
|
|
|
put_byte (amigamemptr + PSSO_ModeInfo_Flags, 0);
|
|
|
|
put_word (amigamemptr + PSSO_ModeInfo_HorTotal, dm->res.width);
|
|
|
|
put_word (amigamemptr + PSSO_ModeInfo_HorBlankSize, 0);
|
|
|
|
put_word (amigamemptr + PSSO_ModeInfo_HorSyncStart, 0);
|
|
|
|
put_word (amigamemptr + PSSO_ModeInfo_HorSyncSize, 0);
|
|
|
|
put_byte (amigamemptr + PSSO_ModeInfo_HorSyncSkew, 0);
|
|
|
|
put_byte (amigamemptr + PSSO_ModeInfo_HorEnableSkew, 0);
|
|
|
|
|
|
|
|
put_word (amigamemptr + PSSO_ModeInfo_VerTotal, dm->res.height);
|
|
|
|
put_word (amigamemptr + PSSO_ModeInfo_VerBlankSize, 0);
|
|
|
|
put_word (amigamemptr + PSSO_ModeInfo_VerSyncStart, 0);
|
|
|
|
put_word (amigamemptr + PSSO_ModeInfo_VerSyncSize, 0);
|
|
|
|
|
|
|
|
put_byte (amigamemptr + PSSO_ModeInfo_first_union, 98);
|
|
|
|
put_byte (amigamemptr + PSSO_ModeInfo_second_union, 14);
|
|
|
|
|
|
|
|
put_long (amigamemptr + PSSO_ModeInfo_PixelClock,
|
|
|
|
dm->res.width * dm->res.height * dm->refresh);
|
|
|
|
}
|
|
|
|
|
2014-01-25 12:19:44 +01:00
|
|
|
struct modeids {
|
|
|
|
int width, height;
|
|
|
|
int id;
|
|
|
|
};
|
|
|
|
static const struct modeids mi[] =
|
|
|
|
{
|
|
|
|
/* "original" modes */
|
|
|
|
|
|
|
|
{ 320, 200, 0 },
|
|
|
|
{ 320, 240, 1 },
|
|
|
|
{ 640, 400, 2 },
|
|
|
|
{ 640, 480, 3 },
|
|
|
|
{ 800, 600, 4 },
|
|
|
|
{ 1024, 768, 5 },
|
|
|
|
{ 1152, 864, 6 },
|
|
|
|
{ 1280,1024, 7 },
|
|
|
|
{ 1600,1280, 8 },
|
|
|
|
|
|
|
|
/* new modes */
|
|
|
|
|
|
|
|
{ 704, 480, 129 },
|
|
|
|
{ 704, 576, 130 },
|
|
|
|
{ 720, 480, 131 },
|
|
|
|
{ 720, 576, 132 },
|
|
|
|
{ 768, 483, 133 },
|
|
|
|
{ 768, 576, 134 },
|
|
|
|
{ 800, 480, 135 },
|
|
|
|
{ 848, 480, 136 },
|
|
|
|
{ 854, 480, 137 },
|
|
|
|
{ 948, 576, 138 },
|
|
|
|
{ 1024, 576, 139 },
|
|
|
|
{ 1152, 768, 140 },
|
|
|
|
{ 1152, 864, 141 },
|
|
|
|
{ 1280, 720, 142 },
|
|
|
|
{ 1280, 768, 143 },
|
|
|
|
{ 1280, 800, 144 },
|
|
|
|
{ 1280, 854, 145 },
|
|
|
|
{ 1280, 960, 146 },
|
|
|
|
{ 1366, 768, 147 },
|
|
|
|
{ 1440, 900, 148 },
|
|
|
|
{ 1440, 960, 149 },
|
|
|
|
{ 1600,1200, 150 },
|
|
|
|
{ 1680,1050, 151 },
|
|
|
|
{ 1920,1080, 152 },
|
|
|
|
{ 1920,1200, 153 },
|
|
|
|
{ 2048,1152, 154 },
|
|
|
|
{ 2048,1536, 155 },
|
|
|
|
{ 2560,1600, 156 },
|
|
|
|
{ 2560,2048, 157 },
|
|
|
|
{ 400, 300, 158 },
|
|
|
|
{ 512, 384, 159 },
|
|
|
|
{ 640, 432, 160 },
|
|
|
|
{ 1360, 768, 161 },
|
|
|
|
{ 1360,1024, 162 },
|
|
|
|
{ 1400,1050, 163 },
|
|
|
|
{ 1792,1344, 164 },
|
|
|
|
{ 1800,1440, 165 },
|
|
|
|
{ 1856,1392, 166 },
|
|
|
|
{ 1920,1440, 167 },
|
|
|
|
{ 480, 360, 168 },
|
|
|
|
{ 640, 350, 169 },
|
|
|
|
{ 1600, 900, 170 },
|
|
|
|
{ 960, 600, 171 },
|
|
|
|
{ 1088, 612, 172 },
|
|
|
|
{ -1, -1, 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
static uae_u32 AssignModeID (int w, int h, unsigned int *non_standard_count)
|
2009-05-05 17:36:48 +02:00
|
|
|
{
|
2014-01-25 12:19:44 +01:00
|
|
|
unsigned int i;
|
2009-05-05 17:36:48 +02:00
|
|
|
|
2014-01-25 12:19:44 +01:00
|
|
|
for (i = 0; mi[i].width > 0; i++) {
|
|
|
|
if (w == mi[i].width && h == mi[i].height)
|
|
|
|
return 0x50001000 | (mi[i].id * 0x10000);
|
|
|
|
}
|
|
|
|
(*non_standard_count)++;
|
|
|
|
write_log ("P96: Non-stanard mode %dx%d\n", w, h);
|
|
|
|
return 0x51001000 - (*non_standard_count) * 0x10000;
|
2009-05-05 17:36:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************
|
|
|
|
* InitCard()
|
|
|
|
*
|
|
|
|
* a2: BoardInfo structure ptr - Amiga-based address in Intel endian-format
|
|
|
|
*
|
|
|
|
* Job - fill in the following structure members:
|
|
|
|
* gbi_RGBFormats: the pixel formats that the host-OS of UAE supports
|
|
|
|
* If UAE is running in a window, it should ONLY report the pixel format of
|
|
|
|
* the host-OS desktop.
|
|
|
|
* If UAE is running full-screen, it should report ALL pixel formats that
|
|
|
|
* the host-OS can handle in full-screen.
|
|
|
|
* NOTE: If full-screen, and the user toggles to windowed-mode, all hell
|
|
|
|
* will break loose visually. Must inform user that they're doing
|
|
|
|
* something stupid (unless their desktop and full-screen colour modes
|
|
|
|
* match).
|
|
|
|
* gbi_SoftSpriteFlags: should be the same as above for now, until actual
|
|
|
|
* cursor support is added
|
|
|
|
* gbi_BitsPerCannon: could be 6 or 8 or ???, depending on the host-OS gfx-card
|
|
|
|
* gbi_MaxHorResolution: fill this in for all modes (even if you don't support
|
|
|
|
* them).
|
|
|
|
* gbi_MaxVerResolution: fill this in for all modes (even if you don't support
|
|
|
|
* them).
|
|
|
|
*/
|
|
|
|
uae_u32 REGPARAM2 picasso_InitCard (struct regstruct *regs)
|
|
|
|
{
|
|
|
|
struct LibResolution res;
|
|
|
|
int i;
|
2014-01-25 12:19:44 +01:00
|
|
|
unsigned int non_standard_count = 0;
|
2009-05-05 17:36:48 +02:00
|
|
|
int ModeInfoStructureCount = 1, LibResolutionStructureCount = 0;
|
|
|
|
uaecptr amigamemptr = 0;
|
|
|
|
uaecptr AmigaBoardInfo = m68k_areg (regs, 2);
|
|
|
|
|
|
|
|
put_word (AmigaBoardInfo + PSSO_BoardInfo_BitsPerCannon, DX_BitsPerCannon ());
|
|
|
|
put_word (AmigaBoardInfo + PSSO_BoardInfo_RGBFormats, picasso96_pixel_format);
|
|
|
|
put_word (AmigaBoardInfo + PSSO_BoardInfo_SoftSpriteFlags, picasso96_pixel_format);
|
|
|
|
put_long (AmigaBoardInfo + PSSO_BoardInfo_BoardType, BT_uaegfx);
|
|
|
|
put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 0, planar.width);
|
|
|
|
put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 2, chunky.width);
|
|
|
|
put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 4, hicolour.width);
|
|
|
|
put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 6, truecolour.width);
|
|
|
|
put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 8, alphacolour.width);
|
|
|
|
put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 0, planar.height);
|
|
|
|
put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 2, chunky.height);
|
|
|
|
put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 4, hicolour.height);
|
|
|
|
put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 6, truecolour.height);
|
|
|
|
put_word (AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 8, alphacolour.height);
|
|
|
|
|
|
|
|
for (i = 0; i < mode_count;) {
|
|
|
|
int j = i;
|
|
|
|
/* Add a LibResolution structure to the ResolutionsList MinList in our BoardInfo */
|
2014-01-25 12:19:44 +01:00
|
|
|
res.DisplayID = AssignModeID (DisplayModes[i].res.width, DisplayModes[i].res.height, &non_standard_count);
|
2009-05-05 17:36:48 +02:00
|
|
|
res.BoardInfo = AmigaBoardInfo;
|
|
|
|
res.Width = DisplayModes[i].res.width;
|
|
|
|
res.Height = DisplayModes[i].res.height;
|
|
|
|
res.Flags = P96F_PUBLIC;
|
|
|
|
res.P96ID[0] = 'P';
|
|
|
|
res.P96ID[1] = '9';
|
|
|
|
res.P96ID[2] = '6';
|
|
|
|
res.P96ID[3] = '-';
|
|
|
|
res.P96ID[4] = '0';
|
|
|
|
res.P96ID[5] = ':';
|
|
|
|
strcpy (res.Name, "uaegfx:");
|
|
|
|
strncat (res.Name, DisplayModes[i].name,
|
|
|
|
strchr (DisplayModes[i].name, ',') - DisplayModes[i].name);
|
|
|
|
res.Modes[PLANAR] = 0;
|
|
|
|
res.Modes[CHUNKY] = 0;
|
|
|
|
res.Modes[HICOLOR] = 0;
|
|
|
|
res.Modes[TRUECOLOR] = 0;
|
|
|
|
res.Modes[TRUEALPHA] = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
/* Handle this display mode's depth */
|
|
|
|
/* Only add the modes when there is enough P96 RTG memory to hold the bitmap */
|
|
|
|
unsigned long required = DisplayModes[i].res.width * DisplayModes[i].res.height
|
|
|
|
* DisplayModes[i].depth;
|
|
|
|
if (allocated_gfxmem - 32768 > required) {
|
|
|
|
amigamemptr = gfxmem_start + allocated_gfxmem
|
|
|
|
- (PSSO_ModeInfo_sizeof * ModeInfoStructureCount++);
|
|
|
|
FillBoardInfo (amigamemptr, &res, &DisplayModes[i]);
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
} while (i < mode_count
|
|
|
|
&& DisplayModes[i].res.width == DisplayModes[j].res.width
|
|
|
|
&& DisplayModes[i].res.height == DisplayModes[j].res.height);
|
|
|
|
|
|
|
|
amigamemptr = gfxmem_start + allocated_gfxmem - 16384
|
|
|
|
+ (PSSO_LibResolution_sizeof * LibResolutionStructureCount++);
|
|
|
|
|
|
|
|
CopyLibResolutionStructureU2A (&res, amigamemptr);
|
|
|
|
DumpLibResolutionStructure (amigamemptr);
|
|
|
|
|
|
|
|
AmigaListAddTail (AmigaBoardInfo + PSSO_BoardInfo_ResolutionsList, amigamemptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern int x_size, y_size;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SetSwitch:
|
|
|
|
* a0: struct BoardInfo
|
|
|
|
* d0.w: BOOL state
|
|
|
|
* this function should set a board switch to let the Amiga signal pass
|
|
|
|
* through when supplied with a 0 in d0 and to show the board signal if
|
|
|
|
* a 1 is passed in d0. You should remember the current state of the
|
|
|
|
* switch to avoid unneeded switching. If your board has no switch, then
|
|
|
|
* simply supply a function that does nothing except a RTS.
|
|
|
|
*
|
|
|
|
* NOTE: Return the opposite of the switch-state. BDK
|
|
|
|
*/
|
|
|
|
uae_u32 REGPARAM2 picasso_SetSwitch (struct regstruct *regs)
|
|
|
|
{
|
|
|
|
uae_u16 flag = m68k_dreg (regs, 0) & 0xFFFF;
|
|
|
|
|
|
|
|
/* Do not switch immediately. Tell the custom chip emulation about the
|
|
|
|
* desired state, and wait for custom.c to call picasso_enablescreen
|
|
|
|
* whenever it is ready to change the screen state. */
|
|
|
|
picasso_requested_on = !!flag;
|
|
|
|
|
|
|
|
P96TRACE (("P96: SetSwitch() - trying to show %s screen\n", flag ? "picasso96" : "amiga"));
|
|
|
|
|
|
|
|
flush_icache (5); /* Changing the screen mode might make gfx memory
|
|
|
|
directly accessible, or no longer thus accessible */
|
|
|
|
|
|
|
|
/* Put old switch-state in D0 */
|
|
|
|
return !flag;
|
|
|
|
}
|
|
|
|
|
|
|
|
void picasso_enablescreen (int on)
|
|
|
|
{
|
|
|
|
currline_start = 0xFFFFFFFF;
|
|
|
|
picasso_refresh (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int first_color_changed = 256;
|
|
|
|
static int last_color_changed = -1;
|
|
|
|
|
|
|
|
void picasso_handle_vsync (void)
|
|
|
|
{
|
|
|
|
if (first_color_changed < last_color_changed) {
|
|
|
|
DX_SetPalette (first_color_changed,
|
|
|
|
last_color_changed - first_color_changed);
|
|
|
|
/* If we're emulating a CLUT mode, we need to redraw the entire
|
|
|
|
* screen. */
|
|
|
|
if (picasso_vidinfo.rgbformat != picasso96_state.RGBFormat)
|
|
|
|
picasso_refresh (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
first_color_changed = 256;
|
|
|
|
last_color_changed = -1;
|
|
|
|
|
|
|
|
/* Flush any cached changes to the screen. */
|
|
|
|
wgfx_flushline ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void picasso_handle_hsync (void)
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
static int p96hsync;
|
|
|
|
|
|
|
|
if (currprefs.gfxmem_size == 0)
|
|
|
|
return;
|
|
|
|
if (WIN32GFX_IsPicassoScreen () && currprefs.gfx_pfullscreen && currprefs.gfx_vsync) {
|
|
|
|
if (DirectDraw_GetVerticalBlankStatus ())
|
|
|
|
p96hsync = 0;
|
|
|
|
} else
|
|
|
|
p96hsync--;
|
|
|
|
|
|
|
|
if (p96hsync <= 0) {
|
|
|
|
rtarea[get_long (RTAREA_BASE + 36) + 12 - 1]++;
|
|
|
|
p96hsync = p96syncrate;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void init_hz_p96 (void)
|
|
|
|
{
|
|
|
|
int rate = 0;
|
|
|
|
p96syncrate = maxvpos * vblank_hz;
|
|
|
|
#if 0
|
|
|
|
if (isfullscreen ())
|
|
|
|
rate = DirectDraw_CurrentRefreshRate ();
|
|
|
|
else
|
|
|
|
rate = currprefs.gfx_refreshrate;
|
|
|
|
#endif
|
|
|
|
if (rate <= 0)
|
|
|
|
rate = 60;
|
|
|
|
p96syncrate /= rate;
|
|
|
|
}
|
|
|
|
|
|
|
|
void picasso_clip_mouse (int *px, int *py)
|
|
|
|
{
|
|
|
|
int xoff = picasso96_state.XOffset;
|
|
|
|
int yoff = picasso96_state.YOffset;
|
|
|
|
|
|
|
|
if (*px < -xoff)
|
|
|
|
*px = -xoff;
|
|
|
|
if (*px + xoff > picasso_vidinfo.width)
|
|
|
|
*px = picasso_vidinfo.width - xoff;
|
|
|
|
if (*py < -yoff)
|
|
|
|
*py = -yoff;
|
|
|
|
if (*py + yoff > picasso_vidinfo.height)
|
|
|
|
*py = picasso_vidinfo.height - yoff;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SetColorArray:
|
|
|
|
* a0: struct BoardInfo
|
|
|
|
* d0.w: startindex
|
|
|
|
* d1.w: count
|
|
|
|
* when this function is called, your driver has to fetch "count" color
|
|
|
|
* values starting at "startindex" from the CLUT field of the BoardInfo
|
|
|
|
* structure and write them to the hardware. The color values are always
|
|
|
|
* between 0 and 255 for each component regardless of the number of bits
|
|
|
|
* per cannon your board has. So you might have to shift the colors
|
|
|
|
* before writing them to the hardware.
|
|
|
|
*/
|
|
|
|
uae_u32 REGPARAM2 picasso_SetColorArray (struct regstruct *regs)
|
|
|
|
{
|
|
|
|
/* Fill in some static UAE related structure about this new CLUT setting.
|
|
|
|
* We need this for CLUT-based displays, and for mapping CLUT to hi/true
|
|
|
|
* colour */
|
|
|
|
uaecptr boardinfo = m68k_areg (regs, 0);
|
|
|
|
uae_u16 start = m68k_dreg (regs, 0);
|
|
|
|
uae_u16 count = m68k_dreg (regs, 1);
|
|
|
|
|
|
|
|
uaecptr clut = boardinfo + PSSO_BoardInfo_CLUT + start * 3;
|
|
|
|
int changed = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = start; i < start + count; i++) {
|
|
|
|
int r = get_byte (clut);
|
|
|
|
int g = get_byte (clut + 1);
|
|
|
|
int b = get_byte (clut + 2);
|
|
|
|
|
|
|
|
changed |= (picasso96_state.CLUT[i].Red != r
|
|
|
|
|| picasso96_state.CLUT[i].Green != g
|
|
|
|
|| picasso96_state.CLUT[i].Blue != b);
|
|
|
|
|
|
|
|
picasso96_state.CLUT[i].Red = r;
|
|
|
|
picasso96_state.CLUT[i].Green = g;
|
|
|
|
picasso96_state.CLUT[i].Blue = b;
|
|
|
|
|
|
|
|
clut += 3;
|
|
|
|
}
|
|
|
|
if (changed) {
|
|
|
|
if (start < first_color_changed)
|
|
|
|
first_color_changed = start;
|
|
|
|
if (start + count > last_color_changed)
|
|
|
|
last_color_changed = start + count;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SetDAC:
|
|
|
|
* a0: struct BoardInfo
|
|
|
|
* d7: RGBFTYPE RGBFormat
|
|
|
|
* This function is called whenever the RGB format of the display changes,
|
|
|
|
* e.g. from chunky to TrueColor. Usually, all you have to do is to set
|
|
|
|
* the RAMDAC of your board accordingly.
|
|
|
|
*/
|
|
|
|
uae_u32 REGPARAM2 picasso_SetDAC (struct regstruct *regs)
|
|
|
|
{
|
|
|
|
/* Fill in some static UAE related structure about this new DAC setting.
|
|
|
|
* Lets us keep track of what pixel format the Amiga is thinking about in
|
|
|
|
* our frame-buffer */
|
|
|
|
P96TRACE (("P96: SetDAC()\n"));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void init_picasso_screen (void)
|
|
|
|
{
|
|
|
|
int width = picasso96_state.Width;
|
|
|
|
int height = picasso96_state.Height;
|
|
|
|
int vwidth = picasso96_state.VirtualWidth;
|
|
|
|
int vheight = picasso96_state.VirtualHeight;
|
|
|
|
int xoff = 0;
|
|
|
|
int yoff = 0;
|
|
|
|
|
|
|
|
if (!set_gc_called)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (set_panning_called) {
|
|
|
|
picasso96_state.Extent = picasso96_state.Address
|
2014-01-25 12:19:44 +01:00
|
|
|
+ (picasso96_state.BytesPerRow * vheight);
|
2009-05-05 17:36:48 +02:00
|
|
|
xoff = picasso96_state.XOffset;
|
|
|
|
yoff = picasso96_state.YOffset;
|
|
|
|
}
|
|
|
|
|
|
|
|
gfx_set_picasso_modeinfo (width, height, picasso96_state.GC_Depth,
|
|
|
|
picasso96_state.RGBFormat);
|
|
|
|
DX_SetPalette (0, 256);
|
|
|
|
|
|
|
|
currline_start = 0xFFFFFFFF;
|
|
|
|
picasso_refresh (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SetGC:
|
|
|
|
* a0: struct BoardInfo
|
|
|
|
* a1: struct ModeInfo
|
|
|
|
* d0: BOOL Border
|
|
|
|
* This function is called whenever another ModeInfo has to be set. This
|
|
|
|
* function simply sets up the CRTC and TS registers to generate the
|
|
|
|
* timing used for that screen mode. You should not set the DAC, clocks
|
|
|
|
* or linear start adress. They will be set when appropriate by their
|
|
|
|
* own functions.
|
|
|
|
*/
|
|
|
|
uae_u32 REGPARAM2 picasso_SetGC (struct regstruct *regs)
|
|
|
|
{
|
|
|
|
/* Fill in some static UAE related structure about this new ModeInfo
|
|
|
|
* setting */
|
|
|
|
uaecptr modeinfo = m68k_areg (regs, 1);
|
|
|
|
|
|
|
|
picasso96_state.Width = get_word (modeinfo + PSSO_ModeInfo_Width);
|
|
|
|
picasso96_state.VirtualWidth = picasso96_state.Width; /* in case SetPanning doesn't get called */
|
|
|
|
|
|
|
|
picasso96_state.Height = get_word (modeinfo + PSSO_ModeInfo_Height);
|
|
|
|
picasso96_state.VirtualHeight = picasso96_state.Height;
|
|
|
|
|
|
|
|
picasso96_state.GC_Depth = get_byte (modeinfo + PSSO_ModeInfo_Depth);
|
|
|
|
picasso96_state.GC_Flags = get_byte (modeinfo + PSSO_ModeInfo_Flags);
|
|
|
|
|
|
|
|
P96TRACE (("P96: SetGC (%d,%d,%d)\n", picasso96_state.Width, picasso96_state.Height,
|
|
|
|
picasso96_state.GC_Depth));
|
|
|
|
|
|
|
|
set_gc_called = 1; /* @@@ when do we need to reset this? */
|
|
|
|
init_picasso_screen ();
|
|
|
|
init_hz_p96 ();
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SetPanning:
|
|
|
|
* a0: struct BoardInfo
|
|
|
|
* a1: UBYTE *Memory
|
|
|
|
* d0: uae_u16 Width
|
|
|
|
* d1: WORD XOffset
|
|
|
|
* d2: WORD YOffset
|
|
|
|
* d7: RGBFTYPE RGBFormat
|
|
|
|
* This function sets the view origin of a display which might also be
|
|
|
|
* overscanned. In register a1 you get the start address of the screen
|
|
|
|
* bitmap on the Amiga side. You will have to subtract the starting
|
|
|
|
* address of the board memory from that value to get the memory start
|
|
|
|
* offset within the board. Then you get the offset in pixels of the
|
|
|
|
* left upper edge of the visible part of an overscanned display. From
|
|
|
|
* these values you will have to calculate the LinearStartingAddress
|
|
|
|
* fields of the CRTC registers.
|
|
|
|
|
|
|
|
* NOTE: SetPanning() can be used to know when a Picasso96 screen is
|
|
|
|
* being opened. Better to do the appropriate clearing of the
|
|
|
|
* background here than in SetSwitch() derived functions,
|
|
|
|
* because SetSwitch() is not called for subsequent Picasso screens.
|
|
|
|
*/
|
|
|
|
uae_u32 REGPARAM2 picasso_SetPanning (struct regstruct *regs)
|
|
|
|
{
|
|
|
|
uaecptr bmeptr;
|
|
|
|
uaecptr bi = m68k_areg (regs, 0);
|
|
|
|
uaecptr start_of_screen = m68k_areg (regs, 1);
|
|
|
|
uae_u16 Width = m68k_dreg (regs, 0);
|
|
|
|
picasso96_state.XOffset = (uae_s16) m68k_dreg (regs, 1);
|
|
|
|
picasso96_state.YOffset = (uae_s16) m68k_dreg (regs, 2);
|
|
|
|
picasso96_state.RGBFormat = m68k_dreg (regs, 7);
|
|
|
|
|
|
|
|
wgfx_flushline();
|
|
|
|
|
|
|
|
/* Get our BoardInfo ptr's BitMapExtra ptr */
|
|
|
|
bmeptr = get_long (bi + PSSO_BoardInfo_BitMapExtra);
|
|
|
|
|
|
|
|
picasso96_state.Address = start_of_screen; /* Amiga-side address */
|
|
|
|
picasso96_state.VirtualWidth = get_word (bmeptr + PSSO_BitMapExtra_Width);
|
|
|
|
picasso96_state.VirtualHeight = get_word (bmeptr + PSSO_BitMapExtra_Height);
|
|
|
|
picasso96_state.BytesPerPixel = GetBytesPerPixel (picasso96_state.RGBFormat);
|
|
|
|
picasso96_state.BytesPerRow = Width * picasso96_state.BytesPerPixel;
|
|
|
|
|
|
|
|
set_panning_called = 1;
|
|
|
|
|
|
|
|
P96TRACE (("P96: SetPanning(%d, %d, %d) Start 0x%x, BPR %d\n",
|
|
|
|
Width, picasso96_state.XOffset, picasso96_state.YOffset,
|
|
|
|
start_of_screen, picasso96_state.BytesPerRow));
|
|
|
|
|
|
|
|
init_picasso_screen ();
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void do_xor8 (uae_u8 * ptr, long len, uae_u32 val)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
#if 0 && defined ALIGN_POINTER_TO32
|
|
|
|
int align_adjust = ALIGN_POINTER_TO32 (ptr);
|
|
|
|
int len2;
|
|
|
|
|
|
|
|
len -= align_adjust;
|
|
|
|
while (align_adjust) {
|
|
|
|
*ptr ^= val;
|
|
|
|
ptr++;
|
|
|
|
align_adjust--;
|
|
|
|
}
|
|
|
|
len2 = len >> 2;
|
|
|
|
len -= len2 << 2;
|
|
|
|
for (i = 0; i < len2; i++, ptr += 4) {
|
|
|
|
*(uae_u32 *) ptr ^= val;
|
|
|
|
}
|
|
|
|
while (len) {
|
|
|
|
*ptr ^= val;
|
|
|
|
ptr++;
|
|
|
|
len--;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
#endif
|
|
|
|
for (i = 0; i < len; i++, ptr++) {
|
|
|
|
do_put_mem_byte (ptr, do_get_mem_byte (ptr) ^ val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* InvertRect:
|
|
|
|
*
|
|
|
|
* Inputs:
|
|
|
|
* a0:struct BoardInfo *bi
|
|
|
|
* a1:struct RenderInfo *ri
|
|
|
|
* d0.w:X
|
|
|
|
* d1.w:Y
|
|
|
|
* d2.w:Width
|
|
|
|
* d3.w:Height
|
|
|
|
* d4.l:Mask
|
|
|
|
* d7.l:RGBFormat
|
|
|
|
*
|
|
|
|
* This function is used to invert a rectangular area on the board. It is
|
|
|
|
* called by BltBitMap, BltPattern and BltTemplate.
|
|
|
|
*/
|
|
|
|
uae_u32 REGPARAM2 picasso_InvertRect (struct regstruct *regs)
|
|
|
|
{
|
|
|
|
uaecptr renderinfo = m68k_areg (regs, 1);
|
|
|
|
unsigned long X = (uae_u16)m68k_dreg (regs, 0);
|
|
|
|
unsigned long Y = (uae_u16)m68k_dreg (regs, 1);
|
|
|
|
unsigned long Width = (uae_u16)m68k_dreg (regs, 2);
|
|
|
|
unsigned long Height = (uae_u16)m68k_dreg (regs, 3);
|
|
|
|
uae_u8 mask = (uae_u8) m68k_dreg (regs, 4);
|
|
|
|
int Bpp = GetBytesPerPixel (m68k_dreg (regs, 7));
|
|
|
|
|
|
|
|
uae_u32 xorval;
|
|
|
|
unsigned int lines;
|
|
|
|
struct RenderInfo ri;
|
|
|
|
uae_u8 *uae_mem, *rectstart;
|
|
|
|
unsigned long width_in_bytes;
|
|
|
|
int result = 0;
|
|
|
|
|
|
|
|
wgfx_flushline ();
|
|
|
|
|
|
|
|
if (CopyRenderInfoStructureA2U (renderinfo, &ri)) {
|
|
|
|
P96TRACE (("P96: InvertRect %dbpp 0x%lx\n", Bpp, (long)mask));
|
|
|
|
|
|
|
|
if (mask != 0xFF && Bpp > 1)
|
|
|
|
mask = 0xFF;
|
|
|
|
|
|
|
|
xorval = 0x01010101 * (mask & 0xFF);
|
|
|
|
width_in_bytes = Bpp * Width;
|
|
|
|
rectstart = uae_mem = ri.Memory + Y*ri.BytesPerRow + X*Bpp;
|
|
|
|
|
|
|
|
for (lines = 0; lines < Height; lines++, uae_mem += ri.BytesPerRow)
|
|
|
|
do_xor8 (uae_mem, width_in_bytes, xorval);
|
|
|
|
|
|
|
|
if (renderinfo_is_current_screen (&ri)) {
|
|
|
|
if (mask == 0xFF)
|
|
|
|
do_invertrect (&ri, Bpp, X, Y, Width, Height);
|
|
|
|
else
|
|
|
|
do_blit (&ri, Bpp, X, Y, X, Y, Width, Height, BLIT_SRC, 0);
|
2014-01-25 12:19:44 +01:00
|
|
|
}
|
|
|
|
result = 1;
|
2009-05-05 17:36:48 +02:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fill a rectangle in the screen.
|
|
|
|
*/
|
|
|
|
STATIC_INLINE void do_fillrect_frame_buffer (struct RenderInfo *ri,
|
|
|
|
int X, int Y,
|
|
|
|
int Width, int Height,
|
|
|
|
uae_u32 Pen, int Bpp,
|
|
|
|
RGBFTYPE RGBFormat)
|
|
|
|
{
|
|
|
|
int cols;
|
|
|
|
uae_u8 *start, *oldstart;
|
|
|
|
uae_u8 *src, *dst;
|
|
|
|
int lines;
|
|
|
|
|
|
|
|
/* Do our virtual frame-buffer memory. First, we do a single line
|
|
|
|
* fill by hand */
|
|
|
|
oldstart = start = src = ri->Memory + X * Bpp + Y * ri->BytesPerRow;
|
|
|
|
|
|
|
|
switch (Bpp) {
|
|
|
|
case 1:
|
|
|
|
memset (start, Pen, Width);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
for (cols = 0; cols < Width; cols++) {
|
|
|
|
do_put_mem_word ((uae_u16 *)start, (uae_u16)Pen);
|
|
|
|
start += 2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
for (cols = 0; cols < Width; cols++) {
|
|
|
|
do_put_mem_byte (start, (uae_u8)Pen);
|
|
|
|
start++;
|
|
|
|
*(uae_u16 *)(start) = (Pen & 0x00FFFF00) >> 8;
|
|
|
|
start+=2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
for (cols = 0; cols < Width; cols++) {
|
|
|
|
do_put_mem_long ((uae_u32 *)start, Pen);
|
|
|
|
start += 4;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
} /* switch (Bpp) */
|
|
|
|
|
|
|
|
src = oldstart;
|
|
|
|
dst = src + ri->BytesPerRow;
|
|
|
|
|
|
|
|
/* next, we do the remaining line fills via memcpy() for > 1 BPP,
|
|
|
|
* otherwise some more memset() calls */
|
|
|
|
if (Bpp > 1) {
|
|
|
|
for (lines = 0; lines < (Height - 1); lines++, dst += ri->BytesPerRow)
|
|
|
|
memcpy (dst, src, Width * Bpp);
|
|
|
|
} else {
|
|
|
|
for (lines = 0; lines < (Height - 1); lines++, dst += ri->BytesPerRow)
|
|
|
|
memset( dst, Pen, Width );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************
|
|
|
|
FillRect:
|
|
|
|
***********************************************************
|
|
|
|
* a0: struct BoardInfo *
|
|
|
|
* a1: struct RenderInfo *
|
|
|
|
* d0: WORD X
|
|
|
|
* d1: WORD Y
|
|
|
|
* d2: WORD Width
|
|
|
|
* d3: WORD Height
|
|
|
|
* d4: uae_u32 Pen
|
|
|
|
* d5: UBYTE Mask
|
|
|
|
* d7: uae_u32 RGBFormat
|
|
|
|
***********************************************************/
|
|
|
|
uae_u32 REGPARAM2 picasso_FillRect (struct regstruct *regs)
|
|
|
|
{
|
|
|
|
uaecptr renderinfo = m68k_areg (regs, 1);
|
|
|
|
uae_u32 X = (uae_u16)m68k_dreg (regs, 0);
|
|
|
|
uae_u32 Y = (uae_u16)m68k_dreg (regs, 1);
|
|
|
|
uae_u32 Width = (uae_u16)m68k_dreg (regs, 2);
|
|
|
|
uae_u32 Height = (uae_u16)m68k_dreg (regs, 3);
|
|
|
|
uae_u32 Pen = m68k_dreg (regs, 4);
|
|
|
|
uae_u8 Mask = (uae_u8) m68k_dreg (regs, 5);
|
|
|
|
RGBFTYPE RGBFormat = m68k_dreg (regs, 7);
|
|
|
|
|
|
|
|
uae_u8 *src;
|
|
|
|
uae_u8 *oldstart;
|
|
|
|
int Bpp;
|
|
|
|
struct RenderInfo ri;
|
|
|
|
uae_u32 result = 0;
|
|
|
|
|
|
|
|
#ifdef JIT
|
|
|
|
special_mem |= picasso_is_special_read | picasso_is_special;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
wgfx_flushline ();
|
|
|
|
|
|
|
|
if (CopyRenderInfoStructureA2U (renderinfo, &ri) && Y != 0xFFFF) {
|
|
|
|
if (ri.RGBFormat != RGBFormat)
|
|
|
|
write_log ("Weird Stuff!\n");
|
|
|
|
|
|
|
|
Bpp = GetBytesPerPixel (RGBFormat);
|
|
|
|
|
|
|
|
P96TRACE (("P96: FillRect(%d, %d, %d, %d) Pen 0x%x BPP %d BPR %d"
|
|
|
|
" Mask 0x%x\n", X, Y, Width, Height, Pen, Bpp,
|
|
|
|
ri.BytesPerRow, Mask));
|
|
|
|
|
|
|
|
if (Bpp > 1)
|
|
|
|
Mask = 0xFF;
|
|
|
|
|
|
|
|
if (Mask == 0xFF) {
|
|
|
|
if ((Width == 1) || (Height == 1)) {
|
|
|
|
unsigned int i;
|
|
|
|
uaecptr addr;
|
|
|
|
if (renderinfo_is_current_screen (&ri)) {
|
|
|
|
uae_u32 offset = X * Bpp + Y * ri.BytesPerRow;
|
|
|
|
addr = gfxmem_start + (uaecptr)(ri.Memory - gfxmemory) + offset;
|
|
|
|
|
|
|
|
if (Width == 1) {
|
|
|
|
for (i = 0; i < Height; i++) {
|
|
|
|
if( Bpp == 4 )
|
|
|
|
gfxmem_lput (addr + (i * picasso96_state.BytesPerRow), Pen);
|
|
|
|
else if (Bpp == 2)
|
|
|
|
gfxmem_wput (addr + (i * picasso96_state.BytesPerRow), Pen);
|
|
|
|
else
|
|
|
|
gfxmem_bput (addr + (i * picasso96_state.BytesPerRow), Pen);
|
|
|
|
}
|
|
|
|
} else if (Height == 1) {
|
|
|
|
for (i = 0; i < Width; i++) {
|
|
|
|
if (Bpp == 4)
|
|
|
|
gfxmem_lput (addr + (i*Bpp), Pen);
|
|
|
|
else if (Bpp == 2)
|
|
|
|
gfxmem_wput (addr + (i*Bpp), Pen);
|
|
|
|
else
|
|
|
|
gfxmem_bput( addr + (i*Bpp), Pen );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Do the fill-rect in the frame-buffer */
|
|
|
|
do_fillrect_frame_buffer (&ri, X, Y, Width, Height, Pen, Bpp, RGBFormat);
|
|
|
|
|
|
|
|
/* Now we do the on-screen display, if renderinfo points to it */
|
|
|
|
if (renderinfo_is_current_screen (&ri)) {
|
|
|
|
src = ri.Memory + X * Bpp + Y * ri.BytesPerRow;
|
|
|
|
X = X - picasso96_state.XOffset;
|
|
|
|
Y = Y - picasso96_state.YOffset;
|
|
|
|
if ((int)X < 0) {Width = Width + X; X=0;}
|
|
|
|
if ((int)Width < 1) return 1;
|
|
|
|
if ((int)Y < 0) {Height = Height + Y; Y=0;}
|
|
|
|
if ((int)Height < 1) return 1;
|
|
|
|
|
|
|
|
/* Argh - why does P96Speed do this to me, with FillRect only?! */
|
|
|
|
if ((X < picasso96_state.Width) && (Y < picasso96_state.Height)) {
|
|
|
|
if (X + Width > picasso96_state.Width)
|
|
|
|
Width = picasso96_state.Width - X;
|
|
|
|
if (Y+Height > picasso96_state.Height)
|
|
|
|
Height = picasso96_state.Height - Y;
|
|
|
|
|
|
|
|
do_fillrect (src, X, Y, Width, Height, Pen, Bpp, RGBFormat);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
result = 1;
|
|
|
|
} else {
|
|
|
|
/* We get here only if Mask != 0xFF */
|
|
|
|
if (Bpp != 1) {
|
|
|
|
P96TRACE (("P96: WARNING - FillRect() has unhandled mask 0x%x with Bpp %d."\
|
|
|
|
" Using fall-back routine.\n", Mask, Bpp));
|
|
|
|
} else {
|
|
|
|
Pen &= Mask;
|
|
|
|
Mask = ~Mask;
|
|
|
|
oldstart = ri.Memory + Y * ri.BytesPerRow + X * Bpp;
|
|
|
|
{
|
|
|
|
uae_u8 *start = oldstart;
|
|
|
|
uae_u8 *end = start + Height * ri.BytesPerRow;
|
|
|
|
for (; start != end; start += ri.BytesPerRow) {
|
|
|
|
uae_u8 *p = start;
|
|
|
|
unsigned long cols;
|
|
|
|
for (cols = 0; cols < Width; cols++) {
|
|
|
|
uae_u32 tmpval = do_get_mem_byte (p + cols) & Mask;
|
|
|
|
do_put_mem_byte (p + cols, (uae_u8)(Pen | tmpval));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (renderinfo_is_current_screen (&ri))
|
|
|
|
do_blit (&ri, Bpp, X, Y, X, Y, Width, Height, BLIT_SRC, 0);
|
|
|
|
result = 1;
|
|
|
|
}
|
2014-01-25 12:19:44 +01:00
|
|
|
}
|
2009-05-05 17:36:48 +02:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* BlitRect() is a generic (any chunky pixel format) rectangle copier.
|
|
|
|
* NOTE: If dstri is NULL, then we're only dealing with one RenderInfo area,
|
|
|
|
* and called from picasso_BlitRect().
|
|
|
|
*
|
|
|
|
* OpCodes:
|
|
|
|
* 0 = FALSE: dst = 0
|
|
|
|
* 1 = NOR: dst = ~(src | dst)
|
|
|
|
* 2 = ONLYDST: dst = dst & ~src
|
|
|
|
* 3 = NOTSRC: dst = ~src
|
|
|
|
* 4 = ONLYSRC: dst = src & ~dst
|
|
|
|
* 5 = NOTDST: dst = ~dst
|
|
|
|
* 6 = EOR: dst = src^dst
|
|
|
|
* 7 = NAND: dst = ~(src & dst)
|
|
|
|
* 8 = AND: dst = (src & dst)
|
|
|
|
* 9 = NEOR: dst = ~(src ^ dst)
|
|
|
|
*10 = DST: dst = dst
|
|
|
|
*11 = NOTONLYSRC: dst = ~src | dst
|
|
|
|
*12 = SRC: dst = src
|
|
|
|
*13 = NOTONLYDST: dst = ~dst | src
|
|
|
|
*14 = OR: dst = src | dst
|
|
|
|
*15 = TRUE: dst = 0xFF
|
|
|
|
*/
|
|
|
|
struct blitdata
|
|
|
|
{
|
|
|
|
struct RenderInfo ri_struct;
|
|
|
|
struct RenderInfo dstri_struct;
|
|
|
|
struct RenderInfo *ri; /* Self-referencing pointers */
|
|
|
|
struct RenderInfo *dstri;
|
|
|
|
unsigned long srcx;
|
|
|
|
unsigned long srcy;
|
|
|
|
unsigned long dstx;
|
|
|
|
unsigned long dsty;
|
|
|
|
unsigned long width;
|
|
|
|
unsigned long height;
|
|
|
|
uae_u8 mask;
|
|
|
|
BLIT_OPCODE opcode;
|
|
|
|
} blitrectdata;
|
|
|
|
|
|
|
|
STATIC_INLINE int BlitRectHelper (void)
|
|
|
|
{
|
|
|
|
struct RenderInfo *ri = blitrectdata.ri;
|
|
|
|
struct RenderInfo *dstri = blitrectdata.dstri;
|
|
|
|
unsigned long srcx = blitrectdata.srcx;
|
|
|
|
unsigned long srcy = blitrectdata.srcy;
|
|
|
|
unsigned long dstx = blitrectdata.dstx;
|
|
|
|
unsigned long dsty = blitrectdata.dsty;
|
|
|
|
unsigned long width = blitrectdata.width;
|
|
|
|
unsigned long height = blitrectdata.height;
|
|
|
|
uae_u8 mask = blitrectdata.mask;
|
|
|
|
BLIT_OPCODE opcode = blitrectdata.opcode;
|
|
|
|
|
|
|
|
uae_u8 Bpp = GetBytesPerPixel (ri->RGBFormat);
|
|
|
|
int can_do_visible_blit = 0;
|
|
|
|
|
|
|
|
if (opcode == BLIT_DST) {
|
2014-01-25 12:19:44 +01:00
|
|
|
write_log ("P96: WARNING - BlitRect() being called with opcode of BLIT_DST\n");
|
|
|
|
return 1;
|
2009-05-05 17:36:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we have no destination RenderInfo, then we're dealing with a
|
|
|
|
* single-buffer action, called from picasso_BlitRect(). The code in
|
|
|
|
* do_blitrect_frame_buffer() deals with the frame-buffer, while the
|
|
|
|
* do_blit() code deals with the visible screen.
|
|
|
|
*
|
|
|
|
* If we have a destination RenderInfo, then we've been called from
|
|
|
|
* picasso_BlitRectNoMaskComplete() and we need to put the results on the
|
|
|
|
* screen from the frame-buffer.
|
|
|
|
*/
|
|
|
|
if (dstri == NULL) {
|
|
|
|
if (mask != 0xFF && Bpp > 1) {
|
|
|
|
mask = 0xFF;
|
|
|
|
}
|
|
|
|
dstri = ri;
|
|
|
|
can_do_visible_blit = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Do our virtual frame-buffer memory first */
|
|
|
|
do_blitrect_frame_buffer (ri, dstri, srcx, srcy, dstx, dsty, width, height,
|
|
|
|
mask, opcode);
|
|
|
|
|
|
|
|
|
|
|
|
/* Now we do the on-screen display, if renderinfo points to it */
|
|
|
|
if (renderinfo_is_current_screen (dstri)) {
|
|
|
|
if (mask == 0xFF || Bpp > 1) {
|
|
|
|
if (can_do_visible_blit)
|
|
|
|
do_blit (dstri, Bpp, srcx, srcy, dstx, dsty, width, height, opcode, 1);
|
|
|
|
else
|
|
|
|
do_blit (dstri, Bpp, dstx, dsty, dstx, dsty, width, height, opcode, 0);
|
|
|
|
} else
|
|
|
|
do_blit (dstri, Bpp, dstx, dsty, dstx, dsty, width, height, opcode, 0);
|
|
|
|
|
|
|
|
P96TRACE (("P96: Did do_blit 1 in BlitRect()\n"));
|
|
|
|
} else {
|
2014-01-25 12:19:44 +01:00
|
|
|
P96TRACE (("P96: Did not do_blit 1 in BlitRect()\n"));
|
2009-05-05 17:36:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
STATIC_INLINE int BlitRect (uaecptr ri, uaecptr dstri,
|
2014-01-25 12:19:44 +01:00
|
|
|
unsigned long srcx, unsigned long srcy,
|
2009-05-05 17:36:48 +02:00
|
|
|
unsigned long dstx, unsigned long dsty,
|
2014-01-25 12:19:44 +01:00
|
|
|
unsigned long width, unsigned long height,
|
2009-05-05 17:36:48 +02:00
|
|
|
uae_u8 mask, BLIT_OPCODE opcode)
|
|
|
|
{
|
|
|
|
/* Set up the params */
|
|
|
|
CopyRenderInfoStructureA2U (ri, &blitrectdata.ri_struct);
|
|
|
|
blitrectdata.ri = &blitrectdata.ri_struct;
|
|
|
|
|
|
|
|
if (dstri) {
|
|
|
|
CopyRenderInfoStructureA2U( dstri, &blitrectdata.dstri_struct );
|
|
|
|
blitrectdata.dstri = &blitrectdata.dstri_struct;
|
|
|
|
} else
|
|
|
|
blitrectdata.dstri = NULL;
|
|
|
|
|
|
|
|
blitrectdata.srcx = srcx;
|
|
|
|
blitrectdata.srcy = srcy;
|
|
|
|
blitrectdata.dstx = dstx;
|
|
|
|
blitrectdata.dsty = dsty;
|
|
|
|
blitrectdata.width = width;
|
|
|
|
blitrectdata.height = height;
|
|
|
|
blitrectdata.mask = mask;
|
|
|
|
blitrectdata.opcode = opcode;
|
|
|
|
|
|
|
|
return BlitRectHelper();
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************
|
|
|
|
BlitRect:
|
|
|
|
***********************************************************
|
|
|
|
* a0: struct BoardInfo
|
|
|
|
* a1: struct RenderInfo
|
|
|
|
* d0: WORD SrcX
|
|
|
|
* d1: WORD SrcY
|
|
|
|
* d2: WORD DstX
|
|
|
|
* d3: WORD DstY
|
|
|
|
* d4: WORD Width
|
|
|
|
* d5: WORD Height
|
|
|
|
* d6: UBYTE Mask
|
|
|
|
* d7: uae_u32 RGBFormat
|
|
|
|
***********************************************************/
|
|
|
|
uae_u32 REGPARAM2 picasso_BlitRect (struct regstruct *regs)
|
|
|
|
{
|
|
|
|
uaecptr renderinfo = m68k_areg (regs, 1);
|
|
|
|
unsigned long srcx = (uae_u16)m68k_dreg (regs, 0);
|
|
|
|
unsigned long srcy = (uae_u16)m68k_dreg (regs, 1);
|
|
|
|
unsigned long dstx = (uae_u16)m68k_dreg (regs, 2);
|
|
|
|
unsigned long dsty = (uae_u16)m68k_dreg (regs, 3);
|
|
|
|
unsigned long width = (uae_u16)m68k_dreg (regs, 4);
|
|
|
|
unsigned long height = (uae_u16)m68k_dreg (regs, 5);
|
|
|
|
uae_u8 Mask = (uae_u8) m68k_dreg (regs, 6);
|
|
|
|
|
|
|
|
int result = 0;
|
|
|
|
|
|
|
|
#ifdef JIT
|
|
|
|
special_mem |= picasso_is_special_read | picasso_is_special;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
wgfx_flushline ();
|
|
|
|
|
|
|
|
P96TRACE (("P96: BlitRect(%d, %d, %d, %d, %d, %d, 0x%x)\n", srcx, srcy,
|
|
|
|
dstx, dsty, width, height, Mask));
|
|
|
|
|
2014-01-25 12:19:44 +01:00
|
|
|
result = BlitRect (renderinfo, 0, srcx, srcy, dstx, dsty,
|
2009-05-05 17:36:48 +02:00
|
|
|
width, height, Mask, BLIT_SRC);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************
|
|
|
|
BlitRectNoMaskComplete:
|
|
|
|
***********************************************************
|
|
|
|
* a0: struct BoardInfo
|
|
|
|
* a1: struct RenderInfo (src)
|
|
|
|
* a2: struct RenderInfo (dst)
|
|
|
|
* d0: WORD SrcX
|
|
|
|
* d1: WORD SrcY
|
|
|
|
* d2: WORD DstX
|
|
|
|
* d3: WORD DstY
|
|
|
|
* d4: WORD Width
|
|
|
|
* d5: WORD Height
|
|
|
|
* d6: UBYTE OpCode
|
|
|
|
* d7: uae_u32 RGBFormat
|
|
|
|
* NOTE: MUST return 0 in D0 if we're not handling this operation
|
|
|
|
* because the RGBFormat or opcode aren't supported.
|
|
|
|
* OTHERWISE return 1
|
|
|
|
***********************************************************/
|
|
|
|
uae_u32 REGPARAM2 picasso_BlitRectNoMaskComplete (struct regstruct *regs)
|
|
|
|
{
|
|
|
|
uaecptr srcri = m68k_areg (regs, 1);
|
|
|
|
uaecptr dstri = m68k_areg (regs, 2);
|
|
|
|
unsigned long srcx = (uae_u16)m68k_dreg (regs, 0);
|
|
|
|
unsigned long srcy = (uae_u16)m68k_dreg (regs, 1);
|
|
|
|
unsigned long dstx = (uae_u16)m68k_dreg (regs, 2);
|
|
|
|
unsigned long dsty = (uae_u16)m68k_dreg (regs, 3);
|
|
|
|
unsigned long width = (uae_u16)m68k_dreg (regs, 4);
|
|
|
|
unsigned long height = (uae_u16)m68k_dreg (regs, 5);
|
|
|
|
uae_u8 OpCode = m68k_dreg (regs, 6);
|
|
|
|
/* uae_u32 RGBFmt = m68k_dreg (regs, 7); */
|
|
|
|
|
|
|
|
int result = 0;
|
|
|
|
|
|
|
|
#ifdef JIT
|
|
|
|
special_mem |= picasso_is_special_read | picasso_is_special;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
wgfx_flushline ();
|
|
|
|
|
|
|
|
P96TRACE (("P96: BlitRectNoMaskComplete() op 0x%2x, xy(%4d,%4d) -->"
|
|
|
|
" xy(%4d,%4d), wh(%4d,%4d)\n",
|
|
|
|
OpCode, srcx, srcy, dstx, dsty, width, height));
|
|
|
|
|
|
|
|
result = BlitRect (srcri, dstri, srcx, srcy, dstx, dsty,
|
|
|
|
width, height, 0xFF, OpCode);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This utility function is used both by BlitTemplate() and BlitPattern() */
|
|
|
|
STATIC_INLINE void PixelWrite1 (uae_u8 * mem, int bits, uae_u32 fgpen, uae_u32 mask)
|
|
|
|
{
|
|
|
|
if (mask != 0xFF)
|
|
|
|
fgpen = (fgpen & mask) | (do_get_mem_byte (mem + bits) & ~mask);
|
|
|
|
do_put_mem_byte (mem + bits, fgpen);
|
|
|
|
}
|
|
|
|
|
|
|
|
STATIC_INLINE void PixelWrite2 (uae_u8 * mem, int bits, uae_u32 fgpen)
|
|
|
|
{
|
|
|
|
do_put_mem_word (((uae_u16 *) mem) + bits, fgpen);
|
|
|
|
}
|
|
|
|
|
|
|
|
STATIC_INLINE void PixelWrite3 (uae_u8 * mem, int bits, uae_u32 fgpen)
|
|
|
|
{
|
|
|
|
do_put_mem_byte (mem + bits * 3, fgpen & 0x000000FF);
|
|
|
|
*(uae_u16 *) (mem + bits * 3 + 1) = (fgpen & 0x00FFFF00) >> 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
STATIC_INLINE void PixelWrite4 (uae_u8 * mem, int bits, uae_u32 fgpen)
|
|
|
|
{
|
|
|
|
do_put_mem_long (((uae_u32 *) mem) + bits, fgpen);
|
|
|
|
}
|
|
|
|
|
|
|
|
STATIC_INLINE void PixelWrite (uae_u8 * mem, int bits, uae_u32 fgpen, uae_u8 Bpp, uae_u32 mask)
|
|
|
|
{
|
|
|
|
switch (Bpp) {
|
|
|
|
case 1:
|
|
|
|
if (mask != 0xFF)
|
|
|
|
fgpen = (fgpen & mask) | (do_get_mem_byte (mem + bits) & ~mask);
|
|
|
|
do_put_mem_byte (mem + bits, fgpen);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
do_put_mem_word (((uae_u16 *) mem) + bits, fgpen);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
do_put_mem_byte (mem + bits * 3, fgpen & 0x000000FF);
|
|
|
|
*(uae_u16 *) (mem + bits * 3 + 1) = (fgpen & 0x00FFFF00) >> 8;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
do_put_mem_long (((uae_u32 *) mem) + bits, fgpen);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* BlitPattern:
|
|
|
|
*
|
|
|
|
* Synopsis:BlitPattern(bi, ri, pattern, X, Y, Width, Height, Mask, RGBFormat);
|
|
|
|
* Inputs:
|
|
|
|
* a0:struct BoardInfo *bi
|
|
|
|
* a1:struct RenderInfo *ri
|
|
|
|
* a2:struct Pattern *pattern
|
|
|
|
* d0.w:X
|
|
|
|
* d1.w:Y
|
|
|
|
* d2.w:Width
|
|
|
|
* d3.w:Height
|
|
|
|
* d4.w:Mask
|
|
|
|
* d7.l:RGBFormat
|
|
|
|
*
|
|
|
|
* This function is used to paint a pattern on the board memory using the
|
|
|
|
* blitter. It is called by BltPattern, if a AreaPtrn is used with positive
|
|
|
|
* AreaPtSz. The pattern consists of a b/w image using a single plane of image
|
|
|
|
* data which will be expanded repeatedly to the destination RGBFormat using
|
|
|
|
* ForeGround and BackGround pens as well as draw modes. The width of the
|
|
|
|
* pattern data is always 16 pixels (one word) and the height is calculated as
|
|
|
|
* 2^Size. The data must be shifted up and to the left by XOffset and YOffset
|
|
|
|
* pixels at the beginning.
|
|
|
|
*/
|
|
|
|
uae_u32 REGPARAM picasso_BlitPattern (struct regstruct *regs)
|
|
|
|
{
|
|
|
|
uaecptr rinf = m68k_areg (regs, 1);
|
|
|
|
uaecptr pinf = m68k_areg (regs, 2);
|
|
|
|
unsigned long X = (uae_u16)m68k_dreg (regs, 0);
|
|
|
|
unsigned long Y = (uae_u16)m68k_dreg (regs, 1);
|
|
|
|
unsigned long W = (uae_u16)m68k_dreg (regs, 2);
|
|
|
|
unsigned long H = (uae_u16)m68k_dreg (regs, 3);
|
|
|
|
uae_u8 Mask = (uae_u8) m68k_dreg (regs, 4);
|
|
|
|
uae_u32 RGBFmt = m68k_dreg (regs, 7);
|
|
|
|
|
|
|
|
uae_u8 Bpp = GetBytesPerPixel (RGBFmt);
|
|
|
|
int inversion = 0;
|
|
|
|
struct RenderInfo ri;
|
|
|
|
struct Pattern pattern;
|
|
|
|
unsigned long rows;
|
|
|
|
uae_u32 fgpen;
|
|
|
|
uae_u8 *uae_mem;
|
|
|
|
int xshift;
|
|
|
|
unsigned long ysize_mask;
|
|
|
|
int result = 0;
|
|
|
|
|
|
|
|
#ifdef JIT
|
|
|
|
special_mem |= picasso_is_special_read | picasso_is_special;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
wgfx_flushline ();
|
|
|
|
|
|
|
|
if (CopyRenderInfoStructureA2U (rinf, &ri)
|
2014-01-25 12:19:44 +01:00
|
|
|
&& CopyPatternStructureA2U (pinf, &pattern)) {
|
2009-05-05 17:36:48 +02:00
|
|
|
Bpp = GetBytesPerPixel (ri.RGBFormat);
|
|
|
|
uae_mem = ri.Memory + Y*ri.BytesPerRow + X*Bpp; /* offset with address */
|
|
|
|
|
|
|
|
if (pattern.DrawMode & INVERS)
|
|
|
|
inversion = 1;
|
|
|
|
|
|
|
|
pattern.DrawMode &= 0x03;
|
|
|
|
|
|
|
|
if (Mask != 0xFF) {
|
|
|
|
if( Bpp > 1 )
|
|
|
|
Mask = 0xFF;
|
|
|
|
|
|
|
|
if( pattern.DrawMode == COMP)
|
|
|
|
P96TRACE (("P96: WARNING - BlitPattern() has unhandled mask 0x%x with"\
|
2014-01-25 12:19:44 +01:00
|
|
|
" COMP DrawMode. Using fall-back routine.\n", Mask));
|
2009-05-05 17:36:48 +02:00
|
|
|
else
|
|
|
|
result = 1;
|
|
|
|
} else
|
|
|
|
result = 1;
|
|
|
|
|
|
|
|
if (result) {
|
|
|
|
# ifdef P96TRACING_ENABLED
|
|
|
|
DumpPattern (&pattern);
|
|
|
|
# endif
|
|
|
|
ysize_mask = (1 << pattern.Size) - 1;
|
|
|
|
xshift = pattern.XOffset & 15;
|
|
|
|
|
|
|
|
for (rows = 0; rows < H; rows++, uae_mem += ri.BytesPerRow) {
|
|
|
|
unsigned long prow = (rows + pattern.YOffset) & ysize_mask;
|
|
|
|
unsigned int d = do_get_mem_word (((uae_u16 *)pattern.Memory) + prow);
|
|
|
|
uae_u8 *uae_mem2 = uae_mem;
|
|
|
|
unsigned long cols;
|
|
|
|
|
|
|
|
if (xshift != 0)
|
|
|
|
d = (d << xshift) | (d >> (16 - xshift));
|
|
|
|
|
|
|
|
for (cols = 0; cols < W; cols += 16, uae_mem2 += Bpp << 4) {
|
|
|
|
long bits;
|
|
|
|
long max = W - cols;
|
|
|
|
unsigned int data = d;
|
|
|
|
|
|
|
|
if (max > 16)
|
|
|
|
max = 16;
|
|
|
|
|
|
|
|
for (bits = 0; bits < max; bits++) {
|
|
|
|
int bit_set = data & 0x8000;
|
|
|
|
data <<= 1;
|
|
|
|
switch (pattern.DrawMode) {
|
|
|
|
case JAM1:
|
|
|
|
if (inversion)
|
|
|
|
bit_set = !bit_set;
|
|
|
|
if (bit_set)
|
|
|
|
PixelWrite (uae_mem2, bits, pattern.FgPen, Bpp, Mask);
|
|
|
|
break;
|
|
|
|
case JAM2:
|
|
|
|
if (inversion)
|
|
|
|
bit_set = !bit_set;
|
|
|
|
if (bit_set)
|
|
|
|
PixelWrite (uae_mem2, bits, pattern.FgPen, Bpp, Mask);
|
|
|
|
else
|
|
|
|
PixelWrite (uae_mem2, bits, pattern.BgPen, Bpp, Mask);
|
|
|
|
break;
|
|
|
|
case COMP:
|
|
|
|
if (bit_set) {
|
|
|
|
fgpen = pattern.FgPen;
|
|
|
|
|
|
|
|
switch (Bpp) {
|
|
|
|
case 1: {
|
|
|
|
uae_u8 *addr = uae_mem2 + bits;
|
|
|
|
do_put_mem_byte (addr, (uae_u8)(do_get_mem_byte (addr) ^ fgpen));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 2: {
|
|
|
|
uae_u16 *addr = ((uae_u16 *)uae_mem2) + bits;
|
|
|
|
do_put_mem_word (addr, (uae_u16)(do_get_mem_word (addr) ^ fgpen));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 3: {
|
|
|
|
uae_u32 *addr = (uae_u32 *)(uae_mem2 + bits * 3);
|
|
|
|
do_put_mem_long (addr, do_get_mem_long (addr) ^ (fgpen & 0x00FFFFFF));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 4: {
|
|
|
|
uae_u32 *addr = ((uae_u32 *)uae_mem2) + bits;
|
|
|
|
do_put_mem_long (addr, do_get_mem_long (addr) ^ fgpen);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} /* switch (Bpp) */
|
|
|
|
}
|
|
|
|
break;
|
2014-01-25 12:19:44 +01:00
|
|
|
} /* switch (pattern.DrawMode) */
|
|
|
|
} /* for (bits) */
|
|
|
|
} /* for (cols) */
|
|
|
|
} /* for (rows) */
|
2009-05-05 17:36:48 +02:00
|
|
|
|
|
|
|
/* If we need to update a second-buffer (extra_mem is set), then do it only if visible! */
|
2014-01-25 12:19:44 +01:00
|
|
|
if (picasso_vidinfo.extra_mem && renderinfo_is_current_screen (&ri))
|
2009-05-05 17:36:48 +02:00
|
|
|
do_blit (&ri, Bpp, X, Y, X, Y, W, H, BLIT_SRC, 0);
|
|
|
|
|
|
|
|
result = 1;
|
2014-01-25 12:19:44 +01:00
|
|
|
}
|
2009-05-05 17:36:48 +02:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************
|
|
|
|
BlitTemplate:
|
|
|
|
**************************************************
|
|
|
|
* Synopsis: BlitTemplate(bi, ri, template, X, Y, Width, Height, Mask, RGBFormat);
|
|
|
|
* a0: struct BoardInfo *bi
|
|
|
|
* a1: struct RenderInfo *ri
|
|
|
|
* a2: struct Template *template
|
|
|
|
* d0.w: X
|
|
|
|
* d1.w: Y
|
|
|
|
* d2.w: Width
|
|
|
|
* d3.w: Height
|
|
|
|
* d4.w: Mask
|
|
|
|
* d7.l: RGBFormat
|
|
|
|
*
|
|
|
|
* This function is used to paint a template on the board memory using the
|
|
|
|
* blitter. It is called by BltPattern and BltTemplate. The template consists
|
|
|
|
* of a b/w image using a single plane of image data which will be expanded to
|
|
|
|
* the destination RGBFormat using ForeGround and BackGround pens as well as
|
|
|
|
* draw modes.
|
|
|
|
***********************************************************************************/
|
|
|
|
uae_u32 REGPARAM2 picasso_BlitTemplate (struct regstruct *regs)
|
|
|
|
{
|
|
|
|
uaecptr rinf = m68k_areg (regs, 1);
|
|
|
|
uaecptr tmpl = m68k_areg (regs, 2);
|
|
|
|
unsigned long X = (uae_u16)m68k_dreg (regs, 0);
|
|
|
|
unsigned long Y = (uae_u16)m68k_dreg (regs, 1);
|
|
|
|
unsigned long W = (uae_u16)m68k_dreg (regs, 2);
|
|
|
|
unsigned long H = (uae_u16)m68k_dreg (regs, 3);
|
|
|
|
uae_u16 Mask = (uae_u16)m68k_dreg (regs, 4);
|
|
|
|
|
|
|
|
uae_u8 inversion = 0;
|
|
|
|
struct Template tmp;
|
|
|
|
struct RenderInfo ri;
|
|
|
|
unsigned long rows;
|
|
|
|
int bitoffset;
|
|
|
|
uae_u32 fgpen;
|
|
|
|
uae_u8 *uae_mem, Bpp;
|
|
|
|
uae_u8 *tmpl_base;
|
|
|
|
uae_u32 result = 0;
|
|
|
|
|
|
|
|
#ifdef JIT
|
|
|
|
special_mem |= picasso_is_special_read | picasso_is_special;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
wgfx_flushline ();
|
|
|
|
|
|
|
|
if (CopyRenderInfoStructureA2U (rinf, &ri) && CopyTemplateStructureA2U (tmpl, &tmp)) {
|
|
|
|
Bpp = GetBytesPerPixel (ri.RGBFormat);
|
|
|
|
uae_mem = ri.Memory + Y*ri.BytesPerRow + X*Bpp; /* offset into address */
|
|
|
|
|
|
|
|
if (tmp.DrawMode & INVERS)
|
|
|
|
inversion = 1;
|
|
|
|
|
|
|
|
tmp.DrawMode &= 0x03;
|
|
|
|
|
|
|
|
if (Mask != 0xFF) {
|
|
|
|
if (Bpp > 1)
|
|
|
|
Mask = 0xFF;
|
|
|
|
|
|
|
|
if (tmp.DrawMode == COMP) {
|
|
|
|
P96TRACE (("P96: WARNING - BlitTemplate() has unhandled mask 0x%x with"\
|
|
|
|
" COMP DrawMode. Using fall-back routine.\n", Mask));
|
|
|
|
# if 0 //def _WIN32
|
|
|
|
flushpixels(); //only need in the windows Version
|
|
|
|
# endif
|
|
|
|
return 0;
|
|
|
|
} else
|
2014-01-25 12:19:44 +01:00
|
|
|
result = 1;
|
|
|
|
} else
|
|
|
|
result = 1;
|
2009-05-05 17:36:48 +02:00
|
|
|
|
|
|
|
#if 1
|
2014-01-25 12:19:44 +01:00
|
|
|
if (tmp.DrawMode == COMP) {
|
|
|
|
/* workaround, let native blitter handle COMP mode */
|
2009-05-05 17:36:48 +02:00
|
|
|
# if 0 //def _WIN32
|
|
|
|
flushpixels();
|
|
|
|
# endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (result) {
|
|
|
|
P96TRACE (("P96: BlitTemplate() xy(%d,%d), wh(%d,%d) draw 0x%x fg 0x%x bg 0x%x\n",
|
|
|
|
X, Y, W, H, tmp.DrawMode, tmp.FgPen, tmp.BgPen));
|
|
|
|
|
|
|
|
bitoffset = tmp.XOffset % 8;
|
|
|
|
|
|
|
|
# if defined( P96TRACING_ENABLED ) && ( P96TRACING_LEVEL > 0 )
|
|
|
|
DumpTemplate (&tmp, W, H);
|
|
|
|
# endif
|
|
|
|
|
|
|
|
tmpl_base = tmp.Memory + tmp.XOffset / 8;
|
|
|
|
|
|
|
|
for (rows = 0; rows < H; rows++, uae_mem += ri.BytesPerRow, tmpl_base += tmp.BytesPerRow) {
|
|
|
|
unsigned long cols;
|
|
|
|
uae_u8 *tmpl_mem = tmpl_base;
|
|
|
|
uae_u8 *uae_mem2 = uae_mem;
|
|
|
|
unsigned int data = *tmpl_mem;
|
|
|
|
|
|
|
|
for (cols = 0; cols < W; cols += 8, uae_mem2 += Bpp << 3) {
|
|
|
|
unsigned int byte;
|
|
|
|
long bits;
|
|
|
|
long max = W - cols;
|
|
|
|
|
|
|
|
if (max > 8)
|
|
|
|
max = 8;
|
|
|
|
|
|
|
|
data <<= 8;
|
|
|
|
data |= *++tmpl_mem;
|
|
|
|
|
|
|
|
byte = data >> (8 - bitoffset);
|
|
|
|
|
|
|
|
for (bits = 0; bits < max; bits++) {
|
|
|
|
int bit_set = (byte & 0x80);
|
|
|
|
byte <<= 1;
|
|
|
|
switch (tmp.DrawMode) {
|
|
|
|
case JAM1:
|
|
|
|
if (inversion)
|
|
|
|
bit_set = !bit_set;
|
|
|
|
if (bit_set) {
|
|
|
|
fgpen = tmp.FgPen;
|
|
|
|
PixelWrite (uae_mem2, bits, fgpen, Bpp, Mask);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case JAM2:
|
|
|
|
if (inversion)
|
|
|
|
bit_set = !bit_set;
|
|
|
|
fgpen = tmp.BgPen;
|
|
|
|
if (bit_set)
|
|
|
|
fgpen = tmp.FgPen;
|
|
|
|
PixelWrite (uae_mem2, bits, fgpen, Bpp, Mask);
|
|
|
|
break;
|
|
|
|
case COMP:
|
|
|
|
if (bit_set) {
|
|
|
|
fgpen = tmp.FgPen;
|
|
|
|
|
|
|
|
switch (Bpp) {
|
|
|
|
case 1: {
|
|
|
|
uae_u8 *addr = uae_mem2 + bits;
|
|
|
|
do_put_mem_byte (addr, (uae_u8) (do_get_mem_byte (addr) ^ fgpen));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 2: {
|
|
|
|
uae_u16 *addr = ((uae_u16 *)uae_mem2) + bits;
|
|
|
|
do_put_mem_word (addr, (uae_u16) (do_get_mem_word (addr) ^ fgpen));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 3: {
|
|
|
|
uae_u32 *addr = (uae_u32 *)(uae_mem2 + bits * 3);
|
|
|
|
do_put_mem_long (addr, do_get_mem_long (addr) ^ (fgpen & 0x00FFFFFF));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 4: {
|
|
|
|
uae_u32 *addr = ((uae_u32 *)uae_mem2) + bits;
|
|
|
|
do_put_mem_long (addr, do_get_mem_long (addr) ^ fgpen);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} /* switch (Bpp) */
|
|
|
|
} /* if (bit_set) */
|
|
|
|
break;
|
|
|
|
} /* switch (tmp.DrawMode) */
|
|
|
|
} /* for (bits) */
|
|
|
|
} /* for (cols) */
|
|
|
|
} /* for (rows) */
|
|
|
|
|
|
|
|
/* If we need to update a second-buffer (extra_mem is set), then do it only if visible! */
|
|
|
|
if (picasso_vidinfo.extra_mem && renderinfo_is_current_screen (&ri))
|
|
|
|
do_blit (&ri, Bpp, X, Y, X, Y, W, H, BLIT_SRC, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* CalculateBytesPerRow:
|
|
|
|
* a0: struct BoardInfo
|
|
|
|
* d0: uae_u16 Width
|
|
|
|
* d7: RGBFTYPE RGBFormat
|
|
|
|
* This function calculates the amount of bytes needed for a line of
|
|
|
|
* "Width" pixels in the given RGBFormat.
|
|
|
|
*/
|
|
|
|
uae_u32 REGPARAM2 picasso_CalculateBytesPerRow (struct regstruct *regs)
|
|
|
|
{
|
|
|
|
uae_u16 width = m68k_dreg (regs, 0);
|
|
|
|
uae_u32 type = m68k_dreg (regs, 7);
|
|
|
|
|
|
|
|
width = GetBytesPerPixel (type) * width;
|
|
|
|
P96TRACE (("P96: CalculateBytesPerRow() = %d\n", width));
|
|
|
|
|
|
|
|
return width;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SetDisplay:
|
|
|
|
* a0: struct BoardInfo
|
|
|
|
* d0: BOOL state
|
|
|
|
* This function enables and disables the video display.
|
|
|
|
*
|
|
|
|
* NOTE: return the opposite of the state
|
|
|
|
*/
|
|
|
|
uae_u32 REGPARAM2 picasso_SetDisplay (struct regstruct *regs)
|
|
|
|
{
|
|
|
|
uae_u32 state = m68k_dreg (regs, 0);
|
|
|
|
P96TRACE (("P96: SetDisplay(%d)\n", state));
|
|
|
|
return !state;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* WaitVerticalSync:
|
|
|
|
* a0: struct BoardInfo
|
|
|
|
* This function waits for the next horizontal retrace.
|
|
|
|
*/
|
|
|
|
uae_u32 REGPARAM2 picasso_WaitVerticalSync (struct regstruct *regs)
|
|
|
|
{
|
|
|
|
/*write_log ("WaitVerticalSync()\n"); */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* NOTE: Watch for those planeptrs of 0x00000000 and 0xFFFFFFFF for all zero / all one bitmaps !!!! */
|
|
|
|
static void PlanarToChunky (struct RenderInfo *ri, struct BitMap *bm,
|
|
|
|
unsigned long srcx, unsigned long srcy,
|
|
|
|
unsigned long dstx, unsigned long dsty,
|
|
|
|
unsigned long width, unsigned long height,
|
|
|
|
uae_u8 mask)
|
|
|
|
{
|
|
|
|
int j;
|
|
|
|
|
|
|
|
uae_u8 *PLANAR[8];
|
|
|
|
uae_u8 *image = ri->Memory + dstx * GetBytesPerPixel (ri->RGBFormat)
|
2014-01-25 12:19:44 +01:00
|
|
|
+ dsty * ri->BytesPerRow;
|
2009-05-05 17:36:48 +02:00
|
|
|
int Depth = bm->Depth;
|
|
|
|
unsigned long rows, bitoffset = srcx & 7;
|
|
|
|
long eol_offset;
|
|
|
|
|
|
|
|
/* Set up our bm->Planes[] pointers to the right horizontal offset */
|
|
|
|
for (j = 0; j < Depth; j++) {
|
|
|
|
uae_u8 *p = bm->Planes[j];
|
|
|
|
if (p != &all_zeros_bitmap && p != &all_ones_bitmap)
|
|
|
|
p += srcx / 8 + srcy * bm->BytesPerRow;
|
|
|
|
PLANAR[j] = p;
|
|
|
|
if ((mask & (1 << j)) == 0)
|
|
|
|
PLANAR[j] = &all_zeros_bitmap;
|
|
|
|
}
|
|
|
|
eol_offset = (long) bm->BytesPerRow - (long) ((width + 7) >> 3);
|
|
|
|
for (rows = 0; rows < height; rows++, image += ri->BytesPerRow) {
|
|
|
|
unsigned long cols;
|
|
|
|
|
|
|
|
for (cols = 0; cols < width; cols += 8) {
|
|
|
|
int k;
|
|
|
|
uae_u32 a = 0, b = 0;
|
|
|
|
unsigned int msk = 0xFF;
|
|
|
|
long tmp = cols + 8 - width;
|
|
|
|
if (tmp > 0) {
|
|
|
|
msk <<= tmp;
|
|
|
|
b = do_get_mem_long ((uae_u32 *) (image + cols + 4));
|
|
|
|
if (tmp < 4)
|
|
|
|
b &= 0xFFFFFFFF >> (32 - tmp * 8);
|
|
|
|
else if (tmp > 4) {
|
|
|
|
a = do_get_mem_long ((uae_u32 *) (image + cols));
|
|
|
|
a &= 0xFFFFFFFF >> (64 - tmp * 8);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (k = 0; k < Depth; k++) {
|
|
|
|
unsigned int data;
|
|
|
|
if (PLANAR[k] == &all_zeros_bitmap)
|
|
|
|
data = 0;
|
|
|
|
else if (PLANAR[k] == &all_ones_bitmap)
|
|
|
|
data = 0xFF;
|
|
|
|
else {
|
|
|
|
data = (uae_u8) (do_get_mem_word ((uae_u16 *) PLANAR[k]) >> (8 - bitoffset));
|
|
|
|
PLANAR[k]++;
|
|
|
|
}
|
|
|
|
data &= msk;
|
|
|
|
a |= p2ctab[data][0] << k;
|
|
|
|
b |= p2ctab[data][1] << k;
|
|
|
|
}
|
|
|
|
do_put_mem_long ((uae_u32 *) (image + cols), a);
|
|
|
|
do_put_mem_long ((uae_u32 *) (image + cols + 4), b);
|
|
|
|
}
|
|
|
|
for (j = 0; j < Depth; j++) {
|
|
|
|
if (PLANAR[j] != &all_zeros_bitmap && PLANAR[j] != &all_ones_bitmap) {
|
|
|
|
PLANAR[j] += eol_offset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* BlitPlanar2Chunky:
|
|
|
|
* a0: struct BoardInfo *bi
|
|
|
|
* a1: struct BitMap *bm - source containing planar information and assorted details
|
|
|
|
* a2: struct RenderInfo *ri - dest area and its details
|
|
|
|
* d0.w: SrcX
|
|
|
|
* d1.w: SrcY
|
|
|
|
* d2.w: DstX
|
|
|
|
* d3.w: DstY
|
|
|
|
* d4.w: SizeX
|
|
|
|
* d5.w: SizeY
|
|
|
|
* d6.b: MinTerm - uh oh!
|
|
|
|
* d7.b: Mask - uh oh!
|
|
|
|
*
|
|
|
|
* This function is currently used to blit from planar bitmaps within system
|
|
|
|
* memory to chunky bitmaps on the board. Watch out for plane pointers that
|
|
|
|
* are 0x00000000 (represents a plane with all bits "0") or 0xffffffff
|
|
|
|
* (represents a plane with all bits "1").
|
|
|
|
*/
|
|
|
|
uae_u32 REGPARAM2 picasso_BlitPlanar2Chunky (struct regstruct *regs)
|
|
|
|
{
|
|
|
|
uaecptr bm = m68k_areg (regs, 1);
|
|
|
|
uaecptr ri = m68k_areg (regs, 2);
|
|
|
|
unsigned long srcx = (uae_u16) m68k_dreg (regs, 0);
|
|
|
|
unsigned long srcy = (uae_u16) m68k_dreg (regs, 1);
|
|
|
|
unsigned long dstx = (uae_u16) m68k_dreg (regs, 2);
|
|
|
|
unsigned long dsty = (uae_u16) m68k_dreg (regs, 3);
|
|
|
|
unsigned long width = (uae_u16) m68k_dreg (regs, 4);
|
|
|
|
unsigned long height = (uae_u16) m68k_dreg (regs, 5);
|
|
|
|
uae_u8 minterm = m68k_dreg (regs, 6) & 0xFF;
|
|
|
|
uae_u8 mask = m68k_dreg (regs, 7) & 0xFF;
|
|
|
|
|
|
|
|
struct RenderInfo local_ri;
|
|
|
|
struct BitMap local_bm;
|
|
|
|
|
|
|
|
wgfx_flushline ();
|
|
|
|
|
|
|
|
if (minterm != 0x0C) {
|
|
|
|
P96TRACE (("P96: ERROR - BlitPlanar2Chunky() has minterm 0x%x, which"
|
|
|
|
" I don't handle. Using fall-back routine.\n", minterm));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (!CopyRenderInfoStructureA2U (ri, &local_ri)
|
2014-01-25 12:19:44 +01:00
|
|
|
|| !CopyBitMapStructureA2U (bm, &local_bm))
|
2009-05-05 17:36:48 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
P96TRACE (("P96: BlitPlanar2Chunky(%d, %d, %d, %d, %d, %d) Minterm 0x%x,"
|
|
|
|
" Mask 0x%x, Depth %d\n", srcx, srcy, dstx, dsty, width, height,
|
|
|
|
minterm, mask, local_bm.Depth));
|
|
|
|
P96TRACE (("P96: P2C - BitMap has %d BPR, %d rows\n",
|
|
|
|
local_bm.BytesPerRow, local_bm.Rows));
|
|
|
|
|
|
|
|
PlanarToChunky (&local_ri, &local_bm, srcx, srcy, dstx, dsty,
|
|
|
|
width, height, mask);
|
|
|
|
if (renderinfo_is_current_screen (&local_ri)) {
|
|
|
|
do_blit (&local_ri, GetBytesPerPixel (local_ri.RGBFormat), dstx, dsty,
|
|
|
|
dstx, dsty, width, height, BLIT_SRC, 0);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void PlanarToDirect (struct RenderInfo *ri, struct BitMap *bm,
|
|
|
|
unsigned long srcx, unsigned long srcy,
|
|
|
|
unsigned long dstx, unsigned long dsty,
|
|
|
|
unsigned long width, unsigned long height,
|
|
|
|
uae_u8 mask, struct ColorIndexMapping *cim)
|
|
|
|
{
|
|
|
|
int j;
|
|
|
|
int bpp = GetBytesPerPixel (ri->RGBFormat);
|
|
|
|
uae_u8 *PLANAR[8];
|
|
|
|
uae_u8 *image = ri->Memory + dstx * bpp + dsty * ri->BytesPerRow;
|
|
|
|
int Depth = bm->Depth;
|
|
|
|
unsigned long rows;
|
|
|
|
long eol_offset;
|
|
|
|
|
|
|
|
/* Set up our bm->Planes[] pointers to the right horizontal offset */
|
|
|
|
for (j = 0; j < Depth; j++) {
|
|
|
|
uae_u8 *p = bm->Planes[j];
|
|
|
|
if (p != &all_zeros_bitmap && p != &all_ones_bitmap)
|
|
|
|
p += srcx / 8 + srcy * bm->BytesPerRow;
|
|
|
|
PLANAR[j] = p;
|
|
|
|
if ((mask & (1 << j)) == 0)
|
|
|
|
PLANAR[j] = &all_zeros_bitmap;
|
|
|
|
}
|
|
|
|
|
|
|
|
eol_offset = (long) bm->BytesPerRow - (long) ((width + (srcx & 7)) >> 3);
|
|
|
|
for (rows = 0; rows < height; rows++, image += ri->BytesPerRow) {
|
|
|
|
unsigned long cols;
|
|
|
|
uae_u8 *image2 = image;
|
|
|
|
unsigned int bitoffs = 7 - (srcx & 7);
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (cols = 0; cols < width; cols++) {
|
|
|
|
int v = 0, k;
|
|
|
|
for (k = 0; k < Depth; k++) {
|
|
|
|
if (PLANAR[k] == &all_ones_bitmap)
|
|
|
|
v |= 1 << k;
|
|
|
|
else if (PLANAR[k] != &all_zeros_bitmap) {
|
|
|
|
v |= ((*PLANAR[k] >> bitoffs) & 1) << k;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (bpp) {
|
|
|
|
case 2:
|
|
|
|
do_put_mem_word ((uae_u16 *) image2, cim->Colors[v]);
|
|
|
|
image2 += 2;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
do_put_mem_byte (image2++, cim->Colors[v] & 0x000000FF);
|
|
|
|
do_put_mem_word ((uae_u16 *) image2, (cim->Colors[v] & 0x00FFFF00) >> 8);
|
|
|
|
image2 += 2;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
do_put_mem_long ((uae_u32 *) image2, cim->Colors[v]);
|
|
|
|
image2 += 4;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
bitoffs--;
|
|
|
|
bitoffs &= 7;
|
|
|
|
if (bitoffs == 7) {
|
|
|
|
int k;
|
|
|
|
for (k = 0; k < Depth; k++) {
|
|
|
|
if (PLANAR[k] != &all_zeros_bitmap && PLANAR[k] != &all_ones_bitmap) {
|
|
|
|
PLANAR[k]++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < Depth; i++) {
|
|
|
|
if (PLANAR[i] != &all_zeros_bitmap && PLANAR[i] != &all_ones_bitmap) {
|
|
|
|
PLANAR[i] += eol_offset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* BlitPlanar2Direct:
|
|
|
|
*
|
|
|
|
* Synopsis:
|
|
|
|
* BlitPlanar2Direct(bi, bm, ri, cim, SrcX, SrcY, DstX, DstY, SizeX, SizeY,
|
|
|
|
* MinTerm, Mask);
|
|
|
|
* Inputs:
|
|
|
|
* a0:struct BoardInfo *bi
|
|
|
|
* a1:struct BitMap *bm
|
|
|
|
* a2:struct RenderInfo *ri
|
|
|
|
* a3:struct ColorIndexMapping *cmi
|
|
|
|
* d0.w:SrcX
|
|
|
|
* d1.w:SrcY
|
|
|
|
* d2.w:DstX
|
|
|
|
* d3.w:DstY
|
|
|
|
* d4.w:SizeX
|
|
|
|
* d5.w:SizeY
|
|
|
|
* d6.b:MinTerm
|
|
|
|
* d7.b:Mask
|
|
|
|
*
|
|
|
|
* This function is currently used to blit from planar bitmaps within system
|
|
|
|
* memory to direct color bitmaps (15, 16, 24 or 32 bit) on the board. Watch
|
|
|
|
* out for plane pointers that are 0x00000000 (represents a plane with all
|
|
|
|
* bits "0") or 0xffffffff (represents a plane with all bits "1"). The
|
|
|
|
* ColorIndexMapping is used to map the color index of each pixel formed by
|
|
|
|
* the bits in the bitmap's planes to a direct color value which is written to
|
|
|
|
* the destination RenderInfo. The color mask and all colors within the mapping
|
|
|
|
* are words, triple bytes or longwords respectively similar to the color
|
|
|
|
* values used in FillRect(), BlitPattern() or BlitTemplate().
|
|
|
|
*/
|
|
|
|
|
|
|
|
uae_u32 REGPARAM2 picasso_BlitPlanar2Direct (struct regstruct *regs)
|
|
|
|
{
|
|
|
|
uaecptr bm = m68k_areg (regs, 1);
|
|
|
|
uaecptr ri = m68k_areg (regs, 2);
|
|
|
|
uaecptr cim = m68k_areg (regs, 3);
|
|
|
|
uae_u16 srcx = (uae_u16)m68k_dreg (regs, 0);
|
|
|
|
uae_u16 srcy = (uae_u16)m68k_dreg (regs, 1);
|
|
|
|
uae_u16 dstx = (uae_u16)m68k_dreg (regs, 2);
|
|
|
|
uae_u16 dsty = (uae_u16)m68k_dreg (regs, 3);
|
|
|
|
uae_u16 width = (uae_u16)m68k_dreg (regs, 4);
|
|
|
|
uae_u16 height = (uae_u16)m68k_dreg (regs, 5);
|
|
|
|
uae_u8 minterm = m68k_dreg (regs, 6);
|
|
|
|
uae_u8 Mask; //= m68k_dreg (regs, 7);
|
|
|
|
|
|
|
|
struct RenderInfo local_ri;
|
|
|
|
struct BitMap local_bm;
|
|
|
|
struct ColorIndexMapping local_cim;
|
|
|
|
int result = 0;
|
|
|
|
|
|
|
|
#ifdef JIT
|
|
|
|
special_mem |= picasso_is_special_read | picasso_is_special;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
wgfx_flushline ();
|
|
|
|
|
|
|
|
if (minterm == BLIT_SRC) {
|
|
|
|
if (CopyRenderInfoStructureA2U (ri, &local_ri)
|
|
|
|
&& CopyBitMapStructureA2U (bm, &local_bm)) {
|
|
|
|
|
|
|
|
Mask = 0xFF;
|
|
|
|
CopyColorIndexMappingA2U (cim, &local_cim);
|
|
|
|
|
|
|
|
P96TRACE (("P96: BlitPlanar2Direct(%d, %d, %d, %d, %d, %d) Minterm"
|
|
|
|
" 0x%x, Mask 0x%x, Depth %d\n", srcx, srcy, dstx, dsty,
|
|
|
|
width, height, minterm, Mask, local_bm.Depth));
|
|
|
|
|
|
|
|
PlanarToDirect (&local_ri, &local_bm, srcx, srcy, dstx, dsty,
|
|
|
|
width, height, Mask, &local_cim);
|
|
|
|
|
|
|
|
if (renderinfo_is_current_screen (&local_ri)) {
|
|
|
|
do_blit (&local_ri, GetBytesPerPixel (local_ri.RGBFormat),
|
|
|
|
dstx, dsty, dstx, dsty, width, height, BLIT_SRC, 0);
|
|
|
|
}
|
|
|
|
result = 1;
|
|
|
|
} else {
|
|
|
|
P96TRACE (("P96: WARNING - BlitPlanar2Direct() failed."
|
|
|
|
" Using fall-back routine.\n"));
|
|
|
|
}
|
|
|
|
} else {
|
2014-01-25 12:19:44 +01:00
|
|
|
P96TRACE (("P96: WARNING - BlitPlanar2Direct () has unhandled op-code"
|
2009-05-05 17:36:48 +02:00
|
|
|
" 0x%x. Using fall-back routine.\n", minterm));
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* @@@ - Work to be done here!
|
|
|
|
*
|
|
|
|
* The address is the offset into our Picasso96 frame-buffer (pointed to by
|
|
|
|
* gfxmem_start) where the value was put.
|
|
|
|
*
|
|
|
|
* Porting work: on some machines you may not need these functions, ie. if the
|
|
|
|
* memory for the Picasso96 frame-buffer is directly viewable or directly
|
|
|
|
* blittable. On Win32 with DirectX, this is not the case. So I provide some
|
|
|
|
* write-through functions (as per Mathias' orders!)
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check whether data written to the P96 framebuffer needs to be flushed
|
|
|
|
* to the real screen
|
|
|
|
*
|
|
|
|
* addr = address in Amiga memory of data written.
|
|
|
|
* size = size of data written in bytes
|
|
|
|
*/
|
|
|
|
STATIC_INLINE void flush_write (uaecptr addr, uae_u8 size)
|
|
|
|
{
|
|
|
|
if (picasso_on) {
|
2014-01-25 12:19:44 +01:00
|
|
|
/* Is this data on the same framebuffer line as previous
|
2009-05-05 17:36:48 +02:00
|
|
|
* successive writes? */
|
2014-01-25 12:19:44 +01:00
|
|
|
if (addr >= currline_start && (addr + size) <= currline_end) {
|
2009-05-05 17:36:48 +02:00
|
|
|
/* Yes. Don't flush now. We'll flush the whole line later */
|
|
|
|
if (addr < currline_min)
|
2014-01-25 12:19:44 +01:00
|
|
|
currline_min = addr;
|
2009-05-05 17:36:48 +02:00
|
|
|
if ((addr + size) > currline_max)
|
2014-01-25 12:19:44 +01:00
|
|
|
currline_max = addr + size;
|
2009-05-05 17:36:48 +02:00
|
|
|
} else {
|
|
|
|
/* Otherwise, this data is on different line, or
|
|
|
|
* we don't have a current line */
|
2014-01-25 12:19:44 +01:00
|
|
|
int line_no;
|
2009-05-05 17:36:48 +02:00
|
|
|
|
|
|
|
/* If there is a current line, flush it to the display now */
|
|
|
|
if (currline_start != 0xFFFFFFFF)
|
2014-01-25 12:19:44 +01:00
|
|
|
flush_currline ();
|
2009-05-05 17:36:48 +02:00
|
|
|
|
|
|
|
/* Now we need to set up a new current line, starting with this
|
|
|
|
* write.*/
|
|
|
|
line_no = (addr - picasso96_state.Address)/picasso96_state.BytesPerRow;
|
|
|
|
|
|
|
|
/* If this line is outside of the p96 screen in the framebuffer
|
|
|
|
* we ignore it */
|
|
|
|
if ((line_no >= picasso96_state.YOffset) && (line_no < picasso96_state.YOffset + picasso96_state.Height)) {
|
2014-01-25 12:19:44 +01:00
|
|
|
currline_start = picasso96_state.Address + line_no * picasso96_state.BytesPerRow;
|
|
|
|
currline_end = currline_start + picasso96_state.BytesPerRow;
|
|
|
|
currline_min = addr;
|
|
|
|
currline_max = addr+size;
|
|
|
|
currline_y = line_no;
|
2009-05-05 17:36:48 +02:00
|
|
|
}
|
2014-01-25 12:19:44 +01:00
|
|
|
}
|
2009-05-05 17:36:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Access routines to the P96 framebuffer
|
|
|
|
*/
|
|
|
|
static uae_u32 REGPARAM2 gfxmem_lget (uaecptr addr)
|
|
|
|
{
|
|
|
|
uae_u32 *m;
|
|
|
|
|
|
|
|
#ifdef JIT
|
|
|
|
special_mem |= picasso_is_special_read;
|
|
|
|
#endif
|
|
|
|
addr -= gfxmem_start;
|
|
|
|
addr &= gfxmem_mask;
|
|
|
|
m = (uae_u32 *) (gfxmemory + addr);
|
|
|
|
return do_get_mem_long (m);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uae_u32 REGPARAM2 gfxmem_wget (uaecptr addr)
|
|
|
|
{
|
|
|
|
uae_u16 *m;
|
|
|
|
|
|
|
|
#ifdef JIT
|
|
|
|
special_mem |= picasso_is_special_read;
|
|
|
|
#endif
|
|
|
|
addr -= gfxmem_start;
|
|
|
|
addr &= gfxmem_mask;
|
|
|
|
m = (uae_u16 *) (gfxmemory + addr);
|
|
|
|
return do_get_mem_word (m);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uae_u32 REGPARAM2 gfxmem_bget (uaecptr addr)
|
|
|
|
{
|
|
|
|
#ifdef JIT
|
|
|
|
special_mem |= picasso_is_special_read;
|
|
|
|
#endif
|
|
|
|
addr -= gfxmem_start;
|
|
|
|
addr &= gfxmem_mask;
|
|
|
|
return gfxmemory[addr];
|
|
|
|
}
|
|
|
|
|
|
|
|
static void REGPARAM2 gfxmem_lput (uaecptr addr, uae_u32 l)
|
|
|
|
{
|
|
|
|
uae_u32 *m;
|
|
|
|
#ifdef JIT
|
|
|
|
special_mem |= picasso_is_special;
|
|
|
|
#endif
|
|
|
|
m = (uae_u32 *)(((addr - gfxmem_start) & gfxmem_mask) + gfxmemory);
|
|
|
|
do_put_mem_long (m, l);
|
|
|
|
|
|
|
|
/* Flush long written to the display */
|
|
|
|
flush_write (addr, 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void REGPARAM2 gfxmem_wput (uaecptr addr, uae_u32 w)
|
|
|
|
{
|
|
|
|
uae_u16 *m;
|
|
|
|
#ifdef JIT
|
|
|
|
special_mem |= picasso_is_special;
|
|
|
|
#endif
|
|
|
|
m = (uae_u16 *)(((addr - gfxmem_start) & gfxmem_mask) + gfxmemory);
|
|
|
|
do_put_mem_word (m, (uae_u16)w);
|
|
|
|
|
|
|
|
/* Flush word written to the display */
|
|
|
|
flush_write (addr, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void REGPARAM2 gfxmem_bput (uaecptr addr, uae_u32 b)
|
|
|
|
{
|
|
|
|
uae_u8 *m;
|
|
|
|
#ifdef JIT
|
|
|
|
special_mem |= picasso_is_special;
|
|
|
|
#endif
|
|
|
|
m = (uae_u8 *)(((addr - gfxmem_start) & gfxmem_mask) + gfxmemory);
|
|
|
|
*m = (uae_u8) b;
|
|
|
|
|
|
|
|
/* Flush byte written to the display */
|
|
|
|
flush_write (addr, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int REGPARAM2 gfxmem_check (uaecptr addr, uae_u32 size)
|
|
|
|
{
|
|
|
|
addr -= gfxmem_start;
|
|
|
|
addr &= gfxmem_mask;
|
|
|
|
return (addr + size) < allocated_gfxmem;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uae_u8 REGPARAM2 *gfxmem_xlate (uaecptr addr)
|
|
|
|
{
|
|
|
|
addr -= gfxmem_start;
|
|
|
|
addr &= gfxmem_mask;
|
|
|
|
return gfxmemory + addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
addrbank gfxmem_bank = {
|
|
|
|
gfxmem_lget, gfxmem_wget, gfxmem_bget,
|
|
|
|
gfxmem_lput, gfxmem_wput, gfxmem_bput,
|
|
|
|
gfxmem_xlate, gfxmem_check, NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
int picasso_display_mode_index (uae_u32 x, uae_u32 y, uae_u32 d)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < mode_count; i++) {
|
2014-01-25 12:19:44 +01:00
|
|
|
if (DisplayModes[i].res.width == x
|
2009-05-05 17:36:48 +02:00
|
|
|
&& DisplayModes[i].res.height == y
|
|
|
|
&& DisplayModes[i].depth == (int)d)
|
2014-01-25 12:19:44 +01:00
|
|
|
break;
|
2009-05-05 17:36:48 +02:00
|
|
|
}
|
|
|
|
if (i == mode_count)
|
2014-01-25 12:19:44 +01:00
|
|
|
i = -1;
|
2009-05-05 17:36:48 +02:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int resolution_compare (const void *a, const void *b)
|
|
|
|
{
|
|
|
|
struct PicassoResolution *ma = (struct PicassoResolution *) a;
|
|
|
|
struct PicassoResolution *mb = (struct PicassoResolution *) b;
|
|
|
|
if (ma->res.width > mb->res.width)
|
|
|
|
return -1;
|
|
|
|
if (ma->res.width < mb->res.width)
|
|
|
|
return 1;
|
|
|
|
if (ma->res.height > mb->res.height)
|
|
|
|
return -1;
|
|
|
|
if (ma->res.height < mb->res.height)
|
|
|
|
return 1;
|
|
|
|
return ma->depth - mb->depth;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Call this function first, near the beginning of code flow
|
|
|
|
* NOTE: Don't stuff it in InitGraphics() which seems reasonable...
|
|
|
|
* Instead, put it in customreset() for safe-keeping. */
|
|
|
|
void InitPicasso96 (void)
|
|
|
|
{
|
|
|
|
static int first_time = 1;
|
|
|
|
|
|
|
|
memset (&picasso96_state, 0, sizeof (struct picasso96_state_struct));
|
|
|
|
|
|
|
|
if (first_time) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < 256; i++) {
|
|
|
|
p2ctab[i][0] = (((i & 128) ? 0x01000000 : 0)
|
|
|
|
| ((i & 64) ? 0x010000 : 0)
|
|
|
|
| ((i & 32) ? 0x0100 : 0)
|
|
|
|
| ((i & 16) ? 0x01 : 0));
|
|
|
|
p2ctab[i][1] = (((i & 8) ? 0x01000000 : 0)
|
|
|
|
| ((i & 4) ? 0x010000 : 0)
|
|
|
|
| ((i & 2) ? 0x0100 : 0)
|
|
|
|
| ((i & 1) ? 0x01 : 0));
|
|
|
|
}
|
|
|
|
mode_count = DX_FillResolutions (&picasso96_pixel_format);
|
|
|
|
|
2014-01-25 12:19:44 +01:00
|
|
|
qsort (DisplayModes, mode_count, sizeof (struct PicassoResolution),
|
2009-05-05 17:36:48 +02:00
|
|
|
resolution_compare);
|
|
|
|
|
2014-01-25 12:19:44 +01:00
|
|
|
/* Work-around for possible P96 bug. A8R8G8B8 modes have
|
2009-05-05 17:36:48 +02:00
|
|
|
* palette emulation issues. Tell the world we have a
|
|
|
|
* a BGRA mode instead (and we'll byte-swap all pixels output).
|
|
|
|
*/
|
2014-01-25 12:19:44 +01:00
|
|
|
if (picasso_vidinfo.rgbformat == RGBFB_A8R8G8B8) {
|
2009-05-05 17:36:48 +02:00
|
|
|
picasso_vidinfo.rgbformat = RGBFB_B8G8R8A8;
|
|
|
|
picasso96_pixel_format &= RGBFF_CHUNKY;
|
|
|
|
picasso96_pixel_format |= 1 << picasso_vidinfo.rgbformat;
|
|
|
|
need_argb32_hack = 1;
|
|
|
|
write_log ("Enabling argb32 byte-swapping for P96.\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < mode_count; i++) {
|
|
|
|
sprintf (DisplayModes[i].name, "%dx%d, %d-bit, %d Hz",
|
|
|
|
DisplayModes[i].res.width, DisplayModes[i].res.height,
|
|
|
|
DisplayModes[i].depth * 8, DisplayModes[i].refresh);
|
|
|
|
switch (DisplayModes[i].depth) {
|
|
|
|
case 1:
|
|
|
|
if (DisplayModes[i].res.width > chunky.width)
|
|
|
|
chunky.width = DisplayModes[i].res.width;
|
|
|
|
if (DisplayModes[i].res.height > chunky.height)
|
|
|
|
chunky.height = DisplayModes[i].res.height;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if (DisplayModes[i].res.width > hicolour.width)
|
|
|
|
hicolour.width = DisplayModes[i].res.width;
|
|
|
|
if (DisplayModes[i].res.height > hicolour.height)
|
|
|
|
hicolour.height = DisplayModes[i].res.height;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
if (DisplayModes[i].res.width > truecolour.width)
|
|
|
|
truecolour.width = DisplayModes[i].res.width;
|
|
|
|
if (DisplayModes[i].res.height > truecolour.height)
|
|
|
|
truecolour.height = DisplayModes[i].res.height;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
if (DisplayModes[i].res.width > alphacolour.width)
|
|
|
|
alphacolour.width = DisplayModes[i].res.width;
|
|
|
|
if (DisplayModes[i].res.height > alphacolour.height)
|
|
|
|
alphacolour.height = DisplayModes[i].res.height;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ShowSupportedResolutions ();
|
|
|
|
|
|
|
|
first_time = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|