手機 - Nokia N900 - Maemo - 解決Screen Tearing問題



雖然司徒之前已經有上網找尋這個問題,不過沒有找到解答,所以司徒一直認為是N900的驅動問題,直到最近,司徒再度心血來潮,想說來解解看這個問題,這才發現OMAP2的顯示驅動似乎怪怪的,過程如下說明

main.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <string.h>
#include <linux/fb.h>
#include <linux/omapfb.h>
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>

int main(int argc, char* args[])
{
    SDL_Surface* screen = NULL;
    int index = 0, cnt = 200;
    int fd = open("/dev/fb0", O_RDWR);

    SDL_Init(SDL_INIT_VIDEO);
    screen = SDL_SetVideoMode(800, 480, 16, SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_FULLSCREEN);
    SDL_ShowCursor(0);

    while (cnt--) {
        switch (index) {
        case 0:
            SDL_FillRect(screen, &screen->clip_rect, SDL_MapRGB(screen->format, 0xff, 0x00, 0x00));
            break;
        case 1:
            SDL_FillRect(screen, &screen->clip_rect, SDL_MapRGB(screen->format, 0x00, 0xff, 0x00));
            break;
        case 2:
            SDL_FillRect(screen, &screen->clip_rect, SDL_MapRGB(screen->format, 0x00, 0x00, 0xff));
            break;
        }
        index += 1;
        if (index >= 3) {
            index = 0;
        }
        SDL_Flip(screen);

        int zero = 0;
        ioctl(fd, FBIO_WAITFORVSYNC, &zero);
        SDL_Delay(30);
    }
    close(fd);
    SDL_Quit();
    return 0;
}

$ dmesg



Kernel

int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
{
  struct omapfb_info *ofbi = FB2OFB(fbi);
  struct omapfb2_device *fbdev = ofbi->fbdev;
  struct omap_display *display = fb2display(fbi);

  ...
  switch (cmd) {
  ...
  case OMAPFB_WAITFORVSYNC:
    DBG("ioctl WAITFORVSYNC\n");
    if (!display) {
      r = -EINVAL;
      break;
    }

    omap_dss_lock();
    r = display->wait_vsync(display);
    omap_dss_unlock();
    break;

  ...
  default:
    dev_err(fbdev->dev, "Unknown ioctl 0x%x\n", cmd);
    r = -EINVAL;
  }

  if (r < 0)
    DBG("ioctl failed: %d\n", r);

  return r;
}

最後改成使用OMAPFB_WAITFORVSYNC即可解決Screen Tearing問題,而不是使用FBIO_WAITFORVSYNC

ioctl(fd, OMAPFB_WAITFORVSYNC, &zero);