Stan grafiki w Linuksie


Wstęp

Po zaprzestaniu prac nad Xgl otrzymałem wiele listów i przeczytałem sporo wypowiedzi. Wywnioskowałem z nich, że większość nie wie jak naprawdę wygląda stan grafiki w Linuksie. Łatwo zrozumieć, czemu ludzie nie mają pełnego obrazu. Grafika to duży i złożony obszar, wypełniony wieloma komponentami programistycznymi i konkurującymi ze sobą grupami twórców. Napisałem ten artykuł jako próbę wyjaśnienia, jak te wszystkie części mają się do siebie nawzajem.

Historia

W tym roku serwer X obchodzi swoje 21. urodziny. Środowisko X jest powszechnie używane i napędza większość obecnych linuksowych biurek. Artykuł w Wikipedii dostarcza znacznie więcej szczegółów, ale ogólnie mówiąc dwie największe innowacje w X-ach są projektami Open Source, co pozwoliło na obsługę wielu platform oraz na przeźroczystą obsługę sieci.

A jednak od zaprojektowania X-ów minęło 20 lat i przez ten czas zmienił się sprzęt. Jeśli przyjrzeć się architekturze współczesnego układu grafiki, to widać tam małą sekcję oznaczoną 2D. To dlatego, że 90% kości jest przeznaczone do obsługi 3D. Skoro już płacimy za ten sprzęt do 3D, to byłoby miło gdyby biurko z niego korzystało. Wiele ludzi nie zdaje sobie sprawy, że taki sprzęt potrafi wyświetlać grafikę dwuwymiarową. Spójrz na swój ekran, ma płaską powierzchnię, prawda? Dowolny obraz wygenerowany przez sprzęt 3D jest i tak wyświetlany na płaskim ekranie 2D. To powinno prowadzić do wniosku, że przy pomocy odpowiedniego oprogramowania sprzęt 3D może wyświetlać płaskie obrazy.

Producenci sprzętu

Dawnymi laty producenci układów graficznych szczycili się udostępnianiem danych technicznych i informacji programistycznych o swoim sprzęcie. Ale im bardziej rosły biblioteki patentów, tym bardziej rósł też lęk przed pozwami o ich naruszenie. W tej chwili producenci ukrywają wszystkie te informacje aby utrudnić posiadaczom patentów ujawnienie takich przypadków. Przynajmniej tym tłumaczą ukrywanie specyfikacji technicznej. Twierdzą też, że utrudnia to rozgryzanie budowy układu przez konkurencję, ale w to także wątpię. Wszystkie te utajnione specyfikacje bardzo utrudniają pisanie otwartych sterowników do tych kości. W zamian jesteśmy zmuszani do polegania na sterownikach do najnowszego sprzętu dostarczanych przez producentów. Na wypadek gdyby ktoś tego nie zauważył, producenci dbają tylko o MS Windows, więc wkładają minimum wysiłku w sterowniki dla Linuksa. Zdarzają się wyjątki. Intel zapewnia otwarte sterowniki dla niektórych swoich układów. Nvidia/ATI dostarczają własnościowe sterowniki, ale są one opóźnione w stosunku do wersji dla Windows. Końcowy efekt to bardzo szeroki wachlarz, od sterowników o przyzwoitej jakości do zupełnego ich braku.

Inne systemy graficzne

Inne systemy biurkowe, Windows
i Mac, używają akceleracji grafiki. Są one w oczywisty i widoczny sposób lepsze od swoich poprzedników. W niektórych przypadkach te nowe systemy potrafią wyświetlać grafikę ponad stukrotnie szybciej niż starsze wersje. W pewnym punkcie w przyszłości producenci kości graficznych zamierzają usunąć elementy 2D i zostawić nas tylko ze sprzętem 3D. Wydaje się, że do Microsoftu i Apple już dotarło, że 3D jest przyszłą ścieżką rozwoju, i właśnie dokonują migracji. Z drugiej strony niektórzy twórcy X-ów chcą żebym przestał opowiadać o konkurencji. Mówią, że chcą jedynie ulepszać X-y. Chociaż może ich to nie obchodzić, to jestem pewien, że kierownictwo Red Hata czy Novella nie zgodzi się z nimi, gdy tylko z powodu niekonkurencyjnego interfejsu graficznego zacznie im spadać sprzedaż.

Używanie 3D do grafiki biurkowej to nie tylko kwestia atrakcyjnych efektów wizualnych. Wiele z nich może być tylko błyskotkami, ale istnieją także istotne przyczyny aby korzystać z 3D. 3D jest po prostu szybsze niż 2D, bo nikt już nie optymalizuje wydajności funkcji 2D, cała inżynieria układu przechodzi na 3D. W ten sposób możliwe jest dokonywanie szybkiej, swobodnej obróbki obrazu, jak choćby konwersji przestrzeni barwnej, rozciągania/wyginania itp. Widziałem niezwykle złożone filtrowanie wykonywane przez sprzętowy shader w czasie rzeczywistym, które na zwykłym procesorze wymagałoby kilku sekund na każdą klatkę. Możliwa jest obsługa okien o różnej głębi koloru (jednocześnie 8-, 16- i 24-bitowej) z dowolnymi zestawami kolorów. Przełączanie/obrót ekranu w locie dla projektorów oraz skalowanie całego ekranu dla osób z wadami wzroku itp. Niezależność od rozdzielczości pozwala na wyświetlanie obiektów o dowolnej rozdzielczości i rozmiarach, resamplowanych w górę i w dół w trakcie projekcji na ekranie. Więcej interesujących możliwości zostało opisane w dalszej części tekstu, dotyczącej okienek.

Obecny serwer X.org

X.org planuje opublikować
X11R7. Głównym celem tej wersji jest modularyzacja kodu źródłowego X-ów. Choć modularyzacja dla większości użytkowników nie ma żadnego znaczenia, to znacznie uprości pracę nad tym kodem. Do tej pory kod źródłówy X-ów składał się z około 16 milionów wierszy tworzących jeden projekt. Po modularyzacji zostanie on podzielony na wiele niezależnych fragmentów, co bardzo ułatwi budowanie i zwiększy jego czytelność.

X jako system operacyjny

Czy X-y to aplikacja czy system operacyjny? Dobre wyjaśnienie budowy serwera X jest podane tu,
i chociaż ma ono już 8 lat, to w większości jest nadal aktualne. Przeczytaj je jeśli nie wiesz co znaczy DIX, mi, DDX, CFB itp. Gdzieś w okolicach wersji X11R6.3 wydzieliło się Xfree86 i architektura serwera X stała się niezwykle przenośna. Rożne systemy operacyjne na których działały X-y miały różny poziom obsługi na przykład wykrywania sprzętu. Aby rozwiązać ten problem w X-ach pojawił się kod badający szynę PCI w poszukiwaniu sprzętu, kod wyszukujący ROM grafiki i uruchamiający go aby zresetować ustawienia, wyszukujący myszkę oraz klawiaturę i zapewniający im sterowniki, zarządzający kwestią wielu kart VGA, wreszcie odpowiadający za samodzielne ładowanie modułów. Na tym etapie zaczęła się zacierać granica między byciem aplikacją a systemem operacyjnym. Podczas gdy niektóre środowiska rozpaczliwie wymagały takiego wsparcia niemal na poziomie systemu operacyjnego, to implementacja tych funkcji w systemach, które same zapewniały takie usługi, jak choćby Linux, doprowadziła w końcu do obecnych konfliktów między X-ami a systemem operacyjnym. Oczywiście systemy operacyjne to ruchomy cel i decyzje, które miały sens dziesięć lat temu, dziś mogą już go nie mieć.

