Skip to content

Instantly share code, notes, and snippets.

@mac-l1
Last active September 15, 2023 10:31
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mac-l1/8e37223dc8749c9554936c9f0949a55d to your computer and use it in GitHub Desktop.
Save mac-l1/8e37223dc8749c9554936c9f0949a55d to your computer and use it in GitHub Desktop.
sample code to use rockchip drm api; based on rockchip rga test code, modified for yuvrgb conversion for FB display and for X11); needs rockhip drm rga support in kernel and user lib, and probably armsoc X11 display driver; ran on firefly with 3.14 kernel and ubuntu 16.04
/*
* Copyright (C) 2013 Samsung Electronics Co.Ltd
* Authors:
* Yakir Yang <ykk@rock-chips.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#define DEST_RGB_DISP 1
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <unistd.h>
#include <sys/mman.h>
#include <linux/stddef.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <libkms.h>
#include <drm_fourcc.h>
#include "rockchip_drm.h"
#include "rockchip_drmif.h"
#include "rockchip_rga.h"
#define DRM_MODULE_NAME "rockchip"
#define MAX_TEST_CASE 1
struct rga_context *ctx;
struct connector {
uint32_t id;
char mode_str[64];
char format_str[5];
unsigned int fourcc;
drmModeModeInfo *mode;
drmModeEncoder *encoder;
int crtc;
int pipe;
int plane_zpos;
unsigned int fb_id[2], current_fb_id;
struct timeval start;
int swap_count;
};
struct rga_test {
struct rockchip_device *dev;
struct rockchip_bo *dst_bo;
struct rockchip_bo *src_bo;
struct connector src_con;
struct connector dst_con;
struct rga_image src_img;
struct rga_image dst_img;
};
static void connector_find_mode(int fd, struct connector *c, drmModeRes *resources)
{
drmModeConnector *connector;
int i, j;
/* First, find the connector & mode */
c->mode = NULL;
for (i = 0; i < resources->count_connectors; i++) {
connector = drmModeGetConnector(fd, resources->connectors[i]);
if (!connector) {
fprintf(stderr, "could not get connector %i: %s\n",
resources->connectors[i], strerror(errno));
drmModeFreeConnector(connector);
continue;
}
if (!connector->count_modes) {
drmModeFreeConnector(connector);
continue;
}
if (connector->connector_id != c->id) {
drmModeFreeConnector(connector);
continue;
}
for (j = 0; j < connector->count_modes; j++) {
c->mode = &connector->modes[j];
if (!strcmp(c->mode->name, c->mode_str))
break;
}
/* Found it, break out */
if (c->mode)
break;
drmModeFreeConnector(connector);
}
if (!c->mode) {
fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str);
return;
}
/* Now get the encoder */
for (i = 0; i < resources->count_encoders; i++) {
c->encoder = drmModeGetEncoder(fd, resources->encoders[i]);
if (!c->encoder) {
fprintf(stderr, "could not get encoder %i: %s\n",
resources->encoders[i], strerror(errno));
drmModeFreeEncoder(c->encoder);
continue;
}
if (c->encoder->encoder_id == connector->encoder_id)
break;
drmModeFreeEncoder(c->encoder);
}
if (c->crtc == -1)
c->crtc = c->encoder->crtc_id;
}
static int drm_set_crtc(struct rockchip_device *dev, struct connector *c,
unsigned int fb_id)
{
int ret;
ret = drmModeSetCrtc(dev->fd, c->crtc, fb_id, 0, 0, &c->id, 1, c->mode);
if (ret) {
printf("failed to set mode: %s\n", strerror(errno));
goto err;
}
return 0;
err:
return ret;
}
static struct rockchip_bo *rockchip_create_buffer(struct rockchip_device *dev,
unsigned long size,
unsigned int flags)
{
struct rockchip_bo *bo;
bo = rockchip_bo_create(dev, size, flags);
if (!bo)
return bo;
if (!rockchip_bo_map(bo)) {
rockchip_bo_destroy(bo);
return NULL;
}
return bo;
}
static void rockchip_destroy_buffer(struct rockchip_bo *bo)
{
rockchip_bo_destroy(bo);
}
static int read_yuv(const char* filename, uint8_t* pdata, int width, int height)
{
FILE *fp = fopen(filename, "rb");
if ((pdata == NULL) || (fp == NULL)) return 0;
printf("read yuv-frame(%dx%d) data from %s\n", width, height, filename );
fread(pdata, width*height*3/2, 1, fp);
fclose(fp);
return 1;
}
int write_truecolor_tga(char* filename, int* data, int width, int height) {
FILE *fp = fopen(filename, "wb");
if (fp == NULL) return 0;
printf("write frame(tga) data to %s\n", filename );
char header[ 18 ] = { 0 }; // char = byte
header[ 2 ] = 2; // truecolor
header[ 12 ] = width & 0xFF;
header[ 13 ] = (width >> 8) & 0xFF;
header[ 14 ] = height & 0xFF;
header[ 15 ] = (height >> 8) & 0xFF;
header[ 16 ] = 24; // bits per pixel
fwrite((const char*)&header, 1, sizeof(header), fp);
int x,y;
// The image data is stored bottom-to-top, left-to-right
for (y = height -1; y >= 0; y--)
for (x = 0; x < width; x++)
{
char b = (data[x+(y*width)] & 0x0000FF);
char g = (data[x+(y*width)] & 0x00FF00) >> 8;
char r = (data[x+(y*width)] & 0xFF0000) >> 16;
//putc((int)(r & 0xFF),fp);
//putc((int)(g & 0xFF),fp);
//putc((int)(b & 0xFF),fp);
putc((int)(b & 0xFF),fp);
putc((int)(g & 0xFF),fp);
putc((int)(r & 0xFF),fp);
}
// The file footer
static const char footer[ 26 ] =
"\0\0\0\0" // no extension area
"\0\0\0\0" // no developer directory
"TRUEVISION-XFILE" // yep, this is a TGA file
".";
fwrite((const char*)&footer, 1, sizeof(footer), fp);
fclose(fp);
return 1;
}
unsigned int mac_arg_fmt = 0;
static int rga_yuvimg_test(struct rga_test *test)
{
struct rockchip_device *dev = test->dev;
struct rga_image test1 = test->src_img;
struct rga_image test2 = test->dst_img;
uint8_t * _src = test->src_bo->vaddr;
uint8_t * _dst = test->dst_bo->vaddr;
unsigned int img_w, img_h;
unsigned int i, j;
int ret;
img_w = 1920;
img_h = 1088;
//read_yuv("sintel.nv21",_src,img_w,img_h);
read_yuv("rgb1920x1088.nv12",_src,img_w,img_h);
//read_yuv("frame601.yuv",_src,img_w,img_h);
//memcpy(_dst,&_src[img_w*img_h],img_w*img_h/2);
//memcpy(&_src[img_w*img_h+(img_w*img_h/2)],&_src[img_w*img_h],img_w*img_h/2);
//memcpy(&_src[img_w*img_h],_dst,img_w*img_h/2);
test1.width = img_w;
test1.height = img_h;
test1.stride = test1.width;
//test1.color_mode = DRM_FORMAT_YVU420; // yuv420p
test1.color_mode = DRM_FORMAT_NV12;
#define DST_FMT DRM_FORMAT_ARGB8888
img_h = 1080;
test2.width = img_w;
test2.height = img_h;
test2.stride = img_w * 4;
test2.color_mode = DRM_FORMAT_ABGR8888;
//RGA_SRC_COLOR_RB_SWAP = 1,
//RGA_SRC_COLOR_ALPHA_SWAP = 2,
//RGA_SRC_COLOR_UV_SWAP = 4,
//RGA_SRC_CSC_MODE_BT601_R0 = 0,
//RGA_SRC_CSC_MODE_BT601_R1 = 1,
//RGA_SRC_CSC_MODE_BT709_R0 = 2, <<<<<< this one works :-) !!!
//RGA_SRC_CSC_MODE_BT709_R1 = 3,
//RGA_DST_CSC_MODE_BYPASS = 0,
//RGA_DST_CSC_MODE_BT601_R0 = 1,
//RGA_DST_CSC_MODE_BT601_R1 = 2,
//RGA_DST_CSC_MODE_BT709_R0 = 3,
unsigned int mac_format = 0;
if( mac_arg_fmt != -1 ) {
mac_format = 0x80000000 | mac_arg_fmt;
} else {
mac_format = 0;
}
rga_multiple_transform(ctx, &test1, &test2,
0, 0, test1.width, test1.height,
0, 0, test2.width, test2.height,
mac_format, 0, 0);
ret = rga_exec(ctx);
write_truecolor_tga("sintel.tga",_dst,img_w,img_h);
getchar();
return 0;
}
static int rga_context_test(struct rga_test *test)
{
struct rockchip_device *dev = test->dev;
struct rga_image test1 = test->src_img;
struct rga_image test2 = test->dst_img;
uint8_t * _src = test->src_bo->vaddr;
uint8_t * _dst = test->dst_bo->vaddr;
unsigned int img_w, img_h;
unsigned int i, j;
int ret;
img_w = 720;
img_h = 306;
test1.width = img_w;
test1.height = img_h;
test1.stride = test1.width;
test1.color_mode = DRM_FORMAT_NV12;
test2.width = img_h;
test2.height = img_w;
test2.stride = test2.width;
test2.color_mode = DRM_FORMAT_NV12;
test1.fill_color = 0xAA;
ret = rga_solid_fill(ctx, &test1, 0, 0, test1.width, test1.height);
ret = rga_exec(ctx);
if (ret)
return ret;
test2.fill_color = 0x00;
ret = rga_solid_fill(ctx, &test2, 0, 0, test2.width, test2.height);
ret = rga_exec(ctx);
if (ret)
return ret;
rga_multiple_transform(ctx, &test1, &test2, 0, 0, test1.width, test1.height,
0, 0, test2.width, test2.height, 90, 0, 0);
ret = rga_exec(ctx);
if (ret < 0)
return ret;
for (i = 0; i < img_w; i++) {
for (j = 0; j < img_h; j++) {
if (_src[j * img_w + i] != _dst[j * img_w + i]) {
printf("*[RGA ERROR]* : src (%d, %d) [%x] != "
"dst (%d, %d) [%x]\n", i, j, _src[j * img_w + i],
j, i, _dst[j* img_w + i]);
return -1;
}
}
}
return 0;
}
static int rga_rot_scale_test(struct rga_test *test)
{
struct rga_image *src = &test->src_img;
struct rga_image *dst = &test->dst_img;
struct rga_image test_img = *src;
unsigned int i, j;
int ret;
printf("-------- Fill source buffer pattern\n");
src->fill_color = 0x0;
ret = rga_solid_fill(ctx, src, 0, 0, src->width, src->height);
ret = rga_exec(ctx);
if (ret)
return ret;
src->fill_color = 0xff00;
rga_solid_fill(ctx, src, 5, 5, 500, 100);
src->fill_color = 0xff;
rga_solid_fill(ctx, src, 5, 105, 500, 100);
src->fill_color = 0xff0000;
rga_solid_fill(ctx, src, 5, 205, 500, 100);
src->fill_color = 0xffffffff;
rga_solid_fill(ctx, src, 50, 5, 50, 400);
ret = rga_exec(ctx);
if (ret)
return ret;
dst->fill_color = 0x0;
ret = rga_solid_fill(ctx, dst, 0, 0, dst->width, dst->height);
ret = rga_exec(ctx);
if (ret)
return ret;
for (i = 100; i < dst->width; i++) {
for (j = 100; j < dst->height; j+=1) {
printf("------- 0 degree (500, 400) --> (%d, %d)\n", i, j);
rga_multiple_transform(ctx, src, dst, 0, 0, 500, 400,
0, 0, i, j, 0, 0, 0);
ret = rga_exec(ctx);
if (ret < 0)
return ret;
#if 0
/*
* RGA API Related:
*
* This code would SCALING and RORATE 90 Degree the source
* framebuffer, and place the output to dest framebuffer,
* and the window size is:
*/
printf("------- 90 degree (500, 400) --> (%d, %d)\n", i, j);
rga_multiple_transform(ctx, src, dst, 0, 0, 500, 400,
0, 0, i, j, 90, 0, 0);
ret = rga_exec(ctx);
if (ret < 0)
return ret;
printf("------- 180 degree (500, 400) --> (%d, %d)\n", i, j);
rga_multiple_transform(ctx, src, dst, 0, 0, 500, 400,
0, 0, i, j, 180, 0, 0);
ret = rga_exec(ctx);
if (ret < 0)
return ret;
printf("------- 270 degree (500, 400) --> (%d, %d)\n", i, j);
rga_multiple_transform(ctx, src, dst, 0, 0, 500, 400,
0, 0, i, j, 270, 0, 0);
ret = rga_exec(ctx);
if (ret < 0)
return ret;
#endif
}
}
return 0;
}
static int rga_cmdlist_test(struct rga_test *test)
{
struct rga_image *dst = &test->dst_img;
int ret;
{///while (1) {
dst->fill_color = 0x0;
rga_solid_fill(ctx, dst, 0, 0, dst->width, dst->height);
ret = rga_exec(ctx);
if (ret)
return ret;
dst->fill_color = 0xff00;
rga_solid_fill(ctx, dst, 5, 5, 500, 100);
dst->fill_color = 0xff;
rga_solid_fill(ctx, dst, 5, 105, 500, 100);
dst->fill_color = 0xff0000;
rga_solid_fill(ctx, dst, 5, 205, 500, 100);
dst->fill_color = 0xffffffff;
rga_solid_fill(ctx, dst, 50, 5, 50, 400);
ret = rga_exec(ctx);
if (ret)
return ret;
getchar();
}
return 0;
}
static int rga_color_fill_test(struct rga_test *test)
{
int ret;
struct rga_image *dst = &test->dst_img;
/*
* RGA API Related:
*
* Initialize the source framebuffer and dest framebuffer with BLACK color.
*
* The "->fill_color" variable is corresponding to RGA target color, and it's
* ARGB8888 format, like if you want the source framebuffer filled with
* RED COLOR, then you should fill the "->fill_color" with 0x00ff0000.
*/
dst->fill_color = 0xff0000ff;
rga_solid_fill(ctx, dst, 0, 0, dst->width, dst->height);
ret = rga_exec(ctx);
if (ret)
return ret;
sleep(1);
dst->fill_color = 0xff00ff00;
rga_solid_fill(ctx, dst, 0, 0, dst->width, dst->height);
ret = rga_exec(ctx);
if (ret)
return ret;
sleep(1);
dst->fill_color = 0xffff0000;
rga_solid_fill(ctx, dst, 0, 0, dst->width, dst->height);
ret = rga_exec(ctx);
if (ret)
return ret;
sleep(1);
return 0;
}
static int rga_csc_test(struct rockchip_device *dev, struct rga_image *src, struct rga_image *dst)
{
struct rga_image test = *src;
int ret;
test.width = src->width;
test.height = src->height;
test.stride = test.width * 4;
test.color_mode = DRM_FORMAT_XRGB8888;
test.fill_color = 0xffffffff;
rga_solid_fill(ctx, &test, 0, 0, test.width, test.height);
ret = rga_exec(ctx);
if (ret)
return ret;
sleep(1);
ret = rga_multiple_transform(ctx, &test, dst, 0, 0, test.width, test.height,
0, 0, dst->width, dst->height, 0, 0, 0);
ret = rga_exec(ctx);
if (ret)
return ret;
return 0;
}
static int rga_test(struct rga_test *test)
{
int ret;
/*
printf("cmdlist test\n");
ret = rga_cmdlist_test(test);
if (ret) {
printf("*[RGA ERROR]*: Failed at cmdlist test\n");
return ret;
}
*/
ret = rga_yuvimg_test(test);
/*
printf("color fill test\n");
ret = rga_color_fill_test(test);
if (ret) {
printf("*[RGA ERROR]*: Failed at color fill test\n");
return ret;
}
ret = rga_context_test(test);
if (ret) {
printf("*[RGA ERROR]*: Failed at context test\n");
return ret;
}
printf("rotate / scale test\n");
ret = rga_rot_scale_test(test);
if (ret) {
printf("*[RGA ERROR]*: Failed at rotate / scale test\n");
return ret;
}
*/
return 0;
}
static int rga_copy_nv12_to_nv12_test(struct rga_test *test, enum e_rga_buf_type type)
{
struct rockchip_device *dev = test->dev;
struct rockchip_bo *src = test->src_bo;
struct rockchip_bo *dst = test->dst_bo;
struct connector *src_con = &test->src_con;
struct connector *dst_con = &test->dst_con;
struct rga_image src_img = {0}, dst_img = {0};
unsigned int img_w, img_h;
int dst_fd, src_fd;
/*
* RGA API Related:
*
* Due to RGA API only accept the fd of dma_buf, so we need
* to conver the dma_buf Handle to dma_buf FD.
*
* And then just assigned the src/dst framebuffer FD to the
* "struct rga_img".
*
* And for now, RGA driver only support GEM buffer type, so
* we also need to assign the src/dst buffer type to RGA_IMGBUF_GEM.
*
* For futher, I would try to add user point support.
*/
drmPrimeHandleToFD(dev->fd, dst->handle, 0 , &dst_fd);
drmPrimeHandleToFD(dev->fd, src->handle, 0 , &src_fd);
dst_img.bo[0] = dst_fd;
src_img.bo[0] = src_fd;
/*
* RGA API Related:
*
* Configure the source FB width / height / stride / color_mode.
*
* The width / height is correspond to the framebuffer width /height
*
* The stride is equal to (width * pixel_width).
*
* The color_mode should configure to the standard DRM color format
* which defined in "/user/include/drm/drm_fourcc.h"
*
*/
img_w = src_con->mode->hdisplay;
img_h = src_con->mode->vdisplay;
src_img.width = img_w;
src_img.height = img_h;
src_img.stride = img_w;
src_img.buf_type = type;
src_img.color_mode = DRM_FORMAT_NV12;
img_w = dst_con->mode->hdisplay;
img_h = dst_con->mode->vdisplay;
dst_img.width = img_w;
dst_img.height = img_h;
dst_img.buf_type = type;
#ifdef DEST_RGB_DISP
dst_img.stride = img_w * 4;
dst_img.color_mode = DST_FMT;
#else
dst_img.stride = img_w;
dst_img.color_mode = DRM_FORMAT_NV12;
#endif
/*
* RGA Tested Related:
*
* Start to run test between source FB and dest FB
*/
test->dst_img = dst_img;
test->src_img = src_img;
rga_test(test);
close(src_fd);
close(dst_fd);
return 0;
}
static struct rockchip_bo *init_crtc(struct connector *con,
struct rockchip_device *dev)
{
struct rockchip_bo *bo;
unsigned int screen_width, screen_height;
drmModeRes *resources;
resources = drmModeGetResources(dev->fd);
if (!resources) {
fprintf(stderr, "drmModeGetResources failed: %s\n",
strerror(errno));
return NULL;
}
connector_find_mode(dev->fd, con, resources);
drmModeFreeResources(resources);
if (!con->mode) {
fprintf(stderr, "failed to find usable connector\n");
return NULL;
}
screen_width = con->mode->hdisplay;
screen_height = con->mode->vdisplay;
if (screen_width == 0 || screen_height == 0) {
fprintf(stderr, "failed to find sane resolution on connector\n");
return NULL;
}
printf("screen width = %d, screen height = %d\n", screen_width, screen_height);
bo = rockchip_create_buffer(dev, screen_width * screen_height * 4, 0);
if (!bo) {
return NULL;
}
con->plane_zpos = -1;
return bo;
}
static int rga_nv12_to_nv12_test(struct rga_test *test)
{
struct rockchip_device *dev = test->dev;
struct rockchip_bo *dst_bo = test->dst_bo;
struct connector *dst_con = &test->dst_con;
uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
unsigned int dst_fb_id;
int ret, modes;
/*
* Dest FB Displayed Related:
*
* Add the dest framebuffer to DRM connector, note that for NV12
* display, the virtual stride is (width), that's why pitches[0]
* is hdisplay.
*/
#ifdef DEST_RGB_DISP
modes = DST_FMT;
pitches[0] = dst_con->mode->hdisplay * 4;
#else
modes = DRM_FORMAT_NV12;
pitches[0] = dst_con->mode->hdisplay;
handles[1] = dst_bo->handle;
pitches[1] = dst_con->mode->hdisplay;
offsets[1] = dst_con->mode->hdisplay * dst_con->mode->vdisplay;
#endif
handles[0] = dst_bo->handle;
offsets[0] = 0;
ret = drmModeAddFB2(dev->fd, dst_con->mode->hdisplay, dst_con->mode->vdisplay,
modes, handles, pitches, offsets, &dst_fb_id, 0);
if (ret < 0)
return -EFAULT;
ret = drm_set_crtc(dev, dst_con, dst_fb_id);
if (ret < 0)
return -EFAULT;
/*
* TEST RGA Related:
*
* Start to configure the RGA module and run test
*/
ret = rga_copy_nv12_to_nv12_test(test, RGA_IMGBUF_GEM);
if (ret < 0) {
fprintf(stderr, "failed to test copy operation.\n");
return -EFAULT;
}
/*
* Display Related:
*
* Released the display framebufffer refer which hold
* by DRM display framework
*/
drmModeRmFB(dev->fd, dst_fb_id);
return 0;
}
int main_old(int argc, char **argv)
{
struct rockchip_device *dev;
struct connector src_con, dst_con;
struct rga_test test = {0};
int fd;
fd = drmOpen(DRM_MODULE_NAME, NULL);
if (fd < 0) {
fprintf(stderr, "failed to open.\n");
return fd;
}
dev = rockchip_device_create(fd);
if (!dev) {
drmClose(dev->fd);
return -EFAULT;
}
/*
* RGA API Related:
*
* Open the RGA device
*/
ctx = rga_init(dev->fd);
if (!ctx)
return -EFAULT;
/*
* Test Display Related:
*
* Source framebuffer display connector init. Just a
* hack. Directly use the eDP monitor, and force to
* use the 1920x1080 display mode.
*/
memset(&src_con, 0, sizeof(struct connector));
src_con.crtc = -1;
src_con.id = 33;
src_con.mode = alloca(sizeof(drmModeModeInfo));
src_con.mode->hdisplay = 720;
src_con.mode->vdisplay = 720;
src_con.plane_zpos = -1;
test.src_bo = rockchip_create_buffer(dev, src_con.mode->hdisplay * src_con.mode->vdisplay * 4, 0);
if (!test.src_bo) {
fprintf(stderr, "Failed to create source fb!\n");
return -EFAULT;
}
/*
* Test Display Related:
*
* Dest framebuffer display connector init. Just a
* hack. Directly use the eDP monitor, and force to
* use the 1280x800 display mode.
*/
dst_con.crtc = -1;
dst_con.id = 29;
strcpy(dst_con.mode_str, "2560x1600");
strcpy(dst_con.mode_str, "2048x1536");
dst_con.id = 27;
strcpy(dst_con.mode_str, "1200x1920");
dst_con.id = 30;
strcpy(dst_con.mode_str, "1920x1080");
test.dst_bo = init_crtc(&dst_con, dev);
if (test.dst_bo == NULL) {
printf("init dst crtc failed \n");
return 0;
}
test.dst_con = dst_con;
test.src_con = src_con;
test.dev = dev;
printf("Satrting NV12 to NV12 RGA test, [Press Enter to continue]\n");
rga_nv12_to_nv12_test(&test);
rga_fini(ctx);
rockchip_destroy_buffer(test.src_bo);
rockchip_destroy_buffer(test.dst_bo);
drmClose(dev->fd);
rockchip_device_destroy(dev);
return 0;
}
int main(int argc, char **argv)
{
struct rockchip_device *dev;
struct connector src_con, dst_con;
struct rga_test test = {0};
int fd;
mac_arg_fmt = -1;
if( argc > 1) {
sscanf(argv[1],"%X",&mac_arg_fmt);
printf("mac_arg_fmt = %x = %d\n", mac_arg_fmt, mac_arg_fmt);
}
fd = drmOpen(DRM_MODULE_NAME, NULL);
if (fd < 0) {
fprintf(stderr, "failed to open.\n");
return fd;
}
dev = rockchip_device_create(fd);
if (!dev) {
drmClose(dev->fd);
return -EFAULT;
}
ctx = rga_init(dev->fd);
if (!ctx)
return -EFAULT;
memset(&src_con, 0, sizeof(struct connector));
src_con.mode = alloca(sizeof(drmModeModeInfo));
src_con.mode->hdisplay = 1920;
src_con.mode->vdisplay = 1088;
test.src_bo = rockchip_create_buffer(dev, src_con.mode->hdisplay * src_con.mode->vdisplay * 4, 0);
if (!test.src_bo) {
fprintf(stderr, "Failed to create source fb!\n");
return -EFAULT;
}
#if 1
dst_con.crtc = -1;
dst_con.id = 31;
strcpy(dst_con.mode_str, "1920x1080");
test.dst_bo = init_crtc(&dst_con, dev);
if (test.dst_bo == NULL) {
printf("init dst crtc failed \n");
return 0;
}
#else
memset(&dst_con, 0, sizeof(struct connector));
dst_con.mode = alloca(sizeof(drmModeModeInfo));
dst_con.mode->hdisplay = 1920;
dst_con.mode->vdisplay = 1080;
test.dst_bo = rockchip_create_buffer(dev, dst_con.mode->hdisplay * dst_con.mode->vdisplay * 4, 0);
if (!test.dst_bo) {
fprintf(stderr, "Failed to create source fb!\n");
return -EFAULT;
}
#endif
test.src_con = src_con;
test.dst_con = dst_con;
test.dev = dev;
rga_nv12_to_nv12_test(&test);
//rga_copy_nv12_to_nv12_test(&test, RGA_IMGBUF_GEM);
rga_fini(ctx);
rockchip_destroy_buffer(test.src_bo);
rockchip_destroy_buffer(test.dst_bo);
drmClose(dev->fd);
rockchip_device_destroy(dev);
return 0;
}
/*
* Copyright (C) 2013 Samsung Electronics Co.Ltd
* Authors:
* Yakir Yang <ykk@rock-chips.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#define DEST_RGB_DISP 1
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/stddef.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <libkms.h>
#include <drm_fourcc.h>
#include "rockchip_drm.h"
#include "rockchip_drmif.h"
#include "rockchip_rga.h"
#include <X11/Xlib.h>
#include <X11/Xmd.h>
#include <X11/extensions/dri2proto.h>
#include <X11/extensions/dri2.h>
#include <X11/Xlibint.h>
#include <X11/extensions/Xext.h>
#include <X11/extensions/extutil.h>
#include <X11/Xutil.h>
#include <sys/shm.h>
#include <X11/extensions/XShm.h>
#include <stdint.h>
#define DRM_MODULE_NAME "rockchip"
#define DEMO_DEBUG(fmt, ...) do { printf("DEBUG:%s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__); } while (0)
#define DEMO_ERROR(fmt, ...) do { printf("ERROR:%s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__); } while (0)
#define DEMO_INFO(fmt, ...) do { printf("INFO:%s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__); } while (0)
struct rga_context *ctx;
struct rk_dma_buffer {
int fd;
int handle;
uint8_t *vir_addr;
int size;
};
struct cmd_context {
Display *display;
Window win;
struct rk_dma_buffer x11_dma_buffers[2];
DRI2Buffer *dri2_bufs;
int nbufs;
int screen_width;
int screen_height;
int choose_screen;
int displayed;
/* rga display */
struct rga_context *rga_ctx;
/* /dev/dri/card0 fd with xserver authenticated */
int authenticated_fd;
};
struct connector {
uint32_t id;
char mode_str[64];
char format_str[5];
unsigned int fourcc;
drmModeModeInfo *mode;
drmModeEncoder *encoder;
int crtc;
int pipe;
int plane_zpos;
unsigned int fb_id[2], current_fb_id;
struct timeval start;
int swap_count;
};
struct rga_test {
struct rockchip_device *dev;
struct rockchip_bo *dst_bo;
struct rockchip_bo *src_bo;
struct connector src_con;
struct connector dst_con;
struct rga_image src_img;
struct rga_image dst_img;
};
void init_x11_context(struct cmd_context *cmd_ctx)
{
//cmd_ctx->display = XOpenDisplay(getenv("DISPLAY"));
cmd_ctx->display = XOpenDisplay(":0.0");
#if 1
/* Initial Window */
cmd_ctx->win = XCreateSimpleWindow(cmd_ctx->display,
RootWindow(cmd_ctx->display, DefaultScreen(cmd_ctx->display)),
0, 0,
DisplayWidth(cmd_ctx->display, 0),
DisplayHeight(cmd_ctx->display, 0),
0,
BlackPixel(cmd_ctx->display, DefaultScreen(cmd_ctx->display)),
BlackPixel(cmd_ctx->display, DefaultScreen(cmd_ctx->display)));
XMapWindow(cmd_ctx->display, cmd_ctx->win);
XResizeWindow(cmd_ctx->display, cmd_ctx->win, 800, 600);
XSync(cmd_ctx->display, False);
XFlush(cmd_ctx->display);
usleep(100000);
#endif
}
static int dri2_connect(Display *dpy, int fd, int driverType, char **driver)
{
int eventBase, errorBase, major, minor;
char *device;
drm_magic_t magic;
Window root;
if (!DRI2InitDisplay(dpy, NULL)) {
DEMO_ERROR("DRI2InitDisplay failed");
return -1;
}
if (!DRI2QueryExtension(dpy, &eventBase, &errorBase)) {
DEMO_ERROR("DRI2QueryExtension failed");
return -1;
}
DEMO_DEBUG("DRI2QueryExtension: eventBase=%d, errorBase=%d", eventBase, errorBase);
if (!DRI2QueryVersion(dpy, &major, &minor)) {
DEMO_ERROR("DRI2QueryVersion failed");
return -1;
}
DEMO_DEBUG("DRI2QueryVersion: major=%d, minor=%d", major, minor);
root = RootWindow(dpy, DefaultScreen(dpy));
if (!DRI2Connect(dpy, root, driverType, driver, &device)) {
DEMO_ERROR("DRI2Connect failed");
return -1;
}
DEMO_DEBUG("DRI2Connect: driver=%s, device=%s", *driver, device);
if (drmGetMagic(fd, &magic)) {
DEMO_ERROR("drmGetMagic failed");
return -1;
}
if (!DRI2Authenticate(dpy, root, magic)) {
DEMO_ERROR("DRI2Authenticate failed");
return -1;
}
return fd;
}
int init_authenticated_fd(struct cmd_context *cmd_ctx)
{
char *driver;
cmd_ctx->authenticated_fd = open("/dev/dri/card0", O_RDWR);
if (cmd_ctx->authenticated_fd < 0) {
DEMO_ERROR("failed to open");
return -1;
}
dri2_connect(cmd_ctx->display, cmd_ctx->authenticated_fd, DRI2DriverDRI, &driver);
cmd_ctx->rga_ctx = rga_init(cmd_ctx->authenticated_fd);
if (!cmd_ctx->rga_ctx) {
DEMO_ERROR("rga init failed");
return -1;
}
DEMO_DEBUG("driver name:%s", driver);
}
int get_x11_dma_buffer(struct cmd_context *cmd_ctx)
{
int i;
unsigned attachments[] = {
0,
1,
};
/* create X11 display buffer. in fact, they are dma_buffers */
DRI2CreateDrawable(cmd_ctx->display, cmd_ctx->win);
cmd_ctx->dri2_bufs = DRI2GetBuffers(cmd_ctx->display, cmd_ctx->win,
&cmd_ctx->screen_width,
&cmd_ctx->screen_height,
attachments, 2, &cmd_ctx->nbufs);
DEMO_DEBUG("display width %d height %d nbufs %d", cmd_ctx->screen_width,
cmd_ctx->screen_height, cmd_ctx->nbufs);
/* get x11 display buffer handle */
for (i = 0; i < cmd_ctx->nbufs; i++) {
int err;
struct drm_gem_open req;
DEMO_DEBUG("dri2_bufs[%d] name %u attachment %u flags %u cpp %u pitch %u",
i, cmd_ctx->dri2_bufs[i].names[0],
cmd_ctx->dri2_bufs[i].attachment,
cmd_ctx->dri2_bufs[i].flags,
cmd_ctx->dri2_bufs[i].cpp,
cmd_ctx->dri2_bufs[i].pitch[0]);
req.name = cmd_ctx->dri2_bufs[i].names[0];
int ret = drmIoctl(cmd_ctx->authenticated_fd, DRM_IOCTL_GEM_OPEN, &req);
cmd_ctx->x11_dma_buffers[i].handle = req.handle;
cmd_ctx->x11_dma_buffers[i].size = req.size;
DEMO_DEBUG("ret %d dri2_bufs[%d] handle is %d size %lu", ret, i, req.handle, req.size);
drmPrimeHandleToFD(cmd_ctx->authenticated_fd,
cmd_ctx->x11_dma_buffers[i].handle, 0, &cmd_ctx->x11_dma_buffers[i].fd);
struct drm_mode_map_dumb dmmd;
memset(&dmmd, 0, sizeof(dmmd));
dmmd.handle = req.handle;
err = drmIoctl(cmd_ctx->authenticated_fd, DRM_IOCTL_MODE_MAP_DUMB, &dmmd);
if (err) {
DEMO_ERROR("drm mode map failed");
return err;
}
cmd_ctx->x11_dma_buffers[i].vir_addr = mmap(0, cmd_ctx->x11_dma_buffers[i].size,
PROT_READ | PROT_WRITE,
MAP_SHARED, cmd_ctx->authenticated_fd,
dmmd.offset);
DEMO_DEBUG("x11_dma_buffers[%d].vir_addr %p", i, cmd_ctx->x11_dma_buffers[i].vir_addr);
if (cmd_ctx->x11_dma_buffers[i].vir_addr == MAP_FAILED) {
DEMO_ERROR("drm map failed");
return err;
}
}
}
static int rga_convert_copy(struct rga_context *rga_ctx,
int src_fd,
int src_width,
int src_height,
uint32_t src_stride,
uint32_t src_fmt,
int dst_fd,
int dst_width,
int dst_height,
uint32_t dst_stride,
uint32_t dst_fmt,
enum e_rga_buf_type type)
{
struct rga_image src_img = { 0 }, dst_img = { 0 };
unsigned int img_w, img_h;
dst_img.bo[0] = dst_fd;
src_img.bo[0] = src_fd;
/*
* Source Framebuffer OPS
*/
src_img.width = src_width;
src_img.height = src_height;
src_img.stride = src_stride;
src_img.buf_type = type;
src_img.color_mode = src_fmt;
/*
* Dest Framebuffer OPS
*/
dst_img.width = dst_width;
dst_img.height = dst_height;
dst_img.stride = dst_stride;
dst_img.buf_type = type;
dst_img.color_mode = dst_fmt;
DEMO_DEBUG("src fd %d stride %d dst stirde %d fd %d", src_fd, src_img.stride, dst_img.stride, dst_fd);
/*
* RGA API Related:
*
* This code would SCALING the source framebuffer, and place
* the output to dest framebuffer, and the window size is:
*
* Source Window Dest Window
* Start - End Start - End
* (0, 0) - (src_w, src_h) (0.0) - (dst_w, dst_h)
*/
rga_multiple_transform(rga_ctx, &src_img, &dst_img,
0, 0, src_img.width, src_img.height,
0, 0, dst_img.width, dst_img.height,
0, 0, 0);
rga_exec(rga_ctx);
return 0;
}
static void connector_find_mode(int fd, struct connector *c, drmModeRes *resources)
{
drmModeConnector *connector;
int i, j;
/* First, find the connector & mode */
c->mode = NULL;
for (i = 0; i < resources->count_connectors; i++) {
connector = drmModeGetConnector(fd, resources->connectors[i]);
if (!connector) {
fprintf(stderr, "could not get connector %i: %s\n",
resources->connectors[i], strerror(errno));
drmModeFreeConnector(connector);
continue;
}
if (!connector->count_modes) {
drmModeFreeConnector(connector);
continue;
}
if (connector->connector_id != c->id) {
drmModeFreeConnector(connector);
continue;
}
for (j = 0; j < connector->count_modes; j++) {
c->mode = &connector->modes[j];
if (!strcmp(c->mode->name, c->mode_str))
break;
}
/* Found it, break out */
if (c->mode)
break;
drmModeFreeConnector(connector);
}
if (!c->mode) {
fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str);
return;
}
/* Now get the encoder */
for (i = 0; i < resources->count_encoders; i++) {
c->encoder = drmModeGetEncoder(fd, resources->encoders[i]);
if (!c->encoder) {
fprintf(stderr, "could not get encoder %i: %s\n",
resources->encoders[i], strerror(errno));
drmModeFreeEncoder(c->encoder);
continue;
}
if (c->encoder->encoder_id == connector->encoder_id)
break;
drmModeFreeEncoder(c->encoder);
}
if (c->crtc == -1)
c->crtc = c->encoder->crtc_id;
}
static int drm_set_crtc(struct rockchip_device *dev, struct connector *c,
unsigned int fb_id)
{
int ret;
ret = drmModeSetCrtc(dev->fd, c->crtc, fb_id, 0, 0, &c->id, 1, c->mode);
if (ret) {
printf("failed to set mode: %s\n", strerror(errno));
goto err;
}
return 0;
err:
return ret;
}
static struct rockchip_bo *rockchip_create_buffer(struct rockchip_device *dev,
unsigned long size,
unsigned int flags)
{
struct rockchip_bo *bo;
bo = rockchip_bo_create(dev, size, flags);
if (!bo)
return bo;
if (!rockchip_bo_map(bo)) {
rockchip_bo_destroy(bo);
return NULL;
}
return bo;
}
static void rockchip_destroy_buffer(struct rockchip_bo *bo)
{
rockchip_bo_destroy(bo);
}
static int read_yuv(const char* filename, uint8_t* pdata, int width, int height)
{
FILE *fp = fopen(filename, "rb");
if ((pdata == NULL) || (fp == NULL)) return 0;
printf("read yuv-frame(%dx%d) data from %s\n", width, height, filename );
fread(pdata, width*height*3/2, 1, fp);
fclose(fp);
return 1;
}
int write_truecolor_tga(char* filename, int* data, int width, int height) {
FILE *fp = fopen(filename, "wb");
if (fp == NULL) return 0;
printf("write frame(tga) data to %s\n", filename );
char header[ 18 ] = { 0 }; // char = byte
header[ 2 ] = 2; // truecolor
header[ 12 ] = width & 0xFF;
header[ 13 ] = (width >> 8) & 0xFF;
header[ 14 ] = height & 0xFF;
header[ 15 ] = (height >> 8) & 0xFF;
header[ 16 ] = 24; // bits per pixel
fwrite((const char*)&header, 1, sizeof(header), fp);
int x,y;
// The image data is stored bottom-to-top, left-to-right
for (y = height -1; y >= 0; y--)
for (x = 0; x < width; x++)
{
char b = (data[x+(y*width)] & 0x0000FF);
char g = (data[x+(y*width)] & 0x00FF00) >> 8;
char r = (data[x+(y*width)] & 0xFF0000) >> 16;
//putc((int)(r & 0xFF),fp);
//putc((int)(g & 0xFF),fp);
//putc((int)(b & 0xFF),fp);
putc((int)(b & 0xFF),fp);
putc((int)(g & 0xFF),fp);
putc((int)(r & 0xFF),fp);
}
// The file footer
static const char footer[ 26 ] =
"\0\0\0\0" // no extension area
"\0\0\0\0" // no developer directory
"TRUEVISION-XFILE" // yep, this is a TGA file
".";
fwrite((const char*)&footer, 1, sizeof(footer), fp);
fclose(fp);
return 1;
}
unsigned int mac_arg_fmt = 0;
static int rga_yuvimg_test(struct rga_test *test)
{
struct rockchip_device *dev = test->dev;
struct rga_image test1 = test->src_img;
struct rga_image test2 = test->dst_img;
uint8_t * _src = test->src_bo->vaddr;
//uint8_t * _dst = test->dst_bo->vaddr;
unsigned int img_w, img_h;
unsigned int i, j;
int ret;
img_w = 1920;
img_h = 1088;
//read_yuv("sintel.nv21",_src,img_w,img_h);
read_yuv("rgb1920x1088.nv12",_src,img_w,img_h);
//read_yuv("frame601.yuv",_src,img_w,img_h);
//memcpy(_dst,&_src[img_w*img_h],img_w*img_h/2);
//memcpy(&_src[img_w*img_h+(img_w*img_h/2)],&_src[img_w*img_h],img_w*img_h/2);
//memcpy(&_src[img_w*img_h],_dst,img_w*img_h/2);
test1.width = img_w;
test1.height = img_h;
test1.stride = test1.width;
//test1.color_mode = DRM_FORMAT_YVU420; // yuv420p
test1.color_mode = DRM_FORMAT_NV12;
//img_h = 1080;
//test2.width = img_w;
//test2.height = img_h;
//test2.stride = img_w * 4;
//test2.color_mode = DRM_FORMAT_ABGR8888;
//RGA_SRC_COLOR_RB_SWAP = 1,
//RGA_SRC_COLOR_ALPHA_SWAP = 2,
//RGA_SRC_COLOR_UV_SWAP = 4,
//RGA_SRC_CSC_MODE_BT601_R0 = 0,
//RGA_SRC_CSC_MODE_BT601_R1 = 1,
//RGA_SRC_CSC_MODE_BT709_R0 = 2, <<<<<< this one works :-) !!!
//RGA_SRC_CSC_MODE_BT709_R1 = 3,
//RGA_DST_CSC_MODE_BYPASS = 0,
//RGA_DST_CSC_MODE_BT601_R0 = 1,
//RGA_DST_CSC_MODE_BT601_R1 = 2,
//RGA_DST_CSC_MODE_BT709_R0 = 3,
unsigned int mac_format = 0;
if( mac_arg_fmt != -1 ) {
mac_format = 0x80000000 | mac_arg_fmt;
} else {
mac_format = 0;
}
rga_multiple_transform(ctx, &test1, &test2,
0, 0, test1.width, test1.height,
0, 0, test2.width, test2.height,
mac_format, 0, 0);
ret = rga_exec(ctx);
//write_truecolor_tga("sintel.tga",_dst,img_w,img_h);
//getchar();
return 0;
}
static int rga_context_test(struct rga_test *test)
{
struct rockchip_device *dev = test->dev;
struct rga_image test1 = test->src_img;
struct rga_image test2 = test->dst_img;
uint8_t * _src = test->src_bo->vaddr;
uint8_t * _dst = test->dst_bo->vaddr;
unsigned int img_w, img_h;
unsigned int i, j;
int ret;
img_w = 720;
img_h = 306;
test1.width = img_w;
test1.height = img_h;
test1.stride = test1.width;
test1.color_mode = DRM_FORMAT_NV12;
test2.width = img_h;
test2.height = img_w;
test2.stride = test2.width;
test2.color_mode = DRM_FORMAT_NV12;
test1.fill_color = 0xAA;
ret = rga_solid_fill(ctx, &test1, 0, 0, test1.width, test1.height);
ret = rga_exec(ctx);
if (ret)
return ret;
test2.fill_color = 0x00;
ret = rga_solid_fill(ctx, &test2, 0, 0, test2.width, test2.height);
ret = rga_exec(ctx);
if (ret)
return ret;
rga_multiple_transform(ctx, &test1, &test2, 0, 0, test1.width, test1.height,
0, 0, test2.width, test2.height, 90, 0, 0);
ret = rga_exec(ctx);
if (ret < 0)
return ret;
for (i = 0; i < img_w; i++) {
for (j = 0; j < img_h; j++) {
if (_src[j * img_w + i] != _dst[j * img_w + i]) {
printf("*[RGA ERROR]* : src (%d, %d) [%x] != "
"dst (%d, %d) [%x]\n", i, j, _src[j * img_w + i],
j, i, _dst[j* img_w + i]);
return -1;
}
}
}
return 0;
}
static int rga_rot_scale_test(struct rga_test *test)
{
struct rga_image *src = &test->src_img;
struct rga_image *dst = &test->dst_img;
struct rga_image test_img = *src;
unsigned int i, j;
int ret;
printf("-------- Fill source buffer pattern\n");
src->fill_color = 0x0;
ret = rga_solid_fill(ctx, src, 0, 0, src->width, src->height);
ret = rga_exec(ctx);
if (ret)
return ret;
src->fill_color = 0xff00;
rga_solid_fill(ctx, src, 5, 5, 500, 100);
src->fill_color = 0xff;
rga_solid_fill(ctx, src, 5, 105, 500, 100);
src->fill_color = 0xff0000;
rga_solid_fill(ctx, src, 5, 205, 500, 100);
src->fill_color = 0xffffffff;
rga_solid_fill(ctx, src, 50, 5, 50, 400);
ret = rga_exec(ctx);
if (ret)
return ret;
dst->fill_color = 0x0;
ret = rga_solid_fill(ctx, dst, 0, 0, dst->width, dst->height);
ret = rga_exec(ctx);
if (ret)
return ret;
for (i = 100; i < dst->width; i++) {
for (j = 100; j < dst->height; j+=1) {
printf("------- 0 degree (500, 400) --> (%d, %d)\n", i, j);
rga_multiple_transform(ctx, src, dst, 0, 0, 500, 400,
0, 0, i, j, 0, 0, 0);
ret = rga_exec(ctx);
if (ret < 0)
return ret;
#if 0
/*
* RGA API Related:
*
* This code would SCALING and RORATE 90 Degree the source
* framebuffer, and place the output to dest framebuffer,
* and the window size is:
*/
printf("------- 90 degree (500, 400) --> (%d, %d)\n", i, j);
rga_multiple_transform(ctx, src, dst, 0, 0, 500, 400,
0, 0, i, j, 90, 0, 0);
ret = rga_exec(ctx);
if (ret < 0)
return ret;
printf("------- 180 degree (500, 400) --> (%d, %d)\n", i, j);
rga_multiple_transform(ctx, src, dst, 0, 0, 500, 400,
0, 0, i, j, 180, 0, 0);
ret = rga_exec(ctx);
if (ret < 0)
return ret;
printf("------- 270 degree (500, 400) --> (%d, %d)\n", i, j);
rga_multiple_transform(ctx, src, dst, 0, 0, 500, 400,
0, 0, i, j, 270, 0, 0);
ret = rga_exec(ctx);
if (ret < 0)
return ret;
#endif
}
}
return 0;
}
static int rga_cmdlist_test(struct rga_test *test)
{
struct rga_image *dst = &test->dst_img;
int ret;
{///while (1) {
dst->fill_color = 0x0;
rga_solid_fill(ctx, dst, 0, 0, dst->width, dst->height);
ret = rga_exec(ctx);
if (ret)
return ret;
dst->fill_color = 0xff00;
rga_solid_fill(ctx, dst, 5, 5, 500, 100);
dst->fill_color = 0xff;
rga_solid_fill(ctx, dst, 5, 105, 500, 100);
dst->fill_color = 0xff0000;
rga_solid_fill(ctx, dst, 5, 205, 500, 100);
dst->fill_color = 0xffffffff;
rga_solid_fill(ctx, dst, 50, 5, 50, 400);
ret = rga_exec(ctx);
if (ret)
return ret;
getchar();
}
return 0;
}
static int rga_color_fill_test(struct rga_test *test)
{
int ret;
struct rga_image *dst = &test->dst_img;
/*
* RGA API Related:
*
* Initialize the source framebuffer and dest framebuffer with BLACK color.
*
* The "->fill_color" variable is corresponding to RGA target color, and it's
* ARGB8888 format, like if you want the source framebuffer filled with
* RED COLOR, then you should fill the "->fill_color" with 0x00ff0000.
*/
dst->fill_color = 0xff0000ff;
rga_solid_fill(ctx, dst, 0, 0, dst->width, dst->height);
ret = rga_exec(ctx);
if (ret)
return ret;
sleep(1);
dst->fill_color = 0xff00ff00;
rga_solid_fill(ctx, dst, 0, 0, dst->width, dst->height);
ret = rga_exec(ctx);
if (ret)
return ret;
sleep(1);
dst->fill_color = 0xffff0000;
rga_solid_fill(ctx, dst, 0, 0, dst->width, dst->height);
ret = rga_exec(ctx);
if (ret)
return ret;
sleep(1);
return 0;
}
static int rga_csc_test(struct rockchip_device *dev, struct rga_image *src, struct rga_image *dst)
{
struct rga_image test = *src;
int ret;
test.width = src->width;
test.height = src->height;
test.stride = test.width * 4;
test.color_mode = DRM_FORMAT_XRGB8888;
test.fill_color = 0xffffffff;
rga_solid_fill(ctx, &test, 0, 0, test.width, test.height);
ret = rga_exec(ctx);
if (ret)
return ret;
sleep(1);
ret = rga_multiple_transform(ctx, &test, dst, 0, 0, test.width, test.height,
0, 0, dst->width, dst->height, 0, 0, 0);
ret = rga_exec(ctx);
if (ret)
return ret;
return 0;
}
static int rga_test(struct rga_test *test)
{
int ret;
/*
printf("cmdlist test\n");
ret = rga_cmdlist_test(test);
if (ret) {
printf("*[RGA ERROR]*: Failed at cmdlist test\n");
return ret;
}
*/
ret = rga_yuvimg_test(test);
/*
printf("color fill test\n");
ret = rga_color_fill_test(test);
if (ret) {
printf("*[RGA ERROR]*: Failed at color fill test\n");
return ret;
}
ret = rga_context_test(test);
if (ret) {
printf("*[RGA ERROR]*: Failed at context test\n");
return ret;
}
printf("rotate / scale test\n");
ret = rga_rot_scale_test(test);
if (ret) {
printf("*[RGA ERROR]*: Failed at rotate / scale test\n");
return ret;
}
*/
return 0;
}
static int x11_rga_copy_nv12_to_nv12_test(struct cmd_context *cmd_ctx, struct rga_test *test, enum e_rga_buf_type type)
{
struct rockchip_device *dev = test->dev;
struct rockchip_bo *src = test->src_bo;
//struct rockchip_bo *dst = test->dst_bo;
struct connector *src_con = &test->src_con;
struct connector *dst_con = &test->dst_con;
struct rga_image src_img = {0}, dst_img = {0};
unsigned int img_w, img_h;
int dst_fd, src_fd;
//drmPrimeHandleToFD(dev->fd, dst->handle, 0 , &dst_fd);
dst_fd = cmd_ctx->x11_dma_buffers[cmd_ctx->choose_screen % cmd_ctx->nbufs].fd;
drmPrimeHandleToFD(dev->fd, src->handle, 0 , &src_fd);
dst_img.bo[0] = dst_fd;
src_img.bo[0] = src_fd;
img_w = src_con->mode->hdisplay;
img_h = src_con->mode->vdisplay;
src_img.width = img_w;
src_img.height = img_h;
src_img.stride = img_w;
src_img.buf_type = type;
src_img.color_mode = DRM_FORMAT_NV12;
img_w = dst_con->mode->hdisplay;
img_h = dst_con->mode->vdisplay;
dst_img.width = img_w;
dst_img.height = img_h;
dst_img.buf_type = type;
#ifdef DEST_RGB_DISP
dst_img.stride = img_w * 4;
dst_img.color_mode = DRM_FORMAT_ABGR8888;
#else
dst_img.stride = img_w;
dst_img.color_mode = DRM_FORMAT_NV12;
#endif
test->dst_img = dst_img;
test->src_img = src_img;
rga_test(test);
unsigned long count;
cmd_ctx->choose_screen++;
DRI2SwapBuffers(cmd_ctx->display, cmd_ctx->win, 0, 0, 0, &count);
DEMO_DEBUG("DRI2SwapBuffers: count = %lu", count);
getchar();
close(src_fd);
//close(dst_fd);
return 0;
}
static int rga_copy_nv12_to_nv12_test(struct rga_test *test, enum e_rga_buf_type type)
{
struct rockchip_device *dev = test->dev;
struct rockchip_bo *src = test->src_bo;
struct rockchip_bo *dst = test->dst_bo;
struct connector *src_con = &test->src_con;
struct connector *dst_con = &test->dst_con;
struct rga_image src_img = {0}, dst_img = {0};
unsigned int img_w, img_h;
int dst_fd, src_fd;
/*
* RGA API Related:
*
* Due to RGA API only accept the fd of dma_buf, so we need
* to conver the dma_buf Handle to dma_buf FD.
*
* And then just assigned the src/dst framebuffer FD to the
* "struct rga_img".
*
* And for now, RGA driver only support GEM buffer type, so
* we also need to assign the src/dst buffer type to RGA_IMGBUF_GEM.
*
* For futher, I would try to add user point support.
*/
drmPrimeHandleToFD(dev->fd, dst->handle, 0 , &dst_fd);
drmPrimeHandleToFD(dev->fd, src->handle, 0 , &src_fd);
dst_img.bo[0] = dst_fd;
src_img.bo[0] = src_fd;
/*
* RGA API Related:
*
* Configure the source FB width / height / stride / color_mode.
*
* The width / height is correspond to the framebuffer width /height
*
* The stride is equal to (width * pixel_width).
*
* The color_mode should configure to the standard DRM color format
* which defined in "/user/include/drm/drm_fourcc.h"
*
*/
img_w = src_con->mode->hdisplay;
img_h = src_con->mode->vdisplay;
src_img.width = img_w;
src_img.height = img_h;
src_img.stride = img_w;
src_img.buf_type = type;
src_img.color_mode = DRM_FORMAT_NV12;
img_w = dst_con->mode->hdisplay;
img_h = dst_con->mode->vdisplay;
dst_img.width = img_w;
dst_img.height = img_h;
dst_img.buf_type = type;
#ifdef DEST_RGB_DISP
dst_img.stride = img_w * 4;
dst_img.color_mode = DRM_FORMAT_ARGB8888;
#else
dst_img.stride = img_w;
dst_img.color_mode = DRM_FORMAT_NV12;
#endif
/*
* RGA Tested Related:
*
* Start to run test between source FB and dest FB
*/
test->dst_img = dst_img;
test->src_img = src_img;
rga_test(test);
close(src_fd);
close(dst_fd);
return 0;
}
static struct rockchip_bo *init_crtc(struct connector *con,
struct rockchip_device *dev)
{
struct rockchip_bo *bo;
unsigned int screen_width, screen_height;
drmModeRes *resources;
resources = drmModeGetResources(dev->fd);
if (!resources) {
fprintf(stderr, "drmModeGetResources failed: %s\n",
strerror(errno));
return NULL;
}
connector_find_mode(dev->fd, con, resources);
drmModeFreeResources(resources);
if (!con->mode) {
fprintf(stderr, "failed to find usable connector\n");
return NULL;
}
screen_width = con->mode->hdisplay;
screen_height = con->mode->vdisplay;
if (screen_width == 0 || screen_height == 0) {
fprintf(stderr, "failed to find sane resolution on connector\n");
return NULL;
}
printf("screen width = %d, screen height = %d\n", screen_width, screen_height);
bo = rockchip_create_buffer(dev, screen_width * screen_height * 4, 0);
if (!bo) {
return NULL;
}
con->plane_zpos = -1;
return bo;
}
static int rga_nv12_to_nv12_test(struct rga_test *test)
{
struct rockchip_device *dev = test->dev;
struct rockchip_bo *dst_bo = test->dst_bo;
struct connector *dst_con = &test->dst_con;
uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
unsigned int dst_fb_id;
int ret, modes;
/*
* Dest FB Displayed Related:
*
* Add the dest framebuffer to DRM connector, note that for NV12
* display, the virtual stride is (width), that's why pitches[0]
* is hdisplay.
*/
#ifdef DEST_RGB_DISP
modes = DRM_FORMAT_ARGB8888;
pitches[0] = dst_con->mode->hdisplay * 4;
#else
modes = DRM_FORMAT_NV12;
pitches[0] = dst_con->mode->hdisplay;
handles[1] = dst_bo->handle;
pitches[1] = dst_con->mode->hdisplay;
offsets[1] = dst_con->mode->hdisplay * dst_con->mode->vdisplay;
#endif
handles[0] = dst_bo->handle;
offsets[0] = 0;
ret = drmModeAddFB2(dev->fd, dst_con->mode->hdisplay, dst_con->mode->vdisplay,
modes, handles, pitches, offsets, &dst_fb_id, 0);
if (ret < 0)
return -EFAULT;
ret = drm_set_crtc(dev, dst_con, dst_fb_id);
if (ret < 0)
return -EFAULT;
/*
* TEST RGA Related:
*
* Start to configure the RGA module and run test
*/
ret = rga_copy_nv12_to_nv12_test(test, RGA_IMGBUF_GEM);
if (ret < 0) {
fprintf(stderr, "failed to test copy operation.\n");
return -EFAULT;
}
/*
* Display Related:
*
* Released the display framebufffer refer which hold
* by DRM display framework
*/
drmModeRmFB(dev->fd, dst_fb_id);
return 0;
}
int main(int argc, char **argv)
{
struct rockchip_device *dev;
struct connector src_con, dst_con;
struct rga_test test = {0};
int fd;
struct cmd_context cmd_ctx;
mac_arg_fmt = -1;
if( argc > 1) {
sscanf(argv[1],"%X",&mac_arg_fmt);
printf("mac_arg_fmt = %x = %d\n", mac_arg_fmt, mac_arg_fmt);
}
#if 1
init_x11_context(&cmd_ctx);
init_authenticated_fd(&cmd_ctx);
//sleep(1);
get_x11_dma_buffer(&cmd_ctx);
fd = cmd_ctx.authenticated_fd;
dev = rockchip_device_create(fd);
if (!dev) {
drmClose(dev->fd);
return -EFAULT;
}
ctx = cmd_ctx.rga_ctx;
#else
fd = drmOpen(DRM_MODULE_NAME, NULL);
if (fd < 0) {
fprintf(stderr, "failed to open.\n");
return fd;
}
ctx = rga_init(dev->fd);
if (!ctx)
return -EFAULT;
#endif
memset(&src_con, 0, sizeof(struct connector));
src_con.mode = alloca(sizeof(drmModeModeInfo));
src_con.mode->hdisplay = 1920;
src_con.mode->vdisplay = 1088;
test.src_bo = rockchip_create_buffer(dev, src_con.mode->hdisplay * src_con.mode->vdisplay * 4, 0);
if (!test.src_bo) {
fprintf(stderr, "Failed to create source fb!\n");
return -EFAULT;
}
#if 0
dst_con.crtc = -1;
dst_con.id = 31;
strcpy(dst_con.mode_str, "1920x1080");
test.dst_bo = init_crtc(&dst_con, dev);
if (test.dst_bo == NULL) {
printf("init dst crtc failed \n");
return 0;
}
#else
memset(&dst_con, 0, sizeof(struct connector));
dst_con.mode = alloca(sizeof(drmModeModeInfo));
#if 0
dst_con.mode->hdisplay = 1920;
dst_con.mode->vdisplay = 1080;
test.dst_bo = rockchip_create_buffer(dev, dst_con.mode->hdisplay * dst_con.mode->vdisplay * 4, 0);
if (!test.dst_bo) {
fprintf(stderr, "Failed to create source fb!\n");
return -EFAULT;
}
#else
dst_con.mode->hdisplay = cmd_ctx.screen_width;
dst_con.mode->vdisplay = cmd_ctx.screen_height;
#endif
#endif
test.src_con = src_con;
test.dst_con = dst_con;
test.dev = dev;
//rga_nv12_to_nv12_test(&test);
//rga_copy_nv12_to_nv12_test(&test, RGA_IMGBUF_GEM);
x11_rga_copy_nv12_to_nv12_test(&cmd_ctx, &test, RGA_IMGBUF_GEM);
rga_fini(ctx);
rockchip_destroy_buffer(test.src_bo);
rockchip_destroy_buffer(test.dst_bo);
drmClose(dev->fd);
rockchip_device_destroy(dev);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment