VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 7 weeks ago

Copyright year updates by scm.

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