Los Shaders nunca, absolutamente nunca ejecutan en modo directo ni indirecto por la naturaleza de las propias GPUs. Entiendase modo directo como el siguiente formato de instrucción:

Instrucción+Dirección de Memoria de los datos.

Existen instrucciones que se realizan de manera inmediata (el dato a procesar se encuentra en la misma instrucción) y otras en modo directo e indirecto. En el caso de una ALU en una CPU esta tiene la capacidad de ir bajando niveles pero en el caso de una GPU pese a haber diferentes niveles de cache las ALUs de los shaders no operan sobre estos sino solo sobre sus registros por lo que tiene un subsistema de captación de datos diferentes a una CPU. ¿Las ventajas de esto?

  • En primer lugar permite mantener fijas las duraciones en ciclos de las instrucciones y esto permite a los planificadores en los diferentes niveles organizarse ya que están organizados como un reloj suizo en precision.
  • En segundo lugar reduce la complejidad en el set de instrucciones de las ALUs de la GPU reduciendo la complejidad de dichos núcleos al eliminar las instrucciones de gestión de memoria del procesador así como sus registros típicos.

¿Entonces como saben las ALUs que han de procesar? Bueno, lo saben porque lo que ejecutan son lo que tienen en sus registros. Pero esos datos y la instruccion pertinente son alimentados por el planificador del procesador, como he dicho antes los shaders no tienen mecanismos de captación de datos, son elementos completamente pasivos que necesitan de un organo director que les vaya dando los datos y las instrucciones a procesar. Es decir, requieren de un caudal de datos por eso se les llama procesadores de caudal o Stream Processors en Inglés. El paradigma es que ado una secuencia de dato (un causal) una serie de operaciones llamadas llamadas «kernels de computación» se ejecutan. ¿Que es un kernel de computacion? Se trata de una rutina que no es ejecutada en la CPU sino en un acelerador externo que en este caso es una GPU pero con la particularidad de que se trata de un bucle circular, es decir, se trata de un programa que cuando se llega a la última dirección de memoria se vuelve a la inicial en lo que a la lista de instrucciones se refiere. Es decir, los Shaders aplican un programa a un caudal que puede ser de n instrucciones que corresponden al bucle circular y cuando se vuelve a la instrucción 0 se carga un nuevo caudal de datos para que sea procesado, un caudal de datos pueden ser vertices (vertex shaders), primitivas gráficas (geometry shader) o fragmentos/pixeles (Pixel/Fragment Shader) pero simplemente pueden ser datos genéricos (Compute Shaders).

¿La salida de los datos? Dependerá de la etapa en la que nos encontremos del pipeline gráfico.

shader_full.jpeg

La carga computacional dependerá de la cantidad de datos a procesar en cada una de las etapas del pipeline. Siendo la más grande la de los Pixel/Fragment Shaders.

DiamondStructure

Es decir, en la etapa del texturizado el caudal de dato es mucho mayor que en otras etapas anteriores.  Ahora bien, solo al final del pipeline es cuando los datos se copían directamente a la memoria principal.En el pipeline gráfico esa salida se envia a los ROPS de la GPU y en el caso de que sea el pipeline de computación a la cache L1 o la L2 como salida. Los ROPS dependiendo de la arquitectura escribiran a una memoria interna, una cache L2 o directamente a la memoria externa. Pero eso será solo al final del pipeline porque los datos en las demás etapas no van a la memoria principal sino que se quedan circulando dentro de la propia GPU y es ahí donde entramos en otra parte que explica la naturaleza de los shaders que es la interconexión entre las diferentes partes de la GPU con los Shaders.

¿Que tenemos que tener en cuenta? Pues que actualmente los Shaders no están especializados al tipo de dato sino que son recursivos por lo que estos tienen un sistema de interconexión con el resto de componentes que componenen la GPU en conjunto. La interconexion entre las diferentes partes se puede hacer de diversas maneras pero se ha de tener que existe una enorme cantidad de unidades. ¿Como las comunicamos entre si? Hay dos formas por lo general.

  • La primera es generar un anillo. Pensad en ello como la clásica autopista urbana (ronda) de muchos carriles y cuando un dato/coche llega a su destino entonces coge esa salida.
  • La segunda es una red en matriz donde todos los componentes están conectados entre si o al menos los que se necesita que estén conectados. ¿Los efectos de esto? Necesitariamos un enorme ancho de banda interno para traspasar todos los datos. Ahora imaginaos la complejidad en el cableado si le diesemos a las ALUs de una GPU la capacidad de acceder a la memoria principal.

¿Entendéis ahora porque los shaders no tienen método alguno de acceder a la memoria? Simplemente es el sacrificio que se ha de hacer para tener no decenas hoy en dia sino centenares e incluso miles de ALUs operando a tiempo real. Imaginaos la enorme complejidad del sistema de captación de memoria si cada ALU tuviese un mecanismo de captación activo.

¿Y toda esta larga explicación para que? Para explicar porque las ALUs de la GPU no pueden operar más allá de sus registros, lo que significa que no pueden operar con un sistema operativo y si os habéis preguntado porque lenguajes shader de alto nivel como PSSL, HLSL y GLSL carecen de punteros, simplemento estos al ser lenguajes para programar los shaders y ser su producto los kernels de computación que es lo que llamamos «Shaders» acaban ajustandose a su naturaleza.