VirtualBox

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

Last change on this file since 46150 was 45940, checked in by vboxsync, 11 years ago

crOpenGL->Fe/Qt notification mechanism

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