src/video/ps2gs/SDL_gsvideo.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 07 Dec 2008 22:37:40 +0000
changeset 2853 6258fa7cd300
parent 2735 204be4fc2726
child 2859 99210400e8b9
permissions -rw-r--r--
Fixed picking blit function when RLE fails
slouken@70
     1
/*
slouken@1312
     2
    SDL - Simple DirectMedia Layer
slouken@1312
     3
    Copyright (C) 1997-2006 Sam Lantinga
slouken@70
     4
slouken@1312
     5
    This library is free software; you can redistribute it and/or
slouken@1312
     6
    modify it under the terms of the GNU Lesser General Public
slouken@1312
     7
    License as published by the Free Software Foundation; either
slouken@1312
     8
    version 2.1 of the License, or (at your option) any later version.
slouken@70
     9
slouken@1312
    10
    This library is distributed in the hope that it will be useful,
slouken@1312
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@1312
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@1312
    13
    Lesser General Public License for more details.
slouken@70
    14
slouken@1312
    15
    You should have received a copy of the GNU Lesser General Public
slouken@1312
    16
    License along with this library; if not, write to the Free Software
slouken@1312
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
slouken@70
    18
slouken@1312
    19
    Sam Lantinga
slouken@1312
    20
    slouken@libsdl.org
slouken@70
    21
*/
slouken@1402
    22
#include "SDL_config.h"
slouken@70
    23
slouken@70
    24
/* Framebuffer console based SDL video driver implementation.
slouken@70
    25
*/
slouken@70
    26
slouken@70
    27
#include <fcntl.h>
slouken@70
    28
#include <unistd.h>
slouken@70
    29
#include <sys/ioctl.h>
slouken@70
    30
#include <sys/mman.h>
slouken@70
    31
slouken@70
    32
#include "SDL_video.h"
slouken@70
    33
#include "SDL_mouse.h"
slouken@1361
    34
#include "../SDL_sysvideo.h"
slouken@1361
    35
#include "../SDL_pixels_c.h"
slouken@1361
    36
#include "../../events/SDL_events_c.h"
slouken@1361
    37
#include "../SDL_cursor_c.h"
slouken@70
    38
#include "SDL_gsvideo.h"
slouken@70
    39
#include "SDL_gsmouse_c.h"
slouken@70
    40
#include "SDL_gsevents_c.h"
slouken@70
    41
#include "SDL_gsyuv_c.h"
slouken@70
    42
slouken@70
    43
slouken@70
    44
/* Initialization/Query functions */
slouken@1895
    45
static int GS_VideoInit(_THIS, SDL_PixelFormat * vformat);
slouken@1895
    46
static SDL_Rect **GS_ListModes(_THIS, SDL_PixelFormat * format, Uint32 flags);
slouken@1895
    47
static SDL_Surface *GS_SetVideoMode(_THIS, SDL_Surface * current, int width,
slouken@1895
    48
                                    int height, int bpp, Uint32 flags);
slouken@1895
    49
static int GS_SetColors(_THIS, int firstcolor, int ncolors,
slouken@1895
    50
                        SDL_Color * colors);
slouken@70
    51
static void GS_VideoQuit(_THIS);
slouken@70
    52
slouken@70
    53
/* Hardware surface functions */
slouken@1895
    54
static int GS_AllocHWSurface(_THIS, SDL_Surface * surface);
slouken@1895
    55
static int GS_LockHWSurface(_THIS, SDL_Surface * surface);
slouken@1895
    56
static void GS_UnlockHWSurface(_THIS, SDL_Surface * surface);
slouken@1895
    57
static void GS_FreeHWSurface(_THIS, SDL_Surface * surface);
slouken@70
    58
slouken@70
    59
/* GS driver bootstrap functions */
slouken@70
    60
slouken@1895
    61
static int
slouken@1895
    62
GS_Available(void)
slouken@70
    63
{
slouken@1895
    64
    int console, memory;
slouken@70
    65
slouken@1895
    66
    console = open(PS2_DEV_GS, O_RDWR, 0);
slouken@1895
    67
    if (console >= 0) {
slouken@1895
    68
        close(console);
slouken@1895
    69
    }
slouken@1895
    70
    memory = open(PS2_DEV_MEM, O_RDWR, 0);
slouken@1895
    71
    if (memory >= 0) {
slouken@1895
    72
        close(memory);
slouken@1895
    73
    }
slouken@1895
    74
    return ((console >= 0) && (memory >= 0));
slouken@70
    75
}
slouken@70
    76
slouken@1895
    77
static void
slouken@1895
    78
GS_DeleteDevice(SDL_VideoDevice * device)
slouken@70
    79
{
slouken@1895
    80
    SDL_free(device->hidden);
slouken@1895
    81
    SDL_free(device);
slouken@70
    82
}
slouken@70
    83
slouken@1895
    84
static SDL_VideoDevice *
slouken@1895
    85
