Shader: ce este, tipuri de shader-e și cum funcționează

Autor: IT Sectr Publicat: 2026-06-11 Timp de citire: 8 min

Shader (shader) — este un program care rulează pe GPU pentru procesarea datelor grafice: vârfuri, fragmente sau sarcini de calcul. Spre deosebire de codul obișnuit pe CPU, shader-ul lucrează paralel pe sute de nuclee, procesând fiecare element independent. Conform datelor Khronos Group (2025), shader-ele sunt folosite în 100% din aplicațiile 3D moderne — de la jocuri mobile până la efecte UI în aplicații de sistem. Dezvoltatorii scriu shader-e în limbaje specializate: GLSL, HLSL, Metal Shading Language sau SPIR-V.

Principalele

  • Shader — program pentru GPU, executat paralel pe sute de nuclee pentru fiecare element al scenei.
  • Tipuri de shader-e: de vârf, fragment, compute, geometry, tessellation și mesh-shader-e.
  • Limbaje: GLSL (OpenGL), HLSL (DirectX), MSL (Metal), SPIR-V (Vulkan) — toate se compilează în cod mașină GPU.
  • Shader-ele în dezvoltarea mobilă sunt folosite pentru efecte, post-procesare, iluminare și calcule.
  • Optimizarea shader-elor: precizie mediump, minimizarea ramificărilor și ATF (Adaptive Texture Fetch) pentru GPU-uri mobile.

Ce este Shader?

Shader — este un program mic, scris într-un limbaj specializat și executat pe GPU. Fiecare shader procesează un element de date — un vârf, un fragment (pixel) sau un element de lucru — independent de celelalte. Paralelismul GPU permite lansarea a mii de instanțe de shader simultan.

Termenul a fost introdus de Pixar în anii 1980 pentru a descrie programele care controlează aspectul suprafețelor în RenderMan. În timp real, shader-ele au apărut cu NVIDIA GeForce 3 (2001) — prima placă video cu pipeline programabil. Înainte de shader-e, grafica era configurată prin parametri ficși: culoare, textură, mod de amestecare.

Conform datelor Unity Technologies (2025), un joc mobil obișnuit folosește 50–200 de shader-e. Fiecare shader are variante (variants) pentru diferite platforme, niveluri de calitate și configurații de iluminare. Numărul de variante poate ajunge la 10 000 per proiect.

Arhitectura shader-ului se împarte în date de intrare (atribute, variabile uniform, texturi), cod program și date de ieșire (culoare, poziție). Variabilele uniform sunt setate din CPU înainte de lansarea shader-ului și sunt neschimbate pentru toate elementele cadrului. Atributele sunt date per element (coordonatele vârfului, normala, coordonatele UV).

Modelul de execuție SIMT

SIMT (Single Instruction, Multiple Threads) — modelul de execuție al shader-elor pe GPU. O instrucțiune este încărcată o singură dată, dar executată de sute de fire pe date diferite. De exemplu, Fragment Shader pentru 1000 de pixeli lansează 1000 de fire cu același cod, dar fiecare fir primește propriile coordonate UV și atribute interpolate.

O consecință importantă a SIMT: ramificările în shader-e sunt costisitoare. Dacă în interiorul unui bloc if jumătate din fire merg pe o ramură și jumătate pe alta, GPU-ul execută ambele ramuri secvențial pentru toate firele. Performanța scade la 50%. Evitați ramificările dinamice în shader-e sau minimizați-le prin calcule prealabile pe CPU.

Tipuri de shader-e

GPU-urile moderne suportă mai multe tipuri de shader-e, fiecare pentru etapa sa din pipeline-ul grafic sau de calcul. Să analizăm tipurile principale: de vârf, fragment, compute și mesh-shader-ele moderne.

Tip shaderEtapa pipelineProceseazăLimbaj
Vertex ShaderVârfFiecare vârfGLSL, HLSL
Fragment ShaderFragmentFiecare pixelGLSL, HLSL
Compute ShaderCalculDate arbitrareGLSL, HLSL
Geometry ShaderGeometricPrimitiveGLSL, HLSL
Tessellation ShaderTeselațiePatch-uriGLSL, HLSL
Mesh ShaderPipeline MeshTask + MeshHLSL, MSL

Vertex Shader

Vertex Shader procesează fiecare vârf al geometriei: transformă coordonatele, calculează iluminarea, transmite datele către fragment shader. Aceasta este o etapă obligatorie a pipeline-ului grafic — fără ea, vârfurile nu ajung pe ecran. Vertex Shader este apelat pentru fiecare vârf al fiecărui cadru.