Jądro Linuksa zapewnia podsystemy w rodzaju PCI i bufora ramki (framebuffer), których nie ma w BSD i na niektórych innych platformach. W celu obsługi wielu platform serwer X dorobił się równoległych implementacji tych podsystemów. W przeszłości była taka potrzeba, ale na obecnych systemach linuksowych powoduje to, że dwa różne fragmenty oprogramowania starają się sterować tym samym sprzętem. Linux ma wielu użytkowników kart graficznych, dla których jedynym punktem stycznym z X-ami jest jądro. Jądro zapewnia im wiele mechanizmów koordynacji, na przykład podsystem PCI, sterowniki urządzeń wejściowych, obsługę urządzeń hotplug oraz sterowniki. Najlepszym wyjściem na rzecz koordynacji w Linuksie jest wykorzystanie usług jądra i używanie tych zduplikowanych bibliotek tylko na innych platformach. Fbdev i XAA są najbardziej wyraźnymi przykładami takich zduplikowanych sterowników.

Linux ma znakomitą obsługę urządzeń typu hotplug i system grafiki naprawdę powinien zacząć z niej korzystać. Ekrany mogą być podłączane w różny sposób. Tradycyjnym sposobem jest kiedy ktoś wkłada nową kartę graficzną do maszyny z obsługą hotplugu. Ale są też inne, niestandardowe sposoby. Inny użytkownik może używać ekranu, który chcemy dołączyć do swojej grupy ekranów, i powstanie hotplug gdy tylko się z niego wyloguje. Można wygenerować hotplug przez podłączenie do laptopa zewnętrznego monitora. Można połączyć się bezprzewodowo do ściany wideo z czymś takim jak DMX albo Chromium. USB jest również obfitym źródłem hotplugów. Użytkownik może na gorąco podłączać myszki, tablety, klawiatury, urządzenia dźwiękowe a nawet karty grafiki. Obecny serwer X tego nie obsługuje, ponieważ nie komunikuje się z podsystemem hotplug w jądrze.

Standardowe biurko pod Linuksem używa "zamocowanych" (rooted) X-ów. To znaczy, że X-y kontrolują wyświetlanie warstwy grafiki najwyższego poziomu oraz znajdujących się na niej okienek. Cygwin/X, Directfb oraz Apple Darwin używają X-ów "niezamocowanych" (rootless). Te środowiska mają inny system okienek zajmujący się wyświetlaniem. Systemy te wyświetlają główną warstwę grafiki i mają własne okienkowe API. X-y mogą być zintegrowane z takim systemem działając właśnie w trybie niezamocowanym. W takim trybie okna aplikacji X są synchronizowane z głównym systemem okienek i wyświetlana jest ich zawartość. Niezamocowane X-y zapewniają też protokoły przekazywania zdarzeń myszy i klawiatury między tymi dwoma środowiskami.

X Render

Rozszerzenie X Render. W 2000 roku KeithP oświadczył, że istniejący serwer X jest niezdolny do wydajnego wyświetlania czytelnego, wygładzanego tekstu, i aby rozwiązać ten problem doszedł do rozszerzenia X Render. X Render to podstawowa funkcja X-ów umożliwiająca takie rzeczy jak ładne fonty czy implementacja cairo w serwerze X. X Render wprowadza do serwera X operatory Portera-Duffa. Te operatory pozwalają na różne operacje na powierzchniach. Są one bardzo podobne do koncepcji tekstur i operacji na teksturach w OpenGL, ale tylko podobne i nie odpowiadają im bezpośrednio.

XAA

XAA,
X Acceleration Architecture, pojawiła się w XFree86 4.0. Aby osiągnąć przenośność między platformami, XAA implementuje sterowniki obrazu 2D w przestrzeni użytkownika, bez korzystania ze sterowników jądra. Sterowniki w przestrzeni użytkownika działają, ale ponieważ nie ma sterowników jądra, to jądro nie może śledzić co X-y robią ze sprzętem. X-y nie wstają zanim system w pełni się nie załaduje. Chcielibyśmy mieć działający ekran na wypadek gdyby coś poszło nie tak przy starcie X-ów, prawda? Ekran podczas ładowania systemu jest obsługiwany przez sterowniki trybu tekstowego (konsoli), z których najpopularniejszy jest VGAcon. Tak więc pod Linuksem mamy w efekcie dwa sterowniki graficzne, X-ów i konsoli, i oba próbują kontrolować ten sam kawałek sprzętu. Kombinacja XAA, konsoli i funkcji wirtualnych terminali w jądrze Linuksa może wywołać mnóstwo konfliktów, ale więcej o tym będzie dalej.

EXA

EXA zastępuje istniejące sterowniki 2D XAA, pozwalając działać obecnemu modelowi serwera nieco dłużej. EXA rozwija ideę XAA poprzez użycie sprzętu 3D do akceleracji rozszerzenia X Render. EXA była pierwotnie prezentowana jako rozwiązane dla dowolnego sprzętu, także tego starszego. Ale to nieprawda. Jeśli starszy sprzęt nie potrafi sprzętowo przyspieszać wyświetlania, to EXA nic na to nie pomoże. Ostatecznie więc sprzęt na którym pracuje EXA, to ten sam sprzęt dla którego już istniały sterowniki OpenGL. Sterownik EXA działa na sprzęt 3D ze sterownika 2D XAA, dodając do długiej listy programów, które próbują korzystać z karty graficznej jednocześnie, jeszcze jednego powodującego konflikty użytkownika. W efekcie EXA to tylko proteza, która utrzyma stary kod serwera X jeszcze przez rok czy dwa. Istnieje też niebezpieczeństwo, że EXA zacznie się rozszerzać w kierunku pozostałych funkcji układów 3D. Ta proteza zadziała, ale nie jest to rozwiązanie długoterminowe. Jej istnienie powoduje także opóźnienie w stworzeniu rozwiązania na dłuższą metę. Najważniejszą do zapamiętania sprawą jest to, że EXA/render to jedynie podzbiór szerszego API Mesa OpenGL, i że z czasem zawsze będziemy chcieli coraz więcej możliwości.

Cairo

Celem cairo jest stworzenie wysokiej jakości API do rysowania, które jest równie dobre do wydruków jak i na ekrany. Jest zaprojektowane z myślą o rozszerzeniu X Render i implementuje model wyświetlania PDF 1.4. Interesujące operacje obejmują obrysowywanie i wypełnianie krzywych Béziera trzeciego stopnia, transformacje i nakładanie przeźroczystych obrazów oraz wyświetlanie wygładzanego tekstu. Cairo jest przenośne i pozwala na wyświetlanie przez wtyczki takie jak image, glitz, png, ps, PDF, svg, quartz, GDI czy xlib. Prace nad cairo trwają w tej chwili od około dwóch lat i powinny znaleźć zastosowanie w nadchodzących wersjach GDK i Mozilli. Zasadniczym celem cairo jest ułatwienie programistom uzyskanie wysokiej jakości płaskiej grafiki ekranowej, którą da się następnie łatwo wydrukować. Wtyczki wyjściowe pozwalają aplikacji na użycie tego samego kodu do rysowania i do drukowania.

