[PATCH weston] Add a nested YUV client to the weston-nested example
Neil Roberts
neil at linux.intel.com
Mon Feb 10 09:05:53 PST 2014
This adds a separate nested client to the weston-nested example which
will create YUV buffers using libva. The code is based on the
putsurface test in libva. The client can be used by passing the -y
option to weston-nested.
---
.gitignore | 1 +
Makefile.am | 11 +
clients/nested-client-yuv.c | 1058 +++++++++++++++++++++++++++++++++++++++++++
clients/nested.c | 96 ++--
configure.ac | 21 +-
5 files changed, 1150 insertions(+), 37 deletions(-)
create mode 100644 clients/nested-client-yuv.c
diff --git a/.gitignore b/.gitignore
index e0a73c0..3728f36 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,6 +42,7 @@ weston-gears
weston-image
weston-nested
weston-nested-client
+weston-nested-client-yuv
weston-resizor
weston-scaler
weston-simple-egl
diff --git a/Makefile.am b/Makefile.am
index dc50da3..9309b91 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -491,6 +491,17 @@ weston_nested_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
weston_nested_client_SOURCES = clients/nested-client.c
weston_nested_client_LDADD = $(SIMPLE_EGL_CLIENT_LIBS) -lm
weston_nested_client_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+
+if HAVE_LIBVA_WAYLAND
+demo_clients += weston-nested-client-yuv
+weston_nested_client_yuv_SOURCES = clients/nested-client-yuv.c
+weston_nested_client_yuv_LDADD = $(LIBVA_WAYLAND_LIBS) $(SIMPLE_CLIENT_LIBS)
+weston_nested_client_yuv_CFLAGS = \
+ $(CLIENT_CFLAGS) \
+ $(AM_CFLAGS) \
+ $(LIBVA_WAYLAND_CFLAGS)
+endif
+
endif
weston_eventdemo_SOURCES = clients/eventdemo.c
diff --git a/clients/nested-client-yuv.c b/clients/nested-client-yuv.c
new file mode 100644
index 0000000..ba6ee0d
--- /dev/null
+++ b/clients/nested-client-yuv.c
@@ -0,0 +1,1058 @@
+/*
+ * Copyright (c) 2008, 2009, 2014 Intel Corporation. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <sys/time.h>
+
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <pthread.h>
+
+#include <va/va_wayland.h>
+
+/*currently, if XCheckWindowEvent was called in more than one thread,
+ * it would ucause
+ * XIO: fatal IO error 11 (Resource temporarily unavailable) on X server ":0.0"
+ * after 87 requests (83 known processed) with 0 events remaining.
+ *
+ * X Error of failed request: BadGC (invalid GC parameter)
+ * Major opcode of failed request: 60 (X_FreeGC)
+ * Resource id in failed request: 0x600034
+ * Serial number of failed request: 398
+ * Current serial number in output stream: 399
+ * The root cause is unknown. */
+
+#define CHECK_VASTATUS(va_status,func) \
+ if (va_status != VA_STATUS_SUCCESS) { \
+ fprintf(stderr,"%s:%s (%d) failed,exit\n", \
+ __func__, \
+ func, \
+ __LINE__); \
+ exit(1); \
+ }
+
+static void *open_display(void);
+static void close_display(void *win_display);
+static int create_window(void *win_display,
+ int x, int y, int width, int height);
+static int check_window_event(void *win_display, void *drawable,
+ int *width, int *height, int *quit);
+
+struct display;
+struct drawable;
+
+static VAStatus
+va_put_surface(
+ VADisplay dpy,
+ struct drawable *wl_drawable,
+ VASurfaceID va_surface,
+ const VARectangle *src_rect,
+ const VARectangle *dst_rect,
+ const VARectangle *cliprects,
+ unsigned int num_cliprects,
+ unsigned int flags
+);
+
+/* Glue code for the current PutSurface test design */
+#define CAST_DRAWABLE(a) (struct drawable *)(a)
+
+static inline VADisplay
+vaGetDisplay(VANativeDisplay native_dpy)
+{
+ return vaGetDisplayWl(native_dpy);
+}
+
+static VAStatus
+vaPutSurface(
+ VADisplay dpy,
+ VASurfaceID surface,
+ struct drawable *wl_drawable,
+ short src_x,
+ short src_y,
+ unsigned short src_w,
+ unsigned short src_h,
+ short dst_x,
+ short dst_y,
+ unsigned short dst_w,
+ unsigned short dst_h,
+ const VARectangle *cliprects,
+ unsigned int num_cliprects,
+ unsigned int flags
+)
+{
+ VARectangle src_rect, dst_rect;
+
+ src_rect.x = src_x;
+ src_rect.y = src_y;
+ src_rect.width = src_w;
+ src_rect.height = src_h;
+
+ dst_rect.x = src_x;
+ dst_rect.y = src_y;
+ dst_rect.width = src_w;
+ dst_rect.height = src_h;
+ return va_put_surface(dpy, wl_drawable, surface, &src_rect, &dst_rect,
+ cliprects, num_cliprects, flags);
+}
+
+static const struct {
+ unsigned char y, u, v;
+} color_bars[7] = {
+ { 180, 128, 128 },
+ { 168, 44, 136 },
+ { 145, 147, 44 },
+ { 133, 63, 52 },
+ { 63, 193, 204 },
+ { 51, 109, 212 },
+ { 28, 212, 120 }
+};
+
+static int
+yuvgen_planar(int width, int height,
+ unsigned char *Y_start, int Y_pitch,
+ unsigned char *U_start, int U_pitch,
+ unsigned char *V_start, int V_pitch,
+ unsigned int fourcc, int box_width, int row_shift, int field)
+{
+ int row, jj;
+ unsigned char u_value, v_value;
+ int y_factor, uv_factor = 1;
+
+ /* copy Y plane */
+ y_factor = 1;
+ if (fourcc == VA_FOURCC_YUY2)
+ y_factor = 2;
+
+ switch (fourcc) {
+ case VA_FOURCC_NV12:
+ uv_factor = 2;
+ break;
+ case VA_FOURCC_YV12:
+ uv_factor = 1;
+ break;
+ case VA_FOURCC_YUY2:
+ uv_factor = 4;
+ break;
+ default:
+ printf("unsupported fourcc\n");
+ assert(0);
+ }
+
+ for (row = 0; row < height; row++) {
+ unsigned char *Y_row = Y_start + row * Y_pitch;
+ int xpos, ypos;
+
+ ypos = (row / box_width) & 0x1;
+
+ /* fill garbage data into the other field */
+ if (((field == VA_TOP_FIELD) && (row & 1))
+ || ((field == VA_BOTTOM_FIELD) && ((row & 1) == 0))) {
+ memset(Y_row, 0xff, width);
+ continue;
+ }
+
+ for (jj = 0; jj < width; jj++) {
+ xpos = ((row_shift + jj) / box_width) & 0x1;
+ if (row < height / 2)
+ Y_row[jj * y_factor] =
+ color_bars[jj * 7 / width].y;
+ else if (xpos == ypos)
+ Y_row[jj * y_factor] = 0xeb;
+ else
+ Y_row[jj * y_factor] = 0x10;
+ }
+ }
+
+ /* copy UV data */
+ for (row = 0; row < height / 2; row++) {
+ unsigned char *U_row = U_start + row * U_pitch;
+ unsigned char *V_row = V_start + row * V_pitch;
+
+ for (jj = 0; jj < width / 2; jj++) {
+ /* fill garbage data into the other field */
+ if (((field == VA_TOP_FIELD) && (row & 1))
+ || ((field == VA_BOTTOM_FIELD) &&
+ ((row & 1) == 0))) {
+ u_value = 0xff;
+ v_value = 0xff;
+ } else if (row >= height / 4) {
+ u_value = 0x80;
+ v_value = 0x80;
+ } else {
+ u_value = color_bars[jj * 7 * 2 / width].u;
+ v_value = color_bars[jj * 7 * 2 / width].v;
+ }
+
+ U_row[jj * uv_factor] = u_value;
+ V_row[jj * uv_factor] = v_value;
+ }
+ }
+
+ return 0;
+}
+
+static int
+upload_surface(VADisplay va_dpy, VASurfaceID surface_id,
+ int box_width, int row_shift, int field)
+{
+ VAImage surface_image;
+ void *surface_p = NULL, *U_start = NULL, *V_start = NULL;
+ VAStatus va_status;
+ unsigned int pitches[3] = { 0, 0, 0 };
+
+ va_status = vaDeriveImage(va_dpy, surface_id, &surface_image);
+ CHECK_VASTATUS(va_status, "vaDeriveImage");
+
+ vaMapBuffer(va_dpy, surface_image.buf, &surface_p);
+ assert(VA_STATUS_SUCCESS == va_status);
+
+ pitches[0] = surface_image.pitches[0];
+ switch (surface_image.format.fourcc) {
+ case VA_FOURCC_NV12:
+ U_start = (char *)surface_p + surface_image.offsets[1];
+ V_start = (char *)U_start + 1;
+ pitches[1] = surface_image.pitches[1];
+ pitches[2] = surface_image.pitches[1];
+ break;
+ case VA_FOURCC_IYUV:
+ U_start = (char *)surface_p + surface_image.offsets[1];
+ V_start = (char *)surface_p + surface_image.offsets[2];
+ pitches[1] = surface_image.pitches[1];
+ pitches[2] = surface_image.pitches[2];
+ break;
+ case VA_FOURCC_YV12:
+ U_start = (char *)surface_p + surface_image.offsets[2];
+ V_start = (char *)surface_p + surface_image.offsets[1];
+ pitches[1] = surface_image.pitches[2];
+ pitches[2] = surface_image.pitches[1];
+ break;
+ case VA_FOURCC_YUY2:
+ U_start = (char *)surface_p + 1;
+ V_start = (char *)surface_p + 3;
+ pitches[1] = surface_image.pitches[0];
+ pitches[2] = surface_image.pitches[0];
+ break;
+ default:
+ assert(0);
+ }
+
+ /* assume surface is planar format */
+ yuvgen_planar(surface_image.width, surface_image.height,
+ (unsigned char *)surface_p, pitches[0],
+ (unsigned char *)U_start, pitches[1],
+ (unsigned char *)V_start, pitches[2],
+ surface_image.format.fourcc, box_width, row_shift, field);
+
+ vaUnmapBuffer(va_dpy, surface_image.buf);
+
+ vaDestroyImage(va_dpy, surface_image.image_id);
+
+ return 0;
+}
+
+#define SURFACE_NUM 16
+
+static void *win_display;
+static VADisplay va_dpy;
+static VAImageFormat *va_image_formats;
+static int va_num_image_formats = -1;
+static VAConfigID vpp_config_id = VA_INVALID_ID;
+static VASurfaceAttrib *va_surface_attribs;
+static int va_num_surface_attribs = -1;
+static VASurfaceID surface_id[SURFACE_NUM];
+static pthread_mutex_t surface_mutex[SURFACE_NUM];
+
+static void *drawable_thread0, *drawable_thread1;
+static int surface_width = 250, surface_height = 250;
+static int win_x = 0, win_y = 0;
+static int win_width = 250, win_height = 250;
+static int frame_rate = 0;
+static unsigned long long frame_num_total = ~0;
+static int check_event = 1;
+static int test_clip = 0;
+static int display_field = VA_FRAME_PICTURE;
+static pthread_mutex_t gmutex;
+static int box_width = 32;
+static int multi_thread = 0;
+static int verbose = 0;
+static int test_color_conversion = 0;
+static int csc_src_fourcc = 0, csc_dst_fourcc = 0;
+static VAImage csc_dst_fourcc_image;
+static VASurfaceID csc_render_surface;
+
+typedef struct {
+ char *fmt_str;
+ unsigned int fourcc;
+} fourcc_map;
+fourcc_map va_fourcc_map[] = {
+ {"YUYV", VA_FOURCC_YUY2},
+ {"YUY2", VA_FOURCC_YUY2},
+ {"NV12", VA_FOURCC_NV12},
+ {"YV12", VA_FOURCC_YV12},
+ {"BGRA", VA_FOURCC_BGRA},
+ {"RGBA", VA_FOURCC_RGBA},
+ {"BGRX", VA_FOURCC_BGRX},
+ {"RGBX", VA_FOURCC_RGBX},
+};
+
+static char *
+map_vafourcc_to_str(unsigned int format)
+{
+ static char unknown_format[] = "unknown-format";
+ size_t i;
+ for (i = 0; i < sizeof(va_fourcc_map) / sizeof(fourcc_map); i++) {
+ if (va_fourcc_map[i].fourcc == format) {
+ return va_fourcc_map[i].fmt_str;
+ }
+ }
+
+ return unknown_format;
+
+}
+
+static int
+va_value_equals(const VAGenericValue * v1, const VAGenericValue * v2)
+{
+ if (v1->type != v2->type)
+ return 0;
+
+ switch (v1->type) {
+ case VAGenericValueTypeInteger:
+ return v1->value.i == v2->value.i;
+ case VAGenericValueTypeFloat:
+ return v1->value.f == v2->value.f;
+ case VAGenericValueTypePointer:
+ return v1->value.p == v2->value.p;
+ case VAGenericValueTypeFunc:
+ return v1->value.fn == v2->value.fn;
+ }
+ return 0;
+}
+
+static int
+ensure_image_formats(void)
+{
+ VAStatus va_status;
+ VAImageFormat *image_formats;
+ int num_image_formats;
+
+ if (va_num_image_formats >= 0)
+ return va_num_image_formats;
+
+ num_image_formats = vaMaxNumImageFormats(va_dpy);
+ if (num_image_formats == 0)
+ return 0;
+
+ image_formats = malloc(num_image_formats * sizeof(*image_formats));
+ if (!image_formats)
+ return 0;
+
+ va_status =
+ vaQueryImageFormats(va_dpy, image_formats, &num_image_formats);
+ CHECK_VASTATUS(va_status, "vaQuerySurfaceAttributes()");
+
+ va_image_formats = image_formats;
+ va_num_image_formats = num_image_formats;
+ return num_image_formats;
+}
+
+static const VAImageFormat *
+lookup_image_format(uint32_t fourcc)
+{
+ int i;
+
+ if (!ensure_image_formats())
+ return NULL;
+
+ for (i = 0; i < va_num_image_formats; i++) {
+ const VAImageFormat *const image_format = &va_image_formats[i];
+ if (image_format->fourcc == fourcc)
+ return image_format;
+ }
+ return NULL;
+}
+
+static int
+ensure_surface_attribs(void)
+{
+ VAStatus va_status;
+ VASurfaceAttrib *surface_attribs;
+ unsigned int num_image_formats, num_surface_attribs;
+
+ if (va_num_surface_attribs >= 0)
+ return va_num_surface_attribs;
+
+ num_image_formats = vaMaxNumImageFormats(va_dpy);
+ if (num_image_formats == 0)
+ return 0;
+
+ va_status = vaCreateConfig(va_dpy, VAProfileNone, VAEntrypointVideoProc,
+ NULL, 0, &vpp_config_id);
+ CHECK_VASTATUS(va_status, "vaCreateConfig()");
+
+ /* Guess the number of surface attributes, thus including any
+ pixel-format supported by the VA driver */
+ num_surface_attribs = VASurfaceAttribCount + num_image_formats;
+ surface_attribs =
+ malloc(num_surface_attribs * sizeof(*surface_attribs));
+ if (!surface_attribs)
+ return 0;
+
+ va_status = vaQuerySurfaceAttributes(va_dpy, vpp_config_id,
+ surface_attribs,
+ &num_surface_attribs);
+ if (va_status == VA_STATUS_SUCCESS)
+ va_surface_attribs = surface_attribs;
+ else if (va_status == VA_STATUS_ERROR_MAX_NUM_EXCEEDED) {
+ va_surface_attribs = realloc(surface_attribs,
+ num_surface_attribs *
+ sizeof(*va_surface_attribs));
+ if (!va_surface_attribs) {
+ free(surface_attribs);
+ return 0;
+ }
+ va_status = vaQuerySurfaceAttributes(va_dpy, vpp_config_id,
+ va_surface_attribs,
+ &num_surface_attribs);
+ }
+ CHECK_VASTATUS(va_status, "vaQuerySurfaceAttributes()");
+ va_num_surface_attribs = num_surface_attribs;
+ return num_surface_attribs;
+}
+
+static const VASurfaceAttrib *
+lookup_surface_attrib(VASurfaceAttribType type, const VAGenericValue * value)
+{
+ int i;
+
+ if (!ensure_surface_attribs())
+ return NULL;
+
+ for (i = 0; i < va_num_surface_attribs; i++) {
+ const VASurfaceAttrib *const surface_attrib =
+ &va_surface_attribs[i];
+ if (surface_attrib->type != type)
+ continue;
+ if (!(surface_attrib->flags & VA_SURFACE_ATTRIB_SETTABLE))
+ continue;
+ if (va_value_equals(&surface_attrib->value, value))
+ return surface_attrib;
+ }
+ return NULL;
+}
+
+static int
+csc_preparation(void)
+{
+ VAStatus va_status;
+
+ // 1. make sure dst fourcc is supported for vaImage
+ if (!lookup_image_format(csc_dst_fourcc)) {
+ test_color_conversion = 0;
+ printf
+ ("VA driver doesn't support %s image, skip additional color conversion\n",
+ map_vafourcc_to_str(csc_dst_fourcc));
+ goto cleanup;
+ }
+ // 2. make sure src_fourcc is supported for vaSurface
+ VASurfaceAttrib surface_attribs[1], *const s_attrib =
+ &surface_attribs[0];
+ s_attrib->type = VASurfaceAttribPixelFormat;
+ s_attrib->flags = VA_SURFACE_ATTRIB_SETTABLE;
+ s_attrib->value.type = VAGenericValueTypeInteger;
+ s_attrib->value.value.i = csc_src_fourcc;
+
+ if (!lookup_surface_attrib
+ (VASurfaceAttribPixelFormat, &s_attrib->value)) {
+ printf("VA driver doesn't support %s surface, "
+ "skip additional color conversion\n",
+ map_vafourcc_to_str(csc_src_fourcc));
+ test_color_conversion = 0;
+ goto cleanup;
+ }
+ // 3 create all objs required by csc
+ // 3.1 vaSurface with src fourcc
+ va_status = vaCreateSurfaces(va_dpy,
+ VA_RT_FORMAT_YUV420, surface_width,
+ surface_height, &surface_id[0],
+ SURFACE_NUM, surface_attribs, 1);
+ CHECK_VASTATUS(va_status, "vaCreateSurfaces");
+
+ // 3.2 vaImage with dst fourcc
+ VAImageFormat image_format;
+ image_format.fourcc = csc_dst_fourcc;
+ image_format.byte_order = VA_LSB_FIRST;
+ image_format.bits_per_pixel = 16;
+
+ va_status = vaCreateImage(va_dpy, &image_format,
+ surface_width, surface_height,
+ &csc_dst_fourcc_image);
+ CHECK_VASTATUS(va_status, "vaCreateImage");
+
+ // 3.3 create a temp VASurface for final rendering(vaPutSurface)
+ s_attrib->value.value.i = VA_FOURCC_NV12;
+ va_status = vaCreateSurfaces(va_dpy, VA_RT_FORMAT_YUV420,
+ surface_width, surface_height,
+ &csc_render_surface, 1,
+ surface_attribs, 1);
+ CHECK_VASTATUS(va_status, "vaCreateSurfaces");
+
+ cleanup:
+ return test_color_conversion;
+}
+
+static VASurfaceID
+get_next_free_surface(int *index)
+{
+ VASurfaceStatus surface_status;
+ int i;
+
+ assert(index);
+
+ if (multi_thread == 0) {
+ i = *index;
+ i++;
+ if (i == SURFACE_NUM)
+ i = 0;
+ *index = i;
+
+ return surface_id[i];
+ }
+
+ for (i = 0; i < SURFACE_NUM; i++) {
+ surface_status = (VASurfaceStatus) 0;
+ vaQuerySurfaceStatus(va_dpy, surface_id[i], &surface_status);
+ if (surface_status == VASurfaceReady) {
+ if (0 == pthread_mutex_trylock(&surface_mutex[i])) {
+ *index = i;
+ break;
+ }
+ }
+ }
+
+ if (i == SURFACE_NUM)
+ return VA_INVALID_SURFACE;
+ else
+ return surface_id[i];
+}
+
+static int
+upload_source_YUV_once_for_all(void)
+{
+ int box_width_loc = 8;
+ int row_shift_loc = 0;
+ int i;
+
+ for (i = 0; i < SURFACE_NUM; i++) {
+ printf("\rLoading data into surface %d.....", i);
+ upload_surface(va_dpy, surface_id[i], box_width_loc,
+ row_shift_loc, 0);
+
+ row_shift_loc++;
+ if (row_shift_loc == (2 * box_width_loc))
+ row_shift_loc = 0;
+ }
+ printf("\n");
+
+ return 0;
+}
+
+/*
+ * Helper function for profiling purposes
+ */
+static unsigned long
+get_tick_count(void)
+{
+ struct timeval tv;
+ if (gettimeofday(&tv, NULL))
+ return 0;
+ return tv.tv_usec / 1000 + tv.tv_sec * 1000;
+}
+
+static void
+update_clipbox(VARectangle * cliprects, int width, int height)
+{
+ if (test_clip == 0)
+ return;
+
+ srand((unsigned)time(NULL));
+
+ cliprects[0].x = (rand() % width);
+ cliprects[0].y = (rand() % height);
+ cliprects[0].width = (rand() % (width - cliprects[0].x));
+ cliprects[0].height = (rand() % (height - cliprects[0].y));
+
+ cliprects[1].x = (rand() % width);
+ cliprects[1].y = (rand() % height);
+ cliprects[1].width = (rand() % (width - cliprects[1].x));
+ cliprects[1].height = (rand() % (height - cliprects[1].y));
+ printf("\nTest clip (%d,%d, %d x %d) and (%d,%d, %d x %d) \n",
+ cliprects[0].x, cliprects[0].y, cliprects[0].width,
+ cliprects[0].height, cliprects[1].x, cliprects[1].y,
+ cliprects[1].width, cliprects[1].height);
+}
+
+static void *
+putsurface_thread(void *data)
+{
+ int width = win_width, height = win_height;
+ void *drawable = data;
+ int quit = 0;
+ VAStatus vaStatus;
+ int row_shift = 0;
+ int index = 0;
+ unsigned int frame_num = 0, start_time, putsurface_time;
+ VARectangle cliprects[2]; /* client supplied clip list */
+ int continue_display = 0;
+
+ if (drawable == drawable_thread0)
+ printf("Enter into thread0\n\n");
+ if (drawable == drawable_thread1)
+ printf("Enter into thread1\n\n");
+
+ putsurface_time = 0;
+ while (!quit) {
+ VASurfaceID surface_id = VA_INVALID_SURFACE;
+
+ while (surface_id == VA_INVALID_SURFACE)
+ surface_id = get_next_free_surface(&index);
+
+ if (verbose)
+ printf("Thread: %p Display surface 0x%x,\n", drawable,
+ surface_id);
+
+ if (multi_thread)
+ upload_surface(va_dpy, surface_id, box_width, row_shift,
+ display_field);
+
+ if (check_event)
+ pthread_mutex_lock(&gmutex);
+
+ start_time = get_tick_count();
+ if ((continue_display == 0) && getenv("FRAME_STOP")) {
+ char c;
+ printf("Press any key to display frame %d..."
+ "(c/C to continue)\n",
+ frame_num);
+ c = getchar();
+ if (c == 'c' || c == 'C')
+ continue_display = 1;
+ }
+ if (test_color_conversion) {
+ static int _put_surface_count = 0;
+ if (_put_surface_count++ % 50 == 0) {
+ printf("do additional colorcoversion from "
+ "%s to %s\n",
+ map_vafourcc_to_str(csc_src_fourcc),
+ map_vafourcc_to_str(csc_dst_fourcc));
+ }
+ // get image from surface, csc_src_fourcc to
+ // csc_dst_fourcc conversion happens
+ vaStatus = vaGetImage(va_dpy, surface_id, 0, 0,
+ surface_width, surface_height,
+ csc_dst_fourcc_image.image_id);
+ CHECK_VASTATUS(vaStatus, "vaGetImage");
+
+ // render csc_dst_fourcc image to temp surface
+ vaStatus =
+ vaPutImage(va_dpy, csc_render_surface,
+ csc_dst_fourcc_image.image_id, 0, 0,
+ surface_width, surface_height, 0, 0,
+ surface_width, surface_height);
+ CHECK_VASTATUS(vaStatus, "vaPutImage");
+
+ // render the temp surface, it should be same
+ // with original surface without color
+ // conversion test
+ vaStatus =
+ vaPutSurface(va_dpy, csc_render_surface,
+ CAST_DRAWABLE(drawable), 0, 0,
+ surface_width, surface_height, 0, 0,
+ width, height,
+ (test_clip ==
+ 0) ? NULL : &cliprects[0],
+ (test_clip == 0) ? 0 : 2,
+ display_field);
+ CHECK_VASTATUS(vaStatus, "vaPutSurface");
+
+ } else {
+ vaStatus =
+ vaPutSurface(va_dpy, surface_id,
+ CAST_DRAWABLE(drawable), 0, 0,
+ surface_width, surface_height, 0, 0,
+ width, height,
+ (test_clip ==
+ 0) ? NULL : &cliprects[0],
+ (test_clip == 0) ? 0 : 2,
+ display_field);
+ CHECK_VASTATUS(vaStatus, "vaPutSurface");
+ }
+
+ putsurface_time += (get_tick_count() - start_time);
+
+ if (check_event)
+ pthread_mutex_unlock(&gmutex);
+
+ /* locked in get_next_free_surface */
+ pthread_mutex_unlock(&surface_mutex[index]);
+
+ if ((frame_num % 0xff) == 0) {
+ fprintf(stderr, "%.2f FPS \r",
+ 256000.0 / (float)putsurface_time);
+ putsurface_time = 0;
+ update_clipbox(cliprects, width, height);
+ }
+
+ if (check_event)
+ check_window_event(win_display, drawable, &width,
+ &height, &quit);
+
+ if (multi_thread) { /* reload surface content */
+ row_shift++;
+ if (row_shift == (2 * box_width))
+ row_shift = 0;
+ }
+
+ if (frame_rate != 0) /* rough framerate control */
+ usleep(1000 / frame_rate * 1000);
+
+ frame_num++;
+ if (frame_num >= frame_num_total)
+ quit = 1;
+ }
+
+ if (drawable == drawable_thread1)
+ pthread_exit(NULL);
+
+ return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+ int major_ver, minor_ver;
+ VAStatus va_status;
+ pthread_t thread1;
+ int ret;
+ int i;
+
+ if (csc_src_fourcc && csc_dst_fourcc) {
+ test_color_conversion = 1;
+ }
+
+ win_display = (void *)open_display();
+ if (win_display == NULL) {
+ fprintf(stderr, "Can't open the connection of display!\n");
+ exit(-1);
+ }
+ create_window(win_display, win_x, win_y, win_width, win_height);
+
+ va_dpy = vaGetDisplay(win_display);
+ va_status = vaInitialize(va_dpy, &major_ver, &minor_ver);
+ CHECK_VASTATUS(va_status, "vaInitialize");
+
+ if (test_color_conversion) {
+ ret = csc_preparation();
+ }
+ if (!test_color_conversion || !ret) {
+ va_status = vaCreateSurfaces(va_dpy,
+ VA_RT_FORMAT_YUV420, surface_width,
+ surface_height, &surface_id[0],
+ SURFACE_NUM, NULL, 0);
+ }
+ CHECK_VASTATUS(va_status, "vaCreateSurfaces");
+ if (multi_thread == 0) /* upload the content for all surfaces */
+ upload_source_YUV_once_for_all();
+
+ if (check_event)
+ pthread_mutex_init(&gmutex, NULL);
+
+ for (i = 0; i < SURFACE_NUM; i++)
+ pthread_mutex_init(&surface_mutex[i], NULL);
+
+ if (multi_thread == 1)
+ ret =
+ pthread_create(&thread1, NULL, putsurface_thread,
+ (void *)drawable_thread1);
+
+ putsurface_thread((void *)drawable_thread0);
+
+ if (multi_thread == 1)
+ pthread_join(thread1, (void **)&ret);
+ printf("thread1 is free\n");
+
+ if (test_color_conversion) {
+ // destroy temp surface/image
+ va_status = vaDestroySurfaces(va_dpy, &csc_render_surface, 1);
+ CHECK_VASTATUS(va_status, "vaDestroySurfaces");
+
+ va_status =
+ vaDestroyImage(va_dpy, csc_dst_fourcc_image.image_id);
+ CHECK_VASTATUS(va_status, "vaDestroyImage");
+ }
+
+ if (vpp_config_id != VA_INVALID_ID) {
+ vaDestroyConfig(va_dpy, vpp_config_id);
+ vpp_config_id = VA_INVALID_ID;
+ }
+
+ vaDestroySurfaces(va_dpy, &surface_id[0], SURFACE_NUM);
+ vaTerminate(va_dpy);
+
+ free(va_image_formats);
+ free(va_surface_attribs);
+ close_display(win_display);
+
+ return 0;
+}
+
+struct display {
+ struct wl_display *display;
+ struct wl_compositor *compositor;
+ struct wl_registry *registry;
+ int event_fd;
+};
+
+struct drawable {
+ struct wl_display *display;
+ struct wl_surface *surface;
+ unsigned int redraw_pending : 1;
+};
+
+static void
+frame_redraw_callback(void *data, struct wl_callback *callback, uint32_t time)
+{
+ struct drawable * const drawable = data;
+
+ drawable->redraw_pending = 0;
+ wl_callback_destroy(callback);
+}
+
+static const struct wl_callback_listener frame_callback_listener = {
+ frame_redraw_callback
+};
+
+static VAStatus
+va_put_surface(
+ VADisplay dpy,
+ struct drawable *wl_drawable,
+ VASurfaceID va_surface,
+ const VARectangle *src_rect,
+ const VARectangle *dst_rect,
+ const VARectangle *cliprects,
+ unsigned int num_cliprects,
+ unsigned int flags
+)
+{
+ struct display *d;
+ struct wl_callback *callback;
+ VAStatus va_status;
+ struct wl_buffer *buffer;
+
+ if (!wl_drawable)
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+
+ d = wl_display_get_user_data(wl_drawable->display);
+ if (!d)
+ return VA_STATUS_ERROR_INVALID_DISPLAY;
+
+ /* Wait for the previous frame to complete redraw */
+ if (wl_drawable->redraw_pending) {
+ wl_display_flush(d->display);
+ while (wl_drawable->redraw_pending)
+ wl_display_dispatch(wl_drawable->display);
+ }
+
+ va_status = vaGetSurfaceBufferWl(va_dpy, va_surface, VA_FRAME_PICTURE, &buffer);
+ if (va_status != VA_STATUS_SUCCESS)
+ return va_status;
+
+ wl_surface_attach(wl_drawable->surface, buffer, 0, 0);
+ wl_surface_damage(
+ wl_drawable->surface,
+ dst_rect->x, dst_rect->y, dst_rect->width, dst_rect->height
+ );
+
+ wl_display_flush(d->display);
+ wl_drawable->redraw_pending = 1;
+ callback = wl_surface_frame(wl_drawable->surface);
+ wl_surface_commit(wl_drawable->surface);
+ wl_callback_add_listener(callback, &frame_callback_listener, wl_drawable);
+ return VA_STATUS_SUCCESS;
+}
+
+static void
+registry_handle_global(
+ void *data,
+ struct wl_registry *registry,
+ uint32_t id,
+ const char *interface,
+ uint32_t version
+)
+{
+ struct display * const d = data;
+
+ if (strcmp(interface, "wl_compositor") == 0)
+ d->compositor =
+ wl_registry_bind(registry, id, &wl_compositor_interface, 1);
+}
+
+static const struct wl_registry_listener registry_listener = {
+ registry_handle_global,
+ NULL,
+};
+
+static void *
+open_display(void)
+{
+ struct display *d;
+
+ d = calloc(1, sizeof *d);
+ if (!d)
+ return NULL;
+
+ d->display = wl_display_connect(NULL);
+ if (!d->display)
+ return NULL;
+
+ wl_display_set_user_data(d->display, d);
+ d->registry = wl_display_get_registry(d->display);
+ wl_registry_add_listener(d->registry, ®istry_listener, d);
+ d->event_fd = wl_display_get_fd(d->display);
+ wl_display_dispatch(d->display);
+ return d->display;
+}
+
+static void
+close_display(void *win_display)
+{
+ struct display * const d = wl_display_get_user_data(win_display);
+
+ if (d->compositor) {
+ wl_compositor_destroy(d->compositor);
+ d->compositor = NULL;
+ }
+
+ if (d->display) {
+ wl_display_disconnect(d->display);
+ d->display = NULL;
+ }
+ free(d);
+}
+
+static int
+create_window(void *win_display, int x, int y, int width, int height)
+{
+ struct wl_display * const display = win_display;
+ struct display * const d = wl_display_get_user_data(display);
+ struct wl_surface *surface1, *surface2;
+ struct drawable *drawable1, *drawable2;
+
+ surface1 = wl_compositor_create_surface(d->compositor);
+
+ drawable1 = malloc(sizeof(*drawable1));
+ drawable1->display = display;
+ drawable1->surface = surface1;
+ drawable1->redraw_pending = 0;
+
+ /* global out */
+ drawable_thread0 = drawable1;
+
+ if (multi_thread == 0)
+ return 0;
+
+ surface2 = wl_compositor_create_surface(d->compositor);
+
+ drawable2 = malloc(sizeof(*drawable2));
+ drawable2->display = display;
+ drawable1->surface = surface2;
+ drawable2->redraw_pending = 0;
+
+ /* global out */
+ drawable_thread1 = drawable2;
+ return 0;
+}
+
+static int
+check_window_event(
+ void *win_display,
+ void *drawable,
+ int *width,
+ int *height,
+ int *quit
+)
+{
+ struct wl_display * const display = win_display;
+ struct display * const d = wl_display_get_user_data(display);
+ struct timeval tv;
+ fd_set rfds;
+ int retval;
+
+ if (check_event == 0)
+ return 0;
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ do {
+ FD_ZERO(&rfds);
+ FD_SET(d->event_fd, &rfds);
+
+ retval = select(d->event_fd + 1, &rfds, NULL, NULL, &tv);
+ if (retval < 0) {
+ perror("select");
+ break;
+ }
+ if (retval == 1) {
+ if (wl_display_dispatch(d->display) == -1)
+ break;
+ }
+ } while (retval > 0);
+
+#if 0
+ /* bail on any focused key press */
+ if(event.type == KeyPress) {
+ *quit = 1;
+ return 0;
+ }
+#endif
+
+#if 0
+ /* rescale the video to fit the window */
+ if(event.type == ConfigureNotify) {
+ *width = event.xconfigure.width;
+ *height = event.xconfigure.height;
+ printf("Scale window to %dx%d\n", width, height);
+ }
+#endif
+ return 0;
+}
+
diff --git a/clients/nested.c b/clients/nested.c
index d75e953..1d754d0 100644
--- a/clients/nested.c
+++ b/clients/nested.c
@@ -58,6 +58,7 @@ typedef struct wl_buffer * (EGLAPIENTRYP PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL) (
#endif
static int option_blit;
+static int option_yuv;
struct nested {
struct display *display;
@@ -105,9 +106,12 @@ struct nested_buffer {
struct nested_surface {
struct wl_resource *resource;
struct nested *nested;
- EGLImageKHR *image;
+ EGLImageKHR images[3];
struct wl_list link;
+ EGLint format;
+ int n_planes;
+
struct wl_list frame_callback_list;
struct {
@@ -156,6 +160,7 @@ struct nested_renderer {
static const struct weston_option nested_options[] = {
{ WESTON_OPTION_BOOLEAN, "blit", 'b', &option_blit },
+ { WESTON_OPTION_BOOLEAN, "yuv", 'y', &option_yuv }
};
static const struct nested_renderer nested_blit_renderer;
@@ -430,19 +435,25 @@ surface_attach(struct wl_client *client,
struct nested_buffer *buffer = NULL;
if (buffer_resource) {
- int format;
-
if (!query_buffer(nested->egl_display, (void *) buffer_resource,
- EGL_TEXTURE_FORMAT, &format)) {
+ EGL_TEXTURE_FORMAT, &surface->format)) {
wl_resource_post_error(buffer_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
"attaching non-egl wl_buffer");
return;
}
- switch (format) {
+ switch (surface->format) {
case EGL_TEXTURE_RGB:
case EGL_TEXTURE_RGBA:
+ surface->n_planes = 1;
+ break;
+ case EGL_TEXTURE_Y_U_V_WL:
+ surface->n_planes = 3;
+ break;
+ case EGL_TEXTURE_Y_UV_WL:
+ case EGL_TEXTURE_Y_XUXV_WL:
+ surface->n_planes = 2;
break;
default:
wl_resource_post_error(buffer_resource,
@@ -474,16 +485,24 @@ nested_surface_attach(struct nested_surface *surface,
struct nested_buffer *buffer)
{
struct nested *nested = surface->nested;
-
- if (surface->image != EGL_NO_IMAGE_KHR)
- destroy_image(nested->egl_display, surface->image);
-
- surface->image = create_image(nested->egl_display, NULL,
- EGL_WAYLAND_BUFFER_WL, buffer->resource,
- NULL);
- if (surface->image == EGL_NO_IMAGE_KHR) {
- fprintf(stderr, "failed to create img\n");
- return;
+ EGLint attribs[] = { EGL_WAYLAND_PLANE_WL, 0, EGL_NONE };
+ int i;
+
+ for (i = 0; i < 3; i++)
+ if (surface->images[i] != EGL_NO_IMAGE_KHR)
+ destroy_image(nested->egl_display, surface->images[i]);
+
+ for (i = 0; i < surface->n_planes; i++) {
+ attribs[1] = i;
+ surface->images[i] =
+ create_image(nested->egl_display, NULL,
+ EGL_WAYLAND_BUFFER_WL,
+ buffer->resource,
+ attribs);
+ if (surface->images[i] == EGL_NO_IMAGE_KHR) {
+ fprintf(stderr, "failed to create img\n");
+ return;
+ }
}
nested->renderer->surface_attach(surface, buffer);
@@ -902,7 +921,7 @@ blit_render_clients(struct nested *nested,
nested->window, NULL);
glBindTexture(GL_TEXTURE_2D, blit_surface->texture);
- image_target_texture_2d(GL_TEXTURE_2D, s->image);
+ image_target_texture_2d(GL_TEXTURE_2D, s->images[0]);
display_release_window_surface(nested->display,
nested->window);
@@ -1045,30 +1064,42 @@ static const struct wl_callback_listener ss_frame_listener = {
ss_frame_callback
};
+static struct wl_buffer *
+get_parent_buffer(struct nested_surface *surface,
+ struct nested_buffer *buffer)
+{
+ struct nested *nested = surface->nested;
+ EGLDisplay *edpy = nested->egl_display;
+
+ /* Create a representation of the buffer in the parent
+ * compositor if we haven't already */
+ if (buffer->parent_buffer)
+ return buffer->parent_buffer;
+
+ buffer->parent_buffer =
+ create_wayland_buffer_from_image(edpy,
+ surface->format,
+ surface->images,
+ surface->n_planes);
+
+ wl_buffer_add_listener(buffer->parent_buffer,
+ &ss_buffer_listener,
+ buffer);
+
+ return buffer->parent_buffer;
+}
+
static void
ss_surface_attach(struct nested_surface *surface,
struct nested_buffer *buffer)
{
- struct nested *nested = surface->nested;
struct nested_ss_surface *ss_surface = surface->renderer_data;
struct wl_buffer *parent_buffer;
const pixman_box32_t *rects;
int n_rects, i;
if (buffer) {
- /* Create a representation of the buffer in the parent
- * compositor if we haven't already */
- if (buffer->parent_buffer == NULL) {
- EGLDisplay *edpy = nested->egl_display;
- EGLImageKHR image = surface->image;
-
- buffer->parent_buffer =
- create_wayland_buffer_from_image(edpy, image);
-
- wl_buffer_add_listener(buffer->parent_buffer,
- &ss_buffer_listener,
- buffer);
- }
+ parent_buffer = get_parent_buffer(surface, buffer);
parent_buffer = buffer->parent_buffer;
@@ -1129,7 +1160,10 @@ main(int argc, char *argv[])
nested = nested_create(display);
- launch_client(nested, "weston-nested-client");
+ launch_client(nested,
+ option_yuv ?
+ "weston-nested-client-yuv" :
+ "weston-nested-client");
display_run(display);
diff --git a/configure.ac b/configure.ac
index 00d7123..63b59a2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -250,19 +250,28 @@ PKG_CHECK_MODULES(WEBP, [libwebp], [have_webp=yes], [have_webp=no])
AS_IF([test "x$have_webp" = "xyes"],
[AC_DEFINE([HAVE_WEBP], [1], [Have webp])])
+PKG_CHECK_MODULES(LIBVA, [libva >= 0.34.0 libva-drm >= 0.34.0],
+ [have_libva=yes], [have_libva=no])
+
+have_libva_wayland=no
+AS_IF([test "x$have_libva" = "xyes"],
+ [PKG_CHECK_MODULES(LIBVA_WAYLAND,
+ [libva >= 0.34.0 libva-drm >= 0.34.0
+ libva-wayland >= 0.34.0],
+ [have_libva_wayland=yes], [have_libva_wayland=no])])
+AM_CONDITIONAL(HAVE_LIBVA_WAYLAND, test "x$have_libva_wayland" = xyes)
+
AC_ARG_ENABLE(vaapi-recorder, [ --enable-vaapi-recorder],,
enable_vaapi_recorder=auto)
if test x$enable_vaapi_recorder != xno; then
- PKG_CHECK_MODULES(LIBVA, [libva >= 0.34.0 libva-drm >= 0.34.0],
- [have_libva=yes], [have_libva=no])
if test "x$have_libva" = "xno" -a "x$enable_vaapi_recorder" = "xyes"; then
AC_MSG_ERROR([vaapi-recorder explicitly enabled, but libva couldn't be found])
fi
- AS_IF([test "x$have_libva" = "xyes"],
+ enable_vaapi_recorder="$have_libva"
+ AS_IF([test "x$enable_vaapi_recorder" = "xyes"],
[AC_DEFINE([BUILD_VAAPI_RECORDER], [1], [Build the vaapi recorder])])
fi
-AM_CONDITIONAL(ENABLE_VAAPI_RECORDER, test "x$have_libva" = xyes)
-
+AM_CONDITIONAL(ENABLE_VAAPI_RECORDER, test "x$enable_vaapi_recorder" = xyes)
AC_CHECK_LIB([jpeg], [jpeg_CreateDecompress], have_jpeglib=yes)
if test x$have_jpeglib = xyes; then
@@ -520,5 +529,5 @@ AC_MSG_RESULT([
LCMS2 Support ${have_lcms}
libwebp Support ${have_webp}
libunwind Support ${have_libunwind}
- VA H.264 encoding Support ${have_libva}
+ VA H.264 encoding Support ${enable_vaapi_recorder}
])
--
1.8.5.3
More information about the wayland-devel
mailing list