O que é o Screen Tearing e porque motivo acontece.

Recentemente foi revelado Sniper Elite 3 para a a PS4 e Xbox One, sendo que uma das principais diferenças entre as versões é a existência de uma enorme quantidade de um efeito gráfico chamado “Screen Tearing” na versão Xbox One. Sabe o que é, e porque motivo isso acontece.

Quem lida com PCs deverá já ter-se deparado com uma opção na placa gráfica denominada de VSync.

O que é o Vsync? VSync significa Vertical Synchronization ou Sincronização Vertical e a ideia básica é sincronizar os frames criados pela placa gráfica com o refrescamento do monitor. A ideia é eliminar um efeito gráfico chamado de “tearing” e que vamos descrever.

Apesar da inovação introduzida pelos LCDs onde não há um verdadeiro refrescamento de ecrã pois os pixels mantêm-se acesos até ordem em contrário, os Hz de refrescamento continuam a governar o funcionamento de todo o sistema. Esse é o motivo pelo qual ainda se fala em Hz de refrescamento de ecrã, apesar de eles na realidade não fazerem qualquer refrescamento.

Ora qualquer jogo baseia-se nos FPS. São os fotogramas por segundo ou o número de imagens que uma placa gráfica consegue produzir em um segundo.

Publicidade

Retomando o nosso artigo

Claro que mais é melhor, apesar de que manter esse valor estável é complicado pois a complexidade da cena varia constantemente bastando uma mudança de ângulo para que mesmo com as mesmas variáveis no ecrã a performance se altere. E é aqui que o “Tearing” acontece.

O tearing é um fenómeno que cria uma imagem quebrada. Imaginem tirar uma foto e depois mover a câmara um pouco para o lado e tirar outra foto. Agora sobreponham as fotos, cortem-nas horizontalmente pelo local que quiserem e juntem a parte de cima da primeira foto com a de baixo da segunda foto. O resultado é uma imagem quebrada com diferenças posicionais, o “Tearing”, e que pode acontecer em qualquer parte do ecrã.

A imagem que se segue mostra o efeito a ocorrer na Xbox One no jogo Sniper Elite 3.

Tearing

Porque motivo isto acontece? Vamos dar um exemplo específico:

Imaginem um ecrã com um refrescamento de 75 Hz. E no teu jogo favorito estás a ter 100 fps. Temos aqui um problema pois o monitor actualiza-se 75 vezes por segundo, mas tens 100 imagens por segundo enviadas pela placa. Isto são 33% mais fotogramas do que o monitor pode mostrar.

Isto quer dizer que entre cada refrescamento de ecrã a placa gráfica produziu 1 fotograma completo mais 1/3 de outro. Este terço de frame seguinte será sobreposto no frame buffer ao frame anterior. Quando o monitor vai buscar a imagem este 1+1/3 de frame é desenhado no ecrã criando um efeito de “tearing” pela diferença entre as duas imagens. Mas a placa gráfica entretanto acaba os 2/3 que faltam da imagem e rende mais 2/3 do seguinte. E o ecrã desenha de novo estas imagens incompletas e sobrepostas e temos novo “tearing”, e por aí fora.

Este é um efeito que se torna especialmente notório em movimentações de imagem, sendo que com ela relativamente parada não se nota de forma clara a quebra que se dá na imagem.

Será então de pensar que o ideal para que isto não aconteça será colocar a placa gráfica a calcular exactamente o mesmo número de frames que o refrescamento (fps cravados). E sim, essa é a solução ideal, mas como sabemos isso é algo que nem sempre é possível e para além disso nem sempre é a opção dos programadores.

Como se resolveria esta situação onde a placa gráfica calcula mais fps do que a velocidade de refrescamento do ecrã é capaz de representar?

Isto resolve-se com um buffer duplo, ou Double Buffering. Basicamente uma técnica destinada a mitigar este problema, apesar de não o resolver completamente.

