Programmiererecke - Farbskalierer, die II.

Mittlerweile sind VDI-Grafiktreiber für Darstellungen mit mehr als 12 Bit Farbtiefe pro Pixel kein unerschwinglicher Traum mehr. Es wird Zeit, über die Zukunft des Farbsystems nachzudenken.

In der Mai-Ausgabe des ST-Magazins stellten wir eine Routine vor, die Farbskalierern helfen sollte, die Farbauflösung der gemappten Farben im verwendeten System zu ermitteln [1]. Zwischenzeitlich hat sich herausgestellt, daß sie aufgrund von VDI-Rundungsfehlern auch manchmal versagen kann.

Die vorgestellte Routine geht grundsätzlich davon aus, daß das VDI, wenn ein »vs_color()«-Aufruf eine Änderung eines Farb-Map-Eintrages beantragt, immer den gewünschten Wert, oder aber den ihm am nächsten stehenden physikalisch realisierbaren Wert einstellt. Wie sich mittlerweile gezeigt hat, ist dem jedoch nicht so. Aufgrund von Rundungsfehlern, die sich dadurch ergeben, daß alle VDIs im Integer-Format rechnen, können die eingestellten Farbwerte um 1 /1001stel verschoben werden. Das ist bislang niemandem aufgefallen, zumal bei nur 16 Farbstufen statistisch gesehen nur bei jedem 1001/16 = 62.56ten VDI-Farbwunsch ein Umbruch zur nächsten physikalisch realisierbaren Farbe stattfindet. Mittlerweile sind jedoch Grafikkarten mit immerhin 256 Farbstufen im Handel und beim Anwender. Hier treten Farbwechsel erheblich häufiger auf, so daß ein Versatz um 1 die Annahme, das VDI würde immer den nächsten von der Hardware realisierbaren Farbwert einstellen, schnell zum Kippen bringt.

Im angesprochenen Beispiel trat dieser Fehler erstmals beim Umbruch der VDI-Farbintensität 47/50 auf. Die Hardware war in der Lage, die VDI-Intensitätsstufen 47 und 50 voneinander zu unterscheiden. Unser Farbskalierer bat nun das VDI darum, die Farbe 49 einzustellen und erwartete, daß es entweder die Farbe 49 selbst, oder den ihr am nächsten stehenden in der Hardware realisierbaren Wert einstellen würde. Das geschah aber nicht. Statt dessen stellte das VDI den Wert 47 ein, der von 49 um 2 verschieden war. Nachdem wir zunächst auf einen Fehler im VDI-Treiber schlossen, steht mittlerweile fest, daß dieses Verhalten den VDI von DRI zumindest gebilligt ist, zumal die veröffentlichte Formel denselben Rundungsfehler aufweist [2].

Es mußte also unser Farbskalierer angepaßt werden. Deshalb stellen wir Ihnen an dieser Stelle einen veränderten Farbskalierer vor, der den Problemen (hoffentlich) endgültig den Garaus macht.

Die calling-conventions haben sich dabei geringfügig geändert. Da es uns ratsam erschien, nicht nur die Anzahl der möglichen Stufen, sondern auch deren exakte Übergänge zu speichern, erwartet die Routine nun einen Zeiger auf ein 1001 x 3 Words langes Array, in dem die Rot- Grün- und Blau-Übergänge separat gespeichert werden. Im vorliegenden Beispiel-Listing wird dieses Array lokal eingerichtet, weshalb darauf geachtet werden sollte, daß auf dem Stack genügend Freiraum zur Verfügung steht, um das knapp 6 KByte große Array aufzunehmen. Ein anderer, etwas einfacherer Weg wäre es, das Array global statisch anzulegen, wodurch der fällige Speicher im BSS reserviert und der Stack nicht damit belastet würde.

Zu beachten ist weiterhin, daß das Array in den »0er«-RGB-Elementen immer die Werte -1 erhält. Das vereinfacht die Abfrage. Wenn der Farbskalierer also 16 Rot-Übergänge meldet, befinden sich deren Schwellenwerte in »rgb_tab[1][0]« bis »rgb_tab[16] [0]«. In »rgb_tab[0][0]« hingegen befindet sich der Wert -1, der natürlich nicht als VDI-Farbintensität zu interpretieren ist, sondern allenfalls darauf aufbauenden Routinen die Arbeit erleichtert.

Mit etwas Geschick können Sie die Skalierroutine auch auf eine dynamische Tabellenverwaltung umstellen, so daß die Tabelle nicht ständig ganze 6 KByte verschlingt.