GS_CreateDevice(int devindex)
slouken@70
    86
{
slouken@1895
    87
    SDL_VideoDevice *this;
slouken@70
    88
slouken@1895
    89
    /* Initialize all variables that we clean on shutdown */
slouken@1895
    90
    this = (SDL_VideoDevice *) SDL_malloc(sizeof(SDL_VideoDevice));
slouken@1895
    91
    if (this) {
slouken@1895
    92
        SDL_memset(this, 0, (sizeof *this));
slouken@1895
    93
        this->hidden = (struct SDL_PrivateVideoData *)
slouken@1895
    94
            SDL_malloc((sizeof *this->hidden));
slouken@1895
    95
    }
slouken@1895
    96
    if ((this == NULL) || (this->hidden == NULL)) {
slouken@1895
    97
        SDL_OutOfMemory();
slouken@1895
    98
        if (this) {
slouken@1895
    99
            SDL_free(this);
slouken@1895
   100
        }
slouken@1895
   101
        return (0);
slouken@1895
   102
    }
slouken@1895
   103
    SDL_memset(this->hidden, 0, (sizeof *this->hidden));
slouken@1895
   104
    mouse_fd = -1;
slouken@1895
   105
    keyboard_fd = -1;
slouken@70
   106
slouken@1895
   107
    /* Set the function pointers */
slouken@1895
   108
    this->VideoInit = GS_VideoInit;
slouken@1895
   109
    this->ListModes = GS_ListModes;
slouken@1895
   110
    this->SetVideoMode = GS_SetVideoMode;
slouken@1895
   111
    this->CreateYUVOverlay = GS_CreateYUVOverlay;
slouken@1895
   112
    this->SetColors = GS_SetColors;
slouken@1895
   113
    this->UpdateRects = NULL;
slouken@1895
   114
    this->VideoQuit = GS_VideoQuit;
slouken@1895
   115
    this->AllocHWSurface = GS_AllocHWSurface;
slouken@1895
   116
    this->CheckHWBlit = NULL;
slouken@1895
   117
    this->FillHWRect = NULL;
slouken@1895
   118
    this->SetHWColorKey = NULL;
slouken@1895
   119
    this->SetHWAlpha = NULL;
slouken@1895
   120
    this->LockHWSurface = GS_LockHWSurface;
slouken@1895
   121
    this->UnlockHWSurface = GS_UnlockHWSurface;
slouken@1895
   122
    this->FlipHWSurface = NULL;
slouken@1895
   123
    this->FreeHWSurface = GS_FreeHWSurface;
slouken@1895
   124
    this->SetIcon = NULL;
slouken@1895
   125
    this->SetCaption = NULL;
slouken@1895
   126
    this->GetWMInfo = NULL;
slouken@1895
   127
    this->FreeWMCursor = GS_FreeWMCursor;
slouken@1895
   128
    this->CreateWMCursor = GS_CreateWMCursor;
slouken@1895
   129
    this->ShowWMCursor = GS_ShowWMCursor;
slouken@1895
   130
    this->MoveWMCursor = GS_MoveWMCursor;
slouken@1895
   131
    this->InitOSKeymap = GS_InitOSKeymap;
slouken@1895
   132
    this->PumpEvents = GS_PumpEvents;
slouken@70
   133
slouken@1895
   134
    this->free = GS_DeleteDevice;
slouken@70
   135
slouken@1895
   136
    return this;
slouken@70
   137
}
slouken@70
   138
slouken@70
   139
VideoBootStrap PS2GS_bootstrap = {
slouken@1895
   140
    "ps2gs", "PlayStation 2 Graphics Synthesizer",
slouken@1895
   141
    GS_Available, GS_CreateDevice
slouken@70
   142
};
slouken@70
   143
slouken@70
   144
/* These are the pixel formats for the 32, 24, and 16 bit video modes */
slouken@1895
   145
static struct
slouken@1895
   146
{
slouken@1895
   147
    int bpp;
slouken@1895
   148
    Uint32 r;
slouken@1895
   149
    Uint32 g;
slouken@1895
   150
    Uint32 b;
slouken@70
   151
} GS_pixelmasks[] = {
slouken@1895
   152
    {
slouken@1895
   153
        32, 0x000000FF,         /* RGB little-endian */
slouken@1895
   154
    0x0000FF00, 0x00FF0000}, {
slouken@1895
   155
        24, 0x000000FF,         /* RGB little-endian */
slouken@1895
   156
    0x0000FF00, 0x00FF0000}, {
slouken@1895
   157
        16, 0x0000001f,         /* RGB little-endian */
slouken@1895
   158
0x000003e0, 0x00007c00},};
slouken@1895
   159
slouken@70
   160
/* This is a mapping from SDL bytes-per-pixel to GS pixel format */
slouken@70
   161
static int GS_formatmap[] = {
slouken@1895
   162
    -1,                         /* 0 bpp, not a legal value */
slouken@1895
   163
    -1,                         /* 8 bpp, not supported (yet?) */
slouken@1895
   164
    PS2_GS_PSMCT16,             /* 16 bpp */
slouken@1895
   165
    PS2_GS_PSMCT24,             /* 24 bpp */
slouken@1895
   166
    PS2_GS_PSMCT32              /* 32 bpp */
slouken@70
   167
};
slouken@70
   168
slouken@1895
   169
