Akademia Górniczo-Hutnicza im. Stanisława Staszica w Krakowie. Marcin Rociek. promotor: dr inż. Witold Alda



Podobne dokumenty
Plan wykładu. Akcelerator 3D Potok graficzny

Grafika Komputerowa Wykład 5. Potok Renderowania Oświetlenie. mgr inż. Michał Chwesiuk 1/38

Analiza moż liwości i porównanie nowych ję zyków do programowania grafiki

Programowanie gier komputerowych Tomasz Martyn Wykład 6. Materiały informacje podstawowe

Julia 4D - raytracing

Animowana grafika 3D. Opracowanie: J. Kęsik.

Oświetlenie. Modelowanie oświetlenia sceny 3D. Algorytmy cieniowania.

Implementacja sieci neuronowych na karcie graficznej. Waldemar Pawlaszek

Oświetlenie obiektów 3D

GRK 4. dr Wojciech Palubicki

Laboratorium grafiki komputerowej i animacji. Ćwiczenie V - Biblioteka OpenGL - oświetlenie sceny

Karty graficzne możemy podzielić na:

Widoczność zmiennych Czy wartości każdej zmiennej można zmieniać w dowolnym miejscu kodu? Czy można zadeklarować dwie zmienne o takich samych nazwach?

W naukach technicznych większość rozpatrywanych wielkości możemy zapisać w jednej z trzech postaci: skalara, wektora oraz tensora.

Grafika Komputerowa Wykład 6. Teksturowanie. mgr inż. Michał Chwesiuk 1/23

Filtrowanie tekstur. Kinga Laurowska

1. Prymitywy graficzne

Grafika Komputerowa Wykład 4. Synteza grafiki 3D. mgr inż. Michał Chwesiuk 1/30

Grafika komputerowa i wizualizacja

0. OpenGL ma układ współrzędnych taki, że oś y jest skierowana (względem monitora) a) w dół b) w górę c) w lewo d) w prawo e) w kierunku do

Synteza i obróbka obrazu. Tekstury. Opracowanie: dr inż. Grzegorz Szwoch Politechnika Gdańska Katedra Systemów Multimedialnych

RDZEŃ x86 x86 rodzina architektur (modeli programowych) procesorów firmy Intel, należących do kategorii CISC, stosowana w komputerach PC,

GLKit. Wykład 10. Programowanie aplikacji mobilnych na urządzenia Apple (IOS i ObjectiveC) #import "Fraction.h" #import <stdio.h>

LABORATORIUM 3 ALGORYTMY OBLICZENIOWE W ELEKTRONICE I TELEKOMUNIKACJI. Wprowadzenie do środowiska Matlab

Aproksymacja funkcji a regresja symboliczna

RENDERING W CZASIE RZECZYWISTYM. Michał Radziszewski

która metoda jest najlepsza

Przegląd architektury PlayStation 3

Model oświetlenia. Radosław Mantiuk. Wydział Informatyki Zachodniopomorski Uniwersytet Technologiczny w Szczecinie

Architektura Procesorów Graficznych

GRAFIKA RASTROWA. WYKŁAD 1 Wprowadzenie do grafiki rastrowej. Jacek Wiślicki Katedra Informatyki Stosowanej

Programowanie Strukturalne i Obiektowe Słownik podstawowych pojęć 1 z 5 Opracował Jan T. Biernat

Wykład 4. Rendering (1) Informacje podstawowe

Podstawy Informatyki Systemy sterowane przepływem argumentów

RENDERING W CZASIE RZECZYWISTYM. Michał Radziszewski

Techniki animacji komputerowej

1 Podstawy c++ w pigułce.

PRZEWODNIK PO PRZEDMIOCIE

Architektura komputerów

OpenGL : Oświetlenie. mgr inż. Michał Chwesiuk mgr inż. Tomasz Sergej inż. Patryk Piotrowski. Szczecin, r 1/23

w analizie wyników badań eksperymentalnych, w problemach modelowania zjawisk fizycznych, w analizie obserwacji statystycznych.

PROGRAMOWANIE WSPÓŁCZESNYCH ARCHITEKTUR KOMPUTEROWYCH DR INŻ. KRZYSZTOF ROJEK

Technologie Informacyjne

KRYPTOGRAFIA I OCHRONA DANYCH PROJEKT

Próbny egzamin z matematyki dla uczniów klas II LO i III Technikum. w roku szkolnym 2012/2013

Procesor ma architekturę rejestrową L/S. Wskaż rozkazy spoza listy tego procesora. bgt Rx, Ry, offset nand Rx, Ry, A add Rx, #1, Rz store Rx, [Rz]

Programowanie niskopoziomowe. dr inż. Paweł Pełczyński

Rok akademicki: 2017/2018 Kod: JFM s Punkty ECTS: 7. Poziom studiów: Studia I stopnia Forma i tryb studiów: Stacjonarne

Scenariusz lekcji opartej na programie Program nauczania informatyki w gimnazjum DKW /99

GRAFIKA KOMPUTEROWA. Rozwiązania sprzętowe i programowe. Przyspieszanie sprzętowe. Synteza dźwięku i obrazu

Definicje. Algorytm to:

Podstawy Programowania Obiektowego

Karta graficzna karta rozszerzeo odpowiedzialna generowanie sygnału graficznego dla ekranu monitora. Podstawowym zadaniem karty graficznej jest

SPOSOBY POMIARU KĄTÓW W PROGRAMIE AutoCAD

Zaawansowana Grafika Komputerowa

Bartłomiej Filipek

Wykład z Technologii Informacyjnych. Piotr Mika

Bartosz Bazyluk SYNTEZA GRAFIKI 3D Grafika realistyczna i czasu rzeczywistego. Pojęcie sceny i kamery. Grafika Komputerowa, Informatyka, I Rok

GRAFIKA KOMPUTEROWA. Rozwiązania sprzętowe i programowe. Przyspieszanie sprzętowe. Synteza i obróbka obrazu

Antyaliasing w 1 milisekundę. Krzysztof Kluczek

Metody optymalizacji soft-procesorów NIOS

Technologie informacyjne - wykład 12 -

GRAFIKA KOMPUTEROWA 7: Kolory i cieniowanie

Politechnika Krakowska im. Tadeusza Kościuszki. Karta przedmiotu. obowiązuje studentów rozpoczynających studia w roku akademickim 2013/2014

Analiza obrazów - sprawozdanie nr 2

Automatyczne tworzenie trójwymiarowego planu pomieszczenia z zastosowaniem metod stereowizyjnych

Jak napisać program obliczający pola powierzchni różnych figur płaskich?

CUDA Median Filter filtr medianowy wykorzystujący bibliotekę CUDA sprawozdanie z projektu

Karta przedmiotu. Podstawy programowania procesorów graficznych. realizowanego w ramach projektu PO WER

Budowa Mikrokomputera

Podstawy Programowania C++

Ćwiczenia nr 7. TEMATYKA: Krzywe Bézier a

Zastosowania Robotów Mobilnych

Architektura potokowa RISC

a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] a[10]

5. Rozwiązywanie układów równań liniowych

HDR. Obrazy o rozszerzonym zakresie dynamiki

Synteza i obróbka obrazu HDR. Obrazy o rozszerzonym zakresie dynamiki

Lab 9 Podstawy Programowania

Przetwarzanie obrazów rastrowych macierzą konwolucji

Część 4 życie programu

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

Budowa komputera Komputer computer computare

Zapisywanie algorytmów w języku programowania

Autodesk 3D Studio MAX Teksturowanie modeli 3D

XQTav - reprezentacja diagramów przepływu prac w formacie SCUFL przy pomocy XQuery

Scena 3D. Cieniowanie (ang. Shading) Scena 3D - Materia" Obliczenie koloru powierzchni (ang. Lighting)

Grafika komputerowa. Dla DSI II

Teoria przetwarzania A/C i C/A.

Wymagania edukacyjne z matematyki w klasie III gimnazjum

6 Przygotował: mgr inż. Maciej Lasota

Złożoność obliczeniowa zadania, zestaw 2

ZMODYFIKOWANY Szczegółowy opis przedmiotu zamówienia

Kumulowanie się defektów jest możliwe - analiza i potwierdzenie tezy

SYMULACJA OPADÓW ATMOSFERYCZNYCH I POKRYWY ŚNIEŻNEJ W GENERATORZE OBRAZU JASKIER IG

Instytut Mechaniki i Inżynierii Obliczeniowej Wydział Mechaniczny Technologiczny Politechnika Śląska

PORÓWNANIE TREŚCI ZAWARTYCH W OBOWIĄZUJĄCYCH STANDARDACH EGZAMINACYJNYCH Z TREŚCIAMI NOWEJ PODSTAWY PROGRAMOWEJ

