Bagaimana saya bisa membuat demo grafik tanpa frame buffer?

Aug 18 2020

Saya memprogram mikrokontroler - komputer 8 bit kecil yang memiliki kecepatan jam CPU sekitar 100Mhz - 300Mhz dan RAM aplikasi 64K (sebenarnya ROM), tetapi hanya sejumlah kecil RAM (6K) - tidak cukup dekat untuk buffer bingkai grafis.

Jadi, saya ingin menampilkan demo grafik animasi di mesin ini. Tampaknya memiliki daya komputasi yang cukup untuk menghitung grafik animasi.

Untuk menampilkan grafik animasi, saya perlu memiliki program komputer yang setiap kali dipanggil, mengembalikan satu baris piksel dari satu bingkai gambar, yang kemudian ditampilkan. Program pengontrol tampilan terus melakukan ini, memanggil baris demi baris hingga telah menampilkan seluruh bingkai, kemudian dimulai lagi dari atas untuk bingkai berikutnya.

Untuk memperjelas, saya tidak bertanya tentang program yang mengontrol tampilan. Saya bertanya tentang program demo. Saya memerlukan program demo yang menghasilkan grafiknya satu baris pada satu waktu, yang kemudian akan ditampilkan oleh pengontrol tampilan saya ke layar.

Saya mencoba membayangkan program grafik seperti apa yang bisa bekerja seperti ini? Agaknya tampilan semacam rumus matematika.

Adakah yang bisa menyarankan teknik untuk pemrograman grafis yang bekerja dengan cara ini, di mana suatu fungsi dapat dipanggil, yang menghitung dan mengembalikan garis bingkai, hanya jika diminta untuk melakukannya? Apakah ada program yang bekerja seperti ini yang dapat saya periksa?

Saya harap pertanyaannya masuk akal. Setiap petunjuk ke arah yang benar atau petunjuk akan dihargai.

Jawaban

4 NicolBolas Aug 18 2020 at 22:55

Ini adalah kasus di mana melihat cara kerja perangkat keras retro lebih masuk akal. Perangkat keras yang lebih lama memiliki batasan yang kuat pada memori dan daya pemrosesan. Chip 100 + Mhz Anda jauh lebih cepat daripada kebanyakan chip tingkat konsumen tahun 80-an dan sebelumnya. Jadi sementara CPU tersebut membutuhkan chip grafis khusus untuk dapat merender, CPU Anda yang jauh lebih cepat mungkin dapat menangani tugas tersebut dengan memadai.

Saya akan menyarankan untuk memulai dengan sesuatu seperti arsitektur tilemap-and-sprite NES. Arsitektur ini dirancang untuk menjadi efisien memori (mendapatkan banyak dari ruang penyimpanan terbatas) dan efisien secara komputasi dalam output baris demi baris, karena mereka menghasilkan data piksel dan mengirimkannya langsung ke perangkat tampilan dengan kecepatan yang diharapkan dari CRT.

Gagasan luasnya adalah ini. Peta ubin terdiri dari dua bagian: serangkaian petak dan larik indeks 2D ke dalam peta petak yang mewakili gambar yang sedang dibuat. Ubin biasanya berukuran 8x8, dan pada SEN adalah 2-bit-per-piksel dan ubin menggunakan palet. Atau lebih khusus lagi, indeks ke dalam peta petak tidak hanya mencakup indeks petak tetapi juga indeks palet yang akan digunakan dengan petak itu. Jadi ubin tidak secara inheren terkait dengan palet; pengaitan dibuat di titik penggunaan (secara teknis, pada SEN, peta ubin dan peta palet dipisahkan, karena setiap blok ubin 2x2 semuanya harus menggunakan palet yang sama).

Untuk memungkinkan pengguliran, peta ubin lebih besar dari layar yang terlihat, dan ada offset yang menunjukkan di mana sudut kiri atas layar yang terlihat berada di dalam peta til. Biarkan offset ini berada pada posisi Xoffdan Yoff.

