Last active
September 15, 2023 10:31
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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