mirror of
https://github.com/thead-yocto-mirror/gfx-examples
synced 2026-06-21 08:52:37 +02:00
Linux_SDK_V0.9.5
This commit is contained in:
19
COPYING
Normal file
19
COPYING
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
9
README.txt
Normal file
9
README.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
== Build
|
||||
TBD
|
||||
|
||||
== Run "gtk01" Tests
|
||||
TBD
|
||||
|
||||
== Run "wl-tester" Tests
|
||||
1. Prepare a YUV raw file, you can convert it by ffmpeg.
|
||||
2. Run wl-tester in target device and check Wayland Compositor's UI.
|
||||
65
gtk01/gtk01.c
Normal file
65
gtk01/gtk01.c
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright © Jan Newmarch, jan@newmarch.name
|
||||
* https://jan.newmarch.name/Wayland/GTK/
|
||||
*/
|
||||
|
||||
#include <gtk-3.0/gtk/gtk.h>
|
||||
|
||||
gint count = 0;
|
||||
char buf[5];
|
||||
|
||||
void increase(GtkWidget *widget, gpointer label) {
|
||||
count++;
|
||||
|
||||
sprintf(buf, "%d", count);
|
||||
gtk_label_set_text(GTK_LABEL(label), buf);
|
||||
}
|
||||
|
||||
void decrease(GtkWidget *widget, gpointer label) {
|
||||
count--;
|
||||
|
||||
sprintf(buf, "%d", count);
|
||||
gtk_label_set_text(GTK_LABEL(label), buf);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
GtkWidget *label;
|
||||
GtkWidget *window;
|
||||
GtkWidget *frame;
|
||||
GtkWidget *plus;
|
||||
GtkWidget *minus;
|
||||
|
||||
gtk_init(&argc, &argv);
|
||||
|
||||
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
|
||||
gtk_window_set_default_size(GTK_WINDOW(window), 250, 180);
|
||||
gtk_window_set_title(GTK_WINDOW(window), "+-");
|
||||
|
||||
frame = gtk_fixed_new();
|
||||
gtk_container_add(GTK_CONTAINER(window), frame);
|
||||
|
||||
plus = gtk_button_new_with_label("+");
|
||||
gtk_widget_set_size_request(plus, 80, 35);
|
||||
gtk_fixed_put(GTK_FIXED(frame), plus, 50, 20);
|
||||
|
||||
minus = gtk_button_new_with_label("-");
|
||||
gtk_widget_set_size_request(minus, 80, 35);
|
||||
gtk_fixed_put(GTK_FIXED(frame), minus, 50, 80);
|
||||
|
||||
label = gtk_label_new("0");
|
||||
gtk_fixed_put(GTK_FIXED(frame), label, 190, 58);
|
||||
|
||||
gtk_widget_show_all(window);
|
||||
|
||||
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
|
||||
|
||||
g_signal_connect(plus, "clicked", G_CALLBACK(increase), label);
|
||||
|
||||
g_signal_connect(minus, "clicked", G_CALLBACK(decrease), label);
|
||||
|
||||
gtk_main();
|
||||
|
||||
return 0;
|
||||
}
|
||||
9
gtk01/meson.build
Normal file
9
gtk01/meson.build
Normal file
@@ -0,0 +1,9 @@
|
||||
gtk01_sources = files(
|
||||
'gtk01.c',
|
||||
)
|
||||
|
||||
cc = meson.get_compiler('c')
|
||||
dep_gtk3 = dependency('gtk+-3.0', version : '>=3.20')
|
||||
dep_common = [dep_gtk3]
|
||||
|
||||
executable('gtk01', gtk01_sources, dependencies : dep_common, install : true)
|
||||
15
meson.build
Normal file
15
meson.build
Normal file
@@ -0,0 +1,15 @@
|
||||
project(
|
||||
'gfx-examples',
|
||||
'c',
|
||||
version : '0.0.1',
|
||||
license : 'MIT',
|
||||
meson_version : '>= 0.47',
|
||||
default_options : ['c_std=gnu99', 'warning_level=2']
|
||||
)
|
||||
|
||||
if get_option('c_std') != 'gnu99'
|
||||
error('c_std must be gnu99')
|
||||
endif
|
||||
|
||||
subdir('gtk01')
|
||||
subdir('wl-tester')
|
||||
400
wl-tester/buffers.c
Normal file
400
wl-tester/buffers.c
Normal file
@@ -0,0 +1,400 @@
|
||||
/*
|
||||
* Source updates from:
|
||||
* - https://wayland-book.com/xdg-shell-basics/example-code.html
|
||||
* - libdrm's "modetest"
|
||||
*/
|
||||
|
||||
/*
|
||||
* DRM based mode setting test program
|
||||
* Copyright 2008 Tungsten Graphics
|
||||
* Jakob Bornecrantz <jakob@tungstengraphics.com>
|
||||
* Copyright 2008 Intel Corporation
|
||||
* Jesse Barnes <jesse.barnes@intel.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "drm/drm.h"
|
||||
#include "drm/drm_fourcc.h"
|
||||
#include "xf86drm.h"
|
||||
|
||||
#include "buffers.h"
|
||||
|
||||
long int raw_offset = 0;
|
||||
|
||||
static void randname(char *buf) {
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
long r = ts.tv_nsec;
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
buf[i] = 'A' + (r & 15) + (r & 16) * 2;
|
||||
r >>= 5;
|
||||
}
|
||||
}
|
||||
|
||||
static int create_shm_file(void) {
|
||||
int retries = 100;
|
||||
do {
|
||||
char name[] = "/wl_shm-XXXXXX";
|
||||
randname(name + sizeof(name) - 7);
|
||||
--retries;
|
||||
int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||
if (fd >= 0) {
|
||||
shm_unlink(name);
|
||||
return fd;
|
||||
}
|
||||
} while (retries > 0 && errno == EEXIST);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int allocate_shm_file(size_t size) {
|
||||
int fd = create_shm_file();
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
int ret;
|
||||
do {
|
||||
ret = ftruncate(fd, size);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
if (ret < 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int fill_with_raw(FILE *fp, uint32_t width, uint32_t height,
|
||||
uint8_t *data) {
|
||||
fseek(fp, 0, SEEK_END);
|
||||
uint32_t file_size = ftell(fp);
|
||||
uint32_t frame_size = (width * height + 2 * ((width + 1) / 2) * ((height + 1) / 2));
|
||||
fseek(fp, raw_offset, SEEK_SET);
|
||||
|
||||
size_t result = fread(data, 1, frame_size, fp);
|
||||
if (result != frame_size) {
|
||||
fprintf(stderr, "Error reading yuv image\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
raw_offset = raw_offset + frame_size;
|
||||
if (raw_offset >= file_size)
|
||||
raw_offset = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct bo *bo_create_dumb(int fd, unsigned int width,
|
||||
unsigned int height, unsigned int bpp) {
|
||||
struct drm_mode_create_dumb arg;
|
||||
struct bo *bo;
|
||||
int ret;
|
||||
|
||||
bo = calloc(1, sizeof(*bo));
|
||||
if (bo == NULL) {
|
||||
fprintf(stderr, "failed to allocate buffer object\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(&arg, 0, sizeof(arg));
|
||||
arg.bpp = bpp;
|
||||
arg.width = width;
|
||||
arg.height = height;
|
||||
|
||||
ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &arg);
|
||||
if (ret) {
|
||||
fprintf(stderr, "failed to create dumb buffer: %s\n", strerror(errno));
|
||||
free(bo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bo->fd = fd;
|
||||
bo->handle = arg.handle;
|
||||
bo->size = arg.size;
|
||||
bo->pitch = arg.pitch;
|
||||
|
||||
return bo;
|
||||
}
|
||||
|
||||
int bo_map(struct bo *bo, void **out) {
|
||||
struct drm_mode_map_dumb arg;
|
||||
void *map;
|
||||
int ret;
|
||||
|
||||
memset(&arg, 0, sizeof(arg));
|
||||
arg.handle = bo->handle;
|
||||
|
||||
ret = drmIoctl(bo->fd, DRM_IOCTL_MODE_MAP_DUMB, &arg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
map =
|
||||
mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, bo->fd, arg.offset);
|
||||
|
||||
bo->ptr = map;
|
||||
*out = map;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bo_unmap(struct bo *bo) {
|
||||
if (!bo->ptr)
|
||||
return;
|
||||
|
||||
munmap(bo->ptr, bo->size);
|
||||
bo->ptr = NULL;
|
||||
}
|
||||
|
||||
struct bo *bo_create(int fd, unsigned int format, unsigned int width,
|
||||
unsigned int height, unsigned int handles[4],
|
||||
unsigned int pitches[4], unsigned int offsets[4]) {
|
||||
unsigned int virtual_height;
|
||||
struct bo *bo;
|
||||
unsigned int bpp;
|
||||
void *planes[3] = {
|
||||
0,
|
||||
};
|
||||
void *virtual;
|
||||
int ret;
|
||||
|
||||
switch (format) {
|
||||
case DRM_FORMAT_C8:
|
||||
case DRM_FORMAT_NV12:
|
||||
case DRM_FORMAT_NV21:
|
||||
case DRM_FORMAT_NV16:
|
||||
case DRM_FORMAT_NV61:
|
||||
case DRM_FORMAT_YUV420:
|
||||
case DRM_FORMAT_YVU420:
|
||||
bpp = 8;
|
||||
break;
|
||||
|
||||
case DRM_FORMAT_ARGB4444:
|
||||
case DRM_FORMAT_XRGB4444:
|
||||
case DRM_FORMAT_ABGR4444:
|
||||
case DRM_FORMAT_XBGR4444:
|
||||
case DRM_FORMAT_RGBA4444:
|
||||
case DRM_FORMAT_RGBX4444:
|
||||
case DRM_FORMAT_BGRA4444:
|
||||
case DRM_FORMAT_BGRX4444:
|
||||
case DRM_FORMAT_ARGB1555:
|
||||
case DRM_FORMAT_XRGB1555:
|
||||
case DRM_FORMAT_ABGR1555:
|
||||
case DRM_FORMAT_XBGR1555:
|
||||
case DRM_FORMAT_RGBA5551:
|
||||
case DRM_FORMAT_RGBX5551:
|
||||
case DRM_FORMAT_BGRA5551:
|
||||
case DRM_FORMAT_BGRX5551:
|
||||
case DRM_FORMAT_RGB565:
|
||||
case DRM_FORMAT_BGR565:
|
||||
case DRM_FORMAT_UYVY:
|
||||
case DRM_FORMAT_VYUY:
|
||||
case DRM_FORMAT_YUYV:
|
||||
case DRM_FORMAT_YVYU:
|
||||
bpp = 16;
|
||||
break;
|
||||
|
||||
case DRM_FORMAT_BGR888:
|
||||
case DRM_FORMAT_RGB888:
|
||||
bpp = 24;
|
||||
break;
|
||||
|
||||
case DRM_FORMAT_ARGB8888:
|
||||
case DRM_FORMAT_XRGB8888:
|
||||
case DRM_FORMAT_ABGR8888:
|
||||
case DRM_FORMAT_XBGR8888:
|
||||
case DRM_FORMAT_RGBA8888:
|
||||
case DRM_FORMAT_RGBX8888:
|
||||
case DRM_FORMAT_BGRA8888:
|
||||
case DRM_FORMAT_BGRX8888:
|
||||
case DRM_FORMAT_ARGB2101010:
|
||||
case DRM_FORMAT_XRGB2101010:
|
||||
case DRM_FORMAT_ABGR2101010:
|
||||
case DRM_FORMAT_XBGR2101010:
|
||||
case DRM_FORMAT_RGBA1010102:
|
||||
case DRM_FORMAT_RGBX1010102:
|
||||
case DRM_FORMAT_BGRA1010102:
|
||||
case DRM_FORMAT_BGRX1010102:
|
||||
bpp = 32;
|
||||
break;
|
||||
|
||||
case DRM_FORMAT_XRGB16161616F:
|
||||
case DRM_FORMAT_XBGR16161616F:
|
||||
case DRM_FORMAT_ARGB16161616F:
|
||||
case DRM_FORMAT_ABGR16161616F:
|
||||
bpp = 64;
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "unsupported format 0x%08x\n", format);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
case DRM_FORMAT_NV12:
|
||||
case DRM_FORMAT_NV21:
|
||||
case DRM_FORMAT_YUV420:
|
||||
case DRM_FORMAT_YVU420:
|
||||
virtual_height = height * 3 / 2;
|
||||
break;
|
||||
|
||||
case DRM_FORMAT_NV16:
|
||||
case DRM_FORMAT_NV61:
|
||||
virtual_height = height * 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
virtual_height = height;
|
||||
break;
|
||||
}
|
||||
|
||||
bo = bo_create_dumb(fd, width, virtual_height, bpp);
|
||||
if (!bo)
|
||||
return NULL;
|
||||
|
||||
ret = bo_map(bo, &virtual);
|
||||
if (ret) {
|
||||
fprintf(stderr, "failed to map buffer: %s\n", strerror(-errno));
|
||||
bo_destroy(bo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* just testing a limited # of formats to test single
|
||||
* and multi-planar path.. would be nice to add more..
|
||||
*/
|
||||
switch (format) {
|
||||
case DRM_FORMAT_UYVY:
|
||||
case DRM_FORMAT_VYUY:
|
||||
case DRM_FORMAT_YUYV:
|
||||
case DRM_FORMAT_YVYU:
|
||||
offsets[0] = 0;
|
||||
handles[0] = bo->handle;
|
||||
pitches[0] = bo->pitch;
|
||||
|
||||
planes[0] = virtual;
|
||||
break;
|
||||
|
||||
case DRM_FORMAT_NV12:
|
||||
case DRM_FORMAT_NV21:
|
||||
case DRM_FORMAT_NV16:
|
||||
case DRM_FORMAT_NV61:
|
||||
offsets[0] = 0;
|
||||
handles[0] = bo->handle;
|
||||
pitches[0] = bo->pitch;
|
||||
pitches[1] = pitches[0];
|
||||
offsets[1] = pitches[0] * height;
|
||||
handles[1] = bo->handle;
|
||||
|
||||
planes[0] = virtual;
|
||||
planes[1] = virtual + offsets[1];
|
||||
break;
|
||||
|
||||
case DRM_FORMAT_YUV420:
|
||||
case DRM_FORMAT_YVU420:
|
||||
offsets[0] = 0;
|
||||
handles[0] = bo->handle;
|
||||
pitches[0] = bo->pitch;
|
||||
pitches[1] = pitches[0] / 2;
|
||||
offsets[1] = pitches[0] * height;
|
||||
handles[1] = bo->handle;
|
||||
pitches[2] = pitches[1];
|
||||
offsets[2] = offsets[1] + pitches[1] * height / 2;
|
||||
handles[2] = bo->handle;
|
||||
|
||||
planes[0] = virtual;
|
||||
planes[1] = virtual + offsets[1];
|
||||
planes[2] = virtual + offsets[2];
|
||||
break;
|
||||
|
||||
case DRM_FORMAT_C8:
|
||||
case DRM_FORMAT_ARGB4444:
|
||||
case DRM_FORMAT_XRGB4444:
|
||||
case DRM_FORMAT_ABGR4444:
|
||||
case DRM_FORMAT_XBGR4444:
|
||||
case DRM_FORMAT_RGBA4444:
|
||||
case DRM_FORMAT_RGBX4444:
|
||||
case DRM_FORMAT_BGRA4444:
|
||||
case DRM_FORMAT_BGRX4444:
|
||||
case DRM_FORMAT_ARGB1555:
|
||||
case DRM_FORMAT_XRGB1555:
|
||||
case DRM_FORMAT_ABGR1555:
|
||||
case DRM_FORMAT_XBGR1555:
|
||||
case DRM_FORMAT_RGBA5551:
|
||||
case DRM_FORMAT_RGBX5551:
|
||||
case DRM_FORMAT_BGRA5551:
|
||||
case DRM_FORMAT_BGRX5551:
|
||||
case DRM_FORMAT_RGB565:
|
||||
case DRM_FORMAT_BGR565:
|
||||
case DRM_FORMAT_BGR888:
|
||||
case DRM_FORMAT_RGB888:
|
||||
case DRM_FORMAT_ARGB8888:
|
||||
case DRM_FORMAT_XRGB8888:
|
||||
case DRM_FORMAT_ABGR8888:
|
||||
case DRM_FORMAT_XBGR8888:
|
||||
case DRM_FORMAT_RGBA8888:
|
||||
case DRM_FORMAT_RGBX8888:
|
||||
case DRM_FORMAT_BGRA8888:
|
||||
case DRM_FORMAT_BGRX8888:
|
||||
case DRM_FORMAT_ARGB2101010:
|
||||
case DRM_FORMAT_XRGB2101010:
|
||||
case DRM_FORMAT_ABGR2101010:
|
||||
case DRM_FORMAT_XBGR2101010:
|
||||
case DRM_FORMAT_RGBA1010102:
|
||||
case DRM_FORMAT_RGBX1010102:
|
||||
case DRM_FORMAT_BGRA1010102:
|
||||
case DRM_FORMAT_BGRX1010102:
|
||||
case DRM_FORMAT_XRGB16161616F:
|
||||
case DRM_FORMAT_XBGR16161616F:
|
||||
case DRM_FORMAT_ARGB16161616F:
|
||||
case DRM_FORMAT_ABGR16161616F:
|
||||
offsets[0] = 0;
|
||||
handles[0] = bo->handle;
|
||||
pitches[0] = bo->pitch;
|
||||
|
||||
planes[0] = virtual;
|
||||
break;
|
||||
}
|
||||
|
||||
bo_unmap(bo);
|
||||
|
||||
return bo;
|
||||
}
|
||||
|
||||
void bo_destroy(struct bo *bo) {
|
||||
struct drm_mode_destroy_dumb arg;
|
||||
int ret;
|
||||
|
||||
memset(&arg, 0, sizeof(arg));
|
||||
arg.handle = bo->handle;
|
||||
|
||||
ret = drmIoctl(bo->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
|
||||
if (ret)
|
||||
fprintf(stderr, "failed to destroy dumb buffer: %s\n", strerror(errno));
|
||||
|
||||
free(bo);
|
||||
}
|
||||
66
wl-tester/buffers.h
Normal file
66
wl-tester/buffers.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* DRM based mode setting test program
|
||||
* Copyright 2008 Tungsten Graphics
|
||||
* Jakob Bornecrantz <jakob@tungstengraphics.com>
|
||||
* Copyright 2008 Intel Corporation
|
||||
* Jesse Barnes <jesse.barnes@intel.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __BUFFERS_H__
|
||||
#define __BUFFERS_H__
|
||||
|
||||
#define FORMAT_MAX_PLANES 4
|
||||
|
||||
struct fb_buffer {
|
||||
struct wl_buffer *buffer;
|
||||
struct bo *bo;
|
||||
void *buf_vma;
|
||||
bool busy;
|
||||
};
|
||||
|
||||
struct shm_buffer {
|
||||
struct wl_buffer *buffer;
|
||||
struct wl_shm *wl_shm;
|
||||
void *buf_vma;
|
||||
int fd;
|
||||
bool busy;
|
||||
};
|
||||
|
||||
struct bo {
|
||||
int fd;
|
||||
void *ptr;
|
||||
size_t size;
|
||||
size_t offset;
|
||||
size_t pitch;
|
||||
unsigned handle;
|
||||
};
|
||||
|
||||
int allocate_shm_file(size_t size);
|
||||
int fill_with_raw(FILE *fp, uint32_t width, uint32_t height, uint8_t *data);
|
||||
|
||||
int bo_map(struct bo *bo, void **out);
|
||||
void bo_unmap(struct bo *bo);
|
||||
struct bo *bo_create(int fd, unsigned int format, unsigned int width,
|
||||
unsigned int height, unsigned int handles[4],
|
||||
unsigned int pitches[4], unsigned int offsets[4]);
|
||||
void bo_destroy(struct bo *bo);
|
||||
|
||||
#endif
|
||||
506
wl-tester/common.c
Normal file
506
wl-tester/common.c
Normal file
@@ -0,0 +1,506 @@
|
||||
/*
|
||||
* Source updates from:
|
||||
* - https://wayland-book.com/xdg-shell-basics/example-code.html
|
||||
* - weston's clients examples
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "drm/drm.h"
|
||||
#include "drm/drm_fourcc.h"
|
||||
#include "xf86drm.h"
|
||||
|
||||
#include "linux-dmabuf-unstable-v1-client-protocol.h"
|
||||
#include "xdg-shell-client-protocol.h"
|
||||
#include <wayland-client.h>
|
||||
#include "viewporter-client-protocol.h"
|
||||
#include "xdg-output-unstable-v1-client-protocol.h"
|
||||
|
||||
#include "buffers.h"
|
||||
#include "common.h"
|
||||
|
||||
int ms_buf_index = 0;
|
||||
int raw_frame_index = 0;
|
||||
static const int benchmark_interval = 5;
|
||||
|
||||
static void ms_flip(void *data, struct wl_callback *callback, uint32_t time);
|
||||
|
||||
static void wl_buffer_release(void *data, struct wl_buffer *wl_buffer) {
|
||||
}
|
||||
|
||||
const struct wl_buffer_listener wl_buffer_listener = {
|
||||
.release = wl_buffer_release,
|
||||
};
|
||||
|
||||
static void fb_buffer_release(void *data, struct wl_buffer *wl_buffer) {
|
||||
struct fb_buffer *buffer = data;
|
||||
|
||||
buffer->busy = false;
|
||||
}
|
||||
|
||||
const struct wl_buffer_listener fb_buffer_listener = {
|
||||
.release = fb_buffer_release,
|
||||
};
|
||||
|
||||
static void xdg_surface_configure(void *data, struct xdg_surface *xdg_surface,
|
||||
uint32_t serial) {
|
||||
|
||||
struct example_window *window = data;
|
||||
if ( !window->wait_for_configure)
|
||||
return;
|
||||
|
||||
xdg_surface_ack_configure(xdg_surface, serial);
|
||||
|
||||
if (window->initialized && window->wait_for_configure) {
|
||||
ms_flip(data, NULL, 0);
|
||||
}
|
||||
|
||||
window->wait_for_configure = false;
|
||||
}
|
||||
|
||||
const struct xdg_surface_listener xdg_surface_listener = {
|
||||
.configure = xdg_surface_configure,
|
||||
};
|
||||
|
||||
static void xdg_wm_base_ping(void *data, struct xdg_wm_base *xdg_wm_base,
|
||||
uint32_t serial) {
|
||||
xdg_wm_base_pong(xdg_wm_base, serial);
|
||||
}
|
||||
|
||||
const struct xdg_wm_base_listener xdg_wm_base_listener = {
|
||||
.ping = xdg_wm_base_ping,
|
||||
};
|
||||
|
||||
static void dmabuf_modifier(void *data,
|
||||
struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf,
|
||||
uint32_t format, uint32_t modifier_hi,
|
||||
uint32_t modifier_lo) {}
|
||||
|
||||
static void dmabuf_format(void *data,
|
||||
struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf,
|
||||
uint32_t format) {}
|
||||
|
||||
const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {
|
||||
.format = dmabuf_format,
|
||||
.modifier = dmabuf_modifier,
|
||||
};
|
||||
|
||||
/* Start of XDG Output */
|
||||
/* Can got output infos to future usages */
|
||||
|
||||
static void
|
||||
display_handle_geometry(void *data,
|
||||
struct wl_output *wl_output,
|
||||
int x, int y,
|
||||
int physical_width,
|
||||
int physical_height,
|
||||
int subpixel,
|
||||
const char *make,
|
||||
const char *model,
|
||||
int transform)
|
||||
{
|
||||
//printf("YG: x=%d, y=%d, p-width=%d, p-height=%d, subpixel=%d, transform=%d, model=\"%s\"\n", x, y,
|
||||
// physical_width, physical_height, subpixel, transform, model);
|
||||
}
|
||||
|
||||
static void
|
||||
display_handle_done(void *data,
|
||||
struct wl_output *wl_output)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
display_handle_scale(void *data,
|
||||
struct wl_output *wl_output,
|
||||
int32_t scale)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
display_handle_mode(void *data,
|
||||
struct wl_output *wl_output,
|
||||
uint32_t flags,
|
||||
int width,
|
||||
int height,
|
||||
int refresh)
|
||||
{
|
||||
//printf("YG:width=%d, height=%d, flags=%d, refresh=%d\n", width, height, flags, refresh);
|
||||
}
|
||||
|
||||
static const struct wl_output_listener output_listener = {
|
||||
display_handle_geometry,
|
||||
display_handle_mode,
|
||||
display_handle_done,
|
||||
display_handle_scale
|
||||
};
|
||||
|
||||
static void
|
||||
window_add_output(struct example_window *window, uint32_t id)
|
||||
{
|
||||
struct output *output;
|
||||
|
||||
output = malloc(sizeof *output);
|
||||
memset(output, 0, sizeof *output);
|
||||
output->output = wl_registry_bind(window->wl_registry, id, &wl_output_interface, 2);
|
||||
//wl_list_insert(window->output_list.prev, &output->link);
|
||||
|
||||
wl_output_add_listener(output->output, &output_listener, output);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_xdg_output_v1_logical_position(void *data, struct zxdg_output_v1 *output,
|
||||
int32_t x, int32_t y)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
handle_xdg_output_v1_logical_size(void *data, struct zxdg_output_v1 *output,
|
||||
int32_t width, int32_t height)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
handle_xdg_output_v1_done(void *data, struct zxdg_output_v1 *output)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
handle_xdg_output_v1_name(void *data, struct zxdg_output_v1 *output,
|
||||
const char *name)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
handle_xdg_output_v1_description(void *data, struct zxdg_output_v1 *output,
|
||||
const char *description)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct zxdg_output_v1_listener xdg_output_v1_listener = {
|
||||
.logical_position = handle_xdg_output_v1_logical_position,
|
||||
.logical_size = handle_xdg_output_v1_logical_size,
|
||||
.done = handle_xdg_output_v1_done,
|
||||
.name = handle_xdg_output_v1_name,
|
||||
.description = handle_xdg_output_v1_description,
|
||||
};
|
||||
|
||||
static void
|
||||
add_xdg_output_manager_v1_info(struct example_window *window, uint32_t id, uint32_t version)
|
||||
{
|
||||
window->xdg_output_manager = wl_registry_bind(window->wl_registry, id,
|
||||
&zxdg_output_manager_v1_interface, version > 2 ? 2 : version);
|
||||
}
|
||||
/* End of XDG Output */
|
||||
|
||||
static void registry_global(void *data, struct wl_registry *wl_registry,
|
||||
uint32_t name, const char *interface,
|
||||
uint32_t version) {
|
||||
struct example_window *window = data;
|
||||
if (strcmp(interface, wl_shm_interface.name) == 0) {
|
||||
window->ss_buffer.wl_shm = wl_registry_bind(wl_registry, name, &wl_shm_interface, 1);
|
||||
} else if (strcmp(interface, wl_compositor_interface.name) == 0) {
|
||||
window->wl_compositor =
|
||||
wl_registry_bind(wl_registry, name, &wl_compositor_interface, 4);
|
||||
} else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
|
||||
window->xdg_wm_base =
|
||||
wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, 1);
|
||||
xdg_wm_base_add_listener(window->xdg_wm_base, &xdg_wm_base_listener, window);
|
||||
} else if (strcmp(interface, wl_subcompositor_interface.name) == 0) {
|
||||
window->wl_subcompositor =
|
||||
wl_registry_bind(wl_registry, name, &wl_subcompositor_interface, 1);
|
||||
} else if (strcmp(interface, zwp_linux_dmabuf_v1_interface.name) == 0) {
|
||||
window->dmabuf =
|
||||
wl_registry_bind(wl_registry, name, &zwp_linux_dmabuf_v1_interface, 3);
|
||||
zwp_linux_dmabuf_v1_add_listener(window->dmabuf, &dmabuf_listener, window);
|
||||
} else if (strcmp(interface, wl_output_interface.name) == 0) {
|
||||
window_add_output(window, name);
|
||||
} else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0)
|
||||
add_xdg_output_manager_v1_info(window, name, version);
|
||||
}
|
||||
|
||||
static void registry_global_remove(void *data, struct wl_registry *wl_registry,
|
||||
uint32_t name) {}
|
||||
|
||||
const struct wl_registry_listener wl_registry_listener = {
|
||||
.global = registry_global,
|
||||
.global_remove = registry_global_remove,
|
||||
};
|
||||
|
||||
static const struct wl_callback_listener frame_listener = {
|
||||
ms_flip
|
||||
};
|
||||
|
||||
static void ms_flip(void *data, struct wl_callback *callback, uint32_t time) {
|
||||
struct example_window *window = data;
|
||||
|
||||
while(1){
|
||||
if (ms_buf_index >= FB_BUFFER_NUM)
|
||||
ms_buf_index = 0;
|
||||
|
||||
if (!window->ms_buffers[ms_buf_index].busy){
|
||||
break;
|
||||
}
|
||||
ms_buf_index++;
|
||||
}
|
||||
|
||||
if (!window->noread){
|
||||
int ret = fill_with_raw(window->raw_fp, window->width, window->height, (uint8_t *)(window->ms_buffers[ms_buf_index].buf_vma));
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "failed to fill the buf\n");
|
||||
}
|
||||
}
|
||||
|
||||
wl_surface_attach(window->wl_surface, window->ms_buffers[ms_buf_index].buffer, 0, 0);
|
||||
wl_surface_damage(window->wl_surface, 0, 0, window->width, window->height);
|
||||
|
||||
if (callback)
|
||||
wl_callback_destroy(callback);
|
||||
|
||||
window->callback = wl_surface_frame(window->wl_surface);
|
||||
wl_callback_add_listener(window->callback, &frame_listener, window);
|
||||
wl_surface_commit(window->wl_surface);
|
||||
|
||||
window->ms_buffers[ms_buf_index].busy = true;
|
||||
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
time = tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||||
if (window->frames_num == 0)
|
||||
window->benchmark_time = time;
|
||||
|
||||
if (time - window->benchmark_time > (benchmark_interval * 1000)) {
|
||||
printf("%d frames in %d seconds: %f fps\n",
|
||||
window->frames_num,
|
||||
benchmark_interval,
|
||||
(float) window->frames_num / benchmark_interval);
|
||||
window->benchmark_time = time;
|
||||
window->frames_num = 0;
|
||||
}
|
||||
window->frames_num++;
|
||||
return;
|
||||
}
|
||||
|
||||
static void create_succeeded(void *data,
|
||||
struct zwp_linux_buffer_params_v1 *params,
|
||||
struct wl_buffer *new_buffer) {
|
||||
zwp_linux_buffer_params_v1_destroy(params);
|
||||
}
|
||||
|
||||
static void create_failed(void *data,
|
||||
struct zwp_linux_buffer_params_v1 *params) {
|
||||
zwp_linux_buffer_params_v1_destroy(params);
|
||||
fprintf(stderr, "Error: zwp_linux_buffer_params.create failed.\n");
|
||||
}
|
||||
|
||||
static const struct zwp_linux_buffer_params_v1_listener params_listener = {
|
||||
create_succeeded, create_failed};
|
||||
|
||||
|
||||
int init_buffers(struct example_window *window) {
|
||||
int ret = 0;
|
||||
|
||||
window->drm_dev_fd = open(window->drm_node, O_RDWR);
|
||||
if (window->drm_dev_fd < 0) {
|
||||
fprintf(stderr, "failed to open device %s: %s\n", window->drm_node, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
//Init main surface buffers
|
||||
for(int i_buf = 0; i_buf < FB_BUFFER_NUM; i_buf++){
|
||||
uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
|
||||
|
||||
window->ms_buffers[i_buf].bo = bo_create(window->drm_dev_fd, DRM_FORMAT_NV12, window->width, window->height, handles, pitches, offsets);
|
||||
window->ms_buffers[i_buf].busy = false;
|
||||
if (!window->ms_buffers[i_buf].bo) {
|
||||
fprintf(stderr, "failed to create bo\n");
|
||||
close(window->drm_dev_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//TODO: need unmap in handling of exception or exit
|
||||
ret = bo_map(window->ms_buffers[i_buf].bo, &(window->ms_buffers[i_buf].buf_vma));
|
||||
if (ret) {
|
||||
fprintf(stderr, "failed to map buffer: %s\n", strerror(-errno));
|
||||
bo_destroy(window->ms_buffers[i_buf].bo);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct zwp_linux_buffer_params_v1 *params;
|
||||
params = zwp_linux_dmabuf_v1_create_params(window->dmabuf);
|
||||
|
||||
int fd_plane = 0;
|
||||
for (int i = 0; i < FORMAT_MAX_PLANES; ++i) {
|
||||
if (!handles[i])
|
||||
continue;
|
||||
|
||||
int ret = drmPrimeHandleToFD(window->drm_dev_fd, handles[i], 0, &fd_plane);
|
||||
if (ret < 0 || fd_plane < 0) {
|
||||
fprintf(stderr, "error: failed to get dmabuf_fd\n");
|
||||
bo_destroy(window->ms_buffers[i_buf].bo);
|
||||
close(window->drm_dev_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
zwp_linux_buffer_params_v1_add(params, fd_plane, i, offsets[i], pitches[i],
|
||||
DRM_FORMAT_MOD_INVALID >> 32,
|
||||
DRM_FORMAT_MOD_INVALID & 0xffffffff);
|
||||
}
|
||||
|
||||
uint32_t flags = 0;
|
||||
zwp_linux_buffer_params_v1_add_listener(params, ¶ms_listener, window);
|
||||
window->ms_buffers[i_buf].buffer = zwp_linux_buffer_params_v1_create_immed(params, window->width, window->height, WL_SHM_FORMAT_NV12, flags);
|
||||
wl_buffer_add_listener(window->ms_buffers[i_buf].buffer, &fb_buffer_listener, &(window->ms_buffers[i_buf]));
|
||||
}
|
||||
|
||||
//Init sub surface buffers
|
||||
if (window->show_bar) {
|
||||
int ss_stride = window->width * 4;
|
||||
int ss_height = window->width/5;
|
||||
int ss_size = ss_stride * (ss_height);
|
||||
|
||||
if (window->ss_usedma){
|
||||
uint32_t ss_handles[4] = {0}, ss_pitches[4] = {0}, ss_offsets[4] = {0};
|
||||
//Using BGR as DMA Buf in Light can't support RGB
|
||||
struct bo *ss_bo = bo_create(window->drm_dev_fd, DRM_FORMAT_ARGB8888, window->width, ss_height, ss_handles, ss_pitches, ss_offsets);
|
||||
if (!ss_bo) {
|
||||
fprintf(stderr, "failed to create ss_bo\n");
|
||||
close(window->drm_dev_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = bo_map(ss_bo, &(window->ss_buffer.buf_vma));
|
||||
if (ret) {
|
||||
fprintf(stderr, "failed to map buffer: %s\n", strerror(-errno));
|
||||
bo_destroy(ss_bo);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct zwp_linux_buffer_params_v1 *ss_params;
|
||||
ss_params = zwp_linux_dmabuf_v1_create_params(window->dmabuf);
|
||||
|
||||
int ss_fd_plane = 0;
|
||||
for (int i = 0; i < FORMAT_MAX_PLANES; ++i) {
|
||||
if (!ss_handles[i])
|
||||
continue;
|
||||
|
||||
ret = drmPrimeHandleToFD(window->drm_dev_fd, ss_handles[i], 0, &ss_fd_plane);
|
||||
if (ret < 0 || ss_fd_plane < 0) {
|
||||
fprintf(stderr, "error: failed to get ss dmabuf fd\n");
|
||||
bo_destroy(ss_bo);
|
||||
close(window->drm_dev_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
zwp_linux_buffer_params_v1_add(ss_params, ss_fd_plane, i, ss_offsets[i], ss_pitches[i],
|
||||
DRM_FORMAT_MOD_INVALID >> 32,
|
||||
DRM_FORMAT_MOD_INVALID & 0xffffffff);
|
||||
}
|
||||
|
||||
uint32_t ss_flags = 0;
|
||||
zwp_linux_buffer_params_v1_add_listener(ss_params, ¶ms_listener, window);
|
||||
window->ss_buffer.buffer = zwp_linux_buffer_params_v1_create_immed(ss_params, window->width,
|
||||
ss_height, 0x34325241, ss_flags);
|
||||
} else {
|
||||
window->ss_buffer.fd = allocate_shm_file(ss_size);
|
||||
if (window->ss_buffer.fd == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct wl_shm_pool *pool = wl_shm_create_pool(window->ss_buffer.wl_shm, window->ss_buffer.fd, ss_size);
|
||||
window->ss_buffer.buffer = wl_shm_pool_create_buffer(pool, 0, window->width, ss_height, ss_stride, WL_SHM_FORMAT_XRGB8888);
|
||||
wl_shm_pool_destroy(pool);
|
||||
|
||||
window->ss_buffer.buf_vma = mmap(NULL, ss_size, PROT_READ | PROT_WRITE, MAP_SHARED, window->ss_buffer.fd, 0);
|
||||
if (window->ss_buffer.buf_vma == MAP_FAILED) {
|
||||
close(window->ss_buffer.fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//Start fill sub surface buffer
|
||||
for (int y = 0; y < ss_height; ++y) {
|
||||
for (int x = 0; x < window->width; ++x) {
|
||||
if ((x + y / 8 * 8) % 16 < 8)
|
||||
((uint32_t *)window->ss_buffer.buf_vma)[y * window->width + x] = 0xFF666666;
|
||||
else
|
||||
((uint32_t *)window->ss_buffer.buf_vma)[y * window->width + x] = 0xFFEEEEEE;
|
||||
}
|
||||
}
|
||||
|
||||
munmap(window->ss_buffer.buf_vma, ss_size);
|
||||
|
||||
wl_surface_attach(window->wl_subsurface, window->ss_buffer.buffer, 0, 0);
|
||||
wl_surface_damage(window->wl_subsurface, 0, 0, window->width, ss_height);
|
||||
wl_surface_commit(window->wl_subsurface);
|
||||
wl_buffer_add_listener(window->ss_buffer.buffer, &wl_buffer_listener, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int init_window(struct example_window *window) {
|
||||
|
||||
window->frames_num = 0;
|
||||
window->wl_display = wl_display_connect(NULL);
|
||||
window->wl_registry = wl_display_get_registry(window->wl_display);
|
||||
wl_registry_add_listener(window->wl_registry, &wl_registry_listener, window);
|
||||
wl_display_roundtrip(window->wl_display);
|
||||
|
||||
window->wl_surface = wl_compositor_create_surface(window->wl_compositor);
|
||||
window->wl_subsurface =
|
||||
wl_compositor_create_surface(window->wl_compositor);
|
||||
window->subsurface = wl_subcompositor_get_subsurface(
|
||||
window->wl_subcompositor, window->wl_subsurface, window->wl_surface);
|
||||
|
||||
//we are using xdg_surface_set_window_geometry() to set window position now.
|
||||
//wl_subsurface_set_position(window->subsurface, window->x, window->y);
|
||||
|
||||
window->xdg_surface =
|
||||
xdg_wm_base_get_xdg_surface(window->xdg_wm_base, window->wl_surface);
|
||||
xdg_surface_add_listener(window->xdg_surface, &xdg_surface_listener, window);
|
||||
window->xdg_toplevel = xdg_surface_get_toplevel(window->xdg_surface);
|
||||
xdg_toplevel_set_title(window->xdg_toplevel,
|
||||
"Graphics Wayland Buf Display Example");
|
||||
xdg_toplevel_set_app_id(window->xdg_toplevel, "wl-tester");
|
||||
xdg_surface_set_window_geometry(window->xdg_surface, window->x, window->y, window->width, window->height);
|
||||
|
||||
//Not sure if it is workable?
|
||||
//xdg_toplevel_set_fullscreen();
|
||||
|
||||
window->wait_for_configure = true;
|
||||
if (window->sync)
|
||||
wl_subsurface_set_sync(window->subsurface);
|
||||
else
|
||||
wl_subsurface_set_desync(window->subsurface);
|
||||
|
||||
wl_surface_commit(window->wl_surface);
|
||||
|
||||
int ret = init_buffers(window);
|
||||
if (ret != 0){
|
||||
fprintf(stderr, "Error init buffers\n");
|
||||
return -1;
|
||||
}
|
||||
wl_display_roundtrip(window->wl_display);
|
||||
|
||||
if (!window->wait_for_configure){
|
||||
ms_flip(window, NULL, 0);
|
||||
}
|
||||
window->initialized = true;
|
||||
|
||||
while (wl_display_dispatch(window->wl_display)) {
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
47
wl-tester/common.h
Normal file
47
wl-tester/common.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifndef TESTER_COMMON_H
|
||||
#define TESTER_COMMON_H
|
||||
|
||||
#define FB_BUFFER_NUM 3
|
||||
|
||||
struct output {
|
||||
struct wl_output *output;
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
struct example_window {
|
||||
struct wl_display *wl_display;
|
||||
char *drm_node;
|
||||
int drm_dev_fd;
|
||||
int width;
|
||||
int height;
|
||||
struct fb_buffer ms_buffers[FB_BUFFER_NUM];
|
||||
char *raw_file;
|
||||
FILE *raw_fp;
|
||||
struct shm_buffer ss_buffer;
|
||||
int x;
|
||||
int y;
|
||||
struct wl_registry *wl_registry;
|
||||
struct wl_compositor *wl_compositor;
|
||||
struct wl_subcompositor *wl_subcompositor;
|
||||
struct xdg_wm_base *xdg_wm_base;
|
||||
struct wl_surface *wl_surface;
|
||||
struct wl_surface *wl_subsurface;
|
||||
struct wl_subsurface *subsurface;
|
||||
struct xdg_surface *xdg_surface;
|
||||
struct xdg_toplevel *xdg_toplevel;
|
||||
struct zwp_linux_dmabuf_v1 *dmabuf;
|
||||
struct wl_callback *callback;
|
||||
bool wait_for_configure;
|
||||
bool initialized;
|
||||
uint32_t frames_num;
|
||||
uint32_t benchmark_time;
|
||||
bool show_bar;
|
||||
bool sync;
|
||||
bool noread;
|
||||
bool ss_usedma;
|
||||
struct wl_list output_list;
|
||||
struct zxdg_output_manager_v1 *xdg_output_manager;
|
||||
};
|
||||
|
||||
int init_window(struct example_window *window);
|
||||
#endif
|
||||
41
wl-tester/meson.build
Normal file
41
wl-tester/meson.build
Normal file
@@ -0,0 +1,41 @@
|
||||
tester_sources = files(
|
||||
'tester.c',
|
||||
'common.c',
|
||||
'buffers.c',
|
||||
)
|
||||
|
||||
cc = meson.get_compiler('c')
|
||||
wl_req = '>= 1.15'
|
||||
wl_scanner = find_program('wayland-scanner')
|
||||
drm_dep = dependency('libdrm')
|
||||
rt_dep = cc.find_library('rt', required: false)
|
||||
wl_client_dep = dependency('wayland-client', version: wl_req)
|
||||
wl_protocol_dep = dependency('wayland-protocols', version: wl_req)
|
||||
|
||||
protocols_datadir = wl_protocol_dep.get_pkgconfig_variable('pkgdatadir')
|
||||
protocol_defs = [
|
||||
['/stable/viewporter/viewporter.xml', 'viewporter-protocol.c', 'viewporter-client-protocol.h'],
|
||||
['/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml',
|
||||
'linux-dmabuf-unstable-v1-protocol.c', 'linux-dmabuf-unstable-v1-client-protocol.h'],
|
||||
['/unstable/xdg-output/xdg-output-unstable-v1.xml',
|
||||
'xdg-output-unstable-v1-protocol.c', 'xdg-output-unstable-v1-client-protocol.h'],
|
||||
['/stable/xdg-shell/xdg-shell.xml', 'xdg-shell-protocol.c', 'xdg-shell-client-protocol.h'],
|
||||
]
|
||||
protocols_files = []
|
||||
|
||||
foreach protodef: protocol_defs
|
||||
xmlfile = protocols_datadir + protodef.get(0)
|
||||
|
||||
protocols_files += [custom_target(protodef.get(1),
|
||||
output : protodef.get(1),
|
||||
input : xmlfile,
|
||||
command : [wl_scanner, 'code', '@INPUT@', '@OUTPUT@'])]
|
||||
|
||||
protocols_files += [custom_target(protodef.get(2),
|
||||
output : protodef.get(2),
|
||||
input : xmlfile,
|
||||
command : [wl_scanner, 'client-header', '@INPUT@', '@OUTPUT@'])]
|
||||
endforeach
|
||||
|
||||
dep_common = [drm_dep, rt_dep, wl_client_dep, wl_protocol_dep]
|
||||
wl_tester = executable('wl-tester', tester_sources + protocols_files, dependencies : dep_common, install : true)
|
||||
107
wl-tester/tester.c
Normal file
107
wl-tester/tester.c
Normal file
@@ -0,0 +1,107 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#include "buffers.h"
|
||||
#include "common.h"
|
||||
|
||||
static void print_usage_and_exit(void) {
|
||||
printf("Usages:\n\n"
|
||||
"wl-tester -d /dev/dri/card0 -w 1280 -h 720 -f /path-to/test.yuv -x 100 -y 200 -s -b\n\n"
|
||||
"\t-d: DRM device node path\n"
|
||||
"\t-w: RAW YUV file's width\n"
|
||||
"\t-h: RAW YUV file's height\n"
|
||||
"\t-f: RAW YUV file's path\n"
|
||||
"\t-x: Window Surface's x position if compositor supports window position\n"
|
||||
"\t-y: Window Surface's y position if compositor supports window position\n"
|
||||
"\t-b: Show Sub Surface/bar\n"
|
||||
"\t-s: sync mode of sub surface\n"
|
||||
"\t-n: not read YUV file in loop, for perf debug purpose\n"
|
||||
"\t-u: Sub Surface use DMA Buf also, default is using Share Memory\n"
|
||||
);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct example_window window = {0};
|
||||
int c, option_index;
|
||||
int ret = 0;
|
||||
char default_drm_node[32] = "/dev/dri/card0";
|
||||
|
||||
window.drm_node = default_drm_node;
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"drm-node", required_argument, 0, 'd'},
|
||||
{"raw-file", required_argument, 0, 'f'},
|
||||
{"width", required_argument, 0, 'w'},
|
||||
{"height", required_argument, 0, 'h'},
|
||||
{"sx", required_argument, 0, 'x'},
|
||||
{"sy", required_argument, 0, 'y'},
|
||||
{"show-bar", no_argument, NULL, 'b'},
|
||||
{"sync", no_argument, NULL, 's'},
|
||||
{"noread", no_argument, NULL, 'n'},
|
||||
{"ss-usedma", no_argument, NULL, 'u'},
|
||||
{"help", no_argument, 0, 0},
|
||||
{0, 0, 0, 0}};
|
||||
|
||||
while ((c = getopt_long(argc, argv, "bsnud:f:w:h:x:y:", long_options, &option_index)) !=
|
||||
-1) {
|
||||
switch (c) {
|
||||
case 'w':
|
||||
window.width = atoi(optarg);
|
||||
break;
|
||||
case 'h':
|
||||
window.height = atoi(optarg);
|
||||
break;
|
||||
case 'x':
|
||||
window.x = atoi(optarg);
|
||||
break;
|
||||
case 'y':
|
||||
window.y = atoi(optarg);
|
||||
break;
|
||||
case 'd':
|
||||
window.drm_node = optarg;
|
||||
break;
|
||||
case 'f':
|
||||
window.raw_file = optarg;
|
||||
break;
|
||||
case 's':
|
||||
window.sync = true;
|
||||
break;
|
||||
case 'n':
|
||||
window.noread = true;
|
||||
break;
|
||||
case 'u':
|
||||
window.ss_usedma = true;
|
||||
break;
|
||||
case 'b':
|
||||
window.show_bar = true;
|
||||
break;
|
||||
default:
|
||||
print_usage_and_exit();
|
||||
}
|
||||
}
|
||||
|
||||
window.raw_fp = fopen(window.raw_file, "rb");
|
||||
if (!window.raw_fp) {
|
||||
fprintf(stderr, "Error opening yuv image for read\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = init_window(&window);
|
||||
if (ret){
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user