Introduce intel-gpu-overlay

A realtime display of GPU activity. Note, this is just at the point of
minimum usability...

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
Chris Wilson 2013-08-17 11:12:07 +01:00
parent 7df9caeea1
commit f9a50de3dc
21 changed files with 1757 additions and 1 deletions

View File

@ -21,7 +21,7 @@
ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} -I m4 ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} -I m4
SUBDIRS = lib man tools scripts benchmarks demos SUBDIRS = lib man tools scripts benchmarks demos overlay
if BUILD_ASSEMBLER if BUILD_ASSEMBLER
SUBDIRS += assembler SUBDIRS += assembler

View File

@ -72,6 +72,9 @@ AC_SUBST(ASSEMBLER_WARN_CFLAGS)
PKG_CHECK_MODULES(DRM, [libdrm_intel >= 2.4.45 libdrm]) PKG_CHECK_MODULES(DRM, [libdrm_intel >= 2.4.45 libdrm])
PKG_CHECK_MODULES(PCIACCESS, [pciaccess >= 0.10]) PKG_CHECK_MODULES(PCIACCESS, [pciaccess >= 0.10])
PKG_CHECK_MODULES(OVERLAY, [xv x11 xext], enable_overlay=yes, enable_overlay=no)
AM_CONDITIONAL(BUILD_OVERLAY, [test "x$enable_overlay" = xyes])
# for testdisplay # for testdisplay
PKG_CHECK_MODULES(CAIRO, [cairo >= 1.12.0]) PKG_CHECK_MODULES(CAIRO, [cairo >= 1.12.0])
@ -184,6 +187,7 @@ AC_CONFIG_FILES([
assembler/doc/Makefile assembler/doc/Makefile
assembler/test/Makefile assembler/test/Makefile
assembler/intel-gen4asm.pc assembler/intel-gen4asm.pc
overlay/Makefile
]) ])
AC_OUTPUT AC_OUTPUT
@ -200,6 +204,7 @@ echo " • Tools:"
echo " Assembler : ${enable_assembler}" echo " Assembler : ${enable_assembler}"
echo " Debugger : ${enable_debugger}" echo " Debugger : ${enable_debugger}"
echo " Python dumper : ${DUMPER}" echo " Python dumper : ${DUMPER}"
echo " Overlay : ${enable_overlay}"
echo "" echo ""
# vim: set ft=config ts=8 sw=8 tw=0 noet : # vim: set ft=config ts=8 sw=8 tw=0 noet :

1
overlay/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
intel-gpu-overlay

28
overlay/Makefile.am Normal file
View File

@ -0,0 +1,28 @@
if BUILD_OVERLAY
bin_PROGRAMS = intel-gpu-overlay
endif
AM_CPPFLAGS = -I.
AM_CFLAGS = $(DRM_CFLAGS) $(PCIACCESS_CFLAGS) $(CWARNFLAGS) $(CAIRO_CFLAGS) $(OVERLAY_CFLAGS)
LDADD = $(DRM_LIBS) $(PCIACCESS_LIBS) $(CAIRO_LIBS) $(OVERLAY_LIBS)
intel_gpu_overlay_SOURCES = \
i915_pciids.h \
overlay.h \
overlay.c \
chart.h \
chart.c \
gem-objects.h \
gem-objects.c \
gpu-top.h \
gpu-top.c \
igfx.h \
igfx.c \
x11/dri2.c \
x11/dri2.h \
x11/rgb2yuv.c \
x11/rgb2yuv.h \
x11/x11-overlay.c \
$(NULL)
EXTRA_DIST=README

8
overlay/README Normal file
View File

@ -0,0 +1,8 @@
This is a simple overlay showing current GPU activity. An asynchronous
overlay is used, rendered by the CPU to avoid introducing any extra work
on the GPU that we wish to monitor.
The x11-overlay backend requires xf86-video-intel 2.21.15 or later, with
SNA enabled.
As it requires access to debug information, it needs to be run as root.

135
overlay/chart.c Normal file
View File

@ -0,0 +1,135 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <cairo.h>
#include <stdio.h>
#include "chart.h"
int chart_init(struct chart *chart, const char *name, int num_samples)
{
memset(chart, 0, sizeof(*chart));
chart->name = name;
chart->samples = malloc(sizeof(*chart->samples)*num_samples);
if (chart->samples == NULL)
return ENOMEM;
chart->num_samples = num_samples;
chart->range_automatic = 1;
return 0;
}
void chart_set_rgba(struct chart *chart, float red, float green, float blue, float alpha)
{
chart->rgb[0] = red;
chart->rgb[1] = green;
chart->rgb[2] = blue;
chart->rgb[3] = alpha;
}
void chart_set_position(struct chart *chart, int x, int y)
{
chart->x = x;
chart->y = y;
}
void chart_set_size(struct chart *chart, int w, int h)
{
chart->w = w;
chart->h = h;
}
void chart_set_range(struct chart *chart, double min, double max)
{
chart->range[0] = min;
chart->range[1] = max;
chart->range_automatic = 0;
}
void chart_add_sample(struct chart *chart, double value)
{
int pos;
pos = chart->current_sample % chart->num_samples;
chart->samples[pos] = value;
chart->current_sample++;
}
static void chart_update_range(struct chart *chart)
{
int n, max = chart->current_sample;
if (max > chart->num_samples)
max = chart->num_samples;
chart->range[0] = chart->range[1] = chart->samples[0];
for (n = 1; n < max; n++) {
if (chart->samples[n] < chart->range[0])
chart->range[0] = chart->samples[n];
else if (chart->samples[n] > chart->range[1])
chart->range[1] = chart->samples[n];
}
}
static double value_at(struct chart *chart, int n)
{
if (n <= chart->current_sample - chart->num_samples)
n = chart->current_sample;
else if (n >= chart->current_sample)
n = chart->current_sample - 1;
return chart->samples[n % chart->num_samples];
}
static double gradient_at(struct chart *chart, int n)
{
double y0, y1;
y0 = value_at(chart, n-1);
y1 = value_at(chart, n+1);
return (y1 - y0) / 2.;
}
void chart_draw(struct chart *chart, cairo_t *cr)
{
int i, n, max, x;
if (chart->current_sample == 0)
return;
if (chart->range_automatic)
chart_update_range(chart);
cairo_save(cr);
cairo_translate(cr, chart->x, chart->y + chart->h);
cairo_scale(cr,
chart->w / (double)chart->num_samples,
-chart->h / (chart->range[1] - chart->range[0]));
x = 0;
max = chart->current_sample;
if (max >= chart->num_samples) {
max = chart->num_samples;
i = chart->current_sample - max;
} else {
i = 0;
x = chart->num_samples - max;
}
cairo_translate(cr, x, -chart->range[0]);
cairo_new_path(cr);
for (n = 0; n < max; n++) {
cairo_curve_to(cr,
n-2/3., value_at(chart, i + n -1) + gradient_at(chart, i + n - 1)/3.,
n-1/3., value_at(chart, i + n) - gradient_at(chart, i + n)/3.,
n, value_at(chart, i + n));
}
cairo_identity_matrix(cr);
cairo_set_line_width(cr, 1);
cairo_set_source_rgba(cr, chart->rgb[0], chart->rgb[1], chart->rgb[2], chart->rgb[3]);
cairo_stroke(cr);
cairo_restore(cr);
}