Podstawy OpenCL część 2

Światła i rodzaje świateł. Dorota Smorawa

Architektura komputerów

Transkrypt:

Akademia Górniczo-Hutnicza im. Stanisława Staszica w Krakowie Marcin Rociek Analiza możliwości i porównanie nowych języków do programowania grafiki Na przykładzie C for Graphics i OpenGL 2.0 Shading Language promotor: dr inż. Witold Alda Wydział Elektrotechniki, Automatyki, Informatyki i Elektroniki kierunek: Informatyka 25 czerwca 2003

Streszczenie W ciągu kilku ostatnich lat można zauważyć szczególnie intensywny rozwój technologiczny kart graficznych, które przejmują na siebie coraz większą funkcjonalność w dziedzinie tworzenia obrazu. Dzisiejsze akceleratory graficzne to superszybkie, specjalizowane układy przeznaczone tylko do tego celu. Coraz istotniejszą rolę stanowią w nich programowalne procesory efektów, które umożliwiają tworzenie niespotykanych do tej pory efektów w czasie rzeczywistym. Procesory te mogą wykonywać specjalne krótkie programy tworzone w języku niskiego poziomu. Ponieważ programowanie w języku niskiego poziomu jest uciążliwe i mało elastyczne, podejmowane są kroki w celu stworzenia języków wysokiego poziomu przeznaczonego tylko i wyłącznie do programowania kart graficznych. Pierwszym takim językiem jest Cg (C for Graphics) opracowany przez firmę NVIDIA, drugim zaś język GLslang (OpenGL Shading Language) wchodzący w skład specyfikacji OpenGL 2.0, opracowywany przez firmę 3DLabs. Niniejsza praca przedstawia kryjące się za tymi językami możliwości oraz ich porównanie pod względem tychże możliwości, ich funkcjonalności i dostępności.

Spis treści 1. Nazewnictwo potyczki z językiem polskim............................ 5 2. Wprowadzenie............................................. 6 3. Akceleratory graficzne......................................... 8 3.1. Przykładowa architektura - GeForce 3 (NV20).......................... 8 3.1.1. Technologia........................................ 9 3.1.2. Vertex Shader....................................... 9 3.1.3. Przykłady......................................... 13 3.1.3.1. Iloczyn wektorowy.............................. 13 3.1.3.2. Wartość bezwzględna............................. 14 3.1.3.3. Dzielenie skalarów.............................. 14 3.1.3.4. Normalizacja wektora............................. 14 3.1.3.5. Kompletny program.............................. 15 3.1.4. Pixel Shader....................................... 15 3.2. Kolejne modele GeForce..................................... 17 3.2.1. GeForce 4 (NV25).................................... 17 3.2.2. GeForce FX (NV30)................................... 18 3.2.2.1. Vertex Shader................................. 18 3.2.2.2. Pixel Shader.................................. 18 4. Protoplaści i inne rozwiazania.................................... 22 4.1. Rendering offline: RenderMan Shading Language........................ 22 4.2. Rendering w czasie rzeczywistym................................ 25 4.2.1. Stanford Shading Language............................... 25 4.2.2. SGI Interactive Shading Language............................ 26 4.2.2.1. OpenGL Shader Software Development Kit................. 27 4.2.3. PixelFlow Shading Language.............................. 28 4.2.3.1. Dedykowany sprzęt.............................. 28 4.2.3.2. Język...................................... 28 5. C for Graphics Cg......................................... 29 5.1. Składnia.............................................. 29 5.2. Model programowania...................................... 29 5.3. Profile............................................... 30 5.3.1. Deklaracja programów w Cg............................... 31 5.4. Dane wejściowe i wyjściowe programu............................. 31 5.4.1. Rodzaje danych wejściowych.............................. 31 5.4.1.1. Zmienne dane wejściowe z fragment shadera................. 32 5.4.1.2. Zmienne dane wyjściowe z fragment shadera................. 33 5.4.2. Dane w Cg........................................ 33 5.4.2.1. Typy proste.................................. 34 5.4.2.2. Konwersja typów danych........................... 34 5.4.2.3. Struktury.................................... 35

Spis treści 3 5.4.2.4. Tablice..................................... 35 5.4.3. Instrukcje sterujace i operatory.............................. 35 5.4.3.1. Instrukcje sterujace.............................. 35 5.4.3.2. Definiowanie oraz przeciażanie funkcji.................... 36 5.4.3.3. Operatory arytmetyczne............................ 36 5.4.3.4. Funkcje mnożace............................... 36 5.4.3.5. Konstruktor wektora.............................. 37 5.4.3.6. Operatory logiczne oraz porównujace..................... 37 5.4.3.7. Operator mieszania.............................. 37 5.4.3.8. Operator maskowania zapisu......................... 38 5.4.3.9. Operator warunkowy............................. 38 5.4.3.10. Próbkowanie tekstur.............................. 38 5.5. Dostępne funkcje......................................... 39 5.5.1. Funkcje matematyczne.................................. 39 5.5.2. Funkcje geometryczne.................................. 41 5.5.3. Funkcje próbkujace tekstury............................... 41 5.5.4. Funkcje pochodne.................................... 43 5.6. Biblioteka Runtime........................................ 43 5.6.1. Zalety........................................... 43 5.6.2. Składowe......................................... 44 5.6.3. Przykład wykorzystania z poziomu OpenGL...................... 44 6. OpenGL 2.0 Shading Language GLslang............................. 47 6.1. OpenGL obecnie......................................... 47 6.2. GLslang.............................................. 48 6.3. Motywacja twórców....................................... 48 6.4. Założenia projektowe GLslang.................................. 48 6.5. Procesor wierzchołków (vertex processor)............................ 49 6.6. Procesor fragmentów....................................... 50 6.7. Zmienne i typy danych...................................... 53 6.7.1. Podstawowe typy danych................................. 53 6.7.2. Struktury......................................... 53 6.7.3. Tablice.......................................... 54 6.7.4. Zakres widoczności zmiennych............................. 54 6.7.5. Kwalifikatory typów................................... 54 6.7.5.1. Domyślne kwalifikatory............................ 54 6.7.5.2. const..................................... 54 6.7.5.3. Wyrażenia stałe................................ 55 6.7.5.4. Atrybuty.................................... 55 6.7.5.5. Zmienne jednolite............................... 55 6.7.5.6. Zmienne varying............................... 55 6.8. Wyrażenia............................................. 56 6.8.1. Dostęp do tablic..................................... 56 6.8.2. Konstruktory....................................... 56 6.8.2.1. Konwersje typów skalarnych......................... 56 6.8.2.2. Konstruktory wektorów i macierzy...................... 56 6.8.2.3. Konstruktory struktur............................. 57 6.8.3. Składniki wektora.................................... 57 6.8.4. Składniki macierzy.................................... 58 6.8.5. Struktury i pola...................................... 58 6.8.6. Operacje na wektorach i macierzach........................... 58

Spis treści 4 6.8.7. Instrukcje i struktura programu.............................. 59 6.8.7.1. Definicje funkcji................................ 59 6.8.7.2. Wywoływanie funkcji............................. 60 6.8.7.3. Instrukcje sterujace.............................. 60 6.9. Wbudowane zmienne....................................... 61 6.9.1. Specjalne zmienne vertex shadera............................ 61 6.9.2. Specjalne zmienne Fragment Shadera.......................... 61 6.9.3. Wbudowane atrybuty vertex shadera........................... 62 6.9.4. Wbudowane stałe..................................... 62 6.9.5. Wbudowane stany jednolite............................... 62 6.9.6. Wbudowane zmienne varying.............................. 63 6.10. Wbudowane funkcje....................................... 64 6.10.1. Funkcje trygonometryczne................................ 64 6.10.2. Funkcje wykładnicze................................... 65 6.10.3. Funkcje ogólne...................................... 65 6.10.4. Funkcje geometryczne.................................. 65 6.10.5. Funkcje macierzowe................................... 66 6.10.6. Funkcje porównujace wektory.............................. 66 6.10.7. Funkcje próbkujace tekstury............................... 67 6.10.8. Funkcje wspierajace przetwarzanie fragmentów..................... 68 6.10.9. Funkcje stochastyczne.................................. 69 7. Porównanie............................................... 70 7.1. Położenie pomiędzy aplikacja a sprzętem............................ 70 7.2. Składnia.............................................. 71 7.3. Przekazywanie parametrów.................................... 72 7.4. Dostęp do stanów OpenGL.................................... 73 7.5. Dostępność............................................ 73 7.6. Konkluzje............................................. 74 8. Przykładowy program dla GPU................................... 75 Literatura.................................................. 82 Spis rysunków............................................... 83

