[26709] | 1 | /* $Id: UIFrameBufferSDL.cpp 28800 2010-04-27 08:22:32Z vboxsync $ */
|
---|
[382] | 2 | /** @file
|
---|
| 3 | *
|
---|
| 4 | * VBox frontends: Qt GUI ("VirtualBox"):
|
---|
[26822] | 5 | * UIFrameBufferSDL class
|
---|
[382] | 6 | */
|
---|
| 7 |
|
---|
| 8 | /*
|
---|
[28800] | 9 | * Copyright (C) 2010 Oracle Corporation
|
---|
[382] | 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
|
---|
[5999] | 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.
|
---|
[382] | 18 | */
|
---|
| 19 |
|
---|
[26822] | 20 | #ifdef VBOX_GUI_USE_SDL
|
---|
| 21 |
|
---|
[25526] | 22 | #ifdef VBOX_WITH_PRECOMPILED_HEADERS
|
---|
| 23 | # include "precomp.h"
|
---|
| 24 | #else /* !VBOX_WITH_PRECOMPILED_HEADERS */
|
---|
[26822] | 25 |
|
---|
[26637] | 26 | /* Local includes */
|
---|
[26822] | 27 | # include "UIFrameBufferSDL.h"
|
---|
| 28 | # include "UIMachineView.h"
|
---|
| 29 | # include "VBoxX11Helper.h"
|
---|
[382] | 30 |
|
---|
[26822] | 31 | /* Global includes */
|
---|
| 32 | # include <QApplication>
|
---|
[382] | 33 |
|
---|
[26822] | 34 | #endif /* !VBOX_WITH_PRECOMPILED_HEADERS */
|
---|
[382] | 35 |
|
---|
[26637] | 36 | /** @class UIFrameBufferSDL
|
---|
[382] | 37 | *
|
---|
[26637] | 38 | * The UIFrameBufferSDL class is a class that implements the IFrameBuffer
|
---|
[382] | 39 | * interface and uses SDL to store and render VM display data.
|
---|
| 40 | */
|
---|
[26637] | 41 | UIFrameBufferSDL::UIFrameBufferSDL(UIMachineView *pMachineView)
|
---|
| 42 | : UIFrameBuffer(pMachineView)
|
---|
[382] | 43 | {
|
---|
[26637] | 44 | m_pScreen = NULL;
|
---|
| 45 | m_uPixelFormat = FramebufferPixelFormat_FOURCC_RGB;
|
---|
| 46 | m_pSurfVRAM = NULL;
|
---|
[382] | 47 |
|
---|
[11417] | 48 | X11ScreenSaverSettingsInit();
|
---|
[27107] | 49 | UIResizeEvent event(FramebufferPixelFormat_Opaque, NULL, 0, 0, 640, 480);
|
---|
| 50 | resizeEvent(&event);
|
---|
[382] | 51 | }
|
---|
| 52 |
|
---|
[26637] | 53 | UIFrameBufferSDL::~UIFrameBufferSDL()
|
---|
[382] | 54 | {
|
---|
[26637] | 55 | if (m_pSurfVRAM)
|
---|
[382] | 56 | {
|
---|
[26637] | 57 | SDL_FreeSurface(m_pSurfVRAM);
|
---|
| 58 | m_pSurfVRAM = NULL;
|
---|
[382] | 59 | }
|
---|
[11417] | 60 | X11ScreenSaverSettingsSave();
|
---|
[26637] | 61 | SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
---|
[11417] | 62 | X11ScreenSaverSettingsRestore();
|
---|
[382] | 63 | }
|
---|
| 64 |
|
---|
| 65 | /** @note This method is called on EMT from under this object's lock */
|
---|
[26637] | 66 | STDMETHODIMP UIFrameBufferSDL::NotifyUpdate(ULONG uX, ULONG uY, ULONG uW, ULONG uH)
|
---|
[382] | 67 | {
|
---|
[5329] | 68 | #if !defined (Q_WS_WIN) && !defined (Q_WS_PM)
|
---|
| 69 | /* we're not on the GUI thread and update() isn't thread safe in Qt 3.3.x
|
---|
| 70 | on the Mac (4.2.x is), on Linux (didn't check Qt 4.x there) and
|
---|
| 71 | probably on other non-DOS platforms, so post the event instead. */
|
---|
[26822] | 72 | QApplication::postEvent (m_pMachineView, new UIRepaintEvent(uX, uY, uW, uH));
|
---|
[5329] | 73 | #else
|
---|
[382] | 74 | /* we're not on the GUI thread, so update() instead of repaint()! */
|
---|
[26637] | 75 | m_pMachineView->viewport()->update(uX - m_pMachineView->contentsX(), uY - m_pMachineView->contentsY(), uW, uH);
|
---|
[5329] | 76 | #endif
|
---|
[382] | 77 | return S_OK;
|
---|
| 78 | }
|
---|
| 79 |
|
---|
[26637] | 80 | void UIFrameBufferSDL::paintEvent(QPaintEvent *pEvent)
|
---|
[382] | 81 | {
|
---|
[26637] | 82 | if (m_pScreen)
|
---|
[382] | 83 | {
|
---|
[26637] | 84 | if (m_pScreen->pixels)
|
---|
[382] | 85 | {
|
---|
[26637] | 86 | QRect r = pEvent->rect();
|
---|
[382] | 87 |
|
---|
[26637] | 88 | if (m_pSurfVRAM)
|
---|
[382] | 89 | {
|
---|
[26637] | 90 | SDL_Rect rect = { (Sint16)r.x(), (Sint16)r.y(), (Sint16)r.width(), (Sint16)r.height() };
|
---|
| 91 | SDL_BlitSurface(m_pSurfVRAM, &rect, m_pScreen, &rect);
|
---|
| 92 | /** @todo may be: if ((m_pScreen->flags & SDL_HWSURFACE) == 0) */
|
---|
| 93 | SDL_UpdateRect(m_pScreen, r.x(), r.y(), r.width(), r.height());
|
---|
[382] | 94 | }
|
---|
| 95 | else
|
---|
| 96 | {
|
---|
[26637] | 97 | SDL_UpdateRect(m_pScreen, r.x(), r.y(), r.width(), r.height());
|
---|
[382] | 98 | }
|
---|
| 99 | }
|
---|
| 100 | }
|
---|
| 101 | }
|
---|
| 102 |
|
---|
[26637] | 103 | void UIFrameBufferSDL::resizeEvent(UIResizeEvent *pEvent)
|
---|
[382] | 104 | {
|
---|
[15900] | 105 | /* Check whether the guest resolution has not been changed. */
|
---|
[26637] | 106 | bool fSameResolutionRequested = (width() == pEvent->width() && height() == pEvent->height());
|
---|
[15900] | 107 |
|
---|
| 108 | /* Check if the guest VRAM can be used as the source bitmap. */
|
---|
[26637] | 109 | bool bFallback = false;
|
---|
[15900] | 110 |
|
---|
| 111 | Uint32 Rmask = 0;
|
---|
| 112 | Uint32 Gmask = 0;
|
---|
| 113 | Uint32 Bmask = 0;
|
---|
| 114 |
|
---|
[26637] | 115 | if (pEvent->pixelFormat() == FramebufferPixelFormat_FOURCC_RGB)
|
---|
[15900] | 116 | {
|
---|
[26637] | 117 | switch (pEvent->bitsPerPixel())
|
---|
[15900] | 118 | {
|
---|
| 119 | case 32:
|
---|
| 120 | Rmask = 0x00FF0000;
|
---|
| 121 | Gmask = 0x0000FF00;
|
---|
| 122 | Bmask = 0x000000FF;
|
---|
| 123 | break;
|
---|
| 124 | case 24:
|
---|
| 125 | Rmask = 0x00FF0000;
|
---|
| 126 | Gmask = 0x0000FF00;
|
---|
| 127 | Bmask = 0x000000FF;
|
---|
| 128 | break;
|
---|
| 129 | case 16:
|
---|
| 130 | Rmask = 0xF800;
|
---|
| 131 | Gmask = 0x07E0;
|
---|
| 132 | Bmask = 0x001F;
|
---|
| 133 | break;
|
---|
| 134 | default:
|
---|
| 135 | /* Unsupported format leads to the indirect buffer */
|
---|
[26637] | 136 | bFallback = true;
|
---|
[15900] | 137 | break;
|
---|
| 138 | }
|
---|
| 139 | }
|
---|
| 140 | else
|
---|
| 141 | {
|
---|
| 142 | /* Unsupported format leads to the indirect buffer */
|
---|
[26637] | 143 | bFallback = true;
|
---|
[15900] | 144 | }
|
---|
| 145 |
|
---|
[26637] | 146 | m_width = pEvent->width();
|
---|
| 147 | m_height = pEvent->height();
|
---|
[382] | 148 |
|
---|
[15900] | 149 | /* Recreate the source surface. */
|
---|
[26637] | 150 | if (m_pSurfVRAM)
|
---|
[382] | 151 | {
|
---|
[26637] | 152 | SDL_FreeSurface(m_pSurfVRAM);
|
---|
| 153 | m_pSurfVRAM = NULL;
|
---|
[382] | 154 | }
|
---|
[15900] | 155 |
|
---|
[26637] | 156 | if (!bFallback)
|
---|
[15900] | 157 | {
|
---|
| 158 | /* It is OK to create the source surface from the guest VRAM. */
|
---|
[26637] | 159 | m_pSurfVRAM = SDL_CreateRGBSurfaceFrom(pEvent->VRAM(), pEvent->width(), pEvent->height(),
|
---|
| 160 | pEvent->bitsPerPixel(),
|
---|
| 161 | pEvent->bytesPerLine(),
|
---|
| 162 | Rmask, Gmask, Bmask, 0);
|
---|
| 163 | LogFlowFunc(("Created VRAM surface %p\n", m_pSurfVRAM));
|
---|
| 164 | if (m_pSurfVRAM == NULL)
|
---|
[15900] | 165 | {
|
---|
[26637] | 166 | bFallback = true;
|
---|
[15900] | 167 | }
|
---|
| 168 | }
|
---|
| 169 |
|
---|
| 170 | if (fSameResolutionRequested)
|
---|
| 171 | {
|
---|
[16269] | 172 | LogFlowFunc(("the same resolution requested, skipping the resize.\n"));
|
---|
[15900] | 173 | return;
|
---|
| 174 | }
|
---|
| 175 |
|
---|
| 176 | /* close SDL so we can init it again */
|
---|
[26637] | 177 | if (m_pScreen)
|
---|
[382] | 178 | {
|
---|
[11417] | 179 | X11ScreenSaverSettingsSave();
|
---|
[26637] | 180 | SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
---|
[11417] | 181 | X11ScreenSaverSettingsRestore();
|
---|
[26637] | 182 | m_pScreen = NULL;
|
---|
[382] | 183 | }
|
---|
| 184 |
|
---|
| 185 | /*
|
---|
[26637] | 186 | * initialize the SDL library, use its super hack to integrate it with our client window
|
---|
[382] | 187 | */
|
---|
| 188 | static char sdlHack[64];
|
---|
[26637] | 189 | LogFlowFunc(("Using client window 0x%08lX to initialize SDL\n", m_pMachineView->viewport()->winId()));
|
---|
[3761] | 190 | /* Note: SDL_WINDOWID must be decimal (not hex) to work on Win32 */
|
---|
[26637] | 191 | sprintf(sdlHack, "SDL_WINDOWID=%lu", m_pMachineView->viewport()->winId());
|
---|
| 192 | putenv(sdlHack);
|
---|
[11417] | 193 | X11ScreenSaverSettingsSave();
|
---|
[26637] | 194 | int rc = SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE);
|
---|
[11418] | 195 | X11ScreenSaverSettingsRestore();
|
---|
[26637] | 196 | AssertMsg(rc == 0, ("SDL initialization failed: %s\n", SDL_GetError()));
|
---|
[382] | 197 | NOREF(rc);
|
---|
| 198 |
|
---|
| 199 | #ifdef Q_WS_X11
|
---|
| 200 | /* undo signal redirections from SDL, it'd steal keyboard events from us! */
|
---|
[26637] | 201 | signal(SIGINT, SIG_DFL);
|
---|
| 202 | signal(SIGQUIT, SIG_DFL);
|
---|
[382] | 203 | #endif
|
---|
| 204 |
|
---|
[26637] | 205 | LogFlowFunc(("Setting SDL video mode to %d x %d\n", m_width, m_height));
|
---|
[382] | 206 |
|
---|
[3761] | 207 | /* Pixel format is RGB in any case */
|
---|
[26637] | 208 | m_uPixelFormat = FramebufferPixelFormat_FOURCC_RGB;
|
---|
[3761] | 209 |
|
---|
[26637] | 210 | m_pScreen = SDL_SetVideoMode(m_width, m_height, 0, SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL);
|
---|
| 211 | AssertMsg(m_pScreen, ("SDL video mode could not be set!\n"));
|
---|
[382] | 212 | }
|
---|
| 213 |
|
---|
[26822] | 214 | #endif /* VBOX_GUI_USE_SDL */
|
---|
[6645] | 215 |
|
---|