VirtualBox

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

Last change on this file since 16894 was 15868, checked in by vboxsync, 16 years ago

VBoxSDL framebuffer resize optimization (xTracker #3487).

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