Подтвердить что ты не робот

Покрасьте пикселы на экран через Linux FrameBuffer

Недавно меня поразила любопытная идея взять входные данные из /dev/urandom, преобразовать соответствующие символы в случайные целые числа и использовать эти целые числа в качестве значений rgb/xy для пикселей для рисования на экране.

Я провел некоторые исследования (здесь, в StackOverflow и в других местах), и многие предполагают, что вы можете просто записать в /dev/fb0 напрямую, так как это файловое представление устройства. К сожалению, это не дает каких-либо визуально видимых результатов.

Я нашел пример программы на C, которая была из учебника по QT (больше недоступна), которая использовала mmap для записи в буфер. Программа работает успешно, но опять же, нет вывода на экран. Интересно, что когда я поместил свой ноутбук в Suspend и позже восстановил его, я увидел кратковременную вспышку изображения (красный квадрат), которое было записано в кадровый буфер гораздо раньше. Работает ли запись в фреймбуфер в Linux для рисования на экран? В идеале я хотел бы написать сценарий (ba) sh, но C или аналогичный вариант тоже подойдут. Спасибо!

РЕДАКТИРОВАТЬ: Здесь образец программы... может показаться знакомым для ветеринаров.

#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;
}
4b9b3361

Ответ 1

Если вы используете X11, вы ДОЛЖНЫ пройти через API X11, чтобы рисовать на экране. Обход X-сервера очень сломан (и, часто, как вы видели, не работает). Это может также вызвать сбои или просто общее повреждение дисплея.

Если вы хотите работать везде (как в консоли, так и под X), посмотрите SDL или GGI. Если вы только заботитесь о X11, вы можете использовать GTK, QT или даже Xlib. Существует много вариантов...

Ответ 2

У меня был успех в следующих нескольких экспериментах.

Сначала выясните, использует ли X TrueColor RGB до 32 бит (или просто предположим, что это так). Затем выясните, есть ли у вас разрешение на запись в fb0 (и что оно существует). Если они верны (и я ожидаю, что многие современные инструментальные средства/настольные компьютеры/ПК могут использовать их как значения по умолчанию), то вы должны иметь возможность сделать следующее (и если эти значения по умолчанию не выполняются, то вы, вероятно, все еще можете добиться успеха с следующие тесты, хотя детали могут отличаться):

Тест 1: откройте виртуальный терминал (в X) и введите: $ echo "ddd... ddd" > /dev/fb0 где... на самом деле это несколько скриншотов d. Результатом будет одна или несколько (частичных) линий серого в верхней части экрана, в зависимости от того, как долго ваша эхо-строка и какое разрешение пикселей вы включили. Вы также можете выбрать любые буквы (значения ascii все меньше 0x80, поэтому цвет будет темно-серым цветом.. и измените буквы, если вы хотите что-то, кроме серого). Очевидно, что это можно обобщить на цикл оболочки или вы можете написать большой файл, чтобы увидеть эффект более четко: например: $ cat/lib/libc.so.6 > /dev/fb0 чтобы увидеть истинные цвета некоторых сторонников fsf; -P

Не беспокойтесь, если надпись на большом экране будет написана. X по-прежнему контролирует указатель мыши и все еще имеет представление о том, где отображаются окна. Все, что вам нужно сделать, это захватить любое окно и немного перетащить его, чтобы стереть шум.

Тест 2: cat/dev/fb0 > xxx затем измените внешний вид рабочего стола (например, откройте новые окна и закройте другие). Наконец, сделайте обратное: cat xxx > /dev/fb0, чтобы вернуть старый рабочий стол!

Ха, ну, не совсем. Образ старого рабочего стола - это иллюзия, и вы быстро обойдете его, когда вы откроете любое окно на весь экран.

