绘制一条线和绘制多个点之间的区别

4

我是使用SDL2引擎的C++。

我不明白为什么用宽度为10000的线条绘制比循环10000次并绘制构成线条的所有点要快。

绘制一条线:

SDL_RenderDrawLine(Renderer, 0, 100, 10000, 100);

绘制10000个点:

for(unsigned k=0; k<10000; k++) {
    SDL_RenderDrawPoint(Renderer, 0+k, 100);
}

为什么绘制所有点会影响程序性能? 我认为draw_line函数也是这样做的...
我想知道为什么会这样,因为我正在尝试创建一些关于着色器的函数...

如果您想绘制许多点,请使用 SDL_RenderDrawPoints(末尾带有s)。我无法回答您的问题,因为我不知道它为什么会变慢,但我的假设是在每次绘制调用的开头和/或结尾发生了一些非常昂贵的操作。 - Garrett Gutierrez
@GarrettGutierrez 我也这么认为。这让我感到很难过。 - manudicri
就像我说的那样,这可以通过将要渲染的点推送到连续的内存部分,然后在指向第一个点的指针上使用 SDL_RenderDrawPoints 来完全避免。 - Garrett Gutierrez
@GarrettGutierrez 好的,但我每帧应该推10000个点。这样会慢吗? - manudicri
@GarrettGutierrez 我试过这个,但速度很慢 => 1fps - manudicri
3
如果我们谈论硬件加速渲染,每次绘制调用都会在内存压力和驱动程序/GPU处理方面产生开销-这就是为什么将100万个三角形绘制为一个调用比进行100万次绘制要快得多的原因。除此之外,渲染器具有巨大的并行性,仅绘制一个点就利用了例如执行单元的1/64(例如)在最佳情况下。相较于三角形,绘制线条也很昂贵,但单独的点会大大降低性能。 - keltar
1个回答

5

驱动函数调用开销。SDL_Renderer(至少OpenGL后端)不尝试批处理多个非s调用(SDL_RenderDrawLine() / SDL_RenderDrawPoint() / SDL_RenderDrawRect() / SDL_RenderFillRect()),它只是调用具有count = 1s变体

// src/render/SDL_render.c#l1558
int
SDL_RenderDrawPoint(SDL_Renderer * renderer, int x, int y)
{
    SDL_Point point;

    point.x = x;
    point.y = y;
    return SDL_RenderDrawPoints(renderer, &point, 1);
}

s函数(SDL_RenderDrawLines()/SDL_RenderDrawPoints()/SDL_RenderDrawRects()/SDL_RenderFillRects())通常只是将它们的绘制内容直接输出到驱动程序:

// src/render/opengl/SDL_render_gl.c#l1220
static int
GL_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points,
                    int count)
{
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
    int i;

    GL_SetDrawingState(renderer);

    data->glBegin(GL_POINTS);
    for (i = 0; i < count; ++i) {
        data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
    }
    data->glEnd();

    return 0;
}

一种更为复杂的后端技术可以将几何体收集到更大的缓冲区中,并仅在 API 的排序语义绝对需要时向驱动程序发出实际的绘制调用。像这样将几何体和绘制调用批处理在一起通常会带来 更高的吞吐量


我在我的程序中不使用OpenGL。 - manudicri
5
@DiCri,SDL可以实现这一功能(或者不是GL,而是像DirectX或Metal这样的库——具体取决于操作系统和环境,但基本思想是相同的)。 - keltar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接