DevVGA_VBVA.cpp revision e6e6613fd415747d105a4f857c5aa2ecfd203359
/* $Id$ */
/** @file
* VirtualBox Video Acceleration (VBVA).
*/
/*
* Copyright (C) 2006-2013 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.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_DEV_VGA
#include <VBox/VBoxVideo.h>
#ifdef VBOX_WITH_VIDEOHWACCEL
#include <iprt/semaphore.h>
#endif
#include "DevVGA.h"
/* A very detailed logging. */
#if 0 // def DEBUG_sunlover
#define LOGVBVABUFFER(a) LogFlow(a)
#else
#define LOGVBVABUFFER(a) do {} while (0)
#endif
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
typedef struct VBVAPARTIALRECORD
{
typedef struct VBVAVIEW
{
} VBVAVIEW;
typedef struct VBVAMOUSESHAPEINFO
{
bool fSet;
bool fVisible;
bool fAlpha;
/** @todo saved state: save and restore VBVACONTEXT */
typedef struct VBVACONTEXT
{
bool fPaused;
} VBVACONTEXT;
/** Copies @a cb bytes from the VBVA ring buffer to the @a pu8Dst.
* Used for partial records or for records which cross the ring boundary.
*/
{
/** @todo replace the 'if' with an assert. The caller must ensure this condition. */
{
return;
}
if (i32Diff <= 0)
{
/* Chunk will not cross buffer boundary. */
}
else
{
/* Chunk crosses buffer boundary. */
}
/* Advance data offset. */
return;
}
static bool vbvaPartialRead (VBVAPARTIALRECORD *pPartialRecord, uint32_t cbRecord, VBVABUFFER *pVBVA)
{
LOGVBVABUFFER(("vbvaPartialRead: p = %p, cb = %d, cbRecord 0x%08X\n",
if (pPartialRecord->pu8)
{
}
else
{
}
if (!pu8New)
{
/* Memory allocation failed, fail the function. */
Log(("vbvaPartialRead: failed to (re)alocate memory for partial record!!! cbRecord 0x%08X\n",
cbRecord));
if (pPartialRecord->pu8)
{
}
pPartialRecord->cb = 0;
return false;
}
/* Fetch data from the ring buffer. */
return true;
}
/* For contiguous chunks just return the address in the buffer.
* For crossing boundary - allocate a buffer from heap.
*/
static bool vbvaFetchCmd (VBVAPARTIALRECORD *pPartialRecord, VBVABUFFER *pVBVA, VBVACMDHDR **ppHdr, uint32_t *pcbCmd)
{
LOGVBVABUFFER(("first = %d, free = %d\n",
if (indexRecordFirst == indexRecordFree)
{
/* No records to process. Return without assigning output variables. */
return true;
}
LOGVBVABUFFER(("cbRecord = 0x%08X, pPartialRecord->cb = 0x%08X\n", cbRecordCurrent, pPartialRecord->cb));
if (pPartialRecord->cb)
{
/* There is a partial read in process. Continue with it. */
LOGVBVABUFFER(("continue partial record cb = %d cbRecord 0x%08X, first = %d, free = %d\n",
{
/* New data has been added to the record. */
{
return false;
}
}
if (!(cbRecordCurrent & VBVA_F_RECORD_PARTIAL))
{
/* The record is completed by guest. Return it to the caller. */
pPartialRecord->cb = 0;
/* Advance the record index. */
LOGVBVABUFFER(("partial done ok, data = %d, free = %d\n",
}
return true;
}
/* A new record need to be processed. */
{
/* Current record is being written by guest. '=' is important here,
* because the guest will do a FLUSH at this condition.
* This partial record is too large for the ring buffer and must
* be accumulated in an allocated buffer.
*/
{
/* Partial read must be started. */
{
return false;
}
LOGVBVABUFFER(("started partial record cb = 0x%08X cbRecord 0x%08X, first = %d, free = %d\n",
}
return true;
}
/* Current record is complete. If it is not empty, process it. */
if (cbRecord)
{
/* The size of largest contiguous chunk in the ring biffer. */
/* The pointer to data in the ring buffer. */
/* Fetch or point the data. */
if (u32BytesTillBoundary >= cbRecord)
{
/* The command does not cross buffer boundary. Return address in the buffer. */
/* Advance data offset. */
}
else
{
/* The command crosses buffer boundary. Rare case, so not optimized. */
if (!dst)
{
return false;
}
}
}
/* Advance the record index. */
LOGVBVABUFFER(("done ok, data = %d, free = %d\n",
return true;
}
static void vbvaReleaseCmd (VBVAPARTIALRECORD *pPartialRecord, VBVABUFFER *pVBVA, VBVACMDHDR *pHdr, uint32_t cbCmd)
{
{
/* The pointer is inside ring buffer. Must be continuous chunk. */
/* Do nothing. */
}
else
{
/* The pointer is outside. It is then an allocated copy. */
{
pPartialRecord->cb = 0;
}
else
{
}
}
return;
}
static int vbvaFlushProcess (unsigned uScreenId, PVGASTATE pVGAState, VBVAPARTIALRECORD *pPartialRecord, VBVABUFFER *pVBVA)
{
LOGVBVABUFFER(("uScreenId %d, indexRecordFirst = %d, indexRecordFree = %d, off32Data = %d, off32Free = %d\n",
struct {
/* The rectangle that includes all dirty rectangles. */
} dirtyRect;
bool fUpdate = false; /* Whether there were any updates. */
bool fDirtyEmpty = true;
for (;;)
{
/* Fetch the command data. */
{
LogFunc(("unable to fetch command. off32Data = %d, off32Free = %d!!!\n",
/* @todo old code disabled VBVA processing here. */
return VERR_NOT_SUPPORTED;
}
{
/* No more commands yet in the queue. */
break;
}
if (cbCmd != 0)
{
if (!fUpdate)
{
fUpdate = true;
}
/* Updates the rectangle and sends the command to the VRDP server. */
/* These are global coords, relative to the primary screen. */
LOGVBVABUFFER(("cbCmd = %d, x=%d, y=%d, w=%d, h=%d\n",
LogRel3(("%s: update command cbCmd = %d, x=%d, y=%d, w=%d, h=%d\n",
phdr->h));
/* Collect all rects into one. */
if (fDirtyEmpty)
{
/* This is the first rectangle to be added. */
fDirtyEmpty = false;
}
else
{
/* Adjust region coordinates. */
{
}
{
}
{
}
{
}
}
}
}
if (fUpdate)
{
{
LogRel3(("%s: sending update screen=%d, x=%d, y=%d, w=%d, h=%d\n",
}
else
{
}
}
return VINF_SUCCESS;
}
{
unsigned uScreenId;
{
if (pVBVA)
{
}
}
/* @todo rc */
return VINF_SUCCESS;
}
{
/* Verify pNewScreen. */
/* @todo */
/* Apply these changes. */
/* @todo process VINF_VGA_RESIZE_IN_PROGRESS? */
return rc;
}
static int vbvaEnable (unsigned uScreenId, PVGASTATE pVGAState, VBVACONTEXT *pCtx, VBVABUFFER *pVBVA, uint32_t u32Offset, bool fRestored)
{
/* @todo old code did a UpdateDisplayAll at this place. */
int rc;
{
}
else
{
}
if (RT_SUCCESS (rc))
{
/* pVBVA->hostFlags has been set up by pfnVBVAEnable. */
LogFlowFunc(("u32HostEvents 0x%08X, u32SupportedOrders 0x%08X\n",
if (!fRestored)
{
/* @todo Actually this function must not touch the partialRecord structure at all,
* because initially it is a zero and when VBVA is disabled this should be set to zero.
* But I'm not sure that no code depends on zeroing partialRecord here.
* So for now (a quick fix for 4.1) just do not do this if the VM was restored,
* when partialRecord might be loaded already from the saved state.
*/
}
/* VBVA is working so disable the pause. */
}
return rc;
}
{
/* Process any pending orders and empty the VBVA ring buffer. */
{
}
return VINF_SUCCESS;
}
{
if (pHGSMI)
{
if (pCtx)
{
{
return true;
}
}
}
return false;
}
#ifdef DEBUG_sunlover
{
LogFlow(("fSet = %d, fVisible %d, fAlpha %d, @%d,%d %dx%d (%p, %d/%d)\n",
));
}
#endif
static int vbvaUpdateMousePointerShape(PVGASTATE pVGAState, VBVAMOUSESHAPEINFO *pMouseShapeInfo, bool fShape, const uint8_t *pu8Shape)
{
int rc;
LogFlowFunc(("pVGAState %p, pMouseShapeInfo %p, fShape %d, pu8Shape %p\n",
#ifdef DEBUG_sunlover
#endif
{
pu8Shape);
}
else
{
false,
0, 0,
0, 0,
NULL);
}
return rc;
}
static int vbvaMousePointerShape (PVGASTATE pVGAState, VBVACONTEXT *pCtx, const VBVAMOUSEPOINTERSHAPE *pShape, HGSMISIZE cbShape)
{
HGSMISIZE cbPointerData = 0;
if (fShape)
{
{
Log(("vbvaMousePointerShape: unsupported size %ux%u\n",
return VERR_INVALID_PARAMETER;
}
}
{
Log(("vbvaMousePointerShape: calculated pointer data size is too big (%d bytes, limit %d)\n",
return VERR_INVALID_PARAMETER;
}
/* Save mouse info it will be used to restore mouse pointer after restoring saved state. */
if (fShape)
{
/* Data related to shape. */
/* Reallocate memory buffer if necessary. */
{
if (pu8Shape)
{
}
}
/* Copy shape bitmaps. */
{
}
}
{
return VERR_NOT_SUPPORTED;
}
int rc = vbvaUpdateMousePointerShape(pVGAState, &pCtx->mouseShapeInfo, fShape, &pShape->au8Data[0]);
return rc;
}
{
/* Check which view contains the buffer. */
if (offBuffer != HGSMIOFFSET_VOID)
{
unsigned uScreenId;
{
if ( pView->u32ViewSize > 0
{
return pView->u32ViewIndex;
}
}
}
return ~0U;
}
#ifdef DEBUG_sunlover
{
{
Log((" view %d o 0x%x s 0x%x m 0x%x\n",
Log((" screen %d @%d,%d s 0x%x l 0x%x %dx%d bpp %d f 0x%x\n",
Log((" VBVA o 0x%x p %p\n",
Log((" PR cb 0x%x p %p\n",
}
}
#endif /* DEBUG_sunlover */
#define VBOXVBVASAVEDSTATE_VHWAAVAILABLE_MAGIC 0x12345678
#define VBOXVBVASAVEDSTATE_VHWAUNAVAILABLE_MAGIC 0x9abcdef0
#ifdef VBOX_WITH_VIDEOHWACCEL
{
}
static VBOXVHWACMD* vbvaVHWAHHCommandCreate (PVGASTATE pVGAState, VBOXVHWACMD_TYPE enmCmd, int32_t iDisplay, VBOXVHWACMD_LENGTH cbCmd)
{
if (pHdr)
return pHdr;
}
{
if(!cRefs)
{
}
}
{
}
{
if (fAsyncCommand)
{
}
else
{
}
}
{
return;
RTListForEachSafe(&pVGAState->pendingVhwaCommands.PendingList, pIter, pNext, VBOX_VHWA_PENDINGCMD, Node)
{
}
}
{
return;
RTListForEachSafe(&pVGAState->pendingVhwaCommands.PendingList, pIter, pNext, VBOX_VHWA_PENDINGCMD, Node)
{
}
}
{
int rc = VERR_BUFFER_OVERFLOW;
{
if (pPend)
{
{
return;
}
LogRel(("Pending command count has reached its threshold.. completing them all.."));
}
else
rc = VERR_NO_MEMORY;
}
else
LogRel(("Pending command count has reached its threshold, completing them all.."));
}
{
{
return false;
default:
return true;
}
}
{
{
rc = SSMR3PutU32(pSSM, (uint32_t)(((uint8_t*)pIter->pCommand) - ((uint8_t*)pVGAState->vram_ptrR3)));
}
return rc;
}
{
return VINF_SUCCESS;
int rc;
{
}
return rc;
}
{
bool fPend = false;
{
if (rc == VINF_CALLBACK_RETURN)
{
return true; /* command will be completed asynchronously, return right away */
}
else if (rc == VERR_INVALID_STATE)
{
if (!fPend)
{
}
else
}
else
{
}
/* the command was completed, take a special care about it (seee below) */
}
else
{
AssertFailed();
}
if (fPend)
return false;
return true;
}
{
return true;
RTListForEachSafe(&pVGAState->pendingVhwaCommands.PendingList, pIter, pNext, VBOX_VHWA_PENDINGCMD, Node)
{
{
return false; /* the command should be pended still */
}
}
return true;
}
{
}
{
{
return;
}
}
{
}
{
if(RT_SUCCESS(rc))
{
/* ensure the cmd is not deleted until we process it */
{
}
else
{
/* the command is completed */
}
if(RT_SUCCESS(rc))
{
}
}
return rc;
}
{
VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_CONSTRUCT, 0, sizeof(VBOXVHWACMD_HH_CONSTRUCT));
if(pCmd)
{
int rc = VINF_SUCCESS;
do
{
if(RT_SUCCESS(rc))
{
if(rc == VERR_NOT_IMPLEMENTED)
{
/* @todo: set some flag in pVGAState indicating VHWA is not supported */
/* VERR_NOT_IMPLEMENTED is not a failure, we just do not support it */
rc = VINF_SUCCESS;
}
if (!RT_SUCCESS(rc))
break;
}
else
break;
++iDisplay;
break;
} while (true);
return rc;
}
return VERR_OUT_OF_RESOURCES;
}
{
/* ensure we have all pending cmds processed and h->g cmds disabled */
if(pCmd)
{
int rc = VINF_SUCCESS;
do
{
if(RT_SUCCESS(rc))
{
if (rc == VERR_NOT_IMPLEMENTED)
rc = VINF_SUCCESS;
}
if (!RT_SUCCESS(rc))
break;
++iDisplay;
break;
} while (true);
return rc;
}
return VERR_OUT_OF_RESOURCES;
}
typedef DECLCALLBACK(bool) FNVBOXVHWAHHCMDPRECB(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext);
typedef FNVBOXVHWAHHCMDPRECB *PFNVBOXVHWAHHCMDPRECB;
typedef DECLCALLBACK(bool) FNVBOXVHWAHHCMDPOSTCB(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, int rc, void *pvContext);
typedef FNVBOXVHWAHHCMDPOSTCB *PFNVBOXVHWAHHCMDPOSTCB;
int vbvaVHWAHHPost(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, PFNVBOXVHWAHHCMDPRECB pfnPre, PFNVBOXVHWAHHCMDPOSTCB pfnPost, void *pvContext)
{
int rc = VINF_SUCCESS;
do
{
{
if (pfnPost)
{
{
rc = VINF_SUCCESS;
break;
}
rc = VINF_SUCCESS;
}
else if(RT_SUCCESS(rc))
{
if(rc == VERR_NOT_IMPLEMENTED)
{
rc = VINF_SUCCESS;
}
}
if (!RT_SUCCESS(rc))
break;
}
++iDisplay;
break;
} while (true);
return rc;
}
/* @todo call this also on reset? */
{
const VBOXVHWACMD_TYPE enmType = bEnable ? VBOXVHWACMD_TYPE_HH_ENABLE : VBOXVHWACMD_TYPE_HH_DISABLE;
0, 0);
if(pCmd)
{
return rc;
}
return VERR_OUT_OF_RESOURCES;
}
{
/* ensure we have no pending commands */
}
{
/* ensure we have no pending commands */
}
{
int rc;
{
#ifdef VBOX_WITH_WDDM
{
}
else
#endif
{
{
(void**)&pHostCmd,
VBVAHOSTCMD_SIZE(sizeof(VBVAHOSTCMDEVENT)),
if(RT_SUCCESS(rc))
{
pHostCmd->customOpCode = 0;
}
}
else
{
if(offCmd != HGSMIOFFSET_VOID)
{
(void**)&pHostCmd,
VBVAHOSTCMD_SIZE(sizeof(VBVAHOSTCMDVHWACMDCOMPLETE)),
if(RT_SUCCESS(rc))
{
}
}
else
{
}
}
if(RT_SUCCESS(rc))
{
rc = HGSMIHostCommandProcessAndFreeAsynch(pIns, pHostCmd, (pCmd->Flags & VBOXVHWACMD_FLAG_GH_ASYNCH_IRQ) != 0);
if(RT_SUCCESS(rc))
{
return rc;
}
}
}
}
else
{
if(pfn)
{
}
rc = VINF_SUCCESS;
}
return rc;
}
typedef struct VBOXVBVASAVEDSTATECBDATA
{
int rc;
bool ab2DOn[VBOX_VIDEO_MAX_SCREENS];
static DECLCALLBACK(bool) vboxVBVASaveStateBeginPostCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, int rc, void *pvContext)
{
return false;
if (RT_FAILURE(rc))
{
return false;
}
{
return false;
}
{
}
{
return false;
}
return true;
}
static DECLCALLBACK(bool) vboxVBVASaveStatePerformPreCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext)
{
return false;
{
return false;
}
int rc;
{
if (RT_FAILURE(rc))
{
return false;
}
return true;
}
if (RT_FAILURE(rc))
{
return false;
}
return false;
}
static DECLCALLBACK(bool) vboxVBVASaveStateEndPreCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext)
{
{
return true;
}
return false;
}
static DECLCALLBACK(bool) vboxVBVALoadStatePerformPostCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, int rc, void *pvContext)
{
return false;
if (RT_FAILURE(rc))
{
return false;
}
{
return false;
}
{
return false;
}
{
return false;
}
return true;
}
static DECLCALLBACK(bool) vboxVBVALoadStatePerformPreCb(PVGASTATE pVGAState, VBOXVHWACMD *pCmd, uint32_t iDisplay, void *pvContext)
{
return false;
{
return false;
}
int rc;
if (RT_FAILURE(rc))
{
return false;
}
switch (u32)
{
return true;
return false;
default:
return false;
}
}
#endif /* #ifdef VBOX_WITH_VIDEOHWACCEL */
{
if (RT_SUCCESS(rc))
{
/* Save VBVACONTEXT. */
if (!pCtx)
{
AssertFailed();
/* Still write a valid value to the SSM. */
}
else
{
#ifdef DEBUG_sunlover
#endif
{
{
}
}
/* Save mouse pointer shape information. */
{
}
#ifdef VBOX_WITH_WDDM
/* Size of some additional data. For future extensions. */
#else
/* Size of some additional data. For future extensions. */
#endif
{
sizeof(VBVAMODEHINT));
}
}
}
return rc;
}
{
int rc;
#ifdef VBOX_WITH_VIDEOHWACCEL
VBOXVBVASAVEDSTATECBDATA VhwaData = {0};
VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEBEGIN, 0, cbCmd);
if(pCmd)
{
if (RT_SUCCESS(rc))
{
#endif
#ifdef VBOX_WITH_VIDEOHWACCEL
if (RT_SUCCESS(rc))
{
VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM *pSave = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM);
if (RT_SUCCESS(rc))
{
}
}
}
}
else
#else
if (RT_SUCCESS(rc))
{
{
}
}
/* no pending commands */
SSMR3PutU32(pSSM, 0);
#endif
return rc;
}
{
{
/* Nothing was saved. */
return VINF_SUCCESS;
}
if (RT_SUCCESS(rc))
{
/* Load VBVACONTEXT. */
if (!pCtx)
{
/* This should not happen. */
AssertFailed();
}
else
{
{
{
}
else
{
if (!pu8)
{
return VERR_NO_MEMORY;
}
}
{
}
else
{
}
}
{
/* Read mouse pointer shape information. */
{
{
return VERR_NO_MEMORY;
}
}
else
{
}
/* Size of some additional data. For future extensions. */
#ifdef VBOX_WITH_WDDM
if (cbExtra >= 4)
{
cbExtra -= 4;
}
#endif
if (cbExtra > 0)
{
}
{
unsigned iHint;
{
if ( cbModeHints <= sizeof(VBVAMODEHINT)
else
}
}
}
{
bool fLoadCommands;
{
}
else
fLoadCommands = true;
#ifdef VBOX_WITH_VIDEOHWACCEL
VBOXVHWACMD *pCmd = vbvaVHWAHHCommandCreate(pVGAState, VBOXVHWACMD_TYPE_HH_SAVESTATE_LOADPERFORM, 0, cbCmd);
if(pCmd)
{
VBOXVBVASAVEDSTATECBDATA VhwaData = {0};
VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM *pLoad = VBOXVHWACMD_BODY(pCmd, VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM);
vbvaVHWAHHPost (pVGAState, pCmd, vboxVBVALoadStatePerformPreCb, vboxVBVALoadStatePerformPostCb, &VhwaData);
if (fLoadCommands)
{
}
}
else
{
}
#else
{
{
LogRel(("2D data while 2D is not supported\n"));
return VERR_NOT_SUPPORTED;
}
}
if (fLoadCommands)
{
if (u32)
{
LogRel(("2D pending command while 2D is not supported\n"));
return VERR_NOT_SUPPORTED;
}
}
#endif
}
#ifdef DEBUG_sunlover
#endif
}
}
return rc;
}
{
if (pCtx)
{
{
{
#ifdef VBOX_WITH_CRHGSMI
#endif
}
}
{
}
}
return VINF_SUCCESS;
}
{
}
{
return VINF_SUCCESS;
}
{
/* we can not use PDMDevHlpPCISetIrqNoWait here, because we need to set IRG host flag and raise IRQ atomically,
* otherwise there might be a situation, when:
* 1. Flag is set
* 2. guest issues an IRQ clean request, that cleans up the flag and the interrupt
* 3. IRQ is set */
VMR3ReqCallNoWait(PDMDevHlpGetVM(pVGAState->pDevInsR3), VMCPUID_ANY, (PFNRT)vbvaRaiseIrqEMT, 2, pVGAState, fFlags);
}
{
LogFlowFunc(("VBVA_INFO_VIEW: index %d, offset 0x%x, size 0x%x, max screen size 0x%x\n",
/* @todo verify view data. */
{
Log(("View index too large %d!!!\n",
pView->u32ViewIndex));
return VERR_INVALID_PARAMETER;
}
return VINF_SUCCESS;
}
{
/* Calculate the offset of the end of the screen so we can make
* sure it is inside the view. I assume that screen rollover is not
* implemented. */
LogRel(("VBVA_INFO_SCREEN: [%d] @%d,%d %dx%d, line 0x%x, BPP %d, flags 0x%x\n",
{
return VINF_SUCCESS;
}
LogRelFlow(("VBVA_INFO_SCREEN [%lu]: bad data: %lux%lu, line 0x%lx, BPP %u, start offset %lu, max screen size %lu\n",
(unsigned long)pScreen->u32ViewIndex,
(unsigned long)pScreen->u32LineSize,
(unsigned long)pScreen->u16BitsPerPixel,
(unsigned long)pScreen->u32StartOffset,
(unsigned long)pView->u32MaxScreenSize));
return VERR_INVALID_PARAMETER;
}
int VBVAGetInfoViewAndScreen(PVGASTATE pVGAState, uint32_t u32ViewIndex, VBVAINFOVIEW *pView, VBVAINFOSCREEN *pScreen)
{
return VERR_INVALID_PARAMETER;
if (pView)
if (pScreen)
return VINF_SUCCESS;
}
/*
*
* New VBVA uses a new interface id: #define VBE_DISPI_ID_VBOX_VIDEO 0xBE01
*
* VBVA uses two 32 bits IO ports to write VRAM offsets of shared memory blocks for commands.
* Read Write
* Host port 0x3b0 to process completed
* Guest port 0x3d0 control value? to process
*
*/
{
#if defined(VBOX_WITH_HGSMI) && (defined(VBOX_WITH_VIDEOHWACCEL) || defined(VBOX_WITH_VDMA) || defined(VBOX_WITH_WDDM))
VBVARaiseIrqNoWait (pVGAState, 0);
#else
#endif
}
/* The guest submitted a buffer. @todo Verify all guest data. */
static DECLCALLBACK(int) vbvaChannelHandler (void *pvHandler, uint16_t u16ChannelInfo, void *pvBuffer, HGSMISIZE cbBuffer)
{
int rc = VINF_SUCCESS;
LogFlowFunc(("pvHandler %p, u16ChannelInfo %d, pvBuffer %p, cbBuffer %u\n",
switch (u16ChannelInfo)
{
case VBVA_CMDVBVA_SUBMIT:
{
# ifdef VBOX_WITH_CRHGSMI
#endif
break;
}
case VBVA_CMDVBVA_FLUSH:
{
# ifdef VBOX_WITH_CRHGSMI
#endif
break;
}
case VBVA_CMDVBVA_CTL:
{
#ifdef VBOX_WITH_CRHGSMI
{
Log(("buffer too small\n"));
#ifdef DEBUG_misha
AssertMsgFailed(("buffer too small\n"));
#endif
break;
}
#endif
break;
}
#ifdef VBOX_WITH_VDMA
case VBVA_VDMA_CMD:
{
{
break;
}
rc = VINF_SUCCESS;
break;
}
case VBVA_VDMA_CTL:
{
{
break;
}
rc = VINF_SUCCESS;
break;
}
#endif
case VBVA_QUERY_CONF32:
{
if (cbBuffer < sizeof (VBVACONF32))
{
break;
}
LogFlowFunc(("VBVA_QUERY_CONF32: u32Index %d, u32Value 0x%x\n",
{
}
{
/* @todo a value calculated from the vram size */
}
{
}
{
}
{
}
else
{
Log(("Unsupported VBVA_QUERY_CONF32 index %d!!!\n",
}
} break;
case VBVA_SET_CONF32:
{
if (cbBuffer < sizeof (VBVACONF32))
{
break;
}
LogFlowFunc(("VBVA_SET_CONF32: u32Index %d, u32Value 0x%x\n",
{
/* do nothing. this is a const. */
}
{
/* do nothing. this is a const. */
}
else
{
Log(("Unsupported VBVA_SET_CONF32 index %d!!!\n",
}
} break;
case VBVA_INFO_VIEW:
{
#ifdef VBOX_WITH_CRHGSMI
{
AssertMsgFailed(("VBVA_INFO_VIEW is not acceptible for CmdVbva\n"));
break;
}
#endif
if (cbBuffer < sizeof (VBVAINFOVIEW))
{
break;
}
/* Guest submits an array of VBVAINFOVIEW structures. */
for (;
cbBuffer >= sizeof (VBVAINFOVIEW);
{
if (RT_FAILURE(rc))
break;
}
} break;
case VBVA_INFO_HEAP:
{
if (cbBuffer < sizeof (VBVAINFOHEAP))
{
break;
}
LogFlowFunc(("VBVA_INFO_HEAP: offset 0x%x, size 0x%x\n",
} break;
case VBVA_FLUSH:
{
{
break;
}
LogFlowFunc(("VBVA_FLUSH: u32Reserved 0x%x\n",
pFlush->u32Reserved));
} break;
case VBVA_INFO_SCREEN:
{
if (cbBuffer < sizeof (VBVAINFOSCREEN))
{
break;
}
#ifdef VBOX_WITH_CRHGSMI
{
AssertMsgFailed(("VBVA_INFO_SCREEN is not acceptible for CmdVbva\n"));
break;
}
#endif
} break;
case VBVA_ENABLE:
{
#ifdef VBOX_WITH_CRHGSMI
{
AssertMsgFailed(("VBVA_ENABLE is not acceptible for CmdVbva\n"));
break;
}
#endif
if (cbBuffer < sizeof (VBVAENABLE))
{
break;
}
unsigned uScreenId;
{
if (cbBuffer < sizeof (VBVAENABLE_EX))
{
break;
}
}
else
{
}
if (uScreenId == ~0U)
{
break;
}
LogFlowFunc(("VBVA_ENABLE[%d]: u32Flags 0x%x u32Offset 0x%x\n",
{
/* Guest reported offset relative to view. */
{
}
if (pVBVA)
{
/* Process any pending orders and empty the VBVA ring buffer. */
}
else
{
Log(("Invalid VBVABUFFER offset 0x%x!!!\n",
}
}
{
}
else
{
Log(("Invalid VBVA_ENABLE flags 0x%x!!!\n",
}
} break;
case VBVA_MOUSE_POINTER_SHAPE:
{
if (cbBuffer < sizeof (VBVAMOUSEPOINTERSHAPE))
{
break;
}
LogFlowFunc(("VBVA_MOUSE_POINTER_SHAPE: i32Result 0x%x, fu32Flags 0x%x, hot spot %d,%d, size %dx%d\n",
} break;
#ifdef VBOX_WITH_VIDEOHWACCEL
case VBVA_VHWA_CMD:
{
if (cbBuffer < sizeof (VBOXVHWACMD))
{
break;
}
rc = VINF_SUCCESS;
break;
} break;
#endif
#ifdef VBOX_WITH_WDDM
case VBVA_INFO_CAPS:
{
{
break;
}
} break;
#endif
case VBVA_SCANLINE_CFG:
{
if (cbBuffer < sizeof (VBVASCANLINECFG))
{
break;
}
} break;
case VBVA_QUERY_MODE_HINTS:
{
if (cbBuffer < sizeof(VBVAQUERYMODEHINTS))
{
break;
}
LogRelFlowFunc(("VBVA_QUERY_MODE_HINTS: cHintsQueried=%u, cbHintStructureGuest=%u\n",
(unsigned)pModeHintQuery->cHintsQueried,
(unsigned)pModeHintQuery->cbHintStructureGuest));
if (cbBuffer < sizeof (VBVAQUERYMODEHINTS)
{
break;
}
unsigned iHint;
{
sizeof(VBVAMODEHINT)));
}
} break;
{
if (cbBuffer != sizeof(VBVAREPORTINPUTMAPPING))
{
break;
}
LogRelFlowFunc(("VBVA_REPORT_INPUT_MAPPING: x=%u, y=%u, cx=%u, cy=%u\n", (unsigned)pReport->x, (unsigned)pReport->y,
pVGAState->pDrv->pfnVBVAInputMappingUpdate(pVGAState->pDrv, pReport->x, pReport->y, pReport->cx, pReport->cy);
} break;
case VBVA_CURSOR_POSITION:
{
if (cbBuffer != sizeof(VBVACURSORPOSITION))
{
break;
}
= (VBVACURSORPOSITION *)pvBuffer;
LogRelFlowFunc(("VBVA_CURSOR_POSITION: fReportPosition=%RTbool",
LogRelFlowFunc(("VBVA_CURSOR_POSITION: fReportPosition=true, x=%u, y=%u\n",
else
LogRelFlowFunc(("VBVA_CURSOR_POSITION: fReportPosition=false\n"));
} break;
default:
Log(("Unsupported VBVA guest command %d!!!\n",
break;
}
return rc;
}
/* When VBVA is paused, then VGA device is allowed to work but
* no HGSMI etc state is changed.
*/
{
{
return;
}
if (pCtx)
{
}
}
{
{
return;
}
#ifdef VBOX_WITH_VIDEOHWACCEL
#endif
if(HgFlags & HGSMIHOSTFLAGS_IRQ)
{
/* this means the IRQ is LEVEL_HIGH, need to reset it */
}
if (pCtx)
{
unsigned uScreenId;
{
}
}
}
{
if (pCtx)
{
{
if (RT_SUCCESS (rc))
{
{
/* VBVA is not enabled for the first view, so VGA device must do updates. */
}
}
}
}
return rc;
}
{
/** @note See Display::setVideoModeHint: "It is up to the guest to decide
* whether the hint is valid. Therefore don't do any VRAM sanity checks
* here! */
return VERR_OUT_OF_RANGE;
if (fNotifyGuest && pThis->fGuestCaps & VBVACAPS_IRQ && pThis->fGuestCaps & VBVACAPS_VIDEO_MODE_HINTS)
return VINF_SUCCESS;
}
/** Converts a display port interface pointer to a vga state pointer. */
#define IDISPLAYPORT_2_VGASTATE(pInterface) ( (PVGASTATE)((uintptr_t)pInterface - RT_OFFSETOF(VGASTATE, IPort)) )
{
int rc;
return rc;
}
DECLCALLBACK(void) vbvaPortReportHostCursorCapabilities(PPDMIDISPLAYPORT pInterface, uint32_t fCapabilitiesAdded,
{
}
{
}
{
pVM,
"VBVA",
0,
sizeof (VBVACONTEXT));
if (RT_SUCCESS (rc))
{
if (RT_SUCCESS (rc))
{
}
}
return rc;
}
{
if (pCtx)
{
}
}