static unsigned long long head_tags[] __attribute__ ((aligned(16))) = {
slouken@1895
   170
    4 | (1LL << 60),            /* GIFtag */
slouken@1895
   171
        0x0e,                   /* A+D */
slouken@1895
   172
        0,                      /* 2 */
slouken@1895
   173
        PS2_GS_BITBLTBUF, 0,    /* 4 */
slouken@1895
   174
        PS2_GS_TRXPOS, 0,       /* 6 */
slouken@1895
   175
        PS2_GS_TRXREG, 0,       /* 8 */
slouken@1895
   176
PS2_GS_TRXDIR};
slouken@70
   177
slouken@70
   178
#define MAXIMG		(32767 * 16)
slouken@70
   179
#define MAXTAGS		8
slouken@70
   180
slouken@1895
   181
static inline int
slouken@1895
   182
loadimage_nonblock(int fd, struct ps2_image *image, int size,
slouken@1895
   183
                   unsigned long long *hm, unsigned long long *im)
slouken@70
   184
{
slouken@1895
   185
    struct ps2_plist plist;
slouken@1895
   186
    struct ps2_packet packet[1 + MAXTAGS * 2];
slouken@1895
   187
    int isize;
slouken@1895
   188
    int pnum, it, eop;
slouken@1895
   189
    char *data;
slouken@70
   190
slouken@1895
   191
    /* initialize the variables */
slouken@1895
   192
    data = (char *) image->ptr;
slouken@1895
   193
    pnum = it = eop = 0;
slouken@1895
   194
    plist.packet = packet;
slouken@70
   195
slouken@1895
   196
    /* make BITBLT packet */
slouken@1895
   197
    packet[pnum].ptr = hm;
slouken@1895
   198
    packet[pnum].len = sizeof(head_tags);
slouken@1895
   199
    pnum++;
slouken@1895
   200
    hm[2] = ((unsigned long long) image->fbp << 32) |
slouken@1895
   201
        ((unsigned long long) image->fbw << 48) |
slouken@1895
   202
        ((unsigned long long) image->psm << 56);
slouken@1895
   203
    hm[4] = ((unsigned long long) image->x << 32) |
slouken@1895
   204
        ((unsigned long long) image->y << 48);
slouken@1895
   205
    hm[6] = (unsigned long long) image->w |
slouken@1895
   206
        ((unsigned long long) image->h << 32);
slouken@70
   207
slouken@1895
   208
    /* make image mode tags */
slouken@1895
   209
    while (!eop) {
slouken@1895
   210
        isize = size > MAXIMG ? MAXIMG : size;
slouken@1895
   211
        size -= isize;
slouken@1895
   212
        eop = (size == 0);
slouken@70
   213
slouken@1895
   214
        packet[pnum].ptr = &im[it];
slouken@1895
   215
        packet[pnum].len = sizeof(unsigned long long) * 2;
slouken@1895
   216
        pnum++;
slouken@1895
   217
        im[it++] = (isize >> 4) | (eop ? (1 << 15) : 0) | (2LL << 58);
slouken@1895
   218
        im[it++] = 0;
slouken@70
   219
slouken@1895
   220
        packet[pnum].ptr = (void *) data;
slouken@1895
   221
        packet[pnum].len = isize;
slouken@1895
   222
        pnum++;
slouken@1895
   223
        data += isize;
slouken@1895
   224
    }
slouken@1895
   225
    plist.num = pnum;
slouken@70
   226
slouken@1895
   227
    return ioctl(fd, PS2IOC_SENDL, &plist);
slouken@70
   228
}
slouken@70
   229
slouken@1895
   230
static unsigned long long tex_tags[] __attribute__ ((aligned(16))) = {
slouken@1895
   231
    3 | (1LL << 60),            /* GIFtag */
slouken@1895
   232
        0x0e,                   /* A+D */
slouken@1895
   233
        0,                      /* 2 */
slouken@1895
   234
PS2_GS_TEX0_1, (1 << 5) + (1 << 6), PS2_GS_TEX1_1, 0, PS2_GS_TEXFLUSH};
slouken@2735
   235
slouken@1895
   236
static unsigned long long scale_tags[] __attribute__ ((aligned(16))) = {
slouken@1895
   237
    5 | (1LL << 60),            /* GIFtag */
slouken@1895
   238
        0x0e,                   /* A+D */
slouken@1895
   239
        6 + (1 << 4) + (1 << 8), PS2_GS_PRIM, ((unsigned long long) 0 * 16) + (((unsigned long long) 0 * 16) << 16), PS2_GS_UV, ((unsigned long long) 0 * 16) + (((unsigned long long) 0 * 16) << 16), PS2_GS_XYZ2, 0,  /* 8 */
slouken@1895
   240
        PS2_GS_UV, 0,           /* 10 */
slouken@1895
   241
PS2_GS_XYZ2};
slouken@136
   242
slouken@136
   243
slouken@1895
   244
int
slouken@1895
   245
