Aceleradoras de vídeo: 2D

As interfaces gráficas
E então vieram as interfaces gráficas. A primeira a ter alguma aceitação comercial foi a do Apple MacIntosh, lançado em 1984, mas restrita a um nicho de mercado. O sucesso veio em 1990 com Windows 3 (as versões anteriores, assim como outras tentativas de uso de interfaces gráficas não “vingaram”). E então as coisas mudaram. Pois todas as telas tornaram-se gráficas, inclusive a do sistema operacional.
Desculpe insistir, mas quem jamais usou uma tela de caracteres, como a maioria dos leitores desta coluna, talvez não consiga perceber a diferença. Então vou tentar explicar.
Enquanto uma tela de caracteres era uma matriz de retângulos nos quais cabia um caractere em cada, uma tela gráfica, mesmo nos tempos de antanho (entenda-se por antanho a era do IBM XT, primeira metade da década de oitenta do século passado) era constituída por uma matriz de pontos. E como os pontos formam a imagem, recebem o nome de “célula de imagem”, ou “Picture Cell“, em inglês, expressão contraída para “pixel”.
Quantos pixels e quantas cores cada tela gráfica pode exibir depende do padrão de vídeo. Uma das mais simples é a que se vê na Figura 2, mostrando o King´s Quest, um dos primeiros jogos para PC, usando o padrão CGA (Color Graphics Array) que exibia 200 linhas de 320 pixels cada, que podiam assumir uma entre dezesseis diferentes cores.
Sim, eu sei, comparada com as telas dos jogos modernos a da Figura 2 há de provocar gargalhadas. Mas não se iluda: para a época era um progresso e tanto (embora ainda não o suficiente para ser usada em uma interface gráfica). Mas comparada com uma tela de caracteres, era (literalmente) outra coisa…
Para começar, a tela gráfica é formada por pontos coloridos, não por retângulos contendo informações. E o número de pontos é muito maior. Assim como, dependendo do número de cores, também é maior o número de informações nela contidas. Complicou? Pois expliquemos.
Tomemos uma tela de caracteres 80×25. Ela é formada por 2.000 elementos (retângulos). Cada elemento contém um código de caractere (de acordo com a tabela ASCII então usada para caracteres, cada um deles ocupa um byte), que pode assumir uma entre dezesseis cores (e para exprimir 16 números diferentes bastam quatro bits, ou meio byte) e pode ter quatro atributos, cada um deles “ligado” ou “desligado” (mais quatro bits para armazenar o estado dos atributos). Portanto, cada elemento pode ser inteiramente caracterizado por dois bytes (um para o código de caractere, meio para a cor e meio para o atributo). Uma tela inteira pode ser armazenada em um total de 2.000 elementos x 2 bytes = 4.000 bytes
E como saber a posição do elemento na tela? Ora, basta lembrar que os elementos devem ser lidos da esquerda para a direita e de cima para baixo, de dois em dois bytes, linha após linha (ou seja: ao chegar ao final de uma linha, salta-se para a primeira posição da de baixo). Portanto a ordem do conjunto de bytes que constituem uma “tela” na memória de vídeo é suficiente para identificar a posição de cada elemento.
A tela gráfica obedece ao mesmo princípio. Imagine uma tela um pouco mais sofisticada que a da Figura 2, a tela CGA de 256 cores (na qual cada pixel pode assumir uma dentre 256 diferentes cores que, portanto, podem ser expressas por números de zero a 255 que ocupam um byte). Neste caso, para exprimir um pixel, basta sua cor (pois a posição, como vimos, é desnecessária já que, como os elementos da tela de caracteres, são “desenhados” na tela um a um, da esquerda para a direita e de cima para baixo, linha a linha).
Então, que espaço da memória de vídeo é ocupado por uma tela gráfica CGA 320×200 de 256 cores? Ora, 320 x 200 x 1 = 64.000 bytes (um para cada pixel).
Agora, pense. Para exibir a tela de caracteres, a UCP tem que montá-la na memória de vídeo sessenta vezes por segundo, ou seja, enviar 60 vezes 4.000 bytes = 240.000 bytes/s para a controladora de vídeo (que abriga a memória de vídeo).
Já para exibir uma tela gráfica é preciso enviar 60 x 64.000 = 3.840.000 bytes/s. E isto para a mais simples das telas.
Quando as interfaces gráficas começaram a se popularizar, o padrão de tela dominante era a VGA (Video Graphics Array) de 640 x 480 pixels e 65.536 cores (ou 64K cores, que exigia 16 bits ? ou 2 bytes ? para armazenar cada cor). Uma tela inteira ocupava então na memória de vídeo um total de 640 x 480 x 2 = 614.400 bytes. Que, para ser renovada 60 vezes por segundo, exigia que a UCP compusesse cada uma das telas e as enviasse para a controladora de vídeo em uma taxa de 60 x 614,400 = 36.864.000 bytes/s.
Tínhamos aí dois problemas.
O primeiro era a carga de trabalho sobre a UCP, ou microprocessador. Que, além de todas as demais tarefas exigidas pelos programas, ainda tinha que empregar grande parte de sua capacidade de processamento “desenhando” telas.
O segundo era a possibilidade de transportar tantos bytes em um intervalo de tempo tão curto entre UCP e controladora de vídeo usando o lento barramento de Entrada/Saída de então (barramento é o nome que se dá aos condutores elétricos e seus circuitos de controle que comunicam os elementos internos da placa-mãe; os que ligam a UCP à controladora de vídeo, que fica “espetada” em um dos “slots”, constituem o barramento de E/S).
E isto para o padrão VGA de 64K cores. Porque logo depois apareceram padrões de vídeo com maior resolução (número de pixels) e número de cores. Só para que se tenha uma ideia, logo depois de aparecerem as interfaces gráficas o padrão XVGA (eXtended VGA) começou a se popularizar com suas 768 linhas de 1024 pixels cada, capaz de exibir o inacreditável número de 16 milhões de cores (ou seja: eram precisos 4 bytes para armazenar um único pixel). O resultado disto é que apenas uma tela ocupava mais de 3 MB de memória (faça as contas) e, só para renovar as telas, o tráfego sobre o barramento de E/S era da ordem de 180 MB/s.
Não dava.
Alguma coisa precisava ser feita.
Para suportar o aumento do tráfego de dados sobre o barramento a solução foi criar novos padrões de barramento. A primeira tentativa foi o VESA, depois veio o PCI seguido do AGP até, finalmente, chegarmos ao PCI-E (PCI eXpress) usado atualmente pelas controladoras gráficas de alto desempenho, que na versão atual (PCI-E 2.1) é capaz de suportar a extraordinária taxa de transferência de 16 GB/s (Gigabytes por segundo).
E para dar conta do armazenamento das telas, com todos os seus pontos e cores exigidos pelos novos padrões de vídeo (o padrão WQXGA, ou Wide Quad eXtended Graphics Array exibe uma tela de 1600 linhas de 2650 pixels, cada uma ocupando 4,1 MB; e não é o de maior resolução possível: veja a relação no tópico “Graphic display resolutions” da Wikipedia) foi preciso aumentar a capacidade de memória das controladoras de vídeo, que passou dos 16 KB (para quem estranhou, confirmando por extenso: dezesseis quilobytes) das primeiras controladoras CGA para a espantosa casa dos GB (GigaBytes !!!) de memória instalada nas placas modernas.
Talvez um dia falemos sobre uma coisa ou outra. Mas hoje, o que nos interessa é descobrir como os fabricantes resolveram o terceiro aspecto do problema: reduzir a imensa carga de processamento sobre a UCP representada pela necessidade de “desenhar” as telas gráficas das novas interfaces.
Pois foi da maneira mais simples e direta possível: se a UCP não dá conta do trabalho, então vamos arranjar quem a ajude, ou seja, faça o “trabalho braçal” de desenhar as telas em seu lugar, liberando-a para tarefas mais nobres.
E foi assim que surgiram as primeiras “placas aceleradoras”.
