Support proper mode switching on RISC OS

main
Cameron Cawley 2021-08-05 23:16:29 +01:00 committed by Sam Lantinga
parent fe9bb74764
commit f8a8ca3e1f
5 changed files with 299 additions and 141 deletions

View File

@ -97,8 +97,8 @@ int RISCOS_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rect *
regs.r[0] = 512+52;
regs.r[1] = (int)driverdata->fb_area;
regs.r[2] = (int)driverdata->fb_sprite;
regs.r[3] = window->x << 1;
regs.r[4] = window->y << 1;
regs.r[3] = 0; /* window->x << 1; */
regs.r[4] = 0; /* window->y << 1; */
regs.r[5] = 0x50;
regs.r[6] = 0;
regs.r[7] = 0;

View File

@ -0,0 +1,255 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#if SDL_VIDEO_DRIVER_RISCOS
#include "../SDL_sysvideo.h"
#include "SDL_riscosvideo.h"
#include "SDL_riscosmodes.h"
#include <kernel.h>
#include <swis.h>
enum {
MODE_FLAG_565 = 1 << 7,
MODE_FLAG_COLOUR_SPACE = 0xF << 12,
MODE_FLAG_TBGR = 0,
MODE_FLAG_TRGB = 1 << 14,
MODE_FLAG_ABGR = 1 << 15,
MODE_FLAG_ARGB = MODE_FLAG_TRGB | MODE_FLAG_ABGR
};
static const struct {
SDL_PixelFormatEnum pixel_format;
int modeflags, ncolour, log2bpp;
} mode_to_pixelformat[] = {
/* { SDL_PIXELFORMAT_INDEX1LSB, 0, 1, 0 }, */
/* { SDL_PIXELFORMAT_INDEX2LSB, 0, 3, 1 }, */
/* { SDL_PIXELFORMAT_INDEX4LSB, 0, 15, 2 }, */
/* { SDL_PIXELFORMAT_INDEX8, MODE_FLAG_565, 255, 3 }, */
{ SDL_PIXELFORMAT_XBGR1555, MODE_FLAG_TBGR, 65535, 4 },
{ SDL_PIXELFORMAT_XRGB1555, MODE_FLAG_TRGB, 65535, 4 },
{ SDL_PIXELFORMAT_ABGR1555, MODE_FLAG_ABGR, 65535, 4 },
{ SDL_PIXELFORMAT_ARGB1555, MODE_FLAG_ARGB, 65535, 4 },
{ SDL_PIXELFORMAT_XBGR4444, MODE_FLAG_TBGR, 4095, 4 },
{ SDL_PIXELFORMAT_XRGB4444, MODE_FLAG_TRGB, 4095, 4 },
{ SDL_PIXELFORMAT_ABGR4444, MODE_FLAG_ABGR, 4095, 4 },
{ SDL_PIXELFORMAT_ARGB4444, MODE_FLAG_ARGB, 4095, 4 },
{ SDL_PIXELFORMAT_BGR565, MODE_FLAG_TBGR | MODE_FLAG_565, 65535, 4 },
{ SDL_PIXELFORMAT_RGB565, MODE_FLAG_TRGB | MODE_FLAG_565, 65535, 4 },
{ SDL_PIXELFORMAT_BGR24, MODE_FLAG_TBGR, 16777215, 6 },
{ SDL_PIXELFORMAT_RGB24, MODE_FLAG_TRGB, 16777215, 6 },
{ SDL_PIXELFORMAT_XBGR8888, MODE_FLAG_TBGR, -1, 5 },
{ SDL_PIXELFORMAT_XRGB8888, MODE_FLAG_TRGB, -1, 5 },
{ SDL_PIXELFORMAT_ABGR8888, MODE_FLAG_ABGR, -1, 5 },
{ SDL_PIXELFORMAT_ARGB8888, MODE_FLAG_ARGB, -1, 5 }
};
static SDL_PixelFormatEnum
RISCOS_ModeToPixelFormat(int ncolour, int modeflags, int log2bpp)
{
int i;
for (i = 0; i < SDL_arraysize(mode_to_pixelformat); i++) {
if (log2bpp == mode_to_pixelformat[i].log2bpp &&
(ncolour == mode_to_pixelformat[i].ncolour || ncolour == 0) &&
(modeflags & (MODE_FLAG_565 | MODE_FLAG_COLOUR_SPACE)) == mode_to_pixelformat[i].modeflags) {
return mode_to_pixelformat[i].pixel_format;
}
}
return SDL_PIXELFORMAT_UNKNOWN;
}
static size_t
measure_mode_block(const int *block)
{
size_t blockSize = (block[0] == 2) ? 7 : 5;
while(block[blockSize] != -1) {
blockSize += 2;
}
blockSize++;
return blockSize * 4;
}
static int *
read_mode_block(int *block, SDL_DisplayMode *mode)
{
int xres, yres, ncolour, modeflags, log2bpp, rate;
int *end;
xres = block[1];
yres = block[2];
if ((block[0] & 0xFF) == 1) {
log2bpp = block[3];
rate = block[4];
end = block + 5;
ncolour = (1 << (1 << log2bpp)) - 1;
modeflags = MODE_FLAG_TBGR;
} else if ((block[0] & 0xFF) == 3) {
ncolour = block[3];
modeflags = block[4];
log2bpp = block[5];
rate = block[6];
end = block + 7;
} else {
return NULL;
}
mode->w = xres;
mode->h = yres;
mode->format = RISCOS_ModeToPixelFormat(ncolour, modeflags, log2bpp);
mode->refresh_rate = rate;
return end;
}
static void *
copy_memory(const void *src, size_t size, size_t alloc)
{
void *dst = SDL_malloc(alloc);
if (dst) {
SDL_memcpy(dst, src, size);
}
return dst;
}
int
RISCOS_InitModes(_THIS)
{
SDL_DisplayMode mode;
int *current_mode;
_kernel_swi_regs regs;
_kernel_oserror *error;
size_t size;
regs.r[0] = 1;
error = _kernel_swi(OS_ScreenMode, &regs, &regs);
if (error != NULL) {
return SDL_SetError("Unable to retrieve the current screen mode: %s (%i)", error->errmess, error->errnum);
}
current_mode = (int *)regs.r[1];
if (!read_mode_block(current_mode, &mode)) {
return SDL_SetError("Unsupported mode block format %d", current_mode[0]);
}
size = measure_mode_block(current_mode);
mode.driverdata = copy_memory(current_mode, size, size);
if (!mode.driverdata) {
return SDL_OutOfMemory();
}
return SDL_AddBasicVideoDisplay(&mode);
}
void
RISCOS_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
{
SDL_DisplayMode mode;
_kernel_swi_regs regs;
_kernel_oserror *error;
void *block, *pos;
regs.r[0] = 2;
regs.r[2] = 0;
regs.r[6] = 0;
regs.r[7] = 0;
error = _kernel_swi(OS_ScreenMode, &regs, &regs);
if (error != NULL) {
SDL_SetError("Unable to enumerate screen modes: %s (%i)", error->errmess, error->errnum);
return;
}
block = SDL_malloc(-regs.r[7]);
if (!block) {
SDL_OutOfMemory();
return;
}
regs.r[6] = (int)block;
regs.r[7] = -regs.r[7];
error = _kernel_swi(OS_ScreenMode, &regs, &regs);
if (error != NULL) {
SDL_free(block);
SDL_SetError("Unable to enumerate screen modes: %s (%i)", error->errmess, error->errnum);
return;
}
for (pos = block; pos < (void *)regs.r[6]; pos += *((int *)pos)) {
size_t size;
void *end;
end = read_mode_block(pos + 4, &mode);
if (!end) {
continue;
}
if (mode.format == SDL_PIXELFORMAT_UNKNOWN)
continue;
size = (end - pos) - 4;
mode.driverdata = copy_memory(pos + 4, size, size + 4);
if (!mode.driverdata) {
SDL_OutOfMemory();
break;
}
*((int *)(mode.driverdata + size)) = -1;
if (!SDL_AddDisplayMode(display, &mode)) {
SDL_free(mode.driverdata);
}
}
SDL_free(block);
}
int
RISCOS_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
{
const char disable_cursor[] = { 23, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
_kernel_swi_regs regs;
_kernel_oserror *error;
int i;
regs.r[0] = 0;
regs.r[1] = (int)mode->driverdata;
error = _kernel_swi(OS_ScreenMode, &regs, &regs);
if (error != NULL) {
return SDL_SetError("Unable to set the current screen mode: %s (%i)", error->errmess, error->errnum);
}
/* Turn the text cursor off */
for (i = 0; i < SDL_arraysize(disable_cursor); i++) {
_kernel_oswrch(disable_cursor[i]);
}
return 0;
}
#endif /* SDL_VIDEO_DRIVER_RISCOS */
/* vi: set ts=4 sw=4 expandtab: */

View File

@ -0,0 +1,33 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#ifndef SDL_riscosmodes_h_
#define SDL_riscosmodes_h_
extern int RISCOS_InitModes(_THIS);
extern void RISCOS_GetDisplayModes(_THIS, SDL_VideoDisplay * display);
extern int RISCOS_SetDisplayMode(_THIS, SDL_VideoDisplay * display,
SDL_DisplayMode * mode);
#endif /* SDL_riscosmodes_h_ */
/* vi: set ts=4 sw=4 expandtab: */

View File

@ -22,21 +22,6 @@
#if SDL_VIDEO_DRIVER_RISCOS
/* Dummy SDL video driver implementation; this is just enough to make an
* SDL-based application THINK it's got a working video driver, for
* applications that call SDL_Init(SDL_INIT_VIDEO) when they don't need it,
* and also for use as a collection of stubs when porting SDL to a new
* platform for which you haven't yet written a valid video driver.
*
* This is also a great way to determine bottlenecks: if you think that SDL
* is a performance problem for a given platform, enable this driver, and
* then see if your application runs faster without video overhead.
*
* Initial work by Ryan C. Gordon (icculus@icculus.org). A good portion
* of this was cut-and-pasted from Stephane Peter's work in the AAlib
* SDL video driver. Renamed to "DUMMY" by Sam Lantinga.
*/
#include "SDL_video.h"
#include "SDL_mouse.h"
#include "../SDL_sysvideo.h"
@ -46,16 +31,13 @@
#include "SDL_riscosvideo.h"
#include "SDL_riscosevents_c.h"
#include "SDL_riscosframebuffer_c.h"
#include "SDL_riscosmodes.h"
#include "SDL_riscoswindow.h"
#include <kernel.h>
#include <swis.h>
#define RISCOSVID_DRIVER_NAME "riscos"
/* Initialization/Query functions */
static int RISCOS_VideoInit(_THIS);
static int RISCOS_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);
static void RISCOS_VideoQuit(_THIS);
/* RISC OS driver bootstrap functions */
@ -81,9 +63,11 @@ RISCOS_CreateDevice(int devindex)
/* Set the function pointers */
device->VideoInit = RISCOS_VideoInit;
device->VideoQuit = RISCOS_VideoQuit;
device->SetDisplayMode = RISCOS_SetDisplayMode;
device->PumpEvents = RISCOS_PumpEvents;
device->GetDisplayModes = RISCOS_GetDisplayModes;
device->SetDisplayMode = RISCOS_SetDisplayMode;
device->CreateSDLWindow = RISCOS_CreateWindow;
device->DestroyWindow = RISCOS_DestroyWindow;
device->GetWindowWMInfo = RISCOS_GetWindowWMInfo;
@ -102,134 +86,18 @@ VideoBootStrap RISCOS_bootstrap = {
RISCOS_CreateDevice
};
enum {
MODE_FLAG_565 = 1 << 7,
MODE_FLAG_COLOUR_SPACE = 0xF << 12,
MODE_FLAG_TBGR = 0,
MODE_FLAG_TRGB = 1 << 14,
MODE_FLAG_ABGR = 1 << 15,
MODE_FLAG_ARGB = MODE_FLAG_TRGB | MODE_FLAG_ABGR
};
#define MODE_350(type, xdpi, ydpi) \
(1 | (xdpi << 1) | (ydpi << 14) | (type << 27))
#define MODE_521(type, xeig, yeig, flags) \
(0x78000001 | (xeig << 4) | (yeig << 6) | (flags & 0xFF00) | (type << 20))
static const struct {
SDL_PixelFormatEnum pixel_format;
int modeflags, ncolour, log2bpp, sprite_type;
} mode_to_pixelformat[] = {
{ SDL_PIXELFORMAT_INDEX1LSB, 0, 1, 0, 1 },
/* { SDL_PIXELFORMAT_INDEX2LSB, 0, 3, 1, 2 }, */
{ SDL_PIXELFORMAT_INDEX4LSB, 0, 15, 2, 3 },
{ SDL_PIXELFORMAT_INDEX8, MODE_FLAG_565, 255, 3, 4 },
{ SDL_PIXELFORMAT_BGR555, MODE_FLAG_TBGR, 65535, 4, 5 },
{ SDL_PIXELFORMAT_RGB555, MODE_FLAG_TRGB, 65535, 4, 5 },
{ SDL_PIXELFORMAT_ABGR1555, MODE_FLAG_ABGR, 65535, 4, 5 },
{ SDL_PIXELFORMAT_ARGB1555, MODE_FLAG_ARGB, 65535, 4, 5 },
{ SDL_PIXELFORMAT_BGR444, MODE_FLAG_TBGR, 4095, 4, 16 },
{ SDL_PIXELFORMAT_RGB444, MODE_FLAG_TRGB, 4095, 4, 16 },
{ SDL_PIXELFORMAT_ABGR4444, MODE_FLAG_ABGR, 4095, 4, 16 },
{ SDL_PIXELFORMAT_ARGB4444, MODE_FLAG_ARGB, 4095, 4, 16 },
{ SDL_PIXELFORMAT_BGR565, MODE_FLAG_TBGR | MODE_FLAG_565, 65535, 4, 10 },
{ SDL_PIXELFORMAT_RGB565, MODE_FLAG_TRGB | MODE_FLAG_565, 65535, 4, 10 },
{ SDL_PIXELFORMAT_BGR24, MODE_FLAG_TBGR, 16777215, 6, 8 },
{ SDL_PIXELFORMAT_RGB24, MODE_FLAG_TRGB, 16777215, 6, 8 },
{ SDL_PIXELFORMAT_BGR888, MODE_FLAG_TBGR, -1, 5, 6 },
{ SDL_PIXELFORMAT_RGB888, MODE_FLAG_TRGB, -1, 5, 6 },
{ SDL_PIXELFORMAT_ABGR8888, MODE_FLAG_ABGR, -1, 5, 6 },
{ SDL_PIXELFORMAT_ARGB8888, MODE_FLAG_ARGB, -1, 5, 6 }
};
static int ReadModeVariable(int mode, int variable) {
_kernel_swi_regs regs;
regs.r[0] = mode;
regs.r[1] = variable;
_kernel_swi(OS_ReadModeVariable, &regs, &regs);
return regs.r[2];
}
SDL_PixelFormatEnum RISCOS_ModeToPixelFormat(int *mode) {
int i, log2bpp, ncolour, modeflags;
log2bpp = ReadModeVariable((int)mode, 9);
ncolour = ReadModeVariable((int)mode, 3);
modeflags = ReadModeVariable((int)mode, 0);
for (i = 0; i < SDL_arraysize(mode_to_pixelformat); i++) {
if (log2bpp == mode_to_pixelformat[i].log2bpp &&
(ncolour == mode_to_pixelformat[i].ncolour || ncolour == 0) &&
(modeflags & (MODE_FLAG_565 | MODE_FLAG_COLOUR_SPACE)) == mode_to_pixelformat[i].modeflags) {
return mode_to_pixelformat[i].pixel_format;
}
}
return SDL_PIXELFORMAT_UNKNOWN;
}
static void *copy_mode_block(int *storeBlock)
{
int *outBlock;
int blockSize = (storeBlock[0] == 2) ? 7 : 5;
while(storeBlock[blockSize] != -1) {
blockSize += 2;
}
blockSize++;
outBlock = SDL_calloc(sizeof(int), blockSize);
SDL_memcpy(outBlock, storeBlock, sizeof(int) * blockSize);
return outBlock;
}
int
static int
RISCOS_VideoInit(_THIS)
{
SDL_DisplayMode mode;
int *current_mode;
_kernel_swi_regs regs;
_kernel_oserror *error;
regs.r[0] = 1;
error = _kernel_swi(OS_ScreenMode, &regs, &regs);
if (error != NULL) {
SDL_SetError("Unable to retrieve the current screen mode: %s (%i)", error->errmess, error->errnum);
if (RISCOS_InitModes(_this) < 0) {
return -1;
}
current_mode = (int *)regs.r[1];
/* Use a fake 32-bpp desktop mode */
mode.w = current_mode[1];
mode.h = current_mode[2];
if ((current_mode[0] & 0x7F) == 1) {
mode.format = RISCOS_ModeToPixelFormat(current_mode);
mode.refresh_rate = current_mode[4];
} else if ((current_mode[0] & 0x7F) == 3) {
mode.format = RISCOS_ModeToPixelFormat(current_mode);
mode.refresh_rate = current_mode[6];
} else {
return -1;
}
mode.driverdata = copy_mode_block(current_mode);
if (SDL_AddBasicVideoDisplay(&mode) < 0) {
return -1;
}
SDL_AddDisplayMode(&_this->displays[0], &mode);
/* We're done! */
return 0;
}
static int
RISCOS_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
{
return 0;
}
void
static void
RISCOS_VideoQuit(_THIS)
{
}

View File

@ -40,6 +40,8 @@ RISCOS_CreateWindow(_THIS, SDL_Window * window)
}
driverdata->window = window;
window->flags |= SDL_WINDOW_FULLSCREEN;
/* All done! */
window->driverdata = driverdata;
return 0;