scaleimage_nonblock(int fd, unsigned long long *tm, unsigned long long *sm)
slouken@136
   246
{
slouken@1895
   247
    struct ps2_plist plist;
slouken@1895
   248
    struct ps2_packet packet[2];
slouken@136
   249
slouken@1895
   250
    /* initialize the variables */
slouken@1895
   251
    plist.num = 2;
slouken@1895
   252
    plist.packet = packet;
slouken@136
   253
slouken@1895
   254
    packet[0].ptr = tm;
slouken@1895
   255
    packet[0].len = sizeof(tex_tags);
slouken@1895
   256
    packet[1].ptr = sm;
slouken@1895
   257
    packet[1].len = sizeof(scale_tags);
slouken@136
   258
slouken@1895
   259
    return ioctl(fd, PS2IOC_SENDL, &plist);
slouken@136
   260
}
slouken@136
   261
slouken@1895
   262
static int
slouken@1895
   263
power_of_2(int value)
slouken@136
   264
{
slouken@1895
   265
    int shift;
slouken@136
   266
slouken@1895
   267
    for (shift = 0; (1 << shift) < value; ++shift) {
slouken@1895
   268
        /* Keep looking */ ;
slouken@1895
   269
    }
slouken@1895
   270
    return (shift);
slouken@136
   271
}
slouken@136
   272
slouken@1895
   273
static int
slouken@1895
   274
GS_VideoInit(_THIS, SDL_PixelFormat * vformat)
slouken@70
   275
{
slouken@1895
   276
    struct ps2_screeninfo vinfo;
slouken@70
   277
slouken@1895
   278
    /* Initialize the library */
slouken@1895
   279
    console_fd = open(PS2_DEV_GS, O_RDWR, 0);
slouken@1895
   280
    if (console_fd < 0) {
slouken@1895
   281
        SDL_SetError("Unable to open %s", PS2_DEV_GS);
slouken@1895
   282
        return (-1);
slouken@1895
   283
    }
slouken@1895
   284
    memory_fd = open(PS2_DEV_MEM, O_RDWR, 0);
slouken@1895
   285
    if (memory_fd < 0) {
slouken@1895
   286
        close(console_fd);
slouken@1895
   287
        console_fd = -1;
slouken@1895
   288
        SDL_SetError("Unable to open %s", PS2_DEV_MEM);
slouken@1895
   289
        return (-1);
slouken@1895
   290
    }
slouken@70
   291
slouken@1895
   292
    if (ioctl(console_fd, PS2IOC_GSCREENINFO, &vinfo) < 0) {
slouken@1895
   293
        close(memory_fd);
slouken@1895
   294
        close(console_fd);
slouken@1895
   295
        console_fd = -1;
slouken@1895
   296
        SDL_SetError("Couldn't get console pixel format");
slouken@1895
   297
        return (-1);
slouken@1895
   298
    }
slouken@1545
   299
slouken@1895
   300
    /* Determine the current screen size */
slouken@1895
   301
    this->info.current_w = vinfo.w;
slouken@1895
   302
    this->info.current_h = vinfo.h;
slouken@1545
   303
slouken@1895
   304
    /* Determine the current screen depth */
slouken@1895
   305
    switch (vinfo.psm) {
slouken@1895
   306
        /* Supported pixel formats */
slouken@1895
   307
    case PS2_GS_PSMCT32:
slouken@1895
   308
    case PS2_GS_PSMCT24:
slouken@1895
   309
    case PS2_GS_PSMCT16:
slouken@1895
   310
        break;
slouken@1895
   311
    default:
slouken@1895
   312
        GS_VideoQuit(this);
slouken@1895
   313
        SDL_SetError("Unknown console pixel format: %d", vinfo.psm);
slouken@1895
   314
        return (-1);
slouken@1895
   315
    }
slouken@1895
   316
    vformat->BitsPerPixel = GS_pixelmasks[vinfo.psm].bpp;
slouken@1895
   317
    vformat->Rmask = GS_pixelmasks[vinfo.psm].r;
slouken@1895
   318
    vformat->Gmask = GS_pixelmasks[vinfo.psm].g;
slouken@1895
   319
    vformat->Bmask = GS_pixelmasks[vinfo.psm].b;
slouken@1895
   320
    saved_vinfo = vinfo;
slouken@70
   321
slouken@1895
   322
    /* Enable mouse and keyboard support */
slouken@1895
   323
    if (GS_OpenKeyboard(this) < 0) {
slouken@1895
   324
        GS_VideoQuit(this);
slouken@1895
   325
        SDL_SetError("Unable to open keyboard");
slouken@1895
   326
        return (-1);
slouken@1895
   327
    }
slouken@1895
   328
    if (GS_OpenMouse(this) < 0) {
slouken@1895
   329
        const char *sdl_nomouse;
slouken@70
   330
slouken@1895
   331
        sdl_nomouse = SDL_getenv("SDL_NOMOUSE");
slouken@1895
   332
        if (!sdl_nomouse) {
slouken@1895
   333
            GS_VideoQuit(this);
slouken@1895
   334
            SDL_SetError("Unable to open mouse");
slouken@1895
   335
            return (-1);
slouken@1895
   336
        }
slouken@1895
   337
    }
slouken@70
   338
slouken@1895
   339
    /* We're done! */
slouken@1895
   340
    return (0);
slouken@70
   341
}
slouken@70
   342
slouken@1895
   343
static SDL_Rect **
slouken@1895
   344
