VirtualBox

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

Last change on this file since 77910 was 77370, checked in by vboxsync, 5 years ago

Device/Graphics, pdm, Main, Front-ends: infrastructure for host software cursor.
bugref:9376: Complete hardware cursor implementation in VMSVGA.
This change provides the infrastructure for letting front-ends report to the
graphics device that they are able to render a pointer cursor at any location,
not just where the host cursor is, and for the device to ask them to do this.
It also provides mediation in Main/Display between multiple front-ends and the
device, and tells the guest that we can always render the cursor. In a
follow-up change the device is expected to add support for rendering the
cursor itself into the frame-buffer image it provides to the front-end if not
all attached front-ends are capable of rendering it.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use