Skip to content

Commit 1c53c51

Browse files
committed
Devices/Graphics: offload GMR processing to the FIFO thread. bugref:11117
svn:sync-xref-src-repo-rev: r174535
1 parent e13444b commit 1c53c51

2 files changed

Lines changed: 121 additions & 52 deletions

File tree

src/VBox/Devices/Graphics/DevVGA-SVGA-internal.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $Id: DevVGA-SVGA-internal.h 114073 2026-05-05 09:57:55Z vitali.pelenjow@oracle.com $ */
1+
/* $Id: DevVGA-SVGA-internal.h 114699 2026-07-14 12:53:14Z vitali.pelenjow@oracle.com $ */
22
/** @file
33
* VMWare SVGA device - internal header for DevVGA-SVGA* source files.
44
*/
@@ -62,6 +62,16 @@ typedef struct
6262
PVMSVGAGMRDESCRIPTOR paDesc;
6363
} GMR, *PGMR;
6464

65+
typedef struct _VMSVGAGMRINFO
66+
{
67+
uint32_t u32GMRId; /* GMR identifier. Index in pSVGAState->paGMR. */
68+
uint32_t cDescriptors; /* Elements in paDesc array. 0 if GMR must be freed. */
69+
uint32_t cPagesTotal; /* Total number of pages in descriptors. */
70+
uint32_t u32Reserved;
71+
RT_FLEXIBLE_ARRAY_EXTENSION
72+
VMSVGAGMRDESCRIPTOR paDescs[RT_FLEXIBLE_ARRAY]; /* GMR pages. */
73+
} VMSVGAGMRINFO;
74+
6575

6676
typedef struct VMSVGACMDBUF *PVMSVGACMDBUF;
6777
typedef struct VMSVGACMDBUFCTX *PVMSVGACMDBUFCTX;
@@ -74,6 +84,7 @@ typedef enum VMSVGACMDBUFTYPE
7484
} VMSVGACMDBUFTYPE;
7585

7686
#define VMSVGACMDBUF_HOSTCOMMAND_CURSOR_MOBID 1
87+
#define VMSVGACMDBUF_HOSTCOMMAND_GMR_DESCRIPTOR 2
7788

7889
/* Command buffer. */
7990
#include "vmsvga_headers_begin.h" /* GCC complains that 'ISO C++ prohibits anonymous structs' when "-Wpedantic" is enabled. */

src/VBox/Devices/Graphics/DevVGA-SVGA.cpp

Lines changed: 109 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $Id: DevVGA-SVGA.cpp 114638 2026-07-07 17:03:05Z vitali.pelenjow@oracle.com $ */
1+
/* $Id: DevVGA-SVGA.cpp 114699 2026-07-14 12:53:14Z vitali.pelenjow@oracle.com $ */
22
/** @file
33
* VMware SVGA device.
44
*
@@ -2039,6 +2039,42 @@ static void vmsvgaR3CursorMobId(PVGASTATE pThis, PVGASTATECC pThisCC)
20392039
}
20402040
# endif /* VBOX_WITH_VMSVGA3D */
20412041

