mirror of
https://github.com/tiagovignatti/intel-gpu-tools.git
synced 2025-06-08 08:26:10 +00:00
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:
parent
7df9caeea1
commit
f9a50de3dc
@ -21,7 +21,7 @@
|
||||
|
||||
ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} -I m4
|
||||
|
||||
SUBDIRS = lib man tools scripts benchmarks demos
|
||||
SUBDIRS = lib man tools scripts benchmarks demos overlay
|
||||
|
||||
if BUILD_ASSEMBLER
|
||||
SUBDIRS += assembler
|
||||
|
@ -72,6 +72,9 @@ AC_SUBST(ASSEMBLER_WARN_CFLAGS)
|
||||
|
||||
PKG_CHECK_MODULES(DRM, [libdrm_intel >= 2.4.45 libdrm])
|
||||
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
|
||||
PKG_CHECK_MODULES(CAIRO, [cairo >= 1.12.0])
|
||||
@ -184,6 +187,7 @@ AC_CONFIG_FILES([
|
||||
assembler/doc/Makefile
|
||||
assembler/test/Makefile
|
||||
assembler/intel-gen4asm.pc
|
||||
overlay/Makefile
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
||||
@ -200,6 +204,7 @@ echo " • Tools:"
|
||||
echo " Assembler : ${enable_assembler}"
|
||||
echo " Debugger : ${enable_debugger}"
|
||||
echo " Python dumper : ${DUMPER}"
|
||||
echo " Overlay : ${enable_overlay}"
|
||||
echo ""
|
||||
|
||||
# vim: set ft=config ts=8 sw=8 tw=0 noet :
|
||||
|
1
overlay/.gitignore
vendored
Normal file
1
overlay/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
intel-gpu-overlay
|
28
overlay/Makefile.am
Normal file
28
overlay/Makefile.am
Normal 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
8
overlay/README
Normal 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
135
overlay/chart.c
Normal 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
18
overlay/chart.h
Normal 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
19
overlay/gem-objects.c
Normal 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
1
overlay/gem-objects.h
Normal file
@ -0,0 +1 @@
|
||||
int gem_objects_update(char *buf, int buflen);
|
178
overlay/gpu-top.c
Normal file
178
overlay/gpu-top.c
Normal 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
22
overlay/gpu-top.h
Normal 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
211
overlay/i915_pciids.h
Normal 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
217
overlay/igfx.c
Normal 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
15
overlay/igfx.h
Normal 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
196
overlay/overlay.c
Normal 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(>->gpu_top);
|
||||
|
||||
for (n = 0; n < gt->gpu_top.num_rings; n++) {
|
||||
chart_init(>->chart[n],
|
||||
gt->gpu_top.ring[n].name,
|
||||
120);
|
||||
chart_set_position(>->chart[n], 12, 12);
|
||||
chart_set_size(>->chart[n],
|
||||
cairo_image_surface_get_width(surface)-24,
|
||||
100);
|
||||
chart_set_rgba(>->chart[n],
|
||||
rgba[n][0], rgba[n][1], rgba[n][2], rgba[n][3]);
|
||||
chart_set_range(>->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(>->gpu_top);
|
||||
for (n = 0; n < gt->gpu_top.num_rings; n++) {
|
||||
if (update)
|
||||
chart_add_sample(>->chart[n],
|
||||
gt->gpu_top.ring[n].u.u.busy);
|
||||
chart_draw(>->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
37
overlay/overlay.h
Normal 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
169
overlay/x11/dri2.c
Normal 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
1
overlay/x11/dri2.h
Normal file
@ -0,0 +1 @@
|
||||
int dri2_open(Display *dpy);
|
105
overlay/x11/rgb2yuv.c
Normal file
105
overlay/x11/rgb2yuv.c
Normal 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
7
overlay/x11/rgb2yuv.h
Normal 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
383
overlay/x11/x11-overlay.c
Normal 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);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user