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

Podobne dokumenty