SDL2:什么决定单缓冲与双缓冲?

问题描述 投票:0回答:1

我正在尝试恢复 20 多年前我为学生编写的一个旧的跨平台图形库。 Apple 停止使用 Carbon 后,我在 SDL2 之上重新实现了 Mac 端,SDL2 大约 10 年前就已经运行了。该库是围绕持久屏幕模型而不是持久对象模型构建的:绘制后的像素将保持绘制状态,直到被擦除。显然,该模型不适用于双缓冲。所以我围绕这个答案进行了重建,以获得单一缓冲。

单独使用时,下面的代码按预期工作,单缓冲,生成此图像:

enter image description here

将 VERBATIM 复制到我的库的较大主文件中,代替该文件的 main(),它以某种方式以双缓冲模式执行,具有明显的交替行被绘制到交替缓冲区中的模式。此外,有证据表明 SDL_RenderDrawLine 正在绘制某种未初始化的内存,然后被逐块传输到主显示纹理上。 (尽管为了简洁起见,我在此处包含了最少的标头,但即使我包含与库的完整主文件中使用的完全相同的标头(一个更大的集合),独立版本仍然可以按预期工作。)

enter image description hereenter image description here

显然我不能指望有人调试我的大型程序,但是有谁知道:SDL2 中决定它是否在单缓冲区或双缓冲区模式下运行的“开关”到底在哪里?或者我可能暴露了一个错误吗?似乎有一些非常微妙的东西正在做出决定。

MacOS 14.2.1; SDL2 版本 2.30.4

代码:

#include <SDL2/SDL.h>
#include <SDL2/SDL2_gfxPrimitives.h>

#include <unistd.h>

SDL_Window* gWindow = NULL;             //The window we'll be rendering to
SDL_Renderer* gRenderer = NULL;         // Renders to an offscreen "texture" (frequent)
static SDL_Texture *target;
SDL_Event event;

void DrawNow();

int points[][2] = {
    {50, 50},
    {200, 100},
    {50, 300},
    {400, 400},
    {300, 70},
    {70, 450}
};

void AutoDraw() {   // "User" graphics
    filledCircleColor(gRenderer, 100, 100, 40, 0xff00ff00);
    SDL_SetRenderDrawColor(gRenderer, 0xff, 0xaa, 0x00, 0xFF );
    for (int i = 1; i < 6; i++) {
        SDL_RenderDrawLine( gRenderer, 
            points[i - 1][0], points[i - 1][1],
            points[i][0], points[i][1]);
        DrawNow();
        sleep(1);
    }
}

void DrawNow() {
    while (SDL_PollEvent(&event)) {
        printf("Event: %d\n", event.type);
    }

    fprintf(stderr, "step  ");
    SDL_SetRenderTarget(gRenderer, NULL);
    SDL_RenderCopy(gRenderer, target, NULL, NULL);
    SDL_RenderPresent(gRenderer);
    SDL_SetRenderTarget(gRenderer, target);
}

int main() {
    //Initialize SDL
    if( SDL_Init( SDL_INIT_EVERYTHING ) < 0 ) {
        printf( "SDL could not initialize! SDL Error: %s\n", SDL_GetError() );
        return 1;
    }
    gWindow = SDL_CreateWindow("Drawbox", 10, 10, 500, 500, 0);
    if( gWindow == NULL )    {
        printf( "Window could not be created! SDL Error: %s\n", SDL_GetError() );
        return -1;
    }
    //Create renderer for window
    gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
    if( gRenderer == NULL )
    {
        printf( "Renderer could not be created! SDL Error: %s\n", SDL_GetError() );
        return -1;
    }
    /* Create texture for display buffering */
    target = SDL_CreateTexture(gRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, 500, 500);
    SDL_SetRenderTarget(gRenderer, target);

    //Clear buffer
    SDL_SetRenderDrawColor( gRenderer, 0, 0, 0, 0xff );
    SDL_RenderClear( gRenderer );

    // handle window creation events: A MUST!
    SDL_Event event;
    while (SDL_PollEvent(&event)) {
        printf("Event: %d\n", event.type);
    }

    circleColor(gRenderer, 100, 100, 50, 0x00ff00ff);
    DrawNow();

    AutoDraw();    
    sleep(15);
    return 0;
}
c macos sdl-2 double-buffering
1个回答
0
投票

SDL2 中决定运行在单缓冲区还是双缓冲区模式的“开关”到底在哪里?

没有开关,总是假设它是双缓冲的(强调我的):

SDL_RenderPresent()

SDL 的渲染函数在后台缓冲区上运行;也就是说,调用渲染函数(例如 SDL_RenderDrawLine())不会直接在屏幕上放置一条线,而是更新后台缓冲区。因此,您可以组合整个场景,并将组合后的后台缓冲区作为完整图片“呈现”到屏幕上。 因此,当使用 SDL 的渲染 API 时,我们会完成针对该帧的所有绘制,然后每帧调用此函数一次,将最终的绘制呈现给用户。

每次出现后,后台缓冲区都应被视为无效;不要假设帧之间会存在先前的内容。强烈建议您在开始每个新帧的绘制之前调用 SDL_RenderClear() 来初始化后台缓冲区

,即使您计划覆盖每个像素。

因此,对于
DrawNow()

,您需要在

SDL_RenderClear()
“blit”之前使用
SDL_RenderCopy()
来清除后台缓冲区中可能存在或不存在的任何垃圾:
void DrawNow() {
    while (SDL_PollEvent(&event)) {
        printf("Event: %d\n", event.type);
    }

    fprintf(stderr, "step  ");
    SDL_SetRenderTarget(gRenderer, NULL);

    // clear backbuffer
    SDL_SetRenderDrawColor( gRenderer, 0, 0, 0, 0xff );
    SDL_RenderClear( gRenderer )

    SDL_RenderCopy(gRenderer, target, NULL, NULL);
    SDL_RenderPresent(gRenderer);
    SDL_SetRenderTarget(gRenderer, target);
}

	
© www.soinside.com 2019 - 2024. All rights reserved.