Fragment Shader

Fragment Shader (sau Pixel Shader) — cea mai consumatoare de resurse etapă. Acesta calculează culoarea finală a fiecărui fragment, folosind texturi, iluminare și material. Fragment Shader este executat pentru fiecare pixel acoperit de geometrie, ținând cont de toate texturile și efectele aplicate. Optimizarea acestui shader oferă cea mai mare creștere de performanță.

Compute Shader

Compute Shader — shader universal pentru calcule arbitrare pe GPU. Spre deosebire de shader-ele grafice, nu este legat de geometrie sau pixeli. Compute Shader lucrează cu buffere de date arbitrare prin grupuri de lucru. Este folosit pentru fizică, simulare de particule, post-efecte și inferență a rețelelor neuronale.

Mesh Shader

Mesh Shader — cel mai nou tip de shader, apărut în NVIDIA Turing (2018) și Metal 3. Mesh Shader înlocuiește shader-ele de vârf, geometric și de teselație cu un singur pipeline mesh. Lucrează împreună cu Task Shader: Task Shader decide ce grupuri mesh să redeze, Mesh Shader generează geometria din mers.

Limbaje pentru scrierea shader-elor

Shader-ele se scriu în limbaje specializate care se compilează în cod mașină GPU. Alegerea limbajului depinde de platformă și API. Să analizăm limbajele principale: GLSL, HLSL, Metal Shading Language și formatul intermediar SPIR-V.

GLSL (OpenGL Shading Language)

GLSL — limbajul de shader-e pentru OpenGL, OpenGL ES și WebGL. Sintaxa se bazează pe C cu adăugarea tipurilor vectoriale (vec2, vec4, mat4) și a funcțiilor încorporate (texture, normalize, reflect). GLSL ES — versiunea pentru dispozitive mobile cu precizie limitată (lowp, mediump, highp). Conform datelor Khronos (2025), GLSL rămâne cel mai răspândit limbaj de shader-e datorită cross-platformității.

glsl
#version 300 es
precision mediump float;
in vec2 v_texCoord;
uniform sampler2D u_texture;
out vec4 fragColor;

void main() {
    fragColor = texture(u_texture, v_texCoord);
}

Un fragment shader simplu citește culoarea din textură după coordonatele UV. precision mediump indică GPU-ului să folosească jumătate de precizie pentru float — accelerează execuția pe dispozitive mobile cu 25–40%.

HLSL (High-Level Shader Language)

HLSL — limbajul de shader-e de la Microsoft pentru DirectX. Sintaxa este mai apropiată de C++ cu suport pentru clase, structuri și șabloane. HLSL este folosit în aplicațiile Windows și prin Shader Model 6.7+ suportă Ray Tracing, Mesh Shaders și Sampler Feedback. Pentru dezvoltarea mobilă, HLSL nu este folosit direct, dar este compilat în SPIR-V pentru Vulkan.

Metal Shading Language

MSL (Metal Shading Language) — limbajul de shader-e Apple, bazat pe C++14. Spre deosebire de GLSL și HLSL, MSL este compilat împreună cu aplicația, ceea ce elimină compilarea JIT pe dispozitiv. MSL suportă pointeri, șabloane și biblioteca standard C++. Este folosit pe toate dispozitivele Apple: iPhone, iPad, Mac, Apple TV.

cpp
#include <metal_stdlib>
using namespace metal;
struct VertexOut {
    float4 position [[position]];
    float2 texCoord;
};

fragment float4
myFragment(VertexOut in [[stage_in]],
            texture2d<float> tex [[texture(0)]]) {
    constexpr sampler s = sampler(filter::linear);
    return tex.sample(s, in.texCoord);
}

MSL folosește atributele [[position]], [[stage_in]] și [[texture(N)]] pentru legarea resurselor. Compilatorul Apple generează cod optimizat pentru GPU-ul curent, ținând cont de numărul de registre și cache.

SPIR-V

SPIR-V — format binar intermediar pentru shader-e, standardul pentru Vulkan. Shader-ele se scriu în GLSL sau HLSL, se compilează în SPIR-V și se încarcă în aplicația Vulkan. SPIR-V nu este legat de un limbaj specific — există compilatoare din Rust, Python, OpenCL C în SPIR-V.

Shader-e în dezvoltarea mobilă

Shader-ele pe platformele mobile au limitări comparativ cu cele desktop: mai puține registre, precizie limitată și lipsa suportului pentru unele instrucțiuni. Să analizăm specificul shader-elor pe Android (Vulkan/OpenGL ES) și iOS (Metal).

