VirtualBox

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

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

Backing out r49763 to fix Windows burns.

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