https://learn.microsoft.com/en-us/windows/win32/medfound/image-stride
이미지(비디오 포함)가 메모리에 저장될 때, 메모리 버퍼에는 각 행(row)마다 여분의 패딩(padding) 바이트가 포함될 수도 있다. 패딩 바이트는 이미지가 메모리에 어떻게 저장되는지에 영향을 주지만, 이미지가 화면에 표시되는 형태에는 영향을 주지 않는다.
이미지는 테이블 형태(2차원 배열)로 저장된 픽셀이라고 생각할 수 있다. 이때, 스트라이트(stride)는 한 행의 시작지점에서 다음 행의 시작 지점까지의 바이트의 크기가 된다. 스트라이드는 피치(pitch)라고 부르기도 한다. 만약 패딩 바이트가 있다면 스트라이드는 이미지의 너비보다 클 것이고, 패딩이 없다면 스트라이드는 이미지의 너비와 같아질 것이다.
따라서 이미지를 저장하는 과정에서 필요한 바이트는 이미지의 순수한 너비와 높이의 곱이 아니라, 패딩이 포함된 스트라이드와 높이의 곱이 된다. 예를 들어 하나의 픽셀은 RGBA 4바이트의 크기를 가지고 있고, 이미지의 크기가 3 * 3이라고 한다면 이미지 저장에 필요한 저장 공간은 3 * 3 * 4가 아니다. 이미지 저장을 위해 1바이트의 패딩이 추가적으로 필요하다고 한다면 하나의 행을 저장하기 위해서 13 바이트가 필요하게 된다. 따라서 13 * 4인 52 바이트가 필요하게 된다.
이미지 저장을 위해 추가적인 메모리 공간(패딩)을 할당하는 이유는 CPU에서 보다 빠른 속도로 데이터를 가져오게 하기 위함이다. 그러나 이미지에 패딩을 추가하는 작업은 컴퓨터에서 자동으로 최적화를 진행해주는 것이 아닌, 이미지를 저장하는 사람 임의로 지정하는 부분이기 때문에 이미지를 다루는 작업을 진행할 때에는 스트라이드를 항상 염두해 두어야 한다. 다음은 DirectX에서 GPU에 있는 텍스처 이미지를 불러와 파일로 저장하는 코드의 일부이다.
// staging 텍스처 ComPtr<ID3D11Texture2D> stagingTexture; // staging 텍스처 초기화 작업 // ... // R8G8B8A8 이라고 가정 std::vector<uint8_t> pixels(desc.Width * desc.Height * 4); D3D11_MAPPED_SUBRESOURCE ms; context->Map(stagingTexture.Get(), NULL, D3D11_MAP_READ, NULL, &ms); // D3D11_MAP_READ 주의 // ms에 staging 텍스처의 픽셀을 스트라이드(RowPitch) 단위로 복사함 uint8_t *pData = (uint8_t *)ms.pData; for (unsigned int h = 0; h < desc.Height; h++) { memcpy(&pixels[h * desc.Width * 4], &pData[h * ms.RowPitch], desc.Width * sizeof(uint8_t) * 4); } context->Unmap(stagingTexture.Get(), NULL);
위의 코드를 보면 텍스처로부터 데이터를 복사할 때, 실제 이미지의 너비에 해당하는 크기로 복사하는 것이 아니라 RowPitch라고 정의된 서브 리소스의 프로퍼티 단위로 복사하는 것을 알 수 있다. RowPitch는 이미지 스트라이드를 의미한다. 만약 RowPitch가 아닌 이미지의 너비 단위로 데이터를 복사했다면, 패딩이 있는 경우에는 패딩을 복사하는 동작이 실행될 것이다.
'그래픽스' 카테고리의 다른 글
컨텍스트(Context) (0) | 2024.09.11 |
---|---|
1인칭 시점(First Person View) 구현하기 (1) | 2024.06.10 |
yaw, pitch, roll (0) | 2024.06.09 |
림(rim) 효과 (0) | 2024.06.03 |
퐁(Phong) 반사 (0) | 2024.06.01 |