VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxSDL/VBoxSDLTest.cpp@ 25942

Last change on this file since 25942 was 25942, checked in by vboxsync, 15 years ago

*: RTEnv usage cleanup - avoid RTEnvGet() as it doesn't necessarily return UTF-8 encoded strings.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.4 KB
Line 
1/** @file
2 *
3 * VBox frontends: VBoxSDL (simple frontend based on SDL):
4 * VBoxSDL testcases
5 */
6
7/*
8 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23#if defined(RT_OS_WINDOWS) ///@todo someone please explain why we don't follow the book!
24# define _SDL_main_h
25#endif
26#include <SDL.h>
27
28#include <iprt/assert.h>
29#include <iprt/env.h>
30#include <iprt/stream.h>
31#include <iprt/string.h>
32#include <iprt/time.h>
33
34#include <stdlib.h>
35#include <signal.h>
36
37#ifdef VBOX_OPENGL
38#include "SDL_opengl.h"
39#endif
40
41#ifdef RT_OS_WINDOWS
42#define ESC_NORM
43#define ESC_BOLD
44#else
45#define ESC_NORM "\033[m"
46#define ESC_BOLD "\033[1m"
47#endif
48
49static SDL_Surface *gSurfVRAM; /* SDL virtual framebuffer surface */
50static void *gPtrVRAM; /* allocated virtual framebuffer */
51static SDL_Surface *gScreen; /* SDL screen surface */
52static unsigned long guGuestXRes; /* virtual framebuffer width */
53static unsigned long guGuestYRes; /* virtual framebuffer height */
54static unsigned long guGuestBpp; /* virtual framebuffer bits per pixel */
55static unsigned long guMaxScreenWidth; /* max screen width SDL allows */
56static unsigned long guMaxScreenHeight; /* max screen height SDL allows */
57static int gfResizable = 1; /* SDL window is resizable */
58static int gfFullscreen = 0; /* use fullscreen mode */
59#ifdef VBOX_OPENGL
60static unsigned long guTextureWidth; /* width of OpenGL texture */
61static unsigned long guTextureHeight; /* height of OpenGL texture */
62static unsigned int gTexture;
63static int gfOpenGL; /* use OpenGL as backend */
64#endif
65static unsigned int guLoop = 1000; /* Number of frame redrawings for each test */
66
67static void bench(unsigned long w, unsigned long h, unsigned long bpp);
68static void benchExecute(void);
69static int checkSDL(const char *fn, int rc);
70static void checkEvents(void);
71
72int
73main(int argc, char **argv)
74{
75 int rc;
76
77 for (int i = 1; i < argc; i++)
78 {
79#ifdef VBOX_OPENGL
80 if (strcmp(argv[i], "-gl") == 0)
81 {
82 gfOpenGL = 1;
83 continue;
84 }
85#endif
86 if (strcmp(argv[i], "-loop") == 0 && ++i < argc)
87 {
88 guLoop = atoi(argv[i]);
89 continue;
90 }
91 RTPrintf("Unrecognized option '%s'\n", argv[i]);
92 return -1;
93 }
94
95#ifdef RT_OS_WINDOWS
96 /* Default to DirectX if nothing else set. "windib" would be possible. */
97 if (!RTEnvExist("SDL_VIDEODRIVER"))
98 {
99 _putenv("SDL_VIDEODRIVER=directx");
100 }
101#endif
102
103#ifdef RT_OS_WINDOWS
104 _putenv("SDL_VIDEO_WINDOW_POS=0,0");
105#else
106 RTEnvSet("SDL_VIDEO_WINDOW_POS", "0,0");
107#endif
108
109 rc = SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_NOPARACHUTE);
110 if (rc != 0)
111 {
112 RTPrintf("Error: SDL_InitSubSystem failed with message '%s'\n", SDL_GetError());
113 return -1;
114 }
115
116 /* output what SDL is capable of */
117 const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
118
119 if (!videoInfo)
120 {
121 RTPrintf("No SDL video info available!\n");
122 return -1;
123 }
124
125 RTPrintf("SDL capabilities:\n");
126 RTPrintf(" Hardware surface support: %s\n", videoInfo->hw_available ? "yes" : "no");
127 RTPrintf(" Window manager available: %s\n", videoInfo->wm_available ? "yes" : "no");
128 RTPrintf(" Screen to screen blits accelerated: %s\n", videoInfo->blit_hw ? "yes" : "no");
129 RTPrintf(" Screen to screen colorkey blits accelerated: %s\n", videoInfo->blit_hw_CC ? "yes" : "no");
130 RTPrintf(" Screen to screen alpha blits accelerated: %s\n", videoInfo->blit_hw_A ? "yes" : "no");
131 RTPrintf(" Memory to screen blits accelerated: %s\n", videoInfo->blit_sw ? "yes" : "no");
132 RTPrintf(" Memory to screen colorkey blits accelerated: %s\n", videoInfo->blit_sw_CC ? "yes" : "no");
133 RTPrintf(" Memory to screen alpha blits accelerated: %s\n", videoInfo->blit_sw_A ? "yes" : "no");
134 RTPrintf(" Color fills accelerated: %s\n", videoInfo->blit_fill ? "yes" : "no");
135 RTPrintf(" Video memory in kilobytes: %d\n", videoInfo->video_mem);
136 RTPrintf(" Optimal bpp mode: %d\n", videoInfo->vfmt->BitsPerPixel);
137 char buf[256];
138 RTPrintf("Video driver SDL_VIDEODRIVER / active: %s/%s\n", RTEnvGet("SDL_VIDEODRIVER"),
139 SDL_VideoDriverName(buf, sizeof(buf)));
140
141 RTPrintf("\n"
142 "Starting tests. Any key pressed inside the SDL window will abort this\n"
143 "program at the end of the current test. Iterations = %u\n", guLoop);
144
145#ifdef VBOX_OPENGL
146 RTPrintf("\n========== "ESC_BOLD"OpenGL is %s"ESC_NORM" ==========\n",
147 gfOpenGL ? "ON" : "OFF");
148#endif
149 bench( 640, 480, 16); bench( 640, 480, 24); bench( 640, 480, 32);
150 bench(1024, 768, 16); bench(1024, 768, 24); bench(1024, 768, 32);
151 bench(1280, 1024, 16); bench(1280, 1024, 24); bench(1280, 1024, 32);
152
153 RTPrintf("\nSuccess!\n");
154 return 0;
155}
156
157/**
158 * Method that does the actual resize of the guest framebuffer and
159 * then changes the SDL framebuffer setup.
160 */
161static void bench(unsigned long w, unsigned long h, unsigned long bpp)
162{
163 Uint32 Rmask, Gmask, Bmask, Amask = 0;
164 Uint32 Rsize, Gsize, Bsize;
165 Uint32 newWidth, newHeight;
166
167 guGuestXRes = w;
168 guGuestYRes = h;
169 guGuestBpp = bpp;
170
171 RTPrintf("\n");
172
173 /* a different format we support directly? */
174 switch (guGuestBpp)
175 {
176 case 16:
177 {
178 Rmask = 0xF800;
179 Gmask = 0x07E0;
180 Bmask = 0x001F;
181 Amask = 0x0000;
182 Rsize = 5;
183 Gsize = 6;
184 Bsize = 5;
185 break;
186 }
187
188 case 24:
189 {
190 Rmask = 0x00FF0000;
191 Gmask = 0x0000FF00;
192 Bmask = 0x000000FF;
193 Amask = 0x00000000;
194 Rsize = 8;
195 Gsize = 8;
196 Bsize = 8;
197 break;
198 }
199
200 default:
201 Rmask = 0x00FF0000;
202 Gmask = 0x0000FF00;
203 Bmask = 0x000000FF;
204 Amask = 0x00000000;
205 Rsize = 8;
206 Gsize = 8;
207 Bsize = 8;
208 break;
209 }
210
211 int sdlFlags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL;
212#ifdef VBOX_OPENGL
213 if (gfOpenGL)
214 sdlFlags |= SDL_OPENGL;
215#endif
216 if (gfResizable)
217 sdlFlags |= SDL_RESIZABLE;
218 if (gfFullscreen)
219 sdlFlags |= SDL_FULLSCREEN;
220
221 /*
222 * Now we have to check whether there are video mode restrictions
223 */
224 SDL_Rect **modes;
225 /* Get available fullscreen/hardware modes */
226 modes = SDL_ListModes(NULL, sdlFlags);
227 if (modes == NULL)
228 {
229 RTPrintf("Error: SDL_ListModes failed with message '%s'\n", SDL_GetError());
230 return;
231 }
232
233 /* -1 means that any mode is possible (usually non fullscreen) */
234 if (modes != (SDL_Rect **)-1)
235 {
236 /*
237 * according to the SDL documentation, the API guarantees that
238 * the modes are sorted from larger to smaller, so we just
239 * take the first entry as the maximum.
240 */
241 guMaxScreenWidth = modes[0]->w;
242 guMaxScreenHeight = modes[0]->h;
243 }
244 else
245 {
246 /* no restriction */
247 guMaxScreenWidth = ~0;
248 guMaxScreenHeight = ~0;
249 }
250
251 newWidth = RT_MIN(guMaxScreenWidth, guGuestXRes);
252 newHeight = RT_MIN(guMaxScreenHeight, guGuestYRes);
253
254 /*
255 * Now set the screen resolution and get the surface pointer
256 * @todo BPP is not supported!
257 */
258#ifdef VBOX_OPENGL
259 if (gfOpenGL)
260 {
261 checkSDL("SDL_GL_SetAttribute", SDL_GL_SetAttribute(SDL_GL_RED_SIZE, Rsize));
262 checkSDL("SDL_GL_SetAttribute", SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, Gsize));
263 checkSDL("SDL_GL_SetAttribute", SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, Bsize));
264 checkSDL("SDL_GL_SetAttribute", SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 0));
265 }
266#endif
267
268 RTPrintf("Testing "ESC_BOLD"%ldx%ld@%ld"ESC_NORM"\n", guGuestXRes, guGuestYRes, guGuestBpp);
269
270 gScreen = SDL_SetVideoMode(newWidth, newHeight, 0, sdlFlags);
271 if (!gScreen)
272 {
273 RTPrintf("SDL_SetVideoMode failed (%s)\n", SDL_GetError());
274 return;
275 }
276
277 /* first free the current surface */
278 if (gSurfVRAM)
279 {
280 SDL_FreeSurface(gSurfVRAM);
281 gSurfVRAM = NULL;
282 }
283 if (gPtrVRAM)
284 {
285 free(gPtrVRAM);
286 gPtrVRAM = NULL;
287 }
288
289 if (gScreen->format->BitsPerPixel != guGuestBpp)
290 {
291 /* Create a source surface from guest VRAM. */
292 int bytes_per_pixel = (guGuestBpp + 7) / 8;
293 gPtrVRAM = malloc(guGuestXRes * guGuestYRes * bytes_per_pixel);
294 gSurfVRAM = SDL_CreateRGBSurfaceFrom(gPtrVRAM, guGuestXRes, guGuestYRes, guGuestBpp,
295 bytes_per_pixel * guGuestXRes,
296 Rmask, Gmask, Bmask, Amask);
297 }
298 else
299 {
300 /* Create a software surface for which SDL allocates the RAM */
301 gSurfVRAM = SDL_CreateRGBSurface(SDL_SWSURFACE, guGuestXRes, guGuestYRes, guGuestBpp,
302 Rmask, Gmask, Bmask, Amask);
303 }
304
305 if (!gSurfVRAM)
306 {
307 RTPrintf("Failed to allocate surface %ldx%ld@%ld\n",
308 guGuestXRes, guGuestYRes, guGuestBpp);
309 return;
310 }
311
312 RTPrintf(" gScreen=%dx%d@%d (surface: %s)\n",
313 gScreen->w, gScreen->h, gScreen->format->BitsPerPixel,
314 (gScreen->flags & SDL_HWSURFACE) == 0 ? "software" : "hardware");
315
316 SDL_Rect rect = { 0, 0, (Uint16)guGuestXRes, (Uint16)guGuestYRes };
317 checkSDL("SDL_FillRect",
318 SDL_FillRect(gSurfVRAM, &rect,
319 SDL_MapRGB(gSurfVRAM->format, 0x5F, 0x6F, 0x1F)));
320
321#ifdef VBOX_OPENGL
322 if (gfOpenGL)
323 {
324 int r, g, b, d, o;
325 SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &r);
326 SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &g);
327 SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &b);
328 SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &d);
329 SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &o);
330 RTPrintf(" OpenGL ctxt red=%d, green=%d, blue=%d, depth=%d, dbl=%d", r, g, b, d, o);
331
332 glEnable(GL_TEXTURE_2D);
333 glDisable(GL_BLEND);
334 glDisable(GL_DEPTH_TEST);
335 glDepthMask(GL_FALSE);
336 glGenTextures(1, &gTexture);
337 glBindTexture(GL_TEXTURE_2D, gTexture);
338 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
339 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
340 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
341 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
342
343 for (guTextureWidth = 32; guTextureWidth < newWidth; guTextureWidth <<= 1)
344 ;
345 for (guTextureHeight = 32; guTextureHeight < newHeight; guTextureHeight <<= 1)
346 ;
347 RTPrintf(", tex %ldx%ld\n", guTextureWidth, guTextureHeight);
348
349 switch (guGuestBpp)
350 {
351 case 16: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5, guTextureWidth, guTextureHeight, 0,
352 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
353 break;
354 case 24: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, guTextureWidth, guTextureHeight, 0,
355 GL_BGR, GL_UNSIGNED_BYTE, 0);
356 break;
357 case 32: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, guTextureWidth, guTextureHeight, 0,
358 GL_BGRA, GL_UNSIGNED_BYTE, 0);
359 break;
360 default: RTPrintf("guGuestBpp=%d?\n", guGuestBpp);
361 return;
362 }
363
364 glViewport(0, 0, newWidth, newHeight);
365 glMatrixMode(GL_PROJECTION);
366 glLoadIdentity();
367 glOrtho(0.0, newWidth, newHeight, 0.0, -1.0, 1.0);
368 }
369#endif
370
371 checkEvents();
372 benchExecute();
373
374#ifdef VBOX_OPENGL
375 if (gfOpenGL)
376 {
377 glDeleteTextures(1, &gTexture);
378 }
379#endif
380}
381
382static void benchExecute()
383{
384 SDL_Rect rect = { 0, 0, (Uint16)guGuestXRes, (Uint16)guGuestYRes };
385 RTTIMESPEC t1, t2;
386
387 RTTimeNow(&t1);
388 for (unsigned i=0; i<guLoop; i++)
389 {
390#ifdef VBOX_OPENGL
391 if (!gfOpenGL)
392 {
393#endif
394 /* SDL backend */
395 checkSDL("SDL_BlitSurface", SDL_BlitSurface(gSurfVRAM, &rect, gScreen, &rect));
396 if ((gScreen->flags & SDL_HWSURFACE) == 0)
397 SDL_UpdateRect(gScreen, rect.x, rect.y, rect.w, rect.h);
398#ifdef VBOX_OPENGL
399 }
400 else
401 {
402 /* OpenGL backend */
403 glBindTexture(GL_TEXTURE_2D, gTexture);
404 glPixelStorei(GL_UNPACK_SKIP_PIXELS, rect.x);
405 glPixelStorei(GL_UNPACK_SKIP_ROWS, rect.y);
406 glPixelStorei(GL_UNPACK_ROW_LENGTH, gSurfVRAM->pitch / gSurfVRAM->format->BytesPerPixel);
407 switch (gSurfVRAM->format->BitsPerPixel)
408 {
409 case 16: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rect.w, rect.h,
410 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, gSurfVRAM->pixels);
411 break;
412 case 24: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rect.w, rect.h,
413 GL_BGR, GL_UNSIGNED_BYTE, gSurfVRAM->pixels);
414 break;
415 case 32: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rect.w, rect.h,
416 GL_BGRA, GL_UNSIGNED_BYTE, gSurfVRAM->pixels);
417 break;
418 default: RTPrintf("BitsPerPixel=%d?\n", gSurfVRAM->format->BitsPerPixel);
419 return;
420 }
421 GLfloat tx = (GLfloat)((float)rect.w) / guTextureWidth;
422 GLfloat ty = (GLfloat)((float)rect.h) / guTextureHeight;
423 glBegin(GL_QUADS);
424 glColor4f(1.0, 1.0, 1.0, 1.0);
425 glTexCoord2f(0.0, 0.0); glVertex2i(rect.x, rect.y );
426 glTexCoord2f(0.0, ty); glVertex2i(rect.x, rect.y + rect.h);
427 glTexCoord2f(tx, ty); glVertex2i(rect.x + rect.w, rect.y + rect.h);
428 glTexCoord2f(tx, 0.0); glVertex2i(rect.x + rect.w, rect.y );
429 glEnd();
430 glFlush();
431 }
432#endif
433 }
434 RTTimeNow(&t2);
435 int64_t ms = RTTimeSpecGetMilli(&t2) - RTTimeSpecGetMilli(&t1);
436 printf(" %.1fms/frame\n", (double)ms / guLoop);
437}
438
439static int checkSDL(const char *fn, int rc)
440{
441 if (rc == -1)
442 RTPrintf(""ESC_BOLD"%s() failed:"ESC_NORM" '%s'\n", fn, SDL_GetError());
443
444 return rc;
445}
446
447static void checkEvents(void)
448{
449 SDL_Event event;
450 while (SDL_PollEvent(&event))
451 {
452 switch (event.type)
453 {
454 case SDL_KEYDOWN:
455 RTPrintf("\nKey pressed, exiting ...\n");
456 exit(-1);
457 break;
458 }
459 }
460}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette