프레임 버퍼없이 그래픽 데모를 만들려면 어떻게해야합니까?

Aug 18 2020

저는 마이크로 컨트롤러를 프로그래밍하고 있습니다.-약 100Mhz-300Mhz CPU 클럭 속도와 64K 응용 프로그램 RAM (실제로는 ROM)을 가지고 있지만 RAM (6K)의 양이 적지 만 그래픽 프레임 버퍼에 충분하지 않은 작은 8 비트 컴퓨터입니다.

그래서이 컴퓨터에 애니메이션 그래픽 데모를 표시하고 싶습니다. 어떤 종류의 애니메이션 그래픽을 계산하기에 충분한 컴퓨팅 파워를 가지고있는 것 같습니다.

애니메이션 그래픽을 표시하려면 호출 될 때마다 한 이미지 프레임의 픽셀 한 줄을 반환 한 다음 표시되는 컴퓨터 프로그램이 필요합니다. 디스플레이 컨트롤러 프로그램은 전체 프레임을 표시 할 때까지 한 줄씩 호출하고 다음 프레임에 대해 다시 맨 위에서 시작하여이 작업을 계속합니다.

명확하게 말하면 디스플레이를 제어하는 ​​프로그램에 대해 묻는 것이 아닙니다. 데모 프로그램에 대해 묻고 있습니다. 한 번에 한 줄씩 그래픽을 생성하는 데모 프로그램이 필요합니다. 그러면 디스플레이 컨트롤러가 화면에 표시됩니다.

나는 어떤 종류의 그래픽 프로그램이 이런 식으로 작동 할 수 있는지 상상하려고합니다. 아마도 일종의 수학 공식의 표시 일 것입니다.

누구든지 이러한 방식으로 작동하는 그래픽 프로그래밍 기술을 제안 할 수 있습니까? 즉, 요청이있을 때만 프레임의 한 줄을 계산하고 반환하는 함수를 호출 할 수 있습니까? 이와 같이 작동하는 기존 프로그램이 있는지 검토 할 수 있습니까?

질문이 이해되기를 바랍니다. 올바른 방향이나 힌트에 대한 모든 포인터를 주시면 감사하겠습니다.

답변

4 NicolBolas Aug 18 2020 at 22:55

이것은 더 복고풍 하드웨어 의 작동을 보는 것이 합리적 인 경우입니다. 오래된 하드웨어는 메모리와 처리 능력 모두에서 강력한 제한을 가졌습니다. 100 + Mhz 칩은 80 년대 이전의 대부분의 소비자 등급 칩보다 훨씬 빠릅니다. 따라서 이러한 CPU는 렌더링 할 수있는 전용 그래픽 칩이 필요했지만 훨씬 빠른 CPU가 작업을 적절하게 처리 할 수 ​​있습니다.

NES의 타일 맵 및 스프라이트 아키텍처와 같은 것으로 시작하는 것이 좋습니다. 이러한 아키텍처는 픽셀 데이터를 생성하고 예상되는 속도로 디스플레이 장치로 직접 전송하므로 메모리 효율적 (제한된 저장 공간에서 많은 것을 얻음)과 라인 별 출력에서 ​​계산적으로 효율적으로 설계되었습니다. CRT.

광범위한 아이디어는 이것입니다. 타일 ​​맵은 두 부분, 즉 일련의 타일과 생성되는 이미지를 나타내는 타일 맵에 대한 인덱스의 2D 배열로 구성됩니다. 타일은 일반적으로 8x8이고 NES에서는 픽셀 당 2 비트이고 타일은 팔레트를 사용했습니다. 또는 더 구체적으로, 타일 맵에 대한 인덱스에는 타일의 인덱스뿐만 아니라 해당 타일과 함께 사용할 팔레트의 인덱스도 포함됩니다. 따라서 타일은 본질적으로 팔레트와 연관되지 않습니다. 연결은 사용 시점에서 이루어집니다 (기술적으로 NES에서는 타일 맵과 팔레트 맵이 분리되어 있습니다. 타일의 각 2x2 블록은 모두 동일한 팔레트를 사용해야했기 때문입니다).

스크롤을 허용하기 위해 타일 맵은 보이는 화면보다 크고, 보이는 화면의 왼쪽 상단 모서리가 타일 맵 내에있는 위치를 나타내는 오프셋이 있습니다. 이 오프셋을 Xoff및 위치에 둡니다 Yoff.