Jedno z wyjść cairo, o nazwie glitz, to implementacja w OpenGL. Istnieje dobry artykuł szczegółowo objaśniający glitz. Ponieważ cairo potrafi wyświetlać zarówno przez xlib jak i OpenGL, to można dokonać bezpośredniego porównania wydajności między tymi dwoma sposobami wyświetlania. W opublikowanych testach OpenGL bije XAA pod każdym względem od dziesięciu do stu razy lepszą prędkością. Ta ogromna różnica w wydajności jest spowodowana używaniem przez glitz/OpenGL funkcji 3D procesorów graficznych. Porównanie cairo na glitz i na xlib jest dobrym sposobem na zilustrowanie tezy, że sprzęt 3D świetnie sobie radzi z wyświetlaniem płaskiej grafiki.

DRI i OpenGL

DRI, Direct Rendering Infrastructure, implementuje OpenGL we współpracy z serwerem X. DRI składa się z czterech głównych komponentów. Pierwszy to libGL, który dostarcza API OpenGL i pełni funkcję przełącznika między sterownikami. Kolejna część to biblioteka DRI dla konkretnego sprzętu, która steruje procesorem grafiki. Dla funkcji OpenGL, których nie obsługuje sterownik DRI, potrzebny jest programowy mechanizm zapasowy. Zapewnia go Mesa. Zwróćcie uwagę, że Mesa to pełna programowa implementacja OpenGL. Karta, która nie zapewnia żadnej akceleracji, może obsłużyć wszystkie funkcje OpenGL poprzez Mesę. Wreszcie mamy DRM, menedżer wyświetlania bezpośredniego. Sterowniki DRM zarządzają sprzętem i zapewniają odpowiednie zabezpieczenia działając wewnątrz jądra.

Ciekawym aspektem DRI jest zawarta w jego nazwie "bezpośredniość". Każda aplikacja używająca DRI ma bezpośredni dostęp do sprzętu. To inaczej niż w X-ach, gdzie polecenia rysowania są przesyłane do serwera, który działa na sprzęcie w imieniu użytkownika. Sterownik DRM w jądrze koordynuje działania wielu użytkowników tak, aby sobie nawzajem nie przeszkadzali. Zaletą tego modelu jest to, że OpenGL może rysować bez dodatkowych kosztów wynikajacych z przełączania między procesami i przesyłania danych do serwera. Jego wadą jest z kolei to, że karta graficzna może mieć do czynienia z bardzo częstym przełączaniem między kontekstami. Karty w stacjach roboczych wyraźnie dobrze sobie z tym radzą, ale niektóre tańsze modele niekoniecznie. Microsoft już napotkał na ten problem i wymaga zaawansowanej sprzętowej obsługi przełączania kontekstu dla sprzętu mającego pracować pod DirectX 10.

W DRM istnieje koncepcja specjalnego użytkownika, który ma większe uprawnienia niż pozostali. Te dodatkowe uprawnienia pozwalają na inicjalizację urządzeń graficznych oraz kontrolę nad stopniem używania zasobów GPU. Obecny serwer X, który działa z prawami roota, zachowuje się jak specjalny użytkownik DRM. W rzeczywistości nie ma potrzeby żeby specjalny użytkownik DRM działał z prawami roota i istnieje już wstępna wersja łatki, która usuwa to wymaganie.

Kiedy sprzęt nie jest w stanie obsłużyć jakiejś funkcji, Mesa obsługuje ją programowo. Nazywa się to programowy mechanizm zapasowy (software fallback). Powoduje to nieporozumienia wśród użytkowników. Twierdzą oni, że OpenGL nie jest w pełni akcelerowane, a serwer X jest. Zastanówmy się nad tym. Oba sterowniki pracują na tym samym sprzęcie. OpenGL nie jest w pełni akcelerowane, ponieważ oferuje wiele funkcji możliwych do przyspieszenia, podczas gdy X-y oferuje tylko kilka takich funkcji. Jeżeli któraś jest obecna w API obu sterowników, to zapewne oba wykorzystają akcelerację. Jeżeli nie, to trzeba usiąść do klawiatury i naprawić dany sterownik.

Bezpieczeństwo i prawa roota

Jądro Linuksa składa się z 10 milionów wierszy kodu działającego z prawami roota. Serwer X zawiera 16 milionów wierszy kodu, z którego wiele działa z tymi samymi prawami. Gdzie są większe szanse na znalezienie dziury w zabezpieczeniach? Nie ma technicznych powodów aby serwer X pracował z prawami roota. W imię zgodności między platformami obecny serwer X działa jako root w celu dostępu do sprzętu z przestrzeni użytkownika. Linux oferuje rozwiązanie tego problemu. Uprzywilejowany kod przenosi się do sterownika, a aplikacje w przestrzeni użytkownika działają bez przywilejów. Uprzywilejowany sterownik dla przeciętnej karty graficznej ma około 100 KB. To znacznie mniej kodu do sprawdzania niż 16 milionów wierszy.

Starszy sprzęt

Każda karta graficzna, nawet prosta VGA, potrafi obsłużyć serwer X, a Mesa szczęśliwie implementuje pełne API OpenGL programowo. Pytanie tylko jak szybko to działa. Żadna ilość programowania nie zamieni karty VGA w ATI X850. Taki starszy sprzęt dobrze działa z bieżącym serwerem X. Ale nowe systemy projektuje się dla nowego sprzętu, więc na tym starszym mogą działać bardzo wolno. Można wobec tego zastanowić się nad wymianą karty graficznej; nowe karty o porządnej wydajności pod OpenGL można kupić za 40 dolarów, a używane jeszcze taniej. Można też poniechać wymiany i nadal używać tego samego oprogramowania, które dotąd dobrze się sprawowało.

Obsługa grafiki w jądrze

Kiedy jądro się uruchamia, na ekranie widać konsolę startową. Na x86 najpopularniejszą konsolą startową jest VGAcon. VGAcon korzysta ze wstecznej zgodności karty graficznej ze standardem VGA. Ponieważ większość kart pod x86 obsługuje ten standard, VGAcon jest uniwersalną konsolą dla tej platformy. Inne platformy mogą nie posiadać obsługi VGA. Na tych platformach zazwyczaj ładuje się sterownik bufora ramki dla danej kości. Jądro zawiera mnóstwo takich sterowników, więc obsługuje szeroki wachlarz sprzętu.

Tryb VGA

Pierwotna architektura IBM PC miała cokolwiek ograniczony zestaw peryferiów, dostępnych przez stałe, dobrze znane adresy, na przykład port COM1 pod 0x3F8. Niestety, obsługa trybu VGA w większości kart graficznych jest dostępna właśnie pod jednym z tych ustalonych adresów. Dopóki w systemie jest tylko jedna karta, VGA nie sprawia problemów. Jednak po włożeniu drugiej mamy dwa urządzenia które chciałyby zająć na szynie ten sam adres.

Obecny serwer X zawiera kod obsługi wielu kart VGA. Ale ten kod jest nieświadomy obecności innych użytkowników tych urządzeń i będzie z nimi co i rusz kolidował. Te kolizje nie są przyjemne, dlatego potrzebna jest koordynacja wielu użytkowników kart VGA. W Linuksie najlepszym wyjściem jest dodanie tego mechanizmu do jądra. BenH pracuje nad takim rozwiązaniem, które było dyskutowane na OLS.

