2017-09-26 5 views
9

Metal IOS Swift 예제에서 제안하는 3 중 버퍼링 연습을 이해하려고합니다. 이것은 균일 한 애니메이션의 데모 안에 표시됩니다.이 코드는 구조체의 메모리 정렬 크기를 신속하게 어떻게 찾습니까? 바이너리 연산이 필요한 이유는 무엇입니까?

필자는 정렬 된 메모리가 단순히 장치가 실제로 좋아하는 바이트 수의 배수 인 증가량으로 시작한다는 것을 이해합니다. 내 혼란들은 유니폼 구조체의 크기와 바이트를 찾기 위해 사용 코드

// The 256 byte aligned size of our uniform structure 
let alignedUniformsSize = (MemoryLayout<Uniforms>.size & ~0xFF) + 0x100 

의 라인입니다. 나는 이진 연산이 왜 여기에 있는지 혼란 스럽다. 나는 그들이 무엇을하는지에 대해 정말로 확신하지 못한다.

이렇게 정렬 된 크기가 이와 같은 버퍼를 만드는 데 도움이되는 경우. 버퍼가 자동으로 바이트 정렬 메모리를 할당하고 이후 유니폼의 메모리 저장 위치로 사용된다는 것은 확실합니다.

let buffer = self.device.makeBuffer(length:alignedUniformsSize * 3, options:[MTLResourceOptions.storageModeShared]) 

본질적으로 바이트 정렬 메모리를 할당하는 문제를 해결하기보다는 금속이 처리하도록합니다.

let allignedUniformsSize =을했을 때 사용한 전략이 Int 또는 Float 등의 다른 유형에서는 작동하지 않는 이유가 있을까요?

답변

12

버퍼 정렬을 원하는 이유에 대해 먼저 설명하고 비트 연산에 대해 설명 할 수 있습니다.

우리의 목표는 우리 유니폼의 세 (버퍼링 된) 사본을 저장할 수있는 메탈 버퍼를 할당하는 것입니다 (GPU가 다른 곳에서 읽는 동안 버퍼의 한 부분에 쓸 수 있습니다). 이 세 개의 복사본 각각을 읽으려면 버퍼를 바인딩 할 때 오프셋을 제공합니다 (예 : currentBufferIndex * uniformsSize). 특정 금속 장치는 이러한 오프셋을 256의 배수로 요구하므로 대신 currentBufferIndex * alignedUniformsSize을 오프셋으로 사용해야합니다.

정수를 256의 배수 중 가장 큰 배수로 "올림"하는 방법은 무엇입니까? 우리는 "정렬되지 않은"크기의 가장 낮은 8 비트를 버리고 효과적으로 반올림 한 다음 256을 추가하여 다음으로 높은 배수를 얻을 수 있습니다. 반올림 부분은 255의 1의 보수 (~) (32 비트)가 0xFFFFFF00 인 비트 단위 AND 연산에 의해 수행됩니다. 반올림은 0x100을 256으로 추가하는 것만으로 완료됩니다.

흥미롭게도 기본 크기가 이미 정렬 된 경우이 기법은 어쨌든 (예 : 256에서 512로) 반올림됩니다. 정수 나누기 비용 때문에이 낭비를 피할 수 있습니다.

let alignedUniformsSize = ((MemoryLayout<Uniforms>.size + 255)/256) * 256 
+0

정상적인 산술 버전은 훨씬 더 읽기 쉽습니다. – zsero