VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/include/VBoxFrameBuffer.h@ 20242

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

View HW Accel: OpenGL framebuffer

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.3 KB
Line 
1/** @file
2 *
3 * VBox frontends: Qt GUI ("VirtualBox"):
4 * VBoxFrameBuffer class and subclasses declarations
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.215389.xyz. 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#ifndef ___VBoxFrameBuffer_h___
24#define ___VBoxFrameBuffer_h___
25
26#include "COMDefs.h"
27#include <iprt/critsect.h>
28
29/* Qt includes */
30#include <QImage>
31#include <QPixmap>
32#include <QMutex>
33#include <QPaintEvent>
34#include <QMoveEvent>
35#if defined (VBOX_GUI_USE_QGL)
36#include <QGLWidget>
37#endif
38
39#if defined (VBOX_GUI_USE_SDL)
40#include <SDL.h>
41#include <signal.h>
42#endif
43
44#if defined (Q_WS_WIN) && defined (VBOX_GUI_USE_DDRAW)
45// VBox/cdefs.h defines these:
46#undef LOWORD
47#undef HIWORD
48#undef LOBYTE
49#undef HIBYTE
50#include <ddraw.h>
51#endif
52
53class VBoxConsoleView;
54
55/////////////////////////////////////////////////////////////////////////////
56
57/**
58 * Frame buffer resize event.
59 */
60class VBoxResizeEvent : public QEvent
61{
62public:
63
64 VBoxResizeEvent (ulong aPixelFormat, uchar *aVRAM,
65 ulong aBitsPerPixel, ulong aBytesPerLine,
66 ulong aWidth, ulong aHeight) :
67 QEvent ((QEvent::Type) VBoxDefs::ResizeEventType),
68 mPixelFormat (aPixelFormat), mVRAM (aVRAM), mBitsPerPixel (aBitsPerPixel),
69 mBytesPerLine (aBytesPerLine), mWidth (aWidth), mHeight (aHeight) {}
70 ulong pixelFormat() { return mPixelFormat; }
71 uchar *VRAM() { return mVRAM; }
72 ulong bitsPerPixel() { return mBitsPerPixel; }
73 ulong bytesPerLine() { return mBytesPerLine; }
74 ulong width() { return mWidth; }
75 ulong height() { return mHeight; }
76
77private:
78
79 ulong mPixelFormat;
80 uchar *mVRAM;
81 ulong mBitsPerPixel;
82 ulong mBytesPerLine;
83 ulong mWidth;
84 ulong mHeight;
85};
86
87/**
88 * Frame buffer repaint event.
89 */
90class VBoxRepaintEvent : public QEvent
91{
92public:
93 VBoxRepaintEvent (int x, int y, int w, int h) :
94 QEvent ((QEvent::Type) VBoxDefs::RepaintEventType),
95 ex (x), ey (y), ew (w), eh (h)
96 {}
97 int x() { return ex; }
98 int y() { return ey; }
99 int width() { return ew; }
100 int height() { return eh; }
101private:
102 int ex, ey, ew, eh;
103};
104
105/**
106 * Frame buffer set region event.
107 */
108class VBoxSetRegionEvent : public QEvent
109{
110public:
111 VBoxSetRegionEvent (const QRegion &aReg)
112 : QEvent ((QEvent::Type) VBoxDefs::SetRegionEventType)
113 , mReg (aReg) {}
114 QRegion region() { return mReg; }
115private:
116 QRegion mReg;
117};
118
119#ifdef VBOX_WITH_VIDEOHWACCEL
120class VBoxVHWACommandProcessEvent : public QEvent
121{
122public:
123 VBoxVHWACommandProcessEvent (struct _VBOXVHWACMD * pCmd)
124 : QEvent ((QEvent::Type) VBoxDefs::VHWACommandProcessType)
125 , mpCmd (pCmd) {}
126 struct _VBOXVHWACMD * command() { return mpCmd; }
127private:
128 struct _VBOXVHWACMD * mpCmd;
129};
130
131#endif
132
133/////////////////////////////////////////////////////////////////////////////
134
135/**
136 * Common IFramebuffer implementation for all methods used by GUI to maintain
137 * the VM display video memory.
138 *
139 * Note that although this class can be called from multiple threads
140 * (in particular, the GUI thread and EMT) it doesn't protect access to every
141 * data field using its mutex lock. This is because all synchronization between
142 * the GUI and the EMT thread is supposed to be done using the
143 * IFramebuffer::NotifyUpdate() and IFramebuffer::RequestResize() methods
144 * (in particular, the \a aFinished parameter of these methods is responsible
145 * for the synchronization). These methods are always called on EMT and
146 * therefore always follow one another but never in parallel.
147 *
148 * Using this object's mutex lock (exposed also in IFramebuffer::Lock() and
149 * IFramebuffer::Unlock() implementations) usually makes sense only if some
150 * third-party thread (i.e. other than GUI or EMT) needs to make sure that
151 * *no* VM display update or resize event can occur while it is accessing
152 * IFramebuffer properties or the underlying display memory storage area.
153 *
154 * See IFramebuffer documentation for more info.
155 */
156
157class VBoxFrameBuffer : VBOX_SCRIPTABLE_IMPL(IFramebuffer)
158{
159public:
160
161 VBoxFrameBuffer (VBoxConsoleView *aView);
162 virtual ~VBoxFrameBuffer();
163
164 NS_DECL_ISUPPORTS
165
166#if defined (Q_OS_WIN32)
167
168 STDMETHOD_(ULONG, AddRef)()
169 {
170 return ::InterlockedIncrement (&refcnt);
171 }
172
173 STDMETHOD_(ULONG, Release)()
174 {
175 long cnt = ::InterlockedDecrement (&refcnt);
176 if (cnt == 0)
177 delete this;
178 return cnt;
179 }
180
181 STDMETHOD(QueryInterface) (REFIID riid , void **ppObj)
182 {
183 if (riid == IID_IUnknown) {
184 *ppObj = this;
185 AddRef();
186 return S_OK;
187 }
188 if (riid == IID_IFramebuffer) {
189 *ppObj = this;
190 AddRef();
191 return S_OK;
192 }
193 *ppObj = NULL;
194 return E_NOINTERFACE;
195 }
196
197#endif
198
199 // IFramebuffer COM methods
200 STDMETHOD(COMGETTER(Address)) (BYTE **aAddress);
201 STDMETHOD(COMGETTER(Width)) (ULONG *aWidth);
202 STDMETHOD(COMGETTER(Height)) (ULONG *aHeight);
203 STDMETHOD(COMGETTER(BitsPerPixel)) (ULONG *aBitsPerPixel);
204 STDMETHOD(COMGETTER(BytesPerLine)) (ULONG *aBytesPerLine);
205 STDMETHOD(COMGETTER(PixelFormat)) (ULONG *aPixelFormat);
206 STDMETHOD(COMGETTER(UsesGuestVRAM)) (BOOL *aUsesGuestVRAM);
207 STDMETHOD(COMGETTER(HeightReduction)) (ULONG *aHeightReduction);
208 STDMETHOD(COMGETTER(Overlay)) (IFramebufferOverlay **aOverlay);
209 STDMETHOD(COMGETTER(WinId)) (ULONG64 *winId);
210
211 STDMETHOD(Lock)();
212 STDMETHOD(Unlock)();
213
214 STDMETHOD(RequestResize) (ULONG aScreenId, ULONG aPixelFormat,
215 BYTE *aVRAM, ULONG aBitsPerPixel, ULONG aBytesPerLine,
216 ULONG aWidth, ULONG aHeight,
217 BOOL *aFinished);
218
219 STDMETHOD(VideoModeSupported) (ULONG aWidth, ULONG aHeight, ULONG aBPP,
220 BOOL *aSupported);
221
222 STDMETHOD(GetVisibleRegion)(BYTE *aRectangles, ULONG aCount, ULONG *aCountCopied);
223 STDMETHOD(SetVisibleRegion)(BYTE *aRectangles, ULONG aCount);
224
225 STDMETHOD(ProcessVHWACommand)(BYTE *pCommand);
226
227 ulong width() { return mWdt; }
228 ulong height() { return mHgt; }
229
230 virtual ulong pixelFormat()
231 {
232 return FramebufferPixelFormat_FOURCC_RGB;
233 }
234
235 virtual bool usesGuestVRAM()
236 {
237 return false;
238 }
239
240 void lock() { RTCritSectEnter(&mCritSect); }
241 void unlock() { RTCritSectLeave(&mCritSect); }
242
243 virtual uchar *address() = 0;
244 virtual ulong bitsPerPixel() = 0;
245 virtual ulong bytesPerLine() = 0;
246
247 /**
248 * Called on the GUI thread (from VBoxConsoleView) when some part of the
249 * VM display viewport needs to be repainted on the host screen.
250 */
251 virtual void paintEvent (QPaintEvent *pe) = 0;
252
253 /**
254 * Called on the GUI thread (from VBoxConsoleView) after it gets a
255 * VBoxResizeEvent posted from the RequestResize() method implementation.
256 */
257 virtual void resizeEvent (VBoxResizeEvent *re)
258 {
259 mWdt = re->width();
260 mHgt = re->height();
261 }
262
263 /**
264 * Called on the GUI thread (from VBoxConsoleView) when the VM console
265 * window is moved.
266 */
267 virtual void moveEvent (QMoveEvent * /*me*/ ) {}
268
269protected:
270
271 VBoxConsoleView *mView;
272 RTCRITSECT mCritSect;
273 int mWdt;
274 int mHgt;
275 uint64_t mWinId;
276
277#if defined (Q_OS_WIN32)
278private:
279 long refcnt;
280#endif
281};
282
283/////////////////////////////////////////////////////////////////////////////
284
285#if defined (VBOX_GUI_USE_QIMAGE)
286
287class VBoxQImageFrameBuffer : public VBoxFrameBuffer
288{
289public:
290
291 VBoxQImageFrameBuffer (VBoxConsoleView *aView);
292
293 STDMETHOD(NotifyUpdate) (ULONG aX, ULONG aY,
294 ULONG aW, ULONG aH);
295
296 ulong pixelFormat() { return mPixelFormat; }
297 bool usesGuestVRAM() { return mUsesGuestVRAM; }
298
299 uchar *address() { return mImg.bits(); }
300 ulong bitsPerPixel() { return mImg.depth(); }
301 ulong bytesPerLine() { return mImg.bytesPerLine(); }
302
303 void paintEvent (QPaintEvent *pe);
304 void resizeEvent (VBoxResizeEvent *re);
305
306private:
307
308 QPixmap mPM;
309 QImage mImg;
310 ulong mPixelFormat;
311 bool mUsesGuestVRAM;
312};
313
314#endif
315
316/////////////////////////////////////////////////////////////////////////////
317
318#if defined (VBOX_GUI_USE_QGL)
319
320#ifdef DEBUG
321#define VBOXQGL_ASSERTNOERR() \
322 do { GLenum err = glGetError(); \
323 Assert(err == GL_NO_ERROR); \
324 }while(0)
325
326#define VBOXQGL_CHECKERR(_op) \
327 do { \
328 glGetError(); \
329 _op \
330 VBOXQGL_ASSERTNOERR(); \
331 }while(0)
332#else
333#define VBOXQGL_ASSERTNOERR() \
334 do {}while(0)
335
336#define VBOXQGL_CHECKERR(_op) \
337 do { \
338 _op \
339 }while(0)
340#endif
341class VBoxGLWidget : public QGLWidget
342{
343public:
344 VBoxGLWidget (QWidget *aParent)
345 : QGLWidget (aParent),
346 mRe(NULL),
347 mpIntersectionRect(NULL),
348 mDisplay(0),
349 mDisplayInitialized(false),
350 mAddress(NULL),
351 mTexture(0),
352 mFormat(0),
353 mInternalFormat(0),
354 mType(0),
355 mBitsPerPixel(0),
356 mBytesPerPixel(0),
357 mBytesPerLine(0),
358 mPixelFormat(0),
359 mUsesGuestVRAM(false),
360 mDisplayWidth(0),
361 mDisplayHeight(0)
362 {
363// Assert(0);
364 /* No need for background drawing */
365// setAttribute (Qt::WA_OpaquePaintEvent);
366 }
367
368 ulong vboxPixelFormat() { return mPixelFormat; }
369 bool vboxUsesGuestVRAM() { return mUsesGuestVRAM; }
370
371 uchar *vboxAddress() { return mAddress; }
372 ulong vboxBitsPerPixel() { return mBitsPerPixel; }
373 ulong vboxBytesPerLine() { return mBytesPerLine; }
374
375 void vboxPaintEvent (QPaintEvent *pe);
376 void vboxResizeEvent (VBoxResizeEvent *re);
377
378protected:
379// void resizeGL (int height, int width);
380
381 void paintGL();
382
383 void initializeGL();
384
385private:
386 void vboxDoInitDisplay();
387 void vboxDoDeleteDisplay();
388 void vboxDoPerformDisplay() { Assert(mDisplayInitialized); glCallList(mDisplay); }
389
390 void vboxDoResize(VBoxResizeEvent *re);
391 void vboxDoPaint(const QRect *rec);
392
393 VBoxResizeEvent *mRe;
394 const QRect *mpIntersectionRect;
395 GLuint mDisplay;
396 bool mDisplayInitialized;
397 uchar * mAddress;
398 GLuint mTexture;
399
400 GLenum mFormat;
401 GLint mInternalFormat;
402 GLenum mType;
403 ulong mDisplayWidth;
404 ulong mDisplayHeight;
405 ulong mBitsPerPixel;
406 ulong mBytesPerPixel;
407 ulong mBytesPerLine;
408 ulong mPixelFormat;
409 bool mUsesGuestVRAM;
410};
411
412
413class VBoxQGLFrameBuffer : public VBoxFrameBuffer
414{
415public:
416
417 VBoxQGLFrameBuffer (VBoxConsoleView *aView);
418
419 STDMETHOD(NotifyUpdate) (ULONG aX, ULONG aY,
420 ULONG aW, ULONG aH);
421
422 ulong pixelFormat() { return vboxWidget()->vboxPixelFormat(); }
423 bool usesGuestVRAM() { return vboxWidget()->vboxUsesGuestVRAM(); }
424
425 uchar *address() { /*Assert(0); */return vboxWidget()->vboxAddress(); }
426 ulong bitsPerPixel() { return vboxWidget()->vboxBitsPerPixel(); }
427 ulong bytesPerLine() { return vboxWidget()->vboxBytesPerLine(); }
428
429 void paintEvent (QPaintEvent *pe);
430 void resizeEvent (VBoxResizeEvent *re);
431private:
432 void vboxMakeCurrent();
433 VBoxGLWidget * vboxWidget();
434};
435
436
437#endif
438
439/////////////////////////////////////////////////////////////////////////////
440
441#if defined (VBOX_GUI_USE_SDL)
442
443class VBoxSDLFrameBuffer : public VBoxFrameBuffer
444{
445public:
446
447 VBoxSDLFrameBuffer (VBoxConsoleView *aView);
448 virtual ~VBoxSDLFrameBuffer();
449
450 STDMETHOD(NotifyUpdate) (ULONG aX, ULONG aY,
451 ULONG aW, ULONG aH);
452
453 uchar *address()
454 {
455 SDL_Surface *surf = mSurfVRAM ? mSurfVRAM : mScreen;
456 return surf ? (uchar *) (uintptr_t) surf->pixels : 0;
457 }
458
459 ulong bitsPerPixel()
460 {
461 SDL_Surface *surf = mSurfVRAM ? mSurfVRAM : mScreen;
462 return surf ? surf->format->BitsPerPixel : 0;
463 }
464
465 ulong bytesPerLine()
466 {
467 SDL_Surface *surf = mSurfVRAM ? mSurfVRAM : mScreen;
468 return surf ? surf->pitch : 0;
469 }
470
471 ulong pixelFormat()
472 {
473 return mPixelFormat;
474 }
475
476 bool usesGuestVRAM()
477 {
478 return mSurfVRAM != NULL;
479 }
480
481 void paintEvent (QPaintEvent *pe);
482 void resizeEvent (VBoxResizeEvent *re);
483
484private:
485
486 SDL_Surface *mScreen;
487 SDL_Surface *mSurfVRAM;
488
489 ulong mPixelFormat;
490};
491
492#endif
493
494/////////////////////////////////////////////////////////////////////////////
495
496#if defined (VBOX_GUI_USE_DDRAW)
497
498class VBoxDDRAWFrameBuffer : public VBoxFrameBuffer
499{
500public:
501
502 VBoxDDRAWFrameBuffer (VBoxConsoleView *aView);
503 virtual ~VBoxDDRAWFrameBuffer();
504
505 STDMETHOD(NotifyUpdate) (ULONG aX, ULONG aY,
506 ULONG aW, ULONG aH);
507
508 uchar *address() { return (uchar *) mSurfaceDesc.lpSurface; }
509 ulong bitsPerPixel() { return mSurfaceDesc.ddpfPixelFormat.dwRGBBitCount; }
510 ulong bytesPerLine() { return (ulong) mSurfaceDesc.lPitch; }
511
512 ulong pixelFormat() { return mPixelFormat; };
513
514 bool usesGuestVRAM() { return mUsesGuestVRAM; }
515
516 void paintEvent (QPaintEvent *pe);
517 void resizeEvent (VBoxResizeEvent *re);
518 void moveEvent (QMoveEvent *me);
519
520private:
521
522 void releaseObjects();
523
524 bool createSurface (ULONG aPixelFormat, uchar *pvVRAM,
525 ULONG aBitsPerPixel, ULONG aBytesPerLine,
526 ULONG aWidth, ULONG aHeight);
527 void deleteSurface();
528 void drawRect (ULONG x, ULONG y, ULONG w, ULONG h);
529 void getWindowPosition (void);
530
531 LPDIRECTDRAW7 mDDRAW;
532 LPDIRECTDRAWCLIPPER mClipper;
533 LPDIRECTDRAWSURFACE7 mSurface;
534 DDSURFACEDESC2 mSurfaceDesc;
535 LPDIRECTDRAWSURFACE7 mPrimarySurface;
536
537 ulong mPixelFormat;
538
539 bool mUsesGuestVRAM;
540
541 int mWndX;
542 int mWndY;
543
544 bool mSynchronousUpdates;
545};
546
547#endif
548
549/////////////////////////////////////////////////////////////////////////////
550
551#if defined (Q_WS_MAC) && defined (VBOX_GUI_USE_QUARTZ2D)
552
553#include <Carbon/Carbon.h>
554
555class VBoxQuartz2DFrameBuffer : public VBoxFrameBuffer
556{
557public:
558
559 VBoxQuartz2DFrameBuffer (VBoxConsoleView *aView);
560 virtual ~VBoxQuartz2DFrameBuffer ();
561
562 STDMETHOD (NotifyUpdate) (ULONG aX, ULONG aY,
563 ULONG aW, ULONG aH);
564 STDMETHOD (SetVisibleRegion) (BYTE *aRectangles, ULONG aCount);
565
566 uchar *address() { return mDataAddress; }
567 ulong bitsPerPixel() { return CGImageGetBitsPerPixel (mImage); }
568 ulong bytesPerLine() { return CGImageGetBytesPerRow (mImage); }
569 ulong pixelFormat() { return mPixelFormat; };
570 bool usesGuestVRAM() { return mBitmapData == NULL; }
571
572 const CGImageRef imageRef() const { return mImage; }
573
574 void paintEvent (QPaintEvent *pe);
575 void resizeEvent (VBoxResizeEvent *re);
576
577private:
578
579 void clean();
580
581 uchar *mDataAddress;
582 void *mBitmapData;
583 ulong mPixelFormat;
584 CGImageRef mImage;
585 typedef struct
586 {
587 /** The size of this structure expressed in rcts entries. */
588 ULONG allocated;
589 /** The number of entries in the rcts array. */
590 ULONG used;
591 /** Variable sized array of the rectangle that makes up the region. */
592 CGRect rcts[1];
593 } RegionRects;
594 /** The current valid region, all access is by atomic cmpxchg or atomic xchg.
595 *
596 * The protocol for updating and using this has to take into account that
597 * the producer (SetVisibleRegion) and consumer (paintEvent) are running
598 * on different threads. Therefore the producer will create a new RegionRects
599 * structure before atomically replace the existing one. While the consumer
600 * will read the value by atomically replace it by NULL, and then when its
601 * done try restore it by cmpxchg. If the producer has already put a new
602 * region there, it will be discarded (see mRegionUnused).
603 */
604 RegionRects volatile *mRegion;
605 /** For keeping the unused region and thus avoid some RTMemAlloc/RTMemFree calls.
606 * This is operated with atomic cmpxchg and atomic xchg. */
607 RegionRects volatile *mRegionUnused;
608};
609
610#endif /* Q_WS_MAC && VBOX_GUI_USE_QUARTZ2D */
611
612#endif // !___VBoxFrameBuffer_h___
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette