OpenGL에서 "버퍼"와 "어레이"의 차이점은 무엇입니까?


12

webGL 또는 OpenGL에서 doc을 읽으면 함수 및 객체 이름이 사용되는 방식에 몇 가지 패턴이 있습니다. 그러나 버퍼 객체와 배열의 차이점을 이해할 수 없습니다.

"vertex buffer objects", "vertex array objects", 심지어 "buffer array"또는 "arraybuffer"도 있습니다.

OpenGL 컨텍스트에서 "어레이"가 언제 "버퍼"라고해야합니까?


일부 관점에서는 네트워크를 통해 데이터를 가져오고 수신 된 모든 로그를 저장하는 것을 생각하십시오. 소켓을 읽고 수신 된 데이터를 어딘가에 넣어서 전달할 수 있어야합니다. 버퍼입니다. 로컬로 범위가 지정되고 동적으로 할당 된 단순 목록 유형일 수 있습니다. 때로는 char* buffer = socketRead();(의사 코드) 처럼 간단 합니다. 반면에 로그는 전체 앱 수명주기 동안 유지됩니다. 따라서 어딘가에 배열을 만들고 소켓을 읽기 시작하면 데이터를 얻을 때마다 해당 청크를 배열에 기록하여받은 모든 데이터의 깔끔한 목록을 제공합니다.
케빈

답변:


5

정점 배열 객체의 이름은 다소 불행합니다. 응용 프로그램 안팎에서 나타나거나 표시되는 것처럼 보이는 세 가지 항목이 있으며 이름에 "배열"또는 "버퍼"를 사용하여 이름이 다르게 지정된 (역사적으로는) 이름이 있습니다 (프레임 버퍼 개체도 있음) 그러나 나는 그것을 무시할 것이다).

  1. 공식적으로 그리고 실제로 애플리케이션에 존재하지만 OpenGL이 버텍스 별 정점과 달리 한 번에 가져 오는 데이터. 이것은 한때 정점 배열 이라고 부르는 것이 었습니다 .
    OpenGL은 데이터가 일관성이 있다는 약속을했을 때 데이터를 한 번에 한 번에 한 번에 복사하고 AGP 또는 한 블록 내에서 데이터를 푸시 할 수 있기 때문에보다 효율적으로 액세스하기위한 것입니다. 이것은 더 이상 존재하지 않습니다.
  2. "바인딩"될 수있는 (즉, 활성화 된) 핸들에 의해 데이터가 가려지고 액세스 가능합니다. 데이터 실제로 주 메모리 나 그래픽 카드에 살거나 PCIe 매핑 가능 영역으로 이동할 수 있지만 공식적으로 소유하지 않은 방식 (물리적으로 RAM에 있거나 데이터가 응용 프로그램에서 온 경우에도) ) it-해당 API를 통해 현재 "매핑 된"경우가 아니라면 쓰기 가능하고 때로는 읽을 수있는 포인터를 가져옵니다. 또한 데이터에 발생하는 일을 전혀 통제 할 수있는 능력이 제한적입니다 (일부 힌트를 줄 수 있지만 그 정도입니다).
    OpenGL은이 데이터를 어느 정도 자유롭게 이동할 수 있으며, 해당 API를 통해 버퍼로 복사하거나 버퍼에서 복사하거나 데이터가 매핑되는 동안에 만 액세스 할 수 있습니다. 그것이 당신이 버퍼 객체 (정점을 포함한다면 정점 버퍼 객체 라고 부르는 것이지만 실제로는 꼭 필요하지는 않습니다. 이미지 데이터 또는 유니폼 일 수도 있고 정점만이 한 번에 처음 지원되었습니다).
    이것의 목적은 OpenGL이 원하는 것을 (원칙적으로) 수행 할 수 있도록 보장하기 위해, 버퍼를 그리기 전에 PCIe를 통해 버퍼를 푸시 할 수도 있습니다. 데이터를 소유하지 않고 (OpenGL은 사용합니다!) 주어진 API를 통해서만 데이터에 액세스 할 수 있기 때문에 데이터가 유효하다는 것이 항상 알려져 있습니다. 드라이버는 다른 무언가를 위해 메모리가 필요할 때 그래픽 카드의 버퍼 메모리를 버리고 나중에 필요할 때 비밀 사본에서 복원하도록 선택할 수도 있습니다.
  3. 훨씬 더 나은 이름이 버퍼 세트 또는 디스크립터 세트와 같은 이름을 가진 정말 바보 같은 잘못된 이름입니다. 이것은 악명 높은 정점 배열 객체 입니다. 그것은 당신의 관점에서 볼 때 다른 모호한 핸들 (바인딩 할 수있는) 아래에 묶인 버퍼 핸들 세트 일뿐입니다. 현실이 조금 더 복잡합니다. 실제로 VAO는 실제 하드웨어 작동 방식에 훨씬 가깝습니다. 그래픽 카드는 각각 매우 작은 항목을 가진 적은 수의 디스크립터 세트 (버퍼뿐만 아니라 샘플러 용)도 많으며 (이는 종종 2, 4 또는 8과 같은) 매우 효율적으로 전환 할 수 있습니다. .
    이제 정점 배열 객체의 목적은 OpenGL이 내부적으로, 물론 하드웨어를 그대로 사용하기 위해 수행해야하는 API 호출 수를 줄이고 일관성 검사 수를 줄이는 것입니다. 5 개의 버퍼를 바인딩하는 경우 각 버퍼는 고가의 검사를 거쳐야하며, 각 드라이버는 드라이버에서 캐시 누락의 후보이며, 각 단일 버퍼는 설명자 등을 변경하기 위해 그래픽 카드와 통신해야합니다. 하나의 VAO를 바인딩하면 드라이버는 종종 그래픽 카드의 디스크립터 세트를 간단히 전환하여 수행 할 수 있습니다.

