VirtualBox

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

Last change on this file since 41215 was 41215, checked in by vboxsync, 13 years ago

Frontends/VBoxSDL: clean up framebuffer implementation in a COM-compatible fashion

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette