aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/hw/xgl/xglgeometry.c
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/hw/xgl/xglgeometry.c')
-rw-r--r--xorg-server/hw/xgl/xglgeometry.c724
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;
+}