18
overlay/chart.h Normal file
View File

@ -0,0 +1,18 @@
struct chart {
const char *name;
int x, y, w, h;
int num_samples;
int current_sample;
int range_automatic;
float rgb[4];
double range[2];
double *samples;
};
int chart_init(struct chart *chart, const char *name, int num_samples);
void chart_set_rgba(struct chart *chart, float red, float green, float blue, float alpha);
void chart_set_position(struct chart *chart, int x, int y);
void chart_set_size(struct chart *chart, int w, int h);
void chart_set_range(struct chart *chart, double min, double max);
void chart_add_sample(struct chart *chart, double value);
void chart_draw(struct chart *chart, cairo_t *cr);

19
overlay/gem-objects.c Normal file
View File

@ -0,0 +1,19 @@
#include <unistd.h>
#include <fcntl.h>
#include "gem-objects.h"
int gem_objects_update(char *buf, int buflen)
{
int fd, len = -1;
fd = open("/sys/kernel/debug/dri/0/i915_gem_objects", 0);
if (fd >= 0) {
len = read(fd, buf, buflen-1);
if (len >= 0)
buf[len] = '\0';
close(fd);
}
return len;
}

1
overlay/gem-objects.h Normal file
View File

@ -0,0 +1 @@
int gem_objects_update(char *buf, int buflen);

178
overlay/gpu-top.c Normal file
View File

@ -0,0 +1,178 @@
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include "igfx.h"
#include "gpu-top.h"
#define RING_TAIL 0x00
#define RING_HEAD 0x04
#define ADDR_MASK 0x001FFFFC
#define RING_CTL 0x0C
#define RING_WAIT (1<<11)
#define RING_WAIT_SEMAPHORE (1<<10)
struct ring {
int id;
uint32_t mmio;
int idle, wait, sema;
};
static void *mmio;
static uint32_t ring_read(struct ring *ring, uint32_t reg)
{
return igfx_read(mmio, ring->mmio + reg);
}
static void ring_init(struct ring *ring)
{
uint32_t ctl;
ctl = ring_read(ring, RING_CTL);
if ((ctl & 1) == 0)
ring->id = -1;
}
static void ring_reset(struct ring *ring)
{
ring->idle = 0;
ring->wait = 0;
ring->sema = 0;
}
static void ring_sample(struct ring *ring)
{
uint32_t head, tail, ctl;
if (ring->id == -1)
return;
head = ring_read(ring, RING_HEAD) & ADDR_MASK;
tail = ring_read(ring, RING_TAIL) & ADDR_MASK;
ring->idle += head == tail;
ctl = ring_read(ring, RING_CTL);
ring->wait += !!(ctl & RING_WAIT);
ring->sema += !!(ctl & RING_WAIT_SEMAPHORE);
}
static void ring_emit(struct ring *ring, int samples, union gpu_top_payload *payload)
{
if (ring->id == -1)
return;
payload[ring->id].u.busy = 100 - 100 * ring->idle / samples;
payload[ring->id].u.wait = 100 * ring->wait / samples;
payload[ring->id].u.sema = 100 * ring->sema / samples;
}
void gpu_top_init(struct gpu_top *gt)
{
struct ring render_ring = {
.mmio = 0x2030,
.id = 0,
}, bsd_ring = {
.mmio = 0x4030,
.id = 1,
}, bsd6_ring = {
.mmio = 0x12030,
.id = 1,
}, blt_ring = {
.mmio = 0x22030,
.id = 2,
};
const struct igfx_info *info;
struct pci_device *igfx;
int fd[2], i;
memset(gt, 0, sizeof(*gt));
gt->fd = -1;
igfx = igfx_get();
if (!igfx)
return;
if (pipe(fd) < 0)
return;
info = igfx_get_info(igfx);
switch (fork()) {
case -1: return;
default:
fcntl(fd[0], F_SETFL, fcntl(fd[0], F_GETFL) | O_NONBLOCK);
gt->fd = fd[0];
gt->ring[0].name = "render";
gt->num_rings = 1;
if (info->gen >= 040) {
gt->ring[1].name = "bitstream";
gt->num_rings++;
}
if (info->gen >= 060) {
gt->ring[2].name = "blt";
gt->num_rings++;
}
close(fd[1]);
return;
case 0:
close(fd[0]);
break;
}
mmio = igfx_get_mmio(igfx);
ring_init(&render_ring);
if (info->gen >= 060) {
ring_init(&bsd6_ring);
ring_init(&blt_ring);
} else if (info->gen >= 040) {
ring_init(&bsd_ring);
}
for (;;) {
union gpu_top_payload payload[MAX_RINGS];
ring_reset(&render_ring);
ring_reset(&bsd_ring);
ring_reset(&bsd6_ring);
ring_reset(&blt_ring);
for (i = 0; i < 1000; i++) {
ring_sample(&render_ring);
ring_sample(&bsd_ring);
ring_sample(&bsd6_ring);
ring_sample(&blt_ring);
usleep(1000);
}
ring_emit(&render_ring, 1000, payload);
ring_emit(&bsd_ring, 1000, payload);
ring_emit(&bsd6_ring, 1000, payload);
ring_emit(&blt_ring, 1000, payload);
write(fd[1], payload, sizeof(payload));
}
}
int gpu_top_update(struct gpu_top *gt)
{
uint32_t data[1024];
int len, update = 0;
if (gt->fd < 0)
return update;
while ((len = read(gt->fd, data, sizeof(data))) > 0) {
uint32_t *ptr = &data[len/sizeof(uint32_t) - MAX_RINGS];
gt->ring[0].u.payload = ptr[0];
gt->ring[1].u.payload = ptr[1];
gt->ring[2].u.payload = ptr[2];
gt->ring[3].u.payload = ptr[3];
update = 1;
}
return update;
}

22
overlay/gpu-top.h Normal file
View File

@ -0,0 +1,22 @@
#define MAX_RINGS 4
#include <stdint.h>
struct gpu_top {
int fd;
int num_rings;
struct gpu_top_ring {
const char *name;
union gpu_top_payload {
struct {
uint8_t busy;
uint8_t wait;
uint8_t sema;
} u;
uint32_t payload;
} u;
} ring[MAX_RINGS];
};
void gpu_top_init(struct gpu_top *gt);
int gpu_top_update(struct gpu_top *gt);

211
overlay/i915_pciids.h Normal file
View File

