summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/driclient/src/Makefile19
-rw-r--r--src/gallium/auxiliary/Makefile16
-rw-r--r--src/gallium/auxiliary/SConscript11
-rw-r--r--src/gallium/auxiliary/util/u_format.csv8
-rw-r--r--src/gallium/auxiliary/util/u_format_yuv.c135
-rw-r--r--src/gallium/auxiliary/util/u_format_yuv.h135
-rw-r--r--src/gallium/auxiliary/util/u_video.h71
-rw-r--r--src/gallium/auxiliary/vl/vl_bitstream_parser.c167
-rw-r--r--src/gallium/auxiliary/vl/vl_bitstream_parser.h63
-rw-r--r--src/gallium/auxiliary/vl/vl_compositor.c637
-rw-r--r--src/gallium/auxiliary/vl/vl_compositor.h98
-rw-r--r--src/gallium/auxiliary/vl/vl_csc.c206
-rw-r--r--src/gallium/auxiliary/vl/vl_csc.h53
-rw-r--r--src/gallium/auxiliary/vl/vl_idct.c766
-rw-r--r--src/gallium/auxiliary/vl/vl_idct.h124
-rw-r--r--src/gallium/auxiliary/vl/vl_mpeg12_mc_renderer.c1120
-rw-r--r--src/gallium/auxiliary/vl/vl_mpeg12_mc_renderer.h140
-rw-r--r--src/gallium/auxiliary/vl/vl_types.h46
-rw-r--r--src/gallium/auxiliary/vl/vl_vertex_buffers.c183
-rw-r--r--src/gallium/auxiliary/vl/vl_vertex_buffers.h78
-rw-r--r--src/gallium/drivers/nv40/nv40_video_context.c47
-rw-r--r--src/gallium/drivers/nv40/nv40_video_context.h38
-rw-r--r--src/gallium/drivers/nvfx/Makefile3
-rw-r--r--src/gallium/drivers/nvfx/nvfx_screen.c2
-rw-r--r--src/gallium/drivers/nvfx/nvfx_state.h1
-rw-r--r--src/gallium/drivers/nvfx/nvfx_video_context.c48
-rw-r--r--src/gallium/drivers/nvfx/nvfx_video_context.h38
-rw-r--r--src/gallium/drivers/r300/r300_video_context.c328
-rw-r--r--src/gallium/drivers/r300/r300_video_context.h40
-rw-r--r--src/gallium/drivers/r600/Makefile1
-rw-r--r--src/gallium/drivers/r600/eg_asm.c27
-rw-r--r--src/gallium/drivers/r600/r600_asm.c2007
-rw-r--r--src/gallium/drivers/r600/r600_asm.h19
-rw-r--r--src/gallium/drivers/r600/r600_pipe.c2
-rw-r--r--src/gallium/drivers/r600/r600_shader.c388
-rw-r--r--src/gallium/drivers/r600/r600_shader.h2
-rw-r--r--src/gallium/drivers/r600/r600_sq.h2
-rw-r--r--src/gallium/drivers/r600/r600_state.c11
-rw-r--r--src/gallium/drivers/r600/r600_state_inlines.h16
-rw-r--r--src/gallium/drivers/r600/r600_texture.c3
-rw-r--r--src/gallium/drivers/r600/r600_video_context.c21
-rw-r--r--src/gallium/drivers/r600/r600_video_context.h11
-rw-r--r--src/gallium/drivers/r600/r700_asm.c11
-rw-r--r--src/gallium/drivers/softpipe/Makefile5
-rw-r--r--src/gallium/drivers/softpipe/SConscript1
-rw-r--r--src/gallium/drivers/softpipe/sp_screen.c2
-rw-r--r--src/gallium/drivers/softpipe/sp_texture.h1
-rw-r--r--src/gallium/drivers/softpipe/sp_video_context.c645
-rw-r--r--src/gallium/drivers/softpipe/sp_video_context.h70
-rw-r--r--src/gallium/include/pipe/p_defines.h24
-rw-r--r--src/gallium/include/pipe/p_format.h32
-rw-r--r--src/gallium/include/pipe/p_screen.h7
-rw-r--r--src/gallium/include/pipe/p_video_context.h182
-rw-r--r--src/gallium/include/pipe/p_video_state.h133
-rw-r--r--src/gallium/state_trackers/vdpau/Makefile15
-rw-r--r--src/gallium/state_trackers/vdpau/device.c98
-rw-r--r--src/gallium/state_trackers/vdpau/ftab.c122
-rw-r--r--src/gallium/state_trackers/vdpau/htab.c94
-rw-r--r--src/gallium/state_trackers/vdpau/query.c171
-rw-r--r--src/gallium/state_trackers/vdpau/vdpau_private.h59
-rw-r--r--src/gallium/state_trackers/xorg/xvmc/Makefile16
-rw-r--r--src/gallium/state_trackers/xorg/xvmc/attributes.c50
-rw-r--r--src/gallium/state_trackers/xorg/xvmc/block.c92
-rw-r--r--src/gallium/state_trackers/xorg/xvmc/context.c298
-rw-r--r--src/gallium/state_trackers/xorg/xvmc/subpicture.c443
-rw-r--r--src/gallium/state_trackers/xorg/xvmc/surface.c525
-rw-r--r--src/gallium/state_trackers/xorg/xvmc/tests/.gitignore6
-rw-r--r--src/gallium/state_trackers/xorg/xvmc/tests/Makefile31
-rw-r--r--src/gallium/state_trackers/xorg/xvmc/tests/test_blocks.c111
-rw-r--r--src/gallium/state_trackers/xorg/xvmc/tests/test_context.c119
-rw-r--r--src/gallium/state_trackers/xorg/xvmc/tests/test_rendering.c317
-rw-r--r--src/gallium/state_trackers/xorg/xvmc/tests/test_subpicture.c182
-rw-r--r--src/gallium/state_trackers/xorg/xvmc/tests/test_surface.c98
-rw-r--r--src/gallium/state_trackers/xorg/xvmc/tests/testlib.c146
-rw-r--r--src/gallium/state_trackers/xorg/xvmc/tests/testlib.h69
-rw-r--r--src/gallium/state_trackers/xorg/xvmc/tests/xvmc_bench.c300
-rw-r--r--src/gallium/state_trackers/xorg/xvmc/xvmc_private.h102
-rw-r--r--src/gallium/targets/Makefile.vdpau61
-rw-r--r--src/gallium/targets/Makefile.xvmc62
-rw-r--r--src/gallium/targets/dri-nouveau/Makefile1
-rw-r--r--src/gallium/targets/vdpau-softpipe/Makefile19
-rw-r--r--src/gallium/targets/xvmc-nouveau/Makefile23
-rw-r--r--src/gallium/targets/xvmc-r600/Makefile23
-rw-r--r--src/gallium/targets/xvmc-r600/target.c24
-rw-r--r--src/gallium/targets/xvmc-softpipe/Makefile19
-rw-r--r--src/gallium/winsys/g3dvl/Makefile12
-rw-r--r--src/gallium/winsys/g3dvl/dri/Makefile15
-rw-r--r--src/gallium/winsys/g3dvl/dri/XF86dri.c (renamed from src/driclient/src/XF86dri.c)0
-rw-r--r--src/gallium/winsys/g3dvl/dri/dri2.c669
-rw-r--r--src/gallium/winsys/g3dvl/dri/dri2.h106
-rw-r--r--src/gallium/winsys/g3dvl/dri/dri_winsys.c282
-rw-r--r--src/gallium/winsys/g3dvl/dri/driclient.c (renamed from src/driclient/src/driclient.c)90
-rw-r--r--src/gallium/winsys/g3dvl/dri/driclient.h (renamed from src/driclient/include/driclient.h)20
-rw-r--r--src/gallium/winsys/g3dvl/dri/xf86dri.h (renamed from src/driclient/include/xf86dri.h)0
-rw-r--r--src/gallium/winsys/g3dvl/dri/xf86dristr.h (renamed from src/driclient/src/xf86dristr.h)0
-rw-r--r--src/gallium/winsys/g3dvl/drm/Makefile12
-rw-r--r--src/gallium/winsys/g3dvl/drm/Makefile.template66
-rw-r--r--src/gallium/winsys/g3dvl/drm/nouveau/Makefile23
-rw-r--r--src/gallium/winsys/g3dvl/drm/radeon/Makefile20
-rw-r--r--src/gallium/winsys/g3dvl/vl_winsys.h69
-rw-r--r--src/gallium/winsys/g3dvl/xlib/xsp_winsys.c202
101 files changed, 12863 insertions, 663 deletions
diff --git a/src/driclient/src/Makefile b/src/driclient/src/Makefile
deleted file mode 100644
index 34435a2086e..00000000000
--- a/src/driclient/src/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-TARGET = libdriclient.a
-OBJECTS = driclient.o XF86dri.o
-DRMDIR ?= /usr
-
-CFLAGS += -g -Wall -fPIC -I../include -I${DRMDIR}/include -I${DRMDIR}/include/drm
-
-#############################################
-
-.PHONY = all clean
-
-all: ${TARGET}
-
-${TARGET}: ${OBJECTS}
- ar rcs $@ $^
- if ! test -d ../lib; then mkdir ../lib; fi
- cp ${TARGET} ../lib
-
-clean:
- rm -rf ${OBJECTS} ${TARGET} ../lib/${TARGET}
diff --git a/src/gallium/auxiliary/Makefile b/src/gallium/auxiliary/Makefile
index ff355c47832..6cf1ddd43fe 100644
--- a/src/gallium/auxiliary/Makefile
+++ b/src/gallium/auxiliary/Makefile
@@ -142,14 +142,13 @@ C_SOURCES = \
util/u_tile.c \
util/u_transfer.c \
util/u_resource.c \
- util/u_upload_mgr.c
-
- # Disabling until pipe-video branch gets merged in
- #vl/vl_bitstream_parser.c \
- #vl/vl_mpeg12_mc_renderer.c \
- #vl/vl_compositor.c \
- #vl/vl_csc.c \
- #vl/vl_shader_build.c \
+ util/u_upload_mgr.c \
+ vl/vl_bitstream_parser.c \
+ vl/vl_mpeg12_mc_renderer.c \
+ vl/vl_compositor.c \
+ vl/vl_csc.c \
+ vl/vl_idct.c \
+ vl/vl_vertex_buffers.c
GALLIVM_SOURCES = \
gallivm/lp_bld_arit.c \
@@ -220,3 +219,4 @@ util/u_format_table.c: util/u_format_table.py util/u_format_pack.py util/u_forma
util/u_half.c: util/u_half.py
$(PYTHON2) util/u_half.py > $@
+# DO NOT DELETE
diff --git a/src/gallium/auxiliary/SConscript b/src/gallium/auxiliary/SConscript
index fca7e5fd117..e6806d9a723 100644
--- a/src/gallium/auxiliary/SConscript
+++ b/src/gallium/auxiliary/SConscript
@@ -190,12 +190,11 @@ source = [
'util/u_tile.c',
'util/u_transfer.c',
'util/u_upload_mgr.c',
- # Disabling until pipe-video branch gets merged in
- #'vl/vl_bitstream_parser.c',
- #'vl/vl_mpeg12_mc_renderer.c',
- #'vl/vl_compositor.c',
- #'vl/vl_csc.c',
- #'vl/vl_shader_build.c',
+ 'vl/vl_bitstream_parser.c',
+ 'vl/vl_mpeg12_mc_renderer.c',
+ 'vl/vl_compositor.c',
+ 'vl/vl_csc.c',
+ 'target-helpers/wrap_screen.c',
]
if env['llvm']:
diff --git a/src/gallium/auxiliary/util/u_format.csv b/src/gallium/auxiliary/util/u_format.csv
index 26a0eebc544..0ae15c9cc0a 100644
--- a/src/gallium/auxiliary/util/u_format.csv
+++ b/src/gallium/auxiliary/util/u_format.csv
@@ -237,3 +237,11 @@ PIPE_FORMAT_R32G32B32A32_FIXED , plain, 1, 1, h32 , h32 , h32 , h32 , xyzw, r
PIPE_FORMAT_R10G10B10X2_USCALED , plain, 1, 1, u10 , u10 , u10 , x2 , xyz1, rgb
# A.k.a. D3DDECLTYPE_DEC3N
PIPE_FORMAT_R10G10B10X2_SNORM , plain, 1, 1, sn10, sn10, sn10 , x2 , xyz1, rgb
+
+PIPE_FORMAT_YV12 , subsampled, 1, 1, x8 , x8 , x8 , x8 , xyzw, yuv
+PIPE_FORMAT_YV16 , subsampled, 1, 1, x8 , x8 , x8 , x8 , xyzw, yuv
+PIPE_FORMAT_IYUV , subsampled, 1, 1, x8 , x8 , x8 , x8 , xyzw, yuv
+PIPE_FORMAT_NV12 , subsampled, 1, 1, x8 , x8 , x8 , x8 , xyzw, yuv
+PIPE_FORMAT_NV21 , subsampled, 1, 1, x8 , x8 , x8 , x8 , xyzw, yuv
+PIPE_FORMAT_IA44 , subsampled, 1, 1, x8 , x8 , x8 , x8 , xyzw, yuv
+PIPE_FORMAT_AI44 , subsampled, 1, 1, x8 , x8 , x8 , x8 , xyzw, yuv
diff --git a/src/gallium/auxiliary/util/u_format_yuv.c b/src/gallium/auxiliary/util/u_format_yuv.c
index ab8bf29c97b..64ea0b35347 100644
--- a/src/gallium/auxiliary/util/u_format_yuv.c
+++ b/src/gallium/auxiliary/util/u_format_yuv.c
@@ -1045,3 +1045,138 @@ util_format_yuyv_fetch_rgba_float(float *dst, const uint8_t *src,
dst[3] = 1.0f;
}
+
+/* XXX: Stubbed for now */
+void
+util_format_yv12_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_yv12_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_yv12_unpack_rgba_float(float *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_yv12_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride,
+ const float *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_yv12_fetch_rgba_float(float *dst, const uint8_t *src,
+ unsigned i, unsigned j) {}
+void
+util_format_yv16_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_yv16_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_yv16_unpack_rgba_float(float *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_yv16_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride,
+ const float *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_yv16_fetch_rgba_float(float *dst, const uint8_t *src,
+ unsigned i, unsigned j) {}
+void
+util_format_iyuv_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_iyuv_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_iyuv_unpack_rgba_float(float *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_iyuv_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride,
+ const float *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_iyuv_fetch_rgba_float(float *dst, const uint8_t *src,
+ unsigned i, unsigned j) {}
+void
+util_format_nv12_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_nv12_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_nv12_unpack_rgba_float(float *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_nv12_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride,
+ const float *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_nv12_fetch_rgba_float(float *dst, const uint8_t *src,
+ unsigned i, unsigned j) {}
+void
+util_format_nv21_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_nv21_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_nv21_unpack_rgba_float(float *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_nv21_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride,
+ const float *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_nv21_fetch_rgba_float(float *dst, const uint8_t *src,
+ unsigned i, unsigned j) {}
+void
+util_format_ia44_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_ia44_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_ia44_unpack_rgba_float(float *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_ia44_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride,
+ const float *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_ia44_fetch_rgba_float(float *dst, const uint8_t *src,
+ unsigned i, unsigned j) {}
+void
+util_format_ai44_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_ai44_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_ai44_unpack_rgba_float(float *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_ai44_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride,
+ const float *src_row, unsigned src_stride,
+ unsigned width, unsigned height) {}
+void
+util_format_ai44_fetch_rgba_float(float *dst, const uint8_t *src,
+ unsigned i, unsigned j) {}
diff --git a/src/gallium/auxiliary/util/u_format_yuv.h b/src/gallium/auxiliary/util/u_format_yuv.h
index dc9632346d1..9f2365a5266 100644
--- a/src/gallium/auxiliary/util/u_format_yuv.h
+++ b/src/gallium/auxiliary/util/u_format_yuv.h
@@ -169,6 +169,141 @@ void
util_format_yuyv_fetch_rgba_float(float *dst, const uint8_t *src,
unsigned i, unsigned j);
+/* XXX: Stubbed for now */
+void
+util_format_yv12_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_yv12_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_yv12_unpack_rgba_float(float *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_yv12_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride,
+ const float *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_yv12_fetch_rgba_float(float *dst, const uint8_t *src,
+ unsigned i, unsigned j);
+void
+util_format_yv16_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_yv16_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_yv16_unpack_rgba_float(float *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_yv16_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride,
+ const float *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_yv16_fetch_rgba_float(float *dst, const uint8_t *src,
+ unsigned i, unsigned j);
+void
+util_format_iyuv_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_iyuv_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_iyuv_unpack_rgba_float(float *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_iyuv_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride,
+ const float *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_iyuv_fetch_rgba_float(float *dst, const uint8_t *src,
+ unsigned i, unsigned j);
+void
+util_format_nv12_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_nv12_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_nv12_unpack_rgba_float(float *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_nv12_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride,
+ const float *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_nv12_fetch_rgba_float(float *dst, const uint8_t *src,
+ unsigned i, unsigned j);
+void
+util_format_nv21_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_nv21_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_nv21_unpack_rgba_float(float *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_nv21_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride,
+ const float *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_nv21_fetch_rgba_float(float *dst, const uint8_t *src,
+ unsigned i, unsigned j);
+void
+util_format_ia44_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_ia44_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_ia44_unpack_rgba_float(float *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_ia44_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride,
+ const float *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_ia44_fetch_rgba_float(float *dst, const uint8_t *src,
+ unsigned i, unsigned j);
+void
+util_format_ai44_unpack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_ai44_pack_rgba_8unorm(uint8_t *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_ai44_unpack_rgba_float(float *dst_row, unsigned dst_stride,
+ const uint8_t *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_ai44_pack_rgba_float(uint8_t *dst_row, unsigned dst_stride,
+ const float *src_row, unsigned src_stride,
+ unsigned width, unsigned height);
+void
+util_format_ai44_fetch_rgba_float(float *dst, const uint8_t *src,
+ unsigned i, unsigned j);
+
void
util_format_r8g8_b8g8_unorm_unpack_rgba_float(float *dst_row, unsigned dst_stride,
diff --git a/src/gallium/auxiliary/util/u_video.h b/src/gallium/auxiliary/util/u_video.h
new file mode 100644
index 00000000000..78cceb6bcf2
--- /dev/null
+++ b/src/gallium/auxiliary/util/u_video.h
@@ -0,0 +1,71 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 U_VIDEO_H
+#define U_VIDEO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <pipe/p_defines.h>
+
+/* u_reduce_video_profile() needs these */
+#include <pipe/p_compiler.h>
+#include <util/u_debug.h>
+
+static INLINE enum pipe_video_codec
+u_reduce_video_profile(enum pipe_video_profile profile)
+{
+ switch (profile)
+ {
+ case PIPE_VIDEO_PROFILE_MPEG1:
+ case PIPE_VIDEO_PROFILE_MPEG2_SIMPLE:
+ case PIPE_VIDEO_PROFILE_MPEG2_MAIN:
+ return PIPE_VIDEO_CODEC_MPEG12;
+
+ case PIPE_VIDEO_PROFILE_MPEG4_SIMPLE:
+ case PIPE_VIDEO_PROFILE_MPEG4_ADVANCED_SIMPLE:
+ return PIPE_VIDEO_CODEC_MPEG4;
+
+ case PIPE_VIDEO_PROFILE_VC1_SIMPLE:
+ case PIPE_VIDEO_PROFILE_VC1_MAIN:
+ case PIPE_VIDEO_PROFILE_VC1_ADVANCED:
+ return PIPE_VIDEO_CODEC_VC1;
+
+ case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE:
+ case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN:
+ case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
+ return PIPE_VIDEO_CODEC_MPEG4_AVC;
+
+ default:
+ assert(0);
+ return PIPE_VIDEO_CODEC_UNKNOWN;
+ }
+}
+
+#endif /* U_VIDEO_H */
diff --git a/src/gallium/auxiliary/vl/vl_bitstream_parser.c b/src/gallium/auxiliary/vl/vl_bitstream_parser.c
new file mode 100644
index 00000000000..3193ea5f41c
--- /dev/null
+++ b/src/gallium/auxiliary/vl/vl_bitstream_parser.c
@@ -0,0 +1,167 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 "vl_bitstream_parser.h"
+#include <assert.h>
+#include <limits.h>
+#include <util/u_memory.h>
+
+static unsigned
+grab_bits(unsigned cursor, unsigned how_many_bits, unsigned bitstream_elt)
+{
+ unsigned excess_bits = sizeof(unsigned) * CHAR_BIT - how_many_bits - cursor;
+
+ assert(cursor < sizeof(unsigned) * CHAR_BIT);
+ assert(how_many_bits > 0 && how_many_bits <= sizeof(unsigned) * CHAR_BIT);
+ assert(cursor + how_many_bits <= sizeof(unsigned) * CHAR_BIT);
+
+ return (bitstream_elt << excess_bits) >> (excess_bits + cursor);
+}
+
+static unsigned
+show_bits(unsigned cursor, unsigned how_many_bits, const unsigned *bitstream)
+{
+ unsigned cur_int = cursor / (sizeof(unsigned) * CHAR_BIT);
+ unsigned cur_bit = cursor % (sizeof(unsigned) * CHAR_BIT);
+
+ assert(bitstream);
+
+ if (cur_bit + how_many_bits > sizeof(unsigned) * CHAR_BIT) {
+ unsigned lower = grab_bits(cur_bit, sizeof(unsigned) * CHAR_BIT - cur_bit,
+ bitstream[cur_int]);
+ unsigned upper = grab_bits(0, cur_bit + how_many_bits - sizeof(unsigned) * CHAR_BIT,
+ bitstream[cur_int + 1]);
+ return lower | upper << (sizeof(unsigned) * CHAR_BIT - cur_bit);
+ }
+ else
+ return grab_bits(cur_bit, how_many_bits, bitstream[cur_int]);
+}
+
+bool vl_bitstream_parser_init(struct vl_bitstream_parser *parser,
+ unsigned num_bitstreams,
+ const void **bitstreams,
+ const unsigned *sizes)
+{
+ assert(parser);
+ assert(num_bitstreams);
+ assert(bitstreams);
+ assert(sizes);
+
+ parser->num_bitstreams = num_bitstreams;
+ parser->bitstreams = (const unsigned**)bitstreams;
+ parser->sizes = sizes;
+ parser->cur_bitstream = 0;
+ parser->cursor = 0;
+
+ return true;
+}
+
+void vl_bitstream_parser_cleanup(struct vl_bitstream_parser *parser)
+{
+ assert(parser);
+}
+
+unsigned
+vl_bitstream_parser_get_bits(struct vl_bitstream_parser *parser,
+ unsigned how_many_bits)
+{
+ unsigned bits;
+
+ assert(parser);
+
+ bits = vl_bitstream_parser_show_bits(parser, how_many_bits);
+
+ vl_bitstream_parser_forward(parser, how_many_bits);
+
+ return bits;
+}
+
+unsigned
+vl_bitstream_parser_show_bits(struct vl_bitstream_parser *parser,
+ unsigned how_many_bits)
+{
+ unsigned bits = 0;
+ unsigned shift = 0;
+ unsigned cursor;
+ unsigned cur_bitstream;
+
+ assert(parser);
+
+ cursor = parser->cursor;
+ cur_bitstream = parser->cur_bitstream;
+
+ while (1) {
+ unsigned bits_left = parser->sizes[cur_bitstream] * CHAR_BIT - cursor;
+ unsigned bits_to_show = how_many_bits > bits_left ? bits_left : how_many_bits;
+
+ bits |= show_bits(cursor, bits_to_show,
+ parser->bitstreams[cur_bitstream]) << shift;
+
+ if (how_many_bits > bits_to_show) {
+ how_many_bits -= bits_to_show;
+ cursor = 0;
+ ++cur_bitstream;
+ shift += bits_to_show;
+ }
+ else
+ break;
+ }
+
+ return bits;
+}
+
+void vl_bitstream_parser_forward(struct vl_bitstream_parser *parser,
+ unsigned how_many_bits)
+{
+ assert(parser);
+ assert(how_many_bits);
+
+ parser->cursor += how_many_bits;
+
+ while (parser->cursor > parser->sizes[parser->cur_bitstream] * CHAR_BIT) {
+ parser->cursor -= parser->sizes[parser->cur_bitstream++] * CHAR_BIT;
+ assert(parser->cur_bitstream < parser->num_bitstreams);
+ }
+}
+
+void vl_bitstream_parser_rewind(struct vl_bitstream_parser *parser,
+ unsigned how_many_bits)
+{
+ signed c;
+
+ assert(parser);
+ assert(how_many_bits);
+
+ c = parser->cursor - how_many_bits;
+
+ while (c < 0) {
+ c += parser->sizes[parser->cur_bitstream--] * CHAR_BIT;
+ assert(parser->cur_bitstream < parser->num_bitstreams);
+ }
+
+ parser->cursor = (unsigned)c;
+}
diff --git a/src/gallium/auxiliary/vl/vl_bitstream_parser.h b/src/gallium/auxiliary/vl/vl_bitstream_parser.h
new file mode 100644
index 00000000000..30ec743fa75
--- /dev/null
+++ b/src/gallium/auxiliary/vl/vl_bitstream_parser.h
@@ -0,0 +1,63 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 vl_bitstream_parser_h
+#define vl_bitstream_parser_h
+
+#include "pipe/p_compiler.h"
+
+struct vl_bitstream_parser
+{
+ unsigned num_bitstreams;
+ const unsigned **bitstreams;
+ const unsigned *sizes;
+ unsigned cur_bitstream;
+ unsigned cursor;
+};
+
+bool vl_bitstream_parser_init(struct vl_bitstream_parser *parser,
+ unsigned num_bitstreams,
+ const void **bitstreams,
+ const unsigned *sizes);
+
+void vl_bitstream_parser_cleanup(struct vl_bitstream_parser *parser);
+
+unsigned
+vl_bitstream_parser_get_bits(struct vl_bitstream_parser *parser,
+ unsigned how_many_bits);
+
+unsigned
+vl_bitstream_parser_show_bits(struct vl_bitstream_parser *parser,
+ unsigned how_many_bits);
+
+void vl_bitstream_parser_forward(struct vl_bitstream_parser *parser,
+ unsigned how_many_bits);
+
+void vl_bitstream_parser_rewind(struct vl_bitstream_parser *parser,
+ unsigned how_many_bits);
+
+#endif /* vl_bitstream_parser_h */
diff --git a/src/gallium/auxiliary/vl/vl_compositor.c b/src/gallium/auxiliary/vl/vl_compositor.c
new file mode 100644
index 00000000000..5187c635e4b
--- /dev/null
+++ b/src/gallium/auxiliary/vl/vl_compositor.c
@@ -0,0 +1,637 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 "vl_compositor.h"
+#include "util/u_draw.h"
+#include <assert.h>
+#include <pipe/p_context.h>
+#include <util/u_inlines.h>
+#include <util/u_memory.h>
+#include <util/u_keymap.h>
+#include <util/u_sampler.h>
+#include <tgsi/tgsi_ureg.h>
+#include "vl_csc.h"
+
+struct vertex_shader_consts
+{
+ struct vertex4f dst_scale;
+ struct vertex4f dst_trans;
+ struct vertex4f src_scale;
+ struct vertex4f src_trans;
+};
+
+struct fragment_shader_consts
+{
+ float matrix[16];
+};
+
+static bool
+u_video_rects_equal(struct pipe_video_rect *a, struct pipe_video_rect *b)
+{
+ assert(a && b);
+
+ if (a->x != b->x)
+ return false;
+ if (a->y != b->y)
+ return false;
+ if (a->w != b->w)
+ return false;
+ if (a->h != b->h)
+ return false;
+
+ return true;
+}
+
+static bool
+create_vert_shader(struct vl_compositor *c)
+{
+ struct ureg_program *shader;
+ struct ureg_src vpos, vtex;
+ struct ureg_dst o_vpos, o_vtex;
+
+ shader = ureg_create(TGSI_PROCESSOR_VERTEX);
+ if (!shader)
+ return false;
+
+ vpos = ureg_DECL_vs_input(shader, 0);
+ vtex = ureg_DECL_vs_input(shader, 1);
+ o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, 0);
+ o_vtex = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, 1);
+
+ /*
+ * o_vpos = vpos
+ * o_vtex = vtex
+ */
+ ureg_MOV(shader, o_vpos, vpos);
+ ureg_MOV(shader, o_vtex, vtex);
+
+ ureg_END(shader);
+
+ c->vertex_shader = ureg_create_shader_and_destroy(shader, c->pipe);
+ if (!c->vertex_shader)
+ return false;
+
+ return true;
+}
+
+static bool
+create_frag_shader_ycbcr_2_rgb(struct vl_compositor *c)
+{
+ struct ureg_program *shader;
+ struct ureg_src tc;
+ struct ureg_src csc[4];
+ struct ureg_src sampler;
+ struct ureg_dst texel;
+ struct ureg_dst fragment;
+ unsigned i;
+
+ shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
+ if (!shader)
+ return false;
+
+ tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, 1, TGSI_INTERPOLATE_LINEAR);
+ for (i = 0; i < 4; ++i)
+ csc[i] = ureg_DECL_constant(shader, i);
+ sampler = ureg_DECL_sampler(shader, 0);
+ texel = ureg_DECL_temporary(shader);
+ fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
+
+ /*
+ * texel = tex(tc, sampler)
+ * fragment = csc * texel
+ */
+ ureg_TEX(shader, texel, TGSI_TEXTURE_2D, tc, sampler);
+ for (i = 0; i < 4; ++i)
+ ureg_DP4(shader, ureg_writemask(fragment, TGSI_WRITEMASK_X << i), csc[i], ureg_src(texel));
+
+ ureg_release_temporary(shader, texel);
+ ureg_END(shader);
+
+ c->fragment_shader.ycbcr_2_rgb = ureg_create_shader_and_destroy(shader, c->pipe);
+ if (!c->fragment_shader.ycbcr_2_rgb)
+ return false;
+
+ return true;
+}
+
+static bool
+create_frag_shader_rgb_2_rgb(struct vl_compositor *c)
+{
+ struct ureg_program *shader;
+ struct ureg_src tc;
+ struct ureg_src sampler;
+ struct ureg_dst fragment;
+
+ shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
+ if (!shader)
+ return false;
+
+ tc = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, 1, TGSI_INTERPOLATE_LINEAR);
+ sampler = ureg_DECL_sampler(shader, 0);
+ fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
+
+ /*
+ * fragment = tex(tc, sampler)
+ */
+ ureg_TEX(shader, fragment, TGSI_TEXTURE_2D, tc, sampler);
+ ureg_END(shader);
+
+ c->fragment_shader.rgb_2_rgb = ureg_create_shader_and_destroy(shader, c->pipe);
+ if (!c->fragment_shader.rgb_2_rgb)
+ return false;
+
+ return true;
+}
+
+static bool
+init_pipe_state(struct vl_compositor *c)
+{
+ struct pipe_sampler_state sampler;
+
+ assert(c);
+
+ c->fb_state.nr_cbufs = 1;
+ c->fb_state.zsbuf = NULL;
+
+ 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_img_filter = PIPE_TEX_FILTER_LINEAR;
+ sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
+ sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
+ sampler.compare_mode = PIPE_TEX_COMPARE_NONE;
+ sampler.compare_func = PIPE_FUNC_ALWAYS;
+ sampler.normalized_coords = 1;
+ /*sampler.lod_bias = ;*/
+ /*sampler.min_lod = ;*/
+ /*sampler.max_lod = ;*/
+ /*sampler.border_color[i] = ;*/
+ /*sampler.max_anisotropy = ;*/
+ c->sampler = c->pipe->create_sampler_state(c->pipe, &sampler);
+
+ return true;
+}
+
+static void cleanup_pipe_state(struct vl_compositor *c)
+{
+ assert(c);
+
+ c->pipe->delete_sampler_state(c->pipe, c->sampler);
+}
+
+static bool
+init_shaders(struct vl_compositor *c)
+{
+ assert(c);
+
+ if (!create_vert_shader(c)) {
+ debug_printf("Unable to create vertex shader.\n");
+ return false;
+ }
+ if (!create_frag_shader_ycbcr_2_rgb(c)) {
+ debug_printf("Unable to create YCbCr-to-RGB fragment shader.\n");
+ return false;
+ }
+ if (!create_frag_shader_rgb_2_rgb(c)) {
+ debug_printf("Unable to create RGB-to-RGB fragment shader.\n");
+ return false;
+ }
+
+ return true;
+}
+
+static void cleanup_shaders(struct vl_compositor *c)
+{
+ assert(c);
+
+ c->pipe->delete_vs_state(c->pipe, c->vertex_shader);
+ c->pipe->delete_fs_state(c->pipe, c->fragment_shader.ycbcr_2_rgb);
+ c->pipe->delete_fs_state(c->pipe, c->fragment_shader.rgb_2_rgb);
+}
+
+static bool
+init_buffers(struct vl_compositor *c)
+{
+ struct fragment_shader_consts fsc;
+ struct pipe_vertex_element vertex_elems[2];
+
+ assert(c);
+
+ /*
+ * Create our vertex buffer and vertex buffer elements
+ */
+ c->vertex_buf.stride = sizeof(struct vertex4f);
+ c->vertex_buf.max_index = (VL_COMPOSITOR_MAX_LAYERS + 2) * 6 - 1;
+ c->vertex_buf.buffer_offset = 0;
+ /* XXX: Create with DYNAMIC or STREAM */
+ c->vertex_buf.buffer = pipe_buffer_create
+ (
+ c->pipe->screen,
+ PIPE_BIND_VERTEX_BUFFER,
+ sizeof(struct vertex4f) * (VL_COMPOSITOR_MAX_LAYERS + 2) * 6
+ );
+
+ vertex_elems[0].src_offset = 0;
+ vertex_elems[0].instance_divisor = 0;
+ vertex_elems[0].vertex_buffer_index = 0;
+ vertex_elems[0].src_format = PIPE_FORMAT_R32G32_FLOAT;
+ vertex_elems[1].src_offset = sizeof(struct vertex2f);
+ vertex_elems[1].instance_divisor = 0;
+ vertex_elems[1].vertex_buffer_index = 0;
+ vertex_elems[1].src_format = PIPE_FORMAT_R32G32_FLOAT;
+ c->vertex_elems_state = c->pipe->create_vertex_elements_state(c->pipe, 2, vertex_elems);
+
+ /*
+ * Create our fragment shader's constant buffer
+ * Const buffer contains the color conversion matrix and bias vectors
+ */
+ /* XXX: Create with IMMUTABLE/STATIC... although it does change every once in a long while... */
+ c->fs_const_buf = pipe_buffer_create
+ (
+ c->pipe->screen,
+ PIPE_BIND_CONSTANT_BUFFER,
+ sizeof(struct fragment_shader_consts)
+ );
+
+ vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_IDENTITY, NULL, true, fsc.matrix);
+
+ vl_compositor_set_csc_matrix(c, fsc.matrix);
+
+ return true;
+}
+
+static void
+cleanup_buffers(struct vl_compositor *c)
+{
+ assert(c);
+
+ c->pipe->delete_vertex_elements_state(c->pipe, c->vertex_elems_state);
+ pipe_resource_reference(&c->vertex_buf.buffer, NULL);
+ pipe_resource_reference(&c->fs_const_buf, NULL);
+}
+
+static void
+texview_map_delete(const struct keymap *map,
+ const void *key, void *data,
+ void *user)
+{
+ struct pipe_sampler_view *sv = (struct pipe_sampler_view*)data;
+
+ assert(map);
+ assert(key);
+ assert(data);
+ assert(user);
+
+ pipe_sampler_view_reference(&sv, NULL);
+}
+
+bool vl_compositor_init(struct vl_compositor *compositor, struct pipe_context *pipe)
+{
+ unsigned i;
+
+ assert(compositor);
+
+ memset(compositor, 0, sizeof(struct vl_compositor));
+
+ compositor->pipe = pipe;
+
+ compositor->texview_map = util_new_keymap(sizeof(struct pipe_surface*), -1,
+ texview_map_delete);
+ if (!compositor->texview_map)
+ return false;
+
+ if (!init_pipe_state(compositor)) {
+ util_delete_keymap(compositor->texview_map, compositor->pipe);
+ return false;
+ }
+ if (!init_shaders(compositor)) {
+ util_delete_keymap(compositor->texview_map, compositor->pipe);
+ cleanup_pipe_state(compositor);
+ return false;
+ }
+ if (!init_buffers(compositor)) {
+ util_delete_keymap(compositor->texview_map, compositor->pipe);
+ cleanup_shaders(compositor);
+ cleanup_pipe_state(compositor);
+ return false;
+ }
+
+ compositor->fb_state.width = 0;
+ compositor->fb_state.height = 0;
+ compositor->bg = NULL;
+ compositor->dirty_bg = false;
+ for (i = 0; i < VL_COMPOSITOR_MAX_LAYERS; ++i)
+ compositor->layers[i] = NULL;
+ compositor->dirty_layers = 0;
+
+ return true;
+}
+
+void vl_compositor_cleanup(struct vl_compositor *compositor)
+{
+ assert(compositor);
+
+ util_delete_keymap(compositor->texview_map, compositor->pipe);
+ cleanup_buffers(compositor);
+ cleanup_shaders(compositor);
+ cleanup_pipe_state(compositor);
+}
+
+void vl_compositor_set_background(struct vl_compositor *compositor,
+ struct pipe_surface *bg, struct pipe_video_rect *bg_src_rect)
+{
+ assert(compositor);
+ assert((bg && bg_src_rect) || (!bg && !bg_src_rect));
+
+ if (compositor->bg != bg ||
+ !u_video_rects_equal(&compositor->bg_src_rect, bg_src_rect)) {
+ pipe_surface_reference(&compositor->bg, bg);
+ /*if (!u_video_rects_equal(&compositor->bg_src_rect, bg_src_rect))*/
+ compositor->bg_src_rect = *bg_src_rect;
+ compositor->dirty_bg = true;
+ }
+}
+
+void vl_compositor_set_layers(struct vl_compositor *compositor,
+ struct pipe_surface *layers[],
+ struct pipe_video_rect *src_rects[],
+ struct pipe_video_rect *dst_rects[],
+ unsigned num_layers)
+{
+ unsigned i;
+
+ assert(compositor);
+ assert(num_layers <= VL_COMPOSITOR_MAX_LAYERS);
+
+ for (i = 0; i < num_layers; ++i)
+ {
+ assert((layers[i] && src_rects[i] && dst_rects[i]) ||
+ (!layers[i] && !src_rects[i] && !dst_rects[i]));
+
+ if (compositor->layers[i] != layers[i] ||
+ !u_video_rects_equal(&compositor->layer_src_rects[i], src_rects[i]) ||
+ !u_video_rects_equal(&compositor->layer_dst_rects[i], dst_rects[i]))
+ {
+ pipe_surface_reference(&compositor->layers[i], layers[i]);
+ /*if (!u_video_rects_equal(&compositor->layer_src_rects[i], src_rects[i]))*/
+ compositor->layer_src_rects[i] = *src_rects[i];
+ /*if (!u_video_rects_equal(&compositor->layer_dst_rects[i], dst_rects[i]))*/
+ compositor->layer_dst_rects[i] = *dst_rects[i];
+ compositor->dirty_layers |= 1 << i;
+ }
+
+ if (layers[i])
+ compositor->dirty_layers |= 1 << i;
+ }
+
+ for (; i < VL_COMPOSITOR_MAX_LAYERS; ++i)
+ pipe_surface_reference(&compositor->layers[i], NULL);
+}
+
+static void gen_rect_verts(unsigned pos,
+ struct pipe_video_rect *src_rect,
+ struct vertex2f *src_inv_size,
+ struct pipe_video_rect *dst_rect,
+ struct vertex2f *dst_inv_size,
+ struct vertex4f *vb)
+{
+ assert(pos < VL_COMPOSITOR_MAX_LAYERS + 2);
+ assert(src_rect);
+ assert(src_inv_size);
+ assert((dst_rect && dst_inv_size) /*|| (!dst_rect && !dst_inv_size)*/);
+ assert(vb);
+
+ vb[pos * 6 + 0].x = dst_rect->x * dst_inv_size->x;
+ vb[pos * 6 + 0].y = dst_rect->y * dst_inv_size->y;
+ vb[pos * 6 + 0].z = src_rect->x * src_inv_size->x;
+ vb[pos * 6 + 0].w = src_rect->y * src_inv_size->y;
+
+ vb[pos * 6 + 1].x = dst_rect->x * dst_inv_size->x;
+ vb[pos * 6 + 1].y = (dst_rect->y + dst_rect->h) * dst_inv_size->y;
+ vb[pos * 6 + 1].z = src_rect->x * src_inv_size->x;
+ vb[pos * 6 + 1].w = (src_rect->y + src_rect->h) * src_inv_size->y;
+
+ vb[pos * 6 + 2].x = (dst_rect->x + dst_rect->w) * dst_inv_size->x;
+ vb[pos * 6 + 2].y = dst_rect->y * dst_inv_size->y;
+ vb[pos * 6 + 2].z = (src_rect->x + src_rect->w) * src_inv_size->x;
+ vb[pos * 6 + 2].w = src_rect->y * src_inv_size->y;
+
+ vb[pos * 6 + 3].x = (dst_rect->x + dst_rect->w) * dst_inv_size->x;
+ vb[pos * 6 + 3].y = dst_rect->y * dst_inv_size->y;
+ vb[pos * 6 + 3].z = (src_rect->x + src_rect->w) * src_inv_size->x;
+ vb[pos * 6 + 3].w = src_rect->y * src_inv_size->y;
+
+ vb[pos * 6 + 4].x = dst_rect->x * dst_inv_size->x;
+ vb[pos * 6 + 4].y = (dst_rect->y + dst_rect->h) * dst_inv_size->y;
+ vb[pos * 6 + 4].z = src_rect->x * src_inv_size->x;
+ vb[pos * 6 + 4].w = (src_rect->y + src_rect->h) * src_inv_size->y;
+
+ vb[pos * 6 + 5].x = (dst_rect->x + dst_rect->w) * dst_inv_size->x;
+ vb[pos * 6 + 5].y = (dst_rect->y + dst_rect->h) * dst_inv_size->y;
+ vb[pos * 6 + 5].z = (src_rect->x + src_rect->w) * src_inv_size->x;
+ vb[pos * 6 + 5].w = (src_rect->y + src_rect->h) * src_inv_size->y;
+}
+
+static unsigned gen_data(struct vl_compositor *c,
+ struct pipe_surface *src_surface,
+ struct pipe_video_rect *src_rect,
+ struct pipe_video_rect *dst_rect,
+ struct pipe_surface **textures,
+ void **frag_shaders)
+{
+ void *vb;
+ struct pipe_transfer *buf_transfer;
+ unsigned num_rects = 0;
+ unsigned i;
+
+ assert(c);
+ assert(src_surface);
+ assert(src_rect);
+ assert(dst_rect);
+ assert(textures);
+
+ vb = pipe_buffer_map(c->pipe, c->vertex_buf.buffer,
+ PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD,
+ &buf_transfer);
+
+ if (!vb)
+ return 0;
+
+ if (c->dirty_bg) {
+ struct vertex2f bg_inv_size = {1.0f / c->bg->width, 1.0f / c->bg->height};
+ gen_rect_verts(num_rects, &c->bg_src_rect, &bg_inv_size, NULL, NULL, vb);
+ textures[num_rects] = c->bg;
+ /* XXX: Hack */
+ frag_shaders[num_rects] = c->fragment_shader.rgb_2_rgb;
+ ++num_rects;
+ c->dirty_bg = false;
+ }
+
+ {
+ struct vertex2f src_inv_size = { 1.0f / src_surface->width, 1.0f / src_surface->height};
+ gen_rect_verts(num_rects, src_rect, &src_inv_size, dst_rect, &c->fb_inv_size, vb);
+ textures[num_rects] = src_surface;
+ /* XXX: Hack, sort of */
+ frag_shaders[num_rects] = c->fragment_shader.ycbcr_2_rgb;
+ ++num_rects;
+ }
+
+ for (i = 0; c->dirty_layers > 0; i++) {
+ assert(i < VL_COMPOSITOR_MAX_LAYERS);
+
+ if (c->dirty_layers & (1 << i)) {
+ struct vertex2f layer_inv_size = {1.0f / c->layers[i]->width, 1.0f / c->layers[i]->height};
+ gen_rect_verts(num_rects, &c->layer_src_rects[i], &layer_inv_size,
+ &c->layer_dst_rects[i], &c->fb_inv_size, vb);
+ textures[num_rects] = c->layers[i];
+ /* XXX: Hack */
+ frag_shaders[num_rects] = c->fragment_shader.rgb_2_rgb;
+ ++num_rects;
+ c->dirty_layers &= ~(1 << i);
+ }
+ }
+
+ pipe_buffer_unmap(c->pipe, buf_transfer);
+
+ return num_rects;
+}
+
+static void draw_layers(struct vl_compositor *c,
+ struct pipe_surface *src_surface,
+ struct pipe_video_rect *src_rect,
+ struct pipe_video_rect *dst_rect)
+{
+ unsigned num_rects;
+ struct pipe_surface *src_surfaces[VL_COMPOSITOR_MAX_LAYERS + 2];
+ void *frag_shaders[VL_COMPOSITOR_MAX_LAYERS + 2];
+ unsigned i;
+
+ assert(c);
+ assert(src_surface);
+ assert(src_rect);
+ assert(dst_rect);
+
+ num_rects = gen_data(c, src_surface, src_rect, dst_rect, src_surfaces, frag_shaders);
+
+ for (i = 0; i < num_rects; ++i) {
+ boolean delete_view = FALSE;
+ struct pipe_sampler_view *surface_view = (struct pipe_sampler_view*)util_keymap_lookup(c->texview_map,
+ &src_surfaces[i]);
+ if (!surface_view) {
+ struct pipe_sampler_view templat;
+ u_sampler_view_default_template(&templat, src_surfaces[i]->texture,
+ src_surfaces[i]->texture->format);
+ surface_view = c->pipe->create_sampler_view(c->pipe, src_surfaces[i]->texture,
+ &templat);
+ if (!surface_view)
+ return;
+
+ delete_view = !util_keymap_insert(c->texview_map, &src_surfaces[i],
+ surface_view, c->pipe);
+ }
+
+ c->pipe->bind_fs_state(c->pipe, frag_shaders[i]);
+ c->pipe->set_fragment_sampler_views(c->pipe, 1, &surface_view);
+ util_draw_arrays(c->pipe, PIPE_PRIM_TRIANGLES, i * 6, 6);
+
+ if (delete_view) {
+ pipe_sampler_view_reference(&surface_view, NULL);
+ }
+ }
+}
+
+void vl_compositor_render(struct vl_compositor *compositor,
+ struct pipe_surface *src_surface,
+ enum pipe_mpeg12_picture_type picture_type,
+ /*unsigned num_past_surfaces,
+ struct pipe_surface *past_surfaces,
+ unsigned num_future_surfaces,
+ struct pipe_surface *future_surfaces,*/
+ struct pipe_video_rect *src_area,
+ struct pipe_surface *dst_surface,
+ struct pipe_video_rect *dst_area,
+ struct pipe_fence_handle **fence)
+{
+ assert(compositor);
+ assert(src_surface);
+ assert(src_area);
+ assert(dst_surface);
+ assert(dst_area);
+ assert(picture_type == PIPE_MPEG12_PICTURE_TYPE_FRAME);
+
+ if (compositor->fb_state.width != dst_surface->width) {
+ compositor->fb_inv_size.x = 1.0f / dst_surface->width;
+ compositor->fb_state.width = dst_surface->width;
+ }
+ if (compositor->fb_state.height != dst_surface->height) {
+ compositor->fb_inv_size.y = 1.0f / dst_surface->height;
+ compositor->fb_state.height = dst_surface->height;
+ }
+
+ compositor->fb_state.cbufs[0] = dst_surface;
+
+ compositor->viewport.scale[0] = compositor->fb_state.width;
+ compositor->viewport.scale[1] = compositor->fb_state.height;
+ compositor->viewport.scale[2] = 1;
+ compositor->viewport.scale[3] = 1;
+ compositor->viewport.translate[0] = 0;
+ compositor->viewport.translate[1] = 0;
+ compositor->viewport.translate[2] = 0;
+ compositor->viewport.translate[3] = 0;
+
+ compositor->pipe->set_framebuffer_state(compositor->pipe, &compositor->fb_state);
+ compositor->pipe->set_viewport_state(compositor->pipe, &compositor->viewport);
+ compositor->pipe->bind_fragment_sampler_states(compositor->pipe, 1, &compositor->sampler);
+ compositor->pipe->bind_vs_state(compositor->pipe, compositor->vertex_shader);
+ compositor->pipe->set_vertex_buffers(compositor->pipe, 1, &compositor->vertex_buf);
+ compositor->pipe->bind_vertex_elements_state(compositor->pipe, compositor->vertex_elems_state);
+ compositor->pipe->set_constant_buffer(compositor->pipe, PIPE_SHADER_FRAGMENT, 0, compositor->fs_const_buf);
+
+ draw_layers(compositor, src_surface, src_area, dst_area);
+
+ assert(!compositor->dirty_bg && !compositor->dirty_layers);
+ compositor->pipe->flush(compositor->pipe, PIPE_FLUSH_RENDER_CACHE, fence);
+}
+
+void vl_compositor_set_csc_matrix(struct vl_compositor *compositor, const float *mat)
+{
+ struct pipe_transfer *buf_transfer;
+
+ assert(compositor);
+
+ memcpy
+ (
+ pipe_buffer_map(compositor->pipe, compositor->fs_const_buf,
+ PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD,
+ &buf_transfer),
+ mat,
+ sizeof(struct fragment_shader_consts)
+ );
+
+ pipe_buffer_unmap(compositor->pipe, buf_transfer);
+}
diff --git a/src/gallium/auxiliary/vl/vl_compositor.h b/src/gallium/auxiliary/vl/vl_compositor.h
new file mode 100644
index 00000000000..820c9ef6ddb
--- /dev/null
+++ b/src/gallium/auxiliary/vl/vl_compositor.h
@@ -0,0 +1,98 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 vl_compositor_h
+#define vl_compositor_h
+
+#include <pipe/p_compiler.h>
+#include <pipe/p_state.h>
+#include <pipe/p_video_state.h>
+#include "vl_types.h"
+
+struct pipe_context;
+struct keymap;
+
+#define VL_COMPOSITOR_MAX_LAYERS 16
+
+struct vl_compositor
+{
+ struct pipe_context *pipe;
+
+ struct pipe_framebuffer_state fb_state;
+ struct vertex2f fb_inv_size;
+ void *sampler;
+ struct pipe_sampler_view *sampler_view;
+ void *vertex_shader;
+ struct
+ {
+ void *ycbcr_2_rgb;
+ void *rgb_2_rgb;
+ } fragment_shader;
+ struct pipe_viewport_state viewport;
+ struct pipe_vertex_buffer vertex_buf;
+ void *vertex_elems_state;
+ struct pipe_resource *fs_const_buf;
+
+ struct pipe_surface *bg;
+ struct pipe_video_rect bg_src_rect;
+ bool dirty_bg;
+ struct pipe_surface *layers[VL_COMPOSITOR_MAX_LAYERS];
+ struct pipe_video_rect layer_src_rects[VL_COMPOSITOR_MAX_LAYERS];
+ struct pipe_video_rect layer_dst_rects[VL_COMPOSITOR_MAX_LAYERS];
+ unsigned dirty_layers;
+
+ struct keymap *texview_map;
+};
+
+bool vl_compositor_init(struct vl_compositor *compositor, struct pipe_context *pipe);
+
+void vl_compositor_cleanup(struct vl_compositor *compositor);
+
+void vl_compositor_set_background(struct vl_compositor *compositor,
+ struct pipe_surface *bg, struct pipe_video_rect *bg_src_rect);
+
+void vl_compositor_set_layers(struct vl_compositor *compositor,
+ struct pipe_surface *layers[],
+ struct pipe_video_rect *src_rects[],
+ struct pipe_video_rect *dst_rects[],
+ unsigned num_layers);
+
+void vl_compositor_render(struct vl_compositor *compositor,
+ struct pipe_surface *src_surface,
+ enum pipe_mpeg12_picture_type picture_type,
+ /*unsigned num_past_surfaces,
+ struct pipe_surface *past_surfaces,
+ unsigned num_future_surfaces,
+ struct pipe_surface *future_surfaces,*/
+ struct pipe_video_rect *src_area,
+ struct pipe_surface *dst_surface,
+ struct pipe_video_rect *dst_area,
+ struct pipe_fence_handle **fence);
+
+void vl_compositor_set_csc_matrix(struct vl_compositor *compositor, const float *mat);
+
+#endif /* vl_compositor_h */
diff --git a/src/gallium/auxiliary/vl/vl_csc.c b/src/gallium/auxiliary/vl/vl_csc.c
new file mode 100644
index 00000000000..5ecc43a5fa3
--- /dev/null
+++ b/src/gallium/auxiliary/vl/vl_csc.c
@@ -0,0 +1,206 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 "vl_csc.h"
+#include <util/u_math.h>
+#include <util/u_debug.h>
+
+/*
+ * Color space conversion formulas
+ *
+ * To convert YCbCr to RGB,
+ * vec4 ycbcr, rgb
+ * mat44 csc
+ * rgb = csc * ycbcr
+ *
+ * To calculate the color space conversion matrix csc with ProcAmp adjustments,
+ * mat44 csc, cstd, procamp, bias
+ * csc = cstd * (procamp * bias)
+ *
+ * Where cstd is a matrix corresponding to one of the color standards (BT.601, BT.709, etc)
+ * adjusted for the kind of YCbCr -> RGB mapping wanted (1:1, full),
+ * bias is a matrix corresponding to the kind of YCbCr -> RGB mapping wanted (1:1, full)
+ *
+ * To calculate procamp,
+ * mat44 procamp, hue, saturation, brightness, contrast
+ * procamp = brightness * (saturation * (contrast * hue))
+ * Alternatively,
+ * procamp = saturation * (brightness * (contrast * hue))
+ *
+ * contrast
+ * [ c, 0, 0, 0]
+ * [ 0, c, 0, 0]
+ * [ 0, 0, c, 0]
+ * [ 0, 0, 0, 1]
+ *
+ * brightness
+ * [ 1, 0, 0, b]
+ * [ 0, 1, 0, 0]
+ * [ 0, 0, 1, 0]
+ * [ 0, 0, 0, 1]
+ *
+ * saturation
+ * [ 1, 0, 0, 0]
+ * [ 0, s, 0, 0]
+ * [ 0, 0, s, 0]
+ * [ 0, 0, 0, 1]
+ *
+ * hue
+ * [ 1, 0, 0, 0]
+ * [ 0, cos(h), sin(h), 0]
+ * [ 0, -sin(h), cos(h), 0]
+ * [ 0, 0, 0, 1]
+ *
+ * procamp
+ * [ c, 0, 0, b]
+ * [ 0, c*s*cos(h), c*s*sin(h), 0]
+ * [ 0, -c*s*sin(h), c*s*cos(h), 0]
+ * [ 0, 0, 0, 1]
+ *
+ * bias
+ * [ 1, 0, 0, ybias]
+ * [ 0, 1, 0, cbbias]
+ * [ 0, 0, 1, crbias]
+ * [ 0, 0, 0, 1]
+ *
+ * csc
+ * [ c*cstd[ 0], c*cstd[ 1]*s*cos(h) - c*cstd[ 2]*s*sin(h), c*cstd[ 2]*s*cos(h) + c*cstd[ 1]*s*sin(h), cstd[ 3] + cstd[ 0]*(b + c*ybias) + cstd[ 1]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[ 2]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h))]
+ * [ c*cstd[ 4], c*cstd[ 5]*s*cos(h) - c*cstd[ 6]*s*sin(h), c*cstd[ 6]*s*cos(h) + c*cstd[ 5]*s*sin(h), cstd[ 7] + cstd[ 4]*(b + c*ybias) + cstd[ 5]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[ 6]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h))]
+ * [ c*cstd[ 8], c*cstd[ 9]*s*cos(h) - c*cstd[10]*s*sin(h), c*cstd[10]*s*cos(h) + c*cstd[ 9]*s*sin(h), cstd[11] + cstd[ 8]*(b + c*ybias) + cstd[ 9]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[10]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h))]
+ * [ c*cstd[12], c*cstd[13]*s*cos(h) - c*cstd[14]*s*sin(h), c*cstd[14]*s*cos(h) + c*cstd[13]*s*sin(h), cstd[15] + cstd[12]*(b + c*ybias) + cstd[13]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[14]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h))]
+ */
+
+/*
+ * Converts ITU-R BT.601 YCbCr pixels to RGB pixels where:
+ * Y is in [16,235], Cb and Cr are in [16,240]
+ * R, G, and B are in [16,235]
+ */
+static const float bt_601[16] =
+{
+ 1.0f, 0.0f, 1.371f, 0.0f,
+ 1.0f, -0.336f, -0.698f, 0.0f,
+ 1.0f, 1.732f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+};
+
+/*
+ * Converts ITU-R BT.601 YCbCr pixels to RGB pixels where:
+ * Y is in [16,235], Cb and Cr are in [16,240]
+ * R, G, and B are in [0,255]
+ */
+static const float bt_601_full[16] =
+{
+ 1.164f, 0.0f, 1.596f, 0.0f,
+ 1.164f, -0.391f, -0.813f, 0.0f,
+ 1.164f, 2.018f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+};
+
+/*
+ * Converts ITU-R BT.709 YCbCr pixels to RGB pixels where:
+ * Y is in [16,235], Cb and Cr are in [16,240]
+ * R, G, and B are in [16,235]
+ */
+static const float bt_709[16] =
+{
+ 1.0f, 0.0f, 1.540f, 0.0f,
+ 1.0f, -0.183f, -0.459f, 0.0f,
+ 1.0f, 1.816f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+};
+
+/*
+ * Converts ITU-R BT.709 YCbCr pixels to RGB pixels where:
+ * Y is in [16,235], Cb and Cr are in [16,240]
+ * R, G, and B are in [0,255]
+ */
+static const float bt_709_full[16] =
+{
+ 1.164f, 0.0f, 1.793f, 0.0f,
+ 1.164f, -0.213f, -0.534f, 0.0f,
+ 1.164f, 2.115f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+};
+
+static const float identity[16] =
+{
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+};
+
+void vl_csc_get_matrix(enum VL_CSC_COLOR_STANDARD cs,
+ struct vl_procamp *procamp,
+ bool full_range,
+ float *matrix)
+{
+ float ybias = full_range ? -16.0f/255.0f : 0.0f;
+ float cbbias = -128.0f/255.0f;
+ float crbias = -128.0f/255.0f;
+ float c = procamp ? procamp->contrast : 1.0f;
+ float s = procamp ? procamp->saturation : 1.0f;
+ float b = procamp ? procamp->brightness : 0.0f;
+ float h = procamp ? procamp->hue : 0.0f;
+ const float *cstd;
+
+ assert(matrix);
+
+ switch (cs) {
+ case VL_CSC_COLOR_STANDARD_BT_601:
+ cstd = full_range ? &bt_601_full[0] : &bt_601[0];
+ break;
+ case VL_CSC_COLOR_STANDARD_BT_709:
+ cstd = full_range ? &bt_709_full[0] : &bt_709[0];
+ break;
+ case VL_CSC_COLOR_STANDARD_IDENTITY:
+ default:
+ assert(cs == VL_CSC_COLOR_STANDARD_IDENTITY);
+ memcpy(matrix, &identity[0], sizeof(float) * 16);
+ return;
+ }
+
+ matrix[ 0] = c*cstd[ 0];
+ matrix[ 1] = c*cstd[ 1]*s*cosf(h) - c*cstd[ 2]*s*sinf(h);
+ matrix[ 2] = c*cstd[ 2]*s*cosf(h) + c*cstd[ 1]*s*sinf(h);
+ matrix[ 3] = cstd[ 3] + cstd[ 0]*(b + c*ybias) + cstd[ 1]*(c*cbbias*s*cosf(h) + c*crbias*s*sinf(h)) + cstd[ 2]*(c*crbias*s*cosf(h) - c*cbbias*s*sinf(h));
+
+ matrix[ 4] = c*cstd[ 4];
+ matrix[ 5] = c*cstd[ 5]*s*cosf(h) - c*cstd[ 6]*s*sinf(h);
+ matrix[ 6] = c*cstd[ 6]*s*cosf(h) + c*cstd[ 5]*s*sinf(h);
+ matrix[ 7] = cstd[ 7] + cstd[ 4]*(b + c*ybias) + cstd[ 5]*(c*cbbias*s*cosf(h) + c*crbias*s*sinf(h)) + cstd[ 6]*(c*crbias*s*cosf(h) - c*cbbias*s*sinf(h));
+
+ matrix[ 8] = c*cstd[ 8];
+ matrix[ 9] = c*cstd[ 9]*s*cosf(h) - c*cstd[10]*s*sinf(h);
+ matrix[10] = c*cstd[10]*s*cosf(h) + c*cstd[ 9]*s*sinf(h);
+ matrix[11] = cstd[11] + cstd[ 8]*(b + c*ybias) + cstd[ 9]*(c*cbbias*s*cosf(h) + c*crbias*s*sinf(h)) + cstd[10]*(c*crbias*s*cosf(h) - c*cbbias*s*sinf(h));
+
+ matrix[12] = c*cstd[12];
+ matrix[13] = c*cstd[13]*s*cos(h) - c*cstd[14]*s*sin(h);
+ matrix[14] = c*cstd[14]*s*cos(h) + c*cstd[13]*s*sin(h);
+ matrix[15] = cstd[15] + cstd[12]*(b + c*ybias) + cstd[13]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[14]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h));
+}
diff --git a/src/gallium/auxiliary/vl/vl_csc.h b/src/gallium/auxiliary/vl/vl_csc.h
new file mode 100644
index 00000000000..722ca35f339
--- /dev/null
+++ b/src/gallium/auxiliary/vl/vl_csc.h
@@ -0,0 +1,53 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 vl_csc_h
+#define vl_csc_h
+
+#include <pipe/p_compiler.h>
+
+struct vl_procamp
+{
+ float brightness;
+ float contrast;
+ float saturation;
+ float hue;
+};
+
+enum VL_CSC_COLOR_STANDARD
+{
+ VL_CSC_COLOR_STANDARD_IDENTITY,
+ VL_CSC_COLOR_STANDARD_BT_601,
+ VL_CSC_COLOR_STANDARD_BT_709
+};
+
+void vl_csc_get_matrix(enum VL_CSC_COLOR_STANDARD cs,
+ struct vl_procamp *procamp,
+ bool full_range,
+ float *matrix);
+
+#endif /* vl_csc_h */
diff --git a/src/gallium/auxiliary/vl/vl_idct.c b/src/gallium/auxiliary/vl/vl_idct.c
new file mode 100644
index 00000000000..b84b447ce6b
--- /dev/null
+++ b/src/gallium/auxiliary/vl/vl_idct.c
@@ -0,0 +1,766 @@
+/**************************************************************************
+ *
+ * Copyright 2010 Christian König
+ * 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 "vl_idct.h"
+#include "vl_vertex_buffers.h"
+#include "util/u_draw.h"
+#include <assert.h>
+#include <pipe/p_context.h>
+#include <pipe/p_screen.h>
+#include <util/u_inlines.h>
+#include <util/u_sampler.h>
+#include <util/u_format.h>
+#include <tgsi/tgsi_ureg.h>
+#include "vl_types.h"
+
+#define BLOCK_WIDTH 8
+#define BLOCK_HEIGHT 8
+
+#define SCALE_FACTOR_16_TO_9 (32768.0f / 256.0f)
+
+#define NR_RENDER_TARGETS 4
+
+enum VS_INPUT
+{
+ VS_I_RECT,
+ VS_I_VPOS,
+
+ NUM_VS_INPUTS
+};
+
+enum VS_OUTPUT
+{
+ VS_O_VPOS,
+ VS_O_L_ADDR0,
+ VS_O_L_ADDR1,
+ VS_O_R_ADDR0,
+ VS_O_R_ADDR1
+};
+
+static const float const_matrix[8][8] = {
+ { 0.3535530f, 0.3535530f, 0.3535530f, 0.3535530f, 0.3535530f, 0.3535530f, 0.353553f, 0.3535530f },
+ { 0.4903930f, 0.4157350f, 0.2777850f, 0.0975451f, -0.0975452f, -0.2777850f, -0.415735f, -0.4903930f },
+ { 0.4619400f, 0.1913420f, -0.1913420f, -0.4619400f, -0.4619400f, -0.1913420f, 0.191342f, 0.4619400f },
+ { 0.4157350f, -0.0975452f, -0.4903930f, -0.2777850f, 0.2777850f, 0.4903930f, 0.097545f, -0.4157350f },
+ { 0.3535530f, -0.3535530f, -0.3535530f, 0.3535540f, 0.3535530f, -0.3535540f, -0.353553f, 0.3535530f },
+ { 0.2777850f, -0.4903930f, 0.0975452f, 0.4157350f, -0.4157350f, -0.0975451f, 0.490393f, -0.2777850f },
+ { 0.1913420f, -0.4619400f, 0.4619400f, -0.1913420f, -0.1913410f, 0.4619400f, -0.461940f, 0.1913420f },
+ { 0.0975451f, -0.2777850f, 0.4157350f, -0.4903930f, 0.4903930f, -0.4157350f, 0.277786f, -0.0975458f }
+};
+
+static void
+calc_addr(struct ureg_program *shader, struct ureg_dst addr[2],
+ struct ureg_src tc, struct ureg_src start, bool right_side,
+ bool transposed, float size)
+{
+ unsigned wm_start = (right_side == transposed) ? TGSI_WRITEMASK_X : TGSI_WRITEMASK_Y;
+ unsigned sw_start = right_side ? TGSI_SWIZZLE_Y : TGSI_SWIZZLE_X;
+
+ unsigned wm_tc = (right_side == transposed) ? TGSI_WRITEMASK_Y : TGSI_WRITEMASK_X;
+ unsigned sw_tc = right_side ? TGSI_SWIZZLE_X : TGSI_SWIZZLE_Y;
+
+ /*
+ * addr[0..1].(start) = right_side ? start.x : tc.x
+ * addr[0..1].(tc) = right_side ? tc.y : start.y
+ * addr[0..1].z = tc.z
+ * addr[1].(start) += 1.0f / scale
+ */
+ ureg_MOV(shader, ureg_writemask(addr[0], wm_start), ureg_scalar(start, sw_start));
+ ureg_MOV(shader, ureg_writemask(addr[0], wm_tc), ureg_scalar(tc, sw_tc));
+ ureg_MOV(shader, ureg_writemask(addr[0], TGSI_WRITEMASK_Z), tc);
+
+ ureg_ADD(shader, ureg_writemask(addr[1], wm_start), ureg_scalar(start, sw_start), ureg_imm1f(shader, 1.0f / size));
+ ureg_MOV(shader, ureg_writemask(addr[1], wm_tc), ureg_scalar(tc, sw_tc));
+ ureg_MOV(shader, ureg_writemask(addr[1], TGSI_WRITEMASK_Z), tc);
+}
+
+static void *
+create_vert_shader(struct vl_idct *idct, bool matrix_stage)
+{
+ struct ureg_program *shader;
+ struct ureg_src scale;
+ struct ureg_src vrect, vpos;
+ struct ureg_dst t_tex, t_start;
+ struct ureg_dst o_vpos, o_l_addr[2], o_r_addr[2];
+
+ shader = ureg_create(TGSI_PROCESSOR_VERTEX);
+ if (!shader)
+ return NULL;
+
+ t_tex = ureg_DECL_temporary(shader);
+ t_start = ureg_DECL_temporary(shader);
+
+ vrect = ureg_DECL_vs_input(shader, VS_I_RECT);
+ vpos = ureg_DECL_vs_input(shader, VS_I_VPOS);
+
+ o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS);
+
+ o_l_addr[0] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_L_ADDR0);
+ o_l_addr[1] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_L_ADDR1);
+
+ o_r_addr[0] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_R_ADDR0);
+ o_r_addr[1] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_R_ADDR1);
+
+ /*
+ * scale = (BLOCK_WIDTH, BLOCK_HEIGHT) / (dst.width, dst.height)
+ *
+ * t_vpos = vpos + vrect
+ * o_vpos.xy = t_vpos * scale
+ * o_vpos.zw = vpos
+ *
+ * o_l_addr = calc_addr(...)
+ * o_r_addr = calc_addr(...)
+ *
+ */
+ scale = ureg_imm2f(shader,
+ (float)BLOCK_WIDTH / idct->buffer_width,
+ (float)BLOCK_HEIGHT / idct->buffer_height);
+
+ ureg_ADD(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_XY), vpos, vrect);
+ ureg_MUL(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_XY), ureg_src(t_tex), scale);
+ ureg_MUL(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_Z),
+ ureg_scalar(vrect, TGSI_SWIZZLE_X),
+ ureg_imm1f(shader, BLOCK_WIDTH / NR_RENDER_TARGETS));
+
+ ureg_MOV(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_XY), ureg_src(t_tex));
+ ureg_MOV(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_ZW), vpos);
+
+ ureg_MUL(shader, ureg_writemask(t_start, TGSI_WRITEMASK_XY), vpos, scale);
+
+ if(matrix_stage) {
+ calc_addr(shader, o_l_addr, ureg_src(t_tex), ureg_src(t_start), false, false, idct->buffer_width / 4);
+ calc_addr(shader, o_r_addr, vrect, ureg_imm1f(shader, 0.0f), true, true, BLOCK_WIDTH / 4);
+ } else {
+ calc_addr(shader, o_l_addr, vrect, ureg_imm1f(shader, 0.0f), false, false, BLOCK_WIDTH / 4);
+ calc_addr(shader, o_r_addr, ureg_src(t_tex), ureg_src(t_start), true, false, idct->buffer_height / 4);
+ }
+
+ ureg_release_temporary(shader, t_tex);
+ ureg_release_temporary(shader, t_start);
+
+ ureg_END(shader);
+
+ return ureg_create_shader_and_destroy(shader, idct->pipe);
+}
+
+static void
+increment_addr(struct ureg_program *shader, struct ureg_dst daddr[2],
+ struct ureg_src saddr[2], bool right_side, bool transposed,
+ int pos, float size)
+{
+ unsigned wm_start = (right_side == transposed) ? TGSI_WRITEMASK_X : TGSI_WRITEMASK_Y;
+ unsigned wm_tc = (right_side == transposed) ? TGSI_WRITEMASK_Y : TGSI_WRITEMASK_X;
+
+ /*
+ * daddr[0..1].(start) = saddr[0..1].(start)
+ * daddr[0..1].(tc) = saddr[0..1].(tc)
+ */
+
+ ureg_MOV(shader, ureg_writemask(daddr[0], wm_start), saddr[0]);
+ ureg_ADD(shader, ureg_writemask(daddr[0], wm_tc), saddr[0], ureg_imm1f(shader, pos / size));
+ ureg_MOV(shader, ureg_writemask(daddr[1], wm_start), saddr[1]);
+ ureg_ADD(shader, ureg_writemask(daddr[1], wm_tc), saddr[1], ureg_imm1f(shader, pos / size));
+}
+
+static void
+fetch_four(struct ureg_program *shader, struct ureg_dst m[2], struct ureg_src addr[2], struct ureg_src sampler)
+{
+ ureg_TEX(shader, m[0], TGSI_TEXTURE_3D, addr[0], sampler);
+ ureg_TEX(shader, m[1], TGSI_TEXTURE_3D, addr[1], sampler);
+}
+
+static void
+matrix_mul(struct ureg_program *shader, struct ureg_dst dst, struct ureg_dst l[2], struct ureg_dst r[2])
+{
+ struct ureg_dst tmp;
+
+ tmp = ureg_DECL_temporary(shader);
+
+ /*
+ * tmp.xy = dot4(m[0][0..1], m[1][0..1])
+ * dst = tmp.x + tmp.y
+ */
+ ureg_DP4(shader, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_src(l[0]), ureg_src(r[0]));
+ ureg_DP4(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_src(l[1]), ureg_src(r[1]));
+ ureg_ADD(shader, dst,
+ ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X),
+ ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_Y));
+
+ ureg_release_temporary(shader, tmp);
+}
+
+static void *
+create_matrix_frag_shader(struct vl_idct *idct)
+{
+ struct ureg_program *shader;
+
+ struct ureg_src l_addr[2], r_addr[2];
+
+ struct ureg_dst l[4][2], r[2];
+ struct ureg_dst fragment[NR_RENDER_TARGETS];
+
+ unsigned i, j;
+
+ shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
+ if (!shader)
+ return NULL;
+
+ l_addr[0] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_L_ADDR0, TGSI_INTERPOLATE_LINEAR);
+ l_addr[1] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_L_ADDR1, TGSI_INTERPOLATE_LINEAR);
+
+ r_addr[0] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_R_ADDR0, TGSI_INTERPOLATE_LINEAR);
+ r_addr[1] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_R_ADDR1, TGSI_INTERPOLATE_LINEAR);
+
+ for (i = 0; i < NR_RENDER_TARGETS; ++i)
+ fragment[i] = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, i);
+
+ for (i = 0; i < 4; ++i) {
+ l[i][0] = ureg_DECL_temporary(shader);
+ l[i][1] = ureg_DECL_temporary(shader);
+ }
+
+ r[0] = ureg_DECL_temporary(shader);
+ r[1] = ureg_DECL_temporary(shader);
+
+ for (i = 1; i < 4; ++i) {
+ increment_addr(shader, l[i], l_addr, false, false, i, idct->buffer_height);
+ }
+
+ for (i = 0; i < 4; ++i) {
+ struct ureg_src s_addr[2];
+ s_addr[0] = i == 0 ? l_addr[0] : ureg_src(l[i][0]);
+ s_addr[1] = i == 0 ? l_addr[1] : ureg_src(l[i][1]);
+ fetch_four(shader, l[i], s_addr, ureg_DECL_sampler(shader, 1));
+ }
+
+ for (i = 0; i < NR_RENDER_TARGETS; ++i) {
+ if(i > 0)
+ increment_addr(shader, r, r_addr, true, true, i, BLOCK_HEIGHT);
+
+ struct ureg_src s_addr[2] = { ureg_src(r[0]), ureg_src(r[1]) };
+ s_addr[0] = i == 0 ? r_addr[0] : ureg_src(r[0]);
+ s_addr[1] = i == 0 ? r_addr[1] : ureg_src(r[1]);
+ fetch_four(shader, r, s_addr, ureg_DECL_sampler(shader, 0));
+
+ for (j = 0; j < 4; ++j) {
+ matrix_mul(shader, ureg_writemask(fragment[i], TGSI_WRITEMASK_X << j), l[j], r);
+ }
+ }
+
+ for (i = 0; i < 4; ++i) {
+ ureg_release_temporary(shader, l[i][0]);
+ ureg_release_temporary(shader, l[i][1]);
+ }
+ ureg_release_temporary(shader, r[0]);
+ ureg_release_temporary(shader, r[1]);
+
+ ureg_END(shader);
+
+ return ureg_create_shader_and_destroy(shader, idct->pipe);
+}
+
+static void *
+create_transpose_frag_shader(struct vl_idct *idct)
+{
+ struct ureg_program *shader;
+
+ struct ureg_src l_addr[2], r_addr[2];
+
+ struct ureg_dst l[2], r[2];
+ struct ureg_dst fragment;
+
+ shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
+ if (!shader)
+ return NULL;
+
+ l_addr[0] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_L_ADDR0, TGSI_INTERPOLATE_LINEAR);
+ l_addr[1] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_L_ADDR1, TGSI_INTERPOLATE_LINEAR);
+
+ r_addr[0] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_R_ADDR0, TGSI_INTERPOLATE_LINEAR);
+ r_addr[1] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_R_ADDR1, TGSI_INTERPOLATE_LINEAR);
+
+ l[0] = ureg_DECL_temporary(shader);
+ l[1] = ureg_DECL_temporary(shader);
+ r[0] = ureg_DECL_temporary(shader);
+ r[1] = ureg_DECL_temporary(shader);
+
+ fetch_four(shader, l, l_addr, ureg_DECL_sampler(shader, 0));
+ fetch_four(shader, r, r_addr, ureg_DECL_sampler(shader, 1));
+
+ fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
+
+ matrix_mul(shader, ureg_writemask(fragment, TGSI_WRITEMASK_X), l, r);
+
+ ureg_release_temporary(shader, l[0]);
+ ureg_release_temporary(shader, l[1]);
+ ureg_release_temporary(shader, r[0]);
+ ureg_release_temporary(shader, r[1]);
+
+ ureg_END(shader);
+
+ return ureg_create_shader_and_destroy(shader, idct->pipe);
+}
+
+static bool
+init_shaders(struct vl_idct *idct)
+{
+ idct->matrix_vs = create_vert_shader(idct, true);
+ idct->matrix_fs = create_matrix_frag_shader(idct);
+
+ idct->transpose_vs = create_vert_shader(idct, false);
+ idct->transpose_fs = create_transpose_frag_shader(idct);
+
+ return
+ idct->matrix_vs != NULL &&
+ idct->matrix_fs != NULL &&
+ idct->transpose_vs != NULL &&
+ idct->transpose_fs != NULL;
+}
+
+static void
+cleanup_shaders(struct vl_idct *idct)
+{
+ idct->pipe->delete_vs_state(idct->pipe, idct->matrix_vs);
+ idct->pipe->delete_fs_state(idct->pipe, idct->matrix_fs);
+ idct->pipe->delete_vs_state(idct->pipe, idct->transpose_vs);
+ idct->pipe->delete_fs_state(idct->pipe, idct->transpose_fs);
+}
+
+static bool
+init_state(struct vl_idct *idct)
+{
+ struct pipe_vertex_element vertex_elems[NUM_VS_INPUTS];
+ struct pipe_sampler_state sampler;
+ struct pipe_rasterizer_state rs_state;
+ unsigned i;
+
+ assert(idct);
+
+ idct->quad = vl_vb_upload_quads(idct->pipe, idct->max_blocks);
+
+ if(idct->quad.buffer == NULL)
+ return false;
+
+ for (i = 0; i < 4; ++i) {
+ memset(&sampler, 0, sizeof(sampler));
+ sampler.wrap_s = PIPE_TEX_WRAP_REPEAT;
+ sampler.wrap_t = PIPE_TEX_WRAP_REPEAT;
+ sampler.wrap_r = PIPE_TEX_WRAP_REPEAT;
+ sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
+ sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
+ sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
+ sampler.compare_mode = PIPE_TEX_COMPARE_NONE;
+ sampler.compare_func = PIPE_FUNC_ALWAYS;
+ sampler.normalized_coords = 1;
+ /*sampler.shadow_ambient = ; */
+ /*sampler.lod_bias = ; */
+ sampler.min_lod = 0;
+ /*sampler.max_lod = ; */
+ /*sampler.border_color[0] = ; */
+ /*sampler.max_anisotropy = ; */
+ idct->samplers.all[i] = idct->pipe->create_sampler_state(idct->pipe, &sampler);
+ }
+
+ memset(&rs_state, 0, sizeof(rs_state));
+ /*rs_state.sprite_coord_enable */
+ rs_state.sprite_coord_mode = PIPE_SPRITE_COORD_UPPER_LEFT;
+ rs_state.point_quad_rasterization = true;
+ rs_state.point_size = BLOCK_WIDTH;
+ rs_state.gl_rasterization_rules = false;
+ idct->rs_state = idct->pipe->create_rasterizer_state(idct->pipe, &rs_state);
+
+ vertex_elems[VS_I_RECT] = vl_vb_get_quad_vertex_element();
+
+ /* Pos element */
+ vertex_elems[VS_I_VPOS].src_format = PIPE_FORMAT_R32G32_FLOAT;
+
+ idct->vertex_buffer_stride = vl_vb_element_helper(&vertex_elems[VS_I_VPOS], 1, 1);
+ idct->vertex_elems_state = idct->pipe->create_vertex_elements_state(idct->pipe, 2, vertex_elems);
+
+ return true;
+}
+
+static void
+cleanup_state(struct vl_idct *idct)
+{
+ unsigned i;
+
+ for (i = 0; i < 4; ++i)
+ idct->pipe->delete_sampler_state(idct->pipe, idct->samplers.all[i]);
+
+ idct->pipe->delete_rasterizer_state(idct->pipe, idct->rs_state);
+ idct->pipe->delete_vertex_elements_state(idct->pipe, idct->vertex_elems_state);
+}
+
+static bool
+init_textures(struct vl_idct *idct, struct vl_idct_buffer *buffer)
+{
+ struct pipe_resource template;
+ struct pipe_sampler_view sampler_view;
+ unsigned i;
+
+ assert(idct && buffer);
+
+ /* create textures */
+ memset(&template, 0, sizeof(struct pipe_resource));
+ template.last_level = 0;
+ template.depth0 = 1;
+ template.bind = PIPE_BIND_SAMPLER_VIEW;
+ template.flags = 0;
+
+ template.target = PIPE_TEXTURE_2D;
+ template.format = PIPE_FORMAT_R16G16B16A16_SNORM;
+ template.width0 = idct->buffer_width / 4;
+ template.height0 = idct->buffer_height;
+ template.depth0 = 1;
+ template.usage = PIPE_USAGE_STREAM;
+ buffer->textures.individual.source = idct->pipe->screen->resource_create(idct->pipe->screen, &template);
+
+ template.target = PIPE_TEXTURE_3D;
+ template.format = PIPE_FORMAT_R16G16B16A16_SNORM;
+ template.width0 = idct->buffer_width / NR_RENDER_TARGETS;
+ template.height0 = idct->buffer_height / 4;
+ template.depth0 = NR_RENDER_TARGETS;
+ template.usage = PIPE_USAGE_STATIC;
+ buffer->textures.individual.intermediate = idct->pipe->screen->resource_create(idct->pipe->screen, &template);
+
+ for (i = 0; i < 4; ++i) {
+ if(buffer->textures.all[i] == NULL)
+ return false; /* a texture failed to allocate */
+
+ u_sampler_view_default_template(&sampler_view, buffer->textures.all[i], buffer->textures.all[i]->format);
+ buffer->sampler_views.all[i] = idct->pipe->create_sampler_view(idct->pipe, buffer->textures.all[i], &sampler_view);
+ }
+
+ return true;
+}
+
+static void
+cleanup_textures(struct vl_idct *idct, struct vl_idct_buffer *buffer)
+{
+ unsigned i;
+
+ assert(idct && buffer);
+
+ for (i = 0; i < 4; ++i) {
+ pipe_sampler_view_reference(&buffer->sampler_views.all[i], NULL);
+ pipe_resource_reference(&buffer->textures.all[i], NULL);
+ }
+}
+
+static bool
+init_vertex_buffers(struct vl_idct *idct, struct vl_idct_buffer *buffer)
+{
+ assert(idct && buffer);
+
+ buffer->vertex_bufs.individual.quad.stride = idct->quad.stride;
+ buffer->vertex_bufs.individual.quad.max_index = idct->quad.max_index;
+ buffer->vertex_bufs.individual.quad.buffer_offset = idct->quad.buffer_offset;
+ pipe_resource_reference(&buffer->vertex_bufs.individual.quad.buffer, idct->quad.buffer);
+
+ buffer->vertex_bufs.individual.pos = vl_vb_init(
+ &buffer->blocks, idct->pipe, idct->max_blocks, 2,
+ idct->vertex_buffer_stride);
+
+ if(buffer->vertex_bufs.individual.pos.buffer == NULL)
+ return false;
+
+ return true;
+}
+
+static void
+cleanup_vertex_buffers(struct vl_idct *idct, struct vl_idct_buffer *buffer)
+{
+ assert(idct && buffer);
+
+ pipe_resource_reference(&buffer->vertex_bufs.individual.quad.buffer, NULL);
+ pipe_resource_reference(&buffer->vertex_bufs.individual.pos.buffer, NULL);
+
+ vl_vb_cleanup(&buffer->blocks);
+}
+
+struct pipe_resource *
+vl_idct_upload_matrix(struct pipe_context *pipe)
+{
+ struct pipe_resource template, *matrix;
+ struct pipe_transfer *buf_transfer;
+ unsigned i, j, pitch;
+ float *f;
+
+ struct pipe_box rect =
+ {
+ 0, 0, 0,
+ BLOCK_WIDTH / 4,
+ BLOCK_HEIGHT,
+ 1
+ };
+
+ memset(&template, 0, sizeof(struct pipe_resource));
+ template.target = PIPE_TEXTURE_2D;
+ template.format = PIPE_FORMAT_R32G32B32A32_FLOAT;
+ template.last_level = 0;
+ template.width0 = 2;
+ template.height0 = 8;
+ template.depth0 = 1;
+ template.usage = PIPE_USAGE_IMMUTABLE;
+ template.bind = PIPE_BIND_SAMPLER_VIEW;
+ template.flags = 0;
+
+ matrix = pipe->screen->resource_create(pipe->screen, &template);
+
+ /* matrix */
+ buf_transfer = pipe->get_transfer
+ (
+ pipe, matrix,
+ 0, PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD,
+ &rect
+ );
+ pitch = buf_transfer->stride / sizeof(float);
+
+ f = pipe->transfer_map(pipe, buf_transfer);
+ for(i = 0; i < BLOCK_HEIGHT; ++i)
+ for(j = 0; j < BLOCK_WIDTH; ++j)
+ // transpose and scale
+ f[i * pitch + j] = const_matrix[j][i] * sqrtf(SCALE_FACTOR_16_TO_9);
+
+ pipe->transfer_unmap(pipe, buf_transfer);
+ pipe->transfer_destroy(pipe, buf_transfer);
+
+ return matrix;
+}
+
+bool vl_idct_init(struct vl_idct *idct, struct pipe_context *pipe,
+ unsigned buffer_width, unsigned buffer_height,
+ struct pipe_resource *matrix)
+{
+ assert(idct && pipe && matrix);
+
+ idct->pipe = pipe;
+ idct->buffer_width = buffer_width;
+ idct->buffer_height = buffer_height;
+ pipe_resource_reference(&idct->matrix, matrix);
+
+ idct->max_blocks =
+ align(buffer_width, BLOCK_WIDTH) / BLOCK_WIDTH *
+ align(buffer_height, BLOCK_HEIGHT) / BLOCK_HEIGHT;
+
+ if(!init_shaders(idct))
+ return false;
+
+ if(!init_state(idct)) {
+ cleanup_shaders(idct);
+ return false;
+ }
+
+ return true;
+}
+
+void
+vl_idct_cleanup(struct vl_idct *idct)
+{
+ cleanup_shaders(idct);
+ cleanup_state(idct);
+
+ pipe_resource_reference(&idct->matrix, NULL);
+}
+
+bool
+vl_idct_init_buffer(struct vl_idct *idct, struct vl_idct_buffer *buffer, struct pipe_resource *dst)
+{
+ struct pipe_surface template;
+
+ unsigned i;
+
+ assert(buffer);
+ assert(idct);
+ assert(dst);
+
+ pipe_resource_reference(&buffer->textures.individual.matrix, idct->matrix);
+ pipe_resource_reference(&buffer->textures.individual.transpose, idct->matrix);
+ pipe_resource_reference(&buffer->destination, dst);
+
+ if (!init_textures(idct, buffer))
+ return false;
+
+ if (!init_vertex_buffers(idct, buffer))
+ return false;
+
+ /* init state */
+ buffer->viewport[0].scale[0] = buffer->textures.individual.intermediate->width0;
+ buffer->viewport[0].scale[1] = buffer->textures.individual.intermediate->height0;
+
+ buffer->viewport[1].scale[0] = buffer->destination->width0;
+ buffer->viewport[1].scale[1] = buffer->destination->height0;
+
+ buffer->fb_state[0].width = buffer->textures.individual.intermediate->width0;
+ buffer->fb_state[0].height = buffer->textures.individual.intermediate->height0;
+
+ buffer->fb_state[0].nr_cbufs = NR_RENDER_TARGETS;
+ for(i = 0; i < NR_RENDER_TARGETS; ++i) {
+ memset(&template, 0, sizeof(template));
+ template.format = buffer->textures.individual.intermediate->format;
+ template.u.tex.first_layer = i;
+ template.u.tex.last_layer = i;
+ template.usage = PIPE_BIND_RENDER_TARGET;
+ buffer->fb_state[0].cbufs[i] = idct->pipe->create_surface(
+ idct->pipe, buffer->textures.individual.intermediate,
+ &template);
+ }
+
+ buffer->fb_state[1].width = buffer->destination->width0;
+ buffer->fb_state[1].height = buffer->destination->height0;
+
+ buffer->fb_state[1].nr_cbufs = 1;
+
+ memset(&template, 0, sizeof(template));
+ template.format = buffer->destination->format;
+ template.usage = PIPE_BIND_RENDER_TARGET;
+ buffer->fb_state[1].cbufs[0] = idct->pipe->create_surface(
+ idct->pipe, buffer->destination, &template);
+
+ for(i = 0; i < 2; ++i) {
+ buffer->viewport[i].scale[2] = 1;
+ buffer->viewport[i].scale[3] = 1;
+ buffer->viewport[i].translate[0] = 0;
+ buffer->viewport[i].translate[1] = 0;
+ buffer->viewport[i].translate[2] = 0;
+ buffer->viewport[i].translate[3] = 0;
+
+ buffer->fb_state[i].zsbuf = NULL;
+ }
+
+ return true;
+}
+
+void
+vl_idct_cleanup_buffer(struct vl_idct *idct, struct vl_idct_buffer *buffer)
+{
+ unsigned i;
+
+ assert(buffer);
+
+ for(i = 0; i < NR_RENDER_TARGETS; ++i) {
+ idct->pipe->surface_destroy(idct->pipe, buffer->fb_state[0].cbufs[i]);
+ }
+
+ idct->pipe->surface_destroy(idct->pipe, buffer->fb_state[1].cbufs[0]);
+
+ cleanup_textures(idct, buffer);
+ cleanup_vertex_buffers(idct, buffer);
+}
+
+void
+vl_idct_map_buffers(struct vl_idct *idct, struct vl_idct_buffer *buffer)
+{
+ assert(idct);
+
+ struct pipe_box rect =
+ {
+ 0, 0, 0,
+ buffer->textures.individual.source->width0,
+ buffer->textures.individual.source->height0,
+ 1
+ };
+
+ buffer->tex_transfer = idct->pipe->get_transfer
+ (
+ idct->pipe, buffer->textures.individual.source,
+ 0, PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD,
+ &rect
+ );
+
+ buffer->texels = idct->pipe->transfer_map(idct->pipe, buffer->tex_transfer);
+
+ vl_vb_map(&buffer->blocks, idct->pipe);
+}
+
+void
+vl_idct_add_block(struct vl_idct_buffer *buffer, unsigned x, unsigned y, short *block)
+{
+ struct vertex2f v;
+ unsigned tex_pitch;
+ short *texels;
+
+ unsigned i;
+
+ assert(buffer);
+
+ tex_pitch = buffer->tex_transfer->stride / sizeof(short);
+ texels = buffer->texels + y * tex_pitch * BLOCK_HEIGHT + x * BLOCK_WIDTH;
+
+ for (i = 0; i < BLOCK_HEIGHT; ++i)
+ memcpy(texels + i * tex_pitch, block + i * BLOCK_WIDTH, BLOCK_WIDTH * sizeof(short));
+
+ v.x = x;
+ v.y = y;
+ vl_vb_add_block(&buffer->blocks, (float*)&v);
+}
+
+void
+vl_idct_unmap_buffers(struct vl_idct *idct, struct vl_idct_buffer *buffer)
+{
+ assert(idct && buffer);
+
+ idct->pipe->transfer_unmap(idct->pipe, buffer->tex_transfer);
+ idct->pipe->transfer_destroy(idct->pipe, buffer->tex_transfer);
+ vl_vb_unmap(&buffer->blocks, idct->pipe);
+}
+
+void
+vl_idct_flush(struct vl_idct *idct, struct vl_idct_buffer *buffer)
+{
+ unsigned num_verts;
+
+ assert(idct);
+
+ num_verts = vl_vb_restart(&buffer->blocks);
+
+ if(num_verts > 0) {
+
+ idct->pipe->bind_rasterizer_state(idct->pipe, idct->rs_state);
+ idct->pipe->set_vertex_buffers(idct->pipe, 2, buffer->vertex_bufs.all);
+ idct->pipe->bind_vertex_elements_state(idct->pipe, idct->vertex_elems_state);
+
+ /* first stage */
+ idct->pipe->set_framebuffer_state(idct->pipe, &buffer->fb_state[0]);
+ idct->pipe->set_viewport_state(idct->pipe, &buffer->viewport[0]);
+ idct->pipe->set_fragment_sampler_views(idct->pipe, 2, buffer->sampler_views.stage[0]);
+ idct->pipe->bind_fragment_sampler_states(idct->pipe, 2, idct->samplers.stage[0]);
+ idct->pipe->bind_vs_state(idct->pipe, idct->matrix_vs);
+ idct->pipe->bind_fs_state(idct->pipe, idct->matrix_fs);
+ util_draw_arrays(idct->pipe, PIPE_PRIM_QUADS, 0, num_verts);
+
+ /* second stage */
+ idct->pipe->set_framebuffer_state(idct->pipe, &buffer->fb_state[1]);
+ idct->pipe->set_viewport_state(idct->pipe, &buffer->viewport[1]);
+ idct->pipe->set_fragment_sampler_views(idct->pipe, 2, buffer->sampler_views.stage[1]);
+ idct->pipe->bind_fragment_sampler_states(idct->pipe, 2, idct->samplers.stage[1]);
+ idct->pipe->bind_vs_state(idct->pipe, idct->transpose_vs);
+ idct->pipe->bind_fs_state(idct->pipe, idct->transpose_fs);
+ util_draw_arrays(idct->pipe, PIPE_PRIM_QUADS, 0, num_verts);
+ }
+}
diff --git a/src/gallium/auxiliary/vl/vl_idct.h b/src/gallium/auxiliary/vl/vl_idct.h
new file mode 100644
index 00000000000..fcba75a7607
--- /dev/null
+++ b/src/gallium/auxiliary/vl/vl_idct.h
@@ -0,0 +1,124 @@
+/**************************************************************************
+ *
+ * Copyright 2010 Christian König
+ * 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 vl_idct_h
+#define vl_idct_h
+
+#include <pipe/p_state.h>
+#include "vl_vertex_buffers.h"
+
+struct vl_idct
+{
+ struct pipe_context *pipe;
+
+ unsigned buffer_width;
+ unsigned buffer_height;
+
+ unsigned max_blocks;
+
+ void *rs_state;
+ void *vertex_elems_state;
+
+ union
+ {
+ void *all[4];
+ void *stage[2][2];
+ struct {
+ void *matrix, *source;
+ void *transpose, *intermediate;
+ } individual;
+ } samplers;
+
+ void *matrix_vs, *transpose_vs;
+ void *matrix_fs, *transpose_fs;
+
+ struct pipe_resource *matrix;
+ struct pipe_vertex_buffer quad;
+
+ unsigned vertex_buffer_stride;
+};
+
+struct vl_idct_buffer
+{
+ struct pipe_viewport_state viewport[2];
+ struct pipe_framebuffer_state fb_state[2];
+
+ struct pipe_resource *destination;
+
+ union
+ {
+ struct pipe_sampler_view *all[4];
+ struct pipe_sampler_view *stage[2][2];
+ struct {
+ struct pipe_sampler_view *matrix, *source;
+ struct pipe_sampler_view *transpose, *intermediate;
+ } individual;
+ } sampler_views;
+
+ union
+ {
+ struct pipe_resource *all[4];
+ struct pipe_resource *stage[2][2];
+ struct {
+ struct pipe_resource *matrix, *source;
+ struct pipe_resource *transpose, *intermediate;
+ } individual;
+ } textures;
+
+ union
+ {
+ struct pipe_vertex_buffer all[2];
+ struct { struct pipe_vertex_buffer quad, pos; } individual;
+ } vertex_bufs;
+
+ struct vl_vertex_buffer blocks;
+
+ struct pipe_transfer *tex_transfer;
+ short *texels;
+};
+
+struct pipe_resource *vl_idct_upload_matrix(struct pipe_context *pipe);
+
+bool vl_idct_init(struct vl_idct *idct, struct pipe_context *pipe,
+ unsigned buffer_width, unsigned buffer_height,
+ struct pipe_resource *matrix);
+
+void vl_idct_cleanup(struct vl_idct *idct);
+
+bool vl_idct_init_buffer(struct vl_idct *idct, struct vl_idct_buffer *buffer, struct pipe_resource *dst);
+
+void vl_idct_cleanup_buffer(struct vl_idct *idct, struct vl_idct_buffer *buffer);
+
+void vl_idct_map_buffers(struct vl_idct *idct, struct vl_idct_buffer *buffer);
+
+void vl_idct_add_block(struct vl_idct_buffer *buffer, unsigned x, unsigned y, short *block);
+
+void vl_idct_unmap_buffers(struct vl_idct *idct, struct vl_idct_buffer *buffer);
+
+void vl_idct_flush(struct vl_idct *idct, struct vl_idct_buffer *buffer);
+
+#endif
diff --git a/src/gallium/auxiliary/vl/vl_mpeg12_mc_renderer.c b/src/gallium/auxiliary/vl/vl_mpeg12_mc_renderer.c
new file mode 100644
index 00000000000..b195d7e2c39
--- /dev/null
+++ b/src/gallium/auxiliary/vl/vl_mpeg12_mc_renderer.c
@@ -0,0 +1,1120 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 "vl_mpeg12_mc_renderer.h"
+#include "util/u_draw.h"
+#include <assert.h>
+#include <pipe/p_context.h>
+#include <util/u_inlines.h>
+#include <util/u_format.h>
+#include <util/u_math.h>
+#include <util/u_memory.h>
+#include <util/u_keymap.h>
+#include <util/u_sampler.h>
+#include <tgsi/tgsi_ureg.h>
+
+#define DEFAULT_BUF_ALIGNMENT 1
+#define MACROBLOCK_WIDTH 16
+#define MACROBLOCK_HEIGHT 16
+#define BLOCK_WIDTH 8
+#define BLOCK_HEIGHT 8
+
+struct vertex_stream
+{
+ struct vertex2f pos;
+ struct {
+ float y;
+ float cr;
+ float cb;
+ } eb[2][2];
+ float interlaced;
+ float frame_pred;
+ float ref_frames;
+ float bkwd_pred;
+ struct vertex2f mv[4];
+};
+
+enum VS_INPUT
+{
+ VS_I_RECT,
+ VS_I_VPOS,
+ VS_I_EB_0_0,
+ VS_I_EB_0_1,
+ VS_I_EB_1_0,
+ VS_I_EB_1_1,
+ VS_I_INTERLACED,
+ VS_I_FRAME_PRED,
+ VS_I_REF_FRAMES,
+ VS_I_BKWD_PRED,
+ VS_I_MV0,
+ VS_I_MV1,
+ VS_I_MV2,
+ VS_I_MV3,
+
+ NUM_VS_INPUTS
+};
+
+enum VS_OUTPUT
+{
+ VS_O_VPOS,
+ VS_O_LINE,
+ VS_O_TEX0,
+ VS_O_TEX1,
+ VS_O_TEX2,
+ VS_O_EB_0,
+ VS_O_EB_1,
+ VS_O_INFO,
+ VS_O_MV0,
+ VS_O_MV1,
+ VS_O_MV2,
+ VS_O_MV3
+};
+
+static void *
+create_vert_shader(struct vl_mpeg12_mc_renderer *r)
+{
+ struct ureg_program *shader;
+ struct ureg_src block_scale, mv_scale;
+ struct ureg_src vrect, vpos, eb[2][2], vmv[4];
+ struct ureg_src interlaced, frame_pred, ref_frames, bkwd_pred;
+ struct ureg_dst t_vpos, t_vtex, t_vmv;
+ struct ureg_dst o_vpos, o_line, o_vtex[3], o_eb[2], o_vmv[4], o_info;
+ unsigned i, label;
+
+ shader = ureg_create(TGSI_PROCESSOR_VERTEX);
+ if (!shader)
+ return NULL;
+
+ t_vpos = ureg_DECL_temporary(shader);
+ t_vtex = ureg_DECL_temporary(shader);
+ t_vmv = ureg_DECL_temporary(shader);
+
+ vrect = ureg_DECL_vs_input(shader, VS_I_RECT);
+ vpos = ureg_DECL_vs_input(shader, VS_I_VPOS);
+ eb[0][0] = ureg_DECL_vs_input(shader, VS_I_EB_0_0);
+ eb[1][0] = ureg_DECL_vs_input(shader, VS_I_EB_1_0);
+ eb[0][1] = ureg_DECL_vs_input(shader, VS_I_EB_0_1);
+ eb[1][1] = ureg_DECL_vs_input(shader, VS_I_EB_1_1);
+ interlaced = ureg_DECL_vs_input(shader, VS_I_INTERLACED);
+ frame_pred = ureg_DECL_vs_input(shader, VS_I_FRAME_PRED);
+ ref_frames = ureg_DECL_vs_input(shader, VS_I_REF_FRAMES);
+ bkwd_pred = ureg_DECL_vs_input(shader, VS_I_BKWD_PRED);
+
+ o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS);
+ o_line = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_LINE);
+ o_vtex[0] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_TEX0);
+ o_vtex[1] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_TEX1);
+ o_vtex[2] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_TEX2);
+ o_eb[0] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_EB_0);
+ o_eb[1] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_EB_1);
+ o_info = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_INFO);
+
+ for (i = 0; i < 4; ++i) {
+ vmv[i] = ureg_DECL_vs_input(shader, VS_I_MV0 + i);
+ o_vmv[i] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_MV0 + i);
+ }
+
+ /*
+ * block_scale = (MACROBLOCK_WIDTH, MACROBLOCK_HEIGHT) / (dst.width, dst.height)
+ * mv_scale = 0.5 / (dst.width, dst.height);
+ *
+ * t_vpos = (vpos + vrect) * block_scale
+ * o_vpos.xy = t_vpos
+ * o_vpos.zw = vpos
+ *
+ * o_eb[0..1] = vrect.x ? eb[0..1][1] : eb[0..1][0]
+ *
+ * o_frame_pred = frame_pred
+ * o_info.x = ref_frames
+ * o_info.y = ref_frames > 0
+ * o_info.z = bkwd_pred
+ *
+ * // Apply motion vectors
+ * o_vmv[0..count] = t_vpos + vmv[0..count] * mv_scale
+ *
+ * o_line.xy = vrect * 8
+ * o_line.z = interlaced
+ *
+ * if(interlaced) {
+ * t_vtex.x = vrect.x
+ * t_vtex.y = vrect.y * 0.5
+ * t_vtex += vpos
+ *
+ * o_vtex[0].xy = t_vtex * block_scale
+ *
+ * t_vtex.y += 0.5
+ * o_vtex[1].xy = t_vtex * block_scale
+ * } else {
+ * o_vtex[0..1].xy = t_vpos
+ * }
+ * o_vtex[2].xy = t_vpos
+ *
+ */
+ block_scale = ureg_imm2f(shader,
+ (float)MACROBLOCK_WIDTH / r->buffer_width,
+ (float)MACROBLOCK_HEIGHT / r->buffer_height);
+
+ mv_scale = ureg_imm2f(shader,
+ 0.5f / r->buffer_width,
+ 0.5f / r->buffer_height);
+
+ ureg_ADD(shader, ureg_writemask(t_vpos, TGSI_WRITEMASK_XY), vpos, vrect);
+ ureg_MUL(shader, ureg_writemask(t_vpos, TGSI_WRITEMASK_XY), ureg_src(t_vpos), block_scale);
+ ureg_MOV(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_XY), ureg_src(t_vpos));
+ ureg_MOV(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_ZW), vpos);
+
+ ureg_CMP(shader, ureg_writemask(o_eb[0], TGSI_WRITEMASK_XYZ),
+ ureg_negate(ureg_scalar(vrect, TGSI_SWIZZLE_X)),
+ eb[0][1], eb[0][0]);
+ ureg_CMP(shader, ureg_writemask(o_eb[1], TGSI_WRITEMASK_XYZ),
+ ureg_negate(ureg_scalar(vrect, TGSI_SWIZZLE_X)),
+ eb[1][1], eb[1][0]);
+
+ ureg_MOV(shader, ureg_writemask(o_info, TGSI_WRITEMASK_X), ref_frames);
+ ureg_SGE(shader, ureg_writemask(o_info, TGSI_WRITEMASK_Y),
+ ureg_scalar(ref_frames, TGSI_SWIZZLE_X), ureg_imm1f(shader, 0.0f));
+ ureg_MOV(shader, ureg_writemask(o_info, TGSI_WRITEMASK_Z), ureg_scalar(bkwd_pred, TGSI_SWIZZLE_X));
+
+ ureg_MAD(shader, ureg_writemask(o_vmv[0], TGSI_WRITEMASK_XY), mv_scale, vmv[0], ureg_src(t_vpos));
+ ureg_MAD(shader, ureg_writemask(o_vmv[2], TGSI_WRITEMASK_XY), mv_scale, vmv[2], ureg_src(t_vpos));
+
+ ureg_CMP(shader, ureg_writemask(t_vmv, TGSI_WRITEMASK_XY),
+ ureg_negate(ureg_scalar(frame_pred, TGSI_SWIZZLE_X)),
+ vmv[0], vmv[1]);
+ ureg_MAD(shader, ureg_writemask(o_vmv[1], TGSI_WRITEMASK_XY), mv_scale, ureg_src(t_vmv), ureg_src(t_vpos));
+
+ ureg_CMP(shader, ureg_writemask(t_vmv, TGSI_WRITEMASK_XY),
+ ureg_negate(ureg_scalar(frame_pred, TGSI_SWIZZLE_X)),
+ vmv[2], vmv[3]);
+ ureg_MAD(shader, ureg_writemask(o_vmv[3], TGSI_WRITEMASK_XY), mv_scale, ureg_src(t_vmv), ureg_src(t_vpos));
+
+ ureg_MOV(shader, ureg_writemask(o_vtex[0], TGSI_WRITEMASK_XY), ureg_src(t_vpos));
+ ureg_MOV(shader, ureg_writemask(o_vtex[1], TGSI_WRITEMASK_XY), ureg_src(t_vpos));
+ ureg_MOV(shader, ureg_writemask(o_vtex[2], TGSI_WRITEMASK_XY), ureg_src(t_vpos));
+
+ ureg_MOV(shader, ureg_writemask(o_line, TGSI_WRITEMASK_X), ureg_scalar(vrect, TGSI_SWIZZLE_Y));
+ ureg_MUL(shader, ureg_writemask(o_line, TGSI_WRITEMASK_Y),
+ vrect, ureg_imm1f(shader, MACROBLOCK_HEIGHT / 2));
+
+ ureg_IF(shader, ureg_scalar(interlaced, TGSI_SWIZZLE_X), &label);
+
+ ureg_MOV(shader, ureg_writemask(t_vtex, TGSI_WRITEMASK_X), vrect);
+ ureg_MUL(shader, ureg_writemask(t_vtex, TGSI_WRITEMASK_Y), vrect, ureg_imm1f(shader, 0.5f));
+ ureg_ADD(shader, ureg_writemask(t_vtex, TGSI_WRITEMASK_XY), vpos, ureg_src(t_vtex));
+ ureg_MUL(shader, ureg_writemask(o_vtex[0], TGSI_WRITEMASK_XY), ureg_src(t_vtex), block_scale);
+ ureg_ADD(shader, ureg_writemask(t_vtex, TGSI_WRITEMASK_Y), ureg_src(t_vtex), ureg_imm1f(shader, 0.5f));
+ ureg_MUL(shader, ureg_writemask(o_vtex[1], TGSI_WRITEMASK_XY), ureg_src(t_vtex), block_scale);
+
+ ureg_MUL(shader, ureg_writemask(o_line, TGSI_WRITEMASK_X),
+ ureg_scalar(vrect, TGSI_SWIZZLE_Y),
+ ureg_imm1f(shader, MACROBLOCK_HEIGHT / 2));
+
+ ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
+ ureg_ENDIF(shader);
+
+ ureg_release_temporary(shader, t_vtex);
+ ureg_release_temporary(shader, t_vpos);
+ ureg_release_temporary(shader, t_vmv);
+
+ ureg_END(shader);
+
+ return ureg_create_shader_and_destroy(shader, r->pipe);
+}
+
+static struct ureg_dst
+calc_field(struct ureg_program *shader)
+{
+ struct ureg_dst tmp;
+ struct ureg_src line;
+
+ tmp = ureg_DECL_temporary(shader);
+
+ line = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_LINE, TGSI_INTERPOLATE_LINEAR);
+
+ /*
+ * line.x going from 0 to 1 if not interlaced
+ * line.x going from 0 to 8 in steps of 0.5 if interlaced
+ * line.y going from 0 to 8 in steps of 0.5
+ *
+ * tmp.xy = fraction(line)
+ * tmp.xy = tmp.xy >= 0.5 ? 1 : 0
+ */
+ ureg_FRC(shader, ureg_writemask(tmp, TGSI_WRITEMASK_XY), line);
+ ureg_SGE(shader, ureg_writemask(tmp, TGSI_WRITEMASK_XY), ureg_src(tmp), ureg_imm1f(shader, 0.5f));
+
+ return tmp;
+}
+
+static struct ureg_dst
+fetch_ycbcr(struct vl_mpeg12_mc_renderer *r, struct ureg_program *shader, struct ureg_dst field)
+{
+ struct ureg_src tc[3], sampler[3], eb[2];
+ struct ureg_dst texel, t_tc, t_eb_info;
+ unsigned i, label;
+
+ texel = ureg_DECL_temporary(shader);
+ t_tc = ureg_DECL_temporary(shader);
+ t_eb_info = ureg_DECL_temporary(shader);
+
+ tc[0] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_TEX0, TGSI_INTERPOLATE_LINEAR);
+ tc[1] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_TEX1, TGSI_INTERPOLATE_LINEAR);
+ tc[2] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_TEX2, TGSI_INTERPOLATE_LINEAR);
+
+ eb[0] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_EB_0, TGSI_INTERPOLATE_CONSTANT);
+ eb[1] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_EB_1, TGSI_INTERPOLATE_CONSTANT);
+
+ for (i = 0; i < 3; ++i) {
+ sampler[i] = ureg_DECL_sampler(shader, i);
+ }
+
+ /*
+ * texel.y = tex(field.y ? tc[1] : tc[0], sampler[0])
+ * texel.cb = tex(tc[2], sampler[1])
+ * texel.cr = tex(tc[2], sampler[2])
+ */
+
+ ureg_CMP(shader, ureg_writemask(t_tc, TGSI_WRITEMASK_XY),
+ ureg_negate(ureg_scalar(ureg_src(field), TGSI_SWIZZLE_X)),
+ tc[1], tc[0]);
+
+ ureg_CMP(shader, ureg_writemask(t_eb_info, TGSI_WRITEMASK_XYZ),
+ ureg_negate(ureg_scalar(ureg_src(field), TGSI_SWIZZLE_X)),
+ eb[1], eb[0]);
+
+ /* r600g is ignoring TGSI_INTERPOLATE_CONSTANT, just workaround this */
+ ureg_SLT(shader, ureg_writemask(t_eb_info, TGSI_WRITEMASK_XYZ), ureg_src(t_eb_info), ureg_imm1f(shader, 0.5f));
+
+ ureg_MOV(shader, ureg_writemask(texel, TGSI_WRITEMASK_XYZ), ureg_imm1f(shader, 0.0f));
+ for (i = 0; i < 3; ++i) {
+ ureg_IF(shader, ureg_scalar(ureg_src(t_eb_info), TGSI_SWIZZLE_X + i), &label);
+
+ /* Nouveau can't writemask tex dst regs (yet?), so this won't work anymore on nvidia hardware */
+ if(i==0 || r->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_444) {
+ ureg_TEX(shader, ureg_writemask(texel, TGSI_WRITEMASK_X << i), TGSI_TEXTURE_3D, ureg_src(t_tc), sampler[i]);
+ } else {
+ ureg_TEX(shader, ureg_writemask(texel, TGSI_WRITEMASK_X << i), TGSI_TEXTURE_3D, tc[2], sampler[i]);
+ }
+
+ ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
+ ureg_ENDIF(shader);
+ }
+
+ ureg_release_temporary(shader, t_tc);
+ ureg_release_temporary(shader, t_eb_info);
+
+ return texel;
+}
+
+static struct ureg_dst
+fetch_ref(struct ureg_program *shader, struct ureg_dst field)
+{
+ struct ureg_src info;
+ struct ureg_src tc[4], sampler[2];
+ struct ureg_dst ref[2], result;
+ unsigned i, intra_label, bi_label, label;
+
+ info = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_INFO, TGSI_INTERPOLATE_CONSTANT);
+
+ for (i = 0; i < 4; ++i)
+ tc[i] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_MV0 + i, TGSI_INTERPOLATE_LINEAR);
+
+ for (i = 0; i < 2; ++i) {
+ sampler[i] = ureg_DECL_sampler(shader, i + 3);
+ ref[i] = ureg_DECL_temporary(shader);
+ }
+
+ result = ureg_DECL_temporary(shader);
+
+ ureg_MOV(shader, ureg_writemask(result, TGSI_WRITEMASK_XYZ), ureg_imm1f(shader, 0.5f));
+
+ ureg_IF(shader, ureg_scalar(info, TGSI_SWIZZLE_Y), &intra_label);
+ ureg_CMP(shader, ureg_writemask(ref[0], TGSI_WRITEMASK_XY),
+ ureg_negate(ureg_scalar(ureg_src(field), TGSI_SWIZZLE_Y)),
+ tc[1], tc[0]);
+
+ ureg_IF(shader, ureg_scalar(info, TGSI_SWIZZLE_X), &bi_label);
+
+ /*
+ * result = tex(field.z ? tc[1] : tc[0], sampler[bkwd_pred ? 1 : 0])
+ */
+ ureg_IF(shader, ureg_scalar(info, TGSI_SWIZZLE_Z), &label);
+ ureg_TEX(shader, result, TGSI_TEXTURE_2D, ureg_src(ref[0]), sampler[1]);
+ ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
+ ureg_ELSE(shader, &label);
+ ureg_TEX(shader, result, TGSI_TEXTURE_2D, ureg_src(ref[0]), sampler[0]);
+ ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
+ ureg_ENDIF(shader);
+
+ ureg_fixup_label(shader, bi_label, ureg_get_instruction_number(shader));
+ ureg_ELSE(shader, &bi_label);
+
+ /*
+ * if (field.z)
+ * ref[0..1] = tex(tc[0..1], sampler[0..1])
+ * else
+ * ref[0..1] = tex(tc[2..3], sampler[0..1])
+ */
+ ureg_CMP(shader, ureg_writemask(ref[1], TGSI_WRITEMASK_XY),
+ ureg_negate(ureg_scalar(ureg_src(field), TGSI_SWIZZLE_Y)),
+ tc[3], tc[2]);
+ ureg_TEX(shader, ref[0], TGSI_TEXTURE_2D, ureg_src(ref[0]), sampler[0]);
+ ureg_TEX(shader, ref[1], TGSI_TEXTURE_2D, ureg_src(ref[1]), sampler[1]);
+
+ ureg_LRP(shader, ureg_writemask(result, TGSI_WRITEMASK_XYZ), ureg_imm1f(shader, 0.5f),
+ ureg_src(ref[0]), ureg_src(ref[1]));
+
+ ureg_fixup_label(shader, bi_label, ureg_get_instruction_number(shader));
+ ureg_ENDIF(shader);
+ ureg_fixup_label(shader, intra_label, ureg_get_instruction_number(shader));
+ ureg_ENDIF(shader);
+
+ for (i = 0; i < 2; ++i)
+ ureg_release_temporary(shader, ref[i]);
+
+ return result;
+}
+
+static void *
+create_frag_shader(struct vl_mpeg12_mc_renderer *r)
+{
+ struct ureg_program *shader;
+ struct ureg_dst result;
+ struct ureg_dst field, texel;
+ struct ureg_dst fragment;
+
+ shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
+ if (!shader)
+ return NULL;
+
+ fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
+
+ field = calc_field(shader);
+ texel = fetch_ycbcr(r, shader, field);
+
+ result = fetch_ref(shader, field);
+
+ ureg_ADD(shader, ureg_writemask(fragment, TGSI_WRITEMASK_XYZ), ureg_src(texel), ureg_src(result));
+
+ ureg_release_temporary(shader, field);
+ ureg_release_temporary(shader, texel);
+ ureg_release_temporary(shader, result);
+ ureg_END(shader);
+
+ return ureg_create_shader_and_destroy(shader, r->pipe);
+}
+
+static bool
+init_pipe_state(struct vl_mpeg12_mc_renderer *r)
+{
+ struct pipe_sampler_state sampler;
+ struct pipe_rasterizer_state rs_state;
+ unsigned filters[5];
+ unsigned i;
+
+ assert(r);
+
+ r->viewport.scale[0] = r->buffer_width;
+ r->viewport.scale[1] = r->buffer_height;
+ r->viewport.scale[2] = 1;
+ r->viewport.scale[3] = 1;
+ r->viewport.translate[0] = 0;
+ r->viewport.translate[1] = 0;
+ r->viewport.translate[2] = 0;
+ r->viewport.translate[3] = 0;
+
+ r->fb_state.width = r->buffer_width;
+ r->fb_state.height = r->buffer_height;
+ r->fb_state.nr_cbufs = 1;
+ r->fb_state.zsbuf = NULL;
+
+ /* Luma filter */
+ filters[0] = PIPE_TEX_FILTER_NEAREST;
+ /* Chroma filters */
+ if (r->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_444 || true) { //TODO
+ filters[1] = PIPE_TEX_FILTER_NEAREST;
+ filters[2] = PIPE_TEX_FILTER_NEAREST;
+ }
+ else {
+ filters[1] = PIPE_TEX_FILTER_LINEAR;
+ filters[2] = PIPE_TEX_FILTER_LINEAR;
+ }
+ /* Fwd, bkwd ref filters */
+ filters[3] = PIPE_TEX_FILTER_LINEAR;
+ filters[4] = PIPE_TEX_FILTER_LINEAR;
+
+ for (i = 0; i < 5; ++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_BORDER;
+ sampler.min_img_filter = filters[i];
+ sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
+ sampler.mag_img_filter = filters[i];
+ sampler.compare_mode = PIPE_TEX_COMPARE_NONE;
+ sampler.compare_func = PIPE_FUNC_ALWAYS;
+ sampler.normalized_coords = 1;
+ /*sampler.shadow_ambient = ; */
+ /*sampler.lod_bias = ; */
+ sampler.min_lod = 0;
+ /*sampler.max_lod = ; */
+ sampler.border_color[0] = 0.0f;
+ sampler.border_color[1] = 0.0f;
+ sampler.border_color[2] = 0.0f;
+ sampler.border_color[3] = 0.0f;
+ /*sampler.max_anisotropy = ; */
+ r->samplers.all[i] = r->pipe->create_sampler_state(r->pipe, &sampler);
+ }
+
+ memset(&rs_state, 0, sizeof(rs_state));
+ /*rs_state.sprite_coord_enable */
+ rs_state.sprite_coord_mode = PIPE_SPRITE_COORD_UPPER_LEFT;
+ rs_state.point_quad_rasterization = true;
+ rs_state.point_size = BLOCK_WIDTH;
+ rs_state.gl_rasterization_rules = true;
+ r->rs_state = r->pipe->create_rasterizer_state(r->pipe, &rs_state);
+
+ return true;
+}
+
+static void
+cleanup_pipe_state(struct vl_mpeg12_mc_renderer *r)
+{
+ unsigned i;
+
+ assert(r);
+
+ for (i = 0; i < 5; ++i)
+ r->pipe->delete_sampler_state(r->pipe, r->samplers.all[i]);
+
+ r->pipe->delete_rasterizer_state(r->pipe, r->rs_state);
+}
+
+static bool
+init_buffers(struct vl_mpeg12_mc_renderer *r)
+{
+ struct pipe_resource *idct_matrix;
+ struct pipe_vertex_element vertex_elems[NUM_VS_INPUTS];
+
+ const unsigned mbw =
+ align(r->buffer_width, MACROBLOCK_WIDTH) / MACROBLOCK_WIDTH;
+ const unsigned mbh =
+ align(r->buffer_height, MACROBLOCK_HEIGHT) / MACROBLOCK_HEIGHT;
+
+ unsigned i, chroma_width, chroma_height;
+
+ assert(r);
+
+ r->macroblocks_per_batch =
+ mbw * (r->bufmode == VL_MPEG12_MC_RENDERER_BUFFER_PICTURE ? mbh : 1);
+
+ if (!(idct_matrix = vl_idct_upload_matrix(r->pipe)))
+ return false;
+
+ if (!vl_idct_init(&r->idct_luma, r->pipe, r->buffer_width, r->buffer_height, idct_matrix))
+ return false;
+
+ if (r->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420) {
+ chroma_width = r->buffer_width / 2;
+ chroma_height = r->buffer_height / 2;
+ } else if (r->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_422) {
+ chroma_width = r->buffer_width;
+ chroma_height = r->buffer_height / 2;
+ } else {
+ chroma_width = r->buffer_width;
+ chroma_height = r->buffer_height;
+ }
+
+ if(!vl_idct_init(&r->idct_chroma, r->pipe, chroma_width, chroma_height, idct_matrix))
+ return false;
+
+ memset(&vertex_elems, 0, sizeof(vertex_elems));
+
+ vertex_elems[VS_I_RECT] = vl_vb_get_quad_vertex_element();
+ r->quad = vl_vb_upload_quads(r->pipe, r->macroblocks_per_batch);
+
+ /* Position element */
+ vertex_elems[VS_I_VPOS].src_format = PIPE_FORMAT_R32G32_FLOAT;
+
+ /* y, cr, cb empty block element top left block */
+ vertex_elems[VS_I_EB_0_0].src_format = PIPE_FORMAT_R32G32B32_FLOAT;
+
+ /* y, cr, cb empty block element top right block */
+ vertex_elems[VS_I_EB_0_1].src_format = PIPE_FORMAT_R32G32B32_FLOAT;
+
+ /* y, cr, cb empty block element bottom left block */
+ vertex_elems[VS_I_EB_1_0].src_format = PIPE_FORMAT_R32G32B32_FLOAT;
+
+ /* y, cr, cb empty block element bottom right block */
+ vertex_elems[VS_I_EB_1_1].src_format = PIPE_FORMAT_R32G32B32_FLOAT;
+
+ /* progressive=0.0f interlaced=1.0f */
+ vertex_elems[VS_I_INTERLACED].src_format = PIPE_FORMAT_R32_FLOAT;
+
+ /* frame=0.0f field=1.0f */
+ vertex_elems[VS_I_FRAME_PRED].src_format = PIPE_FORMAT_R32_FLOAT;
+
+ /* intra=-1.0f forward/backward=1.0f bi=0.0f */
+ vertex_elems[VS_I_REF_FRAMES].src_format = PIPE_FORMAT_R32_FLOAT;
+
+ /* forward=0.0f backward=1.0f */
+ vertex_elems[VS_I_BKWD_PRED].src_format = PIPE_FORMAT_R32_FLOAT;
+
+ for (i = 0; i < 4; ++i)
+ /* motion vector 0..4 element */
+ vertex_elems[VS_I_MV0 + i].src_format = PIPE_FORMAT_R32G32_FLOAT;
+
+ r->vertex_stream_stride = vl_vb_element_helper(&vertex_elems[VS_I_VPOS], 13, 1);
+
+ r->vertex_elems_state = r->pipe->create_vertex_elements_state(
+ r->pipe, NUM_VS_INPUTS, vertex_elems);
+
+ if (r->vertex_elems_state == NULL)
+ return false;
+
+ r->vs = create_vert_shader(r);
+ r->fs = create_frag_shader(r);
+
+ if (r->vs == NULL || r->fs == NULL)
+ return false;
+
+ return true;
+}
+
+static void
+cleanup_buffers(struct vl_mpeg12_mc_renderer *r)
+{
+ assert(r);
+
+ r->pipe->delete_vs_state(r->pipe, r->vs);
+ r->pipe->delete_fs_state(r->pipe, r->fs);
+
+ vl_idct_cleanup(&r->idct_luma);
+ vl_idct_cleanup(&r->idct_chroma);
+
+ r->pipe->delete_vertex_elements_state(r->pipe, r->vertex_elems_state);
+}
+
+static struct pipe_sampler_view
+*find_or_create_sampler_view(struct vl_mpeg12_mc_renderer *r, struct pipe_surface *surface)
+{
+ struct pipe_sampler_view *sampler_view;
+ assert(r);
+ assert(surface);
+
+ sampler_view = (struct pipe_sampler_view*)util_keymap_lookup(r->texview_map, &surface);
+ if (!sampler_view) {
+ struct pipe_sampler_view templat;
+ boolean added_to_map;
+
+ u_sampler_view_default_template(&templat, surface->texture,
+ surface->texture->format);
+ sampler_view = r->pipe->create_sampler_view(r->pipe, surface->texture,
+ &templat);
+ if (!sampler_view)
+ return NULL;
+
+ added_to_map = util_keymap_insert(r->texview_map, &surface,
+ sampler_view, r->pipe);
+ assert(added_to_map);
+ }
+
+ return sampler_view;
+}
+
+static void
+get_motion_vectors(struct pipe_mpeg12_macroblock *mb, struct vertex2f mv[4])
+{
+ switch (mb->mb_type) {
+ case PIPE_MPEG12_MACROBLOCK_TYPE_BI:
+ {
+ if (mb->mo_type == PIPE_MPEG12_MOTION_TYPE_FRAME) {
+
+ mv[2].x = mb->pmv[0][1][0];
+ mv[2].y = mb->pmv[0][1][1];
+
+ } else {
+ mv[2].x = mb->pmv[0][1][0];
+ mv[2].y = mb->pmv[0][1][1] - (mb->pmv[0][1][1] % 4);
+
+ mv[3].x = mb->pmv[1][1][0];
+ mv[3].y = mb->pmv[1][1][1] - (mb->pmv[1][1][1] % 4);
+
+ if(mb->mvfs[0][1]) mv[2].y += 2;
+ if(!mb->mvfs[1][1]) mv[3].y -= 2;
+ }
+
+ /* fall-through */
+ }
+ case PIPE_MPEG12_MACROBLOCK_TYPE_FWD:
+ case PIPE_MPEG12_MACROBLOCK_TYPE_BKWD:
+ {
+ if (mb->mb_type == PIPE_MPEG12_MACROBLOCK_TYPE_BKWD) {
+
+ if (mb->mo_type == PIPE_MPEG12_MOTION_TYPE_FRAME) {
+ mv[0].x = mb->pmv[0][1][0];
+ mv[0].y = mb->pmv[0][1][1];
+
+ } else {
+ mv[0].x = mb->pmv[0][1][0];
+ mv[0].y = mb->pmv[0][1][1] - (mb->pmv[0][1][1] % 4);
+
+ mv[1].x = mb->pmv[1][1][0];
+ mv[1].y = mb->pmv[1][1][1] - (mb->pmv[1][1][1] % 4);
+
+ if(mb->mvfs[0][1]) mv[0].y += 2;
+ if(!mb->mvfs[1][1]) mv[1].y -= 2;
+ }
+
+ } else {
+
+ if (mb->mo_type == PIPE_MPEG12_MOTION_TYPE_FRAME) {
+ mv[0].x = mb->pmv[0][0][0];
+ mv[0].y = mb->pmv[0][0][1];
+
+ } else {
+ mv[0].x = mb->pmv[0][0][0];
+ mv[0].y = mb->pmv[0][0][1] - (mb->pmv[0][0][1] % 4);
+
+ mv[1].x = mb->pmv[1][0][0];
+ mv[1].y = mb->pmv[1][0][1] - (mb->pmv[1][0][1] % 4);
+
+ if(mb->mvfs[0][0]) mv[0].y += 2;
+ if(!mb->mvfs[1][0]) mv[1].y -= 2;
+ }
+ }
+ }
+ default:
+ break;
+ }
+}
+
+static bool
+empty_block(enum pipe_video_chroma_format chroma_format,
+ unsigned cbp, unsigned component,
+ unsigned x, unsigned y)
+{
+ /* TODO: Implement 422, 444 */
+ assert(chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420);
+
+ if(component == 0) /*luma*/
+ return !(cbp & (1 << (5 - (x + y * 2))));
+ else /*cr cb*/
+ return !(cbp & (1 << (2 - component)));
+}
+
+static void
+grab_vectors(struct vl_mpeg12_mc_renderer *r,
+ struct vl_mpeg12_mc_buffer *buffer,
+ struct pipe_mpeg12_macroblock *mb)
+{
+ struct vertex_stream stream;
+
+ unsigned i, j;
+
+ assert(r);
+ assert(mb);
+
+ stream.pos.x = mb->mbx;
+ stream.pos.y = mb->mby;
+ for ( i = 0; i < 2; ++i) {
+ for ( j = 0; j < 2; ++j) {
+ stream.eb[i][j].y = empty_block(r->chroma_format, mb->cbp, 0, j, i);
+ stream.eb[i][j].cr = empty_block(r->chroma_format, mb->cbp, 1, j, i);
+ stream.eb[i][j].cb = empty_block(r->chroma_format, mb->cbp, 2, j, i);
+ }
+ }
+ stream.interlaced = mb->dct_type == PIPE_MPEG12_DCT_TYPE_FIELD ? 1.0f : 0.0f;
+ stream.frame_pred = mb->mo_type == PIPE_MPEG12_MOTION_TYPE_FRAME ? 1.0f : 0.0f;
+ stream.bkwd_pred = mb->mb_type == PIPE_MPEG12_MACROBLOCK_TYPE_BKWD ? 1.0f : 0.0f;
+ switch (mb->mb_type) {
+ case PIPE_MPEG12_MACROBLOCK_TYPE_INTRA:
+ stream.ref_frames = -1.0f;
+ break;
+
+ case PIPE_MPEG12_MACROBLOCK_TYPE_FWD:
+ case PIPE_MPEG12_MACROBLOCK_TYPE_BKWD:
+ stream.ref_frames = 1.0f;
+ break;
+
+ case PIPE_MPEG12_MACROBLOCK_TYPE_BI:
+ stream.ref_frames = 0.0f;
+ break;
+
+ default:
+ assert(0);
+ }
+
+ get_motion_vectors(mb, stream.mv);
+ vl_vb_add_block(&buffer->vertex_stream, (float*)&stream);
+}
+
+static void
+grab_blocks(struct vl_mpeg12_mc_renderer *r,
+ struct vl_mpeg12_mc_buffer *buffer,
+ unsigned mbx, unsigned mby,
+ unsigned cbp, short *blocks)
+{
+ unsigned tb = 0;
+ unsigned x, y;
+
+ assert(r);
+ assert(blocks);
+
+ for (y = 0; y < 2; ++y) {
+ for (x = 0; x < 2; ++x, ++tb) {
+ if (!empty_block(r->chroma_format, cbp, 0, x, y)) {
+ vl_idct_add_block(&buffer->idct_y, mbx * 2 + x, mby * 2 + y, blocks);
+ blocks += BLOCK_WIDTH * BLOCK_HEIGHT;
+ }
+ }
+ }
+
+ /* TODO: Implement 422, 444 */
+ assert(r->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420);
+
+ for (tb = 1; tb < 3; ++tb) {
+ if (!empty_block(r->chroma_format, cbp, tb, 0, 0)) {
+ if(tb == 1)
+ vl_idct_add_block(&buffer->idct_cb, mbx, mby, blocks);
+ else
+ vl_idct_add_block(&buffer->idct_cr, mbx, mby, blocks);
+ blocks += BLOCK_WIDTH * BLOCK_HEIGHT;
+ }
+ }
+}
+
+static void
+grab_macroblock(struct vl_mpeg12_mc_renderer *r,
+ struct vl_mpeg12_mc_buffer *buffer,
+ struct pipe_mpeg12_macroblock *mb)
+{
+ assert(r);
+ assert(mb);
+ assert(mb->blocks);
+ assert(buffer->num_macroblocks < r->macroblocks_per_batch);
+
+ grab_vectors(r, buffer, mb);
+ grab_blocks(r, buffer, mb->mbx, mb->mby, mb->cbp, mb->blocks);
+
+ ++buffer->num_macroblocks;
+}
+
+static void
+texview_map_delete(const struct keymap *map,
+ const void *key, void *data,
+ void *user)
+{
+ struct pipe_sampler_view *sv = (struct pipe_sampler_view*)data;
+
+ assert(map);
+ assert(key);
+ assert(data);
+ assert(user);
+
+ pipe_sampler_view_reference(&sv, NULL);
+}
+
+bool
+vl_mpeg12_mc_renderer_init(struct vl_mpeg12_mc_renderer *renderer,
+ struct pipe_context *pipe,
+ unsigned buffer_width,
+ unsigned buffer_height,
+ enum pipe_video_chroma_format chroma_format,
+ enum VL_MPEG12_MC_RENDERER_BUFFER_MODE bufmode)
+{
+ assert(renderer);
+ assert(pipe);
+
+ /* TODO: Implement other policies */
+ assert(bufmode == VL_MPEG12_MC_RENDERER_BUFFER_PICTURE);
+
+ memset(renderer, 0, sizeof(struct vl_mpeg12_mc_renderer));
+
+ renderer->pipe = pipe;
+ renderer->buffer_width = buffer_width;
+ renderer->buffer_height = buffer_height;
+ renderer->chroma_format = chroma_format;
+ renderer->bufmode = bufmode;
+
+ renderer->texview_map = util_new_keymap(sizeof(struct pipe_surface*), -1,
+ texview_map_delete);
+ if (!renderer->texview_map)
+ return false;
+
+ if (!init_pipe_state(renderer))
+ goto error_pipe_state;
+
+ if (!init_buffers(renderer))
+ goto error_buffers;
+
+ return true;
+
+error_buffers:
+ cleanup_pipe_state(renderer);
+
+error_pipe_state:
+ util_delete_keymap(renderer->texview_map, renderer->pipe);
+ return false;
+}
+
+void
+vl_mpeg12_mc_renderer_cleanup(struct vl_mpeg12_mc_renderer *renderer)
+{
+ assert(renderer);
+
+ util_delete_keymap(renderer->texview_map, renderer->pipe);
+ cleanup_pipe_state(renderer);
+ cleanup_buffers(renderer);
+}
+
+bool
+vl_mpeg12_mc_init_buffer(struct vl_mpeg12_mc_renderer *renderer, struct vl_mpeg12_mc_buffer *buffer)
+{
+ struct pipe_resource template;
+ struct pipe_sampler_view sampler_view;
+
+ unsigned i;
+
+ assert(renderer && buffer);
+
+ buffer->surface = NULL;
+ buffer->past = NULL;
+ buffer->future = NULL;
+ buffer->num_macroblocks = 0;
+
+ memset(&template, 0, sizeof(struct pipe_resource));
+ template.target = PIPE_TEXTURE_2D;
+ /* TODO: Accomodate HW that can't do this and also for cases when this isn't precise enough */
+ template.format = PIPE_FORMAT_R16_SNORM;
+ template.last_level = 0;
+ template.width0 = renderer->buffer_width;
+ template.height0 = renderer->buffer_height;
+ template.depth0 = 1;
+ template.usage = PIPE_USAGE_DYNAMIC;
+ template.bind = PIPE_BIND_SAMPLER_VIEW;
+ template.flags = 0;
+
+ buffer->textures.individual.y = renderer->pipe->screen->resource_create(renderer->pipe->screen, &template);
+
+ if (!vl_idct_init_buffer(&renderer->idct_luma, &buffer->idct_y, buffer->textures.individual.y))
+ return false;
+
+ if (renderer->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420) {
+ template.width0 = renderer->buffer_width / 2;
+ template.height0 = renderer->buffer_height / 2;
+ }
+ else if (renderer->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_422)
+ template.height0 = renderer->buffer_height / 2;
+
+ buffer->textures.individual.cb =
+ renderer->pipe->screen->resource_create(renderer->pipe->screen, &template);
+ buffer->textures.individual.cr =
+ renderer->pipe->screen->resource_create(renderer->pipe->screen, &template);
+
+ if (!vl_idct_init_buffer(&renderer->idct_chroma, &buffer->idct_cb, buffer->textures.individual.cb))
+ return false;
+
+ if (!vl_idct_init_buffer(&renderer->idct_chroma, &buffer->idct_cr, buffer->textures.individual.cr))
+ return false;
+
+ for (i = 0; i < 3; ++i) {
+ u_sampler_view_default_template(&sampler_view,
+ buffer->textures.all[i],
+ buffer->textures.all[i]->format);
+ sampler_view.swizzle_r = i == 0 ? PIPE_SWIZZLE_RED : PIPE_SWIZZLE_ZERO;
+ sampler_view.swizzle_g = i == 1 ? PIPE_SWIZZLE_RED : PIPE_SWIZZLE_ZERO;
+ sampler_view.swizzle_b = i == 2 ? PIPE_SWIZZLE_RED : PIPE_SWIZZLE_ZERO;
+ sampler_view.swizzle_a = PIPE_SWIZZLE_ONE;
+ buffer->sampler_views.all[i] = renderer->pipe->create_sampler_view(
+ renderer->pipe, buffer->textures.all[i], &sampler_view);
+ }
+
+ buffer->vertex_bufs.individual.quad.stride = renderer->quad.stride;
+ buffer->vertex_bufs.individual.quad.max_index = renderer->quad.max_index;
+ buffer->vertex_bufs.individual.quad.buffer_offset = renderer->quad.buffer_offset;
+ pipe_resource_reference(&buffer->vertex_bufs.individual.quad.buffer, renderer->quad.buffer);
+
+ buffer->vertex_bufs.individual.stream = vl_vb_init(
+ &buffer->vertex_stream, renderer->pipe, renderer->macroblocks_per_batch,
+ sizeof(struct vertex_stream) / sizeof(float),
+ renderer->vertex_stream_stride);
+
+ return true;
+}
+
+void
+vl_mpeg12_mc_cleanup_buffer(struct vl_mpeg12_mc_renderer *renderer, struct vl_mpeg12_mc_buffer *buffer)
+{
+ unsigned i;
+
+ assert(renderer && buffer);
+
+ for (i = 0; i < 3; ++i) {
+ pipe_sampler_view_reference(&buffer->sampler_views.all[i], NULL);
+ pipe_resource_reference(&buffer->vertex_bufs.all[i].buffer, NULL);
+ pipe_resource_reference(&buffer->textures.all[i], NULL);
+ }
+
+ pipe_resource_reference(&buffer->vertex_bufs.individual.quad.buffer, NULL);
+ vl_vb_cleanup(&buffer->vertex_stream);
+
+ vl_idct_cleanup_buffer(&renderer->idct_luma, &buffer->idct_y);
+ vl_idct_cleanup_buffer(&renderer->idct_chroma, &buffer->idct_cb);
+ vl_idct_cleanup_buffer(&renderer->idct_chroma, &buffer->idct_cr);
+
+ pipe_surface_reference(&buffer->surface, NULL);
+ pipe_surface_reference(&buffer->past, NULL);
+ pipe_surface_reference(&buffer->future, NULL);
+}
+
+void
+vl_mpeg12_mc_map_buffer(struct vl_mpeg12_mc_renderer *renderer, struct vl_mpeg12_mc_buffer *buffer)
+{
+ assert(renderer && buffer);
+
+ vl_idct_map_buffers(&renderer->idct_luma, &buffer->idct_y);
+ vl_idct_map_buffers(&renderer->idct_chroma, &buffer->idct_cr);
+ vl_idct_map_buffers(&renderer->idct_chroma, &buffer->idct_cb);
+
+ vl_vb_map(&buffer->vertex_stream, renderer->pipe);
+}
+
+void
+vl_mpeg12_mc_renderer_render_macroblocks(struct vl_mpeg12_mc_renderer *renderer,
+ struct vl_mpeg12_mc_buffer *buffer,
+ struct pipe_surface *surface,
+ struct pipe_surface *past,
+ struct pipe_surface *future,
+ unsigned num_macroblocks,
+ struct pipe_mpeg12_macroblock *mpeg12_macroblocks,
+ struct pipe_fence_handle **fence)
+{
+ assert(renderer && buffer);
+ assert(surface);
+ assert(num_macroblocks);
+ assert(mpeg12_macroblocks);
+
+ if (surface != buffer->surface) {
+ pipe_surface_reference(&buffer->surface, surface);
+ pipe_surface_reference(&buffer->past, past);
+ pipe_surface_reference(&buffer->future, future);
+ buffer->fence = fence;
+ } else {
+ /* If the surface we're rendering hasn't changed the ref frames shouldn't change. */
+ assert(buffer->past == past);
+ assert(buffer->future == future);
+ }
+
+ while (num_macroblocks) {
+ unsigned left_in_batch = renderer->macroblocks_per_batch - buffer->num_macroblocks;
+ unsigned num_to_submit = MIN2(num_macroblocks, left_in_batch);
+ unsigned i;
+
+ for (i = 0; i < num_to_submit; ++i) {
+ assert(mpeg12_macroblocks[i].base.codec == PIPE_VIDEO_CODEC_MPEG12);
+ grab_macroblock(renderer, buffer, &mpeg12_macroblocks[i]);
+ }
+
+ num_macroblocks -= num_to_submit;
+
+ if (buffer->num_macroblocks == renderer->macroblocks_per_batch) {
+ vl_mpeg12_mc_unmap_buffer(renderer, buffer);
+ vl_mpeg12_mc_renderer_flush(renderer, buffer);
+ pipe_surface_reference(&buffer->surface, surface);
+ pipe_surface_reference(&buffer->past, past);
+ pipe_surface_reference(&buffer->future, future);
+ vl_mpeg12_mc_map_buffer(renderer, buffer);
+ }
+ }
+}
+
+void
+vl_mpeg12_mc_unmap_buffer(struct vl_mpeg12_mc_renderer *renderer, struct vl_mpeg12_mc_buffer *buffer)
+{
+ assert(renderer && buffer);
+
+ vl_idct_unmap_buffers(&renderer->idct_luma, &buffer->idct_y);
+ vl_idct_unmap_buffers(&renderer->idct_chroma, &buffer->idct_cr);
+ vl_idct_unmap_buffers(&renderer->idct_chroma, &buffer->idct_cb);
+
+ vl_vb_unmap(&buffer->vertex_stream, renderer->pipe);
+}
+
+void
+vl_mpeg12_mc_renderer_flush(struct vl_mpeg12_mc_renderer *renderer, struct vl_mpeg12_mc_buffer *buffer)
+{
+ assert(renderer && buffer);
+ assert(buffer->num_macroblocks <= renderer->macroblocks_per_batch);
+
+ if (buffer->num_macroblocks == 0)
+ return;
+
+ vl_idct_flush(&renderer->idct_luma, &buffer->idct_y);
+ vl_idct_flush(&renderer->idct_chroma, &buffer->idct_cr);
+ vl_idct_flush(&renderer->idct_chroma, &buffer->idct_cb);
+
+ vl_vb_restart(&buffer->vertex_stream);
+
+ renderer->fb_state.cbufs[0] = buffer->surface;
+ renderer->pipe->bind_rasterizer_state(renderer->pipe, renderer->rs_state);
+ renderer->pipe->set_framebuffer_state(renderer->pipe, &renderer->fb_state);
+ renderer->pipe->set_viewport_state(renderer->pipe, &renderer->viewport);
+ renderer->pipe->set_vertex_buffers(renderer->pipe, 2, buffer->vertex_bufs.all);
+ renderer->pipe->bind_vertex_elements_state(renderer->pipe, renderer->vertex_elems_state);
+
+ if (buffer->past) {
+ buffer->textures.individual.ref[0] = buffer->past->texture;
+ buffer->sampler_views.individual.ref[0] = find_or_create_sampler_view(renderer, buffer->past);
+ } else {
+ buffer->textures.individual.ref[0] = buffer->surface->texture;
+ buffer->sampler_views.individual.ref[0] = find_or_create_sampler_view(renderer, buffer->surface);
+ }
+
+ if (buffer->future) {
+ buffer->textures.individual.ref[1] = buffer->future->texture;
+ buffer->sampler_views.individual.ref[1] = find_or_create_sampler_view(renderer, buffer->future);
+ } else {
+ buffer->textures.individual.ref[1] = buffer->surface->texture;
+ buffer->sampler_views.individual.ref[1] = find_or_create_sampler_view(renderer, buffer->surface);
+ }
+
+ renderer->pipe->set_fragment_sampler_views(renderer->pipe, 5, buffer->sampler_views.all);
+ renderer->pipe->bind_fragment_sampler_states(renderer->pipe, 5, renderer->samplers.all);
+
+ renderer->pipe->bind_vs_state(renderer->pipe, renderer->vs);
+ renderer->pipe->bind_fs_state(renderer->pipe, renderer->fs);
+ util_draw_arrays(renderer->pipe, PIPE_PRIM_QUADS, 0, buffer->num_macroblocks * 4);
+
+ renderer->pipe->flush(renderer->pipe, PIPE_FLUSH_RENDER_CACHE, buffer->fence);
+
+ /* Next time we get this surface it may have new ref frames */
+ pipe_surface_reference(&buffer->surface, NULL);
+ pipe_surface_reference(&buffer->past, NULL);
+ pipe_surface_reference(&buffer->future, NULL);
+
+ buffer->num_macroblocks = 0;
+}
diff --git a/src/gallium/auxiliary/vl/vl_mpeg12_mc_renderer.h b/src/gallium/auxiliary/vl/vl_mpeg12_mc_renderer.h
new file mode 100644
index 00000000000..79e872c2bee
--- /dev/null
+++ b/src/gallium/auxiliary/vl/vl_mpeg12_mc_renderer.h
@@ -0,0 +1,140 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 vl_mpeg12_mc_renderer_h
+#define vl_mpeg12_mc_renderer_h
+
+#include <pipe/p_compiler.h>
+#include <pipe/p_state.h>
+#include <pipe/p_video_state.h>
+#include "vl_types.h"
+#include "vl_idct.h"
+#include "vl_vertex_buffers.h"
+
+struct pipe_context;
+struct pipe_macroblock;
+struct keymap;
+
+/* A slice is video-width (rounded up to a multiple of macroblock width) x macroblock height */
+enum VL_MPEG12_MC_RENDERER_BUFFER_MODE
+{
+ VL_MPEG12_MC_RENDERER_BUFFER_SLICE, /* Saves memory at the cost of smaller batches */
+ VL_MPEG12_MC_RENDERER_BUFFER_PICTURE /* Larger batches, more memory */
+};
+
+struct vl_mpeg12_mc_renderer
+{
+ struct pipe_context *pipe;
+ unsigned buffer_width;
+ unsigned buffer_height;
+ enum pipe_video_chroma_format chroma_format;
+ enum VL_MPEG12_MC_RENDERER_BUFFER_MODE bufmode;
+ unsigned macroblocks_per_batch;
+
+ unsigned vertex_stream_stride;
+
+ struct pipe_viewport_state viewport;
+ struct pipe_framebuffer_state fb_state;
+
+ struct vl_idct idct_luma, idct_chroma;
+
+ void *vertex_elems_state;
+ void *rs_state;
+
+ void *vs, *fs;
+
+ struct pipe_vertex_buffer quad;
+
+ union
+ {
+ void *all[5];
+ struct { void *y, *cb, *cr, *ref[2]; } individual;
+ } samplers;
+
+ struct keymap *texview_map;
+};
+
+struct vl_mpeg12_mc_buffer
+{
+ struct vl_idct_buffer idct_y, idct_cb, idct_cr;
+
+ struct vl_vertex_buffer vertex_stream;
+
+ union
+ {
+ struct pipe_sampler_view *all[5];
+ struct { struct pipe_sampler_view *y, *cb, *cr, *ref[2]; } individual;
+ } sampler_views;
+
+ union
+ {
+ struct pipe_resource *all[5];
+ struct { struct pipe_resource *y, *cb, *cr, *ref[2]; } individual;
+ } textures;
+
+ union
+ {
+ struct pipe_vertex_buffer all[2];
+ struct {
+ struct pipe_vertex_buffer quad, stream;
+ } individual;
+ } vertex_bufs;
+
+ struct pipe_surface *surface, *past, *future;
+ struct pipe_fence_handle **fence;
+ unsigned num_macroblocks;
+};
+
+bool vl_mpeg12_mc_renderer_init(struct vl_mpeg12_mc_renderer *renderer,
+ struct pipe_context *pipe,
+ unsigned picture_width,
+ unsigned picture_height,
+ enum pipe_video_chroma_format chroma_format,
+ enum VL_MPEG12_MC_RENDERER_BUFFER_MODE bufmode);
+
+void vl_mpeg12_mc_renderer_cleanup(struct vl_mpeg12_mc_renderer *renderer);
+
+bool vl_mpeg12_mc_init_buffer(struct vl_mpeg12_mc_renderer *renderer, struct vl_mpeg12_mc_buffer *buffer);
+
+void vl_mpeg12_mc_cleanup_buffer(struct vl_mpeg12_mc_renderer *renderer, struct vl_mpeg12_mc_buffer *buffer);
+
+void vl_mpeg12_mc_map_buffer(struct vl_mpeg12_mc_renderer *renderer, struct vl_mpeg12_mc_buffer *buffer);
+
+void vl_mpeg12_mc_renderer_render_macroblocks(struct vl_mpeg12_mc_renderer *renderer,
+ struct vl_mpeg12_mc_buffer *buffer,
+ struct pipe_surface *surface,
+ struct pipe_surface *past,
+ struct pipe_surface *future,
+ unsigned num_macroblocks,
+ struct pipe_mpeg12_macroblock *mpeg12_macroblocks,
+ struct pipe_fence_handle **fence);
+
+void vl_mpeg12_mc_unmap_buffer(struct vl_mpeg12_mc_renderer *renderer, struct vl_mpeg12_mc_buffer *buffer);
+
+void vl_mpeg12_mc_renderer_flush(struct vl_mpeg12_mc_renderer *renderer, struct vl_mpeg12_mc_buffer *buffer);
+
+#endif /* vl_mpeg12_mc_renderer_h */
diff --git a/src/gallium/auxiliary/vl/vl_types.h b/src/gallium/auxiliary/vl/vl_types.h
new file mode 100644
index 00000000000..eeabd43cb23
--- /dev/null
+++ b/src/gallium/auxiliary/vl/vl_types.h
@@ -0,0 +1,46 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 vl_types_h
+#define vl_types_h
+
+struct vertex2f
+{
+ float x, y;
+};
+
+struct vertex4f
+{
+ float x, y, z, w;
+};
+
+struct quadf
+{
+ struct vertex2f bl, tl, tr, br;
+};
+
+#endif /* vl_types_h */
diff --git a/src/gallium/auxiliary/vl/vl_vertex_buffers.c b/src/gallium/auxiliary/vl/vl_vertex_buffers.c
new file mode 100644
index 00000000000..3a69730c9da
--- /dev/null
+++ b/src/gallium/auxiliary/vl/vl_vertex_buffers.c
@@ -0,0 +1,183 @@
+/**************************************************************************
+ *
+ * Copyright 2010 Christian König
+ * 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 <assert.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 "vl_vertex_buffers.h"
+#include "vl_types.h"
+
+/* vertices for a quad covering a block */
+static const struct quadf const_quad = {
+ {0.0f, 1.0f}, {0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}
+};
+
+struct pipe_vertex_buffer
+vl_vb_upload_quads(struct pipe_context *pipe, unsigned max_blocks)
+{
+ struct pipe_vertex_buffer quad;
+ struct pipe_transfer *buf_transfer;
+ struct quadf *v;
+
+ unsigned i;
+
+ assert(pipe);
+ assert(max_blocks);
+
+ /* create buffer */
+ quad.stride = sizeof(struct vertex2f);
+ quad.max_index = 4 * max_blocks - 1;
+ quad.buffer_offset = 0;
+ quad.buffer = pipe_buffer_create
+ (
+ pipe->screen,
+ PIPE_BIND_VERTEX_BUFFER,
+ sizeof(struct vertex2f) * 4 * max_blocks
+ );
+
+ if(!quad.buffer)
+ return quad;
+
+ /* and fill it */
+ v = pipe_buffer_map
+ (
+ pipe,
+ quad.buffer,
+ PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD,
+ &buf_transfer
+ );
+
+ for ( i = 0; i < max_blocks; ++i)
+ memcpy(v + i, &const_quad, sizeof(const_quad));
+
+ pipe_buffer_unmap(pipe, buf_transfer);
+
+ return quad;
+}
+
+struct pipe_vertex_element
+vl_vb_get_quad_vertex_element()
+{
+ struct pipe_vertex_element element;
+
+ /* setup rectangle element */
+ element.src_offset = 0;
+ element.instance_divisor = 0;
+ element.vertex_buffer_index = 0;
+ element.src_format = PIPE_FORMAT_R32G32_FLOAT;
+
+ return element;
+}
+
+unsigned
+vl_vb_element_helper(struct pipe_vertex_element* elements, unsigned num_elements,
+ unsigned vertex_buffer_index)
+{
+ unsigned i, offset = 0;
+
+ assert(elements && num_elements);
+
+ for ( i = 0; i < num_elements; ++i ) {
+ elements[i].src_offset = offset;
+ elements[i].instance_divisor = 0;
+ elements[i].vertex_buffer_index = vertex_buffer_index;
+ offset += util_format_get_blocksize(elements[i].src_format);
+ }
+
+ return offset;
+}
+
+struct pipe_vertex_buffer
+vl_vb_init(struct vl_vertex_buffer *buffer, struct pipe_context *pipe,
+ unsigned max_blocks, unsigned num_elements, unsigned stride)
+{
+ struct pipe_vertex_buffer buf;
+
+ assert(buffer);
+
+ buffer->num_verts = 0;
+ buffer->num_elements = num_elements;
+
+ buf.stride = stride;
+ buf.max_index = 4 * max_blocks - 1;
+ buf.buffer_offset = 0;
+ buf.buffer = pipe_buffer_create
+ (
+ pipe->screen,
+ PIPE_BIND_VERTEX_BUFFER,
+ stride * 4 * max_blocks
+ );
+
+ pipe_resource_reference(&buffer->resource, buf.buffer);
+
+ vl_vb_map(buffer, pipe);
+
+ return buf;
+}
+
+void
+vl_vb_map(struct vl_vertex_buffer *buffer, struct pipe_context *pipe)
+{
+ assert(buffer && pipe);
+
+ buffer->vectors = pipe_buffer_map
+ (
+ pipe,
+ buffer->resource,
+ PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD,
+ &buffer->transfer
+ );
+}
+
+void
+vl_vb_unmap(struct vl_vertex_buffer *buffer, struct pipe_context *pipe)
+{
+ assert(buffer && pipe);
+
+ pipe_buffer_unmap(pipe, buffer->transfer);
+}
+
+unsigned
+vl_vb_restart(struct vl_vertex_buffer *buffer)
+{
+ assert(buffer);
+
+ unsigned todo = buffer->num_verts;
+ buffer->num_verts = 0;
+ return todo;
+}
+
+void
+vl_vb_cleanup(struct vl_vertex_buffer *buffer)
+{
+ assert(buffer);
+
+ pipe_resource_reference(&buffer->resource, NULL);
+}
diff --git a/src/gallium/auxiliary/vl/vl_vertex_buffers.h b/src/gallium/auxiliary/vl/vl_vertex_buffers.h
new file mode 100644
index 00000000000..e312515dc30
--- /dev/null
+++ b/src/gallium/auxiliary/vl/vl_vertex_buffers.h
@@ -0,0 +1,78 @@
+/**************************************************************************
+ *
+ * Copyright 2010 Christian König
+ * 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 vl_vertex_buffers_h
+#define vl_vertex_buffers_h
+
+#include <assert.h>
+#include <pipe/p_state.h>
+#include "vl_types.h"
+
+struct vl_vertex_buffer
+{
+ unsigned num_verts;
+ unsigned num_elements;
+ struct pipe_resource *resource;
+ struct pipe_transfer *transfer;
+ float *vectors;
+};
+
+struct pipe_vertex_buffer vl_vb_upload_quads(struct pipe_context *pipe, unsigned max_blocks);
+
+struct pipe_vertex_element vl_vb_get_quad_vertex_element();
+
+unsigned vl_vb_element_helper(struct pipe_vertex_element* elements, unsigned num_elements,
+ unsigned vertex_buffer_index);
+
+struct pipe_vertex_buffer vl_vb_init(struct vl_vertex_buffer *buffer,
+ struct pipe_context *pipe,
+ unsigned max_blocks, unsigned num_elements,
+ unsigned stride);
+
+void vl_vb_map(struct vl_vertex_buffer *buffer, struct pipe_context *pipe);
+
+static inline void
+vl_vb_add_block(struct vl_vertex_buffer *buffer, float *elements)
+{
+ float *pos;
+ unsigned i;
+
+ assert(buffer);
+
+ for(i = 0; i < 4; ++i) {
+ pos = buffer->vectors + buffer->num_verts * buffer->num_elements;
+ memcpy(pos, elements, sizeof(float) * buffer->num_elements);
+ buffer->num_verts++;
+ }
+}
+
+void vl_vb_unmap(struct vl_vertex_buffer *buffer, struct pipe_context *pipe);
+
+unsigned vl_vb_restart(struct vl_vertex_buffer *buffer);
+
+void vl_vb_cleanup(struct vl_vertex_buffer *buffer);
+
+#endif
diff --git a/src/gallium/drivers/nv40/nv40_video_context.c b/src/gallium/drivers/nv40/nv40_video_context.c
new file mode 100644
index 00000000000..e6e57ee787c
--- /dev/null
+++ b/src/gallium/drivers/nv40/nv40_video_context.c
@@ -0,0 +1,47 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 "nv40_video_context.h"
+#include <softpipe/sp_video_context.h>
+
+struct pipe_video_context *
+nv40_video_create(struct pipe_screen *screen, enum pipe_video_profile profile,
+ enum pipe_video_chroma_format chroma_format,
+ unsigned width, unsigned height, void *priv)
+{
+ struct pipe_context *pipe;
+
+ assert(screen);
+
+ pipe = screen->context_create(screen, priv);
+ if (!pipe)
+ return NULL;
+
+ return sp_video_create_ex(pipe, profile, chroma_format, width, height,
+ VL_MPEG12_MC_RENDERER_BUFFER_PICTURE,
+ true);
+}
diff --git a/src/gallium/drivers/nv40/nv40_video_context.h b/src/gallium/drivers/nv40/nv40_video_context.h
new file mode 100644
index 00000000000..64196caca72
--- /dev/null
+++ b/src/gallium/drivers/nv40/nv40_video_context.h
@@ -0,0 +1,38 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 __NV40_VIDEO_CONTEXT_H__
+#define __NV40_VIDEO_CONTEXT_H__
+
+#include <pipe/p_video_context.h>
+
+struct pipe_video_context *
+nv40_video_create(struct pipe_screen *screen, enum pipe_video_profile profile,
+ enum pipe_video_chroma_format chroma_format,
+ unsigned width, unsigned height, void *priv);
+
+#endif
diff --git a/src/gallium/drivers/nvfx/Makefile b/src/gallium/drivers/nvfx/Makefile
index 46bb0823881..95da7782256 100644
--- a/src/gallium/drivers/nvfx/Makefile
+++ b/src/gallium/drivers/nvfx/Makefile
@@ -24,7 +24,8 @@ C_SOURCES = \
nvfx_surface.c \
nvfx_transfer.c \
nvfx_vbo.c \
- nvfx_vertprog.c
+ nvfx_vertprog.c \
+ nvfx_video_context.c
LIBRARY_INCLUDES = \
-I$(TOP)/src/gallium/drivers/nouveau/include
diff --git a/src/gallium/drivers/nvfx/nvfx_screen.c b/src/gallium/drivers/nvfx/nvfx_screen.c
index aa1e9567d31..15db574a1d0 100644
--- a/src/gallium/drivers/nvfx/nvfx_screen.c
+++ b/src/gallium/drivers/nvfx/nvfx_screen.c
@@ -6,6 +6,7 @@
#include "nouveau/nouveau_screen.h"
#include "nouveau/nv_object.xml.h"
#include "nvfx_context.h"
+#include "nvfx_video_context.h"
#include "nvfx_screen.h"
#include "nvfx_resource.h"
#include "nvfx_tex.h"
@@ -455,6 +456,7 @@ nvfx_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev)
pscreen->get_paramf = nvfx_screen_get_paramf;
pscreen->is_format_supported = nvfx_screen_is_format_supported;
pscreen->context_create = nvfx_create;
+ pscreen->video_context_create = nvfx_video_create;
switch (dev->chipset & 0xf0) {
case 0x30:
diff --git a/src/gallium/drivers/nvfx/nvfx_state.h b/src/gallium/drivers/nvfx/nvfx_state.h
index 8fafca1950c..15e1cbb1986 100644
--- a/src/gallium/drivers/nvfx/nvfx_state.h
+++ b/src/gallium/drivers/nvfx/nvfx_state.h
@@ -2,6 +2,7 @@
#define __NVFX_STATE_H__
#include "pipe/p_state.h"
+#include "pipe/p_video_state.h"
#include "tgsi/tgsi_scan.h"
#include "nouveau/nouveau_statebuf.h"
#include "util/u_dynarray.h"
diff --git a/src/gallium/drivers/nvfx/nvfx_video_context.c b/src/gallium/drivers/nvfx/nvfx_video_context.c
new file mode 100644
index 00000000000..58e1c0baa27
--- /dev/null
+++ b/src/gallium/drivers/nvfx/nvfx_video_context.c
@@ -0,0 +1,48 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 "nvfx_video_context.h"
+#include <softpipe/sp_video_context.h>
+
+struct pipe_video_context *
+nvfx_video_create(struct pipe_screen *screen, enum pipe_video_profile profile,
+ enum pipe_video_chroma_format chroma_format,
+ unsigned width, unsigned height, void *priv)
+{
+ struct pipe_context *pipe;
+
+ assert(screen);
+
+ pipe = screen->context_create(screen, priv);
+ if (!pipe)
+ return NULL;
+
+ return sp_video_create_ex(pipe, profile, chroma_format, width, height,
+ VL_MPEG12_MC_RENDERER_BUFFER_PICTURE,
+ true,
+ PIPE_FORMAT_VUYX);
+}
diff --git a/src/gallium/drivers/nvfx/nvfx_video_context.h b/src/gallium/drivers/nvfx/nvfx_video_context.h
new file mode 100644
index 00000000000..6619427cc29
--- /dev/null
+++ b/src/gallium/drivers/nvfx/nvfx_video_context.h
@@ -0,0 +1,38 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 __NVFX_VIDEO_CONTEXT_H__
+#define __NVFX_VIDEO_CONTEXT_H__
+
+#include <pipe/p_video_context.h>
+
+struct pipe_video_context *
+nvfx_video_create(struct pipe_screen *screen, enum pipe_video_profile profile,
+ enum pipe_video_chroma_format chroma_format,
+ unsigned width, unsigned height, void *priv);
+
+#endif
diff --git a/src/gallium/drivers/r300/r300_video_context.c b/src/gallium/drivers/r300/r300_video_context.c
new file mode 100644
index 00000000000..9fe6d6fcf25
--- /dev/null
+++ b/src/gallium/drivers/r300/r300_video_context.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2009-2010 Advanced Micro Devices, 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 COPYRIGHT HOLDER(S) 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:
+ */
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <pipe/p_defines.h>
+#include <pipe/p_context.h>
+#include <pipe/p_screen.h>
+#include <pipe/p_inlines.h>
+#include <util/u_memory.h>
+#include <X11/Xlib.h>
+
+#include <fcntl.h>
+
+#include "radeon_buffer.h"
+#include "radeon_r300.h"
+#include "r300_screen.h"
+#include "r300_texture.h"
+#include "p_video_context.h"
+#include "radeon_vl.h"
+#include "softpipe/sp_winsys.h"
+#include "softpipe/sp_texture.h"
+
+#include "r300_video_context.h"
+#include <softpipe/sp_video_context.h>
+
+static void r300_mpeg12_destroy(struct pipe_video_context *vpipe)
+{
+ struct radeon_mpeg12_context *ctx = (struct radeon_mpeg12_context*)vpipe;
+
+ assert(vpipe);
+
+ ctx->pipe->bind_vs_state(ctx->pipe, NULL);
+ ctx->pipe->bind_fs_state(ctx->pipe, NULL);
+
+ ctx->pipe->delete_blend_state(ctx->pipe, ctx->blend);
+ ctx->pipe->delete_rasterizer_state(ctx->pipe, ctx->rast);
+ ctx->pipe->delete_depth_stencil_alpha_state(ctx->pipe, ctx->dsa);
+
+ pipe_video_surface_reference(&ctx->decode_target, NULL);
+ vl_compositor_cleanup(&ctx->compositor);
+ vl_mpeg12_mc_renderer_cleanup(&ctx->mc_renderer);
+ ctx->pipe->destroy(ctx->pipe);
+
+ FREE(ctx);
+}
+
+static void
+r300_mpeg12_decode_macroblocks(struct pipe_video_context *vpipe,
+ struct pipe_video_surface *past,
+ struct pipe_video_surface *future,
+ unsigned num_macroblocks,
+ struct pipe_macroblock *macroblocks,
+ struct pipe_fence_handle **fence)
+{
+ struct radeon_mpeg12_context *ctx = (struct radeon_mpeg12_context*)vpipe;
+ struct pipe_mpeg12_macroblock *mpeg12_macroblocks =
+ (struct pipe_mpeg12_macroblock*)macroblocks;
+
+ assert(vpipe);
+ assert(num_macroblocks);
+ assert(macroblocks);
+ assert(macroblocks->codec == PIPE_VIDEO_CODEC_MPEG12);
+ assert(ctx->decode_target);
+
+ vl_mpeg12_mc_renderer_render_macroblocks(
+ &ctx->mc_renderer,
+ r300_video_surface(ctx->decode_target)->tex,
+ past ? r300_video_surface(past)->tex : NULL,
+ future ? r300_video_surface(future)->tex : NULL,
+ num_macroblocks, mpeg12_macroblocks, fence);
+}
+
+static void r300_mpeg12_clear_surface(struct pipe_video_context *vpipe,
+ unsigned x, unsigned y,
+ unsigned width, unsigned height,
+ unsigned value,
+ struct pipe_surface *surface)
+{
+ struct radeon_mpeg12_context *ctx = (struct radeon_mpeg12_context*)vpipe;
+
+ assert(vpipe);
+ assert(surface);
+
+ if (ctx->pipe->surface_fill)
+ ctx->pipe->surface_fill(ctx->pipe, surface, x, y, width, height, value);
+ else
+ util_surface_fill(ctx->pipe, surface, x, y, width, height, value);
+}
+
+static void
+r300_mpeg12_render_picture(struct pipe_video_context *vpipe,
+ struct pipe_video_surface *src_surface,
+ enum pipe_mpeg12_picture_type picture_type,
+ struct pipe_video_rect *src_area,
+ struct pipe_surface *dst_surface,
+ struct pipe_video_rect *dst_area,
+ struct pipe_fence_handle **fence)
+{
+ struct radeon_mpeg12_context *ctx = (struct radeon_mpeg12_context*)vpipe;
+
+ assert(vpipe);
+ assert(src_surface);
+ assert(src_area);
+ assert(dst_surface);
+ assert(dst_area);
+
+ vl_compositor_render(&ctx->compositor,
+ r300_video_surface(src_surface)->tex,
+ picture_type, src_area, dst_surface->texture,
+ dst_area, fence);
+}
+
+static void r300_mpeg12_set_decode_target(struct pipe_video_context *vpipe,
+ struct pipe_video_surface *dt)
+{
+ struct radeon_mpeg12_context *ctx = (struct radeon_mpeg12_context*)vpipe;
+
+ assert(vpipe);
+ assert(dt);
+
+ pipe_video_surface_reference(&ctx->decode_target, dt);
+}
+
+static void r300_mpeg12_set_csc_matrix(struct pipe_video_context *vpipe,
+ const float *mat)
+{
+ struct radeon_mpeg12_context *ctx = (struct radeon_mpeg12_context*)vpipe;
+
+ assert(vpipe);
+
+ vl_compositor_set_csc_matrix(&ctx->compositor, mat);
+}
+
+static bool r300_mpeg12_init_pipe_state(struct radeon_mpeg12_context *ctx)
+{
+ struct pipe_rasterizer_state rast;
+ struct pipe_blend_state blend;
+ struct pipe_depth_stencil_alpha_state dsa;
+ unsigned i;
+
+ assert(ctx);
+
+ rast.flatshade = 1;
+ rast.flatshade_first = 0;
+ rast.light_twoside = 0;
+ rast.front_winding = PIPE_WINDING_CCW;
+ rast.cull_mode = PIPE_WINDING_CW;
+ rast.fill_cw = PIPE_POLYGON_MODE_FILL;
+ rast.fill_ccw = PIPE_POLYGON_MODE_FILL;
+ rast.offset_cw = 0;
+ rast.offset_ccw = 0;
+ rast.scissor = 0;
+ rast.poly_smooth = 0;
+ rast.poly_stipple_enable = 0;
+ rast.point_sprite = 0;
+ rast.point_size_per_vertex = 0;
+ rast.multisample = 0;
+ rast.line_smooth = 0;
+ rast.line_stipple_enable = 0;
+ rast.line_stipple_factor = 0;
+ rast.line_stipple_pattern = 0;
+ rast.line_last_pixel = 0;
+ rast.bypass_vs_clip_and_viewport = 0;
+ rast.line_width = 1;
+ rast.point_smooth = 0;
+ rast.point_size = 1;
+ rast.offset_units = 1;
+ rast.offset_scale = 1;
+ /*rast.sprite_coord_mode[i] = ;*/
+ ctx->rast = ctx->pipe->create_rasterizer_state(ctx->pipe, &rast);
+ ctx->pipe->bind_rasterizer_state(ctx->pipe, ctx->rast);
+
+ blend.blend_enable = 0;
+ blend.rgb_func = PIPE_BLEND_ADD;
+ blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rgb_dst_factor = PIPE_BLENDFACTOR_ONE;
+ blend.alpha_func = PIPE_BLEND_ADD;
+ blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
+ blend.logicop_enable = 0;
+ blend.logicop_func = PIPE_LOGICOP_CLEAR;
+ /* Needed to allow color writes to FB, even if blending disabled */
+ blend.colormask = PIPE_MASK_RGBA;
+ blend.dither = 0;
+ ctx->blend = ctx->pipe->create_blend_state(ctx->pipe, &blend);
+ ctx->pipe->bind_blend_state(ctx->pipe, ctx->blend);
+
+ dsa.depth.enabled = 0;
+ dsa.depth.writemask = 0;
+ dsa.depth.func = PIPE_FUNC_ALWAYS;
+ for (i = 0; i < 2; ++i)
+ {
+ dsa.stencil[i].enabled = 0;
+ dsa.stencil[i].func = PIPE_FUNC_ALWAYS;
+ dsa.stencil[i].fail_op = PIPE_STENCIL_OP_KEEP;
+ dsa.stencil[i].zpass_op = PIPE_STENCIL_OP_KEEP;
+ dsa.stencil[i].zfail_op = PIPE_STENCIL_OP_KEEP;
+ dsa.stencil[i].ref_value = 0;
+ dsa.stencil[i].valuemask = 0;
+ dsa.stencil[i].writemask = 0;
+ }
+ dsa.alpha.enabled = 0;
+ dsa.alpha.func = PIPE_FUNC_ALWAYS;
+ dsa.alpha.ref_value = 0;
+ ctx->dsa = ctx->pipe->create_depth_stencil_alpha_state(ctx->pipe, &dsa);
+ ctx->pipe->bind_depth_stencil_alpha_state(ctx->pipe, ctx->dsa);
+
+ return true;
+}
+
+static struct pipe_video_context *
+r300_mpeg12_context_create(struct pipe_screen *screen,
+ enum pipe_video_profile profile,
+ enum pipe_video_chroma_format chroma_format,
+ unsigned int width,
+ unsigned int height)
+{
+ struct radeon_mpeg12_context *ctx;
+ ctx = CALLOC_STRUCT(radeon_mpeg12_context);
+ if (!ctx)
+ return NULL;
+
+ ctx->base.profile = profile;
+ ctx->base.chroma_format = chroma_format;
+ ctx->base.width = width;
+ ctx->base.height = height;
+ ctx->base.screen = screen;
+
+ ctx->base.destroy = radeon_mpeg12_destroy;
+ ctx->base.decode_macroblocks = radeon_mpeg12_decode_macroblocks;
+ ctx->base.clear_surface = radeon_mpeg12_clear_surface;
+ ctx->base.render_picture = radeon_mpeg12_render_picture;
+ ctx->base.set_decode_target = radeon_mpeg12_set_decode_target;
+ ctx->base.set_csc_matrix = radeon_mpeg12_set_csc_matrix;
+
+ ctx->pipe = r300_create_context(screen,(struct r300_winsys*)screen->winsys);
+ if (!ctx->pipe)
+ {
+ FREE(ctx);
+ return NULL;
+ }
+
+ if (!vl_mpeg12_mc_renderer_init(&ctx->mc_renderer, ctx->pipe,
+ width, height, chroma_format,
+ VL_MPEG12_MC_RENDERER_BUFFER_PICTURE,
+ true))
+ {
+ ctx->pipe->destroy(ctx->pipe);
+ FREE(ctx);
+ return NULL;
+ }
+
+ if (!vl_compositor_init(&ctx->compositor, ctx->pipe))
+ {
+ vl_mpeg12_mc_renderer_cleanup(&ctx->mc_renderer);
+ ctx->pipe->destroy(ctx->pipe);
+ FREE(ctx);
+ return NULL;
+ }
+
+ if (!radeon_mpeg12_init_pipe_state(ctx))
+ {
+ vl_compositor_cleanup(&ctx->compositor);
+ vl_mpeg12_mc_renderer_cleanup(&ctx->mc_renderer);
+ ctx->pipe->destroy(ctx->pipe);
+ FREE(ctx);
+ return NULL;
+ }
+
+ return &ctx->base;
+}
+
+struct pipe_video_context *
+r300_video_create(struct pipe_context *pipe, enum pipe_video_profile profile,
+ enum pipe_video_chroma_format chroma_format,
+ unsigned width, unsigned height,
+ unsigned pvctx_id)
+{
+ struct pipe_video_context *vpipe;
+ struct radeon_vl_context *rvl_ctx;
+
+ assert(p_screen);
+ assert(width && height);
+
+ /* create radeon pipe_context */
+ switch(u_reduce_video_profile(profile))
+ {
+ case PIPE_VIDEO_CODEC_MPEG12:
+ vpipe = radeon_mpeg12_context_create(p_screen, profile, chr_f,
+ width, height);
+ break;
+ default:
+ return NULL;
+ }
+
+ /* create radeon_vl_context */
+ rvl_ctx = calloc(1, sizeof(struct radeon_vl_context));
+ rvl_ctx->display = display;
+ rvl_ctx->screen = screen;
+
+ vpipe->priv = rvl_ctx;
+
+ return vpipe;
+}
diff --git a/src/gallium/drivers/r300/r300_video_context.h b/src/gallium/drivers/r300/r300_video_context.h
new file mode 100644
index 00000000000..a8210ba7b71
--- /dev/null
+++ b/src/gallium/drivers/r300/r300_video_context.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2009-2010 Advanced Micro Devices, 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 COPYRIGHT HOLDER(S) 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:
+ */
+
+#ifndef __R300_VIDEO_CONTEXT_H__
+#define __R300_VIDEO_CONTEXT_H__
+
+#include <pipe/p_video_context.h>
+
+struct pipe_context;
+
+struct pipe_video_context*
+r300_video_create(struct pipe_context *pipe, enum pipe_video_profile profile,
+ enum pipe_video_chroma_format chroma_format,
+ unsigned width, unsigned height,
+ unsigned pvctx_id);
+
+#endif
diff --git a/src/gallium/drivers/r600/Makefile b/src/gallium/drivers/r600/Makefile
index b476b9af3b8..a690b671e49 100644
--- a/src/gallium/drivers/r600/Makefile
+++ b/src/gallium/drivers/r600/Makefile
@@ -17,6 +17,7 @@ C_SOURCES = \
r600_shader.c \
r600_state.c \
r600_texture.c \
+ r600_video_context.c \
r700_asm.c \
evergreen_state.c \
eg_asm.c \
diff --git a/src/gallium/drivers/r600/eg_asm.c b/src/gallium/drivers/r600/eg_asm.c
index c44506c7eba..1881e633d54 100644
--- a/src/gallium/drivers/r600/eg_asm.c
+++ b/src/gallium/drivers/r600/eg_asm.c
@@ -32,10 +32,12 @@
int eg_bc_cf_build(struct r600_bc *bc, struct r600_bc_cf *cf)
{
unsigned id = cf->id;
+ unsigned end_of_program = bc->cf.prev == &cf->list;
switch (cf->inst) {
case (EG_V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3):
case (EG_V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE << 3):
+ assert(!end_of_program);
bc->bytecode[id++] = S_SQ_CF_ALU_WORD0_ADDR(cf->addr >> 1) |
S_SQ_CF_ALU_WORD0_KCACHE_MODE0(cf->kcache[0].mode) |
S_SQ_CF_ALU_WORD0_KCACHE_BANK0(cf->kcache[0].bank) |
@@ -44,15 +46,16 @@ int eg_bc_cf_build(struct r600_bc *bc, struct r600_bc_cf *cf)
S_SQ_CF_ALU_WORD1_KCACHE_MODE1(cf->kcache[1].mode) |
S_SQ_CF_ALU_WORD1_KCACHE_ADDR0(cf->kcache[0].addr) |
S_SQ_CF_ALU_WORD1_KCACHE_ADDR1(cf->kcache[1].addr) |
- S_SQ_CF_ALU_WORD1_BARRIER(1) |
- S_SQ_CF_ALU_WORD1_COUNT((cf->ndw / 2) - 1);
+ S_SQ_CF_ALU_WORD1_BARRIER(cf->barrier) |
+ S_SQ_CF_ALU_WORD1_COUNT((cf->ndw / 2) - 1);
break;
case EG_V_SQ_CF_WORD1_SQ_CF_INST_TEX:
case EG_V_SQ_CF_WORD1_SQ_CF_INST_VTX:
bc->bytecode[id++] = S_SQ_CF_WORD0_ADDR(cf->addr >> 1);
bc->bytecode[id++] = S_SQ_CF_WORD1_CF_INST(cf->inst) |
- S_SQ_CF_WORD1_BARRIER(1) |
- S_SQ_CF_WORD1_COUNT((cf->ndw / 4) - 1);
+ S_SQ_CF_WORD1_BARRIER(cf->barrier) |
+ S_SQ_CF_WORD1_COUNT((cf->ndw / 4) - 1) |
+ S_SQ_CF_WORD1_END_OF_PROGRAM(end_of_program);
break;
case EG_V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT:
case EG_V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT_DONE:
@@ -60,13 +63,14 @@ int eg_bc_cf_build(struct r600_bc *bc, struct r600_bc_cf *cf)
S_SQ_CF_ALLOC_EXPORT_WORD0_ELEM_SIZE(cf->output.elem_size) |
S_SQ_CF_ALLOC_EXPORT_WORD0_ARRAY_BASE(cf->output.array_base) |
S_SQ_CF_ALLOC_EXPORT_WORD0_TYPE(cf->output.type);
- bc->bytecode[id++] = S_SQ_CF_ALLOC_EXPORT_WORD1_SWIZ_SEL_X(cf->output.swizzle_x) |
+ bc->bytecode[id++] = S_SQ_CF_ALLOC_EXPORT_WORD1_BURST_COUNT(cf->output.burst_count - 1) |
+ S_SQ_CF_ALLOC_EXPORT_WORD1_SWIZ_SEL_X(cf->output.swizzle_x) |
S_SQ_CF_ALLOC_EXPORT_WORD1_SWIZ_SEL_Y(cf->output.swizzle_y) |
S_SQ_CF_ALLOC_EXPORT_WORD1_SWIZ_SEL_Z(cf->output.swizzle_z) |
S_SQ_CF_ALLOC_EXPORT_WORD1_SWIZ_SEL_W(cf->output.swizzle_w) |
- S_SQ_CF_ALLOC_EXPORT_WORD1_BARRIER(cf->output.barrier) |
- S_SQ_CF_ALLOC_EXPORT_WORD1_CF_INST(cf->output.inst) |
- S_SQ_CF_ALLOC_EXPORT_WORD1_END_OF_PROGRAM(cf->output.end_of_program);
+ S_SQ_CF_ALLOC_EXPORT_WORD1_BARRIER(cf->barrier) |
+ S_SQ_CF_ALLOC_EXPORT_WORD1_CF_INST(cf->inst) |
+ S_SQ_CF_ALLOC_EXPORT_WORD1_END_OF_PROGRAM(end_of_program);
break;
case EG_V_SQ_CF_WORD1_SQ_CF_INST_JUMP:
case EG_V_SQ_CF_WORD1_SQ_CF_INST_ELSE:
@@ -79,9 +83,10 @@ int eg_bc_cf_build(struct r600_bc *bc, struct r600_bc_cf *cf)
case EG_V_SQ_CF_WORD1_SQ_CF_INST_RETURN:
bc->bytecode[id++] = S_SQ_CF_WORD0_ADDR(cf->cf_addr >> 1);
bc->bytecode[id++] = S_SQ_CF_WORD1_CF_INST(cf->inst) |
- S_SQ_CF_WORD1_BARRIER(1) |
- S_SQ_CF_WORD1_COND(cf->cond) |
- S_SQ_CF_WORD1_POP_COUNT(cf->pop_count);
+ S_SQ_CF_WORD1_BARRIER(cf->barrier) |
+ S_SQ_CF_WORD1_COND(cf->cond) |
+ S_SQ_CF_WORD1_POP_COUNT(cf->pop_count) |
+ S_SQ_CF_WORD1_END_OF_PROGRAM(end_of_program);
break;
default:
diff --git a/src/gallium/drivers/r600/r600_asm.c b/src/gallium/drivers/r600/r600_asm.c
index 326724520b3..b15758adc33 100644
--- a/src/gallium/drivers/r600/r600_asm.c
+++ b/src/gallium/drivers/r600/r600_asm.c
@@ -32,6 +32,12 @@
#include "r600_formats.h"
#include "r600d.h"
+#define NUM_OF_CYCLES 3
+#define NUM_OF_COMPONENTS 4
+
+#define PREV_ALU(alu) LIST_ENTRY(struct r600_bc_alu, alu->list.prev, list)
+#define NEXT_ALU(alu) LIST_ENTRY(struct r600_bc_alu, alu->list.next, list)
+
static inline unsigned int r600_bc_get_num_operands(struct r600_bc_alu *alu)
{
if(alu->is_op3)
@@ -45,10 +51,10 @@ static inline unsigned int r600_bc_get_num_operands(struct r600_bc_alu *alu)
case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGT:
case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGE:
case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLNE:
- case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MUL:
+ case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MUL:
case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MAX:
case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MIN:
- case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SETE:
+ case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SETE:
case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SETNE:
case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SETGT:
case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SETGE:
@@ -61,7 +67,7 @@ static inline unsigned int r600_bc_get_num_operands(struct r600_bc_alu *alu)
case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_CUBE:
return 2;
- case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV:
+ case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV:
case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOVA_FLOOR:
case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_FRACT:
case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_FLOOR:
@@ -76,7 +82,7 @@ static inline unsigned int r600_bc_get_num_operands(struct r600_bc_alu *alu)
case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_COS:
return 1;
default: R600_ERR(
- "Need instruction operand number for 0x%x.\n", alu->inst);
+ "Need instruction operand number for 0x%x.\n", alu->inst);
};
return 3;
@@ -94,6 +100,7 @@ static struct r600_bc_cf *r600_bc_cf(void)
LIST_INITHEAD(&cf->alu);
LIST_INITHEAD(&cf->vtx);
LIST_INITHEAD(&cf->tex);
+ cf->barrier = 1;
return cf;
}
@@ -104,7 +111,6 @@ static struct r600_bc_alu *r600_bc_alu(void)
if (alu == NULL)
return NULL;
LIST_INITHEAD(&alu->list);
- LIST_INITHEAD(&alu->bs_list);
return alu;
}
@@ -183,6 +189,44 @@ static int r600_bc_add_cf(struct r600_bc *bc)
return 0;
}
+static void r600_bc_remove_cf(struct r600_bc *bc, struct r600_bc_cf *cf)
+{
+ struct r600_bc_cf *other;
+ LIST_FOR_EACH_ENTRY(other, &bc->cf, list) {
+ if (other->id > cf->id)
+ other->id -= 2;
+ if (other->cf_addr > cf->id)
+ other->cf_addr -= 2;
+ }
+ LIST_DEL(&cf->list);
+ free(cf);
+}
+
+static void r600_bc_move_cf(struct r600_bc *bc, struct r600_bc_cf *cf, struct r600_bc_cf *next)
+{
+ struct r600_bc_cf *prev = LIST_ENTRY(struct r600_bc_cf, next->list.prev, list);
+ unsigned old_id = cf->id;
+ unsigned new_id = prev->id + 2;
+ struct r600_bc_cf *other;
+
+ if (prev == cf)
+ return; /* position hasn't changed */
+
+ LIST_DEL(&cf->list);
+ LIST_FOR_EACH_ENTRY(other, &bc->cf, list) {
+ if (other->id > old_id)
+ other->id -= 2;
+ if (other->id >= new_id)
+ other->id += 2;
+ if (other->cf_addr > old_id)
+ other->cf_addr -= 2;
+ if (other->cf_addr > new_id)
+ other->cf_addr += 2;
+ }
+ cf->id = new_id;
+ LIST_ADD(&cf->list, &prev->list);
+}
+
int r600_bc_add_output(struct r600_bc *bc, const struct r600_bc_output *output)
{
int r;
@@ -190,227 +234,620 @@ int r600_bc_add_output(struct r600_bc *bc, const struct r600_bc_output *output)
r = r600_bc_add_cf(bc);
if (r)
return r;
- bc->cf_last->inst = output->inst;
+ bc->cf_last->inst = BC_INST(bc, V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT);
memcpy(&bc->cf_last->output, output, sizeof(struct r600_bc_output));
+ bc->cf_last->output.burst_count = 1;
return 0;
}
-const unsigned bank_swizzle_vec[8] = {SQ_ALU_VEC_210, //000
- SQ_ALU_VEC_120, //001
- SQ_ALU_VEC_102, //010
+/* alu predicate instructions */
+static int is_alu_pred_inst(struct r600_bc_alu *alu)
+{
+ return !alu->is_op3 && (
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGT_UINT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGE_UINT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETE ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGE ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETNE ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SET_INV ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SET_POP ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SET_CLR ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SET_RESTORE ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETE_PUSH ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGT_PUSH ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGE_PUSH ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETNE_PUSH ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETE_INT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGT_INT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGE_INT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETNE_INT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETE_PUSH_INT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGT_PUSH_INT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGE_PUSH_INT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETNE_PUSH_INT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETLT_PUSH_INT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETLE_PUSH_INT);
+}
- SQ_ALU_VEC_201, //011
- SQ_ALU_VEC_012, //100
- SQ_ALU_VEC_021, //101
+/* alu kill instructions */
+static int is_alu_kill_inst(struct r600_bc_alu *alu)
+{
+ return !alu->is_op3 && (
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLE ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGE ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLNE ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGT_UINT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGE_UINT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLE_INT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGT_INT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGE_INT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLNE_INT);
+}
- SQ_ALU_VEC_012, //110
- SQ_ALU_VEC_012}; //111
+/* alu instructions that can ony exits once per group */
+static int is_alu_once_inst(struct r600_bc_alu *alu)
+{
+ return is_alu_kill_inst(alu) ||
+ is_alu_pred_inst(alu);
+}
-const unsigned bank_swizzle_scl[8] = {SQ_ALU_SCL_210, //000
- SQ_ALU_SCL_122, //001
- SQ_ALU_SCL_122, //010
+static int is_alu_reduction_inst(struct r600_bc_alu *alu)
+{
+ return !alu->is_op3 && (
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_CUBE ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_DOT4 ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_DOT4_IEEE ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MAX4);
+}
+
+static int is_alu_mova_inst(struct r600_bc_alu *alu)
+{
+ return !alu->is_op3 && (
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOVA ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOVA_FLOOR ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOVA_INT);
+}
+
+/* alu instructions that can only execute on the vector unit */
+static int is_alu_vec_unit_inst(struct r600_bc_alu *alu)
+{
+ return is_alu_reduction_inst(alu) ||
+ is_alu_mova_inst(alu);
+}
+
+/* alu instructions that can only execute on the trans unit */
+static int is_alu_trans_unit_inst(struct r600_bc_alu *alu)
+{
+ if(!alu->is_op3)
+ return alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_ASHR_INT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_FLT_TO_INT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_INT_TO_FLT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_LSHL_INT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_LSHR_INT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MULHI_INT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MULHI_UINT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MULLO_INT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MULLO_UINT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIP_INT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIP_UINT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_UINT_TO_FLT ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_COS ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_EXP_IEEE ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_LOG_CLAMPED ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_LOG_IEEE ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIP_CLAMPED ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIP_FF ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIP_IEEE ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIPSQRT_CLAMPED ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIPSQRT_FF ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIPSQRT_IEEE ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SIN ||
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SQRT_IEEE;
+ else
+ return alu->inst == V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_MUL_LIT ||
+ alu->inst == V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_MUL_LIT_D2 ||
+ alu->inst == V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_MUL_LIT_M2 ||
+ alu->inst == V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_MUL_LIT_M4;
+}
+
+/* alu instructions that can execute on any unit */
+static int is_alu_any_unit_inst(struct r600_bc_alu *alu)
+{
+ return !is_alu_vec_unit_inst(alu) &&
+ !is_alu_trans_unit_inst(alu);
+}
+
+static int assign_alu_units(struct r600_bc_alu *alu_first, struct r600_bc_alu *assignment[5])
+{
+ struct r600_bc_alu *alu;
+ unsigned i, chan, trans;
+
+ for (i = 0; i < 5; i++)
+ assignment[i] = NULL;
+
+ for (alu = alu_first; alu; alu = NEXT_ALU(alu)) {
+ chan = alu->dst.chan;
+ if (is_alu_trans_unit_inst(alu))
+ trans = 1;
+ else if (is_alu_vec_unit_inst(alu))
+ trans = 0;
+ else if (assignment[chan])
+ trans = 1; // assume ALU_INST_PREFER_VECTOR
+ else
+ trans = 0;
- SQ_ALU_SCL_221, //011
- SQ_ALU_SCL_212, //100
- SQ_ALU_SCL_122, //101
+ if (trans) {
+ if (assignment[4]) {
+ assert(0); //ALU.Trans has already been allocated
+ return -1;
+ }
+ assignment[4] = alu;
+ } else {
+ if (assignment[chan]) {
+ assert(0); //ALU.chan has already been allocated
+ return -1;
+ }
+ assignment[chan] = alu;
+ }
- SQ_ALU_SCL_122, //110
- SQ_ALU_SCL_122}; //111
+ if (alu->last)
+ break;
+ }
+ return 0;
+}
-static int init_gpr(struct r600_bc_alu *alu)
+struct alu_bank_swizzle {
+ int hw_gpr[NUM_OF_CYCLES][NUM_OF_COMPONENTS];
+ int hw_cfile_addr[4];
+ int hw_cfile_elem[4];
+};
+
+const unsigned cycle_for_bank_swizzle_vec[][3] = {
+ [SQ_ALU_VEC_012] = { 0, 1, 2 },
+ [SQ_ALU_VEC_021] = { 0, 2, 1 },
+ [SQ_ALU_VEC_120] = { 1, 2, 0 },
+ [SQ_ALU_VEC_102] = { 1, 0, 2 },
+ [SQ_ALU_VEC_201] = { 2, 0, 1 },
+ [SQ_ALU_VEC_210] = { 2, 1, 0 }
+};
+
+const unsigned cycle_for_bank_swizzle_scl[][3] = {
+ [SQ_ALU_SCL_210] = { 2, 1, 0 },
+ [SQ_ALU_SCL_122] = { 1, 2, 2 },
+ [SQ_ALU_SCL_212] = { 2, 1, 2 },
+ [SQ_ALU_SCL_221] = { 2, 2, 1 }
+};
+
+static void init_bank_swizzle(struct alu_bank_swizzle *bs)
{
- int cycle, component;
+ int i, cycle, component;
/* set up gpr use */
for (cycle = 0; cycle < NUM_OF_CYCLES; cycle++)
for (component = 0; component < NUM_OF_COMPONENTS; component++)
- alu->hw_gpr[cycle][component] = -1;
- return 0;
+ bs->hw_gpr[cycle][component] = -1;
+ for (i = 0; i < 4; i++)
+ bs->hw_cfile_addr[i] = -1;
+ for (i = 0; i < 4; i++)
+ bs->hw_cfile_elem[i] = -1;
}
-#if 0
-static int reserve_gpr(struct r600_bc_alu *alu, unsigned sel, unsigned chan, unsigned cycle)
+static int reserve_gpr(struct alu_bank_swizzle *bs, unsigned sel, unsigned chan, unsigned cycle)
{
- if (alu->hw_gpr[cycle][chan] < 0)
- alu->hw_gpr[cycle][chan] = sel;
- else if (alu->hw_gpr[cycle][chan] != (int)sel) {
- R600_ERR("Another scalar operation has already used GPR read port for channel\n");
+ if (bs->hw_gpr[cycle][chan] == -1)
+ bs->hw_gpr[cycle][chan] = sel;
+ else if (bs->hw_gpr[cycle][chan] != (int)sel) {
+ // Another scalar operation has already used GPR read port for channel
return -1;
}
return 0;
}
-static int cycle_for_scalar_bank_swizzle(const int swiz, const int sel, unsigned *p_cycle)
-{
- int table[3];
- int ret = 0;
- switch (swiz) {
- case SQ_ALU_SCL_210:
- table[0] = 2; table[1] = 1; table[2] = 0;
- *p_cycle = table[sel];
- break;
- case SQ_ALU_SCL_122:
- table[0] = 1; table[1] = 2; table[2] = 2;
- *p_cycle = table[sel];
- break;
- case SQ_ALU_SCL_212:
- table[0] = 2; table[1] = 1; table[2] = 2;
- *p_cycle = table[sel];
- break;
- case SQ_ALU_SCL_221:
- table[0] = 2; table[1] = 2; table[2] = 1;
- *p_cycle = table[sel];
- break;
- break;
- default:
- R600_ERR("bad scalar bank swizzle value\n");
- ret = -1;
- break;
+static int reserve_cfile(struct alu_bank_swizzle *bs, unsigned sel, unsigned chan)
+{
+ int res, resmatch = -1, resempty = -1;
+ for (res = 3; res >= 0; --res) {
+ if (bs->hw_cfile_addr[res] == -1)
+ resempty = res;
+ else if (bs->hw_cfile_addr[res] == sel &&
+ bs->hw_cfile_elem[res] == chan)
+ resmatch = res;
}
- return ret;
-}
-
-static int cycle_for_vector_bank_swizzle(const int swiz, const int sel, unsigned *p_cycle)
-{
- int table[3];
- int ret;
-
- switch (swiz) {
- case SQ_ALU_VEC_012:
- table[0] = 0; table[1] = 1; table[2] = 2;
- *p_cycle = table[sel];
- break;
- case SQ_ALU_VEC_021:
- table[0] = 0; table[1] = 2; table[2] = 1;
- *p_cycle = table[sel];
- break;
- case SQ_ALU_VEC_120:
- table[0] = 1; table[1] = 2; table[2] = 0;
- *p_cycle = table[sel];
- break;
- case SQ_ALU_VEC_102:
- table[0] = 1; table[1] = 0; table[2] = 2;
- *p_cycle = table[sel];
- break;
- case SQ_ALU_VEC_201:
- table[0] = 2; table[1] = 0; table[2] = 1;
- *p_cycle = table[sel];
- break;
- case SQ_ALU_VEC_210:
- table[0] = 2; table[1] = 1; table[2] = 0;
- *p_cycle = table[sel];
- break;
- default:
- R600_ERR("bad vector bank swizzle value\n");
- ret = -1;
- break;
+ if (resmatch != -1)
+ return 0; // Read for this scalar element already reserved, nothing to do here.
+ else if (resempty != -1) {
+ bs->hw_cfile_addr[resempty] = sel;
+ bs->hw_cfile_elem[resempty] = chan;
+ } else {
+ // All cfile read ports are used, cannot reference vector element
+ return -1;
}
- return ret;
+ return 0;
}
+static int is_gpr(unsigned sel)
+{
+ return (sel >= 0 && sel <= 127);
+}
+static int is_cfile(unsigned sel)
+{
+ return (sel > 255 && sel < 512);
+}
-static void update_chan_counter(struct r600_bc_alu *alu, int *chan_counter)
+/* CB constants start at 512, and get translated to a kcache index when ALU
+ * clauses are constructed. Note that we handle kcache constants the same way
+ * as (the now gone) cfile constants, is that really required? */
+static int is_cb_const(int sel)
{
- int num_src;
- int i;
- int channel_swizzle;
+ if (sel > 511 && sel < 4607)
+ return 1;
+ return 0;
+}
- num_src = r600_bc_get_num_operands(alu);
+static int is_const(int sel)
+{
+ return is_cfile(sel) ||
+ is_cb_const(sel) ||
+ (sel >= V_SQ_ALU_SRC_0 &&
+ sel <= V_SQ_ALU_SRC_LITERAL);
+}
+
+static int check_vector(struct r600_bc_alu *alu, struct alu_bank_swizzle *bs, int bank_swizzle)
+{
+ int r, src, num_src, sel, elem, cycle;
- for (i = 0; i < num_src; i++) {
- channel_swizzle = alu->src[i].chan;
- if ((alu->src[i].sel > 0 && alu->src[i].sel < 128) && channel_swizzle <= 3)
- chan_counter[channel_swizzle]++;
+ num_src = r600_bc_get_num_operands(alu);
+ for (src = 0; src < num_src; src++) {
+ sel = alu->src[src].sel;
+ elem = alu->src[src].chan;
+ if (is_gpr(sel)) {
+ cycle = cycle_for_bank_swizzle_vec[bank_swizzle][src];
+ if (src == 1 && sel == alu->src[0].sel && elem == alu->src[0].chan)
+ // Nothing to do; special-case optimization,
+ // second source uses first source’s reservation
+ continue;
+ else {
+ r = reserve_gpr(bs, sel, elem, cycle);
+ if (r)
+ return r;
+ }
+ } else if (is_cfile(sel)) {
+ r = reserve_cfile(bs, sel, elem);
+ if (r)
+ return r;
+ }
+ // No restrictions on PV, PS, literal or special constants
}
+ return 0;
}
-/* we need something like this I think - but this is bogus */
-int check_read_slots(struct r600_bc *bc, struct r600_bc_alu *alu_first)
+static int check_scalar(struct r600_bc_alu *alu, struct alu_bank_swizzle *bs, int bank_swizzle)
{
- struct r600_bc_alu *alu;
- int chan_counter[4] = { 0 };
-
- update_chan_counter(alu_first, chan_counter);
+ int r, src, num_src, const_count, sel, elem, cycle;
- LIST_FOR_EACH_ENTRY(alu, &alu_first->bs_list, bs_list) {
- update_chan_counter(alu, chan_counter);
+ num_src = r600_bc_get_num_operands(alu);
+ for (const_count = 0, src = 0; src < num_src; ++src) {
+ sel = alu->src[src].sel;
+ elem = alu->src[src].chan;
+ if (is_const(sel)) { // Any constant, including literal and inline constants
+ if (const_count >= 2)
+ // More than two references to a constant in
+ // transcendental operation.
+ return -1;
+ else
+ const_count++;
+ }
+ if (is_cfile(sel)) {
+ r = reserve_cfile(bs, sel, elem);
+ if (r)
+ return r;
+ }
}
-
- if (chan_counter[0] > 3 ||
- chan_counter[1] > 3 ||
- chan_counter[2] > 3 ||
- chan_counter[3] > 3) {
- R600_ERR("needed to split instruction for input ran out of banks %x %d %d %d %d\n",
- alu_first->inst, chan_counter[0], chan_counter[1], chan_counter[2], chan_counter[3]);
- return -1;
+ for (src = 0; src < num_src; ++src) {
+ sel = alu->src[src].sel;
+ elem = alu->src[src].chan;
+ if (is_gpr(sel)) {
+ cycle = cycle_for_bank_swizzle_scl[bank_swizzle][src];
+ if (cycle < const_count)
+ // Cycle for GPR load conflicts with
+ // constant load in transcendental operation.
+ return -1;
+ r = reserve_gpr(bs, sel, elem, cycle);
+ if (r)
+ return r;
+ }
+ // Constants already processed
+ // No restrictions on PV, PS
}
return 0;
}
-#endif
-/* CB constants start at 512, and get translated to a kcache index when ALU
- * clauses are constructed. Note that we handle kcache constants the same way
- * as (the now gone) cfile constants, is that really required? */
-static int is_const(int sel)
+static int check_and_set_bank_swizzle(struct r600_bc_alu *slots[5])
{
- if (sel > 511 && sel < 4607)
- return 1;
- return 0;
+ struct alu_bank_swizzle bs;
+ int bank_swizzle[5];
+ int i, r = 0, forced = 0;
+
+ for (i = 0; i < 5; i++)
+ if (slots[i] && slots[i]->bank_swizzle_force) {
+ slots[i]->bank_swizzle = slots[i]->bank_swizzle_force;
+ forced = 1;
+ }
+
+ if (forced)
+ return 0;
+
+ // just check every possible combination of bank swizzle
+ // not very efficent, but works on the first try in most of the cases
+ for (i = 0; i < 4; i++)
+ bank_swizzle[i] = SQ_ALU_VEC_012;
+ bank_swizzle[4] = SQ_ALU_SCL_210;
+ while(bank_swizzle[4] <= SQ_ALU_SCL_221) {
+ init_bank_swizzle(&bs);
+ for (i = 0; i < 4; i++) {
+ if (slots[i]) {
+ r = check_vector(slots[i], &bs, bank_swizzle[i]);
+ if (r)
+ break;
+ }
+ }
+ if (!r && slots[4]) {
+ r = check_scalar(slots[4], &bs, bank_swizzle[4]);
+ }
+ if (!r) {
+ for (i = 0; i < 5; i++) {
+ if (slots[i])
+ slots[i]->bank_swizzle = bank_swizzle[i];
+ }
+ return 0;
+ }
+
+ for (i = 0; i < 5; i++) {
+ bank_swizzle[i]++;
+ if (bank_swizzle[i] <= SQ_ALU_VEC_210)
+ break;
+ else
+ bank_swizzle[i] = SQ_ALU_VEC_012;
+ }
+ }
+
+ // couldn't find a working swizzle
+ return -1;
}
-static int check_scalar(struct r600_bc *bc, struct r600_bc_alu *alu)
+static int replace_gpr_with_pv_ps(struct r600_bc_alu *slots[5], struct r600_bc_alu *alu_prev)
{
- unsigned swizzle_key;
+ struct r600_bc_alu *prev[5];
+ int gpr[5], chan[5];
+ int i, j, r, src, num_src;
- if (alu->bank_swizzle_force) {
- alu->bank_swizzle = alu->bank_swizzle_force;
- return 0;
+ r = assign_alu_units(alu_prev, prev);
+ if (r)
+ return r;
+
+ for (i = 0; i < 5; ++i) {
+ if(prev[i] && prev[i]->dst.write && !prev[i]->dst.rel) {
+ gpr[i] = prev[i]->dst.sel;
+ if (is_alu_reduction_inst(prev[i]))
+ chan[i] = 0;
+ else
+ chan[i] = prev[i]->dst.chan;
+ } else
+ gpr[i] = -1;
+ }
+
+ for (i = 0; i < 5; ++i) {
+ struct r600_bc_alu *alu = slots[i];
+ if(!alu)
+ continue;
+
+ num_src = r600_bc_get_num_operands(alu);
+ for (src = 0; src < num_src; ++src) {
+ if (!is_gpr(alu->src[src].sel) || alu->src[src].rel)
+ continue;
+
+ if (alu->src[src].sel == gpr[4] &&
+ alu->src[src].chan == chan[4]) {
+ alu->src[src].sel = V_SQ_ALU_SRC_PS;
+ alu->src[src].chan = 0;
+ continue;
+ }
+
+ for (j = 0; j < 4; ++j) {
+ if (alu->src[src].sel == gpr[j] &&
+ alu->src[src].chan == j) {
+ alu->src[src].sel = V_SQ_ALU_SRC_PV;
+ alu->src[src].chan = chan[j];
+ break;
+ }
+ }
+ }
}
- swizzle_key = (is_const(alu->src[0].sel) ? 4 : 0 ) +
- (is_const(alu->src[1].sel) ? 2 : 0 ) +
- (is_const(alu->src[2].sel) ? 1 : 0 );
- alu->bank_swizzle = bank_swizzle_scl[swizzle_key];
return 0;
}
-static int check_vector(struct r600_bc *bc, struct r600_bc_alu *alu)
+void r600_bc_special_constants(u32 value, unsigned *sel, unsigned *neg)
{
- unsigned swizzle_key;
-
- if (alu->bank_swizzle_force) {
- alu->bank_swizzle = alu->bank_swizzle_force;
- return 0;
+ switch(value) {
+ case 0:
+ *sel = V_SQ_ALU_SRC_0;
+ break;
+ case 1:
+ *sel = V_SQ_ALU_SRC_1_INT;
+ break;
+ case -1:
+ *sel = V_SQ_ALU_SRC_M_1_INT;
+ break;
+ case 0x3F800000: // 1.0f
+ *sel = V_SQ_ALU_SRC_1;
+ break;
+ case 0x3F000000: // 0.5f
+ *sel = V_SQ_ALU_SRC_0_5;
+ break;
+ case 0xBF800000: // -1.0f
+ *sel = V_SQ_ALU_SRC_1;
+ *neg ^= 1;
+ break;
+ case 0xBF000000: // -0.5f
+ *sel = V_SQ_ALU_SRC_0_5;
+ *neg ^= 1;
+ break;
+ default:
+ *sel = V_SQ_ALU_SRC_LITERAL;
+ break;
}
- swizzle_key = (is_const(alu->src[0].sel) ? 4 : 0 ) +
- (is_const(alu->src[1].sel) ? 2 : 0 ) +
- (is_const(alu->src[2].sel) ? 1 : 0 );
+}
- alu->bank_swizzle = bank_swizzle_vec[swizzle_key];
+/* compute how many literal are needed */
+static int r600_bc_alu_nliterals(struct r600_bc_alu *alu, uint32_t literal[4], unsigned *nliteral)
+{
+ unsigned num_src = r600_bc_get_num_operands(alu);
+ unsigned i, j;
+
+ for (i = 0; i < num_src; ++i) {
+ if (alu->src[i].sel == V_SQ_ALU_SRC_LITERAL) {
+ uint32_t value = alu->src[i].value[alu->src[i].chan];
+ unsigned found = 0;
+ for (j = 0; j < *nliteral; ++j) {
+ if (literal[j] == value) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ if (*nliteral >= 4)
+ return -EINVAL;
+ literal[(*nliteral)++] = value;
+ }
+ }
+ }
return 0;
}
-static int check_and_set_bank_swizzle(struct r600_bc *bc, struct r600_bc_alu *alu_first)
+static void r600_bc_alu_adjust_literals(struct r600_bc_alu *alu, uint32_t literal[4], unsigned nliteral)
{
- struct r600_bc_alu *alu = NULL;
- int num_instr = 1;
+ unsigned num_src = r600_bc_get_num_operands(alu);
+ unsigned i, j;
+
+ for (i = 0; i < num_src; ++i) {
+ if (alu->src[i].sel == V_SQ_ALU_SRC_LITERAL) {
+ uint32_t value = alu->src[i].value[alu->src[i].chan];
+ for (j = 0; j < nliteral; ++j) {
+ if (literal[j] == value) {
+ alu->src[i].chan = j;
+ break;
+ }
+ }
+ }
+ }
+}
- init_gpr(alu_first);
+static int merge_inst_groups(struct r600_bc *bc, struct r600_bc_alu *slots[5], struct r600_bc_alu *alu_prev)
+{
+ struct r600_bc_alu *prev[5];
+ struct r600_bc_alu *result[5] = { NULL };
+
+ uint32_t literal[4];
+ unsigned nliteral = 0;
+
+ int i, j, r, src, num_src;
+ int num_once_inst = 0;
+
+ r = assign_alu_units(alu_prev, prev);
+ if (r)
+ return r;
- LIST_FOR_EACH_ENTRY(alu, &alu_first->bs_list, bs_list) {
- num_instr++;
+ for (i = 0; i < 5; ++i) {
+ /* check number of literals */
+ if (prev[i] && r600_bc_alu_nliterals(prev[i], literal, &nliteral))
+ return 0;
+ if (slots[i] && r600_bc_alu_nliterals(slots[i], literal, &nliteral))
+ return 0;
+
+ // let's check used slots
+ if (prev[i] && !slots[i]) {
+ result[i] = prev[i];
+ num_once_inst += is_alu_once_inst(prev[i]);
+ continue;
+ } else if (prev[i] && slots[i]) {
+ if (result[4] == NULL && prev[4] == NULL && slots[4] == NULL) {
+ // trans unit is still free try to use it
+ if (is_alu_any_unit_inst(slots[i])) {
+ result[i] = prev[i];
+ result[4] = slots[i];
+ } else if (is_alu_any_unit_inst(prev[i])) {
+ result[i] = slots[i];
+ result[4] = prev[i];
+ } else
+ return 0;
+ } else
+ return 0;
+ } else if(!slots[i]) {
+ continue;
+ } else
+ result[i] = slots[i];
+
+ // let's check source gprs
+ struct r600_bc_alu *alu = slots[i];
+ num_once_inst += is_alu_once_inst(alu);
+
+ num_src = r600_bc_get_num_operands(alu);
+ for (src = 0; src < num_src; ++src) {
+ // constants doesn't matter
+ if (!is_gpr(alu->src[src].sel))
+ continue;
+
+ for (j = 0; j < 5; ++j) {
+ if (!prev[j] || !prev[j]->dst.write)
+ continue;
+
+ // if it's relative then we can't determin which gpr is really used
+ if (prev[j]->dst.chan == alu->src[src].chan &&
+ (prev[j]->dst.sel == alu->src[src].sel ||
+ prev[j]->dst.rel || alu->src[src].rel))
+ return 0;
+ }
+ }
}
- if (num_instr == 1) {
- check_scalar(bc, alu_first);
-
- } else {
-/* check_read_slots(bc, bc->cf_last->curr_bs_head);*/
- check_vector(bc, alu_first);
- LIST_FOR_EACH_ENTRY(alu, &alu_first->bs_list, bs_list) {
- check_vector(bc, alu);
+ /* more than one PRED_ or KILL_ ? */
+ if (num_once_inst > 1)
+ return 0;
+
+ /* check if the result can still be swizzlet */
+ r = check_and_set_bank_swizzle(result);
+ if (r)
+ return 0;
+
+ /* looks like everything worked out right, apply the changes */
+
+ /* sort instructions */
+ for (i = 0; i < 5; ++i) {
+ slots[i] = result[i];
+ if (result[i]) {
+ LIST_DEL(&result[i]->list);
+ result[i]->last = 0;
+ LIST_ADDTAIL(&result[i]->list, &bc->cf_last->alu);
}
}
+
+ /* determine new last instruction */
+ LIST_ENTRY(struct r600_bc_alu, bc->cf_last->alu.prev, list)->last = 1;
+
+ /* determine new first instruction */
+ for (i = 0; i < 5; ++i) {
+ if (result[i]) {
+ bc->cf_last->curr_bs_head = result[i];
+ break;
+ }
+ }
+
+ bc->cf_last->prev_bs_head = bc->cf_last->prev2_bs_head;
+ bc->cf_last->prev2_bs_head = NULL;
+
return 0;
}
@@ -537,18 +974,30 @@ int r600_bc_add_alu_type(struct r600_bc *bc, const struct r600_bc_alu *alu, int
if (nalu == NULL)
return -ENOMEM;
memcpy(nalu, alu, sizeof(struct r600_bc_alu));
- nalu->nliteral = 0;
+
+ if (bc->cf_last != NULL && bc->cf_last->inst != (type << 3)) {
+ /* check if we could add it anyway */
+ if (bc->cf_last->inst == (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3) &&
+ type == V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE) {
+ LIST_FOR_EACH_ENTRY(lalu, &bc->cf_last->alu, list) {
+ if (lalu->predicate) {
+ bc->force_add_cf = 1;
+ break;
+ }
+ }
+ } else
+ bc->force_add_cf = 1;
+ }
/* cf can contains only alu or only vtx or only tex */
- if (bc->cf_last == NULL || bc->cf_last->inst != (type << 3) ||
- bc->force_add_cf) {
+ if (bc->cf_last == NULL || bc->force_add_cf) {
r = r600_bc_add_cf(bc);
if (r) {
free(nalu);
return r;
}
- bc->cf_last->inst = (type << 3);
}
+ bc->cf_last->inst = (type << 3);
/* Setup the kcache for this ALU instruction. This will start a new
* ALU clause if needed. */
@@ -559,37 +1008,18 @@ int r600_bc_add_alu_type(struct r600_bc *bc, const struct r600_bc_alu *alu, int
if (!bc->cf_last->curr_bs_head) {
bc->cf_last->curr_bs_head = nalu;
- LIST_INITHEAD(&nalu->bs_list);
- } else {
- LIST_ADDTAIL(&nalu->bs_list, &bc->cf_last->curr_bs_head->bs_list);
}
- /* at most 128 slots, one add alu can add 4 slots + 4 constants(2 slots)
+ /* at most 128 slots, one add alu can add 5 slots + 4 constants(2 slots)
* worst case */
if (nalu->last && (bc->cf_last->ndw >> 1) >= 120) {
bc->force_add_cf = 1;
}
- /* number of gpr == the last gpr used in any alu */
+ /* replace special constants */
for (i = 0; i < 3; i++) {
- if (nalu->src[i].sel >= bc->ngpr && nalu->src[i].sel < 128) {
- bc->ngpr = nalu->src[i].sel + 1;
- }
- /* compute how many literal are needed
- * either 2 or 4 literals
- */
- if (nalu->src[i].sel == 253) {
- if (((nalu->src[i].chan + 2) & 0x6) > nalu->nliteral) {
- nalu->nliteral = (nalu->src[i].chan + 2) & 0x6;
- }
- }
- }
- if (!LIST_IS_EMPTY(&bc->cf_last->alu)) {
- lalu = LIST_ENTRY(struct r600_bc_alu, bc->cf_last->alu.prev, list);
- if (!lalu->last && lalu->nliteral > nalu->nliteral) {
- nalu->nliteral = lalu->nliteral;
- }
- }
- if (nalu->dst.sel >= bc->ngpr) {
- bc->ngpr = nalu->dst.sel + 1;
+ if (nalu->src[i].sel == V_SQ_ALU_SRC_LITERAL)
+ r600_bc_special_constants(
+ nalu->src[i].value[nalu->src[i].chan],
+ &nalu->src[i].sel, &nalu->src[i].neg);
}
LIST_ADDTAIL(&nalu->list, &bc->cf_last->alu);
/* each alu use 2 dwords */
@@ -598,7 +1028,29 @@ int r600_bc_add_alu_type(struct r600_bc *bc, const struct r600_bc_alu *alu, int
/* process cur ALU instructions for bank swizzle */
if (nalu->last) {
- check_and_set_bank_swizzle(bc, bc->cf_last->curr_bs_head);
+ struct r600_bc_alu *slots[5];
+ r = assign_alu_units(bc->cf_last->curr_bs_head, slots);
+ if (r)
+ return r;
+
+ if (bc->cf_last->prev_bs_head) {
+ r = merge_inst_groups(bc, slots, bc->cf_last->prev_bs_head);
+ if (r)
+ return r;
+ }
+
+ if (bc->cf_last->prev_bs_head) {
+ r = replace_gpr_with_pv_ps(slots, bc->cf_last->prev_bs_head);
+ if (r)
+ return r;
+ }
+
+ r = check_and_set_bank_swizzle(slots);
+ if (r)
+ return r;
+
+ bc->cf_last->prev2_bs_head = bc->cf_last->prev_bs_head;
+ bc->cf_last->prev_bs_head = bc->cf_last->curr_bs_head;
bc->cf_last->curr_bs_head = NULL;
}
return 0;
@@ -609,42 +1061,14 @@ int r600_bc_add_alu(struct r600_bc *bc, const struct r600_bc_alu *alu)
return r600_bc_add_alu_type(bc, alu, BC_INST(bc, V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU));
}
-int r600_bc_add_literal(struct r600_bc *bc, const u32 *value)
+static void r600_bc_remove_alu(struct r600_bc_cf *cf, struct r600_bc_alu *alu)
{
- struct r600_bc_alu *alu;
-
- if (bc->cf_last == NULL) {
- return 0;
- }
- if (bc->cf_last->inst == V_SQ_CF_WORD1_SQ_CF_INST_TEX) {
- return 0;
- }
- /* all same on EG */
- if (bc->cf_last->inst == V_SQ_CF_WORD1_SQ_CF_INST_JUMP ||
- bc->cf_last->inst == V_SQ_CF_WORD1_SQ_CF_INST_ELSE ||
- bc->cf_last->inst == V_SQ_CF_WORD1_SQ_CF_INST_LOOP_START_NO_AL ||
- bc->cf_last->inst == V_SQ_CF_WORD1_SQ_CF_INST_LOOP_BREAK ||
- bc->cf_last->inst == V_SQ_CF_WORD1_SQ_CF_INST_LOOP_CONTINUE ||
- bc->cf_last->inst == V_SQ_CF_WORD1_SQ_CF_INST_LOOP_END ||
- bc->cf_last->inst == V_SQ_CF_WORD1_SQ_CF_INST_POP) {
- return 0;
- }
- /* same on EG */
- if (((bc->cf_last->inst != (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3)) &&
- (bc->cf_last->inst != (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE << 3))) ||
- LIST_IS_EMPTY(&bc->cf_last->alu)) {
- R600_ERR("last CF is not ALU (%p)\n", bc->cf_last);
- return -EINVAL;
- }
- alu = LIST_ENTRY(struct r600_bc_alu, bc->cf_last->alu.prev, list);
- if (!alu->last || !alu->nliteral || alu->literal_added) {
- return 0;
+ if (alu->last && alu->list.prev != &cf->alu) {
+ PREV_ALU(alu)->last = 1;
}
- memcpy(alu->value, value, 4 * 4);
- bc->cf_last->ndw += alu->nliteral;
- bc->ndw += alu->nliteral;
- alu->literal_added = 1;
- return 0;
+ LIST_DEL(&alu->list);
+ free(alu);
+ cf->ndw -= 2;
}
int r600_bc_add_vtx(struct r600_bc *bc, const struct r600_bc_vtx *vtx)
@@ -672,7 +1096,7 @@ int r600_bc_add_vtx(struct r600_bc *bc, const struct r600_bc_vtx *vtx)
/* each fetch use 4 dwords */
bc->cf_last->ndw += 4;
bc->ndw += 4;
- if ((bc->ndw / 4) > 7)
+ if ((bc->cf_last->ndw / 4) > 7)
bc->force_add_cf = 1;
return 0;
}
@@ -701,7 +1125,7 @@ int r600_bc_add_tex(struct r600_bc *bc, const struct r600_bc_tex *tex)
/* each texture fetch use 4 dwords */
bc->cf_last->ndw += 4;
bc->ndw += 4;
- if ((bc->ndw / 4) > 7)
+ if ((bc->cf_last->ndw / 4) > 7)
bc->force_add_cf = 1;
return 0;
}
@@ -797,8 +1221,6 @@ static int r600_bc_tex_build(struct r600_bc *bc, struct r600_bc_tex *tex, unsign
/* r600 only, r700/eg bits in r700_asm.c */
static int r600_bc_alu_build(struct r600_bc *bc, struct r600_bc_alu *alu, unsigned id)
{
- unsigned i;
-
/* don't replace gpr by pv or ps for destination register */
bc->bytecode[id++] = S_SQ_ALU_WORD0_SRC0_SEL(alu->src[0].sel) |
S_SQ_ALU_WORD0_SRC0_REL(alu->src[0].rel) |
@@ -829,30 +1251,70 @@ static int r600_bc_alu_build(struct r600_bc *bc, struct r600_bc_alu *alu, unsign
S_SQ_ALU_WORD1_OP2_SRC0_ABS(alu->src[0].abs) |
S_SQ_ALU_WORD1_OP2_SRC1_ABS(alu->src[1].abs) |
S_SQ_ALU_WORD1_OP2_WRITE_MASK(alu->dst.write) |
+ S_SQ_ALU_WORD1_OP2_OMOD(alu->omod) |
S_SQ_ALU_WORD1_OP2_ALU_INST(alu->inst) |
S_SQ_ALU_WORD1_BANK_SWIZZLE(alu->bank_swizzle) |
S_SQ_ALU_WORD1_OP2_UPDATE_EXECUTE_MASK(alu->predicate) |
S_SQ_ALU_WORD1_OP2_UPDATE_PRED(alu->predicate);
}
- if (alu->last) {
- if (alu->nliteral && !alu->literal_added) {
- R600_ERR("Bug in ALU processing for instruction 0x%08x, literal not added correctly\n", alu->inst);
- }
- for (i = 0; i < alu->nliteral; i++) {
- bc->bytecode[id++] = alu->value[i];
- }
- }
return 0;
}
+enum cf_class
+{
+ CF_CLASS_ALU,
+ CF_CLASS_TEXTURE,
+ CF_CLASS_VERTEX,
+ CF_CLASS_EXPORT,
+ CF_CLASS_OTHER
+};
+
+static enum cf_class get_cf_class(struct r600_bc_cf *cf)
+{
+ switch (cf->inst) {
+ case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3):
+ case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP_AFTER << 3):
+ case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP2_AFTER << 3):
+ case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE << 3):
+ return CF_CLASS_ALU;
+
+ case V_SQ_CF_WORD1_SQ_CF_INST_TEX:
+ return CF_CLASS_TEXTURE;
+
+ case V_SQ_CF_WORD1_SQ_CF_INST_VTX:
+ case V_SQ_CF_WORD1_SQ_CF_INST_VTX_TC:
+ return CF_CLASS_VERTEX;
+
+ case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT:
+ case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT_DONE:
+ return CF_CLASS_EXPORT;
+
+ case V_SQ_CF_WORD1_SQ_CF_INST_JUMP:
+ case V_SQ_CF_WORD1_SQ_CF_INST_ELSE:
+ case V_SQ_CF_WORD1_SQ_CF_INST_POP:
+ case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_START_NO_AL:
+ case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_END:
+ case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_CONTINUE:
+ case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_BREAK:
+ case V_SQ_CF_WORD1_SQ_CF_INST_CALL_FS:
+ case V_SQ_CF_WORD1_SQ_CF_INST_RETURN:
+ return CF_CLASS_OTHER;
+
+ default:
+ R600_ERR("unsupported CF instruction (0x%X)\n", cf->inst);
+ return -EINVAL;
+ }
+}
+
/* common for r600/r700 - eg in eg_asm.c */
static int r600_bc_cf_build(struct r600_bc *bc, struct r600_bc_cf *cf)
{
unsigned id = cf->id;
+ unsigned end_of_program = bc->cf.prev == &cf->list;
- switch (cf->inst) {
- case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3):
- case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE << 3):
+ switch (get_cf_class(cf)) {
+ case CF_CLASS_ALU:
+ assert(!end_of_program);
bc->bytecode[id++] = S_SQ_CF_ALU_WORD0_ADDR(cf->addr >> 1) |
S_SQ_CF_ALU_WORD0_KCACHE_MODE0(cf->kcache[0].mode) |
S_SQ_CF_ALU_WORD0_KCACHE_BANK0(cf->kcache[0].bank) |
@@ -862,46 +1324,39 @@ static int r600_bc_cf_build(struct r600_bc *bc, struct r600_bc_cf *cf)
S_SQ_CF_ALU_WORD1_KCACHE_MODE1(cf->kcache[1].mode) |
S_SQ_CF_ALU_WORD1_KCACHE_ADDR0(cf->kcache[0].addr) |
S_SQ_CF_ALU_WORD1_KCACHE_ADDR1(cf->kcache[1].addr) |
- S_SQ_CF_ALU_WORD1_BARRIER(1) |
- S_SQ_CF_ALU_WORD1_USES_WATERFALL(bc->chiprev == CHIPREV_R600 ? cf->r6xx_uses_waterfall : 0) |
- S_SQ_CF_ALU_WORD1_COUNT((cf->ndw / 2) - 1);
+ S_SQ_CF_ALU_WORD1_BARRIER(cf->barrier) |
+ S_SQ_CF_ALU_WORD1_USES_WATERFALL(bc->chiprev == CHIPREV_R600 ? cf->r6xx_uses_waterfall : 0) |
+ S_SQ_CF_ALU_WORD1_COUNT((cf->ndw / 2) - 1);
break;
- case V_SQ_CF_WORD1_SQ_CF_INST_TEX:
- case V_SQ_CF_WORD1_SQ_CF_INST_VTX:
- case V_SQ_CF_WORD1_SQ_CF_INST_VTX_TC:
+ case CF_CLASS_TEXTURE:
+ case CF_CLASS_VERTEX:
bc->bytecode[id++] = S_SQ_CF_WORD0_ADDR(cf->addr >> 1);
bc->bytecode[id++] = S_SQ_CF_WORD1_CF_INST(cf->inst) |
- S_SQ_CF_WORD1_BARRIER(1) |
- S_SQ_CF_WORD1_COUNT((cf->ndw / 4) - 1);
+ S_SQ_CF_WORD1_BARRIER(cf->barrier) |
+ S_SQ_CF_WORD1_COUNT((cf->ndw / 4) - 1) |
+ S_SQ_CF_WORD1_END_OF_PROGRAM(end_of_program);
break;
- case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT:
- case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT_DONE:
+ case CF_CLASS_EXPORT:
bc->bytecode[id++] = S_SQ_CF_ALLOC_EXPORT_WORD0_RW_GPR(cf->output.gpr) |
S_SQ_CF_ALLOC_EXPORT_WORD0_ELEM_SIZE(cf->output.elem_size) |
S_SQ_CF_ALLOC_EXPORT_WORD0_ARRAY_BASE(cf->output.array_base) |
S_SQ_CF_ALLOC_EXPORT_WORD0_TYPE(cf->output.type);
- bc->bytecode[id++] = S_SQ_CF_ALLOC_EXPORT_WORD1_SWIZ_SEL_X(cf->output.swizzle_x) |
+ bc->bytecode[id++] = S_SQ_CF_ALLOC_EXPORT_WORD1_BURST_COUNT(cf->output.burst_count - 1) |
+ S_SQ_CF_ALLOC_EXPORT_WORD1_SWIZ_SEL_X(cf->output.swizzle_x) |
S_SQ_CF_ALLOC_EXPORT_WORD1_SWIZ_SEL_Y(cf->output.swizzle_y) |
S_SQ_CF_ALLOC_EXPORT_WORD1_SWIZ_SEL_Z(cf->output.swizzle_z) |
S_SQ_CF_ALLOC_EXPORT_WORD1_SWIZ_SEL_W(cf->output.swizzle_w) |
- S_SQ_CF_ALLOC_EXPORT_WORD1_BARRIER(cf->output.barrier) |
- S_SQ_CF_ALLOC_EXPORT_WORD1_CF_INST(cf->output.inst) |
- S_SQ_CF_ALLOC_EXPORT_WORD1_END_OF_PROGRAM(cf->output.end_of_program);
+ S_SQ_CF_ALLOC_EXPORT_WORD1_BARRIER(cf->barrier) |
+ S_SQ_CF_ALLOC_EXPORT_WORD1_CF_INST(cf->inst) |
+ S_SQ_CF_ALLOC_EXPORT_WORD1_END_OF_PROGRAM(end_of_program);
break;
- case V_SQ_CF_WORD1_SQ_CF_INST_JUMP:
- case V_SQ_CF_WORD1_SQ_CF_INST_ELSE:
- case V_SQ_CF_WORD1_SQ_CF_INST_POP:
- case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_START_NO_AL:
- case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_END:
- case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_CONTINUE:
- case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_BREAK:
- case V_SQ_CF_WORD1_SQ_CF_INST_CALL_FS:
- case V_SQ_CF_WORD1_SQ_CF_INST_RETURN:
+ case CF_CLASS_OTHER:
bc->bytecode[id++] = S_SQ_CF_WORD0_ADDR(cf->cf_addr >> 1);
bc->bytecode[id++] = S_SQ_CF_WORD1_CF_INST(cf->inst) |
- S_SQ_CF_WORD1_BARRIER(1) |
- S_SQ_CF_WORD1_COND(cf->cond) |
- S_SQ_CF_WORD1_POP_COUNT(cf->pop_count);
+ S_SQ_CF_WORD1_BARRIER(cf->barrier) |
+ S_SQ_CF_WORD1_COND(cf->cond) |
+ S_SQ_CF_WORD1_POP_COUNT(cf->pop_count) |
+ S_SQ_CF_WORD1_END_OF_PROGRAM(end_of_program);
break;
default:
@@ -911,14 +1366,776 @@ static int r600_bc_cf_build(struct r600_bc *bc, struct r600_bc_cf *cf)
return 0;
}
+struct gpr_usage_range {
+ int replacement;
+ int32_t start;
+ int32_t end;
+};
+
+struct gpr_usage {
+ unsigned channels:4;
+ int32_t first_write;
+ int32_t last_write[4];
+ unsigned nranges;
+ struct gpr_usage_range *ranges;
+};
+
+static struct gpr_usage_range* add_gpr_usage_range(struct gpr_usage *usage)
+{
+ usage->nranges++;
+ usage->ranges = realloc(usage->ranges, usage->nranges * sizeof(struct gpr_usage_range));
+ if (!usage->ranges)
+ return NULL;
+ return &usage->ranges[usage->nranges-1];
+}
+
+static void notice_gpr_read(struct gpr_usage *usage, int32_t id, unsigned chan)
+{
+ usage->channels |= 1 << chan;
+ usage->first_write = -1;
+ if (!usage->nranges) {
+ struct gpr_usage_range* range = add_gpr_usage_range(usage);
+ range->replacement = -1;
+ range->start = -1;
+ range->end = -1;
+ }
+ if (usage->ranges[usage->nranges-1].end < id)
+ usage->ranges[usage->nranges-1].end = id;
+}
+
+static void notice_gpr_rel_read(struct gpr_usage usage[128], int32_t id, unsigned chan)
+{
+ unsigned i;
+ for (i = 0; i < 128; ++i)
+ notice_gpr_read(&usage[i], id, chan);
+}
+
+static void notice_gpr_last_write(struct gpr_usage *usage, int32_t id, unsigned chan)
+{
+ usage->last_write[chan] = id;
+}
+
+static void notice_gpr_write(struct gpr_usage *usage, int32_t id, unsigned chan,
+ int predicate, int prefered_replacement)
+{
+ int32_t start = usage->first_write != -1 ? usage->first_write : id;
+ usage->channels &= ~(1 << chan);
+ if (usage->channels) {
+ if (usage->first_write == -1)
+ usage->first_write = id;
+ } else if (!usage->nranges || (usage->ranges[usage->nranges-1].start != start && !predicate)) {
+ usage->first_write = start;
+ struct gpr_usage_range* range = add_gpr_usage_range(usage);
+ range->replacement = prefered_replacement;
+ range->start = start;
+ range->end = -1;
+ } else if (usage->ranges[usage->nranges-1].start == start && prefered_replacement != -1) {
+ usage->ranges[usage->nranges-1].replacement = prefered_replacement;
+ }
+ notice_gpr_last_write(usage, id, chan);
+}
+
+static void notice_gpr_rel_last_write(struct gpr_usage usage[128], int32_t id, unsigned chan)
+{
+ unsigned i;
+ for (i = 0; i < 128; ++i)
+ notice_gpr_last_write(&usage[i], id, chan);
+}
+
+static void notice_gpr_rel_write(struct gpr_usage usage[128], int32_t id, unsigned chan)
+{
+ unsigned i;
+ for (i = 0; i < 128; ++i)
+ notice_gpr_write(&usage[i], id, chan, 1, -1);
+}
+
+static void notice_alu_src_gprs(struct r600_bc_alu *alu, struct gpr_usage usage[128], int32_t id)
+{
+ unsigned src, num_src;
+
+ num_src = r600_bc_get_num_operands(alu);
+ for (src = 0; src < num_src; ++src) {
+ // constants doesn't matter
+ if (!is_gpr(alu->src[src].sel))
+ continue;
+
+ if (alu->src[src].rel)
+ notice_gpr_rel_read(usage, id, alu->src[src].chan);
+ else
+ notice_gpr_read(&usage[alu->src[src].sel], id, alu->src[src].chan);
+ }
+}
+
+static void notice_alu_dst_gprs(struct r600_bc_alu *alu_first, struct gpr_usage usage[128],
+ int32_t id, int predicate)
+{
+ struct r600_bc_alu *alu;
+ for (alu = alu_first; alu; alu = LIST_ENTRY(struct r600_bc_alu, alu->list.next, list)) {
+ if (alu->dst.write) {
+ if (alu->dst.rel)
+ notice_gpr_rel_write(usage, id, alu->dst.chan);
+ else if (alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV && is_gpr(alu->src[0].sel))
+ notice_gpr_write(&usage[alu->dst.sel], id, alu->dst.chan,
+ predicate, alu->src[0].sel);
+ else
+ notice_gpr_write(&usage[alu->dst.sel], id, alu->dst.chan, predicate, -1);
+ }
+
+ if (alu->last)
+ break;
+ }
+}
+
+static void notice_tex_gprs(struct r600_bc_tex *tex, struct gpr_usage usage[128],
+ int32_t id, int predicate)
+{
+ if (tex->src_rel) {
+ if (tex->src_sel_x < 4)
+ notice_gpr_rel_read(usage, id, tex->src_sel_x);
+ if (tex->src_sel_y < 4)
+ notice_gpr_rel_read(usage, id, tex->src_sel_y);
+ if (tex->src_sel_z < 4)
+ notice_gpr_rel_read(usage, id, tex->src_sel_z);
+ if (tex->src_sel_w < 4)
+ notice_gpr_rel_read(usage, id, tex->src_sel_w);
+ } else {
+ if (tex->src_sel_x < 4)
+ notice_gpr_read(&usage[tex->src_gpr], id, tex->src_sel_x);
+ if (tex->src_sel_y < 4)
+ notice_gpr_read(&usage[tex->src_gpr], id, tex->src_sel_y);
+ if (tex->src_sel_z < 4)
+ notice_gpr_read(&usage[tex->src_gpr], id, tex->src_sel_z);
+ if (tex->src_sel_w < 4)
+ notice_gpr_read(&usage[tex->src_gpr], id, tex->src_sel_w);
+ }
+ if (tex->dst_rel) {
+ if (tex->dst_sel_x != 7)
+ notice_gpr_rel_write(usage, id, 0);
+ if (tex->dst_sel_y != 7)
+ notice_gpr_rel_write(usage, id, 1);
+ if (tex->dst_sel_z != 7)
+ notice_gpr_rel_write(usage, id, 2);
+ if (tex->dst_sel_w != 7)
+ notice_gpr_rel_write(usage, id, 3);
+ } else {
+ if (tex->dst_sel_x != 7)
+ notice_gpr_write(&usage[tex->dst_gpr], id, 0, predicate, -1);
+ if (tex->dst_sel_y != 7)
+ notice_gpr_write(&usage[tex->dst_gpr], id, 1, predicate, -1);
+ if (tex->dst_sel_z != 7)
+ notice_gpr_write(&usage[tex->dst_gpr], id, 2, predicate, -1);
+ if (tex->dst_sel_w != 7)
+ notice_gpr_write(&usage[tex->dst_gpr], id, 3, predicate, -1);
+ }
+}
+
+static void notice_vtx_gprs(struct r600_bc_vtx *vtx, struct gpr_usage usage[128],
+ int32_t id, int predicate)
+{
+ notice_gpr_read(&usage[vtx->src_gpr], id, vtx->src_sel_x);
+
+ if (vtx->dst_sel_x != 7)
+ notice_gpr_write(&usage[vtx->dst_gpr], id, 0, predicate, -1);
+ if (vtx->dst_sel_y != 7)
+ notice_gpr_write(&usage[vtx->dst_gpr], id, 1, predicate, -1);
+ if (vtx->dst_sel_z != 7)
+ notice_gpr_write(&usage[vtx->dst_gpr], id, 2, predicate, -1);
+ if (vtx->dst_sel_w != 7)
+ notice_gpr_write(&usage[vtx->dst_gpr], id, 3, predicate, -1);
+}
+
+static void notice_export_gprs(struct r600_bc_cf *cf, struct gpr_usage usage[128],
+ struct r600_bc_cf *export_cf[128], int32_t export_remap[128])
+{
+ //TODO handle other memory operations
+ struct gpr_usage *output = &usage[cf->output.gpr];
+ int32_t id = (output->last_write[0] + 0x100) & ~0xFF;
+
+ export_cf[cf->output.gpr] = cf;
+ export_remap[cf->output.gpr] = id;
+ if (cf->output.swizzle_x < 4)
+ notice_gpr_read(output, id, cf->output.swizzle_x);
+ if (cf->output.swizzle_y < 4)
+ notice_gpr_read(output, id, cf->output.swizzle_y);
+ if (cf->output.swizzle_z < 4)
+ notice_gpr_read(output, id, cf->output.swizzle_z);
+ if (cf->output.swizzle_w < 4)
+ notice_gpr_read(output, id, cf->output.swizzle_w);
+}
+
+static struct gpr_usage_range *find_src_range(struct gpr_usage *usage, int32_t id)
+{
+ unsigned i;
+ for (i = 0; i < usage->nranges; ++i) {
+ struct gpr_usage_range* range = &usage->ranges[i];
+
+ if (range->start < id && id <= range->end)
+ return range;
+ }
+ return NULL;
+}
+
+static struct gpr_usage_range *find_dst_range(struct gpr_usage *usage, int32_t id)
+{
+ unsigned i;
+ for (i = 0; i < usage->nranges; ++i) {
+ struct gpr_usage_range* range = &usage->ranges[i];
+ int32_t end = range->end;
+
+ if (range->start <= id && (id < end || end == -1))
+ return range;
+ }
+ assert(0); /* should not happen */
+ return NULL;
+}
+
+static int is_barrier_needed(struct gpr_usage *usage, int32_t id, unsigned chan, int32_t last_barrier)
+{
+ if (usage->last_write[chan] != (id & ~0xFF))
+ return usage->last_write[chan] >= last_barrier;
+ else
+ return 0;
+}
+
+static int is_intersection(struct gpr_usage_range* a, struct gpr_usage_range* b)
+{
+ return a->start <= b->end && b->start < a->end;
+}
+
+static int rate_replacement(struct gpr_usage *usage, struct gpr_usage_range* range)
+{
+ unsigned i;
+ int32_t best_start = 0x3FFFFFFF, best_end = 0x3FFFFFFF;
+
+ for (i = 0; i < usage->nranges; ++i) {
+ if (usage->ranges[i].replacement != -1)
+ continue; /* ignore already remapped ranges */
+
+ if (is_intersection(&usage->ranges[i], range))
+ return -1; /* forget it if usages overlap */
+
+ if (range->start >= usage->ranges[i].end)
+ best_start = MIN2(best_start, range->start - usage->ranges[i].end);
+
+ if (range->end != -1 && range->end <= usage->ranges[i].start)
+ best_end = MIN2(best_end, usage->ranges[i].start - range->end);
+ }
+ return best_start + best_end;
+}
+
+static void find_replacement(struct gpr_usage usage[128], unsigned current,
+ struct gpr_usage_range *range, int is_export)
+{
+ unsigned i;
+ int best_gpr = -1, best_rate = 0x7FFFFFFF;
+
+ if (range->replacement != -1 && range->replacement <= current) {
+ struct gpr_usage_range *other = find_src_range(&usage[range->replacement], range->start);
+ if (other && other->replacement != -1)
+ range->replacement = other->replacement;
+ }
+
+ if (range->replacement != -1 && range->replacement < current) {
+ int rate = rate_replacement(&usage[range->replacement], range);
+
+ /* check if prefered replacement can be used */
+ if (rate != -1) {
+ best_rate = rate;
+ best_gpr = range->replacement;
+ }
+ }
+
+ if (best_gpr == -1 && (range->start & ~0xFF) == (range->end & ~0xFF)) {
+ /* register is just used inside one ALU clause */
+ /* try to use clause temporaryis for it */
+ for (i = 127; i > 123; --i) {
+ int rate = rate_replacement(&usage[i], range);
+
+ if (rate == -1) /* can't be used because ranges overlap */
+ continue;
+
+ if (rate < best_rate) {
+ best_rate = rate;
+ best_gpr = i;
+
+ /* can't get better than this */
+ if (rate == 0 || is_export)
+ break;
+ }
+ }
+ }
+
+ if (best_gpr == -1) {
+ for (i = 0; i < current; ++i) {
+ int rate = rate_replacement(&usage[i], range);
+
+ if (rate == -1) /* can't be used because ranges overlap */
+ continue;
+
+ if (rate < best_rate) {
+ best_rate = rate;
+ best_gpr = i;
+
+ /* can't get better than this */
+ if (rate == 0)
+ break;
+ }
+ }
+ }
+
+ range->replacement = best_gpr;
+ if (best_gpr != -1) {
+ struct gpr_usage_range *reservation = add_gpr_usage_range(&usage[best_gpr]);
+ reservation->replacement = -1;
+ reservation->start = range->start;
+ reservation->end = range->end;
+ }
+}
+
+static void find_export_replacement(struct gpr_usage usage[128],
+ struct gpr_usage_range *range, struct r600_bc_cf *current,
+ struct r600_bc_cf *next, int32_t next_id)
+{
+ if (!next || next_id <= range->start || next_id > range->end)
+ return;
+
+ if (current->output.type != next->output.type)
+ return;
+
+ if ((current->output.array_base + 1) != next->output.array_base)
+ return;
+
+ find_src_range(&usage[next->output.gpr], next_id)->replacement = range->replacement + 1;
+}
+
+static void replace_alu_gprs(struct r600_bc_alu *alu, struct gpr_usage usage[128],
+ int32_t id, int32_t last_barrier, unsigned *barrier)
+{
+ struct gpr_usage *cur_usage;
+ struct gpr_usage_range *range;
+ unsigned src, num_src;
+
+ num_src = r600_bc_get_num_operands(alu);
+ for (src = 0; src < num_src; ++src) {
+ // constants doesn't matter
+ if (!is_gpr(alu->src[src].sel))
+ continue;
+
+ cur_usage = &usage[alu->src[src].sel];
+ range = find_src_range(cur_usage, id);
+ if (range->replacement != -1)
+ alu->src[src].sel = range->replacement;
+
+ *barrier |= is_barrier_needed(cur_usage, id, alu->src[src].chan, last_barrier);
+ }
+
+ if (alu->dst.write) {
+ cur_usage = &usage[alu->dst.sel];
+ range = find_dst_range(cur_usage, id);
+ if (range->replacement == alu->dst.sel) {
+ if (!alu->is_op3)
+ alu->dst.write = 0;
+ else
+ /*TODO: really check that register 123 is useable */
+ alu->dst.sel = 123;
+ } else if (range->replacement != -1) {
+ alu->dst.sel = range->replacement;
+ }
+ if (alu->dst.rel)
+ notice_gpr_rel_last_write(usage, id, alu->dst.chan);
+ else
+ notice_gpr_last_write(cur_usage, id, alu->dst.chan);
+ }
+}
+
+static void replace_tex_gprs(struct r600_bc_tex *tex, struct gpr_usage usage[128],
+ int32_t id, int32_t last_barrier, unsigned *barrier)
+{
+ struct gpr_usage *cur_usage = &usage[tex->src_gpr];
+ struct gpr_usage_range *range = find_src_range(cur_usage, id);
+
+ if (tex->src_rel) {
+ *barrier = 1;
+ } else {
+ if (tex->src_sel_x < 4)
+ *barrier |= is_barrier_needed(cur_usage, id, tex->src_sel_x, last_barrier);
+ if (tex->src_sel_y < 4)
+ *barrier |= is_barrier_needed(cur_usage, id, tex->src_sel_y, last_barrier);
+ if (tex->src_sel_z < 4)
+ *barrier |= is_barrier_needed(cur_usage, id, tex->src_sel_z, last_barrier);
+ if (tex->src_sel_w < 4)
+ *barrier |= is_barrier_needed(cur_usage, id, tex->src_sel_w, last_barrier);
+ }
+
+ if (range->replacement != -1)
+ tex->src_gpr = range->replacement;
+
+ cur_usage = &usage[tex->dst_gpr];
+ range = find_dst_range(cur_usage, id);
+ if (range->replacement != -1)
+ tex->dst_gpr = range->replacement;
+
+ if (tex->dst_rel) {
+ if (tex->dst_sel_x != 7)
+ notice_gpr_rel_last_write(usage, id, tex->dst_sel_x);
+ if (tex->dst_sel_y != 7)
+ notice_gpr_rel_last_write(usage, id, tex->dst_sel_y);
+ if (tex->dst_sel_z != 7)
+ notice_gpr_rel_last_write(usage, id, tex->dst_sel_z);
+ if (tex->dst_sel_w != 7)
+ notice_gpr_rel_last_write(usage, id, tex->dst_sel_w);
+ } else {
+ if (tex->dst_sel_x != 7)
+ notice_gpr_last_write(cur_usage, id, tex->dst_sel_x);
+ if (tex->dst_sel_y != 7)
+ notice_gpr_last_write(cur_usage, id, tex->dst_sel_y);
+ if (tex->dst_sel_z != 7)
+ notice_gpr_last_write(cur_usage, id, tex->dst_sel_z);
+ if (tex->dst_sel_w != 7)
+ notice_gpr_last_write(cur_usage, id, tex->dst_sel_w);
+ }
+}
+
+static void replace_vtx_gprs(struct r600_bc_vtx *vtx, struct gpr_usage usage[128],
+ int32_t id, int32_t last_barrier, unsigned *barrier)
+{
+ struct gpr_usage *cur_usage = &usage[vtx->src_gpr];
+ struct gpr_usage_range *range = find_src_range(cur_usage, id);
+
+ *barrier |= is_barrier_needed(cur_usage, id, vtx->src_sel_x, last_barrier);
+
+ if (range->replacement != -1)
+ vtx->src_gpr = range->replacement;
+
+ cur_usage = &usage[vtx->dst_gpr];
+ range = find_dst_range(cur_usage, id);
+ if (range->replacement != -1)
+ vtx->dst_gpr = range->replacement;
+
+ if (vtx->dst_sel_x != 7)
+ notice_gpr_last_write(cur_usage, id, vtx->dst_sel_x);
+ if (vtx->dst_sel_y != 7)
+ notice_gpr_last_write(cur_usage, id, vtx->dst_sel_y);
+ if (vtx->dst_sel_z != 7)
+ notice_gpr_last_write(cur_usage, id, vtx->dst_sel_z);
+ if (vtx->dst_sel_w != 7)
+ notice_gpr_last_write(cur_usage, id, vtx->dst_sel_w);
+}
+
+static void replace_export_gprs(struct r600_bc_cf *cf, struct gpr_usage usage[128],
+ int32_t id, int32_t last_barrier)
+{
+ //TODO handle other memory operations
+ struct gpr_usage *cur_usage = &usage[cf->output.gpr];
+ struct gpr_usage_range *range = find_src_range(cur_usage, id);
+
+ cf->barrier = 0;
+ if (cf->output.swizzle_x < 4)
+ cf->barrier |= is_barrier_needed(cur_usage, -1, cf->output.swizzle_x, last_barrier);
+ if (cf->output.swizzle_y < 4)
+ cf->barrier |= is_barrier_needed(cur_usage, -1, cf->output.swizzle_y, last_barrier);
+ if (cf->output.swizzle_z < 4)
+ cf->barrier |= is_barrier_needed(cur_usage, -1, cf->output.swizzle_z, last_barrier);
+ if (cf->output.swizzle_w < 4)
+ cf->barrier |= is_barrier_needed(cur_usage, -1, cf->output.swizzle_w, last_barrier);
+
+ if (range->replacement != -1)
+ cf->output.gpr = range->replacement;
+}
+
+static void optimize_alu_inst(struct r600_bc_cf *cf, struct r600_bc_alu *alu)
+{
+ struct r600_bc_alu *alu_next;
+ unsigned chan;
+ unsigned src, num_src;
+
+ /* check if a MOV could be optimized away */
+ if (alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV) {
+
+ /* destination equals source? */
+ if (alu->dst.sel != alu->src[0].sel ||
+ alu->dst.chan != alu->src[0].chan)
+ return;
+
+ /* any special handling for the source? */
+ if (alu->src[0].rel || alu->src[0].neg || alu->src[0].abs)
+ return;
+
+ /* any special handling for destination? */
+ if (alu->dst.rel || alu->dst.clamp)
+ return;
+
+ /* ok find next instruction group and check if ps/pv is used */
+ for (alu_next = alu; !alu_next->last; alu_next = NEXT_ALU(alu_next));
+
+ if (alu_next->list.next != &cf->alu) {
+ chan = is_alu_reduction_inst(alu) ? 0 : alu->dst.chan;
+ for (alu_next = NEXT_ALU(alu_next); alu_next; alu_next = NEXT_ALU(alu_next)) {
+ num_src = r600_bc_get_num_operands(alu_next);
+ for (src = 0; src < num_src; ++src) {
+ if (alu_next->src[src].sel == V_SQ_ALU_SRC_PV &&
+ alu_next->src[src].chan == chan)
+ return;
+
+ if (alu_next->src[src].sel == V_SQ_ALU_SRC_PS)
+ return;
+ }
+
+ if (alu_next->last)
+ break;
+ }
+ }
+
+ r600_bc_remove_alu(cf, alu);
+ }
+}
+
+static void optimize_export_inst(struct r600_bc *bc, struct r600_bc_cf *cf)
+{
+ struct r600_bc_cf *prev = LIST_ENTRY(struct r600_bc_cf, cf->list.prev, list);
+ if (&prev->list == &bc->cf ||
+ prev->inst != cf->inst ||
+ prev->output.type != cf->output.type ||
+ prev->output.elem_size != cf->output.elem_size ||
+ prev->output.swizzle_x != cf->output.swizzle_x ||
+ prev->output.swizzle_y != cf->output.swizzle_y ||
+ prev->output.swizzle_z != cf->output.swizzle_z ||
+ prev->output.swizzle_w != cf->output.swizzle_w)
+ return;
+
+ if ((prev->output.burst_count + cf->output.burst_count) > 16)
+ return;
+
+ if ((prev->output.gpr + prev->output.burst_count) == cf->output.gpr &&
+ (prev->output.array_base + prev->output.burst_count) == cf->output.array_base) {
+
+ prev->output.burst_count += cf->output.burst_count;
+ r600_bc_remove_cf(bc, cf);
+
+ } else if (prev->output.gpr == (cf->output.gpr + cf->output.burst_count) &&
+ prev->output.array_base == (cf->output.array_base + cf->output.burst_count)) {
+
+ cf->output.burst_count += prev->output.burst_count;
+ r600_bc_remove_cf(bc, prev);
+ }
+}
+
+static void r600_bc_optimize(struct r600_bc *bc)
+{
+ struct r600_bc_cf *cf, *next_cf;
+ struct r600_bc_alu *first, *next_alu;
+ struct r600_bc_alu *alu;
+ struct r600_bc_vtx *vtx;
+ struct r600_bc_tex *tex;
+ struct gpr_usage usage[128];
+
+ /* assume that each gpr is exported only once */
+ struct r600_bc_cf *export_cf[128] = { NULL };
+ int32_t export_remap[128];
+
+ int32_t id, barrier[bc->nstack];
+ unsigned i, j, stack, predicate, old_stack;
+
+ memset(&usage, 0, sizeof(usage));
+ for (i = 0; i < 128; ++i) {
+ usage[i].first_write = -1;
+ usage[i].last_write[0] = -1;
+ usage[i].last_write[1] = -1;
+ usage[i].last_write[2] = -1;
+ usage[i].last_write[3] = -1;
+ }
+
+ /* first gather some informations about the gpr usage */
+ id = 0; stack = 0;
+ LIST_FOR_EACH_ENTRY(cf, &bc->cf, list) {
+ switch (get_cf_class(cf)) {
+ case CF_CLASS_ALU:
+ predicate = 0;
+ first = NULL;
+ LIST_FOR_EACH_ENTRY(alu, &cf->alu, list) {
+ if (!first)
+ first = alu;
+ notice_alu_src_gprs(alu, usage, id);
+ if (alu->last) {
+ notice_alu_dst_gprs(first, usage, id, predicate || stack > 0);
+ first = NULL;
+ ++id;
+ }
+ if (is_alu_pred_inst(alu))
+ predicate++;
+ }
+ if (cf->inst == V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE << 3)
+ stack += predicate;
+ else if (cf->inst == V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP_AFTER << 3)
+ stack -= 1;
+ else if (cf->inst == V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP2_AFTER << 3)
+ stack -= 2;
+ break;
+ case CF_CLASS_TEXTURE:
+ LIST_FOR_EACH_ENTRY(tex, &cf->tex, list) {
+ notice_tex_gprs(tex, usage, id++, stack > 0);
+ }
+ break;
+ case CF_CLASS_VERTEX:
+ LIST_FOR_EACH_ENTRY(vtx, &cf->vtx, list) {
+ notice_vtx_gprs(vtx, usage, id++, stack > 0);
+ }
+ break;
+ case CF_CLASS_EXPORT:
+ notice_export_gprs(cf, usage, export_cf, export_remap);
+ continue; // don't increment id
+ case CF_CLASS_OTHER:
+ switch (cf->inst) {
+ case V_SQ_CF_WORD1_SQ_CF_INST_JUMP:
+ case V_SQ_CF_WORD1_SQ_CF_INST_ELSE:
+ case V_SQ_CF_WORD1_SQ_CF_INST_CALL_FS:
+ break;
+
+ case V_SQ_CF_WORD1_SQ_CF_INST_POP:
+ stack -= cf->pop_count;
+ break;
+
+ default:
+ // TODO implement loop handling
+ goto out;
+ }
+ }
+ id += 0x100;
+ id &= ~0xFF;
+ }
+ assert(stack == 0);
+
+ /* try to optimize gpr usage */
+ for (i = 0; i < 124; ++i) {
+ for (j = 0; j < usage[i].nranges; ++j) {
+ struct gpr_usage_range *range = &usage[i].ranges[j];
+ int is_export = export_cf[i] && export_cf[i + 1] &&
+ range->start < export_remap[i] &&
+ export_remap[i] <= range->end;
+
+ if (range->start == -1)
+ range->replacement = -1;
+ else if (range->end == -1)
+ range->replacement = i;
+ else
+ find_replacement(usage, i, range, is_export);
+
+ if (range->replacement == -1)
+ bc->ngpr = i;
+ else if (range->replacement < i && range->replacement > bc->ngpr)
+ bc->ngpr = range->replacement;
+
+ if (is_export && range->replacement != -1) {
+ find_export_replacement(usage, range, export_cf[i],
+ export_cf[i + 1], export_remap[i + 1]);
+ }
+ }
+ }
+ bc->ngpr++;
+
+ /* apply the changes */
+ for (i = 0; i < 128; ++i) {
+ usage[i].last_write[0] = -1;
+ usage[i].last_write[1] = -1;
+ usage[i].last_write[2] = -1;
+ usage[i].last_write[3] = -1;
+ }
+ barrier[0] = 0;
+ id = 0; stack = 0;
+ LIST_FOR_EACH_ENTRY_SAFE(cf, next_cf, &bc->cf, list) {
+ old_stack = stack;
+ switch (get_cf_class(cf)) {
+ case CF_CLASS_ALU:
+ predicate = 0;
+ first = NULL;
+ cf->barrier = 0;
+ LIST_FOR_EACH_ENTRY_SAFE(alu, next_alu, &cf->alu, list) {
+ replace_alu_gprs(alu, usage, id, barrier[stack], &cf->barrier);
+ if (alu->last)
+ ++id;
+
+ if (is_alu_pred_inst(alu))
+ predicate++;
+
+ if (cf->inst == V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3)
+ optimize_alu_inst(cf, alu);
+ }
+ if (cf->inst == V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE << 3)
+ stack += predicate;
+ else if (cf->inst == V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP_AFTER << 3)
+ stack -= 1;
+ else if (cf->inst == V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP2_AFTER << 3)
+ stack -= 2;
+ if (LIST_IS_EMPTY(&cf->alu)) {
+ r600_bc_remove_cf(bc, cf);
+ cf = NULL;
+ }
+ break;
+ case CF_CLASS_TEXTURE:
+ cf->barrier = 0;
+ LIST_FOR_EACH_ENTRY(tex, &cf->tex, list) {
+ replace_tex_gprs(tex, usage, id++, barrier[stack], &cf->barrier);
+ }
+ break;
+ case CF_CLASS_VERTEX:
+ cf->barrier = 0;
+ LIST_FOR_EACH_ENTRY(vtx, &cf->vtx, list) {
+ replace_vtx_gprs(vtx, usage, id++, barrier[stack], &cf->barrier);
+ }
+ break;
+ case CF_CLASS_EXPORT:
+ continue; // don't increment id
+ case CF_CLASS_OTHER:
+ if (cf->inst == V_SQ_CF_WORD1_SQ_CF_INST_POP) {
+ cf->barrier = 0;
+ stack -= cf->pop_count;
+ }
+ break;
+ }
+
+ id &= ~0xFF;
+ if (cf && cf->barrier)
+ barrier[old_stack] = id;
+
+ for (i = old_stack + 1; i <= stack; ++i)
+ barrier[i] = barrier[old_stack];
+
+ id += 0x100;
+ if (stack != 0) /* ensue exports are placed outside of conditional blocks */
+ continue;
+
+ for (i = 0; i < 128; ++i) {
+ if (!export_cf[i] || id < export_remap[i])
+ continue;
+
+ r600_bc_move_cf(bc, export_cf[i], next_cf);
+ replace_export_gprs(export_cf[i], usage, export_remap[i], barrier[stack]);
+ if (export_cf[i]->barrier)
+ barrier[stack] = id - 1;
+ next_cf = LIST_ENTRY(struct r600_bc_cf, export_cf[i]->list.next, list);
+ optimize_export_inst(bc, export_cf[i]);
+ export_cf[i] = NULL;
+ }
+ }
+ assert(stack == 0);
+
+out:
+ for (i = 0; i < 128; ++i) {
+ free(usage[i].ranges);
+ }
+}
+
int r600_bc_build(struct r600_bc *bc)
{
struct r600_bc_cf *cf;
struct r600_bc_alu *alu;
struct r600_bc_vtx *vtx;
struct r600_bc_tex *tex;
+ struct r600_bc_cf *exports[4] = { NULL };
+ uint32_t literal[4];
+ unsigned nliteral;
unsigned addr;
- int r;
+ int i, r;
if (bc->callstack[0].max > 0)
bc->nstack = ((bc->callstack[0].max + 3) >> 2) + 2;
@@ -926,35 +2143,37 @@ int r600_bc_build(struct r600_bc *bc)
bc->nstack = 1;
}
+ r600_bc_optimize(bc);
+
/* first path compute addr of each CF block */
/* addr start after all the CF instructions */
- addr = bc->cf_last->id + 2;
+ addr = LIST_ENTRY(struct r600_bc_cf, bc->cf.prev, list)->id + 2;
LIST_FOR_EACH_ENTRY(cf, &bc->cf, list) {
- switch (cf->inst) {
- case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3):
- case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE << 3):
+ switch (get_cf_class(cf)) {
+ case CF_CLASS_ALU:
+ nliteral = 0;
+ LIST_FOR_EACH_ENTRY(alu, &cf->alu, list) {
+ r = r600_bc_alu_nliterals(alu, literal, &nliteral);
+ if (r)
+ return r;
+ if (alu->last) {
+ cf->ndw += align(nliteral, 2);
+ nliteral = 0;
+ }
+ }
break;
- case V_SQ_CF_WORD1_SQ_CF_INST_TEX:
- case V_SQ_CF_WORD1_SQ_CF_INST_VTX:
- case V_SQ_CF_WORD1_SQ_CF_INST_VTX_TC:
+ case CF_CLASS_TEXTURE:
+ case CF_CLASS_VERTEX:
/* fetch node need to be 16 bytes aligned*/
addr += 3;
addr &= 0xFFFFFFFCUL;
break;
- case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT:
- case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT_DONE:
- case EG_V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT:
- case EG_V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT_DONE:
break;
- case V_SQ_CF_WORD1_SQ_CF_INST_JUMP:
- case V_SQ_CF_WORD1_SQ_CF_INST_ELSE:
- case V_SQ_CF_WORD1_SQ_CF_INST_POP:
- case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_START_NO_AL:
- case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_END:
- case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_CONTINUE:
- case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_BREAK:
- case V_SQ_CF_WORD1_SQ_CF_INST_CALL_FS:
- case V_SQ_CF_WORD1_SQ_CF_INST_RETURN:
+ case CF_CLASS_EXPORT:
+ if (cf->inst == BC_INST(bc, V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT))
+ exports[cf->output.type] = cf;
+ break;
+ case CF_CLASS_OTHER:
break;
default:
R600_ERR("unsupported CF instruction (0x%X)\n", cf->inst);
@@ -964,6 +2183,14 @@ int r600_bc_build(struct r600_bc *bc)
addr += cf->ndw;
bc->ndw = cf->addr + cf->ndw;
}
+
+ /* set export done on last export of each type */
+ for (i = 0; i < 4; ++i) {
+ if (exports[i]) {
+ exports[i]->inst = BC_INST(bc, V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT_DONE);
+ }
+ }
+
free(bc->bytecode);
bc->bytecode = calloc(1, bc->ndw * 4);
if (bc->bytecode == NULL)
@@ -976,10 +2203,14 @@ int r600_bc_build(struct r600_bc *bc)
r = r600_bc_cf_build(bc, cf);
if (r)
return r;
- switch (cf->inst) {
- case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3):
- case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE << 3):
+ switch (get_cf_class(cf)) {
+ case CF_CLASS_ALU:
+ nliteral = 0;
LIST_FOR_EACH_ENTRY(alu, &cf->alu, list) {
+ r = r600_bc_alu_nliterals(alu, literal, &nliteral);
+ if (r)
+ return r;
+ r600_bc_alu_adjust_literals(alu, literal, nliteral);
switch(bc->chiprev) {
case CHIPREV_R600:
r = r600_bc_alu_build(bc, alu, addr);
@@ -996,12 +2227,14 @@ int r600_bc_build(struct r600_bc *bc)
return r;
addr += 2;
if (alu->last) {
- addr += alu->nliteral;
+ for (i = 0; i < align(nliteral, 2); ++i) {
+ bc->bytecode[addr++] = literal[i];
+ }
+ nliteral = 0;
}
}
break;
- case V_SQ_CF_WORD1_SQ_CF_INST_VTX:
- case V_SQ_CF_WORD1_SQ_CF_INST_VTX_TC:
+ case CF_CLASS_VERTEX:
LIST_FOR_EACH_ENTRY(vtx, &cf->vtx, list) {
r = r600_bc_vtx_build(bc, vtx, addr);
if (r)
@@ -1009,7 +2242,7 @@ int r600_bc_build(struct r600_bc *bc)
addr += 4;
}
break;
- case V_SQ_CF_WORD1_SQ_CF_INST_TEX:
+ case CF_CLASS_TEXTURE:
LIST_FOR_EACH_ENTRY(tex, &cf->tex, list) {
r = r600_bc_tex_build(bc, tex, addr);
if (r)
@@ -1017,19 +2250,8 @@ int r600_bc_build(struct r600_bc *bc)
addr += 4;
}
break;
- case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT:
- case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT_DONE:
- case EG_V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT:
- case EG_V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT_DONE:
- case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_START_NO_AL:
- case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_END:
- case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_CONTINUE:
- case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_BREAK:
- case V_SQ_CF_WORD1_SQ_CF_INST_JUMP:
- case V_SQ_CF_WORD1_SQ_CF_INST_ELSE:
- case V_SQ_CF_WORD1_SQ_CF_INST_POP:
- case V_SQ_CF_WORD1_SQ_CF_INST_CALL_FS:
- case V_SQ_CF_WORD1_SQ_CF_INST_RETURN:
+ case CF_CLASS_EXPORT:
+ case CF_CLASS_OTHER:
break;
default:
R600_ERR("unsupported CF instruction (0x%X)\n", cf->inst);
@@ -1077,7 +2299,14 @@ void r600_bc_clear(struct r600_bc *bc)
void r600_bc_dump(struct r600_bc *bc)
{
- unsigned i;
+ struct r600_bc_cf *cf;
+ struct r600_bc_alu *alu;
+ struct r600_bc_vtx *vtx;
+ struct r600_bc_tex *tex;
+
+ unsigned i, id;
+ uint32_t literal[4];
+ unsigned nliteral;
char chip = '6';
switch (bc->chiprev) {
@@ -1092,11 +2321,124 @@ void r600_bc_dump(struct r600_bc *bc)
chip = '6';
break;
}
- fprintf(stderr, "bytecode %d dw -----------------------\n", bc->ndw);
+ fprintf(stderr, "bytecode %d dw -- %d gprs -----------------------\n", bc->ndw, bc->ngpr);
fprintf(stderr, " %c\n", chip);
- for (i = 0; i < bc->ndw; i++) {
- fprintf(stderr, "0x%08X\n", bc->bytecode[i]);
+
+ LIST_FOR_EACH_ENTRY(cf, &bc->cf, list) {
+ id = cf->id;
+
+ switch (get_cf_class(cf)) {
+ case CF_CLASS_ALU:
+ fprintf(stderr, "%04d %08X ALU ", id, bc->bytecode[id]);
+ fprintf(stderr, "ADDR:%04d ", cf->addr);
+ fprintf(stderr, "KCACHE_MODE0:%X ", cf->kcache0_mode);
+ fprintf(stderr, "KCACHE_BANK0:%X ", cf->kcache0_bank);
+ fprintf(stderr, "KCACHE_BANK1:%X\n", cf->kcache1_bank);
+ id++;
+ fprintf(stderr, "%04d %08X ALU ", id, bc->bytecode[id]);
+ fprintf(stderr, "INST:%d ", cf->inst);
+ fprintf(stderr, "KCACHE_MODE1:%X ", cf->kcache1_mode);
+ fprintf(stderr, "KCACHE_ADDR0:%X ", cf->kcache0_addr);
+ fprintf(stderr, "KCACHE_ADDR1:%X ", cf->kcache1_addr);
+ fprintf(stderr, "BARRIER:%d ", cf->barrier);
+ fprintf(stderr, "COUNT:%d\n", cf->ndw / 2);
+ break;
+ case CF_CLASS_TEXTURE:
+ case CF_CLASS_VERTEX:
+ fprintf(stderr, "%04d %08X TEX/VTX ", id, bc->bytecode[id]);
+ fprintf(stderr, "ADDR:%04d\n", cf->addr);
+ id++;
+ fprintf(stderr, "%04d %08X TEX/VTX ", id, bc->bytecode[id]);
+ fprintf(stderr, "INST:%d ", cf->inst);
+ fprintf(stderr, "BARRIER:%d ", cf->barrier);
+ fprintf(stderr, "COUNT:%d\n", cf->ndw / 4);
+ break;
+ case CF_CLASS_EXPORT:
+ fprintf(stderr, "%04d %08X EXPORT ", id, bc->bytecode[id]);
+ fprintf(stderr, "GPR:%d ", cf->output.gpr);
+ fprintf(stderr, "ELEM_SIZE:%X ", cf->output.elem_size);
+ fprintf(stderr, "ARRAY_BASE:%X ", cf->output.array_base);
+ fprintf(stderr, "TYPE:%X\n", cf->output.type);
+ id++;
+ fprintf(stderr, "%04d %08X EXPORT ", id, bc->bytecode[id]);
+ fprintf(stderr, "SWIZ_X:%X ", cf->output.swizzle_x);
+ fprintf(stderr, "SWIZ_Y:%X ", cf->output.swizzle_y);
+ fprintf(stderr, "SWIZ_Z:%X ", cf->output.swizzle_z);
+ fprintf(stderr, "SWIZ_W:%X ", cf->output.swizzle_w);
+ fprintf(stderr, "SWIZ_W:%X ", cf->output.swizzle_w);
+ fprintf(stderr, "BARRIER:%d ", cf->barrier);
+ fprintf(stderr, "INST:%d ", cf->inst);
+ fprintf(stderr, "BURST_COUNT:%d\n", cf->output.burst_count);
+ break;
+ case CF_CLASS_OTHER:
+ fprintf(stderr, "%04d %08X CF ", id, bc->bytecode[id]);
+ fprintf(stderr, "ADDR:%04d\n", cf->cf_addr);
+ id++;
+ fprintf(stderr, "%04d %08X CF ", id, bc->bytecode[id]);
+ fprintf(stderr, "INST:%d ", cf->inst);
+ fprintf(stderr, "COND:%X ", cf->cond);
+ fprintf(stderr, "BARRIER:%d ", cf->barrier);
+ fprintf(stderr, "POP_COUNT:%X\n", cf->pop_count);
+ break;
+ }
+
+ id = cf->addr;
+ nliteral = 0;
+ LIST_FOR_EACH_ENTRY(alu, &cf->alu, list) {
+ r600_bc_alu_nliterals(alu, literal, &nliteral);
+
+ fprintf(stderr, "%04d %08X ", id, bc->bytecode[id]);
+ fprintf(stderr, "SRC0(SEL:%d ", alu->src[0].sel);
+ fprintf(stderr, "REL:%d ", alu->src[0].rel);
+ fprintf(stderr, "CHAN:%d ", alu->src[0].chan);
+ fprintf(stderr, "NEG:%d) ", alu->src[0].neg);
+ fprintf(stderr, "SRC1(SEL:%d ", alu->src[1].sel);
+ fprintf(stderr, "REL:%d ", alu->src[1].rel);
+ fprintf(stderr, "CHAN:%d ", alu->src[1].chan);
+ fprintf(stderr, "NEG:%d) ", alu->src[1].neg);
+ fprintf(stderr, "LAST:%d)\n", alu->last);
+ id++;
+ fprintf(stderr, "%04d %08X %c ", id, bc->bytecode[id], alu->last ? '*' : ' ');
+ fprintf(stderr, "INST:%d ", alu->inst);
+ fprintf(stderr, "DST(SEL:%d ", alu->dst.sel);
+ fprintf(stderr, "CHAN:%d ", alu->dst.chan);
+ fprintf(stderr, "REL:%d ", alu->dst.rel);
+ fprintf(stderr, "CLAMP:%d) ", alu->dst.clamp);
+ fprintf(stderr, "BANK_SWIZZLE:%d ", alu->bank_swizzle);
+ if (alu->is_op3) {
+ fprintf(stderr, "SRC2(SEL:%d ", alu->src[2].sel);
+ fprintf(stderr, "REL:%d ", alu->src[2].rel);
+ fprintf(stderr, "CHAN:%d ", alu->src[2].chan);
+ fprintf(stderr, "NEG:%d)\n", alu->src[2].neg);
+ } else {
+ fprintf(stderr, "SRC0_ABS:%d ", alu->src[0].abs);
+ fprintf(stderr, "SRC1_ABS:%d ", alu->src[1].abs);
+ fprintf(stderr, "WRITE_MASK:%d ", alu->dst.write);
+ fprintf(stderr, "OMOD:%d ", alu->omod);
+ fprintf(stderr, "EXECUTE_MASK:%d ", alu->predicate);
+ fprintf(stderr, "UPDATE_PRED:%d\n", alu->predicate);
+ }
+
+ id++;
+ if (alu->last) {
+ for (i = 0; i < nliteral; i++, id++) {
+ float *f = (float*)(bc->bytecode + id);
+ fprintf(stderr, "%04d %08X %f\n", id, bc->bytecode[id], *f);
+ }
+ id += nliteral & 1;
+ nliteral = 0;
+ }
+ }
+
+ LIST_FOR_EACH_ENTRY(tex, &cf->tex, list) {
+ //TODO
+ }
+
+ LIST_FOR_EACH_ENTRY(vtx, &cf->vtx, list) {
+ //TODO
+ }
}
+
fprintf(stderr, "--------------------------------------\n");
}
@@ -1108,21 +2450,21 @@ void r600_cf_vtx(struct r600_vertex_element *ve, u32 *bytecode, unsigned count)
if (count > 8) {
bytecode[i++] = S_SQ_CF_WORD0_ADDR(8 >> 1);
bytecode[i++] = S_SQ_CF_WORD1_CF_INST(V_SQ_CF_WORD1_SQ_CF_INST_VTX) |
- S_SQ_CF_WORD1_BARRIER(1) |
+ S_SQ_CF_WORD1_BARRIER(0) |
S_SQ_CF_WORD1_COUNT(8 - 1);
bytecode[i++] = S_SQ_CF_WORD0_ADDR(40 >> 1);
bytecode[i++] = S_SQ_CF_WORD1_CF_INST(V_SQ_CF_WORD1_SQ_CF_INST_VTX) |
- S_SQ_CF_WORD1_BARRIER(1) |
+ S_SQ_CF_WORD1_BARRIER(0) |
S_SQ_CF_WORD1_COUNT(count - 8 - 1);
} else {
bytecode[i++] = S_SQ_CF_WORD0_ADDR(8 >> 1);
bytecode[i++] = S_SQ_CF_WORD1_CF_INST(V_SQ_CF_WORD1_SQ_CF_INST_VTX) |
- S_SQ_CF_WORD1_BARRIER(1) |
+ S_SQ_CF_WORD1_BARRIER(0) |
S_SQ_CF_WORD1_COUNT(count - 1);
}
bytecode[i++] = S_SQ_CF_WORD0_ADDR(0);
bytecode[i++] = S_SQ_CF_WORD1_CF_INST(V_SQ_CF_WORD1_SQ_CF_INST_RETURN) |
- S_SQ_CF_WORD1_BARRIER(1);
+ S_SQ_CF_WORD1_BARRIER(0);
rstate = &ve->rstate;
rstate->id = R600_PIPE_STATE_FETCH_SHADER;
@@ -1144,21 +2486,21 @@ void r600_cf_vtx_tc(struct r600_vertex_element *ve, u32 *bytecode, unsigned coun
if (count > 8) {
bytecode[i++] = S_SQ_CF_WORD0_ADDR(8 >> 1);
bytecode[i++] = S_SQ_CF_WORD1_CF_INST(V_SQ_CF_WORD1_SQ_CF_INST_VTX_TC) |
- S_SQ_CF_WORD1_BARRIER(1) |
+ S_SQ_CF_WORD1_BARRIER(0) |
S_SQ_CF_WORD1_COUNT(8 - 1);
bytecode[i++] = S_SQ_CF_WORD0_ADDR(40 >> 1);
bytecode[i++] = S_SQ_CF_WORD1_CF_INST(V_SQ_CF_WORD1_SQ_CF_INST_VTX_TC) |
- S_SQ_CF_WORD1_BARRIER(1) |
+ S_SQ_CF_WORD1_BARRIER(0) |
S_SQ_CF_WORD1_COUNT((count - 8) - 1);
} else {
bytecode[i++] = S_SQ_CF_WORD0_ADDR(8 >> 1);
bytecode[i++] = S_SQ_CF_WORD1_CF_INST(V_SQ_CF_WORD1_SQ_CF_INST_VTX_TC) |
- S_SQ_CF_WORD1_BARRIER(1) |
+ S_SQ_CF_WORD1_BARRIER(0) |
S_SQ_CF_WORD1_COUNT(count - 1);
}
bytecode[i++] = S_SQ_CF_WORD0_ADDR(0);
bytecode[i++] = S_SQ_CF_WORD1_CF_INST(V_SQ_CF_WORD1_SQ_CF_INST_RETURN) |
- S_SQ_CF_WORD1_BARRIER(1);
+ S_SQ_CF_WORD1_BARRIER(0);
rstate = &ve->rstate;
rstate->id = R600_PIPE_STATE_FETCH_SHADER;
@@ -1308,31 +2650,6 @@ out_unknown:
R600_ERR("unsupported vertex format %s\n", util_format_name(pformat));
}
-static void r600_bc(unsigned ndw, unsigned chiprev, u32 *bytecode)
-{
- unsigned i;
- char chip = '6';
-
- switch (chiprev) {
- case 1:
- chip = '7';
- break;
- case 2:
- chip = 'E';
- break;
- case 0:
- default:
- chip = '6';
- break;
- }
- fprintf(stderr, "bytecode %d dw -----------------------\n", ndw);
- fprintf(stderr, " %c\n", chip);
- for (i = 0; i < ndw; i++) {
- fprintf(stderr, "0x%08X\n", bytecode[i]);
- }
- fprintf(stderr, "--------------------------------------\n");
-}
-
int r600_vertex_elements_build_fetch_shader(struct r600_pipe_context *rctx, struct r600_vertex_element *ve)
{
unsigned ndw, i;
diff --git a/src/gallium/drivers/r600/r600_asm.h b/src/gallium/drivers/r600/r600_asm.h
index a5504ad39f4..519245f3af2 100644
--- a/src/gallium/drivers/r600/r600_asm.h
+++ b/src/gallium/drivers/r600/r600_asm.h
@@ -25,9 +25,6 @@
#include "util/u_double_list.h"
-#define NUM_OF_CYCLES 3
-#define NUM_OF_COMPONENTS 4
-
struct r600_vertex_element;
struct r600_pipe_context;
@@ -37,6 +34,7 @@ struct r600_bc_alu_src {
unsigned neg;
unsigned abs;
unsigned rel;
+ u32 *value;
};
struct r600_bc_alu_dst {
@@ -49,19 +47,15 @@ struct r600_bc_alu_dst {
struct r600_bc_alu {
struct list_head list;
- struct list_head bs_list; /* bank swizzle list */
struct r600_bc_alu_src src[3];
struct r600_bc_alu_dst dst;
unsigned inst;
unsigned last;
unsigned is_op3;
unsigned predicate;
- unsigned nliteral;
- unsigned literal_added;
unsigned bank_swizzle;
unsigned bank_swizzle_force;
- u32 value[4];
- int hw_gpr[NUM_OF_CYCLES][NUM_OF_COMPONENTS];
+ unsigned omod;
};
struct r600_bc_tex {
@@ -114,15 +108,13 @@ struct r600_bc_vtx {
struct r600_bc_output {
unsigned array_base;
unsigned type;
- unsigned end_of_program;
- unsigned inst;
unsigned elem_size;
unsigned gpr;
unsigned swizzle_x;
unsigned swizzle_y;
unsigned swizzle_z;
unsigned swizzle_w;
- unsigned barrier;
+ unsigned burst_count;
};
struct r600_bc_kcache {
@@ -140,6 +132,7 @@ struct r600_bc_cf {
unsigned cond;
unsigned pop_count;
unsigned cf_addr; /* control flow addr */
+ unsigned barrier;
struct r600_bc_kcache kcache[2];
unsigned r6xx_uses_waterfall;
struct list_head alu;
@@ -147,6 +140,8 @@ struct r600_bc_cf {
struct list_head vtx;
struct r600_bc_output output;
struct r600_bc_alu *curr_bs_head;
+ struct r600_bc_alu *prev_bs_head;
+ struct r600_bc_alu *prev2_bs_head;
};
#define FC_NONE 0
@@ -198,13 +193,13 @@ void eg_cf_vtx(struct r600_vertex_element *ve, u32 *bytecode, unsigned count);
int r600_bc_init(struct r600_bc *bc, enum radeon_family family);
void r600_bc_clear(struct r600_bc *bc);
int r600_bc_add_alu(struct r600_bc *bc, const struct r600_bc_alu *alu);
-int r600_bc_add_literal(struct r600_bc *bc, const u32 *value);
int r600_bc_add_vtx(struct r600_bc *bc, const struct r600_bc_vtx *vtx);
int r600_bc_add_tex(struct r600_bc *bc, const struct r600_bc_tex *tex);
int r600_bc_add_output(struct r600_bc *bc, const struct r600_bc_output *output);
int r600_bc_build(struct r600_bc *bc);
int r600_bc_add_cfinst(struct r600_bc *bc, int inst);
int r600_bc_add_alu_type(struct r600_bc *bc, const struct r600_bc_alu *alu, int type);
+void r600_bc_special_constants(u32 value, unsigned *sel, unsigned *neg);
void r600_bc_dump(struct r600_bc *bc);
void r600_cf_vtx(struct r600_vertex_element *ve, u32 *bytecode, unsigned count);
void r600_cf_vtx_tc(struct r600_vertex_element *ve, u32 *bytecode, unsigned count);
diff --git a/src/gallium/drivers/r600/r600_pipe.c b/src/gallium/drivers/r600/r600_pipe.c
index 20838e4d98f..ad14dbe14f4 100644
--- a/src/gallium/drivers/r600/r600_pipe.c
+++ b/src/gallium/drivers/r600/r600_pipe.c
@@ -42,6 +42,7 @@
#include "r600_shader.h"
#include "r600_pipe.h"
#include "r600_state_inlines.h"
+#include "r600_video_context.h"
/*
* pipe_context
@@ -483,6 +484,7 @@ struct pipe_screen *r600_screen_create(struct radeon *radeon)
rscreen->screen.get_paramf = r600_get_paramf;
rscreen->screen.is_format_supported = r600_is_format_supported;
rscreen->screen.context_create = r600_create_context;
+ rscreen->screen.video_context_create = r600_video_create;
r600_init_screen_resource_functions(&rscreen->screen);
rscreen->tiling_info = r600_get_tiling_info(radeon);
diff --git a/src/gallium/drivers/r600/r600_shader.c b/src/gallium/drivers/r600/r600_shader.c
index 51ff7db3612..95367d7c536 100644
--- a/src/gallium/drivers/r600/r600_shader.c
+++ b/src/gallium/drivers/r600/r600_shader.c
@@ -225,21 +225,23 @@ int r600_pipe_shader(struct pipe_context *ctx, struct r600_pipe_shader *shader)
return 0;
}
-int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_shader *shader);
+int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_shader *shader, u32 **literals);
int r600_pipe_shader_create(struct pipe_context *ctx, struct r600_pipe_shader *shader, const struct tgsi_token *tokens)
{
struct r600_pipe_context *rctx = (struct r600_pipe_context *)ctx;
+ u32 *literals;
int r;
//fprintf(stderr, "--------------------------------------------------------------\n");
//tgsi_dump(tokens, 0);
shader->shader.family = r600_get_family(rctx->radeon);
- r = r600_shader_from_tgsi(tokens, &shader->shader);
+ r = r600_shader_from_tgsi(tokens, &shader->shader, &literals);
if (r) {
R600_ERR("translation from TGSI failed !\n");
return r;
}
r = r600_bc_build(&shader->shader.bc);
+ free(literals);
if (r) {
R600_ERR("building bytecode failed !\n");
return r;
@@ -272,7 +274,6 @@ struct r600_shader_ctx {
struct r600_shader_tgsi_instruction *inst_info;
struct r600_bc *bc;
struct r600_shader *shader;
- u32 value[4];
u32 *literals;
u32 nliterals;
u32 max_driver_temp_used;
@@ -481,12 +482,12 @@ static int evergreen_gpr_count(struct r600_shader_ctx *ctx)
return ctx->num_interp_gpr;
}
-int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_shader *shader)
+int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_shader *shader, u32 **literals)
{
struct tgsi_full_immediate *immediate;
struct r600_shader_ctx ctx;
struct r600_bc_output output[32];
- unsigned output_done, noutput;
+ unsigned noutput;
unsigned opcode;
int i, r = 0, pos0;
@@ -546,7 +547,7 @@ int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_shader *s
* kcache banks later. */
ctx.file_offset[TGSI_FILE_CONSTANT] = 512;
- ctx.file_offset[TGSI_FILE_IMMEDIATE] = 253;
+ ctx.file_offset[TGSI_FILE_IMMEDIATE] = V_SQ_ALU_SRC_LITERAL;
ctx.temp_reg = ctx.file_offset[TGSI_FILE_TEMPORARY] +
ctx.info.file_count[TGSI_FILE_TEMPORARY];
@@ -589,9 +590,6 @@ int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_shader *s
r = ctx.inst_info->process(&ctx);
if (r)
goto out_err;
- r = r600_bc_add_literal(ctx.bc, ctx.value);
- if (r)
- goto out_err;
break;
case TGSI_TOKEN_TYPE_PROPERTY:
break;
@@ -611,10 +609,8 @@ int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_shader *s
output[i].swizzle_y = 1;
output[i].swizzle_z = 2;
output[i].swizzle_w = 3;
- output[i].barrier = 1;
output[i].type = V_SQ_CF_ALLOC_EXPORT_WORD0_SQ_EXPORT_PARAM;
output[i].array_base = i - pos0;
- output[i].inst = BC_INST(ctx.bc, V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT);
switch (ctx.type) {
case TGSI_PROCESSOR_VERTEX:
if (shader->output[i].name == TGSI_SEMANTIC_POSITION) {
@@ -674,10 +670,8 @@ int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_shader *s
output[i].swizzle_y = 1;
output[i].swizzle_z = 2;
output[i].swizzle_w = 3;
- output[i].barrier = 1;
output[i].type = V_SQ_CF_ALLOC_EXPORT_WORD0_SQ_EXPORT_PARAM;
output[i].array_base = 0;
- output[i].inst = BC_INST(ctx.bc, V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT);
noutput++;
}
}
@@ -690,29 +684,17 @@ int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_shader *s
output[0].swizzle_y = 7;
output[0].swizzle_z = 7;
output[0].swizzle_w = 7;
- output[0].barrier = 1;
output[0].type = V_SQ_CF_ALLOC_EXPORT_WORD0_SQ_EXPORT_PIXEL;
output[0].array_base = 0;
- output[0].inst = BC_INST(ctx.bc, V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT);
noutput++;
}
- /* set export done on last export of each type */
- for (i = noutput - 1, output_done = 0; i >= 0; i--) {
- if (i == (noutput - 1)) {
- output[i].end_of_program = 1;
- }
- if (!(output_done & (1 << output[i].type))) {
- output_done |= (1 << output[i].type);
- output[i].inst = BC_INST(ctx.bc, V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT_DONE);
- }
- }
/* add output to bytecode */
for (i = 0; i < noutput; i++) {
r = r600_bc_add_output(ctx.bc, &output[i]);
if (r)
goto out_err;
}
- free(ctx.literals);
+ *literals = ctx.literals;
tgsi_parse_free(&ctx.parse);
return 0;
out_err:
@@ -736,22 +718,29 @@ static int tgsi_src(struct r600_shader_ctx *ctx,
const struct tgsi_full_src_register *tgsi_src,
struct r600_bc_alu_src *r600_src)
{
- int index;
memset(r600_src, 0, sizeof(struct r600_bc_alu_src));
- r600_src->sel = tgsi_src->Register.Index;
+ r600_src->neg = tgsi_src->Register.Negate;
+ r600_src->abs = tgsi_src->Register.Absolute;
if (tgsi_src->Register.File == TGSI_FILE_IMMEDIATE) {
- r600_src->sel = 0;
+ int index;
+ if((tgsi_src->Register.SwizzleX == tgsi_src->Register.SwizzleY) &&
+ (tgsi_src->Register.SwizzleX == tgsi_src->Register.SwizzleZ) &&
+ (tgsi_src->Register.SwizzleX == tgsi_src->Register.SwizzleW)) {
+
+ index = tgsi_src->Register.Index * 4 + tgsi_src->Register.SwizzleX;
+ r600_bc_special_constants(ctx->literals[index], &r600_src->sel, &r600_src->neg);
+ if (r600_src->sel != V_SQ_ALU_SRC_LITERAL)
+ return 0;
+ }
index = tgsi_src->Register.Index;
- ctx->value[0] = ctx->literals[index * 4 + 0];
- ctx->value[1] = ctx->literals[index * 4 + 1];
- ctx->value[2] = ctx->literals[index * 4 + 2];
- ctx->value[3] = ctx->literals[index * 4 + 3];
+ r600_src->sel = V_SQ_ALU_SRC_LITERAL;
+ r600_src->value = ctx->literals + index * 4;
+ } else {
+ if (tgsi_src->Register.Indirect)
+ r600_src->rel = V_SQ_REL_RELATIVE;
+ r600_src->sel = tgsi_src->Register.Index;
+ r600_src->sel += ctx->file_offset[tgsi_src->Register.File];
}
- if (tgsi_src->Register.Indirect)
- r600_src->rel = V_SQ_REL_RELATIVE;
- r600_src->neg = tgsi_src->Register.Negate;
- r600_src->abs = tgsi_src->Register.Absolute;
- r600_src->sel += ctx->file_offset[tgsi_src->Register.File];
return 0;
}
@@ -839,18 +828,19 @@ static int tgsi_split_literal_constant(struct r600_shader_ctx *ctx, struct r600_
int i, j, k, nliteral, r;
for (i = 0, nliteral = 0; i < inst->Instruction.NumSrcRegs; i++) {
- if (inst->Src[i].Register.File == TGSI_FILE_IMMEDIATE) {
+ if (r600_src[i].sel == V_SQ_ALU_SRC_LITERAL) {
nliteral++;
}
}
for (i = 0, j = nliteral - 1; i < inst->Instruction.NumSrcRegs; i++) {
- if (j > 0 && inst->Src[i].Register.File == TGSI_FILE_IMMEDIATE) {
+ if (j > 0 && r600_src[i].sel == V_SQ_ALU_SRC_LITERAL) {
int treg = r600_get_temp(ctx);
for (k = 0; k < 4; k++) {
memset(&alu, 0, sizeof(struct r600_bc_alu));
alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV);
alu.src[0].sel = r600_src[i].sel;
alu.src[0].chan = k;
+ alu.src[0].value = r600_src[i].value;
alu.dst.sel = treg;
alu.dst.chan = k;
alu.dst.write = 1;
@@ -860,9 +850,6 @@ static int tgsi_split_literal_constant(struct r600_shader_ctx *ctx, struct r600_
if (r)
return r;
}
- r = r600_bc_add_literal(ctx->bc, &ctx->literals[inst->Src[i].Register.Index * 4]);
- if (r)
- return r;
r600_src[i].sel = treg;
j--;
}
@@ -870,19 +857,25 @@ static int tgsi_split_literal_constant(struct r600_shader_ctx *ctx, struct r600_
return 0;
}
-static int tgsi_op2_s(struct r600_shader_ctx *ctx, int swap)
+static int tgsi_last_instruction(unsigned writemask)
{
- struct tgsi_full_instruction *inst = &ctx->parse.FullToken.FullInstruction;
- struct r600_bc_alu_src r600_src[3];
- struct r600_bc_alu alu;
- int i, j, r;
- int lasti = 0;
+ int i, lasti = 0;
for (i = 0; i < 4; i++) {
- if (inst->Dst[0].Register.WriteMask & (1 << i)) {
+ if (writemask & (1 << i)) {
lasti = i;
}
}
+ return lasti;
+}
+
+static int tgsi_op2_s(struct r600_shader_ctx *ctx, int swap)
+{
+ struct tgsi_full_instruction *inst = &ctx->parse.FullToken.FullInstruction;
+ struct r600_bc_alu_src r600_src[3];
+ struct r600_bc_alu alu;
+ int i, j, r;
+ int lasti = tgsi_last_instruction(inst->Dst[0].Register.WriteMask);
r = tgsi_split_constant(ctx, r600_src);
if (r)
@@ -951,12 +944,14 @@ static int tgsi_op2_swap(struct r600_shader_ctx *ctx)
static int tgsi_setup_trig(struct r600_shader_ctx *ctx,
struct r600_bc_alu_src r600_src[3])
{
+ static float half_inv_pi = 1.0 /(3.1415926535 * 2);
+ static float double_pi = 3.1415926535 * 2;
+ static float neg_pi = -3.1415926535;
+
struct tgsi_full_instruction *inst = &ctx->parse.FullToken.FullInstruction;
int r;
- uint32_t lit_vals[4];
struct r600_bc_alu alu;
- memset(lit_vals, 0, 4*4);
r = tgsi_split_constant(ctx, r600_src);
if (r)
return r;
@@ -964,9 +959,6 @@ static int tgsi_setup_trig(struct r600_shader_ctx *ctx,
if (r)
return r;
- lit_vals[0] = fui(1.0 /(3.1415926535 * 2));
- lit_vals[1] = fui(0.5f);
-
memset(&alu, 0, sizeof(struct r600_bc_alu));
alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_MULADD);
alu.is_op3 = 1;
@@ -980,15 +972,13 @@ static int tgsi_setup_trig(struct r600_shader_ctx *ctx,
alu.src[1].sel = V_SQ_ALU_SRC_LITERAL;
alu.src[1].chan = 0;
- alu.src[2].sel = V_SQ_ALU_SRC_LITERAL;
+ alu.src[1].value = (uint32_t *)&half_inv_pi;
+ alu.src[2].sel = V_SQ_ALU_SRC_0_5;
alu.src[2].chan = 1;
alu.last = 1;
r = r600_bc_add_alu(ctx->bc, &alu);
if (r)
return r;
- r = r600_bc_add_literal(ctx->bc, lit_vals);
- if (r)
- return r;
memset(&alu, 0, sizeof(struct r600_bc_alu));
alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_FRACT);
@@ -1004,14 +994,6 @@ static int tgsi_setup_trig(struct r600_shader_ctx *ctx,
if (r)
return r;
- if (ctx->bc->chiprev == CHIPREV_R600) {
- lit_vals[0] = fui(3.1415926535897f * 2.0f);
- lit_vals[1] = fui(-3.1415926535897f);
- } else {
- lit_vals[0] = fui(1.0f);
- lit_vals[1] = fui(-0.5f);
- }
-
memset(&alu, 0, sizeof(struct r600_bc_alu));
alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_MULADD);
alu.is_op3 = 1;
@@ -1027,13 +1009,20 @@ static int tgsi_setup_trig(struct r600_shader_ctx *ctx,
alu.src[1].chan = 0;
alu.src[2].sel = V_SQ_ALU_SRC_LITERAL;
alu.src[2].chan = 1;
+
+ if (ctx->bc->chiprev == CHIPREV_R600) {
+ alu.src[1].value = (uint32_t *)&double_pi;
+ alu.src[2].value = (uint32_t *)&neg_pi;
+ } else {
+ alu.src[1].sel = V_SQ_ALU_SRC_1;
+ alu.src[2].sel = V_SQ_ALU_SRC_0_5;
+ alu.src[2].neg = 1;
+ }
+
alu.last = 1;
r = r600_bc_add_alu(ctx->bc, &alu);
if (r)
return r;
- r = r600_bc_add_literal(ctx->bc, lit_vals);
- if (r)
- return r;
return 0;
}
@@ -1043,7 +1032,7 @@ static int tgsi_trig(struct r600_shader_ctx *ctx)
struct r600_bc_alu_src r600_src[3];
struct r600_bc_alu alu;
int i, r;
- int lasti = 0;
+ int lasti = tgsi_last_instruction(inst->Dst[0].Register.WriteMask);
r = tgsi_setup_trig(ctx, r600_src);
if (r)
@@ -1063,10 +1052,6 @@ static int tgsi_trig(struct r600_shader_ctx *ctx)
return r;
/* replicate result */
- for (i = 0; i < 4; i++) {
- if (inst->Dst[0].Register.WriteMask & (1 << i))
- lasti = i;
- }
for (i = 0; i < lasti + 1; i++) {
if (!(inst->Dst[0].Register.WriteMask & (1 << i)))
continue;
@@ -1153,10 +1138,6 @@ static int tgsi_scs(struct r600_shader_ctx *ctx)
r = r600_bc_add_alu(ctx->bc, &alu);
if (r)
return r;
-
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
}
/* dst.w = 1.0; */
@@ -1177,10 +1158,6 @@ static int tgsi_scs(struct r600_shader_ctx *ctx)
r = r600_bc_add_alu(ctx->bc, &alu);
if (r)
return r;
-
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
}
return 0;
@@ -1216,9 +1193,6 @@ static int tgsi_kill(struct r600_shader_ctx *ctx)
if (r)
return r;
}
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
/* kill must be last in ALU */
ctx->bc->force_add_cf = 1;
@@ -1281,10 +1255,6 @@ static int tgsi_lit(struct r600_shader_ctx *ctx)
if (r)
return r;
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
-
if (inst->Dst[0].Register.WriteMask & (1 << 2))
{
int chan;
@@ -1303,10 +1273,6 @@ static int tgsi_lit(struct r600_shader_ctx *ctx)
if (r)
return r;
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
-
chan = alu.dst.chan;
sel = alu.dst.sel;
@@ -1329,9 +1295,6 @@ static int tgsi_lit(struct r600_shader_ctx *ctx)
if (r)
return r;
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
/* dst.z = exp(tmp.x) */
memset(&alu, 0, sizeof(struct r600_bc_alu));
alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_EXP_IEEE);
@@ -1375,9 +1338,6 @@ static int tgsi_rsq(struct r600_shader_ctx *ctx)
r = r600_bc_add_alu(ctx->bc, &alu);
if (r)
return r;
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
/* replicate result */
return tgsi_helper_tempx_replicate(ctx);
}
@@ -1426,9 +1386,6 @@ static int tgsi_trans_srcx_replicate(struct r600_shader_ctx *ctx)
r = r600_bc_add_alu(ctx->bc, &alu);
if (r)
return r;
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
/* replicate result */
return tgsi_helper_tempx_replicate(ctx);
}
@@ -1452,9 +1409,6 @@ static int tgsi_pow(struct r600_shader_ctx *ctx)
r = r600_bc_add_alu(ctx->bc, &alu);
if (r)
return r;
- r = r600_bc_add_literal(ctx->bc,ctx->value);
- if (r)
- return r;
/* b * LOG2(a) */
memset(&alu, 0, sizeof(struct r600_bc_alu));
alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MUL);
@@ -1469,9 +1423,6 @@ static int tgsi_pow(struct r600_shader_ctx *ctx)
r = r600_bc_add_alu(ctx->bc, &alu);
if (r)
return r;
- r = r600_bc_add_literal(ctx->bc,ctx->value);
- if (r)
- return r;
/* POW(a,b) = EXP2(b * LOG2(a))*/
memset(&alu, 0, sizeof(struct r600_bc_alu));
alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_EXP_IEEE);
@@ -1482,9 +1433,6 @@ static int tgsi_pow(struct r600_shader_ctx *ctx)
r = r600_bc_add_alu(ctx->bc, &alu);
if (r)
return r;
- r = r600_bc_add_literal(ctx->bc,ctx->value);
- if (r)
- return r;
return tgsi_helper_tempx_replicate(ctx);
}
@@ -1524,9 +1472,6 @@ static int tgsi_ssg(struct r600_shader_ctx *ctx)
if (r)
return r;
}
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
/* dst = (-tmp > 0 ? -1 : tmp) */
for (i = 0; i < 4; i++) {
@@ -1561,9 +1506,6 @@ static int tgsi_helper_copy(struct r600_shader_ctx *ctx, struct tgsi_full_instru
struct r600_bc_alu alu;
int i, r;
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
for (i = 0; i < 4; i++) {
memset(&alu, 0, sizeof(struct r600_bc_alu));
if (!(inst->Dst[0].Register.WriteMask & (1 << i))) {
@@ -1593,6 +1535,7 @@ static int tgsi_op3(struct r600_shader_ctx *ctx)
struct r600_bc_alu_src r600_src[3];
struct r600_bc_alu alu;
int i, j, r;
+ int lasti = tgsi_last_instruction(inst->Dst[0].Register.WriteMask);
r = tgsi_split_constant(ctx, r600_src);
if (r)
@@ -1600,26 +1543,32 @@ static int tgsi_op3(struct r600_shader_ctx *ctx)
r = tgsi_split_literal_constant(ctx, r600_src);
if (r)
return r;
- /* do it in 2 step as op3 doesn't support writemask */
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < lasti + 1; i++) {
+ if (!(inst->Dst[0].Register.WriteMask & (1 << i)))
+ continue;
+
memset(&alu, 0, sizeof(struct r600_bc_alu));
alu.inst = ctx->inst_info->r600_opcode;
for (j = 0; j < inst->Instruction.NumSrcRegs; j++) {
alu.src[j] = r600_src[j];
alu.src[j].chan = tgsi_chan(&inst->Src[j], i);
}
- alu.dst.sel = ctx->temp_reg;
+
+ r = tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst);
+ if (r)
+ return r;
+
alu.dst.chan = i;
alu.dst.write = 1;
alu.is_op3 = 1;
- if (i == 3) {
+ if (i == lasti) {
alu.last = 1;
}
r = r600_bc_add_alu(ctx->bc, &alu);
if (r)
return r;
}
- return tgsi_helper_copy(ctx, inst);
+ return 0;
}
static int tgsi_dp(struct r600_shader_ctx *ctx)
@@ -1642,9 +1591,13 @@ static int tgsi_dp(struct r600_shader_ctx *ctx)
alu.src[j] = r600_src[j];
alu.src[j].chan = tgsi_chan(&inst->Src[j], i);
}
- alu.dst.sel = ctx->temp_reg;
+
+ r = tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst);
+ if (r)
+ return r;
+
alu.dst.chan = i;
- alu.dst.write = 1;
+ alu.dst.write = (inst->Dst[0].Register.WriteMask >> i) & 1;
/* handle some special cases */
switch (ctx->inst_info->tgsi_opcode) {
case TGSI_OPCODE_DP2:
@@ -1676,19 +1629,21 @@ static int tgsi_dp(struct r600_shader_ctx *ctx)
if (r)
return r;
}
- return tgsi_helper_copy(ctx, inst);
+ return 0;
}
static int tgsi_tex(struct r600_shader_ctx *ctx)
{
+ static float one_point_five = 1.5f;
struct tgsi_full_instruction *inst = &ctx->parse.FullToken.FullInstruction;
struct r600_bc_tex tex;
struct r600_bc_alu alu;
unsigned src_gpr;
int r, i;
int opcode;
- boolean src_not_temp = inst->Src[0].Register.File != TGSI_FILE_TEMPORARY;
- uint32_t lit_vals[4];
+ boolean src_not_temp =
+ inst->Src[0].Register.File != TGSI_FILE_TEMPORARY &&
+ inst->Src[0].Register.File != TGSI_FILE_INPUT;
src_gpr = ctx->file_offset[inst->Src[0].Register.File] + inst->Src[0].Register.Index;
@@ -1837,6 +1792,7 @@ static int tgsi_tex(struct r600_shader_ctx *ctx)
alu.src[2].sel = V_SQ_ALU_SRC_LITERAL;
alu.src[2].chan = 0;
+ alu.src[2].value = (u32*)&one_point_five;
alu.dst.sel = ctx->temp_reg;
alu.dst.chan = 1;
@@ -1847,11 +1803,6 @@ static int tgsi_tex(struct r600_shader_ctx *ctx)
if (r)
return r;
- lit_vals[0] = fui(1.5f);
-
- r = r600_bc_add_literal(ctx->bc, lit_vals);
- if (r)
- return r;
src_not_temp = FALSE;
src_gpr = ctx->temp_reg;
}
@@ -1924,6 +1875,7 @@ static int tgsi_lrp(struct r600_shader_ctx *ctx)
struct tgsi_full_instruction *inst = &ctx->parse.FullToken.FullInstruction;
struct r600_bc_alu_src r600_src[3];
struct r600_bc_alu alu;
+ int lasti = tgsi_last_instruction(inst->Dst[0].Register.WriteMask);
unsigned i;
int r;
@@ -1933,8 +1885,40 @@ static int tgsi_lrp(struct r600_shader_ctx *ctx)
r = tgsi_split_literal_constant(ctx, r600_src);
if (r)
return r;
+
+ /* optimize if it's just an equal balance */
+ if(r600_src[0].sel == V_SQ_ALU_SRC_0_5) {
+ for (i = 0; i < lasti + 1; i++) {
+ if (!(inst->Dst[0].Register.WriteMask & (1 << i)))
+ continue;
+
+ memset(&alu, 0, sizeof(struct r600_bc_alu));
+ alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_ADD);
+ alu.src[0] = r600_src[1];
+ alu.src[0].chan = tgsi_chan(&inst->Src[1], i);
+ alu.src[1] = r600_src[2];
+ alu.src[1].chan = tgsi_chan(&inst->Src[2], i);
+ alu.omod = 3;
+ r = tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst);
+ if (r)
+ return r;
+
+ alu.dst.chan = i;
+ if (i == lasti) {
+ alu.last = 1;
+ }
+ r = r600_bc_add_alu(ctx->bc, &alu);
+ if (r)
+ return r;
+ }
+ return 0;
+ }
+
/* 1 - src0 */
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < lasti + 1; i++) {
+ if (!(inst->Dst[0].Register.WriteMask & (1 << i)))
+ continue;
+
memset(&alu, 0, sizeof(struct r600_bc_alu));
alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_ADD);
alu.src[0].sel = V_SQ_ALU_SRC_1;
@@ -1944,7 +1928,7 @@ static int tgsi_lrp(struct r600_shader_ctx *ctx)
alu.src[1].neg = 1;
alu.dst.sel = ctx->temp_reg;
alu.dst.chan = i;
- if (i == 3) {
+ if (i == lasti) {
alu.last = 1;
}
alu.dst.write = 1;
@@ -1952,12 +1936,12 @@ static int tgsi_lrp(struct r600_shader_ctx *ctx)
if (r)
return r;
}
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
/* (1 - src0) * src2 */
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < lasti + 1; i++) {
+ if (!(inst->Dst[0].Register.WriteMask & (1 << i)))
+ continue;
+
memset(&alu, 0, sizeof(struct r600_bc_alu));
alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MUL);
alu.src[0].sel = ctx->temp_reg;
@@ -1966,7 +1950,7 @@ static int tgsi_lrp(struct r600_shader_ctx *ctx)
alu.src[1].chan = tgsi_chan(&inst->Src[2], i);
alu.dst.sel = ctx->temp_reg;
alu.dst.chan = i;
- if (i == 3) {
+ if (i == lasti) {
alu.last = 1;
}
alu.dst.write = 1;
@@ -1974,12 +1958,12 @@ static int tgsi_lrp(struct r600_shader_ctx *ctx)
if (r)
return r;
}
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
/* src0 * src1 + (1 - src0) * src2 */
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < lasti + 1; i++) {
+ if (!(inst->Dst[0].Register.WriteMask & (1 << i)))
+ continue;
+
memset(&alu, 0, sizeof(struct r600_bc_alu));
alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_MULADD);
alu.is_op3 = 1;
@@ -1989,16 +1973,20 @@ static int tgsi_lrp(struct r600_shader_ctx *ctx)
alu.src[1].chan = tgsi_chan(&inst->Src[1], i);
alu.src[2].sel = ctx->temp_reg;
alu.src[2].chan = i;
- alu.dst.sel = ctx->temp_reg;
+
+ r = tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst);
+ if (r)
+ return r;
+
alu.dst.chan = i;
- if (i == 3) {
+ if (i == lasti) {
alu.last = 1;
}
r = r600_bc_add_alu(ctx->bc, &alu);
if (r)
return r;
}
- return tgsi_helper_copy(ctx, inst);
+ return 0;
}
static int tgsi_cmp(struct r600_shader_ctx *ctx)
@@ -2006,8 +1994,8 @@ static int tgsi_cmp(struct r600_shader_ctx *ctx)
struct tgsi_full_instruction *inst = &ctx->parse.FullToken.FullInstruction;
struct r600_bc_alu_src r600_src[3];
struct r600_bc_alu alu;
- int use_temp = 0;
int i, r;
+ int lasti = tgsi_last_instruction(inst->Dst[0].Register.WriteMask);
r = tgsi_split_constant(ctx, r600_src);
if (r)
@@ -2016,10 +2004,10 @@ static int tgsi_cmp(struct r600_shader_ctx *ctx)
if (r)
return r;
- if (inst->Dst[0].Register.WriteMask != 0xf)
- use_temp = 1;
+ for (i = 0; i < lasti + 1; i++) {
+ if (!(inst->Dst[0].Register.WriteMask & (1 << i)))
+ continue;
- for (i = 0; i < 4; i++) {
memset(&alu, 0, sizeof(struct r600_bc_alu));
alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_CNDGE);
alu.src[0] = r600_src[0];
@@ -2031,24 +2019,19 @@ static int tgsi_cmp(struct r600_shader_ctx *ctx)
alu.src[2] = r600_src[1];
alu.src[2].chan = tgsi_chan(&inst->Src[1], i);
- if (use_temp)
- alu.dst.sel = ctx->temp_reg;
- else {
- r = tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst);
- if (r)
- return r;
- }
+ r = tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst);
+ if (r)
+ return r;
+
alu.dst.chan = i;
alu.dst.write = 1;
alu.is_op3 = 1;
- if (i == 3)
+ if (i == lasti)
alu.last = 1;
r = r600_bc_add_alu(ctx->bc, &alu);
if (r)
return r;
}
- if (use_temp)
- return tgsi_helper_copy(ctx, inst);
return 0;
}
@@ -2115,10 +2098,6 @@ static int tgsi_xpd(struct r600_shader_ctx *ctx)
r = r600_bc_add_alu(ctx->bc, &alu);
if (r)
return r;
-
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
}
for (i = 0; i < 4; i++) {
@@ -2176,10 +2155,6 @@ static int tgsi_xpd(struct r600_shader_ctx *ctx)
r = r600_bc_add_alu(ctx->bc, &alu);
if (r)
return r;
-
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
}
if (use_temp)
return tgsi_helper_copy(ctx, inst);
@@ -2212,10 +2187,6 @@ static int tgsi_exp(struct r600_shader_ctx *ctx)
if (r)
return r;
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
-
alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_EXP_IEEE);
alu.src[0].sel = ctx->temp_reg;
alu.src[0].chan = 0;
@@ -2227,10 +2198,6 @@ static int tgsi_exp(struct r600_shader_ctx *ctx)
r = r600_bc_add_alu(ctx->bc, &alu);
if (r)
return r;
-
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
}
/* result.y = tmp - floor(tmp); */
@@ -2256,9 +2223,6 @@ static int tgsi_exp(struct r600_shader_ctx *ctx)
r = r600_bc_add_alu(ctx->bc, &alu);
if (r)
return r;
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
}
/* result.z = RoughApprox2ToX(tmp);*/
@@ -2279,9 +2243,6 @@ static int tgsi_exp(struct r600_shader_ctx *ctx)
r = r600_bc_add_alu(ctx->bc, &alu);
if (r)
return r;
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
}
/* result.w = 1.0;*/
@@ -2299,9 +2260,6 @@ static int tgsi_exp(struct r600_shader_ctx *ctx)
r = r600_bc_add_alu(ctx->bc, &alu);
if (r)
return r;
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
}
return tgsi_helper_copy(ctx, inst);
}
@@ -2331,10 +2289,6 @@ static int tgsi_log(struct r600_shader_ctx *ctx)
if (r)
return r;
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
-
alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_FLOOR);
alu.src[0].sel = ctx->temp_reg;
alu.src[0].chan = 0;
@@ -2347,10 +2301,6 @@ static int tgsi_log(struct r600_shader_ctx *ctx)
r = r600_bc_add_alu(ctx->bc, &alu);
if (r)
return r;
-
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
}
/* result.y = src.x / (2 ^ floor(log2(src.x))); */
@@ -2373,10 +2323,6 @@ static int tgsi_log(struct r600_shader_ctx *ctx)
if (r)
return r;
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
-
memset(&alu, 0, sizeof(struct r600_bc_alu));
alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_FLOOR);
@@ -2392,10 +2338,6 @@ static int tgsi_log(struct r600_shader_ctx *ctx)
if (r)
return r;
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
-
memset(&alu, 0, sizeof(struct r600_bc_alu));
alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_EXP_IEEE);
@@ -2411,10 +2353,6 @@ static int tgsi_log(struct r600_shader_ctx *ctx)
if (r)
return r;
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
-
memset(&alu, 0, sizeof(struct r600_bc_alu));
alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIP_IEEE);
@@ -2430,10 +2368,6 @@ static int tgsi_log(struct r600_shader_ctx *ctx)
if (r)
return r;
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
-
memset(&alu, 0, sizeof(struct r600_bc_alu));
alu.inst = CTX_INST(V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MUL);
@@ -2455,10 +2389,6 @@ static int tgsi_log(struct r600_shader_ctx *ctx)
r = r600_bc_add_alu(ctx->bc, &alu);
if (r)
return r;
-
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
}
/* result.z = log2(src);*/
@@ -2480,10 +2410,6 @@ static int tgsi_log(struct r600_shader_ctx *ctx)
r = r600_bc_add_alu(ctx->bc, &alu);
if (r)
return r;
-
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
}
/* result.w = 1.0; */
@@ -2502,10 +2428,6 @@ static int tgsi_log(struct r600_shader_ctx *ctx)
r = r600_bc_add_alu(ctx->bc, &alu);
if (r)
return r;
-
- r = r600_bc_add_literal(ctx->bc, ctx->value);
- if (r)
- return r;
}
return tgsi_helper_copy(ctx, inst);
@@ -2660,9 +2582,25 @@ static int emit_logic_pred(struct r600_shader_ctx *ctx, int opcode)
static int pops(struct r600_shader_ctx *ctx, int pops)
{
- r600_bc_add_cfinst(ctx->bc, CTX_INST(V_SQ_CF_WORD1_SQ_CF_INST_POP));
- ctx->bc->cf_last->pop_count = pops;
- ctx->bc->cf_last->cf_addr = ctx->bc->cf_last->id + 2;
+ int alu_pop = 3;
+ if (ctx->bc->cf_last) {
+ if (ctx->bc->cf_last->inst == CTX_INST(V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU) << 3)
+ alu_pop = 0;
+ else if (ctx->bc->cf_last->inst == CTX_INST(V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP_AFTER) << 3)
+ alu_pop = 1;
+ }
+ alu_pop += pops;
+ if (alu_pop == 1) {
+ ctx->bc->cf_last->inst = CTX_INST(V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP_AFTER) << 3;
+ ctx->bc->force_add_cf = 1;
+ } else if (alu_pop == 2) {
+ ctx->bc->cf_last->inst = CTX_INST(V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP2_AFTER) << 3;
+ ctx->bc->force_add_cf = 1;
+ } else {
+ r600_bc_add_cfinst(ctx->bc, CTX_INST(V_SQ_CF_WORD1_SQ_CF_INST_POP));
+ ctx->bc->cf_last->pop_count = pops;
+ ctx->bc->cf_last->cf_addr = ctx->bc->cf_last->id + 2;
+ }
return 0;
}
diff --git a/src/gallium/drivers/r600/r600_shader.h b/src/gallium/drivers/r600/r600_shader.h
index 35b0331525a..935dd6fe3ab 100644
--- a/src/gallium/drivers/r600/r600_shader.h
+++ b/src/gallium/drivers/r600/r600_shader.h
@@ -47,6 +47,6 @@ struct r600_shader {
boolean uses_kill;
};
-int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_shader *shader);
+int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_shader *shader, u32 **literals);
#endif
diff --git a/src/gallium/drivers/r600/r600_sq.h b/src/gallium/drivers/r600/r600_sq.h
index d812bfd1fed..56ed35e8b32 100644
--- a/src/gallium/drivers/r600/r600_sq.h
+++ b/src/gallium/drivers/r600/r600_sq.h
@@ -191,6 +191,8 @@
#define V_SQ_ALU_SRC_M_1_INT 0x000000FB
#define V_SQ_ALU_SRC_0_5 0x000000FC
#define V_SQ_ALU_SRC_LITERAL 0x000000FD
+#define V_SQ_ALU_SRC_PV 0x000000FE
+#define V_SQ_ALU_SRC_PS 0x000000FF
#define V_SQ_ALU_SRC_PARAM_BASE 0x000001C0
#define S_SQ_ALU_WORD0_SRC0_REL(x) (((x) & 0x1) << 9)
#define G_SQ_ALU_WORD0_SRC0_REL(x) (((x) >> 9) & 0x1)
diff --git a/src/gallium/drivers/r600/r600_state.c b/src/gallium/drivers/r600/r600_state.c
index 96b02d72b94..9572ff9a1a2 100644
--- a/src/gallium/drivers/r600/r600_state.c
+++ b/src/gallium/drivers/r600/r600_state.c
@@ -925,6 +925,17 @@ static void r600_cb(struct r600_pipe_context *rctx, struct r600_pipe_state *rsta
desc = util_format_description(rtex->resource.base.b.format);
if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB)
ntype = V_0280A0_NUMBER_SRGB;
+ else if (desc->layout == UTIL_FORMAT_LAYOUT_PLAIN) {
+ switch(desc->channel[0].type) {
+ case UTIL_FORMAT_TYPE_UNSIGNED:
+ ntype = V_0280A0_NUMBER_UNORM;
+ break;
+
+ case UTIL_FORMAT_TYPE_SIGNED:
+ ntype = V_0280A0_NUMBER_SNORM;
+ break;
+ }
+ }
format = r600_translate_colorformat(rtex->resource.base.b.format);
swap = r600_translate_colorswap(rtex->resource.base.b.format);
diff --git a/src/gallium/drivers/r600/r600_state_inlines.h b/src/gallium/drivers/r600/r600_state_inlines.h
index d994196e19d..39ca0a74f3f 100644
--- a/src/gallium/drivers/r600/r600_state_inlines.h
+++ b/src/gallium/drivers/r600/r600_state_inlines.h
@@ -310,6 +310,7 @@ static inline uint32_t r600_translate_colorswap(enum pipe_format format)
return V_0280A0_SWAP_STD;
case PIPE_FORMAT_R16_UNORM:
+ case PIPE_FORMAT_R16_SNORM:
return V_0280A0_SWAP_STD;
/* 32-bit buffers. */
@@ -360,7 +361,7 @@ static inline uint32_t r600_translate_colorswap(enum pipe_format format)
// return FMT_16_16_16_16_FLOAT;
/* 128-bit buffers. */
- case PIPE_FORMAT_R32G32B32A32_FLOAT:
+ //case PIPE_FORMAT_R32G32B32A32_FLOAT:
// return FMT_32_32_32_32_FLOAT;
return 0;
default:
@@ -401,6 +402,7 @@ static INLINE uint32_t r600_translate_colorformat(enum pipe_format format)
return V_0280A0_COLOR_8_8;
case PIPE_FORMAT_R16_UNORM:
+ case PIPE_FORMAT_R16_SNORM:
return V_0280A0_COLOR_16;
/* 32-bit buffers. */
@@ -433,8 +435,8 @@ static INLINE uint32_t r600_translate_colorformat(enum pipe_format format)
case PIPE_FORMAT_S8_USCALED_Z24_UNORM:
return V_0280A0_COLOR_24_8;
- case PIPE_FORMAT_R32_FLOAT:
- return V_0280A0_COLOR_32_FLOAT;
+ //case PIPE_FORMAT_R32_FLOAT:
+ // return V_0280A0_COLOR_32_FLOAT;
case PIPE_FORMAT_R16G16_FLOAT:
return V_0280A0_COLOR_16_16_FLOAT;
@@ -465,10 +467,10 @@ static INLINE uint32_t r600_translate_colorformat(enum pipe_format format)
return V_0280A0_COLOR_32_32;
/* 128-bit buffers. */
- case PIPE_FORMAT_R32G32B32_FLOAT:
- return V_0280A0_COLOR_32_32_32_FLOAT;
- case PIPE_FORMAT_R32G32B32A32_FLOAT:
- return V_0280A0_COLOR_32_32_32_32_FLOAT;
+ //case PIPE_FORMAT_R32G32B32_FLOAT:
+ // return V_0280A0_COLOR_32_32_32_FLOAT;
+ //case PIPE_FORMAT_R32G32B32A32_FLOAT:
+ // return V_0280A0_COLOR_32_32_32_32_FLOAT;
/* YUV buffers. */
case PIPE_FORMAT_UYVY:
diff --git a/src/gallium/drivers/r600/r600_texture.c b/src/gallium/drivers/r600/r600_texture.c
index e2745624575..6add92e6d4c 100644
--- a/src/gallium/drivers/r600/r600_texture.c
+++ b/src/gallium/drivers/r600/r600_texture.c
@@ -562,7 +562,8 @@ struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx,
use_staging_texture = TRUE;
if (!permit_hardware_blit(ctx->screen, texture) ||
- (texture->flags & R600_RESOURCE_FLAG_TRANSFER))
+ (texture->flags & R600_RESOURCE_FLAG_TRANSFER) ||
+ (texture->usage == PIPE_USAGE_STREAM))
use_staging_texture = FALSE;
trans = CALLOC_STRUCT(r600_transfer);
diff --git a/src/gallium/drivers/r600/r600_video_context.c b/src/gallium/drivers/r600/r600_video_context.c
new file mode 100644
index 00000000000..b3885db0f55
--- /dev/null
+++ b/src/gallium/drivers/r600/r600_video_context.c
@@ -0,0 +1,21 @@
+#include "r600_video_context.h"
+#include <softpipe/sp_video_context.h>
+
+struct pipe_video_context *
+r600_video_create(struct pipe_screen *screen, enum pipe_video_profile profile,
+ enum pipe_video_chroma_format chroma_format,
+ unsigned width, unsigned height, void *priv)
+{
+ struct pipe_context *pipe;
+
+ assert(screen);
+
+ pipe = screen->context_create(screen, priv);
+ if (!pipe)
+ return NULL;
+
+ return sp_video_create_ex(pipe, profile, chroma_format, width, height,
+ VL_MPEG12_MC_RENDERER_BUFFER_PICTURE,
+ true,
+ PIPE_FORMAT_VUYX);
+}
diff --git a/src/gallium/drivers/r600/r600_video_context.h b/src/gallium/drivers/r600/r600_video_context.h
new file mode 100644
index 00000000000..bda33a00d44
--- /dev/null
+++ b/src/gallium/drivers/r600/r600_video_context.h
@@ -0,0 +1,11 @@
+#ifndef __R600_VIDEO_CONTEXT_H__
+#define __R600_VIDEO_CONTEXT_H__
+
+#include <pipe/p_video_context.h>
+
+struct pipe_video_context *
+r600_video_create(struct pipe_screen *screen, enum pipe_video_profile profile,
+ enum pipe_video_chroma_format chroma_format,
+ unsigned width, unsigned height, void *priv);
+
+#endif
diff --git a/src/gallium/drivers/r600/r700_asm.c b/src/gallium/drivers/r600/r700_asm.c
index 892dee86baf..a7f2f54736e 100644
--- a/src/gallium/drivers/r600/r700_asm.c
+++ b/src/gallium/drivers/r600/r700_asm.c
@@ -29,8 +29,6 @@
int r700_bc_alu_build(struct r600_bc *bc, struct r600_bc_alu *alu, unsigned id)
{
- unsigned i;
-
bc->bytecode[id++] = S_SQ_ALU_WORD0_SRC0_SEL(alu->src[0].sel) |
S_SQ_ALU_WORD0_SRC0_REL(alu->src[0].rel) |
S_SQ_ALU_WORD0_SRC0_CHAN(alu->src[0].chan) |
@@ -61,18 +59,11 @@ int r700_bc_alu_build(struct r600_bc *bc, struct r600_bc_alu *alu, unsigned id)
S_SQ_ALU_WORD1_OP2_SRC0_ABS(alu->src[0].abs) |
S_SQ_ALU_WORD1_OP2_SRC1_ABS(alu->src[1].abs) |
S_SQ_ALU_WORD1_OP2_WRITE_MASK(alu->dst.write) |
+ S_SQ_ALU_WORD1_OP2_OMOD(alu->omod) |
S_SQ_ALU_WORD1_OP2_ALU_INST(alu->inst) |
S_SQ_ALU_WORD1_BANK_SWIZZLE(alu->bank_swizzle) |
S_SQ_ALU_WORD1_OP2_UPDATE_EXECUTE_MASK(alu->predicate) |
S_SQ_ALU_WORD1_OP2_UPDATE_PRED(alu->predicate);
}
- if (alu->last) {
- if (alu->nliteral && !alu->literal_added) {
- R600_ERR("Bug in ALU processing for instruction 0x%08x, literal not added correctly\n", alu->inst);
- }
- for (i = 0; i < alu->nliteral; i++) {
- bc->bytecode[id++] = alu->value[i];
- }
- }
return 0;
}
diff --git a/src/gallium/drivers/softpipe/Makefile b/src/gallium/drivers/softpipe/Makefile
index 28953582f0a..8876bd16398 100644
--- a/src/gallium/drivers/softpipe/Makefile
+++ b/src/gallium/drivers/softpipe/Makefile
@@ -19,7 +19,7 @@ C_SOURCES = \
sp_quad_fs.c \
sp_quad_blend.c \
sp_screen.c \
- sp_setup.c \
+ sp_setup.c \
sp_state_blend.c \
sp_state_clip.c \
sp_state_derived.c \
@@ -33,6 +33,7 @@ C_SOURCES = \
sp_tex_sample.c \
sp_tex_tile_cache.c \
sp_tile_cache.c \
- sp_surface.c
+ sp_surface.c \
+ sp_video_context.c
include ../../Makefile.template
diff --git a/src/gallium/drivers/softpipe/SConscript b/src/gallium/drivers/softpipe/SConscript
index ea10e8a9f98..9b2abdfd7f1 100644
--- a/src/gallium/drivers/softpipe/SConscript
+++ b/src/gallium/drivers/softpipe/SConscript
@@ -35,6 +35,7 @@ softpipe = env.ConvenienceLibrary(
'sp_tex_tile_cache.c',
'sp_texture.c',
'sp_tile_cache.c',
+ 'sp_video_context.c',
])
env.Alias('softpipe', softpipe)
diff --git a/src/gallium/drivers/softpipe/sp_screen.c b/src/gallium/drivers/softpipe/sp_screen.c
index cbdea19af43..cd3b6240fe9 100644
--- a/src/gallium/drivers/softpipe/sp_screen.c
+++ b/src/gallium/drivers/softpipe/sp_screen.c
@@ -39,6 +39,7 @@
#include "sp_texture.h"
#include "sp_screen.h"
#include "sp_context.h"
+#include "sp_video_context.h"
#include "sp_fence.h"
#include "sp_public.h"
@@ -304,6 +305,7 @@ softpipe_create_screen(struct sw_winsys *winsys)
screen->base.is_format_supported = softpipe_is_format_supported;
screen->base.context_create = softpipe_create_context;
screen->base.flush_frontbuffer = softpipe_flush_frontbuffer;
+ screen->base.video_context_create = sp_video_create;
util_format_s3tc_init();
diff --git a/src/gallium/drivers/softpipe/sp_texture.h b/src/gallium/drivers/softpipe/sp_texture.h
index 5603110eeb3..533d6252e25 100644
--- a/src/gallium/drivers/softpipe/sp_texture.h
+++ b/src/gallium/drivers/softpipe/sp_texture.h
@@ -79,7 +79,6 @@ struct softpipe_transfer
};
-
/** cast wrappers */
static INLINE struct softpipe_resource *
softpipe_resource(struct pipe_resource *pt)
diff --git a/src/gallium/drivers/softpipe/sp_video_context.c b/src/gallium/drivers/softpipe/sp_video_context.c
new file mode 100644
index 00000000000..895aab1b2b1
--- /dev/null
+++ b/src/gallium/drivers/softpipe/sp_video_context.c
@@ -0,0 +1,645 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 "util/u_inlines.h"
+#include "util/u_memory.h"
+
+#include "sp_video_context.h"
+#include <util/u_inlines.h>
+#include <util/u_memory.h>
+#include <util/u_keymap.h>
+#include <util/u_rect.h>
+#include <util/u_video.h>
+#include <util/u_surface.h>
+#include "sp_public.h"
+#include "sp_texture.h"
+
+#define NUM_BUFFERS 2
+
+static void
+flush_buffer(struct sp_mpeg12_context *ctx)
+{
+ assert(ctx);
+
+ if(ctx->mc_buffer != NULL) {
+
+ vl_mpeg12_mc_unmap_buffer(&ctx->mc_renderer, ctx->mc_buffer);
+ vl_mpeg12_mc_renderer_flush(&ctx->mc_renderer, ctx->mc_buffer);
+
+ ctx->mc_buffer = NULL;
+ }
+}
+
+static void
+rotate_buffer(struct sp_mpeg12_context *ctx)
+{
+ static unsigned key = 0;
+ struct vl_mpeg12_mc_buffer *buffer;
+
+ assert(ctx);
+
+ flush_buffer(ctx);
+
+ buffer = (struct vl_mpeg12_mc_buffer*)util_keymap_lookup(ctx->buffer_map, &key);
+ if (!buffer) {
+ boolean added_to_map;
+
+ buffer = CALLOC_STRUCT(vl_mpeg12_mc_buffer);
+ if (buffer == NULL)
+ return;
+
+ if(!vl_mpeg12_mc_init_buffer(&ctx->mc_renderer, buffer)) {
+ FREE(buffer);
+ return;
+ }
+
+ added_to_map = util_keymap_insert(ctx->buffer_map, &key, buffer, ctx);
+ assert(added_to_map);
+ }
+ ++key;
+ key %= NUM_BUFFERS;
+ ctx->mc_buffer = buffer;
+
+ vl_mpeg12_mc_map_buffer(&ctx->mc_renderer, ctx->mc_buffer);
+}
+
+static void
+delete_buffer(const struct keymap *map,
+ const void *key, void *data,
+ void *user)
+{
+ struct sp_mpeg12_context *ctx = (struct sp_mpeg12_context*)user;
+ struct vl_mpeg12_mc_buffer *buf = (struct vl_mpeg12_mc_buffer*)data;
+
+ assert(map);
+ assert(key);
+ assert(data);
+ assert(user);
+
+ vl_mpeg12_mc_cleanup_buffer(&ctx->mc_renderer, buf);
+}
+
+static void
+sp_mpeg12_destroy(struct pipe_video_context *vpipe)
+{
+ struct sp_mpeg12_context *ctx = (struct sp_mpeg12_context*)vpipe;
+
+ assert(vpipe);
+
+ flush_buffer(ctx);
+
+ /* Asserted in softpipe_delete_fs_state() for some reason */
+ ctx->pipe->bind_vs_state(ctx->pipe, NULL);
+ ctx->pipe->bind_fs_state(ctx->pipe, NULL);
+
+ ctx->pipe->delete_blend_state(ctx->pipe, ctx->blend);
+ ctx->pipe->delete_rasterizer_state(ctx->pipe, ctx->rast);
+ ctx->pipe->delete_depth_stencil_alpha_state(ctx->pipe, ctx->dsa);
+
+ pipe_surface_reference(&ctx->decode_target, NULL);
+ vl_compositor_cleanup(&ctx->compositor);
+ util_delete_keymap(ctx->buffer_map, ctx);
+ vl_mpeg12_mc_renderer_cleanup(&ctx->mc_renderer);
+ ctx->pipe->destroy(ctx->pipe);
+
+ FREE(ctx);
+}
+
+static int
+sp_mpeg12_get_param(struct pipe_video_context *vpipe, int param)
+{
+ struct sp_mpeg12_context *ctx = (struct sp_mpeg12_context*)vpipe;
+
+ assert(vpipe);
+
+ switch (param) {
+ case PIPE_CAP_NPOT_TEXTURES:
+ /* XXX: Temporary; not all paths are NPOT-tested */
+#if 0
+ return ctx->pipe->screen->get_param(ctx->pipe->screen, param);
+#endif
+ return FALSE;
+ case PIPE_CAP_DECODE_TARGET_PREFERRED_FORMAT:
+ return ctx->decode_format;
+ default:
+ {
+ debug_printf("Softpipe: Unknown PIPE_CAP %d\n", param);
+ return 0;
+ }
+ }
+}
+
+static struct pipe_surface *
+sp_mpeg12_create_surface(struct pipe_video_context *vpipe,
+ struct pipe_resource *resource,
+ const struct pipe_surface *templat)
+{
+ struct sp_mpeg12_context *ctx = (struct sp_mpeg12_context*)vpipe;
+
+ assert(vpipe);
+
+ return ctx->pipe->create_surface(ctx->pipe, resource, templat);
+}
+
+static boolean
+sp_mpeg12_is_format_supported(struct pipe_video_context *vpipe,
+ enum pipe_format format,
+ unsigned usage,
+ unsigned geom)
+{
+ struct sp_mpeg12_context *ctx = (struct sp_mpeg12_context*)vpipe;
+
+ assert(vpipe);
+
+ /* XXX: Temporary; not all paths are NPOT-tested */
+ if (geom & PIPE_TEXTURE_GEOM_NON_POWER_OF_TWO)
+ return FALSE;
+
+ return ctx->pipe->screen->is_format_supported(ctx->pipe->screen, format, PIPE_TEXTURE_2D,
+ 0, usage, geom);
+}
+
+static void
+sp_mpeg12_decode_macroblocks(struct pipe_video_context *vpipe,
+ struct pipe_surface *past,
+ struct pipe_surface *future,
+ unsigned num_macroblocks,
+ struct pipe_macroblock *macroblocks,
+ struct pipe_fence_handle **fence)
+{
+ struct sp_mpeg12_context *ctx = (struct sp_mpeg12_context*)vpipe;
+ struct pipe_mpeg12_macroblock *mpeg12_macroblocks = (struct pipe_mpeg12_macroblock*)macroblocks;
+
+ assert(vpipe);
+ assert(num_macroblocks);
+ assert(macroblocks);
+ assert(macroblocks->codec == PIPE_VIDEO_CODEC_MPEG12);
+ assert(ctx->decode_target);
+ assert(ctx->mc_buffer);
+
+ vl_mpeg12_mc_renderer_render_macroblocks(&ctx->mc_renderer,
+ ctx->mc_buffer,
+ ctx->decode_target,
+ past, future, num_macroblocks,
+ mpeg12_macroblocks, fence);
+}
+
+static void
+sp_mpeg12_surface_fill(struct pipe_video_context *vpipe,
+ struct pipe_surface *dst,
+ unsigned dstx, unsigned dsty,
+ unsigned width, unsigned height,
+ unsigned value)
+{
+ struct sp_mpeg12_context *ctx = (struct sp_mpeg12_context*)vpipe;
+ float rgba[4] = { 0, 0, 0, 0 };
+
+ assert(vpipe);
+ assert(dst);
+
+ if (ctx->pipe->clear_render_target)
+ ctx->pipe->clear_render_target(ctx->pipe, dst, rgba, dstx, dsty, width, height);
+ else
+ util_clear_render_target(ctx->pipe, dst, rgba, dstx, dsty, width, height);
+}
+
+static void
+sp_mpeg12_surface_copy(struct pipe_video_context *vpipe,
+ struct pipe_surface *dst,
+ unsigned dstx, unsigned dsty,
+ struct pipe_surface *src,
+ unsigned srcx, unsigned srcy,
+ unsigned width, unsigned height)
+{
+ struct sp_mpeg12_context *ctx = (struct sp_mpeg12_context*)vpipe;
+
+ assert(vpipe);
+ assert(dst);
+
+ struct pipe_box box;
+ box.x = srcx;
+ box.y = srcy;
+ box.z = 0;
+ box.width = width;
+ box.height = height;
+
+ if (ctx->pipe->resource_copy_region)
+ ctx->pipe->resource_copy_region(ctx->pipe, dst->texture, dst->u.tex.level,
+ dstx, dsty, dst->u.tex.first_layer,
+ src->texture, src->u.tex.level, &box);
+ else
+ util_resource_copy_region(ctx->pipe, dst->texture, dst->u.tex.level,
+ dstx, dsty, dst->u.tex.first_layer,
+ src->texture, src->u.tex.level, &box);
+}
+
+static struct pipe_transfer*
+sp_mpeg12_get_transfer(struct pipe_video_context *vpipe,
+ struct pipe_resource *resource,
+ unsigned level,
+ unsigned usage, /* a combination of PIPE_TRANSFER_x */
+ const struct pipe_box *box)
+{
+ struct sp_mpeg12_context *ctx = (struct sp_mpeg12_context*)vpipe;
+
+ assert(vpipe);
+ assert(resource);
+ assert(box);
+
+ return ctx->pipe->get_transfer(ctx->pipe, resource, level, usage, box);
+}
+
+static void
+sp_mpeg12_transfer_destroy(struct pipe_video_context *vpipe,
+ struct pipe_transfer *transfer)
+{
+ struct sp_mpeg12_context *ctx = (struct sp_mpeg12_context*)vpipe;
+
+ assert(vpipe);
+ assert(transfer);
+
+ ctx->pipe->transfer_destroy(ctx->pipe, transfer);
+}
+
+static void*
+sp_mpeg12_transfer_map(struct pipe_video_context *vpipe,
+ struct pipe_transfer *transfer)
+{
+ struct sp_mpeg12_context *ctx = (struct sp_mpeg12_context*)vpipe;
+
+ assert(vpipe);
+ assert(transfer);
+
+ return ctx->pipe->transfer_map(ctx->pipe, transfer);
+}
+
+static void
+sp_mpeg12_transfer_flush_region(struct pipe_video_context *vpipe,
+ struct pipe_transfer *transfer,
+ const struct pipe_box *box)
+{
+ struct sp_mpeg12_context *ctx = (struct sp_mpeg12_context*)vpipe;
+
+ assert(vpipe);
+ assert(transfer);
+ assert(box);
+
+ ctx->pipe->transfer_flush_region(ctx->pipe, transfer, box);
+}
+
+static void
+sp_mpeg12_transfer_unmap(struct pipe_video_context *vpipe,
+ struct pipe_transfer *transfer)
+{
+ struct sp_mpeg12_context *ctx = (struct sp_mpeg12_context*)vpipe;
+
+ assert(vpipe);
+ assert(transfer);
+
+ ctx->pipe->transfer_unmap(ctx->pipe, transfer);
+}
+
+static void
+sp_mpeg12_transfer_inline_write(struct pipe_video_context *vpipe,
+ struct pipe_resource *resource,
+ unsigned level,
+ unsigned usage, /* a combination of PIPE_TRANSFER_x */
+ const struct pipe_box *box,
+ const void *data,
+ unsigned stride,
+ unsigned slice_stride)
+{
+ struct sp_mpeg12_context *ctx = (struct sp_mpeg12_context*)vpipe;
+
+ assert(vpipe);
+ assert(resource);
+ assert(box);
+ assert(data);
+ assert(ctx->pipe->transfer_inline_write);
+
+ ctx->pipe->transfer_inline_write(ctx->pipe, resource, level, usage,
+ box, data, stride, slice_stride);
+}
+
+static void
+sp_mpeg12_render_picture(struct pipe_video_context *vpipe,
+ struct pipe_surface *src_surface,
+ enum pipe_mpeg12_picture_type picture_type,
+ /*unsigned num_past_surfaces,
+ struct pipe_surface *past_surfaces,
+ unsigned num_future_surfaces,
+ struct pipe_surface *future_surfaces,*/
+ struct pipe_video_rect *src_area,
+ struct pipe_surface *dst_surface,
+ struct pipe_video_rect *dst_area,
+ struct pipe_fence_handle **fence)
+{
+ struct sp_mpeg12_context *ctx = (struct sp_mpeg12_context*)vpipe;
+
+ assert(vpipe);
+ assert(src_surface);
+ assert(src_area);
+ assert(dst_surface);
+ assert(dst_area);
+
+ flush_buffer(ctx);
+
+ vl_compositor_render(&ctx->compositor, src_surface,
+ picture_type, src_area, dst_surface, dst_area, fence);
+}
+
+static void
+sp_mpeg12_set_picture_background(struct pipe_video_context *vpipe,
+ struct pipe_surface *bg,
+ struct pipe_video_rect *bg_src_rect)
+{
+ struct sp_mpeg12_context *ctx = (struct sp_mpeg12_context*)vpipe;
+
+ assert(vpipe);
+ assert(bg);
+ assert(bg_src_rect);
+
+ vl_compositor_set_background(&ctx->compositor, bg, bg_src_rect);
+}
+
+static void
+sp_mpeg12_set_picture_layers(struct pipe_video_context *vpipe,
+ struct pipe_surface *layers[],
+ struct pipe_video_rect *src_rects[],
+ struct pipe_video_rect *dst_rects[],
+ unsigned num_layers)
+{
+ struct sp_mpeg12_context *ctx = (struct sp_mpeg12_context*)vpipe;
+
+ assert(vpipe);
+ assert((layers && src_rects && dst_rects) ||
+ (!layers && !src_rects && !dst_rects));
+
+ vl_compositor_set_layers(&ctx->compositor, layers, src_rects, dst_rects, num_layers);
+}
+
+static void
+sp_mpeg12_set_decode_target(struct pipe_video_context *vpipe,
+ struct pipe_surface *dt)
+{
+ struct sp_mpeg12_context *ctx = (struct sp_mpeg12_context*)vpipe;
+
+ assert(vpipe);
+ assert(dt);
+
+ if (ctx->decode_target != dt || ctx->mc_buffer == NULL) {
+ rotate_buffer(ctx);
+
+ pipe_surface_reference(&ctx->decode_target, dt);
+ }
+}
+
+static void
+sp_mpeg12_set_csc_matrix(struct pipe_video_context *vpipe, const float *mat)
+{
+ struct sp_mpeg12_context *ctx = (struct sp_mpeg12_context*)vpipe;
+
+ assert(vpipe);
+
+ vl_compositor_set_csc_matrix(&ctx->compositor, mat);
+}
+
+static bool
+init_pipe_state(struct sp_mpeg12_context *ctx)
+{
+ struct pipe_rasterizer_state rast;
+ struct pipe_blend_state blend;
+ struct pipe_depth_stencil_alpha_state dsa;
+ unsigned i;
+
+ assert(ctx);
+
+ memset(&rast, 0, sizeof rast);
+ rast.flatshade = 1;
+ rast.flatshade_first = 0;
+ rast.light_twoside = 0;
+ rast.front_ccw = 1;
+ rast.cull_face = PIPE_FACE_NONE;
+ rast.fill_back = PIPE_POLYGON_MODE_FILL;
+ rast.fill_front = PIPE_POLYGON_MODE_FILL;
+ rast.offset_point = 0;
+ rast.offset_line = 0;
+ rast.scissor = 0;
+ rast.poly_smooth = 0;
+ rast.poly_stipple_enable = 0;
+ rast.sprite_coord_enable = 0;
+ rast.point_size_per_vertex = 0;
+ rast.multisample = 0;
+ rast.line_smooth = 0;
+ rast.line_stipple_enable = 0;
+ rast.line_stipple_factor = 0;
+ rast.line_stipple_pattern = 0;
+ rast.line_last_pixel = 0;
+ rast.line_width = 1;
+ rast.point_smooth = 0;
+ rast.point_quad_rasterization = 0;
+ rast.point_size = 1;
+ rast.offset_units = 1;
+ rast.offset_scale = 1;
+ rast.gl_rasterization_rules = 1;
+ ctx->rast = ctx->pipe->create_rasterizer_state(ctx->pipe, &rast);
+ ctx->pipe->bind_rasterizer_state(ctx->pipe, ctx->rast);
+
+ memset(&blend, 0, sizeof blend);
+ blend.independent_blend_enable = 0;
+ blend.rt[0].blend_enable = 0;
+ blend.rt[0].rgb_func = PIPE_BLEND_ADD;
+ blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].alpha_func = PIPE_BLEND_ADD;
+ blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
+ blend.logicop_enable = 0;
+ blend.logicop_func = PIPE_LOGICOP_CLEAR;
+ /* Needed to allow color writes to FB, even if blending disabled */
+ blend.rt[0].colormask = PIPE_MASK_RGBA;
+ blend.dither = 0;
+ ctx->blend = ctx->pipe->create_blend_state(ctx->pipe, &blend);
+ ctx->pipe->bind_blend_state(ctx->pipe, ctx->blend);
+
+ memset(&dsa, 0, sizeof dsa);
+ dsa.depth.enabled = 0;
+ dsa.depth.writemask = 0;
+ dsa.depth.func = PIPE_FUNC_ALWAYS;
+ for (i = 0; i < 2; ++i) {
+ dsa.stencil[i].enabled = 0;
+ dsa.stencil[i].func = PIPE_FUNC_ALWAYS;
+ dsa.stencil[i].fail_op = PIPE_STENCIL_OP_KEEP;
+ dsa.stencil[i].zpass_op = PIPE_STENCIL_OP_KEEP;
+ dsa.stencil[i].zfail_op = PIPE_STENCIL_OP_KEEP;
+ dsa.stencil[i].valuemask = 0;
+ dsa.stencil[i].writemask = 0;
+ }
+ dsa.alpha.enabled = 0;
+ dsa.alpha.func = PIPE_FUNC_ALWAYS;
+ dsa.alpha.ref_value = 0;
+ ctx->dsa = ctx->pipe->create_depth_stencil_alpha_state(ctx->pipe, &dsa);
+ ctx->pipe->bind_depth_stencil_alpha_state(ctx->pipe, ctx->dsa);
+
+ return true;
+}
+
+static struct pipe_video_context *
+sp_mpeg12_create(struct pipe_context *pipe, enum pipe_video_profile profile,
+ enum pipe_video_chroma_format chroma_format,
+ unsigned width, unsigned height,
+ enum VL_MPEG12_MC_RENDERER_BUFFER_MODE bufmode,
+ bool pot_buffers,
+ enum pipe_format decode_format)
+{
+ unsigned buffer_width, buffer_height;
+ struct sp_mpeg12_context *ctx;
+
+ assert(u_reduce_video_profile(profile) == PIPE_VIDEO_CODEC_MPEG12);
+
+ ctx = CALLOC_STRUCT(sp_mpeg12_context);
+
+ if (!ctx)
+ return NULL;
+
+ /* TODO: Non-pot buffers untested, probably doesn't work without changes to texcoord generation, vert shader, etc */
+ assert(pot_buffers);
+
+ buffer_width = pot_buffers ? util_next_power_of_two(width) : width;
+ buffer_height = pot_buffers ? util_next_power_of_two(height) : height;
+
+ ctx->base.profile = profile;
+ ctx->base.chroma_format = chroma_format;
+ ctx->base.width = width;
+ ctx->base.height = height;
+
+ ctx->base.screen = pipe->screen;
+ ctx->base.destroy = sp_mpeg12_destroy;
+ ctx->base.get_param = sp_mpeg12_get_param;
+ ctx->base.is_format_supported = sp_mpeg12_is_format_supported;
+ ctx->base.create_surface = sp_mpeg12_create_surface;
+ ctx->base.decode_macroblocks = sp_mpeg12_decode_macroblocks;
+ ctx->base.render_picture = sp_mpeg12_render_picture;
+ ctx->base.surface_fill = sp_mpeg12_surface_fill;
+ ctx->base.surface_copy = sp_mpeg12_surface_copy;
+ ctx->base.get_transfer = sp_mpeg12_get_transfer;
+ ctx->base.transfer_destroy = sp_mpeg12_transfer_destroy;
+ ctx->base.transfer_map = sp_mpeg12_transfer_map;
+ ctx->base.transfer_flush_region = sp_mpeg12_transfer_flush_region;
+ ctx->base.transfer_unmap = sp_mpeg12_transfer_unmap;
+ if (pipe->transfer_inline_write)
+ ctx->base.transfer_inline_write = sp_mpeg12_transfer_inline_write;
+ ctx->base.set_picture_background = sp_mpeg12_set_picture_background;
+ ctx->base.set_picture_layers = sp_mpeg12_set_picture_layers;
+ ctx->base.set_decode_target = sp_mpeg12_set_decode_target;
+ ctx->base.set_csc_matrix = sp_mpeg12_set_csc_matrix;
+
+ ctx->pipe = pipe;
+ ctx->decode_format = decode_format;
+
+ if (!vl_mpeg12_mc_renderer_init(&ctx->mc_renderer, ctx->pipe,
+ buffer_width, buffer_height, chroma_format,
+ bufmode)) {
+ ctx->pipe->destroy(ctx->pipe);
+ FREE(ctx);
+ return NULL;
+ }
+
+ ctx->buffer_map = util_new_keymap(sizeof(unsigned), -1, delete_buffer);
+ if (!ctx->buffer_map) {
+ vl_mpeg12_mc_renderer_cleanup(&ctx->mc_renderer);
+ ctx->pipe->destroy(ctx->pipe);
+ FREE(ctx);
+ return NULL;
+ }
+
+ if (!vl_compositor_init(&ctx->compositor, ctx->pipe)) {
+ util_delete_keymap(ctx->buffer_map, ctx);
+ vl_mpeg12_mc_renderer_cleanup(&ctx->mc_renderer);
+ ctx->pipe->destroy(ctx->pipe);
+ FREE(ctx);
+ return NULL;
+ }
+
+ if (!init_pipe_state(ctx)) {
+ vl_compositor_cleanup(&ctx->compositor);
+ util_delete_keymap(ctx->buffer_map, ctx);
+ vl_mpeg12_mc_renderer_cleanup(&ctx->mc_renderer);
+ ctx->pipe->destroy(ctx->pipe);
+ FREE(ctx);
+ return NULL;
+ }
+
+ return &ctx->base;
+}
+
+struct pipe_video_context *
+sp_video_create(struct pipe_screen *screen, enum pipe_video_profile profile,
+ enum pipe_video_chroma_format chroma_format,
+ unsigned width, unsigned height, void *priv)
+{
+ struct pipe_context *pipe;
+
+ assert(screen);
+ assert(width && height);
+
+ pipe = screen->context_create(screen, NULL);
+ if (!pipe)
+ return NULL;
+
+ /* TODO: Use slice buffering for softpipe when implemented, no advantage to buffering an entire picture with softpipe */
+ return sp_video_create_ex(pipe, profile,
+ chroma_format,
+ width, height,
+ VL_MPEG12_MC_RENDERER_BUFFER_PICTURE,
+ true,
+ PIPE_FORMAT_XYUV);
+}
+
+struct pipe_video_context *
+sp_video_create_ex(struct pipe_context *pipe, enum pipe_video_profile profile,
+ enum pipe_video_chroma_format chroma_format,
+ unsigned width, unsigned height,
+ enum VL_MPEG12_MC_RENDERER_BUFFER_MODE bufmode,
+ bool pot_buffers,
+ enum pipe_format decode_format)
+{
+ assert(pipe);
+ assert(width && height);
+
+ switch (u_reduce_video_profile(profile)) {
+ case PIPE_VIDEO_CODEC_MPEG12:
+ return sp_mpeg12_create(pipe, profile,
+ chroma_format,
+ width, height,
+ bufmode,
+ pot_buffers,
+ decode_format);
+ default:
+ return NULL;
+ }
+}
diff --git a/src/gallium/drivers/softpipe/sp_video_context.h b/src/gallium/drivers/softpipe/sp_video_context.h
new file mode 100644
index 00000000000..9b60bad6b8f
--- /dev/null
+++ b/src/gallium/drivers/softpipe/sp_video_context.h
@@ -0,0 +1,70 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 SP_VIDEO_CONTEXT_H
+#define SP_VIDEO_CONTEXT_H
+
+#include <pipe/p_video_context.h>
+#include <vl/vl_mpeg12_mc_renderer.h>
+#include <vl/vl_compositor.h>
+
+struct pipe_screen;
+struct pipe_context;
+
+struct sp_mpeg12_context
+{
+ struct pipe_video_context base;
+ struct pipe_context *pipe;
+ struct pipe_surface *decode_target;
+ struct vl_mpeg12_mc_renderer mc_renderer;
+ struct keymap *buffer_map;
+ struct vl_mpeg12_mc_buffer *mc_buffer;
+ struct vl_compositor compositor;
+
+ void *rast;
+ void *dsa;
+ void *blend;
+
+ enum pipe_format decode_format;
+};
+
+struct pipe_video_context *
+sp_video_create(struct pipe_screen *screen, enum pipe_video_profile profile,
+ enum pipe_video_chroma_format chroma_format,
+ unsigned width, unsigned height, void *priv);
+
+/* Other drivers can call this function in their pipe_video_context constructors and pass it
+ an accelerated pipe_context along with suitable buffering modes, etc */
+struct pipe_video_context *
+sp_video_create_ex(struct pipe_context *pipe, enum pipe_video_profile profile,
+ enum pipe_video_chroma_format chroma_format,
+ unsigned width, unsigned height,
+ enum VL_MPEG12_MC_RENDERER_BUFFER_MODE bufmode,
+ bool pot_buffers,
+ enum pipe_format decode_format);
+
+#endif /* SP_VIDEO_CONTEXT_H */
diff --git a/src/gallium/include/pipe/p_defines.h b/src/gallium/include/pipe/p_defines.h
index f5af15ff9ff..7aaf6110456 100644
--- a/src/gallium/include/pipe/p_defines.h
+++ b/src/gallium/include/pipe/p_defines.h
@@ -495,6 +495,30 @@ enum pipe_shader_cap
#define PIPE_REFERENCED_FOR_READ (1 << 0)
#define PIPE_REFERENCED_FOR_WRITE (1 << 1)
+enum pipe_video_codec
+{
+ PIPE_VIDEO_CODEC_UNKNOWN = 0,
+ PIPE_VIDEO_CODEC_MPEG12, /**< MPEG1, MPEG2 */
+ PIPE_VIDEO_CODEC_MPEG4, /**< DIVX, XVID */
+ PIPE_VIDEO_CODEC_VC1, /**< WMV */
+ PIPE_VIDEO_CODEC_MPEG4_AVC /**< H.264 */
+};
+
+enum pipe_video_profile
+{
+ PIPE_VIDEO_PROFILE_MPEG1,
+ PIPE_VIDEO_PROFILE_MPEG2_SIMPLE,
+ PIPE_VIDEO_PROFILE_MPEG2_MAIN,
+ PIPE_VIDEO_PROFILE_MPEG4_SIMPLE,
+ PIPE_VIDEO_PROFILE_MPEG4_ADVANCED_SIMPLE,
+ PIPE_VIDEO_PROFILE_VC1_SIMPLE,
+ PIPE_VIDEO_PROFILE_VC1_MAIN,
+ PIPE_VIDEO_PROFILE_VC1_ADVANCED,
+ PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE,
+ PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN,
+ PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH
+};
+
/**
* Composite query types
*/
diff --git a/src/gallium/include/pipe/p_format.h b/src/gallium/include/pipe/p_format.h
index 74a9939df73..3aa11be4b5b 100644
--- a/src/gallium/include/pipe/p_format.h
+++ b/src/gallium/include/pipe/p_format.h
@@ -186,19 +186,37 @@ enum pipe_format {
PIPE_FORMAT_R8G8B8X8_UNORM = 134,
PIPE_FORMAT_B4G4R4X4_UNORM = 135,
+ PIPE_FORMAT_YV12 = 136,
+ PIPE_FORMAT_YV16 = 137,
+ PIPE_FORMAT_IYUV = 138, /**< aka I420 */
+ PIPE_FORMAT_NV12 = 139,
+ PIPE_FORMAT_NV21 = 140,
+ PIPE_FORMAT_AYUV = PIPE_FORMAT_A8R8G8B8_UNORM,
+ PIPE_FORMAT_VUYA = PIPE_FORMAT_B8G8R8A8_UNORM,
+ PIPE_FORMAT_XYUV = PIPE_FORMAT_X8R8G8B8_UNORM,
+ PIPE_FORMAT_VUYX = PIPE_FORMAT_B8G8R8X8_UNORM,
+ PIPE_FORMAT_IA44 = 141,
+ PIPE_FORMAT_AI44 = 142,
+
/* some stencil samplers formats */
- PIPE_FORMAT_X24S8_USCALED = 136,
- PIPE_FORMAT_S8X24_USCALED = 137,
- PIPE_FORMAT_X32_S8X24_USCALED = 138,
+ PIPE_FORMAT_X24S8_USCALED = 143,
+ PIPE_FORMAT_S8X24_USCALED = 144,
+ PIPE_FORMAT_X32_S8X24_USCALED = 145,
- PIPE_FORMAT_B2G3R3_UNORM = 139,
- PIPE_FORMAT_L16A16_UNORM = 140,
- PIPE_FORMAT_A16_UNORM = 141,
- PIPE_FORMAT_I16_UNORM = 142,
+ PIPE_FORMAT_B2G3R3_UNORM = 146,
+ PIPE_FORMAT_L16A16_UNORM = 147,
+ PIPE_FORMAT_A16_UNORM = 148,
+ PIPE_FORMAT_I16_UNORM = 149,
PIPE_FORMAT_COUNT
};
+enum pipe_video_chroma_format
+{
+ PIPE_VIDEO_CHROMA_FORMAT_420,
+ PIPE_VIDEO_CHROMA_FORMAT_422,
+ PIPE_VIDEO_CHROMA_FORMAT_444
+};
#ifdef __cplusplus
}
diff --git a/src/gallium/include/pipe/p_screen.h b/src/gallium/include/pipe/p_screen.h
index 850eb84a3c8..ef03ed74a20 100644
--- a/src/gallium/include/pipe/p_screen.h
+++ b/src/gallium/include/pipe/p_screen.h
@@ -93,7 +93,12 @@ struct pipe_screen {
int (*get_shader_param)( struct pipe_screen *, unsigned shader, enum pipe_shader_cap param );
struct pipe_context * (*context_create)( struct pipe_screen *,
- void *priv );
+ void *priv );
+
+ struct pipe_video_context * (*video_context_create)( struct pipe_screen *screen,
+ enum pipe_video_profile profile,
+ enum pipe_video_chroma_format chroma_format,
+ unsigned width, unsigned height, void *priv );
/**
* Check if the given pipe_format is supported as a texture or
diff --git a/src/gallium/include/pipe/p_video_context.h b/src/gallium/include/pipe/p_video_context.h
new file mode 100644
index 00000000000..2dfdba413ac
--- /dev/null
+++ b/src/gallium/include/pipe/p_video_context.h
@@ -0,0 +1,182 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 PIPE_VIDEO_CONTEXT_H
+#define PIPE_VIDEO_CONTEXT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <pipe/p_video_state.h>
+
+/* XXX: Move to an appropriate place */
+#define PIPE_CAP_DECODE_TARGET_PREFERRED_FORMAT 256
+
+struct pipe_screen;
+struct pipe_buffer;
+struct pipe_surface;
+struct pipe_macroblock;
+struct pipe_picture_desc;
+struct pipe_fence_handle;
+
+/**
+ * Gallium video rendering context
+ */
+struct pipe_video_context
+{
+ struct pipe_screen *screen;
+ enum pipe_video_profile profile;
+ enum pipe_video_chroma_format chroma_format;
+ unsigned width;
+ unsigned height;
+
+ void *priv; /**< context private data (for DRI for example) */
+
+ /**
+ * Query an integer-valued capability/parameter/limit
+ * \param param one of PIPE_CAP_x
+ */
+ int (*get_param)(struct pipe_video_context *vpipe, int param);
+
+ /**
+ * Check if the given pipe_format is supported as a texture or
+ * drawing surface.
+ */
+ boolean (*is_format_supported)(struct pipe_video_context *vpipe,
+ enum pipe_format format,
+ unsigned usage,
+ unsigned geom);
+
+ void (*destroy)(struct pipe_video_context *vpipe);
+
+ struct pipe_surface *(*create_surface)(struct pipe_video_context *vpipe,
+ struct pipe_resource *resource,
+ const struct pipe_surface *templat);
+
+ /**
+ * Picture decoding and displaying
+ */
+ /*@{*/
+ void (*decode_bitstream)(struct pipe_video_context *vpipe,
+ unsigned num_bufs,
+ struct pipe_buffer **bitstream_buf);
+
+ void (*decode_macroblocks)(struct pipe_video_context *vpipe,
+ struct pipe_surface *past,
+ struct pipe_surface *future,
+ unsigned num_macroblocks,
+ struct pipe_macroblock *macroblocks,
+ struct pipe_fence_handle **fence);
+
+ void (*render_picture)(struct pipe_video_context *vpipe,
+ struct pipe_surface *src_surface,
+ enum pipe_mpeg12_picture_type picture_type,
+ /*unsigned num_past_surfaces,
+ struct pipe_surface *past_surfaces,
+ unsigned num_future_surfaces,
+ struct pipe_surface *future_surfaces,*/
+ struct pipe_video_rect *src_area,
+ struct pipe_surface *dst_surface,
+ struct pipe_video_rect *dst_area,
+ struct pipe_fence_handle **fence);
+
+ void (*surface_fill)(struct pipe_video_context *vpipe,
+ struct pipe_surface *dst,
+ unsigned dstx, unsigned dsty,
+ unsigned width, unsigned height,
+ unsigned value);
+
+ void (*surface_copy)(struct pipe_video_context *vpipe,
+ struct pipe_surface *dst,
+ unsigned dstx, unsigned dsty,
+ struct pipe_surface *src,
+ unsigned srcx, unsigned srcy,
+ unsigned width, unsigned height);
+
+ struct pipe_transfer *(*get_transfer)(struct pipe_video_context *vpipe,
+ struct pipe_resource *resource,
+ unsigned level,
+ unsigned usage, /* a combination of PIPE_TRANSFER_x */
+ const struct pipe_box *box);
+
+ void (*transfer_destroy)(struct pipe_video_context *vpipe,
+ struct pipe_transfer *transfer);
+
+ void* (*transfer_map)(struct pipe_video_context *vpipe,
+ struct pipe_transfer *transfer);
+
+ void (*transfer_flush_region)(struct pipe_video_context *vpipe,
+ struct pipe_transfer *transfer,
+ const struct pipe_box *box);
+
+ void (*transfer_unmap)(struct pipe_video_context *vpipe,
+ struct pipe_transfer *transfer);
+
+ void (*transfer_inline_write)(struct pipe_video_context *vpipe,
+ struct pipe_resource *resource,
+ unsigned level,
+ unsigned usage, /* a combination of PIPE_TRANSFER_x */
+ const struct pipe_box *box,
+ const void *data,
+ unsigned stride,
+ unsigned slice_stride);
+
+ /*@}*/
+
+ /**
+ * Parameter-like states (or properties)
+ */
+ /*@{*/
+ void (*set_picture_background)(struct pipe_video_context *vpipe,
+ struct pipe_surface *bg,
+ struct pipe_video_rect *bg_src_rect);
+
+ void (*set_picture_layers)(struct pipe_video_context *vpipe,
+ struct pipe_surface *layers[],
+ struct pipe_video_rect *src_rects[],
+ struct pipe_video_rect *dst_rects[],
+ unsigned num_layers);
+
+ void (*set_picture_desc)(struct pipe_video_context *vpipe,
+ const struct pipe_picture_desc *desc);
+
+ void (*set_decode_target)(struct pipe_video_context *vpipe,
+ struct pipe_surface *dt);
+
+ void (*set_csc_matrix)(struct pipe_video_context *vpipe, const float *mat);
+
+ /* TODO: Interface for scaling modes, post-processing, etc. */
+ /*@}*/
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPE_VIDEO_CONTEXT_H */
diff --git a/src/gallium/include/pipe/p_video_state.h b/src/gallium/include/pipe/p_video_state.h
new file mode 100644
index 00000000000..e5e85e3deb3
--- /dev/null
+++ b/src/gallium/include/pipe/p_video_state.h
@@ -0,0 +1,133 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 PIPE_VIDEO_STATE_H
+#define PIPE_VIDEO_STATE_H
+
+#include <pipe/p_defines.h>
+#include <pipe/p_format.h>
+#include <pipe/p_state.h>
+#include <pipe/p_screen.h>
+#include <util/u_inlines.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct pipe_video_rect
+{
+ unsigned x, y, w, h;
+};
+
+enum pipe_mpeg12_picture_type
+{
+ PIPE_MPEG12_PICTURE_TYPE_FIELD_TOP,
+ PIPE_MPEG12_PICTURE_TYPE_FIELD_BOTTOM,
+ PIPE_MPEG12_PICTURE_TYPE_FRAME
+};
+
+enum pipe_mpeg12_macroblock_type
+{
+ PIPE_MPEG12_MACROBLOCK_TYPE_INTRA,
+ PIPE_MPEG12_MACROBLOCK_TYPE_FWD,
+ PIPE_MPEG12_MACROBLOCK_TYPE_BKWD,
+ PIPE_MPEG12_MACROBLOCK_TYPE_BI,
+
+ PIPE_MPEG12_MACROBLOCK_NUM_TYPES
+};
+
+enum pipe_mpeg12_motion_type
+{
+ PIPE_MPEG12_MOTION_TYPE_FIELD,
+ PIPE_MPEG12_MOTION_TYPE_FRAME,
+ PIPE_MPEG12_MOTION_TYPE_DUALPRIME,
+ PIPE_MPEG12_MOTION_TYPE_16x8
+};
+
+enum pipe_mpeg12_dct_type
+{
+ PIPE_MPEG12_DCT_TYPE_FIELD,
+ PIPE_MPEG12_DCT_TYPE_FRAME
+};
+
+struct pipe_macroblock
+{
+ enum pipe_video_codec codec;
+};
+
+struct pipe_mpeg12_macroblock
+{
+ struct pipe_macroblock base;
+
+ unsigned mbx;
+ unsigned mby;
+ enum pipe_mpeg12_macroblock_type mb_type;
+ enum pipe_mpeg12_motion_type mo_type;
+ enum pipe_mpeg12_dct_type dct_type;
+ signed pmv[2][2][2];
+ bool mvfs[2][2];
+ unsigned cbp;
+ short *blocks;
+};
+
+#if 0
+struct pipe_picture_desc
+{
+ enum pipe_video_format format;
+};
+
+struct pipe_mpeg12_picture_desc
+{
+ struct pipe_picture_desc base;
+
+ /* TODO: Use bitfields where possible? */
+ struct pipe_surface *forward_reference;
+ struct pipe_surface *backward_reference;
+ unsigned picture_coding_type;
+ unsigned fcode;
+ unsigned intra_dc_precision;
+ unsigned picture_structure;
+ unsigned top_field_first;
+ unsigned frame_pred_frame_dct;
+ unsigned concealment_motion_vectors;
+ unsigned q_scale_type;
+ unsigned intra_vlc_format;
+ unsigned alternate_scan;
+ unsigned full_pel_forward_vector;
+ unsigned full_pel_backward_vector;
+ struct pipe_buffer *intra_quantizer_matrix;
+ struct pipe_buffer *non_intra_quantizer_matrix;
+ struct pipe_buffer *chroma_intra_quantizer_matrix;
+ struct pipe_buffer *chroma_non_intra_quantizer_matrix;
+};
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPE_VIDEO_STATE_H */
diff --git a/src/gallium/state_trackers/vdpau/Makefile b/src/gallium/state_trackers/vdpau/Makefile
new file mode 100644
index 00000000000..346cce9d43b
--- /dev/null
+++ b/src/gallium/state_trackers/vdpau/Makefile
@@ -0,0 +1,15 @@
+TOP = ../../../..
+include $(TOP)/configs/current
+
+LIBNAME = vdpautracker
+
+LIBRARY_INCLUDES = \
+ $(shell pkg-config --cflags-only-I vdpau) \
+ -I$(TOP)/src/gallium/winsys/g3dvl
+
+C_SOURCES = htab.c \
+ ftab.c \
+ device.c \
+ query.c
+
+include ../../Makefile.template
diff --git a/src/gallium/state_trackers/vdpau/device.c b/src/gallium/state_trackers/vdpau/device.c
new file mode 100644
index 00000000000..83fcaff0282
--- /dev/null
+++ b/src/gallium/state_trackers/vdpau/device.c
@@ -0,0 +1,98 @@
+/**************************************************************************
+ *
+ * Copyright 2010 Younes Manton.
+ * 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 <vdpau/vdpau_x11.h>
+#include <pipe/p_compiler.h>
+#include <vl_winsys.h>
+#include <util/u_memory.h>
+#include "vdpau_private.h"
+
+VdpDeviceCreateX11 vdp_imp_device_create_x11;
+
+PUBLIC VdpStatus
+vdp_imp_device_create_x11(Display *display, int screen, VdpDevice *device, VdpGetProcAddress **get_proc_address)
+{
+ VdpStatus ret;
+ vlVdpDevice *dev;
+
+ if (!(display && device && get_proc_address))
+ return VDP_STATUS_INVALID_POINTER;
+
+ if (!vlCreateHTAB()) {
+ ret = VDP_STATUS_RESOURCES;
+ goto no_htab;
+ }
+
+ dev = CALLOC(1, sizeof(vlVdpDevice));
+ if (!dev) {
+ ret = VDP_STATUS_RESOURCES;
+ goto no_dev;
+ }
+
+ *device = vlAddDataHTAB(dev);
+ if (*device == 0) {
+ ret = VDP_STATUS_ERROR;
+ goto no_handle;
+ }
+
+ *get_proc_address = &vlVdpGetProcAddress;
+
+ return VDP_STATUS_OK;
+
+no_handle:
+ FREE(dev);
+no_dev:
+ vlDestroyHTAB();
+no_htab:
+ return ret;
+}
+
+VdpStatus vlVdpDeviceDestroy(VdpDevice device)
+{
+ vlVdpDevice *dev = vlGetDataHTAB(device);
+ if (!dev)
+ return VDP_STATUS_INVALID_HANDLE;
+ FREE(dev);
+ vlDestroyHTAB();
+
+ return VDP_STATUS_OK;
+}
+
+VdpStatus vlVdpGetProcAddress(VdpDevice device, VdpFuncId function_id, void **function_pointer)
+{
+ vlVdpDevice *dev = vlGetDataHTAB(device);
+ if (!dev)
+ return VDP_STATUS_INVALID_HANDLE;
+
+ if (!function_pointer)
+ return VDP_STATUS_INVALID_POINTER;
+
+ if (!vlGetFuncFTAB(function_id, function_pointer))
+ return VDP_STATUS_INVALID_FUNC_ID;
+
+ return VDP_STATUS_OK;
+}
diff --git a/src/gallium/state_trackers/vdpau/ftab.c b/src/gallium/state_trackers/vdpau/ftab.c
new file mode 100644
index 00000000000..a8a29857df7
--- /dev/null
+++ b/src/gallium/state_trackers/vdpau/ftab.c
@@ -0,0 +1,122 @@
+/**************************************************************************
+ *
+ * Copyright 2010 Younes Manton.
+ * 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 <assert.h>
+#include "vdpau_private.h"
+
+static void* ftab[67] =
+{
+ 0, /* VDP_FUNC_ID_GET_ERROR_STRING */
+ 0, /* VDP_FUNC_ID_GET_PROC_ADDRESS */
+ &vlVdpGetApiVersion, /* VDP_FUNC_ID_GET_API_VERSION */
+ 0,
+ &vlVdpGetInformationString, /* VDP_FUNC_ID_GET_INFORMATION_STRING */
+ &vlVdpDeviceDestroy, /* VDP_FUNC_ID_DEVICE_DESTROY */
+ 0, /* VDP_FUNC_ID_GENERATE_CSC_MATRIX */
+ &vlVdpVideoSurfaceQueryCapabilities, /* VDP_FUNC_ID_VIDEO_SURFACE_QUERY_CAPABILITIES */
+ &vlVdpVideoSurfaceQueryGetPutBitsYCbCrCapabilities, /* VDP_FUNC_ID_VIDEO_SURFACE_QUERY_GET_PUT_BITS_Y_CB_CR_CAPABILITIES */
+ 0, /* VDP_FUNC_ID_VIDEO_SURFACE_CREATE */
+ 0, /* VDP_FUNC_ID_VIDEO_SURFACE_DESTROY */
+ 0, /* VDP_FUNC_ID_VIDEO_SURFACE_GET_PARAMETERS */
+ 0, /* VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR */
+ 0, /* VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR */
+ &vlVdpOutputSurfaceQueryCapabilities, /* VDP_FUNC_ID_OUTPUT_SURFACE_QUERY_CAPABILITIES */
+ &vlVdpOutputSurfaceQueryGetPutBitsNativeCapabilities, /* VDP_FUNC_ID_OUTPUT_SURFACE_QUERY_GET_PUT_BITS_NATIVE_CAPABILITIES */
+ 0, /* VDP_FUNC_ID_OUTPUT_SURFACE_QUERY_PUT_BITS_INDEXED_CAPABILITIES */
+ &vlVdpOutputSurfaceQueryPutBitsYCbCrCapabilities, /* VDP_FUNC_ID_OUTPUT_SURFACE_QUERY_PUT_BITS_Y_CB_CR_CAPABILITIES */
+ 0, /* VDP_FUNC_ID_OUTPUT_SURFACE_CREATE */
+ 0, /* VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY */
+ 0, /* VDP_FUNC_ID_OUTPUT_SURFACE_GET_PARAMETERS */
+ 0, /* VDP_FUNC_ID_OUTPUT_SURFACE_GET_BITS_NATIVE */
+ 0, /* VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE */
+ 0, /* VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED */
+ 0, /* VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_Y_CB_CR */
+ &vlVdpBitmapSurfaceQueryCapabilities, /* VDP_FUNC_ID_BITMAP_SURFACE_QUERY_CAPABILITIES */
+ 0, /* VDP_FUNC_ID_BITMAP_SURFACE_CREATE */
+ 0, /* VDP_FUNC_ID_BITMAP_SURFACE_DESTROY */
+ 0, /* VDP_FUNC_ID_BITMAP_SURFACE_GET_PARAMETERS */
+ 0, /* VDP_FUNC_ID_BITMAP_SURFACE_PUT_BITS_NATIVE */
+ 0,
+ 0,
+ 0,
+ 0, /* VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE */
+ 0, /* VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_BITMAP_SURFACE */
+ 0, /* VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_VIDEO_SURFACE_LUMA */
+ &vlVdpDecoderQueryCapabilities, /* VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES */
+ 0, /* VDP_FUNC_ID_DECODER_CREATE */
+ 0, /* VDP_FUNC_ID_DECODER_DESTROY */
+ 0, /* VDP_FUNC_ID_DECODER_GET_PARAMETERS */
+ 0, /* VDP_FUNC_ID_DECODER_RENDER */
+ &vlVdpVideoMixerQueryFeatureSupport, /* VDP_FUNC_ID_VIDEO_MIXER_QUERY_FEATURE_SUPPORT */
+ &vlVdpVideoMixerQueryParameterSupport, /* VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_SUPPORT */
+ &vlVdpVideoMixerQueryAttributeSupport, /* VDP_FUNC_ID_VIDEO_MIXER_QUERY_ATTRIBUTE_SUPPORT */
+ &vlVdpVideoMixerQueryParameterValueRange, /* VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_VALUE_RANGE */
+ &vlVdpVideoMixerQueryAttributeValueRange, /* VDP_FUNC_ID_VIDEO_MIXER_QUERY_ATTRIBUTE_VALUE_RANGE */
+ 0, /* VDP_FUNC_ID_VIDEO_MIXER_CREATE */
+ 0, /* VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES */
+ 0, /* VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES */
+ 0, /* VDP_FUNC_ID_VIDEO_MIXER_GET_FEATURE_SUPPORT */
+ 0, /* VDP_FUNC_ID_VIDEO_MIXER_GET_FEATURE_ENABLES */
+ 0, /* VDP_FUNC_ID_VIDEO_MIXER_GET_PARAMETER_VALUES */
+ 0, /* VDP_FUNC_ID_VIDEO_MIXER_GET_ATTRIBUTE_VALUES */
+ 0, /* VDP_FUNC_ID_VIDEO_MIXER_DESTROY */
+ 0, /* VDP_FUNC_ID_VIDEO_MIXER_RENDER */
+ 0, /* VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_DESTROY */
+ 0, /* VDP_FUNC_ID_PRESENTATION_QUEUE_CREATE */
+ 0, /* VDP_FUNC_ID_PRESENTATION_QUEUE_DESTROY */
+ 0, /* VDP_FUNC_ID_PRESENTATION_QUEUE_SET_BACKGROUND_COLOR */
+ 0, /* VDP_FUNC_ID_PRESENTATION_QUEUE_GET_BACKGROUND_COLOR */
+ 0,
+ 0,
+ 0, /* VDP_FUNC_ID_PRESENTATION_QUEUE_GET_TIME */
+ 0, /* VDP_FUNC_ID_PRESENTATION_QUEUE_DISPLAY */
+ 0, /* VDP_FUNC_ID_PRESENTATION_QUEUE_BLOCK_UNTIL_SURFACE_IDLE */
+ 0, /* VDP_FUNC_ID_PRESENTATION_QUEUE_QUERY_SURFACE_STATUS */
+ 0 /* VDP_FUNC_ID_PREEMPTION_CALLBACK_REGISTER */
+};
+
+static void* ftab_winsys[1] =
+{
+ 0 /* VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_CREATE_X11 */
+};
+
+boolean vlGetFuncFTAB(VdpFuncId function_id, void **func)
+{
+ assert(func);
+ if (function_id < VDP_FUNC_ID_BASE_WINSYS) {
+ if (function_id > 66)
+ return FALSE;
+ *func = ftab[function_id];
+ }
+ else {
+ function_id -= VDP_FUNC_ID_BASE_WINSYS;
+ if (function_id > 0)
+ return FALSE;
+ *func = ftab_winsys[function_id];
+ }
+ return TRUE;
+}
diff --git a/src/gallium/state_trackers/vdpau/htab.c b/src/gallium/state_trackers/vdpau/htab.c
new file mode 100644
index 00000000000..0c958055374
--- /dev/null
+++ b/src/gallium/state_trackers/vdpau/htab.c
@@ -0,0 +1,94 @@
+/**************************************************************************
+ *
+ * Copyright 2010 Younes Manton.
+ * 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 <util/u_handle_table.h>
+#include <os/os_thread.h>
+#include "vdpau_private.h"
+
+#ifdef VL_HANDLES
+static struct handle_table *htab = NULL;
+pipe_static_mutex(htab_lock);
+#endif
+
+boolean vlCreateHTAB(void)
+{
+#ifdef VL_HANDLES
+ boolean ret;
+ /* Make sure handle table handles match VDPAU handles. */
+ assert(sizeof(unsigned) <= sizeof(vlHandle));
+ pipe_mutex_lock(htab_lock);
+ if (!htab)
+ htab = handle_table_create();
+ ret = htab != NULL;
+ pipe_mutex_unlock(htab_lock);
+ return ret;
+#else
+ return TRUE;
+#endif
+}
+
+void vlDestroyHTAB(void)
+{
+#ifdef VL_HANDLES
+ pipe_mutex_lock(htab_lock);
+ if (htab) {
+ handle_table_destroy(htab);
+ htab = NULL;
+ }
+ pipe_mutex_unlock(htab_lock);
+#endif
+}
+
+vlHandle vlAddDataHTAB(void *data)
+{
+ assert(data);
+#ifdef VL_HANDLES
+ vlHandle handle = 0;
+ pipe_mutex_lock(htab_lock);
+ if (htab)
+ handle = handle_table_add(htab, data);
+ pipe_mutex_unlock(htab_lock);
+ return handle;
+#else
+ return (vlHandle)data;
+#endif
+}
+
+void* vlGetDataHTAB(vlHandle handle)
+{
+ assert(handle);
+#ifdef VL_HANDLES
+ void *data = NULL;
+ pipe_mutex_lock(htab_lock);
+ if (htab)
+ data = handle_table_get(htab, handle);
+ pipe_mutex_unlock(htab_lock);
+ return data;
+#else
+ return (void*)handle;
+#endif
+}
diff --git a/src/gallium/state_trackers/vdpau/query.c b/src/gallium/state_trackers/vdpau/query.c
new file mode 100644
index 00000000000..57bd7fb7526
--- /dev/null
+++ b/src/gallium/state_trackers/vdpau/query.c
@@ -0,0 +1,171 @@
+/**************************************************************************
+ *
+ * Copyright 2010 Younes Manton.
+ * 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 "vdpau_private.h"
+
+VdpStatus
+vlVdpGetApiVersion(uint32_t *api_version)
+{
+ if (!api_version)
+ return VDP_STATUS_INVALID_POINTER;
+
+ *api_version = 1;
+ return VDP_STATUS_OK;
+}
+
+VdpStatus
+vlVdpGetInformationString(char const **information_string)
+{
+ if (!information_string)
+ return VDP_STATUS_INVALID_POINTER;
+
+ *information_string = "VDPAU-G3DVL";
+ return VDP_STATUS_OK;
+}
+
+VdpStatus
+vlVdpVideoSurfaceQueryCapabilities(VdpDevice device, VdpChromaType surface_chroma_type,
+ VdpBool *is_supported, uint32_t *max_width, uint32_t *max_height)
+{
+ if (!(is_supported && max_width && max_height))
+ return VDP_STATUS_INVALID_POINTER;
+
+ return VDP_STATUS_NO_IMPLEMENTATION;
+}
+
+VdpStatus
+vlVdpVideoSurfaceQueryGetPutBitsYCbCrCapabilities(VdpDevice device, VdpChromaType surface_chroma_type,
+ VdpYCbCrFormat bits_ycbcr_format,
+ VdpBool *is_supported)
+{
+ if (!is_supported)
+ return VDP_STATUS_INVALID_POINTER;
+
+ return VDP_STATUS_NO_IMPLEMENTATION;
+}
+
+VdpStatus
+vlVdpDecoderQueryCapabilities(VdpDevice device, VdpDecoderProfile profile,
+ VdpBool *is_supported, uint32_t *max_level, uint32_t *max_macroblocks,
+ uint32_t *max_width, uint32_t *max_height)
+{
+ if (!(is_supported && max_level && max_macroblocks && max_width && max_height))
+ return VDP_STATUS_INVALID_POINTER;
+
+ return VDP_STATUS_NO_IMPLEMENTATION;
+}
+
+VdpStatus
+vlVdpOutputSurfaceQueryCapabilities(VdpDevice device, VdpRGBAFormat surface_rgba_format,
+ VdpBool *is_supported, uint32_t *max_width, uint32_t *max_height)
+{
+ if (!(is_supported && max_width && max_height))
+ return VDP_STATUS_INVALID_POINTER;
+
+ return VDP_STATUS_NO_IMPLEMENTATION;
+}
+
+VdpStatus
+vlVdpOutputSurfaceQueryGetPutBitsNativeCapabilities(VdpDevice device, VdpRGBAFormat surface_rgba_format,
+ VdpBool *is_supported)
+{
+ if (!is_supported)
+ return VDP_STATUS_INVALID_POINTER;
+
+ return VDP_STATUS_NO_IMPLEMENTATION;
+}
+
+VdpStatus
+vlVdpOutputSurfaceQueryPutBitsYCbCrCapabilities(VdpDevice device, VdpRGBAFormat surface_rgba_format,
+ VdpYCbCrFormat bits_ycbcr_format,
+ VdpBool *is_supported)
+{
+ if (!is_supported)
+ return VDP_STATUS_INVALID_POINTER;
+
+ return VDP_STATUS_NO_IMPLEMENTATION;
+}
+
+VdpStatus
+vlVdpBitmapSurfaceQueryCapabilities(VdpDevice device, VdpRGBAFormat surface_rgba_format,
+ VdpBool *is_supported, uint32_t *max_width, uint32_t *max_height)
+{
+ if (!(is_supported && max_width && max_height))
+ return VDP_STATUS_INVALID_POINTER;
+
+ return VDP_STATUS_NO_IMPLEMENTATION;
+}
+
+VdpStatus
+vlVdpVideoMixerQueryFeatureSupport(VdpDevice device, VdpVideoMixerFeature feature,
+ VdpBool *is_supported)
+{
+ if (!is_supported)
+ return VDP_STATUS_INVALID_POINTER;
+
+ return VDP_STATUS_NO_IMPLEMENTATION;
+}
+
+VdpStatus
+vlVdpVideoMixerQueryParameterSupport(VdpDevice device, VdpVideoMixerParameter parameter,
+ VdpBool *is_supported)
+{
+ if (!is_supported)
+ return VDP_STATUS_INVALID_POINTER;
+
+ return VDP_STATUS_NO_IMPLEMENTATION;
+}
+
+VdpStatus
+vlVdpVideoMixerQueryParameterValueRange(VdpDevice device, VdpVideoMixerParameter parameter,
+ void *min_value, void *max_value)
+{
+ if (!(min_value && max_value))
+ return VDP_STATUS_INVALID_POINTER;
+
+ return VDP_STATUS_NO_IMPLEMENTATION;
+}
+
+VdpStatus
+vlVdpVideoMixerQueryAttributeSupport(VdpDevice device, VdpVideoMixerAttribute attribute,
+ VdpBool *is_supported)
+{
+ if (!is_supported)
+ return VDP_STATUS_INVALID_POINTER;
+
+ return VDP_STATUS_NO_IMPLEMENTATION;
+}
+
+VdpStatus
+vlVdpVideoMixerQueryAttributeValueRange(VdpDevice device, VdpVideoMixerAttribute attribute,
+ void *min_value, void *max_value)
+{
+ if (!(min_value && max_value))
+ return VDP_STATUS_INVALID_POINTER;
+
+ return VDP_STATUS_NO_IMPLEMENTATION;
+}
diff --git a/src/gallium/state_trackers/vdpau/vdpau_private.h b/src/gallium/state_trackers/vdpau/vdpau_private.h
new file mode 100644
index 00000000000..8f54ae657ce
--- /dev/null
+++ b/src/gallium/state_trackers/vdpau/vdpau_private.h
@@ -0,0 +1,59 @@
+/**************************************************************************
+ *
+ * Copyright 2010 Younes Manton.
+ * 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 <vdpau/vdpau.h>
+#include <pipe/p_compiler.h>
+
+typedef struct
+{
+ int dummy;
+} vlVdpDevice;
+
+typedef uint32_t vlHandle;
+
+boolean vlCreateHTAB(void);
+void vlDestroyHTAB(void);
+vlHandle vlAddDataHTAB(void *data);
+void* vlGetDataHTAB(vlHandle handle);
+boolean vlGetFuncFTAB(VdpFuncId function_id, void **func);
+
+VdpDeviceDestroy vlVdpDeviceDestroy;
+VdpGetProcAddress vlVdpGetProcAddress;
+VdpGetApiVersion vlVdpGetApiVersion;
+VdpGetInformationString vlVdpGetInformationString;
+VdpVideoSurfaceQueryCapabilities vlVdpVideoSurfaceQueryCapabilities;
+VdpVideoSurfaceQueryGetPutBitsYCbCrCapabilities vlVdpVideoSurfaceQueryGetPutBitsYCbCrCapabilities;
+VdpDecoderQueryCapabilities vlVdpDecoderQueryCapabilities;
+VdpOutputSurfaceQueryCapabilities vlVdpOutputSurfaceQueryCapabilities;
+VdpOutputSurfaceQueryGetPutBitsNativeCapabilities vlVdpOutputSurfaceQueryGetPutBitsNativeCapabilities;
+VdpOutputSurfaceQueryPutBitsYCbCrCapabilities vlVdpOutputSurfaceQueryPutBitsYCbCrCapabilities;
+VdpBitmapSurfaceQueryCapabilities vlVdpBitmapSurfaceQueryCapabilities;
+VdpVideoMixerQueryFeatureSupport vlVdpVideoMixerQueryFeatureSupport;
+VdpVideoMixerQueryParameterSupport vlVdpVideoMixerQueryParameterSupport;
+VdpVideoMixerQueryParameterValueRange vlVdpVideoMixerQueryParameterValueRange;
+VdpVideoMixerQueryAttributeSupport vlVdpVideoMixerQueryAttributeSupport;
+VdpVideoMixerQueryAttributeValueRange vlVdpVideoMixerQueryAttributeValueRange;
diff --git a/src/gallium/state_trackers/xorg/xvmc/Makefile b/src/gallium/state_trackers/xorg/xvmc/Makefile
new file mode 100644
index 00000000000..126dc6d58f1
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xvmc/Makefile
@@ -0,0 +1,16 @@
+TOP = ../../../../..
+include $(TOP)/configs/current
+
+LIBNAME = xvmctracker
+
+LIBRARY_INCLUDES = \
+ $(shell pkg-config --cflags-only-I xvmc) \
+ -I$(TOP)/src/gallium/winsys/g3dvl
+
+C_SOURCES = block.c \
+ surface.c \
+ context.c \
+ subpicture.c \
+ attributes.c
+
+include ../../../Makefile.template
diff --git a/src/gallium/state_trackers/xorg/xvmc/attributes.c b/src/gallium/state_trackers/xorg/xvmc/attributes.c
new file mode 100644
index 00000000000..d23d8635b66
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xvmc/attributes.c
@@ -0,0 +1,50 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 <assert.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/Xvlib.h>
+#include <X11/extensions/XvMClib.h>
+#include <pipe/p_compiler.h>
+
+PUBLIC
+XvAttribute* XvMCQueryAttributes(Display *dpy, XvMCContext *context, int *number)
+{
+ return NULL;
+}
+
+PUBLIC
+Status XvMCSetAttribute(Display *dpy, XvMCContext *context, Atom attribute, int value)
+{
+ return BadImplementation;
+}
+
+PUBLIC
+Status XvMCGetAttribute(Display *dpy, XvMCContext *context, Atom attribute, int *value)
+{
+ return BadImplementation;
+}
diff --git a/src/gallium/state_trackers/xorg/xvmc/block.c b/src/gallium/state_trackers/xorg/xvmc/block.c
new file mode 100644
index 00000000000..c7da7a84a7b
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xvmc/block.c
@@ -0,0 +1,92 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 <assert.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/XvMClib.h>
+#include <util/u_memory.h>
+#include "xvmc_private.h"
+
+PUBLIC
+Status XvMCCreateBlocks(Display *dpy, XvMCContext *context, unsigned int num_blocks, XvMCBlockArray *blocks)
+{
+ assert(dpy);
+
+ if (!context)
+ return XvMCBadContext;
+ if (num_blocks == 0)
+ return BadValue;
+
+ assert(blocks);
+
+ blocks->context_id = context->context_id;
+ blocks->num_blocks = num_blocks;
+ blocks->blocks = MALLOC(BLOCK_SIZE_BYTES * num_blocks);
+ blocks->privData = NULL;
+
+ return Success;
+}
+
+PUBLIC
+Status XvMCDestroyBlocks(Display *dpy, XvMCBlockArray *blocks)
+{
+ assert(dpy);
+ assert(blocks);
+ FREE(blocks->blocks);
+
+ return Success;
+}
+
+PUBLIC
+Status XvMCCreateMacroBlocks(Display *dpy, XvMCContext *context, unsigned int num_blocks, XvMCMacroBlockArray *blocks)
+{
+ assert(dpy);
+
+ if (!context)
+ return XvMCBadContext;
+ if (num_blocks == 0)
+ return BadValue;
+
+ assert(blocks);
+
+ blocks->context_id = context->context_id;
+ blocks->num_blocks = num_blocks;
+ blocks->macro_blocks = MALLOC(sizeof(XvMCMacroBlock) * num_blocks);
+ blocks->privData = NULL;
+
+ return Success;
+}
+
+PUBLIC
+Status XvMCDestroyMacroBlocks(Display *dpy, XvMCMacroBlockArray *blocks)
+{
+ assert(dpy);
+ assert(blocks);
+ FREE(blocks->macro_blocks);
+
+ return Success;
+}
diff --git a/src/gallium/state_trackers/xorg/xvmc/context.c b/src/gallium/state_trackers/xorg/xvmc/context.c
new file mode 100644
index 00000000000..06a1633288b
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xvmc/context.c
@@ -0,0 +1,298 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 <assert.h>
+#include <X11/Xlibint.h>
+#include <X11/extensions/XvMClib.h>
+#include <pipe/p_screen.h>
+#include <pipe/p_video_context.h>
+#include <pipe/p_video_state.h>
+#include <pipe/p_state.h>
+#include <vl_winsys.h>
+#include <util/u_memory.h>
+#include <vl/vl_csc.h>
+#include "xvmc_private.h"
+
+static Status Validate(Display *dpy, XvPortID port, int surface_type_id,
+ unsigned int width, unsigned int height, int flags,
+ bool *found_port, int *screen, int *chroma_format,
+ int *mc_type, int *surface_flags,
+ unsigned short *subpic_max_w,
+ unsigned short *subpic_max_h)
+{
+ bool found_surface = false;
+ XvAdaptorInfo *adaptor_info;
+ unsigned int num_adaptors;
+ int num_types;
+ unsigned int max_width, max_height;
+ Status ret;
+
+ assert(dpy);
+ assert(found_port);
+ assert(screen);
+ assert(chroma_format);
+ assert(mc_type);
+ assert(surface_flags);
+ assert(subpic_max_w);
+ assert(subpic_max_h);
+
+ *found_port = false;
+
+ for (unsigned int i = 0; i < XScreenCount(dpy); ++i) {
+ ret = XvQueryAdaptors(dpy, XRootWindow(dpy, i), &num_adaptors, &adaptor_info);
+ if (ret != Success)
+ return ret;
+
+ for (unsigned int j = 0; j < num_adaptors && !*found_port; ++j) {
+ for (unsigned int k = 0; k < adaptor_info[j].num_ports && !*found_port; ++k) {
+ XvMCSurfaceInfo *surface_info;
+
+ if (adaptor_info[j].base_id + k != port)
+ continue;
+
+ *found_port = true;
+
+ surface_info = XvMCListSurfaceTypes(dpy, adaptor_info[j].base_id, &num_types);
+ if (!surface_info) {
+ XvFreeAdaptorInfo(adaptor_info);
+ return BadAlloc;
+ }
+
+ for (unsigned int l = 0; l < num_types && !found_surface; ++l) {
+ if (surface_info[l].surface_type_id != surface_type_id)
+ continue;
+
+ found_surface = true;
+ max_width = surface_info[l].max_width;
+ max_height = surface_info[l].max_height;
+ *chroma_format = surface_info[l].chroma_format;
+ *mc_type = surface_info[l].mc_type;
+ *surface_flags = surface_info[l].flags;
+ *subpic_max_w = surface_info[l].subpicture_max_width;
+ *subpic_max_h = surface_info[l].subpicture_max_height;
+ *screen = i;
+
+ XVMC_MSG(XVMC_TRACE, "[XvMC] Found requested context surface format.\n" \
+ "[XvMC] screen=%u, port=%u\n" \
+ "[XvMC] id=0x%08X\n" \
+ "[XvMC] max width=%u, max height=%u\n" \
+ "[XvMC] chroma format=0x%08X\n" \
+ "[XvMC] acceleration level=0x%08X\n" \
+ "[XvMC] flags=0x%08X\n" \
+ "[XvMC] subpicture max width=%u, max height=%u\n",
+ i, port, surface_type_id, max_width, max_height, *chroma_format,
+ *mc_type, *surface_flags, *subpic_max_w, *subpic_max_h);
+ }
+
+ XFree(surface_info);
+ }
+ }
+
+ XvFreeAdaptorInfo(adaptor_info);
+ }
+
+ if (!*found_port) {
+ XVMC_MSG(XVMC_ERR, "[XvMC] Could not find a suitable port.\n");
+ return XvBadPort;
+ }
+ if (!found_surface) {
+ XVMC_MSG(XVMC_ERR, "[XvMC] Could not find a suitable surface.\n");
+ return BadMatch;
+ }
+ if (width > max_width || height > max_height) {
+ XVMC_MSG(XVMC_ERR, "[XvMC] Requested context dimensions (w=%u,h=%u) too large (max w=%u,h=%u).\n",
+ width, height, max_width, max_height);
+ return BadValue;
+ }
+ if (flags != XVMC_DIRECT && flags != 0) {
+ XVMC_MSG(XVMC_ERR, "[XvMC] Invalid context flags 0x%08X.\n", flags);
+ return BadValue;
+ }
+
+ return Success;
+}
+
+static enum pipe_video_profile ProfileToPipe(int xvmc_profile)
+{
+ if (xvmc_profile & XVMC_MPEG_1)
+ assert(0);
+ if (xvmc_profile & XVMC_MPEG_2)
+ return PIPE_VIDEO_PROFILE_MPEG2_MAIN;
+ if (xvmc_profile & XVMC_H263)
+ assert(0);
+ if (xvmc_profile & XVMC_MPEG_4)
+ assert(0);
+
+ assert(0);
+
+ XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized profile 0x%08X.\n", xvmc_profile);
+
+ return -1;
+}
+
+static enum pipe_video_chroma_format FormatToPipe(int xvmc_format)
+{
+ switch (xvmc_format) {
+ case XVMC_CHROMA_FORMAT_420:
+ return PIPE_VIDEO_CHROMA_FORMAT_420;
+ case XVMC_CHROMA_FORMAT_422:
+ return PIPE_VIDEO_CHROMA_FORMAT_422;
+ case XVMC_CHROMA_FORMAT_444:
+ return PIPE_VIDEO_CHROMA_FORMAT_444;
+ default:
+ assert(0);
+ }
+
+ XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized format 0x%08X.\n", xvmc_format);
+
+ return -1;
+}
+
+PUBLIC
+Status XvMCCreateContext(Display *dpy, XvPortID port, int surface_type_id,
+ int width, int height, int flags, XvMCContext *context)
+{
+ bool found_port;
+ int scrn;
+ int chroma_format;
+ int mc_type;
+ int surface_flags;
+ unsigned short subpic_max_w;
+ unsigned short subpic_max_h;
+ Status ret;
+ struct vl_screen *vscreen;
+ struct vl_context *vctx;
+ XvMCContextPrivate *context_priv;
+ float csc[16];
+
+ XVMC_MSG(XVMC_TRACE, "[XvMC] Creating context %p.\n", context);
+
+ assert(dpy);
+
+ if (!context)
+ return XvMCBadContext;
+
+ ret = Validate(dpy, port, surface_type_id, width, height, flags,
+ &found_port, &scrn, &chroma_format, &mc_type, &surface_flags,
+ &subpic_max_w, &subpic_max_h);
+
+ /* Success and XvBadPort have the same value */
+ if (ret != Success || !found_port)
+ return ret;
+
+ /* XXX: Current limits */
+ if (chroma_format != XVMC_CHROMA_FORMAT_420) {
+ XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Unsupported chroma format.\n");
+ return BadImplementation;
+ }
+ if (mc_type != (XVMC_IDCT | XVMC_MOCOMP | XVMC_MPEG_2)) {
+ XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Non-MPEG2/Mocomp/iDCT acceleration unsupported.\n");
+ return BadImplementation;
+ }
+ if (surface_flags & XVMC_INTRA_UNSIGNED) {
+ XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Unsigned intra unsupported.\n");
+ return BadImplementation;
+ }
+
+ context_priv = CALLOC(1, sizeof(XvMCContextPrivate));
+ if (!context_priv)
+ return BadAlloc;
+
+ /* TODO: Reuse screen if process creates another context */
+ vscreen = vl_screen_create(dpy, scrn);
+
+ if (!vscreen) {
+ XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL screen.\n");
+ FREE(context_priv);
+ return BadAlloc;
+ }
+
+ vctx = vl_video_create(vscreen, ProfileToPipe(mc_type),
+ FormatToPipe(chroma_format), width, height);
+
+ if (!vctx) {
+ XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL context.\n");
+ vl_screen_destroy(vscreen);
+ FREE(context_priv);
+ return BadAlloc;
+ }
+
+ /* TODO: Define some Xv attribs to allow users to specify color standard, procamp */
+ vl_csc_get_matrix
+ (
+ debug_get_bool_option("G3DVL_NO_CSC", FALSE) ?
+ VL_CSC_COLOR_STANDARD_IDENTITY : VL_CSC_COLOR_STANDARD_BT_601,
+ NULL, true, csc
+ );
+ vctx->vpipe->set_csc_matrix(vctx->vpipe, csc);
+
+ context_priv->vctx = vctx;
+ context_priv->subpicture_max_width = subpic_max_w;
+ context_priv->subpicture_max_height = subpic_max_h;
+
+ context->context_id = XAllocID(dpy);
+ context->surface_type_id = surface_type_id;
+ context->width = width;
+ context->height = height;
+ context->flags = flags;
+ context->port = port;
+ context->privData = context_priv;
+
+ SyncHandle();
+
+ XVMC_MSG(XVMC_TRACE, "[XvMC] Context %p created.\n", context);
+
+ return Success;
+}
+
+PUBLIC
+Status XvMCDestroyContext(Display *dpy, XvMCContext *context)
+{
+ struct vl_screen *vscreen;
+ struct vl_context *vctx;
+ XvMCContextPrivate *context_priv;
+
+ XVMC_MSG(XVMC_TRACE, "[XvMC] Destroying context %p.\n", context);
+
+ assert(dpy);
+
+ if (!context || !context->privData)
+ return XvMCBadContext;
+
+ context_priv = context->privData;
+ vctx = context_priv->vctx;
+ pipe_surface_reference(&context_priv->backbuffer, NULL);
+ vscreen = vctx->vscreen;
+ vl_video_destroy(vctx);
+ vl_screen_destroy(vscreen);
+ FREE(context_priv);
+ context->privData = NULL;
+
+ XVMC_MSG(XVMC_TRACE, "[XvMC] Context %p destroyed.\n", context);
+
+ return Success;
+}
diff --git a/src/gallium/state_trackers/xorg/xvmc/subpicture.c b/src/gallium/state_trackers/xorg/xvmc/subpicture.c
new file mode 100644
index 00000000000..1c70d1deb66
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xvmc/subpicture.c
@@ -0,0 +1,443 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 <assert.h>
+#include <X11/Xlibint.h>
+#include <X11/extensions/XvMClib.h>
+#include <xorg/fourcc.h>
+#include <vl_winsys.h>
+#include <pipe/p_screen.h>
+#include <pipe/p_video_context.h>
+#include <pipe/p_state.h>
+#include <util/u_memory.h>
+#include <util/u_math.h>
+#include "xvmc_private.h"
+
+#define FOURCC_RGB 0x0000003
+
+static enum pipe_format XvIDToPipe(int xvimage_id)
+{
+ switch (xvimage_id) {
+ case FOURCC_RGB:
+ return PIPE_FORMAT_B8G8R8X8_UNORM;
+ default:
+ XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized Xv image ID 0x%08X.\n", xvimage_id);
+ return PIPE_FORMAT_NONE;
+ }
+}
+
+static int PipeToComponentOrder(enum pipe_format format, char *component_order)
+{
+ assert(component_order);
+
+ switch (format) {
+ case PIPE_FORMAT_B8G8R8X8_UNORM:
+ return 0;
+ default:
+ XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized PIPE_FORMAT 0x%08X.\n", format);
+ component_order[0] = 0;
+ component_order[1] = 0;
+ component_order[2] = 0;
+ component_order[3] = 0;
+ }
+
+ return 0;
+}
+
+static Status Validate(Display *dpy, XvPortID port, int surface_type_id, int xvimage_id)
+{
+ XvImageFormatValues *subpictures;
+ int num_subpics;
+ unsigned int i;
+
+ subpictures = XvMCListSubpictureTypes(dpy, port, surface_type_id, &num_subpics);
+ if (num_subpics < 1) {
+ if (subpictures)
+ XFree(subpictures);
+ return BadMatch;
+ }
+ if (!subpictures)
+ return BadAlloc;
+
+ for (i = 0; i < num_subpics; ++i) {
+ if (subpictures[i].id == xvimage_id) {
+ XVMC_MSG(XVMC_TRACE, "[XvMC] Found requested subpicture format.\n" \
+ "[XvMC] port=%u\n" \
+ "[XvMC] surface id=0x%08X\n" \
+ "[XvMC] image id=0x%08X\n" \
+ "[XvMC] type=%08X\n" \
+ "[XvMC] byte order=%08X\n" \
+ "[XvMC] bits per pixel=%u\n" \
+ "[XvMC] format=%08X\n" \
+ "[XvMC] num planes=%d\n",
+ port, surface_type_id, xvimage_id, subpictures[i].type, subpictures[i].byte_order,
+ subpictures[i].bits_per_pixel, subpictures[i].format, subpictures[i].num_planes);
+ if (subpictures[i].type == XvRGB) {
+ XVMC_MSG(XVMC_TRACE, "[XvMC] depth=%d\n" \
+ "[XvMC] red mask=0x%08X\n" \
+ "[XvMC] green mask=0x%08X\n" \
+ "[XvMC] blue mask=0x%08X\n",
+ subpictures[i].depth, subpictures[i].red_mask, subpictures[i].green_mask, subpictures[i].blue_mask);
+ }
+ else if (subpictures[i].type == XvYUV) {
+ XVMC_MSG(XVMC_TRACE, "[XvMC] y sample bits=0x%08X\n" \
+ "[XvMC] u sample bits=0x%08X\n" \
+ "[XvMC] v sample bits=0x%08X\n" \
+ "[XvMC] horz y period=%u\n" \
+ "[XvMC] horz u period=%u\n" \
+ "[XvMC] horz v period=%u\n" \
+ "[XvMC] vert y period=%u\n" \
+ "[XvMC] vert u period=%u\n" \
+ "[XvMC] vert v period=%u\n",
+ subpictures[i].y_sample_bits, subpictures[i].u_sample_bits, subpictures[i].v_sample_bits,
+ subpictures[i].horz_y_period, subpictures[i].horz_u_period, subpictures[i].horz_v_period,
+ subpictures[i].vert_y_period, subpictures[i].vert_u_period, subpictures[i].vert_v_period);
+ }
+ break;
+ }
+ }
+
+ XFree(subpictures);
+
+ return i < num_subpics ? Success : BadMatch;
+}
+
+PUBLIC
+Status XvMCCreateSubpicture(Display *dpy, XvMCContext *context, XvMCSubpicture *subpicture,
+ unsigned short width, unsigned short height, int xvimage_id)
+{
+ XvMCContextPrivate *context_priv;
+ XvMCSubpicturePrivate *subpicture_priv;
+ struct pipe_video_context *vpipe;
+ struct pipe_resource template;
+ struct pipe_resource *tex;
+ struct pipe_surface surf_template;
+ Status ret;
+
+ XVMC_MSG(XVMC_TRACE, "[XvMC] Creating subpicture %p.\n", subpicture);
+
+ assert(dpy);
+
+ if (!context)
+ return XvMCBadContext;
+
+ context_priv = context->privData;
+ vpipe = context_priv->vctx->vpipe;
+
+ if (!subpicture)
+ return XvMCBadSubpicture;
+
+ if (width > context_priv->subpicture_max_width ||
+ height > context_priv->subpicture_max_height)
+ return BadValue;
+
+ ret = Validate(dpy, context->port, context->surface_type_id, xvimage_id);
+ if (ret != Success)
+ return ret;
+
+ subpicture_priv = CALLOC(1, sizeof(XvMCSubpicturePrivate));
+ if (!subpicture_priv)
+ return BadAlloc;
+
+ memset(&template, 0, sizeof(struct pipe_resource));
+ template.target = PIPE_TEXTURE_2D;
+ template.format = XvIDToPipe(xvimage_id);
+ template.last_level = 0;
+ if (vpipe->get_param(vpipe, PIPE_CAP_NPOT_TEXTURES)) {
+ template.width0 = width;
+ template.height0 = height;
+ }
+ else {
+ template.width0 = util_next_power_of_two(width);
+ template.height0 = util_next_power_of_two(height);
+ }
+ template.depth0 = 1;
+ template.usage = PIPE_USAGE_DYNAMIC;
+ template.bind = PIPE_BIND_SAMPLER_VIEW;
+ template.flags = 0;
+
+ subpicture_priv->context = context;
+ tex = vpipe->screen->resource_create(vpipe->screen, &template);
+
+ memset(&surf_template, 0, sizeof(surf_template));
+ surf_template.format = tex->format;
+ surf_template.usage = PIPE_BIND_SAMPLER_VIEW;
+ subpicture_priv->sfc = vpipe->create_surface(vpipe, tex, &surf_template);
+ pipe_resource_reference(&tex, NULL);
+ if (!subpicture_priv->sfc) {
+ FREE(subpicture_priv);
+ return BadAlloc;
+ }
+
+ subpicture->subpicture_id = XAllocID(dpy);
+ subpicture->context_id = context->context_id;
+ subpicture->xvimage_id = xvimage_id;
+ subpicture->width = width;
+ subpicture->height = height;
+ subpicture->num_palette_entries = 0;
+ subpicture->entry_bytes = PipeToComponentOrder(template.format, subpicture->component_order);
+ subpicture->privData = subpicture_priv;
+
+ SyncHandle();
+
+ XVMC_MSG(XVMC_TRACE, "[XvMC] Subpicture %p created.\n", subpicture);
+
+ return Success;
+}
+
+PUBLIC
+Status XvMCClearSubpicture(Display *dpy, XvMCSubpicture *subpicture, short x, short y,
+ unsigned short width, unsigned short height, unsigned int color)
+{
+ XvMCSubpicturePrivate *subpicture_priv;
+ XvMCContextPrivate *context_priv;
+
+ assert(dpy);
+
+ if (!subpicture)
+ return XvMCBadSubpicture;
+
+ subpicture_priv = subpicture->privData;
+ context_priv = subpicture_priv->context->privData;
+ /* TODO: Assert clear rect is within bounds? Or clip? */
+ context_priv->vctx->vpipe->surface_fill(context_priv->vctx->vpipe,
+ subpicture_priv->sfc, x, y,
+ width, height, color);
+
+ return Success;
+}
+
+PUBLIC
+Status XvMCCompositeSubpicture(Display *dpy, XvMCSubpicture *subpicture, XvImage *image,
+ short srcx, short srcy, unsigned short width, unsigned short height,
+ short dstx, short dsty)
+{
+ XvMCSubpicturePrivate *subpicture_priv;
+ XvMCContextPrivate *context_priv;
+ struct pipe_video_context *vpipe;
+ struct pipe_transfer *xfer;
+ unsigned char *src, *dst, *dst_line;
+ unsigned x, y;
+ struct pipe_box dst_box = {dstx, dsty, 0, width, height, 1};
+
+ XVMC_MSG(XVMC_TRACE, "[XvMC] Compositing subpicture %p.\n", subpicture);
+
+ assert(dpy);
+
+ if (!subpicture)
+ return XvMCBadSubpicture;
+
+ assert(image);
+
+ if (subpicture->xvimage_id != image->id)
+ return BadMatch;
+
+ /* No planar support for now */
+ if (image->num_planes != 1)
+ return BadMatch;
+
+ subpicture_priv = subpicture->privData;
+ context_priv = subpicture_priv->context->privData;
+ vpipe = context_priv->vctx->vpipe;
+
+ /* TODO: Assert rects are within bounds? Or clip? */
+
+ xfer = vpipe->get_transfer(vpipe, subpicture_priv->sfc->texture,
+ 0, PIPE_TRANSFER_WRITE, &dst_box);
+ if (!xfer)
+ return BadAlloc;
+
+ src = image->data;
+ dst = vpipe->transfer_map(vpipe, xfer);
+ if (!dst) {
+ vpipe->transfer_destroy(vpipe, xfer);
+ return BadAlloc;
+ }
+
+ switch (image->id) {
+ case FOURCC_RGB:
+ assert(subpicture_priv->sfc->format == XvIDToPipe(image->id));
+ for (y = 0; y < height; ++y) {
+ dst_line = dst;
+ for (x = 0; x < width; ++x, src += 3, dst_line += 4) {
+ dst_line[0] = src[2]; /* B */
+ dst_line[1] = src[1]; /* G */
+ dst_line[2] = src[0]; /* R */
+ }
+ dst += xfer->stride;
+ }
+ break;
+ default:
+ XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized Xv image ID 0x%08X.\n", image->id);
+ }
+
+ vpipe->transfer_unmap(vpipe, xfer);
+ vpipe->transfer_destroy(vpipe, xfer);
+
+ XVMC_MSG(XVMC_TRACE, "[XvMC] Subpicture %p composited.\n", subpicture);
+
+ return Success;
+}
+
+PUBLIC
+Status XvMCDestroySubpicture(Display *dpy, XvMCSubpicture *subpicture)
+{
+ XvMCSubpicturePrivate *subpicture_priv;
+
+ XVMC_MSG(XVMC_TRACE, "[XvMC] Destroying subpicture %p.\n", subpicture);
+
+ assert(dpy);
+
+ if (!subpicture)
+ return XvMCBadSubpicture;
+
+ subpicture_priv = subpicture->privData;
+ pipe_surface_reference(&subpicture_priv->sfc, NULL);
+ FREE(subpicture_priv);
+
+ XVMC_MSG(XVMC_TRACE, "[XvMC] Subpicture %p destroyed.\n", subpicture);
+
+ return Success;
+}
+
+PUBLIC
+Status XvMCSetSubpicturePalette(Display *dpy, XvMCSubpicture *subpicture, unsigned char *palette)
+{
+ assert(dpy);
+
+ if (!subpicture)
+ return XvMCBadSubpicture;
+
+ assert(palette);
+
+ /* We don't support paletted subpictures */
+ return BadMatch;
+}
+
+PUBLIC
+Status XvMCBlendSubpicture(Display *dpy, XvMCSurface *target_surface, XvMCSubpicture *subpicture,
+ short subx, short suby, unsigned short subw, unsigned short subh,
+ short surfx, short surfy, unsigned short surfw, unsigned short surfh)
+{
+ XvMCSurfacePrivate *surface_priv;
+ XvMCSubpicturePrivate *subpicture_priv;
+
+ XVMC_MSG(XVMC_TRACE, "[XvMC] Associating subpicture %p with surface %p.\n", subpicture, target_surface);
+
+ assert(dpy);
+
+ if (!target_surface)
+ return XvMCBadSurface;
+
+ if (!subpicture)
+ return XvMCBadSubpicture;
+
+ if (target_surface->context_id != subpicture->context_id)
+ return BadMatch;
+
+ /* TODO: Verify against subpicture independent scaling */
+
+ surface_priv = target_surface->privData;
+ subpicture_priv = subpicture->privData;
+
+ /* TODO: Assert rects are within bounds? Or clip? */
+
+ surface_priv->subpicture = subpicture;
+ surface_priv->subx = subx;
+ surface_priv->suby = suby;
+ surface_priv->subw = subw;
+ surface_priv->subh = subh;
+ surface_priv->surfx = surfx;
+ surface_priv->surfy = surfy;
+ surface_priv->surfw = surfw;
+ surface_priv->surfh = surfh;
+ subpicture_priv->surface = target_surface;
+
+ return Success;
+}
+
+PUBLIC
+Status XvMCBlendSubpicture2(Display *dpy, XvMCSurface *source_surface, XvMCSurface *target_surface,
+ XvMCSubpicture *subpicture, short subx, short suby, unsigned short subw, unsigned short subh,
+ short surfx, short surfy, unsigned short surfw, unsigned short surfh)
+{
+ assert(dpy);
+
+ if (!source_surface || !target_surface)
+ return XvMCBadSurface;
+
+ if (!subpicture)
+ return XvMCBadSubpicture;
+
+ if (source_surface->context_id != subpicture->context_id)
+ return BadMatch;
+
+ if (source_surface->context_id != subpicture->context_id)
+ return BadMatch;
+
+ /* TODO: Assert rects are within bounds? Or clip? */
+
+ return Success;
+}
+
+PUBLIC
+Status XvMCSyncSubpicture(Display *dpy, XvMCSubpicture *subpicture)
+{
+ assert(dpy);
+
+ if (!subpicture)
+ return XvMCBadSubpicture;
+
+ return Success;
+}
+
+PUBLIC
+Status XvMCFlushSubpicture(Display *dpy, XvMCSubpicture *subpicture)
+{
+ assert(dpy);
+
+ if (!subpicture)
+ return XvMCBadSubpicture;
+
+ return Success;
+}
+
+PUBLIC
+Status XvMCGetSubpictureStatus(Display *dpy, XvMCSubpicture *subpicture, int *status)
+{
+ assert(dpy);
+
+ if (!subpicture)
+ return XvMCBadSubpicture;
+
+ assert(status);
+
+ /* TODO */
+ *status = 0;
+
+ return Success;
+}
diff --git a/src/gallium/state_trackers/xorg/xvmc/surface.c b/src/gallium/state_trackers/xorg/xvmc/surface.c
new file mode 100644
index 00000000000..d7285a478fb
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xvmc/surface.c
@@ -0,0 +1,525 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 <assert.h>
+#include <stdio.h>
+#include <X11/Xlibint.h>
+#include <vl_winsys.h>
+#include <pipe/p_video_context.h>
+#include <pipe/p_video_state.h>
+#include <pipe/p_state.h>
+#include <util/u_inlines.h>
+#include <util/u_memory.h>
+#include <util/u_math.h>
+#include "xvmc_private.h"
+
+static enum pipe_mpeg12_macroblock_type TypeToPipe(int xvmc_mb_type)
+{
+ if (xvmc_mb_type & XVMC_MB_TYPE_INTRA)
+ return PIPE_MPEG12_MACROBLOCK_TYPE_INTRA;
+ if ((xvmc_mb_type & (XVMC_MB_TYPE_MOTION_FORWARD | XVMC_MB_TYPE_MOTION_BACKWARD)) == XVMC_MB_TYPE_MOTION_FORWARD)
+ return PIPE_MPEG12_MACROBLOCK_TYPE_FWD;
+ if ((xvmc_mb_type & (XVMC_MB_TYPE_MOTION_FORWARD | XVMC_MB_TYPE_MOTION_BACKWARD)) == XVMC_MB_TYPE_MOTION_BACKWARD)
+ return PIPE_MPEG12_MACROBLOCK_TYPE_BKWD;
+ if ((xvmc_mb_type & (XVMC_MB_TYPE_MOTION_FORWARD | XVMC_MB_TYPE_MOTION_BACKWARD)) == (XVMC_MB_TYPE_MOTION_FORWARD | XVMC_MB_TYPE_MOTION_BACKWARD))
+ return PIPE_MPEG12_MACROBLOCK_TYPE_BI;
+
+ assert(0);
+
+ XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized mb type 0x%08X.\n", xvmc_mb_type);
+
+ return -1;
+}
+
+static enum pipe_mpeg12_picture_type PictureToPipe(int xvmc_pic)
+{
+ switch (xvmc_pic) {
+ case XVMC_TOP_FIELD:
+ return PIPE_MPEG12_PICTURE_TYPE_FIELD_TOP;
+ case XVMC_BOTTOM_FIELD:
+ return PIPE_MPEG12_PICTURE_TYPE_FIELD_BOTTOM;
+ case XVMC_FRAME_PICTURE:
+ return PIPE_MPEG12_PICTURE_TYPE_FRAME;
+ default:
+ assert(0);
+ }
+
+ XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized picture type 0x%08X.\n", xvmc_pic);
+
+ return -1;
+}
+
+static enum pipe_mpeg12_motion_type MotionToPipe(int xvmc_motion_type, unsigned int xvmc_picture_structure)
+{
+ switch (xvmc_motion_type) {
+ case XVMC_PREDICTION_FRAME:
+ if (xvmc_picture_structure == XVMC_FRAME_PICTURE)
+ return PIPE_MPEG12_MOTION_TYPE_FRAME;
+ else
+ return PIPE_MPEG12_MOTION_TYPE_16x8;
+ break;
+ case XVMC_PREDICTION_FIELD:
+ return PIPE_MPEG12_MOTION_TYPE_FIELD;
+ case XVMC_PREDICTION_DUAL_PRIME:
+ return PIPE_MPEG12_MOTION_TYPE_DUALPRIME;
+ default:
+ assert(0);
+ }
+
+ XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized motion type 0x%08X (with picture structure 0x%08X).\n", xvmc_motion_type, xvmc_picture_structure);
+
+ return -1;
+}
+
+#if 0
+static bool
+CreateOrResizeBackBuffer(struct vl_context *vctx, unsigned int width, unsigned int height,
+ struct pipe_surface **backbuffer)
+{
+ struct pipe_video_context *vpipe;
+ struct pipe_resource template;
+ struct pipe_resource *tex;
+
+ assert(vctx);
+
+ vpipe = vctx->vpipe;
+
+ if (*backbuffer) {
+ if ((*backbuffer)->width != width || (*backbuffer)->height != height)
+ pipe_surface_reference(backbuffer, NULL);
+ else
+ return true;
+ }
+
+ memset(&template, 0, sizeof(struct pipe_resource));
+ template.target = PIPE_TEXTURE_2D;
+ template.format = vctx->vscreen->format;
+ template.last_level = 0;
+ template.width0 = width;
+ template.height0 = height;
+ template.depth0 = 1;
+ template.usage = PIPE_USAGE_DEFAULT;
+ template.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_BLIT_SOURCE;
+ template.flags = 0;
+
+ tex = vpipe->screen->resource_create(vpipe->screen, &template);
+ if (!tex)
+ return false;
+
+ *backbuffer = vpipe->screen->get_tex_surface(vpipe->screen, tex, 0, 0, 0,
+ template.bind);
+ pipe_resource_reference(&tex, NULL);
+
+ if (!*backbuffer)
+ return false;
+
+ /* Clear the backbuffer in case the video doesn't cover the whole window */
+ /* FIXME: Need to clear every time a frame moves and leaves dirty rects */
+ vpipe->surface_fill(vpipe, *backbuffer, 0, 0, width, height, 0);
+
+ return true;
+}
+#endif
+
+static void
+MacroBlocksToPipe(struct pipe_screen *screen,
+ unsigned int xvmc_picture_structure,
+ const XvMCMacroBlockArray *xvmc_macroblocks,
+ const XvMCBlockArray *xvmc_blocks,
+ unsigned int first_macroblock,
+ unsigned int num_macroblocks,
+ struct pipe_mpeg12_macroblock *pipe_macroblocks)
+{
+ unsigned int i, j, k, l;
+ XvMCMacroBlock *xvmc_mb;
+
+ assert(xvmc_macroblocks);
+ assert(xvmc_blocks);
+ assert(pipe_macroblocks);
+ assert(num_macroblocks);
+
+ xvmc_mb = xvmc_macroblocks->macro_blocks + first_macroblock;
+
+ for (i = 0; i < num_macroblocks; ++i) {
+ pipe_macroblocks->base.codec = PIPE_VIDEO_CODEC_MPEG12;
+ pipe_macroblocks->mbx = xvmc_mb->x;
+ pipe_macroblocks->mby = xvmc_mb->y;
+ pipe_macroblocks->mb_type = TypeToPipe(xvmc_mb->macroblock_type);
+ if (pipe_macroblocks->mb_type != PIPE_MPEG12_MACROBLOCK_TYPE_INTRA)
+ pipe_macroblocks->mo_type = MotionToPipe(xvmc_mb->motion_type, xvmc_picture_structure);
+ /* Get rid of Valgrind 'undefined' warnings */
+ else
+ pipe_macroblocks->mo_type = -1;
+ pipe_macroblocks->dct_type = xvmc_mb->dct_type == XVMC_DCT_TYPE_FIELD ?
+ PIPE_MPEG12_DCT_TYPE_FIELD : PIPE_MPEG12_DCT_TYPE_FRAME;
+
+ for (j = 0; j < 2; ++j)
+ for (k = 0; k < 2; ++k)
+ for (l = 0; l < 2; ++l)
+ pipe_macroblocks->pmv[j][k][l] = xvmc_mb->PMV[j][k][l];
+
+ pipe_macroblocks->mvfs[0][0] = xvmc_mb->motion_vertical_field_select & XVMC_SELECT_FIRST_FORWARD;
+ pipe_macroblocks->mvfs[0][1] = xvmc_mb->motion_vertical_field_select & XVMC_SELECT_FIRST_BACKWARD;
+ pipe_macroblocks->mvfs[1][0] = xvmc_mb->motion_vertical_field_select & XVMC_SELECT_SECOND_FORWARD;
+ pipe_macroblocks->mvfs[1][1] = xvmc_mb->motion_vertical_field_select & XVMC_SELECT_SECOND_BACKWARD;
+
+ pipe_macroblocks->cbp = xvmc_mb->coded_block_pattern;
+ pipe_macroblocks->blocks = xvmc_blocks->blocks + xvmc_mb->index * BLOCK_SIZE_SAMPLES;
+
+ ++pipe_macroblocks;
+ ++xvmc_mb;
+ }
+}
+
+PUBLIC
+Status XvMCCreateSurface(Display *dpy, XvMCContext *context, XvMCSurface *surface)
+{
+ XvMCContextPrivate *context_priv;
+ struct pipe_video_context *vpipe;
+ XvMCSurfacePrivate *surface_priv;
+ struct pipe_resource template;
+ struct pipe_resource *vsfc_tex;
+ struct pipe_surface surf_template;
+ struct pipe_surface *vsfc;
+
+ XVMC_MSG(XVMC_TRACE, "[XvMC] Creating surface %p.\n", surface);
+
+ assert(dpy);
+
+ if (!context)
+ return XvMCBadContext;
+ if (!surface)
+ return XvMCBadSurface;
+
+ context_priv = context->privData;
+ vpipe = context_priv->vctx->vpipe;
+
+ surface_priv = CALLOC(1, sizeof(XvMCSurfacePrivate));
+ if (!surface_priv)
+ return BadAlloc;
+
+ memset(&template, 0, sizeof(struct pipe_resource));
+ template.target = PIPE_TEXTURE_2D;
+ template.format = (enum pipe_format)vpipe->get_param(vpipe, PIPE_CAP_DECODE_TARGET_PREFERRED_FORMAT);
+ template.last_level = 0;
+ if (vpipe->is_format_supported(vpipe, template.format,
+ PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET,
+ PIPE_TEXTURE_GEOM_NON_POWER_OF_TWO)) {
+ template.width0 = context->width;
+ template.height0 = context->height;
+ }
+ else {
+ assert(vpipe->is_format_supported(vpipe, template.format,
+ PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET,
+ PIPE_TEXTURE_GEOM_NON_SQUARE));
+ template.width0 = util_next_power_of_two(context->width);
+ template.height0 = util_next_power_of_two(context->height);
+ }
+ template.depth0 = 1;
+ template.usage = PIPE_USAGE_DEFAULT;
+ template.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
+ template.flags = 0;
+ vsfc_tex = vpipe->screen->resource_create(vpipe->screen, &template);
+ if (!vsfc_tex) {
+ FREE(surface_priv);
+ return BadAlloc;
+ }
+
+ memset(&surf_template, 0, sizeof(surf_template));
+ surf_template.format = vsfc_tex->format;
+ surf_template.usage = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
+ vsfc = vpipe->create_surface(vpipe, vsfc_tex, &surf_template);
+ pipe_resource_reference(&vsfc_tex, NULL);
+ if (!vsfc) {
+ FREE(surface_priv);
+ return BadAlloc;
+ }
+
+ surface_priv->pipe_vsfc = vsfc;
+ surface_priv->context = context;
+
+ surface->surface_id = XAllocID(dpy);
+ surface->context_id = context->context_id;
+ surface->surface_type_id = context->surface_type_id;
+ surface->width = context->width;
+ surface->height = context->height;
+ surface->privData = surface_priv;
+
+ SyncHandle();
+
+ XVMC_MSG(XVMC_TRACE, "[XvMC] Surface %p created.\n", surface);
+
+ return Success;
+}
+
+PUBLIC
+Status XvMCRenderSurface(Display *dpy, XvMCContext *context, unsigned int picture_structure,
+ XvMCSurface *target_surface, XvMCSurface *past_surface, XvMCSurface *future_surface,
+ unsigned int flags, unsigned int num_macroblocks, unsigned int first_macroblock,
+ XvMCMacroBlockArray *macroblocks, XvMCBlockArray *blocks
+)
+{
+ struct pipe_video_context *vpipe;
+ struct pipe_surface *t_vsfc;
+ struct pipe_surface *p_vsfc;
+ struct pipe_surface *f_vsfc;
+ XvMCContextPrivate *context_priv;
+ XvMCSurfacePrivate *target_surface_priv;
+ XvMCSurfacePrivate *past_surface_priv;
+ XvMCSurfacePrivate *future_surface_priv;
+ struct pipe_mpeg12_macroblock pipe_macroblocks[num_macroblocks];
+
+ XVMC_MSG(XVMC_TRACE, "[XvMC] Rendering to surface %p.\n", target_surface);
+
+ assert(dpy);
+
+ if (!context || !context->privData)
+ return XvMCBadContext;
+ if (!target_surface || !target_surface->privData)
+ return XvMCBadSurface;
+
+ if (picture_structure != XVMC_TOP_FIELD &&
+ picture_structure != XVMC_BOTTOM_FIELD &&
+ picture_structure != XVMC_FRAME_PICTURE)
+ return BadValue;
+ /* Bkwd pred equivalent to fwd (past && !future) */
+ if (future_surface && !past_surface)
+ return BadMatch;
+
+ assert(context->context_id == target_surface->context_id);
+ assert(!past_surface || context->context_id == past_surface->context_id);
+ assert(!future_surface || context->context_id == future_surface->context_id);
+
+ assert(macroblocks);
+ assert(blocks);
+
+ assert(macroblocks->context_id == context->context_id);
+ assert(blocks->context_id == context->context_id);
+
+ assert(flags == 0 || flags == XVMC_SECOND_FIELD);
+
+ target_surface_priv = target_surface->privData;
+ past_surface_priv = past_surface ? past_surface->privData : NULL;
+ future_surface_priv = future_surface ? future_surface->privData : NULL;
+
+ assert(target_surface_priv->context == context);
+ assert(!past_surface || past_surface_priv->context == context);
+ assert(!future_surface || future_surface_priv->context == context);
+
+ context_priv = context->privData;
+ vpipe = context_priv->vctx->vpipe;
+
+ t_vsfc = target_surface_priv->pipe_vsfc;
+ p_vsfc = past_surface ? past_surface_priv->pipe_vsfc : NULL;
+ f_vsfc = future_surface ? future_surface_priv->pipe_vsfc : NULL;
+
+ MacroBlocksToPipe(vpipe->screen, picture_structure, macroblocks, blocks, first_macroblock,
+ num_macroblocks, pipe_macroblocks);
+
+ vpipe->set_decode_target(vpipe, t_vsfc);
+ vpipe->decode_macroblocks(vpipe, p_vsfc, f_vsfc, num_macroblocks,
+ &pipe_macroblocks->base, &target_surface_priv->render_fence);
+
+ XVMC_MSG(XVMC_TRACE, "[XvMC] Submitted surface %p for rendering.\n", target_surface);
+
+ return Success;
+}
+
+PUBLIC
+Status XvMCFlushSurface(Display *dpy, XvMCSurface *surface)
+{
+ assert(dpy);
+
+ if (!surface)
+ return XvMCBadSurface;
+
+ return Success;
+}
+
+PUBLIC
+Status XvMCSyncSurface(Display *dpy, XvMCSurface *surface)
+{
+ assert(dpy);
+
+ if (!surface)
+ return XvMCBadSurface;
+
+ return Success;
+}
+
+PUBLIC
+Status XvMCPutSurface(Display *dpy, XvMCSurface *surface, Drawable drawable,
+ short srcx, short srcy, unsigned short srcw, unsigned short srch,
+ short destx, short desty, unsigned short destw, unsigned short desth,
+ int flags)
+{
+ static int dump_window = -1;
+
+ struct pipe_video_context *vpipe;
+ XvMCSurfacePrivate *surface_priv;
+ XvMCContextPrivate *context_priv;
+ XvMCSubpicturePrivate *subpicture_priv;
+ XvMCContext *context;
+ struct pipe_video_rect src_rect = {srcx, srcy, srcw, srch};
+ struct pipe_video_rect dst_rect = {destx, desty, destw, desth};
+ struct pipe_surface *drawable_surface;
+
+ XVMC_MSG(XVMC_TRACE, "[XvMC] Displaying surface %p.\n", surface);
+
+ assert(dpy);
+
+ if (!surface || !surface->privData)
+ return XvMCBadSurface;
+
+ surface_priv = surface->privData;
+ context = surface_priv->context;
+ context_priv = context->privData;
+
+ drawable_surface = vl_drawable_surface_get(context_priv->vctx, drawable);
+ if (!drawable_surface)
+ return BadDrawable;
+
+ assert(flags == XVMC_TOP_FIELD || flags == XVMC_BOTTOM_FIELD || flags == XVMC_FRAME_PICTURE);
+ assert(srcx + srcw - 1 < surface->width);
+ assert(srcy + srch - 1 < surface->height);
+ /*
+ * Some apps (mplayer) hit these asserts because they call
+ * this function after the window has been resized by the WM
+ * but before they've handled the corresponding XEvent and
+ * know about the new dimensions. The output should be clipped
+ * until the app updates destw and desth.
+ */
+ /*
+ assert(destx + destw - 1 < drawable_surface->width);
+ assert(desty + desth - 1 < drawable_surface->height);
+ */
+
+ subpicture_priv = surface_priv->subpicture ? surface_priv->subpicture->privData : NULL;
+ vpipe = context_priv->vctx->vpipe;
+
+#if 0
+ if (!CreateOrResizeBackBuffer(context_priv->vctx, width, height, &context_priv->backbuffer))
+ return BadAlloc;
+#endif
+
+ if (subpicture_priv) {
+ struct pipe_video_rect src_rect = {surface_priv->subx, surface_priv->suby, surface_priv->subw, surface_priv->subh};
+ struct pipe_video_rect dst_rect = {surface_priv->surfx, surface_priv->surfy, surface_priv->surfw, surface_priv->surfh};
+ struct pipe_video_rect *src_rects[1] = {&src_rect};
+ struct pipe_video_rect *dst_rects[1] = {&dst_rect};
+
+ XVMC_MSG(XVMC_TRACE, "[XvMC] Surface %p has subpicture %p.\n", surface, surface_priv->subpicture);
+
+ assert(subpicture_priv->surface == surface);
+ vpipe->set_picture_layers(vpipe, &subpicture_priv->sfc, src_rects, dst_rects, 1);
+
+ surface_priv->subpicture = NULL;
+ subpicture_priv->surface = NULL;
+ }
+ else
+ vpipe->set_picture_layers(vpipe, NULL, NULL, NULL, 0);
+
+ vpipe->render_picture(vpipe, surface_priv->pipe_vsfc, PictureToPipe(flags), &src_rect,
+ drawable_surface, &dst_rect, &surface_priv->disp_fence);
+
+ XVMC_MSG(XVMC_TRACE, "[XvMC] Submitted surface %p for display. Pushing to front buffer.\n", surface);
+
+ vpipe->screen->flush_frontbuffer
+ (
+ vpipe->screen,
+ drawable_surface->texture,
+ 0, 0,
+ vl_contextprivate_get(context_priv->vctx, drawable_surface)
+ );
+
+ pipe_surface_reference(&drawable_surface, NULL);
+
+ if(dump_window == -1) {
+ dump_window = debug_get_num_option("XVMC_DUMP", 0);
+ }
+
+ if(dump_window) {
+ static unsigned int framenum = 0;
+ char cmd[256];
+ sprintf(cmd, "xwd -id %d -out xvmc_frame_%08d.xwd", (int)drawable, ++framenum);
+ system(cmd);
+ }
+
+ XVMC_MSG(XVMC_TRACE, "[XvMC] Pushed surface %p to front buffer.\n", surface);
+
+ return Success;
+}
+
+PUBLIC
+Status XvMCGetSurfaceStatus(Display *dpy, XvMCSurface *surface, int *status)
+{
+ assert(dpy);
+
+ if (!surface)
+ return XvMCBadSurface;
+
+ assert(status);
+
+ *status = 0;
+
+ return Success;
+}
+
+PUBLIC
+Status XvMCDestroySurface(Display *dpy, XvMCSurface *surface)
+{
+ XvMCSurfacePrivate *surface_priv;
+
+ XVMC_MSG(XVMC_TRACE, "[XvMC] Destroying surface %p.\n", surface);
+
+ assert(dpy);
+
+ if (!surface || !surface->privData)
+ return XvMCBadSurface;
+
+ surface_priv = surface->privData;
+ pipe_surface_reference(&surface_priv->pipe_vsfc, NULL);
+ FREE(surface_priv);
+ surface->privData = NULL;
+
+ XVMC_MSG(XVMC_TRACE, "[XvMC] Surface %p destroyed.\n", surface);
+
+ return Success;
+}
+
+PUBLIC
+Status XvMCHideSurface(Display *dpy, XvMCSurface *surface)
+{
+ assert(dpy);
+
+ if (!surface || !surface->privData)
+ return XvMCBadSurface;
+
+ /* No op, only for overlaid rendering */
+
+ return Success;
+}
diff --git a/src/gallium/state_trackers/xorg/xvmc/tests/.gitignore b/src/gallium/state_trackers/xorg/xvmc/tests/.gitignore
new file mode 100644
index 00000000000..9a8e05d9472
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xvmc/tests/.gitignore
@@ -0,0 +1,6 @@
+test_context
+test_surface
+test_subpicture
+test_blocks
+test_rendering
+xvmc_bench
diff --git a/src/gallium/state_trackers/xorg/xvmc/tests/Makefile b/src/gallium/state_trackers/xorg/xvmc/tests/Makefile
new file mode 100644
index 00000000000..88b03763563
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xvmc/tests/Makefile
@@ -0,0 +1,31 @@
+TOP = ../../../../../..
+include $(TOP)/configs/current
+
+LIBS = -lXvMCW -lXvMC -lXv -lX11
+
+#############################################
+
+.PHONY: default clean
+
+default: test_context test_surface test_subpicture test_blocks test_rendering xvmc_bench
+
+test_context: test_context.o testlib.o
+ $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+test_surface: test_surface.o testlib.o
+ $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+test_subpicture: test_subpicture.o testlib.o
+ $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+test_blocks: test_blocks.o testlib.o
+ $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+test_rendering: test_rendering.o testlib.o
+ $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+xvmc_bench: xvmc_bench.o testlib.o
+ $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+clean:
+ $(RM) -rf *.o test_context test_surface test_subpicture test_blocks test_rendering xvmc_bench
diff --git a/src/gallium/state_trackers/xorg/xvmc/tests/test_blocks.c b/src/gallium/state_trackers/xorg/xvmc/tests/test_blocks.c
new file mode 100644
index 00000000000..994e3ca4d14
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xvmc/tests/test_blocks.c
@@ -0,0 +1,111 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 <assert.h>
+#include <error.h>
+#include "testlib.h"
+
+int main(int argc, char **argv)
+{
+ const unsigned int width = 16, height = 16;
+ const unsigned int min_required_blocks = 1, min_required_macroblocks = 1;
+ const unsigned int mc_types[2] = {XVMC_MOCOMP | XVMC_MPEG_2, XVMC_IDCT | XVMC_MPEG_2};
+
+ Display *display;
+ XvPortID port_num;
+ int surface_type_id;
+ unsigned int is_overlay, intra_unsigned;
+ int colorkey;
+ XvMCContext context;
+ XvMCSurface surface;
+ XvMCBlockArray blocks = {0};
+ XvMCMacroBlockArray macroblocks = {0};
+
+ display = XOpenDisplay(NULL);
+
+ if (!GetPort
+ (
+ display,
+ width,
+ height,
+ XVMC_CHROMA_FORMAT_420,
+ mc_types,
+ 2,
+ &port_num,
+ &surface_type_id,
+ &is_overlay,
+ &intra_unsigned
+ ))
+ {
+ XCloseDisplay(display);
+ error(1, 0, "Error, unable to find a good port.\n");
+ }
+
+ if (is_overlay)
+ {
+ Atom xv_colorkey = XInternAtom(display, "XV_COLORKEY", 0);
+ XvGetPortAttribute(display, port_num, xv_colorkey, &colorkey);
+ }
+
+ assert(XvMCCreateContext(display, port_num, surface_type_id, width, height, XVMC_DIRECT, &context) == Success);
+ assert(XvMCCreateSurface(display, &context, &surface) == Success);
+
+ /* Test NULL context */
+ assert(XvMCCreateBlocks(display, NULL, 1, &blocks) == XvMCBadContext);
+ /* Test 0 blocks */
+ assert(XvMCCreateBlocks(display, &context, 0, &blocks) == BadValue);
+ /* Test valid params */
+ assert(XvMCCreateBlocks(display, &context, min_required_blocks, &blocks) == Success);
+ /* Test context id assigned and correct */
+ assert(blocks.context_id == context.context_id);
+ /* Test number of blocks assigned and correct */
+ assert(blocks.num_blocks == min_required_blocks);
+ /* Test block pointer valid */
+ assert(blocks.blocks != NULL);
+ /* Test NULL context */
+ assert(XvMCCreateMacroBlocks(display, NULL, 1, &macroblocks) == XvMCBadContext);
+ /* Test 0 macroblocks */
+ assert(XvMCCreateMacroBlocks(display, &context, 0, &macroblocks) == BadValue);
+ /* Test valid params */
+ assert(XvMCCreateMacroBlocks(display, &context, min_required_macroblocks, &macroblocks) == Success);
+ /* Test context id assigned and correct */
+ assert(macroblocks.context_id == context.context_id);
+ /* Test macroblock pointer valid */
+ assert(macroblocks.macro_blocks != NULL);
+ /* Test valid params */
+ assert(XvMCDestroyMacroBlocks(display, &macroblocks) == Success);
+ /* Test valid params */
+ assert(XvMCDestroyBlocks(display, &blocks) == Success);
+
+ assert(XvMCDestroySurface(display, &surface) == Success);
+ assert(XvMCDestroyContext(display, &context) == Success);
+
+ XvUngrabPort(display, port_num, CurrentTime);
+ XCloseDisplay(display);
+
+ return 0;
+}
diff --git a/src/gallium/state_trackers/xorg/xvmc/tests/test_context.c b/src/gallium/state_trackers/xorg/xvmc/tests/test_context.c
new file mode 100644
index 00000000000..3da957c9330
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xvmc/tests/test_context.c
@@ -0,0 +1,119 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 <assert.h>
+#include <error.h>
+#include "testlib.h"
+
+int main(int argc, char **argv)
+{
+ const unsigned int width = 16, height = 16;
+ const unsigned int mc_types[2] = {XVMC_MOCOMP | XVMC_MPEG_2, XVMC_IDCT | XVMC_MPEG_2};
+
+ Display *display;
+ XvPortID port_num;
+ int surface_type_id;
+ unsigned int is_overlay, intra_unsigned;
+ int colorkey;
+ XvMCContext context = {0};
+
+ display = XOpenDisplay(NULL);
+
+ if (!GetPort
+ (
+ display,
+ width,
+ height,
+ XVMC_CHROMA_FORMAT_420,
+ mc_types,
+ 2,
+ &port_num,
+ &surface_type_id,
+ &is_overlay,
+ &intra_unsigned
+ ))
+ {
+ XCloseDisplay(display);
+ error(1, 0, "Error, unable to find a good port.\n");
+ }
+
+ if (is_overlay)
+ {
+ Atom xv_colorkey = XInternAtom(display, "XV_COLORKEY", 0);
+ XvGetPortAttribute(display, port_num, xv_colorkey, &colorkey);
+ }
+
+ /* Test NULL context */
+ /* XXX: XvMCBadContext not a valid return for XvMCCreateContext in the XvMC API, but openChrome driver returns it */
+ assert(XvMCCreateContext(display, port_num, surface_type_id, width, height, XVMC_DIRECT, NULL) == XvMCBadContext);
+ /* Test invalid port */
+ /* XXX: Success and XvBadPort have the same value, if this call actually gets passed the validation step as of now we'll crash later */
+ assert(XvMCCreateContext(display, -1, surface_type_id, width, height, XVMC_DIRECT, &context) == XvBadPort);
+ /* Test invalid surface */
+ assert(XvMCCreateContext(display, port_num, -1, width, height, XVMC_DIRECT, &context) == BadMatch);
+ /* Test invalid flags */
+ assert(XvMCCreateContext(display, port_num, surface_type_id, width, height, -1, &context) == BadValue);
+ /* Test huge width */
+ assert(XvMCCreateContext(display, port_num, surface_type_id, 16384, height, XVMC_DIRECT, &context) == BadValue);
+ /* Test huge height */
+ assert(XvMCCreateContext(display, port_num, surface_type_id, width, 16384, XVMC_DIRECT, &context) == BadValue);
+ /* Test huge width & height */
+ assert(XvMCCreateContext(display, port_num, surface_type_id, 16384, 16384, XVMC_DIRECT, &context) == BadValue);
+ /* Test valid params */
+ assert(XvMCCreateContext(display, port_num, surface_type_id, width, height, XVMC_DIRECT, &context) == Success);
+ /* Test context id assigned */
+ assert(context.context_id != 0);
+ /* Test surface type id assigned and correct */
+ assert(context.surface_type_id == surface_type_id);
+ /* Test width & height assigned and correct */
+ assert(context.width == width && context.height == height);
+ /* Test port assigned and correct */
+ assert(context.port == port_num);
+ /* Test flags assigned and correct */
+ assert(context.flags == XVMC_DIRECT);
+ /* Test NULL context */
+ assert(XvMCDestroyContext(display, NULL) == XvMCBadContext);
+ /* Test valid params */
+ assert(XvMCDestroyContext(display, &context) == Success);
+ /* Test awkward but valid width */
+ assert(XvMCCreateContext(display, port_num, surface_type_id, width + 1, height, XVMC_DIRECT, &context) == Success);
+ assert(context.width >= width + 1);
+ assert(XvMCDestroyContext(display, &context) == Success);
+ /* Test awkward but valid height */
+ assert(XvMCCreateContext(display, port_num, surface_type_id, width, height + 1, XVMC_DIRECT, &context) == Success);
+ assert(context.height >= height + 1);
+ assert(XvMCDestroyContext(display, &context) == Success);
+ /* Test awkward but valid width & height */
+ assert(XvMCCreateContext(display, port_num, surface_type_id, width + 1, height + 1, XVMC_DIRECT, &context) == Success);
+ assert(context.width >= width + 1 && context.height >= height + 1);
+ assert(XvMCDestroyContext(display, &context) == Success);
+
+ XvUngrabPort(display, port_num, CurrentTime);
+ XCloseDisplay(display);
+
+ return 0;
+}
diff --git a/src/gallium/state_trackers/xorg/xvmc/tests/test_rendering.c b/src/gallium/state_trackers/xorg/xvmc/tests/test_rendering.c
new file mode 100644
index 00000000000..6058783a798
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xvmc/tests/test_rendering.c
@@ -0,0 +1,317 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <error.h>
+#include "testlib.h"
+
+#define BLOCK_WIDTH 8
+#define BLOCK_HEIGHT 8
+#define BLOCK_SIZE (BLOCK_WIDTH * BLOCK_HEIGHT)
+#define MACROBLOCK_WIDTH 16
+#define MACROBLOCK_HEIGHT 16
+#define MACROBLOCK_WIDTH_IN_BLOCKS (MACROBLOCK_WIDTH / BLOCK_WIDTH)
+#define MACROBLOCK_HEIGHT_IN_BLOCKS (MACROBLOCK_HEIGHT / BLOCK_HEIGHT)
+#define BLOCKS_PER_MACROBLOCK 6
+
+#define INPUT_WIDTH 16
+#define INPUT_HEIGHT 16
+#define INPUT_WIDTH_IN_MACROBLOCKS (INPUT_WIDTH / MACROBLOCK_WIDTH)
+#define INPUT_HEIGHT_IN_MACROBLOCKS (INPUT_HEIGHT / MACROBLOCK_HEIGHT)
+#define NUM_MACROBLOCKS (INPUT_WIDTH_IN_MACROBLOCKS * INPUT_HEIGHT_IN_MACROBLOCKS)
+
+#define DEFAULT_OUTPUT_WIDTH INPUT_WIDTH
+#define DEFAULT_OUTPUT_HEIGHT INPUT_HEIGHT
+#define DEFAULT_ACCEPTABLE_ERR 0.01
+
+void ParseArgs(int argc, char **argv, unsigned int *output_width, unsigned int *output_height, double *acceptable_error, int *prompt);
+void Gradient(short *block, unsigned int start, unsigned int stop, int horizontal);
+
+void ParseArgs(int argc, char **argv, unsigned int *output_width, unsigned int *output_height, double *acceptable_error, int *prompt)
+{
+ int fail = 0;
+ int i;
+
+ *output_width = DEFAULT_OUTPUT_WIDTH;
+ *output_height = DEFAULT_OUTPUT_WIDTH;
+ *acceptable_error = DEFAULT_ACCEPTABLE_ERR;
+ *prompt = 1;
+
+ for (i = 1; i < argc && !fail; ++i)
+ {
+ if (!strcmp(argv[i], "-w"))
+ {
+ if (sscanf(argv[++i], "%u", output_width) != 1)
+ fail = 1;
+ }
+ else if (!strcmp(argv[i], "-h"))
+ {
+ if (sscanf(argv[++i], "%u", output_height) != 1)
+ fail = 1;
+ }
+ else if (!strcmp(argv[i], "-e"))
+ {
+ if (sscanf(argv[++i], "%lf", acceptable_error) != 1)
+ fail = 1;
+ }
+ else if (strcmp(argv[i], "-n"))
+ *prompt = 0;
+ else
+ fail = 1;
+ }
+
+ if (fail)
+ error
+ (
+ 1, 0,
+ "Bad argument.\n"
+ "\n"
+ "Usage: %s [options]\n"
+ "\t-w <width>\tOutput width\n"
+ "\t-h <height>\tOutput height\n"
+ "\t-e <error>\tAcceptable margin of error per pixel, from 0 to 1\n"
+ "\t-n\tDon't prompt for quit\n",
+ argv[0]
+ );
+}
+
+void Gradient(short *block, unsigned int start, unsigned int stop, int horizontal)
+{
+ unsigned int x, y;
+ unsigned int range = stop - start;
+
+ if (horizontal)
+ {
+ for (y = 0; y < BLOCK_HEIGHT; ++y)
+ for (x = 0; x < BLOCK_WIDTH; ++x)
+ block[y * BLOCK_WIDTH + x] = (short)(start + range * (x / (float)(BLOCK_WIDTH - 1)));
+ }
+ else
+ {
+ for (y = 0; y < BLOCK_HEIGHT; ++y)
+ for (x = 0; x < BLOCK_WIDTH; ++x)
+ block[y * BLOCK_WIDTH + x] = (short)(start + range * (y / (float)(BLOCK_HEIGHT - 1)));
+ }
+}
+
+int main(int argc, char **argv)
+{
+ unsigned int output_width;
+ unsigned int output_height;
+ double acceptable_error;
+ int prompt;
+ Display *display;
+ Window root, window;
+ const unsigned int mc_types[2] = {XVMC_MOCOMP | XVMC_MPEG_2, XVMC_IDCT | XVMC_MPEG_2};
+ XvPortID port_num;
+ int surface_type_id;
+ unsigned int is_overlay, intra_unsigned;
+ int colorkey;
+ XvMCContext context;
+ XvMCSurface surface;
+ XvMCBlockArray block_array;
+ XvMCMacroBlockArray mb_array;
+ int mbx, mby, bx, by;
+ XvMCMacroBlock *mb;
+ short *blocks;
+ int quit = 0;
+
+ ParseArgs(argc, argv, &output_width, &output_height, &acceptable_error, &prompt);
+
+ display = XOpenDisplay(NULL);
+
+ if (!GetPort
+ (
+ display,
+ INPUT_WIDTH,
+ INPUT_HEIGHT,
+ XVMC_CHROMA_FORMAT_420,
+ mc_types,
+ 2,
+ &port_num,
+ &surface_type_id,
+ &is_overlay,
+ &intra_unsigned
+ ))
+ {
+ XCloseDisplay(display);
+ error(1, 0, "Error, unable to find a good port.\n");
+ }
+
+ if (is_overlay)
+ {
+ Atom xv_colorkey = XInternAtom(display, "XV_COLORKEY", 0);
+ XvGetPortAttribute(display, port_num, xv_colorkey, &colorkey);
+ }
+
+ root = XDefaultRootWindow(display);
+ window = XCreateSimpleWindow(display, root, 0, 0, output_width, output_height, 0, 0, colorkey);
+
+ assert(XvMCCreateContext(display, port_num, surface_type_id, INPUT_WIDTH, INPUT_HEIGHT, XVMC_DIRECT, &context) == Success);
+ assert(XvMCCreateSurface(display, &context, &surface) == Success);
+ assert(XvMCCreateBlocks(display, &context, NUM_MACROBLOCKS * BLOCKS_PER_MACROBLOCK, &block_array) == Success);
+ assert(XvMCCreateMacroBlocks(display, &context, NUM_MACROBLOCKS, &mb_array) == Success);
+
+ mb = mb_array.macro_blocks;
+ blocks = block_array.blocks;
+
+ for (mby = 0; mby < INPUT_HEIGHT_IN_MACROBLOCKS; ++mby)
+ for (mbx = 0; mbx < INPUT_WIDTH_IN_MACROBLOCKS; ++mbx)
+ {
+ mb->x = mbx;
+ mb->y = mby;
+ mb->macroblock_type = XVMC_MB_TYPE_INTRA;
+ /*mb->motion_type = ;*/
+ /*mb->motion_vertical_field_select = ;*/
+ mb->dct_type = XVMC_DCT_TYPE_FRAME;
+ /*mb->PMV[0][0][0] = ;
+ mb->PMV[0][0][1] = ;
+ mb->PMV[0][1][0] = ;
+ mb->PMV[0][1][1] = ;
+ mb->PMV[1][0][0] = ;
+ mb->PMV[1][0][1] = ;
+ mb->PMV[1][1][0] = ;
+ mb->PMV[1][1][1] = ;*/
+ mb->index = (mby * INPUT_WIDTH_IN_MACROBLOCKS + mbx) * BLOCKS_PER_MACROBLOCK;
+ mb->coded_block_pattern = 0x3F;
+
+ mb++;
+
+ for (by = 0; by < MACROBLOCK_HEIGHT_IN_BLOCKS; ++by)
+ for (bx = 0; bx < MACROBLOCK_WIDTH_IN_BLOCKS; ++bx)
+ {
+ const int start = 16, stop = 235, range = stop - start;
+
+ Gradient
+ (
+ blocks,
+ (short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH) / (float)(INPUT_WIDTH - 1))),
+ (short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH + BLOCK_WIDTH - 1) / (float)(INPUT_WIDTH - 1))),
+ 1
+ );
+
+ blocks += BLOCK_SIZE;
+ }
+
+ for (by = 0; by < MACROBLOCK_HEIGHT_IN_BLOCKS / 2; ++by)
+ for (bx = 0; bx < MACROBLOCK_WIDTH_IN_BLOCKS / 2; ++bx)
+ {
+ const int start = 16, stop = 240, range = stop - start;
+
+ Gradient
+ (
+ blocks,
+ (short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH) / (float)(INPUT_WIDTH - 1))),
+ (short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH + BLOCK_WIDTH - 1) / (float)(INPUT_WIDTH - 1))),
+ 1
+ );
+
+ blocks += BLOCK_SIZE;
+
+ Gradient
+ (
+ blocks,
+ (short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH) / (float)(INPUT_WIDTH - 1))),
+ (short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH + BLOCK_WIDTH - 1) / (float)(INPUT_WIDTH - 1))),
+ 1
+ );
+
+ blocks += BLOCK_SIZE;
+ }
+ }
+
+ XSelectInput(display, window, ExposureMask | KeyPressMask);
+ XMapWindow(display, window);
+ XSync(display, 0);
+
+ /* Test NULL context */
+ assert(XvMCRenderSurface(display, NULL, XVMC_FRAME_PICTURE, &surface, NULL, NULL, 0, NUM_MACROBLOCKS, 0, &mb_array, &block_array) == XvMCBadContext);
+ /* Test NULL surface */
+ assert(XvMCRenderSurface(display, &context, XVMC_FRAME_PICTURE, NULL, NULL, NULL, 0, NUM_MACROBLOCKS, 0, &mb_array, &block_array) == XvMCBadSurface);
+ /* Test bad picture structure */
+ assert(XvMCRenderSurface(display, &context, 0, &surface, NULL, NULL, 0, NUM_MACROBLOCKS, 0, &mb_array, &block_array) == BadValue);
+ /* Test valid params */
+ assert(XvMCRenderSurface(display, &context, XVMC_FRAME_PICTURE, &surface, NULL, NULL, 0, NUM_MACROBLOCKS, 0, &mb_array, &block_array) == Success);
+
+ /* Test NULL surface */
+ assert(XvMCPutSurface(display, NULL, window, 0, 0, INPUT_WIDTH, INPUT_HEIGHT, 0, 0, output_width, output_height, XVMC_FRAME_PICTURE) == XvMCBadSurface);
+ /* Test bad window */
+ /* XXX: X halts with a bad drawable for some reason, doesn't return BadDrawable as expected */
+ /*assert(XvMCPutSurface(display, &surface, 0, 0, 0, width, height, 0, 0, width, height, XVMC_FRAME_PICTURE) == BadDrawable);*/
+
+ if (prompt)
+ {
+ puts("Press any button to quit...");
+
+ while (!quit)
+ {
+ if (XPending(display) > 0)
+ {
+ XEvent event;
+
+ XNextEvent(display, &event);
+
+ switch (event.type)
+ {
+ case Expose:
+ {
+ /* Test valid params */
+ assert
+ (
+ XvMCPutSurface
+ (
+ display, &surface, window,
+ 0, 0, INPUT_WIDTH, INPUT_HEIGHT,
+ 0, 0, output_width, output_height,
+ XVMC_FRAME_PICTURE
+ ) == Success
+ );
+ break;
+ }
+ case KeyPress:
+ {
+ quit = 1;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ assert(XvMCDestroyBlocks(display, &block_array) == Success);
+ assert(XvMCDestroyMacroBlocks(display, &mb_array) == Success);
+ assert(XvMCDestroySurface(display, &surface) == Success);
+ assert(XvMCDestroyContext(display, &context) == Success);
+
+ XvUngrabPort(display, port_num, CurrentTime);
+ XDestroyWindow(display, window);
+ XCloseDisplay(display);
+
+ return 0;
+}
diff --git a/src/gallium/state_trackers/xorg/xvmc/tests/test_subpicture.c b/src/gallium/state_trackers/xorg/xvmc/tests/test_subpicture.c
new file mode 100644
index 00000000000..20d0907a07f
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xvmc/tests/test_subpicture.c
@@ -0,0 +1,182 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 <assert.h>
+#include <error.h>
+#include <stdio.h>
+#include "testlib.h"
+
+static void PrintGUID(const char *guid)
+{
+ int i;
+ printf("\tguid: ");
+ for (i = 0; i < 4; ++i)
+ printf("%C,", guid[i] == 0 ? '0' : guid[i]);
+ for (; i < 15; ++i)
+ printf("%x,", (unsigned char)guid[i]);
+ printf("%x\n", (unsigned int)guid[15]);
+}
+
+static void PrintComponentOrder(const char *co)
+{
+ int i;
+ printf("\tcomponent_order:\n\t ");
+ for (i = 0; i < 4; ++i)
+ printf("%C,", co[i] == 0 ? '0' : co[i]);
+ for (; i < 31; ++i)
+ printf("%x,", (unsigned int)co[i]);
+ printf("%x\n", (unsigned int)co[31]);
+}
+
+int main(int argc, char **argv)
+{
+ const unsigned int width = 16, height = 16;
+ const unsigned int mc_types[2] = {XVMC_MOCOMP | XVMC_MPEG_2, XVMC_IDCT | XVMC_MPEG_2};
+ const unsigned int subpic_width = 16, subpic_height = 16;
+
+ Display *display;
+ XvPortID port_num;
+ int surface_type_id;
+ unsigned int is_overlay, intra_unsigned;
+ int colorkey;
+ XvMCContext context;
+ XvImageFormatValues *subpics;
+ int num_subpics;
+ XvMCSubpicture subpicture = {0};
+ int i;
+
+ display = XOpenDisplay(NULL);
+
+ if (!GetPort
+ (
+ display,
+ width,
+ height,
+ XVMC_CHROMA_FORMAT_420,
+ mc_types,
+ 2,
+ &port_num,
+ &surface_type_id,
+ &is_overlay,
+ &intra_unsigned
+ ))
+ {
+ XCloseDisplay(display);
+ error(1, 0, "Error, unable to find a good port.\n");
+ }
+
+ if (is_overlay)
+ {
+ Atom xv_colorkey = XInternAtom(display, "XV_COLORKEY", 0);
+ XvGetPortAttribute(display, port_num, xv_colorkey, &colorkey);
+ }
+
+ assert(XvMCCreateContext(display, port_num, surface_type_id, width, height, XVMC_DIRECT, &context) == Success);
+
+ subpics = XvMCListSubpictureTypes(display, port_num, surface_type_id, &num_subpics);
+ assert((subpics && num_subpics) > 0 || (!subpics && num_subpics == 0));
+
+ for (i = 0; i < num_subpics; ++i)
+ {
+ printf("Subpicture %d:\n", i);
+ printf("\tid: 0x%08x\n", subpics[i].id);
+ printf("\ttype: %s\n", subpics[i].type == XvRGB ? "XvRGB" : (subpics[i].type == XvYUV ? "XvYUV" : "Unknown"));
+ printf("\tbyte_order: %s\n", subpics[i].byte_order == LSBFirst ? "LSB First" : (subpics[i].byte_order == MSBFirst ? "MSB First" : "Unknown"));
+ PrintGUID(subpics[i].guid);
+ printf("\tbpp: %u\n", subpics[i].bits_per_pixel);
+ printf("\tformat: %s\n", subpics[i].format == XvPacked ? "XvPacked" : (subpics[i].format == XvPlanar ? "XvPlanar" : "Unknown"));
+ printf("\tnum_planes: %u\n", subpics[i].num_planes);
+
+ if (subpics[i].type == XvRGB)
+ {
+ printf("\tdepth: %u\n", subpics[i].depth);
+ printf("\tred_mask: 0x%08x\n", subpics[i].red_mask);
+ printf("\tgreen_mask: 0x%08x\n", subpics[i].green_mask);
+ printf("\tblue_mask: 0x%08x\n", subpics[i].blue_mask);
+ }
+ else if (subpics[i].type == XvYUV)
+ {
+ printf("\ty_sample_bits: %u\n", subpics[i].y_sample_bits);
+ printf("\tu_sample_bits: %u\n", subpics[i].u_sample_bits);
+ printf("\tv_sample_bits: %u\n", subpics[i].v_sample_bits);
+ printf("\thorz_y_period: %u\n", subpics[i].horz_y_period);
+ printf("\thorz_u_period: %u\n", subpics[i].horz_u_period);
+ printf("\thorz_v_period: %u\n", subpics[i].horz_v_period);
+ printf("\tvert_y_period: %u\n", subpics[i].vert_y_period);
+ printf("\tvert_u_period: %u\n", subpics[i].vert_u_period);
+ printf("\tvert_v_period: %u\n", subpics[i].vert_v_period);
+ }
+ PrintComponentOrder(subpics[i].component_order);
+ printf("\tscanline_order: %s\n", subpics[i].scanline_order == XvTopToBottom ? "XvTopToBottom" : (subpics[i].scanline_order == XvBottomToTop ? "XvBottomToTop" : "Unknown"));
+ }
+
+ if (num_subpics == 0)
+ {
+ printf("Subpictures not supported, nothing to test.\n");
+ return 0;
+ }
+
+ /* Test NULL context */
+ assert(XvMCCreateSubpicture(display, NULL, &subpicture, subpic_width, subpic_height, subpics[0].id) == XvMCBadContext);
+ /* Test NULL subpicture */
+ assert(XvMCCreateSubpicture(display, &context, NULL, subpic_width, subpic_height, subpics[0].id) == XvMCBadSubpicture);
+ /* Test invalid subpicture */
+ assert(XvMCCreateSubpicture(display, &context, &subpicture, subpic_width, subpic_height, -1) == BadMatch);
+ /* Test huge width */
+ assert(XvMCCreateSubpicture(display, &context, &subpicture, 16384, subpic_height, subpics[0].id) == BadValue);
+ /* Test huge height */
+ assert(XvMCCreateSubpicture(display, &context, &subpicture, subpic_width, 16384, subpics[0].id) == BadValue);
+ /* Test huge width & height */
+ assert(XvMCCreateSubpicture(display, &context, &subpicture, 16384, 16384, subpics[0].id) == BadValue);
+ for (i = 0; i < num_subpics; ++i)
+ {
+ /* Test valid params */
+ assert(XvMCCreateSubpicture(display, &context, &subpicture, subpic_width, subpic_height, subpics[i].id) == Success);
+ /* Test subpicture id assigned */
+ assert(subpicture.subpicture_id != 0);
+ /* Test context id assigned and correct */
+ assert(subpicture.context_id == context.context_id);
+ /* Test subpicture type id assigned and correct */
+ assert(subpicture.xvimage_id == subpics[i].id);
+ /* Test width & height assigned and correct */
+ assert(subpicture.width == width && subpicture.height == height);
+ /* Test no palette support */
+ assert(subpicture.num_palette_entries == 0 && subpicture.entry_bytes == 0);
+ /* Test valid params */
+ assert(XvMCDestroySubpicture(display, &subpicture) == Success);
+ }
+ /* Test NULL surface */
+ assert(XvMCDestroySubpicture(display, NULL) == XvMCBadSubpicture);
+
+ assert(XvMCDestroyContext(display, &context) == Success);
+
+ XFree(subpics);
+ XvUngrabPort(display, port_num, CurrentTime);
+ XCloseDisplay(display);
+
+ return 0;
+}
diff --git a/src/gallium/state_trackers/xorg/xvmc/tests/test_surface.c b/src/gallium/state_trackers/xorg/xvmc/tests/test_surface.c
new file mode 100644
index 00000000000..b65eb265c0a
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xvmc/tests/test_surface.c
@@ -0,0 +1,98 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 <assert.h>
+#include <error.h>
+#include "testlib.h"
+
+int main(int argc, char **argv)
+{
+ const unsigned int width = 16, height = 16;
+ const unsigned int mc_types[2] = {XVMC_MOCOMP | XVMC_MPEG_2, XVMC_IDCT | XVMC_MPEG_2};
+
+ Display *display;
+ XvPortID port_num;
+ int surface_type_id;
+ unsigned int is_overlay, intra_unsigned;
+ int colorkey;
+ XvMCContext context;
+ XvMCSurface surface = {0};
+
+ display = XOpenDisplay(NULL);
+
+ if (!GetPort
+ (
+ display,
+ width,
+ height,
+ XVMC_CHROMA_FORMAT_420,
+ mc_types,
+ 2,
+ &port_num,
+ &surface_type_id,
+ &is_overlay,
+ &intra_unsigned
+ ))
+ {
+ XCloseDisplay(display);
+ error(1, 0, "Error, unable to find a good port.\n");
+ }
+
+ if (is_overlay)
+ {
+ Atom xv_colorkey = XInternAtom(display, "XV_COLORKEY", 0);
+ XvGetPortAttribute(display, port_num, xv_colorkey, &colorkey);
+ }
+
+ assert(XvMCCreateContext(display, port_num, surface_type_id, width, height, XVMC_DIRECT, &context) == Success);
+
+ /* Test NULL context */
+ assert(XvMCCreateSurface(display, NULL, &surface) == XvMCBadContext);
+ /* Test NULL surface */
+ assert(XvMCCreateSurface(display, &context, NULL) == XvMCBadSurface);
+ /* Test valid params */
+ assert(XvMCCreateSurface(display, &context, &surface) == Success);
+ /* Test surface id assigned */
+ assert(surface.surface_id != 0);
+ /* Test context id assigned and correct */
+ assert(surface.context_id == context.context_id);
+ /* Test surface type id assigned and correct */
+ assert(surface.surface_type_id == surface_type_id);
+ /* Test width & height assigned and correct */
+ assert(surface.width == width && surface.height == height);
+ /* Test valid params */
+ assert(XvMCDestroySurface(display, &surface) == Success);
+ /* Test NULL surface */
+ assert(XvMCDestroySurface(display, NULL) == XvMCBadSurface);
+
+ assert(XvMCDestroyContext(display, &context) == Success);
+
+ XvUngrabPort(display, port_num, CurrentTime);
+ XCloseDisplay(display);
+
+ return 0;
+}
diff --git a/src/gallium/state_trackers/xorg/xvmc/tests/testlib.c b/src/gallium/state_trackers/xorg/xvmc/tests/testlib.c
new file mode 100644
index 00000000000..142c09bb590
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xvmc/tests/testlib.c
@@ -0,0 +1,146 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 "testlib.h"
+#include <stdio.h>
+
+/*
+void test(int pred, const char *pred_string, const char *doc_string, const char *file, unsigned int line)
+{
+ fputs(doc_string, stderr);
+ if (!pred)
+ fprintf(stderr, " FAIL!\n\t\"%s\" at %s:%u\n", pred_string, file, line);
+ else
+ fputs(" PASS!\n", stderr);
+}
+*/
+
+int GetPort
+(
+ Display *display,
+ unsigned int width,
+ unsigned int height,
+ unsigned int chroma_format,
+ const unsigned int *mc_types,
+ unsigned int num_mc_types,
+ XvPortID *port_id,
+ int *surface_type_id,
+ unsigned int *is_overlay,
+ unsigned int *intra_unsigned
+)
+{
+ unsigned int found_port = 0;
+ XvAdaptorInfo *adaptor_info;
+ unsigned int num_adaptors;
+ int num_types;
+ int ev_base, err_base;
+ unsigned int i, j, k, l;
+
+ if (!XvMCQueryExtension(display, &ev_base, &err_base))
+ return 0;
+ if (XvQueryAdaptors(display, XDefaultRootWindow(display), &num_adaptors, &adaptor_info) != Success)
+ return 0;
+
+ for (i = 0; i < num_adaptors && !found_port; ++i)
+ {
+ if (adaptor_info[i].type & XvImageMask)
+ {
+ XvMCSurfaceInfo *surface_info = XvMCListSurfaceTypes(display, adaptor_info[i].base_id, &num_types);
+
+ if (surface_info)
+ {
+ for (j = 0; j < num_types && !found_port; ++j)
+ {
+ if
+ (
+ surface_info[j].chroma_format == chroma_format &&
+ surface_info[j].max_width >= width &&
+ surface_info[j].max_height >= height
+ )
+ {
+ for (k = 0; k < num_mc_types && !found_port; ++k)
+ {
+ if (surface_info[j].mc_type == mc_types[k])
+ {
+ for (l = 0; l < adaptor_info[i].num_ports && !found_port; ++l)
+ {
+ if (XvGrabPort(display, adaptor_info[i].base_id + l, CurrentTime) == Success)
+ {
+ *port_id = adaptor_info[i].base_id + l;
+ *surface_type_id = surface_info[j].surface_type_id;
+ *is_overlay = surface_info[j].flags & XVMC_OVERLAID_SURFACE;
+ *intra_unsigned = surface_info[j].flags & XVMC_INTRA_UNSIGNED;
+ found_port = 1;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ XFree(surface_info);
+ }
+ }
+ }
+
+ XvFreeAdaptorInfo(adaptor_info);
+
+ return found_port;
+}
+
+unsigned int align(unsigned int value, unsigned int alignment)
+{
+ return (value + alignment - 1) & ~(alignment - 1);
+}
+
+/* From the glibc manual */
+int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y)
+{
+ /* Perform the carry for the later subtraction by updating y. */
+ if (x->tv_usec < y->tv_usec)
+ {
+ int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
+ y->tv_usec -= 1000000 * nsec;
+ y->tv_sec += nsec;
+ }
+ if (x->tv_usec - y->tv_usec > 1000000)
+ {
+ int nsec = (x->tv_usec - y->tv_usec) / 1000000;
+ y->tv_usec += 1000000 * nsec;
+ y->tv_sec -= nsec;
+ }
+
+ /*
+ * Compute the time remaining to wait.
+ * tv_usec is certainly positive.
+ */
+ result->tv_sec = x->tv_sec - y->tv_sec;
+ result->tv_usec = x->tv_usec - y->tv_usec;
+
+ /* Return 1 if result is negative. */
+ return x->tv_sec < y->tv_sec;
+}
diff --git a/src/gallium/state_trackers/xorg/xvmc/tests/testlib.h b/src/gallium/state_trackers/xorg/xvmc/tests/testlib.h
new file mode 100644
index 00000000000..0438e52928b
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xvmc/tests/testlib.h
@@ -0,0 +1,69 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 testlib_h
+#define testlib_h
+
+/*
+#define TEST(pred, doc) test(pred, #pred, doc, __FILE__, __LINE__)
+
+void test(int pred, const char *pred_string, const char *doc_string, const char *file, unsigned int line);
+*/
+
+#include <sys/time.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/XvMClib.h>
+
+/*
+ * display: IN A valid X display
+ * width, height: IN Surface size that the port must display
+ * chroma_format: IN Chroma format that the port must display
+ * mc_types, num_mc_types: IN List of MC types that the port must support, first port that matches the first mc_type will be returned
+ * port_id: OUT Your port's ID
+ * surface_type_id: OUT Your port's surface ID
+ * is_overlay: OUT If 1, port uses overlay surfaces, you need to set a colorkey
+ * intra_unsigned: OUT If 1, port uses unsigned values for intra-coded blocks
+ */
+int GetPort
+(
+ Display *display,
+ unsigned int width,
+ unsigned int height,
+ unsigned int chroma_format,
+ const unsigned int *mc_types,
+ unsigned int num_mc_types,
+ XvPortID *port_id,
+ int *surface_type_id,
+ unsigned int *is_overlay,
+ unsigned int *intra_unsigned
+);
+
+unsigned int align(unsigned int value, unsigned int alignment);
+
+int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y);
+
+#endif
diff --git a/src/gallium/state_trackers/xorg/xvmc/tests/xvmc_bench.c b/src/gallium/state_trackers/xorg/xvmc/tests/xvmc_bench.c
new file mode 100644
index 00000000000..bf94d856234
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xvmc/tests/xvmc_bench.c
@@ -0,0 +1,300 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <error.h>
+#include <sys/time.h>
+#include "testlib.h"
+
+#define MACROBLOCK_WIDTH 16
+#define MACROBLOCK_HEIGHT 16
+#define BLOCKS_PER_MACROBLOCK 6
+
+#define DEFAULT_INPUT_WIDTH 720
+#define DEFAULT_INPUT_HEIGHT 480
+#define DEFAULT_REPS 100
+
+#define PIPELINE_STEP_MC 1
+#define PIPELINE_STEP_CSC 2
+#define PIPELINE_STEP_SWAP 4
+
+#define MB_TYPE_I 1
+#define MB_TYPE_P 2
+#define MB_TYPE_B 4
+
+struct Config
+{
+ unsigned int input_width;
+ unsigned int input_height;
+ unsigned int output_width;
+ unsigned int output_height;
+ unsigned int pipeline;
+ unsigned int mb_types;
+ unsigned int reps;
+};
+
+void ParseArgs(int argc, char **argv, struct Config *config);
+
+void ParseArgs(int argc, char **argv, struct Config *config)
+{
+ int fail = 0;
+ int i;
+
+ config->input_width = DEFAULT_INPUT_WIDTH;
+ config->input_height = DEFAULT_INPUT_HEIGHT;
+ config->output_width = 0;
+ config->output_height = 0;
+ config->pipeline = 0;
+ config->mb_types = 0;
+ config->reps = DEFAULT_REPS;
+
+ for (i = 1; i < argc && !fail; ++i)
+ {
+ if (!strcmp(argv[i], "-iw"))
+ {
+ if (sscanf(argv[++i], "%u", &config->input_width) != 1)
+ fail = 1;
+ }
+ else if (!strcmp(argv[i], "-ih"))
+ {
+ if (sscanf(argv[++i], "%u", &config->input_height) != 1)
+ fail = 1;
+ }
+ else if (!strcmp(argv[i], "-ow"))
+ {
+ if (sscanf(argv[++i], "%u", &config->output_width) != 1)
+ fail = 1;
+ }
+ else if (!strcmp(argv[i], "-oh"))
+ {
+ if (sscanf(argv[++i], "%u", &config->output_height) != 1)
+ fail = 1;
+ }
+ else if (!strcmp(argv[i], "-p"))
+ {
+ char *token = strtok(argv[++i], ",");
+
+ while (token && !fail)
+ {
+ if (!strcmp(token, "mc"))
+ config->pipeline |= PIPELINE_STEP_MC;
+ else if (!strcmp(token, "csc"))
+ config->pipeline |= PIPELINE_STEP_CSC;
+ else if (!strcmp(token, "swp"))
+ config->pipeline |= PIPELINE_STEP_SWAP;
+ else
+ fail = 1;
+
+ if (!fail)
+ token = strtok(NULL, ",");
+ }
+ }
+ else if (!strcmp(argv[i], "-mb"))
+ {
+ char *token = strtok(argv[++i], ",");
+
+ while (token && !fail)
+ {
+ if (strcmp(token, "i"))
+ config->mb_types |= MB_TYPE_I;
+ else if (strcmp(token, "p"))
+ config->mb_types |= MB_TYPE_P;
+ else if (strcmp(token, "b"))
+ config->mb_types |= MB_TYPE_B;
+ else
+ fail = 1;
+
+ if (!fail)
+ token = strtok(NULL, ",");
+ }
+ }
+ else if (!strcmp(argv[i], "-r"))
+ {
+ if (sscanf(argv[++i], "%u", &config->reps) != 1)
+ fail = 1;
+ }
+ else
+ fail = 1;
+ }
+
+ if (fail)
+ error
+ (
+ 1, 0,
+ "Bad argument.\n"
+ "\n"
+ "Usage: %s [options]\n"
+ "\t-iw <width>\tInput width\n"
+ "\t-ih <height>\tInput height\n"
+ "\t-ow <width>\tOutput width\n"
+ "\t-oh <height>\tOutput height\n"
+ "\t-p <pipeline>\tPipeline to test\n"
+ "\t-mb <mb type>\tMacroBlock types to use\n"
+ "\t-r <reps>\tRepetitions\n\n"
+ "\tPipeline steps: mc,csc,swap\n"
+ "\tMB types: i,p,b\n",
+ argv[0]
+ );
+
+ if (config->output_width == 0)
+ config->output_width = config->input_width;
+ if (config->output_height == 0)
+ config->output_height = config->input_height;
+ if (!config->pipeline)
+ config->pipeline = PIPELINE_STEP_MC | PIPELINE_STEP_CSC | PIPELINE_STEP_SWAP;
+ if (!config->mb_types)
+ config->mb_types = MB_TYPE_I | MB_TYPE_P | MB_TYPE_B;
+}
+
+int main(int argc, char **argv)
+{
+ struct Config config;
+ Display *display;
+ Window root, window;
+ const unsigned int mc_types[2] = {XVMC_MOCOMP | XVMC_MPEG_2, XVMC_IDCT | XVMC_MPEG_2};
+ XvPortID port_num;
+ int surface_type_id;
+ unsigned int is_overlay, intra_unsigned;
+ int colorkey;
+ XvMCContext context;
+ XvMCSurface surface;
+ XvMCBlockArray block_array;
+ XvMCMacroBlockArray mb_array;
+ unsigned int mbw, mbh;
+ unsigned int mbx, mby;
+ unsigned int reps;
+ struct timeval start, stop, diff;
+ double diff_secs;
+
+ ParseArgs(argc, argv, &config);
+
+ mbw = align(config.input_width, MACROBLOCK_WIDTH) / MACROBLOCK_WIDTH;
+ mbh = align(config.input_height, MACROBLOCK_HEIGHT) / MACROBLOCK_HEIGHT;
+
+ display = XOpenDisplay(NULL);
+
+ if (!GetPort
+ (
+ display,
+ config.input_width,
+ config.input_height,
+ XVMC_CHROMA_FORMAT_420,
+ mc_types,
+ 2,
+ &port_num,
+ &surface_type_id,
+ &is_overlay,
+ &intra_unsigned
+ ))
+ {
+ XCloseDisplay(display);
+ error(1, 0, "Error, unable to find a good port.\n");
+ }
+
+ if (is_overlay)
+ {
+ Atom xv_colorkey = XInternAtom(display, "XV_COLORKEY", 0);
+ XvGetPortAttribute(display, port_num, xv_colorkey, &colorkey);
+ }
+
+ root = XDefaultRootWindow(display);
+ window = XCreateSimpleWindow(display, root, 0, 0, config.output_width, config.output_height, 0, 0, colorkey);
+
+ assert(XvMCCreateContext(display, port_num, surface_type_id, config.input_width, config.input_height, XVMC_DIRECT, &context) == Success);
+ assert(XvMCCreateSurface(display, &context, &surface) == Success);
+ assert(XvMCCreateBlocks(display, &context, mbw * mbh * BLOCKS_PER_MACROBLOCK, &block_array) == Success);
+ assert(XvMCCreateMacroBlocks(display, &context, mbw * mbh, &mb_array) == Success);
+
+ for (mby = 0; mby < mbh; ++mby)
+ for (mbx = 0; mbx < mbw; ++mbx)
+ {
+ mb_array.macro_blocks[mby * mbw + mbx].x = mbx;
+ mb_array.macro_blocks[mby * mbw + mbx].y = mby;
+ mb_array.macro_blocks[mby * mbw + mbx].macroblock_type = XVMC_MB_TYPE_INTRA;
+ /*mb->motion_type = ;*/
+ /*mb->motion_vertical_field_select = ;*/
+ mb_array.macro_blocks[mby * mbw + mbx].dct_type = XVMC_DCT_TYPE_FRAME;
+ /*mb->PMV[0][0][0] = ;
+ mb->PMV[0][0][1] = ;
+ mb->PMV[0][1][0] = ;
+ mb->PMV[0][1][1] = ;
+ mb->PMV[1][0][0] = ;
+ mb->PMV[1][0][1] = ;
+ mb->PMV[1][1][0] = ;
+ mb->PMV[1][1][1] = ;*/
+ mb_array.macro_blocks[mby * mbw + mbx].index = (mby * mbw + mbx) * BLOCKS_PER_MACROBLOCK;
+ mb_array.macro_blocks[mby * mbw + mbx].coded_block_pattern = 0x3F;
+ }
+
+ XSelectInput(display, window, ExposureMask | KeyPressMask);
+ XMapWindow(display, window);
+ XSync(display, 0);
+
+ gettimeofday(&start, NULL);
+
+ for (reps = 0; reps < config.reps; ++reps)
+ {
+ if (config.pipeline & PIPELINE_STEP_MC)
+ {
+ assert(XvMCRenderSurface(display, &context, XVMC_FRAME_PICTURE, &surface, NULL, NULL, 0, mbw * mbh, 0, &mb_array, &block_array) == Success);
+ assert(XvMCFlushSurface(display, &surface) == Success);
+ }
+ if (config.pipeline & PIPELINE_STEP_CSC)
+ assert(XvMCPutSurface(display, &surface, window, 0, 0, config.input_width, config.input_height, 0, 0, config.output_width, config.output_height, XVMC_FRAME_PICTURE) == Success);
+ }
+
+ gettimeofday(&stop, NULL);
+
+ timeval_subtract(&diff, &stop, &start);
+ diff_secs = (double)diff.tv_sec + (double)diff.tv_usec / 1000000.0;
+
+ printf("XvMC Benchmark\n");
+ printf("Input: %u,%u\nOutput: %u,%u\n", config.input_width, config.input_height, config.output_width, config.output_height);
+ printf("Pipeline: ");
+ if (config.pipeline & PIPELINE_STEP_MC)
+ printf("|mc|");
+ if (config.pipeline & PIPELINE_STEP_CSC)
+ printf("|csc|");
+ if (config.pipeline & PIPELINE_STEP_SWAP)
+ printf("|swap|");
+ printf("\n");
+ printf("Reps: %u\n", config.reps);
+ printf("Total time: %.2lf (%.2lf reps / sec)\n", diff_secs, config.reps / diff_secs);
+
+ assert(XvMCDestroyBlocks(display, &block_array) == Success);
+ assert(XvMCDestroyMacroBlocks(display, &mb_array) == Success);
+ assert(XvMCDestroySurface(display, &surface) == Success);
+ assert(XvMCDestroyContext(display, &context) == Success);
+
+ XvUngrabPort(display, port_num, CurrentTime);
+ XDestroyWindow(display, window);
+ XCloseDisplay(display);
+
+ return 0;
+}
diff --git a/src/gallium/state_trackers/xorg/xvmc/xvmc_private.h b/src/gallium/state_trackers/xorg/xvmc/xvmc_private.h
new file mode 100644
index 00000000000..1e2dfb4223a
--- /dev/null
+++ b/src/gallium/state_trackers/xorg/xvmc/xvmc_private.h
@@ -0,0 +1,102 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 xvmc_private_h
+#define xvmc_private_h
+
+#include <X11/Xlib.h>
+#include <X11/extensions/XvMClib.h>
+#include <util/u_debug.h>
+
+#define BLOCK_SIZE_SAMPLES 64
+#define BLOCK_SIZE_BYTES (BLOCK_SIZE_SAMPLES * 2)
+
+struct vl_context;
+struct pipe_surface;
+struct pipe_fence_handle;
+
+typedef struct
+{
+ struct vl_context *vctx;
+ struct pipe_surface *backbuffer;
+ unsigned short subpicture_max_width;
+ unsigned short subpicture_max_height;
+} XvMCContextPrivate;
+
+typedef struct
+{
+ struct pipe_surface *pipe_vsfc;
+ struct pipe_fence_handle *render_fence;
+ struct pipe_fence_handle *disp_fence;
+
+ /* The subpicture associated with this surface, if any. */
+ XvMCSubpicture *subpicture;
+ short subx, suby;
+ unsigned short subw, subh;
+ short surfx, surfy;
+ unsigned short surfw, surfh;
+
+ /* Some XvMC functions take a surface but not a context,
+ so we keep track of which context each surface belongs to. */
+ XvMCContext *context;
+} XvMCSurfacePrivate;
+
+typedef struct
+{
+ struct pipe_surface *sfc;
+
+ /* The surface this subpicture is currently associated with, if any. */
+ XvMCSurface *surface;
+
+ /* Some XvMC functions take a subpicture but not a context,
+ so we keep track of which context each subpicture belongs to. */
+ XvMCContext *context;
+} XvMCSubpicturePrivate;
+
+#define XVMC_OUT 0
+#define XVMC_ERR 1
+#define XVMC_WARN 2
+#define XVMC_TRACE 3
+static INLINE void XVMC_MSG(unsigned int level, const char *fmt, ...)
+{
+ static boolean check_dbg_level = TRUE;
+ static unsigned int debug_level;
+
+ if (check_dbg_level) {
+ debug_level = debug_get_num_option("XVMC_DEBUG", 0);
+ check_dbg_level = FALSE;
+ }
+
+ if (level <= debug_level) {
+ va_list ap;
+ va_start(ap, fmt);
+ _debug_vprintf(fmt, ap);
+ va_end(ap);
+ }
+}
+
+#endif /* xvmc_private_h */
diff --git a/src/gallium/targets/Makefile.vdpau b/src/gallium/targets/Makefile.vdpau
new file mode 100644
index 00000000000..e5c3dad7dad
--- /dev/null
+++ b/src/gallium/targets/Makefile.vdpau
@@ -0,0 +1,61 @@
+# This makefile template is used to build libvdpau_g3dvl.so
+
+LIBBASENAME = vdpau_g3dvl
+LIBNAME = lib$(LIBBASENAME).so
+VDPAU_MAJOR = 1
+VDPAU_MINOR = 0
+INCLUDES = -I$(TOP)/src/gallium/include \
+ -I$(TOP)/src/gallium/drivers \
+ -I$(TOP)/src/gallium/auxiliary \
+ -I$(TOP)/src/gallium/winsys/g3dvl \
+ $(DRIVER_INCLUDES)
+DEFINES = -DGALLIUM_TRACE $(DRIVER_DEFINES)
+LIBS = $(EXTRA_LIB_PATH) $(DRIVER_LIBS) -lvdpau -lXext -lX11 -lm
+STATE_TRACKER_LIB = $(TOP)/src/gallium/state_trackers/vdpau/libvdpautracker.a
+
+# XXX: Hack, VDPAU public funcs aren't exported if we link to libvdpautracker.a :(
+OBJECTS = $(C_SOURCES:.c=.o) \
+ $(ASM_SOURCES:.S=.o) \
+ $(TOP)/src/gallium/state_trackers/vdpau/*.o
+
+##### RULES #####
+
+.c.o:
+ $(CC) -c $(INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@
+
+.S.o:
+ $(CC) -c $(INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@
+
+##### TARGETS #####
+
+default: depend symlinks $(TOP)/$(LIB_DIR)/gallium/$(LIBNAME)
+
+$(TOP)/$(LIB_DIR)/gallium/$(LIBNAME): $(OBJECTS) $(PIPE_DRIVERS) $(STATE_TRACKER_LIB) $(TOP)/$(LIB_DIR)/gallium Makefile
+ $(MKLIB) -o $(LIBBASENAME) -linker '$(CC)' -ldflags '$(LDFLAGS)' \
+ -major $(VDPAU_MAJOR) -minor $(VDPAU_MINOR) $(MKLIB_OPTIONS) \
+ -install $(TOP)/$(LIB_DIR)/gallium \
+ $(OBJECTS) $(STATE_TRACKER_LIB) $(PIPE_DRIVERS) $(LIBS)
+
+$(TOP)/$(LIB_DIR)/gallium:
+ mkdir -p $@
+
+depend: $(C_SOURCES) $(ASM_SOURCES) $(SYMLINKS)
+ rm -f depend
+ touch depend
+ $(MKDEP) $(MKDEP_OPTIONS) $(DEFINES) $(INCLUDES) $(C_SOURCES) \
+ $(ASM_SOURCES) 2> /dev/null
+
+# Emacs tags
+tags:
+ etags `find . -name \*.[ch]` `find ../include`
+
+# Remove .o and backup files
+clean:
+ -rm -f *.o *~ *.so $(SYMLINKS)
+ -rm -f depend depend.bak
+
+#install: $(LIBNAME)
+# $(INSTALL) -d $(DESTDIR)$(DRI_DRIVER_INSTALL_DIR)
+# $(MINSTALL) -m 755 $(LIBNAME) $(DESTDIR)$(DRI_DRIVER_INSTALL_DIR)
+
+include depend
diff --git a/src/gallium/targets/Makefile.xvmc b/src/gallium/targets/Makefile.xvmc
new file mode 100644
index 00000000000..08529b38b70
--- /dev/null
+++ b/src/gallium/targets/Makefile.xvmc
@@ -0,0 +1,62 @@
+# This makefile template is used to build libXvMCg3dvl.so
+
+LIBBASENAME = XvMCg3dvl
+LIBNAME = lib$(LIBBASENAME).so
+XVMC_MAJOR = 1
+XVMC_MINOR = 0
+INCLUDES = -I$(TOP)/src/gallium/include \
+ -I$(TOP)/src/gallium/drivers \
+ -I$(TOP)/src/gallium/auxiliary \
+ -I$(TOP)/src/gallium/winsys \
+ -I$(TOP)/src/gallium/winsys/g3dvl \
+ $(DRIVER_INCLUDES)
+DEFINES = -DGALLIUM_TRACE $(DRIVER_DEFINES)
+LIBS = $(EXTRA_LIB_PATH) $(DRIVER_LIBS) -lXvMC -lXv -lX11 -lm
+STATE_TRACKER_LIB = $(TOP)/src/gallium/state_trackers/xorg/xvmc/libxvmctracker.a
+
+# XXX: Hack, XvMC public funcs aren't exported if we link to libxvmctracker.a :(
+OBJECTS = $(C_SOURCES:.c=.o) \
+ $(ASM_SOURCES:.S=.o) \
+ $(TOP)/src/gallium/state_trackers/xorg/xvmc/*.o
+
+##### RULES #####
+
+.c.o:
+ $(CC) -c $(INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@
+
+.S.o:
+ $(CC) -c $(INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@
+
+##### TARGETS #####
+
+default: depend symlinks $(TOP)/$(LIB_DIR)/gallium/$(LIBNAME)
+
+$(TOP)/$(LIB_DIR)/gallium/$(LIBNAME): $(OBJECTS) $(PIPE_DRIVERS) $(STATE_TRACKER_LIB) $(TOP)/$(LIB_DIR)/gallium Makefile
+ $(MKLIB) -o $(LIBBASENAME) -linker '$(CC)' -ldflags '$(LDFLAGS)' \
+ -major $(XVMC_MAJOR) -minor $(XVMC_MINOR) $(MKLIB_OPTIONS) \
+ -install $(TOP)/$(LIB_DIR)/gallium \
+ $(OBJECTS) $(STATE_TRACKER_LIB) $(PIPE_DRIVERS) $(LIBS)
+
+$(TOP)/$(LIB_DIR)/gallium:
+ mkdir -p $@
+
+depend: $(C_SOURCES) $(ASM_SOURCES) $(SYMLINKS)
+ rm -f depend
+ touch depend
+ $(MKDEP) $(MKDEP_OPTIONS) $(DEFINES) $(INCLUDES) $(C_SOURCES) \
+ $(ASM_SOURCES) 2> /dev/null
+
+# Emacs tags
+tags:
+ etags `find . -name \*.[ch]` `find ../include`
+
+# Remove .o and backup files
+clean:
+ -rm -f *.o *~ *.so $(SYMLINKS)
+ -rm -f depend depend.bak
+
+#install: $(LIBNAME)
+# $(INSTALL) -d $(DESTDIR)$(DRI_DRIVER_INSTALL_DIR)
+# $(MINSTALL) -m 755 $(LIBNAME) $(DESTDIR)$(DRI_DRIVER_INSTALL_DIR)
+
+include depend
diff --git a/src/gallium/targets/dri-nouveau/Makefile b/src/gallium/targets/dri-nouveau/Makefile
index eb1ee859a00..26c927e0a81 100644
--- a/src/gallium/targets/dri-nouveau/Makefile
+++ b/src/gallium/targets/dri-nouveau/Makefile
@@ -11,6 +11,7 @@ PIPE_DRIVERS = \
$(TOP)/src/gallium/drivers/nvfx/libnvfx.a \
$(TOP)/src/gallium/drivers/nv50/libnv50.a \
$(TOP)/src/gallium/drivers/nvc0/libnvc0.a \
+ $(TOP)/src/gallium/drivers/softpipe/libsoftpipe.a \
$(TOP)/src/gallium/drivers/nouveau/libnouveau.a
C_SOURCES = \
diff --git a/src/gallium/targets/vdpau-softpipe/Makefile b/src/gallium/targets/vdpau-softpipe/Makefile
new file mode 100644
index 00000000000..29dea50e7fb
--- /dev/null
+++ b/src/gallium/targets/vdpau-softpipe/Makefile
@@ -0,0 +1,19 @@
+TOP = ../../../..
+include $(TOP)/configs/current
+
+DRIVER_DEFINES = -DGALLIUM_SOFTPIPE
+DRIVER_INCLUDES =
+
+PIPE_DRIVERS = \
+ $(TOP)/src/gallium/winsys/sw/xlib/libws_xlib.a \
+ $(TOP)/src/gallium/drivers/softpipe/libsoftpipe.a \
+ $(TOP)/src/gallium/auxiliary/libgallium.a
+
+C_SOURCES = \
+ $(TOP)/src/gallium/winsys/g3dvl/xlib/xsp_winsys.c
+
+DRIVER_LIBS =
+
+include ../Makefile.vdpau
+
+symlinks:
diff --git a/src/gallium/targets/xvmc-nouveau/Makefile b/src/gallium/targets/xvmc-nouveau/Makefile
new file mode 100644
index 00000000000..fe418b07681
--- /dev/null
+++ b/src/gallium/targets/xvmc-nouveau/Makefile
@@ -0,0 +1,23 @@
+TOP = ../../../..
+include $(TOP)/configs/current
+
+#LIBNAME =
+
+PIPE_DRIVERS = \
+ $(TOP)/src/gallium/winsys/g3dvl/dri/libvldri.a \
+ $(TOP)/src/gallium/winsys/nouveau/drm/libnouveaudrm.a \
+ $(TOP)/src/gallium/drivers/nvfx/libnvfx.a \
+ $(TOP)/src/gallium/drivers/nv50/libnv50.a \
+ $(TOP)/src/gallium/drivers/softpipe/libsoftpipe.a \
+ $(TOP)/src/gallium/drivers/nouveau/libnouveau.a \
+ $(TOP)/src/gallium/auxiliary/libgallium.a
+
+C_SOURCES = \
+ $(COMMON_GALLIUM_SOURCES) \
+ $(DRIVER_SOURCES)
+
+DRIVER_LIBS = $(shell pkg-config libdrm_nouveau --libs) -lXfixes
+
+include ../Makefile.xvmc
+
+symlinks:
diff --git a/src/gallium/targets/xvmc-r600/Makefile b/src/gallium/targets/xvmc-r600/Makefile
new file mode 100644
index 00000000000..25aeb65059f
--- /dev/null
+++ b/src/gallium/targets/xvmc-r600/Makefile
@@ -0,0 +1,23 @@
+TOP = ../../../..
+include $(TOP)/configs/current
+
+#LIBNAME =
+
+PIPE_DRIVERS = \
+ $(TOP)/src/gallium/drivers/r600/libr600.a \
+ $(TOP)/src/gallium/winsys/g3dvl/dri/libvldri.a \
+ $(TOP)/src/gallium/winsys/r600/drm/libr600winsys.a \
+ $(TOP)/src/gallium/drivers/softpipe/libsoftpipe.a \
+ $(TOP)/src/gallium/drivers/trace/libtrace.a \
+ $(TOP)/src/gallium/auxiliary/libgallium.a
+
+C_SOURCES = \
+ target.c \
+ $(COMMON_GALLIUM_SOURCES) \
+ $(DRIVER_SOURCES)
+
+DRIVER_LIBS = $(shell pkg-config libdrm_radeon --libs) -lXfixes
+
+include ../Makefile.xvmc
+
+symlinks:
diff --git a/src/gallium/targets/xvmc-r600/target.c b/src/gallium/targets/xvmc-r600/target.c
new file mode 100644
index 00000000000..8753e2bab17
--- /dev/null
+++ b/src/gallium/targets/xvmc-r600/target.c
@@ -0,0 +1,24 @@
+#include "state_tracker/drm_driver.h"
+#include "target-helpers/inline_debug_helper.h"
+#include "r600/drm/r600_drm_public.h"
+#include "r600/r600_public.h"
+
+static struct pipe_screen *create_screen(int fd)
+{
+ struct radeon *radeon;
+ struct pipe_screen *screen;
+
+ radeon = r600_drm_winsys_create(fd);
+ if (!radeon)
+ return NULL;
+
+ screen = r600_screen_create(radeon);
+ if (!screen)
+ return NULL;
+
+ screen = debug_screen_wrap(screen);
+
+ return screen;
+}
+
+DRM_DRIVER_DESCRIPTOR("r600", "radeon", create_screen)
diff --git a/src/gallium/targets/xvmc-softpipe/Makefile b/src/gallium/targets/xvmc-softpipe/Makefile
new file mode 100644
index 00000000000..1e3ff8ac89c
--- /dev/null
+++ b/src/gallium/targets/xvmc-softpipe/Makefile
@@ -0,0 +1,19 @@
+TOP = ../../../..
+include $(TOP)/configs/current
+
+DRIVER_DEFINES = -DGALLIUM_SOFTPIPE
+DRIVER_INCLUDES =
+
+PIPE_DRIVERS = \
+ $(TOP)/src/gallium/winsys/sw/xlib/libws_xlib.a \
+ $(TOP)/src/gallium/drivers/softpipe/libsoftpipe.a \
+ $(TOP)/src/gallium/auxiliary/libgallium.a
+
+C_SOURCES = \
+ $(TOP)/src/gallium/winsys/g3dvl/xlib/xsp_winsys.c
+
+DRIVER_LIBS =
+
+include ../Makefile.xvmc
+
+symlinks:
diff --git a/src/gallium/winsys/g3dvl/Makefile b/src/gallium/winsys/g3dvl/Makefile
new file mode 100644
index 00000000000..6c793e0f15b
--- /dev/null
+++ b/src/gallium/winsys/g3dvl/Makefile
@@ -0,0 +1,12 @@
+# src/gallium/winsys/Makefile
+TOP = ../../../..
+include $(TOP)/configs/current
+
+SUBDIRS = $(GALLIUM_STATE_TRACKERS_DIRS) $(GALLIUM_WINSYS_DIRS)
+
+default install clean:
+ @for dir in $(SUBDIRS) ; do \
+ if [ -d $$dir ] ; then \
+ (cd $$dir && $(MAKE) $@) || exit 1; \
+ fi \
+ done
diff --git a/src/gallium/winsys/g3dvl/dri/Makefile b/src/gallium/winsys/g3dvl/dri/Makefile
new file mode 100644
index 00000000000..b270e780fec
--- /dev/null
+++ b/src/gallium/winsys/g3dvl/dri/Makefile
@@ -0,0 +1,15 @@
+TOP = ../../../../..
+include $(TOP)/configs/current
+
+LIBNAME = vldri
+
+LIBRARY_INCLUDES = -I$(TOP)/src/gallium/winsys/g3dvl \
+ $(shell pkg-config libdrm --cflags-only-I)
+
+C_SOURCES = \
+ driclient.c \
+ XF86dri.c \
+ dri2.c \
+ dri_winsys.c
+
+include ../../../Makefile.template
diff --git a/src/driclient/src/XF86dri.c b/src/gallium/winsys/g3dvl/dri/XF86dri.c
index 831a7603396..831a7603396 100644
--- a/src/driclient/src/XF86dri.c
+++ b/src/gallium/winsys/g3dvl/dri/XF86dri.c
diff --git a/src/gallium/winsys/g3dvl/dri/dri2.c b/src/gallium/winsys/g3dvl/dri/dri2.c
new file mode 100644
index 00000000000..23fb7780882
--- /dev/null
+++ b/src/gallium/winsys/g3dvl/dri/dri2.c
@@ -0,0 +1,669 @@
+/*
+ * Copyright © 2008 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Soft-
+ * ware"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, provided that the above copyright
+ * notice(s) and this permission notice appear in all copies of the Soft-
+ * ware and that both the above copyright notice(s) and this permission
+ * notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
+ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
+ * MANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization of
+ * the copyright holder.
+ *
+ * Authors:
+ * Kristian Høgsberg ([email protected])
+ */
+
+
+#define NEED_REPLIES
+#include <stdio.h>
+#include <X11/Xlibint.h>
+#include <X11/extensions/Xext.h>
+#include <X11/extensions/extutil.h>
+#include <X11/extensions/dri2proto.h>
+#include "xf86drm.h"
+#include "dri2.h"
+#if 0
+#include "glxclient.h"
+#include "GL/glxext.h"
+#endif
+
+/* Allow the build to work with an older versions of dri2proto.h and
+ * dri2tokens.h.
+ */
+#if DRI2_MINOR < 1
+#undef DRI2_MINOR
+#define DRI2_MINOR 1
+#define X_DRI2GetBuffersWithFormat 7
+#endif
+
+
+static char dri2ExtensionName[] = DRI2_NAME;
+static XExtensionInfo *dri2Info;
+static XEXT_GENERATE_CLOSE_DISPLAY (DRI2CloseDisplay, dri2Info)
+
+static Bool
+DRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire);
+static Status
+DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire);
+
+static /* const */ XExtensionHooks dri2ExtensionHooks = {
+ NULL, /* create_gc */
+ NULL, /* copy_gc */
+ NULL, /* flush_gc */
+ NULL, /* free_gc */
+ NULL, /* create_font */
+ NULL, /* free_font */
+ DRI2CloseDisplay, /* close_display */
+ DRI2WireToEvent, /* wire_to_event */
+ DRI2EventToWire, /* event_to_wire */
+ NULL, /* error */
+ NULL, /* error_string */
+};
+
+static XEXT_GENERATE_FIND_DISPLAY (DRI2FindDisplay,
+ dri2Info,
+ dri2ExtensionName,
+ &dri2ExtensionHooks,
+ 0, NULL)
+
+static Bool
+DRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire)
+{
+#if 0
+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
+ XExtDisplayInfo *glx_info = __glXFindDisplay(dpy);
+
+ XextCheckExtension(dpy, info, dri2ExtensionName, False);
+
+ switch ((wire->u.u.type & 0x7f) - info->codes->first_event) {
+
+#ifdef X_DRI2SwapBuffers
+ case DRI2_BufferSwapComplete:
+ {
+ GLXBufferSwapComplete *aevent = (GLXBufferSwapComplete *)event;
+ xDRI2BufferSwapComplete *awire = (xDRI2BufferSwapComplete *)wire;
+ aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
+ aevent->type =
+ (glx_info->codes->first_event + GLX_BufferSwapComplete) & 0x75;
+ aevent->send_event = (awire->type & 0x80) != 0;
+ aevent->display = dpy;
+ aevent->drawable = awire->drawable;
+ switch (awire->event_type) {
+ case DRI2_EXCHANGE_COMPLETE:
+ aevent->event_type = GLX_EXCHANGE_COMPLETE_INTEL;
+ break;
+ case DRI2_BLIT_COMPLETE:
+ aevent->event_type = GLX_BLIT_COMPLETE_INTEL;
+ break;
+ case DRI2_FLIP_COMPLETE:
+ aevent->event_type = GLX_FLIP_COMPLETE_INTEL;
+ break;
+ default:
+ /* unknown swap completion type */
+ return False;
+ }
+ aevent->ust = ((CARD64)awire->ust_hi << 32) | awire->ust_lo;
+ aevent->msc = ((CARD64)awire->msc_hi << 32) | awire->msc_lo;
+ aevent->sbc = ((CARD64)awire->sbc_hi << 32) | awire->sbc_lo;
+ return True;
+ }
+#endif
+#ifdef DRI2_InvalidateBuffers
+ case DRI2_InvalidateBuffers:
+ {
+ xDRI2InvalidateBuffers *awire = (xDRI2InvalidateBuffers *)wire;
+
+ dri2InvalidateBuffers(dpy, awire->drawable);
+ return False;
+ }
+#endif
+ default:
+ /* client doesn't support server event */
+ break;
+ }
+#endif
+ return False;
+}
+
+/* We don't actually support this. It doesn't make sense for clients to
+ * send each other DRI2 events.
+ */
+static Status
+DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire)
+{
+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
+
+ XextCheckExtension(dpy, info, dri2ExtensionName, False);
+
+ switch (event->type) {
+ default:
+ /* client doesn't support server event */
+ break;
+ }
+
+ return Success;
+}
+
+Bool
+DRI2QueryExtension(Display * dpy, int *eventBase, int *errorBase)
+{
+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
+
+ if (XextHasExtension(info)) {
+ *eventBase = info->codes->first_event;
+ *errorBase = info->codes->first_error;
+ return True;
+ }
+
+ return False;
+}
+
+Bool
+DRI2QueryVersion(Display * dpy, int *major, int *minor)
+{
+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
+ xDRI2QueryVersionReply rep;
+ xDRI2QueryVersionReq *req;
+ int i, nevents;
+
+ XextCheckExtension(dpy, info, dri2ExtensionName, False);
+
+ LockDisplay(dpy);
+ GetReq(DRI2QueryVersion, req);
+ req->reqType = info->codes->major_opcode;
+ req->dri2ReqType = X_DRI2QueryVersion;
+ req->majorVersion = DRI2_MAJOR;
+ req->minorVersion = DRI2_MINOR;
+ if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return False;
+ }
+ *major = rep.majorVersion;
+ *minor = rep.minorVersion;
+ UnlockDisplay(dpy);
+ SyncHandle();
+
+ switch (rep.minorVersion) {
+ case 1:
+ nevents = 0;
+ break;
+ case 2:
+ nevents = 1;
+ break;
+ case 3:
+ default:
+ nevents = 2;
+ break;
+ }
+
+ for (i = 0; i < nevents; i++) {
+ XESetWireToEvent (dpy, info->codes->first_event + i, DRI2WireToEvent);
+ XESetEventToWire (dpy, info->codes->first_event + i, DRI2EventToWire);
+ }
+
+ return True;
+}
+
+Bool
+DRI2Connect(Display * dpy, XID window, char **driverName, char **deviceName)
+{
+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
+ xDRI2ConnectReply rep;
+ xDRI2ConnectReq *req;
+
+ XextCheckExtension(dpy, info, dri2ExtensionName, False);
+
+ LockDisplay(dpy);
+ GetReq(DRI2Connect, req);
+ req->reqType = info->codes->major_opcode;
+ req->dri2ReqType = X_DRI2Connect;
+ req->window = window;
+ req->driverType = DRI2DriverDRI;
+ if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return False;
+ }
+
+ if (rep.driverNameLength == 0 && rep.deviceNameLength == 0) {
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return False;
+ }
+
+ *driverName = Xmalloc(rep.driverNameLength + 1);
+ if (*driverName == NULL) {
+ _XEatData(dpy,
+ ((rep.driverNameLength + 3) & ~3) +
+ ((rep.deviceNameLength + 3) & ~3));
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return False;
+ }
+ _XReadPad(dpy, *driverName, rep.driverNameLength);
+ (*driverName)[rep.driverNameLength] = '\0';
+
+ *deviceName = Xmalloc(rep.deviceNameLength + 1);
+ if (*deviceName == NULL) {
+ Xfree(*driverName);
+ _XEatData(dpy, ((rep.deviceNameLength + 3) & ~3));
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return False;
+ }
+ _XReadPad(dpy, *deviceName, rep.deviceNameLength);
+ (*deviceName)[rep.deviceNameLength] = '\0';
+
+ UnlockDisplay(dpy);
+ SyncHandle();
+
+ return True;
+}
+
+Bool
+DRI2Authenticate(Display * dpy, XID window, drm_magic_t magic)
+{
+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
+ xDRI2AuthenticateReq *req;
+ xDRI2AuthenticateReply rep;
+
+ XextCheckExtension(dpy, info, dri2ExtensionName, False);
+
+ LockDisplay(dpy);
+ GetReq(DRI2Authenticate, req);
+ req->reqType = info->codes->major_opcode;
+ req->dri2ReqType = X_DRI2Authenticate;
+ req->window = window;
+ req->magic = magic;
+
+ if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return False;
+ }
+
+ UnlockDisplay(dpy);
+ SyncHandle();
+
+ return rep.authenticated;
+}
+
+void
+DRI2CreateDrawable(Display * dpy, XID drawable)
+{
+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
+ xDRI2CreateDrawableReq *req;
+
+ XextSimpleCheckExtension(dpy, info, dri2ExtensionName);
+
+ LockDisplay(dpy);
+ GetReq(DRI2CreateDrawable, req);
+ req->reqType = info->codes->major_opcode;
+ req->dri2ReqType = X_DRI2CreateDrawable;
+ req->drawable = drawable;
+ UnlockDisplay(dpy);
+ SyncHandle();
+}
+
+void
+DRI2DestroyDrawable(Display * dpy, XID drawable)
+{
+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
+ xDRI2DestroyDrawableReq *req;
+
+ XextSimpleCheckExtension(dpy, info, dri2ExtensionName);
+
+ XSync(dpy, False);
+
+ LockDisplay(dpy);
+ GetReq(DRI2DestroyDrawable, req);
+ req->reqType = info->codes->major_opcode;
+ req->dri2ReqType = X_DRI2DestroyDrawable;
+ req->drawable = drawable;
+ UnlockDisplay(dpy);
+ SyncHandle();
+}
+
+DRI2Buffer *
+DRI2GetBuffers(Display * dpy, XID drawable,
+ int *width, int *height,
+ unsigned int *attachments, int count, int *outCount)
+{
+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
+ xDRI2GetBuffersReply rep;
+ xDRI2GetBuffersReq *req;
+ DRI2Buffer *buffers;
+ xDRI2Buffer repBuffer;
+ CARD32 *p;
+ int i;
+
+ XextCheckExtension(dpy, info, dri2ExtensionName, False);
+
+ LockDisplay(dpy);
+ GetReqExtra(DRI2GetBuffers, count * 4, req);
+ req->reqType = info->codes->major_opcode;
+ req->dri2ReqType = X_DRI2GetBuffers;
+ req->drawable = drawable;
+ req->count = count;
+ p = (CARD32 *) & req[1];
+ for (i = 0; i < count; i++)
+ p[i] = attachments[i];
+
+ if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return NULL;
+ }
+
+ *width = rep.width;
+ *height = rep.height;
+ *outCount = rep.count;
+
+ buffers = Xmalloc(rep.count * sizeof buffers[0]);
+ if (buffers == NULL) {
+ _XEatData(dpy, rep.count * sizeof repBuffer);
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return NULL;
+ }
+
+ for (i = 0; i < rep.count; i++) {
+ _XReadPad(dpy, (char *) &repBuffer, sizeof repBuffer);
+ buffers[i].attachment = repBuffer.attachment;
+ buffers[i].name = repBuffer.name;
+ buffers[i].pitch = repBuffer.pitch;
+ buffers[i].cpp = repBuffer.cpp;
+ buffers[i].flags = repBuffer.flags;
+ }
+
+ UnlockDisplay(dpy);
+ SyncHandle();
+
+ return buffers;
+}
+
+
+DRI2Buffer *
+DRI2GetBuffersWithFormat(Display * dpy, XID drawable,
+ int *width, int *height,
+ unsigned int *attachments, int count, int *outCount)
+{
+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
+ xDRI2GetBuffersReply rep;
+ xDRI2GetBuffersReq *req;
+ DRI2Buffer *buffers;
+ xDRI2Buffer repBuffer;
+ CARD32 *p;
+ int i;
+
+ XextCheckExtension(dpy, info, dri2ExtensionName, False);
+
+ LockDisplay(dpy);
+ GetReqExtra(DRI2GetBuffers, count * (4 * 2), req);
+ req->reqType = info->codes->major_opcode;
+ req->dri2ReqType = X_DRI2GetBuffersWithFormat;
+ req->drawable = drawable;
+ req->count = count;
+ p = (CARD32 *) & req[1];
+ for (i = 0; i < (count * 2); i++)
+ p[i] = attachments[i];
+
+ if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return NULL;
+ }
+
+ *width = rep.width;
+ *height = rep.height;
+ *outCount = rep.count;
+
+ buffers = Xmalloc(rep.count * sizeof buffers[0]);
+ if (buffers == NULL) {
+ _XEatData(dpy, rep.count * sizeof repBuffer);
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return NULL;
+ }
+
+ for (i = 0; i < rep.count; i++) {
+ _XReadPad(dpy, (char *) &repBuffer, sizeof repBuffer);
+ buffers[i].attachment = repBuffer.attachment;
+ buffers[i].name = repBuffer.name;
+ buffers[i].pitch = repBuffer.pitch;
+ buffers[i].cpp = repBuffer.cpp;
+ buffers[i].flags = repBuffer.flags;
+ }
+
+ UnlockDisplay(dpy);
+ SyncHandle();
+
+ return buffers;
+}
+
+
+void
+DRI2CopyRegion(Display * dpy, XID drawable, XserverRegion region,
+ CARD32 dest, CARD32 src)
+{
+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
+ xDRI2CopyRegionReq *req;
+ xDRI2CopyRegionReply rep;
+
+ XextSimpleCheckExtension(dpy, info, dri2ExtensionName);
+
+ LockDisplay(dpy);
+ GetReq(DRI2CopyRegion, req);
+ req->reqType = info->codes->major_opcode;
+ req->dri2ReqType = X_DRI2CopyRegion;
+ req->drawable = drawable;
+ req->region = region;
+ req->dest = dest;
+ req->src = src;
+
+ _XReply(dpy, (xReply *) & rep, 0, xFalse);
+
+ UnlockDisplay(dpy);
+ SyncHandle();
+}
+
+#ifdef X_DRI2SwapBuffers
+static void
+load_swap_req(xDRI2SwapBuffersReq *req, CARD64 target, CARD64 divisor,
+ CARD64 remainder)
+{
+ req->target_msc_hi = target >> 32;
+ req->target_msc_lo = target & 0xffffffff;
+ req->divisor_hi = divisor >> 32;
+ req->divisor_lo = divisor & 0xffffffff;
+ req->remainder_hi = remainder >> 32;
+ req->remainder_lo = remainder & 0xffffffff;
+}
+
+static CARD64
+vals_to_card64(CARD32 lo, CARD32 hi)
+{
+ return (CARD64)hi << 32 | lo;
+}
+
+void DRI2SwapBuffers(Display *dpy, XID drawable, CARD64 target_msc,
+ CARD64 divisor, CARD64 remainder, CARD64 *count)
+{
+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
+ xDRI2SwapBuffersReq *req;
+ xDRI2SwapBuffersReply rep;
+
+ XextSimpleCheckExtension (dpy, info, dri2ExtensionName);
+
+ LockDisplay(dpy);
+ GetReq(DRI2SwapBuffers, req);
+ req->reqType = info->codes->major_opcode;
+ req->dri2ReqType = X_DRI2SwapBuffers;
+ req->drawable = drawable;
+ load_swap_req(req, target_msc, divisor, remainder);
+
+ _XReply(dpy, (xReply *)&rep, 0, xFalse);
+
+ *count = vals_to_card64(rep.swap_lo, rep.swap_hi);
+
+ UnlockDisplay(dpy);
+ SyncHandle();
+}
+#endif
+
+#ifdef X_DRI2GetMSC
+Bool DRI2GetMSC(Display *dpy, XID drawable, CARD64 *ust, CARD64 *msc,
+ CARD64 *sbc)
+{
+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
+ xDRI2GetMSCReq *req;
+ xDRI2MSCReply rep;
+
+ XextCheckExtension (dpy, info, dri2ExtensionName, False);
+
+ LockDisplay(dpy);
+ GetReq(DRI2GetMSC, req);
+ req->reqType = info->codes->major_opcode;
+ req->dri2ReqType = X_DRI2GetMSC;
+ req->drawable = drawable;
+
+ if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return False;
+ }
+
+ *ust = vals_to_card64(rep.ust_lo, rep.ust_hi);
+ *msc = vals_to_card64(rep.msc_lo, rep.msc_hi);
+ *sbc = vals_to_card64(rep.sbc_lo, rep.sbc_hi);
+
+ UnlockDisplay(dpy);
+ SyncHandle();
+
+ return True;
+}
+#endif
+
+#ifdef X_DRI2WaitMSC
+static void
+load_msc_req(xDRI2WaitMSCReq *req, CARD64 target, CARD64 divisor,
+ CARD64 remainder)
+{
+ req->target_msc_hi = target >> 32;
+ req->target_msc_lo = target & 0xffffffff;
+ req->divisor_hi = divisor >> 32;
+ req->divisor_lo = divisor & 0xffffffff;
+ req->remainder_hi = remainder >> 32;
+ req->remainder_lo = remainder & 0xffffffff;
+}
+
+Bool DRI2WaitMSC(Display *dpy, XID drawable, CARD64 target_msc, CARD64 divisor,
+ CARD64 remainder, CARD64 *ust, CARD64 *msc, CARD64 *sbc)
+{
+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
+ xDRI2WaitMSCReq *req;
+ xDRI2MSCReply rep;
+
+ XextCheckExtension (dpy, info, dri2ExtensionName, False);
+
+ LockDisplay(dpy);
+ GetReq(DRI2WaitMSC, req);
+ req->reqType = info->codes->major_opcode;
+ req->dri2ReqType = X_DRI2WaitMSC;
+ req->drawable = drawable;
+ load_msc_req(req, target_msc, divisor, remainder);
+
+ if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return False;
+ }
+
+ *ust = ((CARD64)rep.ust_hi << 32) | (CARD64)rep.ust_lo;
+ *msc = ((CARD64)rep.msc_hi << 32) | (CARD64)rep.msc_lo;
+ *sbc = ((CARD64)rep.sbc_hi << 32) | (CARD64)rep.sbc_lo;
+
+ UnlockDisplay(dpy);
+ SyncHandle();
+
+ return True;
+}
+#endif
+
+#ifdef X_DRI2WaitSBC
+static void
+load_sbc_req(xDRI2WaitSBCReq *req, CARD64 target)
+{
+ req->target_sbc_hi = target >> 32;
+ req->target_sbc_lo = target & 0xffffffff;
+}
+
+Bool DRI2WaitSBC(Display *dpy, XID drawable, CARD64 target_sbc, CARD64 *ust,
+ CARD64 *msc, CARD64 *sbc)
+{
+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
+ xDRI2WaitSBCReq *req;
+ xDRI2MSCReply rep;
+
+ XextCheckExtension (dpy, info, dri2ExtensionName, False);
+
+ LockDisplay(dpy);
+ GetReq(DRI2WaitSBC, req);
+ req->reqType = info->codes->major_opcode;
+ req->dri2ReqType = X_DRI2WaitSBC;
+ req->drawable = drawable;
+ load_sbc_req(req, target_sbc);
+
+ if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return False;
+ }
+
+ *ust = ((CARD64)rep.ust_hi << 32) | rep.ust_lo;
+ *msc = ((CARD64)rep.msc_hi << 32) | rep.msc_lo;
+ *sbc = ((CARD64)rep.sbc_hi << 32) | rep.sbc_lo;
+
+ UnlockDisplay(dpy);
+ SyncHandle();
+
+ return True;
+}
+#endif
+
+#ifdef X_DRI2SwapInterval
+void DRI2SwapInterval(Display *dpy, XID drawable, int interval)
+{
+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
+ xDRI2SwapIntervalReq *req;
+
+ XextSimpleCheckExtension (dpy, info, dri2ExtensionName);
+
+ LockDisplay(dpy);
+ GetReq(DRI2SwapInterval, req);
+ req->reqType = info->codes->major_opcode;
+ req->dri2ReqType = X_DRI2SwapInterval;
+ req->drawable = drawable;
+ req->interval = interval;
+ UnlockDisplay(dpy);
+ SyncHandle();
+}
+#endif
diff --git a/src/gallium/winsys/g3dvl/dri/dri2.h b/src/gallium/winsys/g3dvl/dri/dri2.h
new file mode 100644
index 00000000000..114e9f8f965
--- /dev/null
+++ b/src/gallium/winsys/g3dvl/dri/dri2.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright © 2007,2008 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Soft-
+ * ware"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, provided that the above copyright
+ * notice(s) and this permission notice appear in all copies of the Soft-
+ * ware and that both the above copyright notice(s) and this permission
+ * notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+ * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+ * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+ * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
+ * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
+ * MANCE OF THIS SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization of
+ * the copyright holder.
+ *
+ * Authors:
+ * Kristian Høgsberg ([email protected])
+ */
+
+#ifndef _DRI2_H_
+#define _DRI2_H_
+
+#include <X11/extensions/Xfixes.h>
+#include <X11/extensions/dri2tokens.h>
+
+typedef struct
+{
+ unsigned int attachment;
+ unsigned int name;
+ unsigned int pitch;
+ unsigned int cpp;
+ unsigned int flags;
+} DRI2Buffer;
+
+extern Bool
+DRI2QueryExtension(Display * display, int *eventBase, int *errorBase);
+
+extern Bool
+DRI2QueryVersion(Display * display, int *major, int *minor);
+
+extern Bool
+DRI2Connect(Display * display, XID window,
+ char **driverName, char **deviceName);
+
+extern Bool
+DRI2Authenticate(Display * display, XID window, drm_magic_t magic);
+
+extern void
+DRI2CreateDrawable(Display * display, XID drawable);
+
+extern void
+DRI2DestroyDrawable(Display * display, XID handle);
+
+extern DRI2Buffer*
+DRI2GetBuffers(Display * dpy, XID drawable,
+ int *width, int *height,
+ unsigned int *attachments, int count,
+ int *outCount);
+
+/**
+ * \note
+ * This function is only supported with DRI2 version 1.1 or later.
+ */
+extern DRI2Buffer*
+DRI2GetBuffersWithFormat(Display * dpy, XID drawable,
+ int *width, int *height,
+ unsigned int *attachments,
+ int count, int *outCount);
+
+extern void
+DRI2CopyRegion(Display * dpy, XID drawable,
+ XserverRegion region,
+ CARD32 dest, CARD32 src);
+
+extern void
+DRI2SwapBuffers(Display *dpy, XID drawable, CARD64 target_msc, CARD64 divisor,
+ CARD64 remainder, CARD64 *count);
+
+extern Bool
+DRI2GetMSC(Display *dpy, XID drawable, CARD64 *ust, CARD64 *msc, CARD64 *sbc);
+
+extern Bool
+DRI2WaitMSC(Display *dpy, XID drawable, CARD64 target_msc, CARD64 divisor,
+ CARD64 remainder, CARD64 *ust, CARD64 *msc, CARD64 *sbc);
+
+extern Bool
+DRI2WaitSBC(Display *dpy, XID drawable, CARD64 target_sbc, CARD64 *ust,
+ CARD64 *msc, CARD64 *sbc);
+
+extern void
+DRI2SwapInterval(Display *dpy, XID drawable, int interval);
+
+#endif
diff --git a/src/gallium/winsys/g3dvl/dri/dri_winsys.c b/src/gallium/winsys/g3dvl/dri/dri_winsys.c
new file mode 100644
index 00000000000..8588ddd17cb
--- /dev/null
+++ b/src/gallium/winsys/g3dvl/dri/dri_winsys.c
@@ -0,0 +1,282 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 <vl_winsys.h>
+#include <driclient.h>
+#include <pipe/p_video_context.h>
+#include <pipe/p_state.h>
+#include <util/u_memory.h>
+#include <util/u_hash.h>
+#include <util/u_hash_table.h>
+#include <state_tracker/drm_driver.h>
+#include <X11/Xlibint.h>
+
+struct vl_dri_screen
+{
+ struct vl_screen base;
+ dri_screen_t *dri_screen;
+ struct util_hash_table *drawable_table;
+ Drawable last_seen_drawable;
+};
+
+struct vl_dri_context
+{
+ struct vl_context base;
+ int fd;
+};
+
+static struct pipe_surface*
+vl_dri2_get_front(struct vl_context *vctx, Drawable drawable)
+{
+ int w, h;
+ unsigned int attachments[1] = {DRI_BUFFER_FRONT_LEFT};
+ int count;
+ DRI2Buffer *dri2_front;
+ struct pipe_resource *front_tex;
+ struct pipe_surface *front_surf = NULL;
+
+ assert(vctx);
+
+ struct vl_dri_screen *vl_dri_scrn = (struct vl_dri_screen*)vctx->vscreen;
+ assert(vl_dri_scrn);
+
+ dri2_front = DRI2GetBuffers(vl_dri_scrn->dri_screen->display,
+ drawable, &w, &h, attachments, 1, &count);
+
+ assert(count == 1);
+
+ if (dri2_front) {
+ struct winsys_handle dri2_front_handle =
+ {
+ .type = DRM_API_HANDLE_TYPE_SHARED,
+ .handle = dri2_front->name,
+ .stride = dri2_front->pitch
+ };
+ struct pipe_resource template;
+ struct pipe_surface surf_template;
+
+ memset(&template, 0, sizeof(struct pipe_resource));
+ template.target = PIPE_TEXTURE_2D;
+ template.format = PIPE_FORMAT_B8G8R8X8_UNORM;
+ template.last_level = 0;
+ template.width0 = w;
+ template.height0 = h;
+ template.depth0 = 1;
+ template.usage = PIPE_USAGE_STATIC;
+ template.bind = PIPE_BIND_RENDER_TARGET;
+ template.flags = 0;
+
+ front_tex = vl_dri_scrn->base.pscreen->resource_from_handle(vl_dri_scrn->base.pscreen, &template, &dri2_front_handle);
+ if (front_tex) {
+ memset(&surf_template, 0, sizeof(surf_template));
+ surf_template.format = front_tex->format;
+ surf_template.usage = PIPE_BIND_RENDER_TARGET;
+ front_surf = vctx->vpipe->create_surface(vctx->vpipe, front_tex, &surf_template);
+ }
+ pipe_resource_reference(&front_tex, NULL);
+ Xfree(dri2_front);
+ }
+
+ return front_surf;
+}
+
+static void
+vl_dri2_flush_frontbuffer(struct pipe_screen *screen,
+ struct pipe_resource *resource,
+ unsigned level, unsigned layer,
+ void *context_private)
+{
+ struct vl_dri_context *vl_dri_ctx = (struct vl_dri_context*)context_private;
+ struct vl_dri_screen *vl_dri_scrn = (struct vl_dri_screen*)vl_dri_ctx->base.vscreen;
+
+ assert(screen);
+ assert(resource);
+ assert(context_private);
+
+ dri2CopyDrawable(vl_dri_scrn->dri_screen, vl_dri_scrn->last_seen_drawable,
+ DRI_BUFFER_FRONT_LEFT, DRI_BUFFER_FAKE_FRONT_LEFT);
+}
+
+struct pipe_surface*
+vl_drawable_surface_get(struct vl_context *vctx, Drawable drawable)
+{
+ assert(vctx);
+
+ struct vl_dri_screen *vl_dri_scrn = (struct vl_dri_screen*)vctx->vscreen;
+ assert(vl_dri_scrn);
+
+ if (vl_dri_scrn->last_seen_drawable != drawable) {
+ /* Hash table business depends on this equality */
+ assert(None == NULL);
+ Drawable lookup_drawable = (Drawable)util_hash_table_get(vl_dri_scrn->drawable_table, (void*)drawable);
+ if (lookup_drawable == None) {
+ dri2CreateDrawable(vl_dri_scrn->dri_screen, drawable);
+ util_hash_table_set(vl_dri_scrn->drawable_table, (void*)drawable, (void*)drawable);
+ }
+ vl_dri_scrn->last_seen_drawable = drawable;
+ }
+
+ return vl_dri2_get_front(vctx, drawable);
+}
+
+void*
+vl_contextprivate_get(struct vl_context *vctx, struct pipe_surface *displaytarget)
+{
+ return vctx;
+}
+
+static unsigned drawable_hash(void *key)
+{
+ Drawable drawable = (Drawable)key;
+ assert(drawable != None);
+ return util_hash_crc32(&drawable, sizeof(Drawable));
+}
+
+static int drawable_cmp(void *key1, void *key2)
+{
+ Drawable d1 = (Drawable)key1;
+ Drawable d2 = (Drawable)key2;
+ assert(d1 != None);
+ assert(d2 != None);
+ return d1 != d2;
+}
+
+static enum pipe_error
+drawable_destroy(void *key, void *value, void *data)
+{
+ Drawable drawable = (Drawable)key;
+ struct vl_dri_screen *vl_dri_scrn = (struct vl_dri_screen*)data;
+
+ assert(drawable != None);
+ assert(value);
+ assert(data);
+
+ dri2DestroyDrawable(vl_dri_scrn->dri_screen, drawable);
+
+ return PIPE_OK;
+}
+
+struct vl_screen*
+vl_screen_create(Display *display, int screen)
+{
+ struct vl_dri_screen *vl_dri_scrn;
+
+ assert(display);
+
+ vl_dri_scrn = CALLOC_STRUCT(vl_dri_screen);
+ if (!vl_dri_scrn)
+ goto no_struct;
+
+ if (dri2CreateScreen(display, screen, &vl_dri_scrn->dri_screen))
+ goto no_dri2screen;
+
+ vl_dri_scrn->base.pscreen = driver_descriptor.create_screen(vl_dri_scrn->dri_screen->fd);
+
+ if (!vl_dri_scrn->base.pscreen)
+ goto no_pscreen;
+
+ vl_dri_scrn->drawable_table = util_hash_table_create(&drawable_hash, &drawable_cmp);
+ if (!vl_dri_scrn->drawable_table)
+ goto no_hash;
+
+ vl_dri_scrn->last_seen_drawable = None;
+ vl_dri_scrn->base.pscreen->flush_frontbuffer = vl_dri2_flush_frontbuffer;
+
+ return &vl_dri_scrn->base;
+
+no_hash:
+ vl_dri_scrn->base.pscreen->destroy(vl_dri_scrn->base.pscreen);
+no_pscreen:
+ dri2DestroyScreen(vl_dri_scrn->dri_screen);
+no_dri2screen:
+ FREE(vl_dri_scrn);
+no_struct:
+ return NULL;
+}
+
+void vl_screen_destroy(struct vl_screen *vscreen)
+{
+ struct vl_dri_screen *vl_dri_scrn = (struct vl_dri_screen*)vscreen;
+
+ assert(vscreen);
+
+ util_hash_table_foreach(vl_dri_scrn->drawable_table, drawable_destroy, vl_dri_scrn);
+ util_hash_table_destroy(vl_dri_scrn->drawable_table);
+ vl_dri_scrn->base.pscreen->destroy(vl_dri_scrn->base.pscreen);
+ dri2DestroyScreen(vl_dri_scrn->dri_screen);
+ FREE(vl_dri_scrn);
+}
+
+struct vl_context*
+vl_video_create(struct vl_screen *vscreen,
+ enum pipe_video_profile profile,
+ enum pipe_video_chroma_format chroma_format,
+ unsigned width, unsigned height)
+{
+ struct vl_dri_screen *vl_dri_scrn = (struct vl_dri_screen*)vscreen;
+ struct vl_dri_context *vl_dri_ctx;
+
+ vl_dri_ctx = CALLOC_STRUCT(vl_dri_context);
+ if (!vl_dri_ctx)
+ goto no_struct;
+
+ if (!vscreen->pscreen->video_context_create) {
+ debug_printf("[G3DVL] No video support found on %s/%s.\n",
+ vscreen->pscreen->get_vendor(vscreen->pscreen),
+ vscreen->pscreen->get_name(vscreen->pscreen));
+ goto no_vpipe;
+ }
+
+ vl_dri_ctx->base.vpipe = vscreen->pscreen->video_context_create(vscreen->pscreen,
+ profile, chroma_format,
+ width, height,
+ vl_dri_ctx);
+
+ if (!vl_dri_ctx->base.vpipe)
+ goto no_vpipe;
+
+ vl_dri_ctx->base.vpipe->priv = vl_dri_ctx;
+ vl_dri_ctx->base.vscreen = vscreen;
+ vl_dri_ctx->fd = vl_dri_scrn->dri_screen->fd;
+
+ return &vl_dri_ctx->base;
+
+no_vpipe:
+ FREE(vl_dri_ctx);
+no_struct:
+ return NULL;
+}
+
+void vl_video_destroy(struct vl_context *vctx)
+{
+ struct vl_dri_context *vl_dri_ctx = (struct vl_dri_context*)vctx;
+
+ assert(vctx);
+
+ vl_dri_ctx->base.vpipe->destroy(vl_dri_ctx->base.vpipe);
+ FREE(vl_dri_ctx);
+}
diff --git a/src/driclient/src/driclient.c b/src/gallium/winsys/g3dvl/dri/driclient.c
index dc2189afec3..90e48a7cb28 100644
--- a/src/driclient/src/driclient.c
+++ b/src/gallium/winsys/g3dvl/dri/driclient.c
@@ -1,6 +1,8 @@
#include "driclient.h"
#include <assert.h>
#include <stdlib.h>
+#include <fcntl.h>
+#include <X11/Xlibint.h>
int driCreateScreen(Display *display, int screen, dri_screen_t **dri_screen, dri_framebuffer_t *dri_framebuf)
{
@@ -222,12 +224,12 @@ int driUpdateDrawableInfo(dri_drawable_t *dri_drawable)
dri_drawable->dri_screen->display,
dri_drawable->dri_screen->num,
dri_drawable->x_drawable,
- &dri_drawable->sarea_index,
- &dri_drawable->last_sarea_stamp,
- &dri_drawable->x,
- &dri_drawable->y,
- &dri_drawable->w,
- &dri_drawable->h,
+ &dri_drawable->sarea_index,
+ &dri_drawable->last_sarea_stamp,
+ &dri_drawable->x,
+ &dri_drawable->y,
+ &dri_drawable->w,
+ &dri_drawable->h,
&dri_drawable->num_cliprects,
&dri_drawable->cliprects,
&dri_drawable->back_x,
@@ -308,3 +310,79 @@ int driDestroyContext(dri_context_t *dri_context)
return 0;
}
+
+int dri2CreateScreen(Display *display, int screen, dri_screen_t **dri_screen)
+{
+ dri_screen_t *dri_scrn;
+ drm_magic_t magic;
+ char *drvName;
+ char *devName;
+
+ dri_scrn = calloc(1, sizeof(dri_screen_t));
+
+ if (!dri_scrn)
+ return 1;
+
+ if (!DRI2Connect(display, XRootWindow(display, screen), &drvName, &devName))
+ goto free_screen;
+
+ dri_scrn->fd = open(devName, O_RDWR);
+ Xfree(drvName);
+ Xfree(devName);
+ if (dri_scrn->fd < 0)
+ goto free_screen;
+
+ if (drmGetMagic(dri_scrn->fd, &magic))
+ goto free_screen;
+
+ if (!DRI2Authenticate(display, RootWindow(display, screen), magic))
+ goto free_screen;
+
+ dri_scrn->display = display;
+ dri_scrn->num = screen;
+ *dri_screen = dri_scrn;
+
+ return 0;
+
+free_screen:
+ free(dri_scrn);
+
+ return 1;
+}
+
+int dri2DestroyScreen(dri_screen_t *dri_screen)
+{
+ /* Not much to do here apparently... */
+ assert(dri_screen);
+ free(dri_screen);
+ return 0;
+}
+
+int dri2CreateDrawable(dri_screen_t *dri_screen, XID drawable)
+{
+ assert(dri_screen);
+ DRI2CreateDrawable(dri_screen->display, drawable);
+ return 0;
+}
+
+int dri2DestroyDrawable(dri_screen_t *dri_screen, XID drawable)
+{
+ assert(dri_screen);
+ DRI2DestroyDrawable(dri_screen->display, drawable);
+ return 0;
+}
+
+int dri2CopyDrawable(dri_screen_t *dri_screen, XID drawable, int dest, int src)
+{
+ XserverRegion region;
+
+ assert(dri_screen);
+ assert(dest >= DRI_BUFFER_FRONT_LEFT && dest <= DRI_BUFFER_DEPTH_STENCIL);
+ assert(src >= DRI_BUFFER_FRONT_LEFT && src <= DRI_BUFFER_DEPTH_STENCIL);
+
+ region = XFixesCreateRegionFromWindow(dri_screen->display, drawable, WindowRegionBounding);
+ DRI2CopyRegion(dri_screen->display, drawable, region, dest, src);
+ XFixesDestroyRegion(dri_screen->display, region);
+
+ return 0;
+}
diff --git a/src/driclient/include/driclient.h b/src/gallium/winsys/g3dvl/dri/driclient.h
index d3915250392..4e4fd362395 100644
--- a/src/driclient/include/driclient.h
+++ b/src/gallium/winsys/g3dvl/dri/driclient.h
@@ -2,9 +2,12 @@
#define driclient_h
#include <stdint.h>
+#include <X11/Xmd.h>
#include <X11/Xlib.h>
#include <drm_sarea.h>
+//#include <X11/extensions/dri2proto.h>
#include "xf86dri.h"
+#include "dri2.h"
/* TODO: Bring in DRI XML options */
@@ -93,5 +96,22 @@ do \
} \
} while (0)
+int dri2CreateScreen(Display *display, int screen, dri_screen_t **dri_screen);
+int dri2DestroyScreen(dri_screen_t *dri_screen);
+int dri2CreateDrawable(dri_screen_t *dri_screen, XID drawable);
+int dri2DestroyDrawable(dri_screen_t *dri_screen, XID drawable);
+int dri2CopyDrawable(dri_screen_t *dri_screen, XID drawable, int dest, int src);
+
+#define DRI_BUFFER_FRONT_LEFT 0
+#define DRI_BUFFER_BACK_LEFT 1
+#define DRI_BUFFER_FRONT_RIGHT 2
+#define DRI_BUFFER_BACK_RIGHT 3
+#define DRI_BUFFER_DEPTH 4
+#define DRI_BUFFER_STENCIL 5
+#define DRI_BUFFER_ACCUM 6
+#define DRI_BUFFER_FAKE_FRONT_LEFT 7
+#define DRI_BUFFER_FAKE_FRONT_RIGHT 8
+#define DRI_BUFFER_DEPTH_STENCIL 9 /**< Only available with DRI2 1.1 */
+
#endif
diff --git a/src/driclient/include/xf86dri.h b/src/gallium/winsys/g3dvl/dri/xf86dri.h
index baf80a7a9dd..baf80a7a9dd 100644
--- a/src/driclient/include/xf86dri.h
+++ b/src/gallium/winsys/g3dvl/dri/xf86dri.h
diff --git a/src/driclient/src/xf86dristr.h b/src/gallium/winsys/g3dvl/dri/xf86dristr.h
index b834bd1a1a0..b834bd1a1a0 100644
--- a/src/driclient/src/xf86dristr.h
+++ b/src/gallium/winsys/g3dvl/dri/xf86dristr.h
diff --git a/src/gallium/winsys/g3dvl/drm/Makefile b/src/gallium/winsys/g3dvl/drm/Makefile
new file mode 100644
index 00000000000..0711f44d8e3
--- /dev/null
+++ b/src/gallium/winsys/g3dvl/drm/Makefile
@@ -0,0 +1,12 @@
+# src/gallium/winsys/Makefile
+TOP = ../../../../..
+include $(TOP)/configs/current
+
+SUBDIRS = $(GALLIUM_WINSYS_DRM_DIRS)
+
+default install clean:
+ @for dir in $(SUBDIRS) ; do \
+ if [ -d $$dir ] ; then \
+ (cd $$dir && $(MAKE) $@) || exit 1; \
+ fi \
+ done
diff --git a/src/gallium/winsys/g3dvl/drm/Makefile.template b/src/gallium/winsys/g3dvl/drm/Makefile.template
new file mode 100644
index 00000000000..2b79deef4bc
--- /dev/null
+++ b/src/gallium/winsys/g3dvl/drm/Makefile.template
@@ -0,0 +1,66 @@
+XVMC_MAJOR = 1
+XVMC_MINOR = 0
+XVMC_LIB = XvMCg3dvl
+XVMC_LIB_NAME = lib$(XVMC_LIB).so
+XVMC_LIB_DEPS = $(EXTRA_LIB_PATH) -lXvMC -lXv -lX11 -lm
+
+###############################################################
+
+INCLUDES = $(DRIVER_INCLUDES) \
+ -I$(TOP)/src/gallium/include \
+ -I$(TOP)/src/gallium/auxiliary \
+ -I$(TOP)/src/gallium/drivers \
+ -I$(TOP)/src/gallium/winsys/g3dvl \
+ -I$(TOP)/src/gallium/winsys/g3dvl/dri
+
+DEFINES += $(DRIVER_DEFINES) \
+ -DGALLIUM_SOFTPIPE \
+ -DGALLIUM_TRACE
+
+# XXX: Hack, if we include libxvmctracker.a in LIBS none of the symbols are
+# pulled in by the linker because xsp_winsys.c doesn't refer to them
+OBJECTS = $(C_SOURCES:.c=.o) $(TOP)/src/gallium/state_trackers/xorg/xvmc/*.o
+
+LIBS = $(TOP)/src/gallium/winsys/g3dvl/dri/libvldri.a \
+ $(PIPE_DRIVERS) \
+ $(TOP)/src/gallium/auxiliary/libgallium.a
+
+.c.o:
+ $(CC) -c $(INCLUDES) $(DEFINES) $(CFLAGS) $< -o $@
+
+.S.o:
+ $(CC) -c $(INCLUDES) $(DEFINES) $(CFLAGS) $< -o $@
+
+.PHONY: default $(TOP)/$(LIB_DIR)/gallium clean
+
+default: depend $(TOP)/$(LIB_DIR)/gallium $(TOP)/$(LIB_DIR)/gallium/$(XVMC_LIB_NAME)
+
+$(TOP)/$(LIB_DIR)/gallium:
+ @mkdir -p $(TOP)/$(LIB_DIR)/gallium
+
+# Make the libXvMCg3dvl.so library
+$(TOP)/$(LIB_DIR)/gallium/$(XVMC_LIB_NAME): $(OBJECTS) $(LIBS) Makefile
+ $(MKLIB) -o $(XVMC_LIB) -linker '$(CC)' -ldflags '$(LDFLAGS)' \
+ -major $(XVMC_MAJOR) -minor $(XVMC_MINOR) $(MKLIB_OPTIONS) \
+ -install $(TOP)/$(LIB_DIR)/gallium -id $(INSTALL_LIB_DIR)/lib$(XVMC_LIB).1.dylib \
+ $(XVMC_LIB_DEPS) $(DRIVER_LIB_DEPS) $(OBJECTS) $(LIBS)
+
+depend: $(SOURCES) Makefile
+ $(RM) depend
+ touch depend
+ $(MKDEP) $(MKDEP_OPTIONS) $(DEFINES) $(INCLUDES) $(SOURCES)
+
+#install: default
+# $(INSTALL) -d $(INSTALL_DIR)/include/GL
+# $(INSTALL) -d $(INSTALL_DIR)/$(LIB_DIR)
+# $(INSTALL) -m 644 $(TOP)/include/GL/*.h $(INSTALL_DIR)/include/GL
+# @if [ -e $(TOP)/$(LIB_DIR)/$(GL_LIB_NAME) ]; then \
+# $(INSTALL) $(TOP)/$(LIB_DIR)/libGL* $(INSTALL_DIR)/$(LIB_DIR); \
+# fi
+
+clean: Makefile
+ $(RM) $(TOP)/$(LIB_DIR)/gallium/$(XVMC_LIB_NAME)
+ $(RM) *.o *~
+ $(RM) depend depend.bak
+
+-include depend
diff --git a/src/gallium/winsys/g3dvl/drm/nouveau/Makefile b/src/gallium/winsys/g3dvl/drm/nouveau/Makefile
new file mode 100644
index 00000000000..5c55186f672
--- /dev/null
+++ b/src/gallium/winsys/g3dvl/drm/nouveau/Makefile
@@ -0,0 +1,23 @@
+# This makefile produces a libXvMCg3dvl.so which is
+# based on DRM/DRI
+
+TOP = ../../../../../..
+include $(TOP)/configs/current
+
+C_SOURCES =
+
+DRIVER_INCLUDES = $(shell pkg-config libdrm libdrm_nouveau --cflags-only-I) \
+ -I$(TOP)/src/gallium/winsys/drm/nouveau
+DRIVER_DEFINES = $(shell pkg-config libdrm libdrm_nouveau --cflags-only-other)
+
+PIPE_DRIVERS = \
+ $(TOP)/src/gallium/winsys/drm/nouveau/drm/libnouveaudrm.a \
+ $(TOP)/src/gallium/drivers/nv30/libnv30.a \
+ $(TOP)/src/gallium/drivers/nv40/libnv40.a \
+ $(TOP)/src/gallium/drivers/nv50/libnv50.a \
+ $(TOP)/src/gallium/drivers/nouveau/libnouveau.a \
+ $(TOP)/src/gallium/drivers/softpipe/libsoftpipe.a
+
+DRIVER_LIB_DEPS += $(shell pkg-config libdrm_nouveau --libs)
+
+include ../Makefile.template
diff --git a/src/gallium/winsys/g3dvl/drm/radeon/Makefile b/src/gallium/winsys/g3dvl/drm/radeon/Makefile
new file mode 100644
index 00000000000..0f7fd1c15ad
--- /dev/null
+++ b/src/gallium/winsys/g3dvl/drm/radeon/Makefile
@@ -0,0 +1,20 @@
+# This makefile produces a libXvMCg3dvl.so which is
+# based on DRM/DRI
+
+TOP = ../../../../../..
+include $(TOP)/configs/current
+
+C_SOURCES =
+
+DRIVER_INCLUDES = $(shell pkg-config libdrm libdrm_radeon --cflags-only-I) \
+ -I$(TOP)/src/gallium/winsys/drm/radeon \
+DRIVER_DEFINES = $(shell pkg-config libdrm libdrm_radeon --cflags-only-other)
+
+PIPE_DRIVERS = \
+ $(TOP)/src/gallium/winsys/drm/radeon/core/libradeonwinsys.a \
+ $(TOP)/src/gallium/drivers/r300/libr300.a \
+ $(TOP)/src/gallium/drivers/softpipe/libsoftpipe.a
+
+DRIVER_LIB_DEPS += $(shell pkg-config libdrm_radeon --libs)
+
+include ../Makefile.template
diff --git a/src/gallium/winsys/g3dvl/vl_winsys.h b/src/gallium/winsys/g3dvl/vl_winsys.h
new file mode 100644
index 00000000000..58f548849f6
--- /dev/null
+++ b/src/gallium/winsys/g3dvl/vl_winsys.h
@@ -0,0 +1,69 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 vl_winsys_h
+#define vl_winsys_h
+
+#include <X11/Xlib.h>
+#include <pipe/p_defines.h>
+#include <pipe/p_format.h>
+
+struct pipe_screen;
+struct pipe_video_context;
+struct pipe_surface;
+
+struct vl_screen
+{
+ struct pipe_screen *pscreen;
+};
+
+struct vl_context
+{
+ struct vl_screen *vscreen;
+ struct pipe_video_context *vpipe;
+};
+
+struct vl_screen*
+vl_screen_create(Display *display, int screen);
+
+void vl_screen_destroy(struct vl_screen *vscreen);
+
+struct vl_context*
+vl_video_create(struct vl_screen *vscreen,
+ enum pipe_video_profile profile,
+ enum pipe_video_chroma_format chroma_format,
+ unsigned width, unsigned height);
+
+void vl_video_destroy(struct vl_context *vctx);
+
+struct pipe_surface*
+vl_drawable_surface_get(struct vl_context *vctx, Drawable drawable);
+
+void*
+vl_contextprivate_get(struct vl_context *vctx, struct pipe_surface *drawable_surface);
+
+#endif
diff --git a/src/gallium/winsys/g3dvl/xlib/xsp_winsys.c b/src/gallium/winsys/g3dvl/xlib/xsp_winsys.c
new file mode 100644
index 00000000000..cc80583f088
--- /dev/null
+++ b/src/gallium/winsys/g3dvl/xlib/xsp_winsys.c
@@ -0,0 +1,202 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * 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 <vl_winsys.h>
+#include <X11/Xlibint.h>
+#include <state_tracker/xlib_sw_winsys.h>
+#include <util/u_memory.h>
+#include <util/u_format.h>
+#include <softpipe/sp_public.h>
+#include <softpipe/sp_video_context.h>
+
+struct vl_xsp_screen
+{
+ struct vl_screen base;
+ Display *display;
+ int screen;
+ Visual visual;
+ struct xlib_drawable xdraw;
+ struct pipe_surface *drawable_surface;
+};
+
+struct pipe_surface*
+vl_drawable_surface_get(struct vl_screen *vscreen, Drawable drawable)
+{
+ struct vl_xsp_screen *xsp_screen = (struct vl_xsp_screen*)vscreen;
+ Window root;
+ int x, y;
+ unsigned int width, height;
+ unsigned int border_width;
+ unsigned int depth;
+ struct pipe_resource templat, *drawable_tex;
+ struct pipe_surface *drawable_surface = NULL;
+
+ assert(vscreen);
+ assert(drawable != None);
+
+ if (XGetGeometry(xsp_screen->display, drawable, &root, &x, &y, &width, &height, &border_width, &depth) == BadDrawable)
+ return NULL;
+
+ xsp_screen->xdraw.drawable = drawable;
+
+ if (xsp_screen->drawable_surface) {
+ if (xsp_screen->drawable_surface->width == width &&
+ xsp_screen->drawable_surface->height == height) {
+ pipe_surface_reference(&drawable_surface, xsp_screen->drawable_surface);
+ return drawable_surface;
+ }
+ else
+ pipe_surface_reference(&xsp_screen->drawable_surface, NULL);
+ }
+
+ memset(&templat, 0, sizeof(struct pipe_resource));
+ templat.target = PIPE_TEXTURE_2D;
+ /* XXX: Need to figure out drawable's format */
+ templat.format = PIPE_FORMAT_B8G8R8X8_UNORM;
+ templat.last_level = 0;
+ templat.width0 = width;
+ templat.height0 = height;
+ templat.depth0 = 1;
+ templat.usage = PIPE_USAGE_DEFAULT;
+ templat.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_DISPLAY_TARGET;
+ templat.flags = 0;
+
+ drawable_tex = vscreen->pscreen->resource_create(vscreen->pscreen, &templat);
+ if (!drawable_tex)
+ return NULL;
+
+ xsp_screen->drawable_surface = vscreen->pscreen->get_tex_surface(vscreen->pscreen, drawable_tex,
+ 0, 0, 0,
+ templat.bind);
+ pipe_resource_reference(&drawable_tex, NULL);
+
+ if (!xsp_screen->drawable_surface)
+ return NULL;
+
+ pipe_surface_reference(&drawable_surface, xsp_screen->drawable_surface);
+
+ xsp_screen->xdraw.depth = 24/*util_format_get_blocksizebits(templat.format) /
+ util_format_get_blockwidth(templat.format)*/;
+
+ return drawable_surface;
+}
+
+void*
+vl_contextprivate_get(struct vl_context *vctx, struct pipe_surface *drawable_surface)
+{
+ struct vl_xsp_screen *xsp_screen = (struct vl_xsp_screen*)vctx->vscreen;
+
+ assert(vctx);
+ assert(drawable_surface);
+ assert(xsp_screen->drawable_surface == drawable_surface);
+
+ return &xsp_screen->xdraw;
+}
+
+struct vl_screen*
+vl_screen_create(Display *display, int screen)
+{
+ struct vl_xsp_screen *xsp_screen;
+ struct sw_winsys *winsys;
+
+ assert(display);
+
+ xsp_screen = CALLOC_STRUCT(vl_xsp_screen);
+ if (!xsp_screen)
+ return NULL;
+
+ winsys = xlib_create_sw_winsys(display);
+ if (!winsys) {
+ FREE(xsp_screen);
+ return NULL;
+ }
+
+ xsp_screen->base.pscreen = softpipe_create_screen(winsys);
+ if (!xsp_screen->base.pscreen) {
+ winsys->destroy(winsys);
+ FREE(xsp_screen);
+ return NULL;
+ }
+
+ xsp_screen->display = display;
+ xsp_screen->screen = screen;
+ xsp_screen->xdraw.visual = XDefaultVisual(display, screen);
+
+ return &xsp_screen->base;
+}
+
+void vl_screen_destroy(struct vl_screen *vscreen)
+{
+ struct vl_xsp_screen *xsp_screen = (struct vl_xsp_screen*)vscreen;
+
+ assert(vscreen);
+
+ pipe_surface_reference(&xsp_screen->drawable_surface, NULL);
+ vscreen->pscreen->destroy(vscreen->pscreen);
+ FREE(vscreen);
+}
+
+struct vl_context*
+vl_video_create(struct vl_screen *vscreen,
+ enum pipe_video_profile profile,
+ enum pipe_video_chroma_format chroma_format,
+ unsigned width, unsigned height)
+{
+ struct pipe_video_context *vpipe;
+ struct vl_context *vctx;
+
+ assert(vscreen);
+ assert(width && height);
+ assert(vscreen->pscreen->video_context_create);
+
+ vpipe = vscreen->pscreen->video_context_create(vscreen->pscreen,
+ profile,
+ chroma_format,
+ width, height, NULL);
+ if (!vpipe)
+ return NULL;
+
+ vctx = CALLOC_STRUCT(vl_context);
+ if (!vctx) {
+ vpipe->destroy(vpipe);
+ return NULL;
+ }
+
+ vpipe->priv = vctx;
+ vctx->vpipe = vpipe;
+ vctx->vscreen = vscreen;
+
+ return vctx;
+}
+
+void vl_video_destroy(struct vl_context *vctx)
+{
+ assert(vctx);
+
+ vctx->vpipe->destroy(vctx->vpipe);
+ FREE(vctx);
+}