diff options
Diffstat (limited to 'src')
87 files changed, 10033 insertions, 47 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 f37d59e9a3a..49ff1653e0e 100644 --- a/src/gallium/auxiliary/Makefile +++ b/src/gallium/auxiliary/Makefile @@ -143,14 +143,11 @@ C_SOURCES = \ util/u_transfer.c \ util/u_resource.c \ util/u_upload_mgr.c \ - target-helpers/wrap_screen.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 \ + target-helpers/wrap_screen.c \ + vl/vl_bitstream_parser.c \ + vl/vl_mpeg12_mc_renderer.c \ + vl/vl_compositor.c \ + vl/vl_csc.c GALLIVM_SOURCES = \ gallivm/lp_bld_arit.c \ diff --git a/src/gallium/auxiliary/SConscript b/src/gallium/auxiliary/SConscript index 94cd74424a0..f22c8b96123 100644 --- a/src/gallium/auxiliary/SConscript +++ b/src/gallium/auxiliary/SConscript @@ -192,12 +192,10 @@ 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', ] diff --git a/src/gallium/auxiliary/util/u_format.csv b/src/gallium/auxiliary/util/u_format.csv index 1fbd83841c1..8e5d4487a67 100644 --- a/src/gallium/auxiliary/util/u_format.csv +++ b/src/gallium/auxiliary/util/u_format.csv @@ -233,3 +233,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..1a05f369d9b --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_compositor.c @@ -0,0 +1,638 @@ +/************************************************************************** + * + * 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, c->vertex_buf.buffer, 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, compositor->fs_const_buf, + 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_mpeg12_mc_renderer.c b/src/gallium/auxiliary/vl/vl_mpeg12_mc_renderer.c new file mode 100644 index 00000000000..977c8d67b55 --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_mpeg12_mc_renderer.c @@ -0,0 +1,1477 @@ +/************************************************************************** + * + * 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 +#define ZERO_BLOCK_NIL -1.0f +#define ZERO_BLOCK_IS_NIL(zb) ((zb).x < 0.0f) +#define SCALE_FACTOR_16_TO_9 (32767.0f / 255.0f) + +struct vertex_shader_consts +{ + struct vertex4f denorm; +}; + +struct fragment_shader_consts +{ + struct vertex4f multiplier; + struct vertex4f div; +}; + +struct vert_stream_0 +{ + struct vertex2f pos; + struct vertex2f luma_tc; + struct vertex2f cb_tc; + struct vertex2f cr_tc; +}; + +enum MACROBLOCK_TYPE +{ + MACROBLOCK_TYPE_INTRA, + MACROBLOCK_TYPE_FWD_FRAME_PRED, + MACROBLOCK_TYPE_FWD_FIELD_PRED, + MACROBLOCK_TYPE_BKWD_FRAME_PRED, + MACROBLOCK_TYPE_BKWD_FIELD_PRED, + MACROBLOCK_TYPE_BI_FRAME_PRED, + MACROBLOCK_TYPE_BI_FIELD_PRED, + + NUM_MACROBLOCK_TYPES +}; + +static bool +create_intra_vert_shader(struct vl_mpeg12_mc_renderer *r) +{ + struct ureg_program *shader; + struct ureg_src vpos, vtex[3]; + struct ureg_dst o_vpos, o_vtex[3]; + unsigned i; + + shader = ureg_create(TGSI_PROCESSOR_VERTEX); + if (!shader) + return false; + + vpos = ureg_DECL_vs_input(shader, 0); + for (i = 0; i < 3; ++i) + vtex[i] = ureg_DECL_vs_input(shader, i + 1); + o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, 0); + for (i = 0; i < 3; ++i) + o_vtex[i] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, i + 1); + + /* + * o_vpos = vpos + * o_vtex[0..2] = vtex[0..2] + */ + ureg_MOV(shader, o_vpos, vpos); + for (i = 0; i < 3; ++i) + ureg_MOV(shader, o_vtex[i], vtex[i]); + + ureg_END(shader); + + r->i_vs = ureg_create_shader_and_destroy(shader, r->pipe); + if (!r->i_vs) + return false; + + return true; +} + +static bool +create_intra_frag_shader(struct vl_mpeg12_mc_renderer *r) +{ + struct ureg_program *shader; + struct ureg_src tc[3]; + struct ureg_src sampler[3]; + struct ureg_dst texel, temp; + struct ureg_dst fragment; + unsigned i; + + shader = ureg_create(TGSI_PROCESSOR_FRAGMENT); + if (!shader) + return false; + + for (i = 0; i < 3; ++i) { + tc[i] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, i + 1, TGSI_INTERPOLATE_LINEAR); + sampler[i] = ureg_DECL_sampler(shader, i); + } + texel = ureg_DECL_temporary(shader); + temp = ureg_DECL_temporary(shader); + fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0); + + /* + * texel.r = tex(tc[0], sampler[0]) + * texel.g = tex(tc[1], sampler[1]) + * texel.b = tex(tc[2], sampler[2]) + * fragment = texel * scale + */ + for (i = 0; i < 3; ++i) { + /* Nouveau can't writemask tex dst regs (yet?), do in two steps */ + ureg_TEX(shader, temp, TGSI_TEXTURE_2D, tc[i], sampler[i]); + ureg_MOV(shader, ureg_writemask(texel, TGSI_WRITEMASK_X << i), ureg_scalar(ureg_src(temp), TGSI_SWIZZLE_X)); + } + ureg_MUL(shader, fragment, ureg_src(texel), ureg_scalar(ureg_imm1f(shader, SCALE_FACTOR_16_TO_9), TGSI_SWIZZLE_X)); + + ureg_release_temporary(shader, texel); + ureg_release_temporary(shader, temp); + ureg_END(shader); + + r->i_fs = ureg_create_shader_and_destroy(shader, r->pipe); + if (!r->i_fs) + return false; + + return true; +} + +static bool +create_frame_pred_vert_shader(struct vl_mpeg12_mc_renderer *r) +{ + struct ureg_program *shader; + struct ureg_src vpos, vtex[4]; + struct ureg_dst o_vpos, o_vtex[4]; + unsigned i; + + shader = ureg_create(TGSI_PROCESSOR_VERTEX); + if (!shader) + return false; + + vpos = ureg_DECL_vs_input(shader, 0); + for (i = 0; i < 4; ++i) + vtex[i] = ureg_DECL_vs_input(shader, i + 1); + o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, 0); + for (i = 0; i < 4; ++i) + o_vtex[i] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, i + 1); + + /* + * o_vpos = vpos + * o_vtex[0..2] = vtex[0..2] + * o_vtex[3] = vpos + vtex[3] // Apply motion vector + */ + ureg_MOV(shader, o_vpos, vpos); + for (i = 0; i < 3; ++i) + ureg_MOV(shader, o_vtex[i], vtex[i]); + ureg_ADD(shader, o_vtex[3], vpos, vtex[3]); + + ureg_END(shader); + + r->p_vs[0] = ureg_create_shader_and_destroy(shader, r->pipe); + if (!r->p_vs[0]) + return false; + + return true; +} + +#if 0 +static void +create_field_pred_vert_shader(struct vl_mpeg12_mc_renderer *r) +{ + assert(false); +} +#endif + +static bool +create_frame_pred_frag_shader(struct vl_mpeg12_mc_renderer *r) +{ + struct ureg_program *shader; + struct ureg_src tc[4]; + struct ureg_src sampler[4]; + struct ureg_dst texel, ref; + struct ureg_dst fragment; + unsigned i; + + shader = ureg_create(TGSI_PROCESSOR_FRAGMENT); + if (!shader) + return false; + + for (i = 0; i < 4; ++i) { + tc[i] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, i + 1, TGSI_INTERPOLATE_LINEAR); + sampler[i] = ureg_DECL_sampler(shader, i); + } + texel = ureg_DECL_temporary(shader); + ref = ureg_DECL_temporary(shader); + fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0); + + /* + * texel.r = tex(tc[0], sampler[0]) + * texel.g = tex(tc[1], sampler[1]) + * texel.b = tex(tc[2], sampler[2]) + * ref = tex(tc[3], sampler[3]) + * fragment = texel * scale + ref + */ + for (i = 0; i < 3; ++i) { + /* Nouveau can't writemask tex dst regs (yet?), do in two steps */ + ureg_TEX(shader, ref, TGSI_TEXTURE_2D, tc[i], sampler[i]); + ureg_MOV(shader, ureg_writemask(texel, TGSI_WRITEMASK_X << i), ureg_scalar(ureg_src(ref), TGSI_SWIZZLE_X)); + } + ureg_TEX(shader, ref, TGSI_TEXTURE_2D, tc[3], sampler[3]); + ureg_MAD(shader, fragment, ureg_src(texel), ureg_scalar(ureg_imm1f(shader, SCALE_FACTOR_16_TO_9), TGSI_SWIZZLE_X), ureg_src(ref)); + + ureg_release_temporary(shader, texel); + ureg_release_temporary(shader, ref); + ureg_END(shader); + + r->p_fs[0] = ureg_create_shader_and_destroy(shader, r->pipe); + if (!r->p_fs[0]) + return false; + + return true; +} + +#if 0 +static void +create_field_pred_frag_shader(struct vl_mpeg12_mc_renderer *r) +{ + assert(false); +} +#endif + +static bool +create_frame_bi_pred_vert_shader(struct vl_mpeg12_mc_renderer *r) +{ + struct ureg_program *shader; + struct ureg_src vpos, vtex[5]; + struct ureg_dst o_vpos, o_vtex[5]; + unsigned i; + + shader = ureg_create(TGSI_PROCESSOR_VERTEX); + if (!shader) + return false; + + vpos = ureg_DECL_vs_input(shader, 0); + for (i = 0; i < 4; ++i) + vtex[i] = ureg_DECL_vs_input(shader, i + 1); + /* Skip input 5 */ + ureg_DECL_vs_input(shader, 5); + vtex[4] = ureg_DECL_vs_input(shader, 6); + o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, 0); + for (i = 0; i < 5; ++i) + o_vtex[i] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, i + 1); + + /* + * o_vpos = vpos + * o_vtex[0..2] = vtex[0..2] + * o_vtex[3..4] = vpos + vtex[3..4] // Apply motion vector + */ + ureg_MOV(shader, o_vpos, vpos); + for (i = 0; i < 3; ++i) + ureg_MOV(shader, o_vtex[i], vtex[i]); + for (i = 3; i < 5; ++i) + ureg_ADD(shader, o_vtex[i], vpos, vtex[i]); + + ureg_END(shader); + + r->b_vs[0] = ureg_create_shader_and_destroy(shader, r->pipe); + if (!r->b_vs[0]) + return false; + + return true; +} + +#if 0 +static void +create_field_bi_pred_vert_shader(struct vl_mpeg12_mc_renderer *r) +{ + assert(false); +} +#endif + +static bool +create_frame_bi_pred_frag_shader(struct vl_mpeg12_mc_renderer *r) +{ + struct ureg_program *shader; + struct ureg_src tc[5]; + struct ureg_src sampler[5]; + struct ureg_dst texel, ref[2]; + struct ureg_dst fragment; + unsigned i; + + shader = ureg_create(TGSI_PROCESSOR_FRAGMENT); + if (!shader) + return false; + + for (i = 0; i < 5; ++i) { + tc[i] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, i + 1, TGSI_INTERPOLATE_LINEAR); + sampler[i] = ureg_DECL_sampler(shader, i); + } + texel = ureg_DECL_temporary(shader); + ref[0] = ureg_DECL_temporary(shader); + ref[1] = ureg_DECL_temporary(shader); + fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0); + + /* + * texel.r = tex(tc[0], sampler[0]) + * texel.g = tex(tc[1], sampler[1]) + * texel.b = tex(tc[2], sampler[2]) + * ref[0..1 = tex(tc[3..4], sampler[3..4]) + * ref[0] = lerp(ref[0], ref[1], 0.5) + * fragment = texel * scale + ref[0] + */ + for (i = 0; i < 3; ++i) { + /* Nouveau can't writemask tex dst regs (yet?), do in two steps */ + ureg_TEX(shader, ref[0], TGSI_TEXTURE_2D, tc[i], sampler[i]); + ureg_MOV(shader, ureg_writemask(texel, TGSI_WRITEMASK_X << i), ureg_scalar(ureg_src(ref[0]), TGSI_SWIZZLE_X)); + } + ureg_TEX(shader, ref[0], TGSI_TEXTURE_2D, tc[3], sampler[3]); + ureg_TEX(shader, ref[1], TGSI_TEXTURE_2D, tc[4], sampler[4]); + ureg_LRP(shader, ref[0], ureg_scalar(ureg_imm1f(shader, 0.5f), TGSI_SWIZZLE_X), ureg_src(ref[0]), ureg_src(ref[1])); + + ureg_MAD(shader, fragment, ureg_src(texel), ureg_scalar(ureg_imm1f(shader, SCALE_FACTOR_16_TO_9), TGSI_SWIZZLE_X), ureg_src(ref[0])); + + ureg_release_temporary(shader, texel); + ureg_release_temporary(shader, ref[0]); + ureg_release_temporary(shader, ref[1]); + ureg_END(shader); + + r->b_fs[0] = ureg_create_shader_and_destroy(shader, r->pipe); + if (!r->b_fs[0]) + return false; + + return true; +} + +#if 0 +static void +create_field_bi_pred_frag_shader(struct vl_mpeg12_mc_renderer *r) +{ + assert(false); +} +#endif + +static void +xfer_buffers_map(struct vl_mpeg12_mc_renderer *r) +{ + unsigned i; + + assert(r); + + for (i = 0; i < 3; ++i) { + struct pipe_box rect = + { + 0, 0, 0, + r->textures.all[i]->width0, + r->textures.all[i]->height0, + 1 + }; + + r->tex_transfer[i] = r->pipe->get_transfer + ( + r->pipe, r->textures.all[i], + u_subresource(0, 0), + PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD, + &rect + ); + + r->texels[i] = r->pipe->transfer_map(r->pipe, r->tex_transfer[i]); + } +} + +static void +xfer_buffers_unmap(struct vl_mpeg12_mc_renderer *r) +{ + unsigned i; + + assert(r); + + for (i = 0; i < 3; ++i) { + r->pipe->transfer_unmap(r->pipe, r->tex_transfer[i]); + r->pipe->transfer_destroy(r->pipe, r->tex_transfer[i]); + } +} + +static bool +init_pipe_state(struct vl_mpeg12_mc_renderer *r) +{ + struct pipe_sampler_state sampler; + unsigned filters[5]; + unsigned i; + + assert(r); + + r->viewport.scale[0] = r->pot_buffers ? + util_next_power_of_two(r->picture_width) : r->picture_width; + r->viewport.scale[1] = r->pot_buffers ? + util_next_power_of_two(r->picture_height) : r->picture_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->pot_buffers ? + util_next_power_of_two(r->picture_width) : r->picture_width; + r->fb_state.height = r->pot_buffers ? + util_next_power_of_two(r->picture_height) : r->picture_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 || + r->eb_handling == VL_MPEG12_MC_RENDERER_EMPTY_BLOCK_XFER_ONE) { + 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_EDGE; + 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[i] = ; */ + /*sampler.max_anisotropy = ; */ + r->samplers.all[i] = r->pipe->create_sampler_state(r->pipe, &sampler); + } + + 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]); +} + +static bool +init_shaders(struct vl_mpeg12_mc_renderer *r) +{ + assert(r); + + create_intra_vert_shader(r); + create_intra_frag_shader(r); + create_frame_pred_vert_shader(r); + create_frame_pred_frag_shader(r); + create_frame_bi_pred_vert_shader(r); + create_frame_bi_pred_frag_shader(r); + + return true; +} + +static void +cleanup_shaders(struct vl_mpeg12_mc_renderer *r) +{ + assert(r); + + r->pipe->delete_vs_state(r->pipe, r->i_vs); + r->pipe->delete_fs_state(r->pipe, r->i_fs); + r->pipe->delete_vs_state(r->pipe, r->p_vs[0]); + r->pipe->delete_fs_state(r->pipe, r->p_fs[0]); + r->pipe->delete_vs_state(r->pipe, r->b_vs[0]); + r->pipe->delete_fs_state(r->pipe, r->b_fs[0]); +} + +static bool +init_buffers(struct vl_mpeg12_mc_renderer *r) +{ + struct pipe_resource template; + struct pipe_vertex_element vertex_elems[8]; + struct pipe_sampler_view sampler_view; + + const unsigned mbw = + align(r->picture_width, MACROBLOCK_WIDTH) / MACROBLOCK_WIDTH; + const unsigned mbh = + align(r->picture_height, MACROBLOCK_HEIGHT) / MACROBLOCK_HEIGHT; + + unsigned i; + + assert(r); + + r->macroblocks_per_batch = + mbw * (r->bufmode == VL_MPEG12_MC_RENDERER_BUFFER_PICTURE ? mbh : 1); + r->num_macroblocks = 0; + r->macroblock_buf = MALLOC(r->macroblocks_per_batch * sizeof(struct pipe_mpeg12_macroblock)); + + 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 = r->pot_buffers ? + util_next_power_of_two(r->picture_width) : r->picture_width; + template.height0 = r->pot_buffers ? + util_next_power_of_two(r->picture_height) : r->picture_height; + template.depth0 = 1; + template.usage = PIPE_USAGE_DYNAMIC; + template.bind = PIPE_BIND_SAMPLER_VIEW; + template.flags = 0; + + r->textures.individual.y = r->pipe->screen->resource_create(r->pipe->screen, &template); + + if (r->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420) { + template.width0 = r->pot_buffers ? + util_next_power_of_two(r->picture_width / 2) : + r->picture_width / 2; + template.height0 = r->pot_buffers ? + util_next_power_of_two(r->picture_height / 2) : + r->picture_height / 2; + } + else if (r->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_422) + template.height0 = r->pot_buffers ? + util_next_power_of_two(r->picture_height / 2) : + r->picture_height / 2; + + r->textures.individual.cb = + r->pipe->screen->resource_create(r->pipe->screen, &template); + r->textures.individual.cr = + r->pipe->screen->resource_create(r->pipe->screen, &template); + + for (i = 0; i < 3; ++i) { + u_sampler_view_default_template(&sampler_view, + r->textures.all[i], + r->textures.all[i]->format); + r->sampler_views.all[i] = r->pipe->create_sampler_view(r->pipe, r->textures.all[i], &sampler_view); + } + + r->vertex_bufs.individual.ycbcr.stride = sizeof(struct vertex2f) * 4; + r->vertex_bufs.individual.ycbcr.max_index = 24 * r->macroblocks_per_batch - 1; + r->vertex_bufs.individual.ycbcr.buffer_offset = 0; + /* XXX: Create with usage DYNAMIC or STREAM */ + r->vertex_bufs.individual.ycbcr.buffer = pipe_buffer_create + ( + r->pipe->screen, + PIPE_BIND_VERTEX_BUFFER, + sizeof(struct vertex2f) * 4 * 24 * r->macroblocks_per_batch + ); + + for (i = 1; i < 3; ++i) { + r->vertex_bufs.all[i].stride = sizeof(struct vertex2f) * 2; + r->vertex_bufs.all[i].max_index = 24 * r->macroblocks_per_batch - 1; + r->vertex_bufs.all[i].buffer_offset = 0; + /* XXX: Create with usage DYNAMIC or STREAM */ + r->vertex_bufs.all[i].buffer = pipe_buffer_create + ( + r->pipe->screen, + PIPE_BIND_VERTEX_BUFFER, + sizeof(struct vertex2f) * 2 * 24 * r->macroblocks_per_batch + ); + } + + memset(&vertex_elems, 0, sizeof(vertex_elems)); + + /* Position element */ + 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; + + /* Luma, texcoord element */ + 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; + + /* Chroma Cr texcoord element */ + vertex_elems[2].src_offset = sizeof(struct vertex2f) * 2; + vertex_elems[2].instance_divisor = 0; + vertex_elems[2].vertex_buffer_index = 0; + vertex_elems[2].src_format = PIPE_FORMAT_R32G32_FLOAT; + + /* Chroma Cb texcoord element */ + vertex_elems[3].src_offset = sizeof(struct vertex2f) * 3; + vertex_elems[3].instance_divisor = 0; + vertex_elems[3].vertex_buffer_index = 0; + vertex_elems[3].src_format = PIPE_FORMAT_R32G32_FLOAT; + + /* First ref surface top field texcoord element */ + vertex_elems[4].src_offset = 0; + vertex_elems[4].instance_divisor = 0; + vertex_elems[4].vertex_buffer_index = 1; + vertex_elems[4].src_format = PIPE_FORMAT_R32G32_FLOAT; + + /* First ref surface bottom field texcoord element */ + vertex_elems[5].src_offset = sizeof(struct vertex2f); + vertex_elems[5].instance_divisor = 0; + vertex_elems[5].vertex_buffer_index = 1; + vertex_elems[5].src_format = PIPE_FORMAT_R32G32_FLOAT; + + /* Second ref surface top field texcoord element */ + vertex_elems[6].src_offset = 0; + vertex_elems[6].instance_divisor = 0; + vertex_elems[6].vertex_buffer_index = 2; + vertex_elems[6].src_format = PIPE_FORMAT_R32G32_FLOAT; + + /* Second ref surface bottom field texcoord element */ + vertex_elems[7].src_offset = sizeof(struct vertex2f); + vertex_elems[7].instance_divisor = 0; + vertex_elems[7].vertex_buffer_index = 2; + vertex_elems[7].src_format = PIPE_FORMAT_R32G32_FLOAT; + + r->vertex_elems_state.individual.i = r->pipe->create_vertex_elements_state(r->pipe, 4, vertex_elems); + r->vertex_elems_state.individual.p = r->pipe->create_vertex_elements_state(r->pipe, 6, vertex_elems); + r->vertex_elems_state.individual.b = r->pipe->create_vertex_elements_state(r->pipe, 8, vertex_elems); + + r->vs_const_buf = pipe_buffer_create + ( + r->pipe->screen, + PIPE_BIND_CONSTANT_BUFFER, + sizeof(struct vertex_shader_consts) + ); + + return true; +} + +static void +cleanup_buffers(struct vl_mpeg12_mc_renderer *r) +{ + unsigned i; + + assert(r); + + pipe_resource_reference(&r->vs_const_buf, NULL); + + for (i = 0; i < 3; ++i) { + pipe_sampler_view_reference(&r->sampler_views.all[i], NULL); + r->pipe->delete_vertex_elements_state(r->pipe, r->vertex_elems_state.all[i]); + pipe_resource_reference(&r->vertex_bufs.all[i].buffer, NULL); + pipe_resource_reference(&r->textures.all[i], NULL); + } + + FREE(r->macroblock_buf); +} + +static enum MACROBLOCK_TYPE +get_macroblock_type(struct pipe_mpeg12_macroblock *mb) +{ + assert(mb); + + switch (mb->mb_type) { + case PIPE_MPEG12_MACROBLOCK_TYPE_INTRA: + return MACROBLOCK_TYPE_INTRA; + case PIPE_MPEG12_MACROBLOCK_TYPE_FWD: + return mb->mo_type == PIPE_MPEG12_MOTION_TYPE_FRAME ? + MACROBLOCK_TYPE_FWD_FRAME_PRED : MACROBLOCK_TYPE_FWD_FIELD_PRED; + case PIPE_MPEG12_MACROBLOCK_TYPE_BKWD: + return mb->mo_type == PIPE_MPEG12_MOTION_TYPE_FRAME ? + MACROBLOCK_TYPE_BKWD_FRAME_PRED : MACROBLOCK_TYPE_BKWD_FIELD_PRED; + case PIPE_MPEG12_MACROBLOCK_TYPE_BI: + return mb->mo_type == PIPE_MPEG12_MOTION_TYPE_FRAME ? + MACROBLOCK_TYPE_BI_FRAME_PRED : MACROBLOCK_TYPE_BI_FIELD_PRED; + default: + assert(0); + } + + /* Unreachable */ + return -1; +} + +static void +gen_block_verts(struct vert_stream_0 *vb, unsigned cbp, unsigned mbx, unsigned mby, + const struct vertex2f *unit, const struct vertex2f *half, const struct vertex2f *offset, + unsigned luma_mask, unsigned cb_mask, unsigned cr_mask, + bool use_zeroblocks, struct vertex2f *zero_blocks) +{ + struct vertex2f v; + + assert(vb); + assert(unit && half && offset); + assert(zero_blocks || !use_zeroblocks); + + /* Generate vertices for two triangles covering a block */ + v.x = mbx * unit->x + offset->x; + v.y = mby * unit->y + offset->y; + + vb[0].pos.x = v.x; + vb[0].pos.y = v.y; + vb[1].pos.x = v.x; + vb[1].pos.y = v.y + half->y; + vb[2].pos.x = v.x + half->x; + vb[2].pos.y = v.y; + vb[3].pos.x = v.x + half->x; + vb[3].pos.y = v.y; + vb[4].pos.x = v.x; + vb[4].pos.y = v.y + half->y; + vb[5].pos.x = v.x + half->x; + vb[5].pos.y = v.y + half->y; + + /* Generate texcoords for the triangles, either pointing to the correct area on the luma/chroma texture + or if zero blocks are being used, to the zero block if the appropriate CBP bits aren't set (i.e. no data + for this channel is defined for this block) */ + + if (!use_zeroblocks || cbp & luma_mask) { + v.x = mbx * unit->x + offset->x; + v.y = mby * unit->y + offset->y; + } + else { + v.x = zero_blocks[0].x; + v.y = zero_blocks[0].y; + } + + vb[0].luma_tc.x = v.x; + vb[0].luma_tc.y = v.y; + vb[1].luma_tc.x = v.x; + vb[1].luma_tc.y = v.y + half->y; + vb[2].luma_tc.x = v.x + half->x; + vb[2].luma_tc.y = v.y; + vb[3].luma_tc.x = v.x + half->x; + vb[3].luma_tc.y = v.y; + vb[4].luma_tc.x = v.x; + vb[4].luma_tc.y = v.y + half->y; + vb[5].luma_tc.x = v.x + half->x; + vb[5].luma_tc.y = v.y + half->y; + + if (!use_zeroblocks || cbp & cb_mask) { + v.x = mbx * unit->x + offset->x; + v.y = mby * unit->y + offset->y; + } + else { + v.x = zero_blocks[1].x; + v.y = zero_blocks[1].y; + } + + vb[0].cb_tc.x = v.x; + vb[0].cb_tc.y = v.y; + vb[1].cb_tc.x = v.x; + vb[1].cb_tc.y = v.y + half->y; + vb[2].cb_tc.x = v.x + half->x; + vb[2].cb_tc.y = v.y; + vb[3].cb_tc.x = v.x + half->x; + vb[3].cb_tc.y = v.y; + vb[4].cb_tc.x = v.x; + vb[4].cb_tc.y = v.y + half->y; + vb[5].cb_tc.x = v.x + half->x; + vb[5].cb_tc.y = v.y + half->y; + + if (!use_zeroblocks || cbp & cr_mask) { + v.x = mbx * unit->x + offset->x; + v.y = mby * unit->y + offset->y; + } + else { + v.x = zero_blocks[2].x; + v.y = zero_blocks[2].y; + } + + vb[0].cr_tc.x = v.x; + vb[0].cr_tc.y = v.y; + vb[1].cr_tc.x = v.x; + vb[1].cr_tc.y = v.y + half->y; + vb[2].cr_tc.x = v.x + half->x; + vb[2].cr_tc.y = v.y; + vb[3].cr_tc.x = v.x + half->x; + vb[3].cr_tc.y = v.y; + vb[4].cr_tc.x = v.x; + vb[4].cr_tc.y = v.y + half->y; + vb[5].cr_tc.x = v.x + half->x; + vb[5].cr_tc.y = v.y + half->y; +} + +static void +gen_macroblock_verts(struct vl_mpeg12_mc_renderer *r, + struct pipe_mpeg12_macroblock *mb, unsigned pos, + struct vert_stream_0 *ycbcr_vb, struct vertex2f **ref_vb) +{ + struct vertex2f mo_vec[2]; + + unsigned i; + + assert(r); + assert(mb); + assert(ycbcr_vb); + assert(pos < r->macroblocks_per_batch); + + mo_vec[1].x = 0; + mo_vec[1].y = 0; + + switch (mb->mb_type) { + case PIPE_MPEG12_MACROBLOCK_TYPE_BI: + { + struct vertex2f *vb; + + assert(ref_vb && ref_vb[1]); + + vb = ref_vb[1] + pos * 2 * 24; + + mo_vec[0].x = mb->pmv[0][1][0] * 0.5f * r->surface_tex_inv_size.x; + mo_vec[0].y = mb->pmv[0][1][1] * 0.5f * r->surface_tex_inv_size.y; + + if (mb->mo_type == PIPE_MPEG12_MOTION_TYPE_FRAME) { + for (i = 0; i < 24 * 2; i += 2) { + vb[i].x = mo_vec[0].x; + vb[i].y = mo_vec[0].y; + } + } + else { + mo_vec[1].x = mb->pmv[1][1][0] * 0.5f * r->surface_tex_inv_size.x; + mo_vec[1].y = mb->pmv[1][1][1] * 0.5f * r->surface_tex_inv_size.y; + + for (i = 0; i < 24 * 2; i += 2) { + vb[i].x = mo_vec[0].x; + vb[i].y = mo_vec[0].y; + vb[i + 1].x = mo_vec[1].x; + vb[i + 1].y = mo_vec[1].y; + } + } + + /* fall-through */ + } + case PIPE_MPEG12_MACROBLOCK_TYPE_FWD: + case PIPE_MPEG12_MACROBLOCK_TYPE_BKWD: + { + struct vertex2f *vb; + + assert(ref_vb && ref_vb[0]); + + vb = ref_vb[0] + pos * 2 * 24; + + if (mb->mb_type == PIPE_MPEG12_MACROBLOCK_TYPE_BKWD) { + mo_vec[0].x = mb->pmv[0][1][0] * 0.5f * r->surface_tex_inv_size.x; + mo_vec[0].y = mb->pmv[0][1][1] * 0.5f * r->surface_tex_inv_size.y; + + if (mb->mo_type == PIPE_MPEG12_MOTION_TYPE_FIELD) { + mo_vec[1].x = mb->pmv[1][1][0] * 0.5f * r->surface_tex_inv_size.x; + mo_vec[1].y = mb->pmv[1][1][1] * 0.5f * r->surface_tex_inv_size.y; + } + } + else { + mo_vec[0].x = mb->pmv[0][0][0] * 0.5f * r->surface_tex_inv_size.x; + mo_vec[0].y = mb->pmv[0][0][1] * 0.5f * r->surface_tex_inv_size.y; + + if (mb->mo_type == PIPE_MPEG12_MOTION_TYPE_FIELD) { + mo_vec[1].x = mb->pmv[1][0][0] * 0.5f * r->surface_tex_inv_size.x; + mo_vec[1].y = mb->pmv[1][0][1] * 0.5f * r->surface_tex_inv_size.y; + } + } + + if (mb->mo_type == PIPE_MPEG12_MOTION_TYPE_FRAME) { + for (i = 0; i < 24 * 2; i += 2) { + vb[i].x = mo_vec[0].x; + vb[i].y = mo_vec[0].y; + } + } + else { + for (i = 0; i < 24 * 2; i += 2) { + vb[i].x = mo_vec[0].x; + vb[i].y = mo_vec[0].y; + vb[i + 1].x = mo_vec[1].x; + vb[i + 1].y = mo_vec[1].y; + } + } + + /* fall-through */ + } + case PIPE_MPEG12_MACROBLOCK_TYPE_INTRA: + { + const struct vertex2f unit = + { + r->surface_tex_inv_size.x * MACROBLOCK_WIDTH, + r->surface_tex_inv_size.y * MACROBLOCK_HEIGHT + }; + const struct vertex2f half = + { + r->surface_tex_inv_size.x * (MACROBLOCK_WIDTH / 2), + r->surface_tex_inv_size.y * (MACROBLOCK_HEIGHT / 2) + }; + const struct vertex2f offsets[2][2] = + { + { + {0, 0}, {0, half.y} + }, + { + {half.x, 0}, {half.x, half.y} + } + }; + const bool use_zb = r->eb_handling == VL_MPEG12_MC_RENDERER_EMPTY_BLOCK_XFER_ONE; + + struct vert_stream_0 *vb = ycbcr_vb + pos * 24; + + gen_block_verts(vb, mb->cbp, mb->mbx, mb->mby, + &unit, &half, &offsets[0][0], + 32, 2, 1, use_zb, r->zero_block); + + gen_block_verts(vb + 6, mb->cbp, mb->mbx, mb->mby, + &unit, &half, &offsets[1][0], + 16, 2, 1, use_zb, r->zero_block); + + gen_block_verts(vb + 12, mb->cbp, mb->mbx, mb->mby, + &unit, &half, &offsets[0][1], + 8, 2, 1, use_zb, r->zero_block); + + gen_block_verts(vb + 18, mb->cbp, mb->mbx, mb->mby, + &unit, &half, &offsets[1][1], + 4, 2, 1, use_zb, r->zero_block); + + break; + } + default: + assert(0); + } +} + +static void +gen_macroblock_stream(struct vl_mpeg12_mc_renderer *r, + unsigned *num_macroblocks) +{ + unsigned offset[NUM_MACROBLOCK_TYPES]; + struct vert_stream_0 *ycbcr_vb; + struct vertex2f *ref_vb[2]; + struct pipe_transfer *buf_transfer[3]; + unsigned i; + + assert(r); + assert(num_macroblocks); + + for (i = 0; i < r->num_macroblocks; ++i) { + enum MACROBLOCK_TYPE mb_type = get_macroblock_type(&r->macroblock_buf[i]); + ++num_macroblocks[mb_type]; + } + + offset[0] = 0; + + for (i = 1; i < NUM_MACROBLOCK_TYPES; ++i) + offset[i] = offset[i - 1] + num_macroblocks[i - 1]; + + ycbcr_vb = (struct vert_stream_0 *)pipe_buffer_map + ( + r->pipe, + r->vertex_bufs.individual.ycbcr.buffer, + PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD, + &buf_transfer[0] + ); + + for (i = 0; i < 2; ++i) + ref_vb[i] = (struct vertex2f *)pipe_buffer_map + ( + r->pipe, + r->vertex_bufs.individual.ref[i].buffer, + PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD, + &buf_transfer[i + 1] + ); + + for (i = 0; i < r->num_macroblocks; ++i) { + enum MACROBLOCK_TYPE mb_type = get_macroblock_type(&r->macroblock_buf[i]); + + gen_macroblock_verts(r, &r->macroblock_buf[i], offset[mb_type], + ycbcr_vb, ref_vb); + + ++offset[mb_type]; + } + + pipe_buffer_unmap(r->pipe, r->vertex_bufs.individual.ycbcr.buffer, buf_transfer[0]); + for (i = 0; i < 2; ++i) + pipe_buffer_unmap(r->pipe, r->vertex_bufs.individual.ref[i].buffer, buf_transfer[i + 1]); +} + +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 +flush(struct vl_mpeg12_mc_renderer *r) +{ + unsigned num_macroblocks[NUM_MACROBLOCK_TYPES] = { 0 }; + unsigned vb_start = 0; + struct vertex_shader_consts *vs_consts; + struct pipe_transfer *buf_transfer; + unsigned i; + + assert(r); + assert(r->num_macroblocks == r->macroblocks_per_batch); + + gen_macroblock_stream(r, num_macroblocks); + + r->fb_state.cbufs[0] = r->surface; + + r->pipe->set_framebuffer_state(r->pipe, &r->fb_state); + r->pipe->set_viewport_state(r->pipe, &r->viewport); + + vs_consts = pipe_buffer_map + ( + r->pipe, r->vs_const_buf, + PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD, + &buf_transfer + ); + + vs_consts->denorm.x = r->surface->width; + vs_consts->denorm.y = r->surface->height; + + pipe_buffer_unmap(r->pipe, r->vs_const_buf, buf_transfer); + + r->pipe->set_constant_buffer(r->pipe, PIPE_SHADER_VERTEX, 0, + r->vs_const_buf); + + if (num_macroblocks[MACROBLOCK_TYPE_INTRA] > 0) { + r->pipe->set_vertex_buffers(r->pipe, 1, r->vertex_bufs.all); + r->pipe->bind_vertex_elements_state(r->pipe, r->vertex_elems_state.individual.i); + r->pipe->set_fragment_sampler_views(r->pipe, 3, r->sampler_views.all); + r->pipe->bind_fragment_sampler_states(r->pipe, 3, r->samplers.all); + r->pipe->bind_vs_state(r->pipe, r->i_vs); + r->pipe->bind_fs_state(r->pipe, r->i_fs); + + util_draw_arrays(r->pipe, PIPE_PRIM_TRIANGLES, vb_start, + num_macroblocks[MACROBLOCK_TYPE_INTRA] * 24); + vb_start += num_macroblocks[MACROBLOCK_TYPE_INTRA] * 24; + } + + if (num_macroblocks[MACROBLOCK_TYPE_FWD_FRAME_PRED] > 0) { + r->pipe->set_vertex_buffers(r->pipe, 2, r->vertex_bufs.all); + r->pipe->bind_vertex_elements_state(r->pipe, r->vertex_elems_state.individual.p); + r->textures.individual.ref[0] = r->past->texture; + r->sampler_views.individual.ref[0] = find_or_create_sampler_view(r, r->past); + r->pipe->set_fragment_sampler_views(r->pipe, 4, r->sampler_views.all); + r->pipe->bind_fragment_sampler_states(r->pipe, 4, r->samplers.all); + r->pipe->bind_vs_state(r->pipe, r->p_vs[0]); + r->pipe->bind_fs_state(r->pipe, r->p_fs[0]); + + util_draw_arrays(r->pipe, PIPE_PRIM_TRIANGLES, vb_start, + num_macroblocks[MACROBLOCK_TYPE_FWD_FRAME_PRED] * 24); + vb_start += num_macroblocks[MACROBLOCK_TYPE_FWD_FRAME_PRED] * 24; + } + + if (false /*num_macroblocks[MACROBLOCK_TYPE_FWD_FIELD_PRED] > 0 */ ) { + r->pipe->set_vertex_buffers(r->pipe, 2, r->vertex_bufs.all); + r->pipe->bind_vertex_elements_state(r->pipe, r->vertex_elems_state.individual.p); + r->textures.individual.ref[0] = r->past->texture; + r->sampler_views.individual.ref[0] = find_or_create_sampler_view(r, r->past); + r->pipe->set_fragment_sampler_views(r->pipe, 4, r->sampler_views.all); + r->pipe->bind_fragment_sampler_states(r->pipe, 4, r->samplers.all); + r->pipe->bind_vs_state(r->pipe, r->p_vs[1]); + r->pipe->bind_fs_state(r->pipe, r->p_fs[1]); + + util_draw_arrays(r->pipe, PIPE_PRIM_TRIANGLES, vb_start, + num_macroblocks[MACROBLOCK_TYPE_FWD_FIELD_PRED] * 24); + vb_start += num_macroblocks[MACROBLOCK_TYPE_FWD_FIELD_PRED] * 24; + } + + if (num_macroblocks[MACROBLOCK_TYPE_BKWD_FRAME_PRED] > 0) { + r->pipe->set_vertex_buffers(r->pipe, 2, r->vertex_bufs.all); + r->pipe->bind_vertex_elements_state(r->pipe, r->vertex_elems_state.individual.p); + r->textures.individual.ref[0] = r->future->texture; + r->sampler_views.individual.ref[0] = find_or_create_sampler_view(r, r->future); + r->pipe->set_fragment_sampler_views(r->pipe, 4, r->sampler_views.all); + r->pipe->bind_fragment_sampler_states(r->pipe, 4, r->samplers.all); + r->pipe->bind_vs_state(r->pipe, r->p_vs[0]); + r->pipe->bind_fs_state(r->pipe, r->p_fs[0]); + + util_draw_arrays(r->pipe, PIPE_PRIM_TRIANGLES, vb_start, + num_macroblocks[MACROBLOCK_TYPE_BKWD_FRAME_PRED] * 24); + vb_start += num_macroblocks[MACROBLOCK_TYPE_BKWD_FRAME_PRED] * 24; + } + + if (false /*num_macroblocks[MACROBLOCK_TYPE_BKWD_FIELD_PRED] > 0*/ ) { + r->pipe->set_vertex_buffers(r->pipe, 2, r->vertex_bufs.all); + r->pipe->bind_vertex_elements_state(r->pipe, r->vertex_elems_state.individual.p); + r->textures.individual.ref[0] = r->future->texture; + r->sampler_views.individual.ref[0] = find_or_create_sampler_view(r, r->future); + r->pipe->set_fragment_sampler_views(r->pipe, 4, r->sampler_views.all); + r->pipe->bind_fragment_sampler_states(r->pipe, 4, r->samplers.all); + r->pipe->bind_vs_state(r->pipe, r->p_vs[1]); + r->pipe->bind_fs_state(r->pipe, r->p_fs[1]); + + util_draw_arrays(r->pipe, PIPE_PRIM_TRIANGLES, vb_start, + num_macroblocks[MACROBLOCK_TYPE_BKWD_FIELD_PRED] * 24); + vb_start += num_macroblocks[MACROBLOCK_TYPE_BKWD_FIELD_PRED] * 24; + } + + if (num_macroblocks[MACROBLOCK_TYPE_BI_FRAME_PRED] > 0) { + r->pipe->set_vertex_buffers(r->pipe, 3, r->vertex_bufs.all); + r->pipe->bind_vertex_elements_state(r->pipe, r->vertex_elems_state.individual.b); + r->textures.individual.ref[0] = r->past->texture; + r->textures.individual.ref[1] = r->future->texture; + r->sampler_views.individual.ref[0] = find_or_create_sampler_view(r, r->past); + r->sampler_views.individual.ref[1] = find_or_create_sampler_view(r, r->future); + r->pipe->set_fragment_sampler_views(r->pipe, 5, r->sampler_views.all); + r->pipe->bind_fragment_sampler_states(r->pipe, 5, r->samplers.all); + r->pipe->bind_vs_state(r->pipe, r->b_vs[0]); + r->pipe->bind_fs_state(r->pipe, r->b_fs[0]); + + util_draw_arrays(r->pipe, PIPE_PRIM_TRIANGLES, vb_start, + num_macroblocks[MACROBLOCK_TYPE_BI_FRAME_PRED] * 24); + vb_start += num_macroblocks[MACROBLOCK_TYPE_BI_FRAME_PRED] * 24; + } + + if (false /*num_macroblocks[MACROBLOCK_TYPE_BI_FIELD_PRED] > 0 */ ) { + r->pipe->set_vertex_buffers(r->pipe, 3, r->vertex_bufs.all); + r->pipe->bind_vertex_elements_state(r->pipe, r->vertex_elems_state.individual.b); + r->textures.individual.ref[0] = r->past->texture; + r->textures.individual.ref[1] = r->future->texture; + r->sampler_views.individual.ref[0] = find_or_create_sampler_view(r, r->past); + r->sampler_views.individual.ref[1] = find_or_create_sampler_view(r, r->future); + r->pipe->set_fragment_sampler_views(r->pipe, 5, r->sampler_views.all); + r->pipe->bind_fragment_sampler_states(r->pipe, 5, r->samplers.all); + r->pipe->bind_vs_state(r->pipe, r->b_vs[1]); + r->pipe->bind_fs_state(r->pipe, r->b_fs[1]); + + util_draw_arrays(r->pipe, PIPE_PRIM_TRIANGLES, vb_start, + num_macroblocks[MACROBLOCK_TYPE_BI_FIELD_PRED] * 24); + vb_start += num_macroblocks[MACROBLOCK_TYPE_BI_FIELD_PRED] * 24; + } + + r->pipe->flush(r->pipe, PIPE_FLUSH_RENDER_CACHE, r->fence); + + if (r->eb_handling == VL_MPEG12_MC_RENDERER_EMPTY_BLOCK_XFER_ONE) + for (i = 0; i < 3; ++i) + r->zero_block[i].x = ZERO_BLOCK_NIL; + + r->num_macroblocks = 0; +} + +static void +grab_frame_coded_block(short *src, short *dst, unsigned dst_pitch) +{ + unsigned y; + + assert(src); + assert(dst); + + for (y = 0; y < BLOCK_HEIGHT; ++y) + memcpy(dst + y * dst_pitch, src + y * BLOCK_WIDTH, BLOCK_WIDTH * 2); +} + +static void +grab_field_coded_block(short *src, short *dst, unsigned dst_pitch) +{ + unsigned y; + + assert(src); + assert(dst); + + for (y = 0; y < BLOCK_HEIGHT; ++y) + memcpy(dst + y * dst_pitch * 2, src + y * BLOCK_WIDTH, BLOCK_WIDTH * 2); +} + +static void +fill_zero_block(short *dst, unsigned dst_pitch) +{ + unsigned y; + + assert(dst); + + for (y = 0; y < BLOCK_HEIGHT; ++y) + memset(dst + y * dst_pitch, 0, BLOCK_WIDTH * 2); +} + +static void +grab_blocks(struct vl_mpeg12_mc_renderer *r, unsigned mbx, unsigned mby, + enum pipe_mpeg12_dct_type dct_type, unsigned cbp, short *blocks) +{ + unsigned tex_pitch; + short *texels; + unsigned tb = 0, sb = 0; + unsigned mbpx = mbx * MACROBLOCK_WIDTH, mbpy = mby * MACROBLOCK_HEIGHT; + unsigned x, y; + + assert(r); + assert(blocks); + + tex_pitch = r->tex_transfer[0]->stride / util_format_get_blocksize(r->tex_transfer[0]->resource->format); + texels = r->texels[0] + mbpy * tex_pitch + mbpx; + + for (y = 0; y < 2; ++y) { + for (x = 0; x < 2; ++x, ++tb) { + if ((cbp >> (5 - tb)) & 1) { + if (dct_type == PIPE_MPEG12_DCT_TYPE_FRAME) { + grab_frame_coded_block(blocks + sb * BLOCK_WIDTH * BLOCK_HEIGHT, + texels + y * tex_pitch * BLOCK_WIDTH + + x * BLOCK_WIDTH, tex_pitch); + } + else { + grab_field_coded_block(blocks + sb * BLOCK_WIDTH * BLOCK_HEIGHT, + texels + y * tex_pitch + x * BLOCK_WIDTH, + tex_pitch); + } + + ++sb; + } + else if (r->eb_handling != VL_MPEG12_MC_RENDERER_EMPTY_BLOCK_XFER_NONE) { + if (r->eb_handling == VL_MPEG12_MC_RENDERER_EMPTY_BLOCK_XFER_ALL || + ZERO_BLOCK_IS_NIL(r->zero_block[0])) { + fill_zero_block(texels + y * tex_pitch * BLOCK_WIDTH + x * BLOCK_WIDTH, tex_pitch); + if (r->eb_handling == VL_MPEG12_MC_RENDERER_EMPTY_BLOCK_XFER_ONE) { + r->zero_block[0].x = (mbpx + x * 8) * r->surface_tex_inv_size.x; + r->zero_block[0].y = (mbpy + y * 8) * r->surface_tex_inv_size.y; + } + } + } + } + } + + /* TODO: Implement 422, 444 */ + assert(r->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420); + + mbpx /= 2; + mbpy /= 2; + + for (tb = 0; tb < 2; ++tb) { + tex_pitch = r->tex_transfer[tb + 1]->stride / util_format_get_blocksize(r->tex_transfer[tb + 1]->resource->format); + texels = r->texels[tb + 1] + mbpy * tex_pitch + mbpx; + + if ((cbp >> (1 - tb)) & 1) { + grab_frame_coded_block(blocks + sb * BLOCK_WIDTH * BLOCK_HEIGHT, texels, tex_pitch); + ++sb; + } + else if (r->eb_handling != VL_MPEG12_MC_RENDERER_EMPTY_BLOCK_XFER_NONE) { + if (r->eb_handling == VL_MPEG12_MC_RENDERER_EMPTY_BLOCK_XFER_ALL || + ZERO_BLOCK_IS_NIL(r->zero_block[tb + 1])) { + fill_zero_block(texels, tex_pitch); + if (r->eb_handling == VL_MPEG12_MC_RENDERER_EMPTY_BLOCK_XFER_ONE) { + r->zero_block[tb + 1].x = (mbpx << 1) * r->surface_tex_inv_size.x; + r->zero_block[tb + 1].y = (mbpy << 1) * r->surface_tex_inv_size.y; + } + } + } + } +} + +static void +grab_macroblock(struct vl_mpeg12_mc_renderer *r, + struct pipe_mpeg12_macroblock *mb) +{ + assert(r); + assert(mb); + assert(mb->blocks); + assert(r->num_macroblocks < r->macroblocks_per_batch); + + memcpy(&r->macroblock_buf[r->num_macroblocks], mb, + sizeof(struct pipe_mpeg12_macroblock)); + + grab_blocks(r, mb->mbx, mb->mby, mb->dct_type, mb->cbp, mb->blocks); + + ++r->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 picture_width, + unsigned picture_height, + enum pipe_video_chroma_format chroma_format, + enum VL_MPEG12_MC_RENDERER_BUFFER_MODE bufmode, + enum VL_MPEG12_MC_RENDERER_EMPTY_BLOCK eb_handling, + bool pot_buffers) +{ + unsigned i; + + assert(renderer); + assert(pipe); + /* TODO: Implement other policies */ + assert(bufmode == VL_MPEG12_MC_RENDERER_BUFFER_PICTURE); + /* TODO: Implement this */ + /* XXX: XFER_ALL sampling issue at block edges when using bilinear filtering */ + assert(eb_handling != VL_MPEG12_MC_RENDERER_EMPTY_BLOCK_XFER_NONE); + /* TODO: Non-pot buffers untested, probably doesn't work without changes to texcoord generation, vert shader, etc */ + assert(pot_buffers); + + memset(renderer, 0, sizeof(struct vl_mpeg12_mc_renderer)); + + renderer->pipe = pipe; + renderer->picture_width = picture_width; + renderer->picture_height = picture_height; + renderer->chroma_format = chroma_format; + renderer->bufmode = bufmode; + renderer->eb_handling = eb_handling; + renderer->pot_buffers = pot_buffers; + + 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)) { + util_delete_keymap(renderer->texview_map, renderer->pipe); + return false; + } + if (!init_shaders(renderer)) { + util_delete_keymap(renderer->texview_map, renderer->pipe); + cleanup_pipe_state(renderer); + return false; + } + if (!init_buffers(renderer)) { + util_delete_keymap(renderer->texview_map, renderer->pipe); + cleanup_shaders(renderer); + cleanup_pipe_state(renderer); + return false; + } + + renderer->surface = NULL; + renderer->past = NULL; + renderer->future = NULL; + for (i = 0; i < 3; ++i) + renderer->zero_block[i].x = ZERO_BLOCK_NIL; + renderer->num_macroblocks = 0; + + xfer_buffers_map(renderer); + + return true; +} + +void +vl_mpeg12_mc_renderer_cleanup(struct vl_mpeg12_mc_renderer *renderer) +{ + assert(renderer); + + xfer_buffers_unmap(renderer); + + util_delete_keymap(renderer->texview_map, renderer->pipe); + cleanup_pipe_state(renderer); + cleanup_shaders(renderer); + cleanup_buffers(renderer); + + pipe_surface_reference(&renderer->surface, NULL); + pipe_surface_reference(&renderer->past, NULL); + pipe_surface_reference(&renderer->future, NULL); +} + +void +vl_mpeg12_mc_renderer_render_macroblocks(struct vl_mpeg12_mc_renderer + *renderer, + 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) +{ + bool new_surface = false; + + assert(renderer); + assert(surface); + assert(num_macroblocks); + assert(mpeg12_macroblocks); + + if (renderer->surface) { + if (surface != renderer->surface) { + if (renderer->num_macroblocks > 0) { + xfer_buffers_unmap(renderer); + flush(renderer); + } + + new_surface = true; + } + + /* If the surface we're rendering hasn't changed the ref frames shouldn't change. */ + assert(surface != renderer->surface || renderer->past == past); + assert(surface != renderer->surface || renderer->future == future); + } + else + new_surface = true; + + if (new_surface) { + pipe_surface_reference(&renderer->surface, surface); + pipe_surface_reference(&renderer->past, past); + pipe_surface_reference(&renderer->future, future); + renderer->fence = fence; + renderer->surface_tex_inv_size.x = 1.0f / surface->width; + renderer->surface_tex_inv_size.y = 1.0f / surface->height; + } + + while (num_macroblocks) { + unsigned left_in_batch = renderer->macroblocks_per_batch - renderer->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, &mpeg12_macroblocks[i]); + } + + num_macroblocks -= num_to_submit; + + if (renderer->num_macroblocks == renderer->macroblocks_per_batch) { + xfer_buffers_unmap(renderer); + flush(renderer); + xfer_buffers_map(renderer); + /* Next time we get this surface it may have new ref frames */ + pipe_surface_reference(&renderer->surface, NULL); + pipe_surface_reference(&renderer->past, NULL); + pipe_surface_reference(&renderer->future, NULL); + } + } +} 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..85191cf6b02 --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_mpeg12_mc_renderer.h @@ -0,0 +1,132 @@ +/************************************************************************** + * + * 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" + +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 */ +}; + +enum VL_MPEG12_MC_RENDERER_EMPTY_BLOCK +{ + VL_MPEG12_MC_RENDERER_EMPTY_BLOCK_XFER_ALL, /* Waste of memory bandwidth */ + VL_MPEG12_MC_RENDERER_EMPTY_BLOCK_XFER_ONE, /* Can only do point-filtering when interpolating subsampled chroma channels */ + VL_MPEG12_MC_RENDERER_EMPTY_BLOCK_XFER_NONE /* Needs conditional texel fetch! */ +}; + +struct vl_mpeg12_mc_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; + enum VL_MPEG12_MC_RENDERER_EMPTY_BLOCK eb_handling; + bool pot_buffers; + unsigned macroblocks_per_batch; + + struct pipe_viewport_state viewport; + struct pipe_resource *vs_const_buf; + struct pipe_framebuffer_state fb_state; + union + { + void *all[3]; + struct { void *i, *p, *b; } individual; + } vertex_elems_state; + + union + { + void *all[5]; + struct { void *y, *cb, *cr, *ref[2]; } individual; + } samplers; + + union + { + struct pipe_sampler_view *all[5]; + struct { struct pipe_sampler_view *y, *cb, *cr, *ref[2]; } individual; + } sampler_views; + + void *i_vs, *p_vs[2], *b_vs[2]; + void *i_fs, *p_fs[2], *b_fs[2]; + + union + { + struct pipe_resource *all[5]; + struct { struct pipe_resource *y, *cb, *cr, *ref[2]; } individual; + } textures; + + union + { + struct pipe_vertex_buffer all[3]; + struct { struct pipe_vertex_buffer ycbcr, ref[2]; } individual; + } vertex_bufs; + + struct pipe_surface *surface, *past, *future; + struct pipe_fence_handle **fence; + unsigned num_macroblocks; + struct pipe_mpeg12_macroblock *macroblock_buf; + struct pipe_transfer *tex_transfer[3]; + short *texels[3]; + struct vertex2f surface_tex_inv_size; + struct vertex2f zero_block[3]; + + struct keymap *texview_map; +}; + +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, + enum VL_MPEG12_MC_RENDERER_EMPTY_BLOCK eb_handling, + bool pot_buffers); + +void vl_mpeg12_mc_renderer_cleanup(struct vl_mpeg12_mc_renderer *renderer); + +void vl_mpeg12_mc_renderer_render_macroblocks(struct vl_mpeg12_mc_renderer *renderer, + 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); + +#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..ce175546894 --- /dev/null +++ b/src/gallium/auxiliary/vl/vl_types.h @@ -0,0 +1,41 @@ +/************************************************************************** + * + * 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; +}; + +#endif /* vl_types_h */ 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..15a26ea3b3b --- /dev/null +++ b/src/gallium/drivers/nv40/nv40_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 "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, + VL_MPEG12_MC_RENDERER_EMPTY_BLOCK_XFER_ONE, + 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 8024800bd09..875b3a96ca6 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" @@ -434,6 +435,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..9212ae57fc0 --- /dev/null +++ b/src/gallium/drivers/nvfx/nvfx_video_context.c @@ -0,0 +1,49 @@ +/************************************************************************** + * + * 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, + VL_MPEG12_MC_RENDERER_EMPTY_BLOCK_XFER_ONE, + 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..622f1b8820b --- /dev/null +++ b/src/gallium/drivers/r300/r300_video_context.c @@ -0,0 +1,329 @@ +/* + * 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: + * CooperYuan <[email protected]>, <[email protected]> + */ + +#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, + VL_MPEG12_MC_RENDERER_EMPTY_BLOCK_XFER_ONE, + 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: + * CooperYuan <[email protected]>, <[email protected]> + */ + +#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 a484f38e9f1..436de9c4dbd 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/r600_pipe.c b/src/gallium/drivers/r600/r600_pipe.c index 35645398437..87ec8cd2e83 100644 --- a/src/gallium/drivers/r600/r600_pipe.c +++ b/src/gallium/drivers/r600/r600_pipe.c @@ -43,6 +43,7 @@ #include "r600_shader.h" #include "r600_pipe.h" #include "r600_state_inlines.h" +#include "r600_video_context.h" /* * pipe_context @@ -451,6 +452,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_texture_functions(&rscreen->screen); r600_init_screen_resource_functions(&rscreen->screen); 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..2bbf622052b --- /dev/null +++ b/src/gallium/drivers/r600/r600_video_context.c @@ -0,0 +1,22 @@ +#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, + VL_MPEG12_MC_RENDERER_EMPTY_BLOCK_XFER_ONE, + 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/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 d5f4d28aeff..dea7f885e0d 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', ]) Export('softpipe') diff --git a/src/gallium/drivers/softpipe/sp_screen.c b/src/gallium/drivers/softpipe/sp_screen.c index d90cf56808c..edc2a6dacf2 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" @@ -298,6 +299,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 6b205dc5329..7e3249b46f0 100644 --- a/src/gallium/drivers/softpipe/sp_texture.h +++ b/src/gallium/drivers/softpipe/sp_texture.h @@ -82,7 +82,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..ff217d66c85 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_video_context.c @@ -0,0 +1,541 @@ +/************************************************************************** + * + * 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_rect.h> +#include <util/u_video.h> +#include <util/u_surface.h> +#include "sp_public.h" +#include "sp_texture.h" + +static void +sp_mpeg12_destroy(struct pipe_video_context *vpipe) +{ + struct sp_mpeg12_context *ctx = (struct sp_mpeg12_context*)vpipe; + + assert(vpipe); + + /* 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); + 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 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); + + vl_mpeg12_mc_renderer_render_macroblocks(&ctx->mc_renderer, + 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_subresource subdst, subsrc; + subdst.face = dst->face; + subdst.level = dst->level; + subsrc.face = src->face; + subsrc.level = src->level; + + if (ctx->pipe->resource_copy_region) + ctx->pipe->resource_copy_region(ctx->pipe, dst->texture, subdst, dstx, dsty, dst->zslice, + src->texture, subsrc, srcx, srcy, src->zslice, + width, height); + else + util_resource_copy_region(ctx->pipe, dst->texture, subdst, dstx, dsty, dst->zslice, + src->texture, subsrc, srcx, srcy, src->zslice, + width, height); +} + +static struct pipe_transfer* +sp_mpeg12_get_transfer(struct pipe_video_context *vpipe, + struct pipe_resource *resource, + struct pipe_subresource subresource, + 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, subresource, 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, + struct pipe_subresource subresource, + 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, subresource, 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); + + 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); + + 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, + enum VL_MPEG12_MC_RENDERER_EMPTY_BLOCK eb_handling, + bool pot_buffers, + enum pipe_format decode_format) +{ + 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; + + 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.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, + width, height, chroma_format, + bufmode, eb_handling, pot_buffers)) { + 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 (!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 * +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 */ + /* TODO: Use XFER_NONE when implemented */ + return sp_video_create_ex(pipe, profile, + chroma_format, + width, height, + VL_MPEG12_MC_RENDERER_BUFFER_PICTURE, + VL_MPEG12_MC_RENDERER_EMPTY_BLOCK_XFER_ONE, + 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, + enum VL_MPEG12_MC_RENDERER_EMPTY_BLOCK eb_handling, + 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, eb_handling, + 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..0fe48d7a872 --- /dev/null +++ b/src/gallium/drivers/softpipe/sp_video_context.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 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 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, + enum VL_MPEG12_MC_RENDERER_EMPTY_BLOCK eb_handling, + 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 53f7b601ad5..5cbe2beb83e 100644 --- a/src/gallium/include/pipe/p_defines.h +++ b/src/gallium/include/pipe/p_defines.h @@ -494,6 +494,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 22cc7aa18a2..119d304d927 100644 --- a/src/gallium/include/pipe/p_format.h +++ b/src/gallium/include/pipe/p_format.h @@ -186,13 +186,31 @@ 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_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 912631242f5..2f22ac22bbf 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..294dc464c36 --- /dev/null +++ b/src/gallium/include/pipe/p_video_context.h @@ -0,0 +1,178 @@ +/************************************************************************** + * + * 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); + + /** + * 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, + struct pipe_subresource subresource, + 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, + struct pipe_subresource subresource, + 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..5eb96352139 --- /dev/null +++ b/src/gallium/include/pipe/p_video_state.h @@ -0,0 +1,132 @@ +/************************************************************************** + * + * 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]; + 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..5e4af9e555a --- /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_MOCOMP | XVMC_MPEG_2)) { + XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Non-MPEG2/Mocomp acceleration unsupported.\n"); + return BadImplementation; + } + if (!(surface_flags & XVMC_INTRA_UNSIGNED)) { + XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Signed 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..e0c9e303817 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xvmc/subpicture.c @@ -0,0 +1,440 @@ +/************************************************************************** + * + * 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; + 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); + subpicture_priv->sfc = vpipe->screen->get_tex_surface(vpipe->screen, tex, 0, 0, 0, + PIPE_BIND_SAMPLER_VIEW); + 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}; + struct pipe_subresource sr = {0, 0}; + + 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, + sr, 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..0decc45a0bb --- /dev/null +++ b/src/gallium/state_trackers/xorg/xvmc/surface.c @@ -0,0 +1,501 @@ +/************************************************************************** + * + * 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 <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, int xvmc_dct_type) +{ + switch (xvmc_motion_type) { + case XVMC_PREDICTION_FRAME: + if (xvmc_dct_type == XVMC_DCT_TYPE_FIELD) + return PIPE_MPEG12_MOTION_TYPE_16x8; + else if (xvmc_dct_type == XVMC_DCT_TYPE_FRAME) + return PIPE_MPEG12_MOTION_TYPE_FRAME; + 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 DCT type 0x%08X).\n", xvmc_motion_type, xvmc_dct_type); + + 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, + 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_mb->dct_type); + /* 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->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 *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; + } + + vsfc = vpipe->screen->get_tex_surface(vpipe->screen, vsfc_tex, 0, 0, 0, + PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET); + 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, 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) +{ + 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->vscreen, 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, + vl_contextprivate_get(context_priv->vctx, drawable_surface) + ); + + pipe_surface_reference(&drawable_surface, NULL); + + 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, ¯oblocks) == XvMCBadContext); + /* Test 0 macroblocks */ + assert(XvMCCreateMacroBlocks(display, &context, 0, ¯oblocks) == BadValue); + /* Test valid params */ + assert(XvMCCreateMacroBlocks(display, &context, min_required_macroblocks, ¯oblocks) == 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, ¯oblocks) == 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 2f64f312b84..9dfe86c8949 100644 --- a/src/gallium/targets/dri-nouveau/Makefile +++ b/src/gallium/targets/dri-nouveau/Makefile @@ -10,6 +10,7 @@ PIPE_DRIVERS = \ $(TOP)/src/gallium/drivers/rbug/librbug.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 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..4d10e27c580 --- /dev/null +++ b/src/gallium/winsys/g3dvl/dri/dri_winsys.c @@ -0,0 +1,273 @@ +/************************************************************************** + * + * 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_dri_screen *vl_dri_scrn, 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(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; + + 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) + front_surf = vl_dri_scrn->base.pscreen->get_tex_surface(vl_dri_scrn->base.pscreen, + front_tex, 0, 0, 0, + PIPE_BIND_RENDER_TARGET); + pipe_resource_reference(&front_tex, NULL); + Xfree(dri2_front); + } + + return front_surf; +} + +static void +vl_dri2_flush_frontbuffer(struct pipe_screen *screen, + struct pipe_surface *surf, 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(surf); + 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_screen *vscreen, Drawable drawable) +{ + struct vl_dri_screen *vl_dri_scrn = (struct vl_dri_screen*)vscreen; + + assert(vscreen); + + 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(vl_dri_scrn, 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..381478637a8 --- /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_screen *vscreen, 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); +} |