feat(clusterApp):BringUp OpenGlES+DRM on RK3576

This commit is contained in:
2026-04-28 21:30:18 +08:00
parent f3f5d1b00b
commit d5b56baefc
213 changed files with 136403 additions and 678 deletions

19
test/drmcap-main/LICENSE Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2022-2030 Gopise.Yuan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
OR OTHER DEALINGS IN THE SOFTWARE.

43
test/drmcap-main/Makefile Normal file
View File

@@ -0,0 +1,43 @@
# Configurations:
# Toolchain location:
#TOOLCHAIN = /workspace/gopbuild-4.14.98-2.3.3-ga/sdk/a64/toolchain
# Sysroot location: It should contain the header and library for target platform (e.g. ARM):
ROOTFS = /home/huaxu/develop/cluster/packages/install/usr
CROSS_COMPILE = /opt/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-
INC = -I$(ROOTFS)/usr/src/kernel/include \
-I$(ROOTFS)/include \
-I$(ROOTFS)/lib \
-I$(ROOTFS)/include/drm \
-I$(ROOTFS)/include/libdrm
LIB = -L$(ROOTFS)/lib \
-I$(ROOTFS)/lib/libdrm
TARGET = drmcap
OBJ = drmcap.o
CC = $(CROSS_COMPILE)gcc
CPP = $(CROSS_COMPILE)g++
LD = $(CROSS_COMPILE)gcc
# CFLAGS
#CFLAGS = --sysroot=$(ROOTFS) $(INC) -DLINUX
CFLAGS = $(INC) -DLINUX
# LDFLAGS
#LDFLAGS = --sysroot=$(ROOTFS)
LDFLAGS = $(LIB)
%.o:%.c
$(CC) $(CFLAGS) -Wall -c $(@D)/$(<F) -o $(@D)/$(@F) -O2 -g
all: $(TARGET)
$(TARGET): $(OBJ)
$(CC) -o $(TARGET) $(OBJ) $(LDFLAGS) -ldrm -lm
#$(CC) -o $(TARGET) $(OBJ) $(LDFLAGS) -ldrm -lm -static
.PHONY: clean
clean:
- rm -f $(TARGET) $(OBJ)

View File

@@ -0,0 +1,34 @@
# drmcap
A debugging tool for screen capture under DRM (Direct Render Manager)
This is a debugging tool for screen capture under DRM (Direct Render Manager).
This also a revised version for previous “drmfbcap” (DRM Framebuffer Capture).
Unlike the FB based system under which we can capture the frame buffer easily through reading the device node, the DRM is much more complex and secure-protected. No direct way for reading framebuffer data from user space.
Under DRM case, we need to open the DRM device, query the resource, get and map the FB object and then read the buffer eventually.
With this tool, we can capture the buffer content from a DRM device and output as raw RGB/YUV data.
Features:
-----------------------------------------------------------------------------------------
1. Capture all planes or specific plane, including hidden/covered planes or planes (overlays) managed by applications directly.
2. Both RGB and YUV supported (auto detect).
3. Repeat mode which can capture frames continuously.
4. Tile format (VSI Super-Tile) is also supported (not available for open source version).
Important notes:
-----------------------------------------------------------------------------------------
Behavior of DRM subsystem is different between Linux 4.x and 5.x/6.x.
For Linux 4.x, you can capture the RGB buffer without any problem. But, theres no API for YUV (multi-plane) buffer.
To capture YUV, please patch kernel with: “kernel_0001-drm-Add-getfb2-ioctl_L4.14.98.patch”.
For Linux 5.x, mapping/capturing the internal buffer is not allowed by default due to security reason.
To overcome this temporary (for debug only), patch the kernel with: “0001-drm-enable-mapping-of-internal-object-for-debugging_L5.x.patch”. It contains a minor change to remove this guard.
Both patches are included in project.
To get more details about how to use this tool, try “-h” option to print the usage message.
Enjoy!

BIN
test/drmcap-main/drmcap Executable file

Binary file not shown.

621
test/drmcap-main/drmcap.c Executable file
View File