GS_ListModes(_THIS, SDL_PixelFormat * format, Uint32 flags)
slouken@70
   345
{
slouken@1895
   346
    static SDL_Rect GS_vesa_mode_list[] = {
slouken@1895
   347
        {0, 0, 1280, 1024},
slouken@1895
   348
        {0, 0, 1024, 768},
slouken@1895
   349
        {0, 0, 800, 600},
slouken@1895
   350
        {0, 0, 640, 480}
slouken@1895
   351
    };
slouken@1895
   352
    static SDL_Rect *GS_vesa_modes[] = {
slouken@1895
   353
        &GS_vesa_mode_list[0],
slouken@1895
   354
        &GS_vesa_mode_list[1],
slouken@1895
   355
        &GS_vesa_mode_list[2],
slouken@1895
   356
        &GS_vesa_mode_list[3],
slouken@1895
   357
        NULL
slouken@1895
   358
    };
slouken@1895
   359
    static SDL_Rect GS_tvout_stretch;
slouken@1895
   360
    static SDL_Rect GS_tvout_mode;
slouken@1895
   361
    static SDL_Rect *GS_tvout_modes[3];
slouken@1895
   362
    SDL_Rect **modes = NULL;
slouken@70
   363
slouken@1895
   364
    switch (format->BitsPerPixel) {
slouken@1895
   365
    case 16:
slouken@1895
   366
    case 24:
slouken@1895
   367
    case 32:
slouken@1895
   368
        if (saved_vinfo.mode == PS2_GS_VESA) {
slouken@1895
   369
            modes = GS_vesa_modes;
slouken@1895
   370
        } else {
slouken@1895
   371
            int i, j = 0;
slouken@136
   372
slouken@136
   373
// FIXME - what's wrong with the stretch code at 16 bpp?
slouken@1895
   374
            if (format->BitsPerPixel != 32)
slouken@1895
   375
                break;
slouken@1895
   376
            /* Add a mode that we could possibly stretch to */
slouken@1895
   377
            for (i = 0; GS_vesa_modes[i]; ++i) {
slouken@1895
   378
                if ((GS_vesa_modes[i]->w == saved_vinfo.w) &&
slouken@1895
   379
                    (GS_vesa_modes[i]->h != saved_vinfo.h)) {
slouken@1895
   380
                    GS_tvout_stretch.w = GS_vesa_modes[i]->w;
slouken@1895
   381
                    GS_tvout_stretch.h = GS_vesa_modes[i]->h;
slouken@1895
   382
                    GS_tvout_modes[j++] = &GS_tvout_stretch;
slouken@1895
   383
                    break;
slouken@1895
   384
                }
slouken@1895
   385
            }
slouken@1895
   386
            /* Add the current TV video mode */
slouken@1895
   387
            GS_tvout_mode.w = saved_vinfo.w;
slouken@1895
   388
            GS_tvout_mode.h = saved_vinfo.h;
slouken@1895
   389
            GS_tvout_modes[j++] = &GS_tvout_mode;
slouken@1895
   390
            GS_tvout_modes[j++] = NULL;
slouken@136
   391
slouken@1895
   392
            /* Return the created list of modes */
slouken@1895
   393
            modes = GS_tvout_modes;
slouken@1895
   394
        }
slouken@1895
   395
        break;
slouken@1895
   396
    default:
slouken@1895
   397
        break;
slouken@1895
   398
    }
slouken@1895
   399
    return (modes);
slouken@70
   400
}
slouken@70
   401
slouken@70
   402
/* Various screen update functions available */
slouken@1895
   403
static void GS_DMAFullUpdate(_THIS, int numrects, SDL_Rect * rects);
slouken@70
   404
slouken@1895
   405
static SDL_Surface *
slouken@1895
   406
GS_SetVideoMode(_THIS, SDL_Surface * current,
slouken@1895
   407
                int width, int height, int bpp, Uint32 flags)
