summaryrefslogtreecommitdiff
path: root/src/gallium/state_trackers
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/state_trackers')
-rw-r--r--src/gallium/state_trackers/Makefile29
-rw-r--r--src/gallium/state_trackers/README2
-rw-r--r--src/gallium/state_trackers/dri/Makefile12
-rw-r--r--src/gallium/state_trackers/dri/SConscript6
-rw-r--r--src/gallium/state_trackers/dri/common/dri1_helper.c129
-rw-r--r--src/gallium/state_trackers/dri/common/dri1_helper.h61
-rw-r--r--src/gallium/state_trackers/dri/common/dri_context.c180
-rw-r--r--src/gallium/state_trackers/dri/common/dri_context.h96
-rw-r--r--src/gallium/state_trackers/dri/common/dri_drawable.c224
-rw-r--r--src/gallium/state_trackers/dri/common/dri_drawable.h98
-rw-r--r--src/gallium/state_trackers/dri/common/dri_screen.c439
-rw-r--r--src/gallium/state_trackers/dri/common/dri_screen.h139
-rw-r--r--src/gallium/state_trackers/dri/common/dri_wrapper.h10
-rw-r--r--src/gallium/state_trackers/dri/drm/Makefile31
-rw-r--r--src/gallium/state_trackers/dri/drm/SConscript28
l---------src/gallium/state_trackers/dri/drm/dri1_helper.c1
-rw-r--r--src/gallium/state_trackers/dri/drm/dri2.c546
-rw-r--r--src/gallium/state_trackers/dri/drm/dri2.h37
l---------src/gallium/state_trackers/dri/drm/dri_context.c1
l---------src/gallium/state_trackers/dri/drm/dri_drawable.c1
l---------src/gallium/state_trackers/dri/drm/dri_screen.c1
-rw-r--r--src/gallium/state_trackers/dri/sw/Makefile26
-rw-r--r--src/gallium/state_trackers/dri/sw/SConscript28
l---------src/gallium/state_trackers/dri/sw/dri1_helper.c1
l---------src/gallium/state_trackers/dri/sw/dri_context.c1
l---------src/gallium/state_trackers/dri/sw/dri_drawable.c1
l---------src/gallium/state_trackers/dri/sw/dri_screen.c1
-rw-r--r--src/gallium/state_trackers/dri/sw/drisw.c289
-rw-r--r--src/gallium/state_trackers/dri/sw/drisw.h43
-rw-r--r--src/gallium/state_trackers/egl/Makefile87
-rw-r--r--src/gallium/state_trackers/egl/SConscript32
-rw-r--r--src/gallium/state_trackers/egl/common/egl_g3d.c616
-rw-r--r--src/gallium/state_trackers/egl/common/egl_g3d.h109
-rw-r--r--src/gallium/state_trackers/egl/common/egl_g3d_api.c814
-rw-r--r--src/gallium/state_trackers/egl/common/egl_g3d_api.h37
-rw-r--r--src/gallium/state_trackers/egl/common/egl_g3d_image.c136
-rw-r--r--src/gallium/state_trackers/egl/common/egl_g3d_image.h42
-rw-r--r--src/gallium/state_trackers/egl/common/egl_g3d_st.c479
-rw-r--r--src/gallium/state_trackers/egl/common/egl_g3d_st.h83
-rw-r--r--src/gallium/state_trackers/egl/common/native.h217
-rw-r--r--src/gallium/state_trackers/egl/common/native_helper.c253
-rw-r--r--src/gallium/state_trackers/egl/common/native_helper.h74
-rw-r--r--src/gallium/state_trackers/egl/common/native_modeset.h88
-rw-r--r--src/gallium/state_trackers/egl/common/native_probe.h68
-rw-r--r--src/gallium/state_trackers/egl/fbdev/native_fbdev.c470
-rw-r--r--src/gallium/state_trackers/egl/gdi/native_gdi.c406
-rw-r--r--src/gallium/state_trackers/egl/kms/native_kms.c830
-rw-r--r--src/gallium/state_trackers/egl/kms/native_kms.h138
-rw-r--r--src/gallium/state_trackers/egl/x11/glxinit.c682
-rw-r--r--src/gallium/state_trackers/egl/x11/glxinit.h11
-rw-r--r--src/gallium/state_trackers/egl/x11/native_dri2.c794
-rw-r--r--src/gallium/state_trackers/egl/x11/native_x11.c152
-rw-r--r--src/gallium/state_trackers/egl/x11/native_x11.h41
-rw-r--r--src/gallium/state_trackers/egl/x11/native_ximage.c498
-rw-r--r--src/gallium/state_trackers/egl/x11/x11_screen.c434
-rw-r--r--src/gallium/state_trackers/egl/x11/x11_screen.h110
-rw-r--r--src/gallium/state_trackers/glx/Makefile25
-rw-r--r--src/gallium/state_trackers/glx/xlib/Makefile19
-rw-r--r--src/gallium/state_trackers/glx/xlib/SConscript27
-rw-r--r--src/gallium/state_trackers/glx/xlib/glx_api.c2648
-rw-r--r--src/gallium/state_trackers/glx/xlib/glx_getproc.c215
-rw-r--r--src/gallium/state_trackers/glx/xlib/glx_usefont.c375
-rw-r--r--src/gallium/state_trackers/glx/xlib/xm_api.c1240
-rw-r--r--src/gallium/state_trackers/glx/xlib/xm_api.h383
-rw-r--r--src/gallium/state_trackers/glx/xlib/xm_public.h48
-rw-r--r--src/gallium/state_trackers/glx/xlib/xm_st.c338
-rw-r--r--src/gallium/state_trackers/glx/xlib/xm_st.h52
-rw-r--r--src/gallium/state_trackers/python/README43
-rw-r--r--src/gallium/state_trackers/python/SConscript59
-rw-r--r--src/gallium/state_trackers/python/gallium.i105
-rw-r--r--src/gallium/state_trackers/python/p_compiler.i29
-rw-r--r--src/gallium/state_trackers/python/p_context.i768
-rw-r--r--src/gallium/state_trackers/python/p_device.i140
-rw-r--r--src/gallium/state_trackers/python/p_state.i184
-rw-r--r--src/gallium/state_trackers/python/p_texture.i156
-rw-r--r--src/gallium/state_trackers/python/st_device.c305
-rw-r--r--src/gallium/state_trackers/python/st_device.h106
-rw-r--r--src/gallium/state_trackers/python/st_hardpipe_winsys.c212
-rw-r--r--src/gallium/state_trackers/python/st_sample.c595
-rw-r--r--src/gallium/state_trackers/python/st_sample.h53
-rw-r--r--src/gallium/state_trackers/python/st_softpipe_winsys.c78
-rw-r--r--src/gallium/state_trackers/python/st_winsys.h43
-rw-r--r--src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-abs.pngbin0 -> 8750 bytes
-rw-r--r--src/gallium/state_trackers/python/u_format.i88
-rw-r--r--src/gallium/state_trackers/vega/Makefile41
-rw-r--r--src/gallium/state_trackers/vega/SConscript51
-rw-r--r--src/gallium/state_trackers/vega/api.c88
-rw-r--r--src/gallium/state_trackers/vega/api.h51
-rw-r--r--src/gallium/state_trackers/vega/api_consts.h56
-rw-r--r--src/gallium/state_trackers/vega/api_context.c79
-rw-r--r--src/gallium/state_trackers/vega/api_filters.c830
-rw-r--r--src/gallium/state_trackers/vega/api_images.c489
-rw-r--r--src/gallium/state_trackers/vega/api_masks.c368
-rw-r--r--src/gallium/state_trackers/vega/api_misc.c84
-rw-r--r--src/gallium/state_trackers/vega/api_paint.c167
-rw-r--r--src/gallium/state_trackers/vega/api_params.c1674
-rw-r--r--src/gallium/state_trackers/vega/api_path.c488
-rw-r--r--src/gallium/state_trackers/vega/api_text.c259
-rw-r--r--src/gallium/state_trackers/vega/api_transform.c129
-rw-r--r--src/gallium/state_trackers/vega/arc.c709
-rw-r--r--src/gallium/state_trackers/vega/arc.h80
-rw-r--r--src/gallium/state_trackers/vega/asm_fill.h455
-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.c706
-rw-r--r--src/gallium/state_trackers/vega/bezier.h81
-rw-r--r--src/gallium/state_trackers/vega/image.c662
-rw-r--r--src/gallium/state_trackers/vega/image.h104
-rw-r--r--src/gallium/state_trackers/vega/mask.c697
-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.c719
-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.c613
-rw-r--r--src/gallium/state_trackers/vega/renderer.h77
-rw-r--r--src/gallium/state_trackers/vega/shader.c311
-rw-r--r--src/gallium/state_trackers/vega/shader.h56
-rw-r--r--src/gallium/state_trackers/vega/shaders_cache.c440
-rw-r--r--src/gallium/state_trackers/vega/shaders_cache.h77
-rw-r--r--src/gallium/state_trackers/vega/st_inlines.h122
-rw-r--r--src/gallium/state_trackers/vega/stroker.c1350
-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_api.h37
-rw-r--r--src/gallium/state_trackers/vega/vg_context.c568
-rw-r--r--src/gallium/state_trackers/vega/vg_context.h303
-rw-r--r--src/gallium/state_trackers/vega/vg_manager.c552
-rw-r--r--src/gallium/state_trackers/vega/vg_manager.h41
-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_translate.c1112
-rw-r--r--src/gallium/state_trackers/vega/vg_translate.h49
-rw-r--r--src/gallium/state_trackers/vega/vgu.c450
-rw-r--r--src/gallium/state_trackers/wgl/SConscript42
-rw-r--r--src/gallium/state_trackers/wgl/opengl32.def389
-rw-r--r--src/gallium/state_trackers/wgl/opengl32.mingw.def388
-rw-r--r--src/gallium/state_trackers/wgl/stw_context.c727
-rw-r--r--src/gallium/state_trackers/wgl/stw_context.h55
-rw-r--r--src/gallium/state_trackers/wgl/stw_device.c223
-rw-r--r--src/gallium/state_trackers/wgl/stw_device.h81
-rw-r--r--src/gallium/state_trackers/wgl/stw_ext_extensionsstring.c59
-rw-r--r--src/gallium/state_trackers/wgl/stw_ext_gallium.c50
-rw-r--r--src/gallium/state_trackers/wgl/stw_ext_gallium.h47
-rw-r--r--src/gallium/state_trackers/wgl/stw_ext_pixelformat.c482
-rw-r--r--src/gallium/state_trackers/wgl/stw_ext_swapinterval.c57
-rw-r--r--src/gallium/state_trackers/wgl/stw_framebuffer.c592
-rw-r--r--src/gallium/state_trackers/wgl/stw_framebuffer.h167
-rw-r--r--src/gallium/state_trackers/wgl/stw_getprocaddress.c90
-rw-r--r--src/gallium/state_trackers/wgl/stw_icd.h599
-rw-r--r--src/gallium/state_trackers/wgl/stw_pixelformat.c403
-rw-r--r--src/gallium/state_trackers/wgl/stw_pixelformat.h69
-rw-r--r--src/gallium/state_trackers/wgl/stw_st.c312
-rw-r--r--src/gallium/state_trackers/wgl/stw_st.h47
-rw-r--r--src/gallium/state_trackers/wgl/stw_tls.c139
-rw-r--r--src/gallium/state_trackers/wgl/stw_tls.h59
-rw-r--r--src/gallium/state_trackers/wgl/stw_wgl.c321
-rw-r--r--src/gallium/state_trackers/wgl/stw_wgl.h79
-rw-r--r--src/gallium/state_trackers/wgl/stw_winsys.h106
-rw-r--r--src/gallium/state_trackers/xorg/Makefile23
-rw-r--r--src/gallium/state_trackers/xorg/SConscript36
-rw-r--r--src/gallium/state_trackers/xorg/xorg_composite.c583
-rw-r--r--src/gallium/state_trackers/xorg/xorg_composite.h36
-rw-r--r--src/gallium/state_trackers/xorg/xorg_crtc.c417
-rw-r--r--src/gallium/state_trackers/xorg/xorg_dri2.c467
-rw-r--r--src/gallium/state_trackers/xorg/xorg_driver.c1243
-rw-r--r--src/gallium/state_trackers/xorg/xorg_exa.c1088
-rw-r--r--src/gallium/state_trackers/xorg/xorg_exa.h81
-rw-r--r--src/gallium/state_trackers/xorg/xorg_exa_tgsi.c690
-rw-r--r--src/gallium/state_trackers/xorg/xorg_exa_tgsi.h59
-rw-r--r--src/gallium/state_trackers/xorg/xorg_output.c294
-rw-r--r--src/gallium/state_trackers/xorg/xorg_renderer.c716
-rw-r--r--src/gallium/state_trackers/xorg/xorg_renderer.h96
-rw-r--r--src/gallium/state_trackers/xorg/xorg_tracker.h218
-rw-r--r--src/gallium/state_trackers/xorg/xorg_winsys.h50
-rw-r--r--src/gallium/state_trackers/xorg/xorg_xv.c768
180 files changed, 50408 insertions, 0 deletions
diff --git a/src/gallium/state_trackers/Makefile b/src/gallium/state_trackers/Makefile
new file mode 100644
index 0000000000..0900efc664
--- /dev/null
+++ b/src/gallium/state_trackers/Makefile
@@ -0,0 +1,29 @@
+TOP = ../../..
+include $(TOP)/configs/current
+
+
+SUBDIRS = $(GALLIUM_STATE_TRACKERS_DIRS)
+
+
+default: subdirs
+
+
+subdirs:
+ @for dir in $(SUBDIRS) ; do \
+ if [ -d $$dir ] ; then \
+ (cd $$dir && $(MAKE)) || exit 1 ; \
+ fi \
+ done
+
+
+clean:
+ rm -f `find . -name \*.[oa]`
+ rm -f `find . -name depend`
+
+
+install:
+ @for dir in $(SUBDIRS) ; do \
+ if [ -d $$dir ] ; then \
+ (cd $$dir && $(MAKE) $@) || exit 1 ; \
+ fi \
+ done
diff --git a/src/gallium/state_trackers/README b/src/gallium/state_trackers/README
new file mode 100644
index 0000000000..28dd27bbd5
--- /dev/null
+++ b/src/gallium/state_trackers/README
@@ -0,0 +1,2 @@
+This directory is a placeholder for incubating state-trackers. Mesa's
+state-tracker is in src/mesa.
diff --git a/src/gallium/state_trackers/dri/Makefile b/src/gallium/state_trackers/dri/Makefile
new file mode 100644
index 0000000000..72e70577b3
--- /dev/null
+++ b/src/gallium/state_trackers/dri/Makefile
@@ -0,0 +1,12 @@
+# src/gallium/state_trackers/dri/Makefile
+TOP = ../../../..
+include $(TOP)/configs/current
+
+SUBDIRS = drm sw
+
+default install clean:
+ @for dir in $(SUBDIRS) ; do \
+ if [ -d $$dir ] ; then \
+ (cd $$dir && $(MAKE) $@) || exit 1; \
+ fi \
+ done
diff --git a/src/gallium/state_trackers/dri/SConscript b/src/gallium/state_trackers/dri/SConscript
new file mode 100644
index 0000000000..aba60fb8c5
--- /dev/null
+++ b/src/gallium/state_trackers/dri/SConscript
@@ -0,0 +1,6 @@
+Import('*')
+
+SConscript([
+ 'sw/SConscript',
+ 'drm/SConscript',
+])
diff --git a/src/gallium/state_trackers/dri/common/dri1_helper.c b/src/gallium/state_trackers/dri/common/dri1_helper.c
new file mode 100644
index 0000000000..ad6c7d3750
--- /dev/null
+++ b/src/gallium/state_trackers/dri/common/dri1_helper.c
@@ -0,0 +1,129 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+/*
+ * Management of pipe objects (surface / pipe / fences) used by DRI1 and DRISW.
+ *
+ * Author: Keith Whitwell <keithw@vmware.com>
+ * Author: Jakob Bornecrantz <wallbraker@gmail.com>
+ */
+
+#include "util/u_inlines.h"
+#include "pipe/p_context.h"
+
+#include "dri_screen.h"
+#include "dri_context.h"
+#include "dri_drawable.h"
+#include "dri1_helper.h"
+
+struct pipe_fence_handle *
+dri1_swap_fences_pop_front(struct dri_drawable *draw)
+{
+ struct pipe_screen *screen = dri_screen(draw->sPriv)->base.screen;
+ struct pipe_fence_handle *fence = NULL;
+
+ if (draw->cur_fences >= draw->desired_fences) {
+ screen->fence_reference(screen, &fence, draw->swap_fences[draw->tail]);
+ screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL);
+ --draw->cur_fences;
+ draw->tail &= DRI_SWAP_FENCES_MASK;
+ }
+ return fence;
+}
+
+void
+dri1_swap_fences_push_back(struct dri_drawable *draw,
+ struct pipe_fence_handle *fence)
+{
+ struct pipe_screen *screen = dri_screen(draw->sPriv)->base.screen;
+
+ if (!fence)
+ return;
+
+ if (draw->cur_fences < DRI_SWAP_FENCES_MAX) {
+ draw->cur_fences++;
+ screen->fence_reference(screen, &draw->swap_fences[draw->head++],
+ fence);
+ draw->head &= DRI_SWAP_FENCES_MASK;
+ }
+}
+
+void
+dri1_swap_fences_clear(struct dri_drawable *drawable)
+{
+ struct pipe_screen *screen = dri_screen(drawable->sPriv)->base.screen;
+ struct pipe_fence_handle *fence;
+
+ while (drawable->cur_fences) {
+ fence = dri1_swap_fences_pop_front(drawable);
+ screen->fence_reference(screen, &fence, NULL);
+ }
+}
+
+struct pipe_surface *
+dri1_get_pipe_surface(struct dri_drawable *drawable, struct pipe_resource *ptex)
+{
+ struct pipe_screen *pipe_screen = dri_screen(drawable->sPriv)->base.screen;
+ struct pipe_surface *psurf = drawable->dri1_surface;
+
+ if (!psurf || psurf->texture != ptex) {
+ pipe_surface_reference(&drawable->dri1_surface, NULL);
+
+ drawable->dri1_surface = pipe_screen->get_tex_surface(pipe_screen,
+ ptex, 0, 0, 0, 0/* no bind flag???*/);
+
+ psurf = drawable->dri1_surface;
+ }
+
+ return psurf;
+}
+
+void
+dri1_destroy_pipe_surface(struct dri_drawable *drawable)
+{
+ pipe_surface_reference(&drawable->dri1_surface, NULL);
+}
+
+struct pipe_context *
+dri1_get_pipe_context(struct dri_screen *screen)
+{
+ struct pipe_context *pipe = screen->dri1_pipe;
+
+ if (!pipe) {
+ screen->dri1_pipe =
+ screen->base.screen->context_create(screen->base.screen, NULL);
+ pipe = screen->dri1_pipe;
+ }
+
+ return pipe;
+}
+
+void
+dri1_destroy_pipe_context(struct dri_screen *screen)
+{
+ if (screen->dri1_pipe)
+ screen->dri1_pipe->destroy(screen->dri1_pipe);
+}
diff --git a/src/gallium/state_trackers/dri/common/dri1_helper.h b/src/gallium/state_trackers/dri/common/dri1_helper.h
new file mode 100644
index 0000000000..c98adf2df2
--- /dev/null
+++ b/src/gallium/state_trackers/dri/common/dri1_helper.h
@@ -0,0 +1,61 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+/*
+ * Author: Keith Whitwell <keithw@vmware.com>
+ * Author: Jakob Bornecrantz <wallbraker@gmail.com>
+ */
+
+#ifndef DRI1_HELPER_H
+#define DRI1_HELPER_H
+
+#include "dri_screen.h"
+#include "dri_context.h"
+#include "dri_drawable.h"
+
+struct pipe_fence_handle *
+dri1_swap_fences_pop_front(struct dri_drawable *draw);
+
+void
+dri1_swap_fences_push_back(struct dri_drawable *draw,
+ struct pipe_fence_handle *fence);
+
+void
+dri1_swap_fences_clear(struct dri_drawable *drawable);
+
+struct pipe_surface *
+dri1_get_pipe_surface(struct dri_drawable *drawable, struct pipe_resource *ptex);
+
+void
+dri1_destroy_pipe_surface(struct dri_drawable *drawable);
+
+struct pipe_context *
+dri1_get_pipe_context(struct dri_screen *screen);
+
+void
+dri1_destroy_pipe_context(struct dri_screen *screen);
+
+#endif /* DRI1_HELPER_H */
diff --git a/src/gallium/state_trackers/dri/common/dri_context.c b/src/gallium/state_trackers/dri/common/dri_context.c
new file mode 100644
index 0000000000..203682ef33
--- /dev/null
+++ b/src/gallium/state_trackers/dri/common/dri_context.c
@@ -0,0 +1,180 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+/*
+ * Author: Keith Whitwell <keithw@vmware.com>
+ * Author: Jakob Bornecrantz <wallbraker@gmail.com>
+ */
+
+#include "utils.h"
+
+#include "dri_screen.h"
+#include "dri_drawable.h"
+#include "dri_context.h"
+
+#include "pipe/p_context.h"
+#include "state_tracker/st_context.h"
+
+static void
+dri_init_extensions(struct dri_context *ctx)
+{
+ struct st_context *st = (struct st_context *) ctx->st;
+
+ /* New extensions should be added in mesa/state_tracker/st_extensions.c
+ * and not in this file. */
+ driInitExtensions(st->ctx, NULL, GL_FALSE);
+}
+
+GLboolean
+dri_create_context(gl_api api, const __GLcontextModes * visual,
+ __DRIcontext * cPriv, void *sharedContextPrivate)
+{
+ __DRIscreen *sPriv = cPriv->driScreenPriv;
+ struct dri_screen *screen = dri_screen(sPriv);
+ struct st_api *stapi = screen->st_api;
+ struct dri_context *ctx = NULL;
+ struct st_context_iface *st_share = NULL;
+ struct st_visual stvis;
+
+ if (sharedContextPrivate) {
+ st_share = ((struct dri_context *)sharedContextPrivate)->st;
+ }
+
+ ctx = CALLOC_STRUCT(dri_context);
+ if (ctx == NULL)
+ goto fail;
+
+ cPriv->driverPrivate = ctx;
+ ctx->cPriv = cPriv;
+ ctx->sPriv = sPriv;
+ ctx->lock = screen->drmLock;
+
+ driParseConfigFiles(&ctx->optionCache,
+ &screen->optionCache, sPriv->myNum, "dri");
+
+ dri_fill_st_visual(&stvis, screen, visual);
+ ctx->st = stapi->create_context(stapi, &screen->base, &stvis, st_share);
+ if (ctx->st == NULL)
+ goto fail;
+ ctx->st->st_manager_private = (void *) ctx;
+
+ dri_init_extensions(ctx);
+
+ return GL_TRUE;
+
+ fail:
+ if (ctx && ctx->st)
+ ctx->st->destroy(ctx->st);
+
+ FREE(ctx);
+ return FALSE;
+}
+
+void
+dri_destroy_context(__DRIcontext * cPriv)
+{
+ struct dri_context *ctx = dri_context(cPriv);
+
+ /* note: we are freeing values and nothing more because
+ * driParseConfigFiles allocated values only - the rest
+ * is owned by screen optionCache.
+ */
+ FREE(ctx->optionCache.values);
+
+ /* No particular reason to wait for command completion before
+ * destroying a context, but it is probably worthwhile flushing it
+ * to avoid having to add code elsewhere to cope with flushing a
+ * partially destroyed context.
+ */
+ ctx->st->flush(ctx->st, 0, NULL);
+ ctx->st->destroy(ctx->st);
+
+ FREE(ctx);
+}
+
+GLboolean
+dri_unbind_context(__DRIcontext * cPriv)
+{
+ /* dri_util.c ensures cPriv is not null */
+ struct dri_screen *screen = dri_screen(cPriv->driScreenPriv);
+ struct dri_context *ctx = dri_context(cPriv);
+ struct st_api *stapi = screen->st_api;
+
+ if (--ctx->bind_count == 0) {
+ if (ctx->st == stapi->get_current(stapi)) {
+ ctx->st->flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
+ stapi->make_current(stapi, NULL, NULL, NULL);
+ }
+ }
+
+ return GL_TRUE;
+}
+
+GLboolean
+dri_make_current(__DRIcontext * cPriv,
+ __DRIdrawable * driDrawPriv,
+ __DRIdrawable * driReadPriv)
+{
+ /* dri_util.c ensures cPriv is not null */
+ struct dri_screen *screen = dri_screen(cPriv->driScreenPriv);
+ struct dri_context *ctx = dri_context(cPriv);
+ struct st_api *stapi = screen->st_api;
+ struct dri_drawable *draw = dri_drawable(driDrawPriv);
+ struct dri_drawable *read = dri_drawable(driReadPriv);
+ struct st_context_iface *old_st = stapi->get_current(stapi);
+
+ if (old_st && old_st != ctx->st)
+ old_st->flush(old_st, PIPE_FLUSH_RENDER_CACHE, NULL);
+
+ ++ctx->bind_count;
+
+ if (ctx->dPriv != driDrawPriv) {
+ ctx->dPriv = driDrawPriv;
+ draw->texture_stamp = driDrawPriv->lastStamp - 1;
+ }
+ if (ctx->rPriv != driReadPriv) {
+ ctx->rPriv = driReadPriv;
+ read->texture_stamp = driReadPriv->lastStamp - 1;
+ }
+
+ stapi->make_current(stapi, ctx->st, &draw->base, &read->base);
+
+ return GL_TRUE;
+}
+
+struct dri_context *
+dri_get_current(__DRIscreen *sPriv)
+{
+ struct dri_screen *screen = dri_screen(sPriv);
+ struct st_api *stapi = screen->st_api;
+ struct st_context_iface *st;
+
+ st = stapi->get_current(stapi);
+
+ return (struct dri_context *) (st) ? st->st_manager_private : NULL;
+}
+
+/* vim: set sw=3 ts=8 sts=3 expandtab: */
diff --git a/src/gallium/state_trackers/dri/common/dri_context.h b/src/gallium/state_trackers/dri/common/dri_context.h
new file mode 100644
index 0000000000..b29e853383
--- /dev/null
+++ b/src/gallium/state_trackers/dri/common/dri_context.h
@@ -0,0 +1,96 @@
+/**************************************************************************
+ *
+ * Copyright (C) 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.
+ *
+ **************************************************************************/
+/*
+ * Author: Keith Whitwell <keithw@vmware.com>
+ * Author: Jakob Bornecrantz <wallbraker@gmail.com>
+ */
+
+#ifndef DRI_CONTEXT_H
+#define DRI_CONTEXT_H
+
+#include "pipe/p_compiler.h"
+#include "dri_wrapper.h"
+#include "main/mtypes.h"
+
+struct pipe_context;
+struct pipe_fence;
+struct st_context;
+struct dri_drawable;
+
+struct dri_context
+{
+ /* dri */
+ __DRIscreen *sPriv;
+ __DRIcontext *cPriv;
+ __DRIdrawable *dPriv;
+ __DRIdrawable *rPriv;
+
+ driOptionCache optionCache;
+
+ drmLock *lock;
+ boolean isLocked;
+ boolean stLostLock;
+ boolean wsLostLock;
+
+ unsigned int bind_count;
+
+ /* gallium */
+ struct st_context_iface *st;
+};
+
+static INLINE struct dri_context *
+dri_context(__DRIcontext * driContextPriv)
+{
+ if (!driContextPriv)
+ return NULL;
+ return (struct dri_context *)driContextPriv->driverPrivate;
+}
+
+/***********************************************************************
+ * dri_context.c
+ */
+void dri_destroy_context(__DRIcontext * driContextPriv);
+
+boolean dri_unbind_context(__DRIcontext * driContextPriv);
+
+boolean
+dri_make_current(__DRIcontext * driContextPriv,
+ __DRIdrawable * driDrawPriv,
+ __DRIdrawable * driReadPriv);
+
+struct dri_context *
+dri_get_current(__DRIscreen * driScreenPriv);
+
+boolean
+dri_create_context(gl_api api,
+ const __GLcontextModes * visual,
+ __DRIcontext * driContextPriv,
+ void *sharedContextPrivate);
+
+#endif
+
+/* vim: set sw=3 ts=8 sts=3 expandtab: */
diff --git a/src/gallium/state_trackers/dri/common/dri_drawable.c b/src/gallium/state_trackers/dri/common/dri_drawable.c
new file mode 100644
index 0000000000..2bc0faffef
--- /dev/null
+++ b/src/gallium/state_trackers/dri/common/dri_drawable.c
@@ -0,0 +1,224 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+/*
+ * Author: Keith Whitwell <keithw@vmware.com>
+ * Author: Jakob Bornecrantz <wallbraker@gmail.com>
+ */
+
+#include "dri_screen.h"
+#include "dri_context.h"
+#include "dri_drawable.h"
+#include "dri1_helper.h"
+
+#include "pipe/p_screen.h"
+#include "util/u_format.h"
+#include "util/u_memory.h"
+#include "util/u_inlines.h"
+
+
+static boolean
+dri_st_framebuffer_validate(struct st_framebuffer_iface *stfbi,
+ const enum st_attachment_type *statts,
+ unsigned count,
+ struct pipe_resource **out)
+{
+ struct dri_drawable *drawable =
+ (struct dri_drawable *) stfbi->st_manager_private;
+ struct dri_screen *screen = dri_screen(drawable->sPriv);
+ unsigned statt_mask, new_mask;
+ boolean new_stamp;
+ int i;
+
+ statt_mask = 0x0;
+ for (i = 0; i < count; i++)
+ statt_mask |= (1 << statts[i]);
+
+ /* record newly allocated textures */
+ new_mask = (statt_mask & ~drawable->texture_mask);
+
+ /*
+ * dPriv->pStamp is the server stamp. It should be accessed with a lock, at
+ * least for DRI1. dPriv->lastStamp is the client stamp. It has the value
+ * of the server stamp when last checked.
+ */
+ new_stamp = (drawable->texture_stamp != drawable->dPriv->lastStamp);
+
+ if (new_stamp || new_mask || screen->broken_invalidate) {
+ if (new_stamp && screen->update_drawable_info)
+ screen->update_drawable_info(drawable);
+
+ screen->allocate_textures(drawable, statts, count);
+
+ /* add existing textures */
+ for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
+ if (drawable->textures[i])
+ statt_mask |= (1 << i);
+ }
+
+ drawable->texture_stamp = drawable->dPriv->lastStamp;
+ drawable->texture_mask = statt_mask;
+ }
+
+ if (!out)
+ return TRUE;
+
+ for (i = 0; i < count; i++) {
+ out[i] = NULL;
+ pipe_resource_reference(&out[i], drawable->textures[statts[i]]);
+ }
+
+ return TRUE;
+}
+
+static boolean
+dri_st_framebuffer_flush_front(struct st_framebuffer_iface *stfbi,
+ enum st_attachment_type statt)
+{
+ struct dri_drawable *drawable =
+ (struct dri_drawable *) stfbi->st_manager_private;
+ struct dri_screen *screen = dri_screen(drawable->sPriv);
+
+ /* XXX remove this and just set the correct one on the framebuffer */
+ screen->flush_frontbuffer(drawable, statt);
+
+ return TRUE;
+}
+
+/**
+ * This is called when we need to set up GL rendering to a new X window.
+ */
+boolean
+dri_create_buffer(__DRIscreen * sPriv,
+ __DRIdrawable * dPriv,
+ const __GLcontextModes * visual, boolean isPixmap)
+{
+ struct dri_screen *screen = sPriv->private;
+ struct dri_drawable *drawable = NULL;
+
+ if (isPixmap)
+ goto fail; /* not implemented */
+
+ drawable = CALLOC_STRUCT(dri_drawable);
+ if (drawable == NULL)
+ goto fail;
+
+ dri_fill_st_visual(&drawable->stvis, screen, visual);
+
+ /* setup the st_framebuffer_iface */
+ drawable->base.visual = &drawable->stvis;
+ drawable->base.flush_front = dri_st_framebuffer_flush_front;
+ drawable->base.validate = dri_st_framebuffer_validate;
+ drawable->base.st_manager_private = (void *) drawable;
+
+ drawable->sPriv = sPriv;
+ drawable->dPriv = dPriv;
+ dPriv->driverPrivate = (void *)drawable;
+
+ drawable->desired_fences = 2;
+
+ return GL_TRUE;
+fail:
+ FREE(drawable);
+ return GL_FALSE;
+}
+
+void
+dri_destroy_buffer(__DRIdrawable * dPriv)
+{
+ struct dri_drawable *drawable = dri_drawable(dPriv);
+ int i;
+
+ dri1_swap_fences_clear(drawable);
+
+ dri1_destroy_pipe_surface(drawable);
+
+ for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
+ pipe_resource_reference(&drawable->textures[i], NULL);
+
+ drawable->desired_fences = 0;
+
+ FREE(drawable);
+}
+
+/**
+ * Validate the texture at an attachment. Allocate the texture if it does not
+ * exist.
+ */
+void
+dri_drawable_validate_att(struct dri_drawable *drawable,
+ enum st_attachment_type statt)
+{
+ enum st_attachment_type statts[ST_ATTACHMENT_COUNT];
+ unsigned i, count = 0;
+
+ /* check if buffer already exists */
+ if (drawable->texture_mask & (1 << statt))
+ return;
+
+ /* make sure DRI2 does not destroy existing buffers */
+ for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
+ if (drawable->texture_mask & (1 << i)) {
+ statts[count++] = i;
+ }
+ }
+ statts[count++] = statt;
+
+ drawable->texture_stamp = drawable->dPriv->lastStamp - 1;
+
+ /* this calles into the manager */
+ drawable->base.validate(&drawable->base, statts, count, NULL);
+}
+
+/**
+ * Get the format and binding of an attachment.
+ */
+void
+dri_drawable_get_format(struct dri_drawable *drawable,
+ enum st_attachment_type statt,
+ enum pipe_format *format,
+ unsigned *bind)
+{
+ switch (statt) {
+ case ST_ATTACHMENT_FRONT_LEFT:
+ case ST_ATTACHMENT_BACK_LEFT:
+ case ST_ATTACHMENT_FRONT_RIGHT:
+ case ST_ATTACHMENT_BACK_RIGHT:
+ *format = drawable->stvis.color_format;
+ *bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
+ break;
+ case ST_ATTACHMENT_DEPTH_STENCIL:
+ *format = drawable->stvis.depth_stencil_format;
+ *bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */
+ break;
+ default:
+ *format = PIPE_FORMAT_NONE;
+ *bind = 0;
+ break;
+ }
+}
+
+/* vim: set sw=3 ts=8 sts=3 expandtab: */
diff --git a/src/gallium/state_trackers/dri/common/dri_drawable.h b/src/gallium/state_trackers/dri/common/dri_drawable.h
new file mode 100644
index 0000000000..5fd650ac88
--- /dev/null
+++ b/src/gallium/state_trackers/dri/common/dri_drawable.h
@@ -0,0 +1,98 @@
+/**************************************************************************
+ *
+ * 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 DRI_DRAWABLE_H
+#define DRI_DRAWABLE_H
+
+#include "pipe/p_compiler.h"
+#include "pipe/p_format.h"
+#include "state_tracker/st_api.h"
+
+struct pipe_surface;
+struct pipe_fence_handle;
+struct st_framebuffer;
+struct dri_context;
+
+#define DRI_SWAP_FENCES_MAX 8
+#define DRI_SWAP_FENCES_MASK 7
+
+struct dri_drawable
+{
+ struct st_framebuffer_iface base;
+ struct st_visual stvis;
+
+ /* dri */
+ __DRIdrawable *dPriv;
+ __DRIscreen *sPriv;
+
+ __DRIbuffer old[8];
+ unsigned old_num;
+ unsigned old_w;
+ unsigned old_h;
+
+ struct pipe_resource *textures[ST_ATTACHMENT_COUNT];
+ unsigned int texture_mask, texture_stamp;
+
+ struct pipe_fence_handle *swap_fences[DRI_SWAP_FENCES_MAX];
+ unsigned int head;
+ unsigned int tail;
+ unsigned int desired_fences;
+ unsigned int cur_fences;
+
+ /* used only by DRI1 */
+ struct pipe_surface *dri1_surface;
+};
+
+static INLINE struct dri_drawable *
+dri_drawable(__DRIdrawable * driDrawPriv)
+{
+ return (struct dri_drawable *)driDrawPriv->driverPrivate;
+}
+
+/***********************************************************************
+ * dri_drawable.c
+ */
+boolean
+dri_create_buffer(__DRIscreen * sPriv,
+ __DRIdrawable * dPriv,
+ const __GLcontextModes * visual, boolean isPixmap);
+
+void dri_destroy_buffer(__DRIdrawable * dPriv);
+
+void
+dri_drawable_get_format(struct dri_drawable *drawable,
+ enum st_attachment_type statt,
+ enum pipe_format *format,
+ unsigned *bind);
+
+void
+dri_drawable_validate_att(struct dri_drawable *drawable,
+ enum st_attachment_type statt);
+
+#endif
+
+/* vim: set sw=3 ts=8 sts=3 expandtab: */
diff --git a/src/gallium/state_trackers/dri/common/dri_screen.c b/src/gallium/state_trackers/dri/common/dri_screen.c
new file mode 100644
index 0000000000..25cad8d46c
--- /dev/null
+++ b/src/gallium/state_trackers/dri/common/dri_screen.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.
+ *
+ **************************************************************************/
+/*
+ * Author: Keith Whitwell <keithw@vmware.com>
+ * Author: Jakob Bornecrantz <wallbraker@gmail.com>
+ */
+
+#include "utils.h"
+#ifndef __NOT_HAVE_DRM_H
+#include "vblank.h"
+#endif
+#include "xmlpool.h"
+
+#include "dri_screen.h"
+#include "dri_context.h"
+#include "dri_drawable.h"
+#include "dri1_helper.h"
+#ifndef __NOT_HAVE_DRM_H
+#include "dri2.h"
+#else
+#include "drisw.h"
+#endif
+
+#include "util/u_inlines.h"
+#include "pipe/p_screen.h"
+#include "pipe/p_format.h"
+#include "state_tracker/st_gl_api.h" /* for st_gl_api_create */
+
+#include "util/u_debug.h"
+
+PUBLIC const char __driConfigOptions[] =
+ DRI_CONF_BEGIN DRI_CONF_SECTION_PERFORMANCE
+ DRI_CONF_FTHROTTLE_MODE(DRI_CONF_FTHROTTLE_IRQS)
+ DRI_CONF_VBLANK_MODE(DRI_CONF_VBLANK_DEF_INTERVAL_0)
+ DRI_CONF_SECTION_END DRI_CONF_SECTION_QUALITY
+/* DRI_CONF_FORCE_S3TC_ENABLE(false) */
+ DRI_CONF_ALLOW_LARGE_TEXTURES(1)
+ DRI_CONF_SECTION_END DRI_CONF_END;
+
+static const uint __driNConfigOptions = 3;
+
+static const __DRIconfig **
+dri_fill_in_modes(struct dri_screen *screen,
+ unsigned pixel_bits)
+{
+ __DRIconfig **configs = NULL;
+ __DRIconfig **configs_r5g6b5 = NULL;
+ __DRIconfig **configs_a8r8g8b8 = NULL;
+ __DRIconfig **configs_x8r8g8b8 = NULL;
+ uint8_t depth_bits_array[5];
+ uint8_t stencil_bits_array[5];
+ uint8_t msaa_samples_array[5];
+ unsigned depth_buffer_factor;
+ unsigned back_buffer_factor;
+ unsigned msaa_samples_factor;
+ unsigned i;
+ struct pipe_screen *p_screen = screen->base.screen;
+ boolean pf_r5g6b5, pf_a8r8g8b8, pf_x8r8g8b8;
+ boolean pf_z16, pf_x8z24, pf_z24x8, pf_s8z24, pf_z24s8, pf_z32;
+
+ static const GLenum back_buffer_modes[] = {
+ GLX_NONE, GLX_SWAP_UNDEFINED_OML, GLX_SWAP_COPY_OML
+ };
+
+ depth_bits_array[0] = 0;
+ stencil_bits_array[0] = 0;
+ depth_buffer_factor = 1;
+
+ pf_x8z24 = p_screen->is_format_supported(p_screen, PIPE_FORMAT_Z24X8_UNORM,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_DEPTH_STENCIL, 0);
+ pf_z24x8 = p_screen->is_format_supported(p_screen, PIPE_FORMAT_X8Z24_UNORM,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_DEPTH_STENCIL, 0);
+ pf_s8z24 = p_screen->is_format_supported(p_screen, PIPE_FORMAT_Z24_UNORM_S8_USCALED,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_DEPTH_STENCIL, 0);
+ pf_z24s8 = p_screen->is_format_supported(p_screen, PIPE_FORMAT_S8_USCALED_Z24_UNORM,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_DEPTH_STENCIL, 0);
+ pf_a8r8g8b8 = p_screen->is_format_supported(p_screen, PIPE_FORMAT_B8G8R8A8_UNORM,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_RENDER_TARGET, 0);
+ pf_x8r8g8b8 = p_screen->is_format_supported(p_screen, PIPE_FORMAT_B8G8R8X8_UNORM,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_RENDER_TARGET, 0);
+ pf_r5g6b5 = p_screen->is_format_supported(p_screen, PIPE_FORMAT_B5G6R5_UNORM,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_RENDER_TARGET, 0);
+
+ /* We can only get a 16 or 32 bit depth buffer with getBuffersWithFormat */
+ if (dri_with_format(screen->sPriv)) {
+ pf_z16 = p_screen->is_format_supported(p_screen, PIPE_FORMAT_Z16_UNORM,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_DEPTH_STENCIL, 0);
+ pf_z32 = p_screen->is_format_supported(p_screen, PIPE_FORMAT_Z32_UNORM,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_DEPTH_STENCIL, 0);
+ } else {
+ pf_z16 = FALSE;
+ pf_z32 = FALSE;
+ }
+
+ if (pf_z16) {
+ depth_bits_array[depth_buffer_factor] = 16;
+ stencil_bits_array[depth_buffer_factor++] = 0;
+ }
+ if (pf_x8z24 || pf_z24x8) {
+ depth_bits_array[depth_buffer_factor] = 24;
+ stencil_bits_array[depth_buffer_factor++] = 0;
+ screen->d_depth_bits_last = pf_x8z24;
+ }
+ if (pf_s8z24 || pf_z24s8) {
+ depth_bits_array[depth_buffer_factor] = 24;
+ stencil_bits_array[depth_buffer_factor++] = 8;
+ screen->sd_depth_bits_last = pf_s8z24;
+ }
+ if (pf_z32) {
+ depth_bits_array[depth_buffer_factor] = 32;
+ stencil_bits_array[depth_buffer_factor++] = 0;
+ }
+
+ msaa_samples_array[0] = 0;
+ back_buffer_factor = 3;
+
+ /* also test color for msaa 2/4/6/8 - just assume it'll work for all depth buffers */
+ if (pf_r5g6b5) {
+ msaa_samples_factor = 1;
+ for (i = 1; i < 5; i++) {
+ if (p_screen->is_format_supported(p_screen, PIPE_FORMAT_B5G6R5_UNORM,
+ PIPE_TEXTURE_2D, i*2,
+ PIPE_BIND_RENDER_TARGET, 0)) {
+ msaa_samples_array[msaa_samples_factor] = i * 2;
+ msaa_samples_factor++;
+ }
+ }
+
+ configs_r5g6b5 = driCreateConfigs(GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
+ depth_bits_array, stencil_bits_array,
+ depth_buffer_factor, back_buffer_modes,
+ back_buffer_factor,
+ msaa_samples_array, msaa_samples_factor,
+ GL_TRUE);
+ }
+
+ if (pf_a8r8g8b8) {
+ msaa_samples_factor = 1;
+ for (i = 1; i < 5; i++) {
+ if (p_screen->is_format_supported(p_screen, PIPE_FORMAT_B8G8R8A8_UNORM,
+ PIPE_TEXTURE_2D, i*2,
+ PIPE_BIND_RENDER_TARGET, 0)) {
+ msaa_samples_array[msaa_samples_factor] = i * 2;
+ msaa_samples_factor++;
+ }
+ }
+
+ configs_a8r8g8b8 = driCreateConfigs(GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
+ depth_bits_array,
+ stencil_bits_array,
+ depth_buffer_factor,
+ back_buffer_modes,
+ back_buffer_factor,
+ msaa_samples_array,
+ msaa_samples_factor,
+ GL_TRUE);
+ }
+
+ if (pf_x8r8g8b8) {
+ msaa_samples_factor = 1;
+ for (i = 1; i < 5; i++) {
+ if (p_screen->is_format_supported(p_screen, PIPE_FORMAT_B8G8R8X8_UNORM,
+ PIPE_TEXTURE_2D, i*2,
+ PIPE_BIND_RENDER_TARGET, 0)) {
+ msaa_samples_array[msaa_samples_factor] = i * 2;
+ msaa_samples_factor++;
+ }
+ }
+
+ configs_x8r8g8b8 = driCreateConfigs(GL_BGR, GL_UNSIGNED_INT_8_8_8_8_REV,
+ depth_bits_array,
+ stencil_bits_array,
+ depth_buffer_factor,
+ back_buffer_modes,
+ back_buffer_factor,
+ msaa_samples_array,
+ msaa_samples_factor,
+ GL_TRUE);
+ }
+
+ if (pixel_bits == 16) {
+ configs = configs_r5g6b5;
+ if (configs_a8r8g8b8)
+ configs = configs ? driConcatConfigs(configs, configs_a8r8g8b8) : configs_a8r8g8b8;
+ if (configs_x8r8g8b8)
+ configs = configs ? driConcatConfigs(configs, configs_x8r8g8b8) : configs_x8r8g8b8;
+ } else {
+ configs = configs_a8r8g8b8;
+ if (configs_x8r8g8b8)
+ configs = configs ? driConcatConfigs(configs, configs_x8r8g8b8) : configs_x8r8g8b8;
+ if (configs_r5g6b5)
+ configs = configs ? driConcatConfigs(configs, configs_r5g6b5) : configs_r5g6b5;
+ }
+
+ if (configs == NULL) {
+ debug_printf("%s: driCreateConfigs failed\n", __FUNCTION__);
+ return NULL;
+ }
+
+ return (const __DRIconfig **)configs;
+}
+
+/**
+ * Roughly the converse of dri_fill_in_modes.
+ */
+void
+dri_fill_st_visual(struct st_visual *stvis, struct dri_screen *screen,
+ const __GLcontextModes *mode)
+{
+ memset(stvis, 0, sizeof(*stvis));
+
+ stvis->samples = mode->samples;
+ stvis->render_buffer = ST_ATTACHMENT_INVALID;
+
+ if (mode->redBits == 8) {
+ if (mode->alphaBits == 8)
+ stvis->color_format = PIPE_FORMAT_B8G8R8A8_UNORM;
+ else
+ stvis->color_format = PIPE_FORMAT_B8G8R8X8_UNORM;
+ } else {
+ stvis->color_format = PIPE_FORMAT_B5G6R5_UNORM;
+ }
+
+ switch (mode->depthBits) {
+ default:
+ case 0:
+ stvis->depth_stencil_format = PIPE_FORMAT_NONE;
+ break;
+ case 16:
+ stvis->depth_stencil_format = PIPE_FORMAT_Z16_UNORM;
+ break;
+ case 24:
+ if (mode->stencilBits == 0) {
+ stvis->depth_stencil_format = (screen->d_depth_bits_last) ?
+ PIPE_FORMAT_Z24X8_UNORM:
+ PIPE_FORMAT_X8Z24_UNORM;
+ } else {
+ stvis->depth_stencil_format = (screen->sd_depth_bits_last) ?
+ PIPE_FORMAT_Z24_UNORM_S8_USCALED:
+ PIPE_FORMAT_S8_USCALED_Z24_UNORM;
+ }
+ break;
+ case 32:
+ stvis->depth_stencil_format = PIPE_FORMAT_Z32_UNORM;
+ break;
+ }
+
+ stvis->accum_format = (mode->haveAccumBuffer) ?
+ PIPE_FORMAT_R16G16B16A16_SNORM : PIPE_FORMAT_NONE;
+
+ stvis->buffer_mask |= ST_ATTACHMENT_FRONT_LEFT_MASK;
+ if (mode->doubleBufferMode)
+ stvis->buffer_mask |= ST_ATTACHMENT_BACK_LEFT_MASK;
+ if (mode->stereoMode) {
+ stvis->buffer_mask |= ST_ATTACHMENT_FRONT_RIGHT_MASK;
+ if (mode->doubleBufferMode)
+ stvis->buffer_mask |= ST_ATTACHMENT_BACK_RIGHT_MASK;
+ }
+
+ if (mode->haveDepthBuffer || mode->haveStencilBuffer)
+ stvis->buffer_mask |= ST_ATTACHMENT_DEPTH_STENCIL_MASK;
+ /* let the state tracker allocate the accum buffer */
+}
+
+static boolean
+dri_get_egl_image(struct st_manager *smapi,
+ struct st_context_iface *stctxi,
+ void *egl_image,
+ struct st_egl_image *stimg)
+{
+ struct dri_context *ctx =
+ (struct dri_context *)stctxi->st_manager_private;
+ struct dri_screen *screen = dri_screen(ctx->sPriv);
+ __DRIimage *img = NULL;
+
+ if (screen->lookup_egl_image) {
+ img = screen->lookup_egl_image(ctx, egl_image);
+ }
+
+ if (!img)
+ return FALSE;
+
+ stimg->texture = NULL;
+ pipe_resource_reference(&stimg->texture, img->texture);
+ stimg->face = img->face;
+ stimg->level = img->level;
+ stimg->zslice = img->zslice;
+
+ return TRUE;
+}
+
+static int
+dri_get_param(struct st_manager *smapi,
+ enum st_manager_param param)
+{
+ struct dri_screen *screen = (struct dri_screen *)smapi;
+
+ switch(param) {
+ case ST_MANAGER_BROKEN_INVALIDATE:
+ return screen->broken_invalidate;
+ default:
+ return 0;
+ }
+}
+
+static void
+dri_destroy_option_cache(struct dri_screen * screen)
+{
+ int i;
+
+ if (screen->optionCache.info) {
+ for (i = 0; i < (1 << screen->optionCache.tableSize); ++i) {
+ FREE(screen->optionCache.info[i].name);
+ FREE(screen->optionCache.info[i].ranges);
+ }
+ FREE(screen->optionCache.info);
+ }
+
+ FREE(screen->optionCache.values);
+}
+
+void
+dri_destroy_screen_helper(struct dri_screen * screen)
+{
+ dri1_destroy_pipe_context(screen);
+
+ if (screen->st_api && screen->st_api->destroy)
+ screen->st_api->destroy(screen->st_api);
+
+ if (screen->base.screen)
+ screen->base.screen->destroy(screen->base.screen);
+
+ dri_destroy_option_cache(screen);
+}
+
+static void
+dri_destroy_screen(__DRIscreen * sPriv)
+{
+ struct dri_screen *screen = dri_screen(sPriv);
+
+ dri_destroy_screen_helper(screen);
+
+ FREE(screen);
+ sPriv->private = NULL;
+ sPriv->extensions = NULL;
+}
+
+const __DRIconfig **
+dri_init_screen_helper(struct dri_screen *screen,
+ struct pipe_screen *pscreen,
+ unsigned pixel_bits)
+{
+ screen->base.screen = pscreen;
+ if (!screen->base.screen) {
+ debug_printf("%s: failed to create pipe_screen\n", __FUNCTION__);
+ return NULL;
+ }
+
+ screen->base.get_egl_image = dri_get_egl_image;
+ screen->base.get_param = dri_get_param;
+ screen->st_api = st_gl_api_create();
+
+ if (!screen->st_api)
+ return NULL;
+
+ driParseOptionInfo(&screen->optionCache,
+ __driConfigOptions, __driNConfigOptions);
+
+ return dri_fill_in_modes(screen, pixel_bits);
+}
+
+/**
+ * DRI driver virtual function table.
+ *
+ * DRI versions differ in their implementation of init_screen and swap_buffers.
+ */
+const struct __DriverAPIRec driDriverAPI = {
+ .DestroyScreen = dri_destroy_screen,
+ .CreateContext = dri_create_context,
+ .DestroyContext = dri_destroy_context,
+ .CreateBuffer = dri_create_buffer,
+ .DestroyBuffer = dri_destroy_buffer,
+ .MakeCurrent = dri_make_current,
+ .UnbindContext = dri_unbind_context,
+
+#ifndef __NOT_HAVE_DRM_H
+
+ .GetSwapInfo = NULL,
+ .GetDrawableMSC = NULL,
+ .WaitForMSC = NULL,
+ .InitScreen2 = dri2_init_screen,
+
+ .InitScreen = NULL,
+ .SwapBuffers = NULL,
+ .CopySubBuffer = NULL,
+
+#else
+
+ .InitScreen = drisw_init_screen,
+ .SwapBuffers = drisw_swap_buffers,
+
+#endif
+
+};
+
+/* vim: set sw=3 ts=8 sts=3 expandtab: */
diff --git a/src/gallium/state_trackers/dri/common/dri_screen.h b/src/gallium/state_trackers/dri/common/dri_screen.h
new file mode 100644
index 0000000000..9ff925d4be
--- /dev/null
+++ b/src/gallium/state_trackers/dri/common/dri_screen.h
@@ -0,0 +1,139 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+/*
+ * Author: Keith Whitwell <keithw@vmware.com>
+ * Author: Jakob Bornecrantz <wallbraker@gmail.com>
+ */
+
+#ifndef DRI_SCREEN_H
+#define DRI_SCREEN_H
+
+#include "dri_wrapper.h"
+#include "xmlconfig.h"
+
+#include "pipe/p_compiler.h"
+#include "pipe/p_context.h"
+#include "pipe/p_state.h"
+#include "state_tracker/st_api.h"
+#include "state_tracker/drm_api.h"
+
+struct dri_context;
+struct dri_drawable;
+
+struct dri_screen
+{
+ /* st_api */
+ struct st_manager base;
+ struct st_api *st_api;
+
+ /* on old libGL's invalidate doesn't get called as it should */
+ boolean broken_invalidate;
+
+ /* dri */
+ __DRIscreen *sPriv;
+
+ /**
+ * Configuration cache with default values for all contexts
+ */
+ driOptionCache optionCache;
+
+ /* drm */
+ int fd;
+ drmLock *drmLock;
+
+ /* hooks filled in by dri1, dri2 & drisw */
+ __DRIimage * (*lookup_egl_image)(struct dri_context *ctx, void *handle);
+ void (*allocate_textures)(struct dri_drawable *drawable,
+ const enum st_attachment_type *statts,
+ unsigned count);
+ void (*update_drawable_info)(struct dri_drawable *drawable);
+ void (*flush_frontbuffer)(struct dri_drawable *drawable,
+ enum st_attachment_type statt);
+
+ /* gallium */
+ struct drm_api *api;
+ boolean d_depth_bits_last;
+ boolean sd_depth_bits_last;
+ boolean auto_fake_front;
+
+ /* used only by DRI1 */
+ struct pipe_context *dri1_pipe;
+};
+
+/** cast wrapper */
+static INLINE struct dri_screen *
+dri_screen(__DRIscreen * sPriv)
+{
+ return (struct dri_screen *)sPriv->private;
+}
+
+struct __DRIimageRec {
+ struct pipe_resource *texture;
+ unsigned face;
+ unsigned level;
+ unsigned zslice;
+
+ void *loader_private;
+};
+
+#ifndef __NOT_HAVE_DRM_H
+
+static INLINE boolean
+dri_with_format(__DRIscreen * sPriv)
+{
+ const __DRIdri2LoaderExtension *loader = sPriv->dri2.loader;
+
+ return loader
+ && (loader->base.version >= 3)
+ && (loader->getBuffersWithFormat != NULL);
+}
+
+#else
+
+static INLINE boolean
+dri_with_format(__DRIscreen * sPriv)
+{
+ return TRUE;
+}
+
+#endif
+
+void
+dri_fill_st_visual(struct st_visual *stvis, struct dri_screen *screen,
+ const __GLcontextModes *mode);
+
+const __DRIconfig **
+dri_init_screen_helper(struct dri_screen *screen,
+ struct pipe_screen *pscreen,
+ unsigned pixel_bits);
+
+void
+dri_destroy_screen_helper(struct dri_screen * screen);
+
+#endif
+
+/* vim: set sw=3 ts=8 sts=3 expandtab: */
diff --git a/src/gallium/state_trackers/dri/common/dri_wrapper.h b/src/gallium/state_trackers/dri/common/dri_wrapper.h
new file mode 100644
index 0000000000..141ba02706
--- /dev/null
+++ b/src/gallium/state_trackers/dri/common/dri_wrapper.h
@@ -0,0 +1,10 @@
+#ifndef DRI_WRAPPER_H
+#define DRI_WRAPPER_H
+
+#ifndef __NOT_HAVE_DRM_H
+#include "dri_util.h"
+#else
+#include "drisw_util.h"
+#endif
+
+#endif
diff --git a/src/gallium/state_trackers/dri/drm/Makefile b/src/gallium/state_trackers/dri/drm/Makefile
new file mode 100644
index 0000000000..94fa61fec7
--- /dev/null
+++ b/src/gallium/state_trackers/dri/drm/Makefile
@@ -0,0 +1,31 @@
+TOP = ../../../../..
+include $(TOP)/configs/current
+
+LIBNAME = dridrm
+
+LIBRARY_INCLUDES = \
+ -I$(TOP)/include \
+ -I$(TOP)/src/mapi \
+ -I$(TOP)/src/mesa \
+ -I$(TOP)/src/gallium/state_trackers/dri/common \
+ -I$(TOP)/src/mesa/drivers/dri/common \
+ -I$(TOP)/src/mesa/main \
+ $(shell pkg-config --cflags-only-I libdrm)
+
+
+C_SOURCES = \
+ dri_context.c \
+ dri_screen.c \
+ dri_drawable.c \
+ dri1_helper.c \
+ dri2.c
+
+# $(TOP)/src/mesa/drivers/dri/common/utils.c \
+ $(TOP)/src/mesa/drivers/dri/common/vblank.c \
+ $(TOP)/src/mesa/drivers/dri/common/dri_util.c \
+ $(TOP)/src/mesa/drivers/dri/common/xmlconfig.c \
+ $(TOP)/src/mesa/drivers/common/driverfuncs.c \
+ $(TOP)/src/mesa/drivers/dri/common/texmem.c \
+ $(TOP)/src/mesa/drivers/dri/common/drirenderbuffer.c
+
+include ../../../Makefile.template
diff --git a/src/gallium/state_trackers/dri/drm/SConscript b/src/gallium/state_trackers/dri/drm/SConscript
new file mode 100644
index 0000000000..0c279d2236
--- /dev/null
+++ b/src/gallium/state_trackers/dri/drm/SConscript
@@ -0,0 +1,28 @@
+#######################################################################
+# SConscript for dri state_tracker
+
+Import('*')
+
+if env['dri']:
+
+ env = env.Clone()
+
+ env.ParseConfig('pkg-config --cflags --libs libdrm')
+
+ env.Append(CPPPATH = [
+ '#/src/mapi',
+ '#/src/mesa',
+ '#/src/gallium/state_trackers/dri/common',
+ '#/src/mesa/drivers/dri/common',
+ ])
+
+ st_dri = env.ConvenienceLibrary(
+ target = 'st_dri',
+ source = [ 'dri_context.c',
+ 'dri_drawable.c',
+ 'dri_screen.c',
+ 'dri1_helper.c',
+ 'dri2.c',
+ ]
+ )
+ Export('st_dri')
diff --git a/src/gallium/state_trackers/dri/drm/dri1_helper.c b/src/gallium/state_trackers/dri/drm/dri1_helper.c
new file mode 120000
index 0000000000..c45ebf5c10
--- /dev/null
+++ b/src/gallium/state_trackers/dri/drm/dri1_helper.c
@@ -0,0 +1 @@
+../common/dri1_helper.c \ No newline at end of file
diff --git a/src/gallium/state_trackers/dri/drm/dri2.c b/src/gallium/state_trackers/dri/drm/dri2.c
new file mode 100644
index 0000000000..f4cc8d77eb
--- /dev/null
+++ b/src/gallium/state_trackers/dri/drm/dri2.c
@@ -0,0 +1,546 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.9
+ *
+ * Copyright 2009, VMware, Inc.
+ * All Rights Reserved.
+ * Copyright (C) 2010 LunarG Inc.
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL 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.
+ *
+ * Authors:
+ * Keith Whitwell <keithw@vmware.com>
+ * Jakob Bornecrantz <wallbraker@gmail.com>
+ * Chia-I Wu <olv@lunarg.com>
+ */
+
+#include "util/u_memory.h"
+#include "util/u_inlines.h"
+#include "util/u_format.h"
+#include "util/u_debug.h"
+#include "state_tracker/drm_api.h"
+
+#include "dri_screen.h"
+#include "dri_context.h"
+#include "dri_drawable.h"
+#include "dri2.h"
+
+#include "GL/internal/dri_interface.h"
+
+/**
+ * DRI2 flush extension.
+ */
+static void
+dri2_flush_drawable(__DRIdrawable *draw)
+{
+}
+
+static void
+dri2_invalidate_drawable(__DRIdrawable *dPriv)
+{
+ struct dri_drawable *drawable = dri_drawable(dPriv);
+ struct dri_context *ctx = dri_context(dPriv->driContextPriv);
+
+ dri2InvalidateDrawable(dPriv);
+ drawable->dPriv->lastStamp = *drawable->dPriv->pStamp;
+
+ if (ctx)
+ ctx->st->notify_invalid_framebuffer(ctx->st, &drawable->base);
+}
+
+static const __DRI2flushExtension dri2FlushExtension = {
+ { __DRI2_FLUSH, __DRI2_FLUSH_VERSION },
+ dri2_flush_drawable,
+ dri2_invalidate_drawable,
+};
+
+/**
+ * These are used for GLX_EXT_texture_from_pixmap
+ */
+static void
+dri2_set_tex_buffer2(__DRIcontext *pDRICtx, GLint target,
+ GLint format, __DRIdrawable *dPriv)
+{
+ struct dri_context *ctx = dri_context(pDRICtx);
+ struct dri_drawable *drawable = dri_drawable(dPriv);
+ struct pipe_resource *pt;
+
+ dri_drawable_validate_att(drawable, ST_ATTACHMENT_FRONT_LEFT);
+
+ pt = drawable->textures[ST_ATTACHMENT_FRONT_LEFT];
+
+ if (pt) {
+ enum pipe_format internal_format = pt->format;
+
+ if (format == __DRI_TEXTURE_FORMAT_RGB) {
+ /* only need to cover the formats recognized by dri_fill_st_visual */
+ switch (internal_format) {
+ case PIPE_FORMAT_B8G8R8A8_UNORM:
+ internal_format = PIPE_FORMAT_B8G8R8X8_UNORM;
+ break;
+ case PIPE_FORMAT_A8R8G8B8_UNORM:
+ internal_format = PIPE_FORMAT_X8R8G8B8_UNORM;
+ break;
+ default:
+ break;
+ }
+ }
+
+ ctx->st->teximage(ctx->st,
+ (target == GL_TEXTURE_2D) ? ST_TEXTURE_2D : ST_TEXTURE_RECT,
+ 0, internal_format, pt, FALSE);
+ }
+}
+
+static void
+dri2_set_tex_buffer(__DRIcontext *pDRICtx, GLint target,
+ __DRIdrawable *dPriv)
+{
+ dri2_set_tex_buffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv);
+}
+
+static const __DRItexBufferExtension dri2TexBufferExtension = {
+ { __DRI_TEX_BUFFER, __DRI_TEX_BUFFER_VERSION },
+ dri2_set_tex_buffer,
+ dri2_set_tex_buffer2,
+};
+
+/**
+ * Get the format and binding of an attachment.
+ */
+static INLINE void
+dri2_drawable_get_format(struct dri_drawable *drawable,
+ enum st_attachment_type statt,
+ enum pipe_format *format,
+ unsigned *bind)
+{
+ switch (statt) {
+ case ST_ATTACHMENT_FRONT_LEFT:
+ case ST_ATTACHMENT_BACK_LEFT:
+ case ST_ATTACHMENT_FRONT_RIGHT:
+ case ST_ATTACHMENT_BACK_RIGHT:
+ *format = drawable->stvis.color_format;
+ *bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
+ break;
+ case ST_ATTACHMENT_DEPTH_STENCIL:
+ *format = drawable->stvis.depth_stencil_format;
+ *bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */
+ break;
+ default:
+ *format = PIPE_FORMAT_NONE;
+ *bind = 0;
+ break;
+ }
+}
+
+
+/**
+ * Retrieve __DRIbuffer from the DRI loader.
+ */
+static __DRIbuffer *
+dri2_drawable_get_buffers(struct dri_drawable *drawable,
+ const enum st_attachment_type *statts,
+ unsigned *count)
+{
+ __DRIdrawable *dri_drawable = drawable->dPriv;
+ struct __DRIdri2LoaderExtensionRec *loader = drawable->sPriv->dri2.loader;
+ boolean with_format;
+ __DRIbuffer *buffers;
+ int num_buffers;
+ unsigned attachments[10];
+ unsigned num_attachments, i;
+
+ assert(loader);
+ with_format = dri_with_format(drawable->sPriv);
+
+ num_attachments = 0;
+
+ /* for Xserver 1.6.0 (DRI2 version 1) we always need to ask for the front */
+ if (!with_format)
+ attachments[num_attachments++] = __DRI_BUFFER_FRONT_LEFT;
+
+ for (i = 0; i < *count; i++) {
+ enum pipe_format format;
+ unsigned bind;
+ int att, bpp;
+
+ dri2_drawable_get_format(drawable, statts[i], &format, &bind);
+ if (format == PIPE_FORMAT_NONE)
+ continue;
+
+ switch (statts[i]) {
+ case ST_ATTACHMENT_FRONT_LEFT:
+ /* already added */
+ if (!with_format)
+ continue;
+ att = __DRI_BUFFER_FRONT_LEFT;
+ break;
+ case ST_ATTACHMENT_BACK_LEFT:
+ att = __DRI_BUFFER_BACK_LEFT;
+ break;
+ case ST_ATTACHMENT_FRONT_RIGHT:
+ att = __DRI_BUFFER_FRONT_RIGHT;
+ break;
+ case ST_ATTACHMENT_BACK_RIGHT:
+ att = __DRI_BUFFER_BACK_RIGHT;
+ break;
+ case ST_ATTACHMENT_DEPTH_STENCIL:
+ att = __DRI_BUFFER_DEPTH_STENCIL;
+ break;
+ default:
+ att = -1;
+ break;
+ }
+
+ bpp = util_format_get_blocksizebits(format);
+
+ if (att >= 0) {
+ attachments[num_attachments++] = att;
+ if (with_format) {
+ attachments[num_attachments++] = bpp;
+ }
+ }
+ }
+
+ if (with_format) {
+ num_attachments /= 2;
+ buffers = loader->getBuffersWithFormat(dri_drawable,
+ &dri_drawable->w, &dri_drawable->h,
+ attachments, num_attachments,
+ &num_buffers, dri_drawable->loaderPrivate);
+ }
+ else {
+ buffers = loader->getBuffers(dri_drawable,
+ &dri_drawable->w, &dri_drawable->h,
+ attachments, num_attachments,
+ &num_buffers, dri_drawable->loaderPrivate);
+ }
+
+ if (buffers) {
+ /* set one cliprect to cover the whole dri_drawable */
+ dri_drawable->x = 0;
+ dri_drawable->y = 0;
+ dri_drawable->backX = 0;
+ dri_drawable->backY = 0;
+ dri_drawable->numClipRects = 1;
+ dri_drawable->pClipRects[0].x1 = 0;
+ dri_drawable->pClipRects[0].y1 = 0;
+ dri_drawable->pClipRects[0].x2 = dri_drawable->w;
+ dri_drawable->pClipRects[0].y2 = dri_drawable->h;
+ dri_drawable->numBackClipRects = 1;
+ dri_drawable->pBackClipRects[0].x1 = 0;
+ dri_drawable->pBackClipRects[0].y1 = 0;
+ dri_drawable->pBackClipRects[0].x2 = dri_drawable->w;
+ dri_drawable->pBackClipRects[0].y2 = dri_drawable->h;
+
+ *count = num_buffers;
+ }
+
+ return buffers;
+}
+
+/**
+ * Process __DRIbuffer and convert them into pipe_resources.
+ */
+static void
+dri2_drawable_process_buffers(struct dri_drawable *drawable,
+ __DRIbuffer *buffers, unsigned count)
+{
+ struct dri_screen *screen = dri_screen(drawable->sPriv);
+ __DRIdrawable *dri_drawable = drawable->dPriv;
+ struct pipe_resource templ;
+ struct winsys_handle whandle;
+ boolean have_depth = FALSE;
+ unsigned i, bind;
+
+ if (drawable->old_num == count &&
+ drawable->old_w == dri_drawable->w &&
+ drawable->old_h == dri_drawable->h &&
+ memcmp(drawable->old, buffers, sizeof(__DRIbuffer) * count) == 0)
+ return;
+
+ for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
+ pipe_resource_reference(&drawable->textures[i], NULL);
+
+ memset(&templ, 0, sizeof(templ));
+ templ.target = PIPE_TEXTURE_2D;
+ templ.last_level = 0;
+ templ.width0 = dri_drawable->w;
+ templ.height0 = dri_drawable->h;
+ templ.depth0 = 1;
+
+ memset(&whandle, 0, sizeof(whandle));
+
+ for (i = 0; i < count; i++) {
+ __DRIbuffer *buf = &buffers[i];
+ enum st_attachment_type statt;
+ enum pipe_format format;
+
+ switch (buf->attachment) {
+ case __DRI_BUFFER_FRONT_LEFT:
+ if (!screen->auto_fake_front) {
+ statt = ST_ATTACHMENT_INVALID;
+ break;
+ }
+ /* fallthrough */
+ case __DRI_BUFFER_FAKE_FRONT_LEFT:
+ statt = ST_ATTACHMENT_FRONT_LEFT;
+ break;
+ case __DRI_BUFFER_BACK_LEFT:
+ statt = ST_ATTACHMENT_BACK_LEFT;
+ break;
+ case __DRI_BUFFER_DEPTH:
+ case __DRI_BUFFER_DEPTH_STENCIL:
+ case __DRI_BUFFER_STENCIL:
+ /* use only the first depth/stencil buffer */
+ if (!have_depth) {
+ have_depth = TRUE;
+ statt = ST_ATTACHMENT_DEPTH_STENCIL;
+ }
+ else {
+ statt = ST_ATTACHMENT_INVALID;
+ }
+ break;
+ default:
+ statt = ST_ATTACHMENT_INVALID;
+ break;
+ }
+
+ dri2_drawable_get_format(drawable, statt, &format, &bind);
+ if (statt == ST_ATTACHMENT_INVALID || format == PIPE_FORMAT_NONE)
+ continue;
+
+ templ.format = format;
+ templ.bind = bind;
+ whandle.handle = buf->name;
+ whandle.stride = buf->pitch;
+
+ drawable->textures[statt] =
+ screen->base.screen->resource_from_handle(screen->base.screen,
+ &templ, &whandle);
+ }
+
+ drawable->old_num = count;
+ drawable->old_w = dri_drawable->w;
+ drawable->old_h = dri_drawable->h;
+ memcpy(drawable->old, buffers, sizeof(__DRIbuffer) * count);
+}
+
+/*
+ * Backend functions for st_framebuffer interface.
+ */
+
+static void
+dri2_allocate_textures(struct dri_drawable *drawable,
+ const enum st_attachment_type *statts,
+ unsigned count)
+{
+ __DRIbuffer *buffers;
+ unsigned num_buffers = count;
+
+ buffers = dri2_drawable_get_buffers(drawable, statts, &num_buffers);
+ dri2_drawable_process_buffers(drawable, buffers, num_buffers);
+}
+
+static void
+dri2_flush_frontbuffer(struct dri_drawable *drawable,
+ enum st_attachment_type statt)
+{
+ __DRIdrawable *dri_drawable = drawable->dPriv;
+ struct __DRIdri2LoaderExtensionRec *loader = drawable->sPriv->dri2.loader;
+
+ if (loader->flushFrontBuffer == NULL)
+ return;
+
+ if (statt == ST_ATTACHMENT_FRONT_LEFT) {
+ loader->flushFrontBuffer(dri_drawable, dri_drawable->loaderPrivate);
+ }
+}
+
+static __DRIimage *
+dri2_lookup_egl_image(struct dri_context *ctx, void *handle)
+{
+ __DRIimageLookupExtension *loader = ctx->sPriv->dri2.image;
+ __DRIimage *img;
+
+ if (!loader->lookupEGLImage)
+ return NULL;
+
+ img = loader->lookupEGLImage(ctx->cPriv, handle, ctx->cPriv->loaderPrivate);
+
+ return img;
+}
+
+static __DRIimage *
+dri2_create_image_from_name(__DRIcontext *context,
+ int width, int height, int format,
+ int name, int pitch, void *loaderPrivate)
+{
+ struct dri_screen *screen = dri_screen(context->driScreenPriv);
+ __DRIimage *img;
+ struct pipe_resource templ;
+ struct winsys_handle whandle;
+ unsigned tex_usage;
+ enum pipe_format pf;
+
+ tex_usage = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
+
+ switch (format) {
+ case __DRI_IMAGE_FORMAT_RGB565:
+ pf = PIPE_FORMAT_B5G6R5_UNORM;
+ break;
+ case __DRI_IMAGE_FORMAT_XRGB8888:
+ pf = PIPE_FORMAT_B8G8R8X8_UNORM;
+ break;
+ case __DRI_IMAGE_FORMAT_ARGB8888:
+ pf = PIPE_FORMAT_B8G8R8A8_UNORM;
+ break;
+ default:
+ pf = PIPE_FORMAT_NONE;
+ break;
+ }
+ if (pf == PIPE_FORMAT_NONE)
+ return NULL;
+
+ img = CALLOC_STRUCT(__DRIimageRec);
+ if (!img)
+ return NULL;
+
+ memset(&templ, 0, sizeof(templ));
+ templ.bind = tex_usage;
+ templ.format = pf;
+ templ.target = PIPE_TEXTURE_2D;
+ templ.last_level = 0;
+ templ.width0 = width;
+ templ.height0 = height;
+ templ.depth0 = 1;
+
+ memset(&whandle, 0, sizeof(whandle));
+ whandle.handle = name;
+ whandle.stride = pitch * util_format_get_blocksize(pf);
+
+ img->texture = screen->base.screen->resource_from_handle(screen->base.screen,
+ &templ, &whandle);
+ if (!img->texture) {
+ FREE(img);
+ return NULL;
+ }
+
+ img->face = 0;
+ img->level = 0;
+ img->zslice = 0;
+ img->loader_private = loaderPrivate;
+
+ return img;
+}
+
+static __DRIimage *
+dri2_create_image_from_renderbuffer(__DRIcontext *context,
+ int renderbuffer, void *loaderPrivate)
+{
+ struct dri_context *ctx = dri_context(context->driverPrivate);
+
+ if (!ctx->st->get_resource_for_egl_image)
+ return NULL;
+
+ /* TODO */
+ return NULL;
+}
+
+static void
+dri2_destroy_image(__DRIimage *img)
+{
+ pipe_resource_reference(&img->texture, NULL);
+ FREE(img);
+}
+
+static struct __DRIimageExtensionRec dri2ImageExtension = {
+ { __DRI_IMAGE, __DRI_IMAGE_VERSION },
+ dri2_create_image_from_name,
+ dri2_create_image_from_renderbuffer,
+ dri2_destroy_image,
+};
+
+/*
+ * Backend function init_screen.
+ */
+
+static const __DRIextension *dri_screen_extensions[] = {
+ &driReadDrawableExtension,
+ &driCopySubBufferExtension.base,
+ &driSwapControlExtension.base,
+ &driFrameTrackingExtension.base,
+ &driMediaStreamCounterExtension.base,
+ &dri2TexBufferExtension.base,
+ &dri2FlushExtension.base,
+ &dri2ImageExtension.base,
+ NULL
+};
+
+/**
+ * This is the driver specific part of the createNewScreen entry point.
+ *
+ * Returns the __GLcontextModes supported by this driver.
+ */
+const __DRIconfig **
+dri2_init_screen(__DRIscreen * sPriv)
+{
+ const __DRIconfig **configs;
+ struct dri_screen *screen;
+ struct pipe_screen *pscreen;
+
+ screen = CALLOC_STRUCT(dri_screen);
+ if (!screen)
+ return NULL;
+
+ screen->api = drm_api_create();
+ screen->sPriv = sPriv;
+ screen->fd = sPriv->fd;
+ screen->lookup_egl_image = dri2_lookup_egl_image;
+ screen->allocate_textures = dri2_allocate_textures;
+ screen->flush_frontbuffer = dri2_flush_frontbuffer;
+
+ sPriv->private = (void *)screen;
+ sPriv->extensions = dri_screen_extensions;
+
+ pscreen = screen->api->create_screen(screen->api, screen->fd);
+ /* dri_init_screen_helper checks pscreen for us */
+
+ configs = dri_init_screen_helper(screen, pscreen, 32);
+ if (!configs)
+ goto fail;
+
+ screen->auto_fake_front = dri_with_format(sPriv);
+ screen->broken_invalidate = !sPriv->dri2.useInvalidate;
+
+ return configs;
+fail:
+ dri_destroy_screen_helper(screen);
+ FREE(screen);
+ return NULL;
+}
+
+/* This is the table of extensions that the loader will dlsym() for. */
+PUBLIC const __DRIextension *__driDriverExtensions[] = {
+ &driCoreExtension.base,
+ &driLegacyExtension.base,
+ &driDRI2Extension.base,
+ NULL
+};
+
+/* vim: set sw=3 ts=8 sts=3 expandtab: */
diff --git a/src/gallium/state_trackers/dri/drm/dri2.h b/src/gallium/state_trackers/dri/drm/dri2.h
new file mode 100644
index 0000000000..07adfe4f6c
--- /dev/null
+++ b/src/gallium/state_trackers/dri/drm/dri2.h
@@ -0,0 +1,37 @@
+/**************************************************************************
+ *
+ * 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 DRI2_H
+#define DRI2_H
+
+#include "dri_drawable.h"
+#include "dri_wrapper.h"
+
+const __DRIconfig **
+dri2_init_screen(__DRIscreen * sPriv);
+
+#endif /* DRI2_H */
diff --git a/src/gallium/state_trackers/dri/drm/dri_context.c b/src/gallium/state_trackers/dri/drm/dri_context.c
new file mode 120000
index 0000000000..5cfbbaeb06
--- /dev/null
+++ b/src/gallium/state_trackers/dri/drm/dri_context.c
@@ -0,0 +1 @@
+../common/dri_context.c \ No newline at end of file
diff --git a/src/gallium/state_trackers/dri/drm/dri_drawable.c b/src/gallium/state_trackers/dri/drm/dri_drawable.c
new file mode 120000
index 0000000000..0fc19be6ea
--- /dev/null
+++ b/src/gallium/state_trackers/dri/drm/dri_drawable.c
@@ -0,0 +1 @@
+../common/dri_drawable.c \ No newline at end of file
diff --git a/src/gallium/state_trackers/dri/drm/dri_screen.c b/src/gallium/state_trackers/dri/drm/dri_screen.c
new file mode 120000
index 0000000000..847f6515f2
--- /dev/null
+++ b/src/gallium/state_trackers/dri/drm/dri_screen.c
@@ -0,0 +1 @@
+../common/dri_screen.c \ No newline at end of file
diff --git a/src/gallium/state_trackers/dri/sw/Makefile b/src/gallium/state_trackers/dri/sw/Makefile
new file mode 100644
index 0000000000..a1dadeba5e
--- /dev/null
+++ b/src/gallium/state_trackers/dri/sw/Makefile
@@ -0,0 +1,26 @@
+TOP = ../../../../..
+include $(TOP)/configs/current
+
+LIBNAME = drisw
+
+LIBRARY_DEFINES = -D__NOT_HAVE_DRM_H
+
+LIBRARY_INCLUDES = \
+ -I../dri \
+ -I$(TOP)/include \
+ -I$(TOP)/src/mapi \
+ -I$(TOP)/src/mesa \
+ -I$(TOP)/src/gallium/state_trackers/dri/common \
+ -I$(TOP)/src/mesa/drivers/dri/common \
+ -I$(TOP)/src/mesa/main \
+ -D__NOT_HAVE_DRM_H
+
+
+C_SOURCES = \
+ dri_context.c \
+ dri_screen.c \
+ dri_drawable.c \
+ dri1_helper.c \
+ drisw.c
+
+include ../../../Makefile.template
diff --git a/src/gallium/state_trackers/dri/sw/SConscript b/src/gallium/state_trackers/dri/sw/SConscript
new file mode 100644
index 0000000000..0c5194d6ed
--- /dev/null
+++ b/src/gallium/state_trackers/dri/sw/SConscript
@@ -0,0 +1,28 @@
+#######################################################################
+# SConscript for dri state_tracker
+
+Import('*')
+
+if env['dri']:
+
+ env = env.Clone()
+
+ env.Append(CPPPATH = [
+ '#/src/mapi',
+ '#/src/mesa',
+ '#/src/gallium/state_trackers/dri/common',
+ '#/src/mesa/drivers/dri/common',
+ ])
+
+ env.Append(CPPDEFINES = [('__NOT_HAVE_DRM_H', '1')])
+
+ st_drisw = env.ConvenienceLibrary(
+ target = 'st_drisw',
+ source = [ 'dri_context.c',
+ 'dri_drawable.c',
+ 'dri_screen.c',
+ 'dri1_helper.c',
+ 'drisw.c',
+ ]
+ )
+ Export('st_drisw')
diff --git a/src/gallium/state_trackers/dri/sw/dri1_helper.c b/src/gallium/state_trackers/dri/sw/dri1_helper.c
new file mode 120000
index 0000000000..c45ebf5c10
--- /dev/null
+++ b/src/gallium/state_trackers/dri/sw/dri1_helper.c
@@ -0,0 +1 @@
+../common/dri1_helper.c \ No newline at end of file
diff --git a/src/gallium/state_trackers/dri/sw/dri_context.c b/src/gallium/state_trackers/dri/sw/dri_context.c
new file mode 120000
index 0000000000..5cfbbaeb06
--- /dev/null
+++ b/src/gallium/state_trackers/dri/sw/dri_context.c
@@ -0,0 +1 @@
+../common/dri_context.c \ No newline at end of file
diff --git a/src/gallium/state_trackers/dri/sw/dri_drawable.c b/src/gallium/state_trackers/dri/sw/dri_drawable.c
new file mode 120000
index 0000000000..0fc19be6ea
--- /dev/null
+++ b/src/gallium/state_trackers/dri/sw/dri_drawable.c
@@ -0,0 +1 @@
+../common/dri_drawable.c \ No newline at end of file
diff --git a/src/gallium/state_trackers/dri/sw/dri_screen.c b/src/gallium/state_trackers/dri/sw/dri_screen.c
new file mode 120000
index 0000000000..847f6515f2
--- /dev/null
+++ b/src/gallium/state_trackers/dri/sw/dri_screen.c
@@ -0,0 +1 @@
+../common/dri_screen.c \ No newline at end of file
diff --git a/src/gallium/state_trackers/dri/sw/drisw.c b/src/gallium/state_trackers/dri/sw/drisw.c
new file mode 100644
index 0000000000..dcf645593f
--- /dev/null
+++ b/src/gallium/state_trackers/dri/sw/drisw.c
@@ -0,0 +1,289 @@
+/**************************************************************************
+ *
+ * Copyright 2009, VMware, Inc.
+ * All Rights Reserved.
+ * Copyright 2010 George Sapountzis <gsapountzis@gmail.com>
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+/* TODO:
+ *
+ * xshm / texture_from_pixmap / EGLImage:
+ *
+ * Allow the loaders to use the XSHM extension. It probably requires callbacks
+ * for createImage/destroyImage similar to DRI2 getBuffers.
+ */
+
+#include "util/u_format.h"
+#include "util/u_memory.h"
+#include "util/u_inlines.h"
+#include "pipe/p_context.h"
+#include "state_tracker/drisw_api.h"
+
+#include "dri_screen.h"
+#include "dri_context.h"
+#include "dri_drawable.h"
+#include "dri1_helper.h"
+#include "drisw.h"
+
+
+static INLINE void
+get_drawable_info(__DRIdrawable *dPriv, int *w, int *h)
+{
+ __DRIscreen *sPriv = dPriv->driScreenPriv;
+ const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;
+ int x, y;
+
+ loader->getDrawableInfo(dPriv,
+ &x, &y, w, h,
+ dPriv->loaderPrivate);
+}
+
+static INLINE void
+put_image(__DRIdrawable *dPriv, void *data, unsigned width, unsigned height)
+{
+ __DRIscreen *sPriv = dPriv->driScreenPriv;
+ const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;
+
+ loader->putImage(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP,
+ 0, 0, width, height,
+ data, dPriv->loaderPrivate);
+}
+
+static void
+drisw_update_drawable_info(struct dri_drawable *drawable)
+{
+ __DRIdrawable *dPriv = drawable->dPriv;
+
+ get_drawable_info(dPriv, &dPriv->w, &dPriv->h);
+}
+
+static void
+drisw_put_image(struct dri_drawable *drawable,
+ void *data, unsigned width, unsigned height)
+{
+ __DRIdrawable *dPriv = drawable->dPriv;
+
+ put_image(dPriv, data, width, height);
+}
+
+static INLINE void
+drisw_present_texture(__DRIdrawable *dPriv,
+ struct pipe_resource *ptex)
+{
+ struct dri_drawable *drawable = dri_drawable(dPriv);
+ struct dri_screen *screen = dri_screen(drawable->sPriv);
+ struct pipe_surface *psurf;
+
+ psurf = dri1_get_pipe_surface(drawable, ptex);
+ if (!psurf)
+ return;
+
+ screen->base.screen->flush_frontbuffer(screen->base.screen, psurf, drawable);
+}
+
+static INLINE void
+drisw_invalidate_drawable(__DRIdrawable *dPriv)
+{
+ struct dri_context *ctx = dri_get_current(dPriv->driScreenPriv);
+ struct dri_drawable *drawable = dri_drawable(dPriv);
+
+ drawable->texture_stamp = dPriv->lastStamp - 1;
+
+ /* check if swapping currently bound buffer */
+ if (ctx && ctx->dPriv == dPriv)
+ ctx->st->notify_invalid_framebuffer(ctx->st, &drawable->base);
+}
+
+static INLINE void
+drisw_copy_to_front(__DRIdrawable * dPriv,
+ struct pipe_resource *ptex)
+{
+ drisw_present_texture(dPriv, ptex);
+
+ drisw_invalidate_drawable(dPriv);
+}
+
+/*
+ * Backend functions for st_framebuffer interface and swap_buffers.
+ */
+
+void
+drisw_swap_buffers(__DRIdrawable *dPriv)
+{
+ struct dri_context *ctx = dri_get_current(dPriv->driScreenPriv);
+ struct dri_drawable *drawable = dri_drawable(dPriv);
+ struct pipe_resource *ptex;
+
+ if (!ctx)
+ return;
+
+ ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT];
+
+ if (ptex) {
+ ctx->st->flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
+
+ drisw_copy_to_front(dPriv, ptex);
+ }
+}
+
+static void
+drisw_flush_frontbuffer(struct dri_drawable *drawable,
+ enum st_attachment_type statt)
+{
+ struct dri_context *ctx = dri_get_current(drawable->sPriv);
+ struct pipe_resource *ptex;
+
+ if (!ctx)
+ return;
+
+ ptex = drawable->textures[statt];
+
+ if (ptex) {
+ drisw_copy_to_front(ctx->dPriv, ptex);
+ }
+}
+
+/**
+ * Allocate framebuffer attachments.
+ *
+ * During fixed-size operation, the function keeps allocating new attachments
+ * as they are requested. Unused attachments are not removed, not until the
+ * framebuffer is resized or destroyed.
+ *
+ * It should be possible for DRI1 and DRISW to share this function, but it
+ * seems a better seperation and safer for each DRI version to provide its own
+ * function.
+ */
+static void
+drisw_allocate_textures(struct dri_drawable *drawable,
+ const enum st_attachment_type *statts,
+ unsigned count)
+{
+ struct dri_screen *screen = dri_screen(drawable->sPriv);
+ struct pipe_resource templ;
+ unsigned width, height;
+ boolean resized;
+ int i;
+
+ width = drawable->dPriv->w;
+ height = drawable->dPriv->h;
+
+ resized = (drawable->old_w != width ||
+ drawable->old_h != height);
+
+ /* remove outdated textures */
+ if (resized) {
+ for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
+ pipe_resource_reference(&drawable->textures[i], NULL);
+ }
+
+ memset(&templ, 0, sizeof(templ));
+ templ.target = PIPE_TEXTURE_2D;
+ templ.width0 = width;
+ templ.height0 = height;
+ templ.depth0 = 1;
+ templ.last_level = 0;
+
+ for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
+ enum pipe_format format;
+ unsigned bind;
+
+ /* the texture already exists or not requested */
+ if (drawable->textures[statts[i]])
+ continue;
+
+ dri_drawable_get_format(drawable, statts[i], &format, &bind);
+
+ if (statts[i] != ST_ATTACHMENT_DEPTH_STENCIL)
+ bind |= PIPE_BIND_DISPLAY_TARGET;
+
+ if (format == PIPE_FORMAT_NONE)
+ continue;
+
+ templ.format = format;
+ templ.bind = bind;
+
+ drawable->textures[statts[i]] =
+ screen->base.screen->resource_create(screen->base.screen, &templ);
+ }
+
+ drawable->old_w = width;
+ drawable->old_h = height;
+}
+
+/*
+ * Backend function for init_screen.
+ */
+
+static const __DRIextension *drisw_screen_extensions[] = {
+ NULL
+};
+
+static struct drisw_loader_funcs drisw_lf = {
+ .put_image = drisw_put_image
+};
+
+const __DRIconfig **
+drisw_init_screen(__DRIscreen * sPriv)
+{
+ const __DRIconfig **configs;
+ struct dri_screen *screen;
+ struct pipe_screen *pscreen;
+
+ screen = CALLOC_STRUCT(dri_screen);
+ if (!screen)
+ return NULL;
+
+ screen->api = NULL; /* not needed */
+ screen->sPriv = sPriv;
+ screen->fd = -1;
+ screen->allocate_textures = drisw_allocate_textures;
+ screen->update_drawable_info = drisw_update_drawable_info;
+ screen->flush_frontbuffer = drisw_flush_frontbuffer;
+
+ sPriv->private = (void *)screen;
+ sPriv->extensions = drisw_screen_extensions;
+
+ pscreen = drisw_create_screen(&drisw_lf);
+ /* dri_init_screen_helper checks pscreen for us */
+
+ configs = dri_init_screen_helper(screen, pscreen, 32);
+ if (!configs)
+ goto fail;
+
+ return configs;
+fail:
+ dri_destroy_screen_helper(screen);
+ FREE(screen);
+ return NULL;
+}
+
+/* This is the table of extensions that the loader will dlsym() for. */
+PUBLIC const __DRIextension *__driDriverExtensions[] = {
+ &driCoreExtension.base,
+ &driSWRastExtension.base,
+ NULL
+};
+
+/* vim: set sw=3 ts=8 sts=3 expandtab: */
diff --git a/src/gallium/state_trackers/dri/sw/drisw.h b/src/gallium/state_trackers/dri/sw/drisw.h
new file mode 100644
index 0000000000..6c6c891f35
--- /dev/null
+++ b/src/gallium/state_trackers/dri/sw/drisw.h
@@ -0,0 +1,43 @@
+/**************************************************************************
+ *
+ * Copyright 2009, VMware, Inc.
+ * All Rights Reserved.
+ * Copyright 2010 George Sapountzis <gsapountzis@gmail.com>
+ *
+ * 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 DRISW_H
+#define DRISW_H
+
+#include "dri_context.h"
+#include "dri_drawable.h"
+
+#include "state_tracker/st_api.h"
+#include "dri_wrapper.h"
+
+const __DRIconfig **
+drisw_init_screen(__DRIscreen * sPriv);
+
+void drisw_swap_buffers(__DRIdrawable * dPriv);
+
+#endif /* DRISW_H */
diff --git a/src/gallium/state_trackers/egl/Makefile b/src/gallium/state_trackers/egl/Makefile
new file mode 100644
index 0000000000..fec178ffb3
--- /dev/null
+++ b/src/gallium/state_trackers/egl/Makefile
@@ -0,0 +1,87 @@
+TOP = ../../../..
+include $(TOP)/configs/current
+
+common_INCLUDES = \
+ -I. \
+ -I$(TOP)/src/gallium/include \
+ -I$(TOP)/src/gallium/auxiliary \
+ -I$(TOP)/src/gallium/drivers \
+ -I$(TOP)/src/egl/main \
+ -I$(TOP)/include
+
+common_SOURCES = $(wildcard common/*.c)
+common_OBJECTS = $(common_SOURCES:.c=.o)
+
+
+x11_INCLUDES = \
+ -I$(TOP)/src/gallium/drivers \
+ -I$(TOP)/src/glx \
+ -I$(TOP)/src/mapi \
+ -I$(TOP)/src/mesa \
+ $(X11_CFLAGS) \
+ $(shell pkg-config --cflags-only-I libdrm)
+
+x11_SOURCES = $(wildcard x11/*.c) \
+ $(TOP)/src/glx/dri2.c
+x11_OBJECTS = $(x11_SOURCES:.c=.o)
+
+
+kms_INCLUDES = $(shell pkg-config --cflags-only-I libdrm)
+kms_SOURCES = $(wildcard kms/*.c)
+kms_OBJECTS = $(kms_SOURCES:.c=.o)
+
+
+fbdev_INCLUDES = -I$(TOP)/src/gallium/winsys/sw -I$(TOP)/src/gallium/drivers
+fbdev_SOURCES = $(wildcard fbdev/*.c)
+fbdev_OBJECTS = $(fbdev_SOURCES:.c=.o)
+
+
+ALL_INCLUDES = $(common_INCLUDES) $(x11_INCLUDES) $(kms_INCLUDES) $(fbdev_INCLUDES)
+ALL_SOURCES = $(common_SOURCES) $(x11_SOURCES) $(kms_SOURCES) $(fbdev_SOURCES)
+ALL_OBJECTS = $(common_OBJECTS) $(x11_OBJECTS) $(kms_OBJECTS) $(fbdev_OBJECTS)
+
+##### TARGETS #####
+
+EGL_PLATFORMS_MODS = $(foreach plat, $(EGL_PLATFORMS), libegl$(plat).a)
+
+default: depend $(EGL_PLATFORMS_MODS)
+
+
+libeglx11.a: $(x11_OBJECTS) $(common_OBJECTS) Makefile
+ $(MKLIB) -o eglx11 -static $(x11_OBJECTS) $(common_OBJECTS)
+
+libeglkms.a: $(kms_OBJECTS) $(common_OBJECTS) Makefile
+ $(MKLIB) -o eglkms -static $(kms_OBJECTS) $(common_OBJECTS)
+
+libeglfbdev.a: $(fbdev_OBJECTS) $(common_OBJECTS) Makefile
+ $(MKLIB) -o eglfbdev -static $(fbdev_OBJECTS) $(common_OBJECTS)
+
+depend:
+ rm -f depend
+ touch depend
+ $(MKDEP) $(MKDEP_OPTIONS) $(ALL_INCLUDES) $(ALL_SOURCES) 2> /dev/null
+
+clean:
+ rm -f $(ALL_OBJECTS)
+ rm -f $(EGL_PLATFORMS_MODS)
+ rm -f depend depend.bak
+
+# Dummy target
+install:
+ @echo -n ""
+
+##### RULES #####
+
+$(common_OBJECTS): %.o: %.c
+ $(CC) -c $(common_INCLUDES) $(DEFINES) $(CFLAGS) $< -o $@
+
+$(x11_OBJECTS): %.o: %.c
+ $(CC) -c $(common_INCLUDES) $(x11_INCLUDES) $(DEFINES) $(CFLAGS) $< -o $@
+
+$(kms_OBJECTS): %.o: %.c
+ $(CC) -c $(common_INCLUDES) $(kms_INCLUDES) $(DEFINES) $(CFLAGS) $< -o $@
+
+$(fbdev_OBJECTS): %.o: %.c
+ $(CC) -c $(common_INCLUDES) $(fbdev_INCLUDES) $(DEFINES) $(CFLAGS) $< -o $@
+
+sinclude depend
diff --git a/src/gallium/state_trackers/egl/SConscript b/src/gallium/state_trackers/egl/SConscript
new file mode 100644
index 0000000000..c4d01d6b28
--- /dev/null
+++ b/src/gallium/state_trackers/egl/SConscript
@@ -0,0 +1,32 @@
+#######################################################################
+# SConscript for egl state_tracker
+
+Import('*')
+
+if 'egl' in env['statetrackers']:
+
+ env = env.Clone()
+
+ env.Append(CPPPATH = [
+ '#/src/egl/main',
+ '#/src/gallium/winsys/sw',
+ '.',
+ ])
+
+ common_sources = [
+ 'common/egl_g3d.c',
+ 'common/egl_g3d_api.c',
+ 'common/egl_g3d_image.c',
+ 'common/egl_g3d_st.c',
+ 'common/native_helper.c',
+ ]
+
+ gdi_sources = common_sources + [
+ 'gdi/native_gdi.c',
+ ]
+
+ st_egl_gdi = env.ConvenienceLibrary(
+ target = 'st_egl_gdi',
+ source = gdi_sources,
+ )
+ Export('st_egl_gdi')
diff --git a/src/gallium/state_trackers/egl/common/egl_g3d.c b/src/gallium/state_trackers/egl/common/egl_g3d.c
new file mode 100644
index 0000000000..361cc7960b
--- /dev/null
+++ b/src/gallium/state_trackers/egl/common/egl_g3d.c
@@ -0,0 +1,616 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.8
+ *
+ * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org>
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "egldriver.h"
+#include "eglcurrent.h"
+#include "egllog.h"
+
+#include "pipe/p_screen.h"
+#include "util/u_memory.h"
+#include "util/u_format.h"
+#include "util/u_string.h"
+
+#include "egl_g3d.h"
+#include "egl_g3d_api.h"
+#include "egl_g3d_st.h"
+#include "native.h"
+
+/**
+ * Initialize the state trackers.
+ */
+static void
+egl_g3d_init_st(_EGLDriver *drv)
+{
+ struct egl_g3d_driver *gdrv = egl_g3d_driver(drv);
+ EGLint i;
+
+ /* already initialized */
+ if (gdrv->api_mask)
+ return;
+
+ egl_g3d_init_st_apis(gdrv->stapis);
+ for (i = 0; i < ST_API_COUNT; i++) {
+ if (gdrv->stapis[i])
+ gdrv->api_mask |= egl_g3d_st_api_bit(i);
+ }
+
+ if (gdrv->api_mask)
+ _eglLog(_EGL_DEBUG, "Driver API mask: 0x%x", gdrv->api_mask);
+ else
+ _eglLog(_EGL_WARNING, "No supported client API");
+}
+
+/**
+ * Get the probe object of the display.
+ *
+ * Note that this function may be called before the display is initialized.
+ */
+static struct native_probe *
+egl_g3d_get_probe(_EGLDriver *drv, _EGLDisplay *dpy)
+{
+ struct egl_g3d_driver *gdrv = egl_g3d_driver(drv);
+ struct native_probe *nprobe;
+
+ nprobe = (struct native_probe *) _eglGetProbeCache(gdrv->probe_key);
+ if (!nprobe || nprobe->display != dpy->NativeDisplay) {
+ if (nprobe)
+ nprobe->destroy(nprobe);
+ nprobe = native_create_probe(dpy->NativeDisplay);
+ _eglSetProbeCache(gdrv->probe_key, (void *) nprobe);
+ }
+
+ return nprobe;
+}
+
+/**
+ * Destroy the probe object of the display. The display may be NULL.
+ *
+ * Note that this function may be called before the display is initialized.
+ */
+static void
+egl_g3d_destroy_probe(_EGLDriver *drv, _EGLDisplay *dpy)
+{
+ struct egl_g3d_driver *gdrv = egl_g3d_driver(drv);
+ struct native_probe *nprobe;
+
+ nprobe = (struct native_probe *) _eglGetProbeCache(gdrv->probe_key);
+ if (nprobe && (!dpy || nprobe->display == dpy->NativeDisplay)) {
+ nprobe->destroy(nprobe);
+ _eglSetProbeCache(gdrv->probe_key, NULL);
+ }
+}
+
+#ifdef EGL_MESA_screen_surface
+
+static void
+egl_g3d_add_screens(_EGLDriver *drv, _EGLDisplay *dpy)
+{
+ struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
+ const struct native_connector **native_connectors;
+ EGLint num_connectors, i;
+
+ native_connectors =
+ gdpy->native->modeset->get_connectors(gdpy->native, &num_connectors, NULL);
+ if (!num_connectors) {
+ if (native_connectors)
+ FREE(native_connectors);
+ return;
+ }
+
+ for (i = 0; i < num_connectors; i++) {
+ const struct native_connector *nconn = native_connectors[i];
+ struct egl_g3d_screen *gscr;
+ const struct native_mode **native_modes;
+ EGLint num_modes, j;
+
+ /* TODO support for hotplug */
+ native_modes =
+ gdpy->native->modeset->get_modes(gdpy->native, nconn, &num_modes);
+ if (!num_modes) {
+ if (native_modes)
+ FREE(native_modes);
+ continue;
+ }
+
+ gscr = CALLOC_STRUCT(egl_g3d_screen);
+ if (!gscr) {
+ FREE(native_modes);
+ continue;
+ }
+
+ _eglInitScreen(&gscr->base);
+
+ for (j = 0; j < num_modes; j++) {
+ const struct native_mode *nmode = native_modes[j];
+ _EGLMode *mode;
+
+ mode = _eglAddNewMode(&gscr->base, nmode->width, nmode->height,
+ nmode->refresh_rate, nmode->desc);
+ if (!mode)
+ break;
+ /* gscr->native_modes and gscr->base.Modes should be consistent */
+ assert(mode == &gscr->base.Modes[j]);
+ }
+
+ gscr->native = nconn;
+ gscr->native_modes = native_modes;
+
+ _eglAddScreen(dpy, &gscr->base);
+ }
+
+ FREE(native_connectors);
+}
+
+#endif /* EGL_MESA_screen_surface */
+
+/**
+ * Initialize and validate the EGL config attributes.
+ */
+static EGLBoolean
+init_config_attributes(_EGLConfig *conf, const struct native_config *nconf,
+ EGLint api_mask, enum pipe_format depth_stencil_format)
+{
+ uint rgba[4], depth_stencil[2], buffer_size;
+ EGLint surface_type;
+ EGLint i;
+
+ /* get the color and depth/stencil component sizes */
+ assert(nconf->color_format != PIPE_FORMAT_NONE);
+ buffer_size = 0;
+ for (i = 0; i < 4; i++) {
+ rgba[i] = util_format_get_component_bits(nconf->color_format,
+ UTIL_FORMAT_COLORSPACE_RGB, i);
+ buffer_size += rgba[i];
+ }
+ for (i = 0; i < 2; i++) {
+ if (depth_stencil_format != PIPE_FORMAT_NONE) {
+ depth_stencil[i] =
+ util_format_get_component_bits(depth_stencil_format,
+ UTIL_FORMAT_COLORSPACE_ZS, i);
+ }
+ else {
+ depth_stencil[i] = 0;
+ }
+ }
+
+ surface_type = 0x0;
+ if (nconf->window_bit)
+ surface_type |= EGL_WINDOW_BIT;
+ if (nconf->pixmap_bit)
+ surface_type |= EGL_PIXMAP_BIT;
+#ifdef EGL_MESA_screen_surface
+ if (nconf->scanout_bit)
+ surface_type |= EGL_SCREEN_BIT_MESA;
+#endif
+
+ if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_BACK_LEFT))
+ surface_type |= EGL_PBUFFER_BIT;
+
+ SET_CONFIG_ATTRIB(conf, EGL_CONFORMANT, api_mask);
+ SET_CONFIG_ATTRIB(conf, EGL_RENDERABLE_TYPE, api_mask);
+
+ SET_CONFIG_ATTRIB(conf, EGL_RED_SIZE, rgba[0]);
+ SET_CONFIG_ATTRIB(conf, EGL_GREEN_SIZE, rgba[1]);
+ SET_CONFIG_ATTRIB(conf, EGL_BLUE_SIZE, rgba[2]);
+ SET_CONFIG_ATTRIB(conf, EGL_ALPHA_SIZE, rgba[3]);
+ SET_CONFIG_ATTRIB(conf, EGL_BUFFER_SIZE, buffer_size);
+
+ SET_CONFIG_ATTRIB(conf, EGL_DEPTH_SIZE, depth_stencil[0]);
+ SET_CONFIG_ATTRIB(conf, EGL_STENCIL_SIZE, depth_stencil[1]);
+
+ SET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE, surface_type);
+
+ SET_CONFIG_ATTRIB(conf, EGL_NATIVE_RENDERABLE, EGL_TRUE);
+ if (surface_type & EGL_WINDOW_BIT) {
+ SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_ID, nconf->native_visual_id);
+ SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE,
+ nconf->native_visual_type);
+ }
+
+ if (surface_type & EGL_PBUFFER_BIT) {
+ SET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE);
+ if (rgba[3])
+ SET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE);
+
+ SET_CONFIG_ATTRIB(conf, EGL_MAX_PBUFFER_WIDTH, 4096);
+ SET_CONFIG_ATTRIB(conf, EGL_MAX_PBUFFER_HEIGHT, 4096);
+ SET_CONFIG_ATTRIB(conf, EGL_MAX_PBUFFER_PIXELS, 4096 * 4096);
+ }
+
+ SET_CONFIG_ATTRIB(conf, EGL_LEVEL, nconf->level);
+ SET_CONFIG_ATTRIB(conf, EGL_SAMPLES, nconf->samples);
+ SET_CONFIG_ATTRIB(conf, EGL_SAMPLE_BUFFERS, 1);
+
+ if (nconf->slow_config)
+ SET_CONFIG_ATTRIB(conf, EGL_CONFIG_CAVEAT, EGL_SLOW_CONFIG);
+
+ if (nconf->transparent_rgb) {
+ rgba[0] = nconf->transparent_rgb_values[0];
+ rgba[1] = nconf->transparent_rgb_values[1];
+ rgba[2] = nconf->transparent_rgb_values[2];
+
+ SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_TYPE, EGL_TRANSPARENT_RGB);
+ SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_RED_VALUE, rgba[0]);
+ SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_GREEN_VALUE, rgba[1]);
+ SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_BLUE_VALUE, rgba[2]);
+ }
+
+ return _eglValidateConfig(conf, EGL_FALSE);
+}
+
+/**
+ * Initialize an EGL config from the native config.
+ */
+static EGLBoolean
+egl_g3d_init_config(_EGLDriver *drv, _EGLDisplay *dpy,
+ _EGLConfig *conf, const struct native_config *nconf,
+ enum pipe_format depth_stencil_format)
+{
+ struct egl_g3d_driver *gdrv = egl_g3d_driver(drv);
+ struct egl_g3d_config *gconf = egl_g3d_config(conf);
+ EGLint buffer_mask, api_mask;
+ EGLBoolean valid;
+ EGLint i;
+
+ buffer_mask = 0x0;
+ if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_FRONT_LEFT))
+ buffer_mask |= ST_ATTACHMENT_FRONT_LEFT_MASK;
+ if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_BACK_LEFT))
+ buffer_mask |= ST_ATTACHMENT_BACK_LEFT_MASK;
+ if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_FRONT_RIGHT))
+ buffer_mask |= ST_ATTACHMENT_FRONT_RIGHT_MASK;
+ if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_BACK_RIGHT))
+ buffer_mask |= ST_ATTACHMENT_BACK_RIGHT_MASK;
+
+ gconf->stvis.buffer_mask = buffer_mask;
+ gconf->stvis.color_format = nconf->color_format;
+ gconf->stvis.depth_stencil_format = depth_stencil_format;
+ gconf->stvis.accum_format = PIPE_FORMAT_NONE;
+ gconf->stvis.samples = nconf->samples;
+
+ gconf->stvis.render_buffer = (buffer_mask & ST_ATTACHMENT_BACK_LEFT_MASK) ?
+ ST_ATTACHMENT_BACK_LEFT : ST_ATTACHMENT_FRONT_LEFT;
+
+ api_mask = 0;
+ for (i = 0; i < ST_API_COUNT; i++) {
+ struct st_api *stapi = gdrv->stapis[i];
+ if (stapi) {
+ if (stapi->is_visual_supported(stapi, &gconf->stvis))
+ api_mask |= egl_g3d_st_api_bit(i);
+ }
+ }
+ /* this is required by EGL, not by OpenGL ES */
+ if (nconf->window_bit &&
+ gconf->stvis.render_buffer != ST_ATTACHMENT_BACK_LEFT)
+ api_mask &= ~(EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT);
+
+ if (!api_mask) {
+ _eglLog(_EGL_DEBUG, "no state tracker supports config 0x%x",
+ nconf->native_visual_id);
+ }
+
+ valid = init_config_attributes(&gconf->base,
+ nconf, api_mask, depth_stencil_format);
+ if (!valid) {
+ _eglLog(_EGL_DEBUG, "skip invalid config 0x%x", nconf->native_visual_id);
+ return EGL_FALSE;
+ }
+
+ gconf->native = nconf;
+
+ return EGL_TRUE;
+}
+
+/**
+ * Get all interested depth/stencil formats of a display.
+ */
+static EGLint
+egl_g3d_fill_depth_stencil_formats(_EGLDisplay *dpy,
+ enum pipe_format formats[8])
+{
+ struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
+ struct pipe_screen *screen = gdpy->native->screen;
+ const EGLint candidates[] = {
+ 1, PIPE_FORMAT_Z16_UNORM,
+ 1, PIPE_FORMAT_Z32_UNORM,
+ 2, PIPE_FORMAT_Z24_UNORM_S8_USCALED, PIPE_FORMAT_S8_USCALED_Z24_UNORM,
+ 2, PIPE_FORMAT_Z24X8_UNORM, PIPE_FORMAT_X8Z24_UNORM,
+ 0
+ };
+ const EGLint *fmt = candidates;
+ EGLint count;
+
+ count = 0;
+ formats[count++] = PIPE_FORMAT_NONE;
+
+ while (*fmt) {
+ EGLint i, n = *fmt++;
+
+ /* pick the first supported format */
+ for (i = 0; i < n; i++) {
+ if (screen->is_format_supported(screen, fmt[i],
+ PIPE_TEXTURE_2D, 0, PIPE_BIND_DEPTH_STENCIL, 0)) {
+ formats[count++] = fmt[i];
+ break;
+ }
+ }
+
+ fmt += n;
+ }
+
+ return count;
+}
+
+/**
+ * Add configs to display and return the next config ID.
+ */
+static EGLint
+egl_g3d_add_configs(_EGLDriver *drv, _EGLDisplay *dpy, EGLint id)
+{
+ struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
+ const struct native_config **native_configs;
+ enum pipe_format depth_stencil_formats[8];
+ int num_formats, num_configs, i, j;
+
+ native_configs = gdpy->native->get_configs(gdpy->native, &num_configs);
+ if (!num_configs) {
+ if (native_configs)
+ FREE(native_configs);
+ return id;
+ }
+
+ num_formats = egl_g3d_fill_depth_stencil_formats(dpy,
+ depth_stencil_formats);
+
+ for (i = 0; i < num_configs; i++) {
+ for (j = 0; j < num_formats; j++) {
+ struct egl_g3d_config *gconf;
+
+ gconf = CALLOC_STRUCT(egl_g3d_config);
+ if (gconf) {
+ _eglInitConfig(&gconf->base, dpy, id);
+ if (!egl_g3d_init_config(drv, dpy, &gconf->base,
+ native_configs[i], depth_stencil_formats[j])) {
+ FREE(gconf);
+ break;
+ }
+
+ _eglAddConfig(dpy, &gconf->base);
+ id++;
+ }
+ }
+ }
+
+ FREE(native_configs);
+ return id;
+}
+
+static void
+egl_g3d_invalid_surface(struct native_display *ndpy,
+ struct native_surface *nsurf,
+ unsigned int seq_num)
+{
+ /* XXX not thread safe? */
+ struct egl_g3d_surface *gsurf = egl_g3d_surface(nsurf->user_data);
+ struct egl_g3d_context *gctx;
+
+ /*
+ * Some functions such as egl_g3d_copy_buffers create a temporary native
+ * surface. There is no gsurf associated with it.
+ */
+ gctx = (gsurf) ? egl_g3d_context(gsurf->base.CurrentContext) : NULL;
+ if (gctx)
+ gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, gsurf->stfbi);
+}
+
+static struct native_event_handler egl_g3d_native_event_handler = {
+ egl_g3d_invalid_surface
+};
+
+static EGLBoolean
+egl_g3d_terminate(_EGLDriver *drv, _EGLDisplay *dpy)
+{
+ struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
+ EGLint i;
+
+ _eglReleaseDisplayResources(drv, dpy);
+ _eglCleanupDisplay(dpy);
+
+ if (gdpy->pipe)
+ gdpy->pipe->destroy(gdpy->pipe);
+
+ if (dpy->Screens) {
+ for (i = 0; i < dpy->NumScreens; i++) {
+ struct egl_g3d_screen *gscr = egl_g3d_screen(dpy->Screens[i]);
+ FREE(gscr->native_modes);
+ FREE(gscr);
+ }
+ FREE(dpy->Screens);
+ }
+
+ if (gdpy->smapi)
+ egl_g3d_destroy_st_manager(gdpy->smapi);
+
+ if (gdpy->native)
+ gdpy->native->destroy(gdpy->native);
+
+ FREE(gdpy);
+ dpy->DriverData = NULL;
+
+ return EGL_TRUE;
+}
+
+static EGLBoolean
+egl_g3d_initialize(_EGLDriver *drv, _EGLDisplay *dpy,
+ EGLint *major, EGLint *minor)
+{
+ struct egl_g3d_driver *gdrv = egl_g3d_driver(drv);
+ struct egl_g3d_display *gdpy;
+
+ /* the probe object is unlikely to be needed again */
+ egl_g3d_destroy_probe(drv, dpy);
+
+ gdpy = CALLOC_STRUCT(egl_g3d_display);
+ if (!gdpy) {
+ _eglError(EGL_BAD_ALLOC, "eglInitialize");
+ goto fail;
+ }
+ dpy->DriverData = gdpy;
+
+ gdpy->native = native_create_display(dpy->NativeDisplay,
+ &egl_g3d_native_event_handler);
+ if (!gdpy->native) {
+ _eglError(EGL_NOT_INITIALIZED, "eglInitialize(no usable display)");
+ goto fail;
+ }
+
+ gdpy->native->user_data = (void *) dpy;
+
+ egl_g3d_init_st(&gdrv->base);
+ dpy->ClientAPIsMask = gdrv->api_mask;
+
+ gdpy->smapi = egl_g3d_create_st_manager(dpy);
+ if (!gdpy->smapi) {
+ _eglError(EGL_NOT_INITIALIZED,
+ "eglInitialize(failed to create st manager)");
+ goto fail;
+ }
+
+#ifdef EGL_MESA_screen_surface
+ /* enable MESA_screen_surface before adding (and validating) configs */
+ if (gdpy->native->modeset) {
+ dpy->Extensions.MESA_screen_surface = EGL_TRUE;
+ egl_g3d_add_screens(drv, dpy);
+ }
+#endif
+
+ dpy->Extensions.KHR_image_base = EGL_TRUE;
+ if (gdpy->native->get_param(gdpy->native, NATIVE_PARAM_USE_NATIVE_BUFFER))
+ dpy->Extensions.KHR_image_pixmap = EGL_TRUE;
+
+ if (egl_g3d_add_configs(drv, dpy, 1) == 1) {
+ _eglError(EGL_NOT_INITIALIZED, "eglInitialize(unable to add configs)");
+ goto fail;
+ }
+
+ *major = 1;
+ *minor = 4;
+
+ return EGL_TRUE;
+
+fail:
+ if (gdpy)
+ egl_g3d_terminate(drv, dpy);
+ return EGL_FALSE;
+}
+
+static _EGLProc
+egl_g3d_get_proc_address(_EGLDriver *drv, const char *procname)
+{
+ struct egl_g3d_driver *gdrv = egl_g3d_driver(drv);
+ _EGLProc proc;
+ EGLint i;
+
+ /* in case this is called before a display is initialized */
+ egl_g3d_init_st(&gdrv->base);
+
+ for (i = 0; i < ST_API_COUNT; i++) {
+ struct st_api *stapi = gdrv->stapis[i];
+ if (stapi) {
+ proc = (_EGLProc) stapi->get_proc_address(stapi, procname);
+ if (proc)
+ return proc;
+ }
+ }
+
+ return (_EGLProc) NULL;
+}
+
+static EGLint
+egl_g3d_probe(_EGLDriver *drv, _EGLDisplay *dpy)
+{
+ struct native_probe *nprobe;
+ enum native_probe_result res;
+ EGLint score;
+
+ nprobe = egl_g3d_get_probe(drv, dpy);
+ res = native_get_probe_result(nprobe);
+
+ switch (res) {
+ case NATIVE_PROBE_UNKNOWN:
+ default:
+ score = 0;
+ break;
+ case NATIVE_PROBE_FALLBACK:
+ score = 40;
+ break;
+ case NATIVE_PROBE_SUPPORTED:
+ score = 50;
+ break;
+ case NATIVE_PROBE_EXACT:
+ score = 100;
+ break;
+ }
+
+ return score;
+}
+
+static void
+egl_g3d_unload(_EGLDriver *drv)
+{
+ struct egl_g3d_driver *gdrv = egl_g3d_driver(drv);
+
+ egl_g3d_destroy_st_apis();
+ egl_g3d_destroy_probe(drv, NULL);
+ FREE(gdrv);
+}
+
+_EGLDriver *
+_eglMain(const char *args)
+{
+ static char driver_name[64];
+ struct egl_g3d_driver *gdrv;
+
+ util_snprintf(driver_name, sizeof(driver_name),
+ "Gallium/%s", native_get_name());
+
+ gdrv = CALLOC_STRUCT(egl_g3d_driver);
+ if (!gdrv)
+ return NULL;
+
+ egl_g3d_init_driver_api(&gdrv->base);
+ gdrv->base.API.Initialize = egl_g3d_initialize;
+ gdrv->base.API.Terminate = egl_g3d_terminate;
+ gdrv->base.API.GetProcAddress = egl_g3d_get_proc_address;
+
+ gdrv->base.Name = driver_name;
+ gdrv->base.Probe = egl_g3d_probe;
+ gdrv->base.Unload = egl_g3d_unload;
+
+ /* the key is " EGL G3D" */
+ gdrv->probe_key = 0x0E61063D;
+
+ return &gdrv->base;
+}
diff --git a/src/gallium/state_trackers/egl/common/egl_g3d.h b/src/gallium/state_trackers/egl/common/egl_g3d.h
new file mode 100644
index 0000000000..d516d8fe03
--- /dev/null
+++ b/src/gallium/state_trackers/egl/common/egl_g3d.h
@@ -0,0 +1,109 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.8
+ *
+ * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org>
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _EGL_G3D_H_
+#define _EGL_G3D_H_
+
+#include "pipe/p_compiler.h"
+#include "pipe/p_screen.h"
+#include "pipe/p_context.h"
+#include "pipe/p_format.h"
+#include "egldriver.h"
+#include "egldisplay.h"
+#include "eglcontext.h"
+#include "eglsurface.h"
+#include "eglconfig.h"
+#include "eglimage.h"
+#include "eglscreen.h"
+#include "eglmode.h"
+
+#include "native.h"
+#include "egl_g3d_st.h"
+
+struct egl_g3d_driver {
+ _EGLDriver base;
+ struct st_api *stapis[ST_API_COUNT];
+ EGLint api_mask;
+
+ EGLint probe_key;
+};
+
+struct egl_g3d_display {
+ struct native_display *native;
+
+ struct st_manager *smapi;
+ struct pipe_context *pipe;
+};
+
+struct egl_g3d_context {
+ _EGLContext base;
+
+ struct st_api *stapi;
+
+ struct st_context_iface *stctxi;
+};
+
+struct egl_g3d_surface {
+ _EGLSurface base;
+
+ struct st_visual stvis;
+ struct st_framebuffer_iface *stfbi;
+
+ /* the native surface; NULL for pbuffers */
+ struct native_surface *native;
+ struct pipe_resource *render_texture;
+
+ EGLenum client_buffer_type;
+ EGLClientBuffer client_buffer;
+
+ unsigned int sequence_number;
+};
+
+struct egl_g3d_config {
+ _EGLConfig base;
+ const struct native_config *native;
+ struct st_visual stvis;
+};
+
+struct egl_g3d_image {
+ _EGLImage base;
+ struct pipe_resource *texture;
+ unsigned face;
+ unsigned level;
+ unsigned zslice;
+};
+
+struct egl_g3d_screen {
+ _EGLScreen base;
+ const struct native_connector *native;
+ const struct native_mode **native_modes;
+};
+
+/* standard typecasts */
+_EGL_DRIVER_STANDARD_TYPECASTS(egl_g3d)
+_EGL_DRIVER_TYPECAST(egl_g3d_screen, _EGLScreen, obj)
+_EGL_DRIVER_TYPECAST(egl_g3d_image, _EGLImage, obj)
+
+#endif /* _EGL_G3D_H_ */
diff --git a/src/gallium/state_trackers/egl/common/egl_g3d_api.c b/src/gallium/state_trackers/egl/common/egl_g3d_api.c
new file mode 100644
index 0000000000..255a1fb730
--- /dev/null
+++ b/src/gallium/state_trackers/egl/common/egl_g3d_api.c
@@ -0,0 +1,814 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.9
+ *
+ * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org>
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "egldriver.h"
+#include "eglcurrent.h"
+#include "egllog.h"
+
+#include "pipe/p_screen.h"
+#include "util/u_memory.h"
+#include "util/u_inlines.h"
+
+#include "egl_g3d.h"
+#include "egl_g3d_api.h"
+#include "egl_g3d_image.h"
+#include "egl_g3d_st.h"
+#include "native.h"
+
+/**
+ * Return the state tracker for the given context.
+ */
+static struct st_api *
+egl_g3d_choose_st(_EGLDriver *drv, _EGLContext *ctx)
+{
+ struct egl_g3d_driver *gdrv = egl_g3d_driver(drv);
+ struct st_api *stapi;
+ EGLint idx = -1;
+
+ switch (ctx->ClientAPI) {
+ case EGL_OPENGL_ES_API:
+ switch (ctx->ClientVersion) {
+ case 1:
+ idx = ST_API_OPENGL_ES1;
+ break;
+ case 2:
+ idx = ST_API_OPENGL_ES2;
+ break;
+ default:
+ _eglLog(_EGL_WARNING, "unknown client version %d",
+ ctx->ClientVersion);
+ break;
+ }
+ break;
+ case EGL_OPENVG_API:
+ idx = ST_API_OPENVG;
+ break;
+ case EGL_OPENGL_API:
+ idx = ST_API_OPENGL;
+ break;
+ default:
+ _eglLog(_EGL_WARNING, "unknown client API 0x%04x", ctx->ClientAPI);
+ break;
+ }
+
+ stapi = (idx >= 0) ? gdrv->stapis[idx] : NULL;
+ return stapi;
+}
+
+static _EGLContext *
+egl_g3d_create_context(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
+ _EGLContext *share, const EGLint *attribs)
+{
+ struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
+ struct egl_g3d_context *gshare = egl_g3d_context(share);
+ struct egl_g3d_config *gconf = egl_g3d_config(conf);
+ struct egl_g3d_context *gctx;
+
+ gctx = CALLOC_STRUCT(egl_g3d_context);
+ if (!gctx) {
+ _eglError(EGL_BAD_ALLOC, "eglCreateContext");
+ return NULL;
+ }
+
+ if (!_eglInitContext(&gctx->base, dpy, conf, attribs)) {
+ FREE(gctx);
+ return NULL;
+ }
+
+ gctx->stapi = egl_g3d_choose_st(drv, &gctx->base);
+ if (!gctx->stapi) {
+ FREE(gctx);
+ return NULL;
+ }
+
+ gctx->stctxi = gctx->stapi->create_context(gctx->stapi, gdpy->smapi,
+ &gconf->stvis, (gshare) ? gshare->stctxi : NULL);
+ if (!gctx->stctxi) {
+ FREE(gctx);
+ return NULL;
+ }
+
+ gctx->stctxi->st_manager_private = (void *) &gctx->base;
+
+ return &gctx->base;
+}
+
+/**
+ * Destroy a context.
+ */
+static void
+destroy_context(_EGLDisplay *dpy, _EGLContext *ctx)
+{
+ struct egl_g3d_context *gctx = egl_g3d_context(ctx);
+
+ /* FIXME a context might live longer than its display */
+ if (!dpy->Initialized)
+ _eglLog(_EGL_FATAL, "destroy a context with an unitialized display");
+
+ gctx->stctxi->destroy(gctx->stctxi);
+
+ FREE(gctx);
+}
+
+static EGLBoolean
+egl_g3d_destroy_context(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
+{
+ if (!_eglIsContextBound(ctx))
+ destroy_context(dpy, ctx);
+ return EGL_TRUE;
+}
+
+struct egl_g3d_create_surface_arg {
+ EGLint type;
+ union {
+ EGLNativeWindowType win;
+ EGLNativePixmapType pix;
+ } u;
+};
+
+static _EGLSurface *
+egl_g3d_create_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
+ struct egl_g3d_create_surface_arg *arg,
+ const EGLint *attribs)
+{
+ struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
+ struct egl_g3d_config *gconf = egl_g3d_config(conf);
+ struct egl_g3d_surface *gsurf;
+ struct native_surface *nsurf;
+ const char *err;
+
+ switch (arg->type) {
+ case EGL_WINDOW_BIT:
+ err = "eglCreateWindowSurface";
+ break;
+ case EGL_PIXMAP_BIT:
+ err = "eglCreatePixmapSurface";
+ break;
+#ifdef EGL_MESA_screen_surface
+ case EGL_SCREEN_BIT_MESA:
+ err = "eglCreateScreenSurface";
+ break;
+#endif
+ default:
+ err = "eglCreateUnknownSurface";
+ break;
+ }
+
+ gsurf = CALLOC_STRUCT(egl_g3d_surface);
+ if (!gsurf) {
+ _eglError(EGL_BAD_ALLOC, err);
+ return NULL;
+ }
+
+ if (!_eglInitSurface(&gsurf->base, dpy, arg->type, conf, attribs)) {
+ FREE(gsurf);
+ return NULL;
+ }
+
+ /* create the native surface */
+ switch (arg->type) {
+ case EGL_WINDOW_BIT:
+ nsurf = gdpy->native->create_window_surface(gdpy->native,
+ arg->u.win, gconf->native);
+ break;
+ case EGL_PIXMAP_BIT:
+ nsurf = gdpy->native->create_pixmap_surface(gdpy->native,
+ arg->u.pix, gconf->native);
+ break;
+#ifdef EGL_MESA_screen_surface
+ case EGL_SCREEN_BIT_MESA:
+ /* prefer back buffer (move to _eglInitSurface?) */
+ gsurf->base.RenderBuffer = EGL_BACK_BUFFER;
+ nsurf = gdpy->native->modeset->create_scanout_surface(gdpy->native,
+ gconf->native, gsurf->base.Width, gsurf->base.Height);
+ break;
+#endif
+ default:
+ nsurf = NULL;
+ break;
+ }
+
+ if (!nsurf) {
+ FREE(gsurf);
+ return NULL;
+ }
+ /* initialize the geometry */
+ if (!nsurf->validate(nsurf, 0x0, &gsurf->sequence_number, NULL,
+ &gsurf->base.Width, &gsurf->base.Height)) {
+ nsurf->destroy(nsurf);
+ FREE(gsurf);
+ return NULL;
+ }
+
+ gsurf->stvis = gconf->stvis;
+ if (gsurf->base.RenderBuffer == EGL_SINGLE_BUFFER)
+ gsurf->stvis.render_buffer = ST_ATTACHMENT_FRONT_LEFT;
+
+ gsurf->stfbi = egl_g3d_create_st_framebuffer(&gsurf->base);
+ if (!gsurf->stfbi) {
+ nsurf->destroy(nsurf);
+ FREE(gsurf);
+ return NULL;
+ }
+
+ nsurf->user_data = &gsurf->base;
+ gsurf->native = nsurf;
+
+ return &gsurf->base;
+}
+
+static _EGLSurface *
+egl_g3d_create_window_surface(_EGLDriver *drv, _EGLDisplay *dpy,
+ _EGLConfig *conf, EGLNativeWindowType win,
+ const EGLint *attribs)
+{
+ struct egl_g3d_create_surface_arg arg;
+
+ memset(&arg, 0, sizeof(arg));
+ arg.type = EGL_WINDOW_BIT;
+ arg.u.win = win;
+
+ return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs);
+}
+
+static _EGLSurface *
+egl_g3d_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *dpy,
+ _EGLConfig *conf, EGLNativePixmapType pix,
+ const EGLint *attribs)
+{
+ struct egl_g3d_create_surface_arg arg;
+
+ memset(&arg, 0, sizeof(arg));
+ arg.type = EGL_PIXMAP_BIT;
+ arg.u.pix = pix;
+
+ return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs);
+}
+
+static struct egl_g3d_surface *
+create_pbuffer_surface(_EGLDisplay *dpy, _EGLConfig *conf,
+ const EGLint *attribs, const char *func)
+{
+ struct egl_g3d_config *gconf = egl_g3d_config(conf);
+ struct egl_g3d_surface *gsurf;
+
+ gsurf = CALLOC_STRUCT(egl_g3d_surface);
+ if (!gsurf) {
+ _eglError(EGL_BAD_ALLOC, func);
+ return NULL;
+ }
+
+ if (!_eglInitSurface(&gsurf->base, dpy, EGL_PBUFFER_BIT, conf, attribs)) {
+ FREE(gsurf);
+ return NULL;
+ }
+
+ gsurf->stvis = gconf->stvis;
+
+ gsurf->stfbi = egl_g3d_create_st_framebuffer(&gsurf->base);
+ if (!gsurf->stfbi) {
+ FREE(gsurf);
+ return NULL;
+ }
+
+ return gsurf;
+}
+
+static _EGLSurface *
+egl_g3d_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *dpy,
+ _EGLConfig *conf, const EGLint *attribs)
+{
+ struct egl_g3d_surface *gsurf;
+ struct pipe_resource *ptex = NULL;
+
+ gsurf = create_pbuffer_surface(dpy, conf, attribs,
+ "eglCreatePbufferSurface");
+ if (!gsurf)
+ return NULL;
+
+ gsurf->client_buffer_type = EGL_NONE;
+
+ if (!gsurf->stfbi->validate(gsurf->stfbi,
+ &gsurf->stvis.render_buffer, 1, &ptex)) {
+ egl_g3d_destroy_st_framebuffer(gsurf->stfbi);
+ FREE(gsurf);
+ return NULL;
+ }
+
+ return &gsurf->base;
+}
+
+static _EGLSurface *
+egl_g3d_create_pbuffer_from_client_buffer(_EGLDriver *drv, _EGLDisplay *dpy,
+ EGLenum buftype,
+ EGLClientBuffer buffer,
+ _EGLConfig *conf,
+ const EGLint *attribs)
+{
+ struct egl_g3d_surface *gsurf;
+ struct pipe_resource *ptex = NULL;
+ EGLint pbuffer_attribs[32];
+ EGLint count, i;
+
+ switch (buftype) {
+ case EGL_OPENVG_IMAGE:
+ break;
+ default:
+ _eglError(EGL_BAD_PARAMETER, "eglCreatePbufferFromClientBuffer");
+ return NULL;
+ break;
+ }
+
+ /* parse the attributes first */
+ count = 0;
+ for (i = 0; attribs && attribs[i] != EGL_NONE; i++) {
+ EGLint attr = attribs[i++];
+ EGLint val = attribs[i];
+ EGLint err = EGL_SUCCESS;
+
+ switch (attr) {
+ case EGL_TEXTURE_FORMAT:
+ case EGL_TEXTURE_TARGET:
+ case EGL_MIPMAP_TEXTURE:
+ pbuffer_attribs[count++] = attr;
+ pbuffer_attribs[count++] = val;
+ break;
+ default:
+ err = EGL_BAD_ATTRIBUTE;
+ break;
+ }
+ /* bail out */
+ if (err != EGL_SUCCESS) {
+ _eglError(err, "eglCreatePbufferFromClientBuffer");
+ return NULL;
+ }
+ }
+
+ pbuffer_attribs[count++] = EGL_NONE;
+
+ gsurf = create_pbuffer_surface(dpy, conf, pbuffer_attribs,
+ "eglCreatePbufferFromClientBuffer");
+ if (!gsurf)
+ return NULL;
+
+ gsurf->client_buffer_type = buftype;
+ gsurf->client_buffer = buffer;
+
+ if (!gsurf->stfbi->validate(gsurf->stfbi,
+ &gsurf->stvis.render_buffer, 1, &ptex)) {
+ egl_g3d_destroy_st_framebuffer(gsurf->stfbi);
+ FREE(gsurf);
+ return NULL;
+ }
+
+ return &gsurf->base;
+}
+
+/**
+ * Destroy a surface.
+ */
+static void
+destroy_surface(_EGLDisplay *dpy, _EGLSurface *surf)
+{
+ struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
+
+ /* FIXME a surface might live longer than its display */
+ if (!dpy->Initialized)
+ _eglLog(_EGL_FATAL, "destroy a surface with an unitialized display");
+
+ pipe_resource_reference(&gsurf->render_texture, NULL);
+ egl_g3d_destroy_st_framebuffer(gsurf->stfbi);
+ if (gsurf->native)
+ gsurf->native->destroy(gsurf->native);
+ FREE(gsurf);
+}
+
+static EGLBoolean
+egl_g3d_destroy_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
+{
+ if (!_eglIsSurfaceBound(surf))
+ destroy_surface(dpy, surf);
+ return EGL_TRUE;
+}
+
+static EGLBoolean
+egl_g3d_make_current(_EGLDriver *drv, _EGLDisplay *dpy,
+ _EGLSurface *draw, _EGLSurface *read, _EGLContext *ctx)
+{
+ struct egl_g3d_context *gctx = egl_g3d_context(ctx);
+ struct egl_g3d_surface *gdraw = egl_g3d_surface(draw);
+ struct egl_g3d_surface *gread = egl_g3d_surface(read);
+ struct egl_g3d_context *old_gctx;
+ EGLBoolean ok = EGL_TRUE;
+
+ /* bind the new context and return the "orphaned" one */
+ if (!_eglBindContext(&ctx, &draw, &read))
+ return EGL_FALSE;
+ old_gctx = egl_g3d_context(ctx);
+
+ if (old_gctx) {
+ /* flush old context */
+ old_gctx->stctxi->flush(old_gctx->stctxi,
+ PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL);
+ }
+
+ if (gctx) {
+ ok = gctx->stapi->make_current(gctx->stapi, gctx->stctxi,
+ (gdraw) ? gdraw->stfbi : NULL, (gread) ? gread->stfbi : NULL);
+ if (ok) {
+ gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, gdraw->stfbi);
+ if (gread != gdraw) {
+ gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi,
+ gread->stfbi);
+ }
+
+ if (gdraw->base.Type == EGL_WINDOW_BIT) {
+ gctx->base.WindowRenderBuffer =
+ (gdraw->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT) ?
+ EGL_SINGLE_BUFFER : EGL_BACK_BUFFER;
+ }
+ }
+ }
+ else if (old_gctx) {
+ ok = old_gctx->stapi->make_current(old_gctx->stapi, NULL, NULL, NULL);
+ old_gctx->base.WindowRenderBuffer = EGL_NONE;
+ }
+
+ if (ctx && !_eglIsContextLinked(ctx))
+ destroy_context(dpy, ctx);
+ if (draw && !_eglIsSurfaceLinked(draw))
+ destroy_surface(dpy, draw);
+ if (read && read != draw && !_eglIsSurfaceLinked(read))
+ destroy_surface(dpy, read);
+
+ return ok;
+}
+
+static EGLBoolean
+egl_g3d_swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
+{
+ struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
+ _EGLContext *ctx = _eglGetCurrentContext();
+ struct egl_g3d_context *gctx = NULL;
+
+ /* no-op for pixmap or pbuffer surface */
+ if (gsurf->base.Type == EGL_PIXMAP_BIT ||
+ gsurf->base.Type == EGL_PBUFFER_BIT)
+ return EGL_TRUE;
+
+ /* or when the surface is single-buffered */
+ if (gsurf->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT)
+ return EGL_TRUE;
+
+ if (ctx && ctx->DrawSurface == surf)
+ gctx = egl_g3d_context(ctx);
+
+ /* flush if the surface is current */
+ if (gctx) {
+ gctx->stctxi->flush(gctx->stctxi,
+ PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL);
+ }
+
+ return gsurf->native->swap_buffers(gsurf->native);
+}
+
+/**
+ * Get the pipe surface of the given attachment of the native surface.
+ */
+static struct pipe_resource *
+get_pipe_resource(struct native_display *ndpy, struct native_surface *nsurf,
+ enum native_attachment natt)
+{
+ struct pipe_resource *textures[NUM_NATIVE_ATTACHMENTS];
+
+ textures[natt] = NULL;
+ nsurf->validate(nsurf, 1 << natt, NULL, textures, NULL, NULL);
+
+ return textures[natt];
+}
+
+static EGLBoolean
+egl_g3d_copy_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
+ EGLNativePixmapType target)
+{
+ struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
+ struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
+ _EGLContext *ctx = _eglGetCurrentContext();
+ struct egl_g3d_config *gconf;
+ struct native_surface *nsurf;
+ struct pipe_resource *ptex;
+
+ if (!gsurf->render_texture)
+ return EGL_TRUE;
+
+ gconf = egl_g3d_config(egl_g3d_find_pixmap_config(dpy, target));
+ if (!gconf)
+ return _eglError(EGL_BAD_NATIVE_PIXMAP, "eglCopyBuffers");
+
+ nsurf = gdpy->native->create_pixmap_surface(gdpy->native,
+ target, gconf->native);
+ if (!nsurf)
+ return _eglError(EGL_BAD_NATIVE_PIXMAP, "eglCopyBuffers");
+
+ /* flush if the surface is current */
+ if (ctx && ctx->DrawSurface == &gsurf->base) {
+ struct egl_g3d_context *gctx = egl_g3d_context(ctx);
+ gctx->stctxi->flush(gctx->stctxi,
+ PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL);
+ }
+
+ /* create a pipe context to copy surfaces */
+ if (!gdpy->pipe) {
+ gdpy->pipe =
+ gdpy->native->screen->context_create(gdpy->native->screen, NULL);
+ if (!gdpy->pipe)
+ return EGL_FALSE;
+ }
+
+ ptex = get_pipe_resource(gdpy->native, nsurf, NATIVE_ATTACHMENT_FRONT_LEFT);
+ if (ptex) {
+ struct pipe_resource *psrc = gsurf->render_texture;
+ struct pipe_subresource subsrc, subdst;
+ subsrc.face = 0;
+ subsrc.level = 0;
+ subdst.face = 0;
+ subdst.level = 0;
+
+ if (psrc) {
+ gdpy->pipe->resource_copy_region(gdpy->pipe, ptex, subdst, 0, 0, 0,
+ gsurf->render_texture, subsrc, 0, 0, 0, ptex->width0, ptex->height0);
+
+ nsurf->flush_frontbuffer(nsurf);
+ }
+
+ pipe_resource_reference(&ptex, NULL);
+ }
+
+ nsurf->destroy(nsurf);
+
+ return EGL_TRUE;
+}
+
+static EGLBoolean
+egl_g3d_wait_client(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
+{
+ struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
+ struct egl_g3d_context *gctx = egl_g3d_context(ctx);
+ struct pipe_screen *screen = gdpy->native->screen;
+ struct pipe_fence_handle *fence = NULL;
+
+ gctx->stctxi->flush(gctx->stctxi,
+ PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, &fence);
+ screen->fence_finish(screen, fence, 0);
+ screen->fence_reference(screen, &fence, NULL);
+
+ return EGL_TRUE;
+}
+
+static EGLBoolean
+egl_g3d_wait_native(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine)
+{
+ _EGLContext *ctx = _eglGetCurrentContext();
+
+ if (engine != EGL_CORE_NATIVE_ENGINE)
+ return _eglError(EGL_BAD_PARAMETER, "eglWaitNative");
+
+ if (ctx && ctx->DrawSurface) {
+ struct egl_g3d_surface *gsurf = egl_g3d_surface(ctx->DrawSurface);
+
+ if (gsurf->native)
+ gsurf->native->wait(gsurf->native);
+ }
+
+ return EGL_TRUE;
+}
+
+static EGLBoolean
+egl_g3d_bind_tex_image(_EGLDriver *drv, _EGLDisplay *dpy,
+ _EGLSurface *surf, EGLint buffer)
+{
+ struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
+ _EGLContext *es1 = _eglGetAPIContext(EGL_OPENGL_ES_API);
+ struct egl_g3d_context *gctx;
+ enum pipe_format internal_format;
+ enum st_texture_type target;
+
+ if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT)
+ return _eglError(EGL_BAD_SURFACE, "eglBindTexImage");
+ if (buffer != EGL_BACK_BUFFER)
+ return _eglError(EGL_BAD_PARAMETER, "eglBindTexImage");
+ if (gsurf->base.BoundToTexture)
+ return _eglError(EGL_BAD_ACCESS, "eglBindTexImage");
+
+ switch (gsurf->base.TextureFormat) {
+ case EGL_TEXTURE_RGB:
+ internal_format = PIPE_FORMAT_R8G8B8_UNORM;
+ break;
+ case EGL_TEXTURE_RGBA:
+ internal_format = PIPE_FORMAT_B8G8R8A8_UNORM;
+ break;
+ default:
+ return _eglError(EGL_BAD_MATCH, "eglBindTexImage");
+ }
+
+ switch (gsurf->base.TextureTarget) {
+ case EGL_TEXTURE_2D:
+ target = ST_TEXTURE_2D;
+ break;
+ default:
+ return _eglError(EGL_BAD_MATCH, "eglBindTexImage");
+ }
+
+ if (!es1)
+ return EGL_TRUE;
+ if (!gsurf->render_texture)
+ return EGL_FALSE;
+
+ /* flush properly if the surface is bound */
+ if (gsurf->base.CurrentContext) {
+ gctx = egl_g3d_context(gsurf->base.CurrentContext);
+ gctx->stctxi->flush(gctx->stctxi,
+ PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL);
+ }
+
+ gctx = egl_g3d_context(es1);
+ if (gctx->stctxi->teximage) {
+ if (!gctx->stctxi->teximage(gctx->stctxi, target,
+ gsurf->base.MipmapLevel, internal_format,
+ gsurf->render_texture, gsurf->base.MipmapTexture))
+ return EGL_FALSE;
+ gsurf->base.BoundToTexture = EGL_TRUE;
+ }
+
+ return EGL_TRUE;
+}
+
+static EGLBoolean
+egl_g3d_release_tex_image(_EGLDriver *drv, _EGLDisplay *dpy,
+ _EGLSurface *surf, EGLint buffer)
+{
+ struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
+
+ if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT ||
+ !gsurf->base.BoundToTexture)
+ return _eglError(EGL_BAD_SURFACE, "eglReleaseTexImage");
+ if (buffer != EGL_BACK_BUFFER)
+ return _eglError(EGL_BAD_PARAMETER, "eglReleaseTexImage");
+
+ if (gsurf->render_texture) {
+ _EGLContext *ctx = _eglGetAPIContext(EGL_OPENGL_ES_API);
+ struct egl_g3d_context *gctx = egl_g3d_context(ctx);
+
+ /* what if the context the surface binds to is no longer current? */
+ if (gctx) {
+ gctx->stctxi->teximage(gctx->stctxi, ST_TEXTURE_2D,
+ gsurf->base.MipmapLevel, PIPE_FORMAT_NONE, NULL, FALSE);
+ }
+ }
+
+ gsurf->base.BoundToTexture = EGL_FALSE;
+
+ return EGL_TRUE;
+}
+
+#ifdef EGL_MESA_screen_surface
+
+static _EGLSurface *
+egl_g3d_create_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy,
+ _EGLConfig *conf, const EGLint *attribs)
+{
+ struct egl_g3d_create_surface_arg arg;
+
+ memset(&arg, 0, sizeof(arg));
+ arg.type = EGL_SCREEN_BIT_MESA;
+
+ return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs);
+}
+
+static EGLBoolean
+egl_g3d_show_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy,
+ _EGLScreen *scr, _EGLSurface *surf,
+ _EGLMode *mode)
+{
+ struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
+ struct egl_g3d_screen *gscr = egl_g3d_screen(scr);
+ struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
+ struct native_surface *nsurf;
+ const struct native_mode *nmode;
+ EGLBoolean changed;
+
+ if (gsurf) {
+ EGLint idx;
+
+ if (!mode)
+ return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA");
+ if (gsurf->base.Type != EGL_SCREEN_BIT_MESA)
+ return _eglError(EGL_BAD_SURFACE, "eglShowScreenSurfaceMESA");
+ if (gsurf->base.Width < mode->Width || gsurf->base.Height < mode->Height)
+ return _eglError(EGL_BAD_MATCH,
+ "eglShowSurfaceMESA(surface smaller than mode size)");
+
+ /* find the index of the mode */
+ for (idx = 0; idx < gscr->base.NumModes; idx++)
+ if (mode == &gscr->base.Modes[idx])
+ break;
+ if (idx >= gscr->base.NumModes) {
+ return _eglError(EGL_BAD_MODE_MESA,
+ "eglShowSurfaceMESA(unknown mode)");
+ }
+
+ nsurf = gsurf->native;
+ nmode = gscr->native_modes[idx];
+ }
+ else {
+ if (mode)
+ return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA");
+
+ /* disable the screen */
+ nsurf = NULL;
+ nmode = NULL;
+ }
+
+ /* TODO surface panning by CRTC choosing */
+ changed = gdpy->native->modeset->program(gdpy->native, 0, nsurf,
+ gscr->base.OriginX, gscr->base.OriginY, &gscr->native, 1, nmode);
+ if (changed) {
+ gscr->base.CurrentSurface = &gsurf->base;
+ gscr->base.CurrentMode = mode;
+ }
+
+ return changed;
+}
+
+#endif /* EGL_MESA_screen_surface */
+
+/**
+ * Find a config that supports the pixmap.
+ */
+_EGLConfig *
+egl_g3d_find_pixmap_config(_EGLDisplay *dpy, EGLNativePixmapType pix)
+{
+ struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
+ struct egl_g3d_config *gconf;
+ EGLint i;
+
+ for (i = 0; i < dpy->NumConfigs; i++) {
+ gconf = egl_g3d_config(dpy->Configs[i]);
+ if (gdpy->native->is_pixmap_supported(gdpy->native, pix, gconf->native))
+ break;
+ }
+
+ return (i < dpy->NumConfigs) ? &gconf->base : NULL;
+}
+
+void
+egl_g3d_init_driver_api(_EGLDriver *drv)
+{
+ _eglInitDriverFallbacks(drv);
+
+ drv->API.CreateContext = egl_g3d_create_context;
+ drv->API.DestroyContext = egl_g3d_destroy_context;
+ drv->API.CreateWindowSurface = egl_g3d_create_window_surface;
+ drv->API.CreatePixmapSurface = egl_g3d_create_pixmap_surface;
+ drv->API.CreatePbufferSurface = egl_g3d_create_pbuffer_surface;
+ drv->API.CreatePbufferFromClientBuffer = egl_g3d_create_pbuffer_from_client_buffer;
+ drv->API.DestroySurface = egl_g3d_destroy_surface;
+ drv->API.MakeCurrent = egl_g3d_make_current;
+ drv->API.SwapBuffers = egl_g3d_swap_buffers;
+ drv->API.CopyBuffers = egl_g3d_copy_buffers;
+ drv->API.WaitClient = egl_g3d_wait_client;
+ drv->API.WaitNative = egl_g3d_wait_native;
+
+ drv->API.BindTexImage = egl_g3d_bind_tex_image;
+ drv->API.ReleaseTexImage = egl_g3d_release_tex_image;
+
+ drv->API.CreateImageKHR = egl_g3d_create_image;
+ drv->API.DestroyImageKHR = egl_g3d_destroy_image;
+
+#ifdef EGL_MESA_screen_surface
+ drv->API.CreateScreenSurfaceMESA = egl_g3d_create_screen_surface;
+ drv->API.ShowScreenSurfaceMESA = egl_g3d_show_screen_surface;
+#endif
+}
diff --git a/src/gallium/state_trackers/egl/common/egl_g3d_api.h b/src/gallium/state_trackers/egl/common/egl_g3d_api.h
new file mode 100644
index 0000000000..d5196c12fe
--- /dev/null
+++ b/src/gallium/state_trackers/egl/common/egl_g3d_api.h
@@ -0,0 +1,37 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.9
+ *
+ * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org>
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _EGL_G3D_API_H_
+#define _EGL_G3D_API_H_
+
+#include "egl_g3d.h"
+
+void
+egl_g3d_init_driver_api(_EGLDriver *drv);
+
+_EGLConfig *
+egl_g3d_find_pixmap_config(_EGLDisplay *dpy, EGLNativePixmapType pix);
+
+#endif /* _EGL_G3D_API_H_ */
diff --git a/src/gallium/state_trackers/egl/common/egl_g3d_image.c b/src/gallium/state_trackers/egl/common/egl_g3d_image.c
new file mode 100644
index 0000000000..b1fe30a776
--- /dev/null
+++ b/src/gallium/state_trackers/egl/common/egl_g3d_image.c
@@ -0,0 +1,136 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.8
+ *
+ * Copyright (C) 2010 LunarG Inc.
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Chia-I Wu <olv@lunarg.com>
+ */
+
+#include "pipe/p_screen.h"
+#include "util/u_memory.h"
+#include "util/u_rect.h"
+#include "util/u_inlines.h"
+#include "eglcurrent.h"
+
+#include "native.h"
+#include "egl_g3d.h"
+#include "egl_g3d_api.h"
+#include "egl_g3d_image.h"
+
+/**
+ * Reference and return the front left buffer of the native pixmap.
+ */
+static struct pipe_resource *
+egl_g3d_reference_native_pixmap(_EGLDisplay *dpy, EGLNativePixmapType pix)
+{
+ struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
+ struct egl_g3d_config *gconf;
+ struct native_surface *nsurf;
+ struct pipe_resource *textures[NUM_NATIVE_ATTACHMENTS];
+ enum native_attachment natt;
+
+ gconf = egl_g3d_config(egl_g3d_find_pixmap_config(dpy, pix));
+ if (!gconf)
+ return NULL;
+
+ nsurf = gdpy->native->create_pixmap_surface(gdpy->native,
+ pix, gconf->native);
+ if (!nsurf)
+ return NULL;
+
+ natt = NATIVE_ATTACHMENT_FRONT_LEFT;
+ if (!nsurf->validate(nsurf, 1 << natt, NULL, textures, NULL, NULL))
+ textures[natt] = NULL;
+
+ nsurf->destroy(nsurf);
+
+ return textures[natt];
+}
+
+_EGLImage *
+egl_g3d_create_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx,
+ EGLenum target, EGLClientBuffer buffer,
+ const EGLint *attribs)
+{
+ struct pipe_resource *ptex;
+ struct egl_g3d_image *gimg;
+ unsigned face = 0, level = 0, zslice = 0;
+
+ gimg = CALLOC_STRUCT(egl_g3d_image);
+ if (!gimg) {
+ _eglError(EGL_BAD_ALLOC, "eglCreatePbufferSurface");
+ return NULL;
+ }
+
+ if (!_eglInitImage(&gimg->base, dpy, attribs)) {
+ FREE(gimg);
+ return NULL;
+ }
+
+ switch (target) {
+ case EGL_NATIVE_PIXMAP_KHR:
+ ptex = egl_g3d_reference_native_pixmap(dpy,
+ (EGLNativePixmapType) buffer);
+ break;
+ default:
+ ptex = NULL;
+ break;
+ }
+
+ if (!ptex) {
+ FREE(gimg);
+ return NULL;
+ }
+
+ if (level > ptex->last_level) {
+ _eglError(EGL_BAD_MATCH, "eglCreateEGLImageKHR");
+ pipe_resource_reference(&gimg->texture, NULL);
+ FREE(gimg);
+ return NULL;
+ }
+ if (zslice > ptex->depth0) {
+ _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR");
+ pipe_resource_reference(&gimg->texture, NULL);
+ FREE(gimg);
+ return NULL;
+ }
+
+ /* transfer the ownership to the image */
+ gimg->texture = ptex;
+ gimg->face = face;
+ gimg->level = level;
+ gimg->zslice = zslice;
+
+ return &gimg->base;
+}
+
+EGLBoolean
+egl_g3d_destroy_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLImage *img)
+{
+ struct egl_g3d_image *gimg = egl_g3d_image(img);
+
+ pipe_resource_reference(&gimg->texture, NULL);
+ FREE(gimg);
+
+ return EGL_TRUE;
+}
diff --git a/src/gallium/state_trackers/egl/common/egl_g3d_image.h b/src/gallium/state_trackers/egl/common/egl_g3d_image.h
new file mode 100644
index 0000000000..adda933371
--- /dev/null
+++ b/src/gallium/state_trackers/egl/common/egl_g3d_image.h
@@ -0,0 +1,42 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.8
+ *
+ * Copyright (C) 2010 LunarG Inc.
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Chia-I Wu <olv@lunarg.com>
+ */
+
+#ifndef _EGL_G3D_IMAGE_H_
+#define _EGL_G3D_IMAGE_H_
+
+#include "egl_g3d.h"
+
+_EGLImage *
+egl_g3d_create_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx,
+ EGLenum target, EGLClientBuffer buffer,
+ const EGLint *attribs);
+
+EGLBoolean
+egl_g3d_destroy_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLImage *image);
+
+#endif /* _EGL_G3D_IMAGE_H_ */
diff --git a/src/gallium/state_trackers/egl/common/egl_g3d_st.c b/src/gallium/state_trackers/egl/common/egl_g3d_st.c
new file mode 100644
index 0000000000..683b74f62b
--- /dev/null
+++ b/src/gallium/state_trackers/egl/common/egl_g3d_st.c
@@ -0,0 +1,479 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.9
+ *
+ * Copyright (C) 2010 LunarG Inc.
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Chia-I Wu <olv@lunarg.com>
+ */
+
+#include "util/u_memory.h"
+#include "util/u_string.h"
+#include "util/u_inlines.h"
+#include "util/u_pointer.h"
+#include "util/u_dl.h"
+#include "egldriver.h"
+#include "eglimage.h"
+#include "eglmutex.h"
+
+#include "egl_g3d.h"
+#include "egl_g3d_st.h"
+
+struct egl_g3d_st_manager {
+ struct st_manager base;
+ _EGLDisplay *display;
+};
+
+static INLINE struct egl_g3d_st_manager *
+egl_g3d_st_manager(struct st_manager *smapi)
+{
+ return (struct egl_g3d_st_manager *) smapi;
+}
+
+static struct egl_g3d_st_module {
+ const char *filename;
+ struct util_dl_library *lib;
+ struct st_api *stapi;
+} egl_g3d_st_modules[ST_API_COUNT];
+
+static EGLBoolean
+egl_g3d_search_path_callback(const char *dir, size_t len, void *callback_data)
+{
+ struct egl_g3d_st_module *stmod =
+ (struct egl_g3d_st_module *) callback_data;
+ char path[1024];
+ int ret;
+
+ if (!len) {
+ stmod->lib = util_dl_open(stmod->filename);
+ return !(stmod->lib);
+ }
+
+ ret = util_snprintf(path, sizeof(path),
+ "%.*s/%s", len, dir, stmod->filename);
+ if (ret > 0 && ret < sizeof(path))
+ stmod->lib = util_dl_open(path);
+
+ return !(stmod->lib);
+}
+
+static boolean
+egl_g3d_load_st_module(struct egl_g3d_st_module *stmod,
+ const char *filename, const char *procname)
+{
+ struct st_api *(*create_api)(void);
+
+ stmod->filename = filename;
+ if (stmod->filename)
+ _eglSearchPathForEach(egl_g3d_search_path_callback, (void *) stmod);
+ else
+ stmod->lib = util_dl_open(NULL);
+
+ if (stmod->lib) {
+ create_api = (struct st_api *(*)(void))
+ util_dl_get_proc_address(stmod->lib, procname);
+ if (create_api)
+ stmod->stapi = create_api();
+
+ if (!stmod->stapi) {
+ util_dl_close(stmod->lib);
+ stmod->lib = NULL;
+ }
+ }
+
+ if (stmod->stapi) {
+ return TRUE;
+ }
+ else {
+ stmod->filename = NULL;
+ return FALSE;
+ }
+}
+
+#ifdef PIPE_OS_WINDOWS
+#define ST_MODULE_SUFFIX ".dll"
+#else
+#define ST_MODULE_SUFFIX ".so"
+#endif
+
+void
+egl_g3d_init_st_apis(struct st_api *stapis[ST_API_COUNT])
+{
+ const char *skip_checks[ST_API_COUNT], *symbols[ST_API_COUNT];
+ const char *filenames[ST_API_COUNT][4];
+ struct util_dl_library *self;
+ int num_needed = 0, api;
+
+ self = util_dl_open(NULL);
+
+ /* collect the necessary data for loading modules */
+ for (api = 0; api < ST_API_COUNT; api++) {
+ int count = 0;
+
+ switch (api) {
+ case ST_API_OPENGL:
+ skip_checks[api] = "glColor4d";
+ symbols[api] = ST_CREATE_OPENGL_SYMBOL;
+ filenames[api][count++] = "api_GL" ST_MODULE_SUFFIX;
+ break;
+ case ST_API_OPENGL_ES1:
+ skip_checks[api] = "glColor4x";
+ symbols[api] = ST_CREATE_OPENGL_ES1_SYMBOL;
+ filenames[api][count++] = "api_GLESv1_CM" ST_MODULE_SUFFIX;
+ filenames[api][count++] = "api_GL" ST_MODULE_SUFFIX;
+ break;
+ case ST_API_OPENGL_ES2:
+ skip_checks[api] = "glShaderBinary";
+ symbols[api] = ST_CREATE_OPENGL_ES2_SYMBOL;
+ filenames[api][count++] = "api_GLESv2" ST_MODULE_SUFFIX;
+ filenames[api][count++] = "api_GL" ST_MODULE_SUFFIX;
+ break;
+ case ST_API_OPENVG:
+ skip_checks[api] = "vgClear";
+ symbols[api] = ST_CREATE_OPENVG_SYMBOL;
+ filenames[api][count++]= "api_OpenVG" ST_MODULE_SUFFIX;
+ break;
+ default:
+ assert(!"Unknown API Type\n");
+ skip_checks[api] = NULL;
+ symbols[api] = NULL;
+ break;
+ }
+ filenames[api][count++]= NULL;
+ assert(count < Elements(filenames[api]));
+
+ /* heuristicically decide if the module is needed */
+ if (!self || !skip_checks[api] ||
+ util_dl_get_proc_address(self, skip_checks[api])) {
+ /* unset so the module is not skipped */
+ skip_checks[api] = NULL;
+ num_needed++;
+ }
+ }
+ /* mark all moudles needed if we wrongly decided that none is needed */
+ if (!num_needed)
+ memset(skip_checks, 0, sizeof(skip_checks));
+
+ if (self)
+ util_dl_close(self);
+
+ for (api = 0; api < ST_API_COUNT; api++) {
+ struct egl_g3d_st_module *stmod = &egl_g3d_st_modules[api];
+ const char **p;
+
+ /* skip the module */
+ if (skip_checks[api])
+ continue;
+
+ /* try all filenames, including NULL */
+ for (p = filenames[api]; *p; p++) {
+ if (egl_g3d_load_st_module(stmod, *p, symbols[api]))
+ break;
+ }
+ if (!stmod->stapi)
+ egl_g3d_load_st_module(stmod, NULL, symbols[api]);
+
+ stapis[api] = stmod->stapi;
+ }
+}
+
+void
+egl_g3d_destroy_st_apis(void)
+{
+ int api;
+
+ for (api = 0; api < ST_API_COUNT; api++) {
+ struct egl_g3d_st_module *stmod = &egl_g3d_st_modules[api];
+
+ if (stmod->stapi) {
+ stmod->stapi->destroy(stmod->stapi);
+ stmod->stapi = NULL;
+ }
+ if (stmod->lib) {
+ util_dl_close(stmod->lib);
+ stmod->lib = NULL;
+ }
+ stmod->filename = NULL;
+ }
+}
+
+static boolean
+egl_g3d_st_manager_get_egl_image(struct st_manager *smapi,
+ struct st_context_iface *stctx,
+ void *egl_image,
+ struct st_egl_image *out)
+{
+ struct egl_g3d_st_manager *gsmapi = egl_g3d_st_manager(smapi);
+ EGLImageKHR handle = (EGLImageKHR) egl_image;
+ _EGLImage *img;
+ struct egl_g3d_image *gimg;
+
+ /* this is called from state trackers */
+ _eglLockMutex(&gsmapi->display->Mutex);
+
+ img = _eglLookupImage(handle, gsmapi->display);
+ if (!img) {
+ _eglUnlockMutex(&gsmapi->display->Mutex);
+ return FALSE;
+ }
+
+ gimg = egl_g3d_image(img);
+
+ out->texture = NULL;
+ pipe_resource_reference(&out->texture, gimg->texture);
+ out->face = gimg->face;
+ out->level = gimg->level;
+ out->zslice = gimg->zslice;
+
+ _eglUnlockMutex(&gsmapi->display->Mutex);
+
+ return TRUE;
+}
+
+static int
+egl_g3d_st_manager_get_param(struct st_manager *smapi,
+ enum st_manager_param param)
+{
+ return 0;
+}
+
+struct st_manager *
+egl_g3d_create_st_manager(_EGLDisplay *dpy)
+{
+ struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
+ struct egl_g3d_st_manager *gsmapi;
+
+ gsmapi = CALLOC_STRUCT(egl_g3d_st_manager);
+ if (gsmapi) {
+ gsmapi->display = dpy;
+
+ gsmapi->base.screen = gdpy->native->screen;
+ gsmapi->base.get_egl_image = egl_g3d_st_manager_get_egl_image;
+ gsmapi->base.get_param = egl_g3d_st_manager_get_param;
+ }
+
+ return &gsmapi->base;;
+}
+
+void
+egl_g3d_destroy_st_manager(struct st_manager *smapi)
+{
+ struct egl_g3d_st_manager *gsmapi = egl_g3d_st_manager(smapi);
+ FREE(gsmapi);
+}
+
+static boolean
+egl_g3d_st_framebuffer_flush_front_pbuffer(struct st_framebuffer_iface *stfbi,
+ enum st_attachment_type statt)
+{
+ return TRUE;
+}
+
+static void
+pbuffer_reference_openvg_image(struct egl_g3d_surface *gsurf)
+{
+ /* TODO */
+}
+
+static void
+pbuffer_allocate_render_texture(struct egl_g3d_surface *gsurf)
+{
+ struct egl_g3d_display *gdpy =
+ egl_g3d_display(gsurf->base.Resource.Display);
+ struct pipe_screen *screen = gdpy->native->screen;
+ struct pipe_resource templ, *ptex;
+
+ memset(&templ, 0, sizeof(templ));
+ templ.target = PIPE_TEXTURE_2D;
+ templ.last_level = 0;
+ templ.width0 = gsurf->base.Width;
+ templ.height0 = gsurf->base.Height;
+ templ.depth0 = 1;
+ templ.format = gsurf->stvis.color_format;
+ templ.bind = PIPE_BIND_RENDER_TARGET;
+
+ ptex = screen->resource_create(screen, &templ);
+ gsurf->render_texture = ptex;
+}
+
+static boolean
+egl_g3d_st_framebuffer_validate_pbuffer(struct st_framebuffer_iface *stfbi,
+ const enum st_attachment_type *statts,
+ unsigned count,
+ struct pipe_resource **out)
+{
+ _EGLSurface *surf = (_EGLSurface *) stfbi->st_manager_private;
+ struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
+ unsigned i;
+
+ for (i = 0; i < count; i++) {
+ out[i] = NULL;
+
+ if (gsurf->stvis.render_buffer != statts[i])
+ continue;
+
+ if (!gsurf->render_texture) {
+ switch (gsurf->client_buffer_type) {
+ case EGL_NONE:
+ pbuffer_allocate_render_texture(gsurf);
+ break;
+ case EGL_OPENVG_IMAGE:
+ pbuffer_reference_openvg_image(gsurf);
+ break;
+ default:
+ break;
+ }
+
+ if (!gsurf->render_texture)
+ return FALSE;
+ }
+
+ pipe_resource_reference(&out[i], gsurf->render_texture);
+ }
+
+ return TRUE;
+}
+
+static boolean
+egl_g3d_st_framebuffer_flush_front(struct st_framebuffer_iface *stfbi,
+ enum st_attachment_type statt)
+{
+ _EGLSurface *surf = (_EGLSurface *) stfbi->st_manager_private;
+ struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
+
+ return gsurf->native->flush_frontbuffer(gsurf->native);
+}
+
+static boolean
+egl_g3d_st_framebuffer_validate(struct st_framebuffer_iface *stfbi,
+ const enum st_attachment_type *statts,
+ unsigned count,
+ struct pipe_resource **out)
+{
+ _EGLSurface *surf = (_EGLSurface *) stfbi->st_manager_private;
+ struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
+ struct pipe_resource *textures[NUM_NATIVE_ATTACHMENTS];
+ uint attachment_mask = 0;
+ unsigned i;
+
+ for (i = 0; i < count; i++) {
+ int natt;
+
+ switch (statts[i]) {
+ case ST_ATTACHMENT_FRONT_LEFT:
+ natt = NATIVE_ATTACHMENT_FRONT_LEFT;
+ break;
+ case ST_ATTACHMENT_BACK_LEFT:
+ natt = NATIVE_ATTACHMENT_BACK_LEFT;
+ break;
+ case ST_ATTACHMENT_FRONT_RIGHT:
+ natt = NATIVE_ATTACHMENT_FRONT_RIGHT;
+ break;
+ case ST_ATTACHMENT_BACK_RIGHT:
+ natt = NATIVE_ATTACHMENT_BACK_RIGHT;
+ break;
+ default:
+ natt = -1;
+ break;
+ }
+
+ if (natt >= 0)
+ attachment_mask |= 1 << natt;
+ }
+
+ if (!gsurf->native->validate(gsurf->native, attachment_mask,
+ &gsurf->sequence_number, textures, &gsurf->base.Width,
+ &gsurf->base.Height))
+ return FALSE;
+
+ for (i = 0; i < count; i++) {
+ struct pipe_resource *tex;
+ int natt;
+
+ switch (statts[i]) {
+ case ST_ATTACHMENT_FRONT_LEFT:
+ natt = NATIVE_ATTACHMENT_FRONT_LEFT;
+ break;
+ case ST_ATTACHMENT_BACK_LEFT:
+ natt = NATIVE_ATTACHMENT_BACK_LEFT;
+ break;
+ case ST_ATTACHMENT_FRONT_RIGHT:
+ natt = NATIVE_ATTACHMENT_FRONT_RIGHT;
+ break;
+ case ST_ATTACHMENT_BACK_RIGHT:
+ natt = NATIVE_ATTACHMENT_BACK_RIGHT;
+ break;
+ default:
+ natt = -1;
+ break;
+ }
+
+ if (natt >= 0) {
+ tex = textures[natt];
+
+ if (statts[i] == stfbi->visual->render_buffer)
+ pipe_resource_reference(&gsurf->render_texture, tex);
+
+ if (attachment_mask & (1 << natt)) {
+ /* transfer the ownership to the caller */
+ out[i] = tex;
+ attachment_mask &= ~(1 << natt);
+ }
+ else {
+ /* the attachment is listed more than once */
+ pipe_resource_reference(&out[i], tex);
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+struct st_framebuffer_iface *
+egl_g3d_create_st_framebuffer(_EGLSurface *surf)
+{
+ struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
+ struct st_framebuffer_iface *stfbi;
+
+ stfbi = CALLOC_STRUCT(st_framebuffer_iface);
+ if (!stfbi)
+ return NULL;
+
+ stfbi->visual = &gsurf->stvis;
+ if (gsurf->base.Type != EGL_PBUFFER_BIT) {
+ stfbi->flush_front = egl_g3d_st_framebuffer_flush_front;
+ stfbi->validate = egl_g3d_st_framebuffer_validate;
+ }
+ else {
+ stfbi->flush_front = egl_g3d_st_framebuffer_flush_front_pbuffer;
+ stfbi->validate = egl_g3d_st_framebuffer_validate_pbuffer;
+ }
+ stfbi->st_manager_private = (void *) &gsurf->base;
+
+ return stfbi;
+}
+
+void
+egl_g3d_destroy_st_framebuffer(struct st_framebuffer_iface *stfbi)
+{
+ FREE(stfbi);
+}
diff --git a/src/gallium/state_trackers/egl/common/egl_g3d_st.h b/src/gallium/state_trackers/egl/common/egl_g3d_st.h
new file mode 100644
index 0000000000..ee53799b02
--- /dev/null
+++ b/src/gallium/state_trackers/egl/common/egl_g3d_st.h
@@ -0,0 +1,83 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.9
+ *
+ * Copyright (C) 2010 LunarG Inc.
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Chia-I Wu <olv@lunarg.com>
+ */
+
+#ifndef _EGL_G3D_ST_H_
+#define _EGL_G3D_ST_H_
+
+#include "pipe/p_compiler.h"
+#include "state_tracker/st_api.h"
+#include "egltypedefs.h"
+
+void
+egl_g3d_init_st_apis(struct st_api *stapis[ST_API_COUNT]);
+
+void
+egl_g3d_destroy_st_apis(void);
+
+struct st_manager *
+egl_g3d_create_st_manager(_EGLDisplay *dpy);
+
+void
+egl_g3d_destroy_st_manager(struct st_manager *smapi);
+
+struct st_framebuffer_iface *
+egl_g3d_create_st_framebuffer(_EGLSurface *surf);
+
+void
+egl_g3d_destroy_st_framebuffer(struct st_framebuffer_iface *stfbi);
+
+/**
+ * Return the EGL_<api>_BIT of the st api.
+ */
+static INLINE int
+egl_g3d_st_api_bit(enum st_api_type api)
+{
+ int bit;
+
+ switch (api) {
+ case ST_API_OPENGL:
+ bit = EGL_OPENGL_BIT;
+ break;
+ case ST_API_OPENGL_ES1:
+ bit = EGL_OPENGL_ES_BIT;
+ break;
+ case ST_API_OPENGL_ES2:
+ bit = EGL_OPENGL_ES2_BIT;
+ break;
+ case ST_API_OPENVG:
+ bit = EGL_OPENVG_BIT;
+ break;
+ default:
+ bit = 0;
+ break;
+ }
+
+ return bit;
+}
+
+#endif /* _EGL_G3D_ST_H_ */
diff --git a/src/gallium/state_trackers/egl/common/native.h b/src/gallium/state_trackers/egl/common/native.h
new file mode 100644
index 0000000000..3f60348c48
--- /dev/null
+++ b/src/gallium/state_trackers/egl/common/native.h
@@ -0,0 +1,217 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.8
+ *
+ * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org>
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _NATIVE_H_
+#define _NATIVE_H_
+
+#include "EGL/egl.h" /* for EGL native types */
+
+#include "pipe/p_compiler.h"
+#include "pipe/p_screen.h"
+#include "pipe/p_context.h"
+#include "pipe/p_state.h"
+
+#include "native_probe.h"
+#include "native_modeset.h"
+
+/**
+ * Only color buffers are listed. The others are allocated privately through,
+ * for example, st_renderbuffer_alloc_storage().
+ */
+enum native_attachment {
+ NATIVE_ATTACHMENT_FRONT_LEFT,
+ NATIVE_ATTACHMENT_BACK_LEFT,
+ NATIVE_ATTACHMENT_FRONT_RIGHT,
+ NATIVE_ATTACHMENT_BACK_RIGHT,
+
+ NUM_NATIVE_ATTACHMENTS
+};
+
+enum native_param_type {
+ /*
+ * Return TRUE if window/pixmap surfaces use the buffers of the native
+ * types.
+ */
+ NATIVE_PARAM_USE_NATIVE_BUFFER
+};
+
+struct native_surface {
+ /**
+ * Available for caller's use.
+ */
+ void *user_data;
+
+ void (*destroy)(struct native_surface *nsurf);
+
+ /**
+ * Swap the front and back buffers so that the back buffer is visible. It
+ * is no-op if the surface is single-buffered. The contents of the back
+ * buffer after swapping may or may not be preserved.
+ */
+ boolean (*swap_buffers)(struct native_surface *nsurf);
+
+ /**
+ * Make the front buffer visible. In some native displays, changes to the
+ * front buffer might not be visible immediately and require manual flush.
+ */
+ boolean (*flush_frontbuffer)(struct native_surface *nsurf);
+
+ /**
+ * Validate the buffers of the surface. textures, if not NULL, points to an
+ * array of size NUM_NATIVE_ATTACHMENTS and the returned textures are owned
+ * by the caller. A sequence number is also returned. The caller can use
+ * it to check if anything has changed since the last call. Any of the
+ * pointers may be NULL and it indicates the caller has no interest in those
+ * values.
+ *
+ * If this function is called multiple times with different attachment
+ * masks, those not listed in the latest call might be destroyed. This
+ * behavior might change in the future.
+ */
+ boolean (*validate)(struct native_surface *nsurf, uint attachment_mask,
+ unsigned int *seq_num, struct pipe_resource **textures,
+ int *width, int *height);
+
+ /**
+ * Wait until all native commands affecting the surface has been executed.
+ */
+ void (*wait)(struct native_surface *nsurf);
+};
+
+/**
+ * Describe a native display config.
+ */
+struct native_config {
+ /* available buffers and their format */
+ uint buffer_mask;
+ enum pipe_format color_format;
+
+ /* supported surface types */
+ boolean window_bit;
+ boolean pixmap_bit;
+ boolean scanout_bit;
+
+ int native_visual_id;
+ int native_visual_type;
+ int level;
+ int samples;
+ boolean slow_config;
+ boolean transparent_rgb;
+ int transparent_rgb_values[3];
+};
+
+/**
+ * A pipe winsys abstracts the OS. A pipe screen abstracts the graphcis
+ * hardware. A native display consists of a pipe winsys, a pipe screen, and
+ * the native display server.
+ */
+struct native_display {
+ /**
+ * The pipe screen of the native display.
+ */
+ struct pipe_screen *screen;
+
+ /**
+ * Available for caller's use.
+ */
+ void *user_data;
+
+ void (*destroy)(struct native_display *ndpy);
+
+ /**
+ * Query the parameters of the native display.
+ *
+ * The return value is defined by the parameter.
+ */
+ int (*get_param)(struct native_display *ndpy,
+ enum native_param_type param);
+
+ /**
+ * Get the supported configs. The configs are owned by the display, but
+ * the returned array should be FREE()ed.
+ */
+ const struct native_config **(*get_configs)(struct native_display *ndpy,
+ int *num_configs);
+
+ /**
+ * Test if a pixmap is supported by the given config. Required unless no
+ * config has pixmap_bit set.
+ *
+ * This function is usually called to find a config that supports a given
+ * pixmap. Thus, it is usually called with the same pixmap in a row.
+ */
+ boolean (*is_pixmap_supported)(struct native_display *ndpy,
+ EGLNativePixmapType pix,
+ const struct native_config *nconf);
+
+
+ /**
+ * Create a window surface. Required unless no config has window_bit set.
+ */
+ struct native_surface *(*create_window_surface)(struct native_display *ndpy,
+ EGLNativeWindowType win,
+ const struct native_config *nconf);
+
+ /**
+ * Create a pixmap surface. Required unless no config has pixmap_bit set.
+ */
+ struct native_surface *(*create_pixmap_surface)(struct native_display *ndpy,
+ EGLNativePixmapType pix,
+ const struct native_config *nconf);
+
+ const struct native_display_modeset *modeset;
+};
+
+/**
+ * The handler for events that a native display may generate. The events are
+ * generated asynchronously and the handler may be called by any thread at any
+ * time.
+ */
+struct native_event_handler {
+ /**
+ * This function is called when a surface needs to be validated.
+ */
+ void (*invalid_surface)(struct native_display *ndpy,
+ struct native_surface *nsurf,
+ unsigned int seq_num);
+};
+
+/**
+ * Test whether an attachment is set in the mask.
+ */
+static INLINE boolean
+native_attachment_mask_test(uint mask, enum native_attachment att)
+{
+ return !!(mask & (1 << att));
+}
+
+const char *
+native_get_name(void);
+
+struct native_display *
+native_create_display(EGLNativeDisplayType dpy,
+ struct native_event_handler *handler);
+
+#endif /* _NATIVE_H_ */
diff --git a/src/gallium/state_trackers/egl/common/native_helper.c b/src/gallium/state_trackers/egl/common/native_helper.c
new file mode 100644
index 0000000000..206817ed66
--- /dev/null
+++ b/src/gallium/state_trackers/egl/common/native_helper.c
@@ -0,0 +1,253 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.9
+ *
+ * Copyright (C) 2010 LunarG Inc.
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Chia-I Wu <olv@lunarg.com>
+ */
+
+#include "util/u_inlines.h"
+#include "util/u_memory.h"
+#include "pipe/p_screen.h"
+#include "pipe/p_context.h"
+#include "pipe/p_state.h"
+#include "softpipe/sp_public.h"
+#include "llvmpipe/lp_public.h"
+#include "target-helpers/wrap_screen.h"
+
+#include "native_helper.h"
+
+struct resource_surface {
+ struct pipe_screen *screen;
+ enum pipe_format format;
+ uint bind;
+
+ struct pipe_resource *resources[NUM_NATIVE_ATTACHMENTS];
+ struct pipe_surface *present_surfaces[NUM_NATIVE_ATTACHMENTS];
+ uint resource_mask;
+ uint width, height;
+};
+
+struct resource_surface *
+resource_surface_create(struct pipe_screen *screen,
+ enum pipe_format format, uint bind)
+{
+ struct resource_surface *rsurf = CALLOC_STRUCT(resource_surface);
+
+ if (rsurf) {
+ rsurf->screen = screen;
+ rsurf->format = format;
+ rsurf->bind = bind;
+ }
+
+ return rsurf;
+}
+
+static void
+resource_surface_free_resources(struct resource_surface *rsurf)
+{
+ if (rsurf->resource_mask) {
+ int i;
+
+ for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) {
+ if (rsurf->present_surfaces[i])
+ pipe_surface_reference(&rsurf->present_surfaces[i], NULL);
+ if (rsurf->resources[i])
+ pipe_resource_reference(&rsurf->resources[i], NULL);
+ }
+ rsurf->resource_mask = 0x0;
+ }
+}
+
+void
+resource_surface_destroy(struct resource_surface *rsurf)
+{
+ resource_surface_free_resources(rsurf);
+ FREE(rsurf);
+}
+
+boolean
+resource_surface_set_size(struct resource_surface *rsurf,
+ uint width, uint height)
+{
+ boolean changed = FALSE;
+
+ if (rsurf->width != width || rsurf->height != height) {
+ resource_surface_free_resources(rsurf);
+ rsurf->width = width;
+ rsurf->height = height;
+ changed = TRUE;
+ }
+
+ return changed;
+}
+
+void
+resource_surface_get_size(struct resource_surface *rsurf,
+ uint *width, uint *height)
+{
+ if (width)
+ *width = rsurf->width;
+ if (height)
+ *height = rsurf->height;
+}
+
+boolean
+resource_surface_add_resources(struct resource_surface *rsurf,
+ uint resource_mask)
+{
+ struct pipe_resource templ;
+ int i;
+
+ resource_mask &= ~rsurf->resource_mask;
+ if (!resource_mask)
+ return TRUE;
+
+ if (!rsurf->width || !rsurf->height)
+ return FALSE;
+
+ memset(&templ, 0, sizeof(templ));
+ templ.target = PIPE_TEXTURE_2D;
+ templ.format = rsurf->format;
+ templ.bind = rsurf->bind;
+ templ.width0 = rsurf->width;
+ templ.height0 = rsurf->height;
+ templ.depth0 = 1;
+
+ for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) {
+ if (resource_mask & (1 <<i)) {
+ assert(!rsurf->resources[i]);
+
+ rsurf->resources[i] =
+ rsurf->screen->resource_create(rsurf->screen, &templ);
+ if (rsurf->resources[i])
+ rsurf->resource_mask |= 1 << i;
+ }
+ }
+
+ return ((rsurf->resource_mask & resource_mask) == resource_mask);
+}
+
+
+void
+resource_surface_get_resources(struct resource_surface *rsurf,
+ struct pipe_resource **resources,
+ uint resource_mask)
+{
+ int i;
+
+ for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) {
+ if (resource_mask & (1 << i)) {
+ resources[i] = NULL;
+ pipe_resource_reference(&resources[i], rsurf->resources[i]);
+ }
+ }
+}
+
+struct pipe_resource *
+resource_surface_get_single_resource(struct resource_surface *rsurf,
+ enum native_attachment which)
+{
+ struct pipe_resource *pres = NULL;
+ pipe_resource_reference(&pres, rsurf->resources[which]);
+ return pres;
+}
+
+static INLINE void
+pointer_swap(const void **p1, const void **p2)
+{
+ const void *tmp = *p1;
+ *p1 = *p2;
+ *p2 = tmp;
+}
+
+void
+resource_surface_swap_buffers(struct resource_surface *rsurf,
+ enum native_attachment buf1,
+ enum native_attachment buf2,
+ boolean only_if_exist)
+{
+ const uint buf1_bit = 1 << buf1;
+ const uint buf2_bit = 1 << buf2;
+ uint mask;
+
+ if (only_if_exist && !(rsurf->resources[buf1] && rsurf->resources[buf2]))
+ return;
+
+ pointer_swap((const void **) &rsurf->resources[buf1],
+ (const void **) &rsurf->resources[buf2]);
+ pointer_swap((const void **) &rsurf->present_surfaces[buf1],
+ (const void **) &rsurf->present_surfaces[buf2]);
+
+ /* swap mask bits */
+ mask = rsurf->resource_mask & ~(buf1_bit | buf2_bit);
+ if (rsurf->resource_mask & buf1_bit)
+ mask |= buf2_bit;
+ if (rsurf->resource_mask & buf2_bit)
+ mask |= buf1_bit;
+
+ rsurf->resource_mask = mask;
+}
+
+boolean
+resource_surface_present(struct resource_surface *rsurf,
+ enum native_attachment which,
+ void *winsys_drawable_handle)
+{
+ struct pipe_resource *pres = rsurf->resources[which];
+ struct pipe_surface *psurf = rsurf->present_surfaces[which];
+
+ if (!pres)
+ return TRUE;
+
+ if (!psurf) {
+ psurf = rsurf->screen->get_tex_surface(rsurf->screen,
+ pres, 0, 0, 0, PIPE_BIND_DISPLAY_TARGET);
+ if (!psurf)
+ return FALSE;
+
+ rsurf->present_surfaces[which] = psurf;
+ }
+
+ assert(psurf->texture == pres);
+
+ rsurf->screen->flush_frontbuffer(rsurf->screen,
+ psurf, winsys_drawable_handle);
+
+ return TRUE;
+}
+
+struct pipe_screen *
+native_create_sw_screen(struct sw_winsys *ws)
+{
+ struct pipe_screen *screen = NULL;
+
+#if defined(GALLIUM_LLVMPIPE)
+ if (!screen && !debug_get_bool_option("GALLIUM_NO_LLVM", FALSE))
+ screen = llvmpipe_create_screen(ws);
+#endif
+ if (!screen)
+ screen = softpipe_create_screen(ws);
+
+ return (screen) ? gallium_wrap_screen(screen) : NULL;
+}
diff --git a/src/gallium/state_trackers/egl/common/native_helper.h b/src/gallium/state_trackers/egl/common/native_helper.h
new file mode 100644
index 0000000000..bdb9629466
--- /dev/null
+++ b/src/gallium/state_trackers/egl/common/native_helper.h
@@ -0,0 +1,74 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.9
+ *
+ * Copyright (C) 2010 LunarG Inc.
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Chia-I Wu <olv@lunarg.com>
+ */
+
+#include "native.h"
+
+struct resource_surface;
+struct sw_winsys;
+
+struct resource_surface *
+resource_surface_create(struct pipe_screen *screen,
+ enum pipe_format format, uint bind);
+
+void
+resource_surface_destroy(struct resource_surface *rsurf);
+
+boolean
+resource_surface_set_size(struct resource_surface *rsurf,
+ uint width, uint height);
+
+void
+resource_surface_get_size(struct resource_surface *rsurf,
+ uint *width, uint *height);
+
+boolean
+resource_surface_add_resources(struct resource_surface *rsurf,
+ uint resource_mask);
+
+void
+resource_surface_get_resources(struct resource_surface *rsurf,
+ struct pipe_resource **resources,
+ uint resource_mask);
+
+struct pipe_resource *
+resource_surface_get_single_resource(struct resource_surface *rsurf,
+ enum native_attachment which);
+
+void
+resource_surface_swap_buffers(struct resource_surface *rsurf,
+ enum native_attachment buf1,
+ enum native_attachment buf2,
+ boolean only_if_exist);
+
+boolean
+resource_surface_present(struct resource_surface *rsurf,
+ enum native_attachment which,
+ void *winsys_drawable_handle);
+
+struct pipe_screen *
+native_create_sw_screen(struct sw_winsys *ws);
diff --git a/src/gallium/state_trackers/egl/common/native_modeset.h b/src/gallium/state_trackers/egl/common/native_modeset.h
new file mode 100644
index 0000000000..dee757b3a8
--- /dev/null
+++ b/src/gallium/state_trackers/egl/common/native_modeset.h
@@ -0,0 +1,88 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.8
+ *
+ * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org>
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _NATIVE_MODESET_H_
+#define _NATIVE_MODESET_H_
+
+#include "pipe/p_compiler.h"
+
+struct native_display;
+struct native_surface;
+struct native_config;
+
+struct native_connector {
+ int dummy;
+};
+
+struct native_mode {
+ const char *desc;
+ int width, height;
+ int refresh_rate;
+};
+
+/**
+ * Mode setting interface of the native display. It exposes the mode setting
+ * capabilities of the underlying graphics hardware.
+ */
+struct native_display_modeset {
+ /**
+ * Get the available physical connectors and the number of CRTCs.
+ */
+ const struct native_connector **(*get_connectors)(struct native_display *ndpy,
+ int *num_connectors,
+ int *num_crtcs);
+
+ /**
+ * Get the current supported modes of a connector. The returned modes may
+ * change every time this function is called and those from previous calls
+ * might become invalid.
+ */
+ const struct native_mode **(*get_modes)(struct native_display *ndpy,
+ const struct native_connector *nconn,
+ int *num_modes);
+
+ /**
+ * Create a scan-out surface. Required unless no config has scanout_bit
+ * set.
+ */
+ struct native_surface *(*create_scanout_surface)(struct native_display *ndpy,
+ const struct native_config *nconf,
+ uint width, uint height);
+
+ /**
+ * Program the CRTC to output the surface to the given connectors with the
+ * given mode. When surface is not given, the CRTC is disabled.
+ *
+ * This interface does not export a way to query capabilities of the CRTCs.
+ * The native display usually needs to dynamically map the index to a CRTC
+ * that supports the given connectors.
+ */
+ boolean (*program)(struct native_display *ndpy, int crtc_idx,
+ struct native_surface *nsurf, uint x, uint y,
+ const struct native_connector **nconns, int num_nconns,
+ const struct native_mode *nmode);
+};
+
+#endif /* _NATIVE_MODESET_H_ */
diff --git a/src/gallium/state_trackers/egl/common/native_probe.h b/src/gallium/state_trackers/egl/common/native_probe.h
new file mode 100644
index 0000000000..aeed9f85dd
--- /dev/null
+++ b/src/gallium/state_trackers/egl/common/native_probe.h
@@ -0,0 +1,68 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.8
+ *
+ * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org>
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _NATIVE_PROBE_H_
+#define _NATIVE_PROBE_H_
+
+#include "EGL/egl.h" /* for EGL native types */
+
+/**
+ * Enumerations for probe results.
+ */
+enum native_probe_result {
+ NATIVE_PROBE_UNKNOWN,
+ NATIVE_PROBE_FALLBACK,
+ NATIVE_PROBE_SUPPORTED,
+ NATIVE_PROBE_EXACT,
+};
+
+/**
+ * A probe object for display probe.
+ */
+struct native_probe {
+ int magic;
+ EGLNativeDisplayType display;
+ void *data;
+
+ void (*destroy)(struct native_probe *nprobe);
+};
+
+/**
+ * Return a probe object for the given display.
+ *
+ * Note that the returned object may be cached and used by different native
+ * display modules. It allows fast probing when multiple modules probe the
+ * same display.
+ */
+struct native_probe *
+native_create_probe(EGLNativeDisplayType dpy);
+
+/**
+ * Probe the probe object.
+ */
+enum native_probe_result
+native_get_probe_result(struct native_probe *nprobe);
+
+#endif /* _NATIVE_PROBE_H_ */
diff --git a/src/gallium/state_trackers/egl/fbdev/native_fbdev.c b/src/gallium/state_trackers/egl/fbdev/native_fbdev.c
new file mode 100644
index 0000000000..d70b7c6eb9
--- /dev/null
+++ b/src/gallium/state_trackers/egl/fbdev/native_fbdev.c
@@ -0,0 +1,470 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.9
+ *
+ * Copyright (C) 2010 LunarG Inc.
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Chia-I Wu <olv@lunarg.com>
+ */
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <linux/fb.h>
+
+#include "pipe/p_screen.h"
+#include "util/u_memory.h"
+#include "util/u_inlines.h"
+#include "util/u_pointer.h"
+
+#include "common/native.h"
+#include "common/native_helper.h"
+#include "fbdev/fbdev_sw_winsys.h"
+
+struct fbdev_display {
+ struct native_display base;
+
+ int fd;
+ struct native_event_handler *event_handler;
+
+ struct fb_fix_screeninfo finfo;
+ struct fb_var_screeninfo vinfo;
+
+ struct native_config config;
+ struct native_connector connector;
+ struct native_mode mode;
+
+ struct fbdev_surface *current_surface;
+};
+
+struct fbdev_surface {
+ struct native_surface base;
+
+ struct fbdev_display *fbdpy;
+ struct resource_surface *rsurf;
+ int width, height;
+
+ unsigned int sequence_number;
+
+ boolean is_current;
+};
+
+static INLINE struct fbdev_display *
+fbdev_display(const struct native_display *ndpy)
+{
+ return (struct fbdev_display *) ndpy;
+}
+
+static INLINE struct fbdev_surface *
+fbdev_surface(const struct native_surface *nsurf)
+{
+ return (struct fbdev_surface *) nsurf;
+}
+
+static boolean
+fbdev_surface_validate(struct native_surface *nsurf, uint attachment_mask,
+ unsigned int *seq_num, struct pipe_resource **textures,
+ int *width, int *height)
+{
+ struct fbdev_surface *fbsurf = fbdev_surface(nsurf);
+
+ if (!resource_surface_add_resources(fbsurf->rsurf, attachment_mask))
+ return FALSE;
+ if (textures)
+ resource_surface_get_resources(fbsurf->rsurf, textures, attachment_mask);
+
+ if (seq_num)
+ *seq_num = fbsurf->sequence_number;
+ if (width)
+ *width = fbsurf->width;
+ if (height)
+ *height = fbsurf->height;
+
+ return TRUE;
+}
+
+static boolean
+fbdev_surface_flush_frontbuffer(struct native_surface *nsurf)
+{
+ struct fbdev_surface *fbsurf = fbdev_surface(nsurf);
+
+ if (!fbsurf->is_current)
+ return TRUE;
+
+ return resource_surface_present(fbsurf->rsurf,
+ NATIVE_ATTACHMENT_FRONT_LEFT, NULL);
+}
+
+static boolean
+fbdev_surface_swap_buffers(struct native_surface *nsurf)
+{
+ struct fbdev_surface *fbsurf = fbdev_surface(nsurf);
+ struct fbdev_display *fbdpy = fbsurf->fbdpy;
+ boolean ret = TRUE;
+
+ if (fbsurf->is_current) {
+ ret = resource_surface_present(fbsurf->rsurf,
+ NATIVE_ATTACHMENT_BACK_LEFT, NULL);
+ }
+
+ resource_surface_swap_buffers(fbsurf->rsurf,
+ NATIVE_ATTACHMENT_FRONT_LEFT, NATIVE_ATTACHMENT_BACK_LEFT, TRUE);
+ /* the front/back textures are swapped */
+ fbsurf->sequence_number++;
+ fbdpy->event_handler->invalid_surface(&fbdpy->base,
+ &fbsurf->base, fbsurf->sequence_number);
+
+ return ret;
+}
+
+static void
+fbdev_surface_wait(struct native_surface *nsurf)
+{
+ /* no-op */
+}
+
+static void
+fbdev_surface_destroy(struct native_surface *nsurf)
+{
+ struct fbdev_surface *fbsurf = fbdev_surface(nsurf);
+
+ resource_surface_destroy(fbsurf->rsurf);
+ FREE(fbsurf);
+}
+
+static struct native_surface *
+fbdev_display_create_scanout_surface(struct native_display *ndpy,
+ const struct native_config *nconf,
+ uint width, uint height)
+{
+ struct fbdev_display *fbdpy = fbdev_display(ndpy);
+ struct fbdev_surface *fbsurf;
+
+ fbsurf = CALLOC_STRUCT(fbdev_surface);
+ if (!fbsurf)
+ return NULL;
+
+ fbsurf->fbdpy = fbdpy;
+ fbsurf->width = width;
+ fbsurf->height = height;
+
+ fbsurf->rsurf = resource_surface_create(fbdpy->base.screen,
+ nconf->color_format,
+ PIPE_BIND_RENDER_TARGET |
+ PIPE_BIND_DISPLAY_TARGET |
+ PIPE_BIND_SCANOUT);
+ if (!fbsurf->rsurf) {
+ FREE(fbsurf);
+ return NULL;
+ }
+
+ resource_surface_set_size(fbsurf->rsurf, fbsurf->width, fbsurf->height);
+
+ fbsurf->base.destroy = fbdev_surface_destroy;
+ fbsurf->base.swap_buffers = fbdev_surface_swap_buffers;
+ fbsurf->base.flush_frontbuffer = fbdev_surface_flush_frontbuffer;
+ fbsurf->base.validate = fbdev_surface_validate;
+ fbsurf->base.wait = fbdev_surface_wait;
+
+ return &fbsurf->base;
+}
+
+static boolean
+fbdev_display_program(struct native_display *ndpy, int crtc_idx,
+ struct native_surface *nsurf, uint x, uint y,
+ const struct native_connector **nconns, int num_nconns,
+ const struct native_mode *nmode)
+{
+ struct fbdev_display *fbdpy = fbdev_display(ndpy);
+ struct fbdev_surface *fbsurf = fbdev_surface(nsurf);
+
+ if (x || y)
+ return FALSE;
+
+ if (fbdpy->current_surface) {
+ if (fbdpy->current_surface == fbsurf)
+ return TRUE;
+ fbdpy->current_surface->is_current = FALSE;
+ }
+
+ if (fbsurf)
+ fbsurf->is_current = TRUE;
+ fbdpy->current_surface = fbsurf;
+
+ return TRUE;
+}
+
+static const struct native_mode **
+fbdev_display_get_modes(struct native_display *ndpy,
+ const struct native_connector *nconn,
+ int *num_modes)
+{
+ struct fbdev_display *fbdpy = fbdev_display(ndpy);
+ const struct native_mode **modes;
+
+ modes = MALLOC(sizeof(*modes));
+ if (modes) {
+ modes[0] = &fbdpy->mode;
+ if (num_modes)
+ *num_modes = 1;
+ }
+
+ return modes;
+}
+
+static const struct native_connector **
+fbdev_display_get_connectors(struct native_display *ndpy, int *num_connectors,
+ int *num_crtc)
+{
+ struct fbdev_display *fbdpy = fbdev_display(ndpy);
+ const struct native_connector **connectors;
+
+ connectors = MALLOC(sizeof(*connectors));
+ if (connectors) {
+ connectors[0] = &fbdpy->connector;
+ if (num_connectors)
+ *num_connectors = 1;
+ }
+
+ return connectors;
+}
+
+static struct native_display_modeset fbdev_display_modeset = {
+ .get_connectors = fbdev_display_get_connectors,
+ .get_modes = fbdev_display_get_modes,
+ .create_scanout_surface = fbdev_display_create_scanout_surface,
+ .program = fbdev_display_program
+};
+
+static const struct native_config **
+fbdev_display_get_configs(struct native_display *ndpy, int *num_configs)
+{
+ struct fbdev_display *fbdpy = fbdev_display(ndpy);
+ const struct native_config **configs;
+
+ configs = MALLOC(sizeof(*configs));
+ if (configs) {
+ configs[0] = &fbdpy->config;
+ if (num_configs)
+ *num_configs = 1;
+ }
+
+ return configs;
+}
+
+static int
+fbdev_display_get_param(struct native_display *ndpy,
+ enum native_param_type param)
+{
+ int val;
+
+ switch (param) {
+ default:
+ val = 0;
+ break;
+ }
+
+ return val;
+}
+
+static void
+fbdev_display_destroy(struct native_display *ndpy)
+{
+ struct fbdev_display *fbdpy = fbdev_display(ndpy);
+
+ fbdpy->base.screen->destroy(fbdpy->base.screen);
+ close(fbdpy->fd);
+ FREE(fbdpy);
+}
+
+static boolean
+fbdev_display_init_modes(struct native_display *ndpy)
+{
+ struct fbdev_display *fbdpy = fbdev_display(ndpy);
+ struct native_mode *nmode = &fbdpy->mode;
+
+ nmode->desc = "Current Mode";
+ nmode->width = fbdpy->vinfo.xres;
+ nmode->height = fbdpy->vinfo.yres;
+ nmode->refresh_rate = 60 * 1000; /* dummy */
+
+ return TRUE;
+}
+
+static boolean
+fbdev_display_init_connectors(struct native_display *ndpy)
+{
+ return TRUE;
+}
+
+static enum pipe_format
+vinfo_to_format(const struct fb_var_screeninfo *vinfo)
+{
+ enum pipe_format format = PIPE_FORMAT_NONE;
+
+ switch (vinfo->bits_per_pixel) {
+ case 32:
+ if (vinfo->red.length == 8 &&
+ vinfo->green.length == 8 &&
+ vinfo->blue.length == 8) {
+ format = (vinfo->transp.length == 8) ?
+ PIPE_FORMAT_B8G8R8A8_UNORM : PIPE_FORMAT_B8G8R8X8_UNORM;
+ }
+ break;
+ case 16:
+ if (vinfo->red.length == 5 &&
+ vinfo->green.length == 6 &&
+ vinfo->blue.length == 5 &&
+ vinfo->transp.length == 0)
+ format = PIPE_FORMAT_B5G6R5_UNORM;
+ break;
+ default:
+ break;
+ }
+
+ return format;
+}
+
+static boolean
+fbdev_display_init_configs(struct native_display *ndpy)
+{
+ struct fbdev_display *fbdpy = fbdev_display(ndpy);
+ struct native_config *nconf = &fbdpy->config;
+
+ nconf->color_format = vinfo_to_format(&fbdpy->vinfo);
+ if (nconf->color_format == PIPE_FORMAT_NONE)
+ return FALSE;
+
+ nconf->buffer_mask =
+ (1 << NATIVE_ATTACHMENT_FRONT_LEFT) |
+ (1 << NATIVE_ATTACHMENT_BACK_LEFT);
+
+ nconf->scanout_bit = TRUE;
+
+ return TRUE;
+}
+
+static boolean
+fbdev_display_init(struct native_display *ndpy)
+{
+ struct fbdev_display *fbdpy = fbdev_display(ndpy);
+ struct sw_winsys *ws;
+
+ if (ioctl(fbdpy->fd, FBIOGET_FSCREENINFO, &fbdpy->finfo))
+ return FALSE;
+
+ if (ioctl(fbdpy->fd, FBIOGET_VSCREENINFO, &fbdpy->vinfo))
+ return FALSE;
+
+ if (fbdpy->finfo.visual != FB_VISUAL_TRUECOLOR ||
+ fbdpy->finfo.type != FB_TYPE_PACKED_PIXELS)
+ return FALSE;
+
+ if (!fbdev_display_init_configs(&fbdpy->base) ||
+ !fbdev_display_init_connectors(&fbdpy->base) ||
+ !fbdev_display_init_modes(&fbdpy->base))
+ return FALSE;
+
+ ws = fbdev_create_sw_winsys(fbdpy->fd, fbdpy->config.color_format);
+ if (ws)
+ fbdpy->base.screen = native_create_sw_screen(ws);
+
+ if (fbdpy->base.screen) {
+ if (!fbdpy->base.screen->is_format_supported(fbdpy->base.screen,
+ fbdpy->config.color_format, PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_RENDER_TARGET, 0)) {
+ fbdpy->base.screen->destroy(fbdpy->base.screen);
+ fbdpy->base.screen = NULL;
+ }
+ }
+
+ return (fbdpy->base.screen != NULL);
+}
+
+static struct native_display *
+fbdev_display_create(int fd, struct native_event_handler *event_handler)
+{
+ struct fbdev_display *fbdpy;
+
+ fbdpy = CALLOC_STRUCT(fbdev_display);
+ if (!fbdpy)
+ return NULL;
+
+ fbdpy->fd = fd;
+ fbdpy->event_handler = event_handler;
+
+ if (!fbdev_display_init(&fbdpy->base)) {
+ FREE(fbdpy);
+ return NULL;
+ }
+
+ fbdpy->base.destroy = fbdev_display_destroy;
+ fbdpy->base.get_param = fbdev_display_get_param;
+ fbdpy->base.get_configs = fbdev_display_get_configs;
+
+ fbdpy->base.modeset = &fbdev_display_modeset;
+
+ return &fbdpy->base;
+}
+
+struct native_probe *
+native_create_probe(EGLNativeDisplayType dpy)
+{
+ return NULL;
+}
+
+enum native_probe_result
+native_get_probe_result(struct native_probe *nprobe)
+{
+ return NATIVE_PROBE_UNKNOWN;
+}
+
+const char *
+native_get_name(void)
+{
+ return "FBDEV";
+}
+
+struct native_display *
+native_create_display(EGLNativeDisplayType dpy,
+ struct native_event_handler *event_handler)
+{
+ struct native_display *ndpy;
+ int fd;
+
+ /* well, this makes fd 0 being ignored */
+ if (dpy == EGL_DEFAULT_DISPLAY) {
+ fd = open("/dev/fb0", O_RDWR);
+ }
+ else {
+ fd = dup((int) pointer_to_intptr((void *) dpy));
+ }
+ if (fd < 0)
+ return NULL;
+
+ ndpy = fbdev_display_create(fd, event_handler);
+ if (!ndpy)
+ close(fd);
+
+ return ndpy;
+}
diff --git a/src/gallium/state_trackers/egl/gdi/native_gdi.c b/src/gallium/state_trackers/egl/gdi/native_gdi.c
new file mode 100644
index 0000000000..1791d198d5
--- /dev/null
+++ b/src/gallium/state_trackers/egl/gdi/native_gdi.c
@@ -0,0 +1,406 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.9
+ *
+ * Copyright (C) 2010 LunarG Inc.
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Chia-I Wu <olv@lunarg.com>
+ */
+
+#include <windows.h>
+
+#include "pipe/p_compiler.h"
+#include "util/u_memory.h"
+#include "util/u_format.h"
+#include "util/u_inlines.h"
+#include "gdi/gdi_sw_winsys.h"
+
+#include "common/native_helper.h"
+#include "common/native.h"
+
+struct gdi_display {
+ struct native_display base;
+
+ HDC hDC;
+ struct native_event_handler *event_handler;
+
+ struct native_config *configs;
+ int num_configs;
+};
+
+struct gdi_surface {
+ struct native_surface base;
+
+ HWND hWnd;
+ enum pipe_format color_format;
+
+ struct gdi_display *gdpy;
+
+ unsigned int server_stamp;
+ unsigned int client_stamp;
+
+ struct resource_surface *rsurf;
+};
+
+static INLINE struct gdi_display *
+gdi_display(const struct native_display *ndpy)
+{
+ return (struct gdi_display *) ndpy;
+}
+
+static INLINE struct gdi_surface *
+gdi_surface(const struct native_surface *nsurf)
+{
+ return (struct gdi_surface *) nsurf;
+}
+
+/**
+ * Update the geometry of the surface. This is a slow functions.
+ */
+static void
+gdi_surface_update_geometry(struct native_surface *nsurf)
+{
+ struct gdi_surface *gsurf = gdi_surface(nsurf);
+ RECT rect;
+ uint w, h;
+
+ GetClientRect(gsurf->hWnd, &rect);
+ w = rect.right - rect.left;
+ h = rect.bottom - rect.top;
+
+ if (resource_surface_set_size(gsurf->rsurf, w, h))
+ gsurf->server_stamp++;
+}
+
+/**
+ * Update the buffers of the surface.
+ */
+static boolean
+gdi_surface_update_buffers(struct native_surface *nsurf, uint buffer_mask)
+{
+ struct gdi_surface *gsurf = gdi_surface(nsurf);
+
+ if (gsurf->client_stamp != gsurf->server_stamp) {
+ gdi_surface_update_geometry(&gsurf->base);
+ gsurf->client_stamp = gsurf->server_stamp;
+ }
+
+ return resource_surface_add_resources(gsurf->rsurf, buffer_mask);
+}
+
+/**
+ * Emulate an invalidate event.
+ */
+static void
+gdi_surface_invalidate(struct native_surface *nsurf)
+{
+ struct gdi_surface *gsurf = gdi_surface(nsurf);
+ struct gdi_display *gdpy = gsurf->gdpy;
+
+ gsurf->server_stamp++;
+ gdpy->event_handler->invalid_surface(&gdpy->base,
+ &gsurf->base, gsurf->server_stamp);
+}
+
+static boolean
+gdi_surface_flush_frontbuffer(struct native_surface *nsurf)
+{
+ struct gdi_surface *gsurf = gdi_surface(nsurf);
+ HDC hDC;
+ boolean ret;
+
+ hDC = GetDC(gsurf->hWnd);
+ ret = resource_surface_present(gsurf->rsurf,
+ NATIVE_ATTACHMENT_FRONT_LEFT, (void *) hDC);
+ ReleaseDC(gsurf->hWnd, hDC);
+
+ /* force buffers to be updated in next validation call */
+ gdi_surface_invalidate(&gsurf->base);
+
+ return ret;
+}
+
+static boolean
+gdi_surface_swap_buffers(struct native_surface *nsurf)
+{
+ struct gdi_surface *gsurf = gdi_surface(nsurf);
+ HDC hDC;
+ boolean ret;
+
+ hDC = GetDC(gsurf->hWnd);
+ ret = resource_surface_present(gsurf->rsurf,
+ NATIVE_ATTACHMENT_BACK_LEFT, (void *) hDC);
+ ReleaseDC(gsurf->hWnd, hDC);
+
+ resource_surface_swap_buffers(gsurf->rsurf,
+ NATIVE_ATTACHMENT_FRONT_LEFT, NATIVE_ATTACHMENT_BACK_LEFT, TRUE);
+ /* the front/back buffers have been swapped */
+ gdi_surface_invalidate(&gsurf->base);
+
+ return ret;
+}
+
+static boolean
+gdi_surface_validate(struct native_surface *nsurf, uint attachment_mask,
+ unsigned int *seq_num, struct pipe_resource **textures,
+ int *width, int *height)
+{
+ struct gdi_surface *gsurf = gdi_surface(nsurf);
+ uint w, h;
+
+ if (!gdi_surface_update_buffers(&gsurf->base, attachment_mask))
+ return FALSE;
+
+ if (seq_num)
+ *seq_num = gsurf->client_stamp;
+
+ if (textures)
+ resource_surface_get_resources(gsurf->rsurf, textures, attachment_mask);
+
+ resource_surface_get_size(gsurf->rsurf, &w, &h);
+ if (width)
+ *width = w;
+ if (height)
+ *height = h;
+
+ return TRUE;
+}
+
+static void
+gdi_surface_wait(struct native_surface *nsurf)
+{
+ /* no-op */
+}
+
+static void
+gdi_surface_destroy(struct native_surface *nsurf)
+{
+ struct gdi_surface *gsurf = gdi_surface(nsurf);
+
+ resource_surface_destroy(gsurf->rsurf);
+ FREE(gsurf);
+}
+
+static struct native_surface *
+gdi_display_create_window_surface(struct native_display *ndpy,
+ EGLNativeWindowType win,
+ const struct native_config *nconf)
+{
+ struct gdi_display *gdpy = gdi_display(ndpy);
+ struct gdi_surface *gsurf;
+
+ gsurf = CALLOC_STRUCT(gdi_surface);
+ if (!gsurf)
+ return NULL;
+
+ gsurf->gdpy = gdpy;
+ gsurf->color_format = nconf->color_format;
+ gsurf->hWnd = (HWND) win;
+
+ gsurf->rsurf = resource_surface_create(gdpy->base.screen,
+ gsurf->color_format,
+ PIPE_BIND_RENDER_TARGET |
+ PIPE_BIND_SAMPLER_VIEW |
+ PIPE_BIND_DISPLAY_TARGET |
+ PIPE_BIND_SCANOUT);
+ if (!gsurf->rsurf) {
+ FREE(gsurf);
+ return NULL;
+ }
+
+ /* initialize the geometry */
+ gdi_surface_update_geometry(&gsurf->base);
+
+ gsurf->base.destroy = gdi_surface_destroy;
+ gsurf->base.swap_buffers = gdi_surface_swap_buffers;
+ gsurf->base.flush_frontbuffer = gdi_surface_flush_frontbuffer;
+ gsurf->base.validate = gdi_surface_validate;
+ gsurf->base.wait = gdi_surface_wait;
+
+ return &gsurf->base;
+}
+
+static int
+fill_color_formats(struct native_display *ndpy, enum pipe_format formats[8])
+{
+ struct pipe_screen *screen = ndpy->screen;
+ int i, count = 0;
+
+ enum pipe_format candidates[] = {
+ /* 32-bit */
+ PIPE_FORMAT_B8G8R8A8_UNORM,
+ PIPE_FORMAT_A8R8G8B8_UNORM,
+ /* 24-bit */
+ PIPE_FORMAT_B8G8R8X8_UNORM,
+ PIPE_FORMAT_X8R8G8B8_UNORM,
+ /* 16-bit */
+ PIPE_FORMAT_B5G6R5_UNORM
+ };
+
+ assert(Elements(candidates) <= 8);
+
+ for (i = 0; i < Elements(candidates); i++) {
+ if (screen->is_format_supported(screen, candidates[i],
+ PIPE_TEXTURE_2D, 0, PIPE_BIND_RENDER_TARGET, 0))
+ formats[count++] = candidates[i];
+ }
+
+ return count;
+}
+
+static const struct native_config **
+gdi_display_get_configs(struct native_display *ndpy, int *num_configs)
+{
+ struct gdi_display *gdpy = gdi_display(ndpy);
+ const struct native_config **configs;
+ int i;
+
+ /* first time */
+ if (!gdpy->configs) {
+ enum pipe_format formats[8];
+ int i, count;
+
+ count = fill_color_formats(&gdpy->base, formats);
+
+ gdpy->configs = CALLOC(count, sizeof(*gdpy->configs));
+ if (!gdpy->configs)
+ return NULL;
+
+ for (i = 0; i < count; i++) {
+ struct native_config *nconf = &gdpy->configs[i];
+
+ nconf->buffer_mask =
+ (1 << NATIVE_ATTACHMENT_FRONT_LEFT) |
+ (1 << NATIVE_ATTACHMENT_BACK_LEFT);
+ nconf->color_format = formats[i];
+
+ nconf->window_bit = TRUE;
+ nconf->slow_config = TRUE;
+ }
+
+ gdpy->num_configs = count;
+ }
+
+ configs = MALLOC(gdpy->num_configs * sizeof(*configs));
+ if (configs) {
+ for (i = 0; i < gdpy->num_configs; i++)
+ configs[i] = (const struct native_config *) &gdpy->configs[i];
+ if (num_configs)
+ *num_configs = gdpy->num_configs;
+ }
+ return configs;
+}
+
+static int
+gdi_display_get_param(struct native_display *ndpy,
+ enum native_param_type param)
+{
+ int val;
+
+ switch (param) {
+ case NATIVE_PARAM_USE_NATIVE_BUFFER:
+ /* private buffers are allocated */
+ val = FALSE;
+ break;
+ default:
+ val = 0;
+ break;
+ }
+
+ return val;
+}
+
+static void
+gdi_display_destroy(struct native_display *ndpy)
+{
+ struct gdi_display *gdpy = gdi_display(ndpy);
+
+ if (gdpy->configs)
+ FREE(gdpy->configs);
+
+ gdpy->base.screen->destroy(gdpy->base.screen);
+
+ FREE(gdpy);
+}
+
+static struct native_display *
+gdi_create_display(HDC hDC, struct pipe_screen *screen,
+ struct native_event_handler *event_handler)
+{
+ struct gdi_display *gdpy;
+
+ gdpy = CALLOC_STRUCT(gdi_display);
+ if (!gdpy)
+ return NULL;
+
+ gdpy->hDC = hDC;
+ gdpy->event_handler = event_handler;
+
+ gdpy->base.screen = screen;
+
+ gdpy->base.destroy = gdi_display_destroy;
+ gdpy->base.get_param = gdi_display_get_param;
+
+ gdpy->base.get_configs = gdi_display_get_configs;
+ gdpy->base.create_window_surface = gdi_display_create_window_surface;
+
+ return &gdpy->base;
+}
+
+struct native_probe *
+native_create_probe(EGLNativeDisplayType dpy)
+{
+ return NULL;
+}
+
+enum native_probe_result
+native_get_probe_result(struct native_probe *nprobe)
+{
+ return NATIVE_PROBE_UNKNOWN;
+}
+
+const char *
+native_get_name(void)
+{
+ return "GDI";
+}
+
+struct native_display *
+native_create_display(EGLNativeDisplayType dpy,
+ struct native_event_handler *event_handler)
+{
+ struct sw_winsys *winsys;
+ struct pipe_screen *screen;
+
+ winsys = gdi_create_sw_winsys();
+ if (!winsys)
+ return NULL;
+
+ screen = native_create_sw_screen(winsys);
+ if (!screen) {
+ if (winsys->destroy)
+ winsys->destroy(winsys);
+ return NULL;
+ }
+
+ return gdi_create_display((HDC) dpy, screen, event_handler);
+}
diff --git a/src/gallium/state_trackers/egl/kms/native_kms.c b/src/gallium/state_trackers/egl/kms/native_kms.c
new file mode 100644
index 0000000000..bfb4a9d258
--- /dev/null
+++ b/src/gallium/state_trackers/egl/kms/native_kms.c
@@ -0,0 +1,830 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.8
+ *
+ * Copyright (C) 2010 Chia-I Wu <olv@0xlab.org>
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "pipe/p_screen.h"
+#include "pipe/p_context.h"
+#include "util/u_debug.h"
+#include "util/u_memory.h"
+#include "util/u_inlines.h"
+#include "util/u_pointer.h"
+#include "util/u_string.h"
+#include "egllog.h"
+
+#include "native_kms.h"
+
+static boolean
+kms_surface_validate(struct native_surface *nsurf, uint attachment_mask,
+ unsigned int *seq_num, struct pipe_resource **textures,
+ int *width, int *height)
+{
+ struct kms_surface *ksurf = kms_surface(nsurf);
+
+ if (!resource_surface_add_resources(ksurf->rsurf, attachment_mask))
+ return FALSE;
+ if (textures)
+ resource_surface_get_resources(ksurf->rsurf, textures, attachment_mask);
+
+ if (seq_num)
+ *seq_num = ksurf->sequence_number;
+ if (width)
+ *width = ksurf->width;
+ if (height)
+ *height = ksurf->height;
+
+ return TRUE;
+}
+
+/**
+ * Add textures as DRM framebuffers.
+ */
+static boolean
+kms_surface_init_framebuffers(struct native_surface *nsurf, boolean need_back)
+{
+ struct kms_surface *ksurf = kms_surface(nsurf);
+ struct kms_display *kdpy = ksurf->kdpy;
+ int num_framebuffers = (need_back) ? 2 : 1;
+ int i, err;
+
+ for (i = 0; i < num_framebuffers; i++) {
+ struct kms_framebuffer *fb;
+ enum native_attachment natt;
+ struct winsys_handle whandle;
+ uint block_bits;
+
+ if (i == 0) {
+ fb = &ksurf->front_fb;
+ natt = NATIVE_ATTACHMENT_FRONT_LEFT;
+ }
+ else {
+ fb = &ksurf->back_fb;
+ natt = NATIVE_ATTACHMENT_BACK_LEFT;
+ }
+
+ if (!fb->texture) {
+ /* make sure the texture has been allocated */
+ resource_surface_add_resources(ksurf->rsurf, 1 << natt);
+ fb->texture =
+ resource_surface_get_single_resource(ksurf->rsurf, natt);
+ if (!fb->texture)
+ return FALSE;
+ }
+
+ /* already initialized */
+ if (fb->buffer_id)
+ continue;
+
+ /* TODO detect the real value */
+ fb->is_passive = TRUE;
+
+ memset(&whandle, 0, sizeof(whandle));
+ whandle.type = DRM_API_HANDLE_TYPE_KMS;
+
+ if (!kdpy->base.screen->resource_get_handle(kdpy->base.screen,
+ fb->texture, &whandle))
+ return FALSE;
+
+ block_bits = util_format_get_blocksizebits(ksurf->color_format);
+ err = drmModeAddFB(kdpy->fd, ksurf->width, ksurf->height,
+ block_bits, block_bits, whandle.stride, whandle.handle,
+ &fb->buffer_id);
+ if (err) {
+ fb->buffer_id = 0;
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static boolean
+kms_surface_flush_frontbuffer(struct native_surface *nsurf)
+{
+#ifdef DRM_MODE_FEATURE_DIRTYFB
+ struct kms_surface *ksurf = kms_surface(nsurf);
+ struct kms_display *kdpy = ksurf->kdpy;
+
+ if (ksurf->front_fb.is_passive)
+ drmModeDirtyFB(kdpy->fd, ksurf->front_fb.buffer_id, NULL, 0);
+#endif
+
+ return TRUE;
+}
+
+static boolean
+kms_surface_swap_buffers(struct native_surface *nsurf)
+{
+ struct kms_surface *ksurf = kms_surface(nsurf);
+ struct kms_crtc *kcrtc = &ksurf->current_crtc;
+ struct kms_display *kdpy = ksurf->kdpy;
+ struct kms_framebuffer tmp_fb;
+ int err;
+
+ if (!ksurf->back_fb.buffer_id) {
+ if (!kms_surface_init_framebuffers(&ksurf->base, TRUE))
+ return FALSE;
+ }
+
+ if (ksurf->is_shown && kcrtc->crtc) {
+ err = drmModeSetCrtc(kdpy->fd, kcrtc->crtc->crtc_id,
+ ksurf->back_fb.buffer_id, kcrtc->crtc->x, kcrtc->crtc->y,
+ kcrtc->connectors, kcrtc->num_connectors, &kcrtc->crtc->mode);
+ if (err)
+ return FALSE;
+ }
+
+ /* swap the buffers */
+ tmp_fb = ksurf->front_fb;
+ ksurf->front_fb = ksurf->back_fb;
+ ksurf->back_fb = tmp_fb;
+
+ resource_surface_swap_buffers(ksurf->rsurf,
+ NATIVE_ATTACHMENT_FRONT_LEFT, NATIVE_ATTACHMENT_BACK_LEFT, FALSE);
+ /* the front/back textures are swapped */
+ ksurf->sequence_number++;
+ kdpy->event_handler->invalid_surface(&kdpy->base,
+ &ksurf->base, ksurf->sequence_number);
+
+ return TRUE;
+}
+
+static void
+kms_surface_wait(struct native_surface *nsurf)
+{
+ /* no-op */
+}
+
+static void
+kms_surface_destroy(struct native_surface *nsurf)
+{
+ struct kms_surface *ksurf = kms_surface(nsurf);
+
+ if (ksurf->current_crtc.crtc)
+ drmModeFreeCrtc(ksurf->current_crtc.crtc);
+
+ if (ksurf->front_fb.buffer_id)
+ drmModeRmFB(ksurf->kdpy->fd, ksurf->front_fb.buffer_id);
+ pipe_resource_reference(&ksurf->front_fb.texture, NULL);
+
+ if (ksurf->back_fb.buffer_id)
+ drmModeRmFB(ksurf->kdpy->fd, ksurf->back_fb.buffer_id);
+ pipe_resource_reference(&ksurf->back_fb.texture, NULL);
+
+ resource_surface_destroy(ksurf->rsurf);
+ FREE(ksurf);
+}
+
+static struct kms_surface *
+kms_display_create_surface(struct native_display *ndpy,
+ const struct native_config *nconf,
+ uint width, uint height)
+{
+ struct kms_display *kdpy = kms_display(ndpy);
+ struct kms_config *kconf = kms_config(nconf);
+ struct kms_surface *ksurf;
+
+ ksurf = CALLOC_STRUCT(kms_surface);
+ if (!ksurf)
+ return NULL;
+
+ ksurf->kdpy = kdpy;
+ ksurf->color_format = kconf->base.color_format;
+ ksurf->width = width;
+ ksurf->height = height;
+
+ ksurf->rsurf = resource_surface_create(kdpy->base.screen,
+ ksurf->color_format,
+ PIPE_BIND_RENDER_TARGET |
+ PIPE_BIND_SAMPLER_VIEW |
+ PIPE_BIND_DISPLAY_TARGET |
+ PIPE_BIND_SCANOUT);
+ if (!ksurf->rsurf) {
+ FREE(ksurf);
+ return NULL;
+ }
+
+ resource_surface_set_size(ksurf->rsurf, ksurf->width, ksurf->height);
+
+ ksurf->base.destroy = kms_surface_destroy;
+ ksurf->base.swap_buffers = kms_surface_swap_buffers;
+ ksurf->base.flush_frontbuffer = kms_surface_flush_frontbuffer;
+ ksurf->base.validate = kms_surface_validate;
+ ksurf->base.wait = kms_surface_wait;
+
+ return ksurf;
+}
+
+/**
+ * Choose a CRTC that supports all given connectors.
+ */
+static uint32_t
+kms_display_choose_crtc(struct native_display *ndpy,
+ uint32_t *connectors, int num_connectors)
+{
+ struct kms_display *kdpy = kms_display(ndpy);
+ int idx;
+
+ for (idx = 0; idx < kdpy->resources->count_crtcs; idx++) {
+ boolean found_crtc = TRUE;
+ int i, j;
+
+ for (i = 0; i < num_connectors; i++) {
+ drmModeConnectorPtr connector;
+ int encoder_idx = -1;
+
+ connector = drmModeGetConnector(kdpy->fd, connectors[i]);
+ if (!connector) {
+ found_crtc = FALSE;
+ break;
+ }
+
+ /* find an encoder the CRTC supports */
+ for (j = 0; j < connector->count_encoders; j++) {
+ drmModeEncoderPtr encoder =
+ drmModeGetEncoder(kdpy->fd, connector->encoders[j]);
+ if (encoder->possible_crtcs & (1 << idx)) {
+ encoder_idx = j;
+ break;
+ }
+ drmModeFreeEncoder(encoder);
+ }
+
+ drmModeFreeConnector(connector);
+ if (encoder_idx < 0) {
+ found_crtc = FALSE;
+ break;
+ }
+ }
+
+ if (found_crtc)
+ break;
+ }
+
+ if (idx >= kdpy->resources->count_crtcs) {
+ _eglLog(_EGL_WARNING,
+ "failed to find a CRTC that supports the given %d connectors",
+ num_connectors);
+ return 0;
+ }
+
+ return kdpy->resources->crtcs[idx];
+}
+
+/**
+ * Remember the original CRTC status and set the CRTC
+ */
+static boolean
+kms_display_set_crtc(struct native_display *ndpy, int crtc_idx,
+ uint32_t buffer_id, uint32_t x, uint32_t y,
+ uint32_t *connectors, int num_connectors,
+ drmModeModeInfoPtr mode)
+{
+ struct kms_display *kdpy = kms_display(ndpy);
+ struct kms_crtc *kcrtc = &kdpy->saved_crtcs[crtc_idx];
+ uint32_t crtc_id;
+ int err;
+
+ if (kcrtc->crtc) {
+ crtc_id = kcrtc->crtc->crtc_id;
+ }
+ else {
+ int count = 0, i;
+
+ /*
+ * Choose the CRTC once. It could be more dynamic, but let's keep it
+ * simple for now.
+ */
+ crtc_id = kms_display_choose_crtc(&kdpy->base,
+ connectors, num_connectors);
+
+ /* save the original CRTC status */
+ kcrtc->crtc = drmModeGetCrtc(kdpy->fd, crtc_id);
+ if (!kcrtc->crtc)
+ return FALSE;
+
+ for (i = 0; i < kdpy->num_connectors; i++) {
+ struct kms_connector *kconn = &kdpy->connectors[i];
+ drmModeConnectorPtr connector = kconn->connector;
+ drmModeEncoderPtr encoder;
+
+ encoder = drmModeGetEncoder(kdpy->fd, connector->encoder_id);
+ if (encoder) {
+ if (encoder->crtc_id == crtc_id) {
+ kcrtc->connectors[count++] = connector->connector_id;
+ if (count >= Elements(kcrtc->connectors))
+ break;
+ }
+ drmModeFreeEncoder(encoder);
+ }
+ }
+
+ kcrtc->num_connectors = count;
+ }
+
+ err = drmModeSetCrtc(kdpy->fd, crtc_id, buffer_id, x, y,
+ connectors, num_connectors, mode);
+ if (err) {
+ drmModeFreeCrtc(kcrtc->crtc);
+ kcrtc->crtc = NULL;
+ kcrtc->num_connectors = 0;
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static boolean
+kms_display_program(struct native_display *ndpy, int crtc_idx,
+ struct native_surface *nsurf, uint x, uint y,
+ const struct native_connector **nconns, int num_nconns,
+ const struct native_mode *nmode)
+{
+ struct kms_display *kdpy = kms_display(ndpy);
+ struct kms_surface *ksurf = kms_surface(nsurf);
+ const struct kms_mode *kmode = kms_mode(nmode);
+ uint32_t connector_ids[32];
+ uint32_t buffer_id;
+ drmModeModeInfo mode_tmp, *mode;
+ int i;
+
+ if (num_nconns > Elements(connector_ids)) {
+ _eglLog(_EGL_WARNING, "too many connectors (%d)", num_nconns);
+ num_nconns = Elements(connector_ids);
+ }
+
+ if (ksurf) {
+ if (!kms_surface_init_framebuffers(&ksurf->base, FALSE))
+ return FALSE;
+
+ buffer_id = ksurf->front_fb.buffer_id;
+ /* the mode argument of drmModeSetCrtc is not constified */
+ mode_tmp = kmode->mode;
+ mode = &mode_tmp;
+ }
+ else {
+ /* disable the CRTC */
+ buffer_id = 0;
+ mode = NULL;
+ num_nconns = 0;
+ }
+
+ for (i = 0; i < num_nconns; i++) {
+ struct kms_connector *kconn = kms_connector(nconns[i]);
+ connector_ids[i] = kconn->connector->connector_id;
+ }
+
+ if (!kms_display_set_crtc(&kdpy->base, crtc_idx, buffer_id, x, y,
+ connector_ids, num_nconns, mode)) {
+ _eglLog(_EGL_WARNING, "failed to set CRTC %d", crtc_idx);
+
+ return FALSE;
+ }
+
+ if (kdpy->shown_surfaces[crtc_idx])
+ kdpy->shown_surfaces[crtc_idx]->is_shown = FALSE;
+ kdpy->shown_surfaces[crtc_idx] = ksurf;
+
+ /* remember the settings for buffer swapping */
+ if (ksurf) {
+ uint32_t crtc_id = kdpy->saved_crtcs[crtc_idx].crtc->crtc_id;
+ struct kms_crtc *kcrtc = &ksurf->current_crtc;
+
+ if (kcrtc->crtc)
+ drmModeFreeCrtc(kcrtc->crtc);
+ kcrtc->crtc = drmModeGetCrtc(kdpy->fd, crtc_id);
+
+ assert(num_nconns < Elements(kcrtc->connectors));
+ memcpy(kcrtc->connectors, connector_ids,
+ sizeof(*connector_ids) * num_nconns);
+ kcrtc->num_connectors = num_nconns;
+
+ ksurf->is_shown = TRUE;
+ }
+
+ return TRUE;
+}
+
+static const struct native_mode **
+kms_display_get_modes(struct native_display *ndpy,
+ const struct native_connector *nconn,
+ int *num_modes)
+{
+ struct kms_display *kdpy = kms_display(ndpy);
+ struct kms_connector *kconn = kms_connector(nconn);
+ const struct native_mode **nmodes_return;
+ int count, i;
+
+ /* delete old data */
+ if (kconn->connector) {
+ drmModeFreeConnector(kconn->connector);
+ FREE(kconn->kms_modes);
+
+ kconn->connector = NULL;
+ kconn->kms_modes = NULL;
+ kconn->num_modes = 0;
+ }
+
+ /* detect again */
+ kconn->connector = drmModeGetConnector(kdpy->fd, kconn->connector_id);
+ if (!kconn->connector)
+ return NULL;
+
+ count = kconn->connector->count_modes;
+ kconn->kms_modes = CALLOC(count, sizeof(*kconn->kms_modes));
+ if (!kconn->kms_modes) {
+ drmModeFreeConnector(kconn->connector);
+ kconn->connector = NULL;
+
+ return NULL;
+ }
+
+ for (i = 0; i < count; i++) {
+ struct kms_mode *kmode = &kconn->kms_modes[i];
+ drmModeModeInfoPtr mode = &kconn->connector->modes[i];
+
+ kmode->mode = *mode;
+
+ kmode->base.desc = kmode->mode.name;
+ kmode->base.width = kmode->mode.hdisplay;
+ kmode->base.height = kmode->mode.vdisplay;
+ kmode->base.refresh_rate = kmode->mode.vrefresh;
+ /* not all kernels have vrefresh = refresh_rate * 1000 */
+ if (kmode->base.refresh_rate > 1000)
+ kmode->base.refresh_rate = (kmode->base.refresh_rate + 500) / 1000;
+ }
+
+ nmodes_return = MALLOC(count * sizeof(*nmodes_return));
+ if (nmodes_return) {
+ for (i = 0; i < count; i++)
+ nmodes_return[i] = &kconn->kms_modes[i].base;
+ if (num_modes)
+ *num_modes = count;
+ }
+
+ return nmodes_return;
+}
+
+static const struct native_connector **
+kms_display_get_connectors(struct native_display *ndpy, int *num_connectors,
+ int *num_crtc)
+{
+ struct kms_display *kdpy = kms_display(ndpy);
+ const struct native_connector **connectors;
+ int i;
+
+ if (!kdpy->connectors) {
+ kdpy->connectors =
+ CALLOC(kdpy->resources->count_connectors, sizeof(*kdpy->connectors));
+ if (!kdpy->connectors)
+ return NULL;
+
+ for (i = 0; i < kdpy->resources->count_connectors; i++) {
+ struct kms_connector *kconn = &kdpy->connectors[i];
+
+ kconn->connector_id = kdpy->resources->connectors[i];
+ /* kconn->connector is allocated when the modes are asked */
+ }
+
+ kdpy->num_connectors = kdpy->resources->count_connectors;
+ }
+
+ connectors = MALLOC(kdpy->num_connectors * sizeof(*connectors));
+ if (connectors) {
+ for (i = 0; i < kdpy->num_connectors; i++)
+ connectors[i] = &kdpy->connectors[i].base;
+ if (num_connectors)
+ *num_connectors = kdpy->num_connectors;
+ }
+
+ if (num_crtc)
+ *num_crtc = kdpy->resources->count_crtcs;
+
+ return connectors;
+}
+
+static struct native_surface *
+kms_display_create_scanout_surface(struct native_display *ndpy,
+ const struct native_config *nconf,
+ uint width, uint height)
+{
+ struct kms_surface *ksurf;
+
+ ksurf = kms_display_create_surface(ndpy, nconf, width, height);
+ return &ksurf->base;
+}
+
+static boolean
+kms_display_is_format_supported(struct native_display *ndpy,
+ enum pipe_format fmt, boolean is_color)
+{
+ return ndpy->screen->is_format_supported(ndpy->screen,
+ fmt, PIPE_TEXTURE_2D, 0,
+ (is_color) ? PIPE_BIND_RENDER_TARGET :
+ PIPE_BIND_DEPTH_STENCIL, 0);
+}
+
+static const struct native_config **
+kms_display_get_configs(struct native_display *ndpy, int *num_configs)
+{
+ struct kms_display *kdpy = kms_display(ndpy);
+ const struct native_config **configs;
+
+ /* first time */
+ if (!kdpy->config) {
+ struct native_config *nconf;
+ enum pipe_format format;
+
+ kdpy->config = CALLOC(1, sizeof(*kdpy->config));
+ if (!kdpy->config)
+ return NULL;
+
+ nconf = &kdpy->config->base;
+
+ nconf->buffer_mask =
+ (1 << NATIVE_ATTACHMENT_FRONT_LEFT) |
+ (1 << NATIVE_ATTACHMENT_BACK_LEFT);
+
+ format = PIPE_FORMAT_B8G8R8A8_UNORM;
+ if (!kms_display_is_format_supported(&kdpy->base, format, TRUE)) {
+ format = PIPE_FORMAT_A8R8G8B8_UNORM;
+ if (!kms_display_is_format_supported(&kdpy->base, format, TRUE))
+ format = PIPE_FORMAT_NONE;
+ }
+ if (format == PIPE_FORMAT_NONE) {
+ FREE(kdpy->config);
+ kdpy->config = NULL;
+ return NULL;
+ }
+
+ nconf->color_format = format;
+
+ nconf->scanout_bit = TRUE;
+ }
+
+ configs = MALLOC(sizeof(*configs));
+ if (configs) {
+ configs[0] = &kdpy->config->base;
+ if (num_configs)
+ *num_configs = 1;
+ }
+
+ return configs;
+}
+
+static int
+kms_display_get_param(struct native_display *ndpy,
+ enum native_param_type param)
+{
+ int val;
+
+ switch (param) {
+ default:
+ val = 0;
+ break;
+ }
+
+ return val;
+}
+
+static void
+kms_display_destroy(struct native_display *ndpy)
+{
+ struct kms_display *kdpy = kms_display(ndpy);
+ int i;
+
+ if (kdpy->config)
+ FREE(kdpy->config);
+
+ if (kdpy->connectors) {
+ for (i = 0; i < kdpy->num_connectors; i++) {
+ struct kms_connector *kconn = &kdpy->connectors[i];
+ if (kconn->connector) {
+ drmModeFreeConnector(kconn->connector);
+ FREE(kconn->kms_modes);
+ }
+ }
+ FREE(kdpy->connectors);
+ }
+
+ if (kdpy->shown_surfaces)
+ FREE(kdpy->shown_surfaces);
+
+ if (kdpy->saved_crtcs) {
+ for (i = 0; i < kdpy->resources->count_crtcs; i++) {
+ struct kms_crtc *kcrtc = &kdpy->saved_crtcs[i];
+
+ if (kcrtc->crtc) {
+ /* restore crtc */
+ drmModeSetCrtc(kdpy->fd, kcrtc->crtc->crtc_id,
+ kcrtc->crtc->buffer_id, kcrtc->crtc->x, kcrtc->crtc->y,
+ kcrtc->connectors, kcrtc->num_connectors,
+ &kcrtc->crtc->mode);
+
+ drmModeFreeCrtc(kcrtc->crtc);
+ }
+ }
+ FREE(kdpy->saved_crtcs);
+ }
+
+ if (kdpy->resources)
+ drmModeFreeResources(kdpy->resources);
+
+ if (kdpy->base.screen)
+ kdpy->base.screen->destroy(kdpy->base.screen);
+
+ if (kdpy->fd >= 0)
+ drmClose(kdpy->fd);
+
+ if (kdpy->api && kdpy->api->destroy)
+ kdpy->api->destroy(kdpy->api);
+ FREE(kdpy);
+}
+
+/**
+ * Initialize KMS and pipe screen.
+ */
+static boolean
+kms_display_init_screen(struct native_display *ndpy)
+{
+ struct kms_display *kdpy = kms_display(ndpy);
+ int fd;
+
+ fd = kdpy->fd;
+ if (fd >= 0) {
+ drmVersionPtr version = drmGetVersion(fd);
+ if (!version || strcmp(version->name, kdpy->api->driver_name)) {
+ if (version) {
+ _eglLog(_EGL_WARNING, "unknown driver name %s", version->name);
+ drmFreeVersion(version);
+ }
+ else {
+ _eglLog(_EGL_WARNING, "invalid fd %d", fd);
+ }
+
+ return FALSE;
+ }
+
+ drmFreeVersion(version);
+ }
+ else {
+ fd = drmOpen(kdpy->api->driver_name, NULL);
+ }
+
+ if (fd < 0) {
+ _eglLog(_EGL_WARNING, "failed to open DRM device");
+ return FALSE;
+ }
+
+#if 0
+ if (drmSetMaster(fd)) {
+ _eglLog(_EGL_WARNING, "failed to become DRM master");
+ return FALSE;
+ }
+#endif
+
+ kdpy->base.screen = kdpy->api->create_screen(kdpy->api, fd);
+ if (!kdpy->base.screen) {
+ _eglLog(_EGL_WARNING, "failed to create DRM screen");
+ drmClose(fd);
+ return FALSE;
+ }
+
+ kdpy->fd = fd;
+
+ return TRUE;
+}
+
+static struct native_display_modeset kms_display_modeset = {
+ .get_connectors = kms_display_get_connectors,
+ .get_modes = kms_display_get_modes,
+ .create_scanout_surface = kms_display_create_scanout_surface,
+ .program = kms_display_program
+};
+
+static struct native_display *
+kms_create_display(int fd, struct native_event_handler *event_handler,
+ struct drm_api *api)
+{
+ struct kms_display *kdpy;
+
+ kdpy = CALLOC_STRUCT(kms_display);
+ if (!kdpy)
+ return NULL;
+
+ kdpy->event_handler = event_handler;
+
+ kdpy->api = api;
+ if (!kdpy->api) {
+ _eglLog(_EGL_WARNING, "failed to create DRM API");
+ FREE(kdpy);
+ return NULL;
+ }
+
+ kdpy->fd = fd;
+ if (!kms_display_init_screen(&kdpy->base)) {
+ kms_display_destroy(&kdpy->base);
+ return NULL;
+ }
+
+ /* resources are fixed, unlike crtc, connector, or encoder */
+ kdpy->resources = drmModeGetResources(kdpy->fd);
+ if (!kdpy->resources) {
+ kms_display_destroy(&kdpy->base);
+ return NULL;
+ }
+
+ kdpy->saved_crtcs =
+ CALLOC(kdpy->resources->count_crtcs, sizeof(*kdpy->saved_crtcs));
+ if (!kdpy->saved_crtcs) {
+ kms_display_destroy(&kdpy->base);
+ return NULL;
+ }
+
+ kdpy->shown_surfaces =
+ CALLOC(kdpy->resources->count_crtcs, sizeof(*kdpy->shown_surfaces));
+ if (!kdpy->shown_surfaces) {
+ kms_display_destroy(&kdpy->base);
+ return NULL;
+ }
+
+ kdpy->base.destroy = kms_display_destroy;
+ kdpy->base.get_param = kms_display_get_param;
+ kdpy->base.get_configs = kms_display_get_configs;
+
+ kdpy->base.modeset = &kms_display_modeset;
+
+ return &kdpy->base;
+}
+
+struct native_probe *
+native_create_probe(EGLNativeDisplayType dpy)
+{
+ return NULL;
+}
+
+enum native_probe_result
+native_get_probe_result(struct native_probe *nprobe)
+{
+ return NATIVE_PROBE_UNKNOWN;
+}
+
+/* the api is destroyed with the native display */
+static struct drm_api *drm_api;
+
+const char *
+native_get_name(void)
+{
+ static char kms_name[32];
+
+ if (!drm_api)
+ drm_api = drm_api_create();
+
+ if (drm_api)
+ util_snprintf(kms_name, sizeof(kms_name), "KMS/%s", drm_api->name);
+ else
+ util_snprintf(kms_name, sizeof(kms_name), "KMS");
+
+ return kms_name;
+}
+
+struct native_display *
+native_create_display(EGLNativeDisplayType dpy,
+ struct native_event_handler *event_handler)
+{
+ struct native_display *ndpy = NULL;
+ int fd;
+
+ if (!drm_api)
+ drm_api = drm_api_create();
+
+ if (drm_api) {
+ /* well, this makes fd 0 being ignored */
+ fd = (dpy != EGL_DEFAULT_DISPLAY) ?
+ (int) pointer_to_intptr((void *) dpy) : -1;
+ ndpy = kms_create_display(fd, event_handler, drm_api);
+ }
+
+ return ndpy;
+}
diff --git a/src/gallium/state_trackers/egl/kms/native_kms.h b/src/gallium/state_trackers/egl/kms/native_kms.h
new file mode 100644
index 0000000000..d69c8d38c8
--- /dev/null
+++ b/src/gallium/state_trackers/egl/kms/native_kms.h
@@ -0,0 +1,138 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.8
+ *
+ * Copyright (C) 2010 Chia-I Wu <olv@0xlab.org>
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _NATIVE_KMS_H_
+#define _NATIVE_KMS_H_
+
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "pipe/p_compiler.h"
+#include "util/u_format.h"
+#include "pipe/p_state.h"
+#include "state_tracker/drm_api.h"
+
+#include "common/native.h"
+#include "common/native_helper.h"
+
+struct kms_config;
+struct kms_connector;
+struct kms_mode;
+
+struct kms_crtc {
+ drmModeCrtcPtr crtc;
+ uint32_t connectors[32];
+ int num_connectors;
+};
+
+struct kms_display {
+ struct native_display base;
+
+ struct native_event_handler *event_handler;
+
+ int fd;
+ struct drm_api *api;
+ drmModeResPtr resources;
+ struct kms_config *config;
+
+ struct kms_connector *connectors;
+ int num_connectors;
+
+ struct kms_surface **shown_surfaces;
+ /* save the original settings of the CRTCs */
+ struct kms_crtc *saved_crtcs;
+};
+
+struct kms_framebuffer {
+ struct pipe_resource *texture;
+ boolean is_passive;
+
+ uint32_t buffer_id;
+};
+
+struct kms_surface {
+ struct native_surface base;
+ struct kms_display *kdpy;
+
+ struct resource_surface *rsurf;
+ enum pipe_format color_format;
+ int width, height;
+
+ unsigned int sequence_number;
+ struct kms_framebuffer front_fb, back_fb;
+
+ boolean is_shown;
+ struct kms_crtc current_crtc;
+};
+
+struct kms_config {
+ struct native_config base;
+};
+
+struct kms_connector {
+ struct native_connector base;
+
+ uint32_t connector_id;
+ drmModeConnectorPtr connector;
+ struct kms_mode *kms_modes;
+ int num_modes;
+};
+
+struct kms_mode {
+ struct native_mode base;
+ drmModeModeInfo mode;
+};
+
+static INLINE struct kms_display *
+kms_display(const struct native_display *ndpy)
+{
+ return (struct kms_display *) ndpy;
+}
+
+static INLINE struct kms_surface *
+kms_surface(const struct native_surface *nsurf)
+{
+ return (struct kms_surface *) nsurf;
+}
+
+static INLINE struct kms_config *
+kms_config(const struct native_config *nconf)
+{
+ return (struct kms_config *) nconf;
+}
+
+static INLINE struct kms_connector *
+kms_connector(const struct native_connector *nconn)
+{
+ return (struct kms_connector *) nconn;
+}
+
+static INLINE struct kms_mode *
+kms_mode(const struct native_mode *nmode)
+{
+ return (struct kms_mode *) nmode;
+}
+
+#endif /* _NATIVE_KMS_H_ */
diff --git a/src/gallium/state_trackers/egl/x11/glxinit.c b/src/gallium/state_trackers/egl/x11/glxinit.c
new file mode 100644
index 0000000000..1ed2afd345
--- /dev/null
+++ b/src/gallium/state_trackers/egl/x11/glxinit.c
@@ -0,0 +1,682 @@
+/**
+ * GLX initialization. Code based on glxext.c, glx_query.c, and
+ * glcontextmodes.c under src/glx/. The major difference is that DRI
+ * related code is stripped out.
+ *
+ * If the maintenance of this file takes too much time, we should consider
+ * refactoring glxext.c.
+ */
+
+#include <assert.h>
+#include <X11/Xlib.h>
+#include <X11/Xproto.h>
+#include <X11/extensions/Xext.h>
+#include <X11/extensions/extutil.h>
+#include <sys/time.h>
+
+#include "glxinit.h"
+
+typedef struct GLXGenericGetString
+{
+ CARD8 reqType;
+ CARD8 glxCode;
+ CARD16 length B16;
+ CARD32 for_whom B32;
+ CARD32 name B32;
+} xGLXGenericGetStringReq;
+
+#define sz_xGLXGenericGetStringReq 12
+#define X_GLXGenericGetString 0
+
+/* Extension required boiler plate */
+
+static char *__glXExtensionName = GLX_EXTENSION_NAME;
+static XExtensionInfo *__glXExtensionInfo = NULL;
+
+static int
+__glXCloseDisplay(Display * dpy, XExtCodes * codes)
+{
+ return XextRemoveDisplay(__glXExtensionInfo, dpy);
+}
+
+static /* const */ XExtensionHooks __glXExtensionHooks = {
+ NULL, /* create_gc */
+ NULL, /* copy_gc */
+ NULL, /* flush_gc */
+ NULL, /* free_gc */
+ NULL, /* create_font */
+ NULL, /* free_font */
+ __glXCloseDisplay, /* close_display */
+ NULL, /* wire_to_event */
+ NULL, /* event_to_wire */
+ NULL, /* error */
+ NULL, /* error_string */
+};
+
+XEXT_GENERATE_FIND_DISPLAY(__glXFindDisplay, __glXExtensionInfo,
+ __glXExtensionName, &__glXExtensionHooks,
+ __GLX_NUMBER_EVENTS, NULL)
+
+static GLint
+_gl_convert_from_x_visual_type(int visualType)
+{
+#define NUM_VISUAL_TYPES 6
+ static const int glx_visual_types[NUM_VISUAL_TYPES] = {
+ GLX_STATIC_GRAY, GLX_GRAY_SCALE,
+ GLX_STATIC_COLOR, GLX_PSEUDO_COLOR,
+ GLX_TRUE_COLOR, GLX_DIRECT_COLOR
+ };
+
+ return ((unsigned) visualType < NUM_VISUAL_TYPES)
+ ? glx_visual_types[visualType] : GLX_NONE;
+}
+
+static __GLcontextModes *
+_gl_context_modes_create(unsigned count, size_t minimum_size)
+{
+ const size_t size = (minimum_size > sizeof(__GLcontextModes))
+ ? minimum_size : sizeof(__GLcontextModes);
+ __GLcontextModes *base = NULL;
+ __GLcontextModes **next;
+ unsigned i;
+
+ next = &base;
+ for (i = 0; i < count; i++) {
+ *next = (__GLcontextModes *) Xmalloc(size);
+ if (*next == NULL) {
+ _gl_context_modes_destroy(base);
+ base = NULL;
+ break;
+ }
+
+ memset(*next, 0, size);
+ (*next)->visualID = GLX_DONT_CARE;
+ (*next)->visualType = GLX_DONT_CARE;
+ (*next)->visualRating = GLX_NONE;
+ (*next)->transparentPixel = GLX_NONE;
+ (*next)->transparentRed = GLX_DONT_CARE;
+ (*next)->transparentGreen = GLX_DONT_CARE;
+ (*next)->transparentBlue = GLX_DONT_CARE;
+ (*next)->transparentAlpha = GLX_DONT_CARE;
+ (*next)->transparentIndex = GLX_DONT_CARE;
+ (*next)->xRenderable = GLX_DONT_CARE;
+ (*next)->fbconfigID = GLX_DONT_CARE;
+ (*next)->swapMethod = GLX_SWAP_UNDEFINED_OML;
+ (*next)->bindToTextureRgb = GLX_DONT_CARE;
+ (*next)->bindToTextureRgba = GLX_DONT_CARE;
+ (*next)->bindToMipmapTexture = GLX_DONT_CARE;
+ (*next)->bindToTextureTargets = GLX_DONT_CARE;
+ (*next)->yInverted = GLX_DONT_CARE;
+
+ next = &((*next)->next);
+ }
+
+ return base;
+}
+
+_X_HIDDEN void
+_gl_context_modes_destroy(__GLcontextModes * modes)
+{
+ while (modes != NULL) {
+ __GLcontextModes *const next = modes->next;
+
+ Xfree(modes);
+ modes = next;
+ }
+}
+
+_X_HIDDEN char *
+__glXQueryServerString(Display * dpy, int opcode, CARD32 screen, CARD32 name)
+{
+ xGLXGenericGetStringReq *req;
+ xGLXSingleReply reply;
+ int length;
+ int numbytes;
+ char *buf;
+ CARD32 for_whom = screen;
+ CARD32 glxCode = X_GLXQueryServerString;
+
+
+ LockDisplay(dpy);
+
+
+ /* All of the GLX protocol requests for getting a string from the server
+ * look the same. The exact meaning of the for_whom field is usually
+ * either the screen number (for glXQueryServerString) or the context tag
+ * (for GLXSingle).
+ */
+
+ GetReq(GLXGenericGetString, req);
+ req->reqType = opcode;
+ req->glxCode = glxCode;
+ req->for_whom = for_whom;
+ req->name = name;
+
+ _XReply(dpy, (xReply *) & reply, 0, False);
+
+ length = reply.length * 4;
+ numbytes = reply.size;
+
+ buf = (char *) Xmalloc(numbytes);
+ if (buf != NULL) {
+ _XRead(dpy, buf, numbytes);
+ length -= numbytes;
+ }
+
+ _XEatData(dpy, length);
+
+ UnlockDisplay(dpy);
+ SyncHandle();
+
+ return buf;
+}
+
+/************************************************************************/
+/*
+** Free the per screen configs data as well as the array of
+** __glXScreenConfigs.
+*/
+static void
+FreeScreenConfigs(__GLXdisplayPrivate * priv)
+{
+ __GLXscreenConfigs *psc;
+ GLint i, screens;
+
+ /* Free screen configuration information */
+ psc = priv->screenConfigs;
+ screens = ScreenCount(priv->dpy);
+ for (i = 0; i < screens; i++, psc++) {
+ if (psc->configs) {
+ _gl_context_modes_destroy(psc->configs);
+ psc->configs = NULL; /* NOTE: just for paranoia */
+ }
+ if (psc->visuals) {
+ _gl_context_modes_destroy(psc->visuals);
+ psc->visuals = NULL; /* NOTE: just for paranoia */
+ }
+ Xfree((char *) psc->serverGLXexts);
+ }
+ XFree((char *) priv->screenConfigs);
+ priv->screenConfigs = NULL;
+}
+
+/*
+** Release the private memory referred to in a display private
+** structure. The caller will free the extension structure.
+*/
+static int
+__glXFreeDisplayPrivate(XExtData * extension)
+{
+ __GLXdisplayPrivate *priv;
+
+ priv = (__GLXdisplayPrivate *) extension->private_data;
+ FreeScreenConfigs(priv);
+ if (priv->serverGLXvendor) {
+ Xfree((char *) priv->serverGLXvendor);
+ priv->serverGLXvendor = 0x0; /* to protect against double free's */
+ }
+ if (priv->serverGLXversion) {
+ Xfree((char *) priv->serverGLXversion);
+ priv->serverGLXversion = 0x0; /* to protect against double free's */
+ }
+
+ Xfree((char *) priv);
+ return 0;
+}
+
+/************************************************************************/
+
+/*
+** Query the version of the GLX extension. This procedure works even if
+** the client extension is not completely set up.
+*/
+static Bool
+QueryVersion(Display * dpy, int opcode, int *major, int *minor)
+{
+ xGLXQueryVersionReq *req;
+ xGLXQueryVersionReply reply;
+
+ /* Send the glXQueryVersion request */
+ LockDisplay(dpy);
+ GetReq(GLXQueryVersion, req);
+ req->reqType = opcode;
+ req->glxCode = X_GLXQueryVersion;
+ req->majorVersion = GLX_MAJOR_VERSION;
+ req->minorVersion = GLX_MINOR_VERSION;
+ _XReply(dpy, (xReply *) & reply, 0, False);
+ UnlockDisplay(dpy);
+ SyncHandle();
+
+ if (reply.majorVersion != GLX_MAJOR_VERSION) {
+ /*
+ ** The server does not support the same major release as this
+ ** client.
+ */
+ return GL_FALSE;
+ }
+ *major = reply.majorVersion;
+ *minor = min(reply.minorVersion, GLX_MINOR_VERSION);
+ return GL_TRUE;
+}
+
+_X_HIDDEN void
+__glXInitializeVisualConfigFromTags(__GLcontextModes * config, int count,
+ const INT32 * bp, Bool tagged_only,
+ Bool fbconfig_style_tags)
+{
+ int i;
+
+ if (!tagged_only) {
+ /* Copy in the first set of properties */
+ config->visualID = *bp++;
+
+ config->visualType = _gl_convert_from_x_visual_type(*bp++);
+
+ config->rgbMode = *bp++;
+
+ config->redBits = *bp++;
+ config->greenBits = *bp++;
+ config->blueBits = *bp++;
+ config->alphaBits = *bp++;
+ config->accumRedBits = *bp++;
+ config->accumGreenBits = *bp++;
+ config->accumBlueBits = *bp++;
+ config->accumAlphaBits = *bp++;
+
+ config->doubleBufferMode = *bp++;
+ config->stereoMode = *bp++;
+
+ config->rgbBits = *bp++;
+ config->depthBits = *bp++;
+ config->stencilBits = *bp++;
+ config->numAuxBuffers = *bp++;
+ config->level = *bp++;
+
+ count -= __GLX_MIN_CONFIG_PROPS;
+ }
+
+ /*
+ ** Additional properties may be in a list at the end
+ ** of the reply. They are in pairs of property type
+ ** and property value.
+ */
+
+#define FETCH_OR_SET(tag) \
+ config-> tag = ( fbconfig_style_tags ) ? *bp++ : 1
+
+ for (i = 0; i < count; i += 2) {
+ switch (*bp++) {
+ case GLX_RGBA:
+ FETCH_OR_SET(rgbMode);
+ break;
+ case GLX_BUFFER_SIZE:
+ config->rgbBits = *bp++;
+ break;
+ case GLX_LEVEL:
+ config->level = *bp++;
+ break;
+ case GLX_DOUBLEBUFFER:
+ FETCH_OR_SET(doubleBufferMode);
+ break;
+ case GLX_STEREO:
+ FETCH_OR_SET(stereoMode);
+ break;
+ case GLX_AUX_BUFFERS:
+ config->numAuxBuffers = *bp++;
+ break;
+ case GLX_RED_SIZE:
+ config->redBits = *bp++;
+ break;
+ case GLX_GREEN_SIZE:
+ config->greenBits = *bp++;
+ break;
+ case GLX_BLUE_SIZE:
+ config->blueBits = *bp++;
+ break;
+ case GLX_ALPHA_SIZE:
+ config->alphaBits = *bp++;
+ break;
+ case GLX_DEPTH_SIZE:
+ config->depthBits = *bp++;
+ break;
+ case GLX_STENCIL_SIZE:
+ config->stencilBits = *bp++;
+ break;
+ case GLX_ACCUM_RED_SIZE:
+ config->accumRedBits = *bp++;
+ break;
+ case GLX_ACCUM_GREEN_SIZE:
+ config->accumGreenBits = *bp++;
+ break;
+ case GLX_ACCUM_BLUE_SIZE:
+ config->accumBlueBits = *bp++;
+ break;
+ case GLX_ACCUM_ALPHA_SIZE:
+ config->accumAlphaBits = *bp++;
+ break;
+ case GLX_VISUAL_CAVEAT_EXT:
+ config->visualRating = *bp++;
+ break;
+ case GLX_X_VISUAL_TYPE:
+ config->visualType = *bp++;
+ break;
+ case GLX_TRANSPARENT_TYPE:
+ config->transparentPixel = *bp++;
+ break;
+ case GLX_TRANSPARENT_INDEX_VALUE:
+ config->transparentIndex = *bp++;
+ break;
+ case GLX_TRANSPARENT_RED_VALUE:
+ config->transparentRed = *bp++;
+ break;
+ case GLX_TRANSPARENT_GREEN_VALUE:
+ config->transparentGreen = *bp++;
+ break;
+ case GLX_TRANSPARENT_BLUE_VALUE:
+ config->transparentBlue = *bp++;
+ break;
+ case GLX_TRANSPARENT_ALPHA_VALUE:
+ config->transparentAlpha = *bp++;
+ break;
+ case GLX_VISUAL_ID:
+ config->visualID = *bp++;
+ break;
+ case GLX_DRAWABLE_TYPE:
+ config->drawableType = *bp++;
+ break;
+ case GLX_RENDER_TYPE:
+ config->renderType = *bp++;
+ break;
+ case GLX_X_RENDERABLE:
+ config->xRenderable = *bp++;
+ break;
+ case GLX_FBCONFIG_ID:
+ config->fbconfigID = *bp++;
+ break;
+ case GLX_MAX_PBUFFER_WIDTH:
+ config->maxPbufferWidth = *bp++;
+ break;
+ case GLX_MAX_PBUFFER_HEIGHT:
+ config->maxPbufferHeight = *bp++;
+ break;
+ case GLX_MAX_PBUFFER_PIXELS:
+ config->maxPbufferPixels = *bp++;
+ break;
+ case GLX_OPTIMAL_PBUFFER_WIDTH_SGIX:
+ config->optimalPbufferWidth = *bp++;
+ break;
+ case GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX:
+ config->optimalPbufferHeight = *bp++;
+ break;
+ case GLX_VISUAL_SELECT_GROUP_SGIX:
+ config->visualSelectGroup = *bp++;
+ break;
+ case GLX_SWAP_METHOD_OML:
+ config->swapMethod = *bp++;
+ break;
+ case GLX_SAMPLE_BUFFERS_SGIS:
+ config->sampleBuffers = *bp++;
+ break;
+ case GLX_SAMPLES_SGIS:
+ config->samples = *bp++;
+ break;
+ case GLX_BIND_TO_TEXTURE_RGB_EXT:
+ config->bindToTextureRgb = *bp++;
+ break;
+ case GLX_BIND_TO_TEXTURE_RGBA_EXT:
+ config->bindToTextureRgba = *bp++;
+ break;
+ case GLX_BIND_TO_MIPMAP_TEXTURE_EXT:
+ config->bindToMipmapTexture = *bp++;
+ break;
+ case GLX_BIND_TO_TEXTURE_TARGETS_EXT:
+ config->bindToTextureTargets = *bp++;
+ break;
+ case GLX_Y_INVERTED_EXT:
+ config->yInverted = *bp++;
+ break;
+ case None:
+ i = count;
+ break;
+ default:
+ break;
+ }
+ }
+
+ config->renderType =
+ (config->rgbMode) ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT;
+
+ config->haveAccumBuffer = ((config->accumRedBits +
+ config->accumGreenBits +
+ config->accumBlueBits +
+ config->accumAlphaBits) > 0);
+ config->haveDepthBuffer = (config->depthBits > 0);
+ config->haveStencilBuffer = (config->stencilBits > 0);
+}
+
+static __GLcontextModes *
+createConfigsFromProperties(Display * dpy, int nvisuals, int nprops,
+ int screen, GLboolean tagged_only)
+{
+ INT32 buf[__GLX_TOTAL_CONFIG], *props;
+ unsigned prop_size;
+ __GLcontextModes *modes, *m;
+ int i;
+
+ if (nprops == 0)
+ return NULL;
+
+ /* FIXME: Is the __GLX_MIN_CONFIG_PROPS test correct for FBconfigs? */
+
+ /* Check number of properties */
+ if (nprops < __GLX_MIN_CONFIG_PROPS || nprops > __GLX_MAX_CONFIG_PROPS)
+ return NULL;
+
+ /* Allocate memory for our config structure */
+ modes = _gl_context_modes_create(nvisuals, sizeof(__GLcontextModes));
+ if (!modes)
+ return NULL;
+
+ prop_size = nprops * __GLX_SIZE_INT32;
+ if (prop_size <= sizeof(buf))
+ props = buf;
+ else
+ props = Xmalloc(prop_size);
+
+ /* Read each config structure and convert it into our format */
+ m = modes;
+ for (i = 0; i < nvisuals; i++) {
+ _XRead(dpy, (char *) props, prop_size);
+ /* Older X servers don't send this so we default it here. */
+ m->drawableType = GLX_WINDOW_BIT;
+ __glXInitializeVisualConfigFromTags(m, nprops, props,
+ tagged_only, GL_TRUE);
+ m->screen = screen;
+ m = m->next;
+ }
+
+ if (props != buf)
+ Xfree(props);
+
+ return modes;
+}
+
+static GLboolean
+getVisualConfigs(Display * dpy, __GLXdisplayPrivate * priv, int screen)
+{
+ xGLXGetVisualConfigsReq *req;
+ __GLXscreenConfigs *psc;
+ xGLXGetVisualConfigsReply reply;
+
+ LockDisplay(dpy);
+
+ psc = priv->screenConfigs + screen;
+ psc->visuals = NULL;
+ GetReq(GLXGetVisualConfigs, req);
+ req->reqType = priv->majorOpcode;
+ req->glxCode = X_GLXGetVisualConfigs;
+ req->screen = screen;
+
+ if (!_XReply(dpy, (xReply *) & reply, 0, False))
+ goto out;
+
+ psc->visuals = createConfigsFromProperties(dpy,
+ reply.numVisuals,
+ reply.numProps,
+ screen, GL_FALSE);
+
+ out:
+ UnlockDisplay(dpy);
+ return psc->visuals != NULL;
+}
+
+static GLboolean
+getFBConfigs(Display * dpy, __GLXdisplayPrivate * priv, int screen)
+{
+ xGLXGetFBConfigsReq *fb_req;
+ xGLXGetFBConfigsSGIXReq *sgi_req;
+ xGLXVendorPrivateWithReplyReq *vpreq;
+ xGLXGetFBConfigsReply reply;
+ __GLXscreenConfigs *psc;
+
+ psc = priv->screenConfigs + screen;
+ psc->serverGLXexts =
+ __glXQueryServerString(dpy, priv->majorOpcode, screen, GLX_EXTENSIONS);
+
+ LockDisplay(dpy);
+
+ psc->configs = NULL;
+ if (atof(priv->serverGLXversion) >= 1.3) {
+ GetReq(GLXGetFBConfigs, fb_req);
+ fb_req->reqType = priv->majorOpcode;
+ fb_req->glxCode = X_GLXGetFBConfigs;
+ fb_req->screen = screen;
+ }
+ else if (strstr(psc->serverGLXexts, "GLX_SGIX_fbconfig") != NULL) {
+ GetReqExtra(GLXVendorPrivateWithReply,
+ sz_xGLXGetFBConfigsSGIXReq +
+ sz_xGLXVendorPrivateWithReplyReq, vpreq);
+ sgi_req = (xGLXGetFBConfigsSGIXReq *) vpreq;
+ sgi_req->reqType = priv->majorOpcode;
+ sgi_req->glxCode = X_GLXVendorPrivateWithReply;
+ sgi_req->vendorCode = X_GLXvop_GetFBConfigsSGIX;
+ sgi_req->screen = screen;
+ }
+ else
+ goto out;
+
+ if (!_XReply(dpy, (xReply *) & reply, 0, False))
+ goto out;
+
+ psc->configs = createConfigsFromProperties(dpy,
+ reply.numFBConfigs,
+ reply.numAttribs * 2,
+ screen, GL_TRUE);
+
+ out:
+ UnlockDisplay(dpy);
+ return psc->configs != NULL;
+}
+
+static GLboolean
+AllocAndFetchScreenConfigs(Display * dpy, __GLXdisplayPrivate * priv)
+{
+ __GLXscreenConfigs *psc;
+ GLint i, screens;
+
+ /*
+ ** First allocate memory for the array of per screen configs.
+ */
+ screens = ScreenCount(dpy);
+ psc = (__GLXscreenConfigs *) Xmalloc(screens * sizeof(__GLXscreenConfigs));
+ if (!psc) {
+ return GL_FALSE;
+ }
+ memset(psc, 0, screens * sizeof(__GLXscreenConfigs));
+ priv->screenConfigs = psc;
+
+ priv->serverGLXversion =
+ __glXQueryServerString(dpy, priv->majorOpcode, 0, GLX_VERSION);
+ if (priv->serverGLXversion == NULL) {
+ FreeScreenConfigs(priv);
+ return GL_FALSE;
+ }
+
+ for (i = 0; i < screens; i++, psc++) {
+ getFBConfigs(dpy, priv, i);
+ getVisualConfigs(dpy, priv, i);
+ psc->scr = i;
+ psc->dpy = dpy;
+ }
+
+ SyncHandle();
+
+ return GL_TRUE;
+}
+
+_X_HIDDEN __GLXdisplayPrivate *
+__glXInitialize(Display * dpy)
+{
+ XExtDisplayInfo *info = __glXFindDisplay(dpy);
+ XExtData **privList, *private, *found;
+ __GLXdisplayPrivate *dpyPriv;
+ XEDataObject dataObj;
+ int major, minor;
+
+ if (!XextHasExtension(info))
+ return NULL;
+
+ /* See if a display private already exists. If so, return it */
+ dataObj.display = dpy;
+ privList = XEHeadOfExtensionList(dataObj);
+ found = XFindOnExtensionList(privList, info->codes->extension);
+ if (found)
+ return (__GLXdisplayPrivate *) found->private_data;
+
+ /* See if the versions are compatible */
+ if (!QueryVersion(dpy, info->codes->major_opcode, &major, &minor))
+ return NULL;
+
+ /*
+ ** Allocate memory for all the pieces needed for this buffer.
+ */
+ private = (XExtData *) Xmalloc(sizeof(XExtData));
+ if (!private)
+ return NULL;
+ dpyPriv = (__GLXdisplayPrivate *) Xcalloc(1, sizeof(__GLXdisplayPrivate));
+ if (!dpyPriv) {
+ Xfree(private);
+ return NULL;
+ }
+
+ /*
+ ** Init the display private and then read in the screen config
+ ** structures from the server.
+ */
+ dpyPriv->majorOpcode = info->codes->major_opcode;
+ dpyPriv->majorVersion = major;
+ dpyPriv->minorVersion = minor;
+ dpyPriv->dpy = dpy;
+
+ dpyPriv->serverGLXvendor = NULL;
+ dpyPriv->serverGLXversion = NULL;
+
+ if (!AllocAndFetchScreenConfigs(dpy, dpyPriv)) {
+ Xfree(dpyPriv);
+ Xfree(private);
+ return NULL;
+ }
+
+ /*
+ ** Fill in the private structure. This is the actual structure that
+ ** hangs off of the Display structure. Our private structure is
+ ** referred to by this structure. Got that?
+ */
+ private->number = info->codes->extension;
+ private->next = 0;
+ private->free_private = __glXFreeDisplayPrivate;
+ private->private_data = (char *) dpyPriv;
+ XAddToExtensionList(privList, private);
+
+ return dpyPriv;
+}
diff --git a/src/gallium/state_trackers/egl/x11/glxinit.h b/src/gallium/state_trackers/egl/x11/glxinit.h
new file mode 100644
index 0000000000..1cc7c460fe
--- /dev/null
+++ b/src/gallium/state_trackers/egl/x11/glxinit.h
@@ -0,0 +1,11 @@
+#ifndef GLXINIT_INCLUDED
+#define GLXINIT_INCLUDED
+
+#include <X11/Xlib.h>
+#include "glxclient.h"
+
+/* this is used by DRI loaders */
+extern void
+_gl_context_modes_destroy(__GLcontextModes * modes);
+
+#endif /* GLXINIT_INCLUDED */
diff --git a/src/gallium/state_trackers/egl/x11/native_dri2.c b/src/gallium/state_trackers/egl/x11/native_dri2.c
new file mode 100644
index 0000000000..3f802dd713
--- /dev/null
+++ b/src/gallium/state_trackers/egl/x11/native_dri2.c
@@ -0,0 +1,794 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.8
+ *
+ * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org>
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "util/u_memory.h"
+#include "util/u_math.h"
+#include "util/u_format.h"
+#include "util/u_inlines.h"
+#include "util/u_hash_table.h"
+#include "pipe/p_compiler.h"
+#include "pipe/p_screen.h"
+#include "pipe/p_context.h"
+#include "pipe/p_state.h"
+#include "state_tracker/drm_api.h"
+#include "egllog.h"
+
+#include "native_x11.h"
+#include "x11_screen.h"
+
+enum dri2_surface_type {
+ DRI2_SURFACE_TYPE_WINDOW,
+ DRI2_SURFACE_TYPE_PIXMAP,
+};
+
+struct dri2_display {
+ struct native_display base;
+ Display *dpy;
+ boolean own_dpy;
+
+ struct native_event_handler *event_handler;
+
+ struct drm_api *api;
+ struct x11_screen *xscr;
+ int xscr_number;
+ const char *dri_driver;
+ int dri_major, dri_minor;
+
+ struct dri2_config *configs;
+ int num_configs;
+
+ struct util_hash_table *surfaces;
+};
+
+struct dri2_surface {
+ struct native_surface base;
+ Drawable drawable;
+ enum dri2_surface_type type;
+ enum pipe_format color_format;
+ struct dri2_display *dri2dpy;
+
+ unsigned int server_stamp;
+ unsigned int client_stamp;
+ int width, height;
+ struct pipe_resource *textures[NUM_NATIVE_ATTACHMENTS];
+ uint valid_mask;
+
+ boolean have_back, have_fake;
+
+ struct x11_drawable_buffer *last_xbufs;
+ int last_num_xbufs;
+};
+
+struct dri2_config {
+ struct native_config base;
+};
+
+static INLINE struct dri2_display *
+dri2_display(const struct native_display *ndpy)
+{
+ return (struct dri2_display *) ndpy;
+}
+
+static INLINE struct dri2_surface *
+dri2_surface(const struct native_surface *nsurf)
+{
+ return (struct dri2_surface *) nsurf;
+}
+
+static INLINE struct dri2_config *
+dri2_config(const struct native_config *nconf)
+{
+ return (struct dri2_config *) nconf;
+}
+
+/**
+ * Process the buffers returned by the server.
+ */
+static void
+dri2_surface_process_drawable_buffers(struct native_surface *nsurf,
+ struct x11_drawable_buffer *xbufs,
+ int num_xbufs)
+{
+ struct dri2_surface *dri2surf = dri2_surface(nsurf);
+ struct dri2_display *dri2dpy = dri2surf->dri2dpy;
+ struct pipe_resource templ;
+ struct winsys_handle whandle;
+ uint valid_mask;
+ int i;
+
+ /* free the old textures */
+ for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++)
+ pipe_resource_reference(&dri2surf->textures[i], NULL);
+ dri2surf->valid_mask = 0x0;
+
+ dri2surf->have_back = FALSE;
+ dri2surf->have_fake = FALSE;
+
+ if (!xbufs)
+ return;
+
+ memset(&templ, 0, sizeof(templ));
+ templ.target = PIPE_TEXTURE_2D;
+ templ.last_level = 0;
+ templ.width0 = dri2surf->width;
+ templ.height0 = dri2surf->height;
+ templ.depth0 = 1;
+ templ.format = dri2surf->color_format;
+ templ.bind = PIPE_BIND_RENDER_TARGET;
+
+ valid_mask = 0x0;
+ for (i = 0; i < num_xbufs; i++) {
+ struct x11_drawable_buffer *xbuf = &xbufs[i];
+ const char *desc;
+ enum native_attachment natt;
+
+ switch (xbuf->attachment) {
+ case DRI2BufferFrontLeft:
+ natt = NATIVE_ATTACHMENT_FRONT_LEFT;
+ desc = "DRI2 Front Buffer";
+ break;
+ case DRI2BufferFakeFrontLeft:
+ natt = NATIVE_ATTACHMENT_FRONT_LEFT;
+ desc = "DRI2 Fake Front Buffer";
+ dri2surf->have_fake = TRUE;
+ break;
+ case DRI2BufferBackLeft:
+ natt = NATIVE_ATTACHMENT_BACK_LEFT;
+ desc = "DRI2 Back Buffer";
+ dri2surf->have_back = TRUE;
+ break;
+ default:
+ desc = NULL;
+ break;
+ }
+
+ if (!desc || dri2surf->textures[natt]) {
+ if (!desc)
+ _eglLog(_EGL_WARNING, "unknown buffer %d", xbuf->attachment);
+ else
+ _eglLog(_EGL_WARNING, "both real and fake front buffers are listed");
+ continue;
+ }
+
+ memset(&whandle, 0, sizeof(whandle));
+ whandle.stride = xbuf->pitch;
+ whandle.handle = xbuf->name;
+ dri2surf->textures[natt] = dri2dpy->base.screen->resource_from_handle(
+ dri2dpy->base.screen, &templ, &whandle);
+ if (dri2surf->textures[natt])
+ valid_mask |= 1 << natt;
+ }
+
+ dri2surf->valid_mask = valid_mask;
+}
+
+/**
+ * Get the buffers from the server.
+ */
+static void
+dri2_surface_get_buffers(struct native_surface *nsurf, uint buffer_mask)
+{
+ struct dri2_surface *dri2surf = dri2_surface(nsurf);
+ struct dri2_display *dri2dpy = dri2surf->dri2dpy;
+ unsigned int dri2atts[NUM_NATIVE_ATTACHMENTS * 2];
+ int num_ins, num_outs, att;
+ struct x11_drawable_buffer *xbufs;
+ uint bpp = util_format_get_blocksizebits(dri2surf->color_format);
+ boolean with_format = FALSE; /* never ask for depth/stencil */
+
+ /* We must get the front on servers which doesn't support with format
+ * due to a silly bug in core dri2. You can't copy to/from a buffer
+ * that you haven't requested and you recive BadValue errors */
+ if (dri2surf->dri2dpy->dri_minor < 1) {
+ with_format = FALSE;
+ buffer_mask |= (1 << NATIVE_ATTACHMENT_FRONT_LEFT);
+ }
+
+ /* prepare the attachments */
+ num_ins = 0;
+ for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) {
+ if (native_attachment_mask_test(buffer_mask, att)) {
+ unsigned int dri2att;
+
+ switch (att) {
+ case NATIVE_ATTACHMENT_FRONT_LEFT:
+ dri2att = DRI2BufferFrontLeft;
+ break;
+ case NATIVE_ATTACHMENT_BACK_LEFT:
+ dri2att = DRI2BufferBackLeft;
+ break;
+ case NATIVE_ATTACHMENT_FRONT_RIGHT:
+ dri2att = DRI2BufferFrontRight;
+ break;
+ case NATIVE_ATTACHMENT_BACK_RIGHT:
+ dri2att = DRI2BufferBackRight;
+ break;
+ default:
+ assert(0);
+ dri2att = 0;
+ break;
+ }
+
+ dri2atts[num_ins++] = dri2att;
+ if (with_format)
+ dri2atts[num_ins++] = bpp;
+ }
+ }
+ if (with_format)
+ num_ins /= 2;
+
+ xbufs = x11_drawable_get_buffers(dri2dpy->xscr, dri2surf->drawable,
+ &dri2surf->width, &dri2surf->height,
+ dri2atts, with_format, num_ins, &num_outs);
+
+ /* we should be able to do better... */
+ if (xbufs && dri2surf->last_num_xbufs == num_outs &&
+ memcmp(dri2surf->last_xbufs, xbufs, sizeof(*xbufs) * num_outs) == 0) {
+ FREE(xbufs);
+ dri2surf->client_stamp = dri2surf->server_stamp;
+ return;
+ }
+
+ dri2_surface_process_drawable_buffers(&dri2surf->base, xbufs, num_outs);
+
+ dri2surf->server_stamp++;
+ dri2surf->client_stamp = dri2surf->server_stamp;
+
+ if (dri2surf->last_xbufs)
+ FREE(dri2surf->last_xbufs);
+ dri2surf->last_xbufs = xbufs;
+ dri2surf->last_num_xbufs = num_outs;
+}
+
+/**
+ * Update the buffers of the surface. This is a slow function due to the
+ * round-trip to the server.
+ */
+static boolean
+dri2_surface_update_buffers(struct native_surface *nsurf, uint buffer_mask)
+{
+ struct dri2_surface *dri2surf = dri2_surface(nsurf);
+
+ dri2_surface_get_buffers(&dri2surf->base, buffer_mask);
+
+ return ((dri2surf->valid_mask & buffer_mask) == buffer_mask);
+}
+
+/**
+ * Return TRUE if the surface receives DRI2_InvalidateBuffers events.
+ */
+static INLINE boolean
+dri2_surface_receive_events(struct native_surface *nsurf)
+{
+ struct dri2_surface *dri2surf = dri2_surface(nsurf);
+ return (dri2surf->dri2dpy->dri_minor >= 3);
+}
+
+static boolean
+dri2_surface_flush_frontbuffer(struct native_surface *nsurf)
+{
+ struct dri2_surface *dri2surf = dri2_surface(nsurf);
+ struct dri2_display *dri2dpy = dri2surf->dri2dpy;
+
+ /* copy to real front buffer */
+ if (dri2surf->have_fake)
+ x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
+ 0, 0, dri2surf->width, dri2surf->height,
+ DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
+
+ /* force buffers to be updated in next validation call */
+ if (!dri2_surface_receive_events(&dri2surf->base)) {
+ dri2surf->server_stamp++;
+ dri2dpy->event_handler->invalid_surface(&dri2dpy->base,
+ &dri2surf->base, dri2surf->server_stamp);
+ }
+
+ return TRUE;
+}
+
+static boolean
+dri2_surface_swap_buffers(struct native_surface *nsurf)
+{
+ struct dri2_surface *dri2surf = dri2_surface(nsurf);
+ struct dri2_display *dri2dpy = dri2surf->dri2dpy;
+
+ /* copy to front buffer */
+ if (dri2surf->have_back)
+ x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
+ 0, 0, dri2surf->width, dri2surf->height,
+ DRI2BufferBackLeft, DRI2BufferFrontLeft);
+
+ /* and update fake front buffer */
+ if (dri2surf->have_fake)
+ x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
+ 0, 0, dri2surf->width, dri2surf->height,
+ DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
+
+ /* force buffers to be updated in next validation call */
+ if (!dri2_surface_receive_events(&dri2surf->base)) {
+ dri2surf->server_stamp++;
+ dri2dpy->event_handler->invalid_surface(&dri2dpy->base,
+ &dri2surf->base, dri2surf->server_stamp);
+ }
+
+ return TRUE;
+}
+
+static boolean
+dri2_surface_validate(struct native_surface *nsurf, uint attachment_mask,
+ unsigned int *seq_num, struct pipe_resource **textures,
+ int *width, int *height)
+{
+ struct dri2_surface *dri2surf = dri2_surface(nsurf);
+
+ if (dri2surf->server_stamp != dri2surf->client_stamp ||
+ (dri2surf->valid_mask & attachment_mask) != attachment_mask) {
+ if (!dri2_surface_update_buffers(&dri2surf->base, attachment_mask))
+ return FALSE;
+ }
+
+ if (seq_num)
+ *seq_num = dri2surf->client_stamp;
+
+ if (textures) {
+ int att;
+ for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) {
+ if (native_attachment_mask_test(attachment_mask, att)) {
+ struct pipe_resource *ptex = dri2surf->textures[att];
+
+ textures[att] = NULL;
+ pipe_resource_reference(&textures[att], ptex);
+ }
+ }
+ }
+
+ if (width)
+ *width = dri2surf->width;
+ if (height)
+ *height = dri2surf->height;
+
+ return TRUE;
+}
+
+static void
+dri2_surface_wait(struct native_surface *nsurf)
+{
+ struct dri2_surface *dri2surf = dri2_surface(nsurf);
+ struct dri2_display *dri2dpy = dri2surf->dri2dpy;
+
+ if (dri2surf->have_fake) {
+ x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
+ 0, 0, dri2surf->width, dri2surf->height,
+ DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
+ }
+}
+
+static void
+dri2_surface_destroy(struct native_surface *nsurf)
+{
+ struct dri2_surface *dri2surf = dri2_surface(nsurf);
+ int i;
+
+ if (dri2surf->last_xbufs)
+ FREE(dri2surf->last_xbufs);
+
+ for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) {
+ struct pipe_resource *ptex = dri2surf->textures[i];
+ pipe_resource_reference(&ptex, NULL);
+ }
+
+ if (dri2surf->drawable) {
+ x11_drawable_enable_dri2(dri2surf->dri2dpy->xscr,
+ dri2surf->drawable, FALSE);
+
+ util_hash_table_remove(dri2surf->dri2dpy->surfaces,
+ (void *) dri2surf->drawable);
+ }
+ FREE(dri2surf);
+}
+
+static struct dri2_surface *
+dri2_display_create_surface(struct native_display *ndpy,
+ enum dri2_surface_type type,
+ Drawable drawable,
+ const struct native_config *nconf)
+{
+ struct dri2_display *dri2dpy = dri2_display(ndpy);
+ struct dri2_config *dri2conf = dri2_config(nconf);
+ struct dri2_surface *dri2surf;
+
+ dri2surf = CALLOC_STRUCT(dri2_surface);
+ if (!dri2surf)
+ return NULL;
+
+ dri2surf->dri2dpy = dri2dpy;
+ dri2surf->type = type;
+ dri2surf->drawable = drawable;
+ dri2surf->color_format = dri2conf->base.color_format;
+
+ dri2surf->base.destroy = dri2_surface_destroy;
+ dri2surf->base.swap_buffers = dri2_surface_swap_buffers;
+ dri2surf->base.flush_frontbuffer = dri2_surface_flush_frontbuffer;
+ dri2surf->base.validate = dri2_surface_validate;
+ dri2surf->base.wait = dri2_surface_wait;
+
+ if (drawable) {
+ x11_drawable_enable_dri2(dri2dpy->xscr, drawable, TRUE);
+ /* initialize the geometry */
+ dri2_surface_update_buffers(&dri2surf->base, 0x0);
+
+ util_hash_table_set(dri2surf->dri2dpy->surfaces,
+ (void *) dri2surf->drawable, (void *) &dri2surf->base);
+ }
+
+ return dri2surf;
+}
+
+static struct native_surface *
+dri2_display_create_window_surface(struct native_display *ndpy,
+ EGLNativeWindowType win,
+ const struct native_config *nconf)
+{
+ struct dri2_surface *dri2surf;
+
+ dri2surf = dri2_display_create_surface(ndpy, DRI2_SURFACE_TYPE_WINDOW,
+ (Drawable) win, nconf);
+ return (dri2surf) ? &dri2surf->base : NULL;
+}
+
+static struct native_surface *
+dri2_display_create_pixmap_surface(struct native_display *ndpy,
+ EGLNativePixmapType pix,
+ const struct native_config *nconf)
+{
+ struct dri2_surface *dri2surf;
+
+ dri2surf = dri2_display_create_surface(ndpy, DRI2_SURFACE_TYPE_PIXMAP,
+ (Drawable) pix, nconf);
+ return (dri2surf) ? &dri2surf->base : NULL;
+}
+
+static int
+choose_color_format(const __GLcontextModes *mode, enum pipe_format formats[32])
+{
+ int count = 0;
+
+ switch (mode->rgbBits) {
+ case 32:
+ formats[count++] = PIPE_FORMAT_B8G8R8A8_UNORM;
+ formats[count++] = PIPE_FORMAT_A8R8G8B8_UNORM;
+ break;
+ case 24:
+ formats[count++] = PIPE_FORMAT_B8G8R8X8_UNORM;
+ formats[count++] = PIPE_FORMAT_X8R8G8B8_UNORM;
+ formats[count++] = PIPE_FORMAT_B8G8R8A8_UNORM;
+ formats[count++] = PIPE_FORMAT_A8R8G8B8_UNORM;
+ break;
+ case 16:
+ formats[count++] = PIPE_FORMAT_B5G6R5_UNORM;
+ break;
+ default:
+ break;
+ }
+
+ return count;
+}
+
+static boolean
+is_format_supported(struct pipe_screen *screen,
+ enum pipe_format fmt, unsigned sample_count, boolean is_color)
+{
+ return screen->is_format_supported(screen, fmt, PIPE_TEXTURE_2D, sample_count,
+ (is_color) ? PIPE_BIND_RENDER_TARGET :
+ PIPE_BIND_DEPTH_STENCIL, 0);
+}
+
+static boolean
+dri2_display_convert_config(struct native_display *ndpy,
+ const __GLcontextModes *mode,
+ struct native_config *nconf)
+{
+ enum pipe_format formats[32];
+ int num_formats, i;
+ int sample_count = 0;
+
+ if (!(mode->renderType & GLX_RGBA_BIT) || !mode->rgbMode)
+ return FALSE;
+
+ /* skip single-buffered configs */
+ if (!mode->doubleBufferMode)
+ return FALSE;
+
+ /* only interested in native renderable configs */
+ if (!mode->xRenderable || !mode->drawableType)
+ return FALSE;
+
+ nconf->buffer_mask = 1 << NATIVE_ATTACHMENT_FRONT_LEFT;
+ if (mode->doubleBufferMode)
+ nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_BACK_LEFT;
+ if (mode->stereoMode) {
+ nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_FRONT_RIGHT;
+ if (mode->doubleBufferMode)
+ nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_BACK_RIGHT;
+ }
+
+ /* choose color format */
+ num_formats = choose_color_format(mode, formats);
+ for (i = 0; i < num_formats; i++) {
+ if (is_format_supported(ndpy->screen, formats[i], sample_count, TRUE)) {
+ nconf->color_format = formats[i];
+ break;
+ }
+ }
+ if (nconf->color_format == PIPE_FORMAT_NONE)
+ return FALSE;
+
+ if (mode->drawableType & GLX_WINDOW_BIT)
+ nconf->window_bit = TRUE;
+ if (mode->drawableType & GLX_PIXMAP_BIT)
+ nconf->pixmap_bit = TRUE;
+
+ nconf->native_visual_id = mode->visualID;
+ nconf->native_visual_type = mode->visualType;
+ nconf->level = mode->level;
+ nconf->samples = mode->samples;
+
+ nconf->slow_config = (mode->visualRating == GLX_SLOW_CONFIG);
+
+ if (mode->transparentPixel == GLX_TRANSPARENT_RGB) {
+ nconf->transparent_rgb = TRUE;
+ nconf->transparent_rgb_values[0] = mode->transparentRed;
+ nconf->transparent_rgb_values[1] = mode->transparentGreen;
+ nconf->transparent_rgb_values[2] = mode->transparentBlue;
+ }
+
+ return TRUE;
+}
+
+static const struct native_config **
+dri2_display_get_configs(struct native_display *ndpy, int *num_configs)
+{
+ struct dri2_display *dri2dpy = dri2_display(ndpy);
+ const struct native_config **configs;
+ int i;
+
+ /* first time */
+ if (!dri2dpy->configs) {
+ const __GLcontextModes *modes;
+ int num_modes, count;
+
+ modes = x11_screen_get_glx_configs(dri2dpy->xscr);
+ if (!modes)
+ return NULL;
+ num_modes = x11_context_modes_count(modes);
+
+ dri2dpy->configs = CALLOC(num_modes, sizeof(*dri2dpy->configs));
+ if (!dri2dpy->configs)
+ return NULL;
+
+ count = 0;
+ for (i = 0; i < num_modes; i++) {
+ struct native_config *nconf = &dri2dpy->configs[count].base;
+ if (dri2_display_convert_config(&dri2dpy->base, modes, nconf))
+ count++;
+ modes = modes->next;
+ }
+
+ dri2dpy->num_configs = count;
+ }
+
+ configs = MALLOC(dri2dpy->num_configs * sizeof(*configs));
+ if (configs) {
+ for (i = 0; i < dri2dpy->num_configs; i++)
+ configs[i] = (const struct native_config *) &dri2dpy->configs[i];
+ if (num_configs)
+ *num_configs = dri2dpy->num_configs;
+ }
+
+ return configs;
+}
+
+static boolean
+dri2_display_is_pixmap_supported(struct native_display *ndpy,
+ EGLNativePixmapType pix,
+ const struct native_config *nconf)
+{
+ struct dri2_display *dri2dpy = dri2_display(ndpy);
+ uint depth, nconf_depth;
+
+ depth = x11_drawable_get_depth(dri2dpy->xscr, (Drawable) pix);
+ nconf_depth = util_format_get_blocksizebits(nconf->color_format);
+
+ /* simple depth match for now */
+ return (depth == nconf_depth || (depth == 24 && depth + 8 == nconf_depth));
+}
+
+static int
+dri2_display_get_param(struct native_display *ndpy,
+ enum native_param_type param)
+{
+ int val;
+
+ switch (param) {
+ case NATIVE_PARAM_USE_NATIVE_BUFFER:
+ /* DRI2GetBuffers use the native buffers */
+ val = TRUE;
+ break;
+ default:
+ val = 0;
+ break;
+ }
+
+ return val;
+}
+
+static void
+dri2_display_destroy(struct native_display *ndpy)
+{
+ struct dri2_display *dri2dpy = dri2_display(ndpy);
+
+ if (dri2dpy->configs)
+ FREE(dri2dpy->configs);
+
+ if (dri2dpy->base.screen)
+ dri2dpy->base.screen->destroy(dri2dpy->base.screen);
+
+ if (dri2dpy->surfaces)
+ util_hash_table_destroy(dri2dpy->surfaces);
+
+ if (dri2dpy->xscr)
+ x11_screen_destroy(dri2dpy->xscr);
+ if (dri2dpy->own_dpy)
+ XCloseDisplay(dri2dpy->dpy);
+ if (dri2dpy->api && dri2dpy->api->destroy)
+ dri2dpy->api->destroy(dri2dpy->api);
+ FREE(dri2dpy);
+}
+
+static void
+dri2_display_invalidate_buffers(struct x11_screen *xscr, Drawable drawable,
+ void *user_data)
+{
+ struct native_display *ndpy = (struct native_display* ) user_data;
+ struct dri2_display *dri2dpy = dri2_display(ndpy);
+ struct native_surface *nsurf;
+ struct dri2_surface *dri2surf;
+
+ nsurf = (struct native_surface *)
+ util_hash_table_get(dri2dpy->surfaces, (void *) drawable);
+ if (!nsurf)
+ return;
+
+ dri2surf = dri2_surface(nsurf);
+
+ dri2surf->server_stamp++;
+ dri2dpy->event_handler->invalid_surface(&dri2dpy->base,
+ &dri2surf->base, dri2surf->server_stamp);
+}
+
+/**
+ * Initialize DRI2 and pipe screen.
+ */
+static boolean
+dri2_display_init_screen(struct native_display *ndpy)
+{
+ struct dri2_display *dri2dpy = dri2_display(ndpy);
+ const char *driver = dri2dpy->api->name;
+ int fd;
+
+ if (!x11_screen_support(dri2dpy->xscr, X11_SCREEN_EXTENSION_DRI2) ||
+ !x11_screen_support(dri2dpy->xscr, X11_SCREEN_EXTENSION_GLX)) {
+ _eglLog(_EGL_WARNING, "GLX/DRI2 is not supported");
+ return FALSE;
+ }
+
+ dri2dpy->dri_driver = x11_screen_probe_dri2(dri2dpy->xscr,
+ &dri2dpy->dri_major, &dri2dpy->dri_minor);
+ if (!dri2dpy->dri_driver || !driver ||
+ strcmp(dri2dpy->dri_driver, driver) != 0) {
+ _eglLog(_EGL_WARNING, "Driver mismatch: %s != %s",
+ dri2dpy->dri_driver, dri2dpy->api->name);
+ return FALSE;
+ }
+
+ fd = x11_screen_enable_dri2(dri2dpy->xscr,
+ dri2_display_invalidate_buffers, &dri2dpy->base);
+ if (fd < 0)
+ return FALSE;
+
+ dri2dpy->base.screen = dri2dpy->api->create_screen(dri2dpy->api, fd);
+ if (!dri2dpy->base.screen) {
+ _eglLog(_EGL_WARNING, "failed to create DRM screen");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static unsigned
+dri2_display_hash_table_hash(void *key)
+{
+ XID drawable = pointer_to_uintptr(key);
+ return (unsigned) drawable;
+}
+
+static int
+dri2_display_hash_table_compare(void *key1, void *key2)
+{
+ return (key1 - key2);
+}
+
+struct native_display *
+x11_create_dri2_display(EGLNativeDisplayType dpy,
+ struct native_event_handler *event_handler,
+ struct drm_api *api)
+{
+ struct dri2_display *dri2dpy;
+
+ dri2dpy = CALLOC_STRUCT(dri2_display);
+ if (!dri2dpy)
+ return NULL;
+
+ dri2dpy->event_handler = event_handler;
+ dri2dpy->api = api;
+
+ dri2dpy->dpy = dpy;
+ if (!dri2dpy->dpy) {
+ dri2dpy->dpy = XOpenDisplay(NULL);
+ if (!dri2dpy->dpy) {
+ dri2_display_destroy(&dri2dpy->base);
+ return NULL;
+ }
+ dri2dpy->own_dpy = TRUE;
+ }
+
+ dri2dpy->xscr_number = DefaultScreen(dri2dpy->dpy);
+ dri2dpy->xscr = x11_screen_create(dri2dpy->dpy, dri2dpy->xscr_number);
+ if (!dri2dpy->xscr) {
+ dri2_display_destroy(&dri2dpy->base);
+ return NULL;
+ }
+
+ if (!dri2_display_init_screen(&dri2dpy->base)) {
+ dri2_display_destroy(&dri2dpy->base);
+ return NULL;
+ }
+
+ dri2dpy->surfaces = util_hash_table_create(dri2_display_hash_table_hash,
+ dri2_display_hash_table_compare);
+ if (!dri2dpy->surfaces) {
+ dri2_display_destroy(&dri2dpy->base);
+ return NULL;
+ }
+
+ dri2dpy->base.destroy = dri2_display_destroy;
+ dri2dpy->base.get_param = dri2_display_get_param;
+ dri2dpy->base.get_configs = dri2_display_get_configs;
+ dri2dpy->base.is_pixmap_supported = dri2_display_is_pixmap_supported;
+ dri2dpy->base.create_window_surface = dri2_display_create_window_surface;
+ dri2dpy->base.create_pixmap_surface = dri2_display_create_pixmap_surface;
+
+ return &dri2dpy->base;
+}
diff --git a/src/gallium/state_trackers/egl/x11/native_x11.c b/src/gallium/state_trackers/egl/x11/native_x11.c
new file mode 100644
index 0000000000..b6d51bbf9f
--- /dev/null
+++ b/src/gallium/state_trackers/egl/x11/native_x11.c
@@ -0,0 +1,152 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.8
+ *
+ * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org>
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <string.h>
+#include "util/u_debug.h"
+#include "util/u_memory.h"
+#include "util/u_string.h"
+#include "state_tracker/drm_api.h"
+#include "egllog.h"
+
+#include "native_x11.h"
+#include "x11_screen.h"
+
+#define X11_PROBE_MAGIC 0x11980BE /* "X11PROBE" */
+
+static struct drm_api *api;
+
+static void
+x11_probe_destroy(struct native_probe *nprobe)
+{
+ if (nprobe->data)
+ FREE(nprobe->data);
+ FREE(nprobe);
+}
+
+struct native_probe *
+native_create_probe(EGLNativeDisplayType dpy)
+{
+ struct native_probe *nprobe;
+ struct x11_screen *xscr;
+ int scr;
+ const char *driver_name = NULL;
+ Display *xdpy;
+
+ nprobe = CALLOC_STRUCT(native_probe);
+ if (!nprobe)
+ return NULL;
+
+ xdpy = dpy;
+ if (!xdpy) {
+ xdpy = XOpenDisplay(NULL);
+ if (!xdpy) {
+ FREE(nprobe);
+ return NULL;
+ }
+ }
+
+ scr = DefaultScreen(xdpy);
+ xscr = x11_screen_create(xdpy, scr);
+ if (xscr) {
+ if (x11_screen_support(xscr, X11_SCREEN_EXTENSION_DRI2)) {
+ driver_name = x11_screen_probe_dri2(xscr, NULL, NULL);
+ if (driver_name)
+ nprobe->data = strdup(driver_name);
+ }
+
+ x11_screen_destroy(xscr);
+ }
+
+ if (xdpy != dpy)
+ XCloseDisplay(xdpy);
+
+ nprobe->magic = X11_PROBE_MAGIC;
+ nprobe->display = dpy;
+
+ nprobe->destroy = x11_probe_destroy;
+
+ return nprobe;
+}
+
+enum native_probe_result
+native_get_probe_result(struct native_probe *nprobe)
+{
+ if (!nprobe || nprobe->magic != X11_PROBE_MAGIC)
+ return NATIVE_PROBE_UNKNOWN;
+
+ if (!api)
+ api = drm_api_create();
+
+ /* this is a software driver */
+ if (!api)
+ return NATIVE_PROBE_SUPPORTED;
+
+ /* the display does not support DRI2 or the driver mismatches */
+ if (!nprobe->data || strcmp(api->name, (const char *) nprobe->data) != 0)
+ return NATIVE_PROBE_FALLBACK;
+
+ return NATIVE_PROBE_EXACT;
+}
+
+const char *
+native_get_name(void)
+{
+ static char x11_name[32];
+
+ if (!api)
+ api = drm_api_create();
+
+ if (api)
+ util_snprintf(x11_name, sizeof(x11_name), "X11/%s", api->name);
+ else
+ util_snprintf(x11_name, sizeof(x11_name), "X11");
+
+ return x11_name;
+}
+
+struct native_display *
+native_create_display(EGLNativeDisplayType dpy,
+ struct native_event_handler *event_handler)
+{
+ struct native_display *ndpy = NULL;
+ boolean force_sw;
+
+ if (!api)
+ api = drm_api_create();
+
+ force_sw = debug_get_bool_option("EGL_SOFTWARE", FALSE);
+ if (api && !force_sw) {
+ ndpy = x11_create_dri2_display(dpy, event_handler, api);
+ }
+
+ if (!ndpy) {
+ EGLint level = (force_sw) ? _EGL_INFO : _EGL_WARNING;
+
+ _eglLog(level, "use software fallback");
+ ndpy = x11_create_ximage_display(dpy, event_handler);
+ }
+
+ return ndpy;
+}
diff --git a/src/gallium/state_trackers/egl/x11/native_x11.h b/src/gallium/state_trackers/egl/x11/native_x11.h
new file mode 100644
index 0000000000..1678403b45
--- /dev/null
+++ b/src/gallium/state_trackers/egl/x11/native_x11.h
@@ -0,0 +1,41 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.8
+ *
+ * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org>
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _NATIVE_X11_H_
+#define _NATIVE_X11_H_
+
+#include "state_tracker/drm_api.h"
+#include "common/native.h"
+
+struct native_display *
+x11_create_ximage_display(EGLNativeDisplayType dpy,
+ struct native_event_handler *event_handler);
+
+struct native_display *
+x11_create_dri2_display(EGLNativeDisplayType dpy,
+ struct native_event_handler *event_handler,
+ struct drm_api *api);
+
+#endif /* _NATIVE_X11_H_ */
diff --git a/src/gallium/state_trackers/egl/x11/native_ximage.c b/src/gallium/state_trackers/egl/x11/native_ximage.c
new file mode 100644
index 0000000000..45679fc9b4
--- /dev/null
+++ b/src/gallium/state_trackers/egl/x11/native_ximage.c
@@ -0,0 +1,498 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.8
+ *
+ * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org>
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include "util/u_memory.h"
+#include "util/u_math.h"
+#include "util/u_format.h"
+#include "pipe/p_compiler.h"
+#include "util/u_inlines.h"
+#include "state_tracker/xlib_sw_winsys.h"
+#include "util/u_debug.h"
+#include "egllog.h"
+
+#include "common/native_helper.h"
+#include "native_x11.h"
+#include "x11_screen.h"
+
+enum ximage_surface_type {
+ XIMAGE_SURFACE_TYPE_WINDOW,
+ XIMAGE_SURFACE_TYPE_PIXMAP,
+};
+
+struct ximage_display {
+ struct native_display base;
+ Display *dpy;
+ boolean own_dpy;
+
+ struct native_event_handler *event_handler;
+
+ struct x11_screen *xscr;
+ int xscr_number;
+
+ struct ximage_config *configs;
+ int num_configs;
+};
+
+struct ximage_surface {
+ struct native_surface base;
+ Drawable drawable;
+ enum ximage_surface_type type;
+ enum pipe_format color_format;
+ XVisualInfo visual;
+ struct ximage_display *xdpy;
+
+ unsigned int server_stamp;
+ unsigned int client_stamp;
+
+ struct resource_surface *rsurf;
+ struct xlib_drawable xdraw;
+};
+
+struct ximage_config {
+ struct native_config base;
+ const XVisualInfo *visual;
+};
+
+static INLINE struct ximage_display *
+ximage_display(const struct native_display *ndpy)
+{
+ return (struct ximage_display *) ndpy;
+}
+
+static INLINE struct ximage_surface *
+ximage_surface(const struct native_surface *nsurf)
+{
+ return (struct ximage_surface *) nsurf;
+}
+
+static INLINE struct ximage_config *
+ximage_config(const struct native_config *nconf)
+{
+ return (struct ximage_config *) nconf;
+}
+
+/**
+ * Update the geometry of the surface. This is a slow functions.
+ */
+static void
+ximage_surface_update_geometry(struct native_surface *nsurf)
+{
+ struct ximage_surface *xsurf = ximage_surface(nsurf);
+ Status ok;
+ Window root;
+ int x, y;
+ unsigned int w, h, border, depth;
+
+ ok = XGetGeometry(xsurf->xdpy->dpy, xsurf->drawable,
+ &root, &x, &y, &w, &h, &border, &depth);
+ if (ok && resource_surface_set_size(xsurf->rsurf, w, h))
+ xsurf->server_stamp++;
+}
+
+/**
+ * Update the buffers of the surface.
+ */
+static boolean
+ximage_surface_update_buffers(struct native_surface *nsurf, uint buffer_mask)
+{
+ struct ximage_surface *xsurf = ximage_surface(nsurf);
+
+ if (xsurf->client_stamp != xsurf->server_stamp) {
+ ximage_surface_update_geometry(&xsurf->base);
+ xsurf->client_stamp = xsurf->server_stamp;
+ }
+
+ return resource_surface_add_resources(xsurf->rsurf, buffer_mask);
+}
+
+/**
+ * Emulate an invalidate event.
+ */
+static void
+ximage_surface_invalidate(struct native_surface *nsurf)
+{
+ struct ximage_surface *xsurf = ximage_surface(nsurf);
+ struct ximage_display *xdpy = xsurf->xdpy;
+
+ xsurf->server_stamp++;
+ xdpy->event_handler->invalid_surface(&xdpy->base,
+ &xsurf->base, xsurf->server_stamp);
+}
+
+static boolean
+ximage_surface_flush_frontbuffer(struct native_surface *nsurf)
+{
+ struct ximage_surface *xsurf = ximage_surface(nsurf);
+ boolean ret;
+
+ ret = resource_surface_present(xsurf->rsurf,
+ NATIVE_ATTACHMENT_FRONT_LEFT, (void *) &xsurf->xdraw);
+ /* force buffers to be updated in next validation call */
+ ximage_surface_invalidate(&xsurf->base);
+
+ return ret;
+}
+
+static boolean
+ximage_surface_swap_buffers(struct native_surface *nsurf)
+{
+ struct ximage_surface *xsurf = ximage_surface(nsurf);
+ boolean ret;
+
+ ret = resource_surface_present(xsurf->rsurf,
+ NATIVE_ATTACHMENT_BACK_LEFT, (void *) &xsurf->xdraw);
+
+ resource_surface_swap_buffers(xsurf->rsurf,
+ NATIVE_ATTACHMENT_FRONT_LEFT, NATIVE_ATTACHMENT_BACK_LEFT, TRUE);
+ /* the front/back buffers have been swapped */
+ ximage_surface_invalidate(&xsurf->base);
+
+ return ret;
+}
+
+static boolean
+ximage_surface_validate(struct native_surface *nsurf, uint attachment_mask,
+ unsigned int *seq_num, struct pipe_resource **textures,
+ int *width, int *height)
+{
+ struct ximage_surface *xsurf = ximage_surface(nsurf);
+ uint w, h;
+
+ if (!ximage_surface_update_buffers(&xsurf->base, attachment_mask))
+ return FALSE;
+
+ if (seq_num)
+ *seq_num = xsurf->client_stamp;
+
+ if (textures)
+ resource_surface_get_resources(xsurf->rsurf, textures, attachment_mask);
+
+ resource_surface_get_size(xsurf->rsurf, &w, &h);
+ if (width)
+ *width = w;
+ if (height)
+ *height = h;
+
+ return TRUE;
+}
+
+static void
+ximage_surface_wait(struct native_surface *nsurf)
+{
+ struct ximage_surface *xsurf = ximage_surface(nsurf);
+ XSync(xsurf->xdpy->dpy, FALSE);
+ /* TODO XGetImage and update the front texture */
+}
+
+static void
+ximage_surface_destroy(struct native_surface *nsurf)
+{
+ struct ximage_surface *xsurf = ximage_surface(nsurf);
+
+ resource_surface_destroy(xsurf->rsurf);
+ FREE(xsurf);
+}
+
+static struct ximage_surface *
+ximage_display_create_surface(struct native_display *ndpy,
+ enum ximage_surface_type type,
+ Drawable drawable,
+ const struct native_config *nconf)
+{
+ struct ximage_display *xdpy = ximage_display(ndpy);
+ struct ximage_config *xconf = ximage_config(nconf);
+ struct ximage_surface *xsurf;
+
+ xsurf = CALLOC_STRUCT(ximage_surface);
+ if (!xsurf)
+ return NULL;
+
+ xsurf->xdpy = xdpy;
+ xsurf->type = type;
+ xsurf->color_format = xconf->base.color_format;
+ xsurf->drawable = drawable;
+
+ xsurf->rsurf = resource_surface_create(xdpy->base.screen,
+ xsurf->color_format,
+ PIPE_BIND_RENDER_TARGET |
+ PIPE_BIND_SAMPLER_VIEW |
+ PIPE_BIND_DISPLAY_TARGET |
+ PIPE_BIND_SCANOUT);
+ if (!xsurf->rsurf) {
+ FREE(xsurf);
+ return NULL;
+ }
+
+ xsurf->drawable = drawable;
+ xsurf->visual = *xconf->visual;
+ /* initialize the geometry */
+ ximage_surface_update_geometry(&xsurf->base);
+
+ xsurf->xdraw.visual = xsurf->visual.visual;
+ xsurf->xdraw.depth = xsurf->visual.depth;
+ xsurf->xdraw.drawable = xsurf->drawable;
+
+ xsurf->base.destroy = ximage_surface_destroy;
+ xsurf->base.swap_buffers = ximage_surface_swap_buffers;
+ xsurf->base.flush_frontbuffer = ximage_surface_flush_frontbuffer;
+ xsurf->base.validate = ximage_surface_validate;
+ xsurf->base.wait = ximage_surface_wait;
+
+ return xsurf;
+}
+
+static struct native_surface *
+ximage_display_create_window_surface(struct native_display *ndpy,
+ EGLNativeWindowType win,
+ const struct native_config *nconf)
+{
+ struct ximage_surface *xsurf;
+
+ xsurf = ximage_display_create_surface(ndpy, XIMAGE_SURFACE_TYPE_WINDOW,
+ (Drawable) win, nconf);
+ return (xsurf) ? &xsurf->base : NULL;
+}
+
+static struct native_surface *
+ximage_display_create_pixmap_surface(struct native_display *ndpy,
+ EGLNativePixmapType pix,
+ const struct native_config *nconf)
+{
+ struct ximage_surface *xsurf;
+
+ xsurf = ximage_display_create_surface(ndpy, XIMAGE_SURFACE_TYPE_PIXMAP,
+ (Drawable) pix, nconf);
+ return (xsurf) ? &xsurf->base : NULL;
+}
+
+static enum pipe_format
+choose_format(const XVisualInfo *vinfo)
+{
+ enum pipe_format fmt;
+ /* TODO elaborate the formats */
+ switch (vinfo->depth) {
+ case 32:
+ fmt = PIPE_FORMAT_B8G8R8A8_UNORM;
+ break;
+ case 24:
+ fmt = PIPE_FORMAT_B8G8R8X8_UNORM;
+ break;
+ case 16:
+ fmt = PIPE_FORMAT_B5G6R5_UNORM;
+ break;
+ default:
+ fmt = PIPE_FORMAT_NONE;
+ break;
+ }
+
+ return fmt;
+}
+
+static const struct native_config **
+ximage_display_get_configs(struct native_display *ndpy, int *num_configs)
+{
+ struct ximage_display *xdpy = ximage_display(ndpy);
+ const struct native_config **configs;
+ int i;
+
+ /* first time */
+ if (!xdpy->configs) {
+ const XVisualInfo *visuals;
+ int num_visuals, count;
+
+ visuals = x11_screen_get_visuals(xdpy->xscr, &num_visuals);
+ if (!visuals)
+ return NULL;
+
+ /*
+ * Create two configs for each visual.
+ * One with depth/stencil buffer; one without
+ */
+ xdpy->configs = CALLOC(num_visuals * 2, sizeof(*xdpy->configs));
+ if (!xdpy->configs)
+ return NULL;
+
+ count = 0;
+ for (i = 0; i < num_visuals; i++) {
+ struct ximage_config *xconf = &xdpy->configs[count];
+
+ xconf->visual = &visuals[i];
+ xconf->base.color_format = choose_format(xconf->visual);
+ if (xconf->base.color_format == PIPE_FORMAT_NONE)
+ continue;
+
+ xconf->base.buffer_mask =
+ (1 << NATIVE_ATTACHMENT_FRONT_LEFT) |
+ (1 << NATIVE_ATTACHMENT_BACK_LEFT);
+
+ xconf->base.window_bit = TRUE;
+ xconf->base.pixmap_bit = TRUE;
+
+ xconf->base.native_visual_id = xconf->visual->visualid;
+#if defined(__cplusplus) || defined(c_plusplus)
+ xconf->base.native_visual_type = xconf->visual->c_class;
+#else
+ xconf->base.native_visual_type = xconf->visual->class;
+#endif
+
+ xconf->base.slow_config = TRUE;
+
+ count++;
+ }
+
+ xdpy->num_configs = count;
+ }
+
+ configs = MALLOC(xdpy->num_configs * sizeof(*configs));
+ if (configs) {
+ for (i = 0; i < xdpy->num_configs; i++)
+ configs[i] = (const struct native_config *) &xdpy->configs[i];
+ if (num_configs)
+ *num_configs = xdpy->num_configs;
+ }
+ return configs;
+}
+
+static boolean
+ximage_display_is_pixmap_supported(struct native_display *ndpy,
+ EGLNativePixmapType pix,
+ const struct native_config *nconf)
+{
+ struct ximage_display *xdpy = ximage_display(ndpy);
+ enum pipe_format fmt;
+ uint depth;
+
+ depth = x11_drawable_get_depth(xdpy->xscr, (Drawable) pix);
+ switch (depth) {
+ case 32:
+ fmt = PIPE_FORMAT_B8G8R8A8_UNORM;
+ break;
+ case 24:
+ fmt = PIPE_FORMAT_B8G8R8X8_UNORM;
+ break;
+ case 16:
+ fmt = PIPE_FORMAT_B5G6R5_UNORM;
+ break;
+ default:
+ fmt = PIPE_FORMAT_NONE;
+ break;
+ }
+
+ return (fmt == nconf->color_format);
+}
+
+static int
+ximage_display_get_param(struct native_display *ndpy,
+ enum native_param_type param)
+{
+ int val;
+
+ switch (param) {
+ case NATIVE_PARAM_USE_NATIVE_BUFFER:
+ /* private buffers are allocated */
+ val = FALSE;
+ break;
+ default:
+ val = 0;
+ break;
+ }
+
+ return val;
+}
+
+static void
+ximage_display_destroy(struct native_display *ndpy)
+{
+ struct ximage_display *xdpy = ximage_display(ndpy);
+
+ if (xdpy->configs)
+ FREE(xdpy->configs);
+
+ xdpy->base.screen->destroy(xdpy->base.screen);
+
+ x11_screen_destroy(xdpy->xscr);
+ if (xdpy->own_dpy)
+ XCloseDisplay(xdpy->dpy);
+ FREE(xdpy);
+}
+
+struct native_display *
+x11_create_ximage_display(EGLNativeDisplayType dpy,
+ struct native_event_handler *event_handler)
+{
+ struct ximage_display *xdpy;
+ struct sw_winsys *winsys = NULL;
+
+ xdpy = CALLOC_STRUCT(ximage_display);
+ if (!xdpy)
+ return NULL;
+
+ xdpy->dpy = dpy;
+ if (!xdpy->dpy) {
+ xdpy->dpy = XOpenDisplay(NULL);
+ if (!xdpy->dpy) {
+ FREE(xdpy);
+ return NULL;
+ }
+ xdpy->own_dpy = TRUE;
+ }
+
+ xdpy->event_handler = event_handler;
+
+ xdpy->xscr_number = DefaultScreen(xdpy->dpy);
+ xdpy->xscr = x11_screen_create(xdpy->dpy, xdpy->xscr_number);
+ if (!xdpy->xscr)
+ goto fail;
+
+ winsys = xlib_create_sw_winsys(xdpy->dpy);
+ if (!winsys)
+ goto fail;
+
+ xdpy->base.screen = native_create_sw_screen(winsys);
+ if (!xdpy->base.screen)
+ goto fail;
+
+ xdpy->base.destroy = ximage_display_destroy;
+ xdpy->base.get_param = ximage_display_get_param;
+
+ xdpy->base.get_configs = ximage_display_get_configs;
+ xdpy->base.is_pixmap_supported = ximage_display_is_pixmap_supported;
+ xdpy->base.create_window_surface = ximage_display_create_window_surface;
+ xdpy->base.create_pixmap_surface = ximage_display_create_pixmap_surface;
+
+ return &xdpy->base;
+
+fail:
+ if (winsys && winsys->destroy)
+ winsys->destroy(winsys);
+ if (xdpy->xscr)
+ x11_screen_destroy(xdpy->xscr);
+ if (xdpy->dpy && xdpy->own_dpy)
+ XCloseDisplay(xdpy->dpy);
+ FREE(xdpy);
+ return NULL;
+}
diff --git a/src/gallium/state_trackers/egl/x11/x11_screen.c b/src/gallium/state_trackers/egl/x11/x11_screen.c
new file mode 100644
index 0000000000..6bdff26ec0
--- /dev/null
+++ b/src/gallium/state_trackers/egl/x11/x11_screen.c
@@ -0,0 +1,434 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.8
+ *
+ * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org>
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <xf86drm.h>
+#include <X11/Xlibint.h>
+#include <X11/extensions/XShm.h>
+
+#include "util/u_memory.h"
+#include "egllog.h"
+
+#include "x11_screen.h"
+#include "dri2.h"
+#include "glxinit.h"
+
+struct x11_screen {
+ /* dummy base class */
+ struct __GLXDRIdisplayRec base;
+
+ Display *dpy;
+ int number;
+
+ /*
+ * This is used to fetch GLX visuals/fbconfigs. It steals code from GLX.
+ * It might be better to rewrite the part in Xlib or XCB.
+ */
+ __GLXdisplayPrivate *glx_dpy;
+
+ int dri_major, dri_minor;
+ char *dri_driver;
+ char *dri_device;
+ int dri_fd;
+
+ x11_drawable_invalidate_buffers dri_invalidate_buffers;
+ void *dri_user_data;
+
+ XVisualInfo *visuals;
+ int num_visuals;
+
+ /* cached values for x11_drawable_get_depth */
+ Drawable last_drawable;
+ unsigned int last_depth;
+};
+
+
+/**
+ * Create a X11 screen.
+ */
+struct x11_screen *
+x11_screen_create(Display *dpy, int screen)
+{
+ struct x11_screen *xscr;
+
+ if (screen >= ScreenCount(dpy))
+ return NULL;
+
+ xscr = CALLOC_STRUCT(x11_screen);
+ if (xscr) {
+ xscr->dpy = dpy;
+ xscr->number = screen;
+
+ xscr->dri_major = -1;
+ xscr->dri_fd = -1;
+ }
+ return xscr;
+}
+
+/**
+ * Destroy a X11 screen.
+ */
+void
+x11_screen_destroy(struct x11_screen *xscr)
+{
+ if (xscr->dri_fd >= 0)
+ close(xscr->dri_fd);
+ if (xscr->dri_driver)
+ Xfree(xscr->dri_driver);
+ if (xscr->dri_device)
+ Xfree(xscr->dri_device);
+
+ /* xscr->glx_dpy will be destroyed with the X display */
+ if (xscr->glx_dpy)
+ xscr->glx_dpy->dri2Display = NULL;
+
+ if (xscr->visuals)
+ XFree(xscr->visuals);
+ FREE(xscr);
+}
+
+static boolean
+x11_screen_init_dri2(struct x11_screen *xscr)
+{
+ if (xscr->dri_major < 0) {
+ int eventBase, errorBase;
+
+ if (!DRI2QueryExtension(xscr->dpy, &eventBase, &errorBase) ||
+ !DRI2QueryVersion(xscr->dpy, &xscr->dri_major, &xscr->dri_minor))
+ xscr->dri_major = -1;
+ }
+ return (xscr->dri_major >= 0);
+}
+
+static boolean
+x11_screen_init_glx(struct x11_screen *xscr)
+{
+ if (!xscr->glx_dpy)
+ xscr->glx_dpy = __glXInitialize(xscr->dpy);
+ return (xscr->glx_dpy != NULL);
+}
+
+/**
+ * Return true if the screen supports the extension.
+ */
+boolean
+x11_screen_support(struct x11_screen *xscr, enum x11_screen_extension ext)
+{
+ boolean supported = FALSE;
+
+ switch (ext) {
+ case X11_SCREEN_EXTENSION_XSHM:
+ supported = XShmQueryExtension(xscr->dpy);
+ break;
+ case X11_SCREEN_EXTENSION_GLX:
+ supported = x11_screen_init_glx(xscr);
+ break;
+ case X11_SCREEN_EXTENSION_DRI2:
+ supported = x11_screen_init_dri2(xscr);
+ break;
+ default:
+ break;
+ }
+
+ return supported;
+}
+
+/**
+ * Return the X visuals.
+ */
+const XVisualInfo *
+x11_screen_get_visuals(struct x11_screen *xscr, int *num_visuals)
+{
+ if (!xscr->visuals) {
+ XVisualInfo vinfo_template;
+ vinfo_template.screen = xscr->number;
+ xscr->visuals = XGetVisualInfo(xscr->dpy, VisualScreenMask,
+ &vinfo_template, &xscr->num_visuals);
+ }
+
+ if (num_visuals)
+ *num_visuals = xscr->num_visuals;
+ return xscr->visuals;
+}
+
+/**
+ * Return the GLX fbconfigs.
+ */
+const __GLcontextModes *
+x11_screen_get_glx_configs(struct x11_screen *xscr)
+{
+ return (x11_screen_init_glx(xscr))
+ ? xscr->glx_dpy->screenConfigs[xscr->number].configs
+ : NULL;
+}
+
+/**
+ * Return the GLX visuals.
+ */
+const __GLcontextModes *
+x11_screen_get_glx_visuals(struct x11_screen *xscr)
+{
+ return (x11_screen_init_glx(xscr))
+ ? xscr->glx_dpy->screenConfigs[xscr->number].visuals
+ : NULL;
+}
+
+/**
+ * Probe the screen for the DRI2 driver name.
+ */
+const char *
+x11_screen_probe_dri2(struct x11_screen *xscr, int *major, int *minor)
+{
+ if (!x11_screen_init_dri2(xscr))
+ return NULL;
+
+ /* get the driver name and the device name */
+ if (!xscr->dri_driver) {
+ if (!DRI2Connect(xscr->dpy, RootWindow(xscr->dpy, xscr->number),
+ &xscr->dri_driver, &xscr->dri_device))
+ xscr->dri_driver = xscr->dri_device = NULL;
+ }
+ if (major)
+ *major = xscr->dri_major;
+ if (minor)
+ *minor = xscr->dri_minor;
+
+ return xscr->dri_driver;
+}
+
+/**
+ * Enable DRI2 and returns the file descriptor of the DRM device. The file
+ * descriptor will be closed automatically when the screen is destoryed.
+ */
+int
+x11_screen_enable_dri2(struct x11_screen *xscr,
+ x11_drawable_invalidate_buffers invalidate_buffers,
+ void *user_data)
+{
+ if (xscr->dri_fd < 0) {
+ int fd;
+ drm_magic_t magic;
+
+ /* get the driver name and the device name first */
+ if (!x11_screen_probe_dri2(xscr, NULL, NULL))
+ return -1;
+
+ fd = open(xscr->dri_device, O_RDWR);
+ if (fd < 0) {
+ _eglLog(_EGL_WARNING, "failed to open %s", xscr->dri_device);
+ return -1;
+ }
+
+ memset(&magic, 0, sizeof(magic));
+ if (drmGetMagic(fd, &magic)) {
+ _eglLog(_EGL_WARNING, "failed to get magic");
+ close(fd);
+ return -1;
+ }
+
+ if (!DRI2Authenticate(xscr->dpy,
+ RootWindow(xscr->dpy, xscr->number), magic)) {
+ _eglLog(_EGL_WARNING, "failed to authenticate magic");
+ close(fd);
+ return -1;
+ }
+
+ if (!x11_screen_init_glx(xscr)) {
+ _eglLog(_EGL_WARNING, "failed to initialize GLX");
+ close(fd);
+ return -1;
+ }
+ if (xscr->glx_dpy->dri2Display) {
+ _eglLog(_EGL_WARNING,
+ "display is already managed by another x11 screen");
+ close(fd);
+ return -1;
+ }
+
+ xscr->glx_dpy->dri2Display = (__GLXDRIdisplay *) xscr;
+ xscr->dri_invalidate_buffers = invalidate_buffers;
+ xscr->dri_user_data = user_data;
+
+ xscr->dri_fd = fd;
+ }
+
+ return xscr->dri_fd;
+}
+
+/**
+ * Create/Destroy the DRI drawable.
+ */
+void
+x11_drawable_enable_dri2(struct x11_screen *xscr,
+ Drawable drawable, boolean on)
+{
+ if (on)
+ DRI2CreateDrawable(xscr->dpy, drawable);
+ else
+ DRI2DestroyDrawable(xscr->dpy, drawable);
+}
+
+/**
+ * Copy between buffers of the DRI2 drawable.
+ */
+void
+x11_drawable_copy_buffers(struct x11_screen *xscr, Drawable drawable,
+ int x, int y, int width, int height,
+ int src_buf, int dst_buf)
+{
+ XRectangle rect;
+ XserverRegion region;
+
+ rect.x = x;
+ rect.y = y;
+ rect.width = width;
+ rect.height = height;
+
+ region = XFixesCreateRegion(xscr->dpy, &rect, 1);
+ DRI2CopyRegion(xscr->dpy, drawable, region, dst_buf, src_buf);
+ XFixesDestroyRegion(xscr->dpy, region);
+}
+
+/**
+ * Get the buffers of the DRI2 drawable. The returned array should be freed.
+ */
+struct x11_drawable_buffer *
+x11_drawable_get_buffers(struct x11_screen *xscr, Drawable drawable,
+ int *width, int *height, unsigned int *attachments,
+ boolean with_format, int num_ins, int *num_outs)
+{
+ DRI2Buffer *dri2bufs;
+
+ if (with_format)
+ dri2bufs = DRI2GetBuffersWithFormat(xscr->dpy, drawable, width, height,
+ attachments, num_ins, num_outs);
+ else
+ dri2bufs = DRI2GetBuffers(xscr->dpy, drawable, width, height,
+ attachments, num_ins, num_outs);
+
+ return (struct x11_drawable_buffer *) dri2bufs;
+}
+
+/**
+ * Return the depth of a drawable.
+ *
+ * Unlike other drawable functions, the drawable needs not be a DRI2 drawable.
+ */
+uint
+x11_drawable_get_depth(struct x11_screen *xscr, Drawable drawable)
+{
+ unsigned int depth;
+
+ if (drawable != xscr->last_drawable) {
+ Window root;
+ int x, y;
+ unsigned int w, h, border;
+ Status ok;
+
+ ok = XGetGeometry(xscr->dpy, drawable, &root,
+ &x, &y, &w, &h, &border, &depth);
+ if (!ok)
+ depth = 0;
+
+ xscr->last_drawable = drawable;
+ xscr->last_depth = depth;
+ }
+ else {
+ depth = xscr->last_depth;
+ }
+
+ return depth;
+}
+
+/**
+ * Create a mode list of the given size.
+ */
+__GLcontextModes *
+x11_context_modes_create(unsigned count)
+{
+ const size_t size = sizeof(__GLcontextModes);
+ __GLcontextModes *base = NULL;
+ __GLcontextModes **next;
+ unsigned i;
+
+ next = &base;
+ for (i = 0; i < count; i++) {
+ *next = (__GLcontextModes *) CALLOC(1, size);
+ if (*next == NULL) {
+ x11_context_modes_destroy(base);
+ base = NULL;
+ break;
+ }
+ next = &((*next)->next);
+ }
+
+ return base;
+}
+
+/**
+ * Destroy a mode list.
+ */
+void
+x11_context_modes_destroy(__GLcontextModes *modes)
+{
+ while (modes != NULL) {
+ __GLcontextModes *next = modes->next;
+ FREE(modes);
+ modes = next;
+ }
+}
+
+/**
+ * Return the number of the modes in the mode list.
+ */
+unsigned
+x11_context_modes_count(const __GLcontextModes *modes)
+{
+ const __GLcontextModes *mode;
+ int count = 0;
+ for (mode = modes; mode; mode = mode->next)
+ count++;
+ return count;
+}
+
+/**
+ * This is called from src/glx/dri2.c.
+ */
+void
+dri2InvalidateBuffers(Display *dpy, XID drawable)
+{
+ __GLXdisplayPrivate *priv = __glXInitialize(dpy);
+ struct x11_screen *xscr = NULL;
+
+ if (priv && priv->dri2Display)
+ xscr = (struct x11_screen *) priv->dri2Display;
+ if (!xscr || !xscr->dri_invalidate_buffers)
+ return;
+
+ xscr->dri_invalidate_buffers(xscr, drawable, xscr->dri_user_data);
+}
diff --git a/src/gallium/state_trackers/egl/x11/x11_screen.h b/src/gallium/state_trackers/egl/x11/x11_screen.h
new file mode 100644
index 0000000000..a3c5ee1491
--- /dev/null
+++ b/src/gallium/state_trackers/egl/x11/x11_screen.h
@@ -0,0 +1,110 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.8
+ *
+ * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org>
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _X11_SCREEN_H_
+#define _X11_SCREEN_H_
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/dri2tokens.h>
+#include "GL/gl.h" /* for GL types needed by __GLcontextModes */
+#include "GL/internal/glcore.h" /* for __GLcontextModes */
+#include "pipe/p_compiler.h"
+#include "common/native.h"
+
+enum x11_screen_extension {
+ X11_SCREEN_EXTENSION_XSHM,
+ X11_SCREEN_EXTENSION_GLX,
+ X11_SCREEN_EXTENSION_DRI2,
+};
+
+/* the same as DRI2Buffer */
+struct x11_drawable_buffer {
+ unsigned int attachment;
+ unsigned int name;
+ unsigned int pitch;
+ unsigned int cpp;
+ unsigned int flags;
+};
+
+struct x11_screen;
+
+typedef void (*x11_drawable_invalidate_buffers)(struct x11_screen *xscr,
+ Drawable drawable,
+ void *user_data);
+
+struct x11_screen *
+x11_screen_create(Display *dpy, int screen);
+
+void
+x11_screen_destroy(struct x11_screen *xscr);
+
+boolean
+x11_screen_support(struct x11_screen *xscr, enum x11_screen_extension ext);
+
+const XVisualInfo *
+x11_screen_get_visuals(struct x11_screen *xscr, int *num_visuals);
+
+const __GLcontextModes *
+x11_screen_get_glx_configs(struct x11_screen *xscr);
+
+const __GLcontextModes *
+x11_screen_get_glx_visuals(struct x11_screen *xscr);
+
+const char *
+x11_screen_probe_dri2(struct x11_screen *xscr, int *major, int *minor);
+
+int
+x11_screen_enable_dri2(struct x11_screen *xscr,
+ x11_drawable_invalidate_buffers invalidate_buffers,
+ void *user_data);
+
+__GLcontextModes *
+x11_context_modes_create(unsigned count);
+
+void
+x11_context_modes_destroy(__GLcontextModes *modes);
+
+unsigned
+x11_context_modes_count(const __GLcontextModes *modes);
+
+void
+x11_drawable_enable_dri2(struct x11_screen *xscr,
+ Drawable drawable, boolean on);
+
+void
+x11_drawable_copy_buffers(struct x11_screen *xscr, Drawable drawable,
+ int x, int y, int width, int height,
+ int src_buf, int dst_buf);
+
+struct x11_drawable_buffer *
+x11_drawable_get_buffers(struct x11_screen *xscr, Drawable drawable,
+ int *width, int *height, unsigned int *attachments,
+ boolean with_format, int num_ins, int *num_outs);
+
+uint
+x11_drawable_get_depth(struct x11_screen *xscr, Drawable drawable);
+
+#endif /* _X11_SCREEN_H_ */
diff --git a/src/gallium/state_trackers/glx/Makefile b/src/gallium/state_trackers/glx/Makefile
new file mode 100644
index 0000000000..f779035763
--- /dev/null
+++ b/src/gallium/state_trackers/glx/Makefile
@@ -0,0 +1,25 @@
+TOP = ../../../..
+include $(TOP)/configs/current
+
+
+SUBDIRS = xlib
+
+
+default: subdirs
+
+
+subdirs:
+ @for dir in $(SUBDIRS) ; do \
+ if [ -d $$dir ] ; then \
+ (cd $$dir && $(MAKE)) || exit 1 ; \
+ fi \
+ done
+
+
+clean:
+ rm -f `find . -name \*.[oa]`
+ rm -f `find . -name depend`
+
+
+# Dummy install target
+install:
diff --git a/src/gallium/state_trackers/glx/xlib/Makefile b/src/gallium/state_trackers/glx/xlib/Makefile
new file mode 100644
index 0000000000..84cb36ec36
--- /dev/null
+++ b/src/gallium/state_trackers/glx/xlib/Makefile
@@ -0,0 +1,19 @@
+TOP = ../../../../..
+include $(TOP)/configs/current
+
+LIBNAME = xlib
+
+LIBRARY_INCLUDES = \
+ -I$(TOP)/include \
+ -I$(TOP)/src/mapi \
+ -I$(TOP)/src/mesa \
+ $(X11_CFLAGS)
+
+C_SOURCES = \
+ glx_api.c \
+ glx_getproc.c \
+ glx_usefont.c \
+ xm_api.c \
+ xm_st.c
+
+include ../../../Makefile.template
diff --git a/src/gallium/state_trackers/glx/xlib/SConscript b/src/gallium/state_trackers/glx/xlib/SConscript
new file mode 100644
index 0000000000..9df351a276
--- /dev/null
+++ b/src/gallium/state_trackers/glx/xlib/SConscript
@@ -0,0 +1,27 @@
+#######################################################################
+# SConscript for xlib state_tracker
+
+Import('*')
+
+if env['platform'] == 'linux' \
+ and 'mesa' in env['statetrackers']:
+
+ env = env.Clone()
+
+ env.Append(CPPPATH = [
+ '#/src/mapi',
+ '#/src/mesa',
+ '#/src/mesa/main',
+ ])
+
+ st_xlib = env.ConvenienceLibrary(
+ target = 'st_xlib',
+ source = [
+ 'glx_api.c',
+ 'glx_getproc.c',
+ 'glx_usefont.c',
+ 'xm_api.c',
+ 'xm_st.c',
+ ]
+ )
+ Export('st_xlib')
diff --git a/src/gallium/state_trackers/glx/xlib/glx_api.c b/src/gallium/state_trackers/glx/xlib/glx_api.c
new file mode 100644
index 0000000000..eb8d6a1933
--- /dev/null
+++ b/src/gallium/state_trackers/glx/xlib/glx_api.c
@@ -0,0 +1,2648 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.6
+ *
+ * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
+ * Copyright (C) 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL 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.
+ */
+
+
+/**
+ * "Fake" GLX API implemented in terms of the XMesa*() functions.
+ */
+
+
+
+#define GLX_GLXEXT_PROTOTYPES
+#include "GL/glx.h"
+
+#include "xm_api.h"
+#include "main/context.h"
+#include "main/macros.h"
+#include "main/imports.h"
+#include "main/version.h"
+
+
+/* This indicates the client-side GLX API and GLX encoder version. */
+#define CLIENT_MAJOR_VERSION 1
+#define CLIENT_MINOR_VERSION 4 /* but don't have 1.3's pbuffers, etc yet */
+
+/* This indicates the server-side GLX decoder version.
+ * GLX 1.4 indicates OpenGL 1.3 support
+ */
+#define SERVER_MAJOR_VERSION 1
+#define SERVER_MINOR_VERSION 4
+
+/* This is appended onto the glXGetClient/ServerString version strings. */
+#define MESA_GLX_VERSION "Mesa " MESA_VERSION_STRING
+
+/* Who implemented this GLX? */
+#define VENDOR "Brian Paul"
+
+#define EXTENSIONS \
+ "GLX_MESA_copy_sub_buffer " \
+ "GLX_MESA_pixmap_colormap " \
+ "GLX_MESA_release_buffers " \
+ "GLX_ARB_get_proc_address " \
+ "GLX_EXT_texture_from_pixmap " \
+ "GLX_EXT_visual_info " \
+ "GLX_EXT_visual_rating " \
+ /*"GLX_SGI_video_sync "*/ \
+ "GLX_SGIX_fbconfig " \
+ "GLX_SGIX_pbuffer "
+
+#define DEFAULT_DIRECT GL_TRUE
+
+
+
+/**
+ * The GLXContext typedef is defined as a pointer to this structure.
+ */
+struct __GLXcontextRec
+{
+ Display *currentDpy;
+ GLboolean isDirect;
+ GLXDrawable currentDrawable;
+ GLXDrawable currentReadable;
+ XID xid;
+
+ XMesaContext xmesaContext;
+};
+
+
+
+static pipe_tsd ContextTSD;
+
+/** Set current context for calling thread */
+static void
+SetCurrentContext(GLXContext c)
+{
+ pipe_tsd_set(&ContextTSD, c);
+}
+
+/** Get current context for calling thread */
+static GLXContext
+GetCurrentContext(void)
+{
+ return pipe_tsd_get(&ContextTSD);
+}
+
+
+
+/**********************************************************************/
+/*** GLX Visual Code ***/
+/**********************************************************************/
+
+#define DONT_CARE -1
+
+
+static XMesaVisual *VisualTable = NULL;
+static int NumVisuals = 0;
+
+
+
+/* Macro to handle c_class vs class field name in XVisualInfo struct */
+#if defined(__cplusplus) || defined(c_plusplus)
+#define CLASS c_class
+#else
+#define CLASS class
+#endif
+
+
+
+/*
+ * Test if the given XVisualInfo is usable for Mesa rendering.
+ */
+static GLboolean
+is_usable_visual( XVisualInfo *vinfo )
+{
+ switch (vinfo->CLASS) {
+ case StaticGray:
+ case GrayScale:
+ /* Any StaticGray/GrayScale visual works in RGB or CI mode */
+ return GL_TRUE;
+ case StaticColor:
+ case PseudoColor:
+ /* Any StaticColor/PseudoColor visual of at least 4 bits */
+ if (vinfo->depth>=4) {
+ return GL_TRUE;
+ }
+ else {
+ return GL_FALSE;
+ }
+ case TrueColor:
+ case DirectColor:
+ /* Any depth of TrueColor or DirectColor works in RGB mode */
+ return GL_TRUE;
+ default:
+ /* This should never happen */
+ return GL_FALSE;
+ }
+}
+
+
+/*
+ * Given an XVisualInfo and RGB, Double, and Depth buffer flags, save the
+ * configuration in our list of GLX visuals.
+ */
+static XMesaVisual
+save_glx_visual( Display *dpy, XVisualInfo *vinfo,
+ GLboolean rgbFlag, GLboolean alphaFlag, GLboolean dbFlag,
+ GLboolean stereoFlag,
+ GLint depth_size, GLint stencil_size,
+ GLint accumRedSize, GLint accumGreenSize,
+ GLint accumBlueSize, GLint accumAlphaSize,
+ GLint level, GLint numAuxBuffers )
+{
+ GLboolean ximageFlag = GL_TRUE;
+ XMesaVisual xmvis;
+ GLint i;
+ GLboolean comparePointers;
+
+ if (dbFlag) {
+ /* Check if the MESA_BACK_BUFFER env var is set */
+ char *backbuffer = _mesa_getenv("MESA_BACK_BUFFER");
+ if (backbuffer) {
+ if (backbuffer[0]=='p' || backbuffer[0]=='P') {
+ ximageFlag = GL_FALSE;
+ }
+ else if (backbuffer[0]=='x' || backbuffer[0]=='X') {
+ ximageFlag = GL_TRUE;
+ }
+ else {
+ _mesa_warning(NULL, "Mesa: invalid value for MESA_BACK_BUFFER environment variable, using an XImage.");
+ }
+ }
+ }
+
+ if (stereoFlag) {
+ /* stereo not supported */
+ return NULL;
+ }
+
+ if (stencil_size > 0 && depth_size > 0)
+ depth_size = 24;
+
+ /* Comparing IDs uses less memory but sometimes fails. */
+ /* XXX revisit this after 3.0 is finished. */
+ if (_mesa_getenv("MESA_GLX_VISUAL_HACK"))
+ comparePointers = GL_TRUE;
+ else
+ comparePointers = GL_FALSE;
+
+ /* Force the visual to have an alpha channel */
+ if (rgbFlag && _mesa_getenv("MESA_GLX_FORCE_ALPHA"))
+ alphaFlag = GL_TRUE;
+
+ /* First check if a matching visual is already in the list */
+ for (i=0; i<NumVisuals; i++) {
+ XMesaVisual v = VisualTable[i];
+ if (v->display == dpy
+ && v->mesa_visual.level == level
+ && v->mesa_visual.numAuxBuffers == numAuxBuffers
+ && v->ximage_flag == ximageFlag
+ && v->mesa_visual.rgbMode == rgbFlag
+ && v->mesa_visual.doubleBufferMode == dbFlag
+ && v->mesa_visual.stereoMode == stereoFlag
+ && (v->mesa_visual.alphaBits > 0) == alphaFlag
+ && (v->mesa_visual.depthBits >= depth_size || depth_size == 0)
+ && (v->mesa_visual.stencilBits >= stencil_size || stencil_size == 0)
+ && (v->mesa_visual.accumRedBits >= accumRedSize || accumRedSize == 0)
+ && (v->mesa_visual.accumGreenBits >= accumGreenSize || accumGreenSize == 0)
+ && (v->mesa_visual.accumBlueBits >= accumBlueSize || accumBlueSize == 0)
+ && (v->mesa_visual.accumAlphaBits >= accumAlphaSize || accumAlphaSize == 0)) {
+ /* now either compare XVisualInfo pointers or visual IDs */
+ if ((!comparePointers && v->visinfo->visualid == vinfo->visualid)
+ || (comparePointers && v->vishandle == vinfo)) {
+ return v;
+ }
+ }
+ }
+
+ /* Create a new visual and add it to the list. */
+
+ xmvis = XMesaCreateVisual( dpy, vinfo, rgbFlag, alphaFlag, dbFlag,
+ stereoFlag, ximageFlag,
+ depth_size, stencil_size,
+ accumRedSize, accumBlueSize,
+ accumBlueSize, accumAlphaSize, 0, level,
+ GLX_NONE_EXT );
+ if (xmvis) {
+ /* Save a copy of the pointer now so we can find this visual again
+ * if we need to search for it in find_glx_visual().
+ */
+ xmvis->vishandle = vinfo;
+ /* Allocate more space for additional visual */
+ VisualTable = (XMesaVisual *) _mesa_realloc( VisualTable,
+ sizeof(XMesaVisual) * NumVisuals,
+ sizeof(XMesaVisual) * (NumVisuals + 1));
+ /* add xmvis to the list */
+ VisualTable[NumVisuals] = xmvis;
+ NumVisuals++;
+ /* XXX minor hack, because XMesaCreateVisual doesn't support an
+ * aux buffers parameter.
+ */
+ xmvis->mesa_visual.numAuxBuffers = numAuxBuffers;
+ }
+ return xmvis;
+}
+
+
+/**
+ * Return the default number of bits for the Z buffer.
+ * If defined, use the MESA_GLX_DEPTH_BITS env var value.
+ * Otherwise, use the DEFAULT_SOFTWARE_DEPTH_BITS constant.
+ * XXX probably do the same thing for stencil, accum, etc.
+ */
+static GLint
+default_depth_bits(void)
+{
+ int zBits;
+ const char *zEnv = _mesa_getenv("MESA_GLX_DEPTH_BITS");
+ if (zEnv)
+ zBits = atoi(zEnv);
+ else
+ zBits = DEFAULT_SOFTWARE_DEPTH_BITS;
+ return zBits;
+}
+
+static GLint
+default_alpha_bits(void)
+{
+ int aBits;
+ const char *aEnv = _mesa_getenv("MESA_GLX_ALPHA_BITS");
+ if (aEnv)
+ aBits = atoi(aEnv);
+ else
+ aBits = 0;
+ return aBits;
+}
+
+static GLint
+default_accum_bits(void)
+{
+ return 16;
+}
+
+
+
+/*
+ * Create a GLX visual from a regular XVisualInfo.
+ * This is called when Fake GLX is given an XVisualInfo which wasn't
+ * returned by glXChooseVisual. Since this is the first time we're
+ * considering this visual we'll take a guess at reasonable values
+ * for depth buffer size, stencil size, accum size, etc.
+ * This is the best we can do with a client-side emulation of GLX.
+ */
+static XMesaVisual
+create_glx_visual( Display *dpy, XVisualInfo *visinfo )
+{
+ GLint zBits = default_depth_bits();
+ GLint accBits = default_accum_bits();
+ GLboolean alphaFlag = default_alpha_bits() > 0;
+
+ if (is_usable_visual( visinfo )) {
+ /* Configure this visual as RGB, double-buffered, depth-buffered. */
+ /* This is surely wrong for some people's needs but what else */
+ /* can be done? They should use glXChooseVisual(). */
+ return save_glx_visual( dpy, visinfo,
+ GL_TRUE, /* rgb */
+ alphaFlag, /* alpha */
+ GL_TRUE, /* double */
+ GL_FALSE, /* stereo */
+ zBits,
+ STENCIL_BITS,
+ accBits, /* r */
+ accBits, /* g */
+ accBits, /* b */
+ accBits, /* a */
+ 0, /* level */
+ 0 /* numAux */
+ );
+ }
+ else {
+ _mesa_warning(NULL, "Mesa: error in glXCreateContext: bad visual\n");
+ return NULL;
+ }
+}
+
+
+
+/*
+ * Find the GLX visual associated with an XVisualInfo.
+ */
+static XMesaVisual
+find_glx_visual( Display *dpy, XVisualInfo *vinfo )
+{
+ int i;
+
+ /* try to match visual id */
+ for (i=0;i<NumVisuals;i++) {
+ if (VisualTable[i]->display==dpy
+ && VisualTable[i]->visinfo->visualid == vinfo->visualid) {
+ return VisualTable[i];
+ }
+ }
+
+ /* if that fails, try to match pointers */
+ for (i=0;i<NumVisuals;i++) {
+ if (VisualTable[i]->display==dpy && VisualTable[i]->vishandle==vinfo) {
+ return VisualTable[i];
+ }
+ }
+
+ return NULL;
+}
+
+
+/**
+ * Try to get an X visual which matches the given arguments.
+ */
+static XVisualInfo *
+get_visual( Display *dpy, int scr, unsigned int depth, int xclass )
+{
+ XVisualInfo temp, *vis;
+ long mask;
+ int n;
+ unsigned int default_depth;
+ int default_class;
+
+ mask = VisualScreenMask | VisualDepthMask | VisualClassMask;
+ temp.screen = scr;
+ temp.depth = depth;
+ temp.CLASS = xclass;
+
+ default_depth = DefaultDepth(dpy,scr);
+ default_class = DefaultVisual(dpy,scr)->CLASS;
+
+ if (depth==default_depth && xclass==default_class) {
+ /* try to get root window's visual */
+ temp.visualid = DefaultVisual(dpy,scr)->visualid;
+ mask |= VisualIDMask;
+ }
+
+ vis = XGetVisualInfo( dpy, mask, &temp, &n );
+
+ /* In case bits/pixel > 24, make sure color channels are still <=8 bits.
+ * An SGI Infinite Reality system, for example, can have 30bpp pixels:
+ * 10 bits per color channel. Mesa's limited to a max of 8 bits/channel.
+ */
+ if (vis && depth > 24 && (xclass==TrueColor || xclass==DirectColor)) {
+ if (_mesa_bitcount((GLuint) vis->red_mask ) <= 8 &&
+ _mesa_bitcount((GLuint) vis->green_mask) <= 8 &&
+ _mesa_bitcount((GLuint) vis->blue_mask ) <= 8) {
+ return vis;
+ }
+ else {
+ XFree((void *) vis);
+ return NULL;
+ }
+ }
+
+ return vis;
+}
+
+
+/*
+ * Retrieve the value of the given environment variable and find
+ * the X visual which matches it.
+ * Input: dpy - the display
+ * screen - the screen number
+ * varname - the name of the environment variable
+ * Return: an XVisualInfo pointer to NULL if error.
+ */
+static XVisualInfo *
+get_env_visual(Display *dpy, int scr, const char *varname)
+{
+ char value[100], type[100];
+ int depth, xclass = -1;
+ XVisualInfo *vis;
+
+ if (!_mesa_getenv( varname )) {
+ return NULL;
+ }
+
+ strncpy( value, _mesa_getenv(varname), 100 );
+ value[99] = 0;
+
+ sscanf( value, "%s %d", type, &depth );
+
+ if (strcmp(type,"TrueColor")==0) xclass = TrueColor;
+ else if (strcmp(type,"DirectColor")==0) xclass = DirectColor;
+ else if (strcmp(type,"PseudoColor")==0) xclass = PseudoColor;
+ else if (strcmp(type,"StaticColor")==0) xclass = StaticColor;
+ else if (strcmp(type,"GrayScale")==0) xclass = GrayScale;
+ else if (strcmp(type,"StaticGray")==0) xclass = StaticGray;
+
+ if (xclass>-1 && depth>0) {
+ vis = get_visual( dpy, scr, depth, xclass );
+ if (vis) {
+ return vis;
+ }
+ }
+
+ _mesa_warning(NULL, "GLX unable to find visual class=%s, depth=%d.",
+ type, depth);
+
+ return NULL;
+}
+
+
+
+/*
+ * Select an X visual which satisfies the RGBA flag and minimum depth.
+ * Input: dpy,
+ * screen - X display and screen number
+ * min_depth - minimum visual depth
+ * preferred_class - preferred GLX visual class or DONT_CARE
+ * Return: pointer to an XVisualInfo or NULL.
+ */
+static XVisualInfo *
+choose_x_visual( Display *dpy, int screen, int min_depth,
+ int preferred_class )
+{
+ XVisualInfo *vis;
+ int xclass, visclass = 0;
+ int depth;
+
+ /* First see if the MESA_RGB_VISUAL env var is defined */
+ vis = get_env_visual( dpy, screen, "MESA_RGB_VISUAL" );
+ if (vis) {
+ return vis;
+ }
+ /* Otherwise, search for a suitable visual */
+ if (preferred_class==DONT_CARE) {
+ for (xclass=0;xclass<6;xclass++) {
+ switch (xclass) {
+ case 0: visclass = TrueColor; break;
+ case 1: visclass = DirectColor; break;
+ case 2: visclass = PseudoColor; break;
+ case 3: visclass = StaticColor; break;
+ case 4: visclass = GrayScale; break;
+ case 5: visclass = StaticGray; break;
+ }
+ if (min_depth==0) {
+ /* start with shallowest */
+ for (depth=0;depth<=32;depth++) {
+ if (visclass==TrueColor && depth==8) {
+ /* Special case: try to get 8-bit PseudoColor before */
+ /* 8-bit TrueColor */
+ vis = get_visual( dpy, screen, 8, PseudoColor );
+ if (vis) {
+ return vis;
+ }
+ }
+ vis = get_visual( dpy, screen, depth, visclass );
+ if (vis) {
+ return vis;
+ }
+ }
+ }
+ else {
+ /* start with deepest */
+ for (depth=32;depth>=min_depth;depth--) {
+ if (visclass==TrueColor && depth==8) {
+ /* Special case: try to get 8-bit PseudoColor before */
+ /* 8-bit TrueColor */
+ vis = get_visual( dpy, screen, 8, PseudoColor );
+ if (vis) {
+ return vis;
+ }
+ }
+ vis = get_visual( dpy, screen, depth, visclass );
+ if (vis) {
+ return vis;
+ }
+ }
+ }
+ }
+ }
+ else {
+ /* search for a specific visual class */
+ switch (preferred_class) {
+ case GLX_TRUE_COLOR_EXT: visclass = TrueColor; break;
+ case GLX_DIRECT_COLOR_EXT: visclass = DirectColor; break;
+ case GLX_PSEUDO_COLOR_EXT: visclass = PseudoColor; break;
+ case GLX_STATIC_COLOR_EXT: visclass = StaticColor; break;
+ case GLX_GRAY_SCALE_EXT: visclass = GrayScale; break;
+ case GLX_STATIC_GRAY_EXT: visclass = StaticGray; break;
+ default: return NULL;
+ }
+ if (min_depth==0) {
+ /* start with shallowest */
+ for (depth=0;depth<=32;depth++) {
+ vis = get_visual( dpy, screen, depth, visclass );
+ if (vis) {
+ return vis;
+ }
+ }
+ }
+ else {
+ /* start with deepest */
+ for (depth=32;depth>=min_depth;depth--) {
+ vis = get_visual( dpy, screen, depth, visclass );
+ if (vis) {
+ return vis;
+ }
+ }
+ }
+ }
+
+ /* didn't find a visual */
+ return NULL;
+}
+
+
+
+
+/**********************************************************************/
+/*** Display-related functions ***/
+/**********************************************************************/
+
+
+/**
+ * Free all XMesaVisuals which are associated with the given display.
+ */
+static void
+destroy_visuals_on_display(Display *dpy)
+{
+ int i;
+ for (i = 0; i < NumVisuals; i++) {
+ if (VisualTable[i]->display == dpy) {
+ /* remove this visual */
+ int j;
+ free(VisualTable[i]);
+ for (j = i; j < NumVisuals - 1; j++)
+ VisualTable[j] = VisualTable[j + 1];
+ NumVisuals--;
+ }
+ }
+}
+
+
+/**
+ * Called from XCloseDisplay() to let us free our display-related data.
+ */
+static int
+close_display_callback(Display *dpy, XExtCodes *codes)
+{
+ destroy_visuals_on_display(dpy);
+ xmesa_destroy_buffers_on_display(dpy);
+ return 0;
+}
+
+
+/**
+ * Look for the named extension on given display and return a pointer
+ * to the _XExtension data, or NULL if extension not found.
+ */
+static _XExtension *
+lookup_extension(Display *dpy, const char *extName)
+{
+ _XExtension *ext;
+ for (ext = dpy->ext_procs; ext; ext = ext->next) {
+ if (ext->name && strcmp(ext->name, extName) == 0) {
+ return ext;
+ }
+ }
+ return NULL;
+}
+
+
+/**
+ * Whenever we're given a new Display pointer, call this function to
+ * register our close_display_callback function.
+ */
+static void
+register_with_display(Display *dpy)
+{
+ const char *extName = "MesaGLX";
+ _XExtension *ext;
+
+ ext = lookup_extension(dpy, extName);
+ if (!ext) {
+ XExtCodes *c = XAddExtension(dpy);
+ ext = dpy->ext_procs; /* new extension is at head of list */
+ assert(c->extension == ext->codes.extension);
+ (void) c;
+ ext->name = _mesa_strdup(extName);
+ ext->close_display = close_display_callback;
+ }
+}
+
+
+/**********************************************************************/
+/*** Begin Fake GLX API Functions ***/
+/**********************************************************************/
+
+
+/**
+ * Helper used by glXChooseVisual and glXChooseFBConfig.
+ * The fbConfig parameter must be GL_FALSE for the former and GL_TRUE for
+ * the later.
+ * In either case, the attribute list is terminated with the value 'None'.
+ */
+static XMesaVisual
+choose_visual( Display *dpy, int screen, const int *list, GLboolean fbConfig )
+{
+ const GLboolean rgbModeDefault = fbConfig;
+ const int *parselist;
+ XVisualInfo *vis;
+ int min_ci = 0;
+ int min_red=0, min_green=0, min_blue=0;
+ GLboolean rgb_flag = rgbModeDefault;
+ GLboolean alpha_flag = GL_FALSE;
+ GLboolean double_flag = GL_FALSE;
+ GLboolean stereo_flag = GL_FALSE;
+ GLint depth_size = 0;
+ GLint stencil_size = 0;
+ GLint accumRedSize = 0;
+ GLint accumGreenSize = 0;
+ GLint accumBlueSize = 0;
+ GLint accumAlphaSize = 0;
+ int level = 0;
+ int visual_type = DONT_CARE;
+ int trans_type = DONT_CARE;
+ int trans_value = DONT_CARE;
+ GLint caveat = DONT_CARE;
+ XMesaVisual xmvis = NULL;
+ int desiredVisualID = -1;
+ int numAux = 0;
+
+ xmesa_init( dpy );
+
+ parselist = list;
+
+ while (*parselist) {
+
+ switch (*parselist) {
+ case GLX_USE_GL:
+ if (fbConfig) {
+ /* invalid token */
+ return NULL;
+ }
+ else {
+ /* skip */
+ parselist++;
+ }
+ break;
+ case GLX_BUFFER_SIZE:
+ parselist++;
+ min_ci = *parselist++;
+ break;
+ case GLX_LEVEL:
+ parselist++;
+ level = *parselist++;
+ break;
+ case GLX_RGBA:
+ if (fbConfig) {
+ /* invalid token */
+ return NULL;
+ }
+ else {
+ rgb_flag = GL_TRUE;
+ parselist++;
+ }
+ break;
+ case GLX_DOUBLEBUFFER:
+ parselist++;
+ if (fbConfig) {
+ double_flag = *parselist++;
+ }
+ else {
+ double_flag = GL_TRUE;
+ }
+ break;
+ case GLX_STEREO:
+ parselist++;
+ if (fbConfig) {
+ stereo_flag = *parselist++;
+ }
+ else {
+ stereo_flag = GL_TRUE;
+ }
+ break;
+ case GLX_AUX_BUFFERS:
+ parselist++;
+ numAux = *parselist++;
+ if (numAux > MAX_AUX_BUFFERS)
+ return NULL;
+ break;
+ case GLX_RED_SIZE:
+ parselist++;
+ min_red = *parselist++;
+ break;
+ case GLX_GREEN_SIZE:
+ parselist++;
+ min_green = *parselist++;
+ break;
+ case GLX_BLUE_SIZE:
+ parselist++;
+ min_blue = *parselist++;
+ break;
+ case GLX_ALPHA_SIZE:
+ parselist++;
+ {
+ GLint size = *parselist++;
+ alpha_flag = size ? GL_TRUE : GL_FALSE;
+ }
+ break;
+ case GLX_DEPTH_SIZE:
+ parselist++;
+ depth_size = *parselist++;
+ break;
+ case GLX_STENCIL_SIZE:
+ parselist++;
+ stencil_size = *parselist++;
+ break;
+ case GLX_ACCUM_RED_SIZE:
+ parselist++;
+ {
+ GLint size = *parselist++;
+ accumRedSize = MAX2( accumRedSize, size );
+ }
+ break;
+ case GLX_ACCUM_GREEN_SIZE:
+ parselist++;
+ {
+ GLint size = *parselist++;
+ accumGreenSize = MAX2( accumGreenSize, size );
+ }
+ break;
+ case GLX_ACCUM_BLUE_SIZE:
+ parselist++;
+ {
+ GLint size = *parselist++;
+ accumBlueSize = MAX2( accumBlueSize, size );
+ }
+ break;
+ case GLX_ACCUM_ALPHA_SIZE:
+ parselist++;
+ {
+ GLint size = *parselist++;
+ accumAlphaSize = MAX2( accumAlphaSize, size );
+ }
+ break;
+
+ /*
+ * GLX_EXT_visual_info extension
+ */
+ case GLX_X_VISUAL_TYPE_EXT:
+ parselist++;
+ visual_type = *parselist++;
+ break;
+ case GLX_TRANSPARENT_TYPE_EXT:
+ parselist++;
+ trans_type = *parselist++;
+ break;
+ case GLX_TRANSPARENT_INDEX_VALUE_EXT:
+ parselist++;
+ trans_value = *parselist++;
+ break;
+ case GLX_TRANSPARENT_RED_VALUE_EXT:
+ case GLX_TRANSPARENT_GREEN_VALUE_EXT:
+ case GLX_TRANSPARENT_BLUE_VALUE_EXT:
+ case GLX_TRANSPARENT_ALPHA_VALUE_EXT:
+ /* ignore */
+ parselist++;
+ parselist++;
+ break;
+
+ /*
+ * GLX_EXT_visual_info extension
+ */
+ case GLX_VISUAL_CAVEAT_EXT:
+ parselist++;
+ caveat = *parselist++; /* ignored for now */
+ break;
+
+ /*
+ * GLX_ARB_multisample
+ */
+ case GLX_SAMPLE_BUFFERS_ARB:
+ /* ms not supported */
+ return NULL;
+ case GLX_SAMPLES_ARB:
+ /* ms not supported */
+ return NULL;
+
+ /*
+ * FBConfig attribs.
+ */
+ case GLX_RENDER_TYPE:
+ if (!fbConfig)
+ return NULL;
+ parselist++;
+ if (*parselist & GLX_RGBA_BIT) {
+ rgb_flag = GL_TRUE;
+ }
+ else if (*parselist & GLX_COLOR_INDEX_BIT) {
+ rgb_flag = GL_FALSE;
+ }
+ else if (*parselist == 0) {
+ rgb_flag = GL_TRUE;
+ }
+ parselist++;
+ break;
+ case GLX_DRAWABLE_TYPE:
+ if (!fbConfig)
+ return NULL;
+ parselist++;
+ if (*parselist & ~(GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT)) {
+ return NULL; /* bad bit */
+ }
+ parselist++;
+ break;
+ case GLX_FBCONFIG_ID:
+ if (!fbConfig)
+ return NULL;
+ parselist++;
+ desiredVisualID = *parselist++;
+ break;
+ case GLX_X_RENDERABLE:
+ if (!fbConfig)
+ return NULL;
+ parselist += 2;
+ /* ignore */
+ break;
+
+#ifdef GLX_EXT_texture_from_pixmap
+ case GLX_BIND_TO_TEXTURE_RGB_EXT:
+ parselist++; /*skip*/
+ break;
+ case GLX_BIND_TO_TEXTURE_RGBA_EXT:
+ parselist++; /*skip*/
+ break;
+ case GLX_BIND_TO_MIPMAP_TEXTURE_EXT:
+ parselist++; /*skip*/
+ break;
+ case GLX_BIND_TO_TEXTURE_TARGETS_EXT:
+ parselist++;
+ if (*parselist & ~(GLX_TEXTURE_1D_BIT_EXT |
+ GLX_TEXTURE_2D_BIT_EXT |
+ GLX_TEXTURE_RECTANGLE_BIT_EXT)) {
+ /* invalid bit */
+ return NULL;
+ }
+ break;
+ case GLX_Y_INVERTED_EXT:
+ parselist++; /*skip*/
+ break;
+#endif
+
+ case None:
+ /* end of list */
+ break;
+
+ default:
+ /* undefined attribute */
+ _mesa_warning(NULL, "unexpected attrib 0x%x in choose_visual()",
+ *parselist);
+ return NULL;
+ }
+ }
+
+ (void) caveat;
+
+
+ /*
+ * Since we're only simulating the GLX extension this function will never
+ * find any real GL visuals. Instead, all we can do is try to find an RGB
+ * or CI visual of appropriate depth. Other requested attributes such as
+ * double buffering, depth buffer, etc. will be associated with the X
+ * visual and stored in the VisualTable[].
+ */
+ if (desiredVisualID != -1) {
+ /* try to get a specific visual, by visualID */
+ XVisualInfo temp;
+ int n;
+ temp.visualid = desiredVisualID;
+ temp.screen = screen;
+ vis = XGetVisualInfo(dpy, VisualIDMask | VisualScreenMask, &temp, &n);
+ if (vis) {
+ /* give the visual some useful GLX attributes */
+ double_flag = GL_TRUE;
+ rgb_flag = GL_TRUE;
+ }
+ }
+ else if (level==0) {
+ /* normal color planes */
+ /* Get an RGB visual */
+ int min_rgb = min_red + min_green + min_blue;
+ if (min_rgb>1 && min_rgb<8) {
+ /* a special case to be sure we can get a monochrome visual */
+ min_rgb = 1;
+ }
+ vis = choose_x_visual( dpy, screen, min_rgb, visual_type );
+ }
+ else {
+ _mesa_warning(NULL, "overlay not supported");
+ return NULL;
+ }
+
+ if (vis) {
+ /* Note: we're not exactly obeying the glXChooseVisual rules here.
+ * When GLX_DEPTH_SIZE = 1 is specified we're supposed to choose the
+ * largest depth buffer size, which is 32bits/value. Instead, we
+ * return 16 to maintain performance with earlier versions of Mesa.
+ */
+ if (stencil_size > 0)
+ depth_size = 24; /* if Z and stencil, always use 24+8 format */
+ else if (depth_size > 24)
+ depth_size = 32;
+ else if (depth_size > 16)
+ depth_size = 24;
+ else if (depth_size > 0) {
+ depth_size = default_depth_bits();
+ }
+
+ if (!alpha_flag) {
+ alpha_flag = default_alpha_bits() > 0;
+ }
+
+ /* we only support one size of stencil and accum buffers. */
+ if (stencil_size > 0)
+ stencil_size = STENCIL_BITS;
+
+ if (accumRedSize > 0 ||
+ accumGreenSize > 0 ||
+ accumBlueSize > 0 ||
+ accumAlphaSize > 0) {
+
+ accumRedSize =
+ accumGreenSize =
+ accumBlueSize = default_accum_bits();
+
+ accumAlphaSize = alpha_flag ? accumRedSize : 0;
+ }
+
+ xmvis = save_glx_visual( dpy, vis, rgb_flag, alpha_flag, double_flag,
+ stereo_flag, depth_size, stencil_size,
+ accumRedSize, accumGreenSize,
+ accumBlueSize, accumAlphaSize, level, numAux );
+ }
+
+ return xmvis;
+}
+
+
+PUBLIC XVisualInfo *
+glXChooseVisual( Display *dpy, int screen, int *list )
+{
+ XMesaVisual xmvis;
+
+ /* register ourselves as an extension on this display */
+ register_with_display(dpy);
+
+ xmvis = choose_visual(dpy, screen, list, GL_FALSE);
+ if (xmvis) {
+ /* create a new vishandle - the cached one may be stale */
+ xmvis->vishandle = (XVisualInfo *) malloc(sizeof(XVisualInfo));
+ if (xmvis->vishandle) {
+ memcpy(xmvis->vishandle, xmvis->visinfo, sizeof(XVisualInfo));
+ }
+ return xmvis->vishandle;
+ }
+ else
+ return NULL;
+}
+
+
+PUBLIC GLXContext
+glXCreateContext( Display *dpy, XVisualInfo *visinfo,
+ GLXContext share_list, Bool direct )
+{
+ XMesaVisual xmvis;
+ GLXContext glxCtx;
+ GLXContext shareCtx = share_list;
+
+ if (!dpy || !visinfo)
+ return 0;
+
+ glxCtx = CALLOC_STRUCT(__GLXcontextRec);
+ if (!glxCtx)
+ return 0;
+
+ /* deallocate unused windows/buffers */
+#if 0
+ XMesaGarbageCollect();
+#endif
+
+ xmvis = find_glx_visual( dpy, visinfo );
+ if (!xmvis) {
+ /* This visual wasn't found with glXChooseVisual() */
+ xmvis = create_glx_visual( dpy, visinfo );
+ if (!xmvis) {
+ /* unusable visual */
+ free(glxCtx);
+ return NULL;
+ }
+ }
+
+ glxCtx->xmesaContext = XMesaCreateContext(xmvis,
+ shareCtx ? shareCtx->xmesaContext : NULL);
+ if (!glxCtx->xmesaContext) {
+ free(glxCtx);
+ return NULL;
+ }
+
+ glxCtx->isDirect = DEFAULT_DIRECT;
+ glxCtx->currentDpy = dpy;
+ glxCtx->xid = (XID) glxCtx; /* self pointer */
+
+ return glxCtx;
+}
+
+
+/* XXX these may have to be removed due to thread-safety issues. */
+static GLXContext MakeCurrent_PrevContext = 0;
+static GLXDrawable MakeCurrent_PrevDrawable = 0;
+static GLXDrawable MakeCurrent_PrevReadable = 0;
+static XMesaBuffer MakeCurrent_PrevDrawBuffer = 0;
+static XMesaBuffer MakeCurrent_PrevReadBuffer = 0;
+
+
+/* GLX 1.3 and later */
+PUBLIC Bool
+glXMakeContextCurrent( Display *dpy, GLXDrawable draw,
+ GLXDrawable read, GLXContext ctx )
+{
+ GLXContext glxCtx = ctx;
+ static boolean firsttime = 1, no_rast = 0;
+
+ if (firsttime) {
+ no_rast = getenv("SP_NO_RAST") != NULL;
+ firsttime = 0;
+ }
+
+ if (ctx && draw && read) {
+ XMesaBuffer drawBuffer, readBuffer;
+ XMesaContext xmctx = glxCtx->xmesaContext;
+
+ /* Find the XMesaBuffer which corresponds to the GLXDrawable 'draw' */
+ if (ctx == MakeCurrent_PrevContext
+ && draw == MakeCurrent_PrevDrawable) {
+ drawBuffer = MakeCurrent_PrevDrawBuffer;
+ }
+ else {
+ drawBuffer = XMesaFindBuffer( dpy, draw );
+ }
+ if (!drawBuffer) {
+ /* drawable must be a new window! */
+ drawBuffer = XMesaCreateWindowBuffer( xmctx->xm_visual, draw );
+ if (!drawBuffer) {
+ /* Out of memory, or context/drawable depth mismatch */
+ return False;
+ }
+ }
+
+ /* Find the XMesaBuffer which corresponds to the GLXDrawable 'read' */
+ if (ctx == MakeCurrent_PrevContext
+ && read == MakeCurrent_PrevReadable) {
+ readBuffer = MakeCurrent_PrevReadBuffer;
+ }
+ else {
+ readBuffer = XMesaFindBuffer( dpy, read );
+ }
+ if (!readBuffer) {
+ /* drawable must be a new window! */
+ readBuffer = XMesaCreateWindowBuffer( xmctx->xm_visual, read );
+ if (!readBuffer) {
+ /* Out of memory, or context/drawable depth mismatch */
+ return False;
+ }
+ }
+
+ if (no_rast &&
+ MakeCurrent_PrevContext == ctx &&
+ MakeCurrent_PrevDrawable == draw &&
+ MakeCurrent_PrevReadable == read &&
+ MakeCurrent_PrevDrawBuffer == drawBuffer &&
+ MakeCurrent_PrevReadBuffer == readBuffer)
+ return True;
+
+ MakeCurrent_PrevContext = ctx;
+ MakeCurrent_PrevDrawable = draw;
+ MakeCurrent_PrevReadable = read;
+ MakeCurrent_PrevDrawBuffer = drawBuffer;
+ MakeCurrent_PrevReadBuffer = readBuffer;
+
+ /* Now make current! */
+ if (XMesaMakeCurrent2(xmctx, drawBuffer, readBuffer)) {
+ ctx->currentDpy = dpy;
+ ctx->currentDrawable = draw;
+ ctx->currentReadable = read;
+ SetCurrentContext(ctx);
+ return True;
+ }
+ else {
+ return False;
+ }
+ }
+ else if (!ctx && !draw && !read) {
+ /* release current context w/out assigning new one. */
+ XMesaMakeCurrent2( NULL, NULL, NULL );
+ MakeCurrent_PrevContext = 0;
+ MakeCurrent_PrevDrawable = 0;
+ MakeCurrent_PrevReadable = 0;
+ MakeCurrent_PrevDrawBuffer = 0;
+ MakeCurrent_PrevReadBuffer = 0;
+ SetCurrentContext(NULL);
+ return True;
+ }
+ else {
+ /* The args must either all be non-zero or all zero.
+ * This is an error.
+ */
+ return False;
+ }
+}
+
+
+PUBLIC Bool
+glXMakeCurrent( Display *dpy, GLXDrawable drawable, GLXContext ctx )
+{
+ return glXMakeContextCurrent( dpy, drawable, drawable, ctx );
+}
+
+
+PUBLIC GLXContext
+glXGetCurrentContext(void)
+{
+ return GetCurrentContext();
+}
+
+
+PUBLIC Display *
+glXGetCurrentDisplay(void)
+{
+ GLXContext glxCtx = glXGetCurrentContext();
+
+ return glxCtx ? glxCtx->currentDpy : NULL;
+}
+
+
+PUBLIC Display *
+glXGetCurrentDisplayEXT(void)
+{
+ return glXGetCurrentDisplay();
+}
+
+
+PUBLIC GLXDrawable
+glXGetCurrentDrawable(void)
+{
+ GLXContext gc = glXGetCurrentContext();
+ return gc ? gc->currentDrawable : 0;
+}
+
+
+PUBLIC GLXDrawable
+glXGetCurrentReadDrawable(void)
+{
+ GLXContext gc = glXGetCurrentContext();
+ return gc ? gc->currentReadable : 0;
+}
+
+
+PUBLIC GLXDrawable
+glXGetCurrentReadDrawableSGI(void)
+{
+ return glXGetCurrentReadDrawable();
+}
+
+
+PUBLIC GLXPixmap
+glXCreateGLXPixmap( Display *dpy, XVisualInfo *visinfo, Pixmap pixmap )
+{
+ XMesaVisual v;
+ XMesaBuffer b;
+
+ v = find_glx_visual( dpy, visinfo );
+ if (!v) {
+ v = create_glx_visual( dpy, visinfo );
+ if (!v) {
+ /* unusable visual */
+ return 0;
+ }
+ }
+
+ b = XMesaCreatePixmapBuffer( v, pixmap, 0 );
+ if (!b) {
+ return 0;
+ }
+ return b->drawable;
+}
+
+
+/*** GLX_MESA_pixmap_colormap ***/
+
+PUBLIC GLXPixmap
+glXCreateGLXPixmapMESA( Display *dpy, XVisualInfo *visinfo,
+ Pixmap pixmap, Colormap cmap )
+{
+ XMesaVisual v;
+ XMesaBuffer b;
+
+ v = find_glx_visual( dpy, visinfo );
+ if (!v) {
+ v = create_glx_visual( dpy, visinfo );
+ if (!v) {
+ /* unusable visual */
+ return 0;
+ }
+ }
+
+ b = XMesaCreatePixmapBuffer( v, pixmap, cmap );
+ if (!b) {
+ return 0;
+ }
+ return b->drawable;
+}
+
+
+PUBLIC void
+glXDestroyGLXPixmap( Display *dpy, GLXPixmap pixmap )
+{
+ XMesaBuffer b = XMesaFindBuffer(dpy, pixmap);
+ if (b) {
+ XMesaDestroyBuffer(b);
+ }
+ else if (_mesa_getenv("MESA_DEBUG")) {
+ _mesa_warning(NULL, "Mesa: glXDestroyGLXPixmap: invalid pixmap\n");
+ }
+}
+
+
+PUBLIC void
+glXCopyContext( Display *dpy, GLXContext src, GLXContext dst,
+ unsigned long mask )
+{
+ XMesaContext xm_src = src->xmesaContext;
+ XMesaContext xm_dst = dst->xmesaContext;
+ (void) dpy;
+ if (MakeCurrent_PrevContext == src) {
+ _mesa_Flush();
+ }
+ XMesaCopyContext(xm_src, xm_dst, mask);
+}
+
+
+PUBLIC Bool
+glXQueryExtension( Display *dpy, int *errorBase, int *eventBase )
+{
+ int op, ev, err;
+ /* Mesa's GLX isn't really an X extension but we try to act like one. */
+ if (!XQueryExtension(dpy, GLX_EXTENSION_NAME, &op, &ev, &err))
+ ev = err = 0;
+ if (errorBase)
+ *errorBase = err;
+ if (eventBase)
+ *eventBase = ev;
+ return True; /* we're faking GLX so always return success */
+}
+
+
+PUBLIC void
+glXDestroyContext( Display *dpy, GLXContext ctx )
+{
+ GLXContext glxCtx = ctx;
+ (void) dpy;
+ MakeCurrent_PrevContext = 0;
+ MakeCurrent_PrevDrawable = 0;
+ MakeCurrent_PrevReadable = 0;
+ MakeCurrent_PrevDrawBuffer = 0;
+ MakeCurrent_PrevReadBuffer = 0;
+ XMesaDestroyContext( glxCtx->xmesaContext );
+ XMesaGarbageCollect();
+ free(glxCtx);
+}
+
+
+PUBLIC Bool
+glXIsDirect( Display *dpy, GLXContext ctx )
+{
+ GLXContext glxCtx = ctx;
+ (void) ctx;
+ return glxCtx->isDirect;
+}
+
+
+
+PUBLIC void
+glXSwapBuffers( Display *dpy, GLXDrawable drawable )
+{
+ XMesaBuffer buffer = XMesaFindBuffer( dpy, drawable );
+ static boolean firsttime = 1, no_rast = 0;
+
+ if (firsttime) {
+ no_rast = getenv("SP_NO_RAST") != NULL;
+ firsttime = 0;
+ }
+
+ if (no_rast)
+ return;
+
+ if (buffer) {
+ XMesaSwapBuffers(buffer);
+ }
+ else if (_mesa_getenv("MESA_DEBUG")) {
+ _mesa_warning(NULL, "glXSwapBuffers: invalid drawable 0x%x\n",
+ (int) drawable);
+ }
+}
+
+
+
+/*** GLX_MESA_copy_sub_buffer ***/
+
+PUBLIC void
+glXCopySubBufferMESA( Display *dpy, GLXDrawable drawable,
+ int x, int y, int width, int height )
+{
+ XMesaBuffer buffer = XMesaFindBuffer( dpy, drawable );
+ if (buffer) {
+ XMesaCopySubBuffer(buffer, x, y, width, height);
+ }
+ else if (_mesa_getenv("MESA_DEBUG")) {
+ _mesa_warning(NULL, "Mesa: glXCopySubBufferMESA: invalid drawable\n");
+ }
+}
+
+
+PUBLIC Bool
+glXQueryVersion( Display *dpy, int *maj, int *min )
+{
+ (void) dpy;
+ /* Return GLX version, not Mesa version */
+ assert(CLIENT_MAJOR_VERSION == SERVER_MAJOR_VERSION);
+ *maj = CLIENT_MAJOR_VERSION;
+ *min = MIN2( CLIENT_MINOR_VERSION, SERVER_MINOR_VERSION );
+ return True;
+}
+
+
+/*
+ * Query the GLX attributes of the given XVisualInfo.
+ */
+static int
+get_config( XMesaVisual xmvis, int attrib, int *value, GLboolean fbconfig )
+{
+ ASSERT(xmvis);
+ switch(attrib) {
+ case GLX_USE_GL:
+ if (fbconfig)
+ return GLX_BAD_ATTRIBUTE;
+ *value = (int) True;
+ return 0;
+ case GLX_BUFFER_SIZE:
+ *value = xmvis->visinfo->depth;
+ return 0;
+ case GLX_LEVEL:
+ *value = xmvis->mesa_visual.level;
+ return 0;
+ case GLX_RGBA:
+ if (fbconfig)
+ return GLX_BAD_ATTRIBUTE;
+ if (xmvis->mesa_visual.rgbMode) {
+ *value = True;
+ }
+ else {
+ *value = False;
+ }
+ return 0;
+ case GLX_DOUBLEBUFFER:
+ *value = (int) xmvis->mesa_visual.doubleBufferMode;
+ return 0;
+ case GLX_STEREO:
+ *value = (int) xmvis->mesa_visual.stereoMode;
+ return 0;
+ case GLX_AUX_BUFFERS:
+ *value = xmvis->mesa_visual.numAuxBuffers;
+ return 0;
+ case GLX_RED_SIZE:
+ *value = xmvis->mesa_visual.redBits;
+ return 0;
+ case GLX_GREEN_SIZE:
+ *value = xmvis->mesa_visual.greenBits;
+ return 0;
+ case GLX_BLUE_SIZE:
+ *value = xmvis->mesa_visual.blueBits;
+ return 0;
+ case GLX_ALPHA_SIZE:
+ *value = xmvis->mesa_visual.alphaBits;
+ return 0;
+ case GLX_DEPTH_SIZE:
+ *value = xmvis->mesa_visual.depthBits;
+ return 0;
+ case GLX_STENCIL_SIZE:
+ *value = xmvis->mesa_visual.stencilBits;
+ return 0;
+ case GLX_ACCUM_RED_SIZE:
+ *value = xmvis->mesa_visual.accumRedBits;
+ return 0;
+ case GLX_ACCUM_GREEN_SIZE:
+ *value = xmvis->mesa_visual.accumGreenBits;
+ return 0;
+ case GLX_ACCUM_BLUE_SIZE:
+ *value = xmvis->mesa_visual.accumBlueBits;
+ return 0;
+ case GLX_ACCUM_ALPHA_SIZE:
+ *value = xmvis->mesa_visual.accumAlphaBits;
+ return 0;
+
+ /*
+ * GLX_EXT_visual_info extension
+ */
+ case GLX_X_VISUAL_TYPE_EXT:
+ switch (xmvis->visinfo->CLASS) {
+ case StaticGray: *value = GLX_STATIC_GRAY_EXT; return 0;
+ case GrayScale: *value = GLX_GRAY_SCALE_EXT; return 0;
+ case StaticColor: *value = GLX_STATIC_GRAY_EXT; return 0;
+ case PseudoColor: *value = GLX_PSEUDO_COLOR_EXT; return 0;
+ case TrueColor: *value = GLX_TRUE_COLOR_EXT; return 0;
+ case DirectColor: *value = GLX_DIRECT_COLOR_EXT; return 0;
+ }
+ return 0;
+ case GLX_TRANSPARENT_TYPE_EXT:
+ /* normal planes */
+ *value = GLX_NONE_EXT;
+ return 0;
+ case GLX_TRANSPARENT_INDEX_VALUE_EXT:
+ /* undefined */
+ return 0;
+ case GLX_TRANSPARENT_RED_VALUE_EXT:
+ /* undefined */
+ return 0;
+ case GLX_TRANSPARENT_GREEN_VALUE_EXT:
+ /* undefined */
+ return 0;
+ case GLX_TRANSPARENT_BLUE_VALUE_EXT:
+ /* undefined */
+ return 0;
+ case GLX_TRANSPARENT_ALPHA_VALUE_EXT:
+ /* undefined */
+ return 0;
+
+ /*
+ * GLX_EXT_visual_info extension
+ */
+ case GLX_VISUAL_CAVEAT_EXT:
+ /* test for zero, just in case */
+ if (xmvis->mesa_visual.visualRating > 0)
+ *value = xmvis->mesa_visual.visualRating;
+ else
+ *value = GLX_NONE_EXT;
+ return 0;
+
+ /*
+ * GLX_ARB_multisample
+ */
+ case GLX_SAMPLE_BUFFERS_ARB:
+ *value = 0;
+ return 0;
+ case GLX_SAMPLES_ARB:
+ *value = 0;
+ return 0;
+
+ /*
+ * For FBConfigs:
+ */
+ case GLX_SCREEN_EXT:
+ if (!fbconfig)
+ return GLX_BAD_ATTRIBUTE;
+ *value = xmvis->visinfo->screen;
+ break;
+ case GLX_DRAWABLE_TYPE: /*SGIX too */
+ if (!fbconfig)
+ return GLX_BAD_ATTRIBUTE;
+ *value = GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT;
+ break;
+ case GLX_RENDER_TYPE_SGIX:
+ if (!fbconfig)
+ return GLX_BAD_ATTRIBUTE;
+ if (xmvis->mesa_visual.rgbMode)
+ *value = GLX_RGBA_BIT;
+ else
+ *value = GLX_COLOR_INDEX_BIT;
+ break;
+ case GLX_X_RENDERABLE_SGIX:
+ if (!fbconfig)
+ return GLX_BAD_ATTRIBUTE;
+ *value = True; /* XXX really? */
+ break;
+ case GLX_FBCONFIG_ID_SGIX:
+ if (!fbconfig)
+ return GLX_BAD_ATTRIBUTE;
+ *value = xmvis->visinfo->visualid;
+ break;
+ case GLX_MAX_PBUFFER_WIDTH:
+ if (!fbconfig)
+ return GLX_BAD_ATTRIBUTE;
+ /* XXX or MAX_WIDTH? */
+ *value = DisplayWidth(xmvis->display, xmvis->visinfo->screen);
+ break;
+ case GLX_MAX_PBUFFER_HEIGHT:
+ if (!fbconfig)
+ return GLX_BAD_ATTRIBUTE;
+ *value = DisplayHeight(xmvis->display, xmvis->visinfo->screen);
+ break;
+ case GLX_MAX_PBUFFER_PIXELS:
+ if (!fbconfig)
+ return GLX_BAD_ATTRIBUTE;
+ *value = DisplayWidth(xmvis->display, xmvis->visinfo->screen) *
+ DisplayHeight(xmvis->display, xmvis->visinfo->screen);
+ break;
+ case GLX_VISUAL_ID:
+ if (!fbconfig)
+ return GLX_BAD_ATTRIBUTE;
+ *value = xmvis->visinfo->visualid;
+ break;
+
+#ifdef GLX_EXT_texture_from_pixmap
+ case GLX_BIND_TO_TEXTURE_RGB_EXT:
+ *value = True; /*XXX*/
+ break;
+ case GLX_BIND_TO_TEXTURE_RGBA_EXT:
+ /* XXX review */
+ *value = xmvis->mesa_visual.alphaBits > 0 ? True : False;
+ break;
+ case GLX_BIND_TO_MIPMAP_TEXTURE_EXT:
+ *value = True; /*XXX*/
+ break;
+ case GLX_BIND_TO_TEXTURE_TARGETS_EXT:
+ *value = (GLX_TEXTURE_1D_BIT_EXT |
+ GLX_TEXTURE_2D_BIT_EXT |
+ GLX_TEXTURE_RECTANGLE_BIT_EXT); /*XXX*/
+ break;
+ case GLX_Y_INVERTED_EXT:
+ *value = True; /*XXX*/
+ break;
+#endif
+
+ default:
+ return GLX_BAD_ATTRIBUTE;
+ }
+ return Success;
+}
+
+
+PUBLIC int
+glXGetConfig( Display *dpy, XVisualInfo *visinfo,
+ int attrib, int *value )
+{
+ XMesaVisual xmvis;
+ int k;
+ if (!dpy || !visinfo)
+ return GLX_BAD_ATTRIBUTE;
+
+ xmvis = find_glx_visual( dpy, visinfo );
+ if (!xmvis) {
+ /* this visual wasn't obtained with glXChooseVisual */
+ xmvis = create_glx_visual( dpy, visinfo );
+ if (!xmvis) {
+ /* this visual can't be used for GL rendering */
+ if (attrib==GLX_USE_GL) {
+ *value = (int) False;
+ return 0;
+ }
+ else {
+ return GLX_BAD_VISUAL;
+ }
+ }
+ }
+
+ k = get_config(xmvis, attrib, value, GL_FALSE);
+ return k;
+}
+
+
+PUBLIC void
+glXWaitGL( void )
+{
+ XMesaContext xmesa = XMesaGetCurrentContext();
+ XMesaFlush( xmesa );
+}
+
+
+
+PUBLIC void
+glXWaitX( void )
+{
+ XMesaContext xmesa = XMesaGetCurrentContext();
+ XMesaFlush( xmesa );
+}
+
+
+static const char *
+get_extensions( void )
+{
+ return EXTENSIONS;
+}
+
+
+
+/* GLX 1.1 and later */
+PUBLIC const char *
+glXQueryExtensionsString( Display *dpy, int screen )
+{
+ (void) dpy;
+ (void) screen;
+ return get_extensions();
+}
+
+
+
+/* GLX 1.1 and later */
+PUBLIC const char *
+glXQueryServerString( Display *dpy, int screen, int name )
+{
+ static char version[1000];
+ sprintf(version, "%d.%d %s",
+ SERVER_MAJOR_VERSION, SERVER_MINOR_VERSION, MESA_GLX_VERSION);
+
+ (void) dpy;
+ (void) screen;
+
+ switch (name) {
+ case GLX_EXTENSIONS:
+ return get_extensions();
+ case GLX_VENDOR:
+ return VENDOR;
+ case GLX_VERSION:
+ return version;
+ default:
+ return NULL;
+ }
+}
+
+
+
+/* GLX 1.1 and later */
+PUBLIC const char *
+glXGetClientString( Display *dpy, int name )
+{
+ static char version[1000];
+ sprintf(version, "%d.%d %s", CLIENT_MAJOR_VERSION,
+ CLIENT_MINOR_VERSION, MESA_GLX_VERSION);
+
+ (void) dpy;
+
+ switch (name) {
+ case GLX_EXTENSIONS:
+ return get_extensions();
+ case GLX_VENDOR:
+ return VENDOR;
+ case GLX_VERSION:
+ return version;
+ default:
+ return NULL;
+ }
+}
+
+
+
+/*
+ * GLX 1.3 and later
+ */
+
+
+PUBLIC int
+glXGetFBConfigAttrib( Display *dpy, GLXFBConfig config,
+ int attribute, int *value )
+{
+ XMesaVisual v = (XMesaVisual) config;
+ (void) dpy;
+ (void) config;
+
+ if (!dpy || !config || !value)
+ return -1;
+
+ return get_config(v, attribute, value, GL_TRUE);
+}
+
+
+PUBLIC GLXFBConfig *
+glXGetFBConfigs( Display *dpy, int screen, int *nelements )
+{
+ XVisualInfo *visuals, visTemplate;
+ const long visMask = VisualScreenMask;
+ int i;
+
+ /* Get list of all X visuals */
+ visTemplate.screen = screen;
+ visuals = XGetVisualInfo(dpy, visMask, &visTemplate, nelements);
+ if (*nelements > 0) {
+ XMesaVisual *results;
+ results = (XMesaVisual *) malloc(*nelements * sizeof(XMesaVisual));
+ if (!results) {
+ *nelements = 0;
+ return NULL;
+ }
+ for (i = 0; i < *nelements; i++) {
+ results[i] = create_glx_visual(dpy, visuals + i);
+ if (!results[i]) {
+ *nelements = i;
+ break;
+ }
+ }
+ return (GLXFBConfig *) results;
+ }
+ return NULL;
+}
+
+
+PUBLIC GLXFBConfig *
+glXChooseFBConfig( Display *dpy, int screen,
+ const int *attribList, int *nitems )
+{
+ XMesaVisual xmvis;
+
+ if (!attribList || !attribList[0]) {
+ /* return list of all configs (per GLX_SGIX_fbconfig spec) */
+ return glXGetFBConfigs(dpy, screen, nitems);
+ }
+
+ xmvis = choose_visual(dpy, screen, attribList, GL_TRUE);
+ if (xmvis) {
+ GLXFBConfig *config = (GLXFBConfig *) malloc(sizeof(XMesaVisual));
+ if (!config) {
+ *nitems = 0;
+ return NULL;
+ }
+ *nitems = 1;
+ config[0] = (GLXFBConfig) xmvis;
+ return (GLXFBConfig *) config;
+ }
+ else {
+ *nitems = 0;
+ return NULL;
+ }
+}
+
+
+PUBLIC XVisualInfo *
+glXGetVisualFromFBConfig( Display *dpy, GLXFBConfig config )
+{
+ if (dpy && config) {
+ XMesaVisual xmvis = (XMesaVisual) config;
+#if 0
+ return xmvis->vishandle;
+#else
+ /* create a new vishandle - the cached one may be stale */
+ xmvis->vishandle = (XVisualInfo *) malloc(sizeof(XVisualInfo));
+ if (xmvis->vishandle) {
+ memcpy(xmvis->vishandle, xmvis->visinfo, sizeof(XVisualInfo));
+ }
+ return xmvis->vishandle;
+#endif
+ }
+ else {
+ return NULL;
+ }
+}
+
+
+PUBLIC GLXWindow
+glXCreateWindow( Display *dpy, GLXFBConfig config, Window win,
+ const int *attribList )
+{
+ XMesaVisual xmvis = (XMesaVisual) config;
+ XMesaBuffer xmbuf;
+ if (!xmvis)
+ return 0;
+
+ xmbuf = XMesaCreateWindowBuffer(xmvis, win);
+ if (!xmbuf)
+ return 0;
+
+ (void) dpy;
+ (void) attribList; /* Ignored in GLX 1.3 */
+
+ return win; /* A hack for now */
+}
+
+
+PUBLIC void
+glXDestroyWindow( Display *dpy, GLXWindow window )
+{
+ XMesaBuffer b = XMesaFindBuffer(dpy, (Drawable) window);
+ if (b)
+ XMesaDestroyBuffer(b);
+ /* don't destroy X window */
+}
+
+
+/* XXX untested */
+PUBLIC GLXPixmap
+glXCreatePixmap( Display *dpy, GLXFBConfig config, Pixmap pixmap,
+ const int *attribList )
+{
+ XMesaVisual v = (XMesaVisual) config;
+ XMesaBuffer b;
+ const int *attr;
+ int target = 0, format = 0, mipmap = 0;
+ int value;
+
+ if (!dpy || !config || !pixmap)
+ return 0;
+
+ for (attr = attribList; attr && *attr; attr++) {
+ switch (*attr) {
+ case GLX_TEXTURE_FORMAT_EXT:
+ attr++;
+ switch (*attr) {
+ case GLX_TEXTURE_FORMAT_NONE_EXT:
+ case GLX_TEXTURE_FORMAT_RGB_EXT:
+ case GLX_TEXTURE_FORMAT_RGBA_EXT:
+ format = *attr;
+ break;
+ default:
+ /* error */
+ return 0;
+ }
+ break;
+ case GLX_TEXTURE_TARGET_EXT:
+ attr++;
+ switch (*attr) {
+ case GLX_TEXTURE_1D_EXT:
+ case GLX_TEXTURE_2D_EXT:
+ case GLX_TEXTURE_RECTANGLE_EXT:
+ target = *attr;
+ break;
+ default:
+ /* error */
+ return 0;
+ }
+ break;
+ case GLX_MIPMAP_TEXTURE_EXT:
+ attr++;
+ if (*attr)
+ mipmap = 1;
+ break;
+ default:
+ /* error */
+ return 0;
+ }
+ }
+
+ if (format == GLX_TEXTURE_FORMAT_RGB_EXT) {
+ if (get_config(v, GLX_BIND_TO_TEXTURE_RGB_EXT,
+ &value, GL_TRUE) != Success
+ || !value) {
+ return 0; /* error! */
+ }
+ }
+ else if (format == GLX_TEXTURE_FORMAT_RGBA_EXT) {
+ if (get_config(v, GLX_BIND_TO_TEXTURE_RGBA_EXT,
+ &value, GL_TRUE) != Success
+ || !value) {
+ return 0; /* error! */
+ }
+ }
+ if (mipmap) {
+ if (get_config(v, GLX_BIND_TO_MIPMAP_TEXTURE_EXT,
+ &value, GL_TRUE) != Success
+ || !value) {
+ return 0; /* error! */
+ }
+ }
+ if (target == GLX_TEXTURE_1D_EXT) {
+ if (get_config(v, GLX_BIND_TO_TEXTURE_TARGETS_EXT,
+ &value, GL_TRUE) != Success
+ || (value & GLX_TEXTURE_1D_BIT_EXT) == 0) {
+ return 0; /* error! */
+ }
+ }
+ else if (target == GLX_TEXTURE_2D_EXT) {
+ if (get_config(v, GLX_BIND_TO_TEXTURE_TARGETS_EXT,
+ &value, GL_TRUE) != Success
+ || (value & GLX_TEXTURE_2D_BIT_EXT) == 0) {
+ return 0; /* error! */
+ }
+ }
+ if (target == GLX_TEXTURE_RECTANGLE_EXT) {
+ if (get_config(v, GLX_BIND_TO_TEXTURE_TARGETS_EXT,
+ &value, GL_TRUE) != Success
+ || (value & GLX_TEXTURE_RECTANGLE_BIT_EXT) == 0) {
+ return 0; /* error! */
+ }
+ }
+
+ if (format || target || mipmap) {
+ /* texture from pixmap */
+ b = XMesaCreatePixmapTextureBuffer(v, pixmap, 0, format, target, mipmap);
+ }
+ else {
+ b = XMesaCreatePixmapBuffer( v, pixmap, 0 );
+ }
+ if (!b) {
+ return 0;
+ }
+
+ return pixmap;
+}
+
+
+PUBLIC void
+glXDestroyPixmap( Display *dpy, GLXPixmap pixmap )
+{
+ XMesaBuffer b = XMesaFindBuffer(dpy, (Drawable)pixmap);
+ if (b)
+ XMesaDestroyBuffer(b);
+ /* don't destroy X pixmap */
+}
+
+
+PUBLIC GLXPbuffer
+glXCreatePbuffer( Display *dpy, GLXFBConfig config,
+ const int *attribList )
+{
+ XMesaVisual xmvis = (XMesaVisual) config;
+ XMesaBuffer xmbuf;
+ const int *attrib;
+ int width = 0, height = 0;
+ GLboolean useLargest = GL_FALSE, preserveContents = GL_FALSE;
+
+ (void) dpy;
+
+ for (attrib = attribList; *attrib; attrib++) {
+ switch (*attrib) {
+ case GLX_PBUFFER_WIDTH:
+ attrib++;
+ width = *attrib;
+ break;
+ case GLX_PBUFFER_HEIGHT:
+ attrib++;
+ height = *attrib;
+ break;
+ case GLX_PRESERVED_CONTENTS:
+ attrib++;
+ preserveContents = *attrib;
+ break;
+ case GLX_LARGEST_PBUFFER:
+ attrib++;
+ useLargest = *attrib;
+ break;
+ default:
+ return 0;
+ }
+ }
+
+ if (width == 0 || height == 0)
+ return 0;
+
+ if (width > MAX_WIDTH || height > MAX_HEIGHT) {
+ /* If allocation would have failed and GLX_LARGEST_PBUFFER is set,
+ * allocate the largest possible buffer.
+ */
+ if (useLargest) {
+ width = MAX_WIDTH;
+ height = MAX_HEIGHT;
+ }
+ }
+
+ xmbuf = XMesaCreatePBuffer( xmvis, 0, width, height);
+ /* A GLXPbuffer handle must be an X Drawable because that's what
+ * glXMakeCurrent takes.
+ */
+ if (xmbuf) {
+ xmbuf->largestPbuffer = useLargest;
+ xmbuf->preservedContents = preserveContents;
+ return (GLXPbuffer) xmbuf->drawable;
+ }
+ else {
+ return 0;
+ }
+}
+
+
+PUBLIC void
+glXDestroyPbuffer( Display *dpy, GLXPbuffer pbuf )
+{
+ XMesaBuffer b = XMesaFindBuffer(dpy, pbuf);
+ if (b) {
+ XMesaDestroyBuffer(b);
+ }
+}
+
+
+PUBLIC void
+glXQueryDrawable( Display *dpy, GLXDrawable draw, int attribute,
+ unsigned int *value )
+{
+ GLuint width, height;
+ XMesaBuffer xmbuf = XMesaFindBuffer(dpy, draw);
+ if (!xmbuf)
+ return;
+
+ /* make sure buffer's dimensions are up to date */
+ xmesa_get_window_size(dpy, xmbuf, &width, &height);
+
+ switch (attribute) {
+ case GLX_WIDTH:
+ *value = width;
+ break;
+ case GLX_HEIGHT:
+ *value = height;
+ break;
+ case GLX_PRESERVED_CONTENTS:
+ *value = xmbuf->preservedContents;
+ break;
+ case GLX_LARGEST_PBUFFER:
+ *value = xmbuf->largestPbuffer;
+ break;
+ case GLX_FBCONFIG_ID:
+ *value = xmbuf->xm_visual->visinfo->visualid;
+ return;
+#ifdef GLX_EXT_texture_from_pixmap
+ case GLX_TEXTURE_FORMAT_EXT:
+ *value = xmbuf->TextureFormat;
+ break;
+ case GLX_TEXTURE_TARGET_EXT:
+ *value = xmbuf->TextureTarget;
+ break;
+ case GLX_MIPMAP_TEXTURE_EXT:
+ *value = xmbuf->TextureMipmap;
+ break;
+#endif
+
+ default:
+ return; /* raise BadValue error */
+ }
+}
+
+
+PUBLIC GLXContext
+glXCreateNewContext( Display *dpy, GLXFBConfig config,
+ int renderType, GLXContext shareList, Bool direct )
+{
+ GLXContext glxCtx;
+ GLXContext shareCtx = shareList;
+ XMesaVisual xmvis = (XMesaVisual) config;
+
+ if (!dpy || !config ||
+ (renderType != GLX_RGBA_TYPE && renderType != GLX_COLOR_INDEX_TYPE))
+ return 0;
+
+ glxCtx = CALLOC_STRUCT(__GLXcontextRec);
+ if (!glxCtx)
+ return 0;
+
+ /* deallocate unused windows/buffers */
+ XMesaGarbageCollect();
+
+ glxCtx->xmesaContext = XMesaCreateContext(xmvis,
+ shareCtx ? shareCtx->xmesaContext : NULL);
+ if (!glxCtx->xmesaContext) {
+ free(glxCtx);
+ return NULL;
+ }
+
+ glxCtx->isDirect = DEFAULT_DIRECT;
+ glxCtx->currentDpy = dpy;
+ glxCtx->xid = (XID) glxCtx; /* self pointer */
+
+ return glxCtx;
+}
+
+
+PUBLIC int
+glXQueryContext( Display *dpy, GLXContext ctx, int attribute, int *value )
+{
+ GLXContext glxCtx = ctx;
+ XMesaContext xmctx = glxCtx->xmesaContext;
+
+ (void) dpy;
+ (void) ctx;
+
+ switch (attribute) {
+ case GLX_FBCONFIG_ID:
+ *value = xmctx->xm_visual->visinfo->visualid;
+ break;
+ case GLX_RENDER_TYPE:
+ if (xmctx->xm_visual->mesa_visual.rgbMode)
+ *value = GLX_RGBA_TYPE;
+ else
+ *value = GLX_COLOR_INDEX_TYPE;
+ break;
+ case GLX_SCREEN:
+ *value = 0;
+ return Success;
+ default:
+ return GLX_BAD_ATTRIBUTE;
+ }
+ return 0;
+}
+
+
+PUBLIC void
+glXSelectEvent( Display *dpy, GLXDrawable drawable, unsigned long mask )
+{
+ XMesaBuffer xmbuf = XMesaFindBuffer(dpy, drawable);
+ if (xmbuf)
+ xmbuf->selectedEvents = mask;
+}
+
+
+PUBLIC void
+glXGetSelectedEvent( Display *dpy, GLXDrawable drawable,
+ unsigned long *mask )
+{
+ XMesaBuffer xmbuf = XMesaFindBuffer(dpy, drawable);
+ if (xmbuf)
+ *mask = xmbuf->selectedEvents;
+ else
+ *mask = 0;
+}
+
+
+
+/*** GLX_SGI_swap_control ***/
+
+PUBLIC int
+glXSwapIntervalSGI(int interval)
+{
+ (void) interval;
+ return 0;
+}
+
+
+
+/*** GLX_SGI_video_sync ***/
+
+static unsigned int FrameCounter = 0;
+
+PUBLIC int
+glXGetVideoSyncSGI(unsigned int *count)
+{
+ /* this is a bogus implementation */
+ *count = FrameCounter++;
+ return 0;
+}
+
+PUBLIC int
+glXWaitVideoSyncSGI(int divisor, int remainder, unsigned int *count)
+{
+ if (divisor <= 0 || remainder < 0)
+ return GLX_BAD_VALUE;
+ /* this is a bogus implementation */
+ FrameCounter++;
+ while (FrameCounter % divisor != remainder)
+ FrameCounter++;
+ *count = FrameCounter;
+ return 0;
+}
+
+
+
+/*** GLX_SGI_make_current_read ***/
+
+PUBLIC Bool
+glXMakeCurrentReadSGI(Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx)
+{
+ return glXMakeContextCurrent( dpy, draw, read, ctx );
+}
+
+/* not used
+static GLXDrawable
+glXGetCurrentReadDrawableSGI(void)
+{
+ return 0;
+}
+*/
+
+
+/*** GLX_SGIX_video_source ***/
+#if defined(_VL_H)
+
+PUBLIC GLXVideoSourceSGIX
+glXCreateGLXVideoSourceSGIX(Display *dpy, int screen, VLServer server, VLPath path, int nodeClass, VLNode drainNode)
+{
+ (void) dpy;
+ (void) screen;
+ (void) server;
+ (void) path;
+ (void) nodeClass;
+ (void) drainNode;
+ return 0;
+}
+
+PUBLIC void
+glXDestroyGLXVideoSourceSGIX(Display *dpy, GLXVideoSourceSGIX src)
+{
+ (void) dpy;
+ (void) src;
+}
+
+#endif
+
+
+/*** GLX_EXT_import_context ***/
+
+PUBLIC void
+glXFreeContextEXT(Display *dpy, GLXContext context)
+{
+ (void) dpy;
+ (void) context;
+}
+
+PUBLIC GLXContextID
+glXGetContextIDEXT(const GLXContext context)
+{
+ (void) context;
+ return 0;
+}
+
+PUBLIC GLXContext
+glXImportContextEXT(Display *dpy, GLXContextID contextID)
+{
+ (void) dpy;
+ (void) contextID;
+ return 0;
+}
+
+PUBLIC int
+glXQueryContextInfoEXT(Display *dpy, GLXContext context, int attribute, int *value)
+{
+ (void) dpy;
+ (void) context;
+ (void) attribute;
+ (void) value;
+ return 0;
+}
+
+
+
+/*** GLX_SGIX_fbconfig ***/
+
+PUBLIC int
+glXGetFBConfigAttribSGIX(Display *dpy, GLXFBConfigSGIX config, int attribute, int *value)
+{
+ return glXGetFBConfigAttrib(dpy, config, attribute, value);
+}
+
+PUBLIC GLXFBConfigSGIX *
+glXChooseFBConfigSGIX(Display *dpy, int screen, int *attrib_list, int *nelements)
+{
+ return (GLXFBConfig *) glXChooseFBConfig(dpy, screen, attrib_list, nelements);
+}
+
+
+PUBLIC GLXPixmap
+glXCreateGLXPixmapWithConfigSGIX(Display *dpy, GLXFBConfigSGIX config, Pixmap pixmap)
+{
+ XMesaVisual xmvis = (XMesaVisual) config;
+ XMesaBuffer xmbuf = XMesaCreatePixmapBuffer(xmvis, pixmap, 0);
+ return xmbuf->drawable; /* need to return an X ID */
+}
+
+
+PUBLIC GLXContext
+glXCreateContextWithConfigSGIX(Display *dpy, GLXFBConfigSGIX config, int render_type, GLXContext share_list, Bool direct)
+{
+ XMesaVisual xmvis = (XMesaVisual) config;
+ GLXContext glxCtx;
+ GLXContext shareCtx = share_list;
+
+ glxCtx = CALLOC_STRUCT(__GLXcontextRec);
+ if (!glxCtx)
+ return 0;
+
+ /* deallocate unused windows/buffers */
+ XMesaGarbageCollect();
+
+ glxCtx->xmesaContext = XMesaCreateContext(xmvis,
+ shareCtx ? shareCtx->xmesaContext : NULL);
+ if (!glxCtx->xmesaContext) {
+ free(glxCtx);
+ return NULL;
+ }
+
+ glxCtx->isDirect = DEFAULT_DIRECT;
+ glxCtx->currentDpy = dpy;
+ glxCtx->xid = (XID) glxCtx; /* self pointer */
+
+ return glxCtx;
+}
+
+
+PUBLIC XVisualInfo *
+glXGetVisualFromFBConfigSGIX(Display *dpy, GLXFBConfigSGIX config)
+{
+ return glXGetVisualFromFBConfig(dpy, config);
+}
+
+
+PUBLIC GLXFBConfigSGIX
+glXGetFBConfigFromVisualSGIX(Display *dpy, XVisualInfo *vis)
+{
+ XMesaVisual xmvis = find_glx_visual(dpy, vis);
+ if (!xmvis) {
+ /* This visual wasn't found with glXChooseVisual() */
+ xmvis = create_glx_visual(dpy, vis);
+ }
+
+ return (GLXFBConfigSGIX) xmvis;
+}
+
+
+
+/*** GLX_SGIX_pbuffer ***/
+
+PUBLIC GLXPbufferSGIX
+glXCreateGLXPbufferSGIX(Display *dpy, GLXFBConfigSGIX config,
+ unsigned int width, unsigned int height,
+ int *attribList)
+{
+ XMesaVisual xmvis = (XMesaVisual) config;
+ XMesaBuffer xmbuf;
+ const int *attrib;
+ GLboolean useLargest = GL_FALSE, preserveContents = GL_FALSE;
+
+ (void) dpy;
+
+ for (attrib = attribList; attrib && *attrib; attrib++) {
+ switch (*attrib) {
+ case GLX_PRESERVED_CONTENTS_SGIX:
+ attrib++;
+ preserveContents = *attrib; /* ignored */
+ break;
+ case GLX_LARGEST_PBUFFER_SGIX:
+ attrib++;
+ useLargest = *attrib; /* ignored */
+ break;
+ default:
+ return 0;
+ }
+ }
+
+ /* not used at this time */
+ (void) useLargest;
+ (void) preserveContents;
+
+ xmbuf = XMesaCreatePBuffer( xmvis, 0, width, height);
+ /* A GLXPbuffer handle must be an X Drawable because that's what
+ * glXMakeCurrent takes.
+ */
+ return (GLXPbuffer) xmbuf->drawable;
+}
+
+
+PUBLIC void
+glXDestroyGLXPbufferSGIX(Display *dpy, GLXPbufferSGIX pbuf)
+{
+ XMesaBuffer xmbuf = XMesaFindBuffer(dpy, pbuf);
+ if (xmbuf) {
+ XMesaDestroyBuffer(xmbuf);
+ }
+}
+
+
+PUBLIC int
+glXQueryGLXPbufferSGIX(Display *dpy, GLXPbufferSGIX pbuf, int attribute, unsigned int *value)
+{
+ const XMesaBuffer xmbuf = XMesaFindBuffer(dpy, pbuf);
+
+ if (!xmbuf) {
+ /* Generate GLXBadPbufferSGIX for bad pbuffer */
+ return 0;
+ }
+
+ switch (attribute) {
+ case GLX_PRESERVED_CONTENTS_SGIX:
+ *value = True;
+ break;
+ case GLX_LARGEST_PBUFFER_SGIX:
+ *value = xmesa_buffer_width(xmbuf) * xmesa_buffer_height(xmbuf);
+ break;
+ case GLX_WIDTH_SGIX:
+ *value = xmesa_buffer_width(xmbuf);
+ break;
+ case GLX_HEIGHT_SGIX:
+ *value = xmesa_buffer_height(xmbuf);
+ break;
+ case GLX_EVENT_MASK_SGIX:
+ *value = 0; /* XXX might be wrong */
+ break;
+ default:
+ *value = 0;
+ }
+ return 0;
+}
+
+
+PUBLIC void
+glXSelectEventSGIX(Display *dpy, GLXDrawable drawable, unsigned long mask)
+{
+ XMesaBuffer xmbuf = XMesaFindBuffer(dpy, drawable);
+ if (xmbuf) {
+ /* Note: we'll never generate clobber events */
+ xmbuf->selectedEvents = mask;
+ }
+}
+
+
+PUBLIC void
+glXGetSelectedEventSGIX(Display *dpy, GLXDrawable drawable, unsigned long *mask)
+{
+ XMesaBuffer xmbuf = XMesaFindBuffer(dpy, drawable);
+ if (xmbuf) {
+ *mask = xmbuf->selectedEvents;
+ }
+ else {
+ *mask = 0;
+ }
+}
+
+
+
+/*** GLX_SGI_cushion ***/
+
+PUBLIC void
+glXCushionSGI(Display *dpy, Window win, float cushion)
+{
+ (void) dpy;
+ (void) win;
+ (void) cushion;
+}
+
+
+
+/*** GLX_SGIX_video_resize ***/
+
+PUBLIC int
+glXBindChannelToWindowSGIX(Display *dpy, int screen, int channel , Window window)
+{
+ (void) dpy;
+ (void) screen;
+ (void) channel;
+ (void) window;
+ return 0;
+}
+
+PUBLIC int
+glXChannelRectSGIX(Display *dpy, int screen, int channel, int x, int y, int w, int h)
+{
+ (void) dpy;
+ (void) screen;
+ (void) channel;
+ (void) x;
+ (void) y;
+ (void) w;
+ (void) h;
+ return 0;
+}
+
+PUBLIC int
+glXQueryChannelRectSGIX(Display *dpy, int screen, int channel, int *x, int *y, int *w, int *h)
+{
+ (void) dpy;
+ (void) screen;
+ (void) channel;
+ (void) x;
+ (void) y;
+ (void) w;
+ (void) h;
+ return 0;
+}
+
+PUBLIC int
+glXQueryChannelDeltasSGIX(Display *dpy, int screen, int channel, int *dx, int *dy, int *dw, int *dh)
+{
+ (void) dpy;
+ (void) screen;
+ (void) channel;
+ (void) dx;
+ (void) dy;
+ (void) dw;
+ (void) dh;
+ return 0;
+}
+
+PUBLIC int
+glXChannelRectSyncSGIX(Display *dpy, int screen, int channel, GLenum synctype)
+{
+ (void) dpy;
+ (void) screen;
+ (void) channel;
+ (void) synctype;
+ return 0;
+}
+
+
+
+/*** GLX_SGIX_dmbuffer **/
+
+#if defined(_DM_BUFFER_H_)
+PUBLIC Bool
+glXAssociateDMPbufferSGIX(Display *dpy, GLXPbufferSGIX pbuffer, DMparams *params, DMbuffer dmbuffer)
+{
+ (void) dpy;
+ (void) pbuffer;
+ (void) params;
+ (void) dmbuffer;
+ return False;
+}
+#endif
+
+
+/*** GLX_SGIX_swap_group ***/
+
+PUBLIC void
+glXJoinSwapGroupSGIX(Display *dpy, GLXDrawable drawable, GLXDrawable member)
+{
+ (void) dpy;
+ (void) drawable;
+ (void) member;
+}
+
+
+
+/*** GLX_SGIX_swap_barrier ***/
+
+PUBLIC void
+glXBindSwapBarrierSGIX(Display *dpy, GLXDrawable drawable, int barrier)
+{
+ (void) dpy;
+ (void) drawable;
+ (void) barrier;
+}
+
+PUBLIC Bool
+glXQueryMaxSwapBarriersSGIX(Display *dpy, int screen, int *max)
+{
+ (void) dpy;
+ (void) screen;
+ (void) max;
+ return False;
+}
+
+
+
+/*** GLX_SUN_get_transparent_index ***/
+
+PUBLIC Status
+glXGetTransparentIndexSUN(Display *dpy, Window overlay, Window underlay, long *pTransparent)
+{
+ (void) dpy;
+ (void) overlay;
+ (void) underlay;
+ (void) pTransparent;
+ return 0;
+}
+
+
+
+/*** GLX_MESA_release_buffers ***/
+
+/*
+ * Release the depth, stencil, accum buffers attached to a GLXDrawable
+ * (a window or pixmap) prior to destroying the GLXDrawable.
+ */
+PUBLIC Bool
+glXReleaseBuffersMESA( Display *dpy, GLXDrawable d )
+{
+ XMesaBuffer b = XMesaFindBuffer(dpy, d);
+ if (b) {
+ XMesaDestroyBuffer(b);
+ return True;
+ }
+ return False;
+}
+
+/*** GLX_EXT_texture_from_pixmap ***/
+
+PUBLIC void
+glXBindTexImageEXT(Display *dpy, GLXDrawable drawable, int buffer,
+ const int *attrib_list)
+{
+ XMesaBuffer b = XMesaFindBuffer(dpy, drawable);
+ if (b)
+ XMesaBindTexImage(dpy, b, buffer, attrib_list);
+}
+
+PUBLIC void
+glXReleaseTexImageEXT(Display *dpy, GLXDrawable drawable, int buffer)
+{
+ XMesaBuffer b = XMesaFindBuffer(dpy, drawable);
+ if (b)
+ XMesaReleaseTexImage(dpy, b, buffer);
+}
diff --git a/src/gallium/state_trackers/glx/xlib/glx_getproc.c b/src/gallium/state_trackers/glx/xlib/glx_getproc.c
new file mode 100644
index 0000000000..26fcae78ec
--- /dev/null
+++ b/src/gallium/state_trackers/glx/xlib/glx_getproc.c
@@ -0,0 +1,215 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.6
+ *
+ * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
+ * Copyright (C) 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL 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.
+ */
+
+
+/**
+ * glXGetProcAddress()
+ */
+
+
+#define GLX_GLXEXT_PROTOTYPES
+
+#include <string.h>
+#include "GL/glx.h"
+#include "glapi/glapi.h"
+
+
+struct name_address_pair {
+ const char *Name;
+ __GLXextFuncPtr Address;
+};
+
+
+static struct name_address_pair GLX_functions[] = {
+ /*** GLX_VERSION_1_0 ***/
+ { "glXChooseVisual", (__GLXextFuncPtr) glXChooseVisual },
+ { "glXCopyContext", (__GLXextFuncPtr) glXCopyContext },
+ { "glXCreateContext", (__GLXextFuncPtr) glXCreateContext },
+ { "glXCreateGLXPixmap", (__GLXextFuncPtr) glXCreateGLXPixmap },
+ { "glXDestroyContext", (__GLXextFuncPtr) glXDestroyContext },
+ { "glXDestroyGLXPixmap", (__GLXextFuncPtr) glXDestroyGLXPixmap },
+ { "glXGetConfig", (__GLXextFuncPtr) glXGetConfig },
+ { "glXGetCurrentContext", (__GLXextFuncPtr) glXGetCurrentContext },
+ { "glXGetCurrentDrawable", (__GLXextFuncPtr) glXGetCurrentDrawable },
+ { "glXIsDirect", (__GLXextFuncPtr) glXIsDirect },
+ { "glXMakeCurrent", (__GLXextFuncPtr) glXMakeCurrent },
+ { "glXQueryExtension", (__GLXextFuncPtr) glXQueryExtension },
+ { "glXQueryVersion", (__GLXextFuncPtr) glXQueryVersion },
+ { "glXSwapBuffers", (__GLXextFuncPtr) glXSwapBuffers },
+ { "glXUseXFont", (__GLXextFuncPtr) glXUseXFont },
+ { "glXWaitGL", (__GLXextFuncPtr) glXWaitGL },
+ { "glXWaitX", (__GLXextFuncPtr) glXWaitX },
+
+ /*** GLX_VERSION_1_1 ***/
+ { "glXGetClientString", (__GLXextFuncPtr) glXGetClientString },
+ { "glXQueryExtensionsString", (__GLXextFuncPtr) glXQueryExtensionsString },
+ { "glXQueryServerString", (__GLXextFuncPtr) glXQueryServerString },
+
+ /*** GLX_VERSION_1_2 ***/
+ { "glXGetCurrentDisplay", (__GLXextFuncPtr) glXGetCurrentDisplay },
+
+ /*** GLX_VERSION_1_3 ***/
+ { "glXChooseFBConfig", (__GLXextFuncPtr) glXChooseFBConfig },
+ { "glXCreateNewContext", (__GLXextFuncPtr) glXCreateNewContext },
+ { "glXCreatePbuffer", (__GLXextFuncPtr) glXCreatePbuffer },
+ { "glXCreatePixmap", (__GLXextFuncPtr) glXCreatePixmap },
+ { "glXCreateWindow", (__GLXextFuncPtr) glXCreateWindow },
+ { "glXDestroyPbuffer", (__GLXextFuncPtr) glXDestroyPbuffer },
+ { "glXDestroyPixmap", (__GLXextFuncPtr) glXDestroyPixmap },
+ { "glXDestroyWindow", (__GLXextFuncPtr) glXDestroyWindow },
+ { "glXGetCurrentReadDrawable", (__GLXextFuncPtr) glXGetCurrentReadDrawable },
+ { "glXGetFBConfigAttrib", (__GLXextFuncPtr) glXGetFBConfigAttrib },
+ { "glXGetFBConfigs", (__GLXextFuncPtr) glXGetFBConfigs },
+ { "glXGetSelectedEvent", (__GLXextFuncPtr) glXGetSelectedEvent },
+ { "glXGetVisualFromFBConfig", (__GLXextFuncPtr) glXGetVisualFromFBConfig },
+ { "glXMakeContextCurrent", (__GLXextFuncPtr) glXMakeContextCurrent },
+ { "glXQueryContext", (__GLXextFuncPtr) glXQueryContext },
+ { "glXQueryDrawable", (__GLXextFuncPtr) glXQueryDrawable },
+ { "glXSelectEvent", (__GLXextFuncPtr) glXSelectEvent },
+
+ /*** GLX_VERSION_1_4 ***/
+ { "glXGetProcAddress", (__GLXextFuncPtr) glXGetProcAddress },
+
+ /*** GLX_SGI_swap_control ***/
+ { "glXSwapIntervalSGI", (__GLXextFuncPtr) glXSwapIntervalSGI },
+
+ /*** GLX_SGI_video_sync ***/
+ { "glXGetVideoSyncSGI", (__GLXextFuncPtr) glXGetVideoSyncSGI },
+ { "glXWaitVideoSyncSGI", (__GLXextFuncPtr) glXWaitVideoSyncSGI },
+
+ /*** GLX_SGI_make_current_read ***/
+ { "glXMakeCurrentReadSGI", (__GLXextFuncPtr) glXMakeCurrentReadSGI },
+ { "glXGetCurrentReadDrawableSGI", (__GLXextFuncPtr) glXGetCurrentReadDrawableSGI },
+
+ /*** GLX_SGIX_video_source ***/
+#if defined(_VL_H)
+ { "glXCreateGLXVideoSourceSGIX", (__GLXextFuncPtr) glXCreateGLXVideoSourceSGIX },
+ { "glXDestroyGLXVideoSourceSGIX", (__GLXextFuncPtr) glXDestroyGLXVideoSourceSGIX },
+#endif
+
+ /*** GLX_EXT_import_context ***/
+ { "glXFreeContextEXT", (__GLXextFuncPtr) glXFreeContextEXT },
+ { "glXGetContextIDEXT", (__GLXextFuncPtr) glXGetContextIDEXT },
+ { "glXGetCurrentDisplayEXT", (__GLXextFuncPtr) glXGetCurrentDisplayEXT },
+ { "glXImportContextEXT", (__GLXextFuncPtr) glXImportContextEXT },
+ { "glXQueryContextInfoEXT", (__GLXextFuncPtr) glXQueryContextInfoEXT },
+
+ /*** GLX_SGIX_fbconfig ***/
+ { "glXGetFBConfigAttribSGIX", (__GLXextFuncPtr) glXGetFBConfigAttribSGIX },
+ { "glXChooseFBConfigSGIX", (__GLXextFuncPtr) glXChooseFBConfigSGIX },
+ { "glXCreateGLXPixmapWithConfigSGIX", (__GLXextFuncPtr) glXCreateGLXPixmapWithConfigSGIX },
+ { "glXCreateContextWithConfigSGIX", (__GLXextFuncPtr) glXCreateContextWithConfigSGIX },
+ { "glXGetVisualFromFBConfigSGIX", (__GLXextFuncPtr) glXGetVisualFromFBConfigSGIX },
+ { "glXGetFBConfigFromVisualSGIX", (__GLXextFuncPtr) glXGetFBConfigFromVisualSGIX },
+
+ /*** GLX_SGIX_pbuffer ***/
+ { "glXCreateGLXPbufferSGIX", (__GLXextFuncPtr) glXCreateGLXPbufferSGIX },
+ { "glXDestroyGLXPbufferSGIX", (__GLXextFuncPtr) glXDestroyGLXPbufferSGIX },
+ { "glXQueryGLXPbufferSGIX", (__GLXextFuncPtr) glXQueryGLXPbufferSGIX },
+ { "glXSelectEventSGIX", (__GLXextFuncPtr) glXSelectEventSGIX },
+ { "glXGetSelectedEventSGIX", (__GLXextFuncPtr) glXGetSelectedEventSGIX },
+
+ /*** GLX_SGI_cushion ***/
+ { "glXCushionSGI", (__GLXextFuncPtr) glXCushionSGI },
+
+ /*** GLX_SGIX_video_resize ***/
+ { "glXBindChannelToWindowSGIX", (__GLXextFuncPtr) glXBindChannelToWindowSGIX },
+ { "glXChannelRectSGIX", (__GLXextFuncPtr) glXChannelRectSGIX },
+ { "glXQueryChannelRectSGIX", (__GLXextFuncPtr) glXQueryChannelRectSGIX },
+ { "glXQueryChannelDeltasSGIX", (__GLXextFuncPtr) glXQueryChannelDeltasSGIX },
+ { "glXChannelRectSyncSGIX", (__GLXextFuncPtr) glXChannelRectSyncSGIX },
+
+ /*** GLX_SGIX_dmbuffer **/
+#if defined(_DM_BUFFER_H_)
+ { "glXAssociateDMPbufferSGIX", (__GLXextFuncPtr) glXAssociateDMPbufferSGIX },
+#endif
+
+ /*** GLX_SGIX_swap_group ***/
+ { "glXJoinSwapGroupSGIX", (__GLXextFuncPtr) glXJoinSwapGroupSGIX },
+
+ /*** GLX_SGIX_swap_barrier ***/
+ { "glXBindSwapBarrierSGIX", (__GLXextFuncPtr) glXBindSwapBarrierSGIX },
+ { "glXQueryMaxSwapBarriersSGIX", (__GLXextFuncPtr) glXQueryMaxSwapBarriersSGIX },
+
+ /*** GLX_SUN_get_transparent_index ***/
+ { "glXGetTransparentIndexSUN", (__GLXextFuncPtr) glXGetTransparentIndexSUN },
+
+ /*** GLX_MESA_copy_sub_buffer ***/
+ { "glXCopySubBufferMESA", (__GLXextFuncPtr) glXCopySubBufferMESA },
+
+ /*** GLX_MESA_pixmap_colormap ***/
+ { "glXCreateGLXPixmapMESA", (__GLXextFuncPtr) glXCreateGLXPixmapMESA },
+
+ /*** GLX_MESA_release_buffers ***/
+ { "glXReleaseBuffersMESA", (__GLXextFuncPtr) glXReleaseBuffersMESA },
+
+ /*** GLX_ARB_get_proc_address ***/
+ { "glXGetProcAddressARB", (__GLXextFuncPtr) glXGetProcAddressARB },
+
+ /*** GLX_EXT_texture_from_pixmap ***/
+ { "glXBindTexImageEXT", (__GLXextFuncPtr) glXBindTexImageEXT },
+ { "glXReleaseTexImageEXT", (__GLXextFuncPtr) glXReleaseTexImageEXT },
+
+ { NULL, NULL } /* end of list */
+};
+
+
+
+/**
+ * Return address of named glX function, or NULL if not found.
+ */
+static __GLXextFuncPtr
+_glxapi_get_proc_address(const char *funcName)
+{
+ GLuint i;
+ for (i = 0; GLX_functions[i].Name; i++) {
+ if (strcmp(GLX_functions[i].Name, funcName) == 0)
+ return GLX_functions[i].Address;
+ }
+ return NULL;
+}
+
+
+PUBLIC __GLXextFuncPtr
+glXGetProcAddressARB(const GLubyte *procName)
+{
+ __GLXextFuncPtr f;
+
+ f = _glxapi_get_proc_address((const char *) procName);
+ if (f) {
+ return f;
+ }
+
+ f = (__GLXextFuncPtr) _glapi_get_proc_address((const char *) procName);
+ return f;
+}
+
+
+/* GLX 1.4 */
+PUBLIC
+void (*glXGetProcAddress(const GLubyte *procName))()
+{
+ return glXGetProcAddressARB(procName);
+}
diff --git a/src/gallium/state_trackers/glx/xlib/glx_usefont.c b/src/gallium/state_trackers/glx/xlib/glx_usefont.c
new file mode 100644
index 0000000000..8903b0e6cb
--- /dev/null
+++ b/src/gallium/state_trackers/glx/xlib/glx_usefont.c
@@ -0,0 +1,375 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.6
+ *
+ * Copyright (C) 1995 Thorsten.Ohl @ Physik.TH-Darmstadt.de
+ * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
+ * Copyright (C) 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL 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.
+ */
+
+
+/**
+ * Fake implementation of glXUseXFont().
+ */
+
+
+#include "main/context.h"
+#include "main/imports.h"
+#include <GL/glx.h>
+
+
+/* Some debugging info. */
+
+#ifdef DEBUG
+#undef _R
+#undef _G
+#undef _B
+#include <ctype.h>
+
+int debug_xfonts = 0;
+
+static void
+dump_char_struct(XCharStruct * ch, char *prefix)
+{
+ printf("%slbearing = %d, rbearing = %d, width = %d\n",
+ prefix, ch->lbearing, ch->rbearing, ch->width);
+ printf("%sascent = %d, descent = %d, attributes = %u\n",
+ prefix, ch->ascent, ch->descent, (unsigned int) ch->attributes);
+}
+
+static void
+dump_font_struct(XFontStruct * font)
+{
+ printf("ascent = %d, descent = %d\n", font->ascent, font->descent);
+ printf("char_or_byte2 = (%u,%u)\n",
+ font->min_char_or_byte2, font->max_char_or_byte2);
+ printf("byte1 = (%u,%u)\n", font->min_byte1, font->max_byte1);
+ printf("all_chars_exist = %s\n", font->all_chars_exist ? "True" : "False");
+ printf("default_char = %c (\\%03o)\n",
+ (char) (isprint(font->default_char) ? font->default_char : ' '),
+ font->default_char);
+ dump_char_struct(&font->min_bounds, "min> ");
+ dump_char_struct(&font->max_bounds, "max> ");
+#if 0
+ for (c = font->min_char_or_byte2; c <= font->max_char_or_byte2; c++) {
+ char prefix[8];
+ sprintf(prefix, "%d> ", c);
+ dump_char_struct(&font->per_char[c], prefix);
+ }
+#endif
+}
+
+static void
+dump_bitmap(unsigned int width, unsigned int height, GLubyte * bitmap)
+{
+ unsigned int x, y;
+
+ printf(" ");
+ for (x = 0; x < 8 * width; x++)
+ printf("%o", 7 - (x % 8));
+ putchar('\n');
+ for (y = 0; y < height; y++) {
+ printf("%3o:", y);
+ for (x = 0; x < 8 * width; x++)
+ putchar((bitmap[width * (height - y - 1) + x / 8] & (1 << (7 - (x %
+ 8))))
+ ? '*' : '.');
+ printf(" ");
+ for (x = 0; x < width; x++)
+ printf("0x%02x, ", bitmap[width * (height - y - 1) + x]);
+ putchar('\n');
+ }
+}
+#endif /* DEBUG */
+
+
+/* Implementation. */
+
+/* Fill a BITMAP with a character C from thew current font
+ in the graphics context GC. WIDTH is the width in bytes
+ and HEIGHT is the height in bits.
+
+ Note that the generated bitmaps must be used with
+
+ glPixelStorei (GL_UNPACK_SWAP_BYTES, GL_FALSE);
+ glPixelStorei (GL_UNPACK_LSB_FIRST, GL_FALSE);
+ glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
+ glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
+ glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
+ glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
+
+ Possible optimizations:
+
+ * use only one reusable pixmap with the maximum dimensions.
+ * draw the entire font into a single pixmap (careful with
+ proportional fonts!).
+*/
+
+
+/*
+ * Generate OpenGL-compatible bitmap.
+ */
+static void
+fill_bitmap(Display * dpy, Window win, GC gc,
+ unsigned int width, unsigned int height,
+ int x0, int y0, unsigned int c, GLubyte * bitmap)
+{
+ XImage *image;
+ unsigned int x, y;
+ Pixmap pixmap;
+ XChar2b char2b;
+
+ pixmap = XCreatePixmap(dpy, win, 8 * width, height, 1);
+ XSetForeground(dpy, gc, 0);
+ XFillRectangle(dpy, pixmap, gc, 0, 0, 8 * width, height);
+ XSetForeground(dpy, gc, 1);
+
+ char2b.byte1 = (c >> 8) & 0xff;
+ char2b.byte2 = (c & 0xff);
+
+ XDrawString16(dpy, pixmap, gc, x0, y0, &char2b, 1);
+
+ image = XGetImage(dpy, pixmap, 0, 0, 8 * width, height, 1, XYPixmap);
+ if (image) {
+ /* Fill the bitmap (X11 and OpenGL are upside down wrt each other). */
+ for (y = 0; y < height; y++)
+ for (x = 0; x < 8 * width; x++)
+ if (XGetPixel(image, x, y))
+ bitmap[width * (height - y - 1) + x / 8] |=
+ (1 << (7 - (x % 8)));
+ XDestroyImage(image);
+ }
+
+ XFreePixmap(dpy, pixmap);
+}
+
+/*
+ * determine if a given glyph is valid and return the
+ * corresponding XCharStruct.
+ */
+static XCharStruct *
+isvalid(XFontStruct * fs, unsigned int which)
+{
+ unsigned int rows, pages;
+ unsigned int byte1 = 0, byte2 = 0;
+ int i, valid = 1;
+
+ rows = fs->max_byte1 - fs->min_byte1 + 1;
+ pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1;
+
+ if (rows == 1) {
+ /* "linear" fonts */
+ if ((fs->min_char_or_byte2 > which) || (fs->max_char_or_byte2 < which))
+ valid = 0;
+ }
+ else {
+ /* "matrix" fonts */
+ byte2 = which & 0xff;
+ byte1 = which >> 8;
+ if ((fs->min_char_or_byte2 > byte2) ||
+ (fs->max_char_or_byte2 < byte2) ||
+ (fs->min_byte1 > byte1) || (fs->max_byte1 < byte1))
+ valid = 0;
+ }
+
+ if (valid) {
+ if (fs->per_char) {
+ if (rows == 1) {
+ /* "linear" fonts */
+ return (fs->per_char + (which - fs->min_char_or_byte2));
+ }
+ else {
+ /* "matrix" fonts */
+ i = ((byte1 - fs->min_byte1) * pages) +
+ (byte2 - fs->min_char_or_byte2);
+ return (fs->per_char + i);
+ }
+ }
+ else {
+ return (&fs->min_bounds);
+ }
+ }
+ return (NULL);
+}
+
+
+PUBLIC void
+glXUseXFont(Font font, int first, int count, int listbase)
+{
+ Display *dpy;
+ Window win;
+ Pixmap pixmap;
+ GC gc;
+ XGCValues values;
+ unsigned long valuemask;
+ XFontStruct *fs;
+ GLint swapbytes, lsbfirst, rowlength;
+ GLint skiprows, skippixels, alignment;
+ unsigned int max_width, max_height, max_bm_width, max_bm_height;
+ GLubyte *bm;
+ int i;
+
+ dpy = glXGetCurrentDisplay();
+ if (!dpy)
+ return; /* I guess glXMakeCurrent wasn't called */
+ i = DefaultScreen(dpy);
+ win = RootWindow(dpy, i);
+
+ fs = XQueryFont(dpy, font);
+ if (!fs) {
+ _mesa_error(NULL, GL_INVALID_VALUE,
+ "Couldn't get font structure information");
+ return;
+ }
+
+ /* Allocate a bitmap that can fit all characters. */
+ max_width = fs->max_bounds.rbearing - fs->min_bounds.lbearing;
+ max_height = fs->max_bounds.ascent + fs->max_bounds.descent;
+ max_bm_width = (max_width + 7) / 8;
+ max_bm_height = max_height;
+
+ bm = (GLubyte *) MALLOC((max_bm_width * max_bm_height) * sizeof(GLubyte));
+ if (!bm) {
+ XFreeFontInfo(NULL, fs, 1);
+ _mesa_error(NULL, GL_OUT_OF_MEMORY,
+ "Couldn't allocate bitmap in glXUseXFont()");
+ return;
+ }
+
+#if 0
+ /* get the page info */
+ pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1;
+ firstchar = (fs->min_byte1 << 8) + fs->min_char_or_byte2;
+ lastchar = (fs->max_byte1 << 8) + fs->max_char_or_byte2;
+ rows = fs->max_byte1 - fs->min_byte1 + 1;
+ unsigned int first_char, last_char, pages, rows;
+#endif
+
+ /* Save the current packing mode for bitmaps. */
+ glGetIntegerv(GL_UNPACK_SWAP_BYTES, &swapbytes);
+ glGetIntegerv(GL_UNPACK_LSB_FIRST, &lsbfirst);
+ glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rowlength);
+ glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skiprows);
+ glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skippixels);
+ glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
+
+ /* Enforce a standard packing mode which is compatible with
+ fill_bitmap() from above. This is actually the default mode,
+ except for the (non)alignment. */
+ glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
+ glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ pixmap = XCreatePixmap(dpy, win, 10, 10, 1);
+ values.foreground = BlackPixel(dpy, DefaultScreen(dpy));
+ values.background = WhitePixel(dpy, DefaultScreen(dpy));
+ values.font = fs->fid;
+ valuemask = GCForeground | GCBackground | GCFont;
+ gc = XCreateGC(dpy, pixmap, valuemask, &values);
+ XFreePixmap(dpy, pixmap);
+
+#ifdef DEBUG
+ if (debug_xfonts)
+ dump_font_struct(fs);
+#endif
+
+ for (i = 0; i < count; i++) {
+ unsigned int width, height, bm_width, bm_height;
+ GLfloat x0, y0, dx, dy;
+ XCharStruct *ch;
+ int x, y;
+ unsigned int c = first + i;
+ int list = listbase + i;
+ int valid;
+
+ /* check on index validity and get the bounds */
+ ch = isvalid(fs, c);
+ if (!ch) {
+ ch = &fs->max_bounds;
+ valid = 0;
+ }
+ else {
+ valid = 1;
+ }
+
+#ifdef DEBUG
+ if (debug_xfonts) {
+ char s[7];
+ sprintf(s, isprint(c) ? "%c> " : "\\%03o> ", c);
+ dump_char_struct(ch, s);
+ }
+#endif
+
+ /* glBitmap()' parameters:
+ straight from the glXUseXFont(3) manpage. */
+ width = ch->rbearing - ch->lbearing;
+ height = ch->ascent + ch->descent;
+ x0 = -ch->lbearing;
+ y0 = ch->descent - 0; /* XXX used to subtract 1 here */
+ /* but that caused a conformace failure */
+ dx = ch->width;
+ dy = 0;
+
+ /* X11's starting point. */
+ x = -ch->lbearing;
+ y = ch->ascent;
+
+ /* Round the width to a multiple of eight. We will use this also
+ for the pixmap for capturing the X11 font. This is slightly
+ inefficient, but it makes the OpenGL part real easy. */
+ bm_width = (width + 7) / 8;
+ bm_height = height;
+
+ glNewList(list, GL_COMPILE);
+ if (valid && (bm_width > 0) && (bm_height > 0)) {
+
+ memset(bm, '\0', bm_width * bm_height);
+ fill_bitmap(dpy, win, gc, bm_width, bm_height, x, y, c, bm);
+
+ glBitmap(width, height, x0, y0, dx, dy, bm);
+#ifdef DEBUG
+ if (debug_xfonts) {
+ printf("width/height = %u/%u\n", width, height);
+ printf("bm_width/bm_height = %u/%u\n", bm_width, bm_height);
+ dump_bitmap(bm_width, bm_height, bm);
+ }
+#endif
+ }
+ else {
+ glBitmap(0, 0, 0.0, 0.0, dx, dy, NULL);
+ }
+ glEndList();
+ }
+
+ FREE(bm);
+ XFreeFontInfo(NULL, fs, 1);
+ XFreeGC(dpy, gc);
+
+ /* Restore saved packing modes. */
+ glPixelStorei(GL_UNPACK_SWAP_BYTES, swapbytes);
+ glPixelStorei(GL_UNPACK_LSB_FIRST, lsbfirst);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, rowlength);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, skiprows);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, skippixels);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
+}
diff --git a/src/gallium/state_trackers/glx/xlib/xm_api.c b/src/gallium/state_trackers/glx/xlib/xm_api.c
new file mode 100644
index 0000000000..c0c418306f
--- /dev/null
+++ b/src/gallium/state_trackers/glx/xlib/xm_api.c
@@ -0,0 +1,1240 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.1
+ *
+ * Copyright (C) 1999-2007 Brian Paul 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL 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.
+ */
+
+/**
+ * \file xm_api.c
+ *
+ * All the XMesa* API functions.
+ *
+ *
+ * NOTES:
+ *
+ * The window coordinate system origin (0,0) is in the lower-left corner
+ * of the window. X11's window coordinate origin is in the upper-left
+ * corner of the window. Therefore, most drawing functions in this
+ * file have to flip Y coordinates.
+ *
+ *
+ * Byte swapping: If the Mesa host and the X display use a different
+ * byte order then there's some trickiness to be aware of when using
+ * XImages. The byte ordering used for the XImage is that of the X
+ * display, not the Mesa host.
+ * The color-to-pixel encoding for True/DirectColor must be done
+ * according to the display's visual red_mask, green_mask, and blue_mask.
+ * If XPutPixel is used to put a pixel into an XImage then XPutPixel will
+ * do byte swapping if needed. If one wants to directly "poke" the pixel
+ * into the XImage's buffer then the pixel must be byte swapped first.
+ *
+ */
+
+#ifdef __CYGWIN__
+#undef WIN32
+#undef __WIN32__
+#endif
+
+#include "xm_api.h"
+#include "xm_st.h"
+
+#include "main/context.h"
+#include "pipe/p_defines.h"
+#include "pipe/p_screen.h"
+#include "pipe/p_context.h"
+
+#include "xm_public.h"
+#include <GL/glx.h>
+
+
+/* Driver interface routines, set up by xlib backend on library
+ * _init(). These are global in the same way that function names are
+ * global.
+ */
+static struct xm_driver driver;
+static struct st_api *stapi;
+
+void xmesa_set_driver( const struct xm_driver *templ )
+{
+ driver = *templ;
+ stapi = driver.create_st_api();
+}
+
+
+/*
+ * XXX replace this with a linked list, or better yet, try to attach the
+ * gallium/mesa extra bits to the X Display object with XAddExtension().
+ */
+#define MAX_DISPLAYS 10
+static struct xmesa_display Displays[MAX_DISPLAYS];
+static int NumDisplays = 0;
+
+static int
+xmesa_get_param(struct st_manager *smapi,
+ enum st_manager_param param)
+{
+ return 0;
+}
+
+static XMesaDisplay
+xmesa_init_display( Display *display )
+{
+ pipe_static_mutex(init_mutex);
+ XMesaDisplay xmdpy;
+ int i;
+
+ pipe_mutex_lock(init_mutex);
+
+ /* Look for XMesaDisplay which corresponds to 'display' */
+ for (i = 0; i < NumDisplays; i++) {
+ if (Displays[i].display == display) {
+ /* Found it */
+ pipe_mutex_unlock(init_mutex);
+ return &Displays[i];
+ }
+ }
+
+ /* Create new XMesaDisplay */
+
+ assert(NumDisplays < MAX_DISPLAYS);
+ xmdpy = &Displays[NumDisplays];
+ NumDisplays++;
+
+ if (!xmdpy->display && display) {
+ xmdpy->display = display;
+ xmdpy->screen = driver.create_pipe_screen(display);
+ xmdpy->smapi = CALLOC_STRUCT(st_manager);
+ if (xmdpy->smapi) {
+ xmdpy->smapi->screen = xmdpy->screen;
+ xmdpy->smapi->get_param = xmesa_get_param;
+ }
+
+ if (xmdpy->screen && xmdpy->smapi) {
+ pipe_mutex_init(xmdpy->mutex);
+ }
+ else {
+ if (xmdpy->screen) {
+ xmdpy->screen->destroy(xmdpy->screen);
+ xmdpy->screen = NULL;
+ }
+ if (xmdpy->smapi) {
+ FREE(xmdpy->smapi);
+ xmdpy->smapi = NULL;
+ }
+
+ xmdpy->display = NULL;
+ }
+ }
+ if (!xmdpy->display || xmdpy->display != display)
+ xmdpy = NULL;
+
+ pipe_mutex_unlock(init_mutex);
+
+ return xmdpy;
+}
+
+/**********************************************************************/
+/***** X Utility Functions *****/
+/**********************************************************************/
+
+
+/**
+ * Return the host's byte order as LSBFirst or MSBFirst ala X.
+ */
+static int host_byte_order( void )
+{
+ int i = 1;
+ char *cptr = (char *) &i;
+ return (*cptr==1) ? LSBFirst : MSBFirst;
+}
+
+
+
+
+/**
+ * Return the true number of bits per pixel for XImages.
+ * For example, if we request a 24-bit deep visual we may actually need/get
+ * 32bpp XImages. This function returns the appropriate bpp.
+ * Input: dpy - the X display
+ * visinfo - desribes the visual to be used for XImages
+ * Return: true number of bits per pixel for XImages
+ */
+static int
+bits_per_pixel( XMesaVisual xmv )
+{
+ Display *dpy = xmv->display;
+ XVisualInfo * visinfo = xmv->visinfo;
+ XImage *img;
+ int bitsPerPixel;
+ /* Create a temporary XImage */
+ img = XCreateImage( dpy, visinfo->visual, visinfo->depth,
+ ZPixmap, 0, /*format, offset*/
+ (char*) MALLOC(8), /*data*/
+ 1, 1, /*width, height*/
+ 32, /*bitmap_pad*/
+ 0 /*bytes_per_line*/
+ );
+ assert(img);
+ /* grab the bits/pixel value */
+ bitsPerPixel = img->bits_per_pixel;
+ /* free the XImage */
+ free( img->data );
+ img->data = NULL;
+ XDestroyImage( img );
+ return bitsPerPixel;
+}
+
+
+
+/*
+ * Determine if a given X window ID is valid (window exists).
+ * Do this by calling XGetWindowAttributes() for the window and
+ * checking if we catch an X error.
+ * Input: dpy - the display
+ * win - the window to check for existance
+ * Return: GL_TRUE - window exists
+ * GL_FALSE - window doesn't exist
+ */
+static GLboolean WindowExistsFlag;
+
+static int window_exists_err_handler( Display* dpy, XErrorEvent* xerr )
+{
+ (void) dpy;
+ if (xerr->error_code == BadWindow) {
+ WindowExistsFlag = GL_FALSE;
+ }
+ return 0;
+}
+
+static GLboolean window_exists( Display *dpy, Window win )
+{
+ XWindowAttributes wa;
+ int (*old_handler)( Display*, XErrorEvent* );
+ WindowExistsFlag = GL_TRUE;
+ old_handler = XSetErrorHandler(window_exists_err_handler);
+ XGetWindowAttributes( dpy, win, &wa ); /* dummy request */
+ XSetErrorHandler(old_handler);
+ return WindowExistsFlag;
+}
+
+static Status
+get_drawable_size( Display *dpy, Drawable d, uint *width, uint *height )
+{
+ Window root;
+ Status stat;
+ int xpos, ypos;
+ unsigned int w, h, bw, depth;
+ stat = XGetGeometry(dpy, d, &root, &xpos, &ypos, &w, &h, &bw, &depth);
+ *width = w;
+ *height = h;
+ return stat;
+}
+
+
+/**
+ * Return the size of the window (or pixmap) that corresponds to the
+ * given XMesaBuffer.
+ * \param width returns width in pixels
+ * \param height returns height in pixels
+ */
+void
+xmesa_get_window_size(Display *dpy, XMesaBuffer b,
+ GLuint *width, GLuint *height)
+{
+ XMesaDisplay xmdpy = xmesa_init_display(dpy);
+ Status stat;
+
+ pipe_mutex_lock(xmdpy->mutex);
+ XSync(b->xm_visual->display, 0); /* added for Chromium */
+ stat = get_drawable_size(dpy, b->ws.drawable, width, height);
+ pipe_mutex_unlock(xmdpy->mutex);
+
+ if (!stat) {
+ /* probably querying a window that's recently been destroyed */
+ _mesa_warning(NULL, "XGetGeometry failed!\n");
+ *width = *height = 1;
+ }
+}
+
+#define GET_REDMASK(__v) __v->mesa_visual.redMask
+#define GET_GREENMASK(__v) __v->mesa_visual.greenMask
+#define GET_BLUEMASK(__v) __v->mesa_visual.blueMask
+
+
+/**
+ * Choose the pixel format for the given visual.
+ * This will tell the gallium driver how to pack pixel data into
+ * drawing surfaces.
+ */
+static GLuint
+choose_pixel_format(XMesaVisual v)
+{
+ boolean native_byte_order = (host_byte_order() ==
+ ImageByteOrder(v->display));
+
+ if ( GET_REDMASK(v) == 0x0000ff
+ && GET_GREENMASK(v) == 0x00ff00
+ && GET_BLUEMASK(v) == 0xff0000
+ && v->BitsPerPixel == 32) {
+ if (native_byte_order) {
+ /* no byteswapping needed */
+ return PIPE_FORMAT_R8G8B8A8_UNORM;
+ }
+ else {
+ return PIPE_FORMAT_A8B8G8R8_UNORM;
+ }
+ }
+ else if ( GET_REDMASK(v) == 0xff0000
+ && GET_GREENMASK(v) == 0x00ff00
+ && GET_BLUEMASK(v) == 0x0000ff
+ && v->BitsPerPixel == 32) {
+ if (native_byte_order) {
+ /* no byteswapping needed */
+ return PIPE_FORMAT_B8G8R8A8_UNORM;
+ }
+ else {
+ return PIPE_FORMAT_A8R8G8B8_UNORM;
+ }
+ }
+ else if ( GET_REDMASK(v) == 0x0000ff00
+ && GET_GREENMASK(v) == 0x00ff0000
+ && GET_BLUEMASK(v) == 0xff000000
+ && v->BitsPerPixel == 32) {
+ if (native_byte_order) {
+ /* no byteswapping needed */
+ return PIPE_FORMAT_A8R8G8B8_UNORM;
+ }
+ else {
+ return PIPE_FORMAT_B8G8R8A8_UNORM;
+ }
+ }
+ else if ( GET_REDMASK(v) == 0xf800
+ && GET_GREENMASK(v) == 0x07e0
+ && GET_BLUEMASK(v) == 0x001f
+ && native_byte_order
+ && v->BitsPerPixel == 16) {
+ /* 5-6-5 RGB */
+ return PIPE_FORMAT_B5G6R5_UNORM;
+ }
+
+ return PIPE_FORMAT_NONE;
+}
+
+
+/**
+ * Choose a depth/stencil format that satisfies the given depth and
+ * stencil sizes.
+ */
+static enum pipe_format
+choose_depth_stencil_format(XMesaDisplay xmdpy, int depth, int stencil)
+{
+ const enum pipe_texture_target target = PIPE_TEXTURE_2D;
+ const unsigned tex_usage = PIPE_BIND_DEPTH_STENCIL;
+ const unsigned geom_flags = (PIPE_TEXTURE_GEOM_NON_SQUARE |
+ PIPE_TEXTURE_GEOM_NON_POWER_OF_TWO);
+ const unsigned sample_count = 0;
+ enum pipe_format formats[8], fmt;
+ int count, i;
+
+ count = 0;
+
+ if (depth <= 16 && stencil == 0) {
+ formats[count++] = PIPE_FORMAT_Z16_UNORM;
+ }
+ if (depth <= 24 && stencil == 0) {
+ formats[count++] = PIPE_FORMAT_X8Z24_UNORM;
+ formats[count++] = PIPE_FORMAT_Z24X8_UNORM;
+ }
+ if (depth <= 24 && stencil <= 8) {
+ formats[count++] = PIPE_FORMAT_S8_USCALED_Z24_UNORM;
+ formats[count++] = PIPE_FORMAT_Z24_UNORM_S8_USCALED;
+ }
+ if (depth <= 32 && stencil == 0) {
+ formats[count++] = PIPE_FORMAT_Z32_UNORM;
+ }
+
+ fmt = PIPE_FORMAT_NONE;
+ for (i = 0; i < count; i++) {
+ if (xmdpy->screen->is_format_supported(xmdpy->screen, formats[i],
+ target, sample_count,
+ tex_usage, geom_flags)) {
+ fmt = formats[i];
+ break;
+ }
+ }
+
+ return fmt;
+}
+
+
+
+/**********************************************************************/
+/***** Linked list of XMesaBuffers *****/
+/**********************************************************************/
+
+static XMesaBuffer XMesaBufferList = NULL;
+
+
+/**
+ * Allocate a new XMesaBuffer object which corresponds to the given drawable.
+ * Note that XMesaBuffer is derived from GLframebuffer.
+ * The new XMesaBuffer will not have any size (Width=Height=0).
+ *
+ * \param d the corresponding X drawable (window or pixmap)
+ * \param type either WINDOW, PIXMAP or PBUFFER, describing d
+ * \param vis the buffer's visual
+ * \param cmap the window's colormap, if known.
+ * \return new XMesaBuffer or NULL if any problem
+ */
+static XMesaBuffer
+create_xmesa_buffer(Drawable d, BufferType type,
+ XMesaVisual vis, Colormap cmap)
+{
+ XMesaDisplay xmdpy = xmesa_init_display(vis->display);
+ XMesaBuffer b;
+ uint width, height;
+
+ ASSERT(type == WINDOW || type == PIXMAP || type == PBUFFER);
+
+ if (!xmdpy)
+ return NULL;
+
+ b = (XMesaBuffer) CALLOC_STRUCT(xmesa_buffer);
+ if (!b)
+ return NULL;
+
+ b->ws.drawable = d;
+ b->ws.visual = vis->visinfo->visual;
+ b->ws.depth = vis->visinfo->depth;
+
+ b->xm_visual = vis;
+ b->type = type;
+ b->cmap = cmap;
+
+ get_drawable_size(vis->display, d, &width, &height);
+
+ /*
+ * Create framebuffer, but we'll plug in our own renderbuffers below.
+ */
+ b->stfb = xmesa_create_st_framebuffer(xmdpy, b);
+
+ /* GLX_EXT_texture_from_pixmap */
+ b->TextureTarget = 0;
+ b->TextureFormat = GLX_TEXTURE_FORMAT_NONE_EXT;
+ b->TextureMipmap = 0;
+
+ /* insert buffer into linked list */
+ b->Next = XMesaBufferList;
+ XMesaBufferList = b;
+
+ return b;
+}
+
+
+/**
+ * Find an XMesaBuffer by matching X display and colormap but NOT matching
+ * the notThis buffer.
+ */
+XMesaBuffer
+xmesa_find_buffer(Display *dpy, Colormap cmap, XMesaBuffer notThis)
+{
+ XMesaBuffer b;
+ for (b = XMesaBufferList; b; b = b->Next) {
+ if (b->xm_visual->display == dpy &&
+ b->cmap == cmap &&
+ b != notThis) {
+ return b;
+ }
+ }
+ return NULL;
+}
+
+
+/**
+ * Remove buffer from linked list, delete if no longer referenced.
+ */
+static void
+xmesa_free_buffer(XMesaBuffer buffer)
+{
+ XMesaBuffer prev = NULL, b;
+
+ for (b = XMesaBufferList; b; b = b->Next) {
+ if (b == buffer) {
+ /* unlink buffer from list */
+ if (prev)
+ prev->Next = buffer->Next;
+ else
+ XMesaBufferList = buffer->Next;
+
+ /* Since the X window for the XMesaBuffer is going away, we don't
+ * want to dereference this pointer in the future.
+ */
+ b->ws.drawable = 0;
+
+ /* XXX we should move the buffer to a delete-pending list and destroy
+ * the buffer until it is no longer current.
+ */
+ xmesa_destroy_st_framebuffer(buffer->stfb);
+
+ free(buffer);
+
+ return;
+ }
+ /* continue search */
+ prev = b;
+ }
+ /* buffer not found in XMesaBufferList */
+ _mesa_problem(NULL,"xmesa_free_buffer() - buffer not found\n");
+}
+
+
+
+/**********************************************************************/
+/***** Misc Private Functions *****/
+/**********************************************************************/
+
+
+/**
+ * When a context is bound for the first time, we can finally finish
+ * initializing the context's visual and buffer information.
+ * \param v the XMesaVisual to initialize
+ * \param b the XMesaBuffer to initialize (may be NULL)
+ * \param rgb_flag TRUE = RGBA mode, FALSE = color index mode
+ * \param window the window/pixmap we're rendering into
+ * \param cmap the colormap associated with the window/pixmap
+ * \return GL_TRUE=success, GL_FALSE=failure
+ */
+static GLboolean
+initialize_visual_and_buffer(XMesaVisual v, XMesaBuffer b,
+ GLboolean rgb_flag, Drawable window,
+ Colormap cmap)
+{
+ ASSERT(!b || b->xm_visual == v);
+
+ /* Save true bits/pixel */
+ v->BitsPerPixel = bits_per_pixel(v);
+ assert(v->BitsPerPixel > 0);
+
+ if (rgb_flag == GL_FALSE) {
+ /* COLOR-INDEXED WINDOW: not supported*/
+ return GL_FALSE;
+ }
+ else {
+ /* RGB WINDOW:
+ * We support RGB rendering into almost any kind of visual.
+ */
+ const int xclass = v->mesa_visual.visualType;
+ if (xclass != GLX_TRUE_COLOR && xclass == !GLX_DIRECT_COLOR) {
+ _mesa_warning(NULL,
+ "XMesa: RGB mode rendering not supported in given visual.\n");
+ return GL_FALSE;
+ }
+ v->mesa_visual.indexBits = 0;
+
+ if (v->BitsPerPixel == 32) {
+ /* We use XImages for all front/back buffers. If an X Window or
+ * X Pixmap is 32bpp, there's no guarantee that the alpha channel
+ * will be preserved. For XImages we're in luck.
+ */
+ v->mesa_visual.alphaBits = 8;
+ }
+ }
+
+ /*
+ * If MESA_INFO env var is set print out some debugging info
+ * which can help Brian figure out what's going on when a user
+ * reports bugs.
+ */
+ if (_mesa_getenv("MESA_INFO")) {
+ printf("X/Mesa visual = %p\n", (void *) v);
+ printf("X/Mesa level = %d\n", v->mesa_visual.level);
+ printf("X/Mesa depth = %d\n", v->visinfo->depth);
+ printf("X/Mesa bits per pixel = %d\n", v->BitsPerPixel);
+ }
+
+ return GL_TRUE;
+}
+
+
+
+#define NUM_VISUAL_TYPES 6
+
+/**
+ * Convert an X visual type to a GLX visual type.
+ *
+ * \param visualType X visual type (i.e., \c TrueColor, \c StaticGray, etc.)
+ * to be converted.
+ * \return If \c visualType is a valid X visual type, a GLX visual type will
+ * be returned. Otherwise \c GLX_NONE will be returned.
+ *
+ * \note
+ * This code was lifted directly from lib/GL/glx/glcontextmodes.c in the
+ * DRI CVS tree.
+ */
+static GLint
+xmesa_convert_from_x_visual_type( int visualType )
+{
+ static const int glx_visual_types[ NUM_VISUAL_TYPES ] = {
+ GLX_STATIC_GRAY, GLX_GRAY_SCALE,
+ GLX_STATIC_COLOR, GLX_PSEUDO_COLOR,
+ GLX_TRUE_COLOR, GLX_DIRECT_COLOR
+ };
+
+ return ( (unsigned) visualType < NUM_VISUAL_TYPES )
+ ? glx_visual_types[ visualType ] : GLX_NONE;
+}
+
+
+/**********************************************************************/
+/***** Public Functions *****/
+/**********************************************************************/
+
+
+/*
+ * Create a new X/Mesa visual.
+ * Input: display - X11 display
+ * visinfo - an XVisualInfo pointer
+ * rgb_flag - GL_TRUE = RGB mode,
+ * GL_FALSE = color index mode
+ * alpha_flag - alpha buffer requested?
+ * db_flag - GL_TRUE = double-buffered,
+ * GL_FALSE = single buffered
+ * stereo_flag - stereo visual?
+ * ximage_flag - GL_TRUE = use an XImage for back buffer,
+ * GL_FALSE = use an off-screen pixmap for back buffer
+ * depth_size - requested bits/depth values, or zero
+ * stencil_size - requested bits/stencil values, or zero
+ * accum_red_size - requested bits/red accum values, or zero
+ * accum_green_size - requested bits/green accum values, or zero
+ * accum_blue_size - requested bits/blue accum values, or zero
+ * accum_alpha_size - requested bits/alpha accum values, or zero
+ * num_samples - number of samples/pixel if multisampling, or zero
+ * level - visual level, usually 0
+ * visualCaveat - ala the GLX extension, usually GLX_NONE
+ * Return; a new XMesaVisual or 0 if error.
+ */
+PUBLIC
+XMesaVisual XMesaCreateVisual( Display *display,
+ XVisualInfo * visinfo,
+ GLboolean rgb_flag,
+ GLboolean alpha_flag,
+ GLboolean db_flag,
+ GLboolean stereo_flag,
+ GLboolean ximage_flag,
+ GLint depth_size,
+ GLint stencil_size,
+ GLint accum_red_size,
+ GLint accum_green_size,
+ GLint accum_blue_size,
+ GLint accum_alpha_size,
+ GLint num_samples,
+ GLint level,
+ GLint visualCaveat )
+{
+ XMesaDisplay xmdpy = xmesa_init_display(display);
+ XMesaVisual v;
+ GLint red_bits, green_bits, blue_bits, alpha_bits;
+
+ if (!xmdpy)
+ return NULL;
+
+ /* For debugging only */
+ if (_mesa_getenv("MESA_XSYNC")) {
+ /* This makes debugging X easier.
+ * In your debugger, set a breakpoint on _XError to stop when an
+ * X protocol error is generated.
+ */
+ XSynchronize( display, 1 );
+ }
+
+ v = (XMesaVisual) CALLOC_STRUCT(xmesa_visual);
+ if (!v) {
+ return NULL;
+ }
+
+ v->display = display;
+
+ /* Save a copy of the XVisualInfo struct because the user may Xfree()
+ * the struct but we may need some of the information contained in it
+ * at a later time.
+ */
+ v->visinfo = (XVisualInfo *) MALLOC(sizeof(*visinfo));
+ if (!v->visinfo) {
+ free(v);
+ return NULL;
+ }
+ memcpy(v->visinfo, visinfo, sizeof(*visinfo));
+
+ v->ximage_flag = ximage_flag;
+
+ v->mesa_visual.redMask = visinfo->red_mask;
+ v->mesa_visual.greenMask = visinfo->green_mask;
+ v->mesa_visual.blueMask = visinfo->blue_mask;
+ v->mesa_visual.visualID = visinfo->visualid;
+ v->mesa_visual.screen = visinfo->screen;
+
+#if !(defined(__cplusplus) || defined(c_plusplus))
+ v->mesa_visual.visualType = xmesa_convert_from_x_visual_type(visinfo->class);
+#else
+ v->mesa_visual.visualType = xmesa_convert_from_x_visual_type(visinfo->c_class);
+#endif
+
+ v->mesa_visual.visualRating = visualCaveat;
+
+ if (alpha_flag)
+ v->mesa_visual.alphaBits = 8;
+
+ (void) initialize_visual_and_buffer( v, NULL, rgb_flag, 0, 0 );
+
+ {
+ const int xclass = v->mesa_visual.visualType;
+ if (xclass == GLX_TRUE_COLOR || xclass == GLX_DIRECT_COLOR) {
+ red_bits = _mesa_bitcount(GET_REDMASK(v));
+ green_bits = _mesa_bitcount(GET_GREENMASK(v));
+ blue_bits = _mesa_bitcount(GET_BLUEMASK(v));
+ }
+ else {
+ /* this is an approximation */
+ int depth;
+ depth = v->visinfo->depth;
+ red_bits = depth / 3;
+ depth -= red_bits;
+ green_bits = depth / 2;
+ depth -= green_bits;
+ blue_bits = depth;
+ alpha_bits = 0;
+ assert( red_bits + green_bits + blue_bits == v->visinfo->depth );
+ }
+ alpha_bits = v->mesa_visual.alphaBits;
+ }
+
+ _mesa_initialize_visual( &v->mesa_visual,
+ db_flag, stereo_flag,
+ red_bits, green_bits,
+ blue_bits, alpha_bits,
+ depth_size,
+ stencil_size,
+ accum_red_size, accum_green_size,
+ accum_blue_size, accum_alpha_size,
+ 0 );
+
+ v->stvis.buffer_mask = ST_ATTACHMENT_FRONT_LEFT_MASK;
+ if (db_flag)
+ v->stvis.buffer_mask |= ST_ATTACHMENT_BACK_LEFT_MASK;
+ if (stereo_flag) {
+ v->stvis.buffer_mask |= ST_ATTACHMENT_FRONT_RIGHT_MASK;
+ if (db_flag)
+ v->stvis.buffer_mask |= ST_ATTACHMENT_BACK_RIGHT_MASK;
+ }
+
+ v->stvis.color_format = choose_pixel_format(v);
+ if (v->stvis.color_format == PIPE_FORMAT_NONE) {
+ FREE(v->visinfo);
+ FREE(v);
+ return NULL;
+ }
+
+ v->stvis.depth_stencil_format =
+ choose_depth_stencil_format(xmdpy, depth_size, stencil_size);
+
+ v->stvis.accum_format = (accum_red_size +
+ accum_green_size + accum_blue_size + accum_alpha_size) ?
+ PIPE_FORMAT_R16G16B16A16_SNORM : PIPE_FORMAT_NONE;
+
+ v->stvis.samples = num_samples;
+ v->stvis.render_buffer = ST_ATTACHMENT_INVALID;
+
+ /* XXX minor hack */
+ v->mesa_visual.level = level;
+ return v;
+}
+
+
+PUBLIC
+void XMesaDestroyVisual( XMesaVisual v )
+{
+ free(v->visinfo);
+ free(v);
+}
+
+
+/**
+ * Do per-display initializations.
+ */
+void
+xmesa_init( Display *display )
+{
+ xmesa_init_display(display);
+}
+
+
+/**
+ * Create a new XMesaContext.
+ * \param v the XMesaVisual
+ * \param share_list another XMesaContext with which to share display
+ * lists or NULL if no sharing is wanted.
+ * \return an XMesaContext or NULL if error.
+ */
+PUBLIC
+XMesaContext XMesaCreateContext( XMesaVisual v, XMesaContext share_list )
+{
+ XMesaDisplay xmdpy = xmesa_init_display(v->display);
+ XMesaContext c;
+
+ if (!xmdpy)
+ return NULL;
+
+ /* Note: the XMesaContext contains a Mesa GLcontext struct (inheritance) */
+ c = (XMesaContext) CALLOC_STRUCT(xmesa_context);
+ if (!c)
+ return NULL;
+
+ c->xm_visual = v;
+ c->xm_buffer = NULL; /* set later by XMesaMakeCurrent */
+ c->xm_read_buffer = NULL;
+
+ c->st = stapi->create_context(stapi, xmdpy->smapi,
+ &v->stvis, (share_list) ? share_list->st : NULL);
+ if (c->st == NULL)
+ goto fail;
+
+ c->st->st_manager_private = (void *) c;
+
+ return c;
+
+fail:
+ if (c->st)
+ c->st->destroy(c->st);
+
+ free(c);
+ return NULL;
+}
+
+
+
+PUBLIC
+void XMesaDestroyContext( XMesaContext c )
+{
+ c->st->destroy(c->st);
+
+ /* FIXME: We should destroy the screen here, but if we do so, surfaces may
+ * outlive it, causing segfaults
+ struct pipe_screen *screen = c->st->pipe->screen;
+ screen->destroy(screen);
+ */
+
+ free(c);
+}
+
+
+
+/**
+ * Private function for creating an XMesaBuffer which corresponds to an
+ * X window or pixmap.
+ * \param v the window's XMesaVisual
+ * \param w the window we're wrapping
+ * \return new XMesaBuffer or NULL if error
+ */
+PUBLIC XMesaBuffer
+XMesaCreateWindowBuffer(XMesaVisual v, Window w)
+{
+ XWindowAttributes attr;
+ XMesaBuffer b;
+ Colormap cmap;
+ int depth;
+
+ assert(v);
+ assert(w);
+
+ /* Check that window depth matches visual depth */
+ XGetWindowAttributes( v->display, w, &attr );
+ depth = attr.depth;
+ if (v->visinfo->depth != depth) {
+ _mesa_warning(NULL, "XMesaCreateWindowBuffer: depth mismatch between visual (%d) and window (%d)!\n",
+ v->visinfo->depth, depth);
+ return NULL;
+ }
+
+ /* Find colormap */
+ if (attr.colormap) {
+ cmap = attr.colormap;
+ }
+ else {
+ _mesa_warning(NULL, "Window %u has no colormap!\n", (unsigned int) w);
+ /* this is weird, a window w/out a colormap!? */
+ /* OK, let's just allocate a new one and hope for the best */
+ cmap = XCreateColormap(v->display, w, attr.visual, AllocNone);
+ }
+
+ b = create_xmesa_buffer((Drawable) w, WINDOW, v, cmap);
+ if (!b)
+ return NULL;
+
+ if (!initialize_visual_and_buffer( v, b, v->mesa_visual.rgbMode,
+ (Drawable) w, cmap )) {
+ xmesa_free_buffer(b);
+ return NULL;
+ }
+
+ return b;
+}
+
+
+
+/**
+ * Create a new XMesaBuffer from an X pixmap.
+ *
+ * \param v the XMesaVisual
+ * \param p the pixmap
+ * \param cmap the colormap, may be 0 if using a \c GLX_TRUE_COLOR or
+ * \c GLX_DIRECT_COLOR visual for the pixmap
+ * \returns new XMesaBuffer or NULL if error
+ */
+PUBLIC XMesaBuffer
+XMesaCreatePixmapBuffer(XMesaVisual v, Pixmap p, Colormap cmap)
+{
+ XMesaBuffer b;
+
+ assert(v);
+
+ b = create_xmesa_buffer((Drawable) p, PIXMAP, v, cmap);
+ if (!b)
+ return NULL;
+
+ if (!initialize_visual_and_buffer(v, b, v->mesa_visual.rgbMode,
+ (Drawable) p, cmap)) {
+ xmesa_free_buffer(b);
+ return NULL;
+ }
+
+ return b;
+}
+
+
+/**
+ * For GLX_EXT_texture_from_pixmap
+ */
+XMesaBuffer
+XMesaCreatePixmapTextureBuffer(XMesaVisual v, Pixmap p,
+ Colormap cmap,
+ int format, int target, int mipmap)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ XMesaBuffer b;
+
+ assert(v);
+
+ b = create_xmesa_buffer((Drawable) p, PIXMAP, v, cmap);
+ if (!b)
+ return NULL;
+
+ /* get pixmap size */
+ xmesa_get_window_size(v->display, b, &b->width, &b->height);
+
+ if (target == 0) {
+ /* examine dims */
+ if (ctx->Extensions.ARB_texture_non_power_of_two) {
+ target = GLX_TEXTURE_2D_EXT;
+ }
+ else if ( _mesa_bitcount(b->width) == 1
+ && _mesa_bitcount(b->height) == 1) {
+ /* power of two size */
+ if (b->height == 1) {
+ target = GLX_TEXTURE_1D_EXT;
+ }
+ else {
+ target = GLX_TEXTURE_2D_EXT;
+ }
+ }
+ else if (ctx->Extensions.NV_texture_rectangle) {
+ target = GLX_TEXTURE_RECTANGLE_EXT;
+ }
+ else {
+ /* non power of two textures not supported */
+ XMesaDestroyBuffer(b);
+ return 0;
+ }
+ }
+
+ b->TextureTarget = target;
+ b->TextureFormat = format;
+ b->TextureMipmap = mipmap;
+
+ if (!initialize_visual_and_buffer(v, b, v->mesa_visual.rgbMode,
+ (Drawable) p, cmap)) {
+ xmesa_free_buffer(b);
+ return NULL;
+ }
+
+ return b;
+}
+
+
+
+XMesaBuffer
+XMesaCreatePBuffer(XMesaVisual v, Colormap cmap,
+ unsigned int width, unsigned int height)
+{
+ Window root;
+ Drawable drawable; /* X Pixmap Drawable */
+ XMesaBuffer b;
+
+ /* allocate pixmap for front buffer */
+ root = RootWindow( v->display, v->visinfo->screen );
+ drawable = XCreatePixmap(v->display, root, width, height,
+ v->visinfo->depth);
+ if (!drawable)
+ return NULL;
+
+ b = create_xmesa_buffer(drawable, PBUFFER, v, cmap);
+ if (!b)
+ return NULL;
+
+ if (!initialize_visual_and_buffer(v, b, v->mesa_visual.rgbMode,
+ drawable, cmap)) {
+ xmesa_free_buffer(b);
+ return NULL;
+ }
+
+ return b;
+}
+
+
+
+/*
+ * Deallocate an XMesaBuffer structure and all related info.
+ */
+PUBLIC void
+XMesaDestroyBuffer(XMesaBuffer b)
+{
+ xmesa_free_buffer(b);
+}
+
+
+/**
+ * Query the current drawable size and notify the binding context.
+ */
+void
+xmesa_check_buffer_size(XMesaBuffer b)
+{
+ XMesaContext xmctx = XMesaGetCurrentContext();
+
+ if (b->type == PBUFFER)
+ return;
+
+ xmesa_get_window_size(b->xm_visual->display, b, &b->width, &b->height);
+ if (xmctx && xmctx->xm_buffer == b)
+ xmctx->st->notify_invalid_framebuffer(xmctx->st, b->stfb);
+}
+
+
+/*
+ * Bind buffer b to context c and make c the current rendering context.
+ */
+PUBLIC
+GLboolean XMesaMakeCurrent2( XMesaContext c, XMesaBuffer drawBuffer,
+ XMesaBuffer readBuffer )
+{
+ XMesaContext old_ctx = XMesaGetCurrentContext();
+
+ if (old_ctx && old_ctx != c) {
+ XMesaFlush(old_ctx);
+ old_ctx->xm_buffer = NULL;
+ old_ctx->xm_read_buffer = NULL;
+ }
+
+ if (c) {
+ if (!drawBuffer || !readBuffer)
+ return GL_FALSE; /* must specify buffers! */
+
+ if (c == old_ctx &&
+ c->xm_buffer == drawBuffer &&
+ c->xm_read_buffer == readBuffer)
+ return GL_TRUE;
+
+ xmesa_check_buffer_size(drawBuffer);
+ if (readBuffer != drawBuffer)
+ xmesa_check_buffer_size(readBuffer);
+
+ c->xm_buffer = drawBuffer;
+ c->xm_read_buffer = readBuffer;
+
+ stapi->make_current(stapi, c->st, drawBuffer->stfb, readBuffer->stfb);
+
+ /* Solution to Stephane Rehel's problem with glXReleaseBuffersMESA(): */
+ drawBuffer->wasCurrent = GL_TRUE;
+ }
+ else {
+ /* Detach */
+ stapi->make_current(stapi, NULL, NULL, NULL);
+
+ }
+ return GL_TRUE;
+}
+
+
+/*
+ * Unbind the context c from its buffer.
+ */
+GLboolean XMesaUnbindContext( XMesaContext c )
+{
+ /* A no-op for XFree86 integration purposes */
+ return GL_TRUE;
+}
+
+
+XMesaContext XMesaGetCurrentContext( void )
+{
+ struct st_context_iface *st = stapi->get_current(stapi);
+ return (XMesaContext) (st) ? st->st_manager_private : NULL;
+}
+
+
+
+/**
+ * Swap front and back color buffers and have winsys display front buffer.
+ * If there's no front color buffer no swap actually occurs.
+ */
+PUBLIC
+void XMesaSwapBuffers( XMesaBuffer b )
+{
+ XMesaContext xmctx = XMesaGetCurrentContext();
+
+ if (xmctx && xmctx->xm_buffer == b) {
+ xmctx->st->flush( xmctx->st,
+ PIPE_FLUSH_RENDER_CACHE |
+ PIPE_FLUSH_SWAPBUFFERS |
+ PIPE_FLUSH_FRAME,
+ NULL);
+ }
+
+ xmesa_swap_st_framebuffer(b->stfb);
+}
+
+
+
+/*
+ * Copy sub-region of back buffer to front buffer
+ */
+void XMesaCopySubBuffer( XMesaBuffer b, int x, int y, int width, int height )
+{
+ xmesa_copy_st_framebuffer(b->stfb,
+ ST_ATTACHMENT_BACK_LEFT, ST_ATTACHMENT_FRONT_LEFT,
+ x, y, width, height);
+}
+
+
+
+void XMesaFlush( XMesaContext c )
+{
+ if (c && c->xm_visual->display) {
+ XMesaDisplay xmdpy = xmesa_init_display(c->xm_visual->display);
+ struct pipe_fence_handle *fence = NULL;
+
+ c->st->flush(c->st, PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, &fence);
+ if (fence) {
+ xmdpy->screen->fence_finish(xmdpy->screen, fence, 0);
+ xmdpy->screen->fence_reference(xmdpy->screen, &fence, NULL);
+ }
+ XSync( c->xm_visual->display, False );
+ }
+}
+
+
+
+
+
+XMesaBuffer XMesaFindBuffer( Display *dpy, Drawable d )
+{
+ XMesaBuffer b;
+ for (b = XMesaBufferList; b; b = b->Next) {
+ if (b->ws.drawable == d && b->xm_visual->display == dpy) {
+ return b;
+ }
+ }
+ return NULL;
+}
+
+
+/**
+ * Free/destroy all XMesaBuffers associated with given display.
+ */
+void xmesa_destroy_buffers_on_display(Display *dpy)
+{
+ XMesaBuffer b, next;
+ for (b = XMesaBufferList; b; b = next) {
+ next = b->Next;
+ if (b->xm_visual->display == dpy) {
+ xmesa_free_buffer(b);
+ /* delete head of list? */
+ if (XMesaBufferList == b) {
+ XMesaBufferList = next;
+ }
+ }
+ }
+}
+
+
+/*
+ * Look for XMesaBuffers whose X window has been destroyed.
+ * Deallocate any such XMesaBuffers.
+ */
+void XMesaGarbageCollect( void )
+{
+ XMesaBuffer b, next;
+ for (b=XMesaBufferList; b; b=next) {
+ next = b->Next;
+ if (b->xm_visual &&
+ b->xm_visual->display &&
+ b->ws.drawable &&
+ b->type == WINDOW) {
+ XSync(b->xm_visual->display, False);
+ if (!window_exists( b->xm_visual->display, b->ws.drawable )) {
+ /* found a dead window, free the ancillary info */
+ XMesaDestroyBuffer( b );
+ }
+ }
+ }
+}
+
+
+
+
+PUBLIC void
+XMesaBindTexImage(Display *dpy, XMesaBuffer drawable, int buffer,
+ const int *attrib_list)
+{
+}
+
+
+
+PUBLIC void
+XMesaReleaseTexImage(Display *dpy, XMesaBuffer drawable, int buffer)
+{
+}
+
+
+void
+XMesaCopyContext(XMesaContext src, XMesaContext dst, unsigned long mask)
+{
+ if (dst->st->copy)
+ dst->st->copy(dst->st, src->st, mask);
+}
diff --git a/src/gallium/state_trackers/glx/xlib/xm_api.h b/src/gallium/state_trackers/glx/xlib/xm_api.h
new file mode 100644
index 0000000000..4f2c8a6e6a
--- /dev/null
+++ b/src/gallium/state_trackers/glx/xlib/xm_api.h
@@ -0,0 +1,383 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.1
+ *
+ * Copyright (C) 1999-2007 Brian Paul 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL 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.
+ */
+
+
+
+/* Sample Usage:
+
+In addition to the usual X calls to select a visual, create a colormap
+and create a window, you must do the following to use the X/Mesa interface:
+
+1. Call XMesaCreateVisual() to make an XMesaVisual from an XVisualInfo.
+
+2. Call XMesaCreateContext() to create an X/Mesa rendering context, given
+ the XMesaVisual.
+
+3. Call XMesaCreateWindowBuffer() to create an XMesaBuffer from an X window
+ and XMesaVisual.
+
+4. Call XMesaMakeCurrent() to bind the XMesaBuffer to an XMesaContext and
+ to make the context the current one.
+
+5. Make gl* calls to render your graphics.
+
+6. Use XMesaSwapBuffers() when double buffering to swap front/back buffers.
+
+7. Before the X window is destroyed, call XMesaDestroyBuffer().
+
+8. Before exiting, call XMesaDestroyVisual and XMesaDestroyContext.
+
+*/
+
+
+
+
+#ifndef XMESA_H
+#define XMESA_H
+
+
+#include "main/mtypes.h"
+#include "state_tracker/st_api.h"
+#include "os/os_thread.h"
+
+#include "state_tracker/xlib_sw_winsys.h"
+
+# include <X11/Xlib.h>
+# include <X11/Xlibint.h>
+# include <X11/Xutil.h>
+
+typedef struct xmesa_display *XMesaDisplay;
+typedef struct xmesa_buffer *XMesaBuffer;
+typedef struct xmesa_context *XMesaContext;
+typedef struct xmesa_visual *XMesaVisual;
+
+
+struct xmesa_display {
+ pipe_mutex mutex;
+
+ Display *display;
+ struct pipe_screen *screen;
+ struct st_manager *smapi;
+
+ struct pipe_context *pipe;
+};
+
+
+/*
+ * Create a new X/Mesa visual.
+ * Input: display - X11 display
+ * visinfo - an XVisualInfo pointer
+ * rgb_flag - GL_TRUE = RGB mode,
+ * GL_FALSE = color index mode
+ * alpha_flag - alpha buffer requested?
+ * db_flag - GL_TRUE = double-buffered,
+ * GL_FALSE = single buffered
+ * stereo_flag - stereo visual?
+ * ximage_flag - GL_TRUE = use an XImage for back buffer,
+ * GL_FALSE = use an off-screen pixmap for back buffer
+ * depth_size - requested bits/depth values, or zero
+ * stencil_size - requested bits/stencil values, or zero
+ * accum_red_size - requested bits/red accum values, or zero
+ * accum_green_size - requested bits/green accum values, or zero
+ * accum_blue_size - requested bits/blue accum values, or zero
+ * accum_alpha_size - requested bits/alpha accum values, or zero
+ * num_samples - number of samples/pixel if multisampling, or zero
+ * level - visual level, usually 0
+ * visualCaveat - ala the GLX extension, usually GLX_NONE_EXT
+ * Return; a new XMesaVisual or 0 if error.
+ */
+extern XMesaVisual XMesaCreateVisual( Display *display,
+ XVisualInfo * visinfo,
+ GLboolean rgb_flag,
+ GLboolean alpha_flag,
+ GLboolean db_flag,
+ GLboolean stereo_flag,
+ GLboolean ximage_flag,
+ GLint depth_size,
+ GLint stencil_size,
+ GLint accum_red_size,
+ GLint accum_green_size,
+ GLint accum_blue_size,
+ GLint accum_alpha_size,
+ GLint num_samples,
+ GLint level,
+ GLint visualCaveat );
+
+/*
+ * Destroy an XMesaVisual, but not the associated XVisualInfo.
+ */
+extern void XMesaDestroyVisual( XMesaVisual v );
+
+
+
+/*
+ * Create a new XMesaContext for rendering into an X11 window.
+ *
+ * Input: visual - an XMesaVisual
+ * share_list - another XMesaContext with which to share display
+ * lists or NULL if no sharing is wanted.
+ * Return: an XMesaContext or NULL if error.
+ */
+extern XMesaContext XMesaCreateContext( XMesaVisual v,
+ XMesaContext share_list );
+
+
+/*
+ * Destroy a rendering context as returned by XMesaCreateContext()
+ */
+extern void XMesaDestroyContext( XMesaContext c );
+
+
+
+/*
+ * Create an XMesaBuffer from an X window.
+ */
+extern XMesaBuffer XMesaCreateWindowBuffer( XMesaVisual v, Window w );
+
+
+/*
+ * Create an XMesaBuffer from an X pixmap.
+ */
+extern XMesaBuffer XMesaCreatePixmapBuffer( XMesaVisual v,
+ Pixmap p,
+ Colormap cmap );
+
+
+/*
+ * Destroy an XMesaBuffer, but not the corresponding window or pixmap.
+ */
+extern void XMesaDestroyBuffer( XMesaBuffer b );
+
+
+/*
+ * Return the XMesaBuffer handle which corresponds to an X drawable, if any.
+ *
+ * New in Mesa 2.3.
+ */
+extern XMesaBuffer XMesaFindBuffer( Display *dpy,
+ Drawable d );
+
+
+
+/*
+ * Bind two buffers (read and draw) to a context and make the
+ * context the current one.
+ * New in Mesa 3.3
+ */
+extern GLboolean XMesaMakeCurrent2( XMesaContext c,
+ XMesaBuffer drawBuffer,
+ XMesaBuffer readBuffer );
+
+
+/*
+ * Unbind the current context from its buffer.
+ */
+extern GLboolean XMesaUnbindContext( XMesaContext c );
+
+
+/*
+ * Return a handle to the current context.
+ */
+extern XMesaContext XMesaGetCurrentContext( void );
+
+
+/*
+ * Swap the front and back buffers for the given buffer. No action is
+ * taken if the buffer is not double buffered.
+ */
+extern void XMesaSwapBuffers( XMesaBuffer b );
+
+
+/*
+ * Copy a sub-region of the back buffer to the front buffer.
+ *
+ * New in Mesa 2.6
+ */
+extern void XMesaCopySubBuffer( XMesaBuffer b,
+ int x,
+ int y,
+ int width,
+ int height );
+
+
+
+
+
+/*
+ * Flush/sync a context
+ */
+extern void XMesaFlush( XMesaContext c );
+
+
+
+/*
+ * Scan for XMesaBuffers whose window/pixmap has been destroyed, then free
+ * any memory used by that buffer.
+ *
+ * New in Mesa 2.3.
+ */
+extern void XMesaGarbageCollect( void );
+
+
+
+/*
+ * Create a pbuffer.
+ * New in Mesa 4.1
+ */
+extern XMesaBuffer XMesaCreatePBuffer(XMesaVisual v, Colormap cmap,
+ unsigned int width, unsigned int height);
+
+
+
+/*
+ * Texture from Pixmap
+ * New in Mesa 7.1
+ */
+extern void
+XMesaBindTexImage(Display *dpy, XMesaBuffer drawable, int buffer,
+ const int *attrib_list);
+
+extern void
+XMesaReleaseTexImage(Display *dpy, XMesaBuffer drawable, int buffer);
+
+
+extern XMesaBuffer
+XMesaCreatePixmapTextureBuffer(XMesaVisual v, Pixmap p,
+ Colormap cmap,
+ int format, int target, int mipmap);
+
+
+extern void
+XMesaCopyContext(XMesaContext src, XMesaContext dst, unsigned long mask);
+
+
+/***********************************************************************
+ */
+
+/**
+ * Visual inforation, derived from GLvisual.
+ * Basically corresponds to an XVisualInfo.
+ */
+struct xmesa_visual {
+ GLvisual mesa_visual; /* Device independent visual parameters */
+ Display *display; /* The X11 display */
+ XVisualInfo * visinfo; /* X's visual info (pointer to private copy) */
+ XVisualInfo *vishandle; /* Only used in fakeglx.c */
+ GLint BitsPerPixel; /* True bits per pixel for XImages */
+
+ GLboolean ximage_flag; /* Use XImage for back buffer (not pixmap)? */
+
+ struct st_visual stvis;
+};
+
+
+/**
+ * Context info, derived from st_context.
+ * Basically corresponds to a GLXContext.
+ */
+struct xmesa_context {
+ struct st_context_iface *st;
+ XMesaVisual xm_visual; /** pixel format info */
+ XMesaBuffer xm_buffer; /** current drawbuffer */
+ XMesaBuffer xm_read_buffer; /** current readbuffer */
+};
+
+
+/**
+ * Types of X/GLX drawables we might render into.
+ */
+typedef enum {
+ WINDOW, /* An X window */
+ GLXWINDOW, /* GLX window */
+ PIXMAP, /* GLX pixmap */
+ PBUFFER /* GLX Pbuffer */
+} BufferType;
+
+
+/**
+ * Framebuffer information, derived from.
+ * Basically corresponds to a GLXDrawable.
+ */
+struct xmesa_buffer {
+ struct st_framebuffer_iface *stfb;
+ struct xlib_drawable ws;
+
+ GLboolean wasCurrent; /* was ever the current buffer? */
+ XMesaVisual xm_visual; /* the X/Mesa visual */
+ Drawable drawable; /* Usually the X window ID */
+ Colormap cmap; /* the X colormap */
+ BufferType type; /* window, pixmap, pbuffer or glxwindow */
+
+ GLboolean largestPbuffer; /**< for pbuffers */
+ GLboolean preservedContents; /**< for pbuffers */
+
+ XImage *tempImage;
+ unsigned long selectedEvents;/* for pbuffers only */
+
+
+ GC gc; /* scratch GC for span, line, tri drawing */
+
+ /* GLX_EXT_texture_from_pixmap */
+ GLint TextureTarget; /** GLX_TEXTURE_1D_EXT, for example */
+ GLint TextureFormat; /** GLX_TEXTURE_FORMAT_RGB_EXT, for example */
+ GLint TextureMipmap; /** 0 or 1 */
+
+ struct xmesa_buffer *Next; /* Linked list pointer: */
+
+ unsigned width, height;
+};
+
+
+
+extern void
+xmesa_init(Display *dpy);
+
+extern XMesaBuffer
+xmesa_find_buffer(Display *dpy, Colormap cmap, XMesaBuffer notThis);
+
+extern void
+xmesa_get_window_size(Display *dpy, XMesaBuffer b,
+ GLuint *width, GLuint *height);
+
+extern void
+xmesa_check_buffer_size(XMesaBuffer b);
+
+extern void
+xmesa_destroy_buffers_on_display(Display *dpy);
+
+static INLINE GLuint
+xmesa_buffer_width(XMesaBuffer b)
+{
+ return b->width;
+}
+
+static INLINE GLuint
+xmesa_buffer_height(XMesaBuffer b)
+{
+ return b->height;
+}
+
+
+
+#endif
diff --git a/src/gallium/state_trackers/glx/xlib/xm_public.h b/src/gallium/state_trackers/glx/xlib/xm_public.h
new file mode 100644
index 0000000000..950eb21521
--- /dev/null
+++ b/src/gallium/state_trackers/glx/xlib/xm_public.h
@@ -0,0 +1,48 @@
+
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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 XM_PUBLIC_H
+#define XM_PUBLIC_H
+
+#include <X11/Xlib.h>
+
+struct pipe_screen;
+struct st_api;
+
+/* This is the driver interface required by the glx/xlib state tracker.
+ */
+struct xm_driver {
+ struct pipe_screen *(*create_pipe_screen)( Display *display );
+ struct st_api *(*create_st_api)( void );
+};
+
+extern void
+xmesa_set_driver( const struct xm_driver *driver );
+
+
+#endif /* XM_PUBLIC_H */
diff --git a/src/gallium/state_trackers/glx/xlib/xm_st.c b/src/gallium/state_trackers/glx/xlib/xm_st.c
new file mode 100644
index 0000000000..c62eb8bfbd
--- /dev/null
+++ b/src/gallium/state_trackers/glx/xlib/xm_st.c
@@ -0,0 +1,338 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.9
+ *
+ * Copyright (C) 2010 LunarG Inc.
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Chia-I Wu <olv@lunarg.com>
+ */
+
+#include "util/u_memory.h"
+#include "util/u_inlines.h"
+
+#include "xm_api.h"
+#include "xm_st.h"
+
+struct xmesa_st_framebuffer {
+ XMesaDisplay display;
+ XMesaBuffer buffer;
+ struct pipe_screen *screen;
+
+ struct st_visual stvis;
+
+ unsigned texture_width, texture_height, texture_mask;
+ struct pipe_resource *textures[ST_ATTACHMENT_COUNT];
+
+ struct pipe_surface *display_surface;
+};
+
+static INLINE struct xmesa_st_framebuffer *
+xmesa_st_framebuffer(struct st_framebuffer_iface *stfbi)
+{
+ return (struct xmesa_st_framebuffer *) stfbi->st_manager_private;
+}
+
+/**
+ * Display an attachment to the xlib_drawable of the framebuffer.
+ */
+static boolean
+xmesa_st_framebuffer_display(struct st_framebuffer_iface *stfbi,
+ enum st_attachment_type statt)
+{
+ struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
+ struct pipe_resource *ptex = xstfb->textures[statt];
+ struct pipe_surface *psurf;
+
+ if (!ptex)
+ return TRUE;
+
+ psurf = xstfb->display_surface;
+ /* (re)allocate the surface for the texture to be displayed */
+ if (!psurf || psurf->texture != ptex) {
+ pipe_surface_reference(&xstfb->display_surface, NULL);
+
+ psurf = xstfb->screen->get_tex_surface(xstfb->screen,
+ ptex, 0, 0, 0, PIPE_BIND_DISPLAY_TARGET);
+ if (!psurf)
+ return FALSE;
+
+ xstfb->display_surface = psurf;
+ }
+
+ xstfb->screen->flush_frontbuffer(xstfb->screen, psurf, &xstfb->buffer->ws);
+
+ return TRUE;
+}
+
+/**
+ * Copy the contents between the attachments.
+ */
+static void
+xmesa_st_framebuffer_copy_textures(struct st_framebuffer_iface *stfbi,
+ enum st_attachment_type src_statt,
+ enum st_attachment_type dst_statt,
+ unsigned x, unsigned y,
+ unsigned width, unsigned height)
+{
+ struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
+ struct pipe_resource *src_ptex = xstfb->textures[src_statt];
+ struct pipe_resource *dst_ptex = xstfb->textures[dst_statt];
+ struct pipe_subresource subsrc, subdst;
+ struct pipe_context *pipe;
+
+ if (!src_ptex || !dst_ptex)
+ return;
+
+ pipe = xstfb->display->pipe;
+ if (!pipe) {
+ pipe = xstfb->screen->context_create(xstfb->screen, NULL);
+ if (!pipe)
+ return;
+ xstfb->display->pipe = pipe;
+ }
+
+ subsrc.face = 0;
+ subsrc.level = 0;
+ subdst.face = 0;
+ subdst.level = 0;
+
+ if (src_ptex && dst_ptex)
+ pipe->resource_copy_region(pipe, dst_ptex, subdst, x, y, 0,
+ src_ptex, subsrc, x, y, 0, width, height);
+}
+
+/**
+ * Remove outdated textures and create the requested ones.
+ */
+static boolean
+xmesa_st_framebuffer_validate_textures(struct st_framebuffer_iface *stfbi,
+ unsigned width, unsigned height,
+ unsigned mask)
+{
+ struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
+ struct pipe_resource templ;
+ enum st_attachment_type i;
+
+ /* remove outdated textures */
+ if (xstfb->texture_width != width || xstfb->texture_height != height) {
+ for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
+ pipe_resource_reference(&xstfb->textures[i], NULL);
+ }
+
+ memset(&templ, 0, sizeof(templ));
+ templ.target = PIPE_TEXTURE_2D;
+ templ.width0 = width;
+ templ.height0 = height;
+ templ.depth0 = 1;
+ templ.last_level = 0;
+
+ for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
+ enum pipe_format format;
+ unsigned bind;
+
+ /* the texture already exists or not requested */
+ if (xstfb->textures[i] || !(mask & (1 << i))) {
+ /* remember the texture */
+ if (xstfb->textures[i])
+ mask |= (1 << i);
+ continue;
+ }
+
+ switch (i) {
+ case ST_ATTACHMENT_FRONT_LEFT:
+ case ST_ATTACHMENT_BACK_LEFT:
+ case ST_ATTACHMENT_FRONT_RIGHT:
+ case ST_ATTACHMENT_BACK_RIGHT:
+ format = xstfb->stvis.color_format;
+ bind = PIPE_BIND_DISPLAY_TARGET |
+ PIPE_BIND_RENDER_TARGET;
+ break;
+ case ST_ATTACHMENT_DEPTH_STENCIL:
+ format = xstfb->stvis.depth_stencil_format;
+ bind = PIPE_BIND_DEPTH_STENCIL;
+ break;
+ default:
+ format = PIPE_FORMAT_NONE;
+ break;
+ }
+
+ if (format != PIPE_FORMAT_NONE) {
+ templ.format = format;
+ templ.bind = bind;
+
+ xstfb->textures[i] =
+ xstfb->screen->resource_create(xstfb->screen, &templ);
+ if (!xstfb->textures[i])
+ return FALSE;
+ }
+ }
+
+ xstfb->texture_width = width;
+ xstfb->texture_height = height;
+ xstfb->texture_mask = mask;
+
+ return TRUE;
+}
+
+static boolean
+xmesa_st_framebuffer_validate(struct st_framebuffer_iface *stfbi,
+ const enum st_attachment_type *statts,
+ unsigned count,
+ struct pipe_resource **out)
+{
+ struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
+ unsigned statt_mask, new_mask, i;
+ boolean resized;
+ boolean ret;
+
+ statt_mask = 0x0;
+ for (i = 0; i < count; i++)
+ statt_mask |= 1 << statts[i];
+ /* record newly allocated textures */
+ new_mask = statt_mask & ~xstfb->texture_mask;
+
+ resized = (xstfb->buffer->width != xstfb->texture_width ||
+ xstfb->buffer->height != xstfb->texture_height);
+
+ /* revalidate textures */
+ if (resized || new_mask) {
+ ret = xmesa_st_framebuffer_validate_textures(stfbi,
+ xstfb->buffer->width, xstfb->buffer->height, statt_mask);
+ if (!ret)
+ return ret;
+
+ if (!resized) {
+ enum st_attachment_type back, front;
+
+ back = ST_ATTACHMENT_BACK_LEFT;
+ front = ST_ATTACHMENT_FRONT_LEFT;
+ /* copy the contents if front is newly allocated and back is not */
+ if ((statt_mask & (1 << back)) &&
+ (new_mask & (1 << front)) &&
+ !(new_mask & (1 << back))) {
+ xmesa_st_framebuffer_copy_textures(stfbi, back, front,
+ 0, 0, xstfb->texture_width, xstfb->texture_height);
+ }
+ }
+ }
+
+ for (i = 0; i < count; i++) {
+ out[i] = NULL;
+ pipe_resource_reference(&out[i], xstfb->textures[statts[i]]);
+ }
+
+ return TRUE;
+}
+
+static boolean
+xmesa_st_framebuffer_flush_front(struct st_framebuffer_iface *stfbi,
+ enum st_attachment_type statt)
+{
+ struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
+ boolean ret;
+
+ ret = xmesa_st_framebuffer_display(stfbi, statt);
+ if (ret)
+ xmesa_check_buffer_size(xstfb->buffer);
+
+ return ret;
+}
+
+struct st_framebuffer_iface *
+xmesa_create_st_framebuffer(XMesaDisplay xmdpy, XMesaBuffer b)
+{
+ struct st_framebuffer_iface *stfbi;
+ struct xmesa_st_framebuffer *xstfb;
+
+ assert(xmdpy->display == b->xm_visual->display);
+
+ stfbi = CALLOC_STRUCT(st_framebuffer_iface);
+ xstfb = CALLOC_STRUCT(xmesa_st_framebuffer);
+ if (!stfbi || !xstfb) {
+ if (stfbi)
+ FREE(stfbi);
+ if (xstfb)
+ FREE(xstfb);
+ return NULL;
+ }
+
+ xstfb->display = xmdpy;
+ xstfb->buffer = b;
+ xstfb->screen = xmdpy->screen;
+ xstfb->stvis = b->xm_visual->stvis;
+
+ stfbi->visual = &xstfb->stvis;
+ stfbi->flush_front = xmesa_st_framebuffer_flush_front;
+ stfbi->validate = xmesa_st_framebuffer_validate;
+ stfbi->st_manager_private = (void *) xstfb;
+
+ return stfbi;
+}
+
+void
+xmesa_destroy_st_framebuffer(struct st_framebuffer_iface *stfbi)
+{
+ struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
+ int i;
+
+ pipe_surface_reference(&xstfb->display_surface, NULL);
+
+ for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
+ pipe_resource_reference(&xstfb->textures[i], NULL);
+
+ FREE(xstfb);
+ FREE(stfbi);
+}
+
+void
+xmesa_swap_st_framebuffer(struct st_framebuffer_iface *stfbi)
+{
+ struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
+ boolean ret;
+
+ ret = xmesa_st_framebuffer_display(stfbi, ST_ATTACHMENT_BACK_LEFT);
+ if (ret) {
+ struct pipe_resource **front, **back, *tmp;
+
+ front = &xstfb->textures[ST_ATTACHMENT_FRONT_LEFT];
+ back = &xstfb->textures[ST_ATTACHMENT_BACK_LEFT];
+ /* swap textures only if the front texture has been allocated */
+ if (*front) {
+ tmp = *front;
+ *front = *back;
+ *back = tmp;
+ }
+
+ xmesa_check_buffer_size(xstfb->buffer);
+ }
+}
+
+void
+xmesa_copy_st_framebuffer(struct st_framebuffer_iface *stfbi,
+ enum st_attachment_type src,
+ enum st_attachment_type dst,
+ int x, int y, int w, int h)
+{
+ xmesa_st_framebuffer_copy_textures(stfbi, src, dst, x, y, w, h);
+ if (dst == ST_ATTACHMENT_FRONT_LEFT)
+ xmesa_st_framebuffer_display(stfbi, dst);
+}
diff --git a/src/gallium/state_trackers/glx/xlib/xm_st.h b/src/gallium/state_trackers/glx/xlib/xm_st.h
new file mode 100644
index 0000000000..862597617e
--- /dev/null
+++ b/src/gallium/state_trackers/glx/xlib/xm_st.h
@@ -0,0 +1,52 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.9
+ *
+ * Copyright (C) 2010 LunarG Inc.
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Chia-I Wu <olv@lunarg.com>
+ */
+
+#ifndef _XM_ST_H_
+#define _XM_ST_H_
+
+#include "pipe/p_compiler.h"
+#include "state_tracker/st_api.h"
+
+#include "xm_api.h"
+
+struct st_framebuffer_iface *
+xmesa_create_st_framebuffer(XMesaDisplay xmdpy, XMesaBuffer b);
+
+void
+xmesa_destroy_st_framebuffer(struct st_framebuffer_iface *stfbi);
+
+void
+xmesa_swap_st_framebuffer(struct st_framebuffer_iface *stfbi);
+
+void
+xmesa_copy_st_framebuffer(struct st_framebuffer_iface *stfbi,
+ enum st_attachment_type src,
+ enum st_attachment_type dst,
+ int x, int y, int w, int h);
+
+#endif /* _XM_ST_H_ */
diff --git a/src/gallium/state_trackers/python/README b/src/gallium/state_trackers/python/README
new file mode 100644
index 0000000000..e24a262aba
--- /dev/null
+++ b/src/gallium/state_trackers/python/README
@@ -0,0 +1,43 @@
+This directory contains Python bindings to Gallium3D. It looks like a state
+tracker from the pipe driver perspective, and it looks like a pipe driver from
+the python script perspective.
+
+
+To build you'll need:
+* Python (with development packages)
+* SCons
+* SWIG, http://www.swig.org/download.html
+* Python Imaging Library with TK support, http://www.pythonware.com/products/pil/,
+ for the samples
+
+On a debian-based distro you can simply do:
+
+ aptitude install python-dev scons swig python-imaging python-imaging-tk
+
+On a Windows machine ensure the swig command is in your PATH.
+
+Invoke scons on the top dir as
+
+ scons debug=yes statetrackers=python drivers=softpipe winsys=none
+
+To use it set PYTHONPATH appropriately, e.g, in Linux do:
+
+ export PYTHONPATH=$PWD/build/linux-x86-debug/gallium/state_trackers/python
+
+or (in Windows)
+
+ set PYTHONPATH=%CD%\build\windows-x86-debug\gallium\state_trackers\python
+
+and then try running
+
+ python progs/gallium/python/samples/tri.py
+
+which should show a triangle.
+
+
+This is still work in progress:
+- errors are not handled properly and almost always result in crash
+- state atoms with array members are awkward to set
+
+--
+Jose Fonseca <jfonseca@vmware.com>
diff --git a/src/gallium/state_trackers/python/SConscript b/src/gallium/state_trackers/python/SConscript
new file mode 100644
index 0000000000..aadeaa0a35
--- /dev/null
+++ b/src/gallium/state_trackers/python/SConscript
@@ -0,0 +1,59 @@
+import sys
+import os.path
+
+Import('*')
+
+if 'python' in env['statetrackers']:
+
+ env = env.Clone()
+
+ env.Tool('python')
+
+ env.Tool('swig')
+ env.Append(SWIGPATH = ['#src/gallium/include', '#src/gallium/include/pipe'])
+ env.Append(SWIGFLAGS = ['-python', '-keyword'])
+
+ env.Append(CPPPATH = '.')
+
+ if env['platform'] == 'windows':
+ env.Append(LIBS = [
+ 'opengl32',
+ 'gdi32',
+ 'user32',
+ 'kernel32',
+ 'ws2_32',
+ ])
+ else:
+ env.Append(CPPDEFINES = ['GCC_HASCLASSVISIBILITY'])
+ env.Append(LIBS = [
+ 'GL',
+ 'X11',
+ ])
+
+ sources = [
+ 'gallium.i',
+ 'st_device.c',
+ 'st_sample.c',
+ 'st_hardpipe_winsys.c',
+ 'st_softpipe_winsys.c',
+ ]
+
+ env.Prepend(LIBS = [
+ ws_null,
+ trace,
+ gallium,
+ ])
+
+ if env['llvm']:
+ env.Append(CPPDEFINES = ['HAVE_LLVMPIPE'])
+ env.Prepend(LIBS = [llvmpipe])
+ if True:
+ env.Append(CPPDEFINES = ['HAVE_SOFTPIPE'])
+ env.Prepend(LIBS = [softpipe])
+
+ env['no_import_lib'] = 1
+
+ env.SharedLibrary(
+ target = '_gallium',
+ source = sources,
+ )
diff --git a/src/gallium/state_trackers/python/gallium.i b/src/gallium/state_trackers/python/gallium.i
new file mode 100644
index 0000000000..c6084f78ae
--- /dev/null
+++ b/src/gallium/state_trackers/python/gallium.i
@@ -0,0 +1,105 @@
+ /**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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.
+ *
+ **************************************************************************/
+
+/**
+ * @file
+ * SWIG interface definion for Gallium types.
+ *
+ * @author Jose Fonseca <jrfonseca@tungstengraphics.com>
+ */
+
+%module gallium;
+
+%{
+
+#include <stdio.h>
+
+#include "pipe/p_screen.h"
+#include "pipe/p_context.h"
+#include "pipe/p_shader_tokens.h"
+#include "os/os_stream.h"
+#include "util/u_inlines.h"
+#include "util/u_draw_quad.h"
+#include "util/u_tile.h"
+#include "util/u_math.h"
+#include "util/u_format.h"
+#include "util/u_dump.h"
+#include "util/u_memory.h"
+#include "util/u_sampler.h"
+#include "cso_cache/cso_context.h"
+#include "tgsi/tgsi_text.h"
+#include "tgsi/tgsi_dump.h"
+
+#include "st_device.h"
+#include "st_sample.h"
+
+%}
+
+%include "typemaps.i"
+%include "exception.i"
+%include "cstring.i"
+
+%include "carrays.i"
+%array_class(unsigned char, ByteArray);
+%array_class(int, IntArray);
+%array_class(unsigned, UnsignedArray);
+%array_class(float, FloatArray);
+
+
+%rename(Device) st_device;
+%rename(Context) st_context;
+%rename(Resource) pipe_resource;
+%rename(Surface) st_surface;
+
+%rename(BlendColor) pipe_blend_color;
+%rename(Blend) pipe_blend_state;
+%rename(Clip) pipe_clip_state;
+%rename(Depth) pipe_depth_state;
+%rename(Stencil) pipe_stencil_state;
+%rename(Alpha) pipe_alpha_state;
+%rename(DepthStencilAlpha) pipe_depth_stencil_alpha_state;
+%rename(Framebuffer) pipe_framebuffer_state;
+%rename(PolyStipple) pipe_poly_stipple;
+%rename(Rasterizer) pipe_rasterizer_state;
+%rename(Sampler) pipe_sampler_state;
+%rename(Scissor) pipe_scissor_state;
+%rename(Shader) pipe_shader_state;
+%rename(VertexBuffer) pipe_vertex_buffer;
+%rename(VertexElement) pipe_vertex_element;
+%rename(Viewport) pipe_viewport_state;
+
+
+%include "p_compiler.i"
+%include "p_defines.h"
+%include "p_format.h"
+
+%include "p_device.i"
+%include "p_context.i"
+%include "p_texture.i"
+%include "p_state.i"
+
+%include "u_format.i"
diff --git a/src/gallium/state_trackers/python/p_compiler.i b/src/gallium/state_trackers/python/p_compiler.i
new file mode 100644
index 0000000000..15f6ba5b9d
--- /dev/null
+++ b/src/gallium/state_trackers/python/p_compiler.i
@@ -0,0 +1,29 @@
+ /**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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.
+ *
+ **************************************************************************/
+
+
+typedef unsigned char ubyte;
diff --git a/src/gallium/state_trackers/python/p_context.i b/src/gallium/state_trackers/python/p_context.i
new file mode 100644
index 0000000000..cf0144b5dc
--- /dev/null
+++ b/src/gallium/state_trackers/python/p_context.i
@@ -0,0 +1,768 @@
+ /**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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.
+ *
+ **************************************************************************/
+
+/**
+ * @file
+ * SWIG interface definion for Gallium types.
+ *
+ * @author Jose Fonseca <jrfonseca@tungstengraphics.com>
+ */
+
+%nodefaultctor st_context;
+%nodefaultdtor st_context;
+
+struct st_context {
+};
+
+%extend st_context {
+
+ ~st_context() {
+ st_context_destroy($self);
+ }
+
+ /*
+ * State functions (create/bind/destroy state objects)
+ */
+
+ void set_blend( const struct pipe_blend_state *state ) {
+ cso_set_blend($self->cso, state);
+ }
+
+ void set_fragment_sampler( unsigned index, const struct pipe_sampler_state *state ) {
+ cso_single_sampler($self->cso, index, state);
+ cso_single_sampler_done($self->cso);
+ }
+
+ void set_vertex_sampler( unsigned index, const struct pipe_sampler_state *state ) {
+ cso_single_vertex_sampler($self->cso, index, state);
+ cso_single_vertex_sampler_done($self->cso);
+ }
+
+ void set_rasterizer( const struct pipe_rasterizer_state *state ) {
+ cso_set_rasterizer($self->cso, state);
+ }
+
+ void set_depth_stencil_alpha(const struct pipe_depth_stencil_alpha_state *state) {
+ cso_set_depth_stencil_alpha($self->cso, state);
+ }
+
+ void set_fragment_shader( const struct pipe_shader_state *state ) {
+ void *fs;
+
+ if(!state) {
+ cso_set_fragment_shader_handle($self->cso, NULL);
+ return;
+ }
+
+ fs = $self->pipe->create_fs_state($self->pipe, state);
+ if(!fs)
+ return;
+
+ if(cso_set_fragment_shader_handle($self->cso, fs) != PIPE_OK)
+ return;
+
+ cso_delete_fragment_shader($self->cso, $self->fs);
+ $self->fs = fs;
+ }
+
+ void set_vertex_shader( const struct pipe_shader_state *state ) {
+ void *vs;
+
+ if(!state) {
+ cso_set_vertex_shader_handle($self->cso, NULL);
+ return;
+ }
+
+ vs = $self->pipe->create_vs_state($self->pipe, state);
+ if(!vs)
+ return;
+
+ if(cso_set_vertex_shader_handle($self->cso, vs) != PIPE_OK)
+ return;
+
+ cso_delete_vertex_shader($self->cso, $self->vs);
+ $self->vs = vs;
+ }
+
+ void set_geometry_shader( const struct pipe_shader_state *state ) {
+ void *gs;
+
+ if(!state) {
+ cso_set_geometry_shader_handle($self->cso, NULL);
+ return;
+ }
+
+ gs = $self->pipe->create_gs_state($self->pipe, state);
+ if(!gs)
+ return;
+
+ if(cso_set_geometry_shader_handle($self->cso, gs) != PIPE_OK)
+ return;
+
+ cso_delete_geometry_shader($self->cso, $self->gs);
+ $self->gs = gs;
+ }
+
+ struct pipe_sampler_view *
+ create_sampler_view(struct pipe_resource *texture,
+ enum pipe_format format = PIPE_FORMAT_NONE,
+ unsigned first_level = 0,
+ unsigned last_level = ~0,
+ unsigned swizzle_r = 0,
+ unsigned swizzle_g = 1,
+ unsigned swizzle_b = 2,
+ unsigned swizzle_a = 3)
+ {
+ struct pipe_context *pipe = $self->pipe;
+ struct pipe_sampler_view templat;
+
+ memset(&templat, 0, sizeof templat);
+ if (format == PIPE_FORMAT_NONE) {
+ templat.format = texture->format;
+ } else {
+ templat.format = format;
+ }
+ templat.last_level = MIN2(last_level, texture->last_level);
+ templat.first_level = first_level;
+ templat.last_level = last_level;
+ templat.swizzle_r = swizzle_r;
+ templat.swizzle_g = swizzle_g;
+ templat.swizzle_b = swizzle_b;
+ templat.swizzle_a = swizzle_a;
+
+ return pipe->create_sampler_view(pipe, texture, &templat);
+ }
+
+ void
+ sampler_view_destroy(struct pipe_context *ctx,
+ struct pipe_sampler_view *view)
+ {
+ struct pipe_context *pipe = $self->pipe;
+
+ pipe->sampler_view_destroy(pipe, view);
+ }
+
+ /*
+ * Parameter-like state (or properties)
+ */
+
+ void set_blend_color(const struct pipe_blend_color *state ) {
+ cso_set_blend_color($self->cso, state);
+ }
+
+ void set_stencil_ref(const struct pipe_stencil_ref *state ) {
+ cso_set_stencil_ref($self->cso, state);
+ }
+
+ void set_clip(const struct pipe_clip_state *state ) {
+ $self->pipe->set_clip_state($self->pipe, state);
+ }
+
+ void set_constant_buffer(unsigned shader, unsigned index,
+ struct pipe_resource *buffer )
+ {
+ $self->pipe->set_constant_buffer($self->pipe, shader, index, buffer);
+ }
+
+ void set_framebuffer(const struct pipe_framebuffer_state *state )
+ {
+ memcpy(&$self->framebuffer, state, sizeof *state);
+ cso_set_framebuffer($self->cso, state);
+ }
+
+ void set_polygon_stipple(const struct pipe_poly_stipple *state ) {
+ $self->pipe->set_polygon_stipple($self->pipe, state);
+ }
+
+ void set_scissor(const struct pipe_scissor_state *state ) {
+ $self->pipe->set_scissor_state($self->pipe, state);
+ }
+
+ void set_viewport(const struct pipe_viewport_state *state) {
+ cso_set_viewport($self->cso, state);
+ }
+
+ void set_fragment_sampler_view(unsigned index,
+ struct pipe_sampler_view *view)
+ {
+ pipe_sampler_view_reference(&$self->fragment_sampler_views[index], view);
+
+ $self->pipe->set_fragment_sampler_views($self->pipe,
+ PIPE_MAX_SAMPLERS,
+ $self->fragment_sampler_views);
+ }
+
+ void set_vertex_sampler_view(unsigned index,
+ struct pipe_sampler_view *view)
+ {
+ pipe_sampler_view_reference(&$self->vertex_sampler_views[index], view);
+
+ $self->pipe->set_vertex_sampler_views($self->pipe,
+ PIPE_MAX_VERTEX_SAMPLERS,
+ $self->vertex_sampler_views);
+ }
+
+ void set_fragment_sampler_texture(unsigned index,
+ struct pipe_resource *texture) {
+ struct pipe_sampler_view templ;
+
+ if(!texture)
+ texture = $self->default_texture;
+ pipe_sampler_view_reference(&$self->fragment_sampler_views[index], NULL);
+ u_sampler_view_default_template(&templ,
+ texture,
+ texture->format);
+ $self->fragment_sampler_views[index] = $self->pipe->create_sampler_view($self->pipe,
+ texture,
+ &templ);
+ $self->pipe->set_fragment_sampler_views($self->pipe,
+ PIPE_MAX_SAMPLERS,
+ $self->fragment_sampler_views);
+ }
+
+ void set_vertex_sampler_texture(unsigned index,
+ struct pipe_resource *texture) {
+ struct pipe_sampler_view templ;
+
+ if(!texture)
+ texture = $self->default_texture;
+ pipe_sampler_view_reference(&$self->vertex_sampler_views[index], NULL);
+ u_sampler_view_default_template(&templ,
+ texture,
+ texture->format);
+ $self->vertex_sampler_views[index] = $self->pipe->create_sampler_view($self->pipe,
+ texture,
+ &templ);
+
+ $self->pipe->set_vertex_sampler_views($self->pipe,
+ PIPE_MAX_VERTEX_SAMPLERS,
+ $self->vertex_sampler_views);
+ }
+
+ void set_vertex_buffer(unsigned index,
+ unsigned stride,
+ unsigned max_index,
+ unsigned buffer_offset,
+ struct pipe_resource *buffer)
+ {
+ unsigned i;
+ struct pipe_vertex_buffer state;
+
+ memset(&state, 0, sizeof(state));
+ state.stride = stride;
+ state.max_index = max_index;
+ state.buffer_offset = buffer_offset;
+ state.buffer = buffer;
+
+ memcpy(&$self->vertex_buffers[index], &state, sizeof(state));
+
+ for(i = 0; i < PIPE_MAX_ATTRIBS; ++i)
+ if(self->vertex_buffers[i].buffer)
+ $self->num_vertex_buffers = i + 1;
+
+ $self->pipe->set_vertex_buffers($self->pipe,
+ $self->num_vertex_buffers,
+ $self->vertex_buffers);
+ }
+
+ void set_vertex_element(unsigned index,
+ const struct pipe_vertex_element *element)
+ {
+ memcpy(&$self->vertex_elements[index], element, sizeof(*element));
+ }
+
+ void set_vertex_elements(unsigned num)
+ {
+ $self->num_vertex_elements = num;
+ cso_set_vertex_elements($self->cso,
+ $self->num_vertex_elements,
+ $self->vertex_elements);
+ }
+
+ /*
+ * Draw functions
+ */
+
+ void draw_arrays(unsigned mode, unsigned start, unsigned count) {
+ $self->pipe->draw_arrays($self->pipe, mode, start, count);
+ }
+
+ void draw_elements( struct pipe_resource *indexBuffer,
+ unsigned indexSize, int indexBias,
+ unsigned mode, unsigned start, unsigned count)
+ {
+ $self->pipe->draw_elements($self->pipe,
+ indexBuffer,
+ indexSize,
+ indexBias,
+ mode, start, count);
+ }
+
+ void draw_range_elements( struct pipe_resource *indexBuffer,
+ unsigned indexSize, int indexBias,
+ unsigned minIndex, unsigned maxIndex,
+ unsigned mode, unsigned start, unsigned count)
+ {
+ $self->pipe->draw_range_elements($self->pipe,
+ indexBuffer, indexSize, indexBias,
+ minIndex, maxIndex,
+ mode, start, count);
+ }
+
+ void draw_vertices(unsigned prim,
+ unsigned num_verts,
+ unsigned num_attribs,
+ const float *vertices)
+ {
+ struct pipe_context *pipe = $self->pipe;
+ struct pipe_screen *screen = pipe->screen;
+ struct pipe_resource *vbuf;
+ struct pipe_transfer *transfer;
+ struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS];
+ struct pipe_vertex_buffer vbuffer;
+ float *map;
+ unsigned size;
+ unsigned i;
+
+ size = num_verts * num_attribs * 4 * sizeof(float);
+
+ vbuf = pipe_buffer_create(screen,
+ PIPE_BIND_VERTEX_BUFFER,
+ size);
+ if(!vbuf)
+ goto error1;
+
+ map = pipe_buffer_map(pipe, vbuf, PIPE_TRANSFER_WRITE, &transfer);
+ if (!map)
+ goto error2;
+ memcpy(map, vertices, size);
+ pipe_buffer_unmap(pipe, vbuf, transfer);
+
+ cso_save_vertex_elements($self->cso);
+
+ /* tell pipe about the vertex attributes */
+ for (i = 0; i < num_attribs; i++) {
+ velements[i].src_offset = i * 4 * sizeof(float);
+ velements[i].instance_divisor = 0;
+ velements[i].vertex_buffer_index = 0;
+ velements[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
+ }
+ cso_set_vertex_elements($self->cso, num_attribs, velements);
+
+ /* tell pipe about the vertex buffer */
+ memset(&vbuffer, 0, sizeof(vbuffer));
+ vbuffer.buffer = vbuf;
+ vbuffer.stride = num_attribs * 4 * sizeof(float); /* vertex size */
+ vbuffer.buffer_offset = 0;
+ vbuffer.max_index = num_verts - 1;
+ pipe->set_vertex_buffers(pipe, 1, &vbuffer);
+
+ /* draw */
+ pipe->draw_arrays(pipe, prim, 0, num_verts);
+
+ cso_restore_vertex_elements($self->cso);
+
+error2:
+ pipe_resource_reference(&vbuf, NULL);
+error1:
+ ;
+ }
+
+ void
+ clear(unsigned buffers, const float *rgba, double depth = 0.0f,
+ unsigned stencil = 0)
+ {
+ $self->pipe->clear($self->pipe, buffers, rgba, depth, stencil);
+ }
+
+ void
+ flush(unsigned flags = 0) {
+ struct pipe_fence_handle *fence = NULL;
+ $self->pipe->flush($self->pipe, flags | PIPE_FLUSH_RENDER_CACHE, &fence);
+ if(fence) {
+ /* TODO: allow asynchronous operation */
+ $self->pipe->screen->fence_finish( $self->pipe->screen, fence, 0 );
+ $self->pipe->screen->fence_reference( $self->pipe->screen, &fence, NULL );
+ }
+ }
+
+ /*
+ * Surface functions
+ */
+
+ void resource_copy_region(struct pipe_resource *dst,
+ struct pipe_subresource subdst,
+ unsigned dstx, unsigned dsty, unsigned dstz,
+ struct pipe_resource *src,
+ struct pipe_subresource subsrc,
+ unsigned srcx, unsigned srcy, unsigned srcz,
+ unsigned width, unsigned height)
+ {
+ $self->pipe->resource_copy_region($self->pipe,
+ dst, subdst, dstx, dsty, dstz,
+ src, subsrc, srcx, srcy, srcz,
+ width, height);
+ }
+
+
+ void clear_render_target(struct st_surface *dst,
+ float *rgba,
+ unsigned x, unsigned y,
+ unsigned width, unsigned height)
+ {
+ struct pipe_surface *_dst = NULL;
+
+ _dst = st_pipe_surface(dst, PIPE_BIND_RENDER_TARGET);
+ if(!_dst)
+ SWIG_exception(SWIG_ValueError, "couldn't acquire destination surface for writing");
+
+ $self->pipe->clear_render_target($self->pipe, _dst, rgba, x, y, width, height);
+
+ fail:
+ pipe_surface_reference(&_dst, NULL);
+ }
+
+ void clear_depth_stencil(struct st_surface *dst,
+ unsigned clear_flags,
+ double depth,
+ unsigned stencil,
+ unsigned x, unsigned y,
+ unsigned width, unsigned height)
+ {
+ struct pipe_surface *_dst = NULL;
+
+ _dst = st_pipe_surface(dst, PIPE_BIND_DEPTH_STENCIL);
+ if(!_dst)
+ SWIG_exception(SWIG_ValueError, "couldn't acquire destination surface for writing");
+
+ $self->pipe->clear_depth_stencil($self->pipe, _dst, clear_flags, depth, stencil,
+ x, y, width, height);
+
+ fail:
+ pipe_surface_reference(&_dst, NULL);
+ }
+
+ %cstring_output_allocate_size(char **STRING, int *LENGTH, free(*$1));
+ void
+ surface_read_raw(struct st_surface *surface,
+ unsigned x, unsigned y, unsigned w, unsigned h,
+ char **STRING, int *LENGTH)
+ {
+ struct pipe_resource *texture = surface->texture;
+ struct pipe_context *pipe = $self->pipe;
+ struct pipe_transfer *transfer;
+ unsigned stride;
+
+ stride = util_format_get_stride(texture->format, w);
+ *LENGTH = util_format_get_nblocksy(texture->format, h) * stride;
+ *STRING = (char *) malloc(*LENGTH);
+ if(!*STRING)
+ return;
+
+ transfer = pipe_get_transfer(pipe,
+ surface->texture,
+ surface->face,
+ surface->level,
+ surface->zslice,
+ PIPE_TRANSFER_READ,
+ x, y, w, h);
+ if(transfer) {
+ pipe_get_tile_raw(pipe, transfer, 0, 0, w, h, *STRING, stride);
+ pipe->transfer_destroy(pipe, transfer);
+ }
+ }
+
+ %cstring_input_binary(const char *STRING, unsigned LENGTH);
+ void
+ surface_write_raw(struct st_surface *surface,
+ unsigned x, unsigned y, unsigned w, unsigned h,
+ const char *STRING, unsigned LENGTH, unsigned stride = 0)
+ {
+ struct pipe_resource *texture = surface->texture;
+ struct pipe_context *pipe = $self->pipe;
+ struct pipe_transfer *transfer;
+
+ if(stride == 0)
+ stride = util_format_get_stride(texture->format, w);
+
+ if(LENGTH < util_format_get_nblocksy(texture->format, h) * stride)
+ SWIG_exception(SWIG_ValueError, "offset must be smaller than buffer size");
+
+ transfer = pipe_get_transfer(pipe,
+ surface->texture,
+ surface->face,
+ surface->level,
+ surface->zslice,
+ PIPE_TRANSFER_WRITE,
+ x, y, w, h);
+ if(!transfer)
+ SWIG_exception(SWIG_MemoryError, "couldn't initiate transfer");
+
+ pipe_put_tile_raw(pipe, transfer, 0, 0, w, h, STRING, stride);
+ pipe->transfer_destroy(pipe, transfer);
+
+ fail:
+ return;
+ }
+
+ void
+ surface_read_rgba(struct st_surface *surface,
+ unsigned x, unsigned y, unsigned w, unsigned h,
+ float *rgba)
+ {
+ struct pipe_context *pipe = $self->pipe;
+ struct pipe_transfer *transfer;
+ transfer = pipe_get_transfer(pipe,
+ surface->texture,
+ surface->face,
+ surface->level,
+ surface->zslice,
+ PIPE_TRANSFER_READ,
+ x, y, w, h);
+ if(transfer) {
+ pipe_get_tile_rgba(pipe, transfer, 0, 0, w, h, rgba);
+ pipe->transfer_destroy(pipe, transfer);
+ }
+ }
+
+ void
+ surface_write_rgba(struct st_surface *surface,
+ unsigned x, unsigned y, unsigned w, unsigned h,
+ const float *rgba)
+ {
+ struct pipe_context *pipe = $self->pipe;
+ struct pipe_transfer *transfer;
+ transfer = pipe_get_transfer(pipe,
+ surface->texture,
+ surface->face,
+ surface->level,
+ surface->zslice,
+ PIPE_TRANSFER_WRITE,
+ x, y, w, h);
+ if(transfer) {
+ pipe_put_tile_rgba(pipe, transfer, 0, 0, w, h, rgba);
+ pipe->transfer_destroy(pipe, transfer);
+ }
+ }
+
+ %cstring_output_allocate_size(char **STRING, int *LENGTH, free(*$1));
+ void
+ surface_read_rgba8(struct st_surface *surface,
+ unsigned x, unsigned y, unsigned w, unsigned h,
+ char **STRING, int *LENGTH)
+ {
+ struct pipe_context *pipe = $self->pipe;
+ struct pipe_transfer *transfer;
+ float *rgba;
+ unsigned char *rgba8;
+ unsigned i, j, k;
+
+ *LENGTH = 0;
+ *STRING = NULL;
+
+ if (!surface)
+ return;
+
+ *LENGTH = h*w*4;
+ *STRING = (char *) malloc(*LENGTH);
+ if(!*STRING)
+ return;
+
+ rgba = malloc(h*w*4*sizeof(float));
+ if(!rgba)
+ return;
+
+ rgba8 = (unsigned char *) *STRING;
+
+ transfer = pipe_get_transfer(pipe,
+ surface->texture,
+ surface->face,
+ surface->level,
+ surface->zslice,
+ PIPE_TRANSFER_READ,
+ x, y, w, h);
+ if(transfer) {
+ pipe_get_tile_rgba(pipe, transfer, 0, 0, w, h, rgba);
+ for(j = 0; j < h; ++j) {
+ for(i = 0; i < w; ++i)
+ for(k = 0; k <4; ++k)
+ rgba8[j*w*4 + i*4 + k] = float_to_ubyte(rgba[j*w*4 + i*4 + k]);
+ }
+ pipe->transfer_destroy(pipe, transfer);
+ }
+
+ free(rgba);
+ }
+
+ void
+ surface_read_z(struct st_surface *surface,
+ unsigned x, unsigned y, unsigned w, unsigned h,
+ unsigned *z)
+ {
+ struct pipe_context *pipe = $self->pipe;
+ struct pipe_transfer *transfer;
+ transfer = pipe_get_transfer(pipe,
+ surface->texture,
+ surface->face,
+ surface->level,
+ surface->zslice,
+ PIPE_TRANSFER_READ,
+ x, y, w, h);
+ if(transfer) {
+ pipe_get_tile_z(pipe, transfer, 0, 0, w, h, z);
+ pipe->transfer_destroy(pipe, transfer);
+ }
+ }
+
+ void
+ surface_write_z(struct st_surface *surface,
+ unsigned x, unsigned y, unsigned w, unsigned h,
+ const unsigned *z)
+ {
+ struct pipe_context *pipe = $self->pipe;
+ struct pipe_transfer *transfer;
+ transfer = pipe_get_transfer(pipe,
+ surface->texture,
+ surface->face,
+ surface->level,
+ surface->zslice,
+ PIPE_TRANSFER_WRITE,
+ x, y, w, h);
+ if(transfer) {
+ pipe_put_tile_z(pipe, transfer, 0, 0, w, h, z);
+ pipe->transfer_destroy(pipe, transfer);
+ }
+ }
+
+ void
+ surface_sample_rgba(struct st_surface *surface,
+ float *rgba,
+ int norm = 0)
+ {
+ st_sample_surface($self->pipe, surface, rgba, norm != 0);
+ }
+
+ unsigned
+ surface_compare_rgba(struct st_surface *surface,
+ unsigned x, unsigned y, unsigned w, unsigned h,
+ const float *rgba, float tol = 0.0)
+ {
+ struct pipe_context *pipe = $self->pipe;
+ struct pipe_transfer *transfer;
+ float *rgba2;
+ const float *p1;
+ const float *p2;
+ unsigned i, j, n;
+
+ rgba2 = MALLOC(h*w*4*sizeof(float));
+ if(!rgba2)
+ return ~0;
+
+ transfer = pipe_get_transfer(pipe,
+ surface->texture,
+ surface->face,
+ surface->level,
+ surface->zslice,
+ PIPE_TRANSFER_READ,
+ x, y, w, h);
+ if(!transfer) {
+ FREE(rgba2);
+ return ~0;
+ }
+
+ pipe_get_tile_rgba(pipe, transfer, 0, 0, w, h, rgba2);
+ pipe->transfer_destroy(pipe, transfer);
+
+ p1 = rgba;
+ p2 = rgba2;
+ n = 0;
+ for(i = h*w; i; --i) {
+ unsigned differs = 0;
+ for(j = 4; j; --j) {
+ float delta = *p2++ - *p1++;
+ if (delta < -tol || delta > tol)
+ differs = 1;
+ }
+ n += differs;
+ }
+
+ FREE(rgba2);
+
+ return n;
+ }
+
+ %cstring_input_binary(const char *STRING, unsigned LENGTH);
+ void
+ transfer_inline_write(struct pipe_resource *resource,
+ struct pipe_subresource *sr,
+ unsigned usage,
+ const struct pipe_box *box,
+ const char *STRING, unsigned LENGTH,
+ unsigned stride,
+ unsigned slice_stride)
+ {
+ struct pipe_context *pipe = $self->pipe;
+
+ pipe->transfer_inline_write(pipe, resource, *sr, usage, box, STRING, stride, slice_stride);
+ }
+
+ %cstring_output_allocate_size(char **STRING, int *LENGTH, free(*$1));
+ void buffer_read(struct pipe_resource *buffer,
+ char **STRING, int *LENGTH)
+ {
+ struct pipe_context *pipe = $self->pipe;
+
+ assert(buffer->target == PIPE_BUFFER);
+
+ *LENGTH = buffer->width0;
+ *STRING = (char *) malloc(buffer->width0);
+ if(!*STRING)
+ return;
+
+ pipe_buffer_read(pipe, buffer, 0, buffer->width0, *STRING);
+ }
+
+ void buffer_write(struct pipe_resource *buffer,
+ const char *STRING, unsigned LENGTH, unsigned offset = 0)
+ {
+ struct pipe_context *pipe = $self->pipe;
+
+ assert(buffer->target == PIPE_BUFFER);
+
+ if(offset > buffer->width0)
+ SWIG_exception(SWIG_ValueError, "offset must be smaller than buffer size");
+
+ if(offset + LENGTH > buffer->width0)
+ SWIG_exception(SWIG_ValueError, "data length must fit inside the buffer");
+
+ pipe_buffer_write(pipe, buffer, offset, LENGTH, STRING);
+
+fail:
+ return;
+ }
+
+};
diff --git a/src/gallium/state_trackers/python/p_device.i b/src/gallium/state_trackers/python/p_device.i
new file mode 100644
index 0000000000..d55086fefd
--- /dev/null
+++ b/src/gallium/state_trackers/python/p_device.i
@@ -0,0 +1,140 @@
+ /**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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.
+ *
+ **************************************************************************/
+
+/**
+ * @file
+ * SWIG interface definion for Gallium types.
+ *
+ * @author Jose Fonseca <jrfonseca@tungstengraphics.com>
+ */
+
+
+%nodefaultctor st_device;
+%nodefaultdtor st_device;
+
+
+struct st_device {
+};
+
+%newobject st_device::texture_create;
+%newobject st_device::context_create;
+%newobject st_device::buffer_create;
+
+%extend st_device {
+
+ st_device(int hardware = 1) {
+ return st_device_create(hardware ? TRUE : FALSE);
+ }
+
+ ~st_device() {
+ st_device_destroy($self);
+ }
+
+ const char * get_name( void ) {
+ return $self->screen->get_name($self->screen);
+ }
+
+ const char * get_vendor( void ) {
+ return $self->screen->get_vendor($self->screen);
+ }
+
+ /**
+ * Query an integer-valued capability/parameter/limit
+ * \param param one of PIPE_CAP_x
+ */
+ int get_param( int param ) {
+ return $self->screen->get_param($self->screen, param);
+ }
+
+ /**
+ * Query a float-valued capability/parameter/limit
+ * \param param one of PIPE_CAP_x
+ */
+ float get_paramf( int param ) {
+ return $self->screen->get_paramf($self->screen, param);
+ }
+
+ /**
+ * Check if the given pipe_format is supported as a texture or
+ * drawing surface.
+ * \param bind bitmask of PIPE_BIND flags
+ */
+ int is_format_supported( enum pipe_format format,
+ enum pipe_texture_target target,
+ unsigned sample_count,
+ unsigned bind,
+ unsigned geom_flags ) {
+ /* We can't really display surfaces with the python statetracker so mask
+ * out that usage */
+ bind &= ~PIPE_BIND_DISPLAY_TARGET;
+
+ return $self->screen->is_format_supported( $self->screen,
+ format,
+ target,
+ sample_count,
+ bind,
+ geom_flags );
+ }
+
+ struct st_context *
+ context_create(void) {
+ return st_context_create($self);
+ }
+
+ struct pipe_resource *
+ resource_create(
+ enum pipe_format format,
+ unsigned width,
+ unsigned height,
+ unsigned depth = 1,
+ unsigned last_level = 0,
+ enum pipe_texture_target target = PIPE_TEXTURE_2D,
+ unsigned bind = 0
+ ) {
+ struct pipe_resource templat;
+
+ /* We can't really display surfaces with the python statetracker so mask
+ * out that usage */
+ bind &= ~PIPE_BIND_DISPLAY_TARGET;
+
+ memset(&templat, 0, sizeof(templat));
+ templat.format = format;
+ templat.width0 = width;
+ templat.height0 = height;
+ templat.depth0 = depth;
+ templat.last_level = last_level;
+ templat.target = target;
+ templat.bind = bind;
+
+ return $self->screen->resource_create($self->screen, &templat);
+ }
+
+ struct pipe_resource *
+ buffer_create(unsigned size, unsigned bind = 0) {
+ return pipe_buffer_create($self->screen, bind, size);
+ }
+};
diff --git a/src/gallium/state_trackers/python/p_state.i b/src/gallium/state_trackers/python/p_state.i
new file mode 100644
index 0000000000..c1e6ea1b43
--- /dev/null
+++ b/src/gallium/state_trackers/python/p_state.i
@@ -0,0 +1,184 @@
+ /**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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.
+ *
+ **************************************************************************/
+
+/**
+ * @file
+ * SWIG interface definion for Gallium types.
+ *
+ * @author Jose Fonseca <jrfonseca@tungstengraphics.com>
+ */
+
+%module gallium;
+
+%ignore winsys;
+%ignore pipe_vertex_buffer::buffer;
+
+%include "pipe/p_compiler.h";
+%include "pipe/p_state.h";
+
+
+%array_class(struct pipe_stencil_state, StencilArray);
+
+
+%extend pipe_rt_blend_state
+{
+ struct pipe_rt_blend_state *
+ __getitem__(int index)
+ {
+ if(index < 0 || index >= PIPE_MAX_COLOR_BUFS)
+ SWIG_exception(SWIG_ValueError, "index out of bounds");
+ return $self + index;
+ fail:
+ return NULL;
+ };
+};
+
+
+%extend pipe_blend_state
+{
+ pipe_blend_state(void)
+ {
+ return CALLOC_STRUCT(pipe_blend_state);
+ }
+
+ %cstring_input_binary(const char *STRING, unsigned LENGTH);
+ pipe_blend_state(const char *STRING, unsigned LENGTH)
+ {
+ struct pipe_blend_state *state;
+ state = CALLOC_STRUCT(pipe_blend_state);
+ if (state) {
+ LENGTH = MIN2(sizeof *state, LENGTH);
+ memcpy(state, STRING, LENGTH);
+ }
+ return state;
+ }
+
+ %cstring_output_allocate_size(char **STRING, int *LENGTH, os_free(*$1));
+ void __str__(char **STRING, int *LENGTH)
+ {
+ struct os_stream *stream;
+
+ stream = os_str_stream_create(1);
+ util_dump_blend_state(stream, $self);
+
+ *STRING = os_str_stream_get_and_close(stream);
+ *LENGTH = strlen(*STRING);
+ }
+};
+
+
+%extend pipe_framebuffer_state {
+
+ pipe_framebuffer_state(void) {
+ return CALLOC_STRUCT(pipe_framebuffer_state);
+ }
+
+ ~pipe_framebuffer_state() {
+ unsigned index;
+ for(index = 0; index < PIPE_MAX_COLOR_BUFS; ++index)
+ pipe_surface_reference(&$self->cbufs[index], NULL);
+ pipe_surface_reference(&$self->zsbuf, NULL);
+ FREE($self);
+ }
+
+ void
+ set_cbuf(unsigned index, struct st_surface *surface)
+ {
+ struct pipe_surface *_surface = NULL;
+
+ if(index >= PIPE_MAX_COLOR_BUFS)
+ SWIG_exception(SWIG_ValueError, "index out of bounds");
+
+ if(surface) {
+ _surface = st_pipe_surface(surface, PIPE_BIND_RENDER_TARGET);
+ if(!_surface)
+ SWIG_exception(SWIG_ValueError, "couldn't acquire surface for writing");
+ }
+
+ pipe_surface_reference(&$self->cbufs[index], _surface);
+
+ fail:
+ return;
+ }
+
+ void
+ set_zsbuf(struct st_surface *surface)
+ {
+ struct pipe_surface *_surface = NULL;
+
+ if(surface) {
+ _surface = st_pipe_surface(surface, PIPE_BIND_DEPTH_STENCIL);
+ if(!_surface)
+ SWIG_exception(SWIG_ValueError, "couldn't acquire surface for writing");
+ }
+
+ pipe_surface_reference(&$self->zsbuf, _surface);
+
+ fail:
+ return;
+ }
+
+};
+
+
+%extend pipe_shader_state {
+
+ pipe_shader_state(const char *text, unsigned num_tokens = 1024) {
+ struct tgsi_token *tokens;
+ struct pipe_shader_state *shader;
+
+ tokens = MALLOC(num_tokens * sizeof(struct tgsi_token));
+ if(!tokens)
+ goto error1;
+
+ if(tgsi_text_translate(text, tokens, num_tokens ) != TRUE)
+ goto error2;
+
+ shader = CALLOC_STRUCT(pipe_shader_state);
+ if(!shader)
+ goto error3;
+
+ shader->tokens = tokens;
+
+ return shader;
+
+error3:
+error2:
+ FREE(tokens);
+error1:
+ return NULL;
+ }
+
+ ~pipe_shader_state() {
+ FREE((void*)$self->tokens);
+ FREE($self);
+ }
+
+ void dump(unsigned flags = 0) {
+ tgsi_dump($self->tokens, flags);
+ }
+}
diff --git a/src/gallium/state_trackers/python/p_texture.i b/src/gallium/state_trackers/python/p_texture.i
new file mode 100644
index 0000000000..ae506944c4
--- /dev/null
+++ b/src/gallium/state_trackers/python/p_texture.i
@@ -0,0 +1,156 @@
+ /**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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.
+ *
+ **************************************************************************/
+
+/**
+ * @file
+ * SWIG interface definion for Gallium types.
+ *
+ * @author Jose Fonseca <jrfonseca@tungstengraphics.com>
+ */
+
+
+%nodefaultctor pipe_resource;
+%nodefaultctor st_surface;
+
+%nodefaultdtor pipe_resource;
+%nodefaultdtor st_surface;
+
+%ignore pipe_resource::screen;
+
+%immutable st_surface::texture;
+%immutable st_surface::face;
+%immutable st_surface::level;
+%immutable st_surface::zslice;
+
+%newobject pipe_resource::get_surface;
+
+/* Avoid naming conflict with p_inlines.h's pipe_buffer_read/write */
+%rename(read) read_;
+%rename(write) write_;
+
+%extend pipe_resource {
+
+ ~pipe_resource() {
+ struct pipe_resource *ptr = $self;
+ pipe_resource_reference(&ptr, NULL);
+ }
+
+ unsigned get_width(unsigned level=0) {
+ return u_minify($self->width0, level);
+ }
+
+ unsigned get_height(unsigned level=0) {
+ return u_minify($self->height0, level);
+ }
+
+ unsigned get_depth(unsigned level=0) {
+ return u_minify($self->depth0, level);
+ }
+
+ /** Get a surface which is a "view" into a texture */
+ struct st_surface *
+ get_surface(unsigned face=0, unsigned level=0, unsigned zslice=0)
+ {
+ struct st_surface *surface;
+
+ if(face >= ($self->target == PIPE_TEXTURE_CUBE ? 6U : 1U))
+ SWIG_exception(SWIG_ValueError, "face out of bounds");
+ if(level > $self->last_level)
+ SWIG_exception(SWIG_ValueError, "level out of bounds");
+ if(zslice >= u_minify($self->depth0, level))
+ SWIG_exception(SWIG_ValueError, "zslice out of bounds");
+
+ surface = CALLOC_STRUCT(st_surface);
+ if(!surface)
+ return NULL;
+
+ pipe_resource_reference(&surface->texture, $self);
+ surface->face = face;
+ surface->level = level;
+ surface->zslice = zslice;
+
+ return surface;
+
+ fail:
+ return NULL;
+ }
+
+ unsigned __len__(void)
+ {
+ assert($self->target == PIPE_BUFFER);
+ assert(p_atomic_read(&$self->reference.count) > 0);
+ return $self->width0;
+ }
+
+};
+
+struct st_surface
+{
+ %immutable;
+
+ struct pipe_resource *texture;
+ unsigned face;
+ unsigned level;
+ unsigned zslice;
+
+};
+
+%extend st_surface {
+
+ %immutable;
+
+ unsigned format;
+ unsigned width;
+ unsigned height;
+
+ ~st_surface() {
+ pipe_resource_reference(&$self->texture, NULL);
+ FREE($self);
+ }
+
+
+};
+
+%{
+ static enum pipe_format
+ st_surface_format_get(struct st_surface *surface)
+ {
+ return surface->texture->format;
+ }
+
+ static unsigned
+ st_surface_width_get(struct st_surface *surface)
+ {
+ return u_minify(surface->texture->width0, surface->level);
+ }
+
+ static unsigned
+ st_surface_height_get(struct st_surface *surface)
+ {
+ return u_minify(surface->texture->height0, surface->level);
+ }
+%}
diff --git a/src/gallium/state_trackers/python/st_device.c b/src/gallium/state_trackers/python/st_device.c
new file mode 100644
index 0000000000..dce24bc17d
--- /dev/null
+++ b/src/gallium/state_trackers/python/st_device.c
@@ -0,0 +1,305 @@
+/**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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 "pipe/p_screen.h"
+#include "pipe/p_context.h"
+#include "pipe/p_shader_tokens.h"
+#include "util/u_inlines.h"
+#include "cso_cache/cso_context.h"
+#include "util/u_inlines.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+#include "util/u_sampler.h"
+#include "util/u_simple_shaders.h"
+#include "trace/tr_public.h"
+
+#include "st_device.h"
+#include "st_winsys.h"
+
+
+static void
+st_device_really_destroy(struct st_device *st_dev)
+{
+ if(st_dev->screen) {
+ /* FIXME: Don't really destroy until we keep track of every single
+ * reference or we end up causing a segmentation fault every time
+ * python exits. */
+#if 0
+ st_dev->screen->destroy(st_dev->screen);
+#endif
+ }
+
+ FREE(st_dev);
+}
+
+
+static void
+st_device_reference(struct st_device **ptr, struct st_device *st_dev)
+{
+ struct st_device *old_dev = *ptr;
+
+ if (pipe_reference(&(*ptr)->reference, &st_dev->reference))
+ st_device_really_destroy(old_dev);
+ *ptr = st_dev;
+}
+
+
+void
+st_device_destroy(struct st_device *st_dev)
+{
+ st_device_reference(&st_dev, NULL);
+}
+
+
+struct st_device *
+st_device_create(boolean hardware)
+{
+ struct pipe_screen *screen;
+ struct st_device *st_dev;
+
+ if (hardware)
+ screen = st_hardware_screen_create();
+ else
+ screen = st_software_screen_create("softpipe");
+
+ screen = trace_screen_create(screen);
+ if (!screen)
+ goto no_screen;
+
+ st_dev = CALLOC_STRUCT(st_device);
+ if (!st_dev)
+ goto no_device;
+
+ pipe_reference_init(&st_dev->reference, 1);
+ st_dev->screen = screen;
+
+ return st_dev;
+
+no_device:
+ screen->destroy(screen);
+no_screen:
+ return NULL;
+}
+
+
+void
+st_context_destroy(struct st_context *st_ctx)
+{
+ unsigned i;
+
+ if(st_ctx) {
+ struct st_device *st_dev = st_ctx->st_dev;
+
+ if(st_ctx->cso) {
+ cso_delete_vertex_shader(st_ctx->cso, st_ctx->vs);
+ cso_delete_fragment_shader(st_ctx->cso, st_ctx->fs);
+
+ cso_destroy_context(st_ctx->cso);
+ }
+
+ if(st_ctx->pipe)
+ st_ctx->pipe->destroy(st_ctx->pipe);
+
+ for(i = 0; i < PIPE_MAX_SAMPLERS; ++i)
+ pipe_sampler_view_reference(&st_ctx->fragment_sampler_views[i], NULL);
+ for(i = 0; i < PIPE_MAX_VERTEX_SAMPLERS; ++i)
+ pipe_sampler_view_reference(&st_ctx->vertex_sampler_views[i], NULL);
+ pipe_resource_reference(&st_ctx->default_texture, NULL);
+
+ FREE(st_ctx);
+
+ st_device_reference(&st_dev, NULL);
+ }
+}
+
+
+struct st_context *
+st_context_create(struct st_device *st_dev)
+{
+ struct st_context *st_ctx;
+
+ st_ctx = CALLOC_STRUCT(st_context);
+ if(!st_ctx)
+ return NULL;
+
+ st_device_reference(&st_ctx->st_dev, st_dev);
+
+ st_ctx->pipe = st_dev->screen->context_create(st_dev->screen, NULL);
+ if(!st_ctx->pipe) {
+ st_context_destroy(st_ctx);
+ return NULL;
+ }
+
+ st_ctx->cso = cso_create_context(st_ctx->pipe);
+ if(!st_ctx->cso) {
+ st_context_destroy(st_ctx);
+ return NULL;
+ }
+
+ /* disabled blending/masking */
+ {
+ struct pipe_blend_state blend;
+ memset(&blend, 0, sizeof(blend));
+ blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ blend.rt[0].colormask = PIPE_MASK_RGBA;
+ cso_set_blend(st_ctx->cso, &blend);
+ }
+
+ /* no-op depth/stencil/alpha */
+ {
+ struct pipe_depth_stencil_alpha_state depthstencil;
+ memset(&depthstencil, 0, sizeof(depthstencil));
+ cso_set_depth_stencil_alpha(st_ctx->cso, &depthstencil);
+ }
+
+ /* rasterizer */
+ {
+ struct pipe_rasterizer_state rasterizer;
+ memset(&rasterizer, 0, sizeof(rasterizer));
+ rasterizer.cull_face = PIPE_FACE_NONE;
+ cso_set_rasterizer(st_ctx->cso, &rasterizer);
+ }
+
+ /* clip */
+ {
+ struct pipe_clip_state clip;
+ memset(&clip, 0, sizeof(clip));
+ st_ctx->pipe->set_clip_state(st_ctx->pipe, &clip);
+ }
+
+ /* identity viewport */
+ {
+ struct pipe_viewport_state viewport;
+ viewport.scale[0] = 1.0;
+ viewport.scale[1] = 1.0;
+ viewport.scale[2] = 1.0;
+ viewport.scale[3] = 1.0;
+ viewport.translate[0] = 0.0;
+ viewport.translate[1] = 0.0;
+ viewport.translate[2] = 0.0;
+ viewport.translate[3] = 0.0;
+ cso_set_viewport(st_ctx->cso, &viewport);
+ }
+
+ /* samplers */
+ {
+ struct pipe_sampler_state sampler;
+ unsigned i;
+ 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_NEAREST;
+ sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
+ sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
+ sampler.normalized_coords = 1;
+ for (i = 0; i < PIPE_MAX_SAMPLERS; i++)
+ cso_single_sampler(st_ctx->cso, i, &sampler);
+ cso_single_sampler_done(st_ctx->cso);
+ }
+
+ /* default textures */
+ {
+ struct pipe_context *pipe = st_ctx->pipe;
+ struct pipe_screen *screen = st_dev->screen;
+ struct pipe_resource templat;
+ struct pipe_sampler_view view_templ;
+ struct pipe_sampler_view *view;
+ unsigned i;
+
+ memset( &templat, 0, sizeof( templat ) );
+ templat.target = PIPE_TEXTURE_2D;
+ templat.format = PIPE_FORMAT_B8G8R8A8_UNORM;
+ templat.width0 = 1;
+ templat.height0 = 1;
+ templat.depth0 = 1;
+ templat.last_level = 0;
+ templat.bind = PIPE_BIND_SAMPLER_VIEW;
+
+ st_ctx->default_texture = screen->resource_create( screen, &templat );
+ if(st_ctx->default_texture) {
+ struct pipe_box box;
+ uint32_t zero = 0;
+
+ u_box_origin_2d( 1, 1, &box );
+
+ pipe->transfer_inline_write(pipe,
+ st_ctx->default_texture,
+ u_subresource(0,0),
+ PIPE_TRANSFER_WRITE,
+ &box,
+ &zero,
+ sizeof zero,
+ 0);
+ }
+
+ u_sampler_view_default_template(&view_templ,
+ st_ctx->default_texture,
+ st_ctx->default_texture->format);
+ view = st_ctx->pipe->create_sampler_view(st_ctx->pipe,
+ st_ctx->default_texture,
+ &view_templ);
+
+ for (i = 0; i < PIPE_MAX_SAMPLERS; i++)
+ pipe_sampler_view_reference(&st_ctx->fragment_sampler_views[i], view);
+ for (i = 0; i < PIPE_MAX_VERTEX_SAMPLERS; i++)
+ pipe_sampler_view_reference(&st_ctx->vertex_sampler_views[i], view);
+
+ st_ctx->pipe->set_fragment_sampler_views(st_ctx->pipe,
+ PIPE_MAX_SAMPLERS,
+ st_ctx->fragment_sampler_views);
+ st_ctx->pipe->set_vertex_sampler_views(st_ctx->pipe,
+ PIPE_MAX_VERTEX_SAMPLERS,
+ st_ctx->vertex_sampler_views);
+
+ pipe_sampler_view_reference(&view, NULL);
+ }
+
+ /* vertex shader */
+ {
+ const uint semantic_names[] = { TGSI_SEMANTIC_POSITION,
+ TGSI_SEMANTIC_GENERIC };
+ const uint semantic_indexes[] = { 0, 0 };
+ st_ctx->vs = util_make_vertex_passthrough_shader(st_ctx->pipe,
+ 2,
+ semantic_names,
+ semantic_indexes);
+ cso_set_vertex_shader_handle(st_ctx->cso, st_ctx->vs);
+ }
+
+ /* fragment shader */
+ {
+ st_ctx->fs = util_make_fragment_passthrough_shader(st_ctx->pipe);
+ cso_set_fragment_shader_handle(st_ctx->cso, st_ctx->fs);
+ }
+
+ return st_ctx;
+}
diff --git a/src/gallium/state_trackers/python/st_device.h b/src/gallium/state_trackers/python/st_device.h
new file mode 100644
index 0000000000..2dca7a1974
--- /dev/null
+++ b/src/gallium/state_trackers/python/st_device.h
@@ -0,0 +1,106 @@
+/**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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 ST_DEVICE_H_
+#define ST_DEVICE_H_
+
+
+#include "pipe/p_state.h"
+
+struct cso_context;
+struct pipe_screen;
+struct pipe_context;
+struct st_winsys;
+
+
+struct st_surface
+{
+ struct pipe_resource *texture;
+ unsigned face;
+ unsigned level;
+ unsigned zslice;
+};
+
+
+struct st_context
+{
+ struct st_device *st_dev;
+
+ struct pipe_context *pipe;
+
+ struct cso_context *cso;
+
+ void *vs;
+ void *fs;
+ void *gs;
+
+ struct pipe_resource *default_texture;
+ struct pipe_sampler_view *fragment_sampler_views[PIPE_MAX_SAMPLERS];
+ struct pipe_sampler_view *vertex_sampler_views[PIPE_MAX_VERTEX_SAMPLERS];
+
+ unsigned num_vertex_buffers;
+ struct pipe_vertex_buffer vertex_buffers[PIPE_MAX_ATTRIBS];
+
+ unsigned num_vertex_elements;
+ struct pipe_vertex_element vertex_elements[PIPE_MAX_ATTRIBS];
+
+ struct pipe_framebuffer_state framebuffer;
+};
+
+
+struct st_device
+{
+ /* FIXME: we also need to refcount for textures and surfaces... */
+ struct pipe_reference reference;
+
+ struct pipe_screen *screen;
+};
+
+
+static INLINE struct pipe_surface *
+st_pipe_surface(struct st_surface *surface, unsigned usage)
+{
+ struct pipe_resource *texture = surface->texture;
+ struct pipe_screen *screen = texture->screen;
+ return screen->get_tex_surface(screen, texture, surface->face, surface->level, surface->zslice, usage);
+}
+
+struct st_context *
+st_context_create(struct st_device *st_dev);
+
+void
+st_context_destroy(struct st_context *st_ctx);
+
+struct st_device *
+st_device_create(boolean hardware);
+
+void
+st_device_destroy(struct st_device *st_dev);
+
+
+#endif /* ST_DEVICE_H_ */
diff --git a/src/gallium/state_trackers/python/st_hardpipe_winsys.c b/src/gallium/state_trackers/python/st_hardpipe_winsys.c
new file mode 100644
index 0000000000..c6743dbd9c
--- /dev/null
+++ b/src/gallium/state_trackers/python/st_hardpipe_winsys.c
@@ -0,0 +1,212 @@
+/**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Bismarck, ND., USA
+ * 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 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
+ * THE COPYRIGHT HOLDERS, AUTHORS 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.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ *
+ **************************************************************************/
+
+/**
+ * @file
+ * Get a hardware accelerated Gallium screen/context from the OpenGL driver.
+ */
+
+
+#include "pipe/p_compiler.h"
+
+#ifdef PIPE_OS_WINDOWS
+#include <windows.h>
+#include <GL/gl.h>
+#else
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+#endif
+
+#include "st_winsys.h"
+
+
+typedef struct pipe_screen * (GLAPIENTRY *PFNGETGALLIUMSCREENMESAPROC) (void);
+typedef struct pipe_context * (GLAPIENTRY* PFNCREATEGALLIUMCONTEXTMESAPROC) (void);
+
+static PFNGETGALLIUMSCREENMESAPROC pfnGetGalliumScreenMESA = NULL;
+static PFNCREATEGALLIUMCONTEXTMESAPROC pfnCreateGalliumContextMESA = NULL;
+
+
+#ifdef PIPE_OS_WINDOWS
+
+static INLINE boolean
+st_hardpipe_load(void)
+{
+ WNDCLASS wc;
+ HWND hwnd;
+ HGLRC hglrc;
+ HDC hdc;
+ PIXELFORMATDESCRIPTOR pfd;
+ int iPixelFormat;
+
+ if(pfnGetGalliumScreenMESA && pfnCreateGalliumContextMESA)
+ return TRUE;
+
+ memset(&wc, 0, sizeof wc);
+ wc.lpfnWndProc = DefWindowProc;
+ wc.lpszClassName = "gallium";
+ wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
+ RegisterClass(&wc);
+
+ hwnd = CreateWindow(wc.lpszClassName, "gallium", 0, 0, 0, 0, 0, NULL, 0, wc.hInstance, NULL);
+ if (!hwnd)
+ return FALSE;
+
+ hdc = GetDC(hwnd);
+ if (!hdc)
+ return FALSE;
+
+ pfd.cColorBits = 3;
+ pfd.cRedBits = 1;
+ pfd.cGreenBits = 1;
+ pfd.cBlueBits = 1;
+ pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
+ pfd.iLayerType = PFD_MAIN_PLANE;
+ pfd.iPixelType = PFD_TYPE_RGBA;
+ pfd.nSize = sizeof(pfd);
+ pfd.nVersion = 1;
+
+ iPixelFormat = ChoosePixelFormat(hdc, &pfd);
+ if (!iPixelFormat) {
+ pfd.dwFlags |= PFD_DOUBLEBUFFER;
+ iPixelFormat = ChoosePixelFormat(hdc, &pfd);
+ }
+ if (!iPixelFormat)
+ return FALSE;
+
+ SetPixelFormat(hdc, iPixelFormat, &pfd);
+ hglrc = wglCreateContext(hdc);
+ if (!hglrc)
+ return FALSE;
+
+ if (!wglMakeCurrent(hdc, hglrc))
+ return FALSE;
+
+ pfnGetGalliumScreenMESA = (PFNGETGALLIUMSCREENMESAPROC)wglGetProcAddress("wglGetGalliumScreenMESA");
+ if(!pfnGetGalliumScreenMESA)
+ return FALSE;
+
+ pfnCreateGalliumContextMESA = (PFNCREATEGALLIUMCONTEXTMESAPROC)wglGetProcAddress("wglCreateGalliumContextMESA");
+ if(!pfnCreateGalliumContextMESA)
+ return FALSE;
+
+ DestroyWindow(hwnd);
+
+ return TRUE;
+}
+
+#else
+
+static INLINE boolean
+st_hardpipe_load(void)
+{
+ Display *dpy;
+ int scrnum;
+ Window root;
+ int attribSingle[] = {
+ GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ None };
+ int attribDouble[] = {
+ GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None };
+ XVisualInfo *visinfo;
+ GLXContext ctx = NULL;
+ XSetWindowAttributes attr;
+ unsigned long mask;
+ int width = 100, height = 100;
+ Window win;
+
+ dpy = XOpenDisplay(NULL);
+ if (!dpy)
+ return FALSE;
+
+ scrnum = 0;
+
+ root = RootWindow(dpy, scrnum);
+
+ visinfo = glXChooseVisual(dpy, scrnum, attribSingle);
+ if (!visinfo)
+ visinfo = glXChooseVisual(dpy, scrnum, attribDouble);
+ if (!visinfo)
+ return FALSE;
+
+ ctx = glXCreateContext( dpy, visinfo, NULL, True );
+
+ if (!ctx)
+ return FALSE;
+
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask | ExposureMask;
+
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+ win = XCreateWindow(dpy, root, 0, 0, width, height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr);
+
+ if (!glXMakeCurrent(dpy, win, ctx))
+ return FALSE;
+
+ pfnGetGalliumScreenMESA = (PFNGETGALLIUMSCREENMESAPROC)glXGetProcAddressARB((const GLubyte *)"glXGetGalliumScreenMESA");
+ if(!pfnGetGalliumScreenMESA)
+ return FALSE;
+
+ pfnCreateGalliumContextMESA = (PFNCREATEGALLIUMCONTEXTMESAPROC)glXGetProcAddressARB((const GLubyte *)"glXCreateGalliumContextMESA");
+ if(!pfnCreateGalliumContextMESA)
+ return FALSE;
+
+ glXDestroyContext(dpy, ctx);
+ XFree(visinfo);
+ XDestroyWindow(dpy, win);
+ XCloseDisplay(dpy);
+
+ return TRUE;
+}
+
+#endif
+
+
+struct pipe_screen *
+st_hardware_screen_create(void)
+{
+ if(st_hardpipe_load())
+ return pfnGetGalliumScreenMESA();
+ else
+ return st_software_screen_create(NULL);
+}
diff --git a/src/gallium/state_trackers/python/st_sample.c b/src/gallium/state_trackers/python/st_sample.c
new file mode 100644
index 0000000000..25bfbf1ab7
--- /dev/null
+++ b/src/gallium/state_trackers/python/st_sample.c
@@ -0,0 +1,595 @@
+/**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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 "pipe/p_compiler.h"
+#include "pipe/p_format.h"
+#include "pipe/p_state.h"
+#include "util/u_inlines.h"
+#include "util/u_format.h"
+#include "util/u_tile.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+
+#include "st_device.h"
+#include "st_sample.h"
+
+
+/**
+ * Use our own pseudo random generator to ensure consistent runs among
+ * multiple runs and platforms.
+ *
+ * @sa http://en.wikipedia.org/wiki/Linear_congruential_generator
+ */
+static uint32_t st_random(void) {
+ static uint64_t seed = UINT64_C(0xbb9a063afb0a739d);
+
+ seed = UINT64_C(134775813) * seed + UINT64_C(1);
+
+ return (uint32_t)(seed >> 32);
+}
+
+
+/**
+ * We don't want to include the patent-encumbered DXT code here, so instead
+ * we store several uncompressed/compressed data pairs for hardware testing
+ * purposes.
+ */
+struct dxt_data
+{
+ uint8_t rgba[16*4];
+ uint8_t raw[16];
+};
+
+
+static const struct dxt_data
+dxt1_rgb_data[] = {
+ {
+ {
+ 0x99, 0xb0, 0x8e, 0xff,
+ 0x5d, 0x62, 0x89, 0xff,
+ 0x99, 0xb0, 0x8e, 0xff,
+ 0x99, 0xb0, 0x8e, 0xff,
+ 0xd6, 0xff, 0x94, 0xff,
+ 0x5d, 0x62, 0x89, 0xff,
+ 0x99, 0xb0, 0x8e, 0xff,
+ 0xd6, 0xff, 0x94, 0xff,
+ 0x5d, 0x62, 0x89, 0xff,
+ 0x5d, 0x62, 0x89, 0xff,
+ 0x99, 0xb0, 0x8e, 0xff,
+ 0x21, 0x14, 0x84, 0xff,
+ 0x5d, 0x62, 0x89, 0xff,
+ 0x21, 0x14, 0x84, 0xff,
+ 0x21, 0x14, 0x84, 0xff,
+ 0x99, 0xb0, 0x8e, 0xff
+ },
+ {0xf2, 0xd7, 0xb0, 0x20, 0xae, 0x2c, 0x6f, 0x97}
+ },
+ {
+ {
+ 0xb5, 0xcf, 0x9c, 0xff,
+ 0x83, 0x8c, 0x8b, 0xff,
+ 0x21, 0x08, 0x6b, 0xff,
+ 0x83, 0x8c, 0x8b, 0xff,
+ 0x52, 0x4a, 0x7b, 0xff,
+ 0x83, 0x8c, 0x8b, 0xff,
+ 0x83, 0x8c, 0x8b, 0xff,
+ 0xb5, 0xcf, 0x9c, 0xff,
+ 0x21, 0x08, 0x6b, 0xff,
+ 0xb5, 0xcf, 0x9c, 0xff,
+ 0x83, 0x8c, 0x8b, 0xff,
+ 0x52, 0x4a, 0x7b, 0xff,
+ 0xb5, 0xcf, 0x9c, 0xff,
+ 0x83, 0x8c, 0x8b, 0xff,
+ 0x52, 0x4a, 0x7b, 0xff,
+ 0x83, 0x8c, 0x8b, 0xff
+ },
+ {0x73, 0xb6, 0x4d, 0x20, 0x98, 0x2b, 0xe1, 0xb8}
+ },
+ {
+ {
+ 0x00, 0x2c, 0xff, 0xff,
+ 0x94, 0x8d, 0x7b, 0xff,
+ 0x4a, 0x5c, 0xbd, 0xff,
+ 0x4a, 0x5c, 0xbd, 0xff,
+ 0x4a, 0x5c, 0xbd, 0xff,
+ 0x94, 0x8d, 0x7b, 0xff,
+ 0x94, 0x8d, 0x7b, 0xff,
+ 0x94, 0x8d, 0x7b, 0xff,
+ 0xde, 0xbe, 0x39, 0xff,
+ 0x94, 0x8d, 0x7b, 0xff,
+ 0xde, 0xbe, 0x39, 0xff,
+ 0xde, 0xbe, 0x39, 0xff,
+ 0xde, 0xbe, 0x39, 0xff,
+ 0xde, 0xbe, 0x39, 0xff,
+ 0xde, 0xbe, 0x39, 0xff,
+ 0x94, 0x8d, 0x7b, 0xff
+ },
+ {0xe7, 0xdd, 0x7f, 0x01, 0xf9, 0xab, 0x08, 0x80}
+ },
+ {
+ {
+ 0x6b, 0x24, 0x21, 0xff,
+ 0x7b, 0x4f, 0x5d, 0xff,
+ 0x7b, 0x4f, 0x5d, 0xff,
+ 0x8b, 0x7a, 0x99, 0xff,
+ 0x7b, 0x4f, 0x5d, 0xff,
+ 0x7b, 0x4f, 0x5d, 0xff,
+ 0x6b, 0x24, 0x21, 0xff,
+ 0x8b, 0x7a, 0x99, 0xff,
+ 0x9c, 0xa6, 0xd6, 0xff,
+ 0x6b, 0x24, 0x21, 0xff,
+ 0x7b, 0x4f, 0x5d, 0xff,
+ 0x8b, 0x7a, 0x99, 0xff,
+ 0x6b, 0x24, 0x21, 0xff,
+ 0x8b, 0x7a, 0x99, 0xff,
+ 0x7b, 0x4f, 0x5d, 0xff,
+ 0x9c, 0xa6, 0xd6, 0xff
+ },
+ {0x3a, 0x9d, 0x24, 0x69, 0xbd, 0x9f, 0xb4, 0x39}
+ }
+};
+
+
+static const struct dxt_data
+dxt1_rgba_data[] = {
+ {
+ {
+ 0x00, 0x00, 0x00, 0x00,
+ 0x4e, 0xaa, 0x90, 0xff,
+ 0x4e, 0xaa, 0x90, 0xff,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x4e, 0xaa, 0x90, 0xff,
+ 0x29, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x4e, 0xaa, 0x90, 0xff,
+ 0x73, 0x55, 0x21, 0xff,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x4e, 0xaa, 0x90, 0xff,
+ 0x4e, 0xaa, 0x90, 0xff,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x4e, 0xaa, 0x90, 0xff
+ },
+ {0xff, 0x2f, 0xa4, 0x72, 0xeb, 0xb2, 0xbd, 0xbe}
+ },
+ {
+ {
+ 0xb5, 0xe3, 0x63, 0xff,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x6b, 0x24, 0x84, 0xff,
+ 0xb5, 0xe3, 0x63, 0xff,
+ 0x00, 0x00, 0x00, 0x00,
+ 0xb5, 0xe3, 0x63, 0xff,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x6b, 0x24, 0x84, 0xff,
+ 0x6b, 0x24, 0x84, 0xff,
+ 0x00, 0x00, 0x00, 0x00,
+ 0xb5, 0xe3, 0x63, 0xff,
+ 0x90, 0x83, 0x73, 0xff,
+ 0xb5, 0xe3, 0x63, 0xff
+ },
+ {0x30, 0x69, 0x0c, 0xb7, 0x4d, 0xf7, 0x0f, 0x67}
+ },
+ {
+ {
+ 0x00, 0x00, 0x00, 0x00,
+ 0xc6, 0x86, 0x8c, 0xff,
+ 0xc6, 0x86, 0x8c, 0xff,
+ 0x21, 0x65, 0x42, 0xff,
+ 0x21, 0x65, 0x42, 0xff,
+ 0x21, 0x65, 0x42, 0xff,
+ 0x21, 0x65, 0x42, 0xff,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x21, 0x65, 0x42, 0xff,
+ 0xc6, 0x86, 0x8c, 0xff,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0xc6, 0x86, 0x8c, 0xff
+ },
+ {0x28, 0x23, 0x31, 0xc4, 0x17, 0xc0, 0xd3, 0x7f}
+ },
+ {
+ {
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0xc6, 0xe3, 0x9c, 0xff,
+ 0x7b, 0x1c, 0x52, 0xff,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x7b, 0x1c, 0x52, 0xff,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x7b, 0x1c, 0x52, 0xff,
+ 0xa0, 0x7f, 0x77, 0xff,
+ 0xc6, 0xe3, 0x9c, 0xff,
+ 0x00, 0x00, 0x00, 0x00,
+ 0xa0, 0x7f, 0x77, 0xff
+ },
+ {0xea, 0x78, 0x13, 0xc7, 0x7f, 0xfc, 0x33, 0xb6}
+ },
+};
+
+
+static const struct dxt_data
+dxt3_rgba_data[] = {
+ {
+ {
+ 0x6d, 0xc6, 0x96, 0x77,
+ 0x6d, 0xc6, 0x96, 0xee,
+ 0x6d, 0xc6, 0x96, 0xaa,
+ 0x8c, 0xff, 0xb5, 0x44,
+ 0x6d, 0xc6, 0x96, 0xff,
+ 0x6d, 0xc6, 0x96, 0x88,
+ 0x31, 0x55, 0x5a, 0x66,
+ 0x6d, 0xc6, 0x96, 0x99,
+ 0x31, 0x55, 0x5a, 0xbb,
+ 0x31, 0x55, 0x5a, 0x55,
+ 0x31, 0x55, 0x5a, 0x11,
+ 0x6d, 0xc6, 0x96, 0xcc,
+ 0x6d, 0xc6, 0x96, 0xcc,
+ 0x6d, 0xc6, 0x96, 0x11,
+ 0x31, 0x55, 0x5a, 0x44,
+ 0x31, 0x55, 0x5a, 0x88
+ },
+ {0xe7, 0x4a, 0x8f, 0x96, 0x5b, 0xc1, 0x1c, 0x84, 0xf6, 0x8f, 0xab, 0x32, 0x2a, 0x9a, 0x95, 0x5a}
+ },
+ {
+ {
+ 0xad, 0xeb, 0x73, 0x99,
+ 0x97, 0xaa, 0x86, 0x66,
+ 0x6b, 0x28, 0xad, 0x99,
+ 0xad, 0xeb, 0x73, 0x99,
+ 0x6b, 0x28, 0xad, 0x22,
+ 0xad, 0xeb, 0x73, 0xff,
+ 0x97, 0xaa, 0x86, 0x55,
+ 0x6b, 0x28, 0xad, 0x55,
+ 0x6b, 0x28, 0xad, 0x44,
+ 0xad, 0xeb, 0x73, 0x33,
+ 0x6b, 0x28, 0xad, 0xee,
+ 0x6b, 0x28, 0xad, 0x99,
+ 0x97, 0xaa, 0x86, 0x66,
+ 0xad, 0xeb, 0x73, 0xbb,
+ 0x97, 0xaa, 0x86, 0x99,
+ 0xad, 0xeb, 0x73, 0xbb
+ },
+ {0x69, 0x99, 0xf2, 0x55, 0x34, 0x9e, 0xb6, 0xb9, 0x4e, 0xaf, 0x55, 0x69, 0x18, 0x61, 0x51, 0x22}
+ },
+ {
+ {
+ 0x63, 0xd7, 0xd6, 0x00,
+ 0x57, 0x62, 0x5d, 0xdd,
+ 0x57, 0x62, 0x5d, 0xcc,
+ 0x57, 0x62, 0x5d, 0xbb,
+ 0x52, 0x28, 0x21, 0xaa,
+ 0x57, 0x62, 0x5d, 0xcc,
+ 0x57, 0x62, 0x5d, 0xcc,
+ 0x57, 0x62, 0x5d, 0x66,
+ 0x57, 0x62, 0x5d, 0x22,
+ 0x57, 0x62, 0x5d, 0xdd,
+ 0x63, 0xd7, 0xd6, 0xee,
+ 0x57, 0x62, 0x5d, 0x33,
+ 0x63, 0xd7, 0xd6, 0x55,
+ 0x52, 0x28, 0x21, 0x55,
+ 0x57, 0x62, 0x5d, 0x11,
+ 0x5d, 0x9c, 0x99, 0xee
+ },
+ {0xd0, 0xbc, 0xca, 0x6c, 0xd2, 0x3e, 0x55, 0xe1, 0xba, 0x66, 0x44, 0x51, 0xfc, 0xfd, 0xcf, 0xb4}
+ },
+ {
+ {
+ 0x94, 0x6f, 0x60, 0x22,
+ 0x94, 0x6f, 0x60, 0x22,
+ 0xc5, 0xab, 0x76, 0x11,
+ 0xc5, 0xab, 0x76, 0xee,
+ 0x63, 0x34, 0x4a, 0xdd,
+ 0x63, 0x34, 0x4a, 0x33,
+ 0x94, 0x6f, 0x60, 0x77,
+ 0xf7, 0xe7, 0x8c, 0x00,
+ 0x94, 0x6f, 0x60, 0x33,
+ 0x63, 0x34, 0x4a, 0xaa,
+ 0x94, 0x6f, 0x60, 0x77,
+ 0x63, 0x34, 0x4a, 0xcc,
+ 0x94, 0x6f, 0x60, 0xaa,
+ 0xf7, 0xe7, 0x8c, 0x99,
+ 0x63, 0x34, 0x4a, 0x44,
+ 0xc5, 0xab, 0x76, 0xaa
+ },
+ {0x22, 0xe1, 0x3d, 0x07, 0xa3, 0xc7, 0x9a, 0xa4, 0x31, 0xf7, 0xa9, 0x61, 0xaf, 0x35, 0x77, 0x93}
+ },
+};
+
+
+static const struct dxt_data
+dxt5_rgba_data[] = {
+ {
+ {
+ 0x6d, 0xc6, 0x96, 0x74,
+ 0x6d, 0xc6, 0x96, 0xf8,
+ 0x6d, 0xc6, 0x96, 0xb6,
+ 0x8c, 0xff, 0xb5, 0x53,
+ 0x6d, 0xc6, 0x96, 0xf8,
+ 0x6d, 0xc6, 0x96, 0x95,
+ 0x31, 0x55, 0x5a, 0x53,
+ 0x6d, 0xc6, 0x96, 0x95,
+ 0x31, 0x55, 0x5a, 0xb6,
+ 0x31, 0x55, 0x5a, 0x53,
+ 0x31, 0x55, 0x5a, 0x11,
+ 0x6d, 0xc6, 0x96, 0xd7,
+ 0x6d, 0xc6, 0x96, 0xb6,
+ 0x6d, 0xc6, 0x96, 0x11,
+ 0x31, 0x55, 0x5a, 0x32,
+ 0x31, 0x55, 0x5a, 0x95
+ },
+ {0xf8, 0x11, 0xc5, 0x0c, 0x9a, 0x73, 0xb4, 0x9c, 0xf6, 0x8f, 0xab, 0x32, 0x2a, 0x9a, 0x95, 0x5a}
+ },
+ {
+ {
+ 0xad, 0xeb, 0x73, 0xa1,
+ 0x97, 0xaa, 0x86, 0x65,
+ 0x6b, 0x28, 0xad, 0xa1,
+ 0xad, 0xeb, 0x73, 0xa1,
+ 0x6b, 0x28, 0xad, 0x2a,
+ 0xad, 0xeb, 0x73, 0xfb,
+ 0x97, 0xaa, 0x86, 0x47,
+ 0x6b, 0x28, 0xad, 0x65,
+ 0x6b, 0x28, 0xad, 0x47,
+ 0xad, 0xeb, 0x73, 0x47,
+ 0x6b, 0x28, 0xad, 0xdd,
+ 0x6b, 0x28, 0xad, 0xa1,
+ 0x97, 0xaa, 0x86, 0x65,
+ 0xad, 0xeb, 0x73, 0xbf,
+ 0x97, 0xaa, 0x86, 0xa1,
+ 0xad, 0xeb, 0x73, 0xbf
+ },
+ {0xfb, 0x2a, 0x34, 0x19, 0xdc, 0xbf, 0xe8, 0x71, 0x4e, 0xaf, 0x55, 0x69, 0x18, 0x61, 0x51, 0x22}
+ },
+ {
+ {
+ 0x63, 0xd7, 0xd6, 0x00,
+ 0x57, 0x62, 0x5d, 0xf5,
+ 0x57, 0x62, 0x5d, 0xd2,
+ 0x57, 0x62, 0x5d, 0xaf,
+ 0x52, 0x28, 0x21, 0xaf,
+ 0x57, 0x62, 0x5d, 0xd2,
+ 0x57, 0x62, 0x5d, 0xd2,
+ 0x57, 0x62, 0x5d, 0x69,
+ 0x57, 0x62, 0x5d, 0x23,
+ 0x57, 0x62, 0x5d, 0xd2,
+ 0x63, 0xd7, 0xd6, 0xf5,
+ 0x57, 0x62, 0x5d, 0x46,
+ 0x63, 0xd7, 0xd6, 0x46,
+ 0x52, 0x28, 0x21, 0x69,
+ 0x57, 0x62, 0x5d, 0x23,
+ 0x5d, 0x9c, 0x99, 0xf5
+ },
+ {0xf5, 0x00, 0x81, 0x36, 0xa9, 0x17, 0xec, 0x1e, 0xba, 0x66, 0x44, 0x51, 0xfc, 0xfd, 0xcf, 0xb4}
+ },
+ {
+ {
+ 0x94, 0x6f, 0x60, 0x25,
+ 0x94, 0x6f, 0x60, 0x25,
+ 0xc5, 0xab, 0x76, 0x05,
+ 0xc5, 0xab, 0x76, 0xe8,
+ 0x63, 0x34, 0x4a, 0xe8,
+ 0x63, 0x34, 0x4a, 0x25,
+ 0x94, 0x6f, 0x60, 0x86,
+ 0xf7, 0xe7, 0x8c, 0x05,
+ 0x94, 0x6f, 0x60, 0x25,
+ 0x63, 0x34, 0x4a, 0xa7,
+ 0x94, 0x6f, 0x60, 0x66,
+ 0x63, 0x34, 0x4a, 0xc7,
+ 0x94, 0x6f, 0x60, 0xa7,
+ 0xf7, 0xe7, 0x8c, 0xa7,
+ 0x63, 0x34, 0x4a, 0x45,
+ 0xc5, 0xab, 0x76, 0xa7
+ },
+ {0xe8, 0x05, 0x7f, 0x80, 0x33, 0x5f, 0xb5, 0x79, 0x31, 0xf7, 0xa9, 0x61, 0xaf, 0x35, 0x77, 0x93}
+ },
+};
+
+
+static INLINE void
+st_sample_dxt_pixel_block(enum pipe_format format,
+ uint8_t *raw,
+ float *rgba, unsigned rgba_stride,
+ unsigned w, unsigned h)
+{
+ const struct dxt_data *data;
+ unsigned n;
+ unsigned i;
+ unsigned x, y, ch;
+
+ switch(format) {
+ case PIPE_FORMAT_DXT1_RGB:
+ data = dxt1_rgb_data;
+ n = sizeof(dxt1_rgb_data)/sizeof(dxt1_rgb_data[0]);
+ break;
+ case PIPE_FORMAT_DXT1_RGBA:
+ data = dxt1_rgba_data;
+ n = sizeof(dxt1_rgba_data)/sizeof(dxt1_rgba_data[0]);
+ break;
+ case PIPE_FORMAT_DXT3_RGBA:
+ data = dxt3_rgba_data;
+ n = sizeof(dxt3_rgba_data)/sizeof(dxt3_rgba_data[0]);
+ break;
+ case PIPE_FORMAT_DXT5_RGBA:
+ data = dxt5_rgba_data;
+ n = sizeof(dxt5_rgba_data)/sizeof(dxt5_rgba_data[0]);
+ break;
+ default:
+ assert(0);
+ return;
+ }
+
+ i = st_random() % n;
+
+ for(y = 0; y < h; ++y)
+ for(x = 0; x < w; ++x)
+ for(ch = 0; ch < 4; ++ch)
+ rgba[y*rgba_stride + x*4 + ch] = (float)(data[i].rgba[y*4*4 + x*4 + ch])/255.0f;
+
+ memcpy(raw, data[i].raw, util_format_get_blocksize(format));
+}
+
+
+static INLINE void
+st_sample_generic_pixel_block(enum pipe_format format,
+ uint8_t *raw,
+ float *rgba, unsigned rgba_stride,
+ unsigned w, unsigned h,
+ boolean norm)
+{
+ unsigned i;
+ unsigned x, y, ch;
+ int blocksize = util_format_get_blocksize(format);
+
+ if (norm) {
+ for (y = 0; y < h; ++y) {
+ for (x = 0; x < w; ++x) {
+ for (ch = 0; ch < 4; ++ch) {
+ unsigned offset = y*rgba_stride + x*4 + ch;
+ rgba[offset] = (st_random() & 0xff) / (double)0xff;
+ }
+ }
+ }
+
+ util_format_write_4f(format,
+ rgba, rgba_stride * sizeof(float),
+ raw, util_format_get_stride(format, w),
+ 0, 0, w, h);
+
+ } else {
+ for (i = 0; i < blocksize; ++i)
+ raw[i] = (uint8_t)st_random();
+ }
+
+ util_format_read_4f(format,
+ rgba, rgba_stride * sizeof(float),
+ raw, util_format_get_stride(format, w),
+ 0, 0, w, h);
+
+ if (format == PIPE_FORMAT_UYVY || format == PIPE_FORMAT_YUYV) {
+ for (y = 0; y < h; ++y) {
+ for (x = 0; x < w; ++x) {
+ for (ch = 0; ch < 4; ++ch) {
+ unsigned offset = y*rgba_stride + x*4 + ch;
+ rgba[offset] = CLAMP(rgba[offset], 0.0f, 1.0f);
+ }
+ }
+ }
+ }
+}
+
+
+/**
+ * Randomly sample pixels.
+ */
+void
+st_sample_pixel_block(enum pipe_format format,
+ void *raw,
+ float *rgba, unsigned rgba_stride,
+ unsigned w, unsigned h,
+ boolean norm)
+{
+ switch(format) {
+ case PIPE_FORMAT_DXT1_RGB:
+ case PIPE_FORMAT_DXT1_RGBA:
+ case PIPE_FORMAT_DXT3_RGBA:
+ case PIPE_FORMAT_DXT5_RGBA:
+ st_sample_dxt_pixel_block(format, raw, rgba, rgba_stride, w, h);
+ break;
+
+ default:
+ st_sample_generic_pixel_block(format, raw, rgba, rgba_stride, w, h, norm);
+ break;
+ }
+}
+
+
+void
+st_sample_surface(struct pipe_context *pipe,
+ struct st_surface *surface,
+ float *rgba,
+ boolean norm)
+{
+ struct pipe_resource *texture = surface->texture;
+ unsigned width = u_minify(texture->width0, surface->level);
+ unsigned height = u_minify(texture->height0, surface->level);
+ uint rgba_stride = width * 4;
+ struct pipe_transfer *transfer;
+ void *raw;
+
+ transfer = pipe_get_transfer(pipe,
+ surface->texture,
+ surface->face,
+ surface->level,
+ surface->zslice,
+ PIPE_TRANSFER_WRITE,
+ 0, 0,
+ width,
+ height);
+ if (!transfer)
+ return;
+
+ raw = pipe->transfer_map(pipe, transfer);
+ if (raw) {
+ enum pipe_format format = texture->format;
+ uint x, y;
+ int nblocksx = util_format_get_nblocksx(format, width);
+ int nblocksy = util_format_get_nblocksy(format, height);
+ int blockwidth = util_format_get_blockwidth(format);
+ int blockheight = util_format_get_blockheight(format);
+ int blocksize = util_format_get_blocksize(format);
+
+
+ for (y = 0; y < nblocksy; ++y) {
+ for (x = 0; x < nblocksx; ++x) {
+ st_sample_pixel_block(format,
+ (uint8_t *) raw + y * transfer->stride + x * blocksize,
+ rgba + y * blockheight * rgba_stride + x * blockwidth * 4,
+ rgba_stride,
+ MIN2(blockwidth, width - x*blockwidth),
+ MIN2(blockheight, height - y*blockheight),
+ norm);
+ }
+ }
+
+ pipe->transfer_unmap(pipe, transfer);
+ }
+
+ pipe->transfer_destroy(pipe, transfer);
+}
diff --git a/src/gallium/state_trackers/python/st_sample.h b/src/gallium/state_trackers/python/st_sample.h
new file mode 100644
index 0000000000..2fdbb391f3
--- /dev/null
+++ b/src/gallium/state_trackers/python/st_sample.h
@@ -0,0 +1,53 @@
+/**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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 ST_SAMPLE_H_
+#define ST_SAMPLE_H_
+
+
+#include "pipe/p_format.h"
+
+struct pipe_context;
+struct st_surface;
+
+
+void
+st_sample_pixel_block(enum pipe_format format,
+ void *raw,
+ float *rgba, unsigned rgba_stride,
+ unsigned w, unsigned h,
+ boolean norm);
+
+void
+st_sample_surface(struct pipe_context *pipe,
+ struct st_surface *surface,
+ float *rgba,
+ boolean norm);
+
+
+#endif /* ST_SAMPLE_H_ */
diff --git a/src/gallium/state_trackers/python/st_softpipe_winsys.c b/src/gallium/state_trackers/python/st_softpipe_winsys.c
new file mode 100644
index 0000000000..8584bad467
--- /dev/null
+++ b/src/gallium/state_trackers/python/st_softpipe_winsys.c
@@ -0,0 +1,78 @@
+/**************************************************************************
+ *
+ * Copyright 2007 Tungsten Graphics, Inc., Bismarck, ND., USA
+ * 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 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
+ * THE COPYRIGHT HOLDERS, AUTHORS 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.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ *
+ **************************************************************************/
+
+#include "util/u_debug.h"
+#include "softpipe/sp_public.h"
+#include "llvmpipe/lp_public.h"
+#include "state_tracker/sw_winsys.h"
+#include "sw/null/null_sw_winsys.h"
+#include "st_winsys.h"
+
+
+struct pipe_screen *
+st_software_screen_create(const char *driver)
+{
+ struct sw_winsys *ws;
+ struct pipe_screen *screen = NULL;
+
+ if (!driver) {
+ const char *default_driver;
+
+#if defined(HAVE_LLVMPIPE)
+ default_driver = "llvmpipe";
+#elif defined(HAVE_SOFTPIPE)
+ default_driver = "softpipe";
+#else
+ default_driver = "";
+#endif
+
+ driver = debug_get_option("GALLIUM_DRIVER", default_driver);
+ }
+
+ ws = null_sw_create();
+ if(!ws)
+ return NULL;
+
+#ifdef HAVE_LLVMPIPE
+ if (strcmp(driver, "llvmpipe") == 0) {
+ screen = llvmpipe_create_screen(ws);
+ }
+#endif
+
+#ifdef HAVE_SOFTPIPE
+ if (strcmp(driver, "softpipe") == 0) {
+ screen = softpipe_create_screen(ws);
+ }
+#endif
+
+ if (!screen) {
+ ws->destroy(ws);
+ }
+
+ return screen;
+}
diff --git a/src/gallium/state_trackers/python/st_winsys.h b/src/gallium/state_trackers/python/st_winsys.h
new file mode 100644
index 0000000000..7d4066d947
--- /dev/null
+++ b/src/gallium/state_trackers/python/st_winsys.h
@@ -0,0 +1,43 @@
+/**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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 ST_WINSYS_H_
+#define ST_WINSYS_H_
+
+
+struct pipe_screen;
+
+
+struct pipe_screen *
+st_hardware_screen_create(void);
+
+struct pipe_screen *
+st_software_screen_create(const char *driver);
+
+
+#endif /* ST_WINSYS_H_ */
diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-abs.png b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-abs.png
new file mode 100644
index 0000000000..c947a7b881
--- /dev/null
+++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-abs.png
Binary files differ
diff --git a/src/gallium/state_trackers/python/u_format.i b/src/gallium/state_trackers/python/u_format.i
new file mode 100644
index 0000000000..2184b42084
--- /dev/null
+++ b/src/gallium/state_trackers/python/u_format.i
@@ -0,0 +1,88 @@
+/**************************************************************************
+ *
+ * Copyright 2010 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 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
+ * THE COPYRIGHT HOLDERS, AUTHORS 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.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ **************************************************************************/
+
+
+static INLINE const char *
+util_format_name(enum pipe_format format);
+
+static INLINE boolean
+util_format_is_s3tc(enum pipe_format format);
+
+static INLINE boolean
+util_format_is_depth_or_stencil(enum pipe_format format);
+
+static INLINE boolean
+util_format_is_depth_and_stencil(enum pipe_format format);
+
+
+uint
+util_format_get_blocksizebits(enum pipe_format format);
+
+uint
+util_format_get_blocksize(enum pipe_format format);
+
+uint
+util_format_get_blockwidth(enum pipe_format format);
+
+uint
+util_format_get_blockheight(enum pipe_format format);
+
+unsigned
+util_format_get_nblocksx(enum pipe_format format,
+ unsigned x);
+
+unsigned
+util_format_get_nblocksy(enum pipe_format format,
+ unsigned y);
+
+unsigned
+util_format_get_nblocks(enum pipe_format format,
+ unsigned width,
+ unsigned height);
+
+size_t
+util_format_get_stride(enum pipe_format format,
+ unsigned width);
+
+size_t
+util_format_get_2d_size(enum pipe_format format,
+ size_t stride,
+ unsigned height);
+
+uint
+util_format_get_component_bits(enum pipe_format format,
+ enum util_format_colorspace colorspace,
+ uint component);
+
+boolean
+util_format_has_alpha(enum pipe_format format);
+
+
+unsigned
+util_format_get_nr_components(enum pipe_format format);
+
+
diff --git a/src/gallium/state_trackers/vega/Makefile b/src/gallium/state_trackers/vega/Makefile
new file mode 100644
index 0000000000..e0a87151c4
--- /dev/null
+++ b/src/gallium/state_trackers/vega/Makefile
@@ -0,0 +1,41 @@
+# src/gallium/state_trackers/vega/Makefile
+
+TOP = ../../../..
+include $(TOP)/configs/current
+
+LIBNAME = vega
+
+LIBRARY_INCLUDES = \
+ -I$(TOP)/include \
+ -I$(TOP)/src/mapi
+
+C_SOURCES = \
+ api.c \
+ 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_manager.c \
+ vg_state.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
+
+include ../../Makefile.template
diff --git a/src/gallium/state_trackers/vega/SConscript b/src/gallium/state_trackers/vega/SConscript
new file mode 100644
index 0000000000..548053eb64
--- /dev/null
+++ b/src/gallium/state_trackers/vega/SConscript
@@ -0,0 +1,51 @@
+#######################################################################
+# SConscript for vega state_tracker
+
+Import('*')
+
+if 'egl' in env['statetrackers']:
+
+ env = env.Clone()
+
+ env.Append(CPPPATH = [
+ '#/src/mapi',
+ ])
+
+ vega_sources = [
+ 'api.c',
+ '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_manager.c',
+ 'vg_state.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',
+ ]
+
+ # vgapi_header must be generated first
+ env.Depends(vega_sources, vgapi_header)
+
+ st_vega = env.ConvenienceLibrary(
+ target = 'st_vega',
+ source = vega_sources,
+ )
+ Export('st_vega')
diff --git a/src/gallium/state_trackers/vega/api.c b/src/gallium/state_trackers/vega/api.c
new file mode 100644
index 0000000000..bf1d37493a
--- /dev/null
+++ b/src/gallium/state_trackers/vega/api.c
@@ -0,0 +1,88 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.9
+ *
+ * Copyright (C) 2010 LunarG Inc.
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Chia-I Wu <olv@lunarg.com>
+ */
+
+#include "mapi/mapi.h"
+
+#include "api.h"
+
+static const char vega_spec[] =
+ "1"
+#define MAPI_ABI_ENTRY(ret, name, params) \
+ "\0" #name "\0"
+#define MAPI_ALIAS_ENTRY(alias, ret, name, params) \
+ #name "\0"
+#include "vgapi/vgapi_tmp.h"
+ "\0";
+
+static const mapi_proc vega_procs[] = {
+#define MAPI_ABI_ENTRY(ret, name, params) \
+ (mapi_proc) vega ## name,
+#include "vgapi/vgapi_tmp.h"
+};
+
+static void api_init(void)
+{
+ static boolean initialized = FALSE;
+ if (!initialized) {
+ mapi_init(vega_spec);
+ initialized = TRUE;
+ }
+}
+
+struct mapi_table *api_create_dispatch(void)
+{
+ struct mapi_table *tbl;
+
+ api_init();
+
+ tbl = mapi_table_create();
+ if (tbl)
+ mapi_table_fill(tbl, vega_procs);
+
+ return tbl;
+}
+
+void api_destroy_dispatch(struct mapi_table *tbl)
+{
+ mapi_table_destroy(tbl);
+}
+
+void api_make_dispatch_current(const struct mapi_table *tbl)
+{
+ mapi_table_make_current(tbl);
+}
+
+mapi_proc api_get_proc_address(const char *proc_name)
+{
+ if (!proc_name || proc_name[0] != 'v' || proc_name[1] != 'g')
+ return NULL;
+ proc_name += 2;
+
+ api_init();
+ return mapi_get_proc_address(proc_name);
+}
diff --git a/src/gallium/state_trackers/vega/api.h b/src/gallium/state_trackers/vega/api.h
new file mode 100644
index 0000000000..955508dae9
--- /dev/null
+++ b/src/gallium/state_trackers/vega/api.h
@@ -0,0 +1,51 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.9
+ *
+ * Copyright (C) 2010 LunarG Inc.
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Chia-I Wu <olv@lunarg.com>
+ */
+
+#ifndef API_H
+#define API_H
+
+#include "VG/openvg.h"
+#include "VG/vgext.h"
+#include "vg_manager.h"
+
+/* declare the prototypes */
+#define MAPI_ABI_ENTRY(ret, name, params) \
+ ret VG_API_ENTRY vega ## name params;
+#include "vgapi/vgapi_tmp.h"
+
+struct mapi_table;
+
+struct mapi_table *api_create_dispatch(void);
+
+void api_destroy_dispatch(struct mapi_table *tbl);
+
+void api_make_dispatch_current(const struct mapi_table *tbl);
+
+st_proc_t api_get_proc_address(const char *proc_name);
+
+#endif /* API_H */
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..0d04d8e871
--- /dev/null
+++ b/src/gallium/state_trackers/vega/api_context.c
@@ -0,0 +1,79 @@
+/**************************************************************************
+ *
+ * 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_manager.h"
+#include "vg_context.h"
+#include "api.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_screen.h"
+
+VGErrorCode vegaGetError(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 vegaFlush(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);
+
+ vg_manager_flush_frontbuffer(ctx);
+}
+
+void vegaFinish(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..8ace985336
--- /dev/null
+++ b/src/gallium/state_trackers/vega/api_filters.c
@@ -0,0 +1,830 @@
+/**************************************************************************
+ *
+ * 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 "api.h"
+#include "renderer.h"
+#include "shaders_cache.h"
+#include "st_inlines.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_state.h"
+#include "util/u_inlines.h"
+#include "pipe/p_screen.h"
+#include "pipe/p_shader_tokens.h"
+
+#include "util/u_format.h"
+#include "util/u_memory.h"
+#include "util/u_sampler.h"
+#include "util/u_string.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_sampler_view *extra_texture_view;
+};
+
+static INLINE struct pipe_resource *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_resource *tex = 0;
+ struct pipe_resource templ;
+
+ memset(&templ, 0, sizeof(templ));
+ templ.target = PIPE_TEXTURE_1D;
+ templ.format = PIPE_FORMAT_B8G8R8A8_UNORM;
+ templ.last_level = 0;
+ templ.width0 = color_data_len;
+ templ.height0 = 1;
+ templ.depth0 = 1;
+ templ.bind = PIPE_BIND_SAMPLER_VIEW;
+
+ tex = screen->resource_create(screen, &templ);
+
+ { /* upload color_data */
+ struct pipe_transfer *transfer =
+ pipe_get_transfer(pipe, tex,
+ 0, 0, 0,
+ PIPE_TRANSFER_READ_WRITE ,
+ 0, 0, tex->width0, tex->height0);
+ void *map = pipe->transfer_map(pipe, transfer);
+ memcpy(map, color_data, sizeof(VGint)*color_data_len);
+ pipe->transfer_unmap(pipe, transfer);
+ pipe->transfer_destroy(pipe, transfer);
+ }
+
+ return tex;
+}
+
+static INLINE struct pipe_sampler_view *create_texture_1d_view(struct vg_context *ctx,
+ const VGuint *color_data,
+ const VGint color_data_len)
+{
+ struct pipe_context *pipe = ctx->pipe;
+ struct pipe_resource *texture;
+ struct pipe_sampler_view view_templ;
+ struct pipe_sampler_view *view;
+
+ texture = create_texture_1d(ctx, color_data, color_data_len);
+
+ if (!texture)
+ return NULL;
+
+ u_sampler_view_default_template(&view_templ, texture, texture->format);
+ view = pipe->create_sampler_view(pipe, texture, &view_templ);
+ /* want the texture to go away if the view is freed */
+ pipe_resource_reference(&texture, NULL);
+
+ return view;
+}
+
+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->sampler_view->texture, 0, 0, 0,
+ PIPE_BIND_RENDER_TARGET);
+
+ /* 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.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ if (ctx->state.vg.filter_channel_mask & VG_RED)
+ blend.rt[0].colormask |= PIPE_MASK_R;
+ if (ctx->state.vg.filter_channel_mask & VG_GREEN)
+ blend.rt[0].colormask |= PIPE_MASK_G;
+ if (ctx->state.vg.filter_channel_mask & VG_BLUE)
+ blend.rt[0].colormask |= PIPE_MASK_B;
+ if (ctx->state.vg.filter_channel_mask & VG_ALPHA)
+ blend.rt[0].colormask |= PIPE_MASK_A;
+ blend.rt[0].blend_enable = 0;
+ 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_resource **cbuf = &ctx->filter.buffer;
+
+ /* We always need to get a new buffer, to keep the drivers simple and
+ * avoid gratuitous rendering synchronization. */
+ pipe_resource_reference(cbuf, NULL);
+
+ *cbuf = pipe_buffer_create(pipe->screen,
+ PIPE_BIND_CONSTANT_BUFFER,
+ param_bytes);
+
+ if (*cbuf) {
+ st_no_flush_pipe_buffer_write(ctx, *cbuf,
+ 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_sampler_view *sampler_views[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;
+ sampler_views[0] = NULL;
+ sampler_views[1] = NULL;
+ sampler_views[2] = NULL;
+ sampler_views[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];
+ sampler_views[0] = info->src->sampler_view;
+ ++num_samplers;
+ ++num_textures;
+
+ if (info->extra_texture_view) {
+ memcpy(&sampler[1], &sampler[0], sizeof(struct pipe_sampler_state));
+ samplers[1] = &sampler[1];
+ sampler_views[1] = info->extra_texture_view;
+ ++num_samplers;
+ ++num_textures;
+ }
+
+
+ cso_set_samplers(ctx->cso_context, num_samplers, (const struct pipe_sampler_state **)samplers);
+ cso_set_fragment_sampler_views(ctx->cso_context, num_textures, sampler_views);
+}
+
+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;
+
+ util_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:
+ util_snprintf(buffer, 1023, lookup_single_asm, "xxxx");
+ break;
+ case VG_GREEN:
+ util_snprintf(buffer, 1023, lookup_single_asm, "yyyy");
+ break;
+ case VG_BLUE:
+ util_snprintf(buffer, 1023, lookup_single_asm, "zzzz");
+ break;
+ case VG_ALPHA:
+ util_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_fragment_sampler_views(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->sampler_view->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_fragment_sampler_views(ctx->cso_context);
+
+ vg_shader_destroy(ctx, shader);
+
+ pipe_surface_reference(&dst_surf, NULL);
+}
+
+void vegaColorMatrix(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_view = NULL;
+ execute_filter(ctx, &info);
+}
+
+static VGfloat texture_offset(VGfloat width, VGint kernelSize, VGint current, VGint shift)
+{
+ VGfloat diff = current - shift;
+
+ return diff / width;
+}
+
+void vegaConvolve(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_view = NULL;
+ execute_filter(ctx, &info);
+
+ free(buffer);
+}
+
+void vegaSeparableConvolve(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 vegaGaussianBlur(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_view = NULL;
+ execute_filter(ctx, &info);
+
+ free(buffer);
+ free(kernel);
+}
+
+void vegaLookup(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_sampler_view *lut_texture_view;
+ 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_view = create_texture_1d_view(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_view = lut_texture_view;
+
+ execute_filter(ctx, &info);
+
+ pipe_sampler_view_reference(&lut_texture_view, NULL);
+}
+
+void vegaLookupSingle(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_sampler_view *lut_texture_view;
+ 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_view = create_texture_1d_view(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_view = lut_texture_view;
+
+ execute_filter(ctx, &info);
+
+ pipe_sampler_view_reference(&lut_texture_view, 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..547508f815
--- /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 "api.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_screen.h"
+#include "util/u_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 vegaCreateImage(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 vegaDestroyImage(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 vegaClearImage(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 vegaImageSubData(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 vegaGetImageSubData(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 vegaChildImage(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 vegaGetParent(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 vegaCopyImage(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 vegaDrawImage(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 vegaSetPixels(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 vegaGetPixels(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 vegaWritePixels(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 vegaReadPixels(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 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 = pipe_get_transfer(pipe, 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(pipe, transfer, sx, y, width, 1, df);
+ y += yStep;
+ _vega_pack_rgba_span_float(ctx, width, temp, dataFormat,
+ dst + yoffset + xoffset);
+ dst += dataStride;
+ }
+
+ pipe->transfer_destroy(pipe, transfer);
+ }
+}
+
+void vegaCopyPixels(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..94c1ff5375
--- /dev/null
+++ b/src/gallium/state_trackers/vega/api_masks.c
@@ -0,0 +1,368 @@
+/**************************************************************************
+ *
+ * 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 "api.h"
+
+#include "vg_context.h"
+#include "pipe/p_context.h"
+#include "util/u_inlines.h"
+
+#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_resource *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),
+ PIPE_BIND_VERTEX_BUFFER);
+
+
+ /* draw */
+ if (buf) {
+ cso_set_vertex_elements(st->cso_context, 2, st->velems);
+
+ util_draw_vertex_buffer(pipe, buf, 0,
+ PIPE_PRIM_TRIANGLE_FAN,
+ 4, /* verts */
+ 2); /* attribs/vert */
+
+ pipe_resource_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);
+ */
+
+ 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.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ blend.rt[0].colormask = PIPE_MASK_RGBA;
+ 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 vegaMask(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 vegaClear(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 vegaRenderToMask(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 vegaCreateMaskLayer(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 vegaDestroyMaskLayer(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 vegaFillMaskLayer(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 vegaCopyMask(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..e648549745
--- /dev/null
+++ b/src/gallium/state_trackers/vega/api_misc.c
@@ -0,0 +1,84 @@
+/**************************************************************************
+ *
+ * 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 "api.h"
+
+/* Hardware Queries */
+VGHardwareQueryResult vegaHardwareQuery(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 *vegaGetString(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..d88341b04f
--- /dev/null
+++ b/src/gallium/state_trackers/vega/api_paint.c
@@ -0,0 +1,167 @@
+/**************************************************************************
+ *
+ * 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"
+#include "api.h"
+
+VGPaint vegaCreatePaint(void)
+{
+ return (VGPaint) paint_create(vg_current_context());
+}
+
+void vegaDestroyPaint(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 vegaSetPaint(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 vegaGetPaint(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 vegaSetColor(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 vegaGetColor(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 vegaPaintPattern(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..a10b009e63
--- /dev/null
+++ b/src/gallium/state_trackers/vega/api_params.c
@@ -0,0 +1,1674 @@
+/**************************************************************************
+ *
+ * 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 "api.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 vegaSetf (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 vegaSeti (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 vegaSetfv(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 vegaSetiv(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 vegaGetf(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 vegaGeti(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 vegaGetVectorSize(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 vegaGetfv(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 vegaGetiv(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 vegaSetParameterf(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 vegaSetParameteri(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 vegaSetParameterfv(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 vegaSetParameteriv(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 vegaGetParameterVectorSize(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 vegaGetParameterf(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 vegaGetParameteri(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 vegaGetParameterfv(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 vegaGetParameteriv(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..6c9a2e8d65
--- /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 "api.h"
+
+#include "pipe/p_context.h"
+#include "util/u_inlines.h"
+#include "util/u_draw_quad.h"
+
+VGPath vegaCreatePath(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 vegaClearPath(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 vegaDestroyPath(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 vegaRemovePathCapabilities(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 vegaGetPathCapabilities(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 vegaAppendPath(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 vegaAppendPathData(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_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 vegaModifyPathCoords(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 vegaTransformPath(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 vegaInterpolatePath(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 vegaPathLength(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 vegaPointAlongPath(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 vegaPathBounds(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 vegaPathTransformedBounds(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 vegaDrawPath(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..b35f3be90a
--- /dev/null
+++ b/src/gallium/state_trackers/vega/api_text.c
@@ -0,0 +1,259 @@
+/**************************************************************************
+ *
+ * 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 "api.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 vegaCreateFont(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 vegaDestroyFont(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 vegaSetGlyphToPath(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 vegaSetGlyphToImage(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 vegaClearGlyph(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 vegaDrawGlyph(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 vegaDrawGlyphs(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..0a40fc69b9
--- /dev/null
+++ b/src/gallium/state_trackers/vega/api_transform.c
@@ -0,0 +1,129 @@
+/**************************************************************************
+ *
+ * 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"
+#include "api.h"
+
+void vegaLoadIdentity(void)
+{
+ struct vg_context *ctx = vg_current_context();
+ struct matrix *mat = vg_state_matrix(&ctx->state.vg);
+ matrix_load_identity(mat);
+}
+
+void vegaLoadMatrix(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 vegaGetMatrix(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 vegaMultMatrix(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 vegaTranslate(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 vegaScale(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 vegaShear(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 vegaRotate(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..65a985fbbb
--- /dev/null
+++ b/src/gallium/state_trackers/vega/arc.c
@@ -0,0 +1,709 @@
+/**************************************************************************
+ *
+ * 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 "util/u_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;
+ int i;
+ found = VG_TRUE;
+ for (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 i;
+ 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 (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..27773467fa
--- /dev/null
+++ b/src/gallium/state_trackers/vega/asm_fill.h
@@ -0,0 +1,455 @@
+/**************************************************************************
+ *
+ * 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
+
+#include "tgsi/tgsi_ureg.h"
+
+typedef void (* ureg_func)( struct ureg_program *ureg,
+ struct ureg_dst *out,
+ struct ureg_src *in,
+ struct ureg_src *sampler,
+ struct ureg_dst *temp,
+ struct ureg_src *constant);
+
+static INLINE void
+solid_fill( struct ureg_program *ureg,
+ struct ureg_dst *out,
+ struct ureg_src *in,
+ struct ureg_src *sampler,
+ struct ureg_dst *temp,
+ struct ureg_src *constant)
+{
+ ureg_MOV(ureg, *out, constant[0]);
+}
+
+static INLINE void
+linear_grad( struct ureg_program *ureg,
+ struct ureg_dst *out,
+ struct ureg_src *in,
+ struct ureg_src *sampler,
+ struct ureg_dst *temp,
+ struct ureg_src *constant)
+{
+
+ ureg_MOV(ureg,
+ ureg_writemask(temp[0], TGSI_WRITEMASK_XY),
+ in[0]);
+ ureg_MOV(ureg,
+ ureg_writemask(temp[0], TGSI_WRITEMASK_Z),
+ ureg_scalar(constant[1], TGSI_SWIZZLE_Y));
+ ureg_DP3(ureg, temp[1], constant[2], ureg_src(temp[0]));
+ ureg_DP3(ureg, temp[2], constant[3], ureg_src(temp[0]));
+ ureg_DP3(ureg, temp[3], constant[4], ureg_src(temp[0]));
+ ureg_RCP(ureg, temp[3], ureg_src(temp[3]));
+ ureg_MUL(ureg, temp[1], ureg_src(temp[1]), ureg_src(temp[3]));
+ ureg_MUL(ureg, temp[2], ureg_src(temp[2]), ureg_src(temp[3]));
+ ureg_MOV(ureg, ureg_writemask(temp[4], TGSI_WRITEMASK_X), ureg_src(temp[1]));
+ ureg_MOV(ureg, ureg_writemask(temp[4], TGSI_WRITEMASK_Y), ureg_src(temp[2]));
+ ureg_MUL(ureg, temp[0],
+ ureg_scalar(constant[0], TGSI_SWIZZLE_Y),
+ ureg_scalar(ureg_src(temp[4]), TGSI_SWIZZLE_Y));
+ ureg_MAD(ureg, temp[1],
+ ureg_scalar(constant[0], TGSI_SWIZZLE_X),
+ ureg_scalar(ureg_src(temp[4]), TGSI_SWIZZLE_X),
+ ureg_src(temp[0]));
+ ureg_MUL(ureg, temp[2], ureg_src(temp[1]),
+ ureg_scalar(constant[0], TGSI_SWIZZLE_Z));
+ ureg_TEX(ureg, *out, TGSI_TEXTURE_1D, ureg_src(temp[2]), sampler[0]);
+}
+
+static INLINE void
+radial_grad( struct ureg_program *ureg,
+ struct ureg_dst *out,
+ struct ureg_src *in,
+ struct ureg_src *sampler,
+ struct ureg_dst *temp,
+ struct ureg_src *constant)
+{
+
+ ureg_MOV(ureg, ureg_writemask(temp[0], TGSI_WRITEMASK_XY), in[0]);
+ ureg_MOV(ureg,
+ ureg_writemask(temp[0], TGSI_WRITEMASK_Z),
+ ureg_scalar(constant[1], TGSI_SWIZZLE_Y));
+ ureg_DP3(ureg, temp[1], constant[2], ureg_src(temp[0]));
+ ureg_DP3(ureg, temp[2], constant[3], ureg_src(temp[0]));
+ ureg_DP3(ureg, temp[3], constant[4], ureg_src(temp[0]));
+ ureg_RCP(ureg, temp[3], ureg_src(temp[3]));
+ ureg_MUL(ureg, temp[1], ureg_src(temp[1]), ureg_src(temp[3]));
+ ureg_MUL(ureg, temp[2], ureg_src(temp[2]), ureg_src(temp[3]));
+ ureg_MOV(ureg, ureg_writemask(temp[5], TGSI_WRITEMASK_X), ureg_src(temp[1]));
+ ureg_MOV(ureg, ureg_writemask(temp[5], TGSI_WRITEMASK_Y), ureg_src(temp[2]));
+ ureg_MUL(ureg, temp[0], ureg_scalar(constant[0], TGSI_SWIZZLE_Y),
+ ureg_scalar(ureg_src(temp[5]), TGSI_SWIZZLE_Y));
+ ureg_MAD(ureg, temp[1],
+ ureg_scalar(constant[0], TGSI_SWIZZLE_X),
+ ureg_scalar(ureg_src(temp[5]), TGSI_SWIZZLE_X), ureg_src(temp[0]));
+ ureg_ADD(ureg, temp[1], ureg_src(temp[1]), ureg_src(temp[1]));
+ ureg_MUL(ureg, temp[3],
+ ureg_scalar(ureg_src(temp[5]), TGSI_SWIZZLE_Y),
+ ureg_scalar(ureg_src(temp[5]), TGSI_SWIZZLE_Y));
+ ureg_MAD(ureg, temp[4],
+ ureg_scalar(ureg_src(temp[5]), TGSI_SWIZZLE_X),
+ ureg_scalar(ureg_src(temp[5]), TGSI_SWIZZLE_X),
+ ureg_src(temp[3]));
+ ureg_MOV(ureg, temp[4], ureg_negate(ureg_src(temp[4])));
+ ureg_MUL(ureg, temp[2],
+ ureg_scalar(constant[0], TGSI_SWIZZLE_Z),
+ ureg_src(temp[4]));
+ ureg_MUL(ureg, temp[0],
+ ureg_scalar(constant[1], TGSI_SWIZZLE_W),
+ ureg_src(temp[2]));
+ ureg_MUL(ureg, temp[3], ureg_src(temp[1]), ureg_src(temp[1]));
+
+ ureg_SUB(ureg, temp[2], ureg_src(temp[3]), ureg_src(temp[0]));
+ ureg_RSQ(ureg, temp[2], ureg_abs(ureg_src(temp[2])));
+ ureg_RCP(ureg, temp[2], ureg_src(temp[2]));
+ ureg_SUB(ureg, temp[1], ureg_src(temp[2]), ureg_src(temp[1]));
+ ureg_ADD(ureg, temp[0],
+ ureg_scalar(constant[0], TGSI_SWIZZLE_Z),
+ ureg_scalar(constant[0], TGSI_SWIZZLE_Z));
+ ureg_RCP(ureg, temp[0], ureg_src(temp[0]));
+ ureg_MUL(ureg, temp[2], ureg_src(temp[1]), ureg_src(temp[0]));
+ ureg_TEX(ureg, *out, TGSI_TEXTURE_1D, ureg_src(temp[2]), sampler[0]);
+
+}
+
+
+static INLINE void
+pattern( struct ureg_program *ureg,
+ struct ureg_dst *out,
+ struct ureg_src *in,
+ struct ureg_src *sampler,
+ struct ureg_dst *temp,
+ struct ureg_src *constant)
+{
+ ureg_MOV(ureg,
+ ureg_writemask(temp[0], TGSI_WRITEMASK_XY),
+ in[0]);
+ ureg_MOV(ureg,
+ ureg_writemask(temp[0], TGSI_WRITEMASK_Z),
+ ureg_scalar(constant[1], TGSI_SWIZZLE_Y));
+ ureg_DP3(ureg, temp[1], constant[2], ureg_src(temp[0]));
+ ureg_DP3(ureg, temp[2], constant[3], ureg_src(temp[0]));
+ ureg_DP3(ureg, temp[3], constant[4], ureg_src(temp[0]));
+ ureg_RCP(ureg, temp[3], ureg_src(temp[3]));
+ ureg_MUL(ureg, temp[1], ureg_src(temp[1]), ureg_src(temp[3]));
+ ureg_MUL(ureg, temp[2], ureg_src(temp[2]), ureg_src(temp[3]));
+ ureg_MOV(ureg, ureg_writemask(temp[4], TGSI_WRITEMASK_X), ureg_src(temp[1]));
+ ureg_MOV(ureg, ureg_writemask(temp[4], TGSI_WRITEMASK_Y), ureg_src(temp[2]));
+ ureg_RCP(ureg, temp[0],
+ ureg_swizzle(constant[1],
+ TGSI_SWIZZLE_Z,
+ TGSI_SWIZZLE_W,
+ TGSI_SWIZZLE_Z,
+ TGSI_SWIZZLE_W));
+ ureg_MOV(ureg, temp[1], ureg_src(temp[4]));
+ ureg_MUL(ureg,
+ ureg_writemask(temp[1], TGSI_WRITEMASK_X),
+ ureg_src(temp[1]),
+ ureg_src(temp[0]));
+ ureg_MUL(ureg,
+ ureg_writemask(temp[1], TGSI_WRITEMASK_Y),
+ ureg_src(temp[1]),
+ ureg_src(temp[0]));
+ ureg_TEX(ureg, *out, TGSI_TEXTURE_2D, ureg_src(temp[1]), sampler[0]);
+}
+
+static INLINE void
+mask( struct ureg_program *ureg,
+ struct ureg_dst *out,
+ struct ureg_src *in,
+ struct ureg_src *sampler,
+ struct ureg_dst *temp,
+ struct ureg_src *constant)
+{
+ ureg_TEX(ureg, temp[1], TGSI_TEXTURE_2D, in[0], sampler[1]);
+ ureg_MUL(ureg, ureg_writemask(temp[0], TGSI_WRITEMASK_W),
+ ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_W),
+ ureg_scalar(ureg_src(temp[1]), TGSI_SWIZZLE_W));
+ ureg_MOV(ureg, *out, ureg_src(temp[0]));
+}
+
+static INLINE void
+image_normal( struct ureg_program *ureg,
+ struct ureg_dst *out,
+ struct ureg_src *in,
+ struct ureg_src *sampler,
+ struct ureg_dst *temp,
+ struct ureg_src *constant)
+{
+ ureg_TEX(ureg, *out, TGSI_TEXTURE_2D, in[1], sampler[3]);
+}
+
+
+static INLINE void
+image_multiply( struct ureg_program *ureg,
+ struct ureg_dst *out,
+ struct ureg_src *in,
+ struct ureg_src *sampler,
+ struct ureg_dst *temp,
+ struct ureg_src *constant)
+{
+ ureg_TEX(ureg, temp[1], TGSI_TEXTURE_2D, in[1], sampler[3]);
+ ureg_MUL(ureg, *out, ureg_src(temp[0]), ureg_src(temp[1]));
+}
+
+
+static INLINE void
+image_stencil( struct ureg_program *ureg,
+ struct ureg_dst *out,
+ struct ureg_src *in,
+ struct ureg_src *sampler,
+ struct ureg_dst *temp,
+ struct ureg_src *constant)
+{
+ ureg_TEX(ureg, temp[1], TGSI_TEXTURE_2D, in[1], sampler[3]);
+ ureg_MUL(ureg, *out, ureg_src(temp[0]), ureg_src(temp[1]));
+}
+
+#define EXTENDED_BLENDER_OVER_FUNC \
+ ureg_SUB(ureg, temp[3], \
+ ureg_scalar(constant[1], TGSI_SWIZZLE_Y), \
+ ureg_scalar(ureg_src(temp[1]), TGSI_SWIZZLE_W)); \
+ ureg_SUB(ureg, temp[3], \
+ ureg_scalar(constant[1], TGSI_SWIZZLE_Y), \
+ ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_W)); \
+ ureg_MUL(ureg, temp[3], ureg_src(temp[0]), ureg_src(temp[3])); \
+ ureg_MUL(ureg, temp[4], ureg_src(temp[1]), ureg_src(temp[4])); \
+ ureg_ADD(ureg, temp[3], ureg_src(temp[3]), ureg_src(temp[4]));
+
+
+static INLINE void
+blend_multiply( struct ureg_program *ureg,
+ struct ureg_dst *out,
+ struct ureg_src *in,
+ struct ureg_src *sampler,
+ struct ureg_dst *temp,
+ struct ureg_src *constant)
+{
+ ureg_TEX(ureg, temp[1], TGSI_TEXTURE_2D, in[0], sampler[2]);
+ EXTENDED_BLENDER_OVER_FUNC
+ ureg_MUL(ureg, temp[4], ureg_src(temp[0]), ureg_src(temp[1]));
+ ureg_ADD(ureg, temp[1], ureg_src(temp[4]), ureg_src(temp[3]));
+
+ ureg_MUL(ureg, temp[2], ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_W),
+ ureg_scalar(ureg_src(temp[1]), TGSI_SWIZZLE_W));
+ ureg_ADD(ureg, temp[3], ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_W),
+ ureg_scalar(ureg_src(temp[1]), TGSI_SWIZZLE_W));
+ ureg_SUB(ureg, ureg_writemask(temp[1], TGSI_WRITEMASK_W),
+ ureg_src(temp[3]), ureg_src(temp[2]));
+
+ ureg_MOV(ureg, *out, ureg_src(temp[1]));
+}
+
+static INLINE void
+blend_screen( struct ureg_program *ureg,
+ struct ureg_dst *out,
+ struct ureg_src *in,
+ struct ureg_src *sampler,
+ struct ureg_dst *temp,
+ struct ureg_src *constant)
+{
+ ureg_TEX(ureg, temp[1], TGSI_TEXTURE_2D, in[0], sampler[2]);
+ ureg_ADD(ureg, temp[3], ureg_src(temp[0]), ureg_src(temp[1]));
+ ureg_MUL(ureg, temp[2], ureg_src(temp[0]), ureg_src(temp[1]));
+ ureg_SUB(ureg, *out, ureg_src(temp[3]), ureg_src(temp[2]));
+}
+
+static INLINE void
+blend_darken( struct ureg_program *ureg,
+ struct ureg_dst *out,
+ struct ureg_src *in,
+ struct ureg_src *sampler,
+ struct ureg_dst *temp,
+ struct ureg_src *constant)
+{
+ ureg_TEX(ureg, temp[1], TGSI_TEXTURE_2D, in[0], sampler[2]);
+ EXTENDED_BLENDER_OVER_FUNC
+ ureg_MUL(ureg, temp[4], ureg_src(temp[0]),
+ ureg_scalar(ureg_src(temp[1]), TGSI_SWIZZLE_W));
+ ureg_MUL(ureg, temp[5], ureg_src(temp[1]),
+ ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_W));
+ ureg_MIN(ureg, temp[4], ureg_src(temp[4]), ureg_src(temp[5]));
+ ureg_ADD(ureg, temp[1], ureg_src(temp[3]), ureg_src(temp[4]));
+
+ ureg_MUL(ureg, temp[2], ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_W),
+ ureg_scalar(ureg_src(temp[1]), TGSI_SWIZZLE_W));
+ ureg_ADD(ureg, temp[3], ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_W),
+ ureg_scalar(ureg_src(temp[1]), TGSI_SWIZZLE_W));
+ ureg_SUB(ureg, ureg_writemask(temp[1], TGSI_WRITEMASK_W),
+ ureg_src(temp[3]), ureg_src(temp[2]));
+
+ ureg_MOV(ureg, *out, ureg_src(temp[1]));
+}
+
+static INLINE void
+blend_lighten( struct ureg_program *ureg,
+ struct ureg_dst *out,
+ struct ureg_src *in,
+ struct ureg_src *sampler,
+ struct ureg_dst *temp,
+ struct ureg_src *constant)
+{
+ ureg_TEX(ureg, temp[1], TGSI_TEXTURE_2D, in[0], sampler[2]);
+ EXTENDED_BLENDER_OVER_FUNC
+ ureg_MUL(ureg, temp[4], ureg_src(temp[0]),
+ ureg_scalar(ureg_src(temp[1]), TGSI_SWIZZLE_W));
+ ureg_MUL(ureg, temp[5], ureg_src(temp[1]),
+ ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_W));
+ ureg_MAX(ureg, temp[4], ureg_src(temp[4]), ureg_src(temp[5]));
+ ureg_ADD(ureg, temp[1], ureg_src(temp[3]), ureg_src(temp[4]));
+
+ ureg_MUL(ureg, temp[2], ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_W),
+ ureg_scalar(ureg_src(temp[1]), TGSI_SWIZZLE_W));
+ ureg_ADD(ureg, temp[3], ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_W),
+ ureg_scalar(ureg_src(temp[1]), TGSI_SWIZZLE_W));
+ ureg_SUB(ureg, ureg_writemask(temp[1], TGSI_WRITEMASK_W),
+ ureg_src(temp[3]), ureg_src(temp[2]));
+
+ ureg_MOV(ureg, *out, ureg_src(temp[1]));
+}
+
+static INLINE void
+premultiply( struct ureg_program *ureg,
+ struct ureg_dst *out,
+ struct ureg_src *in,
+ struct ureg_src *sampler,
+ struct ureg_dst *temp,
+ struct ureg_src *constant)
+{
+ ureg_MUL(ureg,
+ ureg_writemask(temp[0], TGSI_WRITEMASK_XYZ),
+ ureg_src(temp[0]),
+ ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_W));
+}
+
+static INLINE void
+unpremultiply( struct ureg_program *ureg,
+ struct ureg_dst *out,
+ struct ureg_src *in,
+ struct ureg_src *sampler,
+ struct ureg_dst *temp,
+ struct ureg_src *constant)
+{
+ ureg_TEX(ureg, temp[0], TGSI_TEXTURE_2D, in[0], sampler[1]);
+}
+
+
+static INLINE void
+color_bw( struct ureg_program *ureg,
+ struct ureg_dst *out,
+ struct ureg_src *in,
+ struct ureg_src *sampler,
+ struct ureg_dst *temp,
+ struct ureg_src *constant)
+{
+ ureg_ADD(ureg, temp[1],
+ ureg_scalar(constant[1], TGSI_SWIZZLE_Y),
+ ureg_scalar(constant[1], TGSI_SWIZZLE_Y));
+ ureg_RCP(ureg, temp[2], ureg_src(temp[1]));
+ ureg_ADD(ureg, temp[1],
+ ureg_scalar(constant[1], TGSI_SWIZZLE_Y),
+ ureg_src(temp[2]));
+ ureg_ADD(ureg, ureg_writemask(temp[2], TGSI_WRITEMASK_X),
+ ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_X),
+ ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_Y));
+ ureg_ADD(ureg, ureg_writemask(temp[2], TGSI_WRITEMASK_X),
+ ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_Z),
+ ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_X));
+ ureg_SGE(ureg,
+ ureg_writemask(temp[0], TGSI_WRITEMASK_XYZ),
+ ureg_scalar(ureg_src(temp[2]), TGSI_SWIZZLE_X),
+ ureg_src(temp[1]));
+ ureg_SGE(ureg,
+ ureg_writemask(temp[0], TGSI_WRITEMASK_W),
+ ureg_scalar(ureg_src(temp[0]), TGSI_SWIZZLE_W),
+ ureg_scalar(ureg_src(temp[2]), TGSI_SWIZZLE_Y));
+ ureg_MOV(ureg, *out, ureg_src(temp[0]));
+}
+
+
+struct shader_asm_info {
+ VGint id;
+ ureg_func func;
+
+ 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, solid_fill,
+ VG_FALSE, 0, 1, 0, 0, 0, 0},
+ {VEGA_LINEAR_GRADIENT_SHADER, linear_grad,
+ VG_TRUE, 0, 5, 0, 1, 0, 5},
+ {VEGA_RADIAL_GRADIENT_SHADER, radial_grad,
+ VG_TRUE, 0, 5, 0, 1, 0, 6},
+ {VEGA_PATTERN_SHADER, pattern,
+ VG_TRUE, 1, 4, 0, 1, 0, 5},
+
+ /* image draw modes */
+ {VEGA_IMAGE_NORMAL_SHADER, image_normal,
+ VG_TRUE, 0, 0, 3, 1, 0, 0},
+ {VEGA_IMAGE_MULTIPLY_SHADER, image_multiply,
+ VG_TRUE, 0, 0, 3, 1, 0, 2},
+ {VEGA_IMAGE_STENCIL_SHADER, image_stencil,
+ VG_TRUE, 0, 0, 3, 1, 0, 2},
+
+ {VEGA_MASK_SHADER, mask,
+ VG_TRUE, 0, 0, 1, 1, 0, 2},
+
+ /* extra blend modes */
+ {VEGA_BLEND_MULTIPLY_SHADER, blend_multiply,
+ VG_TRUE, 1, 1, 2, 1, 0, 5},
+ {VEGA_BLEND_SCREEN_SHADER, blend_screen,
+ VG_TRUE, 0, 0, 2, 1, 0, 4},
+ {VEGA_BLEND_DARKEN_SHADER, blend_darken,
+ VG_TRUE, 1, 1, 2, 1, 0, 6},
+ {VEGA_BLEND_LIGHTEN_SHADER, blend_lighten,
+ VG_TRUE, 1, 1, 2, 1, 0, 6},
+
+ /* premultiply */
+ {VEGA_PREMULTIPLY_SHADER, premultiply,
+ VG_FALSE, 0, 0, 0, 0, 0, 1},
+ {VEGA_UNPREMULTIPLY_SHADER, unpremultiply,
+ VG_FALSE, 0, 0, 0, 0, 0, 1},
+
+ /* color transform to black and white */
+ {VEGA_BW_SHADER, color_bw,
+ 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..60bed197e2
--- /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[] =
+ "FRAG\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[] =
+ "FRAG\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[] =
+ "FRAG\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[] =
+ "FRAG\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..903bfc88a4
--- /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[] =
+ "FRAG\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[] =
+ "FRAG\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[] =
+ "FRAG\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[] =
+ "FRAG\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[] =
+ "FRAG\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[] =
+ "VERT\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[] =
+ "VERT\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[] =
+ "VERT\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..5769e8ea86
--- /dev/null
+++ b/src/gallium/state_trackers/vega/bezier.c
@@ -0,0 +1,706 @@
+/**************************************************************************
+ *
+ * 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;
+ float i;
+ for (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 i;
+ 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 (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..7c421dfcd4
--- /dev/null
+++ b/src/gallium/state_trackers/vega/image.c
@@ -0,0 +1,662 @@
+/**************************************************************************
+ *
+ * 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 "util/u_inlines.h"
+#include "util/u_blit.h"
+#include "util/u_format.h"
+#include "util/u_tile.h"
+#include "util/u_memory.h"
+#include "util/u_math.h"
+#include "util/u_sampler.h"
+
+static enum pipe_format vg_format_to_pipe(VGImageFormat format)
+{
+ switch(format) {
+ case VG_sRGB_565:
+ return PIPE_FORMAT_B5G6R5_UNORM;
+ case VG_sRGBA_5551:
+ return PIPE_FORMAT_B5G5R5A1_UNORM;
+ case VG_sRGBA_4444:
+ return PIPE_FORMAT_B4G4R4A4_UNORM;
+ case VG_sL_8:
+ case VG_lL_8:
+ return PIPE_FORMAT_L8_UNORM;
+ case VG_BW_1:
+ return PIPE_FORMAT_B8G8R8A8_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_B8G8R8A8_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_resource *dst, VGint dx, VGint dy,
+ struct pipe_sampler_view *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->width0;
+ dst_bounds[3] = dst->height0;
+
+ 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->texture->width0;
+ src_bounds[3] = src->texture->height0;
+
+ 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_resource *image_texture(struct vg_image *img)
+{
+ struct pipe_resource *tex = img->sampler_view->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 pipe_context *pipe = ctx->pipe;
+ struct vg_image *image = CALLOC_STRUCT(vg_image);
+ enum pipe_format pformat = vg_format_to_pipe(format);
+ struct pipe_resource pt, *newtex;
+ struct pipe_sampler_view view_templ;
+ struct pipe_sampler_view *view;
+ 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,
+ 0, PIPE_BIND_SAMPLER_VIEW, 0));
+
+ memset(&pt, 0, sizeof(pt));
+ pt.target = PIPE_TEXTURE_2D;
+ pt.format = pformat;
+ pt.last_level = 0;
+ pt.width0 = width;
+ pt.height0 = height;
+ pt.depth0 = 1;
+ pt.bind = PIPE_BIND_SAMPLER_VIEW;
+
+ newtex = screen->resource_create(screen, &pt);
+
+ debug_assert(newtex);
+
+ u_sampler_view_default_template(&view_templ, newtex, newtex->format);
+ view = pipe->create_sampler_view(pipe, newtex, &view_templ);
+ /* want the texture to go away if the view is freed */
+ pipe_resource_reference(&newtex, NULL);
+
+ image->sampler_view = view;
+
+ 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_sampler_view_reference(&img->sampler_view, 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_context *pipe = ctx->pipe;
+ struct pipe_resource *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 = pipe_get_transfer(
+ pipe, texture, 0, 0, 0,
+ PIPE_TRANSFER_WRITE, 0, 0, texture->width0, texture->height0);
+ src += (dataStride * yoffset);
+ for (i = 0; i < height; i++) {
+ _vega_unpack_float_span_rgba(ctx, width, xoffset, src, dataFormat, temp);
+ pipe_put_tile_rgba(pipe, transfer, x+image->x, y+image->y, width, 1, df);
+ y += yStep;
+ src += dataStride;
+ }
+ pipe->transfer_destroy(pipe, 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;
+ 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 =
+ pipe_get_transfer(pipe,
+ image->sampler_view->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(pipe, transfer, sx+image->x, y, width, 1, df);
+ y += yStep;
+ _vega_pack_rgba_span_float(ctx, width, temp, dataFormat, dst);
+ dst += dataStride;
+ }
+
+ pipe->transfer_destroy(pipe, 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->sampler_view = NULL;
+ pipe_sampler_view_reference(&image->sampler_view,
+ parent->sampler_view);
+
+ 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->sampler_view->texture, dst->x + dx, dst->y + dy,
+ src->sampler_view, 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,
+ 0 /* no bind flags as surf isn't actually used??? */);
+
+ 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,
+ 0 /* no bind flags as surf isn't actually used??? */);
+
+ 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_sampler_view **sampler_views)
+{
+ 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;
+ sampler_views[3] = img->sampler_view;
+ 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:
+ /* possibly use anisotropic filtering */
+ 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..a990c9c587
--- /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_resource;
+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_sampler_view *sampler_view;
+ 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_sampler_view **sampler_views);
+
+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..6d627b0e8d
--- /dev/null
+++ b/src/gallium/state_trackers/vega/mask.c
@@ -0,0 +1,697 @@
+/**************************************************************************
+ *
+ * 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 "util/u_inlines.h"
+#include "util/u_format.h"
+#include "util/u_memory.h"
+
+struct vg_mask_layer {
+ struct vg_object base;
+
+ VGint width;
+ VGint height;
+
+ struct pipe_sampler_view *sampler_view;
+};
+
+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_view->texture,
+ 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_BIND_TRANSFER_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_resource **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_resource_reference(cbuf, NULL);
+
+ *cbuf = pipe_buffer_create(ctx->pipe->screen,
+ PIPE_BIND_CONSTANT_BUFFER,
+ param_bytes);
+ if (*cbuf) {
+ st_no_flush_pipe_buffer_write(ctx, *cbuf,
+ 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_sampler_view *umask)
+{
+ struct vg_context *ctx = vg_current_context();
+ struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
+ struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS];
+ struct st_framebuffer *fb_buffers = ctx->draw_buffer;
+ struct pipe_sampler_view *uprev = NULL;
+ struct pipe_sampler_state sampler;
+
+ uprev = fb_buffers->blend_texture_view;
+ sampler = ctx->mask.sampler;
+ sampler.normalized_coords = 1;
+
+ samplers[0] = NULL;
+ samplers[1] = NULL;
+ sampler_views[0] = NULL;
+ sampler_views[1] = NULL;
+
+ samplers[0] = &sampler;
+ samplers[1] = &ctx->mask.sampler;
+
+ sampler_views[0] = umask;
+ sampler_views[1] = uprev;
+
+ cso_set_samplers(ctx->cso_context, 2,
+ (const struct pipe_sampler_state **)samplers);
+ cso_set_fragment_sampler_views(ctx->cso_context, 2, sampler_views);
+}
+
+
+/* setup shader constants */
+static void setup_mask_fill(const VGfloat color[4])
+{
+ struct vg_context *ctx = vg_current_context();
+ struct pipe_resource **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_resource_reference(cbuf, NULL);
+
+ *cbuf = pipe_buffer_create(ctx->pipe->screen,
+ PIPE_BIND_CONSTANT_BUFFER,
+ param_bytes);
+ if (*cbuf) {
+ st_no_flush_pipe_buffer_write(ctx, *cbuf, 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.rt[0].blend_enable = 0;
+ blend.rt[0].colormask = PIPE_MASK_RGBA;
+ blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ blend.rt[0].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_sampler_view *sampler_view,
+ VGMaskOperation operation,
+ VGint x, VGint y,
+ VGint width, VGint height)
+{
+ struct vg_context *ctx = vg_current_context();
+ struct pipe_resource *texture = sampler_view->texture;
+ struct pipe_surface *surface =
+ alpha_mask_surface(ctx, PIPE_BIND_RENDER_TARGET);
+ VGint offsets[4], loc[4];
+
+ if (!surface)
+ return;
+ if (!intersect_rectangles(surface->width, surface->height,
+ texture->width0, texture->height0,
+ 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_fragment_sampler_views(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(sampler_view);
+ 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_fragment_sampler_views(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_resource pt;
+ struct pipe_context *pipe = ctx->pipe;
+ struct pipe_screen *screen = ctx->pipe->screen;
+ struct pipe_sampler_view view_templ;
+ struct pipe_sampler_view *view = NULL;
+ struct pipe_resource *texture;
+
+ memset(&pt, 0, sizeof(pt));
+ pt.target = PIPE_TEXTURE_2D;
+ pt.format = PIPE_FORMAT_B8G8R8A8_UNORM;
+ pt.last_level = 0;
+ pt.width0 = width;
+ pt.height0 = height;
+ pt.depth0 = 1;
+ pt.bind = PIPE_BIND_SAMPLER_VIEW;
+ pt.compressed = 0;
+
+ texture = screen->resource_create(screen, &pt);
+
+ if (texture) {
+ u_sampler_view_default_template(&view_templ, texture, texture->format);
+ view = pipe->create_sampler_view(pipe, texture, &view_templ);
+ }
+ pipe_resource_reference(&texture, NULL);
+ mask->sampler_view = view;
+ }
+
+ 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_resource_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->sampler_view->texture,
+ 0, 0, 0,
+ PIPE_BIND_RENDER_TARGET);
+
+ 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->sampler_view,
+ sx, sy,
+ sx + width, sy + height,
+ fb_buffers->alpha_mask_view->texture,
+ 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->sampler_view->texture, 0, 0, 0,
+ PIPE_BIND_RENDER_TARGET);
+
+ 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_view->texture->width0;
+ height = fb_buffers->alpha_mask_view->texture->width0;
+
+ 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->sampler_view, 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->sampler_view, 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_BIND_RENDER_TARGET);
+
+#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_sampler_view **sampler_views)
+{
+ 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;
+ sampler_views[1] = fb_buffers->alpha_mask_view;
+ 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..c626402c86
--- /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_resource;
+
+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_sampler_view **sampler_views);
+
+#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..05540e8275
--- /dev/null
+++ b/src/gallium/state_trackers/vega/paint.c
@@ -0,0 +1,719 @@
+/**************************************************************************
+ *
+ * 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 "util/u_inlines.h"
+
+#include "util/u_format.h"
+#include "util/u_memory.h"
+#include "util/u_math.h"
+#include "util/u_sampler.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_sampler_view *sampler_view;
+ struct pipe_sampler_state sampler;
+
+ VGfloat *ramp_stops;
+ VGint *ramp_stopsi;
+ VGint num_stops;
+
+ VGboolean color_ramps_premultiplied;
+ } gradient;
+
+ struct {
+ struct pipe_sampler_view *sampler_view;
+ VGTilingMode tiling_mode;
+ struct pipe_sampler_state sampler;
+ } pattern;
+
+ /* XXX next 3 all unneded? */
+ struct pipe_resource *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_resource *create_gradient_texture(struct vg_paint *p)
+{
+ struct pipe_context *pipe = p->base.ctx->pipe;
+ struct pipe_screen *screen = pipe->screen;
+ struct pipe_resource *tex = 0;
+ struct pipe_resource templ;
+
+ memset(&templ, 0, sizeof(templ));
+ templ.target = PIPE_TEXTURE_1D;
+ templ.format = PIPE_FORMAT_B8G8R8A8_UNORM;
+ templ.last_level = 0;
+ templ.width0 = 1024;
+ templ.height0 = 1;
+ templ.depth0 = 1;
+ templ.bind = PIPE_BIND_SAMPLER_VIEW;
+
+ tex = screen->resource_create(screen, &templ);
+
+ { /* upload color_data */
+ struct pipe_transfer *transfer =
+ st_no_flush_get_transfer(p->base.ctx, tex, 0, 0, 0,
+ PIPE_TRANSFER_WRITE, 0, 0, 1024, 1);
+ void *map = pipe->transfer_map(pipe, transfer);
+ memcpy(map, p->gradient.color_data, sizeof(VGint)*1024);
+ pipe->transfer_unmap(pipe, transfer);
+ pipe->transfer_destroy(pipe, transfer);
+ }
+
+ return tex;
+}
+
+static INLINE struct pipe_sampler_view *create_gradient_sampler_view(struct vg_paint *p)
+{
+ struct pipe_context *pipe = p->base.ctx->pipe;
+ struct pipe_resource *texture;
+ struct pipe_sampler_view view_templ;
+ struct pipe_sampler_view *view;
+
+ texture = create_gradient_texture(p);
+
+ if (!texture)
+ return NULL;
+
+ u_sampler_view_default_template(&view_templ, texture, texture->format);
+ view = pipe->create_sampler_view(pipe, texture, &view_templ);
+ /* want the texture to go away if the view is freed */
+ pipe_resource_reference(&texture, NULL);
+
+ return view;
+}
+
+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;
+ pipe_sampler_view_reference(&paint->gradient.sampler_view, NULL);
+ if (paint->pattern.sampler_view)
+ pipe_sampler_view_reference(&paint->pattern.sampler_view, 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.sampler_view->texture->width0;
+ map[7] = paint->pattern.sampler_view->texture->height0;
+ {
+ 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.sampler_view) {
+ pipe_sampler_view_reference(&paint->gradient.sampler_view, NULL);
+ paint->gradient.sampler_view = NULL;
+ }
+
+ paint->gradient.sampler_view = create_gradient_sampler_view(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.sampler_view)
+ pipe_sampler_view_reference(&paint->pattern.sampler_view, NULL);
+
+ paint->pattern.sampler_view = NULL;
+ pipe_sampler_view_reference(&paint->pattern.sampler_view,
+ img->sampler_view);
+}
+
+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_sampler_view **sampler_views)
+{
+ 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.sampler_view) {
+ 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;
+ sampler_views[0] = paint->gradient.sampler_view;
+ 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;
+ sampler_views[0] = paint->pattern.sampler_view;
+ return 1;
+ }
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+void paint_resolve_type(struct vg_paint *paint)
+{
+ if (paint->type == VG_PAINT_TYPE_PATTERN &&
+ !paint->pattern.sampler_view) {
+ 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..012cd3e561
--- /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_resource;
+
+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_sampler_view **sampler_views);
+
+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..4fc23a7a27
--- /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, &pd->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..e9c8f03137
--- /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 "util/u_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_resource *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_resource_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->rt[0].colormask = 0; /*disable colorwrites*/
+
+ blend->rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend->rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
+ blend->rt[0].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_resource_reference(&poly->vbuf,
+ NULL);
+ }
+ poly->screen = pipe->screen;
+ poly->vbuf= pipe_user_buffer_create(poly->screen,
+ poly->data,
+ vert_size,
+ PIPE_BIND_VERTEX_BUFFER);
+ 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 */
+ memset(&velement, 0, sizeof(velement));
+ velement.src_offset = 0;
+ velement.instance_divisor = 0;
+ velement.vertex_buffer_index = 0;
+ velement.src_format = PIPE_FORMAT_R32G32_FLOAT;
+ cso_set_vertex_elements(ctx->cso_context, 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_stencil_ref sr;
+ 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));
+ memset(&sr, 0, sizeof(struct pipe_stencil_ref));
+ /* only need a fixed 0. Rely on default or move it out at least? */
+ cso_set_stencil_ref(ctx->cso_context, &sr);
+
+ 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].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].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].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].valuemask = ~0;
+
+ raster.cull_face = PIPE_FACE_BACK;
+ 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_face = PIPE_FACE_FRONT;
+ 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].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_stencil_ref sr;
+ 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));
+ memset(&sr, 0, sizeof(struct pipe_stencil_ref));
+ /* only need a fixed 0. Rely on default or move it out at least? */
+ cso_set_stencil_ref(ctx->cso_context, &sr);
+
+ 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].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].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].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].valuemask = ~0;
+
+ raster.cull_face = PIPE_FACE_BACK;
+ 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_face = PIPE_FACE_FRONT;
+ 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].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..c40ea8675e
--- /dev/null
+++ b/src/gallium/state_trackers/vega/renderer.c
@@ -0,0 +1,613 @@
+/**************************************************************************
+ *
+ * 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 "util/u_inlines.h"
+#include "pipe/p_screen.h"
+#include "pipe/p_shader_tokens.h"
+
+#include "util/u_draw_quad.h"
+#include "util/u_format.h"
+#include "util/u_simple_shaders.h"
+#include "util/u_memory.h"
+#include "util/u_rect.h"
+#include "util/u_sampler.h"
+#include "util/u_surface.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, TGSI_TEXTURE_2D,
+ TGSI_INTERPOLATE_LINEAR);
+}
+
+static struct pipe_resource *
+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),
+ PIPE_BIND_VERTEX_BUFFER);
+}
+
+static struct pipe_resource *
+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),
+ PIPE_BIND_VERTEX_BUFFER);
+}
+
+
+static struct pipe_resource *
+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),
+ PIPE_BIND_VERTEX_BUFFER);
+}
+
+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_resource *buf;
+
+ buf = setup_vertex_data(r, x1, y1, x2, y2, depth);
+
+ if (buf) {
+ cso_set_vertex_elements(r->cso, 2, r->owner->velems);
+ util_draw_vertex_buffer(r->pipe, buf, 0,
+ PIPE_PRIM_TRIANGLE_FAN,
+ 4, /* verts */
+ 2); /* attribs/vert */
+
+ pipe_resource_reference( &buf,
+ NULL );
+ }
+}
+
+void renderer_draw_texture(struct renderer *r,
+ struct pipe_resource *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_resource *buf;
+ VGfloat s0, t0, s1, t1;
+
+ assert(tex->width0 != 0);
+ assert(tex->height0 != 0);
+
+ s0 = x1offset / tex->width0;
+ s1 = x2offset / tex->width0;
+ t0 = y1offset / tex->height0;
+ t1 = y2offset / tex->height0;
+
+ 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) {
+ cso_set_vertex_elements(r->cso, 2, r->owner->velems);
+ util_draw_vertex_buffer(pipe, buf, 0,
+ PIPE_PRIM_TRIANGLE_FAN,
+ 4, /* verts */
+ 2); /* attribs/vert */
+
+ pipe_resource_reference( &buf,
+ NULL );
+ }
+
+ cso_restore_vertex_shader(r->cso);
+}
+
+void renderer_copy_texture(struct renderer *ctx,
+ struct pipe_sampler_view *src,
+ VGfloat sx1, VGfloat sy1,
+ VGfloat sx2, VGfloat sy2,
+ struct pipe_resource *dst,
+ VGfloat dx1, VGfloat dy1,
+ VGfloat dx2, VGfloat dy2)
+{
+ struct pipe_context *pipe = ctx->pipe;
+ struct pipe_screen *screen = pipe->screen;
+ struct pipe_resource *tex = src->texture;
+ struct pipe_resource *buf;
+ struct pipe_surface *dst_surf = screen->get_tex_surface(
+ screen, dst, 0, 0, 0,
+ PIPE_BIND_RENDER_TARGET);
+ struct pipe_framebuffer_state fb;
+ float s0, t0, s1, t1;
+
+ assert(tex->width0 != 0);
+ assert(tex->height0 != 0);
+ assert(dst->width0 != 0);
+ assert(dst->height0 != 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 / tex->width0;
+ s1 = sx2 / tex->width0;
+ t0 = sy1 / tex->height0;
+ t1 = sy2 / tex->height0;
+#else
+ s0 = 0;
+ s1 = 1;
+ t0 = 0;
+ t1 = 1;
+#endif
+
+ assert(screen->is_format_supported(screen, dst_surf->format, PIPE_TEXTURE_2D,
+ 0, PIPE_BIND_RENDER_TARGET, 0));
+
+ /* save state (restored below) */
+ cso_save_blend(ctx->cso);
+ cso_save_samplers(ctx->cso);
+ cso_save_fragment_sampler_views(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.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ blend.rt[0].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_fragment_sampler_views(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) {
+ cso_set_vertex_elements(ctx->cso, 2, ctx->owner->velems);
+ util_draw_vertex_buffer(ctx->pipe, buf, 0,
+ PIPE_PRIM_TRIANGLE_FAN,
+ 4, /* verts */
+ 2); /* attribs/vert */
+
+ pipe_resource_reference( &buf,
+ NULL );
+ }
+
+ /* restore state we changed */
+ cso_restore_blend(ctx->cso);
+ cso_restore_samplers(ctx->cso);
+ cso_restore_fragment_sampler_views(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_resource *buf;
+ struct pipe_sampler_view view_templ;
+ struct pipe_sampler_view *view;
+ struct pipe_resource texTemp, *tex;
+ struct pipe_subresource subsrc, subdst;
+ 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,
+ 0, PIPE_BIND_SAMPLER_VIEW, 0));
+ assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D,
+ 0, PIPE_BIND_SAMPLER_VIEW, 0));
+ assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D,
+ 0, PIPE_BIND_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.width0 = srcW;
+ texTemp.height0 = srcH;
+ texTemp.depth0 = 1;
+ texTemp.bind = PIPE_BIND_SAMPLER_VIEW;
+
+ tex = screen->resource_create(screen, &texTemp);
+ if (!tex)
+ return;
+
+ u_sampler_view_default_template(&view_templ, tex, tex->format);
+ view = pipe->create_sampler_view(pipe, tex, &view_templ);
+
+ if (!view)
+ return;
+
+ subdst.face = 0;
+ subdst.level = 0;
+ subsrc.face = src->face;
+ subsrc.level = src->level;
+
+ pipe->resource_copy_region(pipe,
+ tex, subdst, 0, 0, 0, /* dest */
+ src->texture, subsrc, srcLeft, srcTop, src->zslice, /* src */
+ srcW, srcH); /* size */
+
+ /* save state (restored below) */
+ cso_save_blend(ctx->cso);
+ cso_save_samplers(ctx->cso);
+ cso_save_fragment_sampler_views(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.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ blend.rt[0].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_fragment_sampler_views(ctx->cso, 1, &view);
+
+ /* 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) {
+ cso_set_vertex_elements(ctx->cso, 2, ctx->owner->velems);
+ util_draw_vertex_buffer(ctx->pipe, buf, 0,
+ PIPE_PRIM_TRIANGLE_FAN,
+ 4, /* verts */
+ 2); /* attribs/vert */
+
+ pipe_resource_reference( &buf,
+ NULL );
+ }
+
+
+ /* restore state we changed */
+ cso_restore_blend(ctx->cso);
+ cso_restore_samplers(ctx->cso);
+ cso_restore_fragment_sampler_views(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_resource_reference(&tex, NULL);
+ pipe_sampler_view_reference(&view, NULL);
+}
+
+void renderer_texture_quad(struct renderer *r,
+ struct pipe_resource *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_resource *buf;
+ VGfloat s0, t0, s1, t1;
+
+ assert(tex->width0 != 0);
+ assert(tex->height0 != 0);
+
+ s0 = x1offset / tex->width0;
+ s1 = x2offset / tex->width0;
+ t0 = y1offset / tex->height0;
+ t1 = y2offset / tex->height0;
+
+ 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) {
+ cso_set_vertex_elements(r->cso, 2, r->owner->velems);
+ util_draw_vertex_buffer(pipe, buf, 0,
+ PIPE_PRIM_TRIANGLE_FAN,
+ 4, /* verts */
+ 2); /* attribs/vert */
+
+ pipe_resource_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..b1a9fb58be
--- /dev/null
+++ b/src/gallium/state_trackers/vega/renderer.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 RENDERER_H
+#define RENDERER_H
+
+#include "VG/openvg.h"
+
+struct renderer;
+
+struct vg_context;
+struct pipe_resource;
+struct pipe_sampler_view;
+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_resource *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_resource *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_sampler_view *src,
+ VGfloat sx1, VGfloat sy1,
+ VGfloat sx2, VGfloat sy2,
+ struct pipe_resource *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..6eef94ce76
--- /dev/null
+++ b/src/gallium/state_trackers/vega/shader.c
@@ -0,0 +1,311 @@
+/**************************************************************************
+ *
+ * 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 "util/u_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_resource *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_resource **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 == NULL ||
+ memcmp(temp_buf, shader->constants, param_bytes) != 0)
+ {
+ pipe_resource_reference(cbuf, NULL);
+
+ memcpy(shader->constants, temp_buf, param_bytes);
+ *cbuf = pipe_user_buffer_create(pipe->screen,
+ &shader->constants,
+ sizeof(shader->constants),
+ PIPE_BIND_VERTEX_BUFFER);
+ }
+
+ 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_sampler_view **sampler_views)
+{
+ 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;
+ sampler_views[2] = stfb->blend_texture_view;
+
+ if (!samplers[0] || !sampler_views[0]) {
+ samplers[0] = samplers[2];
+ sampler_views[0] = sampler_views[2];
+ }
+ if (!samplers[1] || !sampler_views[1]) {
+ samplers[1] = samplers[0];
+ sampler_views[1] = sampler_views[0];
+ }
+
+ return 1;
+ }
+ return 0;
+}
+
+static void setup_samplers(struct shader *shader)
+{
+ struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
+ struct pipe_sampler_view *sampler_views[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;
+ sampler_views[0] = NULL;
+ sampler_views[1] = NULL;
+ sampler_views[2] = NULL;
+ sampler_views[3] = NULL;
+
+ num += paint_bind_samplers(shader->paint, samplers, sampler_views);
+ num += mask_bind_samplers(samplers, sampler_views);
+ num += blend_bind_samplers(ctx, samplers, sampler_views);
+ if (shader->drawing_image && shader->image)
+ num += image_bind_samplers(shader->image, samplers, sampler_views);
+
+ if (num) {
+ cso_set_samplers(ctx->cso_context, 4, (const struct pipe_sampler_state **)samplers);
+ cso_set_fragment_sampler_views(ctx->cso_context, 4, sampler_views);
+ }
+}
+
+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..f43fe6ee4c
--- /dev/null
+++ b/src/gallium/state_trackers/vega/shaders_cache.c
@@ -0,0 +1,440 @@
+/**************************************************************************
+ *
+ * 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 "util/u_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[] =
+ "FRAG\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 *
+combine_shaders(const struct shader_asm_info *shaders[SHADER_STAGES], int num_shaders,
+ struct pipe_context *pipe,
+ struct pipe_shader_state *shader)
+{
+ 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, current_shader = 0;
+ VGint num_consts, num_temps, num_samplers;
+ struct ureg_program *ureg;
+ struct ureg_src in[2];
+ struct ureg_src *sampler = NULL;
+ struct ureg_src *constant = NULL;
+ struct ureg_dst out, *temp = NULL;
+ void *p = NULL;
+
+ 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;
+
+ ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT);
+ if (!ureg)
+ return NULL;
+
+ if (declare_input) {
+ in[0] = ureg_DECL_fs_input(ureg,
+ TGSI_SEMANTIC_POSITION,
+ 0,
+ TGSI_INTERPOLATE_LINEAR);
+ in[1] = ureg_DECL_fs_input(ureg,
+ TGSI_SEMANTIC_GENERIC,
+ 0,
+ TGSI_INTERPOLATE_PERSPECTIVE);
+ }
+
+ /* we always have a color output */
+ out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0);
+
+ if (num_consts >= 1) {
+ constant = (struct ureg_src *) malloc(sizeof(struct ureg_src) * end_const);
+ for (i = start_const; i < end_const; i++) {
+ constant[i] = ureg_DECL_constant(ureg, i);
+ }
+
+ }
+
+ if (num_temps >= 1) {
+ temp = (struct ureg_dst *) malloc(sizeof(struct ureg_dst) * end_temp);
+ for (i = start_temp; i < end_temp; i++) {
+ temp[i] = ureg_DECL_temporary(ureg);
+ }
+ }
+
+ if (num_samplers >= 1) {
+ sampler = (struct ureg_src *) malloc(sizeof(struct ureg_src) * end_sampler);
+ for (i = start_sampler; i < end_sampler; i++) {
+ sampler[i] = ureg_DECL_sampler(ureg, i);
+ }
+ }
+
+ while (current_shader < num_shaders) {
+ if ((current_shader + 1) == num_shaders) {
+ shaders[current_shader]->func(ureg,
+ &out,
+ in,
+ sampler,
+ temp,
+ constant);
+ } else {
+ shaders[current_shader]->func(ureg,
+ &temp[0],
+ in,
+ sampler,
+ temp,
+ constant);
+ }
+ current_shader++;
+ }
+
+ ureg_END(ureg);
+
+ shader->tokens = ureg_finalize(ureg);
+ if(!shader->tokens)
+ return NULL;
+
+ p = pipe->create_fs_state(pipe, shader);
+ ureg_destroy(ureg);
+
+ if (num_temps >= 1) {
+ for (i = start_temp; i < end_temp; i++) {
+ ureg_release_temporary(ureg, temp[i]);
+ }
+ }
+
+ if (temp)
+ free(temp);
+ if (constant)
+ free(constant);
+ if (sampler)
+ free(sampler);
+
+ return p;
+}
+
+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..7eaa67c76a
--- /dev/null
+++ b/src/gallium/state_trackers/vega/st_inlines.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.
+ *
+ **************************************************************************/
+
+/**
+ * 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 "util/u_inlines.h"
+#include "pipe/p_state.h"
+
+static INLINE struct pipe_transfer *
+st_cond_flush_get_transfer(struct vg_context *st,
+ struct pipe_resource *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_context *pipe = st->pipe;
+
+ return pipe_get_transfer(pipe, pt, face, level, zslice, usage,
+ x, y, w, h);
+}
+
+static INLINE struct pipe_transfer *
+st_no_flush_get_transfer(struct vg_context *st,
+ struct pipe_resource *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_context *pipe = st->pipe;
+
+ return pipe_get_transfer(pipe, pt, face, level,
+ zslice, usage, x, y, w, h);
+}
+
+
+static INLINE void
+st_cond_flush_pipe_buffer_write(struct vg_context *st,
+ struct pipe_resource *buf,
+ unsigned int offset,
+ unsigned int size,
+ const void * data)
+{
+ struct pipe_context *pipe = st->pipe;
+
+ pipe_buffer_write(pipe, buf, offset, size, data);
+}
+
+static INLINE void
+st_no_flush_pipe_buffer_write(struct vg_context *st,
+ struct pipe_resource *buf,
+ unsigned int offset,
+ unsigned int size,
+ const void * data)
+{
+ pipe_buffer_write(st->pipe, buf, offset, size, data);
+}
+
+static INLINE void
+st_cond_flush_pipe_buffer_read(struct vg_context *st,
+ struct pipe_resource *buf,
+ unsigned int offset,
+ unsigned int size,
+ void * data)
+{
+ struct pipe_context *pipe = st->pipe;
+
+ pipe_buffer_read(pipe, buf, offset, size, data);
+}
+
+static INLINE void
+st_no_flush_pipe_buffer_read(struct vg_context *st,
+ struct pipe_resource *buf,
+ unsigned int offset,
+ unsigned int size,
+ void * data)
+{
+ pipe_buffer_read(st->pipe, 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..d89b6cf25c
--- /dev/null
+++ b/src/gallium/state_trackers/vega/stroker.c
@@ -0,0 +1,1350 @@
+/**************************************************************************
+ *
+ * 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 "util/u_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] = { 0 };
+ 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] = { 0 };
+ 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)
+{
+#define 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;
+ }
+#undef MAX_OFFSET
+}
+
+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..b2d22f476e
--- /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_api.h b/src/gallium/state_trackers/vega/vg_api.h
new file mode 100644
index 0000000000..ce2a0d6bb4
--- /dev/null
+++ b/src/gallium/state_trackers/vega/vg_api.h
@@ -0,0 +1,37 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.9
+ *
+ * Copyright (C) 2010 LunarG Inc.
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Chia-I Wu <olv@lunarg.com>
+ */
+
+#ifndef VG_API_H
+#define VG_API_H
+
+struct st_api;
+
+const struct st_api *
+vg_api_get(void);
+
+#endif /* VG_API_H */
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..f02db8949d
--- /dev/null
+++ b/src/gallium/state_trackers/vega/vg_context.c
@@ -0,0 +1,568 @@
+/**************************************************************************
+ *
+ * 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 "vg_manager.h"
+#include "api.h"
+
+#include "pipe/p_context.h"
+#include "util/u_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"
+#include "util/u_sampler.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;
+ api_make_dispatch_current((ctx) ? ctx->dispatch : NULL);
+}
+
+struct vg_context * vg_create_context(struct pipe_context *pipe,
+ const void *visual,
+ struct vg_context *share)
+{
+ struct vg_context *ctx;
+ unsigned i;
+
+ ctx = CALLOC_STRUCT(vg_context);
+
+ ctx->pipe = pipe;
+
+ ctx->dispatch = api_create_dispatch();
+
+ 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;
+
+ for (i = 0; i < 2; i++) {
+ ctx->velems[i].src_offset = i * 4 * sizeof(float);
+ ctx->velems[i].instance_divisor = 0;
+ ctx->velems[i].vertex_buffer_index = 0;
+ ctx->velems[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
+ }
+
+ 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_resource **cbuf = &ctx->mask.cbuf;
+ struct pipe_resource **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)
+ pipe_resource_reference(cbuf, NULL);
+
+ if (*vsbuf)
+ pipe_resource_reference(vsbuf, 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]);
+
+ api_destroy_dispatch(ctx->dispatch);
+
+ 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;
+ int i;
+
+ 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->rt[0].colormask = 0; /*disable colorwrites*/
+ cso_set_blend(ctx->cso_context, blend);
+
+ /* enable scissoring */
+ for (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);
+ }
+
+ 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)
+{
+ vg_manager_validate_framebuffer(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->rt[0].blend_enable = 1;
+ blend->rt[0].colormask = PIPE_MASK_RGBA;
+
+ switch (ctx->state.vg.blend_mode) {
+ case VG_BLEND_SRC:
+ blend->rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend->rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ blend->rt[0].blend_enable = 0;
+ break;
+ case VG_BLEND_SRC_OVER:
+ blend->rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
+ blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend->rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
+ blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
+ break;
+ case VG_BLEND_DST_OVER:
+ blend->rt[0].rgb_src_factor = PIPE_BLENDFACTOR_INV_DST_ALPHA;
+ blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_INV_DST_ALPHA;
+ blend->rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_DST_ALPHA;
+ blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_DST_ALPHA;
+ break;
+ case VG_BLEND_SRC_IN:
+ blend->rt[0].rgb_src_factor = PIPE_BLENDFACTOR_DST_ALPHA;
+ blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_DST_ALPHA;
+ blend->rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ break;
+ case VG_BLEND_DST_IN:
+ blend->rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ZERO;
+ blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ZERO;
+ blend->rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
+ blend->rt[0].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->rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend->rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ blend->rt[0].blend_enable = 0;
+ break;
+ case VG_BLEND_ADDITIVE:
+ blend->rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend->rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ONE;
+ blend->rt[0].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_resource **cbuf = &ctx->vs_const_buffer;
+
+ vg_set_viewport(ctx, VEGA_Y0_BOTTOM);
+
+ pipe_resource_reference(cbuf, NULL);
+ *cbuf = pipe_buffer_create(ctx->pipe->screen,
+ PIPE_BIND_CONSTANT_BUFFER,
+ param_bytes);
+
+ if (*cbuf) {
+ st_no_flush_pipe_buffer_write(ctx, *cbuf,
+ 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 pipe_sampler_view *view;
+ struct pipe_sampler_view view_templ;
+ struct st_framebuffer *stfb = ctx->draw_buffer;
+ struct st_renderbuffer *strb = stfb->strb;
+
+ /* first finish all pending rendering */
+ vgFinish();
+
+ u_sampler_view_default_template(&view_templ, strb->texture, strb->texture->format);
+ view = pipe->create_sampler_view(pipe, strb->texture, &view_templ);
+
+ dest_surface = pipe->screen->get_tex_surface(pipe->screen,
+ stfb->blend_texture_view->texture,
+ 0, 0, 0,
+ PIPE_BIND_RENDER_TARGET);
+ /* flip it, because we want to use it as a sampler */
+ util_blit_pixels_tex(ctx->blit,
+ view,
+ 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();
+
+ pipe_sampler_view_reference(&view, NULL);
+}
+
+
+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_view->texture,
+ 0, 0, 0,
+ PIPE_BIND_RENDER_TARGET);
+
+ /* flip it, because we want to use it as a sampler */
+ util_blit_pixels_tex(ctx->blit,
+ stfb->alpha_mask_view,
+ 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..7b59ad512a
--- /dev/null
+++ b/src/gallium/state_trackers/vega/vg_context.h
@@ -0,0 +1,303 @@
+/**************************************************************************
+ *
+ * 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 "state_tracker/st_api.h"
+
+#include "cso_cache/cso_hash.h"
+#include "cso_cache/cso_context.h"
+
+struct renderer;
+struct shaders_cache;
+struct shader;
+struct vg_shader;
+struct mapi_table;
+
+struct st_renderbuffer {
+ enum pipe_format format;
+ struct pipe_surface *surface;
+ struct pipe_resource *texture;
+ VGint width, height;
+};
+
+struct st_framebuffer {
+ VGint width, height;
+ struct st_renderbuffer *strb;
+ struct st_renderbuffer *dsrb;
+
+ struct pipe_sampler_view *alpha_mask_view;
+
+ struct pipe_sampler_view *blend_texture_view;
+
+
+ struct st_framebuffer_iface *iface;
+ enum st_attachment_type strb_att;
+
+ 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 st_context_iface iface;
+ struct mapi_table *dispatch;
+
+ 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;
+ int32_t draw_buffer_invalid;
+
+ 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_resource *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_resource *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_resource *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_resource *vs_const_buffer;
+ struct pipe_vertex_element velems[2];
+};
+
+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_manager.c b/src/gallium/state_trackers/vega/vg_manager.c
new file mode 100644
index 0000000000..3b04816df0
--- /dev/null
+++ b/src/gallium/state_trackers/vega/vg_manager.c
@@ -0,0 +1,552 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.9
+ *
+ * Copyright 2009 VMware, Inc. All Rights Reserved.
+ * Copyright (C) 2010 LunarG Inc.
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Chia-I Wu <olv@lunarg.com>
+ */
+
+#include "state_tracker/st_api.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_screen.h"
+#include "util/u_memory.h"
+#include "util/u_inlines.h"
+#include "util/u_format.h"
+#include "util/u_sampler.h"
+
+#include "vg_api.h"
+#include "vg_manager.h"
+#include "vg_context.h"
+#include "image.h"
+#include "mask.h"
+#include "api.h"
+
+static struct pipe_resource *
+create_texture(struct pipe_context *pipe, enum pipe_format format,
+ VGint width, VGint height)
+{
+ struct pipe_resource templ;
+
+ memset(&templ, 0, sizeof(templ));
+
+ if (format != PIPE_FORMAT_NONE) {
+ templ.format = format;
+ }
+ else {
+ templ.format = PIPE_FORMAT_B8G8R8A8_UNORM;
+ }
+
+ templ.target = PIPE_TEXTURE_2D;
+ templ.width0 = width;
+ templ.height0 = height;
+ templ.depth0 = 1;
+ templ.last_level = 0;
+
+ if (util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 1)) {
+ templ.bind = PIPE_BIND_DEPTH_STENCIL;
+ } else {
+ templ.bind = (PIPE_BIND_DISPLAY_TARGET |
+ PIPE_BIND_RENDER_TARGET |
+ PIPE_BIND_SAMPLER_VIEW);
+ }
+
+ return pipe->screen->resource_create(pipe->screen, &templ);
+}
+
+static struct pipe_sampler_view *
+create_tex_and_view(struct pipe_context *pipe, enum pipe_format format,
+ VGint width, VGint height)
+{
+ struct pipe_resource *texture;
+ struct pipe_sampler_view view_templ;
+ struct pipe_sampler_view *view;
+
+ texture = create_texture(pipe, format, width, height);
+
+ if (!texture)
+ return NULL;
+
+ u_sampler_view_default_template(&view_templ, texture, texture->format);
+ view = pipe->create_sampler_view(pipe, texture, &view_templ);
+ /* want the texture to go away if the view is freed */
+ pipe_resource_reference(&texture, NULL);
+
+ return view;
+}
+
+static void
+setup_new_alpha_mask(struct vg_context *ctx, struct st_framebuffer *stfb)
+{
+ struct pipe_context *pipe = ctx->pipe;
+ struct pipe_sampler_view *old_sampler_view = stfb->alpha_mask_view;
+
+ /*
+ we use PIPE_FORMAT_B8G8R8A8_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_view = create_tex_and_view(pipe,
+ PIPE_FORMAT_B8G8R8A8_UNORM, stfb->width, stfb->height);
+
+ if (!stfb->alpha_mask_view) {
+ if (old_sampler_view)
+ pipe_sampler_view_reference(&old_sampler_view, NULL);
+ return;
+ }
+
+ /* XXX could this call be avoided? */
+ vg_validate_state(ctx);
+
+ /* alpha mask starts with 1.f alpha */
+ mask_fill(0, 0, stfb->width, stfb->height, 1.f);
+
+ /* if we had an old surface copy it over */
+ if (old_sampler_view) {
+ struct pipe_subresource subsurf, subold_surf;
+ subsurf.face = 0;
+ subsurf.level = 0;
+ subold_surf.face = 0;
+ subold_surf.level = 0;
+ pipe->resource_copy_region(pipe,
+ stfb->alpha_mask_view->texture,
+ subsurf,
+ 0, 0, 0,
+ old_sampler_view->texture,
+ subold_surf,
+ 0, 0, 0,
+ MIN2(old_sampler_view->texture->width0,
+ stfb->alpha_mask_view->texture->width0),
+ MIN2(old_sampler_view->texture->height0,
+ stfb->alpha_mask_view->texture->height0));
+ }
+
+ /* Free the old texture
+ */
+ if (old_sampler_view)
+ pipe_sampler_view_reference(&old_sampler_view, NULL);
+}
+
+static boolean
+vg_context_update_depth_stencil_rb(struct vg_context * ctx,
+ uint width, uint height)
+{
+ struct st_renderbuffer *dsrb = ctx->draw_buffer->dsrb;
+ struct pipe_context *pipe = ctx->pipe;
+ unsigned surface_usage;
+
+ if ((dsrb->width == width && dsrb->height == height) && dsrb->texture)
+ return FALSE;
+
+ /* unreference existing ones */
+ pipe_surface_reference(&dsrb->surface, NULL);
+ pipe_resource_reference(&dsrb->texture, NULL);
+ dsrb->width = dsrb->height = 0;
+
+ /* Probably need dedicated flags for surface usage too:
+ */
+ surface_usage = PIPE_BIND_DEPTH_STENCIL; /* XXX: was: RENDER_TARGET */
+
+ dsrb->texture = create_texture(pipe, dsrb->format, width, height);
+ if (!dsrb->texture)
+ return TRUE;
+
+ dsrb->surface = pipe->screen->get_tex_surface(pipe->screen,
+ dsrb->texture,
+ 0, 0, 0,
+ surface_usage);
+ if (!dsrb->surface) {
+ pipe_resource_reference(&dsrb->texture, NULL);
+ return TRUE;
+ }
+
+ dsrb->width = width;
+ dsrb->height = height;
+
+ assert(dsrb->surface->width == width);
+ assert(dsrb->surface->height == height);
+
+ return TRUE;
+}
+
+static boolean
+vg_context_update_color_rb(struct vg_context *ctx, struct pipe_resource *pt)
+{
+ struct st_renderbuffer *strb = ctx->draw_buffer->strb;
+ struct pipe_screen *screen = ctx->pipe->screen;
+
+ if (strb->texture == pt) {
+ pipe_resource_reference(&pt, NULL);
+ return FALSE;
+ }
+
+ /* unreference existing ones */
+ pipe_surface_reference(&strb->surface, NULL);
+ pipe_resource_reference(&strb->texture, NULL);
+ strb->width = strb->height = 0;
+
+ strb->texture = pt;
+ strb->surface = screen->get_tex_surface(screen, strb->texture, 0, 0, 0,
+ PIPE_BIND_RENDER_TARGET);
+ if (!strb->surface) {
+ pipe_resource_reference(&strb->texture, NULL);
+ return TRUE;
+ }
+
+ strb->width = pt->width0;
+ strb->height = pt->height0;
+
+ return TRUE;
+}
+
+static void
+vg_context_update_draw_buffer(struct vg_context *ctx, struct pipe_resource *pt)
+{
+ struct st_framebuffer *stfb = ctx->draw_buffer;
+ boolean new_cbuf, new_zsbuf, new_size;
+
+ new_cbuf = vg_context_update_color_rb(ctx, pt);
+ new_zsbuf =
+ vg_context_update_depth_stencil_rb(ctx, pt->width0, pt->height0);
+
+ new_size = (stfb->width != pt->width0 || stfb->height != pt->height0);
+ stfb->width = pt->width0;
+ stfb->height = pt->height0;
+
+ if (new_cbuf || new_zsbuf || new_size) {
+ struct pipe_framebuffer_state *state = &ctx->state.g3d.fb;
+
+ memset(state, 0, sizeof(struct pipe_framebuffer_state));
+ state->width = stfb->width;
+ state->height = stfb->height;
+ state->nr_cbufs = 1;
+ state->cbufs[0] = stfb->strb->surface;
+ state->zsbuf = stfb->dsrb->surface;
+
+ cso_set_framebuffer(ctx->cso_context, state);
+ }
+
+ if (new_zsbuf || new_size) {
+ 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);
+
+ pipe_sampler_view_reference( &stfb->blend_texture_view, NULL);
+ stfb->blend_texture_view = create_tex_and_view(ctx->pipe,
+ PIPE_FORMAT_B8G8R8A8_UNORM, stfb->width, stfb->height);
+ }
+}
+
+/**
+ * Flush the front buffer if the current context renders to the front buffer.
+ */
+void
+vg_manager_flush_frontbuffer(struct vg_context *ctx)
+{
+ struct st_framebuffer *stfb = ctx->draw_buffer;
+
+ if (!stfb)
+ return;
+
+ switch (stfb->strb_att) {
+ case ST_ATTACHMENT_FRONT_LEFT:
+ case ST_ATTACHMENT_FRONT_RIGHT:
+ stfb->iface->flush_front(stfb->iface, stfb->strb_att);
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * Re-validate the framebuffer.
+ */
+void
+vg_manager_validate_framebuffer(struct vg_context *ctx)
+{
+ struct st_framebuffer *stfb = ctx->draw_buffer;
+ struct pipe_resource *pt;
+
+ /* no binding surface */
+ if (!stfb)
+ return;
+
+ if (!p_atomic_read(&ctx->draw_buffer_invalid))
+ return;
+
+ /* validate the fb */
+ if (!stfb->iface->validate(stfb->iface, &stfb->strb_att, 1, &pt) || !pt)
+ return;
+
+ /*
+ * unset draw_buffer_invalid first because vg_context_update_draw_buffer
+ * will cause the framebuffer to be validated again because of a call to
+ * vg_validate_state
+ */
+ p_atomic_set(&ctx->draw_buffer_invalid, FALSE);
+ vg_context_update_draw_buffer(ctx, pt);
+}
+
+
+static void
+vg_context_notify_invalid_framebuffer(struct st_context_iface *stctxi,
+ struct st_framebuffer_iface *stfbi)
+{
+ struct vg_context *ctx = (struct vg_context *) stctxi;
+ p_atomic_set(&ctx->draw_buffer_invalid, TRUE);
+}
+
+static void
+vg_context_flush(struct st_context_iface *stctxi, unsigned flags,
+ struct pipe_fence_handle **fence)
+{
+ struct vg_context *ctx = (struct vg_context *) stctxi;
+ ctx->pipe->flush(ctx->pipe, flags, fence);
+ if (flags & PIPE_FLUSH_RENDER_CACHE)
+ vg_manager_flush_frontbuffer(ctx);
+}
+
+static void
+vg_context_destroy(struct st_context_iface *stctxi)
+{
+ struct vg_context *ctx = (struct vg_context *) stctxi;
+ vg_destroy_context(ctx);
+}
+
+static struct st_context_iface *
+vg_api_create_context(struct st_api *stapi, struct st_manager *smapi,
+ const struct st_visual *visual,
+ struct st_context_iface *shared_stctxi)
+{
+ struct vg_context *shared_ctx = (struct vg_context *) shared_stctxi;
+ struct vg_context *ctx;
+ struct pipe_context *pipe;
+
+ pipe = smapi->screen->context_create(smapi->screen, NULL);
+ if (!pipe)
+ return NULL;
+ ctx = vg_create_context(pipe, NULL, shared_ctx);
+ if (!ctx) {
+ pipe->destroy(pipe);
+ return NULL;
+ }
+
+ ctx->iface.destroy = vg_context_destroy;
+
+ ctx->iface.notify_invalid_framebuffer =
+ vg_context_notify_invalid_framebuffer;
+ ctx->iface.flush = vg_context_flush;
+
+ ctx->iface.teximage = NULL;
+ ctx->iface.copy = NULL;
+
+ ctx->iface.st_context_private = (void *) smapi;
+
+ return &ctx->iface;
+}
+
+static struct st_renderbuffer *
+create_renderbuffer(enum pipe_format format)
+{
+ struct st_renderbuffer *strb;
+
+ strb = CALLOC_STRUCT(st_renderbuffer);
+ if (strb)
+ strb->format = format;
+
+ return strb;
+}
+
+static void
+destroy_renderbuffer(struct st_renderbuffer *strb)
+{
+ pipe_surface_reference(&strb->surface, NULL);
+ pipe_resource_reference(&strb->texture, NULL);
+ free(strb);
+}
+
+/**
+ * Decide the buffer to render to.
+ */
+static enum st_attachment_type
+choose_attachment(struct st_framebuffer_iface *stfbi)
+{
+ enum st_attachment_type statt;
+
+ statt = stfbi->visual->render_buffer;
+ if (statt != ST_ATTACHMENT_INVALID) {
+ /* use the buffer given by the visual, unless it is unavailable */
+ if (!st_visual_have_buffers(stfbi->visual, 1 << statt)) {
+ switch (statt) {
+ case ST_ATTACHMENT_BACK_LEFT:
+ statt = ST_ATTACHMENT_FRONT_LEFT;
+ break;
+ case ST_ATTACHMENT_BACK_RIGHT:
+ statt = ST_ATTACHMENT_FRONT_RIGHT;
+ break;
+ default:
+ break;
+ }
+
+ if (!st_visual_have_buffers(stfbi->visual, 1 << statt))
+ statt = ST_ATTACHMENT_INVALID;
+ }
+ }
+
+ return statt;
+}
+
+/**
+ * Bind the context to the given framebuffers.
+ */
+static boolean
+vg_context_bind_framebuffers(struct st_context_iface *stctxi,
+ struct st_framebuffer_iface *stdrawi,
+ struct st_framebuffer_iface *streadi)
+{
+ struct vg_context *ctx = (struct vg_context *) stctxi;
+ struct st_framebuffer *stfb;
+ enum st_attachment_type strb_att;
+
+ /* the draw and read framebuffers must be the same */
+ if (stdrawi != streadi)
+ return FALSE;
+
+ p_atomic_set(&ctx->draw_buffer_invalid, TRUE);
+
+ strb_att = (stdrawi) ? choose_attachment(stdrawi) : ST_ATTACHMENT_INVALID;
+
+ if (ctx->draw_buffer) {
+ stfb = ctx->draw_buffer;
+
+ /* free the existing fb */
+ if (!stdrawi ||
+ stfb->strb_att != strb_att ||
+ stfb->strb->format != stdrawi->visual->color_format ||
+ stfb->dsrb->format != stdrawi->visual->depth_stencil_format) {
+ destroy_renderbuffer(stfb->strb);
+ destroy_renderbuffer(stfb->dsrb);
+ free(stfb);
+
+ ctx->draw_buffer = NULL;
+ }
+ }
+
+ if (!stdrawi)
+ return TRUE;
+
+ if (strb_att == ST_ATTACHMENT_INVALID)
+ return FALSE;
+
+ /* create a new fb */
+ if (!ctx->draw_buffer) {
+ stfb = CALLOC_STRUCT(st_framebuffer);
+ if (!stfb)
+ return FALSE;
+
+ stfb->strb = create_renderbuffer(stdrawi->visual->color_format);
+ if (!stfb->strb) {
+ free(stfb);
+ return FALSE;
+ }
+
+ stfb->dsrb = create_renderbuffer(stdrawi->visual->depth_stencil_format);
+ if (!stfb->dsrb) {
+ free(stfb->strb);
+ free(stfb);
+ return FALSE;
+ }
+
+ stfb->width = 0;
+ stfb->height = 0;
+ stfb->strb_att = strb_att;
+
+ ctx->draw_buffer = stfb;
+ }
+
+ ctx->draw_buffer->iface = stdrawi;
+
+ return TRUE;
+}
+
+static boolean
+vg_api_make_current(struct st_api *stapi, struct st_context_iface *stctxi,
+ struct st_framebuffer_iface *stdrawi,
+ struct st_framebuffer_iface *streadi)
+{
+ struct vg_context *ctx = (struct vg_context *) stctxi;
+
+ if (stctxi)
+ vg_context_bind_framebuffers(stctxi, stdrawi, streadi);
+ vg_set_current_context(ctx);
+
+ return TRUE;
+}
+
+static struct st_context_iface *
+vg_api_get_current(struct st_api *stapi)
+{
+ struct vg_context *ctx = vg_current_context();
+
+ return (ctx) ? &ctx->iface : NULL;
+}
+
+static boolean
+vg_api_is_visual_supported(struct st_api *stapi,
+ const struct st_visual *visual)
+{
+ /* the impl requires a depth/stencil buffer */
+ return util_format_is_depth_and_stencil(visual->depth_stencil_format);
+}
+
+static st_proc_t
+vg_api_get_proc_address(struct st_api *stapi, const char *procname)
+{
+ return api_get_proc_address(procname);
+}
+
+static void
+vg_api_destroy(struct st_api *stapi)
+{
+}
+
+static const struct st_api vg_api = {
+ vg_api_destroy,
+ vg_api_get_proc_address,
+ vg_api_is_visual_supported,
+ vg_api_create_context,
+ vg_api_make_current,
+ vg_api_get_current,
+};
+
+const struct st_api *
+vg_api_get(void)
+{
+ return &vg_api;
+}
diff --git a/src/gallium/state_trackers/vega/vg_manager.h b/src/gallium/state_trackers/vega/vg_manager.h
new file mode 100644
index 0000000000..1d97eb864b
--- /dev/null
+++ b/src/gallium/state_trackers/vega/vg_manager.h
@@ -0,0 +1,41 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.9
+ *
+ * Copyright (C) 2010 LunarG Inc.
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Chia-I Wu <olv@lunarg.com>
+ */
+
+#ifndef VG_MANAGER_H
+#define VG_MANAGER_H
+
+#include "state_tracker/st_api.h"
+#include "vg_context.h"
+
+void
+vg_manager_flush_frontbuffer(struct vg_context *ctx);
+
+void
+vg_manager_validate_framebuffer(struct vg_context *ctx);
+
+#endif /* VG_MANAGER_H */
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_translate.c b/src/gallium/state_trackers/vega/vg_translate.c
new file mode 100644
index 0000000000..03575ca3dd
--- /dev/null
+++ b/src/gallium/state_trackers/vega/vg_translate.c
@@ -0,0 +1,1112 @@
+/**************************************************************************
+ *
+ * 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;
+ union util_color uc;
+
+ 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, &uc);
+ rgba[i][0] = uc.f[0];
+ rgba[i][1] = uc.f[1];
+ rgba[i][2] = uc.f[2];
+ rgba[i][3] = uc.f[3];
+ ++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, &uc);
+ rgba[i][0] = uc.f[0];
+ rgba[i][1] = uc.f[1];
+ rgba[i][2] = uc.f[2];
+ rgba[i][3] = uc.f[3];
+ ++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, &uc);
+ rgba[i][0] = uc.f[0];
+ rgba[i][1] = uc.f[1];
+ rgba[i][2] = uc.f[2];
+ rgba[i][3] = uc.f[3];
+ ++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, &uc);
+ rgba[i][0] = uc.f[0];
+ rgba[i][1] = uc.f[1];
+ rgba[i][2] = uc.f[2];
+ rgba[i][3] = uc.f[3];
+ ++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, &uc);
+ rgba[i][0] = uc.f[0];
+ rgba[i][1] = uc.f[1];
+ rgba[i][2] = uc.f[2];
+ rgba[i][3] = uc.f[3];
+ ++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, &uc);
+ rgba[i][0] = uc.f[0];
+ rgba[i][1] = uc.f[1];
+ rgba[i][2] = uc.f[2];
+ rgba[i][3] = uc.f[3];
+ ++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, &uc);
+ rgba[i][0] = uc.f[0];
+ rgba[i][1] = uc.f[1];
+ rgba[i][2] = uc.f[2];
+ rgba[i][3] = uc.f[3];
+ ++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, &uc);
+ rgba[i][0] = uc.f[0];
+ rgba[i][1] = uc.f[1];
+ rgba[i][2] = uc.f[2];
+ rgba[i][3] = uc.f[3];
+ ++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, &uc);
+ rgba[i][0] = uc.f[0];
+ rgba[i][1] = uc.f[1];
+ rgba[i][2] = uc.f[2];
+ rgba[i][3] = uc.f[3];
+ ++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, &uc);
+ rgba[i][0] = uc.f[0];
+ rgba[i][1] = uc.f[1];
+ rgba[i][2] = uc.f[2];
+ rgba[i][3] = uc.f[3];
+ ++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, &uc);
+ rgba[i][0] = uc.f[0];
+ rgba[i][1] = uc.f[1];
+ rgba[i][2] = uc.f[2];
+ rgba[i][3] = uc.f[3];
+ ++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, &uc);
+ rgba[i][0] = uc.f[0];
+ rgba[i][1] = uc.f[1];
+ rgba[i][2] = uc.f[2];
+ rgba[i][3] = uc.f[3];
+ ++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, &uc);
+ rgba[i+j][0] = uc.f[0];
+ rgba[i+j][1] = uc.f[1];
+ rgba[i+j][2] = uc.f[2];
+ rgba[i+j][3] = uc.f[3];
+ }
+ ++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, &uc);
+ rgba[i+j][0] = uc.f[0];
+ rgba[i+j][1] = uc.f[1];
+ rgba[i+j][2] = uc.f[2];
+ rgba[i+j][3] = uc.f[3];
+ }
+ ++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, &uc);
+ rgba[i+j][0] = uc.f[0];
+ rgba[i+j][1] = uc.f[1];
+ rgba[i+j][2] = uc.f[2];
+ rgba[i+j][3] = uc.f[3];
+ }
+ ++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, &uc);
+ rgba[i][0] = uc.f[0];
+ rgba[i][1] = uc.f[1];
+ rgba[i][2] = uc.f[2];
+ rgba[i][3] = uc.f[3];
+ ++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, &uc);
+ rgba[i][0] = uc.f[0];
+ rgba[i][1] = uc.f[1];
+ rgba[i][2] = uc.f[2];
+ rgba[i][3] = uc.f[3];
+ ++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, &uc);
+ rgba[i][0] = uc.f[0];
+ rgba[i][1] = uc.f[1];
+ rgba[i][2] = uc.f[2];
+ rgba[i][3] = uc.f[3];
+ ++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, &uc);
+ rgba[i][0] = uc.f[0];
+ rgba[i][1] = uc.f[1];
+ rgba[i][2] = uc.f[2];
+ rgba[i][3] = uc.f[3];
+ ++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, &uc);
+ rgba[i][0] = uc.f[0];
+ rgba[i][1] = uc.f[1];
+ rgba[i][2] = uc.f[2];
+ rgba[i][3] = uc.f[3];
+ ++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, &uc);
+ rgba[i][0] = uc.f[0];
+ rgba[i][1] = uc.f[1];
+ rgba[i][2] = uc.f[2];
+ rgba[i][3] = uc.f[3];
+ ++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, &uc);
+ rgba[i][0] = uc.f[0];
+ rgba[i][1] = uc.f[1];
+ rgba[i][2] = uc.f[2];
+ rgba[i][3] = uc.f[3];
+ ++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, &uc);
+ rgba[i][0] = uc.f[0];
+ rgba[i][1] = uc.f[1];
+ rgba[i][2] = uc.f[2];
+ rgba[i][3] = uc.f[3];
+ ++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, &uc);
+ rgba[i][0] = uc.f[0];
+ rgba[i][1] = uc.f[1];
+ rgba[i][2] = uc.f[2];
+ rgba[i][3] = uc.f[3];
+ ++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, &uc);
+ rgba[i][0] = uc.f[0];
+ rgba[i][1] = uc.f[1];
+ rgba[i][2] = uc.f[2];
+ rgba[i][3] = uc.f[3];
+ ++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, &uc);
+ rgba[i][0] = uc.f[0];
+ rgba[i][1] = uc.f[1];
+ rgba[i][2] = uc.f[2];
+ rgba[i][3] = uc.f[3];
+ ++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, &uc);
+ rgba[i][0] = uc.f[0];
+ rgba[i][1] = uc.f[1];
+ rgba[i][2] = uc.f[2];
+ rgba[i][3] = uc.f[3];
+ ++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;
+}
diff --git a/src/gallium/state_trackers/wgl/SConscript b/src/gallium/state_trackers/wgl/SConscript
new file mode 100644
index 0000000000..0f580b859c
--- /dev/null
+++ b/src/gallium/state_trackers/wgl/SConscript
@@ -0,0 +1,42 @@
+import os
+
+Import('*')
+
+if env['platform'] in ['windows']:
+
+ env = env.Clone()
+
+ env.Append(CPPPATH = [
+ '#src/mapi',
+ '#src/mesa',
+ '.',
+ ])
+
+ env.AppendUnique(CPPDEFINES = [
+ '_GDI32_', # prevent wgl* being declared __declspec(dllimport)
+ 'BUILD_GL32', # declare gl* as __declspec(dllexport) in Mesa headers
+ 'WIN32_THREADS', # use Win32 thread API
+ 'WIN32_LEAN_AND_MEAN', # http://msdn2.microsoft.com/en-us/library/6dwk3a1z.aspx
+ ])
+
+ sources = [
+ 'stw_context.c',
+ 'stw_device.c',
+ 'stw_ext_extensionsstring.c',
+ 'stw_ext_gallium.c',
+ 'stw_ext_pixelformat.c',
+ 'stw_ext_swapinterval.c',
+ 'stw_framebuffer.c',
+ 'stw_getprocaddress.c',
+ 'stw_pixelformat.c',
+ 'stw_st.c',
+ 'stw_tls.c',
+ 'stw_wgl.c',
+ ]
+
+ wgl = env.ConvenienceLibrary(
+ target ='wgl',
+ source = sources,
+ )
+
+ Export('wgl')
diff --git a/src/gallium/state_trackers/wgl/opengl32.def b/src/gallium/state_trackers/wgl/opengl32.def
new file mode 100644
index 0000000000..01a29d0391
--- /dev/null
+++ b/src/gallium/state_trackers/wgl/opengl32.def
@@ -0,0 +1,389 @@
+EXPORTS
+; GlmfBeginGlsBlock
+; GlmfCloseMetaFile
+; GlmfEndGlsBlock
+; GlmfEndPlayback
+; GlmfInitPlayback
+; GlmfPlayGlsRecord
+ glAccum
+ glAlphaFunc
+ glAreTexturesResident
+ glArrayElement
+ glBegin
+ glBindTexture
+ glBitmap
+ glBlendFunc
+ glCallList
+ glCallLists
+ glClear
+ glClearAccum
+ glClearColor
+ glClearDepth
+ glClearIndex
+ glClearStencil
+ glClipPlane
+ glColor3b
+ glColor3bv
+ glColor3d
+ glColor3dv
+ glColor3f
+ glColor3fv
+ glColor3i
+ glColor3iv
+ glColor3s
+ glColor3sv
+ glColor3ub
+ glColor3ubv
+ glColor3ui
+ glColor3uiv
+ glColor3us
+ glColor3usv
+ glColor4b
+ glColor4bv
+ glColor4d
+ glColor4dv
+ glColor4f
+ glColor4fv
+ glColor4i
+ glColor4iv
+ glColor4s
+ glColor4sv
+ glColor4ub
+ glColor4ubv
+ glColor4ui
+ glColor4uiv
+ glColor4us
+ glColor4usv
+ glColorMask
+ glColorMaterial
+ glColorPointer
+ glCopyPixels
+ glCopyTexImage1D
+ glCopyTexImage2D
+ glCopyTexSubImage1D
+ glCopyTexSubImage2D
+ glCullFace
+; glDebugEntry
+ glDeleteLists
+ glDeleteTextures
+ glDepthFunc
+ glDepthMask
+ glDepthRange
+ glDisable
+ glDisableClientState
+ glDrawArrays
+ glDrawBuffer
+ glDrawElements
+ glDrawPixels
+ glEdgeFlag
+ glEdgeFlagPointer
+ glEdgeFlagv
+ glEnable
+ glEnableClientState
+ glEnd
+ glEndList
+ glEvalCoord1d
+ glEvalCoord1dv
+ glEvalCoord1f
+ glEvalCoord1fv
+ glEvalCoord2d
+ glEvalCoord2dv
+ glEvalCoord2f
+ glEvalCoord2fv
+ glEvalMesh1
+ glEvalMesh2
+ glEvalPoint1
+ glEvalPoint2
+ glFeedbackBuffer
+ glFinish
+ glFlush
+ glFogf
+ glFogfv
+ glFogi
+ glFogiv
+ glFrontFace
+ glFrustum
+ glGenLists
+ glGenTextures
+ glGetBooleanv
+ glGetClipPlane
+ glGetDoublev
+ glGetError
+ glGetFloatv
+ glGetIntegerv
+ glGetLightfv
+ glGetLightiv
+ glGetMapdv
+ glGetMapfv
+ glGetMapiv
+ glGetMaterialfv
+ glGetMaterialiv
+ glGetPixelMapfv
+ glGetPixelMapuiv
+ glGetPixelMapusv
+ glGetPointerv
+ glGetPolygonStipple
+ glGetString
+ glGetTexEnvfv
+ glGetTexEnviv
+ glGetTexGendv
+ glGetTexGenfv
+ glGetTexGeniv
+ glGetTexImage
+ glGetTexLevelParameterfv
+ glGetTexLevelParameteriv
+ glGetTexParameterfv
+ glGetTexParameteriv
+ glHint
+ glIndexMask
+ glIndexPointer
+ glIndexd
+ glIndexdv
+ glIndexf
+ glIndexfv
+ glIndexi
+ glIndexiv
+ glIndexs
+ glIndexsv
+ glIndexub
+ glIndexubv
+ glInitNames
+ glInterleavedArrays
+ glIsEnabled
+ glIsList
+ glIsTexture
+ glLightModelf
+ glLightModelfv
+ glLightModeli
+ glLightModeliv
+ glLightf
+ glLightfv
+ glLighti
+ glLightiv
+ glLineStipple
+ glLineWidth
+ glListBase
+ glLoadIdentity
+ glLoadMatrixd
+ glLoadMatrixf
+ glLoadName
+ glLogicOp
+ glMap1d
+ glMap1f
+ glMap2d
+ glMap2f
+ glMapGrid1d
+ glMapGrid1f
+ glMapGrid2d
+ glMapGrid2f
+ glMaterialf
+ glMaterialfv
+ glMateriali
+ glMaterialiv
+ glMatrixMode
+ glMultMatrixd
+ glMultMatrixf
+ glNewList
+ glNormal3b
+ glNormal3bv
+ glNormal3d
+ glNormal3dv
+ glNormal3f
+ glNormal3fv
+ glNormal3i
+ glNormal3iv
+ glNormal3s
+ glNormal3sv
+ glNormalPointer
+ glOrtho
+ glPassThrough
+ glPixelMapfv
+ glPixelMapuiv
+ glPixelMapusv
+ glPixelStoref
+ glPixelStorei
+ glPixelTransferf
+ glPixelTransferi
+ glPixelZoom
+ glPointSize
+ glPolygonMode
+ glPolygonOffset
+ glPolygonStipple
+ glPopAttrib
+ glPopClientAttrib
+ glPopMatrix
+ glPopName
+ glPrioritizeTextures
+ glPushAttrib
+ glPushClientAttrib
+ glPushMatrix
+ glPushName
+ glRasterPos2d
+ glRasterPos2dv
+ glRasterPos2f
+ glRasterPos2fv
+ glRasterPos2i
+ glRasterPos2iv
+ glRasterPos2s
+ glRasterPos2sv
+ glRasterPos3d
+ glRasterPos3dv
+ glRasterPos3f
+ glRasterPos3fv
+ glRasterPos3i
+ glRasterPos3iv
+ glRasterPos3s
+ glRasterPos3sv
+ glRasterPos4d
+ glRasterPos4dv
+ glRasterPos4f
+ glRasterPos4fv
+ glRasterPos4i
+ glRasterPos4iv
+ glRasterPos4s
+ glRasterPos4sv
+ glReadBuffer
+ glReadPixels
+ glRectd
+ glRectdv
+ glRectf
+ glRectfv
+ glRecti
+ glRectiv
+ glRects
+ glRectsv
+ glRenderMode
+ glRotated
+ glRotatef
+ glScaled
+ glScalef
+ glScissor
+ glSelectBuffer
+ glShadeModel
+ glStencilFunc
+ glStencilMask
+ glStencilOp
+ glTexCoord1d
+ glTexCoord1dv
+ glTexCoord1f
+ glTexCoord1fv
+ glTexCoord1i
+ glTexCoord1iv
+ glTexCoord1s
+ glTexCoord1sv
+ glTexCoord2d
+ glTexCoord2dv
+ glTexCoord2f
+ glTexCoord2fv
+ glTexCoord2i
+ glTexCoord2iv
+ glTexCoord2s
+ glTexCoord2sv
+ glTexCoord3d
+ glTexCoord3dv
+ glTexCoord3f
+ glTexCoord3fv
+ glTexCoord3i
+ glTexCoord3iv
+ glTexCoord3s
+ glTexCoord3sv
+ glTexCoord4d
+ glTexCoord4dv
+ glTexCoord4f
+ glTexCoord4fv
+ glTexCoord4i
+ glTexCoord4iv
+ glTexCoord4s
+ glTexCoord4sv
+ glTexCoordPointer
+ glTexEnvf
+ glTexEnvfv
+ glTexEnvi
+ glTexEnviv
+ glTexGend
+ glTexGendv
+ glTexGenf
+ glTexGenfv
+ glTexGeni
+ glTexGeniv
+ glTexImage1D
+ glTexImage2D
+ glTexParameterf
+ glTexParameterfv
+ glTexParameteri
+ glTexParameteriv
+ glTexSubImage1D
+ glTexSubImage2D
+ glTranslated
+ glTranslatef
+ glVertex2d
+ glVertex2dv
+ glVertex2f
+ glVertex2fv
+ glVertex2i
+ glVertex2iv
+ glVertex2s
+ glVertex2sv
+ glVertex3d
+ glVertex3dv
+ glVertex3f
+ glVertex3fv
+ glVertex3i
+ glVertex3iv
+ glVertex3s
+ glVertex3sv
+ glVertex4d
+ glVertex4dv
+ glVertex4f
+ glVertex4fv
+ glVertex4i
+ glVertex4iv
+ glVertex4s
+ glVertex4sv
+ glVertexPointer
+ glViewport
+ wglChoosePixelFormat
+ wglCopyContext
+ wglCreateContext
+ wglCreateLayerContext
+ wglDeleteContext
+ wglDescribeLayerPlane
+ wglDescribePixelFormat
+ wglGetCurrentContext
+ wglGetCurrentDC
+; wglGetDefaultProcAddress
+ wglGetLayerPaletteEntries
+ wglGetPixelFormat
+ wglGetProcAddress
+ wglMakeCurrent
+ wglRealizeLayerPalette
+ wglSetLayerPaletteEntries
+ wglSetPixelFormat
+ wglShareLists
+ wglSwapBuffers
+ wglSwapLayerBuffers
+ wglSwapMultipleBuffers
+ wglUseFontBitmapsA
+ wglUseFontBitmapsW
+ wglUseFontOutlinesA
+ wglUseFontOutlinesW
+ wglGetExtensionsStringARB
+ DrvCopyContext
+ DrvCreateContext
+ DrvCreateLayerContext
+ DrvDeleteContext
+ DrvDescribeLayerPlane
+ DrvDescribePixelFormat
+ DrvGetLayerPaletteEntries
+ DrvGetProcAddress
+ DrvPresentBuffers
+ DrvRealizeLayerPalette
+ DrvReleaseContext
+ DrvSetCallbackProcs
+ DrvSetContext
+ DrvSetLayerPaletteEntries
+ DrvSetPixelFormat
+ DrvShareLists
+ DrvSwapBuffers
+ DrvSwapLayerBuffers
+ DrvValidateVersion
diff --git a/src/gallium/state_trackers/wgl/opengl32.mingw.def b/src/gallium/state_trackers/wgl/opengl32.mingw.def
new file mode 100644
index 0000000000..0bceee0697
--- /dev/null
+++ b/src/gallium/state_trackers/wgl/opengl32.mingw.def
@@ -0,0 +1,388 @@
+EXPORTS
+; GlmfBeginGlsBlock = GlmfBeginGlsBlock@4
+; GlmfCloseMetaFile = GlmfCloseMetaFile@4
+; GlmfEndGlsBlock = GlmfEndGlsBlock@4
+; GlmfEndPlayback = GlmfEndPlayback@4
+; GlmfInitPlayback = GlmfInitPlayback@12
+; GlmfPlayGlsRecord = GlmfPlayGlsRecord@16
+ glAccum = glAccum@8
+ glAlphaFunc = glAlphaFunc@8
+ glAreTexturesResident = glAreTexturesResident@12
+ glArrayElement = glArrayElement@4
+ glBegin = glBegin@4
+ glBindTexture = glBindTexture@8
+ glBitmap = glBitmap@28
+ glBlendFunc = glBlendFunc@8
+ glCallList = glCallList@4
+ glCallLists = glCallLists@12
+ glClear = glClear@4
+ glClearAccum = glClearAccum@16
+ glClearColor = glClearColor@16
+ glClearDepth = glClearDepth@8
+ glClearIndex = glClearIndex@4
+ glClearStencil = glClearStencil@4
+ glClipPlane = glClipPlane@8
+ glColor3b = glColor3b@12
+ glColor3bv = glColor3bv@4
+ glColor3d = glColor3d@24
+ glColor3dv = glColor3dv@4
+ glColor3f = glColor3f@12
+ glColor3fv = glColor3fv@4
+ glColor3i = glColor3i@12
+ glColor3iv = glColor3iv@4
+ glColor3s = glColor3s@12
+ glColor3sv = glColor3sv@4
+ glColor3ub = glColor3ub@12
+ glColor3ubv = glColor3ubv@4
+ glColor3ui = glColor3ui@12
+ glColor3uiv = glColor3uiv@4
+ glColor3us = glColor3us@12
+ glColor3usv = glColor3usv@4
+ glColor4b = glColor4b@16
+ glColor4bv = glColor4bv@4
+ glColor4d = glColor4d@32
+ glColor4dv = glColor4dv@4
+ glColor4f = glColor4f@16
+ glColor4fv = glColor4fv@4
+ glColor4i = glColor4i@16
+ glColor4iv = glColor4iv@4
+ glColor4s = glColor4s@16
+ glColor4sv = glColor4sv@4
+ glColor4ub = glColor4ub@16
+ glColor4ubv = glColor4ubv@4
+ glColor4ui = glColor4ui@16
+ glColor4uiv = glColor4uiv@4
+ glColor4us = glColor4us@16
+ glColor4usv = glColor4usv@4
+ glColorMask = glColorMask@16
+ glColorMaterial = glColorMaterial@8
+ glColorPointer = glColorPointer@16
+ glCopyPixels = glCopyPixels@20
+ glCopyTexImage1D = glCopyTexImage1D@28
+ glCopyTexImage2D = glCopyTexImage2D@32
+ glCopyTexSubImage1D = glCopyTexSubImage1D@24
+ glCopyTexSubImage2D = glCopyTexSubImage2D@32
+ glCullFace = glCullFace@4
+; glDebugEntry = glDebugEntry@8
+ glDeleteLists = glDeleteLists@8
+ glDeleteTextures = glDeleteTextures@8
+ glDepthFunc = glDepthFunc@4
+ glDepthMask = glDepthMask@4
+ glDepthRange = glDepthRange@16
+ glDisable = glDisable@4
+ glDisableClientState = glDisableClientState@4
+ glDrawArrays = glDrawArrays@12
+ glDrawBuffer = glDrawBuffer@4
+ glDrawElements = glDrawElements@16
+ glDrawPixels = glDrawPixels@20
+ glEdgeFlag = glEdgeFlag@4
+ glEdgeFlagPointer = glEdgeFlagPointer@8
+ glEdgeFlagv = glEdgeFlagv@4
+ glEnable = glEnable@4
+ glEnableClientState = glEnableClientState@4
+ glEnd = glEnd@0
+ glEndList = glEndList@0
+ glEvalCoord1d = glEvalCoord1d@8
+ glEvalCoord1dv = glEvalCoord1dv@4
+ glEvalCoord1f = glEvalCoord1f@4
+ glEvalCoord1fv = glEvalCoord1fv@4
+ glEvalCoord2d = glEvalCoord2d@16
+ glEvalCoord2dv = glEvalCoord2dv@4
+ glEvalCoord2f = glEvalCoord2f@8
+ glEvalCoord2fv = glEvalCoord2fv@4
+ glEvalMesh1 = glEvalMesh1@12
+ glEvalMesh2 = glEvalMesh2@20
+ glEvalPoint1 = glEvalPoint1@4
+ glEvalPoint2 = glEvalPoint2@8
+ glFeedbackBuffer = glFeedbackBuffer@12
+ glFinish = glFinish@0
+ glFlush = glFlush@0
+ glFogf = glFogf@8
+ glFogfv = glFogfv@8
+ glFogi = glFogi@8
+ glFogiv = glFogiv@8
+ glFrontFace = glFrontFace@4
+ glFrustum = glFrustum@48
+ glGenLists = glGenLists@4
+ glGenTextures = glGenTextures@8
+ glGetBooleanv = glGetBooleanv@8
+ glGetClipPlane = glGetClipPlane@8
+ glGetDoublev = glGetDoublev@8
+ glGetError = glGetError@0
+ glGetFloatv = glGetFloatv@8
+ glGetIntegerv = glGetIntegerv@8
+ glGetLightfv = glGetLightfv@12
+ glGetLightiv = glGetLightiv@12
+ glGetMapdv = glGetMapdv@12
+ glGetMapfv = glGetMapfv@12
+ glGetMapiv = glGetMapiv@12
+ glGetMaterialfv = glGetMaterialfv@12
+ glGetMaterialiv = glGetMaterialiv@12
+ glGetPixelMapfv = glGetPixelMapfv@8
+ glGetPixelMapuiv = glGetPixelMapuiv@8
+ glGetPixelMapusv = glGetPixelMapusv@8
+ glGetPointerv = glGetPointerv@8
+ glGetPolygonStipple = glGetPolygonStipple@4
+ glGetString = glGetString@4
+ glGetTexEnvfv = glGetTexEnvfv@12
+ glGetTexEnviv = glGetTexEnviv@12
+ glGetTexGendv = glGetTexGendv@12
+ glGetTexGenfv = glGetTexGenfv@12
+ glGetTexGeniv = glGetTexGeniv@12
+ glGetTexImage = glGetTexImage@20
+ glGetTexLevelParameterfv = glGetTexLevelParameterfv@16
+ glGetTexLevelParameteriv = glGetTexLevelParameteriv@16
+ glGetTexParameterfv = glGetTexParameterfv@12
+ glGetTexParameteriv = glGetTexParameteriv@12
+ glHint = glHint@8
+ glIndexMask = glIndexMask@4
+ glIndexPointer = glIndexPointer@12
+ glIndexd = glIndexd@8
+ glIndexdv = glIndexdv@4
+ glIndexf = glIndexf@4
+ glIndexfv = glIndexfv@4
+ glIndexi = glIndexi@4
+ glIndexiv = glIndexiv@4
+ glIndexs = glIndexs@4
+ glIndexsv = glIndexsv@4
+ glIndexub = glIndexub@4
+ glIndexubv = glIndexubv@4
+ glInitNames = glInitNames@0
+ glInterleavedArrays = glInterleavedArrays@12
+ glIsEnabled = glIsEnabled@4
+ glIsList = glIsList@4
+ glIsTexture = glIsTexture@4
+ glLightModelf = glLightModelf@8
+ glLightModelfv = glLightModelfv@8
+ glLightModeli = glLightModeli@8
+ glLightModeliv = glLightModeliv@8
+ glLightf = glLightf@12
+ glLightfv = glLightfv@12
+ glLighti = glLighti@12
+ glLightiv = glLightiv@12
+ glLineStipple = glLineStipple@8
+ glLineWidth = glLineWidth@4
+ glListBase = glListBase@4
+ glLoadIdentity = glLoadIdentity@0
+ glLoadMatrixd = glLoadMatrixd@4
+ glLoadMatrixf = glLoadMatrixf@4
+ glLoadName = glLoadName@4
+ glLogicOp = glLogicOp@4
+ glMap1d = glMap1d@32
+ glMap1f = glMap1f@24
+ glMap2d = glMap2d@56
+ glMap2f = glMap2f@40
+ glMapGrid1d = glMapGrid1d@20
+ glMapGrid1f = glMapGrid1f@12
+ glMapGrid2d = glMapGrid2d@40
+ glMapGrid2f = glMapGrid2f@24
+ glMaterialf = glMaterialf@12
+ glMaterialfv = glMaterialfv@12
+ glMateriali = glMateriali@12
+ glMaterialiv = glMaterialiv@12
+ glMatrixMode = glMatrixMode@4
+ glMultMatrixd = glMultMatrixd@4
+ glMultMatrixf = glMultMatrixf@4
+ glNewList = glNewList@8
+ glNormal3b = glNormal3b@12
+ glNormal3bv = glNormal3bv@4
+ glNormal3d = glNormal3d@24
+ glNormal3dv = glNormal3dv@4
+ glNormal3f = glNormal3f@12
+ glNormal3fv = glNormal3fv@4
+ glNormal3i = glNormal3i@12
+ glNormal3iv = glNormal3iv@4
+ glNormal3s = glNormal3s@12
+ glNormal3sv = glNormal3sv@4
+ glNormalPointer = glNormalPointer@12
+ glOrtho = glOrtho@48
+ glPassThrough = glPassThrough@4
+ glPixelMapfv = glPixelMapfv@12
+ glPixelMapuiv = glPixelMapuiv@12
+ glPixelMapusv = glPixelMapusv@12
+ glPixelStoref = glPixelStoref@8
+ glPixelStorei = glPixelStorei@8
+ glPixelTransferf = glPixelTransferf@8
+ glPixelTransferi = glPixelTransferi@8
+ glPixelZoom = glPixelZoom@8
+ glPointSize = glPointSize@4
+ glPolygonMode = glPolygonMode@8
+ glPolygonOffset = glPolygonOffset@8
+ glPolygonStipple = glPolygonStipple@4
+ glPopAttrib = glPopAttrib@0
+ glPopClientAttrib = glPopClientAttrib@0
+ glPopMatrix = glPopMatrix@0
+ glPopName = glPopName@0
+ glPrioritizeTextures = glPrioritizeTextures@12
+ glPushAttrib = glPushAttrib@4
+ glPushClientAttrib = glPushClientAttrib@4
+ glPushMatrix = glPushMatrix@0
+ glPushName = glPushName@4
+ glRasterPos2d = glRasterPos2d@16
+ glRasterPos2dv = glRasterPos2dv@4
+ glRasterPos2f = glRasterPos2f@8
+ glRasterPos2fv = glRasterPos2fv@4
+ glRasterPos2i = glRasterPos2i@8
+ glRasterPos2iv = glRasterPos2iv@4
+ glRasterPos2s = glRasterPos2s@8
+ glRasterPos2sv = glRasterPos2sv@4
+ glRasterPos3d = glRasterPos3d@24
+ glRasterPos3dv = glRasterPos3dv@4
+ glRasterPos3f = glRasterPos3f@12
+ glRasterPos3fv = glRasterPos3fv@4
+ glRasterPos3i = glRasterPos3i@12
+ glRasterPos3iv = glRasterPos3iv@4
+ glRasterPos3s = glRasterPos3s@12
+ glRasterPos3sv = glRasterPos3sv@4
+ glRasterPos4d = glRasterPos4d@32
+ glRasterPos4dv = glRasterPos4dv@4
+ glRasterPos4f = glRasterPos4f@16
+ glRasterPos4fv = glRasterPos4fv@4
+ glRasterPos4i = glRasterPos4i@16
+ glRasterPos4iv = glRasterPos4iv@4
+ glRasterPos4s = glRasterPos4s@16
+ glRasterPos4sv = glRasterPos4sv@4
+ glReadBuffer = glReadBuffer@4
+ glReadPixels = glReadPixels@28
+ glRectd = glRectd@32
+ glRectdv = glRectdv@8
+ glRectf = glRectf@16
+ glRectfv = glRectfv@8
+ glRecti = glRecti@16
+ glRectiv = glRectiv@8
+ glRects = glRects@16
+ glRectsv = glRectsv@8
+ glRenderMode = glRenderMode@4
+ glRotated = glRotated@32
+ glRotatef = glRotatef@16
+ glScaled = glScaled@24
+ glScalef = glScalef@12
+ glScissor = glScissor@16
+ glSelectBuffer = glSelectBuffer@8
+ glShadeModel = glShadeModel@4
+ glStencilFunc = glStencilFunc@12
+ glStencilMask = glStencilMask@4
+ glStencilOp = glStencilOp@12
+ glTexCoord1d = glTexCoord1d@8
+ glTexCoord1dv = glTexCoord1dv@4
+ glTexCoord1f = glTexCoord1f@4
+ glTexCoord1fv = glTexCoord1fv@4
+ glTexCoord1i = glTexCoord1i@4
+ glTexCoord1iv = glTexCoord1iv@4
+ glTexCoord1s = glTexCoord1s@4
+ glTexCoord1sv = glTexCoord1sv@4
+ glTexCoord2d = glTexCoord2d@16
+ glTexCoord2dv = glTexCoord2dv@4
+ glTexCoord2f = glTexCoord2f@8
+ glTexCoord2fv = glTexCoord2fv@4
+ glTexCoord2i = glTexCoord2i@8
+ glTexCoord2iv = glTexCoord2iv@4
+ glTexCoord2s = glTexCoord2s@8
+ glTexCoord2sv = glTexCoord2sv@4
+ glTexCoord3d = glTexCoord3d@24
+ glTexCoord3dv = glTexCoord3dv@4
+ glTexCoord3f = glTexCoord3f@12
+ glTexCoord3fv = glTexCoord3fv@4
+ glTexCoord3i = glTexCoord3i@12
+ glTexCoord3iv = glTexCoord3iv@4
+ glTexCoord3s = glTexCoord3s@12
+ glTexCoord3sv = glTexCoord3sv@4
+ glTexCoord4d = glTexCoord4d@32
+ glTexCoord4dv = glTexCoord4dv@4
+ glTexCoord4f = glTexCoord4f@16
+ glTexCoord4fv = glTexCoord4fv@4
+ glTexCoord4i = glTexCoord4i@16
+ glTexCoord4iv = glTexCoord4iv@4
+ glTexCoord4s = glTexCoord4s@16
+ glTexCoord4sv = glTexCoord4sv@4
+ glTexCoordPointer = glTexCoordPointer@16
+ glTexEnvf = glTexEnvf@12
+ glTexEnvfv = glTexEnvfv@12
+ glTexEnvi = glTexEnvi@12
+ glTexEnviv = glTexEnviv@12
+ glTexGend = glTexGend@16
+ glTexGendv = glTexGendv@12
+ glTexGenf = glTexGenf@12
+ glTexGenfv = glTexGenfv@12
+ glTexGeni = glTexGeni@12
+ glTexGeniv = glTexGeniv@12
+ glTexImage1D = glTexImage1D@32
+ glTexImage2D = glTexImage2D@36
+ glTexParameterf = glTexParameterf@12
+ glTexParameterfv = glTexParameterfv@12
+ glTexParameteri = glTexParameteri@12
+ glTexParameteriv = glTexParameteriv@12
+ glTexSubImage1D = glTexSubImage1D@28
+ glTexSubImage2D = glTexSubImage2D@36
+ glTranslated = glTranslated@24
+ glTranslatef = glTranslatef@12
+ glVertex2d = glVertex2d@16
+ glVertex2dv = glVertex2dv@4
+ glVertex2f = glVertex2f@8
+ glVertex2fv = glVertex2fv@4
+ glVertex2i = glVertex2i@8
+ glVertex2iv = glVertex2iv@4
+ glVertex2s = glVertex2s@8
+ glVertex2sv = glVertex2sv@4
+ glVertex3d = glVertex3d@24
+ glVertex3dv = glVertex3dv@4
+ glVertex3f = glVertex3f@12
+ glVertex3fv = glVertex3fv@4
+ glVertex3i = glVertex3i@12
+ glVertex3iv = glVertex3iv@4
+ glVertex3s = glVertex3s@12
+ glVertex3sv = glVertex3sv@4
+ glVertex4d = glVertex4d@32
+ glVertex4dv = glVertex4dv@4
+ glVertex4f = glVertex4f@16
+ glVertex4fv = glVertex4fv@4
+ glVertex4i = glVertex4i@16
+ glVertex4iv = glVertex4iv@4
+ glVertex4s = glVertex4s@16
+ glVertex4sv = glVertex4sv@4
+ glVertexPointer = glVertexPointer@16
+ glViewport = glViewport@16
+ wglChoosePixelFormat = wglChoosePixelFormat@8
+ wglCopyContext = wglCopyContext@12
+ wglCreateContext = wglCreateContext@4
+ wglCreateLayerContext = wglCreateLayerContext@8
+ wglDeleteContext = wglDeleteContext@4
+ wglDescribeLayerPlane = wglDescribeLayerPlane@20
+ wglDescribePixelFormat = wglDescribePixelFormat@16
+ wglGetCurrentContext = wglGetCurrentContext@0
+ wglGetCurrentDC = wglGetCurrentDC@0
+; wglGetDefaultProcAddress = wglGetDefaultProcAddress@4
+ wglGetLayerPaletteEntries = wglGetLayerPaletteEntries@20
+ wglGetPixelFormat = wglGetPixelFormat@4
+ wglGetProcAddress = wglGetProcAddress@4
+ wglMakeCurrent = wglMakeCurrent@8
+ wglRealizeLayerPalette = wglRealizeLayerPalette@12
+ wglSetLayerPaletteEntries = wglSetLayerPaletteEntries@20
+ wglSetPixelFormat = wglSetPixelFormat@12
+ wglShareLists = wglShareLists@8
+ wglSwapBuffers = wglSwapBuffers@4
+ wglSwapLayerBuffers = wglSwapLayerBuffers@8
+ wglSwapMultipleBuffers = wglSwapMultipleBuffers@8
+ wglUseFontBitmapsA = wglUseFontBitmapsA@16
+ wglUseFontBitmapsW = wglUseFontBitmapsW@16
+ wglUseFontOutlinesA = wglUseFontOutlinesA@32
+ wglUseFontOutlinesW = wglUseFontOutlinesW@32
+ DrvCopyContext = DrvCopyContext@12
+ DrvCreateContext = DrvCreateContext@4
+ DrvCreateLayerContext = DrvCreateLayerContext@8
+ DrvDeleteContext = DrvDeleteContext@4
+ DrvDescribeLayerPlane = DrvDescribeLayerPlane@20
+ DrvDescribePixelFormat = DrvDescribePixelFormat@16
+ DrvGetLayerPaletteEntries = DrvGetLayerPaletteEntries@20
+ DrvGetProcAddress = DrvGetProcAddress@4
+ DrvPresentBuffers = DrvPresentBuffers@8
+ DrvRealizeLayerPalette = DrvRealizeLayerPalette@12
+ DrvReleaseContext = DrvReleaseContext@4
+ DrvSetCallbackProcs = DrvSetCallbackProcs@8
+ DrvSetContext = DrvSetContext@12
+ DrvSetLayerPaletteEntries = DrvSetLayerPaletteEntries@20
+ DrvSetPixelFormat = DrvSetPixelFormat@8
+ DrvShareLists = DrvShareLists@8
+ DrvSwapBuffers = DrvSwapBuffers@4
+ DrvSwapLayerBuffers = DrvSwapLayerBuffers@8
+ DrvValidateVersion = DrvValidateVersion@4
diff --git a/src/gallium/state_trackers/wgl/stw_context.c b/src/gallium/state_trackers/wgl/stw_context.c
new file mode 100644
index 0000000000..0fb7cd8306
--- /dev/null
+++ b/src/gallium/state_trackers/wgl/stw_context.c
@@ -0,0 +1,727 @@
+/**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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 <windows.h>
+
+#include "pipe/p_compiler.h"
+#include "pipe/p_context.h"
+#include "state_tracker/st_api.h"
+
+/* for _mesa_share_state */
+#include "state_tracker/st_context.h"
+#include "main/context.h"
+
+#include "stw_icd.h"
+#include "stw_device.h"
+#include "stw_winsys.h"
+#include "stw_framebuffer.h"
+#include "stw_pixelformat.h"
+#include "stw_context.h"
+#include "stw_tls.h"
+
+
+static INLINE struct stw_context *
+stw_current_context(void)
+{
+ struct st_context_iface *st;
+
+ st = (stw_dev) ? stw_dev->stapi->get_current(stw_dev->stapi) : NULL;
+
+ return (struct stw_context *) ((st) ? st->st_manager_private : NULL);
+}
+
+BOOL APIENTRY
+DrvCopyContext(
+ DHGLRC dhrcSource,
+ DHGLRC dhrcDest,
+ UINT fuMask )
+{
+ struct stw_context *src;
+ struct stw_context *dst;
+ BOOL ret = FALSE;
+
+ if (!stw_dev)
+ return FALSE;
+
+ pipe_mutex_lock( stw_dev->ctx_mutex );
+
+ src = stw_lookup_context_locked( dhrcSource );
+ dst = stw_lookup_context_locked( dhrcDest );
+
+ if (src && dst) {
+ /* FIXME */
+ assert(0);
+ (void) src;
+ (void) dst;
+ (void) fuMask;
+ }
+
+ pipe_mutex_unlock( stw_dev->ctx_mutex );
+
+ return ret;
+}
+
+BOOL APIENTRY
+DrvShareLists(
+ DHGLRC dhglrc1,
+ DHGLRC dhglrc2 )
+{
+ struct stw_context *ctx1;
+ struct stw_context *ctx2;
+ BOOL ret = FALSE;
+
+ if (!stw_dev)
+ return FALSE;
+
+ pipe_mutex_lock( stw_dev->ctx_mutex );
+
+ ctx1 = stw_lookup_context_locked( dhglrc1 );
+ ctx2 = stw_lookup_context_locked( dhglrc2 );
+
+ if (ctx1 && ctx2) {
+ struct st_context *st1, *st2;
+
+ st1 = (struct st_context *) ctx1->st;
+ st2 = (struct st_context *) ctx2->st;
+ ret = _mesa_share_state(st2->ctx, st1->ctx);
+ }
+
+ pipe_mutex_unlock( stw_dev->ctx_mutex );
+
+ return ret;
+}
+
+DHGLRC APIENTRY
+DrvCreateContext(
+ HDC hdc )
+{
+ return DrvCreateLayerContext( hdc, 0 );
+}
+
+DHGLRC APIENTRY
+DrvCreateLayerContext(
+ HDC hdc,
+ INT iLayerPlane )
+{
+ int iPixelFormat;
+ const struct stw_pixelformat_info *pfi;
+ struct stw_context *ctx = NULL;
+
+ if(!stw_dev)
+ return 0;
+
+ if (iLayerPlane != 0)
+ return 0;
+
+ iPixelFormat = GetPixelFormat(hdc);
+ if(!iPixelFormat)
+ return 0;
+
+ pfi = stw_pixelformat_get_info( iPixelFormat - 1 );
+
+ ctx = CALLOC_STRUCT( stw_context );
+ if (ctx == NULL)
+ goto no_ctx;
+
+ ctx->hdc = hdc;
+ ctx->iPixelFormat = iPixelFormat;
+
+ ctx->st = stw_dev->stapi->create_context(stw_dev->stapi,
+ stw_dev->smapi, &pfi->stvis, NULL);
+ if (ctx->st == NULL)
+ goto no_st_ctx;
+
+ ctx->st->st_manager_private = (void *) ctx;
+
+ pipe_mutex_lock( stw_dev->ctx_mutex );
+ ctx->dhglrc = handle_table_add(stw_dev->ctx_table, ctx);
+ pipe_mutex_unlock( stw_dev->ctx_mutex );
+ if (!ctx->dhglrc)
+ goto no_hglrc;
+
+ return ctx->dhglrc;
+
+no_hglrc:
+ ctx->st->destroy(ctx->st);
+no_st_ctx:
+ FREE(ctx);
+no_ctx:
+ return 0;
+}
+
+BOOL APIENTRY
+DrvDeleteContext(
+ DHGLRC dhglrc )
+{
+ struct stw_context *ctx ;
+ BOOL ret = FALSE;
+
+ if (!stw_dev)
+ return FALSE;
+
+ pipe_mutex_lock( stw_dev->ctx_mutex );
+ ctx = stw_lookup_context_locked(dhglrc);
+ handle_table_remove(stw_dev->ctx_table, dhglrc);
+ pipe_mutex_unlock( stw_dev->ctx_mutex );
+
+ if (ctx) {
+ struct stw_context *curctx = stw_current_context();
+
+ /* Unbind current if deleting current context. */
+ if (curctx == ctx)
+ stw_dev->stapi->make_current(stw_dev->stapi, NULL, NULL, NULL);
+
+ ctx->st->destroy(ctx->st);
+ FREE(ctx);
+
+ ret = TRUE;
+ }
+
+ return ret;
+}
+
+BOOL APIENTRY
+DrvReleaseContext(
+ DHGLRC dhglrc )
+{
+ struct stw_context *ctx;
+
+ if (!stw_dev)
+ return FALSE;
+
+ pipe_mutex_lock( stw_dev->ctx_mutex );
+ ctx = stw_lookup_context_locked( dhglrc );
+ pipe_mutex_unlock( stw_dev->ctx_mutex );
+
+ if (!ctx)
+ return FALSE;
+
+ /* The expectation is that ctx is the same context which is
+ * current for this thread. We should check that and return False
+ * if not the case.
+ */
+ if (ctx != stw_current_context())
+ return FALSE;
+
+ if (stw_make_current( NULL, 0 ) == FALSE)
+ return FALSE;
+
+ return TRUE;
+}
+
+
+DHGLRC
+stw_get_current_context( void )
+{
+ struct stw_context *ctx;
+
+ ctx = stw_current_context();
+ if(!ctx)
+ return 0;
+
+ return ctx->dhglrc;
+}
+
+HDC
+stw_get_current_dc( void )
+{
+ struct stw_context *ctx;
+
+ ctx = stw_current_context();
+ if(!ctx)
+ return NULL;
+
+ return ctx->hdc;
+}
+
+BOOL
+stw_make_current(
+ HDC hdc,
+ DHGLRC dhglrc )
+{
+ struct stw_context *curctx = NULL;
+ struct stw_context *ctx = NULL;
+ struct stw_framebuffer *fb = NULL;
+
+ if (!stw_dev)
+ goto fail;
+
+ curctx = stw_current_context();
+ if (curctx != NULL) {
+ if (curctx->dhglrc != dhglrc)
+ curctx->st->flush(curctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
+
+ /* Return if already current. */
+ if (curctx->dhglrc == dhglrc && curctx->hdc == hdc) {
+ ctx = curctx;
+ fb = stw_framebuffer_from_hdc( hdc );
+ goto success;
+ }
+
+ stw_framebuffer_reference(&curctx->current_framebuffer, NULL);
+ }
+
+ if (hdc == NULL || dhglrc == 0) {
+ return stw_dev->stapi->make_current(stw_dev->stapi, NULL, NULL, NULL);
+ }
+
+ pipe_mutex_lock( stw_dev->ctx_mutex );
+ ctx = stw_lookup_context_locked( dhglrc );
+ pipe_mutex_unlock( stw_dev->ctx_mutex );
+ if(!ctx)
+ goto fail;
+
+ fb = stw_framebuffer_from_hdc( hdc );
+ if (fb) {
+ stw_framebuffer_update(fb);
+ }
+ else {
+ /* Applications should call SetPixelFormat before creating a context,
+ * but not all do, and the opengl32 runtime seems to use a default pixel
+ * format in some cases, so we must create a framebuffer for those here
+ */
+ int iPixelFormat = GetPixelFormat(hdc);
+ if(iPixelFormat)
+ fb = stw_framebuffer_create( hdc, iPixelFormat );
+ if(!fb)
+ goto fail;
+ }
+
+ if(fb->iPixelFormat != ctx->iPixelFormat)
+ goto fail;
+
+ /* Bind the new framebuffer */
+ ctx->hdc = hdc;
+
+ if (!stw_dev->stapi->make_current(stw_dev->stapi, ctx->st, fb->stfb, fb->stfb))
+ goto fail;
+
+ stw_framebuffer_reference(&ctx->current_framebuffer, fb);
+
+success:
+ assert(fb);
+ if(fb) {
+ stw_framebuffer_release(fb);
+ }
+
+ return TRUE;
+
+fail:
+ if(fb)
+ stw_framebuffer_release(fb);
+ stw_dev->stapi->make_current(stw_dev->stapi, NULL, NULL, NULL);
+ return FALSE;
+}
+
+/**
+ * Flush the current context if it is bound to the framebuffer.
+ */
+void
+stw_flush_current_locked( struct stw_framebuffer *fb )
+{
+ struct stw_context *ctx = stw_current_context();
+
+ if (ctx && ctx->current_framebuffer == fb) {
+ ctx->st->flush(ctx->st,
+ PIPE_FLUSH_RENDER_CACHE |
+ PIPE_FLUSH_SWAPBUFFERS |
+ PIPE_FLUSH_FRAME,
+ NULL);
+ }
+}
+
+/**
+ * Notify the current context that the framebuffer has become invalid.
+ */
+void
+stw_notify_current_locked( struct stw_framebuffer *fb )
+{
+ struct stw_context *ctx = stw_current_context();
+
+ if (ctx && ctx->current_framebuffer == fb)
+ ctx->st->notify_invalid_framebuffer(ctx->st, fb->stfb);
+}
+
+/**
+ * Although WGL allows different dispatch entrypoints per context
+ */
+static const GLCLTPROCTABLE cpt =
+{
+ OPENGL_VERSION_110_ENTRIES,
+ {
+ &glNewList,
+ &glEndList,
+ &glCallList,
+ &glCallLists,
+ &glDeleteLists,
+ &glGenLists,
+ &glListBase,
+ &glBegin,
+ &glBitmap,
+ &glColor3b,
+ &glColor3bv,
+ &glColor3d,
+ &glColor3dv,
+ &glColor3f,
+ &glColor3fv,
+ &glColor3i,
+ &glColor3iv,
+ &glColor3s,
+ &glColor3sv,
+ &glColor3ub,
+ &glColor3ubv,
+ &glColor3ui,
+ &glColor3uiv,
+ &glColor3us,
+ &glColor3usv,
+ &glColor4b,
+ &glColor4bv,
+ &glColor4d,
+ &glColor4dv,
+ &glColor4f,
+ &glColor4fv,
+ &glColor4i,
+ &glColor4iv,
+ &glColor4s,
+ &glColor4sv,
+ &glColor4ub,
+ &glColor4ubv,
+ &glColor4ui,
+ &glColor4uiv,
+ &glColor4us,
+ &glColor4usv,
+ &glEdgeFlag,
+ &glEdgeFlagv,
+ &glEnd,
+ &glIndexd,
+ &glIndexdv,
+ &glIndexf,
+ &glIndexfv,
+ &glIndexi,
+ &glIndexiv,
+ &glIndexs,
+ &glIndexsv,
+ &glNormal3b,
+ &glNormal3bv,
+ &glNormal3d,
+ &glNormal3dv,
+ &glNormal3f,
+ &glNormal3fv,
+ &glNormal3i,
+ &glNormal3iv,
+ &glNormal3s,
+ &glNormal3sv,
+ &glRasterPos2d,
+ &glRasterPos2dv,
+ &glRasterPos2f,
+ &glRasterPos2fv,
+ &glRasterPos2i,
+ &glRasterPos2iv,
+ &glRasterPos2s,
+ &glRasterPos2sv,
+ &glRasterPos3d,
+ &glRasterPos3dv,
+ &glRasterPos3f,
+ &glRasterPos3fv,
+ &glRasterPos3i,
+ &glRasterPos3iv,
+ &glRasterPos3s,
+ &glRasterPos3sv,
+ &glRasterPos4d,
+ &glRasterPos4dv,
+ &glRasterPos4f,
+ &glRasterPos4fv,
+ &glRasterPos4i,
+ &glRasterPos4iv,
+ &glRasterPos4s,
+ &glRasterPos4sv,
+ &glRectd,
+ &glRectdv,
+ &glRectf,
+ &glRectfv,
+ &glRecti,
+ &glRectiv,
+ &glRects,
+ &glRectsv,
+ &glTexCoord1d,
+ &glTexCoord1dv,
+ &glTexCoord1f,
+ &glTexCoord1fv,
+ &glTexCoord1i,
+ &glTexCoord1iv,
+ &glTexCoord1s,
+ &glTexCoord1sv,
+ &glTexCoord2d,
+ &glTexCoord2dv,
+ &glTexCoord2f,
+ &glTexCoord2fv,
+ &glTexCoord2i,
+ &glTexCoord2iv,
+ &glTexCoord2s,
+ &glTexCoord2sv,
+ &glTexCoord3d,
+ &glTexCoord3dv,
+ &glTexCoord3f,
+ &glTexCoord3fv,
+ &glTexCoord3i,
+ &glTexCoord3iv,
+ &glTexCoord3s,
+ &glTexCoord3sv,
+ &glTexCoord4d,
+ &glTexCoord4dv,
+ &glTexCoord4f,
+ &glTexCoord4fv,
+ &glTexCoord4i,
+ &glTexCoord4iv,
+ &glTexCoord4s,
+ &glTexCoord4sv,
+ &glVertex2d,
+ &glVertex2dv,
+ &glVertex2f,
+ &glVertex2fv,
+ &glVertex2i,
+ &glVertex2iv,
+ &glVertex2s,
+ &glVertex2sv,
+ &glVertex3d,
+ &glVertex3dv,
+ &glVertex3f,
+ &glVertex3fv,
+ &glVertex3i,
+ &glVertex3iv,
+ &glVertex3s,
+ &glVertex3sv,
+ &glVertex4d,
+ &glVertex4dv,
+ &glVertex4f,
+ &glVertex4fv,
+ &glVertex4i,
+ &glVertex4iv,
+ &glVertex4s,
+ &glVertex4sv,
+ &glClipPlane,
+ &glColorMaterial,
+ &glCullFace,
+ &glFogf,
+ &glFogfv,
+ &glFogi,
+ &glFogiv,
+ &glFrontFace,
+ &glHint,
+ &glLightf,
+ &glLightfv,
+ &glLighti,
+ &glLightiv,
+ &glLightModelf,
+ &glLightModelfv,
+ &glLightModeli,
+ &glLightModeliv,
+ &glLineStipple,
+ &glLineWidth,
+ &glMaterialf,
+ &glMaterialfv,
+ &glMateriali,
+ &glMaterialiv,
+ &glPointSize,
+ &glPolygonMode,
+ &glPolygonStipple,
+ &glScissor,
+ &glShadeModel,
+ &glTexParameterf,
+ &glTexParameterfv,
+ &glTexParameteri,
+ &glTexParameteriv,
+ &glTexImage1D,
+ &glTexImage2D,
+ &glTexEnvf,
+ &glTexEnvfv,
+ &glTexEnvi,
+ &glTexEnviv,
+ &glTexGend,
+ &glTexGendv,
+ &glTexGenf,
+ &glTexGenfv,
+ &glTexGeni,
+ &glTexGeniv,
+ &glFeedbackBuffer,
+ &glSelectBuffer,
+ &glRenderMode,
+ &glInitNames,
+ &glLoadName,
+ &glPassThrough,
+ &glPopName,
+ &glPushName,
+ &glDrawBuffer,
+ &glClear,
+ &glClearAccum,
+ &glClearIndex,
+ &glClearColor,
+ &glClearStencil,
+ &glClearDepth,
+ &glStencilMask,
+ &glColorMask,
+ &glDepthMask,
+ &glIndexMask,
+ &glAccum,
+ &glDisable,
+ &glEnable,
+ &glFinish,
+ &glFlush,
+ &glPopAttrib,
+ &glPushAttrib,
+ &glMap1d,
+ &glMap1f,
+ &glMap2d,
+ &glMap2f,
+ &glMapGrid1d,
+ &glMapGrid1f,
+ &glMapGrid2d,
+ &glMapGrid2f,
+ &glEvalCoord1d,
+ &glEvalCoord1dv,
+ &glEvalCoord1f,
+ &glEvalCoord1fv,
+ &glEvalCoord2d,
+ &glEvalCoord2dv,
+ &glEvalCoord2f,
+ &glEvalCoord2fv,
+ &glEvalMesh1,
+ &glEvalPoint1,
+ &glEvalMesh2,
+ &glEvalPoint2,
+ &glAlphaFunc,
+ &glBlendFunc,
+ &glLogicOp,
+ &glStencilFunc,
+ &glStencilOp,
+ &glDepthFunc,
+ &glPixelZoom,
+ &glPixelTransferf,
+ &glPixelTransferi,
+ &glPixelStoref,
+ &glPixelStorei,
+ &glPixelMapfv,
+ &glPixelMapuiv,
+ &glPixelMapusv,
+ &glReadBuffer,
+ &glCopyPixels,
+ &glReadPixels,
+ &glDrawPixels,
+ &glGetBooleanv,
+ &glGetClipPlane,
+ &glGetDoublev,
+ &glGetError,
+ &glGetFloatv,
+ &glGetIntegerv,
+ &glGetLightfv,
+ &glGetLightiv,
+ &glGetMapdv,
+ &glGetMapfv,
+ &glGetMapiv,
+ &glGetMaterialfv,
+ &glGetMaterialiv,
+ &glGetPixelMapfv,
+ &glGetPixelMapuiv,
+ &glGetPixelMapusv,
+ &glGetPolygonStipple,
+ &glGetString,
+ &glGetTexEnvfv,
+ &glGetTexEnviv,
+ &glGetTexGendv,
+ &glGetTexGenfv,
+ &glGetTexGeniv,
+ &glGetTexImage,
+ &glGetTexParameterfv,
+ &glGetTexParameteriv,
+ &glGetTexLevelParameterfv,
+ &glGetTexLevelParameteriv,
+ &glIsEnabled,
+ &glIsList,
+ &glDepthRange,
+ &glFrustum,
+ &glLoadIdentity,
+ &glLoadMatrixf,
+ &glLoadMatrixd,
+ &glMatrixMode,
+ &glMultMatrixf,
+ &glMultMatrixd,
+ &glOrtho,
+ &glPopMatrix,
+ &glPushMatrix,
+ &glRotated,
+ &glRotatef,
+ &glScaled,
+ &glScalef,
+ &glTranslated,
+ &glTranslatef,
+ &glViewport,
+ &glArrayElement,
+ &glBindTexture,
+ &glColorPointer,
+ &glDisableClientState,
+ &glDrawArrays,
+ &glDrawElements,
+ &glEdgeFlagPointer,
+ &glEnableClientState,
+ &glIndexPointer,
+ &glIndexub,
+ &glIndexubv,
+ &glInterleavedArrays,
+ &glNormalPointer,
+ &glPolygonOffset,
+ &glTexCoordPointer,
+ &glVertexPointer,
+ &glAreTexturesResident,
+ &glCopyTexImage1D,
+ &glCopyTexImage2D,
+ &glCopyTexSubImage1D,
+ &glCopyTexSubImage2D,
+ &glDeleteTextures,
+ &glGenTextures,
+ &glGetPointerv,
+ &glIsTexture,
+ &glPrioritizeTextures,
+ &glTexSubImage1D,
+ &glTexSubImage2D,
+ &glPopClientAttrib,
+ &glPushClientAttrib
+ }
+};
+
+PGLCLTPROCTABLE APIENTRY
+DrvSetContext(
+ HDC hdc,
+ DHGLRC dhglrc,
+ PFN_SETPROCTABLE pfnSetProcTable )
+{
+ PGLCLTPROCTABLE r = (PGLCLTPROCTABLE)&cpt;
+
+ if (!stw_make_current( hdc, dhglrc ))
+ r = NULL;
+
+ return r;
+}
diff --git a/src/gallium/state_trackers/wgl/stw_context.h b/src/gallium/state_trackers/wgl/stw_context.h
new file mode 100644
index 0000000000..0bbed84104
--- /dev/null
+++ b/src/gallium/state_trackers/wgl/stw_context.h
@@ -0,0 +1,55 @@
+/**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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 STW_CONTEXT_H
+#define STW_CONTEXT_H
+
+#include <windows.h>
+
+struct stw_framebuffer;
+struct st_context_iface;
+
+struct stw_context
+{
+ struct st_context_iface *st;
+ DHGLRC dhglrc;
+ int iPixelFormat;
+ HDC hdc;
+
+ struct stw_framebuffer *current_framebuffer;
+};
+
+DHGLRC stw_get_current_context( void );
+
+HDC stw_get_current_dc( void );
+
+BOOL stw_make_current( HDC hdc, DHGLRC dhglrc );
+
+void stw_flush_current_locked( struct stw_framebuffer *fb );
+void stw_notify_current_locked( struct stw_framebuffer *fb );
+
+#endif /* STW_CONTEXT_H */
diff --git a/src/gallium/state_trackers/wgl/stw_device.c b/src/gallium/state_trackers/wgl/stw_device.c
new file mode 100644
index 0000000000..a107c71bda
--- /dev/null
+++ b/src/gallium/state_trackers/wgl/stw_device.c
@@ -0,0 +1,223 @@
+/**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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 <windows.h>
+
+#include "glapi/glthread.h"
+#include "util/u_debug.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+#include "pipe/p_screen.h"
+
+#include "stw_device.h"
+#include "stw_winsys.h"
+#include "stw_pixelformat.h"
+#include "stw_icd.h"
+#include "stw_tls.h"
+#include "stw_framebuffer.h"
+#include "stw_st.h"
+
+#ifdef WIN32_THREADS
+extern _glthread_Mutex OneTimeLock;
+#endif
+
+
+struct stw_device *stw_dev = NULL;
+
+static int
+stw_get_param(struct st_manager *smapi,
+ enum st_manager_param param)
+{
+ return 0;
+}
+
+boolean
+stw_init(const struct stw_winsys *stw_winsys)
+{
+ static struct stw_device stw_dev_storage;
+ struct pipe_screen *screen;
+
+ debug_printf("%s\n", __FUNCTION__);
+
+ assert(!stw_dev);
+
+ stw_tls_init();
+
+ stw_dev = &stw_dev_storage;
+ memset(stw_dev, 0, sizeof(*stw_dev));
+
+#ifdef DEBUG
+ stw_dev->memdbg_no = debug_memory_begin();
+#endif
+
+ stw_dev->stw_winsys = stw_winsys;
+
+#ifdef WIN32_THREADS
+ _glthread_INIT_MUTEX(OneTimeLock);
+#endif
+
+ stw_dev->stapi = stw_st_create_api();
+ stw_dev->smapi = CALLOC_STRUCT(st_manager);
+ if (!stw_dev->stapi || !stw_dev->smapi)
+ goto error1;
+
+ screen = stw_winsys->create_screen();
+ if(!screen)
+ goto error1;
+
+ if(stw_winsys->get_adapter_luid)
+ stw_winsys->get_adapter_luid(screen, &stw_dev->AdapterLuid);
+
+ stw_dev->smapi->screen = screen;
+ stw_dev->smapi->get_param = stw_get_param;
+ stw_dev->screen = screen;
+
+ pipe_mutex_init( stw_dev->ctx_mutex );
+ pipe_mutex_init( stw_dev->fb_mutex );
+
+ stw_dev->ctx_table = handle_table_create();
+ if (!stw_dev->ctx_table) {
+ goto error1;
+ }
+
+ stw_pixelformat_init();
+
+ return TRUE;
+
+error1:
+ if (stw_dev->smapi)
+ FREE(stw_dev->smapi);
+ if (stw_dev->stapi)
+ stw_dev->stapi->destroy(stw_dev->stapi);
+
+ stw_dev = NULL;
+ return FALSE;
+}
+
+
+boolean
+stw_init_thread(void)
+{
+ return stw_tls_init_thread();
+}
+
+
+void
+stw_cleanup_thread(void)
+{
+ stw_tls_cleanup_thread();
+}
+
+
+void
+stw_cleanup(void)
+{
+ DHGLRC dhglrc;
+
+ debug_printf("%s\n", __FUNCTION__);
+
+ if (!stw_dev)
+ return;
+
+ /*
+ * Abort cleanup if there are still active contexts. In some situations
+ * this DLL may be unloaded before the DLL that is using GL contexts is.
+ */
+ pipe_mutex_lock( stw_dev->ctx_mutex );
+ dhglrc = handle_table_get_first_handle(stw_dev->ctx_table);
+ pipe_mutex_unlock( stw_dev->ctx_mutex );
+ if (dhglrc) {
+ debug_printf("%s: contexts still active -- cleanup aborted\n", __FUNCTION__);
+ stw_dev = NULL;
+ return;
+ }
+
+ handle_table_destroy(stw_dev->ctx_table);
+
+ stw_framebuffer_cleanup();
+
+ pipe_mutex_destroy( stw_dev->fb_mutex );
+ pipe_mutex_destroy( stw_dev->ctx_mutex );
+
+ FREE(stw_dev->smapi);
+ stw_dev->stapi->destroy(stw_dev->stapi);
+
+ stw_dev->screen->destroy(stw_dev->screen);
+
+#ifdef WIN32_THREADS
+ _glthread_DESTROY_MUTEX(OneTimeLock);
+
+ _glapi_destroy_multithread();
+#endif
+
+#ifdef DEBUG
+ debug_memory_end(stw_dev->memdbg_no);
+#endif
+
+ stw_tls_cleanup();
+
+ stw_dev = NULL;
+}
+
+
+struct stw_context *
+stw_lookup_context_locked( DHGLRC dhglrc )
+{
+ if (dhglrc == 0)
+ return NULL;
+
+ if (stw_dev == NULL)
+ return NULL;
+
+ return (struct stw_context *) handle_table_get(stw_dev->ctx_table, dhglrc);
+}
+
+
+void APIENTRY
+DrvSetCallbackProcs(
+ INT nProcs,
+ PROC *pProcs )
+{
+ size_t size;
+
+ if (stw_dev == NULL)
+ return;
+
+ size = MIN2(nProcs * sizeof *pProcs, sizeof stw_dev->callbacks);
+ memcpy(&stw_dev->callbacks, pProcs, size);
+
+ return;
+}
+
+
+BOOL APIENTRY
+DrvValidateVersion(
+ ULONG ulVersion )
+{
+ /* TODO: get the expected version from the winsys */
+ return ulVersion == 1;
+}
diff --git a/src/gallium/state_trackers/wgl/stw_device.h b/src/gallium/state_trackers/wgl/stw_device.h
new file mode 100644
index 0000000000..1b836960d0
--- /dev/null
+++ b/src/gallium/state_trackers/wgl/stw_device.h
@@ -0,0 +1,81 @@
+/**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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 STW_DEVICE_H_
+#define STW_DEVICE_H_
+
+
+#include "pipe/p_compiler.h"
+#include "os/os_thread.h"
+#include "util/u_handle_table.h"
+#include "stw_icd.h"
+#include "stw_pixelformat.h"
+
+
+#define STW_MAX_PIXELFORMATS 256
+
+
+struct pipe_screen;
+struct st_api;
+struct st_manager;
+struct stw_framebuffer;
+
+struct stw_device
+{
+ const struct stw_winsys *stw_winsys;
+
+ struct pipe_screen *screen;
+
+ struct st_api *stapi;
+ struct st_manager *smapi;
+
+ LUID AdapterLuid;
+
+ struct stw_pixelformat_info pixelformats[STW_MAX_PIXELFORMATS];
+ unsigned pixelformat_count;
+ unsigned pixelformat_extended_count;
+
+ GLCALLBACKTABLE callbacks;
+
+ pipe_mutex ctx_mutex;
+ struct handle_table *ctx_table;
+
+ pipe_mutex fb_mutex;
+ struct stw_framebuffer *fb_head;
+
+#ifdef DEBUG
+ unsigned long memdbg_no;
+#endif
+};
+
+struct stw_context *
+stw_lookup_context_locked( DHGLRC hglrc );
+
+extern struct stw_device *stw_dev;
+
+
+#endif /* STW_DEVICE_H_ */
diff --git a/src/gallium/state_trackers/wgl/stw_ext_extensionsstring.c b/src/gallium/state_trackers/wgl/stw_ext_extensionsstring.c
new file mode 100644
index 0000000000..62c859e1f9
--- /dev/null
+++ b/src/gallium/state_trackers/wgl/stw_ext_extensionsstring.c
@@ -0,0 +1,59 @@
+/**************************************************************************
+ *
+ * Copyright 2009 VMware, Inc.
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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 <windows.h>
+
+#define WGL_WGLEXT_PROTOTYPES
+
+#include <GL/gl.h>
+#include <GL/wglext.h>
+
+
+static const char *stw_extension_string =
+ "WGL_ARB_extensions_string "
+ "WGL_ARB_multisample "
+ "WGL_ARB_pixel_format "
+/* "WGL_EXT_swap_interval " */
+ "WGL_EXT_extensions_string";
+
+
+WINGDIAPI const char * APIENTRY
+wglGetExtensionsStringARB(
+ HDC hdc )
+{
+ (void) hdc;
+
+ return stw_extension_string;
+}
+
+
+WINGDIAPI const char * APIENTRY
+wglGetExtensionsStringEXT( void )
+{
+ return stw_extension_string;
+}
diff --git a/src/gallium/state_trackers/wgl/stw_ext_gallium.c b/src/gallium/state_trackers/wgl/stw_ext_gallium.c
new file mode 100644
index 0000000000..5ecbd8048d
--- /dev/null
+++ b/src/gallium/state_trackers/wgl/stw_ext_gallium.c
@@ -0,0 +1,50 @@
+/**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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 "pipe/p_screen.h"
+#include "stw_device.h"
+#include "stw_winsys.h"
+#include "stw_ext_gallium.h"
+
+
+struct pipe_screen * APIENTRY
+wglGetGalliumScreenMESA(void)
+{
+ return stw_dev ? stw_dev->screen : NULL;
+}
+
+
+/* XXX: Unify with stw_create_layer_context */
+struct pipe_context * APIENTRY
+wglCreateGalliumContextMESA(void)
+{
+ if(!stw_dev)
+ return NULL;
+
+ return stw_dev->screen->context_create( stw_dev->screen, NULL );
+}
diff --git a/src/gallium/state_trackers/wgl/stw_ext_gallium.h b/src/gallium/state_trackers/wgl/stw_ext_gallium.h
new file mode 100644
index 0000000000..cc35f2bb7f
--- /dev/null
+++ b/src/gallium/state_trackers/wgl/stw_ext_gallium.h
@@ -0,0 +1,47 @@
+/**************************************************************************
+ *
+ * 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 STW_EXTGALLIUM_H_
+#define STW_EXTGALLIUM_H_
+
+
+#include <windows.h>
+
+
+struct pipe_screen;
+struct pipe_context;
+
+
+struct pipe_screen * APIENTRY
+wglGetGalliumScreenMESA(void);
+
+
+struct pipe_context * APIENTRY
+wglCreateGalliumContextMESA(void);
+
+
+#endif /* STW_EXTGALLIUM_H_ */
diff --git a/src/gallium/state_trackers/wgl/stw_ext_pixelformat.c b/src/gallium/state_trackers/wgl/stw_ext_pixelformat.c
new file mode 100644
index 0000000000..ab56800e28
--- /dev/null
+++ b/src/gallium/state_trackers/wgl/stw_ext_pixelformat.c
@@ -0,0 +1,482 @@
+/**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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.
+ *
+ **************************************************************************/
+
+/**
+ * @file
+ *
+ * WGL_ARB_pixel_format extension implementation.
+ *
+ * @sa http://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt
+ */
+
+
+#include <windows.h>
+
+#define WGL_WGLEXT_PROTOTYPES
+
+#include <GL/gl.h>
+#include <GL/wglext.h>
+
+#include "pipe/p_compiler.h"
+#include "util/u_memory.h"
+#include "stw_pixelformat.h"
+
+
+static boolean
+stw_query_attrib(
+ int iPixelFormat,
+ int iLayerPlane,
+ int attrib,
+ int *pvalue )
+{
+ uint count;
+ uint index;
+ const struct stw_pixelformat_info *pfi;
+
+ count = stw_pixelformat_get_extended_count();
+
+ if (attrib == WGL_NUMBER_PIXEL_FORMATS_ARB) {
+ *pvalue = (int) count;
+ return TRUE;
+ }
+
+ index = (uint) iPixelFormat - 1;
+ if (index >= count)
+ return FALSE;
+
+ pfi = stw_pixelformat_get_info( index );
+
+ switch (attrib) {
+ case WGL_DRAW_TO_WINDOW_ARB:
+ *pvalue = pfi->pfd.dwFlags & PFD_DRAW_TO_WINDOW ? TRUE : FALSE;
+ return TRUE;
+
+ case WGL_DRAW_TO_BITMAP_ARB:
+ *pvalue = pfi->pfd.dwFlags & PFD_DRAW_TO_BITMAP ? TRUE : FALSE;
+ return TRUE;
+
+ case WGL_NEED_PALETTE_ARB:
+ *pvalue = pfi->pfd.dwFlags & PFD_NEED_PALETTE ? TRUE : FALSE;
+ return TRUE;
+
+ case WGL_NEED_SYSTEM_PALETTE_ARB:
+ *pvalue = pfi->pfd.dwFlags & PFD_NEED_SYSTEM_PALETTE ? TRUE : FALSE;
+ return TRUE;
+
+ case WGL_SWAP_METHOD_ARB:
+ *pvalue = pfi->pfd.dwFlags & PFD_SWAP_COPY ? WGL_SWAP_COPY_ARB : WGL_SWAP_UNDEFINED_ARB;
+ return TRUE;
+
+ case WGL_SWAP_LAYER_BUFFERS_ARB:
+ *pvalue = FALSE;
+ return TRUE;
+
+ case WGL_NUMBER_OVERLAYS_ARB:
+ *pvalue = 0;
+ return TRUE;
+
+ case WGL_NUMBER_UNDERLAYS_ARB:
+ *pvalue = 0;
+ return TRUE;
+ }
+
+ if (iLayerPlane != 0)
+ return FALSE;
+
+ switch (attrib) {
+ case WGL_ACCELERATION_ARB:
+ *pvalue = WGL_FULL_ACCELERATION_ARB;
+ break;
+
+ case WGL_TRANSPARENT_ARB:
+ *pvalue = FALSE;
+ break;
+
+ case WGL_TRANSPARENT_RED_VALUE_ARB:
+ case WGL_TRANSPARENT_GREEN_VALUE_ARB:
+ case WGL_TRANSPARENT_BLUE_VALUE_ARB:
+ case WGL_TRANSPARENT_ALPHA_VALUE_ARB:
+ case WGL_TRANSPARENT_INDEX_VALUE_ARB:
+ break;
+
+ case WGL_SHARE_DEPTH_ARB:
+ case WGL_SHARE_STENCIL_ARB:
+ case WGL_SHARE_ACCUM_ARB:
+ *pvalue = TRUE;
+ break;
+
+ case WGL_SUPPORT_GDI_ARB:
+ *pvalue = pfi->pfd.dwFlags & PFD_SUPPORT_GDI ? TRUE : FALSE;
+ break;
+
+ case WGL_SUPPORT_OPENGL_ARB:
+ *pvalue = pfi->pfd.dwFlags & PFD_SUPPORT_OPENGL ? TRUE : FALSE;
+ break;
+
+ case WGL_DOUBLE_BUFFER_ARB:
+ *pvalue = pfi->pfd.dwFlags & PFD_DOUBLEBUFFER ? TRUE : FALSE;
+ break;
+
+ case WGL_STEREO_ARB:
+ *pvalue = pfi->pfd.dwFlags & PFD_STEREO ? TRUE : FALSE;
+ break;
+
+ case WGL_PIXEL_TYPE_ARB:
+ switch (pfi->pfd.iPixelType) {
+ case PFD_TYPE_RGBA:
+ *pvalue = WGL_TYPE_RGBA_ARB;
+ break;
+ case PFD_TYPE_COLORINDEX:
+ *pvalue = WGL_TYPE_COLORINDEX_ARB;
+ break;
+ default:
+ return FALSE;
+ }
+ break;
+
+ case WGL_COLOR_BITS_ARB:
+ *pvalue = pfi->pfd.cColorBits;
+ break;
+
+ case WGL_RED_BITS_ARB:
+ *pvalue = pfi->pfd.cRedBits;
+ break;
+
+ case WGL_RED_SHIFT_ARB:
+ *pvalue = pfi->pfd.cRedShift;
+ break;
+
+ case WGL_GREEN_BITS_ARB:
+ *pvalue = pfi->pfd.cGreenBits;
+ break;
+
+ case WGL_GREEN_SHIFT_ARB:
+ *pvalue = pfi->pfd.cGreenShift;
+ break;
+
+ case WGL_BLUE_BITS_ARB:
+ *pvalue = pfi->pfd.cBlueBits;
+ break;
+
+ case WGL_BLUE_SHIFT_ARB:
+ *pvalue = pfi->pfd.cBlueShift;
+ break;
+
+ case WGL_ALPHA_BITS_ARB:
+ *pvalue = pfi->pfd.cAlphaBits;
+ break;
+
+ case WGL_ALPHA_SHIFT_ARB:
+ *pvalue = pfi->pfd.cAlphaShift;
+ break;
+
+ case WGL_ACCUM_BITS_ARB:
+ *pvalue = pfi->pfd.cAccumBits;
+ break;
+
+ case WGL_ACCUM_RED_BITS_ARB:
+ *pvalue = pfi->pfd.cAccumRedBits;
+ break;
+
+ case WGL_ACCUM_GREEN_BITS_ARB:
+ *pvalue = pfi->pfd.cAccumGreenBits;
+ break;
+
+ case WGL_ACCUM_BLUE_BITS_ARB:
+ *pvalue = pfi->pfd.cAccumBlueBits;
+ break;
+
+ case WGL_ACCUM_ALPHA_BITS_ARB:
+ *pvalue = pfi->pfd.cAccumAlphaBits;
+ break;
+
+ case WGL_DEPTH_BITS_ARB:
+ *pvalue = pfi->pfd.cDepthBits;
+ break;
+
+ case WGL_STENCIL_BITS_ARB:
+ *pvalue = pfi->pfd.cStencilBits;
+ break;
+
+ case WGL_AUX_BUFFERS_ARB:
+ *pvalue = pfi->pfd.cAuxBuffers;
+ break;
+
+ case WGL_SAMPLE_BUFFERS_ARB:
+ *pvalue = 1;
+ break;
+
+ case WGL_SAMPLES_ARB:
+ *pvalue = pfi->stvis.samples;
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+struct attrib_match_info
+{
+ int attribute;
+ int weight;
+ BOOL exact;
+};
+
+static const struct attrib_match_info attrib_match[] = {
+
+ /* WGL_ARB_pixel_format */
+ { WGL_DRAW_TO_WINDOW_ARB, 0, TRUE },
+ { WGL_DRAW_TO_BITMAP_ARB, 0, TRUE },
+ { WGL_ACCELERATION_ARB, 0, TRUE },
+ { WGL_NEED_PALETTE_ARB, 0, TRUE },
+ { WGL_NEED_SYSTEM_PALETTE_ARB, 0, TRUE },
+ { WGL_SWAP_LAYER_BUFFERS_ARB, 0, TRUE },
+ { WGL_SWAP_METHOD_ARB, 0, TRUE },
+ { WGL_NUMBER_OVERLAYS_ARB, 4, FALSE },
+ { WGL_NUMBER_UNDERLAYS_ARB, 4, FALSE },
+ /*{ WGL_SHARE_DEPTH_ARB, 0, TRUE },*/ /* no overlays -- ignore */
+ /*{ WGL_SHARE_STENCIL_ARB, 0, TRUE },*/ /* no overlays -- ignore */
+ /*{ WGL_SHARE_ACCUM_ARB, 0, TRUE },*/ /* no overlays -- ignore */
+ { WGL_SUPPORT_GDI_ARB, 0, TRUE },
+ { WGL_SUPPORT_OPENGL_ARB, 0, TRUE },
+ { WGL_DOUBLE_BUFFER_ARB, 0, TRUE },
+ { WGL_STEREO_ARB, 0, TRUE },
+ { WGL_PIXEL_TYPE_ARB, 0, TRUE },
+ { WGL_COLOR_BITS_ARB, 1, FALSE },
+ { WGL_RED_BITS_ARB, 1, FALSE },
+ { WGL_GREEN_BITS_ARB, 1, FALSE },
+ { WGL_BLUE_BITS_ARB, 1, FALSE },
+ { WGL_ALPHA_BITS_ARB, 1, FALSE },
+ { WGL_ACCUM_BITS_ARB, 1, FALSE },
+ { WGL_ACCUM_RED_BITS_ARB, 1, FALSE },
+ { WGL_ACCUM_GREEN_BITS_ARB, 1, FALSE },
+ { WGL_ACCUM_BLUE_BITS_ARB, 1, FALSE },
+ { WGL_ACCUM_ALPHA_BITS_ARB, 1, FALSE },
+ { WGL_DEPTH_BITS_ARB, 1, FALSE },
+ { WGL_STENCIL_BITS_ARB, 1, FALSE },
+ { WGL_AUX_BUFFERS_ARB, 2, FALSE },
+
+ /* WGL_ARB_multisample */
+ { WGL_SAMPLE_BUFFERS_ARB, 2, FALSE },
+ { WGL_SAMPLES_ARB, 2, FALSE }
+};
+
+struct stw_pixelformat_score
+{
+ int points;
+ uint index;
+};
+
+static BOOL
+score_pixelformats(
+ struct stw_pixelformat_score *scores,
+ uint count,
+ int attribute,
+ int expected_value )
+{
+ uint i;
+ const struct attrib_match_info *ami = NULL;
+ uint index;
+
+ /* Find out if a given attribute should be considered for score calculation.
+ */
+ for (i = 0; i < sizeof( attrib_match ) / sizeof( attrib_match[0] ); i++) {
+ if (attrib_match[i].attribute == attribute) {
+ ami = &attrib_match[i];
+ break;
+ }
+ }
+ if (ami == NULL)
+ return TRUE;
+
+ /* Iterate all pixelformats, query the requested attribute and calculate
+ * score points.
+ */
+ for (index = 0; index < count; index++) {
+ int actual_value;
+
+ if (!stw_query_attrib( index + 1, 0, attribute, &actual_value ))
+ return FALSE;
+
+ if (ami->exact) {
+ /* For an exact match criteria, if the actual and expected values differ,
+ * the score is set to 0 points, effectively removing the pixelformat
+ * from a list of matching pixelformats.
+ */
+ if (actual_value != expected_value)
+ scores[index].points = 0;
+ }
+ else {
+ /* For a minimum match criteria, if the actual value is smaller than the expected
+ * value, the pixelformat is rejected (score set to 0). However, if the actual
+ * value is bigger, the pixelformat is given a penalty to favour pixelformats that
+ * more closely match the expected values.
+ */
+ if (actual_value < expected_value)
+ scores[index].points = 0;
+ else if (actual_value > expected_value)
+ scores[index].points -= (actual_value - expected_value) * ami->weight;
+ }
+ }
+
+ return TRUE;
+}
+
+WINGDIAPI BOOL APIENTRY
+wglChoosePixelFormatARB(
+ HDC hdc,
+ const int *piAttribIList,
+ const FLOAT *pfAttribFList,
+ UINT nMaxFormats,
+ int *piFormats,
+ UINT *nNumFormats )
+{
+ uint count;
+ struct stw_pixelformat_score *scores;
+ uint i;
+
+ *nNumFormats = 0;
+
+ /* Allocate and initialize pixelformat score table -- better matches
+ * have higher scores. Start with a high score and take out penalty
+ * points for a mismatch when the match does not have to be exact.
+ * Set a score to 0 if there is a mismatch for an exact match criteria.
+ */
+ count = stw_pixelformat_get_extended_count();
+ scores = (struct stw_pixelformat_score *) MALLOC( count * sizeof( struct stw_pixelformat_score ) );
+ if (scores == NULL)
+ return FALSE;
+ for (i = 0; i < count; i++) {
+ scores[i].points = 0x7fffffff;
+ scores[i].index = i;
+ }
+
+ /* Given the attribute list calculate a score for each pixelformat.
+ */
+ if (piAttribIList != NULL) {
+ while (*piAttribIList != 0) {
+ if (!score_pixelformats( scores, count, piAttribIList[0], piAttribIList[1] )) {
+ FREE( scores );
+ return FALSE;
+ }
+ piAttribIList += 2;
+ }
+ }
+ if (pfAttribFList != NULL) {
+ while (*pfAttribFList != 0) {
+ if (!score_pixelformats( scores, count, (int) pfAttribFList[0], (int) pfAttribFList[1] )) {
+ FREE( scores );
+ return FALSE;
+ }
+ pfAttribFList += 2;
+ }
+ }
+
+ /* Bubble-sort the resulting scores. Pixelformats with higher scores go first.
+ * TODO: Find out if there are any patent issues with it.
+ */
+ if (count > 1) {
+ uint n = count;
+ boolean swapped;
+
+ do {
+ swapped = FALSE;
+ for (i = 1; i < n; i++) {
+ if (scores[i - 1].points < scores[i].points) {
+ struct stw_pixelformat_score score = scores[i - 1];
+
+ scores[i - 1] = scores[i];
+ scores[i] = score;
+ swapped = TRUE;
+ }
+ }
+ n--;
+ }
+ while (swapped);
+ }
+
+ /* Return a list of pixelformats that are the best match.
+ * Reject pixelformats with non-positive scores.
+ */
+ for (i = 0; i < count; i++) {
+ if (scores[i].points > 0) {
+ if (*nNumFormats < nMaxFormats)
+ piFormats[*nNumFormats] = scores[i].index + 1;
+ (*nNumFormats)++;
+ }
+ }
+
+ FREE( scores );
+ return TRUE;
+}
+
+WINGDIAPI BOOL APIENTRY
+wglGetPixelFormatAttribfvARB(
+ HDC hdc,
+ int iPixelFormat,
+ int iLayerPlane,
+ UINT nAttributes,
+ const int *piAttributes,
+ FLOAT *pfValues )
+{
+ UINT i;
+
+ (void) hdc;
+
+ for (i = 0; i < nAttributes; i++) {
+ int value;
+
+ if (!stw_query_attrib( iPixelFormat, iLayerPlane, piAttributes[i], &value ))
+ return FALSE;
+ pfValues[i] = (FLOAT) value;
+ }
+
+ return TRUE;
+}
+
+WINGDIAPI BOOL APIENTRY
+wglGetPixelFormatAttribivARB(
+ HDC hdc,
+ int iPixelFormat,
+ int iLayerPlane,
+ UINT nAttributes,
+ const int *piAttributes,
+ int *piValues )
+{
+ UINT i;
+
+ (void) hdc;
+
+ for (i = 0; i < nAttributes; i++) {
+ if (!stw_query_attrib( iPixelFormat, iLayerPlane, piAttributes[i], &piValues[i] ))
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/src/gallium/state_trackers/wgl/stw_ext_swapinterval.c b/src/gallium/state_trackers/wgl/stw_ext_swapinterval.c
new file mode 100644
index 0000000000..9eac6a1d09
--- /dev/null
+++ b/src/gallium/state_trackers/wgl/stw_ext_swapinterval.c
@@ -0,0 +1,57 @@
+/**************************************************************************
+ *
+ * Copyright 2009 VMware, Inc.
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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 <windows.h>
+
+#define WGL_WGLEXT_PROTOTYPES
+
+#include <GL/gl.h>
+#include <GL/wglext.h>
+#include "util/u_debug.h"
+
+/* A dummy implementation of this extension.
+ *
+ * Required as some applications retrieve and call these functions
+ * regardless of the fact that we don't advertise the extension and
+ * further more the results of wglGetProcAddress are NULL.
+ */
+WINGDIAPI BOOL APIENTRY
+wglSwapIntervalEXT(int interval)
+{
+ (void) interval;
+ debug_printf("%s: %d\n", __FUNCTION__, interval);
+ return TRUE;
+}
+
+WINGDIAPI int APIENTRY
+wglGetSwapIntervalEXT(void)
+{
+ return 0;
+}
+
+
diff --git a/src/gallium/state_trackers/wgl/stw_framebuffer.c b/src/gallium/state_trackers/wgl/stw_framebuffer.c
new file mode 100644
index 0000000000..259b22f22c
--- /dev/null
+++ b/src/gallium/state_trackers/wgl/stw_framebuffer.c
@@ -0,0 +1,592 @@
+/**************************************************************************
+ *
+ * Copyright 2008-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 <windows.h>
+
+#include "pipe/p_format.h"
+#include "pipe/p_screen.h"
+#include "util/u_format.h"
+#include "util/u_memory.h"
+#include "state_tracker/st_api.h"
+
+#include "stw_icd.h"
+#include "stw_framebuffer.h"
+#include "stw_device.h"
+#include "stw_winsys.h"
+#include "stw_tls.h"
+#include "stw_context.h"
+#include "stw_st.h"
+
+
+/**
+ * Search the framebuffer with the matching HWND while holding the
+ * stw_dev::fb_mutex global lock.
+ */
+static INLINE struct stw_framebuffer *
+stw_framebuffer_from_hwnd_locked(
+ HWND hwnd )
+{
+ struct stw_framebuffer *fb;
+
+ for (fb = stw_dev->fb_head; fb != NULL; fb = fb->next)
+ if (fb->hWnd == hwnd) {
+ pipe_mutex_lock(fb->mutex);
+ break;
+ }
+
+ return fb;
+}
+
+
+/**
+ * Destroy this framebuffer. Both stw_dev::fb_mutex and stw_framebuffer::mutex
+ * must be held, by this order. If there are still references to the
+ * framebuffer, nothing will happen.
+ */
+static INLINE void
+stw_framebuffer_destroy_locked(
+ struct stw_framebuffer *fb )
+{
+ struct stw_framebuffer **link;
+
+ /* check the reference count */
+ fb->refcnt--;
+ if (fb->refcnt) {
+ pipe_mutex_unlock( fb->mutex );
+ return;
+ }
+
+ link = &stw_dev->fb_head;
+ while (*link != fb)
+ link = &(*link)->next;
+ assert(*link);
+ *link = fb->next;
+ fb->next = NULL;
+
+ if(fb->shared_surface)
+ stw_dev->stw_winsys->shared_surface_close(stw_dev->screen, fb->shared_surface);
+
+ stw_st_destroy_framebuffer_locked(fb->stfb);
+
+ pipe_mutex_unlock( fb->mutex );
+
+ pipe_mutex_destroy( fb->mutex );
+
+ FREE( fb );
+}
+
+
+void
+stw_framebuffer_release(
+ struct stw_framebuffer *fb)
+{
+ assert(fb);
+ pipe_mutex_unlock( fb->mutex );
+}
+
+
+static INLINE void
+stw_framebuffer_get_size( struct stw_framebuffer *fb )
+{
+ unsigned width, height;
+ RECT client_rect;
+ RECT window_rect;
+ POINT client_pos;
+
+ assert(fb->hWnd);
+
+ /* Get the client area size. */
+ GetClientRect( fb->hWnd, &client_rect );
+ assert(client_rect.left == 0);
+ assert(client_rect.top == 0);
+ width = client_rect.right - client_rect.left;
+ height = client_rect.bottom - client_rect.top;
+
+ if(width < 1)
+ width = 1;
+ if(height < 1)
+ height = 1;
+
+ if(width != fb->width || height != fb->height) {
+ fb->must_resize = TRUE;
+ fb->width = width;
+ fb->height = height;
+ }
+
+ client_pos.x = 0;
+ client_pos.y = 0;
+ ClientToScreen(fb->hWnd, &client_pos);
+
+ GetWindowRect(fb->hWnd, &window_rect);
+
+ fb->client_rect.left = client_pos.x - window_rect.left;
+ fb->client_rect.top = client_pos.y - window_rect.top;
+ fb->client_rect.right = fb->client_rect.left + fb->width;
+ fb->client_rect.bottom = fb->client_rect.top + fb->height;
+
+#if 0
+ debug_printf("\n");
+ debug_printf("%s: client_position = (%i, %i)\n",
+ __FUNCTION__, client_pos.x, client_pos.y);
+ debug_printf("%s: window_rect = (%i, %i) - (%i, %i)\n",
+ __FUNCTION__,
+ window_rect.left, window_rect.top,
+ window_rect.right, window_rect.bottom);
+ debug_printf("%s: client_rect = (%i, %i) - (%i, %i)\n",
+ __FUNCTION__,
+ fb->client_rect.left, fb->client_rect.top,
+ fb->client_rect.right, fb->client_rect.bottom);
+#endif
+}
+
+
+/**
+ * @sa http://msdn.microsoft.com/en-us/library/ms644975(VS.85).aspx
+ * @sa http://msdn.microsoft.com/en-us/library/ms644960(VS.85).aspx
+ */
+LRESULT CALLBACK
+stw_call_window_proc(
+ int nCode,
+ WPARAM wParam,
+ LPARAM lParam )
+{
+ struct stw_tls_data *tls_data;
+ PCWPSTRUCT pParams = (PCWPSTRUCT)lParam;
+ struct stw_framebuffer *fb;
+
+ tls_data = stw_tls_get_data();
+ if(!tls_data)
+ return 0;
+
+ if (nCode < 0 || !stw_dev)
+ return CallNextHookEx(tls_data->hCallWndProcHook, nCode, wParam, lParam);
+
+ if (pParams->message == WM_WINDOWPOSCHANGED) {
+ /* We handle WM_WINDOWPOSCHANGED instead of WM_SIZE because according to
+ * http://blogs.msdn.com/oldnewthing/archive/2008/01/15/7113860.aspx
+ * WM_SIZE is generated from WM_WINDOWPOSCHANGED by DefWindowProc so it
+ * can be masked out by the application. */
+ LPWINDOWPOS lpWindowPos = (LPWINDOWPOS)pParams->lParam;
+ if((lpWindowPos->flags & SWP_SHOWWINDOW) ||
+ !(lpWindowPos->flags & SWP_NOMOVE) ||
+ !(lpWindowPos->flags & SWP_NOSIZE)) {
+ fb = stw_framebuffer_from_hwnd( pParams->hwnd );
+ if(fb) {
+ /* Size in WINDOWPOS includes the window frame, so get the size
+ * of the client area via GetClientRect. */
+ stw_framebuffer_get_size(fb);
+ stw_framebuffer_release(fb);
+ }
+ }
+ }
+ else if (pParams->message == WM_DESTROY) {
+ pipe_mutex_lock( stw_dev->fb_mutex );
+ fb = stw_framebuffer_from_hwnd_locked( pParams->hwnd );
+ if(fb)
+ stw_framebuffer_destroy_locked(fb);
+ pipe_mutex_unlock( stw_dev->fb_mutex );
+ }
+
+ return CallNextHookEx(tls_data->hCallWndProcHook, nCode, wParam, lParam);
+}
+
+
+struct stw_framebuffer *
+stw_framebuffer_create(
+ HDC hdc,
+ int iPixelFormat )
+{
+ HWND hWnd;
+ struct stw_framebuffer *fb;
+ const struct stw_pixelformat_info *pfi;
+
+ /* We only support drawing to a window. */
+ hWnd = WindowFromDC( hdc );
+ if(!hWnd)
+ return NULL;
+
+ fb = CALLOC_STRUCT( stw_framebuffer );
+ if (fb == NULL)
+ return NULL;
+
+ fb->hDC = hdc;
+ fb->hWnd = hWnd;
+ fb->iPixelFormat = iPixelFormat;
+
+ fb->pfi = pfi = stw_pixelformat_get_info( iPixelFormat - 1 );
+ fb->stfb = stw_st_create_framebuffer( fb );
+ if (!fb->stfb) {
+ FREE( fb );
+ return NULL;
+ }
+
+ fb->refcnt = 1;
+
+ stw_framebuffer_get_size(fb);
+
+ pipe_mutex_init( fb->mutex );
+
+ /* This is the only case where we lock the stw_framebuffer::mutex before
+ * stw_dev::fb_mutex, since no other thread can know about this framebuffer
+ * and we must prevent any other thread from destroying it before we return.
+ */
+ pipe_mutex_lock( fb->mutex );
+
+ pipe_mutex_lock( stw_dev->fb_mutex );
+ fb->next = stw_dev->fb_head;
+ stw_dev->fb_head = fb;
+ pipe_mutex_unlock( stw_dev->fb_mutex );
+
+ return fb;
+}
+
+/**
+ * Have ptr reference fb. The referenced framebuffer should be locked.
+ */
+void
+stw_framebuffer_reference(
+ struct stw_framebuffer **ptr,
+ struct stw_framebuffer *fb)
+{
+ struct stw_framebuffer *old_fb = *ptr;
+
+ if (old_fb == fb)
+ return;
+
+ if (fb)
+ fb->refcnt++;
+ if (old_fb) {
+ pipe_mutex_lock(stw_dev->fb_mutex);
+
+ pipe_mutex_lock(old_fb->mutex);
+ stw_framebuffer_destroy_locked(old_fb);
+
+ pipe_mutex_unlock(stw_dev->fb_mutex);
+ }
+
+ *ptr = fb;
+}
+
+
+/**
+ * Update the framebuffer's size if necessary.
+ */
+void
+stw_framebuffer_update(
+ struct stw_framebuffer *fb)
+{
+ assert(fb->stfb);
+ assert(fb->height);
+ assert(fb->width);
+
+ /* XXX: It would be nice to avoid checking the size again -- in theory
+ * stw_call_window_proc would have cought the resize and stored the right
+ * size already, but unfortunately threads created before the DllMain is
+ * called don't get a DLL_THREAD_ATTACH notification, and there is no way
+ * to know of their existing without using the not very portable PSAPI.
+ */
+ stw_framebuffer_get_size(fb);
+}
+
+
+void
+stw_framebuffer_cleanup( void )
+{
+ struct stw_framebuffer *fb;
+ struct stw_framebuffer *next;
+
+ if (!stw_dev)
+ return;
+
+ pipe_mutex_lock( stw_dev->fb_mutex );
+
+ fb = stw_dev->fb_head;
+ while (fb) {
+ next = fb->next;
+
+ pipe_mutex_lock(fb->mutex);
+ stw_framebuffer_destroy_locked(fb);
+
+ fb = next;
+ }
+ stw_dev->fb_head = NULL;
+
+ pipe_mutex_unlock( stw_dev->fb_mutex );
+}
+
+
+/**
+ * Given an hdc, return the corresponding stw_framebuffer.
+ */
+static INLINE struct stw_framebuffer *
+stw_framebuffer_from_hdc_locked(
+ HDC hdc )
+{
+ HWND hwnd;
+ struct stw_framebuffer *fb;
+
+ /*
+ * Some applications create and use several HDCs for the same window, so
+ * looking up the framebuffer by the HDC is not reliable. Use HWND whenever
+ * possible.
+ */
+ hwnd = WindowFromDC(hdc);
+ if(hwnd)
+ return stw_framebuffer_from_hwnd_locked(hwnd);
+
+ for (fb = stw_dev->fb_head; fb != NULL; fb = fb->next)
+ if (fb->hDC == hdc) {
+ pipe_mutex_lock(fb->mutex);
+ break;
+ }
+
+ return fb;
+}
+
+
+/**
+ * Given an hdc, return the corresponding stw_framebuffer.
+ */
+struct stw_framebuffer *
+stw_framebuffer_from_hdc(
+ HDC hdc )
+{
+ struct stw_framebuffer *fb;
+
+ if (!stw_dev)
+ return NULL;
+
+ pipe_mutex_lock( stw_dev->fb_mutex );
+ fb = stw_framebuffer_from_hdc_locked(hdc);
+ pipe_mutex_unlock( stw_dev->fb_mutex );
+
+ return fb;
+}
+
+
+/**
+ * Given an hdc, return the corresponding stw_framebuffer.
+ */
+struct stw_framebuffer *
+stw_framebuffer_from_hwnd(
+ HWND hwnd )
+{
+ struct stw_framebuffer *fb;
+
+ pipe_mutex_lock( stw_dev->fb_mutex );
+ fb = stw_framebuffer_from_hwnd_locked(hwnd);
+ pipe_mutex_unlock( stw_dev->fb_mutex );
+
+ return fb;
+}
+
+
+BOOL APIENTRY
+DrvSetPixelFormat(
+ HDC hdc,
+ LONG iPixelFormat )
+{
+ uint count;
+ uint index;
+ struct stw_framebuffer *fb;
+
+ if (!stw_dev)
+ return FALSE;
+
+ index = (uint) iPixelFormat - 1;
+ count = stw_pixelformat_get_extended_count();
+ if (index >= count)
+ return FALSE;
+
+ fb = stw_framebuffer_from_hdc_locked(hdc);
+ if(fb) {
+ /* SetPixelFormat must be called only once */
+ stw_framebuffer_release( fb );
+ return FALSE;
+ }
+
+ fb = stw_framebuffer_create(hdc, iPixelFormat);
+ if(!fb) {
+ return FALSE;
+ }
+
+ stw_framebuffer_release( fb );
+
+ /* Some applications mistakenly use the undocumented wglSetPixelFormat
+ * function instead of SetPixelFormat, so we call SetPixelFormat here to
+ * avoid opengl32.dll's wglCreateContext to fail */
+ if (GetPixelFormat(hdc) == 0) {
+ SetPixelFormat(hdc, iPixelFormat, NULL);
+ }
+
+ return TRUE;
+}
+
+
+int
+stw_pixelformat_get(
+ HDC hdc )
+{
+ int iPixelFormat = 0;
+ struct stw_framebuffer *fb;
+
+ fb = stw_framebuffer_from_hdc(hdc);
+ if(fb) {
+ iPixelFormat = fb->iPixelFormat;
+ stw_framebuffer_release(fb);
+ }
+
+ return iPixelFormat;
+}
+
+
+BOOL APIENTRY
+DrvPresentBuffers(HDC hdc, PGLPRESENTBUFFERSDATA data)
+{
+ struct stw_framebuffer *fb;
+ struct pipe_screen *screen;
+ struct pipe_surface *surface;
+
+ if (!stw_dev)
+ return FALSE;
+
+ fb = stw_framebuffer_from_hdc( hdc );
+ if (fb == NULL)
+ return FALSE;
+
+ screen = stw_dev->screen;
+
+ surface = (struct pipe_surface *)data->pPrivateData;
+
+ if(data->hSharedSurface != fb->hSharedSurface) {
+ if(fb->shared_surface) {
+ stw_dev->stw_winsys->shared_surface_close(screen, fb->shared_surface);
+ fb->shared_surface = NULL;
+ }
+
+ fb->hSharedSurface = data->hSharedSurface;
+
+ if(data->hSharedSurface &&
+ stw_dev->stw_winsys->shared_surface_open) {
+ fb->shared_surface = stw_dev->stw_winsys->shared_surface_open(screen, fb->hSharedSurface);
+ }
+ }
+
+ if(fb->shared_surface) {
+ stw_dev->stw_winsys->compose(screen,
+ surface,
+ fb->shared_surface,
+ &fb->client_rect,
+ data->PresentHistoryToken);
+ }
+ else {
+ stw_dev->stw_winsys->present( screen, surface, hdc );
+ }
+
+ stw_framebuffer_update(fb);
+ stw_notify_current_locked(fb);
+
+ stw_framebuffer_release(fb);
+
+ return TRUE;
+}
+
+
+/**
+ * Queue a composition.
+ *
+ * It will drop the lock on success.
+ */
+BOOL
+stw_framebuffer_present_locked(HDC hdc,
+ struct stw_framebuffer *fb,
+ struct pipe_surface *surface)
+{
+ if(stw_dev->callbacks.wglCbPresentBuffers &&
+ stw_dev->stw_winsys->compose) {
+ GLCBPRESENTBUFFERSDATA data;
+
+ memset(&data, 0, sizeof data);
+ data.magic1 = 2;
+ data.magic2 = 0;
+ data.AdapterLuid = stw_dev->AdapterLuid;
+ data.rect = fb->client_rect;
+ data.pPrivateData = (void *)surface;
+
+ stw_notify_current_locked(fb);
+ stw_framebuffer_release(fb);
+
+ return stw_dev->callbacks.wglCbPresentBuffers(hdc, &data);
+ }
+ else {
+ struct pipe_screen *screen = stw_dev->screen;
+
+ stw_dev->stw_winsys->present( screen, surface, hdc );
+
+ stw_framebuffer_update(fb);
+ stw_notify_current_locked(fb);
+ stw_framebuffer_release(fb);
+
+ return TRUE;
+ }
+}
+
+
+BOOL APIENTRY
+DrvSwapBuffers(
+ HDC hdc )
+{
+ struct stw_framebuffer *fb;
+
+ if (!stw_dev)
+ return FALSE;
+
+ fb = stw_framebuffer_from_hdc( hdc );
+ if (fb == NULL)
+ return FALSE;
+
+ if (!(fb->pfi->pfd.dwFlags & PFD_DOUBLEBUFFER)) {
+ stw_framebuffer_release(fb);
+ return TRUE;
+ }
+
+ stw_flush_current_locked(fb);
+
+ return stw_st_swap_framebuffer_locked(fb->stfb);
+}
+
+
+BOOL APIENTRY
+DrvSwapLayerBuffers(
+ HDC hdc,
+ UINT fuPlanes )
+{
+ if(fuPlanes & WGL_SWAP_MAIN_PLANE)
+ return DrvSwapBuffers(hdc);
+
+ return FALSE;
+}
diff --git a/src/gallium/state_trackers/wgl/stw_framebuffer.h b/src/gallium/state_trackers/wgl/stw_framebuffer.h
new file mode 100644
index 0000000000..89d12300e6
--- /dev/null
+++ b/src/gallium/state_trackers/wgl/stw_framebuffer.h
@@ -0,0 +1,167 @@
+/**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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 STW_FRAMEBUFFER_H
+#define STW_FRAMEBUFFER_H
+
+#include <windows.h>
+
+#include "os/os_thread.h"
+
+struct pipe_surface;
+struct st_framebuffer_iface;
+struct stw_pixelformat_info;
+
+/**
+ * Windows framebuffer, derived from gl_framebuffer.
+ */
+struct stw_framebuffer
+{
+ /**
+ * This mutex has two purposes:
+ * - protect the access to the mutable data members below
+ * - prevent the framebuffer from being deleted while being accessed.
+ *
+ * It is OK to lock this mutex while holding the stw_device::fb_mutex lock,
+ * but the opposite must never happen.
+ */
+ pipe_mutex mutex;
+
+ /*
+ * Immutable members.
+ *
+ * Note that even access to immutable members implies acquiring the mutex
+ * above, to prevent the framebuffer from being destroyed.
+ */
+
+ HDC hDC;
+ HWND hWnd;
+
+ int iPixelFormat;
+ const struct stw_pixelformat_info *pfi;
+
+ struct st_framebuffer_iface *stfb;
+
+ /*
+ * Mutable members.
+ */
+
+ unsigned refcnt;
+
+
+ /* FIXME: Make this work for multiple contexts bound to the same framebuffer */
+ boolean must_resize;
+
+ unsigned width;
+ unsigned height;
+
+ /**
+ * Client area rectangle, relative to the window upper-left corner.
+ *
+ * @sa GLCBPRESENTBUFFERSDATA::rect.
+ */
+ RECT client_rect;
+
+ HANDLE hSharedSurface;
+ struct stw_shared_surface *shared_surface;
+
+ /**
+ * This is protected by stw_device::fb_mutex, not the mutex above.
+ *
+ * Deletions must be done by first acquiring stw_device::fb_mutex, and then
+ * acquiring the stw_framebuffer::mutex of the framebuffer to be deleted.
+ * This ensures that nobody else is reading/writing to the.
+ *
+ * It is not necessary to aquire the mutex above to navigate the linked list
+ * given that deletions are done with stw_device::fb_mutex held, so no other
+ * thread can delete.
+ */
+ struct stw_framebuffer *next;
+};
+
+
+/**
+ * Create a new framebuffer object which will correspond to the given HDC.
+ *
+ * This function will acquire stw_framebuffer::mutex. stw_framebuffer_release
+ * must be called when done
+ */
+struct stw_framebuffer *
+stw_framebuffer_create(
+ HDC hdc,
+ int iPixelFormat );
+
+void
+stw_framebuffer_reference(
+ struct stw_framebuffer **ptr,
+ struct stw_framebuffer *fb);
+
+/**
+ * Search a framebuffer with a matching HWND.
+ *
+ * This function will acquire stw_framebuffer::mutex. stw_framebuffer_release
+ * must be called when done
+ */
+struct stw_framebuffer *
+stw_framebuffer_from_hwnd(
+ HWND hwnd );
+
+/**
+ * Search a framebuffer with a matching HDC.
+ *
+ * This function will acquire stw_framebuffer::mutex. stw_framebuffer_release
+ * must be called when done
+ */
+struct stw_framebuffer *
+stw_framebuffer_from_hdc(
+ HDC hdc );
+
+BOOL
+stw_framebuffer_present_locked(HDC hdc,
+ struct stw_framebuffer *fb,
+ struct pipe_surface *surface);
+
+void
+stw_framebuffer_update(
+ struct stw_framebuffer *fb);
+
+/**
+ * Release stw_framebuffer::mutex lock. This framebuffer must not be accessed
+ * after calling this function, as it may have been deleted by another thread
+ * in the meanwhile.
+ */
+void
+stw_framebuffer_release(
+ struct stw_framebuffer *fb);
+
+/**
+ * Cleanup any existing framebuffers when exiting application.
+ */
+void
+stw_framebuffer_cleanup(void);
+
+#endif /* STW_FRAMEBUFFER_H */
diff --git a/src/gallium/state_trackers/wgl/stw_getprocaddress.c b/src/gallium/state_trackers/wgl/stw_getprocaddress.c
new file mode 100644
index 0000000000..d43a55fa9e
--- /dev/null
+++ b/src/gallium/state_trackers/wgl/stw_getprocaddress.c
@@ -0,0 +1,90 @@
+/**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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 <windows.h>
+
+#define WGL_WGLEXT_PROTOTYPES
+
+#include <GL/gl.h>
+#include <GL/wglext.h>
+
+#include "glapi/glapi.h"
+#include "stw_ext_gallium.h"
+#include "stw_device.h"
+#include "stw_icd.h"
+
+struct stw_extension_entry
+{
+ const char *name;
+ PROC proc;
+};
+
+#define STW_EXTENSION_ENTRY(P) { #P, (PROC) P }
+
+static const struct stw_extension_entry stw_extension_entries[] = {
+
+ /* WGL_ARB_extensions_string */
+ STW_EXTENSION_ENTRY( wglGetExtensionsStringARB ),
+
+ /* WGL_ARB_pixel_format */
+ STW_EXTENSION_ENTRY( wglChoosePixelFormatARB ),
+ STW_EXTENSION_ENTRY( wglGetPixelFormatAttribfvARB ),
+ STW_EXTENSION_ENTRY( wglGetPixelFormatAttribivARB ),
+
+ /* WGL_EXT_extensions_string */
+ STW_EXTENSION_ENTRY( wglGetExtensionsStringEXT ),
+
+ /* WGL_EXT_swap_interval */
+ STW_EXTENSION_ENTRY( wglGetSwapIntervalEXT ),
+ STW_EXTENSION_ENTRY( wglSwapIntervalEXT ),
+
+ /* WGL_EXT_gallium ? */
+ STW_EXTENSION_ENTRY( wglGetGalliumScreenMESA ),
+ STW_EXTENSION_ENTRY( wglCreateGalliumContextMESA ),
+
+ { NULL, NULL }
+};
+
+PROC APIENTRY
+DrvGetProcAddress(
+ LPCSTR lpszProc )
+{
+ const struct stw_extension_entry *entry;
+
+ if (!stw_dev)
+ return NULL;
+
+ if (lpszProc[0] == 'w' && lpszProc[1] == 'g' && lpszProc[2] == 'l')
+ for (entry = stw_extension_entries; entry->name; entry++)
+ if (strcmp( lpszProc, entry->name ) == 0)
+ return entry->proc;
+
+ if (lpszProc[0] == 'g' && lpszProc[1] == 'l')
+ return (PROC) _glapi_get_proc_address( lpszProc );
+
+ return NULL;
+}
diff --git a/src/gallium/state_trackers/wgl/stw_icd.h b/src/gallium/state_trackers/wgl/stw_icd.h
new file mode 100644
index 0000000000..02eb543fef
--- /dev/null
+++ b/src/gallium/state_trackers/wgl/stw_icd.h
@@ -0,0 +1,599 @@
+/**************************************************************************
+ *
+ * Copyright 2008-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 STW_ICD_H
+#define STW_ICD_H
+
+
+#include <windows.h>
+
+#include "GL/gl.h"
+
+
+typedef ULONG DHGLRC;
+
+#define OPENGL_VERSION_110_ENTRIES 336
+
+struct __GLdispatchTableRec
+{
+ void (GLAPIENTRY * NewList)(GLuint, GLenum);
+ void (GLAPIENTRY * EndList)(void);
+ void (GLAPIENTRY * CallList)(GLuint);
+ void (GLAPIENTRY * CallLists)(GLsizei, GLenum, const GLvoid *);
+ void (GLAPIENTRY * DeleteLists)(GLuint, GLsizei);
+ GLuint (GLAPIENTRY * GenLists)(GLsizei);
+ void (GLAPIENTRY * ListBase)(GLuint);
+ void (GLAPIENTRY * Begin)(GLenum);
+ void (GLAPIENTRY * Bitmap)(GLsizei, GLsizei, GLfloat, GLfloat, GLfloat, GLfloat, const GLubyte *);
+ void (GLAPIENTRY * Color3b)(GLbyte, GLbyte, GLbyte);
+ void (GLAPIENTRY * Color3bv)(const GLbyte *);
+ void (GLAPIENTRY * Color3d)(GLdouble, GLdouble, GLdouble);
+ void (GLAPIENTRY * Color3dv)(const GLdouble *);
+ void (GLAPIENTRY * Color3f)(GLfloat, GLfloat, GLfloat);
+ void (GLAPIENTRY * Color3fv)(const GLfloat *);
+ void (GLAPIENTRY * Color3i)(GLint, GLint, GLint);
+ void (GLAPIENTRY * Color3iv)(const GLint *);
+ void (GLAPIENTRY * Color3s)(GLshort, GLshort, GLshort);
+ void (GLAPIENTRY * Color3sv)(const GLshort *);
+ void (GLAPIENTRY * Color3ub)(GLubyte, GLubyte, GLubyte);
+ void (GLAPIENTRY * Color3ubv)(const GLubyte *);
+ void (GLAPIENTRY * Color3ui)(GLuint, GLuint, GLuint);
+ void (GLAPIENTRY * Color3uiv)(const GLuint *);
+ void (GLAPIENTRY * Color3us)(GLushort, GLushort, GLushort);
+ void (GLAPIENTRY * Color3usv)(const GLushort *);
+ void (GLAPIENTRY * Color4b)(GLbyte, GLbyte, GLbyte, GLbyte);
+ void (GLAPIENTRY * Color4bv)(const GLbyte *);
+ void (GLAPIENTRY * Color4d)(GLdouble, GLdouble, GLdouble, GLdouble);
+ void (GLAPIENTRY * Color4dv)(const GLdouble *);
+ void (GLAPIENTRY * Color4f)(GLfloat, GLfloat, GLfloat, GLfloat);
+ void (GLAPIENTRY * Color4fv)(const GLfloat *);
+ void (GLAPIENTRY * Color4i)(GLint, GLint, GLint, GLint);
+ void (GLAPIENTRY * Color4iv)(const GLint *);
+ void (GLAPIENTRY * Color4s)(GLshort, GLshort, GLshort, GLshort);
+ void (GLAPIENTRY * Color4sv)(const GLshort *);
+ void (GLAPIENTRY * Color4ub)(GLubyte, GLubyte, GLubyte, GLubyte);
+ void (GLAPIENTRY * Color4ubv)(const GLubyte *);
+ void (GLAPIENTRY * Color4ui)(GLuint, GLuint, GLuint, GLuint);
+ void (GLAPIENTRY * Color4uiv)(const GLuint *);
+ void (GLAPIENTRY * Color4us)(GLushort, GLushort, GLushort, GLushort);
+ void (GLAPIENTRY * Color4usv)(const GLushort *);
+ void (GLAPIENTRY * EdgeFlag)(GLboolean);
+ void (GLAPIENTRY * EdgeFlagv)(const GLboolean *);
+ void (GLAPIENTRY * End)(void);
+ void (GLAPIENTRY * Indexd)(GLdouble);
+ void (GLAPIENTRY * Indexdv)(const GLdouble *);
+ void (GLAPIENTRY * Indexf)(GLfloat);
+ void (GLAPIENTRY * Indexfv)(const GLfloat *);
+ void (GLAPIENTRY * Indexi)(GLint);
+ void (GLAPIENTRY * Indexiv)(const GLint *);
+ void (GLAPIENTRY * Indexs)(GLshort);
+ void (GLAPIENTRY * Indexsv)(const GLshort *);
+ void (GLAPIENTRY * Normal3b)(GLbyte, GLbyte, GLbyte);
+ void (GLAPIENTRY * Normal3bv)(const GLbyte *);
+ void (GLAPIENTRY * Normal3d)(GLdouble, GLdouble, GLdouble);
+ void (GLAPIENTRY * Normal3dv)(const GLdouble *);
+ void (GLAPIENTRY * Normal3f)(GLfloat, GLfloat, GLfloat);
+ void (GLAPIENTRY * Normal3fv)(const GLfloat *);
+ void (GLAPIENTRY * Normal3i)(GLint, GLint, GLint);
+ void (GLAPIENTRY * Normal3iv)(const GLint *);
+ void (GLAPIENTRY * Normal3s)(GLshort, GLshort, GLshort);
+ void (GLAPIENTRY * Normal3sv)(const GLshort *);
+ void (GLAPIENTRY * RasterPos2d)(GLdouble, GLdouble);
+ void (GLAPIENTRY * RasterPos2dv)(const GLdouble *);
+ void (GLAPIENTRY * RasterPos2f)(GLfloat, GLfloat);
+ void (GLAPIENTRY * RasterPos2fv)(const GLfloat *);
+ void (GLAPIENTRY * RasterPos2i)(GLint, GLint);
+ void (GLAPIENTRY * RasterPos2iv)(const GLint *);
+ void (GLAPIENTRY * RasterPos2s)(GLshort, GLshort);
+ void (GLAPIENTRY * RasterPos2sv)(const GLshort *);
+ void (GLAPIENTRY * RasterPos3d)(GLdouble, GLdouble, GLdouble);
+ void (GLAPIENTRY * RasterPos3dv)(const GLdouble *);
+ void (GLAPIENTRY * RasterPos3f)(GLfloat, GLfloat, GLfloat);
+ void (GLAPIENTRY * RasterPos3fv)(const GLfloat *);
+ void (GLAPIENTRY * RasterPos3i)(GLint, GLint, GLint);
+ void (GLAPIENTRY * RasterPos3iv)(const GLint *);
+ void (GLAPIENTRY * RasterPos3s)(GLshort, GLshort, GLshort);
+ void (GLAPIENTRY * RasterPos3sv)(const GLshort *);
+ void (GLAPIENTRY * RasterPos4d)(GLdouble, GLdouble, GLdouble, GLdouble);
+ void (GLAPIENTRY * RasterPos4dv)(const GLdouble *);
+ void (GLAPIENTRY * RasterPos4f)(GLfloat, GLfloat, GLfloat, GLfloat);
+ void (GLAPIENTRY * RasterPos4fv)(const GLfloat *);
+ void (GLAPIENTRY * RasterPos4i)(GLint, GLint, GLint, GLint);
+ void (GLAPIENTRY * RasterPos4iv)(const GLint *);
+ void (GLAPIENTRY * RasterPos4s)(GLshort, GLshort, GLshort, GLshort);
+ void (GLAPIENTRY * RasterPos4sv)(const GLshort *);
+ void (GLAPIENTRY * Rectd)(GLdouble, GLdouble, GLdouble, GLdouble);
+ void (GLAPIENTRY * Rectdv)(const GLdouble *, const GLdouble *);
+ void (GLAPIENTRY * Rectf)(GLfloat, GLfloat, GLfloat, GLfloat);
+ void (GLAPIENTRY * Rectfv)(const GLfloat *, const GLfloat *);
+ void (GLAPIENTRY * Recti)(GLint, GLint, GLint, GLint);
+ void (GLAPIENTRY * Rectiv)(const GLint *, const GLint *);
+ void (GLAPIENTRY * Rects)(GLshort, GLshort, GLshort, GLshort);
+ void (GLAPIENTRY * Rectsv)(const GLshort *, const GLshort *);
+ void (GLAPIENTRY * TexCoord1d)(GLdouble);
+ void (GLAPIENTRY * TexCoord1dv)(const GLdouble *);
+ void (GLAPIENTRY * TexCoord1f)(GLfloat);
+ void (GLAPIENTRY * TexCoord1fv)(const GLfloat *);
+ void (GLAPIENTRY * TexCoord1i)(GLint);
+ void (GLAPIENTRY * TexCoord1iv)(const GLint *);
+ void (GLAPIENTRY * TexCoord1s)(GLshort);
+ void (GLAPIENTRY * TexCoord1sv)(const GLshort *);
+ void (GLAPIENTRY * TexCoord2d)(GLdouble, GLdouble);
+ void (GLAPIENTRY * TexCoord2dv)(const GLdouble *);
+ void (GLAPIENTRY * TexCoord2f)(GLfloat, GLfloat);
+ void (GLAPIENTRY * TexCoord2fv)(const GLfloat *);
+ void (GLAPIENTRY * TexCoord2i)(GLint, GLint);
+ void (GLAPIENTRY * TexCoord2iv)(const GLint *);
+ void (GLAPIENTRY * TexCoord2s)(GLshort, GLshort);
+ void (GLAPIENTRY * TexCoord2sv)(const GLshort *);
+ void (GLAPIENTRY * TexCoord3d)(GLdouble, GLdouble, GLdouble);
+ void (GLAPIENTRY * TexCoord3dv)(const GLdouble *);
+ void (GLAPIENTRY * TexCoord3f)(GLfloat, GLfloat, GLfloat);
+ void (GLAPIENTRY * TexCoord3fv)(const GLfloat *);
+ void (GLAPIENTRY * TexCoord3i)(GLint, GLint, GLint);
+ void (GLAPIENTRY * TexCoord3iv)(const GLint *);
+ void (GLAPIENTRY * TexCoord3s)(GLshort, GLshort, GLshort);
+ void (GLAPIENTRY * TexCoord3sv)(const GLshort *);
+ void (GLAPIENTRY * TexCoord4d)(GLdouble, GLdouble, GLdouble, GLdouble);
+ void (GLAPIENTRY * TexCoord4dv)(const GLdouble *);
+ void (GLAPIENTRY * TexCoord4f)(GLfloat, GLfloat, GLfloat, GLfloat);
+ void (GLAPIENTRY * TexCoord4fv)(const GLfloat *);
+ void (GLAPIENTRY * TexCoord4i)(GLint, GLint, GLint, GLint);
+ void (GLAPIENTRY * TexCoord4iv)(const GLint *);
+ void (GLAPIENTRY * TexCoord4s)(GLshort, GLshort, GLshort, GLshort);
+ void (GLAPIENTRY * TexCoord4sv)(const GLshort *);
+ void (GLAPIENTRY * Vertex2d)(GLdouble, GLdouble);
+ void (GLAPIENTRY * Vertex2dv)(const GLdouble *);
+ void (GLAPIENTRY * Vertex2f)(GLfloat, GLfloat);
+ void (GLAPIENTRY * Vertex2fv)(const GLfloat *);
+ void (GLAPIENTRY * Vertex2i)(GLint, GLint);
+ void (GLAPIENTRY * Vertex2iv)(const GLint *);
+ void (GLAPIENTRY * Vertex2s)(GLshort, GLshort);
+ void (GLAPIENTRY * Vertex2sv)(const GLshort *);
+ void (GLAPIENTRY * Vertex3d)(GLdouble, GLdouble, GLdouble);
+ void (GLAPIENTRY * Vertex3dv)(const GLdouble *);
+ void (GLAPIENTRY * Vertex3f)(GLfloat, GLfloat, GLfloat);
+ void (GLAPIENTRY * Vertex3fv)(const GLfloat *);
+ void (GLAPIENTRY * Vertex3i)(GLint, GLint, GLint);
+ void (GLAPIENTRY * Vertex3iv)(const GLint *);
+ void (GLAPIENTRY * Vertex3s)(GLshort, GLshort, GLshort);
+ void (GLAPIENTRY * Vertex3sv)(const GLshort *);
+ void (GLAPIENTRY * Vertex4d)(GLdouble, GLdouble, GLdouble, GLdouble);
+ void (GLAPIENTRY * Vertex4dv)(const GLdouble *);
+ void (GLAPIENTRY * Vertex4f)(GLfloat, GLfloat, GLfloat, GLfloat);
+ void (GLAPIENTRY * Vertex4fv)(const GLfloat *);
+ void (GLAPIENTRY * Vertex4i)(GLint, GLint, GLint, GLint);
+ void (GLAPIENTRY * Vertex4iv)(const GLint *);
+ void (GLAPIENTRY * Vertex4s)(GLshort, GLshort, GLshort, GLshort);
+ void (GLAPIENTRY * Vertex4sv)(const GLshort *);
+ void (GLAPIENTRY * ClipPlane)(GLenum, const GLdouble *);
+ void (GLAPIENTRY * ColorMaterial)(GLenum, GLenum);
+ void (GLAPIENTRY * CullFace)(GLenum);
+ void (GLAPIENTRY * Fogf)(GLenum, GLfloat);
+ void (GLAPIENTRY * Fogfv)(GLenum, const GLfloat *);
+ void (GLAPIENTRY * Fogi)(GLenum, GLint);
+ void (GLAPIENTRY * Fogiv)(GLenum, const GLint *);
+ void (GLAPIENTRY * FrontFace)(GLenum);
+ void (GLAPIENTRY * Hint)(GLenum, GLenum);
+ void (GLAPIENTRY * Lightf)(GLenum, GLenum, GLfloat);
+ void (GLAPIENTRY * Lightfv)(GLenum, GLenum, const GLfloat *);
+ void (GLAPIENTRY * Lighti)(GLenum, GLenum, GLint);
+ void (GLAPIENTRY * Lightiv)(GLenum, GLenum, const GLint *);
+ void (GLAPIENTRY * LightModelf)(GLenum, GLfloat);
+ void (GLAPIENTRY * LightModelfv)(GLenum, const GLfloat *);
+ void (GLAPIENTRY * LightModeli)(GLenum, GLint);
+ void (GLAPIENTRY * LightModeliv)(GLenum, const GLint *);
+ void (GLAPIENTRY * LineStipple)(GLint, GLushort);
+ void (GLAPIENTRY * LineWidth)(GLfloat);
+ void (GLAPIENTRY * Materialf)(GLenum, GLenum, GLfloat);
+ void (GLAPIENTRY * Materialfv)(GLenum, GLenum, const GLfloat *);
+ void (GLAPIENTRY * Materiali)(GLenum, GLenum, GLint);
+ void (GLAPIENTRY * Materialiv)(GLenum, GLenum, const GLint *);
+ void (GLAPIENTRY * PointSize)(GLfloat);
+ void (GLAPIENTRY * PolygonMode)(GLenum, GLenum);
+ void (GLAPIENTRY * PolygonStipple)(const GLubyte *);
+ void (GLAPIENTRY * Scissor)(GLint, GLint, GLsizei, GLsizei);
+ void (GLAPIENTRY * ShadeModel)(GLenum);
+ void (GLAPIENTRY * TexParameterf)(GLenum, GLenum, GLfloat);
+ void (GLAPIENTRY * TexParameterfv)(GLenum, GLenum, const GLfloat *);
+ void (GLAPIENTRY * TexParameteri)(GLenum, GLenum, GLint);
+ void (GLAPIENTRY * TexParameteriv)(GLenum, GLenum, const GLint *);
+ void (GLAPIENTRY * TexImage1D)(GLenum, GLint, GLint, GLsizei, GLint, GLenum, GLenum, const GLvoid *);
+ void (GLAPIENTRY * TexImage2D)(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *);
+ void (GLAPIENTRY * TexEnvf)(GLenum, GLenum, GLfloat);
+ void (GLAPIENTRY * TexEnvfv)(GLenum, GLenum, const GLfloat *);
+ void (GLAPIENTRY * TexEnvi)(GLenum, GLenum, GLint);
+ void (GLAPIENTRY * TexEnviv)(GLenum, GLenum, const GLint *);
+ void (GLAPIENTRY * TexGend)(GLenum, GLenum, GLdouble);
+ void (GLAPIENTRY * TexGendv)(GLenum, GLenum, const GLdouble *);
+ void (GLAPIENTRY * TexGenf)(GLenum, GLenum, GLfloat);
+ void (GLAPIENTRY * TexGenfv)(GLenum, GLenum, const GLfloat *);
+ void (GLAPIENTRY * TexGeni)(GLenum, GLenum, GLint);
+ void (GLAPIENTRY * TexGeniv)(GLenum, GLenum, const GLint *);
+ void (GLAPIENTRY * FeedbackBuffer)(GLsizei, GLenum, GLfloat *);
+ void (GLAPIENTRY * SelectBuffer)(GLsizei, GLuint *);
+ GLint (GLAPIENTRY * RenderMode)(GLenum);
+ void (GLAPIENTRY * InitNames)(void);
+ void (GLAPIENTRY * LoadName)(GLuint);
+ void (GLAPIENTRY * PassThrough)(GLfloat);
+ void (GLAPIENTRY * PopName)(void);
+ void (GLAPIENTRY * PushName)(GLuint);
+ void (GLAPIENTRY * DrawBuffer)(GLenum);
+ void (GLAPIENTRY * Clear)(GLbitfield);
+ void (GLAPIENTRY * ClearAccum)(GLfloat, GLfloat, GLfloat, GLfloat);
+ void (GLAPIENTRY * ClearIndex)(GLfloat);
+ void (GLAPIENTRY * ClearColor)(GLclampf, GLclampf, GLclampf, GLclampf);
+ void (GLAPIENTRY * ClearStencil)(GLint);
+ void (GLAPIENTRY * ClearDepth)(GLclampd);
+ void (GLAPIENTRY * StencilMask)(GLuint);
+ void (GLAPIENTRY * ColorMask)(GLboolean, GLboolean, GLboolean, GLboolean);
+ void (GLAPIENTRY * DepthMask)(GLboolean);
+ void (GLAPIENTRY * IndexMask)(GLuint);
+ void (GLAPIENTRY * Accum)(GLenum, GLfloat);
+ void (GLAPIENTRY * Disable)(GLenum);
+ void (GLAPIENTRY * Enable)(GLenum);
+ void (GLAPIENTRY * Finish)(void);
+ void (GLAPIENTRY * Flush)(void);
+ void (GLAPIENTRY * PopAttrib)(void);
+ void (GLAPIENTRY * PushAttrib)(GLbitfield);
+ void (GLAPIENTRY * Map1d)(GLenum, GLdouble, GLdouble, GLint, GLint, const GLdouble *);
+ void (GLAPIENTRY * Map1f)(GLenum, GLfloat, GLfloat, GLint, GLint, const GLfloat *);
+ void (GLAPIENTRY * Map2d)(GLenum, GLdouble, GLdouble, GLint, GLint, GLdouble, GLdouble, GLint, GLint, const GLdouble *);
+ void (GLAPIENTRY * Map2f)(GLenum, GLfloat, GLfloat, GLint, GLint, GLfloat, GLfloat, GLint, GLint, const GLfloat *);
+ void (GLAPIENTRY * MapGrid1d)(GLint, GLdouble, GLdouble);
+ void (GLAPIENTRY * MapGrid1f)(GLint, GLfloat, GLfloat);
+ void (GLAPIENTRY * MapGrid2d)(GLint, GLdouble, GLdouble, GLint, GLdouble, GLdouble);
+ void (GLAPIENTRY * MapGrid2f)(GLint, GLfloat, GLfloat, GLint, GLfloat, GLfloat);
+ void (GLAPIENTRY * EvalCoord1d)(GLdouble);
+ void (GLAPIENTRY * EvalCoord1dv)(const GLdouble *);
+ void (GLAPIENTRY * EvalCoord1f)(GLfloat);
+ void (GLAPIENTRY * EvalCoord1fv)(const GLfloat *);
+ void (GLAPIENTRY * EvalCoord2d)(GLdouble, GLdouble);
+ void (GLAPIENTRY * EvalCoord2dv)(const GLdouble *);
+ void (GLAPIENTRY * EvalCoord2f)(GLfloat, GLfloat);
+ void (GLAPIENTRY * EvalCoord2fv)(const GLfloat *);
+ void (GLAPIENTRY * EvalMesh1)(GLenum, GLint, GLint);
+ void (GLAPIENTRY * EvalPoint1)(GLint);
+ void (GLAPIENTRY * EvalMesh2)(GLenum, GLint, GLint, GLint, GLint);
+ void (GLAPIENTRY * EvalPoint2)(GLint, GLint);
+ void (GLAPIENTRY * AlphaFunc)(GLenum, GLclampf);
+ void (GLAPIENTRY * BlendFunc)(GLenum, GLenum);
+ void (GLAPIENTRY * LogicOp)(GLenum);
+ void (GLAPIENTRY * StencilFunc)(GLenum, GLint, GLuint);
+ void (GLAPIENTRY * StencilOp)(GLenum, GLenum, GLenum);
+ void (GLAPIENTRY * DepthFunc)(GLenum);
+ void (GLAPIENTRY * PixelZoom)(GLfloat, GLfloat);
+ void (GLAPIENTRY * PixelTransferf)(GLenum, GLfloat);
+ void (GLAPIENTRY * PixelTransferi)(GLenum, GLint);
+ void (GLAPIENTRY * PixelStoref)(GLenum, GLfloat);
+ void (GLAPIENTRY * PixelStorei)(GLenum, GLint);
+ void (GLAPIENTRY * PixelMapfv)(GLenum, GLint, const GLfloat *);
+ void (GLAPIENTRY * PixelMapuiv)(GLenum, GLint, const GLuint *);
+ void (GLAPIENTRY * PixelMapusv)(GLenum, GLint, const GLushort *);
+ void (GLAPIENTRY * ReadBuffer)(GLenum);
+ void (GLAPIENTRY * CopyPixels)(GLint, GLint, GLsizei, GLsizei, GLenum);
+ void (GLAPIENTRY * ReadPixels)(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoid *);
+ void (GLAPIENTRY * DrawPixels)(GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+ void (GLAPIENTRY * GetBooleanv)(GLenum, GLboolean *);
+ void (GLAPIENTRY * GetClipPlane)(GLenum, GLdouble *);
+ void (GLAPIENTRY * GetDoublev)(GLenum, GLdouble *);
+ GLenum (GLAPIENTRY * GetError)(void);
+ void (GLAPIENTRY * GetFloatv)(GLenum, GLfloat *);
+ void (GLAPIENTRY * GetIntegerv)(GLenum, GLint *);
+ void (GLAPIENTRY * GetLightfv)(GLenum, GLenum, GLfloat *);
+ void (GLAPIENTRY * GetLightiv)(GLenum, GLenum, GLint *);
+ void (GLAPIENTRY * GetMapdv)(GLenum, GLenum, GLdouble *);
+ void (GLAPIENTRY * GetMapfv)(GLenum, GLenum, GLfloat *);
+ void (GLAPIENTRY * GetMapiv)(GLenum, GLenum, GLint *);
+ void (GLAPIENTRY * GetMaterialfv)(GLenum, GLenum, GLfloat *);
+ void (GLAPIENTRY * GetMaterialiv)(GLenum, GLenum, GLint *);
+ void (GLAPIENTRY * GetPixelMapfv)(GLenum, GLfloat *);
+ void (GLAPIENTRY * GetPixelMapuiv)(GLenum, GLuint *);
+ void (GLAPIENTRY * GetPixelMapusv)(GLenum, GLushort *);
+ void (GLAPIENTRY * GetPolygonStipple)(GLubyte *);
+ const GLubyte * (GLAPIENTRY * GetString)(GLenum);
+ void (GLAPIENTRY * GetTexEnvfv)(GLenum, GLenum, GLfloat *);
+ void (GLAPIENTRY * GetTexEnviv)(GLenum, GLenum, GLint *);
+ void (GLAPIENTRY * GetTexGendv)(GLenum, GLenum, GLdouble *);
+ void (GLAPIENTRY * GetTexGenfv)(GLenum, GLenum, GLfloat *);
+ void (GLAPIENTRY * GetTexGeniv)(GLenum, GLenum, GLint *);
+ void (GLAPIENTRY * GetTexImage)(GLenum, GLint, GLenum, GLenum, GLvoid *);
+ void (GLAPIENTRY * GetTexParameterfv)(GLenum, GLenum, GLfloat *);
+ void (GLAPIENTRY * GetTexParameteriv)(GLenum, GLenum, GLint *);
+ void (GLAPIENTRY * GetTexLevelParameterfv)(GLenum, GLint, GLenum, GLfloat *);
+ void (GLAPIENTRY * GetTexLevelParameteriv)(GLenum, GLint, GLenum, GLint *);
+ GLboolean (GLAPIENTRY * IsEnabled)(GLenum);
+ GLboolean (GLAPIENTRY * IsList)(GLuint);
+ void (GLAPIENTRY * DepthRange)(GLclampd, GLclampd);
+ void (GLAPIENTRY * Frustum)(GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble);
+ void (GLAPIENTRY * LoadIdentity)(void);
+ void (GLAPIENTRY * LoadMatrixf)(const GLfloat *);
+ void (GLAPIENTRY * LoadMatrixd)(const GLdouble *);
+ void (GLAPIENTRY * MatrixMode)(GLenum);
+ void (GLAPIENTRY * MultMatrixf)(const GLfloat *);
+ void (GLAPIENTRY * MultMatrixd)(const GLdouble *);
+ void (GLAPIENTRY * Ortho)(GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble);
+ void (GLAPIENTRY * PopMatrix)(void);
+ void (GLAPIENTRY * PushMatrix)(void);
+ void (GLAPIENTRY * Rotated)(GLdouble, GLdouble, GLdouble, GLdouble);
+ void (GLAPIENTRY * Rotatef)(GLfloat, GLfloat, GLfloat, GLfloat);
+ void (GLAPIENTRY * Scaled)(GLdouble, GLdouble, GLdouble);
+ void (GLAPIENTRY * Scalef)(GLfloat, GLfloat, GLfloat);
+ void (GLAPIENTRY * Translated)(GLdouble, GLdouble, GLdouble);
+ void (GLAPIENTRY * Translatef)(GLfloat, GLfloat, GLfloat);
+ void (GLAPIENTRY * Viewport)(GLint, GLint, GLsizei, GLsizei);
+ void (GLAPIENTRY * ArrayElement)(GLint);
+ void (GLAPIENTRY * BindTexture)(GLenum, GLuint);
+ void (GLAPIENTRY * ColorPointer)(GLint, GLenum, GLsizei, const GLvoid *);
+ void (GLAPIENTRY * DisableClientState)(GLenum);
+ void (GLAPIENTRY * DrawArrays)(GLenum, GLint, GLsizei);
+ void (GLAPIENTRY * DrawElements)(GLenum, GLsizei, GLenum, const GLvoid *);
+ void (GLAPIENTRY * EdgeFlagPointer)(GLsizei, const GLvoid *);
+ void (GLAPIENTRY * EnableClientState)(GLenum);
+ void (GLAPIENTRY * IndexPointer)(GLenum, GLsizei, const GLvoid *);
+ void (GLAPIENTRY * Indexub)(GLubyte);
+ void (GLAPIENTRY * Indexubv)(const GLubyte *);
+ void (GLAPIENTRY * InterleavedArrays)(GLenum, GLsizei, const GLvoid *);
+ void (GLAPIENTRY * NormalPointer)(GLenum, GLsizei, const GLvoid *);
+ void (GLAPIENTRY * PolygonOffset)(GLfloat, GLfloat);
+ void (GLAPIENTRY * TexCoordPointer)(GLint, GLenum, GLsizei, const GLvoid *);
+ void (GLAPIENTRY * VertexPointer)(GLint, GLenum, GLsizei, const GLvoid *);
+ GLboolean (GLAPIENTRY * AreTexturesResident)(GLsizei, const GLuint *, GLboolean *);
+ void (GLAPIENTRY * CopyTexImage1D)(GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLint);
+ void (GLAPIENTRY * CopyTexImage2D)(GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint);
+ void (GLAPIENTRY * CopyTexSubImage1D)(GLenum, GLint, GLint, GLint, GLint, GLsizei);
+ void (GLAPIENTRY * CopyTexSubImage2D)(GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei);
+ void (GLAPIENTRY * DeleteTextures)(GLsizei, const GLuint *);
+ void (GLAPIENTRY * GenTextures)(GLsizei, GLuint *);
+ void (GLAPIENTRY * GetPointerv)(GLenum, GLvoid **);
+ GLboolean (GLAPIENTRY * IsTexture)(GLuint);
+ void (GLAPIENTRY * PrioritizeTextures)(GLsizei, const GLuint *, const GLclampf *);
+ void (GLAPIENTRY * TexSubImage1D)(GLenum, GLint, GLint, GLsizei, GLenum, GLenum, const GLvoid *);
+ void (GLAPIENTRY * TexSubImage2D)(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+ void (GLAPIENTRY * PopClientAttrib)(void);
+ void (GLAPIENTRY * PushClientAttrib)(GLbitfield);
+};
+
+typedef struct __GLdispatchTableRec GLDISPATCHTABLE;
+
+typedef struct _GLCLTPROCTABLE
+{
+ int cEntries;
+ GLDISPATCHTABLE glDispatchTable;
+} GLCLTPROCTABLE, * PGLCLTPROCTABLE;
+
+typedef VOID (APIENTRY * PFN_SETPROCTABLE)(PGLCLTPROCTABLE);
+
+/**
+ * Presentation data passed to opengl32!wglCbPresentBuffers.
+ *
+ * Pure software drivers don't need to worry about this -- if they stick to the
+ * GDI API then will integrate with the Desktop Window Manager (DWM) without
+ * problems. Hardware drivers, however, cannot present directly to the primary
+ * surface while the DWM is active, as DWM gets exclusive access to the primary
+ * surface.
+ *
+ * Proper DWM integration requires:
+ * - advertise the PFD_SUPPORT_COMPOSITION flag
+ * - redirect glFlush/glfinish/wglSwapBuffers into a surface shared with the
+ * DWM process.
+ *
+ * @sa http://www.opengl.org/pipeline/article/vol003_7/
+ * @sa http://blogs.msdn.com/greg_schechter/archive/2006/05/02/588934.aspx
+ */
+typedef struct _GLCBPRESENTBUFFERSDATA
+{
+ /**
+ * wglCbPresentBuffers enforces this to be 2.
+ */
+ DWORD magic1;
+
+ /**
+ * wglCbPresentBuffers enforces to be 0 or 1, but it is most commonly
+ * set to 0.
+ */
+ DWORD magic2;
+
+ /**
+ * Locally unique identifier (LUID) of the graphics adapter.
+ *
+ * This should contain the value returned by D3DKMTOpenAdapterFromHdc. It
+ * is passed to dwmapi!DwmpDxGetWindowSharedSurface in order to obtain
+ * the shared surface handle for the bound drawable (window).
+ *
+ * @sa http://msdn.microsoft.com/en-us/library/ms799177.aspx
+ */
+ LUID AdapterLuid;
+
+ /**
+ * This is passed unmodified to DrvPresentBuffers
+ */
+ LPVOID pPrivateData;
+
+ /**
+ * Client area rectangle to update, relative to the window upper-left corner.
+ */
+ RECT rect;
+} GLCBPRESENTBUFFERSDATA, *PGLCBPRESENTBUFFERSDATA;
+
+/**
+ * Callbacks supplied to DrvSetCallbackProcs by the OpenGL runtime.
+ *
+ * Pointers to several callback functions in opengl32.dll.
+ */
+typedef struct _GLCALLBACKTABLE
+{
+ /** Unused */
+ PROC wglCbSetCurrentValue;
+
+ /** Unused */
+ PROC wglCbGetCurrentValue;
+
+ /** Unused */
+ PROC wglCbGetDhglrc;
+
+ /** Unused */
+ PROC wglCbGetDdHandle;
+
+ /**
+ * Queue a present composition.
+ *
+ * Makes the runtime call DrvPresentBuffers with the composition information.
+ */
+ BOOL (APIENTRY *wglCbPresentBuffers)(HDC hdc, PGLCBPRESENTBUFFERSDATA data);
+
+} GLCALLBACKTABLE;
+
+typedef struct _GLPRESENTBUFFERSDATA
+{
+ /**
+ * The shared surface handle.
+ *
+ * Return by dwmapi!DwmpDxGetWindowSharedSurface.
+ *
+ * @sa http://channel9.msdn.com/forums/TechOff/251261-Help-Getting-the-shared-window-texture-out-of-DWM-/
+ */
+ HANDLE hSharedSurface;
+
+ LUID AdapterLuid;
+
+ /**
+ * Present history token.
+ *
+ * This is returned by dwmapi!DwmpDxGetWindowSharedSurface and
+ * should be passed to D3DKMTRender in D3DKMT_RENDER::PresentHistoryToken.
+ *
+ * @sa http://msdn.microsoft.com/en-us/library/ms799176.aspx
+ */
+ ULONGLONG PresentHistoryToken;
+
+ /** Same as GLCBPRESENTBUFFERSDATA::pPrivateData */
+ LPVOID pPrivateData;
+} GLPRESENTBUFFERSDATA, *PGLPRESENTBUFFERSDATA;
+
+BOOL APIENTRY
+DrvCopyContext(
+ DHGLRC dhrcSource,
+ DHGLRC dhrcDest,
+ UINT fuMask );
+
+DHGLRC APIENTRY
+DrvCreateLayerContext(
+ HDC hdc,
+ INT iLayerPlane );
+
+DHGLRC APIENTRY
+DrvCreateContext(
+ HDC hdc );
+
+BOOL APIENTRY
+DrvDeleteContext(
+ DHGLRC dhglrc );
+
+BOOL APIENTRY
+DrvDescribeLayerPlane(
+ HDC hdc,
+ INT iPixelFormat,
+ INT iLayerPlane,
+ UINT nBytes,
+ LPLAYERPLANEDESCRIPTOR plpd );
+
+LONG APIENTRY
+DrvDescribePixelFormat(
+ HDC hdc,
+ INT iPixelFormat,
+ ULONG cjpfd,
+ PIXELFORMATDESCRIPTOR *ppfd );
+
+int APIENTRY
+DrvGetLayerPaletteEntries(
+ HDC hdc,
+ INT iLayerPlane,
+ INT iStart,
+ INT cEntries,
+ COLORREF *pcr );
+
+PROC APIENTRY
+DrvGetProcAddress(
+ LPCSTR lpszProc );
+
+BOOL APIENTRY
+DrvPresentBuffers(HDC hdc, PGLPRESENTBUFFERSDATA data);
+
+BOOL APIENTRY
+DrvRealizeLayerPalette(
+ HDC hdc,
+ INT iLayerPlane,
+ BOOL bRealize );
+
+BOOL APIENTRY
+DrvReleaseContext(
+ DHGLRC dhglrc );
+
+void APIENTRY
+DrvSetCallbackProcs(
+ INT nProcs,
+ PROC *pProcs );
+
+PGLCLTPROCTABLE APIENTRY
+DrvSetContext(
+ HDC hdc,
+ DHGLRC dhglrc,
+ PFN_SETPROCTABLE pfnSetProcTable );
+
+int APIENTRY
+DrvSetLayerPaletteEntries(
+ HDC hdc,
+ INT iLayerPlane,
+ INT iStart,
+ INT cEntries,
+ CONST COLORREF *pcr );
+
+BOOL APIENTRY
+DrvSetPixelFormat(
+ HDC hdc,
+ LONG iPixelFormat );
+
+BOOL APIENTRY
+DrvShareLists(
+ DHGLRC dhglrc1,
+ DHGLRC dhglrc2 );
+
+BOOL APIENTRY
+DrvSwapBuffers(
+ HDC hdc );
+
+BOOL APIENTRY
+DrvSwapLayerBuffers(
+ HDC hdc,
+ UINT fuPlanes );
+
+BOOL APIENTRY
+DrvValidateVersion(
+ ULONG ulVersion );
+
+#endif /* STW_ICD_H */
diff --git a/src/gallium/state_trackers/wgl/stw_pixelformat.c b/src/gallium/state_trackers/wgl/stw_pixelformat.c
new file mode 100644
index 0000000000..e606477e97
--- /dev/null
+++ b/src/gallium/state_trackers/wgl/stw_pixelformat.c
@@ -0,0 +1,403 @@
+/**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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 "main/mtypes.h"
+#include "main/context.h"
+
+#include "pipe/p_format.h"
+#include "pipe/p_defines.h"
+#include "pipe/p_screen.h"
+
+#include "util/u_format.h"
+#include "util/u_debug.h"
+
+#include "stw_icd.h"
+#include "stw_device.h"
+#include "stw_pixelformat.h"
+#include "stw_tls.h"
+
+
+struct stw_pf_color_info
+{
+ enum pipe_format format;
+ struct {
+ unsigned char red;
+ unsigned char green;
+ unsigned char blue;
+ unsigned char alpha;
+ } bits;
+ struct {
+ unsigned char red;
+ unsigned char green;
+ unsigned char blue;
+ unsigned char alpha;
+ } shift;
+};
+
+struct stw_pf_depth_info
+{
+ enum pipe_format format;
+ struct {
+ unsigned char depth;
+ unsigned char stencil;
+ } bits;
+};
+
+
+/* NOTE: order matters, since in otherwise equal circumstances the first
+ * format listed will get chosen */
+
+static const struct stw_pf_color_info
+stw_pf_color[] = {
+ /* no-alpha */
+ { PIPE_FORMAT_B8G8R8X8_UNORM, { 8, 8, 8, 0}, {16, 8, 0, 0} },
+ { PIPE_FORMAT_X8R8G8B8_UNORM, { 8, 8, 8, 0}, { 8, 16, 24, 0} },
+ { PIPE_FORMAT_B5G6R5_UNORM, { 5, 6, 5, 0}, {11, 5, 0, 0} },
+ /* alpha */
+ { PIPE_FORMAT_B8G8R8A8_UNORM, { 8, 8, 8, 8}, {16, 8, 0, 24} },
+ { PIPE_FORMAT_A8R8G8B8_UNORM, { 8, 8, 8, 8}, { 8, 16, 24, 0} },
+#if 0
+ { PIPE_FORMAT_R10G10B10A2_UNORM, {10, 10, 10, 2}, { 0, 10, 20, 30} },
+#endif
+ { PIPE_FORMAT_B5G5R5A1_UNORM, { 5, 5, 5, 1}, {10, 5, 0, 15} },
+ { PIPE_FORMAT_B4G4R4A4_UNORM, { 4, 4, 4, 4}, {16, 4, 0, 12} }
+};
+
+
+static const struct stw_pf_depth_info
+stw_pf_depth_stencil[] = {
+ /* pure depth */
+ { PIPE_FORMAT_Z32_UNORM, {32, 0} },
+ { PIPE_FORMAT_X8Z24_UNORM, {24, 0} },
+ { PIPE_FORMAT_Z24X8_UNORM, {24, 0} },
+ { PIPE_FORMAT_Z16_UNORM, {16, 0} },
+ /* combined depth-stencil */
+ { PIPE_FORMAT_Z24_UNORM_S8_USCALED, {24, 8} },
+ { PIPE_FORMAT_S8_USCALED_Z24_UNORM, {24, 8} }
+};
+
+
+static const boolean
+stw_pf_doublebuffer[] = {
+ FALSE,
+ TRUE,
+};
+
+
+const unsigned
+stw_pf_multisample[] = {
+ 0,
+ 4
+};
+
+
+static void
+stw_pixelformat_add(
+ struct stw_device *stw_dev,
+ const struct stw_pf_color_info *color,
+ const struct stw_pf_depth_info *depth,
+ unsigned accum,
+ boolean doublebuffer,
+ unsigned samples )
+{
+ boolean extended = FALSE;
+ struct stw_pixelformat_info *pfi;
+
+ assert(stw_dev->pixelformat_extended_count < STW_MAX_PIXELFORMATS);
+ if(stw_dev->pixelformat_extended_count >= STW_MAX_PIXELFORMATS)
+ return;
+
+ assert(util_format_get_component_bits(color->format, UTIL_FORMAT_COLORSPACE_RGB, 0) == color->bits.red);
+ assert(util_format_get_component_bits(color->format, UTIL_FORMAT_COLORSPACE_RGB, 1) == color->bits.green);
+ assert(util_format_get_component_bits(color->format, UTIL_FORMAT_COLORSPACE_RGB, 2) == color->bits.blue);
+ assert(util_format_get_component_bits(color->format, UTIL_FORMAT_COLORSPACE_RGB, 3) == color->bits.alpha);
+ assert(util_format_get_component_bits(depth->format, UTIL_FORMAT_COLORSPACE_ZS, 0) == depth->bits.depth);
+ assert(util_format_get_component_bits(depth->format, UTIL_FORMAT_COLORSPACE_ZS, 1) == depth->bits.stencil);
+
+ pfi = &stw_dev->pixelformats[stw_dev->pixelformat_extended_count];
+
+ memset(pfi, 0, sizeof *pfi);
+
+ pfi->pfd.nSize = sizeof pfi->pfd;
+ pfi->pfd.nVersion = 1;
+
+ pfi->pfd.dwFlags = PFD_SUPPORT_OPENGL;
+
+ /* TODO: also support non-native pixel formats */
+ pfi->pfd.dwFlags |= PFD_DRAW_TO_WINDOW;
+
+ /* See http://www.opengl.org/pipeline/article/vol003_7/ */
+ pfi->pfd.dwFlags |= PFD_SUPPORT_COMPOSITION;
+
+ if (doublebuffer)
+ pfi->pfd.dwFlags |= PFD_DOUBLEBUFFER | PFD_SWAP_COPY;
+
+ pfi->pfd.iPixelType = PFD_TYPE_RGBA;
+
+ pfi->pfd.cColorBits = color->bits.red + color->bits.green + color->bits.blue + color->bits.alpha;
+ pfi->pfd.cRedBits = color->bits.red;
+ pfi->pfd.cRedShift = color->shift.red;
+ pfi->pfd.cGreenBits = color->bits.green;
+ pfi->pfd.cGreenShift = color->shift.green;
+ pfi->pfd.cBlueBits = color->bits.blue;
+ pfi->pfd.cBlueShift = color->shift.blue;
+ pfi->pfd.cAlphaBits = color->bits.alpha;
+ pfi->pfd.cAlphaShift = color->shift.alpha;
+ pfi->pfd.cAccumBits = 4*accum;
+ pfi->pfd.cAccumRedBits = accum;
+ pfi->pfd.cAccumGreenBits = accum;
+ pfi->pfd.cAccumBlueBits = accum;
+ pfi->pfd.cAccumAlphaBits = accum;
+ pfi->pfd.cDepthBits = depth->bits.depth;
+ pfi->pfd.cStencilBits = depth->bits.stencil;
+ pfi->pfd.cAuxBuffers = 0;
+ pfi->pfd.iLayerType = 0;
+ pfi->pfd.bReserved = 0;
+ pfi->pfd.dwLayerMask = 0;
+ pfi->pfd.dwVisibleMask = 0;
+ pfi->pfd.dwDamageMask = 0;
+
+ /*
+ * since state trackers can allocate depth/stencil/accum buffers, we provide
+ * only color buffers here
+ */
+ pfi->stvis.buffer_mask = ST_ATTACHMENT_FRONT_LEFT_MASK;
+ if (doublebuffer)
+ pfi->stvis.buffer_mask = ST_ATTACHMENT_BACK_LEFT_MASK;
+
+ pfi->stvis.color_format = color->format;
+ pfi->stvis.depth_stencil_format = depth->format;
+
+ pfi->stvis.accum_format = (accum) ?
+ PIPE_FORMAT_R16G16B16A16_SNORM : PIPE_FORMAT_NONE;
+
+ pfi->stvis.samples = samples;
+ pfi->stvis.render_buffer = ST_ATTACHMENT_INVALID;
+
+ ++stw_dev->pixelformat_extended_count;
+
+ if(!extended) {
+ ++stw_dev->pixelformat_count;
+ assert(stw_dev->pixelformat_count == stw_dev->pixelformat_extended_count);
+ }
+}
+
+void
+stw_pixelformat_init( void )
+{
+ struct pipe_screen *screen = stw_dev->screen;
+ unsigned i, j, k, l;
+
+ assert( !stw_dev->pixelformat_count );
+ assert( !stw_dev->pixelformat_extended_count );
+
+ for(i = 0; i < Elements(stw_pf_multisample); ++i) {
+ unsigned samples = stw_pf_multisample[i];
+
+ /* FIXME: re-enabled MSAA when we can query it */
+ if(samples)
+ continue;
+
+ for(j = 0; j < Elements(stw_pf_color); ++j) {
+ const struct stw_pf_color_info *color = &stw_pf_color[j];
+
+ if(!screen->is_format_supported(screen, color->format, PIPE_TEXTURE_2D,
+ 0, PIPE_BIND_RENDER_TARGET |
+ PIPE_BIND_DISPLAY_TARGET, 0))
+ continue;
+
+ for(k = 0; k < Elements(stw_pf_doublebuffer); ++k) {
+ unsigned doublebuffer = stw_pf_doublebuffer[k];
+
+ for(l = 0; l < Elements(stw_pf_depth_stencil); ++l) {
+ const struct stw_pf_depth_info *depth = &stw_pf_depth_stencil[l];
+
+ if(!screen->is_format_supported(screen, depth->format, PIPE_TEXTURE_2D,
+ 0, PIPE_BIND_DEPTH_STENCIL, 0))
+ continue;
+
+ stw_pixelformat_add( stw_dev, color, depth, 0, doublebuffer, samples );
+ stw_pixelformat_add( stw_dev, color, depth, 16, doublebuffer, samples );
+ }
+ }
+ }
+ }
+
+ assert( stw_dev->pixelformat_count <= stw_dev->pixelformat_extended_count );
+ assert( stw_dev->pixelformat_extended_count <= STW_MAX_PIXELFORMATS );
+}
+
+uint
+stw_pixelformat_get_count( void )
+{
+ return stw_dev->pixelformat_count;
+}
+
+uint
+stw_pixelformat_get_extended_count( void )
+{
+ return stw_dev->pixelformat_extended_count;
+}
+
+const struct stw_pixelformat_info *
+stw_pixelformat_get_info( uint index )
+{
+ assert( index < stw_dev->pixelformat_extended_count );
+
+ return &stw_dev->pixelformats[index];
+}
+
+
+LONG APIENTRY
+DrvDescribePixelFormat(
+ HDC hdc,
+ INT iPixelFormat,
+ ULONG cjpfd,
+ PIXELFORMATDESCRIPTOR *ppfd )
+{
+ uint count;
+ uint index;
+ const struct stw_pixelformat_info *pfi;
+
+ (void) hdc;
+
+ if (!stw_dev)
+ return 0;
+
+ count = stw_pixelformat_get_extended_count();
+ index = (uint) iPixelFormat - 1;
+
+ if (ppfd == NULL)
+ return count;
+ if (index >= count || cjpfd != sizeof( PIXELFORMATDESCRIPTOR ))
+ return 0;
+
+ pfi = stw_pixelformat_get_info( index );
+
+ memcpy(ppfd, &pfi->pfd, sizeof( PIXELFORMATDESCRIPTOR ));
+
+ return count;
+}
+
+BOOL APIENTRY
+DrvDescribeLayerPlane(
+ HDC hdc,
+ INT iPixelFormat,
+ INT iLayerPlane,
+ UINT nBytes,
+ LPLAYERPLANEDESCRIPTOR plpd )
+{
+ assert(0);
+ return FALSE;
+}
+
+int APIENTRY
+DrvGetLayerPaletteEntries(
+ HDC hdc,
+ INT iLayerPlane,
+ INT iStart,
+ INT cEntries,
+ COLORREF *pcr )
+{
+ assert(0);
+ return 0;
+}
+
+int APIENTRY
+DrvSetLayerPaletteEntries(
+ HDC hdc,
+ INT iLayerPlane,
+ INT iStart,
+ INT cEntries,
+ CONST COLORREF *pcr )
+{
+ assert(0);
+ return 0;
+}
+
+BOOL APIENTRY
+DrvRealizeLayerPalette(
+ HDC hdc,
+ INT iLayerPlane,
+ BOOL bRealize )
+{
+ assert(0);
+ return FALSE;
+}
+
+/* Only used by the wgl code, but have it here to avoid exporting the
+ * pixelformat.h functionality.
+ */
+int stw_pixelformat_choose( HDC hdc,
+ CONST PIXELFORMATDESCRIPTOR *ppfd )
+{
+ uint count;
+ uint index;
+ uint bestindex;
+ uint bestdelta;
+
+ (void) hdc;
+
+ count = stw_pixelformat_get_count();
+ bestindex = count;
+ bestdelta = ~0U;
+
+ for (index = 0; index < count; index++) {
+ uint delta = 0;
+ const struct stw_pixelformat_info *pfi = stw_pixelformat_get_info( index );
+
+ if (!(ppfd->dwFlags & PFD_DOUBLEBUFFER_DONTCARE) &&
+ !!(ppfd->dwFlags & PFD_DOUBLEBUFFER) !=
+ !!(pfi->pfd.dwFlags & PFD_DOUBLEBUFFER))
+ continue;
+
+ /* FIXME: Take in account individual channel bits */
+ if (ppfd->cColorBits != pfi->pfd.cColorBits)
+ delta += 8;
+
+ if (ppfd->cDepthBits != pfi->pfd.cDepthBits)
+ delta += 4;
+
+ if (ppfd->cStencilBits != pfi->pfd.cStencilBits)
+ delta += 2;
+
+ if (ppfd->cAlphaBits != pfi->pfd.cAlphaBits)
+ delta++;
+
+ if (delta < bestdelta) {
+ bestindex = index;
+ bestdelta = delta;
+ if (bestdelta == 0)
+ break;
+ }
+ }
+
+ if (bestindex == count)
+ return 0;
+
+ return bestindex + 1;
+}
diff --git a/src/gallium/state_trackers/wgl/stw_pixelformat.h b/src/gallium/state_trackers/wgl/stw_pixelformat.h
new file mode 100644
index 0000000000..d405172773
--- /dev/null
+++ b/src/gallium/state_trackers/wgl/stw_pixelformat.h
@@ -0,0 +1,69 @@
+/**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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 STW_PIXELFORMAT_H
+#define STW_PIXELFORMAT_H
+
+#include <windows.h>
+
+#ifndef PFD_SUPPORT_COMPOSITION
+#define PFD_SUPPORT_COMPOSITION 0x00008000
+#endif
+
+#include "main/mtypes.h"
+
+#include "pipe/p_compiler.h"
+#include "pipe/p_format.h"
+#include "state_tracker/st_api.h"
+
+struct stw_pixelformat_info
+{
+ PIXELFORMATDESCRIPTOR pfd;
+
+ struct st_visual stvis;
+};
+
+void
+stw_pixelformat_init( void );
+
+uint
+stw_pixelformat_get_count( void );
+
+uint
+stw_pixelformat_get_extended_count( void );
+
+const struct stw_pixelformat_info *
+stw_pixelformat_get_info( uint index );
+
+int
+stw_pixelformat_choose( HDC hdc,
+ CONST PIXELFORMATDESCRIPTOR *ppfd );
+
+int
+stw_pixelformat_get(HDC hdc);
+
+#endif /* STW_PIXELFORMAT_H */
diff --git a/src/gallium/state_trackers/wgl/stw_st.c b/src/gallium/state_trackers/wgl/stw_st.c
new file mode 100644
index 0000000000..bcdd82e4f6
--- /dev/null
+++ b/src/gallium/state_trackers/wgl/stw_st.c
@@ -0,0 +1,312 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.9
+ *
+ * Copyright (C) 2010 LunarG Inc.
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL 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.
+ *
+ * Authors:
+ * Chia-I Wu <olv@lunarg.com>
+ */
+
+#include "util/u_memory.h"
+#include "util/u_inlines.h"
+#include "state_tracker/st_gl_api.h" /* for st_gl_api_create */
+
+#include "stw_st.h"
+#include "stw_device.h"
+#include "stw_framebuffer.h"
+#include "stw_pixelformat.h"
+
+struct stw_st_framebuffer {
+ struct st_framebuffer_iface base;
+
+ struct stw_framebuffer *fb;
+ struct st_visual stvis;
+
+ struct pipe_resource *textures[ST_ATTACHMENT_COUNT];
+ unsigned texture_width, texture_height;
+ unsigned texture_mask;
+
+ struct pipe_surface *front_surface, *back_surface;
+};
+
+static INLINE struct stw_st_framebuffer *
+stw_st_framebuffer(struct st_framebuffer_iface *stfb)
+{
+ return (struct stw_st_framebuffer *) stfb;
+}
+
+/**
+ * Remove outdated textures and create the requested ones.
+ */
+static void
+stw_st_framebuffer_validate_locked(struct st_framebuffer_iface *stfb,
+ unsigned width, unsigned height,
+ unsigned mask)
+{
+ struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
+ struct pipe_resource templ;
+ unsigned i;
+
+ /* remove outdated surface */
+ pipe_surface_reference(&stwfb->front_surface, NULL);
+ pipe_surface_reference(&stwfb->back_surface, NULL);
+
+ /* remove outdated textures */
+ if (stwfb->texture_width != width || stwfb->texture_height != height) {
+ for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
+ pipe_resource_reference(&stwfb->textures[i], NULL);
+ }
+
+ memset(&templ, 0, sizeof(templ));
+ templ.target = PIPE_TEXTURE_2D;
+ templ.width0 = width;
+ templ.height0 = height;
+ templ.depth0 = 1;
+ templ.last_level = 0;
+
+ for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
+ enum pipe_format format;
+ unsigned bind;
+
+ /* the texture already exists or not requested */
+ if (stwfb->textures[i] || !(mask & (1 << i))) {
+ /* remember the texture */
+ if (stwfb->textures[i])
+ mask |= (1 << i);
+ continue;
+ }
+
+ switch (i) {
+ case ST_ATTACHMENT_FRONT_LEFT:
+ case ST_ATTACHMENT_BACK_LEFT:
+ format = stwfb->stvis.color_format;
+ bind = PIPE_BIND_DISPLAY_TARGET |
+ PIPE_BIND_RENDER_TARGET;
+ break;
+ case ST_ATTACHMENT_DEPTH_STENCIL:
+ format = stwfb->stvis.depth_stencil_format;
+ bind = PIPE_BIND_DEPTH_STENCIL;
+ break;
+ default:
+ format = PIPE_FORMAT_NONE;
+ break;
+ }
+
+ if (format != PIPE_FORMAT_NONE) {
+ templ.format = format;
+ templ.bind = bind;
+
+ stwfb->textures[i] =
+ stw_dev->screen->resource_create(stw_dev->screen, &templ);
+ }
+ }
+
+ stwfb->texture_width = width;
+ stwfb->texture_height = height;
+ stwfb->texture_mask = mask;
+}
+
+static boolean
+stw_st_framebuffer_validate(struct st_framebuffer_iface *stfb,
+ const enum st_attachment_type *statts,
+ unsigned count,
+ struct pipe_resource **out)
+{
+ struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
+ unsigned statt_mask, i;
+
+ statt_mask = 0x0;
+ for (i = 0; i < count; i++)
+ statt_mask |= 1 << statts[i];
+
+ pipe_mutex_lock(stwfb->fb->mutex);
+
+ if (stwfb->fb->must_resize || (statt_mask & ~stwfb->texture_mask)) {
+ stw_st_framebuffer_validate_locked(&stwfb->base,
+ stwfb->fb->width, stwfb->fb->height, statt_mask);
+ stwfb->fb->must_resize = FALSE;
+ }
+
+ for (i = 0; i < count; i++) {
+ out[i] = NULL;
+ pipe_resource_reference(&out[i], stwfb->textures[statts[i]]);
+ }
+
+ stw_framebuffer_release(stwfb->fb);
+
+ return TRUE;
+}
+
+static struct pipe_surface *
+get_present_surface_locked(struct st_framebuffer_iface *stfb,
+ enum st_attachment_type statt)
+{
+ struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
+ struct pipe_resource *ptex;
+ struct pipe_surface *psurf, **cache;
+
+ ptex = stwfb->textures[statt];
+ if (!ptex)
+ return NULL;
+
+ psurf = NULL;
+
+ switch (statt) {
+ case ST_ATTACHMENT_FRONT_LEFT:
+ cache = &stwfb->front_surface;
+ break;
+ case ST_ATTACHMENT_BACK_LEFT:
+ cache = &stwfb->back_surface;
+ break;
+ default:
+ cache = &psurf;
+ break;
+ }
+
+ if (!*cache) {
+ *cache = stw_dev->screen->get_tex_surface(stw_dev->screen,
+ ptex, 0, 0, 0,
+ PIPE_BIND_DISPLAY_TARGET |
+ PIPE_BIND_RENDER_TARGET);
+ }
+
+ if (psurf != *cache)
+ pipe_surface_reference(&psurf, *cache);
+
+ return psurf;
+}
+
+/**
+ * Present an attachment of the framebuffer.
+ */
+static boolean
+stw_st_framebuffer_present_locked(struct st_framebuffer_iface *stfb,
+ enum st_attachment_type statt)
+{
+ struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
+ struct pipe_surface *psurf;
+
+ psurf = get_present_surface_locked(&stwfb->base, statt);
+ if (psurf) {
+ stw_framebuffer_present_locked(stwfb->fb->hDC, stwfb->fb, psurf);
+ pipe_surface_reference(&psurf, NULL);
+ }
+
+ return TRUE;
+}
+
+static boolean
+stw_st_framebuffer_flush_front(struct st_framebuffer_iface *stfb,
+ enum st_attachment_type statt)
+{
+ struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
+
+ pipe_mutex_lock(stwfb->fb->mutex);
+
+ return stw_st_framebuffer_present_locked(&stwfb->base, statt);
+}
+
+/**
+ * Create a framebuffer interface.
+ */
+struct st_framebuffer_iface *
+stw_st_create_framebuffer(struct stw_framebuffer *fb)
+{
+ struct stw_st_framebuffer *stwfb;
+
+ stwfb = CALLOC_STRUCT(stw_st_framebuffer);
+ if (!stwfb)
+ return NULL;
+
+ stwfb->fb = fb;
+ stwfb->stvis = fb->pfi->stvis;
+
+ stwfb->base.visual = &stwfb->stvis;
+ stwfb->base.flush_front = stw_st_framebuffer_flush_front;
+ stwfb->base.validate = stw_st_framebuffer_validate;
+
+ return &stwfb->base;
+}
+
+/**
+ * Destroy a framebuffer interface.
+ */
+void
+stw_st_destroy_framebuffer_locked(struct st_framebuffer_iface *stfb)
+{
+ struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
+ int i;
+
+ pipe_surface_reference(&stwfb->front_surface, NULL);
+ pipe_surface_reference(&stwfb->back_surface, NULL);
+
+ for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
+ pipe_resource_reference(&stwfb->textures[i], NULL);
+
+ FREE(stwfb);
+}
+
+/**
+ * Swap the buffers of the given framebuffer.
+ */
+boolean
+stw_st_swap_framebuffer_locked(struct st_framebuffer_iface *stfb)
+{
+ struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
+ unsigned front = ST_ATTACHMENT_FRONT_LEFT, back = ST_ATTACHMENT_BACK_LEFT;
+ struct pipe_resource *ptex;
+ struct pipe_surface *psurf;
+ unsigned mask;
+
+ /* swap the textures */
+ ptex = stwfb->textures[front];
+ stwfb->textures[front] = stwfb->textures[back];
+ stwfb->textures[back] = ptex;
+
+ /* swap the surfaces */
+ psurf = stwfb->front_surface;
+ stwfb->front_surface = stwfb->back_surface;
+ stwfb->back_surface = psurf;
+
+ /* convert to mask */
+ front = 1 << front;
+ back = 1 << back;
+
+ /* swap the bits in mask */
+ mask = stwfb->texture_mask & ~(front | back);
+ if (stwfb->texture_mask & front)
+ mask |= back;
+ if (stwfb->texture_mask & back)
+ mask |= front;
+ stwfb->texture_mask = mask;
+
+ front = ST_ATTACHMENT_FRONT_LEFT;
+ return stw_st_framebuffer_present_locked(&stwfb->base, front);
+}
+
+/**
+ * Create an st_api of the state tracker.
+ */
+struct st_api *
+stw_st_create_api(void)
+{
+ return st_gl_api_create();
+}
diff --git a/src/gallium/state_trackers/wgl/stw_st.h b/src/gallium/state_trackers/wgl/stw_st.h
new file mode 100644
index 0000000000..23771d8bef
--- /dev/null
+++ b/src/gallium/state_trackers/wgl/stw_st.h
@@ -0,0 +1,47 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.9
+ *
+ * Copyright (C) 2010 LunarG Inc.
+ *
+ * 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL 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.
+ *
+ * Authors:
+ * Chia-I Wu <olv@lunarg.com>
+ */
+
+#ifndef STW_ST_H
+#define STW_ST_H
+
+#include "state_tracker/st_api.h"
+
+struct stw_framebuffer;
+
+struct st_api *
+stw_st_create_api(void);
+
+struct st_framebuffer_iface *
+stw_st_create_framebuffer(struct stw_framebuffer *fb);
+
+void
+stw_st_destroy_framebuffer_locked(struct st_framebuffer_iface *stfb);
+
+boolean
+stw_st_swap_framebuffer_locked(struct st_framebuffer_iface *stfb);
+
+#endif /* STW_ST_H */
diff --git a/src/gallium/state_trackers/wgl/stw_tls.c b/src/gallium/state_trackers/wgl/stw_tls.c
new file mode 100644
index 0000000000..4bd6a9289c
--- /dev/null
+++ b/src/gallium/state_trackers/wgl/stw_tls.c
@@ -0,0 +1,139 @@
+/**************************************************************************
+ *
+ * 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 TUNGSTEN GRAPHICS 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 <windows.h>
+
+#include "pipe/p_compiler.h"
+#include "util/u_memory.h"
+#include "stw_tls.h"
+
+static DWORD tlsIndex = TLS_OUT_OF_INDEXES;
+
+boolean
+stw_tls_init(void)
+{
+ tlsIndex = TlsAlloc();
+ if (tlsIndex == TLS_OUT_OF_INDEXES) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static INLINE struct stw_tls_data *
+stw_tls_data_create()
+{
+ struct stw_tls_data *data;
+
+ data = CALLOC_STRUCT(stw_tls_data);
+ if (!data)
+ goto no_data;
+
+ data->hCallWndProcHook = SetWindowsHookEx(WH_CALLWNDPROC,
+ stw_call_window_proc,
+ NULL,
+ GetCurrentThreadId());
+ if(data->hCallWndProcHook == NULL)
+ goto no_hook;
+
+ TlsSetValue(tlsIndex, data);
+
+ return data;
+
+no_hook:
+ FREE(data);
+no_data:
+ return NULL;
+}
+
+boolean
+stw_tls_init_thread(void)
+{
+ struct stw_tls_data *data;
+
+ if (tlsIndex == TLS_OUT_OF_INDEXES) {
+ return FALSE;
+ }
+
+ data = stw_tls_data_create();
+ if(!data)
+ return FALSE;
+
+ return TRUE;
+}
+
+void
+stw_tls_cleanup_thread(void)
+{
+ struct stw_tls_data *data;
+
+ if (tlsIndex == TLS_OUT_OF_INDEXES) {
+ return;
+ }
+
+ data = (struct stw_tls_data *) TlsGetValue(tlsIndex);
+ if(data) {
+ TlsSetValue(tlsIndex, NULL);
+
+ if(data->hCallWndProcHook) {
+ UnhookWindowsHookEx(data->hCallWndProcHook);
+ data->hCallWndProcHook = NULL;
+ }
+
+ FREE(data);
+ }
+}
+
+void
+stw_tls_cleanup(void)
+{
+ if (tlsIndex != TLS_OUT_OF_INDEXES) {
+ TlsFree(tlsIndex);
+ tlsIndex = TLS_OUT_OF_INDEXES;
+ }
+}
+
+struct stw_tls_data *
+stw_tls_get_data(void)
+{
+ struct stw_tls_data *data;
+
+ if (tlsIndex == TLS_OUT_OF_INDEXES) {
+ return NULL;
+ }
+
+ data = (struct stw_tls_data *) TlsGetValue(tlsIndex);
+ if(!data) {
+ /* DllMain is called with DLL_THREAD_ATTACH only by threads created after
+ * the DLL is loaded by the process */
+ data = stw_tls_data_create();
+ if(!data)
+ return NULL;
+ }
+
+ return data;
+}
diff --git a/src/gallium/state_trackers/wgl/stw_tls.h b/src/gallium/state_trackers/wgl/stw_tls.h
new file mode 100644
index 0000000000..fbf8b1cbee
--- /dev/null
+++ b/src/gallium/state_trackers/wgl/stw_tls.h
@@ -0,0 +1,59 @@
+/**************************************************************************
+ *
+ * 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 TUNGSTEN GRAPHICS 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 STW_TLS_H
+#define STW_TLS_H
+
+#include <windows.h>
+
+struct stw_tls_data
+{
+ HHOOK hCallWndProcHook;
+};
+
+boolean
+stw_tls_init(void);
+
+boolean
+stw_tls_init_thread(void);
+
+void
+stw_tls_cleanup_thread(void);
+
+void
+stw_tls_cleanup(void);
+
+struct stw_tls_data *
+stw_tls_get_data(void);
+
+LRESULT CALLBACK
+stw_call_window_proc(
+ int nCode,
+ WPARAM wParam,
+ LPARAM lParam );
+
+#endif /* STW_TLS_H */
diff --git a/src/gallium/state_trackers/wgl/stw_wgl.c b/src/gallium/state_trackers/wgl/stw_wgl.c
new file mode 100644
index 0000000000..5fbb7bf7cf
--- /dev/null
+++ b/src/gallium/state_trackers/wgl/stw_wgl.c
@@ -0,0 +1,321 @@
+/**************************************************************************
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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 <windows.h>
+
+#include "util/u_debug.h"
+#include "stw_icd.h"
+#include "stw_context.h"
+#include "stw_pixelformat.h"
+#include "stw_wgl.h"
+
+
+WINGDIAPI BOOL APIENTRY
+wglCopyContext(
+ HGLRC hglrcSrc,
+ HGLRC hglrcDst,
+ UINT mask )
+{
+ return DrvCopyContext( (DHGLRC)(UINT_PTR)hglrcSrc,
+ (DHGLRC)(UINT_PTR)hglrcDst,
+ mask );
+}
+
+WINGDIAPI HGLRC APIENTRY
+wglCreateContext(
+ HDC hdc )
+{
+ return (HGLRC) DrvCreateContext(hdc);
+}
+
+WINGDIAPI HGLRC APIENTRY
+wglCreateLayerContext(
+ HDC hdc,
+ int iLayerPlane )
+{
+ return (HGLRC) DrvCreateLayerContext( hdc, iLayerPlane );
+}
+
+WINGDIAPI BOOL APIENTRY
+wglDeleteContext(
+ HGLRC hglrc )
+{
+ return DrvDeleteContext((DHGLRC)(UINT_PTR)hglrc );
+}
+
+
+WINGDIAPI HGLRC APIENTRY
+wglGetCurrentContext( VOID )
+{
+ return (HGLRC)(UINT_PTR)stw_get_current_context();
+}
+
+WINGDIAPI HDC APIENTRY
+wglGetCurrentDC( VOID )
+{
+ return stw_get_current_dc();
+}
+
+WINGDIAPI BOOL APIENTRY
+wglMakeCurrent(
+ HDC hdc,
+ HGLRC hglrc )
+{
+ return DrvSetContext( hdc, (DHGLRC)(UINT_PTR)hglrc, NULL ) ? TRUE : FALSE;
+}
+
+
+WINGDIAPI BOOL APIENTRY
+wglSwapBuffers(
+ HDC hdc )
+{
+ return DrvSwapBuffers( hdc );
+}
+
+
+WINGDIAPI DWORD WINAPI
+wglSwapMultipleBuffers(UINT n,
+ CONST WGLSWAP *ps)
+{
+ UINT i;
+
+ for (i =0; i < n; ++i)
+ wglSwapBuffers(ps->hdc);
+
+ return 0;
+}
+
+
+WINGDIAPI BOOL APIENTRY
+wglSwapLayerBuffers(
+ HDC hdc,
+ UINT fuPlanes )
+{
+ return DrvSwapLayerBuffers( hdc, fuPlanes );
+}
+
+WINGDIAPI PROC APIENTRY
+wglGetProcAddress(
+ LPCSTR lpszProc )
+{
+ return DrvGetProcAddress( lpszProc );
+}
+
+
+WINGDIAPI int APIENTRY
+wglChoosePixelFormat(
+ HDC hdc,
+ CONST PIXELFORMATDESCRIPTOR *ppfd )
+{
+ if (ppfd->nSize != sizeof( PIXELFORMATDESCRIPTOR ) || ppfd->nVersion != 1)
+ return 0;
+ if (ppfd->iPixelType != PFD_TYPE_RGBA)
+ return 0;
+ if (!(ppfd->dwFlags & PFD_DRAW_TO_WINDOW))
+ return 0;
+ if (!(ppfd->dwFlags & PFD_SUPPORT_OPENGL))
+ return 0;
+ if (ppfd->dwFlags & PFD_DRAW_TO_BITMAP)
+ return 0;
+ if (ppfd->dwFlags & PFD_SUPPORT_GDI)
+ return 0;
+ if (!(ppfd->dwFlags & PFD_STEREO_DONTCARE) && (ppfd->dwFlags & PFD_STEREO))
+ return 0;
+
+ return stw_pixelformat_choose( hdc, ppfd );
+}
+
+WINGDIAPI int APIENTRY
+wglDescribePixelFormat(
+ HDC hdc,
+ int iPixelFormat,
+ UINT nBytes,
+ LPPIXELFORMATDESCRIPTOR ppfd )
+{
+ return DrvDescribePixelFormat( hdc, iPixelFormat, nBytes, ppfd );
+}
+
+WINGDIAPI int APIENTRY
+wglGetPixelFormat(
+ HDC hdc )
+{
+ return stw_pixelformat_get( hdc );
+}
+
+WINGDIAPI BOOL APIENTRY
+wglSetPixelFormat(
+ HDC hdc,
+ int iPixelFormat,
+ const PIXELFORMATDESCRIPTOR *ppfd )
+{
+ if (ppfd->nSize != sizeof( PIXELFORMATDESCRIPTOR ))
+ return FALSE;
+
+ return DrvSetPixelFormat( hdc, iPixelFormat );
+}
+
+
+WINGDIAPI BOOL APIENTRY
+wglUseFontBitmapsA(
+ HDC hdc,
+ DWORD first,
+ DWORD count,
+ DWORD listBase )
+{
+ (void) hdc;
+ (void) first;
+ (void) count;
+ (void) listBase;
+
+ assert( 0 );
+
+ return FALSE;
+}
+
+WINGDIAPI BOOL APIENTRY
+wglShareLists(
+ HGLRC hglrc1,
+ HGLRC hglrc2 )
+{
+ return DrvShareLists((DHGLRC)(UINT_PTR)hglrc1,
+ (DHGLRC)(UINT_PTR)hglrc2);
+}
+
+WINGDIAPI BOOL APIENTRY
+wglUseFontBitmapsW(
+ HDC hdc,
+ DWORD first,
+ DWORD count,
+ DWORD listBase )
+{
+ (void) hdc;
+ (void) first;
+ (void) count;
+ (void) listBase;
+
+ assert( 0 );
+
+ return FALSE;
+}
+
+WINGDIAPI BOOL APIENTRY
+wglUseFontOutlinesA(
+ HDC hdc,
+ DWORD first,
+ DWORD count,
+ DWORD listBase,
+ FLOAT deviation,
+ FLOAT extrusion,
+ int format,
+ LPGLYPHMETRICSFLOAT lpgmf )
+{
+ (void) hdc;
+ (void) first;
+ (void) count;
+ (void) listBase;
+ (void) deviation;
+ (void) extrusion;
+ (void) format;
+ (void) lpgmf;
+
+ assert( 0 );
+
+ return FALSE;
+}
+
+WINGDIAPI BOOL APIENTRY
+wglUseFontOutlinesW(
+ HDC hdc,
+ DWORD first,
+ DWORD count,
+ DWORD listBase,
+ FLOAT deviation,
+ FLOAT extrusion,
+ int format,
+ LPGLYPHMETRICSFLOAT lpgmf )
+{
+ (void) hdc;
+ (void) first;
+ (void) count;
+ (void) listBase;
+ (void) deviation;
+ (void) extrusion;
+ (void) format;
+ (void) lpgmf;
+
+ assert( 0 );
+
+ return FALSE;
+}
+
+WINGDIAPI BOOL APIENTRY
+wglDescribeLayerPlane(
+ HDC hdc,
+ int iPixelFormat,
+ int iLayerPlane,
+ UINT nBytes,
+ LPLAYERPLANEDESCRIPTOR plpd )
+{
+ return DrvDescribeLayerPlane(hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
+}
+
+WINGDIAPI int APIENTRY
+wglSetLayerPaletteEntries(
+ HDC hdc,
+ int iLayerPlane,
+ int iStart,
+ int cEntries,
+ CONST COLORREF *pcr )
+{
+ return DrvSetLayerPaletteEntries(hdc, iLayerPlane, iStart, cEntries, pcr);
+}
+
+WINGDIAPI int APIENTRY
+wglGetLayerPaletteEntries(
+ HDC hdc,
+ int iLayerPlane,
+ int iStart,
+ int cEntries,
+ COLORREF *pcr )
+{
+ return DrvGetLayerPaletteEntries(hdc, iLayerPlane, iStart, cEntries, pcr);
+}
+
+WINGDIAPI BOOL APIENTRY
+wglRealizeLayerPalette(
+ HDC hdc,
+ int iLayerPlane,
+ BOOL bRealize )
+{
+ (void) hdc;
+ (void) iLayerPlane;
+ (void) bRealize;
+
+ assert( 0 );
+
+ return FALSE;
+}
diff --git a/src/gallium/state_trackers/wgl/stw_wgl.h b/src/gallium/state_trackers/wgl/stw_wgl.h
new file mode 100644
index 0000000000..57baaf0a11
--- /dev/null
+++ b/src/gallium/state_trackers/wgl/stw_wgl.h
@@ -0,0 +1,79 @@
+/**************************************************************************
+ *
+ * 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 STW_WGL_H_
+#define STW_WGL_H_
+
+
+#include <windows.h>
+
+#include <GL/gl.h>
+
+
+/*
+ * Undeclared APIs exported by opengl32.dll
+ */
+
+WINGDIAPI BOOL WINAPI
+wglSwapBuffers(HDC hdc);
+
+WINGDIAPI int WINAPI
+wglChoosePixelFormat(HDC hdc,
+ CONST PIXELFORMATDESCRIPTOR *ppfd);
+
+WINGDIAPI int WINAPI
+wglDescribePixelFormat(HDC hdc,
+ int iPixelFormat,
+ UINT nBytes,
+ LPPIXELFORMATDESCRIPTOR ppfd);
+
+WINGDIAPI int WINAPI
+wglGetPixelFormat(HDC hdc);
+
+WINGDIAPI BOOL WINAPI
+wglSetPixelFormat(HDC hdc,
+ int iPixelFormat,
+ CONST PIXELFORMATDESCRIPTOR *ppfd);
+
+#if defined(__MINGW32__) || (WINVER < 0x0500)
+
+typedef struct _WGLSWAP
+{
+ HDC hdc;
+ UINT uiFlags;
+} WGLSWAP;
+
+#define WGL_SWAPMULTIPLE_MAX 16
+
+WINGDIAPI DWORD WINAPI
+wglSwapMultipleBuffers(UINT n,
+ CONST WGLSWAP *ps);
+
+#endif
+
+
+#endif /* STW_WGL_H_ */
diff --git a/src/gallium/state_trackers/wgl/stw_winsys.h b/src/gallium/state_trackers/wgl/stw_winsys.h
new file mode 100644
index 0000000000..270fad56a1
--- /dev/null
+++ b/src/gallium/state_trackers/wgl/stw_winsys.h
@@ -0,0 +1,106 @@
+/**************************************************************************
+ *
+ * Copyright 2008-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 STW_WINSYS_H
+#define STW_WINSYS_H
+
+#include <windows.h> /* for HDC */
+
+#include "pipe/p_compiler.h"
+
+struct pipe_screen;
+struct pipe_context;
+struct pipe_surface;
+
+struct stw_shared_surface;
+
+struct stw_winsys
+{
+ struct pipe_screen *
+ (*create_screen)( void );
+
+ /**
+ * Present the color buffer to the window associated with the device context.
+ */
+ void
+ (*present)( struct pipe_screen *screen,
+ struct pipe_surface *surf,
+ HDC hDC );
+
+ /**
+ * Locally unique identifier (LUID) of the graphics adapter.
+ *
+ * @sa GLCBPRESENTBUFFERSDATA::AdapterLuid;
+ */
+ boolean
+ (*get_adapter_luid)( struct pipe_screen *screen,
+ LUID *pAdapterLuid );
+
+ /**
+ * Open a shared surface (optional).
+ *
+ * @sa GLCBPRESENTBUFFERSDATA::hSharedSurface;
+ */
+ struct stw_shared_surface *
+ (*shared_surface_open)(struct pipe_screen *screen,
+ HANDLE hSharedSurface);
+
+ /**
+ * Close a shared surface (optional).
+ */
+ void
+ (*shared_surface_close)(struct pipe_screen *screen,
+ struct stw_shared_surface *surface);
+
+ /**
+ * Compose into a shared (optional).
+ *
+ * Blit the color buffer into a shared surface.
+ *
+ * @sa GLPRESENTBUFFERSDATA::PresentHistoryToken.
+ */
+ void
+ (*compose)( struct pipe_screen *screen,
+ struct pipe_surface *src,
+ struct stw_shared_surface *dest,
+ LPCRECT pRect,
+ ULONGLONG PresentHistoryToken );
+};
+
+boolean
+stw_init(const struct stw_winsys *stw_winsys);
+
+boolean
+stw_init_thread(void);
+
+void
+stw_cleanup_thread(void);
+
+void
+stw_cleanup(void);
+
+#endif /* STW_WINSYS_H */
diff --git a/src/gallium/state_trackers/xorg/Makefile b/src/gallium/state_trackers/xorg/Makefile
new file mode 100644
index 0000000000..cb2c3aea41
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/Makefile
@@ -0,0 +1,23 @@
+TOP = ../../../..
+include $(TOP)/configs/current
+
+LIBNAME = xorgtracker
+
+LIBRARY_INCLUDES = \
+ -DHAVE_CONFIG_H \
+ $(shell pkg-config xextproto --atleast-version=7.0.99.1 \
+ && echo "-DHAVE_XEXTPROTO_71") \
+ $(shell pkg-config libkms --atleast-version=1.0 \
+ && echo "-DHAVE_LIBKMS") \
+ $(shell pkg-config libkms --silence-errors --cflags-only-I) \
+ $(shell pkg-config --cflags-only-I pixman-1 xorg-server libdrm xproto) \
+ -I$(TOP)/src/gallium/include \
+ -I$(TOP)/src/gallium/auxiliary \
+ -I$(TOP)/include \
+ -I$(TOP)/src/mesa \
+ -I$(TOP)/src/mesa/drivers/dri/common \
+ -I$(TOP)/src/mesa/main
+
+C_SOURCES = $(wildcard ./*.c)
+
+include ../../Makefile.template
diff --git a/src/gallium/state_trackers/xorg/SConscript b/src/gallium/state_trackers/xorg/SConscript
new file mode 100644
index 0000000000..0b598dab6e
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/SConscript
@@ -0,0 +1,36 @@
+#######################################################################
+# SConscript for xorg state_tracker
+
+Import('*')
+
+if 'xorg' in env['statetrackers']:
+
+ env = env.Clone()
+
+ env.Append(CPPPATH = [
+ '#/src/mesa',
+ ])
+
+ env.ParseConfig('pkg-config --cflags --libs libdrm xorg-server')
+
+ conf = env.Configure()
+
+ if conf.CheckHeader('X11/extensions/dpmsconst.h'):
+ env.Append(CPPDEFINES = [('HAVE_XEXTPROTO_71', '1')])
+
+ conf.Finish()
+
+ st_xorg = env.ConvenienceLibrary(
+ target = 'st_xorg',
+ source = [ 'xorg_composite.c',
+ 'xorg_crtc.c',
+ 'xorg_dri2.c',
+ 'xorg_driver.c',
+ 'xorg_exa.c',
+ 'xorg_exa_tgsi.c',
+ 'xorg_output.c',
+ 'xorg_renderer.c',
+ 'xorg_xv.c',
+ ]
+ )
+ Export('st_xorg')
diff --git a/src/gallium/state_trackers/xorg/xorg_composite.c b/src/gallium/state_trackers/xorg/xorg_composite.c
new file mode 100644
index 0000000000..4ff48026e5
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xorg_composite.c
@@ -0,0 +1,583 @@
+#include "xorg_composite.h"
+
+#include "xorg_renderer.h"
+#include "xorg_exa_tgsi.h"
+
+#include "cso_cache/cso_context.h"
+#include "util/u_sampler.h"
+
+
+/*XXX also in Xrender.h but the including it here breaks compilition */
+#define XFixedToDouble(f) (((double) (f)) / 65536.)
+
+struct xorg_composite_blend {
+ int op : 8;
+
+ unsigned alpha_dst : 4;
+ unsigned alpha_src : 4;
+
+ unsigned rgb_src : 8; /**< PIPE_BLENDFACTOR_x */
+ unsigned rgb_dst : 8; /**< PIPE_BLENDFACTOR_x */
+};
+
+#define BLEND_OP_OVER 3
+static const struct xorg_composite_blend xorg_blends[] = {
+ { PictOpClear,
+ 0, 0, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO},
+ { PictOpSrc,
+ 0, 0, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ZERO},
+ { PictOpDst,
+ 0, 0, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ONE},
+ { PictOpOver,
+ 0, 1, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_INV_SRC_ALPHA},
+ { PictOpOverReverse,
+ 1, 0, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_ONE},
+ { PictOpIn,
+ 1, 0, PIPE_BLENDFACTOR_DST_ALPHA, PIPE_BLENDFACTOR_ZERO},
+ { PictOpInReverse,
+ 0, 1, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_SRC_ALPHA},
+ { PictOpOut,
+ 1, 0, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_ZERO},
+ { PictOpOutReverse,
+ 0, 1, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_INV_SRC_ALPHA},
+ { PictOpAtop,
+ 1, 1, PIPE_BLENDFACTOR_DST_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA},
+ { PictOpAtopReverse,
+ 1, 1, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_SRC_ALPHA},
+ { PictOpXor,
+ 1, 1, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA},
+ { PictOpAdd,
+ 0, 0, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE},
+};
+
+
+static INLINE void
+pixel_to_float4(Pixel pixel, float *color)
+{
+ CARD32 r, g, b, a;
+
+ a = (pixel >> 24) & 0xff;
+ r = (pixel >> 16) & 0xff;
+ g = (pixel >> 8) & 0xff;
+ b = (pixel >> 0) & 0xff;
+ color[0] = ((float)r) / 255.;
+ color[1] = ((float)g) / 255.;
+ color[2] = ((float)b) / 255.;
+ color[3] = ((float)a) / 255.;
+}
+
+static boolean
+blend_for_op(struct xorg_composite_blend *blend,
+ int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
+ PicturePtr pDstPicture)
+{
+ const int num_blends =
+ sizeof(xorg_blends)/sizeof(struct xorg_composite_blend);
+ int i;
+ boolean supported = FALSE;
+
+ /* our default in case something goes wrong */
+ *blend = xorg_blends[BLEND_OP_OVER];
+
+ for (i = 0; i < num_blends; ++i) {
+ if (xorg_blends[i].op == op) {
+ *blend = xorg_blends[i];
+ supported = TRUE;
+ }
+ }
+
+ /* If there's no dst alpha channel, adjust the blend op so that we'll treat
+ * it as always 1. */
+ if (pDstPicture &&
+ PICT_FORMAT_A(pDstPicture->format) == 0 && blend->alpha_dst) {
+ if (blend->rgb_src == PIPE_BLENDFACTOR_DST_ALPHA)
+ blend->rgb_src = PIPE_BLENDFACTOR_ONE;
+ else if (blend->rgb_src == PIPE_BLENDFACTOR_INV_DST_ALPHA)
+ blend->rgb_src = PIPE_BLENDFACTOR_ZERO;
+ }
+
+ /* If the source alpha is being used, then we should only be in a case where
+ * the source blend factor is 0, and the source blend value is the mask
+ * channels multiplied by the source picture's alpha. */
+ if (pMaskPicture && pMaskPicture->componentAlpha &&
+ PICT_FORMAT_RGB(pMaskPicture->format) && blend->alpha_src) {
+ if (blend->rgb_dst == PIPE_BLENDFACTOR_SRC_ALPHA) {
+ blend->rgb_dst = PIPE_BLENDFACTOR_SRC_COLOR;
+ } else if (blend->rgb_dst == PIPE_BLENDFACTOR_INV_SRC_ALPHA) {
+ blend->rgb_dst = PIPE_BLENDFACTOR_INV_SRC_COLOR;
+ }
+ }
+
+ return supported;
+}
+
+static INLINE int
+render_repeat_to_gallium(int mode)
+{
+ switch(mode) {
+ case RepeatNone:
+ return PIPE_TEX_WRAP_CLAMP_TO_BORDER;
+ case RepeatNormal:
+ return PIPE_TEX_WRAP_REPEAT;
+ case RepeatReflect:
+ return PIPE_TEX_WRAP_MIRROR_REPEAT;
+ case RepeatPad:
+ return PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+ default:
+ debug_printf("Unsupported repeat mode\n");
+ }
+ return PIPE_TEX_WRAP_REPEAT;
+}
+
+static INLINE boolean
+render_filter_to_gallium(int xrender_filter, int *out_filter)
+{
+
+ switch (xrender_filter) {
+ case PictFilterNearest:
+ *out_filter = PIPE_TEX_FILTER_NEAREST;
+ break;
+ case PictFilterBilinear:
+ *out_filter = PIPE_TEX_FILTER_LINEAR;
+ break;
+ case PictFilterFast:
+ *out_filter = PIPE_TEX_FILTER_NEAREST;
+ break;
+ case PictFilterGood:
+ *out_filter = PIPE_TEX_FILTER_LINEAR;
+ break;
+ case PictFilterBest:
+ *out_filter = PIPE_TEX_FILTER_LINEAR;
+ break;
+ case PictFilterConvolution:
+ *out_filter = PIPE_TEX_FILTER_NEAREST;
+ return FALSE;
+ default:
+ debug_printf("Unknown xrender filter\n");
+ *out_filter = PIPE_TEX_FILTER_NEAREST;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static boolean is_filter_accelerated(PicturePtr pic)
+{
+ int filter;
+ if (pic && !render_filter_to_gallium(pic->filter, &filter))
+ return FALSE;
+ return TRUE;
+}
+
+boolean xorg_composite_accelerated(int op,
+ PicturePtr pSrcPicture,
+ PicturePtr pMaskPicture,
+ PicturePtr pDstPicture)
+{
+ ScreenPtr pScreen = pDstPicture->pDrawable->pScreen;
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct xorg_composite_blend blend;
+
+ if (!is_filter_accelerated(pSrcPicture) ||
+ !is_filter_accelerated(pMaskPicture)) {
+ XORG_FALLBACK("Unsupported Xrender filter");
+ }
+
+ if (pSrcPicture->pSourcePict) {
+ if (pSrcPicture->pSourcePict->type != SourcePictTypeSolidFill)
+ XORG_FALLBACK("Gradients not enabled (haven't been well tested)");
+ }
+
+ if (blend_for_op(&blend, op,
+ pSrcPicture, pMaskPicture, pDstPicture)) {
+ /* Check for component alpha */
+ if (pMaskPicture && pMaskPicture->componentAlpha &&
+ PICT_FORMAT_RGB(pMaskPicture->format)) {
+ if (blend.alpha_src && blend.rgb_src != PIPE_BLENDFACTOR_ZERO) {
+ XORG_FALLBACK("Component alpha not supported with source "
+ "alpha and source value blending. (op=%d)",
+ op);
+ }
+ }
+
+ return TRUE;
+ }
+ XORG_FALLBACK("Unsupported composition operation = %d", op);
+}
+
+static void
+bind_blend_state(struct exa_context *exa, int op,
+ PicturePtr pSrcPicture,
+ PicturePtr pMaskPicture,
+ PicturePtr pDstPicture)
+{
+ struct xorg_composite_blend blend_opt;
+ struct pipe_blend_state blend;
+
+ blend_for_op(&blend_opt, op, pSrcPicture, pMaskPicture, pDstPicture);
+
+ memset(&blend, 0, sizeof(struct pipe_blend_state));
+ blend.rt[0].blend_enable = 1;
+ blend.rt[0].colormask = PIPE_MASK_RGBA;
+
+ blend.rt[0].rgb_src_factor = blend_opt.rgb_src;
+ blend.rt[0].alpha_src_factor = blend_opt.rgb_src;
+ blend.rt[0].rgb_dst_factor = blend_opt.rgb_dst;
+ blend.rt[0].alpha_dst_factor = blend_opt.rgb_dst;
+
+ cso_set_blend(exa->renderer->cso, &blend);
+}
+
+static unsigned
+picture_format_fixups(struct exa_pixmap_priv *pSrc, PicturePtr pSrcPicture, boolean mask,
+ PicturePtr pDstPicture)
+{
+ boolean set_alpha = FALSE;
+ boolean swizzle = FALSE;
+ unsigned ret = 0;
+
+ if (pSrc->picture_format == pSrcPicture->format) {
+ if (pSrc->picture_format == PICT_a8) {
+ if (mask)
+ return FS_MASK_LUMINANCE;
+ else if (pDstPicture->format != PICT_a8) {
+ /* if both dst and src are luminance then
+ * we don't want to swizzle the alpha (X) of the
+ * source into W component of the dst because
+ * it will break our destination */
+ return FS_SRC_LUMINANCE;
+ }
+ }
+ return 0;
+ }
+
+ if (pSrc->picture_format != PICT_a8r8g8b8) {
+ assert(!"can not handle formats");
+ return 0;
+ }
+
+ /* pSrc->picture_format == PICT_a8r8g8b8 */
+ switch (pSrcPicture->format) {
+ case PICT_x8b8g8r8:
+ case PICT_b8g8r8:
+ set_alpha = TRUE; /* fall trough */
+ case PICT_a8b8g8r8:
+ swizzle = TRUE;
+ break;
+ case PICT_x8r8g8b8:
+ case PICT_r8g8b8:
+ set_alpha = TRUE; /* fall through */
+ case PICT_a8r8g8b8:
+ break;
+#ifdef PICT_TYPE_BGRA
+ case PICT_b8g8r8a8:
+ case PICT_b8g8r8x8:
+ case PICT_a2r10g10b10:
+ case PICT_x2r10g10b10:
+ case PICT_a2b10g10r10:
+ case PICT_x2b10g10r10:
+#endif
+ default:
+ assert(!"can not handle formats");
+ return 0;
+ }
+
+ if (set_alpha)
+ ret |= mask ? FS_MASK_SET_ALPHA : FS_SRC_SET_ALPHA;
+ if (swizzle)
+ ret |= mask ? FS_MASK_SWIZZLE_RGB : FS_SRC_SWIZZLE_RGB;
+
+ return ret;
+}
+
+static void
+bind_shaders(struct exa_context *exa, int op,
+ PicturePtr pSrcPicture, PicturePtr pMaskPicture, PicturePtr pDstPicture,
+ struct exa_pixmap_priv *pSrc, struct exa_pixmap_priv *pMask)
+{
+ unsigned vs_traits = 0, fs_traits = 0;
+ struct xorg_shader shader;
+
+ exa->has_solid_color = FALSE;
+
+ if (pSrcPicture) {
+ if (pSrcPicture->repeatType == RepeatNone && pSrcPicture->transform)
+ fs_traits |= FS_SRC_REPEAT_NONE;
+
+ if (pSrcPicture->pSourcePict) {
+ if (pSrcPicture->pSourcePict->type == SourcePictTypeSolidFill) {
+ fs_traits |= FS_SOLID_FILL;
+ vs_traits |= VS_SOLID_FILL;
+ debug_assert(pSrcPicture->format == PICT_a8r8g8b8);
+ pixel_to_float4(pSrcPicture->pSourcePict->solidFill.color,
+ exa->solid_color);
+ exa->has_solid_color = TRUE;
+ } else {
+ debug_assert("!gradients not supported");
+ }
+ } else {
+ fs_traits |= FS_COMPOSITE;
+ vs_traits |= VS_COMPOSITE;
+ }
+
+ fs_traits |= picture_format_fixups(pSrc, pSrcPicture, FALSE, pDstPicture);
+ }
+
+ if (pMaskPicture) {
+ vs_traits |= VS_MASK;
+ fs_traits |= FS_MASK;
+ if (pMaskPicture->repeatType == RepeatNone && pMaskPicture->transform)
+ fs_traits |= FS_MASK_REPEAT_NONE;
+ if (pMaskPicture->componentAlpha) {
+ struct xorg_composite_blend blend;
+ blend_for_op(&blend, op,
+ pSrcPicture, pMaskPicture, NULL);
+ if (blend.alpha_src) {
+ fs_traits |= FS_CA_SRCALPHA;
+ } else
+ fs_traits |= FS_CA_FULL;
+ }
+
+ fs_traits |= picture_format_fixups(pMask, pMaskPicture, TRUE, pDstPicture);
+ }
+
+ shader = xorg_shaders_get(exa->renderer->shaders, vs_traits, fs_traits);
+ cso_set_vertex_shader_handle(exa->renderer->cso, shader.vs);
+ cso_set_fragment_shader_handle(exa->renderer->cso, shader.fs);
+}
+
+static void
+bind_samplers(struct exa_context *exa, int op,
+ PicturePtr pSrcPicture, PicturePtr pMaskPicture,
+ PicturePtr pDstPicture,
+ struct exa_pixmap_priv *pSrc,
+ struct exa_pixmap_priv *pMask,
+ struct exa_pixmap_priv *pDst)
+{
+ struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
+ struct pipe_sampler_state src_sampler, mask_sampler;
+ struct pipe_sampler_view view_templ;
+ struct pipe_sampler_view *src_view;
+ struct pipe_context *pipe = exa->pipe;
+
+ exa->num_bound_samplers = 0;
+
+ memset(&src_sampler, 0, sizeof(struct pipe_sampler_state));
+ memset(&mask_sampler, 0, sizeof(struct pipe_sampler_state));
+
+ if (pSrcPicture && pSrc) {
+ if (exa->has_solid_color) {
+ debug_assert(!"solid color with textures");
+ samplers[0] = NULL;
+ pipe_sampler_view_reference(&exa->bound_sampler_views[0], NULL);
+ } else {
+ unsigned src_wrap = render_repeat_to_gallium(
+ pSrcPicture->repeatType);
+ int filter;
+
+ render_filter_to_gallium(pSrcPicture->filter, &filter);
+
+ src_sampler.wrap_s = src_wrap;
+ src_sampler.wrap_t = src_wrap;
+ src_sampler.min_img_filter = filter;
+ src_sampler.mag_img_filter = filter;
+ src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST;
+ src_sampler.normalized_coords = 1;
+ samplers[0] = &src_sampler;
+ exa->num_bound_samplers = 1;
+ u_sampler_view_default_template(&view_templ,
+ pSrc->tex,
+ pSrc->tex->format);
+ src_view = pipe->create_sampler_view(pipe, pSrc->tex, &view_templ);
+ pipe_sampler_view_reference(&exa->bound_sampler_views[0], NULL);
+ exa->bound_sampler_views[0] = src_view;
+ }
+ }
+
+ if (pMaskPicture && pMask) {
+ unsigned mask_wrap = render_repeat_to_gallium(
+ pMaskPicture->repeatType);
+ int filter;
+
+ render_filter_to_gallium(pMaskPicture->filter, &filter);
+
+ mask_sampler.wrap_s = mask_wrap;
+ mask_sampler.wrap_t = mask_wrap;
+ mask_sampler.min_img_filter = filter;
+ mask_sampler.mag_img_filter = filter;
+ src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST;
+ mask_sampler.normalized_coords = 1;
+ samplers[1] = &mask_sampler;
+ exa->num_bound_samplers = 2;
+ u_sampler_view_default_template(&view_templ,
+ pMask->tex,
+ pMask->tex->format);
+ src_view = pipe->create_sampler_view(pipe, pMask->tex, &view_templ);
+ pipe_sampler_view_reference(&exa->bound_sampler_views[1], NULL);
+ exa->bound_sampler_views[1] = src_view;
+ }
+
+ cso_set_samplers(exa->renderer->cso, exa->num_bound_samplers,
+ (const struct pipe_sampler_state **)samplers);
+ cso_set_fragment_sampler_views(exa->renderer->cso, exa->num_bound_samplers,
+ exa->bound_sampler_views);
+}
+
+
+
+static INLINE boolean matrix_from_pict_transform(PictTransform *trans, float *matrix)
+{
+ if (!trans)
+ return FALSE;
+
+ matrix[0] = XFixedToDouble(trans->matrix[0][0]);
+ matrix[3] = XFixedToDouble(trans->matrix[0][1]);
+ matrix[6] = XFixedToDouble(trans->matrix[0][2]);
+
+ matrix[1] = XFixedToDouble(trans->matrix[1][0]);
+ matrix[4] = XFixedToDouble(trans->matrix[1][1]);
+ matrix[7] = XFixedToDouble(trans->matrix[1][2]);
+
+ matrix[2] = XFixedToDouble(trans->matrix[2][0]);
+ matrix[5] = XFixedToDouble(trans->matrix[2][1]);
+ matrix[8] = XFixedToDouble(trans->matrix[2][2]);
+
+ return TRUE;
+}
+
+static void
+setup_transforms(struct exa_context *exa,
+ PicturePtr pSrcPicture, PicturePtr pMaskPicture)
+{
+ PictTransform *src_t = NULL;
+ PictTransform *mask_t = NULL;
+
+ if (pSrcPicture)
+ src_t = pSrcPicture->transform;
+ if (pMaskPicture)
+ mask_t = pMaskPicture->transform;
+
+ exa->transform.has_src =
+ matrix_from_pict_transform(src_t, exa->transform.src);
+ exa->transform.has_mask =
+ matrix_from_pict_transform(mask_t, exa->transform.mask);
+}
+
+boolean xorg_composite_bind_state(struct exa_context *exa,
+ int op,
+ PicturePtr pSrcPicture,
+ PicturePtr pMaskPicture,
+ PicturePtr pDstPicture,
+ struct exa_pixmap_priv *pSrc,
+ struct exa_pixmap_priv *pMask,
+ struct exa_pixmap_priv *pDst)
+{
+ struct pipe_surface *dst_surf = xorg_gpu_surface(exa->scrn, pDst);
+
+ renderer_bind_destination(exa->renderer, dst_surf,
+ pDst->width,
+ pDst->height);
+
+ bind_blend_state(exa, op, pSrcPicture, pMaskPicture, pDstPicture);
+ bind_shaders(exa, op, pSrcPicture, pMaskPicture, pDstPicture, pSrc, pMask);
+ bind_samplers(exa, op, pSrcPicture, pMaskPicture,
+ pDstPicture, pSrc, pMask, pDst);
+
+ setup_transforms(exa, pSrcPicture, pMaskPicture);
+
+ if (exa->num_bound_samplers == 0 ) { /* solid fill */
+ renderer_begin_solid(exa->renderer);
+ } else {
+ renderer_begin_textures(exa->renderer,
+ exa->num_bound_samplers);
+ }
+
+
+ pipe_surface_reference(&dst_surf, NULL);
+ return TRUE;
+}
+
+void xorg_composite(struct exa_context *exa,
+ struct exa_pixmap_priv *dst,
+ int srcX, int srcY, int maskX, int maskY,
+ int dstX, int dstY, int width, int height)
+{
+ if (exa->num_bound_samplers == 0 ) { /* solid fill */
+ renderer_solid(exa->renderer,
+ dstX, dstY, dstX + width, dstY + height,
+ exa->solid_color);
+ } else {
+ int pos[6] = {srcX, srcY, maskX, maskY, dstX, dstY};
+ float *src_matrix = NULL;
+ float *mask_matrix = NULL;
+
+ if (exa->transform.has_src)
+ src_matrix = exa->transform.src;
+ if (exa->transform.has_mask)
+ mask_matrix = exa->transform.mask;
+
+ renderer_texture(exa->renderer,
+ pos, width, height,
+ exa->bound_sampler_views,
+ exa->num_bound_samplers,
+ src_matrix, mask_matrix);
+ }
+}
+
+boolean xorg_solid_bind_state(struct exa_context *exa,
+ struct exa_pixmap_priv *pixmap,
+ Pixel fg)
+{
+ struct pipe_surface *dst_surf = xorg_gpu_surface(exa->scrn, pixmap);
+ unsigned vs_traits, fs_traits;
+ struct xorg_shader shader;
+
+ pixel_to_float4(fg, exa->solid_color);
+ exa->has_solid_color = TRUE;
+
+#if 0
+ debug_printf("Color Pixel=(%d, %d, %d, %d), RGBA=(%f, %f, %f, %f)\n",
+ (fg >> 24) & 0xff, (fg >> 16) & 0xff,
+ (fg >> 8) & 0xff, (fg >> 0) & 0xff,
+ exa->solid_color[0], exa->solid_color[1],
+ exa->solid_color[2], exa->solid_color[3]);
+#endif
+
+ vs_traits = VS_SOLID_FILL;
+ fs_traits = FS_SOLID_FILL;
+
+ renderer_bind_destination(exa->renderer, dst_surf,
+ pixmap->width, pixmap->height);
+ bind_blend_state(exa, PictOpSrc, NULL, NULL, NULL);
+ cso_set_samplers(exa->renderer->cso, 0, NULL);
+ cso_set_fragment_sampler_views(exa->renderer->cso, 0, NULL);
+
+ shader = xorg_shaders_get(exa->renderer->shaders, vs_traits, fs_traits);
+ cso_set_vertex_shader_handle(exa->renderer->cso, shader.vs);
+ cso_set_fragment_shader_handle(exa->renderer->cso, shader.fs);
+
+ renderer_begin_solid(exa->renderer);
+
+ pipe_surface_reference(&dst_surf, NULL);
+ return TRUE;
+}
+
+void xorg_solid(struct exa_context *exa,
+ struct exa_pixmap_priv *pixmap,
+ int x0, int y0, int x1, int y1)
+{
+ renderer_solid(exa->renderer,
+ x0, y0, x1, y1, exa->solid_color);
+}
+
+void
+xorg_composite_done(struct exa_context *exa)
+{
+ renderer_draw_flush(exa->renderer);
+
+ exa->transform.has_src = FALSE;
+ exa->transform.has_mask = FALSE;
+ exa->has_solid_color = FALSE;
+ exa->num_bound_samplers = 0;
+}
diff --git a/src/gallium/state_trackers/xorg/xorg_composite.h b/src/gallium/state_trackers/xorg/xorg_composite.h
new file mode 100644
index 0000000000..ec71ebfe0d
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xorg_composite.h
@@ -0,0 +1,36 @@
+#ifndef XORG_COMPOSITE_H
+#define XORG_COMPOSITE_H
+
+#include "xorg_exa.h"
+
+boolean xorg_composite_accelerated(int op,
+ PicturePtr pSrcPicture,
+ PicturePtr pMaskPicture,
+ PicturePtr pDstPicture);
+
+boolean xorg_composite_bind_state(struct exa_context *exa,
+ int op,
+ PicturePtr pSrcPicture,
+ PicturePtr pMaskPicture,
+ PicturePtr pDstPicture,
+ struct exa_pixmap_priv *pSrc,
+ struct exa_pixmap_priv *pMask,
+ struct exa_pixmap_priv *pDst);
+
+void xorg_composite(struct exa_context *exa,
+ struct exa_pixmap_priv *dst,
+ int srcX, int srcY, int maskX, int maskY,
+ int dstX, int dstY, int width, int height);
+
+boolean xorg_solid_bind_state(struct exa_context *exa,
+ struct exa_pixmap_priv *pixmap,
+ Pixel fg);
+void xorg_solid(struct exa_context *exa,
+ struct exa_pixmap_priv *pixmap,
+ int x0, int y0, int x1, int y1);
+
+
+void
+xorg_composite_done(struct exa_context *exa);
+
+#endif
diff --git a/src/gallium/state_trackers/xorg/xorg_crtc.c b/src/gallium/state_trackers/xorg/xorg_crtc.c
new file mode 100644
index 0000000000..f1a07bd863
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xorg_crtc.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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.
+ *
+ *
+ * Author: Alan Hourihane <alanh@tungstengraphics.com>
+ * Author: Jakob Bornecrantz <wallbraker@gmail.com>
+ *
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <math.h>
+#include <stdint.h>
+
+#include "xorg-server.h"
+#include <xf86.h>
+#include <xf86i2c.h>
+#include <xf86Crtc.h>
+#include <cursorstr.h>
+#include "xorg_tracker.h"
+#include "xf86Modes.h"
+
+#ifdef HAVE_XEXTPROTO_71
+#include <X11/extensions/dpmsconst.h>
+#else
+#define DPMS_SERVER
+#include <X11/extensions/dpms.h>
+#endif
+
+#include "util/u_inlines.h"
+#include "util/u_rect.h"
+
+#ifdef HAVE_LIBKMS
+#include "libkms.h"
+#endif
+
+struct crtc_private
+{
+ drmModeCrtcPtr drm_crtc;
+
+ /* hwcursor */
+ struct pipe_resource *cursor_tex;
+ struct kms_bo *cursor_bo;
+
+ unsigned cursor_handle;
+};
+
+static void
+crtc_dpms(xf86CrtcPtr crtc, int mode)
+{
+ /* ScrnInfoPtr pScrn = crtc->scrn; */
+
+ switch (mode) {
+ case DPMSModeOn:
+ case DPMSModeStandby:
+ case DPMSModeSuspend:
+ break;
+ case DPMSModeOff:
+ break;
+ }
+}
+
+static Bool
+crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
+ Rotation rotation, int x, int y)
+{
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
+ modesettingPtr ms = modesettingPTR(crtc->scrn);
+ xf86OutputPtr output = NULL;
+ struct crtc_private *crtcp = crtc->driver_private;
+ drmModeCrtcPtr drm_crtc = crtcp->drm_crtc;
+ drmModeModeInfo drm_mode;
+ int i, ret, connector_id;
+
+ for (i = 0; i < config->num_output; output = NULL, i++) {
+ output = config->output[i];
+
+ if (output->crtc == crtc)
+ break;
+ }
+
+ if (!output)
+ return FALSE;
+
+ connector_id = xorg_output_get_id(output);
+
+ drm_mode.clock = mode->Clock;
+ drm_mode.hdisplay = mode->HDisplay;
+ drm_mode.hsync_start = mode->HSyncStart;
+ drm_mode.hsync_end = mode->HSyncEnd;
+ drm_mode.htotal = mode->HTotal;
+ drm_mode.vdisplay = mode->VDisplay;
+ drm_mode.vsync_start = mode->VSyncStart;
+ drm_mode.vsync_end = mode->VSyncEnd;
+ drm_mode.vtotal = mode->VTotal;
+ drm_mode.flags = mode->Flags;
+ drm_mode.hskew = mode->HSkew;
+ drm_mode.vscan = mode->VScan;
+ drm_mode.vrefresh = mode->VRefresh;
+ if (!mode->name)
+ xf86SetModeDefaultName(mode);
+ strncpy(drm_mode.name, mode->name, DRM_DISPLAY_MODE_LEN - 1);
+ drm_mode.name[DRM_DISPLAY_MODE_LEN - 1] = '\0';
+
+ ret = drmModeSetCrtc(ms->fd, drm_crtc->crtc_id, ms->fb_id, x, y,
+ &connector_id, 1, &drm_mode);
+
+ if (ret)
+ return FALSE;
+
+ crtc->x = x;
+ crtc->y = y;
+ crtc->mode = *mode;
+ crtc->rotation = rotation;
+
+ return TRUE;
+}
+
+static void
+crtc_gamma_set(xf86CrtcPtr crtc, CARD16 * red, CARD16 * green, CARD16 * blue,
+ int size)
+{
+ /* XXX: hockup */
+}
+
+#if 0 /* Implement and enable to enable rotation and reflection. */
+static void *
+crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
+{
+ /* ScrnInfoPtr pScrn = crtc->scrn; */
+
+ return NULL;
+}
+
+static PixmapPtr
+crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
+{
+ /* ScrnInfoPtr pScrn = crtc->scrn; */
+
+ return NULL;
+}
+
+static void
+crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
+{
+ /* ScrnInfoPtr pScrn = crtc->scrn; */
+}
+
+#endif
+
+/*
+ * Cursor functions
+ */
+
+static void
+crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
+{
+ /* XXX: See if this one is needed, as we only support ARGB cursors */
+}
+
+static void
+crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
+{
+ modesettingPtr ms = modesettingPTR(crtc->scrn);
+ struct crtc_private *crtcp = crtc->driver_private;
+
+ drmModeMoveCursor(ms->fd, crtcp->drm_crtc->crtc_id, x, y);
+}
+
+static void
+crtc_load_cursor_argb_ga3d(xf86CrtcPtr crtc, CARD32 * image)
+{
+ unsigned char *ptr;
+ modesettingPtr ms = modesettingPTR(crtc->scrn);
+ struct crtc_private *crtcp = crtc->driver_private;
+ struct pipe_transfer *transfer;
+
+ if (!crtcp->cursor_tex) {
+ struct pipe_resource templat;
+ struct winsys_handle whandle;
+
+ memset(&templat, 0, sizeof(templat));
+ templat.bind |= PIPE_BIND_RENDER_TARGET;
+ templat.bind |= PIPE_BIND_SCANOUT;
+ templat.target = PIPE_TEXTURE_2D;
+ templat.last_level = 0;
+ templat.depth0 = 1;
+ templat.format = PIPE_FORMAT_B8G8R8A8_UNORM;
+ templat.width0 = 64;
+ templat.height0 = 64;
+
+ memset(&whandle, 0, sizeof(whandle));
+ whandle.type = DRM_API_HANDLE_TYPE_KMS;
+
+ crtcp->cursor_tex = ms->screen->resource_create(ms->screen,
+ &templat);
+ ms->screen->resource_get_handle(ms->screen, crtcp->cursor_tex, &whandle);
+
+ crtcp->cursor_handle = whandle.handle;
+ }
+
+ transfer = pipe_get_transfer(ms->ctx, crtcp->cursor_tex,
+ 0, 0, 0,
+ PIPE_TRANSFER_WRITE,
+ 0, 0, 64, 64);
+ ptr = ms->ctx->transfer_map(ms->ctx, transfer);
+ util_copy_rect(ptr, crtcp->cursor_tex->format,
+ transfer->stride, 0, 0,
+ 64, 64, (void*)image, 64 * 4, 0, 0);
+ ms->ctx->transfer_unmap(ms->ctx, transfer);
+ ms->ctx->transfer_destroy(ms->ctx, transfer);
+}
+
+#if HAVE_LIBKMS
+static void
+crtc_load_cursor_argb_kms(xf86CrtcPtr crtc, CARD32 * image)
+{
+ modesettingPtr ms = modesettingPTR(crtc->scrn);
+ struct crtc_private *crtcp = crtc->driver_private;
+ unsigned char *ptr;
+
+ if (!crtcp->cursor_bo) {
+ unsigned attr[8];
+
+ attr[0] = KMS_BO_TYPE;
+#ifdef KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8
+ attr[1] = KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8;
+#else
+ attr[1] = KMS_BO_TYPE_CURSOR;
+#endif
+ attr[2] = KMS_WIDTH;
+ attr[3] = 64;
+ attr[4] = KMS_HEIGHT;
+ attr[5] = 64;
+ attr[6] = 0;
+
+ if (kms_bo_create(ms->kms, attr, &crtcp->cursor_bo))
+ return;
+
+ if (kms_bo_get_prop(crtcp->cursor_bo, KMS_HANDLE,
+ &crtcp->cursor_handle))
+ goto err_bo_destroy;
+ }
+
+ kms_bo_map(crtcp->cursor_bo, (void**)&ptr);
+ memcpy(ptr, image, 64*64*4);
+ kms_bo_unmap(crtcp->cursor_bo);
+
+ return;
+
+err_bo_destroy:
+ kms_bo_destroy(&crtcp->cursor_bo);
+}
+#endif
+
+static void
+crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 * image)
+{
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
+ modesettingPtr ms = modesettingPTR(crtc->scrn);
+
+ /* Older X servers have cursor reference counting bugs leading to use of
+ * freed memory and consequently random crashes. Should be fixed as of
+ * xserver 1.8, but this workaround shouldn't hurt anyway.
+ */
+ if (config->cursor)
+ config->cursor->refcnt++;
+
+ if (ms->cursor)
+ FreeCursor(ms->cursor, None);
+
+ ms->cursor = config->cursor;
+
+ if (ms->screen)
+ crtc_load_cursor_argb_ga3d(crtc, image);
+#ifdef HAVE_LIBKMS
+ else if (ms->kms)
+ crtc_load_cursor_argb_kms(crtc, image);
+#endif
+}
+
+static void
+crtc_show_cursor(xf86CrtcPtr crtc)
+{
+ modesettingPtr ms = modesettingPTR(crtc->scrn);
+ struct crtc_private *crtcp = crtc->driver_private;
+
+ if (crtcp->cursor_tex || crtcp->cursor_bo)
+ drmModeSetCursor(ms->fd, crtcp->drm_crtc->crtc_id,
+ crtcp->cursor_handle, 64, 64);
+}
+
+static void
+crtc_hide_cursor(xf86CrtcPtr crtc)
+{
+ modesettingPtr ms = modesettingPTR(crtc->scrn);
+ struct crtc_private *crtcp = crtc->driver_private;
+
+ drmModeSetCursor(ms->fd, crtcp->drm_crtc->crtc_id, 0, 0, 0);
+}
+
+/**
+ * Called at vt leave
+ */
+void
+xorg_crtc_cursor_destroy(xf86CrtcPtr crtc)
+{
+ struct crtc_private *crtcp = crtc->driver_private;
+
+ if (crtcp->cursor_tex)
+ pipe_resource_reference(&crtcp->cursor_tex, NULL);
+#ifdef HAVE_LIBKMS
+ if (crtcp->cursor_bo)
+ kms_bo_destroy(&crtcp->cursor_bo);
+#endif
+}
+
+/*
+ * Misc functions
+ */
+
+static void
+crtc_destroy(xf86CrtcPtr crtc)
+{
+ struct crtc_private *crtcp = crtc->driver_private;
+
+ xorg_crtc_cursor_destroy(crtc);
+
+ drmModeFreeCrtc(crtcp->drm_crtc);
+
+ xfree(crtcp);
+ crtc->driver_private = NULL;
+}
+
+static const xf86CrtcFuncsRec crtc_funcs = {
+ .dpms = crtc_dpms,
+ .set_mode_major = crtc_set_mode_major,
+
+ .set_cursor_colors = crtc_set_cursor_colors,
+ .set_cursor_position = crtc_set_cursor_position,
+ .show_cursor = crtc_show_cursor,
+ .hide_cursor = crtc_hide_cursor,
+ .load_cursor_argb = crtc_load_cursor_argb,
+
+ .shadow_create = NULL,
+ .shadow_allocate = NULL,
+ .shadow_destroy = NULL,
+
+ .gamma_set = crtc_gamma_set,
+ .destroy = crtc_destroy,
+};
+
+void
+xorg_crtc_init(ScrnInfoPtr pScrn)
+{
+ modesettingPtr ms = modesettingPTR(pScrn);
+ xf86CrtcPtr crtc;
+ drmModeResPtr res;
+ drmModeCrtcPtr drm_crtc = NULL;
+ struct crtc_private *crtcp;
+ int c;
+
+ res = drmModeGetResources(ms->fd);
+ if (res == 0) {
+ ErrorF("Failed drmModeGetResources %d\n", errno);
+ return;
+ }
+
+ for (c = 0; c < res->count_crtcs; c++) {
+ drm_crtc = drmModeGetCrtc(ms->fd, res->crtcs[c]);
+
+ if (!drm_crtc)
+ continue;
+
+ crtc = xf86CrtcCreate(pScrn, &crtc_funcs);
+ if (crtc == NULL)
+ goto out;
+
+ crtcp = xcalloc(1, sizeof(struct crtc_private));
+ if (!crtcp) {
+ xf86CrtcDestroy(crtc);
+ goto out;
+ }
+
+ crtcp->drm_crtc = drm_crtc;
+
+ crtc->driver_private = crtcp;
+ }
+
+ out:
+ drmModeFreeResources(res);
+}
+
+/* vim: set sw=4 ts=8 sts=4: */
diff --git a/src/gallium/state_trackers/xorg/xorg_dri2.c b/src/gallium/state_trackers/xorg/xorg_dri2.c
new file mode 100644
index 0000000000..4e01bd1030
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xorg_dri2.c
@@ -0,0 +1,467 @@
+/*
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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.
+ *
+ *
+ * Author: Alan Hourihane <alanh@tungstengraphics.com>
+ * Author: Jakob Bornecrantz <wallbraker@gmail.com>
+ *
+ */
+
+#include "xorg-server.h"
+#include "xf86.h"
+#include "xf86_OSproc.h"
+
+#include "xorg_tracker.h"
+#include "xorg_exa.h"
+
+#include "dri2.h"
+
+#include "pipe/p_state.h"
+#include "util/u_inlines.h"
+
+#include "util/u_format.h"
+
+/* Make all the #if cases in the code esier to read */
+#ifndef DRI2INFOREC_VERSION
+#define DRI2INFOREC_VERSION 1
+#endif
+
+#if DRI2INFOREC_VERSION == 2
+static Bool set_format_in_do_create_buffer;
+#endif
+
+typedef struct {
+ PixmapPtr pPixmap;
+ struct pipe_resource *tex;
+ struct pipe_fence_handle *fence;
+} *BufferPrivatePtr;
+
+static Bool
+dri2_do_create_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer, unsigned int format)
+{
+ struct pipe_resource *tex = NULL;
+ ScreenPtr pScreen = pDraw->pScreen;
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct exa_pixmap_priv *exa_priv;
+ BufferPrivatePtr private = buffer->driverPrivate;
+ PixmapPtr pPixmap;
+ struct winsys_handle whandle;
+
+ if (pDraw->type == DRAWABLE_PIXMAP)
+ pPixmap = (PixmapPtr) pDraw;
+ else
+ pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr) pDraw);
+ exa_priv = exaGetPixmapDriverPrivate(pPixmap);
+
+
+ switch (buffer->attachment) {
+ default:
+ if (buffer->attachment != DRI2BufferFakeFrontLeft ||
+ pDraw->type != DRAWABLE_PIXMAP) {
+ private->pPixmap = (*pScreen->CreatePixmap)(pScreen, pDraw->width,
+ pDraw->height,
+ pDraw->depth,
+ 0);
+ }
+ break;
+ case DRI2BufferFrontLeft:
+ break;
+ case DRI2BufferStencil:
+#if DRI2INFOREC_VERSION >= 3
+ case DRI2BufferDepthStencil:
+#else
+ /* Works on old X servers because sanity checking is for the weak */
+ case 9:
+#endif
+ if (exa_priv->depth_stencil_tex &&
+ !util_format_is_depth_or_stencil(exa_priv->depth_stencil_tex->format))
+ exa_priv->depth_stencil_tex = NULL;
+ /* Fall through */
+ case DRI2BufferDepth:
+ if (exa_priv->depth_stencil_tex)
+ pipe_resource_reference(&tex, exa_priv->depth_stencil_tex);
+ else {
+ struct pipe_resource template;
+ unsigned depthBits = (format != 0) ? format : pDraw->depth;
+ memset(&template, 0, sizeof(template));
+ template.target = PIPE_TEXTURE_2D;
+ if (buffer->attachment == DRI2BufferDepth) {
+ switch(depthBits) {
+ case 16:
+ template.format = PIPE_FORMAT_Z16_UNORM;
+ break;
+ case 32:
+ template.format = PIPE_FORMAT_Z32_UNORM;
+ break;
+ default:
+ template.format = ms->ds_depth_bits_last ?
+ PIPE_FORMAT_Z24X8_UNORM : PIPE_FORMAT_X8Z24_UNORM;
+ break;
+ }
+ } else {
+ template.format = ms->ds_depth_bits_last ?
+ PIPE_FORMAT_Z24_UNORM_S8_USCALED : PIPE_FORMAT_S8_USCALED_Z24_UNORM;
+ }
+ template.width0 = pDraw->width;
+ template.height0 = pDraw->height;
+ template.depth0 = 1;
+ template.last_level = 0;
+ template.bind = PIPE_BIND_DEPTH_STENCIL |
+ PIPE_BIND_SHARED;
+ tex = ms->screen->resource_create(ms->screen, &template);
+ pipe_resource_reference(&exa_priv->depth_stencil_tex, tex);
+ }
+ break;
+ }
+
+ if (!private->pPixmap) {
+ private->pPixmap = pPixmap;
+ pPixmap->refcnt++;
+ }
+
+ if (!tex) {
+ /* First call to make sure we have a pixmap private */
+ exaMoveInPixmap(private->pPixmap);
+ xorg_exa_set_shared_usage(private->pPixmap);
+ pScreen->ModifyPixmapHeader(private->pPixmap, 0, 0, 0, 0, 0, NULL);
+ /* Second call to make sure texture has valid contents */
+ exaMoveInPixmap(private->pPixmap);
+ tex = xorg_exa_get_texture(private->pPixmap);
+ }
+
+ if (!tex)
+ FatalError("NO TEXTURE IN DRI2\n");
+
+ memset(&whandle, 0, sizeof(whandle));
+ whandle.type = DRM_API_HANDLE_TYPE_SHARED;
+
+ ms->screen->resource_get_handle(ms->screen, tex, &whandle);
+
+ buffer->name = whandle.handle;
+ buffer->pitch = whandle.stride;
+ buffer->cpp = 4;
+ buffer->driverPrivate = private;
+ buffer->flags = 0; /* not tiled */
+#if DRI2INFOREC_VERSION == 2
+ /* ABI forwards/backwards compatibility */
+ if (set_format_in_do_create_buffer)
+ ((DRI2Buffer2Ptr)buffer)->format = 0;
+#elif DRI2INFOREC_VERSION >= 3
+ buffer->format = 0;
+#endif
+ private->tex = tex;
+
+ return TRUE;
+}
+
+static void
+dri2_do_destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer)
+{
+ ScreenPtr pScreen = pDraw->pScreen;
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ BufferPrivatePtr private = buffer->driverPrivate;
+ struct exa_pixmap_priv *exa_priv = exaGetPixmapDriverPrivate(private->pPixmap);
+
+ pipe_resource_reference(&private->tex, NULL);
+ ms->screen->fence_reference(ms->screen, &private->fence, NULL);
+ pipe_resource_reference(&exa_priv->depth_stencil_tex, NULL);
+ (*pScreen->DestroyPixmap)(private->pPixmap);
+}
+
+#if DRI2INFOREC_VERSION >= 2
+
+static DRI2Buffer2Ptr
+dri2_create_buffer(DrawablePtr pDraw, unsigned int attachment, unsigned int format)
+{
+ DRI2Buffer2Ptr buffer;
+ BufferPrivatePtr private;
+
+ buffer = xcalloc(1, sizeof *buffer);
+ if (!buffer)
+ return NULL;
+
+ private = xcalloc(1, sizeof *private);
+ if (!private) {
+ goto fail;
+ }
+
+ buffer->attachment = attachment;
+ buffer->driverPrivate = private;
+
+ /* So far it is safe to downcast a DRI2Buffer2Ptr to DRI2BufferPtr */
+ if (dri2_do_create_buffer(pDraw, (DRI2BufferPtr)buffer, format))
+ return buffer;
+
+ xfree(private);
+fail:
+ xfree(buffer);
+ return NULL;
+}
+
+static void
+dri2_destroy_buffer(DrawablePtr pDraw, DRI2Buffer2Ptr buffer)
+{
+ /* So far it is safe to downcast a DRI2Buffer2Ptr to DRI2BufferPtr */
+ dri2_do_destroy_buffer(pDraw, (DRI2BufferPtr)buffer);
+
+ xfree(buffer->driverPrivate);
+ xfree(buffer);
+}
+
+#endif /* DRI2INFOREC_VERSION >= 2 */
+
+#if DRI2INFOREC_VERSION <= 2
+
+static DRI2BufferPtr
+dri2_create_buffers(DrawablePtr pDraw, unsigned int *attachments, int count)
+{
+ BufferPrivatePtr privates;
+ DRI2BufferPtr buffers;
+ int i;
+
+ buffers = xcalloc(count, sizeof *buffers);
+ if (!buffers)
+ goto fail_buffers;
+
+ privates = xcalloc(count, sizeof *privates);
+ if (!privates)
+ goto fail_privates;
+
+ for (i = 0; i < count; i++) {
+ buffers[i].attachment = attachments[i];
+ buffers[i].driverPrivate = &privates[i];
+
+ if (!dri2_do_create_buffer(pDraw, &buffers[i], 0))
+ goto fail;
+ }
+
+ return buffers;
+
+fail:
+ xfree(privates);
+fail_privates:
+ xfree(buffers);
+fail_buffers:
+ return NULL;
+}
+
+static void
+dri2_destroy_buffers(DrawablePtr pDraw, DRI2BufferPtr buffers, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ dri2_do_destroy_buffer(pDraw, &buffers[i]);
+ }
+
+ if (buffers) {
+ xfree(buffers[0].driverPrivate);
+ xfree(buffers);
+ }
+}
+
+#endif /* DRI2INFOREC_VERSION <= 2 */
+
+static void
+dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion,
+ DRI2BufferPtr pDestBuffer, DRI2BufferPtr pSrcBuffer)
+{
+ ScreenPtr pScreen = pDraw->pScreen;
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ BufferPrivatePtr dst_priv = pDestBuffer->driverPrivate;
+ BufferPrivatePtr src_priv = pSrcBuffer->driverPrivate;
+ DrawablePtr src_draw;
+ DrawablePtr dst_draw;
+ GCPtr gc;
+ RegionPtr copy_clip;
+ Bool save_accel;
+ CustomizerPtr cust = ms->cust;
+
+ /*
+ * In driCreateBuffers we dewrap windows into the
+ * backing pixmaps in order to get to the texture.
+ * We need to use the real drawable in CopyArea
+ * so that cliprects and offsets are correct.
+ */
+ src_draw = (pSrcBuffer->attachment == DRI2BufferFrontLeft) ? pDraw :
+ &src_priv->pPixmap->drawable;
+ dst_draw = (pDestBuffer->attachment == DRI2BufferFrontLeft) ? pDraw :
+ &dst_priv->pPixmap->drawable;
+
+ /*
+ * The clients implements glXWaitX with a copy front to fake and then
+ * waiting on the server to signal its completion of it. While
+ * glXWaitGL is a client side flush and a copy from fake to front.
+ * This is how it is done in the DRI2 protocol, how ever depending
+ * which type of drawables the server does things a bit differently
+ * then what the protocol says as the fake and front are the same.
+ *
+ * for pixmaps glXWaitX is a server flush.
+ * for pixmaps glXWaitGL is a client flush.
+ * for windows glXWaitX is a copy from front to fake then a server flush.
+ * for windows glXWaitGL is a client flush then a copy from fake to front.
+ *
+ * XXX in the windows case this code always flushes but that isn't a
+ * must in the glXWaitGL case but we don't know if this is a glXWaitGL
+ * or a glFlush/glFinish call.
+ */
+ if (dst_priv->pPixmap == src_priv->pPixmap) {
+ /* pixmap glXWaitX */
+ if (pSrcBuffer->attachment == DRI2BufferFrontLeft &&
+ pDestBuffer->attachment == DRI2BufferFakeFrontLeft) {
+ ms->ctx->flush(ms->ctx, PIPE_FLUSH_SWAPBUFFERS, NULL);
+ return;
+ }
+ /* pixmap glXWaitGL */
+ if (pDestBuffer->attachment == DRI2BufferFrontLeft &&
+ pSrcBuffer->attachment == DRI2BufferFakeFrontLeft) {
+ return;
+ } else {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "copying between the same pixmap\n");
+ }
+ }
+
+ gc = GetScratchGC(pDraw->depth, pScreen);
+ copy_clip = REGION_CREATE(pScreen, NULL, 0);
+ REGION_COPY(pScreen, copy_clip, pRegion);
+ (*gc->funcs->ChangeClip) (gc, CT_REGION, copy_clip, 0);
+ ValidateGC(dst_draw, gc);
+
+ /* If this is a full buffer swap, throttle on the previous one */
+ if (ms->swapThrottling &&
+ dst_priv->fence && REGION_NUM_RECTS(pRegion) == 1) {
+ BoxPtr extents = REGION_EXTENTS(pScreen, pRegion);
+
+ if (extents->x1 == 0 && extents->y1 == 0 &&
+ extents->x2 == pDraw->width && extents->y2 == pDraw->height) {
+ ms->screen->fence_finish(ms->screen, dst_priv->fence, 0);
+ ms->screen->fence_reference(ms->screen, &dst_priv->fence, NULL);
+ }
+ }
+
+ /* Try to make sure the blit will be accelerated */
+ save_accel = ms->exa->accel;
+ ms->exa->accel = TRUE;
+
+ /* In case it won't be though, make sure the GPU copy contents of the
+ * source pixmap will be used for the software fallback - presumably the
+ * client modified them before calling in here.
+ */
+ exaMoveInPixmap(src_priv->pPixmap);
+ DamageRegionAppend(src_draw, pRegion);
+ DamageRegionProcessPending(src_draw);
+
+ if (cust && cust->winsys_context_throttle)
+ cust->winsys_context_throttle(cust, ms->ctx, THROTTLE_SWAP);
+
+ (*gc->ops->CopyArea)(src_draw, dst_draw, gc,
+ 0, 0, pDraw->width, pDraw->height, 0, 0);
+ ms->exa->accel = save_accel;
+
+ FreeScratchGC(gc);
+
+ ms->ctx->flush(ms->ctx, PIPE_FLUSH_SWAPBUFFERS,
+ (pDestBuffer->attachment == DRI2BufferFrontLeft
+ && ms->swapThrottling) ?
+ &dst_priv->fence : NULL);
+
+ if (cust && cust->winsys_context_throttle)
+ cust->winsys_context_throttle(cust, ms->ctx, THROTTLE_RENDER);
+
+}
+
+Bool
+xorg_dri2_init(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ DRI2InfoRec dri2info;
+#if DRI2INFOREC_VERSION >= 2
+ int major, minor;
+
+ if (xf86LoaderCheckSymbol("DRI2Version")) {
+ DRI2Version(&major, &minor);
+ } else {
+ /* Assume version 1.0 */
+ major = 1;
+ minor = 0;
+ }
+#endif
+
+ dri2info.version = min(DRI2INFOREC_VERSION, 3);
+ dri2info.fd = ms->fd;
+
+ dri2info.driverName = pScrn->driverName;
+ dri2info.deviceName = "/dev/dri/card0"; /* FIXME */
+
+#if DRI2INFOREC_VERSION >= 2
+ dri2info.CreateBuffer = dri2_create_buffer;
+ dri2info.DestroyBuffer = dri2_destroy_buffer;
+#endif
+
+ /* For X servers in the 1.6.x series there where two DRI2 version.
+ * This allows us to build one binary that works on both servers.
+ */
+#if DRI2INFOREC_VERSION == 2
+ if (minor == 0) {
+ set_format_in_do_create_buffer = FALSE;
+ dri2info.CreateBuffers = dri2_create_buffers;
+ dri2info.DestroyBuffers = dri2_destroy_buffers;
+ } else
+ set_format_in_do_create_buffer = FALSE;
+#endif
+
+ /* For version 1 set these unconditionaly. */
+#if DRI2INFOREC_VERSION == 1
+ dri2info.CreateBuffers = dri2_create_buffers;
+ dri2info.DestroyBuffers = dri2_destroy_buffers;
+#endif
+ dri2info.CopyRegion = dri2_copy_region;
+ dri2info.Wait = NULL;
+
+ ms->d_depth_bits_last =
+ ms->screen->is_format_supported(ms->screen, PIPE_FORMAT_Z24X8_UNORM,
+ PIPE_TEXTURE_2D,
+ 0,
+ PIPE_BIND_DEPTH_STENCIL, 0);
+ ms->ds_depth_bits_last =
+ ms->screen->is_format_supported(ms->screen, PIPE_FORMAT_Z24_UNORM_S8_USCALED,
+ PIPE_TEXTURE_2D,
+ 0,
+ PIPE_BIND_DEPTH_STENCIL, 0);
+
+ return DRI2ScreenInit(pScreen, &dri2info);
+}
+
+void
+xorg_dri2_close(ScreenPtr pScreen)
+{
+ DRI2CloseScreen(pScreen);
+}
+
+/* vim: set sw=4 ts=8 sts=4: */
diff --git a/src/gallium/state_trackers/xorg/xorg_driver.c b/src/gallium/state_trackers/xorg/xorg_driver.c
new file mode 100644
index 0000000000..a7e57634ae
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xorg_driver.c
@@ -0,0 +1,1243 @@
+/*
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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.
+ *
+ *
+ * Author: Alan Hourihane <alanh@tungstengraphics.com>
+ * Author: Jakob Bornecrantz <wallbraker@gmail.com>
+ *
+ */
+
+
+#include "xorg-server.h"
+#include "xf86.h"
+#include "xf86_OSproc.h"
+#include "compiler.h"
+#include "xf86PciInfo.h"
+#include "xf86Pci.h"
+#include "mipointer.h"
+#include "micmap.h"
+#include <X11/extensions/randr.h>
+#include "fb.h"
+#include "edid.h"
+#include "xf86i2c.h"
+#include "xf86Crtc.h"
+#include "miscstruct.h"
+#include "dixstruct.h"
+#include "xf86xv.h"
+#ifndef XSERVER_LIBPCIACCESS
+#error "libpciaccess needed"
+#endif
+
+#include <pciaccess.h>
+
+#include "pipe/p_context.h"
+#include "xorg_tracker.h"
+#include "xorg_winsys.h"
+
+#ifdef HAVE_LIBKMS
+#include "libkms.h"
+#endif
+
+/*
+ * Functions and symbols exported to Xorg via pointers.
+ */
+
+static Bool drv_pre_init(ScrnInfoPtr pScrn, int flags);
+static Bool drv_screen_init(int scrnIndex, ScreenPtr pScreen, int argc,
+ char **argv);
+static Bool drv_switch_mode(int scrnIndex, DisplayModePtr mode, int flags);
+static void drv_adjust_frame(int scrnIndex, int x, int y, int flags);
+static Bool drv_enter_vt(int scrnIndex, int flags);
+static void drv_leave_vt(int scrnIndex, int flags);
+static void drv_free_screen(int scrnIndex, int flags);
+static ModeStatus drv_valid_mode(int scrnIndex, DisplayModePtr mode, Bool verbose,
+ int flags);
+
+typedef enum
+{
+ OPTION_SW_CURSOR,
+ OPTION_2D_ACCEL,
+ OPTION_DEBUG_FALLBACK,
+ OPTION_THROTTLE_SWAP,
+ OPTION_THROTTLE_DIRTY,
+ OPTION_3D_ACCEL
+} drv_option_enums;
+
+static const OptionInfoRec drv_options[] = {
+ {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_2D_ACCEL, "2DAccel", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_DEBUG_FALLBACK, "DebugFallback", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_THROTTLE_SWAP, "SwapThrottling", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_THROTTLE_DIRTY, "DirtyThrottling", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_3D_ACCEL, "3DAccel", OPTV_BOOLEAN, {0}, FALSE},
+ {-1, NULL, OPTV_NONE, {0}, FALSE}
+};
+
+
+/*
+ * Exported Xorg driver functions to winsys
+ */
+
+const OptionInfoRec *
+xorg_tracker_available_options(int chipid, int busid)
+{
+ return drv_options;
+}
+
+void
+xorg_tracker_set_functions(ScrnInfoPtr scrn)
+{
+ scrn->PreInit = drv_pre_init;
+ scrn->ScreenInit = drv_screen_init;
+ scrn->SwitchMode = drv_switch_mode;
+ scrn->AdjustFrame = drv_adjust_frame;
+ scrn->EnterVT = drv_enter_vt;
+ scrn->LeaveVT = drv_leave_vt;
+ scrn->FreeScreen = drv_free_screen;
+ scrn->ValidMode = drv_valid_mode;
+}
+
+Bool
+xorg_tracker_have_modesetting(ScrnInfoPtr pScrn, struct pci_device *device)
+{
+ char *BusID = xalloc(64);
+ sprintf(BusID, "pci:%04x:%02x:%02x.%d",
+ device->domain, device->bus,
+ device->dev, device->func);
+
+ if (drmCheckModesettingSupported(BusID)) {
+ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0,
+ "Drm modesetting not supported %s\n", BusID);
+ xfree(BusID);
+ return FALSE;
+ }
+
+ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0,
+ "Drm modesetting supported on %s\n", BusID);
+
+ xfree(BusID);
+ return TRUE;
+}
+
+
+/*
+ * Internal function definitions
+ */
+
+static Bool drv_init_front_buffer_functions(ScrnInfoPtr pScrn);
+static Bool drv_close_screen(int scrnIndex, ScreenPtr pScreen);
+
+
+/*
+ * Internal functions
+ */
+
+static Bool
+drv_get_rec(ScrnInfoPtr pScrn)
+{
+ if (pScrn->driverPrivate)
+ return TRUE;
+
+ pScrn->driverPrivate = xnfcalloc(1, sizeof(modesettingRec));
+
+ return TRUE;
+}
+
+static void
+drv_free_rec(ScrnInfoPtr pScrn)
+{
+ if (!pScrn)
+ return;
+
+ if (!pScrn->driverPrivate)
+ return;
+
+ xfree(pScrn->driverPrivate);
+
+ pScrn->driverPrivate = NULL;
+}
+
+static void
+drv_probe_ddc(ScrnInfoPtr pScrn, int index)
+{
+ ConfiguredMonitor = NULL;
+}
+
+static Bool
+drv_crtc_resize(ScrnInfoPtr pScrn, int width, int height)
+{
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+ modesettingPtr ms = modesettingPTR(pScrn);
+ ScreenPtr pScreen = pScrn->pScreen;
+ int old_width, old_height;
+ PixmapPtr rootPixmap;
+ int i;
+
+ if (width == pScrn->virtualX && height == pScrn->virtualY)
+ return TRUE;
+
+ old_width = pScrn->virtualX;
+ old_height = pScrn->virtualY;
+ pScrn->virtualX = width;
+ pScrn->virtualY = height;
+
+ /* ms->create_front_buffer will remove the old front buffer */
+
+ rootPixmap = pScreen->GetScreenPixmap(pScreen);
+ if (!pScreen->ModifyPixmapHeader(rootPixmap, width, height, -1, -1, -1, NULL))
+ goto error_modify;
+
+ pScrn->displayWidth = rootPixmap->devKind / (rootPixmap->drawable.bitsPerPixel / 8);
+
+ if (!ms->create_front_buffer(pScrn) || !ms->bind_front_buffer(pScrn))
+ goto error_create;
+
+ /*
+ * create && bind will turn off all crtc(s) in the kernel so we need to
+ * re-enable all the crtcs again. For real HW we might want to do this
+ * before destroying the old framebuffer.
+ */
+ for (i = 0; i < xf86_config->num_crtc; i++) {
+ xf86CrtcPtr crtc = xf86_config->crtc[i];
+
+ if (!crtc->enabled)
+ continue;
+
+ crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation, crtc->x, crtc->y);
+ }
+
+ return TRUE;
+
+ /*
+ * This is the error recovery path.
+ */
+error_create:
+ if (!pScreen->ModifyPixmapHeader(rootPixmap, old_width, old_height, -1, -1, -1, NULL))
+ FatalError("failed to resize rootPixmap error path\n");
+
+ pScrn->displayWidth = rootPixmap->devKind / (rootPixmap->drawable.bitsPerPixel / 8);
+
+error_modify:
+ pScrn->virtualX = old_width;
+ pScrn->virtualY = old_height;
+
+ if (ms->create_front_buffer(pScrn) && ms->bind_front_buffer(pScrn))
+ return FALSE;
+
+ FatalError("failed to setup old framebuffer\n");
+ return FALSE;
+}
+
+static const xf86CrtcConfigFuncsRec crtc_config_funcs = {
+ .resize = drv_crtc_resize
+};
+
+static Bool
+drv_init_drm(ScrnInfoPtr pScrn)
+{
+ modesettingPtr ms = modesettingPTR(pScrn);
+
+ /* deal with server regeneration */
+ if (ms->fd < 0) {
+ char *BusID;
+
+ BusID = xalloc(64);
+ sprintf(BusID, "PCI:%d:%d:%d",
+ ((ms->PciInfo->domain << 8) | ms->PciInfo->bus),
+ ms->PciInfo->dev, ms->PciInfo->func
+ );
+
+
+ ms->api = drm_api_create();
+ ms->fd = drmOpen(ms->api ? ms->api->driver_name : NULL, BusID);
+ xfree(BusID);
+
+ if (ms->fd >= 0)
+ return TRUE;
+
+ if (ms->api && ms->api->destroy)
+ ms->api->destroy(ms->api);
+
+ ms->api = NULL;
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static Bool
+drv_close_drm(ScrnInfoPtr pScrn)
+{
+ modesettingPtr ms = modesettingPTR(pScrn);
+
+ if (ms->api && ms->api->destroy)
+ ms->api->destroy(ms->api);
+ ms->api = NULL;
+
+ drmClose(ms->fd);
+ ms->fd = -1;
+
+ return TRUE;
+}
+
+static Bool
+drv_init_resource_management(ScrnInfoPtr pScrn)
+{
+ modesettingPtr ms = modesettingPTR(pScrn);
+ /*
+ ScreenPtr pScreen = pScrn->pScreen;
+ PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
+ Bool fbAccessDisabled;
+ CARD8 *fbstart;
+ */
+
+ if (ms->screen || ms->kms)
+ return TRUE;
+
+ if (ms->api) {
+ ms->screen = ms->no3D ? NULL :
+ ms->api->create_screen(ms->api, ms->fd);
+
+ if (ms->screen)
+ return TRUE;
+
+ if (ms->api->destroy)
+ ms->api->destroy(ms->api);
+
+ ms->api = NULL;
+ }
+
+#ifdef HAVE_LIBKMS
+ if (!kms_create(ms->fd, &ms->kms))
+ return TRUE;
+#endif
+
+ return FALSE;
+}
+
+static Bool
+drv_close_resource_management(ScrnInfoPtr pScrn)
+{
+ modesettingPtr ms = modesettingPTR(pScrn);
+
+ if (ms->screen) {
+ assert(ms->ctx == NULL);
+ ms->screen->destroy(ms->screen);
+ }
+ ms->screen = NULL;
+
+#ifdef HAVE_LIBKMS
+ if (ms->kms)
+ kms_destroy(&ms->kms);
+#endif
+
+ return TRUE;
+}
+
+static void
+drv_cleanup_fences(ScrnInfoPtr pScrn)
+{
+ modesettingPtr ms = modesettingPTR(pScrn);
+ int i;
+
+ assert(ms->screen);
+
+ for (i = 0; i < XORG_NR_FENCES; i++) {
+ if (ms->fence[i]) {
+ ms->screen->fence_finish(ms->screen, ms->fence[i], 0);
+ ms->screen->fence_reference(ms->screen, &ms->fence[i], NULL);
+ }
+ }
+}
+
+static Bool
+drv_pre_init(ScrnInfoPtr pScrn, int flags)
+{
+ xf86CrtcConfigPtr xf86_config;
+ modesettingPtr ms;
+ rgb defaultWeight = { 0, 0, 0 };
+ EntityInfoPtr pEnt;
+ EntPtr msEnt = NULL;
+ int max_width, max_height;
+ CustomizerPtr cust;
+
+ if (pScrn->numEntities != 1)
+ return FALSE;
+
+ pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
+
+ if (flags & PROBE_DETECT) {
+ drv_probe_ddc(pScrn, pEnt->index);
+ return TRUE;
+ }
+
+ cust = (CustomizerPtr) pScrn->driverPrivate;
+ pScrn->driverPrivate = NULL;
+
+ /* Allocate driverPrivate */
+ if (!drv_get_rec(pScrn))
+ return FALSE;
+
+ ms = modesettingPTR(pScrn);
+ ms->pEnt = pEnt;
+ ms->cust = cust;
+
+ pScrn->displayWidth = 640; /* default it */
+
+ if (ms->pEnt->location.type != BUS_PCI)
+ return FALSE;
+
+ ms->PciInfo = xf86GetPciInfoForEntity(ms->pEnt->index);
+
+ /* Allocate an entity private if necessary */
+ if (xf86IsEntityShared(pScrn->entityList[0])) {
+ FatalError("Entity");
+#if 0
+ msEnt = xf86GetEntityPrivate(pScrn->entityList[0],
+ modesettingEntityIndex)->ptr;
+ ms->entityPrivate = msEnt;
+#else
+ (void)msEnt;
+#endif
+ } else
+ ms->entityPrivate = NULL;
+
+ if (xf86IsEntityShared(pScrn->entityList[0])) {
+ if (xf86IsPrimInitDone(pScrn->entityList[0])) {
+ /* do something */
+ } else {
+ xf86SetPrimInitDone(pScrn->entityList[0]);
+ }
+ }
+
+ ms->fd = -1;
+ ms->api = NULL;
+ if (!drv_init_drm(pScrn))
+ return FALSE;
+
+ pScrn->monitor = pScrn->confScreen->monitor;
+ pScrn->progClock = TRUE;
+ pScrn->rgbBits = 8;
+
+ if (!xf86SetDepthBpp
+ (pScrn, 0, 0, 0,
+ PreferConvert24to32 | SupportConvert24to32 | Support32bppFb))
+ return FALSE;
+
+ switch (pScrn->depth) {
+ case 15:
+ case 16:
+ case 24:
+ break;
+ default:
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Given depth (%d) is not supported by the driver\n",
+ pScrn->depth);
+ return FALSE;
+ }
+ xf86PrintDepthBpp(pScrn);
+
+ if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight))
+ return FALSE;
+ if (!xf86SetDefaultVisual(pScrn, -1))
+ return FALSE;
+
+ /* Process the options */
+ xf86CollectOptions(pScrn, NULL);
+ if (!(ms->Options = xalloc(sizeof(drv_options))))
+ return FALSE;
+ memcpy(ms->Options, drv_options, sizeof(drv_options));
+ xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, ms->Options);
+
+ /* Allocate an xf86CrtcConfig */
+ xf86CrtcConfigInit(pScrn, &crtc_config_funcs);
+ xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+
+ max_width = 2048; /* A very low default */
+ max_height = 2048; /* see screen_init */
+ xf86CrtcSetSizeRange(pScrn, 320, 200, max_width, max_height);
+
+ if (xf86ReturnOptValBool(ms->Options, OPTION_SW_CURSOR, FALSE)) {
+ ms->SWCursor = TRUE;
+ }
+
+ xorg_crtc_init(pScrn);
+ xorg_output_init(pScrn);
+
+ if (!xf86InitialConfiguration(pScrn, TRUE)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n");
+ return FALSE;
+ }
+
+ /*
+ * If the driver can do gamma correction, it should call xf86SetGamma() here.
+ */
+ {
+ Gamma zeros = { 0.0, 0.0, 0.0 };
+
+ if (!xf86SetGamma(pScrn, zeros)) {
+ return FALSE;
+ }
+ }
+
+ if (pScrn->modes == NULL) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n");
+ return FALSE;
+ }
+
+ pScrn->currentMode = pScrn->modes;
+
+ /* Set display resolution */
+ xf86SetDpi(pScrn, 0, 0);
+
+ /* Load the required sub modules */
+ if (!xf86LoadSubModule(pScrn, "fb"))
+ return FALSE;
+
+ /* XXX: these aren't needed when we are using libkms */
+ if (!xf86LoadSubModule(pScrn, "exa"))
+ return FALSE;
+
+#ifdef DRI2
+ if (!xf86LoadSubModule(pScrn, "dri2"))
+ return FALSE;
+#endif
+
+ return TRUE;
+}
+
+static void drv_block_handler(int i, pointer blockData, pointer pTimeout,
+ pointer pReadmask)
+{
+ ScreenPtr pScreen = screenInfo.screens[i];
+ modesettingPtr ms = modesettingPTR(xf86Screens[pScreen->myNum]);
+
+ pScreen->BlockHandler = ms->blockHandler;
+ pScreen->BlockHandler(i, blockData, pTimeout, pReadmask);
+ pScreen->BlockHandler = drv_block_handler;
+
+ if (ms->ctx) {
+ int j;
+
+ ms->ctx->flush(ms->ctx, PIPE_FLUSH_RENDER_CACHE,
+ ms->dirtyThrottling ?
+ &ms->fence[XORG_NR_FENCES-1] :
+ NULL);
+
+ if (ms->dirtyThrottling) {
+ if (ms->fence[0])
+ ms->ctx->screen->fence_finish(ms->ctx->screen,
+ ms->fence[0], 0);
+
+ /* The amount of rendering generated by a block handler can be
+ * quite small. Let us get a fair way ahead of hardware before
+ * throttling.
+ */
+ for (j = 0; j < XORG_NR_FENCES - 1; j++)
+ ms->screen->fence_reference(ms->screen,
+ &ms->fence[j],
+ ms->fence[j+1]);
+
+ ms->screen->fence_reference(ms->screen,
+ &ms->fence[XORG_NR_FENCES-1],
+ NULL);
+ }
+ }
+
+
+#ifdef DRM_MODE_FEATURE_DIRTYFB
+ {
+ RegionPtr dirty = DamageRegion(ms->damage);
+ unsigned num_cliprects = REGION_NUM_RECTS(dirty);
+
+ if (num_cliprects) {
+ drmModeClip *clip = alloca(num_cliprects * sizeof(drmModeClip));
+ BoxPtr rect = REGION_RECTS(dirty);
+ int i, ret;
+
+ /* XXX no need for copy? */
+ for (i = 0; i < num_cliprects; i++, rect++) {
+ clip[i].x1 = rect->x1;
+ clip[i].y1 = rect->y1;
+ clip[i].x2 = rect->x2;
+ clip[i].y2 = rect->y2;
+ }
+
+ /* TODO query connector property to see if this is needed */
+ ret = drmModeDirtyFB(ms->fd, ms->fb_id, clip, num_cliprects);
+ if (ret) {
+ debug_printf("%s: failed to send dirty (%i, %s)\n",
+ __func__, ret, strerror(-ret));
+ }
+
+ DamageEmpty(ms->damage);
+ }
+ }
+#endif
+}
+
+static Bool
+drv_create_screen_resources(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ PixmapPtr rootPixmap;
+ Bool ret;
+
+ ms->noEvict = TRUE;
+
+ pScreen->CreateScreenResources = ms->createScreenResources;
+ ret = pScreen->CreateScreenResources(pScreen);
+ pScreen->CreateScreenResources = drv_create_screen_resources;
+
+ ms->bind_front_buffer(pScrn);
+
+ ms->noEvict = FALSE;
+
+ drv_adjust_frame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
+
+#ifdef DRM_MODE_FEATURE_DIRTYFB
+ rootPixmap = pScreen->GetScreenPixmap(pScreen);
+ ms->damage = DamageCreate(NULL, NULL, DamageReportNone, TRUE,
+ pScreen, rootPixmap);
+
+ if (ms->damage) {
+ DamageRegister(&rootPixmap->drawable, ms->damage);
+
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Damage tracking initialized\n");
+ } else {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Failed to create screen damage record\n");
+ return FALSE;
+ }
+#else
+ (void)rootPixmap;
+#endif
+
+ return ret;
+}
+
+static Bool
+drv_screen_init(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ unsigned max_width, max_height;
+ VisualPtr visual;
+ CustomizerPtr cust = ms->cust;
+ MessageType from_st;
+ MessageType from_dt;
+ MessageType from_3D;
+ Bool use3D;
+
+ if (!drv_init_drm(pScrn)) {
+ FatalError("Could not init DRM");
+ return FALSE;
+ }
+
+ use3D = cust ? !cust->no_3d : TRUE;
+ from_3D = xf86GetOptValBool(ms->Options, OPTION_3D_ACCEL,
+ &use3D) ?
+ X_CONFIG : X_PROBED;
+
+ ms->no3D = !use3D;
+
+ if (!drv_init_resource_management(pScrn)) {
+ FatalError("Could not init resource management (!pipe_screen && !libkms)");
+ return FALSE;
+ }
+
+ if (!drv_init_front_buffer_functions(pScrn)) {
+ FatalError("Could not init front buffer manager");
+ return FALSE;
+ }
+
+ /* get max width and height */
+ {
+ drmModeResPtr res;
+ res = drmModeGetResources(ms->fd);
+ max_width = res->max_width;
+ max_height = res->max_height;
+ drmModeFreeResources(res);
+ }
+
+ if (ms->screen) {
+ int max;
+ max = ms->screen->get_param(ms->screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS);
+ max = 1 << (max - 1);
+ max_width = max < max_width ? max : max_width;
+ max_height = max < max_height ? max : max_height;
+ }
+
+ xf86CrtcSetSizeRange(pScrn, 1, 1, max_width, max_height);
+
+ pScrn->pScreen = pScreen;
+
+ /* HW dependent - FIXME */
+ pScrn->displayWidth = pScrn->virtualX;
+
+ miClearVisualTypes();
+
+ if (!miSetVisualTypes(pScrn->depth,
+ miGetDefaultVisualMask(pScrn->depth),
+ pScrn->rgbBits, pScrn->defaultVisual))
+ return FALSE;
+
+ if (!miSetPixmapDepths())
+ return FALSE;
+
+ pScrn->memPhysBase = 0;
+ pScrn->fbOffset = 0;
+
+ if (!fbScreenInit(pScreen, NULL,
+ pScrn->virtualX, pScrn->virtualY,
+ pScrn->xDpi, pScrn->yDpi,
+ pScrn->displayWidth, pScrn->bitsPerPixel))
+ return FALSE;
+
+ if (pScrn->bitsPerPixel > 8) {
+ /* Fixup RGB ordering */
+ visual = pScreen->visuals + pScreen->numVisuals;
+ while (--visual >= pScreen->visuals) {
+ if ((visual->class | DynamicClass) == DirectColor) {
+ visual->offsetRed = pScrn->offset.red;
+ visual->offsetGreen = pScrn->offset.green;
+ visual->offsetBlue = pScrn->offset.blue;
+ visual->redMask = pScrn->mask.red;
+ visual->greenMask = pScrn->mask.green;
+ visual->blueMask = pScrn->mask.blue;
+ }
+ }
+ }
+
+ fbPictureInit(pScreen, NULL, 0);
+
+ ms->blockHandler = pScreen->BlockHandler;
+ pScreen->BlockHandler = drv_block_handler;
+ ms->createScreenResources = pScreen->CreateScreenResources;
+ pScreen->CreateScreenResources = drv_create_screen_resources;
+
+ xf86SetBlackWhitePixels(pScreen);
+
+ ms->accelerate_2d = xf86ReturnOptValBool(ms->Options, OPTION_2D_ACCEL, FALSE);
+ ms->debug_fallback = xf86ReturnOptValBool(ms->Options, OPTION_DEBUG_FALLBACK, ms->accelerate_2d);
+
+ if (cust && cust->winsys_screen_init)
+ cust->winsys_screen_init(cust, ms->fd);
+
+ ms->swapThrottling = cust ? cust->swap_throttling : TRUE;
+ from_st = xf86GetOptValBool(ms->Options, OPTION_THROTTLE_SWAP,
+ &ms->swapThrottling) ?
+ X_CONFIG : X_DEFAULT;
+
+ ms->dirtyThrottling = cust ? cust->dirty_throttling : TRUE;
+ from_dt = xf86GetOptValBool(ms->Options, OPTION_THROTTLE_DIRTY,
+ &ms->dirtyThrottling) ?
+ X_CONFIG : X_DEFAULT;
+
+ if (ms->screen) {
+ ms->exa = xorg_exa_init(pScrn, ms->accelerate_2d);
+
+ xorg_xv_init(pScreen);
+#ifdef DRI2
+ xorg_dri2_init(pScreen);
+#endif
+ }
+
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "##################################\n");
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "# Usefull debugging info follows #\n");
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "##################################\n");
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using %s backend\n",
+ ms->screen ? "Gallium3D" : "libkms");
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "2D Acceleration is %s\n",
+ ms->screen && ms->accelerate_2d ? "enabled" : "disabled");
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Fallback debugging is %s\n",
+ ms->debug_fallback ? "enabled" : "disabled");
+#ifdef DRI2
+ xf86DrvMsg(pScrn->scrnIndex, from_3D, "3D Acceleration is %s\n",
+ ms->screen ? "enabled" : "disabled");
+#else
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "3D Acceleration is disabled\n");
+#endif
+ xf86DrvMsg(pScrn->scrnIndex, from_st, "Swap Throttling is %s.\n",
+ ms->swapThrottling ? "enabled" : "disabled");
+ xf86DrvMsg(pScrn->scrnIndex, from_dt, "Dirty Throttling is %s.\n",
+ ms->dirtyThrottling ? "enabled" : "disabled");
+
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "##################################\n");
+
+ miInitializeBackingStore(pScreen);
+ xf86SetBackingStore(pScreen);
+ xf86SetSilkenMouse(pScreen);
+ miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
+
+ /* Need to extend HWcursor support to handle mask interleave */
+ if (!ms->SWCursor)
+ xf86_cursors_init(pScreen, 64, 64,
+ HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 |
+ HARDWARE_CURSOR_ARGB);
+
+ /* Must force it before EnterVT, so we are in control of VT and
+ * later memory should be bound when allocating, e.g rotate_mem */
+ pScrn->vtSema = TRUE;
+
+ pScreen->SaveScreen = xf86SaveScreen;
+ ms->CloseScreen = pScreen->CloseScreen;
+ pScreen->CloseScreen = drv_close_screen;
+
+ if (!xf86CrtcScreenInit(pScreen))
+ return FALSE;
+
+ if (!miCreateDefColormap(pScreen))
+ return FALSE;
+
+ xf86DPMSInit(pScreen, xf86DPMSSet, 0);
+
+ if (serverGeneration == 1)
+ xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
+
+ return drv_enter_vt(scrnIndex, 1);
+}
+
+static void
+drv_adjust_frame(int scrnIndex, int x, int y, int flags)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
+ xf86OutputPtr output = config->output[config->compat_output];
+ xf86CrtcPtr crtc = output->crtc;
+
+ if (crtc && crtc->enabled) {
+ crtc->funcs->set_mode_major(crtc, pScrn->currentMode,
+ RR_Rotate_0, x, y);
+ crtc->x = output->initial_x + x;
+ crtc->y = output->initial_y + y;
+ }
+}
+
+static void
+drv_free_screen(int scrnIndex, int flags)
+{
+ drv_free_rec(xf86Screens[scrnIndex]);
+}
+
+static void
+drv_leave_vt(int scrnIndex, int flags)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
+ CustomizerPtr cust = ms->cust;
+ int o;
+
+ if (cust && cust->winsys_leave_vt)
+ cust->winsys_leave_vt(cust);
+
+ for (o = 0; o < config->num_crtc; o++) {
+ xf86CrtcPtr crtc = config->crtc[o];
+
+ xorg_crtc_cursor_destroy(crtc);
+
+ if (crtc->rotatedPixmap || crtc->rotatedData) {
+ crtc->funcs->shadow_destroy(crtc, crtc->rotatedPixmap,
+ crtc->rotatedData);
+ crtc->rotatedPixmap = NULL;
+ crtc->rotatedData = NULL;
+ }
+ }
+
+ drmModeRmFB(ms->fd, ms->fb_id);
+ ms->fb_id = -1;
+
+ /* idle hardware */
+ if (!ms->kms)
+ drv_cleanup_fences(pScrn);
+
+ if (drmDropMaster(ms->fd))
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "drmDropMaster failed: %s\n", strerror(errno));
+
+ pScrn->vtSema = FALSE;
+}
+
+/*
+ * This gets called when gaining control of the VT, and from ScreenInit().
+ */
+static Bool
+drv_enter_vt(int scrnIndex, int flags)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ CustomizerPtr cust = ms->cust;
+
+ if (drmSetMaster(ms->fd)) {
+ if (errno == EINVAL) {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "drmSetMaster failed: 2.6.29 or newer kernel required for "
+ "multi-server DRI\n");
+ } else {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "drmSetMaster failed: %s\n", strerror(errno));
+ }
+ }
+
+ if (!ms->create_front_buffer(pScrn))
+ return FALSE;
+
+ if (!flags && !ms->bind_front_buffer(pScrn))
+ return FALSE;
+
+ if (!xf86SetDesiredModes(pScrn))
+ return FALSE;
+
+ if (cust && cust->winsys_enter_vt)
+ cust->winsys_enter_vt(cust);
+
+ return TRUE;
+}
+
+static Bool
+drv_switch_mode(int scrnIndex, DisplayModePtr mode, int flags)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+
+ return xf86SetSingleMode(pScrn, mode, RR_Rotate_0);
+}
+
+static Bool
+drv_close_screen(int scrnIndex, ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ CustomizerPtr cust = ms->cust;
+
+ if (ms->cursor) {
+ FreeCursor(ms->cursor, None);
+ ms->cursor = NULL;
+ }
+
+ if (cust && cust->winsys_screen_close)
+ cust->winsys_screen_close(cust);
+
+#ifdef DRI2
+ if (ms->screen)
+ xorg_dri2_close(pScreen);
+#endif
+
+ pScreen->BlockHandler = ms->blockHandler;
+ pScreen->CreateScreenResources = ms->createScreenResources;
+
+#ifdef DRM_MODE_FEATURE_DIRTYFB
+ if (ms->damage) {
+ DamageUnregister(&pScreen->GetScreenPixmap(pScreen)->drawable, ms->damage);
+ DamageDestroy(ms->damage);
+ ms->damage = NULL;
+ }
+#endif
+
+ drmModeRmFB(ms->fd, ms->fb_id);
+ ms->destroy_front_buffer(pScrn);
+
+ if (ms->exa)
+ xorg_exa_close(pScrn);
+ ms->exa = NULL;
+
+ /* calls drop master make sure we don't talk to 3D HW after that */
+ if (pScrn->vtSema) {
+ drv_leave_vt(scrnIndex, 0);
+ }
+
+ drv_close_resource_management(pScrn);
+
+ drv_close_drm(pScrn);
+
+ pScrn->vtSema = FALSE;
+ pScreen->CloseScreen = ms->CloseScreen;
+ return (*pScreen->CloseScreen) (scrnIndex, pScreen);
+}
+
+static ModeStatus
+drv_valid_mode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
+{
+ return MODE_OK;
+}
+
+
+/*
+ * Front buffer backing store functions.
+ */
+
+static Bool
+drv_destroy_front_buffer_ga3d(ScrnInfoPtr pScrn)
+{
+ modesettingPtr ms = modesettingPTR(pScrn);
+
+ if (!ms->root_texture)
+ return TRUE;
+
+ if (ms->fb_id != -1) {
+ drmModeRmFB(ms->fd, ms->fb_id);
+ ms->fb_id = -1;
+ }
+
+ pipe_resource_reference(&ms->root_texture, NULL);
+ return TRUE;
+}
+
+static Bool
+drv_create_front_buffer_ga3d(ScrnInfoPtr pScrn)
+{
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct pipe_resource *tex;
+ struct winsys_handle whandle;
+ unsigned fb_id;
+ int ret;
+
+ ms->noEvict = TRUE;
+
+ tex = xorg_exa_create_root_texture(pScrn, pScrn->virtualX, pScrn->virtualY,
+ pScrn->depth, pScrn->bitsPerPixel);
+
+ if (!tex)
+ return FALSE;
+
+ memset(&whandle, 0, sizeof(whandle));
+ whandle.type = DRM_API_HANDLE_TYPE_KMS;
+
+ if (!ms->screen->resource_get_handle(ms->screen, tex, &whandle))
+ goto err_destroy;
+
+ ret = drmModeAddFB(ms->fd,
+ pScrn->virtualX,
+ pScrn->virtualY,
+ pScrn->depth,
+ pScrn->bitsPerPixel,
+ whandle.stride,
+ whandle.handle,
+ &fb_id);
+ if (ret) {
+ debug_printf("%s: failed to create framebuffer (%i, %s)\n",
+ __func__, ret, strerror(-ret));
+ goto err_destroy;
+ }
+
+ if (!drv_destroy_front_buffer_ga3d(pScrn))
+ FatalError("%s: failed to take down old framebuffer\n", __func__);
+
+ pScrn->frameX0 = 0;
+ pScrn->frameY0 = 0;
+ drv_adjust_frame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
+
+ pipe_resource_reference(&ms->root_texture, tex);
+ pipe_resource_reference(&tex, NULL);
+ ms->fb_id = fb_id;
+
+ return TRUE;
+
+err_destroy:
+ pipe_resource_reference(&tex, NULL);
+ return FALSE;
+}
+
+static Bool
+drv_bind_front_buffer_ga3d(ScrnInfoPtr pScrn)
+{
+ modesettingPtr ms = modesettingPTR(pScrn);
+ ScreenPtr pScreen = pScrn->pScreen;
+ PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
+ struct pipe_resource *check;
+
+ xorg_exa_set_displayed_usage(rootPixmap);
+ xorg_exa_set_shared_usage(rootPixmap);
+ xorg_exa_set_texture(rootPixmap, ms->root_texture);
+ if (!pScreen->ModifyPixmapHeader(rootPixmap, -1, -1, -1, -1, -1, NULL))
+ FatalError("Couldn't adjust screen pixmap\n");
+
+ check = xorg_exa_get_texture(rootPixmap);
+ if (ms->root_texture != check)
+ FatalError("Created new root texture\n");
+
+ pipe_resource_reference(&check, NULL);
+ return TRUE;
+}
+
+#ifdef HAVE_LIBKMS
+static Bool
+drv_destroy_front_buffer_kms(ScrnInfoPtr pScrn)
+{
+ modesettingPtr ms = modesettingPTR(pScrn);
+ ScreenPtr pScreen = pScrn->pScreen;
+ PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
+
+ /* XXX Do something with the rootPixmap.
+ * This currently works fine but if we are getting crashes in
+ * the fb functions after VT switches maybe look more into it.
+ */
+ (void)rootPixmap;
+
+ if (!ms->root_bo)
+ return TRUE;
+
+ if (ms->fb_id != -1) {
+ drmModeRmFB(ms->fd, ms->fb_id);
+ ms->fb_id = -1;
+ }
+
+ kms_bo_unmap(ms->root_bo);
+ kms_bo_destroy(&ms->root_bo);
+ return TRUE;
+}
+
+static Bool
+drv_create_front_buffer_kms(ScrnInfoPtr pScrn)
+{
+ modesettingPtr ms = modesettingPTR(pScrn);
+ unsigned handle, stride;
+ struct kms_bo *bo;
+ unsigned attr[8];
+ unsigned fb_id;
+ int ret;
+
+ attr[0] = KMS_BO_TYPE;
+#ifdef KMS_BO_TYPE_SCANOUT_X8R8G8B8
+ attr[1] = KMS_BO_TYPE_SCANOUT_X8R8G8B8;
+#else
+ attr[1] = KMS_BO_TYPE_SCANOUT;
+#endif
+ attr[2] = KMS_WIDTH;
+ attr[3] = pScrn->virtualX;
+ attr[4] = KMS_HEIGHT;
+ attr[5] = pScrn->virtualY;
+ attr[6] = 0;
+
+ if (kms_bo_create(ms->kms, attr, &bo))
+ return FALSE;
+
+ if (kms_bo_get_prop(bo, KMS_PITCH, &stride))
+ goto err_destroy;
+
+ if (kms_bo_get_prop(bo, KMS_HANDLE, &handle))
+ goto err_destroy;
+
+ ret = drmModeAddFB(ms->fd,
+ pScrn->virtualX,
+ pScrn->virtualY,
+ pScrn->depth,
+ pScrn->bitsPerPixel,
+ stride,
+ handle,
+ &fb_id);
+ if (ret) {
+ debug_printf("%s: failed to create framebuffer (%i, %s)",
+ __func__, ret, strerror(-ret));
+ goto err_destroy;
+ }
+
+ if (!drv_destroy_front_buffer_kms(pScrn))
+ FatalError("%s: could not takedown old bo", __func__);
+
+ pScrn->frameX0 = 0;
+ pScrn->frameY0 = 0;
+ drv_adjust_frame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
+ ms->root_bo = bo;
+ ms->fb_id = fb_id;
+
+ return TRUE;
+
+err_destroy:
+ kms_bo_destroy(&bo);
+ return FALSE;
+}
+
+static Bool
+drv_bind_front_buffer_kms(ScrnInfoPtr pScrn)
+{
+ modesettingPtr ms = modesettingPTR(pScrn);
+ ScreenPtr pScreen = pScrn->pScreen;
+ PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
+ unsigned stride;
+ void *ptr;
+
+ if (kms_bo_get_prop(ms->root_bo, KMS_PITCH, &stride))
+ return FALSE;
+
+ if (kms_bo_map(ms->root_bo, &ptr))
+ goto err_destroy;
+
+ pScreen->ModifyPixmapHeader(rootPixmap,
+ pScrn->virtualX,
+ pScrn->virtualY,
+ pScreen->rootDepth,
+ pScrn->bitsPerPixel,
+ stride,
+ ptr);
+
+ /* This a hack to work around EnableDisableFBAccess setting the pointer
+ * the real fix would be to replace pScrn->EnableDisableFBAccess hook
+ * and set the rootPixmap->devPrivate.ptr to something valid before that.
+ *
+ * But in its infinit visdome something uses either this some times before
+ * that, so our hook doesn't get called before the crash happens.
+ */
+ pScrn->pixmapPrivate.ptr = ptr;
+
+ return TRUE;
+
+err_destroy:
+ kms_bo_destroy(&ms->root_bo);
+ return FALSE;
+}
+#endif /* HAVE_LIBKMS */
+
+static Bool drv_init_front_buffer_functions(ScrnInfoPtr pScrn)
+{
+ modesettingPtr ms = modesettingPTR(pScrn);
+ if (ms->screen) {
+ ms->destroy_front_buffer = drv_destroy_front_buffer_ga3d;
+ ms->create_front_buffer = drv_create_front_buffer_ga3d;
+ ms->bind_front_buffer = drv_bind_front_buffer_ga3d;
+#ifdef HAVE_LIBKMS
+ } else if (ms->kms) {
+ ms->destroy_front_buffer = drv_destroy_front_buffer_kms;
+ ms->create_front_buffer = drv_create_front_buffer_kms;
+ ms->bind_front_buffer = drv_bind_front_buffer_kms;
+#endif
+ } else
+ return FALSE;
+
+ return TRUE;
+}
+
+CustomizerPtr xorg_customizer(ScrnInfoPtr pScrn)
+{
+ return modesettingPTR(pScrn)->cust;
+}
+
+Bool xorg_has_gallium(ScrnInfoPtr pScrn)
+{
+ return modesettingPTR(pScrn)->screen != NULL;
+}
+
+/* vim: set sw=4 ts=8 sts=4: */
diff --git a/src/gallium/state_trackers/xorg/xorg_exa.c b/src/gallium/state_trackers/xorg/xorg_exa.c
new file mode 100644
index 0000000000..bd84668300
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xorg_exa.c
@@ -0,0 +1,1088 @@
+/*
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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.
+ *
+ *
+ * Author: Alan Hourihane <alanh@tungstengraphics.com>
+ * Author: Jakob Bornecrantz <wallbraker@gmail.com>
+ *
+ */
+
+#include "xorg_exa.h"
+#include "xorg_tracker.h"
+#include "xorg_composite.h"
+#include "xorg_exa_tgsi.h"
+
+#include <xorg-server.h>
+#include <xf86.h>
+#include <picturestr.h>
+#include <picture.h>
+
+#include "pipe/p_format.h"
+#include "pipe/p_context.h"
+#include "pipe/p_state.h"
+
+#include "util/u_rect.h"
+#include "util/u_math.h"
+#include "util/u_debug.h"
+#include "util/u_format.h"
+
+#define DEBUG_PRINT 0
+#define ROUND_UP_TEXTURES 1
+
+/*
+ * Helper functions
+ */
+struct render_format_str {
+ int format;
+ const char *name;
+};
+static const struct render_format_str formats_info[] =
+{
+ {PICT_a8r8g8b8, "PICT_a8r8g8b8"},
+ {PICT_x8r8g8b8, "PICT_x8r8g8b8"},
+ {PICT_a8b8g8r8, "PICT_a8b8g8r8"},
+ {PICT_x8b8g8r8, "PICT_x8b8g8r8"},
+#ifdef PICT_TYPE_BGRA
+ {PICT_b8g8r8a8, "PICT_b8g8r8a8"},
+ {PICT_b8g8r8x8, "PICT_b8g8r8x8"},
+ {PICT_a2r10g10b10, "PICT_a2r10g10b10"},
+ {PICT_x2r10g10b10, "PICT_x2r10g10b10"},
+ {PICT_a2b10g10r10, "PICT_a2b10g10r10"},
+ {PICT_x2b10g10r10, "PICT_x2b10g10r10"},
+#endif
+ {PICT_r8g8b8, "PICT_r8g8b8"},
+ {PICT_b8g8r8, "PICT_b8g8r8"},
+ {PICT_r5g6b5, "PICT_r5g6b5"},
+ {PICT_b5g6r5, "PICT_b5g6r5"},
+ {PICT_a1r5g5b5, "PICT_a1r5g5b5"},
+ {PICT_x1r5g5b5, "PICT_x1r5g5b5"},
+ {PICT_a1b5g5r5, "PICT_a1b5g5r5"},
+ {PICT_x1b5g5r5, "PICT_x1b5g5r5"},
+ {PICT_a4r4g4b4, "PICT_a4r4g4b4"},
+ {PICT_x4r4g4b4, "PICT_x4r4g4b4"},
+ {PICT_a4b4g4r4, "PICT_a4b4g4r4"},
+ {PICT_x4b4g4r4, "PICT_x4b4g4r4"},
+ {PICT_a8, "PICT_a8"},
+ {PICT_r3g3b2, "PICT_r3g3b2"},
+ {PICT_b2g3r3, "PICT_b2g3r3"},
+ {PICT_a2r2g2b2, "PICT_a2r2g2b2"},
+ {PICT_a2b2g2r2, "PICT_a2b2g2r2"},
+ {PICT_c8, "PICT_c8"},
+ {PICT_g8, "PICT_g8"},
+ {PICT_x4a4, "PICT_x4a4"},
+ {PICT_x4c4, "PICT_x4c4"},
+ {PICT_x4g4, "PICT_x4g4"},
+ {PICT_a4, "PICT_a4"},
+ {PICT_r1g2b1, "PICT_r1g2b1"},
+ {PICT_b1g2r1, "PICT_b1g2r1"},
+ {PICT_a1r1g1b1, "PICT_a1r1g1b1"},
+ {PICT_a1b1g1r1, "PICT_a1b1g1r1"},
+ {PICT_c4, "PICT_c4"},
+ {PICT_g4, "PICT_g4"},
+ {PICT_a1, "PICT_a1"},
+ {PICT_g1, "PICT_g1"}
+};
+static const char *render_format_name(int format)
+{
+ int i = 0;
+ for (i = 0; i < sizeof(formats_info)/sizeof(formats_info[0]); ++i) {
+ if (formats_info[i].format == format)
+ return formats_info[i].name;
+ }
+ return NULL;
+}
+
+static void
+exa_get_pipe_format(int depth, enum pipe_format *format, int *bbp, int *picture_format)
+{
+ switch (depth) {
+ case 32:
+ *format = PIPE_FORMAT_B8G8R8A8_UNORM;
+ *picture_format = PICT_a8r8g8b8;
+ assert(*bbp == 32);
+ break;
+ case 24:
+ *format = PIPE_FORMAT_B8G8R8X8_UNORM;
+ *picture_format = PICT_x8r8g8b8;
+ assert(*bbp == 32);
+ break;
+ case 16:
+ *format = PIPE_FORMAT_B5G6R5_UNORM;
+ *picture_format = PICT_r5g6b5;
+ assert(*bbp == 16);
+ break;
+ case 15:
+ *format = PIPE_FORMAT_B5G5R5A1_UNORM;
+ *picture_format = PICT_x1r5g5b5;
+ assert(*bbp == 16);
+ break;
+ case 8:
+ *format = PIPE_FORMAT_L8_UNORM;
+ *picture_format = PICT_a8;
+ assert(*bbp == 8);
+ break;
+ case 4:
+ case 1:
+ *format = PIPE_FORMAT_B8G8R8A8_UNORM; /* bad bad bad */
+ break;
+ default:
+ assert(0);
+ break;
+ }
+}
+
+
+/*
+ * Static exported EXA functions
+ */
+
+static void
+ExaWaitMarker(ScreenPtr pScreen, int marker)
+{
+ /* Nothing to do, handled in the PrepareAccess hook */
+}
+
+static int
+ExaMarkSync(ScreenPtr pScreen)
+{
+ return 1;
+}
+
+
+/***********************************************************************
+ * Screen upload/download
+ */
+
+static Bool
+ExaDownloadFromScreen(PixmapPtr pPix, int x, int y, int w, int h, char *dst,
+ int dst_pitch)
+{
+ ScreenPtr pScreen = pPix->drawable.pScreen;
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct exa_context *exa = ms->exa;
+ struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPix);
+ struct pipe_transfer *transfer;
+
+ if (!priv || !priv->tex)
+ return FALSE;
+
+ transfer = pipe_get_transfer(exa->pipe, priv->tex, 0, 0, 0,
+ PIPE_TRANSFER_READ, x, y, w, h);
+ if (!transfer)
+ return FALSE;
+
+#if DEBUG_PRINT
+ debug_printf("------ ExaDownloadFromScreen(%d, %d, %d, %d, %d)\n",
+ x, y, w, h, dst_pitch);
+#endif
+
+ util_copy_rect((unsigned char*)dst, priv->tex->format, dst_pitch, 0, 0,
+ w, h, exa->pipe->transfer_map(exa->pipe, transfer),
+ transfer->stride, 0, 0);
+
+ exa->pipe->transfer_unmap(exa->pipe, transfer);
+ exa->pipe->transfer_destroy(exa->pipe, transfer);
+
+ return TRUE;
+}
+
+static Bool
+ExaUploadToScreen(PixmapPtr pPix, int x, int y, int w, int h, char *src,
+ int src_pitch)
+{
+ ScreenPtr pScreen = pPix->drawable.pScreen;
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct exa_context *exa = ms->exa;
+ struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPix);
+ struct pipe_transfer *transfer;
+
+ if (!priv || !priv->tex)
+ return FALSE;
+
+ transfer = pipe_get_transfer(exa->pipe, priv->tex, 0, 0, 0,
+ PIPE_TRANSFER_WRITE, x, y, w, h);
+ if (!transfer)
+ return FALSE;
+
+#if DEBUG_PRINT
+ debug_printf("++++++ ExaUploadToScreen(%d, %d, %d, %d, %d)\n",
+ x, y, w, h, src_pitch);
+#endif
+
+ util_copy_rect(exa->pipe->transfer_map(exa->pipe, transfer),
+ priv->tex->format, transfer->stride, 0, 0, w, h,
+ (unsigned char*)src, src_pitch, 0, 0);
+
+ exa->pipe->transfer_unmap(exa->pipe, transfer);
+ exa->pipe->transfer_destroy(exa->pipe, transfer);
+
+ return TRUE;
+}
+
+static Bool
+ExaPrepareAccess(PixmapPtr pPix, int index)
+{
+ ScreenPtr pScreen = pPix->drawable.pScreen;
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct exa_context *exa = ms->exa;
+ struct exa_pixmap_priv *priv;
+
+ priv = exaGetPixmapDriverPrivate(pPix);
+
+ if (!priv)
+ return FALSE;
+
+ if (!priv->tex)
+ return FALSE;
+
+ if (priv->map_count == 0)
+ {
+ assert(pPix->drawable.width <= priv->tex->width0);
+ assert(pPix->drawable.height <= priv->tex->height0);
+
+ priv->map_transfer =
+ pipe_get_transfer(exa->pipe, priv->tex, 0, 0, 0,
+#ifdef EXA_MIXED_PIXMAPS
+ PIPE_TRANSFER_MAP_DIRECTLY |
+#endif
+ PIPE_TRANSFER_READ_WRITE,
+ 0, 0,
+ pPix->drawable.width,
+ pPix->drawable.height );
+ if (!priv->map_transfer)
+#ifdef EXA_MIXED_PIXMAPS
+ return FALSE;
+#else
+ FatalError("failed to create transfer\n");
+#endif
+
+ pPix->devPrivate.ptr =
+ exa->pipe->transfer_map(exa->pipe, priv->map_transfer);
+ pPix->devKind = priv->map_transfer->stride;
+ }
+
+ priv->map_count++;
+
+ return TRUE;
+}
+
+static void
+ExaFinishAccess(PixmapPtr pPix, int index)
+{
+ ScreenPtr pScreen = pPix->drawable.pScreen;
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct exa_context *exa = ms->exa;
+ struct exa_pixmap_priv *priv;
+ priv = exaGetPixmapDriverPrivate(pPix);
+
+ if (!priv)
+ return;
+
+ if (!priv->map_transfer)
+ return;
+
+ if (--priv->map_count == 0) {
+ assert(priv->map_transfer);
+ exa->pipe->transfer_unmap(exa->pipe, priv->map_transfer);
+ exa->pipe->transfer_destroy(exa->pipe, priv->map_transfer);
+ priv->map_transfer = NULL;
+ pPix->devPrivate.ptr = NULL;
+ }
+}
+
+/***********************************************************************
+ * Solid Fills
+ */
+
+static Bool
+ExaPrepareSolid(PixmapPtr pPixmap, int alu, Pixel planeMask, Pixel fg)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap);
+ struct exa_context *exa = ms->exa;
+
+#if DEBUG_PRINT
+ debug_printf("ExaPrepareSolid(0x%x)\n", fg);
+#endif
+ if (!exa->accel)
+ return FALSE;
+
+ if (!exa->pipe)
+ XORG_FALLBACK("accle not enabled");
+
+ if (!priv || !priv->tex)
+ XORG_FALLBACK("%s", !priv ? "!priv" : "!priv->tex");
+
+ if (!EXA_PM_IS_SOLID(&pPixmap->drawable, planeMask))
+ XORG_FALLBACK("planeMask is not solid");
+
+ if (alu != GXcopy)
+ XORG_FALLBACK("not GXcopy");
+
+ if (!exa->scrn->is_format_supported(exa->scrn, priv->tex->format,
+ priv->tex->target, 0,
+ PIPE_BIND_RENDER_TARGET, 0)) {
+ XORG_FALLBACK("format %s", util_format_name(priv->tex->format));
+ }
+
+ return xorg_solid_bind_state(exa, priv, fg);
+}
+
+static void
+ExaSolid(PixmapPtr pPixmap, int x0, int y0, int x1, int y1)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct exa_context *exa = ms->exa;
+ struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap);
+
+#if DEBUG_PRINT
+ debug_printf("\tExaSolid(%d, %d, %d, %d)\n", x0, y0, x1, y1);
+#endif
+
+ if (x0 == 0 && y0 == 0 &&
+ x1 == pPixmap->drawable.width && y1 == pPixmap->drawable.height) {
+ exa->pipe->clear(exa->pipe, PIPE_CLEAR_COLOR, exa->solid_color, 0.0, 0);
+ return;
+ }
+
+ xorg_solid(exa, priv, x0, y0, x1, y1) ;
+}
+
+
+static void
+ExaDoneSolid(PixmapPtr pPixmap)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap);
+ struct exa_context *exa = ms->exa;
+
+ if (!priv)
+ return;
+
+ xorg_composite_done(exa);
+}
+
+/***********************************************************************
+ * Copy Blits
+ */
+
+static Bool
+ExaPrepareCopy(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int xdir,
+ int ydir, int alu, Pixel planeMask)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct exa_context *exa = ms->exa;
+ struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pDstPixmap);
+ struct exa_pixmap_priv *src_priv = exaGetPixmapDriverPrivate(pSrcPixmap);
+
+#if DEBUG_PRINT
+ debug_printf("ExaPrepareCopy\n");
+#endif
+
+ if (!exa->accel)
+ return FALSE;
+
+ if (!exa->pipe)
+ XORG_FALLBACK("accle not enabled");
+
+ if (!priv || !priv->tex)
+ XORG_FALLBACK("pDst %s", !priv ? "!priv" : "!priv->tex");
+
+ if (!src_priv || !src_priv->tex)
+ XORG_FALLBACK("pSrc %s", !src_priv ? "!priv" : "!priv->tex");
+
+ if (!EXA_PM_IS_SOLID(&pSrcPixmap->drawable, planeMask))
+ XORG_FALLBACK("planeMask is not solid");
+
+ if (alu != GXcopy)
+ XORG_FALLBACK("alu not GXcopy");
+
+ if (!exa->scrn->is_format_supported(exa->scrn, priv->tex->format,
+ priv->tex->target, 0,
+ PIPE_BIND_RENDER_TARGET, 0))
+ XORG_FALLBACK("pDst format %s", util_format_name(priv->tex->format));
+
+ if (!exa->scrn->is_format_supported(exa->scrn, src_priv->tex->format,
+ src_priv->tex->target, 0,
+ PIPE_BIND_SAMPLER_VIEW, 0))
+ XORG_FALLBACK("pSrc format %s", util_format_name(src_priv->tex->format));
+
+ exa->copy.src = src_priv;
+ exa->copy.dst = priv;
+
+ /* XXX this used to use resource_copy_region for same-surface copies,
+ * but they were redefined to not allow overlaps (some of the util code
+ * always assumed this anyway).
+ * Drivers should implement accelerated resource_copy_region or it will
+ * be slow - disable for now.
+ */
+ if (0 && exa->copy.src != exa->copy.dst) {
+ exa->copy.use_surface_copy = TRUE;
+ }
+ else {
+ exa->copy.use_surface_copy = FALSE;
+
+ if (exa->copy.dst == exa->copy.src)
+ exa->copy.src_texture = renderer_clone_texture( exa->renderer,
+ exa->copy.src->tex );
+ else
+ pipe_resource_reference(&exa->copy.src_texture,
+ exa->copy.src->tex);
+
+ exa->copy.dst_surface =
+ exa->scrn->get_tex_surface(exa->scrn,
+ exa->copy.dst->tex,
+ 0, 0, 0,
+ PIPE_BIND_RENDER_TARGET);
+
+
+ renderer_copy_prepare(exa->renderer,
+ exa->copy.dst_surface,
+ exa->copy.src_texture );
+ }
+
+
+ return TRUE;
+}
+
+static void
+ExaCopy(PixmapPtr pDstPixmap, int srcX, int srcY, int dstX, int dstY,
+ int width, int height)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct exa_context *exa = ms->exa;
+ struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pDstPixmap);
+
+#if DEBUG_PRINT
+ debug_printf("\tExaCopy(srcx=%d, srcy=%d, dstX=%d, dstY=%d, w=%d, h=%d)\n",
+ srcX, srcY, dstX, dstY, width, height);
+#endif
+
+ debug_assert(priv == exa->copy.dst);
+ (void) priv;
+
+ if (exa->copy.use_surface_copy) {
+ struct pipe_subresource subdst, subsrc;
+ subdst.face = 0;
+ subdst.level = 0;
+ subsrc.face = 0;
+ subsrc.level = 0;
+ exa->pipe->resource_copy_region( exa->pipe,
+ exa->copy.dst->tex,
+ subdst,
+ dstX, dstY, 0,
+ exa->copy.src->tex,
+ subsrc,
+ srcX, srcY, 0,
+ width, height );
+ }
+ else {
+ renderer_copy_pixmap(exa->renderer,
+ dstX, dstY,
+ srcX, srcY,
+ width, height,
+ exa->copy.src_texture->width0,
+ exa->copy.src_texture->height0);
+ }
+}
+
+static void
+ExaDoneCopy(PixmapPtr pPixmap)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap);
+ struct exa_context *exa = ms->exa;
+
+ if (!priv)
+ return;
+
+ renderer_draw_flush(exa->renderer);
+
+ exa->copy.src = NULL;
+ exa->copy.dst = NULL;
+ pipe_surface_reference(&exa->copy.dst_surface, NULL);
+ pipe_resource_reference(&exa->copy.src_texture, NULL);
+}
+
+
+
+static Bool
+picture_check_formats(struct exa_pixmap_priv *pSrc, PicturePtr pSrcPicture)
+{
+ if (pSrc->picture_format == pSrcPicture->format)
+ return TRUE;
+
+ if (pSrc->picture_format != PICT_a8r8g8b8)
+ return FALSE;
+
+ /* pSrc->picture_format == PICT_a8r8g8b8 */
+ switch (pSrcPicture->format) {
+ case PICT_a8r8g8b8:
+ case PICT_x8r8g8b8:
+ case PICT_a8b8g8r8:
+ case PICT_x8b8g8r8:
+ /* just treat these two as x8... */
+ case PICT_r8g8b8:
+ case PICT_b8g8r8:
+ return TRUE;
+#ifdef PICT_TYPE_BGRA
+ case PICT_b8g8r8a8:
+ case PICT_b8g8r8x8:
+ return FALSE; /* does not support swizzleing the alpha channel yet */
+ case PICT_a2r10g10b10:
+ case PICT_x2r10g10b10:
+ case PICT_a2b10g10r10:
+ case PICT_x2b10g10r10:
+ return FALSE;
+#endif
+ default:
+ return FALSE;
+ }
+ return FALSE;
+}
+
+/***********************************************************************
+ * Composite entrypoints
+ */
+
+static Bool
+ExaCheckComposite(int op,
+ PicturePtr pSrcPicture, PicturePtr pMaskPicture,
+ PicturePtr pDstPicture)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pDstPicture->pDrawable->pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct exa_context *exa = ms->exa;
+
+#if DEBUG_PRINT
+ debug_printf("ExaCheckComposite(%d, %p, %p, %p) = %d\n",
+ op, pSrcPicture, pMaskPicture, pDstPicture, accelerated);
+#endif
+
+ if (!exa->accel)
+ return FALSE;
+
+ return xorg_composite_accelerated(op,
+ pSrcPicture,
+ pMaskPicture,
+ pDstPicture);
+}
+
+
+static Bool
+ExaPrepareComposite(int op, PicturePtr pSrcPicture,
+ PicturePtr pMaskPicture, PicturePtr pDstPicture,
+ PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct exa_context *exa = ms->exa;
+ struct exa_pixmap_priv *priv;
+
+ if (!exa->accel)
+ return FALSE;
+
+#if DEBUG_PRINT
+ debug_printf("ExaPrepareComposite(%d, src=0x%p, mask=0x%p, dst=0x%p)\n",
+ op, pSrcPicture, pMaskPicture, pDstPicture);
+ debug_printf("\tFormats: src(%s), mask(%s), dst(%s)\n",
+ pSrcPicture ? render_format_name(pSrcPicture->format) : "none",
+ pMaskPicture ? render_format_name(pMaskPicture->format) : "none",
+ pDstPicture ? render_format_name(pDstPicture->format) : "none");
+#endif
+ if (!exa->pipe)
+ XORG_FALLBACK("accle not enabled");
+
+ priv = exaGetPixmapDriverPrivate(pDst);
+ if (!priv || !priv->tex)
+ XORG_FALLBACK("pDst %s", !priv ? "!priv" : "!priv->tex");
+
+ if (!exa->scrn->is_format_supported(exa->scrn, priv->tex->format,
+ priv->tex->target, 0,
+ PIPE_BIND_RENDER_TARGET, 0))
+ XORG_FALLBACK("pDst format: %s", util_format_name(priv->tex->format));
+
+ if (priv->picture_format != pDstPicture->format)
+ XORG_FALLBACK("pDst pic_format: %s != %s",
+ render_format_name(priv->picture_format),
+ render_format_name(pDstPicture->format));
+
+ if (pSrc) {
+ priv = exaGetPixmapDriverPrivate(pSrc);
+ if (!priv || !priv->tex)
+ XORG_FALLBACK("pSrc %s", !priv ? "!priv" : "!priv->tex");
+
+ if (!exa->scrn->is_format_supported(exa->scrn, priv->tex->format,
+ priv->tex->target, 0,
+ PIPE_BIND_SAMPLER_VIEW, 0))
+ XORG_FALLBACK("pSrc format: %s", util_format_name(priv->tex->format));
+
+ if (!picture_check_formats(priv, pSrcPicture))
+ XORG_FALLBACK("pSrc pic_format: %s != %s",
+ render_format_name(priv->picture_format),
+ render_format_name(pSrcPicture->format));
+
+ }
+
+ if (pMask) {
+ priv = exaGetPixmapDriverPrivate(pMask);
+ if (!priv || !priv->tex)
+ XORG_FALLBACK("pMask %s", !priv ? "!priv" : "!priv->tex");
+
+ if (!exa->scrn->is_format_supported(exa->scrn, priv->tex->format,
+ priv->tex->target, 0,
+ PIPE_BIND_SAMPLER_VIEW, 0))
+ XORG_FALLBACK("pMask format: %s", util_format_name(priv->tex->format));
+
+ if (!picture_check_formats(priv, pMaskPicture))
+ XORG_FALLBACK("pMask pic_format: %s != %s",
+ render_format_name(priv->picture_format),
+ render_format_name(pMaskPicture->format));
+ }
+
+ return xorg_composite_bind_state(exa, op, pSrcPicture, pMaskPicture,
+ pDstPicture,
+ pSrc ? exaGetPixmapDriverPrivate(pSrc) : NULL,
+ pMask ? exaGetPixmapDriverPrivate(pMask) : NULL,
+ exaGetPixmapDriverPrivate(pDst));
+}
+
+static void
+ExaComposite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY,
+ int dstX, int dstY, int width, int height)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct exa_context *exa = ms->exa;
+ struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pDst);
+
+#if DEBUG_PRINT
+ debug_printf("\tExaComposite(src[%d,%d], mask=[%d, %d], dst=[%d, %d], dim=[%d, %d])\n",
+ srcX, srcY, maskX, maskY, dstX, dstY, width, height);
+ debug_printf("\t Num bound samplers = %d\n",
+ exa->num_bound_samplers);
+#endif
+
+ xorg_composite(exa, priv, srcX, srcY, maskX, maskY,
+ dstX, dstY, width, height);
+}
+
+
+
+static void
+ExaDoneComposite(PixmapPtr pPixmap)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct exa_context *exa = ms->exa;
+
+ xorg_composite_done(exa);
+}
+
+
+/***********************************************************************
+ * Pixmaps
+ */
+
+static void *
+ExaCreatePixmap(ScreenPtr pScreen, int size, int align)
+{
+ struct exa_pixmap_priv *priv;
+
+ priv = xcalloc(1, sizeof(struct exa_pixmap_priv));
+ if (!priv)
+ return NULL;
+
+ return priv;
+}
+
+static void
+ExaDestroyPixmap(ScreenPtr pScreen, void *dPriv)
+{
+ struct exa_pixmap_priv *priv = (struct exa_pixmap_priv *)dPriv;
+
+ if (!priv)
+ return;
+
+ pipe_resource_reference(&priv->tex, NULL);
+
+ xfree(priv);
+}
+
+static Bool
+ExaPixmapIsOffscreen(PixmapPtr pPixmap)
+{
+ struct exa_pixmap_priv *priv;
+
+ priv = exaGetPixmapDriverPrivate(pPixmap);
+
+ if (!priv)
+ return FALSE;
+
+ if (priv->tex)
+ return TRUE;
+
+ return FALSE;
+}
+
+int
+xorg_exa_set_displayed_usage(PixmapPtr pPixmap)
+{
+ struct exa_pixmap_priv *priv;
+ priv = exaGetPixmapDriverPrivate(pPixmap);
+
+ if (!priv) {
+ FatalError("NO PIXMAP PRIVATE\n");
+ return 0;
+ }
+
+ priv->flags |= PIPE_BIND_SCANOUT;
+
+ return 0;
+}
+
+int
+xorg_exa_set_shared_usage(PixmapPtr pPixmap)
+{
+ struct exa_pixmap_priv *priv;
+ priv = exaGetPixmapDriverPrivate(pPixmap);
+
+ if (!priv) {
+ FatalError("NO PIXMAP PRIVATE\n");
+ return 0;
+ }
+
+ priv->flags |= PIPE_BIND_SHARED;
+
+ return 0;
+}
+
+
+
+static Bool
+size_match( int width, int tex_width )
+{
+#if ROUND_UP_TEXTURES
+ if (width > tex_width)
+ return FALSE;
+
+ if (width * 2 < tex_width)
+ return FALSE;
+
+ return TRUE;
+#else
+ return width == tex_width;
+#endif
+}
+
+static Bool
+ExaModifyPixmapHeader(PixmapPtr pPixmap, int width, int height,
+ int depth, int bitsPerPixel, int devKind,
+ pointer pPixData)
+{
+ ScreenPtr pScreen = pPixmap->drawable.pScreen;
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap);
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct exa_context *exa = ms->exa;
+
+ if (!priv || pPixData)
+ return FALSE;
+
+ if (0) {
+ debug_printf("%s pixmap %p sz %dx%dx%d devKind %d\n",
+ __FUNCTION__, pPixmap, width, height, bitsPerPixel, devKind);
+
+ if (priv->tex)
+ debug_printf(" ==> old texture %dx%d\n",
+ priv->tex->width0,
+ priv->tex->height0);
+ }
+
+
+ if (depth <= 0)
+ depth = pPixmap->drawable.depth;
+
+ if (bitsPerPixel <= 0)
+ bitsPerPixel = pPixmap->drawable.bitsPerPixel;
+
+ if (width <= 0)
+ width = pPixmap->drawable.width;
+
+ if (height <= 0)
+ height = pPixmap->drawable.height;
+
+ if (width <= 0 || height <= 0 || depth <= 0)
+ return FALSE;
+
+ miModifyPixmapHeader(pPixmap, width, height, depth,
+ bitsPerPixel, devKind, NULL);
+
+ priv->width = width;
+ priv->height = height;
+
+ /* Deal with screen resize */
+ if ((exa->accel || priv->flags) &&
+ (!priv->tex ||
+ !size_match(width, priv->tex->width0) ||
+ !size_match(height, priv->tex->height0) ||
+ priv->tex_flags != priv->flags)) {
+ struct pipe_resource *texture = NULL;
+ struct pipe_resource template;
+
+ memset(&template, 0, sizeof(template));
+ template.target = PIPE_TEXTURE_2D;
+ exa_get_pipe_format(depth, &template.format, &bitsPerPixel, &priv->picture_format);
+ if (ROUND_UP_TEXTURES && priv->flags == 0) {
+ template.width0 = util_next_power_of_two(width);
+ template.height0 = util_next_power_of_two(height);
+ }
+ else {
+ template.width0 = width;
+ template.height0 = height;
+ }
+
+ template.depth0 = 1;
+ template.last_level = 0;
+ template.bind = PIPE_BIND_RENDER_TARGET | priv->flags;
+ priv->tex_flags = priv->flags;
+ texture = exa->scrn->resource_create(exa->scrn, &template);
+
+ if (priv->tex) {
+ struct pipe_subresource subdst, subsrc;
+ struct pipe_surface *src_surf;
+
+ subdst.face = 0;
+ subdst.level = 0;
+ subsrc.face = 0;
+ subsrc.level = 0;
+ exa->pipe->resource_copy_region(exa->pipe, texture,
+ subdst, 0, 0, 0,
+ priv->tex,
+ subsrc, 0, 0, 0,
+ min(width, texture->width0),
+ min(height, texture->height0));
+ }
+
+ pipe_resource_reference(&priv->tex, texture);
+ /* the texture we create has one reference */
+ pipe_resource_reference(&texture, NULL);
+ }
+
+ return TRUE;
+}
+
+struct pipe_resource *
+xorg_exa_get_texture(PixmapPtr pPixmap)
+{
+ struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap);
+ struct pipe_resource *tex = NULL;
+ pipe_resource_reference(&tex, priv->tex);
+ return tex;
+}
+
+Bool
+xorg_exa_set_texture(PixmapPtr pPixmap, struct pipe_resource *tex)
+{
+ struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap);
+
+ int mask = PIPE_BIND_SHARED | PIPE_BIND_SCANOUT;
+
+ if (!priv)
+ return FALSE;
+
+ if (pPixmap->drawable.width != tex->width0 ||
+ pPixmap->drawable.height != tex->height0)
+ return FALSE;
+
+ pipe_resource_reference(&priv->tex, tex);
+ priv->tex_flags = tex->bind & mask;
+
+ return TRUE;
+}
+
+struct pipe_resource *
+xorg_exa_create_root_texture(ScrnInfoPtr pScrn,
+ int width, int height,
+ int depth, int bitsPerPixel)
+{
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct exa_context *exa = ms->exa;
+ struct pipe_resource template;
+ int dummy;
+
+ memset(&template, 0, sizeof(template));
+ template.target = PIPE_TEXTURE_2D;
+ exa_get_pipe_format(depth, &template.format, &bitsPerPixel, &dummy);
+ template.width0 = width;
+ template.height0 = height;
+ template.depth0 = 1;
+ template.last_level = 0;
+ template.bind |= PIPE_BIND_RENDER_TARGET;
+ template.bind |= PIPE_BIND_SCANOUT;
+ template.bind |= PIPE_BIND_SHARED;
+
+ return exa->scrn->resource_create(exa->scrn, &template);
+}
+
+void
+xorg_exa_close(ScrnInfoPtr pScrn)
+{
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct exa_context *exa = ms->exa;
+
+ pipe_sampler_view_reference(&exa->bound_sampler_views[0], NULL);
+ pipe_sampler_view_reference(&exa->bound_sampler_views[1], NULL);
+
+ renderer_destroy(exa->renderer);
+
+ xorg_exa_finish(exa);
+
+ if (exa->pipe)
+ exa->pipe->destroy(exa->pipe);
+ exa->pipe = NULL;
+ /* Since this was shared be proper with the pointer */
+ ms->ctx = NULL;
+
+ exaDriverFini(pScrn->pScreen);
+ xfree(exa);
+ ms->exa = NULL;
+}
+
+void *
+xorg_exa_init(ScrnInfoPtr pScrn, Bool accel)
+{
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct exa_context *exa;
+ ExaDriverPtr pExa;
+ CustomizerPtr cust = ms->cust;
+
+ exa = xcalloc(1, sizeof(struct exa_context));
+ if (!exa)
+ return NULL;
+
+ pExa = exaDriverAlloc();
+ if (!pExa) {
+ goto out_err;
+ }
+
+ memset(pExa, 0, sizeof(*pExa));
+
+ pExa->exa_major = 2;
+ pExa->exa_minor = 2;
+ pExa->memoryBase = 0;
+ pExa->memorySize = 0;
+ pExa->offScreenBase = 0;
+ pExa->pixmapOffsetAlign = 0;
+ pExa->pixmapPitchAlign = 1;
+ pExa->flags = EXA_OFFSCREEN_PIXMAPS | EXA_HANDLES_PIXMAPS;
+#ifdef EXA_SUPPORTS_PREPARE_AUX
+ pExa->flags |= EXA_SUPPORTS_PREPARE_AUX;
+#endif
+#ifdef EXA_MIXED_PIXMAPS
+ pExa->flags |= EXA_MIXED_PIXMAPS;
+#endif
+ pExa->maxX = 8191; /* FIXME */
+ pExa->maxY = 8191; /* FIXME */
+
+ pExa->WaitMarker = ExaWaitMarker;
+ pExa->MarkSync = ExaMarkSync;
+ pExa->PrepareSolid = ExaPrepareSolid;
+ pExa->Solid = ExaSolid;
+ pExa->DoneSolid = ExaDoneSolid;
+ pExa->PrepareCopy = ExaPrepareCopy;
+ pExa->Copy = ExaCopy;
+ pExa->DoneCopy = ExaDoneCopy;
+ pExa->CheckComposite = ExaCheckComposite;
+ pExa->PrepareComposite = ExaPrepareComposite;
+ pExa->Composite = ExaComposite;
+ pExa->DoneComposite = ExaDoneComposite;
+ pExa->PixmapIsOffscreen = ExaPixmapIsOffscreen;
+ pExa->DownloadFromScreen = ExaDownloadFromScreen;
+ pExa->UploadToScreen = ExaUploadToScreen;
+ pExa->PrepareAccess = ExaPrepareAccess;
+ pExa->FinishAccess = ExaFinishAccess;
+ pExa->CreatePixmap = ExaCreatePixmap;
+ pExa->DestroyPixmap = ExaDestroyPixmap;
+ pExa->ModifyPixmapHeader = ExaModifyPixmapHeader;
+
+ if (!exaDriverInit(pScrn->pScreen, pExa)) {
+ goto out_err;
+ }
+
+ exa->scrn = ms->screen;
+ exa->pipe = exa->scrn->context_create(exa->scrn, NULL);
+ if (exa->pipe == NULL)
+ goto out_err;
+
+ /* Share context with DRI */
+ ms->ctx = exa->pipe;
+ if (cust && cust->winsys_context_throttle)
+ cust->winsys_context_throttle(cust, ms->ctx, THROTTLE_RENDER);
+
+ exa->renderer = renderer_create(exa->pipe);
+ exa->accel = accel;
+
+ return (void *)exa;
+
+out_err:
+ xorg_exa_close(pScrn);
+
+ return NULL;
+}
+
+struct pipe_surface *
+xorg_gpu_surface(struct pipe_screen *scrn, struct exa_pixmap_priv *priv)
+{
+ return scrn->get_tex_surface(scrn, priv->tex, 0, 0, 0,
+ PIPE_BIND_RENDER_TARGET);
+
+}
+
+void xorg_exa_flush(struct exa_context *exa, uint pipeFlushFlags,
+ struct pipe_fence_handle **fence)
+{
+ exa->pipe->flush(exa->pipe, pipeFlushFlags, fence);
+}
+
+void xorg_exa_finish(struct exa_context *exa)
+{
+ struct pipe_fence_handle *fence = NULL;
+
+ xorg_exa_flush(exa, PIPE_FLUSH_RENDER_CACHE, &fence);
+
+ exa->pipe->screen->fence_finish(exa->pipe->screen, fence, 0);
+ exa->pipe->screen->fence_reference(exa->pipe->screen, &fence, NULL);
+}
+
diff --git a/src/gallium/state_trackers/xorg/xorg_exa.h b/src/gallium/state_trackers/xorg/xorg_exa.h
new file mode 100644
index 0000000000..86a1afc06e
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xorg_exa.h
@@ -0,0 +1,81 @@
+#ifndef XORG_EXA_H
+#define XORG_EXA_H
+
+#include "xorg_tracker.h"
+
+#include <pipe/p_state.h>
+
+struct cso_context;
+struct xorg_shaders;
+
+/* src + mask + dst */
+#define MAX_EXA_SAMPLERS 3
+
+struct exa_context
+{
+ ExaDriverPtr pExa;
+ struct pipe_context *pipe;
+ struct pipe_screen *scrn;
+ struct xorg_renderer *renderer;
+
+ struct pipe_sampler_view *bound_sampler_views[MAX_EXA_SAMPLERS];
+ int num_bound_samplers;
+
+ float solid_color[4];
+ boolean has_solid_color;
+
+ boolean accel;
+
+ /* float[9] projective matrix bound to pictures */
+ struct {
+ float src[9];
+ float mask[9];
+ boolean has_src;
+ boolean has_mask;
+ } transform;
+
+ struct {
+ boolean use_surface_copy;
+
+ struct exa_pixmap_priv *src;
+ struct exa_pixmap_priv *dst;
+
+ struct pipe_surface *dst_surface;
+
+ struct pipe_resource *src_texture;
+ } copy;
+};
+
+struct exa_pixmap_priv
+{
+ int width, height;
+
+ int flags;
+ int tex_flags;
+
+ int picture_format;
+
+ struct pipe_resource *tex;
+ struct pipe_resource *depth_stencil_tex;
+
+ struct pipe_transfer *map_transfer;
+ unsigned map_count;
+};
+
+#define XORG_FALLBACK(s, arg...) \
+do { \
+ if (ms->debug_fallback) { \
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, \
+ "%s fallback " s "\n", __FUNCTION__, ##arg); \
+ } \
+ return FALSE; \
+} while(0)
+
+struct pipe_surface *
+xorg_gpu_surface(struct pipe_screen *scrn, struct exa_pixmap_priv *priv);
+
+void xorg_exa_flush(struct exa_context *exa, uint pipeFlushFlags,
+ struct pipe_fence_handle **fence);
+void xorg_exa_finish(struct exa_context *exa);
+
+#endif
diff --git a/src/gallium/state_trackers/xorg/xorg_exa_tgsi.c b/src/gallium/state_trackers/xorg/xorg_exa_tgsi.c
new file mode 100644
index 0000000000..3e5e6bd6a6
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xorg_exa_tgsi.c
@@ -0,0 +1,690 @@
+#include "xorg_exa_tgsi.h"
+
+/*### stupidity defined in X11/extensions/XI.h */
+#undef Absolute
+
+#include "pipe/p_format.h"
+#include "pipe/p_context.h"
+#include "pipe/p_state.h"
+#include "pipe/p_shader_tokens.h"
+
+#include "util/u_memory.h"
+
+#include "tgsi/tgsi_ureg.h"
+
+#include "cso_cache/cso_context.h"
+#include "cso_cache/cso_hash.h"
+
+/* Vertex shader:
+ * IN[0] = vertex pos
+ * IN[1] = src tex coord | solid fill color
+ * IN[2] = mask tex coord
+ * IN[3] = dst tex coord
+ * CONST[0] = (2/dst_width, 2/dst_height, 1, 1)
+ * CONST[1] = (-1, -1, 0, 0)
+ *
+ * OUT[0] = vertex pos
+ * OUT[1] = src tex coord | solid fill color
+ * OUT[2] = mask tex coord
+ * OUT[3] = dst tex coord
+ */
+
+/* Fragment shader:
+ * SAMP[0] = src
+ * SAMP[1] = mask
+ * SAMP[2] = dst
+ * IN[0] = pos src | solid fill color
+ * IN[1] = pos mask
+ * IN[2] = pos dst
+ * CONST[0] = (0, 0, 0, 1)
+ *
+ * OUT[0] = color
+ */
+
+static void
+print_fs_traits(int fs_traits)
+{
+ const char *strings[] = {
+ "FS_COMPOSITE", /* = 1 << 0, */
+ "FS_MASK", /* = 1 << 1, */
+ "FS_SOLID_FILL", /* = 1 << 2, */
+ "FS_LINGRAD_FILL", /* = 1 << 3, */
+ "FS_RADGRAD_FILL", /* = 1 << 4, */
+ "FS_CA_FULL", /* = 1 << 5, */ /* src.rgba * mask.rgba */
+ "FS_CA_SRCALPHA", /* = 1 << 6, */ /* src.aaaa * mask.rgba */
+ "FS_YUV", /* = 1 << 7, */
+ "FS_SRC_REPEAT_NONE", /* = 1 << 8, */
+ "FS_MASK_REPEAT_NONE",/* = 1 << 9, */
+ "FS_SRC_SWIZZLE_RGB", /* = 1 << 10, */
+ "FS_MASK_SWIZZLE_RGB",/* = 1 << 11, */
+ "FS_SRC_SET_ALPHA", /* = 1 << 12, */
+ "FS_MASK_SET_ALPHA", /* = 1 << 13, */
+ "FS_SRC_LUMINANCE", /* = 1 << 14, */
+ "FS_MASK_LUMINANCE", /* = 1 << 15, */
+ };
+ int i, k;
+ debug_printf("%s: ", __func__);
+
+ for (i = 0, k = 1; k < (1 << 16); i++, k <<= 1) {
+ if (fs_traits & k)
+ debug_printf("%s, ", strings[i]);
+ }
+
+ debug_printf("\n");
+}
+
+struct xorg_shaders {
+ struct xorg_renderer *r;
+
+ struct cso_hash *vs_hash;
+ struct cso_hash *fs_hash;
+};
+
+static INLINE void
+src_in_mask(struct ureg_program *ureg,
+ struct ureg_dst dst,
+ struct ureg_src src,
+ struct ureg_src mask,
+ unsigned component_alpha,
+ unsigned mask_luminance)
+{
+ if (component_alpha == FS_CA_FULL) {
+ ureg_MUL(ureg, dst, src, mask);
+ } else if (component_alpha == FS_CA_SRCALPHA) {
+ ureg_MUL(ureg, dst,
+ ureg_scalar(src, TGSI_SWIZZLE_W), mask);
+ }
+ else {
+ if (mask_luminance)
+ ureg_MUL(ureg, dst, src,
+ ureg_scalar(mask, TGSI_SWIZZLE_X));
+ else
+ ureg_MUL(ureg, dst, src,
+ ureg_scalar(mask, TGSI_SWIZZLE_W));
+ }
+}
+
+static struct ureg_src
+vs_normalize_coords(struct ureg_program *ureg, struct ureg_src coords,
+ struct ureg_src const0, struct ureg_src const1)
+{
+ struct ureg_dst tmp = ureg_DECL_temporary(ureg);
+ struct ureg_src ret;
+ ureg_MAD(ureg, tmp, coords, const0, const1);
+ ret = ureg_src(tmp);
+ ureg_release_temporary(ureg, tmp);
+ return ret;
+}
+
+static void
+linear_gradient(struct ureg_program *ureg,
+ struct ureg_dst out,
+ struct ureg_src pos,
+ struct ureg_src sampler,
+ struct ureg_src coords,
+ struct ureg_src const0124,
+ struct ureg_src matrow0,
+ struct ureg_src matrow1,
+ struct ureg_src matrow2)
+{
+ struct ureg_dst temp0 = ureg_DECL_temporary(ureg);
+ struct ureg_dst temp1 = ureg_DECL_temporary(ureg);
+ struct ureg_dst temp2 = ureg_DECL_temporary(ureg);
+ struct ureg_dst temp3 = ureg_DECL_temporary(ureg);
+ struct ureg_dst temp4 = ureg_DECL_temporary(ureg);
+ struct ureg_dst temp5 = ureg_DECL_temporary(ureg);
+
+ ureg_MOV(ureg,
+ ureg_writemask(temp0, TGSI_WRITEMASK_XY), pos);
+ ureg_MOV(ureg,
+ ureg_writemask(temp0, TGSI_WRITEMASK_Z),
+ ureg_scalar(const0124, TGSI_SWIZZLE_Y));
+
+ ureg_DP3(ureg, temp1, matrow0, ureg_src(temp0));
+ ureg_DP3(ureg, temp2, matrow1, ureg_src(temp0));
+ ureg_DP3(ureg, temp3, matrow2, ureg_src(temp0));
+ ureg_RCP(ureg, temp3, ureg_src(temp3));
+ ureg_MUL(ureg, temp1, ureg_src(temp1), ureg_src(temp3));
+ ureg_MUL(ureg, temp2, ureg_src(temp2), ureg_src(temp3));
+
+ ureg_MOV(ureg, ureg_writemask(temp4, TGSI_WRITEMASK_X),
+ ureg_src(temp1));
+ ureg_MOV(ureg, ureg_writemask(temp4, TGSI_WRITEMASK_Y),
+ ureg_src(temp2));
+
+ ureg_MUL(ureg, temp0,
+ ureg_scalar(coords, TGSI_SWIZZLE_Y),
+ ureg_scalar(ureg_src(temp4), TGSI_SWIZZLE_Y));
+ ureg_MAD(ureg, temp1,
+ ureg_scalar(coords, TGSI_SWIZZLE_X),
+ ureg_scalar(ureg_src(temp4), TGSI_SWIZZLE_X),
+ ureg_src(temp0));
+
+ ureg_MUL(ureg, temp2,
+ ureg_src(temp1),
+ ureg_scalar(coords, TGSI_SWIZZLE_Z));
+
+ ureg_TEX(ureg, out,
+ TGSI_TEXTURE_1D, ureg_src(temp2), sampler);
+
+ ureg_release_temporary(ureg, temp0);
+ ureg_release_temporary(ureg, temp1);
+ ureg_release_temporary(ureg, temp2);
+ ureg_release_temporary(ureg, temp3);
+ ureg_release_temporary(ureg, temp4);
+ ureg_release_temporary(ureg, temp5);
+}
+
+
+static void
+radial_gradient(struct ureg_program *ureg,
+ struct ureg_dst out,
+ struct ureg_src pos,
+ struct ureg_src sampler,
+ struct ureg_src coords,
+ struct ureg_src const0124,
+ struct ureg_src matrow0,
+ struct ureg_src matrow1,
+ struct ureg_src matrow2)
+{
+ struct ureg_dst temp0 = ureg_DECL_temporary(ureg);
+ struct ureg_dst temp1 = ureg_DECL_temporary(ureg);
+ struct ureg_dst temp2 = ureg_DECL_temporary(ureg);
+ struct ureg_dst temp3 = ureg_DECL_temporary(ureg);
+ struct ureg_dst temp4 = ureg_DECL_temporary(ureg);
+ struct ureg_dst temp5 = ureg_DECL_temporary(ureg);
+
+ ureg_MOV(ureg,
+ ureg_writemask(temp0, TGSI_WRITEMASK_XY),
+ pos);
+ ureg_MOV(ureg,
+ ureg_writemask(temp0, TGSI_WRITEMASK_Z),
+ ureg_scalar(const0124, TGSI_SWIZZLE_Y));
+
+ ureg_DP3(ureg, temp1, matrow0, ureg_src(temp0));
+ ureg_DP3(ureg, temp2, matrow1, ureg_src(temp0));
+ ureg_DP3(ureg, temp3, matrow2, ureg_src(temp0));
+ ureg_RCP(ureg, temp3, ureg_src(temp3));
+ ureg_MUL(ureg, temp1, ureg_src(temp1), ureg_src(temp3));
+ ureg_MUL(ureg, temp2, ureg_src(temp2), ureg_src(temp3));
+
+ ureg_MOV(ureg, ureg_writemask(temp5, TGSI_WRITEMASK_X),
+ ureg_src(temp1));
+ ureg_MOV(ureg, ureg_writemask(temp5, TGSI_WRITEMASK_Y),
+ ureg_src(temp2));
+
+ ureg_MUL(ureg, temp0, ureg_scalar(coords, TGSI_SWIZZLE_Y),
+ ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_Y));
+ ureg_MAD(ureg, temp1,
+ ureg_scalar(coords, TGSI_SWIZZLE_X),
+ ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_X),
+ ureg_src(temp0));
+ ureg_ADD(ureg, temp1,
+ ureg_src(temp1), ureg_src(temp1));
+ ureg_MUL(ureg, temp3,
+ ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_Y),
+ ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_Y));
+ ureg_MAD(ureg, temp4,
+ ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_X),
+ ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_X),
+ ureg_src(temp3));
+ ureg_MOV(ureg, temp4, ureg_negate(ureg_src(temp4)));
+ ureg_MUL(ureg, temp2,
+ ureg_scalar(coords, TGSI_SWIZZLE_Z),
+ ureg_src(temp4));
+ ureg_MUL(ureg, temp0,
+ ureg_scalar(const0124, TGSI_SWIZZLE_W),
+ ureg_src(temp2));
+ ureg_MUL(ureg, temp3,
+ ureg_src(temp1), ureg_src(temp1));
+ ureg_SUB(ureg, temp2,
+ ureg_src(temp3), ureg_src(temp0));
+ ureg_RSQ(ureg, temp2, ureg_abs(ureg_src(temp2)));
+ ureg_RCP(ureg, temp2, ureg_src(temp2));
+ ureg_SUB(ureg, temp1,
+ ureg_src(temp2), ureg_src(temp1));
+ ureg_ADD(ureg, temp0,
+ ureg_scalar(coords, TGSI_SWIZZLE_Z),
+ ureg_scalar(coords, TGSI_SWIZZLE_Z));
+ ureg_RCP(ureg, temp0, ureg_src(temp0));
+ ureg_MUL(ureg, temp2,
+ ureg_src(temp1), ureg_src(temp0));
+ ureg_TEX(ureg, out, TGSI_TEXTURE_1D,
+ ureg_src(temp2), sampler);
+
+ ureg_release_temporary(ureg, temp0);
+ ureg_release_temporary(ureg, temp1);
+ ureg_release_temporary(ureg, temp2);
+ ureg_release_temporary(ureg, temp3);
+ ureg_release_temporary(ureg, temp4);
+ ureg_release_temporary(ureg, temp5);
+}
+
+static void *
+create_vs(struct pipe_context *pipe,
+ unsigned vs_traits)
+{
+ struct ureg_program *ureg;
+ struct ureg_src src;
+ struct ureg_dst dst;
+ struct ureg_src const0, const1;
+ boolean is_fill = (vs_traits & VS_FILL) != 0;
+ boolean is_composite = (vs_traits & VS_COMPOSITE) != 0;
+ boolean has_mask = (vs_traits & VS_MASK) != 0;
+ boolean is_yuv = (vs_traits & VS_YUV) != 0;
+ unsigned input_slot = 0;
+
+ ureg = ureg_create(TGSI_PROCESSOR_VERTEX);
+ if (ureg == NULL)
+ return 0;
+
+ const0 = ureg_DECL_constant(ureg, 0);
+ const1 = ureg_DECL_constant(ureg, 1);
+
+ /* it has to be either a fill or a composite op */
+ debug_assert((is_fill ^ is_composite) ^ is_yuv);
+
+ src = ureg_DECL_vs_input(ureg, input_slot++);
+ dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0);
+ src = vs_normalize_coords(ureg, src,
+ const0, const1);
+ ureg_MOV(ureg, dst, src);
+
+ if (is_yuv) {
+ src = ureg_DECL_vs_input(ureg, input_slot++);
+ dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 0);
+ ureg_MOV(ureg, dst, src);
+ }
+
+ if (is_composite) {
+ src = ureg_DECL_vs_input(ureg, input_slot++);
+ dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 0);
+ ureg_MOV(ureg, dst, src);
+ }
+
+ if (is_fill) {
+ src = ureg_DECL_vs_input(ureg, input_slot++);
+ dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0);
+ ureg_MOV(ureg, dst, src);
+ }
+
+ if (has_mask) {
+ src = ureg_DECL_vs_input(ureg, input_slot++);
+ dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 1);
+ ureg_MOV(ureg, dst, src);
+ }
+
+ ureg_END(ureg);
+
+ return ureg_create_shader_and_destroy(ureg, pipe);
+}
+
+static void *
+create_yuv_shader(struct pipe_context *pipe, struct ureg_program *ureg)
+{
+ struct ureg_src y_sampler, u_sampler, v_sampler;
+ struct ureg_src pos;
+ struct ureg_src matrow0, matrow1, matrow2;
+ struct ureg_dst y, u, v, rgb;
+ struct ureg_dst out = ureg_DECL_output(ureg,
+ TGSI_SEMANTIC_COLOR,
+ 0);
+
+ pos = ureg_DECL_fs_input(ureg,
+ TGSI_SEMANTIC_GENERIC,
+ 0,
+ TGSI_INTERPOLATE_PERSPECTIVE);
+
+ rgb = ureg_DECL_temporary(ureg);
+ y = ureg_DECL_temporary(ureg);
+ u = ureg_DECL_temporary(ureg);
+ v = ureg_DECL_temporary(ureg);
+
+ y_sampler = ureg_DECL_sampler(ureg, 0);
+ u_sampler = ureg_DECL_sampler(ureg, 1);
+ v_sampler = ureg_DECL_sampler(ureg, 2);
+
+ matrow0 = ureg_DECL_constant(ureg, 0);
+ matrow1 = ureg_DECL_constant(ureg, 1);
+ matrow2 = ureg_DECL_constant(ureg, 2);
+
+ ureg_TEX(ureg, y,
+ TGSI_TEXTURE_2D, pos, y_sampler);
+ ureg_TEX(ureg, u,
+ TGSI_TEXTURE_2D, pos, u_sampler);
+ ureg_TEX(ureg, v,
+ TGSI_TEXTURE_2D, pos, v_sampler);
+
+ ureg_SUB(ureg, u, ureg_src(u),
+ ureg_scalar(matrow0, TGSI_SWIZZLE_W));
+ ureg_SUB(ureg, v, ureg_src(v),
+ ureg_scalar(matrow0, TGSI_SWIZZLE_W));
+
+ ureg_MUL(ureg, rgb,
+ ureg_scalar(ureg_src(y), TGSI_SWIZZLE_X),
+ matrow0);
+ ureg_MAD(ureg, rgb,
+ ureg_scalar(ureg_src(u), TGSI_SWIZZLE_X),
+ matrow1,
+ ureg_src(rgb));
+ ureg_MAD(ureg, rgb,
+ ureg_scalar(ureg_src(v), TGSI_SWIZZLE_X),
+ matrow2,
+ ureg_src(rgb));
+
+ /* rgb.a = 1; */
+ ureg_MOV(ureg, ureg_writemask(rgb, TGSI_WRITEMASK_W),
+ ureg_scalar(matrow0, TGSI_SWIZZLE_X));
+
+ ureg_MOV(ureg, out, ureg_src(rgb));
+
+ ureg_release_temporary(ureg, rgb);
+ ureg_release_temporary(ureg, y);
+ ureg_release_temporary(ureg, u);
+ ureg_release_temporary(ureg, v);
+
+ ureg_END(ureg);
+
+ return ureg_create_shader_and_destroy(ureg, pipe);
+}
+
+
+static INLINE void
+xrender_tex(struct ureg_program *ureg,
+ struct ureg_dst dst,
+ struct ureg_src coords,
+ struct ureg_src sampler,
+ struct ureg_src imm0,
+ boolean repeat_none,
+ boolean swizzle,
+ boolean set_alpha)
+{
+ if (repeat_none) {
+ struct ureg_dst tmp0 = ureg_DECL_temporary(ureg);
+ struct ureg_dst tmp1 = ureg_DECL_temporary(ureg);
+ ureg_SGT(ureg, tmp1, ureg_swizzle(coords,
+ TGSI_SWIZZLE_X,
+ TGSI_SWIZZLE_Y,
+ TGSI_SWIZZLE_X,
+ TGSI_SWIZZLE_Y),
+ ureg_scalar(imm0, TGSI_SWIZZLE_X));
+ ureg_SLT(ureg, tmp0, ureg_swizzle(coords,
+ TGSI_SWIZZLE_X,
+ TGSI_SWIZZLE_Y,
+ TGSI_SWIZZLE_X,
+ TGSI_SWIZZLE_Y),
+ ureg_scalar(imm0, TGSI_SWIZZLE_W));
+ ureg_MIN(ureg, tmp0, ureg_src(tmp0), ureg_src(tmp1));
+ ureg_MIN(ureg, tmp0, ureg_scalar(ureg_src(tmp0), TGSI_SWIZZLE_X),
+ ureg_scalar(ureg_src(tmp0), TGSI_SWIZZLE_Y));
+ ureg_TEX(ureg, tmp1, TGSI_TEXTURE_2D, coords, sampler);
+ if (swizzle)
+ ureg_MOV(ureg, tmp1, ureg_swizzle(ureg_src(tmp1),
+ TGSI_SWIZZLE_Z,
+ TGSI_SWIZZLE_Y,
+ TGSI_SWIZZLE_X,
+ TGSI_SWIZZLE_W));
+ if (set_alpha)
+ ureg_MOV(ureg,
+ ureg_writemask(tmp1, TGSI_WRITEMASK_W),
+ ureg_scalar(imm0, TGSI_SWIZZLE_W));
+ ureg_MUL(ureg, dst, ureg_src(tmp1), ureg_src(tmp0));
+ ureg_release_temporary(ureg, tmp0);
+ ureg_release_temporary(ureg, tmp1);
+ } else {
+ if (swizzle) {
+ struct ureg_dst tmp = ureg_DECL_temporary(ureg);
+ ureg_TEX(ureg, tmp, TGSI_TEXTURE_2D, coords, sampler);
+ ureg_MOV(ureg, dst, ureg_swizzle(ureg_src(tmp),
+ TGSI_SWIZZLE_Z,
+ TGSI_SWIZZLE_Y,
+ TGSI_SWIZZLE_X,
+ TGSI_SWIZZLE_W));
+ ureg_release_temporary(ureg, tmp);
+ } else {
+ ureg_TEX(ureg, dst, TGSI_TEXTURE_2D, coords, sampler);
+ }
+ if (set_alpha)
+ ureg_MOV(ureg,
+ ureg_writemask(dst, TGSI_WRITEMASK_W),
+ ureg_scalar(imm0, TGSI_SWIZZLE_W));
+ }
+}
+
+static void *
+create_fs(struct pipe_context *pipe,
+ unsigned fs_traits)
+{
+ struct ureg_program *ureg;
+ struct ureg_src /*dst_sampler,*/ src_sampler, mask_sampler;
+ struct ureg_src /*dst_pos,*/ src_input, mask_pos;
+ struct ureg_dst src, mask;
+ struct ureg_dst out;
+ struct ureg_src imm0 = { 0 };
+ unsigned has_mask = (fs_traits & FS_MASK) != 0;
+ unsigned is_fill = (fs_traits & FS_FILL) != 0;
+ unsigned is_composite = (fs_traits & FS_COMPOSITE) != 0;
+ unsigned is_solid = (fs_traits & FS_SOLID_FILL) != 0;
+ unsigned is_lingrad = (fs_traits & FS_LINGRAD_FILL) != 0;
+ unsigned is_radgrad = (fs_traits & FS_RADGRAD_FILL) != 0;
+ unsigned comp_alpha_mask = fs_traits & FS_COMPONENT_ALPHA;
+ unsigned is_yuv = (fs_traits & FS_YUV) != 0;
+ unsigned src_repeat_none = (fs_traits & FS_SRC_REPEAT_NONE) != 0;
+ unsigned mask_repeat_none = (fs_traits & FS_MASK_REPEAT_NONE) != 0;
+ unsigned src_swizzle = (fs_traits & FS_SRC_SWIZZLE_RGB) != 0;
+ unsigned mask_swizzle = (fs_traits & FS_MASK_SWIZZLE_RGB) != 0;
+ unsigned src_set_alpha = (fs_traits & FS_SRC_SET_ALPHA) != 0;
+ unsigned mask_set_alpha = (fs_traits & FS_MASK_SET_ALPHA) != 0;
+ unsigned src_luminance = (fs_traits & FS_SRC_LUMINANCE) != 0;
+ unsigned mask_luminance = (fs_traits & FS_MASK_LUMINANCE) != 0;
+
+#if 0
+ print_fs_traits(fs_traits);
+#else
+ (void)print_fs_traits;
+#endif
+
+ ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT);
+ if (ureg == NULL)
+ return 0;
+
+ /* it has to be either a fill, a composite op or a yuv conversion */
+ debug_assert((is_fill ^ is_composite) ^ is_yuv);
+ (void) is_yuv;
+
+ out = ureg_DECL_output(ureg,
+ TGSI_SEMANTIC_COLOR,
+ 0);
+
+ if (src_repeat_none || mask_repeat_none ||
+ src_set_alpha || mask_set_alpha ||
+ src_luminance) {
+ imm0 = ureg_imm4f(ureg, 0, 0, 0, 1);
+ }
+ if (is_composite) {
+ src_sampler = ureg_DECL_sampler(ureg, 0);
+ src_input = ureg_DECL_fs_input(ureg,
+ TGSI_SEMANTIC_GENERIC,
+ 0,
+ TGSI_INTERPOLATE_PERSPECTIVE);
+ } else if (is_fill) {
+ if (is_solid)
+ src_input = ureg_DECL_fs_input(ureg,
+ TGSI_SEMANTIC_COLOR,
+ 0,
+ TGSI_INTERPOLATE_PERSPECTIVE);
+ else
+ src_input = ureg_DECL_fs_input(ureg,
+ TGSI_SEMANTIC_POSITION,
+ 0,
+ TGSI_INTERPOLATE_PERSPECTIVE);
+ } else {
+ debug_assert(is_yuv);
+ return create_yuv_shader(pipe, ureg);
+ }
+
+ if (has_mask) {
+ mask_sampler = ureg_DECL_sampler(ureg, 1);
+ mask_pos = ureg_DECL_fs_input(ureg,
+ TGSI_SEMANTIC_GENERIC,
+ 1,
+ TGSI_INTERPOLATE_PERSPECTIVE);
+ }
+
+#if 0 /* unused right now */
+ dst_sampler = ureg_DECL_sampler(ureg, 2);
+ dst_pos = ureg_DECL_fs_input(ureg,
+ TGSI_SEMANTIC_POSITION,
+ 2,
+ TGSI_INTERPOLATE_PERSPECTIVE);
+#endif
+
+
+ if (is_composite) {
+ if (has_mask || src_luminance)
+ src = ureg_DECL_temporary(ureg);
+ else
+ src = out;
+ xrender_tex(ureg, src, src_input, src_sampler, imm0,
+ src_repeat_none, src_swizzle, src_set_alpha);
+ } else if (is_fill) {
+ if (is_solid) {
+ if (has_mask || src_luminance)
+ src = ureg_dst(src_input);
+ else
+ ureg_MOV(ureg, out, src_input);
+ } else if (is_lingrad || is_radgrad) {
+ struct ureg_src coords, const0124,
+ matrow0, matrow1, matrow2;
+
+ if (has_mask || src_luminance)
+ src = ureg_DECL_temporary(ureg);
+ else
+ src = out;
+
+ coords = ureg_DECL_constant(ureg, 0);
+ const0124 = ureg_DECL_constant(ureg, 1);
+ matrow0 = ureg_DECL_constant(ureg, 2);
+ matrow1 = ureg_DECL_constant(ureg, 3);
+ matrow2 = ureg_DECL_constant(ureg, 4);
+
+ if (is_lingrad) {
+ linear_gradient(ureg, src,
+ src_input, src_sampler,
+ coords, const0124,
+ matrow0, matrow1, matrow2);
+ } else if (is_radgrad) {
+ radial_gradient(ureg, src,
+ src_input, src_sampler,
+ coords, const0124,
+ matrow0, matrow1, matrow2);
+ }
+ } else
+ debug_assert(!"Unknown fill type!");
+ }
+ if (src_luminance) {
+ ureg_MOV(ureg, src,
+ ureg_scalar(ureg_src(src), TGSI_SWIZZLE_X));
+ ureg_MOV(ureg, ureg_writemask(src, TGSI_WRITEMASK_XYZ),
+ ureg_scalar(imm0, TGSI_SWIZZLE_X));
+ if (!has_mask)
+ ureg_MOV(ureg, out, ureg_src(src));
+ }
+
+ if (has_mask) {
+ mask = ureg_DECL_temporary(ureg);
+ xrender_tex(ureg, mask, mask_pos, mask_sampler, imm0,
+ mask_repeat_none, mask_swizzle, mask_set_alpha);
+ /* src IN mask */
+ src_in_mask(ureg, out, ureg_src(src), ureg_src(mask),
+ comp_alpha_mask, mask_luminance);
+ ureg_release_temporary(ureg, mask);
+ }
+
+ ureg_END(ureg);
+
+ return ureg_create_shader_and_destroy(ureg, pipe);
+}
+
+struct xorg_shaders * xorg_shaders_create(struct xorg_renderer *r)
+{
+ struct xorg_shaders *sc = CALLOC_STRUCT(xorg_shaders);
+
+ sc->r = r;
+ sc->vs_hash = cso_hash_create();
+ sc->fs_hash = cso_hash_create();
+
+ return sc;
+}
+
+static void
+cache_destroy(struct cso_context *cso,
+ struct cso_hash *hash,
+ unsigned processor)
+{
+ struct cso_hash_iter iter = cso_hash_first_node(hash);
+ while (!cso_hash_iter_is_null(iter)) {
+ void *shader = (void *)cso_hash_iter_data(iter);
+ if (processor == PIPE_SHADER_FRAGMENT) {
+ cso_delete_fragment_shader(cso, shader);
+ } else if (processor == PIPE_SHADER_VERTEX) {
+ cso_delete_vertex_shader(cso, shader);
+ }
+ iter = cso_hash_erase(hash, iter);
+ }
+ cso_hash_delete(hash);
+}
+
+void xorg_shaders_destroy(struct xorg_shaders *sc)
+{
+ cache_destroy(sc->r->cso, sc->vs_hash,
+ PIPE_SHADER_VERTEX);
+ cache_destroy(sc->r->cso, sc->fs_hash,
+ PIPE_SHADER_FRAGMENT);
+
+ free(sc);
+}
+
+static INLINE void *
+shader_from_cache(struct pipe_context *pipe,
+ unsigned type,
+ struct cso_hash *hash,
+ unsigned key)
+{
+ void *shader = 0;
+
+ struct cso_hash_iter iter = cso_hash_find(hash, key);
+
+ if (cso_hash_iter_is_null(iter)) {
+ if (type == PIPE_SHADER_VERTEX)
+ shader = create_vs(pipe, key);
+ else
+ shader = create_fs(pipe, key);
+ cso_hash_insert(hash, key, shader);
+ } else
+ shader = (void *)cso_hash_iter_data(iter);
+
+ return shader;
+}
+
+struct xorg_shader xorg_shaders_get(struct xorg_shaders *sc,
+ unsigned vs_traits,
+ unsigned fs_traits)
+{
+ struct xorg_shader shader = { NULL, NULL };
+ void *vs, *fs;
+
+ vs = shader_from_cache(sc->r->pipe, PIPE_SHADER_VERTEX,
+ sc->vs_hash, vs_traits);
+ fs = shader_from_cache(sc->r->pipe, PIPE_SHADER_FRAGMENT,
+ sc->fs_hash, fs_traits);
+
+ debug_assert(vs && fs);
+ if (!vs || !fs)
+ return shader;
+
+ shader.vs = vs;
+ shader.fs = fs;
+
+ return shader;
+}
diff --git a/src/gallium/state_trackers/xorg/xorg_exa_tgsi.h b/src/gallium/state_trackers/xorg/xorg_exa_tgsi.h
new file mode 100644
index 0000000000..6f2a361d03
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xorg_exa_tgsi.h
@@ -0,0 +1,59 @@
+#ifndef XORG_EXA_TGSI_H
+#define XORG_EXA_TGSI_H
+
+#include "xorg_renderer.h"
+
+enum xorg_vs_traits {
+ VS_COMPOSITE = 1 << 0,
+ VS_MASK = 1 << 1,
+ VS_SOLID_FILL = 1 << 2,
+ VS_LINGRAD_FILL = 1 << 3,
+ VS_RADGRAD_FILL = 1 << 4,
+ VS_YUV = 1 << 5,
+
+
+ VS_FILL = (VS_SOLID_FILL |
+ VS_LINGRAD_FILL |
+ VS_RADGRAD_FILL)
+};
+
+enum xorg_fs_traits {
+ FS_COMPOSITE = 1 << 0,
+ FS_MASK = 1 << 1,
+ FS_SOLID_FILL = 1 << 2,
+ FS_LINGRAD_FILL = 1 << 3,
+ FS_RADGRAD_FILL = 1 << 4,
+ FS_CA_FULL = 1 << 5, /* src.rgba * mask.rgba */
+ FS_CA_SRCALPHA = 1 << 6, /* src.aaaa * mask.rgba */
+ FS_YUV = 1 << 7,
+ FS_SRC_REPEAT_NONE = 1 << 8,
+ FS_MASK_REPEAT_NONE = 1 << 9,
+ FS_SRC_SWIZZLE_RGB = 1 << 10,
+ FS_MASK_SWIZZLE_RGB = 1 << 11,
+ FS_SRC_SET_ALPHA = 1 << 12,
+ FS_MASK_SET_ALPHA = 1 << 13,
+ FS_SRC_LUMINANCE = 1 << 14,
+ FS_MASK_LUMINANCE = 1 << 15,
+
+ FS_FILL = (FS_SOLID_FILL |
+ FS_LINGRAD_FILL |
+ FS_RADGRAD_FILL),
+ FS_COMPONENT_ALPHA = (FS_CA_FULL |
+ FS_CA_SRCALPHA)
+};
+
+struct xorg_shader {
+ void *fs;
+ void *vs;
+};
+
+struct xorg_shaders;
+
+struct xorg_shaders *xorg_shaders_create(struct xorg_renderer *renderer);
+void xorg_shaders_destroy(struct xorg_shaders *shaders);
+
+struct xorg_shader xorg_shaders_get(struct xorg_shaders *shaders,
+ unsigned vs_traits,
+ unsigned fs_traits);
+
+#endif
diff --git a/src/gallium/state_trackers/xorg/xorg_output.c b/src/gallium/state_trackers/xorg/xorg_output.c
new file mode 100644
index 0000000000..056098f76b
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xorg_output.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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.
+ *
+ *
+ * Author: Alan Hourihane <alanh@tungstengraphics.com>
+ * Author: Jakob Bornecrantz <wallbraker@gmail.com>
+ *
+ */
+
+#include "xorg-server.h"
+#include <xf86.h>
+#include <xf86i2c.h>
+#include <xf86Crtc.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#ifdef HAVE_XEXTPROTO_71
+#include <X11/extensions/dpmsconst.h>
+#else
+#define DPMS_SERVER
+#include <X11/extensions/dpms.h>
+#endif
+
+#include "xorg_tracker.h"
+
+struct output_private
+{
+ drmModeConnectorPtr drm_connector;
+
+ int c;
+};
+
+static char *output_enum_list[] = {
+ "Unknown",
+ "VGA",
+ "DVI",
+ "DVI",
+ "DVI",
+ "Composite",
+ "SVIDEO",
+ "LVDS",
+ "CTV",
+ "DIN",
+ "DP",
+ "HDMI",
+ "HDMI",
+};
+
+static void
+output_create_resources(xf86OutputPtr output)
+{
+#ifdef RANDR_12_INTERFACE
+#endif /* RANDR_12_INTERFACE */
+}
+
+static void
+output_dpms(xf86OutputPtr output, int mode)
+{
+}
+
+static xf86OutputStatus
+output_detect(xf86OutputPtr output)
+{
+ modesettingPtr ms = modesettingPTR(output->scrn);
+ struct output_private *priv = output->driver_private;
+ drmModeConnectorPtr drm_connector;
+ xf86OutputStatus status;
+
+ drm_connector = drmModeGetConnector(ms->fd, priv->drm_connector->connector_id);
+ if (drm_connector) {
+ drmModeFreeConnector(priv->drm_connector);
+ priv->drm_connector = drm_connector;
+ } else {
+ drm_connector = priv->drm_connector;
+ }
+
+ switch (drm_connector->connection) {
+ case DRM_MODE_CONNECTED:
+ status = XF86OutputStatusConnected;
+ break;
+ case DRM_MODE_DISCONNECTED:
+ status = XF86OutputStatusDisconnected;
+ break;
+ default:
+ status = XF86OutputStatusUnknown;
+ }
+
+ return status;
+}
+
+static DisplayModePtr
+output_get_modes(xf86OutputPtr output)
+{
+ struct output_private *priv = output->driver_private;
+ drmModeConnectorPtr drm_connector = priv->drm_connector;
+ drmModeModeInfoPtr drm_mode = NULL;
+ DisplayModePtr modes = NULL, mode = NULL;
+ int i;
+
+ for (i = 0; i < drm_connector->count_modes; i++) {
+ drm_mode = &drm_connector->modes[i];
+ if (drm_mode) {
+ mode = xcalloc(1, sizeof(DisplayModeRec));
+ if (!mode)
+ continue;
+ mode->Clock = drm_mode->clock;
+ mode->HDisplay = drm_mode->hdisplay;
+ mode->HSyncStart = drm_mode->hsync_start;
+ mode->HSyncEnd = drm_mode->hsync_end;
+ mode->HTotal = drm_mode->htotal;
+ mode->VDisplay = drm_mode->vdisplay;
+ mode->VSyncStart = drm_mode->vsync_start;
+ mode->VSyncEnd = drm_mode->vsync_end;
+ mode->VTotal = drm_mode->vtotal;
+ mode->Flags = drm_mode->flags;
+ mode->HSkew = drm_mode->hskew;
+ mode->VScan = drm_mode->vscan;
+ mode->VRefresh = xf86ModeVRefresh(mode);
+ mode->Private = (void *)drm_mode;
+ mode->type = 0;
+ if (drm_mode->type & DRM_MODE_TYPE_PREFERRED)
+ mode->type |= M_T_PREFERRED;
+ if (drm_mode->type & DRM_MODE_TYPE_DRIVER)
+ mode->type |= M_T_DRIVER;
+ xf86SetModeDefaultName(mode);
+ modes = xf86ModesAdd(modes, mode);
+ xf86PrintModeline(0, mode);
+ }
+ }
+
+ return modes;
+}
+
+static int
+output_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
+{
+ return MODE_OK;
+}
+
+#ifdef RANDR_12_INTERFACE
+static Bool
+output_set_property(xf86OutputPtr output, Atom property, RRPropertyValuePtr value)
+{
+ return TRUE;
+}
+#endif /* RANDR_12_INTERFACE */
+
+#ifdef RANDR_13_INTERFACE
+static Bool
+output_get_property(xf86OutputPtr output, Atom property)
+{
+ return TRUE;
+}
+#endif /* RANDR_13_INTERFACE */
+
+static void
+output_destroy(xf86OutputPtr output)
+{
+ struct output_private *priv = output->driver_private;
+ drmModeFreeConnector(priv->drm_connector);
+ xfree(priv);
+ output->driver_private = NULL;
+}
+
+static const xf86OutputFuncsRec output_funcs = {
+ .create_resources = output_create_resources,
+#ifdef RANDR_12_INTERFACE
+ .set_property = output_set_property,
+#endif
+#ifdef RANDR_13_INTERFACE
+ .get_property = output_get_property,
+#endif
+ .dpms = output_dpms,
+ .detect = output_detect,
+
+ .get_modes = output_get_modes,
+ .mode_valid = output_mode_valid,
+ .destroy = output_destroy,
+};
+
+void
+xorg_output_init(ScrnInfoPtr pScrn)
+{
+ modesettingPtr ms = modesettingPTR(pScrn);
+ xf86OutputPtr output;
+ drmModeResPtr res;
+ drmModeConnectorPtr drm_connector = NULL;
+ drmModeEncoderPtr drm_encoder = NULL;
+ struct output_private *priv;
+ char name[32];
+ int c, v, p;
+
+ res = drmModeGetResources(ms->fd);
+ if (res == 0) {
+ DRV_ERROR("Failed drmModeGetResources\n");
+ return;
+ }
+
+ for (c = 0; c < res->count_connectors; c++) {
+ drm_connector = drmModeGetConnector(ms->fd, res->connectors[c]);
+ if (!drm_connector)
+ goto out;
+
+#if 0
+ for (p = 0; p < drm_connector->count_props; p++) {
+ drmModePropertyPtr prop;
+
+ prop = drmModeGetProperty(ms->fd, drm_connector->props[p]);
+
+ name = NULL;
+ if (prop) {
+ ErrorF("VALUES %d\n", prop->count_values);
+
+ for (v = 0; v < prop->count_values; v++)
+ ErrorF("%s %lld\n", prop->name, prop->values[v]);
+ }
+ }
+#else
+ (void)p;
+ (void)v;
+#endif
+
+ snprintf(name, 32, "%s%d",
+ output_enum_list[drm_connector->connector_type],
+ drm_connector->connector_type_id);
+
+
+ priv = xcalloc(sizeof(*priv), 1);
+ if (!priv) {
+ continue;
+ }
+
+ output = xf86OutputCreate(pScrn, &output_funcs, name);
+ if (!output) {
+ xfree(priv);
+ continue;
+ }
+
+ drm_encoder = drmModeGetEncoder(ms->fd, drm_connector->encoders[0]);
+ if (drm_encoder) {
+ output->possible_crtcs = drm_encoder->possible_crtcs;
+ output->possible_clones = drm_encoder->possible_clones;
+ } else {
+ output->possible_crtcs = 0;
+ output->possible_clones = 0;
+ }
+ priv->c = c;
+ priv->drm_connector = drm_connector;
+ output->driver_private = priv;
+ output->subpixel_order = SubPixelHorizontalRGB;
+ output->interlaceAllowed = FALSE;
+ output->doubleScanAllowed = FALSE;
+ }
+
+ out:
+ drmModeFreeResources(res);
+}
+
+unsigned
+xorg_output_get_id(xf86OutputPtr output)
+{
+ struct output_private *priv = output->driver_private;
+ return priv->drm_connector->connector_id;
+}
+
+/* vim: set sw=4 ts=8 sts=4: */
diff --git a/src/gallium/state_trackers/xorg/xorg_renderer.c b/src/gallium/state_trackers/xorg/xorg_renderer.c
new file mode 100644
index 0000000000..92f1cc5065
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xorg_renderer.c
@@ -0,0 +1,716 @@
+#include "xorg_exa.h"
+#include "xorg_renderer.h"
+
+#include "xorg_exa_tgsi.h"
+
+#include "cso_cache/cso_context.h"
+#include "util/u_draw_quad.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+#include "util/u_sampler.h"
+
+#include "util/u_inlines.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 NUM_COMPONENTS 4
+
+static INLINE boolean is_affine(float *matrix)
+{
+ return floatIsZero(matrix[2]) && floatIsZero(matrix[5])
+ && floatsEqual(matrix[8], 1);
+}
+static INLINE void map_point(float *mat, float x, float y,
+ float *out_x, float *out_y)
+{
+ if (!mat) {
+ *out_x = x;
+ *out_y = y;
+ return;
+ }
+
+ *out_x = mat[0]*x + mat[3]*y + mat[6];
+ *out_y = mat[1]*x + mat[4]*y + mat[7];
+ if (!is_affine(mat)) {
+ float w = 1/(mat[2]*x + mat[5]*y + mat[8]);
+ *out_x *= w;
+ *out_y *= w;
+ }
+}
+
+static INLINE struct pipe_resource *
+renderer_buffer_create(struct xorg_renderer *r)
+{
+ struct pipe_resource *buf =
+ pipe_user_buffer_create(r->pipe->screen,
+ r->buffer,
+ sizeof(float)*
+ r->buffer_size,
+/* XXX was: PIPE_BUFFER_USAGE_PIXEL/PIPE_BUFFER_USAGE_GPU_WRITE even though this is a vertex buffer??? */
+ PIPE_BIND_VERTEX_BUFFER);
+ r->buffer_size = 0;
+
+ return buf;
+}
+
+static INLINE void
+renderer_draw(struct xorg_renderer *r)
+{
+ struct pipe_context *pipe = r->pipe;
+ struct pipe_resource *buf = 0;
+ int num_verts = r->buffer_size/(r->attrs_per_vertex * NUM_COMPONENTS);
+
+ if (!r->buffer_size)
+ return;
+
+ buf = renderer_buffer_create(r);
+
+
+ if (buf) {
+ cso_set_vertex_elements(r->cso, r->attrs_per_vertex, r->velems);
+
+ util_draw_vertex_buffer(pipe, buf, 0,
+ PIPE_PRIM_QUADS,
+ num_verts, /* verts */
+ r->attrs_per_vertex); /* attribs/vert */
+
+ pipe_resource_reference(&buf, NULL);
+ }
+}
+
+static INLINE void
+renderer_draw_conditional(struct xorg_renderer *r,
+ int next_batch)
+{
+ if (r->buffer_size + next_batch >= BUF_SIZE ||
+ (next_batch == 0 && r->buffer_size)) {
+ renderer_draw(r);
+ }
+}
+
+static void
+renderer_init_state(struct xorg_renderer *r)
+{
+ struct pipe_depth_stencil_alpha_state dsa;
+ struct pipe_rasterizer_state raster;
+ unsigned i;
+
+ /* set common initial clip state */
+ memset(&dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state));
+ cso_set_depth_stencil_alpha(r->cso, &dsa);
+
+
+ /* XXX: move to renderer_init_state? */
+ memset(&raster, 0, sizeof(struct pipe_rasterizer_state));
+ raster.gl_rasterization_rules = 1;
+ cso_set_rasterizer(r->cso, &raster);
+
+ /* vertex elements state */
+ memset(&r->velems[0], 0, sizeof(r->velems[0]) * 3);
+ for (i = 0; i < 3; i++) {
+ r->velems[i].src_offset = i * 4 * sizeof(float);
+ r->velems[i].instance_divisor = 0;
+ r->velems[i].vertex_buffer_index = 0;
+ r->velems[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
+ }
+}
+
+
+static INLINE void
+add_vertex_color(struct xorg_renderer *r,
+ float x, float y,
+ float color[4])
+{
+ float *vertex = r->buffer + r->buffer_size;
+
+ vertex[0] = x;
+ vertex[1] = y;
+ vertex[2] = 0.f; /*z*/
+ vertex[3] = 1.f; /*w*/
+
+ vertex[4] = color[0]; /*r*/
+ vertex[5] = color[1]; /*g*/
+ vertex[6] = color[2]; /*b*/
+ vertex[7] = color[3]; /*a*/
+
+ r->buffer_size += 8;
+}
+
+static INLINE void
+add_vertex_1tex(struct xorg_renderer *r,
+ float x, float y, float s, float t)
+{
+ float *vertex = r->buffer + r->buffer_size;
+
+ vertex[0] = x;
+ vertex[1] = y;
+ vertex[2] = 0.f; /*z*/
+ vertex[3] = 1.f; /*w*/
+
+ vertex[4] = s; /*s*/
+ vertex[5] = t; /*t*/
+ vertex[6] = 0.f; /*r*/
+ vertex[7] = 1.f; /*q*/
+
+ r->buffer_size += 8;
+}
+
+static void
+add_vertex_data1(struct xorg_renderer *r,
+ float srcX, float srcY, float dstX, float dstY,
+ float width, float height,
+ struct pipe_resource *src, float *src_matrix)
+{
+ float s0, t0, s1, t1, s2, t2, s3, t3;
+ float pt0[2], pt1[2], pt2[2], pt3[2];
+
+ pt0[0] = srcX;
+ pt0[1] = srcY;
+ pt1[0] = (srcX + width);
+ pt1[1] = srcY;
+ pt2[0] = (srcX + width);
+ pt2[1] = (srcY + height);
+ pt3[0] = srcX;
+ pt3[1] = (srcY + height);
+
+ if (src_matrix) {
+ map_point(src_matrix, pt0[0], pt0[1], &pt0[0], &pt0[1]);
+ map_point(src_matrix, pt1[0], pt1[1], &pt1[0], &pt1[1]);
+ map_point(src_matrix, pt2[0], pt2[1], &pt2[0], &pt2[1]);
+ map_point(src_matrix, pt3[0], pt3[1], &pt3[0], &pt3[1]);
+ }
+
+ s0 = pt0[0] / src->width0;
+ s1 = pt1[0] / src->width0;
+ s2 = pt2[0] / src->width0;
+ s3 = pt3[0] / src->width0;
+ t0 = pt0[1] / src->height0;
+ t1 = pt1[1] / src->height0;
+ t2 = pt2[1] / src->height0;
+ t3 = pt3[1] / src->height0;
+
+ /* 1st vertex */
+ add_vertex_1tex(r, dstX, dstY, s0, t0);
+ /* 2nd vertex */
+ add_vertex_1tex(r, dstX + width, dstY, s1, t1);
+ /* 3rd vertex */
+ add_vertex_1tex(r, dstX + width, dstY + height, s2, t2);
+ /* 4th vertex */
+ add_vertex_1tex(r, dstX, dstY + height, s3, t3);
+}
+
+
+static INLINE void
+add_vertex_2tex(struct xorg_renderer *r,
+ float x, float y,
+ float s0, float t0, float s1, float t1)
+{
+ float *vertex = r->buffer + r->buffer_size;
+
+ vertex[0] = x;
+ vertex[1] = y;
+ vertex[2] = 0.f; /*z*/
+ vertex[3] = 1.f; /*w*/
+
+ vertex[4] = s0; /*s*/
+ vertex[5] = t0; /*t*/
+ vertex[6] = 0.f; /*r*/
+ vertex[7] = 1.f; /*q*/
+
+ vertex[8] = s1; /*s*/
+ vertex[9] = t1; /*t*/
+ vertex[10] = 0.f; /*r*/
+ vertex[11] = 1.f; /*q*/
+
+ r->buffer_size += 12;
+}
+
+static void
+add_vertex_data2(struct xorg_renderer *r,
+ float srcX, float srcY, float maskX, float maskY,
+ float dstX, float dstY, float width, float height,
+ struct pipe_resource *src,
+ struct pipe_resource *mask,
+ float *src_matrix, float *mask_matrix)
+{
+ float src_s0, src_t0, src_s1, src_t1;
+ float mask_s0, mask_t0, mask_s1, mask_t1;
+ float spt0[2], spt1[2];
+ float mpt0[2], mpt1[2];
+
+ spt0[0] = srcX;
+ spt0[1] = srcY;
+ spt1[0] = srcX + width;
+ spt1[1] = srcY + height;
+
+ mpt0[0] = maskX;
+ mpt0[1] = maskY;
+ mpt1[0] = maskX + width;
+ mpt1[1] = maskY + height;
+
+ if (src_matrix) {
+ map_point(src_matrix, spt0[0], spt0[1], &spt0[0], &spt0[1]);
+ map_point(src_matrix, spt1[0], spt1[1], &spt1[0], &spt1[1]);
+ }
+
+ if (mask_matrix) {
+ map_point(mask_matrix, mpt0[0], mpt0[1], &mpt0[0], &mpt0[1]);
+ map_point(mask_matrix, mpt1[0], mpt1[1], &mpt1[0], &mpt1[1]);
+ }
+
+ src_s0 = spt0[0] / src->width0;
+ src_t0 = spt0[1] / src->height0;
+ src_s1 = spt1[0] / src->width0;
+ src_t1 = spt1[1] / src->height0;
+
+ mask_s0 = mpt0[0] / mask->width0;
+ mask_t0 = mpt0[1] / mask->height0;
+ mask_s1 = mpt1[0] / mask->width0;
+ mask_t1 = mpt1[1] / mask->height0;
+
+ /* 1st vertex */
+ add_vertex_2tex(r, dstX, dstY,
+ src_s0, src_t0, mask_s0, mask_t0);
+ /* 2nd vertex */
+ add_vertex_2tex(r, dstX + width, dstY,
+ src_s1, src_t0, mask_s1, mask_t0);
+ /* 3rd vertex */
+ add_vertex_2tex(r, dstX + width, dstY + height,
+ src_s1, src_t1, mask_s1, mask_t1);
+ /* 4th vertex */
+ add_vertex_2tex(r, dstX, dstY + height,
+ src_s0, src_t1, mask_s0, mask_t1);
+}
+
+static struct pipe_resource *
+setup_vertex_data_yuv(struct xorg_renderer *r,
+ float srcX, float srcY, float srcW, float srcH,
+ float dstX, float dstY, float dstW, float dstH,
+ struct pipe_resource **tex)
+{
+ float s0, t0, s1, t1;
+ float spt0[2], spt1[2];
+
+ spt0[0] = srcX;
+ spt0[1] = srcY;
+ spt1[0] = srcX + srcW;
+ spt1[1] = srcY + srcH;
+
+ s0 = spt0[0] / tex[0]->width0;
+ t0 = spt0[1] / tex[0]->height0;
+ s1 = spt1[0] / tex[0]->width0;
+ t1 = spt1[1] / tex[0]->height0;
+
+ /* 1st vertex */
+ add_vertex_1tex(r, dstX, dstY, s0, t0);
+ /* 2nd vertex */
+ add_vertex_1tex(r, dstX + dstW, dstY,
+ s1, t0);
+ /* 3rd vertex */
+ add_vertex_1tex(r, dstX + dstW, dstY + dstH,
+ s1, t1);
+ /* 4th vertex */
+ add_vertex_1tex(r, dstX, dstY + dstH,
+ s0, t1);
+
+ return renderer_buffer_create(r);
+}
+
+
+
+/* Set up framebuffer, viewport and vertex shader constant buffer
+ * state for a particular destinaton surface. In all our rendering,
+ * these concepts are linked.
+ */
+void renderer_bind_destination(struct xorg_renderer *r,
+ struct pipe_surface *surface,
+ int width,
+ int height )
+{
+
+ struct pipe_framebuffer_state fb;
+ struct pipe_viewport_state viewport;
+
+ /* Framebuffer uses actual surface width/height
+ */
+ memset(&fb, 0, sizeof fb);
+ fb.width = surface->width;
+ fb.height = surface->height;
+ fb.nr_cbufs = 1;
+ fb.cbufs[0] = surface;
+ fb.zsbuf = 0;
+
+ /* Viewport just touches the bit we're interested in:
+ */
+ viewport.scale[0] = width / 2.f;
+ viewport.scale[1] = height / 2.f;
+ viewport.scale[2] = 1.0;
+ viewport.scale[3] = 1.0;
+ viewport.translate[0] = width / 2.f;
+ viewport.translate[1] = height / 2.f;
+ viewport.translate[2] = 0.0;
+ viewport.translate[3] = 0.0;
+
+ /* Constant buffer set up to match viewport dimensions:
+ */
+ if (r->fb_width != width ||
+ r->fb_height != height)
+ {
+ float vs_consts[8] = {
+ 2.f/width, 2.f/height, 1, 1,
+ -1, -1, 0, 0
+ };
+
+ r->fb_width = width;
+ r->fb_height = height;
+
+ renderer_set_constants(r, PIPE_SHADER_VERTEX,
+ vs_consts, sizeof vs_consts);
+ }
+
+ cso_set_framebuffer(r->cso, &fb);
+ cso_set_viewport(r->cso, &viewport);
+}
+
+
+struct xorg_renderer * renderer_create(struct pipe_context *pipe)
+{
+ struct xorg_renderer *renderer = CALLOC_STRUCT(xorg_renderer);
+
+ renderer->pipe = pipe;
+ renderer->cso = cso_create_context(pipe);
+ renderer->shaders = xorg_shaders_create(renderer);
+
+ renderer_init_state(renderer);
+
+ return renderer;
+}
+
+void renderer_destroy(struct xorg_renderer *r)
+{
+ struct pipe_resource **vsbuf = &r->vs_const_buffer;
+ struct pipe_resource **fsbuf = &r->fs_const_buffer;
+
+ if (*vsbuf)
+ pipe_resource_reference(vsbuf, NULL);
+
+ if (*fsbuf)
+ pipe_resource_reference(fsbuf, NULL);
+
+ if (r->shaders) {
+ xorg_shaders_destroy(r->shaders);
+ r->shaders = NULL;
+ }
+
+ if (r->cso) {
+ cso_release_all(r->cso);
+ cso_destroy_context(r->cso);
+ r->cso = NULL;
+ }
+}
+
+
+
+
+
+void renderer_set_constants(struct xorg_renderer *r,
+ int shader_type,
+ const float *params,
+ int param_bytes)
+{
+ struct pipe_resource **cbuf =
+ (shader_type == PIPE_SHADER_VERTEX) ? &r->vs_const_buffer :
+ &r->fs_const_buffer;
+
+ pipe_resource_reference(cbuf, NULL);
+ *cbuf = pipe_buffer_create(r->pipe->screen,
+ PIPE_BIND_CONSTANT_BUFFER,
+ param_bytes);
+
+ if (*cbuf) {
+ pipe_buffer_write(r->pipe, *cbuf,
+ 0, param_bytes, params);
+ }
+ r->pipe->set_constant_buffer(r->pipe, shader_type, 0, *cbuf);
+}
+
+
+void renderer_copy_prepare(struct xorg_renderer *r,
+ struct pipe_surface *dst_surface,
+ struct pipe_resource *src_texture)
+{
+ struct pipe_context *pipe = r->pipe;
+ struct pipe_screen *screen = pipe->screen;
+ struct xorg_shader shader;
+
+ assert(screen->is_format_supported(screen, dst_surface->format,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_RENDER_TARGET,
+ 0));
+ (void) screen;
+
+
+ /* set misc state we care about */
+ {
+ struct pipe_blend_state blend;
+ memset(&blend, 0, sizeof(blend));
+ blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ blend.rt[0].colormask = PIPE_MASK_RGBA;
+ cso_set_blend(r->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(r->cso, 0, &sampler);
+ cso_single_sampler_done(r->cso);
+ }
+
+ renderer_bind_destination(r, dst_surface,
+ dst_surface->width,
+ dst_surface->height);
+
+ /* texture/sampler view */
+ {
+ struct pipe_sampler_view templ;
+ struct pipe_sampler_view *src_view;
+ u_sampler_view_default_template(&templ,
+ src_texture,
+ src_texture->format);
+ src_view = pipe->create_sampler_view(pipe, src_texture, &templ);
+ cso_set_fragment_sampler_views(r->cso, 1, &src_view);
+ pipe_sampler_view_reference(&src_view, NULL);
+ }
+
+ /* shaders */
+ shader = xorg_shaders_get(r->shaders,
+ VS_COMPOSITE,
+ FS_COMPOSITE);
+ cso_set_vertex_shader_handle(r->cso, shader.vs);
+ cso_set_fragment_shader_handle(r->cso, shader.fs);
+
+ r->buffer_size = 0;
+ r->attrs_per_vertex = 2;
+}
+
+struct pipe_resource *
+renderer_clone_texture(struct xorg_renderer *r,
+ struct pipe_resource *src)
+{
+ enum pipe_format format;
+ struct pipe_context *pipe = r->pipe;
+ struct pipe_screen *screen = pipe->screen;
+ struct pipe_resource *pt;
+ struct pipe_resource templ;
+
+ if (pipe->is_resource_referenced(pipe, src, 0, 0) &
+ PIPE_REFERENCED_FOR_WRITE)
+ pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
+
+ /* the coming in texture should already have that invariance */
+ debug_assert(screen->is_format_supported(screen, src->format,
+ PIPE_TEXTURE_2D, 0,
+ PIPE_BIND_SAMPLER_VIEW, 0));
+
+ format = src->format;
+
+ memset(&templ, 0, sizeof(templ));
+ templ.target = PIPE_TEXTURE_2D;
+ templ.format = format;
+ templ.last_level = 0;
+ templ.width0 = src->width0;
+ templ.height0 = src->height0;
+ templ.depth0 = 1;
+ templ.bind = PIPE_BIND_SAMPLER_VIEW;
+
+ pt = screen->resource_create(screen, &templ);
+
+ debug_assert(!pt || pipe_is_referenced(&pt->reference));
+
+ if (!pt)
+ return NULL;
+
+ {
+ /* copy source framebuffer surface into texture */
+ struct pipe_subresource subsrc, subdst;
+ subsrc.face = 0;
+ subsrc.level = 0;
+ subdst.face = 0;
+ subdst.level = 0;
+ pipe->resource_copy_region(pipe,
+ pt, /* dest */
+ subdst,
+ 0, 0, 0, /* destx/y/z */
+ src,
+ subsrc,
+ 0, 0, 0,
+ src->width0, src->height0);
+ }
+
+ return pt;
+}
+
+
+void renderer_copy_pixmap(struct xorg_renderer *r,
+ int dx, int dy,
+ int sx, int sy,
+ int width, int height,
+ float src_width,
+ float src_height)
+{
+ float s0, t0, s1, t1;
+ float x0, y0, x1, y1;
+
+
+ /* XXX: could put the texcoord scaling calculation into the vertex
+ * shader.
+ */
+ s0 = sx / src_width;
+ s1 = (sx + width) / src_width;
+ t0 = sy / src_height;
+ t1 = (sy + height) / src_height;
+
+ x0 = dx;
+ x1 = dx + width;
+ y0 = dy;
+ y1 = dy + height;
+
+ /* draw quad */
+ renderer_draw_conditional(r, 4*8);
+ add_vertex_1tex(r, x0, y0, s0, t0);
+ add_vertex_1tex(r, x1, y0, s1, t0);
+ add_vertex_1tex(r, x1, y1, s1, t1);
+ add_vertex_1tex(r, x0, y1, s0, t1);
+}
+
+
+
+
+void renderer_draw_yuv(struct xorg_renderer *r,
+ float src_x, float src_y, float src_w, float src_h,
+ int dst_x, int dst_y, int dst_w, int dst_h,
+ struct pipe_resource **textures)
+{
+ struct pipe_context *pipe = r->pipe;
+ struct pipe_resource *buf = 0;
+
+ buf = setup_vertex_data_yuv(r,
+ src_x, src_y, src_w, src_h,
+ dst_x, dst_y, dst_w, dst_h,
+ textures);
+
+ if (buf) {
+ const int num_attribs = 2; /*pos + tex coord*/
+
+ cso_set_vertex_elements(r->cso, num_attribs, r->velems);
+
+ util_draw_vertex_buffer(pipe, buf, 0,
+ PIPE_PRIM_QUADS,
+ 4, /* verts */
+ num_attribs); /* attribs/vert */
+
+ pipe_resource_reference(&buf, NULL);
+ }
+}
+
+void renderer_begin_solid(struct xorg_renderer *r)
+{
+ r->buffer_size = 0;
+ r->attrs_per_vertex = 2;
+}
+
+void renderer_solid(struct xorg_renderer *r,
+ int x0, int y0,
+ int x1, int y1,
+ float *color)
+{
+ /*
+ debug_printf("solid rect[(%d, %d), (%d, %d)], rgba[%f, %f, %f, %f]\n",
+ x0, y0, x1, y1, color[0], color[1], color[2], color[3]);*/
+
+ renderer_draw_conditional(r, 4 * 8);
+
+ /* 1st vertex */
+ add_vertex_color(r, x0, y0, color);
+ /* 2nd vertex */
+ add_vertex_color(r, x1, y0, color);
+ /* 3rd vertex */
+ add_vertex_color(r, x1, y1, color);
+ /* 4th vertex */
+ add_vertex_color(r, x0, y1, color);
+}
+
+void renderer_draw_flush(struct xorg_renderer *r)
+{
+ renderer_draw_conditional(r, 0);
+}
+
+void renderer_begin_textures(struct xorg_renderer *r,
+ int num_textures)
+{
+ r->attrs_per_vertex = 1 + num_textures;
+ r->buffer_size = 0;
+}
+
+void renderer_texture(struct xorg_renderer *r,
+ int *pos,
+ int width, int height,
+ struct pipe_sampler_view **sampler_view,
+ int num_textures,
+ float *src_matrix,
+ float *mask_matrix)
+{
+
+#if 0
+ if (src_matrix) {
+ debug_printf("src_matrix = \n");
+ debug_printf("%f, %f, %f\n", src_matrix[0], src_matrix[1], src_matrix[2]);
+ debug_printf("%f, %f, %f\n", src_matrix[3], src_matrix[4], src_matrix[5]);
+ debug_printf("%f, %f, %f\n", src_matrix[6], src_matrix[7], src_matrix[8]);
+ }
+ if (mask_matrix) {
+ debug_printf("mask_matrix = \n");
+ debug_printf("%f, %f, %f\n", mask_matrix[0], mask_matrix[1], mask_matrix[2]);
+ debug_printf("%f, %f, %f\n", mask_matrix[3], mask_matrix[4], mask_matrix[5]);
+ debug_printf("%f, %f, %f\n", mask_matrix[6], mask_matrix[7], mask_matrix[8]);
+ }
+#endif
+
+ switch(r->attrs_per_vertex) {
+ case 2:
+ renderer_draw_conditional(r, 4 * 8);
+ add_vertex_data1(r,
+ pos[0], pos[1], /* src */
+ pos[4], pos[5], /* dst */
+ width, height,
+ sampler_view[0]->texture, src_matrix);
+ break;
+ case 3:
+ renderer_draw_conditional(r, 4 * 12);
+ add_vertex_data2(r,
+ pos[0], pos[1], /* src */
+ pos[2], pos[3], /* mask */
+ pos[4], pos[5], /* dst */
+ width, height,
+ sampler_view[0]->texture, sampler_view[1]->texture,
+ src_matrix, mask_matrix);
+ break;
+ default:
+ debug_assert(!"Unsupported number of textures");
+ break;
+ }
+}
diff --git a/src/gallium/state_trackers/xorg/xorg_renderer.h b/src/gallium/state_trackers/xorg/xorg_renderer.h
new file mode 100644
index 0000000000..fb09fabe15
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xorg_renderer.h
@@ -0,0 +1,96 @@
+#ifndef XORG_RENDERER_H
+#define XORG_RENDERER_H
+
+#include "pipe/p_context.h"
+#include "pipe/p_state.h"
+
+struct xorg_shaders;
+struct exa_pixmap_priv;
+
+/* max number of vertices *
+ * max number of attributes per vertex *
+ * max number of components per attribute
+ *
+ * currently the max is 100 quads
+ */
+#define BUF_SIZE (100 * 4 * 3 * 4)
+
+struct xorg_renderer {
+ struct pipe_context *pipe;
+
+ struct cso_context *cso;
+ struct xorg_shaders *shaders;
+
+ int fb_width;
+ int fb_height;
+ struct pipe_resource *vs_const_buffer;
+ struct pipe_resource *fs_const_buffer;
+
+ float buffer[BUF_SIZE];
+ int buffer_size;
+ struct pipe_vertex_element velems[3];
+
+ /* number of attributes per vertex for the current
+ * draw operation */
+ int attrs_per_vertex;
+};
+
+struct xorg_renderer *renderer_create(struct pipe_context *pipe);
+void renderer_destroy(struct xorg_renderer *renderer);
+
+void renderer_bind_destination(struct xorg_renderer *r,
+ struct pipe_surface *surface,
+ int width,
+ int height );
+
+void renderer_bind_framebuffer(struct xorg_renderer *r,
+ struct exa_pixmap_priv *priv);
+void renderer_bind_viewport(struct xorg_renderer *r,
+ struct exa_pixmap_priv *dst);
+void renderer_set_constants(struct xorg_renderer *r,
+ int shader_type,
+ const float *buffer,
+ int size);
+
+
+void renderer_draw_yuv(struct xorg_renderer *r,
+ float src_x, float src_y, float src_w, float src_h,
+ int dst_x, int dst_y, int dst_w, int dst_h,
+ struct pipe_resource **textures);
+
+void renderer_begin_solid(struct xorg_renderer *r);
+void renderer_solid(struct xorg_renderer *r,
+ int x0, int y0,
+ int x1, int y1,
+ float *color);
+
+void renderer_begin_textures(struct xorg_renderer *r,
+ int num_textures);
+
+void renderer_texture(struct xorg_renderer *r,
+ int *pos,
+ int width, int height,
+ struct pipe_sampler_view **textures,
+ int num_textures,
+ float *src_matrix,
+ float *mask_matrix);
+
+void renderer_draw_flush(struct xorg_renderer *r);
+
+struct pipe_resource *
+renderer_clone_texture(struct xorg_renderer *r,
+ struct pipe_resource *src);
+
+void renderer_copy_prepare(struct xorg_renderer *r,
+ struct pipe_surface *dst_surface,
+ struct pipe_resource *src_texture);
+
+void renderer_copy_pixmap(struct xorg_renderer *r,
+ int dx, int dy,
+ int sx, int sy,
+ int width, int height,
+ float src_width,
+ float src_height);
+
+
+#endif
diff --git a/src/gallium/state_trackers/xorg/xorg_tracker.h b/src/gallium/state_trackers/xorg/xorg_tracker.h
new file mode 100644
index 0000000000..df56ad1b15
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xorg_tracker.h
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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.
+ *
+ *
+ * Author: Alan Hourihane <alanh@tungstengraphics.com>
+ * Author: Jakob Bornecrantz <wallbraker@gmail.com>
+ *
+ */
+
+#ifndef _XORG_TRACKER_H_
+#define _XORG_TRACKER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <errno.h>
+#include <drm.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <xorg-server.h>
+#include <xf86.h>
+#include "xf86Crtc.h"
+#include <exa.h>
+
+#ifdef DRM_MODE_FEATURE_DIRTYFB
+#include <damage.h>
+#endif
+
+#include "pipe/p_screen.h"
+#include "util/u_inlines.h"
+#include "util/u_debug.h"
+#include "state_tracker/drm_api.h"
+
+#define DRV_ERROR(msg) xf86DrvMsg(pScrn->scrnIndex, X_ERROR, msg);
+
+struct kms_bo;
+struct kms_driver;
+struct exa_context;
+
+typedef struct
+{
+ int lastInstance;
+ int refCount;
+ ScrnInfoPtr pScrn_1;
+ ScrnInfoPtr pScrn_2;
+} EntRec, *EntPtr;
+
+#define XORG_NR_FENCES 3
+
+enum xorg_throttling_reason {
+ THROTTLE_RENDER,
+ THROTTLE_SWAP
+};
+
+typedef struct _CustomizerRec
+{
+ Bool dirty_throttling;
+ Bool swap_throttling;
+ Bool no_3d;
+ Bool (*winsys_screen_init)(struct _CustomizerRec *cust, int fd);
+ Bool (*winsys_screen_close)(struct _CustomizerRec *cust);
+ Bool (*winsys_enter_vt)(struct _CustomizerRec *cust);
+ Bool (*winsys_leave_vt)(struct _CustomizerRec *cust);
+ void (*winsys_context_throttle)(struct _CustomizerRec *cust,
+ struct pipe_context *pipe,
+ enum xorg_throttling_reason reason);
+} CustomizerRec, *CustomizerPtr;
+
+typedef struct _modesettingRec
+{
+ /* drm */
+ int fd;
+ unsigned fb_id;
+
+ /* X */
+ EntPtr entityPrivate;
+
+ int Chipset;
+ EntityInfoPtr pEnt;
+ struct pci_device *PciInfo;
+
+ Bool noAccel;
+ Bool SWCursor;
+ CursorPtr cursor;
+ Bool swapThrottling;
+ Bool dirtyThrottling;
+ CloseScreenProcPtr CloseScreen;
+ Bool no3D;
+
+ /* Broken-out options. */
+ OptionInfoPtr Options;
+
+ void (*blockHandler)(int, pointer, pointer, pointer);
+ struct pipe_fence_handle *fence[XORG_NR_FENCES];
+
+ CreateScreenResourcesProcPtr createScreenResources;
+
+ /* for frontbuffer backing store */
+ Bool (*destroy_front_buffer)(ScrnInfoPtr pScrn);
+ Bool (*create_front_buffer)(ScrnInfoPtr pScrn);
+ Bool (*bind_front_buffer)(ScrnInfoPtr pScrn);
+
+ /* kms */
+ struct kms_driver *kms;
+ struct kms_bo *root_bo;
+
+ /* gallium */
+ struct drm_api *api;
+ struct pipe_screen *screen;
+ struct pipe_context *ctx;
+ boolean d_depth_bits_last;
+ boolean ds_depth_bits_last;
+ struct pipe_resource *root_texture;
+
+ /* exa */
+ struct exa_context *exa;
+ Bool noEvict;
+ Bool accelerate_2d;
+ Bool debug_fallback;
+
+ CustomizerPtr cust;
+
+#ifdef DRM_MODE_FEATURE_DIRTYFB
+ DamagePtr damage;
+#endif
+} modesettingRec, *modesettingPtr;
+
+#define modesettingPTR(p) ((modesettingPtr)((p)->driverPrivate))
+
+CustomizerPtr xorg_customizer(ScrnInfoPtr pScrn);
+
+Bool xorg_has_gallium(ScrnInfoPtr pScrn);
+
+/***********************************************************************
+ * xorg_exa.c
+ */
+struct pipe_resource *
+xorg_exa_get_texture(PixmapPtr pPixmap);
+
+int
+xorg_exa_set_displayed_usage(PixmapPtr pPixmap);
+
+int
+xorg_exa_set_shared_usage(PixmapPtr pPixmap);
+
+Bool
+xorg_exa_set_texture(PixmapPtr pPixmap, struct pipe_resource *tex);
+
+struct pipe_resource *
+xorg_exa_create_root_texture(ScrnInfoPtr pScrn,
+ int width, int height,
+ int depth, int bpp);
+
+void *
+xorg_exa_init(ScrnInfoPtr pScrn, Bool accel);
+
+void
+xorg_exa_close(ScrnInfoPtr pScrn);
+
+
+/***********************************************************************
+ * xorg_dri2.c
+ */
+Bool
+xorg_dri2_init(ScreenPtr pScreen);
+
+void
+xorg_dri2_close(ScreenPtr pScreen);
+
+
+/***********************************************************************
+ * xorg_crtc.c
+ */
+void
+xorg_crtc_init(ScrnInfoPtr pScrn);
+
+void
+xorg_crtc_cursor_destroy(xf86CrtcPtr crtc);
+
+
+/***********************************************************************
+ * xorg_output.c
+ */
+void
+xorg_output_init(ScrnInfoPtr pScrn);
+
+unsigned
+xorg_output_get_id(xf86OutputPtr output);
+
+
+/***********************************************************************
+ * xorg_xv.c
+ */
+void
+xorg_xv_init(ScreenPtr pScreen);
+
+
+#endif /* _XORG_TRACKER_H_ */
diff --git a/src/gallium/state_trackers/xorg/xorg_winsys.h b/src/gallium/state_trackers/xorg/xorg_winsys.h
new file mode 100644
index 0000000000..865733bca2
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xorg_winsys.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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 TUNGSTEN GRAPHICS 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.
+ *
+ *
+ * Author: Alan Hourihane <alanh@tungstengraphics.com>
+ * Author: Jakob Bornecrantz <wallbraker@gmail.com>
+ *
+ */
+
+/*
+ * File with all the junk needed to personalize the a xorg driver.
+ */
+
+#ifndef _XORG_WINSYS_H_
+#define _XORG_WINSYS_H_
+
+#include "xorg-server.h"
+#include "xf86.h"
+#include "pciaccess.h"
+
+#ifndef XSERVER_LIBPCIACCESS
+#error "libpciaccess needed"
+#endif
+
+void xorg_tracker_set_functions(ScrnInfoPtr scrn);
+const OptionInfoRec * xorg_tracker_available_options(int chipid, int busid);
+Bool xorg_tracker_have_modesetting(ScrnInfoPtr pScrn, struct pci_device *device);
+
+#endif
diff --git a/src/gallium/state_trackers/xorg/xorg_xv.c b/src/gallium/state_trackers/xorg/xorg_xv.c
new file mode 100644
index 0000000000..f98bd93901
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xorg_xv.c
@@ -0,0 +1,768 @@
+#include "xorg_tracker.h"
+
+#include <xf86xv.h>
+#include <X11/extensions/Xv.h>
+#include <fourcc.h>
+
+#include "xorg_exa.h"
+#include "xorg_renderer.h"
+#include "xorg_exa_tgsi.h"
+
+#include "cso_cache/cso_context.h"
+#include "util/u_sampler.h"
+
+#include "pipe/p_screen.h"
+
+/*XXX get these from pipe's texture limits */
+#define IMAGE_MAX_WIDTH 2048
+#define IMAGE_MAX_HEIGHT 2048
+
+#define RES_720P_X 1280
+#define RES_720P_Y 720
+
+
+/* The ITU-R BT.601 conversion matrix for SDTV. */
+/* original, matrix, but we transpose it to
+ * make the shader easier
+static const float bt_601[] = {
+ 1.0, 0.0, 1.4075, ,
+ 1.0, -0.3455, -0.7169, 0,
+ 1.0, 1.7790, 0., 0,
+};*/
+static const float bt_601[] = {
+ 1.0, 1.0, 1.0, 0.5,
+ 0.0, -0.3455, 1.7790, 0,
+ 1.4075, -0.7169, 0., 0,
+};
+
+/* The ITU-R BT.709 conversion matrix for HDTV. */
+/* original, but we transpose to make the conversion
+ * in the shader easier
+static const float bt_709[] = {
+ 1.0, 0.0, 1.581, 0,
+ 1.0, -0.1881, -0.47, 0,
+ 1.0, 1.8629, 0., 0,
+};*/
+static const float bt_709[] = {
+ 1.0, 1.0, 1.0, 0.5,
+ 0.0, -0.1881, 1.8629, 0,
+ 1.581,-0.47 , 0.0, 0,
+};
+
+#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
+
+static Atom xvBrightness, xvContrast;
+
+#define NUM_TEXTURED_ATTRIBUTES 2
+static XF86AttributeRec TexturedAttributes[NUM_TEXTURED_ATTRIBUTES] = {
+ {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"},
+ {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"}
+};
+
+#define NUM_FORMATS 3
+static XF86VideoFormatRec Formats[NUM_FORMATS] = {
+ {15, TrueColor}, {16, TrueColor}, {24, TrueColor}
+};
+
+static XF86VideoEncodingRec DummyEncoding[1] = {
+ {
+ 0,
+ "XV_IMAGE",
+ IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT,
+ {1, 1}
+ }
+};
+
+#define NUM_IMAGES 3
+static XF86ImageRec Images[NUM_IMAGES] = {
+ XVIMAGE_UYVY,
+ XVIMAGE_YUY2,
+ XVIMAGE_YV12,
+};
+
+struct xorg_xv_port_priv {
+ struct xorg_renderer *r;
+
+ RegionRec clip;
+
+ int brightness;
+ int contrast;
+
+ int current_set;
+ /* juggle two sets of seperate Y, U and V
+ * textures */
+ struct pipe_resource *yuv[2][3];
+ struct pipe_sampler_view *yuv_views[2][3];
+};
+
+
+static void
+stop_video(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
+{
+ struct xorg_xv_port_priv *priv = (struct xorg_xv_port_priv *)data;
+
+ REGION_EMPTY(pScrn->pScreen, &priv->clip);
+}
+
+static int
+set_port_attribute(ScrnInfoPtr pScrn,
+ Atom attribute, INT32 value, pointer data)
+{
+ struct xorg_xv_port_priv *priv = (struct xorg_xv_port_priv *)data;
+
+ if (attribute == xvBrightness) {
+ if ((value < -128) || (value > 127))
+ return BadValue;
+ priv->brightness = value;
+ } else if (attribute == xvContrast) {
+ if ((value < 0) || (value > 255))
+ return BadValue;
+ priv->contrast = value;
+ } else
+ return BadMatch;
+
+ return Success;
+}
+
+static int
+get_port_attribute(ScrnInfoPtr pScrn,
+ Atom attribute, INT32 * value, pointer data)
+{
+ struct xorg_xv_port_priv *priv = (struct xorg_xv_port_priv *)data;
+
+ if (attribute == xvBrightness)
+ *value = priv->brightness;
+ else if (attribute == xvContrast)
+ *value = priv->contrast;
+ else
+ return BadMatch;
+
+ return Success;
+}
+
+static void
+query_best_size(ScrnInfoPtr pScrn,
+ Bool motion,
+ short vid_w, short vid_h,
+ short drw_w, short drw_h,
+ unsigned int *p_w, unsigned int *p_h, pointer data)
+{
+ if (vid_w > (drw_w << 1))
+ drw_w = vid_w >> 1;
+ if (vid_h > (drw_h << 1))
+ drw_h = vid_h >> 1;
+
+ *p_w = drw_w;
+ *p_h = drw_h;
+}
+
+static INLINE struct pipe_resource *
+create_component_texture(struct pipe_context *pipe,
+ int width, int height)
+{
+ struct pipe_screen *screen = pipe->screen;
+ struct pipe_resource *tex = 0;
+ struct pipe_resource templ;
+
+ memset(&templ, 0, sizeof(templ));
+ templ.target = PIPE_TEXTURE_2D;
+ templ.format = PIPE_FORMAT_L8_UNORM;
+ templ.last_level = 0;
+ templ.width0 = width;
+ templ.height0 = height;
+ templ.depth0 = 1;
+ templ.bind = PIPE_BIND_SAMPLER_VIEW;
+
+ tex = screen->resource_create(screen, &templ);
+
+ return tex;
+}
+
+static int
+check_yuv_textures(struct xorg_xv_port_priv *priv, int width, int height)
+{
+ struct pipe_resource **dst = priv->yuv[priv->current_set];
+ struct pipe_sampler_view **dst_view = priv->yuv_views[priv->current_set];
+ struct pipe_sampler_view view_templ;
+ struct pipe_context *pipe = priv->r->pipe;
+
+ if (!dst[0] ||
+ dst[0]->width0 != width ||
+ dst[0]->height0 != height) {
+ pipe_resource_reference(&dst[0], NULL);
+ pipe_sampler_view_reference(&dst_view[0], NULL);
+ }
+ if (!dst[1] ||
+ dst[1]->width0 != width ||
+ dst[1]->height0 != height) {
+ pipe_resource_reference(&dst[1], NULL);
+ pipe_sampler_view_reference(&dst_view[1], NULL);
+ }
+ if (!dst[2] ||
+ dst[2]->width0 != width ||
+ dst[2]->height0 != height) {
+ pipe_resource_reference(&dst[2], NULL);
+ pipe_sampler_view_reference(&dst_view[2], NULL);
+ }
+
+ if (!dst[0]) {
+ dst[0] = create_component_texture(priv->r->pipe, width, height);
+ if (dst[0]) {
+ u_sampler_view_default_template(&view_templ,
+ dst[0],
+ dst[0]->format);
+ dst_view[0] = pipe->create_sampler_view(pipe, dst[0], &view_templ);
+ }
+ }
+
+ if (!dst[1]) {
+ dst[1] = create_component_texture(priv->r->pipe, width, height);
+ if (dst[1]) {
+ u_sampler_view_default_template(&view_templ,
+ dst[1],
+ dst[1]->format);
+ dst_view[1] = pipe->create_sampler_view(pipe, dst[1], &view_templ);
+ }
+ }
+
+ if (!dst[2]) {
+ dst[2] = create_component_texture(priv->r->pipe, width, height);
+ if (dst[2]) {
+ u_sampler_view_default_template(&view_templ,
+ dst[2],
+ dst[2]->format);
+ dst_view[2] = pipe->create_sampler_view(pipe, dst[2], &view_templ);
+ }
+ }
+
+ if (!dst[0] || !dst[1] || !dst[2] || !dst_view[0] || !dst_view[1] || !dst_view[2] )
+ return BadAlloc;
+
+ return Success;
+}
+
+static int
+query_image_attributes(ScrnInfoPtr pScrn,
+ int id,
+ unsigned short *w, unsigned short *h,
+ int *pitches, int *offsets)
+{
+ int size, tmp;
+
+ if (*w > IMAGE_MAX_WIDTH)
+ *w = IMAGE_MAX_WIDTH;
+ if (*h > IMAGE_MAX_HEIGHT)
+ *h = IMAGE_MAX_HEIGHT;
+
+ *w = (*w + 1) & ~1;
+ if (offsets)
+ offsets[0] = 0;
+
+ switch (id) {
+ case FOURCC_YV12:
+ *h = (*h + 1) & ~1;
+ size = (*w + 3) & ~3;
+ if (pitches) {
+ pitches[0] = size;
+ }
+ size *= *h;
+ if (offsets) {
+ offsets[1] = size;
+ }
+ tmp = ((*w >> 1) + 3) & ~3;
+ if (pitches) {
+ pitches[1] = pitches[2] = tmp;
+ }
+ tmp *= (*h >> 1);
+ size += tmp;
+ if (offsets) {
+ offsets[2] = size;
+ }
+ size += tmp;
+ break;
+ case FOURCC_UYVY:
+ case FOURCC_YUY2:
+ default:
+ size = *w << 1;
+ if (pitches)
+ pitches[0] = size;
+ size *= *h;
+ break;
+ }
+
+ return size;
+}
+
+static void
+copy_packed_data(ScrnInfoPtr pScrn,
+ struct xorg_xv_port_priv *port,
+ int id,
+ unsigned char *buf,
+ int left,
+ int top,
+ unsigned short w, unsigned short h)
+{
+ int i, j;
+ struct pipe_resource **dst = port->yuv[port->current_set];
+ struct pipe_transfer *ytrans, *utrans, *vtrans;
+ struct pipe_context *pipe = port->r->pipe;
+ char *ymap, *vmap, *umap;
+ unsigned char y1, y2, u, v;
+ int yidx, uidx, vidx;
+ int y_array_size = w * h;
+
+ ytrans = pipe_get_transfer(pipe, dst[0],
+ 0, 0, 0,
+ PIPE_TRANSFER_WRITE,
+ left, top, w, h);
+ utrans = pipe_get_transfer(pipe, dst[1],
+ 0, 0, 0,
+ PIPE_TRANSFER_WRITE,
+ left, top, w, h);
+ vtrans = pipe_get_transfer(pipe, dst[2],
+ 0, 0, 0,
+ PIPE_TRANSFER_WRITE,
+ left, top, w, h);
+
+ ymap = (char*)pipe->transfer_map(pipe, ytrans);
+ umap = (char*)pipe->transfer_map(pipe, utrans);
+ vmap = (char*)pipe->transfer_map(pipe, vtrans);
+
+ yidx = uidx = vidx = 0;
+
+ switch (id) {
+ case FOURCC_YV12: {
+ int pitches[3], offsets[3];
+ unsigned char *y, *u, *v;
+ query_image_attributes(pScrn, FOURCC_YV12,
+ &w, &h, pitches, offsets);
+
+ y = buf + offsets[0];
+ v = buf + offsets[1];
+ u = buf + offsets[2];
+ for (i = 0; i < h; ++i) {
+ for (j = 0; j < w; ++j) {
+ int yoffset = (w*i+j);
+ int ii = (i|1), jj = (j|1);
+ int vuoffset = (w/2)*(ii/2) + (jj/2);
+ ymap[yidx++] = y[yoffset];
+ umap[uidx++] = u[vuoffset];
+ vmap[vidx++] = v[vuoffset];
+ }
+ }
+ }
+ break;
+ case FOURCC_UYVY:
+ for (i = 0; i < y_array_size; i +=2 ) {
+ /* extracting two pixels */
+ u = buf[0];
+ y1 = buf[1];
+ v = buf[2];
+ y2 = buf[3];
+ buf += 4;
+
+ ymap[yidx++] = y1;
+ ymap[yidx++] = y2;
+ umap[uidx++] = u;
+ umap[uidx++] = u;
+ vmap[vidx++] = v;
+ vmap[vidx++] = v;
+ }
+ break;
+ case FOURCC_YUY2:
+ for (i = 0; i < y_array_size; i +=2 ) {
+ /* extracting two pixels */
+ y1 = buf[0];
+ u = buf[1];
+ y2 = buf[2];
+ v = buf[3];
+
+ buf += 4;
+
+ ymap[yidx++] = y1;
+ ymap[yidx++] = y2;
+ umap[uidx++] = u;
+ umap[uidx++] = u;
+ vmap[vidx++] = v;
+ vmap[vidx++] = v;
+ }
+ break;
+ default:
+ debug_assert(!"Unsupported yuv format!");
+ break;
+ }
+
+ pipe->transfer_unmap(pipe, ytrans);
+ pipe->transfer_unmap(pipe, utrans);
+ pipe->transfer_unmap(pipe, vtrans);
+ pipe->transfer_destroy(pipe, ytrans);
+ pipe->transfer_destroy(pipe, utrans);
+ pipe->transfer_destroy(pipe, vtrans);
+}
+
+
+static void
+setup_fs_video_constants(struct xorg_renderer *r, boolean hdtv)
+{
+ const int param_bytes = 12 * sizeof(float);
+ const float *video_constants = (hdtv) ? bt_709 : bt_601;
+
+ renderer_set_constants(r, PIPE_SHADER_FRAGMENT,
+ video_constants, param_bytes);
+}
+
+static void
+draw_yuv(struct xorg_xv_port_priv *port,
+ float src_x, float src_y, float src_w, float src_h,
+ int dst_x, int dst_y, int dst_w, int dst_h)
+{
+ struct pipe_resource **textures = port->yuv[port->current_set];
+
+ /*debug_printf(" draw_yuv([%d, %d, %d ,%d], [%d, %d, %d, %d])\n",
+ src_x, src_y, src_w, src_h,
+ dst_x, dst_y, dst_w, dst_h);*/
+ renderer_draw_yuv(port->r,
+ src_x, src_y, src_w, src_h,
+ dst_x, dst_y, dst_w, dst_h,
+ textures);
+}
+
+static void
+bind_blend_state(struct xorg_xv_port_priv *port)
+{
+ struct pipe_blend_state blend;
+
+ memset(&blend, 0, sizeof(struct pipe_blend_state));
+ blend.rt[0].blend_enable = 0;
+ blend.rt[0].colormask = PIPE_MASK_RGBA;
+
+ /* porter&duff src */
+ blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
+
+ cso_set_blend(port->r->cso, &blend);
+}
+
+
+static void
+bind_shaders(struct xorg_xv_port_priv *port)
+{
+ unsigned vs_traits = 0, fs_traits = 0;
+ struct xorg_shader shader;
+
+ vs_traits |= VS_YUV;
+ fs_traits |= FS_YUV;
+
+ shader = xorg_shaders_get(port->r->shaders, vs_traits, fs_traits);
+ cso_set_vertex_shader_handle(port->r->cso, shader.vs);
+ cso_set_fragment_shader_handle(port->r->cso, shader.fs);
+}
+
+static INLINE void
+conditional_flush(struct pipe_context *pipe, struct pipe_resource **tex,
+ int num)
+{
+ int i;
+ for (i = 0; i < num; ++i) {
+ if (tex[i] && pipe->is_resource_referenced(pipe, tex[i], 0, 0) &
+ PIPE_REFERENCED_FOR_WRITE) {
+ pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
+ return;
+ }
+ }
+}
+
+static void
+bind_samplers(struct xorg_xv_port_priv *port)
+{
+ struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
+ struct pipe_sampler_state sampler;
+ struct pipe_resource **dst = port->yuv[port->current_set];
+ struct pipe_sampler_view **dst_views = port->yuv_views[port->current_set];
+
+ memset(&sampler, 0, sizeof(struct pipe_sampler_state));
+
+ conditional_flush(port->r->pipe, dst, 3);
+
+ sampler.wrap_s = PIPE_TEX_WRAP_CLAMP;
+ sampler.wrap_t = PIPE_TEX_WRAP_CLAMP;
+ sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR;
+ sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
+ sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST;
+ sampler.normalized_coords = 1;
+
+ samplers[0] = &sampler;
+ samplers[1] = &sampler;
+ samplers[2] = &sampler;
+
+
+ cso_set_samplers(port->r->cso, 3,
+ (const struct pipe_sampler_state **)samplers);
+ cso_set_fragment_sampler_views(port->r->cso, 3, dst_views);
+}
+
+static int
+display_video(ScrnInfoPtr pScrn, struct xorg_xv_port_priv *pPriv, int id,
+ RegionPtr dstRegion,
+ int src_x, int src_y, int src_w, int src_h,
+ int dstX, int dstY, int dst_w, int dst_h,
+ PixmapPtr pPixmap)
+{
+ modesettingPtr ms = modesettingPTR(pScrn);
+ BoxPtr pbox;
+ int nbox;
+ int dxo, dyo;
+ Bool hdtv;
+ int x, y, w, h;
+ struct exa_pixmap_priv *dst;
+ struct pipe_surface *dst_surf = NULL;
+
+ exaMoveInPixmap(pPixmap);
+ dst = exaGetPixmapDriverPrivate(pPixmap);
+
+ /*debug_printf("display_video([%d, %d, %d, %d], [%d, %d, %d, %d])\n",
+ src_x, src_y, src_w, src_h, dstX, dstY, dst_w, dst_h);*/
+
+ if (dst && !dst->tex) {
+ xorg_exa_set_shared_usage(pPixmap);
+ pScrn->pScreen->ModifyPixmapHeader(pPixmap, 0, 0, 0, 0, 0, NULL);
+ }
+
+ if (!dst || !dst->tex)
+ XORG_FALLBACK("Xv destination %s", !dst ? "!dst" : "!dst->tex");
+
+ dst_surf = xorg_gpu_surface(pPriv->r->pipe->screen, dst);
+ hdtv = ((src_w >= RES_720P_X) && (src_h >= RES_720P_Y));
+
+ REGION_TRANSLATE(pScrn->pScreen, dstRegion, -pPixmap->screen_x,
+ -pPixmap->screen_y);
+
+ dxo = dstRegion->extents.x1;
+ dyo = dstRegion->extents.y1;
+
+ pbox = REGION_RECTS(dstRegion);
+ nbox = REGION_NUM_RECTS(dstRegion);
+
+ renderer_bind_destination(pPriv->r, dst_surf,
+ dst_surf->width, dst_surf->height);
+
+ bind_blend_state(pPriv);
+ bind_shaders(pPriv);
+ bind_samplers(pPriv);
+ setup_fs_video_constants(pPriv->r, hdtv);
+
+ DamageDamageRegion(&pPixmap->drawable, dstRegion);
+
+ while (nbox--) {
+ int box_x1 = pbox->x1;
+ int box_y1 = pbox->y1;
+ int box_x2 = pbox->x2;
+ int box_y2 = pbox->y2;
+ float diff_x = (float)src_w / (float)dst_w;
+ float diff_y = (float)src_h / (float)dst_h;
+ float offset_x = box_x1 - dstX + pPixmap->screen_x;
+ float offset_y = box_y1 - dstY + pPixmap->screen_y;
+ float offset_w;
+ float offset_h;
+
+ x = box_x1;
+ y = box_y1;
+ w = box_x2 - box_x1;
+ h = box_y2 - box_y1;
+
+ offset_w = dst_w - w;
+ offset_h = dst_h - h;
+
+ draw_yuv(pPriv,
+ (float) src_x + offset_x*diff_x, (float) src_y + offset_y*diff_y,
+ (float) src_w - offset_w*diff_x, (float) src_h - offset_h*diff_y,
+ x, y, w, h);
+
+ pbox++;
+ }
+ DamageRegionProcessPending(&pPixmap->drawable);
+
+ pipe_surface_reference(&dst_surf, NULL);
+
+ return TRUE;
+}
+
+static int
+put_image(ScrnInfoPtr pScrn,
+ short src_x, short src_y,
+ short drw_x, short drw_y,
+ short src_w, short src_h,
+ short drw_w, short drw_h,
+ int id, unsigned char *buf,
+ short width, short height,
+ Bool sync, RegionPtr clipBoxes, pointer data,
+ DrawablePtr pDraw)
+{
+ struct xorg_xv_port_priv *pPriv = (struct xorg_xv_port_priv *) data;
+ ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
+ PixmapPtr pPixmap;
+ INT32 x1, x2, y1, y2;
+ BoxRec dstBox;
+ int ret;
+
+ /* Clip */
+ x1 = src_x;
+ x2 = src_x + src_w;
+ y1 = src_y;
+ y2 = src_y + src_h;
+
+ dstBox.x1 = drw_x;
+ dstBox.x2 = drw_x + drw_w;
+ dstBox.y1 = drw_y;
+ dstBox.y2 = drw_y + drw_h;
+
+ if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes,
+ width, height))
+ return Success;
+
+ ret = check_yuv_textures(pPriv, width, height);
+
+ if (ret)
+ return ret;
+
+ copy_packed_data(pScrn, pPriv, id, buf,
+ src_x, src_y, width, height);
+
+ if (pDraw->type == DRAWABLE_WINDOW) {
+ pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr)pDraw);
+ } else {
+ pPixmap = (PixmapPtr)pDraw;
+ }
+
+ display_video(pScrn, pPriv, id, clipBoxes,
+ src_x, src_y, src_w, src_h,
+ drw_x, drw_y,
+ drw_w, drw_h, pPixmap);
+
+ pPriv->current_set = (pPriv->current_set + 1) & 1;
+ return Success;
+}
+
+static struct xorg_xv_port_priv *
+port_priv_create(struct xorg_renderer *r)
+{
+ struct xorg_xv_port_priv *priv = NULL;
+
+ priv = calloc(1, sizeof(struct xorg_xv_port_priv));
+
+ if (!priv)
+ return NULL;
+
+ priv->r = r;
+
+ REGION_NULL(pScreen, &priv->clip);
+
+ debug_assert(priv && priv->r);
+
+ return priv;
+}
+
+static XF86VideoAdaptorPtr
+xorg_setup_textured_adapter(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ XF86VideoAdaptorPtr adapt;
+ XF86AttributePtr attrs;
+ DevUnion *dev_unions;
+ int nports = 16, i;
+ int nattributes;
+
+ nattributes = NUM_TEXTURED_ATTRIBUTES;
+
+ debug_assert(ms->exa);
+ debug_assert(ms->exa->renderer);
+
+ adapt = calloc(1, sizeof(XF86VideoAdaptorRec));
+ dev_unions = calloc(nports, sizeof(DevUnion));
+ attrs = calloc(nattributes, sizeof(XF86AttributeRec));
+ if (adapt == NULL || dev_unions == NULL || attrs == NULL) {
+ free(adapt);
+ free(dev_unions);
+ free(attrs);
+ return NULL;
+ }
+
+ adapt->type = XvWindowMask | XvInputMask | XvImageMask;
+ adapt->flags = 0;
+ adapt->name = "Gallium3D Textured Video";
+ adapt->nEncodings = 1;
+ adapt->pEncodings = DummyEncoding;
+ adapt->nFormats = NUM_FORMATS;
+ adapt->pFormats = Formats;
+ adapt->nPorts = 0;
+ adapt->pPortPrivates = dev_unions;
+ adapt->nAttributes = nattributes;
+ adapt->pAttributes = attrs;
+ memcpy(attrs, TexturedAttributes, nattributes * sizeof(XF86AttributeRec));
+ adapt->nImages = NUM_IMAGES;
+ adapt->pImages = Images;
+ adapt->PutVideo = NULL;
+ adapt->PutStill = NULL;
+ adapt->GetVideo = NULL;
+ adapt->GetStill = NULL;
+ adapt->StopVideo = stop_video;
+ adapt->SetPortAttribute = set_port_attribute;
+ adapt->GetPortAttribute = get_port_attribute;
+ adapt->QueryBestSize = query_best_size;
+ adapt->PutImage = put_image;
+ adapt->QueryImageAttributes = query_image_attributes;
+
+ for (i = 0; i < nports; i++) {
+ struct xorg_xv_port_priv *priv =
+ port_priv_create(ms->exa->renderer);
+
+ adapt->pPortPrivates[i].ptr = (pointer) (priv);
+ adapt->nPorts++;
+ }
+
+ return adapt;
+}
+
+void
+xorg_xv_init(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ /*modesettingPtr ms = modesettingPTR(pScrn);*/
+ XF86VideoAdaptorPtr *adaptors, *new_adaptors = NULL;
+ XF86VideoAdaptorPtr textured_adapter;
+ int num_adaptors;
+
+ num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
+ new_adaptors = malloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr *));
+ if (new_adaptors == NULL)
+ return;
+
+ memcpy(new_adaptors, adaptors, num_adaptors * sizeof(XF86VideoAdaptorPtr));
+ adaptors = new_adaptors;
+
+ /* Add the adaptors supported by our hardware. First, set up the atoms
+ * that will be used by both output adaptors.
+ */
+ xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
+ xvContrast = MAKE_ATOM("XV_CONTRAST");
+
+ textured_adapter = xorg_setup_textured_adapter(pScreen);
+
+ debug_assert(textured_adapter);
+
+ if (textured_adapter) {
+ adaptors[num_adaptors++] = textured_adapter;
+ }
+
+ if (num_adaptors) {
+ xf86XVScreenInit(pScreen, adaptors, num_adaptors);
+ } else {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "Disabling Xv because no adaptors could be initialized.\n");
+ }
+
+ free(adaptors);
+}