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, ®s, ®s);
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, ®s, ®s);
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, ®s, ®s);
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, ®s, ®s);
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, ®s, ®s);
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