2011-11-20 7 views
9

Mam grę, która działa całkiem dobrze (55-60 fps) na wyświetlaczu siatkówki. Chcę dodać nakładkę pełnoekranową, która łączy się z istniejącą sceną. Jednak nawet przy użyciu małej tekstury osiągi są ogromne. Czy istnieje optymalizacja, którą mogę wykonać, aby była ona użyteczna?Uderzenie wydajności z mieszania dużego quada

Jeśli używam tekstury 80x120 (tekstura jest renderowana w locie, dlatego nie jest kwadratowa), otrzymuję 25-30 FPS. Jeśli sprawię, że tekstura będzie mniejsza, wydajność wzrośnie, ale jakość nie będzie akceptowalna. Generalnie jednak jakość nakładki nie jest bardzo ważna (to tylko oświetlenie).

Wykorzystanie renderera wynosi 99%.

Nawet jeśli użyję kwadratowej tekstury z pliku (.png), wydajność jest zła.

ten sposób utworzyć teksturę:

[EAGLContext setCurrentContext:context]; 

    // Create default framebuffer object. 
    glGenFramebuffers(1, &lightFramebuffer); 
    glBindFramebuffer(GL_FRAMEBUFFER, lightFramebuffer); 

    // Create color render buffer and allocate backing store. 
    glGenRenderbuffers(1, &lightRenderbuffer); 
    glBindRenderbuffer(GL_RENDERBUFFER, lightRenderbuffer); 
    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, LIGHT_WIDTH, LIGHT_HEIGHT); 

    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, lightRenderbuffer); 

    glGenTextures(1, &lightImage); 
    glBindTexture(GL_TEXTURE_2D, lightImage); 

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, LIGHT_WIDTH, LIGHT_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); 

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, lightImage, 0); 

A oto renderowania ...

/* Draw scene... */ 

glBlendFunc(GL_ONE, GL_ONE); 


//Switch to offscreen texture buffer 
glBindFramebuffer(GL_FRAMEBUFFER, lightFramebuffer); 
glBindRenderbuffer(GL_RENDERBUFFER, lightRenderbuffer); 
glViewport(0, 0, LIGHT_WIDTH, LIGHT_HEIGHT); 

glClearColor(ambientLight, ambientLight, ambientLight, ambientLight); 
glClear(GL_COLOR_BUFFER_BIT); 

/* Draw lights to texture... */ 

//Switch back to main frame buffer 
glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer); 
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer); 
glViewport(0, 0, framebufferWidth, framebufferHeight); 

glBlendFunc(GL_DST_COLOR, GL_ZERO); 

glBindTexture(GL_TEXTURE_2D, glview.lightImage);  

/* Set up drawing... */ 

glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, 0); 

Oto niektóre odniesienia wziąłem podczas próby zawężenia problemu. "Bez mieszania" oznacza, że ​​mogę wyłączyć (GL_BLEND) zanim narysuję quad. "Brak przełączania bufora" oznacza, że ​​przed rysowaniem nie przełączam się z bufora poza ekranem.

(Tests using a static 256x256 .png) 
No blend, No buffer switching: 52FPS 
Yes blend, No buffer switching: 29FPS //disabled the glClear, which would artificially speed up the rendering 
No blend, Yes buffer switching: 29FPS 
Yes blend, Yes buffer switching: 27FPS 

Yes buffer switching, No drawing: 46FPS 

Każda pomoc jest doceniana. Dzięki!

UPDATE

Zamiast mieszania cały lightmap potem skończyło się na napisanie cieniującego do pracy na bieżąco. Każdy fragment pobiera próbki i miesza się z mapą światła (rodzaj podobnego multiteksturowania). Początkowo przyrost wydajności był minimalny, ale potem użyłem lowpl sampler2d dla mapy światła, a następnie uzyskałem około 45 FPS.

Oto fragment shader:

lowp vec4 texColor = texture2D(tex, texCoordsVarying); 
lowp vec4 lightColor = texture2D(lightMap, worldPosVarying); 
lightColor.rgb *= lightColor.a; 
lightColor.a = 1.0; 

gl_FragColor = texColor * color * lightColor; 
+0

Podejrzewam, że 'bufor glView' przełączniki są prawdopodobnie winowajcą. Co się dzieje w tych metodach? Dlaczego nie użyć 'glBindRenderBuffer'? – Justicle

+0

Wprowadzę te metody do wyjaśnienia. – whooops

+0

Ok do debufowania problemu perf, spróbuj wstępnego renderowania nakładki (po prostu pozostaw to na razie statyczne), a następnie skopiuj ją do głównego bufora każdej klatki. To przynajmniej powie ci, czy przełączniki bufora są wolne (tj. Wykonywanie dwóch wywołań do glBindFrame, glBindRender, glViewport dla każdej klatki). – Justicle

