What does a framebuffer do?

Framebuffer Optimering i Unity med OpenGL ES

22/12/2013

Rating: 4.58 (9889 votes)

Grafisk rendering i Unity er en kompleks proces, der kræver en dyb forståelse for at opnå optimal ydeevne, især på mobile enheder. En af de mest kritiske, men ofte oversete, komponenter i denne proces er framebuffer. At forstå, hvordan Unity interagerer med framebufferen, især ved brug af OpenGL ES, er afgørende for enhver udvikler, der ønsker at skabe flydende og effektive applikationer. Denne artikel vil dykke ned i framebufferens funktion, hvordan Unity administrerer den, og hvilke bedste praksisser du kan følge for at reducere GPU'ens arbejdsbyrde og forbedre den overordnede brugeroplevelse.

Does unity clear a framebuffer when using opengles?
When using OpenGLES on Adreno GPUs, Unity only discards the framebuffer to avoid a framebuffer restore. On PVR and Mali GPUs, Unity clears to prevent a framebuffer restore.
Indholdsfortegnelse

Hvad er en Framebuffer?

En framebuffer er ikke bare en enkelt buffer; det er en samling af buffere, der gemmer forskellige typer information for hver pixel på skærmen. Tænk på det som det digitale lærred, hvor det endelige billede bliver malet, før det vises for brugeren. De primære komponenter i en framebuffer er:

  • Farvebuffer (Color Buffer): Dette er den mest kendte del. Den indeholder RGBA (Rød, Grøn, Blå, Alpha) farveinformation for hver pixel. Det er denne buffer, vi i sidste ende ser på skærmen. Afhængigt af systemet kan der være flere farvebuffere i brug (f.eks. til dobbelt eller tredobbelt buffering).
  • Dybdebuffer (Depth Buffer / Z-buffer): Denne buffer gemmer dybdeinformation (afstanden fra kameraet) for hver pixel. Den er afgørende for korrekt håndtering af skjulte overflader (hidden-surface removal). Når et nyt objekt skal tegnes på en pixel, sammenlignes dets dybde med den værdi, der allerede er i dybdebufferen. Hvis det nye objekt er tættere på, bliver det tegnet, og dybdebufferen opdateres. Ellers bliver det kasseret.
  • Stencilbuffer (Stencil Buffer): Denne buffer tillader mere avancerede operationer pr. pixel. Den kan bruges til at maskere bestemte områder af skærmen, så der kun tegnes inden for eller uden for masken. Dette er nyttigt til at skabe komplekse effekter som spejle, skygger i realtid eller udskæringer i geometrien.

Samlet set udgør disse buffere det komplette billede og de data, der er nødvendige for at gengive en scene korrekt. Hver fragment (en potentiel pixel), der genereres af GPU'en, gennemgår en række tests – saks-, alfa-, stencil- og dybdetest – før det får lov til at ændre værdierne i framebufferen.

Framebuffer-håndtering på Mobile Enheder: Vigtigheden af 'Clear'

På desktop- og konsol-GPU'er (ofte kaldet 'streaming GPUs') er arkitekturen anderledes end på de fleste mobile enheder. Mobile GPU'er (som Adreno, Mali, PowerVR) er typisk tile-baserede renderere. Det betyder, at de opdeler skærmen i små firkanter (tiles), f.eks. 32x32 pixels, og behandler hver tile færdig, før de går videre til den næste. Denne tilgang er meget strømeffektiv.

Denne arkitektur har dog en stor konsekvens for håndteringen af framebufferen. I begyndelsen af renderingen af en ny frame er det ekstremt dyrt at indlæse indholdet af den forrige frame fra hovedhukommelsen ind i GPU'ens hurtige on-chip hukommelse for hver tile. Det koster båndbredde, tid og batteri.

Det er her, 'clear'-kommandoen (glClear i OpenGL ES) bliver altafgørende. Når du kalder glClear, signalerer du til grafikdriveren, at du ikke har brug for indholdet fra den forrige frame. Driveren kan derfor helt undgå den dyre indlæsningsoperation. Unity håndterer dette intelligent for dig:

  • På Adreno GPU'er: Unity bruger en 'discard'-operation, som effektivt fortæller GPU'en at ignorere det tidligere indhold.
  • På PowerVR og Mali GPU'er: Unity udfører en 'clear'-operation for at opnå det samme resultat – at undgå en dyr gendannelse af framebufferen.

Derfor er det en kritisk fejl at bruge kameraets 'Clear Flag' sat til 'Don't Clear' på mobile platforme. Det tvinger GPU'en til at udføre den dyre indlæsningsoperation, hvilket kan have en alvorlig negativ indvirkning på din apps ydeevne.

Dobbelt og Tredobbelt Buffering

For at undgå visuelle artefakter som 'tearing' (hvor man ser dele af to forskellige frames på samme tid), bruger systemer ofte dobbelt eller tredobbelt buffering.

  • Dobbelt buffering: Systemet har to framebuffere. Mens den ene (front buffer) vises på skærmen, tegnes den næste frame i den anden (back buffer). Når den er færdig, byttes de.
  • Tredobbelt buffering: Her bruges tre buffere. Dette kan give en endnu mere jævn framerate, da GPU'en kan begynde at tegne en tredje frame, mens den venter på, at skærmen er klar til at bytte buffer.