2042+
2043+
/** Defines or frees a GMR.
2044+
*
2045+
* @param pThis The shared VGA/VMSVGA instance data.
2046+
* @param pThisCC The VGA/VMSVGA state for the current context.
2047+
* @param pGMRInfo The GMR description.
2048+
* @thread FIFO
2049+
*/
2050+
static void vmsvgaR3GMRDescriptor(PVGASTATE pThis, PVGASTATECC pThisCC, VMSVGAGMRINFO const *pGMRInfo)
2051+
{
2052+
PVMSVGAR3STATE pSVGAState = pThisCC->svga.pSvgaR3State;
2053+
2054+
uint32_t const idGMR = pGMRInfo->u32GMRId;
2055+
AssertReturnVoid(idGMR < pThis->svga.cGMR);
2056+
RT_UNTRUSTED_VALIDATED_FENCE();
2057+
2058+
/* Free the old GMR if present. */
2059+
vmsvgaR3GmrFree(pThisCC, idGMR);
2060+
2061+
if (pGMRInfo->cDescriptors != 0)
2062+
{
2063+
/* Commit the GMR. */
2064+
size_t const cbAlloc = pGMRInfo->cDescriptors * sizeof(VMSVGAGMRDESCRIPTOR);
2065+
pSVGAState->paGMR[idGMR].paDesc = (PVMSVGAGMRDESCRIPTOR)RTMemAlloc(cbAlloc);
2066+
AssertReturnVoid(pSVGAState->paGMR[idGMR].paDesc);
2067+
memcpy(pSVGAState->paGMR[idGMR].paDesc, pGMRInfo->paDescs, cbAlloc);
2068+
2069+
pSVGAState->paGMR[idGMR].numDescriptors = pGMRInfo->cDescriptors;
2070+
pSVGAState->paGMR[idGMR].cMaxPages = pGMRInfo->cPagesTotal;
2071+
pSVGAState->paGMR[idGMR].cbTotal = pGMRInfo->cPagesTotal * GUEST_PAGE_SIZE;
2072+
Assert((pSVGAState->paGMR[idGMR].cbTotal >> GUEST_PAGE_SHIFT) == pGMRInfo->cPagesTotal);
2073+
Log(("Defined new gmrid = %u: numDescriptors=%u cbTotal=%#x (%#x pages)\n",
2074+
idGMR, pGMRInfo->cDescriptors, pSVGAState->paGMR[idGMR].cbTotal, pGMRInfo->cPagesTotal));
2075+
}
2076+
}
2077+
20422078
#endif /* IN_RING3 */
20432079

20442080

