VirtualBox

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

Last change on this file since 94740 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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