VBoxFrameBuffer.h revision 213c11c77e9681d265b243e98dd33a6f8a827155
/** @file
*
* VBox frontends: Qt GUI ("VirtualBox"):
* VBoxFrameBuffer class and subclasses declarations
*/
/*
* Copyright (C) 2006-2007 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
#ifndef ___VBoxFrameBuffer_h___
#define ___VBoxFrameBuffer_h___
//#define VBOXQGL_PROF_BASE 1
//#define VBOXQGL_DBG_SURF 1
#include "COMDefs.h"
#include <iprt/critsect.h>
/* Qt includes */
#include <QImage>
#include <QPixmap>
#include <QMutex>
#include <QPaintEvent>
#include <QMoveEvent>
#if defined (VBOX_GUI_USE_QGL)
#include <QGLWidget>
#endif
#if defined (VBOX_GUI_USE_SDL)
#include <SDL.h>
#include <signal.h>
#endif
#if defined (Q_WS_WIN) && defined (VBOX_GUI_USE_DDRAW)
#include <ddraw.h>
#endif
/////////////////////////////////////////////////////////////////////////////
/**
* Frame buffer resize event.
*/
{
};
/**
* Frame buffer repaint event.
*/
{
VBoxRepaintEvent (int x, int y, int w, int h) :
{}
int x() { return ex; }
int y() { return ey; }
};
/**
* Frame buffer set region event.
*/
{
};
#ifdef VBOX_GUI_USE_QGL
typedef enum
{
{
{
}
{
}
{
switch(aType)
{
case VBOXVHWA_PIPECMD_PAINT:
break;
case VBOXVHWA_PIPECMD_VHWA:
break;
}
}
struct _VBOXVHWACMD * mpCmd;
};
{
{}
{
if(mpLast)
{
}
else
{
}
}
{
if(mpLast)
{
return pHead;
}
return NULL;
}
};
{
{
}
{
}
{
if(mpFirst)
{
return ret;
}
return NULL;
}
};
{
{
}
};
#endif
/////////////////////////////////////////////////////////////////////////////
/**
* Common IFramebuffer implementation for all methods used by GUI to maintain
* the VM display video memory.
*
* Note that although this class can be called from multiple threads
* (in particular, the GUI thread and EMT) it doesn't protect access to every
* data field using its mutex lock. This is because all synchronization between
* the GUI and the EMT thread is supposed to be done using the
* IFramebuffer::NotifyUpdate() and IFramebuffer::RequestResize() methods
* (in particular, the \a aFinished parameter of these methods is responsible
* for the synchronization). These methods are always called on EMT and
* therefore always follow one another but never in parallel.
*
* Using this object's mutex lock (exposed also in IFramebuffer::Lock() and
* IFramebuffer::Unlock() implementations) usually makes sense only if some
* third-party thread (i.e. other than GUI or EMT) needs to make sure that
* *no* VM display update or resize event can occur while it is accessing
* IFramebuffer properties or the underlying display memory storage area.
*
* See IFramebuffer documentation for more info.
*/
{
#if defined (Q_OS_WIN32)
{
return ::InterlockedIncrement (&refcnt);
}
{
if (cnt == 0)
return cnt;
}
#endif
// IFramebuffer COM methods
BOOL *aSupported);
{
}
virtual bool usesGuestVRAM()
{
return false;
}
/**
* Called on the GUI thread (from VBoxConsoleView) when some part of the
* VM display viewport needs to be repainted on the host screen.
*/
/**
* Called on the GUI thread (from VBoxConsoleView) after it gets a
* VBoxResizeEvent posted from the RequestResize() method implementation.
*/
{
}
/**
* Called on the GUI thread (from VBoxConsoleView) when the VM console
* window is moved.
*/
#ifdef VBOX_GUI_USE_QGL
/* this method is called from the GUI thread
* to perform the actual Video HW Acceleration command processing */
#endif
int mWdt;
int mHgt;
#if defined (Q_OS_WIN32)
long refcnt;
#endif
};
/////////////////////////////////////////////////////////////////////////////
#if defined (VBOX_GUI_USE_QIMAGE)
{
bool usesGuestVRAM() { return mUsesGuestVRAM; }
bool mUsesGuestVRAM;
};
#endif
/////////////////////////////////////////////////////////////////////////////
#if defined (VBOX_GUI_USE_QGL)
#ifdef DEBUG
#else
#define VBOXQGLLOG(_m)
#endif
#define VBOXQGLLOG_ENTER(_m)
//do{VBOXQGLLOG(("==>[%s]:", __FUNCTION__)); VBOXQGLLOG(_m);}while(0)
#define VBOXQGLLOG_EXIT(_m)
//do{VBOXQGLLOG(("<==[%s]:", __FUNCTION__)); VBOXQGLLOG(_m);}while(0)
#ifdef DEBUG
#define VBOXQGL_ASSERTNOERR() \
}while(0)
#define VBOXQGL_CHECKERR(_op) \
do { \
glGetError(); \
_op \
VBOXQGL_ASSERTNOERR(); \
}while(0)
#else
#define VBOXQGL_ASSERTNOERR() \
do {}while(0)
#define VBOXQGL_CHECKERR(_op) \
do { \
_op \
}while(0)
#endif
#ifdef DEBUG
#define VBOXGETTIME() RTTimeNanoTS()
VBOXQGLLOG(_m); \
}while(0)
{
const char* mMsg;
};
#else
#define VBOXQGLLOG_METHODTIME(_m)
#endif
VBOXQGLLOG((_p " x(%d), y(%d), w(%d), h(%d)" _s, (_pr)->x(), (_pr)->y(), (_pr)->width(), (_pr)->height()));\
}while(0)
}while(0)
{
mIsClear(true)
{}
{
{
mIsClear = false;
}
else
{
mIsClear = true;
}
}
{
return;
mIsClear = false;
}
{
return;
}
{
{
mIsClear = true;
}
else
{
mIsClear = false;
}
}
bool intersects(const VBoxVHWADirtyRect & aRect) const {return mIsClear ? false : aRect.intersects(mRect);}
bool mIsClear;
};
{
VBoxVHWAColorKey() :
mUpper(0),
mLower(0)
{}
{}
bool operator==(const VBoxVHWAColorKey & other) const { return mUpper == other.mUpper && mLower == other.mLower; }
};
{
mMask(0),
mRange(0),
mOffset(32),
mcBits(0)
{}
};
{
// VBoxVHWAColorFormat(GLint aInternalFormat, GLenum aFormat, GLenum aType, uint32_t aDataFormat);
bool isValid() const {return mBitsPerPixel != 0; }
// uint32_t bitsPerPixelDd() const { return mBitsPerPixelDd; }
// uint32_t r(uint32_t pix);
// uint32_t g(uint32_t pix);
// uint32_t b(uint32_t pix);
// uint32_t mBitsPerPixelDd;
};
{
VBoxVHWATexture() {}
// GLuint texture() {return mTexture;}
uint32_t rectSizeTex(const QRect * pRect) {return pRect->width() * pRect->height() * mBytesPerPixelTex;}
uchar * pointAddress(int x, int y)
{
x = toXTex(x);
y = toYTex(y);
return pointAddressTex(x, y);
}
virtual void initParams();
void uninit();
};
{
VBoxVHWATextureNP2() : VBoxVHWATexture() {}
mTexRect = QRect(0, 0, pRect->width()/pFormat->widthCompression(), pRect->height()/pFormat->heightCompression());
}
};
{
VBoxVHWATextureNP2Rect() : VBoxVHWATextureNP2() {}
};
{
};
/* data flow:
* I. NON-Yinverted surface:
* mem->tex->fb
* 2.blt
* srcTex->invFB->tex->fb
* |->mem
*
* II. Yinverted surface:
* mem->tex->fb
* 2.blt
* srcTex->fb->tex
* |->mem
*
* III. flip support:
* 1. Yinverted<->NON-YInverted conversion :
* mem->tex-(rotate model view, force LAZY complete fb update)->invFB->tex
* fb-->| |->mem
* */
{
#if 0
bool aIsYInverted,
#endif
bool bVGA);
void uninit();
static void globalInit();
// int blt(const QRect * aDstRect, VBoxVHWASurfaceBase * aSrtSurface, const QRect * aSrcRect, const VBoxVHWAColorKey * pDstCKeyOverride, const VBoxVHWAColorKey * pSrcCKeyOverride);
// int overlay(VBoxVHWASurfaceBase * aOverlaySurface);
int unlock();
bool addressAlocated() const { return mFreeAddress; }
// ulong bytesPerPixel() { return mpTex[0]->bytesPerPixel(); }
// ulong bitsPerPixelDd() { return mColorFormat.bitsPerPixelDd(); }
{
if(ckey)
{
mDstBltCKey = *ckey;
}
else
{
mpDstBltCKey = NULL;
}
}
{
if(ckey)
{
mSrcBltCKey = *ckey;
}
else
{
mpSrcBltCKey = NULL;
}
}
{
if(ckey)
{
}
else
{
}
}
{
if(ckey)
{
}
else
{
}
}
{
if(ckey)
{
}
else
{
}
}
{
if(ckey)
{
}
else
{
}
}
const VBoxVHWAColorKey * getActiveSrcOverlayCKey()
{
return mpSrcOverlayCKey;
}
{
}
/* clients should treat the returned texture as read-only */
// GLuint textureSynched(const QRect * aRect) { /*synchTex(aRect); */synchTexMem(aRect); return mTexture; }
// const QRect& texRect() {return mTexRect;}
// /* surface currently being displayed in a flip chain */
// virtual bool isPrimary() = 0;
// /* surface representing the main framebuffer. */
// virtual bool isMainFramebuffer() = 0;
#if 0
virtual void makeCurrent() = 0;
virtual void makeYInvertedCurrent() = 0;
bool isYInverted() {return mIsYInverted; }
bool isHidden() {return mIsYInverted; }
{
if(hidden == mIsYInverted)
return;
invert();
}
int invert();
bool isFrontBuffer() {return !mIsYInverted; }
#endif
static int setCKey(class VBoxVHWAGlProgramVHWA * pProgram, const VBoxVHWAColorFormat * pFormat, const VBoxVHWAColorKey * pCKey, bool bDst);
void deleteDisplay();
// void initDisplay(bool bInverted);
// void deleteDisplay(bool bInverted);
#if 0
bool bInverted
#endif
);
#if 0
#endif
int performBlt(const QRect * pDstRect, VBoxVHWASurfaceBase * pSrcSurface, const QRect * pSrcRect, const VBoxVHWAColorKey * pDstCKey, const VBoxVHWAColorKey * pSrcCKey, bool blt);
// void doTex2FB(const QRect * aRect);
void doMultiTex2FB(const QRect * pDstRect, VBoxVHWATexture * pDstTex, const QRect * pSrcRect, int cSrcTex);
// void doMultiTex2FB(GLenum tex, const QRect * pDstRect, const QRect * pSrcRect);
// QRect mTexRect; /* texture size */
#if 0
#endif
#if 0
#endif
// GLenum mFormat;
// GLint mInternalFormat;
// GLenum mType;
// ulong mDisplayWidth;
// ulong mDisplayHeight;
// ulong mBytesPerPixel;
// ulong mBytesPerLine;
int mLockCount;
/* memory buffer not reflected in fm and texture, e.g if memory buffer is replaced or in case of lock/unlock */
#if 0
/* memory buffer not reflected in fm and texture, e.g if memory buffer is replaced or in case of lock/unlock */
/*in case of blit we blit from another surface's texture, so our current texture gets durty */
/*in case of blit the memory buffer does not get updated until we need it, e.g. for paint or lock operations */
#endif
bool mFreeAddress;
#if 0
bool mIsYInverted;
#endif
#if 0
#endif
};
{
{
if(pOld)
{
}
}
void clear()
{
{
}
}
{
}
{
}
};
{
VBoxVHWADisplay() :
// ,
// mSurfPrimary(NULL)
{}
{
if(pVga)
{
}
// mSurfPrimary = pVga;
return old;
}
{
return mSurfVGA;
}
{
}
//
// void setPrimary(VBoxVHWASurfList * pSurf)
// {
// mSurfPrimary = pSurf;
// }
{
}
{
if(!hasOverlay(pSurf))
}
{
{
{
return true;
}
}
return false;
}
{
}
void performDisplay()
{
{
if(pOverlay)
{
// pPrimary->overlay(pOverlay);
}
}
}
};
{
~VBoxGLWidget();
bool vboxUsesGuestVRAM() { return mUsesGuestVRAM; }
#ifdef VBOX_WITH_VIDEOHWACCEL
#endif
typedef void (VBoxGLWidget::*PFNVBOXQGLOP)(void* );
//typedef FNVBOXQGLOP *PFNVBOXQGLOP;
//#ifdef VBOXQGL_DBG_SURF
// void vboxTestSurfaces () {vboxPerformGLOp(&VBoxGLWidget::vboxDoTestSurfaces, NULL);}
//#endif
void vboxProcessVHWACommands(VBoxVHWACommandProcessEvent * pEvent) {vboxPerformGLOp(&VBoxGLWidget::vboxDoProcessVHWACommands, pEvent);}
#ifdef VBOX_WITH_VIDEOHWACCEL
void vboxVHWACmd (struct _VBOXVHWACMD * pCmd) {vboxPerformGLOp(&VBoxGLWidget::vboxDoVHWACmd, pCmd);}
#endif
// void resizeGL (int height, int width);
void paintGL()
{
// Assert(mState.getCurrent() == NULL);
// /* we are called with QGLWidget context */
// mState.assertCurrent(mDisplay.getVGA(), false);
if(mpfnOp)
{
}
else
{
}
// /* restore the context */
// mState.makeCurrent(mDisplay.getVGA());
// /* clear*/
// mState.assertCurrent(NULL, false);
}
void initializeGL();
// void vboxDoInitDisplay();
// void vboxDoDeleteDisplay();
// void vboxDoPerformDisplay() { Assert(mDisplayInitialized); glCallList(mDisplay); }
void vboxDoResize(void *re);
void vboxDoPaint(void *rec);
#ifdef VBOXQGL_DBG_SURF
void vboxDoTestSurfaces(void *context);
#endif
#ifdef VBOX_WITH_VIDEOHWACCEL
void vboxDoVHWACmd(void *cmd);
{
#ifndef VBOXQGL_DBG_SURF
if(offset == 0xffffffff)
{
return;
}
#endif
if (pSurface->addressAlocated())
{
if(addr)
{
}
}
}
void vhwaDoSurfaceOverlayUpdate(VBoxVHWASurfaceBase *pDstSurf, VBoxVHWASurfaceBase *pSrcSurf, struct _VBOXVHWACMD_SURF_OVERLAY_UPDATE *pCmd);
#endif
static const QGLFormat & vboxGLFormat();
// VBoxVHWASurfaceQGL * pDisplay;
/* we need to do all opengl stuff in the paintGL context,
* submit the operation to be performed */
void vboxPerformGLOp(PFNVBOXQGLOP pfn, void* pContext) {mpfnOp = pfn; mOpContext = pContext; updateGL();}
void cmdPipeInit();
void cmdPipeDelete();
void vboxDoProcessVHWACommands(void *pContext);
VBoxVHWACommandElement * detachCmdList(VBoxVHWACommandElement * pFirst2Free, VBoxVHWACommandElement * pLast2Free);
void *mOpContext;
// ulong mBitsPerPixel;
bool mUsesGuestVRAM;
#if 0
#endif
bool mbNewEvent;
};
{
#ifdef VBOXQGL_PROF_BASE
#endif
#ifdef VBOX_WITH_VIDEOHWACCEL
#endif
// void vboxMakeCurrent();
VBoxGLWidget * vboxWidget();
};
#endif
/////////////////////////////////////////////////////////////////////////////
#if defined (VBOX_GUI_USE_SDL)
{
{
}
{
}
{
}
{
return mPixelFormat;
}
bool usesGuestVRAM()
{
}
};
#endif
/////////////////////////////////////////////////////////////////////////////
#if defined (VBOX_GUI_USE_DDRAW)
{
bool usesGuestVRAM() { return mUsesGuestVRAM; }
void releaseObjects();
void deleteSurface();
void getWindowPosition (void);
bool mUsesGuestVRAM;
int mWndX;
int mWndY;
bool mSynchronousUpdates;
};
#endif
/////////////////////////////////////////////////////////////////////////////
#if defined (Q_WS_MAC) && defined (VBOX_GUI_USE_QUARTZ2D)
{
void clean();
void *mBitmapData;
typedef struct
{
/** The size of this structure expressed in rcts entries. */
/** The number of entries in the rcts array. */
/** Variable sized array of the rectangle that makes up the region. */
} RegionRects;
/** The current valid region, all access is by atomic cmpxchg or atomic xchg.
*
* The protocol for updating and using this has to take into account that
* the producer (SetVisibleRegion) and consumer (paintEvent) are running
* on different threads. Therefore the producer will create a new RegionRects
* structure before atomically replace the existing one. While the consumer
* will read the value by atomically replace it by NULL, and then when its
* done try restore it by cmpxchg. If the producer has already put a new
* region there, it will be discarded (see mRegionUnused).
*/
RegionRects volatile *mRegion;
/** For keeping the unused region and thus avoid some RTMemAlloc/RTMemFree calls.
* This is operated with atomic cmpxchg and atomic xchg. */
RegionRects volatile *mRegionUnused;
};
#endif /* Q_WS_MAC && VBOX_GUI_USE_QUARTZ2D */
#endif // !___VBoxFrameBuffer_h___