8

VAO (Vertex Array Object)는 하나 이상의 정점 버퍼 객체를 포함하는 객체로, 렌더링 된 객체에 대한 정보를 저장하도록 설계되었습니다.

( 크로노스 에서 잡아 당김 )

각 버퍼는 정점 배열 (객체)의 하나의 속성을 구성하는 경향이 있습니다. VAO는 많은 정점 속성 (예 : 위치, 색상, UV)을 포함 할 수 있습니다. 각 버퍼는 자체 버퍼에 보관 될 수 있습니다. 여기서 버퍼 는 포맷되지 않은 일련의 연속 바이트를 나타내며 CPU 측 OpenGL 호출 및 GPU 측 셰이더 작업 모두에 대해 버퍼 요소 당 크기 (유형)를 명시 적으로 지정해야합니다.

한 가지 방법입니다. 이것이 작동하는 다른 방법은 다음과 같습니다.

  • 모든 속성은 단일 버퍼 에 인터리브 되어 저장됩니다.
  • 일부 속성은 자체 전용 버퍼에 있으며 다른 속성은 버퍼를 공유합니다.

아래 다이어그램은이 두 가지 경우를 보여줍니다.

여기에 이미지 설명을 입력하십시오

결론 : "vertex array"라는 문구가 OpenGL에서 규정되지 않은 것으로 사용되는 경우 OpenGL 컨텍스트에서 (특히) 버퍼와는 매우 다른 VAO를 의미한다고 가정 할 수 있습니다.

주석 편집 :: GL_ARRAY_BUFFER위에서 설명한 것처럼 해당 버퍼 객체를 꼭짓점 속성 데이터에 사용하려는 의도를 나타냅니다. 버퍼는 꼭짓점 속성 에만 사용되지 않기 때문 입니다. 그러나 가장 일반적인 사용 사례이며 VAO에 대해 묻기 때문에 다른 것에 대해서는 다루지 않겠습니다. 그러나 여기 에는 설정할 수있는 다른 유형의 버퍼 목록이 있습니다.


그래서 버퍼가 있습니다 : GPU에서 1.reside의 시간 2.most 데이터의 종류를 포함 (버텍스, 요법 만 컬러), 3.Data이 요법 111122223333입니다, 인터리브된다. 4. 데이터에 액세스 할 수있는 방법제공하지 않습니다 (buffer [2] 또는 buffer [vertex_3434] 아님). 이제 배열 은 다음과 같습니다. 1. 버퍼 모음, 2. 포함 된 버퍼를 구문 분석하는 방법에 대한 정보를 저장합니다. , 버퍼의 데이터에 올바르게 액세스 할 수있는 요소의 크기, 오프셋, 오른쪽?
coobit

1. 버퍼 는 양쪽 끝에 존재하며 CPU와 GPU 사이에서 전송됩니다 (잠재적으로 앞뒤로). 그렇지 않으면 디스크에서 메쉬를로드 할 때 GPU에 업로드 할 데이터를 어떻게 채우겠습니까?. 예, 요소는 버퍼 전체에서 균일 한 유형이지만 사용중인 기술에 따라 각 버퍼 요소는 기본 또는 struct유형일 수 있습니다. 버퍼 당 데이터 인터리브되거나 완전히 균일 할 수 있습니다. CPU의 기존 C 배열과 마찬가지로 색인을 생성 할 수 있습니다. 배열 객체 (이 올바른 용어를 사용하거나 혼란스러워합니다!) ... (아래 계속)
Engineer

2. 예, 그리고 정점 프로세서에 의해 사용되는 데이터의 정의 관련된 모든 상태가 정점에 캡슐화된다 "당신은 확실히 당신의 셰이더 버퍼 선언을 사용하면 CPU 측에 VAO에 설정된 사양과 일치합니다 명시 적으로 만들 필요가 배열 객체. " (khronos docs)
엔지니어 10

그래서, 손톱을 더 치기 위해 ... 사람들은 BO 만 사용하여 AO 전에 어떻게 일했습니까? 아니면 AO는 항상 OpenGL에 있었고 나중에 VBO에 도입 된 VAO입니까?
coobit

