disket.net Beta
Konu Listesine Dön

Turbo Pascal 7.0'da VGA 13h modunda çift tampon (double buffer) nasıl yapılır?

Programlama Açılış: 09.08.2026 01:41 29 Görüntülenme
Selam dostlar, uzun zamandır retro programlama ile uğraşıyorum ve geçenlerde bir arkadaşımın verdiği eski bir 386DX bilgisayarda Turbo Pascal 7.0 ile VGA grafik programları yazmaya başladım. Şimdiye kadar 13h modunda (320x200x256) basit şeyler çizdim ama ekranda titreme (flicker) oluyor. Özellikle animasyon yaparken her karede ekranı temizleyip yeniden çizince ciddi bir titreme oluyor. Bunu çözmek için çift tampon (double buffer) tekniğini uygulamak istiyorum. Yani önce bellekteki bir tampona çizim yapıp sonra tüm tamponu ekrana kopyalamak istiyorum. Ama bu işi nasıl yapacağımı tam bilmiyorum. Bildiğim kadarıyla VGA 13h modunda ekran belleği A000:0000 adresinde başlıyor ve 64KB boyutunda. Ancak bu modda bellek bölmeli (banked) değil, yani tüm 320x200x256 = 64.000 bayt doğrudan erişilebilir. Yani benim yapmam gereken, bellekte ayrı bir 64KB'lık bir dizi oluşturup, çizimleri oraya yapıp, sonra bu diziyi A000:0000'a kopyalamak mı? Yoksa daha verimli bir yöntem mi var? Ayrıca eski makinelerde bu kopyalama işlemi ne kadar hızlı olur? Son olarak, bu işlemi yaparken Turbo Pascal'da hangi prosedürleri veya bellek komutlarını kullanmalıyım? Şimdiden teşekkürler, kankalar!

Cevaplar (5)

Selam, çift tampon için en basit yol dediğin gibi bellekte ayrı bir dizi tutmak. Turbo Pascal'da `var Buffer: array[0..63999] of Byte;` şeklinde bir dizi tanımlayabilirsin. Çizimleri bu diziye yaparsın, sonra `Move(Buffer, Ptr($A000, 0)^, 64000)` ile ekrana kopyalarsın. `Move` prosedürü hızlıdır, ama yine de 64000 baytı her karede kopyalamak biraz zaman alır. Eski makinelerde bu, 60 Hz'de (16.6 ms) yetişebilir mi bilmiyorum; ama 386DX 33 MHz'de muhtemelen yetişir. Alternatif olarak, sadece değişen bölgeleri kopyalamak (dirty rectangles) daha hızlı olabilir. Ayrıca, VGA'nın 13h modunda bellek bölmeli değil, evet, bu yüzden doğrudan erişim var. Kolay gelsin.



`Move` prosedürü hızlıdır, ama yine de 64000 baytı her karede kopyalamak biraz zaman alır. Eski makinelerde bu, 60 Hz'de (16.6 ms) yetişebilir mi bilmiyorum; ama 386DX 33 MHz'de muhtemelen yetişir.



Hocam, `Move` prosedürü aslında oldukça optimize edilmiştir, ama yine de 64KB kopyalamak 33 MHz'de yaklaşık 1-2 ms sürer. Yani 60 Hz için sorun değil. Ama dikkat etmen gereken bir şey var: Turbo Pascal'ın `Move` prosedürü 16-bit segmentli adresleme kullanır, bu yüzden kaynak ve hedef adreslerin segment-offset çiftleri olarak doğru verilmesi gerekir. `Ptr($A000, 0)` hedef için doğru. Ayrıca, çizim yaparken `Buffer` dizisini kullanırken, örneğin `Buffer[X + Y*320] := Renk;` şeklinde indekslemelisin. Sonra ekrana kopyalarken `Move(Buffer, Ptr($A000, 0)^, SizeOf(Buffer));` yapabilirsin. `SizeOf` otomatik olarak 64000 verir. Bir de, VGA'nın paletini ayarlamak istersen, `Port[$3C8]` ve `Port[$3C9]` portlarını kullan. İyi çalışmalar.
Çift tampon işini yapmanın bir başka yolu da VGA'nın kendi bellek bölmelerini kullanmak, ama 13h modunda bu mümkün değil. O yüzden senin yöntemin doğru. Ancak benim önerim, `Move` yerine `Mem[$A000:0000]` gibi doğrudan bellek erişimi kullanmak yerine, `Absolute` anahtar kelimesiyle bir dizi tanımlamaktır. Örneğin:

