1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
4 
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8 
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12 
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22 
23 #if SDL_VIDEO_DRIVER_RISCOS
24 
25 #include "../SDL_sysvideo.h"
26 
27 #include "SDL_riscosvideo.h"
28 #include "SDL_riscosmodes.h"
29 
30 #include <kernel.h>
31 #include <swis.h>
32 
33 enum {
34     MODE_FLAG_565 = 1 << 7,
35 
36     MODE_FLAG_COLOUR_SPACE = 0xF << 12,
37 
38     MODE_FLAG_TBGR = 0,
39     MODE_FLAG_TRGB = 1 << 14,
40     MODE_FLAG_ABGR = 1 << 15,
41     MODE_FLAG_ARGB = MODE_FLAG_TRGB | MODE_FLAG_ABGR
42 };
43 
44 static const struct {
45     SDL_PixelFormatEnum pixel_format;
46     int modeflags, ncolour, log2bpp;
47 } mode_to_pixelformat[] = {
48     /* { SDL_PIXELFORMAT_INDEX1LSB, 0, 1, 0 }, */
49     /* { SDL_PIXELFORMAT_INDEX2LSB, 0, 3, 1 }, */
50     /* { SDL_PIXELFORMAT_INDEX4LSB, 0, 15, 2 }, */
51     /* { SDL_PIXELFORMAT_INDEX8,    MODE_FLAG_565, 255, 3 }, */
52     { SDL_PIXELFORMAT_XBGR1555,  MODE_FLAG_TBGR, 65535, 4 },
53     { SDL_PIXELFORMAT_XRGB1555,  MODE_FLAG_TRGB, 65535, 4 },
54     { SDL_PIXELFORMAT_ABGR1555,  MODE_FLAG_ABGR, 65535, 4 },
55     { SDL_PIXELFORMAT_ARGB1555,  MODE_FLAG_ARGB, 65535, 4 },
56     { SDL_PIXELFORMAT_XBGR4444,  MODE_FLAG_TBGR, 4095, 4 },
57     { SDL_PIXELFORMAT_XRGB4444,  MODE_FLAG_TRGB, 4095, 4 },
58     { SDL_PIXELFORMAT_ABGR4444,  MODE_FLAG_ABGR, 4095, 4 },
59     { SDL_PIXELFORMAT_ARGB4444,  MODE_FLAG_ARGB, 4095, 4 },
60     { SDL_PIXELFORMAT_BGR565,    MODE_FLAG_TBGR | MODE_FLAG_565, 65535, 4 },
61     { SDL_PIXELFORMAT_RGB565,    MODE_FLAG_TRGB | MODE_FLAG_565, 65535, 4 },
62     { SDL_PIXELFORMAT_BGR24,     MODE_FLAG_TBGR, 16777215, 6 },
63     { SDL_PIXELFORMAT_RGB24,     MODE_FLAG_TRGB, 16777215, 6 },
64     { SDL_PIXELFORMAT_XBGR8888,  MODE_FLAG_TBGR, -1, 5 },
65     { SDL_PIXELFORMAT_XRGB8888,  MODE_FLAG_TRGB, -1, 5 },
66     { SDL_PIXELFORMAT_ABGR8888,  MODE_FLAG_ABGR, -1, 5 },
67     { SDL_PIXELFORMAT_ARGB8888,  MODE_FLAG_ARGB, -1, 5 }
68 };
69 
70 static SDL_PixelFormatEnum
RISCOS_ModeToPixelFormat(int ncolour,int modeflags,int log2bpp)71 RISCOS_ModeToPixelFormat(int ncolour, int modeflags, int log2bpp)
72 {
73     int i;
74 
75     for (i = 0; i < SDL_arraysize(mode_to_pixelformat); i++) {
76         if (log2bpp == mode_to_pixelformat[i].log2bpp &&
77            (ncolour == mode_to_pixelformat[i].ncolour || ncolour == 0) &&
78            (modeflags & (MODE_FLAG_565 | MODE_FLAG_COLOUR_SPACE)) == mode_to_pixelformat[i].modeflags) {
79             return mode_to_pixelformat[i].pixel_format;
80         }
81     }
82 
83     return SDL_PIXELFORMAT_UNKNOWN;
84 }
85 
86 static size_t
measure_mode_block(const int * block)87 measure_mode_block(const int *block)
88 {
89     size_t blockSize = ((block[0] & 0xFF) == 3) ? 7 : 5;
90     while(block[blockSize] != -1) {
91         blockSize += 2;
92     }
93     blockSize++;
94 
95     return blockSize * 4;
96 }
97 
98 static int
read_mode_variable(int * block,int var)99 read_mode_variable(int *block, int var)
100 {
101     _kernel_swi_regs regs;
102     regs.r[0] = (int)block;
103     regs.r[1] = var;
104     _kernel_swi(OS_ReadModeVariable, &regs, &regs);
105     return regs.r[2];
106 }
107 
108 static SDL_bool
read_mode_block(int * block,SDL_DisplayMode * mode,SDL_bool extended)109 read_mode_block(int *block, SDL_DisplayMode *mode, SDL_bool extended)
110 {
111     int xres, yres, ncolour, modeflags, log2bpp, rate;
112 
113     if ((block[0] & 0xFF) == 1) {
114         xres = block[1];
115         yres = block[2];
116         log2bpp = block[3];
117         rate = block[4];
118         ncolour = (1 << (1 << log2bpp)) - 1;
119         modeflags = MODE_FLAG_TBGR;
120     } else if ((block[0] & 0xFF) == 3) {
121         xres = block[1];
122         yres = block[2];
123         ncolour = block[3];
124         modeflags = block[4];
125         log2bpp = block[5];
126         rate = block[6];
127     } else {
128         return SDL_FALSE;
129     }
130 
131     if (extended) {
132         xres = read_mode_variable(block, 11) + 1;
133         yres = read_mode_variable(block, 12) + 1;
134         log2bpp = read_mode_variable(block, 9);
135         ncolour = read_mode_variable(block, 3);
136         modeflags = read_mode_variable(block, 0);
137     }
138 
139     mode->w = xres;
140     mode->h = yres;
141     mode->format = RISCOS_ModeToPixelFormat(ncolour, modeflags, log2bpp);
142     mode->refresh_rate = rate;
143 
144     return SDL_TRUE;
145 }
146 
147 static void *
convert_mode_block(const int * block)148 convert_mode_block(const int *block)
149 {
150     int xres, yres, log2bpp, rate, ncolour = 0, modeflags = 0;
151     size_t pos = 0;
152     int *dst;
153 
154     if ((block[0] & 0xFF) == 1) {
155         xres = block[1];
156         yres = block[2];
157         log2bpp = block[3];
158         rate = block[4];
159     } else if ((block[0] & 0xFF) == 3) {
160         xres = block[1];
161         yres = block[2];
162         ncolour = block[3];
163         modeflags = block[4];
164         log2bpp = block[5];
165         rate = block[6];
166     } else {
167         return NULL;
168     }
169 
170     dst = SDL_malloc(40);
171     if (!dst) {
172         return NULL;
173     }
174 
175     dst[pos++] = 1;
176     dst[pos++] = xres;
177     dst[pos++] = yres;
178     dst[pos++] = log2bpp;
179     dst[pos++] = rate;
180     if (ncolour != 0) {
181         dst[pos++] = 3;
182         dst[pos++] = ncolour;
183     }
184     if (modeflags != 0) {
185         dst[pos++] = 0;
186         dst[pos++] = modeflags;
187     }
188     dst[pos++] = -1;
189 
190     return dst;
191 }
192 
193 static void *
copy_memory(const void * src,size_t size,size_t alloc)194 copy_memory(const void *src, size_t size, size_t alloc)
195 {
196     void *dst = SDL_malloc(alloc);
197     if (dst) {
198         SDL_memcpy(dst, src, size);
199     }
200     return dst;
201 }
202 
203 int
RISCOS_InitModes(_THIS)204 RISCOS_InitModes(_THIS)
205 {
206     SDL_DisplayMode mode;
207     int *current_mode;
208     _kernel_swi_regs regs;
209     _kernel_oserror *error;
210     size_t size;
211 
212     regs.r[0] = 1;
213     error = _kernel_swi(OS_ScreenMode, &regs, &regs);
214     if (error != NULL) {
215         return SDL_SetError("Unable to retrieve the current screen mode: %s (%i)", error->errmess, error->errnum);
216     }
217 
218     current_mode = (int *)regs.r[1];
219     if (!read_mode_block(current_mode, &mode, SDL_TRUE)) {
220         return SDL_SetError("Unsupported mode block format %d", current_mode[0]);
221     }
222 
223     size = measure_mode_block(current_mode);
224     mode.driverdata = copy_memory(current_mode, size, size);
225     if (!mode.driverdata) {
226         return SDL_OutOfMemory();
227     }
228 
229     return SDL_AddBasicVideoDisplay(&mode);
230 }
231 
232 void
RISCOS_GetDisplayModes(_THIS,SDL_VideoDisplay * display)233 RISCOS_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
234 {
235     SDL_DisplayMode mode;
236     _kernel_swi_regs regs;
237     _kernel_oserror *error;
238     void *block, *pos;
239 
240     regs.r[0] = 2;
241     regs.r[2] = 0;
242     regs.r[6] = 0;
243     regs.r[7] = 0;
244     error = _kernel_swi(OS_ScreenMode, &regs, &regs);
245     if (error != NULL) {
246         SDL_SetError("Unable to enumerate screen modes: %s (%i)", error->errmess, error->errnum);
247         return;
248     }
249 
250     block = SDL_malloc(-regs.r[7]);
251     if (!block) {
252         SDL_OutOfMemory();
253         return;
254     }
255 
256     regs.r[6] = (int)block;
257     regs.r[7] = -regs.r[7];
258     error = _kernel_swi(OS_ScreenMode, &regs, &regs);
259     if (error != NULL) {
260         SDL_free(block);
261         SDL_SetError("Unable to enumerate screen modes: %s (%i)", error->errmess, error->errnum);
262         return;
263     }
264 
265     for (pos = block; pos < (void *)regs.r[6]; pos += *((int *)pos)) {
266         if (!read_mode_block(pos + 4, &mode, SDL_FALSE)) {
267             continue;
268         }
269 
270         if (mode.format == SDL_PIXELFORMAT_UNKNOWN)
271             continue;
272 
273         mode.driverdata = convert_mode_block(pos + 4);
274         if (!mode.driverdata) {
275             SDL_OutOfMemory();
276             break;
277         }
278 
279         if (!SDL_AddDisplayMode(display, &mode)) {
280             SDL_free(mode.driverdata);
281         }
282     }
283 
284     SDL_free(block);
285 }
286 
287 int
RISCOS_SetDisplayMode(_THIS,SDL_VideoDisplay * display,SDL_DisplayMode * mode)288 RISCOS_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
289 {
290     const char disable_cursor[] = { 23, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
291     _kernel_swi_regs regs;
292     _kernel_oserror *error;
293     int i;
294 
295     regs.r[0] = 0;
296     regs.r[1] = (int)mode->driverdata;
297     error = _kernel_swi(OS_ScreenMode, &regs, &regs);
298     if (error != NULL) {
299         return SDL_SetError("Unable to set the current screen mode: %s (%i)", error->errmess, error->errnum);
300     }
301 
302     /* Turn the text cursor off */
303     for (i = 0; i < SDL_arraysize(disable_cursor); i++) {
304         _kernel_oswrch(disable_cursor[i]);
305     }
306 
307     /* Turn the mouse pointer on */
308     /* _kernel_osbyte(106, 1, 0); */
309 
310     return 0;
311 }
312 
313 #endif /* SDL_VIDEO_DRIVER_RISCOS */
314 
315 /* vi: set ts=4 sw=4 expandtab: */
316