1. Nazewnictwo potyczki z językiem polskim Prawdopodobnie każda specjalistyczna dziedzina boryka się z trudnościami natury językowej, gdy zachodzi potrzeba zastosowania w tekście terminów jeszcze nie przetłumaczonych bądź wręcz nieprzetłumaczalnych. Trudności te wzrastają niewspółmiernie w przypadku tak dynamicznie rozwijającej się dziedziny jaką jest informatyka. Jakkolwiek język nasz jest kwiecisty, uniemożliwia niestety stosowanie zwartych konstrukcji językowych, tak popularnych w języku angielskim, niewymagających długich opisów wyjaśniających ich znaczenie. Jest niezwykle prawdopodobne, iż z punktu widzenia czystości językowej również niniejsza praca może razić swoistym językowym kalectwem, lecz takie właśnie są uroki informatyki. Przede wszystkim problem stwarza novum jakim jest przedmiot rozważań niniejszej pracy, czyli vertex shader i jego brat pixel shader, a właściwie poprawniej fragment shader. Choć wiadomo, że vertex to wierzchołek (a nie werteks), a pixel to zadomowiony już w języku polskim piksel, to jednak trudno w dwóch słowach zawrzeć to, że jest to coś, co cieniuje wierzchołki. W zasadzie nawet mówienie o cieniowaniu nie byłoby zbyt precyzyjne ani ścisłe, jako że patrząc z punktu widzenia funkcjonalności, vertex shader może znacznie więcej niż tylko cieniować wierzchołki. Wynika z tego, że nawet jego angielska nazwa nie jest zbyt fortunna, istnieje wszakże bardziej ogólne określenie vertex program. W pracy tej przyjęto konwencję (która może być odebrana jako brak konwencji), stosowania w zależności od kontekstu zarówno anglojęzycznych określeń vertex shader, vertex program jak i spolszczonego procesor wierzchołków (np. w odniesieniu stricte do sprzętu).

2. Wprowadzenie W ciągu wielu lat prac nad generowaną grafika komputerową istniały niejako dwa główne tory rozwoju: jeden z nich skupiał się na interaktywności, drugi zaś na jakości obrazu. Interaktywna grafika to przede wszystkim gry komputerowe. Te najdynamiczniejsze i najbardziej zaawansowane wizualnie, aby generować obraz w czasie rzeczywistym potrzebują z reguły najszybszych dostępnych na rynku maszyn i kart graficznych. Producenci kart prześcigają się w rozwiązaniach technologicznych, stale zwiększając szybkość i funkcjonalność procesorów umieszczonych na kartach. O ile szybkość tych procesorów zwiększa się mniej więcej wykładniczo to w przypadku udostępnianej funkcjonalności, jej przyrosty następują skokowo. Jednym z większych skoków jeśli nie największym było umożliwienie wprowadzania do karty graficznej krótkich programów uruchamianych dla każdego wierzchołka przekształcanego obiektu 3D, oraz takich uruchamianych dla każdego piksela rysowanego obrazu. Krótko mówiąc karty graficzne stały się programowalne. Znaczenie tej rewolucji może uzmysłowić fakt, że wcześniej karta graficzna była dla programisty czarna skrzynką z mnóstwem przełączników i pokręteł, których z czasem przybywało coraz więcej. Grafika komputerowa przedkładająca jakość nad interaktywność to przede wszystkim film. Czas rysowania jednej klatki animacji może być bardzo długi a wykorzystywany sprzęt to z reguły duże komputery lub klastry. W tym przypadku stosowane są różne techniki proceduralne, do których zalicza się m.in. RenderMan. Umożliwia on opisywanie wyglądu powierzchni za pomocą krótkich programów tworzonych w języku wysokiego poziomu. Programy te wykonywane są dla każdego piksela rysowanego obrazu i wyliczają jego kolor na podstawie informacji o materiale, z którego zbudowana jest dana powierzchnia. Tymczasem moc obliczeniowa kart graficznych zbliżyła się do takiego poziomu, w którym stało się możliwe stosowanie technik takich jak RenderMan w grafice czasu rzeczywistego. Potrzebny stał się język wysokiego poziomu, który pozwoliłby w prosty sposób oprogramować karty graficzne. W ten właśnie sposób doszło do powstania języków Cg i GLslang (rys. 2.1). Cg został opracowany przez firmę NVIDIA i po raz pierwszy udostępniony w wersji beta w czerwcu 2002, natomiast pierwsza oficjalna wersja dopiero w grudniu 2002. GLslang opracowywany jest przede wszystkim przez firmę 3Dlabs, lecz ostateczna specyfikacja OpenGL 2.0 nie została jeszcze ukończona. Języki te nie są tak ogólne jak C czy C++, gdyż procesory graficzne nie osiągnęły jeszcze takiego stopnia ogólności. Z drugiej zaś strony już na poziomie języka definiują bardzo specyficzne cechy dostępne właśnie w procesorach graficznych, np. wektorowe typy danych.

2. Wprowadzenie 7 Programowalne shadery w kartach graficznych Języki wysokiego poziomu do programowania sprzętowych shaderów (Cg, GLslang) Shadery programowe wysokiego poziomu Rysunek 2.1: Cg i GLslang jako naturalna konsekwencja skrzyżowania się technologii sprzętowej i istniejących wcześniej rozwiązań programowych

3. Akceleratory graficzne Gwałtowny rozwój wydajności kart graficznych do zastosowań domowych rozpoczął się w roku 1995 wraz z wprowadzeniem przez firmę 3dfx pierwszych modeli kart serii Voodoo. Proces ciągłego polepszania się wydajności powodował że można było podziwiać coraz bardziej skomplikowaną i dynamiczną grafikę generowaną w czasie rzeczywistym najczęściej w postaci gier. Niestety u podstaw działania akceleratorów graficznych leżało podstawowe ograniczenie jakim była zależność od zdefiniowanych na stałe funkcji, które te karty udostępniały. Sprowadzało się to do tego, że projektanci kart graficznych umieszczali w kości pewną ilość specyficznych algorytmów graficznych, a projektanci gier i programów wykorzystujących zaawansowane możliwości sprzętu byli ograniczeni możliwością korzystania tylko z tych specyficznych, zdefiniowanych na stałe algorytmów. Wprowadzane w ostatnim czasie modele programowalnych kart graficznych zmieniają ten wizerunek. Tani sprzęt powszechnego użytku osiągnął taki poziom złożoności, że możliwe stało się programowanie oświetlenia techniką shaderów, działającego w czasie rzeczywistym. Wcześniej metoda opisywania modelu oświetlenia shaderami stosowana była głównie na potrzeby aplikacji renderujących grafikę offline, np. w wykorzystywanym na potrzeby przemysłu filmowego RenderManie firmy Pixar. W ciągu ostatnich kilku lat przemysł kart graficznych przeszedł kilka znacznych przemian w wydajności sprzętu oraz sposobie jego działania. Wydajność GPU rośnie dużo szybciej niż CPU, osiągając obecnie poziom, w którym procesor graficzny umieszczony na karcie musi bezczynnie czekać na dane przychodzące z głównego procesora. Kolejne przemiany dokonały się w sposobie działania sprzętu: karty graficzne wyewoluowały od postaci biernego bufora ramki, w której grafika w całości tworzona była przez CPU. Następna era kart potrafiła już sama rysować linie i wielokąty, a dzisiejsze GPU posiadają w pełni programowalne procesory, zwielokrotnione jednostki przekształcające geometrię, w pełni sprzętowe oświetlenie kilkoma źródłami światła, sprzętowy antyaliasing itd. Jest to przejście od stanu w którym całą pracę wykonywał CPU, do postaci w której GPU wykonuje niemal wszystko co potrzebne do renderowania skomplikowanej sceny 3D w czasie rzeczywistym. Z nastaniem ery wysoce programowalnych procesorów graficznych, programiści gier otrzymali potężne narzędzie pozwalające na tworzenie wyróżniającego się stylu aplikacji nie tylko poprzez ilustrację graficzna, lecz również na poziomie programu. Własne modele oświetlenia, złożone materiały, obróbka bufora ramki - to dopiero początek eksploracji nowych możliwości. 3.1. Przykładowa architektura - GeForce 3 (NV20) Przykładowa architektura programowalnej karty graficznej omówiona zostanie na przykładzie karty GeForce3 firmy NVIDIA. Wybór tej karty jako architektury bazowej podyktowany jest dwoma względami: 1. GeForce3 była pierwszą kartą w której NVIDIA umieściła programowalne jednostki Vertex Shader i Pixel Shader niewątpliwie gigantyczny skok technologiczny w porównaniu z wcześniejszymi kartami tej firmy.

