X server

Z HPM wiki
Přejít na: navigace, hledání

X server slouží ke grafické interakci s uživatelem - stará se o obrazovku, klávesnici a myš. Výpočet může probíhat i na jiném počítači, který je s X serverem spojen sítí. Z jednoho X serveru tak uživatel může ovládat celou řadu počítačů.

Komunikace probíhá takzvaným X protokolem a k usnadnění programování této komunikace slouží na nejnižší úrovni knihovna Xlib, která umožňuje například napsat text, vykreslit čáru či obdélník nebo přenést obdélníkový kus barevného obrazu do X serveru, nebo i zpět z X serveru.

Abyste mohli přeložit jednoduchý program používající X server, potřebujete nainstalovat balíček libx11-dev:

sudo apt-get update; sudo apt-get -y install libx11-dev

Prostý program pro přenos obdélníkové části obrazu pak může obsahovat:

#include <X11/Xlib.h>

...
  XGetImage(...);
...


#include <stdlib.h>
#include <stdio.h>

#include <X11/Xlib.h>

Display		*dpy;
Window		wind,rootwind;
GC    gc;
XImage *xip;
Drawable d, d_in;
unsigned long plane_mask = -1;
XGCValues xgcvalues;
int screen;
Window rootwind;
unsigned long White,Black;
XEvent ev;

main(int argc, char**argv){
  d_in = strtol( argv[1]+2, NULL, 16 );

  if ( !(dpy = XOpenDisplay(":0") )){
    fprintf(stderr,"Cannot open display\n");
    exit(-1);
  }
  fprintf(stderr,"Display connected OK\n");
  fprintf(stderr,"Copying window 0x%x\n", d_in);

  screen	= DefaultScreen(dpy);
  rootwind	= RootWindow(dpy,screen);
  White		= WhitePixel(dpy,screen);
  Black		= BlackPixel(dpy,screen);

  gc = XCreateGC(dpy, rootwind, 0, &xgcvalues); /* mask=0, use nothing from xgcvalues */
  XSetFunction( dpy, gc, GXcopy );

  XSetForeground( dpy, gc, Black );

  d = XCreateSimpleWindow(dpy,rootwind,5 /*x*/,20 /*y*/,400,200,10 /*?*/,Black,White);
  XMapWindow(dpy,d);

  XSelectInput(dpy,d,ExposureMask|ButtonPressMask|ButtonReleaseMask|StructureNotifyMask|
	       SubstructureNotifyMask);

  XNextEvent(dpy,&ev);
  while (ev.type != MapNotify) XNextEvent(dpy,&ev);

  XDrawLine(dpy,d,gc,10,20,40,60);

  while (1){
    fprintf(stderr,".");
    fflush(stderr);
    XNextEvent(dpy,&ev);

    xip = XGetImage(dpy, d_in, 0, 0, 400, 200, plane_mask, ZPixmap);

    // CHANGE IMAGE HERE

    XPutImage(dpy, d, gc, xip, 0, 0, 20, 20, 400, 200);
  }
  exit(0);
}

Obsah

Kompilace

gcc -O3 pokus.c -lX11 -o pokus

Spusteni

xwininfo
./pokus  0x1c0003c

Modifikace dat

    ...
    int c;
    ...


    // CHANGE IMAGE HERE
    for( c=0; c < 10000; c++ ){
      (xip->data)[c]=78;
    }

Modry pruh:

    // CHANGE IMAGE HERE
    for( c=0; c < 70000; c+=4 ){
      (xip->data)[c]=255; //blue
      (xip->data)[c+1]=0; //green
      (xip->data)[c+2]=0; //red
      (xip->data)[c+3]=0; //nic?
    }

Zmena barevneho obrazu na cernobily:

    // CHANGE IMAGE HERE
    for( c=0; c < 70000; c+=4 ){
      unsigned char r, g, b;
      b = (xip->data)[c];
      g = (xip->data)[c+1];
      r = (xip->data)[c+2];
      r=g=b=(r+g+b)/3;
      (xip->data)[c] = b;
      (xip->data)[c+1] = g;
      (xip->data)[c+2] = r;
      (xip->data)[c+3] = 0;
    }

Modifikace dat pomocí SSE

K modifikaci můžeme použít SSE operace s 16 byty.

Překlad:

gcc -O3 pokus.c -msse3 -lX11 -o pokus

Fragment programu:

...
#include <pmmintrin.h>    /* Intel(R) Pentium4 processor SSE3 intrinsics */
...

    // CHANGE IMAGE HERE
    {
      unsigned char k[16] = {200,0,0,0, 200,0,0,0, 200,0,0,0, 200,0,0,0};
      __m128i a, b, v;
      int c;
      a = *(__m128i *)k;

      for( c=8; c < 200000; c+=16 ){
	__m128i *p = (xip->data)+c;
	b = *p;
	v = _mm_adds_epu8(a, b); //PADDUSB usat(a + b)
	*p = v;
      }
    }

Pointer p musí být násobek 16, jinak nastane při zápisu problém. Ve výše uvedeném fragmentu je použit empiricky zjištěný vhodný start c=8, ale nelze na to spoléhat. Jistější by bylo zarovnat pointer p na nejbližší vyšší násobek 16:

      printf("p=%x\n", (unsigned int)p);
      p = (__m128i *) (((unsigned int)p | 15) + 1); // align to multiple of 16
      printf("p=%x\n", (unsigned int)p);

Od této počáteční hodnoty se už můžeme pohybovat pointerovou aritmetikou pomocí p++, které po použití zvětší pointer o velikost __m128i, tedy o 16:

      for( c=0; c < 200000; c+=16 ){
 	b = *p;
	v = _mm_adds_epu8(a, b);
	*(p++) = v;
      }

Úplně přímý přístup k obrazu v RAM

Opravdu hodně dobrodružná alternativa k XGetImage() a XPutImage() je použití mmap().

Osobní nástroje
Jmenné prostory
Varianty
Akce
Navigace
Nástroje