view src/video/photon/SDL_ph_image.c @ 2776:caf3d5b2153f

Sort by HID usage, which makes more sense and is more cross-platform
author Sam Lantinga <slouken@libsdl.org>
date Sat, 08 Nov 2008 07:34:21 +0000
parents 204be4fc2726
children 99210400e8b9
line wrap: on
line source

/*
    SDL - Simple DirectMedia Layer
    Copyright (C) 1997-2006 Sam Lantinga

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

    Sam Lantinga
    slouken@libsdl.org
*/
#include "SDL_config.h"

#include <Ph.h>
#include <photon/Pg.h>

#include "SDL_endian.h"
#include "SDL_video.h"
#include "../SDL_pixels_c.h"
#include "SDL_ph_video.h"
#include "SDL_ph_image_c.h"
#include "SDL_ph_modes_c.h"
#include "SDL_ph_gl.h"

int
ph_SetupImage(_THIS, SDL_Surface * screen)
{
    PgColor_t *palette = NULL;
    int type = 0;
    int bpp;

    bpp = screen->format->BitsPerPixel;

    /* Determine image type */
    switch (bpp) {
    case 8:
        {
            type = Pg_IMAGE_PALETTE_BYTE;
        }
        break;
    case 15:
        {
            type = Pg_IMAGE_DIRECT_555;
        }
        break;
    case 16:
        {
            type = Pg_IMAGE_DIRECT_565;
        }
        break;
    case 24:
        {
            type = Pg_IMAGE_DIRECT_888;
        }
        break;
    case 32:
        {
            type = Pg_IMAGE_DIRECT_8888;
        }
        break;
    default:
        {
            SDL_SetError("ph_SetupImage(): unsupported bpp=%d !\n", bpp);
            return -1;
        }
        break;
    }

    /* palette emulation code */
    if ((bpp == 8) && (desktoppal == SDLPH_PAL_EMULATE)) {
        /* creating image palette */
        palette = SDL_malloc(_Pg_MAX_PALETTE * sizeof(PgColor_t));
        if (palette == NULL) {
            SDL_SetError
                ("ph_SetupImage(): can't allocate memory for palette !\n");
            return -1;
        }
        PgGetPalette(palette);

        /* using shared memory for speed (set last param to 1) */
        if ((SDL_Image =
             PhCreateImage(NULL, screen->w, screen->h, type, palette,
                           _Pg_MAX_PALETTE, 1)) == NULL) {
            SDL_SetError
                ("ph_SetupImage(): PhCreateImage() failed for bpp=8 !\n");
            SDL_free(palette);
            return -1;
        }
    } else {
        /* using shared memory for speed (set last param to 1) */
        if ((SDL_Image =
             PhCreateImage(NULL, screen->w, screen->h, type, NULL, 0,
                           1)) == NULL) {
            SDL_SetError
                ("ph_SetupImage(): PhCreateImage() failed for bpp=%d !\n",
                 bpp);
            return -1;
        }
    }

    screen->pixels = SDL_Image->image;
    screen->pitch = SDL_Image->bpl;

    this->UpdateRects = ph_NormalUpdate;

    return 0;
}