3. Akceleratory graficzne 9 2. Autor niniejszej pracy jest w posiadaniu takiej karty, w związku z czym wszelkie rzeczywiste przykłady programowania kart będą odnosiły się właśnie do GeForce3 i na tej karcie będą przeprowadzane. 3.1.1. Technologia Na początek słów kilka o danych znamionowych GeForce3: Technologia 0 15µm 57 milionów tranzystorów 4 potoki pikseli 2 tekstury na piksel Maksymalnie 4 aktywne tekstury na piksel w jednym przebiegu 36 operacji cieniowania pikseli w jednym przebiegu 128 instrukcji Vertex Shadera w jednym przebiegu Częstotliwość taktowania zegara rdzenia procesora karty: 200MHz Częstotliwość taktowania pamięci karty: 230MHz (DDR) Bufor ramki: 64MB Obsługiwana pamięć: SDR lub DDR Szerokość szyny pamięci: 128 bitów 3.1.2. Vertex Shader Jednym z najistotniejszych elementów GeForce3 jest programowalna jednostka Vertex Shader, okupująca większą część z 32 milionów tranzystorów o które karta jest bogatsza od swojej poprzedniczki GeForce 2. Vertex Shader pozwala twórcom aplikacji 3D na tworzenie specjalnych krótkich programów, które zaaplikowane do poszczególnych wierzchołków obiektów trójwymiarowych modyfikują odpowiednio parametry związane z wierzchołkami. Ponieważ programy te wykonywane są przez sam procesor karty, powoduje to drastyczne zwiększenie wydajności aplikacji z kilku powodów: procesor karty jest skonstruowany tylko i wyłącznie do tego celu, w związku z czym jest niezwykle wydajny; typem danych procesora karty są czterowymiarowe wektory, powszechnie stosowane w przetwarzaniu grafiki 3D; główny procesor komputera jest odciążony z obliczeń i jego moc może być w wydajniejszy sposób wykorzystana do obliczeń na poziomie wyższym niż pojedyncze wierzchołki. Idealnym rozwiązaniem jest rzecz jasna maksymalne zrównoważenie obciążenia pomiędzy głównym procesorem a procesorem karty. Pisanie aplikacji w sposób dotychczasowy, czyli niewykorzystywanie możliwości specjalizowanego sprzętowego Vertex Shadera jest po prostu marnowaniem zasobów sprzętowych. Z drugiej zaś strony bezsensowne może być zwalanie na siłę całej roboty na Vertex Shader, kiedy pewne obliczenia mogą być wykonane przez główny procesor. Wydajność karty graficznej nie jest studnią bez dna, do której można bez zastanowienia wysyłać dowolne ilości rysowanych obiektów. Jak pokazuje czas, wydajność rośnie niewiarygodnie szybko w kolejnych modelach. Każdy przetwarzany wierzchołek może przenosić znaczna ilość parametrów, z których wymienić można m.in: współrzędne w przestrzeni, waga, wektor normalny, kolor,

3. Akceleratory graficzne 10 współrzędne w teksturze, współczynnik mgły, wielkość punktu, itd. Vertex Shader pozwala na dowolne modyfikacje tych informacji za pomocą krótkich programów wykonywanych przez sam Vertex Shader, nie wymagając mocy obliczeniowej CPU. W klasycznym podejściu tworzenia aplikacji wykorzystującym sprzętowe przekształcanie i oświetlenie T&L (Transform & Lighting) programista był ograniczony do wpływania na to co się dzieje tylko do momentu w którym potok 3D osiągał etap przekształceń. Wykorzystując Vertex Shader można wpływać w zupełnie dowolny sposób na obiekty 3D bez obciążania CPU. Możliwości są dość spore: program wykonywany przez Vertex Shader może modyfikować np. położenie wierzchołka, modyfikując w ten sposób kształt obiektu w celu uzyskania realistycznego ruchu, deformacji itd. Modyfikując kolor wierzchołka lub współrzędne tekstury można wpływać na wygląd powierzchni obiektu. Podstawowym ograniczeniem jest długość programu, która nie może przekraczać 128 instrukcji. Rzecz jasna czas jego wykonania jest również znaczacy dla ogólnej wydajności aplikacji. Dane wejściowe 128 bitów 4 float 16 pozycji Pamięć stałych Rejestry 128 bitów 4 float 12 pozycji Vertex Shader 128 instrukcji A0 adres dana 128 bitów 4 float Dane wyjściowe 128 bitów 4 float 96 pozycji 15 pozycji Rysunek 3.1: Architektura Vertex Shadera w GeForce3 Rysunek 3.1 przedstawia schematyczną strukturę Vertex Shadera. Jak widać Vertex Shader może dokonywać obliczeń na wierzchołkach przenoszących maksymalnie 16 parametrów wejściowych. Każdy z nich jest wektorem składającym się z czterech 32-bitowych liczb zmiennoprzecinkowych. W tych 16 parametrach można z dużą swobodą zmieścić współrzędne wierzchołka, wagę, wektor normalny, współczynniki rozpraszania światła, mgły oraz kilka współrzędne w kilku teksturach. float float float float x y z w 4 float = 4 32 bity = 128 bitów Rysunek 3.2: Format danych Vertex Shadera GeForce3 Sam Vertex Shader operuje bezpośrednio na danych w postaci 128-bitowych słów, składających się z czterech 32-bitowych liczb zmiennoprzecinkowych (rys. 3.2). Jest on więc procesorem SIMD

3. Akceleratory graficzne 11 (Single Instruction Multiple Data), ponieważ każda instrukcja operuje na zestawie czterech równoległych zmiennych. Jest to rozwiązanie idealne dla grafiki 3D, w której większość operacji przekształcania i oświetlania wykorzystuje macierze 3 3 lub 4 4. Ponieważ każda zmienna traktowana jest jako liczba zmiennoprzecinkowa, widać że każda operacja wykonywana przez Vertex Shader jest w rzeczywistości obliczeniem zmiennoprzecinkowym. Vertex Shader jest tak naprawdę bardzo wydajnym FPU typu SIMD. Kolejnym składnikiem Vertex Shadera jest zestaw 12 rejestrów ogólnego przeznaczenia, z których każdy może przechowywać 4 32-bitowe liczby float. Rejestry te mogą być używane zarówno do zapisu jak i do odczytu. Poza wymienionymi rejestrami ogólnego przeznaczenia Vertex Shader ma dostęp do zbioru 96 stałych (4 32 bity), które są wypełnione parametrami zdefiniowanymi przez aplikację zanim program Vertex Shadera jest uruchomiony. Typowym wykorzystaniem tych parametrów jest przekazanie do programu macierzy przekształceń (zwykle o wymiarach 4 4), charakterystyki modelu oświetlenia, danych wykorzystywanych w animacji itd. Same instrukcje Vertex Shadera są w miarę proste i zrozumiałe. Vertex Shader nie dopuszcza żadnych pętli, skoków czy rozgałęzień kodu. Oznacza to tyle, że program wykonywany jest liniowo, instrukcja po instrukcji. Program może się składać maksymalnie z 128 instrukcji. Po wykonaniu się programu, wierzchołek powinien zostać przekształcony zgodnie z intencjami twórcy programu, powinien być już też przekształcony i oświetlony. Wynikiem działania programu wykonanego przez Vertex Shader jest wierzchołek przekształcony do przestrzeni jednorodnej i oświetlony. Istotne jest to, że Vertex Shader nie jest w stanie tworzyć wierzchołków ani ich usuwać: jeśli przetwarzany jest jeden wierzchołek, to na wyjściu dostajemy dokładnie jeden wierzchołek. W tablicach 3.1 oraz 3.2 zestawiono instrukcje Vertex Shadera dostępne w GeForce3. Instrukcja Argumenty Opis nop - brak operacji mov dest, src dest = src mul dest, src1, src2 Mnożenie przez siebie każdego składnika wektorów: dest = src1*src2 add dest, src1, src2 Dodawanie wektorów: dest = src1 + src2 Przy pomocy opcjonalnej negacji można uzyskać operację odejmowania. mad dest, src1, src2, src3 dest = src1*src2 + src3 rsq dest, src Odwrotność pierwiastka kwadratowego: dest.x = dest.y = dest.z = dest.w = 1/sqrt(src.w) dp3 dest, src1, src2 3-składnikowy iloczyn skalarny dest.x = dest.y = dest.z = dest.w = src1.x*src2.x + src1.y*src2.y + src1.z*src2.z dp4 dest, src1, src2 4-składnikowy iloczyn skalarny dest.w = src1.x*src2.x + src1.y*src2.y + src1.z*src2.z + src1.w*src2.w Tablica 3.1: Instrukcje Vertex Shadera GeForce3 (1/2)