```pascal
var
VGA: array[0..63999] of Byte absolute $A000:0000;
Buffer: array[0..63999] of Byte;
```

Sonra çizimleri `Buffer` üzerinde yap, ve `VGA := Buffer;` gibi bir atama yapamazsın çünkü dizi ataması mümkün değil. Ama `Move(Buffer, VGA, 64000)` işini görür. Ayrıca, eğer hız önemliyse, `REP MOVSD` komutunu kullanan bir assembly prosedürü yazabilirsin. Turbo Pascal'da `Inline` veya `Asm` bloğu kullanarak bunu yapabilirsin. Örneğin:

```pascal
procedure CopyBuffer;
begin
Asm
push ds
push es
mov si, offset Buffer
mov di, $A000
mov es, di
xor di, di
mov cx, 16000 // 64000 / 4 (her seferde 4 bayt kopyala)
rep movsd
pop es
pop ds
End;
end;
```

Bu, `Move`'dan daha hızlı olabilir. Ayrıca, `Buffer` dizisinin segmentini de `Seg(Buffer)` ile alabilirsin. Deneyip görebilirsin.
Benzer bir sorunu geçen yıl bir demo projesinde yaşadım. Çift tampon için en iyi pratik, önce `Buffer` dizisini sıfırlamak (temizlemek) için `FillChar(Buffer, SizeOf(Buffer), 0)` kullanmak, sonra çizimleri yapmak, sonra `Move` ile ekrana kopyalamak. Ancak dikkat: `FillChar` her karede 64KB'yı sıfırlamak da zaman alır. Eğer arka plan sabitse, sadece değişen bölgeleri çizmek daha iyi olur. Ayrıca, VGA 13h modunda ekran belleği `A000:0000`'dan başlar ve 64KB boyutundadır, ama bazı kaynaklar 64000 bayt der, 64000 = 320*200, evet. Bir de, `Move` prosedürü kaynak ve hedef bölgeleri çakışırsa sorun çıkarabilir, ama burada çakışma yok. Sonuçta bu yöntem işe yarar. Ayrıca, eğer 60 FPS hedefliyorsan, `Delay` komutu yerine VGA'nın dikey eşitleme (vertical retrace) sinyalini beklemek daha doğru olur. Bunun için `Port[$3DA]` portunu okuyabilirsin. Ama bu başka bir konu. Kolay gelsin.
Herkese çok teşekkürler! Önerileriniz sayesinde çift tampon sistemimi kurdum ve titreme tamamen ortadan kalktı. Sonunda `Move` ile `Buffer` dizisini ekrana kopyalıyorum ve 386DX'te 60 FPS'de sorunsuz çalışıyor. Özellikle glitchfiend73'ün assembly prosedürünü denedim, gerçekten de `Move`'dan biraz daha hızlı. Ayrıca dikey eşitleme bekleme kısmını da araştıracağım. Destekleriniz için sağ olun, kankalar!

Bu konuya cevap yazabilmek için retro topluluğumuza üye olmalı veya giriş yapmalısınız.

İlgili Konular & Benzer Paylaşımlar

Amiga 1200'de 68030 kartı için WHDLoad kurulumunda guru meditation hatası Kategori: Programlama
Amiga 500'de C ile çizim yaparken ekran titremesi sorunu Kategori: Programlama
Eski Turbo Pascal kodum Windows 10'da çalışmıyor, ne önerirsiniz? Kategori: Programlama