Odpowiedz

3

Ok myślę, że rozbieg przed ograniczeń sprzętowych. Połączenie kwadratowego kwadratu z całą sceną jest prawdopodobnie szczególnie niekorzystne dla sprzętu opartego na płytkach. PowerVR SGX (na iPhone) jest zoptymalizowany do usuwania ukrytej powierzchni, aby uniknąć rysowania rzeczy, gdy nie są potrzebne. Ma niską przepustowość pamięci, ponieważ jest zoptymalizowana pod kątem urządzeń o niskim poborze mocy.

Kwadratowe zmiksowane kwadraty czyta się, a następnie zapisuje każdy fragment na ekranie. Oooo!

Przyspieszenie jest związane z - ponieważ mówisz GL, że nie przejmujesz się zawartością bufora wstecznego przed renderowaniem, co powoduje zapisanie poprzedniej zawartości w pamięci.

Jest to bardzo dobry przegląd sprzętu iOS tutaj: http://www.imgtec.com/factsheets/SDK/POWERVR%20SGX.OpenGL%20ES%202.0%20Application%20Development%20Recommendations.1.1f.External.pdf

Jak dla rzeczywistego rozwiązania - Chciałbym spróbować bezpośrednio renderowania swoją nakładkę na scenie gier.

Na przykład, czynią pętla powinna wyglądać następująco:

[EAGLContext setCurrentContext:context]; 

// Set up game view port and render the game 
InitGameViewPort(); 
GameRender(); 

// Change camera to 2d/orthographic, turn off depth write and compare 
InitOverlayViewPort() 

// Render overlay into same buffer 
OverlayRender() 
+0

Dzięki. Tak, doszedłem do tego samego wniosku. Niestety, nie mogę użyć twojego rozwiązania - nakładka, którą rysuję, jest raczej mapą lightmapy, więc wpływa na rzeczywiste piksele środowiska gry. Skończyłem na pisaniu shadera, aby wykonać tę samą pracę, z całkiem niezłym sukcesem. Opublikuję szczegóły tego w moim pytaniu. Dziękujemy za pomoc w zbadaniu tego problemu! – whooops

+0

Awesome - Chciałbym zobaczyć, co zrobiłeś. – Justicle

+0

Używam rozmiarów ekranu o rozmiarze kwadratu w całej scenie w mojej grze i nie uzyskałem zmniejszenia liczby klatek na sekundę (30 fps w 3G, 60 w siatkówkach). Spowolnienie może polegać na stworzeniu tekstury? robisz to w każdej klatce? – led42

1

Jeśli odda cel render na układzie scalonym PowerVR, przełączyć się na inny renderowanie cel i renderowanie, a następnie powrócić do poprzednich renderowania docelowemu ucierpi w wyniku poważnego uderzenia. Ten rodzaj wzorca dostępu jest oznaczony jako "Logical Buffer Load" przez OpenGL ES Analyzer wbudowany w najnowsze Instrumenty.

Jeśli zmienisz kolejność renderowania, aby najpierw narysować swój cel renderowania lightmapy, a następnie wyrenderować scenę do głównego bufora ramki, a następnie wykonaj mieszankę pełnoekranową tekstury docelowej renderowania mapy światła, wydajność powinna być znacznie wyższa.

0

Mogę potwierdzić, na iPadzie 1 przy użyciu iOS 4.2, włączyć/wyłączyć GL_BLEND dla jednego pełnego ekranu quad przełączanego między 18 a 31 fps. W obu przebiegach wykorzystanie renderera wynosiło 90-100%.

0

Nawet przed manipulowaniem teksturą upewnij się, że twój moduł cieniujący jest zoptymalizowany. Podczas wypełniania ekranu 960x640 (614400 pikseli) każda operacja w module cieniującym ma ogromny wpływ.

Jedną dobrą rzeczą jest stworzenie konkretnej wersji modułu cieniującego fragmenty dla tej sytuacji. To powinno być coś takiego:

varying mediump vec2 vertexTexCoord; 
uniform sampler2D texture; 

void main() { 
    gl_FragColor = texture2D(texture, vertexTexCoord); 
} 

Utwórz inny program z tego fragmentu cieniującego i używać go przed wyciągnięciem swój wielki quad, a następnie przywrócić normalny program. IPhone 4 jest w stanie renderować około 7 pełnoekranowych, teksturowanych quadów 1: 1 na ramkę z mieszaniem, ale szybko spada do około 1 z bardziej wyrafinowanym shaderem.

(Dodatkowo w przypadku próby do renderowania nakładki tekstury, potem normalne elementy, a następnie tekstury nad resztą. To powinno poprawić wydajność przez znaczny margines.)

Powiązane problemy