Shader-e pe Android

Android folosește GLSL ES pentru OpenGL și SPIR-V pentru Vulkan. OpenGL ES 3.2 suportă shader-e cu precizie implicită mediump. Vulkan necesită compilarea explicită a GLSL în SPIR-V prin glslangValidator. Pe Android, shader-ele se încarcă din resurse text sau din fișiere SPIR-V compilate.

Qualcomm Adreno GPU optimizează shader-ele la nivel de driver. Recomandări: folosiți mediump pentru culoare și UV, highp doar pentru poziții; evitați eșantionarea texturilor în shader-ele de vârf; grupați calculele în vectori (vec4 în loc de 4x float). Conform datelor Qualcomm (2025), aceste optimizări oferă o creștere de 30–50%.

Shader-e pe iOS

iOS folosește exclusiv Metal Shading Language. Shader-ele sunt compilate în cod mașină împreună cu aplicația prin Xcode. Metal oferă Shader Debugger și GPU Capture pentru profilarea shader-elor. GPU-ul Apple (TBDR) are optimizări specifice: early fragment test, memoryless render targets și amestecare programabilă.

Conform datelor Apple WWDC 2024, pentru shader-ele iOS este critic să folosiți half în loc de float, să limitați presiunea pe registre (max 64 de registre) și să evitați eșantionările dependente de texturi. Shader-ele iOS trebuie să fie compacte — dimensiunea optimă este 50–100 de instrucțiuni ALU.

Shader-e în Unity și Unreal Engine

Motoarele de joc Unity și Unreal Engine oferă editoare vizuale de shader-e (Shader Graph, Material Editor) și limbaje abstracte (ShaderLab, USF). Dezvoltatorul scrie shader-ul într-un limbaj de nivel înalt, iar motorul îl compilează pentru platforma țintă. Unity folosește HLSL ca limbaj intermediar, Unreal — USF (Unreal Shader Format).

Optimizarea shader-elor

Optimizarea shader-elor — etapa cheie a dezvoltării grafice pentru dispozitive mobile. Un shader prost scris poate reduce FPS-ul de la 60 la 20. Să analizăm regulile și tehnicile principale de optimizare.

Precizia calculelor

Folosiți precizia minimă suficientă: lowp pentru culoare și UV, mediump pentru normale și iluminare, highp doar pentru poziții și matrici. Conform datelor ARM (2025), operațiile mediump sunt de 2 ori mai rapide decât highp pe GPU-ul Mali. În GLSL ES, aceasta se setează prin calificatorii precision.

Minimizarea eșantionărilor de texturi

Eșantionarea texturilor — cea mai costisitoare operație într-un shader (10–30 de cicluri față de 1–2 pentru o instrucțiune ALU). Reduceți numărul de eșantionări: combinați texturile în atlase, folosiți stocarea în array-uri uniform în loc de texturi, stocați în cache rezultatele pixelilor vecini prin instrucțiuni derivative.

Evitați ramificările

Ramificările dinamice (if cu variabilă uniform) reduc performanța pipeline-ului SIMT. Înlocuiți ramificările cu funcții matematice: mix(), step(), smoothstep() și clamp(). Aceste funcții se execută în 1–2 instrucțiuni, în timp ce o ramificare poate costa 8–16 instrucțiuni din cauza divergenței firelor.

glsl
// Rău: ramificare dinamică în shader
if (u_enableLight) {
    color *= computeLighting(normal);
}

// Bine: înlocuirea matematică a ramificării
color *= mix(1.0, computeLighting(normal),
              float(u_enableLight));

mix() efectuează interpolarea liniară între două valori. Când u_enableLight=0, se returnează 1.0 — culoarea nu se schimbă. Când u_enableLight=1, se returnează rezultatul iluminării. Fără ramificare — toate firele execută același cod.

Exemple de shader-e

Să analizăm exemple practice de shader-e pentru dezvoltarea mobilă — de la umbrirea simplă până la generarea procedurală de texturi. Fiecare exemplu demonstrează o tehnică specifică.

Umbrirea Phong (vertex shader)

Modelul Phong — modelul clasic de iluminare cu componente difuză și speculară. Vertex Shader calculează iluminarea pentru fiecare vârf, Fragment Shader doar interpolează rezultatul (Gouraud shading). Potrivit pentru dispozitive mobile datorită costului redus.