Kolejny problem to inicjalizacja wielu kart graficznych. Karty te mają swój ROM, często nazywany też VBIOS, który jest uruchamiany podczas startu w celu zainicjowania sprzętu. Z przyczyn historycznych wiele z nich używa obsługi VGA. Ponieważ zgodnie ze starym standardem może być tylko jedna karta VGA, BIOS komputera inicjuje tylko pierwszą z nich. Pozostałe karty można zainicjować w późniejszej fazie startu. W tym celu ich VBIOS jest uruchamiany w trybie vm86 i koordynowany z użyciem pojedynczego urządzenia VGA. Aby było jeszcze trudniej, występują dwa powszechne formaty ROM-u: x86 i Open Firmware. Ponieważ modele z Open Firmware są o wiele droższe, użytkownicy często wykorzystują karty dla x86 w maszynach o innej architekturze. Żeby to zadziałało, VBIOS musi być uruchamiany przez  emulator x86. BenH pracuje także nad tym problemem.

Fbdev, zwany także buforem ramki. Pod Linuksem bufor ramki odpowiada głównie za: inicjalizację sprzętu, wykrywanie dołączonych monitorów, określenie prawidłowych trybów ich pracy, ustawienie trybu skanowania i konfiguracji, sprzętowy kursor, wygaszanie, mapowanie kolorów, obsługę widzialnych obszarów oraz usypianie/budzenie. W jądrze jest wiele sterowników bufora ramki i reprezentują one różny poziom obsługi tych funkcji. Warto zauważyć, że chociaż interfejs do fbdev jest w jądrze, to nic nie stoi na przeszkodzie aby fbdev obsługiwał też pomocnicze aplikacje w przestrzeni użytkownika. Te aplikacje mogą być używane do wywołań VBIOS-u gdy nie ma dostępu do  kodu źródłowego.

VBIOS po uruchomieniu tworzy zestaw niskopoziomowych punktów wejścia, za pomocą których można kontrolować ekran. Ten opis robi się bardzo szczegółowy, więc nie będę już wyjaśniał różnic między trybami VGA, Int10 i VESA. Tytułem omówienia, VGA to standard podstawowych rejestrów sprzętu wprowadzony przez IBM. Int10 dotyczy używania do wyświetlania mechanizmu przerwań. Przerwania programowe działają tylko w trybie rzeczywistym x86 i nie są już zbyt powszechne poza programami takimi jak GRUB. Kod obsługi Int10 zawiera VBIOS i instaluje go po uruchomieniu ROM-u. Może być tylko jeden zainstalowany sterownik Int10. VESA przejęła model Int10 i przystosowała go do pracy w trybie chronionym. Podczas konfiguracji jądra do wyboru są trzy sterowniki: VGA i VESA fbdev, który wymaga załadowania sterownika fbconsole, oraz VGAcon, który zawiera wszystko co trzeba. Na architekturach innych niż x86 zazwyczaj potrzeba fbdev i fbconsole.

Obsługa wielu użytkowników

Linux jest systemem obsługującym wielu użytkowników. Zawsze tak było. Ale jedyne sposoby ich podłączenia to łącza szeregowe oraz sieć. A jeśli zainstaluje się wiele kart graficznych i udostępni się to użytkownikom lokalnie? To nie zadziała. Istnieją łatki, które próbują sobie z tym poradzić, jak choćby Linux console project i różne sztuczki z X-ami. Problem polega na tym, że system wirtualnych terminali na linuksowej konsoli kontroluje lokalne karty graficzne i w praktyce obsługuje tylko jednego użytkownika. Zwróćmy uwagę, że fbdev działa prawidłowo dla wielu użytkowników, tylko system wirtualnych konsol jest przeznaczony dla pojedynczego użytkownika.

Obsługa wielu użytkowników ma zastosowanie w miejscach typu szkoły, systemy monitorowania, kafejki internetowe, a nawet w domach. Jak dotąd popyt na obsługę wielu kart graficznych nie był zbyt wysoki, ponieważ standardowe PC ma tylko jedno gniazdo AGP. Rozwiązania składające się z wielu kart PCI działają, ale ich wydajność nie jest duża. Istnieją zaawansowane maszyny z wieloma gniazdami AGP, ale nie są powszechne. Tą sytuację zmienia PCI Express. W tym systemie wszystkie gniazda są funkcjonalnie równoważne. Jedyna różnica to ilość ścieżek doprowadzonych do danego gniazda. Ta zmiana sprzętowa pozwala na łatwe budowanie systemów z wieloma wydajnymi kartami graficznymi. Planowane są kości PCIe pozwalające na obecność w pojedynczym systemie do 16 kart graficznych.

Podział kodu konsoli

Analizując kod obsługi konsoli szybko daje się zauważyć, że są dwie różne klasy związane z konsolą. Konsola systemowa, która zapewnia ekran startowy i jest używana do wyświetlania błędów systemowych, napraw i obsługi systemu. I konsola użytkownika, zwykły ekran na który użytkownik się loguje i pracuje w wierszu poleceń lub edytuje. W obecnym systemie konsoli pod Linuksem obie obsługuje ten sam kod.

Można podzielić kod konsoli w zależności od typu użytkowania i w ten sposób załatwić wiele obecnych problemów z konsolą pod Linuksem. Przede wszystkim konsola systemowa powinna być całkowicie godna zaufania i odporna na zakłócenia. Nie musi być szybka. Musi być napisana możliwie najprostszym kodem i działać podczas przerwań i paniki jądra. Jej zastosowania obejmują naprawę systemu i tryb pojedynczego użytkownika. Możliwe jest też wyświetlanie komunikatów podczas startu systemu i obsługa kdbg. Konsola systemowa może udostępniać SAK oraz bezpieczny ekran logowania. W celu obsługi niezależnych użytkowników zalogowanych przy różnych monitorach musi być zaimplementowana dla każdej karty graficznej osobno. Do nowej konsoli systemowej powinno dać się wejść przez klawisz SysReq: powinna wówczas zakryć bieżący ekran i używać bieżącego trybu graficznego. Tak właśnie działa Novell kernel debugger. Konsola systemowa nie potrzebuje wirtualnych terminali i nie oferuje przełączania konsol. Ponieważ zna aktualny tryb graficzny, może wywłaszczyć ekran w razie problemów, na przykład fatalnych padów jądra (OOPs).

Projekt konsoli systemowej używa fbdev do śledzenia trybu graficznego oraz położenia bufora skanowania. Aby była tak rzetelna, jak to tylko możliwe, musi być z niej usunięta wszelka akceleracja. Fbconsole do manipulowania buforem ramki używa wówczas głównego procesora. Konsola jest wyświetlana przez pisanie bezpośrednio do bufora skanowania, za pomocą istniejącego w fbconsole kodu obsługi czcionek bitmapowych.

Konsola użytkownika to przeciwieństwo konsoli systemowej, musi być bardzo wydajna i przyjazna. Implementacja jej w przestrzeni użytkownika pozwoli na łatwą obsługę wielu użytkowników przez przydzielenie każdemu z nich osobnego procesu. Przestrzeń użytkownika umożliwia pełne wykorzystanie sprzętowej akceleracji grafiki przez fbdev i DRM. Daje też łatwy dostęp do to Xft/FreeType, co pozwala uzyskać pełne wyświetlanie Unikodu. Przy odpowiednim zaprojektowaniu konsola może nawet dopuszczać różnych użytkowników przy każdym monitorze. Przy użyciu odpowiednio ustalonych klawiszy skrótu może się zachowywać zupełnie jak istniejące wirtualne terminale i pozwalać na przełączanie między konsolami.

