Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C-SDL不一致的帧率和屏幕垃圾已通过调用printf?y修复_C_Linux_Sdl_Frame Rate - Fatal编程技术网

C-SDL不一致的帧率和屏幕垃圾已通过调用printf?y修复

C-SDL不一致的帧率和屏幕垃圾已通过调用printf?y修复,c,linux,sdl,frame-rate,C,Linux,Sdl,Frame Rate,我一直在做一个非常简单的SDL闪光灯程序,它以可变的速率在屏幕上闪烁两种不同的颜色。速率和两种颜色在命令行中指定, ie:/选通13 0xffffff 0x000000。指定13hz的选通频率,白色和黑色分别作为color1和color2/频闪-h显示使用信息和一些其他信息。我使用gcc在Lubuntu 14.10上编译如下: gcc strobe.c$sdl config-cflags-libs-lSDL-std=c99-pedantic-o选通 我使用delta-time技术,通过计算循环结

我一直在做一个非常简单的SDL闪光灯程序,它以可变的速率在屏幕上闪烁两种不同的颜色。速率和两种颜色在命令行中指定, ie:/选通13 0xffffff 0x000000。指定13hz的选通频率,白色和黑色分别作为color1和color2/频闪-h显示使用信息和一些其他信息。我使用gcc在Lubuntu 14.10上编译如下: gcc strobe.c$sdl config-cflags-libs-lSDL-std=c99-pedantic-o选通

我使用delta-time技术,通过计算循环结束时渲染帧所需的时间,并在帧提前完成时调用SDL_-Delay,将帧速率限制在指定的值

我唯一真正的问题是,帧速率似乎有点急促和不一致,当不是全屏时,我注意到屏幕右上角和窗口右上角有一些垃圾。这两种颜色之间的占空比有时似乎也略有不同,我在查看代码时找不到这样做的理由

也许对我来说最令人费解的部分是:我在调用SDL_Delay之前添加了一个printf调用,以便打印在该帧上花费的毫秒数t的值,看看它是否变化很大。令我惊讶的是,这个简单的东西解决了这个问题,屏幕上角不再有垃圾,帧速率看起来更加一致!唯一的问题是,我无法理解这到底是如何产生任何差异的,我不想在每个帧上用当前值t填充终端。我在这里问这个问题是希望比我更了解SDL的人能够解释这一点,并提供一些关于我代码中这种奇怪异常机制的见解

我将在下面发布完整的代码。请原谅,如果我遗漏了更不相关的部分,我很想这样做,但觉得提供一个完整的图片可能更好

在外while循环main末尾的最后几行是我认为可能存在问题的地方

#include <SDL/SDL.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>

#define HRES 640
#define VRES 480
#define NCOLORS 2
#define MAXFPS 400

Uint16 create_hicolor_pixel(SDL_PixelFormat * fmt, Uint8 red, Uint8 green,
              Uint8 blue)
{
    Uint16 value;
    /* This series of bit shifts uses the information from the SDL_Format
     * structure to correctly compose a 16-bit pixel value from 8-bit RGB */
    value = ((red  >> fmt->Rloss) << fmt->Rshift) +
        ((green >> fmt->Gloss) << fmt->Gshift)    +
        ((blue  >> fmt->Bloss) << fmt->Bshift);

    return value;
}

int getargs(int argc, char **argv, int *fps, Uint32 *rgb_color)
{
    int error = 0;
    /* Command line args */
    if (argc < 4) {
        fprintf(stderr, "Too few parameters.\n");
        error = 1;
    } else if (argc > 4) {
        fprintf(stderr, "Too many parameters.\n");
        error = 1;
    } else {
        char *endptr;

        *fps = (int) strtol(*++argv, &endptr, 0);
        if (endptr == *(argv - 1) || (*fps < 1 || *fps > MAXFPS)) {
            fprintf(stderr, "Bad frequency value. Try values between 1 - %d\n",
                    MAXFPS);
            error = 1;
        }

        rgb_color[0] = (Uint32) strtol(*++argv, &endptr, 16);
        if ((endptr == *(argv - 1)) || (rgb_color[0] < 0) || 
                                     (rgb_color[0] > 0xffffff)) {
            fprintf(stderr, "Bad color value. Must be valid 24bit RGB hex\n");
            error = 1;
        }

        rgb_color[1] = (Uint32) strtol(*++argv, &endptr, 16);
        if ((endptr == *(argv - 1)) || (rgb_color[1] < 0) || 
                                     (rgb_color[1] > 0xffffff)) {
            fprintf(stderr, "Bad color value. Must be valid 24bit RGB hex\n");
            error = 1;
        }
    }

    return error;
}

void showusageinfo(char *prgname)
{
    printf("\nUsage: %s [freq] [color1] [color2]\n\n", prgname);

    printf("Strobe is a simple program that uses the users monitor to implement a\n"
        "strobe light effect. The user can set the flash frequency and the two\n"
        "colors to flash between by passing these to strobe as command line\n"
        "arguments. Strobe uses the SDL library, and currently displays in\n"
        "hi-color (16bit) mode. User entered color values are automatically\n"
        "composed into the correct hi-color format for the user's system.\n\n");

    printf("The first parameter is the strobe rate (frequency) in hertz or cycles\n"
        "per second. This parameter takes a decimal value from 1 to MAXFPS.\n"
        "Flash rates higher than your monitors refresh rate will probably not\n"
        "display correctly. You may also be limited by the speed of your machine's"
        "\n\nCPU and video card.\n");

    printf("The second two parameters shall be 24bit RGB hexadecimal values for\n"
        "color1 and color2 respectively such as 0xffffff for white, and\n"
        "0xffff00 for yellow. As of version 0.1 common names of colors are\n"
        "not supported.\n\n");

    printf("An example for running strobe at a 15hz strobe rate, with yellow and\n"
        "a turquois shade of blue as color1 and color2, respectively:\n\n"
        "strobe 15 0xffff00 0x0080ff\n\n");

    printf("Pressing the 'ESC' key, or the 'q' key while strobe is running will\n"
           "safely exit from the program.\n\n");
}