slouken@70
   408
{
slouken@1895
   409
    struct ps2_screeninfo vinfo;
slouken@70
   410
slouken@1895
   411
    /* Set the terminal into graphics mode */
slouken@1895
   412
    if (GS_EnterGraphicsMode(this) < 0) {
slouken@1895
   413
        return (NULL);
slouken@1895
   414
    }
slouken@70
   415
slouken@1895
   416
    /* Set the video mode and get the final screen format */
slouken@1895
   417
    if (ioctl(console_fd, PS2IOC_GSCREENINFO, &vinfo) < 0) {
slouken@1895
   418
        SDL_SetError("Couldn't get console screen info");
slouken@1895
   419
        return (NULL);
slouken@1895
   420
    }
slouken@1895
   421
    if ((vinfo.w != width) || (vinfo.h != height) ||
slouken@1895
   422
        (GS_pixelmasks[vinfo.psm].bpp != bpp)) {
slouken@1895
   423
        /* If we're not in VESA mode, we have to scale resolution */
slouken@1895
   424
        if (saved_vinfo.mode == PS2_GS_VESA) {
slouken@1895
   425
            switch (width) {
slouken@1895
   426
            case 640:
slouken@1895
   427
                vinfo.res = PS2_GS_640x480;
slouken@1895
   428
                break;
slouken@1895
   429
            case 800:
slouken@1895
   430
                vinfo.res = PS2_GS_800x600;
slouken@1895
   431
                break;
slouken@1895
   432
            case 1024:
slouken@1895
   433
                vinfo.res = PS2_GS_1024x768;
slouken@1895
   434
                break;
slouken@1895
   435
            case 1280:
slouken@1895
   436
                vinfo.res = PS2_GS_1280x1024;
slouken@1895
   437
                break;
slouken@1895
   438
            default:
slouken@1895
   439
                SDL_SetError("Unsupported resolution: %dx%d\n",
slouken@1895
   440
                             width, height);
slouken@1895
   441
                return (NULL);
slouken@1895
   442
            }
slouken@1895
   443
            vinfo.res |= (PS2_GS_75Hz << 8);
slouken@1895
   444
            vinfo.w = width;
slouken@1895
   445
            vinfo.h = height;
slouken@1895
   446
        }
slouken@1895
   447
        vinfo.fbp = 0;
slouken@1895
   448
        vinfo.psm = GS_formatmap[bpp / 8];
slouken@1895
   449
        if (vinfo.psm < 0) {
slouken@1895
   450
            SDL_SetError("Unsupported depth: %d bpp\n", bpp);
slouken@1895
   451
            return (NULL);
slouken@1895
   452
        }
slouken@1895
   453
        if (ioctl(console_fd, PS2IOC_SSCREENINFO, &vinfo) < 0) {
slouken@1895
   454
            SDL_SetError("Couldn't set console screen info");
slouken@1895
   455
            return (NULL);
slouken@1895
   456
        }
slouken@70
   457
slouken@1895
   458
        /* Unmap the previous DMA buffer */
slouken@1895
   459
        if (mapped_mem) {
slouken@1895
   460
            munmap(mapped_mem, mapped_len);
slouken@1895
   461
            mapped_mem = NULL;
slouken@1895
   462
        }
slouken@1895
   463
    }
slouken@1895
   464
    if (!SDL_ReallocFormat(current, GS_pixelmasks[vinfo.psm].bpp,
slouken@1895
   465
                           GS_pixelmasks[vinfo.psm].r,
slouken@1895
   466
                           GS_pixelmasks[vinfo.psm].g,
slouken@1895
   467
                           GS_pixelmasks[vinfo.psm].b, 0)) {
slouken@1895
   468
        return (NULL);
slouken@1895
   469
    }
slouken@70
   470
slouken@1895
   471
    /* Set up the new mode framebuffer */
slouken@1895
   472
    current->flags = SDL_FULLSCREEN;
slouken@1895
   473
    current->w = width;
slouken@1895
   474
    current->h = height;
slouken@1895
   475
    current->pitch = SDL_CalculatePitch(current);
slouken@70
   476
slouken@1895
   477
    /* Memory map the DMA area for block memory transfer */
slouken@1895
   478
    if (!mapped_mem) {
slouken@1895
   479
        pixels_len = height * current->pitch;
slouken@1895
   480
        mapped_len = pixels_len +
slouken@1895
   481
            /* Screen update DMA command area */
slouken@1895
   482
            sizeof(head_tags) + ((2 * MAXTAGS) * 16);
slouken@1895
   483
        if (saved_vinfo.mode != PS2_GS_VESA) {
slouken@1895
   484
            mapped_len += sizeof(tex_tags) + sizeof(scale_tags);
slouken@1895
   485
        }
slouken@1895
   486
        mapped_mem = mmap(0, mapped_len, PROT_READ | PROT_WRITE,
slouken@1895
   487
                          MAP_SHARED, memory_fd, 0);
slouken@1895
   488
        if (mapped_mem == MAP_FAILED) {
slouken@1895
   489
            SDL_SetError("Unable to map %d bytes for DMA", mapped_len);
slouken@1895
   490
            mapped_mem = NULL;
slouken@1895
   491
            return (NULL);
slouken@1895
   492
        }
slouken@70
   493
slouken@1895
   494
        /* Set up the entire screen for DMA transfer */
slouken@1895
   495
        screen_image.ptr = mapped_mem;
slouken@1895
   496
        screen_image.fbp = 0;
slouken@1895
   497
        screen_image.fbw = (vinfo.w + 63) / 64;
slouken@1895
   498
        screen_image.psm = vinfo.psm;
slouken@1895
   499
        screen_image.x = 0;
slouken@1895
   500
        if (vinfo.h == height) {
slouken@1895
   501
            screen_image.y = 0;
slouken@1895
   502
        } else {
slouken@1895
   503
            /* Put image offscreen and scale to screen height */
slouken@1895
   504
            screen_image.y = vinfo.h;
slouken@1895
   505
        }
slouken@1895
   506
        screen_image.w = current->w;
slouken@1895
   507
        screen_image.h = current->h;
slouken@70
   508
slouken@1895
   509
        /* get screen image data size (qword aligned) */
slouken@1895
   510
        screen_image_size = (screen_image.w * screen_image.h);
slouken@1895
   511
        switch (screen_image.psm) {
slouken@1895
   512
        case PS2_GS_PSMCT32:
slouken@1895
   513
            screen_image_size *= 4;
slouken@1895
   514
            break;
slouken@1895
   515
        case PS2_GS_PSMCT24:
slouken@1895
   516
            screen_image_size *= 3;
slouken@1895
   517
            break;
slouken@1895
   518
        case PS2_GS_PSMCT16:
slouken@1895
   519
            screen_image_size *= 2;
slouken@1895
   520
            break;
slouken@1895
   521
        }
slouken@1895
   522
        screen_image_size = (screen_image_size + 15) & ~15;
slouken@70
   523
slouken@1895
   524
        /* Set up the memory for screen update DMA commands */
slouken@1895
   525
        head_tags_mem = (unsigned long long *) (mapped_mem + pixels_len);
slouken@1895
   526
        image_tags_mem = (unsigned long long *)
slouken@1895
   527
            ((caddr_t) head_tags_mem + sizeof(head_tags));
slouken@1895
   528
        SDL_memcpy(head_tags_mem, head_tags, sizeof(head_tags));
slouken@1895
   529
        if (saved_vinfo.mode != PS2_GS_VESA) {
slouken@1895
   530
            tex_tags_mem = (unsigned long long *)
slouken@1895
   531
                ((caddr_t) image_tags_mem + ((2 * MAXTAGS) * 16));
slouken@1895
   532
            scale_tags_mem = (unsigned long long *)
slouken@1895
   533
                ((caddr_t) tex_tags_mem + sizeof(tex_tags));
slouken@1895
   534
            SDL_memcpy(tex_tags_mem, tex_tags, sizeof(tex_tags));
slouken@1895
   535
            tex_tags_mem[2] =
slouken@1895
   536
                (vinfo.h * vinfo.w) / 64 +
slouken@1895
   537
                ((unsigned long long) screen_image.fbw << 14) +
slouken@1895
   538
                ((unsigned long long) screen_image.psm << 20) +
slouken@1895
   539
                ((unsigned long long) power_of_2(screen_image.w) << 26) +
slouken@1895
   540
                ((unsigned long long) power_of_2(screen_image.h) << 30) +
slouken@1895
   541
                ((unsigned long long) 1 << 34) +
slouken@1895
   542
                ((unsigned long long) 1 << 35);
slouken@1895
   543
            SDL_memcpy(scale_tags_mem, scale_tags, sizeof(scale_tags));
slouken@1895
   544
            scale_tags_mem[8] =
slouken@1895
   545
                ((unsigned long long) screen_image.w * 16) +
slouken@1895
   546
                (((unsigned long long) screen_image.h * 16) << 16);
slouken@1895
   547
            scale_tags_mem[10] =
slouken@1895
   548
                ((unsigned long long) vinfo.w * 16) +
slouken@1895
   549
                (((unsigned long long) vinfo.h * 16) << 16);
slouken@1895
   550
        }
slouken@1895
   551
    }
slouken@1895
   552
    current->pixels = NULL;
slouken@1895
   553
    if (SDL_getenv("SDL_FULLSCREEN_UPDATE")) {
slouken@1895
   554
        /* Correct semantics */
slouken@1895
   555
        current->flags |= SDL_ASYNCBLIT;
slouken@1895
   556
    } else {
slouken@1895
   557
        /* We lie here - the screen memory isn't really the visible
slouken@1895
   558
           display memory and still requires an update, but this
slouken@1895
   559
           has the desired effect for most applications.
slouken@1895
   560
         */
slouken@1895
   561
        current->flags |= SDL_HWSURFACE;
slouken@1895
   562
    }
slouken@70
   563
slouken@1895
   564
    /* Set the update rectangle function */
slouken@1895
   565
    this->UpdateRects = GS_DMAFullUpdate;
slouken@70
   566
slouken@1895
   567
    /* We're done */
slouken@1895
   568
    return (current);
slouken@70
   569
}
slouken@70
   570