3. Akceleratory graficzne 12 Instrukcja Argumenty Opis dst dest, src1, src2 Obliczenie wektora odległości. Jeśli src1 jest wektorem (, d d, d d, ) a src2 jest wektorem (, 1 d,, 1 d) to w dest otrzymujemy (1, d, d d, 1 d): dest.x = 1 dest.y = src1.y*src2.y dest.z = src1.z dest.w = src2.w lit dest, src Obliczenie współczynników oświetlenia. Jeśli src.x = N L (N wektor normalny, L wektor światła), src.y = N H (H wektor połówkowy), src.z = power (z przedziału od 128 do 128) to dokonywana jest następujaca operacja: dest.x = 1.0; dest.y = max(src.x, 0.0, 0.0); dest.z = 0.0; if (src.x > 0.0 && src.w == 0.0) dest.z = 1.0; else if (src.x > 0.0 && src.y > 0.0) dest.z = (src.y)^src.w dest.w = 1.0; min dest, src1, src2 Minimum max dest, src1, src2 Maksimum slt dest, src1, src2 Sprawdzenie, czy src1 < src2: dest = (src1 < src2)? 1 : 0 sge dest, src1, src2 Sprawdzenie, czy src1 <= src2: dst = (src1 >= src2)? 1 : 0 expp dest, src.w dest.x = 2^(int)src.w dest.y = mantissa(src.w) dest.z = 2^src.w dest.w = 1.0 log dest, src.w dest.x = exponent((int)src.w) dest.y = mantissa(src.w) dest.z = log2(src.w) dest.w = 1.0 rcp dest, src.w Odwrotność skalara dest.x=dest.y=dest.z=dest.w=1/src Tablica 3.2: Instrukcje Vertex Shadera GeForce3 (2/2)

3. Akceleratory graficzne 13 Vertex Shader oferuje ponadto bardzo ciekawą i praktyczną możliwość prostego mieszania poszczególnych składników wektora i ich negacji. Przykładowo jeśli rejestr r2 zawiera wektor (7, 3, 6, 2) to wykonanie instrukcji mov r1, r2.yzwx spowoduje wypełnienie rejestru r1 wartościami (3, 6, 2, 7), czyli składnikami rejestru r2 w zmienionej kolejności (rys. 3.3). Parametry x, y, z i w oznaczaja odpowiednio kolejne składniki wektora przechowywanego w rejestrze. Jeśli dodatkowo przed rejestrem źródłowym postawimy znak to zmieniony zostanie znak liczb przechowywanych w rejestrze. Wykonanie instrukcji mov r1, -r2.yzzx spowoduje więc wypełnienie rejestru r1 wartościami (-3, -6, -6, -7) (rys. 3.3). Istnienie operatora umożliwiającego w prosty sposób dokonać opcjonalnego odwrócenia znaku wektora powoduje m.in. brak konieczności istnienia instrukcji odejmującej wektory, która może być z powodzeniem zastąpiona instrukcją dodawania, np. w taki sposób: add r0, r1, -r2. mov r1, r2.yzwx mov r1, -r2.yzzx przed po r1 r2 r1 r2 przed po r1 r2 r1 r2 0,0 x 7,0 x 3,0 x 7,0 x 0,0 x 7,0 x -3,0 x 7,0 x 0,0 y 3,0 y 6,0 y 3,0 y 0,0 y 3,0 y -6,0 y 3,0 y 0,0 z 6,0 z 2,0 z 6,0 z 0,0 z 6,0 z -6,0 z 6,0 z 0,0 w 2,0 w 7,0 w 2,0 w 0,0 w 2,0 w -7,0 w 2,0 w Rysunek 3.3: Przykłady żonglowania składnikami rejestrów źródłowych oraz ich negacji Stosowanie przyrostków x, y, z, w przy rejestrach docelowych umożliwia maskowanie zapisu do rejestru. W ten sposób można określić, które składniki docelowego rejestru mają być zmodyfikowane: r1 r1.x r1.xw Zapis do całego rejestru r1 Zapis jedynie składnika x Zapis składników x i w 3.1.3. Przykłady Poniżej zostanie przedstawione kilka prostych przykładów obrazujących podstawowe możliwości instrukcji vertex shadera oraz przykładowy kompletny program. 3.1.3.1. Iloczyn wektorowy Iloczyn wektorowy dwóch trójwymiarowych wektorów definiowany jest w sposób następujący: a i j k b a x a y a z a y b z a z b y a z b x a x b z a x b y a y b x b x b y b z Do wykonania tej operacji vertex shader potrzebuje tylko dwóch instrukcji. Zakładając, że wektory znajdują się w rejestrach r1 i r2, kod który obliczy ich iloczyn wektorowy i wynik umieści w rejestrze r0 wygląda następująco: mul r0, r1.yzxw, r2.zxyw mad r0, -r2.yzxw, r1.zxyw, r0

3. Akceleratory graficzne 14 Działa to w sposób następujący: pierwsza instrukcja (mul) mnoży przez siebie odpowiednie składniki rejestrów r1 i r2, a wynik umieszcza w rejestrze r0: r0.x = r1.y*r2.z r0.y = r1.z*r2.x r0.z = r1.x*r2.y r0.w = r1.w*r2.w Następnie instrukcja mad mnoży przez siebie podane składniki rejestrów r2 i r1 oraz dodaje zawartość rejestru r0. Wynik umieszczony w rejestrze r0 jest iloczynem wektorowym wektorów znajdujących się w rejestrach r1 i r2: r0.x = -r2.y*r1.z + r0.x = -r2.y*r1.z + r1.y*r2.z r0.y = -r2.z*r1.x + r0.y = -r2.z*r1.x + r1.z*r2.x r0.z = -r2.x*r1.y + r0.z = -r2.x*r1.y + r1.x*r2.y r0.w = -r2.w*r1.w + r0.w = -r2.w*r1.w + r1.w*r2.w = 0 3.1.3.2. Wartość bezwzględna Do obliczenia wartości bezwzględnej można wykorzystać instrukcję max: # r0 = r1 max r0, r1, -r1 3.1.3.3. Dzielenie skalarów Z powodu braku instrukcji dzielenia, do operacji dzielenia skalarów należy wykorzystać instrukcję rcp obliczającą odwrotność skalara: # r0.x = r1.x/r2.x rcp r0.x, r2.x mul r0.x, r1.x, r0.x 3.1.3.4. Normalizacja wektora Normalizacja wektora to stworzenie wektora o takim samym kierunku i długości równej 1 (wersora) poprzez podzielenie wektora przez jego długość: n v v 2 x v 2 y v 2 z Wykonanie tej operacji to tylko trzy instrukcje vertex shadera. Zakładając, że oryginalny wektor znajduje sie w rejestrze r1, a docelowy w rejestrze r0, kod przedstawia się następująco: dp3 r0.w, r1, r1; rsq r0.w, r0.w; mul r0.xyz, r1, r0.w;

3. Akceleratory graficzne 15 3.1.3.5. Kompletny program Program ten przekształca współrzędne wierzchołka do układu związanego z obserwatorem (czynność taką powinien wykonać każdy vertex program). Ponadto obliczany jest kolor wierzchołka. W celu poprawnego działania wymaga zainicjowania rejestrów stałych następującymi wartościami: c[0-3] macierz przekształceń i projekcji c[4-7] odwrócona i transponowana macierz przekształceń c[32] wektor w kierunku źródła światła (L) c[33] wektor połówkowy (H) c[35].x jasność obiektu (diffuse) c[35].y jasność otoczenia (ambient) c[36] jasność odblasku (specular) c[38].x wielkość odblasku Treść programu:!!vp1.0 # przekształcenie współrzędnych dp4 o[hpos].x, c[0], v[opos]; dp4 o[hpos].y, c[1], v[opos]; dp4 o[hpos].z, c[2], v[opos]; dp4 o[hpos].w, c[3], v[opos]; # obliczenie wektora normalnego N dp3 r0.x, c[4], v[nrml]; dp3 r0.y, c[5], v[nrml]; dp3 r0.z, c[6], v[nrml]; dp3 r1.x, c[32], r0; # r1.x = L o N dp3 r1.y, c[33], r0; # r1.y = H o N mov r1.w, c[38].x; lit r2, r1; # obliczenie współczynników oświetlenia mad r3, c[35].x, r2.y, c[35].y; # diffuse + ambient mad o[col0].xyz, c[36], r2.z, r3; # + specular end 3.1.4. Pixel Shader Wierzchołki sceny 3D po opuszczeniu Vertex Shadera są już odpowiednio przekształcone i oświetlone. Następnym etapem jest odrzucenie tych elementów (trójkątów), które nie znajdą się w rysowanym obszarze oraz tych, które są odwrócone tyłem do kamery. Wreszcie współrzędne X i Y wierzchołków są mapowane na współrzędne ekranowe. Następuje etap przygotowania trójkątów do narysowania i w tym właśnie momencie kończy się życie wierzchołków w przestrzeni 3D a zaczyna tworzenie poszczególnych pikseli tworzących rysowany obraz. Przygotowanie trójkątów polega na wyznaczeniu dla każdego rysowanego trójkąta parametrów potrzebnych do rasteryzacji każdej z linii trójkąta. Polega to na tym, że dla każdej rysowanej linii