Es bleibt uns leider nicht erspart, einige Worte über die in der vergangenen Ausgabe des ST-Magazins erschienene Programmiererecke zu verlieren. Kurz nach Redaktionsschluß stellten wir erstaunt fest, daß das dort beschriebene Problem leider noch größeren Ausmaßes ist, als bisher gedacht. Dort schrieben wir, daß »EDITABLE«-Objekte durch ein »Verstecken« mittels des »ob_flags«-Bits »HIDETREE« nicht unsichtbar gemacht werden könnten, sondern das GEM sie vielmehr fröhlich weiterhin verarztet. Zu unserem Erstaunen stellten wir fest, daß dies ebenfalls für Objekte mit dem Status »DEFAULT« gilt, was in komplizierteren Objektstrukturen für allerhand Unruhe sorgen dürfte. Dementsprechend sollten Sie das veröffentlichte Listing um einige Zeilen ergänzen, die auch dieses Problem beseitigen. Als "HIDDEN_DEFAULT«-Bit empfehlen wir das Bit Nr. 14, direkt neben den höchsten Bit in »ob_flags« angesiedelt. Die »# define«-Zeile sollte dementsprechend lauten

*define HIDDEN_DEFAULT 0x4000

Des weiteren sollte nicht unerwähnt bleiben, daß Shifts »Interface« bereits größere Ressourcen als 32 KByte verarbeitet, weil es, im Gegensatz zum offensichtlich fehlerhaften »DRI-RCS«, die RSHDR-Struktur mit »unsigned« WORDs initialisiert und demnach Ressourcen bis 64 KByte verarbeitet. Diese 64-KByteGrenze allerdings ist mit den bestehenden »rsrc_«-Funktionen von GEM nicht mehr zu durchbrechen, weshalb man Ersatzroutinen zum Laden noch größerer Ressourcen benötigt.

Die VDI-Routine »vr_trnfm()« hat uns schon mehrfach beschäftigt. Insbesondere im Zeitalter immer schnellerer, farbenprächtigerer und billigerer Grafikkarten gewinnt sie an Bedeutung, stellt sie doch die einzige legale Möglichkeit dar, schnell auf größere Grafikblöcke zuzugreifen.

»Schnell« ist dabei mehr als relativ zu sehen: Ein True-Color-Bild kann durchaus mehrere Megabytes Pixeldaten enthalten. Das von den Grafikkarten verwendete »Pixel-Packed«-Verfahren hat jedoch weder mit den bisherigen Atari-Geräteformaten noch mit dem GEM-Standardformat für Bit-Blöcke irgendetwas zu tun. Folglich ist »vr_trnfm()« ebenso wie »vro_cpyfm()« eine reichlich gestreßte Funktion. Insbesondere dann wird es haarig, wenn Transformationen auf ein und denselben Speicherbereich laufen müssen: Die Bit-Schieberei wird schier grenzenlos. Deshalb benötigt auch ein TT zum Transformieren eines mit 150 KByte ziemlich kleinen Bildes sehr lange, wenn die Transformation auf denselben Speicherbereich arbeitet. Intelligente Treiber legen deshalb vorsorglich einen Puffer für Bitschiebereien an. So verfügt der Matrix-Farbgrafiktreiber über ein recht schnelles Verfahren zum Umbasteln der Grafikformate, während das Atari-VDI im TT sich schneckenlahm gibt.

Um den Zeitverlust in Grenzen zu halten, sollte deshalb bei allen Transformationen zwei getrennte Speicher zur Verfügung stehen, was dem Rechner ein ständiges »Nachkopieren« erspart. Nachdem uns das dauernde »malloc()«e irgendwann gehörig auf die Nerven ging, schrieben wir die Funktion »vr_convert()«, die als einzige Parameter den Quell-MFDB sowie das gewünschte Format (0 für das gerätespezifische, 1 für das VDI-Bitmap-Standardformat) benötigt. Die Routine versucht eigenständig, einen temporären Zwischenpuffer anzulegen.

Leider gibt es immer noch zu viele Programme, die mit dem zur Verfügung stehenden Speicher raffsüchtig umgehen. Sie werden in einem Multitasking-System entweder allen anderen Prozessen den Speicher wegschnappen, oder aber das Betriebssystem ist von sich aus schlau genug, ihnen nicht den gesamten Speicher zur Verfügung zu stellen.

Auf jeden Fall bietet der Multitasking-Kernel »MiNT«, den Atari in seinem Multitasking-Betriebssystem einsetzt, eine solche Möglichkeit.

Laurenz Prüssner/uw

Literatur:

[1] [L. Prüßner: »Farbenspiele«][1], ST-Magazin 5/Mai 1992, Seiten 50f., Markt&Technik
[2] Digital Research Inc.: »GEM Programmer's Guide«, Volume 1: VDN, DRI 1985.

farbskal.zip



Aus: ST-Magazin 07 / 1992, Seite

Links

Copyright-Bestimmungen: siehe Über diese Seite