VirtualBox

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

Last change on this file since 29807 was 28800, checked in by vboxsync, 15 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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