이것이 어떻게 행 단위 처리를 사소하게 만드는지 알 수 있습니다. 수평 위치 Ypos(화면 공간)에 대한 수평 행을 생성하려면 타일 ​​맵 내에서 시작 픽셀을 가져와야합니다. 이를 위해서는 XY 위치 (0, Ypos)를 화면 공간에서 타일 맵 공간으로 변환해야 합니다. 따라서 (Xoff, Yoff)벡터``Xoff, Yoff + Ypos)` 를 사용하여 벡터를 추가합니다 .

화면 공간에서 타일 맵 공간으로 매핑을 수행 할 때 타일 맵 공간은 X 축과 Y 축 모두에서 둘러싸여 야합니다. 따라서 타일 맵 공간에서 새 픽셀을 계산할 때마다 타일 맵 공간의 크기를 감싸 야합니다.

이제이 타일 맵 픽셀을 두 개의 2D 구성 요소로 분해해야합니다.이 픽셀을 제공하는 타일 맵 내의 타일 인덱스와이 픽셀에 대해 가져와야하는 해당 타일 내의 픽셀입니다. 타일 ​​인덱스는 타일 크기로 정수 나눈 타일 맵 공간 픽셀입니다. 픽셀 좌표는 정수로 인 tilemap 공간 픽셀입니다 modded하게 타일 크기. 8x8 타일 크기가 주어지면 다음을 수행합니다.

ivec2 tilemap_pixel = ...; //Compute the tilemap starting pixel as above.
ivec2 tilemap_tile = ivec2(tilemap_pixel.x & ~0x7, tilemap_pixel.y & ~0x7); //Mask off the lower 3 bits.
ivec2 pixel_in_tile = ivec2(tilemap_pixel.x & 0x7, tilemap_pixel.y & 0x7); //Mask off all but the lower 3 bits.

따라서 tilemap_tile, 현재 작업중인 타일의 인덱스가 있습니다. 그리고 pixel_in_tile우리가 작업중인 픽셀을 제공합니다. 따라서 해당 픽셀의 값을 팔레트에 매핑하여 해당 픽셀의 최종 색상을 생성 할 수있는 해당 픽셀을 가져올 수 있습니다. 또는 직접 사용할 수 있습니다.

다음 픽셀을 얻는 것은 매우 간단합니다. pixel_in_tile.x타일 ​​크기를 모듈로 1 씩 증가시킵니다 . 증분이 타일 크기를 초과하면 타일 tilemap_tile.x맵 크기를 모듈로 1 씩 증분 합니다. 그리고 픽셀 행을 채울 때까지 계속 진행합니다.

이러한 알고리즘의 성능 최적화를위한 많은 기회가 있습니다.

타일은 아마도 가장 큰 데이터를 나타냅니다. 2bpp에서도 8x8 타일의 128 요소 타일 세트는 2K입니다. 그러나 문제는 타일 ​​자체를 변경하지 않기 때문에 ROM에 저장할 수 있다는 것입니다. 타일 ​​맵의 크기 (RAM에 있어야한다고 가정)는 원하는 출력 해상도와 타일 크기에 따라 다릅니다. 320x240 화면을 덮을 수있는 8x8 타일의 타일 맵은 1,200 바이트입니다. 정확히 작지는 않습니다. 부드러운 스크롤 (따라서 더 큰 타일 맵)을위한 공간을 원한다면 더 많은 메모리를 차지해야합니다.

즉, "출력 크기"가 디스플레이 장치 의 실제 크기 일 필요는 없다는 점에 유의하는 것도 중요합니다 . 예를 들어 1080p 디스플레이 장치에 그리려는 경우 8 배 더 작은 240x135와 같은 내부 해상도로 렌더링 할 수 있습니다. 이 알고리즘을 수정하여 기본적으로 동일한 픽셀 값을 연속으로 8 번 생성하고 1080p 라인 당 8 번 동일한 라인을 재사용하는 것은 쉽습니다. 실제로이 알고리즘이 하위 픽셀 스크롤 (135p 공간이 아닌 1080p 공간에서 스크롤)을 허용하고 픽셀 값 사이에 일부 필터링을 추가하는 것은 그리 어렵지 않습니다. 240x135 "출력 크기"타일 맵은 가시 영역에 510 바이트 만 필요하므로 더 큰 스크롤 영역을위한 더 많은 공간이 필요합니다.