Ponieważ obecnie kod obu konsol jest wspólny, przełączanie między wirtualnymi terminalami daje oba typy konsoli. W nowym modelu obecne kombinacje klawiszy służące do przełączania między konsolami dadzą konsolę w przestrzeni użytkownika. Klawisz SysReq powinien aktywować konsolę systemową. Proces powłoki związany z konsolą systemową mógłby pracować z wysokim priorytetem, co ułatwiłoby próbę przejęcia kontroli po błędnym procesie.

Grupowanie sprzętu

Lokalna obsługa wielu użytkowników zakłada, że Linux zrealizuje koncepcję grupowania konsol dla peryferiów związanych z interfejsem użytkownika. Grupy konsol to zbiory sprzętu, które razem tworzą  konsolę. Przykład takiej grupy może zawierać monitor, mysz, klawiaturę i kartę dźwiękową. Podczas logowania PAM przydziela te urządzenia zalogowanemu użytkownikowi. Ciekawym rozwinięciem tej idei jest potraktowanie gniazda lub portu USB jako części takiej grupy. W czasie, kiedy użytkownik jest zalogowany, wszystkie urządzenia podłączane przez port USB będą także należeć do niego. Po wylogowaniu wszystko wraca do puli urządzeń bez przydziału.

Inne alternatywy

Drobniejsi goście: directfb, svgalib, fresco, Y Windows, FBUI itp. Linux przyciąga wiele osób, które chcą poeksperymentować z kodem wyświetlania. W obecnym modelu wirtualnych terminali te alternatywne systemy wyświetlania powodują masę problemów przy przełączaniu. Po przejściu na inną wirtualną konsolę nowo uruchomiony system wyświetlania może robić ze sprzętem co zechce. W tym dokonać jego ponownej inicjalizacji, przeprogramowania i wyczyszczenia VRAM-u. Kiedy wracamy do poprzedniej konsoli, oczekujemy że pierwotny system przywróci stan sprzed tych zmian. Nie tylko ci drobni goście mogą tu sprawić kłopoty. Można przełączać się między konsolą i X-ami lub nawet między dwoma systemami grafiki typu X i Xegl. Ten model był zapewne dobry dla kart VGA z 14 rejestrami i 32 KB VRAM. Ale nie jest to dobry model dla karty graficznej z 300 rejestrami, 512 MB VRAM i niezależnym koprocesorem graficznym.

Efektywna współpraca

Uważam, że najlepszym rozwiązaniem tego problemu jest zapewnienie dla każdej karty graficznej jednego ogólnego sterownika w jądrze. To oznacza, że konkurencyjne sterowniki, jak fbdev i DRM, muszą zostać zaprzęgnięte do współpracy. To znaczy też, że dostęp do sprzętu z przestrzeni użytkownika w czasie działania załadowanego sterownika powinien być blokowany. Podejrzewam, że jeśli Linux zaoferuje standardowe ogólne sterowniki dla różnych kart graficznych, to zniknie większość tęsknot za stworzeniem kolejnego sterownika do Radeona.

Nie znaczy to, że projekty takie jak fresco nie powinny rozwijać własnych sterowników. To oznacza tylko tyle, że trzeba będzie najpierw usuwać z pamięci standardowy sterownik i załadować własny przed uruchomieniem nowego programu. Takie zachowanie nie różni się niczym od obsługi wszystkich innych sterowników w jądrze. Używanie klawisza skrótu do przeskakiwania (przełączania wirtualnych konsol) między dwoma aktywnymi sterownikami grafiki działającymi na tym samym sprzęcie nie byłoby już możliwe. Jeśli w standardowym sterowniku czegoś brak, to lepszym podejściem jest przesłanie łatki do niego. Dzięki umieszczeniu wymaganych rozszerzeń w standardowym sterowniku wszystkie programy mogą z nich korzystać i powinno być łatwo przełączać się między aplikacjami poprzez system konsol w przestrzeni użytkownika.

Jeżeli mamy zamiar utrzymać dotychczasową możliwość przeskakiwania między sterownikami grafiki za pomocą klawiszy skrótu, to myślę że równie słuszne jest przypisanie klawiszy skrótu do przełączania między sterownikami dysku i sieci.

OpenGL/ES

Khronos Group to grupa zajmująca się nowymi standardami, składająca się z ponad setki korporacji członkowskich. Jej najbardziej popularnym standardem jest OpenGL ES. OpenGL ES określa bardzo użyteczny podzbiór OpenGL przeznaczony dla urządzeń wyposażonych w małą ilość pamięci. Definiuje też EGL, które jest niezależnym od platformy odpowiednikiem API GLX/agl/wgl z OpenGL. "EGL zapewnia mechanizm tworzenia powierzchni, na których mogą rysować klienckie API jak OpenGL ES czy OpenVG, na których można tworzyć konteksty graficzne dla tych API oraz synchronizować proces rysowania zarówno przez API klienckie jak i przez API macierzyste dla danej platformy. Umożliwia to bezkonfliktowe, wydajne, korzystające z akceleracji wyświetlanie przy pomocy OpenGL ES i OpenVG w mieszanym środowisku 2D i 3D."

EGL zakłada istnienie systemu okienek zapewnianego przez inne części systemu operacyjnego. Ale architektura EGL jest niezależna od platformy, i w przeciwieństwie do GLX/agl/wgl nic w API EGL nie jest związane z konkretnym systemem okienek. Wszystkie powiązania z lokalnym systemem okienek są obsługiwane przez nieprzeźroczyste wskażniki.

Twórcy Mesy zebrali propozycje rozszerzenia EGL w celu stworzenia na bazie EGL systemu okienek. Zasadnicza część tego rozszerzenia zapewnia API do zliczania dostępnych ekranów, ustawiania trybu pracy i konfiguracji bufora ramki, przewijania ekranu i pytania o atrybuty. Wśród rzeczy których rozszerzenie EGL jeszcze nie obejmuje jest obsługa sprzętowego kursora oraz mapowanie kolorów. Dodanie tych rozszerzeń do EGL zapewnia wystarczającą kontrolę nad sprzętem, aby móc zaimplementować serwer i system okienek jak w Xegl. OpenGL połączone z EGL i rozszerzeniami Mesy zapewnia naprawdę przenośne API do korzystania z wielu rodzajów sprzętu graficznego, począwszy od telefonów komórkowych, przez Playstation 3 i PC-ty, aż do graficznych superkomputerów.

Rozszerzone API EGL świetnie nadaje się dla Linuksa. Zapewnia solidne fundamenty do tworzenia systemów okienkowych lub aplikacji wbudowanych. Jest łatwe w użyciu, co czyni go świetną platformą do badań i eksperymentów. Pozwala się skupić na nowych aplikacjach lub systemach okienkowych zapominając o wszystkich niuansach sprzętowych.

Uważam, że Khronos Group to wielka niewykorzystana okazja dla X.org i społeczności zajmujących się grafiką w Linuksie. Większość standardów Khronosa nie ma otwartych implementacji wzorcowych, systemów ułatwiających programowanie i testów zgodności. Wiele firm wspierających tą grupę sprzedaje systemy oparte na Linuksie. Gdyby X.org rozszerzyło swoją działalność, to mogłoby uzgodnić z Khronos Group swoją rolę jako neutralnej niekomercyjnej lokomotywy dla tworzenia otwartych implementacji wzorcowych i systemów ułatwiających programowanie bazujących na Linuksie i standardach Khronosa. Takie partnerstwo dałoby członkom Khronos Group szansę wniesienia bezinteresownego wkładu do X.org, podobnie jak robi to IBM z Fundacją Eclipse.

