Add support for (scaled down) high resolution modes.
[SDL.s60v3.git] / src / video / symbian / SDL_epocvideo.cpp
blobea572996c34a0749e086dd63fd522e851bcc4800
1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997, 1998, 1999, 2000, 2001 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
19 Sam Lantinga
20 slouken@devolution.com
23 #include "epoc_sdl.h"
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
28 extern "C" {
29 #include "SDL_error.h"
30 #include "SDL_timer.h"
31 #include "SDL_video.h"
32 #undef NULL
33 #include "SDL_pixels_c.h"
34 #include "SDL.h"
35 #include "SDL_mouse.h"
38 #include "SDL_epocvideo.h"
39 #include "SDL_epocevents_c.h"
40 #include <coedef.h>
41 #include <flogger.h>
42 #include <eikenv.h>
43 #include <eikappui.h>
44 #include <eikapp.h>
45 #include "sdlepocapi.h"
46 #include <SDL_gliop.h>
47 #include <egl.h>
48 #include "gles_armv5_def.h"
50 extern "C"
52 /* Initialization/Query functions */
53 static int S60_VideoInit(_THIS, SDL_PixelFormat *vformat);
54 static SDL_Rect **S60_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
55 static SDL_Surface *S60_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
56 static int S60_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors);
57 static void S60_VideoQuit(_THIS);
59 /* Hardware surface functions */
60 static int S60_AllocHWSurface(_THIS, SDL_Surface *surface);
61 static int S60_LockHWSurface(_THIS, SDL_Surface *surface);
62 static int S60_FlipHWSurface(_THIS, SDL_Surface *surface);
63 static void S60_UnlockHWSurface(_THIS, SDL_Surface *surface);
64 static void S60_FreeHWSurface(_THIS, SDL_Surface *surface);
65 static void S60_DirectUpdate(_THIS, int numrects, SDL_Rect *rects);
67 static int S60_Available(void);
68 static SDL_VideoDevice *S60_CreateDevice(int devindex);
70 /* Mouse functions */
71 static WMcursor *S60_CreateWMCursor(_THIS, Uint8 *data, Uint8 *mask, int w, int h, int hot_x, int hot_y);
72 static void S60_FreeWMCursor(_THIS, WMcursor *cursor);
73 static int S60_ShowWMCursor(_THIS, WMcursor *cursor);
75 /*GL Functions*/
76 static int S60_GlesLoadLibrary(_THIS, const char* path);
77 static void* S60_GlesGetProcAddress(_THIS, const char *proc);
78 static int S60_GlesGetAttribute(_THIS, SDL_GLattr attrib, int* value);
79 static int S60_GlesMakeCurrent(_THIS);
80 static void S60_GlesSwapBuffers(_THIS);
82 struct WMcursor
87 static TSize GetScreenSize()
89 CWsScreenDevice *sd = new CWsScreenDevice(CEikonEnv::Static()->WsSession());
90 sd->Construct();
91 const TSize sz(sd->SizeInPixels());
92 delete sd;
94 return sz;
97 /* Epoc video driver bootstrap functions */
98 static int S60_Available(void)
100 return 1; /* Always available */
103 static void S60_DeleteDevice(SDL_VideoDevice *device)
105 delete device->gl_data;
106 delete device->hidden;
107 delete device;
110 static SDL_VideoDevice *S60_CreateDevice(int /*devindex*/)
112 SDL_VideoDevice *device;
114 /* Allocate all variables that we free on delete */
115 device = new SDL_VideoDevice;
116 if (device)
118 Mem::FillZ(device, (sizeof *device));
119 device->hidden = new SDL_PrivateVideoData;
120 device->gl_data = new SDL_PrivateGLData;
122 else
124 SDL_OutOfMemory();
125 return 0;
127 if((device->hidden == NULL) || (device->gl_data == NULL))
129 SDL_OutOfMemory();
130 delete device->hidden;
131 delete device->gl_data;
132 delete device;
133 return 0;
136 Mem::FillZ(device->hidden, (sizeof *device->hidden));
138 /* Set the function pointers */
139 device->VideoInit = S60_VideoInit;
140 device->ListModes = S60_ListModes;
141 device->SetVideoMode = S60_SetVideoMode;
142 device->SetColors = S60_SetColors;
143 device->UpdateRects = NULL;
144 device->VideoQuit = S60_VideoQuit;
145 device->AllocHWSurface = S60_AllocHWSurface;
146 device->CheckHWBlit = NULL;
147 device->FillHWRect = NULL;
148 device->SetHWColorKey = NULL;
149 device->SetHWAlpha = NULL;
150 device->LockHWSurface = S60_LockHWSurface;
151 device->UnlockHWSurface = S60_UnlockHWSurface;
152 device->FlipHWSurface = S60_FlipHWSurface;
153 device->FreeHWSurface = S60_FreeHWSurface;
154 device->SetIcon = NULL;
155 device->SetCaption = NULL;
156 device->GetWMInfo = NULL;
157 device->FreeWMCursor = S60_FreeWMCursor;
158 device->CreateWMCursor = S60_CreateWMCursor;
159 device->ShowWMCursor = S60_ShowWMCursor;
160 device->WarpWMCursor = NULL;
161 device->InitOSKeymap = EPOC_InitOSKeymap;
162 device->PumpEvents = EPOC_PumpEvents;
163 device->free = S60_DeleteDevice;
165 /*gles funtions*/
166 device->GL_LoadLibrary = S60_GlesLoadLibrary;
167 device->GL_GetProcAddress = S60_GlesGetProcAddress;
168 device->GL_GetAttribute = S60_GlesGetAttribute;
169 device->GL_MakeCurrent = S60_GlesMakeCurrent;
170 device->GL_SwapBuffers = S60_GlesSwapBuffers;
172 device->gl_data->iLibrary.SetHandle(0);
174 return device;
177 VideoBootStrap EPOC_bootstrap = {
178 "epoc\0\0\0", "EPOC system",
179 S60_Available, S60_CreateDevice
182 int S60_VideoInit(_THIS, SDL_PixelFormat *vformat)
184 /* Initialise Epoc frame buffer */
186 /* The "best" video format should be returned to caller. */
188 vformat->BitsPerPixel = 16;
189 vformat->BytesPerPixel = 2;
191 Private->iRect = new SDL_Rect*[5];
192 Private->iRect[0] = new SDL_Rect;
193 Private->iRect[1] = new SDL_Rect;
194 Private->iRect[2] = new SDL_Rect;
195 Private->iRect[3] = new SDL_Rect;
196 Private->iRect[4] = NULL;
198 for( int i=0; i<4; i++ )
200 Private->iRect[i]->x = 0;
201 Private->iRect[i]->y = 0;
204 const TSize sz = GetScreenSize();
206 Private->iRect[0]->w = sz.iWidth;
207 Private->iRect[0]->h = sz.iHeight;
209 Private->iRect[1]->w = sz.iHeight;
210 Private->iRect[1]->h = sz.iWidth;
212 Private->iRect[2]->w = sz.iWidth * 2;
213 Private->iRect[2]->h = sz.iHeight * 2;
215 Private->iRect[3]->w = sz.iHeight * 2;
216 Private->iRect[3]->h = sz.iWidth * 2;
218 Private->iOrientation = new CAknAppUi::TAppUiOrientation[4];
220 if(sz.iWidth < sz.iHeight)
222 Private->iOrientation[0] = CAknAppUi::EAppUiOrientationPortrait;
223 Private->iOrientation[1] = CAknAppUi::EAppUiOrientationLandscape;
224 Private->iOrientation[2] = CAknAppUi::EAppUiOrientationPortrait;
225 Private->iOrientation[3] = CAknAppUi::EAppUiOrientationLandscape;
227 else
229 Private->iOrientation[0] = CAknAppUi::EAppUiOrientationLandscape;
230 Private->iOrientation[1] = CAknAppUi::EAppUiOrientationPortrait;
231 Private->iOrientation[2] = CAknAppUi::EAppUiOrientationLandscape;
232 Private->iOrientation[3] = CAknAppUi::EAppUiOrientationPortrait;
235 return(0);
238 SDL_Rect **S60_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
240 if(flags & SDL_HWSURFACE)
242 if(format->BytesPerPixel != 4) //in HW only full color is supported
243 return NULL;
245 if(flags & SDL_FULLSCREEN)
247 return Private->iRect;
250 return (SDL_Rect **)(-1); //everythingisok, but too small shoes
253 int S60_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
255 if ((firstcolor+ncolors) > 256)
256 return -1;
257 TUint32 palette[256];
258 int c = 0;
260 for(int i = firstcolor; i < firstcolor+ncolors; i++)
262 TUint32 color64K = (colors[c].r & 0x0000f8) << 8;
263 color64K |= (colors[c].g & 0x0000fc) << 3;
264 color64K |= (colors[c].b & 0x0000f8) >> 3;
265 palette[i] = color64K;
266 c++;
269 if(EpocSdlEnv::SetPalette(firstcolor, ncolors, palette) == KErrNone)
271 return 0;
273 return -1;
276 int S60_GlesLoadLibrary(SDL_VideoDevice* _this, const char* path)
278 if(_this->gl_data->iLibrary.Handle() != 0)
279 return KErrAlreadyExists; //already loaded
280 const char* const gles_lib[] = {"libgles_cm.dll", "libSWGLES.dll"};
281 int err = KErrNotFound;
282 for(int i = 0; i < 2 && err != KErrNone; i++)
284 const char* name8 = path == NULL ? gles_lib[i] : path;
285 TFileName lib;
286 lib.Copy(TPtrC8((unsigned char*)name8));
287 err = _this->gl_data->iLibrary.Load(lib);
289 if(err == KErrNone)
290 _this->gl_config.driver_loaded = 1;
291 return err;
294 typedef int (*Ftp)(...);
295 #define DC(x) ((Ftp) S60_GlesGetProcAddress(_this, #x))
297 const char* const OpenGL[] = //these funtions are in gl, but not in gles, at least in all in all versions...
299 "glBegin",
300 "glEnd",
301 "glOrtho",
302 "glPopAttrib",
303 "glPopClientAttrib",
304 "glPushAttrib",
305 "glPushClientAttrib",
306 "glTexCoord2f",
307 "glVertex2i",
308 "glTexParameteri"
311 int NotSupported()
313 User::Panic(_L("SDL, Gles"), KErrNotSupported);
314 return 0;
317 void* S60_GlesGetProcAddress(_THIS, const char *proc)
319 if(_this->gl_data->iLibrary.Handle() == 0)
320 return NULL; //not loaded
321 TLibraryFunction f = NULL;
322 for(int i = 0; i < G_ordinals_count; i++)
324 if(strcmp(G_ordinals[i].name, proc) == 0)
326 f = _this->gl_data->iLibrary.Lookup(G_ordinals[i].ord);
327 break;
331 if(f != NULL) /*Lookup may fail*/
332 return (void*) f;
334 for(int i = 0; i < sizeof(OpenGL) / sizeof(char*); i++)
336 if(strcmp(OpenGL[i], proc) == 0)
337 return (void*) NotSupported;
340 return NULL;
343 int S60_GlesGetAttribute(_THIS, SDL_GLattr aAttrib, int* aValue)
345 EGLint attrib;
346 switch(aAttrib)
348 /*todo*/
349 case SDL_GL_RED_SIZE: attrib = EGL_RED_SIZE; break;
350 case SDL_GL_GREEN_SIZE: attrib = EGL_GREEN_SIZE; break;
351 case SDL_GL_BLUE_SIZE:attrib = EGL_BLUE_SIZE; break;
352 case SDL_GL_ALPHA_SIZE: attrib = EGL_ALPHA_SIZE; break;
353 case SDL_GL_BUFFER_SIZE: attrib = EGL_BUFFER_SIZE; break;
354 case SDL_GL_DOUBLEBUFFER: *aValue = 1; return 0; //always
355 case SDL_GL_DEPTH_SIZE: attrib = EGL_DEPTH_SIZE; break;
356 case SDL_GL_STENCIL_SIZE: attrib = EGL_STENCIL_SIZE; break;
357 case SDL_GL_ACCUM_RED_SIZE:
358 case SDL_GL_ACCUM_GREEN_SIZE:
359 case SDL_GL_ACCUM_BLUE_SIZE:
360 case SDL_GL_ACCUM_ALPHA_SIZE:
361 case SDL_GL_STEREO:
362 case SDL_GL_MULTISAMPLEBUFFERS:
363 case SDL_GL_MULTISAMPLESAMPLES:
364 case SDL_GL_ACCELERATED_VISUAL:
365 case SDL_GL_SWAP_CONTROL:
366 *aValue = 0;
367 return -1;
369 const int success = DC(eglGetConfigAttrib)
371 _this->gl_data->iDisplay,
372 _this->gl_data->iConfig,
373 attrib,
374 aValue);
375 return success == EGL_FALSE ? -1 : 0;
379 int S60_GlesMakeCurrent(_THIS)
381 DC(eglMakeCurrent)
382 (_this->gl_data->iDisplay,
383 _this->gl_data->iSurface,
384 _this->gl_data->iSurface,
385 _this->gl_data->iContext);
386 return DC(eglGetError)();
389 void S60_GlesSwapBuffers(_THIS)
391 DC(eglSwapBuffers)(
392 _this->gl_data->iDisplay,
393 _this->gl_data->iSurface);
396 static void glAssert(_THIS)
398 const EGLint err = DC(eglGetError)();
399 if(err != EGL_SUCCESS)
401 User::Leave(err);
405 static void CreateGles(_THIS, RWindow& aWindow, int bpp, SDL_PrivateGLData& aData)
407 SDL_GL_LoadLibrary(NULL); //just if its not already loaded
408 aData.iDisplay = DC(eglGetDisplay)(EGL_DEFAULT_DISPLAY);
409 DC(eglInitialize)(aData.iDisplay, NULL, NULL);
411 glAssert(_this);
413 int configs = 0;
414 EGLConfig* configList = NULL;
415 int configSz = 0;
416 DC(eglGetConfigs)(aData.iDisplay, configList, configSz, &configs);
417 configSz = configs;
419 glAssert(_this);
421 configList = new EGLConfig[configSz];
423 int red, green, blue;
424 if(bpp == 16)
426 red = 5;
427 green = 6;
428 blue = 5;
430 else
432 red = 8;
433 green = 8;
434 blue = 8;
437 const EGLint attribList[] =
439 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
440 EGL_RED_SIZE, red,
441 EGL_GREEN_SIZE, green,
442 EGL_BLUE_SIZE, blue,
443 EGL_BUFFER_SIZE, EGL_DONT_CARE,
444 EGL_DEPTH_SIZE, 8,
445 EGL_NONE
448 DC(eglChooseConfig)(aData.iDisplay,
449 attribList,
450 configList,
451 configSz,
452 &configs);
455 glAssert(_this);
457 __ASSERT_ALWAYS(configs > 0, User::Invariant());
459 aData.iConfig = configList[0];
461 delete[] configList;
463 aData.iContext = DC(eglCreateContext)(aData.iDisplay,
464 aData.iConfig,
465 EGL_NO_CONTEXT,
466 NULL);
468 glAssert(_this);
470 aData.iSurface = DC(eglCreateWindowSurface)(aData.iDisplay,
471 aData.iConfig,
472 &aWindow,
473 NULL);
475 glAssert(_this);
479 static void DestroyGles(_THIS)
481 if( _this->gl_config.driver_loaded)
483 DC(eglMakeCurrent)(_this->gl_data->iDisplay,
484 EGL_NO_SURFACE,
485 EGL_NO_SURFACE,
486 EGL_NO_CONTEXT);
487 DC(eglDestroySurface)(_this->gl_data->iDisplay, _this->gl_data->iSurface);
488 DC(eglDestroyContext)(_this->gl_data->iDisplay, _this->gl_data->iContext);
489 DC(eglTerminate)(_this->gl_data->iDisplay);
490 _this->gl_data->iLibrary.Close();
491 _this->gl_config.driver_loaded = 0;
495 SDL_Surface *S60_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags)
497 if(flags & SDL_OPENGL)
499 current->flags |= SDL_OPENGL;
500 current->w = width;
501 current->h = height;
503 RWindow* win = EpocSdlEnv::Window();
504 EpocSdlEnv::ApplyGlesDsa();
506 CreateGles(_this, *win, bpp, *_this->gl_data);
508 return current;
511 if(flags & SDL_HWSURFACE)
512 return NULL;
514 // check orientation and resolution validity
515 bool resValid = false;
516 Orientation orientation = CAknAppUi::EAppUiOrientationUnspecified;
517 for(int i=0; i<4; i++)
519 if(width <= Private->iRect[i]->w && height <= Private->iRect[i]->h)
521 orientation = Private->iOrientation[i];
522 resValid = true;
523 break;
526 if(!resValid)
527 return NULL;
529 if(!SDL_ReallocFormat(current, bpp, 0, 0, 0, 0))
530 return NULL;
532 const int numBytesPerPixel = ((bpp-1)>>3) + 1;
533 current->pitch = numBytesPerPixel * width;
535 // set proper surface flags
536 current->flags = SDL_SWSURFACE | SDL_PREALLOC;
537 if(flags & SDL_FULLSCREEN)
538 current->flags |= SDL_FULLSCREEN;
539 if(flags & SDL_RESIZABLE)
540 current->flags |= SDL_RESIZABLE;
541 if(bpp <= 8)
542 current->flags |= SDL_HWPALETTE;
544 current->w = width;
545 current->h = height;
547 // allocate surface
548 const int surfacesize = width * height * numBytesPerPixel;
549 Private->iSwSurfaceSize = TSize(width, height);
551 delete[] (TUint8*)current->pixels;
552 current->pixels = new TUint8[surfacesize];
553 Private->iSwSurface = (TUint8*) current->pixels;
555 if(current->pixels == NULL)
556 return NULL;
558 const TSize sz = GetScreenSize();
560 if(sz.iWidth < sz.iHeight && orientation != CAknAppUi::EAppUiOrientationPortrait ||
561 sz.iWidth > sz.iHeight && orientation != CAknAppUi::EAppUiOrientationLandscape)
563 g_SDL->SetOrientation(orientation, current->format->BitsPerPixel / 8);
565 else
567 if((flags & SDL_RESIZABLE) == 0)
569 TRAPD(err, static_cast<CAknAppUi*>(CEikonEnv::Static()->EikAppUi())->SetOrientationL(orientation));
571 else
573 TRAPD(err, static_cast<CAknAppUi*>(CEikonEnv::Static()->EikAppUi())->SetOrientationL(CAknAppUi::EAppUiOrientationUnspecified));
576 const int err = EpocSdlEnv::AllocSurface(current->format->BitsPerPixel / 8);
577 if(err != KErrNone)
578 return NULL;
581 // Set the blit function
582 _this->UpdateRects = S60_DirectUpdate;
584 return current;
587 static int S60_AllocHWSurface(_THIS, SDL_Surface* surface)
589 return KErrNone == EpocSdlEnv::AllocSurface(surface->format->BitsPerPixel / 8);
592 static void S60_FreeHWSurface(_THIS, SDL_Surface* /*surface*/)
596 static int S60_LockHWSurface(_THIS, SDL_Surface* surface)
598 if(EpocSdlEnv::IsDsaAvailable())
600 TUint8* address = EpocSdlEnv::LockHwSurface();
601 if(address != NULL)
603 surface->pixels = address;
604 return 1;
607 return 0;
609 static void S60_UnlockHWSurface(_THIS, SDL_Surface* /*surface*/)
611 EpocSdlEnv::UnlockHwSurface();
614 static int S60_FlipHWSurface(_THIS, SDL_Surface* /*surface*/)
616 return(0);
619 static void S60_DirectUpdate(_THIS, int numrects, SDL_Rect *rects)
621 if(EpocSdlEnv::IsDsaAvailable())
623 if(Private->iSwSurface)
625 EpocSdlEnv::Blit(Private->iSwSurface, Private->iSwSurfaceSize);
627 if(!Private->iIsWindowFocused)
629 User::After(100000);
634 /* Note: If we are terminated, this could be called in the middle of
635 another SDL video routine -- notably UpdateRects.
637 void S60_VideoQuit(_THIS)
639 delete[] Private->iOrientation;
641 delete Private->iRect[0];
642 delete Private->iRect[1];
643 delete[] Private->iRect;
645 if(_this->gl_data)
646 DestroyGles(_this);
648 delete[] Private->iSwSurface;
649 Private->iSwSurface = NULL;
650 EpocSdlEnv::FreeSurface();
654 WMcursor *S60_CreateWMCursor(_THIS, Uint8* /*data*/, Uint8* /*mask*/, int /*w*/, int /*h*/, int /*hot_x*/, int /*hot_y*/)
656 // prevents SDL from displaying standard cursor
657 return (WMcursor*) 1;
660 void S60_FreeWMCursor(_THIS, WMcursor* /*cursor*/)
664 int S60_ShowWMCursor(_THIS, WMcursor *cursor)
666 return true;
669 /*FOR GL comp*/
671 void glBegin(GLenum a) {}
672 void glEnd(void) {}
673 void glOrtho(GLdouble l, GLdouble r, GLdouble b, GLdouble t, GLdouble n, GLdouble f) {}
674 void glPopAttrib(void) {}
675 void glPopClientAttrib(void){}
676 void glPushAttrib(GLbitfield mask) {}
677 void glPushClientAttrib(GLbitfield mask) {}
678 void glTexCoord2f(GLfloat s, GLfloat t) {}
679 void glVertex2i(GLint x, GLint y) {}