glsl
#version 300 es
layout(location = 0) in vec4 a_position;
layout(location = 1) in vec3 a_normal;
uniform mat4 u_mvp;
uniform mat4 u_modelView;
out vec3 v_color;

void main() {
    vec3 normal = normalize(mat3(u_modelView) * a_normal);
    vec3 lightDir = normalize(vec3(0.0, 1.0, 1.0));
    float diff = max(dot(normal, lightDir), 0.0);
    v_color = vec3(0.8, 0.2, 0.2) * (0.3 + diff * 0.7);
    gl_Position = u_mvp * a_position;
}

Shader-ul calculează iluminarea diffuse: produsul scalar dintre normală și direcția luminii. Rezultatul este amestecat cu componentele ambient (0.3) și diffuse (0.7). Execută 10–15 instrucțiuni ALU per vârf — acceptabil pentru 100 000 de poligoane la 60 FPS pe un GPU mobil.

Textură procedurală (fragment shader)

Texturile procedurale sunt generate în Fragment Shader fără încărcare din fișier. Economisesc memoria video și simplifică animația. Exemplu — o tablă de șah cu dimensiunea variabilă a celulelor. Doar câteva instrucțiuni ALU — încărcare minimă pe GPU.

glsl
#version 300 es
precision mediump float;
in vec2 v_uv;
uniform float u_cells;
out vec4 fragColor;

void main() {
    vec2 cell = floor(v_uv * u_cells);
    float isWhite = mod(cell.x + cell.y, 2.0);
    fragColor = mix(vec4(0.1, 0.1, 0.1, 1.0),
                     vec4(0.9, 0.9, 0.9, 1.0),
                     isWhite);
}

8 instrucțiuni ALU — shader-ul ideal pentru dispozitive mobile. u_cells setează numărul de celule pe axă. floor și mod — operații ieftine, executate în 1 ciclu pe toate GPU-urile mobile.

Întrebări frecvente

Cu ce se deosebește un shader de un program obișnuit în C++?

Shader rulează pe GPU în modul SIMT — o instrucțiune pentru sute de fire. Un program obișnuit în C++ — pe CPU în modul MIMD. Shader-ul nu are acces la sistemul de fișiere, intrare/ieșire și memorie dinamică. Primește date prin buffere și texturi și returnează poziția sau culoarea.

Ce limbaj de shader-e să învăț pentru dezvoltarea mobilă?

GLSL — pentru OpenGL ES și WebGL, cross-platform. Metal Shading Language — pentru iOS. HLSL — baza pentru Unity și Unreal Engine. Începeți cu GLSL — înțelegerea de bază se transferă pe orice limbaj de shader-e.

De ce shader-ele funcționează lent pe dispozitive mobile?

Cauzele principale: precizie ridicată (highp în loc de mediump), eșantionări excesive de texturi, ramificări dinamice și depășirea limitei de registre. Folosiți RenderDoc sau Xcode GPU Frame Debugger pentru analiza shader-elor.

Ce este compute shader și la ce servește?

Compute Shader — shader pentru calcule arbitrare pe GPU: fizica particulelor, procesarea imaginilor, simularea țesăturilor. Spre deosebire de Fragment Shader, nu este legat de pixeli și poate scrie în buffere arbitrare.

Se pot scrie shader-e fără cunoștințe de limbaje de programare?

Da, prin editoare vizuale: Shader Graph în Unity, Material Editor în Unreal Engine sau Metal Shader Converter. Acestea generează cod de shader pe baza unei scheme de noduri. Pentru optimizare profundă, este necesară înțelegerea limbajului de shader-e.

Concluzii

  • Shader — program paralel pentru GPU, procesând vârfuri, fragmente sau date arbitrare în masă.
  • Tipuri de shader-e: Vertex, Fragment, Compute, Geometry, Tessellation și Mesh — fiecare răspunde de etapa sa din pipeline.
  • Limbaje: GLSL (OpenGL), HLSL (DirectX), MSL (Metal), SPIR-V (Vulkan) — se compilează în cod mașină GPU.
  • Specificul mobil: precizie mediump, minim de eșantionări de texturi, fără ramificări dinamice.
  • Optimizare: mix() în loc de if, precizie half, ATF, combinarea texturilor în atlase și calcule prealabile pe CPU.
  • Aplicare: iluminare Phong, texturi procedurale, post-efecte, fizica particulelor și efecte UI.
  • Unelte: RenderDoc, Xcode GPU Debugger, Qualcomm Adreno Profiler și Mali Offline Compiler pentru analiza shader-elor.

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și