int
ph_SetupOCImage(_THIS, SDL_Surface * screen)
{
    int type = 0;
    int bpp;

    OCImage.flags = screen->flags;

    bpp = screen->format->BitsPerPixel;

    /* Determine image type */
    switch (bpp) {
    case 8:
        {
            type = Pg_IMAGE_PALETTE_BYTE;
        }
        break;
    case 15:
        {
            type = Pg_IMAGE_DIRECT_555;
        }
        break;
    case 16:
        {
            type = Pg_IMAGE_DIRECT_565;
        }
        break;
    case 24:
        {
            type = Pg_IMAGE_DIRECT_888;
        }
        break;
    case 32:
        {
            type = Pg_IMAGE_DIRECT_8888;
        }
        break;
    default:
        {
            SDL_SetError("ph_SetupOCImage(): unsupported bpp=%d !\n", bpp);
            return -1;
        }
        break;
    }

    /* Currently offscreen contexts with the same bit depth as display bpp only can be created */
    OCImage.offscreen_context =
        PdCreateOffscreenContext(0, screen->w, screen->h,
                                 Pg_OSC_MEM_PAGE_ALIGN);

    if (OCImage.offscreen_context == NULL) {
        SDL_SetError
            ("ph_SetupOCImage(): PdCreateOffscreenContext() function failed !\n");
        return -1;
    }

    screen->pitch = OCImage.offscreen_context->pitch;

    OCImage.dc_ptr =
        (unsigned char *) PdGetOffscreenContextPtr(OCImage.offscreen_context);

    if (OCImage.dc_ptr == NULL) {
        SDL_SetError
            ("ph_SetupOCImage(): PdGetOffscreenContextPtr function failed !\n");
        PhDCRelease(OCImage.offscreen_context);
        return -1;
    }

    OCImage.FrameData0 = OCImage.dc_ptr;
    OCImage.CurrentFrameData = OCImage.FrameData0;
    OCImage.current = 0;

    PhDCSetCurrent(OCImage.offscreen_context);

    screen->pixels = OCImage.CurrentFrameData;

    this->UpdateRects = ph_OCUpdate;

    return 0;
}