@@ -2377,77 +2413,97 @@ static VBOXSTRICTRC vmsvgaWritePort(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTA
23772413
AssertBreak(idGMR < pThis->svga.cGMR);
23782414
RT_UNTRUSTED_VALIDATED_FENCE();
23792415

2380-
/* Free the old GMR if present. */
2381-
vmsvgaR3GmrFree(pThisCC, idGMR);
2416+
/* GMRs must be modified from FIFO thread. Fetch the data and forward it to the FIFO thread. */
2417+
VMSVGAGMRINFO *pGMRInfo = (VMSVGAGMRINFO *)RTMemAlloc(RT_UOFFSETOF(VMSVGAGMRINFO, paDescs));
2418+
if (!pGMRInfo)
2419+
{
2420+
STAM_REL_COUNTER_INC(&pSVGAState->StatR3RegGmrDescriptorWrErrors);
2421+
break;
2422+
}
2423+
2424+
pGMRInfo->u32GMRId = idGMR;
2425+
pGMRInfo->cDescriptors = 0;
2426+
pGMRInfo->cPagesTotal = 0;
2427+
pGMRInfo->u32Reserved = 0;
2428+
2429+
int rc2 = VINF_SUCCESS;
23822430

2383-
/* Just undefine the GMR? */
23842431
RTGCPHYS GCPhys = (RTGCPHYS)u32 << GUEST_PAGE_SHIFT;
23852432
if (GCPhys == 0)
23862433
{
23872434
STAM_REL_COUNTER_INC(&pSVGAState->StatR3RegGmrDescriptorWrFree);
2388-
break;
23892435
}
2390-
2391-
2392-
/* Never cross a page boundary automatically. */
2393-
const uint32_t cMaxPages = RT_MIN(VMSVGA_MAX_GMR_PAGES, UINT32_MAX / X86_PAGE_SIZE);
2394-
uint32_t cPagesTotal = 0;
2395-
uint32_t iDesc = 0;
2396-
PVMSVGAGMRDESCRIPTOR paDescs = NULL;
2397-
uint32_t cLoops = 0;
2398-
RTGCPHYS GCPhysBase = GCPhys;
2399-
while ((GCPhys >> GUEST_PAGE_SHIFT) == (GCPhysBase >> GUEST_PAGE_SHIFT))
2436+
else
24002437
{
2401-
/* Read descriptor. */
2402-
SVGAGuestMemDescriptor desc;
2403-
rc = PDMDevHlpPCIPhysRead(pDevIns, GCPhys, &desc, sizeof(desc));
2404-
AssertRCBreak(VBOXSTRICTRC_VAL(rc));
2405-
2406-
if (desc.numPages != 0)
2438+
/* Never cross a page boundary automatically. */
2439+
const uint32_t cMaxPages = RT_MIN(VMSVGA_MAX_GMR_PAGES, UINT32_MAX / X86_PAGE_SIZE);
2440+
uint32_t cLoops = 0;
2441+
RTGCPHYS GCPhysBase = GCPhys;
2442+
while ((GCPhys >> GUEST_PAGE_SHIFT) == (GCPhysBase >> GUEST_PAGE_SHIFT))
24072443
{
2408-
AssertBreakStmt(desc.numPages <= cMaxPages, rc = VERR_OUT_OF_RANGE);
2409-
cPagesTotal += desc.numPages;
2410-
AssertBreakStmt(cPagesTotal <= cMaxPages, rc = VERR_OUT_OF_RANGE);
2444+
/* Read descriptor. */
2445+
SVGAGuestMemDescriptor desc;
2446+
rc2 = PDMDevHlpPCIPhysRead(pDevIns, GCPhys, &desc, sizeof(desc));
2447+
AssertRCBreak(rc2);
24112448

2412-
if ((iDesc & 15) == 0)
2449+
if (desc.numPages != 0)
24132450
{
2414-
void *pvNew = RTMemRealloc(paDescs, (iDesc + 16) * sizeof(VMSVGAGMRDESCRIPTOR));
2415-
AssertBreakStmt(pvNew, rc = VERR_NO_MEMORY);
2416-
paDescs = (PVMSVGAGMRDESCRIPTOR)pvNew;
2417-
}
2451+
AssertBreakStmt(desc.numPages <= cMaxPages, rc2 = VERR_OUT_OF_RANGE);
2452+
pGMRInfo->cPagesTotal += desc.numPages;
2453+
AssertBreakStmt(pGMRInfo->cPagesTotal <= cMaxPages, rc2 = VERR_OUT_OF_RANGE);
24182454

2419-
paDescs[iDesc].GCPhys = (RTGCPHYS)desc.ppn << GUEST_PAGE_SHIFT;
2420-
paDescs[iDesc++].numPages = desc.numPages;
2455+
if ((pGMRInfo->cDescriptors & 15) == 0)
2456+
{
2457+
size_t const cbAlloc = RT_UOFFSETOF(VMSVGAGMRINFO, paDescs)
2458+
+ (pGMRInfo->cDescriptors + 16) * sizeof(VMSVGAGMRDESCRIPTOR);
2459+
void *pvNew = RTMemRealloc(pGMRInfo, cbAlloc);
2460+
AssertBreakStmt(pvNew, rc2 = VERR_NO_MEMORY);
2461+
pGMRInfo = (VMSVGAGMRINFO *)pvNew;
2462+
}
2463+
2464+
pGMRInfo->paDescs[pGMRInfo->cDescriptors].GCPhys = (RTGCPHYS)desc.ppn << GUEST_PAGE_SHIFT;
2465+
pGMRInfo->paDescs[pGMRInfo->cDescriptors++].numPages = desc.numPages;
2466+
2467+
/* Continue with the next descriptor. */
2468+
GCPhys += sizeof(desc);
2469+
}
2470+
else if (desc.ppn == 0)
2471+
break; /* terminator */
2472+
else /* Pointer to the next physical page of descriptors. */
2473+
GCPhys = GCPhysBase = (RTGCPHYS)desc.ppn << GUEST_PAGE_SHIFT;
24212474

2422-
/* Continue with the next descriptor. */
2423-
GCPhys += sizeof(desc);
2475+
cLoops++;
2476+
AssertBreakStmt(cLoops < VMSVGA_MAX_GMR_DESC_LOOP_COUNT, rc2 = VERR_OUT_OF_RANGE);
24242477
}
2425-
else if (desc.ppn == 0)
2426-
break; /* terminator */
2427-
else /* Pointer to the next physical page of descriptors. */
2428-
GCPhys = GCPhysBase = (RTGCPHYS)desc.ppn << GUEST_PAGE_SHIFT;
24292478

2430-
cLoops++;
2431-
AssertBreakStmt(cLoops < VMSVGA_MAX_GMR_DESC_LOOP_COUNT, rc = VERR_OUT_OF_RANGE);
2479+
AssertStmt(pGMRInfo->cDescriptors > 0 || RT_FAILURE_NP(rc2), rc2 = VERR_OUT_OF_RANGE);
24322480
}
24332481