3. Akceleratory graficzne 16 trójkąta wyznaczane zostają współrzędne pierwszego oraz ostatniego piksela w linii (rys. 3.4), oraz parametry skojarzone z tymi pikselami. Rysunek 3.4: Przygotowanie trójkąta i jego rasteryzacja. Następnie następuje etap rasteryzacji, w którym dla każdej rysowanej linii trójkąta dokonywana jest interpolacja koloru, głębokości oraz współrzędnych w teksturze pomiędzy wartościami brzegowymi danej linii. Wszystkie te parametry mogą być potem wykorzystywane przez Pixel Shader dla każdego rysowanego piksela. Na tym etapie trójkąt istnieje już tylko w przestrzeni 2D, przy czym z każdym pikselem skojarzona jest wartość głębokości Z, interpolowana przez rasteryzator pomiędzy wartościami Z w wierzchołkach trójkąta. Linie pikseli reprezentujące trójkąt przesyłane są następnie do jednostki renderującej piksele, w przypadku GeForce3 do Pixel Shadera. To Pixel Shader jest odpowiedzialny za generowanie pikseli, które wyświetlane są na ekranie w czasie działania aplikacji 3D. Łączy on kolor oraz informacje o oświetleniu z danymi z tekstur tak, aby stworzyć końcowy kolor każdego piksela. Pixel Shader Rysunek 3.5: Pixel Shader w potoku renderującym. Schemat przedstawiony na rysunku 3.5 w uproszczony sposób przedstawia funkcjonalność Pixel Shadera. Może on wykonać dowolnie programowalne operacje adresowania maksymalnie 4 tekstur, po których może wykonać do 8 dowolnie programowalnych instrukcji mieszających kolor piksela z danymi pobranymi z tych 4 różnych tekstur. Po tych operacjach następuje dodanie oświetlenia, mgły oraz przeźroczystości. Program Pixel Shadera może składać się maksymalnie z 12 instrukcji, z których 4 to instrukcje pobierające kolor z tekstury, zaś pozostałe 8 to instrukcje mieszające kolory. Ponieważ Pixel Shader przetwarza dane po ich przejściu przez Vertex Shader, możliwe jest przekazanie parametrów z Vertex Shadera do Pixel Shadera. Program Pixel Shadera może składać się z trzech typów instrukcji: 1. Definiowanie stałych parametrów w rejestrach c0..c7, 2. Maksymalnie 4 instrukcje pobierające kolor z tekstury, 3. Maksymalnie 8 instrukcji łączacych ze sobą kolory stałe, kolory pikseli oraz kolory pobrane z tekstury, tworzące w ten sposób wynikowy kolor oraz przeźroczystość. Zestaw instrukcji Pixel Shadera przedstawiono w tablicach 3.3 (instrukcje próbkujące tekstury) oraz 3.4 (instrukcje mieszające kolory).

3. Akceleratory graficzne 17 Rejestry koloru Współrzędne w teksturze TC0 TC1 TC2 TC3 Stany tekstury Rejestry tekstur v0 v1 Rejestry stałych c0 TEXOP TEX0 t0 c1 TEXOP Operacje na danych z tekstur TEXOP TEXOP TEX1 TEX2 TEX3 t1 t2 t3 Pixel Shader ALU c2 c3... c7 Rejestry wyjś! #"$% r0 r1 Rysunek 3.6: Pixel Shader (1.1 1.3) logiczny przepływ danych. 3.2. Kolejne modele GeForce Rzecz jasna ani NVIDIA ani inni producenci z branży nie śpią i trudno byłoby się nie spodziewać kolejnych lepszych i szybszych kart. W rozdziale niniejszym skrótowo opisane zostaną następcy GeForce 3, kolejne produkty firmy NVIDIA przeznaczone do zastosowań domowych: GeForce 4 i GeForce FX. 3.2.1. GeForce 4 (NV25) W zasadzie GeForce 4 można bardziej nazwać rozwiązaniem ewolucyjnym niż rewolucyjnym w porównaniu do GeForce 3. Jest to jednak dość typowe dla tej firmy zachowanie: najpierw wydanie produktu niosącego dużą ilość nowych technologii, a następnie jego ulepszonego i zoptymalizowanego wariantu. Przykładami wcześniejszych takich par są np. Riva TNT & Riva TNT2 oraz GeForce 256 & GeForce 2. Regułą jest to, że właśnie te poprawione i ulepszone warianty ciesza się dużo większym powodzeniem. Z punktu widzenia Vertex i Pixel Shaderów, zmiany w GeForce 4 są raczej niewielkie w stosunku do GeForce 3: Została poszerzona do dwóch ilość jednostek interpretujących i implementujących Vertex Shadery. Obie jednostki nie mogą równocześnie wykonywać różnych programów, więc w zasadzie jedyną zaletą przetwarzania dwóch wierzchołków na raz jest wzrost wydajności. Jednostka Pixel Shader może wykonywać programy w wersjach 1.0 ' ( 1.3 (GeForce 3 jedynie 1.0 i 1.1). Oczywiście pod nazwą GeForce 4 bierzemy pod uwagę tylko i wyłącznie rodzinę kart opartych na procesorze NV25. Karty GeForce 4 MX oparte na NV17, nie posiadające w ogóle Vertex Shadera ani Pixel Shadera są technologicznie krokiem wstecz w porównaniu z GeForce 3. Ich istnienie jest zapewne podyktowane względami marketingowymi i potrzebą wypełnienia rynku tanimi kartami z cyferkę 4 w nazwie.

3. Akceleratory graficzne 18 3.2.2. GeForce FX (NV30) Długo oczekiwana karta GeForce FX stanowi niebagatelną rewolucję w stosunku do poprzedniczek. Poza spodziewanymi ulepszeniami technologiczno-wydajnościowymi, bardzo rozbudowana została programowalność jednostek przetwarzających wierzchołki i piksele. Imponujący jest zestaw instrukcji zarówno Vertex Shadera (tablica 3.5) jak i Pixel Shadera (tablica 3.6), który w GeForce FX został znacznie rozbudowany. Można śmiało powiedzieć, że GeForce FX to wielki krok w rozwoju specjalizowanych, programowalnych procesorów graficznych. 3.2.2.1. Vertex Shader Choć maksymalny rozmiar programu Vertex Shadera został zwiększony tylko dwukrotnie (do 256 instrukcji), to wprowadzenie pętli i procedur drastycznie zwiększa faktyczną ilość instrukcji wykonywanych przy przetwarzaniu jednego wierzchołka maksymalnie do 65536. Taka elastyczność wpływa również na redukcję ogólnej ilości różnych shaderów wymaganych przez jedną aplikację. Ilość stałych, z których korzystać może Vertex Shader została zwiększona z 96 do 256. W praktyce oznacza to w zależności od ich zastosowania np. zwiększenie ilości macierzy szkieletu przy wykorzystywaniu animacji szkieletowej czy też zwiększenie ilości jednoczesnych źródeł światła. Ilość rejestrów ogólnego przeznaczenia została zwiększona z 12 do 16. Vertex Shader może zawierać maksymalnie 64 różnych docelowych pozycji rozgałęzień i pętli (w tym zagnieżdżonych). W praktyce ogranicza to odgórnie m.in. ilość różnych pętli występujących w programie. Uprzednio adresowanie stałych odbywało się za pomocą skalara, obecnie rejestr adresujący jest wektorem. Vertex Shader umożliwia stosowanie semantyki wywoływania procedur CALL/RETURN, przy czym poziom zagnieżdżenia wywołań ograniczony jest wielkością stosu, który ma rozmiar 4. Zestaw instrukcji (tablica 3.5) został rozszerzony m.in. o instrukcje umożliwiające rozgałęzianie kodu (BRA), funkcje trygonometryczne wysokiej precyzji (COS, SIN) oraz funkcje wykładnicze i logarytmiczne wysokiej precyzji (EX2, LG2 i inne). 3.2.2.2. Pixel Shader Dane przechowywane w rejestrach oraz przetwarzane przez instrukcje mogą być w postaci 12-bitowych liczb stałoprzecinkowych, 16-bitowych liczb zmiennoprzecinkowych lub 32-bitowych liczb zmiennoprzecinkowych. Znacznie zwiększona została ilość operacji wykonywanych na jednym pikselu, program może mieć teraz długość do 1024 instrukcji. W porównaniu z 12 instrukcjami występującymi we wcześniejszych kartach, jest to różnica kolosalna. Program może wykonać dowolną ilość pobrań danych z maksymalnie 16 różnych tekstur, przy czym możliwe jest operowanie na maksymalnie 8 zestawach współrzędnych w teksturach. Tekstury te mogą w dowolny sposób opisywać rysowaną powierzchnię, mogą to być np. mapy wypukłości, połysku, otoczenia, cienia, współczynniki albedo itp. Jedynie maksymalna ilość instrukcji ogranicza ilość możliwych operacji pobrania teksela. Program może dokonać nawet 1024 operacji pobrania danych z tekstur (maksymalnie z 16 różnych). Programista może dowolnie wybierać teksturę oraz parę współrzędnych w celu pobrania piksela z tekstury, współrzędne w teksturach nie są już bowiem kojarzone z określonymi teksturami. Można więc dokonać pobrania próbek z 16 tekstur przy użyciu tylko jednego zestawu współrzędnych, jak również można dokonać pobrania próbek z ośmiu różnych lokalizacji w jednej teksturze. Program Pixel Shadera w przeciwieństwie do Vertex Shadera, przechowywany jest w pamięci obrazu. Rozwiązanie takie obniża koszty zarzadzania dużą ilością programów.

