VirtualBox

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

Last change on this file since 55810 was 55810, checked in by vboxsync, 10 years ago

VBoxSDL: Made it build again on darwin, added hack for playing with OpenGL.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 47.7 KB
Line 
1/* $Id: Framebuffer.cpp 55810 2015-05-11 20:27:08Z 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)(LONG64 *winId)
390{
391 if (!winId)
392 return E_POINTER;
393#ifdef RT_OS_DARWIN
394 if (mWinId == NULL) /* (In case it failed the first time.) */
395 mWinId = (intptr_t)VBoxSDLGetDarwinWindowId();
396#endif
397 *winId = mWinId;
398 return S_OK;
399}
400
401STDMETHODIMP VBoxSDLFB::COMGETTER(Capabilities)(ComSafeArrayOut(FramebufferCapabilities_T, aCapabilities))
402{
403 if (ComSafeArrayOutIsNull(aCapabilities))
404 return E_POINTER;
405
406 com::SafeArray<FramebufferCapabilities_T> caps;
407
408 if (mfUpdateImage)
409 {
410 caps.resize(1);
411 caps[0] = FramebufferCapabilities_UpdateImage;
412 }
413 else
414 {
415 /* No caps to return. */
416 }
417
418 caps.detachTo(ComSafeArrayOutArg(aCapabilities));
419 return S_OK;
420}
421
422/**
423 * Notify framebuffer of an update.
424 *
425 * @returns COM status code
426 * @param x Update region upper left corner x value.
427 * @param y Update region upper left corner y value.
428 * @param w Update region width in pixels.
429 * @param h Update region height in pixels.
430 * @param finished Address of output flag whether the update
431 * could be fully processed in this call (which
432 * has to return immediately) or VBox should wait
433 * for a call to the update complete API before
434 * continuing with display updates.
435 */
436STDMETHODIMP VBoxSDLFB::NotifyUpdate(ULONG x, ULONG y,
437 ULONG w, ULONG h)
438{
439 /*
440 * The input values are in guest screen coordinates.
441 */
442 LogFlow(("VBoxSDLFB::NotifyUpdate: x = %d, y = %d, w = %d, h = %d\n",
443 x, y, w, h));
444
445#ifdef VBOXSDL_WITH_X11
446 /*
447 * SDL does not allow us to make this call from any other thread than
448 * the main SDL thread (which initialized the video mode). So we have
449 * to send an event to the main SDL thread and process it there. For
450 * sake of simplicity, we encode all information in the event parameters.
451 */
452 SDL_Event event;
453 event.type = SDL_USEREVENT;
454 event.user.code = mScreenId;
455 event.user.type = SDL_USER_EVENT_UPDATERECT;
456 // 16 bit is enough for coordinates
457 event.user.data1 = (void*)(uintptr_t)(x << 16 | y);
458 event.user.data2 = (void*)(uintptr_t)(w << 16 | h);
459 PushNotifyUpdateEvent(&event);
460#else /* !VBOXSDL_WITH_X11 */
461 update(x, y, w, h, true /* fGuestRelative */);
462#endif /* !VBOXSDL_WITH_X11 */
463
464 return S_OK;
465}
466
467STDMETHODIMP VBoxSDLFB::NotifyUpdateImage(ULONG aX,
468 ULONG aY,
469 ULONG aWidth,
470 ULONG aHeight,
471 ComSafeArrayIn(BYTE, aImage))
472{
473 LogFlow(("NotifyUpdateImage: %d,%d %dx%d\n", aX, aY, aWidth, aHeight));
474
475 com::SafeArray<BYTE> image(ComSafeArrayInArg(aImage));
476
477 /* Copy to mSurfVRAM. */
478 SDL_Rect srcRect;
479 SDL_Rect dstRect;
480 srcRect.x = 0;
481 srcRect.y = 0;
482 srcRect.w = (uint16_t)aWidth;
483 srcRect.h = (uint16_t)aHeight;
484 dstRect.x = (int16_t)aX;
485 dstRect.y = (int16_t)aY;
486 dstRect.w = (uint16_t)aWidth;
487 dstRect.h = (uint16_t)aHeight;
488
489 const uint32_t Rmask = 0x00FF0000, Gmask = 0x0000FF00, Bmask = 0x000000FF, Amask = 0;
490 SDL_Surface *surfSrc = SDL_CreateRGBSurfaceFrom(image.raw(), aWidth, aHeight, 32, aWidth * 4,
491 Rmask, Gmask, Bmask, Amask);
492 if (surfSrc)
493 {
494 RTCritSectEnter(&mUpdateLock);
495 if (mfUpdates)
496 SDL_BlitSurface(surfSrc, &srcRect, mSurfVRAM, &dstRect);
497 RTCritSectLeave(&mUpdateLock);
498
499 SDL_FreeSurface(surfSrc);
500 }
501
502 return NotifyUpdate(aX, aY, aWidth, aHeight);
503}
504
505extern ComPtr<IDisplay> gpDisplay;
506
507STDMETHODIMP VBoxSDLFB::NotifyChange(ULONG aScreenId,
508 ULONG aXOrigin,
509 ULONG aYOrigin,
510 ULONG aWidth,
511 ULONG aHeight)
512{
513 LogRel(("NotifyChange: %d %d,%d %dx%d\n",
514 aScreenId, aXOrigin, aYOrigin, aWidth, aHeight));
515
516 ComPtr<IDisplaySourceBitmap> pSourceBitmap;
517 if (!mfUpdateImage)
518 gpDisplay->QuerySourceBitmap(aScreenId, pSourceBitmap.asOutParam());
519
520 RTCritSectEnter(&mUpdateLock);
521
522 /* Disable screen updates. */
523 mfUpdates = false;
524
525 if (mfUpdateImage)
526 {
527 mGuestXRes = aWidth;
528 mGuestYRes = aHeight;
529 mPtrVRAM = NULL;
530 mBitsPerPixel = 0;
531 mBytesPerLine = 0;
532 }
533 else
534 {
535 /* Save the new bitmap. */
536 mpPendingSourceBitmap = pSourceBitmap;
537 }
538
539 RTCritSectLeave(&mUpdateLock);
540
541 SDL_Event event;
542 event.type = SDL_USEREVENT;
543 event.user.type = SDL_USER_EVENT_NOTIFYCHANGE;
544 event.user.code = mScreenId;
545
546 PushSDLEventForSure(&event);
547
548 RTThreadYield();
549
550 return S_OK;
551}
552
553/**
554 * Returns whether we like the given video mode.
555 *
556 * @returns COM status code
557 * @param width video mode width in pixels
558 * @param height video mode height in pixels
559 * @param bpp video mode bit depth in bits per pixel
560 * @param supported pointer to result variable
561 */
562STDMETHODIMP VBoxSDLFB::VideoModeSupported(ULONG width, ULONG height, ULONG bpp, BOOL *supported)
563{
564 if (!supported)
565 return E_POINTER;
566
567 /* are constraints set? */
568 if ( ( (mMaxScreenWidth != ~(uint32_t)0)
569 && (width > mMaxScreenWidth))
570 || ( (mMaxScreenHeight != ~(uint32_t)0)
571 && (height > mMaxScreenHeight)))
572 {
573 /* nope, we don't want that (but still don't freak out if it is set) */
574#ifdef DEBUG
575 printf("VBoxSDL::VideoModeSupported: we refused mode %dx%dx%d\n", width, height, bpp);
576#endif
577 *supported = false;
578 }
579 else
580 {
581 /* anything will do */
582 *supported = true;
583 }
584 return S_OK;
585}
586
587STDMETHODIMP VBoxSDLFB::GetVisibleRegion(BYTE *aRectangles, ULONG aCount,
588 ULONG *aCountCopied)
589{
590 PRTRECT rects = (PRTRECT)aRectangles;
591
592 if (!rects)
593 return E_POINTER;
594
595 /// @todo
596
597 NOREF(aCount);
598 NOREF(aCountCopied);
599
600 return S_OK;
601}
602
603STDMETHODIMP VBoxSDLFB::SetVisibleRegion(BYTE *aRectangles, ULONG aCount)
604{
605 PRTRECT rects = (PRTRECT)aRectangles;
606
607 if (!rects)
608 return E_POINTER;
609
610 /// @todo
611
612 NOREF(aCount);
613
614 return S_OK;
615}
616
617STDMETHODIMP VBoxSDLFB::ProcessVHWACommand(BYTE *pCommand)
618{
619 return E_NOTIMPL;
620}
621
622STDMETHODIMP VBoxSDLFB::Notify3DEvent(ULONG uType, ComSafeArrayIn(BYTE, aData))
623{
624 return E_NOTIMPL;
625}
626
627//
628// Internal public methods
629//
630
631/* This method runs on the main SDL thread. */
632void VBoxSDLFB::notifyChange(ULONG aScreenId)
633{
634 /* Disable screen updates. */
635 RTCritSectEnter(&mUpdateLock);
636
637 if (!mfUpdateImage && mpPendingSourceBitmap.isNull())
638 {
639 /* Do nothing. Change event already processed. */
640 RTCritSectLeave(&mUpdateLock);
641 return;
642 }
643
644 /* Release the current bitmap and keep the pending one. */
645 mpSourceBitmap = mpPendingSourceBitmap;
646 mpPendingSourceBitmap.setNull();
647
648 RTCritSectLeave(&mUpdateLock);
649
650 if (mpSourceBitmap.isNull())
651 {
652 mPtrVRAM = NULL;
653 mBitsPerPixel = 32;
654 mBytesPerLine = mGuestXRes * 4;
655 }
656 else
657 {
658 BYTE *pAddress = NULL;
659 ULONG ulWidth = 0;
660 ULONG ulHeight = 0;
661 ULONG ulBitsPerPixel = 0;
662 ULONG ulBytesPerLine = 0;
663 BitmapFormat_T bitmapFormat = BitmapFormat_Opaque;
664
665 mpSourceBitmap->QueryBitmapInfo(&pAddress,
666 &ulWidth,
667 &ulHeight,
668 &ulBitsPerPixel,
669 &ulBytesPerLine,
670 &bitmapFormat);
671
672 if ( mGuestXRes == ulWidth
673 && mGuestYRes == ulHeight
674 && mBitsPerPixel == ulBitsPerPixel
675 && mBytesPerLine == ulBytesPerLine
676 && mPtrVRAM == pAddress
677 )
678 {
679 mfSameSizeRequested = true;
680 }
681 else
682 {
683 mfSameSizeRequested = false;
684 }
685
686 mGuestXRes = ulWidth;
687 mGuestYRes = ulHeight;
688 mPtrVRAM = pAddress;
689 mBitsPerPixel = ulBitsPerPixel;
690 mBytesPerLine = ulBytesPerLine;
691 }
692
693 resizeGuest();
694
695 gpDisplay->InvalidateAndUpdateScreen(aScreenId);
696}
697
698/**
699 * Method that does the actual resize of the guest framebuffer and
700 * then changes the SDL framebuffer setup.
701 */
702void VBoxSDLFB::resizeGuest()
703{
704 LogFlowFunc (("mGuestXRes: %d, mGuestYRes: %d\n", mGuestXRes, mGuestYRes));
705 AssertMsg(gSdlNativeThread == RTThreadNativeSelf(),
706 ("Wrong thread! SDL is not threadsafe!\n"));
707
708 RTCritSectEnter(&mUpdateLock);
709
710 const uint32_t Rmask = 0x00FF0000, Gmask = 0x0000FF00, Bmask = 0x000000FF, Amask = 0;
711
712 /* first free the current surface */
713 if (mSurfVRAM)
714 {
715 SDL_FreeSurface(mSurfVRAM);
716 mSurfVRAM = NULL;
717 }
718
719 if (mPtrVRAM)
720 {
721 /* Create a source surface from the source bitmap. */
722 mSurfVRAM = SDL_CreateRGBSurfaceFrom(mPtrVRAM, mGuestXRes, mGuestYRes, mBitsPerPixel,
723 mBytesPerLine, Rmask, Gmask, Bmask, Amask);
724 LogFlow(("VBoxSDL:: using the source bitmap\n"));
725 }
726 else
727 {
728 mSurfVRAM = SDL_CreateRGBSurface(SDL_SWSURFACE, mGuestXRes, mGuestYRes, mBitsPerPixel,
729 Rmask, Gmask, Bmask, Amask);
730 LogFlow(("VBoxSDL:: using SDL_SWSURFACE\n"));
731 }
732 LogFlow(("VBoxSDL:: created VRAM surface %p\n", mSurfVRAM));
733
734 if (mfSameSizeRequested)
735 {
736 mfSameSizeRequested = false;
737 LogFlow(("VBoxSDL:: the same resolution requested, skipping the resize.\n"));
738 }
739 else
740 {
741 /* now adjust the SDL resolution */
742 resizeSDL();
743 }
744
745 /* Enable screen updates. */
746 mfUpdates = true;
747
748 RTCritSectLeave(&mUpdateLock);
749
750 repaint();
751}
752
753/**
754 * Sets SDL video mode. This is independent from guest video
755 * mode changes.
756 *
757 * @remarks Must be called from the SDL thread!
758 */
759void VBoxSDLFB::resizeSDL(void)
760{
761 LogFlow(("VBoxSDL:resizeSDL\n"));
762
763 /*
764 * We request a hardware surface from SDL so that we can perform
765 * accelerated system memory to VRAM blits. The way video handling
766 * works it that on the one hand we have the screen surface from SDL
767 * and on the other hand we have a software surface that we create
768 * using guest VRAM memory for linear modes and using SDL allocated
769 * system memory for text and non linear graphics modes. We never
770 * directly write to the screen surface but always use SDL blitting
771 * functions to blit from our system memory surface to the VRAM.
772 * Therefore, SDL can take advantage of hardware acceleration.
773 */
774 int sdlFlags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL;
775#ifndef RT_OS_OS2 /* doesn't seem to work for some reason... */
776 if (mfResizable)
777 sdlFlags |= SDL_RESIZABLE;
778#endif
779 if (mfFullscreen)
780 sdlFlags |= SDL_FULLSCREEN;
781
782 /*
783 * Now we have to check whether there are video mode restrictions
784 */
785 SDL_Rect **modes;
786 /* Get available fullscreen/hardware modes */
787 modes = SDL_ListModes(NULL, sdlFlags);
788 Assert(modes != NULL);
789 /* -1 means that any mode is possible (usually non fullscreen) */
790 if (modes != (SDL_Rect **)-1)
791 {
792 /*
793 * according to the SDL documentation, the API guarantees that
794 * the modes are sorted from larger to smaller, so we just
795 * take the first entry as the maximum.
796 */
797 mMaxScreenWidth = modes[0]->w;
798 mMaxScreenHeight = modes[0]->h;
799 }
800 else
801 {
802 /* no restriction */
803 mMaxScreenWidth = ~(uint32_t)0;
804 mMaxScreenHeight = ~(uint32_t)0;
805 }
806
807 uint32_t newWidth;
808 uint32_t newHeight;
809
810 /* reset the centering offsets */
811 mCenterXOffset = 0;
812 mCenterYOffset = 0;
813
814 /* we either have a fixed SDL resolution or we take the guest's */
815 if (mFixedSDLWidth != ~(uint32_t)0)
816 {
817 newWidth = mFixedSDLWidth;
818 newHeight = mFixedSDLHeight;
819 }
820 else
821 {
822 newWidth = RT_MIN(mGuestXRes, mMaxScreenWidth);
823#ifdef VBOX_SECURELABEL
824 newHeight = RT_MIN(mGuestYRes + mLabelHeight, mMaxScreenHeight);
825#else
826 newHeight = RT_MIN(mGuestYRes, mMaxScreenHeight);
827#endif
828 }
829
830 /* we don't have any extra space by default */
831 mTopOffset = 0;
832
833#if defined(VBOX_WITH_SDL13)
834 int sdlWindowFlags = SDL_WINDOW_SHOWN;
835 if (mfResizable)
836 sdlWindowFlags |= SDL_WINDOW_RESIZABLE;
837 if (!mWindow)
838 {
839 SDL_DisplayMode desktop_mode;
840 int x = 40 + mScreenId * 20;
841 int y = 40 + mScreenId * 15;
842
843 SDL_GetDesktopDisplayMode(&desktop_mode);
844 /* create new window */
845
846 char szTitle[64];
847 RTStrPrintf(szTitle, sizeof(szTitle), "SDL window %d", mScreenId);
848 mWindow = SDL_CreateWindow(szTitle, x, y,
849 newWidth, newHeight, sdlWindowFlags);
850 if (SDL_CreateRenderer(mWindow, -1,
851 SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTDISCARD) < 0)
852 AssertReleaseFailed();
853
854 SDL_GetRendererInfo(&mRenderInfo);
855
856 mTexture = SDL_CreateTexture(desktop_mode.format,
857 SDL_TEXTUREACCESS_STREAMING, newWidth, newHeight);
858 if (!mTexture)
859 AssertReleaseFailed();
860 }
861 else
862 {
863 int w, h;
864 uint32_t format;
865 int access;
866
867 /* resize current window */
868 SDL_GetWindowSize(mWindow, &w, &h);
869
870 if (w != (int)newWidth || h != (int)newHeight)
871 SDL_SetWindowSize(mWindow, newWidth, newHeight);
872
873 SDL_QueryTexture(mTexture, &format, &access, &w, &h);
874 SDL_SelectRenderer(mWindow);
875 SDL_DestroyTexture(mTexture);
876 mTexture = SDL_CreateTexture(format, access, newWidth, newHeight);
877 if (!mTexture)
878 AssertReleaseFailed();
879 }
880
881 void *pixels;
882 int pitch;
883 int w, h, bpp;
884 uint32_t Rmask, Gmask, Bmask, Amask;
885 uint32_t format;
886
887 if (SDL_QueryTexture(mTexture, &format, NULL, &w, &h) < 0)
888 AssertReleaseFailed();
889
890 if (!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask))
891 AssertReleaseFailed();
892
893 if (SDL_QueryTexturePixels(mTexture, &pixels, &pitch) == 0)
894 {
895 mScreen = SDL_CreateRGBSurfaceFrom(pixels, w, h, bpp, pitch,
896 Rmask, Gmask, Bmask, Amask);
897 }
898 else
899 {
900 mScreen = SDL_CreateRGBSurface(0, w, h, bpp, Rmask, Gmask, Bmask, Amask);
901 AssertReleaseFailed();
902 }
903
904 SDL_SetClipRect(mScreen, NULL);
905
906#else
907 /*
908 * Now set the screen resolution and get the surface pointer
909 * @todo BPP is not supported!
910 */
911 mScreen = SDL_SetVideoMode(newWidth, newHeight, 0, sdlFlags);
912
913 /*
914 * Set the Window ID. Currently used for OpenGL accelerated guests.
915 */
916# if defined (RT_OS_WINDOWS)
917 SDL_SysWMinfo info;
918 SDL_VERSION(&info.version);
919 if (SDL_GetWMInfo(&info))
920 mWinId = (LONG64) info.window;
921# elif defined (RT_OS_LINUX)
922 SDL_SysWMinfo info;
923 SDL_VERSION(&info.version);
924 if (SDL_GetWMInfo(&info))
925 mWinId = (LONG64) info.info.x11.wmwindow;
926# elif defined(RT_OS_DARWIN)
927 mWinId = (intptr_t)VBoxSDLGetDarwinWindowId();
928# else
929 /* XXX ignore this for other architectures */
930# endif
931#endif
932#ifdef VBOX_SECURELABEL
933 /*
934 * For non fixed SDL resolution, the above call tried to add the label height
935 * to the guest height. If it worked, we have an offset. If it didn't the below
936 * code will try again with the original guest resolution.
937 */
938 if (mFixedSDLWidth == ~(uint32_t)0)
939 {
940 /* if it didn't work, then we have to go for the original resolution and paint over the guest */
941 if (!mScreen)
942 {
943 mScreen = SDL_SetVideoMode(newWidth, newHeight - mLabelHeight, 0, sdlFlags);
944 }
945 else
946 {
947 /* we now have some extra space */
948 mTopOffset = mLabelHeight;
949 }
950 }
951 else
952 {
953 /* in case the guest resolution is small enough, we do have a top offset */
954 if (mFixedSDLHeight - mGuestYRes >= mLabelHeight)
955 mTopOffset = mLabelHeight;
956
957 /* we also might have to center the guest picture */
958 if (mFixedSDLWidth > mGuestXRes)
959 mCenterXOffset = (mFixedSDLWidth - mGuestXRes) / 2;
960 if (mFixedSDLHeight > mGuestYRes + mLabelHeight)
961 mCenterYOffset = (mFixedSDLHeight - (mGuestYRes + mLabelHeight)) / 2;
962 }
963#endif
964 AssertMsg(mScreen, ("Error: SDL_SetVideoMode failed!\n"));
965 if (mScreen)
966 {
967#ifdef VBOX_WIN32_UI
968 /* inform the UI code */
969 resizeUI(mScreen->w, mScreen->h);
970#endif
971 if (mfShowSDLConfig)
972 RTPrintf("Resized to %dx%d, screen surface type: %s\n", mScreen->w, mScreen->h,
973 ((mScreen->flags & SDL_HWSURFACE) == 0) ? "software" : "hardware");
974 }
975}
976
977/**
978 * Update specified framebuffer area. The coordinates can either be
979 * relative to the guest framebuffer or relative to the screen.
980 *
981 * @remarks Must be called from the SDL thread on Linux!
982 * @param x left column
983 * @param y top row
984 * @param w width in pixels
985 * @param h height in pixels
986 * @param fGuestRelative flag whether the above values are guest relative or screen relative;
987 */
988void VBoxSDLFB::update(int x, int y, int w, int h, bool fGuestRelative)
989{
990#ifdef VBOXSDL_WITH_X11
991 AssertMsg(gSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
992#endif
993 RTCritSectEnter(&mUpdateLock);
994 Log(("Updates %d, %d,%d %dx%d\n", mfUpdates, x, y, w, h));
995 if (!mfUpdates)
996 {
997 RTCritSectLeave(&mUpdateLock);
998 return;
999 }
1000
1001 Assert(mScreen);
1002 Assert(mSurfVRAM);
1003 if (!mScreen || !mSurfVRAM)
1004 {
1005 RTCritSectLeave(&mUpdateLock);
1006 return;
1007 }
1008
1009 /* the source and destination rectangles */
1010 SDL_Rect srcRect;
1011 SDL_Rect dstRect;
1012
1013 /* this is how many pixels we have to cut off from the height for this specific blit */
1014 int yCutoffGuest = 0;
1015
1016#ifdef VBOX_SECURELABEL
1017 bool fPaintLabel = false;
1018 /* if we have a label and no space for it, we have to cut off a bit */
1019 if (mLabelHeight && !mTopOffset)
1020 {
1021 if (y < (int)mLabelHeight)
1022 yCutoffGuest = mLabelHeight - y;
1023 }
1024#endif
1025
1026 /**
1027 * If we get a SDL window relative update, we
1028 * just perform a full screen update to keep things simple.
1029 *
1030 * @todo improve
1031 */
1032 if (!fGuestRelative)
1033 {
1034#ifdef VBOX_SECURELABEL
1035 /* repaint the label if necessary */
1036 if (y < (int)mLabelHeight)
1037 fPaintLabel = true;
1038#endif
1039 x = 0;
1040 w = mGuestXRes;
1041 y = 0;
1042 h = mGuestYRes;
1043 }
1044
1045 srcRect.x = x;
1046 srcRect.y = y + yCutoffGuest;
1047 srcRect.w = w;
1048 srcRect.h = RT_MAX(0, h - yCutoffGuest);
1049
1050 /*
1051 * Destination rectangle is just offset by the label height.
1052 * There are two cases though: label height is added to the
1053 * guest resolution (mTopOffset == mLabelHeight; yCutoffGuest == 0)
1054 * or the label cuts off a portion of the guest screen (mTopOffset == 0;
1055 * yCutoffGuest >= 0)
1056 */
1057 dstRect.x = x + mCenterXOffset;
1058#ifdef VBOX_SECURELABEL
1059 dstRect.y = RT_MAX(mLabelHeight, y + yCutoffGuest + mTopOffset) + mCenterYOffset;
1060#else
1061 dstRect.y = y + yCutoffGuest + mTopOffset + mCenterYOffset;
1062#endif
1063 dstRect.w = w;
1064 dstRect.h = RT_MAX(0, h - yCutoffGuest);
1065
1066 /*
1067 * Now we just blit
1068 */
1069 SDL_BlitSurface(mSurfVRAM, &srcRect, mScreen, &dstRect);
1070 /* hardware surfaces don't need update notifications */
1071#if defined(VBOX_WITH_SDL13)
1072 AssertRelease(mScreen->flags & SDL_PREALLOC);
1073 SDL_SelectRenderer(mWindow);
1074 SDL_DirtyTexture(mTexture, 1, &dstRect);
1075 AssertRelease(mRenderInfo.flags & SDL_RENDERER_PRESENTCOPY);
1076 SDL_RenderCopy(mTexture, &dstRect, &dstRect);
1077 SDL_RenderPresent();
1078#else
1079 if ((mScreen->flags & SDL_HWSURFACE) == 0)
1080 SDL_UpdateRect(mScreen, dstRect.x, dstRect.y, dstRect.w, dstRect.h);
1081#endif
1082
1083#ifdef VBOX_SECURELABEL
1084 if (fPaintLabel)
1085 paintSecureLabel(0, 0, 0, 0, false);
1086#endif
1087 RTCritSectLeave(&mUpdateLock);
1088}
1089
1090/**
1091 * Repaint the whole framebuffer
1092 *
1093 * @remarks Must be called from the SDL thread!
1094 */
1095void VBoxSDLFB::repaint()
1096{
1097 AssertMsg(gSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
1098 LogFlow(("VBoxSDLFB::repaint\n"));
1099 update(0, 0, mScreen->w, mScreen->h, false /* fGuestRelative */);
1100}
1101
1102/**
1103 * Toggle fullscreen mode
1104 *
1105 * @remarks Must be called from the SDL thread!
1106 */
1107void VBoxSDLFB::setFullscreen(bool fFullscreen)
1108{
1109 AssertMsg(gSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
1110 LogFlow(("VBoxSDLFB::SetFullscreen: fullscreen: %d\n", fFullscreen));
1111 mfFullscreen = fFullscreen;
1112 /* only change the SDL resolution, do not touch the guest framebuffer */
1113 resizeSDL();
1114 repaint();
1115}
1116
1117/**
1118 * Return the geometry of the host. This isn't very well tested but it seems
1119 * to work at least on Linux hosts.
1120 */
1121void VBoxSDLFB::getFullscreenGeometry(uint32_t *width, uint32_t *height)
1122{
1123 SDL_Rect **modes;
1124
1125 /* Get available fullscreen/hardware modes */
1126 modes = SDL_ListModes(NULL, SDL_FULLSCREEN);
1127 Assert(modes != NULL);
1128 /* -1 means that any mode is possible (usually non fullscreen) */
1129 if (modes != (SDL_Rect **)-1)
1130 {
1131 /*
1132 * According to the SDL documentation, the API guarantees that the modes
1133 * are sorted from larger to smaller, so we just take the first entry as
1134 * the maximum.
1135 *
1136 * XXX Crude Xinerama hack :-/
1137 */
1138 if ( modes[0]->w > (16*modes[0]->h/9)
1139 && modes[1]
1140 && modes[1]->h == modes[0]->h)
1141 {
1142 *width = modes[1]->w;
1143 *height = modes[1]->h;
1144 }
1145 else
1146 {
1147 *width = modes[0]->w;
1148 *height = modes[0]->w;
1149 }
1150 }
1151}
1152
1153#ifdef VBOX_SECURELABEL
1154/**
1155 * Setup the secure labeling parameters
1156 *
1157 * @returns VBox status code
1158 * @param height height of the secure label area in pixels
1159 * @param font file path fo the TrueType font file
1160 * @param pointsize font size in points
1161 */
1162int VBoxSDLFB::initSecureLabel(uint32_t height, char *font, uint32_t pointsize, uint32_t labeloffs)
1163{
1164 LogFlow(("VBoxSDLFB:initSecureLabel: new offset: %d pixels, new font: %s, new pointsize: %d\n",
1165 height, font, pointsize));
1166 mLabelHeight = height;
1167 mLabelOffs = labeloffs;
1168 Assert(font);
1169 pTTF_Init();
1170 mLabelFont = pTTF_OpenFont(font, pointsize);
1171 if (!mLabelFont)
1172 {
1173 AssertMsgFailed(("Failed to open TTF font file %s\n", font));
1174 return VERR_OPEN_FAILED;
1175 }
1176 mSecureLabelColorFG = 0x0000FF00;
1177 mSecureLabelColorBG = 0x00FFFF00;
1178 repaint();
1179 return VINF_SUCCESS;
1180}
1181
1182/**
1183 * Set the secure label text and repaint the label
1184 *
1185 * @param text UTF-8 string of new label
1186 * @remarks must be called from the SDL thread!
1187 */
1188void VBoxSDLFB::setSecureLabelText(const char *text)
1189{
1190 mSecureLabelText = text;
1191 paintSecureLabel(0, 0, 0, 0, true);
1192}
1193
1194/**
1195 * Sets the secure label background color.
1196 *
1197 * @param colorFG encoded RGB value for text
1198 * @param colorBG encored RGB value for background
1199 * @remarks must be called from the SDL thread!
1200 */
1201void VBoxSDLFB::setSecureLabelColor(uint32_t colorFG, uint32_t colorBG)
1202{
1203 mSecureLabelColorFG = colorFG;
1204 mSecureLabelColorBG = colorBG;
1205 paintSecureLabel(0, 0, 0, 0, true);
1206}
1207
1208/**
1209 * Paint the secure label if required
1210 *
1211 * @param fForce Force the repaint
1212 * @remarks must be called from the SDL thread!
1213 */
1214void VBoxSDLFB::paintSecureLabel(int x, int y, int w, int h, bool fForce)
1215{
1216#ifdef VBOXSDL_WITH_X11
1217 AssertMsg(gSdlNativeThread == RTThreadNativeSelf(), ("Wrong thread! SDL is not threadsafe!\n"));
1218#endif
1219 /* only when the function is present */
1220 if (!pTTF_RenderUTF8_Solid)
1221 return;
1222 /* check if we can skip the paint */
1223 if (!fForce && ((uint32_t)y > mLabelHeight))
1224 {
1225 return;
1226 }
1227 /* first fill the background */
1228 SDL_Rect rect = {0, 0, (Uint16)mScreen->w, (Uint16)mLabelHeight};
1229 SDL_FillRect(mScreen, &rect, SDL_MapRGB(mScreen->format,
1230 (mSecureLabelColorBG & 0x00FF0000) >> 16, /* red */
1231 (mSecureLabelColorBG & 0x0000FF00) >> 8, /* green */
1232 mSecureLabelColorBG & 0x000000FF)); /* blue */
1233
1234 /* now the text */
1235 if ( mLabelFont != NULL
1236 && !mSecureLabelText.isEmpty()
1237 )
1238 {
1239 SDL_Color clrFg = {(uint8_t)((mSecureLabelColorFG & 0x00FF0000) >> 16),
1240 (uint8_t)((mSecureLabelColorFG & 0x0000FF00) >> 8),
1241 (uint8_t)( mSecureLabelColorFG & 0x000000FF ), 0};
1242 SDL_Surface *sText = (pTTF_RenderUTF8_Blended != NULL)
1243 ? pTTF_RenderUTF8_Blended(mLabelFont, mSecureLabelText.c_str(), clrFg)
1244 : pTTF_RenderUTF8_Solid(mLabelFont, mSecureLabelText.c_str(), clrFg);
1245 rect.x = 10;
1246 rect.y = mLabelOffs;
1247 SDL_BlitSurface(sText, NULL, mScreen, &rect);
1248 SDL_FreeSurface(sText);
1249 }
1250 /* make sure to update the screen */
1251 SDL_UpdateRect(mScreen, 0, 0, mScreen->w, mLabelHeight);
1252}
1253#endif /* VBOX_SECURELABEL */
1254
1255// IFramebufferOverlay
1256///////////////////////////////////////////////////////////////////////////////////
1257
1258/**
1259 * Constructor for the VBoxSDLFBOverlay class (IFramebufferOverlay implementation)
1260 *
1261 * @param x Initial X offset for the overlay
1262 * @param y Initial Y offset for the overlay
1263 * @param width Initial width for the overlay
1264 * @param height Initial height for the overlay
1265 * @param visible Whether the overlay is initially visible
1266 * @param alpha Initial alpha channel value for the overlay
1267 */
1268VBoxSDLFBOverlay::VBoxSDLFBOverlay(ULONG x, ULONG y, ULONG width, ULONG height,
1269 BOOL visible, VBoxSDLFB *aParent) :
1270 mOverlayX(x), mOverlayY(y), mOverlayWidth(width),
1271 mOverlayHeight(height), mOverlayVisible(visible),
1272 mParent(aParent)
1273{}
1274
1275/**
1276 * Destructor for the VBoxSDLFBOverlay class.
1277 */
1278VBoxSDLFBOverlay::~VBoxSDLFBOverlay()
1279{
1280 SDL_FreeSurface(mBlendedBits);
1281 SDL_FreeSurface(mOverlayBits);
1282}
1283
1284/**
1285 * Perform any initialisation of the overlay that can potentially fail
1286 *
1287 * @returns S_OK on success or the reason for the failure
1288 */
1289HRESULT VBoxSDLFBOverlay::init()
1290{
1291 mBlendedBits = SDL_CreateRGBSurface(SDL_ANYFORMAT, mOverlayWidth, mOverlayHeight, 32,
1292 0x00ff0000, 0x0000ff00, 0x000000ff, 0);
1293 AssertMsgReturn(mBlendedBits != NULL, ("Failed to create an SDL surface\n"),
1294 E_OUTOFMEMORY);
1295 mOverlayBits = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, mOverlayWidth,
1296 mOverlayHeight, 32, 0x00ff0000, 0x0000ff00,
1297 0x000000ff, 0xff000000);
1298 AssertMsgReturn(mOverlayBits != NULL, ("Failed to create an SDL surface\n"),
1299 E_OUTOFMEMORY);
1300 return S_OK;
1301}
1302
1303/**
1304 * Returns the current overlay X offset in pixels.
1305 *
1306 * @returns COM status code
1307 * @param x Address of result buffer.
1308 */
1309STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(X)(ULONG *x)
1310{
1311 LogFlow(("VBoxSDLFBOverlay::GetX\n"));
1312 if (!x)
1313 return E_INVALIDARG;
1314 *x = mOverlayX;
1315 return S_OK;
1316}
1317
1318/**
1319 * Returns the current overlay height in pixels.
1320 *
1321 * @returns COM status code
1322 * @param height Address of result buffer.
1323 */
1324STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Y)(ULONG *y)
1325{
1326 LogFlow(("VBoxSDLFBOverlay::GetY\n"));
1327 if (!y)
1328 return E_INVALIDARG;
1329 *y = mOverlayY;
1330 return S_OK;
1331}
1332
1333/**
1334 * Returns the current overlay width in pixels. In fact, this returns the line size.
1335 *
1336 * @returns COM status code
1337 * @param width Address of result buffer.
1338 */
1339STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Width)(ULONG *width)
1340{
1341 LogFlow(("VBoxSDLFBOverlay::GetWidth\n"));
1342 if (!width)
1343 return E_INVALIDARG;
1344 *width = mOverlayBits->pitch;
1345 return S_OK;
1346}
1347
1348/**
1349 * Returns the current overlay line size in pixels.
1350 *
1351 * @returns COM status code
1352 * @param lineSize Address of result buffer.
1353 */
1354STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(BytesPerLine)(ULONG *bytesPerLine)
1355{
1356 LogFlow(("VBoxSDLFBOverlay::GetBytesPerLine\n"));
1357 if (!bytesPerLine)
1358 return E_INVALIDARG;
1359 *bytesPerLine = mOverlayBits->pitch;
1360 return S_OK;
1361}
1362
1363/**
1364 * Returns the current overlay height in pixels.
1365 *
1366 * @returns COM status code
1367 * @param height Address of result buffer.
1368 */
1369STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Height)(ULONG *height)
1370{
1371 LogFlow(("VBoxSDLFBOverlay::GetHeight\n"));
1372 if (!height)
1373 return E_INVALIDARG;
1374 *height = mOverlayHeight;
1375 return S_OK;
1376}
1377
1378/**
1379 * Returns whether the overlay is currently visible.
1380 *
1381 * @returns COM status code
1382 * @param visible Address of result buffer.
1383 */
1384STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Visible)(BOOL *visible)
1385{
1386 LogFlow(("VBoxSDLFBOverlay::GetVisible\n"));
1387 if (!visible)
1388 return E_INVALIDARG;
1389 *visible = mOverlayVisible;
1390 return S_OK;
1391}
1392
1393/**
1394 * Sets whether the overlay is currently visible.
1395 *
1396 * @returns COM status code
1397 * @param visible New value.
1398 */
1399STDMETHODIMP VBoxSDLFBOverlay::COMSETTER(Visible)(BOOL visible)
1400{
1401 LogFlow(("VBoxSDLFBOverlay::SetVisible\n"));
1402 mOverlayVisible = visible;
1403 return S_OK;
1404}
1405
1406/**
1407 * Returns the value of the global alpha channel.
1408 *
1409 * @returns COM status code
1410 * @param alpha Address of result buffer.
1411 */
1412STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Alpha)(ULONG *alpha)
1413{
1414 LogFlow(("VBoxSDLFBOverlay::GetAlpha\n"));
1415 return E_NOTIMPL;
1416}
1417
1418/**
1419 * Sets whether the overlay is currently visible.
1420 *
1421 * @returns COM status code
1422 * @param alpha new value.
1423 */
1424STDMETHODIMP VBoxSDLFBOverlay::COMSETTER(Alpha)(ULONG alpha)
1425{
1426 LogFlow(("VBoxSDLFBOverlay::SetAlpha\n"));
1427 return E_NOTIMPL;
1428}
1429
1430/**
1431 * Returns the address of the framebuffer bits for writing to.
1432 *
1433 * @returns COM status code
1434 * @param alpha Address of result buffer.
1435 */
1436STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Address)(ULONG *address)
1437{
1438 LogFlow(("VBoxSDLFBOverlay::GetAddress\n"));
1439 if (!address)
1440 return E_INVALIDARG;
1441 *address = (uintptr_t) mOverlayBits->pixels;
1442 return S_OK;
1443}
1444
1445/**
1446 * Returns the current colour depth. In fact, this is always 32bpp.
1447 *
1448 * @returns COM status code
1449 * @param bitsPerPixel Address of result buffer.
1450 */
1451STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(BitsPerPixel)(ULONG *bitsPerPixel)
1452{
1453 LogFlow(("VBoxSDLFBOverlay::GetBitsPerPixel\n"));
1454 if (!bitsPerPixel)
1455 return E_INVALIDARG;
1456 *bitsPerPixel = 32;
1457 return S_OK;
1458}
1459
1460/**
1461 * Returns the current pixel format. In fact, this is always RGB.
1462 *
1463 * @returns COM status code
1464 * @param pixelFormat Address of result buffer.
1465 */
1466STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(PixelFormat)(ULONG *pixelFormat)
1467{
1468 LogFlow(("VBoxSDLFBOverlay::GetPixelFormat\n"));
1469 if (!pixelFormat)
1470 return E_INVALIDARG;
1471 *pixelFormat = BitmapFormat_BGR;
1472 return S_OK;
1473}
1474
1475/**
1476 * Returns whether the guest VRAM is used directly. In fact, this is always FALSE.
1477 *
1478 * @returns COM status code
1479 * @param usesGuestVRAM Address of result buffer.
1480 */
1481STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(UsesGuestVRAM)(BOOL *usesGuestVRAM)
1482{
1483 LogFlow(("VBoxSDLFBOverlay::GetUsesGuestVRAM\n"));
1484 if (!usesGuestVRAM)
1485 return E_INVALIDARG;
1486 *usesGuestVRAM = FALSE;
1487 return S_OK;
1488}
1489
1490/**
1491 * Returns the height reduction. In fact, this is always 0.
1492 *
1493 * @returns COM status code
1494 * @param heightReduction Address of result buffer.
1495 */
1496STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(HeightReduction)(ULONG *heightReduction)
1497{
1498 LogFlow(("VBoxSDLFBOverlay::GetHeightReduction\n"));
1499 if (!heightReduction)
1500 return E_INVALIDARG;
1501 *heightReduction = 0;
1502 return S_OK;
1503}
1504
1505/**
1506 * Returns the overlay for this framebuffer. Obviously, we return NULL here.
1507 *
1508 * @returns COM status code
1509 * @param overlay Address of result buffer.
1510 */
1511STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(Overlay)(IFramebufferOverlay **aOverlay)
1512{
1513 LogFlow(("VBoxSDLFBOverlay::GetOverlay\n"));
1514 if (!aOverlay)
1515 return E_INVALIDARG;
1516 *aOverlay = 0;
1517 return S_OK;
1518}
1519
1520/**
1521 * Returns associated window handle. We return NULL here.
1522 *
1523 * @returns COM status code
1524 * @param winId Address of result buffer.
1525 */
1526STDMETHODIMP VBoxSDLFBOverlay::COMGETTER(WinId)(LONG64 *winId)
1527{
1528 LogFlow(("VBoxSDLFBOverlay::GetWinId\n"));
1529 if (!winId)
1530 return E_INVALIDARG;
1531 *winId = 0;
1532 return S_OK;
1533}
1534
1535
1536/**
1537 * Lock the overlay. This should not be used - lock the parent IFramebuffer instead.
1538 *
1539 * @returns COM status code
1540 */
1541STDMETHODIMP VBoxSDLFBOverlay::Lock()
1542{
1543 LogFlow(("VBoxSDLFBOverlay::Lock\n"));
1544 AssertMsgFailed(("You should not attempt to lock an IFramebufferOverlay object -\n"
1545 "lock the parent IFramebuffer object instead.\n"));
1546 return E_NOTIMPL;
1547}
1548
1549/**
1550 * Unlock the overlay.
1551 *
1552 * @returns COM status code
1553 */
1554STDMETHODIMP VBoxSDLFBOverlay::Unlock()
1555{
1556 LogFlow(("VBoxSDLFBOverlay::Unlock\n"));
1557 AssertMsgFailed(("You should not attempt to lock an IFramebufferOverlay object -\n"
1558 "lock the parent IFramebuffer object instead.\n"));
1559 return E_NOTIMPL;
1560}
1561
1562/**
1563 * Change the X and Y co-ordinates of the overlay area.
1564 *
1565 * @returns COM status code
1566 * @param x New X co-ordinate.
1567 * @param y New Y co-ordinate.
1568 */
1569STDMETHODIMP VBoxSDLFBOverlay::Move(ULONG x, ULONG y)
1570{
1571 mOverlayX = x;
1572 mOverlayY = y;
1573 return S_OK;
1574}
1575
1576/**
1577 * Notify the overlay that a section of the framebuffer has been redrawn.
1578 *
1579 * @returns COM status code
1580 * @param x X co-ordinate of upper left corner of modified area.
1581 * @param y Y co-ordinate of upper left corner of modified area.
1582 * @param w Width of modified area.
1583 * @param h Height of modified area.
1584 * @retval finished Set if the operation has completed.
1585 *
1586 * All we do here is to send a request to the parent to update the affected area,
1587 * translating between our co-ordinate system and the parent's. It would be have
1588 * been better to call the parent directly, but such is life. We leave bounds
1589 * checking to the parent.
1590 */
1591STDMETHODIMP VBoxSDLFBOverlay::NotifyUpdate(ULONG x, ULONG y,
1592 ULONG w, ULONG h)
1593{
1594 return mParent->NotifyUpdate(x + mOverlayX, y + mOverlayY, w, h);
1595}
1596
1597/**
1598 * Change the dimensions of the overlay.
1599 *
1600 * @returns COM status code
1601 * @param pixelFormat Must be BitmapFormat_BGR.
1602 * @param vram Must be NULL.
1603 * @param lineSize Ignored.
1604 * @param w New overlay width.
1605 * @param h New overlay height.
1606 * @retval finished Set if the operation has completed.
1607 */
1608STDMETHODIMP VBoxSDLFBOverlay::RequestResize(ULONG aScreenId, ULONG pixelFormat, ULONG vram,
1609 ULONG bitsPerPixel, ULONG bytesPerLine,
1610 ULONG w, ULONG h, BOOL *finished)
1611{
1612 AssertReturn(pixelFormat == BitmapFormat_BGR, E_INVALIDARG);
1613 AssertReturn(vram == 0, E_INVALIDARG);
1614 AssertReturn(bitsPerPixel == 32, E_INVALIDARG);
1615 mOverlayWidth = w;
1616 mOverlayHeight = h;
1617 SDL_FreeSurface(mOverlayBits);
1618 mBlendedBits = SDL_CreateRGBSurface(SDL_ANYFORMAT, mOverlayWidth, mOverlayHeight, 32,
1619 0x00ff0000, 0x0000ff00, 0x000000ff, 0);
1620 AssertMsgReturn(mBlendedBits != NULL, ("Failed to create an SDL surface\n"),
1621 E_OUTOFMEMORY);
1622 mOverlayBits = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, mOverlayWidth,
1623 mOverlayHeight, 32, 0x00ff0000, 0x0000ff00,
1624 0x000000ff, 0xff000000);
1625 AssertMsgReturn(mOverlayBits != NULL, ("Failed to create an SDL surface\n"),
1626 E_OUTOFMEMORY);
1627 return S_OK;
1628}
1629
1630/**
1631 * Returns whether we like the given video mode.
1632 *
1633 * @returns COM status code
1634 * @param width video mode width in pixels
1635 * @param height video mode height in pixels
1636 * @param bpp video mode bit depth in bits per pixel
1637 * @retval supported pointer to result variable
1638 *
1639 * Basically, we support anything with 32bpp.
1640 */
1641STDMETHODIMP VBoxSDLFBOverlay::VideoModeSupported(ULONG width, ULONG height, ULONG bpp,
1642 BOOL *supported)
1643{
1644 if (!supported)
1645 return E_POINTER;
1646 if (bpp == 32)
1647 *supported = true;
1648 else
1649 *supported = false;
1650 return S_OK;
1651}
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