c linux framebuffer

c - Pinte los píxeles a la pantalla a través de Linux FrameBuffer



(6)

Cuando utilicé este programa para escribir a pantalla completa, se bloqueó porque el cálculo del tamaño de la pantalla es incorrecto.

// Figure out the size of the screen in bytes screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;

Esto se supone que es:

/* Calculate the size of the screen in bytes */ screensize = vinfo.xres_virtual * vinfo.yres_virtual * (vinfo.bits_per_pixel / 8);

Hace poco me llamó la atención una curiosa idea de tomar aportes de / dev / urandom, convertir caracteres relevantes en enteros aleatorios y usar esos enteros como los valores rgb / xy para que los píxeles se pinten en la pantalla.

He realizado algunas investigaciones (aquí en StackOverflow y en otros lugares) y muchos sugieren que simplemente puede escribir en / dev / fb0 directamente ya que es la representación del archivo del dispositivo. Desafortunadamente, esto no parece producir ningún resultado visual aparente.

Encontré un programa de muestra C que provenía de un tutorial de QT (ya no estaba disponible) que usaba un mmap para escribir en el búfer. El programa se ejecuta con éxito, pero de nuevo, no hay salida a la pantalla. Curiosamente, cuando coloqué mi computadora portátil en Suspensión y luego la restauré, vi un destello momentáneo de la imagen (un cuadrado rojo) que se escribió en el framebuffer mucho antes. ¿Funciona la escritura en el framebuffer en Linux para pintar en pantalla? Idealmente, me gustaría escribir un script (ba) sh, pero C o similar también funcionaría. ¡Gracias!

EDITAR: Aquí está el programa de muestra ... puede parecerle familiar a los veterinarios.

#include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <fcntl.h> #include <linux/fb.h> #include <sys/mman.h> #include <sys/ioctl.h> int main() { int fbfd = 0; struct fb_var_screeninfo vinfo; struct fb_fix_screeninfo finfo; long int screensize = 0; char *fbp = 0; int x = 0, y = 0; long int location = 0; // Open the file for reading and writing fbfd = open("/dev/fb0", O_RDWR); if (fbfd == -1) { perror("Error: cannot open framebuffer device"); exit(1); } printf("The framebuffer device was opened successfully./n"); // Get fixed screen information if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) { perror("Error reading fixed information"); exit(2); } // Get variable screen information if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) { perror("Error reading variable information"); exit(3); } printf("%dx%d, %dbpp/n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel); // Figure out the size of the screen in bytes screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; // Map the device to memory fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0); if ((int)fbp == -1) { perror("Error: failed to map framebuffer device to memory"); exit(4); } printf("The framebuffer device was mapped to memory successfully./n"); x = 100; y = 100; // Where we are going to put the pixel // Figure out where in memory to put the pixel for (y = 100; y < 300; y++) for (x = 100; x < 300; x++) { location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) + (y+vinfo.yoffset) * finfo.line_length; if (vinfo.bits_per_pixel == 32) { *(fbp + location) = 100; // Some blue *(fbp + location + 1) = 15+(x-100)/2; // A little green *(fbp + location + 2) = 200-(y-100)/5; // A lot of red *(fbp + location + 3) = 0; // No transparency //location += 4; } else { //assume 16bpp int b = 10; int g = (x-100)/6; // A little green int r = 31-(y-100)/16; // A lot of red unsigned short int t = r<<11 | g << 5 | b; *((unsigned short int*)(fbp + location)) = t; } } munmap(fbp, screensize); close(fbfd); return 0; }


Deberías usar fb_fix_screeninfo.smem_len para el tamaño de pantalla en lugar de hacer la multiplicación tú mismo. El buffer puede alinearse en 4 bytes o algo más.

screensize = finfo.smem_len;


He tenido éxito con los siguientes experimentos.

Primero, descubra si X está usando TrueColor RGB con relleno de 32 bits (o simplemente asuma que este es el caso). Luego averigua si tienes permiso de escritura para fb0 (y que existe). Si esto es cierto (y espero que muchos toolkits / desktops / PC modernos puedan usar estos como valores predeterminados), entonces usted debería poder hacer lo siguiente (y si estos valores predeterminados no se cumplen, entonces probablemente todavía pueda tener algún éxito con las siguientes pruebas aunque los detalles pueden variar):

