VirtualBox

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

Last change on this file since 46861 was 46658, checked in by vboxsync, 12 years ago

include VBox/com/EventQueue only if necessary

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