~ubuntu-branches/ubuntu/gutsy/virtualbox-ose/gutsy

« back to all changes in this revision

Viewing changes to src/VBox/Frontends/VBoxSDL/VBoxSDLTest.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Steve Kowalik
  • Date: 2007-09-08 16:44:58 UTC
  • Revision ID: james.westby@ubuntu.com-20070908164458-wao29470vqtr8ksy
Tags: upstream-1.5.0-dfsg2
ImportĀ upstreamĀ versionĀ 1.5.0-dfsg2

Show diffs side-by-side

added added

removed removed

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