VirtualBox

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

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

Main,Frontends: use BitmapFormat in API.

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