int
ph_SetupFullScreenImage(_THIS, SDL_Surface * screen)
{
    OCImage.flags = screen->flags;

    /* Begin direct and fullscreen mode */
    if (!ph_EnterFullScreen(this, screen, PH_ENTER_DIRECTMODE)) {
        return -1;
    }

    /* store palette for fullscreen */
    if ((screen->format->BitsPerPixel == 8) && (desktopbpp != 8)) {
        PgGetPalette(savedpal);
        PgGetPalette(syspalph);
    }

    OCImage.offscreen_context =
        PdCreateOffscreenContext(0, 0, 0,
                                 Pg_OSC_MAIN_DISPLAY | Pg_OSC_MEM_PAGE_ALIGN
                                 | Pg_OSC_CRTC_SAFE);
    if (OCImage.offscreen_context == NULL) {
        SDL_SetError
            ("ph_SetupFullScreenImage(): PdCreateOffscreenContext() function failed !\n");
        return -1;
    }

    if ((screen->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF) {
        OCImage.offscreen_backcontext =
            PdDupOffscreenContext(OCImage.offscreen_context,
                                  Pg_OSC_MEM_PAGE_ALIGN | Pg_OSC_CRTC_SAFE);
        if (OCImage.offscreen_backcontext == NULL) {
            SDL_SetError
                ("ph_SetupFullScreenImage(): PdCreateOffscreenContext(back) function failed !\n");
            return -1;
        }
    }

    OCImage.FrameData0 =
        (unsigned char *) PdGetOffscreenContextPtr(OCImage.offscreen_context);
    if (OCImage.FrameData0 == NULL) {
        SDL_SetError
            ("ph_SetupFullScreenImage(): PdGetOffscreenContextPtr() function failed !\n");
        ph_DestroyImage(this, screen);
        return -1;
    }

    if ((screen->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF) {
        OCImage.FrameData1 = (unsigned char *)
            PdGetOffscreenContextPtr(OCImage.offscreen_backcontext);
        if (OCImage.FrameData1 == NULL) {
            SDL_SetError
                ("ph_SetupFullScreenImage(back): PdGetOffscreenContextPtr() function failed !\n");
            ph_DestroyImage(this, screen);
            return -1;
        }
    }

    /* wait for the hardware */
    PgFlush();
    PgWaitHWIdle();

    if ((screen->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF) {
        OCImage.current = 0;
        PhDCSetCurrent(OCImage.offscreen_context);
        screen->pitch = OCImage.offscreen_context->pitch;
        screen->pixels = OCImage.FrameData0;

        /* emulate 640x400 videomode */
        if (videomode_emulatemode == 1) {
            int i;

            for (i = 0; i < 40; i++) {
                SDL_memset(screen->pixels + screen->pitch * i, 0x00,
                           screen->pitch);
            }
            for (i = 440; i < 480; i++) {
                SDL_memset(screen->pixels + screen->pitch * i, 0x00,
                           screen->pitch);
            }
            screen->pixels += screen->pitch * 40;
        }
        PgSwapDisplay(OCImage.offscreen_backcontext, 0);
    } else {
        OCImage.current = 0;
        PhDCSetCurrent(OCImage.offscreen_context);
        screen->pitch = OCImage.offscreen_context->pitch;
        screen->pixels = OCImage.FrameData0;

        /* emulate 640x400 videomode */
        if (videomode_emulatemode == 1) {
            int i;

            for (i = 0; i < 40; i++) {
                SDL_memset(screen->pixels + screen->pitch * i, 0x00,
                           screen->pitch);
            }
            for (i = 440; i < 480; i++) {
                SDL_memset(screen->pixels + screen->pitch * i, 0x00,
                           screen->pitch);
            }
            screen->pixels += screen->pitch * 40;
        }
    }

    this->UpdateRects = ph_OCDCUpdate;

    /* wait for the hardware */
    PgFlush();
    PgWaitHWIdle();

    return 0;
}

#if SDL_VIDEO_OPENGL

int
ph_SetupOpenGLImage(_THIS, SDL_Surface * screen)
{
    this->UpdateRects = ph_OpenGLUpdate;
    screen->pixels = NULL;
    screen->pitch = NULL;

#if (_NTO_VERSION >= 630)
    if ((screen->flags & SDL_FULLSCREEN) == SDL_FULLSCREEN) {
        if (!ph_EnterFullScreen(this, screen, PH_IGNORE_DIRECTMODE)) {
            screen->flags &= ~SDL_FULLSCREEN;
            return -1;
        }
    }
#endif /* 6.3.0 */

    if (ph_SetupOpenGLContext
        (this, screen->w, screen->h, screen->format->BitsPerPixel,
         screen->flags) != 0) {
        screen->flags &= ~SDL_INTERNALOPENGL;
        return -1;
    }

    return 0;
}

#endif /* SDL_VIDEO_OPENGL */

void
ph_DestroyImage(_THIS, SDL_Surface * screen)
{

#if SDL_VIDEO_OPENGL
    if (screen->flags & SDL_INTERNALOPENGL) {
        if (oglctx) {
#if (_NTO_VERSION < 630)
            PhDCSetCurrent(NULL);
            PhDCRelease(oglctx);
#else
            qnxgl_context_destroy(oglctx);
            qnxgl_buffers_destroy(oglbuffers);
            qnxgl_finish();
#endif /* 6.3.0 */
            oglctx = NULL;
            oglbuffers = NULL;
            oglflags = 0;
            oglbpp = 0;
        }
#if (_NTO_VERSION >= 630)
        if (currently_fullscreen) {
            ph_LeaveFullScreen(this);
        }
#endif /* 6.3.0 */

        return;
    }
#endif /* SDL_VIDEO_OPENGL */

    if (currently_fullscreen) {
        /* if we right now in 8bpp fullscreen we must release palette */
        if ((screen->format->BitsPerPixel == 8) && (desktopbpp != 8)) {
            PgSetPalette(syspalph, 0, -1, 0, 0, 0);
            PgSetPalette(savedpal, 0, 0, _Pg_MAX_PALETTE,
                         Pg_PALSET_GLOBAL | Pg_PALSET_FORCE_EXPOSE, 0);
            PgFlush();
        }
        ph_LeaveFullScreen(this);
    }

    if (OCImage.offscreen_context != NULL) {
        PhDCRelease(OCImage.offscreen_context);
        OCImage.offscreen_context = NULL;
        OCImage.FrameData0 = NULL;
    }
    if (OCImage.offscreen_backcontext != NULL) {
        PhDCRelease(OCImage.offscreen_backcontext);
        OCImage.offscreen_backcontext = NULL;
        OCImage.FrameData1 = NULL;
    }
    OCImage.CurrentFrameData = NULL;

    if (SDL_Image) {
        /* if palette allocated, free it */
        if (SDL_Image->palette) {
            SDL_free(SDL_Image->palette);
        }
        PgShmemDestroy(SDL_Image->image);
        SDL_free(SDL_Image);
    }

    /* Must be zeroed everytime */
    SDL_Image = NULL;

    if (screen) {
        screen->pixels = NULL;
    }
}

int
ph_UpdateHWInfo(_THIS)
{
    PgVideoModeInfo_t vmode;
    PgHWCaps_t hwcaps;

    /* Update video ram amount */
    if (PgGetGraphicsHWCaps(&hwcaps) < 0) {
        SDL_SetError
            ("ph_UpdateHWInfo(): GetGraphicsHWCaps() function failed !\n");
        return -1;
    }
    this->info.video_mem = hwcaps.currently_available_video_ram / 1024;

    /* obtain current mode capabilities */
    if (PgGetVideoModeInfo(hwcaps.current_video_mode, &vmode) < 0) {
        SDL_SetError
            ("ph_UpdateHWInfo(): GetVideoModeInfo() function failed !\n");
        return -1;
    }

    if ((vmode.mode_capabilities1 & PgVM_MODE_CAP1_OFFSCREEN) ==
        PgVM_MODE_CAP1_OFFSCREEN) {
        /* this is a special test for drivers which tries to lie about offscreen capability */
        if (hwcaps.currently_available_video_ram != 0) {
            this->info.hw_available = 1;
        } else {
            this->info.hw_available = 0;
        }
    } else {
        this->info.hw_available = 0;
    }

    if ((vmode.mode_capabilities2 & PgVM_MODE_CAP2_RECTANGLE) ==
        PgVM_MODE_CAP2_RECTANGLE) {
        this->info.blit_fill = 1;
    } else {
        this->info.blit_fill = 0;
    }

    if ((vmode.mode_capabilities2 & PgVM_MODE_CAP2_BITBLT) ==
        PgVM_MODE_CAP2_BITBLT) {
        this->info.blit_hw = 1;
    } else {
        this->info.blit_hw = 0;
    }

    if ((vmode.mode_capabilities2 & PgVM_MODE_CAP2_ALPHA_BLEND) ==
        PgVM_MODE_CAP2_ALPHA_BLEND) {
        this->info.blit_hw_A = 1;
    } else {
        this->info.blit_hw_A = 0;
    }

    if ((vmode.mode_capabilities2 & PgVM_MODE_CAP2_CHROMA) ==
        PgVM_MODE_CAP2_CHROMA) {
        this->info.blit_hw_CC = 1;
    } else {
        this->info.blit_hw_CC = 0;
    }

    return 0;
}

int
ph_SetupUpdateFunction(_THIS, SDL_Surface * screen, Uint32 flags)
{
    int setupresult = -1;

    ph_DestroyImage(this, screen);

#if SDL_VIDEO_OPENGL
    if (flags & SDL_INTERNALOPENGL) {
        setupresult = ph_SetupOpenGLImage(this, screen);
    } else {
#endif
        if ((flags & SDL_FULLSCREEN) == SDL_FULLSCREEN) {
            setupresult = ph_SetupFullScreenImage(this, screen);
        } else {
            if ((flags & SDL_HWSURFACE) == SDL_HWSURFACE) {
                setupresult = ph_SetupOCImage(this, screen);
            } else {
                setupresult = ph_SetupImage(this, screen);
            }
        }
#if SDL_VIDEO_OPENGL
    }
#endif
    if (setupresult != -1) {
        ph_UpdateHWInfo(this);
    }

    return setupresult;
}

int
ph_AllocHWSurface(_THIS, SDL_Surface * surface)
{
    PgHWCaps_t hwcaps;

    if (surface->hwdata != NULL) {
        SDL_SetError("ph_AllocHWSurface(): hwdata already exists!\n");
        return -1;
    }
    surface->hwdata = SDL_malloc(sizeof(struct private_hwdata));
    SDL_memset(surface->hwdata, 0x00, sizeof(struct private_hwdata));
    surface->hwdata->offscreenctx =
        PdCreateOffscreenContext(0, surface->w, surface->h,
                                 Pg_OSC_MEM_PAGE_ALIGN);
    if (surface->hwdata->offscreenctx == NULL) {
        SDL_SetError
            ("ph_AllocHWSurface(): PdCreateOffscreenContext() function failed !\n");
        return -1;
    }
    surface->pixels = PdGetOffscreenContextPtr(surface->hwdata->offscreenctx);
    if (surface->pixels == NULL) {
        PhDCRelease(surface->hwdata->offscreenctx);
        SDL_SetError
            ("ph_AllocHWSurface(): PdGetOffscreenContextPtr() function failed !\n");
        return -1;
    }
    surface->pitch = surface->hwdata->offscreenctx->pitch;
    surface->flags |= SDL_HWSURFACE;
    surface->flags |= SDL_PREALLOC;

#if 0                           /* FIXME */
    /* create simple offscreen lock */
    surface->hwdata->crlockparam.flags = 0;
    if (PdCreateOffscreenLock
        (surface->hwdata->offscreenctx, &surface->hwdata->crlockparam) != EOK)
    {
        PhDCRelease(surface->hwdata->offscreenctx);
        SDL_SetError("ph_AllocHWSurface(): Can't create offscreen lock !\n");
        return -1;
    }
#endif /* 0 */

    /* Update video ram amount */
    if (PgGetGraphicsHWCaps(&hwcaps) < 0) {
        PdDestroyOffscreenLock(surface->hwdata->offscreenctx);
        PhDCRelease(surface->hwdata->offscreenctx);
        SDL_SetError
            ("ph_AllocHWSurface(): GetGraphicsHWCaps() function failed !\n");
        return -1;
    }
    this->info.video_mem = hwcaps.currently_available_video_ram / 1024;

    return 0;
}

void
ph_FreeHWSurface(_THIS, SDL_Surface * surface)
{
    PgHWCaps_t hwcaps;

    if (surface->hwdata == NULL) {
        SDL_SetError("ph_FreeHWSurface(): no hwdata!\n");
        return;
    }
    if (surface->hwdata->offscreenctx == NULL) {
        SDL_SetError("ph_FreeHWSurface(): no offscreen context to delete!\n");
        return;
    }
#if 0                           /* FIXME */
    /* unlock the offscreen context if it has been locked before destroy it */
    if (PdIsOffscreenLocked(surface->hwdata->offscreenctx) == Pg_OSC_LOCKED) {
        PdUnlockOffscreen(surface->hwdata->offscreenctx);
    }

    PdDestroyOffscreenLock(surface->hwdata->offscreenctx);
#endif /* 0 */

    PhDCRelease(surface->hwdata->offscreenctx);

    SDL_free(surface->hwdata);
    surface->hwdata = NULL;

    /* Update video ram amount */
    if (PgGetGraphicsHWCaps(&hwcaps) < 0) {
        SDL_SetError
            ("ph_FreeHWSurface(): GetGraphicsHWCaps() function failed !\n");
        return;
    }
    this->info.video_mem = hwcaps.currently_available_video_ram / 1024;

    return;
}

int
ph_CheckHWBlit(_THIS, SDL_Surface * src, SDL_Surface * dst)
{
    if ((src->hwdata == NULL) && (src != this->screen)) {
        SDL_SetError
            ("ph_CheckHWBlit(): Source surface haven't hardware specific data.\n");
        src->flags &= ~SDL_HWACCEL;
        return -1;
    }
    if ((src->flags & SDL_HWSURFACE) != SDL_HWSURFACE) {
        SDL_SetError
            ("ph_CheckHWBlit(): Source surface isn't a hardware surface.\n");
        src->flags &= ~SDL_HWACCEL;
        return -1;
    }

    if ((src->flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY) {
        if (this->info.blit_hw_CC != 1) {
            src->flags &= ~SDL_HWACCEL;
            src->map->hw_blit = NULL;
            return -1;
        }
    }

    if ((src->flags & SDL_SRCALPHA) == SDL_SRCALPHA) {
        if (this->info.blit_hw_A != 1) {
            src->flags &= ~SDL_HWACCEL;
            src->map->hw_blit = NULL;
            return -1;
        }
    }

    src->flags |= SDL_HWACCEL;
    src->map->hw_blit = ph_HWAccelBlit;

    return 1;
}

PgColor_t
ph_ExpandColor(_THIS, SDL_Surface * surface, Uint32 color)
{
    Uint32 truecolor;

    /* Photon API accepts true colors only during hw filling operations */
    switch (surface->format->BitsPerPixel) {
    case 8:
        {
            if ((surface->format->palette)
                && (color <= surface->format->palette->ncolors)) {
                truecolor =
                    PgRGB(surface->format->palette->colors[color].r,
                          surface->format->palette->colors[color].g,
                          surface->format->palette->colors[color].b);
            } else {
                SDL_SetError
                    ("ph_ExpandColor(): Color out of range for the 8bpp mode !\n");
                return 0xFFFFFFFFUL;
            }
        }
        break;
    case 15:
        {
            truecolor = ((color & 0x00007C00UL) << 9) | /* R */
                ((color & 0x000003E0UL) << 6) | /* G */
                ((color & 0x0000001FUL) << 3) | /* B */
                ((color & 0x00007000UL) << 4) | /* R compensation */
                ((color & 0x00000380UL) << 1) | /* G compensation */
                ((color & 0x0000001CUL) >> 2);  /* B compensation */
        }
        break;
    case 16:
        {
            truecolor = ((color & 0x0000F800UL) << 8) | /* R */
                ((color & 0x000007E0UL) << 5) | /* G */
                ((color & 0x0000001FUL) << 3) | /* B */
                ((color & 0x0000E000UL) << 3) | /* R compensation */
                ((color & 0x00000600UL) >> 1) | /* G compensation */
                ((color & 0x0000001CUL) >> 2);  /* B compensation */

        }
        break;
    case 24:
        {
            truecolor = color & 0x00FFFFFFUL;
        }
        break;
    case 32:
        {
            truecolor = color;
        }
        break;
    default:
        {
            SDL_SetError
                ("ph_ExpandColor(): Unsupported depth for the hardware operations !\n");
            return 0xFFFFFFFFUL;
        }
    }

    return truecolor;
}

int
ph_FillHWRect(_THIS, SDL_Surface * surface, SDL_Rect * rect, Uint32 color)
{
    PgColor_t oldcolor;
    Uint32 truecolor;
    int ydisp = 0;

    if (this->info.blit_fill != 1) {
        return -1;
    }

    truecolor = ph_ExpandColor(this, surface, color);
    if (truecolor == 0xFFFFFFFFUL) {
        return -1;
    }

    oldcolor = PgSetFillColor(truecolor);

    /* 640x400 videomode emulation */
    if (videomode_emulatemode == 1) {
        ydisp += 40;
    }

    PgDrawIRect(rect->x, rect->y + ydisp, rect->w + rect->x - 1,
                rect->h + rect->y + ydisp - 1, Pg_DRAW_FILL);
    PgSetFillColor(oldcolor);
    PgFlush();
    PgWaitHWIdle();

    return 0;
}

int
ph_FlipHWSurface(_THIS, SDL_Surface * screen)
{
    PhArea_t farea;

    if ((screen->flags & SDL_FULLSCREEN) == SDL_FULLSCREEN) {
        /* flush all drawing ops before blitting */
        PgFlush();
        PgWaitHWIdle();

        farea.pos.x = 0;
        farea.pos.y = 0;
        farea.size.w = screen->w;
        farea.size.h = screen->h;

        /* emulate 640x400 videomode */
        if (videomode_emulatemode == 1) {
            farea.pos.y += 40;
        }

        PgContextBlitArea(OCImage.offscreen_context, &farea,
                          OCImage.offscreen_backcontext, &farea);

        /* flush the blitting */
        PgFlush();
        PgWaitHWIdle();
    }
    return 0;
}

int
ph_LockHWSurface(_THIS, SDL_Surface * surface)
{

#if 0                           /* FIXME */
    int lockresult;

    if (surface->hwdata == NULL) {
        return;
    }

    surface->hwdata->lockparam.flags = 0;
    surface->hwdata->lockparam.time_out = NULL;
    lockresult =
        PdLockOffscreen(surface->hwdata->offscreenctx,
                        &surface->hwdata->lockparam);

    switch (lockresult) {
    case EOK:
        break;
    case Pg_OSC_LOCK_DEADLOCK:
        SDL_SetError("ph_LockHWSurface(): Deadlock detected !\n");
        return -1;
    case Pg_OSC_LOCK_INVALID:
        SDL_SetError("ph_LockHWSurface(): Lock invalid !\n");
        return -1;
    default:
        SDL_SetError("ph_LockHWSurface(): Can't lock the surface !\n");
        return -1;
    }
#endif /* 0 */

    return 0;
}

void
ph_UnlockHWSurface(_THIS, SDL_Surface * surface)
{

#if 0                           /* FIXME */
    int unlockresult;

    if ((surface == NULL) || (surface->hwdata == NULL)) {
        return;
    }

    if (PdIsOffscreenLocked(surface->hwdata->offscreenctx) == Pg_OSC_LOCKED) {
        unlockresult = PdUnlockOffscreen(surface->hwdata->offscreenctx);
    }
#endif /* 0 */

    return;
}

int
ph_HWAccelBlit(SDL_Surface * src, SDL_Rect * srcrect, SDL_Surface * dst,
               SDL_Rect * dstrect)
{
    SDL_VideoDevice *this = current_video;
    PhArea_t srcarea;
    PhArea_t dstarea;
    int ydisp = 0;

    /* 640x400 videomode emulation */
    if (videomode_emulatemode == 1) {
        ydisp += 40;
    }

    srcarea.pos.x = srcrect->x;
    srcarea.pos.y = srcrect->y;
    srcarea.size.w = srcrect->w;
    srcarea.size.h = srcrect->h;

    dstarea.pos.x = dstrect->x;
    dstarea.pos.y = dstrect->y;
    dstarea.size.w = dstrect->w;
    dstarea.size.h = dstrect->h;

    if (((src == this->screen) || (src->hwdata != NULL))
        && ((dst == this->screen) || (dst->hwdata != NULL))) {
        if ((src->flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY) {
            ph_SetHWColorKey(this, src, src->format->colorkey);
            PgChromaOn();
        }

        if ((src->flags & SDL_SRCALPHA) == SDL_SRCALPHA) {
            ph_SetHWAlpha(this, src, src->format->alpha);
            PgAlphaOn();
        }

        if (dst == this->screen) {
            if (src == this->screen) {
                /* blitting from main screen to main screen */
                dstarea.pos.y += ydisp;
                srcarea.pos.y += ydisp;
                PgContextBlitArea(OCImage.offscreen_context, &srcarea,
                                  OCImage.offscreen_context, &dstarea);
            } else {
                /* blitting from offscreen to main screen */
                dstarea.pos.y += ydisp;
                PgContextBlitArea(src->hwdata->offscreenctx, &srcarea,
                                  OCImage.offscreen_context, &dstarea);
            }
        } else {
            if (src == this->screen) {
                /* blitting from main screen to offscreen */
                srcarea.pos.y += ydisp;
                PgContextBlitArea(OCImage.offscreen_context, &srcarea,
                                  dst->hwdata->offscreenctx, &dstarea);
            } else {
                /* blitting offscreen to offscreen */
                PgContextBlitArea(src->hwdata->offscreenctx, &srcarea,
                                  dst->hwdata->offscreenctx, &dstarea);
            }
        }

        if ((src->flags & SDL_SRCALPHA) == SDL_SRCALPHA) {
            PgAlphaOff();
        }

        if ((src->flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY) {
            PgChromaOff();
        }
    } else {
        SDL_SetError
            ("ph_HWAccelBlit(): Source or target surface is not a hardware surface !\n");
        return -1;
    }

    PgFlush();
    PgWaitHWIdle();

    return 0;
}

int
ph_SetHWColorKey(_THIS, SDL_Surface * surface, Uint32 key)
{
    if (this->info.blit_hw_CC != 1) {
        return -1;
    }

    if (surface->hwdata != NULL) {
        surface->hwdata->colorkey = ph_ExpandColor(this, surface, key);
        if (surface->hwdata->colorkey == 0xFFFFFFFFUL) {
            return -1;
        }
    }
    PgSetChroma(surface->hwdata->colorkey,
                Pg_CHROMA_SRC_MATCH | Pg_CHROMA_NODRAW);

    return 0;
}

int
ph_SetHWAlpha(_THIS, SDL_Surface * surface, Uint8 alpha)
{
    if (this->info.blit_hw_A != 1) {
        return -1;
    }

    PgSetAlphaBlend(NULL, alpha);

    return 0;
}

#if SDL_VIDEO_OPENGL
void
ph_OpenGLUpdate(_THIS, int numrects, SDL_Rect * rects)
{
    this->GL_SwapBuffers(this);

    return;
}
#endif /* SDL_VIDEO_OPENGL */

void
ph_NormalUpdate(_THIS, int numrects, SDL_Rect * rects)
{
    PhPoint_t ph_pos;
    PhRect_t ph_rect;
    int i;

    for (i = 0; i < numrects; ++i) {
        if (rects[i].w == 0) {  /* Clipped? dunno why but this occurs sometime. */
            continue;
        }

        if (rects[i].h == 0) {  /* Clipped? dunno why but this occurs sometime. */
            continue;
        }

        ph_pos.x = rects[i].x;
        ph_pos.y = rects[i].y;
        ph_rect.ul.x = rects[i].x;
        ph_rect.ul.y = rects[i].y;
        ph_rect.lr.x = rects[i].x + rects[i].w;
        ph_rect.lr.y = rects[i].y + rects[i].h;

        if (PgDrawPhImageRectmx(&ph_pos, SDL_Image, &ph_rect, 0) < 0) {
            SDL_SetError("ph_NormalUpdate(): PgDrawPhImageRectmx failed!\n");
            return;
        }
    }

    if (PgFlush() < 0) {
        SDL_SetError("ph_NormalUpdate(): PgFlush() function failed!\n");
    }
}

void
ph_OCUpdate(_THIS, int numrects, SDL_Rect * rects)
{
    int i;

    PhPoint_t zero = { 0, 0 };
    PhArea_t src_rect;
    PhArea_t dest_rect;

    PgSetTranslation(&zero, 0);
    PgSetRegion(PtWidgetRid(window));
    PgSetClipping(0, NULL);

    PgFlush();
    PgWaitHWIdle();

    for (i = 0; i < numrects; ++i) {
        if (rects[i].w == 0) {  /* Clipped? */
            continue;
        }

        if (rects[i].h == 0) {  /* Clipped? */
            continue;
        }

        src_rect.pos.x = rects[i].x;
        src_rect.pos.y = rects[i].y;
        dest_rect.pos.x = rects[i].x;
        dest_rect.pos.y = rects[i].y;

        src_rect.size.w = rects[i].w;
        src_rect.size.h = rects[i].h;
        dest_rect.size.w = rects[i].w;
        dest_rect.size.h = rects[i].h;

        PgContextBlitArea(OCImage.offscreen_context, &src_rect, NULL,
                          &dest_rect);
    }

    if (PgFlush() < 0) {
        SDL_SetError("ph_OCUpdate(): PgFlush failed.\n");
    }
}

void
ph_OCDCUpdate(_THIS, int numrects, SDL_Rect * rects)
{
    PgWaitHWIdle();

    if (PgFlush() < 0) {
        SDL_SetError("ph_OCDCUpdate(): PgFlush failed.\n");
    }
}

/* vi: set ts=4 sw=4 expandtab: */