slouken@70
   571
/* We don't support hardware surfaces yet */
slouken@1895
   572
static int
slouken@1895
   573
GS_AllocHWSurface(_THIS, SDL_Surface * surface)
slouken@70
   574
{
slouken@1895
   575
    return (-1);
slouken@70
   576
}
slouken@2735
   577
slouken@1895
   578
static void
slouken@1895
   579
GS_FreeHWSurface(_THIS, SDL_Surface * surface)
slouken@70
   580
{
slouken@1895
   581
    return;
slouken@70
   582
}
slouken@2735
   583
slouken@1895
   584
static int
slouken@1895
   585
GS_LockHWSurface(_THIS, SDL_Surface * surface)
slouken@70
   586
{
slouken@1895
   587
    if (surface == this->screen) {
slouken@1895
   588
        /* Since mouse motion affects 'pixels', lock it */
slouken@1895
   589
        SDL_LockCursor();
slouken@70
   590
slouken@1895
   591
        /* Make sure any pending DMA has completed */
slouken@1895
   592
        if (dma_pending) {
slouken@1895
   593
            ioctl(console_fd, PS2IOC_SENDQCT, 1);
slouken@1895
   594
            dma_pending = 0;
slouken@1895
   595
        }
slouken@70
   596
slouken@1895
   597
        /* If the cursor is drawn on the DMA area, remove it */
slouken@1895
   598
        if (cursor_drawn) {
slouken@1895
   599
            surface->pixels = mapped_mem + surface->offset;
slouken@1895
   600
            SDL_EraseCursorNoLock(this->screen);
slouken@1895
   601
            cursor_drawn = 0;
slouken@1895
   602
        }
slouken@70
   603
slouken@1895
   604
        /* Set the surface pixels to the base of the DMA area */
slouken@1895
   605
        surface->pixels = mapped_mem;
slouken@70
   606
slouken@1895
   607
        /* We're finished! */
slouken@1895
   608
        SDL_UnlockCursor();
slouken@1895
   609
    }
slouken@1895
   610
    return (0);
slouken@70
   611
}
slouken@2735
   612
