diff options
Diffstat (limited to 'xorg-server/hw/xgl/xglgeometry.c')
-rw-r--r-- | xorg-server/hw/xgl/xglgeometry.c | 724 |
1 files changed, 724 insertions, 0 deletions
diff --git a/xorg-server/hw/xgl/xglgeometry.c b/xorg-server/hw/xgl/xglgeometry.c new file mode 100644 index 000000000..7ab1ba45c --- /dev/null +++ b/xorg-server/hw/xgl/xglgeometry.c @@ -0,0 +1,724 @@ +/* + * Copyright © 2004 David Reveman + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * David Reveman not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * David Reveman makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: David Reveman <davidr@novell.com> + */ + +#include "xgl.h" +#include <X11/fonts/fontstruct.h> +#include "dixfontstr.h" + +xglDataTypeInfoRec xglGeometryDataTypes[2] = { + { GLITZ_DATA_TYPE_SHORT, sizeof (glitz_short_t) }, + { GLITZ_DATA_TYPE_FLOAT, sizeof (glitz_float_t) } +}; + +glitz_buffer_hint_t usageTypes[] = { + GLITZ_BUFFER_HINT_STREAM_DRAW, + GLITZ_BUFFER_HINT_STATIC_DRAW, + GLITZ_BUFFER_HINT_DYNAMIC_DRAW +}; + +void +xglGeometryResize (ScreenPtr pScreen, + xglGeometryPtr pGeometry, + int size) +{ + XGL_SCREEN_PRIV (pScreen); + + if (size == pGeometry->size) + return; + + if (pGeometry->broken) + return; + + if (pGeometry->usage == GEOMETRY_USAGE_SYSMEM) + { + pGeometry->data = xrealloc (pGeometry->data, size); + + if (pGeometry->buffer) + glitz_buffer_destroy (pGeometry->buffer); + + pGeometry->buffer = NULL; + + if (pGeometry->data) + { + pGeometry->buffer = glitz_buffer_create_for_data (pGeometry->data); + if (!pGeometry->buffer) + { + pGeometry->broken = TRUE; + return; + } + } + else if (size) + { + pGeometry->broken = TRUE; + return; + } + } + else + { + glitz_buffer_t *newBuffer; + + if (size) + { + newBuffer = + glitz_vertex_buffer_create (pScreenPriv->drawable, NULL, size, + usageTypes[pGeometry->usage]); + if (!newBuffer) + { + pGeometry->broken = TRUE; + return; + } + } else + newBuffer = NULL; + + if (pGeometry->buffer && newBuffer) + { + void *oldData, *newData; + + oldData = glitz_buffer_map (pGeometry->buffer, + GLITZ_BUFFER_ACCESS_READ_ONLY); + newData = glitz_buffer_map (newBuffer, + GLITZ_BUFFER_ACCESS_WRITE_ONLY); + + if (oldData && newData) + memcpy (newData, oldData, MIN (size, pGeometry->size)); + + glitz_buffer_unmap (pGeometry->buffer); + glitz_buffer_unmap (newBuffer); + + glitz_buffer_destroy (pGeometry->buffer); + } + pGeometry->buffer = newBuffer; + } + + pGeometry->size = size; + + if (pGeometry->endOffset > size) + pGeometry->endOffset = size; +} + +#define MAP_GEOMETRY(pScreen, pGeometry, offset, units, ptr, _size) \ + if ((pGeometry)->broken) \ + return; \ + (_size) = (units) * xglGeometryDataTypes[(pGeometry)->dataType].size; \ + if (((pGeometry)->size - (offset)) < (_size)) \ + { \ + xglGeometryResize (pScreen, pGeometry, \ + (pGeometry)->endOffset + (_size) + 500); \ + if ((pGeometry)->broken) \ + return; \ + } \ + (ptr) = glitz_buffer_map ((pGeometry)->buffer, \ + GLITZ_BUFFER_ACCESS_WRITE_ONLY); \ + if (!(ptr)) \ + { \ + (pGeometry)->broken = TRUE; \ + return; \ + } \ + (ptr) += (offset) + +#define UNMAP_GEOMETRY(pGeometry, offset, _size) \ + if (glitz_buffer_unmap ((pGeometry)->buffer)) \ + { \ + (pGeometry)->broken = TRUE; \ + return; \ + } \ + if (((offset) + (_size)) > (pGeometry)->endOffset) \ + { \ + (pGeometry)->endOffset = (offset) + (_size); \ + (pGeometry)->count = (pGeometry)->endOffset / \ + (2 * xglGeometryDataTypes[(pGeometry)->dataType].size); \ + } + +/* + * Adds a number of boxes as GL_QUAD primitives + */ +void +xglGeometryAddBox (ScreenPtr pScreen, + xglGeometryPtr pGeometry, + BoxPtr pBox, + int nBox, + int offset) +{ + int size; + char *ptr; + + if (nBox < 1) + return; + + MAP_GEOMETRY (pScreen, pGeometry, offset, nBox * 8, ptr, size); + + switch (pGeometry->dataType) { + case GEOMETRY_DATA_TYPE_SHORT: + { + glitz_short_t *data = (glitz_short_t *) ptr; + + while (nBox--) + { + *data++ = (glitz_short_t) pBox->x1; + *data++ = (glitz_short_t) pBox->y1; + *data++ = (glitz_short_t) pBox->x2; + *data++ = (glitz_short_t) pBox->y1; + *data++ = (glitz_short_t) pBox->x2; + *data++ = (glitz_short_t) pBox->y2; + *data++ = (glitz_short_t) pBox->x1; + *data++ = (glitz_short_t) pBox->y2; + + pBox++; + } + } break; + case GEOMETRY_DATA_TYPE_FLOAT: + { + glitz_float_t *data = (glitz_float_t *) ptr; + + while (nBox--) + { + *data++ = (glitz_float_t) pBox->x1; + *data++ = (glitz_float_t) pBox->y1; + *data++ = (glitz_float_t) pBox->x2; + *data++ = (glitz_float_t) pBox->y1; + *data++ = (glitz_float_t) pBox->x2; + *data++ = (glitz_float_t) pBox->y2; + *data++ = (glitz_float_t) pBox->x1; + *data++ = (glitz_float_t) pBox->y2; + + pBox++; + } + } break; + } + + UNMAP_GEOMETRY (pGeometry, offset, size); +} + +/* + * Adds a number of spans as GL_LINE primitives + */ +void +xglGeometryAddSpan (ScreenPtr pScreen, + xglGeometryPtr pGeometry, + DDXPointPtr ppt, + int *pwidth, + int n, + int offset) +{ + int size; + char *ptr; + + if (n < 1) + return; + + MAP_GEOMETRY (pScreen, pGeometry, offset, n * 4, ptr, size); + + switch (pGeometry->dataType) { + case GEOMETRY_DATA_TYPE_SHORT: + { + glitz_short_t *data = (glitz_short_t *) ptr; + + while (n--) + { + *data++ = (glitz_short_t) ppt->x; + *data++ = (glitz_short_t) ppt->y; + *data++ = (glitz_short_t) (ppt->x + *pwidth); + *data++ = (glitz_short_t) ppt->y; + + ppt++; + pwidth++; + } + } break; + case GEOMETRY_DATA_TYPE_FLOAT: + { + glitz_float_t *data = (glitz_float_t *) ptr; + + while (n--) + { + *data++ = (glitz_float_t) ppt->x; + *data++ = (glitz_float_t) ppt->y; + *data++ = (glitz_float_t) (ppt->x + *pwidth); + *data++ = (glitz_float_t) ppt->y; + + ppt++; + pwidth++; + } + } break; + } + + UNMAP_GEOMETRY (pGeometry, offset, size); +} + +/* + * This macro is needed for end pixels to be rasterized correctly using + * OpenGL as OpenGL line segments are half-opened. + */ +#define ADJUST_END_POINT(start, end, isPoint) \ + (((end) > (start)) ? (end) + 1: \ + ((end) < (start)) ? (end) - 1: \ + (isPoint) ? (end) + 1: \ + (end)) + +/* + * Adds a number of connected lines as GL_LINE_STRIP primitives + */ +void +xglGeometryAddLine (ScreenPtr pScreen, + xglGeometryPtr pGeometry, + int loop, + int mode, + int npt, + DDXPointPtr ppt, + int offset) +{ + DDXPointRec pt; + int size; + char *ptr; + + if (npt < 2) + return; + + MAP_GEOMETRY (pScreen, pGeometry, offset, npt * 2, ptr, size); + + pt.x = 0; + pt.y = 0; + + switch (pGeometry->dataType) { + case GEOMETRY_DATA_TYPE_SHORT: + { + glitz_short_t *data = (glitz_short_t *) ptr; + + while (npt--) + { + if (mode == CoordModePrevious) + { + pt.x += ppt->x; + pt.y += ppt->y; + } + else + { + pt.x = ppt->x; + pt.y = ppt->y; + } + + if (npt || loop) + { + *data++ = (glitz_short_t) pt.x; + *data++ = (glitz_short_t) pt.y; + } + else + { + ppt--; + *data++ = (glitz_short_t) + ADJUST_END_POINT (ppt->x, pt.x, ppt->y == pt.y); + *data++ = (glitz_short_t) ADJUST_END_POINT (ppt->y, pt.y, 0); + } + + ppt++; + } + } break; + case GEOMETRY_DATA_TYPE_FLOAT: + { + glitz_float_t *data = (glitz_float_t *) ptr; + + while (npt--) + { + if (mode == CoordModePrevious) + { + pt.x += ppt->x; + pt.y += ppt->y; + } + else + { + pt.x = ppt->x; + pt.y = ppt->y; + } + + if (npt || loop) + { + *data++ = (glitz_float_t) pt.x; + *data++ = (glitz_float_t) pt.y; + } + else + { + ppt--; + *data++ = (glitz_float_t) + ADJUST_END_POINT (ppt->x, pt.x, ppt->y == pt.y); + *data++ = (glitz_float_t) ADJUST_END_POINT (ppt->y, pt.y, 0); + } + + ppt++; + } + } break; + } + + UNMAP_GEOMETRY (pGeometry, offset, size); +} + +/* + * Adds a number of line segments as GL_LINE primitives + */ +void +xglGeometryAddSegment (ScreenPtr pScreen, + xglGeometryPtr pGeometry, + int nsegInit, + xSegment *pSegInit, + int offset) +{ + int size; + char *ptr; + + if (nsegInit < 1) + return; + + MAP_GEOMETRY (pScreen, pGeometry, offset, nsegInit * 4, ptr, size); + + switch (pGeometry->dataType) { + case GEOMETRY_DATA_TYPE_SHORT: + { + glitz_short_t *data = (glitz_short_t *) ptr; + + while (nsegInit--) + { + *data++ = (glitz_short_t) pSegInit->x1; + *data++ = (glitz_short_t) pSegInit->y1; + *data++ = (glitz_short_t) + ADJUST_END_POINT (pSegInit->x1, pSegInit->x2, + pSegInit->y1 == pSegInit->y2); + *data++ = (glitz_short_t) + ADJUST_END_POINT (pSegInit->y1, pSegInit->y2, 0); + + pSegInit++; + } + } break; + case GEOMETRY_DATA_TYPE_FLOAT: + { + glitz_float_t *data = (glitz_float_t *) ptr; + + while (nsegInit--) + { + *data++ = (glitz_float_t) pSegInit->x1; + *data++ = (glitz_float_t) pSegInit->y1; + *data++ = (glitz_float_t) + ADJUST_END_POINT (pSegInit->x1, pSegInit->x2, + pSegInit->y1 == pSegInit->y2); + *data++ = (glitz_float_t) + ADJUST_END_POINT (pSegInit->y1, pSegInit->y2, 0); + + pSegInit++; + } + } break; + } + + UNMAP_GEOMETRY (pGeometry, offset, size); +} + +void +xglGeometryForGlyph (ScreenPtr pScreen, + xglGeometryPtr pGeometry, + unsigned int nGlyph, + CharInfoPtr *ppciInit, + pointer pglyphBase) +{ + CharInfoPtr *ppci; + CharInfoPtr pci; + unsigned char *glyphbase = (pointer) ~0; + unsigned char *pglyph; + int x = 0; + int gx, gy; + int gWidth, gHeight; + int n, lastX = 0, lastY = 0; + glitz_multi_array_t *array; + glitz_buffer_t *buffer; + + ppci = ppciInit; + n = nGlyph; + + while (n--) + { + pglyph = FONTGLYPHBITS (pglyphBase, *ppci++); + if (pglyph < glyphbase) + glyphbase = pglyph; + } + + buffer = glitz_buffer_create_for_data (glyphbase); + if (!buffer) + { + pGeometry->broken = TRUE; + return; + } + + GEOMETRY_SET_BUFFER (pGeometry, buffer); + + array = glitz_multi_array_create (nGlyph); + if (!array) + { + pGeometry->broken = TRUE; + return; + } + + GEOMETRY_SET_MULTI_ARRAY (pGeometry, array); + + ppci = ppciInit; + while (nGlyph--) + { + pci = *ppci++; + pglyph = FONTGLYPHBITS (pglyphBase, pci); + gWidth = GLYPHWIDTHPIXELS (pci); + gHeight = GLYPHHEIGHTPIXELS (pci); + + if (gWidth && gHeight) + { + gx = x + pci->metrics.leftSideBearing; + gy = -pci->metrics.ascent; + + glitz_multi_array_add (array, + (pglyph - glyphbase) * 8, + gWidth, gHeight, + (gx - lastX) << 16, (gy - lastY) << 16); + lastX = gx; + lastY = gy; + } + x += pci->metrics.characterWidth; + } + + glitz_buffer_destroy (buffer); + glitz_multi_array_destroy (array); +} + +#define FIXED_LINE_X_TO_FLOAT(line, v) \ + (((glitz_float_t) \ + ((line).p1.x + (xFixed_16_16) \ + (((xFixed_32_32) ((v) - (line).p1.y) * \ + ((line).p2.x - (line).p1.x)) / \ + ((line).p2.y - (line).p1.y)))) / 65536) + +#define FIXED_LINE_X_CEIL_TO_FLOAT(line, v) \ + (((glitz_float_t) \ + ((line).p1.x + (xFixed_16_16) \ + (((((line).p2.y - (line).p1.y) - 1) + \ + ((xFixed_32_32) ((v) - (line).p1.y) * \ + ((line).p2.x - (line).p1.x))) / \ + ((line).p2.y - (line).p1.y)))) / 65536) + +/* + * Adds a number of trapezoids as GL_QUAD primitives + */ +void +xglGeometryAddTrapezoid (ScreenPtr pScreen, + xglGeometryPtr pGeometry, + xTrapezoid *pTrap, + int nTrap, + int offset) +{ + int size; + char *ptr; + + if (nTrap < 1) + return; + + MAP_GEOMETRY (pScreen, pGeometry, offset, nTrap * 8, ptr, size); + + switch (pGeometry->dataType) { + case GEOMETRY_DATA_TYPE_SHORT: + /* not supported */ + pGeometry->broken = TRUE; + break; + case GEOMETRY_DATA_TYPE_FLOAT: + { + glitz_float_t *data = (glitz_float_t *) ptr; + glitz_float_t top, bottom; + + while (nTrap--) + { + top = FIXED_TO_FLOAT (pTrap->top); + bottom = FIXED_TO_FLOAT (pTrap->bottom); + + *data++ = FIXED_LINE_X_TO_FLOAT (pTrap->left, pTrap->top); + *data++ = top; + *data++ = FIXED_LINE_X_CEIL_TO_FLOAT (pTrap->right, pTrap->top); + *data++ = top; + *data++ = FIXED_LINE_X_CEIL_TO_FLOAT (pTrap->right, pTrap->bottom); + *data++ = bottom; + *data++ = FIXED_LINE_X_TO_FLOAT (pTrap->left, pTrap->bottom); + *data++ = bottom; + + pTrap++; + } + } break; + } + + UNMAP_GEOMETRY (pGeometry, offset, size); +} + +/* + * Adds a number of traps as GL_QUAD primitives + */ +void +xglGeometryAddTrap (ScreenPtr pScreen, + xglGeometryPtr pGeometry, + xTrap *pTrap, + int nTrap, + int offset) +{ + int size; + char *ptr; + + if (nTrap < 1) + return; + + MAP_GEOMETRY (pScreen, pGeometry, offset, nTrap * 8, ptr, size); + + switch (pGeometry->dataType) { + case GEOMETRY_DATA_TYPE_SHORT: + /* not supported */ + pGeometry->broken = TRUE; + break; + case GEOMETRY_DATA_TYPE_FLOAT: + { + glitz_float_t *data = (glitz_float_t *) ptr; + glitz_float_t top, bottom; + + while (nTrap--) + { + top = FIXED_TO_FLOAT (pTrap->top.y); + bottom = FIXED_TO_FLOAT (pTrap->bot.y); + + *data++ = FIXED_TO_FLOAT (pTrap->top.l); + *data++ = top; + *data++ = FIXED_TO_FLOAT (pTrap->top.r); + *data++ = top; + *data++ = FIXED_TO_FLOAT (pTrap->bot.r); + *data++ = bottom; + *data++ = FIXED_TO_FLOAT (pTrap->bot.l); + *data++ = bottom; + + pTrap++; + } + } break; + } + + UNMAP_GEOMETRY (pGeometry, offset, size); +} + +/* XXX: scratch geometry size never shrinks, it just gets larger when + required. this is not acceptable. */ +xglGeometryPtr +xglGetScratchGeometryWithSize (ScreenPtr pScreen, + int size) +{ + xglGeometryPtr pGeometry; + + XGL_SCREEN_PRIV (pScreen); + + pGeometry = &pScreenPriv->scratchGeometry; + + if (pGeometry->broken || pGeometry->size < size) + { + GEOMETRY_UNINIT (pGeometry); + GEOMETRY_INIT (pScreen, pGeometry, pGeometry->type, + pScreenPriv->geometryUsage, size); + } + else + { + if (pGeometry->array) + { + glitz_multi_array_destroy (pGeometry->array); + pGeometry->array = NULL; + } + pGeometry->endOffset = 0; + pGeometry->xOff = 0; + pGeometry->yOff = 0; + pGeometry->first = 0; + pGeometry->count = 0; + pGeometry->width = 2; + } + + return pGeometry; +} + +xglGeometryPtr +xglGetScratchVertexGeometryWithType (ScreenPtr pScreen, + int type, + int count) +{ + xglGeometryPtr pGeometry; + int stride; + + stride = 2 * xglGeometryDataTypes[type].size; + + pGeometry = xglGetScratchGeometryWithSize (pScreen, count * stride); + + pGeometry->type = GLITZ_GEOMETRY_TYPE_VERTEX; + pGeometry->dataType = type; + + pGeometry->f.vertex.primitive = GLITZ_PRIMITIVE_QUADS; + pGeometry->f.vertex.type = xglGeometryDataTypes[type].type; + pGeometry->f.vertex.bytes_per_vertex = stride; + pGeometry->f.vertex.attributes = 0; + + return pGeometry; +} + +xglGeometryPtr +xglGetScratchVertexGeometry (ScreenPtr pScreen, + int count) +{ + xglGeometryPtr pGeometry; + int type, stride; + + XGL_SCREEN_PRIV (pScreen); + + type = pScreenPriv->geometryDataType; + stride = 2 * xglGeometryDataTypes[type].size; + + pGeometry = xglGetScratchGeometryWithSize (pScreen, count * stride); + + pGeometry->type = GLITZ_GEOMETRY_TYPE_VERTEX; + pGeometry->dataType = type; + + pGeometry->f.vertex.primitive = GLITZ_PRIMITIVE_QUADS; + pGeometry->f.vertex.type = xglGeometryDataTypes[type].type; + pGeometry->f.vertex.bytes_per_vertex = stride; + pGeometry->f.vertex.attributes = 0; + + return pGeometry; +} + +Bool +xglSetGeometry (xglGeometryPtr pGeometry, + glitz_surface_t *surface) +{ + if (pGeometry->broken) + return FALSE; + + glitz_set_geometry (surface, pGeometry->type, &pGeometry->f, + pGeometry->buffer); + + if (pGeometry->array) + glitz_set_multi_array (surface, pGeometry->array, + pGeometry->xOff, pGeometry->yOff); + else + glitz_set_array (surface, + pGeometry->first, pGeometry->width, pGeometry->count, + pGeometry->xOff, pGeometry->yOff); + + return TRUE; +} |