This is an automated email from the git hooks/post-receive script. x2go pushed a change to branch master in repository x2gokdrive. from 1edfc23 patches.xorg/21.1.4/xorg-server-configure-ac.patch: fix FTBFS, typo when applying patch. new e1107f4 - automatically decrease the jpeg quality when to many frames in queue. - update the screen with png frames when no data is transmitted. The 1 revisions listed above as "new" are entirely new to this repository and will be described in separate emails. The revisions listed as "adds" were already present in the repository and have only been added to this reference. Summary of changes: debian/changelog | 2 + x2gokdriveremote.c | 184 ++++++++++++++++++++++++++++++++++++++++++++++------- x2gokdriveremote.h | 30 +++++++-- 3 files changed, 186 insertions(+), 30 deletions(-) -- Alioth's /home/x2go-admin/maintenancescripts/git/hooks/post-receive-email on /srv/git/code.x2go.org/x2gokdrive.git
This is an automated email from the git hooks/post-receive script. x2go pushed a commit to branch master in repository x2gokdrive. commit e1107f47d77eab648efae39322483ead4b6023a3 Author: Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> Date: Fri Oct 7 12:51:28 2022 -0500 - automatically decrease the jpeg quality when to many frames in queue. - update the screen with png frames when no data is transmitted. --- debian/changelog | 2 + x2gokdriveremote.c | 184 ++++++++++++++++++++++++++++++++++++++++++++++------- x2gokdriveremote.h | 30 +++++++-- 3 files changed, 186 insertions(+), 30 deletions(-) diff --git a/debian/changelog b/debian/changelog index eeabf70..997128b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -34,6 +34,8 @@ x2gokdrive (0.0.0.1-0x2go1) UNRELEASED; urgency=medium - sending KEYRELEASE immediately after KEYPRESS to avoid the "key sticking". - set initial geometry form the -geometry command line option. - change from alder32 to crc32 to avoid collisions on small frames. + - automatically decrease the jpeg quality when to many frames in queue. + - update the screen with png frames when no data is transmitted. [ Mihai Moldovan ] * Initial release: diff --git a/x2gokdriveremote.c b/x2gokdriveremote.c index 04c47ca..bd1f558 100644 --- a/x2gokdriveremote.c +++ b/x2gokdriveremote.c @@ -1518,7 +1518,7 @@ void remote_send_win_updates(char* updateBuf, uint32_t bufSize) *((uint32_t*)buffer)=WINUPDATE; *((uint32_t*)buffer+1)=bufSize; - write(remoteVars.clientsock,buffer,56); + l=write(remoteVars.clientsock,buffer,56); while(sent<bufSize) { @@ -1682,6 +1682,10 @@ static void *send_frame_thread (void *threadid) { enum SelectionType r; + int dirty_region; + unsigned int ms_to_wait=100; + struct timespec ts; + struct timeval tp; #ifdef EPHYR_WANT_DEBUG debug_sendThreadId=pthread_self(); @@ -1710,12 +1714,45 @@ void *send_frame_thread (void *threadid) } - if(!remoteVars.first_sendqueue_element && !remoteVars.firstCursor && !remoteVars.selstruct.firstOutputChunk && !remoteVars.cache_rebuilt && !remoteVars.windowsUpdated) { - /* sleep if frame queue is empty */ - pthread_cond_wait(&remoteVars.have_sendqueue_cond, &remoteVars.sendqueue_mutex); + gettimeofday(&tp, NULL); + /* Convert from timeval to timespec */ + ts.tv_sec = tp.tv_sec; + ts.tv_nsec = tp.tv_usec * 1000+ms_to_wait*1000000UL;//wait ms_to_wait miliseconds + if(ts.tv_nsec>=1000000000UL) + { + ts.tv_nsec-=1000000000UL; + ++ts.tv_sec; + } + /*sleep with timeout till signal from other thread is sent*/ + switch(pthread_cond_timedwait(&remoteVars.have_sendqueue_cond, &remoteVars.sendqueue_mutex, &ts)) + { + case 0: //have a signal from other thread, continue execution + ms_to_wait=100; //reset timer + break; + case ETIMEDOUT: //timeout is ocured, we have nothing else to do, let's see if we need to update some screen regions + dirty_region=getDirtyScreenRegion(); + if(dirty_region!=-1) + { + send_dirty_region(dirty_region); + ms_to_wait=1; //we can start to repaint faster till we don't have any new data incoming + } + else + { + /* sleep till we have a signal from another thread if + *frame, cursor ,selection queue is empty and all regions are updated*/ + ms_to_wait=100; //reset timer + pthread_cond_wait(&remoteVars.have_sendqueue_cond, &remoteVars.sendqueue_mutex); + } + break; + default: + EPHYR_DBG("Error is occured in pthread_cond_timedwait"); + ms_to_wait=100; //reset timer + break; + } + } /* mutex is locked on this point */ @@ -1817,7 +1854,17 @@ void *send_frame_thread (void *threadid) { remoteVars.maxfr=elems; } - // EPHYR_DBG("have %d max frames in queue, current %d", remoteVars.,elems); +// EPHYR_DBG(" frames in queue %d, quality %d", elems, remoteVars.jpegQuality); + if(elems > 3) + { + if(remoteVars.jpegQuality >10) + remoteVars.jpegQuality-=10; + } + if(elems <3) + { + if(remoteVars.jpegQuality <remoteVars.initialJpegQuality) + remoteVars.jpegQuality+=10; + } frame=remoteVars.first_sendqueue_element->frame; /* delete first element from frame queue */ @@ -1845,18 +1892,17 @@ void *send_frame_thread (void *threadid) /* unlock sendqueue for main thread */ + markDirtyRegions(x, y, frame_width, frame_height, remoteVars.jpegQuality, winId); pthread_mutex_unlock(&remoteVars.sendqueue_mutex); send_frame(frame_width, frame_height, x, y, crc, frame->regions, winId); } else { // EPHYR_DBG("Sending main image or screen update"); - + markDirtyRegions(x, y, width, height, remoteVars.jpegQuality, winId); pthread_mutex_unlock(&remoteVars.sendqueue_mutex); sendMainImageFromSendThread(width, height, x, y, winId); } - - pthread_mutex_lock(&remoteVars.sendqueue_mutex); if(frame) { @@ -1877,30 +1923,23 @@ void *send_frame_thread (void *threadid) frame->regions[i].rect.size.width=0; } } - if(remoteVars.cache_size>CACHEMAXELEMENTS) { clear_frame_cache(CACHEMAXELEMENTS); } - if(remoteVars.first_deleted_elements) { send_deleted_elements(); } - if(remoteVars.first_deleted_cursor) { send_deleted_cursors(); } - - pthread_mutex_unlock(&remoteVars.sendqueue_mutex); remoteVars.framenum++; } else { - - pthread_mutex_unlock(&remoteVars.sendqueue_mutex); } } @@ -3146,6 +3185,8 @@ void terminateServer(int exitStatus) { free(remoteVars.main_img); free(remoteVars.second_buffer); + EPHYR_DBG("free screen regions"); + free(remoteVars.screen_regions); } @@ -3188,7 +3229,14 @@ void processConfigFileSetting(char* key, char* value) remoteVars.compression=JPEG; EPHYR_DBG("Using JPEG Compression"); } - remoteVars.jpegQuality=(quality-'0')*10+9; + remoteVars.initialJpegQuality=(quality-'0')*10+9; + if(remoteVars.initialJpegQuality > JPG_QUALITY) + { + //x2goclient can set by default quality 90, but it doesn't really makes sence, Maybe we could think about overreiding it in the future + EPHYR_DBG("JPEG quality %d is requested, x2gokdrive will override it to %d",remoteVars.initialJpegQuality, JPG_QUALITY); + remoteVars.initialJpegQuality=JPG_QUALITY; + } + remoteVars.jpegQuality=remoteVars.initialJpegQuality; EPHYR_DBG("Image quality: %d", remoteVars.jpegQuality); } } @@ -3283,18 +3331,17 @@ void readOptionsFromFile(void) int remote_init(void) { - - EPHYR_DBG("Setting initial arguments"); char* displayVar = NULL; /*init it in OsInit*/ + EPHYR_DBG("Setting initial arguments"); fclose(stdout); fclose(stdin); remoteVars.serversock=-1; - remoteVars.jpegQuality=JPG_QUALITY; + remoteVars.initialJpegQuality=remoteVars.jpegQuality=JPG_QUALITY; remoteVars.compression=DEFAULT_COMPRESSION; remoteVars.selstruct.selectionMode = CLIP_BOTH; if(!strlen(remote_get_init_geometry())) @@ -4531,12 +4578,12 @@ uint32_t calculate_crc(uint32_t width, uint32_t height, int32_t dx, int32_t dy) return crc; } -const char* remote_get_init_geometry() +const char* remote_get_init_geometry(void) { return remoteVars.initGeometry; } -void remote_set_init_geometry(char* geometry) +void remote_set_init_geometry ( const char* geometry ) { if(strlen(geometry)>128) { @@ -4598,6 +4645,7 @@ remote_screen_init(KdScreenInfo *screen, if(remoteVars.main_img) { free(remoteVars.main_img); + free(remoteVars.screen_regions); EPHYR_DBG("FREE DBF"); free(remoteVars.second_buffer); @@ -4608,8 +4656,15 @@ remote_screen_init(KdScreenInfo *screen, EPHYR_DBG("TRYING TO ALLOC DOUBLE BUF %d", width*height*XSERVERBPP); remoteVars.second_buffer=malloc(width*height*XSERVERBPP); - memset(remoteVars.main_img,0, width*height*XSERVERBPP); - memset(remoteVars.second_buffer,0, width*height*XSERVERBPP); + remoteVars.reg_horiz=width/SCREEN_REG_WIDTH; + if(width%SCREEN_REG_WIDTH) + ++remoteVars.reg_horiz; + remoteVars.reg_vert=height/SCREEN_REG_HEIGHT; + if(height%SCREEN_REG_HEIGHT) + ++remoteVars.reg_vert; + EPHYR_DBG("Initializing %dx%d screen regions", remoteVars.reg_horiz, remoteVars.reg_vert); + remoteVars.screen_regions=malloc(remoteVars.reg_horiz*remoteVars.reg_vert*sizeof(screen_region)); + EPHYR_DBG("ALL INITIALIZED"); if(!remoteVars.main_img) @@ -4623,6 +4678,16 @@ remote_screen_init(KdScreenInfo *screen, exit(-1); } + if(!remoteVars.second_buffer) + { + EPHYR_DBG("failed to init screen regions"); + exit(-1); + } + + memset(remoteVars.screen_regions, 0, remoteVars.reg_horiz*remoteVars.reg_vert*sizeof(screen_region)); + memset(remoteVars.main_img,0, width*height*XSERVERBPP); + memset(remoteVars.second_buffer,0, width*height*XSERVERBPP); + remoteVars.main_img_width=width; remoteVars.main_img_height=height; @@ -4655,3 +4720,76 @@ void rebuild_caches(void) pthread_cond_signal(&remoteVars.have_sendqueue_cond); pthread_mutex_unlock(&remoteVars.sendqueue_mutex); } + +void markDirtyRegions(uint32_t x, uint32_t y, uint32_t width, uint32_t height, uint8_t jpegQuality, uint32_t winId) +{ + int first_horiz, last_horiz; + int first_vert, last_vert; + int i,j; +// #warning for debugging +// int marked=0; + first_horiz=x/SCREEN_REG_WIDTH; + first_vert=y/SCREEN_REG_HEIGHT; + last_horiz=(x+width)/SCREEN_REG_WIDTH-1; + last_vert=(y+height)/SCREEN_REG_HEIGHT-1; + if((x+width)%SCREEN_REG_WIDTH) + ++last_horiz; + if((y+height)%SCREEN_REG_HEIGHT) + ++last_vert; +// EPHYR_DBG("marking regions at %d,%d for %dx%d, first %dx%d, last %dx%d", x,y,width, height, first_horiz, first_vert, last_horiz, last_vert); + for(i=first_vert;i<=last_vert;++i) + for(j=first_horiz;j<=last_horiz;++j) + { +// ++marked; + if((remoteVars.screen_regions[i*remoteVars.reg_horiz+j].quality == 0)||(remoteVars.screen_regions[i*remoteVars.reg_horiz+j].quality>jpegQuality)) + remoteVars.screen_regions[i*remoteVars.reg_horiz+j].quality=jpegQuality; + remoteVars.screen_regions[i*remoteVars.reg_horiz+j].winId=winId; + } +// EPHYR_DBG("Marked %d regions",marked); +} + +int getDirtyScreenRegion(void) +{ + int i; + int worst_reg=-1; + for(i=0;i<remoteVars.reg_horiz*remoteVars.reg_vert;++i) + { + if(remoteVars.screen_regions[i].quality) + { + if((worst_reg == -1)||(remoteVars.screen_regions[worst_reg].quality>remoteVars.screen_regions[i].quality)) + { + worst_reg=i; + } + } + } + return worst_reg; +} + +void send_dirty_region(int index) +{ + //remoteVars.sendqueue_mutex is locked + int width, height, x, y, winId; + unsigned char compression; + if(index==-1) + return; + x=(index%remoteVars.reg_horiz)*SCREEN_REG_WIDTH; + y=(index/remoteVars.reg_horiz)*SCREEN_REG_HEIGHT; + if(x+SCREEN_REG_WIDTH > remoteVars.main_img_width) + width=remoteVars.main_img_width-x; + else + width=SCREEN_REG_WIDTH; + if(y+SCREEN_REG_HEIGHT > remoteVars.main_img_height) + height=remoteVars.main_img_height-y; + else + height=SCREEN_REG_HEIGHT; + + winId=remoteVars.screen_regions[index].winId; + remoteVars.screen_regions[index].quality=0; + pthread_mutex_unlock(&remoteVars.sendqueue_mutex); +// EPHYR_DBG("SEND REGION UPDATE %d,%d %dx%d", x,y,width,height); + compression=remoteVars.compression; + remoteVars.compression=PNG; + sendMainImageFromSendThread(width, height, x, y, winId); + remoteVars.compression=compression; + pthread_mutex_lock(&remoteVars.sendqueue_mutex); +} diff --git a/x2gokdriveremote.h b/x2gokdriveremote.h index c10e86c..a5d4580 100644 --- a/x2gokdriveremote.h +++ b/x2gokdriveremote.h @@ -116,9 +116,7 @@ //it define how close should be two pages to search common regions (see find_best_match) #define MAX_MATCH_VAL 51 -#define JPG_QUALITY 80 - - +#define JPG_QUALITY 70 //always 4 #define XSERVERBPP 4 @@ -171,6 +169,18 @@ enum WinState{WIN_UNCHANGED, WIN_DELETED, WIN_ICONIFIED}; #define EVLENGTH 41 +//width of screen region +#define SCREEN_REG_WIDTH 40 + +//height of screen region +#define SCREEN_REG_HEIGHT 40 + +//represents the screen regions for updates +typedef struct +{ + uint8_t quality; + uint32_t winId; +} screen_region; typedef struct { @@ -395,7 +405,7 @@ struct _remoteHostVars char displayName[256]; char initGeometry[128]; int listenPort; - int jpegQuality; + int jpegQuality, initialJpegQuality; uint32_t framenum; uint32_t framenum_sent; uint32_t eventnum; @@ -428,6 +438,10 @@ struct _remoteHostVars int clientsock, serversock; BOOL rootless; + //array of screen regions + screen_region* screen_regions; + int reg_horiz, reg_vert; + struct cache_elem* first_cache_element; struct cache_elem* last_cache_element; @@ -556,8 +570,8 @@ remote_paint_rect(KdScreenInfo *screen, void request_selection_from_client(enum SelectionType selection); void rebuild_caches(void); void remote_set_rootless(void); -void remote_set_init_geometry(char* geometry); -const char* remote_get_init_geometry(); +void remote_set_init_geometry(const char* geometry); +const char* remote_get_init_geometry(void); void remote_check_windowstree(WindowPtr root); void remote_check_window(WindowPtr win); struct remoteWindow* remote_find_window(WindowPtr win); @@ -569,5 +583,7 @@ void client_win_change(char* buff); void client_win_close(uint32_t winId); void client_win_iconify(uint32_t winId); void remote_check_rootless_windows_for_updates(KdScreenInfo *screen); - +void markDirtyRegions(uint32_t x, uint32_t y, uint32_t width, uint32_t height, uint8_t jpegQuality, uint32_t winId); +int getDirtyScreenRegion(void); +void send_dirty_region(int index); #endif /* X2GOKDRIVE_REMOTE_H */ -- Alioth's /home/x2go-admin/maintenancescripts/git/hooks/post-receive-email on /srv/git/code.x2go.org/x2gokdrive.git