slouken@1895
   613
static void
slouken@1895
   614
GS_UnlockHWSurface(_THIS, SDL_Surface * surface)
slouken@70
   615
{
slouken@1895
   616
    if (surface == this->screen) {
slouken@1895
   617
        /* Since mouse motion affects 'pixels', lock it */
slouken@1895
   618
        SDL_LockCursor();
slouken@1895
   619
        surface->pixels = NULL;
slouken@1895
   620
        SDL_UnlockCursor();
slouken@1895
   621
    }
slouken@70
   622
}
slouken@70
   623
slouken@1895
   624
static void
slouken@1895
   625
GS_DMAFullUpdate(_THIS, int numrects, SDL_Rect * rects)
slouken@70
   626
{
slouken@1895
   627
    /* Lock so we aren't interrupted by a mouse update */
slouken@1895
   628
    SDL_LockCursor();
slouken@70
   629
slouken@1895
   630
    /* Make sure any pending DMA has completed */
slouken@1895
   631
    if (dma_pending) {
slouken@1895
   632
        ioctl(console_fd, PS2IOC_SENDQCT, 1);
slouken@1895
   633
        dma_pending = 0;
slouken@1895
   634
    }
slouken@70
   635
slouken@1895
   636
    /* If the mouse is visible, draw it on the DMA area */
slouken@1895
   637
    if ((SDL_cursorstate & CURSOR_VISIBLE) && !cursor_drawn) {
slouken@1895
   638
        this->screen->pixels = mapped_mem + this->screen->offset;
slouken@1895
   639
        SDL_DrawCursorNoLock(this->screen);
slouken@1895
   640
        this->screen->pixels = NULL;
slouken@1895
   641
        cursor_drawn = 1;
slouken@1895
   642
    }
slouken@70
   643
slouken@1895
   644
    /* Put the image onto the screen */
slouken@1895
   645
    loadimage_nonblock(console_fd,
slouken@1895
   646
                       &screen_image, screen_image_size,
slouken@1895
   647
                       head_tags_mem, image_tags_mem);
slouken@1895
   648
    if (screen_image.y > 0) {
slouken@1895
   649
        /* Need to scale offscreen image to TV output */
slouken@1895
   650
        ioctl(console_fd, PS2IOC_SENDQCT, 1);
slouken@1895
   651
        dma_pending = 0;
slouken@1895
   652
        scaleimage_nonblock(console_fd, tex_tags_mem, scale_tags_mem);
slouken@1895
   653
    } else {
slouken@1895
   654
        dma_pending = 1;
slouken@1895
   655
    }
slouken@70
   656
slouken@1895
   657
    /* We're finished! */
slouken@1895
   658
    SDL_UnlockCursor();
slouken@70
   659
}
slouken@70
   660
slouken@1895
   661
static int
slouken@1895
   662
GS_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color * colors)
slouken@70
   663
{
slouken@1895
   664
    return (0);
slouken@70
   665
}
slouken@70
   666
slouken@1895
   667
static void
slouken@1895
   668
GS_VideoQuit(_THIS)
slouken@70
   669
{
slouken@1895
   670
    /* Close console and input file descriptors */
slouken@1895
   671
    if (console_fd > 0) {
slouken@1895
   672
        /* Unmap the video framebuffer */
slouken@1895
   673
        if (mapped_mem) {
slouken@1895
   674
            /* Unmap the video framebuffer */
slouken@1895
   675
            munmap(mapped_mem, mapped_len);
slouken@1895
   676
            mapped_mem = NULL;
slouken@1895
   677
        }
slouken@1895
   678
        close(memory_fd);
slouken@70
   679
slouken@1895
   680
        /* Restore the original video mode */
slouken@1895
   681
        if (GS_InGraphicsMode(this)) {
slouken@1895
   682
            ioctl(console_fd, PS2IOC_SSCREENINFO, &saved_vinfo);
slouken@1895
   683
        }
slouken@70
   684
slouken@1895
   685
        /* We're all done with the graphics device */
slouken@1895
   686
        close(console_fd);
slouken@1895
   687
        console_fd = -1;
slouken@1895
   688
    }
slouken@1895
   689
    GS_CloseMouse(this);
slouken@1895
   690
    GS_CloseKeyboard(this);
slouken@70
   691
}
slouken@1895
   692
slouken@1895
   693
/* vi: set ts=4 sw=4 expandtab: */