298 lines
6.9 KiB
C
298 lines
6.9 KiB
C
|
/*
|
||
|
* video-formats -- Demonstrate all supported video overlay formats.
|
||
|
*
|
||
|
* XXX: There are some known bugs in the currently released VMware
|
||
|
* products, which are exposed by this test:
|
||
|
*
|
||
|
* 1. The very first VideoFlush may not appear. In this test,
|
||
|
* the bug manifests as "No Overlay" for test #1.
|
||
|
*
|
||
|
* 2. Software emulated scaling is very low quality.
|
||
|
*
|
||
|
* 3. If the host is using hardware video overlay rather than
|
||
|
* its software fallback, it assumes that colorkey is always
|
||
|
* enabled. This means our video will only draw in the black
|
||
|
* portions of the background image (inside the "X", and
|
||
|
* the box around the "No overlay" text.)
|
||
|
*
|
||
|
* Copyright (C) 2008-2009 VMware, Inc. Licensed under the MIT
|
||
|
* License, please see the README.txt. All rights reserved.
|
||
|
*/
|
||
|
|
||
|
|
||
|
#include "svga.h"
|
||
|
#include "png.h"
|
||
|
#include "intr.h"
|
||
|
#include "datafile.h"
|
||
|
|
||
|
|
||
|
/*
|
||
|
* This is our video test card, in UYVY format.
|
||
|
*
|
||
|
* It's a 720x576 pixel 4:3 aspect test card designed by Barney
|
||
|
* Wol. (http://www.barney-wol.net/testpatterns)
|
||
|
*/
|
||
|
|
||
|
DECLARE_DATAFILE(testCardFile, wols4x3_yuv_z);
|
||
|
|
||
|
#define TESTCARD_WIDTH 720
|
||
|
#define TESTCARD_HEIGHT 576
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Our background image, in PNG format.
|
||
|
*
|
||
|
* This has 'cutouts' where we're supposed to display the test
|
||
|
* pattern. Each of these are described by the table of overlay
|
||
|
* settings below.
|
||
|
*/
|
||
|
|
||
|
DECLARE_DATAFILE(screenPNGFile, screen_png);
|
||
|
|
||
|
#define OFFSET_YUY2 0x400000
|
||
|
#define OFFSET_UYVY 0x500000
|
||
|
#define OFFSET_YV12 0x600000
|
||
|
|
||
|
static SVGAOverlayUnit overlays[] = {
|
||
|
// #0 - YUY2 Large
|
||
|
{
|
||
|
.enabled = TRUE,
|
||
|
.format = VMWARE_FOURCC_YUY2,
|
||
|
.width = TESTCARD_WIDTH,
|
||
|
.height = TESTCARD_HEIGHT,
|
||
|
.srcWidth = TESTCARD_WIDTH,
|
||
|
.srcHeight = TESTCARD_HEIGHT,
|
||
|
.dstX = 109,
|
||
|
.dstY = 407,
|
||
|
.dstWidth = 320,
|
||
|
.dstHeight = 240,
|
||
|
.pitches[0] = TESTCARD_WIDTH * 2,
|
||
|
.dataOffset = OFFSET_YUY2,
|
||
|
},
|
||
|
|
||
|
// #1 - YV12 Large
|
||
|
{
|
||
|
.enabled = TRUE,
|
||
|
.format = VMWARE_FOURCC_YV12,
|
||
|
.width = TESTCARD_WIDTH,
|
||
|
.height = TESTCARD_HEIGHT,
|
||
|
.srcWidth = TESTCARD_WIDTH,
|
||
|
.srcHeight = TESTCARD_HEIGHT,
|
||
|
.dstX = 564,
|
||
|
.dstY = 58,
|
||
|
.dstWidth = 320,
|
||
|
.dstHeight = 240,
|
||
|
.pitches[0] = TESTCARD_WIDTH,
|
||
|
.pitches[1] = TESTCARD_WIDTH / 2,
|
||
|
.pitches[2] = TESTCARD_WIDTH / 2,
|
||
|
.dataOffset = OFFSET_YV12,
|
||
|
},
|
||
|
|
||
|
// #2 - UYVY Large
|
||
|
{
|
||
|
.enabled = TRUE,
|
||
|
.format = VMWARE_FOURCC_UYVY,
|
||
|
.width = TESTCARD_WIDTH,
|
||
|
.height = TESTCARD_HEIGHT,
|
||
|
.srcWidth = TESTCARD_WIDTH,
|
||
|
.srcHeight = TESTCARD_HEIGHT,
|
||
|
.dstX = 564,
|
||
|
.dstY = 407,
|
||
|
.dstWidth = 320,
|
||
|
.dstHeight = 240,
|
||
|
.pitches[0] = TESTCARD_WIDTH * 2,
|
||
|
.dataOffset = OFFSET_UYVY,
|
||
|
},
|
||
|
|
||
|
// #3 - YUY2 Small
|
||
|
{
|
||
|
.enabled = TRUE,
|
||
|
.format = VMWARE_FOURCC_YUY2,
|
||
|
.width = TESTCARD_WIDTH,
|
||
|
.height = TESTCARD_HEIGHT,
|
||
|
.srcX = 34,
|
||
|
.srcY = 31,
|
||
|
.srcWidth = 76,
|
||
|
.srcHeight = 79,
|
||
|
.dstX = 109,
|
||
|
.dstY = 652,
|
||
|
.dstWidth = 64,
|
||
|
.dstHeight = 64,
|
||
|
.pitches[0] = TESTCARD_WIDTH * 2,
|
||
|
.dataOffset = OFFSET_YUY2,
|
||
|
},
|
||
|
|
||
|
// #4 - YV12 Small
|
||
|
{
|
||
|
.enabled = TRUE,
|
||
|
.format = VMWARE_FOURCC_YV12,
|
||
|
.width = TESTCARD_WIDTH,
|
||
|
.height = TESTCARD_HEIGHT,
|
||
|
.srcX = 34,
|
||
|
.srcY = 31,
|
||
|
.srcWidth = 76,
|
||
|
.srcHeight = 79,
|
||
|
.dstX = 564,
|
||
|
.dstY = 303,
|
||
|
.dstWidth = 64,
|
||
|
.dstHeight = 64,
|
||
|
.pitches[0] = TESTCARD_WIDTH,
|
||
|
.pitches[1] = TESTCARD_WIDTH / 2,
|
||
|
.pitches[2] = TESTCARD_WIDTH / 2,
|
||
|
.dataOffset = OFFSET_YV12,
|
||
|
},
|
||
|
|
||
|
// #5 - UYVY Small
|
||
|
{
|
||
|
.enabled = TRUE,
|
||
|
.format = VMWARE_FOURCC_UYVY,
|
||
|
.width = TESTCARD_WIDTH,
|
||
|
.height = TESTCARD_HEIGHT,
|
||
|
.srcX = 34,
|
||
|
.srcY = 31,
|
||
|
.srcWidth = 76,
|
||
|
.srcHeight = 79,
|
||
|
.dstX = 564,
|
||
|
.dstY = 652,
|
||
|
.dstWidth = 64,
|
||
|
.dstHeight = 64,
|
||
|
.pitches[0] = TESTCARD_WIDTH * 2,
|
||
|
.dataOffset = OFFSET_UYVY,
|
||
|
},
|
||
|
};
|
||
|
|
||
|
|
||
|
/*
|
||
|
* convertUYVYtoYUY2 --
|
||
|
*
|
||
|
* Convert the test card image from UYVY format to YUY2.
|
||
|
* Both of these are packed-pixel formats, they just use
|
||
|
* different byte orders.
|
||
|
*/
|
||
|
|
||
|
static void
|
||
|
convertUYVYtoYUY2(uint8 *src, // IN
|
||
|
uint8 *dest) // OUT
|
||
|
{
|
||
|
uint32 numWords = TESTCARD_WIDTH / 2 * TESTCARD_HEIGHT;
|
||
|
|
||
|
while (numWords--) {
|
||
|
uint8 u = *(src++);
|
||
|
uint8 y1 = *(src++);
|
||
|
uint8 v = *(src++);
|
||
|
uint8 y2 = *(src++);
|
||
|
|
||
|
*(dest++) = y1;
|
||
|
*(dest++) = u;
|
||
|
*(dest++) = y2;
|
||
|
*(dest++) = v;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* convertUYVYtoYV12 --
|
||
|
*
|
||
|
* Convert the test card image from UYVY format (packed pixel) to
|
||
|
* YV12 (planar). This vertically decimates the chroma planes by
|
||
|
* 1/2.
|
||
|
*/
|
||
|
|
||
|
static void
|
||
|
convertUYVYtoYV12(uint8 *src, // IN
|
||
|
uint8 *dest) // OUT
|
||
|
{
|
||
|
/*
|
||
|
* Y plane, full resolution.
|
||
|
*/
|
||
|
|
||
|
uint8 *s = src;
|
||
|
uint32 numWords = TESTCARD_WIDTH / 2 * TESTCARD_HEIGHT;
|
||
|
while (numWords--) {
|
||
|
s++; // U
|
||
|
*(dest++) = *(s++); // Y1
|
||
|
s++; // V
|
||
|
*(dest++) = *(s++); // Y2
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* U and V planes, at 1/2 height.
|
||
|
*/
|
||
|
|
||
|
uint32 x, y;
|
||
|
const uint32 pitch = TESTCARD_WIDTH * 2;
|
||
|
uint8 *line1 = src;
|
||
|
uint8 *v = dest;
|
||
|
uint8 *u = v + (TESTCARD_WIDTH * TESTCARD_HEIGHT) / 4;
|
||
|
|
||
|
for (y = TESTCARD_HEIGHT/2; y; y--) {
|
||
|
uint8 *line2 = line1 + pitch;
|
||
|
|
||
|
for (x = TESTCARD_WIDTH/2; x; x--) {
|
||
|
|
||
|
uint8 u1 = *(line1)++; // U
|
||
|
line1++; // Y1
|
||
|
uint8 v1 = *(line1)++; // V
|
||
|
line1++; // Y2
|
||
|
|
||
|
uint8 u2 = *(line2)++; // U
|
||
|
line2++; // Y1
|
||
|
uint8 v2 = *(line2)++; // V
|
||
|
line2++; // Y2
|
||
|
|
||
|
*(u++) = ((int)u1 + (int)u2) >> 1;
|
||
|
*(v++) = ((int)v1 + (int)v2) >> 1;
|
||
|
}
|
||
|
|
||
|
line1 = line2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* main --
|
||
|
*
|
||
|
* Set up the virtual hardware, decompress the YUV images, and
|
||
|
* program the overlay units.
|
||
|
*/
|
||
|
|
||
|
int
|
||
|
main(void)
|
||
|
{
|
||
|
PNGChunkIHDR *screenPNG = PNG_Header(screenPNGFile->ptr);
|
||
|
uint32 width = bswap32(screenPNG->width);
|
||
|
uint32 height = bswap32(screenPNG->height);
|
||
|
uint32 streamId;
|
||
|
|
||
|
Intr_Init();
|
||
|
Intr_SetFaultHandlers(SVGA_DefaultFaultHandler);
|
||
|
SVGA_Init();
|
||
|
SVGA_SetMode(width, height, 32);
|
||
|
|
||
|
/*
|
||
|
* Draw the background image
|
||
|
*/
|
||
|
|
||
|
PNG_DecompressBGRX(screenPNG, (uint32*) gSVGA.fbMem, gSVGA.pitch);
|
||
|
SVGA_Update(0, 0, width, height);
|
||
|
|
||
|
/*
|
||
|
* Decompress the YUY2 image, and use it to generate UYVY and YV12 versions.
|
||
|
*/
|
||
|
|
||
|
DataFile_Decompress(testCardFile, gSVGA.fbMem + OFFSET_UYVY, 0x100000);
|
||
|
convertUYVYtoYUY2(gSVGA.fbMem + OFFSET_UYVY, gSVGA.fbMem + OFFSET_YUY2);
|
||
|
convertUYVYtoYV12(gSVGA.fbMem + OFFSET_UYVY, gSVGA.fbMem + OFFSET_YV12);
|
||
|
|
||
|
/*
|
||
|
* Program the overlay units
|
||
|
*/
|
||
|
|
||
|
for (streamId = 0; streamId < arraysize(overlays); streamId++) {
|
||
|
SVGA_VideoSetAllRegs(streamId, &overlays[streamId], SVGA_VIDEO_PITCH_3);
|
||
|
SVGA_VideoFlush(streamId);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|