VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxSDL/Framebuffer.cpp@ 52180

Last change on this file since 52180 was 52122, checked in by vboxsync, 11 years ago

VBoxSDL: redraw the guest screen after a resize.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 47.2 KB
Line 
1/** @file
2 *
3 * VBox frontends: VBoxSDL (simple frontend based on SDL):
4 * Implementation of VBoxSDLFB (SDL framebuffer) class
5 */
6
7/*
8 * Copyright (C) 2006-2012 Oracle Corporation
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 (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#include <VBox/com/com.h>
20#include <VBox/com/array.h>
21#include <VBox/com/string.h>
22#include <VBox/com/Guid.h>
23#include <VBox/com/ErrorInfo.h>
24#include <VBox/com/VirtualBox.h>
25
26#include <iprt/stream.h>
27#include <iprt/env.h>
28
29#ifdef RT_OS_OS2
30# undef RT_MAX
31// from <iprt/cdefs.h>
32# define RT_MAX(Value1, Value2) ((Value1) >= (Value2) ? (Value1) : (Value2))
33#endif
34
35using namespace com;
36
37#define LOG_GROUP LOG_GROUP_GUI
38#include <VBox/err.h>
39#include <VBox/log.h>
40
41#include "VBoxSDL.h"
42#include "Framebuffer.h"
43#include "Ico64x01.h"
44
45#if defined(RT_OS_WINDOWS) || defined(RT_OS_LINUX)
46#include <SDL_syswm.h> /* for SDL_GetWMInfo() */
47#endif
48
49#if defined(VBOX_WITH_XPCOM)
50NS_IMPL_THREADSAFE_ISUPPORTS1_CI(VBoxSDLFB, IFramebuffer)
51NS_DECL_CLASSINFO(VBoxSDLFB)
52NS_IMPL_THREADSAFE_ISUPPORTS2_CI(VBoxSDLFBOverlay, IFramebufferOverlay, IFramebuffer)
53NS_DECL_CLASSINFO(VBoxSDLFBOverlay)
54#endif
55
56#ifdef VBOX_SECURELABEL
57/* function pointers */
58extern "C"
59{
60DECLSPEC int (SDLCALL *pTTF_Init)(void);
61DECLSPEC TTF_Font* (SDLCALL *pTTF_OpenFont)(const char *file, int ptsize);
62DECLSPEC SDL_Surface* (SDLCALL *pTTF_RenderUTF8_Solid)(TTF_Font *font, const char *text, SDL_Color fg);
63DECLSPEC SDL_Surface* (SDLCALL *pTTF_RenderUTF8_Blended)(TTF_Font *font, const char *text, SDL_Color fg);
64DECLSPEC void (SDLCALL *pTTF_CloseFont)(TTF_Font *font);
65DECLSPEC void (SDLCALL *pTTF_Quit)(void);
66}
67#endif /* VBOX_SECURELABEL */
68
69static bool gfSdlInitialized = false; /**< if SDL was initialized */
70static SDL_Surface *gWMIcon = NULL; /**< the application icon */
71static RTNATIVETHREAD gSdlNativeThread = NIL_RTNATIVETHREAD; /**< the SDL thread */
72
73//
74// Constructor / destructor
75//
76
77VBoxSDLFB::VBoxSDLFB()
78{
79}
80
81HRESULT VBoxSDLFB::FinalConstruct()
82{
83 return 0;
84}
85
86void VBoxSDLFB::FinalRelease()
87{
88 return;
89}
90
91/**
92 * SDL framebuffer constructor. It is called from the main
93 * (i.e. SDL) thread. Therefore it is safe to use SDL calls
94 * here.
95 * @param fFullscreen flag whether we start in fullscreen mode
96 * @param fResizable flag whether the SDL window should be resizable
97 * @param fShowSDLConfig flag whether we print out SDL settings
98 * @param fKeepHostRes flag whether we switch the host screen resolution
99 * when switching to fullscreen or not
100 * @param iFixedWidth fixed SDL width (-1 means not set)
101 * @param iFixedHeight fixed SDL height (-1 means not set)
102 */
103HRESULT VBoxSDLFB::init(uint32_t uScreenId,
104 bool fFullscreen, bool fResizable, bool fShowSDLConfig,
105 bool fKeepHostRes, uint32_t u32FixedWidth,
106 uint32_t u32FixedHeight, uint32_t u32FixedBPP,
107 bool fUpdateImage)
108{
109 int rc;
110 LogFlow(("VBoxSDLFB::VBoxSDLFB\n"));
111
112 mScreenId = uScreenId;
113 mfUpdateImage = fUpdateImage;
114 mScreen = NULL;
115#ifdef VBOX_WITH_SDL13
116 mWindow = 0;
117 mTexture = 0;
118#endif
119 mSurfVRAM = NULL;
120 mfInitialized = false;
121 mfFullscreen = fFullscreen;
122 mfKeepHostRes = fKeepHostRes;
123 mTopOffset = 0;
124 mfResizable = fResizable;
125 mfShowSDLConfig = fShowSDLConfig;
126 mFixedSDLWidth = u32FixedWidth;
127 mFixedSDLHeight = u32FixedHeight;
128 mFixedSDLBPP = u32FixedBPP;
129 mCenterXOffset = 0;
130 mCenterYOffset = 0;
131 /* Start with standard screen dimensions. */
132 mGuestXRes = 640;
133 mGuestYRes = 480;
134 mPtrVRAM = NULL;
135 mBitsPerPixel = 0;
136 mBytesPerLine = 0;
137 mfSameSizeRequested = false;
138#ifdef VBOX_SECURELABEL
139 mLabelFont = NULL;
140 mLabelHeight = 0;
141 mLabelOffs = 0;
142#endif
143
144 mfUpdates = false;
145
146 rc = RTCritSectInit(&mUpdateLock);
147 AssertMsg(rc == VINF_SUCCESS, ("Error from RTCritSectInit!\n"));
148
149 resizeGuest();
150 Assert(mScreen);
151 mfInitialized = true;
152#ifdef RT_OS_WINDOWS
153 HRESULT hr = CoCreateFreeThreadedMarshaler(this, //GetControllingUnknown(),
154 &m_pUnkMarshaler.p);
155 Log(("CoCreateFreeThreadedMarshaler hr %08X\n", hr));
156#endif
157
158 return 0;
159}
160
161VBoxSDLFB::~VBoxSDLFB()
162{
163 LogFlow(("VBoxSDLFB::~VBoxSDLFB\n"));
164 if (mSurfVRAM)
165 {
166 SDL_FreeSurface(mSurfVRAM);
167 mSurfVRAM = NULL;
168 }
169 mScreen = NULL;
170
171#ifdef VBOX_SECURELABEL
172 if (mLabelFont)
173 pTTF_CloseFont(mLabelFont);
174 if (pTTF_Quit)
175 pTTF_Quit();
176#endif
177
178 RTCritSectDelete(&mUpdateLock);
179}
180
181bool VBoxSDLFB::init(bool fShowSDLConfig)
182{
183 LogFlow(("VBoxSDLFB::init\n"));
184
185 /* memorize the thread that inited us, that's the SDL thread */
186 gSdlNativeThread = RTThreadNativeSelf();
187
188#ifdef RT_OS_WINDOWS
189 /* default to DirectX if nothing else set */
190 if (!RTEnvExist("SDL_VIDEODRIVER"))
191 {
192 _putenv("SDL_VIDEODRIVER=directx");
193// _putenv("SDL_VIDEODRIVER=windib");
194 }
195#endif
196#ifdef VBOXSDL_WITH_X11
197 /* On some X servers the mouse is stuck inside the bottom right corner.
198 * See http://wiki.clug.org.za/wiki/QEMU_mouse_not_working */
199 RTEnvSet("SDL_VIDEO_X11_DGAMOUSE", "0");
200#endif
201 int rc = SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_NOPARACHUTE);
202 if (rc != 0)
203 {
204 RTPrintf("SDL Error: '%s'\n", SDL_GetError());
205 return false;
206 }
207 gfSdlInitialized = true;
208
209 const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
210 Assert(videoInfo);
211 if (videoInfo)
212 {
213 /* output what SDL is capable of */
214 if (fShowSDLConfig)
215 RTPrintf("SDL capabilities:\n"
216 " Hardware surface support: %s\n"
217 " Window manager available: %s\n"
218 " Screen to screen blits accelerated: %s\n"
219 " Screen to screen colorkey blits accelerated: %s\n"
220 " Screen to screen alpha blits accelerated: %s\n"
221 " Memory to screen blits accelerated: %s\n"
222 " Memory to screen colorkey blits accelerated: %s\n"
223 " Memory to screen alpha blits accelerated: %s\n"
224 " Color fills accelerated: %s\n"
225 " Video memory in kilobytes: %d\n"
226 " Optimal bpp mode: %d\n"
227 "SDL video driver: %s\n",
228 videoInfo->hw_available ? "yes" : "no",
229 videoInfo->wm_available ? "yes" : "no",
230 videoInfo->blit_hw ? "yes" : "no",
231 videoInfo->blit_hw_CC ? "yes" : "no",
232 videoInfo->blit_hw_A ? "yes" : "no",
233 videoInfo->blit_sw ? "yes" : "no",
234 videoInfo->blit_sw_CC ? "yes" : "no",
235 videoInfo->blit_sw_A ? "yes" : "no",
236 videoInfo->blit_fill ? "yes" : "no",
237 videoInfo->video_mem,
238 videoInfo->vfmt->BitsPerPixel,
239 RTEnvGet("SDL_VIDEODRIVER"));
240 }
241
242 if (12320 == g_cbIco64x01)
243 {
244 gWMIcon = SDL_AllocSurface(SDL_SWSURFACE, 64, 64, 24, 0xff, 0xff00, 0xff0000, 0);
245 /** @todo make it as simple as possible. No PNM interpreter here... */
246 if (gWMIcon)
247 {
248 memcpy(gWMIcon->pixels, g_abIco64x01+32, g_cbIco64x01-32);
249 SDL_WM_SetIcon(gWMIcon, NULL);
250 }
251 }
252
253 return true;
254}
255
256/**
257 * Terminate SDL
258 *
259 * @remarks must be called from the SDL thread!
260 */
261void VBoxSDLFB::uninit()
262{
263 if (gfSdlInitialized)
264 {
265 AssertMsg(gSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
266 SDL_QuitSubSystem(SDL_INIT_VIDEO);
267 if (gWMIcon)
268 {
269 SDL_FreeSurface(gWMIcon);
270 gWMIcon = NULL;
271 }
272 }
273}
274
275/**
276 * Returns the current framebuffer width in pixels.
277 *
278 * @returns COM status code
279 * @param width Address of result buffer.
280 */
281STDMETHODIMP VBoxSDLFB::COMGETTER(Width)(ULONG *width)
282{
283 LogFlow(("VBoxSDLFB::GetWidth\n"));
284 if (!width)
285 return E_INVALIDARG;
286 *width = mGuestXRes;
287 return S_OK;
288}
289
290/**
291 * Returns the current framebuffer height in pixels.
292 *
293 * @returns COM status code
294 * @param height Address of result buffer.
295 */
296STDMETHODIMP VBoxSDLFB::COMGETTER(Height)(ULONG *height)
297{
298 LogFlow(("VBoxSDLFB::GetHeight\n"));
299 if (!height)
300 return E_INVALIDARG;
301 *height = mGuestYRes;
302 return S_OK;
303}
304
305/**
306 * Return the current framebuffer color depth.
307 *
308 * @returns COM status code
309 * @param bitsPerPixel Address of result variable
310 */
311STDMETHODIMP VBoxSDLFB::COMGETTER(BitsPerPixel)(ULONG *bitsPerPixel)
312{
313 LogFlow(("VBoxSDLFB::GetBitsPerPixel\n"));
314 if (!bitsPerPixel)
315 return E_INVALIDARG;
316 /* get the information directly from the surface in use */
317 Assert(mSurfVRAM);
318 *bitsPerPixel = (ULONG)(mSurfVRAM ? mSurfVRAM->format->BitsPerPixel : 0);
319 return S_OK;
320}
321
322/**
323 * Return the current framebuffer line size in bytes.
324 *
325 * @returns COM status code.
326 * @param lineSize Address of result variable.
327 */
328STDMETHODIMP VBoxSDLFB::COMGETTER(BytesPerLine)(ULONG *bytesPerLine)
329{
330 LogFlow(("VBoxSDLFB::GetBytesPerLine\n"));
331 if (!bytesPerLine)
332 return E_INVALIDARG;
333 /* get the information directly from the surface */
334 Assert(mSurfVRAM);
335 *bytesPerLine = (ULONG)(mSurfVRAM ? mSurfVRAM->pitch : 0);
336 return S_OK;
337}
338
339STDMETHODIMP VBoxSDLFB::COMGETTER(PixelFormat) (ULONG *pixelFormat)
340{
341 if (!pixelFormat)
342 return E_POINTER;
343 *pixelFormat = FramebufferPixelFormat_FOURCC_RGB;
344 return S_OK;
345}
346
347/**
348 * Returns by how many pixels the guest should shrink its
349 * video mode height values.
350 *
351 * @returns COM status code.
352 * @param heightReduction Address of result variable.
353 */
354STDMETHODIMP VBoxSDLFB::COMGETTER(HeightReduction)(ULONG *heightReduction)
355{
356 if (!heightReduction)
357 return E_POINTER;
358#ifdef VBOX_SECURELABEL
359 *heightReduction = mLabelHeight;
360#else
361 *heightReduction = 0;
362#endif
363 return S_OK;
364}
365
366/**
367 * Returns a pointer to an alpha-blended overlay used for displaying status
368 * icons above the framebuffer.
369 *
370 * @returns COM status code.
371 * @param aOverlay The overlay framebuffer.
372 */
373STDMETHODIMP VBoxSDLFB::COMGETTER(Overlay)(IFramebufferOverlay **aOverlay)
374{
375 if (!aOverlay)
376 return E_POINTER;
377 /* Not yet implemented */
378 *aOverlay = 0;
379 return S_OK;
380}
381
382/**
383 * Returns handle of window where framebuffer context is being drawn
384 *
385 * @returns COM status code.
386 * @param winId Handle of associated window.
387 */
388STDMETHODIMP VBoxSDLFB::COMGETTER(WinId)(int64_t *winId)
389{
390 if (!winId)
391 return E_POINTER;
392 *winId = mWinId;
393 return S_OK;
394}
395
396/**
397 * Notify framebuffer of an update.
398 *
399 * @returns COM status code
400 * @param x Update region upper left corner x value.
401 * @param y Update region upper left corner y value.
402 * @param w Update region width in pixels.
403 * @param h Update region height in pixels.
404 * @param finished Address of output flag whether the update
405 * could be fully processed in this call (which
406 * has to return immediately) or VBox should wait
407 * for a call to the update complete API before
408 * continuing with display updates.
409 */
410STDMETHODIMP VBoxSDLFB::NotifyUpdate(ULONG x, ULONG y,
411 ULONG w, ULONG h)
412{
413 /*
414 * The input values are in guest screen coordinates.
415 */
416 LogFlow(("VBoxSDLFB::NotifyUpdate: x = %d, y = %d, w = %d, h = %d\n",
417 x, y, w, h));
418
419#ifdef VBOXSDL_WITH_X11
420 /*
421 * SDL does not allow us to make this call from any other thread than
422 * the main SDL thread (which initialized the video mode). So we have
423 * to send an event to the main SDL thread and process it there. For
424 * sake of simplicity, we encode all information in the event parameters.
425 */
426 SDL_Event event;
427 event.type = SDL_USEREVENT;
428 event.user.code = mScreenId;
429 event.user.type = SDL_USER_EVENT_UPDATERECT;
430 // 16 bit is enough for coordinates
431 event.user.data1 = (void*)(uintptr_t)(x << 16 | y);
432 event.user.data2 = (void*)(uintptr_t)(w << 16 | h);
433 PushNotifyUpdateEvent(&event);
434#else /* !VBOXSDL_WITH_X11 */
435 update(x, y, w, h, true /* fGuestRelative */);
436#endif /* !VBOXSDL_WITH_X11 */
437
438 return S_OK;
439}
440
441STDMETHODIMP VBoxSDLFB::NotifyUpdateImage(ULONG aX,
442 ULONG aY,
443 ULONG aWidth,
444 ULONG aHeight,
445 ComSafeArrayIn(BYTE, aImage))
446{
447 LogFlow(("NotifyUpdateImage: %d,%d %dx%d\n", aX, aY, aWidth, aHeight));
448
449 com::SafeArray<BYTE> image(ComSafeArrayInArg(aImage));
450
451 /* Copy to mSurfVRAM. */
452 SDL_Rect srcRect;
453 SDL_Rect dstRect;
454 srcRect.x = 0;
455 srcRect.y = 0;
456 srcRect.w = (uint16_t)aWidth;
457 srcRect.h = (uint16_t)aHeight;
458 dstRect.x = (int16_t)aX;
459 dstRect.y = (int16_t)aY;
460 dstRect.w = (uint16_t)aWidth;
461 dstRect.h = (uint16_t)aHeight;
462
463 const uint32_t Rmask = 0x00FF0000, Gmask = 0x0000FF00, Bmask = 0x000000FF, Amask = 0;
464 SDL_Surface *surfSrc = SDL_CreateRGBSurfaceFrom(image.raw(), aWidth, aHeight, 32, aWidth * 4,
465 Rmask, Gmask, Bmask, Amask);
466 if (surfSrc)
467 {
468 RTCritSectEnter(&mUpdateLock);
469 if (mfUpdates)
470 SDL_BlitSurface(surfSrc, &srcRect, mSurfVRAM, &dstRect);
471 RTCritSectLeave(&mUpdateLock);
472
473 SDL_FreeSurface(surfSrc);
474 }
475
476 return NotifyUpdate(aX, aY, aWidth, aHeight);
477}
478
479extern ComPtr<IDisplay> gpDisplay;
480
481STDMETHODIMP VBoxSDLFB::NotifyChange(ULONG aScreenId,
482 ULONG aXOrigin,
483 ULONG aYOrigin,
484 ULONG aWidth,
485 ULONG aHeight)
486{
487 LogRel(("NotifyChange: %d %d,%d %dx%d\n",
488 aScreenId, aXOrigin, aYOrigin, aWidth, aHeight));
489
490 ComPtr<IDisplaySourceBitmap> pSourceBitmap;
491 if (!mfUpdateImage)
492 gpDisplay->QuerySourceBitmap(aScreenId, pSourceBitmap.asOutParam());
493
494 RTCritSectEnter(&mUpdateLock);
495
496 /* Disable screen updates. */
497 mfUpdates = false;
498
499 if (mfUpdateImage)
500 {
501 mGuestXRes = aWidth;
502 mGuestYRes = aHeight;
503 mPtrVRAM = NULL;
504 mBitsPerPixel = 0;
505 mBytesPerLine = 0;
506 }
507 else
508 {
509 /* Save the new bitmap. */
510 mpPendingSourceBitmap = pSourceBitmap;
511 }
512
513 RTCritSectLeave(&mUpdateLock);
514
515 SDL_Event event;
516 event.type = SDL_USEREVENT;
517 event.user.type = SDL_USER_EVENT_NOTIFYCHANGE;
518 event.user.code = mScreenId;
519
520 PushSDLEventForSure(&event);
521
522 RTThreadYield();
523
524 return S_OK;
525}
526
527/**
528 * Returns whether we like the given video mode.
529 *
530 * @returns COM status code
531 * @param width video mode width in pixels
532 * @param height video mode height in pixels
533 * @param bpp video mode bit depth in bits per pixel
534 * @param supported pointer to result variable
535 */
536STDMETHODIMP VBoxSDLFB::VideoModeSupported(ULONG width, ULONG height, ULONG bpp, BOOL *supported)
537{
538 if (!supported)
539 return E_POINTER;
540
541 /* are constraints set? */
542 if ( ( (mMaxScreenWidth != ~(uint32_t)0)
543 && (width > mMaxScreenWidth))
544 || ( (mMaxScreenHeight != ~(uint32_t)0)
545 && (height > mMaxScreenHeight)))
546 {
547 /* nope, we don't want that (but still don't freak out if it is set) */
548#ifdef DEBUG
549 printf("VBoxSDL::VideoModeSupported: we refused mode %dx%dx%d\n", width, height, bpp);
550#endif
551 *supported = false;
552 }
553 else
554 {
555 /* anything will do */
556 *supported = true;
557 }
558 return S_OK;
559}
560
561STDMETHODIMP VBoxSDLFB::GetVisibleRegion(BYTE *aRectangles, ULONG aCount,
562 ULONG *aCountCopied)
563{
564 PRTRECT rects = (PRTRECT)aRectangles;
565
566 if (!rects)
567 return E_POINTER;
568
569 /// @todo
570
571 NOREF(aCount);
572 NOREF(aCountCopied);
573
574 return S_OK;
575}
576
577STDMETHODIMP VBoxSDLFB::SetVisibleRegion(BYTE *aRectangles, ULONG aCount)
578{
579 PRTRECT rects = (PRTRECT)aRectangles;
580
581 if (!rects)
582 return E_POINTER;
583
584 /// @todo
585
586 NOREF(aCount);
587
588 return S_OK;
589}
590
591STDMETHODIMP VBoxSDLFB::ProcessVHWACommand(BYTE *pCommand)
592{
593 return E_NOTIMPL;
594}
595
596STDMETHODIMP VBoxSDLFB::Notify3DEvent(ULONG uType, ComSafeArrayIn(BYTE, aData))
597{
598 return E_NOTIMPL;
599}
600
601//
602// Internal public methods
603//
604
605/* This method runs on the main SDL thread. */
606void VBoxSDLFB::notifyChange(ULONG aScreenId)
607{
608 /* Disable screen updates. */
609 RTCritSectEnter(&mUpdateLock);
610
611 if (!mfUpdateImage && mpPendingSourceBitmap.isNull())
612 {
613 /* Do nothing. Change event already processed. */
614 RTCritSectLeave(&mUpdateLock);
615 return;
616 }
617
618 /* Release the current bitmap and keep the pending one. */
619 mpSourceBitmap = mpPendingSourceBitmap;
620 mpPendingSourceBitmap.setNull();
621
622 RTCritSectLeave(&mUpdateLock);
623
624 if (mpSourceBitmap.isNull())
625 {
626 mPtrVRAM = NULL;
627 mBitsPerPixel = 32;
628 mBytesPerLine = mGuestXRes * 4;
629 }
630 else
631 {
632 BYTE *pAddress = NULL;
633 ULONG ulWidth = 0;
634 ULONG ulHeight = 0;
635 ULONG ulBitsPerPixel = 0;
636 ULONG ulBytesPerLine = 0;
637 ULONG ulPixelFormat = 0;
638
639 mpSourceBitmap->QueryBitmapInfo(&pAddress,
640 &ulWidth,
641 &ulHeight,
642 &ulBitsPerPixel,
643 &ulBytesPerLine,
644 &ulPixelFormat);
645
646 if ( mGuestXRes == ulWidth
647 && mGuestYRes == ulHeight
648 && mBitsPerPixel == ulBitsPerPixel
649 && mBytesPerLine == ulBytesPerLine
650 && mPtrVRAM == pAddress
651 )
652 {
653 mfSameSizeRequested = true;
654 }
655 else
656 {
657 mfSameSizeRequested = false;
658 }
659
660 mGuestXRes = ulWidth;
661 mGuestYRes = ulHeight;
662 mPtrVRAM = pAddress;
663 mBitsPerPixel = ulBitsPerPixel;
664 mBytesPerLine = ulBytesPerLine;
665 }
666
667 resizeGuest();
668
669 if (mfUpdateImage)
670 {
671 gpDisplay->SetFramebufferUpdateMode(aScreenId, FramebufferUpdateMode_NotifyUpdateImage);
672 }
673
674 gpDisplay->InvalidateAndUpdateScreen(aScreenId);
675}
676
677/**
678 * Method that does the actual resize of the guest framebuffer and
679 * then changes the SDL framebuffer setup.
680 */
681void VBoxSDLFB::resizeGuest()
682{
683 LogFlowFunc (("mGuestXRes: %d, mGuestYRes: %d\n", mGuestXRes, mGuestYRes));
684 AssertMsg(gSdlNativeThread == RTThreadNativeSelf(),
685 ("Wrong thread! SDL is not threadsafe!\n"));
686
687 RTCritSectEnter(&mUpdateLock);
688
689 const uint32_t Rmask = 0x00FF0000, Gmask = 0x0000FF00, Bmask = 0x000000FF, Amask = 0;
690
691 /* first free the current surface */
692 if (mSurfVRAM)
693 {
694 SDL_FreeSurface(mSurfVRAM);
695 mSurfVRAM = NULL;
696 }
697
698 if (mPtrVRAM)
699 {
700 /* Create a source surface from the source bitmap. */
701 mSurfVRAM = SDL_CreateRGBSurfaceFrom(mPtrVRAM, mGuestXRes, mGuestYRes, mBitsPerPixel,
702 mBytesPerLine, Rmask, Gmask, Bmask, Amask);
703 LogFlow(("VBoxSDL:: using the source bitmap\n"));
704 }
705 else
706 {
707 mSurfVRAM = SDL_CreateRGBSurface(SDL_SWSURFACE, mGuestXRes, mGuestYRes, mBitsPerPixel,
708 Rmask, Gmask, Bmask, Amask);
709 LogFlow(("VBoxSDL:: using SDL_SWSURFACE\n"));
710 }
711 LogFlow(("VBoxSDL:: created VRAM surface %p\n", mSurfVRAM));
712
713 if (mfSameSizeRequested)
714 {
715 mfSameSizeRequested = false;
716 LogFlow(("VBoxSDL:: the same resolution requested, skipping the resize.\n"));
717 }
718 else
719 {
720 /* now adjust the SDL resolution */
721 resizeSDL();
722 }
723
724 /* Enable screen updates. */
725 mfUpdates = true;
726
727 RTCritSectLeave(&mUpdateLock);
728
729 repaint();
730}
731
732/**
733 * Sets SDL video mode. This is independent from guest video
734 * mode changes.
735 *
736 * @remarks Must be called from the SDL thread!
737 */
738void VBoxSDLFB::resizeSDL(void)
739{
740 LogFlow(("VBoxSDL:resizeSDL\n"));
741
742 /*
743 * We request a hardware surface from SDL so that we can perform
744 * accelerated system memory to VRAM blits. The way video handling
745 * works it that on the one hand we have the screen surface from SDL
746 * and on the other hand we have a software surface that we create
747 * using guest VRAM memory for linear modes and using SDL allocated
748 * system memory for text and non linear graphics modes. We never
749 * directly write to the screen surface but always use SDL blitting
750 * functions to blit from our system memory surface to the VRAM.
751 * Therefore, SDL can take advantage of hardware acceleration.
752 */
753 int sdlFlags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL;
754#ifndef RT_OS_OS2 /* doesn't seem to work for some reason... */
755 if (mfResizable)
756 sdlFlags |= SDL_RESIZABLE;
757#endif
758 if (mfFullscreen)
759 sdlFlags |= SDL_FULLSCREEN;
760
761 /*
762 * Now we have to check whether there are video mode restrictions
763 */
764 SDL_Rect **modes;
765 /* Get available fullscreen/hardware modes */
766 modes = SDL_ListModes(NULL, sdlFlags);
767 Assert(modes != NULL);
768 /* -1 means that any mode is possible (usually non fullscreen) */
769 if (modes != (SDL_Rect **)-1)
770 {
771 /*
772 * according to the SDL documentation, the API guarantees that
773 * the modes are sorted from larger to smaller, so we just
774 * take the first entry as the maximum.
775 */
776 mMaxScreenWidth = modes[0]->w;
777 mMaxScreenHeight = modes[0]->h;
778 }
779 else
780 {
781 /* no restriction */
782 mMaxScreenWidth = ~(uint32_t)0;
783 mMaxScreenHeight = ~(uint32_t)0;
784 }
785
786 uint32_t newWidth;
787 uint32_t newHeight;
788
789 /* reset the centering offsets */
790 mCenterXOffset = 0;
791 mCenterYOffset = 0;
792
793 /* we either have a fixed SDL resolution or we take the guest's */
794 if (mFixedSDLWidth != ~(uint32_t)0)
795 {
796 newWidth = mFixedSDLWidth;
797 newHeight = mFixedSDLHeight;
798 }
799 else
800 {
801 newWidth = RT_MIN(mGuestXRes, mMaxScreenWidth);
802#ifdef VBOX_SECURELABEL
803 newHeight = RT_MIN(mGuestYRes + mLabelHeight, mMaxScreenHeight);
804#else
805 newHeight = RT_MIN(mGuestYRes, mMaxScreenHeight);
806#endif
807 }
808
809 /* we don't have any extra space by default */
810 mTopOffset = 0;
811
812#if defined(VBOX_WITH_SDL13)
813 int sdlWindowFlags = SDL_WINDOW_SHOWN;
814 if (mfResizable)
815 sdlWindowFlags |= SDL_WINDOW_RESIZABLE;
816 if (!mWindow)
817 {
818 SDL_DisplayMode desktop_mode;
819 int x = 40 + mScreenId * 20;
820 int y = 40 + mScreenId * 15;
821
822 SDL_GetDesktopDisplayMode(&desktop_mode);
823 /* create new window */
824
825 char szTitle[64];
826 RTStrPrintf(szTitle, sizeof(szTitle), "SDL window %d", mScreenId);
827 mWindow = SDL_CreateWindow(szTitle, x, y,
828 newWidth, newHeight, sdlWindowFlags);
829 if (SDL_CreateRenderer(mWindow, -1,
830 SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTDISCARD) < 0)
831 AssertReleaseFailed();
832
833 SDL_GetRendererInfo(&mRenderInfo);
834
835 mTexture = SDL_CreateTexture(desktop_mode.format,
836 SDL_TEXTUREACCESS_STREAMING, newWidth, newHeight);
837 if (!mTexture)
838 AssertReleaseFailed();
839 }
840 else
841 {
842 int w, h;
843 uint32_t format;
844 int access;
845
846 /* resize current window */
847 SDL_GetWindowSize(mWindow, &w, &h);
848
849 if (w != (int)newWidth || h != (int)newHeight)
850 SDL_SetWindowSize(mWindow, newWidth, newHeight);
851
852 SDL_QueryTexture(mTexture, &format, &access, &w, &h);
853 SDL_SelectRenderer(mWindow);
854 SDL_DestroyTexture(mTexture);
855 mTexture = SDL_CreateTexture(format, access, newWidth, newHeight);
856 if (!mTexture)
857 AssertReleaseFailed();
858 }
859
860 void *pixels;
861 int pitch;
862 int w, h, bpp;
863 uint32_t Rmask, Gmask, Bmask, Amask;
864 uint32_t format;
865
866 if (SDL_QueryTexture(mTexture, &format, NULL, &w, &h) < 0)
867 AssertReleaseFailed();
868
869 if (!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask))
870 AssertReleaseFailed();
871
872 if (SDL_QueryTexturePixels(mTexture, &pixels, &pitch) == 0)
873 {
874 mScreen = SDL_CreateRGBSurfaceFrom(pixels, w, h, bpp, pitch,
875 Rmask, Gmask, Bmask, Amask);
876 }
877 else
878 {
879 mScreen = SDL_CreateRGBSurface(0, w, h, bpp, Rmask, Gmask, Bmask, Amask);
880 AssertReleaseFailed();
881 }
882
883 SDL_SetClipRect(mScreen, NULL);
884
885#else
886 /*
887 * Now set the screen resolution and get the surface pointer
888 * @todo BPP is not supported!
889 */
890 mScreen = SDL_SetVideoMode(newWidth, newHeight, 0, sdlFlags);
891
892 /*
893 * Set the Window ID. Currently used for OpenGL accelerated guests.
894 */
895# if defined (RT_OS_WINDOWS)
896 SDL_SysWMinfo info;
897 SDL_VERSION(&info.version);
898 if (SDL_GetWMInfo(&info))
899 mWinId = (LONG64) info.window;
900# elif defined (RT_OS_LINUX)
901 SDL_SysWMinfo info;
902 SDL_VERSION(&info.version);
903 if (SDL_GetWMInfo(&info))
904 mWinId = (LONG64) info.info.x11.wmwindow;
905# else
906 /* XXX ignore this for other architectures */
907# endif
908#endif
909#ifdef VBOX_SECURELABEL
910 /*
911 * For non fixed SDL resolution, the above call tried to add the label height
912 * to the guest height. If it worked, we have an offset. If it didn't the below
913 * code will try again with the original guest resolution.
914 */
915 if (mFixedSDLWidth == ~(uint32_t)0)
916 {
917 /* if it didn't work, then we have to go for the original resolution and paint over the guest */
918 if (!mScreen)
919 {
920 mScreen = SDL_SetVideoMode(newWidth, newHeight - mLabelHeight, 0, sdlFlags);
921 }
922 else
923 {
924 /* we now have some extra space */
925 mTopOffset = mLabelHeight;
926 }
927 }
928 else
929 {
930 /* in case the guest resolution is small enough, we do have a top offset */
931 if (mFixedSDLHeight - mGuestYRes >= mLabelHeight)
932 mTopOffset = mLabelHeight;
933
934 /* we also might have to center the guest picture */
935 if (mFixedSDLWidth > mGuestXRes)
936 mCenterXOffset = (mFixedSDLWidth - mGuestXRes) / 2;
937 if (mFixedSDLHeight > mGuestYRes + mLabelHeight)
938 mCenterYOffset = (mFixedSDLHeight - (mGuestYRes + mLabelHeight)) / 2;
939 }
940#endif
941 AssertMsg(mScreen, ("Error: SDL_SetVideoMode failed!\n"));
942 if (mScreen)
943 {
944#ifdef VBOX_WIN32_UI
945 /* inform the UI code */
946 resizeUI(mScreen->w, mScreen->h);
947#endif
948 if (mfShowSDLConfig)
949 RTPrintf("Resized to %dx%d, screen surface type: %s\n", mScreen->w, mScreen->h,
950 ((mScreen->flags & SDL_HWSURFACE) == 0) ? "software" : "hardware");
951 }
952}
953
954/**
955 * Update specified framebuffer area. The coordinates can either be
956 * relative to the guest framebuffer or relative to the screen.
957 *
958 * @remarks Must be called from the SDL thread on Linux!
959 * @param x left column
960 * @param y top row
961 * @param w width in pixels
962 * @param h height in pixels
963 * @param fGuestRelative flag whether the above values are guest relative or screen relative;
964 */
965void VBoxSDLFB::update(int x, int y, int w, int h, bool fGuestRelative)
966{
967#ifdef VBOXSDL_WITH_X11
968 AssertMsg(gSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
969#endif
970 RTCritSectEnter(&mUpdateLock);
971 Log(("Updates %d, %d,%d %dx%d\n", mfUpdates, x, y, w, h));
972 if (!mfUpdates)
973 {
974 RTCritSectLeave(&mUpdateLock);
975 return;
976 }
977
978 Assert(mScreen);
979 Assert(mSurfVRAM);
980 if (!mScreen || !mSurfVRAM)
981 {
982 RTCritSectLeave(&mUpdateLock);
983 return;
984 }
985
986 /* the source and destination rectangles */
987 SDL_Rect srcRect;
988 SDL_Rect dstRect;
989
990 /* this is how many pixels we have to cut off from the height for this specific blit */
991 int yCutoffGuest = 0;
992
993#ifdef VBOX_SECURELABEL
994 bool fPaintLabel = false;
995 /* if we have a label and no space for it, we have to cut off a bit */
996 if (mLabelHeight && !mTopOffset)
997 {
998 if (y < (int)mLabelHeight)
999 yCutoffGuest = mLabelHeight - y;
1000 }
1001#endif
1002
1003 /**
1004 * If we get a SDL window relative update, we
1005 * just perform a full screen update to keep things simple.
1006 *
1007 * @todo improve
1008 */
1009 if (!fGuestRelative)
1010 {
1011#ifdef VBOX_SECURELABEL
1012 /* repaint the label if necessary */
1013 if (y < (int)mLabelHeight)
1014 fPaintLabel = true;
1015#endif
1016 x = 0;
1017 w = mGuestXRes;
1018 y = 0;
1019 h = mGuestYRes;
1020 }
1021
1022 srcRect.x = x;
1023 srcRect.y = y + yCutoffGuest;
1024 srcRect.w = w;
1025 srcRect.h = RT_MAX(0, h - yCutoffGuest);
1026
1027 /*
1028 * Destination rectangle is just offset by the label height.
1029 * There are two cases though: label height is added to the
1030 * guest resolution (mTopOffset == mLabelHeight; yCutoffGuest == 0)
1031 * or the label cuts off a portion of the guest screen (mTopOffset == 0;
1032 * yCutoffGuest >= 0)
1033 */
1034 dstRect.x = x + mCenterXOffset;
1035#ifdef VBOX_SECURELABEL
1036 dstRect.y = RT_MAX(mLabelHeight, y + yCutoffGuest + mTopOffset) + mCenterYOffset;
1037#else
1038 dstRect.y = y + yCutoffGuest + mTopOffset + mCenterYOffset;
1039#endif
1040 dstRect.w = w;
1041 dstRect.h = RT_MAX(0, h - yCutoffGuest);
1042
1043 /*
1044 * Now we just blit
1045 */
1046 SDL_BlitSurface(mSurfVRAM, &srcRect, mScreen, &dstRect);
1047 /* hardware surfaces don't need update notifications */
1048#if defined(VBOX_WITH_SDL13)
1049 AssertRelease(mScreen->flags & SDL_PREALLOC);
1050 SDL_SelectRenderer(mWindow);
1051 SDL_DirtyTexture(mTexture, 1, &dstRect);
1052 AssertRelease(mRenderInfo.flags & SDL_RENDERER_PRESENTCOPY);
1053 SDL_RenderCopy(mTexture, &dstRect, &dstRect);
1054 SDL_RenderPresent();
1055#else
1056 if ((mScreen->flags & SDL_HWSURFACE) == 0)
1057 SDL_UpdateRect(mScreen, dstRect.x, dstRect.y, dstRect.w, dstRect.h);
1058#endif
1059
1060#ifdef VBOX_SECURELABEL
1061 if (fPaintLabel)
1062 paintSecureLabel(0, 0, 0, 0, false);
1063#endif
1064 RTCritSectLeave(&mUpdateLock);
1065}
1066
1067/**
1068 * Repaint the whole framebuffer
1069 *
1070 * @remarks Must be called from the SDL thread!
1071 */
1072void VBoxSDLFB::repaint()
1073{
1074 AssertMsg(gSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
1075 LogFlow(("VBoxSDLFB::repaint\n"));
1076 update(0, 0, mScreen->w, mScreen->h, false /* fGuestRelative */);
1077}
1078
1079/**
1080 * Toggle fullscreen mode
1081 *
1082 * @remarks Must be called from the SDL thread!
1083 */
1084void VBoxSDLFB::setFullscreen(bool fFullscreen)
1085{
1086 AssertMsg(gSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
1087 LogFlow(("VBoxSDLFB::SetFullscreen: fullscreen: %d\n", fFullscreen));
1088 mfFullscreen = fFullscreen;
1089 /* only change the SDL resolution, do not touch the guest framebuffer */
1090 resizeSDL();
1091 repaint();
1092}
1093
1094/**
1095 * Return the geometry of the host. This isn't very well tested but it seems
1096 * to work at least on Linux hosts.
1097 */
1098void VBoxSDLFB::getFullscreenGeometry(uint32_t *width, uint32_t *height)
1099{
1100 SDL_Rect **modes;
1101
1102 /* Get available fullscreen/hardware modes */
1103 modes = SDL_ListModes(NULL, SDL_FULLSCREEN);
1104 Assert(modes != NULL);
1105 /* -1 means that any mode is possible (usually non fullscreen) */
1106 if (modes != (SDL_Rect **)-1)
1107 {
1108 /*
1109 * According to the SDL documentation, the API guarantees that the modes
1110 * are sorted from larger to smaller, so we just take the first entry as
1111 * the maximum.
1112 *
1113 * XXX Crude Xinerama hack :-/
1114 */
1115 if ( modes[0]->w > (16*modes[0]->h/9)
1116 && modes[1]
1117 && modes[1]->h == modes[0]->h)
1118 {
1119 *width = modes[1]->w;
1120 *height = modes[1]->h;
1121 }
1122 else
1123 {
1124 *width = modes[0]->w;
1125 *height = modes[0]->w;
1126 }
1127 }
1128}
1129
1130#ifdef VBOX_SECURELABEL
1131/**
1132 * Setup the secure labeling parameters
1133 *
1134 * @returns VBox status code
1135 * @param height height of the secure label area in pixels
1136 * @param font file path fo the TrueType font file
1137 * @param pointsize font size in points
1138 */
1139int VBoxSDLFB::initSecureLabel(uint32_t height, char *font, uint32_t pointsize, uint32_t labeloffs)
1140{
1141 LogFlow(("VBoxSDLFB:initSecureLabel: new offset: %d pixels, new font: %s, new pointsize: %d\n",
1142 height, font, pointsize));
1143 mLabelHeight = height;
1144 mLabelOffs = labeloffs;
1145 Assert(font);
1146 pTTF_Init();
1147 mLabelFont = pTTF_OpenFont(font, pointsize);
1148 if (!mLabelFont)
1149 {
1150 AssertMsgFailed(("Failed to open TTF font file %s\n", font));
1151 return VERR_OPEN_FAILED;
1152 }
1153 mSecureLabelColorFG = 0x0000FF00;
1154 mSecureLabelColorBG = 0x00FFFF00;
1155 repaint();
1156 return VINF_SUCCESS;
1157}
1158
1159/**
1160 * Set the secure label text and repaint the label
1161 *
1162 * @param text UTF-8 string of new label
1163 * @remarks must be called from the SDL thread!
1164 */
1165void VBoxSDLFB::setSecureLabelText(const char *text)
1166{
1167 mSecureLabelText = text;
1168 paintSecureLabel(0, 0, 0, 0, true);
1169}
1170
1171/**
1172 * Sets the secure label background color.
1173 *
1174 * @param colorFG encoded RGB value for text
1175 * @param colorBG encored RGB value for background
1176 * @remarks must be called from the SDL thread!
1177 */
1178void VBoxSDLFB::setSecureLabelColor(uint32_t colorFG, uint32_t colorBG)
1179{
1180 mSecureLabelColorFG = colorFG;
1181 mSecureLabelColorBG = colorBG;
1182 paintSecureLabel(0, 0, 0, 0, true);
1183}
1184
1185/**
1186 * Paint the secure label if required
1187 *
1188 * @param fForce Force the repaint
1189 * @remarks must be called from the SDL thread!
1190 */
1191void VBoxSDLFB::paintSecureLabel(int x, int y, int w, int h, bool fForce)
1192{
1193#ifdef VBOXSDL_WITH_X11
1194 AssertMsg(gSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
1195#endif
1196 /* only when the function is present */
1197 if (!pTTF_RenderUTF8_Solid)
1198 return;
1199 /* check if we can skip the paint */
1200 if (!fForce && ((uint32_t)y > mLabelHeight))
1201 {
1202 return;
1203 }
1204 /* first fill the background */
1205 SDL_Rect rect = {0, 0, (Uint16)mScreen->w, (Uint16)mLabelHeight};
1206 SDL_FillRect(mScreen, &rect, SDL_MapRGB(mScreen->format,
1207 (mSecureLabelColorBG & 0x00FF0000) >> 16, /* red */
1208 (mSecureLabelColorBG & 0x0000FF00) >> 8, /* green */
1209 mSecureLabelColorBG & 0x000000FF)); /* blue */
1210
1211 /* now the text */
1212 if ( mLabelFont != NULL
1213 && !mSecureLabelText.isEmpty()
1214 )
1215 {
1216 SDL_Color clrFg = {(uint8_t)((mSecureLabelColorFG & 0x00FF0000) >> 16),
1217 (uint8_t)((mSecureLabelColorFG & 0x0000FF00) >> 8),
1218 (uint8_t)( mSecureLabelColorFG & 0x000000FF ), 0};
1219 SDL_Surface *sText = (pTTF_RenderUTF8_Blended != NULL)
1220 ? pTTF_RenderUTF8_Blended(mLabelFont, mSecureLabelText.c_str(), clrFg)
1221 : pTTF_RenderUTF8_Solid(mLabelFont, mSecureLabelText.c_str(), clrFg);
1222 rect.x = 10;
1223 rect.y = mLabelOffs;
1224 SDL_BlitSurface(sText, NULL, mScreen, &rect);
1225 SDL_FreeSurface(sText);
1226 }
1227 /* make sure to update the screen */
1228 SDL_UpdateRect(mScreen, 0, 0, mScreen->w, mLabelHeight);
1229}
1230#endif /* VBOX_SECURELABEL */
1231
1232// IFramebufferOverlay
1233///////////////////////////////////////////////////////////////////////////////////
1234
1235/**
1236 * Constructor for the VBoxSDLFBOverlay class (IFramebufferOverlay implementation)
1237 *
1238 * @param x Initial X offset for the overlay
1239 * @param y Initial Y offset for the overlay
1240 * @param width Initial width for the overlay
1241 * @param height Initial height for the overlay
1242 * @param visible Whether the overlay is initially visible
1243 * @param alpha Initial alpha channel value for the overlay
1244 */
1245VBoxSDLFBOverlay::VBoxSDLFBOverlay(ULONG x, ULONG y, ULONG width, ULONG height,
1246 BOOL visible, VBoxSDLFB *aParent) :
1247 mOverlayX(x), mOverlayY(y), mOverlayWidth(width),
1248 mOverlayHeight(height), mOverlayVisible(visible),
1249 mParent(aParent)
1250{}
1251
1252/**
1253 * Destructor for the VBoxSDLFBOverlay class.
1254 */
1255VBoxSDLFBOverlay::~VBoxSDLFBOverlay()
1256{
1257 SDL_FreeSurface(mBlendedBits);
1258 SDL_FreeSurface(mOverlayBits);
1259}
1260
1261/**
1262 * Perform any initialisation of the overlay that can potentially fail
1263 *
1264 * @returns S_OK on success or the reason for the failure
1265 */
1266HRESULT VBoxSDLFBOverlay::init()
1267{
1268 mBlendedBits = SDL_CreateRGBSurface(SDL_ANYFORMAT, mOverlayWidth, mOverlayHeight, 32,
1269 0x00ff0000, 0x0000ff00, 0x000000ff, 0);
1270 AssertMsgReturn(mBlendedBits != NULL, ("Failed to create an SDL surface\n"),
1271 E_OUTOFMEMORY);
1272 mOverlayBits = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, mOverlayWidth,
1273 mOverlayHeight, 32, 0x00ff0000, 0x0000ff00,
1274 0x000000ff, 0xff000000);
1275 AssertMsgReturn(mOverlayBits != NULL, ("Failed to create an SDL surface\n"),
1276 E_OUTOFMEMORY);
1277 return S_OK;
1278}
1279
1280/**
1281 * Returns the current overlay X offset in pixels.
1282 *
1283 * @returns COM status code
1284 * @param x Address of result buffer.
1285 */
1286STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(X)(ULONG *x)
1287{
1288 LogFlow(("VBoxSDLFBOverlay::GetX\n"));
1289 if (!x)
1290 return E_INVALIDARG;
1291 *x = mOverlayX;
1292 return S_OK;
1293}
1294
1295/**
1296 * Returns the current overlay height in pixels.
1297 *
1298 * @returns COM status code
1299 * @param height Address of result buffer.
1300 */
1301STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Y)(ULONG *y)
1302{
1303 LogFlow(("VBoxSDLFBOverlay::GetY\n"));
1304 if (!y)
1305 return E_INVALIDARG;
1306 *y = mOverlayY;
1307 return S_OK;
1308}
1309
1310/**
1311 * Returns the current overlay width in pixels. In fact, this returns the line size.
1312 *
1313 * @returns COM status code
1314 * @param width Address of result buffer.
1315 */
1316STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Width)(ULONG *width)
1317{
1318 LogFlow(("VBoxSDLFBOverlay::GetWidth\n"));
1319 if (!width)
1320 return E_INVALIDARG;
1321 *width = mOverlayBits->pitch;
1322 return S_OK;
1323}
1324
1325/**
1326 * Returns the current overlay line size in pixels.
1327 *
1328 * @returns COM status code
1329 * @param lineSize Address of result buffer.
1330 */
1331STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(BytesPerLine)(ULONG *bytesPerLine)
1332{
1333 LogFlow(("VBoxSDLFBOverlay::GetBytesPerLine\n"));
1334 if (!bytesPerLine)
1335 return E_INVALIDARG;
1336 *bytesPerLine = mOverlayBits->pitch;
1337 return S_OK;
1338}
1339
1340/**
1341 * Returns the current overlay height in pixels.
1342 *
1343 * @returns COM status code
1344 * @param height Address of result buffer.
1345 */
1346STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Height)(ULONG *height)
1347{
1348 LogFlow(("VBoxSDLFBOverlay::GetHeight\n"));
1349 if (!height)
1350 return E_INVALIDARG;
1351 *height = mOverlayHeight;
1352 return S_OK;
1353}
1354
1355/**
1356 * Returns whether the overlay is currently visible.
1357 *
1358 * @returns COM status code
1359 * @param visible Address of result buffer.
1360 */
1361STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Visible)(BOOL *visible)
1362{
1363 LogFlow(("VBoxSDLFBOverlay::GetVisible\n"));
1364 if (!visible)
1365 return E_INVALIDARG;
1366 *visible = mOverlayVisible;
1367 return S_OK;
1368}
1369
1370/**
1371 * Sets whether the overlay is currently visible.
1372 *
1373 * @returns COM status code
1374 * @param visible New value.
1375 */
1376STDMETHODIMP VBoxSDLFBOverlay::COMSETTER(Visible)(BOOL visible)
1377{
1378 LogFlow(("VBoxSDLFBOverlay::SetVisible\n"));
1379 mOverlayVisible = visible;
1380 return S_OK;
1381}
1382
1383/**
1384 * Returns the value of the global alpha channel.
1385 *
1386 * @returns COM status code
1387 * @param alpha Address of result buffer.
1388 */
1389STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Alpha)(ULONG *alpha)
1390{
1391 LogFlow(("VBoxSDLFBOverlay::GetAlpha\n"));
1392 return E_NOTIMPL;
1393}
1394
1395/**
1396 * Sets whether the overlay is currently visible.
1397 *
1398 * @returns COM status code
1399 * @param alpha new value.
1400 */
1401STDMETHODIMP VBoxSDLFBOverlay::COMSETTER(Alpha)(ULONG alpha)
1402{
1403 LogFlow(("VBoxSDLFBOverlay::SetAlpha\n"));
1404 return E_NOTIMPL;
1405}
1406
1407/**
1408 * Returns the address of the framebuffer bits for writing to.
1409 *
1410 * @returns COM status code
1411 * @param alpha Address of result buffer.
1412 */
1413STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Address)(ULONG *address)
1414{
1415 LogFlow(("VBoxSDLFBOverlay::GetAddress\n"));
1416 if (!address)
1417 return E_INVALIDARG;
1418 *address = (uintptr_t) mOverlayBits->pixels;
1419 return S_OK;
1420}
1421
1422/**
1423 * Returns the current colour depth. In fact, this is always 32bpp.
1424 *
1425 * @returns COM status code
1426 * @param bitsPerPixel Address of result buffer.
1427 */
1428STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(BitsPerPixel)(ULONG *bitsPerPixel)
1429{
1430 LogFlow(("VBoxSDLFBOverlay::GetBitsPerPixel\n"));
1431 if (!bitsPerPixel)
1432 return E_INVALIDARG;
1433 *bitsPerPixel = 32;
1434 return S_OK;
1435}
1436
1437/**
1438 * Returns the current pixel format. In fact, this is always RGB.
1439 *
1440 * @returns COM status code
1441 * @param pixelFormat Address of result buffer.
1442 */
1443STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(PixelFormat)(ULONG *pixelFormat)
1444{
1445 LogFlow(("VBoxSDLFBOverlay::GetPixelFormat\n"));
1446 if (!pixelFormat)
1447 return E_INVALIDARG;
1448 *pixelFormat = FramebufferPixelFormat_FOURCC_RGB;
1449 return S_OK;
1450}
1451
1452/**
1453 * Returns whether the guest VRAM is used directly. In fact, this is always FALSE.
1454 *
1455 * @returns COM status code
1456 * @param usesGuestVRAM Address of result buffer.
1457 */
1458STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(UsesGuestVRAM)(BOOL *usesGuestVRAM)
1459{
1460 LogFlow(("VBoxSDLFBOverlay::GetUsesGuestVRAM\n"));
1461 if (!usesGuestVRAM)
1462 return E_INVALIDARG;
1463 *usesGuestVRAM = FALSE;
1464 return S_OK;
1465}
1466
1467/**
1468 * Returns the height reduction. In fact, this is always 0.
1469 *
1470 * @returns COM status code
1471 * @param heightReduction Address of result buffer.
1472 */
1473STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(HeightReduction)(ULONG *heightReduction)
1474{
1475 LogFlow(("VBoxSDLFBOverlay::GetHeightReduction\n"));
1476 if (!heightReduction)
1477 return E_INVALIDARG;
1478 *heightReduction = 0;
1479 return S_OK;
1480}
1481
1482/**
1483 * Returns the overlay for this framebuffer. Obviously, we return NULL here.
1484 *
1485 * @returns COM status code
1486 * @param overlay Address of result buffer.
1487 */
1488STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Overlay)(IFramebufferOverlay **aOverlay)
1489{
1490 LogFlow(("VBoxSDLFBOverlay::GetOverlay\n"));
1491 if (!aOverlay)
1492 return E_INVALIDARG;
1493 *aOverlay = 0;
1494 return S_OK;
1495}
1496
1497/**
1498 * Returns associated window handle. We return NULL here.
1499 *
1500 * @returns COM status code
1501 * @param winId Address of result buffer.
1502 */
1503STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(WinId)(LONG64 *winId)
1504{
1505 LogFlow(("VBoxSDLFBOverlay::GetWinId\n"));
1506 if (!winId)
1507 return E_INVALIDARG;
1508 *winId = 0;
1509 return S_OK;
1510}
1511
1512
1513/**
1514 * Lock the overlay. This should not be used - lock the parent IFramebuffer instead.
1515 *
1516 * @returns COM status code
1517 */
1518STDMETHODIMP VBoxSDLFBOverlay::Lock()
1519{
1520 LogFlow(("VBoxSDLFBOverlay::Lock\n"));
1521 AssertMsgFailed(("You should not attempt to lock an IFramebufferOverlay object -\n"
1522 "lock the parent IFramebuffer object instead.\n"));
1523 return E_NOTIMPL;
1524}
1525
1526/**
1527 * Unlock the overlay.
1528 *
1529 * @returns COM status code
1530 */
1531STDMETHODIMP VBoxSDLFBOverlay::Unlock()
1532{
1533 LogFlow(("VBoxSDLFBOverlay::Unlock\n"));
1534 AssertMsgFailed(("You should not attempt to lock an IFramebufferOverlay object -\n"
1535 "lock the parent IFramebuffer object instead.\n"));
1536 return E_NOTIMPL;
1537}
1538
1539/**
1540 * Change the X and Y co-ordinates of the overlay area.
1541 *
1542 * @returns COM status code
1543 * @param x New X co-ordinate.
1544 * @param y New Y co-ordinate.
1545 */
1546STDMETHODIMP VBoxSDLFBOverlay::Move(ULONG x, ULONG y)
1547{
1548 mOverlayX = x;
1549 mOverlayY = y;
1550 return S_OK;
1551}
1552
1553/**
1554 * Notify the overlay that a section of the framebuffer has been redrawn.
1555 *
1556 * @returns COM status code
1557 * @param x X co-ordinate of upper left corner of modified area.
1558 * @param y Y co-ordinate of upper left corner of modified area.
1559 * @param w Width of modified area.
1560 * @param h Height of modified area.
1561 * @retval finished Set if the operation has completed.
1562 *
1563 * All we do here is to send a request to the parent to update the affected area,
1564 * translating between our co-ordinate system and the parent's. It would be have
1565 * been better to call the parent directly, but such is life. We leave bounds
1566 * checking to the parent.
1567 */
1568STDMETHODIMP VBoxSDLFBOverlay::NotifyUpdate(ULONG x, ULONG y,
1569 ULONG w, ULONG h)
1570{
1571 return mParent->NotifyUpdate(x + mOverlayX, y + mOverlayY, w, h);
1572}
1573
1574/**
1575 * Change the dimensions of the overlay.
1576 *
1577 * @returns COM status code
1578 * @param pixelFormat Must be FramebufferPixelFormat_PixelFormatRGB32.
1579 * @param vram Must be NULL.
1580 * @param lineSize Ignored.
1581 * @param w New overlay width.
1582 * @param h New overlay height.
1583 * @retval finished Set if the operation has completed.
1584 */
1585STDMETHODIMP VBoxSDLFBOverlay::RequestResize(ULONG aScreenId, ULONG pixelFormat, ULONG vram,
1586 ULONG bitsPerPixel, ULONG bytesPerLine,
1587 ULONG w, ULONG h, BOOL *finished)
1588{
1589 AssertReturn(pixelFormat == FramebufferPixelFormat_FOURCC_RGB, E_INVALIDARG);
1590 AssertReturn(vram == 0, E_INVALIDARG);
1591 AssertReturn(bitsPerPixel == 32, E_INVALIDARG);
1592 mOverlayWidth = w;
1593 mOverlayHeight = h;
1594 SDL_FreeSurface(mOverlayBits);
1595 mBlendedBits = SDL_CreateRGBSurface(SDL_ANYFORMAT, mOverlayWidth, mOverlayHeight, 32,
1596 0x00ff0000, 0x0000ff00, 0x000000ff, 0);
1597 AssertMsgReturn(mBlendedBits != NULL, ("Failed to create an SDL surface\n"),
1598 E_OUTOFMEMORY);
1599 mOverlayBits = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, mOverlayWidth,
1600 mOverlayHeight, 32, 0x00ff0000, 0x0000ff00,
1601 0x000000ff, 0xff000000);
1602 AssertMsgReturn(mOverlayBits != NULL, ("Failed to create an SDL surface\n"),
1603 E_OUTOFMEMORY);
1604 return S_OK;
1605}
1606
1607/**
1608 * Returns whether we like the given video mode.
1609 *
1610 * @returns COM status code
1611 * @param width video mode width in pixels
1612 * @param height video mode height in pixels
1613 * @param bpp video mode bit depth in bits per pixel
1614 * @retval supported pointer to result variable
1615 *
1616 * Basically, we support anything with 32bpp.
1617 */
1618STDMETHODIMP VBoxSDLFBOverlay::VideoModeSupported(ULONG width, ULONG height, ULONG bpp,
1619 BOOL *supported)
1620{
1621 if (!supported)
1622 return E_POINTER;
1623 if (bpp == 32)
1624 *supported = true;
1625 else
1626 *supported = false;
1627 return S_OK;
1628}
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