VirtualBox

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

Last change on this file since 7392 was 7207, checked in by vboxsync, 17 years ago

Main: Reworked enums to avoid 1) weird duplication of enum name when referring to enum values in cross-platform code; 2) possible clashes on Win32 due to putting identifiers like Paused or Disabled to the global namespace (via C enums). In the new style, enums are used like this: a) USBDeviceState_T v = USBDeviceState_Busy from cross-platform non-Qt code; b) KUSBDeviceState v = KUSBDeviceState_Busy from Qt code; c) USBDeviceState v = USBDeviceState_Busy from plain Win32 and d) PRUInt32 USBDeviceState v = USBDeviceState::Busy from plain XPCOM.

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