2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2009 Sam Lantinga
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "SDL_config.h"
25 File added by Alan Buckley (alan_baa@hotmail.com) for RISC OS compatability
28 Implements RISC OS full screen display.
31 #include "SDL_video.h"
32 #include "SDL_mouse.h"
33 #include "../SDL_sysvideo.h"
34 #include "../SDL_pixels_c.h"
35 #include "../../events/SDL_events_c.h"
37 #include "SDL_riscostask.h"
38 #include "SDL_riscosvideo.h"
39 #include "SDL_riscosevents_c.h"
40 #include "SDL_riscosmouse_c.h"
44 #include "unixlib/os.h"
45 #include "unixlib/local.h"
47 /* Private structures */
48 typedef struct tagScreenModeBlock
50 int flags; // mode selector flags, bit 0 = 1, bit 1-7 format specifier, 8-31 reserved
53 int pixel_depth; // 2^pixel_depth = bpp,i.e. 0 = 1, 1 = 2, 4 = 16, 5 = 32
54 int frame_rate; // -1 use first match
55 int mode_vars[5]; // array of index, value pairs terminated by -1
59 /* Helper functions */
60 void FULLSCREEN_SetDeviceMode(_THIS);
61 int FULLSCREEN_SetMode(int width, int height, int bpp);
62 void FULLSCREEN_SetupBanks(_THIS);
64 /* SDL video device functions for fullscreen mode */
65 static int FULLSCREEN_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors);
66 static int FULLSCREEN_FlipHWSurface(_THIS, SDL_Surface *surface);
67 void FULLSCREEN_SetWMCaption(_THIS, const char *title, const char *icon);
68 extern int RISCOS_GetWmInfo(_THIS, SDL_SysWMinfo *info);
70 /* UpdateRects variants */
71 static void FULLSCREEN_UpdateRects(_THIS, int numrects, SDL_Rect *rects);
72 static void FULLSCREEN_UpdateRectsMemCpy(_THIS, int numrects, SDL_Rect *rects);
73 static void FULLSCREEN_UpdateRects8bpp(_THIS, int numrects, SDL_Rect *rects);
74 static void FULLSCREEN_UpdateRects16bpp(_THIS, int numrects, SDL_Rect *rects);
75 static void FULLSCREEN_UpdateRects32bpp(_THIS, int numrects, SDL_Rect *rects);
76 static void FULLSCREEN_UpdateRectsOS(_THIS, int numrects, SDL_Rect *rects);
78 /* Local helper functions */
79 static int cmpmodes(const void *va, const void *vb);
80 static int FULLSCREEN_AddMode(_THIS, int bpp, int w, int h);
81 void FULLSCREEN_SetWriteBank(int bank);
82 void FULLSCREEN_SetDisplayBank(int bank);
83 static void FULLSCREEN_DisableEscape();
84 static void FULLSCREEN_EnableEscape();
85 void FULLSCREEN_BuildModeList(_THIS);
87 /* Following variable is set up in riskosTask.c */
88 extern int riscos_backbuffer; /* Create a back buffer in system memory for full screen mode */
90 /* Following is used to create a sprite back buffer */
91 extern unsigned char *WIMP_CreateBuffer(int width, int height, int bpp);
93 /* Fast assembler copy */
94 extern void RISCOS_Put32(void *to, int pixels, int pitch, int rows, void *from, int src_skip_bytes);
96 SDL_Surface *FULLSCREEN_SetVideoMode(_THIS, SDL_Surface *current,
97 int width, int height, int bpp, Uint32 flags)
99 _kernel_swi_regs regs;
103 int create_back_buffer = riscos_backbuffer;
108 flags |= SDL_HWPALETTE;
125 SDL_SetError("Pixel depth not supported");
130 if (FULLSCREEN_SetMode(width, height, bpp) == 0)
132 SDL_SetError("Couldn't set requested mode");
136 /* printf("Setting mode %dx%d\n", width, height); */
138 /* Allocate the new pixel format for the screen */
139 if ( ! SDL_ReallocFormat(current, bpp, Rmask, Gmask, Bmask, 0) ) {
140 RISCOS_RestoreWimpMode();
141 SDL_SetError("Couldn't allocate new pixel format for requested mode");
145 /* Set up the new mode framebuffer */
147 this->hidden->height = current->h = height;
149 regs.r[0] = -1; /* -1 for current screen mode */
151 /* Get screen width in bytes */
152 regs.r[1] = 6; // Screen Width in bytes
153 _kernel_swi(OS_ReadModeVariable, ®s, ®s);
155 current->pitch = regs.r[2];
157 if (flags & SDL_DOUBLEBUF)
159 regs.r[0] = 2; /* Screen area */
160 _kernel_swi(OS_ReadDynamicArea, ®s, ®s);
162 /* Reg 1 has amount of memory currently used for display */
163 regs.r[0] = 2; /* Screen area */
164 regs.r[1] = (current->pitch * height * 2) - regs.r[1];
165 if (_kernel_swi(OS_ChangeDynamicArea, ®s, ®s) != NULL)
167 /* Can't allocate enough screen memory for double buffer */
168 flags &= ~SDL_DOUBLEBUF;
172 current->flags = flags | SDL_FULLSCREEN | SDL_HWSURFACE | SDL_PREALLOC;
175 /* Need to set display banks here for double buffering */
176 if (flags & SDL_DOUBLEBUF)
178 FULLSCREEN_SetWriteBank(0);
179 FULLSCREEN_SetDisplayBank(1);
181 create_back_buffer = 0; /* Don't need a back buffer for a double buffered display */
184 FULLSCREEN_SetupBanks(this);
186 if (create_back_buffer)
188 /* If not double buffered we may need to create a memory
189 ** back buffer to simulate processing on other OSes.
190 ** This is turned on by setting the enviromental variable
191 ** SDL$<name>$BackBuffer >= 1
193 if (riscos_backbuffer == 3)
194 this->hidden->bank[0] = WIMP_CreateBuffer(width, height, bpp);
196 this->hidden->bank[0] = SDL_malloc(height * current->pitch);
197 if (this->hidden->bank[0] == 0)
199 RISCOS_RestoreWimpMode();
200 SDL_SetError("Couldnt allocate memory for back buffer");
203 /* Surface updated in programs is now a software surface */
204 current->flags &= ~SDL_HWSURFACE;
207 /* Store address of allocated screen bank to be freed later */
208 if (this->hidden->alloc_bank) SDL_free(this->hidden->alloc_bank);
209 if (create_back_buffer)
211 this->hidden->alloc_bank = this->hidden->bank[0];
212 if (riscos_backbuffer == 3)
214 this->hidden->bank[0] += 60; /* Start of sprite data */
215 if (bpp == 8) this->hidden->bank[0] += 2048; /* 8bpp sprite have palette first */
218 this->hidden->alloc_bank = 0;
220 // Clear both banks to black
221 SDL_memset(this->hidden->bank[0], 0, height * current->pitch);
222 SDL_memset(this->hidden->bank[1], 0, height * current->pitch);
224 this->hidden->current_bank = 0;
225 current->pixels = this->hidden->bank[0];
227 /* Have to set the screen here, so SetDeviceMode will pick it up */
228 this->screen = current;
230 /* Reset device functions for the wimp */
231 FULLSCREEN_SetDeviceMode(this);
233 /* FULLSCREEN_DisableEscape(); */
239 /* Reset any device functions that have been changed because we have run in WIMP mode */
240 void FULLSCREEN_SetDeviceMode(_THIS)
242 /* Update rects is different if we have a backbuffer */
244 if (riscos_backbuffer && (this->screen->flags & SDL_DOUBLEBUF) == 0)
246 switch(riscos_backbuffer)
248 case 2: /* ARM code full word copy */
249 switch(this->screen->format->BytesPerPixel)
251 case 1: /* 8bpp modes */
252 this->UpdateRects = FULLSCREEN_UpdateRects8bpp;
254 case 2: /* 15/16bpp modes */
255 this->UpdateRects = FULLSCREEN_UpdateRects16bpp;
257 case 4: /* 32 bpp modes */
258 this->UpdateRects = FULLSCREEN_UpdateRects32bpp;
261 default: /* Just default to the memcpy routine */
262 this->UpdateRects = FULLSCREEN_UpdateRectsMemCpy;
267 case 3: /* Use OS sprite plot routine */
268 this->UpdateRects = FULLSCREEN_UpdateRectsOS;
271 default: /* Old but safe memcpy */
272 this->UpdateRects = FULLSCREEN_UpdateRectsMemCpy;
276 this->UpdateRects = FULLSCREEN_UpdateRects; /* Default do nothing implementation */
278 this->SetColors = FULLSCREEN_SetColors;
280 this->FlipHWSurface = FULLSCREEN_FlipHWSurface;
282 this->SetCaption = FULLSCREEN_SetWMCaption;
283 this->SetIcon = NULL;
284 this->IconifyWindow = NULL;
286 this->ShowWMCursor = RISCOS_ShowWMCursor;
287 this->WarpWMCursor = FULLSCREEN_WarpWMCursor;
289 this->PumpEvents = FULLSCREEN_PumpEvents;
292 /* Query for the list of available video modes */
293 void FULLSCREEN_BuildModeList(_THIS)
295 _kernel_swi_regs regs;
296 char *enumInfo = NULL;
302 /* Find out how much space we need */
303 regs.r[0] = 2; /* Reason code */
304 regs.r[2] = 0; /* Number of modes to skip */
305 regs.r[6] = 0; /* pointer to block or 0 for count */
306 regs.r[7] = 0; /* Size of block in bytes */
307 _kernel_swi(OS_ScreenMode, ®s, ®s);
309 num_modes = -regs.r[2];
311 /* Video memory should be in r[5] */
312 this->info.video_mem = regs.r[5]/1024;
314 enumInfo = (unsigned char *)SDL_malloc(-regs.r[7]);
315 if (enumInfo == NULL)
320 /* Read mode information into block */
322 regs.r[6] = (int)enumInfo;
323 regs.r[7] = -regs.r[7];
324 _kernel_swi(OS_ScreenMode, ®s, ®s);
328 for (j =0; j < num_modes;j++)
330 blockInfo = (int *)enum_ptr;
331 if ((blockInfo[1] & 255) == 1) /* We understand this format */
335 case 3: /* 8 bits per pixel */
336 FULLSCREEN_AddMode(this, 8, blockInfo[2], blockInfo[3]);
338 case 4: /* 15 bits per pixel */
339 FULLSCREEN_AddMode(this, 15, blockInfo[2], blockInfo[3]);
341 case 5: /* 32 bits per pixel */
342 FULLSCREEN_AddMode(this, 32, blockInfo[2], blockInfo[3]);
347 enum_ptr += blockInfo[0];
352 /* Sort the mode lists */
353 for ( j=0; j<NUM_MODELISTS; ++j ) {
354 if ( SDL_nummodes[j] > 0 ) {
355 SDL_qsort(SDL_modelist[j], SDL_nummodes[j], sizeof *SDL_modelist[j], cmpmodes);
360 static int FULLSCREEN_FlipHWSurface(_THIS, SDL_Surface *surface)
362 _kernel_swi_regs regs;
365 FULLSCREEN_SetDisplayBank(this->hidden->current_bank);
366 this->hidden->current_bank ^= 1;
367 FULLSCREEN_SetWriteBank(this->hidden->current_bank);
368 surface->pixels = this->hidden->bank[this->hidden->current_bank];
371 _kernel_swi(OS_Byte, ®s, ®s);
376 /* Nothing to do if we are writing direct to hardware */
377 static void FULLSCREEN_UpdateRects(_THIS, int numrects, SDL_Rect *rects)
381 /* Safe but slower Memory copy from our allocated back buffer */
382 static void FULLSCREEN_UpdateRectsMemCpy(_THIS, int numrects, SDL_Rect *rects)
386 int pitch = this->screen->pitch;
388 int xmult = this->screen->format->BytesPerPixel;
389 for (j = 0; j < numrects; j++)
391 from = this->hidden->bank[0] + rects->x * xmult + rects->y * pitch;
392 to = this->hidden->bank[1] + rects->x * xmult + rects->y * pitch;
393 for (row = 0; row < rects->h; row++)
395 SDL_memcpy(to, from, rects->w * xmult);
403 /* Use optimized assembler memory copy. Deliberately copies extra columns if
404 necessary to ensure the rectangle is word aligned. */
405 static void FULLSCREEN_UpdateRects8bpp(_THIS, int numrects, SDL_Rect *rects)
409 int pitch = this->screen->pitch;
413 for (j = 0; j < numrects; j++)
415 from = this->hidden->bank[0] + rects->x + rects->y * pitch;
416 to = this->hidden->bank[1] + rects->x + rects->y * pitch;
417 width_bytes = rects->w;
420 int extra = ((int)from & 3);
423 width_bytes += extra;
425 if (width_bytes & 3) width_bytes += 4 - (width_bytes & 3);
426 src_skip_bytes = pitch - width_bytes;
428 RISCOS_Put32(to, (width_bytes >> 2), pitch, (int)rects->h, from, src_skip_bytes);
433 /* Use optimized assembler memory copy. Deliberately copies extra columns if
434 necessary to ensure the rectangle is word aligned. */
435 static void FULLSCREEN_UpdateRects16bpp(_THIS, int numrects, SDL_Rect *rects)
439 int pitch = this->screen->pitch;
443 for (j = 0; j < numrects; j++)
445 from = this->hidden->bank[0] + (rects->x << 1) + rects->y * pitch;
446 to = this->hidden->bank[1] + (rects->x << 1) + rects->y * pitch;
447 width_bytes = (((int)rects->w) << 1);
454 if (width_bytes & 3) width_bytes += 2;
455 src_skip_bytes = pitch - width_bytes;
457 RISCOS_Put32(to, (width_bytes >> 2), pitch, (int)rects->h, from, src_skip_bytes);
462 /* Use optimized assembler memory copy. 32 bpp modes are always word aligned */
463 static void FULLSCREEN_UpdateRects32bpp(_THIS, int numrects, SDL_Rect *rects)
467 int pitch = this->screen->pitch;
470 for (j = 0; j < numrects; j++)
472 from = this->hidden->bank[0] + (rects->x << 2) + rects->y * pitch;
473 to = this->hidden->bank[1] + (rects->x << 2) + rects->y * pitch;
474 width = (int)rects->w ;
476 RISCOS_Put32(to, width, pitch, (int)rects->h, from, pitch - (width << 2));
481 /* Use operating system sprite plots. Currently this is much slower than the
482 other variants however accelerated sprite plotting can be seen on the horizon
483 so this prepares for it. */
484 static void FULLSCREEN_UpdateRectsOS(_THIS, int numrects, SDL_Rect *rects)
486 _kernel_swi_regs regs;
487 _kernel_oserror *err;
491 regs.r[0] = 28 + 512;
492 regs.r[1] = (unsigned int)this->hidden->alloc_bank;
493 regs.r[2] = (unsigned int)this->hidden->alloc_bank+16;
496 for (j = 0; j < numrects; j++)
498 y = this->screen->h - rects->y; /* top of clipping region */
499 _kernel_oswrch(24); /* Set graphics clip region */
500 _kernel_oswrch((rects->x << this->hidden->xeig) & 0xFF); /* left */
501 _kernel_oswrch(((rects->x << this->hidden->xeig) >> 8) & 0xFF);
502 _kernel_oswrch(((y - rects->h) << this->hidden->yeig) & 0xFF); /* bottom */
503 _kernel_oswrch((((y - rects->h) << this->hidden->yeig)>> 8) & 0xFF);
504 _kernel_oswrch(((rects->x + rects->w - 1) << this->hidden->xeig) & 0xFF); /* right */
505 _kernel_oswrch((((rects->x + rects->w - 1)<< this->hidden->xeig) >> 8) & 0xFF);
506 _kernel_oswrch(((y-1) << this->hidden->yeig) & 0xFF); /* top */
507 _kernel_oswrch((((y-1) << this->hidden->yeig) >> 8) & 0xFF);
512 if ((err = _kernel_swi(OS_SpriteOp, ®s, ®s)) != 0)
514 printf("OS_SpriteOp failed \n%s\n",err->errmess);
519 /* Reset to full screen clipping */
520 _kernel_oswrch(24); /* Set graphics clip region */
521 _kernel_oswrch(0); /* left */
523 _kernel_oswrch(0); /* bottom */
525 _kernel_oswrch(((this->screen->w-1) << this->hidden->xeig) & 0xFF); /* right */
526 _kernel_oswrch((((this->screen->w-1) << this->hidden->xeig) >> 8) & 0xFF);
527 _kernel_oswrch(((this->screen->h-1) << this->hidden->yeig) & 0xFF); /* top */
528 _kernel_oswrch((((this->screen->h-1) << this->hidden->yeig) >> 8) & 0xFF);
533 int FULLSCREEN_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
535 _kernel_swi_regs regs;
540 regs.r[2] = (int)palette;
543 _kernel_swi(ColourTrans_ReadPalette, ®s, ®s);
547 palette[firstcolor] = ((colors->b) << 24) | ((colors->g) << 16) | ((colors->r) << 8);
554 regs.r[2] = (int)palette;
557 _kernel_swi(ColourTrans_WritePalette, ®s, ®s);
563 static int cmpmodes(const void *va, const void *vb)
565 SDL_Rect *a = *(SDL_Rect **)va;
566 SDL_Rect *b = *(SDL_Rect **)vb;
573 static int FULLSCREEN_AddMode(_THIS, int bpp, int w, int h)
579 /* Check to see if we already have this mode */
580 if ( bpp < 8 ) { /* Not supported */
583 index = ((bpp+7)/8)-1;
584 for ( i=0; i<SDL_nummodes[index]; ++i ) {
585 mode = SDL_modelist[index][i];
586 if ( (mode->w == w) && (mode->h == h) ) {
591 /* Set up the new video mode rectangle */
592 mode = (SDL_Rect *)SDL_malloc(sizeof *mode);
593 if ( mode == NULL ) {
602 /* Allocate the new list of modes, and fill in the new mode */
603 next_mode = SDL_nummodes[index];
604 SDL_modelist[index] = (SDL_Rect **)
605 SDL_realloc(SDL_modelist[index], (1+next_mode+1)*sizeof(SDL_Rect *));
606 if ( SDL_modelist[index] == NULL ) {
608 SDL_nummodes[index] = 0;
612 SDL_modelist[index][next_mode] = mode;
613 SDL_modelist[index][next_mode+1] = NULL;
614 SDL_nummodes[index]++;
619 void FULLSCREEN_SetWriteBank(int bank)
621 _kernel_swi_regs regs;
624 _kernel_swi(OS_Byte, ®s, ®s);
627 void FULLSCREEN_SetDisplayBank(int bank)
629 _kernel_swi_regs regs;
632 _kernel_swi(OS_Byte, ®s, ®s);
636 /** Disable special escape key processing */
637 static void FULLSCREEN_DisableEscape()
639 _kernel_swi_regs regs;
643 _kernel_swi(OS_Byte, ®s, ®s);
647 /** Enable special escape key processing */
648 static void FULLSCREEN_EnableEscape()
650 _kernel_swi_regs regs;
654 _kernel_swi(OS_Byte, ®s, ®s);
658 /** Store caption in case this is called before we create a window */
659 void FULLSCREEN_SetWMCaption(_THIS, const char *title, const char *icon)
661 SDL_strlcpy(this->hidden->title, title, SDL_arraysize(this->hidden->title));
666 * Returns 1 if mode is set ok, otherwise 0
669 int FULLSCREEN_SetMode(int width, int height, int bpp)
672 _kernel_swi_regs regs;
675 smb.x_pixels = width;
676 smb.y_pixels = height;
677 smb.mode_vars[0] = -1;
683 /* Note: Need to set ModeFlags to 128 and NColour variables to 255 get full 8 bit palette */
684 smb.mode_vars[0] = 0; smb.mode_vars[1] = 128; /* Mode flags */
685 smb.mode_vars[2] = 3; smb.mode_vars[3] = 255; /* NColour (number of colours -1) */
686 smb.mode_vars[4] = -1; /* End of list */
699 SDL_SetError("Pixel depth not supported");
707 regs.r[1] = (int)&smb;
709 if (_kernel_swi(OS_ScreenMode, ®s, ®s) != 0)
711 SDL_SetError("Couldn't set requested mode");
716 _kernel_oswrch(23);_kernel_oswrch(1);_kernel_oswrch(0);
717 _kernel_oswrch(0);_kernel_oswrch(0);_kernel_oswrch(0);
718 _kernel_oswrch(0);_kernel_oswrch(0);_kernel_oswrch(0);
719 _kernel_oswrch(0);_kernel_oswrch(0);
724 /* Get Start addresses for the screen banks */
725 void FULLSCREEN_SetupBanks(_THIS)
727 _kernel_swi_regs regs;
729 block[0] = 148; /* Write screen start */
730 block[1] = 149; /* Display screen start */
731 block[2] = 4; /* X eig factor */
732 block[3] = 5; /* Y eig factor */
733 block[4] = -1; /* End of list of variables to request */
735 regs.r[0] = (int)block;
736 regs.r[1] = (int)block;
737 _kernel_swi(OS_ReadVduVariables, ®s, ®s);
739 this->hidden->bank[0] = (void *)block[0];
740 this->hidden->bank[1] = (void *)block[1];
741 this->hidden->xeig = block[2];
742 this->hidden->yeig = block[3];
745 /* Toggle to full screen mode from the WIMP */
747 int FULLSCREEN_ToggleFromWimp(_THIS)
749 int width = this->screen->w;
750 int height = this->screen->h;
751 int bpp = this->screen->format->BitsPerPixel;
753 RISCOS_StoreWimpMode();
754 if (FULLSCREEN_SetMode(width, height, bpp))
756 char *buffer = this->hidden->alloc_bank; /* This is start of sprite data */
757 /* Support back buffer mode only */
758 if (riscos_backbuffer == 0) riscos_backbuffer = 1;
760 FULLSCREEN_SetupBanks(this);
762 this->hidden->bank[0] = buffer + 60; /* Start of sprite data */
763 if (bpp == 8) this->hidden->bank[0] += 2048; /* 8bpp sprite have palette first */
765 this->hidden->current_bank = 0;
766 this->screen->pixels = this->hidden->bank[0];
768 /* Copy back buffer to screen memory */
769 SDL_memcpy(this->hidden->bank[1], this->hidden->bank[0], width * height * this->screen->format->BytesPerPixel);
771 FULLSCREEN_SetDeviceMode(this);
774 RISCOS_RestoreWimpMode();