Basicamente com este método temos um frame-buffer e um back-buffer, ou seja um buffer de imagem duplo. Sempre que o monitor quer refrescar-se ele vai buscar a imagem ao frame-buffer, e a placa coloca o novo frame no back buffer copiando-o para o frame buffer apenas quando ele está completo, de modo que teoricamente o monitor nunca vai buscar uma imagem incompleta.

Infelizmente este double buffer requer o dobro da memória vídeo.

No entanto há ainda um problema. O monitor pode refrescar  no exacto momento em que a placa gráfica está a copiar um frame. E nesse caso irá ler informação mista, e iremos ter novamente um frame quebrado.

É aqui que entra o Vsync. Basicamente esta opção cria uma regra que refere que o back buffer só se pode copiar para a frame buffer após um refrescamento do ecrã, evitando esse problema de escrita e leitura simultânea e sincronizando o rácio de frames com o refrescamento do ecrã.

Mas aqui neste caso de Sniper Elite 3 temos o problema ao contrário. Aqui o ecrã está a refrescar a 60 Hz ou mais, mas a consola não está a debitar 60 fps. Ou seja, se até agora falamos no caso em que os FPS são mais do que os Hz, aqui temos o caso contrario.

Para perceber como resolver isso, vamos voltar ao nosso exemplo. E com o mesmo ecrã anteriormente referido, a 75 Hz, vamos colocar a consola a debitar 50 fps, ou seja 33% mais lenta que o ecrã. Ou seja, sempre que o monitor se refresca a placa gráfica ainda só calculou 2/3 da imagem. Vamos ver o que acontece aqui!

O monitor refresca inicialmente sem qualquer imagem até que o frame 1 é copiado para o frame buffer. 2/3 do frame 2 vão para o back buffer e o monitor refresca novamente, indo buscar o primeiro frame. Agora a placa acabou o último terço do segundo frame, mas devido ao Vsync tem de esperar pois só pode actualizar o frame buffer após um refrescamento. O monitor refresca indo buscar novamente o frame 1 e o frame 2 passa para o frame buffer. A placa gráfica desenha 2/3 do frame 3 para o back buffer e o refrescamento acontece, indo-se buscar o frame 2 novamente. A terceira imagem é completa, mas a placa tem mais uma vez de esperar por um refrescamento, o que leva o monitor a ir buscar o frame 2 pela terceira vez.

Publicidade

Retomando o nosso artigo

Ou seja, em 4 ciclos (e daqui para a frente tudo se repete), apenas 2 imagens foram desenhadas. E isto limita as performances do sistema tremendamente (para metade do refrescamento), não podendo acontecer pois a 75hz teriamos apenas 37.5 fps quando a placa debitava 50. Tudo devido às esperas.

Ou seja, o Vsync aqui está a ser um limitador. E este é um dos problemas do Vsync: é bom quando os fotogramas são superiores ao refrescamento, mas limita o máximo dos fps a metade da velocidade do refrescamento quando eles são inferiores.

Este é o motivo pelo qual o Vsync é mal amado e quando menor for o refrescamento do ecrã, pior.

Para resolver isto há uma técnica chamada de triple buffering, ou buffer triplo. Mas que infelizmente requer o triplo da memória de um frame buffer normal.

Com este buffer vamos voltar ao exemplo dos 75 hz e 50 fps. Temos o frame 1 no frame buffer, e 2/3 do segundo no back buffer. O refrescamento acontece e apanha o frame 1 pela primeira vez. O ultimo terço do frame 2 é completo no back buffer, e o primeiro terço do frame 3 é colocado no segundo back buffer. O refrescamento acontece e apanha pela segunda vez o frame 1, o frame 2 é copiado para o frame buffer e o primeiro terço do frame 3 é copiado para o primeiro back buffer, sendo escritos os últimos 2 terços desse mesmo frame. Agora com um novo refrescamento o frame 2 é apanhado pela primeira vez e o frame 3 copia para o frame buffer. E basicamente voltamos ao ponto de partida onde apenas temos o frame buffer cheio. Tivemos 2 frames em 3 ciclos de refrescamento o que é exactamente a percentagem dos fps face ao refrescamento. E isto é verdade para qualquer exemplo que se crie conseguindo-se manter a proporção entre os FPS e os Hz sempre correcta.

