VBoxFBOverlay.h revision 8bf8c6b1914c9e7e60b1547888400668f1774497
/** @file
*
* VBox frontends: Qt GUI ("VirtualBox"):
* VBoxFrameBuffer Overly classes declarations
*/
/*
* Copyright (C) 2006-2007 Oracle Corporation
*
* 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.
*/
#ifndef __VBoxFBOverlay_h__
#define __VBoxFBOverlay_h__
#if defined (VBOX_GUI_USE_QGL) || defined(VBOX_WITH_VIDEOHWACCEL)
//#define VBOXQGL_PROF_BASE 1
//#define VBOXQGL_DBG_SURF 1
//#define VBOXVHWADBG_RENDERCHECK
/* Qt includes: */
#include <QGLWidget>
/* GUI includes: */
#include "VBoxFBOverlayCommon.h"
/* COM includes: */
#include "COMEnums.h"
#include "CSession.h"
/* Other VBox includes: */
#include <iprt/critsect.h>
#include <VBox/VBoxGL2D.h>
#define VBOXVHWA_ALLOW_PRIMARY_AND_OVERLAY_ONLY 1
#ifdef DEBUG_misha
# define VBOXVHWA_PROFILE_FPS
#endif
#ifdef VBOXVHWA_PROFILE_FPS
#endif
#ifdef DEBUG
{
~VBoxVHWADbgTimer();
void frame();
};
#endif
{
int fourccEnabledCount() const { return mFourccEnabledCount; }
bool isStretchLinearEnabled() const { return mStretchLinearEnabled; }
static int calcIntersection (int c1, const uint32_t *a1, int c2, const uint32_t *a2, int cOut, uint32_t *aOut);
{
return calcIntersection (mFourccEnabledCount, mFourccEnabledList, aInfo.getFourccSupportedCount(), aInfo.getFourccSupportedList(), cOut, aOut);
}
{
&& calcIntersection (aInfo.getFourccSupportedCount(), aInfo.getFourccSupportedList(), 1, &format, 0, NULL);
}
int mFourccEnabledCount;
bool mStretchLinearEnabled;
};
{
mIsClear(true)
{}
{
{
mIsClear = false;
}
else
{
mIsClear = true;
}
}
{
return;
mIsClear = false;
}
{
return;
}
{
{
mIsClear = true;
}
else
{
mIsClear = false;
}
}
{
if(isClear())
{
}
return mRect;
}
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)
{}
};
{
mBitsPerPixel(0) /* needed for isValid() to work */
{}
bool isValid() const {return mBitsPerPixel != 0; }
const VBoxVHWAColorComponent& r() const {return mR;}
const VBoxVHWAColorComponent& g() const {return mG;}
const VBoxVHWAColorComponent& b() const {return mB;}
const VBoxVHWAColorComponent& a() const {return mA;}
ulong toVBoxPixelFormat() const
{
if (!mDataFormat)
{
/* RGB data */
switch (mFormat)
{
case GL_BGRA_EXT:
}
}
return FramebufferPixelFormat_Opaque;
}
};
{
VBoxVHWATexture() :
mTexture(0),
mBytesPerPixel(0),
mBytesPerLine(0),
{}
VBoxVHWATexture(const QRect & aRect, const VBoxVHWAColorFormat &aFormat, uint32_t bytesPerLine, GLint scaleFuncttion);
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);
}
#ifdef DEBUG_misha
void dbgDump();
#endif
virtual void initParams();
void uninit();
};
{
VBoxVHWATextureNP2() : VBoxVHWATexture() {}
VBoxVHWATextureNP2(const QRect & aRect, const VBoxVHWAColorFormat &aFormat, uint32_t bytesPerLine, GLint scaleFuncttion) :
mTexRect = QRect(0, 0, aRect.width()/aFormat.widthCompression(), aRect.height()/aFormat.heightCompression());
}
};
{
VBoxVHWATextureNP2Rect() : VBoxVHWATextureNP2() {}
VBoxVHWATextureNP2Rect(const QRect & aRect, const VBoxVHWAColorFormat &aFormat, uint32_t bytesPerLine, GLint scaleFuncttion) :
};
{
mPBO(0)
{}
VBoxVHWATextureNP2RectPBO(const QRect & aRect, const VBoxVHWAColorFormat &aFormat, uint32_t bytesPerLine, GLint scaleFuncttion) :
mPBO(0)
{}
};
{
mcbOffset(0)
{}
VBoxVHWATextureNP2RectPBOMapped(const QRect & aRect, const VBoxVHWAColorFormat &aFormat, uint32_t bytesPerLine, GLint scaleFuncttion) :
mcbOffset(0)
{
}
void unmapBuffer();
{
}
static size_t calcOffset(void* pvBase, void* pvOffset) { return (size_t)(((uintptr_t)pvBase) - ((uintptr_t)pvOffset)); }
};
#define VBOXVHWAIMG_PBO 0x00000001U
#define VBOXVHWAIMG_PBOIMG 0x00000002U
#define VBOXVHWAIMG_FBO 0x00000004U
#define VBOXVHWAIMG_LINEAR 0x00000008U
typedef uint32_t VBOXVHWAIMG_TYPE;
{
VBoxVHWATextureImage(const QRect &size, const VBoxVHWAColorFormat &format, class VBoxVHWAGlProgramMngr * aMgr, VBOXVHWAIMG_TYPE flags);
{
{
}
}
{
{
}
}
{
{
if(pRect)
{
}
else
{
}
}
}
void deleteDisplay();
bool displayInitialized() { return !!mVisibleDisplay;}
{
{
}
}
{
}
{
{
}
return size;
}
bool notIntersectedMode() { return mbNotIntersected; }
#ifdef DEBUG_misha
void dbgDump();
#endif
static int setCKey(class VBoxVHWAGlProgramVHWA * pProgram, const VBoxVHWAColorFormat * pFormat, const VBoxVHWAColorKey * pCKey, bool bDst);
{
}
{
}
{
uint32_t c = 1;
{
int x2 = x/2;
int y2 = y/2;
++c;
}
return c;
}
virtual uint32_t calcProgramType(VBoxVHWATextureImage *pDst, const VBoxVHWAColorKey * pDstCKey, const VBoxVHWAColorKey * pSrcCKey, bool bNotIntersected);
virtual class VBoxVHWAGlProgramVHWA * calcProgram(VBoxVHWATextureImage *pDst, const VBoxVHWAColorKey * pDstCKey, const VBoxVHWAColorKey * pSrcCKey, bool bNotIntersected);
virtual int createDisplay(VBoxVHWATextureImage *pDst, const QRect * pDstRect, const QRect * pSrcRect,
virtual int createDisplayList(VBoxVHWATextureImage *pDst, const QRect * pDstRect, const QRect * pSrcRect,
virtual void deleteDisplayList();
virtual void updateCKeys(VBoxVHWATextureImage * pDst, class VBoxVHWAGlProgramVHWA * pProgram, const VBoxVHWAColorKey * pDstCKey, const VBoxVHWAColorKey * pSrcCKey);
/* display info */
bool mbNotIntersected;
};
{
VBoxVHWATextureImagePBO(const QRect &size, const VBoxVHWAColorFormat &format, class VBoxVHWAGlProgramMngr * aMgr, VBOXVHWAIMG_TYPE flags) :
mPBO(0)
{
}
{
if(mPBO)
{
);
}
}
{
);
);
);
if(buf)
{
}
}
{
);
);
if(buf)
{
#ifdef VBOXVHWADBG_RENDERCHECK
{
{
}
}
#else
#endif
bool unmapped;
);
}
else
{
VBOXQGLLOGREL(("failed to map PBO, trying fallback to non-PBO approach\n"));
}
}
{
}
};
{
void** mTable;
};
/* 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
* */
{
const QRect & aVisTargRect,
void uninit();
static void globalInit();
int unlock();
void updateVisibility (VBoxVHWASurfaceBase *pPrimary, const QRect & aVisibleTargRect, bool bNotIntersected, bool bForce);
bool addressAlocated() const { return mFreeAddress; }
{
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;
}
{
}
void initDisplay();
int performBlt (const QRect * pDstRect, VBoxVHWASurfaceBase * pSrcSurface, const QRect * pSrcRect, const VBoxVHWAColorKey * pDstCKey, const VBoxVHWAColorKey * pSrcCKey, bool blt);
int mLockCount;
/* memory buffer not reflected in fm and texture, e.g if memory buffer is replaced or in case of lock/unlock */
bool mFreeAddress;
bool mbNotIntersected;
#ifdef DEBUG
#endif
};
{
{
if(pOld)
{
}
}
void clear()
{
{
}
}
{
}
{
}
};
{
VBoxVHWADisplay() :
mbDisplayPrimary(true)
// ,
// mSurfPrimary(NULL)
{}
{
if(pVga)
{
}
return old;
}
{
return old;
}
VBoxVHWASurfaceBase * getVGA() const
{
return mSurfVGA;
}
{
}
{
}
{
if(!hasOverlay(pSurf))
}
{
{
{
return true;
}
}
return false;
}
{
}
bool performDisplay(bool bForce)
{
if(mbDisplayPrimary)
{
#ifdef DEBUG_misha
/* should only display overlay now */
#endif
}
{
if(pOverlay)
{
}
}
return bForce;
}
bool mbDisplayPrimary;
};
typedef void (*PFNVBOXQGLFUNC)(void*, void*);
typedef enum
{
typedef struct VBOXVHWAFUNCCALLBACKINFO
{
void * pContext1;
void * pContext2;
{
bNewEvent(false)
{}
{
}
{
}
{
u.mFuncCallback = aOp;
}
{
switch(aType)
{
case VBOXVHWA_PIPECMD_PAINT:
break;
case VBOXVHWA_PIPECMD_VHWA:
break;
case VBOXVHWA_PIPECMD_FUNC:
break;
default:
Assert(0);
break;
}
}
bool isNewEvent() const { return bNewEvent; }
union
{
struct VBOXVHWACMD * mpCmd;
}u;
bool bNewEvent;
};
{
{}
{
if (mpLast)
{
}
else
{
}
}
{
}
{
if (mpLast)
}
{
if (!mpFirst)
else if (pLast)
{
}
}
{
}
{
if (!mpLast)
else if (pLast)
{
}
}
{
if (mpLast)
{
if (ppLast)
return pHead;
}
if (ppLast)
return NULL;
}
{
if (ppLast)
return mpFirst;
}
};
{
{
}
{
}
{
if(mpFirst)
{
return ret;
}
return NULL;
}
};
{
#define VBOXVHWA_INIFITE_WAITCOUNT (~0U)
VBoxVHWARefCounter() : m_cRefs(0) {}
{
return cRefs;
}
{
int rc = VINF_SUCCESS;
do
{
if (!refs())
break;
if (!cWaits)
{
rc = VERR_TIMEOUT;
break;
}
if (cWaits != VBOXVHWA_INIFITE_WAITCOUNT)
--cWaits;
if (!RT_SUCCESS(rc))
break;
} while(1);
return rc;
}
};
#define VBOXVHWACMDPIPEC_NEWEVENT 0x00000001
#define VBOXVHWACMDPIPEC_COMPLETEEVENT 0x00000002
{
bool completeCurrentEvent();
void disable();
void enable();
void lock();
void unlock();
#ifdef DEBUG_misha
#endif
bool mbNewEvent;
bool mbProcessingList;
};
/* added to workaround this ** [VBox|UI] duplication */
{
VBoxFBSizeInfo() {}
bool bUsesGuestVram) :
bool usesGuestVram() const {return mUsesGuestVram;}
bool mUsesGuestVram;
};
{
VBoxVHWAImage ();
~VBoxVHWAImage();
#ifdef VBOX_WITH_VIDEOHWACCEL
#ifdef VBOX_WITH_WDDM
#endif
bool hasSurfaces() const;
bool hasVisibleOverlays();
#endif
static const QGLFormat & vboxGLFormat();
#ifdef VBOXVHWA_OLD_COORD
#endif
#ifdef VBOXVHWA_PROFILE_FPS
void reportNewFrame() { mbNewFrame = true; }
#endif
bool performDisplay(bool bForce)
{
#ifdef VBOXVHWA_PROFILE_FPS
if(mbNewFrame)
{
mFPSCounter.frame();
{
}
mbNewFrame = false;
}
#endif
return bForce;
}
{
glPushMatrix();
setupMatricies(display, false);
}
static void popSettingsAfterSetupViewport()
{
glPopAttrib();
glPopMatrix();
}
#ifdef VBOXQGL_DBG_SURF
void vboxDoTestSurfaces(void *context);
#endif
#ifdef VBOX_WITH_VIDEOHWACCEL
{
if (pSurface->addressAlocated())
{
if (addr)
{
}
}
}
static int vhwaLoadSurface(VHWACommandList * pCmdList, struct SSMHANDLE * pSSM, uint32_t cBackBuffers, uint32_t u32Version);
static int vhwaLoadOverlayData(VHWACommandList * pCmdList, struct SSMHANDLE * pSSM, uint32_t u32Version);
void vhwaDoSurfaceOverlayUpdate(VBoxVHWASurfaceBase *pDstSurf, VBoxVHWASurfaceBase *pSrcSurf, struct VBOXVHWACMD_SURF_OVERLAY_UPDATE *pCmd);
#endif
{
return pSurf;
}
bool mRepaintNeeded;
void *mpvVRAM;
#ifdef VBOXVHWA_PROFILE_FPS
bool mbNewFrame;
#endif
};
{
void paintGL()
{
mpImage->performDisplay(true);
}
};
{
VBoxVHWAFBO() :
mFBO(0)
{}
~VBoxVHWAFBO()
{
if(mFBO)
{
}
}
void init()
{
);
}
void bind()
{
);
}
void unbind()
{
);
}
{
vboxglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, pTex->texTarget(), pTex->texture(), 0);
);
}
};
{
VBoxVHWATextureImageFBO(const QRect &size, const VBoxVHWAColorFormat &format, class VBoxVHWAGlProgramMngr * aMgr, VBOXVHWAIMG_TYPE flags) :
{
}
{
if(mpvFBOTexMem)
}
{
}
virtual int createDisplay(VBoxVHWATextureImage *pDst, const QRect * pDstRect, const QRect * pSrcRect,
{
}
{
T::display();
}
{
}
{
}
};
{
{
if (mpShareWgt)
}
/**
* to be called on NotifyUpdate framebuffer call
* @return true if the request was processed & should not be forwarded to the framebuffer
* false - otherwise */
/**
* to be called on RequestResize framebuffer call
* @return true if the request was processed & should not be forwarded to the framebuffer
* false - otherwise */
BOOL * pbFinished)
{
if (mCmdPipe.completeCurrentEvent())
return false;
/* TODO: more graceful resize handling */
return true;
}
{
mGlCurrent = false;
}
{
mGlCurrent = false;
}
static bool isAcceleration2DVideoAvailable();
/** additional video memory required for the best 2D support performance
* total amount of VRAM required is thus calculated as requiredVideoMemory + required2DOffscreenVideoMemory */
static quint64 required2DOffscreenVideoMemory();
/* not supposed to be called by clients */
void repaintMain();
void repaintOverlay()
{
{
mNeedOverlayRepaint = false;
}
if(mNeedSetVisible)
{
mNeedSetVisible = false;
mpOverlayWgt->setVisible (true);
}
}
void repaint()
{
repaintMain();
}
void makeCurrent()
{
if (!mGlCurrent)
{
mGlCurrent = true;
}
}
void performDisplayOverlay()
{
if (mOverlayVisible)
{
makeCurrent();
if (mOverlayImage.performDisplay(false))
}
}
void vboxSetGlOn (bool on);
bool vboxGetGlOn() { return mGlOn; }
bool vboxSynchGl();
void vboxDoVHWACmdExec(void *cmd);
void vboxShowOverlay (bool show);
void vboxDoCheckUpdateViewport();
void vboxDoVHWACmd (void *cmd);
int reset();
int resetGl();
void initGl();
bool mGlOn;
bool mOverlayWidgetVisible;
bool mOverlayVisible;
bool mGlCurrent;
bool mProcessingCommands;
bool mNeedOverlayRepaint;
bool mNeedSetVisible;
/* this is used in saved state restore to postpone surface restoration
* till the framebuffer size is restored */
};
/* these two additional class V, class R are to workaround the [VBox|UI] duplication,
* @todo: remove them once VBox stuff is removed */
{
: T (pView),
{
/* sync with framebuffer */
mOverlay.onResizeEventPostprocess (VBoxFBSizeInfo(this), QPoint(mpView->contentsX(), mpView->contentsY()));
}
{
}
{
}
{
&result,
{
return result;
}
}
{
return S_OK;
}
{
/* TODO: tmp workaround: the lock should be moved to the calling code??
* otherwise we may end up calling a null View */
/* Todo: can we call VideoModeSupported with the lock held?
* if not we can introduce a ref counting for the mpView usage
* to ensure it stays alive till we need it*/
{
if (mpView)
}
return retHr;
}
void resizeEvent (R *re)
{
T::resizeEvent (re);
}
{
T::viewportResized (re);
}
{
}
{
/* lock to ensure we do not collide with the EMT thread passing commands to us */
{
}
}
V *mpView;
};
#endif
#endif /* #ifndef __VBoxFBOverlay_h__ */