@ -0,0 +1,211 @@
/*
* Copyright 2013 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 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 _I915_PCIIDS_H
#define _I915_PCIIDS_H
/*
* A pci_device_id struct {
* __u32 vendor, device;
* __u32 subvendor, subdevice;
* __u32 class, class_mask;
* kernel_ulong_t driver_data;
* };
* Don't use C99 here because "class" is reserved and we want to
* give userspace flexibility.
*/
#define INTEL_VGA_DEVICE(id, info) { \
0x8086, id, \
~0, ~0, \
0x030000, 0xff0000, \
(unsigned long) info }
#define INTEL_QUANTA_VGA_DEVICE(info) { \
0x8086, 0x16a, \
0x152d, 0x8990, \
0x030000, 0xff0000, \
(unsigned long) info }
#define INTEL_I830_IDS(info) \
INTEL_VGA_DEVICE(0x3577, info)
#define INTEL_I845G_IDS(info) \
INTEL_VGA_DEVICE(0x2562, info)
#define INTEL_I85X_IDS(info) \
INTEL_VGA_DEVICE(0x3582, info), /* I855_GM */ \
INTEL_VGA_DEVICE(0x358e, info)
#define INTEL_I865G_IDS(info) \
INTEL_VGA_DEVICE(0x2572, info) /* I865_G */
#define INTEL_I915G_IDS(info) \
INTEL_VGA_DEVICE(0x2582, info), /* I915_G */ \
INTEL_VGA_DEVICE(0x258a, info) /* E7221_G */
#define INTEL_I915GM_IDS(info) \
INTEL_VGA_DEVICE(0x2592, info) /* I915_GM */
#define INTEL_I945G_IDS(info) \
INTEL_VGA_DEVICE(0x2772, info) /* I945_G */
#define INTEL_I945GM_IDS(info) \
INTEL_VGA_DEVICE(0x27a2, info), /* I945_GM */ \
INTEL_VGA_DEVICE(0x27ae, info) /* I945_GME */
#define INTEL_I965G_IDS(info) \
INTEL_VGA_DEVICE(0x2972, info), /* I946_GZ */ \
INTEL_VGA_DEVICE(0x2982, info), /* G35_G */ \
INTEL_VGA_DEVICE(0x2992, info), /* I965_Q */ \
INTEL_VGA_DEVICE(0x29a2, info) /* I965_G */
#define INTEL_G33_IDS(info) \
INTEL_VGA_DEVICE(0x29b2, info), /* Q35_G */ \
INTEL_VGA_DEVICE(0x29c2, info), /* G33_G */ \
INTEL_VGA_DEVICE(0x29d2, info) /* Q33_G */
#define INTEL_I965GM_IDS(info) \
INTEL_VGA_DEVICE(0x2a02, info), /* I965_GM */ \
INTEL_VGA_DEVICE(0x2a12, info) /* I965_GME */
#define INTEL_GM45_IDS(info) \
INTEL_VGA_DEVICE(0x2a42, info) /* GM45_G */
#define INTEL_G45_IDS(info) \
INTEL_VGA_DEVICE(0x2e02, info), /* IGD_E_G */ \
INTEL_VGA_DEVICE(0x2e12, info), /* Q45_G */ \
INTEL_VGA_DEVICE(0x2e22, info), /* G45_G */ \
INTEL_VGA_DEVICE(0x2e32, info), /* G41_G */ \
INTEL_VGA_DEVICE(0x2e42, info), /* B43_G */ \
INTEL_VGA_DEVICE(0x2e92, info) /* B43_G.1 */
#define INTEL_PINEVIEW_IDS(info) \
INTEL_VGA_DEVICE(0xa001, info), \
INTEL_VGA_DEVICE(0xa011, info)
#define INTEL_IRONLAKE_D_IDS(info) \
INTEL_VGA_DEVICE(0x0042, info)
#define INTEL_IRONLAKE_M_IDS(info) \
INTEL_VGA_DEVICE(0x0046, info)
#define INTEL_SNB_D_IDS(info) \
INTEL_VGA_DEVICE(0x0102, info), \
INTEL_VGA_DEVICE(0x0112, info), \
INTEL_VGA_DEVICE(0x0122, info), \
INTEL_VGA_DEVICE(0x010A, info)
#define INTEL_SNB_M_IDS(info) \
INTEL_VGA_DEVICE(0x0106, info), \
INTEL_VGA_DEVICE(0x0116, info), \
INTEL_VGA_DEVICE(0x0126, info)
#define INTEL_IVB_M_IDS(info) \
INTEL_VGA_DEVICE(0x0156, info), /* GT1 mobile */ \
INTEL_VGA_DEVICE(0x0166, info) /* GT2 mobile */
#define INTEL_IVB_D_IDS(info) \
INTEL_VGA_DEVICE(0x0152, info), /* GT1 desktop */ \
INTEL_VGA_DEVICE(0x0162, info), /* GT2 desktop */ \
INTEL_VGA_DEVICE(0x015a, info), /* GT1 server */ \
INTEL_VGA_DEVICE(0x016a, info) /* GT2 server */
#define INTEL_IVB_Q_IDS(info) \
INTEL_QUANTA_VGA_DEVICE(info) /* Quanta transcode */
#define INTEL_HSW_D_IDS(info) \
INTEL_VGA_DEVICE(0x0402, info), /* GT1 desktop */ \
INTEL_VGA_DEVICE(0x0412, info), /* GT2 desktop */ \
INTEL_VGA_DEVICE(0x0422, info), /* GT3 desktop */ \
INTEL_VGA_DEVICE(0x040a, info), /* GT1 server */ \
INTEL_VGA_DEVICE(0x041a, info), /* GT2 server */ \
INTEL_VGA_DEVICE(0x042a, info), /* GT3 server */ \
INTEL_VGA_DEVICE(0x040B, info), /* GT1 reserved */ \
INTEL_VGA_DEVICE(0x041B, info), /* GT2 reserved */ \
INTEL_VGA_DEVICE(0x042B, info), /* GT3 reserved */ \
INTEL_VGA_DEVICE(0x040E, info), /* GT1 reserved */ \
INTEL_VGA_DEVICE(0x041E, info), /* GT2 reserved */ \
INTEL_VGA_DEVICE(0x042E, info), /* GT3 reserved */ \
INTEL_VGA_DEVICE(0x0C02, info), /* SDV GT1 desktop */ \
INTEL_VGA_DEVICE(0x0C12, info), /* SDV GT2 desktop */ \
INTEL_VGA_DEVICE(0x0C22, info), /* SDV GT3 desktop */ \
INTEL_VGA_DEVICE(0x0C0A, info), /* SDV GT1 server */ \
INTEL_VGA_DEVICE(0x0C1A, info), /* SDV GT2 server */ \
INTEL_VGA_DEVICE(0x0C2A, info), /* SDV GT3 server */ \
INTEL_VGA_DEVICE(0x0C0B, info), /* SDV GT1 reserved */ \
INTEL_VGA_DEVICE(0x0C1B, info), /* SDV GT2 reserved */ \
INTEL_VGA_DEVICE(0x0C2B, info), /* SDV GT3 reserved */ \
INTEL_VGA_DEVICE(0x0C0E, info), /* SDV GT1 reserved */ \
INTEL_VGA_DEVICE(0x0C1E, info), /* SDV GT2 reserved */ \
INTEL_VGA_DEVICE(0x0C2E, info), /* SDV GT3 reserved */ \
INTEL_VGA_DEVICE(0x0A02, info), /* ULT GT1 desktop */ \
INTEL_VGA_DEVICE(0x0A12, info), /* ULT GT2 desktop */ \
INTEL_VGA_DEVICE(0x0A22, info), /* ULT GT3 desktop */ \
INTEL_VGA_DEVICE(0x0A0A, info), /* ULT GT1 server */ \
INTEL_VGA_DEVICE(0x0A1A, info), /* ULT GT2 server */ \
INTEL_VGA_DEVICE(0x0A2A, info), /* ULT GT3 server */ \
INTEL_VGA_DEVICE(0x0A0B, info), /* ULT GT1 reserved */ \
INTEL_VGA_DEVICE(0x0A1B, info), /* ULT GT2 reserved */ \
INTEL_VGA_DEVICE(0x0A2B, info), /* ULT GT3 reserved */ \
INTEL_VGA_DEVICE(0x0D02, info), /* CRW GT1 desktop */ \
INTEL_VGA_DEVICE(0x0D12, info), /* CRW GT2 desktop */ \
INTEL_VGA_DEVICE(0x0D22, info), /* CRW GT3 desktop */ \
INTEL_VGA_DEVICE(0x0D0A, info), /* CRW GT1 server */ \
INTEL_VGA_DEVICE(0x0D1A, info), /* CRW GT2 server */ \
INTEL_VGA_DEVICE(0x0D2A, info), /* CRW GT3 server */ \
INTEL_VGA_DEVICE(0x0D0B, info), /* CRW GT1 reserved */ \
INTEL_VGA_DEVICE(0x0D1B, info), /* CRW GT2 reserved */ \
INTEL_VGA_DEVICE(0x0D2B, info), /* CRW GT3 reserved */ \
INTEL_VGA_DEVICE(0x0D0E, info), /* CRW GT1 reserved */ \
INTEL_VGA_DEVICE(0x0D1E, info), /* CRW GT2 reserved */ \
INTEL_VGA_DEVICE(0x0D2E, info) /* CRW GT3 reserved */ \
#define INTEL_HSW_M_IDS(info) \
INTEL_VGA_DEVICE(0x0406, info), /* GT1 mobile */ \
INTEL_VGA_DEVICE(0x0416, info), /* GT2 mobile */ \
INTEL_VGA_DEVICE(0x0426, info), /* GT2 mobile */ \
INTEL_VGA_DEVICE(0x0C06, info), /* SDV GT1 mobile */ \
INTEL_VGA_DEVICE(0x0C16, info), /* SDV GT2 mobile */ \
INTEL_VGA_DEVICE(0x0C26, info), /* SDV GT3 mobile */ \
INTEL_VGA_DEVICE(0x0A06, info), /* ULT GT1 mobile */ \
INTEL_VGA_DEVICE(0x0A16, info), /* ULT GT2 mobile */ \
INTEL_VGA_DEVICE(0x0A26, info), /* ULT GT3 mobile */ \
INTEL_VGA_DEVICE(0x0A0E, info), /* ULT GT1 reserved */ \
INTEL_VGA_DEVICE(0x0A1E, info), /* ULT GT2 reserved */ \
INTEL_VGA_DEVICE(0x0A2E, info), /* ULT GT3 reserved */ \
INTEL_VGA_DEVICE(0x0D06, info), /* CRW GT1 mobile */ \
INTEL_VGA_DEVICE(0x0D16, info), /* CRW GT2 mobile */ \
INTEL_VGA_DEVICE(0x0D26, info) /* CRW GT3 mobile */
#define INTEL_VLV_M_IDS(info) \
INTEL_VGA_DEVICE(0x0f30, info), \
INTEL_VGA_DEVICE(0x0f31, info), \
INTEL_VGA_DEVICE(0x0f32, info), \
INTEL_VGA_DEVICE(0x0f33, info), \
INTEL_VGA_DEVICE(0x0157, info)
#define INTEL_VLV_D_IDS(info) \
INTEL_VGA_DEVICE(0x0155, info)
#endif /* _I915_PCIIDS_H */

