68478eab4b
but couldn't release immediately since they depended on virtual GPU features which were not yet publicly released in any products. This checkin moves those features from our internal repository to the open source repository. Future development on these tests and examples will take place directly in the open source repository. The primary feature added by this patch is 'Screen Object', a new dynamic display management extension supported by Workstation 7.0 and Fusion 3.0. See the README for a quick explanation.
203 lines
5.5 KiB
C
203 lines
5.5 KiB
C
/*
|
|
* Stress test for GMR-to-screen blits with dynamic GMR mapping.
|
|
*
|
|
* This test uses GMRs in a rather extreme way- it repeatedly repaints
|
|
* the screen in page-sized (32*32*4 = 4096) chunks, using GMRs which
|
|
* are redefined for each DMA operation. Each in-flight DMA has a
|
|
* separate GMR allocated to it.
|
|
*
|
|
* The first page of each GMR contains the data we're actually blitting
|
|
* to the screen. This page comes from a rotating pool of 4096 pages
|
|
* (16 MB of memory) which has a static pattern of colored tiles painted
|
|
* into it during initialization.
|
|
*
|
|
* The rest of each GMR is fluff. After the single page of useful
|
|
* data, we have 128 dummy pages. This makes the GMRs a bit more
|
|
* reasonably sized (512 KB) to simulate the size of a more typical
|
|
* graphics-related mapping.
|
|
*/
|
|
|
|
#include "svga.h"
|
|
#include "gmr.h"
|
|
#include "screen.h"
|
|
#include "intr.h"
|
|
#include "math.h"
|
|
|
|
|
|
/*
|
|
* fillPages --
|
|
*
|
|
* Fill a range of contiguous pages with a test pattern. In this
|
|
* case, each page is a solid color and each consecutive page has a
|
|
* different color.
|
|
*/
|
|
|
|
static void
|
|
fillPages(PPN firstPage, uint32 count, uint32 tileSize)
|
|
{
|
|
while (count) {
|
|
const uint32 tick = (uint32)firstPage;
|
|
const float rPhase = tick * 0.01;
|
|
const float gPhase = tick * 0.02;
|
|
const float bPhase = tick * 0.03;
|
|
|
|
const uint8 r = sinf(rPhase) * 0x60 + 0x80;
|
|
const uint8 g = sinf(gPhase) * 0x60 + 0x80;
|
|
const uint8 b = sinf(bPhase) * 0x60 + 0x80;
|
|
|
|
const uint32 color = (r << 16) | (g << 8) | b;
|
|
|
|
memset32(PPN_POINTER(firstPage), color, tileSize * tileSize);
|
|
|
|
count--;
|
|
firstPage++;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* main --
|
|
*
|
|
* Main loop and initialization.
|
|
*/
|
|
|
|
int
|
|
main(void)
|
|
{
|
|
Intr_Init();
|
|
Intr_SetFaultHandlers(SVGA_DefaultFaultHandler);
|
|
SVGA_Init();
|
|
GMR_Init();
|
|
Heap_Reset();
|
|
SVGA_SetMode(0, 0, 32);
|
|
Screen_Init();
|
|
|
|
SVGAScreenObject myScreen = {
|
|
.structSize = sizeof(SVGAScreenObject),
|
|
.id = 0,
|
|
.flags = SVGA_SCREEN_HAS_ROOT | SVGA_SCREEN_IS_PRIMARY,
|
|
.size = { 800, 600 },
|
|
.root = { -1234, 5678 },
|
|
};
|
|
Screen_Define(&myScreen);
|
|
|
|
const uint32 numPages = 4096;
|
|
const uint32 tileSize = 32;
|
|
|
|
const uint32 bitsPerPixel = 32;
|
|
const uint32 colorDepth = 24;
|
|
|
|
const uint32 tileBytesPerLine = tileSize * sizeof(uint32);
|
|
|
|
const SVGAGMRImageFormat tileFormat = {{{
|
|
.bitsPerPixel = bitsPerPixel,
|
|
.colorDepth = colorDepth,
|
|
}}};
|
|
|
|
/*
|
|
* Allocate a pool of system memory pages. In a real driver, these
|
|
* might be pages we get at runtime from a user-mode app and lock
|
|
* down prior to a DMA operation. We have many more pages than we
|
|
* have GMRs or in-flight DMAs.
|
|
*/
|
|
|
|
PPN firstPage = Heap_AllocPages(numPages);
|
|
PPN lastPage = firstPage + numPages - 1;
|
|
PPN currentPage = firstPage;
|
|
fillPages(firstPage, numPages, tileSize);
|
|
|
|
/*
|
|
* Allocate a GMR descriptor full of dummy mappings. We'll throw a
|
|
* handful of these into each GMR, so that the resulting GMRs have
|
|
* a more realistic size than just a single page.
|
|
*/
|
|
|
|
static SVGAGuestMemDescriptor dummyPages[128];
|
|
int i;
|
|
|
|
for (i = 0; i < arraysize(dummyPages); i++) {
|
|
dummyPages[i].ppn = 1024 + (i & 0xF) * 3;
|
|
dummyPages[i].numPages = 1;
|
|
}
|
|
|
|
PPN dummyDescriptor = GMR_AllocDescriptor(dummyPages, arraysize(dummyPages));
|
|
|
|
/*
|
|
* Allocate a single page to use for the GMR descriptor
|
|
* head. Instead of using GMR_Define(), we'll do this manually so
|
|
* that we can keep recycling the same single-page descriptor.
|
|
*/
|
|
|
|
PPN descPage = Heap_AllocPages(1);
|
|
SVGAGuestMemDescriptor *desc = PPN_POINTER(descPage);
|
|
|
|
/*
|
|
* Each GMR has a fence, so we can wait to re-use it until after
|
|
* the DMA has expired. In this example, we use the first 32 GMRs.
|
|
*/
|
|
|
|
uint32 gmrFences[32] = { 0 };
|
|
uint32 gmrIndex = 5;
|
|
|
|
/*
|
|
* Keep looping over the whole screen, tile by tile.
|
|
*/
|
|
|
|
while (1) {
|
|
int x, y;
|
|
for (y = 0; y < myScreen.size.height; y += tileSize) {
|
|
for (x = 0; x < myScreen.size.width; x += tileSize) {
|
|
|
|
/*
|
|
* Wait until we're done with the old GMR.
|
|
*/
|
|
|
|
SVGA_SyncToFence(gmrFences[gmrIndex]);
|
|
|
|
/*
|
|
* Define the new GMR, point it to the next sysmem page in
|
|
* our pool. The first page in this GMR will be our
|
|
* filled page, the rest will be dummy pages.
|
|
*/
|
|
|
|
desc[0].ppn = currentPage;
|
|
desc[0].numPages = 1;
|
|
desc[1].ppn = dummyDescriptor;
|
|
desc[1].numPages = 0;
|
|
|
|
SVGA_WriteReg(SVGA_REG_GMR_ID, gmrIndex);
|
|
SVGA_WriteReg(SVGA_REG_GMR_DESCRIPTOR, descPage);
|
|
|
|
currentPage++;
|
|
if (currentPage == lastPage) {
|
|
currentPage = firstPage;
|
|
}
|
|
|
|
/*
|
|
* Do a blit from this GMR to the screen, and set a fence so that
|
|
* we can wait to recycle the GMR until after this DMA completes.
|
|
*/
|
|
|
|
SVGAGuestPtr gPtr = {
|
|
.gmrId = gmrIndex,
|
|
.offset = 0,
|
|
};
|
|
Screen_DefineGMRFB(gPtr, tileBytesPerLine, tileFormat);
|
|
|
|
SVGASignedPoint blitOrigin = { 0, 0 };
|
|
SVGASignedRect blitDest = { x, y, x+tileSize, y+tileSize };
|
|
|
|
Screen_BlitFromGMRFB(&blitOrigin, &blitDest, myScreen.id);
|
|
gmrFences[gmrIndex] = SVGA_InsertFence();
|
|
|
|
/*
|
|
* Next GMR..
|
|
*/
|
|
gmrIndex = (gmrIndex + 1) % arraysize(gmrFences);
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|