Dokładność co do piksela

Dokładność co do piksela to mit. Jedyne co da się osiągnąć to pewien stopień dokładności. Źródła błędów tkwią wszędzie. Podświetlanie ekranów LCD, konsystencja tuszu w drukarce, jakość konwerterów cyfrowo-analogowych, odbijanie światła przez papier, problemy z dopasowaniem kolorów, różnice w algorytmach rysowania w procesorze graficznym itd. OpenGL nie gwarantuje dokładności co do piksela w przypadku różnych implementacji. Najbliżej do pikselowej identyczności można podejść tylko stosując w każdym przypadku tą samą wersję programowej Mesy. Swoją drogą, serwer X także nie daje takiej dokładności. Ja stosuję następującą praktyczną regułę: jeśli różnicę widać dopiero pod szkłem powiększającym, to jest wystarczająco dokładnie. Ta sprawa wywołuje dużo nieporozumień. Jeśli OpenGL ma wyświetlić mapę bitową, to skopiuje te piksele na ekran bez zmian, chyba że dostanie inne polecenie. Kwestia dokładności rysowania co do piksela ma zastosowanie raczej do skalowalnych wektorów, na przykład linii.

Podpikselowe wygładzanie liter nie jest problemem, OpenGL oferuje wiele tego rodzaju rozwiązań. Może na przykład używać dokładnie tego samego mechanizmu wyświetlania glifów jak obecny serwer X. Ponieważ mechanizm jest ten sam, to i glify będą identyczne. Niepożądane jest też przywiązywanie rysowania do konkretnego algorytmu, bo to hamuje postęp. Na przykład ten 
artykuł
(wideo) prezentuje zupełnie nowy sposób generowania czcionek przez procesor grafiki. Istnieje też inny interesujący artykuł "Resolution Independent Curve Rendering using Programmable Graphics Hardware" Loopa i Blinna z SIGGRAPH 2005. Gdyby rysowanie czcionek było określone z dokładnością co do piksela, zastosowanie tych nowych technik byłoby prawdopodobnie niemożliwe. Te glify są generowane przez procesor graficzny i używają algorytmów, które są wbudowane w sprzęt i których użytkownik nie może zmieniać. Konwersja obrysów do pikseli, aby wyświetlać je jako zestaw grafik, to tylko jeden możliwy sposób wyświetlania glifów. Programowalne procesory graficzne dostarczają nowych alternatyw. Każde długo istniejące API musi wziąć to pod uwagę.

Trzy generacje okien

W obecnym serwerze X oraz wielu innych systemach okienkowych okna są rysowane na ekranie w obszarach obcinania (clip regions) za pomocą algorytmu malarza. Ten algorytm działa tak, jak przy rzeczywistym malowaniu: każda kolejna warstwa zasłania poprzednią. Najpierw rysuje się tło, a następnie wszystkie okna w odwrotnej kolejności bufora Z. Jeśli nie ma przeźroczystości i zna się z góry położenie wszystkich okien, to można usprawnić ten algorytm (jak to robią X-y) za pomocą prostokątnych obszarów wycinania, aby każdy piksel na ekranie był rysowany tylko raz. Można zwiększyć wydajność śledząc uszkodzenia obrazu. Tylko okna w naruszonym obszarze muszą być ponownie narysowane, podczas gdy reszta ekranu jest chroniona przez obszary wycinania. Dodatkową korzyść przynosi "zapisywanie spodu". System okienek widzi, że elementy takie jak rozwijające się menu odbudowują zawartość okna kiedy znikają. "Zapisywanie spodu" zapisuje zawartość ekranu pod tymi elementami, a potem ją przywraca.

Rozszerzenie Composite korzysta ze zwiększonej wydajności nowego sprzętu. Przy jego zastosowaniu okna są rysowane poza ekranem (off screen), w niewidocznej pamięci obrazu. Menedżer okien składa te okna razem do formy widzialnego ekranu. Składanie nadal wykorzystuje algorytm malarza, ale ponieważ menedżer okien zawsze posiada zawartość wszystkich okien, to możliwe jest wyświetlanie przeźroczystych okien. Przeźroczystość powstaje przez wymieszanie zawartości ekranu spod danego okna z poprzednią zawartością tego okna w trakcie kopiowania do bufora skanowania (scanout buffer). Nazywa się to łączenie alfa (alpha blending). Obsługuje je większość współczesnego sprzętu. Migotanie podczas rysowania jest eliminowane za pomocą podwójnego buforowania. W tym modelu wszystko jest nadal płaskie i ma prostą kolejność w buforze Z.

Bardziej zaawansowany sprzęt z obsługą multitekstur potrafi całkiem uniknąć algorytmu malarza. Każde okno nakładające się na dany region ekranu może być potraktowane jako osobna tekstura. Następnie można rysować na ekranie wielokąty reprezentujące okna. Te wielokąty mogą mieć odpowiednie koordynaty tekstur na wierzchołkach dla każdego okna/tekstury, a następnie sprzęt wykonuje składanie okien/tekstur tworząc oczekiwany rezultat. W skrajnym przypadku za pomocą pojedynczego prostokąta złożonego z wielu tekstur można przerysować cały ekran! Ta technika jest niezwykle szybka i nie wymaga nawet podwójnego buforowania, bo migotanie jest minimalne.

Xgl implementuje model składania. Chociaż nie jest to wymagane, Xgl korzysta z nowej cechy OpenGL obiektów bufora ramki (FBO). W tak rozszerzonym OpenGL obiekty bufora ramki mogłyby umożliwić bardzo wydajne udostępnianie okien aplikacji z niewidocznej pamięci obrazu dla menedżera okien. Nie jest to takie trudne, obecnie współdzielimy przecież pbuffers między procesami. Dla aplikacji FBO wyglądają jak normalne okna do rysowania. Dla menedżera okien okienka wyglądają jak tekstury i można nimi manipulować za pomocą zwykłych poleceń rysowania jak multiteksturami. W tym modelu okna aplikacji są nadal płaskie, ale można już napisać oparty na OpenGL menedżer okien w rodzaju Luminosity. Taki menedżer może składać okna używając bufora Z i przełamywać granice ścisłej kolejności Z narzucane przez 2D. Okno może być na przykład przekształcone w falę i przecinać się w wielu miejscach z innym oknem.

Wreszcie można też usunąć ograniczenia 2D z okien aplikacji i nadać im grubość lub inne trójwymiarowe kształty. Na przykład rozwijające się menu może pojawiać się wyżej niż zawartość okna. Jeśli dodać do tego źródło swiatła, to cień będzie padał naturalnie, zamiast być sztucznie dokładany jak w grafice płaskiej. Projekt Suna Looking Glass 
jest właśnie tego rodzaju menedżerem. Efekt grubości okien prezentuje demonstarcyjny filmik z tego projektu. Looking Glass obsługuje istniejące aplikacje dla X-ów za pomocą niezamocowanego serwera X. Okna mają nadaną grubość i współistnieją z pełnymi aplikacjami 3D w rodzaju demonstracyjnej zmieniarki płyt CD.