2434-
AssertStmt(iDesc > 0 || RT_FAILURE_NP(rc), rc = VERR_OUT_OF_RANGE);
2435-
if (RT_SUCCESS(rc))
2482+
if (RT_SUCCESS(rc2))
24362483
{
2437-
/* Commit the GMR. */
2438-
pSVGAState->paGMR[idGMR].paDesc = paDescs;
2439-
pSVGAState->paGMR[idGMR].numDescriptors = iDesc;
2440-
pSVGAState->paGMR[idGMR].cMaxPages = cPagesTotal;
2441-
pSVGAState->paGMR[idGMR].cbTotal = cPagesTotal * GUEST_PAGE_SIZE;
2442-
Assert((pSVGAState->paGMR[idGMR].cbTotal >> GUEST_PAGE_SHIFT) == cPagesTotal);
2443-
Log(("Defined new gmr %x numDescriptors=%d cbTotal=%x (%#x pages)\n",
2444-
idGMR, iDesc, pSVGAState->paGMR[idGMR].cbTotal, cPagesTotal));
2484+
/* Forward to the FIFO thread. */
2485+
PVMSVGACMDBUFCTX pCmdBufCtx = pThisCC->svga.pSvgaR3State->apCmdBufCtxs[0];
2486+
PVMSVGACMDBUF pCmdBuf = vmsvgaR3CmdBufAlloc(pCmdBufCtx, VMSVGACMDBUFTYPE_HOST);
2487+
if (RT_LIKELY(pCmdBuf))
2488+
{
2489+
pCmdBuf->idHostCommand = VMSVGACMDBUF_HOSTCOMMAND_GMR_DESCRIPTOR;
2490+
pCmdBuf->cbHostCommandData = RT_UOFFSETOF(VMSVGAGMRINFO, paDescs)
2491+
+ pGMRInfo->cDescriptors * sizeof(VMSVGAGMRDESCRIPTOR);
2492+
pCmdBuf->pvHostCommandData = pGMRInfo;
2493+
vmsvgaR3CmdBufSubmitHostCommand(pDevIns, pThis, pThisCC, pCmdBuf);
2494+
Log(("Defining gmrid = %u: numDescriptors=%u, %#x pages\n",
2495+
idGMR, pGMRInfo->cDescriptors, pGMRInfo->cPagesTotal));
2496+
}
2497+
else
2498+
rc2 = VERR_NO_MEMORY;
24452499
}
2446-
else
2500+
2501+
if (RT_FAILURE(rc2))
24472502
{
2448-
RTMemFree(paDescs);
2503+
RTMemFree(pGMRInfo);
24492504
STAM_REL_COUNTER_INC(&pSVGAState->StatR3RegGmrDescriptorWrErrors);
24502505
}
2506+
24512507
break;
24522508
}
24532509
# endif /* IN_RING3 */
@@ -4599,6 +4655,8 @@ static void vmsvgaR3CmdBufProcessBuffers(PPDMDEVINS pDevIns, PVGASTATE pThis, PV
45994655
#else
46004656
; /* Nothing. */
46014657
#endif
4658+
else if (pCmdBuf->idHostCommand == VMSVGACMDBUF_HOSTCOMMAND_GMR_DESCRIPTOR)
4659+
vmsvgaR3GMRDescriptor(pThis, pThisCC, (VMSVGAGMRINFO *)pCmdBuf->pvHostCommandData);
46024660
else
46034661
AssertFailed();
46044662
vmsvgaR3CmdBufFree(pCmdBuf);

0 commit comments

Comments
 (0)