217
overlay/igfx.c Normal file
View File

@ -0,0 +1,217 @@
#include <pciaccess.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include "igfx.h"
#include "i915_pciids.h"
static const struct igfx_info generic_info = {
.gen = -1,
};
static const struct igfx_info i81x_info = {
.gen = 010,
};
static const struct igfx_info i830_info = {
.gen = 020,
};
static const struct igfx_info i845_info = {
.gen = 020,
};
static const struct igfx_info i855_info = {
.gen = 021,
};
static const struct igfx_info i865_info = {
.gen = 022,
};
static const struct igfx_info i915_info = {
.gen = 030,
};
static const struct igfx_info i945_info = {
.gen = 031,
};
static const struct igfx_info g33_info = {
.gen = 033,
};
static const struct igfx_info i965_info = {
.gen = 040,
};
static const struct igfx_info g4x_info = {
.gen = 045,
};
static const struct igfx_info ironlake_info = {
.gen = 050,
};
static const struct igfx_info sandybridge_info = {
.gen = 060,
};
static const struct igfx_info ivybridge_info = {
.gen = 070,
};
static const struct igfx_info valleyview_info = {
.gen = 071,
};
static const struct igfx_info haswell_info = {
.gen = 075,
};
static const struct pci_id_match match[] = {
#if 0
INTEL_VGA_DEVICE(PCI_CHIP_I810, &i81x_info),
INTEL_VGA_DEVICE(PCI_CHIP_I810_DC100, &i81x_info),
INTEL_VGA_DEVICE(PCI_CHIP_I810_E, &i81x_info),
INTEL_VGA_DEVICE(PCI_CHIP_I815, &i81x_info),
#endif
INTEL_I830_IDS(&i830_info),
INTEL_I845G_IDS(&i830_info),
INTEL_I85X_IDS(&i855_info),
INTEL_I865G_IDS(&i865_info),
INTEL_I915G_IDS(&i915_info),
INTEL_I915GM_IDS(&i915_info),
INTEL_I945G_IDS(&i945_info),
INTEL_I945GM_IDS(&i945_info),
INTEL_G33_IDS(&g33_info),
INTEL_PINEVIEW_IDS(&g33_info),
INTEL_I965G_IDS(&i965_info),
INTEL_I965GM_IDS(&i965_info),
INTEL_G45_IDS(&g4x_info),
INTEL_GM45_IDS(&g4x_info),
INTEL_IRONLAKE_D_IDS(&ironlake_info),
INTEL_IRONLAKE_M_IDS(&ironlake_info),
INTEL_SNB_D_IDS(&sandybridge_info),
INTEL_SNB_M_IDS(&sandybridge_info),
INTEL_IVB_D_IDS(&ivybridge_info),
INTEL_IVB_M_IDS(&ivybridge_info),
INTEL_HSW_D_IDS(&haswell_info),
INTEL_HSW_M_IDS(&haswell_info),
INTEL_VLV_D_IDS(&valleyview_info),
INTEL_VLV_M_IDS(&valleyview_info),
INTEL_VGA_DEVICE(PCI_MATCH_ANY, &generic_info),
{ 0, 0, 0 },
};
struct pci_device *igfx_get(void)
{
struct pci_device *dev;
if (pci_system_init())
return 0;
dev = pci_device_find_by_slot(0, 0, 2, 0);
if (dev == NULL || dev->vendor_id != 0x8086) {
struct pci_device_iterator *iter;
iter = pci_id_match_iterator_create(match);
if (!iter)
return 0;
dev = pci_device_next(iter);
pci_iterator_destroy(iter);
}
return dev;
}
const struct igfx_info *igfx_get_info(struct pci_device *dev)
{
int i;
if (!dev)
return 0;
for (i = 0; match[i].device_id != PCI_MATCH_ANY; i++)
if (dev->device_id == match[i].device_id)
return (const struct igfx_info *)match[i].match_data;
return &generic_info;
}
static int forcewake = -1;
static void
igfx_forcewake(void)
{
char buf[1024];
const char *path[] = {
"/sys/kernel/debug/dri/",
"/debug/dri/",
0,
};
int i, j;
for (j = 0; path[j]; j++) {
struct stat st;
if (stat(path[j], &st))
continue;
for (i = 0; i < 16; i++) {
snprintf(buf, sizeof(buf),
"%s/%i/i915_forcewake_user",
path[j], i);
forcewake = open(buf, 0);
if (forcewake != -1)
return;
}
}
}
void *igfx_get_mmio(struct pci_device *dev)
{
const struct igfx_info *info;
int mmio_bar, mmio_size;
void *mmio;
info = igfx_get_info(dev);
if (info->gen >> 3 == 2)
mmio_bar = 1;
else
mmio_bar = 0;
if (info->gen < 030)
mmio_size = 512*1024;
else if (info->gen < 050)
mmio_size = 512*1024;
else
mmio_size = 2*1024*1024;
if (pci_device_probe(dev))
return 0;
if (pci_device_map_range(dev,
dev->regions[mmio_bar].base_addr,
mmio_size,
PCI_DEV_MAP_FLAG_WRITABLE,
&mmio))
return 0;
if (info->gen >= 060)
igfx_forcewake();
return mmio;
}