@coobit io7m.com/documents/history-vertex-spec- 고정 파이프 라인 (오래된 학교) OpenGL, 3Dfx 등과 프로그래밍 가능한 최신 파이프 라인 OpenGL 및 Direct3D의 차이점에 대한 아이디어를 제공합니다.
엔지니어

5

이 용어는 OpenGL의 역사에 뿌리를두고 있습니다. 기억해야 할 것은 여기에 관련된 대부분의 GL 버전에서 OpenGL은 점진적으로 발전했으며 API를 변경하는 대신 기존 API에 새로운 기능을 추가함으로써 점진적으로 발전했다는 것입니다.

OpenGL의 첫 번째 버전에는 이러한 객체 유형이 없었습니다. 여러 glBegin / glEnd 호출을 실행하여 그리기를 수행했으며이 모델의 한 가지 문제점은 함수 호출 오버 헤드 측면에서 매우 비효율적이라는 점이었습니다.

OpenGL 1.1은 정점 배열을 도입하여이를 해결하기위한 첫 단계를 수행했습니다. 꼭짓점 데이터를 직접 지정하는 대신 이제 C / C ++ 배열에서 소스를 지정할 수 있습니다. 따라서 정점 배열은 정점 배열과 정점을 지정하는 데 필요한 GL 상태의 배열입니다.

다음 주요 진화는 GL 1.5와 함께 제공되었으며 시스템 ( "클라이언트 측") 메모리가 아닌 GPU 메모리에 정점 배열 데이터를 저장할 수있게했습니다. GL 1.1 정점 배열 사양의 약점은 전체 정점 데이터를 사용할 때마다 GPU로 전송해야한다는 것입니다. 이미 GPU에있는 경우이 전송을 피하고 잠재적 인 성능 향상을 달성 할 수 있습니다.

따라서이 데이터를 GPU에 저장할 수 있도록 새로운 유형의 GL 객체가 만들어졌습니다. 텍스처 객체를 사용하여 텍스처 데이터를 저장하는 것처럼 정점 버퍼 객체는 정점 데이터를 저장합니다. 실제로는 비 특정 데이터를 저장할 수있는보다 일반적인 버퍼 객체 유형의 특수한 경우입니다.

버텍스 버퍼 객체를 사용하기위한 API는 이미 존재하는 버텍스 어레이 API에 대해 피기 백되었습니다. 이제 우리는 상태를 저장하는 정점 배열 API를 가지고 있으며, 데이터는 메모리 내 배열이 아닌 버퍼 객체에서 소스로 제공됩니다.

이것은 우리를 거의 이야기의 끝으로 데려옵니다. 결과 API는 정점 배열 상태를 지정할 때 매우 장황했기 때문에 최적화의 또 다른 방법은이 상태를 모두 수집하고 단일 API 호출에서 여러 정점 배열 상태 변경을 허용하고 GPU를 허용하는 새로운 객체 유형을 만드는 것이 었습니다 어떤 상태가 미리 사용 될지 알 수 있기 때문에 잠재적으로 최적화를 수행합니다.

이 모든 것을 모아 정점 배열 객체를 입력하십시오.

요약하자면, 정점 배열 은 상태를 그리기위한 상태와 데이터 (어레이에 저장 됨)로 시작되었습니다. 정점 버퍼가 이탈하는 GL 객체 타입과 메모리 어레이 스토리지를 대체 정점 어레이 단지 상태중인. 정점 배열 객체는 더 쉽게 변경 적은 API 호출을 할 수 있도록이 상태 단지 컨테이너 개체입니다.


0

한동안 OpenGL과 함께 일하지 않았으므로 절반 만 할 수 있습니다. 일반적으로 : 버퍼는 포맷되지 않은 메모리 배열을 저장합니다. 배열은 연속 메모리의 일반적인 용어입니다.

버퍼는 컨텍스트에 바인딩되어야하지만 배열은 데이터 배열 일뿐입니다. 올바르게 호출하면 버퍼의 데이터가 그래픽 카드에 복사됩니다 (따라서 바인딩).

희망이 조금 도움이되기를 바랍니다.


그러면 GL_ARRAY_BUFFER는 무엇입니까? 왜 그렇게 불렸습니까? 당신의 가설에 따르면 그것은 "포맷되지 않은 연속 메모리"입니다. :)
coobit

글쎄,이 특정 예제는 버퍼에 대한 id (배열을 바인딩하는)입니다. 배열 버퍼 (예에서)는 정점 속성에 사용되므로 기본적으로 정점 속성 배열을 버퍼에 바인딩합니다. 혼란스럽게 들리므로 예를 들어 보겠습니다. CPU 측에 색상, 정상, 위치 등이 될 수있는 배열이 있으며 이제 GPU가 액세스하려고합니다. bindBuffer가 들어 오면 기본적으로 "cpu-array"를 "gpu-array"에 매핑합니다.
Juicef

왜 그렇게 불려 졌는지에 대해서는 대답 할 수 없습니다. 컬러, 노멀 등과 같은 다양한 데이터가 있기 때문일 것입니다.
Juicef
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.