GUI: Added a new Display tab that only updates when the cpu finished producing a new frame and made massive performance improvements with the help of the new profiler

This commit is contained in:
(Tim) Efthimis Kritikos 2024-02-26 22:11:30 +00:00
parent 201ac2d401
commit 316d4952fa
2 changed files with 125 additions and 48 deletions

View File

@ -52,6 +52,7 @@ callgrind.out:first ${MAIN_ROM}
${QUIET_VALGRIND}
${Q}if ldd first |grep asan > /dev/null;\
then\
rm -f "$@";\
echo ERROR: Binary build with libasan, please rebuild without address sanitiser;\
else\
valgrind --tool=callgrind --dump-instr=yes --simulate-cache=yes --collect-jumps=yes --callgrind-out-file=callgrind.out ./first -i programs/3d_renderer.rom;\

172
gui.c
View File

@ -49,6 +49,8 @@ WINDOW *pipeline_disas;
WINDOW *debug_simdata;
WINDOW *display_terminal_output;
int monochrome;
int get_terminal_size(){
@ -61,7 +63,7 @@ int get_terminal_size(){
}
char *tab_name[]={"Overview","Memory","Pipeline","Debug"};
char *tab_name[]={"Overview","Memory","Pipeline","Debug","Display"};
unsigned int CURRENT_TAB=1;
@ -92,12 +94,16 @@ int gui_ncurses_refresh(){
}else if(CURRENT_TAB==4){
if(wrefresh(debug_simdata)==ERR)
return 1;
}else if(CURRENT_TAB==5){
if(wrefresh(display_terminal_output)==ERR)
return 1;
}
return 0;
}
enum GUI_CPU_STATE_t GUI_CPU_STATE=GUI_CPU_SINGLE_STEPPING;
void update_tabs(){
wattron(tabs,A_BOLD);
wattron(tabs,COLOR_PAIR(2));
@ -225,6 +231,8 @@ int start_gui(){
pipeline_pipeline=newwin(terminal_height-1-border*2,terminal_width-border*3-GENERAL_DISAS_WIDTH,1+border,border);
pipeline_disas=newwin(terminal_height-1-border*2,GENERAL_DISAS_WIDTH,1+border,border+terminal_width-border*3-GENERAL_DISAS_WIDTH);
display_terminal_output=newwin(terminal_height-1,terminal_width,1,0);
gui_settings=malloc(sizeof(struct gui_settings_t));
gui_settings->cycles_per_frame=100;
@ -604,7 +612,7 @@ L'⢀',L'⢁',L'⢂',L'⢃',L'⢄',L'⢅',L'⢆',L'⢇',L'⢈',L'⢉',L'⢊',L'
L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',L'',
};
int print_braille_frame_buffer(WINDOW* win,uint8_t *buffer,int width,int height){
int print_braille_frame_buffer(WINDOW* win,uint8_t *buffer,int width,int height,int fullscreen){
for(int h=0;h<height/4;h++){
for(int w=0;w<width/2;w++){
uint8_t select=0;
@ -624,7 +632,10 @@ int print_braille_frame_buffer(WINDOW* win,uint8_t *buffer,int width,int height)
select|=0x20;
if(buffer[w*2+1 +width*(h*4+3 )])
select|=0x80;
mvwprintw(win,h+1,w+1,"%lc",braille_lookup[select]);
if(fullscreen)
mvwprintw(win,h,w,"%lc",braille_lookup[select]);
else
mvwprintw(win,h+1,w+1,"%lc",braille_lookup[select]);
}
}
return 0;
@ -648,24 +659,31 @@ void braille_frame_buffer_line(uint8_t *buffer,int buffer_width,int buffer_heigh
}
}
int update_general_terminal_output(struct simdata_t *simdata){
int update_terminal_output(WINDOW *win, struct simdata_t *simdata,uint8_t fullscreen){
int width,height;
werase(general_terminal_output);
getmaxyx(general_terminal_output,height,width);
werase(win);
getmaxyx(win,height,width);
term_curs_x=0;
term_curs_y=0;
uint8_t* vector_working_frame_buffer=malloc((height*4)*(width*2));
uint8_t* vector_display_frame_buffer=malloc((height*4)*(width*2));
memset(vector_working_frame_buffer,0,(height*4)*(width*2));
memset(vector_display_frame_buffer,0,(height*4)*(width*2));
int vector=0;
int vstate=0;
int vfb_width=(width-2)*2;
int vfb_height=(height-2)*4;
int vfb_width, vfb_height;
if(fullscreen){
vfb_width=(width)*2;
vfb_height=(height)*4;
}else{
vfb_width=(width-2)*2;
vfb_height=(height-2)*4;
}
uint8_t* vector_working_frame_buffer=malloc(vfb_height*vfb_width);
uint8_t* vector_display_frame_buffer=malloc(vfb_height*vfb_width);
memset(vector_working_frame_buffer,0,vfb_height*vfb_width);
memset(vector_display_frame_buffer,0,vfb_height*vfb_width);
float x0,y0,x1,y1;
for(uint64_t i=0;i < simdata->terminal_output_size/4;i++){
uint32_t c=simdata->terminal_output[i];
@ -675,9 +693,9 @@ int update_general_terminal_output(struct simdata_t *simdata){
if(c==0x00000001)
vector=0;
else if(c==0x00000002)
memset(vector_working_frame_buffer,0,(height*4)*(width*2));
memset(vector_working_frame_buffer,0,vfb_height*vfb_width);
else if(c==0x00000003)
memcpy(vector_display_frame_buffer,vector_working_frame_buffer,(height*4)*(width*2));
memcpy(vector_display_frame_buffer,vector_working_frame_buffer,vfb_height*vfb_width);
else
vstate++;
break;
@ -709,17 +727,17 @@ int update_general_terminal_output(struct simdata_t *simdata){
}
}else{
if(c>=' '&&c<='~'){
mvwprintw(general_terminal_output,term_curs_y+1,term_curs_x+1,"%c",c);
mvwprintw(win,term_curs_y+1,term_curs_x+1,"%c",c);
term_curs_x++;
if(term_curs_x>=width-2){
if(term_curs_x>=width){
term_curs_x=0;
term_curs_y++;
}
if(term_curs_y>=height-2){
wscrl(general_terminal_output,1);
if(term_curs_y>=height){
wscrl(win,1);
term_curs_y--;
for(int i=0;i<width;i++){
mvwprintw(general_terminal_output,term_curs_y+1,i," ");
mvwprintw(win,term_curs_y+1,i," ");
}
}
}else{
@ -730,37 +748,49 @@ int update_general_terminal_output(struct simdata_t *simdata){
case 0x0a:
term_curs_x=0;
term_curs_y++;
if(term_curs_y>=height-2){
wscrl(general_terminal_output,1);
if(term_curs_y>=vfb_height){
wscrl(win,1);
term_curs_y--;
box(general_terminal_output, 0 , 0);
mvwprintw(general_terminal_output,0,width/2-7,"[ TERM OUTPUT ]");
box(win, 0 , 0);
mvwprintw(win,0,width/2-7,"[ TERM OUTPUT ]");
}
break;
default:
werase(general_terminal_output);
box(general_terminal_output, 0 , 0);
mvwprintw(general_terminal_output,0,width/2-7,"[ TERM OUTPUT ]");
mvwprintw(general_terminal_output,1,1,"Invalid output");
werase(win);
box(win, 0 , 0);
mvwprintw(win,0,width/2-7,"[ TERM OUTPUT ]");
mvwprintw(win,1,1,"Invalid output");
return 0;
}
}
}
}
box(general_terminal_output, 0 , 0);
if(!vector){
mvwchgat(general_terminal_output,term_curs_y+1,term_curs_x+1, 1, A_REVERSE, 0, NULL);
mvwprintw(general_terminal_output,0,width/2-7,"[ TERM OUTPUT ]");
}else{
print_braille_frame_buffer(general_terminal_output,vector_display_frame_buffer,(width-2)*2,(height-2)*4);
mvwprintw(general_terminal_output,0,width/2-9,"[ VECTOR DISPLAY ]");
}
if(!fullscreen){
box(win, 0 , 0);
if(!vector){
mvwchgat(win,term_curs_y+1,term_curs_x+1, 1, A_REVERSE, 0, NULL);
mvwprintw(win,0,width/2-7,"[ TERM OUTPUT ]");
}else{
print_braille_frame_buffer(win,vector_display_frame_buffer,vfb_width,vfb_height,0);
mvwprintw(win,0,width/2-9,"[ VECTOR DISPLAY ]");
}
}else
if(vector)
print_braille_frame_buffer(win,vector_display_frame_buffer,vfb_width,vfb_height,1);
free(vector_working_frame_buffer);
free(vector_display_frame_buffer);
return 0;
}
int update_general_terminal_output(WINDOW *win, struct simdata_t *simdata){
return update_terminal_output(win,simdata,0);
}
int update_display_terminal_output(WINDOW *win, struct simdata_t *simdata){
return update_terminal_output(win,simdata,1);
}
int update_debug_simdata(struct simdata_t *simdata){
int width,height;
werase(debug_simdata);
@ -856,18 +886,34 @@ int update_pipeline(WINDOW *win,struct simdata_t *simdata){
return 0;
}
int force_disp_terminal_output_update(struct simdata_t *simdata){
if(update_display_terminal_output(display_terminal_output,simdata))
return 1;
if(gui_ncurses_refresh())
return 1;
if(simdata)
return 0;
else return 0;
}
int clear_back_window=1;
int write_tabs=1;
int update_gui(struct simdata_t *simdata){
if(simdata->cpu_state==CPU_HALTED)
if(simdata->cpu_state==CPU_HALTED){
GUI_CPU_STATE=GUI_CPU_STOPPED;
if(CURRENT_TAB==5)
force_disp_terminal_output_update(simdata);
}
if(clear_back_window){
clear();
clear_back_window=0;
}
if((simdata->current_clock)%(gui_settings->cycles_per_frame)==0 || GUI_CPU_STATE!=GUI_CPU_RUNNING ){
if(write_tabs){
update_tabs();
write_tabs=0;
}
if((simdata->current_clock)%(gui_settings->cycles_per_frame)==0 || GUI_CPU_STATE!=GUI_CPU_RUNNING ){
if(CURRENT_TAB==1){
if(update_general_memdump(simdata))
return 1;
@ -877,7 +923,7 @@ int update_gui(struct simdata_t *simdata){
return 1;
if(update_general_registers(simdata))
return 1;
if(update_general_terminal_output(simdata))
if(update_general_terminal_output(general_terminal_output,simdata))
return 1;
}else if(CURRENT_TAB==2){
if(update_memory_memdump(simdata))
@ -890,10 +936,15 @@ int update_gui(struct simdata_t *simdata){
}else if(CURRENT_TAB==4){
if(update_debug_simdata(simdata))
return 1;
}else if(CURRENT_TAB==5){
if(GUI_CPU_STATE!=GUI_CPU_RUNNING)
force_disp_terminal_output_update(simdata);
}
if(CURRENT_TAB!=5)
if(gui_ncurses_refresh())
return 1;
}
if(gui_ncurses_refresh())
return 1;
return 0;
}
@ -901,18 +952,23 @@ int gui_continue_request(struct simdata_t *simdata){
int inch;
int release=0;
while(release==0){
if(((inch=getch())==ERR)){
if(GUI_CPU_STATE==GUI_CPU_SINGLE_STEPPING)
return 1;
else
release=1;
}
inch=ERR;
if(((simdata->current_clock)%(gui_settings->cycles_per_frame))==0 || GUI_CPU_STATE!=GUI_CPU_RUNNING ){
if(((inch=getch())==ERR)){
if(GUI_CPU_STATE==GUI_CPU_SINGLE_STEPPING)
return 1;
else
release=1;
}
}else
release=1;
switch(inch){
case 'r':
if(simdata->cpu_state!=CPU_HALTED){
if(GUI_CPU_STATE==GUI_CPU_RUNNING){
GUI_CPU_STATE=GUI_CPU_SINGLE_STEPPING;
update_gui(simdata);
if(CURRENT_TAB!=5)
update_gui(simdata);
nodelay(stdscr, FALSE);
}else{
GUI_CPU_STATE=GUI_CPU_RUNNING;
@ -929,6 +985,7 @@ int gui_continue_request(struct simdata_t *simdata){
if(CURRENT_TAB!=1){
CURRENT_TAB=1;
clear();
update_tabs();
update_gui(simdata);
}
break;
@ -936,6 +993,7 @@ int gui_continue_request(struct simdata_t *simdata){
if(CURRENT_TAB!=2){
CURRENT_TAB=2;
clear();
update_tabs();
update_gui(simdata);
}
break;
@ -943,6 +1001,7 @@ int gui_continue_request(struct simdata_t *simdata){
if(CURRENT_TAB!=3){
CURRENT_TAB=3;
clear();
update_tabs();
update_gui(simdata);
}
break;
@ -950,9 +1009,18 @@ int gui_continue_request(struct simdata_t *simdata){
if(CURRENT_TAB!=4){
CURRENT_TAB=4;
clear();
update_tabs();
update_gui(simdata);
}
break;
case '5':
if(CURRENT_TAB!=5){
CURRENT_TAB=5;
clear();
update_tabs();
force_disp_terminal_output_update(simdata);
}
break;
case 'j':
if(CURRENT_TAB==2){
memory_window_address++;
@ -976,6 +1044,7 @@ int gui_continue_request(struct simdata_t *simdata){
return 0;
}
uint32_t highest_disps=0;//XXX: remember that if we create a clear screen command it should zero this out too
int clean_cpu_output(struct simdata_t *simdata){
uint32_t last_vect_disp=0;
uint32_t second_last_vect_disp=simdata->terminal_output_size/4;//TODO: I shouldn't have to initialise this. GCC gives a warning erroneously
@ -1015,12 +1084,19 @@ int clean_cpu_output(struct simdata_t *simdata){
}
}
}
if(highest_disps<disps_found){
highest_disps=disps_found;
if(CURRENT_TAB==5)
force_disp_terminal_output_update(simdata);
}
if(disps_found>=2){
int final_data_size=simdata->terminal_output_size-(second_last_vect_disp+4);
memmove((uint8_t*)simdata->terminal_output+4,(uint8_t*)simdata->terminal_output+simdata->terminal_output_size-final_data_size,final_data_size);
simdata->terminal_output[0]=0xFFFFFFFF;
simdata->terminal_output=realloc(simdata->terminal_output,final_data_size+4);
simdata->terminal_output_size=final_data_size+4;
if(CURRENT_TAB==5)
force_disp_terminal_output_update(simdata);
}
return 0;
}