15
overlay/igfx.h Normal file
View File

@ -0,0 +1,15 @@
struct igfx_info {
int gen;
};
struct pci_device;
struct pci_device *igfx_get(void);
const struct igfx_info *igfx_get_info(struct pci_device *pci_dev);
void *igfx_get_mmio(struct pci_device *pci_dev);
static inline uint32_t
igfx_read(void *mmio, uint32_t reg)
{
return *(volatile uint32_t *)((volatile char *)mmio + reg);
}

196
overlay/overlay.c Normal file
View File

@ -0,0 +1,196 @@
#include <X11/Xlib.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <cairo.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "overlay.h"
#include "gpu-top.h"
#include "gem-objects.h"
#include "chart.h"
const cairo_user_data_key_t overlay_key;
static void overlay_show(cairo_surface_t *surface)
{
struct overlay *overlay;
overlay = cairo_surface_get_user_data(surface, &overlay_key);
if (overlay == NULL)
return;
overlay->show(overlay);
}
#if 0
static void overlay_position(cairo_surface_t *surface, enum position p)
{
struct overlay *overlay;
overlay = cairo_surface_get_user_data(surface, &overlay_key);
if (overlay == NULL)
return;
overlay->position(overlay, p);
}
static void overlay_hide(cairo_surface_t *surface)
{
struct overlay *overlay;
overlay = cairo_surface_get_user_data(surface, &overlay_key);
if (overlay == NULL)
return;
overlay->hide(overlay);
}
#endif
struct overlay_gpu_top {
struct gpu_top gpu_top;
struct chart chart[MAX_RINGS];
};
static void init_gpu_top(struct overlay_gpu_top *gt,
cairo_surface_t *surface)
{
const double rgba[][4] = {
{ 1, 0, 0, 1 },
{ 0, 1, 0, 1 },
{ 0, 0, 1, 1 },
{ 1, 1, 1, 1 },
};
int n;
gpu_top_init(&gt->gpu_top);
for (n = 0; n < gt->gpu_top.num_rings; n++) {
chart_init(&gt->chart[n],
gt->gpu_top.ring[n].name,
120);
chart_set_position(&gt->chart[n], 12, 12);
chart_set_size(&gt->chart[n],
cairo_image_surface_get_width(surface)-24,
100);
chart_set_rgba(&gt->chart[n],
rgba[n][0], rgba[n][1], rgba[n][2], rgba[n][3]);
chart_set_range(&gt->chart[n], 0, 100);
}
}
static void show_gpu_top(cairo_t *cr, struct overlay_gpu_top *gt)
{
int y, n, update;
update = gpu_top_update(&gt->gpu_top);
for (n = 0; n < gt->gpu_top.num_rings; n++) {
if (update)
chart_add_sample(&gt->chart[n],
gt->gpu_top.ring[n].u.u.busy);
chart_draw(&gt->chart[n], cr);
}
cairo_set_source_rgb(cr, 1, 1, 1);
y = 12;
for (n = 0; n < gt->gpu_top.num_rings; n++) {
char txt[160];
int len;
len = sprintf(txt, "%s: %d%% busy",
gt->gpu_top.ring[n].name,
gt->gpu_top.ring[n].u.u.busy);
if (gt->gpu_top.ring[n].u.u.wait)
len += sprintf(txt + len, ", %d%% wait",
gt->gpu_top.ring[n].u.u.wait);
if (gt->gpu_top.ring[n].u.u.sema)
len += sprintf(txt + len, ", %d%% sema",
gt->gpu_top.ring[n].u.u.sema);
cairo_move_to(cr, 12, y);
cairo_show_text(cr, txt);
y += 14;
}
}
static void show_gem_objects(cairo_t *cr)
{
char gem_objects[1024], *s, *t, *end;
int len, y;
len = gem_objects_update(gem_objects, sizeof(gem_objects));
if (len <= 0)
return;
y = 130;
s = gem_objects;
end = s + len - 1;
while (s < end) {
t = strchr(s, '\n');
if (t == NULL)
t = end;
*t = '\0';
cairo_move_to(cr, 12, y);
cairo_show_text(cr, s);
y += 14;
s = t+1;
}
}
int main(int argc, char **argv)
{
cairo_surface_t *surface;
struct overlay_gpu_top gpu_top;
int i = 0;
if (argc > 1) {
x11_overlay_stop();
return 0;
}
surface = x11_overlay_create(POS_TOP_RIGHT, 640, 480);
if (surface == NULL)
return ENOMEM;
init_gpu_top(&gpu_top, surface);
while (1) {
cairo_t *cr;
usleep(500*1000);
cr = cairo_create(surface);
cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
cairo_paint(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
{
char buf[80];
cairo_text_extents_t extents;
sprintf(buf, "%d", i++);
cairo_set_source_rgb(cr, .5, .5, .5);
cairo_text_extents(cr, buf, &extents);
cairo_move_to(cr,
cairo_image_surface_get_width(surface)-extents.width-6,
6+extents.height);
cairo_show_text(cr, buf);
}
show_gpu_top(cr, &gpu_top);
show_gem_objects(cr);
cairo_destroy(cr);
overlay_show(surface);
}
return 0;
}

37
overlay/overlay.h Normal file
View File

@ -0,0 +1,37 @@
#include <cairo.h>
enum position {
POS_UNSET = -1,
POS_LEFT = 0,
POS_CENTRE = 1,
POS_RIGHT = 2,
POS_TOP = 0 << 4,
POS_MIDDLE = 1 << 4,
POS_BOTTOM = 2 << 4,
POS_TOP_LEFT = POS_TOP | POS_LEFT,
POS_TOP_CENTRE = POS_TOP | POS_CENTRE,
POS_TOP_RIGHT = POS_TOP | POS_RIGHT,
POS_MIDDLE_LEFT = POS_MIDDLE | POS_LEFT,
POS_MIDDLE_CENTRE = POS_MIDDLE | POS_CENTRE,
POS_MIDDLE_RIGHT = POS_MIDDLE | POS_RIGHT,
POS_BOTTOM_LEFT = POS_BOTTOM | POS_LEFT,
POS_BOTTOM_CENTRE = POS_BOTTOM | POS_CENTRE,
POS_BOTTOM_RIGHT = POS_BOTTOM | POS_RIGHT,
};
struct overlay {
cairo_surface_t *surface;
void (*show)(struct overlay *);
void (*position)(struct overlay *, enum position);
void (*hide)(struct overlay *);
};
extern const cairo_user_data_key_t overlay_key;
cairo_surface_t *x11_overlay_create(enum position pos, int max_width, int max_height);
void x11_overlay_stop(void);

169
overlay/x11/dri2.c Normal file
View File

@ -0,0 +1,169 @@
/*
* Copyright © 2008 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Soft-
* ware"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, provided that the above copyright
* notice(s) and this permission notice appear in all copies of the Soft-
* ware and that both the above copyright notice(s) and this permission
* notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
* ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
* RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
* THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
* QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
* MANCE OF THIS SOFTWARE.
*
* Except as contained in this notice, the name of a copyright holder shall
* not be used in advertising or otherwise to promote the sale, use or
* other dealings in this Software without prior written authorization of
* the copyright holder.
*
* Authors:
* Kristian Høgsberg (krh@redhat.com)
*/
#include <stdio.h>
#include <X11/Xlibint.h>
#include <X11/extensions/Xext.h>
#include <X11/extensions/extutil.h>
#include <X11/extensions/dri2proto.h>
#include <X11/extensions/dri2tokens.h>
#include <xf86drm.h>
#include <drm.h>
#include <fcntl.h>
#include "dri2.h"
static char dri2ExtensionName[] = DRI2_NAME;
static XExtensionInfo *dri2Info;
static XEXT_GENERATE_CLOSE_DISPLAY (DRI2CloseDisplay, dri2Info)
static /* const */ XExtensionHooks dri2ExtensionHooks = {
NULL, /* create_gc */
NULL, /* copy_gc */
NULL, /* flush_gc */
NULL, /* free_gc */
NULL, /* create_font */
NULL, /* free_font */
DRI2CloseDisplay, /* close_display */
};
static XEXT_GENERATE_FIND_DISPLAY (DRI2FindDisplay,
dri2Info,
dri2ExtensionName,
&dri2ExtensionHooks,
0, NULL)
static Bool
DRI2Connect(Display *dpy, XID window, char **driverName, char **deviceName)
{
XExtDisplayInfo *info = DRI2FindDisplay(dpy);
xDRI2ConnectReply rep;
xDRI2ConnectReq *req;
XextCheckExtension(dpy, info, dri2ExtensionName, False);
LockDisplay(dpy);
GetReq(DRI2Connect, req);
req->reqType = info->codes->major_opcode;
req->dri2ReqType = X_DRI2Connect;
req->window = window;
req->driverType = DRI2DriverDRI;
if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
UnlockDisplay(dpy);
SyncHandle();
return False;
}
if (rep.driverNameLength == 0 && rep.deviceNameLength == 0) {
UnlockDisplay(dpy);
SyncHandle();
return False;
}
*driverName = Xmalloc(rep.driverNameLength + 1);
if (*driverName == NULL) {
_XEatData(dpy,
((rep.driverNameLength + 3) & ~3) +
((rep.deviceNameLength + 3) & ~3));
UnlockDisplay(dpy);
SyncHandle();
return False;
}
_XReadPad(dpy, *driverName, rep.driverNameLength);
(*driverName)[rep.driverNameLength] = '\0';
*deviceName = Xmalloc(rep.deviceNameLength + 1);
if (*deviceName == NULL) {
Xfree(*driverName);
_XEatData(dpy, ((rep.deviceNameLength + 3) & ~3));
UnlockDisplay(dpy);
SyncHandle();
return False;
}
_XReadPad(dpy, *deviceName, rep.deviceNameLength);
(*deviceName)[rep.deviceNameLength] = '\0';
UnlockDisplay(dpy);
SyncHandle();
return True;
}
static Bool
DRI2Authenticate(Display * dpy, XID window, unsigned int magic)
{
XExtDisplayInfo *info = DRI2FindDisplay(dpy);
xDRI2AuthenticateReq *req;
xDRI2AuthenticateReply rep;
XextCheckExtension(dpy, info, dri2ExtensionName, False);
LockDisplay(dpy);
GetReq(DRI2Authenticate, req);
req->reqType = info->codes->major_opcode;
req->dri2ReqType = X_DRI2Authenticate;
req->window = window;
req->magic = magic;
if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
UnlockDisplay(dpy);
SyncHandle();
return False;
}
UnlockDisplay(dpy);
SyncHandle();
return rep.authenticated;
}
int dri2_open(Display *dpy)
{
drm_auth_t auth;
char *driver, *device;
int fd;
if (!DRI2Connect(dpy, DefaultRootWindow(dpy), &driver, &device))
return -1;
fd = open(device, O_RDWR);
if (fd < 0)
return -1;
if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
return -1;
if (!DRI2Authenticate(dpy, DefaultRootWindow(dpy), auth.magic))
return -1;
return fd;
}