Anda dapat melihat bagaimana hal ini membuat pemrosesan baris demi baris menjadi sepele. Untuk menghasilkan baris horizontal untuk posisi horizontal Ypos(dalam ruang-layar), Anda perlu mendapatkan piksel awal dalam peta til. Itu membutuhkan perubahan posisi XY (0, Ypos)dari screen-space ke tilemap space. Jadi Anda menambahkan vektor (Xoff, Yoff), memegang vektor `` Xoff, Yoff + Ypos) `.

Perhatikan bahwa ketika melakukan pemetaan dari screen-space ke tilemap space, ruang tilemap harus melingkari sumbu X dan Y. Jadi, setiap kali Anda menghitung piksel baru dalam ruang tilemap, Anda harus membungkusnya dengan ukuran ruang tilemap.

Sekarang, kita perlu memecah piksel tilemap ini menjadi dua komponen 2D: indeks petak di dalam peta tilem yang memberi kita piksel ini, dan piksel di dalam petak itu yang perlu kita ambil untuk piksel ini. Indeks petak hanyalah bilangan bulat piksel tilemap-space-dibagi dengan ukuran petak. Pixel koordinat pixel tilemap-ruang integer- modded oleh ukuran tile. Diberikan ukuran ubin 8x8, Anda melakukan ini:

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.

Jadi diberikan tilemap_tile, kita sekarang memiliki indeks ubin yang sedang kita kerjakan. Dan pixel_in_tilememberi kita piksel tempat kita bekerja. Jadi kita bisa mengambil piksel itu, yang nilainya bisa dipetakan ke dalam palet untuk menghasilkan warna akhir untuk piksel itu. Atau kita bisa menggunakannya secara langsung.

Untuk mendapatkan piksel berikutnya cukup sepele. Kami hanya menambah pixel_in_tile.x1, modulo ukuran ubin. Jika selisih melebihi ukuran tilemap_tile.xpetak , maka kami juga menambah sebesar 1, modulo ukuran peta til. Dan Anda terus melakukannya sampai Anda mengisi baris piksel.

Ada banyak peluang untuk pengoptimalan kinerja dari algoritme semacam itu.

Ubin mungkin mewakili data terbesar. Satu set ubin elemen 128 dari ubin 8x8, bahkan pada 2bpp, adalah 2K. Tapi masalahnya, itu bisa disimpan di ROM , karena Anda mungkin tidak mengubah ubin itu sendiri. Ukuran peta petak (dengan asumsi itu harus dalam RAM) bergantung pada resolusi keluaran yang diinginkan dan ukuran petak. Peta ubin untuk ubin 8x8 yang dapat menutupi layar 320x240 berukuran 1.200 byte. Tidak terlalu kecil. Anda harus menggunakan lebih banyak memori jika Anda menginginkan ruang untuk pengguliran yang mulus (dan dengan demikian peta petak yang lebih besar).

Karena itu, penting juga untuk diperhatikan bahwa "ukuran keluaran" tidak harus menjadi ukuran sebenarnya dari perangkat tampilan . Misalnya, jika Anda ingin menggambar perangkat dengan layar 1080p, Anda masih dapat merender ke resolusi internal yang, misalnya, 8 kali lebih kecil, 240x135. Sangat mudah untuk memodifikasi algoritme ini untuk menghasilkan nilai piksel yang sama 8 kali berturut-turut, serta menggunakan kembali baris yang sama 8 kali per baris 1080p. Memang, tidak akan terlalu sulit untuk memiliki algoritma ini yang memungkinkan subpixel scrolling (scrolling dalam ruang 1080p, bukan ruang 135p) dan bahkan menambahkan beberapa pemfilteran di antara nilai piksel. Tilemap "ukuran keluaran" 240x135 hanya akan membutuhkan 510 byte untuk wilayah yang terlihat, jadi Anda akan memiliki lebih banyak ruang untuk area pengguliran yang lebih besar.