to get the file
Transkrypt
to get the file
Instrukcja 9 Współczesne procesory graficzne Temat: Przetwarzanie obrazów z użyciem CUDA. część 2 Przygotował: mgr inż. Tomasz Michno 1 Wstęp 1.1 Pixel Buffer Object (PBO) Pixel Buffer Object Rodzaj buforu OpenGl, służący do przechowywania pikseli (obrazu, tekstur itp.). Przechowuje piksele w szybkiej pamięci video RAM lub AGP RAM – czyli na GPU. Do kodu aplikacji OpenGL zwraca wskaźnik na przydzieloną pamięć, jednocześnie dbając o prawidłową obsługę bufora (można się do niego odwoływać jak do tablicy). OpenCL/OpenGL interoperation Manipulacja buforami OpenGL bez przesyłania danych z pamięci głównej do GPU i z powrotem. W celu korzystania z CUDA/OpenGL interoperation najlepiej jest dodać nagłówki: 1 2 #i n c l u d e <GL/ glew . h> #i n c l u d e <cuda_gl_interop . h> Zawiera on najpotrzebniejsze funkcje do komunikacji z OpenGL, m.in. takie jak mapowanie/odmapowanie buforów. Dodatkowo wymagana jest biblioteka GLEW, którą należy zainicjować na początku programu: 1 2 3 4 5 glewInit () ; i f ( ! g l e w I s S u p p o r t e d ( "GL_VERSION_2_0 " ) ) { f p r i n t f ( s t d e r r , "ERROR: Support f o r n e c e s s a r y OpenGL e x t e n s i o n s missing . ") ; return 1;\ } Podział pracy przy interoperacji jest następujący: OpenGL: 1. Tworzenie standardowych elementów OpenGL 1 2. Utworzenie OpenGL pixel buffer’a 3. Wyświetlenie pixel buffer’a CUDA: 1. Wykonywanie operacji na pixel bufferze 1.2 Obsługa PBO Obiekt PBO w OpenGL jest definiowany jako zmienna typu GLInt: 1 GLuint pbo=NULL; Stworzenie obiektu pbo jest realizowane przez funkcje OpenGL oraz CUDA: 1 2 v o i d createPBO ( GLuint ∗ pbo ) { 3 i n t num_texels = WYSOKOSC_OKNA ∗ SZEROKOSC_OKNA; i n t num_values = num_texels ∗ 4 ; i n t size_tex_data = s i z e o f ( GLubyte ) ∗ num_values ; 4 5 6 7 g l G e n B u f f e r s ( 1 , pbo ) ; 8 9 g l B i n d B u f f e r (GL_PIXEL_UNPACK_BUFFER, ∗pbo ) ; 10 11 g l B u f f e r D a t a (GL_PIXEL_UNPACK_BUFFER, size_tex_data , NULL, GL_DYNAMIC_COPY) ; c u d a G L R e g i s t e r B u f f e r O b j e c t ( ∗pbo ) ; 12 13 14 15 } Usunięcie obiektu PBO można zrealizować za pomocą podobnych funkcji: 1 2 3 v o i d deletePBO ( GLuint ∗ pbo ) { i f ( pbo ) { 4 5 c u d a G L U n r e g i s t e r B u f f e r O b j e c t ( ∗ pbo ) ; 6 7 8 g l B i n d B u f f e r (GL_ARRAY_BUFFER, ∗pbo ) ; g l D e l e t e B u f f e r s ( 1 , pbo ) ; 9 10 ∗pbo = NULL; 2 } 11 12 } W celu wczytania pikseli z ekranu do pbo można użyć następującego kodu: g l B i n d B u f f e r (GL_PIXEL_PACK_BUFFER, pbo ) ; 1 2 g l R e a d P i x e l s ( 0 , 0 , SZEROKOSC, WYSOKOSC, GL_RGB,GL_FLOAT, 0 ) ; g l B i n d B u f f e r ( GL_PIXEL_UNPACK_BUFFER, 0 ) ; 3 4 GL_PIXEL_PACK_BUFFER oznacza, że będziemy zapisywali do pbo, z kolei GL_PIXEL_UNPACK_BUFFER oznacza odczyt. Sam odczyt pikseli z ekranu i zapis do pbo odbywa się za pomocą funkcji glReadPixels, której ostatni parametr jest ustawiony na 0 (przy zwykłym użyciu podajemy tam wskaźnik na bufor pikseli w pamięci głównej). Zapis pikseli na ekran odbywa się identycznie - podajemy jako parametr glBindBuffer flagę GL_PIXEL_UNPACK_BUFFER oraz używamy funkcji glWritePixels. 1.3 Interakcja z CUDA W celu używania pbo po stronie karty graficznej, musimy użyć funkcji mapujących i odmapowujących bufor. Mapowanie pbo dla CUDA (po tej funkcji aplikacja hosta traci dostęp do pbo): 1 2 uchar4 ∗ d p t r=NULL; cudaGLMapBufferObject ( ( v o i d ∗ ∗ )&dptr , pbo ) ; Teraz możemy przekazać do kernela wskaźnik dptr i używać go jako zwykłą tablicę typu uchar4 (element przechowuje wartość R (pole x elementu), G (pole y), B (pole z) oraz kanał Alpha (pole w)). Po wykonaniu wszystkich operacji po stronie karty graficznej na pbo, należy je odmapować: 1 cudaGLUnmapBufferObject ( pbo ) ; 3 1.4 Alternatywne wyświetlanie PBO na ekranie W celu wyświetlenia pikseli na ekranie można zastosować również inny sposób - stworzenie tekstury oraz wyświetlenie jej na prostokącie o rozmiarach okna/ekranu, np.: g l B i n d B u f f e r (GL_PIXEL_UNPACK_BUFFER, pbo ) ; 1 2 g l B i n d T e x t u r e (GL_TEXTURE_2D, t e x t u r e I D ) ; 3 4 glTexSubImage2D (GL_TEXTURE_2D, 0 , 0 , 0 , 5 1 2 , 5 1 2 , GL_RGBA, GL_UNSIGNED_BYTE, NULL) ; 5 6 7 g l B e g i n (GL_QUADS) ; glTexCoord2f ( 0 . 0 f , 0 . 0 glTexCoord2f ( 0 . 0 f , 1 . 0 glTexCoord2f ( 1 . 0 f , 1 . 0 glTexCoord2f ( 1 . 0 f , 0 . 0 glEnd ( ) ; 8 9 10 11 12 13 f); f); f); f); g l V e r t e x 3 f ( −1.0 f , −1.0 f , 0 . 0 f ) ; g l V e r t e x 3 f ( −1.0 f , 1 . 0 f , 0 . 0 f ) ; glVertex3f (1.0 f ,1.0 f ,0.0 f ) ; g l V e r t e x 3 f ( 1 . 0 f , −1.0 f , 0 . 0 f ) ; Uwaga! Z niewiadomych względów w funkcji renderującej OpenGL nie wolno używać czyszczenia buforów: glClear(GL_COLOR_BUFFER_BIT). Dobrze jest również wyłączyć bufor głębokości. Działa za to podwójne buforowanie i funkcja glutSwapBuffers(). 2 Zadanie Napisz program, który będzie wyświetlał dowolny, kolorowy rysunek rysowany po stronie GPU z użyciem PBO. Na rysunek nałóż operację konwersji na odcienie szarości (z dowolnymi wagami), tak jak w poprzedniej instrukcji (można zaimplementować w tym samym kernelu). 4