1
overlay/x11/dri2.h Normal file
View File

@ -0,0 +1 @@
int dri2_open(Display *dpy);

105
overlay/x11/rgb2yuv.c Normal file
View File

@ -0,0 +1,105 @@
#include <stdint.h>
#include <stdlib.h>
#include "rgb2yuv.h"
static int RGB2YUV_YR[256], RGB2YUV_YG[256], RGB2YUV_YB[256];
static int RGB2YUV_UR[256], RGB2YUV_UG[256], RGB2YUV_UBVR[256];
static int RGB2YUV_VG[256], RGB2YUV_VB[256];
void rgb2yuv_init(void)
{
int i;
for (i = 0; i < 256; i++)
RGB2YUV_YR[i] = 65.481 * (i << 8);
for (i = 0; i < 256; i++)
RGB2YUV_YG[i] = 128.553 * (i << 8);
for (i = 0; i < 256; i++)
RGB2YUV_YB[i] = 24.966 * (i << 8);
for (i = 0; i < 256; i++)
RGB2YUV_UR[i] = 37.797 * (i << 8);
for (i = 0; i < 256; i++)
RGB2YUV_UG[i] = 74.203 * (i << 8);
for (i = 0; i < 256; i++)
RGB2YUV_VG[i] = 93.786 * (i << 8);
for (i = 0; i < 256; i++)
RGB2YUV_VB[i] = 18.214 * (i << 8);
for (i = 0; i < 256; i++)
RGB2YUV_UBVR[i] = 112 * (i << 8);
}
int rgb2yuv(cairo_surface_t *surface, XvImage *image, uint8_t *yuv)
{
uint8_t *data = cairo_image_surface_get_data(surface);
int rgb_stride = cairo_image_surface_get_stride(surface);
int width = cairo_image_surface_get_width(surface);
int height = cairo_image_surface_get_height(surface);
int y_stride = image->pitches[0];
int uv_stride = image->pitches[1];
uint8_t *tmp, *tl, *tr, *bl, *br;
int i, j;
tmp = malloc(2*width*height);
if (tmp == NULL)
return 0;
tl = tmp;
bl = tmp + width*height;
for (i = 0; i < height; i++) {
uint16_t *rgb = (uint16_t *)(data + i * rgb_stride);
for (j = 0; j < width; j++) {
uint8_t r = (rgb[j] >> 11) & 0x1f;
uint8_t g = (rgb[j] >> 5) & 0x3f;
uint8_t b = (rgb[j] >> 0) & 0x1f;
r = r<<3 | r>>2;
g = g<<2 | g>>4;
b = b<<3 | b>>2;
yuv[j] = (RGB2YUV_YR[r] + RGB2YUV_YG[g] + RGB2YUV_YB[b] + 1048576) >> 16;
*tl++ = (-RGB2YUV_UR[r] - RGB2YUV_UG[g] + RGB2YUV_UBVR[b] + 8388608) >> 16;
*bl++ = (RGB2YUV_UBVR[r] - RGB2YUV_VG[g] - RGB2YUV_VB[b] + 8388608) >> 16;
}
yuv += y_stride;
}
tl = tmp; tr = tl + 1;
bl = tl + width; br = bl + 1;
for (i = 0; i < height/2; i ++) {
for (j = 0; j < width/2; j ++) {
yuv[j] = ((int)*tl + *tr + *bl + *br) >> 2;
tl += 2; tr += 2;
bl += 2; br += 2;
}
yuv += uv_stride;
tl += width; tr += width;
bl += width; br += width;
}
tl = tmp + width*height; tr = tl + 1;
bl = tl + width; br = bl + 1;
for (i = 0; i < height/2; i++) {
for (j = 0; j < width/2; j++) {
yuv[j] = ((int)*tl + *tr + *bl + *br) >> 2;
tl += 2; tr += 2;
bl += 2; br += 2;
}
yuv += uv_stride;
tl += width; tr += width;
bl += width; br += width;
}
free(tmp);
return 1;
}

