묶음의 미학, 바인드 그룹

92025년 08월 07일4

새로운 언어, WGSL의 탄생을 자축하는 것도 잠시, NXT 팀은 곧바로 다음 허들에 부딪혔다. 견고한 ‘파이프라인’이라는 구조물은 세워졌지만, 그것은 아직 텅 빈 기계에 불과했다.

카이가 날카롭게 핵심을 찔렀다.
“파이프라인은 렌더링의 ‘방법’을 정의합니다. 하지만 ‘무엇을’ 렌더링할지에 대한 정보, 즉 데이터는 어떻게 전달해야 할까요? 3D 모델의 정점 정보, 표면에 입힐 텍스처, 카메라의 위치를 담은 행렬… 이 모든 데이터를 파이프라인에 어떻게 효율적으로 연결할 수 있습니까?”

그의 질문에 연구실의 공기가 다시 진지해졌다. 모두의 머릿속에 WebGL 시절의 악몽이 떠올랐다.

벤이 읊조렸다.
“WebGL에서는… 끔찍했죠. gl.uniformMatrix4fv로 행렬을 보내고, gl.bindBuffer로 정점 버퍼를 연결하고, gl.activeTexturegl.bindTexture로 텍스처를 설정하고… 객체 하나를 그리기 위해 수십 개의 함수를 순서대로 호출해야 했습니다.”

그것은 단순한 번거로움의 문제가 아니었다. 각각의 함수 호출은 CPU가 드라이버를 통해 GPU의 상태를 변경하는 과정이었다. 수많은 작은 호출들이 모여 거대한 CPU 오버헤드를 만들어냈다. 파이프라인을 도입해 렌더링 상태 설정의 부담을 줄였지만, 데이터를 전달하는 과정이 예전과 같다면 개선 효과는 반감될 수밖에 없었다.

드미트리는 조용히 듣고 있다가 입을 열었다.
“우리는 데이터를 하나씩 흩뿌리는 방식을 버려야 합니다. 대신, 필요한 모든 자원을 미리 하나의 ‘묶음’으로 만들어 전달해야 합니다.”

그는 화이트보드에 ‘Pipeline’ 옆에 새로운 상자를 그렸다.

“파이프라인은 어떤 종류의 자원을 필요로 하는지 스스로 알고 있어야 합니다. 예를 들어, ‘이 파이프라인은 0번 슬롯에 카메라 정보가 담긴 버퍼가 필요하고, 1번 슬롯에는 물체 표면을 위한 텍스처가 필요하다’는 식으로요. 이 약속, 이 자원들의 배치도를 우리는 ‘Bind Group Layout’이라고 부를 겁니다.”

그는 BindGroupLayout이라는 단어를 적었다.
“이 Layout은 파이프라인을 만들 때 함께 정의됩니다. 즉, 파이프라인은 태어날 때부터 자신이 어떤 데이터 구조를 필요로 하는지 명확히 알고 있는 거죠. 여기서도 ‘사전 정의’와 ‘불변’의 원칙이 적용됩니다.”

팀원들은 숨을 죽이고 그의 다음 말을 기다렸다.

“그다음, 실제 렌더링을 할 때가 되면, 우리는 이 Layout에 맞춰 실제 자원들—실제 버퍼와 실제 텍스처—을 담은 객체를 만듭니다. 이것이 바로 ‘Bind Group’입니다.”

드미트리는 BindGroup이라고 적고, 화살표로 BindGroupLayout과 연결했다.

“이제 Command Encoder에게 내릴 명령은 극도로 단순해집니다. encoder.setPipeline(myPipeline)을 호출한 뒤, 딱 한 줄만 더 추가하면 됩니다. encoder.setBindGroup(0, myObjectDataGroup). 이걸로 끝입니다.”

그 말이 떨어지는 순간, 연구실에는 짜릿한 전율이 흘렀다.
수십 개의 gl.uniform*, gl.bind* 함수 호출이 단 하나의 setBindGroup 호출로 압축되는 마법.

카이가 탄성을 터뜨렸다.
“이해했습니다. 드라이버는 Bind Group Layout을 통해 자원의 유효성을 미리 검증하고 최적화할 수 있습니다. 그리고 런타임에는 그저 잘 포장된 데이터 묶음(Bind Group)의 주소만 넘겨주면 되는군요. CPU는 더 이상 자잘한 심부름에 시달릴 필요가 없어지는 겁니다.”

이것은 단순히 코드를 줄이는 차원이 아니었다. 파이프라인이 ‘어떻게 그릴 것인가’를 정의한다면, 바인드 그룹은 ‘무엇을 가지고 그릴 것인가’를 정의했다. 이 둘의 명확한 분리와 효율적인 결합. 이것이 바로 NXT가 추구하는 성능의 핵심이었다.

이제 개발자는 더 이상 렌더링 루프 안에서 상태를 바꾸고 데이터를 하나씩 주입하는 고통스러운 작업을 반복할 필요가 없었다. 대신 잘 설계된 파이프라인들과, 그에 맞는 데이터 묶음들을 미리 준비해두었다가, 필요할 때마다 레고 블록처럼 간단히 결합하기만 하면 되었다.

NXT의 구조가 비로소 완전한 형태를 갖추기 시작했다.
AdapterDevice로 GPU의 문을 열고, PipelineBindGroup으로 렌더링의 설계도를 완성하며, Command Buffer에 그 모든 명령을 담아 Queue에 던진다.

드미트리는 화이트보드에 그려진 다이어그램을 만족스럽게 바라보았다. 이것은 단순한 API가 아니었다. CPU와 GPU가 가장 효율적으로 협업할 수 있도록 설계된, 웹 그래픽을 위한 현대적인 공장 자동화 시스템이었다. 이제 남은 것은 이 공장을 실제로 가동시키는 일뿐이었다. 길고 긴 구현의 여정이 그들을 기다리고 있었다.