From: Younes Manton Date: Sun, 8 Jun 2008 07:04:14 +0000 (-0400) Subject: Initial commit for g3dvl. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=c11a7ec821d41b91a3825c5abfb4687c98b5bf98;p=mesa.git Initial commit for g3dvl. Initial commit for g3dvl, contains support for basic XvMC features. - Context, surface, block, macroblock creation and deletion - Surface rendering - Frame pictures - Frame based motion compensation - Intra-coded macroblocks - Predicted macroblocks - Bi-directionally predicted macroblocks - Surface display - Color conversion - Scaling --- diff --git a/src/gallium/state_trackers/g3dvl/Makefile b/src/gallium/state_trackers/g3dvl/Makefile new file mode 100644 index 00000000000..a0d85fbcc8f --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/Makefile @@ -0,0 +1,18 @@ +TARGET = libg3dvl.a +OBJECTS = vl_context.o vl_data.o vl_surface.o +GALLIUMDIR = ../.. + +CFLAGS += -g -Wall -fPIC -Werror -I${GALLIUMDIR}/include -I${GALLIUMDIR}/auxiliary + +############################################# + +.PHONY = all clean + +all: ${TARGET} + +${TARGET}: ${OBJECTS} + ar rcs $@ $^ + +clean: + rm -rf ${OBJECTS} ${TARGET} + diff --git a/src/gallium/state_trackers/g3dvl/tests/.gitignore b/src/gallium/state_trackers/g3dvl/tests/.gitignore new file mode 100644 index 00000000000..939666da9ab --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/tests/.gitignore @@ -0,0 +1,6 @@ +test_context +test_surface +test_i_rendering +test_p_rendering +test_b_rendering + diff --git a/src/gallium/state_trackers/g3dvl/tests/Makefile b/src/gallium/state_trackers/g3dvl/tests/Makefile new file mode 100644 index 00000000000..8f983593c3a --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/tests/Makefile @@ -0,0 +1,42 @@ +GALLIUMDIR = ../../.. + +CFLAGS += -g -Wall -Werror \ + -I${GALLIUMDIR}/state_trackers/g3dvl \ + -I${GALLIUMDIR}/winsys/g3dvl \ + -I${GALLIUMDIR}/include \ + -I${GALLIUMDIR}/auxiliary \ + -I${GALLIUMDIR}/drivers +LDFLAGS += -L${GALLIUMDIR}/state_trackers/g3dvl \ + -L${GALLIUMDIR}/drivers/softpipe \ + -L${GALLIUMDIR}/auxiliary/tgsi \ + -L${GALLIUMDIR}/auxiliary/draw \ + -L${GALLIUMDIR}/auxiliary/util \ + -L${GALLIUMDIR}/auxiliary/translate \ + -L${GALLIUMDIR}/auxiliary/cso_cache \ + -L${GALLIUMDIR}/auxiliary/rtasm +LIBS += -lg3dvl -lsoftpipe -ldraw -ltgsi -ltranslate -lrtasm -lcso_cache -lutil -lX11 -lm + +############################################# + +.PHONY = all clean + +all: test_context test_surface test_i_rendering test_p_rendering test_b_rendering + +test_context: test_context.o ${GALLIUMDIR}/winsys/g3dvl/xsp_winsys.o + $(CC) ${LDFLAGS} -o $@ $^ ${LIBS} + +test_surface: test_surface.o ${GALLIUMDIR}/winsys/g3dvl/xsp_winsys.o + $(CC) ${LDFLAGS} -o $@ $^ ${LIBS} + +test_i_rendering: test_i_rendering.o ${GALLIUMDIR}/winsys/g3dvl/xsp_winsys.o + $(CC) ${LDFLAGS} -o $@ $^ ${LIBS} + +test_p_rendering: test_p_rendering.o ${GALLIUMDIR}/winsys/g3dvl/xsp_winsys.o + $(CC) ${LDFLAGS} -o $@ $^ ${LIBS} + +test_b_rendering: test_b_rendering.o ${GALLIUMDIR}/winsys/g3dvl/xsp_winsys.o + $(CC) ${LDFLAGS} -o $@ $^ ${LIBS} + +clean: + rm -rf *.o test_context test_surface test_i_rendering test_p_rendering test_b_rendering + diff --git a/src/gallium/state_trackers/g3dvl/tests/test_b_rendering.c b/src/gallium/state_trackers/g3dvl/tests/test_b_rendering.c new file mode 100644 index 00000000000..b78cc851ae4 --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/tests/test_b_rendering.c @@ -0,0 +1,226 @@ +#include +#include +#include +#include +#include + +static const unsigned short ycbcr16x16_420[8*8*6] = +{ + 0x00A5,0x00A5,0x00A5,0x0072,0x00A5,0x0072,0x0072,0x0072, + 0x0072,0x00A5,0x0072,0x0072,0x00A5,0x0072,0x0072,0x0072, + 0x0072,0x00A5,0x0072,0x0072,0x00A5,0x00A5,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x00A5, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x00A5,0x00A5, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x00A5,0x00A5,0x00A5, + 0x0072,0x0072,0x0072,0x0072,0x00A5,0x00A5,0x00A5,0x00A5, + + 0x004F,0x004F,0x004F,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2, + 0x00B2,0x00B2,0x004F,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2, + 0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2, + 0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2, + 0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2, + 0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2, + 0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x004F, + 0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x004F,0x004F, + + 0x003E,0x003E,0x003E,0x0060,0x0060,0x0060,0x0060,0x0060, + 0x0060,0x0060,0x003E,0x0060,0x0060,0x0060,0x0060,0x0060, + 0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060, + 0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060, + 0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060, + 0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060, + 0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x003E, + 0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x003E,0x003E +}; + +static const signed short ycbcr16x16_420_2[8*8*6] = +{ + -0x00A5,-0x00A5,-0x00A5,-0x0072,-0x00A5,-0x0072,-0x0072,-0x0072, + -0x0072,-0x00A5,-0x0072,-0x0072,-0x00A5,-0x0072,-0x0072,-0x0072, + -0x0072,-0x00A5,-0x0072,-0x0072,-0x00A5,-0x00A5,-0x0072,-0x0072, + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072, + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072, + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072, + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072, + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072, + + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072, + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072, + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072, + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072, + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072, + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072, + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072, + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072, + + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072, + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072, + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072, + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072, + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072, + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072, + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072, + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072, + + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072, + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072, + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072, + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072, + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x00A5, + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x00A5,-0x00A5, + -0x0072,-0x0072,-0x0072,-0x0072,-0x0072,-0x00A5,-0x00A5,-0x00A5, + -0x0072,-0x0072,-0x0072,-0x0072,-0x00A5,-0x00A5,-0x00A5,-0x00A5, + + -0x004F,-0x004F,-0x004F,-0x00B2,-0x00B2,-0x00B2,-0x00B2,-0x00B2, + -0x00B2,-0x00B2,-0x004F,-0x00B2,-0x00B2,-0x00B2,-0x00B2,-0x00B2, + -0x00B2,-0x00B2,-0x00B2,-0x00B2,-0x00B2,-0x00B2,-0x00B2,-0x00B2, + -0x00B2,-0x00B2,-0x00B2,-0x00B2,-0x00B2,-0x00B2,-0x00B2,-0x00B2, + -0x00B2,-0x00B2,-0x00B2,-0x00B2,-0x00B2,-0x00B2,-0x00B2,-0x00B2, + -0x00B2,-0x00B2,-0x00B2,-0x00B2,-0x00B2,-0x00B2,-0x00B2,-0x00B2, + -0x00B2,-0x00B2,-0x00B2,-0x00B2,-0x00B2,-0x00B2,-0x00B2,-0x004F, + -0x00B2,-0x00B2,-0x00B2,-0x00B2,-0x00B2,-0x00B2,-0x004F,-0x004F, + + -0x003E,-0x003E,-0x003E,-0x0060,-0x0060,-0x0060,-0x0060,-0x0060, + -0x0060,-0x0060,-0x003E,-0x0060,-0x0060,-0x0060,-0x0060,-0x0060, + -0x0060,-0x0060,-0x0060,-0x0060,-0x0060,-0x0060,-0x0060,-0x0060, + -0x0060,-0x0060,-0x0060,-0x0060,-0x0060,-0x0060,-0x0060,-0x0060, + -0x0060,-0x0060,-0x0060,-0x0060,-0x0060,-0x0060,-0x0060,-0x0060, + -0x0060,-0x0060,-0x0060,-0x0060,-0x0060,-0x0060,-0x0060,-0x0060, + -0x0060,-0x0060,-0x0060,-0x0060,-0x0060,-0x0060,-0x0060,-0x003E, + -0x0060,-0x0060,-0x0060,-0x0060,-0x0060,-0x0060,-0x003E,-0x003E +}; + +int main(int argc, char **argv) +{ + const unsigned int video_width = 32, video_height = 32; + const unsigned int window_width = video_width * 2, window_height = video_height * 2; + int quit = 0; + Display *display; + Window root, window; + Pixmap framebuffer; + XEvent event; + struct pipe_context *pipe; + struct VL_CONTEXT *ctx; + struct VL_SURFACE *sfc, *past_sfc, *future_sfc; + struct VL_MOTION_VECTOR motion_vector[2] = + { + { + {0, 0}, {0, 0} + }, + { + {0, 0}, {0, 0} + } + }; + + display = XOpenDisplay(NULL); + root = XDefaultRootWindow(display); + window = XCreateSimpleWindow(display, root, 0, 0, window_width, window_height, 0, 0, 0); + framebuffer = XCreatePixmap(display, root, window_width, window_height, 24); + + XSelectInput(display, window, ExposureMask | KeyPressMask); + XMapWindow(display, window); + XSync(display, 0); + + pipe = create_pipe_context(display); + vlCreateContext(display, pipe, video_width, video_height, VL_FORMAT_YCBCR_420, &ctx); + vlCreateSurface(ctx, &sfc); + vlCreateSurface(ctx, &past_sfc); + vlCreateSurface(ctx, &future_sfc); + + vlRenderIMacroBlock(VL_FRAME_PICTURE, VL_FIELD_FIRST, 0, 0, 0x3F, VL_DCT_FRAME_CODED, (short*)ycbcr16x16_420, past_sfc); + vlRenderIMacroBlock(VL_FRAME_PICTURE, VL_FIELD_FIRST, 1, 0, 0x3F, VL_DCT_FRAME_CODED, (short*)ycbcr16x16_420, past_sfc); + vlRenderIMacroBlock(VL_FRAME_PICTURE, VL_FIELD_FIRST, 0, 1, 0x3F, VL_DCT_FRAME_CODED, (short*)ycbcr16x16_420, past_sfc); + vlRenderIMacroBlock(VL_FRAME_PICTURE, VL_FIELD_FIRST, 1, 1, 0x3F, VL_DCT_FRAME_CODED, (short*)ycbcr16x16_420, past_sfc); + vlRenderIMacroBlock(VL_FRAME_PICTURE, VL_FIELD_FIRST, 0, 0, 0x3F, VL_DCT_FRAME_CODED, (short*)ycbcr16x16_420, future_sfc); + vlRenderIMacroBlock(VL_FRAME_PICTURE, VL_FIELD_FIRST, 1, 0, 0x3F, VL_DCT_FRAME_CODED, (short*)ycbcr16x16_420, future_sfc); + vlRenderIMacroBlock(VL_FRAME_PICTURE, VL_FIELD_FIRST, 0, 1, 0x3F, VL_DCT_FRAME_CODED, (short*)ycbcr16x16_420, future_sfc); + vlRenderIMacroBlock(VL_FRAME_PICTURE, VL_FIELD_FIRST, 1, 1, 0x3F, VL_DCT_FRAME_CODED, (short*)ycbcr16x16_420, future_sfc); + vlRenderBMacroBlock + ( + VL_FRAME_PICTURE, + VL_FIELD_FIRST, + 0, + 0, + VL_FRAME_MC, + motion_vector, + 0x3F, + VL_DCT_FRAME_CODED, + (short*)ycbcr16x16_420_2, + past_sfc, + future_sfc, + sfc + ); + vlPutSurface(sfc, framebuffer, 0, 0, video_width, video_height, 0, 0, window_width, window_height, VL_FRAME_PICTURE); + + puts("Press any key to continue..."); + + while (!quit) + { + XNextEvent(display, &event); + switch (event.type) + { + case Expose: + { + XCopyArea + ( + display, + framebuffer, + window, + XDefaultGC(display, XDefaultScreen(display)), + 0, + 0, + window_width, + window_height, + 0, + 0 + ); + break; + } + case KeyPress: + { + quit = 1; + break; + } + } + } + + vlDestroySurface(sfc); + vlDestroySurface(past_sfc); + vlDestroySurface(future_sfc); + vlDestroyContext(ctx); + + XFreePixmap(display, framebuffer); + XDestroyWindow(display, window); + XCloseDisplay(display); + + return 0; +} + diff --git a/src/gallium/state_trackers/g3dvl/tests/test_context.c b/src/gallium/state_trackers/g3dvl/tests/test_context.c new file mode 100644 index 00000000000..2002977ee24 --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/tests/test_context.c @@ -0,0 +1,22 @@ +#include +#include + +int main(int argc, char **argv) +{ + const unsigned int video_width = 32, video_height = 32; + + Display *display; + struct pipe_context *pipe; + struct VL_CONTEXT *ctx; + + display = XOpenDisplay(NULL); + pipe = create_pipe_context(display); + + vlCreateContext(display, pipe, video_width, video_height, VL_FORMAT_YCBCR_420, &ctx); + vlDestroyContext(ctx); + + XCloseDisplay(display); + + return 0; +} + diff --git a/src/gallium/state_trackers/g3dvl/tests/test_i_rendering.c b/src/gallium/state_trackers/g3dvl/tests/test_i_rendering.c new file mode 100644 index 00000000000..1f964711308 --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/tests/test_i_rendering.c @@ -0,0 +1,137 @@ +#include +#include +#include +#include +#include + +static const unsigned short ycbcr16x16_420[8*8*6] = +{ + 0x00A5,0x00A5,0x00A5,0x0072,0x00A5,0x0072,0x0072,0x0072, + 0x0072,0x00A5,0x0072,0x0072,0x00A5,0x0072,0x0072,0x0072, + 0x0072,0x00A5,0x0072,0x0072,0x00A5,0x00A5,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x00A5, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x00A5,0x00A5, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x00A5,0x00A5,0x00A5, + 0x0072,0x0072,0x0072,0x0072,0x00A5,0x00A5,0x00A5,0x00A5, + + 0x004F,0x004F,0x004F,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2, + 0x00B2,0x00B2,0x004F,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2, + 0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2, + 0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2, + 0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2, + 0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2, + 0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x004F, + 0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x004F,0x004F, + + 0x003E,0x003E,0x003E,0x0060,0x0060,0x0060,0x0060,0x0060, + 0x0060,0x0060,0x003E,0x0060,0x0060,0x0060,0x0060,0x0060, + 0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060, + 0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060, + 0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060, + 0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060, + 0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x003E, + 0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x003E,0x003E +}; + +int main(int argc, char **argv) +{ + const unsigned int video_width = 32, video_height = 32; + const unsigned int window_width = video_width * 2, window_height = video_height * 2; + int quit = 0; + Display *display; + Window root, window; + Pixmap framebuffer; + XEvent event; + struct pipe_context *pipe; + struct VL_CONTEXT *ctx; + struct VL_SURFACE *sfc; + + display = XOpenDisplay(NULL); + root = XDefaultRootWindow(display); + window = XCreateSimpleWindow(display, root, 0, 0, window_width, window_height, 0, 0, 0); + framebuffer = XCreatePixmap(display, root, window_width, window_height, 24); + + XSelectInput(display, window, ExposureMask | KeyPressMask); + XMapWindow(display, window); + XSync(display, 0); + + pipe = create_pipe_context(display); + vlCreateContext(display, pipe, video_width, video_height, VL_FORMAT_YCBCR_420, &ctx); + vlCreateSurface(ctx, &sfc); + + vlRenderIMacroBlock(VL_FRAME_PICTURE, VL_FIELD_FIRST, 0, 0, 0x3F, VL_DCT_FRAME_CODED, (short*)ycbcr16x16_420, sfc); + vlRenderIMacroBlock(VL_FRAME_PICTURE, VL_FIELD_FIRST, 1, 0, 0x3F, VL_DCT_FRAME_CODED, (short*)ycbcr16x16_420, sfc); + vlRenderIMacroBlock(VL_FRAME_PICTURE, VL_FIELD_FIRST, 0, 1, 0x3F, VL_DCT_FRAME_CODED, (short*)ycbcr16x16_420, sfc); + vlRenderIMacroBlock(VL_FRAME_PICTURE, VL_FIELD_FIRST, 1, 1, 0x3F, VL_DCT_FRAME_CODED, (short*)ycbcr16x16_420, sfc); + vlPutSurface(sfc, framebuffer, 0, 0, video_width, video_height, 0, 0, window_width, window_height, VL_FRAME_PICTURE); + + puts("Press any key to continue..."); + + while (!quit) + { + XNextEvent(display, &event); + switch (event.type) + { + case Expose: + { + XCopyArea + ( + display, + framebuffer, + window, + XDefaultGC(display, XDefaultScreen(display)), + 0, + 0, + window_width, + window_height, + 0, + 0 + ); + break; + } + case KeyPress: + { + quit = 1; + break; + } + } + } + + vlDestroySurface(sfc); + vlDestroyContext(ctx); + + XFreePixmap(display, framebuffer); + XDestroyWindow(display, window); + XCloseDisplay(display); + + return 0; +} + diff --git a/src/gallium/state_trackers/g3dvl/tests/test_p_rendering.c b/src/gallium/state_trackers/g3dvl/tests/test_p_rendering.c new file mode 100644 index 00000000000..2203349784f --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/tests/test_p_rendering.c @@ -0,0 +1,214 @@ +#include +#include +#include +#include +#include + +static const unsigned short ycbcr16x16_420[8*8*6] = +{ + 0x00A5,0x00A5,0x00A5,0x0072,0x00A5,0x0072,0x0072,0x0072, + 0x0072,0x00A5,0x0072,0x0072,0x00A5,0x0072,0x0072,0x0072, + 0x0072,0x00A5,0x0072,0x0072,0x00A5,0x00A5,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x00A5, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x0072,0x00A5,0x00A5, + 0x0072,0x0072,0x0072,0x0072,0x0072,0x00A5,0x00A5,0x00A5, + 0x0072,0x0072,0x0072,0x0072,0x00A5,0x00A5,0x00A5,0x00A5, + + 0x004F,0x004F,0x004F,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2, + 0x00B2,0x00B2,0x004F,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2, + 0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2, + 0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2, + 0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2, + 0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2, + 0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x004F, + 0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x00B2,0x004F,0x004F, + + 0x003E,0x003E,0x003E,0x0060,0x0060,0x0060,0x0060,0x0060, + 0x0060,0x0060,0x003E,0x0060,0x0060,0x0060,0x0060,0x0060, + 0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060, + 0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060, + 0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060, + 0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060, + 0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x003E, + 0x0060,0x0060,0x0060,0x0060,0x0060,0x0060,0x003E,0x003E +}; + +static const signed short ycbcr16x16_420_2[8*8*6] = +{ + -51,-51,-51, 0,-51, 0, 0, 0, + 0,-51, 0, 0,-51, 0, 0, 0, + 0,-51, 0, 0,-51,-51, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + + 99, 99, 99, 0, 0, 0, 0, 0, + 0, 0, 99, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + + 33, 33, 33, 0, 0, 0, 0, 0, + 0, 0, 33, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +int main(int argc, char **argv) +{ + const unsigned int video_width = 32, video_height = 32; + const unsigned int window_width = video_width * 2, window_height = video_height * 2; + int quit = 0; + Display *display; + Window root, window; + Pixmap framebuffer; + XEvent event; + struct pipe_context *pipe; + struct VL_CONTEXT *ctx; + struct VL_SURFACE *sfc, *ref_sfc; + struct VL_MOTION_VECTOR motion_vector = + { + {0, 0}, {0, 0} + }; + + display = XOpenDisplay(NULL); + root = XDefaultRootWindow(display); + window = XCreateSimpleWindow(display, root, 0, 0, window_width, window_height, 0, 0, 0); + framebuffer = XCreatePixmap(display, root, window_width, window_height, 24); + + XSelectInput(display, window, ExposureMask | KeyPressMask); + XMapWindow(display, window); + XSync(display, 0); + + pipe = create_pipe_context(display); + vlCreateContext(display, pipe, video_width, video_height, VL_FORMAT_YCBCR_420, &ctx); + vlCreateSurface(ctx, &sfc); + vlCreateSurface(ctx, &ref_sfc); + + vlRenderIMacroBlock(VL_FRAME_PICTURE, VL_FIELD_FIRST, 0, 0, 0x3F, VL_DCT_FRAME_CODED, (short*)ycbcr16x16_420, ref_sfc); + vlRenderIMacroBlock(VL_FRAME_PICTURE, VL_FIELD_FIRST, 1, 0, 0x3F, VL_DCT_FRAME_CODED, (short*)ycbcr16x16_420, ref_sfc); + vlRenderIMacroBlock(VL_FRAME_PICTURE, VL_FIELD_FIRST, 0, 1, 0x3F, VL_DCT_FRAME_CODED, (short*)ycbcr16x16_420, ref_sfc); + vlRenderIMacroBlock(VL_FRAME_PICTURE, VL_FIELD_FIRST, 1, 1, 0x3F, VL_DCT_FRAME_CODED, (short*)ycbcr16x16_420, ref_sfc); + vlRenderPMacroBlock + ( + VL_FRAME_PICTURE, + VL_FIELD_FIRST, + 0, + 0, + VL_FRAME_MC, + &motion_vector, + 0x3F, + VL_DCT_FRAME_CODED, + (short*)ycbcr16x16_420_2, + ref_sfc, + sfc + ); + vlPutSurface(sfc, framebuffer, 0, 0, video_width, video_height, 0, 0, window_width, window_height, VL_FRAME_PICTURE); + + puts("Press any key to continue..."); + + while (!quit) + { + XNextEvent(display, &event); + switch (event.type) + { + case Expose: + { + XCopyArea + ( + display, + framebuffer, + window, + XDefaultGC(display, XDefaultScreen(display)), + 0, + 0, + window_width, + window_height, + 0, + 0 + ); + break; + } + case KeyPress: + { + quit = 1; + break; + } + } + } + + vlDestroySurface(sfc); + vlDestroySurface(ref_sfc); + vlDestroyContext(ctx); + + XFreePixmap(display, framebuffer); + XDestroyWindow(display, window); + XCloseDisplay(display); + + return 0; +} + diff --git a/src/gallium/state_trackers/g3dvl/tests/test_surface.c b/src/gallium/state_trackers/g3dvl/tests/test_surface.c new file mode 100644 index 00000000000..4d1946396af --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/tests/test_surface.c @@ -0,0 +1,26 @@ +#include +#include +#include + +int main(int argc, char **argv) +{ + const unsigned int video_width = 32, video_height = 32; + + Display *display; + struct pipe_context *pipe; + struct VL_CONTEXT *ctx; + struct VL_SURFACE *sfc; + + display = XOpenDisplay(NULL); + pipe = create_pipe_context(display); + + vlCreateContext(display, pipe, video_width, video_height, VL_FORMAT_YCBCR_420, &ctx); + vlCreateSurface(ctx, &sfc); + vlDestroySurface(sfc); + vlDestroyContext(ctx); + + XCloseDisplay(display); + + return 0; +} + diff --git a/src/gallium/state_trackers/g3dvl/vl_context.c b/src/gallium/state_trackers/g3dvl/vl_context.c new file mode 100644 index 00000000000..7193f7cceaf --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_context.c @@ -0,0 +1,2293 @@ +#include "vl_context.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "vl_data.h" + +static int vlInitIDCT(struct VL_CONTEXT *context) +{ + assert(context); + + + + return 0; +} + +static int vlDestroyIDCT(struct VL_CONTEXT *context) +{ + assert(context); + + + + return 0; +} + +static int vlCreateVertexShaderIMC(struct VL_CONTEXT *context) +{ + const unsigned int max_tokens = 50; + const unsigned int num_attribs = 4; + const unsigned int semantic_names[4] = + { + TGSI_SEMANTIC_POSITION, + TGSI_SEMANTIC_GENERIC, + TGSI_SEMANTIC_GENERIC, + TGSI_SEMANTIC_GENERIC + }; + const unsigned int semantic_indexes[4] = {0, 1, 2, 3}; + const unsigned int proc_type = TGSI_PROCESSOR_VERTEX; + + struct pipe_context *pipe; + struct pipe_shader_state vs; + struct tgsi_token *tokens; + struct tgsi_header *header; + struct tgsi_processor *processor; + + struct tgsi_full_declaration decl; + struct tgsi_full_instruction inst; + + unsigned int ti; + unsigned int i; + + assert(context); + + pipe = context->pipe; + + tokens = (struct tgsi_token*)malloc(max_tokens * sizeof(struct tgsi_token)); + + /* Version */ + *(struct tgsi_version*)&tokens[0] = tgsi_build_version(); + + /* Header */ + header = (struct tgsi_header*)&tokens[1]; + *header = tgsi_build_header(); + + /* Processor */ + processor = (struct tgsi_processor*)&tokens[2]; + *processor = tgsi_build_processor(proc_type, header); + + ti = 3; + + /* Declare inputs (pos, texcoords) */ + for (i = 0; i < num_attribs; i++) + { + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_INPUT; + + decl.Declaration.Semantic = 1; + decl.Semantic.SemanticName = semantic_names[i]; + decl.Semantic.SemanticIndex = semantic_indexes[i]; + + decl.u.DeclarationRange.First = i; + decl.u.DeclarationRange.Last = i; + ti += tgsi_build_full_declaration + ( + &decl, + &tokens[ti], + header, + max_tokens - ti + ); + } + + /* Declare constant inputs */ + /* C[0] scales the normalized MB to cover 16x16 pixels, + C[1] translates the macroblock into position on the surface */ + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_CONSTANT; + decl.Declaration.Semantic = 1; + decl.Semantic.SemanticName = TGSI_SEMANTIC_GENERIC; + decl.Semantic.SemanticIndex = 0; + decl.u.DeclarationRange.First = 0; + decl.u.DeclarationRange.Last = 1; + ti += tgsi_build_full_declaration + ( + &decl, + &tokens[ti], + header, + max_tokens - ti + ); + + /* Declare outputs (pos, texcoords) */ + for (i = 0; i < num_attribs; i++) + { + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_OUTPUT; + decl.Declaration.Semantic = 1; + decl.Semantic.SemanticName = semantic_names[i]; + decl.Semantic.SemanticIndex = semantic_indexes[i]; + decl.u.DeclarationRange.First = i; + decl.u.DeclarationRange.Last = i; + ti += tgsi_build_full_declaration + ( + &decl, + &tokens[ti], + header, + max_tokens - ti + ); + } + + /* mul t0, i0, c0 ; Scale normalized coords to window coords */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_MUL; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_TEMPORARY; + inst.FullDstRegisters[0].DstRegister.Index = 0; + inst.Instruction.NumSrcRegs = 2; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_INPUT; + inst.FullSrcRegisters[0].SrcRegister.Index = 0; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_CONSTANT; + inst.FullSrcRegisters[1].SrcRegister.Index = 0; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + /* add o0, t0, c1 ; Translate vertex into position */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_ADD; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_OUTPUT; + inst.FullDstRegisters[0].DstRegister.Index = 0; + inst.Instruction.NumSrcRegs = 2; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_TEMPORARY; + inst.FullSrcRegisters[0].SrcRegister.Index = 0; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_CONSTANT; + inst.FullSrcRegisters[1].SrcRegister.Index = 1; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + /* + mov o1, i1 ; Move texcoords to output + mov o2, i2 + mov o3, i3 + */ + for (i = 1; i < num_attribs; ++i) + { + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_MOV; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_OUTPUT; + inst.FullDstRegisters[0].DstRegister.Index = i; + inst.Instruction.NumSrcRegs = 1; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_INPUT; + inst.FullSrcRegisters[0].SrcRegister.Index = i; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + } + + /* END */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_END; + inst.Instruction.NumDstRegs = 0; + inst.Instruction.NumSrcRegs = 0; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + vs.tokens = tokens; + + context->states.mc.i_vs = pipe->create_vs_state(pipe, &vs); + + return 0; +} + +static int vlCreateFragmentShaderIMC(struct VL_CONTEXT *context) +{ + const unsigned int max_tokens = 50; + const unsigned int proc_type = TGSI_PROCESSOR_FRAGMENT; + + struct pipe_context *pipe; + struct pipe_shader_state fs; + struct tgsi_token *tokens; + struct tgsi_header *header; + struct tgsi_processor *processor; + + struct tgsi_full_declaration decl; + struct tgsi_full_instruction inst; + + unsigned int ti; + unsigned int i; + + assert(context); + + pipe = context->pipe; + + tokens = (struct tgsi_token*)malloc(max_tokens * sizeof(struct tgsi_token)); + + /* Version */ + *(struct tgsi_version*)&tokens[0] = tgsi_build_version(); + + /* Header */ + header = (struct tgsi_header*)&tokens[1]; + *header = tgsi_build_header(); + + /* Processor */ + processor = (struct tgsi_processor*)&tokens[2]; + *processor = tgsi_build_processor(proc_type, header); + + ti = 3; + + /* Declare inputs (texcoords) */ + for (i = 0; i < 3; ++i) + { + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_INPUT; + decl.Declaration.Semantic = 1; + decl.Semantic.SemanticName = TGSI_SEMANTIC_GENERIC; + decl.Semantic.SemanticIndex = i + 1; + decl.Declaration.Interpolate = 1; + decl.Interpolation.Interpolate = TGSI_INTERPOLATE_LINEAR; + decl.u.DeclarationRange.First = i; + decl.u.DeclarationRange.Last = i; + ti += tgsi_build_full_declaration + ( + &decl, + &tokens[ti], + header, + max_tokens - ti + ); + } + + /* Declare output (color) */ + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_OUTPUT; + decl.Declaration.Semantic = 1; + decl.Semantic.SemanticName = TGSI_SEMANTIC_COLOR; + decl.Semantic.SemanticIndex = 0; + decl.u.DeclarationRange.First = 0; + decl.u.DeclarationRange.Last = 0; + ti += tgsi_build_full_declaration + ( + &decl, + &tokens[ti], + header, + max_tokens - ti + ); + + /* Declare samplers */ + for (i = 0; i < 3; ++i) + { + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_SAMPLER; + decl.u.DeclarationRange.First = i; + decl.u.DeclarationRange.Last = i; + ti += tgsi_build_full_declaration + ( + &decl, + &tokens[ti], + header, + max_tokens - ti + ); + } + + /* + tex2d o0.x, i0, s0 ; Read texel from luma texture into .x channel + tex2d o0.y, i1, s1 ; Read texel from chroma Cb texture into .y channel + tex2d o0.z, i2, s2 ; Read texel from chroma Cr texture into .z channel + */ + for (i = 0; i < 3; ++i) + { + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_TEX; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_OUTPUT; + inst.FullDstRegisters[0].DstRegister.Index = 0; + inst.FullDstRegisters[0].DstRegister.WriteMask = TGSI_WRITEMASK_X << i; + inst.Instruction.NumSrcRegs = 2; + inst.InstructionExtTexture.Texture = TGSI_TEXTURE_2D; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_INPUT; + inst.FullSrcRegisters[0].SrcRegister.Index = i; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_SAMPLER; + inst.FullSrcRegisters[1].SrcRegister.Index = i; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + } + + /* END */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_END; + inst.Instruction.NumDstRegs = 0; + inst.Instruction.NumSrcRegs = 0; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + fs.tokens = tokens; + + context->states.mc.i_fs = pipe->create_fs_state(pipe, &fs); + + return 0; +} + +static int vlCreateVertexShaderPMC(struct VL_CONTEXT *context) +{ + const unsigned int max_tokens = 100; + const unsigned int num_attribs = 5; + const unsigned int semantic_names[5] = + { + TGSI_SEMANTIC_POSITION, + TGSI_SEMANTIC_GENERIC, + TGSI_SEMANTIC_GENERIC, + TGSI_SEMANTIC_GENERIC, + TGSI_SEMANTIC_GENERIC + }; + const unsigned int semantic_indexes[5] = {0, 1, 2, 3, 4}; + const unsigned int proc_type = TGSI_PROCESSOR_VERTEX; + + struct pipe_context *pipe; + struct pipe_shader_state vs; + struct tgsi_token *tokens; + struct tgsi_header *header; + struct tgsi_processor *processor; + + struct tgsi_full_declaration decl; + struct tgsi_full_instruction inst; + + unsigned int ti; + unsigned int i; + + assert(context); + + pipe = context->pipe; + + tokens = (struct tgsi_token*)malloc(max_tokens * sizeof(struct tgsi_token)); + + /* Version */ + *(struct tgsi_version*)&tokens[0] = tgsi_build_version(); + + /* Header */ + header = (struct tgsi_header*)&tokens[1]; + *header = tgsi_build_header(); + + /* Processor */ + processor = (struct tgsi_processor*)&tokens[2]; + *processor = tgsi_build_processor(proc_type, header); + + ti = 3; + + /* Declare inputs (pos, texcoords) */ + for (i = 0; i < num_attribs; i++) + { + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_INPUT; + + decl.Declaration.Semantic = 1; + decl.Semantic.SemanticName = semantic_names[i]; + decl.Semantic.SemanticIndex = semantic_indexes[i]; + + decl.u.DeclarationRange.First = i; + decl.u.DeclarationRange.Last = i; + ti += tgsi_build_full_declaration + ( + &decl, + &tokens[ti], + header, + max_tokens - ti + ); + } + + /* Declare constant inputs */ + /* C[0] scales the normalized MB to cover 16x16 pixels, + C[1] translates the macroblock into position on the surface + C[2] translates the ref surface texcoords to the ref macroblock */ + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_CONSTANT; + decl.Declaration.Semantic = 1; + decl.Semantic.SemanticName = TGSI_SEMANTIC_GENERIC; + decl.Semantic.SemanticIndex = 0; + decl.u.DeclarationRange.First = 0; + decl.u.DeclarationRange.Last = 2; + ti += tgsi_build_full_declaration + ( + &decl, + &tokens[ti], + header, + max_tokens - ti + ); + + /* Declare outputs (pos, texcoords) */ + for (i = 0; i < num_attribs; i++) + { + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_OUTPUT; + decl.Declaration.Semantic = 1; + decl.Semantic.SemanticName = semantic_names[i]; + decl.Semantic.SemanticIndex = semantic_indexes[i]; + decl.u.DeclarationRange.First = i; + decl.u.DeclarationRange.Last = i; + ti += tgsi_build_full_declaration + ( + &decl, + &tokens[ti], + header, + max_tokens - ti + ); + } + + /* mul t0, i0, c0 ; Scale normalized coords to window coords */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_MUL; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_TEMPORARY; + inst.FullDstRegisters[0].DstRegister.Index = 0; + inst.Instruction.NumSrcRegs = 2; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_INPUT; + inst.FullSrcRegisters[0].SrcRegister.Index = 0; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_CONSTANT; + inst.FullSrcRegisters[1].SrcRegister.Index = 0; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + /* add o0, t0, c1 ; Translate vertex into position */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_ADD; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_OUTPUT; + inst.FullDstRegisters[0].DstRegister.Index = 0; + inst.Instruction.NumSrcRegs = 2; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_TEMPORARY; + inst.FullSrcRegisters[0].SrcRegister.Index = 0; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_CONSTANT; + inst.FullSrcRegisters[1].SrcRegister.Index = 1; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + /* + mov o1, i1 ; Move luma & chroma texcoords to output + mov o2, i2 + mov o3, i3 + */ + for (i = 1; i < num_attribs - 1; ++i) + { + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_MOV; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_OUTPUT; + inst.FullDstRegisters[0].DstRegister.Index = i; + inst.Instruction.NumSrcRegs = 1; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_INPUT; + inst.FullSrcRegisters[0].SrcRegister.Index = i; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + } + + /* mul t0, i4, c0 ; Scale normalized coords to window coords */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_MUL; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_TEMPORARY; + inst.FullDstRegisters[0].DstRegister.Index = 0; + inst.Instruction.NumSrcRegs = 2; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_INPUT; + inst.FullSrcRegisters[0].SrcRegister.Index = 4; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_CONSTANT; + inst.FullSrcRegisters[1].SrcRegister.Index = 0; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + /* add o4, t0, c2 ; Translate texcoords into position */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_ADD; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_OUTPUT; + inst.FullDstRegisters[0].DstRegister.Index = 4; + inst.Instruction.NumSrcRegs = 2; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_TEMPORARY; + inst.FullSrcRegisters[0].SrcRegister.Index = 0; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_CONSTANT; + inst.FullSrcRegisters[1].SrcRegister.Index = 2; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + /* END */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_END; + inst.Instruction.NumDstRegs = 0; + inst.Instruction.NumSrcRegs = 0; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + vs.tokens = tokens; + + context->states.mc.p_vs = pipe->create_vs_state(pipe, &vs); + + return 0; +} + +static int vlCreateFragmentShaderPMC(struct VL_CONTEXT *context) +{ + const unsigned int max_tokens = 100; + const unsigned int proc_type = TGSI_PROCESSOR_FRAGMENT; + + struct pipe_context *pipe; + struct pipe_shader_state fs; + struct tgsi_token *tokens; + struct tgsi_header *header; + struct tgsi_processor *processor; + + struct tgsi_full_declaration decl; + struct tgsi_full_instruction inst; + + unsigned int ti; + unsigned int i; + + assert(context); + + pipe = context->pipe; + + tokens = (struct tgsi_token*)malloc(max_tokens * sizeof(struct tgsi_token)); + + /* Version */ + *(struct tgsi_version*)&tokens[0] = tgsi_build_version(); + + /* Header */ + header = (struct tgsi_header*)&tokens[1]; + *header = tgsi_build_header(); + + /* Processor */ + processor = (struct tgsi_processor*)&tokens[2]; + *processor = tgsi_build_processor(proc_type, header); + + ti = 3; + + /* Declare inputs (texcoords) */ + for (i = 0; i < 4; ++i) + { + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_INPUT; + decl.Declaration.Semantic = 1; + decl.Semantic.SemanticName = TGSI_SEMANTIC_GENERIC; + decl.Semantic.SemanticIndex = i + 1; + decl.Declaration.Interpolate = 1; + decl.Interpolation.Interpolate = TGSI_INTERPOLATE_LINEAR; + decl.u.DeclarationRange.First = i; + decl.u.DeclarationRange.Last = i; + ti += tgsi_build_full_declaration + ( + &decl, + &tokens[ti], + header, + max_tokens - ti + ); + } + + /* Declare constant input */ + /* C[0] is a multiplier to use when concatenating differential into a single channel + C[0] is a bias to get differential back to -1,1 range*/ + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_CONSTANT; + decl.Declaration.Semantic = 1; + decl.Semantic.SemanticName = TGSI_SEMANTIC_GENERIC; + decl.Semantic.SemanticIndex = 0; + decl.u.DeclarationRange.First = 0; + decl.u.DeclarationRange.Last = 1; + ti += tgsi_build_full_declaration + ( + &decl, + &tokens[ti], + header, + max_tokens - ti + ); + + /* Declare output */ + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_OUTPUT; + decl.Declaration.Semantic = 1; + decl.Semantic.SemanticName = TGSI_SEMANTIC_COLOR; + decl.Semantic.SemanticIndex = 0; + decl.u.DeclarationRange.First = 0; + decl.u.DeclarationRange.Last = 0; + ti += tgsi_build_full_declaration + ( + &decl, + &tokens[ti], + header, + max_tokens - ti + ); + + /* Declare samplers */ + for (i = 0; i < 4; ++i) + { + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_SAMPLER; + decl.u.DeclarationRange.First = i; + decl.u.DeclarationRange.Last = i; + ti += tgsi_build_full_declaration + ( + &decl, + &tokens[ti], + header, + max_tokens - ti + ); + } + + /* + tex2d t0.xw, i0, s0 ; Read texel from luma texture into .x and .w channels + mov t1.x, t0.w ; Move high part from .w channel to .x + tex2d t0.yw, i1, s1 ; Read texel from chroma Cb texture into .y and .w channels + mov t1.y, t0.w ; Move high part from .w channel to .y + tex2d t0.zw, i2, s2 ; Read texel from chroma Cr texture into .z and .w channels + mov t1.z, t0.w ; Move high part from .w channel to .z + */ + for (i = 0; i < 3; ++i) + { + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_TEX; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_TEMPORARY; + inst.FullDstRegisters[0].DstRegister.Index = 0; + inst.FullDstRegisters[0].DstRegister.WriteMask = (TGSI_WRITEMASK_X << i) | TGSI_WRITEMASK_W; + inst.Instruction.NumSrcRegs = 2; + inst.InstructionExtTexture.Texture = TGSI_TEXTURE_2D; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_INPUT; + inst.FullSrcRegisters[0].SrcRegister.Index = i; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_SAMPLER; + inst.FullSrcRegisters[1].SrcRegister.Index = i; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_MOV; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_TEMPORARY; + inst.FullDstRegisters[0].DstRegister.Index = 1; + inst.FullDstRegisters[0].DstRegister.WriteMask = TGSI_WRITEMASK_X << i; + inst.Instruction.NumSrcRegs = 1; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_TEMPORARY; + inst.FullSrcRegisters[0].SrcRegister.Index = 0; + inst.FullSrcRegisters[0].SrcRegister.SwizzleX = TGSI_SWIZZLE_W; + inst.FullSrcRegisters[0].SrcRegister.SwizzleY = TGSI_SWIZZLE_W; + inst.FullSrcRegisters[0].SrcRegister.SwizzleZ = TGSI_SWIZZLE_W; + inst.FullSrcRegisters[0].SrcRegister.SwizzleW = TGSI_SWIZZLE_W; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + } + + /* mul t1, t1, c0 ; Muliply high part by multiplier to get back its full value */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_MUL; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_TEMPORARY; + inst.FullDstRegisters[0].DstRegister.Index = 1; + inst.Instruction.NumSrcRegs = 2; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_TEMPORARY; + inst.FullSrcRegisters[0].SrcRegister.Index = 1; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_CONSTANT; + inst.FullSrcRegisters[1].SrcRegister.Index = 0; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + /* add t0, t0, t1 ; Add luma and chroma low and high parts to get a single value */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_ADD; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_TEMPORARY; + inst.FullDstRegisters[0].DstRegister.Index = 0; + inst.Instruction.NumSrcRegs = 2; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_TEMPORARY; + inst.FullSrcRegisters[0].SrcRegister.Index = 0; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_TEMPORARY; + inst.FullSrcRegisters[1].SrcRegister.Index = 1; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + /* sub t0, t0, c1 ; Subtract bias to get back the signed value */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_SUB; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_TEMPORARY; + inst.FullDstRegisters[0].DstRegister.Index = 0; + inst.Instruction.NumSrcRegs = 2; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_TEMPORARY; + inst.FullSrcRegisters[0].SrcRegister.Index = 0; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_CONSTANT; + inst.FullSrcRegisters[1].SrcRegister.Index = 1; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + /* tex2d t1, i3, s3 ; Read texel from ref macroblock */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_TEX; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_TEMPORARY; + inst.FullDstRegisters[0].DstRegister.Index = 1; + inst.Instruction.NumSrcRegs = 2; + inst.InstructionExtTexture.Texture = TGSI_TEXTURE_2D; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_INPUT; + inst.FullSrcRegisters[0].SrcRegister.Index = 3; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_SAMPLER; + inst.FullSrcRegisters[1].SrcRegister.Index = 3; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + /* add o0, t0, t1 ; Add ref and differential to form final output */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_ADD; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_OUTPUT; + inst.FullDstRegisters[0].DstRegister.Index = 0; + inst.Instruction.NumSrcRegs = 2; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_TEMPORARY; + inst.FullSrcRegisters[0].SrcRegister.Index = 0; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_TEMPORARY; + inst.FullSrcRegisters[1].SrcRegister.Index = 1; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + /* END */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_END; + inst.Instruction.NumDstRegs = 0; + inst.Instruction.NumSrcRegs = 0; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + fs.tokens = tokens; + + context->states.mc.p_fs = pipe->create_fs_state(pipe, &fs); + + return 0; +} + +static int vlCreateVertexShaderBMC(struct VL_CONTEXT *context) +{ + const unsigned int max_tokens = 100; + const unsigned int num_attribs = 6; + const unsigned int semantic_names[6] = + { + TGSI_SEMANTIC_POSITION, + TGSI_SEMANTIC_GENERIC, + TGSI_SEMANTIC_GENERIC, + TGSI_SEMANTIC_GENERIC, + TGSI_SEMANTIC_GENERIC, + TGSI_SEMANTIC_GENERIC + }; + const unsigned int semantic_indexes[6] = {0, 1, 2, 3, 4, 5}; + const unsigned int proc_type = TGSI_PROCESSOR_VERTEX; + + struct pipe_context *pipe; + struct pipe_shader_state vs; + struct tgsi_token *tokens; + struct tgsi_header *header; + struct tgsi_processor *processor; + + struct tgsi_full_declaration decl; + struct tgsi_full_instruction inst; + + unsigned int ti; + unsigned int i; + + assert(context); + + pipe = context->pipe; + + tokens = (struct tgsi_token*)malloc(max_tokens * sizeof(struct tgsi_token)); + + /* Version */ + *(struct tgsi_version*)&tokens[0] = tgsi_build_version(); + + /* Header */ + header = (struct tgsi_header*)&tokens[1]; + *header = tgsi_build_header(); + + /* Processor */ + processor = (struct tgsi_processor*)&tokens[2]; + *processor = tgsi_build_processor(proc_type, header); + + ti = 3; + + /* Declare inputs (pos, texcoords) */ + for (i = 0; i < num_attribs; i++) + { + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_INPUT; + + decl.Declaration.Semantic = 1; + decl.Semantic.SemanticName = semantic_names[i]; + decl.Semantic.SemanticIndex = semantic_indexes[i]; + + decl.u.DeclarationRange.First = i; + decl.u.DeclarationRange.Last = i; + ti += tgsi_build_full_declaration + ( + &decl, + &tokens[ti], + header, + max_tokens - ti + ); + } + + /* Declare constant inputs */ + /* C[0] scales the normalized MB to cover 16x16 pixels, + C[1] translates the macroblock into position on the surface + C[2] translates the past surface texcoords to the ref macroblock + C[3] translates the future surface texcoords to the ref macroblock */ + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_CONSTANT; + decl.Declaration.Semantic = 1; + decl.Semantic.SemanticName = TGSI_SEMANTIC_GENERIC; + decl.Semantic.SemanticIndex = 0; + decl.u.DeclarationRange.First = 0; + decl.u.DeclarationRange.Last = 3; + ti += tgsi_build_full_declaration + ( + &decl, + &tokens[ti], + header, + max_tokens - ti + ); + + /* Declare outputs (pos, texcoords) */ + for (i = 0; i < num_attribs; i++) + { + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_OUTPUT; + decl.Declaration.Semantic = 1; + decl.Semantic.SemanticName = semantic_names[i]; + decl.Semantic.SemanticIndex = semantic_indexes[i]; + decl.u.DeclarationRange.First = i; + decl.u.DeclarationRange.Last = i; + ti += tgsi_build_full_declaration + ( + &decl, + &tokens[ti], + header, + max_tokens - ti + ); + } + + /* mul t0, i0, c0 ; Scale normalized coords to window coords */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_MUL; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_TEMPORARY; + inst.FullDstRegisters[0].DstRegister.Index = 0; + inst.Instruction.NumSrcRegs = 2; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_INPUT; + inst.FullSrcRegisters[0].SrcRegister.Index = 0; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_CONSTANT; + inst.FullSrcRegisters[1].SrcRegister.Index = 0; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + /* add o0, t0, c1 ; Translate vertex into position */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_ADD; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_OUTPUT; + inst.FullDstRegisters[0].DstRegister.Index = 0; + inst.Instruction.NumSrcRegs = 2; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_TEMPORARY; + inst.FullSrcRegisters[0].SrcRegister.Index = 0; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_CONSTANT; + inst.FullSrcRegisters[1].SrcRegister.Index = 1; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + /* + mov o1, i1 ; Move luma & chroma texcoords to output + mov o2, i2 + mov o3, i3 + */ + for (i = 1; i < num_attribs - 1; ++i) + { + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_MOV; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_OUTPUT; + inst.FullDstRegisters[0].DstRegister.Index = i; + inst.Instruction.NumSrcRegs = 1; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_INPUT; + inst.FullSrcRegisters[0].SrcRegister.Index = i; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + } + + /* mul t0, i4, c0 ; Scale normalized coords to window coords + add o4, t0, c2 ; Translate texcoords into position + mul t1, i5, c0 ; Repeat for the future surface + add o5, t1, c3 */ + for (i = 0; i < 2; ++i) + { + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_MUL; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_TEMPORARY; + inst.FullDstRegisters[0].DstRegister.Index = i; + inst.Instruction.NumSrcRegs = 2; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_INPUT; + inst.FullSrcRegisters[0].SrcRegister.Index = i + 4; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_CONSTANT; + inst.FullSrcRegisters[1].SrcRegister.Index = 0; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_ADD; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_OUTPUT; + inst.FullDstRegisters[0].DstRegister.Index = i + 4; + inst.Instruction.NumSrcRegs = 2; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_TEMPORARY; + inst.FullSrcRegisters[0].SrcRegister.Index = i; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_CONSTANT; + inst.FullSrcRegisters[1].SrcRegister.Index = i + 2; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + } + + /* END */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_END; + inst.Instruction.NumDstRegs = 0; + inst.Instruction.NumSrcRegs = 0; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + vs.tokens = tokens; + + context->states.mc.b_vs = pipe->create_vs_state(pipe, &vs); + + return 0; +} + +static int vlCreateFragmentShaderBMC(struct VL_CONTEXT *context) +{ + const unsigned int max_tokens = 100; + const unsigned int proc_type = TGSI_PROCESSOR_FRAGMENT; + + struct pipe_context *pipe; + struct pipe_shader_state fs; + struct tgsi_token *tokens; + struct tgsi_header *header; + struct tgsi_processor *processor; + + struct tgsi_full_declaration decl; + struct tgsi_full_instruction inst; + + unsigned int ti; + unsigned int i; + + assert(context); + + pipe = context->pipe; + + tokens = (struct tgsi_token*)malloc(max_tokens * sizeof(struct tgsi_token)); + + /* Version */ + *(struct tgsi_version*)&tokens[0] = tgsi_build_version(); + + /* Header */ + header = (struct tgsi_header*)&tokens[1]; + *header = tgsi_build_header(); + + /* Processor */ + processor = (struct tgsi_processor*)&tokens[2]; + *processor = tgsi_build_processor(proc_type, header); + + ti = 3; + + /* Declare inputs (texcoords) */ + for (i = 0; i < 5; ++i) + { + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_INPUT; + decl.Declaration.Semantic = 1; + decl.Semantic.SemanticName = TGSI_SEMANTIC_GENERIC; + decl.Semantic.SemanticIndex = i + 1; + decl.Declaration.Interpolate = 1; + decl.Interpolation.Interpolate = TGSI_INTERPOLATE_LINEAR; + decl.u.DeclarationRange.First = i; + decl.u.DeclarationRange.Last = i; + ti += tgsi_build_full_declaration + ( + &decl, + &tokens[ti], + header, + max_tokens - ti + ); + } + + /* Declare constant input */ + /* C[0] is a multiplier to use when concatenating differential into a single channel + C[0] is a bias to get differential back to -1,1 range*/ + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_CONSTANT; + decl.Declaration.Semantic = 1; + decl.Semantic.SemanticName = TGSI_SEMANTIC_GENERIC; + decl.Semantic.SemanticIndex = 0; + decl.u.DeclarationRange.First = 0; + decl.u.DeclarationRange.Last = 1; + ti += tgsi_build_full_declaration + ( + &decl, + &tokens[ti], + header, + max_tokens - ti + ); + + /* Declare output */ + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_OUTPUT; + decl.Declaration.Semantic = 1; + decl.Semantic.SemanticName = TGSI_SEMANTIC_COLOR; + decl.Semantic.SemanticIndex = 0; + decl.u.DeclarationRange.First = 0; + decl.u.DeclarationRange.Last = 0; + ti += tgsi_build_full_declaration + ( + &decl, + &tokens[ti], + header, + max_tokens - ti + ); + + /* Declare samplers */ + for (i = 0; i < 5; ++i) + { + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_SAMPLER; + decl.u.DeclarationRange.First = i; + decl.u.DeclarationRange.Last = i; + ti += tgsi_build_full_declaration + ( + &decl, + &tokens[ti], + header, + max_tokens - ti + ); + } + + /* + tex2d t0.xw, i0, s0 ; Read texel from luma texture into .x and .w channels + mov t1.x, t0.w ; Move high part from .w channel to .x + tex2d t0.yw, i1, s1 ; Read texel from chroma Cb texture into .y and .w channels + mov t1.y, t0.w ; Move high part from .w channel to .y + tex2d t0.zw, i2, s2 ; Read texel from chroma Cr texture into .z and .w channels + mov t1.z, t0.w ; Move high part from .w channel to .z + */ + for (i = 0; i < 3; ++i) + { + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_TEX; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_TEMPORARY; + inst.FullDstRegisters[0].DstRegister.Index = 0; + inst.FullDstRegisters[0].DstRegister.WriteMask = (TGSI_WRITEMASK_X << i) | TGSI_WRITEMASK_W; + inst.Instruction.NumSrcRegs = 2; + inst.InstructionExtTexture.Texture = TGSI_TEXTURE_2D; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_INPUT; + inst.FullSrcRegisters[0].SrcRegister.Index = i; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_SAMPLER; + inst.FullSrcRegisters[1].SrcRegister.Index = i; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_MOV; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_TEMPORARY; + inst.FullDstRegisters[0].DstRegister.Index = 1; + inst.FullDstRegisters[0].DstRegister.WriteMask = TGSI_WRITEMASK_X << i; + inst.Instruction.NumSrcRegs = 1; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_TEMPORARY; + inst.FullSrcRegisters[0].SrcRegister.Index = 0; + inst.FullSrcRegisters[0].SrcRegister.SwizzleX = TGSI_SWIZZLE_W; + inst.FullSrcRegisters[0].SrcRegister.SwizzleY = TGSI_SWIZZLE_W; + inst.FullSrcRegisters[0].SrcRegister.SwizzleZ = TGSI_SWIZZLE_W; + inst.FullSrcRegisters[0].SrcRegister.SwizzleW = TGSI_SWIZZLE_W; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + } + + /* mul t1, t1, c0 ; Muliply high part by multiplier to get back its full value */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_MUL; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_TEMPORARY; + inst.FullDstRegisters[0].DstRegister.Index = 1; + inst.Instruction.NumSrcRegs = 2; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_TEMPORARY; + inst.FullSrcRegisters[0].SrcRegister.Index = 1; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_CONSTANT; + inst.FullSrcRegisters[1].SrcRegister.Index = 0; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + /* add t0, t0, t1 ; Add luma and chroma low and high parts to get a single value */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_ADD; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_TEMPORARY; + inst.FullDstRegisters[0].DstRegister.Index = 0; + inst.Instruction.NumSrcRegs = 2; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_TEMPORARY; + inst.FullSrcRegisters[0].SrcRegister.Index = 0; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_TEMPORARY; + inst.FullSrcRegisters[1].SrcRegister.Index = 1; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + /* sub t0, t0, c1 ; Subtract bias to get back the signed value */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_SUB; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_TEMPORARY; + inst.FullDstRegisters[0].DstRegister.Index = 0; + inst.Instruction.NumSrcRegs = 2; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_TEMPORARY; + inst.FullSrcRegisters[0].SrcRegister.Index = 0; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_CONSTANT; + inst.FullSrcRegisters[1].SrcRegister.Index = 1; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + /* tex2d t1, i3, s3 ; Read texel from past macroblock + tex2d t2, i4, s4 ; Read texel from future macroblock */ + for (i = 0; i < 2; ++i) + { + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_TEX; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_TEMPORARY; + inst.FullDstRegisters[0].DstRegister.Index = i + 1; + inst.Instruction.NumSrcRegs = 2; + inst.InstructionExtTexture.Texture = TGSI_TEXTURE_2D; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_INPUT; + inst.FullSrcRegisters[0].SrcRegister.Index = i + 3; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_SAMPLER; + inst.FullSrcRegisters[1].SrcRegister.Index = i + 3; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + } + + /* add t0, t0, t1 ; Add past and differential to form partial output */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_ADD; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_TEMPORARY; + inst.FullDstRegisters[0].DstRegister.Index = 0; + inst.Instruction.NumSrcRegs = 2; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_TEMPORARY; + inst.FullSrcRegisters[0].SrcRegister.Index = 0; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_TEMPORARY; + inst.FullSrcRegisters[1].SrcRegister.Index = 1; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + /* add o0, t0, t2 ; Add future and differential to form final output */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_ADD; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_OUTPUT; + inst.FullDstRegisters[0].DstRegister.Index = 0; + inst.Instruction.NumSrcRegs = 2; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_TEMPORARY; + inst.FullSrcRegisters[0].SrcRegister.Index = 0; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_TEMPORARY; + inst.FullSrcRegisters[1].SrcRegister.Index = 2; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + /* END */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_END; + inst.Instruction.NumDstRegs = 0; + inst.Instruction.NumSrcRegs = 0; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + fs.tokens = tokens; + + context->states.mc.b_fs = pipe->create_fs_state(pipe, &fs); + + return 0; +} + +int vlCreateDataBufsMC(struct VL_CONTEXT *context) +{ + struct pipe_context *pipe; + unsigned int i; + + assert(context); + + pipe = context->pipe; + + /* Create our vertex buffer and vertex buffer element */ + context->states.mc.vertex_bufs[0].pitch = sizeof(struct VL_VERTEX2F); + context->states.mc.vertex_bufs[0].max_index = 23; + context->states.mc.vertex_bufs[0].buffer_offset = 0; + context->states.mc.vertex_bufs[0].buffer = pipe->winsys->buffer_create + ( + pipe->winsys, + 1, + PIPE_BUFFER_USAGE_VERTEX, + sizeof(struct VL_VERTEX2F) * 24 + ); + + context->states.mc.vertex_buf_elems[0].src_offset = 0; + context->states.mc.vertex_buf_elems[0].vertex_buffer_index = 0; + context->states.mc.vertex_buf_elems[0].nr_components = 2; + context->states.mc.vertex_buf_elems[0].src_format = PIPE_FORMAT_R32G32_FLOAT; + + /* Create our texcoord buffers and texcoord buffer elements */ + /* TODO: Should be able to use 1 texcoord buf for chroma textures, 1 buf for ref surfaces */ + for (i = 1; i < 6; ++i) + { + context->states.mc.vertex_bufs[i].pitch = sizeof(struct VL_TEXCOORD2F); + context->states.mc.vertex_bufs[i].max_index = 23; + context->states.mc.vertex_bufs[i].buffer_offset = 0; + context->states.mc.vertex_bufs[i].buffer = pipe->winsys->buffer_create + ( + pipe->winsys, + 1, + PIPE_BUFFER_USAGE_VERTEX, + sizeof(struct VL_TEXCOORD2F) * 24 + ); + + context->states.mc.vertex_buf_elems[i].src_offset = 0; + context->states.mc.vertex_buf_elems[i].vertex_buffer_index = i; + context->states.mc.vertex_buf_elems[i].nr_components = 2; + context->states.mc.vertex_buf_elems[i].src_format = PIPE_FORMAT_R32G32_FLOAT; + } + + /* Fill buffers */ + memcpy + ( + pipe->winsys->buffer_map(pipe->winsys, context->states.mc.vertex_bufs[0].buffer, PIPE_BUFFER_USAGE_CPU_WRITE), + vl_chroma_420_texcoords, + sizeof(struct VL_VERTEX2F) * 24 + ); + memcpy + ( + pipe->winsys->buffer_map(pipe->winsys, context->states.mc.vertex_bufs[1].buffer, PIPE_BUFFER_USAGE_CPU_WRITE), + vl_luma_texcoords, + sizeof(struct VL_TEXCOORD2F) * 24 + ); + /* TODO: Accomodate 422, 444 */ + memcpy + ( + pipe->winsys->buffer_map(pipe->winsys, context->states.mc.vertex_bufs[2].buffer, PIPE_BUFFER_USAGE_CPU_WRITE), + vl_chroma_420_texcoords, + sizeof(struct VL_TEXCOORD2F) * 24 + ); + memcpy + ( + pipe->winsys->buffer_map(pipe->winsys, context->states.mc.vertex_bufs[3].buffer, PIPE_BUFFER_USAGE_CPU_WRITE), + vl_chroma_420_texcoords, + sizeof(struct VL_TEXCOORD2F) * 24 + ); + memcpy + ( + pipe->winsys->buffer_map(pipe->winsys, context->states.mc.vertex_bufs[4].buffer, PIPE_BUFFER_USAGE_CPU_WRITE), + vl_ref_surface_texcoords, + sizeof(struct VL_TEXCOORD2F) * 24 + ); + memcpy + ( + pipe->winsys->buffer_map(pipe->winsys, context->states.mc.vertex_bufs[5].buffer, PIPE_BUFFER_USAGE_CPU_WRITE), + vl_ref_surface_texcoords, + sizeof(struct VL_TEXCOORD2F) * 24 + ); + + for (i = 0; i < 6; ++i) + pipe->winsys->buffer_unmap(pipe->winsys, context->states.mc.vertex_bufs[i].buffer); + + /* Create our constant buffer */ + context->states.mc.vs_const_buf.size = sizeof(struct VL_MC_VS_CONSTS); + context->states.mc.vs_const_buf.buffer = pipe->winsys->buffer_create + ( + pipe->winsys, + 1, + PIPE_BUFFER_USAGE_CONSTANT, + context->states.mc.vs_const_buf.size + ); + + context->states.mc.fs_const_buf.size = sizeof(struct VL_MC_FS_CONSTS); + context->states.mc.fs_const_buf.buffer = pipe->winsys->buffer_create + ( + pipe->winsys, + 1, + PIPE_BUFFER_USAGE_CONSTANT, + context->states.mc.fs_const_buf.size + ); + + memcpy + ( + pipe->winsys->buffer_map(pipe->winsys, context->states.mc.fs_const_buf.buffer, PIPE_BUFFER_USAGE_CPU_WRITE), + &vl_mc_fs_consts, + sizeof(struct VL_MC_FS_CONSTS) + ); + + pipe->winsys->buffer_unmap(pipe->winsys, context->states.mc.fs_const_buf.buffer); + + return 0; +} + +static int vlInitMC(struct VL_CONTEXT *context) +{ + struct pipe_context *pipe; + struct pipe_sampler_state sampler; + struct pipe_texture template; + unsigned int filters[5]; + unsigned int i; + + assert(context); + + pipe = context->pipe; + + context->states.mc.viewport.scale[0] = context->video_width; + context->states.mc.viewport.scale[1] = context->video_height; + context->states.mc.viewport.scale[2] = 1; + context->states.mc.viewport.scale[3] = 1; + context->states.mc.viewport.translate[0] = 0; + context->states.mc.viewport.translate[1] = 0; + context->states.mc.viewport.translate[2] = 0; + context->states.mc.viewport.translate[3] = 0; + + context->states.mc.render_target.width = context->video_width; + context->states.mc.render_target.height = context->video_height; + context->states.mc.render_target.num_cbufs = 1; + /* FB for MC stage is a VL_SURFACE, set in vlSetRenderSurface() */ + /*context->states.mc.render_target.cbufs[0] = ;*/ + context->states.mc.render_target.zsbuf = NULL; + + filters[0] = PIPE_TEX_FILTER_NEAREST; + filters[1] = context->video_format == VL_FORMAT_YCBCR_444 ? PIPE_TEX_FILTER_NEAREST : PIPE_TEX_FILTER_LINEAR; + filters[2] = context->video_format == VL_FORMAT_YCBCR_444 ? PIPE_TEX_FILTER_NEAREST : PIPE_TEX_FILTER_LINEAR; + filters[3] = PIPE_TEX_FILTER_NEAREST; + filters[4] = PIPE_TEX_FILTER_NEAREST; + + for (i = 0; i < 5; ++i) + { + 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.prefilter = ;*/ + /*sampler.shadow_ambient = ;*/ + /*sampler.lod_bias = ;*/ + /*sampler.min_lod = ;*/ + /*sampler.max_lod = ;*/ + /*sampler.border_color[i] = ;*/ + /*sampler.max_anisotropy = ;*/ + context->states.mc.samplers[i] = pipe->create_sampler_state(pipe, &sampler); + } + + memset(&template, 0, sizeof(struct pipe_texture)); + template.target = PIPE_TEXTURE_2D; + template.format = PIPE_FORMAT_A8L8_UNORM; + template.last_level = 0; + template.width[0] = 8; + template.height[0] = 8 * 4; + template.depth[0] = 1; + template.compressed = 0; + template.cpp = 2; + context->states.mc.textures[0] = pipe->screen->texture_create(pipe->screen, &template); + + if (context->video_format == VL_FORMAT_YCBCR_420) + template.height[0] = 8; + else if (context->video_format == VL_FORMAT_YCBCR_422) + template.height[0] = 8 * 2; + else if (context->video_format == VL_FORMAT_YCBCR_444) + template.height[0] = 8 * 4; + else + assert(0); + + context->states.mc.textures[1] = pipe->screen->texture_create(pipe->screen, &template); + context->states.mc.textures[2] = pipe->screen->texture_create(pipe->screen, &template); + + /* textures[3] & textures[4] are assigned from VL_SURFACEs for P and B macroblocks at render time */ + + vlCreateVertexShaderIMC(context); + vlCreateFragmentShaderIMC(context); + vlCreateVertexShaderPMC(context); + vlCreateFragmentShaderPMC(context); + vlCreateVertexShaderBMC(context); + vlCreateFragmentShaderBMC(context); + vlCreateDataBufsMC(context); + + return 0; +} + +static int vlDestroyMC(struct VL_CONTEXT *context) +{ + unsigned int i; + + assert(context); + + for (i = 0; i < 5; ++i) + { + context->pipe->delete_sampler_state(context->pipe, context->states.mc.samplers[i]); + context->pipe->winsys->buffer_destroy(context->pipe->winsys, context->states.mc.vertex_bufs[i].buffer); + } + + context->pipe->winsys->buffer_destroy(context->pipe->winsys, context->states.mc.vertex_bufs[5].buffer); + + /* Textures 3 & 4 are not created directly, no need to release them here */ + for (i = 0; i < 3; ++i) + pipe_texture_release(&context->states.mc.textures[i]); + + context->pipe->delete_vs_state(context->pipe, context->states.mc.i_vs); + context->pipe->delete_fs_state(context->pipe, context->states.mc.i_fs); + context->pipe->delete_vs_state(context->pipe, context->states.mc.p_vs); + context->pipe->delete_fs_state(context->pipe, context->states.mc.p_fs); + context->pipe->delete_vs_state(context->pipe, context->states.mc.b_vs); + context->pipe->delete_fs_state(context->pipe, context->states.mc.b_fs); + + context->pipe->winsys->buffer_destroy(context->pipe->winsys, context->states.mc.vs_const_buf.buffer); + context->pipe->winsys->buffer_destroy(context->pipe->winsys, context->states.mc.fs_const_buf.buffer); + + return 0; +} + +static int vlCreateVertexShaderCSC(struct VL_CONTEXT *context) +{ + const unsigned int max_tokens = 50; + const unsigned int num_attribs = 2; + const unsigned int semantic_names[2] = {TGSI_SEMANTIC_POSITION, TGSI_SEMANTIC_GENERIC}; + const unsigned int semantic_indexes[2] = {0, 1}; + const unsigned int proc_type = TGSI_PROCESSOR_VERTEX; + + struct pipe_context *pipe; + struct pipe_shader_state vs; + struct tgsi_token *tokens; + struct tgsi_header *header; + struct tgsi_processor *processor; + + struct tgsi_full_declaration decl; + struct tgsi_full_instruction inst; + + unsigned int ti; + unsigned int i; + + assert(context); + + pipe = context->pipe; + + tokens = (struct tgsi_token*)malloc(max_tokens * sizeof(struct tgsi_token)); + + /* Version */ + *(struct tgsi_version*)&tokens[0] = tgsi_build_version(); + + /* Header */ + header = (struct tgsi_header*)&tokens[1]; + *header = tgsi_build_header(); + + /* Processor */ + processor = (struct tgsi_processor*)&tokens[2]; + *processor = tgsi_build_processor(proc_type, header); + + ti = 3; + + /* Declare inputs (pos, texcoords) */ + for (i = 0; i < num_attribs; i++) + { + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_INPUT; + + decl.Declaration.Semantic = 1; + decl.Semantic.SemanticName = semantic_names[i]; + decl.Semantic.SemanticIndex = semantic_indexes[i]; + + decl.u.DeclarationRange.First = i; + decl.u.DeclarationRange.Last = i; + ti += tgsi_build_full_declaration + ( + &decl, + &tokens[ti], + header, + max_tokens - ti + ); + } + + /* Declare outputs (pos, texcoords) */ + for (i = 0; i < num_attribs; i++) + { + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_OUTPUT; + decl.Declaration.Semantic = 1; + decl.Semantic.SemanticName = semantic_names[i]; + decl.Semantic.SemanticIndex = semantic_indexes[i]; + decl.u.DeclarationRange.First = i; + decl.u.DeclarationRange.Last = i; + ti += tgsi_build_full_declaration + ( + &decl, + &tokens[ti], + header, + max_tokens - ti + ); + } + + /* MOV instructions */ + /* mov o0, i0 + mov o1, i1 */ + for (i = 0; i < num_attribs; i++) + { + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_MOV; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_OUTPUT; + inst.FullDstRegisters[0].DstRegister.Index = i; + inst.Instruction.NumSrcRegs = 1; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_INPUT; + inst.FullSrcRegisters[0].SrcRegister.Index = i; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + } + + /* END instruction */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_END; + inst.Instruction.NumDstRegs = 0; + inst.Instruction.NumSrcRegs = 0; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + vs.tokens = tokens; + + context->states.csc.vertex_shader = pipe->create_vs_state(pipe, &vs); + + return 0; +} + +static int vlCreateFragmentShaderCSC(struct VL_CONTEXT *context) +{ + const unsigned int max_tokens = 50; + const unsigned int proc_type = TGSI_PROCESSOR_FRAGMENT; + + struct pipe_context *pipe; + struct pipe_shader_state fs; + struct tgsi_token *tokens; + struct tgsi_header *header; + struct tgsi_processor *processor; + + struct tgsi_full_declaration decl; + struct tgsi_full_instruction inst; + + unsigned int ti; + unsigned int i; + + assert(context); + + pipe = context->pipe; + + tokens = (struct tgsi_token*)malloc(max_tokens * sizeof(struct tgsi_token)); + + /* Version */ + *(struct tgsi_version*)&tokens[0] = tgsi_build_version(); + + /* Header */ + header = (struct tgsi_header*)&tokens[1]; + *header = tgsi_build_header(); + + /* Processor */ + processor = (struct tgsi_processor*)&tokens[2]; + *processor = tgsi_build_processor(proc_type, header); + + ti = 3; + + /* Declare TEX[0] input */ + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_INPUT; + decl.Declaration.Semantic = 1; + decl.Semantic.SemanticName = TGSI_SEMANTIC_GENERIC; + decl.Semantic.SemanticIndex = 1; + decl.Declaration.Interpolate = 1; + decl.Interpolation.Interpolate = TGSI_INTERPOLATE_LINEAR; + decl.u.DeclarationRange.First = 0; + decl.u.DeclarationRange.Last = 0; + ti += tgsi_build_full_declaration + ( + &decl, + &tokens[ti], + header, + max_tokens - ti + ); + + /* Declare constant input */ + /* Constants include bias vector, 4x4 csc matrix, total 5 vectors */ + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_CONSTANT; + decl.Declaration.Semantic = 1; + decl.Semantic.SemanticName = TGSI_SEMANTIC_GENERIC; + decl.Semantic.SemanticIndex = 0; + decl.u.DeclarationRange.First = 0; + decl.u.DeclarationRange.Last = 4; + ti += tgsi_build_full_declaration + ( + &decl, + &tokens[ti], + header, + max_tokens - ti + ); + + /* Declare output */ + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_OUTPUT; + decl.Declaration.Semantic = 1; + decl.Semantic.SemanticName = TGSI_SEMANTIC_COLOR; + decl.Semantic.SemanticIndex = 0; + decl.u.DeclarationRange.First = 0; + decl.u.DeclarationRange.Last = 0; + ti += tgsi_build_full_declaration + ( + &decl, + &tokens[ti], + header, + max_tokens - ti + ); + + /* Declare sampler */ + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_SAMPLER; + decl.u.DeclarationRange.First = 0; + decl.u.DeclarationRange.Last = 0; + ti += tgsi_build_full_declaration + ( + &decl, + &tokens[ti], + header, + max_tokens - ti + ); + + /* TEX instruction */ + /* tex2d t0, i0, s0 */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_TEX; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_TEMPORARY; + inst.FullDstRegisters[0].DstRegister.Index = 0; + inst.Instruction.NumSrcRegs = 2; + inst.InstructionExtTexture.Texture = TGSI_TEXTURE_2D; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_INPUT; + inst.FullSrcRegisters[0].SrcRegister.Index = 0; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_SAMPLER; + inst.FullSrcRegisters[1].SrcRegister.Index = 0; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + /* SUB instruction */ + /* sub t0, t0, c0 */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_SUB; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_TEMPORARY; + inst.FullDstRegisters[0].DstRegister.Index = 0; + inst.Instruction.NumSrcRegs = 2; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_TEMPORARY; + inst.FullSrcRegisters[0].SrcRegister.Index = 0; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_CONSTANT; + inst.FullSrcRegisters[1].SrcRegister.Index = 0; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + /* DP4 instruction */ + /* dp4 o0.x, t0, c1 + dp4 o0.y, t0, c2 + dp4 o0.z, t0, c3 + dp4 o0.w, t0, c4 */ + for (i = 0; i < 4; ++i) + { + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_DP4; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_OUTPUT; + inst.FullDstRegisters[0].DstRegister.Index = 0; + inst.FullDstRegisters[0].DstRegister.WriteMask = TGSI_WRITEMASK_X << i; + inst.Instruction.NumSrcRegs = 2; + inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_TEMPORARY; + inst.FullSrcRegisters[0].SrcRegister.Index = 0; + inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_CONSTANT; + inst.FullSrcRegisters[1].SrcRegister.Index = i + 1; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + } + + /* END instruction */ + inst = tgsi_default_full_instruction(); + inst.Instruction.Opcode = TGSI_OPCODE_END; + inst.Instruction.NumDstRegs = 0; + inst.Instruction.NumSrcRegs = 0; + ti += tgsi_build_full_instruction + ( + &inst, + &tokens[ti], + header, + max_tokens - ti + ); + + fs.tokens = tokens; + + context->states.csc.fragment_shader = pipe->create_fs_state(pipe, &fs); + + return 0; +} + +static int vlCreateDataBufsCSC(struct VL_CONTEXT *context) +{ + struct pipe_context *pipe; + + assert(context); + + pipe = context->pipe; + + /* + Create our vertex buffer and vertex buffer element + VB contains 4 vertices that render a quad covering the entire window + to display a rendered surface + Quad is rendered as a tri strip + */ + context->states.csc.vertex_bufs[0].pitch = sizeof(struct VL_VERTEX2F); + context->states.csc.vertex_bufs[0].max_index = 3; + context->states.csc.vertex_bufs[0].buffer_offset = 0; + context->states.csc.vertex_bufs[0].buffer = pipe->winsys->buffer_create + ( + pipe->winsys, + 1, + PIPE_BUFFER_USAGE_VERTEX, + sizeof(struct VL_VERTEX2F) * 4 + ); + + memcpy + ( + pipe->winsys->buffer_map(pipe->winsys, context->states.csc.vertex_bufs[0].buffer, PIPE_BUFFER_USAGE_CPU_WRITE), + vl_surface_vertex_positions, + sizeof(struct VL_VERTEX2F) * 4 + ); + + pipe->winsys->buffer_unmap(pipe->winsys, context->states.csc.vertex_bufs[0].buffer); + + context->states.csc.vertex_buf_elems[0].src_offset = 0; + context->states.csc.vertex_buf_elems[0].vertex_buffer_index = 0; + context->states.csc.vertex_buf_elems[0].nr_components = 2; + context->states.csc.vertex_buf_elems[0].src_format = PIPE_FORMAT_R32G32_FLOAT; + + /* + Create our texcoord buffer and texcoord buffer element + Texcoord buffer contains the TCs for mapping the rendered surface to the 4 vertices + */ + context->states.csc.vertex_bufs[1].pitch = sizeof(struct VL_TEXCOORD2F); + context->states.csc.vertex_bufs[1].max_index = 3; + context->states.csc.vertex_bufs[1].buffer_offset = 0; + context->states.csc.vertex_bufs[1].buffer = pipe->winsys->buffer_create + ( + pipe->winsys, + 1, + PIPE_BUFFER_USAGE_VERTEX, + sizeof(struct VL_TEXCOORD2F) * 4 + ); + + memcpy + ( + pipe->winsys->buffer_map(pipe->winsys, context->states.csc.vertex_bufs[1].buffer, PIPE_BUFFER_USAGE_CPU_WRITE), + vl_surface_texcoords, + sizeof(struct VL_TEXCOORD2F) * 4 + ); + + pipe->winsys->buffer_unmap(pipe->winsys, context->states.csc.vertex_bufs[1].buffer); + + context->states.csc.vertex_buf_elems[1].src_offset = 0; + context->states.csc.vertex_buf_elems[1].vertex_buffer_index = 1; + context->states.csc.vertex_buf_elems[1].nr_components = 2; + context->states.csc.vertex_buf_elems[1].src_format = PIPE_FORMAT_R32G32_FLOAT; + + /* + Create our fragment shader's constant buffer + Const buffer contains the color conversion matrix and bias vectors + */ + context->states.csc.fs_const_buf.size = sizeof(struct VL_CSC_FS_CONSTS); + context->states.csc.fs_const_buf.buffer = pipe->winsys->buffer_create + ( + pipe->winsys, + 1, + PIPE_BUFFER_USAGE_CONSTANT, + context->states.csc.fs_const_buf.size + ); + + /* + TODO: Refactor this into a seperate function, + allow changing the csc matrix at runtime to switch between regular & full versions + */ + memcpy + ( + pipe->winsys->buffer_map(pipe->winsys, context->states.csc.fs_const_buf.buffer, PIPE_BUFFER_USAGE_CPU_WRITE), + &vl_csc_fs_consts_601, + sizeof(struct VL_CSC_FS_CONSTS) + ); + + pipe->winsys->buffer_unmap(pipe->winsys, context->states.csc.fs_const_buf.buffer); + + return 0; +} + +static int vlInitCSC(struct VL_CONTEXT *context) +{ + struct pipe_context *pipe; + struct pipe_sampler_state sampler; + + assert(context); + + pipe = context->pipe; + + /* Delay creating the FB until vlPutSurface() so we know window size */ + context->states.csc.framebuffer.num_cbufs = 1; + context->states.csc.framebuffer.cbufs[0] = NULL; + context->states.csc.framebuffer.zsbuf = NULL; + + 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.prefilter = ;*/ + /*sampler.shadow_ambient = ;*/ + /*sampler.lod_bias = ;*/ + /*sampler.min_lod = ;*/ + /*sampler.max_lod = ;*/ + /*sampler.border_color[i] = ;*/ + /*sampler.max_anisotropy = ;*/ + context->states.csc.sampler = pipe->create_sampler_state(pipe, &sampler); + + vlCreateVertexShaderCSC(context); + vlCreateFragmentShaderCSC(context); + vlCreateDataBufsCSC(context); + + return 0; +} + +static int vlDestroyCSC(struct VL_CONTEXT *context) +{ + assert(context); + + /* + Since we create the final FB when we display our first surface, + it may not be created if vlPutSurface() is never called + */ + if (context->states.csc.framebuffer.cbufs[0]) + context->pipe->winsys->surface_release(context->pipe->winsys, &context->states.csc.framebuffer.cbufs[0]); + context->pipe->delete_sampler_state(context->pipe, context->states.csc.sampler); + context->pipe->delete_vs_state(context->pipe, context->states.csc.vertex_shader); + context->pipe->delete_fs_state(context->pipe, context->states.csc.fragment_shader); + context->pipe->winsys->buffer_destroy(context->pipe->winsys, context->states.csc.vertex_bufs[0].buffer); + context->pipe->winsys->buffer_destroy(context->pipe->winsys, context->states.csc.vertex_bufs[1].buffer); + context->pipe->winsys->buffer_destroy(context->pipe->winsys, context->states.csc.fs_const_buf.buffer); + + return 0; +} + +static int vlInitCommon(struct VL_CONTEXT *context) +{ + struct pipe_context *pipe; + struct pipe_rasterizer_state rast; + struct pipe_blend_state blend; + struct pipe_depth_stencil_alpha_state dsa; + unsigned int i; + + assert(context); + + pipe = context->pipe; + + rast.flatshade = 1; + 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.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; + /* Don't need clipping, but viewport mapping done here */ + rast.bypass_clipping = 0; + rast.bypass_vs = 0; + rast.origin_lower_left = 0; + rast.line_width = 1; + rast.point_size = 1; + rast.offset_units = 1; + rast.offset_scale = 1; + /*rast.sprite_coord_mode[i] = ;*/ + context->states.common.raster = pipe->create_rasterizer_state(pipe, &rast); + pipe->bind_rasterizer_state(pipe, context->states.common.raster); + + 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; + context->states.common.blend = pipe->create_blend_state(pipe, &blend); + pipe->bind_blend_state(pipe, context->states.common.blend); + + dsa.depth.enabled = 0; + dsa.depth.writemask = 0; + dsa.depth.func = PIPE_FUNC_ALWAYS; + dsa.depth.occlusion_count = 0; + 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].value_mask = 0; + dsa.stencil[i].write_mask = 0; + } + dsa.alpha.enabled = 0; + dsa.alpha.func = PIPE_FUNC_ALWAYS; + dsa.alpha.ref = 0; + context->states.common.dsa = pipe->create_depth_stencil_alpha_state(pipe, &dsa); + pipe->bind_depth_stencil_alpha_state(pipe, context->states.common.dsa); + + return 0; +} + +static int vlDestroyCommon(struct VL_CONTEXT *context) +{ + assert(context); + + context->pipe->delete_blend_state(context->pipe, context->states.common.blend); + context->pipe->delete_rasterizer_state(context->pipe, context->states.common.raster); + context->pipe->delete_depth_stencil_alpha_state(context->pipe, context->states.common.dsa); + + return 0; +} + +static int vlInit(struct VL_CONTEXT *context) +{ + assert(context); + + vlInitCommon(context); + vlInitCSC(context); + vlInitMC(context); + vlInitIDCT(context); + + return 0; +} + +static int vlDestroy(struct VL_CONTEXT *context) +{ + assert(context); + + /* Must unbind shaders before we can delete them for some reason */ + context->pipe->bind_vs_state(context->pipe, NULL); + context->pipe->bind_fs_state(context->pipe, NULL); + + vlDestroyCommon(context); + vlDestroyCSC(context); + vlDestroyMC(context); + vlDestroyIDCT(context); + + return 0; +} + +int vlCreateContext +( + Display *display, + struct pipe_context *pipe, + unsigned int video_width, + unsigned int video_height, + enum VL_FORMAT video_format, + struct VL_CONTEXT **context +) +{ + struct VL_CONTEXT *ctx; + + assert(display); + assert(pipe); + assert(context); + + ctx = calloc(1, sizeof(struct VL_CONTEXT)); + + ctx->display = display; + ctx->pipe = pipe; + ctx->video_width = video_width; + ctx->video_height = video_height; + ctx->video_format = video_format; + + vlInit(ctx); + + /* Since we only change states in vlPutSurface() we need to start in render mode */ + vlBeginRender(ctx); + + *context = ctx; + + return 0; +} + +int vlDestroyContext(struct VL_CONTEXT *context) +{ + assert(context); + + vlDestroy(context); + + free(context); + + return 0; +} + +int vlBeginRender(struct VL_CONTEXT *context) +{ + struct pipe_context *pipe; + + assert(context); + + pipe = context->pipe; + + /* Frame buffer set in vlRender*Macroblock() */ + /* Shaders, samplers, textures, VBs, VB elements set in vlRender*Macroblock() */ + pipe->set_viewport_state(pipe, &context->states.mc.viewport); + pipe->set_constant_buffer(pipe, PIPE_SHADER_VERTEX, 0, &context->states.mc.vs_const_buf); + pipe->set_constant_buffer(pipe, PIPE_SHADER_FRAGMENT, 0, &context->states.mc.fs_const_buf); + + return 0; +} + +int vlEndRender(struct VL_CONTEXT *context) +{ + struct pipe_context *pipe; + + assert(context); + + pipe = context->pipe; + + pipe->set_framebuffer_state(pipe, &context->states.csc.framebuffer); + pipe->set_viewport_state(pipe, &context->states.csc.viewport); + pipe->bind_sampler_states(pipe, 1, (void**)&context->states.csc.sampler); + /* Source texture set in vlPutSurface() */ + pipe->bind_vs_state(pipe, context->states.csc.vertex_shader); + pipe->bind_fs_state(pipe, context->states.csc.fragment_shader); + pipe->set_vertex_buffers(pipe, 2, context->states.csc.vertex_bufs); + pipe->set_vertex_elements(pipe, 2, context->states.csc.vertex_buf_elems); + pipe->set_constant_buffer(pipe, PIPE_SHADER_FRAGMENT, 0, &context->states.csc.fs_const_buf); + + return 0; +} + diff --git a/src/gallium/state_trackers/g3dvl/vl_context.h b/src/gallium/state_trackers/g3dvl/vl_context.h new file mode 100644 index 00000000000..0aeba184ccb --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_context.h @@ -0,0 +1,73 @@ +#ifndef vl_context_h +#define vl_context_h + +#include +#include +#include "vl_types.h" + +struct pipe_context; + +struct VL_CONTEXT +{ + Display *display; + struct pipe_context *pipe; + unsigned int video_width; + unsigned int video_height; + enum VL_FORMAT video_format; + + struct + { + struct + { + struct pipe_rasterizer_state *raster; + struct pipe_depth_stencil_alpha_state *dsa; + struct pipe_blend_state *blend; + } common; + + struct + { + } idct; + + struct + { + struct pipe_viewport_state viewport; + struct pipe_framebuffer_state render_target; + struct pipe_sampler_state *samplers[5]; + struct pipe_texture *textures[5]; + struct pipe_shader_state *i_vs, *p_vs, *b_vs; + struct pipe_shader_state *i_fs, *p_fs, *b_fs; + struct pipe_vertex_buffer vertex_bufs[6]; + struct pipe_vertex_element vertex_buf_elems[6]; + struct pipe_constant_buffer vs_const_buf, fs_const_buf; + } mc; + + struct + { + struct pipe_viewport_state viewport; + struct pipe_framebuffer_state framebuffer; + struct pipe_sampler_state *sampler; + struct pipe_shader_state *vertex_shader, *fragment_shader; + struct pipe_vertex_buffer vertex_bufs[2]; + struct pipe_vertex_element vertex_buf_elems[2]; + struct pipe_constant_buffer fs_const_buf; + } csc; + } states; +}; + +int vlCreateContext +( + Display *display, + struct pipe_context *pipe, + unsigned int video_width, + unsigned int video_height, + enum VL_FORMAT video_format, + struct VL_CONTEXT **context +); + +int vlDestroyContext(struct VL_CONTEXT *context); + +int vlBeginRender(struct VL_CONTEXT *context); +int vlEndRender(struct VL_CONTEXT *context); + +#endif + diff --git a/src/gallium/state_trackers/g3dvl/vl_data.c b/src/gallium/state_trackers/g3dvl/vl_data.c new file mode 100644 index 00000000000..c04163276d8 --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_data.c @@ -0,0 +1,188 @@ +#include "vl_data.h" + +/* + * Represents 8 triangles (4 quads, 1 per block) in noormalized coords + * that render a macroblock. + * Need to be scaled to cover mbW*mbH macroblock pixels and translated into + * position on target surface. + */ +const struct VL_VERTEX2F vl_mb_vertex_positions[24] = +{ + {0.0f, 0.0f}, {0.0f, 0.5f}, {0.5f, 0.0f}, + {0.5f, 0.0f}, {0.0f, 0.5f}, {0.5f, 0.5f}, + + {0.5f, 0.0f}, {0.5f, 0.5f}, {1.0f, 0.0f}, + {1.0f, 0.0f}, {0.5f, 0.5f}, {1.0f, 0.5f}, + + {0.0f, 0.5f}, {0.0f, 1.0f}, {0.5f, 0.5f}, + {0.5f, 0.5f}, {0.0f, 1.0f}, {0.5f, 1.0f}, + + {0.5f, 0.5f}, {0.5f, 1.0f}, {1.0f, 0.5f}, + {1.0f, 0.5f}, {0.5f, 1.0f}, {1.0f, 1.0f} +}; + +/* + * Represents texcoords for the above for rendering 4 luma blocks arranged + * in a bW*(bH*4) texture. First luma block located at 0,0->bW,bH; second at + * 0,bH->bW,2bH; third at 0,2bH->bW,3bH; fourth at 0,3bH->bW,4bH. + */ +const struct VL_TEXCOORD2F vl_luma_texcoords[24] = +{ + {0.0f, 0.0f}, {0.0f, 0.25f}, {1.0f, 0.0f}, + {1.0f, 0.0f}, {0.0f, 0.25f}, {1.0f, 0.25f}, + + {0.0f, 0.25f}, {0.0f, 0.5f}, {1.0f, 0.25f}, + {1.0f, 0.25f}, {0.0f, 0.5f}, {1.0f, 0.5f}, + + {0.0f, 0.5f}, {0.0f, 0.75f}, {1.0f, 0.5f}, + {1.0f, 0.5f}, {0.0f, 0.75f}, {1.0f, 0.75f}, + + {0.0f, 0.75f}, {0.0f, 1.0f}, {1.0f, 0.75f}, + {1.0f, 0.75f}, {0.0f, 1.0f}, {1.0f, 1.0f} +}; + +/* + * Represents texcoords for the above for rendering 1 chroma block. + * Straight forward 0,0->1,1 mapping so we can reuse the MB pos vectors. + */ +const struct VL_TEXCOORD2F *vl_chroma_420_texcoords = (const struct VL_TEXCOORD2F*)vl_mb_vertex_positions; + +/* + * Represents texcoords for the above for rendering 2 chroma blocks arranged + * in a bW*(bH*2) texture. First chroma block located at 0,0->bW,bH; second at + * 0,bH->bW,2bH. We can render this with 0,0->1,1 mapping. + * Straight forward 0,0->1,1 mapping so we can reuse MB pos vectors. + */ +const struct VL_TEXCOORD2F *vl_chroma_422_texcoords = (const struct VL_TEXCOORD2F*)vl_mb_vertex_positions; + +/* + * Represents texcoords for the above for rendering 4 chroma blocks. + * Same case as 4 luma blocks. + */ +const struct VL_TEXCOORD2F *vl_chroma_444_texcoords = vl_luma_texcoords; + +/* + * Represents texcoords for the above for rendering a predicted macroblock. + * Straight forward 0,0->1,1 mapping so we can reuse MB pos vectors. + * Texcoords need to be translated to cover source macroblock on the + * past/future surface. + */ + const struct VL_TEXCOORD2F *vl_ref_surface_texcoords = (const struct VL_TEXCOORD2F*)vl_mb_vertex_positions; + +/* + * Represents 2 triangles in a strip in normalized coords. + * Used to render the surface onto the frame buffer. + */ +const struct VL_VERTEX2F vl_surface_vertex_positions[4] = +{ + {0.0f, 0.0f}, + {0.0f, 1.0f}, + {1.0f, 0.0f}, + {1.0f, 1.0f} +}; + +/* + * Represents texcoords for the above. We can use the position values directly. + */ +const struct VL_TEXCOORD2F *vl_surface_texcoords = (const struct VL_TEXCOORD2F*)vl_surface_vertex_positions; + +/* + * Used when rendering P and B macroblocks, multiplier is applied to the A channel, + * which is then added to the L channel, then the bias is subtracted from that to + * get back the differential. The differential is then added to the samples from the + * reference surface(s). + */ +const struct VL_MC_FS_CONSTS vl_mc_fs_consts = +{ + {256.0f, 256.0f, 256.0f, 0.0f}, + {256.0f / 255.0f, 256.0f / 255.0f, 256.0f / 255.0f, 0.0f} +}; + +/* + * Identity color conversion constants, for debugging + */ +const struct VL_CSC_FS_CONSTS vl_csc_fs_consts_identity = +{ + { + 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, 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 [16,235] + */ +const struct VL_CSC_FS_CONSTS vl_csc_fs_consts_601 = +{ + { + 0.0f, 0.501960784f, 0.501960784f, 0.0f + }, + { + 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] + */ +const struct VL_CSC_FS_CONSTS vl_csc_fs_consts_601_full = +{ + { + 0.062745098f, 0.501960784f, 0.501960784f, 0.0f + }, + { + 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] + */ +const struct VL_CSC_FS_CONSTS vl_csc_fs_consts_709 = +{ + { + 0.0f, 0.501960784f, 0.501960784f, 0.0f + }, + { + 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] + */ +const struct VL_CSC_FS_CONSTS vl_csc_fs_consts_709_full = +{ + { + 0.062745098f, 0.501960784f, 0.501960784f, 0.0f + }, + { + 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 + } +}; + diff --git a/src/gallium/state_trackers/g3dvl/vl_data.h b/src/gallium/state_trackers/g3dvl/vl_data.h new file mode 100644 index 00000000000..67a0a749909 --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_data.h @@ -0,0 +1,25 @@ +#ifndef vl_data_h +#define vl_data_h + +#include "vl_types.h" + +extern const struct VL_VERTEX2F vl_mb_vertex_positions[24]; +extern const struct VL_TEXCOORD2F vl_luma_texcoords[24]; +extern const struct VL_TEXCOORD2F *vl_chroma_420_texcoords; +extern const struct VL_TEXCOORD2F *vl_chroma_422_texcoords; +extern const struct VL_TEXCOORD2F *vl_chroma_444_texcoords; +extern const struct VL_TEXCOORD2F *vl_ref_surface_texcoords; + +extern const struct VL_VERTEX2F vl_surface_vertex_positions[4]; +extern const struct VL_TEXCOORD2F *vl_surface_texcoords; + +extern const struct VL_MC_FS_CONSTS vl_mc_fs_consts; + +extern const struct VL_CSC_FS_CONSTS vl_csc_fs_consts_identity; +extern const struct VL_CSC_FS_CONSTS vl_csc_fs_consts_601; +extern const struct VL_CSC_FS_CONSTS vl_csc_fs_consts_601_full; +extern const struct VL_CSC_FS_CONSTS vl_csc_fs_consts_709; +extern const struct VL_CSC_FS_CONSTS vl_csc_fs_consts_709_full; + +#endif + diff --git a/src/gallium/state_trackers/g3dvl/vl_defs.h b/src/gallium/state_trackers/g3dvl/vl_defs.h new file mode 100644 index 00000000000..e668a7a10e0 --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_defs.h @@ -0,0 +1,12 @@ +#ifndef vl_defs_h +#define vl_defs_h + +#define VL_BLOCK_WIDTH 8 +#define VL_BLOCK_HEIGHT 8 +#define VL_BLOCK_SIZE (VL_BLOCK_WIDTH * VL_BLOCK_HEIGHT) +#define VL_MACROBLOCK_WIDTH 16 +#define VL_MACROBLOCK_HEIGHT 16 +#define VL_MACROBLOCK_SIZE (VL_MACROBLOCK_WIDTH * VL_MACROBLOCK_HEIGHT) + +#endif + diff --git a/src/gallium/state_trackers/g3dvl/vl_surface.c b/src/gallium/state_trackers/g3dvl/vl_surface.c new file mode 100644 index 00000000000..e58e434dab1 --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_surface.c @@ -0,0 +1,539 @@ +#include "vl_surface.h" +#include +#include +#include +#include +#include +#include +#include "vl_context.h" +#include "vl_defs.h" + +static int vlGrabBlocks +( + struct VL_CONTEXT *context, + unsigned int coded_block_pattern, + enum VL_DCT_TYPE dct_type, + enum VL_SAMPLE_TYPE sample_type, + short *blocks +) +{ + struct pipe_surface *tex_surface; + short *texels; + unsigned int b, x, y, y2; + + assert(context); + assert(blocks); + + tex_surface = context->pipe->screen->get_tex_surface + ( + context->pipe->screen, + context->states.mc.textures[0], + 0, 0, 0, PIPE_BUFFER_USAGE_CPU_WRITE + ); + + texels = pipe_surface_map(tex_surface, 0); + + for (b = 0; b < 4; ++b) + { + if ((coded_block_pattern >> b) & 1) + { + if (dct_type == VL_DCT_FRAME_CODED) + { + if (sample_type == VL_FULL_SAMPLE) + { + for (y = VL_BLOCK_HEIGHT * b; y < VL_BLOCK_HEIGHT * (b + 1); ++y) + memcpy + ( + texels + y * tex_surface->pitch, + blocks + y * VL_BLOCK_WIDTH, + VL_BLOCK_WIDTH * 2 + ); + } + else + { + for (y = VL_BLOCK_HEIGHT * b; y < VL_BLOCK_HEIGHT * (b + 1); ++y) + for (x = 0; x < VL_BLOCK_WIDTH; ++x) + texels[y * tex_surface->pitch + x] = + blocks[y * VL_BLOCK_WIDTH + x] + 0x100; + } + } + else + { + if (sample_type == VL_FULL_SAMPLE) + { + for + ( + y = VL_BLOCK_HEIGHT * (b % 2), y2 = VL_BLOCK_HEIGHT * b; + y < VL_BLOCK_HEIGHT * ((b % 2) + 1); + y += 2, ++y2 + ) + memcpy + ( + texels + y * tex_surface->pitch, + blocks + y2 * VL_BLOCK_WIDTH, + VL_BLOCK_WIDTH * 2 + ); + for + ( + y = VL_BLOCK_HEIGHT * ((b % 2) + 2); + y < VL_BLOCK_HEIGHT * (((b % 2) + 2) + 1); + y += 2, ++y2 + ) + memcpy + ( + texels + y * tex_surface->pitch, + blocks + y2 * VL_BLOCK_WIDTH, + VL_BLOCK_WIDTH * 2 + ); + } + else + { + for + ( + y = VL_BLOCK_HEIGHT * (b % 2), y2 = VL_BLOCK_HEIGHT * b; + y < VL_BLOCK_HEIGHT * ((b % 2) + 1); + y += 2, ++y2 + ) + for (x = 0; x < VL_BLOCK_WIDTH; ++x) + texels[y * tex_surface->pitch + x] = + blocks[y2 * VL_BLOCK_WIDTH + x] + 0x100; + for + ( + y = VL_BLOCK_HEIGHT * ((b % 2) + 2); + y < VL_BLOCK_HEIGHT * (((b % 2) + 2) + 1); + y += 2, ++y2 + ) + for (x = 0; x < VL_BLOCK_WIDTH; ++x) + texels[y * tex_surface->pitch + x] = + blocks[y2 * VL_BLOCK_WIDTH + x] + 0x100; + } + } + } + else + { + for (y = VL_BLOCK_HEIGHT * b; y < VL_BLOCK_HEIGHT * (b + 1); ++y) + { + for (x = 0; x < VL_BLOCK_WIDTH; ++x) + texels[y * tex_surface->pitch + x] = 0x100; + } + } + } + + pipe_surface_unmap(tex_surface); + + /* TODO: Implement 422, 444 */ + for (b = 0; b < 2; ++b) + { + tex_surface = context->pipe->screen->get_tex_surface + ( + context->pipe->screen, + context->states.mc.textures[b + 1], + 0, 0, 0, PIPE_BUFFER_USAGE_CPU_WRITE + ); + + texels = pipe_surface_map(tex_surface, 0); + + if ((coded_block_pattern >> (b + 4)) & 1) + { + if (sample_type == VL_FULL_SAMPLE) + { + for (y = 0; y < tex_surface->height; ++y) + memcpy + ( + texels + y * tex_surface->pitch, + blocks + VL_BLOCK_SIZE * (b + 4) + y * VL_BLOCK_WIDTH, + VL_BLOCK_WIDTH * 2 + ); + } + else + { + for (y = 0; y < tex_surface->height; ++y) + for (x = 0; x < VL_BLOCK_WIDTH; ++x) + texels[y * tex_surface->pitch + x] = + blocks[VL_BLOCK_SIZE * (b + 4) + y * VL_BLOCK_WIDTH + x] + 0x100; + } + } + else + { + for (y = 0; y < tex_surface->height; ++y) + { + for (x = 0; x < VL_BLOCK_WIDTH; ++x) + texels[y * tex_surface->pitch + x] = 0x100; + } + } + + pipe_surface_unmap(tex_surface); + } + + return 0; +} + +int vlCreateSurface(struct VL_CONTEXT *context, struct VL_SURFACE **surface) +{ + struct pipe_context *pipe; + struct pipe_texture template; + struct VL_SURFACE *sfc; + + assert(context); + assert(surface); + + pipe = context->pipe; + + sfc = calloc(1, sizeof(struct VL_SURFACE)); + + sfc->context = context; + sfc->width = context->video_width; + sfc->height = context->video_height; + sfc->format = context->video_format; + + memset(&template, 0, sizeof(struct pipe_texture)); + template.target = PIPE_TEXTURE_2D; + template.format = PIPE_FORMAT_A8R8G8B8_UNORM; + template.last_level = 0; + template.width[0] = sfc->width; + template.height[0] = sfc->height; + template.depth[0] = 1; + template.compressed = 0; + template.cpp = 4; + + sfc->texture = pipe->screen->texture_create(pipe->screen, &template); + + *surface = sfc; + + return 0; +} + +int vlDestroySurface(struct VL_SURFACE *surface) +{ + assert(surface); + pipe_texture_release(&surface->texture); + free(surface); + + return 0; +} + +int vlRenderIMacroBlock +( + enum VL_PICTURE picture_type, + enum VL_FIELD_ORDER field_order, + unsigned int mbx, + unsigned int mby, + unsigned int coded_block_pattern, + enum VL_DCT_TYPE dct_type, + short *blocks, + struct VL_SURFACE *surface +) +{ + struct pipe_context *pipe; + struct VL_MC_VS_CONSTS *vscbdata; + + assert(blocks); + assert(surface); + + /* TODO: Implement interlaced rendering */ + /*assert(picture_type == VL_FRAME_PICTURE);*/ + if (picture_type != VL_FRAME_PICTURE) + { + /*fprintf(stderr, "field picture (I) unimplemented, ignoring\n");*/ + return 0; + } + + pipe = surface->context->pipe; + + vscbdata = pipe->winsys->buffer_map + ( + pipe->winsys, + surface->context->states.mc.vs_const_buf.buffer, + PIPE_BUFFER_USAGE_CPU_WRITE + ); + + vscbdata->scale.x = VL_MACROBLOCK_WIDTH / (float)surface->width; + vscbdata->scale.y = VL_MACROBLOCK_HEIGHT / (float)surface->height; + vscbdata->scale.z = 1.0f; + vscbdata->scale.w = 1.0f; + vscbdata->mb_pos_trans.x = (mbx * VL_MACROBLOCK_WIDTH) / (float)surface->width; + vscbdata->mb_pos_trans.y = (mby * VL_MACROBLOCK_HEIGHT) / (float)surface->height; + vscbdata->mb_pos_trans.z = 0.0f; + vscbdata->mb_pos_trans.w = 0.0f; + + pipe->winsys->buffer_unmap(pipe->winsys, surface->context->states.mc.vs_const_buf.buffer); + + vlGrabBlocks(surface->context, coded_block_pattern, dct_type, VL_FULL_SAMPLE, blocks); + + surface->context->states.mc.render_target.cbufs[0] = pipe->screen->get_tex_surface + ( + pipe->screen, + surface->texture, + 0, 0, 0, PIPE_BUFFER_USAGE_CPU_READ | PIPE_BUFFER_USAGE_CPU_WRITE + ); + pipe->set_framebuffer_state(pipe, &surface->context->states.mc.render_target); + pipe->set_sampler_textures(pipe, 3, surface->context->states.mc.textures); + pipe->bind_sampler_states(pipe, 3, (void**)surface->context->states.mc.samplers); + pipe->set_vertex_buffers(pipe, 4, surface->context->states.mc.vertex_bufs); + pipe->set_vertex_elements(pipe, 4, surface->context->states.mc.vertex_buf_elems); + pipe->bind_vs_state(pipe, surface->context->states.mc.i_vs); + pipe->bind_fs_state(pipe, surface->context->states.mc.i_fs); + + pipe->draw_arrays(pipe, PIPE_PRIM_TRIANGLES, 0, 24); + + return 0; +} + +int vlRenderPMacroBlock +( + enum VL_PICTURE picture_type, + enum VL_FIELD_ORDER field_order, + unsigned int mbx, + unsigned int mby, + enum VL_MC_TYPE mc_type, + struct VL_MOTION_VECTOR *motion_vector, + unsigned int coded_block_pattern, + enum VL_DCT_TYPE dct_type, + short *blocks, + struct VL_SURFACE *ref_surface, + struct VL_SURFACE *surface +) +{ + struct pipe_context *pipe; + struct VL_MC_VS_CONSTS *vscbdata; + + assert(motion_vectors); + assert(blocks); + assert(ref_surface); + assert(surface); + + /* TODO: Implement interlaced rendering */ + /*assert(picture_type == VL_FRAME_PICTURE);*/ + if (picture_type != VL_FRAME_PICTURE) + { + /*fprintf(stderr, "field picture (P) unimplemented, ignoring\n");*/ + return 0; + } + /* TODO: Implement field based motion compensation */ + /*assert(mc_type == VL_FRAME_MC);*/ + if (mc_type != VL_FRAME_MC) + { + /*fprintf(stderr, "field MC (P) unimplemented, ignoring\n");*/ + return 0; + } + + pipe = surface->context->pipe; + + vscbdata = pipe->winsys->buffer_map + ( + pipe->winsys, + surface->context->states.mc.vs_const_buf.buffer, + PIPE_BUFFER_USAGE_CPU_WRITE + ); + + vscbdata->scale.x = VL_MACROBLOCK_WIDTH / (float)surface->width; + vscbdata->scale.y = VL_MACROBLOCK_HEIGHT / (float)surface->height; + vscbdata->scale.z = 1.0f; + vscbdata->scale.w = 1.0f; + vscbdata->mb_pos_trans.x = (mbx * VL_MACROBLOCK_WIDTH) / (float)surface->width; + vscbdata->mb_pos_trans.y = (mby * VL_MACROBLOCK_HEIGHT) / (float)surface->height; + vscbdata->mb_pos_trans.z = 0.0f; + vscbdata->mb_pos_trans.w = 0.0f; + vscbdata->mb_tc_trans[0].x = (mbx * VL_MACROBLOCK_WIDTH + motion_vector->top_field.x * 0.5f) / (float)surface->width; + vscbdata->mb_tc_trans[0].y = (mby * VL_MACROBLOCK_HEIGHT + motion_vector->top_field.y * 0.5f) / (float)surface->height; + vscbdata->mb_tc_trans[0].z = 0.0f; + vscbdata->mb_tc_trans[0].w = 0.0f; + + pipe->winsys->buffer_unmap(pipe->winsys, surface->context->states.mc.vs_const_buf.buffer); + + vlGrabBlocks(surface->context, coded_block_pattern, dct_type, VL_DIFFERENCE_SAMPLE, blocks); + + surface->context->states.mc.render_target.cbufs[0] = pipe->screen->get_tex_surface + ( + pipe->screen, + surface->texture, + 0, 0, 0, PIPE_BUFFER_USAGE_CPU_READ | PIPE_BUFFER_USAGE_CPU_WRITE + ); + pipe->set_framebuffer_state(pipe, &surface->context->states.mc.render_target); + + surface->context->states.mc.textures[3] = ref_surface->texture; + pipe->set_sampler_textures(pipe, 4, surface->context->states.mc.textures); + pipe->bind_sampler_states(pipe, 4, (void**)surface->context->states.mc.samplers); + pipe->set_vertex_buffers(pipe, 5, surface->context->states.mc.vertex_bufs); + pipe->set_vertex_elements(pipe, 5, surface->context->states.mc.vertex_buf_elems); + pipe->bind_vs_state(pipe, surface->context->states.mc.p_vs); + pipe->bind_fs_state(pipe, surface->context->states.mc.p_fs); + + pipe->draw_arrays(pipe, PIPE_PRIM_TRIANGLES, 0, 24); + + return 0; +} + +int vlRenderBMacroBlock +( + enum VL_PICTURE picture_type, + enum VL_FIELD_ORDER field_order, + unsigned int mbx, + unsigned int mby, + enum VL_MC_TYPE mc_type, + struct VL_MOTION_VECTOR *motion_vector, + unsigned int coded_block_pattern, + enum VL_DCT_TYPE dct_type, + short *blocks, + struct VL_SURFACE *past_surface, + struct VL_SURFACE *future_surface, + struct VL_SURFACE *surface +) +{ + struct pipe_context *pipe; + struct VL_MC_VS_CONSTS *vscbdata; + + assert(motion_vectors); + assert(blocks); + assert(ref_surface); + assert(surface); + + /* TODO: Implement interlaced rendering */ + /*assert(picture_type == VL_FRAME_PICTURE);*/ + if (picture_type != VL_FRAME_PICTURE) + { + /*fprintf(stderr, "field picture (B) unimplemented, ignoring\n");*/ + return 0; + } + /* TODO: Implement field based motion compensation */ + /*assert(mc_type == VL_FRAME_MC);*/ + if (mc_type != VL_FRAME_MC) + { + /*fprintf(stderr, "field MC (B) unimplemented, ignoring\n");*/ + return 0; + } + + pipe = surface->context->pipe; + + vscbdata = pipe->winsys->buffer_map + ( + pipe->winsys, + surface->context->states.mc.vs_const_buf.buffer, + PIPE_BUFFER_USAGE_CPU_WRITE + ); + + vscbdata->scale.x = VL_MACROBLOCK_WIDTH / (float)surface->width; + vscbdata->scale.y = VL_MACROBLOCK_HEIGHT / (float)surface->height; + vscbdata->scale.z = 1.0f; + vscbdata->scale.w = 1.0f; + vscbdata->mb_pos_trans.x = (mbx * VL_MACROBLOCK_WIDTH) / (float)surface->width; + vscbdata->mb_pos_trans.y = (mby * VL_MACROBLOCK_HEIGHT) / (float)surface->height; + vscbdata->mb_pos_trans.z = 0.0f; + vscbdata->mb_pos_trans.w = 0.0f; + vscbdata->mb_tc_trans[0].x = (mbx * VL_MACROBLOCK_WIDTH + motion_vector[0].top_field.x * 0.5f) / (float)surface->width; + vscbdata->mb_tc_trans[0].y = (mby * VL_MACROBLOCK_HEIGHT + motion_vector[0].top_field.y * 0.5f) / (float)surface->height; + vscbdata->mb_tc_trans[0].z = 0.0f; + vscbdata->mb_tc_trans[0].w = 0.0f; + vscbdata->mb_tc_trans[1].x = (mbx * VL_MACROBLOCK_WIDTH + motion_vector[1].top_field.x * 0.5f) / (float)surface->width; + vscbdata->mb_tc_trans[1].y = (mby * VL_MACROBLOCK_HEIGHT + motion_vector[1].top_field.y * 0.5f) / (float)surface->height; + vscbdata->mb_tc_trans[1].z = 0.0f; + vscbdata->mb_tc_trans[1].w = 0.0f; + + pipe->winsys->buffer_unmap(pipe->winsys, surface->context->states.mc.vs_const_buf.buffer); + + vlGrabBlocks(surface->context, coded_block_pattern, dct_type, VL_DIFFERENCE_SAMPLE, blocks); + + surface->context->states.mc.render_target.cbufs[0] = pipe->screen->get_tex_surface + ( + pipe->screen, + surface->texture, + 0, 0, 0, PIPE_BUFFER_USAGE_CPU_READ | PIPE_BUFFER_USAGE_CPU_WRITE + ); + pipe->set_framebuffer_state(pipe, &surface->context->states.mc.render_target); + + surface->context->states.mc.textures[3] = past_surface->texture; + surface->context->states.mc.textures[4] = future_surface->texture; + pipe->set_sampler_textures(pipe, 5, surface->context->states.mc.textures); + pipe->bind_sampler_states(pipe, 5, (void**)surface->context->states.mc.samplers); + pipe->set_vertex_buffers(pipe, 6, surface->context->states.mc.vertex_bufs); + pipe->set_vertex_elements(pipe, 6, surface->context->states.mc.vertex_buf_elems); + pipe->bind_vs_state(pipe, surface->context->states.mc.b_vs); + pipe->bind_fs_state(pipe, surface->context->states.mc.b_fs); + + pipe->draw_arrays(pipe, PIPE_PRIM_TRIANGLES, 0, 24); + + return 0; +} + +int vlPutSurface +( + struct VL_SURFACE *surface, + Drawable drawable, + unsigned int srcx, + unsigned int srcy, + unsigned int srcw, + unsigned int srch, + unsigned int destx, + unsigned int desty, + unsigned int destw, + unsigned int desth, + enum VL_PICTURE picture_type +) +{ + unsigned int create_fb = 0; + struct pipe_context *pipe; + + assert(surface); + + pipe = surface->context->pipe; + + if (!surface->context->states.csc.framebuffer.cbufs[0]) + create_fb = 1; + else if + ( + surface->context->states.csc.framebuffer.width != destw || + surface->context->states.csc.framebuffer.height != desth + ) + { + pipe->winsys->surface_release + ( + pipe->winsys, + &surface->context->states.csc.framebuffer.cbufs[0] + ); + + create_fb = 1; + } + + if (create_fb) + { + surface->context->states.csc.viewport.scale[0] = destw; + surface->context->states.csc.viewport.scale[1] = desth; + surface->context->states.csc.viewport.scale[2] = 1; + surface->context->states.csc.viewport.scale[3] = 1; + surface->context->states.csc.viewport.translate[0] = 0; + surface->context->states.csc.viewport.translate[1] = 0; + surface->context->states.csc.viewport.translate[2] = 0; + surface->context->states.csc.viewport.translate[3] = 0; + + surface->context->states.csc.framebuffer.width = destw; + surface->context->states.csc.framebuffer.height = desth; + surface->context->states.csc.framebuffer.cbufs[0] = pipe->winsys->surface_alloc(pipe->winsys); + pipe->winsys->surface_alloc_storage + ( + pipe->winsys, + surface->context->states.csc.framebuffer.cbufs[0], + destw, + desth, + PIPE_FORMAT_A8R8G8B8_UNORM, + PIPE_BUFFER_USAGE_CPU_READ | PIPE_BUFFER_USAGE_CPU_WRITE, + 0 + ); + } + + vlEndRender(surface->context); + + pipe->set_sampler_textures(pipe, 1, &surface->texture); + pipe->draw_arrays(pipe, PIPE_PRIM_TRIANGLE_STRIP, 0, 4); + pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); + pipe->winsys->flush_frontbuffer + ( + pipe->winsys, + surface->context->states.csc.framebuffer.cbufs[0], + &drawable + ); + + vlBeginRender(surface->context); + + return 0; +} + diff --git a/src/gallium/state_trackers/g3dvl/vl_surface.h b/src/gallium/state_trackers/g3dvl/vl_surface.h new file mode 100644 index 00000000000..9f56b77e1e7 --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_surface.h @@ -0,0 +1,81 @@ +#ifndef vl_surface_h +#define vl_surface_h + +#include +#include "vl_types.h" + +struct pipe_texture; + +struct VL_SURFACE +{ + struct VL_CONTEXT *context; + unsigned int width; + unsigned int height; + enum VL_FORMAT format; + struct pipe_texture *texture; +}; + +int vlCreateSurface(struct VL_CONTEXT *context, struct VL_SURFACE **surface); + +int vlDestroySurface(struct VL_SURFACE *surface); + +int vlRenderIMacroBlock +( + enum VL_PICTURE picture_type, + enum VL_FIELD_ORDER field_order, + unsigned int mbx, + unsigned int mby, + unsigned int coded_block_pattern, + enum VL_DCT_TYPE dct_type, + short *blocks, + struct VL_SURFACE *surface +); + +int vlRenderPMacroBlock +( + enum VL_PICTURE picture_type, + enum VL_FIELD_ORDER field_order, + unsigned int mbx, + unsigned int mby, + enum VL_MC_TYPE mc_type, + struct VL_MOTION_VECTOR *motion_vector, + unsigned int coded_block_pattern, + enum VL_DCT_TYPE dct_type, + short *blocks, + struct VL_SURFACE *ref_surface, + struct VL_SURFACE *surface +); + +int vlRenderBMacroBlock +( + enum VL_PICTURE picture_type, + enum VL_FIELD_ORDER field_order, + unsigned int mbx, + unsigned int mby, + enum VL_MC_TYPE mc_type, + struct VL_MOTION_VECTOR *motion_vector, + unsigned int coded_block_pattern, + enum VL_DCT_TYPE dct_type, + short *blocks, + struct VL_SURFACE *past_surface, + struct VL_SURFACE *future_surface, + struct VL_SURFACE *surface +); + +int vlPutSurface +( + struct VL_SURFACE *surface, + Drawable drawable, + unsigned int srcx, + unsigned int srcy, + unsigned int srcw, + unsigned int srch, + unsigned int destx, + unsigned int desty, + unsigned int destw, + unsigned int desth, + enum VL_PICTURE picture_type +); + +#endif + diff --git a/src/gallium/state_trackers/g3dvl/vl_types.h b/src/gallium/state_trackers/g3dvl/vl_types.h new file mode 100644 index 00000000000..7040b745036 --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_types.h @@ -0,0 +1,88 @@ +#ifndef vl_types_h +#define vl_types_h + +enum VL_FORMAT +{ + VL_FORMAT_YCBCR_420, + VL_FORMAT_YCBCR_422, + VL_FORMAT_YCBCR_444 +}; + +enum VL_PICTURE +{ + VL_TOP_FIELD, + VL_BOTTOM_FIELD, + VL_FRAME_PICTURE +}; + +enum VL_FIELD_ORDER +{ + VL_FIELD_FIRST, + VL_FIELD_SECOND +}; + +enum VL_DCT_TYPE +{ + VL_DCT_FIELD_CODED, + VL_DCT_FRAME_CODED +}; + +enum VL_SAMPLE_TYPE +{ + VL_FULL_SAMPLE, + VL_DIFFERENCE_SAMPLE +}; + +enum VL_MC_TYPE +{ + VL_FIELD_MC, + VL_FRAME_MC +}; + +struct VL_VERTEX4F +{ + float x, y, z, w; +}; + +struct VL_VERTEX2F +{ + float x, y; +}; + +struct VL_TEXCOORD2F +{ + float s, t; +}; + +struct VL_MC_VS_CONSTS +{ + struct VL_VERTEX4F scale; + struct VL_VERTEX4F mb_pos_trans; + struct VL_VERTEX4F mb_tc_trans[2]; +}; + +struct VL_MC_FS_CONSTS +{ + struct VL_VERTEX4F multiplier; + struct VL_VERTEX4F bias; +}; + +struct VL_CSC_FS_CONSTS +{ + struct VL_VERTEX4F bias; + float matrix[16]; +}; + +struct VL_MOTION_VECTOR +{ + struct + { + int x, y; + } top_field, bottom_field; +}; + +struct VL_CONTEXT; +struct VL_SURFACE; + +#endif + diff --git a/src/gallium/winsys/g3dvl/xsp_winsys.c b/src/gallium/winsys/g3dvl/xsp_winsys.c new file mode 100644 index 00000000000..eb4c9085d6d --- /dev/null +++ b/src/gallium/winsys/g3dvl/xsp_winsys.c @@ -0,0 +1,256 @@ +#include "xsp_winsys.h" +#include +#include +#include +#include +#include +#include + +/* pipe_winsys implementation */ + +struct xsp_pipe_winsys +{ + struct pipe_winsys base; + Display *display; + XImage fbimage; +}; + +struct xsp_buffer +{ + struct pipe_buffer base; + boolean is_user_buffer; + void *data; + void *mapped_data; +}; + +static struct pipe_buffer* xsp_buffer_create(struct pipe_winsys *pws, unsigned alignment, unsigned usage, unsigned size) +{ + struct xsp_buffer *buffer; + + assert(pws); + + buffer = calloc(1, sizeof(struct xsp_buffer)); + buffer->base.refcount = 1; + buffer->base.alignment = alignment; + buffer->base.usage = usage; + buffer->base.size = size; + buffer->data = align_malloc(size, alignment); + + return (struct pipe_buffer*)buffer; +} + +static struct pipe_buffer* xsp_user_buffer_create(struct pipe_winsys *pws, void *data, unsigned size) +{ + struct xsp_buffer *buffer; + + assert(pws); + + buffer = calloc(1, sizeof(struct xsp_buffer)); + buffer->base.refcount = 1; + buffer->base.size = size; + buffer->is_user_buffer = TRUE; + buffer->data = data; + + return (struct pipe_buffer*)buffer; +} + +static void* xsp_buffer_map(struct pipe_winsys *pws, struct pipe_buffer *buffer, unsigned flags) +{ + struct xsp_buffer *xsp_buf = (struct xsp_buffer*)buffer; + + assert(pws); + assert(buffer); + + xsp_buf->mapped_data = xsp_buf->data; + return xsp_buf->mapped_data; +} + +static void xsp_buffer_unmap(struct pipe_winsys *pws, struct pipe_buffer *buffer) +{ + struct xsp_buffer *xsp_buf = (struct xsp_buffer*)buffer; + + assert(pws); + assert(buffer); + + xsp_buf->mapped_data = NULL; +} + +static void xsp_buffer_destroy(struct pipe_winsys *pws, struct pipe_buffer *buffer) +{ + struct xsp_buffer *xsp_buf = (struct xsp_buffer*)buffer; + + assert(pws); + assert(buffer); + + if (!xsp_buf->is_user_buffer) + align_free(xsp_buf->data); + + free(xsp_buf); +} + +static struct pipe_surface* xsp_surface_alloc(struct pipe_winsys *pws) +{ + struct pipe_surface *surface; + + assert(pws); + + surface = calloc(1, sizeof(struct pipe_surface)); + surface->refcount = 1; + surface->winsys = pws; + + return surface; +} + +static int xsp_surface_alloc_storage +( + struct pipe_winsys *pws, + struct pipe_surface *surface, + unsigned width, + unsigned height, + enum pipe_format format, + unsigned flags, + unsigned tex_usage +) +{ + const unsigned int ALIGNMENT = 1; + + assert(pws); + assert(surface); + + surface->width = width; + surface->height = height; + surface->format = format; + surface->cpp = pf_get_size(format); + surface->pitch = width; + surface->usage = flags; + surface->buffer = pws->buffer_create(pws, ALIGNMENT, PIPE_BUFFER_USAGE_PIXEL, surface->pitch * surface->cpp * height); + + return 0; +} + +static void xsp_surface_release(struct pipe_winsys *pws, struct pipe_surface **surface) +{ + struct pipe_surface *s; + + assert(pws); + assert(surface); + assert(*surface); + + s = *surface; + + s->refcount--; + + if (s->refcount == 0) + { + pipe_buffer_reference(pws, &s->buffer, NULL); + free(s); + } + + *surface = NULL; +} + +static void xsp_flush_frontbuffer(struct pipe_winsys *pws, struct pipe_surface *surface, void *context_private) +{ + struct xsp_pipe_winsys *xsp_winsys; + + assert(pws); + assert(surface); + assert(context_private); + + xsp_winsys = (struct xsp_pipe_winsys*)pws; + + xsp_winsys->fbimage.width = surface->width; + xsp_winsys->fbimage.height = surface->height; + xsp_winsys->fbimage.bytes_per_line = surface->width * (xsp_winsys->fbimage.bits_per_pixel >> 3); + xsp_winsys->fbimage.data = pipe_surface_map(surface, 0); + + XPutImage + ( + xsp_winsys->display, + *(Drawable*)context_private, + XDefaultGC(xsp_winsys->display, XDefaultScreen(xsp_winsys->display)), + &xsp_winsys->fbimage, + 0, + 0, + 0, + 0, + surface->width, + surface->height + ); + XFlush(xsp_winsys->display); + pipe_surface_unmap(surface); +} + +static const char* xsp_get_name(struct pipe_winsys *pws) +{ + assert(pws); + return "X11 SoftPipe"; +} + +/* softpipe_winsys implementation */ + +static boolean xsp_is_format_supported(struct softpipe_winsys *spws, enum pipe_format format) +{ + assert(spws); + + /* TODO: Test that 'format' is equal to our output window's format */ + return TRUE; +} + +/* Show starts here */ + +struct pipe_context* create_pipe_context(Display *display) +{ + struct xsp_pipe_winsys *xsp_winsys; + struct softpipe_winsys *sp_winsys; + struct pipe_screen *p_screen; + struct pipe_context *p_context; + + assert(display); + + xsp_winsys = calloc(1, sizeof(struct xsp_pipe_winsys)); + xsp_winsys->base.buffer_create = xsp_buffer_create; + xsp_winsys->base.user_buffer_create = xsp_user_buffer_create; + xsp_winsys->base.buffer_map = xsp_buffer_map; + xsp_winsys->base.buffer_unmap = xsp_buffer_unmap; + xsp_winsys->base.buffer_destroy = xsp_buffer_destroy; + xsp_winsys->base.surface_alloc = xsp_surface_alloc; + xsp_winsys->base.surface_alloc_storage = xsp_surface_alloc_storage; + xsp_winsys->base.surface_release = xsp_surface_release; + xsp_winsys->base.flush_frontbuffer = xsp_flush_frontbuffer; + xsp_winsys->base.get_name = xsp_get_name; + xsp_winsys->display = display; + + { + /* XXX: Can't use the returned XImage* directly, + since we don't have control over winsys destruction + and we wouldn't be able to free it */ + XImage *template = XCreateImage + ( + display, + XDefaultVisual(display, XDefaultScreen(display)), + XDefaultDepth(display, XDefaultScreen(display)), + ZPixmap, + 0, + NULL, + 0, /* Don't know the width and height until flush_frontbuffer */ + 0, + 32, + 0 + ); + + memcpy(&xsp_winsys->fbimage, template, sizeof(XImage)); + XInitImage(&xsp_winsys->fbimage); + + XDestroyImage(template); + } + + sp_winsys = calloc(1, sizeof(struct softpipe_winsys)); + sp_winsys->is_format_supported = xsp_is_format_supported; + + p_screen = softpipe_create_screen((struct pipe_winsys*)xsp_winsys); + p_context = softpipe_create(p_screen, (struct pipe_winsys*)xsp_winsys, sp_winsys); + + return p_context; +} + diff --git a/src/gallium/winsys/g3dvl/xsp_winsys.h b/src/gallium/winsys/g3dvl/xsp_winsys.h new file mode 100644 index 00000000000..47a6ac6e251 --- /dev/null +++ b/src/gallium/winsys/g3dvl/xsp_winsys.h @@ -0,0 +1,11 @@ +#ifndef xsp_winsys_h +#define xsp_winsys_h + +#include + +struct pipe_context; + +struct pipe_context* create_pipe_context(Display *display); + +#endif + diff --git a/src/libXvMC/Makefile b/src/libXvMC/Makefile new file mode 100644 index 00000000000..b2f41e176d4 --- /dev/null +++ b/src/libXvMC/Makefile @@ -0,0 +1,33 @@ +TARGET = libXvMCg3dvl.so +SONAME = libXvMCg3dvl.so.1 +GALLIUMDIR = ../gallium +OBJECTS = block.o surface.o context.o subpicture.o attributes.o ${GALLIUMDIR}/winsys/g3dvl/xsp_winsys.o + +CFLAGS += -g -fPIC -Wall -Werror \ + -I${GALLIUMDIR}/state_trackers/g3dvl \ + -I${GALLIUMDIR}/winsys/g3dvl \ + -I${GALLIUMDIR}/include \ + -I${GALLIUMDIR}/auxiliary \ + -I${GALLIUMDIR}/drivers +LDFLAGS += -L${GALLIUMDIR}/state_trackers/g3dvl \ + -L${GALLIUMDIR}/drivers/softpipe \ + -L${GALLIUMDIR}/auxiliary/tgsi \ + -L${GALLIUMDIR}/auxiliary/draw \ + -L${GALLIUMDIR}/auxiliary/translate \ + -L${GALLIUMDIR}/auxiliary/cso_cache \ + -L${GALLIUMDIR}/auxiliary/util \ + -L${GALLIUMDIR}/auxiliary/rtasm +LIBS += -lg3dvl -lsoftpipe -ldraw -ltgsi -ltranslate -lrtasm -lcso_cache -lutil + +############################################# + +.PHONY = all clean + +all: ${TARGET} + +${TARGET}: ${OBJECTS} + $(CC) ${LDFLAGS} -shared -Wl,-soname,${SONAME} -o $@ $^ ${LIBS} + +clean: + rm -rf ${OBJECTS} ${TARGET} + diff --git a/src/libXvMC/attributes.c b/src/libXvMC/attributes.c new file mode 100644 index 00000000000..674524b8b82 --- /dev/null +++ b/src/libXvMC/attributes.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +XvAttribute* XvMCQueryAttributes(Display *display, XvMCContext *context, int *number) +{ + return NULL; +} + +Status XvMCSetAttribute(Display *display, XvMCContext *context, Atom attribute, int value) +{ + return BadImplementation; +} + +Status XvMCGetAttribute(Display *display, XvMCContext *context, Atom attribute, int *value) +{ + return BadImplementation; +} + diff --git a/src/libXvMC/block.c b/src/libXvMC/block.c new file mode 100644 index 00000000000..b56348d4645 --- /dev/null +++ b/src/libXvMC/block.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include + +/* + * XvMC defines 64 element blocks (8x8 elements). + * Elements are 8 bits when they represent color values, + * 9 bits when they reprecent DCT coefficients, we + * store them in 2 bytes in either case. DCT coefficients + * can be signed or unsigned, at our option. + */ +#define BLOCK_SIZE (64 * 2) + +Status XvMCCreateBlocks(Display *display, XvMCContext *context, unsigned int num_blocks, XvMCBlockArray *blocks) +{ + struct vl_context *vl_ctx; + + assert(display); + + if (!context) + return XvMCBadContext; + if (num_blocks == 0) + return BadValue; + + assert(blocks); + + vl_ctx = context->privData; + assert(display == vl_ctx->display); + + blocks->context_id = context->context_id; + blocks->num_blocks = num_blocks; + blocks->blocks = malloc(BLOCK_SIZE * num_blocks); + /* Since we don't have a VL type for blocks, set privData to the display so we can catch mismatches */ + blocks->privData = display; + + return Success; +} + +Status XvMCDestroyBlocks(Display *display, XvMCBlockArray *blocks) +{ + assert(display); + assert(blocks); + assert(display == blocks->privData); + free(blocks->blocks); + + return Success; +} + +Status XvMCCreateMacroBlocks(Display *display, XvMCContext *context, unsigned int num_blocks, XvMCMacroBlockArray *blocks) +{ + struct vl_context *vl_ctx; + + assert(display); + + if (!context) + return XvMCBadContext; + if (num_blocks == 0) + return BadValue; + + assert(blocks); + + vl_ctx = context->privData; + assert(display == vl_ctx->display); + + blocks->context_id = context->context_id; + blocks->num_blocks = num_blocks; + blocks->macro_blocks = malloc(sizeof(XvMCMacroBlock) * num_blocks); + /* Since we don't have a VL type for blocks, set privData to the display so we can catch mismatches */ + blocks->privData = display; + + return Success; +} + +Status XvMCDestroyMacroBlocks(Display *display, XvMCMacroBlockArray *blocks) +{ + assert(display); + assert(blocks); + assert(display == blocks->privData); + free(blocks->macro_blocks); + + return Success; +} + diff --git a/src/libXvMC/context.c b/src/libXvMC/context.c new file mode 100644 index 00000000000..c835a6acf7a --- /dev/null +++ b/src/libXvMC/context.c @@ -0,0 +1,154 @@ +#include +#include +#include +#include +#include + +static Status Validate(Display *display, XvPortID port, int surface_type_id, unsigned int width, unsigned int height, int flags, int *chroma_format) +{ + unsigned int found_port = 0; + unsigned int found_surface = 0; + XvAdaptorInfo *adaptor_info; + unsigned int num_adaptors; + int num_types; + unsigned int max_width, max_height; + Status ret; + unsigned int i, j, k; + + assert(display && chroma_format); + + ret = XvQueryAdaptors(display, XDefaultRootWindow(display), &num_adaptors, &adaptor_info); + if (ret != Success) + return ret; + + /* Scan through all adaptors looking for this port and surface */ + for (i = 0; i < num_adaptors && !found_port; ++i) + { + /* Scan through all ports of this adaptor looking for our port */ + for (j = 0; j < adaptor_info[i].num_ports && !found_port; ++j) + { + /* If this is our port, scan through all its surfaces looking for our surface */ + if (adaptor_info[i].base_id + j == port) + { + XvMCSurfaceInfo *surface_info; + + found_port = 1; + surface_info = XvMCListSurfaceTypes(display, adaptor_info[i].base_id, &num_types); + + if (surface_info) + { + for (k = 0; k < num_types && !found_surface; ++k) + { + if (surface_info[k].surface_type_id == surface_type_id) + { + found_surface = 1; + max_width = surface_info[k].max_width; + max_height = surface_info[k].max_height; + *chroma_format = surface_info[k].chroma_format; + } + } + + XFree(surface_info); + } + else + { + XvFreeAdaptorInfo(adaptor_info); + return BadAlloc; + } + } + } + } + + XvFreeAdaptorInfo(adaptor_info); + + if (!found_port) + return XvBadPort; + if (!found_surface) + return BadMatch; + if (width > max_width || height > max_height) + return BadValue; + if (flags != XVMC_DIRECT && flags != 0) + return BadValue; + + return Success; +} + +static enum VL_FORMAT FormatToVL(int xvmc_format) +{ + enum VL_FORMAT vl_format; + + switch (xvmc_format) + { + case XVMC_CHROMA_FORMAT_420: + { + vl_format = VL_FORMAT_YCBCR_420; + break; + } + case XVMC_CHROMA_FORMAT_422: + { + vl_format = VL_FORMAT_YCBCR_422; + break; + } + case XVMC_CHROMA_FORMAT_444: + { + vl_format = VL_FORMAT_YCBCR_444; + break; + } + default: + assert(0); + } + + return vl_format; +} + +Status XvMCCreateContext(Display *display, XvPortID port, int surface_type_id, int width, int height, int flags, XvMCContext *context) +{ + int chroma_format; + Status ret; + struct VL_CONTEXT *vl_ctx; + struct pipe_context *pipe; + + assert(display); + + if (!context) + return XvMCBadContext; + + ret = Validate(display, port, surface_type_id, width, height, flags, &chroma_format); + if (ret != Success) + return ret; + + pipe = create_pipe_context(display); + + assert(pipe); + + vlCreateContext(display, pipe, width, height, FormatToVL(chroma_format), &vl_ctx); + + context->context_id = XAllocID(display); + context->surface_type_id = surface_type_id; + context->width = width; + context->height = height; + context->flags = flags; + context->port = port; + context->privData = vl_ctx; + + return Success; +} + +Status XvMCDestroyContext(Display *display, XvMCContext *context) +{ + struct VL_CONTEXT *vl_ctx; + + assert(display); + + if (!context) + return XvMCBadContext; + + vl_ctx = context->privData; + + assert(display == vl_ctx->display); + + vlDestroyContext(vl_ctx); + + return Success; +} + diff --git a/src/libXvMC/subpicture.c b/src/libXvMC/subpicture.c new file mode 100644 index 00000000000..38d93438334 --- /dev/null +++ b/src/libXvMC/subpicture.c @@ -0,0 +1,110 @@ +#include +#include +#include +#include + +Status XvMCCreateSubpicture +( + Display *display, + XvMCContext *context, + XvMCSubpicture *subpicture, + unsigned short width, + unsigned short height, + int xvimage_id +) +{ + return BadImplementation; +} + +Status XvMCClearSubpicture +( + Display *display, + XvMCSubpicture *subpicture, + short x, + short y, + unsigned short width, + unsigned short height, + unsigned int color +) +{ + return BadImplementation; +} + +Status XvMCCompositeSubpicture +( + Display *display, + XvMCSubpicture *subpicture, + XvImage *image, + short srcx, + short srcy, + unsigned short width, + unsigned short height, + short dstx, + short dsty +) +{ + return BadImplementation; +} + +Status XvMCDestroySubpicture(Display *display, XvMCSubpicture *subpicture) +{ + return BadImplementation; +} + +Status XvMCSetSubpicturePalette(Display *display, XvMCSubpicture *subpicture, unsigned char *palette) +{ + return BadImplementation; +} + +Status XvMCBlendSubpicture +( + Display *display, + 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 +) +{ + return BadImplementation; +} + +Status XvMCBlendSubpicture2 +( + Display *display, + 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 +) +{ + return BadImplementation; +} + +Status XvMCSyncSubpicture(Display *display, XvMCSubpicture *subpicture) +{ + return BadImplementation; +} + +Status XvMCFlushSubpicture(Display *display, XvMCSubpicture *subpicture) +{ + return BadImplementation; +} + +Status XvMCGetSubpictureStatus(Display *display, XvMCSubpicture *subpicture, int *status) +{ + return BadImplementation; +} + diff --git a/src/libXvMC/surface.c b/src/libXvMC/surface.c new file mode 100644 index 00000000000..e4602d82042 --- /dev/null +++ b/src/libXvMC/surface.c @@ -0,0 +1,373 @@ +#include +#include +#include +#include +#include + +static enum VL_PICTURE PictureToVL(int xvmc_pic) +{ + enum VL_PICTURE vl_pic; + + switch (xvmc_pic) + { + case XVMC_TOP_FIELD: + { + vl_pic = VL_TOP_FIELD; + break; + } + case XVMC_BOTTOM_FIELD: + { + vl_pic = VL_BOTTOM_FIELD; + break; + } + case XVMC_FRAME_PICTURE: + { + vl_pic = VL_FRAME_PICTURE; + break; + } + default: + assert(0); + } + + return vl_pic; +} + +Status XvMCCreateSurface(Display *display, XvMCContext *context, XvMCSurface *surface) +{ + struct VL_CONTEXT *vl_ctx; + struct VL_SURFACE *vl_sfc; + + assert(display); + + if (!context) + return XvMCBadContext; + if (!surface) + return XvMCBadSurface; + + vl_ctx = context->privData; + + assert(display == vl_ctx->display); + + vlCreateSurface(vl_ctx, &vl_sfc); + + surface->surface_id = XAllocID(display); + surface->context_id = context->context_id; + surface->surface_type_id = context->surface_type_id; + surface->width = context->width; + surface->height = context->height; + surface->privData = vl_sfc; + + return Success; +} + +Status XvMCRenderSurface +( + Display *display, + 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 VL_CONTEXT *vl_ctx; + struct VL_SURFACE *target_vl_surface; + struct VL_SURFACE *past_vl_surface; + struct VL_SURFACE *future_vl_surface; + unsigned int i; + + assert(display); + + if (!context) + return XvMCBadContext; + if (!target_surface) + return XvMCBadSurface; + + if + ( + picture_structure != XVMC_TOP_FIELD && + picture_structure != XVMC_BOTTOM_FIELD && + picture_structure != XVMC_FRAME_PICTURE + ) + return BadValue; + if (future_surface && !past_surface) + return BadMatch; + + vl_ctx = context->privData; + + assert(display == vl_ctx->display); + + target_vl_surface = target_surface->privData; + past_vl_surface = past_surface ? past_surface->privData : NULL; + future_vl_surface = future_surface ? future_surface->privData : NULL; + + assert(vl_ctx == target_vl_surface->context); + assert(!past_vl_surface || vl_ctx == past_vl_surface->context); + assert(!future_vl_surface || vl_ctx == future_vl_surface->context); + + 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); + + for (i = first_macroblock; i < first_macroblock + num_macroblocks; ++i) + if (macroblocks->macro_blocks[i].macroblock_type & XVMC_MB_TYPE_INTRA) + vlRenderIMacroBlock + ( + PictureToVL(picture_structure), + flags == XVMC_SECOND_FIELD ? VL_FIELD_SECOND : VL_FIELD_FIRST, + macroblocks->macro_blocks[i].x, + macroblocks->macro_blocks[i].y, + macroblocks->macro_blocks[i].coded_block_pattern, + macroblocks->macro_blocks[i].dct_type == XVMC_DCT_TYPE_FIELD ? VL_DCT_FIELD_CODED : VL_DCT_FRAME_CODED, + blocks->blocks + (macroblocks->macro_blocks[i].index * 64), + target_vl_surface + ); + else if + ( + (macroblocks->macro_blocks[i].macroblock_type & (XVMC_MB_TYPE_MOTION_FORWARD | XVMC_MB_TYPE_MOTION_BACKWARD)) + == XVMC_MB_TYPE_MOTION_FORWARD + ) + { + struct VL_MOTION_VECTOR motion_vector = + { + { + macroblocks->macro_blocks[i].PMV[0][0][0], + macroblocks->macro_blocks[i].PMV[0][0][1], + }, + { + macroblocks->macro_blocks[i].PMV[1][0][0], + macroblocks->macro_blocks[i].PMV[1][0][1], + } + }; + + vlRenderPMacroBlock + ( + PictureToVL(picture_structure), + flags == XVMC_SECOND_FIELD ? VL_FIELD_SECOND : VL_FIELD_FIRST, + macroblocks->macro_blocks[i].x, + macroblocks->macro_blocks[i].y, + macroblocks->macro_blocks[i].motion_type == XVMC_PREDICTION_FRAME ? VL_FIELD_MC : VL_FRAME_MC, + &motion_vector, + macroblocks->macro_blocks[i].coded_block_pattern, + macroblocks->macro_blocks[i].dct_type == XVMC_DCT_TYPE_FIELD ? VL_DCT_FIELD_CODED : VL_DCT_FRAME_CODED, + blocks->blocks + (macroblocks->macro_blocks[i].index * 64), + past_vl_surface, + target_vl_surface + ); + } + else if + ( + (macroblocks->macro_blocks[i].macroblock_type & (XVMC_MB_TYPE_MOTION_FORWARD | XVMC_MB_TYPE_MOTION_BACKWARD)) + == XVMC_MB_TYPE_MOTION_BACKWARD + ) + { + struct VL_MOTION_VECTOR motion_vector = + { + { + macroblocks->macro_blocks[i].PMV[0][1][0], + macroblocks->macro_blocks[i].PMV[0][1][1], + }, + { + macroblocks->macro_blocks[i].PMV[1][1][0], + macroblocks->macro_blocks[i].PMV[1][1][1], + } + }; + + vlRenderPMacroBlock + ( + PictureToVL(picture_structure), + flags == XVMC_SECOND_FIELD ? VL_FIELD_SECOND : VL_FIELD_FIRST, + macroblocks->macro_blocks[i].x, + macroblocks->macro_blocks[i].y, + macroblocks->macro_blocks[i].motion_type == XVMC_PREDICTION_FRAME ? VL_FIELD_MC : VL_FRAME_MC, + &motion_vector, + macroblocks->macro_blocks[i].coded_block_pattern, + macroblocks->macro_blocks[i].dct_type == XVMC_DCT_TYPE_FIELD ? VL_DCT_FIELD_CODED : VL_DCT_FRAME_CODED, + blocks->blocks + (macroblocks->macro_blocks[i].index * 64), + future_vl_surface, + target_vl_surface + ); + } + else if + ( + (macroblocks->macro_blocks[i].macroblock_type & (XVMC_MB_TYPE_MOTION_FORWARD | XVMC_MB_TYPE_MOTION_BACKWARD)) + == (XVMC_MB_TYPE_MOTION_FORWARD | XVMC_MB_TYPE_MOTION_BACKWARD) + ) + { + struct VL_MOTION_VECTOR motion_vector[2] = + { + { + { + macroblocks->macro_blocks[i].PMV[0][0][0], + macroblocks->macro_blocks[i].PMV[0][0][1], + }, + { + macroblocks->macro_blocks[i].PMV[1][0][0], + macroblocks->macro_blocks[i].PMV[1][0][1], + } + }, + { + { + macroblocks->macro_blocks[i].PMV[0][1][0], + macroblocks->macro_blocks[i].PMV[0][1][1], + }, + { + macroblocks->macro_blocks[i].PMV[1][1][0], + macroblocks->macro_blocks[i].PMV[1][1][1], + } + } + }; + + vlRenderBMacroBlock + ( + PictureToVL(picture_structure), + flags == XVMC_SECOND_FIELD ? VL_FIELD_SECOND : VL_FIELD_FIRST, + macroblocks->macro_blocks[i].x, + macroblocks->macro_blocks[i].y, + macroblocks->macro_blocks[i].motion_type == XVMC_PREDICTION_FRAME ? VL_FIELD_MC : VL_FRAME_MC, + motion_vector, + macroblocks->macro_blocks[i].coded_block_pattern, + macroblocks->macro_blocks[i].dct_type == XVMC_DCT_TYPE_FIELD ? VL_DCT_FIELD_CODED : VL_DCT_FRAME_CODED, + blocks->blocks + (macroblocks->macro_blocks[i].index * 64), + past_vl_surface, + future_vl_surface, + target_vl_surface + ); + } + else + fprintf(stderr, "Unrecognized macroblock\n"); + + return Success; +} + +Status XvMCFlushSurface(Display *display, XvMCSurface *surface) +{ + /* TODO: Check display & surface match */ + return BadImplementation; +} + +Status XvMCSyncSurface(Display *display, XvMCSurface *surface) +{ + /* TODO: Check display & surface match */ + return BadImplementation; +} + +Status XvMCPutSurface +( + Display *display, + 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 +) +{ + Window root; + int x, y; + unsigned int width, height; + unsigned int border_width; + unsigned int depth; + struct VL_SURFACE *vl_sfc; + + assert(display); + + if (!surface) + return XvMCBadSurface; + + if (XGetGeometry(display, drawable, &root, &x, &y, &width, &height, &border_width, &depth) == BadDrawable) + return BadDrawable; + + assert(flags == XVMC_TOP_FIELD || flags == XVMC_BOTTOM_FIELD || flags == XVMC_FRAME_PICTURE); + + /* TODO: Correct for negative srcx,srcy & destx,desty by clipping */ + + assert(srcx + srcw - 1 < surface->width); + assert(srcy + srch - 1 < surface->height); + assert(destx + destw - 1 < width); + assert(desty + desth - 1 < height); + + vl_sfc = surface->privData; + + vlPutSurface(vl_sfc, drawable, srcx, srcy, srcw, srch, destx, desty, destw, desth, PictureToVL(flags)); + + return Success; +} + +Status XvMCGetSurfaceStatus(Display *display, XvMCSurface *surface, int *status) +{ + struct VL_CONTEXT *vl_ctx; + struct VL_SURFACE *vl_sfc; + + assert(display); + + if (!surface) + return XvMCBadSurface; + + assert(status); + + vl_sfc = surface->privData; + vl_ctx = vl_sfc->context; + + assert(display == vl_ctx->display); + + /* TODO */ + *status = 0; + + return BadImplementation; +} + +Status XvMCDestroySurface(Display *display, XvMCSurface *surface) +{ + struct VL_CONTEXT *vl_ctx; + struct VL_SURFACE *vl_sfc; + + assert(display); + + if (!surface) + return XvMCBadSurface; + + vl_sfc = surface->privData; + vl_ctx = vl_sfc->context; + + assert(display == vl_ctx->display); + + vlDestroySurface(vl_sfc); + + return Success; +} + +Status XvMCHideSurface(Display *display, XvMCSurface *surface) +{ + struct VL_CONTEXT *vl_ctx; + struct VL_SURFACE *vl_sfc; + + assert(display); + + if (!surface) + return XvMCBadSurface; + + vl_sfc = surface->privData; + vl_ctx = vl_sfc->context; + + assert(display == vl_ctx->display); + + /* No op, only for overlaid rendering */ + + return Success; +} + diff --git a/src/libXvMC/tests/.gitignore b/src/libXvMC/tests/.gitignore new file mode 100644 index 00000000000..eb1ef8a0761 --- /dev/null +++ b/src/libXvMC/tests/.gitignore @@ -0,0 +1,5 @@ +test_context +test_surface +test_blocks +test_rendering + diff --git a/src/libXvMC/tests/Makefile b/src/libXvMC/tests/Makefile new file mode 100644 index 00000000000..2cbc97e88ba --- /dev/null +++ b/src/libXvMC/tests/Makefile @@ -0,0 +1,25 @@ +CFLAGS += -g -Wall -Werror +LDFLAGS += +LIBS += -lXvMCW -lXvMC -lXv + +############################################# + +.PHONY = all clean + +all: test_context test_surface test_blocks test_rendering + +test_context: test_context.o testlib.o + $(CC) ${LDFLAGS} -o $@ $^ ${LIBS} + +test_surface: test_surface.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} + +clean: + rm -rf *.o test_context test_surface test_blocks test_rendering + diff --git a/src/libXvMC/tests/test_blocks.c b/src/libXvMC/tests/test_blocks.c new file mode 100644 index 00000000000..0b895ee7737 --- /dev/null +++ b/src/libXvMC/tests/test_blocks.c @@ -0,0 +1,95 @@ +#include +#include +#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 too many blocks */ + /*assert(XvMCCreateBlocks(display, &context, 16384, &blocks) == BadAlloc);*/ + + /* Note: No XvMCBadBlock(s) error in spec */ + + /* 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 too many macroblocks */ + /*assert(XvMCCreateMacroBlocks(display, &context, 16384, ¯oblocks) == BadAlloc);*/ + + /* Note: No XvMCBadMacroBlock(s) error in spec */ + + /* 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/libXvMC/tests/test_context.c b/src/libXvMC/tests/test_context.c new file mode 100644 index 00000000000..22afb7ada4e --- /dev/null +++ b/src/libXvMC/tests/test_context.c @@ -0,0 +1,94 @@ +#include +#include +#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); + } + + /* Note: XvMCBadContext not a valid return for XvMCCreateContext in the XvMC API, but openChrome driver returns it */ + /* Note: Nvidia binary driver segfaults on NULL context, halts with debug output on bad port */ + + /* Test NULL context */ + assert(XvMCCreateContext(display, port_num, surface_type_id, width, height, XVMC_DIRECT, NULL) == XvMCBadContext); + /* Test invalid port */ + assert(XvMCCreateContext(display, port_num + 1, surface_type_id, width, height, XVMC_DIRECT, &context) == XvBadPort); + /* Test invalid surface */ + assert(XvMCCreateContext(display, port_num, surface_type_id + 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/libXvMC/tests/test_rendering.c b/src/libXvMC/tests/test_rendering.c new file mode 100644 index 00000000000..1914b1fb628 --- /dev/null +++ b/src/libXvMC/tests/test_rendering.c @@ -0,0 +1,153 @@ +#include +#include +#include +#include "testlib.h" + +int main(int argc, char **argv) +{ + const unsigned int width = 32, height = 32; + const unsigned int mwidth = width / 16, mheight = height / 16; + const unsigned int num_macroblocks = mwidth * mheight; + const unsigned int num_blocks = num_macroblocks * 6; + const unsigned int mc_types[2] = {XVMC_MOCOMP | XVMC_MPEG_2, XVMC_IDCT | XVMC_MPEG_2}; + + int quit = 0; + Display *display; + Window root, window; + Pixmap framebuffer; + XEvent event; + XvPortID port_num; + int surface_type_id; + unsigned int is_overlay, intra_unsigned; + int colorkey; + XvMCContext context; + XvMCSurface surface; + XvMCBlockArray blocks; + XvMCMacroBlockArray macroblocks; + unsigned int b, x, y; + + 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); + } + + root = XDefaultRootWindow(display); + window = XCreateSimpleWindow(display, root, 0, 0, width, height, 0, 0, colorkey); + framebuffer = XCreatePixmap(display, root, width, height, 24); + + XSelectInput(display, window, ExposureMask | KeyPressMask); + XMapWindow(display, window); + XSync(display, 0); + + assert(XvMCCreateContext(display, port_num, surface_type_id, width, height, XVMC_DIRECT, &context) == Success); + assert(XvMCCreateSurface(display, &context, &surface) == Success); + assert(XvMCCreateBlocks(display, &context, num_blocks, &blocks) == Success); + assert(XvMCCreateMacroBlocks(display, &context, num_macroblocks, ¯oblocks) == Success); + + for (b = 0; b < 6; ++b) + { + for (y = 0; y < 8; ++y) + { + for (x = 0; x < 8; ++x) + { + blocks.blocks[b * 64 + y * 8 + x] = 0xFFFF; + } + } + } + + for (y = 0; y < mheight; ++y) + { + for (x = 0; x < mwidth; ++x) + { + macroblocks.macro_blocks[y * mwidth + x].x = x; + macroblocks.macro_blocks[y * mwidth + x].y = y; + macroblocks.macro_blocks[y * mwidth + x].index = (y * mwidth + x) * 6; + macroblocks.macro_blocks[y * mwidth + x].macroblock_type = XVMC_MB_TYPE_INTRA; + macroblocks.macro_blocks[y * mwidth + x].coded_block_pattern = 0x3F; + macroblocks.macro_blocks[y * mwidth + x].dct_type = XVMC_DCT_TYPE_FRAME; + } + } + + /* Test NULL context */ + assert(XvMCRenderSurface(display, NULL, XVMC_FRAME_PICTURE, &surface, NULL, NULL, 0, 1, 0, ¯oblocks, &blocks) == XvMCBadContext); + /* Test NULL surface */ + assert(XvMCRenderSurface(display, &context, XVMC_FRAME_PICTURE, NULL, NULL, NULL, 0, 1, 0, ¯oblocks, &blocks) == XvMCBadSurface); + /* Test bad picture structure */ + assert(XvMCRenderSurface(display, &context, 0, &surface, NULL, NULL, 0, 1, 0, ¯oblocks, &blocks) == BadValue); + /* Test valid params */ + assert(XvMCRenderSurface(display, &context, XVMC_FRAME_PICTURE, &surface, NULL, NULL, 0, num_macroblocks, 0, ¯oblocks, &blocks) == Success); + + /* Test NULL surface */ + assert(XvMCPutSurface(display, NULL, window, 0, 0, width, height, 0, 0, width, height, XVMC_FRAME_PICTURE) == XvMCBadSurface); + /* Test bad window */ + /* 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);*/ + /* Test valid params */ + assert(XvMCPutSurface(display, &surface, framebuffer, 0, 0, width, height, 0, 0, width, height, XVMC_FRAME_PICTURE) == Success); + + puts("Press any key to continue..."); + + while (!quit) + { + XNextEvent(display, &event); + switch (event.type) + { + case Expose: + { + XCopyArea + ( + display, + framebuffer, + window, + XDefaultGC(display, XDefaultScreen(display)), + 0, + 0, + width, + height, + 0, + 0 + ); + break; + } + case KeyPress: + { + quit = 1; + break; + } + } + } + + assert(XvMCDestroyBlocks(display, &blocks) == Success); + assert(XvMCDestroyMacroBlocks(display, ¯oblocks) == Success); + assert(XvMCDestroySurface(display, &surface) == Success); + assert(XvMCDestroyContext(display, &context) == Success); + + XFreePixmap(display, framebuffer); + XvUngrabPort(display, port_num, CurrentTime); + XDestroyWindow(display, window); + XCloseDisplay(display); + + return 0; +} + diff --git a/src/libXvMC/tests/test_surface.c b/src/libXvMC/tests/test_surface.c new file mode 100644 index 00000000000..25ebdcc4fcf --- /dev/null +++ b/src/libXvMC/tests/test_surface.c @@ -0,0 +1,72 @@ +#include +#include +#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/libXvMC/tests/testlib.c b/src/libXvMC/tests/testlib.c new file mode 100644 index 00000000000..8672aa99998 --- /dev/null +++ b/src/libXvMC/tests/testlib.c @@ -0,0 +1,87 @@ +#include "testlib.h" +#include + +/* +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; +} + diff --git a/src/libXvMC/tests/testlib.h b/src/libXvMC/tests/testlib.h new file mode 100644 index 00000000000..c73845807ec --- /dev/null +++ b/src/libXvMC/tests/testlib.h @@ -0,0 +1,38 @@ +#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 +#include + +/* + * 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 +); + +#endif +