Prueba 1: abra una terminal virtual (en X) y escriba: $ echo "ddd ... ddd"> / dev / fb0 donde la ... es en realidad una pantalla llena de d. El resultado será una o más líneas (parciales) de gris en la parte superior de la pantalla, según el tiempo que tenga su cadena de eco y la resolución de píxeles que haya habilitado. También puede elegir cualquier letra (los valores de ascii son todos menos de 0x80, por lo que el color producido será de un gris oscuro ... y varíe las letras si desea algo además de gris). Obviamente, esto se puede generalizar a un bucle de shell o puede obtener un archivo grande para ver el efecto con mayor claridad: por ejemplo: $ cat /lib/libc.so.6> / dev / fb0 para ver los colores reales de algunos partidarios de fsf ;-P

No se preocupe si se escribe una gran parte de la pantalla. X todavía tiene el control del puntero del mouse y todavía tiene su idea de dónde se asignan las ventanas. Todo lo que tienes que hacer es tomar cualquier ventana y arrastrarla un poco para borrar el ruido.

Prueba 2: cat / dev / fb0> xxx luego cambie la apariencia de su escritorio (por ejemplo, abra ventanas nuevas y cierre otras). Finalmente, haz lo contrario: cat xxx> / dev / fb0 para recuperar tu viejo escritorio.

Ja, bueno, no del todo. La imagen de su escritorio anterior es una ilusión, y prescindirá rápidamente de ella cuando abra cualquier ventana a pantalla completa.

Prueba 3: escriba una pequeña aplicación que capture un volcado anterior de / dev / fb0 y modifique los colores de los píxeles, por ejemplo, para eliminar el componente rojo o aumentar el azul, o voltear el rojo y el verde, etc. Luego, vuelva a escribir estos píxeles en un nuevo archivo que puede ver más adelante mediante el enfoque de shell simple de la prueba 2. Además, tenga en cuenta que probablemente se ocupe de las cantidades de BGRA de 4 bytes por píxel. Esto significa que quiere ignorar cada 4to byte y también tratar el primero en cada conjunto como el componente azul. "ARGB" es big-endian, por lo que si visita estos bytes aumentando el índice de una matriz C, primero aparecerán azul, luego verde, luego rojo ... es decir, BGRA (no ARGB).

Prueba 4: escriba una aplicación en cualquier idioma que gire a la velocidad del video y envíe una imagen no cuadrada (pensar xeyes) a una parte de la pantalla para crear una animación sin bordes de ventanas. Para puntos extra, haz que la animación se mueva por toda la pantalla. Tendrá que asegurarse de omitir un espacio grande después de dibujar una pequeña fila de píxeles (para compensar el ancho de la pantalla que es probablemente mucho más ancho que la imagen que se está animando).

Prueba 5: juega un truco a un amigo, por ejemplo, amplíe la prueba 4 para que aparezca una imagen de una persona animada en su escritorio (tal vez filme usted mismo para obtener los datos de píxeles), luego camine hacia uno de sus escritorios importantes carpetas, recoge la carpeta y la destroza, luego comienza a reír histéricamente, y luego una bola de fuego sale y engulle todo su escritorio. Aunque todo esto será una ilusión, pueden enloquecer un poco ... pero utilícenlo como una experiencia de aprendizaje para mostrar Linux y el código abierto y muestren a un novato su aspecto mucho más aterrador de lo que realmente es. [el "virus" es generalmente ilusiones inofensivas en Linux]


Si está ejecutando X11, DEBE pasar por las API X11 para dibujar en la pantalla. Ir por el servidor X está muy roto (y, a menudo como has visto, no funciona). También puede causar bloqueos, o solo corrupción de visualización general.

Si desea poder ejecutar en todas partes (tanto en la consola como en X), mire SDL o GGI. Si solo te preocupa X11, puedes usar GTK, QT o incluso Xlib. Hay muchas, muchas opciones ...


Yo diría que tenga cuidado antes de intentar escribir en / dev / fb0, como se sugirió anteriormente. Lo intenté en X en ubuntu 10.04 y a) no sucedió nada visualmente, b) arruinó todas las ventanas de shell, incluso otras ttys, lo que generó errores en el kernel y falta de funcionalidad.


si depura su programa, encontrará la línea:

screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;

screensize es 0. porque vinfo.xres es 0. debes cambiarlo a:

long ppc_fx = (((long)fixed_info.smem_start) - ((long) fixed_info.smem_start & ~(PAGE_SIZE-1))); screensize = finfo.smem_len + ppc_fx;

desde Linux 2.6.2? , los 2dos argumentos de mmap (), screensize , no deben ser 0. de lo contrario mmap () devolverá MAP_FAILED.