vmware-svga/lib/util/svga3dtext.c

433 lines
13 KiB
C
Raw Normal View History

2009-04-13 02:05:42 -05:00
/**********************************************************
* Copyright 2008-2009 VMware, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
**********************************************************/
/*
* svga3dtext.c --
*
* Emulated text console, built on the SVGA3D protocol. This
* module allows the use of the VGA Console in 3D mode. We
* convert the ROM BIOS font into a texture, and sample character
* data from the text-mode framebuffer. Text attributes are
* ignored.
*
* This is used as a debug/diagnostic facility in the example
* programs, plus it's a simple but relatively efficient example
* of rendering using dynamic vertex buffer data.
*
* XXX: Now that there can be multiple Console backends, this no
* longer needs to be tied to VGA. We should just implement this
* as a normal Console backend.
*/
#include "svga3dutil.h"
#include "svga3dtext.h"
#include "matrix.h"
#include "console_vga.h"
typedef uint16 IndexType;
typedef struct {
uint16 position[2];
float texCoord[2];
uint32 color;
} VertexType;
#define MAX_NUM_CHARACTERS (VGA_TEXT_WIDTH * VGA_TEXT_HEIGHT)
#define MAX_VERTICES (MAX_NUM_CHARACTERS * 4)
#define MAX_INDICES (MAX_NUM_CHARACTERS * 6)
#define INDEX_BUF_SIZE (MAX_INDICES * sizeof(IndexType))
#define VERTEX_BUF_SIZE (MAX_VERTICES * sizeof(VertexType))
#define FONT_CHARACTERS 256
#define FONT_CHAR_WIDTH 9
#define FONT_CHAR_HEIGHT 9
#define FONT_GRID_WIDTH 25
#define FONT_WIDTH 256
#define FONT_HEIGHT 64
static struct {
uint32 fontSid;
uint32 ibSid;
uint32 vbSid;
SVGAGuestPtr vbGuestPtr;
VertexType *vbBuffer;
uint32 vbFence;
uint32 numTriangles;
Matrix view;
} self;
/*
*----------------------------------------------------------------------
*
* SVGA3DTextUnpackROMFont --
*
* Unpack the ROM BIOS font into a square texture, 16 characters
* by 8 characters, in 8-bit alpha format.
*
* Results:
* None.
*
* Side effects:
* Reads from BIOS memory.
*
*----------------------------------------------------------------------
*/
static void
SVGA3DTextUnpackROMFont(uint8 *buffer)
{
uint8 *romFont = (uint8*) 0xFFA6E;
uint8 fontChar = 0;
int gridX = 0, gridY = 0;
int charY;
memset(buffer, 0, FONT_WIDTH * FONT_HEIGHT);
while (fontChar < 128) {
for (charY = 0; charY < 8; charY++) {
uint8 fontByte = *(romFont++);
uint8 mask = 0x80;
uint8 *bufferLine = &buffer[FONT_WIDTH * (gridY * FONT_CHAR_HEIGHT + charY)
+ gridX * FONT_CHAR_WIDTH];
while (mask) {
if (fontByte & mask) {
*bufferLine = 0xFF;
}
bufferLine++;
mask >>= 1;
}
}
fontChar++;
gridX++;
if (gridX == FONT_GRID_WIDTH) {
gridX = 0;
gridY++;
}
}
}
/*
*----------------------------------------------------------------------
*
* SVGA3DText_Init --
*
* Initialize the SVGA3DText module. This populates the font
* texture, and sets up the vertex buffer and index buffer
* surfaces. It implicitly calls SVGA3DText_Update() for the
* first time.
*
* Results:
* None.
*
* Side effects:
* Allocates buffers, begins DMA.
*
*----------------------------------------------------------------------
*/
void
SVGA3DText_Init(void)
{
int i;
void *fontBuffer;
IndexType *indexBuffer;
SVGAGuestPtr fontGuestPtr;
SVGAGuestPtr ibGuestPtr;
/*
* XXX: We should stop depending on console_vga, and get our own framebuffer.
*/
ConsoleVGA_Init();
/*
* Populate the font texture with our ROM BIOS font.
*/
fontBuffer = SVGA3DUtil_AllocDMABuffer(FONT_WIDTH * FONT_HEIGHT, &fontGuestPtr);
SVGA3DTextUnpackROMFont(fontBuffer);
self.fontSid = SVGA3DUtil_DefineSurface2D(FONT_WIDTH, FONT_HEIGHT, SVGA3D_ALPHA8);
SVGA3DUtil_SurfaceDMA2D(self.fontSid, &fontGuestPtr, SVGA3D_WRITE_HOST_VRAM,
FONT_WIDTH, FONT_HEIGHT);
/*
* Populate the index buffer with a static pattern for drawing quads.
*/
indexBuffer = SVGA3DUtil_AllocDMABuffer(INDEX_BUF_SIZE, &ibGuestPtr);
for (i = 0; i < MAX_NUM_CHARACTERS; i++) {
/* First triangle */
indexBuffer[i * 6 + 0] = i * 4 + 0;
indexBuffer[i * 6 + 1] = i * 4 + 1;
indexBuffer[i * 6 + 2] = i * 4 + 2;
/* Second triangle */
indexBuffer[i * 6 + 3] = i * 4 + 2;
indexBuffer[i * 6 + 4] = i * 4 + 3;
indexBuffer[i * 6 + 5] = i * 4 + 0;
}
self.ibSid = SVGA3DUtil_DefineSurface2D(INDEX_BUF_SIZE, 1, SVGA3D_BUFFER);
SVGA3DUtil_SurfaceDMA2D(self.ibSid, &ibGuestPtr, SVGA3D_WRITE_HOST_VRAM,
INDEX_BUF_SIZE, 1);
/*
* Set up an empty vertex buffer. We'll fill it later.
*/
self.vbBuffer = SVGA3DUtil_AllocDMABuffer(VERTEX_BUF_SIZE, &self.vbGuestPtr);
self.vbSid = SVGA3DUtil_DefineSurface2D(VERTEX_BUF_SIZE, 1, SVGA3D_BUFFER);
/*
* Set up the view matrix.
*/
{
const float border = 0.05;
const float width = (2.0 - border*2) / VGA_TEXT_WIDTH;
const float height = (2.0 - border*2) / VGA_TEXT_HEIGHT;
Matrix_Copy(self.view, gIdentityMatrix);
Matrix_Scale(self.view, width, -height, 1, 1);
Matrix_Translate(self.view, -1 + border, 1 - border, 0);
}
SVGA3DText_Update();
}
/*
*----------------------------------------------------------------------
*
* SVGA3DText_Update --
*
* Build and upload a vertex buffer for rendering text from the
* current contents of the VGA framebuffer.
*
* Results:
* None.
*
* Side effects:
* May SyncToFence. Reads VGA memory.
*
*----------------------------------------------------------------------
*/
void
SVGA3DText_Update(void)
{
uint8 *textFb = (uint8*) 0xB8000;
int x, y;
VertexType *vertex = self.vbBuffer;
/* Wait for any previous DMA operations to finish. */
SVGA_SyncToFence(self.vbFence);
self.numTriangles = 0;
for (y = 0; y < VGA_TEXT_HEIGHT; y++) {
for (x = 0; x < VGA_TEXT_WIDTH; x++) {
uint8 textChar = *textFb;
textFb += 2;
if (textChar > 0 && textChar < 0x80 && textChar != ' ') {
int charX = textChar % FONT_GRID_WIDTH;
int charY = textChar / FONT_GRID_WIDTH;
const float xHalfTexel = 0.5 / (float)FONT_WIDTH;
const float yHalfTexel = 0.5 / (float)FONT_HEIGHT;
const float charWidth = FONT_CHAR_WIDTH / (float)FONT_WIDTH;
const float charHeight = FONT_CHAR_WIDTH / (float)FONT_HEIGHT;
vertex[0].position[0] = x;
vertex[0].position[1] = y;
vertex[0].texCoord[0] = charX * charWidth - xHalfTexel;
vertex[0].texCoord[1] = charY * charHeight - yHalfTexel;
vertex[0].color = 0xFFFFFFFF;
vertex[2].position[0] = x+1;
vertex[2].position[1] = y+1;
vertex[2].texCoord[0] = (charX+1) * charWidth - xHalfTexel;
vertex[2].texCoord[1] = (charY+1) * charHeight - yHalfTexel;
vertex[2].color = 0xFFFFFFFF;
vertex[1].position[0] = vertex[2].position[0];
vertex[1].position[1] = vertex[0].position[1];
vertex[1].texCoord[0] = vertex[2].texCoord[0];
vertex[1].texCoord[1] = vertex[0].texCoord[1];
vertex[1].color = 0xFFFFFFFF;
vertex[3].position[0] = vertex[0].position[0];
vertex[3].position[1] = vertex[2].position[1];
vertex[3].texCoord[0] = vertex[0].texCoord[0];
vertex[3].texCoord[1] = vertex[2].texCoord[1];
vertex[3].color = 0xFFFFFFFF;
self.numTriangles += 2;
vertex += 4;
}
}
}
SVGA3DUtil_SurfaceDMA2D(self.vbSid, &self.vbGuestPtr, SVGA3D_WRITE_HOST_VRAM,
(uint8*)vertex - (uint8*)self.vbBuffer, 1);
self.vbFence = SVGA_InsertFence();
}
/*
*----------------------------------------------------------------------
*
* SVGA3DText_Draw --
*
* Draw a screen full of text, using the current vertex buffer contents.
*
* Results:
* None.
*
* Side effects:
* Modifies a lot of render state.
*
*----------------------------------------------------------------------
*/
void
SVGA3DText_Draw(void)
{
SVGA3dVertexDecl *decls;
SVGA3dPrimitiveRange *ranges;
SVGA3dTextureState *ts;
SVGA3dRenderState *rs;
static const SVGA3dMaterial mat = {
.diffuse = { 1, 1, 1, 1 },
};
SVGA3D_SetMaterial(CID, SVGA3D_FACE_FRONT_BACK, &mat);
SVGA3D_SetTransform(CID, SVGA3D_TRANSFORM_VIEW, self.view);
SVGA3D_SetTransform(CID, SVGA3D_TRANSFORM_WORLD, gIdentityMatrix);
SVGA3D_SetTransform(CID, SVGA3D_TRANSFORM_PROJECTION, gIdentityMatrix);
SVGA3D_BeginSetRenderState(CID, &rs, 8);
{
rs[0].state = SVGA3D_RS_ZENABLE;
rs[0].uintValue = FALSE;
rs[1].state = SVGA3D_RS_ZWRITEENABLE;
rs[1].uintValue = FALSE;
rs[2].state = SVGA3D_RS_BLENDENABLE;
rs[2].uintValue = TRUE;
rs[3].state = SVGA3D_RS_SRCBLEND;
rs[3].uintValue = SVGA3D_BLENDOP_SRCALPHA;
rs[4].state = SVGA3D_RS_DSTBLEND;
rs[4].uintValue = SVGA3D_BLENDOP_INVSRCALPHA;
rs[5].state = SVGA3D_RS_BLENDEQUATION;
rs[5].uintValue = SVGA3D_BLENDEQ_ADD;
rs[6].state = SVGA3D_RS_LIGHTINGENABLE;
rs[6].uintValue = FALSE;
rs[7].state = SVGA3D_RS_CULLMODE;
rs[7].uintValue = SVGA3D_FACE_NONE;
}
SVGA_FIFOCommitAll();
SVGA3D_BeginSetTextureState(CID, &ts, 9);
{
ts[0].stage = 0;
ts[0].name = SVGA3D_TS_BIND_TEXTURE;
ts[0].value = self.fontSid;
ts[1].stage = 0;
ts[1].name = SVGA3D_TS_COLOROP;
ts[1].value = SVGA3D_TC_SELECTARG1;
ts[2].stage = 0;
ts[2].name = SVGA3D_TS_COLORARG1;
ts[2].value = SVGA3D_TA_DIFFUSE;
ts[3].stage = 0;
ts[3].name = SVGA3D_TS_ALPHAOP;
ts[3].value = SVGA3D_TC_SELECTARG1;
ts[4].stage = 0;
ts[4].name = SVGA3D_TS_ALPHAARG1;
ts[4].value = SVGA3D_TA_TEXTURE;
ts[5].stage = 0;
ts[5].name = SVGA3D_TS_MINFILTER;
ts[5].value = SVGA3D_TEX_FILTER_LINEAR;
ts[6].stage = 0;
ts[6].name = SVGA3D_TS_MAGFILTER;
ts[6].value = SVGA3D_TEX_FILTER_LINEAR;
ts[7].stage = 0;
ts[7].name = SVGA3D_TS_ADDRESSU;
ts[7].value = SVGA3D_TEX_ADDRESS_WRAP;
ts[8].stage = 0;
ts[8].name = SVGA3D_TS_ADDRESSV;
ts[8].value = SVGA3D_TEX_ADDRESS_WRAP;
}
SVGA_FIFOCommitAll();
SVGA3D_BeginDrawPrimitives(CID, &decls, 3, &ranges, 1);
{
decls[0].identity.type = SVGA3D_DECLTYPE_SHORT2;
decls[0].identity.usage = SVGA3D_DECLUSAGE_POSITION;
decls[0].array.surfaceId = self.vbSid;
decls[0].array.stride = sizeof(VertexType);
decls[0].array.offset = offsetof(VertexType, position);
decls[1].identity.type = SVGA3D_DECLTYPE_FLOAT2;
decls[1].identity.usage = SVGA3D_DECLUSAGE_TEXCOORD;
decls[1].array.surfaceId = self.vbSid;
decls[1].array.stride = sizeof(VertexType);
decls[1].array.offset = offsetof(VertexType, texCoord);
decls[2].identity.type = SVGA3D_DECLTYPE_D3DCOLOR;
decls[2].identity.usage = SVGA3D_DECLUSAGE_COLOR;
decls[2].array.surfaceId = self.vbSid;
decls[2].array.stride = sizeof(VertexType);
decls[2].array.offset = offsetof(VertexType, color);
ranges[0].primType = SVGA3D_PRIMITIVE_TRIANGLELIST;
ranges[0].primitiveCount = self.numTriangles;
ranges[0].indexArray.surfaceId = self.ibSid;
ranges[0].indexArray.stride = sizeof(IndexType);
ranges[0].indexWidth = sizeof(IndexType);
}
SVGA_FIFOCommitAll();
SVGA_RingDoorbell();
}