Idea trójwymiarowego biurka nie jest taka znowu dziwna. Trójwymiarowe biurko istnieje od kiedy przeszliśmy od kafelkowanych (tiled) okienek w Windows 1.0 do okien nakładających się - po wprowadzeniu kolejności Z, biurko stało się trójwymiarową przestrzenią pozbawioną perspektywy. Koncepcje 3D istnieją w całym biurku, wystarczy spojrzeć na menu i wyskakujące okienka. Ważną przyczyną implementacji składania było wprowadzenie padających cieni, które są oczywiście płaską reprezentacją trójwymiarowej przestrzeni. Nawet płaskie elementy w rodzaju przycisków symulują trójwymiarowy wygląd. Dlaczego nie rysować ich w trzech wymiarach i pozwolić użytkownikom kontrolować źródło światła? Przeźroczystość okien w oczywisty sposób zakłada trójwymiarowość. Dlaczego po prostu nie przyznać, że biurko jest trójwymiarowe i rysować je za pomocą grafiki 3D?

Rysowanie linii

Na ten temat toczyły się dyskusje. Linux ma faktycznie tylko jedną drogę dla przejścia Open Source na biurko oparte o procesor grafiki - implementację OpenGL z Mesy. Oczywiście można sklonować DirectX, ale kto napisze cały ten kod i sterowniki? OpenGL nie jest złym wyborem. Posiadanie go pod Linuksem jest konieczne niezależnie od tego co robimy. Jest ustandaryzowany i kontrolowany przez ARB (radę przeglądu architektury). Jest dobrze zaprojektowany i dobrze udokumentowany. Jest szeroko rozpowszechniony i używany. Szkoły prowadzą zajęcia na jego temat i powstało o nim wiele książek. Działają pod nim świetne aplikacje oraz gry.

Na jakim poziomie sterownik grafiki powinien rysować linię? XAA i fbdev robią to niskopoziomowo. Te API zajmują się pikselami w buforze ramki, bitowymi blokami (bitblit) i ewentualnie także rysowaniem linii. Na tym poziomie wszystkie możliwości oferowane przez układy graficzne są albo niedostępne, albo wymagają sztuczek z API. Xgl rysuje linie w zupełnie inny sposób. Linia powstaje na niezwykle wysokim poziomie API samego OpenGL. Uważam, że takie podejście jest lepsze. Lepiej rysować linię na znacznie wyższym poziomie niż obecny zestaw możliwości zawartych w krzemie, aby pozwolić im ewoluować bez naruszania API. Nie wierzę, że Linux skorzystałby na przechodzeniu przez wiele kolejnych API, jak to było w przypadku DirectX. Lepiej zacząć od bardzo wysokiego poziomu, dostarczyć programową implementację wzorcową, czyli Mesę, a potem zastępować fragmenty Mesy przez implementacje korzystające ze sprzętowej akceleracji, czyli DRI. Istnieje też wiele implementacji OpenGL: Mesa, Nvidia i ATI. Można wybierać - wierzcie lub nie, ale niektórzy lubią własnościowe sterowniki.

Xgl powstał jako krótkoterminowe rozwiązanie przejściowe. Model Xgl zakładał przeźroczystą wymianę systemu wyświetlania z obecnego serwera X na zgodny system wyświatlania, używający OpenGL jako sterownika. Xgl przejął wszystkie istniejące API X-ów jako swoje główne API. Nie wprowadził ani nie porzucił żadnego API. Kod Xgl jest wysokopoziomowy i wieloplatformowy. Jest on ogólny i wymaga portowania na poszczególne środowiska OpenGL. Jeden z takich portów, Xglx, powstał dla 
API GLX. Inny, Xegl, działa na wieloplatformowym API EGL. Zauważmy, że EGL to niezależna od platformy forma korzystania z API GLX, agl oraz wgl. EGL z rozszerzeniem Mesy potrafi kontrolować niskopoziomowy bufor ramki. Ta kombinacja zapewnia wszystko co potrzeba do implementacji systemu okienek (jak obecny serwer X) na gołym sprzęcie graficznym. Ale Xgl to krótkoterminowy model przejściowy, a przy opóźniającym się zapotrzebowaniu na Xgl EXA czyni go w większości zbędnym.

Ciągle powraca argument, że nie powinno się używać OpenGL z powodu starszego sprzętu używanego w krajach rozwijających się. Są dwa rozwiązania tego problemu. Po pierwsze, API OpenGL jest skalowalne. Poprzez programowy mechanizm zapasowy może działać nawet na najsłabszym sprzęcie. OpenGL ES oferuje także profile API. Profile to dobrze określone podzbiory API OpenGL. W razie potrzeby można zdefiniować profil minimum, będący możliwie najmniejszym API OpenGL. Rozmiar kodu nie powinien być problemem, istnieje własnościowa implementacja OpenGL ES o wielkości 100 KB. Inny profil OpenGL ES obywa się bez obsługi liczb zmiennoprzecinkowych. Nie ma przeszkód żeby zbudować jego otwarty odpowiednik jeśli zdecydujemy się przeznaczyć na to zasoby.

Inny argument jest taki, że po prostu należy korzystać z oprogramowania, którego zostało zaprojektowane dla danego sprzętu. Nikt nie oczekuje, że da się uruchomić Windows Longhorn na oryginalnym IBM PC, ale na tym samym PC nadal bez zarzutów działa DOS.

Chodzi o to, że OpenGL skaluje się lepiej niż EXA. Skalowalność EXA załamuje się na szczycie, nie obejmuje takich zaawansowanych funkcji procesorów grafiki jak 3D czy programowalność. Z OpenGL możliwe jest utrzymywanie tego samego API od telefonu komórkowego aż do superkomputerów.

Układanie klocków

Jest zbyt wiele skrótowców, żeby tu wymienić wszystkie na raz. Może lepiej kilka przykładów na to jak poszczególne biblioteki współpracują ze sobą nawzajem:

Aplikacja -> gtk+ -> X -> XAA -> sprzęt

To sytuacja z obecnym serwerem X. Aplikacja komunikuje się z pakietem narzędziowym (toolkit), który używa API xlib dla serwera X. Serwer X rysuje w sprzęcie za pomocą obecnych sterowników XAA. X-y i aplikacje wykorzystują dwa osobne procesy.

Aplikacja -> gtk+ -> Cairo -> X Render -> X -> XAA/EXA -> sprzęt

Pakiet narzędziowy używa biblioteki cairo. Cairo wymaga rozszerzenia X Render. Jeśli jest obecna EXA, to X Render korzysta z akceleracji. X-y i aplikacje wykorzystują dwa osobne procesy.

Aplikacja -> qt -> Arthur -> X Render -> X -> XAA/EXA -> sprzęt

Arthur to odpowiednik cairo stworzony przez Trolltecha, zachowuje się właściwie tak samo jak ono.

Aplikacja -> gtk+ -> Cairo -> glitz -> GL -> sprzęt

Pakiet narzędziowy używa nowej biblioteki cairo. Cairo wybiera wyjście przez glitz dla bezpośredniego rysowania opartego na OpenGL.

Aplikacja -> gtk+ -> Cairo -> X Render -> Xgl -> EGL (samodzielne) -> GL -> sprzęt

W tym przypadku pakiet narzędziowy wybiera wyjście z cairo przez xlib i komunikuje się z serwerem Xegl z rozszerzeniem X Render. Xegl do wyświetlania używa glitz. Glitz bezpośrednio rysuje w sprzęcie. Xegl i aplikacje wykorzystują dwa osobne procesy. Zauważmy, że pakiet narzędziowy mógł wybrać bezpośrednią komunikację z glitz i bezpośrednio rysować w tym samym procesie.

Aplikacja -> gtk+ -> Cairo -> X Render -> Xgl -> GLX (X) -> GL -> sprzęt

