OpenVG 1.0 State Tracker
authorZack Rusin <zackr@vmware.com>
Fri, 1 May 2009 16:41:38 +0000 (12:41 -0400)
committerZack Rusin <zackr@vmware.com>
Fri, 1 May 2009 16:51:59 +0000 (12:51 -0400)
Import of the OpenVG 1.0 state tracker for Gallium.

86 files changed:
docs/openvg.html [new file with mode: 0644]
include/VG/openvg.h [new file with mode: 0644]
include/VG/vgext.h [new file with mode: 0644]
include/VG/vgplatform.h [new file with mode: 0644]
include/VG/vgu.h [new file with mode: 0644]
progs/openvg/demos/Makefile [new file with mode: 0644]
progs/openvg/demos/gears.c [new file with mode: 0644]
progs/openvg/demos/lion-render.c [new file with mode: 0644]
progs/openvg/demos/lion-render.h [new file with mode: 0644]
progs/openvg/demos/lion.c [new file with mode: 0644]
progs/openvg/demos/sp.c [new file with mode: 0644]
progs/openvg/trivial/Makefile [new file with mode: 0644]
progs/openvg/trivial/arc.c [new file with mode: 0644]
progs/openvg/trivial/cap.c [new file with mode: 0644]
progs/openvg/trivial/clear.c [new file with mode: 0644]
progs/openvg/trivial/coord.c [new file with mode: 0644]
progs/openvg/trivial/dash.c [new file with mode: 0644]
progs/openvg/trivial/eglcommon.c [new file with mode: 0644]
progs/openvg/trivial/eglcommon.h [new file with mode: 0644]
progs/openvg/trivial/ellipse.c [new file with mode: 0644]
progs/openvg/trivial/filter.c [new file with mode: 0644]
progs/openvg/trivial/gradorigin.c [new file with mode: 0644]
progs/openvg/trivial/lineto.c [new file with mode: 0644]
progs/openvg/trivial/lingrad.c [new file with mode: 0644]
progs/openvg/trivial/lookup.c [new file with mode: 0644]
progs/openvg/trivial/mask.c [new file with mode: 0644]
progs/openvg/trivial/mask4.c [new file with mode: 0644]
progs/openvg/trivial/path3.c [new file with mode: 0644]
progs/openvg/trivial/radialgrad.c [new file with mode: 0644]
progs/openvg/trivial/readpixels.c [new file with mode: 0644]
progs/openvg/trivial/roundedrect.c [new file with mode: 0644]
progs/openvg/trivial/star-nonzero.c [new file with mode: 0644]
progs/openvg/trivial/star-oddeven.c [new file with mode: 0644]
progs/openvg/trivial/stroke.c [new file with mode: 0644]
progs/openvg/trivial/stroke2.c [new file with mode: 0644]
progs/openvg/trivial/vguarc.c [new file with mode: 0644]
src/gallium/state_trackers/vega/Makefile [new file with mode: 0644]
src/gallium/state_trackers/vega/api_consts.h [new file with mode: 0644]
src/gallium/state_trackers/vega/api_context.c [new file with mode: 0644]
src/gallium/state_trackers/vega/api_filters.c [new file with mode: 0644]
src/gallium/state_trackers/vega/api_images.c [new file with mode: 0644]
src/gallium/state_trackers/vega/api_masks.c [new file with mode: 0644]
src/gallium/state_trackers/vega/api_misc.c [new file with mode: 0644]
src/gallium/state_trackers/vega/api_paint.c [new file with mode: 0644]
src/gallium/state_trackers/vega/api_params.c [new file with mode: 0644]
src/gallium/state_trackers/vega/api_path.c [new file with mode: 0644]
src/gallium/state_trackers/vega/api_text.c [new file with mode: 0644]
src/gallium/state_trackers/vega/api_transform.c [new file with mode: 0644]
src/gallium/state_trackers/vega/arc.c [new file with mode: 0644]
src/gallium/state_trackers/vega/arc.h [new file with mode: 0644]
src/gallium/state_trackers/vega/asm_fill.h [new file with mode: 0644]
src/gallium/state_trackers/vega/asm_filters.h [new file with mode: 0644]
src/gallium/state_trackers/vega/asm_util.h [new file with mode: 0644]
src/gallium/state_trackers/vega/bezier.c [new file with mode: 0644]
src/gallium/state_trackers/vega/bezier.h [new file with mode: 0644]
src/gallium/state_trackers/vega/image.c [new file with mode: 0644]
src/gallium/state_trackers/vega/image.h [new file with mode: 0644]
src/gallium/state_trackers/vega/mask.c [new file with mode: 0644]
src/gallium/state_trackers/vega/mask.h [new file with mode: 0644]
src/gallium/state_trackers/vega/matrix.h [new file with mode: 0644]
src/gallium/state_trackers/vega/paint.c [new file with mode: 0644]
src/gallium/state_trackers/vega/paint.h [new file with mode: 0644]
src/gallium/state_trackers/vega/path.c [new file with mode: 0644]
src/gallium/state_trackers/vega/path.h [new file with mode: 0644]
src/gallium/state_trackers/vega/path_utils.h [new file with mode: 0644]
src/gallium/state_trackers/vega/polygon.c [new file with mode: 0644]
src/gallium/state_trackers/vega/polygon.h [new file with mode: 0644]
src/gallium/state_trackers/vega/renderer.c [new file with mode: 0644]
src/gallium/state_trackers/vega/renderer.h [new file with mode: 0644]
src/gallium/state_trackers/vega/shader.c [new file with mode: 0644]
src/gallium/state_trackers/vega/shader.h [new file with mode: 0644]
src/gallium/state_trackers/vega/shaders_cache.c [new file with mode: 0644]
src/gallium/state_trackers/vega/shaders_cache.h [new file with mode: 0644]
src/gallium/state_trackers/vega/st_inlines.h [new file with mode: 0644]
src/gallium/state_trackers/vega/stroker.c [new file with mode: 0644]
src/gallium/state_trackers/vega/stroker.h [new file with mode: 0644]
src/gallium/state_trackers/vega/util_array.h [new file with mode: 0644]
src/gallium/state_trackers/vega/vg_context.c [new file with mode: 0644]
src/gallium/state_trackers/vega/vg_context.h [new file with mode: 0644]
src/gallium/state_trackers/vega/vg_state.c [new file with mode: 0644]
src/gallium/state_trackers/vega/vg_state.h [new file with mode: 0644]
src/gallium/state_trackers/vega/vg_tracker.c [new file with mode: 0644]
src/gallium/state_trackers/vega/vg_tracker.h [new file with mode: 0644]
src/gallium/state_trackers/vega/vg_translate.c [new file with mode: 0644]
src/gallium/state_trackers/vega/vg_translate.h [new file with mode: 0644]
src/gallium/state_trackers/vega/vgu.c [new file with mode: 0644]

diff --git a/docs/openvg.html b/docs/openvg.html
new file mode 100644 (file)
index 0000000..a8153b9
--- /dev/null
@@ -0,0 +1,48 @@
+<HTML>
+
+<TITLE>Mesa Release Notes</TITLE>
+
+<head><link rel="stylesheet" type="text/css" href="mesa.css"></head>
+
+<BODY>
+
+<body bgcolor="#eeeeee">
+
+<H1>OpenVG State Tracker</H1>
+
+<p>
+The current version of the OpenVG state tracker implements OpenVG 1.0.
+</p>
+<p>
+More informations about OpenVG can be found at <a href="http://www.khronos.org/openvg/">http://www.khronos.org/openvg/</a> .
+</p>
+<p>
+The OpenVG state tracker depends on the Gallium architecture and a working EGL implementation.
+</p>
+
+
+<h2>Building the library</h2>
+<ol>
+<li>Build Mesa3D with Gallium3D. Any build that builds Gallium3D libraries and EGL will suffice</li>
+<li>cd src/gallium/state_trackers/vega; make</li>
+<li>The last step will build libOpenVG library. You can add the libdir to LD_LIBRARY_PATH or install libOpenVG</li>
+</ol>
+
+<h3>Sample build</h3>
+A sample build looks as follows:
+<pre>
+make linux-x86-64-debug
+cd src/gallium/state_trackers/vega
+make
+cd ../../../..
+export LD_LIBRARY_PATH=$PWD/lib64
+export EGL_DRIVER="egl_softpipe"
+</pre>
+
+<h2>Notes</h2>
+<ul>
+<li>EGL_DRIVER environmental variable: forces usage of a specific EGL driver. Unless you force egl_softpipe the implementation will look for a DRI hardware accelerate driver and unless you have a Gallium driver that supports it, you'll see crashes</li>
+</ul>
+
+</body>
+</html>
diff --git a/include/VG/openvg.h b/include/VG/openvg.h
new file mode 100644 (file)
index 0000000..60167e4
--- /dev/null
@@ -0,0 +1,686 @@
+/* $Revision: 6822 $ on $Date:: 2008-10-30 05:14:19 -0400 #$ */
+
+/*------------------------------------------------------------------------
+ *
+ * OpenVG 1.0.1 Reference Implementation
+ * -------------------------------------
+ *
+ * Copyright (c) 2008 The Khronos Group Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and /or associated documentation files
+ * (the "Materials "), to deal in the Materials without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Materials,
+ * and to permit persons to whom the Materials are 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 Materials. 
+ *
+ * THE MATERIALS ARE 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 MATERIALS OR
+ * THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//**
+ * \file
+ * \brief      OpenVG 1.0.1 API.
+ *//*-------------------------------------------------------------------*/
+
+#ifndef _OPENVG_H
+#define _OPENVG_H
+
+#include <VG/vgplatform.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define OPENVG_VERSION_1_0             1
+#define OPENVG_VERSION_1_0_1   1
+
+#ifndef VG_MAXSHORT
+#define VG_MAXSHORT 0x7FFF
+#endif
+
+#ifndef VG_MAXINT
+#define VG_MAXINT 0x7FFFFFFF
+#endif
+
+#ifndef VG_MAX_ENUM
+#define VG_MAX_ENUM 0x7FFFFFFF
+#endif
+
+typedef long VGHandle;
+
+typedef VGHandle VGPath;
+typedef VGHandle VGImage;
+typedef VGHandle VGPaint;
+
+#define VG_INVALID_HANDLE ((VGHandle)0)
+
+typedef enum {
+  VG_FALSE               = 0,
+  VG_TRUE                = 1,
+
+  VG_BOOLEAN_FORCE_SIZE  = VG_MAX_ENUM
+} VGboolean;
+
+typedef enum {
+  VG_NO_ERROR                                 = 0,
+  VG_BAD_HANDLE_ERROR                         = 0x1000,
+  VG_ILLEGAL_ARGUMENT_ERROR                   = 0x1001,
+  VG_OUT_OF_MEMORY_ERROR                      = 0x1002,
+  VG_PATH_CAPABILITY_ERROR                    = 0x1003,
+  VG_UNSUPPORTED_IMAGE_FORMAT_ERROR           = 0x1004,
+  VG_UNSUPPORTED_PATH_FORMAT_ERROR            = 0x1005,
+  VG_IMAGE_IN_USE_ERROR                       = 0x1006,
+  VG_NO_CONTEXT_ERROR                         = 0x1007,
+
+  VG_ERROR_CODE_FORCE_SIZE                    = VG_MAX_ENUM
+} VGErrorCode;
+
+typedef enum {
+  /* Mode settings */
+  VG_MATRIX_MODE                              = 0x1100,
+  VG_FILL_RULE                                = 0x1101,
+  VG_IMAGE_QUALITY                            = 0x1102,
+  VG_RENDERING_QUALITY                        = 0x1103,
+  VG_BLEND_MODE                               = 0x1104,
+  VG_IMAGE_MODE                               = 0x1105,
+
+  /* Scissoring rectangles */
+  VG_SCISSOR_RECTS                            = 0x1106,
+
+  /* Stroke parameters */
+  VG_STROKE_LINE_WIDTH                        = 0x1110,
+  VG_STROKE_CAP_STYLE                         = 0x1111,
+  VG_STROKE_JOIN_STYLE                        = 0x1112,
+  VG_STROKE_MITER_LIMIT                       = 0x1113,
+  VG_STROKE_DASH_PATTERN                      = 0x1114,
+  VG_STROKE_DASH_PHASE                        = 0x1115,
+  VG_STROKE_DASH_PHASE_RESET                  = 0x1116,
+
+  /* Edge fill color for VG_TILE_FILL tiling mode */
+  VG_TILE_FILL_COLOR                          = 0x1120,
+
+  /* Color for vgClear */
+  VG_CLEAR_COLOR                              = 0x1121,
+
+  /* Enable/disable alpha masking and scissoring */
+  VG_MASKING                                  = 0x1130,
+  VG_SCISSORING                               = 0x1131,
+
+  /* Pixel layout information */
+  VG_PIXEL_LAYOUT                             = 0x1140,
+  VG_SCREEN_LAYOUT                            = 0x1141,
+
+  /* Source format selection for image filters */
+  VG_FILTER_FORMAT_LINEAR                     = 0x1150,
+  VG_FILTER_FORMAT_PREMULTIPLIED              = 0x1151,
+
+  /* Destination write enable mask for image filters */
+  VG_FILTER_CHANNEL_MASK                      = 0x1152,
+
+  /* Implementation limits (read-only) */
+  VG_MAX_SCISSOR_RECTS                        = 0x1160,
+  VG_MAX_DASH_COUNT                           = 0x1161,
+  VG_MAX_KERNEL_SIZE                          = 0x1162,
+  VG_MAX_SEPARABLE_KERNEL_SIZE                = 0x1163,
+  VG_MAX_COLOR_RAMP_STOPS                     = 0x1164,
+  VG_MAX_IMAGE_WIDTH                          = 0x1165,
+  VG_MAX_IMAGE_HEIGHT                         = 0x1166,
+  VG_MAX_IMAGE_PIXELS                         = 0x1167,
+  VG_MAX_IMAGE_BYTES                          = 0x1168,
+  VG_MAX_FLOAT                                = 0x1169,
+  VG_MAX_GAUSSIAN_STD_DEVIATION               = 0x116A,
+
+  VG_PARAM_TYPE_FORCE_SIZE                    = VG_MAX_ENUM
+} VGParamType;
+
+typedef enum {
+  VG_RENDERING_QUALITY_NONANTIALIASED         = 0x1200,
+  VG_RENDERING_QUALITY_FASTER                 = 0x1201,
+  VG_RENDERING_QUALITY_BETTER                 = 0x1202, /* Default */
+
+  VG_RENDERING_QUALITY_FORCE_SIZE             = VG_MAX_ENUM
+} VGRenderingQuality;
+
+typedef enum {
+  VG_PIXEL_LAYOUT_UNKNOWN                     = 0x1300,
+  VG_PIXEL_LAYOUT_RGB_VERTICAL                = 0x1301,
+  VG_PIXEL_LAYOUT_BGR_VERTICAL                = 0x1302,
+  VG_PIXEL_LAYOUT_RGB_HORIZONTAL              = 0x1303,
+  VG_PIXEL_LAYOUT_BGR_HORIZONTAL              = 0x1304,
+
+  VG_PIXEL_LAYOUT_FORCE_SIZE                  = VG_MAX_ENUM
+} VGPixelLayout;
+
+typedef enum {
+  VG_MATRIX_PATH_USER_TO_SURFACE              = 0x1400,
+  VG_MATRIX_IMAGE_USER_TO_SURFACE             = 0x1401,
+  VG_MATRIX_FILL_PAINT_TO_USER                = 0x1402,
+  VG_MATRIX_STROKE_PAINT_TO_USER              = 0x1403,
+
+  VG_MATRIX_MODE_FORCE_SIZE                   = VG_MAX_ENUM
+} VGMatrixMode;
+
+typedef enum {
+  VG_CLEAR_MASK                               = 0x1500,
+  VG_FILL_MASK                                = 0x1501,
+  VG_SET_MASK                                 = 0x1502,
+  VG_UNION_MASK                               = 0x1503,
+  VG_INTERSECT_MASK                           = 0x1504,
+  VG_SUBTRACT_MASK                            = 0x1505,
+
+  VG_MASK_OPERATION_FORCE_SIZE                = VG_MAX_ENUM
+} VGMaskOperation;
+
+#define VG_PATH_FORMAT_STANDARD 0
+
+typedef enum {
+  VG_PATH_DATATYPE_S_8                        =  0,
+  VG_PATH_DATATYPE_S_16                       =  1,
+  VG_PATH_DATATYPE_S_32                       =  2,
+  VG_PATH_DATATYPE_F                          =  3,
+
+  VG_PATH_DATATYPE_FORCE_SIZE                 = VG_MAX_ENUM
+} VGPathDatatype;
+
+typedef enum {
+  VG_ABSOLUTE                                 = 0,
+  VG_RELATIVE                                 = 1,
+
+  VG_PATH_ABS_REL_FORCE_SIZE                  = VG_MAX_ENUM
+} VGPathAbsRel;
+
+typedef enum {
+  VG_CLOSE_PATH                               = ( 0 << 1),
+  VG_MOVE_TO                                  = ( 1 << 1),
+  VG_LINE_TO                                  = ( 2 << 1),
+  VG_HLINE_TO                                 = ( 3 << 1),
+  VG_VLINE_TO                                 = ( 4 << 1),
+  VG_QUAD_TO                                  = ( 5 << 1),
+  VG_CUBIC_TO                                 = ( 6 << 1),
+  VG_SQUAD_TO                                 = ( 7 << 1),
+  VG_SCUBIC_TO                                = ( 8 << 1),
+  VG_SCCWARC_TO                               = ( 9 << 1),
+  VG_SCWARC_TO                                = (10 << 1),
+  VG_LCCWARC_TO                               = (11 << 1),
+  VG_LCWARC_TO                                = (12 << 1),
+
+  VG_PATH_SEGMENT_FORCE_SIZE                  = VG_MAX_ENUM
+} VGPathSegment;
+
+typedef enum {
+  VG_MOVE_TO_ABS                              = VG_MOVE_TO    | VG_ABSOLUTE,
+  VG_MOVE_TO_REL                              = VG_MOVE_TO    | VG_RELATIVE,
+  VG_LINE_TO_ABS                              = VG_LINE_TO    | VG_ABSOLUTE,
+  VG_LINE_TO_REL                              = VG_LINE_TO    | VG_RELATIVE,
+  VG_HLINE_TO_ABS                             = VG_HLINE_TO   | VG_ABSOLUTE,
+  VG_HLINE_TO_REL                             = VG_HLINE_TO   | VG_RELATIVE,
+  VG_VLINE_TO_ABS                             = VG_VLINE_TO   | VG_ABSOLUTE,
+  VG_VLINE_TO_REL                             = VG_VLINE_TO   | VG_RELATIVE,
+  VG_QUAD_TO_ABS                              = VG_QUAD_TO    | VG_ABSOLUTE,
+  VG_QUAD_TO_REL                              = VG_QUAD_TO    | VG_RELATIVE,
+  VG_CUBIC_TO_ABS                             = VG_CUBIC_TO   | VG_ABSOLUTE,
+  VG_CUBIC_TO_REL                             = VG_CUBIC_TO   | VG_RELATIVE,
+  VG_SQUAD_TO_ABS                             = VG_SQUAD_TO   | VG_ABSOLUTE,
+  VG_SQUAD_TO_REL                             = VG_SQUAD_TO   | VG_RELATIVE,
+  VG_SCUBIC_TO_ABS                            = VG_SCUBIC_TO  | VG_ABSOLUTE,
+  VG_SCUBIC_TO_REL                            = VG_SCUBIC_TO  | VG_RELATIVE,
+  VG_SCCWARC_TO_ABS                           = VG_SCCWARC_TO | VG_ABSOLUTE,
+  VG_SCCWARC_TO_REL                           = VG_SCCWARC_TO | VG_RELATIVE,
+  VG_SCWARC_TO_ABS                            = VG_SCWARC_TO  | VG_ABSOLUTE,
+  VG_SCWARC_TO_REL                            = VG_SCWARC_TO  | VG_RELATIVE,
+  VG_LCCWARC_TO_ABS                           = VG_LCCWARC_TO | VG_ABSOLUTE,
+  VG_LCCWARC_TO_REL                           = VG_LCCWARC_TO | VG_RELATIVE,
+  VG_LCWARC_TO_ABS                            = VG_LCWARC_TO  | VG_ABSOLUTE,
+  VG_LCWARC_TO_REL                            = VG_LCWARC_TO  | VG_RELATIVE,
+
+  VG_PATH_COMMAND_FORCE_SIZE                  = VG_MAX_ENUM
+} VGPathCommand;
+
+typedef enum {
+  VG_PATH_CAPABILITY_APPEND_FROM              = (1 <<  0),
+  VG_PATH_CAPABILITY_APPEND_TO                = (1 <<  1),
+  VG_PATH_CAPABILITY_MODIFY                   = (1 <<  2),
+  VG_PATH_CAPABILITY_TRANSFORM_FROM           = (1 <<  3),
+  VG_PATH_CAPABILITY_TRANSFORM_TO             = (1 <<  4),
+  VG_PATH_CAPABILITY_INTERPOLATE_FROM         = (1 <<  5),
+  VG_PATH_CAPABILITY_INTERPOLATE_TO           = (1 <<  6),
+  VG_PATH_CAPABILITY_PATH_LENGTH              = (1 <<  7),
+  VG_PATH_CAPABILITY_POINT_ALONG_PATH         = (1 <<  8),
+  VG_PATH_CAPABILITY_TANGENT_ALONG_PATH       = (1 <<  9),
+  VG_PATH_CAPABILITY_PATH_BOUNDS              = (1 << 10),
+  VG_PATH_CAPABILITY_PATH_TRANSFORMED_BOUNDS  = (1 << 11),
+  VG_PATH_CAPABILITY_ALL                      = (1 << 12) - 1,
+
+  VG_PATH_CAPABILITIES_FORCE_SIZE             = VG_MAX_ENUM
+} VGPathCapabilities;
+
+typedef enum {
+  VG_PATH_FORMAT                              = 0x1600,
+  VG_PATH_DATATYPE                            = 0x1601,
+  VG_PATH_SCALE                               = 0x1602,
+  VG_PATH_BIAS                                = 0x1603,
+  VG_PATH_NUM_SEGMENTS                        = 0x1604,
+  VG_PATH_NUM_COORDS                          = 0x1605,
+
+  VG_PATH_PARAM_TYPE_FORCE_SIZE               = VG_MAX_ENUM
+} VGPathParamType;
+
+typedef enum {
+  VG_CAP_BUTT                                 = 0x1700,
+  VG_CAP_ROUND                                = 0x1701,
+  VG_CAP_SQUARE                               = 0x1702,
+
+  VG_CAP_STYLE_FORCE_SIZE                     = VG_MAX_ENUM
+} VGCapStyle;
+
+typedef enum {
+  VG_JOIN_MITER                               = 0x1800,
+  VG_JOIN_ROUND                               = 0x1801,
+  VG_JOIN_BEVEL                               = 0x1802,
+
+  VG_JOIN_STYLE_FORCE_SIZE                    = VG_MAX_ENUM
+} VGJoinStyle;
+
+typedef enum {
+  VG_EVEN_ODD                                 = 0x1900,
+  VG_NON_ZERO                                 = 0x1901,
+
+  VG_FILL_RULE_FORCE_SIZE                     = VG_MAX_ENUM
+} VGFillRule;
+
+typedef enum {
+  VG_STROKE_PATH                              = (1 << 0),
+  VG_FILL_PATH                                = (1 << 1),
+
+  VG_PAINT_MODE_FORCE_SIZE                    = VG_MAX_ENUM
+} VGPaintMode;
+
+typedef enum {
+  /* Color paint parameters */
+  VG_PAINT_TYPE                               = 0x1A00,
+  VG_PAINT_COLOR                              = 0x1A01,
+  VG_PAINT_COLOR_RAMP_SPREAD_MODE             = 0x1A02,
+  VG_PAINT_COLOR_RAMP_PREMULTIPLIED           = 0x1A07,
+  VG_PAINT_COLOR_RAMP_STOPS                   = 0x1A03,
+
+  /* Linear gradient paint parameters */
+  VG_PAINT_LINEAR_GRADIENT                    = 0x1A04,
+
+  /* Radial gradient paint parameters */
+  VG_PAINT_RADIAL_GRADIENT                    = 0x1A05,
+
+  /* Pattern paint parameters */
+  VG_PAINT_PATTERN_TILING_MODE                = 0x1A06,
+
+  VG_PAINT_PARAM_TYPE_FORCE_SIZE              = VG_MAX_ENUM
+} VGPaintParamType;
+
+typedef enum {
+  VG_PAINT_TYPE_COLOR                         = 0x1B00,
+  VG_PAINT_TYPE_LINEAR_GRADIENT               = 0x1B01,
+  VG_PAINT_TYPE_RADIAL_GRADIENT               = 0x1B02,
+  VG_PAINT_TYPE_PATTERN                       = 0x1B03,
+
+  VG_PAINT_TYPE_FORCE_SIZE                    = VG_MAX_ENUM
+} VGPaintType;
+
+typedef enum {
+  VG_COLOR_RAMP_SPREAD_PAD                    = 0x1C00,
+  VG_COLOR_RAMP_SPREAD_REPEAT                 = 0x1C01,
+  VG_COLOR_RAMP_SPREAD_REFLECT                = 0x1C02,
+
+  VG_COLOR_RAMP_SPREAD_MODE_FORCE_SIZE        = VG_MAX_ENUM
+} VGColorRampSpreadMode;
+
+typedef enum {
+  VG_TILE_FILL                                = 0x1D00,
+  VG_TILE_PAD                                 = 0x1D01,
+  VG_TILE_REPEAT                              = 0x1D02,
+  VG_TILE_REFLECT                             = 0x1D03,
+
+  VG_TILING_MODE_FORCE_SIZE                   = VG_MAX_ENUM
+} VGTilingMode;
+
+typedef enum {
+  /* RGB{A,X} channel ordering */
+  VG_sRGBX_8888                               =  0,
+  VG_sRGBA_8888                               =  1,
+  VG_sRGBA_8888_PRE                           =  2,
+  VG_sRGB_565                                 =  3,
+  VG_sRGBA_5551                               =  4,
+  VG_sRGBA_4444                               =  5,
+  VG_sL_8                                     =  6,
+  VG_lRGBX_8888                               =  7,
+  VG_lRGBA_8888                               =  8,
+  VG_lRGBA_8888_PRE                           =  9,
+  VG_lL_8                                     = 10,
+  VG_A_8                                      = 11,
+  VG_BW_1                                     = 12,
+
+  /* {A,X}RGB channel ordering */
+  VG_sXRGB_8888                               =  0 | (1 << 6),
+  VG_sARGB_8888                               =  1 | (1 << 6),
+  VG_sARGB_8888_PRE                           =  2 | (1 << 6),
+  VG_sARGB_1555                               =  4 | (1 << 6),
+  VG_sARGB_4444                               =  5 | (1 << 6),
+  VG_lXRGB_8888                               =  7 | (1 << 6),
+  VG_lARGB_8888                               =  8 | (1 << 6),
+  VG_lARGB_8888_PRE                           =  9 | (1 << 6),
+
+  /* BGR{A,X} channel ordering */
+  VG_sBGRX_8888                               =  0 | (1 << 7),
+  VG_sBGRA_8888                               =  1 | (1 << 7),
+  VG_sBGRA_8888_PRE                           =  2 | (1 << 7),
+  VG_sBGR_565                                 =  3 | (1 << 7),
+  VG_sBGRA_5551                               =  4 | (1 << 7),
+  VG_sBGRA_4444                               =  5 | (1 << 7),
+  VG_lBGRX_8888                               =  7 | (1 << 7),
+  VG_lBGRA_8888                               =  8 | (1 << 7),
+  VG_lBGRA_8888_PRE                           =  9 | (1 << 7),
+
+  /* {A,X}BGR channel ordering */
+  VG_sXBGR_8888                               =  0 | (1 << 6) | (1 << 7),
+  VG_sABGR_8888                               =  1 | (1 << 6) | (1 << 7),
+  VG_sABGR_8888_PRE                           =  2 | (1 << 6) | (1 << 7),
+  VG_sABGR_1555                               =  4 | (1 << 6) | (1 << 7),
+  VG_sABGR_4444                               =  5 | (1 << 6) | (1 << 7),
+  VG_lXBGR_8888                               =  7 | (1 << 6) | (1 << 7),
+  VG_lABGR_8888                               =  8 | (1 << 6) | (1 << 7),
+  VG_lABGR_8888_PRE                           =  9 | (1 << 6) | (1 << 7),
+
+  VG_IMAGE_FORMAT_FORCE_SIZE                  = VG_MAX_ENUM
+} VGImageFormat;
+
+typedef enum {
+  VG_IMAGE_QUALITY_NONANTIALIASED             = (1 << 0),
+  VG_IMAGE_QUALITY_FASTER                     = (1 << 1),
+  VG_IMAGE_QUALITY_BETTER                     = (1 << 2),
+
+  VG_IMAGE_QUALITY_FORCE_SIZE                 = VG_MAX_ENUM
+} VGImageQuality;
+
+typedef enum {
+  VG_IMAGE_FORMAT                             = 0x1E00,
+  VG_IMAGE_WIDTH                              = 0x1E01,
+  VG_IMAGE_HEIGHT                             = 0x1E02,
+
+  VG_IMAGE_PARAM_TYPE_FORCE_SIZE              = VG_MAX_ENUM
+} VGImageParamType;
+
+typedef enum {
+  VG_DRAW_IMAGE_NORMAL                        = 0x1F00,
+  VG_DRAW_IMAGE_MULTIPLY                      = 0x1F01,
+  VG_DRAW_IMAGE_STENCIL                       = 0x1F02,
+
+  VG_IMAGE_MODE_FORCE_SIZE                    = VG_MAX_ENUM
+} VGImageMode;
+
+typedef enum {
+  VG_RED                                      = (1 << 3),
+  VG_GREEN                                    = (1 << 2),
+  VG_BLUE                                     = (1 << 1),
+  VG_ALPHA                                    = (1 << 0),
+
+  VG_IMAGE_CHANNEL_FORCE_SIZE                 = VG_MAX_ENUM
+} VGImageChannel;
+
+typedef enum {
+  VG_BLEND_SRC                                = 0x2000,
+  VG_BLEND_SRC_OVER                           = 0x2001,
+  VG_BLEND_DST_OVER                           = 0x2002,
+  VG_BLEND_SRC_IN                             = 0x2003,
+  VG_BLEND_DST_IN                             = 0x2004,
+  VG_BLEND_MULTIPLY                           = 0x2005,
+  VG_BLEND_SCREEN                             = 0x2006,
+  VG_BLEND_DARKEN                             = 0x2007,
+  VG_BLEND_LIGHTEN                            = 0x2008,
+  VG_BLEND_ADDITIVE                           = 0x2009,
+
+  VG_BLEND_MODE_FORCE_SIZE                    = VG_MAX_ENUM
+} VGBlendMode;
+
+typedef enum {
+  VG_IMAGE_FORMAT_QUERY                       = 0x2100,
+  VG_PATH_DATATYPE_QUERY                      = 0x2101,
+
+  VG_HARDWARE_QUERY_TYPE_FORCE_SIZE           = VG_MAX_ENUM
+} VGHardwareQueryType;
+
+typedef enum {
+  VG_HARDWARE_ACCELERATED                     = 0x2200,
+  VG_HARDWARE_UNACCELERATED                   = 0x2201,
+
+  VG_HARDWARE_QUERY_RESULT_FORCE_SIZE         = VG_MAX_ENUM
+} VGHardwareQueryResult;
+
+typedef enum {
+  VG_VENDOR                                   = 0x2300,
+  VG_RENDERER                                 = 0x2301,
+  VG_VERSION                                  = 0x2302,
+  VG_EXTENSIONS                               = 0x2303,
+
+  VG_STRING_ID_FORCE_SIZE                     = VG_MAX_ENUM
+} VGStringID;
+
+/* Function Prototypes */
+
+#ifndef VG_API_CALL
+#      error VG_API_CALL must be defined
+#endif
+
+#ifndef VG_API_ENTRY
+#   error VG_API_ENTRY must be defined 
+#endif
+
+#ifndef VG_API_EXIT
+#   error VG_API_EXIT must be defined 
+#endif
+
+VG_API_CALL VGErrorCode VG_API_ENTRY vgGetError(void) VG_API_EXIT;
+
+VG_API_CALL void VG_API_ENTRY vgFlush(void) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgFinish(void) VG_API_EXIT;
+
+/* Getters and Setters */
+VG_API_CALL void VG_API_ENTRY vgSetf (VGParamType type, VGfloat value) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgSeti (VGParamType type, VGint value) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgSetfv(VGParamType type, VGint count,
+                         const VGfloat * values) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgSetiv(VGParamType type, VGint count,
+                         const VGint * values) VG_API_EXIT;
+
+VG_API_CALL VGfloat VG_API_ENTRY vgGetf(VGParamType type) VG_API_EXIT;
+VG_API_CALL VGint VG_API_ENTRY vgGeti(VGParamType type) VG_API_EXIT;
+VG_API_CALL VGint VG_API_ENTRY vgGetVectorSize(VGParamType type) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgGetfv(VGParamType type, VGint count, VGfloat * values) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgGetiv(VGParamType type, VGint count, VGint * values) VG_API_EXIT;
+
+VG_API_CALL void VG_API_ENTRY vgSetParameterf(VGHandle object,
+                                 VGint paramType,
+                                 VGfloat value) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgSetParameteri(VGHandle object,
+                                 VGint paramType,
+                                 VGint value) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgSetParameterfv(VGHandle object,
+                                  VGint paramType,
+                                  VGint count, const VGfloat * values) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgSetParameteriv(VGHandle object,
+                                  VGint paramType,
+                                  VGint count, const VGint * values) VG_API_EXIT;
+
+VG_API_CALL VGfloat VG_API_ENTRY vgGetParameterf(VGHandle object,
+                                    VGint paramType) VG_API_EXIT;
+VG_API_CALL VGint VG_API_ENTRY vgGetParameteri(VGHandle object,
+                                  VGint paramType);
+VG_API_CALL VGint VG_API_ENTRY vgGetParameterVectorSize(VGHandle object,
+                                           VGint paramType) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgGetParameterfv(VGHandle object,
+                                  VGint paramType,
+                                  VGint count, VGfloat * values) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgGetParameteriv(VGHandle object,
+                                  VGint paramType,
+                                  VGint count, VGint * values) VG_API_EXIT;
+
+/* Matrix Manipulation */
+VG_API_CALL void VG_API_ENTRY vgLoadIdentity(void) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgLoadMatrix(const VGfloat * m) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgGetMatrix(VGfloat * m) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgMultMatrix(const VGfloat * m) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgTranslate(VGfloat tx, VGfloat ty) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgScale(VGfloat sx, VGfloat sy) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgShear(VGfloat shx, VGfloat shy) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgRotate(VGfloat angle) VG_API_EXIT;
+
+/* Masking and Clearing */
+VG_API_CALL void VG_API_ENTRY vgMask(VGImage mask, VGMaskOperation operation,
+                        VGint x, VGint y, VGint width, VGint height) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgClear(VGint x, VGint y, VGint width, VGint height) VG_API_EXIT;
+
+/* Paths */
+VG_API_CALL VGPath VG_API_ENTRY vgCreatePath(VGint pathFormat,
+                                VGPathDatatype datatype,
+                                VGfloat scale, VGfloat bias,
+                                VGint segmentCapacityHint,
+                                VGint coordCapacityHint,
+                                VGbitfield capabilities) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgClearPath(VGPath path, VGbitfield capabilities) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgDestroyPath(VGPath path) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgRemovePathCapabilities(VGPath path,
+                                          VGbitfield capabilities) VG_API_EXIT;
+VG_API_CALL VGbitfield VG_API_ENTRY vgGetPathCapabilities(VGPath path) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgAppendPath(VGPath dstPath, VGPath srcPath) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgAppendPathData(VGPath dstPath,
+                                  VGint numSegments,
+                                  const VGubyte * pathSegments,
+                                  const void * pathData) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgModifyPathCoords(VGPath dstPath, VGint startIndex,
+                                    VGint numSegments,
+                                    const void * pathData) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgTransformPath(VGPath dstPath, VGPath srcPath) VG_API_EXIT;
+VG_API_CALL VGboolean VG_API_ENTRY vgInterpolatePath(VGPath dstPath,
+                                        VGPath startPath,
+                                        VGPath endPath,
+                                        VGfloat amount) VG_API_EXIT;
+VG_API_CALL VGfloat VG_API_ENTRY vgPathLength(VGPath path,
+                                 VGint startSegment, VGint numSegments) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgPointAlongPath(VGPath path,
+                                  VGint startSegment, VGint numSegments,
+                                  VGfloat distance,
+                                  VGfloat * x, VGfloat * y,
+                                  VGfloat * tangentX, VGfloat * tangentY) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgPathBounds(VGPath path,
+                              VGfloat * minX, VGfloat * minY,
+                              VGfloat * width, VGfloat * height) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgPathTransformedBounds(VGPath path,
+                                         VGfloat * minX, VGfloat * minY,
+                                         VGfloat * width, VGfloat * height) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgDrawPath(VGPath path, VGbitfield paintModes) VG_API_EXIT;
+
+/* Paint */
+VG_API_CALL VGPaint VG_API_ENTRY vgCreatePaint(void) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgDestroyPaint(VGPaint paint) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgSetPaint(VGPaint paint, VGbitfield paintModes) VG_API_EXIT;
+VG_API_CALL VGPaint VG_API_ENTRY vgGetPaint(VGPaintMode paintMode) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgSetColor(VGPaint paint, VGuint rgba) VG_API_EXIT;
+VG_API_CALL VGuint VG_API_ENTRY vgGetColor(VGPaint paint) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgPaintPattern(VGPaint paint, VGImage pattern) VG_API_EXIT;
+
+/* Images */
+VG_API_CALL VGImage VG_API_ENTRY vgCreateImage(VGImageFormat format,
+                                  VGint width, VGint height,
+                                  VGbitfield allowedQuality) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgDestroyImage(VGImage image) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgClearImage(VGImage image,
+                              VGint x, VGint y, VGint width, VGint height) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgImageSubData(VGImage image,
+                                const void * data, VGint dataStride,
+                                VGImageFormat dataFormat,
+                                VGint x, VGint y, VGint width, VGint height) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgGetImageSubData(VGImage image,
+                                   void * data, VGint dataStride,
+                                   VGImageFormat dataFormat,
+                                   VGint x, VGint y,
+                                   VGint width, VGint height) VG_API_EXIT;
+VG_API_CALL VGImage VG_API_ENTRY vgChildImage(VGImage parent,
+                                 VGint x, VGint y, VGint width, VGint height) VG_API_EXIT;
+VG_API_CALL VGImage VG_API_ENTRY vgGetParent(VGImage image) VG_API_EXIT; 
+VG_API_CALL void VG_API_ENTRY vgCopyImage(VGImage dst, VGint dx, VGint dy,
+                             VGImage src, VGint sx, VGint sy,
+                             VGint width, VGint height,
+                             VGboolean dither) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgDrawImage(VGImage image) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgSetPixels(VGint dx, VGint dy,
+                             VGImage src, VGint sx, VGint sy,
+                             VGint width, VGint height) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgWritePixels(const void * data, VGint dataStride,
+                               VGImageFormat dataFormat,
+                               VGint dx, VGint dy,
+                               VGint width, VGint height) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgGetPixels(VGImage dst, VGint dx, VGint dy,
+                             VGint sx, VGint sy,
+                             VGint width, VGint height) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgReadPixels(void * data, VGint dataStride,
+                              VGImageFormat dataFormat,
+                              VGint sx, VGint sy,
+                              VGint width, VGint height) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgCopyPixels(VGint dx, VGint dy,
+                              VGint sx, VGint sy,
+                              VGint width, VGint height) VG_API_EXIT;
+
+/* Image Filters */
+VG_API_CALL void VG_API_ENTRY vgColorMatrix(VGImage dst, VGImage src,
+                               const VGfloat * matrix) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgConvolve(VGImage dst, VGImage src,
+                            VGint kernelWidth, VGint kernelHeight,
+                            VGint shiftX, VGint shiftY,
+                            const VGshort * kernel,
+                            VGfloat scale,
+                            VGfloat bias,
+                            VGTilingMode tilingMode) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgSeparableConvolve(VGImage dst, VGImage src,
+                                     VGint kernelWidth,
+                                     VGint kernelHeight,
+                                     VGint shiftX, VGint shiftY,
+                                     const VGshort * kernelX,
+                                     const VGshort * kernelY,
+                                     VGfloat scale,
+                                     VGfloat bias,
+                                     VGTilingMode tilingMode) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgGaussianBlur(VGImage dst, VGImage src,
+                                VGfloat stdDeviationX,
+                                VGfloat stdDeviationY,
+                                VGTilingMode tilingMode) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgLookup(VGImage dst, VGImage src,
+                          const VGubyte * redLUT,
+                          const VGubyte * greenLUT,
+                          const VGubyte * blueLUT,
+                          const VGubyte * alphaLUT,
+                          VGboolean outputLinear,
+                          VGboolean outputPremultiplied) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgLookupSingle(VGImage dst, VGImage src,
+                                const VGuint * lookupTable,
+                                VGImageChannel sourceChannel,
+                                VGboolean outputLinear,
+                                VGboolean outputPremultiplied) VG_API_EXIT;
+
+/* Hardware Queries */
+VG_API_CALL VGHardwareQueryResult VG_API_ENTRY vgHardwareQuery(VGHardwareQueryType key,
+                                                  VGint setting) VG_API_EXIT;
+
+/* Renderer and Extension Information */
+VG_API_CALL const VGubyte * VG_API_ENTRY vgGetString(VGStringID name) VG_API_EXIT;
+
+#ifdef __cplusplus 
+} /* extern "C" */
+#endif
+
+#endif /* _OPENVG_H */
diff --git a/include/VG/vgext.h b/include/VG/vgext.h
new file mode 100644 (file)
index 0000000..97e3e77
--- /dev/null
@@ -0,0 +1,233 @@
+/* $Revision: 6810 $ on $Date:: 2008-10-29 10:31:37 -0400 #$ */\r
+\r
+/*------------------------------------------------------------------------\r
+ * \r
+ * VG extensions Reference Implementation\r
+ * -------------------------------------\r
+ *\r
+ * Copyright (c) 2008 The Khronos Group Inc.\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining a\r
+ * copy of this software and /or associated documentation files\r
+ * (the "Materials "), to deal in the Materials without restriction,\r
+ * including without limitation the rights to use, copy, modify, merge,\r
+ * publish, distribute, sublicense, and/or sell copies of the Materials,\r
+ * and to permit persons to whom the Materials are furnished to do so,\r
+ * subject to the following conditions: \r
+ *\r
+ * The above copyright notice and this permission notice shall be included \r
+ * in all copies or substantial portions of the Materials. \r
+ *\r
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\r
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\r
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR\r
+ * THE USE OR OTHER DEALINGS IN THE MATERIALS.\r
+ *\r
+ *//**\r
+ * \file\r
+ * \brief      VG extensions\r
+ *//*-------------------------------------------------------------------*/\r
+\r
+\r
+\r
+#ifndef _VGEXT_H\r
+#define _VGEXT_H\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#include <VG/openvg.h>\r
+#include <VG/vgu.h>\r
+\r
+#ifndef VG_API_ENTRYP\r
+#   define VG_API_ENTRYP VG_API_ENTRY*\r
+#endif\r
+\r
+#ifndef VGU_API_ENTRYP\r
+#   define VGU_API_ENTRYP VGU_API_ENTRY*\r
+#endif\r
+\r
+/*-------------------------------------------------------------------------------\r
+ * KHR extensions\r
+ *------------------------------------------------------------------------------*/\r
+\r
+typedef enum  {\r
+\r
+#ifndef VG_KHR_iterative_average_blur\r
+  VG_MAX_AVERAGE_BLUR_DIMENSION_KHR        = 0x116B,\r
+  VG_AVERAGE_BLUR_DIMENSION_RESOLUTION_KHR = 0x116C,\r
+  VG_MAX_AVERAGE_BLUR_ITERATIONS_KHR       = 0x116D,\r
+#endif\r
+\r
+  VG_PARAM_TYPE_KHR_FORCE_SIZE             = VG_MAX_ENUM\r
+} VGParamTypeKHR;\r
+\r
+#ifndef VG_KHR_EGL_image\r
+#define VG_KHR_EGL_image 1\r
+/* VGEGLImageKHR is an opaque handle to an EGLImage */\r
+typedef void* VGeglImageKHR; \r
+\r
+#ifdef VG_VGEXT_PROTOTYPES\r
+VG_API_CALL VGImage VG_API_ENTRY vgCreateEGLImageTargetKHR(VGeglImageKHR image);\r
+#endif\r
+typedef VGImage (VG_API_ENTRYP PFNVGCREATEEGLIMAGETARGETKHRPROC) (VGeglImageKHR image);\r
+\r
+#endif\r
+\r
+\r
+#ifndef VG_KHR_iterative_average_blur\r
+#define VG_KHR_iterative_average_blur 1\r
+\r
+#ifdef VG_VGEXT_PROTOTYPES\r
+VG_API_CALL void vgIterativeAverageBlurKHR(VGImage dst,VGImage src,VGfloat dimX,VGfloat dimY,VGuint iterative,VGTilingMode tilingMode);\r
+#endif \r
+typedef void (VG_API_ENTRYP PFNVGITERATIVEAVERAGEBLURKHRPROC) (VGImage dst,VGImage src,VGfloat dimX,VGfloat dimY,VGuint iterative,VGTilingMode tilingMode);\r
+\r
+#endif\r
+\r
+\r
+#ifndef VG_KHR_advanced_blending\r
+#define VG_KHR_advanced_blending 1\r
+\r
+typedef enum {\r
+  VG_BLEND_OVERLAY_KHR        = 0x2010,\r
+  VG_BLEND_HARDLIGHT_KHR      = 0x2011,\r
+  VG_BLEND_SOFTLIGHT_SVG_KHR  = 0x2012,\r
+  VG_BLEND_SOFTLIGHT_KHR      = 0x2013,\r
+  VG_BLEND_COLORDODGE_KHR     = 0x2014,\r
+  VG_BLEND_COLORBURN_KHR      = 0x2015,\r
+  VG_BLEND_DIFFERENCE_KHR     = 0x2016,\r
+  VG_BLEND_SUBTRACT_KHR       = 0x2017,\r
+  VG_BLEND_INVERT_KHR         = 0x2018,\r
+  VG_BLEND_EXCLUSION_KHR      = 0x2019,\r
+  VG_BLEND_LINEARDODGE_KHR    = 0x201a,\r
+  VG_BLEND_LINEARBURN_KHR     = 0x201b,\r
+  VG_BLEND_VIVIDLIGHT_KHR     = 0x201c,\r
+  VG_BLEND_LINEARLIGHT_KHR    = 0x201d,\r
+  VG_BLEND_PINLIGHT_KHR       = 0x201e,\r
+  VG_BLEND_HARDMIX_KHR        = 0x201f,\r
+  VG_BLEND_CLEAR_KHR          = 0x2020,\r
+  VG_BLEND_DST_KHR            = 0x2021,\r
+  VG_BLEND_SRC_OUT_KHR        = 0x2022,\r
+  VG_BLEND_DST_OUT_KHR        = 0x2023,\r
+  VG_BLEND_SRC_ATOP_KHR       = 0x2024,\r
+  VG_BLEND_DST_ATOP_KHR       = 0x2025,\r
+  VG_BLEND_XOR_KHR            = 0x2026,\r
+\r
+  VG_BLEND_MODE_KHR_FORCE_SIZE= VG_MAX_ENUM\r
+} VGBlendModeKHR;\r
+#endif\r
+\r
+#ifndef VG_KHR_parametric_filter\r
+#define VG_KHR_parametric_filter 1 \r
+\r
+typedef enum {\r
+  VG_PF_OBJECT_VISIBLE_FLAG_KHR = (1 << 0),\r
+  VG_PF_KNOCKOUT_FLAG_KHR       = (1 << 1),\r
+  VG_PF_OUTER_FLAG_KHR          = (1 << 2),\r
+  VG_PF_INNER_FLAG_KHR          = (1 << 3),\r
+\r
+  VG_PF_TYPE_KHR_FORCE_SIZE     = VG_MAX_ENUM\r
+} VGPfTypeKHR;\r
+\r
+typedef enum {\r
+  VGU_IMAGE_IN_USE_ERROR           = 0xF010,\r
+\r
+  VGU_ERROR_CODE_KHR_FORCE_SIZE    = VG_MAX_ENUM\r
+} VGUErrorCodeKHR;\r
+\r
+#ifdef VG_VGEXT_PROTOTYPES\r
+VG_API_CALL void VG_API_ENTRY vgParametricFilterKHR(VGImage dst,VGImage src,VGImage blur,VGfloat strength,VGfloat offsetX,VGfloat offsetY,VGbitfield filterFlags,VGPaint highlightPaint,VGPaint shadowPaint);\r
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguDropShadowKHR(VGImage dst,VGImage src,VGfloat dimX,VGfloat dimY,VGuint iterative,VGfloat strength,VGfloat distance,VGfloat angle,VGbitfield filterFlags,VGbitfield allowedQuality,VGuint shadowColorRGBA);\r
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguGlowKHR(VGImage dst,VGImage src,VGfloat dimX,VGfloat dimY,VGuint iterative,VGfloat strength,VGbitfield filterFlags,VGbitfield allowedQuality,VGuint glowColorRGBA) ;\r
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguBevelKHR(VGImage dst,VGImage src,VGfloat dimX,VGfloat dimY,VGuint iterative,VGfloat strength,VGfloat distance,VGfloat angle,VGbitfield filterFlags,VGbitfield allowedQuality,VGuint highlightColorRGBA,VGuint shadowColorRGBA);\r
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguGradientGlowKHR(VGImage dst,VGImage src,VGfloat dimX,VGfloat dimY,VGuint iterative,VGfloat strength,VGfloat distance,VGfloat angle,VGbitfield filterFlags,VGbitfield allowedQuality,VGuint stopsCount,const VGfloat* glowColorRampStops);\r
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguGradientBevelKHR(VGImage dst,VGImage src,VGfloat dimX,VGfloat dimY,VGuint iterative,VGfloat strength,VGfloat distance,VGfloat angle,VGbitfield filterFlags,VGbitfield allowedQuality,VGuint stopsCount,const VGfloat* bevelColorRampStops);\r
+#endif\r
+typedef void (VG_API_ENTRYP PFNVGPARAMETRICFILTERKHRPROC) (VGImage dst,VGImage src,VGImage blur,VGfloat strength,VGfloat offsetX,VGfloat offsetY,VGbitfield filterFlags,VGPaint highlightPaint,VGPaint shadowPaint);\r
+typedef VGUErrorCode (VGU_API_ENTRYP PFNVGUDROPSHADOWKHRPROC) (VGImage dst,VGImage src,VGfloat dimX,VGfloat dimY,VGuint iterative,VGfloat strength,VGfloat distance,VGfloat angle,VGbitfield filterFlags,VGbitfield allowedQuality,VGuint shadowColorRGBA);\r
+typedef VGUErrorCode (VGU_API_ENTRYP PFNVGUGLOWKHRPROC) (VGImage dst,VGImage src,VGfloat dimX,VGfloat dimY,VGuint iterative,VGfloat strength,VGbitfield filterFlags,VGbitfield allowedQuality,VGuint glowColorRGBA);\r
+typedef VGUErrorCode (VGU_API_ENTRYP PFNVGUBEVELKHRPROC) (VGImage dst,VGImage src,VGfloat dimX,VGfloat dimY,VGuint iterative,VGfloat strength,VGfloat distance,VGfloat angle,VGbitfield filterFlags,VGbitfield allowedQuality,VGuint highlightColorRGBA,VGuint shadowColorRGBA);\r
+typedef VGUErrorCode (VGU_API_ENTRYP PFNVGUGRADIENTGLOWKHRPROC) (VGImage dst,VGImage src,VGfloat dimX,VGfloat dimY,VGuint iterative,VGfloat strength,VGfloat distance,VGfloat angle,VGbitfield filterFlags,VGbitfield allowedQuality,VGuint stopsCount,const VGfloat* glowColorRampStops);\r
+typedef VGUErrorCode (VGU_API_ENTRYP PFNVGUGRADIENTBEVELKHRPROC) (VGImage dst,VGImage src,VGfloat dimX,VGfloat dimY,VGuint iterative,VGfloat strength,VGfloat distance,VGfloat angle,VGbitfield filterFlags,VGbitfield allowedQuality,VGuint stopsCount,const VGfloat* bevelColorRampStops);\r
+\r
+#endif\r
+\r
+\r
+/*-------------------------------------------------------------------------------\r
+ * NDS extensions\r
+ *------------------------------------------------------------------------------*/\r
+\r
+#ifndef VG_NDS_paint_generation\r
+#define VG_NDS_paint_generation 1\r
+\r
+typedef enum { \r
+  VG_PAINT_COLOR_RAMP_LINEAR_NDS            = 0x1A10,\r
+  VG_COLOR_MATRIX_NDS                       = 0x1A11,\r
+  VG_PAINT_COLOR_TRANSFORM_LINEAR_NDS       = 0x1A12,\r
+\r
+  VG_PAINT_PARAM_TYPE_NDS_FORCE_SIZE        = VG_MAX_ENUM\r
+} VGPaintParamTypeNds;\r
+\r
+typedef enum {\r
+  VG_DRAW_IMAGE_COLOR_MATRIX_NDS            = 0x1F10,\r
+\r
+  VG_IMAGE_MODE_NDS_FORCE_SIZE              = VG_MAX_ENUM\r
+} VGImageModeNds;\r
+#endif \r
+\r
+\r
+#ifndef VG_NDS_projective_geometry\r
+#define VG_NDS_projective_geometry 1\r
+\r
+typedef enum {\r
+  VG_CLIP_MODE_NDS                          = 0x1180,\r
+  VG_CLIP_LINES_NDS                         = 0x1181,\r
+  VG_MAX_CLIP_LINES_NDS                     = 0x1182,\r
+\r
+  VG_PARAM_TYPE_NDS_FORCE_SIZE        = VG_MAX_ENUM\r
+} VGParamTypeNds;\r
+\r
+typedef enum {\r
+  VG_CLIPMODE_NONE_NDS                      = 0x3000,\r
+  VG_CLIPMODE_CLIP_CLOSED_NDS               = 0x3001,\r
+  VG_CLIPMODE_CLIP_OPEN_NDS                 = 0x3002,\r
+  VG_CLIPMODE_CULL_NDS                      = 0x3003,\r
+\r
+  VG_CLIPMODE_NDS_FORCE_SIZE = VG_MAX_ENUM\r
+} VGClipModeNds;\r
+\r
+typedef enum {\r
+  VG_RQUAD_TO_NDS              = ( 13 << 1 ),\r
+  VG_RCUBIC_TO_NDS             = ( 14 << 1 ),\r
+  \r
+  VG_PATH_SEGMENT_NDS_FORCE_SIZE = VG_MAX_ENUM\r
+} VGPathSegmentNds;\r
+\r
+typedef enum {\r
+  VG_RQUAD_TO_ABS_NDS            = (VG_RQUAD_TO_NDS  | VG_ABSOLUTE),\r
+  VG_RQUAD_TO_REL_NDS            = (VG_RQUAD_TO_NDS  | VG_RELATIVE),\r
+  VG_RCUBIC_TO_ABS_NDS           = (VG_RCUBIC_TO_NDS | VG_ABSOLUTE),\r
+  VG_RCUBIC_TO_REL_NDS           = (VG_RCUBIC_TO_NDS | VG_RELATIVE),\r
+\r
+  VG_PATH_COMMAND_NDS_FORCE_SIZE = VG_MAX_ENUM\r
+} VGPathCommandNds;\r
+\r
+#ifdef VG_VGEXT_PROTOTYPES\r
+VG_API_CALL void VG_API_ENTRY vgProjectiveMatrixNDS(VGboolean enable) ;\r
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguTransformClipLineNDS(const VGfloat Ain,const VGfloat Bin,const VGfloat Cin,const VGfloat* matrix,const VGboolean inverse,VGfloat* Aout,VGfloat* Bout,VGfloat* Cout);\r
+#endif \r
+typedef void (VG_API_ENTRYP PFNVGPROJECTIVEMATRIXNDSPROC) (VGboolean enable) ;\r
+typedef VGUErrorCode (VGU_API_ENTRYP PFNVGUTRANSFORMCLIPLINENDSPROC) (const VGfloat Ain,const VGfloat Bin,const VGfloat Cin,const VGfloat* matrix,const VGboolean inverse,VGfloat* Aout,VGfloat* Bout,VGfloat* Cout);\r
+\r
+#endif\r
+\r
+#ifdef __cplusplus \r
+} /* extern "C" */\r
+#endif\r
+\r
+#endif /* _VGEXT_H */\r
diff --git a/include/VG/vgplatform.h b/include/VG/vgplatform.h
new file mode 100644 (file)
index 0000000..e4f269f
--- /dev/null
@@ -0,0 +1,106 @@
+/* $Revision: 6810 $ on $Date:: 2008-10-29 10:31:37 -0400 #$ */\r
+\r
+/*------------------------------------------------------------------------\r
+ *\r
+ * VG platform specific header Reference Implementation\r
+ * ----------------------------------------------------\r
+ *\r
+ * Copyright (c) 2008 The Khronos Group Inc.\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining a\r
+ * copy of this software and /or associated documentation files\r
+ * (the "Materials "), to deal in the Materials without restriction,\r
+ * including without limitation the rights to use, copy, modify, merge,\r
+ * publish, distribute, sublicense, and/or sell copies of the Materials,\r
+ * and to permit persons to whom the Materials are furnished to do so,\r
+ * subject to the following conditions: \r
+ *\r
+ * The above copyright notice and this permission notice shall be included \r
+ * in all copies or substantial portions of the Materials. \r
+ *\r
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\r
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\r
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR\r
+ * THE USE OR OTHER DEALINGS IN THE MATERIALS.\r
+ *\r
+ *//**\r
+ * \file\r
+ * \brief VG platform specific header\r
+ *//*-------------------------------------------------------------------*/\r
+\r
+#ifndef _VGPLATFORM_H\r
+#define _VGPLATFORM_H\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#ifndef VG_API_CALL \r
+#if defined(OPENVG_STATIC_LIBRARY)\r
+#      define VG_API_CALL\r
+#else\r
+#      if defined(_WIN32) || defined(__VC32__)                         /* Win32 */\r
+#              if defined (OPENVG_DLL_EXPORTS)\r
+#                      define VG_API_CALL __declspec(dllexport)\r
+#              else\r
+#                      define VG_API_CALL __declspec(dllimport)\r
+#              endif\r
+#      else \r
+#              define VG_API_CALL extern\r
+#      endif /* defined(_WIN32) ||... */\r
+#endif /* defined OPENVG_STATIC_LIBRARY */\r
+#endif /* ifndef VG_API_CALL */\r
+\r
+#ifndef VGU_API_CALL \r
+#if defined(OPENVG_STATIC_LIBRARY)\r
+#      define VGU_API_CALL\r
+#else\r
+#      if defined(_WIN32) || defined(__VC32__)                         /* Win32 */\r
+#              if defined (OPENVG_DLL_EXPORTS)\r
+#                      define VGU_API_CALL __declspec(dllexport)\r
+#              else\r
+#                      define VGU_API_CALL __declspec(dllimport)\r
+#              endif\r
+#      else \r
+#              define VGU_API_CALL extern\r
+#      endif /* defined(_WIN32) ||... */\r
+#endif /* defined OPENVG_STATIC_LIBRARY */\r
+#endif /* ifndef VGU_API_CALL */\r
+\r
+\r
+#ifndef VG_API_ENTRY\r
+#define VG_API_ENTRY\r
+#endif\r
+\r
+#ifndef VG_API_EXIT\r
+#define VG_API_EXIT\r
+#endif\r
+\r
+#ifndef VGU_API_ENTRY\r
+#define VGU_API_ENTRY\r
+#endif\r
+\r
+#ifndef VGU_API_EXIT\r
+#define VGU_API_EXIT\r
+#endif\r
+\r
+typedef float          VGfloat;\r
+typedef signed char    VGbyte;\r
+typedef unsigned char  VGubyte;\r
+typedef signed short   VGshort;\r
+typedef signed int     VGint;\r
+typedef unsigned int   VGuint;\r
+typedef unsigned int   VGbitfield;\r
+\r
+#ifndef VG_VGEXT_PROTOTYPES\r
+#define VG_VGEXT_PROTOTYPES\r
+#endif \r
+\r
+#ifdef __cplusplus \r
+} /* extern "C" */\r
+#endif\r
+\r
+#endif /* _VGPLATFORM_H */\r
diff --git a/include/VG/vgu.h b/include/VG/vgu.h
new file mode 100644 (file)
index 0000000..2799684
--- /dev/null
@@ -0,0 +1,130 @@
+/* $Revision: 6810 $ on $Date:: 2008-10-29 10:31:37 -0400 #$ */\r
+\r
+/*------------------------------------------------------------------------\r
+ * \r
+ * VGU 1.0.1 Reference Implementation\r
+ * -------------------------------------\r
+ *\r
+ * Copyright (c) 2008 The Khronos Group Inc.\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining a\r
+ * copy of this software and /or associated documentation files\r
+ * (the "Materials "), to deal in the Materials without restriction,\r
+ * including without limitation the rights to use, copy, modify, merge,\r
+ * publish, distribute, sublicense, and/or sell copies of the Materials,\r
+ * and to permit persons to whom the Materials are furnished to do so,\r
+ * subject to the following conditions: \r
+ *\r
+ * The above copyright notice and this permission notice shall be included \r
+ * in all copies or substantial portions of the Materials. \r
+ *\r
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\r
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\r
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR\r
+ * THE USE OR OTHER DEALINGS IN THE MATERIALS.\r
+ *\r
+ *//**\r
+ * \file\r
+ * \brief      VGU 1.0.1 API.\r
+ *//*-------------------------------------------------------------------*/\r
+\r
+#ifndef _VGU_H\r
+#define _VGU_H\r
+\r
+#ifdef __cplusplus \r
+extern "C" { \r
+#endif\r
+\r
+#include <VG/openvg.h>\r
+\r
+#define VGU_VERSION_1_0 1\r
+\r
+#ifndef VGU_API_CALL\r
+#      error VGU_API_CALL must be defined\r
+#endif\r
+\r
+#ifndef VGU_API_ENTRY\r
+#   error VGU_API_ENTRY must be defined \r
+#endif\r
+\r
+#ifndef VGU_API_EXIT\r
+#   error VGU_API_EXIT must be defined \r
+#endif\r
+\r
+\r
+typedef enum {\r
+  VGU_NO_ERROR                                 = 0,\r
+  VGU_BAD_HANDLE_ERROR                         = 0xF000,\r
+  VGU_ILLEGAL_ARGUMENT_ERROR                   = 0xF001,\r
+  VGU_OUT_OF_MEMORY_ERROR                      = 0xF002,\r
+  VGU_PATH_CAPABILITY_ERROR                    = 0xF003,\r
+  VGU_BAD_WARP_ERROR                           = 0xF004,\r
+\r
+  VGU_ERROR_CODE_FORCE_SIZE                    = VG_MAX_ENUM\r
+} VGUErrorCode;\r
+\r
+typedef enum {\r
+  VGU_ARC_OPEN                                 = 0xF100,\r
+  VGU_ARC_CHORD                                = 0xF101,\r
+  VGU_ARC_PIE                                  = 0xF102,\r
+\r
+  VGU_ARC_TYPE_FORCE_SIZE                      = VG_MAX_ENUM\r
+} VGUArcType;\r
+\r
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguLine(VGPath path,\r
+                                  VGfloat x0, VGfloat y0,\r
+                                  VGfloat x1, VGfloat y1) VGU_API_EXIT;\r
+\r
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguPolygon(VGPath path,\r
+                                     const VGfloat * points, VGint count,\r
+                                     VGboolean closed) VGU_API_EXIT;\r
+\r
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguRect(VGPath path,\r
+                                  VGfloat x, VGfloat y,\r
+                                  VGfloat width, VGfloat height) VGU_API_EXIT;\r
+\r
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguRoundRect(VGPath path,\r
+                                       VGfloat x, VGfloat y,\r
+                                       VGfloat width, VGfloat height,\r
+                                       VGfloat arcWidth, VGfloat arcHeight) VGU_API_EXIT;\r
+\r
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguEllipse(VGPath path,\r
+                                     VGfloat cx, VGfloat cy,\r
+                                     VGfloat width, VGfloat height) VGU_API_EXIT;\r
+\r
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguArc(VGPath path,\r
+                                 VGfloat x, VGfloat y,\r
+                                 VGfloat width, VGfloat height,\r
+                                 VGfloat startAngle, VGfloat angleExtent,\r
+                                 VGUArcType arcType) VGU_API_EXIT;\r
+\r
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguComputeWarpQuadToSquare(VGfloat sx0, VGfloat sy0,\r
+                                                     VGfloat sx1, VGfloat sy1,\r
+                                                     VGfloat sx2, VGfloat sy2,\r
+                                                     VGfloat sx3, VGfloat sy3,\r
+                                                     VGfloat * matrix) VGU_API_EXIT;\r
+\r
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguComputeWarpSquareToQuad(VGfloat dx0, VGfloat dy0,\r
+                                                     VGfloat dx1, VGfloat dy1,\r
+                                                     VGfloat dx2, VGfloat dy2,\r
+                                                     VGfloat dx3, VGfloat dy3,\r
+                                                     VGfloat * matrix) VGU_API_EXIT;\r
+\r
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguComputeWarpQuadToQuad(VGfloat dx0, VGfloat dy0,\r
+                                                   VGfloat dx1, VGfloat dy1,\r
+                                                   VGfloat dx2, VGfloat dy2,\r
+                                                   VGfloat dx3, VGfloat dy3,\r
+                                                   VGfloat sx0, VGfloat sy0,\r
+                                                   VGfloat sx1, VGfloat sy1,\r
+                                                   VGfloat sx2, VGfloat sy2,\r
+                                                   VGfloat sx3, VGfloat sy3,\r
+                                                   VGfloat * matrix) VGU_API_EXIT;\r
+\r
+#ifdef __cplusplus \r
+} /* extern "C" */\r
+#endif\r
+\r
+#endif /* #ifndef _VGU_H */\r
diff --git a/progs/openvg/demos/Makefile b/progs/openvg/demos/Makefile
new file mode 100644 (file)
index 0000000..7ecb987
--- /dev/null
@@ -0,0 +1,40 @@
+# progs/vg/Makefile
+
+TOP = ../../..
+include $(TOP)/configs/current
+
+VG_LIBS=-lm -pthread -lEGL -lOpenVG
+INCLUDE_DIRS = -I$(TOP)/include
+
+PROGRAMS = \
+       gears \
+        lion
+
+.c.o:
+       $(CC) -c $(INCLUDE_DIRS) $(CFLAGS) $< -o $@
+
+
+
+default: $(PROGRAMS)
+
+
+gears: gears.o
+       $(CC) $(CFLAGS) gears.o -L$(TOP)/$(LIB_DIR) $(VG_LIBS)  -o $@
+
+gears.o: gears.c $(HEADERS)
+       $(CC) -c $(CFLAGS) -I$(TOP)/include gears.c
+
+
+lion: lion.o lion-render.o
+       $(CC) $(CFLAGS) lion.o lion-render.o -L$(TOP)/$(LIB_DIR) $(VG_LIBS) -o $@
+
+lion.o: lion.c lion-render.h $(HEADERS)
+       $(CC) -c $(CFLAGS) -I$(TOP)/include lion.c
+lion-render.o: lion-render.c lion-render.h $(HEADERS)
+       $(CC) -c $(CFLAGS) -I$(TOP)/include lion-render.c
+
+
+clean:
+       rm -f *.o *~
+       rm -f *.so
+       rm -f $(PROGRAMS)
diff --git a/progs/openvg/demos/gears.c b/progs/openvg/demos/gears.c
new file mode 100644 (file)
index 0000000..7dcb395
--- /dev/null
@@ -0,0 +1,394 @@
+#include <assert.h>
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+#include <VG/openvg.h>
+#include <GLES/egl.h>
+
+static VGint width, height;
+static VGPath gear1;
+static VGPath gear2;
+static VGPath gear3;
+
+static VGPaint fill;
+const VGfloat color[4] = {0.5, 0.5, 0.5, 1.0};
+
+static VGfloat gear1_angle = 35;
+static VGfloat gear2_angle = 24;
+static VGfloat gear3_angle = 33.5;
+
+static  void moveTo(VGPath path, VGfloat x, VGfloat y)
+{
+   static VGubyte moveTo = VG_MOVE_TO | VG_ABSOLUTE;
+   VGfloat pathData[2];
+   pathData[0] = x; pathData[1] = y;
+   vgAppendPathData(path, 1, &moveTo, pathData);
+}
+
+static  void lineTo(VGPath path, VGfloat x, VGfloat y)
+{
+   static VGubyte lineTo = VG_LINE_TO | VG_ABSOLUTE;
+   VGfloat pathData[2];
+   pathData[0] = x; pathData[1] = y;
+   vgAppendPathData(path, 1, &lineTo, pathData);
+}
+
+static  void closeSubpath(VGPath path)
+{
+   static VGubyte close = VG_CLOSE_PATH | VG_ABSOLUTE;
+   VGfloat pathData[2];
+   vgAppendPathData(path, 1, &close, pathData);
+}
+
+static  void cubicTo(VGPath path, VGfloat x1, VGfloat y1, VGfloat x2, VGfloat y2,
+                     VGfloat midx, VGfloat midy)
+{
+   static VGubyte cubic = VG_CUBIC_TO | VG_ABSOLUTE;
+   VGfloat pathData[6];
+   pathData[0] = x1;
+   pathData[1] = y1;
+   pathData[2] = x2;
+   pathData[3] = y2;
+   pathData[4] = midx;
+   pathData[5] = midy;
+   vgAppendPathData(path, 1, &cubic, pathData);
+}
+
+static VGPath gearsPath(double inner_radius, double outer_radius,
+                        int teeth, double tooth_depth)
+{
+   VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f,
+                              0, 0, (unsigned int)VG_PATH_CAPABILITY_ALL);
+
+   int i;
+   double r0, r1, r2;
+   double angle, da;
+
+   r0 = inner_radius;
+   r1 = outer_radius - tooth_depth / 2.0;
+   r2 = outer_radius + tooth_depth / 2.0;
+
+   da = 2.0 * M_PI / (VGfloat) teeth / 4.0;
+
+   angle = 0.0;
+   moveTo(path, r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da));
+
+   for (i = 1; i <= teeth; i++) {
+      angle = i * 2.0 * M_PI / (VGfloat)teeth;
+
+      lineTo(path, r1 * cos(angle), r1 * sin(angle));
+      lineTo(path, r2 * cos(angle + da), r2 * sin(angle + da));
+      lineTo(path, r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da));
+
+      if (i < teeth)
+         lineTo(path, r1 * cos(angle + 3 * da),
+                r1 * sin(angle + 3 * da));
+   }
+
+   closeSubpath(path);
+
+   moveTo(path, r0 * cos(angle + 3 * da), r0 * sin(angle + 3 * da));
+
+   for (i = 1; i <= teeth; i++) {
+      angle = i * 2.0 * M_PI / (VGfloat) teeth;
+
+      lineTo(path, r0 * cos(angle), r0 * sin(angle));
+   }
+
+   closeSubpath(path);
+   return path;
+}
+
+static void
+draw(void)
+{
+   vgClear(0, 0, width, height);
+
+   vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+
+   vgLoadIdentity();
+   vgLoadIdentity();
+   vgTranslate(170, 330);
+   vgRotate(gear1_angle);
+   vgDrawPath(gear1, VG_FILL_PATH);
+
+   vgLoadIdentity();
+   vgTranslate(369, 330);
+   vgRotate(gear2_angle);
+   vgDrawPath(gear2, VG_FILL_PATH);
+
+   vgLoadIdentity();
+   vgTranslate(170, 116);
+   vgRotate(gear3_angle);
+   vgDrawPath(gear3, VG_FILL_PATH);
+
+   gear1_angle += 1;
+   gear2_angle -= (20.0 / 12.0);
+   gear3_angle -= (20.0 / 14.0);
+}
+
+
+/* new window size or exposure */
+static void
+reshape(int w, int h)
+{
+   width  = w;
+   height = h;
+}
+
+
+static void
+init(void)
+{
+   float clear_color[4] = {1.0, 1.0, 1.0, 1.0};
+   vgSetfv(VG_CLEAR_COLOR, 4, clear_color);
+
+   gear1 = gearsPath(30.0, 120.0, 20, 20.0);
+   gear2 = gearsPath(15.0, 75.0, 12, 20.0);
+   gear3 = gearsPath(20.0, 90.0, 14, 20.0);
+
+   fill = vgCreatePaint();
+   vgSetParameterfv(fill, VG_PAINT_COLOR, 4, color);
+   vgSetPaint(fill, VG_FILL_PATH);
+}
+
+
+/*
+ * Create an RGB, double-buffered X window.
+ * Return the window and context handles.
+ */
+static void
+make_x_window(Display *x_dpy, EGLDisplay egl_dpy,
+              const char *name,
+              int x, int y, int width, int height,
+              Window *winRet,
+              EGLContext *ctxRet,
+              EGLSurface *surfRet)
+{
+   static const EGLint attribs[] = {
+      EGL_RED_SIZE, 1,
+      EGL_GREEN_SIZE, 1,
+      EGL_BLUE_SIZE, 1,
+      EGL_NONE
+   };
+
+   int scrnum;
+   XSetWindowAttributes attr;
+   unsigned long mask;
+   Window root;
+   Window win;
+   XVisualInfo *visInfo, visTemplate;
+   int num_visuals;
+   EGLContext ctx;
+   EGLConfig config;
+   EGLint num_configs;
+   EGLint vid;
+
+   scrnum = DefaultScreen( x_dpy );
+   root = RootWindow( x_dpy, scrnum );
+
+   if (!eglChooseConfig( egl_dpy, attribs, &config, 1, &num_configs)) {
+      printf("Error: couldn't get an EGL visual config\n");
+      exit(1);
+   }
+
+   assert(config);
+   assert(num_configs > 0);
+
+   if (!eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) {
+      printf("Error: eglGetConfigAttrib() failed\n");
+      exit(1);
+   }
+
+   /* The X window visual must match the EGL config */
+   visTemplate.visualid = vid;
+   visInfo = XGetVisualInfo(x_dpy, VisualIDMask, &visTemplate, &num_visuals);
+   if (!visInfo) {
+      printf("Error: couldn't get X visual\n");
+      exit(1);
+   }
+
+   /* window attributes */
+   attr.background_pixel = 0;
+   attr.border_pixel = 0;
+   attr.colormap = XCreateColormap( x_dpy, root, visInfo->visual, AllocNone);
+   attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
+   mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+   win = XCreateWindow( x_dpy, root, 0, 0, width, height,
+                       0, visInfo->depth, InputOutput,
+                       visInfo->visual, mask, &attr );
+
+   /* set hints and properties */
+   {
+      XSizeHints sizehints;
+      sizehints.x = x;
+      sizehints.y = y;
+      sizehints.width  = width;
+      sizehints.height = height;
+      sizehints.flags = USSize | USPosition;
+      XSetNormalHints(x_dpy, win, &sizehints);
+      XSetStandardProperties(x_dpy, win, name, name,
+                              None, (char **)NULL, 0, &sizehints);
+   }
+
+   eglBindAPI(EGL_OPENVG_API);
+
+   ctx = eglCreateContext(egl_dpy, config, EGL_NO_CONTEXT, NULL );
+   if (!ctx) {
+      printf("Error: eglCreateContext failed\n");
+      exit(1);
+   }
+
+   *surfRet = eglCreateWindowSurface(egl_dpy, config, win, NULL);
+
+   if (!*surfRet) {
+      printf("Error: eglCreateWindowSurface failed\n");
+      exit(1);
+   }
+
+   XFree(visInfo);
+
+   *winRet = win;
+   *ctxRet = ctx;
+}
+
+
+static void
+event_loop(Display *dpy, Window win,
+           EGLDisplay egl_dpy, EGLSurface egl_surf)
+{
+   while (1) {
+      XEvent event;
+
+      while (XPending(dpy) > 0) {
+         XNextEvent(dpy, &event);
+
+         switch (event.type) {
+         case Expose:
+            break;
+         case ConfigureNotify:
+            reshape(event.xconfigure.width, event.xconfigure.height);
+            break;
+         case KeyPress:
+         {
+            char buffer[10];
+            int r, code;
+            code = XLookupKeysym(&event.xkey, 0);
+            r = XLookupString(&event.xkey, buffer, sizeof(buffer),
+                              NULL, NULL);
+            if (buffer[0] == 27) {
+               /* escape */
+               return;
+            }
+         }
+         break;
+         default:
+            ; /*no-op*/
+         }
+      }
+
+      draw();
+      eglSwapBuffers(egl_dpy, egl_surf);
+   }
+}
+
+
+static void
+usage(void)
+{
+   printf("Usage:\n");
+   printf("  -display <displayname>  set the display to run on\n");
+   printf("  -info                   display OpenGL renderer info\n");
+}
+
+int
+main(int argc, char *argv[])
+{
+   const int winWidth = 500, winHeight = 500;
+   Display *x_dpy;
+   Window win;
+   EGLSurface egl_surf;
+   EGLContext egl_ctx;
+   EGLDisplay egl_dpy;
+   char *dpyName = NULL;
+   GLboolean printInfo = GL_FALSE;
+   EGLint egl_major, egl_minor;
+   int i;
+   const char *s;
+
+   for (i = 1; i < argc; i++) {
+      if (strcmp(argv[i], "-display") == 0) {
+         dpyName = argv[i+1];
+         i++;
+      }
+      else if (strcmp(argv[i], "-info") == 0) {
+         printInfo = GL_TRUE;
+      }
+      else {
+         usage();
+         return -1;
+      }
+   }
+
+   x_dpy = XOpenDisplay(dpyName);
+   if (!x_dpy) {
+      printf("Error: couldn't open display %s\n",
+            dpyName ? dpyName : getenv("DISPLAY"));
+      return -1;
+   }
+
+   egl_dpy = eglGetDisplay(x_dpy);
+   if (!egl_dpy) {
+      printf("Error: eglGetDisplay() failed\n");
+      return -1;
+   }
+
+   if (!eglInitialize(egl_dpy, &egl_major, &egl_minor)) {
+      printf("Error: eglInitialize() failed\n");
+      return -1;
+   }
+
+   s = eglQueryString(egl_dpy, EGL_VERSION);
+   printf("EGL_VERSION = %s\n", s);
+
+   make_x_window(x_dpy, egl_dpy,
+                 "xegl_tri", 0, 0, winWidth, winHeight,
+                 &win, &egl_ctx, &egl_surf);
+
+   XMapWindow(x_dpy, win);
+   if (!eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx)) {
+      printf("Error: eglMakeCurrent() failed\n");
+      return -1;
+   }
+
+   if (printInfo) {
+      printf("VG_RENDERER   = %s\n", (char *) vgGetString(VG_RENDERER));
+      printf("VG_VERSION    = %s\n", (char *) vgGetString(VG_VERSION));
+      printf("VG_VENDOR     = %s\n", (char *) vgGetString(VG_VENDOR));
+   }
+
+   init();
+
+   /* Set initial projection/viewing transformation.
+    * We can't be sure we'll get a ConfigureNotify event when the window
+    * first appears.
+    */
+   reshape(winWidth, winHeight);
+
+   event_loop(x_dpy, win, egl_dpy, egl_surf);
+
+   eglDestroyContext(egl_dpy, egl_ctx);
+   eglDestroySurface(egl_dpy, egl_surf);
+   eglTerminate(egl_dpy);
+
+
+   XDestroyWindow(x_dpy, win);
+   XCloseDisplay(x_dpy);
+
+   return 0;
+}
diff --git a/progs/openvg/demos/lion-render.c b/progs/openvg/demos/lion-render.c
new file mode 100644 (file)
index 0000000..f3f151f
--- /dev/null
@@ -0,0 +1,1573 @@
+#include "lion-render.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#define ELEMENTS(x) (sizeof(x)/sizeof((x)[0]))
+
+static void init(struct lion *l, int i, VGint hexColor, const VGfloat *coords, int elems)
+{
+   static VGubyte cmds[128];
+   VGfloat color[4];
+   VGint j;
+
+   color[0] = ((hexColor >> 16) & 0xff) / 255.f;
+   color[1] = ((hexColor >> 8) & 0xff) / 255.f;
+   color[2] = ((hexColor >> 0) & 0xff) / 255.f;
+   color[3] = 1.0;
+
+   l->paths[i] = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f,
+                              0, 0, (unsigned int)VG_PATH_CAPABILITY_ALL);
+   l->fills[i] = vgCreatePaint();
+   vgSetParameterfv(l->fills[i], VG_PAINT_COLOR, 4, color);
+
+   cmds[0] = VG_MOVE_TO_ABS;
+   for (j = 1; j < elems; ++j) {
+      cmds[j] = VG_LINE_TO_ABS;
+   }
+
+   vgAppendPathData(l->paths[i], elems, cmds, coords);
+}
+
+static void poly0(struct lion *l)
+{
+   VGfloat color = 0xf2cc99;
+   static const VGfloat coords[] = {69,18, 82,8, 99,3, 118,5, 135,12, 149,21, 156,13, 165,9, 177,13, 183,28,
+                                    180,50, 164,91, 155,107, 154,114, 151,121, 141,127, 139,136, 155,206, 157,251, 126,342,
+                                    133,357, 128,376, 83,376, 75,368, 67,350, 61,350, 53,369, 4,369, 2,361, 5,354,
+                                    12,342, 16,321, 4,257, 4,244, 7,218, 9,179, 26,127, 43,93, 32,77, 30,70,
+                                    24,67, 16,49, 17,35, 18,23, 30,12, 40,7, 53,7, 62,12
+   };
+
+   init(l, 0, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly1(struct lion *l)
+{
+   VGfloat color = 0xe5b27f;
+   static const VGfloat coords[] = {142,79, 136,74, 138,82, 133,78, 133,84, 127,78, 128,85,
+                                    124,80, 125,87, 119,82, 119,90, 125,99, 125,96, 128,100, 128,94,
+                                    131,98, 132,93, 135,97, 136,93, 138,97, 139,94, 141,98, 143,94,
+                                    144,85
+   };
+
+   init(l, 1, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly2(struct lion *l)
+{
+   VGfloat color = 0xeb8080;
+   static const VGfloat coords[] = {127,101, 132,100, 137,99, 144,101, 143,105, 135,110
+   };
+
+   init(l, 2, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly3(struct lion *l)
+{
+   VGfloat color = 0xf2cc99;
+   static const VGfloat coords[] = {178,229, 157,248, 139,296, 126,349, 137,356,
+                                    158,357, 183,342, 212,332, 235,288, 235,261,
+                                    228,252, 212,250, 188,251
+   };
+
+   init(l, 3, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly4(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {56,229, 48,241, 48,250, 57,281, 63,325, 71,338,
+                                    81,315, 76,321, 79,311, 83,301, 75,308, 80,298,
+                                    73,303, 76,296, 71,298, 74,292, 69,293, 74,284,
+                                    78,278, 71,278, 74,274, 68,273, 70,268, 66,267,
+                                    68,261, 60,266, 62,259, 65,253, 57,258, 59,251,
+                                    55,254, 55,248, 60,237, 54,240, 58,234, 54,236
+   };
+
+   init(l, 4, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly5(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {74,363, 79,368, 81,368, 85,362, 89,363, 92,370, 96,373,
+                                    101,372, 108,361, 110,371, 113,373, 116,371, 120,358, 122,363,
+                                    123,371, 126,371, 129,367, 132,357, 135,361, 130,376, 127,377,
+                                    94,378, 84,376, 76,371
+   };
+
+   init(l, 5, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly6(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {212,250, 219,251, 228,258, 236,270, 235,287, 225,304,
+                                    205,332, 177,343, 171,352, 158,357, 166,352, 168,346,
+                                    168,339, 165,333, 155,327, 155,323, 161,320, 165,316,
+                                    169,316, 167,312, 171,313, 168,308, 173,309, 170,306,
+                                    177,306, 175,308, 177,311, 174,311, 176,316, 171,315,
+                                    174,319, 168,320, 168,323, 175,327, 179,332, 183,326,
+                                    184,332, 189,323, 190,328, 194,320, 194,325, 199,316,
+                                    201,320, 204,313, 206,316, 208,310, 211,305, 219,298,
+                                    226,288, 229,279, 228,266, 224,259, 217,253
+   };
+
+   init(l, 6, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly7(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {151,205, 151,238, 149,252, 141,268, 128,282, 121,301,
+                                    130,300, 126,313, 118,324, 116,337, 120,346, 133,352,
+                                    133,340, 137,333, 145,329, 156,327, 153,319, 153,291,
+                                    157,271, 170,259, 178,277, 193,250, 174,216
+   };
+
+   init(l, 7, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly8(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {78,127, 90,142, 95,155, 108,164, 125,167, 139,175,
+                                    150,206, 152,191, 141,140, 121,148, 100,136
+   };
+
+   init(l, 8, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly9(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {21,58, 35,63, 38,68, 32,69, 42,74, 40,79, 47,80, 54,83,
+                                    45,94, 34,81, 32,73, 24,66
+   };
+
+   init(l, 9, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly10(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {71,34, 67,34, 66,27, 59,24, 54,17, 48,17, 39,22,
+                                    30,26, 28,31, 31,39, 38,46, 29,45, 36,54, 41,61,
+                                    41,70, 50,69, 54,71, 55,58, 67,52, 76,43, 76,39,
+                                    68,44
+   };
+
+   init(l, 10, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly11(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {139,74, 141,83, 143,89, 144,104, 148,104, 155,106,
+                                    154,86, 157,77, 155,72, 150,77, 144,77
+   };
+
+   init(l, 11, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly12(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {105,44, 102,53, 108,58, 111,62, 112,55
+   };
+
+   init(l, 12, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly13(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {141,48, 141,54, 144,58, 139,62, 137,66, 136,59, 137,52
+   };
+
+   init(l, 13, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly14(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {98,135, 104,130, 105,134, 108,132, 108,135, 112,134,
+                                    113,137, 116,136, 116,139, 119,139, 124,141, 128,140,
+                                    133,138, 140,133, 139,140, 126,146, 104,144
+   };
+
+   init(l, 14, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly15(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {97,116, 103,119, 103,116, 111,118, 116,117, 122,114,
+                                    127,107, 135,111, 142,107, 141,114, 145,118, 149,121,
+                                    145,125, 140,124, 127,121, 113,125, 100,124
+   };
+
+   init(l, 15, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly16(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {147,33, 152,35, 157,34, 153,31, 160,31, 156,28, 161,28,
+                                    159,24, 163,25, 163,21, 165,22, 170,23, 167,17, 172,21,
+                                    174,18, 175,23, 176,22, 177,28, 177,33, 174,37, 176,39,
+                                    174,44, 171,49, 168,53, 164,57, 159,68, 156,70, 154,60,
+                                    150,51, 146,43, 144,35
+   };
+
+   init(l, 16, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly17(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {85,72, 89,74, 93,75, 100,76, 105,75, 102,79, 94,79, 88,76
+   };
+
+   init(l, 17, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly18(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {86,214, 79,221, 76,232, 82,225, 78,239, 82,234, 78,245,
+                                    81,243, 79,255, 84,250, 84,267, 87,254, 90,271, 90,257,
+                                    95,271, 93,256, 95,249, 92,252, 93,243, 89,253, 89,241,
+                                    86,250, 87,236, 83,245, 87,231, 82,231, 90,219, 84,221
+   };
+
+   init(l, 18, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly19(struct lion *l)
+{
+   VGfloat color = 0xffcc7f;
+   static const VGfloat coords[] = {93,68, 96,72, 100,73, 106,72, 108,66, 105,63, 100,62
+   };
+
+   init(l, 19, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly20(struct lion *l)
+{
+   VGfloat color = 0xffcc7f;
+   static const VGfloat coords[] = {144,64, 142,68, 142,73, 146,74, 150,73, 154,64, 149,62
+   };
+
+   init(l, 20, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly21(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {57,91, 42,111, 52,105, 41,117, 53,112, 46,120, 53,116,
+                                    50,124, 57,119, 55,127, 61,122, 60,130, 67,126, 66,134,
+                                    71,129, 72,136, 77,130, 76,137, 80,133, 82,138, 86,135,
+                                    96,135, 94,129, 86,124, 83,117, 77,123, 79,117, 73,120,
+                                    75,112, 68,116, 71,111, 65,114, 69,107, 63,110, 68,102,
+                                    61,107, 66,98, 61,103, 63,97, 57,99
+   };
+
+   init(l, 21, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly22(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {83,79, 76,79, 67,82, 75,83, 65,88, 76,87, 65,92, 76,91,
+                                    68,96, 77,95, 70,99, 80,98, 72,104, 80,102, 76,108, 85,103,
+                                    92,101, 87,98, 93,96, 86,94, 91,93, 85,91, 93,89, 99,89, 105,93,
+                                    107,85, 102,82, 92,80
+   };
+
+   init(l, 22, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly23(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {109,77, 111,83, 109,89, 113,94, 117,90, 117,81, 114,78
+   };
+
+   init(l, 23, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly24(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {122,128, 127,126, 134,127, 136,129, 134,130, 130,128, 124,129
+   };
+
+   init(l, 24, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly25(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {78,27, 82,32, 80,33, 82,36, 78,37, 82,40, 78,42, 81,46, 76,47,
+                                    78,49, 74,50, 82,52, 87,50, 83,48, 91,46, 86,45, 91,42, 88,40,
+                                    92,37, 86,34, 90,31, 86,29, 89,26
+   };
+
+   init(l, 25, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly26(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {82,17, 92,20, 79,21, 90,25, 81,25, 94,28, 93,26, 101,30,
+                                    101,26, 107,33, 108,28, 111,40, 113,34, 115,45, 117,39,
+                                    119,54, 121,46, 124,58, 126,47, 129,59, 130,49, 134,58,
+                                    133,44, 137,48, 133,37, 137,40, 133,32, 126,20, 135,26,
+                                    132,19, 138,23, 135,17, 142,18, 132,11, 116,6, 94,6, 78,11,
+                                    92,12, 80,14, 90,16
+   };
+
+   init(l, 26, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly27(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {142,234, 132,227, 124,223, 115,220, 110,225, 118,224, 127,229,
+                                    135,236, 122,234, 115,237, 113,242, 121,238, 139,243, 121,245,
+                                    111,254, 95,254, 102,244, 104,235, 110,229, 100,231, 104,224,
+                                    113,216, 122,215, 132,217, 141,224, 145,230, 149,240
+   };
+
+   init(l, 27, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly28(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {115,252, 125,248, 137,249, 143,258, 134,255, 125,254
+   };
+
+   init(l, 28, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly29(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {114,212, 130,213, 140,219, 147,225, 144,214, 137,209, 128,207
+   };
+
+   init(l, 29, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly30(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {102,263, 108,258, 117,257, 131,258, 116,260, 109,265
+   };
+
+   init(l, 30, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly31(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {51,241, 35,224, 40,238, 23,224, 31,242, 19,239, 28,247, 17,246,
+                                    25,250, 37,254, 39,263, 44,271, 47,294, 48,317, 51,328, 60,351,
+                                    60,323, 53,262, 47,246
+   };
+
+   init(l, 31, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly32(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {2,364, 9,367, 14,366, 18,355, 20,364, 26,366, 31,357, 35,364,
+                                    39,364, 42,357, 47,363, 53,360, 59,357, 54,369, 7,373
+   };
+
+   init(l, 32, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly33(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {7,349, 19,345, 25,339, 18,341, 23,333, 28,326, 23,326, 27,320,
+                                    23,316, 25,311, 20,298, 15,277, 12,264, 9,249, 10,223, 3,248,
+                                    5,261, 15,307, 17,326, 11,343
+   };
+
+   init(l, 33, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly34(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {11,226, 15,231, 25,236, 18,227
+   };
+
+   init(l, 34, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly35(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {13,214, 19,217, 32,227, 23,214, 16,208, 15,190, 24,148,
+                                    31,121, 24,137, 14,170, 8,189
+   };
+
+   init(l, 35, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly36(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {202,254, 195,258, 199,260, 193,263, 197,263, 190,268,
+                                    196,268, 191,273, 188,282, 200,272, 194,272, 201,266,
+                                    197,265, 204,262, 200,258, 204,256
+   };
+
+   init(l, 36, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly37(struct lion *l)
+{
+   VGfloat color = 0x845433;
+   static const VGfloat coords[] = {151,213, 165,212, 179,225, 189,246, 187,262, 179,275,
+                                    176,263, 177,247, 171,233, 163,230, 165,251, 157,264,
+                                    146,298, 145,321, 133,326, 143,285, 154,260, 153,240
+   };
+
+   init(l, 37, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly38(struct lion *l)
+{
+   VGfloat color = 0x845433;
+   static const VGfloat coords[] = {91,132, 95,145, 97,154, 104,148, 107,155, 109,150, 111,158,
+                                    115,152, 118,159, 120,153, 125,161, 126,155, 133,164, 132,154,
+                                    137,163, 137,152, 142,163, 147,186, 152,192, 148,167, 141,143,
+                                    124,145, 105,143
+   };
+
+   init(l, 38, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly39(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {31,57, 23,52, 26,51, 20,44, 23,42, 21,36, 22,29, 25,23,
+                                    24,32, 30,43, 26,41, 30,50, 26,48
+   };
+
+   init(l, 39, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly40(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {147,21, 149,28, 155,21, 161,16, 167,14, 175,15, 173,11, 161,9
+   };
+
+   init(l, 40, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly41(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {181,39, 175,51, 169,57, 171,65, 165,68, 165,75, 160,76,
+                                    162,91, 171,71, 180,51
+   };
+
+   init(l, 41, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly42(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {132,346, 139,348, 141,346, 142,341, 147,342, 143,355, 133,350
+   };
+
+   init(l, 42, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly43(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {146,355, 151,352, 155,348, 157,343, 160,349, 151,356, 147,357
+   };
+
+   init(l, 43, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly44(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {99,266, 100,281, 94,305, 86,322, 78,332, 72,346, 73,331, 91,291
+   };
+
+   init(l, 44, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly45(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {20,347, 32,342, 45,340, 54,345, 45,350, 42,353, 38,350,
+                                    31,353, 29,356, 23,350, 19,353, 15,349
+   };
+
+   init(l, 45, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly46(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {78,344, 86,344, 92,349, 88,358, 84,352
+   };
+
+   init(l, 46, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly47(struct lion *l)
+{
+   VGfloat color = 0x9c826b;
+   static const VGfloat coords[] = {93,347, 104,344, 117,345, 124,354, 121,357, 116,351,
+                                    112,351, 108,355, 102,351
+   };
+
+   init(l, 47, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly48(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {105,12, 111,18, 113,24, 113,29, 119,34, 116,23, 112,16
+   };
+
+   init(l, 48, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly49(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {122,27, 125,34, 127,43, 128,34, 125,29
+   };
+
+   init(l, 49, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly50(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {115,13, 122,19, 122,15, 113,10
+   };
+
+   init(l, 50, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly51(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {116,172, 107,182, 98,193, 98,183, 90,199, 89,189, 84,207,
+                                    88,206, 87,215, 95,206, 93,219, 91,230, 98,216, 97,226,
+                                    104,214, 112,209, 104,208, 113,202, 126,200, 139,207, 132,198,
+                                    142,203, 134,192, 142,195, 134,187, 140,185, 130,181, 136,177,
+                                    126,177, 125,171, 116,180
+   };
+
+   init(l, 51, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly52(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {74,220, 67,230, 67,221, 59,235, 63,233, 60,248, 70,232, 65,249,
+                                    71,243, 67,256, 73,250, 69,262, 73,259, 71,267, 76,262, 72,271,
+                                    78,270, 76,275, 82,274, 78,290, 86,279, 86,289, 92,274, 88,275,
+                                    87,264, 82,270, 82,258, 77,257, 78,247, 73,246, 77,233, 72,236
+   };
+
+   init(l, 52, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly53(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {133,230, 147,242, 148,250, 145,254, 138,247, 129,246, 142,245,
+                                    138,241, 128,237, 137,238
+   };
+
+   init(l, 53, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly54(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {133,261, 125,261, 116,263, 111,267, 125,265
+   };
+
+   init(l, 54, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly55(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {121,271, 109,273, 103,279, 99,305, 92,316, 85,327, 83,335,
+                                    89,340, 97,341, 94,336, 101,336, 96,331, 103,330, 97,327, 108,325,
+                                    99,322, 109,321, 100,318, 110,317, 105,314, 110,312, 107,310, 113,308,
+                                    105,306, 114,303, 105,301, 115,298, 107,295, 115,294, 108,293, 117,291,
+                                    109,289, 117,286, 109,286, 118,283, 112,281, 118,279, 114,278,
+                                    119,276, 115,274
+   };
+
+   init(l, 55, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly56(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {79,364, 74,359, 74,353, 76,347, 80,351, 83,356, 82,360
+   };
+
+   init(l, 56, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly57(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {91,363, 93,356, 97,353, 103,355, 105,360, 103,366, 99,371, 94,368
+   };
+
+   init(l, 57, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly58(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {110,355, 114,353, 118,357, 117,363, 113,369, 111,362
+   };
+
+   init(l, 58, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly59(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {126,354, 123,358, 124,367, 126,369, 129,361, 129,357
+   };
+
+   init(l, 59, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly60(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {30,154, 24,166, 20,182, 23,194, 29,208, 37,218, 41,210, 41,223,
+                                    46,214, 46,227, 52,216, 52,227, 61,216, 59,225, 68,213, 73,219,
+                                    70,207, 77,212, 69,200, 77,202, 70,194, 78,197, 68,187, 76,182,
+                                    64,182, 58,175, 58,185, 53,177, 50,186, 46,171, 44,182, 39,167,
+                                    36,172, 36,162, 30,166
+   };
+
+   init(l, 60, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly61(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {44,130, 41,137, 45,136, 43,150, 48,142, 48,157, 53,150,
+                                    52,164, 60,156, 61,169, 64,165, 66,175, 70,167, 74,176,
+                                    77,168, 80,183, 85,172, 90,182, 93,174, 98,181, 99,173,
+                                    104,175, 105,169, 114,168, 102,163, 95,157, 94,166, 90,154,
+                                    87,162, 82,149, 75,159, 72,148, 68,155, 67,143, 62,148, 62,138,
+                                    58,145, 56,133, 52,142, 52,128, 49,134, 47,125
+   };
+
+   init(l, 61, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly62(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {13,216, 19,219, 36,231, 22,223, 16,222, 22,227, 12,224, 13,220, 16,220
+   };
+
+   init(l, 62, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly63(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {10,231, 14,236, 25,239, 27,237, 19,234
+   };
+
+   init(l, 63, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly64(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {9,245, 14,242, 25,245, 13,245
+   };
+
+   init(l, 64, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly65(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {33,255, 26,253, 18,254, 25,256, 18,258, 27,260, 18,263,
+                                    27,265, 19,267, 29,270, 21,272, 29,276, 21,278, 30,281,
+                                    22,283, 31,287, 24,288, 32,292, 23,293, 34,298, 26,299,
+                                    37,303, 32,305, 39,309, 33,309, 39,314, 34,314, 40,318,
+                                    34,317, 40,321, 34,321, 41,326, 33,326, 40,330, 33,332,
+                                    39,333, 33,337, 42,337, 54,341, 49,337, 52,335, 47,330,
+                                    50,330, 45,325, 49,325, 45,321, 48,321, 45,316, 46,306,
+                                    45,286, 43,274, 36,261
+   };
+
+   init(l, 65, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly66(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {7,358, 9,351, 14,351, 17,359, 11,364
+   };
+
+   init(l, 66, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly67(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {44,354, 49,351, 52,355, 49,361
+   };
+
+   init(l, 67, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly68(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {32,357, 37,353, 40,358, 36,361
+   };
+
+   init(l, 68, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly69(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {139,334, 145,330, 154,330, 158,334, 154,341, 152,348,
+                                    145,350, 149,340, 147,336, 141,339, 139,345, 136,342,
+                                    136,339
+   };
+
+   init(l, 69, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly70(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {208,259, 215,259, 212,255, 220,259, 224,263, 225,274, 224,283,
+                                    220,292, 208,300, 206,308, 203,304, 199,315, 197,309, 195,318,
+                                    193,313, 190,322, 190,316, 185,325, 182,318, 180,325, 172,321,
+                                    178,320, 176,313, 186,312, 180,307, 188,307, 184,303, 191,302,
+                                    186,299, 195,294, 187,290, 197,288, 192,286, 201,283, 194,280,
+                                    203,277, 198,275, 207,271, 200,269, 209,265, 204,265, 212,262
+   };
+
+   init(l, 70, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly71(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {106,126, 106,131, 109,132, 111,134, 115,132, 115,135, 119,133, 118,137,
+                                    123,137, 128,137, 133,134, 136,130, 136,127, 132,124, 118,128, 112,128,
+                                    106,126, 106,126, 106,126
+   };
+
+   init(l, 71, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly72(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {107,114, 101,110, 98,102, 105,97, 111,98, 119,102, 121,108, 118,112, 113,115
+   };
+
+   init(l, 72, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly73(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {148,106, 145,110, 146,116, 150,118, 152,111, 151,107
+   };
+
+   init(l, 73, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly74(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {80,55, 70,52, 75,58, 63,57, 72,61, 57,61, 67,66, 57,67, 62,69, 54,71,
+                                    61,73, 54,77, 63,78, 53,85, 60,84, 56,90, 69,84, 63,82, 75,76, 70,75,
+                                    77,72, 72,71, 78,69, 72,66, 81,67, 78,64, 82,63, 80,60, 86,62
+   };
+
+   init(l, 74, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly75(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {87,56, 91,52, 96,50, 102,56, 98,56, 92,60
+   };
+
+   init(l, 75, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly76(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {85,68, 89,73, 98,76, 106,74, 96,73, 91,70
+   };
+
+   init(l, 76, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly77(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {115,57, 114,64, 111,64, 115,75, 122,81, 122,74, 126,79,
+                                    126,74, 131,78, 130,72, 133,77, 131,68, 126,61, 119,57
+   };
+
+   init(l, 77, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly78(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {145,48, 143,53, 147,59, 151,59, 150,55
+   };
+
+   init(l, 78, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly79(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {26,22, 34,15, 43,10, 52,10, 59,16, 47,15, 32,22
+   };
+
+   init(l, 79, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly80(struct lion *l)
+{
+   VGfloat color = 0xffe5b2;
+   static const VGfloat coords[] = {160,19, 152,26, 149,34, 154,33, 152,30, 157,30, 155,26, 158,27,
+                                    157,23, 161,23
+   };
+
+   init(l, 80, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly81(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {98,117, 105,122, 109,122, 105,117, 113,120, 121,120, 130,112, 128,108,
+                                    123,103, 123,99, 128,101, 132,106, 135,109, 142,105, 142,101, 145,101,
+                                    145,91, 148,101, 145,105, 136,112, 135,116, 143,124, 148,120, 150,122,
+                                    142,128, 133,122, 121,125, 112,126, 103,125, 100,129, 96,124
+   };
+
+   init(l, 81, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly82(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {146,118, 152,118, 152,115, 149,115
+   };
+
+   init(l, 82, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly83(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {148,112, 154,111, 154,109, 149,109
+   };
+
+   init(l, 83, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly84(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {106,112, 108,115, 114,116, 118,114
+   };
+
+   init(l, 84, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly85(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {108,108, 111,110, 116,110, 119,108
+   };
+
+   init(l, 85, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly86(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {106,104, 109,105, 117,106, 115,104
+   };
+
+   init(l, 86, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly87(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {50,25, 41,26, 34,33, 39,43, 49,58, 36,51, 47,68, 55,69, 54,59,
+                                    61,57, 74,46, 60,52, 67,42, 57,48, 61,40, 54,45, 60,36, 59,29,
+                                    48,38, 52,30, 47,32
+   };
+
+   init(l, 87, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly88(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {147,34, 152,41, 155,49, 161,53, 157,47, 164,47, 158,43, 168,44,
+                                    159,40, 164,37, 169,37, 164,33, 169,34, 165,28, 170,30, 170,25,
+                                    173,29, 175,27, 176,32, 173,36, 175,39, 172,42, 172,46, 168,49,
+                                    170,55, 162,57, 158,63, 155,58, 153,50, 149,46
+   };
+
+   init(l, 88, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly89(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {155,71, 159,80, 157,93, 157,102, 155,108, 150,101, 149,93,
+                                    154,101, 152,91, 151,83, 155,79
+   };
+
+   init(l, 89, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly90(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {112,78, 115,81, 114,91, 112,87, 113,82
+   };
+
+   init(l, 90, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly91(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {78,28, 64,17, 58,11, 47,9, 36,10, 28,16, 21,26, 18,41,
+                                    20,51, 23,61, 33,65, 28,68, 37,74, 36,81, 43,87, 48,90,
+                                    43,100, 40,98, 39,90, 31,80, 30,72, 22,71, 17,61, 14,46,
+                                    16,28, 23,17, 33,9, 45,6, 54,6, 65,12
+   };
+
+   init(l, 91, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly92(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {67,18, 76,9, 87,5, 101,2, 118,3, 135,8, 149,20, 149,26,
+                                    144,19, 132,12, 121,9, 105,7, 89,8, 76,14, 70,20
+   };
+
+   init(l, 92, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly93(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {56,98, 48,106, 56,103, 47,112, 56,110, 52,115, 57,113, 52,121, 62,115,
+                                    58,123, 65,119, 63,125, 69,121, 68,127, 74,125, 74,129, 79,128, 83,132,
+                                    94,135, 93,129, 85,127, 81,122, 76,126, 75,121, 71,124, 71,117, 66,121,
+                                    66,117, 62,117, 64,112, 60,113, 60,110, 57,111, 61,105, 57,107, 60,101,
+                                    55,102
+   };
+
+   init(l, 93, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly94(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {101,132, 103,138, 106,134, 106,139, 112,136, 111,142, 115,139,
+                                    114,143, 119,142, 125,145, 131,142, 135,138, 140,134, 140,129,
+                                    143,135, 145,149, 150,171, 149,184, 145,165, 141,150, 136,147,
+                                    132,151, 131,149, 126,152, 125,150, 121,152, 117,148, 111,152,
+                                    110,148, 105,149, 104,145, 98,150, 96,138, 94,132, 94,130, 98,132
+   };
+
+   init(l, 94, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly95(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {41,94, 32,110, 23,132, 12,163, 6,190, 7,217, 5,236,
+                                    3,247, 9,230, 12,211, 12,185, 18,160, 26,134, 35,110,
+                                    43,99
+   };
+
+   init(l, 95, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly96(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {32,246, 41,250, 50,257, 52,267, 53,295, 53,323, 59,350,
+                                    54,363, 51,365, 44,366, 42,360, 40,372, 54,372, 59,366,
+                                    62,353, 71,352, 75,335, 73,330, 66,318, 68,302, 64,294,
+                                    67,288, 63,286, 63,279, 59,275, 58,267, 56,262, 50,247,
+                                    42,235, 44,246, 32,236, 35,244
+   };
+
+   init(l, 96, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly97(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {134,324, 146,320, 159,322, 173,327, 179,337, 179,349,
+                                    172,355, 158,357, 170,350, 174,343, 170,333, 163,328, 152,326,
+                                    134,329
+   };
+
+   init(l, 97, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly98(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {173,339, 183,334, 184,338, 191,329, 194,332, 199,323, 202,325,
+                                    206,318, 209,320, 213,309, 221,303, 228,296, 232,289, 234,279,
+                                    233,269, 230,262, 225,256, 219,253, 208,252, 198,252, 210,249,
+                                    223,250, 232,257, 237,265, 238,277, 238,291, 232,305, 221,323,
+                                    218,335, 212,342, 200,349, 178,348
+   };
+
+   init(l, 98, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly99(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {165,296, 158,301, 156,310, 156,323, 162,324, 159,318,
+                                    162,308, 162,304
+   };
+
+   init(l, 99, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly100(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {99,252, 105,244, 107,234, 115,228, 121,228, 131,235,
+                                    122,233, 113,235, 109,246, 121,239, 133,243, 121,243,
+                                    110,251
+   };
+
+   init(l, 100, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly101(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {117,252, 124,247, 134,249, 136,253, 126,252
+   };
+
+   init(l, 101, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly102(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {117,218, 132,224, 144,233, 140,225, 132,219, 117,218,
+                                    117,218, 117,218
+   };
+
+   init(l, 102, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly103(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {122,212, 134,214, 143,221, 141,213, 132,210
+   };
+
+   init(l, 103, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly104(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {69,352, 70,363, 76,373, 86,378, 97,379, 108,379, 120,377,
+                                    128,378, 132,373, 135,361, 133,358, 132,366, 127,375, 121,374,
+                                    121,362, 119,367, 117,374, 110,376, 110,362, 107,357, 106,371,
+                                    104,375, 97,376, 90,375, 90,368, 86,362, 83,364, 86,369, 85,373,
+                                    78,370, 73,362, 71,351
+   };
+
+   init(l, 104, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly105(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {100,360, 96,363, 99,369, 102,364
+   };
+
+   init(l, 105, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly106(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {115,360, 112,363, 114,369, 117,364
+   };
+
+   init(l, 106, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly107(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {127,362, 125,364, 126,369, 128,365
+   };
+
+   init(l, 107, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly108(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {5,255, 7,276, 11,304, 15,320, 13,334, 6,348, 2,353, 0,363,
+                                    5,372, 12,374, 25,372, 38,372, 44,369, 42,367, 36,368, 31,369,
+                                    30,360, 27,368, 20,370, 16,361, 15,368, 10,369, 3,366, 3,359, 6,352,
+                                    11,348, 17,331, 19,316, 12,291, 9,274
+   };
+
+   init(l, 108, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly109(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {10,358, 7,362, 10,366, 11,362
+   };
+
+   init(l, 109, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly110(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {25,357, 22,360, 24,366, 27,360
+   };
+
+   init(l, 110, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly111(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {37,357, 34,361, 36,365, 38,361
+   };
+
+   init(l, 111, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly112(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {49,356, 46,359, 47,364, 50,360
+   };
+
+   init(l, 112, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly113(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {130,101, 132,102, 135,101, 139,102, 143,103,
+                                    142,101, 137,100, 133,100
+   };
+
+   init(l, 113, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly114(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {106,48, 105,52, 108,56, 109,52
+   };
+
+   init(l, 114, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly115(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {139,52, 139,56, 140,60, 142,58, 141,56
+   };
+
+   init(l, 115, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly116(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {25,349, 29,351, 30,355, 33,350, 37,348, 42,351, 45,347,
+                                    49,345, 44,343, 36,345
+   };
+
+   init(l, 116, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly117(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {98,347, 105,351, 107,354, 109,349, 115,349, 120,353, 118,349,
+                                    113,346, 104,346
+   };
+
+   init(l, 117, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly118(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {83,348, 87,352, 87,357, 89,351, 87,348
+   };
+
+   init(l, 118, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly119(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {155,107, 163,107, 170,107, 186,108, 175,109, 155,109
+   };
+
+   init(l, 119, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly120(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {153,114, 162,113, 175,112, 192,114, 173,114, 154,115
+   };
+
+   init(l, 120, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly121(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {152,118, 164,120, 180,123, 197,129, 169,123, 151,120
+   };
+
+   init(l, 121, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly122(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {68,109, 87,106, 107,106, 106,108, 88,108
+   };
+
+   init(l, 122, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly123(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {105,111, 95,112, 79,114, 71,116, 85,115, 102,113
+   };
+
+   init(l, 123, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly124(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {108,101, 98,99, 87,99, 78,99, 93,100, 105,102
+   };
+
+   init(l, 124, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly125(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {85,63, 91,63, 97,60, 104,60, 108,62, 111,69, 112,75,
+                                    110,74, 108,71, 103,73, 106,69, 105,65, 103,64, 103,67,
+                                    102,70, 99,70, 97,66, 94,67, 97,72, 88,67, 84,66
+   };
+
+   init(l, 125, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly126(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {140,74, 141,66, 144,61, 150,61, 156,62, 153,70, 150,73,
+                                    152,65, 150,65, 151,68, 149,71, 146,71, 144,66, 143,70,
+                                    143,74
+   };
+
+   init(l, 126, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly127(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {146,20, 156,11, 163,9, 172,9, 178,14, 182,18, 184,32, 182,42,
+                                    182,52, 177,58, 176,67, 171,76, 165,90, 157,105, 160,92, 164,85,
+                                    168,78, 167,73, 173,66, 172,62, 175,59, 174,55, 177,53, 180,46,
+                                    181,29, 179,21, 173,13, 166,11, 159,13, 153,18, 148,23
+   };
+
+   init(l, 127, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly128(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {150,187, 148,211, 150,233, 153,247, 148,267, 135,283, 125,299,
+                                    136,292, 131,313, 122,328, 122,345, 129,352, 133,359, 133,367,
+                                    137,359, 148,356, 140,350, 131,347, 129,340, 132,332, 140,328,
+                                    137,322, 140,304, 154,265, 157,244, 155,223, 161,220, 175,229,
+                                    186,247, 185,260, 176,275, 178,287, 185,277, 188,261, 196,253,
+                                    189,236, 174,213
+   };
+
+   init(l, 128, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly129(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {147,338, 142,341, 143,345, 141,354, 147,343
+   };
+
+   init(l, 129, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly130(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {157,342, 156,349, 150,356, 157,353, 163,346, 162,342
+   };
+
+   init(l, 130, color, coords, ELEMENTS(coords)/2);
+}
+
+static void poly131(struct lion *l)
+{
+   VGfloat color = 0x000000;
+   static const VGfloat coords[] = {99,265, 96,284, 92,299, 73,339, 73,333, 87,300
+   };
+
+   init(l, 131, color, coords, ELEMENTS(coords)/2);
+}
+
+
+struct lion * lion_create(void)
+{
+   struct lion *l = calloc(1, sizeof(struct lion));
+
+   poly0(l);
+   poly1(l);
+   poly2(l);
+   poly3(l);
+   poly4(l);
+   poly5(l);
+   poly6(l);
+   poly7(l);
+   poly8(l);
+   poly9(l);
+
+   poly10(l);
+   poly11(l);
+   poly12(l);
+   poly13(l);
+   poly14(l);
+   poly15(l);
+   poly16(l);
+   poly17(l);
+   poly18(l);
+   poly19(l);
+
+   poly20(l);
+   poly21(l);
+   poly22(l);
+   poly23(l);
+   poly24(l);
+   poly25(l);
+   poly26(l);
+   poly27(l);
+   poly28(l);
+   poly29(l);
+
+   poly30(l);
+   poly31(l);
+   poly32(l);
+   poly33(l);
+   poly34(l);
+   poly35(l);
+   poly36(l);
+   poly37(l);
+   poly38(l);
+   poly39(l);
+
+   poly40(l);
+   poly41(l);
+   poly42(l);
+   poly43(l);
+   poly44(l);
+   poly45(l);
+   poly46(l);
+   poly47(l);
+   poly48(l);
+   poly49(l);
+
+   poly50(l);
+   poly51(l);
+   poly52(l);
+   poly53(l);
+   poly54(l);
+   poly55(l);
+   poly56(l);
+   poly57(l);
+   poly58(l);
+   poly59(l);
+
+   poly60(l);
+   poly61(l);
+   poly62(l);
+   poly63(l);
+   poly64(l);
+   poly65(l);
+   poly66(l);
+   poly67(l);
+   poly68(l);
+   poly69(l);
+
+   poly70(l);
+   poly71(l);
+   poly72(l);
+   poly73(l);
+   poly74(l);
+   poly75(l);
+   poly76(l);
+   poly77(l);
+   poly78(l);
+   poly79(l);
+
+   poly80(l);
+   poly81(l);
+   poly82(l);
+   poly83(l);
+   poly84(l);
+   poly85(l);
+   poly86(l);
+   poly87(l);
+   poly88(l);
+   poly89(l);
+
+   poly90(l);
+   poly91(l);
+   poly92(l);
+   poly93(l);
+   poly94(l);
+   poly95(l);
+   poly96(l);
+   poly97(l);
+   poly98(l);
+   poly99(l);
+
+   poly100(l);
+   poly101(l);
+   poly102(l);
+   poly103(l);
+   poly104(l);
+   poly105(l);
+   poly106(l);
+   poly107(l);
+   poly108(l);
+   poly109(l);
+
+   poly110(l);
+   poly111(l);
+   poly112(l);
+   poly113(l);
+   poly114(l);
+   poly115(l);
+   poly116(l);
+   poly117(l);
+   poly118(l);
+   poly119(l);
+
+   poly120(l);
+   poly121(l);
+   poly122(l);
+   poly123(l);
+   poly124(l);
+   poly125(l);
+   poly126(l);
+   poly127(l);
+   poly128(l);
+   poly129(l);
+
+   poly130(l);
+   poly131(l);
+
+   return l;
+}
+
+void lion_render(struct lion *l)
+{
+   VGint i;
+
+   for (i = 0; i < LION_SIZE; ++i) {
+      vgSetPaint(l->fills[i], VG_FILL_PATH);
+      vgDrawPath(l->paths[i], VG_FILL_PATH);
+   }
+}
+
+void lion_destroy(struct lion *l)
+{
+   VGint i;
+   for (i = 0; i < LION_SIZE; ++i) {
+      vgDestroyPaint(l->fills[i]);
+      vgDestroyPath(l->paths[i]);
+   }
+   free(l);
+}
diff --git a/progs/openvg/demos/lion-render.h b/progs/openvg/demos/lion-render.h
new file mode 100644 (file)
index 0000000..c4c020b
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef LION_RENDER_H
+#define LION_RENDER_H
+
+#include <VG/openvg.h>
+
+#define LION_SIZE 132
+struct lion {
+   VGPath paths[LION_SIZE];
+   VGPaint fills[LION_SIZE];
+};
+
+struct lion *lion_create(void);
+void lion_render(struct lion *l);
+void lion_destroy(struct lion *l);
+
+#endif
diff --git a/progs/openvg/demos/lion.c b/progs/openvg/demos/lion.c
new file mode 100644 (file)
index 0000000..7224fed
--- /dev/null
@@ -0,0 +1,288 @@
+#include <assert.h>
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+#include <VG/openvg.h>
+#include <GLES/egl.h>
+
+#include "lion-render.h"
+
+static VGint width, height;
+struct lion *lion = 0;
+VGfloat angle = 0;
+
+static void
+draw(void)
+{
+   vgClear(0, 0, width, height);
+
+   vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+   vgLoadIdentity();
+   vgTranslate(width/2, height/2);
+   vgRotate(angle);
+   vgTranslate(-width/2, -height/2);
+
+   lion_render(lion);
+
+   ++angle;
+}
+
+
+/* new window size or exposure */
+static void
+reshape(int w, int h)
+{
+   width  = w;
+   height = h;
+}
+
+
+static void
+init(void)
+{
+   float clear_color[4] = {1.0, 1.0, 1.0, 1.0};
+   vgSetfv(VG_CLEAR_COLOR, 4, clear_color);
+
+   lion = lion_create();
+}
+
+
+/*
+ * Create an RGB, double-buffered X window.
+ * Return the window and context handles.
+ */
+static void
+make_x_window(Display *x_dpy, EGLDisplay egl_dpy,
+              const char *name,
+              int x, int y, int width, int height,
+              Window *winRet,
+              EGLContext *ctxRet,
+              EGLSurface *surfRet)
+{
+   static const EGLint attribs[] = {
+      EGL_RED_SIZE, 1,
+      EGL_GREEN_SIZE, 1,
+      EGL_BLUE_SIZE, 1,
+      EGL_NONE
+   };
+
+   int scrnum;
+   XSetWindowAttributes attr;
+   unsigned long mask;
+   Window root;
+   Window win;
+   XVisualInfo *visInfo, visTemplate;
+   int num_visuals;
+   EGLContext ctx;
+   EGLConfig config;
+   EGLint num_configs;
+   EGLint vid;
+
+   scrnum = DefaultScreen( x_dpy );
+   root = RootWindow( x_dpy, scrnum );
+
+   if (!eglChooseConfig( egl_dpy, attribs, &config, 1, &num_configs)) {
+      printf("Error: couldn't get an EGL visual config\n");
+      exit(1);
+   }
+
+   assert(config);
+   assert(num_configs > 0);
+
+   if (!eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) {
+      printf("Error: eglGetConfigAttrib() failed\n");
+      exit(1);
+   }
+
+   /* The X window visual must match the EGL config */
+   visTemplate.visualid = vid;
+   visInfo = XGetVisualInfo(x_dpy, VisualIDMask, &visTemplate, &num_visuals);
+   if (!visInfo) {
+      printf("Error: couldn't get X visual\n");
+      exit(1);
+   }
+
+   /* window attributes */
+   attr.background_pixel = 0;
+   attr.border_pixel = 0;
+   attr.colormap = XCreateColormap( x_dpy, root, visInfo->visual, AllocNone);
+   attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
+   mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+   win = XCreateWindow( x_dpy, root, 0, 0, width, height,
+                       0, visInfo->depth, InputOutput,
+                       visInfo->visual, mask, &attr );
+
+   /* set hints and properties */
+   {
+      XSizeHints sizehints;
+      sizehints.x = x;
+      sizehints.y = y;
+      sizehints.width  = width;
+      sizehints.height = height;
+      sizehints.flags = USSize | USPosition;
+      XSetNormalHints(x_dpy, win, &sizehints);
+      XSetStandardProperties(x_dpy, win, name, name,
+                              None, (char **)NULL, 0, &sizehints);
+   }
+
+   eglBindAPI(EGL_OPENVG_API);
+
+   ctx = eglCreateContext(egl_dpy, config, EGL_NO_CONTEXT, NULL );
+   if (!ctx) {
+      printf("Error: eglCreateContext failed\n");
+      exit(1);
+   }
+
+   *surfRet = eglCreateWindowSurface(egl_dpy, config, win, NULL);
+
+   if (!*surfRet) {
+      printf("Error: eglCreateWindowSurface failed\n");
+      exit(1);
+   }
+
+   XFree(visInfo);
+
+   *winRet = win;
+   *ctxRet = ctx;
+}
+
+
+static void
+event_loop(Display *dpy, Window win,
+           EGLDisplay egl_dpy, EGLSurface egl_surf)
+{
+   while (1) {
+      XEvent event;
+
+      while (XPending(dpy) > 0) {
+         XNextEvent(dpy, &event);
+
+         switch (event.type) {
+         case Expose:
+            break;
+         case ConfigureNotify:
+            reshape(event.xconfigure.width, event.xconfigure.height);
+            break;
+         case KeyPress:
+         {
+            char buffer[10];
+            int r, code;
+            code = XLookupKeysym(&event.xkey, 0);
+            r = XLookupString(&event.xkey, buffer, sizeof(buffer),
+                              NULL, NULL);
+            if (buffer[0] == 27) {
+               /* escape */
+               return;
+            }
+         }
+         break;
+         default:
+            ; /*no-op*/
+         }
+      }
+
+      draw();
+      eglSwapBuffers(egl_dpy, egl_surf);
+   }
+}
+
+
+static void
+usage(void)
+{
+   printf("Usage:\n");
+   printf("  -display <displayname>  set the display to run on\n");
+   printf("  -info                   display OpenGL renderer info\n");
+}
+
+int
+main(int argc, char *argv[])
+{
+   const int winWidth = 350, winHeight = 450;
+   Display *x_dpy;
+   Window win;
+   EGLSurface egl_surf;
+   EGLContext egl_ctx;
+   EGLDisplay egl_dpy;
+   char *dpyName = NULL;
+   GLboolean printInfo = GL_FALSE;
+   EGLint egl_major, egl_minor;
+   int i;
+   const char *s;
+
+   for (i = 1; i < argc; i++) {
+      if (strcmp(argv[i], "-display") == 0) {
+         dpyName = argv[i+1];
+         i++;
+      }
+      else if (strcmp(argv[i], "-info") == 0) {
+         printInfo = GL_TRUE;
+      }
+      else {
+         usage();
+         return -1;
+      }
+   }
+
+   x_dpy = XOpenDisplay(dpyName);
+   if (!x_dpy) {
+      printf("Error: couldn't open display %s\n",
+            dpyName ? dpyName : getenv("DISPLAY"));
+      return -1;
+   }
+
+   egl_dpy = eglGetDisplay(x_dpy);
+   if (!egl_dpy) {
+      printf("Error: eglGetDisplay() failed\n");
+      return -1;
+   }
+
+   if (!eglInitialize(egl_dpy, &egl_major, &egl_minor)) {
+      printf("Error: eglInitialize() failed\n");
+      return -1;
+   }
+
+   s = eglQueryString(egl_dpy, EGL_VERSION);
+   printf("EGL_VERSION = %s\n", s);
+
+   make_x_window(x_dpy, egl_dpy,
+                 "Lion Example", 0, 0, winWidth, winHeight,
+                 &win, &egl_ctx, &egl_surf);
+
+   XMapWindow(x_dpy, win);
+   if (!eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx)) {
+      printf("Error: eglMakeCurrent() failed\n");
+      return -1;
+   }
+
+   if (printInfo) {
+      printf("VG_RENDERER   = %s\n", (char *) vgGetString(VG_RENDERER));
+      printf("VG_VERSION    = %s\n", (char *) vgGetString(VG_VERSION));
+      printf("VG_VENDOR     = %s\n", (char *) vgGetString(VG_VENDOR));
+   }
+
+   init();
+
+   /* Set initial projection/viewing transformation.
+    * We can't be sure we'll get a ConfigureNotify event when the window
+    * first appears.
+    */
+   reshape(winWidth, winHeight);
+
+   event_loop(x_dpy, win, egl_dpy, egl_surf);
+
+   eglDestroyContext(egl_dpy, egl_ctx);
+   eglDestroySurface(egl_dpy, egl_surf);
+   eglTerminate(egl_dpy);
+
+
+   XDestroyWindow(x_dpy, win);
+   XCloseDisplay(x_dpy);
+
+   return 0;
+}
diff --git a/progs/openvg/demos/sp.c b/progs/openvg/demos/sp.c
new file mode 100644 (file)
index 0000000..d04f252
--- /dev/null
@@ -0,0 +1,103 @@
+#include "eglcommon.h"
+
+#include <VG/openvg.h>
+#include <VG/vgu.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+
+#include <X11/keysym.h>
+
+struct object {
+   VGPath path;
+   VGPaint fill;
+   VGPaint stroke;
+   VGint draw_mode;
+};
+
+struct character {
+   struct object objects[32];
+   VGint num_objects;
+};
+
+struct character cartman;
+
+static void init_character()
+{
+   struct object object;
+   VGint num_objects = 0;
+
+   {
+      const VGint num_segments = 6;
+      const VGubyte segments[] = {VG_MOVE_TO_ABS,
+                                  VG_CUBIC_TO_ABS,
+                                  VG_CUBIC_TO_ABS,
+                                  VG_CUBIC_TO_ABS,
+                                  VG_CUBIC_TO_ABS,
+                                  VG_CLOSE_PATH};
+      const VGfloat coords[] = {181.83267, 102.60408,
+                                181.83267,102.60408 185.53793,114.5749 186.5355,115.00243,
+                                187.53306,115.42996 286.0073,115.00243 286.0073,115.00243,
+                                286.0073,115.00243 292.70526,103.45914 290.85263,101.03648,
+                                289.00001,98.61381 181.54765,102.31906 181.83267,102.60408
+      };
+      VGuint color = 0x7c4e32ff;
+      object.path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,
+                          1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
+      vgAppendPathData(object.path, num_segments, segments, coords);
+
+      object.fill = vgCreatePaint();
+      vgSetColor(object.fill, color);
+      character.objects[objects.num_objects] = object;
+      ++objects.num_objects;
+   }
+   {
+      
+   }
+}
+
+
+static void
+init(void)
+{
+}
+
+/* new window size or exposure */
+static void
+reshape(int w, int h)
+{
+}
+
+int  key_press(unsigned key)
+{
+    switch(key) {
+    case XK_Right:
+
+        break;
+    case XK_Left:
+        break;
+    case XK_Up:
+        break;
+    case XK_Down:
+        break;
+    case 'a':
+        break;
+    case 's':
+        break;
+    default:
+        break;
+    }
+    return VG_FALSE;
+}
+
+static void
+draw(void)
+{
+}
+
+
+int main(int argc, char **argv)
+{
+    set_window_size(400, 400);
+    return run(argc, argv, init, reshape, draw, key_press);
+}
diff --git a/progs/openvg/trivial/Makefile b/progs/openvg/trivial/Makefile
new file mode 100644 (file)
index 0000000..362360e
--- /dev/null
@@ -0,0 +1,127 @@
+# These programs aren't intended to be included with the normal distro.
+# They're not too interesting but they're good for testing.
+
+TOP = ../../../
+include $(TOP)/configs/current
+
+INCLUDES = -I. -I$(TOP)/include
+LIBS=-L$(TOP)/$(LIB_DIR) -lm -lEGL -lOpenVG -lpthread
+CFLAGS += $(INCLUDES)
+
+HEADERS=eglcommon.h
+
+PROGRAMS = \
+        arc \
+        cap \
+        clear \
+        coord \
+        dash \
+        ellipse \
+        filter \
+        gradorigin \
+        lineto \
+        lingrad \
+        lookup \
+        mask4 \
+        mask \
+        path3 \
+        radialgrad \
+        readpixels \
+        roundedrect \
+        star-nonzero \
+        star-oddeven \
+        stroke2 \
+        stroke \
+        vguarc
+
+
+.c.o:
+       $(CC) -c $(INCLUDE_DIRS) $(CFLAGS) $< -o $@
+
+
+
+default: $(PROGRAMS)
+
+
+arc: arc.c eglcommon.o
+       $(CC) $(CFLAGS) $^ $(LIBS)  $(APP_LIB_DEPS) -o $@
+
+cap: cap.c eglcommon.o
+       $(CC) $(CFLAGS) $^ $(LIBS)  $(APP_LIB_DEPS) -o $@
+
+clear: clear.c eglcommon.o
+       $(CC) $(CFLAGS) $^ $(LIBS)  $(APP_LIB_DEPS) -o $@
+
+coord: coord.c eglcommon.o
+       $(CC) $(CFLAGS) $^ $(LIBS)  $(APP_LIB_DEPS) -o $@
+
+dash: dash.c eglcommon.o
+       $(CC) $(CFLAGS) $^ $(LIBS)  $(APP_LIB_DEPS) -o $@
+
+ellipse: ellipse.c eglcommon.o
+       $(CC) $(CFLAGS) $^ $(LIBS)  $(APP_LIB_DEPS) -o $@
+
+filter: filter.c eglcommon.o
+       $(CC) $(CFLAGS) $^ $(LIBS)  $(APP_LIB_DEPS) -o $@
+
+gradorigin: gradorigin.c eglcommon.o
+       $(CC) $(CFLAGS) $^ $(LIBS)  $(APP_LIB_DEPS) -o $@
+
+image: image.c eglcommon.o
+       $(CC) $(CFLAGS) $^ $(LIBS)  $(APP_LIB_DEPS) -o $@
+
+lineto: lineto.c eglcommon.o
+       $(CC) $(CFLAGS) $^ $(LIBS)  $(APP_LIB_DEPS) -o $@
+
+lingrad: lingrad.c eglcommon.o
+       $(CC) $(CFLAGS) $^ $(LIBS)  $(APP_LIB_DEPS) -o $@
+
+lookup: lookup.c eglcommon.o
+       $(CC) $(CFLAGS) $^ $(LIBS)  $(APP_LIB_DEPS) -o $@
+
+mask: mask.c eglcommon.o
+       $(CC) $(CFLAGS) $^ $(LIBS)  $(APP_LIB_DEPS) -o $@
+
+mask4: mask4.c eglcommon.o
+       $(CC) $(CFLAGS) $^ $(LIBS)  $(APP_LIB_DEPS) -o $@
+
+path3: path3.c eglcommon.o
+       $(CC) $(CFLAGS) $^ $(LIBS)  $(APP_LIB_DEPS) -o $@
+
+pattern: pattern.c eglcommon.o
+       $(CC) $(CFLAGS) $^ $(LIBS)  $(APP_LIB_DEPS) -o $@
+
+radialgrad: radialgrad.c eglcommon.o
+       $(CC) $(CFLAGS) $^ $(LIBS)  $(APP_LIB_DEPS) -o $@
+
+readpixels: readpixels.c eglcommon.o
+       $(CC) $(CFLAGS) $^ $(LIBS)  $(APP_LIB_DEPS) -o $@
+
+roundedrect: roundedrect.c eglcommon.o
+       $(CC) $(CFLAGS) $^ $(LIBS)  $(APP_LIB_DEPS) -o $@
+
+star-nonzero: star-nonzero.c eglcommon.o
+       $(CC) $(CFLAGS) $^ $(LIBS)  $(APP_LIB_DEPS) -o $@
+
+star-oddeven: star-oddeven.c eglcommon.o
+       $(CC) $(CFLAGS) $^ $(LIBS)  $(APP_LIB_DEPS) -o $@
+
+stroke: stroke.c eglcommon.o
+       $(CC) $(CFLAGS) $^ $(LIBS)  $(APP_LIB_DEPS) -o $@
+
+stroke2: stroke2.c eglcommon.o
+       $(CC) $(CFLAGS) $^ $(LIBS)  $(APP_LIB_DEPS) -o $@
+
+vguarc: vguarc.c eglcommon.o
+       $(CC) $(CFLAGS) $^ $(LIBS)  $(APP_LIB_DEPS) -o $@
+
+
+
+eglcommon.o: eglcommon.c $(HEADERS)
+       $(CC) -c $(CFLAGS) eglcommon.c
+
+
+clean:
+       rm -f *.o *~
+       rm -f *.so
+       rm -f $(PROGRAMS)
diff --git a/progs/openvg/trivial/arc.c b/progs/openvg/trivial/arc.c
new file mode 100644 (file)
index 0000000..db686be
--- /dev/null
@@ -0,0 +1,139 @@
+#include "eglcommon.h"
+
+#include <VG/openvg.h>
+#include <math.h>
+
+const VGfloat clear_color[4] = {1.0, 1.0, 1.0, 1.0};
+const VGfloat color[4] = {1.0, 1.0, 1.0, 0.5};
+
+VGPath vgPath;
+
+static void ellipse(VGPath vgPath, VGfloat rx, VGfloat ry, VGfloat angle)
+{
+    static const VGubyte cmd[] =
+    { VG_MOVE_TO_ABS, VG_SCCWARC_TO_REL, VG_SCCWARC_TO_REL, VG_CLOSE_PATH };
+
+    VGfloat val[12];
+    VGfloat c = cos(angle) * rx;
+    VGfloat s = sin(angle) * rx;
+
+    val[0] = c;
+    val[1] = s;
+    val[2] = rx;
+    val[3] = ry;
+    val[4] = angle;
+    val[5] = -2.0f * c;
+    val[6] = -2.0f * s;
+    val[7] = rx;
+    val[8] = ry;
+    val[9] = angle;
+    val[10] = 2.0f * c;
+    val[11] = 2.0f * s;
+
+    vgClearPath(vgPath, VG_PATH_CAPABILITY_ALL);
+    vgAppendPathData(vgPath, sizeof(cmd), cmd, val);
+    vgDrawPath(vgPath, VG_FILL_PATH | VG_STROKE_PATH);
+}
+
+static void
+init(void)
+{
+    VGPaint vgPaint;
+
+    vgSetfv(VG_CLEAR_COLOR, 4, clear_color);
+    vgPath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
+                          VG_PATH_DATATYPE_F, 1.0f, 0.0f, 0, 0,
+                          VG_PATH_CAPABILITY_ALL);
+
+    vgPaint = vgCreatePaint();
+    vgSetParameteri(vgPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
+    vgSetColor(vgPaint, 0x00ff00ff);
+    vgSetPaint(vgPaint, VG_FILL_PATH);
+
+    vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_NONANTIALIASED);
+    vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER);
+    vgSetf(VG_STROKE_LINE_WIDTH, 2.0f);
+    vgSeti(VG_STROKE_CAP_STYLE, VG_CAP_SQUARE);
+    vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_MITER);
+    vgSetf(VG_STROKE_MITER_LIMIT, 4.0f);
+    vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+}
+
+/* new window size or exposure */
+static void
+reshape(int w, int h)
+{
+}
+
+static void
+draw(void)
+{
+    vgClear(0, 0, window_width(), window_height());
+
+#if 0
+    vgLoadIdentity();
+    vgTranslate(40.0f, 24.0f);
+    vgScale(0.61804f, 0.61804f);
+    vgShear(-1.0f, 0.0f);
+    vgDrawPath(vgPath, VG_FILL_PATH | VG_STROKE_PATH);
+#else
+
+    /* row 1, col 1: Identity transform. */
+
+    vgLoadIdentity();
+    vgTranslate(8.0f, 8.0f);
+    ellipse(vgPath, 4.0f, 4.0f, 0.0f);
+
+    /* row 1, col 2: 10^3 horizontal squeeze. */
+
+    vgLoadIdentity();
+    vgTranslate(24.0f, 8.0f);
+    vgScale(1.0e-3f, 1.0f);
+    ellipse(vgPath, 4.0e3f, 4.0f, 0.0f);
+
+    /* row 1, col 3: 10^6 horizontal squeeze. */
+
+    vgLoadIdentity();
+    vgTranslate(40.0f, 8.0f);
+    vgScale(1.0e-6f, 1.0f);
+    ellipse(vgPath, 4.0e6f, 4.0f, 0.0f);
+
+    /* row 1, col 4: 10^9 horizontal squeeze. */
+
+    vgLoadIdentity();
+    vgTranslate(56.0f, 8.0f);
+    vgScale(1.0e-9f, 1.0f);
+    ellipse(vgPath, 4.0e9f, 4.0f, 0.0f);
+
+    /* row 2, col 1: 10^3 vertical squeeze. */
+
+    vgLoadIdentity();
+    vgTranslate(8.0f, 24.0f);
+    vgScale(1.0f, 1.0e-3f);
+    ellipse(vgPath, 4.0f, 4.0e3f, 0.0f);
+
+    /* row 2, col 2: Shear 0. */
+
+    vgLoadIdentity();
+    vgTranslate(24.0f, 24.0f);
+    vgShear(0.0f, 0.0f);
+    ellipse(vgPath, 4.0f, 4.0f, 0.0f);
+
+    /* row 2, col 3: Horizontal shear -1. */
+
+    vgLoadIdentity();
+    vgTranslate(40.0f, 24.0f);
+    vgScale(0.61804f, 0.61804f);
+    vgShear(-1.0f, 0.0f);
+    ellipse(vgPath, 10.47213f, 4.0f, 31.717f);
+#endif
+    vgFlush();
+}
+
+
+int main(int argc, char **argv)
+{
+    set_window_size(64, 64);
+   return run(argc, argv, init, reshape,
+              draw, 0);
+}
diff --git a/progs/openvg/trivial/cap.c b/progs/openvg/trivial/cap.c
new file mode 100644 (file)
index 0000000..cd84fe3
--- /dev/null
@@ -0,0 +1,75 @@
+#include "eglcommon.h"
+
+#include <VG/openvg.h>
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+static void
+init(void)
+{
+
+}
+
+/* new window size or exposure */
+static void
+reshape(int w, int h)
+{
+}
+
+const int subtest = 0;
+static void
+draw(void)
+{
+    VGPath line;
+    VGPaint fillPaint;
+    VGubyte lineCommands[3] = {VG_MOVE_TO_ABS, VG_LINE_TO_ABS, VG_LINE_TO_ABS};
+    VGfloat lineCoords[] =   {-2.0f,-1.0f, 0.0f,0.0f, -1.0f, -2.0f};
+    VGfloat clearColor[] = {0.0f, 0.0f, 0.0f, 1.0f};/* black color */
+    VGfloat fillColor[] = {1.0f, 1.0f, 1.0f, 1.0f};/* white color */
+    //VGfloat testRadius = 60.0f;
+    VGfloat testRadius = 10.0f;
+    int WINDSIZEX = window_width();
+    int WINDSIZEY = window_height();
+
+    line = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,
+                        1.0f, 0.0f, 0, 0, VG_PATH_CAPABILITY_ALL);
+    fillPaint = vgCreatePaint();
+
+    vgSetf(VG_STROKE_LINE_WIDTH, 1.0f);
+    //vgSeti(VG_STROKE_CAP_STYLE, VG_CAP_ROUND);
+    vgSeti(VG_STROKE_CAP_STYLE, VG_CAP_BUTT);
+    vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_ROUND);
+    //vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_BEVEL);
+
+    vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_BETTER);
+
+    vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+    vgLoadIdentity();
+    vgTranslate(60, 60);
+    vgScale(testRadius * 2, testRadius * 2);
+
+    vgAppendPathData(line, 3, lineCommands, lineCoords);
+
+    vgSetfv(VG_CLEAR_COLOR, 4, clearColor);
+
+    vgSetPaint(fillPaint, VG_STROKE_PATH);
+
+    vgSetParameterfv(fillPaint, VG_PAINT_COLOR, 4, fillColor);
+    vgSetParameteri( fillPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
+
+    vgClear(0, 0, WINDSIZEX, WINDSIZEY);
+    vgDrawPath(line, VG_STROKE_PATH);
+
+    vgDestroyPath(line);
+    vgDestroyPaint(fillPaint);
+}
+
+
+int main(int argc, char **argv)
+{
+   set_window_size(100, 100);
+   return run(argc, argv, init, reshape,
+              draw, 0);
+}
diff --git a/progs/openvg/trivial/clear.c b/progs/openvg/trivial/clear.c
new file mode 100644 (file)
index 0000000..efb6bf4
--- /dev/null
@@ -0,0 +1,42 @@
+#include "eglcommon.h"
+
+#include <VG/openvg.h>
+#include <stdio.h>
+
+float red_color[4] = {1.0, 0.0, 0.0, 1.0};
+float blue_color[4] = {0.0, 0.0, 1.0, 1.0};
+
+static void
+init(void)
+{
+}
+
+/* new window size or exposure */
+static void
+reshape(int w, int h)
+{
+   vgLoadIdentity();
+}
+
+static void
+draw(void)
+{
+    VGint scissor[4] = {100, 100, 25, 25};
+    vgSetfv(VG_CLEAR_COLOR, 4, red_color);
+    vgClear(0, 0, window_width(), window_height());
+
+    vgSetfv(VG_CLEAR_COLOR, 4, blue_color);
+    vgClear(50, 50, 50, 50);
+
+    //vgSetiv(VG_SCISSOR_RECTS, 4, scissor);
+    //vgSeti(VG_SCISSORING, VG_TRUE);
+    vgCopyPixels(100, 100, 50, 50, 50, 50);
+    vgClear(150, 150, 50, 50);
+}
+
+
+int main(int argc, char **argv)
+{
+   return run(argc, argv, init, reshape,
+              draw, 0);
+}
diff --git a/progs/openvg/trivial/coord.c b/progs/openvg/trivial/coord.c
new file mode 100644 (file)
index 0000000..81f7cb6
--- /dev/null
@@ -0,0 +1,66 @@
+#include "eglcommon.h"
+
+#include <VG/openvg.h>
+
+const VGfloat white_color[4] = {1.0, 1.0, 1.0, 1.0};
+const VGfloat color[4] = {0.4, 0.1, 1.0, 1.0};
+
+VGPath path;
+VGPaint fill;
+
+
+static void
+init(void)
+{
+   /* Absent VG_CLOSE_PATH */
+   VGubyte commands[] = {VG_MOVE_TO_ABS, VG_LINE_TO_ABS, VG_LINE_TO_ABS, VG_LINE_TO_ABS,
+                         VG_MOVE_TO_ABS, VG_LINE_TO_ABS, VG_LINE_TO_ABS, VG_LINE_TO_ABS};
+   VGfloat clearColor[] = {1.0f, 1.0f, 1.0f, 1.0f};/* white color */
+   VGfloat fillColor[] = {1.0f, 0.0f, 0.0f, 1.0f};/* red color */
+   VGfloat coords[] = {-16.0f, -16.0f, 0.0f, -16.0f, 0.0f, 0.0f, -16.0f, 0.0f,
+                       0.0f, 0.0f, 16.0f, 0.0f, 16.0f, 16.0f, 0.0f, 16.0f};
+
+   vgSetfv(VG_CLEAR_COLOR, 4, clearColor);
+   vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_NONANTIALIASED);
+
+   vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+   vgLoadIdentity();
+   vgTranslate(32.0f, 32.0f);
+
+   path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 0, 0,
+                       VG_PATH_CAPABILITY_ALL);
+   if (path == VG_INVALID_HANDLE)
+      return;
+   fill = vgCreatePaint();
+   if (fill == VG_INVALID_HANDLE) {
+      vgDestroyPath(path);
+      return;
+   }
+   vgAppendPathData(path, 8, commands, coords);
+   vgSetPaint(fill, VG_FILL_PATH);
+   vgSetParameterfv(fill, VG_PAINT_COLOR, 4, fillColor);
+   vgSetParameteri(fill, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
+}
+
+/* new window size or exposure */
+static void
+reshape(int w, int h)
+{
+}
+
+static void
+draw(void)
+{
+   vgClear(0, 0, window_width(), window_height());
+   vgDrawPath(path, VG_FILL_PATH);
+
+   vgFlush();
+}
+
+
+int main(int argc, char **argv)
+{
+   set_window_size(64, 64);
+   return run(argc, argv, init, reshape,
+              draw, 0);
+}
diff --git a/progs/openvg/trivial/dash.c b/progs/openvg/trivial/dash.c
new file mode 100644 (file)
index 0000000..2e84ddb
--- /dev/null
@@ -0,0 +1,95 @@
+#include "eglcommon.h"
+
+#include <VG/openvg.h>
+#include <X11/keysym.h>
+#include <stdio.h>
+
+const VGfloat white_color[4] = {1.0, 1.0, 1.0, 1.0};
+const VGfloat color[4] = {0.4, 0.1, 1.0, 1.0};
+
+VGPath path;
+VGPaint fill;
+
+VGint cap_style = VG_CAP_BUTT;
+
+static void
+init(void)
+{
+   static const VGubyte cmds[] = {VG_MOVE_TO_ABS,
+                                  VG_LINE_TO_ABS,
+                                  VG_LINE_TO_ABS
+   };
+#if 1
+   static const VGfloat coords[]   = {100, 100, 150, 100,
+                                      150, 200
+   };
+#else
+   static const VGfloat coords[]   = {100, 20, 100, 220,
+   };
+#endif
+   VGfloat dash_pattern[2] = { 20.f, 20.f };
+   path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1, 0, 0, 0,
+                       VG_PATH_CAPABILITY_APPEND_TO);
+   vgAppendPathData(path, 3, cmds, coords);
+
+   fill = vgCreatePaint();
+   vgSetParameterfv(fill, VG_PAINT_COLOR, 4, color);
+   vgSetPaint(fill, VG_FILL_PATH);
+
+   vgSetfv(VG_CLEAR_COLOR, 4, white_color);
+   vgSetf(VG_STROKE_LINE_WIDTH, 20);
+   vgSeti(VG_STROKE_CAP_STYLE, cap_style);
+   vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_ROUND);
+   vgSetfv(VG_STROKE_DASH_PATTERN, 2, dash_pattern);
+   vgSetf(VG_STROKE_DASH_PHASE, 0.0f);
+}
+
+/* new window size or exposure */
+static void
+reshape(int w, int h)
+{
+   vgLoadIdentity();
+}
+
+static void
+draw(void)
+{
+   vgClear(0, 0, window_width(), window_height());
+   vgDrawPath(path, VG_STROKE_PATH);
+
+   vgFlush();
+}
+
+static int  key_press(unsigned key)
+{
+    switch(key) {
+    case XK_c:
+    case XK_C:
+        ++cap_style;
+        if (cap_style > VG_CAP_SQUARE)
+            cap_style = VG_CAP_BUTT;
+        switch(cap_style) {
+        case VG_CAP_BUTT:
+            fprintf(stderr, "Cap style 'butt'\n");
+            break;
+        case VG_CAP_ROUND:
+            fprintf(stderr, "Cap style 'round'\n");
+            break;
+        case VG_CAP_SQUARE:
+            fprintf(stderr, "Cap style 'square'\n");
+            break;
+        }
+        vgSeti(VG_STROKE_CAP_STYLE, cap_style);
+        break;
+    default:
+        break;
+    }
+
+    return VG_TRUE;
+}
+
+int main(int argc, char **argv)
+{
+   return run(argc, argv, init, reshape,
+              draw, key_press);
+}
diff --git a/progs/openvg/trivial/eglcommon.c b/progs/openvg/trivial/eglcommon.c
new file mode 100644 (file)
index 0000000..bacd568
--- /dev/null
@@ -0,0 +1,288 @@
+#include "eglcommon.h"
+
+
+#include <assert.h>
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+#include <VG/openvg.h>  /* using full OpenGL for now */
+#include <GLES/egl.h>
+
+
+static init_func    init = 0;
+static draw_func    draw = 0;
+static reshape_func reshape = 0;
+static key_func     keyPress = 0;
+static VGint width = 300, height = 300;
+
+
+void set_window_size(int w, int h)
+{
+   width = w;
+   height = h;
+}
+
+/*
+ * Create an RGB, double-buffered X window.
+ * Return the window and context handles.
+ */
+static void
+make_x_window(Display *x_dpy, EGLDisplay egl_dpy,
+              const char *name,
+              int x, int y, int width, int height,
+              Window *winRet,
+              EGLContext *ctxRet,
+              EGLSurface *surfRet)
+{
+   static const EGLint attribs[] = {
+      EGL_RED_SIZE, 1,
+      EGL_GREEN_SIZE, 1,
+      EGL_BLUE_SIZE, 1,
+      EGL_NONE
+   };
+
+   int scrnum;
+   XSetWindowAttributes attr;
+   unsigned long mask;
+   Window root;
+   Window win;
+   XVisualInfo *visInfo, visTemplate;
+   int num_visuals;
+   EGLContext ctx;
+   EGLConfig config;
+   EGLint num_configs;
+   EGLint vid;
+
+   scrnum = DefaultScreen( x_dpy );
+   root = RootWindow( x_dpy, scrnum );
+
+   if (!eglChooseConfig( egl_dpy, attribs, &config, 1, &num_configs)) {
+      printf("Error: couldn't get an EGL visual config\n");
+      exit(1);
+   }
+
+   assert(config);
+   assert(num_configs > 0);
+
+   if (!eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) {
+      printf("Error: eglGetConfigAttrib() failed\n");
+      exit(1);
+   }
+
+   /* The X window visual must match the EGL config */
+   visTemplate.visualid = vid;
+   visInfo = XGetVisualInfo(x_dpy, VisualIDMask, &visTemplate, &num_visuals);
+   if (!visInfo) {
+      printf("Error: couldn't get X visual\n");
+      exit(1);
+   }
+
+   /* window attributes */
+   attr.background_pixel = 0;
+   attr.border_pixel = 0;
+   attr.colormap = XCreateColormap( x_dpy, root, visInfo->visual, AllocNone);
+   attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
+   mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+   win = XCreateWindow( x_dpy, root, 0, 0, width, height,
+                       0, visInfo->depth, InputOutput,
+                       visInfo->visual, mask, &attr );
+
+   /* set hints and properties */
+   {
+      XSizeHints sizehints;
+      sizehints.x = x;
+      sizehints.y = y;
+      sizehints.width  = width;
+      sizehints.height = height;
+      sizehints.flags = USSize | USPosition;
+      XSetNormalHints(x_dpy, win, &sizehints);
+      XSetStandardProperties(x_dpy, win, name, name,
+                              None, (char **)NULL, 0, &sizehints);
+   }
+
+   eglBindAPI(EGL_OPENVG_API);
+
+   ctx = eglCreateContext(egl_dpy, config, EGL_NO_CONTEXT, NULL );
+   if (!ctx) {
+      printf("Error: eglCreateContext failed\n");
+      exit(1);
+   }
+
+   *surfRet = eglCreateWindowSurface(egl_dpy, config, win, NULL);
+
+   if (!*surfRet) {
+      printf("Error: eglCreateWindowSurface failed\n");
+      exit(1);
+   }
+
+   XFree(visInfo);
+
+   *winRet = win;
+   *ctxRet = ctx;
+}
+
+static void
+event_loop(Display *dpy, Window win,
+           EGLDisplay egl_dpy, EGLSurface egl_surf)
+{
+   while (1) {
+      int redraw = 0;
+      XEvent event;
+
+      XNextEvent(dpy, &event);
+
+      switch (event.type) {
+      case Expose:
+         redraw = 1;
+         break;
+      case ConfigureNotify:
+         if (reshape) {
+            width = event.xconfigure.width;
+            height = event.xconfigure.height;
+            reshape(event.xconfigure.width, event.xconfigure.height);
+         }
+         break;
+      case KeyPress:
+      {
+         char buffer[10];
+         int r, code;
+         code = XLookupKeysym(&event.xkey, 0);
+         if (!keyPress || !keyPress(code)) {
+            r = XLookupString(&event.xkey, buffer, sizeof(buffer),
+                              NULL, NULL);
+            if (buffer[0] == 27) {
+               /* escape */
+               return;
+            }
+         }
+      }
+      redraw = 1;
+      break;
+      default:
+         ; /*no-op*/
+      }
+
+      if (redraw) {
+         draw();
+         eglSwapBuffers(egl_dpy, egl_surf);
+      }
+   }
+}
+
+int window_width(void)
+{
+   return width;
+}
+
+int window_height(void)
+{
+   return height;
+}
+
+static void
+usage(void)
+{
+   printf("Usage:\n");
+   printf("  -display <displayname>  set the display to run on\n");
+   printf("  -info                   display OpenGL renderer info\n");
+}
+
+int run(int argc, char **argv,
+        init_func init_f,
+        reshape_func resh_f,
+        draw_func draw_f,
+        key_func key_f)
+{
+   const int winWidth = width, winHeight = height;
+   Display *x_dpy;
+   Window win;
+   EGLSurface egl_surf;
+   EGLContext egl_ctx;
+   EGLDisplay egl_dpy;
+   char *dpyName = NULL;
+   GLboolean printInfo = GL_FALSE;
+   EGLint egl_major, egl_minor;
+   int i;
+   const char *s;
+
+   init = init_f;
+   draw = draw_f;
+   reshape = resh_f;
+   keyPress = key_f;
+
+   for (i = 1; i < argc; i++) {
+      if (strcmp(argv[i], "-display") == 0) {
+         dpyName = argv[i+1];
+         i++;
+      }
+      else if (strcmp(argv[i], "-info") == 0) {
+         printInfo = GL_TRUE;
+      }
+   }
+
+   x_dpy = XOpenDisplay(dpyName);
+   if (!x_dpy) {
+      printf("Error: couldn't open display %s\n",
+            dpyName ? dpyName : getenv("DISPLAY"));
+      return -1;
+   }
+
+   egl_dpy = eglGetDisplay(x_dpy);
+   if (!egl_dpy) {
+      printf("Error: eglGetDisplay() failed\n");
+      return -1;
+   }
+
+   if (!eglInitialize(egl_dpy, &egl_major, &egl_minor)) {
+      printf("Error: eglInitialize() failed\n");
+      return -1;
+   }
+
+   s = eglQueryString(egl_dpy, EGL_VERSION);
+   printf("EGL_VERSION = %s\n", s);
+
+   make_x_window(x_dpy, egl_dpy,
+                 "OpenVG Example", 0, 0, winWidth, winHeight,
+                 &win, &egl_ctx, &egl_surf);
+
+   XMapWindow(x_dpy, win);
+   if (!eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx)) {
+      printf("Error: eglMakeCurrent() failed\n");
+      return -1;
+   }
+
+   if (printInfo) {
+      printf("VG_RENDERER   = %s\n", (char *) vgGetString(VG_RENDERER));
+      printf("VG_VERSION    = %s\n", (char *) vgGetString(VG_VERSION));
+      printf("VG_VENDOR     = %s\n", (char *) vgGetString(VG_VENDOR));
+   }
+
+   if (init)
+      init();
+
+   /* Set initial projection/viewing transformation.
+    * We can't be sure we'll get a ConfigureNotify event when the window
+    * first appears.
+    */
+   if (reshape)
+      reshape(winWidth, winHeight);
+
+   event_loop(x_dpy, win, egl_dpy, egl_surf);
+
+   eglMakeCurrent(egl_dpy, 0, 0, 0);
+   eglDestroyContext(egl_dpy, egl_ctx);
+   eglDestroySurface(egl_dpy, egl_surf);
+   eglTerminate(egl_dpy);
+
+
+   XDestroyWindow(x_dpy, win);
+   XCloseDisplay(x_dpy);
+
+   return 0;
+}
+
diff --git a/progs/openvg/trivial/eglcommon.h b/progs/openvg/trivial/eglcommon.h
new file mode 100644 (file)
index 0000000..958dae9
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef EGLCOMMON_H
+#define EGLCOMMON_H
+
+typedef void (*init_func)();
+typedef void (*reshape_func)(int, int);
+typedef void (*draw_func)();
+typedef int  (*key_func)(unsigned key);
+
+
+void set_window_size(int width, int height);
+int window_width(void);
+int window_height(void);
+
+int run(int argc, char **argv,
+        init_func init,
+        reshape_func resh,
+        draw_func draw,
+        key_func key);
+
+#endif
diff --git a/progs/openvg/trivial/ellipse.c b/progs/openvg/trivial/ellipse.c
new file mode 100644 (file)
index 0000000..4c7d490
--- /dev/null
@@ -0,0 +1,84 @@
+#include "eglcommon.h"
+
+#include <VG/openvg.h>
+
+#include <math.h>
+#include <stdlib.h>
+
+const VGfloat white_color[4] = {1.0, 1.0, 1.0, 1.0};
+const VGfloat color[4] = {0.0, 0.0, 0.0, 1.0};
+
+VGPath path;
+VGPaint paint;
+
+static void
+init(void)
+{
+   VGfloat clearColor[] = {1.0f, 1.0f, 1.0f, 1.0f};/* white color */
+   VGfloat fillColor[] = {1.0f, 0.0f, 0.0f, 1.0f};/* red color */
+   static const VGubyte segments[4] = {VG_MOVE_TO_ABS,
+                                       VG_SCCWARC_TO_ABS,
+                                       VG_SCCWARC_TO_ABS,
+                                       VG_CLOSE_PATH};
+   VGfloat data[12];
+   const VGfloat cx = 0, cy=29, width=80, height=40;
+   const VGfloat hw = width * 0.5f;
+   const VGfloat hh = height * 0.5f;
+
+   data[0] = cx + hw;
+   data[1] = cy;
+   data[2] = hw;
+   data[3] = hh;
+   data[4] = 0;
+   data[5] = cx - hw;
+   data[6] = cy;
+   data[7] = hw;
+   data[8] = hh;
+   data[9] = 0;
+   data[10] = data[0];
+   data[11] = cy;
+
+   vgSetfv(VG_CLEAR_COLOR, 4, clearColor);
+   vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_NONANTIALIASED);
+
+
+   path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,
+                       1.0f, 0.0f, 0, 0, VG_PATH_CAPABILITY_ALL);
+   if (path == VG_INVALID_HANDLE) {
+      return;
+   }
+   paint = vgCreatePaint();
+   if (paint == VG_INVALID_HANDLE) {
+      vgDestroyPath(path);
+      return;
+   }
+
+   vgAppendPathData(path, 4, segments, data);
+   vgSetParameterfv(paint, VG_PAINT_COLOR, 4, fillColor);
+   vgSetParameteri( paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
+   vgSetPaint(paint, VG_FILL_PATH);
+}
+
+/* new window size or exposure */
+static void
+reshape(int w, int h)
+{
+}
+
+static void
+draw(void)
+{
+   vgClear(0, 0, window_width(), window_height());
+   vgLoadIdentity();
+   vgTranslate(50, 21);
+   vgDrawPath(path, VG_FILL_PATH);
+   vgFlush();
+}
+
+
+int main(int argc, char **argv)
+{
+   set_window_size(100, 100);
+   return run(argc, argv, init, reshape,
+              draw, 0);
+}
diff --git a/progs/openvg/trivial/filter.c b/progs/openvg/trivial/filter.c
new file mode 100644 (file)
index 0000000..d96257a
--- /dev/null
@@ -0,0 +1,107 @@
+#include "eglcommon.h"
+
+#include <VG/openvg.h>
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+const VGfloat white_color[4] = {1.0, 1.0, 1.0, 1.0};
+const VGfloat color[4] = {1.0, 1.0, 1.0, 0.5};
+
+VGImage srcImg;
+VGImage dstImg;
+
+VGPaint fill;
+
+VGfloat bgCol[4] = {0.906f, 0.914f, 0.761f, 1.0f};
+
+static void
+init(void)
+{
+    VGfloat red[4];
+    VGfloat grey[4];
+    VGfloat orange[4];
+    VGfloat blue[4];
+    VGfloat black[4];
+    VGfloat white[4];
+    VGshort transKernel[49] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+    red[0] = 0.6710f;
+    red[1] = 0.1060f;
+    red[2] = 0.1330f;
+    red[3] = 1.0f;
+
+    grey[0] = 0.6347f;
+    grey[1] = 0.6561f;
+    grey[2] = 0.6057f;
+    grey[3] = 1.0f;
+
+    orange[0] = 1.0000f;
+    orange[1] = 0.8227f;
+    orange[2] = 0.5057f;
+    orange[3] = 1.0f;
+
+    blue[0] = 0.0000f;
+    blue[1] = 0.6908f;
+    blue[2] = 0.8595f;
+    blue[3] = 1.0f;
+
+    black[0] = 0;
+    black[1] = 0;
+    black[2] = 0;
+    black[3] = 1.0f;
+
+    white[0] = 1;
+    white[1] = 1;
+    white[2] = 1;
+    white[3] = 1.0f;
+
+    vgSetfv(VG_TILE_FILL_COLOR, 4, blue);
+
+    vgSeti(VG_FILTER_CHANNEL_MASK, 14);
+
+    /* Setup images */
+    srcImg = vgCreateImage(VG_sRGBA_8888, 32, 32,
+                           VG_IMAGE_QUALITY_NONANTIALIASED);
+    dstImg = vgCreateImage(VG_sRGBA_8888, 32, 32,
+                           VG_IMAGE_QUALITY_NONANTIALIASED);
+
+    vgSetfv(VG_CLEAR_COLOR, 4, black);
+    vgClearImage(srcImg, 0, 0, 32, 32);
+    vgSetfv(VG_CLEAR_COLOR, 4, red);
+    vgClearImage(srcImg, 3, 3, 27, 27);
+
+    vgSetfv(VG_CLEAR_COLOR, 4, orange);
+    vgClearImage(dstImg, 0, 0, 32, 32);
+
+    transKernel[8] = 1;
+    vgConvolve(dstImg, srcImg, 3, 3, 3, 0, transKernel,
+               1, 0, VG_TILE_FILL);
+}
+
+/* new window size or exposure */
+static void
+reshape(int w, int h)
+{
+}
+
+static void
+draw(void)
+{
+   vgSetfv(VG_CLEAR_COLOR, 4, bgCol);
+   vgClear(0, 0, window_width(), window_height());
+   vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+   vgLoadIdentity();
+   vgTranslate(10, 10);
+   vgDrawImage(dstImg);
+   vgFlush();
+}
+
+
+int main(int argc, char **argv)
+{
+   set_window_size(64, 64);
+   return run(argc, argv, init, reshape,
+              draw, 0);
+}
diff --git a/progs/openvg/trivial/gradorigin.c b/progs/openvg/trivial/gradorigin.c
new file mode 100644 (file)
index 0000000..b376263
--- /dev/null
@@ -0,0 +1,98 @@
+#include "eglcommon.h"
+
+#include <VG/openvg.h>
+
+#include <stdio.h>
+#include <string.h>
+
+static const VGfloat white_color[4] = {1.0, 1.0, 1.0, 1.0};
+
+static VGPath path;
+static VGPaint fill;
+
+VGColorRampSpreadMode spread = VG_COLOR_RAMP_SPREAD_PAD;
+
+static void
+init(void)
+{
+   VGubyte commands[5] =  {VG_MOVE_TO_ABS, VG_LINE_TO_ABS, VG_LINE_TO_ABS, VG_LINE_TO_ABS, VG_CLOSE_PATH};
+   VGfloat coords[8] =    {0.0f,0.0f, 32.0f,0.0f, 32.0f,32.0f, 0.0f,32.0f };
+
+   VGfloat rampStop[20] = {-0.5f,  1.0f, 1.0f, 1.0f, 1.0f,
+                           0.25f, 1.0f, 0.0f, 0.0f, 1.0f,
+                           0.75f, 0.0f, 0.0f, 1.0f, 1.0f,
+                           1.5f,  0.0f, 0.0f, 0.0f, 0.0f};
+
+   VGfloat defaultColor[] = {1.0f, 1.0f, 1.0f, 1.0f};
+   VGfloat linearGradient[4] = {0.0f, 0.0f, 0.0f, 32.0f};
+
+   path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,
+                       1.0f, 0.0f, 0, 0, VG_PATH_CAPABILITY_ALL);
+   if (path == VG_INVALID_HANDLE)
+      return;
+
+   fill = vgCreatePaint();
+   if (fill == VG_INVALID_HANDLE) {
+      vgDestroyPath(path);
+      return;
+   }
+
+   vgSetfv(VG_CLEAR_COLOR, 4, defaultColor);
+   vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_NONANTIALIASED);
+
+   vgAppendPathData(path, 5, commands, coords);
+
+   vgSetPaint(fill, VG_FILL_PATH);
+   vgSetParameteri(fill, VG_PAINT_TYPE, VG_PAINT_TYPE_LINEAR_GRADIENT);
+   vgSetParameteri(fill, VG_PAINT_COLOR_RAMP_SPREAD_MODE,
+                   VG_COLOR_RAMP_SPREAD_REPEAT);
+   vgSetParameterfv(fill, VG_PAINT_LINEAR_GRADIENT, 4, linearGradient);
+   vgSetParameterfv(fill, VG_PAINT_COLOR_RAMP_STOPS, 20, rampStop);
+}
+
+/* new window size or exposure */
+static void
+reshape(int w, int h)
+{
+   vgLoadIdentity();
+}
+
+static void
+draw(void)
+{
+   vgClear(0, 0, window_width(), window_height());
+
+   vgDrawPath(path, VG_FILL_PATH);
+
+   vgFlush();
+}
+
+
+int main(int argc, char **argv)
+{
+   if (argc > 1) {
+      const char *arg = argv[1];
+      if (!strcmp("-pad", arg))
+         spread = VG_COLOR_RAMP_SPREAD_PAD;
+      else if (!strcmp("-repeat", arg))
+         spread = VG_COLOR_RAMP_SPREAD_REPEAT;
+      else if (!strcmp("-reflect", arg))
+         spread = VG_COLOR_RAMP_SPREAD_REFLECT;
+   }
+
+   switch(spread) {
+   case VG_COLOR_RAMP_SPREAD_PAD:
+      printf("Using spread mode: pad\n");
+      break;
+   case VG_COLOR_RAMP_SPREAD_REPEAT:
+      printf("Using spread mode: repeat\n");
+      break;
+   case VG_COLOR_RAMP_SPREAD_REFLECT:
+      printf("Using spread mode: reflect\n");
+   }
+
+   set_window_size(200, 200);
+
+   return run(argc, argv, init, reshape,
+              draw, 0);
+}
diff --git a/progs/openvg/trivial/lineto.c b/progs/openvg/trivial/lineto.c
new file mode 100644 (file)
index 0000000..94e2981
--- /dev/null
@@ -0,0 +1,56 @@
+#include "eglcommon.h"
+
+#include <VG/openvg.h>
+
+const VGfloat white_color[4] = {1.0, 1.0, 1.0, 1.0};
+const VGfloat color[4] = {0.4, 0.1, 1.0, 1.0};
+
+VGPath path;
+VGPaint fill;
+
+
+static void
+init(void)
+{
+   static const VGubyte sqrCmds[5] = {VG_MOVE_TO_ABS, VG_HLINE_TO_ABS, VG_VLINE_TO_ABS, VG_HLINE_TO_ABS, VG_CLOSE_PATH};
+   static const VGfloat sqrCoords[5]   = {50.0f, 50.0f, 250.0f, 250.0f, 50.0f};
+   path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1, 0, 0, 0,
+                       VG_PATH_CAPABILITY_APPEND_TO);
+   vgAppendPathData(path, 5, sqrCmds, sqrCoords);
+
+   fill = vgCreatePaint();
+   vgSetParameterfv(fill, VG_PAINT_COLOR, 4, color);
+   vgSetPaint(fill, VG_FILL_PATH);
+
+   vgSetfv(VG_CLEAR_COLOR, 4, white_color);
+   vgSetf(VG_STROKE_LINE_WIDTH, 10);
+   vgSeti(VG_STROKE_CAP_STYLE, VG_CAP_BUTT);
+   vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_ROUND);
+   vgSetf(VG_STROKE_MITER_LIMIT, 4.0f);
+}
+
+/* new window size or exposure */
+static void
+reshape(int w, int h)
+{
+   vgLoadIdentity();
+}
+
+static void
+draw(void)
+{
+   vgClear(0, 0, window_width(), window_height());
+   vgSeti(VG_MATRIX_MODE, VG_MATRIX_STROKE_PAINT_TO_USER);
+   vgLoadIdentity();
+   vgScale(2.25, 2.25);
+   vgDrawPath(path, VG_STROKE_PATH);
+
+   vgFlush();
+}
+
+
+int main(int argc, char **argv)
+{
+   return run(argc, argv, init, reshape,
+              draw, 0);
+}
diff --git a/progs/openvg/trivial/lingrad.c b/progs/openvg/trivial/lingrad.c
new file mode 100644 (file)
index 0000000..bcaad1f
--- /dev/null
@@ -0,0 +1,87 @@
+#include "eglcommon.h"
+
+#include <VG/openvg.h>
+
+#include <stdio.h>
+#include <string.h>
+
+static const VGfloat white_color[4] = {1.0, 1.0, 1.0, 1.0};
+
+static VGPath path;
+static VGPaint fill;
+
+VGColorRampSpreadMode spread = VG_COLOR_RAMP_SPREAD_PAD;
+
+static void
+init(void)
+{
+   static const VGubyte sqrCmds[5] = {VG_MOVE_TO_ABS, VG_HLINE_TO_ABS, VG_VLINE_TO_ABS, VG_HLINE_TO_ABS, VG_CLOSE_PATH};
+   static const VGfloat sqrCoords[5]   = {0.0f, 0.0f, 400.0f, 400.0f, 0.0f};
+
+   VGfloat rampStop[] = {0.00f, 1.0f, 1.0f, 1.0f, 1.0f,
+                         0.33f, 1.0f, 0.0f, 0.0f, 1.0f,
+                         0.66f, 0.0f, 1.0f, 0.0f, 1.0f,
+                         1.00f, 0.0f, 0.0f,  1.0f, 1.0f};
+   VGfloat linearGradient[4] = {100.0f, 100.0f, 300.0f, 300.0f};
+
+   path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1, 0, 0, 0,
+                       VG_PATH_CAPABILITY_APPEND_TO);
+   vgAppendPathData(path, 5, sqrCmds, sqrCoords);
+
+   fill = vgCreatePaint();
+   vgSetPaint(fill, VG_FILL_PATH);
+
+   vgSetParameteri(fill, VG_PAINT_TYPE, VG_PAINT_TYPE_LINEAR_GRADIENT);
+   vgSetParameteri(fill, VG_PAINT_COLOR_RAMP_SPREAD_MODE, spread);
+   vgSetParameterfv(fill, VG_PAINT_LINEAR_GRADIENT, 4, linearGradient);
+   vgSetParameterfv(fill, VG_PAINT_COLOR_RAMP_STOPS, 20, rampStop);
+
+   vgSetfv(VG_CLEAR_COLOR, 4, white_color);
+}
+
+/* new window size or exposure */
+static void
+reshape(int w, int h)
+{
+   vgLoadIdentity();
+}
+
+static void
+draw(void)
+{
+   vgClear(0, 0, window_width(), window_height());
+
+   vgDrawPath(path, VG_FILL_PATH);
+
+   vgFlush();
+}
+
+
+int main(int argc, char **argv)
+{
+   if (argc > 1) {
+      const char *arg = argv[1];
+      if (!strcmp("-pad", arg))
+         spread = VG_COLOR_RAMP_SPREAD_PAD;
+      else if (!strcmp("-repeat", arg))
+         spread = VG_COLOR_RAMP_SPREAD_REPEAT;
+      else if (!strcmp("-reflect", arg))
+         spread = VG_COLOR_RAMP_SPREAD_REFLECT;
+   }
+
+   switch(spread) {
+   case VG_COLOR_RAMP_SPREAD_PAD:
+      printf("Using spread mode: pad\n");
+      break;
+   case VG_COLOR_RAMP_SPREAD_REPEAT:
+      printf("Using spread mode: repeat\n");
+      break;
+   case VG_COLOR_RAMP_SPREAD_REFLECT:
+      printf("Using spread mode: reflect\n");
+   }
+
+   set_window_size(400, 400);
+
+   return run(argc, argv, init, reshape,
+              draw, 0);
+}
diff --git a/progs/openvg/trivial/lookup.c b/progs/openvg/trivial/lookup.c
new file mode 100644 (file)
index 0000000..a103ba4
--- /dev/null
@@ -0,0 +1,71 @@
+#include "eglcommon.h"
+
+#include <VG/openvg.h>
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+const VGfloat white_color[4] = {1.0, 1.0, 1.0, 1.0};
+const VGfloat color[4] = {1.0, 1.0, 1.0, 0.5};
+VGfloat clearColor[] = {1.0f, 0.0f, 0.0f, 1.0f};/* red color */
+VGImage parent;
+
+VGPaint fill;
+
+static void
+init(void)
+{
+    VGImage child1, child2;
+    VGubyte *data;
+    VGuint  LUT[256];
+    VGint i;
+
+    data = (VGubyte *)malloc(sizeof(VGubyte)*window_width()*window_height());
+
+    for (i=0;i<window_width()*window_height();i++) {
+        data[i] = 0x00;
+    }
+
+    for (i=0; i<256; i++) {
+        if ( i == 0 )
+            LUT[0] = 0xFFFFFFFF;
+        else
+            LUT[i] = 0xFF00FFFF;
+    }
+
+    parent = vgCreateImage( VG_A_8, 64, 64, VG_IMAGE_QUALITY_NONANTIALIASED );
+
+    vgImageSubData(parent, data, window_width(), VG_A_8, 0, 0,
+                   window_width(), window_height());
+    child1 = vgChildImage(parent, 0, 0, 32, 64);
+    child2 = vgChildImage(parent, 32, 0, 32, 64);
+
+    vgLookupSingle(child2, child1, LUT, VG_GREEN, VG_FALSE, VG_TRUE);
+}
+
+/* new window size or exposure */
+static void
+reshape(int w, int h)
+{
+}
+
+static void
+draw(void)
+{
+   vgSetfv(VG_CLEAR_COLOR, 4, clearColor);
+   vgClear(0, 0, window_width(), window_height());
+   //vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+   //vgLoadIdentity();
+   //vgTranslate(10, 10);
+   vgDrawImage(parent);
+   vgFlush();
+}
+
+
+int main(int argc, char **argv)
+{
+   set_window_size(64, 64);
+   return run(argc, argv, init, reshape,
+              draw, 0);
+}
diff --git a/progs/openvg/trivial/mask.c b/progs/openvg/trivial/mask.c
new file mode 100644 (file)
index 0000000..e5c00c5
--- /dev/null
@@ -0,0 +1,58 @@
+#include "eglcommon.h"
+
+#include <VG/openvg.h>
+
+const VGfloat white_color[4] = {1.0, 1.0, 1.0, 1.0};
+const VGfloat color[4] = {0.4, 0.1, 1.0, 1.0};
+
+VGPath path;
+VGPaint fill;
+
+
+static void
+init(void)
+{
+   static const VGubyte sqrCmds[5] = {VG_MOVE_TO_ABS, VG_HLINE_TO_ABS, VG_VLINE_TO_ABS, VG_HLINE_TO_ABS, VG_CLOSE_PATH};
+   static const VGfloat sqrCoords[5]   = {50.0f, 50.0f, 250.0f, 250.0f, 50.0f};
+   path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1, 0, 0, 0,
+                       VG_PATH_CAPABILITY_APPEND_TO);
+   vgAppendPathData(path, 5, sqrCmds, sqrCoords);
+
+   fill = vgCreatePaint();
+   vgSetParameterfv(fill, VG_PAINT_COLOR, 4, color);
+   vgSetPaint(fill, VG_FILL_PATH);
+
+   vgSetfv(VG_CLEAR_COLOR, 4, white_color);
+   vgSetf(VG_STROKE_LINE_WIDTH, 10);
+   vgSeti(VG_STROKE_CAP_STYLE, VG_CAP_BUTT);
+   vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_ROUND);
+   vgSetf(VG_STROKE_MITER_LIMIT, 4.0f);
+
+   vgSeti(VG_MASKING, VG_TRUE);
+
+   vgMask(VG_INVALID_HANDLE, VG_CLEAR_MASK,
+          25, 25, 100, 100);
+}
+
+/* new window size or exposure */
+static void
+reshape(int w, int h)
+{
+   vgLoadIdentity();
+}
+
+static void
+draw(void)
+{
+   vgClear(0, 0, window_width(), window_height());
+   vgDrawPath(path, VG_FILL_PATH);
+
+   vgFlush();
+}
+
+
+int main(int argc, char **argv)
+{
+   return run(argc, argv, init, reshape,
+              draw, 0);
+}
diff --git a/progs/openvg/trivial/mask4.c b/progs/openvg/trivial/mask4.c
new file mode 100644 (file)
index 0000000..fe6db39
--- /dev/null
@@ -0,0 +1,132 @@
+#include "eglcommon.h"
+
+#include <VG/openvg.h>
+#include <VG/vgu.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+
+#include <X11/keysym.h>
+
+//VGint x_pos = -10, y_pos = -10;
+VGint x_pos = 0, y_pos = 4;
+VGint img_width = 120, img_height = 120;
+
+static void RectToPath(VGPath path, VGfloat x, VGfloat y, VGfloat width, VGfloat height)
+{
+    static const VGubyte segments[5] = {VG_MOVE_TO_ABS,
+                                        VG_HLINE_TO_ABS,
+                                        VG_VLINE_TO_ABS,
+                                        VG_HLINE_TO_ABS,
+                                        VG_CLOSE_PATH};
+    VGfloat data[5];
+
+    data[0] = x;
+    data[1] = y;
+    data[2] = x + width;
+    data[3] = y + height;
+    data[4] = x;
+
+    vgAppendPathData(path, 5, segments, data);
+}
+
+static void
+init(void)
+{
+}
+
+/* new window size or exposure */
+static void
+reshape(int w, int h)
+{
+}
+
+int  key_press(unsigned key)
+{
+    switch(key) {
+    case XK_Right:
+        x_pos +=1;
+        break;
+    case XK_Left:
+        x_pos -=1;
+        break;
+    case XK_Up:
+        y_pos +=1;
+        break;
+    case XK_Down:
+        y_pos -=1;
+        break;
+    case 'a':
+        img_width  -= 5;
+        img_height -= 5;
+        break;
+    case 's':
+        img_width  += 5;
+        img_height += 5;
+        break;
+    default:
+        break;
+    }
+    fprintf(stderr, "Posi = %dx%d\n", x_pos, y_pos);
+    fprintf(stderr, "Size = %dx%d\n", img_width, img_height);
+    return VG_FALSE;
+}
+
+static void
+draw(void)
+{
+    VGint WINDSIZEX = window_width();
+    VGint WINDSIZEY = window_height();
+
+    VGPaint fill;
+    VGPath box;
+    VGfloat color[4]           = {1.f, 0.f, 0.f, 1.f};
+    VGfloat bgCol[4]           = {0.7f, 0.7f, 0.7f, 1.0f};
+    VGfloat transCol[4]         = {0.f, 0.f, 0.f, 0.f};
+    VGImage image = vgCreateImage(VG_sRGBA_8888, img_width, img_height,
+                                  VG_IMAGE_QUALITY_NONANTIALIASED);
+
+    /* Background clear */
+    fill = vgCreatePaint();
+    vgSetParameterfv(fill, VG_PAINT_COLOR, 4, color);
+    vgSetPaint(fill, VG_FILL_PATH);
+
+    box = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,
+                       1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
+    /* Rectangle to cover completely 16x16 pixel area. */
+    RectToPath(box, 0, 0, 64, 64);
+
+    vgSetfv(VG_CLEAR_COLOR, 4, transCol);
+    vgClearImage(image, 0, 0, img_width, img_height);
+    vgSetfv(VG_CLEAR_COLOR, 4, color);
+    vgClearImage(image, 10, 10, 12, 12);
+    //vgImageSubData(image, pukki_64x64_data, pukki_64x64_stride,
+    //               VG_sRGBA_8888, 0, 0, 32, 32);
+    vgSeti(VG_MASKING, VG_TRUE);
+    vgLoadIdentity();
+
+    vgSetfv(VG_CLEAR_COLOR, 4, bgCol);
+    vgClear(0, 0, WINDSIZEX, WINDSIZEY);
+
+
+    vgMask(image, VG_FILL_MASK, 0, 0, window_width(), window_height());
+    vgMask(image, VG_SET_MASK, x_pos, y_pos, 100, 100);
+
+    vgDrawPath(box, VG_FILL_PATH);
+
+    //vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+    //vgTranslate(-10, -10);
+    //vgDrawImage(image);
+
+
+    vgDestroyPaint(fill);
+    vgDestroyPath(box);
+}
+
+
+int main(int argc, char **argv)
+{
+    set_window_size(64, 64);
+    return run(argc, argv, init, reshape,
+               draw, key_press);
+}
diff --git a/progs/openvg/trivial/path3.c b/progs/openvg/trivial/path3.c
new file mode 100644 (file)
index 0000000..5ce600f
--- /dev/null
@@ -0,0 +1,77 @@
+#include "eglcommon.h"
+
+#include <VG/openvg.h>
+#include <VG/vgu.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+
+static void
+init(void)
+{
+}
+
+/* new window size or exposure */
+static void
+reshape(int w, int h)
+{
+}
+
+
+static void
+draw(void)
+{
+    VGint WINDSIZEX = window_width();
+    VGint WINDSIZEY = window_height();
+    VGPath path;
+    VGPaint paint;
+
+    VGfloat clearColor[] = {1.0f, 1.0f, 1.0f, 0.0f};/* white color */
+    VGfloat fillColor[] = {1.0f, 0.0f, 0.0f, 1.0f};/* red color */
+
+#if 1
+    VGubyte commands[4] = {VG_MOVE_TO_ABS, VG_LCWARC_TO_ABS, VG_SCWARC_TO_ABS, VG_CLOSE_PATH};
+#else
+    VGubyte commands[4] = {VG_MOVE_TO_ABS, VG_SCCWARC_TO_ABS, VG_LCCWARC_TO_ABS,VG_CLOSE_PATH};
+#endif
+    VGfloat coords[] = {32.0f,   0.0f,
+                        -32.0f, -32.0f, 0.0f, 64.0f, 32.0f,
+                        -32.0f, -32.0f, 0.0f, 32.0f, 0.0f};
+
+
+    vgSetfv(VG_CLEAR_COLOR, 4, clearColor);
+    vgClear(0, 0, WINDSIZEX, WINDSIZEY);
+    vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_NONANTIALIASED);
+
+    vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+    vgLoadIdentity();
+    //vgTranslate(32.0f, 32.0f);
+
+    path = vgCreatePath( VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,
+                         1.0f, 0.0f, 0, 0, VG_PATH_CAPABILITY_ALL );
+    if ( path == VG_INVALID_HANDLE ) {
+        return;
+    }
+    paint = vgCreatePaint();
+    if ( paint == VG_INVALID_HANDLE ) {
+        vgDestroyPath(path);
+        return;
+    }
+
+    vgAppendPathData(path, 4, commands, coords);
+    vgSetParameterfv(paint, VG_PAINT_COLOR, 4, fillColor);
+    vgSetParameteri( paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
+    vgSetPaint(paint, VG_FILL_PATH);
+    vgDrawPath(path, VG_FILL_PATH);
+
+    vgDestroyPath(path);
+    vgDestroyPaint(paint);
+}
+
+
+int main(int argc, char **argv)
+{
+    set_window_size(64, 64);
+    return run(argc, argv, init, reshape,
+               draw, 0);
+}
diff --git a/progs/openvg/trivial/radialgrad.c b/progs/openvg/trivial/radialgrad.c
new file mode 100644 (file)
index 0000000..cf3b1d5
--- /dev/null
@@ -0,0 +1,99 @@
+#include "eglcommon.h"
+
+#include <VG/openvg.h>
+
+#include <stdio.h>
+#include <string.h>
+
+static const VGfloat white_color[4] = {1.0, 1.0, 1.0, 1.0};
+
+static VGPath path;
+static VGPaint fill;
+
+
+VGfloat centeredGradient[5] = {200.0f, 200.0f, 200.0f, 200.0f, 100};
+VGfloat noncenteredGradient[5] = {200.0f, 200.0f, 250.0f, 250.0f, 100};
+VGfloat *radialGradient = centeredGradient;
+
+VGColorRampSpreadMode spread = VG_COLOR_RAMP_SPREAD_PAD;
+
+static void
+init(void)
+{
+   static const VGubyte sqrCmds[5] = {VG_MOVE_TO_ABS, VG_HLINE_TO_ABS, VG_VLINE_TO_ABS, VG_HLINE_TO_ABS, VG_CLOSE_PATH};
+   static const VGfloat sqrCoords[5]   = {0.0f, 0.0f, 400.0f, 400.0f, 0.0f};
+
+   VGfloat rampStop[] = {0.00f, 1.0f, 1.0f, 1.0f, 1.0f,
+                         0.33f, 1.0f, 0.0f, 0.0f, 1.0f,
+                         0.66f, 0.0f, 1.0f, 0.0f, 1.0f,
+                         1.00f, 0.0f, 0.0f,  1.0f, 1.0f};
+
+   path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1, 0, 0, 0,
+                       VG_PATH_CAPABILITY_APPEND_TO);
+   vgAppendPathData(path, 5, sqrCmds, sqrCoords);
+
+   fill = vgCreatePaint();
+   vgSetPaint(fill, VG_FILL_PATH);
+
+   vgSetParameteri(fill, VG_PAINT_TYPE, VG_PAINT_TYPE_RADIAL_GRADIENT);
+   vgSetParameteri(fill, VG_PAINT_COLOR_RAMP_SPREAD_MODE, spread);
+   vgSetParameterfv(fill, VG_PAINT_RADIAL_GRADIENT, 5, radialGradient);
+   vgSetParameterfv(fill, VG_PAINT_COLOR_RAMP_STOPS, 20, rampStop);
+
+   vgSetfv(VG_CLEAR_COLOR, 4, white_color);
+}
+
+/* new window size or exposure */
+static void
+reshape(int w, int h)
+{
+   vgLoadIdentity();
+}
+
+static void
+draw(void)
+{
+   vgClear(0, 0, window_width(), window_height());
+
+   vgDrawPath(path, VG_FILL_PATH);
+
+   vgFlush();
+}
+
+
+int main(int argc, char **argv)
+{
+   VGint i;
+   for (i = 1; i < argc; ++i) {
+      const char *arg = argv[i];
+      if (!strcmp("-pad", arg))
+         spread = VG_COLOR_RAMP_SPREAD_PAD;
+      else if (!strcmp("-repeat", arg))
+         spread = VG_COLOR_RAMP_SPREAD_REPEAT;
+      else if (!strcmp("-reflect", arg))
+         spread = VG_COLOR_RAMP_SPREAD_REFLECT;
+      else if (!strcmp("-center", arg)) {
+         printf("Centered radial gradient\n");
+         radialGradient = centeredGradient;
+      } else if (!strcmp("-noncenter", arg)) {
+         printf("Non centered radial gradient\n");
+         radialGradient = noncenteredGradient;
+      }
+   }
+
+   switch(spread) {
+   case VG_COLOR_RAMP_SPREAD_PAD:
+      printf("Using spread mode: pad\n");
+      break;
+   case VG_COLOR_RAMP_SPREAD_REPEAT:
+      printf("Using spread mode: repeat\n");
+      break;
+   case VG_COLOR_RAMP_SPREAD_REFLECT:
+      printf("Using spread mode: reflect\n");
+   }
+
+   set_window_size(400, 400);
+
+   return run(argc, argv, init, reshape,
+              draw, 0);
+}
diff --git a/progs/openvg/trivial/readpixels.c b/progs/openvg/trivial/readpixels.c
new file mode 100644 (file)
index 0000000..c8e286d
--- /dev/null
@@ -0,0 +1,75 @@
+#include "eglcommon.h"
+
+#include <VG/openvg.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+float red_color[4] = {1.0, 0.0, 0.0, 1.0};
+float blue_color[4] = {0.0, 0.0, 1.0, 1.0};
+VGint *data;
+
+static void
+init(void)
+{
+   data = malloc(sizeof(VGint)*2048*2048);
+}
+
+/* new window size or exposure */
+static void
+reshape(int w, int h)
+{
+   vgLoadIdentity();
+}
+
+static void
+draw(void)
+{
+   static const VGint red_pixel  = 255 << 24 | 255 << 16 | 0 << 8 |   0;
+   static const VGint blue_pixel = 255 << 24 |   0 << 16 | 0 << 8 | 255;
+   VGint i;
+
+   vgSetfv(VG_CLEAR_COLOR, 4, red_color);
+   vgClear(0, 0, window_width(), window_height());
+   vgFlush();
+
+   memset(data, 0, window_width() * window_height() * sizeof(VGint));
+
+   vgReadPixels(data, window_width() * sizeof(VGint),
+                VG_lARGB_8888,
+                0, 0, window_width(), window_height());
+
+   fprintf(stderr, "Red 0 = 0x%x and at 600 = 0x%x\n",
+           data[0], data[600]);
+   for (i = 0; i < window_width() * window_height(); ++i) {
+      assert(data[i] == red_pixel);
+   }
+
+   vgSetfv(VG_CLEAR_COLOR, 4, blue_color);
+   vgClear(50, 50, 50, 50);
+   vgFlush();
+
+   memset(data, 0, window_width() * window_height() * sizeof(VGint));
+
+   vgReadPixels(data, 50 * sizeof(VGint),
+                VG_lARGB_8888,
+                50, 50, 50, 50);
+
+   fprintf(stderr, "Blue 0 = 0x%x and at 100 = 0x%x\n",
+           data[0], data[100]);
+   for (i = 0; i < 50 * 50; ++i) {
+      assert(data[i] == blue_pixel);
+   }
+}
+
+
+int main(int argc, char **argv)
+{
+   int ret = run(argc, argv, init, reshape,
+                 draw, 0);
+
+   free(data);
+   return ret;
+}
diff --git a/progs/openvg/trivial/roundedrect.c b/progs/openvg/trivial/roundedrect.c
new file mode 100644 (file)
index 0000000..c80a4ed
--- /dev/null
@@ -0,0 +1,67 @@
+#include "eglcommon.h"
+
+#include <VG/openvg.h>
+
+const VGfloat white_color[4] = {1.0, 1.0, 1.0, 1.0};
+const VGfloat color[4] = {0.9, 0.1, 0.1, 0.8};
+
+VGPath path;
+VGPaint fill;
+
+
+static void
+init(void)
+{
+   static const VGubyte sqrCmds[10] = {VG_MOVE_TO_ABS,
+                                       VG_LINE_TO_ABS,
+                                       VG_CUBIC_TO_ABS,
+                                       VG_LINE_TO_ABS,
+                                       VG_CUBIC_TO_ABS,
+                                       VG_LINE_TO_ABS,
+                                       VG_CUBIC_TO_ABS,
+                                       VG_LINE_TO_ABS,
+                                       VG_CUBIC_TO_ABS,
+                                       VG_CLOSE_PATH};
+   static const VGfloat sqrCoords[]   = {
+      45.885571, 62.857143,
+      154.11442, 62.857143,
+      162.1236, 62.857143, 168.57142, 70.260744, 168.57142, 79.457144,
+      168.57142, 123.4,
+      168.57142, 132.5964, 162.1236,  140, 154.11442, 140,
+      45.885571, 140,
+      37.876394, 140, 31.428572, 132.5964, 31.428572, 123.4,
+      31.428572, 79.457144,
+      31.428572, 70.260744, 37.876394,62.857143, 45.885571,62.857143
+   };
+   path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1, 0, 0, 0,
+                       VG_PATH_CAPABILITY_APPEND_TO);
+   vgAppendPathData(path, 10, sqrCmds, sqrCoords);
+
+   fill = vgCreatePaint();
+   vgSetParameterfv(fill, VG_PAINT_COLOR, 4, color);
+   vgSetPaint(fill, VG_FILL_PATH);
+
+   vgSetfv(VG_CLEAR_COLOR, 4, white_color);
+   vgSetf(VG_STROKE_LINE_WIDTH, 6);
+}
+
+/* new window size or exposure */
+static void
+reshape(int w, int h)
+{
+   vgLoadIdentity();
+}
+
+static void
+draw(void)
+{
+   vgClear(0, 0, window_width(), window_height());
+   vgDrawPath(path, VG_STROKE_PATH);
+}
+
+
+int main(int argc, char **argv)
+{
+   return run(argc, argv, init, reshape,
+              draw, 0);
+}
diff --git a/progs/openvg/trivial/star-nonzero.c b/progs/openvg/trivial/star-nonzero.c
new file mode 100644 (file)
index 0000000..012fbd3
--- /dev/null
@@ -0,0 +1,55 @@
+#include "eglcommon.h"
+
+#include <VG/openvg.h>
+
+const VGfloat white_color[4] = {1.0, 1.0, 1.0, 1.0};
+const VGfloat green_color[4] = {0.0, 1.0, 0.0, 0.8};
+
+VGPath path;
+VGPaint fill;
+
+
+static void
+init(void)
+{
+   static const VGubyte cmds[6] = {VG_MOVE_TO_ABS, VG_LINE_TO_ABS, VG_LINE_TO_ABS, VG_LINE_TO_ABS,
+                                   VG_LINE_TO_ABS, VG_CLOSE_PATH};
+   static const VGfloat coords[]   = {  0,  200,
+                                        300,  200,
+                                        50,   0,
+                                        150, 300,
+                                        250,   0};
+   path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1, 0, 0, 0,
+                       VG_PATH_CAPABILITY_APPEND_TO);
+   vgAppendPathData(path, 6, cmds, coords);
+
+   fill = vgCreatePaint();
+   vgSetParameterfv(fill, VG_PAINT_COLOR, 4, green_color);
+   vgSetPaint(fill, VG_FILL_PATH);
+
+   vgSetfv(VG_CLEAR_COLOR, 4, white_color);
+   vgSeti(VG_FILL_RULE, VG_NON_ZERO);
+}
+
+/* new window size or exposure */
+static void
+reshape(int w, int h)
+{
+   vgLoadIdentity();
+}
+
+static void
+draw(void)
+{
+   vgClear(0, 0, window_width(), window_height());
+   vgDrawPath(path, VG_FILL_PATH | VG_STROKE_PATH);
+
+   vgFlush();
+}
+
+
+int main(int argc, char **argv)
+{
+   return run(argc, argv, init, reshape,
+              draw, 0);
+}
diff --git a/progs/openvg/trivial/star-oddeven.c b/progs/openvg/trivial/star-oddeven.c
new file mode 100644 (file)
index 0000000..17311cf
--- /dev/null
@@ -0,0 +1,102 @@
+#include "eglcommon.h"
+
+#include <VG/openvg.h>
+
+const VGfloat white_color[4] = {1.0, 1.0, 1.0, 1.0};
+const VGfloat green_color[4] = {0.0, 1.0, 0.0, 0.8};
+const VGfloat black_color[4] = {0.0, 0.0, 0.0, 1.0};
+
+VGPath path;
+VGPaint fill;
+
+
+static void draw_point(VGfloat x, VGfloat y)
+{
+
+   static const VGubyte cmds[] = {VG_MOVE_TO_ABS, VG_LINE_TO_ABS, VG_LINE_TO_ABS,
+                                  VG_LINE_TO_ABS, VG_CLOSE_PATH};
+   const VGfloat coords[]   = {  x - 2,  y - 2,
+                                 x + 2,  y - 2,
+                                 x + 2,  y + 2,
+                                 x - 2,  y + 2};
+   VGPath path;
+   VGPaint fill;
+
+   path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1, 0, 0, 0,
+                       VG_PATH_CAPABILITY_ALL);
+   vgAppendPathData(path, 5, cmds, coords);
+
+   fill = vgCreatePaint();
+   vgSetParameterfv(fill, VG_PAINT_COLOR, 4, black_color);
+   vgSetPaint(fill, VG_FILL_PATH);
+
+   vgDrawPath(path, VG_FILL_PATH);
+
+   vgDestroyPath(path);
+   vgDestroyPaint(fill);
+}
+
+static void draw_marks(VGPath path)
+{
+    VGfloat point[2], tangent[2];
+    int i = 0;
+
+    for (i = 0; i < 1300; i += 50) {
+        vgPointAlongPath(path, 0, 6, i,
+                         point + 0, point + 1,
+                         tangent + 0, tangent + 1);
+        draw_point(point[0], point[1]);
+    }
+}
+
+static void
+init(void)
+{
+   static const VGubyte cmds[6] = {VG_MOVE_TO_ABS, VG_LINE_TO_ABS, VG_LINE_TO_ABS, VG_LINE_TO_ABS,
+                                   VG_LINE_TO_ABS, VG_CLOSE_PATH};
+   static const VGfloat coords[]   = {  0,  200,
+                                        300,  200,
+                                        50,   0,
+                                        150, 300,
+                                        250,   0};
+   path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1, 0, 0, 0,
+                       VG_PATH_CAPABILITY_ALL);
+   vgAppendPathData(path, 6, cmds, coords);
+
+   fill = vgCreatePaint();
+   vgSetParameterfv(fill, VG_PAINT_COLOR, 4, green_color);
+   vgSetPaint(fill, VG_FILL_PATH);
+
+   vgSetfv(VG_CLEAR_COLOR, 4, white_color);
+}
+
+/* new window size or exposure */
+static void
+reshape(int w, int h)
+{
+   vgLoadIdentity();
+}
+
+static void
+draw(void)
+{
+    VGfloat point[2], tangent[2];
+    int i = 0;
+
+    vgClear(0, 0, window_width(), window_height());
+
+    vgSetPaint(fill, VG_FILL_PATH);
+    vgDrawPath(path, VG_FILL_PATH);
+
+    draw_marks(path);
+
+
+    vgFlush();
+}
+
+
+int main(int argc, char **argv)
+{
+   return run(argc, argv, init, reshape,
+              draw, 0);
+}
diff --git a/progs/openvg/trivial/stroke.c b/progs/openvg/trivial/stroke.c
new file mode 100644 (file)
index 0000000..58ae5b7
--- /dev/null
@@ -0,0 +1,116 @@
+#include "eglcommon.h"
+
+#include <VG/openvg.h>
+#include <X11/keysym.h>
+#include <stdio.h>
+
+const VGfloat white_color[4] = {1.0, 1.0, 1.0, 1.0};
+const VGfloat color[4] = {0.4, 0.1, 1.0, 1.0};
+
+VGPath path;
+VGPaint fill;
+
+VGint cap_style = VG_CAP_BUTT;
+VGint join_style = VG_JOIN_MITER;
+
+static void
+init(void)
+{
+#if 0
+   static const VGubyte cmds[] = {VG_MOVE_TO_ABS,
+                                  VG_CUBIC_TO_ABS,
+   };
+   static const VGfloat coords[]   = {30, 30, 264, 0, 0, 264, 234, 234
+   };
+#else
+   static const VGubyte cmds[] = {VG_MOVE_TO_ABS,
+                                  VG_LINE_TO_ABS,
+                                  VG_LINE_TO_ABS
+   };
+   static const VGfloat coords[]   = {30, 30, 202, 30, 150, 224
+   };
+#endif
+   VGfloat dash_pattern[2] = { 20.f, 20.f };
+   path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1, 0, 0, 0,
+                       VG_PATH_CAPABILITY_APPEND_TO);
+   vgAppendPathData(path, 3, cmds, coords);
+
+   fill = vgCreatePaint();
+   vgSetParameterfv(fill, VG_PAINT_COLOR, 4, color);
+   vgSetPaint(fill, VG_FILL_PATH);
+
+   vgSetfv(VG_CLEAR_COLOR, 4, white_color);
+   vgSetf(VG_STROKE_LINE_WIDTH, 20);
+   vgSeti(VG_STROKE_CAP_STYLE, cap_style);
+   vgSeti(VG_STROKE_JOIN_STYLE, join_style);
+   vgSetfv(VG_STROKE_DASH_PATTERN, 2, dash_pattern);
+   vgSetf(VG_STROKE_DASH_PHASE, 0.0f);
+}
+
+/* new window size or exposure */
+static void
+reshape(int w, int h)
+{
+   vgLoadIdentity();
+}
+
+static void
+draw(void)
+{
+   vgClear(0, 0, window_width(), window_height());
+   vgDrawPath(path, VG_STROKE_PATH);
+
+   vgFlush();
+}
+
+static int  key_press(unsigned key)
+{
+    switch(key) {
+    case XK_c:
+    case XK_C:
+        ++cap_style;
+        if (cap_style > VG_CAP_SQUARE)
+            cap_style = VG_CAP_BUTT;
+        switch(cap_style) {
+        case VG_CAP_BUTT:
+            fprintf(stderr, "Cap style 'butt'\n");
+            break;
+        case VG_CAP_ROUND:
+            fprintf(stderr, "Cap style 'round'\n");
+            break;
+        case VG_CAP_SQUARE:
+            fprintf(stderr, "Cap style 'square'\n");
+            break;
+        }
+        vgSeti(VG_STROKE_CAP_STYLE, cap_style);
+        break;
+    case XK_j:
+    case XK_J:
+        ++join_style;
+        if (join_style > VG_JOIN_BEVEL)
+            join_style = VG_JOIN_MITER;
+        switch(join_style) {
+        case VG_JOIN_MITER:
+            fprintf(stderr, "Join style 'miter'\n");
+            break;
+        case VG_JOIN_ROUND:
+            fprintf(stderr, "Join style 'round'\n");
+            break;
+        case VG_JOIN_BEVEL:
+            fprintf(stderr, "Join style 'bevel'\n");
+            break;
+        }
+        vgSeti(VG_STROKE_JOIN_STYLE, join_style);
+        break;
+    default:
+        break;
+    }
+
+    return VG_TRUE;
+}
+
+int main(int argc, char **argv)
+{
+   return run(argc, argv, init, reshape,
+              draw, key_press);
+}
diff --git a/progs/openvg/trivial/stroke2.c b/progs/openvg/trivial/stroke2.c
new file mode 100644 (file)
index 0000000..ce950c1
--- /dev/null
@@ -0,0 +1,207 @@
+#include "eglcommon.h"
+
+#include <VG/openvg.h>
+#include <X11/keysym.h>
+#include <stdio.h>
+
+VGPaint stroke;
+VGPath target;
+VGPath lines;
+
+VGfloat xform[9];
+VGfloat color1[4];
+VGfloat color2[4];
+VGfloat bgCol[4];
+
+static void
+init(void)
+{
+    VGubyte lineCmds[6];
+    VGfloat lineCoords[8];
+    VGfloat arcCoords[5];
+    VGubyte sccCmd[1];
+    VGubyte scCmd[1];
+    VGubyte lccCmd[1];
+    VGubyte lcCmd[1];
+    VGubyte moveCmd[1];
+    VGfloat moveCoords[2];
+    VGint i;
+
+    bgCol[0] = 1.0f;
+    bgCol[1] = 1.0f;
+    bgCol[2] = 1.0f;
+    bgCol[3] = 1.0f;
+
+    vgSetfv(VG_CLEAR_COLOR, 4, bgCol);
+    vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_NONANTIALIASED);
+
+    stroke = vgCreatePaint();
+    /* Red */
+    color1[0] = 1.0f;
+    color1[1] = 0.0f;
+    color1[2] = 0.0f;
+    color1[3] = 1.0f;
+
+    /* Orange */
+    color2[0] = 1.0000f;
+    color2[1] = 1.0f;
+    color2[2] = 0.0f;
+    color2[3] = 1.0f;
+    vgSetPaint(stroke, VG_STROKE_PATH);
+
+    vgSeti(VG_STROKE_CAP_STYLE, VG_CAP_SQUARE);
+
+    {
+        VGfloat temp[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+        for (i = 0; i < 9; i++)
+        {
+            xform[i] = temp[i];
+        }
+    }
+    vgGetMatrix(xform);
+
+    target = vgCreatePath(VG_PATH_FORMAT_STANDARD,
+                          VG_PATH_DATATYPE_F, 1, 0, 0, 0, VG_PATH_CAPABILITY_TRANSFORM_TO);
+
+#if 0
+    /* Line path */
+    {
+        VGubyte temp[6] = {VG_MOVE_TO_ABS, VG_VLINE_TO_REL,
+                           VG_MOVE_TO_ABS, VG_VLINE_TO_REL,
+                           VG_HLINE_TO_REL, VG_VLINE_TO_REL};
+        for (i = 0; i < 6; i++)
+        {
+            lineCmds[i] = temp[i];
+        }
+    }
+    {
+        VGfloat temp[8] = {0.5f, 0.8f, -0.6f, 0.28f, 0.6f, -0.4f, 0.44f, 0.4f};
+        for (i = 0; i < 8; i++)
+        {
+            lineCoords[i] = temp[i] * window_width();
+        }
+    }
+#else
+    {
+        VGfloat temp[5] = {0.35f, 0.15f, 29, 0.3f, 0.4f};
+        for (i = 0; i < 5; i++)
+        {
+            arcCoords[i] = temp[i] * window_width();
+        }
+        arcCoords[2] = 29;
+    }
+
+    {
+        VGubyte temp[1] = {VG_SCCWARC_TO_ABS};
+        for (i = 0; i < 1; i++)
+        {
+            sccCmd[i] = temp[i];
+        }
+    }
+    {
+        VGubyte temp[1] = {VG_SCWARC_TO_ABS};
+        for (i = 0; i < 1; i++)
+        {
+            scCmd[i] = temp[i];
+        }
+    }
+    {
+        VGubyte temp[1] = {VG_LCCWARC_TO_ABS};
+        for (i = 0; i < 1; i++)
+        {
+            lccCmd[i] = temp[i];
+        }
+    }
+    {
+        VGubyte temp[1] = {VG_LCWARC_TO_ABS};
+        for (i = 0; i < 1; i++)
+        {
+            lcCmd[i] = temp[i];
+        }
+    }
+
+    {
+        VGubyte temp[1] = {VG_MOVE_TO_ABS};
+        for (i = 0; i < 1; i++)
+        {
+            moveCmd[i] = temp[i];
+        }
+    }
+    {
+        VGfloat temp[2] = {0.7f, 0.6f};
+        for (i = 0; i < 2; i++)
+        {
+            moveCoords[i] = temp[i] * window_width();
+        }
+    }
+#endif
+
+    lines = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1,
+                         0, 0, 0,
+                         VG_PATH_CAPABILITY_APPEND_TO|
+                         VG_PATH_CAPABILITY_TRANSFORM_FROM);
+#if 0
+    vgAppendPathData(lines, 6, lineCmds, lineCoords);
+#else
+    vgAppendPathData(lines, 1, moveCmd, moveCoords);
+    vgAppendPathData(lines, 1, sccCmd, arcCoords);
+    vgAppendPathData(lines, 1, moveCmd, moveCoords);
+    vgAppendPathData(lines, 1, scCmd, arcCoords);
+    vgAppendPathData(lines, 1, moveCmd, moveCoords);
+    vgAppendPathData(lines, 1, lccCmd, arcCoords);
+    vgAppendPathData(lines, 1, moveCmd, moveCoords);
+    vgAppendPathData(lines, 1, lcCmd, arcCoords);
+#endif
+
+    vgLoadIdentity();
+    vgTranslate(0.25f * window_width(), 0.25f * window_height());
+    vgRotate(30);
+    vgTranslate(-0.25f * window_width(), -0.25f * window_height());
+    vgTransformPath(target, lines);}
+
+/* new window size or exposure */
+static void
+reshape(int w, int h)
+{
+}
+
+static void
+draw(void)
+{
+    vgClear(0, 0, window_width(), window_height());
+    vgLoadMatrix(xform);
+    vgLoadIdentity();
+    vgTranslate(0.25f * window_width(), 0.25f * window_height());
+    vgRotate(30);
+    vgTranslate(-0.25f * window_width(), -0.25f * window_height());
+    vgSetf(VG_STROKE_LINE_WIDTH, 7);
+    vgSetParameterfv(stroke, VG_PAINT_COLOR, 4, color1);
+    vgDrawPath(lines, VG_STROKE_PATH);
+
+    vgLoadMatrix(xform);
+    vgSetParameterfv(stroke, VG_PAINT_COLOR, 4, color2);
+    vgSetf(VG_STROKE_LINE_WIDTH, 3);
+    vgDrawPath(target, VG_STROKE_PATH);
+}
+
+static int  key_press(unsigned key)
+{
+    switch(key) {
+    case XK_c:
+    case XK_C:
+        break;
+    case XK_j:
+    case XK_J:
+        break;
+    default:
+        break;
+    }
+
+    return VG_TRUE;
+}
+
+int main(int argc, char **argv)
+{
+   return run(argc, argv, init, reshape,
+              draw, key_press);
+}
diff --git a/progs/openvg/trivial/vguarc.c b/progs/openvg/trivial/vguarc.c
new file mode 100644 (file)
index 0000000..8d971d5
--- /dev/null
@@ -0,0 +1,74 @@
+#include "eglcommon.h"
+
+#include <VG/openvg.h>
+#include <VG/vgu.h>
+
+const VGfloat white_color[4] = {1.0, 1.0, 1.0, 1.0};
+const VGfloat color[4] = {0.4, 0.1, 1.0, 1.0};
+
+VGPath path;
+VGPaint paint;
+
+
+static void
+init(void)
+{
+    VGfloat clearColor[] = {0.0f, 0.0f, 0.0f, 1.0f};/* black color */
+    VGfloat greenColor[] = {0.0f, 1.0f, 0.0f, 1.0f};/* green color */
+    VGint arcType = VGU_ARC_OPEN;
+    VGfloat x, y, w, h, startAngle, angleExtent;
+
+    x = 150;
+    y = 150;
+    w = 150;
+    h = 150;
+#if 0
+    startAngle  = -540.0f;
+    angleExtent = 270.0f;
+#else
+    startAngle  = 270.0f;
+    angleExtent = 90.0f;
+#endif
+
+    paint = vgCreatePaint();
+
+    vgSetPaint(paint, VG_STROKE_PATH);
+    vgSetParameterfv(paint, VG_PAINT_COLOR, 4, greenColor);
+    vgSetParameteri( paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
+    vgSetf(VG_STROKE_LINE_WIDTH, 6.0f);
+    vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_NONANTIALIASED);
+    vgSetfv(VG_CLEAR_COLOR, 4, clearColor);
+
+    path  = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,
+                         1.0f, 0.0f, 0, 0, VG_PATH_CAPABILITY_ALL);
+
+    vguArc(path, x, y, w, h, startAngle, angleExtent, arcType);
+
+    vgSeti(VG_STROKE_CAP_STYLE, VG_CAP_BUTT);
+    vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_BEVEL);
+    vgSetf(VG_STROKE_MITER_LIMIT, 4.0f);
+}
+
+/* new window size or exposure */
+static void
+reshape(int w, int h)
+{
+   vgLoadIdentity();
+}
+
+static void
+draw(void)
+{
+   vgClear(0, 0, window_width(), window_height());
+   vgDrawPath(path, VG_STROKE_PATH);
+
+   vgFlush();
+}
+
+
+int main(int argc, char **argv)
+{
+    // set_window_size(64, 63);
+   return run(argc, argv, init, reshape,
+              draw, 0);
+}
diff --git a/src/gallium/state_trackers/vega/Makefile b/src/gallium/state_trackers/vega/Makefile
new file mode 100644 (file)
index 0000000..b8c805b
--- /dev/null
@@ -0,0 +1,128 @@
+# src/mesa/Makefile
+
+TOP = ../../../..
+include $(TOP)/configs/current
+GALLIUM = $(TOP)
+
+### Lists of source files, included by Makefiles
+
+VG_SOURCES = \
+           api_context.c   \
+           api_filters.c   \
+           api_images.c    \
+           api_masks.c     \
+           api_misc.c      \
+           api_paint.c     \
+           api_params.c    \
+           api_path.c      \
+           api_text.c      \
+           api_transform.c \
+           vgu.c        \
+           vg_context.c \
+           vg_state.c   \
+           vg_tracker.c \
+           vg_translate.c \
+           polygon.c    \
+           bezier.c     \
+           path.c       \
+           paint.c      \
+           arc.c \
+           image.c \
+           renderer.c \
+           stroker.c \
+           mask.c \
+           shader.c \
+           shaders_cache.c
+
+
+### All the core C sources
+
+ALL_SOURCES = \
+        $(VG_SOURCES)
+
+
+### Object files
+VG_OBJECTS = \
+       $(VG_SOURCES:.c=.o)
+
+### Include directories
+
+INCLUDE_DIRS = \
+       -I$(TOP)/include \
+       -I$(GALLIUM)/include \
+       -I$(GALLIUM)/src/gallium/include \
+       -I$(GALLIUM)/src/gallium/auxiliary
+
+VG_LIB = OpenVG
+VG_LIB_NAME = lib$(VG_LIB).so
+
+VG_MAJOR = 1
+VG_MINOR = 0
+VG_TINY = 0
+
+GALLIUM_LIBS = \
+       $(GALLIUM)/src/gallium/auxiliary/pipebuffer/libpipebuffer.a \
+       $(GALLIUM)/src/gallium/auxiliary/sct/libsct.a \
+       $(GALLIUM)/src/gallium/auxiliary/draw/libdraw.a \
+       $(GALLIUM)/src/gallium/auxiliary/rtasm/librtasm.a \
+       $(GALLIUM)/src/gallium/auxiliary/translate/libtranslate.a \
+       $(GALLIUM)/src/gallium/auxiliary/cso_cache/libcso_cache.a \
+       $(GALLIUM)/src/gallium/auxiliary/util/libutil.a \
+       $(GALLIUM)/src/gallium/auxiliary/tgsi/libtgsi.a
+
+.SUFFIXES : .cpp
+
+.c.o:
+       $(CC) -c $(INCLUDE_DIRS) $(CFLAGS) $< -o $@
+
+.cpp.o:
+       $(CXX) -c $(INCLUDE_DIRS) $(CXXFLAGS) $< -o $@
+
+.S.o:
+       $(CC) -c $(INCLUDE_DIRS) $(CFLAGS) $< -o $@
+
+
+default: depend subdirs $(TOP)/$(LIB_DIR)/$(VG_LIB_NAME)
+
+# Make the OpenVG library
+$(TOP)/$(LIB_DIR)/$(VG_LIB_NAME): $(VG_OBJECTS) $(GALLIUM_LIBS)
+       $(TOP)/bin/mklib -o $(VG_LIB) \
+               -major $(VG_MAJOR) \
+               -minor $(VG_MINOR) \
+               -patch $(VG_TINY) \
+               -install $(TOP)/$(LIB_DIR) \
+               $(VG_OBJECTS) $(GALLIUM_LIBS) \
+               -Wl,--whole-archive $(LIBS) -Wl,--no-whole-archive $(SYS_LIBS)
+
+######################################################################
+# Generic stuff
+
+depend: $(ALL_SOURCES)
+       @ echo "running $(MKDEP)"
+       @ rm -f depend  # workaround oops on gutsy?!?
+       @ touch depend
+       @ $(MKDEP) $(MKDEP_OPTIONS) $(DEFINES) $(INCLUDE_DIRS) $(ALL_SOURCES) \
+               > /dev/null 2>/dev/null
+
+
+subdirs:
+
+install: default
+       $(INSTALL) -d $(INSTALL_DIR)/include/VG
+       $(INSTALL) -d $(INSTALL_DIR)/$(LIB_DIR)
+       $(INSTALL) -m 644 $(TOP)/include/VG/*.h $(INSTALL_DIR)/include/VG
+       @if [ -e $(TOP)/$(LIB_DIR)/$(VG_LIB_NAME) ]; then \
+               $(INSTALL) $(TOP)/$(LIB_DIR)/libOpenVG* $(INSTALL_DIR)/$(LIB_DIR); \
+       fi
+
+# Emacs tags
+tags:
+       etags `find . -name \*.[ch]` $(TOP)/include/VG/*.h
+
+clean:
+       -rm -f *.o
+       -rm -f */*.o
+       -rm -f */*/*.o
+       -rm -f depend depend.bak
+
+include depend
diff --git a/src/gallium/state_trackers/vega/api_consts.h b/src/gallium/state_trackers/vega/api_consts.h
new file mode 100644 (file)
index 0000000..e1b48d4
--- /dev/null
@@ -0,0 +1,56 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#ifndef API_CONSTS_H
+#define API_CONSTS_H
+
+/*must be at least 32*/
+#define VEGA_MAX_SCISSOR_RECTS 32
+
+/*must be at least 16*/
+#define VEGA_MAX_DASH_COUNT 32
+
+/*must be at least 7*/
+#define VEGA_MAX_KERNEL_SIZE 7
+
+/*must be at least 15*/
+#define VEGA_MAX_SEPARABLE_KERNEL_SIZE 15
+
+/*must be at least 32*/
+#define VEGA_MAX_COLOR_RAMP_STOPS 256
+
+#define VEGA_MAX_IMAGE_WIDTH 2048
+
+#define VEGA_MAX_IMAGE_HEIGHT 2048
+
+#define VEGA_MAX_IMAGE_PIXELS (2048*2048)
+
+#define VEGA_MAX_IMAGE_BYTES (2048*2048 * 4)
+
+/*must be at least 128*/
+#define VEGA_MAX_GAUSSIAN_STD_DEVIATION 128
+
+#endif
diff --git a/src/gallium/state_trackers/vega/api_context.c b/src/gallium/state_trackers/vega/api_context.c
new file mode 100644 (file)
index 0000000..47db102
--- /dev/null
@@ -0,0 +1,75 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#include "VG/openvg.h"
+
+#include "vg_context.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_screen.h"
+
+VGErrorCode vgGetError(void)
+{
+   struct vg_context *ctx = vg_current_context();
+   VGErrorCode error = VG_NO_CONTEXT_ERROR;
+
+   if (!ctx)
+      return error;
+
+   error = ctx->_error;
+   ctx->_error = VG_NO_ERROR;
+
+   return error;
+}
+
+void vgFlush(void)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct pipe_context *pipe;
+
+   if (!ctx)
+      return;
+
+   pipe = ctx->pipe;
+   pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
+}
+
+void vgFinish(void)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct pipe_fence_handle *fence = NULL;
+   struct pipe_context *pipe;
+
+   if (!ctx)
+      return;
+
+   pipe = ctx->pipe;
+
+   pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, &fence);
+
+   pipe->screen->fence_finish(pipe->screen, fence, 0);
+   pipe->screen->fence_reference(pipe->screen, &fence, NULL);
+}
diff --git a/src/gallium/state_trackers/vega/api_filters.c b/src/gallium/state_trackers/vega/api_filters.c
new file mode 100644 (file)
index 0000000..862cbb0
--- /dev/null
@@ -0,0 +1,805 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#include "VG/openvg.h"
+
+#include "vg_context.h"
+#include "image.h"
+#include "renderer.h"
+#include "shaders_cache.h"
+#include "st_inlines.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_state.h"
+#include "pipe/p_inlines.h"
+#include "pipe/p_screen.h"
+#include "pipe/p_shader_tokens.h"
+
+#include "util/u_memory.h"
+
+
+#include "asm_filters.h"
+
+
+struct filter_info {
+   struct vg_image *dst;
+   struct vg_image *src;
+   struct vg_shader * (*setup_shader)(struct vg_context *, void *);
+   void *user_data;
+   const void *const_buffer;
+   VGint const_buffer_len;
+   VGTilingMode tiling_mode;
+   struct pipe_texture *extra_texture;
+};
+
+static INLINE struct pipe_texture *create_texture_1d(struct vg_context *ctx,
+                                                     const VGuint *color_data,
+                                                     const VGint color_data_len)
+{
+   struct pipe_context *pipe = ctx->pipe;
+   struct pipe_screen *screen = pipe->screen;
+   struct pipe_texture *tex = 0;
+   struct pipe_texture templ;
+
+   memset(&templ, 0, sizeof(templ));
+   templ.target = PIPE_TEXTURE_1D;
+   templ.format = PIPE_FORMAT_A8R8G8B8_UNORM;
+   templ.last_level = 0;
+   templ.width[0] = color_data_len;
+   templ.height[0] = 1;
+   templ.depth[0] = 1;
+   pf_get_block(PIPE_FORMAT_A8R8G8B8_UNORM, &templ.block);
+   templ.tex_usage = PIPE_TEXTURE_USAGE_SAMPLER;
+
+   tex = screen->texture_create(screen, &templ);
+
+   { /* upload color_data */
+      struct pipe_transfer *transfer =
+         screen->get_tex_transfer(screen, tex,
+                                  0, 0, 0,
+                                  PIPE_TRANSFER_READ_WRITE ,
+                                  0, 0, tex->width[0], tex->height[0]);
+      void *map = screen->transfer_map(screen, transfer);
+      memcpy(map, color_data, sizeof(VGint)*color_data_len);
+      screen->transfer_unmap(screen, transfer);
+      screen->tex_transfer_destroy(transfer);
+   }
+
+   return tex;
+}
+
+static INLINE struct pipe_surface * setup_framebuffer(struct vg_image *dst)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct pipe_context *pipe = ctx->pipe;
+   struct pipe_framebuffer_state fb;
+   struct pipe_surface *dst_surf = pipe->screen->get_tex_surface(
+      pipe->screen, dst->texture, 0, 0, 0,
+      PIPE_BUFFER_USAGE_GPU_WRITE);
+
+   /* drawing dest */
+   memset(&fb, 0, sizeof(fb));
+   fb.width  = dst->x + dst_surf->width;
+   fb.height = dst->y + dst_surf->height;
+   fb.nr_cbufs = 1;
+   fb.cbufs[0] = dst_surf;
+   {
+      VGint i;
+      for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i)
+         fb.cbufs[i] = 0;
+   }
+   cso_set_framebuffer(ctx->cso_context, &fb);
+
+   return dst_surf;
+}
+
+static void setup_viewport(struct vg_image *dst)
+{
+   struct vg_context *ctx = vg_current_context();
+   vg_set_viewport(ctx, VEGA_Y0_TOP);
+}
+
+static void setup_blend()
+{
+   struct vg_context *ctx = vg_current_context();
+   struct pipe_blend_state blend;
+   memset(&blend, 0, sizeof(blend));
+   blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE;
+   blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+   blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
+   blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
+   if (ctx->state.vg.filter_channel_mask & VG_RED)
+      blend.colormask |= PIPE_MASK_R;
+   if (ctx->state.vg.filter_channel_mask & VG_GREEN)
+      blend.colormask |= PIPE_MASK_G;
+   if (ctx->state.vg.filter_channel_mask & VG_BLUE)
+      blend.colormask |= PIPE_MASK_B;
+   if (ctx->state.vg.filter_channel_mask & VG_ALPHA)
+      blend.colormask |= PIPE_MASK_A;
+   blend.blend_enable = 1;
+   cso_set_blend(ctx->cso_context, &blend);
+}
+
+static void setup_constant_buffer(struct vg_context *ctx, const void *buffer,
+                                  VGint param_bytes)
+{
+   struct pipe_context *pipe = ctx->pipe;
+   struct pipe_constant_buffer *cbuf = &ctx->filter.buffer;
+
+   /* We always need to get a new buffer, to keep the drivers simple and
+    * avoid gratuitous rendering synchronization. */
+   pipe_buffer_reference(&cbuf->buffer, NULL);
+
+   cbuf->buffer = pipe_buffer_create(pipe->screen, 16,
+                                     PIPE_BUFFER_USAGE_CONSTANT,
+                                     param_bytes);
+
+   if (cbuf->buffer) {
+      st_no_flush_pipe_buffer_write(ctx, cbuf->buffer,
+                                    0, param_bytes, buffer);
+   }
+
+   ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_FRAGMENT, 0, cbuf);
+}
+
+static void setup_samplers(struct vg_context *ctx, struct filter_info *info)
+{
+   struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
+   struct pipe_texture *textures[PIPE_MAX_SAMPLERS];
+   struct pipe_sampler_state sampler[3];
+   int num_samplers = 0;
+   int num_textures = 0;
+
+   samplers[0] = NULL;
+   samplers[1] = NULL;
+   samplers[2] = NULL;
+   samplers[3] = NULL;
+   textures[0] = NULL;
+   textures[1] = NULL;
+   textures[2] = NULL;
+   textures[3] = NULL;
+
+   memset(&sampler[0], 0, sizeof(struct pipe_sampler_state));
+   sampler[0].wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+   sampler[0].wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+   sampler[0].wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+   sampler[0].min_img_filter = PIPE_TEX_MIPFILTER_LINEAR;
+   sampler[0].mag_img_filter = PIPE_TEX_MIPFILTER_LINEAR;
+   sampler[0].normalized_coords = 1;
+
+   switch(info->tiling_mode) {
+   case VG_TILE_FILL:
+      sampler[0].wrap_s = PIPE_TEX_WRAP_CLAMP_TO_BORDER;
+      sampler[0].wrap_t = PIPE_TEX_WRAP_CLAMP_TO_BORDER;
+      memcpy(sampler[0].border_color,
+             ctx->state.vg.tile_fill_color,
+             sizeof(VGfloat) * 4);
+      break;
+   case VG_TILE_PAD:
+      sampler[0].wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+      sampler[0].wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+      break;
+   case VG_TILE_REPEAT:
+      sampler[0].wrap_s = PIPE_TEX_WRAP_REPEAT;
+      sampler[0].wrap_t = PIPE_TEX_WRAP_REPEAT;
+      break;
+   case VG_TILE_REFLECT:
+      sampler[0].wrap_s = PIPE_TEX_WRAP_MIRROR_REPEAT;
+      sampler[0].wrap_t = PIPE_TEX_WRAP_MIRROR_REPEAT;
+      break;
+   default:
+      debug_assert(!"Unknown tiling mode");
+   }
+
+   samplers[0] = &sampler[0];
+   textures[0] = info->src->texture;
+   ++num_samplers;
+   ++num_textures;
+
+   if (info->extra_texture) {
+      memcpy(&sampler[1], &sampler[0], sizeof(struct pipe_sampler_state));
+      samplers[1] = &sampler[1];
+      textures[1] = info->extra_texture;
+      ++num_samplers;
+      ++num_textures;
+   }
+
+
+   cso_set_samplers(ctx->cso_context, num_samplers, (const struct pipe_sampler_state **)samplers);
+   cso_set_sampler_textures(ctx->cso_context, num_textures, textures);
+}
+
+static struct vg_shader * setup_color_matrix(struct vg_context *ctx, void *user_data)
+{
+   struct vg_shader *shader =
+      shader_create_from_text(ctx->pipe, color_matrix_asm, 200,
+         PIPE_SHADER_FRAGMENT);
+   cso_set_fragment_shader_handle(ctx->cso_context, shader->driver);
+   return shader;
+}
+
+static struct vg_shader * setup_convolution(struct vg_context *ctx, void *user_data)
+{
+   char buffer[1024];
+   VGint num_consts = (VGint)(long)(user_data);
+   struct vg_shader *shader;
+
+   snprintf(buffer, 1023, convolution_asm, num_consts, num_consts / 2 + 1);
+
+   shader = shader_create_from_text(ctx->pipe, buffer, 200,
+                                    PIPE_SHADER_FRAGMENT);
+
+   cso_set_fragment_shader_handle(ctx->cso_context, shader->driver);
+   return shader;
+}
+
+static struct vg_shader * setup_lookup(struct vg_context *ctx, void *user_data)
+{
+   struct vg_shader *shader =
+      shader_create_from_text(ctx->pipe, lookup_asm,
+                              200, PIPE_SHADER_FRAGMENT);
+
+   cso_set_fragment_shader_handle(ctx->cso_context, shader->driver);
+   return shader;
+}
+
+
+static struct vg_shader * setup_lookup_single(struct vg_context *ctx, void *user_data)
+{
+   char buffer[1024];
+   VGImageChannel channel = (VGImageChannel)(user_data);
+   struct vg_shader *shader;
+
+   switch(channel) {
+   case VG_RED:
+      snprintf(buffer, 1023, lookup_single_asm, "xxxx");
+      break;
+   case VG_GREEN:
+      snprintf(buffer, 1023, lookup_single_asm, "yyyy");
+      break;
+   case VG_BLUE:
+      snprintf(buffer, 1023, lookup_single_asm, "zzzz");
+      break;
+   case VG_ALPHA:
+      snprintf(buffer, 1023, lookup_single_asm, "wwww");
+      break;
+   default:
+      debug_assert(!"Unknown color channel");
+   }
+
+   shader = shader_create_from_text(ctx->pipe, buffer, 200,
+                                    PIPE_SHADER_FRAGMENT);
+
+   cso_set_fragment_shader_handle(ctx->cso_context, shader->driver);
+   return shader;
+}
+
+static void execute_filter(struct vg_context *ctx,
+                           struct filter_info *info)
+{
+   struct pipe_surface *dst_surf;
+   struct vg_shader *shader;
+
+   cso_save_framebuffer(ctx->cso_context);
+   cso_save_fragment_shader(ctx->cso_context);
+   cso_save_viewport(ctx->cso_context);
+   cso_save_blend(ctx->cso_context);
+   cso_save_samplers(ctx->cso_context);
+   cso_save_sampler_textures(ctx->cso_context);
+
+   dst_surf = setup_framebuffer(info->dst);
+   setup_viewport(info->dst);
+   setup_blend();
+   setup_constant_buffer(ctx, info->const_buffer, info->const_buffer_len);
+   shader = info->setup_shader(ctx, info->user_data);
+   setup_samplers(ctx, info);
+
+   renderer_draw_texture(ctx->renderer,
+                         info->src->texture,
+                         info->dst->x, info->dst->y,
+                         info->dst->x + info->dst->width,
+                         info->dst->y + info->dst->height,
+                         info->dst->x, info->dst->y,
+                         info->dst->x + info->dst->width,
+                         info->dst->y + info->dst->height);
+
+   cso_restore_framebuffer(ctx->cso_context);
+   cso_restore_fragment_shader(ctx->cso_context);
+   cso_restore_viewport(ctx->cso_context);
+   cso_restore_blend(ctx->cso_context);
+   cso_restore_samplers(ctx->cso_context);
+   cso_restore_sampler_textures(ctx->cso_context);
+
+   vg_shader_destroy(ctx, shader);
+
+   pipe_surface_reference(&dst_surf, NULL);
+}
+
+void vgColorMatrix(VGImage dst, VGImage src,
+                   const VGfloat * matrix)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct vg_image *d, *s;
+   struct filter_info info;
+
+   if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   if (!matrix || !is_aligned(matrix)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   d = (struct vg_image*)dst;
+   s = (struct vg_image*)src;
+
+   if (vg_image_overlaps(d, s)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   info.dst = d;
+   info.src = s;
+   info.setup_shader = &setup_color_matrix;
+   info.user_data = NULL;
+   info.const_buffer = matrix;
+   info.const_buffer_len = 20 * sizeof(VGfloat);
+   info.tiling_mode = VG_TILE_PAD;
+   info.extra_texture = 0;
+   execute_filter(ctx, &info);
+}
+
+static VGfloat texture_offset(VGfloat width, VGint kernelSize, VGint current, VGint shift)
+{
+   VGfloat diff = current - shift;
+
+   return diff / width;
+}
+
+void vgConvolve(VGImage dst, VGImage src,
+                VGint kernelWidth, VGint kernelHeight,
+                VGint shiftX, VGint shiftY,
+                const VGshort * kernel,
+                VGfloat scale,
+                VGfloat bias,
+                VGTilingMode tilingMode)
+{
+   struct vg_context *ctx = vg_current_context();
+   VGfloat *buffer;
+   VGint buffer_len;
+   VGint i, j;
+   VGint idx = 0;
+   struct vg_image *d, *s;
+   VGint kernel_size = kernelWidth * kernelHeight;
+   struct filter_info info;
+   const VGint max_kernel_size = vgGeti(VG_MAX_KERNEL_SIZE);
+
+   if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   if (kernelWidth <= 0 || kernelHeight <= 0 ||
+      kernelWidth > max_kernel_size || kernelHeight > max_kernel_size) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   if (!kernel || !is_aligned_to(kernel, 2)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   if (tilingMode < VG_TILE_FILL ||
+       tilingMode > VG_TILE_REFLECT) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   d = (struct vg_image*)dst;
+   s = (struct vg_image*)src;
+
+   if (vg_image_overlaps(d, s)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   vg_validate_state(ctx);
+
+   buffer_len = 8 + 2 * 4 * kernel_size;
+   buffer = (VGfloat*)malloc(buffer_len * sizeof(VGfloat));
+
+   buffer[0] = 0.f;
+   buffer[1] = 1.f;
+   buffer[2] = 2.f; /*unused*/
+   buffer[3] = 4.f; /*unused*/
+
+   buffer[4] = kernelWidth * kernelHeight;
+   buffer[5] = scale;
+   buffer[6] = bias;
+   buffer[7] = 0.f;
+
+   idx = 8;
+   for (j = 0; j < kernelHeight; ++j) {
+      for (i = 0; i < kernelWidth; ++i) {
+         VGint index = j * kernelWidth + i;
+         VGfloat x, y;
+
+         x = texture_offset(s->width, kernelWidth, i, shiftX);
+         y = texture_offset(s->height, kernelHeight, j, shiftY);
+
+         buffer[idx + index*4 + 0] = x;
+         buffer[idx + index*4 + 1] = y;
+         buffer[idx + index*4 + 2] = 0.f;
+         buffer[idx + index*4 + 3] = 0.f;
+      }
+   }
+   idx += kernel_size * 4;
+
+   for (j = 0; j < kernelHeight; ++j) {
+      for (i = 0; i < kernelWidth; ++i) {
+         /* transpose the kernel */
+         VGint index = j * kernelWidth + i;
+         VGint kindex = (kernelWidth - i - 1) * kernelHeight + (kernelHeight - j - 1);
+         buffer[idx + index*4 + 0] = kernel[kindex];
+         buffer[idx + index*4 + 1] = kernel[kindex];
+         buffer[idx + index*4 + 2] = kernel[kindex];
+         buffer[idx + index*4 + 3] = kernel[kindex];
+      }
+   }
+
+   info.dst = d;
+   info.src = s;
+   info.setup_shader = &setup_convolution;
+   info.user_data = (void*)(long)(buffer_len/4);
+   info.const_buffer = buffer;
+   info.const_buffer_len = buffer_len * sizeof(VGfloat);
+   info.tiling_mode = tilingMode;
+   info.extra_texture = 0;
+   execute_filter(ctx, &info);
+
+   free(buffer);
+}
+
+void vgSeparableConvolve(VGImage dst, VGImage src,
+                         VGint kernelWidth,
+                         VGint kernelHeight,
+                         VGint shiftX, VGint shiftY,
+                         const VGshort * kernelX,
+                         const VGshort * kernelY,
+                         VGfloat scale,
+                         VGfloat bias,
+                         VGTilingMode tilingMode)
+{
+   struct vg_context *ctx = vg_current_context();
+   VGshort *kernel;
+   VGint i, j, idx = 0;
+   const VGint max_kernel_size = vgGeti(VG_MAX_SEPARABLE_KERNEL_SIZE);
+
+   if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   if (kernelWidth <= 0 || kernelHeight <= 0 ||
+       kernelWidth > max_kernel_size || kernelHeight > max_kernel_size) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   if (!kernelX || !kernelY ||
+       !is_aligned_to(kernelX, 2) || !is_aligned_to(kernelY, 2)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+   if (tilingMode < VG_TILE_FILL ||
+       tilingMode > VG_TILE_REFLECT) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+   kernel = malloc(sizeof(VGshort)*kernelWidth*kernelHeight);
+   for (i = 0; i < kernelWidth; ++i) {
+      for (j = 0; j < kernelHeight; ++j) {
+         kernel[idx] = kernelX[i] * kernelY[j];
+         ++idx;
+      }
+   }
+   vgConvolve(dst, src, kernelWidth, kernelHeight, shiftX, shiftY,
+              kernel, scale, bias, tilingMode);
+   free(kernel);
+}
+
+static INLINE VGfloat compute_gaussian_componenet(VGfloat x, VGfloat y,
+                                                  VGfloat stdDeviationX,
+                                                  VGfloat stdDeviationY)
+{
+   VGfloat mult = 1 / ( 2 * M_PI * stdDeviationX * stdDeviationY);
+   VGfloat e = exp( - ( pow(x, 2)/(2*pow(stdDeviationX, 2)) +
+                        pow(y, 2)/(2*pow(stdDeviationY, 2)) ) );
+   return mult * e;
+}
+
+static INLINE VGint compute_kernel_size(VGfloat deviation)
+{
+   VGint size = ceil(2.146 * deviation);
+   if (size > 11)
+      return 11;
+   return size;
+}
+
+static void compute_gaussian_kernel(VGfloat *kernel,
+                                    VGint width, VGint height,
+                                    VGfloat stdDeviationX,
+                                    VGfloat stdDeviationY)
+{
+   VGint i, j;
+   VGfloat scale = 0.0f;
+
+   for (j = 0; j < height; ++j) {
+      for (i = 0; i < width; ++i) {
+         VGint idx =  (height - j -1) * width + (width - i -1);
+         kernel[idx] = compute_gaussian_componenet(i-(ceil(width/2))-1,
+                                                   j-ceil(height/2)-1,
+                                                   stdDeviationX, stdDeviationY);
+         scale += kernel[idx];
+      }
+   }
+
+   for (j = 0; j < height; ++j) {
+      for (i = 0; i < width; ++i) {
+         VGint idx = j * width + i;
+         kernel[idx] /= scale;
+      }
+   }
+}
+
+void vgGaussianBlur(VGImage dst, VGImage src,
+                    VGfloat stdDeviationX,
+                    VGfloat stdDeviationY,
+                    VGTilingMode tilingMode)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct vg_image *d, *s;
+   VGfloat *buffer, *kernel;
+   VGint kernel_width, kernel_height, kernel_size;
+   VGint buffer_len;
+   VGint idx, i, j;
+   struct filter_info info;
+
+   if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   if (stdDeviationX <= 0 || stdDeviationY <= 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   if (tilingMode < VG_TILE_FILL ||
+       tilingMode > VG_TILE_REFLECT) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   d = (struct vg_image*)dst;
+   s = (struct vg_image*)src;
+
+   if (vg_image_overlaps(d, s)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   kernel_width = compute_kernel_size(stdDeviationX);
+   kernel_height = compute_kernel_size(stdDeviationY);
+   kernel_size = kernel_width * kernel_height;
+   kernel = malloc(sizeof(VGfloat)*kernel_size);
+   compute_gaussian_kernel(kernel, kernel_width, kernel_height,
+                           stdDeviationX, stdDeviationY);
+
+   buffer_len = 8 + 2 * 4 * kernel_size;
+   buffer = (VGfloat*)malloc(buffer_len * sizeof(VGfloat));
+
+   buffer[0] = 0.f;
+   buffer[1] = 1.f;
+   buffer[2] = 2.f; /*unused*/
+   buffer[3] = 4.f; /*unused*/
+
+   buffer[4] = kernel_width * kernel_height;
+   buffer[5] = 1.f;/*scale*/
+   buffer[6] = 0.f;/*bias*/
+   buffer[7] = 0.f;
+
+   idx = 8;
+   for (j = 0; j < kernel_height; ++j) {
+      for (i = 0; i < kernel_width; ++i) {
+         VGint index = j * kernel_width + i;
+         VGfloat x, y;
+
+         x = texture_offset(s->width, kernel_width, i, kernel_width/2);
+         y = texture_offset(s->height, kernel_height, j, kernel_height/2);
+
+         buffer[idx + index*4 + 0] = x;
+         buffer[idx + index*4 + 1] = y;
+         buffer[idx + index*4 + 2] = 0.f;
+         buffer[idx + index*4 + 3] = 0.f;
+      }
+   }
+   idx += kernel_size * 4;
+
+   for (j = 0; j < kernel_height; ++j) {
+      for (i = 0; i < kernel_width; ++i) {
+         /* transpose the kernel */
+         VGint index = j * kernel_width + i;
+         VGint kindex = (kernel_width - i - 1) * kernel_height + (kernel_height - j - 1);
+         buffer[idx + index*4 + 0] = kernel[kindex];
+         buffer[idx + index*4 + 1] = kernel[kindex];
+         buffer[idx + index*4 + 2] = kernel[kindex];
+         buffer[idx + index*4 + 3] = kernel[kindex];
+      }
+   }
+
+   info.dst = d;
+   info.src = s;
+   info.setup_shader = &setup_convolution;
+   info.user_data = (void*)(long)(buffer_len/4);
+   info.const_buffer = buffer;
+   info.const_buffer_len = buffer_len * sizeof(VGfloat);
+   info.tiling_mode = tilingMode;
+   info.extra_texture = 0;
+   execute_filter(ctx, &info);
+
+   free(buffer);
+   free(kernel);
+}
+
+void vgLookup(VGImage dst, VGImage src,
+              const VGubyte * redLUT,
+              const VGubyte * greenLUT,
+              const VGubyte * blueLUT,
+              const VGubyte * alphaLUT,
+              VGboolean outputLinear,
+              VGboolean outputPremultiplied)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct vg_image *d, *s;
+   VGuint color_data[256];
+   VGint i;
+   struct pipe_texture *lut_texture;
+   VGfloat buffer[4];
+   struct filter_info info;
+
+   if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   if (!redLUT || !greenLUT || !blueLUT || !alphaLUT) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   d = (struct vg_image*)dst;
+   s = (struct vg_image*)src;
+
+   if (vg_image_overlaps(d, s)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   for (i = 0; i < 256; ++i) {
+      color_data[i] = blueLUT[i] << 24 | greenLUT[i] << 16 |
+                      redLUT[i]  <<  8 | alphaLUT[i];
+   }
+   lut_texture = create_texture_1d(ctx, color_data, 255);
+
+   buffer[0] = 0.f;
+   buffer[1] = 0.f;
+   buffer[2] = 1.f;
+   buffer[3] = 1.f;
+
+   info.dst = d;
+   info.src = s;
+   info.setup_shader = &setup_lookup;
+   info.user_data = NULL;
+   info.const_buffer = buffer;
+   info.const_buffer_len = 4 * sizeof(VGfloat);
+   info.tiling_mode = VG_TILE_PAD;
+   info.extra_texture = lut_texture;
+
+   execute_filter(ctx, &info);
+
+   pipe_texture_reference(&lut_texture, NULL);
+}
+
+void vgLookupSingle(VGImage dst, VGImage src,
+                    const VGuint * lookupTable,
+                    VGImageChannel sourceChannel,
+                    VGboolean outputLinear,
+                    VGboolean outputPremultiplied)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct vg_image *d, *s;
+   struct pipe_texture *lut_texture;
+   VGfloat buffer[4];
+   struct filter_info info;
+   VGuint color_data[256];
+   VGint i;
+
+   if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   if (!lookupTable || !is_aligned(lookupTable)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   if (sourceChannel != VG_RED && sourceChannel != VG_GREEN &&
+       sourceChannel != VG_BLUE && sourceChannel != VG_ALPHA) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   d = (struct vg_image*)dst;
+   s = (struct vg_image*)src;
+
+   if (vg_image_overlaps(d, s)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   for (i = 0; i < 256; ++i) {
+      VGuint rgba = lookupTable[i];
+      VGubyte blue, green, red, alpha;
+      red   = (rgba & 0xff000000)>>24;
+      green = (rgba & 0x00ff0000)>>16;
+      blue  = (rgba & 0x0000ff00)>> 8;
+      alpha = (rgba & 0x000000ff)>> 0;
+      color_data[i] = blue << 24 | green << 16 |
+                      red  <<  8 | alpha;
+   }
+   lut_texture = create_texture_1d(ctx, color_data, 256);
+
+   buffer[0] = 0.f;
+   buffer[1] = 0.f;
+   buffer[2] = 1.f;
+   buffer[3] = 1.f;
+
+   info.dst = d;
+   info.src = s;
+   info.setup_shader = &setup_lookup_single;
+   info.user_data = (void*)sourceChannel;
+   info.const_buffer = buffer;
+   info.const_buffer_len = 4 * sizeof(VGfloat);
+   info.tiling_mode = VG_TILE_PAD;
+   info.extra_texture = lut_texture;
+
+   execute_filter(ctx, &info);
+
+   pipe_texture_reference(&lut_texture, NULL);
+}
diff --git a/src/gallium/state_trackers/vega/api_images.c b/src/gallium/state_trackers/vega/api_images.c
new file mode 100644 (file)
index 0000000..c437553
--- /dev/null
@@ -0,0 +1,489 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#include "image.h"
+
+#include "VG/openvg.h"
+
+#include "vg_context.h"
+#include "vg_translate.h"
+#include "api_consts.h"
+#include "image.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_screen.h"
+#include "pipe/p_inlines.h"
+#include "util/u_blit.h"
+#include "util/u_tile.h"
+#include "util/u_memory.h"
+
+static INLINE VGboolean supported_image_format(VGImageFormat format)
+{
+   switch(format) {
+   case VG_sRGBX_8888:
+   case VG_sRGBA_8888:
+   case VG_sRGBA_8888_PRE:
+   case VG_sRGB_565:
+   case VG_sRGBA_5551:
+   case VG_sRGBA_4444:
+   case VG_sL_8:
+   case VG_lRGBX_8888:
+   case VG_lRGBA_8888:
+   case VG_lRGBA_8888_PRE:
+   case VG_lL_8:
+   case VG_A_8:
+   case VG_BW_1:
+#ifdef OPENVG_VERSION_1_1
+   case VG_A_1:
+   case VG_A_4:
+#endif
+   case VG_sXRGB_8888:
+   case VG_sARGB_8888:
+   case VG_sARGB_8888_PRE:
+   case VG_sARGB_1555:
+   case VG_sARGB_4444:
+   case VG_lXRGB_8888:
+   case VG_lARGB_8888:
+   case VG_lARGB_8888_PRE:
+   case VG_sBGRX_8888:
+   case VG_sBGRA_8888:
+   case VG_sBGRA_8888_PRE:
+   case VG_sBGR_565:
+   case VG_sBGRA_5551:
+   case VG_sBGRA_4444:
+   case VG_lBGRX_8888:
+   case VG_lBGRA_8888:
+   case VG_lBGRA_8888_PRE:
+   case VG_sXBGR_8888:
+   case VG_sABGR_8888:
+   case VG_sABGR_8888_PRE:
+   case VG_sABGR_1555:
+   case VG_sABGR_4444:
+   case VG_lXBGR_8888:
+   case VG_lABGR_8888:
+   case VG_lABGR_8888_PRE:
+      return VG_TRUE;
+   default:
+      return VG_FALSE;
+   }
+   return VG_FALSE;
+}
+
+VGImage vgCreateImage(VGImageFormat format,
+                      VGint width, VGint height,
+                      VGbitfield allowedQuality)
+{
+   struct vg_context *ctx = vg_current_context();
+
+   if (!supported_image_format(format)) {
+      vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+   if (width <= 0 || height <= 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+   if (width > vgGeti(VG_MAX_IMAGE_WIDTH) ||
+       height > vgGeti(VG_MAX_IMAGE_HEIGHT)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+   if (width * height > vgGeti(VG_MAX_IMAGE_PIXELS)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+
+   if (!(allowedQuality & ((VG_IMAGE_QUALITY_NONANTIALIASED |
+                           VG_IMAGE_QUALITY_FASTER |
+                           VG_IMAGE_QUALITY_BETTER)))) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+
+   return (VGImage)image_create(format, width, height);
+}
+
+void vgDestroyImage(VGImage image)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct vg_image *img = (struct vg_image *)image;
+
+   if (image == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   if (!vg_object_is_valid((void*)image, VG_OBJECT_IMAGE)) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   image_destroy(img);
+}
+
+void vgClearImage(VGImage image,
+                  VGint x, VGint y,
+                  VGint width, VGint height)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct vg_image *img;
+
+   if (image == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   if (width <= 0 || height <= 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   img = (struct vg_image*)image;
+
+   if (x + width < 0 || y + height < 0)
+      return;
+
+   image_clear(img, x, y, width, height);
+
+}
+
+void vgImageSubData(VGImage image,
+                    const void * data,
+                    VGint dataStride,
+                    VGImageFormat dataFormat,
+                    VGint x, VGint y,
+                    VGint width, VGint height)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct vg_image *img;
+
+   if (image == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   if (!supported_image_format(dataFormat)) {
+      vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
+      return;
+   }
+   if (width <= 0 || height <= 0 || !data || !is_aligned(data)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   img = (struct vg_image*)(image);
+   image_sub_data(img, data, dataStride, dataFormat,
+                  x, y, width, height);
+}
+
+void vgGetImageSubData(VGImage image,
+                       void * data,
+                       VGint dataStride,
+                       VGImageFormat dataFormat,
+                       VGint x, VGint y,
+                       VGint width, VGint height)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct vg_image *img;
+
+   if (image == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   if (!supported_image_format(dataFormat)) {
+      vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
+      return;
+   }
+   if (width <= 0 || height <= 0 || !data || !is_aligned(data)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+   img = (struct vg_image*)image;
+   image_get_sub_data(img, data, dataStride, dataFormat,
+                      x, y, width, height);
+}
+
+VGImage vgChildImage(VGImage parent,
+                     VGint x, VGint y,
+                     VGint width, VGint height)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct vg_image *p;
+
+   if (parent == VG_INVALID_HANDLE ||
+       !vg_context_is_object_valid(ctx, VG_OBJECT_IMAGE, (void*)parent) ||
+       !vg_object_is_valid((void*)parent, VG_OBJECT_IMAGE)) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+   if (width <= 0 || height <= 0 || x < 0 || y < 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+   p = (struct vg_image *)parent;
+   if (x > p->width  || y > p->height) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+   if (x + width > p->width  || y + height > p->height) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+
+   return (VGImage)image_child_image(p, x, y, width, height);
+}
+
+VGImage vgGetParent(VGImage image)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct vg_image *img;
+
+   if (image == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+
+   img = (struct vg_image*)image;
+   if (img->parent)
+      return (VGImage)img->parent;
+   else
+      return image;
+}
+
+void vgCopyImage(VGImage dst, VGint dx, VGint dy,
+                 VGImage src, VGint sx, VGint sy,
+                 VGint width, VGint height,
+                 VGboolean dither)
+{
+   struct vg_context *ctx = vg_current_context();
+
+   if (src == VG_INVALID_HANDLE || dst == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   if (width <= 0 || height <= 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+   vg_validate_state(ctx);
+   image_copy((struct vg_image*)dst, dx, dy,
+              (struct vg_image*)src, sx, sy,
+              width, height, dither);
+}
+
+void vgDrawImage(VGImage image)
+{
+   struct vg_context *ctx = vg_current_context();
+
+   if (!ctx)
+      return;
+
+   if (image == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   vg_validate_state(ctx);
+   image_draw((struct vg_image*)image);
+}
+
+void vgSetPixels(VGint dx, VGint dy,
+                 VGImage src, VGint sx, VGint sy,
+                 VGint width, VGint height)
+{
+   struct vg_context *ctx = vg_current_context();
+
+   vg_validate_state(ctx);
+
+   if (src == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   if (width <= 0 || height <= 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+   image_set_pixels(dx, dy, (struct vg_image*)src, sx, sy, width,
+                    height);
+}
+
+void vgGetPixels(VGImage dst, VGint dx, VGint dy,
+                 VGint sx, VGint sy,
+                 VGint width, VGint height)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct vg_image *img;
+
+   if (dst == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   if (width <= 0 || height <= 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   img = (struct vg_image*)dst;
+
+   image_get_pixels(img, dx, dy,
+                    sx, sy, width, height);
+}
+
+void vgWritePixels(const void * data, VGint dataStride,
+                   VGImageFormat dataFormat,
+                   VGint dx, VGint dy,
+                   VGint width, VGint height)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct pipe_context *pipe = ctx->pipe;
+
+   if (!supported_image_format(dataFormat)) {
+      vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
+      return;
+   }
+   if (!data || !is_aligned(data)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+   if (width <= 0 || height <= 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   vg_validate_state(ctx);
+   {
+      struct vg_image *img = image_create(dataFormat, width, height);
+      image_sub_data(img, data, dataStride, dataFormat, 0, 0,
+                     width, height);
+#if 0
+      struct matrix *matrix = &ctx->state.vg.image_user_to_surface_matrix;
+      matrix_translate(matrix, dx, dy);
+      image_draw(img);
+      matrix_translate(matrix, -dx, -dy);
+#else
+      /* this looks like a better approach */
+      image_set_pixels(dx, dy, img, 0, 0, width, height);
+#endif
+      image_destroy(img);
+   }
+   /* make sure rendering has completed */
+   pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
+}
+
+void vgReadPixels(void * data, VGint dataStride,
+                  VGImageFormat dataFormat,
+                  VGint sx, VGint sy,
+                  VGint width, VGint height)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct pipe_context *pipe = ctx->pipe;
+   struct pipe_screen *screen = pipe->screen;
+
+   struct st_framebuffer *stfb = ctx->draw_buffer;
+   struct st_renderbuffer *strb = stfb->strb;
+   struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb;
+
+   VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4];
+   VGfloat *df = (VGfloat*)temp;
+   VGint y = (fb->height - sy) - 1, yStep = -1;
+   VGint i;
+   VGubyte *dst = (VGubyte *)data;
+   VGint xoffset = 0, yoffset = 0;
+
+   if (!supported_image_format(dataFormat)) {
+      vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
+      return;
+   }
+   if (!data || !is_aligned(data)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+   if (width <= 0 || height <= 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   /* make sure rendering has completed */
+   pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
+   if (sx < 0) {
+      xoffset = -sx;
+      xoffset *= _vega_size_for_format(dataFormat);
+      width += sx;
+      sx = 0;
+   }
+   if (sy < 0) {
+      yoffset = -sy;
+      height += sy;
+      sy = 0;
+      y = (fb->height - sy) - 1;
+      yoffset *= dataStride;
+   }
+
+   {
+      struct pipe_transfer *transfer;
+
+      transfer = screen->get_tex_transfer(screen, strb->texture,  0, 0, 0,
+                                          PIPE_TRANSFER_READ,
+                                          0, 0, width, height);
+
+      /* Do a row at a time to flip image data vertically */
+      for (i = 0; i < height; i++) {
+#if 0
+         debug_printf("%d-%d  == %d\n", sy, height, y);
+#endif
+         pipe_get_tile_rgba(transfer, sx, y, width, 1, df);
+         y += yStep;
+         _vega_pack_rgba_span_float(ctx, width, temp, dataFormat,
+                                    dst + yoffset + xoffset);
+         dst += dataStride;
+      }
+
+      screen->tex_transfer_destroy(transfer);
+   }
+}
+
+void vgCopyPixels(VGint dx, VGint dy,
+                  VGint sx, VGint sy,
+                  VGint width, VGint height)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb;
+   struct st_renderbuffer *strb = ctx->draw_buffer->strb;
+
+   if (width <= 0 || height <= 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   /* do nothing if we copy from outside the fb */
+   if (dx >= (VGint)fb->width || dy >= (VGint)fb->height ||
+       sx >= (VGint)fb->width || sy >= (VGint)fb->height)
+      return;
+
+   vg_validate_state(ctx);
+   /* make sure rendering has completed */
+   vgFinish();
+
+   vg_copy_surface(ctx, strb->surface, dx, dy,
+                   strb->surface, sx, sy, width, height);
+}
diff --git a/src/gallium/state_trackers/vega/api_masks.c b/src/gallium/state_trackers/vega/api_masks.c
new file mode 100644 (file)
index 0000000..4f9f3da
--- /dev/null
@@ -0,0 +1,373 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#include "VG/openvg.h"
+
+#include "mask.h"
+#include "renderer.h"
+
+#include "vg_context.h"
+#include "pipe/p_context.h"
+#include "pipe/p_inlines.h"
+#include "pipe/internal/p_winsys_screen.h" /* for winsys->update_buffer */
+
+#include "util/u_pack_color.h"
+#include "util/u_draw_quad.h"
+#include "util/u_memory.h"
+
+
+#define DISABLE_1_1_MASKING 1
+
+/**
+ * Draw a screen-aligned quadrilateral.
+ * Coords are window coords with y=0=bottom.  These coords will be transformed
+ * by the vertex shader and viewport transform.
+ */
+static void
+draw_clear_quad(struct vg_context *st,
+                float x0, float y0, float x1, float y1, float z,
+                const VGfloat color[4])
+{
+   struct pipe_context *pipe = st->pipe;
+   struct pipe_buffer *buf;
+   VGuint i;
+
+   /* positions */
+   st->clear.vertices[0][0][0] = x0;
+   st->clear.vertices[0][0][1] = y0;
+
+   st->clear.vertices[1][0][0] = x1;
+   st->clear.vertices[1][0][1] = y0;
+
+   st->clear.vertices[2][0][0] = x1;
+   st->clear.vertices[2][0][1] = y1;
+
+   st->clear.vertices[3][0][0] = x0;
+   st->clear.vertices[3][0][1] = y1;
+
+   /* same for all verts: */
+   for (i = 0; i < 4; i++) {
+      st->clear.vertices[i][0][2] = z;
+      st->clear.vertices[i][0][3] = 1.0;
+      st->clear.vertices[i][1][0] = color[0];
+      st->clear.vertices[i][1][1] = color[1];
+      st->clear.vertices[i][1][2] = color[2];
+      st->clear.vertices[i][1][3] = color[3];
+   }
+
+
+   /* put vertex data into vbuf */
+   buf =  pipe_user_buffer_create(pipe->screen,
+                                  st->clear.vertices,
+                                  sizeof(st->clear.vertices));
+
+
+   /* draw */
+   if (buf) {
+      util_draw_vertex_buffer(pipe, buf, 0,
+                              PIPE_PRIM_TRIANGLE_FAN,
+                              4,  /* verts */
+                              2); /* attribs/vert */
+
+      pipe_buffer_reference(&buf, NULL);
+   }
+}
+
+/**
+ * Do vgClear by drawing a quadrilateral.
+ */
+static void
+clear_with_quad(struct vg_context *st, float x0, float y0,
+                float width, float height, const VGfloat clear_color[4])
+{
+   VGfloat x1, y1;
+
+   vg_validate_state(st);
+
+   x1 = x0 + width;
+   y1 = y0 + height;
+
+   /*
+     printf("%s %f,%f %f,%f\n", __FUNCTION__,
+     x0, y0,
+     x1, y1);
+   */
+
+   if (st->pipe->winsys && st->pipe->winsys->update_buffer)
+      st->pipe->winsys->update_buffer( st->pipe->winsys,
+                                       st->pipe->priv );
+
+   cso_save_blend(st->cso_context);
+   cso_save_rasterizer(st->cso_context);
+   cso_save_fragment_shader(st->cso_context);
+   cso_save_vertex_shader(st->cso_context);
+
+   /* blend state: RGBA masking */
+   {
+      struct pipe_blend_state blend;
+      memset(&blend, 0, sizeof(blend));
+      blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE;
+      blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+      blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
+      blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
+      blend.colormask |= PIPE_MASK_R;
+      blend.colormask |= PIPE_MASK_G;
+      blend.colormask |= PIPE_MASK_B;
+      blend.colormask |= PIPE_MASK_A;
+      cso_set_blend(st->cso_context, &blend);
+   }
+
+   cso_set_rasterizer(st->cso_context, &st->clear.raster);
+
+   cso_set_fragment_shader_handle(st->cso_context, st->clear.fs);
+   cso_set_vertex_shader_handle(st->cso_context, vg_clear_vs(st));
+
+   /* draw quad matching scissor rect (XXX verify coord round-off) */
+   draw_clear_quad(st, x0, y0, x1, y1, 0, clear_color);
+
+   /* Restore pipe state */
+   cso_restore_blend(st->cso_context);
+   cso_restore_rasterizer(st->cso_context);
+   cso_restore_fragment_shader(st->cso_context);
+   cso_restore_vertex_shader(st->cso_context);
+}
+
+
+void vgMask(VGHandle mask, VGMaskOperation operation,
+            VGint x, VGint y,
+            VGint width, VGint height)
+{
+   struct vg_context *ctx = vg_current_context();
+
+   if (width <=0 || height <= 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   if (operation < VG_CLEAR_MASK || operation > VG_SUBTRACT_MASK) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+
+   vg_validate_state(ctx);
+
+   if (operation == VG_CLEAR_MASK) {
+      mask_fill(x, y, width, height, 0.f);
+   } else if (operation == VG_FILL_MASK) {
+      mask_fill(x, y, width, height, 1.f);
+   } else if (vg_object_is_valid((void*)mask, VG_OBJECT_IMAGE)) {
+      struct vg_image *image = (struct vg_image *)mask;
+      mask_using_image(image, operation, x, y, width, height);
+   } else if (vg_object_is_valid((void*)mask, VG_OBJECT_MASK)) {
+#if DISABLE_1_1_MASKING
+      return;
+#else
+      struct vg_mask_layer *layer = (struct vg_mask_layer *)mask;
+      mask_using_layer(layer, operation, x, y, width, height);
+#endif
+   } else {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+   }
+}
+
+void vgClear(VGint x, VGint y,
+             VGint width, VGint height)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct pipe_framebuffer_state *fb;
+
+   if (width <= 0 || height <= 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   vg_validate_state(ctx);
+#if 0
+   debug_printf("Clear [%d, %d, %d, %d] with [%f, %f, %f, %f]\n",
+                x, y, width, height,
+                ctx->state.vg.clear_color[0],
+                ctx->state.vg.clear_color[1],
+                ctx->state.vg.clear_color[2],
+                ctx->state.vg.clear_color[3]);
+#endif
+
+   fb = &ctx->state.g3d.fb;
+   /* check for a whole surface clear */
+   if (!ctx->state.vg.scissoring &&
+       (x == 0 && y == 0 && width == fb->width && height == fb->height)) {
+      ctx->pipe->clear(ctx->pipe, PIPE_CLEAR_COLOR | PIPE_CLEAR_DEPTHSTENCIL,
+                       ctx->state.vg.clear_color, 1., 0);
+   } else {
+      clear_with_quad(ctx, x, y, width, height, ctx->state.vg.clear_color);
+   }
+}
+
+
+#ifdef OPENVG_VERSION_1_1
+
+
+void vgRenderToMask(VGPath path,
+                    VGbitfield paintModes,
+                    VGMaskOperation operation)
+{
+   struct vg_context *ctx = vg_current_context();
+
+   if (path == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   if (!paintModes || (paintModes&(~(VG_STROKE_PATH|VG_FILL_PATH)))) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+   if (operation < VG_CLEAR_MASK ||
+       operation > VG_SUBTRACT_MASK) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+   if (!vg_object_is_valid((void*)path, VG_OBJECT_PATH)) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+#if DISABLE_1_1_MASKING
+   return;
+#endif
+
+   vg_validate_state(ctx);
+
+   mask_render_to((struct path *)path, paintModes, operation);
+}
+
+VGMaskLayer vgCreateMaskLayer(VGint width, VGint height)
+{
+   struct vg_context *ctx = vg_current_context();
+
+   if (width <= 0 || height <= 0 ||
+       width > vgGeti(VG_MAX_IMAGE_WIDTH) ||
+       height > vgGeti(VG_MAX_IMAGE_HEIGHT)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+
+   return (VGMaskLayer)mask_layer_create(width, height);
+}
+
+void vgDestroyMaskLayer(VGMaskLayer maskLayer)
+{
+   struct vg_mask_layer *mask = 0;
+   struct vg_context *ctx = vg_current_context();
+
+   if (maskLayer == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   if (!vg_object_is_valid((void*)maskLayer, VG_OBJECT_MASK)) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   mask = (struct vg_mask_layer *)maskLayer;
+   mask_layer_destroy(mask);
+}
+
+void vgFillMaskLayer(VGMaskLayer maskLayer,
+                     VGint x, VGint y,
+                     VGint width, VGint height,
+                     VGfloat value)
+{
+   struct vg_mask_layer *mask = 0;
+   struct vg_context *ctx = vg_current_context();
+
+   if (maskLayer == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   if (value < 0 || value > 1) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   if (width <= 0 || height <= 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+   if (x < 0 || y < 0 || (x + width) < 0 || (y + height) < 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   if (!vg_object_is_valid((void*)maskLayer, VG_OBJECT_MASK)) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   mask = (struct vg_mask_layer*)maskLayer;
+
+   if (x + width > mask_layer_width(mask) ||
+       y + height > mask_layer_height(mask)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+#if DISABLE_1_1_MASKING
+   return;
+#endif
+   mask_layer_fill(mask, x, y, width, height, value);
+}
+
+void vgCopyMask(VGMaskLayer maskLayer,
+                VGint sx, VGint sy,
+                VGint dx, VGint dy,
+                VGint width, VGint height)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct vg_mask_layer *mask = 0;
+
+   if (maskLayer == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   if (width <= 0 || height <= 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+   if (!vg_object_is_valid((void*)maskLayer, VG_OBJECT_MASK)) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+#if DISABLE_1_1_MASKING
+   return;
+#endif
+
+   mask = (struct vg_mask_layer*)maskLayer;
+   mask_copy(mask, sx, sy, dx, dy, width, height);
+}
+
+#endif
diff --git a/src/gallium/state_trackers/vega/api_misc.c b/src/gallium/state_trackers/vega/api_misc.c
new file mode 100644 (file)
index 0000000..78ba0bc
--- /dev/null
@@ -0,0 +1,83 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#include "VG/openvg.h"
+
+#include "vg_context.h"
+
+/* Hardware Queries */
+VGHardwareQueryResult vgHardwareQuery(VGHardwareQueryType key,
+                                      VGint setting)
+{
+   struct vg_context *ctx = vg_current_context();
+
+   if (key < VG_IMAGE_FORMAT_QUERY ||
+       key > VG_PATH_DATATYPE_QUERY) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return VG_HARDWARE_UNACCELERATED;
+   }
+
+   if (key == VG_IMAGE_FORMAT_QUERY) {
+      if (setting < VG_sRGBX_8888 ||
+          setting > VG_lABGR_8888_PRE) {
+         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+         return VG_HARDWARE_UNACCELERATED;
+      }
+   } else if (key == VG_PATH_DATATYPE_QUERY) {
+      if (setting < VG_PATH_DATATYPE_S_8 ||
+          setting > VG_PATH_DATATYPE_F) {
+         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+         return VG_HARDWARE_UNACCELERATED;
+      }
+   }
+   /* we're supposed to accelerate everything */
+   return VG_HARDWARE_ACCELERATED;
+}
+
+/* Renderer and Extension Information */
+const VGubyte *vgGetString(VGStringID name)
+{
+   struct vg_context *ctx = vg_current_context();
+   static const VGubyte *vendor = (VGubyte *)"Tungsten Graphics, Inc";
+   static const VGubyte *renderer = (VGubyte *)"Vega OpenVG 1.0";
+   static const VGubyte *version = (VGubyte *)"1.0";
+
+   if (!ctx)
+      return NULL;
+
+   switch(name) {
+   case VG_VENDOR:
+      return vendor;
+   case VG_RENDERER:
+      return renderer;
+   case VG_VERSION:
+      return version;
+   case VG_EXTENSIONS:
+      return NULL;
+   default:
+      return NULL;
+   }
+}
diff --git a/src/gallium/state_trackers/vega/api_paint.c b/src/gallium/state_trackers/vega/api_paint.c
new file mode 100644 (file)
index 0000000..dd3ac5b
--- /dev/null
@@ -0,0 +1,166 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#include "VG/openvg.h"
+
+#include "vg_context.h"
+#include "paint.h"
+#include "image.h"
+
+VGPaint vgCreatePaint(void)
+{
+   return (VGPaint) paint_create(vg_current_context());
+}
+
+void vgDestroyPaint(VGPaint p)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct vg_paint *paint;
+
+   if (p == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   paint = (struct vg_paint *)p;
+   paint_destroy(paint);
+}
+
+void vgSetPaint(VGPaint paint, VGbitfield paintModes)
+{
+   struct vg_context *ctx = vg_current_context();
+
+   if (paint == VG_INVALID_HANDLE) {
+      /* restore the default */
+      paint = (VGPaint)ctx->default_paint;
+   } else if (!vg_object_is_valid((void*)paint, VG_OBJECT_PAINT)) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   if (!(paintModes & ((VG_FILL_PATH|VG_STROKE_PATH)))) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   if (paintModes & VG_FILL_PATH) {
+      ctx->state.vg.fill_paint = (struct vg_paint *)paint;
+   }
+   if (paintModes & VG_STROKE_PATH) {
+      ctx->state.vg.stroke_paint = (struct vg_paint *)paint;
+   }
+}
+
+VGPaint vgGetPaint(VGPaintMode paintMode)
+{
+   struct vg_context *ctx = vg_current_context();
+   VGPaint paint = VG_INVALID_HANDLE;
+
+   if (paintMode < VG_STROKE_PATH || paintMode > VG_FILL_PATH) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+
+   if (paintMode == VG_FILL_PATH)
+      paint = (VGPaint)ctx->state.vg.fill_paint;
+   else if (paintMode == VG_STROKE_PATH)
+      paint = (VGPaint)ctx->state.vg.stroke_paint;
+
+   if (paint == (VGPaint)ctx->default_paint)
+      paint = VG_INVALID_HANDLE;
+
+   return paint;
+}
+
+void vgSetColor(VGPaint paint, VGuint rgba)
+{
+   struct vg_context *ctx = vg_current_context();
+
+   if (paint == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   if (!vg_object_is_valid((void*)paint, VG_OBJECT_PAINT)) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   {
+      struct vg_paint *p = (struct vg_paint *)paint;
+      paint_set_colori(p, rgba);
+   }
+}
+
+VGuint vgGetColor(VGPaint paint)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct vg_paint *p;
+   VGuint rgba = 0;
+
+   if (paint == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return rgba;
+   }
+
+   if (!vg_object_is_valid((void*)paint, VG_OBJECT_PAINT)) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return rgba;
+   }
+   p = (struct vg_paint *)paint;
+
+   return paint_colori(p);
+}
+
+void vgPaintPattern(VGPaint paint, VGImage pattern)
+{
+   struct vg_context *ctx = vg_current_context();
+
+   if (paint == VG_INVALID_HANDLE ||
+       !vg_context_is_object_valid(ctx, VG_OBJECT_PAINT, (void *)paint)) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   if (pattern == VG_INVALID_HANDLE) {
+      paint_set_type((struct vg_paint*)paint, VG_PAINT_TYPE_COLOR);
+      return;
+   }
+
+   if (!vg_context_is_object_valid(ctx, VG_OBJECT_IMAGE, (void *)pattern)) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+
+   if (!vg_object_is_valid((void*)paint, VG_OBJECT_PAINT) ||
+       !vg_object_is_valid((void*)pattern, VG_OBJECT_IMAGE)) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   paint_set_pattern((struct vg_paint*)paint,
+                     (struct vg_image*)pattern);
+}
+
diff --git a/src/gallium/state_trackers/vega/api_params.c b/src/gallium/state_trackers/vega/api_params.c
new file mode 100644 (file)
index 0000000..db77fd9
--- /dev/null
@@ -0,0 +1,1673 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#include "VG/openvg.h"
+
+#include "vg_context.h"
+#include "paint.h"
+#include "path.h"
+#include "image.h"
+#include "matrix.h"
+#include "api_consts.h"
+
+#include "pipe/p_compiler.h"
+#include "util/u_pointer.h"
+#include "util/u_math.h"
+
+#include <math.h>
+
+static INLINE struct vg_state *current_state()
+{
+   struct vg_context *ctx = vg_current_context();
+   if (!ctx)
+      return 0;
+   else
+      return &ctx->state.vg;
+}
+
+static INLINE VGboolean count_in_bounds(VGParamType type, VGint count)
+{
+   if (count < 0)
+      return VG_FALSE;
+
+   if (type == VG_SCISSOR_RECTS)
+      return (!(count % 4) && (count >= 0 || count <= VEGA_MAX_SCISSOR_RECTS * 4));
+   else if (type == VG_STROKE_DASH_PATTERN) {
+      return count <= VEGA_MAX_DASH_COUNT;
+   } else {
+      VGint real_count = vgGetVectorSize(type);
+      return count == real_count;
+   }
+}
+
+void vgSetf (VGParamType type, VGfloat value)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct vg_state *state = current_state();
+   VGErrorCode error = VG_NO_ERROR;
+
+   switch(type) {
+   case VG_MATRIX_MODE:
+   case VG_FILL_RULE:
+   case VG_IMAGE_QUALITY:
+   case VG_RENDERING_QUALITY:
+   case VG_BLEND_MODE:
+   case VG_IMAGE_MODE:
+#ifdef OPENVG_VERSION_1_1
+   case VG_COLOR_TRANSFORM:
+#endif
+   case VG_STROKE_CAP_STYLE:
+   case VG_STROKE_JOIN_STYLE:
+   case VG_STROKE_DASH_PHASE_RESET:
+   case VG_MASKING:
+   case VG_SCISSORING:
+   case VG_PIXEL_LAYOUT:
+   case VG_SCREEN_LAYOUT:
+   case VG_FILTER_FORMAT_LINEAR:
+   case VG_FILTER_FORMAT_PREMULTIPLIED:
+   case VG_FILTER_CHANNEL_MASK:
+
+   case VG_MAX_SCISSOR_RECTS:
+   case VG_MAX_DASH_COUNT:
+   case VG_MAX_KERNEL_SIZE:
+   case VG_MAX_SEPARABLE_KERNEL_SIZE:
+   case VG_MAX_COLOR_RAMP_STOPS:
+   case VG_MAX_IMAGE_WIDTH:
+   case VG_MAX_IMAGE_HEIGHT:
+   case VG_MAX_IMAGE_PIXELS:
+   case VG_MAX_IMAGE_BYTES:
+   case VG_MAX_GAUSSIAN_STD_DEVIATION:
+   case VG_MAX_FLOAT:
+      vgSeti(type, floor(value));
+      return;
+      break;
+   case VG_STROKE_LINE_WIDTH:
+      state->stroke.line_width.f = value;
+      state->stroke.line_width.i = float_to_int_floor(*((VGuint*)(&value)));
+      break;
+   case VG_STROKE_MITER_LIMIT:
+      state->stroke.miter_limit.f = value;
+      state->stroke.miter_limit.i = float_to_int_floor(*((VGuint*)(&value)));
+      break;
+   case VG_STROKE_DASH_PHASE:
+      state->stroke.dash_phase.f = value;
+      state->stroke.dash_phase.i = float_to_int_floor(*((VGuint*)(&value)));
+      break;
+   default:
+      error = VG_ILLEGAL_ARGUMENT_ERROR;
+      break;
+   }
+   vg_set_error(ctx, error);
+}
+
+void vgSeti (VGParamType type, VGint value)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct vg_state *state = current_state();
+   VGErrorCode error = VG_NO_ERROR;
+
+   switch(type) {
+   case VG_MATRIX_MODE:
+      if (value < VG_MATRIX_PATH_USER_TO_SURFACE ||
+#ifdef OPENVG_VERSION_1_1
+          value > VG_MATRIX_GLYPH_USER_TO_SURFACE)
+#else
+          value > VG_MATRIX_STROKE_PAINT_TO_USER)
+#endif
+         error = VG_ILLEGAL_ARGUMENT_ERROR;
+      else
+         state->matrix_mode = value;
+      break;
+   case VG_FILL_RULE:
+      if (value < VG_EVEN_ODD ||
+          value > VG_NON_ZERO)
+         error = VG_ILLEGAL_ARGUMENT_ERROR;
+      else
+         state->fill_rule = value;
+      break;
+   case VG_IMAGE_QUALITY:
+      state->image_quality = value;
+      break;
+   case VG_RENDERING_QUALITY:
+      if (value < VG_RENDERING_QUALITY_NONANTIALIASED ||
+          value > VG_RENDERING_QUALITY_BETTER)
+         error = VG_ILLEGAL_ARGUMENT_ERROR;
+      else
+         state->rendering_quality = value;
+      break;
+   case VG_BLEND_MODE:
+      if (value < VG_BLEND_SRC ||
+          value > VG_BLEND_ADDITIVE)
+         error = VG_ILLEGAL_ARGUMENT_ERROR;
+      else {
+         ctx->state.dirty |= BLEND_DIRTY;
+         state->blend_mode = value;
+      }
+      break;
+   case VG_IMAGE_MODE:
+      if (value < VG_DRAW_IMAGE_NORMAL ||
+          value > VG_DRAW_IMAGE_STENCIL)
+         error = VG_ILLEGAL_ARGUMENT_ERROR;
+      else
+         state->image_mode = value;
+#ifdef OPENVG_VERSION_1_1
+   case VG_COLOR_TRANSFORM:
+      state->color_transform = value;
+#endif
+      break;
+   case VG_STROKE_LINE_WIDTH:
+      state->stroke.line_width.f = value;
+      state->stroke.line_width.i = value;
+      break;
+   case VG_STROKE_CAP_STYLE:
+      if (value < VG_CAP_BUTT ||
+          value > VG_CAP_SQUARE)
+         error = VG_ILLEGAL_ARGUMENT_ERROR;
+      else
+         state->stroke.cap_style = value;
+      break;
+   case VG_STROKE_JOIN_STYLE:
+      if (value < VG_JOIN_MITER ||
+          value > VG_JOIN_BEVEL)
+         error = VG_ILLEGAL_ARGUMENT_ERROR;
+      else
+         state->stroke.join_style = value;
+      break;
+   case VG_STROKE_MITER_LIMIT:
+      state->stroke.miter_limit.f = value;
+      state->stroke.miter_limit.i = value;
+      break;
+   case VG_STROKE_DASH_PHASE:
+      state->stroke.dash_phase.f = value;
+      state->stroke.dash_phase.i = value;
+      break;
+   case VG_STROKE_DASH_PHASE_RESET:
+      state->stroke.dash_phase_reset = value;
+      break;
+   case VG_MASKING:
+      state->masking = value;
+      break;
+   case VG_SCISSORING:
+      state->scissoring = value;
+      ctx->state.dirty |= DEPTH_STENCIL_DIRTY;
+      break;
+   case VG_PIXEL_LAYOUT:
+      if (value < VG_PIXEL_LAYOUT_UNKNOWN ||
+          value > VG_PIXEL_LAYOUT_BGR_HORIZONTAL)
+         error = VG_ILLEGAL_ARGUMENT_ERROR;
+      else
+         state->pixel_layout = value;
+      break;
+   case VG_SCREEN_LAYOUT:
+      /* read only ignore */
+      break;
+   case VG_FILTER_FORMAT_LINEAR:
+      state->filter_format_linear = value;
+      break;
+   case VG_FILTER_FORMAT_PREMULTIPLIED:
+      state->filter_format_premultiplied = value;
+      break;
+   case VG_FILTER_CHANNEL_MASK:
+      state->filter_channel_mask = value;
+      break;
+
+   case VG_MAX_SCISSOR_RECTS:
+   case VG_MAX_DASH_COUNT:
+   case VG_MAX_KERNEL_SIZE:
+   case VG_MAX_SEPARABLE_KERNEL_SIZE:
+   case VG_MAX_COLOR_RAMP_STOPS:
+   case VG_MAX_IMAGE_WIDTH:
+   case VG_MAX_IMAGE_HEIGHT:
+   case VG_MAX_IMAGE_PIXELS:
+   case VG_MAX_IMAGE_BYTES:
+   case VG_MAX_GAUSSIAN_STD_DEVIATION:
+   case VG_MAX_FLOAT:
+      /* read only ignore */
+      break;
+   default:
+      error = VG_ILLEGAL_ARGUMENT_ERROR;
+      break;
+   }
+   vg_set_error(ctx, error);
+}
+
+void vgSetfv(VGParamType type, VGint count,
+             const VGfloat * values)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct vg_state *state = current_state();
+   VGErrorCode error = VG_NO_ERROR;
+
+   if ((count && !values) || !count_in_bounds(type, count) || !is_aligned(values)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   switch(type) {
+   case VG_MATRIX_MODE:
+   case VG_FILL_RULE:
+   case VG_IMAGE_QUALITY:
+   case VG_RENDERING_QUALITY:
+   case VG_BLEND_MODE:
+   case VG_IMAGE_MODE:
+#ifdef OPENVG_VERSION_1_1
+   case VG_COLOR_TRANSFORM:
+#endif
+   case VG_STROKE_CAP_STYLE:
+   case VG_STROKE_JOIN_STYLE:
+   case VG_STROKE_DASH_PHASE_RESET:
+   case VG_MASKING:
+   case VG_SCISSORING:
+   case VG_PIXEL_LAYOUT:
+   case VG_SCREEN_LAYOUT:
+   case VG_FILTER_FORMAT_LINEAR:
+   case VG_FILTER_FORMAT_PREMULTIPLIED:
+   case VG_FILTER_CHANNEL_MASK:
+      vgSeti(type, floor(values[0]));
+      return;
+      break;
+   case VG_SCISSOR_RECTS: {
+      VGint i;
+      VGuint *x = (VGuint*)values;
+      for (i = 0; i < count; ++i) {
+         state->scissor_rects[i].f =  values[i];
+         state->scissor_rects[i].i =  float_to_int_floor(x[i]);
+      }
+      state->scissor_rects_num = count / 4;
+      ctx->state.dirty |= DEPTH_STENCIL_DIRTY;
+   }
+      break;
+#ifdef OPENVG_VERSION_1_1
+   case VG_COLOR_TRANSFORM_VALUES: {
+      VGint i;
+      for (i = 0; i < count; ++i) {
+         state->color_transform_values[i] =  values[i];
+      }
+   }
+      break;
+#endif
+   case VG_STROKE_LINE_WIDTH:
+      state->stroke.line_width.f = values[0];
+      state->stroke.line_width.i = float_to_int_floor(*((VGuint*)(values)));
+      break;
+   case VG_STROKE_MITER_LIMIT:
+      state->stroke.miter_limit.f = values[0];
+      state->stroke.miter_limit.i = float_to_int_floor(*((VGuint*)(values)));
+      break;
+   case VG_STROKE_DASH_PATTERN: {
+      int i;
+      for (i = 0; i < count; ++i) {
+         state->stroke.dash_pattern[i].f = values[i];
+         state->stroke.dash_pattern[i].i =
+            float_to_int_floor(*((VGuint*)(values + i)));
+      }
+      state->stroke.dash_pattern_num = count;
+   }
+      break;
+   case VG_STROKE_DASH_PHASE:
+      state->stroke.dash_phase.f = values[0];
+      state->stroke.dash_phase.i = float_to_int_floor(*((VGuint*)(values)));
+      break;
+   case VG_TILE_FILL_COLOR:
+      state->tile_fill_color[0] = values[0];
+      state->tile_fill_color[1] = values[1];
+      state->tile_fill_color[2] = values[2];
+      state->tile_fill_color[3] = values[3];
+
+      state->tile_fill_colori[0] = float_to_int_floor(*((VGuint*)(values + 0)));
+      state->tile_fill_colori[1] = float_to_int_floor(*((VGuint*)(values + 1)));
+      state->tile_fill_colori[2] = float_to_int_floor(*((VGuint*)(values + 2)));
+      state->tile_fill_colori[3] = float_to_int_floor(*((VGuint*)(values + 3)));
+      break;
+   case VG_CLEAR_COLOR:
+      state->clear_color[0] = values[0];
+      state->clear_color[1] = values[1];
+      state->clear_color[2] = values[2];
+      state->clear_color[3] = values[3];
+
+      state->clear_colori[0] = float_to_int_floor(*((VGuint*)(values + 0)));
+      state->clear_colori[1] = float_to_int_floor(*((VGuint*)(values + 1)));
+      state->clear_colori[2] = float_to_int_floor(*((VGuint*)(values + 2)));
+      state->clear_colori[3] = float_to_int_floor(*((VGuint*)(values + 3)));
+      break;
+#ifdef OPENVG_VERSION_1_1
+   case VG_GLYPH_ORIGIN:
+      state->glyph_origin[0].f = values[0];
+      state->glyph_origin[1].f = values[1];
+
+      state->glyph_origin[0].i = float_to_int_floor(*((VGuint*)(values + 0)));
+      state->glyph_origin[1].i = float_to_int_floor(*((VGuint*)(values + 1)));
+      break;
+#endif
+
+   case VG_MAX_SCISSOR_RECTS:
+   case VG_MAX_DASH_COUNT:
+   case VG_MAX_KERNEL_SIZE:
+   case VG_MAX_SEPARABLE_KERNEL_SIZE:
+   case VG_MAX_COLOR_RAMP_STOPS:
+   case VG_MAX_IMAGE_WIDTH:
+   case VG_MAX_IMAGE_HEIGHT:
+   case VG_MAX_IMAGE_PIXELS:
+   case VG_MAX_IMAGE_BYTES:
+   case VG_MAX_GAUSSIAN_STD_DEVIATION:
+   case VG_MAX_FLOAT:
+      break;
+   default:
+      error = VG_ILLEGAL_ARGUMENT_ERROR;
+      break;
+   }
+   vg_set_error(ctx, error);
+}
+
+void vgSetiv(VGParamType type, VGint count,
+             const VGint * values)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct vg_state *state = current_state();
+
+   if ((count && !values) || !count_in_bounds(type, count) || !is_aligned(values)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   switch(type) {
+   case VG_MATRIX_MODE:
+   case VG_FILL_RULE:
+   case VG_IMAGE_QUALITY:
+   case VG_RENDERING_QUALITY:
+   case VG_BLEND_MODE:
+   case VG_IMAGE_MODE:
+#ifdef OPENVG_VERSION_1_1
+   case VG_COLOR_TRANSFORM:
+#endif
+   case VG_STROKE_CAP_STYLE:
+   case VG_STROKE_JOIN_STYLE:
+   case VG_STROKE_DASH_PHASE_RESET:
+   case VG_MASKING:
+   case VG_SCISSORING:
+   case VG_PIXEL_LAYOUT:
+   case VG_SCREEN_LAYOUT:
+   case VG_FILTER_FORMAT_LINEAR:
+   case VG_FILTER_FORMAT_PREMULTIPLIED:
+   case VG_FILTER_CHANNEL_MASK:
+      vgSeti(type, values[0]);
+      return;
+      break;
+   case VG_SCISSOR_RECTS: {
+      VGint i;
+      for (i = 0; i < count; ++i) {
+         state->scissor_rects[i].i =  values[i];
+         state->scissor_rects[i].f =  values[i];
+      }
+      state->scissor_rects_num = count / 4;
+      ctx->state.dirty |= DEPTH_STENCIL_DIRTY;
+   }
+      break;
+#ifdef OPENVG_VERSION_1_1
+   case VG_COLOR_TRANSFORM_VALUES: {
+      VGint i;
+      for (i = 0; i < count; ++i) {
+         state->color_transform_values[i] =  values[i];
+      }
+   }
+      break;
+#endif
+   case VG_STROKE_LINE_WIDTH:
+      state->stroke.line_width.f = values[0];
+      state->stroke.line_width.i = values[0];
+      break;
+   case VG_STROKE_MITER_LIMIT:
+      state->stroke.miter_limit.f = values[0];
+      state->stroke.miter_limit.i = values[0];
+      break;
+   case VG_STROKE_DASH_PATTERN: {
+      int i;
+      for (i = 0; i < count; ++i) {
+         state->stroke.dash_pattern[i].f = values[i];
+         state->stroke.dash_pattern[i].i = values[i];
+      }
+      state->stroke.dash_pattern_num = count;
+   }
+      break;
+   case VG_STROKE_DASH_PHASE:
+      state->stroke.dash_phase.f = values[0];
+      state->stroke.dash_phase.i = values[0];
+      break;
+   case VG_TILE_FILL_COLOR:
+      state->tile_fill_color[0] = values[0];
+      state->tile_fill_color[1] = values[1];
+      state->tile_fill_color[2] = values[2];
+      state->tile_fill_color[3] = values[3];
+
+      state->tile_fill_colori[0] = values[0];
+      state->tile_fill_colori[1] = values[1];
+      state->tile_fill_colori[2] = values[2];
+      state->tile_fill_colori[3] = values[3];
+      break;
+   case VG_CLEAR_COLOR:
+      state->clear_color[0] = values[0];
+      state->clear_color[1] = values[1];
+      state->clear_color[2] = values[2];
+      state->clear_color[3] = values[3];
+
+      state->clear_colori[0] = values[0];
+      state->clear_colori[1] = values[1];
+      state->clear_colori[2] = values[2];
+      state->clear_colori[3] = values[3];
+      break;
+#ifdef OPENVG_VERSION_1_1
+   case VG_GLYPH_ORIGIN:
+      state->glyph_origin[0].f = values[0];
+      state->glyph_origin[1].f = values[1];
+      state->glyph_origin[0].i = values[0];
+      state->glyph_origin[1].i = values[1];
+      break;
+#endif
+
+   case VG_MAX_SCISSOR_RECTS:
+   case VG_MAX_DASH_COUNT:
+   case VG_MAX_KERNEL_SIZE:
+   case VG_MAX_SEPARABLE_KERNEL_SIZE:
+   case VG_MAX_COLOR_RAMP_STOPS:
+   case VG_MAX_IMAGE_WIDTH:
+   case VG_MAX_IMAGE_HEIGHT:
+   case VG_MAX_IMAGE_PIXELS:
+   case VG_MAX_IMAGE_BYTES:
+   case VG_MAX_GAUSSIAN_STD_DEVIATION:
+   case VG_MAX_FLOAT:
+      break;
+
+   default:
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      break;
+   }
+}
+
+VGfloat vgGetf(VGParamType type)
+{
+   struct vg_context *ctx = vg_current_context();
+   const struct vg_state *state = current_state();
+   VGErrorCode error = VG_NO_ERROR;
+   VGfloat value = 0.0f;
+
+   switch(type) {
+   case VG_MATRIX_MODE:
+   case VG_FILL_RULE:
+   case VG_IMAGE_QUALITY:
+   case VG_RENDERING_QUALITY:
+   case VG_BLEND_MODE:
+   case VG_IMAGE_MODE:
+#ifdef OPENVG_VERSION_1_1
+   case VG_COLOR_TRANSFORM:
+#endif
+   case VG_STROKE_CAP_STYLE:
+   case VG_STROKE_JOIN_STYLE:
+   case VG_STROKE_DASH_PHASE_RESET:
+   case VG_MASKING:
+   case VG_SCISSORING:
+   case VG_PIXEL_LAYOUT:
+   case VG_SCREEN_LAYOUT:
+   case VG_FILTER_FORMAT_LINEAR:
+   case VG_FILTER_FORMAT_PREMULTIPLIED:
+   case VG_FILTER_CHANNEL_MASK:
+      return vgGeti(type);
+      break;
+   case VG_STROKE_LINE_WIDTH:
+      value = state->stroke.line_width.f;
+      break;
+   case VG_STROKE_MITER_LIMIT:
+      value = state->stroke.miter_limit.f;
+      break;
+   case VG_STROKE_DASH_PHASE:
+      value = state->stroke.dash_phase.f;
+      break;
+
+   case VG_MAX_SCISSOR_RECTS:
+   case VG_MAX_DASH_COUNT:
+   case VG_MAX_KERNEL_SIZE:
+   case VG_MAX_SEPARABLE_KERNEL_SIZE:
+   case VG_MAX_COLOR_RAMP_STOPS:
+   case VG_MAX_IMAGE_WIDTH:
+   case VG_MAX_IMAGE_HEIGHT:
+   case VG_MAX_IMAGE_PIXELS:
+   case VG_MAX_IMAGE_BYTES:
+   case VG_MAX_GAUSSIAN_STD_DEVIATION:
+      return vgGeti(type);
+      break;
+   case VG_MAX_FLOAT:
+      value = 1e+10;/*must be at least 1e+10*/
+      break;
+   default:
+      error = VG_ILLEGAL_ARGUMENT_ERROR;
+      break;
+   }
+   vg_set_error(ctx, error);
+   return value;
+}
+
+VGint vgGeti(VGParamType type)
+{
+   const struct vg_state *state = current_state();
+   struct vg_context *ctx = vg_current_context();
+   VGErrorCode error = VG_NO_ERROR;
+   VGint value = 0;
+
+   switch(type) {
+   case VG_MATRIX_MODE:
+      value = state->matrix_mode;
+      break;
+   case VG_FILL_RULE:
+      value = state->fill_rule;
+      break;
+   case VG_IMAGE_QUALITY:
+      value = state->image_quality;
+      break;
+   case VG_RENDERING_QUALITY:
+      value = state->rendering_quality;
+      break;
+   case VG_BLEND_MODE:
+      value = state->blend_mode;
+      break;
+   case VG_IMAGE_MODE:
+      value = state->image_mode;
+      break;
+#ifdef OPENVG_VERSION_1_1
+   case VG_COLOR_TRANSFORM:
+      value = state->color_transform;
+      break;
+#endif
+   case VG_STROKE_LINE_WIDTH:
+      value = state->stroke.line_width.i;
+      break;
+   case VG_STROKE_CAP_STYLE:
+      value = state->stroke.cap_style;
+      break;
+   case VG_STROKE_JOIN_STYLE:
+      value = state->stroke.join_style;
+      break;
+   case VG_STROKE_MITER_LIMIT:
+      value = state->stroke.miter_limit.i;
+      break;
+   case VG_STROKE_DASH_PHASE:
+      value = state->stroke.dash_phase.i;
+      break;
+   case VG_STROKE_DASH_PHASE_RESET:
+      value = state->stroke.dash_phase_reset;
+      break;
+   case VG_MASKING:
+      value = state->masking;
+      break;
+   case VG_SCISSORING:
+      value = state->scissoring;
+      break;
+   case VG_PIXEL_LAYOUT:
+      value = state->pixel_layout;
+      break;
+   case VG_SCREEN_LAYOUT:
+      value = state->screen_layout;
+      break;
+   case VG_FILTER_FORMAT_LINEAR:
+      value = state->filter_format_linear;
+      break;
+   case VG_FILTER_FORMAT_PREMULTIPLIED:
+      value = state->filter_format_premultiplied;
+      break;
+   case VG_FILTER_CHANNEL_MASK:
+      value = state->filter_channel_mask;
+      break;
+
+   case VG_MAX_SCISSOR_RECTS:
+      value = 32; /*must be at least 32*/
+      break;
+   case VG_MAX_DASH_COUNT:
+      value = 16; /*must be at least 16*/
+      break;
+   case VG_MAX_KERNEL_SIZE:
+      value = 7; /*must be at least 7*/
+      break;
+   case VG_MAX_SEPARABLE_KERNEL_SIZE:
+      value = 15; /*must be at least 15*/
+      break;
+   case VG_MAX_COLOR_RAMP_STOPS:
+      value = 256; /*must be at least 32*/
+      break;
+   case VG_MAX_IMAGE_WIDTH:
+      value = 2048;
+      break;
+   case VG_MAX_IMAGE_HEIGHT:
+      value = 2048;
+      break;
+   case VG_MAX_IMAGE_PIXELS:
+      value = 2048*2048;
+      break;
+   case VG_MAX_IMAGE_BYTES:
+      value = 2048*2048 * 4;
+      break;
+   case VG_MAX_GAUSSIAN_STD_DEVIATION:
+      value = 128; /*must be at least 128*/
+      break;
+
+   case VG_MAX_FLOAT: {
+      VGfloat val = vgGetf(type);
+      value = float_to_int_floor(*((VGuint*)&val));
+   }
+      break;
+   default:
+      error = VG_ILLEGAL_ARGUMENT_ERROR;
+      break;
+   }
+   vg_set_error(ctx, error);
+   return value;
+}
+
+VGint vgGetVectorSize(VGParamType type)
+{
+   struct vg_context *ctx = vg_current_context();
+   const struct vg_state *state = current_state();
+   switch(type) {
+   case VG_MATRIX_MODE:
+   case VG_FILL_RULE:
+   case VG_IMAGE_QUALITY:
+   case VG_RENDERING_QUALITY:
+   case VG_BLEND_MODE:
+   case VG_IMAGE_MODE:
+      return 1;
+   case VG_SCISSOR_RECTS:
+      return state->scissor_rects_num * 4;
+#ifdef OPENVG_VERSION_1_1
+   case VG_COLOR_TRANSFORM:
+      return 1;
+   case VG_COLOR_TRANSFORM_VALUES:
+      return 8;
+#endif
+   case VG_STROKE_LINE_WIDTH:
+   case VG_STROKE_CAP_STYLE:
+   case VG_STROKE_JOIN_STYLE:
+   case VG_STROKE_MITER_LIMIT:
+      return 1;
+   case VG_STROKE_DASH_PATTERN:
+      return state->stroke.dash_pattern_num;
+   case VG_STROKE_DASH_PHASE:
+      return 1;
+   case VG_STROKE_DASH_PHASE_RESET:
+      return 1;
+   case VG_TILE_FILL_COLOR:
+      return 4;
+   case VG_CLEAR_COLOR:
+      return 4;
+#ifdef OPENVG_VERSION_1_1
+   case VG_GLYPH_ORIGIN:
+      return 2;
+#endif
+   case VG_MASKING:
+      return 1;
+   case VG_SCISSORING:
+      return 1;
+   case VG_PIXEL_LAYOUT:
+      return 1;
+   case VG_SCREEN_LAYOUT:
+      return 1;
+   case VG_FILTER_FORMAT_LINEAR:
+      return 1;
+   case VG_FILTER_FORMAT_PREMULTIPLIED:
+      return 1;
+   case VG_FILTER_CHANNEL_MASK:
+      return 1;
+
+   case VG_MAX_COLOR_RAMP_STOPS:
+      return 1;
+   case VG_MAX_SCISSOR_RECTS:
+   case VG_MAX_DASH_COUNT:
+   case VG_MAX_KERNEL_SIZE:
+   case VG_MAX_SEPARABLE_KERNEL_SIZE:
+   case VG_MAX_IMAGE_WIDTH:
+   case VG_MAX_IMAGE_HEIGHT:
+   case VG_MAX_IMAGE_PIXELS:
+   case VG_MAX_IMAGE_BYTES:
+   case VG_MAX_FLOAT:
+   case VG_MAX_GAUSSIAN_STD_DEVIATION:
+      return 1;
+   default:
+      if (ctx)
+         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return 0;
+   }
+}
+
+void vgGetfv(VGParamType type, VGint count,
+             VGfloat * values)
+{
+   const struct vg_state *state = current_state();
+   struct vg_context *ctx = vg_current_context();
+   VGint real_count = vgGetVectorSize(type);
+
+   if (!values || count <= 0 || count > real_count || !is_aligned(values)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   switch(type) {
+   case VG_MATRIX_MODE:
+   case VG_FILL_RULE:
+   case VG_IMAGE_QUALITY:
+   case VG_RENDERING_QUALITY:
+   case VG_BLEND_MODE:
+   case VG_IMAGE_MODE:
+#ifdef OPENVG_VERSION_1_1
+   case VG_COLOR_TRANSFORM:
+#endif
+   case VG_STROKE_CAP_STYLE:
+   case VG_STROKE_JOIN_STYLE:
+   case VG_STROKE_DASH_PHASE_RESET:
+   case VG_MASKING:
+   case VG_SCISSORING:
+   case VG_PIXEL_LAYOUT:
+   case VG_SCREEN_LAYOUT:
+   case VG_FILTER_FORMAT_LINEAR:
+   case VG_FILTER_FORMAT_PREMULTIPLIED:
+   case VG_FILTER_CHANNEL_MASK:
+   case VG_MAX_SCISSOR_RECTS:
+   case VG_MAX_DASH_COUNT:
+   case VG_MAX_KERNEL_SIZE:
+   case VG_MAX_SEPARABLE_KERNEL_SIZE:
+   case VG_MAX_COLOR_RAMP_STOPS:
+   case VG_MAX_IMAGE_WIDTH:
+   case VG_MAX_IMAGE_HEIGHT:
+   case VG_MAX_IMAGE_PIXELS:
+   case VG_MAX_IMAGE_BYTES:
+   case VG_MAX_GAUSSIAN_STD_DEVIATION:
+      values[0] = vgGeti(type);
+      break;
+   case VG_MAX_FLOAT:
+      values[0] = vgGetf(type);
+      break;
+   case VG_SCISSOR_RECTS: {
+      VGint i;
+      for (i = 0; i < count; ++i) {
+         values[i] = state->scissor_rects[i].f;
+      }
+   }
+      break;
+#ifdef OPENVG_VERSION_1_1
+   case VG_COLOR_TRANSFORM_VALUES: {
+      memcpy(values, state->color_transform_values,
+             sizeof(VGfloat) * count);
+   }
+      break;
+#endif
+   case VG_STROKE_LINE_WIDTH:
+      values[0] = state->stroke.line_width.f;
+      break;
+   case VG_STROKE_MITER_LIMIT:
+      values[0] = state->stroke.miter_limit.f;
+      break;
+   case VG_STROKE_DASH_PATTERN: {
+      VGint i;
+      for (i = 0; i < count; ++i) {
+         values[i] = state->stroke.dash_pattern[i].f;
+      }
+   }
+      break;
+   case VG_STROKE_DASH_PHASE:
+      values[0] = state->stroke.dash_phase.f;
+      break;
+   case VG_TILE_FILL_COLOR:
+      values[0] = state->tile_fill_color[0];
+      values[1] = state->tile_fill_color[1];
+      values[2] = state->tile_fill_color[2];
+      values[3] = state->tile_fill_color[3];
+      break;
+   case VG_CLEAR_COLOR:
+      values[0] = state->clear_color[0];
+      values[1] = state->clear_color[1];
+      values[2] = state->clear_color[2];
+      values[3] = state->clear_color[3];
+      break;
+#ifdef OPENVG_VERSION_1_1
+   case VG_GLYPH_ORIGIN:
+      values[0] = state->glyph_origin[0].f;
+      values[1] = state->glyph_origin[1].f;
+      break;
+#endif
+   default:
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      break;
+   }
+}
+
+void vgGetiv(VGParamType type, VGint count,
+             VGint * values)
+{
+   const struct vg_state *state = current_state();
+   struct vg_context *ctx = vg_current_context();
+   VGint real_count = vgGetVectorSize(type);
+
+   if (!values || count <= 0 || count > real_count || !is_aligned(values)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   switch(type) {
+   case VG_MATRIX_MODE:
+   case VG_FILL_RULE:
+   case VG_IMAGE_QUALITY:
+   case VG_RENDERING_QUALITY:
+   case VG_BLEND_MODE:
+   case VG_IMAGE_MODE:
+#ifdef OPENVG_VERSION_1_1
+   case VG_COLOR_TRANSFORM:
+#endif
+   case VG_STROKE_CAP_STYLE:
+   case VG_STROKE_JOIN_STYLE:
+   case VG_STROKE_DASH_PHASE_RESET:
+   case VG_MASKING:
+   case VG_SCISSORING:
+   case VG_PIXEL_LAYOUT:
+   case VG_SCREEN_LAYOUT:
+   case VG_FILTER_FORMAT_LINEAR:
+   case VG_FILTER_FORMAT_PREMULTIPLIED:
+   case VG_FILTER_CHANNEL_MASK:
+   case VG_MAX_SCISSOR_RECTS:
+   case VG_MAX_DASH_COUNT:
+   case VG_MAX_KERNEL_SIZE:
+   case VG_MAX_SEPARABLE_KERNEL_SIZE:
+   case VG_MAX_COLOR_RAMP_STOPS:
+   case VG_MAX_IMAGE_WIDTH:
+   case VG_MAX_IMAGE_HEIGHT:
+   case VG_MAX_IMAGE_PIXELS:
+   case VG_MAX_IMAGE_BYTES:
+   case VG_MAX_GAUSSIAN_STD_DEVIATION:
+      values[0] = vgGeti(type);
+      break;
+   case VG_MAX_FLOAT: {
+      VGfloat val = vgGetf(type);
+      values[0] = float_to_int_floor(*((VGuint*)&val));
+   }
+      break;
+   case VG_SCISSOR_RECTS: {
+      VGint i;
+      for (i = 0; i < count; ++i) {
+         values[i] = state->scissor_rects[i].i;
+      }
+   }
+      break;
+#ifdef OPENVG_VERSION_1_1
+   case VG_COLOR_TRANSFORM_VALUES: {
+      VGint i;
+      VGuint *x = (VGuint*)state->color_transform_values;
+      for (i = 0; i < count; ++i) {
+         values[i] = float_to_int_floor(x[i]);
+      }
+   }
+      break;
+#endif
+   case VG_STROKE_LINE_WIDTH:
+      values[0] = state->stroke.line_width.i;
+      break;
+   case VG_STROKE_MITER_LIMIT:
+      values[0] = state->stroke.miter_limit.i;
+      break;
+   case VG_STROKE_DASH_PATTERN: {
+      VGint i;
+      for (i = 0; i < count; ++i) {
+         values[i] = state->stroke.dash_pattern[i].i;
+      }
+   }
+      break;
+   case VG_STROKE_DASH_PHASE:
+      values[0] = state->stroke.dash_phase.i;
+      break;
+   case VG_TILE_FILL_COLOR:
+      values[0] = state->tile_fill_colori[0];
+      values[1] = state->tile_fill_colori[1];
+      values[2] = state->tile_fill_colori[2];
+      values[3] = state->tile_fill_colori[3];
+      break;
+   case VG_CLEAR_COLOR:
+      values[0] = state->clear_colori[0];
+      values[1] = state->clear_colori[1];
+      values[2] = state->clear_colori[2];
+      values[3] = state->clear_colori[3];
+      break;
+#ifdef OPENVG_VERSION_1_1
+   case VG_GLYPH_ORIGIN:
+      values[0] = state->glyph_origin[0].i;
+      values[1] = state->glyph_origin[1].i;
+      break;
+#endif
+   default:
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      break;
+   }
+}
+
+void vgSetParameterf(VGHandle object,
+                     VGint paramType,
+                     VGfloat value)
+{
+   struct vg_context *ctx = vg_current_context();
+   void *ptr = (void*)object;
+
+   if (!object || object == VG_INVALID_HANDLE || !is_aligned(ptr)) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   switch(paramType) {
+   case VG_PAINT_TYPE:
+   case VG_PAINT_COLOR_RAMP_SPREAD_MODE:
+   case VG_PAINT_PATTERN_TILING_MODE:
+      vgSetParameteri(object, paramType, floor(value));
+      return;
+      break;
+   case VG_PAINT_COLOR:
+   case VG_PAINT_COLOR_RAMP_STOPS:
+   case VG_PAINT_LINEAR_GRADIENT:
+   case VG_PAINT_RADIAL_GRADIENT:
+      /* it's an error if paramType refers to a vector parameter */
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      break;
+   case VG_PAINT_COLOR_RAMP_PREMULTIPLIED: {
+      struct vg_paint *p = (struct vg_paint *)object;
+      paint_set_color_ramp_premultiplied(p, value);
+   }
+      break;
+
+   case VG_PATH_DATATYPE:
+   case VG_PATH_FORMAT:
+   case VG_PATH_SCALE:
+   case VG_PATH_BIAS:
+   case VG_PATH_NUM_SEGMENTS:
+   case VG_PATH_NUM_COORDS:
+
+   case VG_IMAGE_FORMAT:
+   case VG_IMAGE_WIDTH:
+   case VG_IMAGE_HEIGHT:
+
+#ifdef OPENVG_VERSION_1_1
+   case VG_FONT_NUM_GLYPHS:
+      /* read only don't produce an error */
+      break;
+#endif
+   default:
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      break;
+   }
+}
+
+void vgSetParameteri(VGHandle object,
+                     VGint paramType,
+                     VGint value)
+{
+   struct vg_context *ctx = vg_current_context();
+   void *ptr = (void*)object;
+
+   if (!object || object == VG_INVALID_HANDLE || !is_aligned(ptr)) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   switch(paramType) {
+   case VG_PAINT_TYPE:
+      if (value < VG_PAINT_TYPE_COLOR ||
+          value > VG_PAINT_TYPE_PATTERN)
+         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      else {
+         struct vg_paint *paint = (struct vg_paint *)ptr;
+         paint_set_type(paint, value);
+      }
+      break;
+   case VG_PAINT_COLOR:
+   case VG_PAINT_COLOR_RAMP_STOPS:
+   case VG_PAINT_LINEAR_GRADIENT:
+   case VG_PAINT_RADIAL_GRADIENT:
+      /* it's an error if paramType refers to a vector parameter */
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      break;
+   case VG_PAINT_COLOR_RAMP_SPREAD_MODE:
+      if (value < VG_COLOR_RAMP_SPREAD_PAD ||
+          value > VG_COLOR_RAMP_SPREAD_REFLECT)
+         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      else {
+         struct vg_paint *paint = (struct vg_paint *)ptr;
+         paint_set_spread_mode(paint, value);
+      }
+      break;
+   case VG_PAINT_COLOR_RAMP_PREMULTIPLIED: {
+      struct vg_paint *p = (struct vg_paint *)object;
+      paint_set_color_ramp_premultiplied(p, value);
+   }
+      break;
+   case VG_PAINT_PATTERN_TILING_MODE:
+      if (value < VG_TILE_FILL ||
+          value > VG_TILE_REFLECT)
+         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      else {
+         struct vg_paint *paint = (struct vg_paint *)ptr;
+         paint_set_pattern_tiling(paint, value);
+      }
+      break;
+
+   case VG_PATH_DATATYPE:
+   case VG_PATH_FORMAT:
+   case VG_PATH_SCALE:
+   case VG_PATH_BIAS:
+   case VG_PATH_NUM_SEGMENTS:
+   case VG_PATH_NUM_COORDS:
+
+   case VG_IMAGE_FORMAT:
+   case VG_IMAGE_WIDTH:
+   case VG_IMAGE_HEIGHT:
+
+#ifdef OPENVG_VERSION_1_1
+   case VG_FONT_NUM_GLYPHS:
+      /* read only don't produce an error */
+      break;
+#endif
+   default:
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+}
+
+void vgSetParameterfv(VGHandle object,
+                      VGint paramType,
+                      VGint count,
+                      const VGfloat * values)
+{
+   struct vg_context *ctx = vg_current_context();
+   void *ptr = (void*)object;
+   VGint real_count = vgGetParameterVectorSize(object, paramType);
+
+   if (!object || object == VG_INVALID_HANDLE || !is_aligned(ptr)) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   if (count < 0 || count < real_count ||
+       (values == NULL && count != 0) ||
+       !is_aligned(values)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   switch(paramType) {
+   case VG_PAINT_TYPE:
+   case VG_PAINT_COLOR_RAMP_SPREAD_MODE:
+   case VG_PAINT_COLOR_RAMP_PREMULTIPLIED:
+   case VG_PAINT_PATTERN_TILING_MODE:
+      if (count != 1)
+         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      else
+         vgSetParameterf(object, paramType, values[0]);
+      return;
+      break;
+   case VG_PAINT_COLOR: {
+      if (count != 4)
+         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      else {
+         struct vg_paint *paint = (struct vg_paint *)object;
+         paint_set_color(paint, values);
+      }
+   }
+      break;
+   case VG_PAINT_COLOR_RAMP_STOPS: {
+      if (count && count < 4)
+         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      else {
+         struct vg_paint *paint = (struct vg_paint *)object;
+         count = MIN2(count, VEGA_MAX_COLOR_RAMP_STOPS);
+         paint_set_ramp_stops(paint, values, count);
+         {
+            VGint stopsi[VEGA_MAX_COLOR_RAMP_STOPS];
+            int i = 0;
+            for (i = 0; i < count; ++i) {
+               stopsi[i] = float_to_int_floor(*((VGuint*)(values + i)));
+            }
+            paint_set_ramp_stopsi(paint, stopsi, count);
+         }
+      }
+   }
+      break;
+   case VG_PAINT_LINEAR_GRADIENT: {
+      if (count != 4)
+         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      else {
+         struct vg_paint *paint = (struct vg_paint *)object;
+         paint_set_linear_gradient(paint, values);
+         {
+            VGint vals[4];
+            vals[0] = FLT_TO_INT(values[0]);
+            vals[1] = FLT_TO_INT(values[1]);
+            vals[2] = FLT_TO_INT(values[2]);
+            vals[3] = FLT_TO_INT(values[3]);
+            paint_set_linear_gradienti(paint, vals);
+         }
+      }
+   }
+      break;
+   case VG_PAINT_RADIAL_GRADIENT: {
+      if (count != 5)
+         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      else {
+         struct vg_paint *paint = (struct vg_paint *)object;
+         paint_set_radial_gradient(paint, values);
+         {
+            VGint vals[5];
+            vals[0] = FLT_TO_INT(values[0]);
+            vals[1] = FLT_TO_INT(values[1]);
+            vals[2] = FLT_TO_INT(values[2]);
+            vals[3] = FLT_TO_INT(values[3]);
+            vals[4] = FLT_TO_INT(values[4]);
+            paint_set_radial_gradienti(paint, vals);
+         }
+      }
+   }
+      break;
+
+   case VG_PATH_DATATYPE:
+   case VG_PATH_FORMAT:
+   case VG_PATH_SCALE:
+   case VG_PATH_BIAS:
+   case VG_PATH_NUM_SEGMENTS:
+   case VG_PATH_NUM_COORDS:
+
+#ifdef OPENVG_VERSION_1_1
+   case VG_FONT_NUM_GLYPHS:
+      /* read only don't produce an error */
+      break;
+#endif
+   default:
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+}
+
+void vgSetParameteriv(VGHandle object,
+                      VGint paramType,
+                      VGint count,
+                      const VGint * values)
+{
+   struct vg_context *ctx = vg_current_context();
+   void *ptr = (void*)object;
+   VGint real_count = vgGetParameterVectorSize(object, paramType);
+
+   if (!object || object == VG_INVALID_HANDLE || !is_aligned(ptr)) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   if (count < 0 || count < real_count ||
+       (values == NULL && count != 0) ||
+       !is_aligned(values)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   switch(paramType) {
+   case VG_PAINT_TYPE:
+   case VG_PAINT_COLOR_RAMP_SPREAD_MODE:
+   case VG_PAINT_COLOR_RAMP_PREMULTIPLIED:
+   case VG_PAINT_PATTERN_TILING_MODE:
+      if (count != 1)
+         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      else
+         vgSetParameteri(object, paramType, values[0]);
+      return;
+      break;
+   case VG_PAINT_COLOR: {
+      if (count != 4)
+         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      else {
+         struct vg_paint *paint = (struct vg_paint *)object;
+         paint_set_coloriv(paint, values);
+      }
+   }
+      break;
+   case VG_PAINT_COLOR_RAMP_STOPS: {
+      if ((count % 5))
+         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      else {
+         VGfloat *vals = 0;
+         int i;
+         struct vg_paint *paint = (struct vg_paint *)object;
+         if (count) {
+            vals = malloc(sizeof(VGfloat)*count);
+            for (i = 0; i < count; ++i)
+               vals[i] = values[i];
+         }
+
+         paint_set_ramp_stopsi(paint, values, count);
+         paint_set_ramp_stops(paint, vals, count);
+         free(vals);
+      }
+   }
+      break;
+   case VG_PAINT_LINEAR_GRADIENT: {
+      if (count != 4)
+         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      else {
+         VGfloat vals[4];
+         struct vg_paint *paint = (struct vg_paint *)object;
+         vals[0] = values[0];
+         vals[1] = values[1];
+         vals[2] = values[2];
+         vals[3] = values[3];
+         paint_set_linear_gradient(paint, vals);
+         paint_set_linear_gradienti(paint, values);
+      }
+   }
+      break;
+   case VG_PAINT_RADIAL_GRADIENT: {
+      if (count != 5)
+         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      else {
+         VGfloat vals[5];
+         struct vg_paint *paint = (struct vg_paint *)object;
+         vals[0] = values[0];
+         vals[1] = values[1];
+         vals[2] = values[2];
+         vals[3] = values[3];
+         vals[4] = values[4];
+         paint_set_radial_gradient(paint, vals);
+         paint_set_radial_gradienti(paint, values);
+      }
+   }
+      break;
+   case VG_PATH_DATATYPE:
+   case VG_PATH_FORMAT:
+   case VG_PATH_SCALE:
+   case VG_PATH_BIAS:
+   case VG_PATH_NUM_SEGMENTS:
+   case VG_PATH_NUM_COORDS:
+      /* read only don't produce an error */
+      break;
+   default:
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+}
+
+VGint vgGetParameterVectorSize(VGHandle object,
+                               VGint paramType)
+{
+   struct vg_context *ctx = vg_current_context();
+   void *ptr = (void*)object;
+
+   if (!ptr || object == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return 0;
+   }
+
+   switch(paramType) {
+   case VG_PAINT_TYPE:
+   case VG_PAINT_COLOR_RAMP_SPREAD_MODE:
+   case VG_PAINT_COLOR_RAMP_PREMULTIPLIED:
+   case VG_PAINT_PATTERN_TILING_MODE:
+      return 1;
+   case VG_PAINT_COLOR:
+      return 4;
+   case VG_PAINT_COLOR_RAMP_STOPS: {
+      struct vg_paint *p = (struct vg_paint *)object;
+      return paint_num_ramp_stops(p);
+   }
+      break;
+   case VG_PAINT_LINEAR_GRADIENT:
+      return 4;
+   case VG_PAINT_RADIAL_GRADIENT:
+      return 5;
+
+
+   case VG_PATH_FORMAT:
+   case VG_PATH_DATATYPE:
+   case VG_PATH_SCALE:
+   case VG_PATH_BIAS:
+   case VG_PATH_NUM_SEGMENTS:
+   case VG_PATH_NUM_COORDS:
+      return 1;
+
+   case VG_IMAGE_FORMAT:
+   case VG_IMAGE_WIDTH:
+   case VG_IMAGE_HEIGHT:
+      return 1;
+
+#ifdef OPENVG_VERSION_1_1
+   case VG_FONT_NUM_GLYPHS:
+      return 1;
+#endif
+
+   default:
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      break;
+   }
+   return 0;
+}
+
+
+VGfloat vgGetParameterf(VGHandle object,
+                        VGint paramType)
+{
+   struct vg_context *ctx = vg_current_context();
+   void *ptr = (void*)object;
+
+   if (!ptr || object == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return 0;
+   }
+
+   switch(paramType) {
+   case VG_PAINT_TYPE:
+   case VG_PAINT_COLOR_RAMP_SPREAD_MODE:
+   case VG_PAINT_COLOR_RAMP_PREMULTIPLIED:
+   case VG_PAINT_PATTERN_TILING_MODE:
+      return vgGetParameteri(object, paramType);
+      break;
+   case VG_PAINT_COLOR:
+   case VG_PAINT_COLOR_RAMP_STOPS:
+   case VG_PAINT_LINEAR_GRADIENT:
+   case VG_PAINT_RADIAL_GRADIENT:
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      break;
+
+   case VG_PATH_FORMAT:
+      return VG_PATH_FORMAT_STANDARD;
+   case VG_PATH_SCALE: {
+      struct path *p = (struct path*)object;
+      return path_scale(p);
+   }
+   case VG_PATH_BIAS: {
+      struct path *p = (struct path*)object;
+      return path_bias(p);
+   }
+   case VG_PATH_DATATYPE:
+   case VG_PATH_NUM_SEGMENTS:
+   case VG_PATH_NUM_COORDS:
+      return vgGetParameteri(object, paramType);
+      break;
+
+   case VG_IMAGE_FORMAT:
+   case VG_IMAGE_WIDTH:
+   case VG_IMAGE_HEIGHT:
+#ifdef OPENVG_VERSION_1_1
+   case VG_FONT_NUM_GLYPHS: 
+      return vgGetParameteri(object, paramType);
+      break;
+#endif
+
+   default:
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      break;
+   }
+   return 0;
+}
+
+VGint vgGetParameteri(VGHandle object,
+                      VGint paramType)
+{
+   struct vg_context *ctx = vg_current_context();
+   void *ptr = (void*)object;
+
+   if (!ptr || object == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return 0;
+   }
+
+   switch(paramType) {
+   case VG_PAINT_TYPE: {
+         struct vg_paint *paint = (struct vg_paint *)ptr;
+         return paint_type(paint);
+   }
+      break;
+   case VG_PAINT_COLOR_RAMP_SPREAD_MODE: {
+      struct vg_paint *p = (struct vg_paint *)object;
+      return paint_spread_mode(p);
+   }
+   case VG_PAINT_COLOR_RAMP_PREMULTIPLIED: {
+      struct vg_paint *p = (struct vg_paint *)object;
+      return paint_color_ramp_premultiplied(p);
+   }
+      break;
+   case VG_PAINT_PATTERN_TILING_MODE: {
+      struct vg_paint *p = (struct vg_paint *)object;
+      return paint_pattern_tiling(p);
+   }
+      break;
+   case VG_PAINT_COLOR:
+   case VG_PAINT_COLOR_RAMP_STOPS:
+   case VG_PAINT_LINEAR_GRADIENT:
+   case VG_PAINT_RADIAL_GRADIENT:
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      break;
+
+   case VG_PATH_FORMAT:
+      return VG_PATH_FORMAT_STANDARD;
+   case VG_PATH_SCALE:
+   case VG_PATH_BIAS:
+      return vgGetParameterf(object, paramType);
+   case VG_PATH_DATATYPE: {
+      struct path *p = (struct path*)object;
+      return path_datatype(p);
+   }
+   case VG_PATH_NUM_SEGMENTS: {
+      struct path *p = (struct path*)object;
+      return path_num_segments(p);
+   }
+   case VG_PATH_NUM_COORDS: {
+      struct path *p = (struct path*)object;
+      return path_num_coords(p);
+   }
+      break;
+
+   case VG_IMAGE_FORMAT: {
+      struct vg_image *img = (struct vg_image*)object;
+      return img->format;
+   }
+      break;
+   case VG_IMAGE_WIDTH: {
+      struct vg_image *img = (struct vg_image*)object;
+      return img->width;
+   }
+      break;
+   case VG_IMAGE_HEIGHT: {
+      struct vg_image *img = (struct vg_image*)object;
+      return img->height;
+   }
+      break;
+
+#ifdef OPENVG_VERSION_1_1
+   case VG_FONT_NUM_GLYPHS: {
+      return 1;
+   }
+      break;
+#endif
+
+   default:
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      break;
+   }
+   return 0;
+}
+
+void vgGetParameterfv(VGHandle object,
+                      VGint paramType,
+                      VGint count,
+                      VGfloat * values)
+{
+   struct vg_context *ctx = vg_current_context();
+   void *ptr = (void*)object;
+   VGint real_count = vgGetParameterVectorSize(object, paramType);
+
+   if (!ptr || object == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   if (!values || count <= 0 || count > real_count ||
+       !is_aligned(values)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   switch(paramType) {
+   case VG_PAINT_TYPE: {
+      struct vg_paint *p = (struct vg_paint *)object;
+      values[0] = paint_type(p);
+   }
+      break;
+   case VG_PAINT_COLOR_RAMP_SPREAD_MODE: {
+      struct vg_paint *p = (struct vg_paint *)object;
+      values[0] = paint_spread_mode(p);
+   }
+      break;
+   case VG_PAINT_COLOR_RAMP_PREMULTIPLIED: {
+      struct vg_paint *p = (struct vg_paint *)object;
+      values[0] = paint_color_ramp_premultiplied(p);
+   }
+      break;
+   case VG_PAINT_PATTERN_TILING_MODE: {
+      values[0] = vgGetParameterf(object, paramType);
+   }
+      break;
+   case VG_PAINT_COLOR: {
+      struct vg_paint *paint = (struct vg_paint *)object;
+      paint_get_color(paint, values);
+   }
+      break;
+   case VG_PAINT_COLOR_RAMP_STOPS: {
+      struct vg_paint *paint = (struct vg_paint *)object;
+      paint_ramp_stops(paint, values, count);
+   }
+      break;
+   case VG_PAINT_LINEAR_GRADIENT: {
+      struct vg_paint *paint = (struct vg_paint *)object;
+      paint_linear_gradient(paint, values);
+   }
+      break;
+   case VG_PAINT_RADIAL_GRADIENT: {
+      struct vg_paint *paint = (struct vg_paint *)object;
+      paint_radial_gradient(paint, values);
+   }
+      break;
+
+   case VG_PATH_FORMAT:
+   case VG_PATH_DATATYPE:
+   case VG_PATH_NUM_SEGMENTS:
+   case VG_PATH_NUM_COORDS:
+      values[0] = vgGetParameteri(object, paramType);
+      break;
+   case VG_PATH_SCALE:
+   case VG_PATH_BIAS:
+      values[0] = vgGetParameterf(object, paramType);
+      break;
+
+   case VG_IMAGE_FORMAT:
+   case VG_IMAGE_WIDTH:
+   case VG_IMAGE_HEIGHT:
+#ifdef OPENVG_VERSION_1_1
+   case VG_FONT_NUM_GLYPHS:
+      values[0] = vgGetParameteri(object, paramType);
+      break;
+#endif
+
+   default:
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      break;
+   }
+}
+
+void vgGetParameteriv(VGHandle object,
+                      VGint paramType,
+                      VGint count,
+                      VGint * values)
+{
+   struct vg_context *ctx = vg_current_context();
+   void *ptr = (void*)object;
+   VGint real_count = vgGetParameterVectorSize(object, paramType);
+
+   if (!ptr || object == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   if (!values || count <= 0 || count > real_count ||
+       !is_aligned(values)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   switch(paramType) {
+   case VG_PAINT_TYPE:
+   case VG_PAINT_COLOR_RAMP_SPREAD_MODE:
+   case VG_PAINT_COLOR_RAMP_PREMULTIPLIED:
+   case VG_PAINT_PATTERN_TILING_MODE:
+#ifdef OPENVG_VERSION_1_1
+   case VG_FONT_NUM_GLYPHS:
+      values[0] = vgGetParameteri(object, paramType);
+      break;
+#endif
+   case VG_PAINT_COLOR: {
+      struct vg_paint *paint = (struct vg_paint *)object;
+      paint_get_coloriv(paint, values);
+   }
+      break;
+   case VG_PAINT_COLOR_RAMP_STOPS: {
+      struct vg_paint *paint = (struct vg_paint *)object;
+      paint_ramp_stopsi(paint, values, count);
+   }
+      break;
+   case VG_PAINT_LINEAR_GRADIENT: {
+      struct vg_paint *paint = (struct vg_paint *)object;
+      paint_linear_gradienti(paint, values);
+   }
+      break;
+   case VG_PAINT_RADIAL_GRADIENT: {
+      struct vg_paint *paint = (struct vg_paint *)object;
+      paint_radial_gradienti(paint, values);
+   }
+      break;
+
+   case VG_PATH_SCALE:
+   case VG_PATH_BIAS:
+      values[0] = vgGetParameterf(object, paramType);
+      break;
+   case VG_PATH_FORMAT:
+   case VG_PATH_DATATYPE:
+   case VG_PATH_NUM_SEGMENTS:
+   case VG_PATH_NUM_COORDS:
+      values[0] = vgGetParameteri(object, paramType);
+      break;
+
+   case VG_IMAGE_FORMAT:
+   case VG_IMAGE_WIDTH:
+   case VG_IMAGE_HEIGHT:
+      values[0] = vgGetParameteri(object, paramType);
+      break;
+
+   default:
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      break;
+   }
+}
diff --git a/src/gallium/state_trackers/vega/api_path.c b/src/gallium/state_trackers/vega/api_path.c
new file mode 100644 (file)
index 0000000..a6b7a2b
--- /dev/null
@@ -0,0 +1,488 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#include "VG/openvg.h"
+
+#include "vg_context.h"
+#include "path.h"
+#include "polygon.h"
+#include "paint.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_inlines.h"
+#include "util/u_draw_quad.h"
+
+VGPath vgCreatePath(VGint pathFormat,
+                    VGPathDatatype datatype,
+                    VGfloat scale, VGfloat bias,
+                    VGint segmentCapacityHint,
+                    VGint coordCapacityHint,
+                    VGbitfield capabilities)
+{
+   struct vg_context *ctx = vg_current_context();
+
+   if (pathFormat != VG_PATH_FORMAT_STANDARD) {
+      vg_set_error(ctx, VG_UNSUPPORTED_PATH_FORMAT_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+   if (datatype < VG_PATH_DATATYPE_S_8 ||
+       datatype > VG_PATH_DATATYPE_F) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+   if (!scale) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+
+   return (VGPath)path_create(datatype, scale, bias,
+                              segmentCapacityHint, coordCapacityHint,
+                              capabilities);
+}
+
+void vgClearPath(VGPath path, VGbitfield capabilities)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct path *p = 0;
+
+   if (path == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   p = (struct path *)path;
+   path_clear(p, capabilities);
+}
+
+void vgDestroyPath(VGPath p)
+{
+   struct path *path = 0;
+   struct vg_context *ctx = vg_current_context();
+
+   if (p == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   path = (struct path *)p;
+   path_destroy(path);
+}
+
+void vgRemovePathCapabilities(VGPath path,
+                              VGbitfield capabilities)
+{
+   struct vg_context *ctx = vg_current_context();
+   VGbitfield current;
+   struct path *p;
+
+   if (path == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   p = (struct path*)path;
+   current = path_capabilities(p);
+   path_set_capabilities(p, (current &
+                             (~(capabilities & VG_PATH_CAPABILITY_ALL))));
+}
+
+VGbitfield vgGetPathCapabilities(VGPath path)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct path *p = 0;
+
+   if (path == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return 0;
+   }
+   p = (struct path*)path;
+   return path_capabilities(p);
+}
+
+void vgAppendPath(VGPath dstPath, VGPath srcPath)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct path *src, *dst;
+
+   if (dstPath == VG_INVALID_HANDLE || srcPath == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   src = (struct path *)srcPath;
+   dst = (struct path *)dstPath;
+
+   if (!(path_capabilities(src) & VG_PATH_CAPABILITY_APPEND_FROM) ||
+       !(path_capabilities(dst) & VG_PATH_CAPABILITY_APPEND_TO)) {
+      vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
+      return;
+   }
+   path_append_path(dst, src);
+}
+
+void vgAppendPathData(VGPath dstPath,
+                      VGint numSegments,
+                      const VGubyte * pathSegments,
+                      const void * pathData)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct path *p = 0;
+   VGint i;
+
+   if (dstPath == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   if (!pathSegments) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+   if (numSegments <= 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+   for (i = 0; i < numSegments; ++i) {
+      if (pathSegments[i] < VG_CLOSE_PATH ||
+          pathSegments[i] > VG_LCWARC_TO_REL) {
+         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+         return;
+      }
+   }
+
+   p = (struct path*)dstPath;
+
+   if (!pathData || !is_aligned_to(pathData, path_datatype_size(p))) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   if (!(path_capabilities(p)&VG_PATH_CAPABILITY_APPEND_TO)) {
+      vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
+      return;
+   }
+
+   path_append_data(p, numSegments, pathSegments, pathData);
+}
+
+void vgModifyPathCoords(VGPath dstPath,
+                        VGint startIndex,
+                        VGint numSegments,
+                        const void * pathData)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct path *p = 0;
+
+   if (dstPath == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   if (startIndex < 0 || numSegments <= 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   p = (struct path *)dstPath;
+
+   if (!pathData || !is_aligned_to(pathData, path_datatype_size(p))) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   if (startIndex + numSegments > path_num_segments(p)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+   if (!(path_capabilities(p)&VG_PATH_CAPABILITY_MODIFY)) {
+      vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
+      return;
+   }
+   path_modify_coords(p, startIndex, numSegments, pathData);
+}
+
+void vgTransformPath(VGPath dstPath, VGPath srcPath)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct path *src = 0, *dst = 0;
+
+   if (dstPath == VG_INVALID_HANDLE || srcPath == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   src = (struct path *)srcPath;
+   dst = (struct path *)dstPath;
+
+   if (!(path_capabilities(src) & VG_PATH_CAPABILITY_TRANSFORM_FROM) ||
+       !(path_capabilities(dst) & VG_PATH_CAPABILITY_TRANSFORM_TO)) {
+      vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
+      return;
+   }
+   path_transform(dst, src);
+}
+
+VGboolean vgInterpolatePath(VGPath dstPath,
+                            VGPath startPath,
+                            VGPath endPath,
+                            VGfloat amount)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct path *start = 0, *dst = 0, *end = 0;
+
+   if (dstPath == VG_INVALID_HANDLE ||
+       startPath == VG_INVALID_HANDLE ||
+       endPath == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return VG_FALSE;
+   }
+   dst = (struct path *)dstPath;
+   start = (struct path *)startPath;
+   end = (struct path *)endPath;
+
+   if (!(path_capabilities(dst) & VG_PATH_CAPABILITY_INTERPOLATE_TO) ||
+       !(path_capabilities(start) & VG_PATH_CAPABILITY_INTERPOLATE_FROM) ||
+       !(path_capabilities(end) & VG_PATH_CAPABILITY_INTERPOLATE_FROM)) {
+      vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
+      return VG_FALSE;
+   }
+
+   return path_interpolate(dst,
+                           start, end, amount);
+}
+
+VGfloat vgPathLength(VGPath path,
+                     VGint startSegment,
+                     VGint numSegments)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct path *p = 0;
+
+   if (path == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return -1;
+   }
+   if (startSegment < 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return -1;
+   }
+   if (numSegments <= 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return -1;
+   }
+   p = (struct path*)path;
+
+   if (!(path_capabilities(p) & VG_PATH_CAPABILITY_PATH_LENGTH)) {
+      vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
+      return -1;
+   }
+   if (startSegment + numSegments > path_num_segments(p)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return -1;
+   }
+
+   return path_length(p, startSegment, numSegments);
+}
+
+void vgPointAlongPath(VGPath path,
+                      VGint startSegment,
+                      VGint numSegments,
+                      VGfloat distance,
+                      VGfloat * x, VGfloat * y,
+                      VGfloat * tangentX,
+                      VGfloat * tangentY)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct path *p = 0;
+   VGbitfield caps;
+
+   if (path == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   if (startSegment < 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+   if (numSegments <= 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   if (!is_aligned(x) || !is_aligned(y) ||
+       !is_aligned(tangentX) || !is_aligned(tangentY)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   p = (struct path*)path;
+
+   caps = path_capabilities(p);
+   if (!(caps & VG_PATH_CAPABILITY_POINT_ALONG_PATH) ||
+       !(caps & VG_PATH_CAPABILITY_TANGENT_ALONG_PATH)) {
+      vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
+      return;
+   }
+
+   if (startSegment + numSegments > path_num_segments(p)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   {
+      VGfloat point[2], normal[2];
+      path_point(p, startSegment, numSegments, distance,
+                 point, normal);
+      if (x)
+         *x = point[0];
+      if (y)
+         *y = point[1];
+      if (tangentX)
+         *tangentX = -normal[1];
+      if (tangentY)
+         *tangentY = normal[0];
+   }
+}
+
+void vgPathBounds(VGPath path,
+                  VGfloat * minX,
+                  VGfloat * minY,
+                  VGfloat * width,
+                  VGfloat * height)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct path *p = 0;
+   VGbitfield caps;
+
+   if (path == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   if (!minX || !minY || !width || !height) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   if (!is_aligned(minX) || !is_aligned(minY) ||
+       !is_aligned(width) || !is_aligned(height)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   p = (struct path*)path;
+
+   caps = path_capabilities(p);
+   if (!(caps & VG_PATH_CAPABILITY_PATH_BOUNDS)) {
+      vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
+      return;
+   }
+
+   path_bounding_rect(p, minX, minY, width, height);
+}
+
+void vgPathTransformedBounds(VGPath path,
+                             VGfloat * minX,
+                             VGfloat * minY,
+                             VGfloat * width,
+                             VGfloat * height)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct path *p = 0;
+   VGbitfield caps;
+
+   if (path == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   if (!minX || !minY || !width || !height) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   if (!is_aligned(minX) || !is_aligned(minY) ||
+       !is_aligned(width) || !is_aligned(height)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   p = (struct path*)path;
+
+   caps = path_capabilities(p);
+   if (!(caps & VG_PATH_CAPABILITY_PATH_TRANSFORMED_BOUNDS)) {
+      vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
+      return;
+   }
+
+#if 0
+   /* faster, but seems to have precision problems... */
+   path_bounding_rect(p, minX, minY, width, height);
+   if (*width > 0 && *height > 0) {
+      VGfloat pts[] = {*minX,          *minY,
+                       *minX + *width, *minY,
+                       *minX + *width, *minY + *height,
+                       *minX,          *minY + *height};
+      struct matrix *matrix = &ctx->state.vg.path_user_to_surface_matrix;
+      VGfloat maxX, maxY;
+      matrix_map_point(matrix, pts[0], pts[1], pts + 0, pts + 1);
+      matrix_map_point(matrix, pts[2], pts[3], pts + 2, pts + 3);
+      matrix_map_point(matrix, pts[4], pts[5], pts + 4, pts + 5);
+      matrix_map_point(matrix, pts[6], pts[7], pts + 6, pts + 7);
+      *minX = MIN2(pts[0], MIN2(pts[2], MIN2(pts[4], pts[6])));
+      *minY = MIN2(pts[1], MIN2(pts[3], MIN2(pts[5], pts[7])));
+      maxX = MAX2(pts[0], MAX2(pts[2], MAX2(pts[4], pts[6])));
+      maxY = MAX2(pts[1], MAX2(pts[3], MAX2(pts[5], pts[7])));
+      *width  = maxX - *minX;
+      *height = maxY - *minY;
+   }
+#else
+   {
+      struct path *dst = path_create(VG_PATH_DATATYPE_F, 1.0, 0,
+                                     0, 0, VG_PATH_CAPABILITY_ALL);
+      path_transform(dst, p);
+      path_bounding_rect(dst, minX, minY, width, height);
+      path_destroy(dst);
+   }
+#endif
+}
+
+
+void vgDrawPath(VGPath path, VGbitfield paintModes)
+{
+   struct vg_context *ctx = vg_current_context();
+
+   if (path == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   if (!(paintModes & (VG_STROKE_PATH | VG_FILL_PATH))) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   if (path_is_empty((struct path*)path))
+      return;
+   path_render((struct path*)path, paintModes);
+}
+
diff --git a/src/gallium/state_trackers/vega/api_text.c b/src/gallium/state_trackers/vega/api_text.c
new file mode 100644 (file)
index 0000000..d8411cf
--- /dev/null
@@ -0,0 +1,258 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#include "VG/openvg.h"
+
+#include "vg_context.h"
+
+#include "util/u_memory.h"
+
+#ifdef OPENVG_VERSION_1_1
+
+struct vg_font {
+   struct vg_object base;
+
+   VGint glyph_indices[200];
+   VGint num_glyphs;
+};
+
+VGFont vgCreateFont(VGint glyphCapacityHint)
+{
+   struct vg_font *font = 0;
+   struct vg_context *ctx = vg_current_context();
+
+   if (glyphCapacityHint < 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+
+   font = CALLOC_STRUCT(vg_font);
+   vg_init_object(&font->base, ctx, VG_OBJECT_FONT);
+   vg_context_add_object(ctx, VG_OBJECT_FONT, font);
+   return (VGFont)font;
+}
+
+void vgDestroyFont(VGFont f)
+{
+   struct vg_font *font = (struct vg_font *)f;
+   struct vg_context *ctx = vg_current_context();
+
+   if (f == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   vg_context_remove_object(ctx, VG_OBJECT_FONT, font);
+   /*free(font);*/
+}
+
+void vgSetGlyphToPath(VGFont font,
+                      VGuint glyphIndex,
+                      VGPath path,
+                      VGboolean isHinted,
+                      VGfloat glyphOrigin [2],
+                      VGfloat escapement[2])
+{
+   struct vg_context *ctx = vg_current_context();
+   struct vg_object *pathObj;
+   struct vg_font *f;
+
+   if (font == VG_INVALID_HANDLE ||
+       !vg_context_is_object_valid(ctx, VG_OBJECT_FONT, (void *)font)) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   if (!glyphOrigin || !escapement ||
+       !is_aligned(glyphOrigin) || !is_aligned(escapement)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+   if (path != VG_INVALID_HANDLE &&
+       !vg_context_is_object_valid(ctx, VG_OBJECT_PATH, (void *)path)) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   pathObj = (struct vg_object*)path;
+   if (pathObj && pathObj->type != VG_OBJECT_PATH) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+
+   f = (struct vg_font*)font;
+   f->glyph_indices[f->num_glyphs] = glyphIndex;
+   ++f->num_glyphs;
+}
+
+void vgSetGlyphToImage(VGFont font,
+                       VGuint glyphIndex,
+                       VGImage image,
+                       VGfloat glyphOrigin [2],
+                       VGfloat escapement[2])
+{
+   struct vg_context *ctx = vg_current_context();
+   struct vg_object *img_obj;
+   struct vg_font *f;
+
+   if (font == VG_INVALID_HANDLE ||
+       !vg_context_is_object_valid(ctx, VG_OBJECT_FONT, (void *)font)) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   if (!glyphOrigin || !escapement ||
+       !is_aligned(glyphOrigin) || !is_aligned(escapement)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+   if (image != VG_INVALID_HANDLE &&
+       !vg_context_is_object_valid(ctx, VG_OBJECT_IMAGE, (void *)image)) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   img_obj = (struct vg_object*)image;
+   if (img_obj && img_obj->type != VG_OBJECT_IMAGE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   f = (struct vg_font*)font;
+   f->glyph_indices[f->num_glyphs] = glyphIndex;
+   ++f->num_glyphs;
+}
+
+static INLINE VGboolean font_contains_glyph(struct vg_font *font,
+                                            VGuint glyph_index)
+{
+   VGint i;
+   for (i = 0; i < font->num_glyphs; ++i) {
+      if (font->glyph_indices[i] == glyph_index) {
+         return VG_TRUE;
+      }
+   }
+   return VG_FALSE;
+}
+
+void vgClearGlyph(VGFont font,
+                  VGuint glyphIndex)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct vg_font *f;
+   VGint i;
+
+   if (font == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   if (glyphIndex <= 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+   f = (struct vg_font*)font;
+   if (!font_contains_glyph(f, glyphIndex)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   for (i = 0; i < f->num_glyphs; ++i) {
+      if (f->glyph_indices[i] == glyphIndex) {
+         /*FIXME*/
+         f->glyph_indices[f->num_glyphs] = 0;
+         --f->num_glyphs;
+         return;
+      }
+   }
+}
+
+void vgDrawGlyph(VGFont font,
+                 VGuint glyphIndex,
+                 VGbitfield paintModes,
+                 VGboolean allowAutoHinting)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct vg_font *f;
+
+   if (font == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   if (glyphIndex <= 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+   if (paintModes & (~(VG_STROKE_PATH|VG_FILL_PATH))) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+   f = (struct vg_font*)font;
+   if (!font_contains_glyph(f, glyphIndex)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+}
+
+void vgDrawGlyphs(VGFont font,
+                  VGint glyphCount,
+                  VGuint *glyphIndices,
+                  VGfloat *adjustments_x,
+                  VGfloat *adjustments_y,
+                  VGbitfield paintModes,
+                  VGboolean allowAutoHinting)
+{
+   struct vg_context *ctx = vg_current_context();
+   VGint i;
+   struct vg_font *f;
+
+   if (font == VG_INVALID_HANDLE) {
+      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
+      return;
+   }
+   if (glyphCount <= 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+   if (!glyphIndices || !is_aligned(glyphIndices)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+   if (!adjustments_x || !is_aligned(adjustments_x) ||
+       !adjustments_y || !is_aligned(adjustments_y)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+   if (paintModes & (~(VG_STROKE_PATH|VG_FILL_PATH))) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   f = (struct vg_font*)font;
+   for (i = 0; i < glyphCount; ++i) {
+      VGuint glyph_index = glyphIndices[i];
+      if (!font_contains_glyph(f, glyph_index)) {
+         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+         return;
+      }
+   }
+}
+
+#endif
diff --git a/src/gallium/state_trackers/vega/api_transform.c b/src/gallium/state_trackers/vega/api_transform.c
new file mode 100644 (file)
index 0000000..763a5ec
--- /dev/null
@@ -0,0 +1,128 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#include "VG/openvg.h"
+
+#include "vg_context.h"
+
+#include "matrix.h"
+
+void vgLoadIdentity(void)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct  matrix *mat = vg_state_matrix(&ctx->state.vg);
+   matrix_load_identity(mat);
+}
+
+void vgLoadMatrix(const VGfloat * m)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct  matrix *mat;
+
+   if (!ctx)
+      return;
+
+   if (!m || !is_aligned(m)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   mat = vg_state_matrix(&ctx->state.vg);
+   matrix_init(mat, m);
+   if (!matrix_is_affine(mat)) {
+      if (ctx->state.vg.matrix_mode != VG_MATRIX_IMAGE_USER_TO_SURFACE) {
+         matrix_make_affine(mat);
+      }
+   }
+}
+
+void vgGetMatrix(VGfloat * m)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct matrix *mat;
+
+   if (!ctx)
+      return;
+
+   if (!m || !is_aligned(m)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   mat = vg_state_matrix(&ctx->state.vg);
+   memcpy(m, mat->m, sizeof(VGfloat)*9);
+}
+
+void vgMultMatrix(const VGfloat * m)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct matrix *dst, src;
+
+   if (!ctx)
+      return;
+
+   if (!m || !is_aligned(m)) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+   matrix_init(&src, m);
+   dst = vg_state_matrix(&ctx->state.vg);
+   if (!matrix_is_affine(&src)) {
+      if (ctx->state.vg.matrix_mode != VG_MATRIX_IMAGE_USER_TO_SURFACE) {
+         matrix_make_affine(&src);
+      }
+   }
+   matrix_mult(dst, &src);
+
+}
+
+void vgTranslate(VGfloat tx, VGfloat ty)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct matrix *dst = vg_state_matrix(&ctx->state.vg);
+   matrix_translate(dst, tx, ty);
+}
+
+void vgScale(VGfloat sx, VGfloat sy)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct matrix *dst = vg_state_matrix(&ctx->state.vg);
+   matrix_scale(dst, sx, sy);
+}
+
+void vgShear(VGfloat shx, VGfloat shy)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct matrix *dst = vg_state_matrix(&ctx->state.vg);
+   matrix_shear(dst, shx, shy);
+}
+
+void vgRotate(VGfloat angle)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct matrix *dst = vg_state_matrix(&ctx->state.vg);
+   matrix_rotate(dst, angle);
+}
diff --git a/src/gallium/state_trackers/vega/arc.c b/src/gallium/state_trackers/vega/arc.c
new file mode 100644 (file)
index 0000000..e74c7f0
--- /dev/null
@@ -0,0 +1,708 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#include "arc.h"
+
+#include "matrix.h"
+#include "bezier.h"
+#include "polygon.h"
+#include "stroker.h"
+#include "path.h"
+
+#include "util/u_debug.h"
+
+#include <math.h>
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#define DEBUG_ARCS 0
+
+static const VGfloat two_pi = M_PI * 2;
+
+
+static const double coeffs3Low[2][4][4] = {
+   {
+      {  3.85268,   -21.229,      -0.330434,    0.0127842  },
+      { -1.61486,     0.706564,    0.225945,    0.263682   },
+      { -0.910164,    0.388383,    0.00551445,  0.00671814 },
+      { -0.630184,    0.192402,    0.0098871,   0.0102527  }
+   },
+   {
+      { -0.162211,    9.94329,     0.13723,     0.0124084  },
+      { -0.253135,    0.00187735,  0.0230286,   0.01264    },
+      { -0.0695069,  -0.0437594,   0.0120636,   0.0163087  },
+      { -0.0328856,  -0.00926032, -0.00173573,  0.00527385 }
+   }
+};
+
+/* coefficients for error estimation
+   while using cubic Bézier curves for approximation
+   1/4 <= b/a <= 1 */
+static const double coeffs3High[2][4][4] = {
+   {
+      {  0.0899116, -19.2349,     -4.11711,     0.183362   },
+      {  0.138148,   -1.45804,     1.32044,     1.38474    },
+      {  0.230903,   -0.450262,    0.219963,    0.414038   },
+      {  0.0590565,  -0.101062,    0.0430592,   0.0204699  }
+   },
+   {
+      {  0.0164649,   9.89394,     0.0919496,   0.00760802 },
+      {  0.0191603,  -0.0322058,   0.0134667,  -0.0825018  },
+      {  0.0156192,  -0.017535,    0.00326508, -0.228157   },
+      { -0.0236752,   0.0405821,  -0.0173086,   0.176187   }
+   }
+};
+
+/* safety factor to convert the "best" error approximation
+   into a "max bound" error */
+static const double safety3[] = {
+   0.001, 4.98, 0.207, 0.0067
+};
+
+/* The code below is from the OpenVG 1.1 Spec
+ * Section 18.4 */
+
+/* Given: Points (x0, y0) and (x1, y1)
+ * Return: TRUE if a solution exists, FALSE otherwise
+ *         Circle centers are written to (cx0, cy0) and (cx1, cy1)
+ */
+static VGboolean
+find_unit_circles(double x0, double y0, double x1, double y1,
+                  double *cx0, double *cy0,
+                  double *cx1, double *cy1)
+{
+   /* Compute differences and averages */
+   double dx = x0 - x1;
+   double dy = y0 - y1;
+   double xm = (x0 + x1)/2;
+   double ym = (y0 + y1)/2;
+   double dsq, disc, s, sdx, sdy;
+
+   /* Solve for intersecting unit circles */
+   dsq = dx*dx + dy*dy;
+   if (dsq == 0.0) return VG_FALSE; /* Points are coincident */
+   disc = 1.0/dsq - 1.0/4.0;
+
+   /* the precision we care about here is around float so if we're
+    * around the float defined zero then make it official to avoid
+    * precision problems later on */
+   if (floatIsZero(disc))
+      disc = 0.0;
+
+   if (disc < 0.0) return VG_FALSE; /* Points are too far apart */
+   s = sqrt(disc);
+   sdx = s*dx;
+   sdy = s*dy;
+   *cx0 = xm + sdy;
+   *cy0 = ym - sdx;
+   *cx1 = xm - sdy;
+   *cy1 = ym + sdx;
+   return VG_TRUE;
+}
+
+
+/* Given:  Ellipse parameters rh, rv, rot (in degrees),
+ *         endpoints (x0, y0) and (x1, y1)
+ * Return: TRUE if a solution exists, FALSE otherwise
+ *         Ellipse centers are written to (cx0, cy0) and (cx1, cy1)
+ */
+static VGboolean
+find_ellipses(double rh, double rv, double rot,
+              double x0, double y0, double x1, double y1,
+              double *cx0, double *cy0, double *cx1, double *cy1)
+{
+   double COS, SIN, x0p, y0p, x1p, y1p, pcx0, pcy0, pcx1, pcy1;
+   /* Convert rotation angle from degrees to radians */
+   rot *= M_PI/180.0;
+   /* Pre-compute rotation matrix entries */
+   COS = cos(rot); SIN = sin(rot);
+   /* Transform (x0, y0) and (x1, y1) into unit space */
+   /* using (inverse) rotate, followed by (inverse) scale   */
+   x0p = (x0*COS + y0*SIN)/rh;
+   y0p = (-x0*SIN + y0*COS)/rv;
+   x1p = (x1*COS + y1*SIN)/rh;
+   y1p = (-x1*SIN + y1*COS)/rv;
+   if (!find_unit_circles(x0p, y0p, x1p, y1p,
+                          &pcx0, &pcy0, &pcx1, &pcy1)) {
+      return VG_FALSE;
+   }
+   /* Transform back to original coordinate space */
+   /* using (forward) scale followed by (forward) rotate */
+   pcx0 *= rh; pcy0 *= rv;
+   pcx1 *= rh; pcy1 *= rv;
+   *cx0 = pcx0*COS - pcy0*SIN;
+   *cy0 = pcx0*SIN + pcy0*COS;
+   *cx1 = pcx1*COS - pcy1*SIN;
+   *cy1 = pcx1*SIN + pcy1*COS;
+   return VG_TRUE;
+}
+
+static INLINE VGboolean
+try_to_fix_radii(struct arc *arc)
+{
+   double COS, SIN, rot, x0p, y0p, x1p, y1p;
+   double dx, dy, dsq, scale;
+
+   /* Convert rotation angle from degrees to radians */
+   rot = DEGREES_TO_RADIANS(arc->theta);
+
+   /* Pre-compute rotation matrix entries */
+   COS = cos(rot); SIN = sin(rot);
+
+   /* Transform (x0, y0) and (x1, y1) into unit space */
+   /* using (inverse) rotate, followed by (inverse) scale   */
+   x0p = (arc->x1*COS + arc->y1*SIN)/arc->a;
+   y0p = (-arc->x1*SIN + arc->y1*COS)/arc->b;
+   x1p = (arc->x2*COS + arc->y2*SIN)/arc->a;
+   y1p = (-arc->x2*SIN + arc->y2*COS)/arc->b;
+   /* Compute differences and averages */
+   dx = x0p - x1p;
+   dy = y0p - y1p;
+
+   dsq = dx*dx + dy*dy;
+#if 0
+   if (dsq <= 0.001) {
+      debug_printf("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaaaaa\n");
+   }
+#endif
+   scale = 1/(2/sqrt(dsq));
+   arc->a *= scale;
+   arc->b *= scale;
+   return VG_TRUE;
+}
+
+static INLINE double vector_normalize(double *v)
+{
+   double sq = v[0] * v[0] + v[1] * v[1];
+   return sqrt(sq);
+}
+static INLINE double vector_orientation(double *v)
+{
+   double norm = vector_normalize(v);
+   double cosa = v[0] / norm;
+   double sina = v[1] / norm;
+   return (sina>=0 ? acos(cosa) : 2*M_PI - acos(cosa));
+}
+static INLINE double vector_dot(double *v0,
+                                double *v1)
+{
+   return v0[0] * v1[0] + v0[1] * v1[1];
+}
+
+static INLINE double vector_angles(double *v0,
+                                   double *v1)
+{
+   double dot = vector_dot(v0, v1);
+   double norm0 = vector_normalize(v0);
+   double norm1 = vector_normalize(v1);
+
+   return acos(dot / (norm0 * norm1));
+}
+
+static VGboolean find_angles(struct arc *arc)
+{
+   double vec0[2], vec1[2];
+   double lambda1, lambda2;
+   double angle;
+   struct matrix matrix;
+
+   if (floatIsZero(arc->a) || floatIsZero(arc->b)) {
+      return VG_FALSE;
+   }
+   /* map the points to an identity circle */
+   matrix_load_identity(&matrix);
+   matrix_scale(&matrix, 1.f, arc->a/arc->b);
+   matrix_rotate(&matrix, -arc->theta);
+   matrix_map_point(&matrix,
+                    arc->x1, arc->y1,
+                    &arc->x1, &arc->y1);
+   matrix_map_point(&matrix,
+                    arc->x2, arc->y2,
+                    &arc->x2, &arc->y2);
+   matrix_map_point(&matrix,
+                    arc->cx, arc->cy,
+                    &arc->cx, &arc->cy);
+
+#if DEBUG_ARCS
+   debug_printf("Matrix 3 [%f, %f, %f| %f, %f, %f| %f, %f, %f]\n",
+                matrix.m[0], matrix.m[1], matrix.m[2],
+                matrix.m[3], matrix.m[4], matrix.m[5],
+                matrix.m[6], matrix.m[7], matrix.m[8]);
+   debug_printf("Endpoints [%f, %f], [%f, %f]\n",
+                arc->x1, arc->y1, arc->x2, arc->y2);
+#endif
+
+   vec0[0] = arc->x1 - arc->cx;
+   vec0[1] = arc->y1 - arc->cy;
+   vec1[0] = arc->x2 - arc->cx;
+   vec1[1] = arc->y2 - arc->cy;
+
+#if DEBUG_ARCS
+   debug_printf("Vec is [%f, %f], [%f, %f], [%f, %f]\n",
+                vec0[0], vec0[1], vec1[0], vec1[1], arc->cx, arc->cy);
+#endif
+
+   lambda1 = vector_orientation(vec0);
+
+   if (isnan(lambda1))
+      lambda1 = 0.f;
+
+   if (arc->type == VG_SCWARC_TO ||
+       arc->type == VG_SCCWARC_TO)
+      angle = vector_angles(vec0, vec1);
+   else if (arc->type == VG_LCWARC_TO ||
+            arc->type == VG_LCCWARC_TO) {
+      angle = 2*M_PI - vector_angles(vec0, vec1);
+   } else
+      abort();
+
+   if (isnan(angle))
+      angle = M_PI;
+
+
+   if (arc->type == VG_SCWARC_TO ||
+       arc->type == VG_LCWARC_TO)
+      lambda2 = lambda1 - angle;
+   else
+      lambda2 = lambda1 + angle;
+
+#if DEBUG_ARCS
+   debug_printf("Angle is %f and (%f, %f)\n", angle, lambda1, lambda2);
+#endif
+
+#if 0
+   arc->eta1 = atan2(sin(lambda1) / arc->b,
+                     cos(lambda1) / arc->a);
+   arc->eta2 = atan2(sin(lambda2) / arc->b,
+                     cos(lambda2) / arc->a);
+
+   /* make sure we have eta1 <= eta2 <= eta1 + 2 PI */
+   arc->eta2 -= two_pi * floor((arc->eta2 - arc->eta1) / two_pi);
+
+   /* the preceding correction fails if we have exactly et2 - eta1 = 2 PI
+      it reduces the interval to zero length */
+   if ((lambda2 - lambda1 > M_PI) && (arc->eta2 - arc->eta1 < M_PI)) {
+      arc->eta2 += 2 * M_PI;
+   }
+#else
+   arc->eta1 = lambda1;
+   arc->eta2 = lambda2;
+#endif
+
+   return VG_TRUE;
+}
+
+#if DEBUG_ARCS
+static void check_endpoints(struct arc *arc)
+{
+   double x1, y1, x2, y2;
+
+   double a_cos_eta1 = arc->a * cos(arc->eta1);
+   double b_sin_eta1 = arc->b * sin(arc->eta1);
+   x1 = arc->cx + a_cos_eta1 * arc->cos_theta -
+        b_sin_eta1 * arc->sin_theta;
+   y1 = arc->cy + a_cos_eta1 * arc->sin_theta +
+        b_sin_eta1 * arc->cos_theta;
+
+   double a_cos_eta2 = arc->a * cos(arc->eta2);
+   double b_sin_eta2 = arc->b * sin(arc->eta2);
+   x2 = arc->cx + a_cos_eta2 * arc->cos_theta -
+        b_sin_eta2 * arc->sin_theta;
+   y2 = arc->cy + a_cos_eta2 * arc->sin_theta +
+        b_sin_eta2 * arc->cos_theta;
+
+   debug_printf("Computed (%f, %f), (%f, %f)\n",
+                x1, y1, x2, y2);
+   debug_printf("Real     (%f, %f), (%f, %f)\n",
+                arc->x1, arc->y1,
+                arc->x2, arc->y2);
+}
+#endif
+
+void arc_init(struct arc *arc,
+              VGPathSegment type,
+              VGfloat x1, VGfloat y1,
+              VGfloat x2, VGfloat y2,
+              VGfloat rh, VGfloat rv,
+              VGfloat rot)
+{
+   assert(type == VG_SCCWARC_TO ||
+          type == VG_SCWARC_TO ||
+          type == VG_LCCWARC_TO ||
+          type == VG_LCWARC_TO);
+   arc->type = type;
+   arc->x1  = x1;
+   arc->y1  = y1;
+   arc->x2  = x2;
+   arc->y2  = y2;
+   arc->a   = rh;
+   arc->b   = rv;
+   arc->theta = rot;
+   arc->cos_theta = cos(arc->theta);
+   arc->sin_theta = sin(arc->theta);
+   {
+      double cx0, cy0, cx1, cy1;
+      double cx, cy;
+      arc->is_valid =  find_ellipses(rh, rv, rot, x1, y1, x2, y2,
+                                     &cx0, &cy0, &cx1, &cy1);
+
+      if (!arc->is_valid && try_to_fix_radii(arc)) {
+         rh = arc->a;
+         rv = arc->b;
+         arc->is_valid =
+            find_ellipses(rh, rv, rot, x1, y1, x2, y2,
+                          &cx0, &cy0, &cx1, &cy1);
+      }
+
+      if (type == VG_SCWARC_TO ||
+          type == VG_LCCWARC_TO) {
+         cx = cx1;
+         cy = cy1;
+      } else {
+         cx = cx0;
+         cy = cy0;
+      }
+#if DEBUG_ARCS
+      debug_printf("Centers are : (%f, %f) , (%f, %f). Real (%f, %f)\n",
+                   cx0, cy0, cx1, cy1, cx, cy);
+#endif
+      arc->cx = cx;
+      arc->cy = cy;
+      if (arc->is_valid) {
+         arc->is_valid = find_angles(arc);
+#if DEBUG_ARCS
+         check_endpoints(arc);
+#endif
+         /* remap a few points. find_angles requires
+          * rot in angles, the rest of the code
+          * will need them in radians. and find_angles
+          * modifies the center to match an identity
+          * circle so lets reset it */
+         arc->theta = DEGREES_TO_RADIANS(rot);
+         arc->cos_theta = cos(arc->theta);
+         arc->sin_theta = sin(arc->theta);
+         arc->cx = cx;
+         arc->cy = cy;
+      }
+   }
+}
+
+static INLINE double rational_function(double x, const double *c)
+{
+   return (x * (x * c[0] + c[1]) + c[2]) / (x + c[3]);
+}
+
+static double estimate_error(struct arc *arc,
+                             double etaA, double etaB)
+{
+   double eta  = 0.5 * (etaA + etaB);
+
+   double x    = arc->b / arc->a;
+   double dEta = etaB - etaA;
+   double cos2 = cos(2 * eta);
+   double cos4 = cos(4 * eta);
+   double cos6 = cos(6 * eta);
+   double c0, c1;
+
+   /* select the right coeficients set according to degree and b/a */
+   const double (*coeffs)[4][4];
+   const double *safety;
+   coeffs = (x < 0.25) ? coeffs3Low : coeffs3High;
+   safety = safety3;
+
+   c0 = rational_function(x, coeffs[0][0])
+        + cos2 * rational_function(x, coeffs[0][1])
+        + cos4 * rational_function(x, coeffs[0][2])
+        + cos6 * rational_function(x, coeffs[0][3]);
+
+   c1 = rational_function(x, coeffs[1][0])
+        + cos2 * rational_function(x, coeffs[1][1])
+        + cos4 * rational_function(x, coeffs[1][2])
+        + cos6 * rational_function(x, coeffs[1][3]);
+
+   return rational_function(x, safety) * arc->a * exp(c0 + c1 * dEta);
+}
+
+struct arc_cb {
+   void (*move)(struct arc_cb *cb, VGfloat x, VGfloat y);
+   void (*point)(struct arc_cb *cb, VGfloat x, VGfloat y);
+   void (*bezier)(struct arc_cb *cb, struct bezier *bezier);
+
+   void *user_data;
+};
+
+static void cb_null_move(struct arc_cb *cb, VGfloat x, VGfloat y)
+{
+}
+
+static void polygon_point(struct arc_cb *cb, VGfloat x, VGfloat y)
+{
+   struct polygon *poly = (struct polygon*)cb->user_data;
+   polygon_vertex_append(poly, x, y);
+}
+
+static void polygon_bezier(struct arc_cb *cb, struct bezier *bezier)
+{
+   struct polygon *poly = (struct polygon*)cb->user_data;
+   bezier_add_to_polygon(bezier, poly);
+}
+
+static void stroke_point(struct arc_cb *cb, VGfloat x, VGfloat y)
+{
+   struct stroker *stroker = (struct stroker*)cb->user_data;
+   stroker_line_to(stroker, x, y);
+}
+
+static void stroke_curve(struct arc_cb *cb, struct bezier *bezier)
+{
+   struct stroker *stroker = (struct stroker*)cb->user_data;
+   stroker_curve_to(stroker,
+                    bezier->x2, bezier->y2,
+                    bezier->x3, bezier->y3,
+                    bezier->x4, bezier->y4);
+}
+
+static void stroke_emit_point(struct arc_cb *cb, VGfloat x, VGfloat y)
+{
+   struct stroker *stroker = (struct stroker*)cb->user_data;
+   stroker_emit_line_to(stroker, x, y);
+}
+
+static void stroke_emit_curve(struct arc_cb *cb, struct bezier *bezier)
+{
+   struct stroker *stroker = (struct stroker*)cb->user_data;
+   stroker_emit_curve_to(stroker,
+                         bezier->x2, bezier->y2,
+                         bezier->x3, bezier->y3,
+                         bezier->x4, bezier->y4);
+}
+
+static void arc_path_move(struct arc_cb *cb, VGfloat x, VGfloat y)
+{
+   struct path *path = (struct path*)cb->user_data;
+   path_move_to(path, x, y);
+}
+
+static void arc_path_point(struct arc_cb *cb, VGfloat x, VGfloat y)
+{
+   struct path *path = (struct path*)cb->user_data;
+   path_line_to(path, x, y);
+}
+
+static void arc_path_bezier(struct arc_cb *cb, struct bezier *bezier)
+{
+   struct path *path = (struct path*)cb->user_data;
+   path_cubic_to(path,
+                 bezier->x2, bezier->y2,
+                 bezier->x3, bezier->y3,
+                 bezier->x4, bezier->y4);
+}
+
+static INLINE int num_beziers_needed(struct arc *arc)
+{
+   double threshold = 0.05;
+   VGboolean found = VG_FALSE;
+   int n = 1;
+   double min_eta, max_eta;
+
+   min_eta = MIN2(arc->eta1, arc->eta2);
+   max_eta = MAX2(arc->eta1, arc->eta2);
+
+   while ((! found) && (n < 1024)) {
+      double d_eta = (max_eta - min_eta) / n;
+      if (d_eta <= 0.5 * M_PI) {
+         double eta_b = min_eta;
+         found = VG_TRUE;
+         for (int i = 0; found && (i < n); ++i) {
+            double etaA = eta_b;
+            eta_b += d_eta;
+            found = (estimate_error(arc, etaA, eta_b) <= threshold);
+         }
+      }
+      n = n << 1;
+   }
+
+   return n;
+}
+
+static void arc_to_beziers(struct arc *arc,
+                           struct arc_cb cb,
+                           struct matrix *matrix)
+{
+   int n = 1;
+   double d_eta, eta_b, cos_eta_b,
+      sin_eta_b, a_cos_eta_b, b_sin_eta_b, a_sin_eta_b,
+      b_cos_eta_b, x_b, y_b, x_b_dot, y_b_dot, lx, ly;
+   double t, alpha;
+
+   { /* always move to the start of the arc */
+      VGfloat x = arc->x1;
+      VGfloat y = arc->y1;
+      matrix_map_point(matrix, x, y, &x, &y);
+      cb.move(&cb, x, y);
+   }
+
+   if (!arc->is_valid) {
+      VGfloat x = arc->x2;
+      VGfloat y = arc->y2;
+      matrix_map_point(matrix, x, y, &x, &y);
+      cb.point(&cb, x, y);
+      return;
+   }
+
+   /* find the number of Bézier curves needed */
+   n = num_beziers_needed(arc);
+
+   d_eta = (arc->eta2 - arc->eta1) / n;
+   eta_b = arc->eta1;
+
+   cos_eta_b  = cos(eta_b);
+   sin_eta_b  = sin(eta_b);
+   a_cos_eta_b = arc->a * cos_eta_b;
+   b_sin_eta_b = arc->b * sin_eta_b;
+   a_sin_eta_b = arc->a * sin_eta_b;
+   b_cos_eta_b = arc->b * cos_eta_b;
+   x_b       = arc->cx + a_cos_eta_b * arc->cos_theta -
+               b_sin_eta_b * arc->sin_theta;
+   y_b       = arc->cy + a_cos_eta_b * arc->sin_theta +
+               b_sin_eta_b * arc->cos_theta;
+   x_b_dot    = -a_sin_eta_b * arc->cos_theta -
+                b_cos_eta_b * arc->sin_theta;
+   y_b_dot    = -a_sin_eta_b * arc->sin_theta +
+                b_cos_eta_b * arc->cos_theta;
+
+   {
+      VGfloat x = x_b, y = y_b;
+      matrix_map_point(matrix, x, y, &x, &y);
+      cb.point(&cb, x, y);
+   }
+   lx = x_b;
+   ly = y_b;
+
+   t     = tan(0.5 * d_eta);
+   alpha = sin(d_eta) * (sqrt(4 + 3 * t * t) - 1) / 3;
+
+   for (int i = 0; i < n; ++i) {
+      struct bezier bezier;
+      double xA    = x_b;
+      double yA    = y_b;
+      double xADot = x_b_dot;
+      double yADot = y_b_dot;
+
+      eta_b    += d_eta;
+      cos_eta_b  = cos(eta_b);
+      sin_eta_b  = sin(eta_b);
+      a_cos_eta_b = arc->a * cos_eta_b;
+      b_sin_eta_b = arc->b * sin_eta_b;
+      a_sin_eta_b = arc->a * sin_eta_b;
+      b_cos_eta_b = arc->b * cos_eta_b;
+      x_b       = arc->cx + a_cos_eta_b * arc->cos_theta -
+                  b_sin_eta_b * arc->sin_theta;
+      y_b       = arc->cy + a_cos_eta_b * arc->sin_theta +
+                  b_sin_eta_b * arc->cos_theta;
+      x_b_dot    = -a_sin_eta_b * arc->cos_theta -
+                   b_cos_eta_b * arc->sin_theta;
+      y_b_dot    = -a_sin_eta_b * arc->sin_theta +
+                   b_cos_eta_b * arc->cos_theta;
+
+      bezier_init(&bezier,
+                  lx, ly,
+                  (float) (xA + alpha * xADot), (float) (yA + alpha * yADot),
+                  (float) (x_b - alpha * x_b_dot), (float) (y_b - alpha * y_b_dot),
+                  (float) x_b,                   (float) y_b);
+#if 0
+      debug_printf("%d) Bezier (%f, %f), (%f, %f), (%f, %f), (%f, %f)\n",
+                   i,
+                   bezier.x1, bezier.y1,
+                   bezier.x2, bezier.y2,
+                   bezier.x3, bezier.y3,
+                   bezier.x4, bezier.y4);
+#endif
+      bezier_transform(&bezier, matrix);
+      cb.bezier(&cb, &bezier);
+      lx = x_b;
+      ly = y_b;
+   }
+}
+
+
+void arc_add_to_polygon(struct arc *arc,
+                        struct polygon *poly,
+                        struct matrix *matrix)
+{
+   struct arc_cb cb;
+
+   cb.move = cb_null_move;
+   cb.point = polygon_point;
+   cb.bezier = polygon_bezier;
+   cb.user_data = poly;
+
+   arc_to_beziers(arc, cb, matrix);
+}
+
+void arc_stroke_cb(struct arc *arc,
+                   struct stroker *stroke,
+                   struct matrix *matrix)
+{
+   struct arc_cb cb;
+
+   cb.move = cb_null_move;
+   cb.point = stroke_point;
+   cb.bezier = stroke_curve;
+   cb.user_data = stroke;
+
+   arc_to_beziers(arc, cb, matrix);
+}
+
+void arc_stroker_emit(struct arc *arc,
+                      struct stroker *stroker,
+                      struct matrix *matrix)
+{
+   struct arc_cb cb;
+
+   cb.move = cb_null_move;
+   cb.point = stroke_emit_point;
+   cb.bezier = stroke_emit_curve;
+   cb.user_data = stroker;
+
+   arc_to_beziers(arc, cb, matrix);
+}
+
+void arc_to_path(struct arc *arc,
+                 struct path *path,
+                 struct matrix *matrix)
+{
+   struct arc_cb cb;
+
+   cb.move = arc_path_move;
+   cb.point = arc_path_point;
+   cb.bezier = arc_path_bezier;
+   cb.user_data = path;
+
+   arc_to_beziers(arc, cb, matrix);
+}
diff --git a/src/gallium/state_trackers/vega/arc.h b/src/gallium/state_trackers/vega/arc.h
new file mode 100644 (file)
index 0000000..3205cd5
--- /dev/null
@@ -0,0 +1,80 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#ifndef ARC_H
+#define ARC_H
+
+#include "VG/openvg.h"
+
+struct polygon;
+struct matrix;
+struct stroker;
+struct path;
+
+struct arc {
+   VGPathSegment type;
+
+   VGfloat cx, cy;
+
+   VGfloat a, b;
+
+   VGfloat theta;
+   VGfloat cos_theta, sin_theta;
+
+   VGfloat eta1;
+   VGfloat eta2;
+
+   VGfloat x1, y1, x2, y2;
+
+   VGboolean is_valid;
+};
+
+void arc_init(struct arc *arc,
+              VGPathSegment type,
+              VGfloat x1, VGfloat y1,
+              VGfloat x2, VGfloat y2,
+              VGfloat rh, VGfloat rv,
+              VGfloat rot);
+
+void arc_add_to_polygon(struct arc *arc,
+                        struct polygon *poly,
+                        struct matrix *matrix);
+
+
+void arc_to_path(struct arc *arc,
+                 struct path *p,
+                 struct matrix *matrix);
+
+void arc_stroke_cb(struct arc *arc,
+                   struct stroker *stroke,
+                   struct matrix *matrix);
+
+void arc_stroker_emit(struct arc *arc,
+                      struct stroker *stroke,
+                      struct matrix *matrix);
+
+
+#endif
diff --git a/src/gallium/state_trackers/vega/asm_fill.h b/src/gallium/state_trackers/vega/asm_fill.h
new file mode 100644 (file)
index 0000000..2f394ad
--- /dev/null
@@ -0,0 +1,246 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#ifndef ASM_FILL_H
+#define ASM_FILL_H
+
+static const char solid_fill_asm[] =
+   "MOV %s, CONST[0]\n";
+
+
+static const char linear_grad_asm[] =
+   "MOV TEMP[0].xy, IN[0]\n"
+   "MOV TEMP[0].z, CONST[1].yyyy\n"
+   "DP3 TEMP[1], CONST[2], TEMP[0]\n"
+   "DP3 TEMP[2], CONST[3], TEMP[0]\n"
+   "DP3 TEMP[3], CONST[4], TEMP[0]\n"
+   "RCP TEMP[3], TEMP[3]\n"
+   "MUL TEMP[1], TEMP[1], TEMP[3]\n"
+   "MUL TEMP[2], TEMP[2], TEMP[3]\n"
+   "MOV TEMP[4].x, TEMP[1]\n"
+   "MOV TEMP[4].y, TEMP[2]\n"
+   "MUL TEMP[0], CONST[0].yyyy, TEMP[4].yyyy\n"
+   "MAD TEMP[1], CONST[0].xxxx, TEMP[4].xxxx, TEMP[0]\n"
+   "MUL TEMP[2], TEMP[1], CONST[0].zzzz\n"
+   "TEX %s, TEMP[2], SAMP[0], 1D\n";
+
+static const char radial_grad_asm[] =
+   "MOV TEMP[0].xy, IN[0]\n"
+   "MOV TEMP[0].z, CONST[1].yyyy\n"
+   "DP3 TEMP[1], CONST[2], TEMP[0]\n"
+   "DP3 TEMP[2], CONST[3], TEMP[0]\n"
+   "DP3 TEMP[3], CONST[4], TEMP[0]\n"
+   "RCP TEMP[3], TEMP[3]\n"
+   "MUL TEMP[1], TEMP[1], TEMP[3]\n"
+   "MUL TEMP[2], TEMP[2], TEMP[3]\n"
+   "MOV TEMP[5].x, TEMP[1]\n"
+   "MOV TEMP[5].y, TEMP[2]\n"
+   "MUL TEMP[0], CONST[0].yyyy, TEMP[5].yyyy\n"
+   "MAD TEMP[1], CONST[0].xxxx, TEMP[5].xxxx, TEMP[0]\n"
+   "ADD TEMP[1], TEMP[1], TEMP[1]\n"
+   "MUL TEMP[3], TEMP[5].yyyy, TEMP[5].yyyy\n"
+   "MAD TEMP[4], TEMP[5].xxxx, TEMP[5].xxxx, TEMP[3]\n"
+   "MOV TEMP[4], -TEMP[4]\n"
+   "MUL TEMP[2], CONST[0].zzzz, TEMP[4]\n"
+   "MUL TEMP[0], CONST[1].wwww, TEMP[2]\n"
+   "MUL TEMP[3], TEMP[1], TEMP[1]\n"
+   "SUB TEMP[2], TEMP[3], TEMP[0]\n"
+   "RSQ TEMP[2], |TEMP[2]|\n"
+   "RCP TEMP[2], TEMP[2]\n"
+   "SUB TEMP[1], TEMP[2], TEMP[1]\n"
+   "ADD TEMP[0], CONST[0].zzzz, CONST[0].zzzz\n"
+   "RCP TEMP[0], TEMP[0]\n"
+   "MUL TEMP[2], TEMP[1], TEMP[0]\n"
+   "TEX %s, TEMP[2], SAMP[0], 1D\n";
+
+static const char pattern_asm[] =
+   "MOV TEMP[0].xy, IN[0]\n"
+   "MOV TEMP[0].z, CONST[1].yyyy\n"
+   "DP3 TEMP[1], CONST[2], TEMP[0]\n"
+   "DP3 TEMP[2], CONST[3], TEMP[0]\n"
+   "DP3 TEMP[3], CONST[4], TEMP[0]\n"
+   "RCP TEMP[3], TEMP[3]\n"
+   "MUL TEMP[1], TEMP[1], TEMP[3]\n"
+   "MUL TEMP[2], TEMP[2], TEMP[3]\n"
+   "MOV TEMP[4].x, TEMP[1]\n"
+   "MOV TEMP[4].y, TEMP[2]\n"
+   "RCP TEMP[0], CONST[1].zwzw\n"
+   "MOV TEMP[1], TEMP[4]\n"
+   "MUL TEMP[1].x, TEMP[1], TEMP[0]\n"
+   "MUL TEMP[1].y, TEMP[1], TEMP[0]\n"
+   "TEX %s, TEMP[1], SAMP[0], 2D\n";
+
+
+static const char mask_asm[] =
+   "TEX TEMP[1], IN[0], SAMP[1], 2D\n"
+   "MUL TEMP[0].w, TEMP[0].wwww, TEMP[1].wwww\n"
+   "MOV %s, TEMP[0]\n";
+
+
+static const char image_normal_asm[] =
+   "TEX %s, IN[1], SAMP[3], 2D\n";
+
+static const char image_multiply_asm[] =
+   "TEX TEMP[1], IN[1], SAMP[3], 2D\n"
+   "MUL %s, TEMP[0], TEMP[1]\n";
+
+static const char image_stencil_asm[] =
+   "TEX TEMP[1], IN[1], SAMP[3], 2D\n"
+   "MUL %s, TEMP[0], TEMP[1]\n";
+
+
+#define EXTENDED_BLEND_OVER                     \
+   "SUB TEMP[3], CONST[1].yyyy, TEMP[1].wwww\n" \
+   "SUB TEMP[4], CONST[1].yyyy, TEMP[0].wwww\n" \
+   "MUL TEMP[3], TEMP[0], TEMP[3]\n"            \
+   "MUL TEMP[4], TEMP[1], TEMP[4]\n"            \
+   "ADD TEMP[3], TEMP[3], TEMP[4]\n"
+
+static const char blend_multiply_asm[] =
+   "TEX TEMP[1], IN[0], SAMP[2], 2D\n"
+   EXTENDED_BLEND_OVER
+   "MUL TEMP[4], TEMP[0], TEMP[1]\n"
+   "ADD TEMP[1], TEMP[4], TEMP[3]\n"/*result.rgb*/
+   "MUL TEMP[2], TEMP[0].wwww, TEMP[1].wwww\n"
+   "ADD TEMP[3], TEMP[0].wwww, TEMP[1].wwww\n"
+   "SUB TEMP[1].w, TEMP[3], TEMP[2]\n"
+   "MOV %s, TEMP[1]\n";
+#if 1
+static const char blend_screen_asm[] =
+   "TEX TEMP[1], IN[0], SAMP[2], 2D\n"
+   "ADD TEMP[3], TEMP[0], TEMP[1]\n"
+   "MUL TEMP[2], TEMP[0], TEMP[1]\n"
+   "SUB %s, TEMP[3], TEMP[2]\n";
+#else
+static const char blend_screen_asm[] =
+   "TEX TEMP[1], IN[0], SAMP[2], 2D\n"
+   "MOV %s, TEMP[1]\n";
+#endif
+
+static const char blend_darken_asm[] =
+   "TEX TEMP[1], IN[0], SAMP[2], 2D\n"
+   EXTENDED_BLEND_OVER
+   "MUL TEMP[4], TEMP[0], TEMP[1].wwww\n"
+   "MUL TEMP[5], TEMP[1], TEMP[0].wwww\n"
+   "MIN TEMP[4], TEMP[4], TEMP[5]\n"
+   "ADD TEMP[1], TEMP[3], TEMP[4]\n"
+   "MUL TEMP[2], TEMP[0].wwww, TEMP[1].wwww\n"
+   "ADD TEMP[3], TEMP[0].wwww, TEMP[1].wwww\n"
+   "SUB TEMP[1].w, TEMP[3], TEMP[2]\n"
+   "MOV %s, TEMP[1]\n";
+
+static const char blend_lighten_asm[] =
+   "TEX TEMP[1], IN[0], SAMP[2], 2D\n"
+   EXTENDED_BLEND_OVER
+   "MUL TEMP[4], TEMP[0], TEMP[1].wwww\n"
+   "MUL TEMP[5], TEMP[1], TEMP[0].wwww\n"
+   "MAX TEMP[4], TEMP[4], TEMP[5]\n"
+   "ADD TEMP[1], TEMP[3], TEMP[4]\n"
+   "MUL TEMP[2], TEMP[0].wwww, TEMP[1].wwww\n"
+   "ADD TEMP[3], TEMP[0].wwww, TEMP[1].wwww\n"
+   "SUB TEMP[1].w, TEMP[3], TEMP[2]\n"
+   "MOV %s, TEMP[1]\n";
+
+
+static const char premultiply_asm[] =
+   "MUL TEMP[0].xyz, TEMP[0], TEMP[0].wwww\n";
+
+static const char unpremultiply_asm[] =
+   "TEX TEMP[0], IN[0], SAMP[1], 2D\n";
+
+
+static const char color_bw_asm[] =
+   "ADD TEMP[1], CONST[1].yyyy, CONST[1].yyyy\n"
+   "RCP TEMP[2], TEMP[1]\n"
+   "ADD TEMP[1], CONST[1].yyyy, TEMP[2]\n"
+   "ADD TEMP[2].x, TEMP[0].xxxx, TEMP[0].yyyy\n"
+   "ADD TEMP[2].x, TEMP[0].zzzz, TEMP[0].xxxx\n"
+   "SGE TEMP[0].xyz, TEMP[2].xxxx, TEMP[1]\n"
+   "SGE TEMP[0].w, TEMP[0].wwww, TEMP[2].yyyy\n"
+   "MOV %s, TEMP[0]\n";
+
+
+struct shader_asm_info {
+   VGint id;
+   VGint num_tokens;
+   const char * txt;
+
+   VGboolean needs_position;
+
+   VGint start_const;
+   VGint num_consts;
+
+   VGint start_sampler;
+   VGint num_samplers;
+
+   VGint start_temp;
+   VGint num_temps;
+};
+
+
+static const struct shader_asm_info shaders_asm[] = {
+   /* fills */
+   {VEGA_SOLID_FILL_SHADER,       40,  solid_fill_asm,
+    VG_FALSE, 0, 1, 0, 0, 0, 0},
+   {VEGA_LINEAR_GRADIENT_SHADER, 200,  linear_grad_asm,
+    VG_TRUE,  0, 5, 0, 1, 0, 5},
+   {VEGA_RADIAL_GRADIENT_SHADER, 200,  radial_grad_asm,
+    VG_TRUE,  0, 5, 0, 1, 0, 6},
+   {VEGA_PATTERN_SHADER,         100,      pattern_asm,
+    VG_TRUE,  1, 4, 0, 1, 0, 5},
+
+   /* image draw modes */
+   {VEGA_IMAGE_NORMAL_SHADER,    200, image_normal_asm,
+    VG_TRUE,  0, 0, 3, 1, 0, 0},
+   {VEGA_IMAGE_MULTIPLY_SHADER,  200, image_multiply_asm,
+    VG_TRUE,  0, 0, 3, 1, 0, 2},
+   {VEGA_IMAGE_STENCIL_SHADER,   200, image_stencil_asm,
+    VG_TRUE,  0, 0, 3, 1, 0, 2},
+
+   {VEGA_MASK_SHADER,            100,         mask_asm,
+    VG_TRUE,  0, 0, 1, 1, 0, 2},
+
+   /* extra blend modes */
+   {VEGA_BLEND_MULTIPLY_SHADER,  200, blend_multiply_asm,
+    VG_TRUE,  1, 1, 2, 1, 0, 5},
+   {VEGA_BLEND_SCREEN_SHADER,    200, blend_screen_asm,
+    VG_TRUE,  0, 0, 2, 1, 0, 4},
+   {VEGA_BLEND_DARKEN_SHADER,    200, blend_darken_asm,
+    VG_TRUE,  1, 1, 2, 1, 0, 6},
+   {VEGA_BLEND_LIGHTEN_SHADER,   200, blend_lighten_asm,
+    VG_TRUE,  1, 1, 2, 1, 0, 6},
+
+   /* premultiply */
+   {VEGA_PREMULTIPLY_SHADER,   100, premultiply_asm,
+    VG_FALSE,  0, 0, 0, 0, 0, 1},
+   {VEGA_UNPREMULTIPLY_SHADER,   100, unpremultiply_asm,
+    VG_FALSE,  0, 0, 0, 0, 0, 1},
+
+   /* color transform to black and white */
+   {VEGA_BW_SHADER,   150, color_bw_asm,
+    VG_FALSE,  1, 1, 0, 0, 0, 3},
+};
+#endif
diff --git a/src/gallium/state_trackers/vega/asm_filters.h b/src/gallium/state_trackers/vega/asm_filters.h
new file mode 100644 (file)
index 0000000..49807b9
--- /dev/null
@@ -0,0 +1,117 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#ifndef ASM_FILTERS_H
+#define ASM_FILTERS_H
+
+static const char color_matrix_asm[] =
+   "FRAG1.1\n"
+   "DCL IN[0], GENERIC[0], PERSPECTIVE\n"
+   "DCL OUT[0], COLOR, CONSTANT\n"
+   "DCL CONST[0..4], CONSTANT\n"
+   "DCL TEMP[0..4], CONSTANT\n"
+   "DCL SAMP[0], CONSTANT\n"
+   "TEX TEMP[0], IN[0], SAMP[0], 2D\n"
+   "MOV TEMP[1], TEMP[0].xxxx\n"
+   "MOV TEMP[2], TEMP[0].yyyy\n"
+   "MOV TEMP[3], TEMP[0].zzzz\n"
+   "MOV TEMP[4], TEMP[0].wwww\n"
+   "MUL TEMP[1], TEMP[1], CONST[0]\n"
+   "MUL TEMP[2], TEMP[2], CONST[1]\n"
+   "MUL TEMP[3], TEMP[3], CONST[2]\n"
+   "MUL TEMP[4], TEMP[4], CONST[3]\n"
+   "ADD TEMP[0], TEMP[1], CONST[4]\n"
+   "ADD TEMP[0], TEMP[0], TEMP[2]\n"
+   "ADD TEMP[0], TEMP[0], TEMP[3]\n"
+   "ADD TEMP[0], TEMP[0], TEMP[4]\n"
+   "MOV OUT[0], TEMP[0]\n"
+   "END\n";
+
+static const char convolution_asm[] =
+   "FRAG1.1\n"
+   "DCL IN[0], GENERIC[0], PERSPECTIVE\n"
+   "DCL OUT[0], COLOR, CONSTANT\n"
+   "DCL TEMP[0..4], CONSTANT\n"
+   "DCL ADDR[0], CONSTANT\n"
+   "DCL CONST[0..%d], CONSTANT\n"
+   "DCL SAMP[0], CONSTANT\n"
+   "0: MOV TEMP[0], CONST[0].xxxx\n"
+   "1: MOV TEMP[1], CONST[0].xxxx\n"
+   "2: BGNLOOP2 :14\n"
+   "3: SGE TEMP[0].z, TEMP[0].yyyy, CONST[1].xxxx\n"
+   "4: IF TEMP[0].zzzz :7\n"
+   "5: BRK\n"
+   "6: ENDIF\n"
+   "7: ARL ADDR[0].x, TEMP[0].yyyy\n"
+   "8: MOV TEMP[3], CONST[ADDR[0]+2]\n"
+   "9: ADD TEMP[4].xy, IN[0], TEMP[3]\n"
+   "10: TEX TEMP[2], TEMP[4], SAMP[0], 2D\n"
+   "11: MOV TEMP[3], CONST[ADDR[0]+%d]\n"
+   "12: MAD TEMP[1], TEMP[2], TEMP[3], TEMP[1]\n"
+   "13: ADD TEMP[0].y, TEMP[0].yyyy, CONST[0].yyyy\n"
+   "14: ENDLOOP2 :2\n"
+   "15: MAD OUT[0], TEMP[1], CONST[1].yyyy, CONST[1].zzzz\n"
+   "16: END\n";
+
+
+static const char lookup_asm[] =
+   "FRAG1.1\n"
+   "DCL IN[0], GENERIC[0], PERSPECTIVE\n"
+   "DCL OUT[0], COLOR, CONSTANT\n"
+   "DCL TEMP[0..2], CONSTANT\n"
+   "DCL CONST[0], CONSTANT\n"
+   "DCL SAMP[0..1], CONSTANT\n"
+   "TEX TEMP[0], IN[0], SAMP[0], 2D\n"
+   "MOV TEMP[1], TEMP[0]\n"
+   /* do red */
+   "TEX TEMP[2], TEMP[1].xxxx, SAMP[1], 1D\n"
+   "MOV TEMP[0].x, TEMP[2].xxxx\n"
+   /* do blue */
+   "TEX TEMP[2], TEMP[1].yyyy, SAMP[1], 1D\n"
+   "MOV TEMP[0].y, TEMP[2].yyyy\n"
+   /* do green */
+   "TEX TEMP[2], TEMP[1].zzzz, SAMP[1], 1D\n"
+   "MOV TEMP[0].z, TEMP[2].zzzz\n"
+   /* do alpha */
+   "TEX TEMP[2], TEMP[1].wwww, SAMP[1], 1D\n"
+   "MOV TEMP[0].w, TEMP[2].wwww\n"
+   "MOV OUT[0], TEMP[0]\n"
+   "END\n";
+
+
+static const char lookup_single_asm[] =
+   "FRAG1.1\n"
+   "DCL IN[0], GENERIC[0], PERSPECTIVE\n"
+   "DCL OUT[0], COLOR, CONSTANT\n"
+   "DCL TEMP[0..2], CONSTANT\n"
+   "DCL CONST[0], CONSTANT\n"
+   "DCL SAMP[0..1], CONSTANT\n"
+   "TEX TEMP[0], IN[0], SAMP[0], 2D\n"
+   "TEX TEMP[1], TEMP[0].%s, SAMP[1], 1D\n"
+   "MOV OUT[0], TEMP[1]\n"
+   "END\n";
+
+#endif
diff --git a/src/gallium/state_trackers/vega/asm_util.h b/src/gallium/state_trackers/vega/asm_util.h
new file mode 100644 (file)
index 0000000..218e1d1
--- /dev/null
@@ -0,0 +1,136 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#ifndef ASM_UTIL_H
+#define ASM_UTIL_H
+
+
+static const char pass_through_depth_asm[] =
+   "FRAG1.1\n"
+   "DCL IN[0], POSITION, LINEAR\n"
+   "DCL OUT[0].z, POSITION, CONSTANT\n"
+   "0: MOV OUT[0].z, IN[0].zzzz\n"
+   "1: END\n";
+
+
+
+/* Î¼new = Î¼mask */
+static const char set_mask_asm[] =
+   "FRAG1.1\n"
+   "DCL IN[0], GENERIC[0], PERSPECTIVE\n"
+   "DCL SAMP[0], CONSTANT\n"
+   "DCL OUT[0], COLOR, CONSTANT\n"
+   "0: TEX OUT[0], IN[0], SAMP[0], 2D\n"/*umask*/
+   "1: END\n";
+
+/* Î¼new = 1 â€“ (1 â€“ Î¼mask)*(1 â€“ Î¼prev) */
+static const char union_mask_asm[] =
+   "FRAG1.1\n"
+   "DCL IN[0], GENERIC[0], PERSPECTIVE\n"
+   "DCL IN[1], POSITION, LINEAR\n"
+   "DCL CONST[0], CONSTANT\n"
+   "DCL SAMP[0..1], CONSTANT\n"
+   "DCL TEMP[0..3], CONSTANT\n"
+   "DCL OUT[0], COLOR, CONSTANT\n"
+   "0: TEX TEMP[1], IN[0], SAMP[0], 2D\n"/*umask*/
+   "1: TEX TEMP[0], IN[1], SAMP[1], 2D\n"/*uprev*/
+   "2: SUB TEMP[2], CONST[0], TEMP[0]\n"
+   "3: SUB TEMP[3], CONST[0], TEMP[1]\n"
+   "4: MUL TEMP[0].w, TEMP[2].wwww, TEMP[3].wwww\n"
+   "5: SUB OUT[0], CONST[0], TEMP[0]\n"
+   "6: END\n";
+
+/* Î¼new = Î¼mask *μprev */
+static const char intersect_mask_asm[] =
+   "FRAG1.1\n"
+   "DCL IN[0], GENERIC[0], PERSPECTIVE\n"
+   "DCL IN[1], POSITION, LINEAR\n"
+   "DCL CONST[0], CONSTANT\n"
+   "DCL SAMP[0..1], CONSTANT\n"
+   "DCL TEMP[0..1], CONSTANT\n"
+   "DCL OUT[0], COLOR, CONSTANT\n"
+   "0: TEX TEMP[0], IN[1], SAMP[1], 2D\n"/*uprev*/
+   "1: TEX TEMP[1], IN[0], SAMP[0], 2D\n"/*umask*/
+   "2: MUL OUT[0], TEMP[0].wwww, TEMP[1].wwww\n"
+   "3: END\n";
+
+/* Î¼new = Î¼prev*(1 â€“ Î¼mask) */
+static const char subtract_mask_asm[] =
+   "FRAG1.1\n"
+   "DCL IN[0], GENERIC[0], PERSPECTIVE\n"
+   "DCL IN[1], POSITION, LINEAR\n"
+   "DCL CONST[0], CONSTANT\n"
+   "DCL SAMP[0..1], CONSTANT\n"
+   "DCL TEMP[0..2], CONSTANT\n"
+   "DCL OUT[0], COLOR, CONSTANT\n"
+   "0: TEX TEMP[1], IN[0], SAMP[0], 2D\n"/*umask*/
+   "1: TEX TEMP[0], IN[1], SAMP[1], 2D\n"/*uprev*/
+   "2: SUB TEMP[2], CONST[0], TEMP[1]\n"
+   "3: MUL OUT[0], TEMP[2].wwww, TEMP[0].wwww\n"
+   "4: END\n";
+
+
+static const char vs_plain_asm[] =
+   "VERT1.1\n"
+   "DCL IN[0]\n"
+   "DCL OUT[0], POSITION\n"
+   "DCL TEMP[0]\n"
+   "DCL CONST[0..1]\n"
+   "0: MUL TEMP[0], IN[0], CONST[0]\n"
+   "1: ADD TEMP[0], TEMP[0], CONST[1]\n"
+   "2: MOV OUT[0], TEMP[0]\n"
+   "3: END\n";
+
+static const char vs_clear_asm[] =
+   "VERT1.1\n"
+   "DCL IN[0]\n"
+   "DCL IN[1]\n"
+   "DCL OUT[0], POSITION\n"
+   "DCL OUT[1], COLOR\n"
+   "DCL TEMP[0]\n"
+   "DCL CONST[0..1]\n"
+   "0: MUL TEMP[0], IN[0], CONST[0]\n"
+   "1: ADD TEMP[0], TEMP[0], CONST[1]\n"
+   "2: MOV OUT[0], TEMP[0]\n"
+   "3: MOV OUT[1], IN[1]\n"
+   "4: END\n";
+
+
+static const char vs_texture_asm[] =
+   "VERT1.1\n"
+   "DCL IN[0]\n"
+   "DCL IN[1]\n"
+   "DCL OUT[0], POSITION\n"
+   "DCL OUT[1], GENERIC\n"
+   "DCL TEMP[0]\n"
+   "DCL CONST[0..1]\n"
+   "0: MUL TEMP[0], IN[0], CONST[0]\n"
+   "1: ADD TEMP[0], TEMP[0], CONST[1]\n"
+   "2: MOV OUT[0], TEMP[0]\n"
+   "3: MOV OUT[1], IN[1]\n"
+   "4: END\n";
+
+#endif
diff --git a/src/gallium/state_trackers/vega/bezier.c b/src/gallium/state_trackers/vega/bezier.c
new file mode 100644 (file)
index 0000000..39a7ade
--- /dev/null
@@ -0,0 +1,704 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#include "bezier.h"
+
+#include "matrix.h"
+#include "polygon.h"
+
+#include "pipe/p_compiler.h"
+#include "util/u_debug.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <math.h>
+
+static const float flatness = 0.5;
+
+
+static INLINE void split_left(struct bezier *bez, VGfloat t, struct bezier* left)
+{
+    left->x1 = bez->x1;
+    left->y1 = bez->y1;
+
+    left->x2 = bez->x1 + t * (bez->x2 - bez->x1);
+    left->y2 = bez->y1 + t * (bez->y2 - bez->y1);
+
+    left->x3 = bez->x2 + t * (bez->x3 - bez->x2);
+    left->y3 = bez->y2 + t * (bez->y3 - bez->y2);
+
+    bez->x3 = bez->x3 + t * (bez->x4 - bez->x3);
+    bez->y3 = bez->y3 + t * (bez->y4 - bez->y3);
+
+    bez->x2 = left->x3 + t * (bez->x3 - left->x3);
+    bez->y2 = left->y3 + t * (bez->y3 - left->y3);
+
+    left->x3 = left->x2 + t * (left->x3 - left->x2);
+    left->y3 = left->y2 + t * (left->y3 - left->y2);
+
+    left->x4 = bez->x1 = left->x3 + t * (bez->x2 - left->x3);
+    left->y4 = bez->y1 = left->y3 + t * (bez->y2 - left->y3);
+}
+
+static INLINE void split(struct bezier *bez,
+                         struct bezier *first_half,
+                         struct bezier *second_half)
+{
+   double c         = (bez->x2 + bez->x3) * 0.5;
+   first_half->x2  = (bez->x1 + bez->x2) * 0.5;
+   second_half->x3 = (bez->x3 + bez->x4) * 0.5;
+   first_half->x1  = bez->x1;
+   second_half->x4 = bez->x4;
+   first_half->x3  = (first_half->x2 + c) * 0.5;
+   second_half->x2 = (second_half->x3 + c) * 0.5;
+   first_half->x4  = second_half->x1 =
+                     (first_half->x3 + second_half->x2) * 0.5;
+
+   c = (bez->y2 + bez->y3) / 2;
+   first_half->y2  = (bez->y1 + bez->y2) * 0.5;
+   second_half->y3 = (bez->y3 + bez->y4) * 0.5;
+   first_half->y1  = bez->y1;
+   second_half->y4 = bez->y4;
+   first_half->y3  = (first_half->y2 + c) * 0.5;
+   second_half->y2 = (second_half->y3 + c) * 0.5;
+   first_half->y4  = second_half->y1 =
+                     (first_half->y3 + second_half->y2) * 0.5;
+}
+
+struct polygon * bezier_to_polygon(struct bezier *bez)
+{
+   struct polygon *poly = polygon_create(64);
+   polygon_vertex_append(poly, bez->x1, bez->y1);
+   bezier_add_to_polygon(bez, poly);
+   return poly;
+}
+
+void bezier_add_to_polygon(const struct bezier *bez,
+                           struct polygon *poly)
+{
+   struct bezier beziers[32];
+   struct bezier *b;
+
+   beziers[0] = *bez;
+   b = beziers;
+
+   while (b >= beziers) {
+      double y4y1 = b->y4 - b->y1;
+      double x4x1 = b->x4 - b->x1;
+      double l = ABS(x4x1) + ABS(y4y1);
+      double d;
+      if (l > 1.f) {
+         d = ABS((x4x1)*(b->y1 - b->y2) - (y4y1)*(b->x1 - b->x2))
+             + ABS((x4x1)*(b->y1 - b->y3) - (y4y1)*(b->x1 - b->x3));
+      } else {
+         d = ABS(b->x1 - b->x2) + ABS(b->y1 - b->y2) +
+             ABS(b->x1 - b->x3) + ABS(b->y1 - b->y3);
+         l = 1.;
+      }
+      if (d < flatness*l || b == beziers + 31) {
+         /* good enough, we pop it off and add the endpoint */
+         polygon_vertex_append(poly, b->x4, b->y4);
+         --b;
+      } else {
+         /* split, second half of the bezier goes lower into the stack */
+         split(b, b+1, b);
+         ++b;
+      }
+   }
+}
+
+static void add_if_close(struct bezier *bez, VGfloat *length, VGfloat error)
+{
+   struct bezier left, right;     /* bez poly splits */
+   VGfloat len = 0.0;        /* arc length */
+   VGfloat chord;            /* chord length */
+
+   len = len + line_length(bez->x1, bez->y1, bez->x2, bez->y2);
+   len = len + line_length(bez->x2, bez->y2, bez->x3, bez->y3);
+   len = len + line_length(bez->x3, bez->y3, bez->x4, bez->y4);
+
+   chord = line_length(bez->x1, bez->y1, bez->x4, bez->y4);
+
+   if ((len-chord) > error) {
+      split(bez, &left, &right);                 /* split in two */
+      add_if_close(&left, length, error);       /* try left side */
+      add_if_close(&right, length, error);      /* try right side */
+      return;
+   }
+
+   *length = *length + len;
+
+   return;
+}
+
+float bezier_length(struct bezier *bez, float error)
+{
+   VGfloat length = 0.f;
+
+   add_if_close(bez, &length, error);
+   return length;
+}
+
+void bezier_init(struct bezier *bez,
+                 float x1, float y1,
+                 float x2, float y2,
+                 float x3, float y3,
+                 float x4, float y4)
+{
+   bez->x1 = x1;
+   bez->y1 = y1;
+   bez->x2 = x2;
+   bez->y2 = y2;
+   bez->x3 = x3;
+   bez->y3 = y3;
+   bez->x4 = x4;
+   bez->y4 = y4;
+#if 0
+   debug_printf("bezier in [%f, %f, %f, %f, %f, %f]\n",
+                x1, y1, x2, y2, x3, y3, x4, y4);
+#endif
+}
+
+
+static INLINE void bezier_init2v(struct bezier *bez,
+                                 float *pt1,
+                                 float *pt2,
+                                 float *pt3,
+                                 float *pt4)
+{
+   bez->x1 = pt1[0];
+   bez->y1 = pt1[1];
+
+   bez->x2 = pt2[0];
+   bez->y2 = pt2[1];
+
+   bez->x3 = pt3[0];
+   bez->y3 = pt3[1];
+
+   bez->x4 = pt4[0];
+   bez->y4 = pt4[1];
+}
+
+
+void bezier_transform(struct bezier *bez,
+                      struct matrix *matrix)
+{
+   assert(matrix_is_affine(matrix));
+   matrix_map_point(matrix, bez->x1, bez->y1, &bez->x1, &bez->y1);
+   matrix_map_point(matrix, bez->x2, bez->y2, &bez->x2, &bez->y2);
+   matrix_map_point(matrix, bez->x3, bez->y3, &bez->x3, &bez->y3);
+   matrix_map_point(matrix, bez->x4, bez->y4, &bez->x4, &bez->y4);
+}
+
+static INLINE void bezier_point_at(const struct bezier *bez, float t, float *pt)
+{
+   float a, b, c, d;
+   float m_t;
+   m_t = 1. - t;
+   b = m_t * m_t;
+   c = t * t;
+   d = c * t;
+   a = b * m_t;
+   b *= 3. * t;
+   c *= 3. * m_t;
+   pt[0] = a*bez->x1 + b*bez->x2 + c*bez->x3 + d*bez->x4;
+   pt[1] = a*bez->y1 + b*bez->y2 + c*bez->y3 + d*bez->y4;
+}
+
+static INLINE void bezier_normal_at(const struct bezier *bez, float t, float *norm)
+{
+   float m_t = 1. - t;
+   float a = m_t * m_t;
+   float b = t * m_t;
+   float c = t * t;
+
+   norm[0] =  (bez->y2-bez->y1) * a + (bez->y3-bez->y2) * b + (bez->y4-bez->y3) * c;
+   norm[1] = -(bez->x2-bez->x1) * a - (bez->x3-bez->x2) * b - (bez->x4-bez->x3) * c;
+}
+
+enum shift_result {
+   Ok,
+   Discard,
+   Split,
+   Circle
+};
+
+static enum shift_result good_offset(const struct bezier *b1,
+                                     const struct bezier *b2,
+                                     float offset, float threshold)
+{
+   const float o2 = offset*offset;
+   const float max_dist_line = threshold*offset*offset;
+   const float max_dist_normal = threshold*offset;
+   const float spacing = 0.25;
+   for (float i = spacing; i < 0.99; i += spacing) {
+      float p1[2],p2[2], d, l;
+      float normal[2];
+      bezier_point_at(b1, i, p1);
+      bezier_point_at(b2, i, p2);
+      d = (p1[0] - p2[0])*(p1[0] - p2[0]) + (p1[1] - p2[1])*(p1[1] - p2[1]);
+      if (ABS(d - o2) > max_dist_line)
+         return Split;
+
+      bezier_normal_at(b1, i, normal);
+      l = ABS(normal[0]) + ABS(normal[1]);
+      if (l != 0.) {
+         d = ABS(normal[0]*(p1[1] - p2[1]) - normal[1]*(p1[0] - p2[0]) ) / l;
+         if (d > max_dist_normal)
+            return Split;
+      }
+   }
+   return Ok;
+}
+
+static INLINE void shift_line_by_normal(float *l, float offset)
+{
+   float norm[4];
+   float tx, ty;
+
+   line_normal(l, norm);
+   line_normalize(norm);
+
+   tx = (norm[2] - norm[0]) * offset;
+   ty = (norm[3] - norm[1]) * offset;
+   l[0] += tx; l[1] += ty;
+   l[2] += tx; l[3] += ty;
+}
+
+static INLINE VGboolean is_bezier_line(float (*points)[2], int count)
+{
+   float dx13 = points[2][0] - points[0][0];
+   float dy13 = points[2][1] - points[0][1];
+
+   float dx12 = points[1][0] - points[0][0];
+   float dy12 = points[1][1] - points[0][1];
+
+   debug_assert(count > 2);
+
+   if (count == 3) {
+      return floatsEqual(dx12 * dy13, dx13 * dy12);
+   } else if (count == 4) {
+      float dx14 = points[3][0] - points[0][0];
+      float dy14 = points[3][1] - points[0][1];
+
+      return (floatsEqual(dx12 * dy13, dx13 * dy12) &&
+              floatsEqual(dx12 * dy14, dx14 * dy12));
+   }
+
+   return VG_FALSE;
+}
+
+static INLINE void compute_pt_normal(float *pt1, float *pt2, float *res)
+{
+   float line[4];
+   float normal[4];
+   line[0] = 0.f; line[1] = 0.f;
+   line[2] = pt2[0] - pt1[0];
+   line[3] = pt2[1] - pt1[1];
+   line_normal(line, normal);
+   line_normalize(normal);
+
+   res[0] = normal[2];
+   res[1] = normal[3];
+}
+
+static enum shift_result shift(const struct bezier *orig,
+                               struct bezier *shifted,
+                               float offset, float threshold)
+{
+   int map[4];
+   VGboolean p1_p2_equal = (orig->x1 == orig->x2 && orig->y1 == orig->y2);
+   VGboolean p2_p3_equal = (orig->x2 == orig->x3 && orig->y2 == orig->y3);
+   VGboolean p3_p4_equal = (orig->x3 == orig->x4 && orig->y3 == orig->y4);
+
+   float points[4][2];
+   int np = 0;
+   float bounds[4];
+   float points_shifted[4][2];
+   float prev_normal[2];
+
+   points[np][0] = orig->x1;
+   points[np][1] = orig->y1;
+   map[0] = 0;
+   ++np;
+   if (!p1_p2_equal) {
+      points[np][0] = orig->x2;
+      points[np][1] = orig->y2;
+      ++np;
+   }
+   map[1] = np - 1;
+   if (!p2_p3_equal) {
+      points[np][0] = orig->x3;
+      points[np][1] = orig->y3;
+      ++np;
+   }
+   map[2] = np - 1;
+   if (!p3_p4_equal) {
+      points[np][0] = orig->x4;
+      points[np][1] = orig->y4;
+      ++np;
+   }
+   map[3] = np - 1;
+   if (np == 1)
+      return Discard;
+
+   /* We need to specialcase lines of 3 or 4 points due to numerical
+      instability in intersection code below */
+   if (np > 2 && is_bezier_line(points, np)) {
+      float l[4] = { points[0][0], points[0][1],
+                     points[np-1][0], points[np-1][1] };
+      float ctrl1[2], ctrl2[2];
+      if (floatsEqual(points[0][0], points[np-1][0]) &&
+          floatsEqual(points[0][1], points[np-1][1]))
+         return Discard;
+
+      shift_line_by_normal(l, offset);
+      line_point_at(l, 0.33, ctrl1);
+      line_point_at(l, 0.66, ctrl2);
+      bezier_init(shifted, l[0], l[1],
+                  ctrl1[0], ctrl1[1], ctrl2[0], ctrl2[1],
+                  l[2], l[3]);
+      return Ok;
+   }
+
+   bezier_bounds(orig, bounds);
+   if (np == 4 && bounds[2] < .1*offset && bounds[3] < .1*offset) {
+      float l = (orig->x1 - orig->x2)*(orig->x1 - orig->x2) +
+                (orig->y1 - orig->y2)*(orig->y1 - orig->y1) *
+                (orig->x3 - orig->x4)*(orig->x3 - orig->x4) +
+                (orig->y3 - orig->y4)*(orig->y3 - orig->y4);
+      float dot = (orig->x1 - orig->x2)*(orig->x3 - orig->x4) +
+                  (orig->y1 - orig->y2)*(orig->y3 - orig->y4);
+      if (dot < 0 && dot*dot < 0.8*l)
+         /* the points are close and reverse dirction. Approximate the whole
+            thing by a semi circle */
+         return Circle;
+   }
+
+   compute_pt_normal(points[0], points[1], prev_normal);
+
+   points_shifted[0][0] = points[0][0] + offset * prev_normal[0];
+   points_shifted[0][1] = points[0][1] + offset * prev_normal[1];
+
+   for (int i = 1; i < np - 1; ++i) {
+      float normal_sum[2], r;
+      float next_normal[2];
+      compute_pt_normal(points[i], points[i + 1], next_normal);
+
+      normal_sum[0] = prev_normal[0] + next_normal[0];
+      normal_sum[1] = prev_normal[1] + next_normal[1];
+
+      r = 1.0 + prev_normal[0] * next_normal[0]
+          + prev_normal[1] * next_normal[1];
+
+      if (floatsEqual(r + 1, 1)) {
+         points_shifted[i][0] = points[i][0] + offset * prev_normal[0];
+         points_shifted[i][1] = points[i][1] + offset * prev_normal[1];
+      } else {
+         float k = offset / r;
+         points_shifted[i][0] = points[i][0] + k * normal_sum[0];
+         points_shifted[i][1] = points[i][1] + k * normal_sum[1];
+      }
+
+      prev_normal[0] = next_normal[0];
+      prev_normal[1] = next_normal[1];
+   }
+
+   points_shifted[np - 1][0] = points[np - 1][0] + offset * prev_normal[0];
+   points_shifted[np - 1][1] = points[np - 1][1] + offset * prev_normal[1];
+
+   bezier_init2v(shifted,
+                 points_shifted[map[0]], points_shifted[map[1]],
+                 points_shifted[map[2]], points_shifted[map[3]]);
+
+   return good_offset(orig, shifted, offset, threshold);
+}
+
+static VGboolean make_circle(const struct bezier *b, float offset, struct bezier *o)
+{
+   float normals[3][2];
+   float dist;
+   float angles[2];
+   float sign = 1.f;
+   int i;
+   float circle[3][2];
+
+   normals[0][0] = b->y2 - b->y1;
+   normals[0][1] = b->x1 - b->x2;
+   dist = sqrt(normals[0][0]*normals[0][0] + normals[0][1]*normals[0][1]);
+   if (floatsEqual(dist + 1, 1.f))
+      return VG_FALSE;
+   normals[0][0] /= dist;
+   normals[0][1] /= dist;
+
+   normals[2][0] = b->y4 - b->y3;
+   normals[2][1] = b->x3 - b->x4;
+   dist = sqrt(normals[2][0]*normals[2][0] + normals[2][1]*normals[2][1]);
+   if (floatsEqual(dist + 1, 1.f))
+      return VG_FALSE;
+   normals[2][0] /= dist;
+   normals[2][1] /= dist;
+
+   normals[1][0] = b->x1 - b->x2 - b->x3 + b->x4;
+   normals[1][1] = b->y1 - b->y2 - b->y3 + b->y4;
+   dist = -1*sqrt(normals[1][0]*normals[1][0] + normals[1][1]*normals[1][1]);
+   normals[1][0] /= dist;
+   normals[1][1] /= dist;
+
+   for (i = 0; i < 2; ++i) {
+      float cos_a = normals[i][0]*normals[i+1][0] + normals[i][1]*normals[i+1][1];
+      if (cos_a > 1.)
+         cos_a = 1.;
+      if (cos_a < -1.)
+         cos_a = -1;
+      angles[i] = acos(cos_a)/M_PI;
+   }
+
+   if (angles[0] + angles[1] > 1.) {
+      /* more than 180 degrees */
+      normals[1][0] = -normals[1][0];
+      normals[1][1] = -normals[1][1];
+      angles[0] = 1. - angles[0];
+      angles[1] = 1. - angles[1];
+      sign = -1.;
+   }
+
+   circle[0][0] = b->x1 + normals[0][0]*offset;
+   circle[0][1] = b->y1 + normals[0][1]*offset;
+
+   circle[1][0] = 0.5*(b->x1 + b->x4) + normals[1][0]*offset;
+   circle[1][1] = 0.5*(b->y1 + b->y4) + normals[1][1]*offset;
+
+   circle[2][0] = b->x4 + normals[2][0]*offset;
+   circle[2][1] = b->y4 + normals[2][1]*offset;
+
+   for (i = 0; i < 2; ++i) {
+      float kappa = 2.*KAPPA * sign * offset * angles[i];
+
+      o->x1 = circle[i][0];
+      o->y1 = circle[i][1];
+      o->x2 = circle[i][0] - normals[i][1]*kappa;
+      o->y2 = circle[i][1] + normals[i][0]*kappa;
+      o->x3 = circle[i+1][0] + normals[i+1][1]*kappa;
+      o->y3 = circle[i+1][1] - normals[i+1][0]*kappa;
+      o->x4 = circle[i+1][0];
+      o->y4 = circle[i+1][1];
+
+      ++o;
+   }
+   return VG_TRUE;
+}
+
+int bezier_translate_by_normal(struct bezier *bez,
+                               struct bezier *curves,
+                               int max_curves,
+                               float normal_len,
+                               float threshold)
+{
+   struct bezier beziers[10];
+   struct bezier *b, *o;
+
+   /* fixme: this should really be floatsEqual */
+   if (bez->x1 == bez->x2 && bez->x1 == bez->x3 && bez->x1 == bez->x4 &&
+       bez->y1 == bez->y2 && bez->y1 == bez->y3 && bez->y1 == bez->y4)
+      return 0;
+
+   --max_curves;
+redo:
+   beziers[0] = *bez;
+   b = beziers;
+   o = curves;
+
+   while (b >= beziers) {
+      int stack_segments = b - beziers + 1;
+      enum shift_result res;
+      if ((stack_segments == 10) || (o - curves == max_curves - stack_segments)) {
+         threshold *= 1.5;
+         if (threshold > 2.)
+            goto give_up;
+         goto redo;
+      }
+      res = shift(b, o, normal_len, threshold);
+      if (res == Discard) {
+         --b;
+      } else if (res == Ok) {
+         ++o;
+         --b;
+         continue;
+      } else if (res == Circle && max_curves - (o - curves) >= 2) {
+         /* add semi circle */
+         if (make_circle(b, normal_len, o))
+            o += 2;
+         --b;
+      } else {
+         split(b, b+1, b);
+         ++b;
+      }
+   }
+
+give_up:
+   while (b >= beziers) {
+      enum shift_result res = shift(b, o, normal_len, threshold);
+
+      /* if res isn't Ok or Split then *o is undefined */
+      if (res == Ok || res == Split)
+         ++o;
+
+      --b;
+   }
+
+   debug_assert(o - curves <= max_curves);
+   return o - curves;
+}
+
+void bezier_bounds(const struct bezier *bez,
+                   float *bounds/*x/y/width/height*/)
+{
+   float xmin = bez->x1;
+   float xmax = bez->x1;
+   float ymin = bez->y1;
+   float ymax = bez->y1;
+
+   if (bez->x2 < xmin)
+      xmin = bez->x2;
+   else if (bez->x2 > xmax)
+      xmax = bez->x2;
+   if (bez->x3 < xmin)
+      xmin = bez->x3;
+   else if (bez->x3 > xmax)
+      xmax = bez->x3;
+   if (bez->x4 < xmin)
+      xmin = bez->x4;
+   else if (bez->x4 > xmax)
+      xmax = bez->x4;
+
+   if (bez->y2 < ymin)
+      ymin = bez->y2;
+   else if (bez->y2 > ymax)
+      ymax = bez->y2;
+   if (bez->y3 < ymin)
+      ymin = bez->y3;
+   else if (bez->y3 > ymax)
+      ymax = bez->y3;
+   if (bez->y4 < ymin)
+      ymin = bez->y4;
+   else if (bez->y4 > ymax)
+      ymax = bez->y4;
+
+   bounds[0] = xmin; /* x */
+   bounds[1] = ymin; /* y */
+   bounds[2] = xmax - xmin; /* width */
+   bounds[3] = ymax - ymin; /* height */
+}
+
+void bezier_start_tangent(const struct bezier *bez,
+                          float *tangent)
+{
+   tangent[0] = bez->x1;
+   tangent[1] = bez->y1;
+   tangent[2] = bez->x2;
+   tangent[3] = bez->y2;
+
+   if (null_line(tangent)) {
+      tangent[0] = bez->x1;
+      tangent[1] = bez->y1;
+      tangent[2] = bez->x3;
+      tangent[3] = bez->y3;
+   }
+   if (null_line(tangent)) {
+      tangent[0] = bez->x1;
+      tangent[1] = bez->y1;
+      tangent[2] = bez->x4;
+      tangent[3] = bez->y4;
+   }
+}
+
+
+static INLINE VGfloat bezier_t_at_length(struct bezier *bez,
+                                         VGfloat at_length,
+                                         VGfloat error)
+{
+   VGfloat len = bezier_length(bez, error);
+   VGfloat t   = 1.0;
+   VGfloat last_bigger = 1.;
+
+   if (at_length > len || floatsEqual(at_length, len))
+      return t;
+
+   if (floatIsZero(at_length))
+      return 0.f;
+
+   t *= 0.5;
+   while (1) {
+      struct bezier right = *bez;
+      struct bezier left;
+      VGfloat tmp_len;
+      split_left(&right, t, &left);
+      tmp_len = bezier_length(&left, error);
+      if (ABS(tmp_len - at_length) < error)
+         break;
+
+      if (tmp_len < at_length) {
+         t += (last_bigger - t)*.5;
+      } else {
+         last_bigger = t;
+         t -= t*.5;
+      }
+   }
+   return t;
+}
+
+void bezier_point_at_length(struct bezier *bez,
+                            float length,
+                            float *point,
+                            float *normal)
+{
+   /* ~0.000001 seems to be required to pass G2080x tests */
+   VGfloat t = bezier_t_at_length(bez, length, 0.000001);
+   bezier_point_at(bez, t, point);
+   bezier_normal_at(bez, t, normal);
+   vector_unit(normal);
+}
+
+void bezier_point_at_t(struct bezier *bez, float t,
+                       float *point, float *normal)
+{
+   bezier_point_at(bez, t, point);
+   bezier_normal_at(bez, t, normal);
+   vector_unit(normal);
+}
+
+void bezier_exact_bounds(const struct bezier *bez,
+                         float *bounds/*x/y/width/height*/)
+{
+   struct polygon *poly = polygon_create(64);
+   polygon_vertex_append(poly, bez->x1, bez->y1);
+   bezier_add_to_polygon(bez, poly);
+   polygon_bounding_rect(poly, bounds);
+   polygon_destroy(poly);
+}
+
diff --git a/src/gallium/state_trackers/vega/bezier.h b/src/gallium/state_trackers/vega/bezier.h
new file mode 100644 (file)
index 0000000..e066660
--- /dev/null
@@ -0,0 +1,81 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#ifndef BEZIER_H
+#define BEZIER_H
+
+struct polygon;
+struct matrix;
+
+struct bezier {
+    float x1, y1;
+    float x2, y2;
+    float x3, y3;
+    float x4, y4;
+};
+
+
+#define BEZIER_DEFAULT_ERROR 0.01
+
+/* kappa as being l of a circle with r = 1, we can emulate any
+ * circle of radius r by using the formula
+ * l = r . kappa
+ * More at:
+ * http://www.whizkidtech.redprince.net/bezier/circle/ */
+#define KAPPA 0.5522847498
+
+void bezier_init(struct bezier *bez,
+                 float x1, float y1,
+                 float x2, float y2,
+                 float x3, float y3,
+                 float x4, float y4);
+
+struct polygon *bezier_to_polygon(struct bezier *bez);
+void bezier_add_to_polygon(const struct bezier *bez,
+                           struct polygon *poly);
+float bezier_length(struct bezier *bez, float error);
+void bezier_transform(struct bezier *bez,
+                      struct matrix *mat);
+
+int bezier_translate_by_normal(struct bezier *b,
+                               struct bezier *curves,
+                               int max_curves,
+                               float normal_len,
+                               float threshold);
+void bezier_bounds(const struct bezier *bez,
+                   float *bounds/*x/y/width/height*/);
+void bezier_exact_bounds(const struct bezier *bez,
+                         float *bounds/*x/y/width/height*/);
+
+void bezier_start_tangent(const struct bezier *bez,
+                          float *tangent);
+
+void bezier_point_at_length(struct bezier *bez, float length,
+                            float *point, float *normal);
+void bezier_point_at_t(struct bezier *bez, float t,
+                       float *point, float *normal);
+
+#endif
diff --git a/src/gallium/state_trackers/vega/image.c b/src/gallium/state_trackers/vega/image.c
new file mode 100644 (file)
index 0000000..9a72298
--- /dev/null
@@ -0,0 +1,654 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#include "image.h"
+
+#include "vg_translate.h"
+#include "vg_context.h"
+#include "matrix.h"
+#include "renderer.h"
+#include "util_array.h"
+#include "api_consts.h"
+#include "shaders_cache.h"
+#include "shader.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_screen.h"
+#include "pipe/p_inlines.h"
+#include "util/u_blit.h"
+#include "util/u_tile.h"
+#include "util/u_memory.h"
+#include "util/u_math.h"
+
+static enum pipe_format vg_format_to_pipe(VGImageFormat format)
+{
+   switch(format) {
+   case VG_sRGB_565:
+      return PIPE_FORMAT_R5G6B5_UNORM;
+   case VG_sRGBA_5551:
+      return PIPE_FORMAT_A1R5G5B5_UNORM;
+   case VG_sRGBA_4444:
+      return PIPE_FORMAT_A4R4G4B4_UNORM;
+   case VG_sL_8:
+   case VG_lL_8:
+      return PIPE_FORMAT_L8_UNORM;
+   case VG_BW_1:
+      return PIPE_FORMAT_A8R8G8B8_UNORM;
+   case VG_A_8:
+      return PIPE_FORMAT_A8_UNORM;
+#ifdef OPENVG_VERSION_1_1
+   case VG_A_1:
+   case VG_A_4:
+      return PIPE_FORMAT_A8_UNORM;
+#endif
+   default:
+      return PIPE_FORMAT_A8R8G8B8_UNORM;
+   }
+}
+
+static INLINE void vg_sync_size(VGfloat *src_loc, VGfloat *dst_loc)
+{
+   src_loc[2] = MIN2(src_loc[2], dst_loc[2]);
+   src_loc[3] = MIN2(src_loc[3], dst_loc[3]);
+   dst_loc[2] = src_loc[2];
+   dst_loc[3] = src_loc[3];
+}
+
+
+static void vg_copy_texture(struct vg_context *ctx,
+                            struct pipe_texture *dst, VGint dx, VGint dy,
+                            struct pipe_texture *src, VGint sx, VGint sy,
+                            VGint width, VGint height)
+{
+   VGfloat dst_loc[4], src_loc[4];
+   VGfloat dst_bounds[4], src_bounds[4];
+   VGfloat src_shift[4], dst_shift[4], shift[4];
+
+   dst_loc[0] = dx;
+   dst_loc[1] = dy;
+   dst_loc[2] = width;
+   dst_loc[3] = height;
+   dst_bounds[0] = 0.f;
+   dst_bounds[1] = 0.f;
+   dst_bounds[2] = dst->width[0];
+   dst_bounds[3] = dst->height[0];
+
+   src_loc[0] = sx;
+   src_loc[1] = sy;
+   src_loc[2] = width;
+   src_loc[3] = height;
+   src_bounds[0] = 0.f;
+   src_bounds[1] = 0.f;
+   src_bounds[2] = src->width[0];
+   src_bounds[3] = src->height[0];
+
+   vg_bound_rect(src_loc, src_bounds, src_shift);
+   vg_bound_rect(dst_loc, dst_bounds, dst_shift);
+   shift[0] = src_shift[0] - dst_shift[0];
+   shift[1] = src_shift[1] - dst_shift[1];
+
+   if (shift[0] < 0)
+      vg_shift_rectx(src_loc, src_bounds, -shift[0]);
+   else
+      vg_shift_rectx(dst_loc, dst_bounds, shift[0]);
+
+   if (shift[1] < 0)
+      vg_shift_recty(src_loc, src_bounds, -shift[1]);
+   else
+      vg_shift_recty(dst_loc, dst_bounds, shift[1]);
+
+   vg_sync_size(src_loc, dst_loc);
+
+   if (src_loc[2] >= 0 && src_loc[3] >= 0 &&
+       dst_loc[2] >= 0 && dst_loc[3] >= 0) {
+      renderer_copy_texture(ctx->renderer,
+                            src,
+                            src_loc[0],
+                            src_loc[1] + src_loc[3],
+                            src_loc[0] + src_loc[2],
+                            src_loc[1],
+                            dst,
+                            dst_loc[0],
+                            dst_loc[1] + dst_loc[3],
+                            dst_loc[0] + dst_loc[2],
+                            dst_loc[1]);
+   }
+
+}
+
+void vg_copy_surface(struct vg_context *ctx,
+                     struct pipe_surface *dst, VGint dx, VGint dy,
+                     struct pipe_surface *src, VGint sx, VGint sy,
+                     VGint width, VGint height)
+{
+   VGfloat dst_loc[4], src_loc[4];
+   VGfloat dst_bounds[4], src_bounds[4];
+   VGfloat src_shift[4], dst_shift[4], shift[4];
+
+   dst_loc[0] = dx;
+   dst_loc[1] = dy;
+   dst_loc[2] = width;
+   dst_loc[3] = height;
+   dst_bounds[0] = 0.f;
+   dst_bounds[1] = 0.f;
+   dst_bounds[2] = dst->width;
+   dst_bounds[3] = dst->height;
+
+   src_loc[0] = sx;
+   src_loc[1] = sy;
+   src_loc[2] = width;
+   src_loc[3] = height;
+   src_bounds[0] = 0.f;
+   src_bounds[1] = 0.f;
+   src_bounds[2] = src->width;
+   src_bounds[3] = src->height;
+
+   vg_bound_rect(src_loc, src_bounds, src_shift);
+   vg_bound_rect(dst_loc, dst_bounds, dst_shift);
+   shift[0] = src_shift[0] - dst_shift[0];
+   shift[1] = src_shift[1] - dst_shift[1];
+
+   if (shift[0] < 0)
+      vg_shift_rectx(src_loc, src_bounds, -shift[0]);
+   else
+      vg_shift_rectx(dst_loc, dst_bounds, shift[0]);
+
+   if (shift[1] < 0)
+      vg_shift_recty(src_loc, src_bounds, -shift[1]);
+   else
+      vg_shift_recty(dst_loc, dst_bounds, shift[1]);
+
+   vg_sync_size(src_loc, dst_loc);
+
+   if (src_loc[2] > 0 && src_loc[3] > 0 &&
+       dst_loc[2] > 0 && dst_loc[3] > 0) {
+      if (src == dst)
+         renderer_copy_surface(ctx->renderer,
+                               src,
+                               src_loc[0],
+                               src->height - (src_loc[1] + src_loc[3]),
+                               src_loc[0] + src_loc[2],
+                               src->height - src_loc[1],
+                               dst,
+                               dst_loc[0],
+                               dst->height - (dst_loc[1] + dst_loc[3]),
+                               dst_loc[0] + dst_loc[2],
+                               dst->height - dst_loc[1],
+                               0, 0);
+      else
+         renderer_copy_surface(ctx->renderer,
+                               src,
+                               src_loc[0],
+                               src->height - src_loc[1],
+                               src_loc[0] + src_loc[2],
+                               src->height - (src_loc[1] + src_loc[3]),
+                               dst,
+                               dst_loc[0],
+                               dst->height - (dst_loc[1] + dst_loc[3]),
+                               dst_loc[0] + dst_loc[2],
+                               dst->height - dst_loc[1],
+                               0, 0);
+   }
+
+}
+
+static struct pipe_texture *image_texture(struct vg_image *img)
+{
+   struct pipe_texture *tex = img->texture;
+   return tex;
+}
+
+
+static void image_cleari(struct vg_image *img, VGint clear_colori,
+                         VGint x, VGint y, VGint width, VGint height)
+{
+   VGint *clearbuf;
+   VGint i;
+   VGfloat dwidth, dheight;
+
+   clearbuf = malloc(sizeof(VGint)*width*height);
+   for (i = 0; i < width*height; ++i)
+      clearbuf[i] = clear_colori;
+
+   dwidth = MIN2(width, img->width);
+   dheight = MIN2(height, img->height);
+
+   image_sub_data(img, clearbuf, width * sizeof(VGint),
+                  VG_sRGBA_8888,
+                  x, y, dwidth, dheight);
+   free(clearbuf);
+}
+
+struct vg_image * image_create(VGImageFormat format,
+                               VGint width, VGint height)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct vg_image *image = CALLOC_STRUCT(vg_image);
+   enum pipe_format pformat = vg_format_to_pipe(format);
+   struct pipe_texture pt, *newtex;
+   struct pipe_screen *screen = ctx->pipe->screen;
+
+   vg_init_object(&image->base, ctx, VG_OBJECT_IMAGE);
+
+   image->format = format;
+   image->width = width;
+   image->height = height;
+
+   image->sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+   image->sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+   image->sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+   image->sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
+   image->sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
+   image->sampler.normalized_coords = 1;
+
+   assert(screen->is_format_supported(screen, pformat, PIPE_TEXTURE_2D,
+                                      PIPE_TEXTURE_USAGE_SAMPLER, 0));
+
+   memset(&pt, 0, sizeof(pt));
+   pt.target = PIPE_TEXTURE_2D;
+   pt.format = pformat;
+   pf_get_block(pformat, &pt.block);
+   pt.last_level = 0;
+   pt.width[0] = width;
+   pt.height[0] = height;
+   pt.depth[0] = 1;
+   pt.tex_usage = PIPE_TEXTURE_USAGE_SAMPLER;
+
+   newtex = screen->texture_create(screen, &pt);
+
+   debug_assert(newtex);
+
+   image->texture = newtex;
+
+   vg_context_add_object(ctx, VG_OBJECT_IMAGE, image);
+
+   image_cleari(image, 0, 0, 0, image->width, image->height);
+   return image;
+}
+
+void image_destroy(struct vg_image *img)
+{
+   struct vg_context *ctx = vg_current_context();
+   vg_context_remove_object(ctx, VG_OBJECT_IMAGE, img);
+
+
+   if (img->parent) {
+      /* remove img from the parent child array */
+      int idx;
+      struct vg_image **array =
+         (struct vg_image **)img->parent->children_array->data;
+
+      for (idx = 0; idx < img->parent->children_array->num_elements; ++idx) {
+         struct vg_image *child = array[idx];
+         if (child == img) {
+            break;
+         }
+      }
+      debug_assert(idx < img->parent->children_array->num_elements);
+      array_remove_element(img->parent->children_array, idx);
+   }
+
+   if (img->children_array && img->children_array->num_elements) {
+      /* reparent the children */
+      VGint i;
+      struct vg_image *parent = img->parent;
+      struct vg_image **children =
+         (struct vg_image **)img->children_array->data;
+      if (!parent) {
+         VGint min_x = children[0]->x;
+         parent = children[0];
+
+         for (i = 1; i < img->children_array->num_elements; ++i) {
+            struct vg_image *child = children[i];
+            if (child->x < min_x) {
+               parent = child;
+            }
+         }
+      }
+
+      for (i = 0; i < img->children_array->num_elements; ++i) {
+         struct vg_image *child = children[i];
+         if (child != parent) {
+            child->parent = parent;
+            if (!parent->children_array) {
+               parent->children_array = array_create(
+                  sizeof(struct vg_image*));
+            }
+            array_append_data(parent->children_array,
+                              &child, 1);
+         } else
+            child->parent = NULL;
+      }
+      array_destroy(img->children_array);
+   }
+
+   pipe_texture_reference(&img->texture, NULL);
+   free(img);
+}
+
+void image_clear(struct vg_image *img,
+                 VGint x, VGint y, VGint width, VGint height)
+{
+   struct vg_context *ctx = vg_current_context();
+   VGfloat *clear_colorf = ctx->state.vg.clear_color;
+   VGubyte r, g, b ,a;
+   VGint clear_colori;
+   /* FIXME: this is very nasty */
+   r = float_to_ubyte(clear_colorf[0]);
+   g = float_to_ubyte(clear_colorf[1]);
+   b = float_to_ubyte(clear_colorf[2]);
+   a = float_to_ubyte(clear_colorf[3]);
+   clear_colori = r << 24 | g << 16 | b << 8 | a;
+   image_cleari(img, clear_colori, x, y, width, height);
+}
+
+void image_sub_data(struct vg_image *image,
+                    const void * data,
+                    VGint dataStride,
+                    VGImageFormat dataFormat,
+                    VGint x, VGint y,
+                    VGint width, VGint height)
+{
+   const VGint yStep = 1;
+   VGubyte *src = (VGubyte *)data;
+   VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4];
+   VGfloat *df = (VGfloat*)temp;
+   VGint i;
+   struct vg_context *ctx = vg_current_context();
+   struct pipe_screen *screen = ctx->pipe->screen;
+   struct pipe_texture *texture = image_texture(image);
+   VGint xoffset = 0, yoffset = 0;
+
+   if (x < 0) {
+      xoffset -= x;
+      width += x;
+      x = 0;
+   }
+   if (y < 0) {
+      yoffset -= y;
+      height += y;
+      y = 0;
+   }
+
+   if (width <= 0 || height <= 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   if (x > image->width || y > image->width) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   if (x + width > image->width) {
+      width = image->width - x;
+   }
+
+   if (y + height > image->height) {
+      height = image->height - y;
+   }
+
+   { /* upload color_data */
+      struct pipe_transfer *transfer = screen->get_tex_transfer(
+         screen, texture, 0, 0, 0,
+         PIPE_TRANSFER_WRITE, 0, 0, texture->width[0], texture->height[0]);
+      src += (dataStride * yoffset);
+      for (i = 0; i < height; i++) {
+         _vega_unpack_float_span_rgba(ctx, width, xoffset, src, dataFormat, temp);
+         pipe_put_tile_rgba(transfer, x+image->x, y+image->y, width, 1, df);
+         y += yStep;
+         src += dataStride;
+      }
+      screen->tex_transfer_destroy(transfer);
+   }
+}
+
+void image_get_sub_data(struct vg_image * image,
+                        void * data,
+                        VGint dataStride,
+                        VGImageFormat dataFormat,
+                        VGint sx, VGint sy,
+                        VGint width, VGint height)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct pipe_context *pipe = ctx->pipe;
+   struct pipe_screen *screen = pipe->screen;
+   VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4];
+   VGfloat *df = (VGfloat*)temp;
+   VGint y = 0, yStep = 1;
+   VGint i;
+   VGubyte *dst = (VGubyte *)data;
+
+   {
+      struct pipe_transfer *transfer =
+         screen->get_tex_transfer(screen,
+                                  image->texture,  0, 0, 0,
+                                  PIPE_TRANSFER_READ,
+                                  0, 0,
+                                  image->x + image->width,
+                                  image->y + image->height);
+      /* Do a row at a time to flip image data vertically */
+      for (i = 0; i < height; i++) {
+#if 0
+         debug_printf("%d-%d  == %d\n", sy, height, y);
+#endif
+         pipe_get_tile_rgba(transfer, sx+image->x, y, width, 1, df);
+         y += yStep;
+         _vega_pack_rgba_span_float(ctx, width, temp, dataFormat, dst);
+         dst += dataStride;
+      }
+
+      screen->tex_transfer_destroy(transfer);
+   }
+}
+
+struct vg_image * image_child_image(struct vg_image *parent,
+                                    VGint x, VGint y,
+                                    VGint width, VGint height)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct vg_image *image = CALLOC_STRUCT(vg_image);
+
+   vg_init_object(&image->base, ctx, VG_OBJECT_IMAGE);
+
+   image->x = parent->x + x;
+   image->y = parent->y + y;
+   image->width = width;
+   image->height = height;
+   image->parent = parent;
+   image->texture = 0;
+   pipe_texture_reference(&image->texture,
+                          parent->texture);
+
+   image->sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+   image->sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+   image->sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+   image->sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
+   image->sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
+   image->sampler.normalized_coords = 1;
+
+   if (!parent->children_array)
+      parent->children_array = array_create(
+         sizeof(struct vg_image*));
+
+   array_append_data(parent->children_array,
+                     &image, 1);
+
+   vg_context_add_object(ctx, VG_OBJECT_IMAGE, image);
+
+   return image;
+}
+
+void image_copy(struct vg_image *dst, VGint dx, VGint dy,
+                struct vg_image *src, VGint sx, VGint sy,
+                VGint width, VGint height,
+                VGboolean dither)
+{
+   struct vg_context *ctx = vg_current_context();
+
+   if (width <= 0 || height <= 0) {
+      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+   /* make sure rendering has completed */
+   ctx->pipe->flush(ctx->pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
+   vg_copy_texture(ctx, dst->texture, dst->x + dx, dst->y + dy,
+                   src->texture, src->x + sx, src->y + sy, width, height);
+}
+
+void image_draw(struct vg_image *img)
+{
+   struct vg_context *ctx = vg_current_context();
+   VGfloat x1, y1;
+   VGfloat x2, y2;
+   VGfloat x3, y3;
+   VGfloat x4, y4;
+   struct matrix *matrix;
+
+   x1 = 0;
+   y1 = 0;
+   x2 = img->width;
+   y2 = 0;
+   x3 = img->width;
+   y3 = img->height;
+   x4 = 0;
+   y4 = img->height;
+
+   matrix = &ctx->state.vg.image_user_to_surface_matrix;
+
+   matrix_map_point(matrix, x1, y1, &x1, &y1);
+   matrix_map_point(matrix, x2, y2, &x2, &y2);
+   matrix_map_point(matrix, x3, y3, &x3, &y3);
+   matrix_map_point(matrix, x4, y4, &x4, &y4);
+
+   shader_set_drawing_image(ctx->shader, VG_TRUE);
+   shader_set_paint(ctx->shader, ctx->state.vg.fill_paint);
+   shader_set_image(ctx->shader, img);
+   shader_bind(ctx->shader);
+
+   renderer_texture_quad(ctx->renderer, image_texture(img),
+                         img->x, img->y, img->x + img->width, img->y + img->height,
+                         x1, y1, x2, y2, x3, y3, x4, y4);
+}
+
+void image_set_pixels(VGint dx, VGint dy,
+                      struct vg_image *src, VGint sx, VGint sy,
+                      VGint width, VGint height)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct pipe_context *pipe = ctx->pipe;
+   struct pipe_screen *screen = pipe->screen;
+   struct pipe_surface *surf;
+   struct st_renderbuffer *strb = ctx->draw_buffer->strb;
+
+   /* make sure rendering has completed */
+   pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
+
+   surf = screen->get_tex_surface(screen, image_texture(src),  0, 0, 0,
+                                  PIPE_BUFFER_USAGE_GPU_READ);
+
+   vg_copy_surface(ctx, strb->surface, dx, dy,
+                   surf, sx+src->x, sy+src->y, width, height);
+
+   screen->tex_surface_destroy(surf);
+}
+
+void image_get_pixels(struct vg_image *dst, VGint dx, VGint dy,
+                      VGint sx, VGint sy,
+                      VGint width, VGint height)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct pipe_context *pipe = ctx->pipe;
+   struct pipe_screen *screen = pipe->screen;
+   struct pipe_surface *surf;
+   struct st_renderbuffer *strb = ctx->draw_buffer->strb;
+
+   /* flip the y coordinates */
+   /*dy = dst->height - dy - height;*/
+
+   /* make sure rendering has completed */
+   pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
+
+   surf = screen->get_tex_surface(screen, image_texture(dst),  0, 0, 0,
+                                  PIPE_BUFFER_USAGE_GPU_WRITE |
+                                  PIPE_BUFFER_USAGE_GPU_READ);
+   vg_copy_surface(ctx, surf, dst->x + dx, dst->y + dy,
+                   strb->surface, sx, sy, width, height);
+
+   pipe_surface_reference(&surf, NULL);
+}
+
+
+VGboolean vg_image_overlaps(struct vg_image *dst,
+                            struct vg_image *src)
+{
+   if (dst == src || dst->parent == src ||
+       dst == src->parent)
+      return VG_TRUE;
+   if (dst->parent && dst->parent == src->parent) {
+      VGfloat left1 = dst->x;
+      VGfloat left2 = src->x;
+      VGfloat right1 = dst->x + dst->width;
+      VGfloat right2 = src->x + src->width;
+      VGfloat bottom1 = dst->y;
+      VGfloat bottom2 = src->y;
+      VGfloat top1 = dst->y + dst->height;
+      VGfloat top2 = src->y + src->height;
+
+      return !(left2 > right1 || right2 < left1 ||
+               top2 > bottom1 || bottom2 < top1);
+   }
+   return VG_FALSE;
+}
+
+VGint image_bind_samplers(struct vg_image *img, struct pipe_sampler_state **samplers,
+                          struct pipe_texture **textures)
+{
+   img->sampler.min_img_filter = image_sampler_filter(img->base.ctx);
+   img->sampler.mag_img_filter = image_sampler_filter(img->base.ctx);
+   samplers[3] = &img->sampler;
+   textures[3] = img->texture;
+   return 1;
+}
+
+VGint image_sampler_filter(struct vg_context *ctx)
+{
+    switch(ctx->state.vg.image_quality) {
+    case VG_IMAGE_QUALITY_NONANTIALIASED:
+       return PIPE_TEX_FILTER_NEAREST;
+       break;
+    case VG_IMAGE_QUALITY_FASTER:
+       return PIPE_TEX_FILTER_NEAREST;
+       break;
+    case VG_IMAGE_QUALITY_BETTER:
+       /*return PIPE_TEX_FILTER_ANISO;*/
+       return PIPE_TEX_FILTER_LINEAR;
+       break;
+    default:
+       debug_printf("Unknown image quality");
+    }
+    return PIPE_TEX_FILTER_NEAREST;
+}
diff --git a/src/gallium/state_trackers/vega/image.h b/src/gallium/state_trackers/vega/image.h
new file mode 100644 (file)
index 0000000..78e17cf
--- /dev/null
@@ -0,0 +1,104 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#ifndef IMAGES_H
+#define IMAGES_H
+
+#include "vg_context.h"
+#include "pipe/p_state.h"
+
+struct pipe_texture;
+struct array;
+struct vg_context;
+struct pipe_surface;
+
+struct vg_image {
+   struct vg_object base;
+   VGImageFormat format;
+   VGint x, y;
+   VGint width, height;
+
+   struct vg_image *parent;
+
+   struct pipe_texture *texture;
+   struct pipe_sampler_state sampler;
+
+   struct array *children_array;
+};
+
+struct vg_image *image_create(VGImageFormat format,
+                              VGint width, VGint height);
+void image_destroy(struct vg_image *img);
+
+void image_clear(struct vg_image *img,
+                 VGint x, VGint y, VGint width, VGint height);
+
+void image_sub_data(struct vg_image *image,
+                    const void * data,
+                    VGint dataStride,
+                    VGImageFormat dataFormat,
+                    VGint x, VGint y,
+                    VGint width, VGint height);
+
+void image_get_sub_data(struct vg_image * image,
+                        void * data,
+                        VGint dataStride,
+                        VGImageFormat dataFormat,
+                        VGint x, VGint y,
+                        VGint width, VGint height);
+
+struct vg_image *image_child_image(struct vg_image *parent,
+                                   VGint x, VGint y,
+                                   VGint width, VGint height);
+
+void image_copy(struct vg_image *dst, VGint dx, VGint dy,
+                struct vg_image *src, VGint sx, VGint sy,
+                VGint width, VGint height,
+                VGboolean dither);
+
+void image_draw(struct vg_image *img);
+
+void image_set_pixels(VGint dx, VGint dy,
+                      struct vg_image *src, VGint sx, VGint sy,
+                      VGint width, VGint height);
+void image_get_pixels(struct vg_image *dst, VGint dx, VGint dy,
+                      VGint sx, VGint sy,
+                      VGint width, VGint height);
+
+VGint image_bind_samplers(struct vg_image *dst, struct pipe_sampler_state **samplers,
+                          struct pipe_texture **textures);
+
+VGboolean vg_image_overlaps(struct vg_image *dst,
+                            struct vg_image *src);
+
+VGint image_sampler_filter(struct vg_context *ctx);
+
+void vg_copy_surface(struct vg_context *ctx,
+                     struct pipe_surface *dst, VGint dx, VGint dy,
+                     struct pipe_surface *src, VGint sx, VGint sy,
+                     VGint width, VGint height);
+
+#endif
diff --git a/src/gallium/state_trackers/vega/mask.c b/src/gallium/state_trackers/vega/mask.c
new file mode 100644 (file)
index 0000000..24650a3
--- /dev/null
@@ -0,0 +1,690 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#include "mask.h"
+
+#include "path.h"
+#include "image.h"
+#include "shaders_cache.h"
+#include "renderer.h"
+#include "asm_util.h"
+#include "st_inlines.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_screen.h"
+#include "pipe/p_inlines.h"
+#include "util/u_memory.h"
+
+struct vg_mask_layer {
+   struct vg_object base;
+
+   VGint width;
+   VGint height;
+
+   struct pipe_texture *texture;
+};
+
+static INLINE struct pipe_surface *
+alpha_mask_surface(struct vg_context *ctx, int usage)
+{
+   struct pipe_screen *screen = ctx->pipe->screen;
+   struct st_framebuffer *stfb = ctx->draw_buffer;
+   return screen->get_tex_surface(screen,
+                                  stfb->alpha_mask,
+                                  0, 0, 0,
+                                  usage);
+}
+
+static INLINE VGboolean
+intersect_rectangles(VGint dwidth, VGint dheight,
+                     VGint swidth, VGint sheight,
+                     VGint tx, VGint ty,
+                     VGint twidth, VGint theight,
+                     VGint *offsets,
+                     VGint *location)
+{
+   if (tx + twidth <= 0 || tx >= dwidth)
+      return VG_FALSE;
+   if (ty + theight <= 0 || ty >= dheight)
+      return VG_FALSE;
+
+   offsets[0] = 0;
+   offsets[1] = 0;
+   location[0] = tx;
+   location[1] = ty;
+
+   if (tx < 0) {
+      offsets[0] -= tx;
+      location[0] = 0;
+
+      location[2] = MIN2(tx + swidth, MIN2(dwidth, tx + twidth));
+      offsets[2] = location[2];
+   } else {
+      offsets[2] = MIN2(twidth, MIN2(dwidth - tx, swidth ));
+      location[2] = offsets[2];
+   }
+
+   if (ty < 0) {
+      offsets[1] -= ty;
+      location[1] = 0;
+
+      location[3] = MIN2(ty + sheight, MIN2(dheight, ty + theight));
+      offsets[3] = location[3];
+   } else {
+      offsets[3] = MIN2(theight, MIN2(dheight - ty, sheight));
+      location[3] = offsets[3];
+   }
+
+   return VG_TRUE;
+}
+
+#if DEBUG_MASKS
+static void read_alpha_mask(void * data, VGint dataStride,
+                            VGImageFormat dataFormat,
+                            VGint sx, VGint sy,
+                            VGint width, VGint height)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct pipe_context *pipe = ctx->pipe;
+   struct pipe_screen *screen = pipe->screen;
+
+   struct st_framebuffer *stfb = ctx->draw_buffer;
+   struct st_renderbuffer *strb = stfb->alpha_mask;
+   struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb;
+
+   VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4];
+   VGfloat *df = (VGfloat*)temp;
+   VGint y = (fb->height - sy) - 1, yStep = -1;
+   VGint i;
+   VGubyte *dst = (VGubyte *)data;
+   VGint xoffset = 0, yoffset = 0;
+
+   /* make sure rendering has completed */
+   pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
+   if (sx < 0) {
+      xoffset = -sx;
+      xoffset *= _vega_size_for_format(dataFormat);
+      width += sx;
+      sx = 0;
+   }
+   if (sy < 0) {
+      yoffset = -sy;
+      height += sy;
+      sy = 0;
+      y = (fb->height - sy) - 1;
+      yoffset *= dataStride;
+   }
+
+   {
+      struct pipe_surface *surf;
+
+      surf = screen->get_tex_surface(screen, strb->texture,  0, 0, 0,
+                                     PIPE_BUFFER_USAGE_CPU_READ);
+
+      /* Do a row at a time to flip image data vertically */
+      for (i = 0; i < height; i++) {
+#if 0
+         debug_printf("%d-%d  == %d\n", sy, height, y);
+#endif
+         pipe_get_tile_rgba(surf, sx, y, width, 1, df);
+         y += yStep;
+         _vega_pack_rgba_span_float(ctx, width, temp, dataFormat,
+                                    dst + yoffset + xoffset);
+         dst += dataStride;
+      }
+
+      pipe_surface_reference(&surf, NULL);
+   }
+}
+
+void save_alpha_to_file(const char *filename)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb;
+   VGint *data;
+   int i, j;
+
+   data = malloc(sizeof(int) * fb->width * fb->height);
+   read_alpha_mask(data, fb->width * sizeof(int),
+                   VG_sRGBA_8888,
+                   0, 0, fb->width, fb->height);
+   fprintf(stderr, "/*---------- start */\n");
+   fprintf(stderr, "const int image_width = %d;\n",
+           fb->width);
+   fprintf(stderr, "const int image_height = %d;\n",
+           fb->height);
+   fprintf(stderr, "const int image_data = {\n");
+   for (i = 0; i < fb->height; ++i) {
+      for (j = 0; j < fb->width; ++j) {
+         int rgba = data[i * fb->height + j];
+         int argb = 0;
+         argb = (rgba >> 8);
+         argb |= ((rgba & 0xff) << 24);
+         fprintf(stderr, "0x%x, ", argb);
+      }
+      fprintf(stderr, "\n");
+   }
+   fprintf(stderr, "};\n");
+   fprintf(stderr, "/*---------- end */\n");
+}
+#endif
+
+static void setup_mask_framebuffer(struct pipe_surface *surf,
+                                   VGint surf_width, VGint surf_height)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct pipe_framebuffer_state fb;
+
+   memset(&fb, 0, sizeof(fb));
+   fb.width = surf_width;
+   fb.height = surf_height;
+   fb.nr_cbufs = 1;
+   fb.cbufs[0] = surf;
+   {
+      VGint i;
+      for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i)
+         fb.cbufs[i] = 0;
+   }
+   cso_set_framebuffer(ctx->cso_context, &fb);
+}
+
+
+/* setup shader constants */
+static void setup_mask_operation(VGMaskOperation operation)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct pipe_constant_buffer *cbuf = &ctx->mask.cbuf;
+   const VGint param_bytes = 4 * sizeof(VGfloat);
+   const VGfloat ones[4] = {1.f, 1.f, 1.f, 1.f};
+   void *shader = 0;
+
+   /* We always need to get a new buffer, to keep the drivers simple and
+    * avoid gratuitous rendering synchronization.
+    */
+   pipe_buffer_reference(&cbuf->buffer, NULL);
+
+   cbuf->buffer = pipe_buffer_create(ctx->pipe->screen, 1,
+                                     PIPE_BUFFER_USAGE_CONSTANT,
+                                     param_bytes);
+   if (cbuf->buffer) {
+      st_no_flush_pipe_buffer_write(ctx, cbuf->buffer,
+                                    0, param_bytes, ones);
+   }
+
+   ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_FRAGMENT, 0, cbuf);
+   switch (operation) {
+   case VG_UNION_MASK: {
+      if (!ctx->mask.union_fs) {
+         ctx->mask.union_fs = shader_create_from_text(ctx->pipe,
+                                                      union_mask_asm,
+                                                      200,
+                                                      PIPE_SHADER_FRAGMENT);
+      }
+      shader = ctx->mask.union_fs->driver;
+   }
+      break;
+   case VG_INTERSECT_MASK: {
+      if (!ctx->mask.intersect_fs) {
+         ctx->mask.intersect_fs = shader_create_from_text(ctx->pipe,
+                                                          intersect_mask_asm,
+                                                          200,
+                                                          PIPE_SHADER_FRAGMENT);
+      }
+      shader = ctx->mask.intersect_fs->driver;
+   }
+      break;
+   case VG_SUBTRACT_MASK: {
+      if (!ctx->mask.subtract_fs) {
+         ctx->mask.subtract_fs = shader_create_from_text(ctx->pipe,
+                                                         subtract_mask_asm,
+                                                         200,
+                                                         PIPE_SHADER_FRAGMENT);
+      }
+      shader = ctx->mask.subtract_fs->driver;
+   }
+      break;
+   case VG_SET_MASK: {
+      if (!ctx->mask.set_fs) {
+         ctx->mask.set_fs = shader_create_from_text(ctx->pipe,
+                                                    set_mask_asm,
+                                                    200,
+                                                    PIPE_SHADER_FRAGMENT);
+      }
+      shader = ctx->mask.set_fs->driver;
+   }
+      break;
+   default:
+         assert(0);
+      break;
+   }
+   cso_set_fragment_shader_handle(ctx->cso_context, shader);
+}
+
+static void setup_mask_samplers(struct pipe_texture *umask)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
+   struct pipe_texture *textures[PIPE_MAX_SAMPLERS];
+   struct st_framebuffer *fb_buffers = ctx->draw_buffer;
+   struct pipe_texture *uprev = NULL;
+   struct pipe_sampler_state sampler;
+
+   uprev = fb_buffers->blend_texture;
+   sampler = ctx->mask.sampler;
+   sampler.normalized_coords = 1;
+
+   samplers[0] = NULL;
+   samplers[1] = NULL;
+   samplers[2] = NULL;
+   textures[0] = NULL;
+   textures[1] = NULL;
+   textures[2] = NULL;
+
+   samplers[0] = &sampler;
+   samplers[1] = &ctx->mask.sampler;
+
+   textures[0] = umask;
+   textures[1] = uprev;
+
+   cso_set_samplers(ctx->cso_context, 2,
+                    (const struct pipe_sampler_state **)samplers);
+   cso_set_sampler_textures(ctx->cso_context, 2, textures);
+}
+
+
+/* setup shader constants */
+static void setup_mask_fill(const VGfloat color[4])
+{
+   struct vg_context *ctx = vg_current_context();
+   struct pipe_constant_buffer *cbuf = &ctx->mask.cbuf;
+   const VGint param_bytes = 4 * sizeof(VGfloat);
+
+   /* We always need to get a new buffer, to keep the drivers simple and
+    * avoid gratuitous rendering synchronization.
+    */
+   pipe_buffer_reference(&cbuf->buffer, NULL);
+
+   cbuf->buffer = pipe_buffer_create(ctx->pipe->screen, 1,
+                                     PIPE_BUFFER_USAGE_CONSTANT,
+                                     param_bytes);
+   if (cbuf->buffer) {
+      st_no_flush_pipe_buffer_write(ctx, cbuf->buffer, 0, param_bytes, color);
+   }
+
+   ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_FRAGMENT, 0, cbuf);
+   cso_set_fragment_shader_handle(ctx->cso_context,
+                                  shaders_cache_fill(ctx->sc,
+                                                     VEGA_SOLID_FILL_SHADER));
+}
+
+static void setup_mask_viewport()
+{
+   struct vg_context *ctx = vg_current_context();
+   vg_set_viewport(ctx, VEGA_Y0_TOP);
+}
+
+static void setup_mask_blend()
+{
+   struct vg_context *ctx = vg_current_context();
+
+   struct pipe_blend_state blend;
+
+   memset(&blend, 0, sizeof(struct pipe_blend_state));
+   blend.blend_enable = 1;
+   blend.colormask |= PIPE_MASK_R;
+   blend.colormask |= PIPE_MASK_G;
+   blend.colormask |= PIPE_MASK_B;
+   blend.colormask |= PIPE_MASK_A;
+   blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE;
+   blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+   blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
+   blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
+
+   cso_set_blend(ctx->cso_context, &blend);
+}
+
+
+static void surface_fill(struct pipe_surface *surf,
+                         int surf_width, int surf_height,
+                         int x, int y, int width, int height,
+                         const VGfloat color[4])
+{
+   struct vg_context *ctx = vg_current_context();
+
+   if (x < 0) {
+      width += x;
+      x = 0;
+   }
+   if (y < 0) {
+      height += y;
+      y = 0;
+   }
+
+   cso_save_framebuffer(ctx->cso_context);
+   cso_save_blend(ctx->cso_context);
+   cso_save_fragment_shader(ctx->cso_context);
+   cso_save_viewport(ctx->cso_context);
+
+   setup_mask_blend();
+   setup_mask_fill(color);
+   setup_mask_framebuffer(surf, surf_width, surf_height);
+   setup_mask_viewport();
+
+   renderer_draw_quad(ctx->renderer, x, y,
+                      x + width, y + height, 0.0f/*depth should be disabled*/);
+
+
+   /* make sure rendering has completed */
+   ctx->pipe->flush(ctx->pipe,
+                    PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME,
+                    NULL);
+
+#if DEBUG_MASKS
+   save_alpha_to_file(0);
+#endif
+
+   cso_restore_blend(ctx->cso_context);
+   cso_restore_framebuffer(ctx->cso_context);
+   cso_restore_fragment_shader(ctx->cso_context);
+   cso_restore_viewport(ctx->cso_context);
+}
+
+
+static void mask_using_texture(struct pipe_texture *texture,
+                               VGMaskOperation operation,
+                               VGint x, VGint y,
+                               VGint width, VGint height)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct pipe_surface *surface =
+      alpha_mask_surface(ctx, PIPE_BUFFER_USAGE_GPU_WRITE);
+   VGint offsets[4], loc[4];
+
+   if (!surface)
+      return;
+   if (!intersect_rectangles(surface->width, surface->height,
+                             texture->width[0], texture->height[0],
+                             x, y, width, height,
+                             offsets, loc))
+      return;
+#if 0
+   debug_printf("Offset = [%d, %d, %d, %d]\n", offsets[0],
+                offsets[1], offsets[2], offsets[3]);
+   debug_printf("Locati = [%d, %d, %d, %d]\n", loc[0],
+                loc[1], loc[2], loc[3]);
+#endif
+
+   /* prepare our blend surface */
+   vg_prepare_blend_surface_from_mask(ctx);
+
+   cso_save_samplers(ctx->cso_context);
+   cso_save_sampler_textures(ctx->cso_context);
+   cso_save_framebuffer(ctx->cso_context);
+   cso_save_blend(ctx->cso_context);
+   cso_save_fragment_shader(ctx->cso_context);
+   cso_save_viewport(ctx->cso_context);
+
+   setup_mask_samplers(texture);
+   setup_mask_blend();
+   setup_mask_operation(operation);
+   setup_mask_framebuffer(surface, surface->width, surface->height);
+   setup_mask_viewport();
+
+   /* render the quad to propagate the rendering from stencil */
+   renderer_draw_texture(ctx->renderer, texture,
+                         offsets[0], offsets[1],
+                         offsets[0] + offsets[2], offsets[1] + offsets[3],
+                         loc[0], loc[1], loc[0] + loc[2], loc[1] + loc[3]);
+
+   /* make sure rendering has completed */
+   ctx->pipe->flush(ctx->pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
+   cso_restore_blend(ctx->cso_context);
+   cso_restore_framebuffer(ctx->cso_context);
+   cso_restore_fragment_shader(ctx->cso_context);
+   cso_restore_samplers(ctx->cso_context);
+   cso_restore_sampler_textures(ctx->cso_context);
+   cso_restore_viewport(ctx->cso_context);
+
+   pipe_surface_reference(&surface, NULL);
+}
+
+
+#ifdef OPENVG_VERSION_1_1
+
+struct vg_mask_layer * mask_layer_create(VGint width, VGint height)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct vg_mask_layer *mask = 0;
+
+   mask = CALLOC_STRUCT(vg_mask_layer);
+   vg_init_object(&mask->base, ctx, VG_OBJECT_MASK);
+   mask->width = width;
+   mask->height = height;
+
+   {
+      struct pipe_texture pt;
+      struct pipe_screen *screen = ctx->pipe->screen;
+
+      memset(&pt, 0, sizeof(pt));
+      pt.target = PIPE_TEXTURE_2D;
+      pt.format = PIPE_FORMAT_A8R8G8B8_UNORM;
+      pf_get_block(PIPE_FORMAT_A8R8G8B8_UNORM, &pt.block);
+      pt.last_level = 0;
+      pt.width[0] = width;
+      pt.height[0] = height;
+      pt.depth[0] = 1;
+      pt.tex_usage = PIPE_TEXTURE_USAGE_SAMPLER;
+      pt.compressed = 0;
+
+      mask->texture = screen->texture_create(screen, &pt);
+   }
+
+   vg_context_add_object(ctx, VG_OBJECT_MASK, mask);
+
+   return mask;
+}
+
+void mask_layer_destroy(struct vg_mask_layer *layer)
+{
+   struct vg_context *ctx = vg_current_context();
+
+   vg_context_remove_object(ctx, VG_OBJECT_MASK, layer);
+   pipe_texture_release(&layer->texture);
+   free(layer);
+}
+
+void mask_layer_fill(struct vg_mask_layer *layer,
+                     VGint x, VGint y,
+                     VGint width, VGint height,
+                     VGfloat value)
+{
+   struct vg_context *ctx = vg_current_context();
+   VGfloat alpha_color[4] = {0, 0, 0, 0};
+   struct pipe_surface *surface;
+
+   alpha_color[3] = value;
+
+   surface = ctx->pipe->screen->get_tex_surface(
+      ctx->pipe->screen, layer->texture,
+      0, 0, 0,
+      PIPE_BUFFER_USAGE_GPU_WRITE);
+
+   surface_fill(surface,
+                layer->width, layer->height,
+                x, y, width, height, alpha_color);
+
+   ctx->pipe->screen->tex_surface_release(ctx->pipe->screen, &surface);
+}
+
+void mask_copy(struct vg_mask_layer *layer,
+               VGint sx, VGint sy,
+               VGint dx, VGint dy,
+               VGint width, VGint height)
+{
+    struct vg_context *ctx = vg_current_context();
+    struct st_framebuffer *fb_buffers = ctx->draw_buffer;
+
+    renderer_copy_texture(ctx->renderer,
+                          layer->texture,
+                          sx, sy,
+                          sx + width, sy + height,
+                          fb_buffers->alpha_mask,
+                          dx, dy,
+                          dx + width, dy + height);
+}
+
+static void mask_layer_render_to(struct vg_mask_layer *layer,
+                                 struct path *path,
+                                 VGbitfield paint_modes)
+{
+   struct vg_context *ctx = vg_current_context();
+   const VGfloat fill_color[4] = {1.f, 1.f, 1.f, 1.f};
+   struct pipe_screen *screen = ctx->pipe->screen;
+   struct pipe_surface *surface;
+
+   surface = screen->get_tex_surface(screen, layer->texture,  0, 0, 0,
+                                     PIPE_BUFFER_USAGE_GPU_WRITE);
+
+   cso_save_framebuffer(ctx->cso_context);
+   cso_save_fragment_shader(ctx->cso_context);
+   cso_save_viewport(ctx->cso_context);
+
+   setup_mask_blend();
+   setup_mask_fill(fill_color);
+   setup_mask_framebuffer(surface, layer->width, layer->height);
+   setup_mask_viewport();
+
+   if (paint_modes & VG_FILL_PATH) {
+      struct matrix *mat = &ctx->state.vg.path_user_to_surface_matrix;
+      path_fill(path, mat);
+   }
+
+   if (paint_modes & VG_STROKE_PATH){
+      path_stroke(path);
+   }
+
+
+   /* make sure rendering has completed */
+   ctx->pipe->flush(ctx->pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
+
+   cso_restore_framebuffer(ctx->cso_context);
+   cso_restore_fragment_shader(ctx->cso_context);
+   cso_restore_viewport(ctx->cso_context);
+   ctx->state.dirty |= BLEND_DIRTY;
+
+   screen->tex_surface_release(ctx->pipe->screen, &surface);
+}
+
+void mask_render_to(struct path *path,
+                    VGbitfield paint_modes,
+                    VGMaskOperation operation)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct st_framebuffer *fb_buffers = ctx->draw_buffer;
+   struct vg_mask_layer *temp_layer;
+   VGint width, height;
+
+   width = fb_buffers->alpha_mask->width[0];
+   height = fb_buffers->alpha_mask->width[0];
+
+   temp_layer = mask_layer_create(width, height);
+
+   mask_layer_render_to(temp_layer, path, paint_modes);
+
+   mask_using_layer(temp_layer, 0, 0, width, height,
+                    operation);
+
+   mask_layer_destroy(temp_layer);
+}
+
+void mask_using_layer(struct vg_mask_layer *layer,
+                      VGMaskOperation operation,
+                      VGint x, VGint y,
+                      VGint width, VGint height)
+{
+   mask_using_texture(layer->texture, operation,
+                      x, y, width, height);
+}
+
+VGint mask_layer_width(struct vg_mask_layer *layer)
+{
+   return layer->width;
+}
+
+VGint mask_layer_height(struct vg_mask_layer *layer)
+{
+   return layer->height;
+}
+
+
+#endif
+
+void mask_using_image(struct vg_image *image,
+                      VGMaskOperation operation,
+                      VGint x, VGint y,
+                      VGint width, VGint height)
+{
+   mask_using_texture(image->texture, operation,
+                      x, y, width, height);
+}
+
+void mask_fill(VGint x, VGint y, VGint width, VGint height,
+               VGfloat value)
+{
+   struct vg_context *ctx = vg_current_context();
+   VGfloat alpha_color[4] = {.0f, .0f, .0f, value};
+   struct pipe_surface *surf = alpha_mask_surface(
+      ctx, PIPE_BUFFER_USAGE_GPU_WRITE);
+
+#if DEBUG_MASKS
+   debug_printf("mask_fill(%d, %d, %d, %d) with  rgba(%f, %f, %f, %f)\n",
+                x, y, width, height,
+                alpha_color[0], alpha_color[1],
+                alpha_color[2], alpha_color[3]);
+   debug_printf("XXX %f  === %f \n",
+                alpha_color[3], value);
+#endif
+
+   surface_fill(surf, surf->width, surf->height,
+                x, y, width, height, alpha_color);
+
+   pipe_surface_reference(&surf, NULL);
+}
+
+VGint mask_bind_samplers(struct pipe_sampler_state **samplers,
+                         struct pipe_texture **textures)
+{
+   struct vg_context *ctx = vg_current_context();
+
+   if (ctx->state.vg.masking) {
+      struct st_framebuffer *fb_buffers = ctx->draw_buffer;
+
+      samplers[1] = &ctx->mask.sampler;
+      textures[1] = fb_buffers->alpha_mask;
+      return 1;
+   } else
+      return 0;
+}
diff --git a/src/gallium/state_trackers/vega/mask.h b/src/gallium/state_trackers/vega/mask.h
new file mode 100644 (file)
index 0000000..5eaaede
--- /dev/null
@@ -0,0 +1,68 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#ifndef MASK_H
+#define MASK_H
+
+#include "vg_context.h"
+
+struct path;
+struct vg_image;
+struct pipe_texture;
+
+struct vg_mask_layer *mask_layer_create(VGint width, VGint height);
+void mask_layer_destroy(struct vg_mask_layer *layer);
+void mask_layer_fill(struct vg_mask_layer *layer,
+                     VGint x, VGint y,
+                     VGint width, VGint height,
+                     VGfloat value);
+VGint mask_layer_width(struct vg_mask_layer *layer);
+VGint mask_layer_height(struct vg_mask_layer *layer);
+void mask_copy(struct vg_mask_layer *layer,
+               VGint sx, VGint sy,
+               VGint dx, VGint dy,
+               VGint width, VGint height);
+
+void mask_render_to(struct path *path,
+                    VGbitfield paint_modes,
+                    VGMaskOperation operation);
+
+void mask_using_layer(struct vg_mask_layer *layer,
+                      VGMaskOperation operation,
+                      VGint x, VGint y,
+                      VGint width, VGint height);
+void mask_using_image(struct vg_image *image,
+                      VGMaskOperation operation,
+                      VGint x, VGint y,
+                      VGint width, VGint height);
+void mask_fill(VGint x, VGint y,
+               VGint width, VGint height,
+               VGfloat value);
+
+VGint mask_bind_samplers(struct pipe_sampler_state **samplers,
+                         struct pipe_texture **textures);
+
+#endif
diff --git a/src/gallium/state_trackers/vega/matrix.h b/src/gallium/state_trackers/vega/matrix.h
new file mode 100644 (file)
index 0000000..4c207f9
--- /dev/null
@@ -0,0 +1,462 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#ifndef MATRIX_H
+#define MATRIX_H
+
+#include "VG/openvg.h"
+
+#include "pipe/p_compiler.h"
+#include "util/u_math.h"
+
+#include <stdio.h>
+#include <math.h>
+
+#define floatsEqual(x, y) (fabs(x - y) <= 0.00001f * MIN2(fabs(x), fabs(y)))
+#define floatIsZero(x) (floatsEqual((x) + 1, 1))
+#define ABS(x) (fabsf(x))
+
+#define DEGREES_TO_RADIANS(d) (0.0174532925199 * (d))
+#define FLT_TO_INT(flt) float_to_int_floor(((VGuint*)&(flt))[0])
+
+static INLINE VGint float_to_int_floor(VGuint bits)
+{
+   int sign = (bits >> 31) ? -1 : 1;
+   int exp  = ((bits >> 23) & 255) - 127;
+   int mant = bits & 0x007fffff;
+   int sh   = 23 - exp;
+
+   /* abs(value) >= 2^31 -> clamp. */
+
+   if (exp >= 31)
+      return (VGint)((sign < 0) ? 0x80000000u : 0x7fffffffu);
+
+   /* abs(value) < 1 -> return -1 or 0. */
+
+   if (exp < 0)
+      return (sign < 0 && (exp > -127 || mant != 0)) ? -1 : 0;
+
+   /* abs(value) >= 2^23 -> shift left. */
+
+   mant |= 0x00800000;
+   if (sh <= 0)
+      return sign * (mant << -sh);
+
+   /* Negative -> add a rounding term. */
+
+   if (sign < 0)
+      mant += (1 << sh) - 1;
+
+   /* Shift right to obtain the result. */
+
+   return sign * (mant >> sh);
+}
+
+
+struct matrix {
+   VGfloat m[9];
+};
+
+static INLINE void matrix_init(struct matrix *mat,
+                               const VGfloat *val)
+{
+   memcpy(mat->m, val, sizeof(VGfloat) * 9);
+}
+
+static INLINE void matrix_inits(struct matrix *mat,
+                                VGfloat m11, VGfloat m12, VGfloat m13,
+                                VGfloat m21, VGfloat m22, VGfloat m23,
+                                VGfloat m31, VGfloat m32, VGfloat m33)
+{
+   mat->m[0] = m11; mat->m[1] = m12; mat->m[2] = m13;
+   mat->m[3] = m21; mat->m[4] = m22; mat->m[5] = m23;
+   mat->m[6] = m31; mat->m[7] = m32; mat->m[8] = m33;
+}
+
+static INLINE void matrix_load_identity(struct matrix *matrix)
+{
+   static const VGfloat identity[9] = {1.f, 0.f, 0.f,
+                                       0.f, 1.f, 0.f,
+                                       0.f, 0.f, 1.f};
+   memcpy(matrix->m, identity, sizeof(identity));
+}
+
+static INLINE VGboolean matrix_is_identity(struct matrix *matrix)
+{
+   return floatsEqual(matrix->m[0], 1) && floatIsZero(matrix->m[1]) &&
+      floatIsZero(matrix->m[2]) &&
+      floatIsZero(matrix->m[3]) && floatsEqual(matrix->m[4], 1) &&
+      floatIsZero(matrix->m[5]) &&
+      floatIsZero(matrix->m[6]) && floatIsZero(matrix->m[7]) &&
+      floatIsZero(matrix->m[8]);
+}
+
+static INLINE VGboolean matrix_is_affine(struct matrix *matrix)
+{
+   return floatIsZero(matrix->m[2]) && floatIsZero(matrix->m[5])
+      && floatsEqual(matrix->m[8], 1);
+}
+
+
+static INLINE void matrix_make_affine(struct matrix *matrix)
+{
+   matrix->m[2] = 0.f;
+   matrix->m[5] = 0.f;
+   matrix->m[8] = 1.f;
+}
+
+static INLINE void matrix_mult(struct matrix *dst,
+                               struct matrix *src)
+{
+   VGfloat m11 = dst->m[0]*src->m[0] + dst->m[3]*src->m[1] + dst->m[6]*src->m[2];
+   VGfloat m12 = dst->m[0]*src->m[3] + dst->m[3]*src->m[4] + dst->m[6]*src->m[5];
+   VGfloat m13 = dst->m[0]*src->m[6] + dst->m[3]*src->m[7] + dst->m[6]*src->m[8];
+
+   VGfloat m21 = dst->m[1]*src->m[0] + dst->m[4]*src->m[1] + dst->m[7]*src->m[2];
+   VGfloat m22 = dst->m[1]*src->m[3] + dst->m[4]*src->m[4] + dst->m[7]*src->m[5];
+   VGfloat m23 = dst->m[1]*src->m[6] + dst->m[4]*src->m[7] + dst->m[7]*src->m[8];
+
+   VGfloat m31 = dst->m[2]*src->m[0] + dst->m[5]*src->m[1] + dst->m[8]*src->m[2];
+   VGfloat m32 = dst->m[2]*src->m[3] + dst->m[5]*src->m[4] + dst->m[8]*src->m[5];
+   VGfloat m33 = dst->m[2]*src->m[6] + dst->m[5]*src->m[7] + dst->m[8]*src->m[8];
+
+   dst->m[0] = m11; dst->m[1] = m21; dst->m[2] = m31;
+   dst->m[3] = m12; dst->m[4] = m22; dst->m[5] = m32;
+   dst->m[6] = m13; dst->m[7] = m23; dst->m[8] = m33;
+}
+
+
+static INLINE void matrix_map_point(struct matrix *mat,
+                                    VGfloat x, VGfloat y,
+                                    VGfloat *out_x, VGfloat *out_y)
+{
+   /* to be able to do matrix_map_point(m, x, y, &x, &y) use
+    * temporaries */
+   VGfloat tmp_x = x, tmp_y = y;
+
+   *out_x = mat->m[0]*tmp_x + mat->m[3]*tmp_y + mat->m[6];
+   *out_y = mat->m[1]*tmp_x + mat->m[4]*tmp_y + mat->m[7];
+   if (!matrix_is_affine(mat)) {
+      VGfloat w = 1/(mat->m[2]*tmp_x + mat->m[5]*tmp_y + mat->m[8]);
+      *out_x *= w;
+      *out_y *= w;
+   }
+}
+
+static INLINE void matrix_translate(struct matrix *dst,
+                                    VGfloat tx, VGfloat ty)
+{
+   if (!matrix_is_affine(dst)) {
+      struct matrix trans_matrix;
+      matrix_load_identity(&trans_matrix);
+      trans_matrix.m[6] = tx;
+      trans_matrix.m[7] = ty;
+      matrix_mult(dst, &trans_matrix);
+   } else {
+      dst->m[6] += tx*dst->m[0] + ty*dst->m[3];
+      dst->m[7] += ty*dst->m[4] + tx*dst->m[1];
+   }
+}
+
+static INLINE void matrix_scale(struct matrix *dst,
+                                VGfloat sx, VGfloat sy)
+{
+   if (!matrix_is_affine(dst)) {
+      struct matrix scale_matrix;
+      matrix_load_identity(&scale_matrix);
+      scale_matrix.m[0] = sx;
+      scale_matrix.m[4] = sy;
+      matrix_mult(dst, &scale_matrix);
+   } else {
+      dst->m[0] *= sx; dst->m[1] *= sx;
+      dst->m[3] *= sy; dst->m[4] *= sy;
+   }
+}
+
+static INLINE void matrix_shear(struct matrix *dst,
+                                VGfloat shx, VGfloat shy)
+{
+   struct matrix shear_matrix;
+   matrix_load_identity(&shear_matrix);
+   shear_matrix.m[1] = shy;
+   shear_matrix.m[3] = shx;
+   matrix_mult(dst, &shear_matrix);
+}
+
+static INLINE void matrix_rotate(struct matrix *dst,
+                                 VGfloat angle)
+{
+   struct matrix mat;
+   float sin_val = 0;
+   float cos_val = 0;
+
+
+   if (floatsEqual(angle, 90) || floatsEqual(angle, -270))
+      sin_val = 1.f;
+   else if (floatsEqual(angle, 270) || floatsEqual(angle, -90))
+      sin_val = -1.f;
+   else if (floatsEqual(angle, 180))
+      cos_val = -1.f;
+   else {
+      float radians = DEGREES_TO_RADIANS(angle);
+      sin_val = sin(radians);
+      cos_val = cos(radians);
+   }
+
+   if (!matrix_is_affine(dst)) {
+      matrix_load_identity(&mat);
+      mat.m[0] =  cos_val;   mat.m[1] =  sin_val;
+      mat.m[3] = -sin_val;   mat.m[4] =  cos_val;
+
+      matrix_mult(dst, &mat);
+   } else  {
+      VGfloat m11 =  cos_val*dst->m[0] + sin_val*dst->m[3];
+      VGfloat m12 =  cos_val*dst->m[1] + sin_val*dst->m[4];
+      VGfloat m21 = -sin_val*dst->m[0] + cos_val*dst->m[3];
+      VGfloat m22 = -sin_val*dst->m[1] + cos_val*dst->m[4];
+      dst->m[0] = m11; dst->m[1] = m12;
+      dst->m[3] = m21; dst->m[4] = m22;
+   }
+}
+
+
+static INLINE VGfloat matrix_determinant(struct matrix *mat)
+{
+   return mat->m[0]*(mat->m[8]*mat->m[4]-mat->m[7]*mat->m[5]) -
+      mat->m[3]*(mat->m[8]*mat->m[1]-mat->m[7]*mat->m[2])+
+      mat->m[6]*(mat->m[5]*mat->m[1]-mat->m[4]*mat->m[2]);
+}
+
+
+static INLINE void matrix_adjoint(struct matrix *mat)
+{
+    VGfloat h[9];
+    h[0] = mat->m[4]*mat->m[8] - mat->m[5]*mat->m[7];
+    h[3] = mat->m[5]*mat->m[6] - mat->m[3]*mat->m[8];
+    h[6] = mat->m[3]*mat->m[7] - mat->m[4]*mat->m[6];
+    h[1] = mat->m[2]*mat->m[7] - mat->m[1]*mat->m[8];
+    h[4] = mat->m[0]*mat->m[8] - mat->m[2]*mat->m[6];
+    h[7] = mat->m[1]*mat->m[6] - mat->m[0]*mat->m[7];
+    h[2] = mat->m[1]*mat->m[5] - mat->m[2]*mat->m[4];
+    h[5] = mat->m[2]*mat->m[3] - mat->m[0]*mat->m[5];
+    h[8] = mat->m[0]*mat->m[4] - mat->m[1]*mat->m[3];
+
+
+    memcpy(mat->m, h, sizeof(VGfloat) * 9);
+}
+
+static INLINE void matrix_divs(struct matrix *mat,
+                               VGfloat s)
+{
+   mat->m[0] /= s;
+   mat->m[1] /= s;
+   mat->m[2] /= s;
+   mat->m[3] /= s;
+   mat->m[4] /= s;
+   mat->m[5] /= s;
+   mat->m[6] /= s;
+   mat->m[7] /= s;
+   mat->m[8] /= s;
+}
+
+static INLINE VGboolean matrix_invert(struct matrix *mat)
+{
+   VGfloat det = matrix_determinant(mat);
+
+   if (floatIsZero(det))
+      return VG_FALSE;
+
+   matrix_adjoint(mat);
+   matrix_divs(mat, det);
+   return VG_TRUE;
+}
+
+static INLINE VGboolean matrix_is_invertible(struct matrix *mat)
+{
+   return !floatIsZero(matrix_determinant(mat));
+}
+
+
+static INLINE VGboolean matrix_square_to_quad(VGfloat dx0, VGfloat dy0,
+                                              VGfloat dx1, VGfloat dy1,
+                                              VGfloat dx3, VGfloat dy3,
+                                              VGfloat dx2, VGfloat dy2,
+                                              struct matrix *mat)
+{
+   VGfloat ax  = dx0 - dx1 + dx2 - dx3;
+   VGfloat ay  = dy0 - dy1 + dy2 - dy3;
+
+   if (floatIsZero(ax) && floatIsZero(ay)) {
+      /* affine case */
+      matrix_inits(mat,
+                   dx1 - dx0, dy1 - dy0,  0,
+                   dx2 - dx1, dy2 - dy1,  0,
+                         dx0,       dy0,  1);
+   } else {
+      VGfloat a, b, c, d, e, f, g, h;
+      VGfloat ax1 = dx1 - dx2;
+      VGfloat ax2 = dx3 - dx2;
+      VGfloat ay1 = dy1 - dy2;
+      VGfloat ay2 = dy3 - dy2;
+
+      /* determinants */
+      VGfloat gtop    =  ax  * ay2 - ax2 * ay;
+      VGfloat htop    =  ax1 * ay  - ax  * ay1;
+      VGfloat bottom  =  ax1 * ay2 - ax2 * ay1;
+
+      if (!bottom)
+         return VG_FALSE;
+
+      g = gtop / bottom;
+      h = htop / bottom;
+
+      a = dx1 - dx0 + g * dx1;
+      b = dx3 - dx0 + h * dx3;
+      c = dx0;
+      d = dy1 - dy0 + g * dy1;
+      e = dy3 - dy0 + h * dy3;
+      f = dy0;
+
+      matrix_inits(mat,
+                   a,  d,   g,
+                   b,  e,   h,
+                   c,  f, 1.f);
+   }
+
+   return VG_TRUE;
+}
+
+static INLINE VGboolean matrix_quad_to_square(VGfloat sx0, VGfloat sy0,
+                                              VGfloat sx1, VGfloat sy1,
+                                              VGfloat sx2, VGfloat sy2,
+                                              VGfloat sx3, VGfloat sy3,
+                                              struct matrix *mat)
+{
+   if (!matrix_square_to_quad(sx0, sy0, sx1, sy1,
+                              sx2, sy2, sx3, sy3,
+                              mat))
+      return VG_FALSE;
+
+    return matrix_invert(mat);
+}
+
+
+static INLINE VGboolean matrix_quad_to_quad(VGfloat dx0, VGfloat dy0,
+                                            VGfloat dx1, VGfloat dy1,
+                                            VGfloat dx2, VGfloat dy2,
+                                            VGfloat dx3, VGfloat dy3,
+                                            VGfloat sx0, VGfloat sy0,
+                                            VGfloat sx1, VGfloat sy1,
+                                            VGfloat sx2, VGfloat sy2,
+                                            VGfloat sx3, VGfloat sy3,
+                                            struct matrix *mat)
+{
+   struct matrix sqr_to_qd;
+
+   if (!matrix_square_to_quad(dx0, dy0, dx1, dy1,
+                              dx2, dy2, dx3, dy3,
+                              mat))
+      return VG_FALSE;
+
+   if (!matrix_quad_to_square(sx0, sy0, sx1, sy1,
+                              sx2, sy2, sx3, sy3,
+                              &sqr_to_qd))
+      return VG_FALSE;
+
+   matrix_mult(mat, &sqr_to_qd);
+
+   return VG_TRUE;
+}
+
+
+static INLINE VGboolean null_line(const VGfloat *l)
+{
+   return floatsEqual(l[0], l[2]) && floatsEqual(l[1], l[3]);
+}
+
+static INLINE void line_normal(float *l, float *norm)
+{
+   norm[0] = l[0];
+   norm[1] = l[1];
+
+   norm[2] = l[0] + (l[3] - l[1]);
+   norm[3] = l[1] - (l[2] - l[0]);
+}
+
+static INLINE void line_normalize(float *l)
+{
+   float x = l[2] - l[0];
+   float y = l[3] - l[1];
+   float len = sqrt(x*x + y*y);
+   l[2] = l[0] + x/len;
+   l[3] = l[1] + y/len;
+}
+
+static INLINE VGfloat line_length(VGfloat x1, VGfloat y1,
+                                  VGfloat x2, VGfloat y2)
+{
+   VGfloat x = x2 - x1;
+   VGfloat y = y2 - y1;
+   return sqrt(x*x + y*y);
+}
+
+static INLINE VGfloat line_lengthv(const VGfloat *l)
+{
+   VGfloat x = l[2] - l[0];
+   VGfloat y = l[3] - l[1];
+   return sqrt(x*x + y*y);
+}
+
+
+static INLINE void line_point_at(float *l, float t, float *pt)
+{
+   float dx = l[2] - l[0];
+   float dy = l[3] - l[1];
+
+   pt[0] = l[0] + dx * t;
+   pt[1] = l[1] + dy * t;
+}
+
+static INLINE void vector_unit(float *vec)
+{
+   float len = sqrt(vec[0] * vec[0] + vec[1] * vec[1]);
+   vec[0] /= len;
+   vec[1] /= len;
+}
+
+static INLINE void line_normal_vector(float *line, float *vec)
+{
+   VGfloat normal[4];
+
+   line_normal(line, normal);
+
+   vec[0] = normal[2] - normal[0];
+   vec[1] = normal[3] - normal[1];
+
+   vector_unit(vec);
+}
+
+#endif
diff --git a/src/gallium/state_trackers/vega/paint.c b/src/gallium/state_trackers/vega/paint.c
new file mode 100644 (file)
index 0000000..04a6ba9
--- /dev/null
@@ -0,0 +1,699 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#include "paint.h"
+
+#include "shaders_cache.h"
+#include "matrix.h"
+#include "image.h"
+#include "st_inlines.h"
+
+#include "pipe/p_compiler.h"
+#include "pipe/p_inlines.h"
+
+#include "util/u_memory.h"
+#include "util/u_math.h"
+
+#include "cso_cache/cso_context.h"
+
+struct vg_paint {
+   struct vg_object base;
+
+   VGPaintType type;
+
+   struct {
+      VGfloat color[4];
+      VGint colori[4];
+   } solid;
+
+   struct {
+      VGColorRampSpreadMode spread;
+      VGuint color_data[1024];
+      struct {
+         VGfloat  coords[4];
+         VGint  coordsi[4];
+      } linear;
+      struct {
+         VGfloat vals[5];
+         VGint valsi[5];
+      } radial;
+      struct pipe_texture *texture;
+      struct pipe_sampler_state sampler;
+
+      VGfloat *ramp_stops;
+      VGint *ramp_stopsi;
+      VGint    num_stops;
+
+      VGboolean color_ramps_premultiplied;
+   } gradient;
+
+   struct {
+      struct pipe_texture *texture;
+      VGTilingMode tiling_mode;
+      struct pipe_sampler_state sampler;
+   } pattern;
+
+   struct pipe_constant_buffer cbuf;
+   struct pipe_shader_state fs_state;
+   void *fs;
+};
+
+static INLINE VGuint mix_pixels(VGuint p1, VGuint a, VGuint p2, VGuint b)
+{
+   VGuint t = (p1 & 0xff00ff) * a + (p2 & 0xff00ff) * b;
+   t >>= 8; t &= 0xff00ff;
+
+   p1 = ((p1 >> 8) & 0xff00ff) * a + ((p2 >> 8) & 0xff00ff) * b;
+   p1 &= 0xff00ff00; p1 |= t;
+
+   return p1;
+}
+
+static INLINE VGuint float4_to_argb(const VGfloat *clr)
+{
+   return float_to_ubyte(clr[3]) << 24 |
+      float_to_ubyte(clr[0]) << 16 |
+      float_to_ubyte(clr[1]) << 8 |
+      float_to_ubyte(clr[2]) << 0;
+}
+
+static INLINE void create_gradient_data(const VGfloat *ramp_stops,
+                                        VGint num,
+                                        VGuint *data,
+                                        VGint size)
+{
+   VGint i;
+   VGint pos = 0;
+   VGfloat fpos = 0, incr = 1.f / size;
+   VGuint last_color;
+
+   while (fpos < ramp_stops[0]) {
+      data[pos] = float4_to_argb(ramp_stops + 1);
+      fpos += incr;
+      ++pos;
+   }
+
+   for (i = 0; i < num - 1; ++i) {
+      VGint rcur  = 5 * i;
+      VGint rnext = 5 * (i + 1);
+      VGfloat delta = 1.f/(ramp_stops[rnext] - ramp_stops[rcur]);
+      while (fpos < ramp_stops[rnext] && pos < size) {
+         VGint dist = 256 * ((fpos - ramp_stops[rcur]) * delta);
+         VGint idist = 256 - dist;
+         VGuint current_color = float4_to_argb(ramp_stops + rcur + 1);
+         VGuint next_color = float4_to_argb(ramp_stops + rnext + 1);
+         data[pos] = mix_pixels(current_color, idist,
+                                next_color, dist);
+         fpos += incr;
+         ++pos;
+      }
+   }
+
+   last_color = float4_to_argb(ramp_stops + ((num - 1) * 5 + 1));
+   while (pos < size) {
+      data[pos] = last_color;
+      ++pos;
+   }
+   data[size-1] = last_color;
+}
+
+static INLINE struct pipe_texture *create_gradient_texture(struct vg_paint *p)
+{
+   struct pipe_context *pipe = p->base.ctx->pipe;
+   struct pipe_screen *screen = pipe->screen;
+   struct pipe_texture *tex = 0;
+   struct pipe_texture templ;
+
+   memset(&templ, 0, sizeof(templ));
+   templ.target = PIPE_TEXTURE_1D;
+   templ.format = PIPE_FORMAT_A8R8G8B8_UNORM;
+   templ.last_level = 0;
+   templ.width[0] = 1024;
+   templ.height[0] = 1;
+   templ.depth[0] = 1;
+   pf_get_block(PIPE_FORMAT_A8R8G8B8_UNORM, &templ.block);
+   templ.tex_usage = PIPE_TEXTURE_USAGE_SAMPLER;
+
+   tex = screen->texture_create(screen, &templ);
+
+   { /* upload color_data */
+      struct pipe_transfer *transfer =
+         st_no_flush_get_tex_transfer(p->base.ctx, tex, 0, 0, 0,
+                                      PIPE_TRANSFER_WRITE, 0, 0, 1024, 1);
+      void *map = screen->transfer_map(screen, transfer);
+      memcpy(map, p->gradient.color_data, sizeof(VGint)*1024);
+      screen->transfer_unmap(screen, transfer);
+      screen->tex_transfer_destroy(transfer);
+   }
+
+   return tex;
+}
+
+struct vg_paint * paint_create(struct vg_context *ctx)
+{
+   struct vg_paint *paint = CALLOC_STRUCT(vg_paint);
+   const VGfloat default_color[] = {0.0f, 0.0f, 0.0f, 1.0f};
+   const VGfloat def_ling[] = {0.0f, 0.0f, 1.0f, 0.0f};
+   const VGfloat def_radg[] = {0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
+   vg_init_object(&paint->base, ctx, VG_OBJECT_PAINT);
+   vg_context_add_object(ctx, VG_OBJECT_PAINT, paint);
+
+   paint->type = VG_PAINT_TYPE_COLOR;
+   memcpy(paint->solid.color, default_color,
+          4 * sizeof(VGfloat));
+   paint->gradient.spread = VG_COLOR_RAMP_SPREAD_PAD;
+   memcpy(paint->gradient.linear.coords, def_ling,
+          4 * sizeof(VGfloat));
+   memcpy(paint->gradient.radial.vals, def_radg,
+          5 * sizeof(VGfloat));
+
+   paint->gradient.sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+   paint->gradient.sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+   paint->gradient.sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
+   paint->gradient.sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
+   paint->gradient.sampler.normalized_coords = 1;
+
+   memcpy(&paint->pattern.sampler,
+          &paint->gradient.sampler,
+          sizeof(struct pipe_sampler_state));
+
+   return paint;
+}
+
+void paint_destroy(struct vg_paint *paint)
+{
+   struct vg_context *ctx = paint->base.ctx;
+   if (paint->pattern.texture)
+      pipe_texture_reference(&paint->pattern.texture, NULL);
+   if (ctx)
+      vg_context_remove_object(ctx, VG_OBJECT_PAINT, paint);
+
+   free(paint->gradient.ramp_stopsi);
+   free(paint->gradient.ramp_stops);
+   free(paint);
+}
+
+void paint_set_color(struct vg_paint *paint,
+                     const VGfloat *color)
+{
+   paint->solid.color[0] = color[0];
+   paint->solid.color[1] = color[1];
+   paint->solid.color[2] = color[2];
+   paint->solid.color[3] = color[3];
+
+   paint->solid.colori[0] = FLT_TO_INT(color[0]);
+   paint->solid.colori[1] = FLT_TO_INT(color[1]);
+   paint->solid.colori[2] = FLT_TO_INT(color[2]);
+   paint->solid.colori[3] = FLT_TO_INT(color[3]);
+}
+
+static INLINE void paint_color_buffer(struct vg_paint *paint, void *buffer)
+{
+   VGfloat *map = (VGfloat*)buffer;
+   memcpy(buffer, paint->solid.color, 4 * sizeof(VGfloat));
+   map[4] = 0.f;
+   map[5] = 1.f;
+   map[6] = 2.f;
+   map[7] = 4.f;
+}
+
+static INLINE void paint_linear_gradient_buffer(struct vg_paint *paint, void *buffer)
+{
+   struct vg_context *ctx = paint->base.ctx;
+   VGfloat *map = (VGfloat*)buffer;
+
+   map[0] = paint->gradient.linear.coords[2] - paint->gradient.linear.coords[0];
+   map[1] = paint->gradient.linear.coords[3] - paint->gradient.linear.coords[1];
+   map[2] = 1.f / (map[0] * map[0] + map[1] * map[1]);
+   map[3] = 1.f;
+
+   map[4] = 0.f;
+   map[5] = 1.f;
+   map[6] = 2.f;
+   map[7] = 4.f;
+   {
+      struct matrix mat;
+      struct matrix inv;
+      matrix_load_identity(&mat);
+      matrix_translate(&mat, -paint->gradient.linear.coords[0], -paint->gradient.linear.coords[1]);
+      memcpy(&inv, &ctx->state.vg.fill_paint_to_user_matrix,
+             sizeof(struct matrix));
+      matrix_invert(&inv);
+      matrix_mult(&inv, &mat);
+      memcpy(&mat, &inv,
+             sizeof(struct matrix));
+
+      map[8]  = mat.m[0]; map[9]  = mat.m[3]; map[10] = mat.m[6]; map[11] = 0.f;
+      map[12] = mat.m[1]; map[13] = mat.m[4]; map[14] = mat.m[7]; map[15] = 0.f;
+      map[16] = mat.m[2]; map[17] = mat.m[5]; map[18] = mat.m[8]; map[19] = 0.f;
+   }
+#if 0
+   debug_printf("Coords  (%f, %f, %f, %f)\n",
+                map[0], map[1], map[2], map[3]);
+#endif
+}
+
+
+static INLINE void paint_radial_gradient_buffer(struct vg_paint *paint, void *buffer)
+{
+   VGfloat *radialCoords = paint->gradient.radial.vals;
+   struct vg_context *ctx = paint->base.ctx;
+
+   VGfloat *map = (VGfloat*)buffer;
+
+   map[0] = radialCoords[0] - radialCoords[2];
+   map[1] = radialCoords[1] - radialCoords[3];
+   map[2] = -map[0] * map[0] - map[1] * map[1] +
+            radialCoords[4] * radialCoords[4];
+   map[3] = 1.f;
+
+   map[4] = 0.f;
+   map[5] = 1.f;
+   map[6] = 2.f;
+   map[7] = 4.f;
+
+   {
+      struct matrix mat;
+      struct matrix inv;
+      matrix_load_identity(&mat);
+      matrix_translate(&mat, -radialCoords[2], -radialCoords[3]);
+      memcpy(&inv, &ctx->state.vg.fill_paint_to_user_matrix,
+             sizeof(struct matrix));
+      matrix_invert(&inv);
+      matrix_mult(&inv, &mat);
+      memcpy(&mat, &inv,
+             sizeof(struct matrix));
+
+      map[8]  = mat.m[0]; map[9]  = mat.m[3]; map[10] = mat.m[6]; map[11] = 0.f;
+      map[12] = mat.m[1]; map[13] = mat.m[4]; map[14] = mat.m[7]; map[15] = 0.f;
+      map[16] = mat.m[2]; map[17] = mat.m[5]; map[18] = mat.m[8]; map[19] = 0.f;
+   }
+
+#if 0
+   debug_printf("Coords  (%f, %f, %f, %f)\n",
+                map[0], map[1], map[2], map[3]);
+#endif
+}
+
+
+static INLINE void  paint_pattern_buffer(struct vg_paint *paint, void *buffer)
+{
+   struct vg_context *ctx = paint->base.ctx;
+
+   VGfloat *map = (VGfloat *)buffer;
+   memcpy(map, paint->solid.color, 4 * sizeof(VGfloat));
+
+   map[4] = 0.f;
+   map[5] = 1.f;
+   map[6] = paint->pattern.texture->width[0];
+   map[7] = paint->pattern.texture->height[0];
+   {
+      struct matrix mat;
+      memcpy(&mat, &ctx->state.vg.fill_paint_to_user_matrix,
+             sizeof(struct matrix));
+      matrix_invert(&mat);
+      {
+         struct matrix pm;
+         memcpy(&pm, &ctx->state.vg.path_user_to_surface_matrix,
+                sizeof(struct matrix));
+         matrix_invert(&pm);
+         matrix_mult(&pm, &mat);
+         memcpy(&mat, &pm, sizeof(struct matrix));
+      }
+
+      map[8]  = mat.m[0]; map[9]  = mat.m[3]; map[10] = mat.m[6]; map[11] = 0.f;
+      map[12] = mat.m[1]; map[13] = mat.m[4]; map[14] = mat.m[7]; map[15] = 0.f;
+      map[16] = mat.m[2]; map[17] = mat.m[5]; map[18] = mat.m[8]; map[19] = 0.f;
+   }
+}
+
+void paint_set_type(struct vg_paint *paint, VGPaintType type)
+{
+   paint->type = type;
+}
+
+void paint_set_ramp_stops(struct vg_paint *paint, const VGfloat *stops,
+                          int num)
+{
+   const VGfloat default_stops[] = {0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
+                                    1.0f, 1.0f, 1.0f, 1.0f, 1.0f};
+   VGint i;
+   const VGint num_stops = num / 5;
+   VGfloat last_coord;
+
+   paint->gradient.num_stops = num;
+   if (num) {
+      free(paint->gradient.ramp_stops);
+      paint->gradient.ramp_stops = malloc(sizeof(VGfloat)*num);
+      memcpy(paint->gradient.ramp_stops, stops, sizeof(VGfloat)*num);
+   } else
+      return;
+
+   /* stops must be in increasing order. the last stop is 1.0. if the
+    * first one is bigger than 1 then the whole sequence is invalid*/
+   if (stops[0] > 1) {
+      stops = default_stops;
+      num = 10;
+   }
+   last_coord = stops[0];
+   for (i = 1; i < num_stops; ++i) {
+      VGint idx = 5 * i;
+      VGfloat coord = stops[idx];
+      if (!floatsEqual(last_coord, coord) && coord < last_coord) {
+         stops = default_stops;
+         num = 10;
+         break;
+      }
+      last_coord = coord;
+   }
+
+   create_gradient_data(stops, num / 5, paint->gradient.color_data,
+                        1024);
+
+   if (paint->gradient.texture) {
+      pipe_texture_reference(&paint->gradient.texture, NULL);
+      paint->gradient.texture = 0;
+   }
+
+   paint->gradient.texture = create_gradient_texture(paint);
+}
+
+void paint_set_colori(struct vg_paint *p,
+                      VGuint rgba)
+{
+   p->solid.color[0] = ((rgba >> 24) & 0xff) / 255.f;
+   p->solid.color[1] = ((rgba >> 16) & 0xff) / 255.f;
+   p->solid.color[2] = ((rgba >>  8) & 0xff) / 255.f;
+   p->solid.color[3] = ((rgba >>  0) & 0xff) / 255.f;
+}
+
+VGuint paint_colori(struct vg_paint *p)
+{
+#define F2B(f) (float_to_ubyte(f))
+
+   return ((F2B(p->solid.color[0]) << 24) |
+           (F2B(p->solid.color[1]) << 16) |
+           (F2B(p->solid.color[2]) << 8)  |
+           (F2B(p->solid.color[3]) << 0));
+#undef F2B
+}
+
+void paint_set_linear_gradient(struct vg_paint *paint,
+                               const VGfloat *coords)
+{
+   memcpy(paint->gradient.linear.coords, coords, sizeof(VGfloat) * 4);
+}
+
+void paint_set_spread_mode(struct vg_paint *paint,
+                           VGint mode)
+{
+   paint->gradient.spread = mode;
+   switch(mode) {
+   case VG_COLOR_RAMP_SPREAD_PAD:
+      paint->gradient.sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+      break;
+   case VG_COLOR_RAMP_SPREAD_REPEAT:
+      paint->gradient.sampler.wrap_s = PIPE_TEX_WRAP_REPEAT;
+      break;
+   case VG_COLOR_RAMP_SPREAD_REFLECT:
+      paint->gradient.sampler.wrap_s = PIPE_TEX_WRAP_MIRROR_REPEAT;
+      break;
+   }
+}
+
+VGColorRampSpreadMode paint_spread_mode(struct vg_paint *paint)
+{
+   return paint->gradient.spread;
+}
+
+void paint_set_radial_gradient(struct vg_paint *paint,
+                               const VGfloat *values)
+{
+   memcpy(paint->gradient.radial.vals, values, sizeof(VGfloat) * 5);
+}
+
+void paint_set_pattern(struct vg_paint *paint,
+                       struct vg_image *img)
+{
+   if (paint->pattern.texture)
+      pipe_texture_reference(&paint->pattern.texture, NULL);
+
+   paint->pattern.texture = 0;
+   pipe_texture_reference(&paint->pattern.texture,
+                          img->texture);
+}
+
+void paint_set_pattern_tiling(struct vg_paint *paint,
+                              VGTilingMode mode)
+{
+   paint->pattern.tiling_mode = mode;
+
+   switch(mode) {
+   case VG_TILE_FILL:
+      paint->pattern.sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_BORDER;
+      paint->pattern.sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_BORDER;
+      break;
+   case VG_TILE_PAD:
+      paint->pattern.sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+      paint->pattern.sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+      break;
+   case VG_TILE_REPEAT:
+      paint->pattern.sampler.wrap_s = PIPE_TEX_WRAP_REPEAT;
+      paint->pattern.sampler.wrap_t = PIPE_TEX_WRAP_REPEAT;
+      break;
+   case VG_TILE_REFLECT:
+      paint->pattern.sampler.wrap_s = PIPE_TEX_WRAP_MIRROR_REPEAT;
+      paint->pattern.sampler.wrap_t = PIPE_TEX_WRAP_MIRROR_REPEAT;
+      break;
+   default:
+      debug_assert("!Unknown tiling mode");
+   }
+}
+
+void paint_get_color(struct vg_paint *paint,
+                     VGfloat *color)
+{
+   color[0] = paint->solid.color[0];
+   color[1] = paint->solid.color[1];
+   color[2] = paint->solid.color[2];
+   color[3] = paint->solid.color[3];
+}
+
+void paint_ramp_stops(struct vg_paint *paint, VGfloat *stops,
+                      int num)
+{
+   memcpy(stops, paint->gradient.ramp_stops, sizeof(VGfloat)*num);
+}
+
+void paint_linear_gradient(struct vg_paint *paint,
+                           VGfloat *coords)
+{
+   memcpy(coords, paint->gradient.linear.coords, sizeof(VGfloat)*4);
+}
+
+void paint_radial_gradient(struct vg_paint *paint,
+                           VGfloat *coords)
+{
+   memcpy(coords, paint->gradient.radial.vals, sizeof(VGfloat)*5);
+}
+
+int paint_num_ramp_stops(struct vg_paint *paint)
+{
+   return paint->gradient.num_stops;
+}
+
+VGPaintType paint_type(struct vg_paint *paint)
+{
+   return paint->type;
+}
+
+void paint_set_coloriv(struct vg_paint *paint,
+                      const VGint *color)
+{
+   paint->solid.color[0] = color[0];
+   paint->solid.color[1] = color[1];
+   paint->solid.color[2] = color[2];
+   paint->solid.color[3] = color[3];
+
+   paint->solid.colori[0] = color[0];
+   paint->solid.colori[1] = color[1];
+   paint->solid.colori[2] = color[2];
+   paint->solid.colori[3] = color[3];
+}
+
+void paint_get_coloriv(struct vg_paint *paint,
+                      VGint *color)
+{
+   color[0] = paint->solid.colori[0];
+   color[1] = paint->solid.colori[1];
+   color[2] = paint->solid.colori[2];
+   color[3] = paint->solid.colori[3];
+}
+
+void paint_set_color_ramp_premultiplied(struct vg_paint *paint,
+                                        VGboolean set)
+{
+   paint->gradient.color_ramps_premultiplied = set;
+}
+
+VGboolean paint_color_ramp_premultiplied(struct vg_paint *paint)
+{
+   return paint->gradient.color_ramps_premultiplied;
+}
+
+void paint_set_ramp_stopsi(struct vg_paint *paint, const VGint *stops,
+                           int num)
+{
+   if (num) {
+      free(paint->gradient.ramp_stopsi);
+      paint->gradient.ramp_stopsi = malloc(sizeof(VGint)*num);
+      memcpy(paint->gradient.ramp_stopsi, stops, sizeof(VGint)*num);
+   }
+}
+
+void paint_ramp_stopsi(struct vg_paint *paint, VGint *stops,
+                       int num)
+{
+   memcpy(stops, paint->gradient.ramp_stopsi, sizeof(VGint)*num);
+}
+
+void paint_set_linear_gradienti(struct vg_paint *paint,
+                                const VGint *coords)
+{
+   memcpy(paint->gradient.linear.coordsi, coords, sizeof(VGint) * 4);
+}
+
+void paint_linear_gradienti(struct vg_paint *paint,
+                            VGint *coords)
+{
+   memcpy(coords, paint->gradient.linear.coordsi, sizeof(VGint)*4);
+}
+
+void paint_set_radial_gradienti(struct vg_paint *paint,
+                                const VGint *values)
+{
+   memcpy(paint->gradient.radial.valsi, values, sizeof(VGint) * 5);
+}
+
+void paint_radial_gradienti(struct vg_paint *paint,
+                            VGint *coords)
+{
+   memcpy(coords, paint->gradient.radial.valsi, sizeof(VGint)*5);
+}
+
+VGTilingMode paint_pattern_tiling(struct vg_paint *paint)
+{
+   return paint->pattern.tiling_mode;
+}
+
+VGint paint_bind_samplers(struct vg_paint *paint, struct pipe_sampler_state **samplers,
+                          struct pipe_texture **textures)
+{
+   struct vg_context *ctx = vg_current_context();
+
+   switch(paint->type) {
+   case VG_PAINT_TYPE_LINEAR_GRADIENT:
+   case VG_PAINT_TYPE_RADIAL_GRADIENT: {
+      if (paint->gradient.texture) {
+         paint->gradient.sampler.min_img_filter = image_sampler_filter(ctx);
+         paint->gradient.sampler.mag_img_filter = image_sampler_filter(ctx);
+         samplers[0] = &paint->gradient.sampler;
+         textures[0] = paint->gradient.texture;
+         return 1;
+      }
+   }
+      break;
+   case VG_PAINT_TYPE_PATTERN: {
+      memcpy(paint->pattern.sampler.border_color,
+             ctx->state.vg.tile_fill_color,
+             sizeof(VGfloat) * 4);
+      paint->pattern.sampler.min_img_filter = image_sampler_filter(ctx);
+      paint->pattern.sampler.mag_img_filter = image_sampler_filter(ctx);
+      samplers[0] = &paint->pattern.sampler;
+      textures[0] = paint->pattern.texture;
+      return 1;
+   }
+      break;
+   default:
+      samplers[0] = &paint->pattern.sampler; /* dummy */
+      textures[0] = 0;
+      return 0;
+      break;
+   }
+   return 0;
+}
+
+void paint_resolve_type(struct vg_paint *paint)
+{
+   if (paint->type == VG_PAINT_TYPE_PATTERN &&
+       !paint->pattern.texture) {
+      paint->type = VG_PAINT_TYPE_COLOR;
+   }
+}
+
+VGint paint_constant_buffer_size(struct vg_paint *paint)
+{
+   switch(paint->type) {
+   case VG_PAINT_TYPE_COLOR:
+      return 8 * sizeof(VGfloat);/*4 color + 4 constants (0.f,1.f,2.f,4.f)*/
+      break;
+   case VG_PAINT_TYPE_LINEAR_GRADIENT:
+      return 20 * sizeof(VGfloat);
+      break;
+   case VG_PAINT_TYPE_RADIAL_GRADIENT:
+      return 20 * sizeof(VGfloat);
+      break;
+   case VG_PAINT_TYPE_PATTERN:
+      return 20 * sizeof(VGfloat);
+      break;
+   default:
+      debug_printf("Uknown paint type: %d\n", paint->type);
+   }
+
+   return 0;
+}
+
+void paint_fill_constant_buffer(struct vg_paint *paint,
+                                void *buffer)
+{
+   switch(paint->type) {
+   case VG_PAINT_TYPE_COLOR:
+      paint_color_buffer(paint, buffer);
+      break;
+   case VG_PAINT_TYPE_LINEAR_GRADIENT:
+      paint_linear_gradient_buffer(paint, buffer);
+      break;
+   case VG_PAINT_TYPE_RADIAL_GRADIENT:
+      paint_radial_gradient_buffer(paint, buffer);
+      break;
+   case VG_PAINT_TYPE_PATTERN:
+      paint_pattern_buffer(paint, buffer);
+      break;
+
+   default:
+      abort();
+   }
+}
diff --git a/src/gallium/state_trackers/vega/paint.h b/src/gallium/state_trackers/vega/paint.h
new file mode 100644 (file)
index 0000000..999b5c1
--- /dev/null
@@ -0,0 +1,118 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#ifndef PAINT_H
+#define PAINT_H
+
+#include "vg_context.h"
+
+#include "VG/openvg.h"
+#include "pipe/p_state.h"
+
+struct vg_paint;
+struct vg_image;
+struct pipe_sampler_state;
+struct pipe_texture;
+
+struct vg_paint *paint_create(struct vg_context *ctx);
+void paint_destroy(struct vg_paint *paint);
+
+void paint_set_color(struct vg_paint *paint,
+                     const VGfloat *color);
+void paint_get_color(struct vg_paint *paint,
+                     VGfloat *color);
+
+void paint_set_coloriv(struct vg_paint *paint,
+                      const VGint *color);
+void paint_get_coloriv(struct vg_paint *paint,
+                      VGint *color);
+
+void paint_set_colori(struct vg_paint *paint,
+                      VGuint rgba);
+
+VGuint paint_colori(struct vg_paint *paint);
+
+void paint_set_type(struct vg_paint *paint, VGPaintType type);
+VGPaintType paint_type(struct vg_paint *paint);
+void paint_resolve_type(struct vg_paint *paint);
+
+void paint_set_linear_gradient(struct vg_paint *paint,
+                               const VGfloat *coords);
+void paint_linear_gradient(struct vg_paint *paint,
+                           VGfloat *coords);
+void paint_set_linear_gradienti(struct vg_paint *paint,
+                               const VGint *coords);
+void paint_linear_gradienti(struct vg_paint *paint,
+                           VGint *coords);
+
+
+void paint_set_radial_gradient(struct vg_paint *paint,
+                               const VGfloat *values);
+void paint_radial_gradient(struct vg_paint *paint,
+                           VGfloat *coords);
+void paint_set_radial_gradienti(struct vg_paint *paint,
+                                const VGint *values);
+void paint_radial_gradienti(struct vg_paint *paint,
+                            VGint *coords);
+
+
+void paint_set_ramp_stops(struct vg_paint *paint, const VGfloat *stops,
+                          int num);
+void paint_ramp_stops(struct vg_paint *paint, VGfloat *stops,
+                      int num);
+
+void paint_set_ramp_stopsi(struct vg_paint *paint, const VGint *stops,
+                           int num);
+void paint_ramp_stopsi(struct vg_paint *paint, VGint *stops,
+                       int num);
+
+int paint_num_ramp_stops(struct vg_paint *paint);
+
+void paint_set_spread_mode(struct vg_paint *paint,
+                           VGint mode);
+VGColorRampSpreadMode paint_spread_mode(struct vg_paint *paint);
+
+
+void paint_set_pattern(struct vg_paint *paint,
+                       struct vg_image *img);
+void paint_set_pattern_tiling(struct vg_paint *paint,
+                              VGTilingMode mode);
+VGTilingMode paint_pattern_tiling(struct vg_paint *paint);
+
+void paint_set_color_ramp_premultiplied(struct vg_paint *paint,
+                                        VGboolean set);
+VGboolean paint_color_ramp_premultiplied(struct vg_paint *paint);
+
+
+VGint paint_bind_samplers(struct vg_paint *paint, struct pipe_sampler_state **samplers,
+                          struct pipe_texture **textures);
+
+VGint paint_constant_buffer_size(struct vg_paint *paint);
+void paint_fill_constant_buffer(struct vg_paint *paint,
+                                void *buffer);
+
+
+#endif
diff --git a/src/gallium/state_trackers/vega/path.c b/src/gallium/state_trackers/vega/path.c
new file mode 100644 (file)
index 0000000..d04f9d9
--- /dev/null
@@ -0,0 +1,2034 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#include "path.h"
+
+#include "stroker.h"
+#include "polygon.h"
+#include "bezier.h"
+#include "matrix.h"
+#include "vg_context.h"
+#include "util_array.h"
+#include "arc.h"
+#include "path_utils.h"
+#include "paint.h"
+#include "shader.h"
+
+#include "util/u_memory.h"
+
+#include <assert.h>
+
+#define DEBUG_PATH 0
+
+struct path {
+   struct vg_object base;
+   VGbitfield caps;
+   VGboolean dirty;
+   VGboolean dirty_stroke;
+
+   VGPathDatatype datatype;
+
+   VGfloat scale;
+   VGfloat bias;
+
+   VGint num_segments;
+
+   struct array * segments;
+   struct array * control_points;
+
+   struct {
+      struct polygon_array polygon_array;
+      struct matrix matrix;
+   } fill_polys;
+
+   struct {
+      struct path *path;
+      struct matrix matrix;
+      VGfloat stroke_width;
+      VGfloat miter_limit;
+      VGCapStyle cap_style;
+      VGJoinStyle join_style;
+   } stroked;
+};
+
+
+static INLINE void data_at(void **data,
+                           struct path *p,
+                           VGint start, VGint count,
+                           VGfloat *out)
+{
+   VGPathDatatype dt = p->datatype;
+   VGint i;
+   VGint end = start + count;
+   VGfloat *itr = out;
+
+   switch(dt) {
+   case VG_PATH_DATATYPE_S_8: {
+      VGbyte **bdata = (VGbyte **)data;
+      for (i = start; i < end; ++i) {
+         *itr = (*bdata)[i];
+         ++itr;
+      }
+      *bdata += count;
+   }
+      break;
+   case VG_PATH_DATATYPE_S_16: {
+      VGshort **bdata = (VGshort **)data;
+      for (i = start; i < end; ++i) {
+         *itr = (*bdata)[i];
+         ++itr;
+      }
+      *bdata += count;
+   }
+      break;
+   case VG_PATH_DATATYPE_S_32: {
+      VGint **bdata = (VGint **)data;
+      for (i = start; i < end; ++i) {
+         *itr = (*bdata)[i];
+         ++itr;
+      }
+      *bdata += count;
+   }
+      break;
+   case VG_PATH_DATATYPE_F: {
+      VGfloat **fdata = (VGfloat **)data;
+      for (i = start; i < end; ++i) {
+         *itr = (*fdata)[i];
+         ++itr;
+      }
+      *fdata += count;
+   }
+      break;
+   default:
+      debug_assert(!"Unknown path datatype!");
+   }
+}
+
+
+void vg_float_to_datatype(VGPathDatatype datatype,
+                          VGubyte *common_data,
+                          const VGfloat *data,
+                          VGint num_coords)
+{
+   VGint i;
+   switch(datatype) {
+   case VG_PATH_DATATYPE_S_8: {
+      for (i = 0; i < num_coords; ++i) {
+         common_data[i] = (VGubyte)data[i];
+      }
+   }
+      break;
+   case VG_PATH_DATATYPE_S_16: {
+      VGshort *buf = (VGshort*)common_data;
+      for (i = 0; i < num_coords; ++i) {
+         buf[i] = (VGshort)data[i];
+      }
+   }
+      break;
+   case VG_PATH_DATATYPE_S_32: {
+      VGint *buf = (VGint*)common_data;
+      for (i = 0; i < num_coords; ++i) {
+         buf[i] = (VGint)data[i];
+      }
+   }
+      break;
+   case VG_PATH_DATATYPE_F: {
+      memcpy(common_data, data, sizeof(VGfloat) * num_coords);
+   }
+      break;
+   default:
+      debug_assert(!"Unknown path datatype!");
+   }
+}
+
+static void coords_adjust_by_scale_bias(struct path *p,
+                                        void *pdata, VGint num_coords,
+                                        VGfloat scale, VGfloat bias,
+                                        VGPathDatatype datatype)
+{
+   VGfloat data[8];
+   void *coords = (VGfloat *)pdata;
+   VGubyte *common_data = (VGubyte *)pdata;
+   VGint size_dst = size_for_datatype(datatype);
+   VGint i;
+
+   for (i = 0; i < num_coords; ++i) {
+      data_at(&coords, p, 0, 1, data);
+      data[0] = data[0] * scale + bias;
+      vg_float_to_datatype(datatype, common_data, data, 1);
+      common_data += size_dst;
+   }
+}
+
+struct path * path_create(VGPathDatatype dt, VGfloat scale, VGfloat bias,
+                          VGint segmentCapacityHint,
+                          VGint coordCapacityHint,
+                          VGbitfield capabilities)
+{
+   struct path *path = CALLOC_STRUCT(path);
+
+   vg_init_object(&path->base, vg_current_context(), VG_OBJECT_PATH);
+   path->caps = capabilities & VG_PATH_CAPABILITY_ALL;
+   vg_context_add_object(vg_current_context(), VG_OBJECT_PATH, path);
+
+   path->datatype = dt;
+   path->scale = scale;
+   path->bias = bias;
+
+   path->segments = array_create(size_for_datatype(VG_PATH_DATATYPE_S_8));
+   path->control_points = array_create(size_for_datatype(dt));
+
+   path->dirty = VG_TRUE;
+   path->dirty_stroke = VG_TRUE;
+
+   return path;
+}
+
+void path_destroy(struct path *p)
+{
+   vg_context_remove_object(vg_current_context(), VG_OBJECT_PATH, p);
+
+   array_destroy(p->segments);
+   array_destroy(p->control_points);
+   array_destroy(p->fill_polys.polygon_array.array);
+
+   if (p->stroked.path)
+      path_destroy(p->stroked.path);
+
+   free(p);
+}
+
+VGbitfield path_capabilities(struct path *p)
+{
+   return p->caps;
+}
+
+void path_set_capabilities(struct path *p, VGbitfield bf)
+{
+   p->caps = (bf & VG_PATH_CAPABILITY_ALL);
+}
+
+void path_append_data(struct path *p,
+                      VGint numSegments,
+                      const VGubyte * pathSegments,
+                      const void * pathData)
+{
+   VGint old_segments = p->num_segments;
+   VGint num_new_coords = num_elements_for_segments(pathSegments, numSegments);
+   array_append_data(p->segments, pathSegments, numSegments);
+   array_append_data(p->control_points, pathData, num_new_coords);
+
+   p->num_segments += numSegments;
+   if (!floatsEqual(p->scale, 1.f) || !floatsEqual(p->bias, 0.f)) {
+      VGubyte *coords = (VGubyte*)p->control_points->data;
+      coords_adjust_by_scale_bias(p,
+                                  coords + old_segments * p->control_points->datatype_size,
+                                  num_new_coords,
+                                  p->scale, p->bias, p->datatype);
+   }
+   p->dirty = VG_TRUE;
+   p->dirty_stroke = VG_TRUE;
+}
+
+VGint path_num_segments(struct path *p)
+{
+   return p->num_segments;
+}
+
+static INLINE void map_if_relative(VGfloat ox, VGfloat oy,
+                                   VGboolean relative,
+                                   VGfloat *x, VGfloat *y)
+{
+   if (relative) {
+      if (x)
+         *x += ox;
+      if (y)
+         *y += oy;
+   }
+}
+
+static INLINE void close_polygon(struct polygon *current,
+                                 VGfloat sx, VGfloat sy,
+                                 VGfloat ox, VGfloat oy,
+                                 struct  matrix *matrix)
+{
+   if (!floatsEqual(sx, ox) ||
+       !floatsEqual(sy, oy)) {
+      VGfloat x0 = sx;
+      VGfloat y0 = sy;
+      matrix_map_point(matrix, x0, y0, &x0, &y0);
+      polygon_vertex_append(current, x0, y0);
+   }
+}
+
+static void convert_path(struct path *p,
+                          VGPathDatatype to,
+                          void *dst,
+                          VGint num_coords)
+{
+   VGfloat data[8];
+   void *coords = (VGfloat *)p->control_points->data;
+   VGubyte *common_data = (VGubyte *)dst;
+   VGint size_dst = size_for_datatype(to);
+   VGint i;
+
+   for (i = 0; i < num_coords; ++i) {
+      data_at(&coords, p, 0, 1, data);
+      vg_float_to_datatype(to, common_data, data, 1);
+      common_data += size_dst;
+   }
+}
+
+
+static void polygon_array_calculate_bounds( struct polygon_array *polyarray )
+{
+   struct array *polys = polyarray->array;
+   VGfloat min_x, max_x;
+   VGfloat min_y, max_y;
+   VGfloat bounds[4];
+   unsigned i;
+
+   assert(polys);
+   assert(polys->num_elements);
+   polygon_bounding_rect((((struct polygon**)polys->data)[0]), bounds);
+   min_x = bounds[0];
+   min_y = bounds[1];
+   max_x = bounds[0] + bounds[2];
+   max_y = bounds[1] + bounds[3];
+   for (i = 1; i < polys->num_elements; ++i) {
+      struct polygon *p = (((struct polygon**)polys->data)[i]);
+      polygon_bounding_rect(p, bounds);
+      min_x = MIN2(min_x, bounds[0]);
+      min_y = MIN2(min_y, bounds[1]);
+      max_x = MAX2(max_x, bounds[0] + bounds[2]);
+      max_y = MAX2(max_y, bounds[1] + bounds[3]);
+   }
+
+   polyarray->min_x = min_x;
+   polyarray->min_y = min_y;
+   polyarray->max_x = max_x;
+   polyarray->max_y = max_y;
+}
+
+
+static struct polygon_array * path_get_fill_polygons(struct path *p, struct matrix *matrix)
+{
+   VGint i;
+   struct polygon *current = 0;
+   VGfloat sx, sy, px, py, ox, oy;
+   VGfloat x0, y0, x1, y1, x2, y2, x3, y3;
+   VGfloat data[8];
+   void *coords = (VGfloat *)p->control_points->data;
+   struct array *array;
+
+   if (p->fill_polys.polygon_array.array)
+   {
+      if (memcmp( &p->fill_polys.matrix,
+                  matrix,
+                  sizeof *matrix ) == 0 && p->dirty == VG_FALSE)
+      {
+         return &p->fill_polys.polygon_array;
+      }
+      else {
+         array_destroy( p->fill_polys.polygon_array.array );
+         p->fill_polys.polygon_array.array = NULL;
+      }
+   }
+
+   array = array_create(sizeof(struct array*));
+
+   sx = sy = px = py = ox = oy = 0.f;
+
+   current = polygon_create(32);
+
+   for (i = 0; i < p->num_segments; ++i) {
+      VGubyte segment = ((VGubyte*)(p->segments->data))[i];
+      VGint command = SEGMENT_COMMAND(segment);
+      VGboolean relative = SEGMENT_ABS_REL(segment);
+
+      switch(command) {
+      case VG_CLOSE_PATH:
+         close_polygon(current, sx, sy, ox, oy, matrix);
+         ox = sx;
+         oy = sy;
+         break;
+      case VG_MOVE_TO:
+         if (current && polygon_vertex_count(current) > 0) {
+            /* add polygon */
+            close_polygon(current, sx, sy, ox, oy, matrix);
+            array_append_data(array, &current, 1);
+            current = polygon_create(32);
+         }
+         data_at(&coords, p, 0, 2, data);
+         x0 = data[0];
+         y0 = data[1];
+         map_if_relative(ox, oy, relative, &x0, &y0);
+         sx = x0;
+         sy = y0;
+         ox = x0;
+         oy = y0;
+         px = x0;
+         py = y0;
+         matrix_map_point(matrix, x0, y0, &x0, &y0);
+         polygon_vertex_append(current, x0, y0);
+         break;
+      case VG_LINE_TO:
+         data_at(&coords, p, 0, 2, data);
+         x0 = data[0];
+         y0 = data[1];
+         map_if_relative(ox, oy, relative, &x0, &y0);
+         ox = x0;
+         oy = y0;
+         px = x0;
+         py = y0;
+         matrix_map_point(matrix, x0, y0, &x0, &y0);
+         polygon_vertex_append(current, x0, y0);
+         break;
+      case VG_HLINE_TO:
+         data_at(&coords, p, 0, 1, data);
+         x0 = data[0];
+         y0 = oy;
+         map_if_relative(ox, oy, relative, &x0, 0);
+         ox = x0;
+         px = x0;
+         py = y0;
+         matrix_map_point(matrix, x0, y0, &x0, &y0);
+         polygon_vertex_append(current, x0, y0);
+         break;
+      case VG_VLINE_TO:
+         data_at(&coords, p, 0, 1, data);
+         x0 = ox;
+         y0 = data[0];
+         map_if_relative(ox, oy, relative, 0, &y0);
+         oy = y0;
+         px = x0;
+         py = y0;
+         matrix_map_point(matrix, x0, y0, &x0, &y0);
+         polygon_vertex_append(current, x0, y0);
+         break;
+      case VG_CUBIC_TO: {
+         struct bezier bezier;
+         data_at(&coords, p, 0, 6, data);
+         x0 = ox;
+         y0 = oy;
+         x1 = data[0];
+         y1 = data[1];
+         x2 = data[2];
+         y2 = data[3];
+         x3 = data[4];
+         y3 = data[5];
+         map_if_relative(ox, oy, relative, &x1, &y1);
+         map_if_relative(ox, oy, relative, &x2, &y2);
+         map_if_relative(ox, oy, relative, &x3, &y3);
+         ox = x3;
+         oy = y3;
+         px = x2;
+         py = y2;
+         assert(matrix_is_affine(matrix));
+         matrix_map_point(matrix, x0, y0, &x0, &y0);
+         matrix_map_point(matrix, x1, y1, &x1, &y1);
+         matrix_map_point(matrix, x2, y2, &x2, &y2);
+         matrix_map_point(matrix, x3, y3, &x3, &y3);
+         bezier_init(&bezier, x0, y0, x1, y1,
+                       x2, y2, x3, y3);
+         bezier_add_to_polygon(&bezier, current);
+      }
+         break;
+      case VG_QUAD_TO: {
+         struct bezier bezier;
+         data_at(&coords, p, 0, 4, data);
+         x0 = ox;
+         y0 = oy;
+         x1 = data[0];
+         y1 = data[1];
+         x3 = data[2];
+         y3 = data[3];
+         map_if_relative(ox, oy, relative, &x1, &y1);
+         map_if_relative(ox, oy, relative, &x3, &y3);
+         px = x1;
+         py = y1;
+         { /* form a cubic out of it */
+            x2 = (x3 + 2*x1) / 3.f;
+            y2 = (y3 + 2*y1) / 3.f;
+            x1 = (x0 + 2*x1) / 3.f;
+            y1 = (y0 + 2*y1) / 3.f;
+         }
+         ox = x3;
+         oy = y3;
+         assert(matrix_is_affine(matrix));
+         matrix_map_point(matrix, x0, y0, &x0, &y0);
+         matrix_map_point(matrix, x1, y1, &x1, &y1);
+         matrix_map_point(matrix, x2, y2, &x2, &y2);
+         matrix_map_point(matrix, x3, y3, &x3, &y3);
+         bezier_init(&bezier, x0, y0, x1, y1,
+                       x2, y2, x3, y3);
+         bezier_add_to_polygon(&bezier, current);
+      }
+         break;
+      case VG_SQUAD_TO: {
+         struct bezier bezier;
+         data_at(&coords, p, 0, 2, data);
+         x0 = ox;
+         y0 = oy;
+         x1 = 2*ox-px;
+         y1 = 2*oy-py;
+         x3 = data[0];
+         y3 = data[1];
+         map_if_relative(ox, oy, relative, &x3, &y3);
+         px = x1;
+         py = y1;
+         { /* form a cubic out of it */
+            x2 = (x3 + 2*x1) / 3.f;
+            y2 = (y3 + 2*y1) / 3.f;
+            x1 = (x0 + 2*x1) / 3.f;
+            y1 = (y0 + 2*y1) / 3.f;
+         }
+         ox = x3;
+         oy = y3;
+         assert(matrix_is_affine(matrix));
+         matrix_map_point(matrix, x0, y0, &x0, &y0);
+         matrix_map_point(matrix, x1, y1, &x1, &y1);
+         matrix_map_point(matrix, x2, y2, &x2, &y2);
+         matrix_map_point(matrix, x3, y3, &x3, &y3);
+         bezier_init(&bezier, x0, y0, x1, y1,
+                     x2, y2, x3, y3);
+         bezier_add_to_polygon(&bezier, current);
+      }
+         break;
+      case VG_SCUBIC_TO: {
+         struct bezier bezier;
+         data_at(&coords, p, 0, 4, data);
+         x0 = ox;
+         y0 = oy;
+         x1 = 2*ox-px;
+         y1 = 2*oy-py;
+         x2 = data[0];
+         y2 = data[1];
+         x3 = data[2];
+         y3 = data[3];
+         map_if_relative(ox, oy, relative, &x2, &y2);
+         map_if_relative(ox, oy, relative, &x3, &y3);
+         ox = x3;
+         oy = y3;
+         px = x2;
+         py = y2;
+         assert(matrix_is_affine(matrix));
+         matrix_map_point(matrix, x0, y0, &x0, &y0);
+         matrix_map_point(matrix, x1, y1, &x1, &y1);
+         matrix_map_point(matrix, x2, y2, &x2, &y2);
+         matrix_map_point(matrix, x3, y3, &x3, &y3);
+         bezier_init(&bezier, x0, y0, x1, y1,
+                              x2, y2, x3, y3);
+         bezier_add_to_polygon(&bezier, current);
+      }
+         break;
+      case VG_SCCWARC_TO:
+      case VG_SCWARC_TO:
+      case VG_LCCWARC_TO:
+      case VG_LCWARC_TO: {
+         VGfloat rh, rv, rot;
+         struct arc arc;
+
+         data_at(&coords, p, 0, 5, data);
+         x0  = ox;
+         y0  = oy;
+         rh  = data[0];
+         rv  = data[1];
+         rot = data[2];
+         x1  = data[3];
+         y1  = data[4];
+         map_if_relative(ox, oy, relative, &x1, &y1);
+#if 0
+         debug_printf("------- ARC (%f, %f), (%f, %f) %f, %f, %f\n",
+                      x0, y0, x1, y1, rh, rv, rot);
+#endif
+         arc_init(&arc, command, x0, y0, x1, y1,
+                  rh, rv, rot);
+         arc_add_to_polygon(&arc, current,
+                            matrix);
+         ox = x1;
+         oy = y1;
+         px = x1;
+         py = y1;
+      }
+         break;
+      default:
+         abort();
+         assert(!"Unknown segment!");
+      }
+   }
+   if (current) {
+      if (polygon_vertex_count(current) > 0) {
+         close_polygon(current, sx, sy, ox, oy, matrix);
+         array_append_data(array, &current, 1);
+      } else
+         polygon_destroy(current);
+   }
+
+   p->fill_polys.polygon_array.array = array;
+   p->fill_polys.matrix = *matrix;
+
+   polygon_array_calculate_bounds( &p->fill_polys.polygon_array );
+
+   p->dirty = VG_FALSE;
+
+   return &p->fill_polys.polygon_array;
+}
+
+VGbyte path_datatype_size(struct path *p)
+{
+   return size_for_datatype(p->datatype);
+}
+
+VGPathDatatype path_datatype(struct path *p)
+{
+   return p->datatype;
+}
+
+VGfloat path_scale(struct path *p)
+{
+   return p->scale;
+}
+
+VGfloat path_bias(struct path *p)
+{
+   return p->bias;
+}
+
+VGint path_num_coords(struct path *p)
+{
+   return num_elements_for_segments((VGubyte*)p->segments->data,
+                                    p->num_segments);
+}
+
+void path_modify_coords(struct path *p,
+                        VGint startIndex,
+                        VGint numSegments,
+                        const void * pathData)
+{
+   VGubyte *segments = (VGubyte*)(p->segments->data);
+   VGint count = num_elements_for_segments(&segments[startIndex], numSegments);
+   VGint start_cp = num_elements_for_segments(segments, startIndex);
+
+   array_change_data(p->control_points, pathData, start_cp, count);
+   coords_adjust_by_scale_bias(p,
+                               ((VGubyte*)p->control_points->data) +
+                               (startIndex * p->control_points->datatype_size),
+                               path_num_coords(p),
+                               p->scale, p->bias, p->datatype);
+   p->dirty = VG_TRUE;
+   p->dirty_stroke = VG_TRUE;
+}
+
+void path_for_each_segment(struct path *path,
+                           path_for_each_cb cb,
+                           void *user_data)
+{
+   VGint i;
+   struct path_for_each_data p;
+   VGfloat data[8];
+   void *coords = (VGfloat *)path->control_points->data;
+
+   p.coords = data;
+   p.sx = p.sy = p.px = p.py = p.ox = p.oy = 0.f;
+   p.user_data = user_data;
+
+   for (i = 0; i < path->num_segments; ++i) {
+      VGint command;
+      VGboolean relative;
+
+      p.segment = ((VGubyte*)(path->segments->data))[i];
+      command = SEGMENT_COMMAND(p.segment);
+      relative = SEGMENT_ABS_REL(p.segment);
+
+      switch(command) {
+      case VG_CLOSE_PATH:
+         cb(path, &p);
+         break;
+      case VG_MOVE_TO:
+         data_at(&coords, path, 0, 2, data);
+         map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
+         cb(path, &p);
+         p.sx = data[0];
+         p.sy = data[1];
+         p.ox = data[0];
+         p.oy = data[1];
+         p.px = data[0];
+         p.py = data[1];
+         break;
+      case VG_LINE_TO:
+         data_at(&coords, path, 0, 2, data);
+         map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
+         cb(path, &p);
+         p.ox = data[0];
+         p.oy = data[1];
+         p.px = data[0];
+         p.py = data[1];
+         break;
+      case VG_HLINE_TO:
+         data_at(&coords, path, 0, 1, data);
+         map_if_relative(p.ox, p.oy, relative, &data[0], 0);
+         p.segment = VG_LINE_TO;
+         data[1] = p.oy;
+         cb(path, &p);
+         p.ox = data[0];
+         p.oy = data[1];
+         p.px = data[0];
+         p.py = data[1];
+         break;
+      case VG_VLINE_TO:
+         data_at(&coords, path, 0, 1, data);
+         map_if_relative(p.ox, p.oy, relative, 0, &data[0]);
+         p.segment = VG_LINE_TO;
+         data[1] = data[0];
+         data[0] = p.ox;
+         cb(path, &p);
+         p.ox = data[0];
+         p.oy = data[1];
+         p.px = data[0];
+         p.py = data[1];
+         break;
+      case VG_CUBIC_TO: {
+         data_at(&coords, path, 0, 6, data);
+         map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
+         map_if_relative(p.ox, p.oy, relative, &data[2], &data[3]);
+         map_if_relative(p.ox, p.oy, relative, &data[4], &data[5]);
+         cb(path, &p);
+         p.px = data[2];
+         p.py = data[3];
+         p.ox = data[4];
+         p.oy = data[5];
+      }
+         break;
+      case VG_QUAD_TO: {
+         data_at(&coords, path, 0, 4, data);
+         map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
+         map_if_relative(p.ox, p.oy, relative, &data[2], &data[3]);
+         cb(path, &p);
+         p.px = data[0];
+         p.py = data[1];
+         p.ox = data[2];
+         p.oy = data[3];
+      }
+         break;
+      case VG_SQUAD_TO: {
+         data_at(&coords, path, 0, 2, data);
+         map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
+         cb(path, &p);
+         p.px = 2*p.ox-p.px;
+         p.py = 2*p.oy-p.py;
+         p.ox = data[2];
+         p.oy = data[3];
+      }
+         break;
+      case VG_SCUBIC_TO: {
+         data_at(&coords, path, 0, 4, data);
+         map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
+         map_if_relative(p.ox, p.oy, relative, &data[2], &data[3]);
+         cb(path, &p);
+         p.px = data[0];
+         p.py = data[1];
+         p.ox = data[2];
+         p.oy = data[3];
+      }
+         break;
+      case VG_SCCWARC_TO:
+      case VG_SCWARC_TO:
+      case VG_LCCWARC_TO:
+      case VG_LCWARC_TO: {
+         data_at(&coords, path, 0, 5, data);
+         map_if_relative(p.ox, p.oy, relative, &data[3], &data[4]);
+#if 0
+         debug_printf("------- ARC (%f, %f), (%f, %f) %f, %f, %f\n",
+                      p.ox, p.oy, data[3], data[4], data[0], data[1], data[2]);
+#endif
+         cb(path, &p);
+         p.ox = data[3];
+         p.oy = data[4];
+         p.px = data[3];
+         p.py = data[4];
+      }
+         break;
+      default:
+         abort();
+         assert(!"Unknown segment!");
+      }
+   }
+}
+
+struct transform_data {
+   struct array *segments;
+   struct array *coords;
+
+   struct matrix *matrix;
+
+   VGPathDatatype datatype;
+};
+
+static VGboolean transform_cb(struct path *p,
+                              struct path_for_each_data *pd)
+{
+   struct transform_data *td = (struct transform_data *)pd->user_data;
+   VGint num_coords = num_elements_for_segments(&pd->segment, 1);
+   VGubyte segment = SEGMENT_COMMAND(pd->segment);/* abs bit is 0 */
+   VGfloat data[8];
+   VGubyte common_data[sizeof(VGfloat)*8];
+
+   memcpy(data, pd->coords, sizeof(VGfloat) * num_coords);
+
+   switch(segment) {
+   case VG_CLOSE_PATH:
+      break;
+   case VG_MOVE_TO:
+      matrix_map_point(td->matrix,
+                       data[0], data[1], &data[0], &data[1]);
+      break;
+   case VG_LINE_TO:
+      matrix_map_point(td->matrix,
+                       data[0], data[1], &data[0], &data[1]);
+      break;
+   case VG_HLINE_TO:
+   case VG_VLINE_TO:
+      assert(0);
+      break;
+   case VG_QUAD_TO:
+      matrix_map_point(td->matrix,
+                       data[0], data[1], &data[0], &data[1]);
+      matrix_map_point(td->matrix,
+                       data[2], data[3], &data[2], &data[3]);
+      break;
+   case VG_CUBIC_TO:
+      matrix_map_point(td->matrix,
+                       data[0], data[1], &data[0], &data[1]);
+      matrix_map_point(td->matrix,
+                       data[2], data[3], &data[2], &data[3]);
+      matrix_map_point(td->matrix,
+                       data[4], data[5], &data[4], &data[5]);
+      break;
+   case VG_SQUAD_TO:
+      matrix_map_point(td->matrix,
+                       data[0], data[1], &data[0], &data[1]);
+      break;
+   case VG_SCUBIC_TO:
+      matrix_map_point(td->matrix,
+                       data[0], data[1], &data[0], &data[1]);
+      matrix_map_point(td->matrix,
+                       data[2], data[3], &data[2], &data[3]);
+      break;
+   case VG_SCCWARC_TO:
+   case VG_SCWARC_TO:
+   case VG_LCCWARC_TO:
+   case VG_LCWARC_TO: {
+      struct arc arc;
+      struct path *path = path_create(td->datatype,
+                                      1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
+      arc_init(&arc, segment,
+               pd->ox, pd->oy, data[3], data[4],
+               data[0], data[1], data[2]);
+
+      arc_to_path(&arc, path, td->matrix);
+
+      num_coords = path_num_coords(path);
+
+      array_append_data(td->segments, path->segments->data,
+                        path->num_segments);
+      array_append_data(td->coords, path->control_points->data,
+                        num_coords);
+      path_destroy(path);
+
+      return VG_TRUE;
+   }
+      break;
+   default:
+      break;
+   }
+
+   vg_float_to_datatype(td->datatype, common_data, data, num_coords);
+
+   array_append_data(td->segments, &segment, 1);
+   array_append_data(td->coords, common_data, num_coords);
+   return VG_TRUE;
+}
+
+void path_transform(struct path *dst, struct path *src)
+{
+   struct transform_data data;
+   struct vg_context *ctx = dst->base.ctx;
+
+   data.segments =  dst->segments;
+   data.coords   =  dst->control_points;
+   data.matrix   = &ctx->state.vg.path_user_to_surface_matrix;
+   data.datatype = dst->datatype;
+
+   path_for_each_segment(src, transform_cb, (void*)&data);
+
+   dst->num_segments = dst->segments->num_elements;
+   dst->dirty = VG_TRUE;
+   dst->dirty_stroke = VG_TRUE;
+}
+
+void path_append_path(struct path *dst,
+                      struct path *src)
+{
+   VGint num_coords = path_num_coords(src);
+   void *dst_data = malloc(size_for_datatype(dst->datatype) * num_coords);
+   array_append_data(dst->segments,
+                     src->segments->data,
+                     src->num_segments);
+   convert_path(src, dst->datatype,
+                dst_data, num_coords);
+   array_append_data(dst->control_points,
+                     dst_data,
+                     num_coords);
+   free(dst_data);
+
+   dst->num_segments += src->num_segments;
+   dst->dirty = VG_TRUE;
+   dst->dirty_stroke = VG_TRUE;
+}
+
+static INLINE VGboolean is_segment_arc(VGubyte segment)
+{
+   VGubyte scommand = SEGMENT_COMMAND(segment);
+   return (scommand == VG_SCCWARC_TO ||
+           scommand == VG_SCWARC_TO ||
+           scommand == VG_LCCWARC_TO ||
+           scommand == VG_LCWARC_TO);
+}
+
+struct path_iter_data {
+   struct path *path;
+   VGubyte segment;
+   void *coords;
+   VGfloat px, py, ox, oy, sx, sy;
+};
+static INLINE VGubyte normalize_coords(struct path_iter_data *pd,
+                                       VGint *num_coords,
+                                       VGfloat *data)
+{
+   VGint command = SEGMENT_COMMAND(pd->segment);
+   VGboolean relative = SEGMENT_ABS_REL(pd->segment);
+
+   switch(command) {
+   case VG_CLOSE_PATH:
+      *num_coords = 0;
+      pd->ox = pd->sx;
+      pd->oy = pd->sy;
+      return VG_CLOSE_PATH;
+      break;
+   case VG_MOVE_TO:
+      data_at(&pd->coords, pd->path, 0, 2, data);
+      map_if_relative(pd->ox, pd->oy, relative, &data[0], &data[1]);
+      pd->sx = data[0];
+      pd->sy = data[1];
+      pd->ox = data[0];
+      pd->oy = data[1];
+      pd->px = data[0];
+      pd->py = data[1];
+      *num_coords = 2;
+      return VG_MOVE_TO_ABS;
+      break;
+   case VG_LINE_TO:
+      data_at(&pd->coords, pd->path, 0, 2, data);
+      map_if_relative(pd->ox, pd->oy, relative, &data[0], &data[1]);
+      pd->ox = data[0];
+      pd->oy = data[1];
+      pd->px = data[0];
+      pd->py = data[1];
+      *num_coords = 2;
+      return VG_LINE_TO_ABS;
+      break;
+   case VG_HLINE_TO:
+      data_at(&pd->coords, pd->path, 0, 1, data);
+      map_if_relative(pd->ox, pd->oy, relative, &data[0], 0);
+      data[1] = pd->oy;
+      pd->ox = data[0];
+      pd->oy = data[1];
+      pd->px = data[0];
+      pd->py = data[1];
+      *num_coords = 2;
+      return VG_LINE_TO_ABS;
+      break;
+   case VG_VLINE_TO:
+      data_at(&pd->coords, pd->path, 0, 1, data);
+      map_if_relative(pd->ox, pd->oy, relative, 0, &data[0]);
+      data[1] = data[0];
+      data[0] = pd->ox;
+      pd->ox = data[0];
+      pd->oy = data[1];
+      pd->px = data[0];
+      pd->py = data[1];
+      *num_coords = 2;
+      return VG_LINE_TO_ABS;
+      break;
+   case VG_CUBIC_TO: {
+      data_at(&pd->coords, pd->path, 0, 6, data);
+      map_if_relative(pd->ox, pd->oy, relative, &data[0], &data[1]);
+      map_if_relative(pd->ox, pd->oy, relative, &data[2], &data[3]);
+      map_if_relative(pd->ox, pd->oy, relative, &data[4], &data[5]);
+      pd->px = data[2];
+      pd->py = data[3];
+      pd->ox = data[4];
+      pd->oy = data[5];
+      *num_coords = 6;
+      return VG_CUBIC_TO_ABS;
+   }
+      break;
+   case VG_QUAD_TO: {
+      VGfloat x0, y0, x1, y1, x2, y2, x3, y3;
+      data_at(&pd->coords, pd->path, 0, 4, data);
+      x0 = pd->ox;
+      y0 = pd->oy;
+      x1 = data[0];
+      y1 = data[1];
+      x3 = data[2];
+      y3 = data[3];
+      map_if_relative(pd->ox, pd->oy, relative, &x1, &y1);
+      map_if_relative(pd->ox, pd->oy, relative, &x3, &y3);
+      pd->px = x1;
+      pd->py = y1;
+      { /* form a cubic out of it */
+         x2 = (x3 + 2*x1) / 3.f;
+         y2 = (y3 + 2*y1) / 3.f;
+         x1 = (x0 + 2*x1) / 3.f;
+         y1 = (y0 + 2*y1) / 3.f;
+      }
+      pd->ox = x3;
+      pd->oy = y3;
+      data[0] = x1;
+      data[1] = y1;
+      data[2] = x2;
+      data[3] = y2;
+      data[4] = x3;
+      data[5] = y3;
+      *num_coords = 6;
+      return VG_CUBIC_TO_ABS;
+   }
+      break;
+   case VG_SQUAD_TO: {
+      VGfloat x0, y0, x1, y1, x2, y2, x3, y3;
+      data_at(&pd->coords, pd->path, 0, 2, data);
+      x0 = pd->ox;
+      y0 = pd->oy;
+      x1 = 2 * pd->ox - pd->px;
+      y1 = 2 * pd->oy - pd->py;
+      x3 = data[0];
+      y3 = data[1];
+      map_if_relative(pd->ox, pd->oy, relative, &x3, &y3);
+      pd->px = x1;
+      pd->py = y1;
+      { /* form a cubic out of it */
+         x2 = (x3 + 2*x1) / 3.f;
+         y2 = (y3 + 2*y1) / 3.f;
+         x1 = (x0 + 2*x1) / 3.f;
+         y1 = (y0 + 2*y1) / 3.f;
+      }
+      pd->ox = x3;
+      pd->oy = y3;
+      data[0] = x1;
+      data[1] = y1;
+      data[2] = x2;
+      data[3] = y2;
+      data[4] = x3;
+      data[5] = y3;
+      *num_coords = 6;
+      return VG_CUBIC_TO_ABS;
+   }
+      break;
+   case VG_SCUBIC_TO: {
+      VGfloat x0, y0, x1, y1, x2, y2, x3, y3;
+      data_at(&pd->coords, pd->path, 0, 4, data);
+      x0 = pd->ox;
+      y0 = pd->oy;
+      x1 = 2*pd->ox-pd->px;
+      y1 = 2*pd->oy-pd->py;
+      x2 = data[0];
+      y2 = data[1];
+      x3 = data[2];
+      y3 = data[3];
+      map_if_relative(pd->ox, pd->oy, relative, &x2, &y2);
+      map_if_relative(pd->ox, pd->oy, relative, &x3, &y3);
+      pd->ox = x3;
+      pd->oy = y3;
+      pd->px = x2;
+      pd->py = y2;
+      data[0] = x1;
+      data[1] = y1;
+      data[2] = x2;
+      data[3] = y2;
+      data[4] = x3;
+      data[5] = y3;
+      *num_coords = 6;
+      return VG_CUBIC_TO_ABS;
+   }
+      break;
+   case VG_SCCWARC_TO:
+   case VG_SCWARC_TO:
+   case VG_LCCWARC_TO:
+   case VG_LCWARC_TO: {
+      data_at(&pd->coords, pd->path, 0, 5, data);
+      map_if_relative(pd->ox, pd->oy, relative, &data[3], &data[4]);
+      pd->ox = data[3];
+      pd->oy = data[4];
+      pd->px = data[3];
+      pd->py = data[4];
+      *num_coords = 5;
+      return command | VG_ABSOLUTE;
+   }
+      break;
+   default:
+      abort();
+      assert(!"Unknown segment!");
+   }
+}
+
+static void linearly_interpolate(VGfloat *result,
+                                 const VGfloat *start,
+                                 const VGfloat *end,
+                                 VGfloat amount,
+                                 VGint number)
+{
+   VGint i;
+   for (i = 0; i < number; ++i) {
+      result[i] = start[i] + (end[i] - start[i]) * amount;
+   }
+}
+
+VGboolean path_interpolate(struct path *dst,
+                           struct path *start, struct path *end,
+                           VGfloat amount)
+{
+   /* temporary path that we can discard if it will turn
+    * out that start is not compatible with end */
+   struct path *res_path = path_create(dst->datatype,
+                                       1.0, 0.0,
+                                       0, 0, dst->caps);
+   VGint i;
+   VGfloat start_coords[8];
+   VGfloat end_coords[8];
+   VGfloat results[8];
+   VGubyte common_data[sizeof(VGfloat)*8];
+   struct path_iter_data start_iter, end_iter;
+
+   memset(&start_iter, 0, sizeof(struct path_iter_data));
+   memset(&end_iter, 0, sizeof(struct path_iter_data));
+
+   start_iter.path = start;
+   start_iter.coords = start->control_points->data;
+   end_iter.path = end;
+   end_iter.coords = end->control_points->data;
+
+   for (i = 0; i < start->num_segments; ++i) {
+      VGubyte segment;
+      VGubyte ssegment, esegment;
+      VGint snum_coords, enum_coords;
+      start_iter.segment = ((VGubyte*)(start->segments->data))[i];
+      end_iter.segment = ((VGubyte*)(end->segments->data))[i];
+
+      ssegment = normalize_coords(&start_iter, &snum_coords,
+                                  start_coords);
+      esegment = normalize_coords(&end_iter, &enum_coords,
+                                  end_coords);
+
+      if (is_segment_arc(ssegment)) {
+         if (!is_segment_arc(esegment)) {
+            path_destroy(res_path);
+            return VG_FALSE;
+         }
+         if (amount > 0.5)
+            segment = esegment;
+         else
+            segment = ssegment;
+      } else if (is_segment_arc(esegment)) {
+         path_destroy(res_path);
+         return VG_FALSE;
+      }
+      else if (ssegment != esegment) {
+         path_destroy(res_path);
+         return VG_FALSE;
+      }
+      else
+         segment = ssegment;
+
+      linearly_interpolate(results, start_coords, end_coords,
+                           amount, snum_coords);
+      vg_float_to_datatype(dst->datatype, common_data, results, snum_coords);
+      path_append_data(res_path, 1, &segment, common_data);
+   }
+
+   path_append_path(dst, res_path);
+   path_destroy(res_path);
+
+   dst->dirty = VG_TRUE;
+   dst->dirty_stroke = VG_TRUE;
+
+   return VG_TRUE;
+}
+
+void path_clear(struct path *p, VGbitfield capabilities)
+{
+   path_set_capabilities(p, capabilities);
+   array_destroy(p->segments);
+   array_destroy(p->control_points);
+   p->segments = array_create(size_for_datatype(VG_PATH_DATATYPE_S_8));
+   p->control_points = array_create(size_for_datatype(p->datatype));
+   p->num_segments = 0;
+   p->dirty = VG_TRUE;
+   p->dirty_stroke = VG_TRUE;
+}
+
+struct path * path_create_stroke(struct path *p,
+                                 struct matrix *matrix)
+{
+   VGint i;
+   VGfloat sx, sy, px, py, ox, oy;
+   VGfloat x0, y0, x1, y1, x2, y2, x3, y3;
+   VGfloat data[8];
+   void *coords = (VGfloat *)p->control_points->data;
+   int dashed = (p->base.ctx->state.vg.stroke.dash_pattern_num ? 1 : 0);
+   struct dash_stroker stroker;
+   struct vg_state *vg_state = &p->base.ctx->state.vg;
+
+   if (p->stroked.path)
+   {
+      /* ### compare the dash patterns to see if we can cache them.
+       *     for now we simply always bail out if the path is dashed.
+       */
+      if (memcmp( &p->stroked.matrix,
+                  matrix,
+                  sizeof *matrix ) == 0 &&
+          !dashed && !p->dirty_stroke &&
+          floatsEqual(p->stroked.stroke_width, vg_state->stroke.line_width.f) &&
+          floatsEqual(p->stroked.miter_limit, vg_state->stroke.miter_limit.f) &&
+          p->stroked.cap_style == vg_state->stroke.cap_style &&
+          p->stroked.join_style == vg_state->stroke.join_style)
+      {
+         return p->stroked.path;
+      }
+      else {
+         path_destroy( p->stroked.path );
+         p->stroked.path = NULL;
+      }
+   }
+
+
+   sx = sy = px = py = ox = oy = 0.f;
+
+   if (dashed)
+      dash_stroker_init((struct stroker *)&stroker, vg_state);
+   else
+      stroker_init((struct stroker *)&stroker, vg_state);
+
+   stroker_begin((struct stroker *)&stroker);
+
+   for (i = 0; i < p->num_segments; ++i) {
+      VGubyte segment = ((VGubyte*)(p->segments->data))[i];
+      VGint command = SEGMENT_COMMAND(segment);
+      VGboolean relative = SEGMENT_ABS_REL(segment);
+
+      switch(command) {
+      case VG_CLOSE_PATH: {
+            VGfloat x0 = sx;
+            VGfloat y0 = sy;
+            matrix_map_point(matrix, x0, y0, &x0, &y0);
+            stroker_line_to((struct stroker *)&stroker, x0, y0);
+      }
+         break;
+      case VG_MOVE_TO:
+         data_at(&coords, p, 0, 2, data);
+         x0 = data[0];
+         y0 = data[1];
+         map_if_relative(ox, oy, relative, &x0, &y0);
+         sx = x0;
+         sy = y0;
+         ox = x0;
+         oy = y0;
+         px = x0;
+         py = y0;
+         matrix_map_point(matrix, x0, y0, &x0, &y0);
+         stroker_move_to((struct stroker *)&stroker, x0, y0);
+         break;
+      case VG_LINE_TO:
+         data_at(&coords, p, 0, 2, data);
+         x0 = data[0];
+         y0 = data[1];
+         map_if_relative(ox, oy, relative, &x0, &y0);
+         ox = x0;
+         oy = y0;
+         px = x0;
+         py = y0;
+         matrix_map_point(matrix, x0, y0, &x0, &y0);
+         stroker_line_to((struct stroker *)&stroker, x0, y0);
+         break;
+      case VG_HLINE_TO:
+         data_at(&coords, p, 0, 1, data);
+         x0 = data[0];
+         y0 = oy;
+         map_if_relative(ox, oy, relative, &x0, 0);
+         ox = x0;
+         px = x0;
+         py = y0;
+         matrix_map_point(matrix, x0, y0, &x0, &y0);
+         stroker_line_to((struct stroker *)&stroker, x0, y0);
+         break;
+      case VG_VLINE_TO:
+         data_at(&coords, p, 0, 1, data);
+         x0 = ox;
+         y0 = data[0];
+         map_if_relative(ox, oy, relative, 0, &y0);
+         oy = y0;
+         px = x0;
+         py = y0;
+         matrix_map_point(matrix, x0, y0, &x0, &y0);
+         stroker_line_to((struct stroker *)&stroker, x0, y0);
+         break;
+      case VG_CUBIC_TO: {
+         data_at(&coords, p, 0, 6, data);
+         x0 = ox;
+         y0 = oy;
+         x1 = data[0];
+         y1 = data[1];
+         x2 = data[2];
+         y2 = data[3];
+         x3 = data[4];
+         y3 = data[5];
+         map_if_relative(ox, oy, relative, &x1, &y1);
+         map_if_relative(ox, oy, relative, &x2, &y2);
+         map_if_relative(ox, oy, relative, &x3, &y3);
+         if (floatsEqual(x1, ox) && floatsEqual(y1, oy) &&
+             floatsEqual(x1, x2) && floatsEqual(y1, y2) &&
+             floatsEqual(x2, x3) && floatsEqual(y2, y3)) {
+            /*ignore the empty segment */
+            continue;
+         } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) {
+            /* if dup vertex, emit a line */
+            ox = x3;
+            oy = y3;
+            matrix_map_point(matrix, x3, y3, &x3, &y3);
+            stroker_line_to((struct stroker *)&stroker, x3, y3);
+            continue;
+         }
+         ox = x3;
+         oy = y3;
+         px = x2;
+         py = y2;
+         assert(matrix_is_affine(matrix));
+         matrix_map_point(matrix, x0, y0, &x0, &y0);
+         matrix_map_point(matrix, x1, y1, &x1, &y1);
+         matrix_map_point(matrix, x2, y2, &x2, &y2);
+         matrix_map_point(matrix, x3, y3, &x3, &y3);
+         stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3);
+      }
+         break;
+      case VG_QUAD_TO: {
+         data_at(&coords, p, 0, 4, data);
+         x0 = ox;
+         y0 = oy;
+         x1 = data[0];
+         y1 = data[1];
+         x3 = data[2];
+         y3 = data[3];
+         map_if_relative(ox, oy, relative, &x1, &y1);
+         map_if_relative(ox, oy, relative, &x3, &y3);
+         px = x1;
+         py = y1;
+         { /* form a cubic out of it */
+            x2 = (x3 + 2*x1) / 3.f;
+            y2 = (y3 + 2*y1) / 3.f;
+            x1 = (x0 + 2*x1) / 3.f;
+            y1 = (y0 + 2*y1) / 3.f;
+         }
+         if (floatsEqual(x1, ox) && floatsEqual(y1, oy) &&
+             floatsEqual(x1, x2) && floatsEqual(y1, y2) &&
+             floatsEqual(x2, x3) && floatsEqual(y2, y3)) {
+            /*ignore the empty segment */
+            continue;
+         } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) {
+            /* if dup vertex, emit a line */
+            ox = x3;
+            oy = y3;
+            matrix_map_point(matrix, x3, y3, &x3, &y3);
+            stroker_line_to((struct stroker *)&stroker, x3, y3);
+            continue;
+         }
+         ox = x3;
+         oy = y3;
+         assert(matrix_is_affine(matrix));
+         matrix_map_point(matrix, x0, y0, &x0, &y0);
+         matrix_map_point(matrix, x1, y1, &x1, &y1);
+         matrix_map_point(matrix, x2, y2, &x2, &y2);
+         matrix_map_point(matrix, x3, y3, &x3, &y3);
+         stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3);
+      }
+         break;
+      case VG_SQUAD_TO: {
+         data_at(&coords, p, 0, 2, data);
+         x0 = ox;
+         y0 = oy;
+         x1 = 2*ox-px;
+         y1 = 2*oy-py;
+         x3 = data[0];
+         y3 = data[1];
+         map_if_relative(ox, oy, relative, &x3, &y3);
+         px = x1;
+         py = y1;
+         { /* form a cubic out of it */
+            x2 = (x3 + 2*x1) / 3.f;
+            y2 = (y3 + 2*y1) / 3.f;
+            x1 = (x0 + 2*x1) / 3.f;
+            y1 = (y0 + 2*y1) / 3.f;
+         }
+         if (floatsEqual(x1, ox) && floatsEqual(y1, oy) &&
+             floatsEqual(x1, x2) && floatsEqual(y1, y2) &&
+             floatsEqual(x2, x3) && floatsEqual(y2, y3)) {
+            /*ignore the empty segment */
+            continue;
+         } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) {
+            /* if dup vertex, emit a line */
+            ox = x3;
+            oy = y3;
+            matrix_map_point(matrix, x3, y3, &x3, &y3);
+            stroker_line_to((struct stroker *)&stroker, x3, y3);
+            continue;
+         }
+         ox = x3;
+         oy = y3;
+         assert(matrix_is_affine(matrix));
+         matrix_map_point(matrix, x0, y0, &x0, &y0);
+         matrix_map_point(matrix, x1, y1, &x1, &y1);
+         matrix_map_point(matrix, x2, y2, &x2, &y2);
+         matrix_map_point(matrix, x3, y3, &x3, &y3);
+         stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3);
+      }
+         break;
+      case VG_SCUBIC_TO: {
+         data_at(&coords, p, 0, 4, data);
+         x0 = ox;
+         y0 = oy;
+         x1 = 2*ox-px;
+         y1 = 2*oy-py;
+         x2 = data[0];
+         y2 = data[1];
+         x3 = data[2];
+         y3 = data[3];
+         map_if_relative(ox, oy, relative, &x2, &y2);
+         map_if_relative(ox, oy, relative, &x3, &y3);
+         if (floatsEqual(x1, ox) && floatsEqual(y1, oy) &&
+             floatsEqual(x1, x2) && floatsEqual(y1, y2) &&
+             floatsEqual(x2, x3) && floatsEqual(y2, y3)) {
+            /*ignore the empty segment */
+            continue;
+         } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) {
+            /* if dup vertex, emit a line */
+            ox = x3;
+            oy = y3;
+            matrix_map_point(matrix, x3, y3, &x3, &y3);
+            stroker_line_to((struct stroker *)&stroker, x3, y3);
+            continue;
+         }
+         ox = x3;
+         oy = y3;
+         px = x2;
+         py = y2;
+         assert(matrix_is_affine(matrix));
+         matrix_map_point(matrix, x0, y0, &x0, &y0);
+         matrix_map_point(matrix, x1, y1, &x1, &y1);
+         matrix_map_point(matrix, x2, y2, &x2, &y2);
+         matrix_map_point(matrix, x3, y3, &x3, &y3);
+         stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3);
+      }
+         break;
+      case VG_SCCWARC_TO:
+      case VG_SCWARC_TO:
+      case VG_LCCWARC_TO:
+      case VG_LCWARC_TO: {
+         VGfloat rh, rv, rot;
+         struct arc arc;
+
+         data_at(&coords, p, 0, 5, data);
+         x0  = ox;
+         y0  = oy;
+         rh  = data[0];
+         rv  = data[1];
+         rot = data[2];
+         x1  = data[3];
+         y1  = data[4];
+         map_if_relative(ox, oy, relative, &x1, &y1);
+         if (floatsEqual(x1, ox) && floatsEqual(y1, oy)) {
+            /* if dup vertex, emit a line */
+            ox = x1;
+            oy = y1;
+            matrix_map_point(matrix, x1, y1, &x1, &y1);
+            stroker_line_to((struct stroker *)&stroker, x1, y1);
+            continue;
+         }
+         arc_init(&arc, command, x0, y0, x1, y1,
+                  rh, rv, rot);
+         arc_stroke_cb(&arc, (struct stroker *)&stroker,
+                       matrix);
+         ox = x1;
+         oy = y1;
+         px = x1;
+         py = y1;
+      }
+         break;
+      default:
+         abort();
+         assert(!"Unknown segment!");
+      }
+   }
+
+   stroker_end((struct stroker *)&stroker);
+
+   if (dashed)
+      dash_stroker_cleanup((struct dash_stroker *)&stroker);
+   else
+      stroker_cleanup((struct stroker *)&stroker);
+
+   p->stroked.path = stroker.base.path;
+   p->stroked.matrix = *matrix;
+   p->dirty_stroke = VG_FALSE;
+   p->stroked.stroke_width = vg_state->stroke.line_width.f;
+   p->stroked.miter_limit = vg_state->stroke.miter_limit.f;
+   p->stroked.cap_style = vg_state->stroke.cap_style;
+   p->stroked.join_style = vg_state->stroke.join_style;
+
+   return stroker.base.path;
+}
+
+void path_render(struct path *p, VGbitfield paintModes)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct matrix *mat = &ctx->state.vg.path_user_to_surface_matrix;
+
+   vg_validate_state(ctx);
+
+   shader_set_drawing_image(ctx->shader, VG_FALSE);
+   shader_set_image(ctx->shader, 0);
+#if 0
+   fprintf(stderr, "Matrix(11=%f 12=%f 13=%f 21=%f 22=%f 23=%f 31=%f 32=%f 33=%f)\n",
+           mat->m[0], mat->m[1], mat->m[2],
+           mat->m[3], mat->m[4], mat->m[5],
+           mat->m[6], mat->m[7], mat->m[8]);
+#endif
+   if (paintModes & VG_FILL_PATH) {
+      /* First the fill */
+      shader_set_paint(ctx->shader, ctx->state.vg.fill_paint);
+      shader_bind(ctx->shader);
+      path_fill(p, mat);
+   }
+
+   if (paintModes & VG_STROKE_PATH){
+      /* 8.7.5: "line width less than or equal to 0 prevents stroking from
+       *  taking place."*/
+      if (ctx->state.vg.stroke.line_width.f <= 0)
+         return;
+      shader_set_paint(ctx->shader, ctx->state.vg.stroke_paint);
+      shader_bind(ctx->shader);
+      path_stroke(p);
+   }
+}
+
+void path_fill(struct path *p, struct matrix *mat)
+{
+   struct vg_context *ctx = vg_current_context();
+   {
+      struct polygon_array *polygon_array = path_get_fill_polygons(p, mat);
+      struct array *polys = polygon_array->array;
+
+      if (!polygon_array || !polys || !polys->num_elements) {
+         return;
+      }
+      polygon_array_fill(polygon_array, ctx);
+   }
+}
+
+void path_stroke(struct path *p)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct matrix *mat = &ctx->state.vg.path_user_to_surface_matrix;
+   VGFillRule old_fill = ctx->state.vg.fill_rule;
+   struct matrix identity;
+   struct path *stroke;
+
+   matrix_load_identity(&identity);
+   stroke = path_create_stroke(p, &identity);
+   if (stroke && !path_is_empty(stroke)) {
+      ctx->state.vg.fill_rule = VG_NON_ZERO;
+
+      path_fill(stroke, mat);
+
+      ctx->state.vg.fill_rule = old_fill;
+   }
+}
+
+void path_move_to(struct path *p, float x, float y)
+{
+   VGubyte segment = VG_MOVE_TO_ABS;
+   VGubyte common_data[sizeof(VGfloat) * 2];
+   VGfloat data[2] = {x, y};
+
+   vg_float_to_datatype(p->datatype, common_data, data, 2);
+   path_append_data(p, 1, &segment, common_data);
+}
+
+void path_line_to(struct path *p, float x, float y)
+{
+   VGubyte segment = VG_LINE_TO_ABS;
+   VGubyte common_data[sizeof(VGfloat) * 2];
+   VGfloat data[2] = {x, y};
+
+   vg_float_to_datatype(p->datatype, common_data, data, 2);
+
+   path_append_data(p, 1, &segment, common_data);
+}
+
+void path_cubic_to(struct path *p, float px1, float py1,
+                   float px2, float py2,
+                   float x, float y)
+{
+   VGubyte segment = VG_CUBIC_TO_ABS;
+   VGubyte common_data[sizeof(VGfloat) * 6];
+   VGfloat data[6];
+
+   data[0] = px1; data[1] = py1;
+   data[2] = px2; data[3] = py2;
+   data[4] = x;   data[5] = y;
+
+   vg_float_to_datatype(p->datatype, common_data, data, 6);
+
+   path_append_data(p, 1, &segment, common_data);
+}
+
+static INLINE void line_bounds(VGfloat *line /*x1,y1,x2,y2*/,
+                               VGfloat *bounds)
+{
+   bounds[0] = MIN2(line[0], line[2]);
+   bounds[1] = MIN2(line[1], line[3]);
+   bounds[2] = MAX2(line[0], line[2]) - bounds[0];
+   bounds[3] = MAX2(line[1], line[3]) - bounds[1];
+}
+
+static INLINE void unite_bounds(VGfloat *bounds,
+                                VGfloat *el)
+{
+   VGfloat cx1, cy1, cx2, cy2;
+   VGfloat nx1, ny1, nx2, ny2;
+
+   cx1 = bounds[0];
+   cy1 = bounds[1];
+   cx2 = bounds[0] + bounds[2];
+   cy2 = bounds[1] + bounds[3];
+
+   nx1 = el[0];
+   ny1 = el[1];
+   nx2 = el[0] + el[2];
+   ny2 = el[1] + el[3];
+
+   bounds[0] = MIN2(cx1, nx1);
+   bounds[1] = MIN2(cy1, ny1);
+   bounds[2] = MAX2(cx2, nx2) - bounds[0];
+   bounds[3] = MAX2(cy2, ny2) - bounds[1];
+}
+
+static INLINE void set_bounds(VGfloat *bounds,
+                              VGfloat *element_bounds,
+                              VGboolean *initialized)
+{
+   if (!(*initialized)) {
+      memcpy(bounds, element_bounds, 4 * sizeof(VGfloat));
+      *initialized = VG_TRUE;
+   } else
+      unite_bounds(bounds, element_bounds);
+}
+
+void path_bounding_rect(struct path *p, float *x, float *y,
+                        float *w, float *h)
+{
+   VGint i;
+   VGfloat coords[8];
+   struct path_iter_data iter;
+   VGint num_coords;
+   VGfloat bounds[4];
+   VGfloat element_bounds[4];
+   VGfloat ox, oy;
+   VGboolean bounds_inited = VG_FALSE;
+
+   memset(&iter, 0, sizeof(struct path_iter_data));
+   memset(&bounds, 0, sizeof(bounds));
+
+   if (!p->num_segments) {
+      bounds[2] = -1;
+      bounds[3] = -1;
+   }
+
+
+   iter.path = p;
+   iter.coords = p->control_points->data;
+
+   for (i = 0; i < p->num_segments; ++i) {
+      VGubyte segment;
+      iter.segment = ((VGubyte*)(p->segments->data))[i];
+
+      ox = iter.ox;
+      oy = iter.oy;
+
+      segment = normalize_coords(&iter, &num_coords, coords);
+
+      switch(segment) {
+      case VG_CLOSE_PATH:
+      case VG_MOVE_TO_ABS:
+         break;
+      case VG_LINE_TO_ABS: {
+         VGfloat line[4] = {ox, oy, coords[0], coords[1]};
+         line_bounds(line, element_bounds);
+         set_bounds(bounds, element_bounds, &bounds_inited);
+      }
+         break;
+      case VG_CUBIC_TO_ABS: {
+         struct bezier bezier;
+         bezier_init(&bezier, ox, oy,
+                     coords[0], coords[1],
+                     coords[2], coords[3],
+                     coords[4], coords[5]);
+         bezier_exact_bounds(&bezier, element_bounds);
+         set_bounds(bounds, element_bounds, &bounds_inited);
+      }
+         break;
+      case VG_SCCWARC_TO:
+      case VG_SCWARC_TO:
+      case VG_LCCWARC_TO:
+      case VG_LCWARC_TO: {
+         struct arc arc;
+         struct matrix identity;
+         struct path *path = path_create(VG_PATH_DATATYPE_F,
+                                         1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
+
+         matrix_load_identity(&identity);
+         arc_init(&arc, segment,
+                  ox, oy, coords[3], coords[4],
+                  coords[0], coords[1], coords[2]);
+
+         arc_to_path(&arc, path, &identity);
+
+         path_bounding_rect(path, element_bounds + 0, element_bounds + 1,
+                            element_bounds + 2, element_bounds + 3);
+         set_bounds(bounds, element_bounds, &bounds_inited);
+      }
+         break;
+      default:
+         assert(0);
+      }
+   }
+
+   *x = bounds[0];
+   *y = bounds[1];
+   *w = bounds[2];
+   *h = bounds[3];
+}
+
+float path_length(struct path *p, int start_segment, int num_segments)
+{
+   VGint i;
+   VGfloat coords[8];
+   struct path_iter_data iter;
+   VGint num_coords;
+   VGfloat length = 0;
+   VGfloat ox, oy;
+   VGboolean in_range = VG_FALSE;
+
+   memset(&iter, 0, sizeof(struct path_iter_data));
+
+   iter.path = p;
+   iter.coords = p->control_points->data;
+
+   for (i = 0; i < (start_segment + num_segments); ++i) {
+      VGubyte segment;
+
+      iter.segment = ((VGubyte*)(p->segments->data))[i];
+
+      ox = iter.ox;
+      oy = iter.oy;
+
+      segment = normalize_coords(&iter, &num_coords, coords);
+
+      in_range = (i >= start_segment) && i <= (start_segment + num_segments);
+      if (!in_range)
+         continue;
+
+      switch(segment) {
+      case VG_MOVE_TO_ABS:
+         break;
+      case VG_CLOSE_PATH: {
+         VGfloat line[4] = {ox, oy, iter.sx, iter.sy};
+         length += line_lengthv(line);
+      }
+         break;
+      case VG_LINE_TO_ABS: {
+         VGfloat line[4] = {ox, oy, coords[0], coords[1]};
+         length += line_lengthv(line);
+      }
+         break;
+      case VG_CUBIC_TO_ABS: {
+         struct bezier bezier;
+         bezier_init(&bezier, ox, oy,
+                     coords[0], coords[1],
+                     coords[2], coords[3],
+                     coords[4], coords[5]);
+         length += bezier_length(&bezier, BEZIER_DEFAULT_ERROR);
+      }
+         break;
+      case VG_SCCWARC_TO:
+      case VG_SCWARC_TO:
+      case VG_LCCWARC_TO:
+      case VG_LCWARC_TO: {
+         struct arc arc;
+         struct matrix identity;
+         struct path *path = path_create(VG_PATH_DATATYPE_F,
+                                         1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
+
+         matrix_load_identity(&identity);
+         arc_init(&arc, segment,
+                  ox, oy, coords[3], coords[4],
+                  coords[0], coords[1], coords[2]);
+
+         arc_to_path(&arc, path, &identity);
+
+         length += path_length(path, 0, path_num_segments(path));
+      }
+         break;
+      default:
+         assert(0);
+      }
+   }
+
+   return length;
+}
+
+static INLINE VGboolean point_on_current_segment(VGfloat distance,
+                                                 VGfloat length,
+                                                 VGfloat segment_length)
+{
+   return
+      (((floatIsZero(distance) || distance < 0) && floatIsZero(length)) ||
+       ((distance > length || floatsEqual(distance, length)) &&
+        (floatsEqual(distance, length + segment_length) ||
+         distance < (length + segment_length))));
+}
+
+static VGboolean path_point_segment(struct path_iter_data iter,
+                                    struct path_iter_data prev_iter,
+                                    VGfloat coords[8],
+                                    VGfloat distance,
+                                    VGfloat length, VGfloat *current_length,
+                                    VGfloat *point, VGfloat *normal)
+{
+   switch (iter.segment) {
+   case VG_MOVE_TO_ABS:
+      break;
+   case VG_CLOSE_PATH: {
+      VGfloat line[4] = {prev_iter.ox, prev_iter.oy, iter.sx, iter.sy};
+      VGboolean on_current_segment = VG_FALSE;
+      *current_length = line_lengthv(line);
+      on_current_segment = point_on_current_segment(distance,
+                                                    length,
+                                                    *current_length);
+      if (on_current_segment) {
+         VGfloat at = (distance - length) / line_lengthv(line);
+         line_normal_vector(line, normal);
+         line_point_at(line, at, point);
+         return VG_TRUE;
+      }
+   }
+      break;
+   case VG_LINE_TO_ABS: {
+      VGfloat line[4] = {prev_iter.ox, prev_iter.oy, coords[0], coords[1]};
+      VGboolean on_current_segment = VG_FALSE;
+      *current_length = line_lengthv(line);
+      on_current_segment = point_on_current_segment(distance,
+                                                    length,
+                                                    *current_length);
+      if (on_current_segment) {
+         VGfloat at = (distance - length) / line_lengthv(line);
+         line_normal_vector(line, normal);
+         line_point_at(line, at, point);
+         return VG_TRUE;
+      }
+   }
+      break;
+   case VG_CUBIC_TO_ABS: {
+      struct bezier bezier;
+      bezier_init(&bezier, prev_iter.ox, prev_iter.oy,
+                  coords[0], coords[1],
+                  coords[2], coords[3],
+                  coords[4], coords[5]);
+      *current_length = bezier_length(&bezier, BEZIER_DEFAULT_ERROR);
+      if (point_on_current_segment(distance, length, *current_length)) {
+         bezier_point_at_length(&bezier, distance - length,
+                                point, normal);
+         return VG_TRUE;
+      }
+   }
+      break;
+   case VG_SCCWARC_TO:
+   case VG_SCWARC_TO:
+   case VG_LCCWARC_TO:
+   case VG_LCWARC_TO: {
+      struct arc arc;
+      struct matrix identity;
+      struct path *path = path_create(VG_PATH_DATATYPE_F,
+                                      1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
+
+      matrix_load_identity(&identity);
+      arc_init(&arc, iter.segment,
+               prev_iter.ox, prev_iter.oy, coords[3], coords[4],
+               coords[0], coords[1], coords[2]);
+
+      arc_to_path(&arc, path, &identity);
+
+      *current_length = path_length(path, 0, path_num_segments(path));
+      if (point_on_current_segment(distance, length, *current_length)) {
+         path_point(path, 0, path_num_segments(path),
+                    distance - length, point, normal);
+         return VG_TRUE;
+      }
+   }
+      break;
+   default:
+      assert(0);
+   }
+   return VG_FALSE;
+}
+
+void path_point(struct path *p, VGint start_segment, VGint num_segments,
+                VGfloat distance, VGfloat *point, VGfloat *normal)
+{
+   VGint i;
+   VGfloat coords[8];
+   struct path_iter_data iter, prev_iter;
+   VGint num_coords;
+   VGfloat length = 0;
+   VGfloat current_length = 0;
+
+   memset(&iter, 0, sizeof(struct path_iter_data));
+   memset(&prev_iter, 0, sizeof(struct path_iter_data));
+
+   point[0] = 0;
+   point[1] = 0;
+
+   normal[0] = 0;
+   normal[1] = -1;
+
+   iter.path = p;
+   iter.coords = p->control_points->data;
+   if (distance < 0)
+      distance = 0;
+
+   for (i = 0; i < (start_segment + num_segments); ++i) {
+      VGboolean outside_range = (i < start_segment ||
+                                 i >= (start_segment + num_segments));
+
+      prev_iter = iter;
+
+      iter.segment = ((VGubyte*)(p->segments->data))[i];
+      iter.segment = normalize_coords(&iter, &num_coords, coords);
+
+      if (outside_range)
+         continue;
+
+      if (path_point_segment(iter, prev_iter, coords,
+                             distance, length, &current_length,
+                             point, normal))
+         return;
+
+      length += current_length;
+   }
+
+   /*
+    *OpenVG 1.0 - 8.6.11 vgPointAlongPath
+    *
+    * If distance is greater than or equal to the path length
+    *(i.e., the value returned by vgPathLength when called with the same
+    *startSegment and numSegments parameters), the visual ending point of
+    *the path is used.
+    */
+   {
+      switch (iter.segment) {
+      case VG_MOVE_TO_ABS:
+         break;
+      case VG_CLOSE_PATH: {
+         VGfloat line[4] = {prev_iter.ox, prev_iter.oy, iter.sx, iter.sy};
+         line_normal_vector(line, normal);
+         line_point_at(line, 1.f, point);
+      }
+         break;
+      case VG_LINE_TO_ABS: {
+         VGfloat line[4] = {prev_iter.ox, prev_iter.oy, coords[0], coords[1]};
+         line_normal_vector(line, normal);
+         line_point_at(line, 1.f, point);
+      }
+         break;
+      case VG_CUBIC_TO_ABS: {
+         struct bezier bezier;
+         bezier_init(&bezier, prev_iter.ox, prev_iter.oy,
+                     coords[0], coords[1],
+                     coords[2], coords[3],
+                     coords[4], coords[5]);
+         bezier_point_at_t(&bezier, 1.f, point, normal);
+      }
+         break;
+      case VG_SCCWARC_TO:
+      case VG_SCWARC_TO:
+      case VG_LCCWARC_TO:
+      case VG_LCWARC_TO: {
+         struct arc arc;
+         struct matrix identity;
+         struct path *path = path_create(VG_PATH_DATATYPE_F,
+                                         1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
+
+         matrix_load_identity(&identity);
+         arc_init(&arc, iter.segment,
+                  prev_iter.ox, prev_iter.oy, coords[3], coords[4],
+                  coords[0], coords[1], coords[2]);
+
+         arc_to_path(&arc, path, &identity);
+
+         path_point(path, 0, path_num_segments(path),
+                    /* to make sure we're bigger than len * 2 it */
+                    2 * path_length(path, 0, path_num_segments(path)),
+                    point, normal);
+      }
+         break;
+      default:
+         assert(0);
+      }
+   }
+}
+
+VGboolean path_is_empty(struct path *p)
+{
+   return p->segments->num_elements == 0;
+}
diff --git a/src/gallium/state_trackers/vega/path.h b/src/gallium/state_trackers/vega/path.h
new file mode 100644 (file)
index 0000000..e34538b
--- /dev/null
@@ -0,0 +1,126 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#ifndef _PATH_H
+#define _PATH_H
+
+#include "VG/openvg.h"
+
+struct path;
+struct polygon;
+struct matrix;
+
+enum fill_rule {
+   ODD_EVEN_FILL,
+   WINDING_FILL
+};
+
+
+struct path_for_each_data {
+   VGubyte segment;
+   /* all coords are absolute, even if segment is relative */
+   const VGfloat *coords;
+   VGfloat sx, sy, ox, oy, px, py;
+   void *user_data;
+};
+
+typedef VGboolean (*path_for_each_cb)(struct path *p,
+                                      struct path_for_each_data *data);
+
+
+struct path *path_create(VGPathDatatype dt, VGfloat scale, VGfloat bias,
+                         VGint segmentCapacityHint,
+                         VGint coordCapacityHint,
+                         VGbitfield capabilities);
+void path_destroy(struct path *p);
+
+VGbitfield path_capabilities(struct path *p);
+void path_set_capabilities(struct path *p, VGbitfield bf);
+
+void path_append_data(struct path *p,
+                      VGint numSegments,
+                      const VGubyte * pathSegments,
+                      const void * pathData);
+
+void path_append_path(struct path *dst,
+                      struct path *src);
+
+VGint path_num_segments(struct path *p);
+
+void path_bounding_rect(struct path *p, float *x, float *y,
+                        float *w, float *h);
+float path_length(struct path *p, int start_segment, int num_segments);
+
+void path_set_fill_rule(enum fill_rule fill);
+enum fill_rule path_fill_rule(enum fill_rule fill);
+
+VGboolean path_is_empty(struct path *p);
+
+VGbyte path_datatype_size(struct path *p);
+
+VGPathDatatype path_datatype(struct path *p);
+VGfloat path_scale(struct path *p);
+VGfloat path_bias(struct path *p);
+VGint path_num_coords(struct path *p);
+
+void path_modify_coords(struct path *p,
+                        VGint startIndex,
+                        VGint numSegments,
+                        const void * pathData);
+
+struct path *path_create_stroke(struct path *p,
+                                struct matrix *m);
+
+void path_for_each_segment(struct path *path,
+                           path_for_each_cb cb,
+                           void *user_data);
+
+void path_transform(struct path *dst, struct path *src);
+VGboolean path_interpolate(struct path *dst,
+                           struct path *start, struct path *end,
+                           VGfloat amount);
+
+void path_clear(struct path *p, VGbitfield capabilities);
+void path_render(struct path *p, VGbitfield paintModes);
+void path_fill(struct path *p, struct matrix *mat);
+void path_stroke(struct path *p);
+
+void path_move_to(struct path *p, float x, float y);
+void path_line_to(struct path *p, float x, float y);
+void path_cubic_to(struct path *p, float px1, float py1,
+                   float px2, float py2,
+                   float x, float y);
+
+void path_point(struct path *p, VGint startSegment, VGint numSegments,
+                VGfloat distance, VGfloat *point, VGfloat *normal);
+
+
+
+void vg_float_to_datatype(VGPathDatatype datatype,
+                          VGubyte *common_data,
+                          const VGfloat *data,
+                          VGint num_coords);
+#endif
diff --git a/src/gallium/state_trackers/vega/path_utils.h b/src/gallium/state_trackers/vega/path_utils.h
new file mode 100644 (file)
index 0000000..c2b3221
--- /dev/null
@@ -0,0 +1,109 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#ifndef PATH_UTILS_H
+#define PATH_UTILS_H
+
+#include "VG/openvg.h"
+
+#define SEGMENT_COMMAND(command) /* Extract segment type */     \
+    ((command) & 0x1e)
+#define SEGMENT_ABS_REL(command) /* Extract absolute/relative bit */ \
+    ((command) & 0x1)
+
+static INLINE VGint size_for_datatype(VGPathDatatype datatype)
+{
+   switch(datatype) {
+   case VG_PATH_DATATYPE_S_8:
+      return 1;
+   case VG_PATH_DATATYPE_S_16:
+      return 2;
+   case VG_PATH_DATATYPE_S_32:
+      return 4;
+   case VG_PATH_DATATYPE_F:
+      return 4;
+   default:
+      assert(!"unknown datatype");
+   }
+   return 0;
+}
+
+static INLINE VGint num_elements_for_segments(const VGubyte *segments,
+                                              VGint num_segments)
+{
+   VGint i;
+   VGint count = 0;
+
+   for (i = 0; i < num_segments; ++i) {
+      VGubyte segment = segments[i];
+      VGint command = SEGMENT_COMMAND(segment);
+      switch(command) {
+      case VG_CLOSE_PATH:
+         break;
+      case VG_MOVE_TO:
+         count += 2;
+         break;
+      case VG_LINE_TO:
+         count += 2;
+         break;
+      case VG_HLINE_TO:
+         count += 1;
+         break;
+      case VG_VLINE_TO:
+         count += 1;
+         break;
+      case VG_QUAD_TO:
+         count += 4;
+         break;
+      case VG_CUBIC_TO:
+         count += 6;
+         break;
+      case VG_SQUAD_TO:
+         count += 2;
+         break;
+      case VG_SCUBIC_TO:
+         count += 4;
+         break;
+      case VG_SCCWARC_TO:
+         count += 5;
+         break;
+      case VG_SCWARC_TO:
+         count += 5;
+         break;
+      case VG_LCCWARC_TO:
+         count += 5;
+         break;
+      case VG_LCWARC_TO:
+         count += 5;
+         break;
+      default:
+         assert(!"Unknown segment!");
+      }
+   }
+   return count;
+}
+
+#endif
diff --git a/src/gallium/state_trackers/vega/polygon.c b/src/gallium/state_trackers/vega/polygon.c
new file mode 100644 (file)
index 0000000..b6d282d
--- /dev/null
@@ -0,0 +1,550 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#include "polygon.h"
+
+#include "matrix.h" /*for floatsEqual*/
+#include "vg_context.h"
+#include "vg_state.h"
+#include "paint.h"
+#include "renderer.h"
+#include "util_array.h"
+#include "VG/openvg.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_defines.h"
+#include "pipe/p_state.h"
+#include "pipe/p_inlines.h"
+#include "pipe/p_screen.h"
+
+#include "util/u_draw_quad.h"
+#include "util/u_math.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#define DEBUG_POLYGON 0
+
+#define COMPONENTS 2
+
+struct polygon
+{
+   VGfloat *data;
+   VGint    size;
+
+   VGint    num_verts;
+
+   VGboolean dirty;
+   struct pipe_buffer *vbuf;
+   struct pipe_screen *screen;
+};
+
+static float *ptr_to_vertex(float *data, int idx)
+{
+   return data + (idx * COMPONENTS);
+}
+
+#if 0
+static void polygon_print(struct polygon *poly)
+{
+   int i;
+   float *vert;
+   debug_printf("Polygon %p, size = %d\n", poly, poly->num_verts);
+   for (i = 0; i < poly->num_verts; ++i) {
+      vert = ptr_to_vertex(poly->data, i);
+      debug_printf("%f, %f,  ", vert[0], vert[1]);
+   }
+   debug_printf("\nend\n");
+}
+#endif
+
+
+struct polygon * polygon_create(int size)
+{
+   struct polygon *poly = (struct polygon*)malloc(sizeof(struct polygon));
+
+   poly->data = malloc(sizeof(float) * COMPONENTS * size);
+   poly->size = size;
+   poly->num_verts = 0;
+   poly->dirty = VG_TRUE;
+   poly->vbuf = NULL;
+
+   return poly;
+}
+
+struct polygon * polygon_create_from_data(float *data, int size)
+{
+   struct polygon *poly = polygon_create(size);
+
+   memcpy(poly->data, data, sizeof(float) * COMPONENTS * size);
+   poly->num_verts = size;
+   poly->dirty = VG_TRUE;
+   poly->vbuf = NULL;
+
+   return poly;
+}
+
+void polygon_destroy(struct polygon *poly)
+{
+   if (poly->vbuf)
+      pipe_buffer_reference(&poly->vbuf, NULL);
+
+   free(poly->data);
+   free(poly);
+}
+
+void polygon_resize(struct polygon *poly, int new_size)
+{
+   float *data = (float*)malloc(sizeof(float) * COMPONENTS * new_size);
+   int size = MIN2(sizeof(float) * COMPONENTS * new_size,
+                   sizeof(float) * COMPONENTS * poly->size);
+   memcpy(data, poly->data, size);
+   free(poly->data);
+   poly->data = data;
+   poly->size = new_size;
+   poly->dirty = VG_TRUE;
+}
+
+int polygon_size(struct polygon *poly)
+{
+   return poly->size;
+}
+
+int polygon_vertex_count(struct polygon *poly)
+{
+   return poly->num_verts;
+}
+
+float * polygon_data(struct polygon *poly)
+{
+   return poly->data;
+}
+
+void polygon_vertex_append(struct polygon *p,
+                           float x, float y)
+{
+   float *vert;
+#if DEBUG_POLYGON
+   debug_printf("Append vertex [%f, %f]\n", x, y);
+#endif
+   if (p->num_verts >= p->size) {
+      polygon_resize(p, p->size * 2);
+   }
+
+   vert = ptr_to_vertex(p->data, p->num_verts);
+   vert[0] = x;
+   vert[1] = y;
+   ++p->num_verts;
+   p->dirty = VG_TRUE;
+}
+
+void polygon_set_vertex(struct polygon *p, int idx,
+                        float x, float y)
+{
+   float *vert;
+   if (idx >= p->num_verts) {
+      /*fixme: error reporting*/
+      abort();
+      return;
+   }
+
+   vert = ptr_to_vertex(p->data, idx);
+   vert[0] = x;
+   vert[1] = y;
+   p->dirty = VG_TRUE;
+}
+
+void polygon_vertex(struct polygon *p, int idx,
+                    float *vertex)
+{
+   float *vert;
+   if (idx >= p->num_verts) {
+      /*fixme: error reporting*/
+      abort();
+      return;
+   }
+
+   vert = ptr_to_vertex(p->data, idx);
+   vertex[0] = vert[0];
+   vertex[1] = vert[1];
+}
+
+void polygon_bounding_rect(struct polygon *p,
+                           float *rect)
+{
+   int i;
+   float minx, miny, maxx, maxy;
+   float *vert = ptr_to_vertex(p->data, 0);
+   minx = vert[0];
+   maxx = vert[0];
+   miny = vert[1];
+   maxy = vert[1];
+
+   for (i = 1; i < p->num_verts; ++i) {
+      vert = ptr_to_vertex(p->data, i);
+      minx = MIN2(vert[0], minx);
+      miny = MIN2(vert[1], miny);
+
+      maxx = MAX2(vert[0], maxx);
+      maxy = MAX2(vert[1], maxy);
+   }
+
+   rect[0] = minx;
+   rect[1] = miny;
+   rect[2] = maxx - minx;
+   rect[3] = maxy - miny;
+}
+
+int polygon_contains_point(struct polygon *p,
+                           float x, float y)
+{
+   return 0;
+}
+
+void polygon_append_polygon(struct polygon *dst,
+                            struct polygon *src)
+{
+   if (dst->num_verts + src->num_verts >= dst->size) {
+      polygon_resize(dst, dst->num_verts + src->num_verts * 1.5);
+   }
+   memcpy(ptr_to_vertex(dst->data, dst->num_verts),
+          src->data, src->num_verts * COMPONENTS * sizeof(VGfloat));
+   dst->num_verts += src->num_verts;
+}
+
+VGboolean polygon_is_closed(struct polygon *p)
+{
+   VGfloat start[2], end[2];
+
+   polygon_vertex(p, 0, start);
+   polygon_vertex(p, p->num_verts - 1, end);
+
+   return floatsEqual(start[0], end[0]) && floatsEqual(start[1], end[1]);
+}
+
+static void set_blend_for_fill(struct pipe_blend_state *blend)
+{
+   memset(blend, 0, sizeof(struct pipe_blend_state));
+   blend->colormask = 0; /*disable colorwrites*/
+
+   blend->rgb_src_factor = PIPE_BLENDFACTOR_ONE;
+   blend->alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+   blend->rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
+   blend->alpha_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
+}
+
+static void draw_polygon(struct vg_context *ctx,
+                         struct polygon *poly)
+{
+   int vert_size;
+   struct pipe_context *pipe;
+   struct pipe_vertex_buffer vbuffer;
+   struct pipe_vertex_element velement;
+
+   vert_size = poly->num_verts * COMPONENTS * sizeof(float);
+
+   /*polygon_print(poly);*/
+
+   pipe = ctx->pipe;
+
+   if (poly->vbuf == NULL || poly->dirty) {
+      if (poly->vbuf) {
+         pipe_buffer_reference(&poly->vbuf,
+                               NULL);
+      }
+      poly->screen = pipe->screen;
+      poly->vbuf= pipe_user_buffer_create(poly->screen,
+                                          poly->data,
+                                          vert_size);
+      poly->dirty = VG_FALSE;
+   }
+
+
+   /* tell pipe about the vertex buffer */
+   memset(&vbuffer, 0, sizeof(vbuffer));
+   vbuffer.buffer = poly->vbuf;
+   vbuffer.stride = COMPONENTS * sizeof(float);  /* vertex size */
+   vbuffer.buffer_offset = 0;
+   vbuffer.max_index = poly->num_verts - 1;
+   pipe->set_vertex_buffers(pipe, 1, &vbuffer);
+
+   /* tell pipe about the vertex attributes */
+   velement.src_offset = 0;
+   velement.vertex_buffer_index = 0;
+   velement.src_format = PIPE_FORMAT_R32G32_FLOAT;
+   velement.nr_components = COMPONENTS;
+   pipe->set_vertex_elements(pipe, 1, &velement);
+
+   /* draw */
+   pipe->draw_arrays(pipe, PIPE_PRIM_TRIANGLE_FAN, 
+                     0, poly->num_verts);
+}
+
+void polygon_fill(struct polygon *poly, struct vg_context *ctx)
+{
+   struct pipe_depth_stencil_alpha_state dsa;
+   struct pipe_blend_state blend;
+   VGfloat bounds[4];
+   VGfloat min_x, min_y, max_x, max_y;
+   assert(poly);
+   polygon_bounding_rect(poly, bounds);
+   min_x = bounds[0];
+   min_y = bounds[1];
+   max_x = bounds[0] + bounds[2];
+   max_y = bounds[1] + bounds[3];
+
+#if DEBUG_POLYGON
+   debug_printf("Poly bounds are [%f, %f], [%f, %f]\n",
+                min_x, min_y, max_x, max_y);
+#endif
+
+   set_blend_for_fill(&blend);
+
+   memset(&dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state));
+
+   cso_save_blend(ctx->cso_context);
+   cso_save_depth_stencil_alpha(ctx->cso_context);
+
+   dsa.stencil[0].enabled = 1;
+   if (ctx->state.vg.fill_rule == VG_EVEN_ODD) {
+      dsa.stencil[0].writemask = 1;
+      dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
+      dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
+      dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INVERT;
+      dsa.stencil[0].func = PIPE_FUNC_ALWAYS;
+      dsa.stencil[0].ref_value = 0;
+      dsa.stencil[0].valuemask = ~0;
+
+      cso_set_blend(ctx->cso_context, &blend);
+      cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
+      draw_polygon(ctx, poly);
+   } else if (ctx->state.vg.fill_rule == VG_NON_ZERO) {
+      struct pipe_screen *screen = ctx->pipe->screen;
+
+      if (screen->get_param(screen, PIPE_CAP_TWO_SIDED_STENCIL)) {
+         /* front */
+         dsa.stencil[0].writemask = ~0;
+         dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
+         dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
+         dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP;
+         dsa.stencil[0].func = PIPE_FUNC_ALWAYS;
+         dsa.stencil[0].ref_value = 0;
+         dsa.stencil[0].valuemask = ~0;
+
+         /* back */
+         dsa.stencil[1].enabled = 1;
+         dsa.stencil[1].writemask = ~0;
+         dsa.stencil[1].fail_op = PIPE_STENCIL_OP_KEEP;
+         dsa.stencil[1].zfail_op = PIPE_STENCIL_OP_KEEP;
+         dsa.stencil[1].zpass_op = PIPE_STENCIL_OP_DECR_WRAP;
+         dsa.stencil[1].func = PIPE_FUNC_ALWAYS;
+         dsa.stencil[1].ref_value = 0;
+         dsa.stencil[1].valuemask = ~0;
+
+         cso_set_blend(ctx->cso_context, &blend);
+         cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
+         draw_polygon(ctx, poly);
+      } else {
+         struct pipe_rasterizer_state raster;
+
+         memcpy(&raster, &ctx->state.g3d.rasterizer, sizeof(struct pipe_rasterizer_state));
+
+         cso_save_rasterizer(ctx->cso_context);
+         dsa.stencil[0].func = PIPE_FUNC_ALWAYS;
+         dsa.stencil[0].ref_value = 0;
+         dsa.stencil[0].valuemask = ~0;
+
+         raster.cull_mode = raster.front_winding ^ PIPE_WINDING_BOTH;
+         dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
+         dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
+         dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP;
+
+         cso_set_blend(ctx->cso_context, &blend);
+         cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
+         cso_set_rasterizer(ctx->cso_context, &raster);
+         draw_polygon(ctx, poly);
+
+         raster.cull_mode = raster.front_winding;
+         dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
+         dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
+         dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_DECR_WRAP;
+         cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
+         cso_set_rasterizer(ctx->cso_context, &raster);
+         draw_polygon(ctx, poly);
+
+         cso_restore_rasterizer(ctx->cso_context);
+      }
+   }
+
+   /* restore color writes */
+   cso_restore_blend(ctx->cso_context);
+   /* setup stencil ops */
+   dsa.stencil[0].func = PIPE_FUNC_NOTEQUAL;
+   dsa.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE;
+   dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE;
+   dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE;
+   dsa.stencil[0].ref_value = 0;
+   dsa.stencil[0].valuemask = dsa.stencil[0].writemask;
+   dsa.stencil[1].enabled = 0;
+   memcpy(&dsa.depth, &ctx->state.g3d.dsa.depth,
+          sizeof(struct pipe_depth_state));
+   cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
+
+   /* render the quad to propagate the rendering from stencil */
+   renderer_draw_quad(ctx->renderer, min_x, min_y,
+                      max_x, max_y, 0.0f/*depth should be disabled*/);
+
+   cso_restore_depth_stencil_alpha(ctx->cso_context);
+}
+
+void polygon_array_fill(struct polygon_array *polyarray, struct vg_context *ctx)
+{
+   struct array *polys = polyarray->array;
+   struct pipe_depth_stencil_alpha_state dsa;
+   struct pipe_blend_state blend;
+   VGfloat min_x = polyarray->min_x;
+   VGfloat min_y = polyarray->min_y;
+   VGfloat max_x = polyarray->max_x;
+   VGfloat max_y = polyarray->max_y;
+   VGint i;
+
+
+#if DEBUG_POLYGON
+   debug_printf("%s: Poly bounds are [%f, %f], [%f, %f]\n",
+                __FUNCTION__,
+                min_x, min_y, max_x, max_y);
+#endif
+
+   set_blend_for_fill(&blend);
+
+   memset(&dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state));
+
+   cso_save_blend(ctx->cso_context);
+   cso_save_depth_stencil_alpha(ctx->cso_context);
+
+   dsa.stencil[0].enabled = 1;
+   if (ctx->state.vg.fill_rule == VG_EVEN_ODD) {
+      dsa.stencil[0].writemask = 1;
+      dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
+      dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
+      dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INVERT;
+      dsa.stencil[0].func = PIPE_FUNC_ALWAYS;
+      dsa.stencil[0].ref_value = 0;
+      dsa.stencil[0].valuemask = ~0;
+
+      cso_set_blend(ctx->cso_context, &blend);
+      cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
+      for (i = 0; i < polys->num_elements; ++i) {
+         struct polygon *poly = (((struct polygon**)polys->data)[i]);
+         draw_polygon(ctx, poly);
+      }
+   } else if (ctx->state.vg.fill_rule == VG_NON_ZERO) {
+      struct pipe_screen *screen = ctx->pipe->screen;
+
+      if (screen->get_param(screen, PIPE_CAP_TWO_SIDED_STENCIL)) {
+         /* front */
+         dsa.stencil[0].writemask = ~0;
+         dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
+         dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
+         dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP;
+         dsa.stencil[0].func = PIPE_FUNC_ALWAYS;
+         dsa.stencil[0].ref_value = 0;
+         dsa.stencil[0].valuemask = ~0;
+
+         /* back */
+         dsa.stencil[1].enabled = 1;
+         dsa.stencil[1].writemask = ~0;
+         dsa.stencil[1].fail_op = PIPE_STENCIL_OP_KEEP;
+         dsa.stencil[1].zfail_op = PIPE_STENCIL_OP_KEEP;
+         dsa.stencil[1].zpass_op = PIPE_STENCIL_OP_DECR_WRAP;
+         dsa.stencil[1].func = PIPE_FUNC_ALWAYS;
+         dsa.stencil[1].ref_value = 0;
+         dsa.stencil[1].valuemask = ~0;
+
+         cso_set_blend(ctx->cso_context, &blend);
+         cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
+         for (i = 0; i < polys->num_elements; ++i) {
+            struct polygon *poly = (((struct polygon**)polys->data)[i]);
+            draw_polygon(ctx, poly);
+         }
+      } else {
+         struct pipe_rasterizer_state raster;
+
+         memcpy(&raster, &ctx->state.g3d.rasterizer, sizeof(struct pipe_rasterizer_state));
+
+         cso_save_rasterizer(ctx->cso_context);
+         dsa.stencil[0].func = PIPE_FUNC_ALWAYS;
+         dsa.stencil[0].ref_value = 0;
+         dsa.stencil[0].valuemask = ~0;
+
+         raster.cull_mode = raster.front_winding ^ PIPE_WINDING_BOTH;
+         dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
+         dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
+         dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP;
+
+         cso_set_blend(ctx->cso_context, &blend);
+         cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
+         cso_set_rasterizer(ctx->cso_context, &raster);
+         for (i = 0; i < polys->num_elements; ++i) {
+            struct polygon *poly = (((struct polygon**)polys->data)[i]);
+            draw_polygon(ctx, poly);
+         }
+
+         raster.cull_mode = raster.front_winding;
+         dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
+         dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
+         dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_DECR_WRAP;
+         cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
+         cso_set_rasterizer(ctx->cso_context, &raster);
+         for (i = 0; i < polys->num_elements; ++i) {
+            struct polygon *poly = (((struct polygon**)polys->data)[i]);
+            draw_polygon(ctx, poly);
+         }
+
+         cso_restore_rasterizer(ctx->cso_context);
+      }
+   }
+
+   /* restore color writes */
+   cso_restore_blend(ctx->cso_context);
+   /* setup stencil ops */
+   dsa.stencil[0].func = PIPE_FUNC_NOTEQUAL;
+   dsa.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE;
+   dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE;
+   dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE;
+   dsa.stencil[0].ref_value = 0;
+   dsa.stencil[0].valuemask = dsa.stencil[0].writemask;
+   dsa.stencil[1].enabled = 0;
+   memcpy(&dsa.depth, &ctx->state.g3d.dsa.depth,
+          sizeof(struct pipe_depth_state));
+   cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
+
+   /* render the quad to propagate the rendering from stencil */
+   renderer_draw_quad(ctx->renderer, min_x, min_y,
+                      max_x, max_y, 0.0f/*depth should be disabled*/);
+
+   cso_restore_depth_stencil_alpha(ctx->cso_context);
+}
diff --git a/src/gallium/state_trackers/vega/polygon.h b/src/gallium/state_trackers/vega/polygon.h
new file mode 100644 (file)
index 0000000..22672b7
--- /dev/null
@@ -0,0 +1,75 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#ifndef POLYGON_H
+#define POLYGON_H
+
+#include "VG/openvg.h"
+
+struct polygon;
+struct vg_context;
+struct vg_paint;
+struct array;
+
+struct polygon *polygon_create(int size);
+struct polygon *polygon_create_from_data(float *data, int size);
+void            polygon_destroy(struct polygon *poly);
+
+void            polygon_resize(struct polygon *poly, int new_size);
+int             polygon_size(struct polygon *poly);
+
+int             polygon_vertex_count(struct polygon *poly);
+float *         polygon_data(struct polygon *poly);
+
+void            polygon_vertex_append(struct polygon *p,
+                                      float x, float y);
+void            polygon_append_polygon(struct polygon *dst,
+                                       struct polygon *src);
+void            polygon_set_vertex(struct polygon *p, int idx,
+                                   float x, float y);
+void            polygon_vertex(struct polygon *p, int idx,
+                               float *vertex);
+
+void            polygon_bounding_rect(struct polygon *p,
+                                      float *rect);
+int             polygon_contains_point(struct polygon *p,
+                                       float x, float y);
+
+VGboolean       polygon_is_closed(struct polygon *p);
+
+void polygon_fill(struct polygon *p, struct vg_context *pipe);
+
+/* TODO: make a file/module around this struct
+ */
+struct polygon_array {
+   struct array *array;
+   VGfloat min_x, max_x;
+   VGfloat min_y, max_y;
+};
+
+void polygon_array_fill(struct polygon_array *polyarray, struct vg_context *ctx);
+
+#endif
diff --git a/src/gallium/state_trackers/vega/renderer.c b/src/gallium/state_trackers/vega/renderer.c
new file mode 100644 (file)
index 0000000..f7c5f2f
--- /dev/null
@@ -0,0 +1,592 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#include "renderer.h"
+
+#include "vg_context.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_state.h"
+#include "pipe/p_inlines.h"
+#include "pipe/p_screen.h"
+#include "pipe/p_shader_tokens.h"
+
+#include "util/u_draw_quad.h"
+#include "util/u_simple_shaders.h"
+#include "util/u_memory.h"
+
+#include "cso_cache/cso_context.h"
+
+struct renderer {
+   struct pipe_context *pipe;
+   struct vg_context *owner;
+
+   struct cso_context *cso;
+
+   void *fs;
+
+   VGfloat vertices[4][2][4];
+};
+
+static void setup_shaders(struct renderer *ctx)
+{
+   struct pipe_context *pipe = ctx->pipe;
+   /* fragment shader */
+   ctx->fs = util_make_fragment_tex_shader(pipe);
+}
+
+static struct pipe_buffer *
+setup_vertex_data(struct renderer *ctx,
+                  float x0, float y0, float x1, float y1, float z)
+{
+   ctx->vertices[0][0][0] = x0;
+   ctx->vertices[0][0][1] = y0;
+   ctx->vertices[0][0][2] = z;
+   ctx->vertices[0][1][0] = 0.0f; /*s*/
+   ctx->vertices[0][1][1] = 0.0f; /*t*/
+
+   ctx->vertices[1][0][0] = x1;
+   ctx->vertices[1][0][1] = y0;
+   ctx->vertices[1][0][2] = z;
+   ctx->vertices[1][1][0] = 1.0f; /*s*/
+   ctx->vertices[1][1][1] = 0.0f; /*t*/
+
+   ctx->vertices[2][0][0] = x1;
+   ctx->vertices[2][0][1] = y1;
+   ctx->vertices[2][0][2] = z;
+   ctx->vertices[2][1][0] = 1.0f;
+   ctx->vertices[2][1][1] = 1.0f;
+
+   ctx->vertices[3][0][0] = x0;
+   ctx->vertices[3][0][1] = y1;
+   ctx->vertices[3][0][2] = z;
+   ctx->vertices[3][1][0] = 0.0f;
+   ctx->vertices[3][1][1] = 1.0f;
+
+   return pipe_user_buffer_create( ctx->pipe->screen,
+                                   ctx->vertices,
+                                   sizeof(ctx->vertices) );
+}
+
+static struct pipe_buffer *
+setup_vertex_data_tex(struct renderer *ctx,
+                      float x0, float y0, float x1, float y1,
+                      float s0, float t0, float s1, float t1,
+                      float z)
+{
+   ctx->vertices[0][0][0] = x0;
+   ctx->vertices[0][0][1] = y0;
+   ctx->vertices[0][0][2] = z;
+   ctx->vertices[0][1][0] = s0; /*s*/
+   ctx->vertices[0][1][1] = t0; /*t*/
+
+   ctx->vertices[1][0][0] = x1;
+   ctx->vertices[1][0][1] = y0;
+   ctx->vertices[1][0][2] = z;
+   ctx->vertices[1][1][0] = s1; /*s*/
+   ctx->vertices[1][1][1] = t0; /*t*/
+
+   ctx->vertices[2][0][0] = x1;
+   ctx->vertices[2][0][1] = y1;
+   ctx->vertices[2][0][2] = z;
+   ctx->vertices[2][1][0] = s1;
+   ctx->vertices[2][1][1] = t1;
+
+   ctx->vertices[3][0][0] = x0;
+   ctx->vertices[3][0][1] = y1;
+   ctx->vertices[3][0][2] = z;
+   ctx->vertices[3][1][0] = s0;
+   ctx->vertices[3][1][1] = t1;
+
+   return pipe_user_buffer_create( ctx->pipe->screen,
+                                   ctx->vertices,
+                                   sizeof(ctx->vertices) );
+}
+
+
+static struct pipe_buffer *
+setup_vertex_data_qtex(struct renderer *ctx,
+                       float x0, float y0, float x1, float y1,
+                       float x2, float y2, float x3, float y3,
+                       float s0, float t0, float s1, float t1,
+                       float z)
+{
+   ctx->vertices[0][0][0] = x0;
+   ctx->vertices[0][0][1] = y0;
+   ctx->vertices[0][0][2] = z;
+   ctx->vertices[0][1][0] = s0; /*s*/
+   ctx->vertices[0][1][1] = t0; /*t*/
+
+   ctx->vertices[1][0][0] = x1;
+   ctx->vertices[1][0][1] = y1;
+   ctx->vertices[1][0][2] = z;
+   ctx->vertices[1][1][0] = s1; /*s*/
+   ctx->vertices[1][1][1] = t0; /*t*/
+
+   ctx->vertices[2][0][0] = x2;
+   ctx->vertices[2][0][1] = y2;
+   ctx->vertices[2][0][2] = z;
+   ctx->vertices[2][1][0] = s1;
+   ctx->vertices[2][1][1] = t1;
+
+   ctx->vertices[3][0][0] = x3;
+   ctx->vertices[3][0][1] = y3;
+   ctx->vertices[3][0][2] = z;
+   ctx->vertices[3][1][0] = s0;
+   ctx->vertices[3][1][1] = t1;
+
+   return pipe_user_buffer_create( ctx->pipe->screen,
+                                   ctx->vertices,
+                                   sizeof(ctx->vertices) );
+}
+
+struct renderer * renderer_create(struct vg_context *owner)
+{
+   VGint i;
+   struct renderer *renderer = CALLOC_STRUCT(renderer);
+
+   if (!renderer)
+      return NULL;
+
+   renderer->owner = owner;
+   renderer->pipe = owner->pipe;
+   renderer->cso = owner->cso_context;
+
+   setup_shaders(renderer);
+
+   /* init vertex data that doesn't change */
+   for (i = 0; i < 4; i++) {
+      renderer->vertices[i][0][3] = 1.0f; /* w */
+      renderer->vertices[i][1][2] = 0.0f; /* r */
+      renderer->vertices[i][1][3] = 1.0f; /* q */
+   }
+
+   return renderer;
+}
+
+void renderer_destroy(struct renderer *ctx)
+{
+#if 0
+   if (ctx->fs) {
+      cso_delete_fragment_shader(ctx->cso, ctx->fs);
+      ctx->fs = NULL;
+   }
+#endif
+   free(ctx);
+}
+
+void renderer_draw_quad(struct renderer *r,
+                        VGfloat x1, VGfloat y1,
+                        VGfloat x2, VGfloat y2,
+                        VGfloat depth)
+{
+   struct pipe_buffer *buf;
+
+   buf = setup_vertex_data(r, x1, y1, x2, y2, depth);
+
+   if (buf) {
+      util_draw_vertex_buffer(r->pipe, buf, 0,
+                              PIPE_PRIM_TRIANGLE_FAN,
+                              4,  /* verts */
+                              2); /* attribs/vert */
+
+      pipe_buffer_reference( &buf,
+                             NULL );
+   }
+}
+
+void renderer_draw_texture(struct renderer *r,
+                           struct pipe_texture *tex,
+                           VGfloat x1offset, VGfloat y1offset,
+                           VGfloat x2offset, VGfloat y2offset,
+                           VGfloat x1, VGfloat y1,
+                           VGfloat x2, VGfloat y2)
+{
+   struct pipe_context *pipe = r->pipe;
+   struct pipe_buffer *buf;
+   VGfloat s0, t0, s1, t1;
+
+   assert(tex->width[0] != 0);
+   assert(tex->height[0] != 0);
+
+   s0 = x1offset / tex->width[0];
+   s1 = x2offset / tex->width[0];
+   t0 = y1offset / tex->height[0];
+   t1 = y2offset / tex->height[0];
+
+   cso_save_vertex_shader(r->cso);
+   /* shaders */
+   cso_set_vertex_shader_handle(r->cso, vg_texture_vs(r->owner));
+
+   /* draw quad */
+   buf = setup_vertex_data_tex(r, x1, y1, x2, y2,
+                               s0, t0, s1, t1, 0.0f);
+
+   if (buf) {
+      util_draw_vertex_buffer(pipe, buf, 0,
+                           PIPE_PRIM_TRIANGLE_FAN,
+                           4,  /* verts */
+                           2); /* attribs/vert */
+
+      pipe_buffer_reference( &buf,
+                             NULL );
+   }
+
+   cso_restore_vertex_shader(r->cso);
+}
+
+void renderer_copy_texture(struct renderer *ctx,
+                           struct pipe_texture *src,
+                           VGfloat sx1, VGfloat sy1,
+                           VGfloat sx2, VGfloat sy2,
+                           struct pipe_texture *dst,
+                           VGfloat dx1, VGfloat dy1,
+                           VGfloat dx2, VGfloat dy2)
+{
+   struct pipe_context *pipe = ctx->pipe;
+   struct pipe_screen *screen = pipe->screen;
+   struct pipe_buffer *buf;
+   struct pipe_surface *dst_surf = screen->get_tex_surface(
+      screen, dst, 0, 0, 0,
+      PIPE_BUFFER_USAGE_GPU_WRITE);
+   struct pipe_framebuffer_state fb;
+   float s0, t0, s1, t1;
+
+   assert(src->width[0] != 0);
+   assert(src->height[0] != 0);
+   assert(dst->width[0] != 0);
+   assert(dst->height[0] != 0);
+
+#if 0
+   debug_printf("copy texture [%f, %f, %f, %f], [%f, %f, %f, %f]\n",
+                sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2);
+#endif
+
+#if 1
+   s0 = sx1 / src->width[0];
+   s1 = sx2 / src->width[0];
+   t0 = sy1 / src->height[0];
+   t1 = sy2 / src->height[0];
+#else
+   s0 = 0;
+   s1 = 1;
+   t0 = 0;
+   t1 = 1;
+#endif
+
+   assert(screen->is_format_supported(screen, dst_surf->format, PIPE_TEXTURE_2D,
+                                      PIPE_TEXTURE_USAGE_RENDER_TARGET, 0));
+
+   /* save state (restored below) */
+   cso_save_blend(ctx->cso);
+   cso_save_samplers(ctx->cso);
+   cso_save_sampler_textures(ctx->cso);
+   cso_save_framebuffer(ctx->cso);
+   cso_save_fragment_shader(ctx->cso);
+   cso_save_vertex_shader(ctx->cso);
+
+   cso_save_viewport(ctx->cso);
+
+
+   /* set misc state we care about */
+   {
+      struct pipe_blend_state blend;
+      memset(&blend, 0, sizeof(blend));
+      blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE;
+      blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+      blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
+      blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
+      blend.colormask = PIPE_MASK_RGBA;
+      cso_set_blend(ctx->cso, &blend);
+   }
+
+   /* sampler */
+   {
+      struct pipe_sampler_state sampler;
+      memset(&sampler, 0, sizeof(sampler));
+      sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+      sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+      sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+      sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
+      sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
+      sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
+      sampler.normalized_coords = 1;
+      cso_single_sampler(ctx->cso, 0, &sampler);
+      cso_single_sampler_done(ctx->cso);
+   }
+
+   vg_set_viewport(ctx->owner, VEGA_Y0_TOP);
+
+   /* texture */
+   cso_set_sampler_textures(ctx->cso, 1, &src);
+
+   /* shaders */
+   cso_set_vertex_shader_handle(ctx->cso, vg_texture_vs(ctx->owner));
+   cso_set_fragment_shader_handle(ctx->cso, ctx->fs);
+
+   /* drawing dest */
+   memset(&fb, 0, sizeof(fb));
+   fb.width = dst_surf->width;
+   fb.height = dst_surf->height;
+   fb.nr_cbufs = 1;
+   fb.cbufs[0] = dst_surf;
+   {
+      VGint i;
+      for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i)
+         fb.cbufs[i] = 0;
+   }
+   cso_set_framebuffer(ctx->cso, &fb);
+
+   /* draw quad */
+   buf = setup_vertex_data_tex(ctx,
+                         dx1, dy1,
+                         dx2, dy2,
+                         s0, t0, s1, t1,
+                         0.0f);
+
+   if (buf) {
+      util_draw_vertex_buffer(ctx->pipe, buf, 0,
+                              PIPE_PRIM_TRIANGLE_FAN,
+                              4,  /* verts */
+                              2); /* attribs/vert */
+
+      pipe_buffer_reference( &buf,
+                             NULL );
+   }
+
+   /* restore state we changed */
+   cso_restore_blend(ctx->cso);
+   cso_restore_samplers(ctx->cso);
+   cso_restore_sampler_textures(ctx->cso);
+   cso_restore_framebuffer(ctx->cso);
+   cso_restore_vertex_shader(ctx->cso);
+   cso_restore_fragment_shader(ctx->cso);
+   cso_restore_viewport(ctx->cso);
+
+   pipe_surface_reference(&dst_surf, NULL);
+}
+
+void renderer_copy_surface(struct renderer *ctx,
+                           struct pipe_surface *src,
+                           int srcX0, int srcY0,
+                           int srcX1, int srcY1,
+                           struct pipe_surface *dst,
+                           int dstX0, int dstY0,
+                           int dstX1, int dstY1,
+                           float z, unsigned filter)
+{
+   struct pipe_context *pipe = ctx->pipe;
+   struct pipe_screen *screen = pipe->screen;
+   struct pipe_buffer *buf;
+   struct pipe_texture texTemp, *tex;
+   struct pipe_surface *texSurf;
+   struct pipe_framebuffer_state fb;
+   struct st_framebuffer *stfb = ctx->owner->draw_buffer;
+   const int srcW = abs(srcX1 - srcX0);
+   const int srcH = abs(srcY1 - srcY0);
+   const int srcLeft = MIN2(srcX0, srcX1);
+   const int srcTop = MIN2(srcY0, srcY1);
+
+   assert(filter == PIPE_TEX_MIPFILTER_NEAREST ||
+          filter == PIPE_TEX_MIPFILTER_LINEAR);
+
+   if (srcLeft != srcX0) {
+      /* left-right flip */
+      int tmp = dstX0;
+      dstX0 = dstX1;
+      dstX1 = tmp;
+   }
+
+   if (srcTop != srcY0) {
+      /* up-down flip */
+      int tmp = dstY0;
+      dstY0 = dstY1;
+      dstY1 = tmp;
+   }
+
+   assert(screen->is_format_supported(screen, src->format, PIPE_TEXTURE_2D,
+                                      PIPE_TEXTURE_USAGE_SAMPLER, 0));
+   assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D,
+                                      PIPE_TEXTURE_USAGE_SAMPLER, 0));
+   assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D,
+                                      PIPE_TEXTURE_USAGE_RENDER_TARGET, 0));
+
+   /*
+    * XXX for now we're always creating a temporary texture.
+    * Strictly speaking that's not always needed.
+    */
+
+   /* create temp texture */
+   memset(&texTemp, 0, sizeof(texTemp));
+   texTemp.target = PIPE_TEXTURE_2D;
+   texTemp.format = src->format;
+   texTemp.last_level = 0;
+   texTemp.width[0] = srcW;
+   texTemp.height[0] = srcH;
+   texTemp.depth[0] = 1;
+   pf_get_block(src->format, &texTemp.block);
+
+   tex = screen->texture_create(screen, &texTemp);
+   if (!tex)
+      return;
+
+   texSurf = screen->get_tex_surface(screen, tex, 0, 0, 0,
+                                     PIPE_BUFFER_USAGE_GPU_WRITE);
+
+   /* load temp texture */
+   pipe->surface_copy(pipe,
+                      texSurf, 0, 0,   /* dest */
+                      src, srcLeft, srcTop, /* src */
+                      srcW, srcH);     /* size */
+
+   /* free the surface, update the texture if necessary.*/
+   screen->tex_surface_destroy(texSurf);
+
+   /* save state (restored below) */
+   cso_save_blend(ctx->cso);
+   cso_save_samplers(ctx->cso);
+   cso_save_sampler_textures(ctx->cso);
+   cso_save_framebuffer(ctx->cso);
+   cso_save_fragment_shader(ctx->cso);
+   cso_save_vertex_shader(ctx->cso);
+   cso_save_viewport(ctx->cso);
+
+   /* set misc state we care about */
+   {
+      struct pipe_blend_state blend;
+      memset(&blend, 0, sizeof(blend));
+      blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE;
+      blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+      blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
+      blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
+      blend.colormask = PIPE_MASK_RGBA;
+      cso_set_blend(ctx->cso, &blend);
+   }
+
+   vg_set_viewport(ctx->owner, VEGA_Y0_TOP);
+
+   /* sampler */
+   {
+      struct pipe_sampler_state sampler;
+      memset(&sampler, 0, sizeof(sampler));
+      sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+      sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+      sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+      sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
+      sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
+      sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
+      sampler.normalized_coords = 1;
+      cso_single_sampler(ctx->cso, 0, &sampler);
+      cso_single_sampler_done(ctx->cso);
+   }
+
+   /* texture */
+   cso_set_sampler_textures(ctx->cso, 1, &tex);
+
+   /* shaders */
+   cso_set_fragment_shader_handle(ctx->cso, ctx->fs);
+   cso_set_vertex_shader_handle(ctx->cso, vg_texture_vs(ctx->owner));
+
+   /* drawing dest */
+   if (stfb->strb->surface != dst) {
+      memset(&fb, 0, sizeof(fb));
+      fb.width = dst->width;
+      fb.height = dst->height;
+      fb.nr_cbufs = 1;
+      fb.cbufs[0] = dst;
+      fb.zsbuf = stfb->dsrb->surface;
+      cso_set_framebuffer(ctx->cso, &fb);
+   }
+
+   /* draw quad */
+   buf = setup_vertex_data(ctx,
+                           (float) dstX0, (float) dstY0,
+                           (float) dstX1, (float) dstY1, z);
+
+   if (buf) {
+      util_draw_vertex_buffer(ctx->pipe, buf, 0,
+                              PIPE_PRIM_TRIANGLE_FAN,
+                              4,  /* verts */
+                              2); /* attribs/vert */
+
+      pipe_buffer_reference( &buf,
+                             NULL );
+   }
+
+
+   /* restore state we changed */
+   cso_restore_blend(ctx->cso);
+   cso_restore_samplers(ctx->cso);
+   cso_restore_sampler_textures(ctx->cso);
+   cso_restore_framebuffer(ctx->cso);
+   cso_restore_fragment_shader(ctx->cso);
+   cso_restore_vertex_shader(ctx->cso);
+   cso_restore_viewport(ctx->cso);
+
+   pipe_texture_reference(&tex, NULL);
+}
+
+void renderer_texture_quad(struct renderer *r,
+                           struct pipe_texture *tex,
+                           VGfloat x1offset, VGfloat y1offset,
+                           VGfloat x2offset, VGfloat y2offset,
+                           VGfloat x1, VGfloat y1,
+                           VGfloat x2, VGfloat y2,
+                           VGfloat x3, VGfloat y3,
+                           VGfloat x4, VGfloat y4)
+{
+   struct pipe_context *pipe = r->pipe;
+   struct pipe_buffer *buf;
+   VGfloat s0, t0, s1, t1;
+
+   assert(tex->width[0] != 0);
+   assert(tex->height[0] != 0);
+
+   s0 = x1offset / tex->width[0];
+   s1 = x2offset / tex->width[0];
+   t0 = y1offset / tex->height[0];
+   t1 = y2offset / tex->height[0];
+
+   cso_save_vertex_shader(r->cso);
+   /* shaders */
+   cso_set_vertex_shader_handle(r->cso, vg_texture_vs(r->owner));
+
+   /* draw quad */
+   buf = setup_vertex_data_qtex(r, x1, y1, x2, y2, x3, y3, x4, y4,
+                          s0, t0, s1, t1, 0.0f);
+
+   if (buf) {
+      util_draw_vertex_buffer(pipe, buf, 0,
+                              PIPE_PRIM_TRIANGLE_FAN,
+                              4,  /* verts */
+                              2); /* attribs/vert */
+
+      pipe_buffer_reference(&buf,
+                            NULL);
+   }
+
+   cso_restore_vertex_shader(r->cso);
+}
diff --git a/src/gallium/state_trackers/vega/renderer.h b/src/gallium/state_trackers/vega/renderer.h
new file mode 100644 (file)
index 0000000..990cd32
--- /dev/null
@@ -0,0 +1,76 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#ifndef RENDERER_H
+#define RENDERER_H
+
+#include "VG/openvg.h"
+
+struct renderer;
+
+struct vg_context;
+struct pipe_texture;
+struct pipe_surface;
+
+struct renderer *renderer_create(struct vg_context *owner);
+void renderer_destroy(struct renderer *);
+
+void renderer_draw_quad(struct renderer *,
+                        VGfloat x1, VGfloat y1,
+                        VGfloat x2, VGfloat y2,
+                        VGfloat depth);
+void renderer_draw_texture(struct renderer *,
+                           struct pipe_texture *texture,
+                           VGfloat x1offset, VGfloat y1offset,
+                           VGfloat x2offset, VGfloat y2offset,
+                           VGfloat x1, VGfloat y1,
+                           VGfloat x2, VGfloat y2);
+void renderer_texture_quad(struct renderer *,
+                           struct pipe_texture *texture,
+                           VGfloat x1offset, VGfloat y1offset,
+                           VGfloat x2offset, VGfloat y2offset,
+                           VGfloat x1, VGfloat y1,
+                           VGfloat x2, VGfloat y2,
+                           VGfloat x3, VGfloat y3,
+                           VGfloat x4, VGfloat y4);
+void renderer_copy_texture(struct renderer *r,
+                           struct pipe_texture *src,
+                           VGfloat sx1, VGfloat sy1,
+                           VGfloat sx2, VGfloat sy2,
+                           struct pipe_texture *dst,
+                           VGfloat dx1, VGfloat dy1,
+                           VGfloat dx2, VGfloat dy2);
+void renderer_copy_surface(struct renderer *r,
+                           struct pipe_surface *src,
+                           int sx1, int sy1,
+                           int sx2, int sy2,
+                           struct pipe_surface *dst,
+                           int dx1, int dy1,
+                           int dx2, int dy2,
+                           float z, unsigned filter);
+
+
+#endif
diff --git a/src/gallium/state_trackers/vega/shader.c b/src/gallium/state_trackers/vega/shader.c
new file mode 100644 (file)
index 0000000..d9074a3
--- /dev/null
@@ -0,0 +1,310 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#include "shader.h"
+
+#include "vg_context.h"
+#include "shaders_cache.h"
+#include "paint.h"
+#include "mask.h"
+#include "image.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_screen.h"
+#include "pipe/p_state.h"
+#include "pipe/p_inlines.h"
+#include "util/u_memory.h"
+
+#define MAX_CONSTANTS 20
+
+struct shader {
+   struct vg_context *context;
+
+   VGboolean masking;
+   struct vg_paint *paint;
+   struct vg_image *image;
+
+   VGboolean drawing_image;
+   VGImageMode image_mode;
+
+   float constants[MAX_CONSTANTS];
+   struct pipe_constant_buffer cbuf;
+   struct pipe_shader_state fs_state;
+   void *fs;
+};
+
+struct shader * shader_create(struct vg_context *ctx)
+{
+   struct shader *shader = 0;
+
+   shader = CALLOC_STRUCT(shader);
+   shader->context = ctx;
+
+   return shader;
+}
+
+void shader_destroy(struct shader *shader)
+{
+   free(shader);
+}
+
+void shader_set_masking(struct shader *shader, VGboolean set)
+{
+   shader->masking = set;
+}
+
+VGboolean shader_is_masking(struct shader *shader)
+{
+   return shader->masking;
+}
+
+void shader_set_paint(struct shader *shader, struct vg_paint *paint)
+{
+   shader->paint = paint;
+}
+
+struct vg_paint * shader_paint(struct shader *shader)
+{
+   return shader->paint;
+}
+
+
+static void setup_constant_buffer(struct shader *shader)
+{
+   struct vg_context *ctx = shader->context;
+   struct pipe_context *pipe = shader->context->pipe;
+   struct pipe_constant_buffer *cbuf = &shader->cbuf;
+   VGint param_bytes = paint_constant_buffer_size(shader->paint);
+   float temp_buf[MAX_CONSTANTS];
+
+   assert(param_bytes <= sizeof(temp_buf));
+   paint_fill_constant_buffer(shader->paint, temp_buf);
+
+   if (cbuf->buffer == NULL ||
+       memcmp(temp_buf, shader->constants, param_bytes) != 0)
+   {
+      pipe_buffer_reference(&cbuf->buffer, NULL);
+
+      memcpy(shader->constants, temp_buf, param_bytes);
+      cbuf->buffer = pipe_user_buffer_create(pipe->screen,
+                                             &shader->constants,
+                                             sizeof(shader->constants));
+   }
+
+   ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_FRAGMENT, 0, cbuf);
+}
+
+static VGint blend_bind_samplers(struct vg_context *ctx,
+                                 struct pipe_sampler_state **samplers,
+                                 struct pipe_texture **textures)
+{
+   VGBlendMode bmode = ctx->state.vg.blend_mode;
+
+   if (bmode == VG_BLEND_MULTIPLY ||
+       bmode == VG_BLEND_SCREEN ||
+       bmode == VG_BLEND_DARKEN ||
+       bmode == VG_BLEND_LIGHTEN) {
+      struct st_framebuffer *stfb = ctx->draw_buffer;
+
+      vg_prepare_blend_surface(ctx);
+
+      samplers[2] = &ctx->blend_sampler;
+      textures[2] = stfb->blend_texture;
+
+      if (!samplers[0] || !textures[0]) {
+         samplers[1] = samplers[2];
+         textures[1] = textures[2];
+      }
+      if (!samplers[1] || !textures[1]) {
+         samplers[1] = samplers[0];
+         textures[1] = textures[0];
+      }
+
+      return 1;
+   }
+   return 0;
+}
+
+static void setup_samplers(struct shader *shader)
+{
+   struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
+   struct pipe_texture *textures[PIPE_MAX_SAMPLERS];
+   struct vg_context *ctx = shader->context;
+   /* a little wonky: we use the num as a boolean that just says
+    * whether any sampler/textures have been set. the actual numbering
+    * for samplers is always the same:
+    * 0 - paint sampler/texture for gradient/pattern
+    * 1 - mask sampler/texture
+    * 2 - blend sampler/texture
+    * 3 - image sampler/texture
+    * */
+   VGint num = 0;
+
+   samplers[0] = NULL;
+   samplers[1] = NULL;
+   samplers[2] = NULL;
+   samplers[3] = NULL;
+   textures[0] = NULL;
+   textures[1] = NULL;
+   textures[2] = NULL;
+   textures[3] = NULL;
+
+   num += paint_bind_samplers(shader->paint, samplers, textures);
+   num += mask_bind_samplers(samplers, textures);
+   num += blend_bind_samplers(ctx, samplers, textures);
+   if (shader->drawing_image && shader->image)
+      num += image_bind_samplers(shader->image, samplers, textures);
+
+   if (num) {
+      cso_set_samplers(ctx->cso_context, 4, (const struct pipe_sampler_state **)samplers);
+      cso_set_sampler_textures(ctx->cso_context, 4, textures);
+   }
+}
+
+static INLINE VGboolean is_format_bw(struct shader *shader)
+{
+#if 0
+   struct vg_context *ctx = shader->context;
+   struct st_framebuffer *stfb = ctx->draw_buffer;
+#endif
+
+   if (shader->drawing_image && shader->image) {
+      if (shader->image->format == VG_BW_1)
+         return VG_TRUE;
+   }
+
+   return VG_FALSE;
+}
+
+static void setup_shader_program(struct shader *shader)
+{
+   struct vg_context *ctx = shader->context;
+   VGint shader_id = 0;
+   VGBlendMode blend_mode = ctx->state.vg.blend_mode;
+   VGboolean black_white = is_format_bw(shader);
+
+   /* 1st stage: fill */
+   if (!shader->drawing_image ||
+       (shader->image_mode == VG_DRAW_IMAGE_MULTIPLY || shader->image_mode == VG_DRAW_IMAGE_STENCIL)) {
+      switch(paint_type(shader->paint)) {
+      case VG_PAINT_TYPE_COLOR:
+         shader_id |= VEGA_SOLID_FILL_SHADER;
+         break;
+      case VG_PAINT_TYPE_LINEAR_GRADIENT:
+         shader_id |= VEGA_LINEAR_GRADIENT_SHADER;
+         break;
+      case VG_PAINT_TYPE_RADIAL_GRADIENT:
+         shader_id |= VEGA_RADIAL_GRADIENT_SHADER;
+         break;
+      case VG_PAINT_TYPE_PATTERN:
+         shader_id |= VEGA_PATTERN_SHADER;
+         break;
+
+      default:
+         abort();
+      }
+   }
+
+   /* second stage image */
+   if (shader->drawing_image) {
+      switch(shader->image_mode) {
+      case VG_DRAW_IMAGE_NORMAL:
+         shader_id |= VEGA_IMAGE_NORMAL_SHADER;
+         break;
+      case VG_DRAW_IMAGE_MULTIPLY:
+         shader_id |= VEGA_IMAGE_MULTIPLY_SHADER;
+         break;
+      case VG_DRAW_IMAGE_STENCIL:
+         shader_id |= VEGA_IMAGE_STENCIL_SHADER;
+         break;
+      default:
+         debug_printf("Unknown image mode!");
+      }
+   }
+
+   if (shader->masking)
+      shader_id |= VEGA_MASK_SHADER;
+
+   switch(blend_mode) {
+   case VG_BLEND_MULTIPLY:
+      shader_id |= VEGA_BLEND_MULTIPLY_SHADER;
+      break;
+   case VG_BLEND_SCREEN:
+      shader_id |= VEGA_BLEND_SCREEN_SHADER;
+      break;
+   case VG_BLEND_DARKEN:
+      shader_id |= VEGA_BLEND_DARKEN_SHADER;
+      break;
+   case VG_BLEND_LIGHTEN:
+      shader_id |= VEGA_BLEND_LIGHTEN_SHADER;
+      break;
+   default:
+      /* handled by pipe_blend_state */
+      break;
+   }
+
+   if (black_white)
+      shader_id |= VEGA_BW_SHADER;
+
+   shader->fs = shaders_cache_fill(ctx->sc, shader_id);
+   cso_set_fragment_shader_handle(ctx->cso_context, shader->fs);
+}
+
+
+void shader_bind(struct shader *shader)
+{
+   /* first resolve the real paint type */
+   paint_resolve_type(shader->paint);
+
+   setup_constant_buffer(shader);
+   setup_samplers(shader);
+   setup_shader_program(shader);
+}
+
+void shader_set_image_mode(struct shader *shader, VGImageMode image_mode)
+{
+   shader->image_mode = image_mode;
+}
+
+VGImageMode shader_image_mode(struct shader *shader)
+{
+   return shader->image_mode;
+}
+
+void shader_set_drawing_image(struct shader *shader, VGboolean drawing_image)
+{
+   shader->drawing_image = drawing_image;
+}
+
+VGboolean shader_drawing_image(struct shader *shader)
+{
+   return shader->drawing_image;
+}
+
+void shader_set_image(struct shader *shader, struct vg_image *img)
+{
+   shader->image = img;
+}
diff --git a/src/gallium/state_trackers/vega/shader.h b/src/gallium/state_trackers/vega/shader.h
new file mode 100644 (file)
index 0000000..847eee6
--- /dev/null
@@ -0,0 +1,56 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#ifndef SHADER_H
+#define SHADER_H
+
+#include "VG/openvg.h"
+
+struct shader;
+struct vg_paint;
+struct vg_context;
+struct vg_image;
+
+struct shader *shader_create(struct vg_context *context);
+void shader_destroy(struct shader *shader);
+
+void shader_set_masking(struct shader *shader, VGboolean set);
+VGboolean shader_is_masking(struct shader *shader);
+
+void shader_set_paint(struct shader *shader, struct vg_paint *paint);
+struct vg_paint *shader_paint(struct shader *shader);
+
+void shader_set_image_mode(struct shader *shader, VGImageMode image_mode);
+VGImageMode shader_image_mode(struct shader *shader);
+
+void shader_set_drawing_image(struct shader *shader, VGboolean drawing_image);
+VGboolean shader_drawing_image(struct shader *shader);
+
+void shader_set_image(struct shader *shader, struct vg_image *img);
+
+void shader_bind(struct shader *shader);
+
+#endif
diff --git a/src/gallium/state_trackers/vega/shaders_cache.c b/src/gallium/state_trackers/vega/shaders_cache.c
new file mode 100644 (file)
index 0000000..fd0831f
--- /dev/null
@@ -0,0 +1,439 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#include "shaders_cache.h"
+
+#include "vg_context.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_defines.h"
+#include "pipe/p_inlines.h"
+#include "pipe/p_screen.h"
+#include "pipe/p_shader_tokens.h"
+
+#include "tgsi/tgsi_build.h"
+#include "tgsi/tgsi_dump.h"
+#include "tgsi/tgsi_parse.h"
+#include "tgsi/tgsi_util.h"
+#include "tgsi/tgsi_text.h"
+
+#include "util/u_memory.h"
+#include "util/u_math.h"
+#include "util/u_debug.h"
+#include "cso_cache/cso_hash.h"
+#include "cso_cache/cso_context.h"
+
+#include "VG/openvg.h"
+
+#include "asm_fill.h"
+
+/* Essentially we construct an ubber-shader based on the state
+ * of the pipeline. The stages are:
+ * 1) Fill (mandatory, solid color/gradient/pattern/image draw)
+ * 2) Image composition (image mode multiply and stencil)
+ * 3) Mask
+ * 4) Extended blend (multiply/screen/darken/lighten)
+ * 5) Premultiply/Unpremultiply
+ * 6) Color transform (to black and white)
+ */
+#define SHADER_STAGES 6
+
+struct cached_shader {
+   void *driver_shader;
+   struct pipe_shader_state state;
+};
+
+struct shaders_cache {
+   struct vg_context *pipe;
+
+   struct cso_hash *hash;
+};
+
+
+static INLINE struct tgsi_token *tokens_from_assembly(const char *txt, int num_tokens)
+{
+   struct tgsi_token *tokens;
+
+   tokens = (struct tgsi_token *) MALLOC(num_tokens * sizeof(tokens[0]));
+
+   tgsi_text_translate(txt, tokens, num_tokens);
+
+#if DEBUG_SHADERS
+   tgsi_dump(tokens, 0);
+#endif
+
+   return tokens;
+}
+
+#define ALL_FILLS (VEGA_SOLID_FILL_SHADER | \
+   VEGA_LINEAR_GRADIENT_SHADER | \
+   VEGA_RADIAL_GRADIENT_SHADER | \
+   VEGA_PATTERN_SHADER         | \
+   VEGA_IMAGE_NORMAL_SHADER)
+
+
+/*
+static const char max_shader_preamble[] =
+   "FRAG1.1\n"
+   "DCL IN[0], POSITION, LINEAR\n"
+   "DCL IN[1], GENERIC[0], PERSPECTIVE\n"
+   "DCL OUT[0], COLOR, CONSTANT\n"
+   "DCL CONST[0..9], CONSTANT\n"
+   "DCL TEMP[0..9], CONSTANT\n"
+   "DCL SAMP[0..9], CONSTANT\n";
+
+   max_shader_preamble strlen == 175
+*/
+#define MAX_PREAMBLE 175
+
+static INLINE VGint range_min(VGint min, VGint current)
+{
+   if (min < 0)
+      min = current;
+   else
+      min = MIN2(min, current);
+   return min;
+}
+
+static INLINE VGint range_max(VGint max, VGint current)
+{
+   return MAX2(max, current);
+}
+
+static void
+create_preamble(char *txt,
+                const struct shader_asm_info *shaders[SHADER_STAGES],
+                int num_shaders)
+{
+   VGboolean declare_input = VG_FALSE;
+   VGint start_const   = -1, end_const   = 0;
+   VGint start_temp    = -1, end_temp    = 0;
+   VGint start_sampler = -1, end_sampler = 0;
+   VGint i;
+   VGint num_consts, num_temps, num_samplers;
+
+   for (i = 0; i < num_shaders; ++i) {
+      if (shaders[i]->num_consts)
+         start_const = range_min(start_const, shaders[i]->start_const);
+      if (shaders[i]->num_temps)
+         start_temp = range_min(start_temp, shaders[i]->start_temp);
+      if (shaders[i]->num_samplers)
+         start_sampler = range_min(start_sampler, shaders[i]->start_sampler);
+
+      end_const = range_max(end_const, shaders[i]->start_const +
+                            shaders[i]->num_consts);
+      end_temp = range_max(end_temp, shaders[i]->start_temp +
+                            shaders[i]->num_temps);
+      end_sampler = range_max(end_sampler, shaders[i]->start_sampler +
+                            shaders[i]->num_samplers);
+      if (shaders[i]->needs_position)
+         declare_input = VG_TRUE;
+   }
+   /* if they're still unitialized, initialize them */
+   if (start_const < 0)
+      start_const = 0;
+   if (start_temp < 0)
+      start_temp = 0;
+   if (start_sampler < 0)
+      start_sampler = 0;
+
+   num_consts   = end_const   - start_const;
+   num_temps    = end_temp    - start_temp;
+   num_samplers = end_sampler - start_sampler;
+   /* end exclusive */
+   --end_const;
+   --end_temp;
+   --end_sampler;
+
+   sprintf(txt, "FRAG1.1\n");
+
+   if (declare_input) {
+      sprintf(txt + strlen(txt), "DCL IN[0], POSITION, LINEAR\n");
+      sprintf(txt + strlen(txt), "DCL IN[1], GENERIC[0], PERSPECTIVE\n");
+   }
+
+   /* we always have a color output */
+   sprintf(txt + strlen(txt), "DCL OUT[0], COLOR, CONSTANT\n");
+
+   if (num_consts > 1)
+      sprintf(txt + strlen(txt), "DCL CONST[%d..%d], CONSTANT\n", start_const, end_const);
+   else if (num_consts == 1)
+      sprintf(txt + strlen(txt), "DCL CONST[%d], CONSTANT\n", start_const);
+
+   if (num_temps > 1)
+      sprintf(txt + strlen(txt), "DCL TEMP[%d..%d], CONSTANT\n", start_temp, end_temp);
+   else if (num_temps > 1)
+      sprintf(txt + strlen(txt), "DCL TEMP[%d], CONSTANT\n", start_temp);
+
+   if (num_samplers > 1)
+      sprintf(txt + strlen(txt), "DCL SAMP[%d..%d], CONSTANT\n", start_sampler, end_sampler);
+   else if (num_samplers == 1)
+      sprintf(txt + strlen(txt), "DCL SAMP[%d], CONSTANT\n", start_sampler);
+}
+
+static void *
+combine_shaders(const struct shader_asm_info *shaders[SHADER_STAGES], int num_shaders,
+                struct pipe_context *pipe,
+                struct pipe_shader_state *shader)
+{
+   char *combined_txt;
+   int combined_len = MAX_PREAMBLE;
+   int combined_tokens = 0;
+   int i = 0;
+   int current_shader = 0;
+   int current_len;
+
+   for (i = 0; i < num_shaders; ++i) {
+      combined_len += strlen(shaders[i]->txt);
+      combined_tokens += shaders[i]->num_tokens;
+   }
+   /* add for the %s->TEMP[0] substitutions */
+   combined_len += num_shaders * 7 /*TEMP[0]*/ + 4 /*"END\n"*/;
+
+   combined_txt = (char*)malloc(combined_len);
+   combined_txt[0] = '\0';
+
+   create_preamble(combined_txt, shaders, num_shaders);
+
+   while (current_shader < num_shaders) {
+      const char temp[] = "TEMP[0]";
+      const char out[] = "OUT[0]";
+      const char *subst = temp;
+
+      current_len = strlen(combined_txt);
+
+      /* if the last shader then output */
+      if (current_shader + 1 == num_shaders)
+         subst = out;
+
+      snprintf(combined_txt + current_len,
+               combined_len - current_len,
+               shaders[current_shader]->txt,
+               subst);
+      ++current_shader;
+   }
+
+
+   current_len = strlen(combined_txt);
+   snprintf(combined_txt + current_len,
+            combined_len - current_len,
+            "END\n");
+
+   debug_printf("Combined shader is : \n%s\n",
+                 combined_txt);
+
+   shader->tokens = tokens_from_assembly(
+            combined_txt, combined_tokens);
+
+   free(combined_txt);
+
+   return pipe->create_fs_state(pipe, shader);
+}
+
+static void *
+create_shader(struct pipe_context *pipe,
+              int id,
+              struct pipe_shader_state *shader)
+{
+   int idx = 0;
+   const struct shader_asm_info * shaders[SHADER_STAGES];
+
+   /* the shader has to have a fill */
+   debug_assert(id & ALL_FILLS);
+
+   /* first stage */
+   if (id & VEGA_SOLID_FILL_SHADER) {
+      debug_assert(idx == 0);
+      shaders[idx] = &shaders_asm[0];
+      debug_assert(shaders_asm[0].id == VEGA_SOLID_FILL_SHADER);
+      ++idx;
+   }
+   if ((id & VEGA_LINEAR_GRADIENT_SHADER)) {
+      debug_assert(idx == 0);
+      shaders[idx] = &shaders_asm[1];
+      debug_assert(shaders_asm[1].id == VEGA_LINEAR_GRADIENT_SHADER);
+      ++idx;
+   }
+   if ((id & VEGA_RADIAL_GRADIENT_SHADER)) {
+      debug_assert(idx == 0);
+      shaders[idx] = &shaders_asm[2];
+      debug_assert(shaders_asm[2].id == VEGA_RADIAL_GRADIENT_SHADER);
+      ++idx;
+   }
+   if ((id & VEGA_PATTERN_SHADER)) {
+      debug_assert(idx == 0);
+      debug_assert(shaders_asm[3].id == VEGA_PATTERN_SHADER);
+      shaders[idx] = &shaders_asm[3];
+      ++idx;
+   }
+   if ((id & VEGA_IMAGE_NORMAL_SHADER)) {
+      debug_assert(idx == 0);
+      debug_assert(shaders_asm[4].id == VEGA_IMAGE_NORMAL_SHADER);
+      shaders[idx] = &shaders_asm[4];
+      ++idx;
+   }
+
+   /* second stage */
+   if ((id & VEGA_IMAGE_MULTIPLY_SHADER)) {
+      debug_assert(shaders_asm[5].id == VEGA_IMAGE_MULTIPLY_SHADER);
+      shaders[idx] = &shaders_asm[5];
+      ++idx;
+   } else if ((id & VEGA_IMAGE_STENCIL_SHADER)) {
+      debug_assert(shaders_asm[6].id == VEGA_IMAGE_STENCIL_SHADER);
+      shaders[idx] = &shaders_asm[6];
+      ++idx;
+   }
+
+   /* third stage */
+   if ((id & VEGA_MASK_SHADER)) {
+      debug_assert(idx == 1);
+      debug_assert(shaders_asm[7].id == VEGA_MASK_SHADER);
+      shaders[idx] = &shaders_asm[7];
+      ++idx;
+   }
+
+   /* fourth stage */
+   if ((id & VEGA_BLEND_MULTIPLY_SHADER)) {
+      debug_assert(shaders_asm[8].id == VEGA_BLEND_MULTIPLY_SHADER);
+      shaders[idx] = &shaders_asm[8];
+      ++idx;
+   } else if ((id & VEGA_BLEND_SCREEN_SHADER)) {
+      debug_assert(shaders_asm[9].id == VEGA_BLEND_SCREEN_SHADER);
+      shaders[idx] = &shaders_asm[9];
+      ++idx;
+   } else if ((id & VEGA_BLEND_DARKEN_SHADER)) {
+      debug_assert(shaders_asm[10].id == VEGA_BLEND_DARKEN_SHADER);
+      shaders[idx] = &shaders_asm[10];
+      ++idx;
+   } else if ((id & VEGA_BLEND_LIGHTEN_SHADER)) {
+      debug_assert(shaders_asm[11].id == VEGA_BLEND_LIGHTEN_SHADER);
+      shaders[idx] = &shaders_asm[11];
+      ++idx;
+   }
+
+   /* fifth stage */
+   if ((id & VEGA_PREMULTIPLY_SHADER)) {
+      debug_assert(shaders_asm[12].id == VEGA_PREMULTIPLY_SHADER);
+      shaders[idx] = &shaders_asm[12];
+      ++idx;
+   } else if ((id & VEGA_UNPREMULTIPLY_SHADER)) {
+      debug_assert(shaders_asm[13].id == VEGA_UNPREMULTIPLY_SHADER);
+      shaders[idx] = &shaders_asm[13];
+      ++idx;
+   }
+
+   /* sixth stage */
+   if ((id & VEGA_BW_SHADER)) {
+      debug_assert(shaders_asm[14].id == VEGA_BW_SHADER);
+      shaders[idx] = &shaders_asm[14];
+      ++idx;
+   }
+
+   return combine_shaders(shaders, idx, pipe, shader);
+}
+
+/*************************************************/
+
+struct shaders_cache * shaders_cache_create(struct vg_context *vg)
+{
+   struct shaders_cache *sc = CALLOC_STRUCT(shaders_cache);
+
+   sc->pipe = vg;
+   sc->hash = cso_hash_create();
+
+   return sc;
+}
+
+void shaders_cache_destroy(struct shaders_cache *sc)
+{
+   struct cso_hash_iter iter = cso_hash_first_node(sc->hash);
+
+   while (!cso_hash_iter_is_null(iter)) {
+      struct cached_shader *cached =
+         (struct cached_shader *)cso_hash_iter_data(iter);
+      cso_delete_fragment_shader(sc->pipe->cso_context,
+                                 cached->driver_shader);
+      iter = cso_hash_erase(sc->hash, iter);
+   }
+
+   cso_hash_delete(sc->hash);
+   free(sc);
+}
+
+void * shaders_cache_fill(struct shaders_cache *sc,
+                          int shader_key)
+{
+   VGint key = shader_key;
+   struct cached_shader *cached;
+   struct cso_hash_iter iter = cso_hash_find(sc->hash, key);
+
+   if (cso_hash_iter_is_null(iter)) {
+      cached = CALLOC_STRUCT(cached_shader);
+      cached->driver_shader = create_shader(sc->pipe->pipe, key, &cached->state);
+
+      cso_hash_insert(sc->hash, key, cached);
+
+      return cached->driver_shader;
+   }
+
+   cached = (struct cached_shader *)cso_hash_iter_data(iter);
+
+   assert(cached->driver_shader);
+   return cached->driver_shader;
+}
+
+struct vg_shader * shader_create_from_text(struct pipe_context *pipe,
+                                           const char *txt, int num_tokens,
+                                           int type)
+{
+   struct vg_shader *shader = (struct vg_shader *)malloc(
+      sizeof(struct vg_shader));
+   struct tgsi_token *tokens = tokens_from_assembly(txt, num_tokens);
+   struct pipe_shader_state state;
+
+   debug_assert(type == PIPE_SHADER_VERTEX ||
+                type == PIPE_SHADER_FRAGMENT);
+
+   state.tokens = tokens;
+   shader->type = type;
+   shader->tokens = tokens;
+
+   if (type == PIPE_SHADER_FRAGMENT)
+      shader->driver = pipe->create_fs_state(pipe, &state);
+   else
+      shader->driver = pipe->create_vs_state(pipe, &state);
+   return shader;
+}
+
+void vg_shader_destroy(struct vg_context *ctx, struct vg_shader *shader)
+{
+   if (shader->type == PIPE_SHADER_FRAGMENT)
+      cso_delete_fragment_shader(ctx->cso_context, shader->driver);
+   else
+      cso_delete_vertex_shader(ctx->cso_context, shader->driver);
+   free(shader->tokens);
+   free(shader);
+}
diff --git a/src/gallium/state_trackers/vega/shaders_cache.h b/src/gallium/state_trackers/vega/shaders_cache.h
new file mode 100644 (file)
index 0000000..feca58b
--- /dev/null
@@ -0,0 +1,77 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#ifndef SHADERS_CACHE_H
+#define SHADERS_CACHE_H
+
+
+struct vg_context;
+struct pipe_context;
+struct tgsi_token;
+struct shaders_cache;
+
+enum VegaShaderType {
+   VEGA_SOLID_FILL_SHADER         = 1 <<  0,
+   VEGA_LINEAR_GRADIENT_SHADER    = 1 <<  1,
+   VEGA_RADIAL_GRADIENT_SHADER    = 1 <<  2,
+   VEGA_PATTERN_SHADER            = 1 <<  3,
+   VEGA_IMAGE_NORMAL_SHADER       = 1 <<  4,
+   VEGA_IMAGE_MULTIPLY_SHADER     = 1 <<  5,
+   VEGA_IMAGE_STENCIL_SHADER      = 1 <<  6,
+
+   VEGA_MASK_SHADER               = 1 <<  7,
+
+   VEGA_BLEND_MULTIPLY_SHADER     = 1 <<  8,
+   VEGA_BLEND_SCREEN_SHADER       = 1 <<  9,
+   VEGA_BLEND_DARKEN_SHADER       = 1 << 10,
+   VEGA_BLEND_LIGHTEN_SHADER      = 1 << 11,
+
+   VEGA_PREMULTIPLY_SHADER        = 1 << 12,
+   VEGA_UNPREMULTIPLY_SHADER      = 1 << 13,
+
+   VEGA_BW_SHADER                 = 1 << 14
+};
+
+struct vg_shader {
+   void *driver;
+   struct tgsi_token *tokens;
+   int type;/* PIPE_SHADER_VERTEX, PIPE_SHADER_FRAGMENT */
+};
+
+struct shaders_cache *shaders_cache_create(struct vg_context *pipe);
+void shaders_cache_destroy(struct shaders_cache *sc);
+void *shaders_cache_fill(struct shaders_cache *sc,
+                         int shader_key);
+
+struct vg_shader *shader_create_from_text(struct pipe_context *pipe,
+                                          const char *txt, int num_tokens,
+                                          int type);
+
+void vg_shader_destroy(struct vg_context *ctx, struct vg_shader *shader);
+
+
+
+#endif
diff --git a/src/gallium/state_trackers/vega/st_inlines.h b/src/gallium/state_trackers/vega/st_inlines.h
new file mode 100644 (file)
index 0000000..1f331df
--- /dev/null
@@ -0,0 +1,159 @@
+/**************************************************************************
+ * 
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ * 
+ **************************************************************************/
+
+/**
+ * Functions for checking if buffers/textures are referenced when we need
+ * to read/write from/to them.  Flush when needed.
+ */
+
+#ifndef ST_INLINES_H
+#define ST_INLINES_H
+
+#include "vg_context.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_screen.h"
+#include "pipe/p_defines.h"
+#include "pipe/p_inlines.h"
+#include "pipe/p_state.h"
+
+static INLINE struct pipe_transfer *
+st_cond_flush_get_tex_transfer(struct vg_context *st,
+                              struct pipe_texture *pt,
+                              unsigned int face,
+                              unsigned int level,
+                              unsigned int zslice,
+                              enum pipe_transfer_usage usage,
+                              unsigned int x, unsigned int y,
+                              unsigned int w, unsigned int h)
+{
+   struct pipe_screen *screen = st->pipe->screen;
+   struct pipe_context *pipe = st->pipe;
+   unsigned referenced =
+      pipe->is_texture_referenced(pipe, pt, face, level);
+
+   if (referenced && ((referenced & PIPE_REFERENCED_FOR_WRITE) ||
+                     usage == PIPE_TRANSFER_WRITE ||
+                     usage == PIPE_TRANSFER_READ_WRITE))
+      vgFlush();
+
+   return screen->get_tex_transfer(screen, pt, face, level, zslice, usage,
+                                  x, y, w, h);
+}
+
+static INLINE struct pipe_transfer *
+st_no_flush_get_tex_transfer(struct vg_context *st,
+                            struct pipe_texture *pt,
+                            unsigned int face,
+                            unsigned int level,
+                            unsigned int zslice,
+                            enum pipe_transfer_usage usage,
+                            unsigned int x, unsigned int y,
+                            unsigned int w, unsigned int h)
+{
+   struct pipe_screen *screen = st->pipe->screen;
+
+   return screen->get_tex_transfer(screen, pt, face, level,
+                                  zslice, usage, x, y, w, h);
+}
+
+static INLINE void *
+st_cond_flush_pipe_buffer_map(struct vg_context *st,
+                             struct pipe_buffer *buf,
+                             unsigned int map_flags)
+{
+   struct pipe_context *pipe = st->pipe;
+   unsigned int referenced = pipe->is_buffer_referenced(pipe, buf);
+
+   if (referenced && ((referenced & PIPE_REFERENCED_FOR_WRITE) ||
+                     (map_flags & PIPE_BUFFER_USAGE_CPU_WRITE)))
+      vgFlush();
+
+   return pipe_buffer_map(pipe->screen, buf, map_flags);
+}
+
+static INLINE void *
+st_no_flush_pipe_buffer_map(struct vg_context *st,
+                           struct pipe_buffer *buf,
+                           unsigned int map_flags)
+{
+   return pipe_buffer_map(st->pipe->screen, buf, map_flags);
+}
+
+
+static INLINE void
+st_cond_flush_pipe_buffer_write(struct vg_context *st,
+                               struct pipe_buffer *buf,
+                               unsigned int offset,
+                               unsigned int size,
+                               const void * data)
+{
+   struct pipe_context *pipe = st->pipe;
+
+   if (pipe->is_buffer_referenced(pipe, buf))
+      vgFlush();
+
+   pipe_buffer_write(pipe->screen, buf, offset, size, data);
+}
+
+static INLINE void
+st_no_flush_pipe_buffer_write(struct vg_context *st,
+                             struct pipe_buffer *buf,
+                             unsigned int offset,
+                             unsigned int size,
+                             const void * data)
+{
+   pipe_buffer_write(st->pipe->screen, buf, offset, size, data);
+}
+
+static INLINE void
+st_cond_flush_pipe_buffer_read(struct vg_context *st,
+                              struct pipe_buffer *buf,
+                              unsigned int offset,
+                              unsigned int size,
+                              void * data)
+{
+   struct pipe_context *pipe = st->pipe;
+
+   if (pipe->is_buffer_referenced(pipe, buf) & PIPE_REFERENCED_FOR_WRITE)
+      vgFlush();
+
+   pipe_buffer_read(pipe->screen, buf, offset, size, data);
+}
+
+static INLINE void
+st_no_flush_pipe_buffer_read(struct vg_context *st,
+                            struct pipe_buffer *buf,
+                            unsigned int offset,
+                            unsigned int size,
+                            void * data)
+{
+   pipe_buffer_read(st->pipe->screen, buf, offset, size, data);
+}
+
+#endif
+
diff --git a/src/gallium/state_trackers/vega/stroker.c b/src/gallium/state_trackers/vega/stroker.c
new file mode 100644 (file)
index 0000000..1b92d2b
--- /dev/null
@@ -0,0 +1,1349 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#include "stroker.h"
+
+#include "path.h"
+#include "vg_state.h"
+#include "util_array.h"
+#include "arc.h"
+#include "bezier.h"
+#include "matrix.h"
+#include "path_utils.h"
+#include "polygon.h"
+
+#include "math.h"
+
+#ifndef M_2PI
+#define M_2PI 6.28318530717958647692528676655900576
+#endif
+
+#define STROKE_SEGMENTS 0
+#define STROKE_DEBUG 0
+#define DEBUG_EMITS 0
+
+static const VGfloat curve_threshold = 0.25f;
+
+static const VGfloat zero_coords[] = {0.f, 0.f};
+
+enum intersection_type {
+   NoIntersections,
+   BoundedIntersection,
+   UnboundedIntersection,
+};
+
+enum line_join_mode {
+   FlatJoin,
+   SquareJoin,
+   MiterJoin,
+   RoundJoin,
+   RoundCap
+};
+
+struct stroke_iterator {
+   void (*next)(struct stroke_iterator *);
+   VGboolean (*has_next)(struct stroke_iterator *);
+
+   VGPathCommand (*current_command)(struct stroke_iterator *it);
+   void (*current_coords)(struct stroke_iterator *it, VGfloat *coords);
+
+   VGint position;
+   VGint coord_position;
+
+   const VGubyte *cmds;
+   const VGfloat *coords;
+   VGint num_commands;
+   VGint num_coords;
+
+   struct polygon *curve_poly;
+   VGint curve_index;
+};
+
+static VGPathCommand stroke_itr_command(struct stroke_iterator *itr)
+{
+   return itr->current_command(itr);
+}
+
+static void stroke_itr_coords(struct stroke_iterator *itr, VGfloat *coords)
+{
+   itr->current_coords(itr, coords);
+}
+
+static void stroke_fw_itr_coords(struct stroke_iterator *itr, VGfloat *coords)
+{
+   if (itr->position >= itr->num_commands)
+      return;
+   switch (stroke_itr_command(itr)) {
+   case VG_MOVE_TO_ABS:
+      coords[0] = itr->coords[itr->coord_position];
+      coords[1] = itr->coords[itr->coord_position + 1];
+      break;
+   case VG_LINE_TO_ABS:
+      coords[0] = itr->coords[itr->coord_position];
+      coords[1] = itr->coords[itr->coord_position + 1];
+      break;
+   case VG_CUBIC_TO_ABS:
+      coords[0] = itr->coords[itr->coord_position];
+      coords[1] = itr->coords[itr->coord_position + 1];
+      coords[2] = itr->coords[itr->coord_position + 2];
+      coords[3] = itr->coords[itr->coord_position + 3];
+      coords[4] = itr->coords[itr->coord_position + 4];
+      coords[5] = itr->coords[itr->coord_position + 5];
+      break;
+   default:
+      debug_assert(!"invalid command!\n");
+   }
+}
+
+
+static void stroke_bw_itr_coords(struct stroke_iterator *itr, VGfloat *coords)
+{
+   if (itr->position >= itr->num_commands)
+      return;
+   switch (stroke_itr_command(itr)) {
+   case VG_MOVE_TO_ABS:
+      coords[0] = itr->coords[itr->coord_position];
+      coords[1] = itr->coords[itr->coord_position + 1];
+      break;
+   case VG_LINE_TO_ABS:
+      coords[0] = itr->coords[itr->coord_position];
+      coords[1] = itr->coords[itr->coord_position + 1];
+      break;
+   case VG_CUBIC_TO_ABS:
+      coords[0] = itr->coords[itr->coord_position + 4];
+      coords[1] = itr->coords[itr->coord_position + 5];
+      coords[2] = itr->coords[itr->coord_position + 2];
+      coords[3] = itr->coords[itr->coord_position + 3];
+      coords[4] = itr->coords[itr->coord_position + 0];
+      coords[5] = itr->coords[itr->coord_position + 1];
+      break;
+   default:
+      debug_assert(!"invalid command!\n");
+   }
+}
+
+
+static VGPathCommand stroke_fw_current_command(struct stroke_iterator *it)
+{
+   return it->cmds[it->position];
+}
+
+static VGPathCommand stroke_bw_current_command(struct stroke_iterator *it)
+{
+   VGPathCommand prev_cmd;
+   if (it->position == it->num_commands  -1)
+      return VG_MOVE_TO_ABS;
+
+   prev_cmd = it->cmds[it->position + 1];
+   return prev_cmd;
+}
+
+static VGboolean stroke_fw_has_next(struct stroke_iterator *itr)
+{
+   return itr->position < (itr->num_commands - 1);
+}
+
+static VGboolean stroke_bw_has_next(struct stroke_iterator *itr)
+{
+   return itr->position > 0;
+}
+
+static void stroke_fw_next(struct stroke_iterator *itr)
+{
+   VGubyte cmd;
+   debug_assert(stroke_fw_has_next(itr));
+
+   cmd = stroke_itr_command(itr);
+
+   itr->coord_position += num_elements_for_segments(&cmd, 1);
+   ++itr->position;
+}
+
+static void stroke_bw_next(struct stroke_iterator *itr)
+{
+   VGubyte cmd;
+   debug_assert(stroke_bw_has_next(itr));
+
+   --itr->position;
+   cmd = stroke_itr_command(itr);
+
+   itr->coord_position -= num_elements_for_segments(&cmd, 1);
+}
+
+static void stroke_itr_common_init(struct stroke_iterator *itr,
+                                   struct array *cmds,
+                                   struct array *coords)
+{
+   itr->cmds = (VGubyte*)cmds->data;
+   itr->num_commands = cmds->num_elements;
+
+   itr->coords = (VGfloat*)coords->data;
+   itr->num_coords = coords->num_elements;
+}
+
+static void stroke_forward_iterator(struct stroke_iterator *itr,
+                                    struct array *cmds,
+                                    struct array *coords)
+{
+   stroke_itr_common_init(itr, cmds, coords);
+   itr->position = 0;
+   itr->coord_position = 0;
+
+   itr->next = stroke_fw_next;
+   itr->has_next = stroke_fw_has_next;
+   itr->current_command = stroke_fw_current_command;
+   itr->current_coords = stroke_fw_itr_coords;
+}
+
+static void stroke_backward_iterator(struct stroke_iterator *itr,
+                                     struct array *cmds,
+                                     struct array *coords)
+{
+   VGubyte cmd;
+   stroke_itr_common_init(itr, cmds, coords);
+   itr->position = itr->num_commands - 1;
+
+   cmd = stroke_bw_current_command(itr);
+   itr->coord_position = itr->num_coords -
+                         num_elements_for_segments(&cmd, 1);
+
+   itr->next = stroke_bw_next;
+   itr->has_next = stroke_bw_has_next;
+   itr->current_command = stroke_bw_current_command;
+   itr->current_coords = stroke_bw_itr_coords;
+}
+
+
+
+static void stroke_flat_next(struct stroke_iterator *itr)
+{
+   VGubyte cmd;
+
+   if (itr->curve_index >= 0) {
+      ++itr->curve_index;
+      if (itr->curve_index >= polygon_vertex_count(itr->curve_poly)) {
+         itr->curve_index = -1;
+         polygon_destroy(itr->curve_poly);
+         itr->curve_poly = 0;
+      } else
+         return;
+   }
+   debug_assert(stroke_fw_has_next(itr));
+
+   cmd = itr->cmds[itr->position];
+   itr->coord_position += num_elements_for_segments(&cmd, 1);
+   ++itr->position;
+
+   cmd = itr->cmds[itr->position];
+
+   if (cmd == VG_CUBIC_TO_ABS) {
+      struct bezier bezier;
+      VGfloat bez[8];
+
+      bez[0] = itr->coords[itr->coord_position - 2];
+      bez[1] = itr->coords[itr->coord_position - 1];
+      bez[2] = itr->coords[itr->coord_position];
+      bez[3] = itr->coords[itr->coord_position + 1];
+      bez[4] = itr->coords[itr->coord_position + 2];
+      bez[5] = itr->coords[itr->coord_position + 3];
+      bez[6] = itr->coords[itr->coord_position + 4];
+      bez[7] = itr->coords[itr->coord_position + 5];
+
+      bezier_init(&bezier,
+                  bez[0], bez[1],
+                  bez[2], bez[3],
+                  bez[4], bez[5],
+                  bez[6], bez[7]);
+      /* skip the first one, it's the same as the prev point */
+      itr->curve_index = 1;
+      if (itr->curve_poly) {
+         polygon_destroy(itr->curve_poly);
+         itr->curve_poly = 0;
+      }
+      itr->curve_poly = bezier_to_polygon(&bezier);
+   }
+}
+
+static VGboolean stroke_flat_has_next(struct stroke_iterator *itr)
+{
+   return  (itr->curve_index >= 0 &&
+            itr->curve_index < (polygon_vertex_count(itr->curve_poly)-1))
+            || itr->position < (itr->num_commands - 1);
+}
+
+static VGPathCommand stroke_flat_current_command(struct stroke_iterator *it)
+{
+   if (it->cmds[it->position] == VG_CUBIC_TO_ABS) {
+      return VG_LINE_TO_ABS;
+   }
+   return it->cmds[it->position];
+}
+
+static void stroke_flat_itr_coords(struct stroke_iterator *itr, VGfloat *coords)
+{
+   if (itr->curve_index <= -1 && itr->position >= itr->num_commands)
+      return;
+
+   if (itr->curve_index >= 0) {
+      polygon_vertex(itr->curve_poly, itr->curve_index,
+                     coords);
+      return;
+   }
+
+   switch (stroke_itr_command(itr)) {
+   case VG_MOVE_TO_ABS:
+      coords[0] = itr->coords[itr->coord_position];
+      coords[1] = itr->coords[itr->coord_position + 1];
+      break;
+   case VG_LINE_TO_ABS:
+      coords[0] = itr->coords[itr->coord_position];
+      coords[1] = itr->coords[itr->coord_position + 1];
+      break;
+   case VG_CUBIC_TO_ABS:
+   default:
+      debug_assert(!"invalid command!\n");
+   }
+}
+
+static void stroke_flat_iterator(struct stroke_iterator *itr,
+                                 struct array *cmds,
+                                 struct array *coords)
+{
+   stroke_itr_common_init(itr, cmds, coords);
+   itr->position = 0;
+   itr->coord_position = 0;
+
+   itr->next = stroke_flat_next;
+   itr->has_next = stroke_flat_has_next;
+   itr->current_command = stroke_flat_current_command;
+   itr->current_coords = stroke_flat_itr_coords;
+   itr->curve_index = -1;
+   itr->curve_poly = 0;
+}
+
+
+static INLINE VGboolean finite_coords4(const VGfloat *c)
+{
+   return
+      isfinite(c[0]) && isfinite(c[1]) &&
+      isfinite(c[2]) && isfinite(c[3]);
+}
+
+/* from Graphics Gems II */
+#define SAME_SIGNS(a, b) ((a) * (b) >= 0)
+static VGboolean do_lines_intersect(VGfloat x1, VGfloat y1, VGfloat x2, VGfloat y2,
+                                    VGfloat x3, VGfloat y3, VGfloat x4, VGfloat y4)
+{
+   VGfloat a1, a2, b1, b2, c1, c2; /* Coefficients of line eqns */
+   VGfloat r1, r2, r3, r4;         /* 'sign' values */
+
+   a1 = y2 - y1;
+   b1 = x1 - x2;
+   c1 = x2 * y1 - x1 * y2;
+
+   r3 = a1 * x3 + b1 * y3 + c1;
+   r4 = a1 * x4 + b1 * y4 + c1;
+
+   if (r3 != 0 && r4 != 0 && SAME_SIGNS(r3, r4))
+      return VG_FALSE;
+
+   a2 = y4 - y3;
+   b2 = x3 - x4;
+   c2 = x4 * y3 - x3 * y4;
+
+   r1 = a2 * x1 + b2 * y1 + c2;
+   r2 = a2 * x2 + b2 * y2 + c2;
+
+   if (r1 != 0 && r2 != 0 && SAME_SIGNS(r1, r2))
+      return VG_FALSE;
+
+   return VG_TRUE;
+}
+
+static INLINE VGfloat line_dx(const VGfloat *l)
+{
+   return l[2] - l[0];
+}
+
+static INLINE VGfloat line_dy(const VGfloat *l)
+{
+   return l[3] - l[1];
+}
+
+static INLINE VGfloat line_angle(const VGfloat *l)
+{
+   const VGfloat dx = line_dx(l);
+   const VGfloat dy = line_dy(l);
+
+   const VGfloat theta = atan2(-dy, dx) * 360.0 / M_2PI;
+
+   const VGfloat theta_normalized = theta < 0 ? theta + 360 : theta;
+
+   if (floatsEqual(theta_normalized, 360.f))
+      return 0;
+   else
+      return theta_normalized;
+}
+
+static INLINE void line_set_length(VGfloat *l, VGfloat len)
+{
+   VGfloat uv[] = {l[0], l[1], l[2], l[3]};
+   if (null_line(l))
+      return;
+   line_normalize(uv);
+   l[2] = l[0] + line_dx(uv) * len;
+   l[3] = l[1] + line_dy(uv) * len;
+}
+
+static INLINE void line_translate(VGfloat *l, VGfloat x, VGfloat y)
+{
+   l[0] += x;
+   l[1] += y;
+   l[2] += x;
+   l[3] += y;
+}
+
+static INLINE VGfloat line_angle_to(const VGfloat *l1,
+                                    const VGfloat *l2)
+{
+   VGfloat a1, a2, delta, delta_normalized;
+   if (null_line(l1) || null_line(l1))
+      return 0;
+
+   a1 = line_angle(l1);
+   a2 = line_angle(l2);
+
+   delta = a2 - a1;
+   delta_normalized = delta < 0 ? delta + 360 : delta;
+
+   if (floatsEqual(delta, 360.f))
+      return 0;
+   else
+      return delta_normalized;
+}
+
+static INLINE VGfloat line_angles(const VGfloat *l1,
+                                  const VGfloat *l2)
+{
+   VGfloat cos_line, rad = 0;
+
+   if (null_line(l1) || null_line(l2))
+      return 0;
+
+   cos_line = (line_dx(l1)*line_dx(l2) + line_dy(l1)*line_dy(l2)) /
+              (line_lengthv(l1)*line_lengthv(l2));
+   rad = 0;
+
+   if (cos_line >= -1.0 && cos_line <= 1.0)
+      rad = acos(cos_line);
+   return rad * 360 / M_2PI;
+}
+
+
+static INLINE VGfloat adapted_angle_on_x(const VGfloat *line)
+{
+   const VGfloat identity[] = {0, 0, 1, 0};
+   VGfloat angle = line_angles(line, identity);
+   if (line_dy(line) > 0)
+      angle = 360 - angle;
+   return angle;
+}
+
+static enum intersection_type line_intersect(const VGfloat *l1,
+                                             const VGfloat *l2,
+                                             float *intersection_point)
+{
+   VGfloat isect[2];
+   enum intersection_type type;
+   VGboolean dx_zero, ldx_zero;
+
+   if (null_line(l1) || null_line(l2) ||
+       !finite_coords4(l1) || !finite_coords4(l2))
+      return NoIntersections;
+
+   type = do_lines_intersect(l1[0], l1[1], l1[2], l1[3], l2[0], l2[1], l2[2], l2[3])
+          ? BoundedIntersection : UnboundedIntersection;
+
+   dx_zero  = floatsEqual(line_dx(l1) + 1, 1);
+   ldx_zero = floatsEqual(line_dx(l2) + 1, 1);
+
+   /* one of the lines is vertical */
+   if (dx_zero && ldx_zero) {
+      type = NoIntersections;
+   } else if (dx_zero) {
+      VGfloat la = line_dy(l2) / line_dx(l2);
+      isect[0] = l1[0];
+      isect[1] = la * l1[0] + l2[1] - la * l2[0];
+   } else if (ldx_zero) {
+      VGfloat ta = line_dy(l1) / line_dx(l1);
+      isect[0] = l2[0];
+      isect[1] = ta * l2[0] + l1[1] - ta*l1[0];
+   } else {
+      VGfloat x;
+      VGfloat ta = line_dy(l1) / line_dx(l1);
+      VGfloat la = line_dy(l2) / line_dx(l2);
+      if (ta == la)
+         return NoIntersections;
+
+      x = ( - l2[1] + la * l2[0] + l1[1] - ta * l1[0] ) / (la - ta);
+      isect[0] = x;
+      isect[1] = ta*(x - l1[0]) + l1[1];
+   }
+   if (intersection_point) {
+      intersection_point[0] = isect[0];
+      intersection_point[1] = isect[1];
+   }
+   return type;
+}
+
+static INLINE enum line_join_mode stroker_join_mode(struct stroker *s)
+{
+   switch(s->join_style) {
+   case VG_JOIN_MITER:
+      return MiterJoin;
+   case VG_JOIN_ROUND:
+      return RoundJoin;
+   case VG_JOIN_BEVEL:
+      return FlatJoin;
+   default:
+      return FlatJoin;
+   }
+}
+
+static INLINE enum line_join_mode stroker_cap_mode(struct stroker *s)
+{
+   switch(s->cap_style) {
+   case VG_CAP_BUTT:
+      return FlatJoin;
+   case VG_CAP_ROUND:
+      return RoundCap;
+   case VG_CAP_SQUARE:
+      return SquareJoin;
+   default:
+      return FlatJoin;
+   }
+}
+
+void stroker_emit_move_to(struct stroker *stroker, VGfloat x, VGfloat y)
+{
+   VGubyte cmds = VG_MOVE_TO_ABS;
+   VGfloat coords[2] = {x, y};
+#if DEBUG_EMITS
+   debug_printf("emit move %f, %f\n", x, y);
+#endif
+   stroker->back2_x = stroker->back1_x;
+   stroker->back2_y = stroker->back1_y;
+   stroker->back1_x = x;
+   stroker->back1_y = y;
+
+   path_append_data(stroker->path,
+                    1,
+                    &cmds, &coords);
+}
+
+void stroker_emit_line_to(struct stroker *stroker, VGfloat x, VGfloat y)
+{
+   VGubyte cmds = VG_LINE_TO_ABS;
+   VGfloat coords[2] = {x, y};
+#if DEBUG_EMITS
+   debug_printf("emit line %f, %f\n", x, y);
+#endif
+   stroker->back2_x = stroker->back1_x;
+   stroker->back2_y = stroker->back1_y;
+   stroker->back1_x = x;
+   stroker->back1_y = y;
+   path_append_data(stroker->path,
+                    1,
+                    &cmds, &coords);
+}
+
+void stroker_emit_curve_to(struct stroker *stroker, VGfloat px1, VGfloat py1,
+                                  VGfloat px2, VGfloat py2,
+                                  VGfloat x, VGfloat y)
+{
+   VGubyte cmds = VG_CUBIC_TO_ABS;
+   VGfloat coords[6] = {px1, py1, px2, py2, x, y};
+#if DEBUG_EMITS
+   debug_printf("emit curve %f, %f, %f, %f, %f, %f\n", px1, py1,
+                px2, py2, x, y);
+#endif
+
+   if (px2 == x && py2 == y) {
+      if (px1 == x && py1 == y) {
+         stroker->back2_x = stroker->back1_x;
+         stroker->back2_y = stroker->back1_y;
+      } else {
+         stroker->back2_x = px1;
+         stroker->back2_y = py1;
+      }
+   } else {
+      stroker->back2_x = px2;
+      stroker->back2_y = py2;
+   }
+   stroker->back1_x = x;
+   stroker->back1_y = y;
+
+   path_append_data(stroker->path,
+                    1,
+                    &cmds, &coords);
+}
+
+static INLINE void create_round_join(struct stroker *stroker,
+                                     VGfloat x1, VGfloat y1,
+                                     VGfloat x2, VGfloat y2,
+                                     VGfloat width, VGfloat height)
+{
+   struct arc arc;
+   struct matrix matrix;
+
+   matrix_load_identity(&matrix);
+
+   /*stroker_emit_line_to(stroker, nx, ny);*/
+
+   arc_init(&arc, VG_SCCWARC_TO_ABS,
+            x1, y1, x2, y2, width/2, height/2, 0);
+   arc_stroker_emit(&arc, stroker, &matrix);
+}
+
+
+static void create_joins(struct stroker *stroker,
+                         VGfloat focal_x, VGfloat focal_y,
+                         const VGfloat *next_line, enum line_join_mode join)
+{
+#if DEBUG_EMITS
+   debug_printf("create_joins: focal=[%f, %f], next_line=[%f, %f,%f, %f]\n",
+                focal_x, focal_y,
+                next_line[0], next_line[1], next_line[2], next_line[3]);
+#endif
+   /* if we're alredy connected do nothing */
+   if (floatsEqual(stroker->back1_x, next_line[0]) &&
+       floatsEqual(stroker->back1_y, next_line[1]))
+      return;
+
+   if (join == FlatJoin) {
+      stroker_emit_line_to(stroker, next_line[0], next_line[1]);
+   } else {
+      VGfloat prev_line[] = {stroker->back2_x, stroker->back2_y,
+                             stroker->back1_x, stroker->back1_y};
+
+      VGfloat isect[2];
+      enum intersection_type type = line_intersect(prev_line, next_line, isect);
+
+      if (join == SquareJoin) {
+         VGfloat offset = stroker->stroke_width / 2;
+         VGfloat l1[4] = {prev_line[0],
+                          prev_line[1],
+                          prev_line[2],
+                          prev_line[3]};
+         VGfloat l2[4] = {next_line[2],
+                          next_line[3],
+                          next_line[0],
+                          next_line[1]};
+
+         line_translate(l1, line_dx(l1), line_dy(l1));
+         line_set_length(l1, offset);
+
+         line_translate(l2, line_dx(l2), line_dy(l2));
+         line_set_length(l2, offset);
+
+         stroker_emit_line_to(stroker, l1[2], l1[3]);
+         stroker_emit_line_to(stroker, l2[2], l2[3]);
+         stroker_emit_line_to(stroker, l2[0], l2[1]);
+      } else if (join == RoundJoin) {
+         VGfloat offset = stroker->stroke_width / 2;
+         VGfloat short_cut[4] = {prev_line[2], prev_line[3],
+                                 next_line[0], next_line[1]};
+         VGfloat angle = line_angles(prev_line, short_cut);
+
+         if (type == BoundedIntersection ||
+             (angle > 90 && !floatsEqual(angle, 90.f))) {
+            stroker_emit_line_to(stroker, next_line[0], next_line[1]);
+            return;
+         }
+         create_round_join(stroker, prev_line[2], prev_line[3],
+                           next_line[0], next_line[1],
+                           offset * 2, offset * 2);
+
+         stroker_emit_line_to(stroker, next_line[0], next_line[1]);
+      } else if (join == RoundCap) {
+         VGfloat offset = stroker->stroke_width / 2;
+         VGfloat l1[4] = { prev_line[0], prev_line[1],
+                           prev_line[2], prev_line[3] };
+         VGfloat l2[4] = {focal_x, focal_y,
+                          prev_line[2], prev_line[3]};
+
+         line_translate(l1, line_dx(l1), line_dy(l1));
+         line_set_length(l1, KAPPA * offset);
+
+         /* normal between prev_line and focal */
+         line_translate(l2, -line_dy(l2), line_dx(l2));
+         line_set_length(l2, KAPPA * offset);
+
+         stroker_emit_curve_to(stroker, l1[2], l1[3],
+                               l2[2], l2[3],
+                               l2[0], l2[1]);
+
+         l2[0] = l2[0];
+         l2[1] = l2[1];
+         l2[2] = l2[0] - line_dx(l2);
+         l2[3] = l2[1] - line_dy(l2);
+
+         line_translate(l1, next_line[0] - l1[0], next_line[1] - l1[1]);
+
+         stroker_emit_curve_to(stroker,
+                               l2[2], l2[3],
+                               l1[2], l1[3],
+                               l1[0], l1[1]);
+      } else if (join == MiterJoin) {
+         VGfloat miter_line[4] = {stroker->back1_x, stroker->back1_y,
+                                  isect[0], isect[1]};
+         VGfloat sl = (stroker->stroke_width * stroker->miter_limit);
+         VGfloat inside_line[4] = {prev_line[2], prev_line[3],
+                                   next_line[0], next_line[1]};
+         VGfloat angle = line_angle_to(inside_line, prev_line);
+
+         if (type == BoundedIntersection ||
+             (angle > 90 && !floatsEqual(angle, 90.f))) {
+            /*
+            debug_printf("f = %f, nl = %f, pl = %f, is = %f\n",
+                         focal_x, next_line[0],
+                         prev_line[2], isect[0]);*/
+            stroker_emit_line_to(stroker, next_line[0], next_line[1]);
+            return;
+         }
+
+         if (type == NoIntersections || line_lengthv(miter_line) > sl) {
+            stroker_emit_line_to(stroker, next_line[0], next_line[1]);
+         } else {
+            stroker_emit_line_to(stroker, isect[0], isect[1]);
+            stroker_emit_line_to(stroker, next_line[0], next_line[1]);
+         }
+      } else {
+         debug_assert(!"create_joins bad join style");
+      }
+   }
+}
+
+static void stroker_add_segment(struct stroker *stroker,
+                                VGPathCommand cmd,
+                                const VGfloat *coords,
+                                VGint num_coords)
+{
+   /* skip duplicated points */
+   if (stroker->segments->num_elements &&
+       stroker->last_cmd == cmd) {
+      VGfloat *data = stroker->control_points->data;
+      data += stroker->control_points->num_elements;
+      data -= num_coords;
+      switch (cmd) {
+      case VG_MOVE_TO_ABS:
+         if (floatsEqual(coords[0], data[0]) &&
+             floatsEqual(coords[1], data[1]))
+            return;
+         break;
+      case VG_LINE_TO_ABS:
+         if (floatsEqual(coords[0], data[0]) &&
+             floatsEqual(coords[1], data[1]))
+            return;
+         break;
+      case VG_CUBIC_TO_ABS:
+         if (floatsEqual(coords[0], data[0]) &&
+             floatsEqual(coords[1], data[1]) &&
+             floatsEqual(coords[2], data[2]) &&
+             floatsEqual(coords[3], data[3]) &&
+             floatsEqual(coords[4], data[4]) &&
+             floatsEqual(coords[5], data[5]))
+            return;
+         break;
+      default:
+         debug_assert(!"Invalid stroke segment");
+      }
+   } else if (stroker->last_cmd == VG_CUBIC_TO_ABS &&
+              cmd == VG_LINE_TO_ABS) {
+      VGfloat *data = stroker->control_points->data;
+      data += stroker->control_points->num_elements;
+      data -= 2;
+      if (floatsEqual(coords[0], data[0]) &&
+          floatsEqual(coords[1], data[1]))
+         return;
+   }
+   stroker->last_cmd = cmd;
+   array_append_data(stroker->segments, &cmd, 1);
+   array_append_data(stroker->control_points, coords, num_coords);
+}
+
+void stroker_move_to(struct stroker *stroker, VGfloat x, VGfloat y)
+{
+   VGfloat coords[2] = {x, y};
+#if STROKE_SEGMENTS
+   debug_printf("stroker_move_to(%f, %f)\n", x, y);
+#endif
+
+   if (stroker->segments->num_elements > 0)
+      stroker->process_subpath(stroker);
+
+   array_reset(stroker->segments);
+   array_reset(stroker->control_points);
+
+   stroker_add_segment(stroker, VG_MOVE_TO_ABS, coords, 2);
+}
+
+void stroker_line_to(struct stroker *stroker, VGfloat x, VGfloat y)
+{
+   VGfloat coords[] = {x, y};
+
+#if STROKE_SEGMENTS
+   debug_printf("stroker_line_to(%f, %f)\n", x, y);
+#endif
+   if (!stroker->segments->num_elements)
+      stroker_add_segment(stroker, VG_MOVE_TO_ABS, zero_coords, 2);
+
+   stroker_add_segment(stroker, VG_LINE_TO_ABS, coords, 2);
+}
+
+void stroker_curve_to(struct stroker *stroker, VGfloat px1, VGfloat py1,
+                      VGfloat px2, VGfloat py2,
+                      VGfloat x, VGfloat y)
+{
+   VGfloat coords[] = {px1, py1,
+                       px2, py2,
+                       x, y};
+#if STROKE_SEGMENTS
+   debug_printf("stroker_curve_to(%f, %f, %f, %f, %f, %f)\n",
+                px1, py1, px2, py2, x, y);
+#endif
+   if (!stroker->segments->num_elements)
+      stroker_add_segment(stroker, VG_MOVE_TO_ABS, zero_coords, 2);
+
+   stroker_add_segment(stroker, VG_CUBIC_TO_ABS, coords, 6);
+}
+
+static INLINE VGboolean is_segment_null(VGPathCommand cmd,
+                                        VGfloat *coords,
+                                        VGfloat *res)
+{
+   switch(cmd) {
+   case VG_MOVE_TO_ABS:
+   case VG_LINE_TO_ABS:
+      return floatsEqual(coords[0], res[0]) &&
+         floatsEqual(coords[1], res[1]);
+      break;
+   case VG_CUBIC_TO_ABS:
+      return floatsEqual(coords[0], res[0]) &&
+         floatsEqual(coords[1], res[1]) &&
+         floatsEqual(coords[2], res[0]) &&
+         floatsEqual(coords[3], res[1]) &&
+         floatsEqual(coords[4], res[0]) &&
+         floatsEqual(coords[5], res[1]);
+      break;
+   default:
+      assert(0);
+   }
+   return VG_FALSE;
+}
+
+static VGboolean vg_stroke_outline(struct stroke_iterator *it,
+                                struct stroker *stroker,
+                                VGboolean cap_first,
+                                VGfloat *start_tangent)
+{
+   const int MAX_OFFSET = 16;
+   struct bezier offset_curves[MAX_OFFSET];
+   VGPathCommand first_element;
+   VGfloat start[2], prev[2];
+   VGboolean first = VG_TRUE;
+   VGfloat offset;
+
+   first_element = stroke_itr_command(it);
+   if (first_element != VG_MOVE_TO_ABS) {
+      stroker_emit_move_to(stroker, 0.f, 0.f);
+      prev[0] = 0.f;
+      prev[1] = 0.f;
+   }
+   stroke_itr_coords(it, start);
+#if STROKE_DEBUG
+   debug_printf(" -> (side) [%.2f, %.2f]\n",
+                start[0],
+                start[1]);
+#endif
+
+   prev[0] = start[0];
+   prev[1] = start[1];
+
+   offset = stroker->stroke_width / 2;
+
+   if (!it->has_next(it)) {
+      /* single point */
+
+      return VG_TRUE;
+   }
+
+   while (it->has_next(it)) {
+      VGPathCommand cmd;
+      VGfloat coords[8];
+
+      it->next(it);
+      cmd = stroke_itr_command(it);
+      stroke_itr_coords(it, coords);
+
+      if (cmd == VG_LINE_TO_ABS) {
+         VGfloat line[4] = {prev[0], prev[1], coords[0], coords[1]};
+         VGfloat normal[4];
+         line_normal(line, normal);
+
+#if STROKE_DEBUG
+         debug_printf("\n ---> (side) lineto [%.2f, %.2f]\n", coords[0], coords[1]);
+#endif
+         line_set_length(normal, offset);
+         line_translate(line, line_dx(normal), line_dy(normal));
+
+         /* if we are starting a new subpath, move to correct starting point */
+         if (first) {
+            if (cap_first)
+               create_joins(stroker, prev[0], prev[1], line,
+                            stroker_cap_mode(stroker));
+            else
+               stroker_emit_move_to(stroker, line[0], line[1]);
+            memcpy(start_tangent, line,
+                   sizeof(VGfloat) * 4);
+            first = VG_FALSE;
+         } else {
+            create_joins(stroker, prev[0], prev[1], line,
+                         stroker_join_mode(stroker));
+         }
+
+         /* add the stroke for this line */
+         stroker_emit_line_to(stroker, line[2], line[3]);
+         prev[0] = coords[0];
+         prev[1] = coords[1];
+      } else if (cmd == VG_CUBIC_TO_ABS) {
+#if STROKE_DEBUG
+         debug_printf("\n ---> (side) cubicTo [%.2f, %.2f]\n",
+                coords[4],
+                coords[5]);
+#endif
+         struct bezier bezier;
+         int count;
+
+         bezier_init(&bezier,
+                     prev[0], prev[1], coords[0], coords[1],
+                     coords[2], coords[3], coords[4], coords[5]);
+
+         count = bezier_translate_by_normal(&bezier,
+                                            offset_curves,
+                                            MAX_OFFSET,
+                                            offset,
+                                            curve_threshold);
+
+         if (count) {
+            /* if we are starting a new subpath, move to correct starting point */
+            VGfloat tangent[4];
+            VGint i;
+
+            bezier_start_tangent(&bezier, tangent);
+            line_translate(tangent,
+                           offset_curves[0].x1 - bezier.x1,
+                           offset_curves[0].y1 - bezier.y1);
+            if (first) {
+               VGfloat pt[2] = {offset_curves[0].x1,
+                                offset_curves[0].y1};
+
+               if (cap_first) {
+                  create_joins(stroker, prev[0], prev[1], tangent,
+                               stroker_cap_mode(stroker));
+               } else {
+                  stroker_emit_move_to(stroker, pt[0], pt[1]);
+               }
+               start_tangent[0] = tangent[0];
+               start_tangent[1] = tangent[1];
+               start_tangent[2] = tangent[2];
+               start_tangent[3] = tangent[3];
+               first = VG_FALSE;
+            } else {
+               create_joins(stroker, prev[0], prev[1], tangent,
+                            stroker_join_mode(stroker));
+            }
+
+            /* add these beziers */
+            for (i = 0; i < count; ++i) {
+               struct bezier *bez = &offset_curves[i];
+               stroker_emit_curve_to(stroker,
+                                     bez->x2, bez->y2,
+                                     bez->x3, bez->y3,
+                                     bez->x4, bez->y4);
+            }
+         }
+
+         prev[0] = coords[4];
+         prev[1] = coords[5];
+      }
+   }
+
+   if (floatsEqual(start[0], prev[0]) &&
+       floatsEqual(start[1], prev[1])) {
+      /* closed subpath, join first and last point */
+#if STROKE_DEBUG
+      debug_printf("\n stroker: closed subpath\n");
+#endif
+      create_joins(stroker, prev[0], prev[1], start_tangent,
+                   stroker_join_mode(stroker));
+      return VG_TRUE;
+   } else {
+#if STROKE_DEBUG
+      debug_printf("\n stroker: open subpath\n");
+#endif
+      return VG_FALSE;
+   }
+}
+
+static void stroker_process_subpath(struct stroker *stroker)
+{
+   VGboolean fwclosed, bwclosed;
+   VGfloat fw_start_tangent[4], bw_start_tangent[4];
+   struct stroke_iterator fwit;
+   struct stroke_iterator bwit;
+   debug_assert(stroker->segments->num_elements > 0);
+
+   memset(fw_start_tangent, 0,
+          sizeof(VGfloat)*4);
+   memset(bw_start_tangent, 0,
+          sizeof(VGfloat)*4);
+
+   stroke_forward_iterator(&fwit, stroker->segments,
+                           stroker->control_points);
+   stroke_backward_iterator(&bwit, stroker->segments,
+                            stroker->control_points);
+
+   debug_assert(fwit.cmds[0] == VG_MOVE_TO_ABS);
+
+   fwclosed = vg_stroke_outline(&fwit, stroker, VG_FALSE, fw_start_tangent);
+   bwclosed = vg_stroke_outline(&bwit, stroker, !fwclosed, bw_start_tangent);
+
+   if (!bwclosed)
+      create_joins(stroker,
+                   fwit.coords[0], fwit.coords[1], fw_start_tangent,
+                   stroker_cap_mode(stroker));
+   else {
+      /* hack to handle the requirement of the VG spec that says that strokes
+       * of len==0 that have butt cap or round cap still need
+       * to be rendered. (8.7.4 Stroke Generation) */
+      if (stroker->segments->num_elements <= 3) {
+         VGPathCommand cmd;
+         VGfloat data[8], coords[8];
+         struct stroke_iterator *it = &fwit;
+
+         stroke_forward_iterator(it, stroker->segments,
+                                 stroker->control_points);
+         cmd = stroke_itr_command(it);
+         stroke_itr_coords(it, coords);
+         if (cmd != VG_MOVE_TO_ABS) {
+            memset(data, 0, sizeof(VGfloat) * 8);
+            if (!is_segment_null(cmd, coords, data))
+               return;
+         } else {
+            data[0] = coords[0];
+            data[1] = coords[1];
+         }
+         while (it->has_next(it)) {
+            it->next(it);
+            cmd = stroke_itr_command(it);
+            stroke_itr_coords(it, coords);
+            if (!is_segment_null(cmd, coords, data))
+               return;
+         }
+         /* generate the square/round cap */
+         if (stroker->cap_style == VG_CAP_SQUARE) {
+            VGfloat offset = stroker->stroke_width / 2;
+            stroker_emit_move_to(stroker, data[0] - offset,
+                                 data[1] - offset);
+            stroker_emit_line_to(stroker, data[0] + offset,
+                                 data[1] - offset);
+            stroker_emit_line_to(stroker, data[0] + offset,
+                                 data[1] + offset);
+            stroker_emit_line_to(stroker, data[0] - offset,
+                                 data[1] + offset);
+            stroker_emit_line_to(stroker, data[0] - offset,
+                                 data[1] - offset);
+         } else if (stroker->cap_style == VG_CAP_ROUND) {
+            VGfloat offset = stroker->stroke_width / 2;
+            VGfloat cx = data[0], cy = data[1];
+            { /*circle */
+               struct arc arc;
+               struct matrix matrix;
+               matrix_load_identity(&matrix);
+
+               stroker_emit_move_to(stroker, cx + offset, cy);
+               arc_init(&arc, VG_SCCWARC_TO_ABS,
+                        cx + offset, cy,
+                        cx - offset, cy,
+                        offset, offset, 0);
+               arc_stroker_emit(&arc, stroker, &matrix);
+               arc_init(&arc, VG_SCCWARC_TO_ABS,
+                         cx - offset, cy,
+                         cx + offset, cy,
+                         offset, offset, 0);
+               arc_stroker_emit(&arc, stroker, &matrix);
+            }
+         }
+      }
+   }
+}
+
+static INLINE VGfloat dash_pattern(struct dash_stroker *stroker,
+                                   VGint idx)
+{
+   if (stroker->dash_pattern[idx] < 0)
+      return 0.f;
+   return stroker->dash_pattern[idx];
+}
+
+static void dash_stroker_process_subpath(struct stroker *str)
+{
+   struct dash_stroker *stroker = (struct dash_stroker *)str;
+   VGfloat sum_length = 0;
+   VGint i;
+   VGint idash = 0;
+   VGfloat pos = 0;
+   VGfloat elen = 0;
+   VGfloat doffset = stroker->dash_phase;
+   VGfloat estart = 0;
+   VGfloat estop = 0;
+   VGfloat cline[4];
+   struct stroke_iterator it;
+   VGfloat prev[2];
+   VGfloat move_to_pos[2];
+   VGfloat line_to_pos[2];
+
+   VGboolean has_move_to = VG_FALSE;
+
+   stroke_flat_iterator(&it, stroker->base.segments,
+                        stroker->base.control_points);
+
+   stroke_itr_coords(&it, prev);
+   move_to_pos[0] = prev[0];
+   move_to_pos[1] = prev[1];
+
+   debug_assert(stroker->dash_pattern_num > 0);
+
+   for (i = 0; i < stroker->dash_pattern_num; ++i) {
+      sum_length += dash_pattern(stroker, i);
+   }
+
+   if (floatIsZero(sum_length)) {
+      return;
+   }
+
+   doffset -= floorf(doffset / sum_length) * sum_length;
+
+   while (!floatIsZero(doffset) && doffset >= dash_pattern(stroker, idash)) {
+      doffset -= dash_pattern(stroker, idash);
+      idash = (idash + 1) % stroker->dash_pattern_num;
+   }
+
+   while (it.has_next(&it)) {
+      VGPathCommand cmd;
+      VGfloat coords[8];
+      VGboolean done;
+
+      it.next(&it);
+      cmd = stroke_itr_command(&it);
+      stroke_itr_coords(&it, coords);
+
+      debug_assert(cmd == VG_LINE_TO_ABS);
+      cline[0] = prev[0];
+      cline[1] = prev[1];
+      cline[2] = coords[0];
+      cline[3] = coords[1];
+
+      elen = line_lengthv(cline);
+
+      estop = estart + elen;
+
+      done = pos >= estop;
+      while (!done) {
+         VGfloat p2[2];
+
+         VGint idash_incr = 0;
+         VGboolean has_offset = doffset > 0;
+         VGfloat dpos = pos + dash_pattern(stroker, idash) - doffset - estart;
+
+         debug_assert(dpos >= 0);
+
+         if (dpos > elen) { /* dash extends this line */
+            doffset = dash_pattern(stroker, idash) - (dpos - elen);
+            pos = estop;
+            done = VG_TRUE;
+            p2[0] = cline[2];
+            p2[1] = cline[3];
+         } else { /* Dash is on this line */
+            line_point_at(cline, dpos/elen, p2);
+            pos = dpos + estart;
+            done = pos >= estop;
+            idash_incr = 1;
+            doffset = 0;
+         }
+
+         if (idash % 2 == 0) {
+            line_to_pos[0] = p2[0];
+            line_to_pos[1] = p2[1];
+
+            if (!has_offset || !has_move_to) {
+               stroker_move_to(&stroker->stroker, move_to_pos[0], move_to_pos[1]);
+               has_move_to = VG_TRUE;
+            }
+            stroker_line_to(&stroker->stroker, line_to_pos[0], line_to_pos[1]);
+         } else {
+            move_to_pos[0] = p2[0];
+            move_to_pos[1] = p2[1];
+         }
+
+         idash = (idash + idash_incr) % stroker->dash_pattern_num;
+      }
+
+      estart = estop;
+      prev[0] = coords[0];
+      prev[1] = coords[1];
+   }
+
+   if (it.curve_poly) {
+      polygon_destroy(it.curve_poly);
+      it.curve_poly = 0;
+   }
+
+   stroker->base.path = stroker->stroker.path;
+}
+
+static void default_begin(struct stroker *stroker)
+{
+   array_reset(stroker->segments);
+   array_reset(stroker->control_points);
+}
+
+static void default_end(struct stroker *stroker)
+{
+   if (stroker->segments->num_elements > 0)
+      stroker->process_subpath(stroker);
+}
+
+
+static void dash_stroker_begin(struct stroker *stroker)
+{
+   struct dash_stroker *dasher =
+      (struct dash_stroker *)stroker;
+
+   default_begin(&dasher->stroker);
+   default_begin(stroker);
+}
+
+static void dash_stroker_end(struct stroker *stroker)
+{
+   struct dash_stroker *dasher =
+      (struct dash_stroker *)stroker;
+
+   default_end(stroker);
+   default_end(&dasher->stroker);
+}
+
+void stroker_init(struct stroker *stroker,
+                  struct vg_state *state)
+{
+   stroker->stroke_width = state->stroke.line_width.f;
+   stroker->miter_limit = state->stroke.miter_limit.f;
+   stroker->cap_style = state->stroke.cap_style;
+   stroker->join_style = state->stroke.join_style;
+
+   stroker->begin = default_begin;
+   stroker->process_subpath = stroker_process_subpath;
+   stroker->end = default_end;
+
+   stroker->segments = array_create(sizeof(VGubyte));
+   stroker->control_points = array_create(sizeof(VGfloat));
+
+   stroker->back1_x = 0;
+   stroker->back1_y = 0;
+   stroker->back2_x = 0;
+   stroker->back2_y = 0;
+
+   stroker->path = path_create(VG_PATH_DATATYPE_F, 1.0f, 0.0f,
+                               0, 0, VG_PATH_CAPABILITY_ALL);
+
+   stroker->last_cmd = VG_CLOSE_PATH;
+}
+
+void dash_stroker_init(struct stroker *str,
+                       struct vg_state *state)
+{
+   struct dash_stroker *stroker = (struct dash_stroker *)str;
+   int i;
+
+   stroker_init(str, state);
+   stroker_init(&stroker->stroker, state);
+
+   {
+      int real_num = state->stroke.dash_pattern_num;
+      if (real_num % 2)/* if odd, ignore the last one */
+         --real_num;
+      for (i = 0; i < real_num; ++i)
+         stroker->dash_pattern[i] = state->stroke.dash_pattern[i].f;
+      stroker->dash_pattern_num = real_num;
+   }
+
+   stroker->dash_phase = state->stroke.dash_phase.f;
+   stroker->dash_phase_reset = state->stroke.dash_phase_reset;
+
+   stroker->base.begin = dash_stroker_begin;
+   stroker->base.process_subpath = dash_stroker_process_subpath;
+   stroker->base.end = dash_stroker_end;
+   path_destroy(stroker->base.path);
+   stroker->base.path = NULL;
+}
+
+void stroker_begin(struct stroker *stroker)
+{
+   stroker->begin(stroker);
+}
+
+void stroker_end(struct stroker *stroker)
+{
+   stroker->end(stroker);
+}
+
+void stroker_cleanup(struct stroker *stroker)
+{
+   array_destroy(stroker->segments);
+   array_destroy(stroker->control_points);
+}
+
+void dash_stroker_cleanup(struct dash_stroker *stroker)
+{
+   /* if stroker->base.path is null means we never
+    * processed a valid path so delete the temp one
+    * we already created */
+   if (!stroker->base.path)
+      path_destroy(stroker->stroker.path);
+   stroker_cleanup(&stroker->stroker);
+   stroker_cleanup((struct stroker*)stroker);
+}
diff --git a/src/gallium/state_trackers/vega/stroker.h b/src/gallium/state_trackers/vega/stroker.h
new file mode 100644 (file)
index 0000000..36543cd
--- /dev/null
@@ -0,0 +1,89 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#ifndef STROKER_H
+#define STROKER_H
+
+#include "VG/openvg.h"
+#include "api_consts.h"
+
+struct path;
+struct vg_state;
+struct array;
+
+struct stroker {
+   void (*begin)(struct stroker *stroker);
+   void (*process_subpath)(struct stroker *stroker);
+   void (*end)(struct stroker *stroker);
+
+   struct array *segments;
+   struct array *control_points;
+   struct path *path;
+
+   VGfloat back1_x, back1_y;
+   VGfloat back2_x, back2_y;
+
+   VGfloat     stroke_width;
+   VGfloat     miter_limit;
+   VGCapStyle  cap_style;
+   VGJoinStyle join_style;
+
+   VGPathCommand last_cmd;
+};
+
+struct dash_stroker {
+   struct stroker base;
+
+   struct stroker stroker;
+
+   VGfloat dash_pattern[VEGA_MAX_DASH_COUNT];
+   VGint dash_pattern_num;
+   VGfloat dash_phase;
+   VGboolean dash_phase_reset;
+};
+
+void stroker_init(struct stroker *stroker,
+                  struct vg_state *state);
+void dash_stroker_init(struct stroker *stroker,
+                       struct vg_state *state);
+void dash_stroker_cleanup(struct dash_stroker *stroker);
+void stroker_cleanup(struct stroker *stroker);
+
+void stroker_begin(struct stroker *stroker);
+void stroker_move_to(struct stroker *stroker, VGfloat x, VGfloat y);
+void stroker_line_to(struct stroker *stroker, VGfloat x, VGfloat y);
+void stroker_curve_to(struct stroker *stroker, VGfloat px1, VGfloat py1,
+                      VGfloat px2, VGfloat py2,
+                      VGfloat x, VGfloat y);
+void stroker_end(struct stroker *stroker);
+
+void stroker_emit_move_to(struct stroker *stroker, VGfloat x, VGfloat y);
+void stroker_emit_line_to(struct stroker *stroker, VGfloat x, VGfloat y);
+void stroker_emit_curve_to(struct stroker *stroker, VGfloat px1, VGfloat py1,
+                           VGfloat px2, VGfloat py2,
+                           VGfloat x, VGfloat y);
+
+#endif
diff --git a/src/gallium/state_trackers/vega/util_array.h b/src/gallium/state_trackers/vega/util_array.h
new file mode 100644 (file)
index 0000000..4343dfe
--- /dev/null
@@ -0,0 +1,122 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#ifndef UTIL_ARRAY_H
+#define UTIL_ARRAY_H
+
+#include "util/u_memory.h"
+
+#define DEFAULT_ARRAY_SIZE 256
+
+struct array {
+   VGint          datatype_size;
+   void          *data;
+   VGint          size;
+   VGint          num_elements;
+};
+
+static INLINE struct array *array_create(VGint datatype_size)
+{
+   struct array *array = CALLOC_STRUCT(array);
+   array->datatype_size = datatype_size;
+
+   array->size = DEFAULT_ARRAY_SIZE;
+   array->data = malloc(array->size * array->datatype_size);
+
+   return array;
+}
+
+
+static INLINE struct array *array_create_size(VGint datatype_size, VGint size)
+{
+   struct array *array = CALLOC_STRUCT(array);
+   array->datatype_size = datatype_size;
+
+   array->size = size;
+   array->data = malloc(array->size * array->datatype_size);
+
+   return array;
+}
+
+static INLINE void array_destroy(struct array *array)
+{
+   if (array)
+      free(array->data);
+   free(array);
+}
+
+static INLINE void array_resize(struct array *array, int num)
+{
+   VGint size = array->datatype_size * num;
+   void *data = malloc(size);
+   memcpy(data, array->data, array->size * array->datatype_size);
+   free(array->data);
+   array->data = data;
+   array->size = num;
+   array->num_elements = (array->num_elements > num) ? num :
+                         array->num_elements;
+}
+
+static INLINE void array_append_data(struct array *array,
+                              const void *data, int num_elements)
+{
+   VGbyte *adata;
+
+   while (array->num_elements + num_elements > array->size) {
+      array_resize(array, (array->num_elements + num_elements) * 1.5);
+   }
+   adata = (VGbyte *)array->data;
+   memcpy(adata + (array->num_elements * array->datatype_size), data,
+          num_elements * array->datatype_size);
+   array->num_elements += num_elements;
+}
+
+static INLINE void array_change_data(struct array *array,
+                              const void *data,
+                              int start_idx,
+                              int num_elements)
+{
+   VGbyte *adata = (VGbyte *)array->data;
+   memcpy(adata + (start_idx * array->datatype_size), data,
+          num_elements * array->datatype_size);
+}
+
+static INLINE void array_remove_element(struct array *array,
+                                        int idx)
+{
+   VGbyte *adata = (VGbyte *)array->data;
+   memmove(adata + (idx * array->datatype_size),
+           adata + ((idx + 1) * array->datatype_size),
+           (array->num_elements - idx - 1) * array->datatype_size);
+   --array->num_elements;
+}
+
+static INLINE void array_reset(struct array *array)
+{
+   array->num_elements = 0;
+}
+
+#endif
diff --git a/src/gallium/state_trackers/vega/vg_context.c b/src/gallium/state_trackers/vega/vg_context.c
new file mode 100644 (file)
index 0000000..e0ff02f
--- /dev/null
@@ -0,0 +1,543 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#include "vg_context.h"
+
+#include "paint.h"
+#include "renderer.h"
+#include "shaders_cache.h"
+#include "shader.h"
+#include "asm_util.h"
+#include "st_inlines.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_inlines.h"
+#include "pipe/p_shader_tokens.h"
+
+#include "cso_cache/cso_context.h"
+
+#include "util/u_simple_shaders.h"
+#include "util/u_memory.h"
+#include "util/u_blit.h"
+
+struct vg_context *_vg_context = 0;
+
+struct vg_context * vg_current_context(void)
+{
+   return _vg_context;
+}
+
+static void init_clear(struct vg_context *st)
+{
+   struct pipe_context *pipe = st->pipe;
+
+   /* rasterizer state: bypass clipping */
+   memset(&st->clear.raster, 0, sizeof(st->clear.raster));
+   st->clear.raster.gl_rasterization_rules = 1;
+
+   /* fragment shader state: color pass-through program */
+   st->clear.fs =
+      util_make_fragment_passthrough_shader(pipe);
+}
+void vg_set_current_context(struct vg_context *ctx)
+{
+   _vg_context = ctx;
+}
+
+struct vg_context * vg_create_context(struct pipe_context *pipe,
+                                      const void *visual,
+                                      struct vg_context *share)
+{
+   struct vg_context *ctx;
+
+   ctx = CALLOC_STRUCT(vg_context);
+
+   ctx->pipe = pipe;
+
+   vg_init_state(&ctx->state.vg);
+   ctx->state.dirty = ALL_DIRTY;
+
+   ctx->cso_context = cso_create_context(pipe);
+
+   init_clear(ctx);
+
+   ctx->default_paint = paint_create(ctx);
+   ctx->state.vg.stroke_paint = ctx->default_paint;
+   ctx->state.vg.fill_paint = ctx->default_paint;
+
+
+   ctx->mask.sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+   ctx->mask.sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+   ctx->mask.sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
+   ctx->mask.sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
+   ctx->mask.sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
+   ctx->mask.sampler.normalized_coords = 0;
+
+   ctx->blend_sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+   ctx->blend_sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+   ctx->blend_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
+   ctx->blend_sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
+   ctx->blend_sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
+   ctx->blend_sampler.normalized_coords = 0;
+
+   vg_set_error(ctx, VG_NO_ERROR);
+
+   ctx->owned_objects[VG_OBJECT_PAINT] = cso_hash_create();
+   ctx->owned_objects[VG_OBJECT_IMAGE] = cso_hash_create();
+   ctx->owned_objects[VG_OBJECT_MASK] = cso_hash_create();
+   ctx->owned_objects[VG_OBJECT_FONT] = cso_hash_create();
+   ctx->owned_objects[VG_OBJECT_PATH] = cso_hash_create();
+
+   ctx->renderer = renderer_create(ctx);
+   ctx->sc = shaders_cache_create(ctx);
+   ctx->shader = shader_create(ctx);
+
+   ctx->blit = util_create_blit(ctx->pipe, ctx->cso_context);
+
+   return ctx;
+}
+
+void vg_destroy_context(struct vg_context *ctx)
+{
+   struct pipe_constant_buffer *cbuf = &ctx->mask.cbuf;
+   struct pipe_constant_buffer *vsbuf = &ctx->vs_const_buffer;
+
+   util_destroy_blit(ctx->blit);
+   renderer_destroy(ctx->renderer);
+   shaders_cache_destroy(ctx->sc);
+   shader_destroy(ctx->shader);
+   paint_destroy(ctx->default_paint);
+
+   if (cbuf && cbuf->buffer)
+      pipe_buffer_reference(&cbuf->buffer, NULL);
+
+   if (vsbuf && vsbuf->buffer)
+      pipe_buffer_reference(&vsbuf->buffer, NULL);
+
+   if (ctx->clear.fs) {
+      cso_delete_fragment_shader(ctx->cso_context, ctx->clear.fs);
+      ctx->clear.fs = NULL;
+   }
+
+   if (ctx->plain_vs) {
+      vg_shader_destroy(ctx, ctx->plain_vs);
+      ctx->plain_vs = NULL;
+   }
+   if (ctx->clear_vs) {
+      vg_shader_destroy(ctx, ctx->clear_vs);
+      ctx->clear_vs = NULL;
+   }
+   if (ctx->texture_vs) {
+      vg_shader_destroy(ctx, ctx->texture_vs);
+      ctx->texture_vs = NULL;
+   }
+
+   if (ctx->pass_through_depth_fs)
+      vg_shader_destroy(ctx, ctx->pass_through_depth_fs);
+   if (ctx->mask.union_fs)
+      vg_shader_destroy(ctx, ctx->mask.union_fs);
+   if (ctx->mask.intersect_fs)
+      vg_shader_destroy(ctx, ctx->mask.intersect_fs);
+   if (ctx->mask.subtract_fs)
+      vg_shader_destroy(ctx, ctx->mask.subtract_fs);
+   if (ctx->mask.set_fs)
+      vg_shader_destroy(ctx, ctx->mask.set_fs);
+
+   cso_release_all(ctx->cso_context);
+   cso_destroy_context(ctx->cso_context);
+
+   cso_hash_delete(ctx->owned_objects[VG_OBJECT_PAINT]);
+   cso_hash_delete(ctx->owned_objects[VG_OBJECT_IMAGE]);
+   cso_hash_delete(ctx->owned_objects[VG_OBJECT_MASK]);
+   cso_hash_delete(ctx->owned_objects[VG_OBJECT_FONT]);
+   cso_hash_delete(ctx->owned_objects[VG_OBJECT_PATH]);
+
+   free(ctx);
+}
+
+void vg_init_object(struct vg_object *obj, struct vg_context *ctx, enum vg_object_type type)
+{
+   obj->type = type;
+   obj->ctx = ctx;
+}
+
+VGboolean vg_context_is_object_valid(struct vg_context *ctx,
+                                enum vg_object_type type,
+                                void *ptr)
+{
+    if (ctx) {
+       struct cso_hash *hash = ctx->owned_objects[type];
+       if (!hash)
+          return VG_FALSE;
+       return cso_hash_contains(hash, (unsigned)(long)ptr);
+    }
+    return VG_FALSE;
+}
+
+void vg_context_add_object(struct vg_context *ctx,
+                           enum vg_object_type type,
+                           void *ptr)
+{
+    if (ctx) {
+       struct cso_hash *hash = ctx->owned_objects[type];
+       if (!hash)
+          return;
+       cso_hash_insert(hash, (unsigned)(long)ptr, ptr);
+    }
+}
+
+void vg_context_remove_object(struct vg_context *ctx,
+                              enum vg_object_type type,
+                              void *ptr)
+{
+   if (ctx) {
+      struct cso_hash *hash = ctx->owned_objects[type];
+      if (!hash)
+         return;
+      cso_hash_take(hash, (unsigned)(long)ptr);
+   }
+}
+
+static void update_clip_state(struct vg_context *ctx)
+{
+   struct pipe_depth_stencil_alpha_state *dsa = &ctx->state.g3d.dsa;
+   struct vg_state *state =  &ctx->state.vg;
+
+   memset(dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state));
+
+   if (state->scissoring) {
+      struct pipe_blend_state *blend = &ctx->state.g3d.blend;
+      struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb;
+      dsa->depth.writemask = 1;/*glDepthMask(TRUE);*/
+      dsa->depth.func = PIPE_FUNC_ALWAYS;
+      dsa->depth.enabled = 1;
+
+      cso_save_blend(ctx->cso_context);
+      cso_save_fragment_shader(ctx->cso_context);
+      /* set a passthrough shader */
+      if (!ctx->pass_through_depth_fs)
+         ctx->pass_through_depth_fs = shader_create_from_text(ctx->pipe,
+                                                              pass_through_depth_asm,
+                                                              40,
+                                                              PIPE_SHADER_FRAGMENT);
+      cso_set_fragment_shader_handle(ctx->cso_context,
+                                     ctx->pass_through_depth_fs->driver);
+      cso_set_depth_stencil_alpha(ctx->cso_context, dsa);
+
+      ctx->pipe->clear(ctx->pipe, PIPE_CLEAR_DEPTHSTENCIL, NULL, 1.0, 0);
+
+      /* disable color writes */
+      blend->colormask = 0; /*disable colorwrites*/
+      cso_set_blend(ctx->cso_context, blend);
+
+      /* enable scissoring */
+      for (int i = 0; i < state->scissor_rects_num; ++i) {
+         const float x      = state->scissor_rects[i * 4 + 0].f;
+         const float y      = state->scissor_rects[i * 4 + 1].f;
+         const float width  = state->scissor_rects[i * 4 + 2].f;
+         const float height = state->scissor_rects[i * 4 + 3].f;
+         VGfloat minx, miny, maxx, maxy;
+
+         minx = 0;
+         miny = 0;
+         maxx = fb->width;
+         maxy = fb->height;
+
+         if (x > minx)
+            minx = x;
+         if (y > miny)
+            miny = y;
+
+         if (x + width < maxx)
+            maxx = x + width;
+         if (y + height < maxy)
+            maxy = y + height;
+
+         /* check for null space */
+         if (minx >= maxx || miny >= maxy)
+            minx = miny = maxx = maxy = 0;
+
+         /*glClear(GL_DEPTH_BUFFER_BIT);*/
+         renderer_draw_quad(ctx->renderer, minx, miny, maxx, maxy, 0.0f);
+      }
+
+      blend->colormask = 1; /*enable colorwrites*/
+      cso_restore_blend(ctx->cso_context);
+      cso_restore_fragment_shader(ctx->cso_context);
+
+      dsa->depth.enabled = 1; /* glEnable(GL_DEPTH_TEST); */
+      dsa->depth.writemask = 0;/*glDepthMask(FALSE);*/
+      dsa->depth.func = PIPE_FUNC_GEQUAL;
+   }
+}
+
+void vg_validate_state(struct vg_context *ctx)
+{
+   if ((ctx->state.dirty & BLEND_DIRTY)) {
+      struct pipe_blend_state *blend = &ctx->state.g3d.blend;
+      memset(blend, 0, sizeof(struct pipe_blend_state));
+      blend->blend_enable = 1;
+      blend->colormask |= PIPE_MASK_R;
+      blend->colormask |= PIPE_MASK_G;
+      blend->colormask |= PIPE_MASK_B;
+      blend->colormask |= PIPE_MASK_A;
+
+      switch (ctx->state.vg.blend_mode) {
+      case VG_BLEND_SRC:
+         blend->rgb_src_factor   = PIPE_BLENDFACTOR_ONE;
+         blend->alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+         blend->rgb_dst_factor   = PIPE_BLENDFACTOR_ZERO;
+         blend->alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
+         break;
+      case VG_BLEND_SRC_OVER:
+         blend->rgb_src_factor   = PIPE_BLENDFACTOR_SRC_ALPHA;
+         blend->alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+         blend->rgb_dst_factor   = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
+         blend->alpha_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
+         break;
+      case VG_BLEND_DST_OVER:
+         blend->rgb_src_factor   = PIPE_BLENDFACTOR_INV_DST_ALPHA;
+         blend->alpha_src_factor = PIPE_BLENDFACTOR_INV_DST_ALPHA;
+         blend->rgb_dst_factor   = PIPE_BLENDFACTOR_DST_ALPHA;
+         blend->alpha_dst_factor = PIPE_BLENDFACTOR_DST_ALPHA;
+         break;
+      case VG_BLEND_SRC_IN:
+         blend->rgb_src_factor   = PIPE_BLENDFACTOR_DST_ALPHA;
+         blend->alpha_src_factor = PIPE_BLENDFACTOR_DST_ALPHA;
+         blend->rgb_dst_factor   = PIPE_BLENDFACTOR_ZERO;
+         blend->alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
+         break;
+      case VG_BLEND_DST_IN:
+         blend->rgb_src_factor   = PIPE_BLENDFACTOR_ZERO;
+         blend->alpha_src_factor = PIPE_BLENDFACTOR_ZERO;
+         blend->rgb_dst_factor   = PIPE_BLENDFACTOR_SRC_ALPHA;
+         blend->alpha_dst_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
+         break;
+      case VG_BLEND_MULTIPLY:
+      case VG_BLEND_SCREEN:
+      case VG_BLEND_DARKEN:
+      case VG_BLEND_LIGHTEN:
+         blend->rgb_src_factor   = PIPE_BLENDFACTOR_ONE;
+         blend->alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+         blend->rgb_dst_factor   = PIPE_BLENDFACTOR_ZERO;
+         blend->alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
+         break;
+      case VG_BLEND_ADDITIVE:
+         blend->rgb_src_factor   = PIPE_BLENDFACTOR_ONE;
+         blend->alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+         blend->rgb_dst_factor   = PIPE_BLENDFACTOR_ONE;
+         blend->alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
+         break;
+      default:
+         assert(!"not implemented blend mode");
+      }
+      cso_set_blend(ctx->cso_context, &ctx->state.g3d.blend);
+   }
+   if ((ctx->state.dirty & RASTERIZER_DIRTY)) {
+      struct pipe_rasterizer_state *raster = &ctx->state.g3d.rasterizer;
+      memset(raster, 0, sizeof(struct pipe_rasterizer_state));
+      raster->gl_rasterization_rules = 1;
+      cso_set_rasterizer(ctx->cso_context, &ctx->state.g3d.rasterizer);
+   }
+   if ((ctx->state.dirty & VIEWPORT_DIRTY)) {
+      struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb;
+      const VGint param_bytes = 8 * sizeof(VGfloat);
+      VGfloat vs_consts[8] = {
+         2.f/fb->width, 2.f/fb->height, 1, 1,
+         -1, -1, 0, 0
+      };
+      struct pipe_constant_buffer *cbuf = &ctx->vs_const_buffer;
+
+      vg_set_viewport(ctx, VEGA_Y0_BOTTOM);
+
+      pipe_buffer_reference(&cbuf->buffer, NULL);
+      cbuf->buffer = pipe_buffer_create(ctx->pipe->screen, 16,
+                                        PIPE_BUFFER_USAGE_CONSTANT,
+                                        param_bytes);
+
+      if (cbuf->buffer) {
+         st_no_flush_pipe_buffer_write(ctx, cbuf->buffer,
+                                       0, param_bytes, vs_consts);
+      }
+      ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_VERTEX, 0, cbuf);
+   }
+   if ((ctx->state.dirty & VS_DIRTY)) {
+      cso_set_vertex_shader_handle(ctx->cso_context,
+                                   vg_plain_vs(ctx));
+   }
+
+   /* must be last because it renders to the depth buffer*/
+   if ((ctx->state.dirty & DEPTH_STENCIL_DIRTY)) {
+      update_clip_state(ctx);
+      cso_set_depth_stencil_alpha(ctx->cso_context, &ctx->state.g3d.dsa);
+   }
+
+   shader_set_masking(ctx->shader, ctx->state.vg.masking);
+   shader_set_image_mode(ctx->shader, ctx->state.vg.image_mode);
+
+   ctx->state.dirty = NONE_DIRTY;
+}
+
+VGboolean vg_object_is_valid(void *ptr, enum vg_object_type type)
+{
+   struct vg_object *obj = ptr;
+   if (ptr && is_aligned(obj) && obj->type == type)
+      return VG_TRUE;
+   else
+      return VG_FALSE;
+}
+
+void vg_set_error(struct vg_context *ctx,
+                  VGErrorCode code)
+{
+   /*vgGetError returns the oldest error code provided by
+    * an API call on the current context since the previous
+    * call to vgGetError on that context (or since the creation
+    of the context).*/
+   if (ctx->_error == VG_NO_ERROR)
+      ctx->_error = code;
+}
+
+void vg_prepare_blend_surface(struct vg_context *ctx)
+{
+   struct pipe_surface *dest_surface = NULL;
+   struct pipe_context *pipe = ctx->pipe;
+   struct st_framebuffer *stfb = ctx->draw_buffer;
+   struct st_renderbuffer *strb = stfb->strb;
+
+   /* first finish all pending rendering */
+   vgFinish();
+
+   dest_surface = pipe->screen->get_tex_surface(pipe->screen,
+                                                stfb->blend_texture,
+                                                0, 0, 0,
+                                                PIPE_BUFFER_USAGE_GPU_WRITE);
+   /* flip it, because we want to use it as a sampler */
+   util_blit_pixels_tex(ctx->blit,
+                        strb->texture,
+                        0, strb->height,
+                        strb->width, 0,
+                        dest_surface,
+                        0, 0,
+                        strb->width, strb->height,
+                        0.0, PIPE_TEX_MIPFILTER_NEAREST);
+
+   if (dest_surface)
+      pipe_surface_reference(&dest_surface, NULL);
+
+   /* make sure it's complete */
+   vgFinish();
+}
+
+
+void vg_prepare_blend_surface_from_mask(struct vg_context *ctx)
+{
+   struct pipe_surface *dest_surface = NULL;
+   struct pipe_context *pipe = ctx->pipe;
+   struct st_framebuffer *stfb = ctx->draw_buffer;
+   struct st_renderbuffer *strb = stfb->strb;
+
+   vg_validate_state(ctx);
+
+   /* first finish all pending rendering */
+   vgFinish();
+
+   dest_surface = pipe->screen->get_tex_surface(pipe->screen,
+                                                stfb->blend_texture,
+                                                0, 0, 0,
+                                                PIPE_BUFFER_USAGE_GPU_WRITE);
+
+   /* flip it, because we want to use it as a sampler */
+   util_blit_pixels_tex(ctx->blit,
+                        stfb->alpha_mask,
+                        0, strb->height,
+                        strb->width, 0,
+                        dest_surface,
+                        0, 0,
+                        strb->width, strb->height,
+                        0.0, PIPE_TEX_MIPFILTER_NEAREST);
+
+   /* make sure it's complete */
+   vgFinish();
+
+   if (dest_surface)
+      pipe_surface_reference(&dest_surface, NULL);
+}
+
+void * vg_plain_vs(struct vg_context *ctx)
+{
+   if (!ctx->plain_vs) {
+      ctx->plain_vs = shader_create_from_text(ctx->pipe,
+                                              vs_plain_asm,
+                                              200,
+                                              PIPE_SHADER_VERTEX);
+   }
+
+   return ctx->plain_vs->driver;
+}
+
+
+void * vg_clear_vs(struct vg_context *ctx)
+{
+   if (!ctx->clear_vs) {
+      ctx->clear_vs = shader_create_from_text(ctx->pipe,
+                                              vs_clear_asm,
+                                              200,
+                                              PIPE_SHADER_VERTEX);
+   }
+
+   return ctx->clear_vs->driver;
+}
+
+void * vg_texture_vs(struct vg_context *ctx)
+{
+   if (!ctx->texture_vs) {
+      ctx->texture_vs = shader_create_from_text(ctx->pipe,
+                                                vs_texture_asm,
+                                                200,
+                                                PIPE_SHADER_VERTEX);
+   }
+
+   return ctx->texture_vs->driver;
+}
+
+void vg_set_viewport(struct vg_context *ctx, VegaOrientation orientation)
+{
+   struct pipe_viewport_state viewport;
+   struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb;
+   VGfloat y_scale = (orientation == VEGA_Y0_BOTTOM) ? -2.f : 2.f;
+
+   viewport.scale[0] =  fb->width / 2.f;
+   viewport.scale[1] =  fb->height / y_scale;
+   viewport.scale[2] =  1.0;
+   viewport.scale[3] =  1.0;
+   viewport.translate[0] = fb->width / 2.f;
+   viewport.translate[1] = fb->height / 2.f;
+   viewport.translate[2] = 0.0;
+   viewport.translate[3] = 0.0;
+
+   cso_set_viewport(ctx->cso_context, &viewport);
+}
diff --git a/src/gallium/state_trackers/vega/vg_context.h b/src/gallium/state_trackers/vega/vg_context.h
new file mode 100644 (file)
index 0000000..ccc8889
--- /dev/null
@@ -0,0 +1,292 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#ifndef VG_CONTEXT_H
+#define VG_CONTEXT_H
+
+#include "vg_state.h"
+
+#include "pipe/p_format.h"
+#include "pipe/p_state.h"
+#include "util/u_pointer.h"
+#include "util/u_math.h"
+
+#include "cso_cache/cso_hash.h"
+#include "cso_cache/cso_context.h"
+
+struct renderer;
+struct shaders_cache;
+struct shader;
+struct vg_shader;
+
+struct st_renderbuffer {
+   enum pipe_format   format;
+   struct pipe_surface *surface;
+   struct pipe_texture *texture;
+   VGint width, height;
+};
+
+struct st_framebuffer {
+   VGint init_width, init_height;
+   struct st_renderbuffer *strb;
+   struct st_renderbuffer *dsrb;
+
+   struct pipe_texture *alpha_mask;
+
+   struct pipe_texture *blend_texture;
+
+   void *privateData;
+};
+
+enum vg_object_type {
+   VG_OBJECT_UNKNOWN = 0,
+   VG_OBJECT_PAINT,
+   VG_OBJECT_IMAGE,
+   VG_OBJECT_MASK,
+   VG_OBJECT_FONT,
+   VG_OBJECT_PATH,
+
+   VG_OBJECT_LAST
+};
+enum dirty_state {
+   NONE_DIRTY          = 0<<0,
+   BLEND_DIRTY         = 1<<1,
+   RASTERIZER_DIRTY    = 1<<2,
+   VIEWPORT_DIRTY      = 1<<3,
+   VS_DIRTY            = 1<<4,
+   DEPTH_STENCIL_DIRTY = 1<<5,
+   ALL_DIRTY           = BLEND_DIRTY | RASTERIZER_DIRTY |
+   VIEWPORT_DIRTY | VS_DIRTY | DEPTH_STENCIL_DIRTY
+};
+
+struct vg_context
+{
+   struct pipe_context *pipe;
+
+   struct {
+      struct vg_state vg;
+      struct {
+         struct pipe_blend_state blend;
+         struct pipe_rasterizer_state rasterizer;
+         struct pipe_shader_state vs_state;
+         struct pipe_depth_stencil_alpha_state dsa;
+         struct pipe_framebuffer_state fb;
+      } g3d;
+      VGbitfield dirty;
+   } state;
+
+   VGErrorCode _error;
+
+   struct st_framebuffer *draw_buffer;
+
+   struct cso_hash *owned_objects[VG_OBJECT_LAST];
+
+   struct {
+      struct pipe_shader_state vert_shader;
+      struct pipe_shader_state frag_shader;
+      struct pipe_rasterizer_state raster;
+      void *fs;
+      float vertices[4][2][4];  /**< vertex pos + color */
+   } clear;
+
+   struct {
+      struct pipe_constant_buffer cbuf;
+      struct pipe_sampler_state sampler;
+
+      struct vg_shader *union_fs;
+      struct vg_shader *intersect_fs;
+      struct vg_shader *subtract_fs;
+      struct vg_shader *set_fs;
+   } mask;
+
+   struct vg_shader *pass_through_depth_fs;
+
+   struct cso_context *cso_context;
+
+   struct pipe_buffer *stencil_quad;
+   VGfloat stencil_vertices[4][2][4];
+
+   struct renderer *renderer;
+   struct shaders_cache *sc;
+   struct shader *shader;
+
+   struct pipe_sampler_state blend_sampler;
+   struct {
+      struct pipe_constant_buffer buffer;
+      void *color_matrix_fs;
+   } filter;
+   struct vg_paint *default_paint;
+
+   struct blit_state *blit;
+
+   struct vg_shader *plain_vs;
+   struct vg_shader *clear_vs;
+   struct vg_shader *texture_vs;
+   struct pipe_constant_buffer vs_const_buffer;
+};
+
+struct vg_object {
+   enum vg_object_type type;
+   struct vg_context *ctx;
+};
+void vg_init_object(struct vg_object *obj, struct vg_context *ctx, enum vg_object_type type);
+VGboolean vg_object_is_valid(void *ptr, enum vg_object_type type);
+
+struct vg_context *vg_create_context(struct pipe_context *pipe,
+                                     const void *visual,
+                                     struct vg_context *share);
+void vg_destroy_context(struct vg_context *ctx);
+struct vg_context *vg_current_context(void);
+void vg_set_current_context(struct vg_context *ctx);
+
+VGboolean vg_context_is_object_valid(struct vg_context *ctx,
+                                     enum vg_object_type type,
+                                     void *ptr);
+void vg_context_add_object(struct vg_context *ctx,
+                           enum vg_object_type type,
+                           void *ptr);
+void vg_context_remove_object(struct vg_context *ctx,
+                              enum vg_object_type type,
+                              void *ptr);
+
+void vg_validate_state(struct vg_context *ctx);
+
+void vg_set_error(struct vg_context *ctx,
+                  VGErrorCode code);
+
+void vg_prepare_blend_surface(struct vg_context *ctx);
+void vg_prepare_blend_surface_from_mask(struct vg_context *ctx);
+
+
+static INLINE VGboolean is_aligned_to(const void *ptr, VGbyte alignment)
+{
+   void *aligned = align_pointer(ptr, alignment);
+   return (ptr == aligned) ? VG_TRUE : VG_FALSE;
+}
+
+static INLINE VGboolean is_aligned(const void *ptr)
+{
+   return is_aligned_to(ptr, 4);
+}
+
+static INLINE void vg_shift_rectx(VGfloat coords[4],
+                                 const VGfloat *bounds,
+                                 const VGfloat shift)
+{
+   coords[0] += shift;
+   coords[2] -= shift;
+   if (bounds) {
+      coords[2] = MIN2(coords[2], bounds[2]);
+      /* bound x/y + width/height */
+      if ((coords[0] + coords[2]) > (bounds[0] + bounds[2])) {
+         coords[2] = (bounds[0] + bounds[2]) - coords[0];
+      }
+   }
+}
+
+static INLINE void vg_shift_recty(VGfloat coords[4],
+                                 const VGfloat *bounds,
+                                 const VGfloat shift)
+{
+   coords[1] += shift;
+   coords[3] -= shift;
+   if (bounds) {
+      coords[3] = MIN2(coords[3], bounds[3]);
+      if ((coords[1] + coords[3]) > (bounds[1] + bounds[3])) {
+         coords[3] = (bounds[1] + bounds[3]) - coords[1];
+      }
+   }
+}
+
+static INLINE void vg_bound_rect(VGfloat coords[4],
+                                 const VGfloat bounds[4],
+                                 VGfloat shift[4])
+{
+   /* if outside the bounds */
+   if (coords[0] > (bounds[0] + bounds[2]) ||
+       coords[1] > (bounds[1] + bounds[3]) ||
+       (coords[0] + coords[2]) < bounds[0] ||
+       (coords[1] + coords[3]) < bounds[1]) {
+      coords[0] = 0.f;
+      coords[1] = 0.f;
+      coords[2] = 0.f;
+      coords[3] = 0.f;
+      shift[0] = 0.f;
+      shift[1] = 0.f;
+      return;
+   }
+
+   /* bound x */
+   if (coords[0] < bounds[0]) {
+      shift[0] = bounds[0] - coords[0];
+      coords[2] -= shift[0];
+      coords[0] = bounds[0];
+   } else
+      shift[0] = 0.f;
+
+   /* bound y */
+   if (coords[1] < bounds[1]) {
+      shift[1] = bounds[1] - coords[1];
+      coords[3] -= shift[1];
+      coords[1] = bounds[1];
+   } else
+      shift[1] = 0.f;
+
+   shift[2] = bounds[2] - coords[2];
+   shift[3] = bounds[3] - coords[3];
+   /* bound width/height */
+   coords[2] = MIN2(coords[2], bounds[2]);
+   coords[3] = MIN2(coords[3], bounds[3]);
+
+   /* bound x/y + width/height */
+   if ((coords[0] + coords[2]) > (bounds[0] + bounds[2])) {
+      coords[2] = (bounds[0] + bounds[2]) - coords[0];
+   }
+   if ((coords[1] + coords[3]) > (bounds[1] + bounds[3])) {
+      coords[3] = (bounds[1] + bounds[3]) - coords[1];
+   }
+
+   /* if outside the bounds */
+   if ((coords[0] + coords[2]) < bounds[0] ||
+       (coords[1] + coords[3]) < bounds[1]) {
+      coords[0] = 0.f;
+      coords[1] = 0.f;
+      coords[2] = 0.f;
+      coords[3] = 0.f;
+      return;
+   }
+}
+
+void *vg_plain_vs(struct vg_context *ctx);
+void *vg_clear_vs(struct vg_context *ctx);
+void *vg_texture_vs(struct vg_context *ctx);
+typedef enum {
+   VEGA_Y0_TOP,
+   VEGA_Y0_BOTTOM
+} VegaOrientation;
+void vg_set_viewport(struct vg_context *ctx, VegaOrientation orientation);
+
+#endif
diff --git a/src/gallium/state_trackers/vega/vg_state.c b/src/gallium/state_trackers/vega/vg_state.c
new file mode 100644 (file)
index 0000000..6f6bfda
--- /dev/null
@@ -0,0 +1,124 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#include "vg_state.h"
+
+#include <string.h>
+
+void vg_init_state(struct vg_state *state)
+{
+   state->matrix_mode = VG_MATRIX_PATH_USER_TO_SURFACE;
+   state->fill_rule = VG_EVEN_ODD;
+   state->image_quality = VG_IMAGE_QUALITY_FASTER;
+   state->rendering_quality = VG_RENDERING_QUALITY_BETTER;
+   state->blend_mode = VG_BLEND_SRC_OVER;
+   state->image_mode = VG_DRAW_IMAGE_NORMAL;
+
+   memset(state->scissor_rects, 0, sizeof(state->scissor_rects));
+   state->scissor_rects_num = 0;
+
+   state->color_transform = VG_FALSE;
+   state->color_transform_values[0] = 1.0f;
+   state->color_transform_values[1] = 1.0f;
+   state->color_transform_values[2] = 1.0f;
+   state->color_transform_values[3] = 1.0f;
+   state->color_transform_values[4] = 0.0f;
+   state->color_transform_values[5] = 0.0f;
+   state->color_transform_values[6] = 0.0f;
+   state->color_transform_values[7] = 0.0f;
+
+   /* Stroke parameters */
+   state->stroke.line_width.f       = 1.0f;
+   state->stroke.line_width.i       = 1;
+   state->stroke.cap_style        = VG_CAP_BUTT;
+   state->stroke.join_style       = VG_JOIN_MITER;
+   state->stroke.miter_limit.f      = 4.0f;
+   state->stroke.miter_limit.i      = 4;
+   state->stroke.dash_pattern_num = 0;
+   state->stroke.dash_phase.f       = 0.0f;
+   state->stroke.dash_phase.i       = 0;
+   state->stroke.dash_phase_reset = VG_FALSE;
+
+   /* Edge fill color for VG_TILE_FILL tiling mode */
+   state->tile_fill_color[0] = 0.0f;
+   state->tile_fill_color[1] = 0.0f;
+   state->tile_fill_color[2] = 0.0f;
+   state->tile_fill_color[3] = 0.0f;
+
+   /* Color for vgClear */
+   state->clear_color[0] = 0.0f;
+   state->clear_color[1] = 0.0f;
+   state->clear_color[2] = 0.0f;
+   state->clear_color[3] = 0.0f;
+
+   /* Glyph origin */
+   state->glyph_origin[0].f = 0.0f;
+   state->glyph_origin[1].f = 0.0f;
+   state->glyph_origin[0].i = 0;
+   state->glyph_origin[1].i = 0;
+
+   /* Enable/disable alpha masking and scissoring */
+   state->masking = VG_FALSE;
+   state->scissoring = VG_FALSE;
+
+   /* Pixel layout information */
+   state->pixel_layout = VG_PIXEL_LAYOUT_UNKNOWN;
+   state->screen_layout = VG_PIXEL_LAYOUT_UNKNOWN;
+
+   /* Source format selection for image filters */
+   state->filter_format_linear = VG_FALSE;
+   state->filter_format_premultiplied = VG_FALSE;
+
+   /* Destination write enable mask for image filters */
+   state->filter_channel_mask = (VG_RED | VG_GREEN | VG_BLUE | VG_ALPHA);
+
+   matrix_load_identity(&state->path_user_to_surface_matrix);
+   matrix_load_identity(&state->image_user_to_surface_matrix);
+   matrix_load_identity(&state->fill_paint_to_user_matrix);
+   matrix_load_identity(&state->stroke_paint_to_user_matrix);
+   matrix_load_identity(&state->glyph_user_to_surface_matrix);
+}
+
+struct matrix *vg_state_matrix(struct vg_state *state)
+{
+    switch(state->matrix_mode) {
+    case VG_MATRIX_PATH_USER_TO_SURFACE:
+       return &state->path_user_to_surface_matrix;
+    case VG_MATRIX_IMAGE_USER_TO_SURFACE:
+       return &state->image_user_to_surface_matrix;
+    case VG_MATRIX_FILL_PAINT_TO_USER:
+       return &state->fill_paint_to_user_matrix;
+    case VG_MATRIX_STROKE_PAINT_TO_USER:
+       return &state->stroke_paint_to_user_matrix;
+#ifdef OPENVG_VERSION_1_1
+    case VG_MATRIX_GLYPH_USER_TO_SURFACE:
+       return &state->glyph_user_to_surface_matrix;
+#endif
+    default:
+       break;
+    }
+    return NULL;
+}
diff --git a/src/gallium/state_trackers/vega/vg_state.h b/src/gallium/state_trackers/vega/vg_state.h
new file mode 100644 (file)
index 0000000..ed90689
--- /dev/null
@@ -0,0 +1,109 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#ifndef VG_STATE_H
+#define VG_STATE_H
+
+#include "VG/openvg.h"
+
+#include "api_consts.h"
+#include "matrix.h"
+
+struct vg_value
+{
+   VGfloat f;
+   VGint   i;
+};
+
+struct vg_state {
+   /* Mode settings */
+   VGMatrixMode matrix_mode;
+   VGFillRule fill_rule;
+   VGImageQuality image_quality;
+   VGRenderingQuality rendering_quality;
+   VGBlendMode blend_mode;
+   VGImageMode image_mode;
+
+   /* Scissoring rectangles */
+   struct vg_value  scissor_rects[32*4];
+   VGint  scissor_rects_num;
+
+   /* Color Transformation */
+   VGboolean color_transform;
+   VGfloat color_transform_values[8];
+
+   /* Stroke parameters */
+   struct {
+      struct vg_value line_width;
+      VGCapStyle cap_style;
+      VGJoinStyle join_style;
+      struct vg_value miter_limit;
+      struct vg_value dash_pattern[VEGA_MAX_DASH_COUNT];
+      VGint   dash_pattern_num;
+      struct vg_value dash_phase;
+      VGboolean dash_phase_reset;
+   } stroke;
+
+   /* Edge fill color for VG_TILE_FILL tiling mode */
+   VGfloat tile_fill_color[4];
+   VGint tile_fill_colori[4];
+
+   /* Color for vgClear */
+   VGfloat clear_color[4];
+   VGint clear_colori[4];
+
+   /* Glyph origin */
+   struct vg_value glyph_origin[2];
+
+   /* Enable/disable alpha masking and scissoring */
+   VGboolean masking;
+   VGboolean scissoring;
+
+   /* Pixel layout information */
+   VGPixelLayout pixel_layout;
+   VGPixelLayout screen_layout;
+
+   /* Source format selection for image filters */
+   VGboolean filter_format_linear;
+   VGboolean filter_format_premultiplied;
+
+   /* Destination write enable mask for image filters */
+   VGbitfield filter_channel_mask;
+
+   struct matrix path_user_to_surface_matrix;
+   struct matrix image_user_to_surface_matrix;
+   struct matrix fill_paint_to_user_matrix;
+   struct matrix stroke_paint_to_user_matrix;
+   struct matrix glyph_user_to_surface_matrix;
+
+   struct vg_paint *stroke_paint;
+   struct vg_paint *fill_paint;
+};
+
+void vg_init_state(struct vg_state *state);
+struct matrix * vg_state_matrix(struct vg_state *state);
+
+#endif
diff --git a/src/gallium/state_trackers/vega/vg_tracker.c b/src/gallium/state_trackers/vega/vg_tracker.c
new file mode 100644 (file)
index 0000000..c262ce0
--- /dev/null
@@ -0,0 +1,406 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#include "vg_context.h"
+#include "vg_tracker.h"
+#include "mask.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_inlines.h"
+#include "pipe/p_screen.h"
+#include "util/u_memory.h"
+#include "util/u_math.h"
+
+static struct pipe_texture *
+create_texture(struct pipe_context *pipe, enum pipe_format format,
+               VGint width, VGint height)
+{
+   struct pipe_texture templ;
+
+   memset(&templ, 0, sizeof(templ));
+
+   if (format != PIPE_FORMAT_NONE) {
+      templ.format = format;
+   }
+   else {
+      templ.format = PIPE_FORMAT_A8R8G8B8_UNORM;
+   }
+
+   templ.target = PIPE_TEXTURE_2D;
+   pf_get_block(templ.format, &templ.block);
+   templ.width[0] = width;
+   templ.height[0] = height;
+   templ.depth[0] = 1;
+   templ.last_level = 0;
+
+   if (pf_get_component_bits(format, PIPE_FORMAT_COMP_S)) {
+      templ.tex_usage = PIPE_TEXTURE_USAGE_DEPTH_STENCIL;
+   } else {
+      templ.tex_usage = (PIPE_TEXTURE_USAGE_DISPLAY_TARGET |
+                         PIPE_TEXTURE_USAGE_RENDER_TARGET |
+                         PIPE_TEXTURE_USAGE_SAMPLER);
+   }
+
+   return pipe->screen->texture_create(pipe->screen, &templ);
+}
+
+/**
+ * Allocate a renderbuffer for a an on-screen window (not a user-created
+ * renderbuffer).  The window system code determines the format.
+ */
+static struct st_renderbuffer *
+st_new_renderbuffer_fb(enum pipe_format format)
+{
+   struct st_renderbuffer *strb;
+
+   strb = CALLOC_STRUCT(st_renderbuffer);
+   if (!strb) {
+      /*_vega_error(NULL, VG_OUT_OF_MEMORY, "creating renderbuffer");*/
+      return NULL;
+   }
+
+   strb->format = format;
+
+   return strb;
+}
+
+
+/**
+ * This is called to allocate the original drawing surface, and
+ * during window resize.
+ */
+static VGboolean
+st_renderbuffer_alloc_storage(struct vg_context * ctx,
+                              struct st_renderbuffer *strb,
+                              VGuint width, VGuint height)
+{
+   struct pipe_context *pipe = ctx->pipe;
+   unsigned surface_usage;
+
+   /* Free the old surface and texture
+    */
+   pipe_surface_reference(&strb->surface, NULL);
+   pipe_texture_reference(&strb->texture, NULL);
+
+
+   /* Probably need dedicated flags for surface usage too:
+    */
+   surface_usage = (PIPE_BUFFER_USAGE_GPU_READ  |
+                    PIPE_BUFFER_USAGE_GPU_WRITE);
+
+   strb->texture = create_texture(pipe, strb->format,
+                                  width, height);
+
+   if (!strb->texture)
+      return FALSE;
+
+   strb->surface = pipe->screen->get_tex_surface(pipe->screen,
+                                                 strb->texture,
+                                                 0, 0, 0,
+                                                 surface_usage);
+   strb->width = width;
+   strb->height = height;
+
+   assert(strb->surface->width == width);
+   assert(strb->surface->height == height);
+
+   return strb->surface != NULL;
+}
+
+struct vg_context * st_create_context(struct pipe_context *pipe,
+                                      const void *visual,
+                                      struct vg_context *share)
+{
+   struct vg_context *ctx = vg_create_context(pipe, visual, share);
+   /*debug_printf("--------- CREATE CONTEXT %p\n", ctx);*/
+   return ctx;
+}
+
+void st_destroy_context(struct vg_context *st)
+{
+   /*debug_printf("--------- DESTROY CONTEXT %p\n", st);*/
+   vg_destroy_context(st);
+}
+
+void st_copy_context_state(struct vg_context *dst, struct vg_context *src,
+                           uint mask)
+{
+   fprintf(stderr, "FIXME: %s\n", __FUNCTION__);
+}
+
+void st_get_framebuffer_dimensions(struct st_framebuffer *stfb,
+                                  uint *width,
+                                  uint *height)
+{
+   *width = stfb->strb->width;
+   *height = stfb->strb->height;
+}
+
+struct st_framebuffer * st_create_framebuffer(const void *visual,
+                                              enum pipe_format colorFormat,
+                                              enum pipe_format depthFormat,
+                                              enum pipe_format stencilFormat,
+                                              uint width, uint height,
+                                              void *privateData)
+{
+   struct st_framebuffer *stfb = CALLOC_STRUCT(st_framebuffer);
+   if (stfb) {
+      struct st_renderbuffer *rb =
+         st_new_renderbuffer_fb(colorFormat);
+      stfb->strb = rb;
+#if 0
+      if (doubleBuffer) {
+         struct st_renderbuffer *rb =
+            st_new_renderbuffer_fb(colorFormat);
+      }
+#endif
+
+      /* we want to combine the depth/stencil */
+      if (stencilFormat == depthFormat)
+         stfb->dsrb = st_new_renderbuffer_fb(stencilFormat);
+      else
+         stfb->dsrb = st_new_renderbuffer_fb(PIPE_FORMAT_S8Z24_UNORM);
+
+      /*### currently we always allocate it but it's possible it's
+        not necessary if EGL_ALPHA_MASK_SIZE was 0
+      */
+      stfb->alpha_mask = 0;
+
+      stfb->init_width = width;
+      stfb->init_height = height;
+      stfb->privateData = privateData;
+   }
+
+   return stfb;
+}
+
+static void setup_new_alpha_mask(struct vg_context *ctx,
+                                 struct st_framebuffer *stfb,
+                                 uint width, uint height)
+{
+   struct pipe_context *pipe = ctx->pipe;
+   struct pipe_texture *old_texture = stfb->alpha_mask;
+
+   /*
+     we use PIPE_FORMAT_A8R8G8B8_UNORM because we want to render to
+     this texture and use it as a sampler, so while this wastes some
+     space it makes both of those a lot simpler
+   */
+   stfb->alpha_mask =
+      create_texture(pipe, PIPE_FORMAT_A8R8G8B8_UNORM, width, height);
+
+   if (!stfb->alpha_mask) {
+      if (old_texture)
+         pipe_texture_reference(&old_texture, NULL);
+      return;
+   }
+
+   vg_validate_state(ctx);
+
+   /* alpha mask starts with 1.f alpha */
+   mask_fill(0, 0, width, height, 1.f);
+
+   /* if we had an old surface copy it over */
+   if (old_texture) {
+      struct pipe_surface *surface = pipe->screen->get_tex_surface(
+         pipe->screen,
+         stfb->alpha_mask,
+         0, 0, 0,
+         PIPE_BUFFER_USAGE_GPU_WRITE);
+      struct pipe_surface *old_surface = pipe->screen->get_tex_surface(
+         pipe->screen,
+         old_texture,
+         0, 0, 0,
+         PIPE_BUFFER_USAGE_GPU_READ);
+      pipe->surface_copy(pipe,
+                         surface,
+                         0, 0,
+                         old_surface,
+                         0, 0,
+                         MIN2(old_surface->width, width),
+                         MIN2(old_surface->height, height));
+      if (surface)
+         pipe_surface_reference(&surface, NULL);
+      if (old_surface)
+         pipe_surface_reference(&old_surface, NULL);
+   }
+
+   /* Free the old texture
+    */
+   if (old_texture)
+      pipe_texture_reference(&old_texture, NULL);
+}
+
+void st_resize_framebuffer(struct st_framebuffer *stfb,
+                           uint width, uint height)
+{
+   struct vg_context *ctx = vg_current_context();
+   struct st_renderbuffer *strb = stfb->strb;
+   struct pipe_framebuffer_state *state;
+
+   if (!ctx)
+      return;
+
+   state = &ctx->state.g3d.fb;
+
+   /* If this is a noop, exit early and don't do the clear, etc below.
+    */
+   if (strb->width == width &&
+       strb->height == height &&
+       state->zsbuf)
+      return;
+
+   if (strb->width != width || strb->height != height)
+      st_renderbuffer_alloc_storage(ctx, strb,
+                                 width, height);
+
+   if (stfb->dsrb->width != width || stfb->dsrb->height != height)
+      st_renderbuffer_alloc_storage(ctx, stfb->dsrb,
+                                 width, height);
+
+   {
+      VGuint i;
+
+      memset(state, 0, sizeof(struct pipe_framebuffer_state));
+
+      state->width  = width;
+      state->height = height;
+
+      state->nr_cbufs = 1;
+      state->cbufs[0] = strb->surface;
+      for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i)
+         state->cbufs[i] = 0;
+
+      state->zsbuf = stfb->dsrb->surface;
+
+      cso_set_framebuffer(ctx->cso_context, state);
+   }
+
+   ctx->state.dirty |= VIEWPORT_DIRTY;
+   ctx->state.dirty |= DEPTH_STENCIL_DIRTY;/*to reset the scissors*/
+
+   ctx->pipe->clear(ctx->pipe, PIPE_CLEAR_DEPTHSTENCIL,
+                    NULL, 0.0, 0);
+
+   /* we need all the other state already set */
+
+   setup_new_alpha_mask(ctx, stfb, width, height);
+
+   pipe_texture_reference( &stfb->blend_texture, NULL );
+   stfb->blend_texture = create_texture(ctx->pipe, PIPE_FORMAT_A8R8G8B8_UNORM,
+                                        width, height);
+}
+
+void st_set_framebuffer_surface(struct st_framebuffer *stfb,
+                                uint surfIndex, struct pipe_surface *surf)
+{
+   struct st_renderbuffer *rb = stfb->strb;
+
+   /* unreference existing surfaces */
+   pipe_surface_reference( &rb->surface, NULL );
+   pipe_texture_reference( &rb->texture, NULL );
+
+   /* reference new ones */
+   pipe_surface_reference( &rb->surface, surf );
+   pipe_texture_reference( &rb->texture, surf->texture );
+
+   rb->width  = surf->width;
+   rb->height = surf->height;
+}
+
+int st_get_framebuffer_surface(struct st_framebuffer *stfb,
+                               uint surfIndex, struct pipe_surface **surf)
+{
+   struct st_renderbuffer *rb = stfb->strb;
+   *surf = rb->surface;
+   return VG_TRUE;
+}
+
+int st_get_framebuffer_texture(struct st_framebuffer *stfb,
+                               uint surfIndex, struct pipe_texture **tex)
+{
+   struct st_renderbuffer *rb = stfb->strb;
+   *tex = rb->texture;
+   return VG_TRUE;
+}
+
+void * st_framebuffer_private(struct st_framebuffer *stfb)
+{
+   return stfb->privateData;
+}
+
+void st_unreference_framebuffer(struct st_framebuffer *stfb)
+{
+   /* FIXME */
+}
+
+void st_make_current(struct vg_context *st,
+                     struct st_framebuffer *draw,
+                     struct st_framebuffer *read)
+{
+   vg_set_current_context(st);
+   if (st) {
+      st->draw_buffer = draw;
+   }
+}
+
+void st_flush(struct vg_context *st, uint pipeFlushFlags,
+              struct pipe_fence_handle **fence)
+{
+   st->pipe->flush(st->pipe, pipeFlushFlags, fence);
+}
+
+void st_finish(struct vg_context *st)
+{
+   struct pipe_fence_handle *fence = NULL;
+
+   st_flush(st, PIPE_FLUSH_RENDER_CACHE, &fence);
+
+   st->pipe->screen->fence_finish(st->pipe->screen, fence, 0);
+   st->pipe->screen->fence_reference(st->pipe->screen, &fence, NULL);
+}
+
+void st_notify_swapbuffers(struct st_framebuffer *stfb)
+{
+   struct vg_context *ctx = vg_current_context();
+   if (ctx && ctx->draw_buffer == stfb) {
+      st_flush(ctx,
+              PIPE_FLUSH_RENDER_CACHE | 
+              PIPE_FLUSH_SWAPBUFFERS |
+              PIPE_FLUSH_FRAME,
+               NULL);
+   }
+}
+
+void st_notify_swapbuffers_complete(struct st_framebuffer *stfb)
+{
+}
+
+int
+st_set_teximage(struct pipe_texture *pt, int target)
+{
+   return 0;
+}
diff --git a/src/gallium/state_trackers/vega/vg_tracker.h b/src/gallium/state_trackers/vega/vg_tracker.h
new file mode 100644 (file)
index 0000000..805c58c
--- /dev/null
@@ -0,0 +1,102 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#ifndef VG_TRACKER_H
+#define VG_TRACKER_H
+
+#include "VG/openvg.h"
+
+#include "pipe/p_compiler.h"
+#include "pipe/p_format.h"
+
+#define ST_SURFACE_FRONT_LEFT   0
+#define ST_SURFACE_BACK_LEFT    1
+#define ST_SURFACE_FRONT_RIGHT  2
+#define ST_SURFACE_BACK_RIGHT   3
+#define ST_SURFACE_DEPTH        8
+
+struct vg_context;
+struct st_framebuffer;
+struct pipe_context;
+struct pipe_fence_handle;
+struct pipe_surface;
+
+
+struct vg_context *st_create_context(struct pipe_context *pipe,
+                                     const void *visual,
+                                     struct vg_context *share);
+
+void st_destroy_context( struct vg_context *st );
+
+void st_copy_context_state(struct vg_context *dst, struct vg_context *src,
+                           uint mask);
+
+struct st_framebuffer *st_create_framebuffer(const void *visual,
+                                             enum pipe_format colorFormat,
+                                             enum pipe_format depthFormat,
+                                             enum pipe_format stencilFormat,
+                                             uint width, uint height,
+                                             void *privateData);
+
+void st_resize_framebuffer(struct st_framebuffer *stfb,
+                           uint width, uint height);
+
+void st_set_framebuffer_surface(struct st_framebuffer *stfb,
+                                uint surfIndex, struct pipe_surface *surf);
+
+void st_get_framebuffer_dimensions( struct st_framebuffer *stfb,
+                                   uint *width, uint *height);
+
+int st_set_teximage(struct pipe_texture *pt, int target);
+
+int st_get_framebuffer_surface(struct st_framebuffer *stfb,
+                               uint surfIndex, struct pipe_surface **surf);
+
+int st_get_framebuffer_texture(struct st_framebuffer *stfb,
+                               uint surfIndex, struct pipe_texture **tex);
+
+void *st_framebuffer_private(struct st_framebuffer *stfb);
+
+void st_unreference_framebuffer(struct st_framebuffer *stfb);
+
+void st_make_current(struct vg_context *st,
+                     struct st_framebuffer *draw,
+                     struct st_framebuffer *read);
+
+void st_flush(struct vg_context *st, uint pipeFlushFlags,
+               struct pipe_fence_handle **fence);
+void st_finish(struct vg_context *st);
+
+void st_notify_swapbuffers(struct st_framebuffer *stfb);
+void st_notify_swapbuffers_complete(struct st_framebuffer *stfb);
+
+
+/** Generic function type */
+typedef void (*st_proc)();
+
+st_proc st_get_proc_address(const char *procname);
+
+#endif
diff --git a/src/gallium/state_trackers/vega/vg_translate.c b/src/gallium/state_trackers/vega/vg_translate.c
new file mode 100644 (file)
index 0000000..00e0764
--- /dev/null
@@ -0,0 +1,1030 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#include "vg_translate.h"
+
+#include "pipe/p_format.h"
+#include "util/u_pack_color.h"
+
+void _vega_pack_rgba_span_float(struct vg_context *ctx,
+                                VGuint n, VGfloat rgba[][4],
+                                VGImageFormat dstFormat,
+                                void *dstAddr)
+{
+   VGint i;
+
+   switch (dstFormat) {
+   case VG_sRGBX_8888: {
+      VGint *dst = (VGint *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = 255;
+         dst[i] = r << 24 | g << 16 | b << 8 | a;
+      }
+      return;
+   }
+      break;
+   case VG_sRGBA_8888: {
+      VGint *dst = (VGint *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = float_to_ubyte(rgba[i][3]);
+         dst[i] = r << 24 | g << 16 | b << 8 | a;
+      }
+      return;
+   }
+      break;
+   case VG_sRGBA_8888_PRE: {
+      VGint *dst = (VGint *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = float_to_ubyte(rgba[i][3]);
+         dst[i] = r << 24 | g << 16 | b << 8 | a;
+      }
+      return;
+   }
+      break;
+   case VG_sRGB_565: {
+      VGshort *dst = (VGshort *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         r = (r / 255.0) * 32;
+         g = (g / 255.0) * 32;
+         b = (b / 255.0) * 32;
+
+         dst[i] = b | g << 5 | r << 11;
+      }
+      return;
+   }
+      break;
+   case VG_sRGBA_5551: {
+      VGshort *dst = (VGshort *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b, a;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = float_to_ubyte(rgba[i][3]);
+         r = (r / 255.0) * 32;
+         g = (g / 255.0) * 32;
+         b = (b / 255.0) * 32;
+         a = (a / 255.0);
+
+         dst[i] =  a | b << 1 | g << 6 | r << 11;
+      }
+      return;
+   }
+      break;
+   case VG_sRGBA_4444: {
+      VGshort *dst = (VGshort *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b, a;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = float_to_ubyte(rgba[i][3]);
+         r = (r / 255.0) * 16;
+         g = (g / 255.0) * 16;
+         b = (b / 255.0) * 16;
+         a = (a / 255.0) * 16;
+
+         dst[i] =  a | b << 4 | g << 8 | r << 12;
+      }
+      return;
+   }
+      break;
+   case VG_sL_8: {
+      VGubyte *dst = (VGubyte *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b, a;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = float_to_ubyte(rgba[i][3]);
+
+         dst[i] =  a;
+      }
+      return;
+   }
+      break;
+   case VG_lRGBX_8888: {
+      VGint *dst = (VGint *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = 255;
+         dst[i] = r << 24 | g << 16 | b << 8 | a;
+      }
+      return;
+   }
+      break;
+   case VG_lRGBA_8888: {
+      VGint *dst = (VGint *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = float_to_ubyte(rgba[i][3]);
+         dst[i] = r << 24 | g << 16 | b << 8 | a;
+      }
+      return;
+   }
+   case VG_lRGBA_8888_PRE: {
+      VGint *dst = (VGint *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = float_to_ubyte(rgba[i][3]);
+         dst[i] = r << 24 | g << 16 | b << 8 | a;
+      }
+      return;
+   }
+      break;
+   case VG_lL_8: {
+      VGubyte *dst = (VGubyte *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = float_to_ubyte(rgba[i][3]);
+         dst[i] = a;
+      }
+      return;
+   }
+      break;
+   case VG_A_8: {
+      VGubyte *dst = (VGubyte *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b, a;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = float_to_ubyte(rgba[i][3]);
+
+         dst[i] = a;
+      }
+      return;
+   }
+      break;
+   case VG_BW_1: {
+      VGshort *dst = (VGshort *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b, a;
+         VGubyte res;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = float_to_ubyte(rgba[i][3]);
+
+         res = (r + g + b + a)/4;
+         dst[i] =   (res & (128));
+      }
+      return;
+   }
+      break;
+#ifdef OPENVG_VERSION_1_1
+   case VG_A_1: {
+      VGshort *dst = (VGshort *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b, a;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = float_to_ubyte(rgba[i][3]);
+
+         dst[i] =   (a & (128));
+      }
+      return;
+   }
+      break;
+   case VG_A_4: {
+      VGshort *dst = (VGshort *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b, a;
+         VGubyte res;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = float_to_ubyte(rgba[i][3]);
+
+         res = a/4;
+         dst[i] =   (res & (128));
+      }
+      return;
+   }
+      break;
+#endif
+   case VG_sXRGB_8888:
+      break;
+   case VG_sARGB_8888: {
+      VGint *dst = (VGint *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = float_to_ubyte(rgba[i][3]);
+         dst[i] = a << 24 | r << 16 | g << 8 | b;
+      }
+      return;
+   }
+      break;
+   case VG_sARGB_8888_PRE:  {
+      VGint *dst = (VGint *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = float_to_ubyte(rgba[i][3]);
+         dst[i] = a << 24 | r << 16 | g << 8 | b;
+      }
+      return;
+   }
+      break;
+   case VG_sARGB_1555:
+      break;
+   case VG_sARGB_4444:
+      break;
+   case VG_lXRGB_8888:
+      break;
+   case VG_lARGB_8888: {
+      VGint *dst = (VGint *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = float_to_ubyte(rgba[i][3]);
+         dst[i] = a << 24 | r << 16 | g << 8 | b;
+      }
+      return;
+   }
+      break;
+   case VG_lARGB_8888_PRE: {
+      VGint *dst = (VGint *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = float_to_ubyte(rgba[i][3]);
+         dst[i] = a << 24 | r << 16 | g << 8 | b;
+      }
+      return;
+   }
+      break;
+   case VG_sBGRX_8888: {
+      VGint *dst = (VGint *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = 0xff;
+         dst[i] = b << 24 | g << 16 | r << 8 | a;
+      }
+      return;
+   }
+      break;
+   case VG_sBGRA_8888: {
+      VGint *dst = (VGint *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = float_to_ubyte(rgba[i][3]);
+         dst[i] = b << 24 | g << 16 | r << 8 | a;
+      }
+      return;
+   }
+      break;
+   case VG_sBGRA_8888_PRE: {
+      VGint *dst = (VGint *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = float_to_ubyte(rgba[i][3]);
+         dst[i] = b << 24 | g << 16 | r << 8 | a;
+      }
+      return;
+   }
+      break;
+   case VG_sBGR_565:
+      break;
+   case VG_sBGRA_5551:
+      break;
+   case VG_sBGRA_4444:
+      break;
+   case VG_lBGRX_8888: {
+      VGint *dst = (VGint *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = 0xff;
+         dst[i] = b << 24 | g << 16 | r << 8 | a;
+      }
+      return;
+   }
+      break;
+   case VG_lBGRA_8888: {
+      VGint *dst = (VGint *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = float_to_ubyte(rgba[i][3]);
+         dst[i] = b << 24 | g << 16 | r << 8 | a;
+      }
+      return;
+   }
+      break;
+   case VG_lBGRA_8888_PRE: {
+      VGint *dst = (VGint *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = float_to_ubyte(rgba[i][3]);
+         dst[i] = b << 24 | g << 16 | r << 8 | a;
+      }
+      return;
+   }
+      break;
+   case VG_sXBGR_8888:
+      break;
+   case VG_sABGR_8888: {
+      VGint *dst = (VGint *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = float_to_ubyte(rgba[i][3]);
+         dst[i] = a << 24 | b << 16 | g << 8 | r;
+      }
+      return;
+   }
+      break;
+   case VG_sABGR_8888_PRE: {
+      VGint *dst = (VGint *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = float_to_ubyte(rgba[i][3]);
+         dst[i] = a << 24 | b << 16 | g << 8 | r;
+      }
+      return;
+   }
+      break;
+   case VG_sABGR_1555:
+      break;
+   case VG_sABGR_4444:
+      break;
+   case VG_lXBGR_8888:
+      break;
+   case VG_lABGR_8888: {
+      VGint *dst = (VGint *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = float_to_ubyte(rgba[i][3]);
+         dst[i] = a << 24 | b << 16 | g << 8 | r;
+      }
+      return;
+   }
+      break;
+   case VG_lABGR_8888_PRE: {
+      VGint *dst = (VGint *)dstAddr;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = float_to_ubyte(rgba[i][0]);
+         g = float_to_ubyte(rgba[i][1]);
+         b = float_to_ubyte(rgba[i][2]);
+         a = float_to_ubyte(rgba[i][3]);
+         dst[i] = a << 24 | b << 16 | g << 8 | r;
+      }
+      return;
+   }
+      break;
+   default:
+      assert(!"Unknown ReadPixels format");
+      break;
+   }
+   assert(!"Not implemented ReadPixels format");
+}
+
+void _vega_unpack_float_span_rgba(struct vg_context *ctx,
+                                  VGuint n,
+                                  VGuint offset,
+                                  const void * data,
+                                  VGImageFormat dataFormat,
+                                  VGfloat rgba[][4])
+{
+   VGint i;
+
+   switch (dataFormat) {
+   case VG_sRGBX_8888: {
+      VGuint *src = (VGuint *)data;
+      src += offset;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = (*src >> 24) & 0xff;
+         g = (*src >> 16) & 0xff;
+         b = (*src >>  8) & 0xff;
+         a = 0xff;
+
+         util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                            rgba[i]);
+         ++src;
+      }
+   }
+      return;
+   case VG_sRGBA_8888: {
+      VGuint *src = (VGuint *)data;
+      src += offset;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = (*src >> 24) & 0xff;
+         g = (*src >> 16) & 0xff;
+         b = (*src >>  8) & 0xff;
+         a = (*src >>  0) & 0xff;
+
+         util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                            rgba[i]);
+         ++src;
+      }
+      return;
+   }
+      break;
+   case VG_sRGBA_8888_PRE: {
+      VGint *src = (VGint *)data;
+      src += offset;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = (*src >> 24) & 0xff;
+         g = (*src >> 16) & 0xff;
+         b = (*src >>  8) & 0xff;
+         a = (*src >>  0) & 0xff;
+
+         util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                            rgba[i]);
+         ++src;
+      }
+      return;
+   }
+      break;
+   case VG_sRGB_565: {
+      VGshort *src = (VGshort *)data;
+      src += offset;
+      for (i = 0; i < n; ++i) {
+         VGfloat clr[4];
+         clr[0] = ((*src >> 10) & 31)/31.;
+         clr[1] = ((*src >>  5) & 95)/95.;
+         clr[2] = ((*src >>  0) & 31)/31.;
+         clr[3] = 1.f;
+
+         util_pack_color(clr, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                         rgba[i]);
+         ++src;
+      }
+   }
+      return;
+   case VG_sRGBA_5551: {
+      VGshort *src = (VGshort *)data;
+      src += offset;
+      for (i = 0; i < n; ++i) {
+         VGfloat clr[4];
+         clr[0] = ((*src >> 10) & 31)/31.;
+         clr[1] = ((*src >>  5) & 31)/31.;
+         clr[2] = ((*src >>  1) & 31)/31.;
+         clr[3] = ((*src >>  0) & 1)/1.;
+
+         util_pack_color(clr, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                         rgba[i]);
+         ++src;
+      }
+   }
+      return;
+   case VG_sRGBA_4444: {
+      VGshort *src = (VGshort *)data;
+      src += offset;
+      for (i = 0; i < n; ++i) {
+         VGfloat clr[4];
+         clr[0] = ((*src >> 12) & 15)/15.;
+         clr[1] = ((*src >>  8) & 15)/15.;
+         clr[2] = ((*src >>  4) & 15)/15.;
+         clr[3] = ((*src >>  0) & 15)/15.;
+
+         util_pack_color(clr, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                         rgba[i]);
+         ++src;
+      }
+   }
+      return;
+   case VG_sL_8: {
+      VGubyte *src = (VGubyte *)data;
+      src += offset;
+      for (i = 0; i < n; ++i) {
+         util_pack_color_ub(0xff, 0xff, 0xff, *src, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                         rgba[i]);
+         ++src;
+      }
+   }
+      return;
+   case VG_lRGBX_8888: {
+      VGuint *src = (VGuint *)data;
+      src += offset;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = (*src >> 24) & 0xff;
+         g = (*src >> 16) & 0xff;
+         b = (*src >>  8) & 0xff;
+         a = 0xff;
+
+         util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                            rgba[i]);
+         ++src;
+      }
+   }
+      return;
+   case VG_lRGBA_8888: {
+      VGint *src = (VGint *)data;
+      src += offset;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = (*src >> 24) & 0xff;
+         g = (*src >> 16) & 0xff;
+         b = (*src >>  8) & 0xff;
+         a = (*src >>  0) & 0xff;
+
+         util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                            rgba[i]);
+         ++src;
+      }
+      return;
+   }
+      break;
+   case VG_lRGBA_8888_PRE: {
+      VGint *src = (VGint *)data;
+      src += offset;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         r = (*src >> 24) & 0xff;
+         g = (*src >> 16) & 0xff;
+         b = (*src >>  8) & 0xff;
+         a = (*src >>  0) & 0xff;
+
+         util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                            rgba[i]);
+         ++src;
+      }
+      return;
+   }
+      break;
+   case VG_lL_8: {
+      VGubyte *src = (VGubyte *)data;
+      src += offset;
+      for (i = 0; i < n; ++i) {
+         util_pack_color_ub(0xff, 0xff, 0xff, *src, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                         rgba[i]);
+         ++src;
+      }
+   }
+      return;
+   case VG_A_8: {
+      VGubyte *src = (VGubyte *)data;
+      src += offset;
+      for (i = 0; i < n; ++i) {
+         util_pack_color_ub(0xff, 0xff, 0xff, *src, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                            rgba[i]);
+         ++src;
+      }
+   }
+      return;
+   case VG_BW_1: {
+      VGubyte *src = (VGubyte *)data;
+      src += offset;
+      for (i = 0; i < n; i += 8) {
+         VGfloat clr[4];
+         VGint j;
+         for (j = 0; j < 8 && j < n ; ++j) {
+            VGint shift = j;
+            clr[0] = (((*src) & (1<<shift)) >> shift);
+            clr[1] = clr[0];
+            clr[2] = clr[0];
+            clr[3] = 1.f;
+
+            util_pack_color(clr, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                            rgba[i+j]);
+         }
+         ++src;
+      }
+   }
+      return;
+#ifdef OPENVG_VERSION_1_1
+   case VG_A_1: {
+      VGubyte *src = (VGubyte *)data;
+      src += offset;
+      for (i = 0; i < n; i += 8) {
+         VGfloat clr[4];
+         VGint j;
+         for (j = 0; j < 8 && j < n ; ++j) {
+            VGint shift = j;
+            clr[0] = 0.f;
+            clr[1] = 0.f;
+            clr[2] = 0.f;
+            clr[3] = (((*src) & (1<<shift)) >> shift);
+
+            util_pack_color(clr, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                            rgba[i+j]);
+         }
+         ++src;
+      }
+   }
+      return;
+   case VG_A_4: {
+      VGubyte *src = (VGubyte *)data;
+      src += offset/2;
+      for (i = 0; i < n; i += 2) {
+         VGfloat clr[4];
+         VGint j;
+         for (j = 0; j < n && j < 2; ++j) {
+            VGint bitter, shift;
+            if (j == 0) {
+               bitter = 0x0f;
+               shift = 0;
+            } else {
+               bitter = 0xf0;
+               shift = 4;
+            }
+            clr[0] = 0.f;
+            clr[1] = 0.f;
+            clr[2] = 0.f;
+            clr[3] = ((*src) & (bitter)) >> shift;
+
+            util_pack_color(clr, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                            rgba[i +j]);
+         }
+         ++src;
+      }
+   }
+      return;
+#endif
+   case VG_sXRGB_8888:
+      break;
+   case VG_sARGB_8888: {
+      VGuint *src = (VGuint *)data;
+      src += offset;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         a = (*src >> 24) & 0xff;
+         r = (*src >> 16) & 0xff;
+         g = (*src >>  8) & 0xff;
+         b = (*src >>  0) & 0xff;
+
+         util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                            rgba[i]);
+         ++src;
+      }
+      return;
+   }
+      break;
+   case VG_sARGB_8888_PRE: {
+      VGuint *src = (VGuint *)data;
+      src += offset;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         a = (*src >> 24) & 0xff;
+         r = (*src >> 16) & 0xff;
+         g = (*src >>  8) & 0xff;
+         b = (*src >>  0) & 0xff;
+
+         util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                            rgba[i]);
+         ++src;
+      }
+      return;
+   }
+      break;
+   case VG_sARGB_1555:
+      break;
+   case VG_sARGB_4444:
+      break;
+   case VG_lXRGB_8888:
+      break;
+   case VG_lARGB_8888: {
+      VGint *src = (VGint *)data;
+      src += offset;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         a = (*src >> 24) & 0xff;
+         r = (*src >> 16) & 0xff;
+         g = (*src >>  8) & 0xff;
+         b = (*src >>  0) & 0xff;
+
+         util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                            rgba[i]);
+         ++src;
+      }
+      return;
+   }
+      break;
+   case VG_lARGB_8888_PRE: {
+      VGint *src = (VGint *)data;
+      src += offset;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         a = (*src >> 24) & 0xff;
+         r = (*src >> 16) & 0xff;
+         g = (*src >>  8) & 0xff;
+         b = (*src >>  0) & 0xff;
+
+         util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                            rgba[i]);
+         ++src;
+      }
+      return;
+   }
+      break;
+   case VG_sBGRX_8888:
+      break;
+   case VG_sBGRA_8888:  {
+      VGuint *src = (VGuint *)data;
+      src += offset;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         b = (*src >> 24) & 0xff;
+         g = (*src >> 16) & 0xff;
+         r = (*src >>  8) & 0xff;
+         a = (*src >>  0) & 0xff;
+
+         util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                            rgba[i]);
+         ++src;
+      }
+      return;
+   }
+      break;
+   case VG_sBGRA_8888_PRE:  {
+      VGuint *src = (VGuint *)data;
+      src += offset;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         b = (*src >> 24) & 0xff;
+         g = (*src >> 16) & 0xff;
+         r = (*src >>  8) & 0xff;
+         a = (*src >>  0) & 0xff;
+
+         util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                            rgba[i]);
+         ++src;
+      }
+      return;
+   }
+      break;
+   case VG_sBGR_565:
+      break;
+   case VG_sBGRA_5551:
+      break;
+   case VG_sBGRA_4444:
+      break;
+   case VG_lBGRX_8888:
+      break;
+   case VG_lBGRA_8888:  {
+      VGuint *src = (VGuint *)data;
+      src += offset;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         b = (*src >> 24) & 0xff;
+         g = (*src >> 16) & 0xff;
+         r = (*src >>  8) & 0xff;
+         a = (*src >>  0) & 0xff;
+
+         util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                            rgba[i]);
+         ++src;
+      }
+      return;
+   }
+      break;
+   case VG_lBGRA_8888_PRE:  {
+      VGuint *src = (VGuint *)data;
+      src += offset;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         b = (*src >> 24) & 0xff;
+         g = (*src >> 16) & 0xff;
+         r = (*src >>  8) & 0xff;
+         a = (*src >>  0) & 0xff;
+
+         util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                            rgba[i]);
+         ++src;
+      }
+      return;
+   }
+      break;
+   case VG_sXBGR_8888:
+      break;
+   case VG_sABGR_8888: {
+      VGuint *src = (VGuint *)data;
+      src += offset;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         a = (*src >> 24) & 0xff;
+         b = (*src >> 16) & 0xff;
+         g = (*src >>  8) & 0xff;
+         r = (*src >>  0) & 0xff;
+
+         util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                            rgba[i]);
+         ++src;
+      }
+      return;
+   }
+      break;
+   case VG_sABGR_8888_PRE: {
+      VGuint *src = (VGuint *)data;
+      src += offset;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         a = (*src >> 24) & 0xff;
+         b = (*src >> 16) & 0xff;
+         g = (*src >>  8) & 0xff;
+         r = (*src >>  0) & 0xff;
+
+         util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                            rgba[i]);
+         ++src;
+      }
+      return;
+   }
+      break;
+   case VG_sABGR_1555:
+      break;
+   case VG_sABGR_4444:
+      break;
+   case VG_lXBGR_8888:
+      break;
+   case VG_lABGR_8888: {
+      VGuint *src = (VGuint *)data;
+      src += offset;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         a = (*src >> 24) & 0xff;
+         b = (*src >> 16) & 0xff;
+         g = (*src >>  8) & 0xff;
+         r = (*src >>  0) & 0xff;
+
+         util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                            rgba[i]);
+         ++src;
+      }
+      return;
+   }
+      break;
+   case VG_lABGR_8888_PRE: {
+      VGuint *src = (VGuint *)data;
+      src += offset;
+      for (i = 0; i < n; ++i) {
+         VGubyte r, g, b ,a;
+         a = (*src >> 24) & 0xff;
+         b = (*src >> 16) & 0xff;
+         g = (*src >>  8) & 0xff;
+         r = (*src >>  0) & 0xff;
+
+         util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT,
+                            rgba[i]);
+         ++src;
+      }
+      return;
+   }
+      break;
+   default:
+      assert(!"Unknown ReadPixels format");
+      break;
+   }
+   assert(!"Not implemented ReadPixels format");
+}
+
+VGint _vega_size_for_format(VGImageFormat dataFormat)
+{
+   switch (dataFormat) {
+   case VG_sRGBX_8888:
+   case VG_sRGBA_8888:
+   case VG_sRGBA_8888_PRE:
+      return 4;
+   case VG_sRGB_565:
+   case VG_sRGBA_5551:
+   case VG_sRGBA_4444:
+      return 2;
+   case VG_sL_8:
+      return 1;
+   case VG_lRGBX_8888:
+   case VG_lRGBA_8888:
+   case VG_lRGBA_8888_PRE:
+      return 4;
+   case VG_lL_8:
+      return 1;
+   case VG_A_8:
+      return 1;
+   case VG_BW_1:
+      return 1;
+#ifdef OPENVG_VERSION_1_1
+   case VG_A_1:
+      break;
+   case VG_A_4:
+      break;
+#endif
+   case VG_sXRGB_8888:
+   case VG_sARGB_8888:
+   case VG_sARGB_8888_PRE:
+      return 4;
+   case VG_sARGB_1555:
+   case VG_sARGB_4444:
+      return 2;
+   case VG_lXRGB_8888:
+   case VG_lARGB_8888:
+   case VG_lARGB_8888_PRE:
+   case VG_sBGRX_8888:
+   case VG_sBGRA_8888:
+   case VG_sBGRA_8888_PRE:
+      return 4;
+   case VG_sBGR_565:
+   case VG_sBGRA_5551:
+   case VG_sBGRA_4444:
+      return 2;
+   case VG_lBGRX_8888:
+   case VG_lBGRA_8888:
+   case VG_lBGRA_8888_PRE:
+   case VG_sXBGR_8888:
+   case VG_sABGR_8888:
+   case VG_sABGR_8888_PRE:
+      return 4;
+   case VG_sABGR_1555:
+   case VG_sABGR_4444:
+      return 2;
+   case VG_lXBGR_8888:
+   case VG_lABGR_8888:
+   case VG_lABGR_8888_PRE:
+      return 4;
+   default:
+      assert(!"Unknown ReadPixels format");
+      break;
+   }
+   assert(!"Not implemented ReadPixels format");
+   return 0;
+}
diff --git a/src/gallium/state_trackers/vega/vg_translate.h b/src/gallium/state_trackers/vega/vg_translate.h
new file mode 100644 (file)
index 0000000..70815ba
--- /dev/null
@@ -0,0 +1,49 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#ifndef VG_TRANSLATE_H
+#define VG_TRANSLATE_H
+
+#include "VG/openvg.h"
+#include "vg_context.h"
+
+/*FIXME: we really should be using translate module
+ * but pipe_format can't express some of the VG formats
+ * (the premultiplied ones) so currently it won't work */
+
+void _vega_pack_rgba_span_float(struct vg_context *ctx,
+                                VGuint n, VGfloat rgba[][4],
+                                VGImageFormat dstFormat,
+                                void *dstAddr);
+void _vega_unpack_float_span_rgba(struct vg_context *ctx,
+                                  VGuint n,
+                                  VGuint offset,
+                                  const void * data,
+                                  VGImageFormat dataFormat,
+                                  VGfloat rgba[][4]);
+VGint _vega_size_for_format(VGImageFormat format);
+
+#endif
diff --git a/src/gallium/state_trackers/vega/vgu.c b/src/gallium/state_trackers/vega/vgu.c
new file mode 100644 (file)
index 0000000..7dc51c5
--- /dev/null
@@ -0,0 +1,450 @@
+/**************************************************************************
+ *
+ * Copyright 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+#include "VG/openvg.h"
+#include "VG/vgu.h"
+
+#include "matrix.h"
+#include "path.h"
+
+#include "util/u_debug.h"
+#include "util/u_pointer.h"
+
+#include <math.h>
+#include <assert.h>
+
+static VGboolean is_aligned_to(const void *ptr, VGbyte alignment)
+{
+   void *aligned = align_pointer(ptr, alignment);
+   return (ptr == aligned) ? VG_TRUE : VG_FALSE;
+}
+
+static VGboolean is_aligned(const void *ptr)
+{
+   return is_aligned_to(ptr, 4);
+}
+
+static void vgu_append_float_coords(VGPath path,
+                                    const VGubyte *cmds,
+                                    VGint num_cmds,
+                                    const VGfloat *coords,
+                                    VGint num_coords)
+{
+   VGubyte common_data[40 * sizeof(VGfloat)];
+   struct path *p = (struct path *)path;
+
+   vg_float_to_datatype(path_datatype(p), common_data, coords, num_coords);
+   vgAppendPathData(path, num_cmds, cmds, common_data);
+}
+
+VGUErrorCode vguLine(VGPath path,
+                     VGfloat x0, VGfloat y0,
+                     VGfloat x1, VGfloat y1)
+{
+   static const VGubyte cmds[] = {VG_MOVE_TO_ABS, VG_LINE_TO_ABS};
+   VGfloat coords[4];
+   VGbitfield caps;
+
+   if (path == VG_INVALID_HANDLE) {
+      return VGU_BAD_HANDLE_ERROR;
+   }
+   caps = vgGetPathCapabilities(path);
+   if (!(caps & VG_PATH_CAPABILITY_APPEND_TO)) {
+      return VGU_PATH_CAPABILITY_ERROR;
+   }
+
+   coords[0] = x0;
+   coords[1] = y0;
+   coords[2] = x1;
+   coords[3] = y1;
+
+   vgu_append_float_coords(path, cmds, 2, coords, 4);
+
+   return VGU_NO_ERROR;
+}
+
+VGUErrorCode vguPolygon(VGPath path,
+                        const VGfloat * points,
+                        VGint count,
+                        VGboolean closed)
+{
+   VGubyte *cmds;
+   VGfloat *coords;
+   VGbitfield caps;
+   VGint i;
+
+   if (path == VG_INVALID_HANDLE) {
+      return VGU_BAD_HANDLE_ERROR;
+   }
+
+   if (!points || count <= 0 || !is_aligned(points)) {
+      return VGU_ILLEGAL_ARGUMENT_ERROR;
+   }
+
+   caps = vgGetPathCapabilities(path);
+   if (!(caps & VG_PATH_CAPABILITY_APPEND_TO)) {
+      return VGU_PATH_CAPABILITY_ERROR;
+   }
+
+   cmds   = malloc(sizeof(VGubyte) * count + 1);
+   coords = malloc(sizeof(VGfloat) * count * 2);
+
+   cmds[0] = VG_MOVE_TO_ABS;
+   coords[0] = points[0];
+   coords[1] = points[1];
+   for (i = 1; i < count; ++i) {
+      cmds[i] = VG_LINE_TO_ABS;
+      coords[2*i + 0] = points[2*i + 0];
+      coords[2*i + 1] = points[2*i + 1];
+   }
+
+   if (closed) {
+      cmds[i] = VG_CLOSE_PATH;
+      ++i;
+   }
+
+   vgu_append_float_coords(path, cmds, i, coords, 2*i);
+
+   free(cmds);
+   free(coords);
+
+   return VGU_NO_ERROR;
+}
+
+VGUErrorCode  vguRect(VGPath path,
+                      VGfloat x, VGfloat y,
+                      VGfloat width, VGfloat height)
+{
+   static const VGubyte cmds[] = {VG_MOVE_TO_ABS,
+                                  VG_HLINE_TO_REL,
+                                  VG_VLINE_TO_REL,
+                                  VG_HLINE_TO_REL,
+                                  VG_CLOSE_PATH
+   };
+   VGfloat coords[5];
+   VGbitfield caps;
+
+   if (path == VG_INVALID_HANDLE) {
+      return VGU_BAD_HANDLE_ERROR;
+   }
+   caps = vgGetPathCapabilities(path);
+   if (!(caps & VG_PATH_CAPABILITY_APPEND_TO)) {
+      return VGU_PATH_CAPABILITY_ERROR;
+   }
+   if (width <= 0 || height <= 0) {
+      return VGU_ILLEGAL_ARGUMENT_ERROR;
+   }
+
+   coords[0] =  x;
+   coords[1] =  y;
+   coords[2] =  width;
+   coords[3] =  height;
+   coords[4] = -width;
+
+   vgu_append_float_coords(path, cmds, 5, coords, 5);
+
+   return VGU_NO_ERROR;
+}
+
+VGUErrorCode vguRoundRect(VGPath path,
+                          VGfloat x, VGfloat y,
+                          VGfloat width,
+                          VGfloat height,
+                          VGfloat arcWidth,
+                          VGfloat arcHeight)
+{
+   static const VGubyte cmds[] = {VG_MOVE_TO_ABS,
+                                  VG_HLINE_TO_REL,
+                                  VG_SCCWARC_TO_REL,
+                                  VG_VLINE_TO_REL,
+                                  VG_SCCWARC_TO_REL,
+                                  VG_HLINE_TO_REL,
+                                  VG_SCCWARC_TO_REL,
+                                  VG_VLINE_TO_REL,
+                                  VG_SCCWARC_TO_REL,
+                                  VG_CLOSE_PATH
+   };
+   VGfloat c[26];
+   VGbitfield caps;
+
+   if (path == VG_INVALID_HANDLE) {
+      return VGU_BAD_HANDLE_ERROR;
+   }
+   caps = vgGetPathCapabilities(path);
+   if (!(caps & VG_PATH_CAPABILITY_APPEND_TO)) {
+      return VGU_PATH_CAPABILITY_ERROR;
+   }
+   if (width <= 0 || height <= 0) {
+      return VGU_ILLEGAL_ARGUMENT_ERROR;
+   }
+
+   c[0] =  x + arcWidth/2; c[1] =  y;
+
+   c[2] = width - arcWidth;
+
+   c[3] = arcWidth/2; c[4] = arcHeight/2; c[5] = 0;
+   c[6] = arcWidth/2; c[7] = arcHeight/2;
+
+   c[8] = height - arcHeight;
+
+   c[9] = arcWidth/2; c[10] = arcHeight/2; c[11] = 0;
+   c[12] = -arcWidth/2; c[13] = arcHeight/2;
+
+   c[14] = -(width - arcWidth);
+
+   c[15] = arcWidth/2; c[16] = arcHeight/2; c[17] = 0;
+   c[18] = -arcWidth/2; c[19] = -arcHeight/2;
+
+   c[20] = -(height - arcHeight);
+
+   c[21] = arcWidth/2; c[22] = arcHeight/2; c[23] = 0;
+   c[24] = arcWidth/2; c[25] = -arcHeight/2;
+
+   vgu_append_float_coords(path, cmds, 10, c, 26);
+
+   return VGU_NO_ERROR;
+}
+
+VGUErrorCode vguEllipse(VGPath path,
+                        VGfloat cx, VGfloat cy,
+                        VGfloat width,
+                        VGfloat height)
+{
+   static const VGubyte cmds[] = {VG_MOVE_TO_ABS,
+                                  VG_SCCWARC_TO_REL,
+                                  VG_SCCWARC_TO_REL,
+                                  VG_CLOSE_PATH
+   };
+   VGfloat coords[12];
+   VGbitfield caps;
+
+   if (path == VG_INVALID_HANDLE) {
+      return VGU_BAD_HANDLE_ERROR;
+   }
+   caps = vgGetPathCapabilities(path);
+   if (!(caps & VG_PATH_CAPABILITY_APPEND_TO)) {
+      return VGU_PATH_CAPABILITY_ERROR;
+   }
+   if (width <= 0 || height <= 0) {
+      return VGU_ILLEGAL_ARGUMENT_ERROR;
+   }
+
+   coords[0] = cx + width/2; coords[1] = cy;
+
+   coords[2] = width/2; coords[3] = height/2; coords[4] = 0;
+   coords[5] = -width; coords[6] = 0;
+
+   coords[7] = width/2; coords[8] = height/2; coords[9] = 0;
+   coords[10] = width; coords[11] = 0;
+
+   vgu_append_float_coords(path, cmds, 4, coords, 11);
+
+   return VGU_NO_ERROR;
+}
+
+VGUErrorCode vguArc(VGPath path,
+                    VGfloat x, VGfloat y,
+                    VGfloat width, VGfloat height,
+                    VGfloat startAngle,
+                    VGfloat angleExtent,
+                    VGUArcType arcType)
+{
+   VGubyte cmds[11];
+   VGfloat coords[40];
+   VGbitfield caps;
+   VGfloat last = startAngle + angleExtent;
+   VGint i, c = 0;
+
+   if (path == VG_INVALID_HANDLE) {
+      return VGU_BAD_HANDLE_ERROR;
+   }
+   caps = vgGetPathCapabilities(path);
+   if (!(caps & VG_PATH_CAPABILITY_APPEND_TO)) {
+      return VGU_PATH_CAPABILITY_ERROR;
+   }
+   if (width <= 0 || height <= 0) {
+      return VGU_ILLEGAL_ARGUMENT_ERROR;
+   }
+   if (arcType != VGU_ARC_OPEN &&
+       arcType != VGU_ARC_CHORD &&
+       arcType != VGU_ARC_PIE) {
+      return VGU_ILLEGAL_ARGUMENT_ERROR;
+   }
+
+   cmds[c] = VG_MOVE_TO_ABS; ++c;
+   coords[0] = x+cos(DEGREES_TO_RADIANS(startAngle))*width/2;
+   coords[1] = y+sin(DEGREES_TO_RADIANS(startAngle))*height/2;
+#ifdef DEBUG_VGUARC
+   debug_printf("start [%f, %f]\n", coords[0], coords[1]);
+#endif
+   i = 2;
+   if (angleExtent > 0) {
+      VGfloat angle = startAngle + 180;
+      while (angle < last) {
+         cmds[c] = VG_SCCWARC_TO_ABS; ++c;
+         coords[i] = width/2; coords[i+1] = height/2; coords[i+2] = 0;
+         coords[i+3] = x + cos(DEGREES_TO_RADIANS(angle))*width/2;
+         coords[i+4] = y + sin(DEGREES_TO_RADIANS(angle))*height/2;
+#ifdef DEBUG_VGUARC
+         debug_printf("1 [%f, %f]\n", coords[i+3],
+                      coords[i+4]);
+#endif
+         i += 5;
+         angle += 180;
+      }
+      cmds[c] = VG_SCCWARC_TO_ABS; ++c;
+      coords[i] = width/2; coords[i+1] = height/2; coords[i+2] = 0;
+      coords[i+3] = x+cos(DEGREES_TO_RADIANS(last))*width/2;
+      coords[i+4] = y+sin(DEGREES_TO_RADIANS(last))*height/2;
+#ifdef DEBUG_VGUARC
+      debug_printf("2 [%f, %f]\n", coords[i+3],
+                   coords[i+4]);
+#endif
+      i += 5;
+   } else {
+      VGfloat angle = startAngle - 180;
+      while (angle > last) {
+         cmds[c] = VG_SCWARC_TO_ABS; ++c;
+         coords[i] =  width/2; coords[i+1] = height/2; coords[i+2] = 0;
+         coords[i+3] = x + cos(DEGREES_TO_RADIANS(angle)) * width/2;
+         coords[i+4] = y + sin(DEGREES_TO_RADIANS(angle)) * height/2;
+#ifdef DEBUG_VGUARC
+         debug_printf("3 [%f, %f]\n", coords[i+3],
+                      coords[i+4]);
+#endif
+         angle -= 180;
+         i += 5;
+      }
+      cmds[c] = VG_SCWARC_TO_ABS; ++c;
+      coords[i] = width/2; coords[i+1] = height/2; coords[i+2] = 0;
+      coords[i+3] = x + cos(DEGREES_TO_RADIANS(last)) * width/2;
+      coords[i+4] = y + sin(DEGREES_TO_RADIANS(last)) * height/2;
+#ifdef DEBUG_VGUARC
+      debug_printf("4 [%f, %f]\n", coords[i+3],
+                   coords[i+4]);
+#endif
+      i += 5;
+   }
+
+   if (arcType == VGU_ARC_PIE) {
+      cmds[c] = VG_LINE_TO_ABS; ++c;
+      coords[i] = x; coords[i + 1] = y;
+      i += 2;
+   }
+   if (arcType == VGU_ARC_PIE || arcType == VGU_ARC_CHORD) {
+      cmds[c] = VG_CLOSE_PATH;
+      ++c;
+   }
+
+   assert(c < 11);
+
+   vgu_append_float_coords(path, cmds, c, coords, i);
+
+   return VGU_NO_ERROR;
+}
+
+VGUErrorCode vguComputeWarpQuadToSquare(VGfloat sx0, VGfloat sy0,
+                                        VGfloat sx1, VGfloat sy1,
+                                        VGfloat sx2, VGfloat sy2,
+                                        VGfloat sx3, VGfloat sy3,
+                                        VGfloat * matrix)
+{
+   struct matrix mat;
+
+   if (!matrix || !is_aligned(matrix))
+      return VGU_ILLEGAL_ARGUMENT_ERROR;
+
+   if (!matrix_quad_to_square(sx0, sy0,
+                              sx1, sy1,
+                              sx2, sy2,
+                              sx3, sy3,
+                              &mat))
+      return VGU_BAD_WARP_ERROR;
+
+   if (!matrix_is_invertible(&mat))
+      return VGU_BAD_WARP_ERROR;
+
+   memcpy(matrix, mat.m, sizeof(VGfloat) * 9);
+
+   return VGU_NO_ERROR;
+}
+
+VGUErrorCode vguComputeWarpSquareToQuad(VGfloat dx0, VGfloat dy0,
+                                        VGfloat dx1, VGfloat dy1,
+                                        VGfloat dx2, VGfloat dy2,
+                                        VGfloat dx3, VGfloat dy3,
+                                        VGfloat * matrix)
+{
+   struct matrix mat;
+
+   if (!matrix || !is_aligned(matrix))
+      return VGU_ILLEGAL_ARGUMENT_ERROR;
+
+   if (!matrix_square_to_quad(dx0, dy0,
+                              dx1, dy1,
+                              dx2, dy2,
+                              dx3, dy3,
+                              &mat))
+      return VGU_BAD_WARP_ERROR;
+
+   if (!matrix_is_invertible(&mat))
+      return VGU_BAD_WARP_ERROR;
+
+   memcpy(matrix, mat.m, sizeof(VGfloat) * 9);
+
+   return VGU_NO_ERROR;
+}
+
+VGUErrorCode vguComputeWarpQuadToQuad(VGfloat dx0, VGfloat dy0,
+                                      VGfloat dx1, VGfloat dy1,
+                                      VGfloat dx2, VGfloat dy2,
+                                      VGfloat dx3, VGfloat dy3,
+                                      VGfloat sx0, VGfloat sy0,
+                                      VGfloat sx1, VGfloat sy1,
+                                      VGfloat sx2, VGfloat sy2,
+                                      VGfloat sx3, VGfloat sy3,
+                                      VGfloat * matrix)
+{
+   struct matrix mat;
+
+   if (!matrix || !is_aligned(matrix))
+      return VGU_ILLEGAL_ARGUMENT_ERROR;
+
+   if (!matrix_quad_to_quad(dx0, dy0,
+                            dx1, dy1,
+                            dx2, dy2,
+                            dx3, dy3,
+                            sx0, sy0,
+                            sx1, sy1,
+                            sx2, sy2,
+                            sx3, sy3,
+                            &mat))
+      return VGU_BAD_WARP_ERROR;
+
+   memcpy(matrix, mat.m, sizeof(VGfloat) * 9);
+
+   return VGU_NO_ERROR;
+}