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