Pakiet narzędziowy ponownie komunikuje się z X Render w serwerze Xglx. Xglx nie jest samodzielnym serwerem, tylko serwerem zagnieżdżonym. Nie jest jednak zwykłym zagnieżdżonym serwerem, używa zagnieżdżenia dla wejścia, ale rysuje całe biurko wewnątrz pojedynczego okna OpenGL udostępnianego przez macierzysty serwer. W trybie pełnoekranowym to okno przestaje być widoczne. Istnieją tu trzy procesy: aplikacja, Xglx i serwer X. Rysowanie odbywa się na linii między aplikacją a Xglx, ponieważ Xglx rysuje bezpośrednio. Trzeci proces, serwer X, jest zaangażowany poprzez udostępnianie okna i wejścia. Jest też gospodarzem dla aplikacji Xglx.

Przyszłe kierunki

Linux będzie z pewnością ostatnim dużym systemem biurkowym, którego graficzny interfejs użytkownika w pełni wykorzysta zalety procesora graficznego. Skoro nie ma już presji czasu, to zapewne ma sens wypracowanie rozwiązania na dłuższą metę. Można więc zaprojektować nowy serwer na bazie OpenGL i cairo.

Ogólnie mówiąc dla takich API jak xlib czy cairo idea programowalnego sprzętu graficznego jest obca. To bardzo istotna uwaga. Ważna nowa cecha procesorów grafiki, programowalność, po prostu nie jest dostępna spod bieżących API X-ów. OpenGL udostępnia ją poprzez język shaderów. 

Zastanawiając się nad nowym serwerem trzeba koniecznie podzielić projekt koncepcyjny na dwie części: zależną i niezależną od platformy. Sterowniki urządzeń są zależne od platformy, ale ponieważ w proponowanym modelu ich rolę pełni OpenGL, to będzie posiadał implementację dla danej platformy. Wszystkie kwestie integracji z innymi podsystemami w Linuksie będą ukryte wewnątrz odpowiednich sterowników. Główny serwer będzie napisany z pomocą wieloplatformowych API, jak gniazda, OpenGL i EGL. Trzeba określić wieloplatformowe API dla urządzeń typu hotplug. Serwer nie powinien być tworzony od zera. Znaczne partie kodu można pobrać z innych projektów i połączyć je na inne sposoby. Wedle mojej oceny 95% lub więcej kodu potrzebnego do napisania nowego serwera już istnieje.

Kluczem do stworzenia dobrego serwera jest modularyzacja. Projekt powinien być podzielony na izolowane biblioteki, które komunikują się przez standardowe interfejsy. Dzięki takiemu podziałowi wymiana biblioteki będzie prosta. Mogą istnieć zupełnie odmienne implementacje danej biblioteki na różnych platformach lub wiele sposobów napisania tej biblioteki na danej platformie. Oczywiście przenośny kod ma swoje zalety. Elementy takie jak biblioteka Mesa mogą być wspólne dla wszystkich obsługiwanych systemów.

Pamiętacie jak DirectFB używa niezamocowanych X-ów? Nowy serwer mógłby udostępniać niezamocowane X-y z programowym wyświetlaniem, aby zachować zgodność wstecz. Model bezpośredniego rysowania z DRI jest dobry i powinien pozostać w przyszłych serwerach. Przeniesienie X-ów do trybu wstecznej zgodności pozwoli na zupełną swobodę w projektowaniu nowego serwera.

Nowy serwer mógłby na przykład mieć nowy protokół sieciowy. Niedawny artykuł z Linux Journal o No Machine i protokole NX pokazuje, że protokół X daje się spakować 200-krotnie lub jeszcze bardziej. Nowy protokół mógłby bazować na OpenGL i unikać opóźnień wynikającego z krążenia danych (round trip) oraz zapewniać trwały (persistent) bufor obrazu. Chromium to ciekawy system pozwalający dzielić obraz wyświetlany przez OpenGL na wiele monitorów połączonych siecią. Jednym ze sposobów ograniczania ruchu w sieci jest śledzenie przez ich bibliotekę sieciową stanu OpenGL.

Bufor glifów także powinien zostać poddany analizie. W obecnym serwerze X klient tworzy mapy bitowe glifów i przesyła je do serwera, gdzie są buforowane. Taki model wyklucza generację glifów przez procesor graficzny, jak to zostało opisane w poprzednio wspomnianym artykule. Czcionki po stronie klienta to dobry pomysł. Program zdecydowanie powinien mieć kontrolę nad układem tekstu. Ale nie ma żadnego realnego powodu, żeby to klient generował bitmapy glifów. W przypadku skalowalnych czcionek tworzonych przez procesor grafiki, do serwera musi trafić więcej danych niż tylko prosta mapa bitowa.

Nowy serwer mógłby załatwić obecne problemy z niedomaganiami sieciowego dźwięku i drukowania. Mógłby zapewnić właściwe pośredniczenie (proxying) wymagane przy ponownym podłączaniu się do sesji. Koniecznie powinien od początku obsługiwać wielu użytkowników.

Obsługa zdarzeń to dobry przykład na wykorzystanie bibliotek. Linux ma evdev, hotplug w jądrze, HAL i D-BUS. Te podsystemy nie są obecne na większości innych platform. Z tego powodu system wejścia w BSD wyglądałby zupełnie inaczej niż w Linuksie. Modularyzacja dużych podsystemów pozwala na ich dopasowanie oraz na pełne wykorzystanie możliwości środowiska w którym działają. To odmienne podejście niż sprowadzanie do najmniejszego wspólnego dla tych platform mianownika.

X-y są wykorzystywane przez różne agencje wywiadowcze na świecie. Wiadomo, że obecny serwer X nie jest wystarczająco bezpieczny do używania z delikatnymi dokumentami. Jeśli ma być wykonana duża praca przy projektowaniu, to powinna od samego początku uwzględniać kwestie bezpieczeństwa. Odpowiednie fundamenty wymagają zadania sobie wiele wysiłku, aby mieć pewność że zostaną zaimplementowane właściwe funkcje.

Na krótszą metę są do wykonania duże zadania i ostatnio rozpoczęły się już prace nad ich wypełnieniem. Najważniejsze to menedżer pamięci dla DRM oraz zmiany umożliwiające korzystanie z FBO (obiektów bufora ramki) w sterownikach DRI. Zaraz po nich w kolejce stoi czyszczenie kodu sterowników fbdev odpowiadających sprzętowi, dla którego istnieją sterowniki DRM. Po wykonaniu pracy u podstaw można się zabierać za projektowanie nowego serwera.

Podsumowanie

Moje doświadczenie z niepowodzeniem Xegl nauczyło mnie, że tworzenie podsystemu grafiki to duże i skomplikowane zadanie, o wiele za duże dla jednej czy dwóch osób. Społeczność X.org jako całość ma zaledwie wystarczającą ilość zasobów aby zbudować jeden serwer. Rozdzielenie tych zasobów na wiele ścieżek daje w rezultacie tylko masę na wpół ukończonych projektów. Wiem, że twórcy wolą pracować nad tym, co ich interesuje, ale przy dostępnych zasobach X.org to podejście nie przyniesie nowego serwera, ani nawet w pełni konkurencyjnego biurka opartego o stary serwer w najbliższym czasie. Być może już czas żeby X.org wypracowało plan, za którym wszyscy będziemy mogli podążyć.

Jon Smirl

30 sierpnia 2005 r.

Jon Smirl
Informatyka

Tłumaczenia Wikiźródeł