Ulempen er, at hver ekstra framebuffer kræver en betydelig mængde hukommelse, især ved høje opløsninger.

Framebufferens Hukommelsesfodaftryk

Moderne mobiltelefoner har ekstremt høje skærmopløsninger, ofte langt over 1080p. At rendere i native opløsning kan være en enorm byrde for GPU'en og hukommelsessystemet. Størrelsen på din framebuffer kan beregnes, og det er vigtigt at være opmærksom på den.

Lad os tage et eksempel: En Full HD-skærm (1920x1080) med en 32-bit farvebuffer (4 bytes pr. pixel).

1920 * 1080 * 4 bytes = 8.294.400 bytes ≈ 7.9 MB

Dette er kun for én farvebuffer. Hvis du bruger tredobbelt buffering, en 24-bit dybdebuffer og en 8-bit stencilbuffer, bliver regnestykket meget større. En Samsung S8 med en opløsning på 1440x2960 kan nemt bruge tæt på 100 MB grafikhukommelse alene til sine framebuffere.

Does unity clear a framebuffer when using opengles?
When using OpenGLES on Adreno GPUs, Unity only discards the framebuffer to avoid a framebuffer restore. On PVR and Mali GPUs, Unity clears to prevent a framebuffer restore.

Tabel over Hukommelsesforbrug pr. Framebuffer

Tabellen nedenfor viser det omtrentlige hukommelsesforbrug for en enkelt framebuffer ved forskellige opløsninger og farvedybder.

OpløsningDimensioner16-bit (2 bytes)24-bit (3 bytes)32-bit (4 bytes)
720p1280 x 7201.76 MB2.64 MB3.51 MB
1080p1920 x 10803.96 MB5.93 MB7.91 MB
1440p2560 x 14407.03 MB10.55 MB14.06 MB
Galaxy S82960 x 14408.13 MB12.20 MB16.27 MB

Bemærk: Husk at multiplicere disse tal med antallet af buffere (f.eks. 3 for tredobbelt buffering) og tilføje størrelsen af dybde- og stencilbufferen for at få det samlede forbrug.

En effektiv strategi er at bruge Screen.SetResolution() til at rendere spillet i en lavere opløsning end skærmens native opløsning. Dette kan give en markant forbedring i ydeevne med et minimalt tab i visuel kvalitet.

Relaterede Optimeringsstrategier

At optimere framebufferen handler også om at reducere mængden af arbejde, der skal udføres, før noget overhovedet skrives til den.

Overdraw

Overdraw opstår, når den samme pixel på skærmen tegnes flere gange inden for den samme frame. Dette sker f.eks., når uigennemsigtige objekter tegnes oven på hinanden, eller når UI-elementer dækker hele 3D-scenen. Hver gang en pixel overskrives, er det spildt arbejde for GPU'en. Unity's 'Overdraw' scene view er et fantastisk værktøj til at identificere problemområder. At reducere overdraw minimerer antallet af unødvendige skriveoperationer til framebufferen og letter presset på GPU'ens fillrate.

Culling

Culling er processen med at fjerne objekter, der ikke skal tegnes.

  • Frustum Culling: Fjerner automatisk objekter, der er uden for kameraets synsfelt.
  • Occlusion Culling: En mere avanceret teknik, hvor objekter, der er skjult bag andre objekter (f.eks. i et andet rum), ikke bliver tegnet.

Effektiv culling betyder, at færre objekter sendes gennem rendering-pipelinen, hvilket reducerer antallet af fragmenter, der skal testes og potentielt skrives til framebufferen.

Ofte Stillede Spørgsmål (FAQ)

Sp: Rydder Unity altid framebufferen, når man bruger OpenGL ES?

Sv: Ja, i praksis er målet det samme. Unity sikrer, at indholdet fra den forrige frame ikke indlæses, hvilket er den dyre operation på mobile GPU'er. Den specifikke metode (om det er en 'clear' eller 'discard'-operation) afhænger af den underliggende hardware (GPU) for at opnå den bedste ydeevne, men resultatet er, at du starter hver frame med et 'rent lærred' og undgår den dyre gendannelsesproces.

Sp: Hvorfor er 'clear'-kommandoen så vigtig på mobile enheder?

Sv: På grund af den tile-baserede arkitektur i de fleste mobile GPU'er. At indlæse den forrige frames data fra hovedhukommelsen til GPU'ens hurtige hukommelse er en langsom og energikrævende proces. En 'clear'-kommando lader GPU'en springe dette trin over, hvilket sparer betydelig båndbredde og forbedrer ydeevnen markant.

Sp: Hvordan kan jeg reducere min apps hukommelsesforbrug relateret til framebufferen?

Sv: Den mest effektive metode er at kontrollere din renderingsopløsning. Brug Screen.SetResolution() til at sætte en lavere opløsning end enhedens native opløsning. Overvej også, om du har brug for dybde- og stencilbuffere. Hvis din app er en simpel 2D-app uden komplekse maskeringsbehov, kan du deaktivere dem i Player Settings for at spare hukommelse.

Hvis du vil læse andre artikler, der ligner Framebuffer Optimering i Unity med OpenGL ES, kan du besøge kategorien Sundhed.

Go up