//author Sylvain Bertrand <digital.ragnarok@gmail.com>
//Protected by GNU Affero GPL v3 with some exceptions.
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <string.h>
#include <math.h>
#include <stdint.h>
#include <stdlib.h>
#include <error.h>
//#include <linux/types.h>
#include <alga/pixel_fmts.h>
#include <alga/amd/dce6/dce6.h>
#include <alga/amd/si/ioctl.h>
#define e(m,...) error(0,0,m,##__VA_ARGS__)
#define o(m,...) printf(m "\n",##__VA_ARGS__)
#define unsignedl unsigned long
#define unsignedll unsigned long long
static void mode(char *str, uint16_t *h, uint16_t *v, uint8_t *r)
{
*h=0;
*v=0;
*r=0;
char *c=str;
//hhhhx
while(1){
if(*c=='\0') return;
if(*c=='x') break;
++c;
}
*c='\0';
*h=(uint16_t)strtoul(str,NULL,10);
*c='x';
++c;
str=c;
//vvvv@
while(1){
if(*c=='\0') return;
if(*c=='@') break;
++c;
}
*c='\0';
*v=(uint16_t)strtoul(str,NULL,10);
*c='@';
++c;
//rrr\0
*r=(uint8_t)strtoul(c,NULL,10);
}
uint8_t alga_pixel_fmt(char *str)
{
uint8_t fmt=1;
while(1){
if(fmt==ALGA_PIXEL_FMTS_N) return 0;
if(!strncmp(str,alga_pixel_fmts_str[fmt],sizeof("ARGB2101010")))
return fmt;
++fmt;
}
}
int main(int argc, char *argv[])
{
if(argc<4){
e("missing arguments:idx(0->5) mode(1920x1080@60) pixel_fmt(ARGB8888)");
goto err;
}
int f=open("/dev/si0", O_RDWR);
if(f==-1){
e("open failed");
goto err;
}
//XXX:why did I do that?
long p_sz=sysconf(_SC_PAGESIZE);
if(p_sz==-1){
e("get page size failed");
goto err;
}
uint16_t h;
uint16_t v;
uint8_t r;
mode(argv[2],&h,&v,&r);
o("from '%s' horizontal=%u pixels, vertical=%u pixels, refresh rate=%u Hz",
argv[2],h,v,r);
uint8_t pixel_fmt=alga_pixel_fmt(argv[3]);
struct si_mem mem;
//Why did I do that? Anyway, for the GPU color blocks the frame buffer must
//be aligned on 256 bytes boundary.
mem.align=p_sz;
uint64_t sz=2*(h*v*alga_pixel_fmts_sz[pixel_fmt]);
mem.sz=sz;
o("db_fb alloc sz=%016llx",(unsignedll)mem.sz);
unsignedl req=_IOWR('d',SI_MEM_ALLOC,mem);
r=ioctl(f,req,&mem);
if(r==-1){
e("alloc db_fb failed");
goto err;
}
o("front_fb=0x%016llx back_fb=0x%016llx",(unsignedll)mem.gpu_addr,
(unsignedll)mem.gpu_addr+sz/2);
struct si_dce_dp_set dp_set;
memset(&dp_set,0,sizeof(dp_set));
dp_set.idx=strtoul(argv[1],NULL,10);
dp_set.primary=mem.gpu_addr;
dp_set.secondary=mem.gpu_addr+sz/2;
strncpy(&dp_set.mode[0],argv[2],sizeof(dp_set.mode));
strncpy(&dp_set.pixel_fmt[0],argv[3],sizeof(dp_set.pixel_fmt));
req=_IOR('d',SI_DCE_DP_SET,dp_set);
r=ioctl(f,req,&dp_set);
if(r==-1){
e("dp set failed");
goto err_free_fb;
}
return 0;
err_free_fb:
req=_IOW('d',SI_MEM_FREE,mem.gpu_addr);
r=ioctl(f,req,&mem.gpu_addr);
if(r==-1) e("free vram fb failed (LEAK!)");
err:
return EXIT_FAILURE;
}