int main(int argc, char **argv)
{
    SDL_Surface *screen;
    SDL_Event   event;
    Uint16  *scr_pixels;
    Uint16  hicolor_color[NCOLORS];
    Uint32  rgb_color[NCOLORS];
    int     coloridx = 0;
    int x, y, i;
    int quit = 0;
    int fps, t;

    if (argc > 1 && strcmp(argv[1], "-h") == 0) {
        showusageinfo(*argv);
        exit(EXIT_SUCCESS);
    }

    if (getargs(argc, argv, &fps, rgb_color) != 0) {
        printf("Usage: %s [freq] [color1] [color2]\n"
               "       %s -h to see help info for this program.\n\n",
               *argv, *argv);
        exit(EXIT_FAILURE);
    }

    /* Init SDL */
    if (SDL_Init(SDL_INIT_VIDEO) != 0) {
        fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError());
        return 1;
    }

    atexit(SDL_Quit);

    (void) SDL_ShowCursor(SDL_DISABLE);
    SDL_WM_SetCaption("Strobe", "Strobe");

    screen = SDL_SetVideoMode(HRES, VRES, 16, SDL_HWSURFACE  |
                                              SDL_DOUBLEBUF  |
                                              0 );//no fullscreen until fixed
    if (screen == NULL) {
        fprintf(stderr, "Unable to set video mode: %s\n", SDL_GetError());
        exit(EXIT_FAILURE);
    }

    /*Initialize hicolor colors*/
    for (i = 0; i < NCOLORS; ++i) {
        hicolor_color[i] = create_hicolor_pixel(screen->format,
                                                (rgb_color[i] & 0xff0000) >> 16,
                                                (rgb_color[i] & 0xff00)   >> 8,
                                                (rgb_color[i] & 0xff)     >> 0);
    }

    /* Get a pointer to the video surface's memory. */
    scr_pixels = (Uint16*) screen->pixels;

    while (!quit) {
        t = SDL_GetTicks();
        if (SDL_PollEvent(&event)) {
            switch (event.type) {
                case SDL_QUIT:
                    quit = 1;
                    break;
                case SDL_KEYDOWN:
                    switch (event.key.keysym.sym) {
                        case SDLK_ESCAPE:
                        case SDLK_q:
                            quit = 1;
                            break;
                    }
                    break;
            }
        }

        SDL_LockSurface(screen);
        coloridx ^= 1;
        for(x = 0; x < HRES; x++) {
            for(y = 0; y < VRES; y++) {
                scr_pixels[(screen->pitch >> 1) * y + x] = hicolor_color[coloridx];
            }
        }
        SDL_UnlockSurface(screen);
        SDL_Flip(screen);

        assert(SDL_GetTicks() > t);
        if ((t = SDL_GetTicks() - t) < 1000 / fps) {
            printf("%d\n", t); //why does this fix the framerate problem?
            SDL_Delay((1000 / fps) - t);
        }
    }

    exit(EXIT_SUCCESS);
}

由于某种原因,在调用SDL_Delay之前的printf调用修复了垃圾。。。但更让我困惑的是,当我尝试用putchar“\0”替换它时,问题再次出现,因此出于某种原因,只有对printf的调用修复了它,而不是putchar,这让我想知道还有哪些调用可能具有相同的效果,我开始怀疑AMD Catalyst驱动程序Omega 14.12,所以在添加了一个命令行选项来打印当前帧数、帧执行时间和平均帧率后,我在另一台运行Lubuntu的机器上使用默认的开源驱动程序尝试了该程序。在这台机器上,一切都正常运转


禁用Catalyst Control Center中的无撕裂选项,修复了屏幕损坏问题。根据我所看到的结果,我认为这个问题可能来自较低级别,可能涉及AMD视频驱动程序。

我还想补充一点,我刚刚尝试将stdout重定向到/dev/null,以便在终端中不会出现任何内容,并出现相同的屏幕垃圾,但是让它进入终端可以修复它??全屏模式有帮助吗?它在全屏模式下给出相同的行为。我也尝试了32bpp而不是hicolor,还有一些不同的分辨率,结果是屏幕上的垃圾和不稳定的帧率。上述对printf的调用似乎也在全屏上解决或至少隐藏了这个问题。我感兴趣的是,即使调用printf,将stdout重定向到/dev/null也会导致问题返回。printf可能正在改变计时。你能在另一台计算机上试试吗?我添加了一个命令行选项来切换printf语句,将帧执行时间发送到stderr。我在另一台运行lubuntu的机器上尝试了这一点,但这台机器运行默认的开源视频驱动程序。除了预期的常规页面外,该行为是正确的。我开始怀疑这可能是AMD catalyst驱动程序的问题,因为当关闭无撕裂模式时,我得到了正确的行为,但没有撕裂。垃圾看起来像来自上一帧/下一帧的小像素块。AMD catalyst驱动程序显然有一些怪癖。