3. Akceleratory graficzne 19 Pixel Shader może być również wykorzystywany do obróbki już istniejącej zawartości bufora ramki. Przy pomocy pobierania z bufora ramki próbek można otrzymać efekty takie jak rozmycie, halo itp. Możliwe jest teraz filtrowanie tekstury z wyższą jakością. Przykładowo filtr dwusześcienny potrzebuje pobrania 16 próbek z tekstury. Program może zawierać do 1024 instrukcji mieszających i obliczających kolory. Dużą ilość takich instrukcji wymagają programy tworzące efekty takie jak dym lub ogień, proceduralne tekstury czy złożone modele oświetlenia. Program może korzystać z przestrzeni maksymalnie 64 rejestrów ogólnego przeznaczenia. Mogą one być wykorzystane w dwojaki sposób: jako 16-bitowe lub 32-bitowe liczby typu float. Przestrzeń tą można więc przeznaczyć na maksymalnie 32 rejestry liczb 32-bitowych, lub 64 rejestry liczb 16-bitowych. Oczywiście każdy rejestr jest wektorem składającym się z 4 takich liczb (64- lub 128-bitowym). Pixel Shader może teraz tak jak i Vertex Shader (rys. 3.3) korzystać z przyrostkowych operatorów mieszających poszczególne składniki wektora (swizzle) i maskujących zapis do rejestrów. Nowa jednostka przetwarzajaca piksele posiada znacznie rozbudowany zestaw instrukcji (tablica 3.6). Instrukcje wcześniej zarezerwowane dla Vertex Shaderów dostępne są teraz również dla Pixel Shadera, rozszerzone dodatkowo o specjalne instrukcje specyficzne dla przetwarzania pikseli: DDX, DDY Aby obliczyć pochodne w przestrzeni ekranu dowolnej wartości z uwzględnieniem współrzędnych x i y, instrukcje te dostarczają miary potrzebne do dostępu do sąsiednich pikseli i są bezcenne w przypadku wielu efektów, takich jak cieniowanie rysunkowe czy antialiasing. TXD Instrukcja ta umożliwia pobieranie próbek z tekstury i dostarcza własnych wartości pochodnych czastkowych współrzędnych w teksturze z uwzględnieniem współrzędnych x i y w rysowanym oknie. Dane te zwykle wykorzystywane są w obliczeniach poziomu detali (LOD). SIN, COS Funkcje trygonometryczne wysokiej precyzji nie istniały w poprzednich generacjach programowalnych kart graficznych nawet na poziomie przekształcania wierzchołków. W GeForce FX są one dostępne nawet na poziomie obróbki pojedynczych pikseli. PK*, UP* Te instrukcje umożliwiają pakowanie i rozpakowywanie mniejszych danych do większych. Przykładowo 16 8-bitowych wartości może być upakowane w 128 bitach (które normalnie były by przeznaczone na 4 32-bitowe liczby). Następnie te 16 wartości może zostać odczytane z powrotem i rozpakowane do poszczególnych rejestrów. Zdolność ta może być wykorzystana do przechowywania więcej niż czterech atrybutów związanych z pikselem.

3. Akceleratory graficzne 20 Instrukcja Argumenty Opis ) + ) + ) + tex t0 Pobranie koloru teksela texbem tdest, tsrc0 Mapowanie wypukłości otoczeniem, U += 2x2 matrix( du ), V += 2x2 matrix( dv ), następnie pobranie próbki z (U, V) texbeml tdest, tsrc0 Mapowanie wypukłości otoczeniem i oświetlenie, U += 2x2 matrix( du ), V += 2x2 matrix( dv ), następnie pobranie próbki z (U, V) i zaaplikowanie oświetlenia texcoord tdest Zamiana współrzędnych w teksturze na kolor texkill tdest Usunięcie teksela jeśli którakolwiek ze współrzędnych s, t, r, q jest mniejsza od 0 texm3x2pad t1, t0 Część instrukcji texm3x2tex dokonuje obliczenia iloczynu skalarnego koloru t0 z współrzędnymi w teksturze texm3x2tex t2, t0 Traktuje iloczyn skalarny obliczony przez instrukcję texm3x2pad jako współrzędna S. Dokonuje obliczenia iloczynu skalarnego koloru t0 z współrzędnymi w teksturze i wynik traktuje jako współrzędna T. Następnie pobierany jest teksel o współrzędnych S* T z tekstury texreg2ar tdest, tsrc Pobranie próbki z (tsrc.a, tsrc.r). Ogólna instrukcja czytania pośredniego, pobiera część koloru z tsrc i używa jako współrzędnych S* T do próbkowania tekstury tdest texreg2gb tdest, tsrc Pobranie próbki z (tsrc.g, tsrc.b). Ogólna instrukcja czytania pośredniego, pobiera część koloru z tsrc i używa jako współrzędnych S* T do próbkowania tekstury tdest texm3x3pad t1, t0 Przygotowanie dla instrukcji macierzowych. Traktuje trójwymiarowe współrzędne w teksturze jako wiersz macierzy. texm3x3spec t3, t0, c0 Obliczenie odbłysku światła widzianego przez nielokalnego widza na podstawie normalnej pobranej z tablicy normalnych. texm3x3vspec t3, t0, c0 Obliczenie odbłysku światła widzianego przez lokalnego widza na podstawie normalnej pobranej z tablicy normalnych. Wektor kamery z kierunku q współrzędnych z 3 zestawów tekstur 4D. texm3x3mat t3, t0, c0 Rotacja wektora poprzez macierz 3, 3 a następnie pobranie próbki z tekstury sześciennej (CubeMap) lub trójwymiarowej. Tablica 3.3: Instrukcje Pixel Shadera GeForce3 pobierające kolor z tekstury

