VirtualBox

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

Last change on this file since 55401 was 55401, checked in by vboxsync, 9 years ago

added a couple of missing Id headers

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