O triple buffer requer um pouco mais de performance com as movimentações de dados e memória rápida adicional para manter os três buffers. Mas o triple Buffer com Vsync é a solução efectiva para os problemas de “tearing” criando a proporção correcta de fps a serem colocados no ecrã.

Este é o motivo pelo qual fps “cravados”/”bloqueados” são os ideais. Forza 5 corre a 60 fps fixos, o que quer dizer que na prática não precisa de qualquer buffer duplo ou triplo, apenas de Vsync. A placa gráfica é configurada para 1080p 60 hz, o que corresponde aos 60 fps constantes do jogo, e o jogo é criado garantindo que cada frame é sempre calculado nos 16,67 ms necessários para os 60 fps, simplificando desta forma o uso da memória. O mesmo acontece se tivermos 30 fps bloqueados e constantes onde o ecrã é colocado a 30 Hz e temos 33,3 ms entre frames (Forza Horizon 2).

Ou seja, para um determinado número de  fps ou eles são “cravados”, ou para garantir a eliminação do “Tearing” teremos de ter um frame buffer triplo o que é um problema para apenas 32 MB de RAM.

Um dos melhores exemplos de um motor que foi criado em torno dos FPS e não o contrário (a situação mais habitual) é Wolfenstein: The New order. O jogo foi concebido para garantir que em cada 16.67 ms um frame é produzido. Em situações em que há algo mais intenso no ecrã e a placa começa a ficar apertada, a situação é detectada, e mal o primeiro fps é criado perto do limite de tempo necessário, o motor desce dinamicamente a resolução (c/ re-escalamento) para compensar. Isso garante que o jogo corre a 60 fps cravados, independentemente do que aconteça, sem qualquer “tearing”, ou necessidade de buffers adicionais. Mesmo na PS3 e Xbox 360 o jogo re-escala a sua qualidade gráfica com os 60 fps em mente!

Publicidade

Retomando o nosso artigo

No caso de Sniper Elite 3 na Xbox One o motor não foi pensado assim, sendo bastante mais tradicional, e a equipa conseguiu os 1080p mas, mesmo com cortes nas texturas, um campo de visão, um Ambient Oclussion mais limitado, e menor Anisotropic Filtering, face à PS4 e PC, não conseguiu os 60 fps cravados (o mesmo se passou na PS4 que também não os atinge apesar de obter frame-rates um pouco melhores), não tendo conseguido espaço nos 32 MB para os triple buffer que compensaria esses problemas, daí que o “Tearing” seja uma constante no jogo (algo que não foi problema na PS4).

No entanto o jogo pode aplicar um Vsync, que tem de ser activado nos menus. Como explicado, tal irá limitar o jogo a 30 fps com 60 Hz de refrescamento, mas aparentemente o double buffer não existe ou tem problemas pois ainda existe algum Tearing visível. Seja como for, os 30 fps não foram o caminho optado por defeito pela equipa optando-se por um frame rate livre, mas infelizmente o resultado é o que vemos de seguida, com o screen tearing a ser basicamente constante.

Será de referir que os frame-buffers não são a única coisa que é necessário colocar na memória rápida. Depth targets, shadowmaps, light maps, render targets e outras situações, precisam igualmente de ir para a RAM rápida. E dependendo da dimensão de todos estes factores, por vezes a memória chega… outras vezes não!

Daí a dificuldade na programação da Xbox One dada a pequena quantidade de memória rápida disponível e para garantir que ela chega sempre há que jogar com tudo isto, mover os dados de um lado para o outro e trabalhar por partes. E nesse campo há quem (equipas e motores) consiga melhores e quem consiga piores resultados, sendo que com a experiência e novos SDKs as situações vão certamente melhorar, esperando-se que um futuro patch já prometido para este Sniper Elite e baseado no novo SDK possa amenizar ou resolver o problema.

Publicidade

Posts Relacionados