Тест 3: напишите небольшое приложение, которое захватывает предыдущий дамп /dev/fb 0 и изменяет цвета пикселей, например, чтобы удалить красный компонент или увеличить синий цвет или перевернуть красный и зеленый цвета и т.д. Затем напишите эти пиксели в новый файл, который вы можете посмотреть позже, используя простой подход к тестированию оболочки 2. Также обратите внимание, что вы, вероятно, будете иметь дело с 4-байтовыми количествами BGRA на пиксель. Это означает, что вы хотите игнорировать каждый 4-й байт, а также обрабатывать первый в каждом наборе как синий компонент. "ARGB" является big-endian, поэтому, если вы посещаете эти байты через увеличивающийся индекс массива C, синий будет первым, затем зеленым, а затем красным, то есть B-G-R-A (не A-R-G-B).

Тест 4: напишите приложение на любом языке, который на скорости видео отправит не квадратное изображение (думаю, xeyes) на часть экрана, чтобы создать анимацию без каких-либо окон. Для дополнительных очков анимация перемещается по всему экрану. Вам нужно будет пропустить большое пространство после рисования пикселов с небольшим количеством пикселей (чтобы компенсировать ширину экрана, которая, вероятно, намного шире, чем анимация изображения).

Тест 5: сыграйте трюк с другом, например, добавьте тест 4, чтобы изображение анимированного человека появилось на рабочем столе (возможно, сделайте снимок для получения данных пикселя), затем переходите к одному из их важные папки для рабочего стола, подбирает папку и разбивает ее на части, затем истерически смеется, а затем появляется огненный шар и поглощает весь рабочий стол. Хотя это все будет иллюзией, они могут немного поразмыслить... но использовать это как опыт обучения, чтобы продемонстрировать Linux и с открытым исходным кодом и показать, как его гораздо страшнее смотреть на новичков, чем на самом деле. [ "вирус", как правило, безвредные иллюзии в Linux]

Ответ 3

Я бы сказал, будьте осторожны, прежде чем пытаться писать в /dev/fb 0, как было предложено выше. Я попробовал это под X в ubuntu 10.04 и a) ничего не произошло визуально, b) он разрушил все окна оболочки, даже другие ttys, что привело к ошибкам ядра и отсутствию функциональности.

Ответ 4

Вы должны использовать fb_fix_screeninfo.smem_len для экранирования вместо того, чтобы делать умножение самостоятельно. Буфер может быть выровнен на 4 байта или что-то еще.

screensize = finfo.smem_len;

Ответ 5

Когда я использовал эту программу для записи полного экрана, она разбилась, что связано с неправильным вычислением размера экрана.

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

Это должно быть:

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

Ответ 6

если вы отлаживаете свою программу, вы найдете строку:

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

screensize равно 0. поскольку vinfo.xres равно 0. вы должны изменить его на:

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

с Linux 2.6.2?, 2-й аргумент mmap(), screensize не должен быть 0. иначе mmap() вернет MAP_FAILED.

Ответ 7

Я думаю о написании программы на основе фреймбуфера, просто потому, что мне нужно иметь возможность прокручивать (SDR водопад). См. Https://www.raspberrypi.org/forums/viewtopic.php?f=28&t=232493&p=1425567#p1425567 Тест прокрутки, который я считаю успешным. В этих двух структурах мы выбираем ioctl для получения информации о глубине цвета. Вы, кажется, основали свою программу на том же примере, что и я. Как получить цвет пикселей из кадрового буфера на Linux (Raspberry Pi)

Мой отлично работает на моем Raspberry Pi, либо с X или нет. Это не влияет на экран моего ноутбука. У него есть /dev/fb0, программа запускается и цифры выглядят правильно, но визуально ничего не делает. Может быть, это двойной буфер или что-то.

Под X это фактически не наносит ущерба. Если вы перетаскиваете несколько окон, чтобы все перерисовывалось, все возвращается. Затем я решил сделать резервную копию того, что на экране, и положить его обратно, когда я закончу, это тоже работает. Окно, которое я переместил и положил обратно, работает так же, как если бы я никогда не касался его. X не понимает, что я испортил экранный буфер, он знает, что там находится, и соответственно регистрирует щелчки мышью. Если бы я переместил окно и не положил его обратно, щелчки все равно работали бы там, где они были.