First import
[xorg_rtime.git] / xorg-server-1.4 / hw / xgl / xglgeometry.c
blob7ab1ba45c67bf4d9121b227e0d5ce4018a0f44b2
1 /*
2 * Copyright © 2004 David Reveman
4 * Permission to use, copy, modify, distribute, and sell this software
5 * and its documentation for any purpose is hereby granted without
6 * fee, provided that the above copyright notice appear in all copies
7 * and that both that copyright notice and this permission notice
8 * appear in supporting documentation, and that the name of
9 * David Reveman not be used in advertising or publicity pertaining to
10 * distribution of the software without specific, written prior permission.
11 * David Reveman makes no representations about the suitability of this
12 * software for any purpose. It is provided "as is" without express or
13 * implied warranty.
15 * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
17 * NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
19 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
21 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Author: David Reveman <davidr@novell.com>
26 #include "xgl.h"
27 #include <X11/fonts/fontstruct.h>
28 #include "dixfontstr.h"
30 xglDataTypeInfoRec xglGeometryDataTypes[2] = {
31 { GLITZ_DATA_TYPE_SHORT, sizeof (glitz_short_t) },
32 { GLITZ_DATA_TYPE_FLOAT, sizeof (glitz_float_t) }
35 glitz_buffer_hint_t usageTypes[] = {
36 GLITZ_BUFFER_HINT_STREAM_DRAW,
37 GLITZ_BUFFER_HINT_STATIC_DRAW,
38 GLITZ_BUFFER_HINT_DYNAMIC_DRAW
41 void
42 xglGeometryResize (ScreenPtr pScreen,
43 xglGeometryPtr pGeometry,
44 int size)
46 XGL_SCREEN_PRIV (pScreen);
48 if (size == pGeometry->size)
49 return;
51 if (pGeometry->broken)
52 return;
54 if (pGeometry->usage == GEOMETRY_USAGE_SYSMEM)
56 pGeometry->data = xrealloc (pGeometry->data, size);
58 if (pGeometry->buffer)
59 glitz_buffer_destroy (pGeometry->buffer);
61 pGeometry->buffer = NULL;
63 if (pGeometry->data)
65 pGeometry->buffer = glitz_buffer_create_for_data (pGeometry->data);
66 if (!pGeometry->buffer)
68 pGeometry->broken = TRUE;
69 return;
72 else if (size)
74 pGeometry->broken = TRUE;
75 return;
78 else
80 glitz_buffer_t *newBuffer;
82 if (size)
84 newBuffer =
85 glitz_vertex_buffer_create (pScreenPriv->drawable, NULL, size,
86 usageTypes[pGeometry->usage]);
87 if (!newBuffer)
89 pGeometry->broken = TRUE;
90 return;
92 } else
93 newBuffer = NULL;
95 if (pGeometry->buffer && newBuffer)
97 void *oldData, *newData;
99 oldData = glitz_buffer_map (pGeometry->buffer,
100 GLITZ_BUFFER_ACCESS_READ_ONLY);
101 newData = glitz_buffer_map (newBuffer,
102 GLITZ_BUFFER_ACCESS_WRITE_ONLY);
104 if (oldData && newData)
105 memcpy (newData, oldData, MIN (size, pGeometry->size));
107 glitz_buffer_unmap (pGeometry->buffer);
108 glitz_buffer_unmap (newBuffer);
110 glitz_buffer_destroy (pGeometry->buffer);
112 pGeometry->buffer = newBuffer;
115 pGeometry->size = size;
117 if (pGeometry->endOffset > size)
118 pGeometry->endOffset = size;
121 #define MAP_GEOMETRY(pScreen, pGeometry, offset, units, ptr, _size) \
122 if ((pGeometry)->broken) \
123 return; \
124 (_size) = (units) * xglGeometryDataTypes[(pGeometry)->dataType].size; \
125 if (((pGeometry)->size - (offset)) < (_size)) \
127 xglGeometryResize (pScreen, pGeometry, \
128 (pGeometry)->endOffset + (_size) + 500); \
129 if ((pGeometry)->broken) \
130 return; \
132 (ptr) = glitz_buffer_map ((pGeometry)->buffer, \
133 GLITZ_BUFFER_ACCESS_WRITE_ONLY); \
134 if (!(ptr)) \
136 (pGeometry)->broken = TRUE; \
137 return; \
139 (ptr) += (offset)
141 #define UNMAP_GEOMETRY(pGeometry, offset, _size) \
142 if (glitz_buffer_unmap ((pGeometry)->buffer)) \
144 (pGeometry)->broken = TRUE; \
145 return; \
147 if (((offset) + (_size)) > (pGeometry)->endOffset) \
149 (pGeometry)->endOffset = (offset) + (_size); \
150 (pGeometry)->count = (pGeometry)->endOffset / \
151 (2 * xglGeometryDataTypes[(pGeometry)->dataType].size); \
155 * Adds a number of boxes as GL_QUAD primitives
157 void
158 xglGeometryAddBox (ScreenPtr pScreen,
159 xglGeometryPtr pGeometry,
160 BoxPtr pBox,
161 int nBox,
162 int offset)
164 int size;
165 char *ptr;
167 if (nBox < 1)
168 return;
170 MAP_GEOMETRY (pScreen, pGeometry, offset, nBox * 8, ptr, size);
172 switch (pGeometry->dataType) {
173 case GEOMETRY_DATA_TYPE_SHORT:
175 glitz_short_t *data = (glitz_short_t *) ptr;
177 while (nBox--)
179 *data++ = (glitz_short_t) pBox->x1;
180 *data++ = (glitz_short_t) pBox->y1;
181 *data++ = (glitz_short_t) pBox->x2;
182 *data++ = (glitz_short_t) pBox->y1;
183 *data++ = (glitz_short_t) pBox->x2;
184 *data++ = (glitz_short_t) pBox->y2;
185 *data++ = (glitz_short_t) pBox->x1;
186 *data++ = (glitz_short_t) pBox->y2;
188 pBox++;
190 } break;
191 case GEOMETRY_DATA_TYPE_FLOAT:
193 glitz_float_t *data = (glitz_float_t *) ptr;
195 while (nBox--)
197 *data++ = (glitz_float_t) pBox->x1;
198 *data++ = (glitz_float_t) pBox->y1;
199 *data++ = (glitz_float_t) pBox->x2;
200 *data++ = (glitz_float_t) pBox->y1;
201 *data++ = (glitz_float_t) pBox->x2;
202 *data++ = (glitz_float_t) pBox->y2;
203 *data++ = (glitz_float_t) pBox->x1;
204 *data++ = (glitz_float_t) pBox->y2;
206 pBox++;
208 } break;
211 UNMAP_GEOMETRY (pGeometry, offset, size);
215 * Adds a number of spans as GL_LINE primitives
217 void
218 xglGeometryAddSpan (ScreenPtr pScreen,
219 xglGeometryPtr pGeometry,
220 DDXPointPtr ppt,
221 int *pwidth,
222 int n,
223 int offset)
225 int size;
226 char *ptr;
228 if (n < 1)
229 return;
231 MAP_GEOMETRY (pScreen, pGeometry, offset, n * 4, ptr, size);
233 switch (pGeometry->dataType) {
234 case GEOMETRY_DATA_TYPE_SHORT:
236 glitz_short_t *data = (glitz_short_t *) ptr;
238 while (n--)
240 *data++ = (glitz_short_t) ppt->x;
241 *data++ = (glitz_short_t) ppt->y;
242 *data++ = (glitz_short_t) (ppt->x + *pwidth);
243 *data++ = (glitz_short_t) ppt->y;
245 ppt++;
246 pwidth++;
248 } break;
249 case GEOMETRY_DATA_TYPE_FLOAT:
251 glitz_float_t *data = (glitz_float_t *) ptr;
253 while (n--)
255 *data++ = (glitz_float_t) ppt->x;
256 *data++ = (glitz_float_t) ppt->y;
257 *data++ = (glitz_float_t) (ppt->x + *pwidth);
258 *data++ = (glitz_float_t) ppt->y;
260 ppt++;
261 pwidth++;
263 } break;
266 UNMAP_GEOMETRY (pGeometry, offset, size);
270 * This macro is needed for end pixels to be rasterized correctly using
271 * OpenGL as OpenGL line segments are half-opened.
273 #define ADJUST_END_POINT(start, end, isPoint) \
274 (((end) > (start)) ? (end) + 1: \
275 ((end) < (start)) ? (end) - 1: \
276 (isPoint) ? (end) + 1: \
277 (end))
280 * Adds a number of connected lines as GL_LINE_STRIP primitives
282 void
283 xglGeometryAddLine (ScreenPtr pScreen,
284 xglGeometryPtr pGeometry,
285 int loop,
286 int mode,
287 int npt,
288 DDXPointPtr ppt,
289 int offset)
291 DDXPointRec pt;
292 int size;
293 char *ptr;
295 if (npt < 2)
296 return;
298 MAP_GEOMETRY (pScreen, pGeometry, offset, npt * 2, ptr, size);
300 pt.x = 0;
301 pt.y = 0;
303 switch (pGeometry->dataType) {
304 case GEOMETRY_DATA_TYPE_SHORT:
306 glitz_short_t *data = (glitz_short_t *) ptr;
308 while (npt--)
310 if (mode == CoordModePrevious)
312 pt.x += ppt->x;
313 pt.y += ppt->y;
315 else
317 pt.x = ppt->x;
318 pt.y = ppt->y;
321 if (npt || loop)
323 *data++ = (glitz_short_t) pt.x;
324 *data++ = (glitz_short_t) pt.y;
326 else
328 ppt--;
329 *data++ = (glitz_short_t)
330 ADJUST_END_POINT (ppt->x, pt.x, ppt->y == pt.y);
331 *data++ = (glitz_short_t) ADJUST_END_POINT (ppt->y, pt.y, 0);
334 ppt++;
336 } break;
337 case GEOMETRY_DATA_TYPE_FLOAT:
339 glitz_float_t *data = (glitz_float_t *) ptr;
341 while (npt--)
343 if (mode == CoordModePrevious)
345 pt.x += ppt->x;
346 pt.y += ppt->y;
348 else
350 pt.x = ppt->x;
351 pt.y = ppt->y;
354 if (npt || loop)
356 *data++ = (glitz_float_t) pt.x;
357 *data++ = (glitz_float_t) pt.y;
359 else
361 ppt--;
362 *data++ = (glitz_float_t)
363 ADJUST_END_POINT (ppt->x, pt.x, ppt->y == pt.y);
364 *data++ = (glitz_float_t) ADJUST_END_POINT (ppt->y, pt.y, 0);
367 ppt++;
369 } break;
372 UNMAP_GEOMETRY (pGeometry, offset, size);
376 * Adds a number of line segments as GL_LINE primitives
378 void
379 xglGeometryAddSegment (ScreenPtr pScreen,
380 xglGeometryPtr pGeometry,
381 int nsegInit,
382 xSegment *pSegInit,
383 int offset)
385 int size;
386 char *ptr;
388 if (nsegInit < 1)
389 return;
391 MAP_GEOMETRY (pScreen, pGeometry, offset, nsegInit * 4, ptr, size);
393 switch (pGeometry->dataType) {
394 case GEOMETRY_DATA_TYPE_SHORT:
396 glitz_short_t *data = (glitz_short_t *) ptr;
398 while (nsegInit--)
400 *data++ = (glitz_short_t) pSegInit->x1;
401 *data++ = (glitz_short_t) pSegInit->y1;
402 *data++ = (glitz_short_t)
403 ADJUST_END_POINT (pSegInit->x1, pSegInit->x2,
404 pSegInit->y1 == pSegInit->y2);
405 *data++ = (glitz_short_t)
406 ADJUST_END_POINT (pSegInit->y1, pSegInit->y2, 0);
408 pSegInit++;
410 } break;
411 case GEOMETRY_DATA_TYPE_FLOAT:
413 glitz_float_t *data = (glitz_float_t *) ptr;
415 while (nsegInit--)
417 *data++ = (glitz_float_t) pSegInit->x1;
418 *data++ = (glitz_float_t) pSegInit->y1;
419 *data++ = (glitz_float_t)
420 ADJUST_END_POINT (pSegInit->x1, pSegInit->x2,
421 pSegInit->y1 == pSegInit->y2);
422 *data++ = (glitz_float_t)
423 ADJUST_END_POINT (pSegInit->y1, pSegInit->y2, 0);
425 pSegInit++;
427 } break;
430 UNMAP_GEOMETRY (pGeometry, offset, size);
433 void
434 xglGeometryForGlyph (ScreenPtr pScreen,
435 xglGeometryPtr pGeometry,
436 unsigned int nGlyph,
437 CharInfoPtr *ppciInit,
438 pointer pglyphBase)
440 CharInfoPtr *ppci;
441 CharInfoPtr pci;
442 unsigned char *glyphbase = (pointer) ~0;
443 unsigned char *pglyph;
444 int x = 0;
445 int gx, gy;
446 int gWidth, gHeight;
447 int n, lastX = 0, lastY = 0;
448 glitz_multi_array_t *array;
449 glitz_buffer_t *buffer;
451 ppci = ppciInit;
452 n = nGlyph;
454 while (n--)
456 pglyph = FONTGLYPHBITS (pglyphBase, *ppci++);
457 if (pglyph < glyphbase)
458 glyphbase = pglyph;
461 buffer = glitz_buffer_create_for_data (glyphbase);
462 if (!buffer)
464 pGeometry->broken = TRUE;
465 return;
468 GEOMETRY_SET_BUFFER (pGeometry, buffer);
470 array = glitz_multi_array_create (nGlyph);
471 if (!array)
473 pGeometry->broken = TRUE;
474 return;
477 GEOMETRY_SET_MULTI_ARRAY (pGeometry, array);
479 ppci = ppciInit;
480 while (nGlyph--)
482 pci = *ppci++;
483 pglyph = FONTGLYPHBITS (pglyphBase, pci);
484 gWidth = GLYPHWIDTHPIXELS (pci);
485 gHeight = GLYPHHEIGHTPIXELS (pci);
487 if (gWidth && gHeight)
489 gx = x + pci->metrics.leftSideBearing;
490 gy = -pci->metrics.ascent;
492 glitz_multi_array_add (array,
493 (pglyph - glyphbase) * 8,
494 gWidth, gHeight,
495 (gx - lastX) << 16, (gy - lastY) << 16);
496 lastX = gx;
497 lastY = gy;
499 x += pci->metrics.characterWidth;
502 glitz_buffer_destroy (buffer);
503 glitz_multi_array_destroy (array);
506 #define FIXED_LINE_X_TO_FLOAT(line, v) \
507 (((glitz_float_t) \
508 ((line).p1.x + (xFixed_16_16) \
509 (((xFixed_32_32) ((v) - (line).p1.y) * \
510 ((line).p2.x - (line).p1.x)) / \
511 ((line).p2.y - (line).p1.y)))) / 65536)
513 #define FIXED_LINE_X_CEIL_TO_FLOAT(line, v) \
514 (((glitz_float_t) \
515 ((line).p1.x + (xFixed_16_16) \
516 (((((line).p2.y - (line).p1.y) - 1) + \
517 ((xFixed_32_32) ((v) - (line).p1.y) * \
518 ((line).p2.x - (line).p1.x))) / \
519 ((line).p2.y - (line).p1.y)))) / 65536)
522 * Adds a number of trapezoids as GL_QUAD primitives
524 void
525 xglGeometryAddTrapezoid (ScreenPtr pScreen,
526 xglGeometryPtr pGeometry,
527 xTrapezoid *pTrap,
528 int nTrap,
529 int offset)
531 int size;
532 char *ptr;
534 if (nTrap < 1)
535 return;
537 MAP_GEOMETRY (pScreen, pGeometry, offset, nTrap * 8, ptr, size);
539 switch (pGeometry->dataType) {
540 case GEOMETRY_DATA_TYPE_SHORT:
541 /* not supported */
542 pGeometry->broken = TRUE;
543 break;
544 case GEOMETRY_DATA_TYPE_FLOAT:
546 glitz_float_t *data = (glitz_float_t *) ptr;
547 glitz_float_t top, bottom;
549 while (nTrap--)
551 top = FIXED_TO_FLOAT (pTrap->top);
552 bottom = FIXED_TO_FLOAT (pTrap->bottom);
554 *data++ = FIXED_LINE_X_TO_FLOAT (pTrap->left, pTrap->top);
555 *data++ = top;
556 *data++ = FIXED_LINE_X_CEIL_TO_FLOAT (pTrap->right, pTrap->top);
557 *data++ = top;
558 *data++ = FIXED_LINE_X_CEIL_TO_FLOAT (pTrap->right, pTrap->bottom);
559 *data++ = bottom;
560 *data++ = FIXED_LINE_X_TO_FLOAT (pTrap->left, pTrap->bottom);
561 *data++ = bottom;
563 pTrap++;
565 } break;
568 UNMAP_GEOMETRY (pGeometry, offset, size);
572 * Adds a number of traps as GL_QUAD primitives
574 void
575 xglGeometryAddTrap (ScreenPtr pScreen,
576 xglGeometryPtr pGeometry,
577 xTrap *pTrap,
578 int nTrap,
579 int offset)
581 int size;
582 char *ptr;
584 if (nTrap < 1)
585 return;
587 MAP_GEOMETRY (pScreen, pGeometry, offset, nTrap * 8, ptr, size);
589 switch (pGeometry->dataType) {
590 case GEOMETRY_DATA_TYPE_SHORT:
591 /* not supported */
592 pGeometry->broken = TRUE;
593 break;
594 case GEOMETRY_DATA_TYPE_FLOAT:
596 glitz_float_t *data = (glitz_float_t *) ptr;
597 glitz_float_t top, bottom;
599 while (nTrap--)
601 top = FIXED_TO_FLOAT (pTrap->top.y);
602 bottom = FIXED_TO_FLOAT (pTrap->bot.y);
604 *data++ = FIXED_TO_FLOAT (pTrap->top.l);
605 *data++ = top;
606 *data++ = FIXED_TO_FLOAT (pTrap->top.r);
607 *data++ = top;
608 *data++ = FIXED_TO_FLOAT (pTrap->bot.r);
609 *data++ = bottom;
610 *data++ = FIXED_TO_FLOAT (pTrap->bot.l);
611 *data++ = bottom;
613 pTrap++;
615 } break;
618 UNMAP_GEOMETRY (pGeometry, offset, size);
621 /* XXX: scratch geometry size never shrinks, it just gets larger when
622 required. this is not acceptable. */
623 xglGeometryPtr
624 xglGetScratchGeometryWithSize (ScreenPtr pScreen,
625 int size)
627 xglGeometryPtr pGeometry;
629 XGL_SCREEN_PRIV (pScreen);
631 pGeometry = &pScreenPriv->scratchGeometry;
633 if (pGeometry->broken || pGeometry->size < size)
635 GEOMETRY_UNINIT (pGeometry);
636 GEOMETRY_INIT (pScreen, pGeometry, pGeometry->type,
637 pScreenPriv->geometryUsage, size);
639 else
641 if (pGeometry->array)
643 glitz_multi_array_destroy (pGeometry->array);
644 pGeometry->array = NULL;
646 pGeometry->endOffset = 0;
647 pGeometry->xOff = 0;
648 pGeometry->yOff = 0;
649 pGeometry->first = 0;
650 pGeometry->count = 0;
651 pGeometry->width = 2;
654 return pGeometry;
657 xglGeometryPtr
658 xglGetScratchVertexGeometryWithType (ScreenPtr pScreen,
659 int type,
660 int count)
662 xglGeometryPtr pGeometry;
663 int stride;
665 stride = 2 * xglGeometryDataTypes[type].size;
667 pGeometry = xglGetScratchGeometryWithSize (pScreen, count * stride);
669 pGeometry->type = GLITZ_GEOMETRY_TYPE_VERTEX;
670 pGeometry->dataType = type;
672 pGeometry->f.vertex.primitive = GLITZ_PRIMITIVE_QUADS;
673 pGeometry->f.vertex.type = xglGeometryDataTypes[type].type;
674 pGeometry->f.vertex.bytes_per_vertex = stride;
675 pGeometry->f.vertex.attributes = 0;
677 return pGeometry;
680 xglGeometryPtr
681 xglGetScratchVertexGeometry (ScreenPtr pScreen,
682 int count)
684 xglGeometryPtr pGeometry;
685 int type, stride;
687 XGL_SCREEN_PRIV (pScreen);
689 type = pScreenPriv->geometryDataType;
690 stride = 2 * xglGeometryDataTypes[type].size;
692 pGeometry = xglGetScratchGeometryWithSize (pScreen, count * stride);
694 pGeometry->type = GLITZ_GEOMETRY_TYPE_VERTEX;
695 pGeometry->dataType = type;
697 pGeometry->f.vertex.primitive = GLITZ_PRIMITIVE_QUADS;
698 pGeometry->f.vertex.type = xglGeometryDataTypes[type].type;
699 pGeometry->f.vertex.bytes_per_vertex = stride;
700 pGeometry->f.vertex.attributes = 0;
702 return pGeometry;
705 Bool
706 xglSetGeometry (xglGeometryPtr pGeometry,
707 glitz_surface_t *surface)
709 if (pGeometry->broken)
710 return FALSE;
712 glitz_set_geometry (surface, pGeometry->type, &pGeometry->f,
713 pGeometry->buffer);
715 if (pGeometry->array)
716 glitz_set_multi_array (surface, pGeometry->array,
717 pGeometry->xOff, pGeometry->yOff);
718 else
719 glitz_set_array (surface,
720 pGeometry->first, pGeometry->width, pGeometry->count,
721 pGeometry->xOff, pGeometry->yOff);
723 return TRUE;