summaryrefslogtreecommitdiff
path: root/src/gallium/state_trackers/vega
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/state_trackers/vega')
-rw-r--r--src/gallium/state_trackers/vega/Makefile128
-rw-r--r--src/gallium/state_trackers/vega/api_consts.h56
-rw-r--r--src/gallium/state_trackers/vega/api_context.c75
-rw-r--r--src/gallium/state_trackers/vega/api_filters.c805
-rw-r--r--src/gallium/state_trackers/vega/api_images.c489
-rw-r--r--src/gallium/state_trackers/vega/api_masks.c373
-rw-r--r--src/gallium/state_trackers/vega/api_misc.c83
-rw-r--r--src/gallium/state_trackers/vega/api_paint.c166
-rw-r--r--src/gallium/state_trackers/vega/api_params.c1673
-rw-r--r--src/gallium/state_trackers/vega/api_path.c488
-rw-r--r--src/gallium/state_trackers/vega/api_text.c258
-rw-r--r--src/gallium/state_trackers/vega/api_transform.c128
-rw-r--r--src/gallium/state_trackers/vega/arc.c708
-rw-r--r--src/gallium/state_trackers/vega/arc.h80
-rw-r--r--src/gallium/state_trackers/vega/asm_fill.h246
-rw-r--r--src/gallium/state_trackers/vega/asm_filters.h117
-rw-r--r--src/gallium/state_trackers/vega/asm_util.h136
-rw-r--r--src/gallium/state_trackers/vega/bezier.c704
-rw-r--r--src/gallium/state_trackers/vega/bezier.h81
-rw-r--r--src/gallium/state_trackers/vega/image.c654
-rw-r--r--src/gallium/state_trackers/vega/image.h104
-rw-r--r--src/gallium/state_trackers/vega/mask.c690
-rw-r--r--src/gallium/state_trackers/vega/mask.h68
-rw-r--r--src/gallium/state_trackers/vega/matrix.h462
-rw-r--r--src/gallium/state_trackers/vega/paint.c699
-rw-r--r--src/gallium/state_trackers/vega/paint.h118
-rw-r--r--src/gallium/state_trackers/vega/path.c2034
-rw-r--r--src/gallium/state_trackers/vega/path.h126
-rw-r--r--src/gallium/state_trackers/vega/path_utils.h109
-rw-r--r--src/gallium/state_trackers/vega/polygon.c550
-rw-r--r--src/gallium/state_trackers/vega/polygon.h75
-rw-r--r--src/gallium/state_trackers/vega/renderer.c592
-rw-r--r--src/gallium/state_trackers/vega/renderer.h76
-rw-r--r--src/gallium/state_trackers/vega/shader.c310
-rw-r--r--src/gallium/state_trackers/vega/shader.h56
-rw-r--r--src/gallium/state_trackers/vega/shaders_cache.c439
-rw-r--r--src/gallium/state_trackers/vega/shaders_cache.h77
-rw-r--r--src/gallium/state_trackers/vega/st_inlines.h159
-rw-r--r--src/gallium/state_trackers/vega/stroker.c1349
-rw-r--r--src/gallium/state_trackers/vega/stroker.h89
-rw-r--r--src/gallium/state_trackers/vega/util_array.h122
-rw-r--r--src/gallium/state_trackers/vega/vg_context.c543
-rw-r--r--src/gallium/state_trackers/vega/vg_context.h292
-rw-r--r--src/gallium/state_trackers/vega/vg_state.c124
-rw-r--r--src/gallium/state_trackers/vega/vg_state.h109
-rw-r--r--src/gallium/state_trackers/vega/vg_tracker.c416
-rw-r--r--src/gallium/state_trackers/vega/vg_tracker.h107
-rw-r--r--src/gallium/state_trackers/vega/vg_translate.c1030
-rw-r--r--src/gallium/state_trackers/vega/vg_translate.h49
-rw-r--r--src/gallium/state_trackers/vega/vgu.c450
50 files changed, 18872 insertions, 0 deletions
diff --git a/src/gallium/state_trackers/vega/Makefile b/src/gallium/state_trackers/vega/Makefile
new file mode 100644
index 0000000000..b8c805b06c
--- /dev/null
+++ b/src/gallium/state_trackers/vega/Makefile
@@ -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
index 0000000000..e1b48d4a46
--- /dev/null
+++ b/src/gallium/state_trackers/vega/api_consts.h
@@ -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
index 0000000000..47db102dd2
--- /dev/null
+++ b/src/gallium/state_trackers/vega/api_context.c
@@ -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
index 0000000000..862cbb03c4
--- /dev/null
+++ b/src/gallium/state_trackers/vega/api_filters.c
@@ -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
index 0000000000..c437553bc2
--- /dev/null
+++ b/src/gallium/state_trackers/vega/api_images.c
@@ -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
index 0000000000..4f9f3dae17
--- /dev/null
+++ b/src/gallium/state_trackers/vega/api_masks.c
@@ -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
index 0000000000..78ba0bc110
--- /dev/null
+++ b/src/gallium/state_trackers/vega/api_misc.c
@@ -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
index 0000000000..dd3ac5bdb0
--- /dev/null
+++ b/src/gallium/state_trackers/vega/api_paint.c
@@ -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
index 0000000000..db77fd9cb0
--- /dev/null
+++ b/src/gallium/state_trackers/vega/api_params.c
@@ -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
index 0000000000..a6b7a2bb93
--- /dev/null
+++ b/src/gallium/state_trackers/vega/api_path.c
@@ -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
index 0000000000..d8411cf3e8
--- /dev/null
+++ b/src/gallium/state_trackers/vega/api_text.c
@@ -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
index 0000000000..763a5ec415
--- /dev/null
+++ b/src/gallium/state_trackers/vega/api_transform.c
@@ -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
index 0000000000..e74c7f0334
--- /dev/null
+++ b/src/gallium/state_trackers/vega/arc.c
@@ -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
index 0000000000..3205cd5021
--- /dev/null
+++ b/src/gallium/state_trackers/vega/arc.h
@@ -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
index 0000000000..2f394ad6c5
--- /dev/null
+++ b/src/gallium/state_trackers/vega/asm_fill.h
@@ -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
index 0000000000..9a49f2e12d
--- /dev/null
+++ b/src/gallium/state_trackers/vega/asm_filters.h
@@ -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: BGNLOOP :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: ENDLOOP :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
index 0000000000..218e1d166d
--- /dev/null
+++ b/src/gallium/state_trackers/vega/asm_util.h
@@ -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
index 0000000000..39a7ade016
--- /dev/null
+++ b/src/gallium/state_trackers/vega/bezier.c
@@ -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
index 0000000000..e06666051c
--- /dev/null
+++ b/src/gallium/state_trackers/vega/bezier.h
@@ -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
index 0000000000..9a722980d5
--- /dev/null
+++ b/src/gallium/state_trackers/vega/image.c
@@ -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
index 0000000000..78e17cffa6
--- /dev/null
+++ b/src/gallium/state_trackers/vega/image.h
@@ -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
index 0000000000..24650a37d5
--- /dev/null
+++ b/src/gallium/state_trackers/vega/mask.c
@@ -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
index 0000000000..5eaaede0e3
--- /dev/null
+++ b/src/gallium/state_trackers/vega/mask.h
@@ -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
index 0000000000..4c207f912a
--- /dev/null
+++ b/src/gallium/state_trackers/vega/matrix.h
@@ -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
index 0000000000..04a6ba9cdc
--- /dev/null
+++ b/src/gallium/state_trackers/vega/paint.c
@@ -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
index 0000000000..999b5c167c
--- /dev/null
+++ b/src/gallium/state_trackers/vega/paint.h
@@ -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
index 0000000000..d04f9d9ae6
--- /dev/null
+++ b/src/gallium/state_trackers/vega/path.c
@@ -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
index 0000000000..e34538b736
--- /dev/null
+++ b/src/gallium/state_trackers/vega/path.h
@@ -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
index 0000000000..c2b3221dc5
--- /dev/null
+++ b/src/gallium/state_trackers/vega/path_utils.h
@@ -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
index 0000000000..b6d282d803
--- /dev/null
+++ b/src/gallium/state_trackers/vega/polygon.c
@@ -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
index 0000000000..22672b728e
--- /dev/null
+++ b/src/gallium/state_trackers/vega/polygon.h
@@ -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
index 0000000000..f7c5f2f0cd
--- /dev/null
+++ b/src/gallium/state_trackers/vega/renderer.c
@@ -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
index 0000000000..990cd32c31
--- /dev/null
+++ b/src/gallium/state_trackers/vega/renderer.h
@@ -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
index 0000000000..d9074a377b
--- /dev/null
+++ b/src/gallium/state_trackers/vega/shader.c
@@ -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
index 0000000000..847eee6a31
--- /dev/null
+++ b/src/gallium/state_trackers/vega/shader.h
@@ -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
index 0000000000..fd0831fab1
--- /dev/null
+++ b/src/gallium/state_trackers/vega/shaders_cache.c
@@ -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
index 0000000000..feca58b61a
--- /dev/null
+++ b/src/gallium/state_trackers/vega/shaders_cache.h
@@ -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
index 0000000000..1f331dfcdb
--- /dev/null
+++ b/src/gallium/state_trackers/vega/st_inlines.h
@@ -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
index 0000000000..1b92d2b5c6
--- /dev/null
+++ b/src/gallium/state_trackers/vega/stroker.c
@@ -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
index 0000000000..36543cd923
--- /dev/null
+++ b/src/gallium/state_trackers/vega/stroker.h
@@ -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
index 0000000000..4343dfe36e
--- /dev/null
+++ b/src/gallium/state_trackers/vega/util_array.h
@@ -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
index 0000000000..e0ff02f3a9
--- /dev/null
+++ b/src/gallium/state_trackers/vega/vg_context.c
@@ -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
index 0000000000..ccc8889c8c
--- /dev/null
+++ b/src/gallium/state_trackers/vega/vg_context.h
@@ -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
index 0000000000..6f6bfdaf7a
--- /dev/null
+++ b/src/gallium/state_trackers/vega/vg_state.c
@@ -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
index 0000000000..ed90689f91
--- /dev/null
+++ b/src/gallium/state_trackers/vega/vg_state.h
@@ -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
index 0000000000..56cc60aebe
--- /dev/null
+++ b/src/gallium/state_trackers/vega/vg_tracker.c
@@ -0,0 +1,416 @@
+/**************************************************************************
+ *
+ * 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;
+ }
+}
+
+struct vg_context *st_get_current(void)
+{
+ return vg_current_context();
+}
+
+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_bind_texture_surface(struct pipe_surface *ps, int target, int level,
+ enum pipe_format format)
+{
+ return 0;
+}
+
+int st_unbind_texture_surface(struct pipe_surface *ps, int target, int level)
+{
+ 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
index 0000000000..5457631106
--- /dev/null
+++ b/src/gallium/state_trackers/vega/vg_tracker.h
@@ -0,0 +1,107 @@
+/**************************************************************************
+ *
+ * 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_bind_texture_surface(struct pipe_surface *ps, int target, int level,
+ enum pipe_format format);
+
+int st_unbind_texture_surface(struct pipe_surface *ps, int target, int level);
+
+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);
+
+struct vg_context *st_get_current(void);
+
+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
index 0000000000..00e0764706
--- /dev/null
+++ b/src/gallium/state_trackers/vega/vg_translate.c
@@ -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
index 0000000000..70815bacbc
--- /dev/null
+++ b/src/gallium/state_trackers/vega/vg_translate.h
@@ -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
index 0000000000..7dc51c5599
--- /dev/null
+++ b/src/gallium/state_trackers/vega/vgu.c
@@ -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;
+}