VirtualBox

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

Last change on this file since 25275 was 23170, checked in by vboxsync, 15 years ago

VBoxSDL: be more tolerant on video driver initialization failures

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

© 2023 Oracle
ContactPrivacy policyTerms of Use