@@ -0,0 +1,621 @@
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <linux/types.h>
#include <setjmp.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <errno.h>
#include <string.h>
#include <drm_fourcc.h>
#include <stdbool.h>
typedef unsigned short WORD;
typedef unsigned int DWORD;
typedef unsigned long int uint64_t;
typedef unsigned int uint32_t;
typedef unsigned short uint16_t;
typedef unsigned char uint8_t;
#define VERSION "1.4"
// Does DRM support VBlank?
//#define SUPPORT_VBLANK
#define DEF_DRM_PATH "/dev/dri/card0"
char sDrm_name[256];
#define DEF_OUTPUT_FOLDER "."
char sOutput_folder[256];
#define FLAG_SAVE_RAW 0x01
#define FLAG_TILE 0x02
#define FLAG_PRINT_ONLY 0x04
#define FLAG_REPEAT 0x08
unsigned int iFlag = 0;
// Specific plane to capture
#define MAX_PLANE 64
int iTargetPlane = -1;
// Repeat mode:
#define DEF_REPEAT_COUNT 30
#define DEF_REPEAT_INTERVAL 15 /* in ms */
int iRepeatCount = 0;
int iRepeatInterval = 0;
int iRCounter = 0;
// Definition for drmModeGetFB2.
// This is only for some old libdrm library which doesn't support GetFB2 call.
// If the libdrm already contains this, remove the following definition
// ----------------------------------------------------------------------------------
#define drmModeGetFB2
#ifndef drmModeGetFB2
typedef struct _drmModeFB2 {
uint32_t fb_id;
uint32_t width, height;
uint32_t pixel_format; /* fourcc code from drm_fourcc.h */
uint32_t modifier; /* applies to all buffers */
uint32_t flags;
/* per-plane GEM handle; may be duplicate entries for multiple planes */
uint32_t handles[4];
uint32_t pitches[4]; /* bytes */
uint32_t offsets[4]; /* bytes */
} drmModeFB2, *drmModeFB2Ptr;
#define DRM_IOCTL_MODE_GETFB2 DRM_IOWR(0xCE, struct drm_mode_fb_cmd2)
static inline int DRM_IOCTL(int fd, unsigned long cmd, void *arg)
{
int ret = drmIoctl(fd, cmd, arg);
return ret < 0 ? -errno : ret;
}
drmModeFB2Ptr
drmModeGetFB2(int fd, uint32_t fb_id)
{
struct drm_mode_fb_cmd2 get;
drmModeFB2Ptr ret;
int err;
memset(&get, 0, sizeof(get));
get.fb_id = fb_id;
err = DRM_IOCTL(fd, DRM_IOCTL_MODE_GETFB2, &get);
if (err != 0)
return NULL;
ret = drmMalloc(sizeof(drmModeFB2));
if (!ret)
return NULL;
ret->fb_id = fb_id;
ret->width = get.width;
ret->height = get.height;
ret->pixel_format = get.pixel_format;
ret->flags = get.flags;
ret->modifier = get.modifier[0];
memcpy(ret->handles, get.handles, sizeof(uint32_t) * 4);
memcpy(ret->pitches, get.pitches, sizeof(uint32_t) * 4);
memcpy(ret->offsets, get.offsets, sizeof(uint32_t) * 4);
return ret;
}
void drmModeFreeFB2(drmModeFB2Ptr ptr)
{
if (!ptr)
return;
/* we might add more frees later. */
drmFree(ptr);
}
#endif
// ----------------------------------------------------------------------------------
/*
* Decode the FOURCC code
* The 'name' must be >=5 bytes long to hold the decoded string
*/
void fourcc_decode(unsigned int code, char *name)
{
char a, b, c, d;
if(!code || !name)
return;
a = (char)(code & 0xFF);
b = (char)(code >> 8 & 0xFF);
c = (char)(code >> 16 & 0xFF);
d = (char)(code >> 24 & 0xFF);
sprintf(name, "%c%c%c%c", a,b,c,d);
}
void dump_buf_file(uint8_t *fb_addr, int len, char *fname)
{
FILE *fp;
int rlen = 0;
fp = fopen(fname, "wb");
if (!fp) {
printf("Error opening file: %s, error: %s\n", fname, strerror(errno));
exit(4);
}
rlen = fwrite((void *)fb_addr, len, 1, fp);
if(rlen <=0) {
printf("Error writing file (%d/%d)! error: %s\n", rlen, len, strerror(errno));
}
fclose(fp);
}
int dump_plane_rgb(uint32_t fd, drmModePlane * ovr)
{
drmModeFBPtr fb;
struct drm_mode_map_dumb map = { };
uint8_t * buf;
int imgsize;
char sFile_name[256];
int ret = 0;
// Get framebuffer object
fb = drmModeGetFB(fd, ovr->fb_id);
if(!fb) {
printf("Failed to get FB from DRM, error: %s\n", strerror(errno));
return errno;
}
printf("-> Plane/FB: %d/%d, [%d x %d], PITCH:%d, BPP:%d, DEPTH:%d, DETILE:%s\n",
ovr->plane_id, fb->fb_id, fb->width, fb->height, fb->pitch, fb->bpp, fb->depth,(iFlag & FLAG_TILE)?"Y":"N");
// Map the framebuffer
map.handle = fb->handle;
ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map);
if (ret) {
printf("Failed to map the buffer from DRM (%d)! error: %s\n", ret, strerror(errno));
return errno;
}
buf = (uint8_t *) mmap(0,
(fb->pitch * fb->height),
PROT_READ | PROT_WRITE, MAP_SHARED, fd,
map.offset);
if(!buf) {
printf("Failed to map the memory! error: %s\n", strerror(errno));
return errno;
}
imgsize = fb->pitch * fb->height;
// Save to raw
if(iFlag & FLAG_TILE) {
printf("Sorry! De-tile not supported!\n");
/*
// Do de-tile
void *tmp = NULL;
int size = fb->width * fb->height * fb->bpp / 8;
tmp = (uint8_t *) malloc(size*8);
if (!tmp) {
printf("Failed to alloc memory, size=%d\n", size*8);
return errno;
}
tmp = detile((const void * )buf, NULL, fb->width, fb->height, 4, SUPERTILED, FASTMSAA_SUPERTILE);
sprintf(sFile_name, "%s/P%d_%dx%d-%d-detile_%04d_FB%d.rgb",sOutput_folder, ovr->plane_id, fb->width, fb->height, fb->bpp, iRCounter+1, ovr->fb_id);
printf("-> Output: %s (%d)\n", sFile_name, size);
dump_buf_file((uint8_t *)tmp, size, sFile_name);
free(tmp);
//*/
} else {
sprintf(sFile_name, "%s/P%d_%dx%d-%d_%04d_FB%d.rgb", sOutput_folder, ovr->plane_id, fb->width, fb->height, fb->bpp, iRCounter+1, ovr->fb_id);
printf("-> Output: %s (%d)\n", sFile_name, imgsize);
dump_buf_file(buf, imgsize , sFile_name);
}
return 0;
}
int dump_plane_yuv(uint32_t fd, drmModePlane * ovr)
{
drmModeFB2Ptr fb2;
struct drm_mode_map_dumb map = { };
char sBuffer[256];
unsigned int imgsize;
//unsigned int ylen, uvlen;
unsigned int ylenp, uvlenp;
uint8_t *pSrc_buf=NULL, *pDst_buf=NULL;
uint8_t *pFb_p0=NULL, *pFb_p1=NULL;
//unsigned char *nBaseAddr[2];
int iBpp = 0;
int ret = 0;
bool bPacked = false;
fb2 = drmModeGetFB2(fd, ovr->fb_id);
if(!fb2) {
printf("Failed to get FB from DRM, error: %s\n", strerror(errno));
return errno;
}
// Detect the format
fourcc_decode(fb2->pixel_format, sBuffer);
sBuffer[4]='\0'; /* terminate */
switch(fb2->pixel_format) {
case DRM_FORMAT_NV21:
case DRM_FORMAT_NV12:
iBpp = 12;
bPacked = false;
break;
case DRM_FORMAT_YUYV:
case DRM_FORMAT_YVYU:
case DRM_FORMAT_UYVY:
case DRM_FORMAT_VYUY:
iBpp = 16;
bPacked = true;
break;
default:
printf("Unsupported format detected: '%s'\n", sBuffer);
return 1;
}
printf("-> Plane/FB: %d/%d, [%d x %d], %s: %s YUV/%s, %dBPP, FMT:%s, MOD:0x%x, DETILE:%s\n",
ovr->plane_id, ovr->fb_id, fb2->width, fb2->height, sBuffer, bPacked ? "Packed":"Planar", iBpp==12 ? "420" : "422",
iBpp, sBuffer, fb2->modifier, (iFlag & FLAG_TILE)?"Y":"N");
// We calculate the total imgsize barely from the pitch. If it's packed mode, pitches[1] will be 0
imgsize = fb2->pitches[0] * fb2->height + fb2->pitches[1] * fb2->height / 2;
pSrc_buf = (uint8_t *)malloc(imgsize);
if (pSrc_buf == NULL) {
printf("Failed to alloc memory! error: %s\n", strerror(errno));
return errno;
}
// Map Y planar
map.handle = fb2->handles[0];
ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map);
if (ret) {
printf("Failed to map the Y buffer from DRM (%d)! error: %s\n", ret, strerror(errno));
return errno;
}
ylenp = fb2->pitches[0] * fb2->height;
pFb_p0 = (uint8_t *) mmap(0, ylenp, PROT_READ | PROT_WRITE, MAP_SHARED, fd, map.offset);
if(!pFb_p0) {
printf("Failed to map the Y memory! error: %s\n", strerror(errno));
return errno;
}
memcpy(pSrc_buf, pFb_p0, ylenp);
if(!bPacked) { // Planar mode, process the second plane
// Map UV planar
map.handle = fb2->handles[1];
ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map);
if (ret) {
printf("Failed to map the UV buffer from DRM (%d)! error: %s\n", ret, strerror(errno));
return errno;
}
uvlenp = fb2->pitches[1] * fb2->height / 2;
pFb_p1 = (uint8_t *) mmap(0, uvlenp, PROT_READ | PROT_WRITE, MAP_SHARED, fd, map.offset);
if(!pFb_p1) {
printf("Failed to map the UV memory! error: %s\n", strerror(errno));
return errno;
}
memcpy(pSrc_buf + ylenp, pFb_p1, uvlenp);
}
// Save raw file
if(iFlag & FLAG_TILE) {
printf("Sorry! De-tile not supported!\n");
/*
if(bPacked) {
printf("De-tile on packed YUV is not currently supported! Exit...\n");
return errno;
}
// Do de-tile.
pDst_buf = (uint8_t *)malloc((fb2->width * fb2->height * iBpp) / 8);
if (pDst_buf == NULL) {
printf("Failed to alloc memory! error: %s\n", strerror(errno));
return errno;
}
nBaseAddr[0] = (unsigned char *)(pFb_p0);
nBaseAddr[1] = (unsigned char *)(pFb_p1);
NV12Tile2linear(fb2->width, fb2->height, 0, 0, fb2->pitches[0], nBaseAddr, pDst_buf);
// Save YUV file
sprintf(sBuffer, "%s/P%d_%dx%d-%d-detile_%04d_FB%d.yuv",sOutput_folder, ovr->plane_id, fb2->width, fb2->height, iBpp, iRCounter+1, ovr->fb_id);
printf("-> Output: %s (%d)\n", sBuffer, (fb2->width * fb2->height * iBpp) /8);
dump_buf_file(pDst_buf, (fb2->width * fb2->height * iBpp) /8 , sBuffer);
//*/
} else {
sprintf(sBuffer, "%s/P%d_%dx%d-%d_%04d_FB%d.yuv",sOutput_folder, ovr->plane_id, fb2->width, fb2->height, iBpp, iRCounter+1, ovr->fb_id);
printf("-> Output: %s (%d)\n", sBuffer, imgsize);
dump_buf_file(pSrc_buf, imgsize, sBuffer);
}
if(!pSrc_buf)
free(pSrc_buf);
if(!pDst_buf)
free(pDst_buf);
return 0;
}
int dump_plane(uint32_t fd, drmModePlane * ovr)
{
drmModeFBPtr fb;
fb = drmModeGetFB(fd, ovr->fb_id);
if(fb && fb->depth > 0)
return dump_plane_rgb(fd, ovr);
else
return dump_plane_yuv(fd, ovr);
}
#ifdef SUPPORT_VBLANK
inline int64_t curTime() {
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec*1000000LL + tv.tv_usec;
}
int64_t wait4vblank(uint32_t fd) {
union drm_wait_vblank vb;
int64_t start = curTime();
vb.request.type = DRM_VBLANK_RELATIVE;
vb.request.sequence = 1;
if(drmWaitVBlank(fd, (drmVBlankPtr)&vb))
return -1;
return curTime()-start;
}
#endif
void showVersion()
{
printf("Version: %s\n", VERSION);
}
void showUsage(char *prog)
{
printf("A DRM based screen capture program (%s)\n", VERSION);
printf("Usage:\n");
printf(" %s [OP] [ARG] [ARG2]\n", prog);
printf("[OP] OPeration (optional):\n");
printf(" -v Show version.\n");
printf(" -h Show this help information.\n");
printf(" -i Show information about target DRM device only (no capture).\n");
printf(" -d DRM device to open. [ARG] should contain the path to the device node. Default: '%s'\n", DEF_DRM_PATH);
printf(" -o Output folder. [ARG] should contain the path to the output folder. Default: '%s'\n", DEF_OUTPUT_FOLDER);
printf(" -p Specific plane # to capture. [ARG] should contain the plane number. If no '-p' specified, capture all planes\n");
printf(" -t Try to de-tile on captured frame, for tile format.\n");
printf(" -r Repeat mode. [ARG] should contain the repeat count and [ARG2] should contain the interval in ms\n");
printf("\n");
printf("Example:\n");
printf(" %s\n", prog);
printf(" Capture all planes on default DRM device.\n");
printf(" %s -d /dev/dri/card1\n", prog);
printf(" Capture all planes on '/dev/dri/card1' device.\n");
printf(" %s -p 44 -t -o /sdcard\n", prog);
printf(" Capture plane 44, do de-tile after capture and then output to /sdcard/.\n");
printf(" %s -r 30 15\n", prog);
printf(" Capture 30 frames with interval of 15ms on default DRM device.\n\n");
printf("Raw buffer capture will be done for each enabled/target plane and one file for each.\nCaptured file will be saved to './' if not specified.\n");
printf("--- By Gopise, 2023/09\n\n");
return;
}
int process_cmdline(int argc, char **argv)
{
int i;
int ret = 0;
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-d") == 0) {
if(i < argc-1)
strcpy(sDrm_name, argv[++i]);
if(strlen(sDrm_name) > 0) {
printf("\tDevice: Target DRM device: %s\n", sDrm_name);
} else {
printf("\tDevice: Error! Unknow target DRM device: %s\n", sDrm_name);
ret = -1;
break;
}
} else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-?") == 0) {
showUsage(argv[0]);
ret = -1;
break;
} else if (strcmp(argv[i], "-v") == 0) {
showVersion();
ret = -1;
break;
} else if (strcmp(argv[i], "-i") == 0) {
printf("\tInfo: Print information only.\n");
iFlag |= FLAG_PRINT_ONLY;
} else if (strcmp(argv[i], "-t") == 0) {
printf("\tDetile: Try de-tile after capture.\n");
iFlag |= FLAG_TILE;
} else if (strcmp(argv[i], "-o") == 0) {
if(i < argc-1)
strcpy(sOutput_folder, argv[++i]);
if(strlen(sOutput_folder) > 0) {
printf("\tOutput: Output folder: %s\n", sOutput_folder);
} else {
printf("\tOutput: Error! Unknow output folder: %s\n", sOutput_folder);
ret = -1;
break;
}
} else if(strcmp(argv[i], "-p") == 0) {
if(i < argc-1)
iTargetPlane = atoi(argv[++i]);
if(iTargetPlane > 0) {
printf("\tPlane: Target plane#: %d\n", iTargetPlane);
} else {
printf("\tPlane: Error! Unknow target plane %s\n", argv[i]);
ret = -1;
break;
}
} else if(strcmp(argv[i], "-r") == 0) {
if(i < argc-1)
iRepeatCount = atoi(argv[++i]);
if(i < argc-1)
iRepeatInterval = atoi(argv[++i]);
if (iRepeatCount <= 0){
printf("\tRepeat: Warning! Unknow repeat count '%s', default to %d\n", argv[i], DEF_REPEAT_COUNT);
iRepeatCount = DEF_REPEAT_COUNT;
}
if (iRepeatInterval <= 0){
printf("\tRepeat: Warning! Unknow repeat interval '%s', default to %d (ms)\n", argv[i], DEF_REPEAT_INTERVAL);
iRepeatInterval = DEF_REPEAT_INTERVAL;
}
printf("\tRepeat: Repeat count: %d, interval: %d\n", iRepeatCount, iRepeatInterval);
iRCounter = 0;
} else {
printf("\tError! Un-recognized parameter: %s\n\n",argv[i]);
showUsage(argv[0]);
ret = -1;
}
}
return ret;
}
int main(int argc, char *argv[])
{
int fd = 0;
drmModeResPtr res = NULL;
drmModePlaneResPtr planeres = NULL;
drmModePlane *ovr[MAX_PLANE];
int i, ct=0, rt=0;
printf("[ DRM screen capture ]\n");
memset(sDrm_name, 0, sizeof(sDrm_name));
memset(ovr, 0, sizeof(ovr));
ct = process_cmdline(argc, argv);
if(ct<0) {
printf("Invalid parameter!");
return -1;
}
if(strlen(sDrm_name) == 0)
strcpy(sDrm_name, DEF_DRM_PATH);
if(strlen(sOutput_folder) == 0)
strcpy(sOutput_folder, DEF_OUTPUT_FOLDER);
printf("\nOpening DRM device: %s (0x%x)\n", sDrm_name, iFlag);
fd = open(sDrm_name, O_RDWR);
if (fd < 0) {
printf("Error:Failed to open the drm device (%s): error: %s\n", sDrm_name, strerror(errno));
rt = -1;
goto Err;
}
drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
res = drmModeGetResources(fd);
if (res == 0) {
printf("Failed to get the resources!\n");
rt = -2;
goto Err;
}
planeres = drmModeGetPlaneResources(fd);
if (!planeres) {
printf("Failed to get the plane resources!\n");
rt = -2;
goto Err;
}
if(planeres->count_planes > MAX_PLANE) {
printf("Too many planes(%d), cap to %d\n", planeres->count_planes, MAX_PLANE);
planeres->count_planes = MAX_PLANE;
}
do {
if (!iRCounter) {
printf("Total plans: %d\n", planeres->count_planes);
printf("%s\t%s\t%s\t%s,%s\t%s,%s\n", "Plane", "CRTC", "FB", "CRTC_x", "CRTC_y", "x", "y");
printf("=================================================\n");
}
ct = 0;
for (i = 0; i < planeres->count_planes; i++) {
ovr[i] = drmModeGetPlane(fd, planeres->planes[i]);
if (!ovr[i])
continue;
if ((ovr[i]->fb_id > 0) && !iRCounter ) {
printf("%d\t%d\t%d\t%d,%d\t\t%d,%d\n",
ovr[i]->plane_id, ovr[i]->crtc_id, ovr[i]->fb_id, ovr[i]->crtc_x,
ovr[i]->crtc_y, ovr[i]->x, ovr[i]->y);
ct++;
}
}
if(!iRCounter)
printf("Plane(s) enabled: %d\n\n", ct);
// Print information only
if(iFlag & FLAG_PRINT_ONLY)
break;
if(!iRCounter)
printf("Dump plane buffer to file ...\n");
ct = 0;
for (i = 0; i < planeres->count_planes; i++) {
if (!ovr[i])
continue;
if ((ovr[i]->fb_id > 0) && (iTargetPlane<0 || iTargetPlane == ovr[i]->plane_id)) {
if(dump_plane(fd, ovr[i])) {
printf("Error found! terminating...");
break;
}
ct ++;
}
}
if(!ct) {
printf("No plane found!\n");
break;
}
#ifdef SUPPORT_VBLANK
/* We will wait for next vblank here */
if(wait4vblank(fd) < 0)
printf("Wait for VBlank failed: %s (%d) \n", strerror(errno), errno);
#else
/* fixed wait */
usleep(iRepeatInterval*1000);
#endif
} while (++iRCounter < iRepeatCount);
/* everything's fine, exit */
goto OK;
Err:
if(rt == -1 || rt == -2)
printf("Try another device through '-d' or refer to the full help message through '-h'\n");
OK:
if(planeres)
drmModeFreePlaneResources(planeres);
if(res)
drmModeFreeResources(res);
if(fd >= 0)
drmClose(fd);
if(!rt) {
printf("\nDone!\n");
}
return 0;
}