7
overlay/x11/rgb2yuv.h Normal file
View File

@ -0,0 +1,7 @@
#include <X11/Xlib.h>
#include <X11/extensions/Xvlib.h>
#include <cairo.h>
#include <stdint.h>
void rgb2yuv_init(void);
int rgb2yuv(cairo_surface_t *rgb, XvImage *image, uint8_t *yuv);

383
overlay/x11/x11-overlay.c Normal file
View File

@ -0,0 +1,383 @@
#include <X11/Xlib.h>
#include <X11/extensions/Xvlib.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <cairo.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <drm.h>
#include <xf86drm.h>
#include <i915_drm.h>
#include "../overlay.h"
#include "dri2.h"
#include "rgb2yuv.h"
#ifndef ALIGN
#define ALIGN(i,m) (((i) + (m) - 1) & ~((m) - 1))
#endif
#define FOURCC_XVMC (('C' << 24) + ('M' << 16) + ('V' << 8) + 'X')
#define FOURCC_RGB565 ((16 << 24) + ('B' << 16) + ('G' << 8) + 'R')
#define FOURCC_RGB888 ((24 << 24) + ('B' << 16) + ('G' << 8) + 'R')
struct x11_overlay {
struct overlay base;
Display *dpy;
GC gc;
XvPortID port;
XvImage *image;
void *map, *mem;
int size;
unsigned name;
int x, y;
int visible;
};
static inline struct x11_overlay *to_x11_overlay(struct overlay *o)
{
return (struct x11_overlay *)o;
}
static int noop(Display *dpy, XErrorEvent *event)
{
return 0;
}
static void x11_overlay_show(struct overlay *overlay)
{
struct x11_overlay *priv = to_x11_overlay(overlay);
if (priv->image->id == FOURCC_XVMC)
rgb2yuv(priv->base.surface, priv->image, priv->map);
else
memcpy(priv->map, priv->mem, priv->size);
if (!priv->visible) {
XvPutImage(priv->dpy, priv->port, DefaultRootWindow(priv->dpy),
priv->gc, priv->image,
0, 0,
priv->image->width, priv->image->height,
priv->x, priv->y,
priv->image->width, priv->image->height);
XFlush(priv->dpy);
priv->visible = true;
}
}
static void x11_overlay_position(struct overlay *overlay,
enum position p)
{
struct x11_overlay *priv = to_x11_overlay(overlay);
Screen *scr = ScreenOfDisplay(priv->dpy, DefaultScreen(priv->dpy));
switch (p & 7) {
default:
case 0: priv->x = 0; break;
case 1: priv->x = (scr->width - priv->image->width)/2; break;
case 2: priv->x = scr->width - priv->image->width; break;
}
switch ((p >> 4) & 7) {
default:
case 0: priv->y = 0; break;
case 1: priv->y = (scr->height - priv->image->height)/2; break;
case 2: priv->y = scr->height - priv->image->height; break;
}
if (priv->visible) {
XvPutImage(priv->dpy, priv->port, DefaultRootWindow(priv->dpy),
priv->gc, priv->image,
0, 0,
priv->image->width, priv->image->height,
priv->x, priv->y,
priv->image->width, priv->image->height);
XFlush(priv->dpy);
}
}
static void x11_overlay_hide(struct overlay *overlay)
{
struct x11_overlay *priv = to_x11_overlay(overlay);
if (priv->visible) {
XClearWindow(priv->dpy, DefaultRootWindow(priv->dpy));
XFlush(priv->dpy);
priv->visible = false;
}
}
static void x11_overlay_destroy(void *data)
{
struct x11_overlay *priv = data;
munmap(priv->map, priv->size);
free(priv->mem);
XCloseDisplay(priv->dpy);
free(priv);
}
cairo_surface_t *
x11_overlay_create(enum position position, int max_width, int max_height)
{
Display *dpy;
Screen *scr;
cairo_surface_t *surface;
struct drm_i915_gem_create create;
struct drm_gem_flink flink;
struct drm_i915_gem_mmap_gtt map;
struct x11_overlay *priv;
unsigned int count, i, j;
int fd, w, h;
XvAdaptorInfo *info;
XvImage *image;
XvPortID port = -1;
void *ptr, *mem;
dpy = XOpenDisplay(NULL);
if (dpy == NULL)
return NULL;
scr = ScreenOfDisplay(dpy, DefaultScreen(dpy));
fd = dri2_open(dpy);
if (fd < 0)
goto err_dpy;
if (XvQueryAdaptors(dpy, DefaultRootWindow(dpy), &count, &info) != Success)
goto err_fd;
for (i = 0; i < count; i++) {
unsigned long visual = 0;
if (info[i].num_ports != 1)
continue;
for (j = 0; j < info[j].num_formats; j++) {
if (info[i].formats[j].depth == 24) {
visual = info[i].formats[j].visual_id;
break;
}
}
if (visual == 0)
continue;
port = info[i].base_id;
}
XvFreeAdaptorInfo(info);
if (port == -1)
goto err_fd;
XSetErrorHandler(noop);
w = scr->width;
switch (position & 7) {
default:
case 0:
case 2: w >>= 1; break;
}
if (max_width > 0 && w > max_width)
w = max_width;
h = scr->height;
switch ((position >> 4) & 7) {
default:
case 0:
case 2: h >>= 1; break;
}
if (max_height > 0 && h > max_height)
h = max_height;
image = XvCreateImage(dpy, port, FOURCC_RGB565, NULL, w, h);
if (image == NULL)
image = XvCreateImage(dpy, port, FOURCC_RGB888, NULL, w, h);
if (image == NULL) {
image = XvCreateImage(dpy, port, FOURCC_XVMC, NULL, w, h);
if (image->pitches[0] == 4) {
image->pitches[0] = ALIGN(image->width, 1024);
image->pitches[1] = ALIGN(image->width/2, 1024);
image->pitches[2] = ALIGN(image->width/2, 1024);
image->offsets[0] = 0;
image->offsets[1] = image->pitches[0] * image->height;
image->offsets[2] = image->offsets[1] + image->pitches[1] * image->height/2;
}
rgb2yuv_init();
}
if (image == NULL)
goto err_fd;
switch (image->id) {
case FOURCC_RGB888:
case FOURCC_RGB565:
create.size = image->pitches[0] * image->height;
break;
case FOURCC_XVMC:
create.size = image->pitches[0] * image->height;
create.size += image->pitches[1] * image->height;
break;
}
create.handle = 0;
create.size = ALIGN(create.size, 4096);
drmIoctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);
if (create.handle == 0)
goto err_image;
flink.handle = create.handle;
if (drmIoctl(fd, DRM_IOCTL_GEM_FLINK, &flink))
goto err_create;
map.handle = create.handle;
if (drmIoctl(fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &map))
goto err_create;
ptr = mmap(0, create.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, map.offset);
if (ptr == (void *)-1)
goto err_create;
mem = malloc(create.size);
if (mem == NULL)
goto err_map;
switch (image->id) {
default:
case FOURCC_RGB888:
i = CAIRO_FORMAT_RGB24;
j = image->pitches[0];
break;
case FOURCC_RGB565:
i = CAIRO_FORMAT_RGB16_565;
j = image->pitches[0];
break;
case FOURCC_XVMC:
i = CAIRO_FORMAT_RGB16_565;
j = cairo_format_stride_for_width(i, image->width);
break;
}
surface = cairo_image_surface_create_for_data(mem, i, image->width, image->height, j);
if (cairo_surface_status(surface))
goto err_mem;
priv = malloc(sizeof(*priv));
if (priv == NULL)
goto err_surface;
priv->base.surface = surface;
priv->base.show = x11_overlay_show;
priv->base.position = x11_overlay_position;
priv->base.hide = x11_overlay_hide;
priv->dpy = dpy;
priv->gc = XCreateGC(dpy, DefaultRootWindow(dpy), 0, NULL);
priv->port = port;
priv->map = ptr;
priv->mem = mem;
priv->size = create.size;
priv->name = flink.name;
priv->visible = false;
switch (position & 7) {
default:
case 0: priv->x = 0; break;
case 1: priv->x = (scr->width - image->width)/2; break;
case 2: priv->x = scr->width - image->width; break;
}
switch ((position >> 4) & 7) {
default:
case 0: priv->y = 0; break;
case 1: priv->y = (scr->height - image->height)/2; break;
case 2: priv->y = scr->height - image->height; break;
}
priv->image = image;
priv->image->data = (void *)&priv->name;
cairo_surface_set_user_data(surface, &overlay_key, priv, x11_overlay_destroy);
XvSetPortAttribute(dpy, port, XInternAtom(dpy, "XV_ALWAYS_ON_TOP", True), 1);
close(fd);
return surface;
err_surface:
cairo_surface_destroy(surface);
err_mem:
free(mem);
err_map:
munmap(ptr, create.size);
err_create:
drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &create.handle);
err_image:
err_fd:
close(fd);
err_dpy:
XCloseDisplay(dpy);
return NULL;
}
void x11_overlay_stop(void)
{
Display *dpy;
unsigned int count, i, j;
XvAdaptorInfo *info;
XvImage *image;
XvPortID port = -1;
uint32_t name;
dpy = XOpenDisplay(NULL);
if (dpy == NULL)
return;
if (XvQueryAdaptors(dpy, DefaultRootWindow(dpy), &count, &info) != Success)
goto close;
for (i = 0; i < count; i++) {
unsigned long visual = 0;
if (info[i].num_ports != 1)
continue;
for (j = 0; j < info[j].num_formats; j++) {
if (info[i].formats[j].depth == 24) {
visual = info[i].formats[j].visual_id;
break;
}
}
if (visual == 0)
continue;
port = info[i].base_id;
}
XvFreeAdaptorInfo(info);
if (port == -1)
goto close;
XSetErrorHandler(noop);
image = XvCreateImage(dpy, port, FOURCC_RGB565, NULL, 16, 16);
if (image == NULL)
image = XvCreateImage(dpy, port, FOURCC_RGB888, NULL, 16, 16);
if (image == NULL)
image = XvCreateImage(dpy, port, FOURCC_XVMC, NULL, 16, 16);
if (image == NULL)
goto close;
name = 0;
image->data = (void *)&name;
XvPutImage(dpy, port, DefaultRootWindow(dpy),
XCreateGC(dpy, DefaultRootWindow(dpy), 0, NULL), image,
0, 0,
1, 1,
0, 0,
1, 1);
XSync(dpy, True);
close:
XCloseDisplay(dpy);
}