VirtualBox

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

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

Video HW Accel: surface handling basics for QGLFrameBuffer

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.9 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
269#ifdef VBOX_WITH_VIDEOHWACCEL
270 /* this method is called from the GUI thread
271 * to perform the actual Video HW Acceleration command processing */
272 virtual void doProcessVHWACommand(struct _VBOXVHWACMD * pCommand);
273#endif
274
275protected:
276
277 VBoxConsoleView *mView;
278 RTCRITSECT mCritSect;
279 int mWdt;
280 int mHgt;
281 uint64_t mWinId;
282
283#if defined (Q_OS_WIN32)
284private:
285 long refcnt;
286#endif
287};
288
289/////////////////////////////////////////////////////////////////////////////
290
291#if defined (VBOX_GUI_USE_QIMAGE)
292
293class VBoxQImageFrameBuffer : public VBoxFrameBuffer
294{
295public:
296
297 VBoxQImageFrameBuffer (VBoxConsoleView *aView);
298
299 STDMETHOD(NotifyUpdate) (ULONG aX, ULONG aY,
300 ULONG aW, ULONG aH);
301
302 ulong pixelFormat() { return mPixelFormat; }
303 bool usesGuestVRAM() { return mUsesGuestVRAM; }
304
305 uchar *address() { return mImg.bits(); }
306 ulong bitsPerPixel() { return mImg.depth(); }
307 ulong bytesPerLine() { return mImg.bytesPerLine(); }
308
309 void paintEvent (QPaintEvent *pe);
310 void resizeEvent (VBoxResizeEvent *re);
311
312private:
313
314 QPixmap mPM;
315 QImage mImg;
316 ulong mPixelFormat;
317 bool mUsesGuestVRAM;
318};
319
320#endif
321
322/////////////////////////////////////////////////////////////////////////////
323
324#if defined (VBOX_GUI_USE_QGL)
325
326class VBoxVHWASurfaceBase
327{
328public:
329 VBoxVHWASurfaceBase(GLsizei aWidth, GLsizei aHeight,
330 GLint aInternalFormat, GLenum aFormat, GLenum aType);
331
332 virtual ~VBoxVHWASurfaceBase();
333
334 virtual void init(uchar *pvMem);
335
336 virtual void uninit();
337
338 static void globalInit();
339
340 int blt(VBoxVHWASurfaceBase * pToSurface, QRect * pSrcRect, QRect * pDstRect);
341
342 int lock(QRect * pRect);
343
344 int unlock();
345
346 virtual void makeCurrent() = 0;
347
348 void paint(const QRect * pRect);
349
350 void performDisplay() { Assert(mDisplayInitialized); glCallList(mDisplay); }
351
352 static ulong calcBytesPerPixel(GLenum format, GLenum type);
353
354 static GLsizei makePowerOf2(GLsizei val);
355
356 uchar * address(){ return mAddress; }
357 ulong bufferSize(){ return mBytesPerLine * mDisplayHeight; }
358
359 ulong width() { return mDisplayWidth; }
360 ulong height() { return mDisplayHeight; }
361
362 GLenum format() {return mFormat; }
363 GLint internalFormat() { return mInternalFormat; }
364 GLenum type() { return mType; }
365 ulong bytesPerPixel() { return mBytesPerPixel; }
366 ulong bytesPerLine() { return mBytesPerLine; }
367
368private:
369 void initDisplay();
370 void deleteDisplay();
371 void updateTexture(const QRect * pRect);
372
373 GLuint mDisplay;
374 bool mDisplayInitialized;
375
376 uchar * mAddress;
377 GLuint mTexture;
378
379 GLenum mFormat;
380 GLint mInternalFormat;
381 GLenum mType;
382 ulong mDisplayWidth;
383 ulong mDisplayHeight;
384 ulong mBytesPerPixel;
385 ulong mBytesPerLine;
386
387 QRect mLockedRect;
388 bool mLocked;
389 bool mFreeAddress;
390};
391
392class VBoxVHWASurfacePrimary : public VBoxVHWASurfaceBase
393{
394public:
395 VBoxVHWASurfacePrimary(GLsizei aWidth, GLsizei aHeight,
396 GLint aInternalFormat, GLenum aFormat, GLenum aType,
397 class VBoxGLWidget *pWidget) :
398 VBoxVHWASurfaceBase(aWidth, aHeight,
399 aInternalFormat, aFormat, aType),
400 mWidget(pWidget)
401 {}
402
403 void makeCurrent();
404private:
405 class VBoxGLWidget *mWidget;
406};
407
408class VBoxGLWidget : public QGLWidget
409{
410public:
411 VBoxGLWidget (QWidget *aParent)
412 : QGLWidget (aParent),
413 pDisplay(NULL),
414 mRe(NULL),
415 mpIntersectionRect(NULL),
416 mBitsPerPixel(0),
417 mPixelFormat(0),
418 mUsesGuestVRAM(false)
419 {
420// /* No need for background drawing */
421// setAttribute (Qt::WA_OpaquePaintEvent);
422 }
423
424 ulong vboxPixelFormat() { return mPixelFormat; }
425 bool vboxUsesGuestVRAM() { return mUsesGuestVRAM; }
426
427 uchar *vboxAddress() { return pDisplay ? pDisplay->address() : NULL; }
428 ulong vboxBitsPerPixel() { return mBitsPerPixel; }
429 ulong vboxBytesPerLine() { return pDisplay ? pDisplay->bytesPerLine() : NULL; }
430
431 void vboxPaintEvent (QPaintEvent *pe);
432 void vboxResizeEvent (VBoxResizeEvent *re);
433
434protected:
435// void resizeGL (int height, int width);
436
437 void paintGL();
438
439 void initializeGL();
440
441private:
442// void vboxDoInitDisplay();
443// void vboxDoDeleteDisplay();
444// void vboxDoPerformDisplay() { Assert(mDisplayInitialized); glCallList(mDisplay); }
445
446 void vboxDoResize(VBoxResizeEvent *re);
447 void vboxDoPaint(const QRect *rec);
448 VBoxVHWASurfacePrimary * pDisplay;
449
450 VBoxResizeEvent *mRe;
451 const QRect *mpIntersectionRect;
452 ulong mBitsPerPixel;
453 ulong mPixelFormat;
454 bool mUsesGuestVRAM;
455};
456
457
458class VBoxQGLFrameBuffer : public VBoxFrameBuffer
459{
460public:
461
462 VBoxQGLFrameBuffer (VBoxConsoleView *aView);
463
464 STDMETHOD(NotifyUpdate) (ULONG aX, ULONG aY,
465 ULONG aW, ULONG aH);
466
467#ifdef VBOX_WITH_VIDEOHWACCEL
468 STDMETHOD(ProcessVHWACommand)(BYTE *pCommand);
469#endif
470
471 ulong pixelFormat() { return vboxWidget()->vboxPixelFormat(); }
472 bool usesGuestVRAM() { return vboxWidget()->vboxUsesGuestVRAM(); }
473
474 uchar *address() { /*Assert(0); */return vboxWidget()->vboxAddress(); }
475 ulong bitsPerPixel() { return vboxWidget()->vboxBitsPerPixel(); }
476 ulong bytesPerLine() { return vboxWidget()->vboxBytesPerLine(); }
477
478 void paintEvent (QPaintEvent *pe);
479 void resizeEvent (VBoxResizeEvent *re);
480#ifdef VBOX_WITH_VIDEOHWACCEL
481 void doProcessVHWACommand(struct _VBOXVHWACMD * pCommand);
482#endif
483
484private:
485 void vboxMakeCurrent();
486 VBoxGLWidget * vboxWidget();
487};
488
489
490#endif
491
492/////////////////////////////////////////////////////////////////////////////
493
494#if defined (VBOX_GUI_USE_SDL)
495
496class VBoxSDLFrameBuffer : public VBoxFrameBuffer
497{
498public:
499
500 VBoxSDLFrameBuffer (VBoxConsoleView *aView);
501 virtual ~VBoxSDLFrameBuffer();
502
503 STDMETHOD(NotifyUpdate) (ULONG aX, ULONG aY,
504 ULONG aW, ULONG aH);
505
506 uchar *address()
507 {
508 SDL_Surface *surf = mSurfVRAM ? mSurfVRAM : mScreen;
509 return surf ? (uchar *) (uintptr_t) surf->pixels : 0;
510 }
511
512 ulong bitsPerPixel()
513 {
514 SDL_Surface *surf = mSurfVRAM ? mSurfVRAM : mScreen;
515 return surf ? surf->format->BitsPerPixel : 0;
516 }
517
518 ulong bytesPerLine()
519 {
520 SDL_Surface *surf = mSurfVRAM ? mSurfVRAM : mScreen;
521 return surf ? surf->pitch : 0;
522 }
523
524 ulong pixelFormat()
525 {
526 return mPixelFormat;
527 }
528
529 bool usesGuestVRAM()
530 {
531 return mSurfVRAM != NULL;
532 }
533
534 void paintEvent (QPaintEvent *pe);
535 void resizeEvent (VBoxResizeEvent *re);
536
537private:
538
539 SDL_Surface *mScreen;
540 SDL_Surface *mSurfVRAM;
541
542 ulong mPixelFormat;
543};
544
545#endif
546
547/////////////////////////////////////////////////////////////////////////////
548
549#if defined (VBOX_GUI_USE_DDRAW)
550
551class VBoxDDRAWFrameBuffer : public VBoxFrameBuffer
552{
553public:
554
555 VBoxDDRAWFrameBuffer (VBoxConsoleView *aView);
556 virtual ~VBoxDDRAWFrameBuffer();
557
558 STDMETHOD(NotifyUpdate) (ULONG aX, ULONG aY,
559 ULONG aW, ULONG aH);
560
561 uchar *address() { return (uchar *) mSurfaceDesc.lpSurface; }
562 ulong bitsPerPixel() { return mSurfaceDesc.ddpfPixelFormat.dwRGBBitCount; }
563 ulong bytesPerLine() { return (ulong) mSurfaceDesc.lPitch; }
564
565 ulong pixelFormat() { return mPixelFormat; };
566
567 bool usesGuestVRAM() { return mUsesGuestVRAM; }
568
569 void paintEvent (QPaintEvent *pe);
570 void resizeEvent (VBoxResizeEvent *re);
571 void moveEvent (QMoveEvent *me);
572
573private:
574
575 void releaseObjects();
576
577 bool createSurface (ULONG aPixelFormat, uchar *pvVRAM,
578 ULONG aBitsPerPixel, ULONG aBytesPerLine,
579 ULONG aWidth, ULONG aHeight);
580 void deleteSurface();
581 void drawRect (ULONG x, ULONG y, ULONG w, ULONG h);
582 void getWindowPosition (void);
583
584 LPDIRECTDRAW7 mDDRAW;
585 LPDIRECTDRAWCLIPPER mClipper;
586 LPDIRECTDRAWSURFACE7 mSurface;
587 DDSURFACEDESC2 mSurfaceDesc;
588 LPDIRECTDRAWSURFACE7 mPrimarySurface;
589
590 ulong mPixelFormat;
591
592 bool mUsesGuestVRAM;
593
594 int mWndX;
595 int mWndY;
596
597 bool mSynchronousUpdates;
598};
599
600#endif
601
602/////////////////////////////////////////////////////////////////////////////
603
604#if defined (Q_WS_MAC) && defined (VBOX_GUI_USE_QUARTZ2D)
605
606#include <Carbon/Carbon.h>
607
608class VBoxQuartz2DFrameBuffer : public VBoxFrameBuffer
609{
610public:
611
612 VBoxQuartz2DFrameBuffer (VBoxConsoleView *aView);
613 virtual ~VBoxQuartz2DFrameBuffer ();
614
615 STDMETHOD (NotifyUpdate) (ULONG aX, ULONG aY,
616 ULONG aW, ULONG aH);
617 STDMETHOD (SetVisibleRegion) (BYTE *aRectangles, ULONG aCount);
618
619 uchar *address() { return mDataAddress; }
620 ulong bitsPerPixel() { return CGImageGetBitsPerPixel (mImage); }
621 ulong bytesPerLine() { return CGImageGetBytesPerRow (mImage); }
622 ulong pixelFormat() { return mPixelFormat; };
623 bool usesGuestVRAM() { return mBitmapData == NULL; }
624
625 const CGImageRef imageRef() const { return mImage; }
626
627 void paintEvent (QPaintEvent *pe);
628 void resizeEvent (VBoxResizeEvent *re);
629
630private:
631
632 void clean();
633
634 uchar *mDataAddress;
635 void *mBitmapData;
636 ulong mPixelFormat;
637 CGImageRef mImage;
638 typedef struct
639 {
640 /** The size of this structure expressed in rcts entries. */
641 ULONG allocated;
642 /** The number of entries in the rcts array. */
643 ULONG used;
644 /** Variable sized array of the rectangle that makes up the region. */
645 CGRect rcts[1];
646 } RegionRects;
647 /** The current valid region, all access is by atomic cmpxchg or atomic xchg.
648 *
649 * The protocol for updating and using this has to take into account that
650 * the producer (SetVisibleRegion) and consumer (paintEvent) are running
651 * on different threads. Therefore the producer will create a new RegionRects
652 * structure before atomically replace the existing one. While the consumer
653 * will read the value by atomically replace it by NULL, and then when its
654 * done try restore it by cmpxchg. If the producer has already put a new
655 * region there, it will be discarded (see mRegionUnused).
656 */
657 RegionRects volatile *mRegion;
658 /** For keeping the unused region and thus avoid some RTMemAlloc/RTMemFree calls.
659 * This is operated with atomic cmpxchg and atomic xchg. */
660 RegionRects volatile *mRegionUnused;
661};
662
663#endif /* Q_WS_MAC && VBOX_GUI_USE_QUARTZ2D */
664
665#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