VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/VBoxFrameBuffer.cpp@ 9203

Last change on this file since 9203 was 8902, checked in by vboxsync, 16 years ago

FE/Qt: Keep style.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.6 KB
Line 
1/** @file
2 *
3 * VBox frontends: Qt GUI ("VirtualBox"):
4 * VBoxFrameBuffer class and subclasses implementation
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 "VBoxFrameBuffer.h"
24
25#include "VBoxConsoleView.h"
26#include "VBoxProblemReporter.h"
27#include "VBoxGlobal.h"
28
29#include <qapplication.h>
30
31//
32// VBoxFrameBuffer class
33/////////////////////////////////////////////////////////////////////////////
34
35/** @class VBoxFrameBuffer
36 *
37 * Base class for all frame buffer implementations.
38 */
39
40#if !defined (Q_OS_WIN32)
41NS_DECL_CLASSINFO (VBoxFrameBuffer)
42NS_IMPL_ISUPPORTS1_CI (VBoxFrameBuffer, IFramebuffer)
43#endif
44
45VBoxFrameBuffer::VBoxFrameBuffer (VBoxConsoleView *aView)
46 : mView (aView), mMutex (new QMutex (true))
47 , mWdt (0), mHgt (0)
48#if defined (Q_OS_WIN32)
49 , refcnt (0)
50#endif
51{
52 AssertMsg (mView, ("VBoxConsoleView must not be null\n"));
53}
54
55VBoxFrameBuffer::~VBoxFrameBuffer()
56{
57 delete mMutex;
58}
59
60// IFramebuffer implementation methods.
61// Just forwarders to relevant class methods.
62
63STDMETHODIMP VBoxFrameBuffer::COMGETTER(Address) (BYTE **aAddress)
64{
65 if (!aAddress)
66 return E_POINTER;
67 *aAddress = address();
68 return S_OK;
69}
70
71STDMETHODIMP VBoxFrameBuffer::COMGETTER(Width) (ULONG *aWidth)
72{
73 if (!aWidth)
74 return E_POINTER;
75 *aWidth = (ULONG) width();
76 return S_OK;
77}
78
79STDMETHODIMP VBoxFrameBuffer::COMGETTER(Height) (ULONG *aHeight)
80{
81 if (!aHeight)
82 return E_POINTER;
83 *aHeight = (ULONG) height();
84 return S_OK;
85}
86
87STDMETHODIMP VBoxFrameBuffer::COMGETTER(BitsPerPixel) (ULONG *aBitsPerPixel)
88{
89 if (!aBitsPerPixel)
90 return E_POINTER;
91 *aBitsPerPixel = bitsPerPixel();
92 return S_OK;
93}
94
95STDMETHODIMP VBoxFrameBuffer::COMGETTER(BytesPerLine) (ULONG *aBytesPerLine)
96{
97 if (!aBytesPerLine)
98 return E_POINTER;
99 *aBytesPerLine = bytesPerLine();
100 return S_OK;
101}
102
103STDMETHODIMP VBoxFrameBuffer::COMGETTER(PixelFormat) (
104 ULONG *aPixelFormat)
105{
106 if (!aPixelFormat)
107 return E_POINTER;
108 *aPixelFormat = pixelFormat();
109 return S_OK;
110}
111
112STDMETHODIMP VBoxFrameBuffer::COMGETTER(UsesGuestVRAM) (
113 BOOL *aUsesGuestVRAM)
114{
115 if (!aUsesGuestVRAM)
116 return E_POINTER;
117 *aUsesGuestVRAM = usesGuestVRAM();
118 return S_OK;
119}
120
121STDMETHODIMP VBoxFrameBuffer::COMGETTER(HeightReduction) (ULONG *aHeightReduction)
122{
123 if (!aHeightReduction)
124 return E_POINTER;
125 /* no reduction */
126 *aHeightReduction = 0;
127 return S_OK;
128}
129
130STDMETHODIMP VBoxFrameBuffer::COMGETTER(Overlay) (IFramebufferOverlay **aOverlay)
131{
132 if (!aOverlay)
133 return E_POINTER;
134 /* not yet implemented */
135 *aOverlay = 0;
136 return S_OK;
137}
138
139STDMETHODIMP VBoxFrameBuffer::Lock()
140{
141 this->lock();
142 return S_OK;
143}
144
145STDMETHODIMP VBoxFrameBuffer::Unlock()
146{
147 this->unlock();
148 return S_OK;
149}
150
151/** @note This method is called on EMT from under this object's lock */
152STDMETHODIMP VBoxFrameBuffer::RequestResize (ULONG aScreenId, ULONG aPixelFormat,
153 BYTE *aVRAM, ULONG aBitsPerPixel, ULONG aBytesPerLine,
154 ULONG aWidth, ULONG aHeight,
155 BOOL *aFinished)
156{
157 NOREF(aScreenId);
158 QApplication::postEvent (mView,
159 new VBoxResizeEvent (aPixelFormat, aVRAM, aBitsPerPixel,
160 aBytesPerLine, aWidth, aHeight));
161
162#ifdef DEBUG_sunlover
163 LogFlowFunc (("pixelFormat=%d, vram=%p, bpp=%d, bpl=%d, w=%d, h=%d\n",
164 aPixelFormat, aVRAM, aBitsPerPixel, aBytesPerLine, aWidth, aHeight));
165#endif /* DEBUG_sunlover */
166
167 /*
168 * the resize has been postponed, return FALSE
169 * to cause the VM thread to sleep until IDisplay::ResizeFinished()
170 * is called from the VBoxResizeEvent event handler.
171 */
172
173 *aFinished = FALSE;
174 return S_OK;
175}
176
177STDMETHODIMP
178VBoxFrameBuffer::OperationSupported (FramebufferAccelerationOperation_T aOperation,
179 BOOL *aSupported)
180{
181 NOREF(aOperation);
182 if (!aSupported)
183 return E_POINTER;
184 *aSupported = FALSE;
185 return S_OK;
186}
187
188/**
189 * Returns whether we like the given video mode.
190 *
191 * @returns COM status code
192 * @param width video mode width in pixels
193 * @param height video mode height in pixels
194 * @param bpp video mode bit depth in bits per pixel
195 * @param supported pointer to result variable
196 */
197STDMETHODIMP VBoxFrameBuffer::VideoModeSupported (ULONG aWidth, ULONG aHeight,
198 ULONG aBPP, BOOL *aSupported)
199{
200 NOREF(aBPP);
201 LogFlowThisFunc(("aWidth=%lu, aHeight=%lu, aBPP=%lu\n",
202 (unsigned long) aWidth, (unsigned long) aHeight,
203 (unsigned long) aBPP));
204 if (!aSupported)
205 return E_POINTER;
206 *aSupported = TRUE;
207 QRect screen = mView->desktopGeometry();
208 if ( (screen.width() != 0)
209 && (aWidth > (ULONG) screen.width())
210 )
211 *aSupported = FALSE;
212 if ( (screen.height() != 0)
213 && (aHeight > (ULONG) screen.height())
214 )
215 *aSupported = FALSE;
216 LogFlowThisFunc(("returning aSupported=%d\n", *aSupported));
217 return S_OK;
218}
219
220STDMETHODIMP VBoxFrameBuffer::SolidFill (ULONG aX, ULONG aY,
221 ULONG aWidth, ULONG aHeight,
222 ULONG aColor, BOOL *aHandled)
223{
224 NOREF(aX);
225 NOREF(aY);
226 NOREF(aWidth);
227 NOREF(aHeight);
228 NOREF(aColor);
229 if (!aHandled)
230 return E_POINTER;
231 *aHandled = FALSE;
232 return S_OK;
233}
234
235STDMETHODIMP VBoxFrameBuffer::CopyScreenBits (ULONG aXDst, ULONG aYDst,
236 ULONG aXSrc, ULONG aYSrc,
237 ULONG aWidth, ULONG aHeight,
238 BOOL *aHandled)
239{
240 NOREF(aXDst);
241 NOREF(aYDst);
242 NOREF(aXSrc);
243 NOREF(aYSrc);
244 NOREF(aWidth);
245 NOREF(aHeight);
246 if (!aHandled)
247 return E_POINTER;
248 *aHandled = FALSE;
249 return S_OK;
250}
251
252STDMETHODIMP VBoxFrameBuffer::GetVisibleRegion(BYTE *aRectangles, ULONG aCount,
253 ULONG *aCountCopied)
254{
255 PRTRECT rects = (PRTRECT)aRectangles;
256
257 if (!rects)
258 return E_POINTER;
259
260 /// @todo what and why?
261
262 NOREF(aCount);
263 NOREF(aCountCopied);
264
265 return S_OK;
266}
267
268STDMETHODIMP VBoxFrameBuffer::SetVisibleRegion (BYTE *aRectangles, ULONG aCount)
269{
270 PRTRECT rects = (PRTRECT)aRectangles;
271
272 if (!rects)
273 return E_POINTER;
274
275 QRegion reg;
276 for (ULONG ind = 0; ind < aCount; ++ ind)
277 {
278 QRect rect;
279 rect.setLeft (rects->xLeft);
280 rect.setTop (rects->yTop);
281 /* QRect are inclusive */
282 rect.setRight (rects->xRight - 1);
283 rect.setBottom (rects->yBottom - 1);
284 reg += rect;
285 ++ rects;
286 }
287 QApplication::postEvent (mView, new VBoxSetRegionEvent (reg));
288
289 return S_OK;
290}
291
292//
293// VBoxQImageFrameBuffer class
294/////////////////////////////////////////////////////////////////////////////
295
296#if defined (VBOX_GUI_USE_QIMAGE)
297
298/** @class VBoxQImageFrameBuffer
299 *
300 * The VBoxQImageFrameBuffer class is a class that implements the IFrameBuffer
301 * interface and uses QImage as the direct storage for VM display data. QImage
302 * is then converted to QPixmap and blitted to the console view widget.
303 */
304
305VBoxQImageFrameBuffer::VBoxQImageFrameBuffer (VBoxConsoleView *aView) :
306 VBoxFrameBuffer (aView)
307{
308 resizeEvent (new VBoxResizeEvent (FramebufferPixelFormat_Opaque,
309 NULL, 0, 0, 640, 480));
310}
311
312/** @note This method is called on EMT from under this object's lock */
313STDMETHODIMP VBoxQImageFrameBuffer::NotifyUpdate (ULONG aX, ULONG aY,
314 ULONG aW, ULONG aH,
315 BOOL *aFinished)
316{
317#if !defined (Q_WS_WIN) && !defined (Q_WS_PM)
318 /* we're not on the GUI thread and update() isn't thread safe in Qt 3.3.x
319 on the Mac (4.2.x is), on Linux (didn't check Qt 4.x there) and
320 probably on other non-DOS platforms, so post the event instead. */
321 QApplication::postEvent (mView,
322 new VBoxRepaintEvent (aX, aY, aW, aH));
323#else
324 /* we're not on the GUI thread, so update() instead of repaint()! */
325 mView->viewport()->update (aX - mView->contentsX(),
326 aY - mView->contentsY(),
327 aW, aH);
328#endif
329 /* the update has been finished, return TRUE */
330 *aFinished = TRUE;
331 return S_OK;
332}
333
334void VBoxQImageFrameBuffer::paintEvent (QPaintEvent *pe)
335{
336 const QRect &r = pe->rect().intersect (mView->viewport()->rect());
337
338 /* some outdated rectangle during processing VBoxResizeEvent */
339 if (r.isEmpty())
340 return;
341
342#if 0
343 LogFlowFunc (("%dx%d-%dx%d (img=%dx%d)\n",
344 r.x(), r.y(), r.width(), r.height(),
345 img.width(), img.height()));
346#endif
347
348 FRAMEBUF_DEBUG_START (xxx);
349
350 if (r.width() < mWdt * 2 / 3)
351 {
352 /* this method is faster for narrow updates */
353 mPM.convertFromImage (mImg.copy (r.x() + mView->contentsX(),
354 r.y() + mView->contentsY(),
355 r.width(), r.height()));
356
357 ::bitBlt (mView->viewport(), r.x(), r.y(),
358 &mPM, 0, 0,
359 r.width(), r.height(),
360 Qt::CopyROP, TRUE);
361 }
362 else
363 {
364 /* this method is faster for wide updates */
365 mPM.convertFromImage (QImage (mImg.scanLine (r.y() + mView->contentsY()),
366 mImg.width(), r.height(), mImg.depth(),
367 0, 0, QImage::LittleEndian));
368
369 ::bitBlt (mView->viewport(), r.x(), r.y(),
370 &mPM, r.x() + mView->contentsX(), 0,
371 r.width(), r.height(),
372 Qt::CopyROP, TRUE);
373 }
374
375 FRAMEBUF_DEBUG_STOP (xxx, r.width(), r.height());
376}
377
378void VBoxQImageFrameBuffer::resizeEvent (VBoxResizeEvent *re)
379{
380#if 0
381 LogFlowFunc (("fmt=%d, vram=%p, bpp=%d, bpl=%d, width=%d, height=%d\n",
382 re->pixelFormat(), re->VRAM(),
383 re->bitsPerPixel(), re->bytesPerLine(),
384 re->width(), re->height()));
385#endif
386
387 mWdt = re->width();
388 mHgt = re->height();
389
390 bool remind = false;
391 bool fallback = false;
392
393 /* check if we support the pixel format and can use the guest VRAM directly */
394 if (re->pixelFormat() == FramebufferPixelFormat_FOURCC_RGB)
395 {
396 switch (re->bitsPerPixel())
397 {
398 /* 32-, 8- and 1-bpp are the only depths suported by QImage */
399 case 32:
400 break;
401 case 8:
402 case 1:
403 remind = true;
404 break;
405 default:
406 remind = true;
407 fallback = true;
408 break;
409 }
410
411 if (!fallback)
412 {
413 /* QImage only supports 32-bit aligned scan lines */
414 fallback = re->bytesPerLine() !=
415 ((mWdt * re->bitsPerPixel() + 31) / 32) * 4;
416 Assert (!fallback);
417 if (!fallback)
418 {
419 mImg = QImage ((uchar *) re->VRAM(), mWdt, mHgt,
420 re->bitsPerPixel(), NULL, 0, QImage::LittleEndian);
421 mPixelFormat = FramebufferPixelFormat_FOURCC_RGB;
422 mUsesGuestVRAM = true;
423 }
424 }
425 }
426 else
427 {
428 fallback = true;
429 }
430
431 if (fallback)
432 {
433 /* we don't support either the pixel format or the color depth,
434 * fallback to a self-provided 32bpp RGB buffer */
435 mImg = QImage (mWdt, mHgt, 32, 0, QImage::LittleEndian);
436 mPixelFormat = FramebufferPixelFormat_FOURCC_RGB;
437 mUsesGuestVRAM = false;
438 }
439
440 if (remind)
441 {
442 class RemindEvent : public VBoxAsyncEvent
443 {
444 ulong mRealBPP;
445 public:
446 RemindEvent (ulong aRealBPP)
447 : mRealBPP (aRealBPP) {}
448 void handle()
449 {
450 vboxProblem().remindAboutWrongColorDepth (mRealBPP, 32);
451 }
452 };
453 (new RemindEvent (re->bitsPerPixel()))->post();
454 }
455}
456
457#endif
458
459//
460// VBoxSDLFrameBuffer class
461/////////////////////////////////////////////////////////////////////////////
462
463#if defined (VBOX_GUI_USE_SDL)
464
465/** @class VBoxSDLFrameBuffer
466 *
467 * The VBoxSDLFrameBuffer class is a class that implements the IFrameBuffer
468 * interface and uses SDL to store and render VM display data.
469 */
470
471VBoxSDLFrameBuffer::VBoxSDLFrameBuffer (VBoxConsoleView *aView) :
472 VBoxFrameBuffer (aView)
473{
474 mScreen = NULL;
475 mPixelFormat = FramebufferPixelFormat_FOURCC_RGB;
476 mSurfVRAM = NULL;
477
478 resizeEvent (new VBoxResizeEvent (FramebufferPixelFormat_Opaque,
479 NULL, 0, 0, 640, 480));
480}
481
482VBoxSDLFrameBuffer::~VBoxSDLFrameBuffer()
483{
484 if (mSurfVRAM)
485 {
486 SDL_FreeSurface (mSurfVRAM);
487 mSurfVRAM = NULL;
488 }
489 SDL_QuitSubSystem (SDL_INIT_VIDEO);
490}
491
492/** @note This method is called on EMT from under this object's lock */
493STDMETHODIMP VBoxSDLFrameBuffer::NotifyUpdate (ULONG aX, ULONG aY,
494 ULONG aW, ULONG aH,
495 BOOL *aFinished)
496{
497#if !defined (Q_WS_WIN) && !defined (Q_WS_PM)
498 /* we're not on the GUI thread and update() isn't thread safe in Qt 3.3.x
499 on the Mac (4.2.x is), on Linux (didn't check Qt 4.x there) and
500 probably on other non-DOS platforms, so post the event instead. */
501 QApplication::postEvent (mView,
502 new VBoxRepaintEvent (aX, aY, aW, aH));
503#else
504 /* we're not on the GUI thread, so update() instead of repaint()! */
505 mView->viewport()->update (aX - mView->contentsX(),
506 aY - mView->contentsY(),
507 aW, aH);
508#endif
509 /* the update has been finished, return TRUE */
510 *aFinished = TRUE;
511 return S_OK;
512}
513
514void VBoxSDLFrameBuffer::paintEvent (QPaintEvent *pe)
515{
516 if (mScreen)
517 {
518#ifdef Q_WS_X11
519 /* make sure we don't conflict with Qt's drawing */
520 //XSync(QPaintDevice::x11Display(), FALSE);
521#endif
522 if (mScreen->pixels)
523 {
524 QRect r = pe->rect();
525
526 if (mSurfVRAM)
527 {
528 SDL_Rect rect = { (Sint16) r.x(), (Sint16) r.y(),
529 (Sint16) r.width(), (Sint16) r.height() };
530 SDL_BlitSurface (mSurfVRAM, &rect, mScreen, &rect);
531 /** @todo may be: if ((mScreen->flags & SDL_HWSURFACE) == 0) */
532 SDL_UpdateRect (mScreen, r.x(), r.y(), r.width(), r.height());
533 }
534 else
535 {
536 SDL_UpdateRect (mScreen, r.x(), r.y(), r.width(), r.height());
537 }
538 }
539 }
540}
541
542void VBoxSDLFrameBuffer::resizeEvent (VBoxResizeEvent *re)
543{
544 mWdt = re->width();
545 mHgt = re->height();
546
547 /* close SDL so we can init it again */
548 if (mSurfVRAM)
549 {
550 SDL_FreeSurface(mSurfVRAM);
551 mSurfVRAM = NULL;
552 }
553 if (mScreen)
554 {
555 SDL_QuitSubSystem (SDL_INIT_VIDEO);
556 mScreen = NULL;
557 }
558
559 /*
560 * initialize the SDL library, use its super hack to integrate it with our
561 * client window
562 */
563 static char sdlHack[64];
564 LogFlowFunc (("Using client window 0x%08lX to initialize SDL\n",
565 mView->viewport()->winId()));
566 /* Note: SDL_WINDOWID must be decimal (not hex) to work on Win32 */
567 sprintf (sdlHack, "SDL_WINDOWID=%lu", mView->viewport()->winId());
568 putenv (sdlHack);
569 int rc = SDL_InitSubSystem (SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE);
570 AssertMsg (rc == 0, ("SDL initialization failed: %s\n", SDL_GetError()));
571 NOREF(rc);
572
573#ifdef Q_WS_X11
574 /* undo signal redirections from SDL, it'd steal keyboard events from us! */
575 signal (SIGINT, SIG_DFL);
576 signal (SIGQUIT, SIG_DFL);
577#endif
578
579 LogFlowFunc (("Setting SDL video mode to %d x %d\n", mWdt, mHgt));
580
581 bool fallback = false;
582
583 Uint32 Rmask = 0;
584 Uint32 Gmask = 0;
585 Uint32 Bmask = 0;
586
587 if (re->pixelFormat() == FramebufferPixelFormat_FOURCC_RGB)
588 {
589 switch (re->bitsPerPixel())
590 {
591 case 32:
592 Rmask = 0x00FF0000;
593 Gmask = 0x0000FF00;
594 Bmask = 0x000000FF;
595 break;
596 case 24:
597 Rmask = 0x00FF0000;
598 Gmask = 0x0000FF00;
599 Bmask = 0x000000FF;
600 break;
601 case 16:
602 Rmask = 0xF800;
603 Gmask = 0x07E0;
604 Bmask = 0x001F;
605 default:
606 /* Unsupported format leads to the indirect buffer */
607 fallback = true;
608 break;
609 }
610
611 if (!fallback)
612 {
613 /* Create a source surface from guest VRAM. */
614 mSurfVRAM = SDL_CreateRGBSurfaceFrom(re->VRAM(), mWdt, mHgt,
615 re->bitsPerPixel(),
616 re->bytesPerLine(),
617 Rmask, Gmask, Bmask, 0);
618 LogFlowFunc (("Created VRAM surface %p\n", mSurfVRAM));
619 if (mSurfVRAM == NULL)
620 fallback = true;
621 }
622 }
623 else
624 {
625 /* Unsupported format leads to the indirect buffer */
626 fallback = true;
627 }
628
629 /* Pixel format is RGB in any case */
630 mPixelFormat = FramebufferPixelFormat_FOURCC_RGB;
631
632 mScreen = SDL_SetVideoMode (mWdt, mHgt, 0,
633 SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL);
634 AssertMsg (mScreen, ("SDL video mode could not be set!\n"));
635}
636
637#endif
638
639//
640// VBoxDDRAWFrameBuffer class
641/////////////////////////////////////////////////////////////////////////////
642
643#if defined (VBOX_GUI_USE_DDRAW)
644
645/* The class is defined in VBoxFBDDRAW.cpp */
646
647#endif
648
649//
650// VBoxQuartz2DFrameBuffer class
651/////////////////////////////////////////////////////////////////////////////
652
653#if defined (VBOX_GUI_USE_QUARTZ2D)
654
655/* The class is defined in VBoxQuartz2D.cpp */
656
657#endif
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use