2 minute read

해당 사이트에서 자세한 설명을 읽을 수 있습니다.

위 사이트의 내용 정리

immediate mode 코드의 예시

glBegin(GL_TRIANGLES);
    glColor3f(1.0f, 0.0f, 0.0f);   glVertex2f(0.0f,   1.0f);
    glColor3f(0.0f, 1.0f, 0.0f);   glVertex2f(0.87f,  -0.5f);
    glColor3f(0.0f, 0.0f, 1.0f);   glVertex2f(-0.87f, -0.5f);
glEnd();

위 처럼 glBegin과 glEnd사이에 glVertex를 사용하는 것이 immediate 모드입니다. 또 다른 예는 glDrawArrays를 클라이언트 정점 배열(client vertex array)과 함께 사용하는 것입니다. (즉, 정점 버퍼 객체가 아니다.)

1. immediate 모드가 optimal하지 않은 이유 (그래서 보통 사용되지 않습니다.)

  • 그래픽 카드가 프로그램의 흐름과 직접 연결되어 있기 때문입니다.
  • 드라이버는 glEnd전에 GPU한테 렌더링을 시작하라고 말할 수 없습니다.
    • 왜냐하면 데이터 제출이 언제 끝날 지 모르기 때문입니다.
    • 그리고 해당 데이터(vertex와 같은 데이터를 말하는 듯하다.)도 같이 전송해야 하는데, glEnd후에만 수행할 수 있기 때문입니다.
  • 마찬가지로 클라이언트 정점 배열을 사용하면 드라이버는 glDrawArrays를 호출하는 순간에만 배열 복사본을 가져올 수 있습니다.
    • 그렇게 하는 동안은 어플리케이션을 차단해야합니다.
    • 그 이유는 드라이버가 캡처하기 전에 우리가 배열의 메모리를 수정 또는 free(해제)할 수 있기 때문입니다.
    • 데이터가 한 시점에서 정확히 유효하다는 것만 알고 있기 때문에 해당 작업을 더 일찍 또는 나중에 예약할 수 없습니다.

2. retained mode의 장점

이와는 대조적으로 정점 버퍼 객체(vertex buffer object)를 사용한다면 버퍼를 데이터로 채우고 OpenGL에 전달합니다. 프로세스는 더 이상 이 데이터를 소유하지 않으므로 더 이상 수정할 수 없습니다. 드라이버는 이 사실을 신뢰할 수 있기에 버스가 비어 있을 때마다 (추측적으로도) 데이터를 업로드할 수 있습니다. 이후의 glDrawArrays 또는 glDrawElements 호출은 작업 대기열로 이동하여 즉시 반환되므로(실제로 완료되기 전에!) 프로그램은 계속해서 명령을 제출하는 동시에 드라이버가 하나씩 작동합니다. 또한 드라이버가 훨씬 더 일찍 데이터가 도착할 때까지 기다릴 필요가 없을 것입니다. 따라서 렌더 스레드와 GPU는 비동기적으로 실행되고 모든 구성 요소는 항상 사용 중이므로 성능이 향상됩니다.

2.1 retained mode 예시코드

일반적인 요청에 따라 retained mode의 동일한 내용은 다음과 같습니다.

float verts = {...};
float colors = {...};
static_assert(sizeof(verts) == sizeof(colors), "");

// not really needed for this example, but mandatory in core profile after GL 3.2
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);

GLuint buf[2];
glGenBuffers(2, buf);

// assuming a layout(location = 0) for position and 
// layout(location = 1) for color in the vertex shader

// vertex positions
glBindBuffer(GL_ARRAY_BUFFER, buf[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
glEnableVertexAttribArray(0); 
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

// copy/paste for color... same code as above. A real, non-trivial program would
// normally use a single buffer for both -- usually with stride (5th param) to
// glVertexAttribPointer -- that presumes interleaving the verts and colors arrays.
// It's somewhat uglier but has better cache performance (ugly does however not
// matter for a real program, since data is loaded from a modelling-tool generated
// binary file anyway).
glBindBuffer(GL_ARRAY_BUFFER, buf[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
glEnableVertexAttribArray(1); 
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);

glDrawArrays(GL_TRIANGLES, 0, 3); 

3. core-profile과 retained mode

https://stackoverflow.com/questions/69796270/is-it-correct-to-say-that-opengl-3-2-core-profile-is-based-on-retained-mode-p https://mulloverthings.com/is-opengl-retained-mode/

core-profile과 retained mode의 설명이 혼용되는 것 같습니다. 이에 따른 정리도 한 번 해보겠습니다.

우선 OpenGL에서는 retained mode라는 것은 존재하지 않습니다.