3. Akceleratory graficzne 21 Instrukcja Argumenty Opis add dest, src1, src2 dest = src1 + sr2 sub dest, src1, src2 dest = src1 - src2 dp3 dest, src1, src2 dest = (src1.x*src2.x + src1.y*src2.y + src1.z*src2.z) lrp dest, factor, src1, src2 dest = (factor)*src1 + (1 - factor)*src2 mul dest, src0, src1 dest = src0*src1 mad dest, src0, src1, src2 dest = (src0 + src1*src2) mov dest, src dest = src cnd dest, r0.a, src1, src2 if (r0.a > 0.5) { dest = src1; } else { dest = src2; } Tablica 3.4: Instrukcje Pixel Shadera GeForce3 mieszające kolory Kategoria Dodawanie i mnożenie Matematyka Porównywanie Rozgałęzianie Adresowanie Graficzne Minimum / maksimum Instrukcje ADD, DP3, DP4, DPH, MAD, MOV, SUB ABS, COS, EX2, EXP, FLR, FRC, LG2, LOG, RCP, RSQ, SIN SEQ, SFL, SGR, SGT, SLE, SLT, SNE, STR BRA, CAL, NOP ARL, ARR DST, LIT MAX, MIN Tablica 3.5: Zestaw instrukcji Vertex Shadera GeForce FX (NV30) Kategoria Dodawanie i mnożenie Teksturowanie Pochodne czastkowe Matematyka Porównywanie Graficzne Minimum / maksimum Pakowanie Rozpakowywanie Usuwanie Instrukcje ADD, LRP, DP3, DP4, LRP, MAD, MOV, SUB TEX, TXD, TXP DDX, DDY ABS, COS, EX2, EXP, FLR, FRC, LG2, LOG, NRM, POW, RCP, RSQ, SIN SEQ, SFL, SGR, SGT, SLE, SLT, SNE, STR DST, LIT, RFL MAX, MIN PK2H, PK2US, PK4B, PK4UB, PK4UBG, PK16 UP2H, UP2US, UP4B, UP4UB, UP4UBG, UP16 KIL Tablica 3.6: Zestaw instrukcji Pixel Shadera GeForce FX (NV30)

4. Protoplaści i inne rozwiazania Cieniowanie proceduralne jest dość dobrze znaną i sprawdzoną techniką renderowania, w której krótkie, tworzone przez użytkownika procedury (shadery) określają rozkład cieni i kolorów na danej powierzchni. Jest to rozwiązanie bardzo eleganckie pozwalające na niesłychaną elastyczność i kontrolę wyglądu powierzchni. Jak dotąd najbardziej rozległym polem użytkowania tej techniki była produkcja animacji, w której od wielu lat używana była w tworzeniu reklam i filmów. Animacje takie są renderowane przez oprogramowanie, a każda klatka jest generowana przez odpowiednio długi, w przybliżeniu proporcjonalny do stopnia skomplikowania obrazu czas: od kilku sekund, nawet do kilku godzin. Dopiero tak spreparowana animacja może być odtwarzana z typową prędkością 24 30 klatek na sekundę. 4.1. Rendering offline: RenderMan Shading Language Opracowany przez firmę Pixar dla potrzeb aplikacji RenderMan język programowania shaderów jest jednym z pierwszych języków wysokiego poziomu tego typu. Shader napisany w tym języku może być wykorzystany w jednej z kilku istniejących aplikacji renderujących off-line, przede wszystkim zaś rzecz jasna w samym RenderManie. Aplikacje takie powstały głównie dla potrzeb przemysłu filmowego i ogólnie są stosowane do tworzenia wszelakiej maści animacji, mniej lub bardziej realistycznych, choć największym wyzwaniem jest oczywiście dążenie do maksymalnej fotorealistyczności tworzonego obrazu. RenderMan Shading Language jest językiem opracowanym w celu tworzenia własnych procedur cieniujących i oświetlających - shaderów. Język ten umożliwia użytkownikowi rozszerzanie istniejących lub tworzenie zupełnie nowych, specjalnych modeli oświetlenia, symulację fizyki materiałów czy też tworzenie specyficznych materiałów. Dokonywane jest to poprzez modelowanie interakcji światła z powierzchnią oraz wnętrzem danego obszaru przestrzeni. Wiele różnych materiałów może być też ze sobą łączonych w celu symulacji kilku warstw farby czy wykończenia danej powierzchni. Język ten upraszcza również wizualizację wyników symulacji naukowych umożliwiając tworzenie shaderów, które obliczają końcowy kolor piksela powierzchni bezpośrednio na podstawie wyników obliczeń. Możliwe jest np. stworzenie shadera określającego kolor na podstawie temperatury i krzywizny powierzchni. Shadery mogą być również używane do modyfikowania końcowej wartości koloru piksela zanim jest on zapisany do wyjściowego obrazu. Język ten jest wzorowanym na C językiem, dodatkowo rozszerzonym o typy danych służące do przechowywania koloru i punktów. Ponadto dostępne jest standardowo: duża ilość funkcji trygonometrycznych i matematycznych (m.in. interpolacja, szum itd.); operatory symulujące miksowanie i filtrowanie światła; operatory dokonujące typowych operacji na punktach i wektorach (iloczyn skalarny, wektorowy); zestaw typowych funkcji geometrycznych (m.in. przekształcanie punktów do specyficznych układów współrzędnych); typowe wzory obliczające oświetlenie i cieniowanie dostępne jako wbudowane funkcje (ambient, diffuse, specular, phong itd);

4. Protoplaści i inne rozwiazania 23 funkcje pobierające dane z obrazów (tekstur, map otoczenia itp). Współrzędne w teksturach mogą być wartościami uprzednio podanymi, lub też całkowicie obliczonymi przez shader. Ponieważ dane pobrane z tekstury są traktowane jak każde inne, mogą być wykorzystywane do kontroli dowolnego aspektu obliczeń. Ponadto nie ma żadnych ograniczeń ilości tekstur dla jednej powierzchni. Język może być również używany do określania funkcji przesuwających powierzchnię, takich jak falowanie czy marszczenie. Ponadto funkcje napisane w Shading Language mogą być używane do operacji na pikselach. Taki typ shadera nosi nazwę imager i jest używany do pewnych efektów specjalnych, do kompensacji nieliniowości medium wyświetlającego, czy też do konwersji koloru do innej przestrzeni kolorów (np. CMYK). Proces obliczenia koloru punktu powierzchni wymaga wyspecyfikowania źródeł światła, parametrów materiału powierzchni, efektów wolumetrycznych lub atmosferycznych oraz operacji pikselowych. Interpolacja koloru w sensie interpolacji Gourauda czy Phonga nie jest brana pod uwagę jako część tego procesu. Każdy etap jest kontrolowany przez zadana funkcję (shader), która w sposób matematyczny opisuje dany etap. RenderMan Shading Language definiuje pięć głównych typów shaderów: Light source shaders Światła mogą istnieć samoistnie lub mogą być powiązane z konkretnymi obiektami. Shader związany z światłem oblicza kolor światła emitowanego z punktu w źródle światła w kierunku punktu oświetlanej powierzchni. Źródło światła posiada zwykle parametry takie jak kolor lub widmo, natężenie, zależności kierunkowe oraz tłumienie zależne od odległości. Displacement shaders Shadery tego typu modyfikują położenie oraz wektory normalne punktów leżących na powierzchni w celu uzyskania wypukłości. Surface shaders Dołączone do wszystkich obiektów geometrycznych, używane są do zamodelowania właściwości optycznych materiału, z którego obiekt został zbudowany. Shader tego typu oblicza światło odbite w określonym kierunku poprzez zsumowanie świateł padających na powierzchnię z uwzględnieniem właściwości powierzchni. Volume shaders Shadery wolumetryczne modulują kolor promienia światła podróżującego przez dane środowiska zdefiniowane we wnętrzu obiektów. Atmosfera jest również takim środowiskiem, zdefiniowanym przed stworzeniem jakiegokolwiek obiektu. Imager shader Używane do programowanie operacji pikselowych dokonywanych przed kwantyzacją obrazu i jego zapisem do wyjścia. Koncepcyjnie najprostsze jest opisanie procesu cieniowania za pomocą algorytmu śledzenia promieni. W klasycznym rekurencyjnym algorytmie, promienie rzucane są z punktu obserwacyjnego poprzez punkt znajdujący się na płaszczyźnie obrazu (rys. 4.1). Każdy promień przecinając się z jakąś powierzchnią powoduje stworzenie nowych promieni, które w dalszym procesie są śledzone rekurencyjnie. Promienie te są zwykle skierowane ku źródłom światła oraz w kierunkach maksymalnego odbicia oraz transmitancji. Gdy tylko promień podróżuje poprzez przestrzeń, jego kolor oraz natężenie jest modulowana przez shader związany z danym obszarem przestrzeni (volume shader). Jeśli obszar ten znajduje się wewnątrz obiektu, shaderem użytym do obliczeń jest ten związany z wnętrzem obiektu, w przeciwnym zaś razie używany jest zewnętrzny shader. Kiedy tylko promień przecina się z jakąś powierzchnią, związany z nią shader (surface shader) wykorzystywany jest do tworzenia kolejnych promieni, do określenia koloru i natężenia przychodzącego promienia na podstawie kolorów i natężeń promieni wychodzących, oraz do określenia właściwości materiału. Wreszcie za każdym razem gdy promień rzucony jest w kierunku źródła światła, związany z tym światłem shader (light shader) jest wykorzystany do obliczenia koloru oraz natężenia emitowanego światła. Potok shaderów pokazany jest na rysunku 4.2.