
WebGLìì í멎ì í íë ìì 귞늬ë ëì, GPUë ìë°±ë§ ê°ì íœì ì ë³ë ¬ë¡ ì²ëЬí©ëë€. ìŽ ë¬žìë í íœì ì êŽì ìì 1/60ìŽ(í íë ì) ëì ìŒìŽëë 몚ë ìŒì ììží ì€ëª í©ëë€.
ìê° t = 0 ms (íë ì ìì) â [CPU] JavaScript ì€í / ë°ìŽí° ì€ë¹ â [GPU] Vertex Shader (ì ì ì²ëЬ) â [GPU] Rasterization (ëì€í°í) â [GPU] Fragment Shader (íœì ì²ëЬ) â ì°ëŠ¬ê° ì§ì€í ë¶ë¶ â [GPU] Output Merger (ìµì¢ ìì ê²°ì ) â [Display] íë ìë²íŒ â 몚ëí° ì¶ë ¥ â ìê° t = 16.67 ms (60 FPS êž°ì€, ë€ì íë ì ìì)
| ëšê³ | ì²ëЬ ìì¹ | ì²ëЬ ëì | ìí |
|---|---|---|---|
| Application | CPU | ë°ìŽí° | íë¡ê·žëš ë¡ì§ |
| Vertex Shader | GPU | ì ì (vertices) | 3D â 2D ì¢í ë³í |
| Rasterization | GPU | êž°íí | êž°íí â íœì ë³í |
| Fragment Shader | GPU | íœì (fragments) | íœì ì ì ê²°ì |
| Output Merger | GPU | íë ìë²íŒ | ìµì¢ ìì êž°ë¡ |
ìŽêž° ìí:
ìºë²ì€ íŽìë: 1024 à 1024 (1,048,576ê° íœì
)
ë ëë§ ë°©ì: Fragment Shader SDF
íë ììš: 60 FPS (íë ìë¹ 16.67ms)
// HTML5 Canvasì WebGL 컚í
ì€íž íìž
const canvas = document.getElementById('glCanvas');
const gl = canvas.getContext('webgl2');
// Uniform ë°ìŽí° ì€ë¹ (몚ë Fragment Shaderì ëìŒíê² ì ë¬)
const resolutionLoc = gl.getUniformLocation(program, 'u_resolution');
gl.uniform2f(resolutionLoc, 1024.0, 1024.0);
ìŽ ëšê³ììì CPU ìì :
ë©ëªšëЬ ìì¹: CPU RAM â GPU VRAM
// GPU ë ëë§ ëª
ë ¹ ë°í
gl.clear(gl.COLOR_BUFFER_BIT); // íë ìë²íŒ ìŽêž°í
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); // ë ëë§ ìì
ìŽ ížì¶ìì:
Vertex Shaderë ê° ì ì ìì ì€íë©ëë€. ì 첎 í멎ì ë®ë ì§ì¬ê°í(2ê° ìŒê°í)ì 귞늬ë¯ë¡ 4ê°ì ì ì ììë§ ì€íë©ëë€.
#version 300 es
in vec4 position; // ì ì ìì¹
void main() {
gl_Position = position; // íŽëŠœ ê³µê° ì¢íë¡ ë³í
}
ì€í:
Vertex 0: (-1, -1) â gl_Position = (-1, -1, 0, 1)
Vertex 1: ( 1, -1) â gl_Position = ( 1, -1, 0, 1)
Vertex 2: (-1, 1) â gl_Position = (-1, 1, 0, 1)
Vertex 3: ( 1, 1) â gl_Position = ( 1, 1, 0, 1)
ì²ëЬ ìê°: ë§€ì° ë¹ ëŠ (ì ëë žìŽ)
ì ì 4ê°ë¡ ì ìë ë ê°ì ìŒê°íì íœì ëšìë¡ ë³íí©ëë€.
ìŒê°í 1: Vertex 0, 1, 2
ìŒê°í 2: Vertex 1, 2, 3
결곌: 1024 à 1024 = 1,048,576ê°ì Fragment ìì±
ê° Fragmentì í ë¹ëë ì 볎:
Fragment (512, 256):
- í멎 ì¢í: (512, 256)
- gl_FragCoord: (512.5, 256.5) (íœì
ì€ì¬)
- Interpolated values: (VaryingData 볎ê°)
- Depth: 0.0 (ê¹ìŽ í
ì€ížì©)
ì²ëЬ ìê°: ë³ë ¬ ì²ëЬ (몚ë íœì ëì)
íê² íœì : (512, 256)
#version 300 es
precision highp float;
uniform vec2 u_resolution;
out vec4 outColor;
float circleSDF(vec2 p, float radius) {
return length(p) - radius;
}
void main() {
// ===== íœì
(512, 256)ì Shader ì€í ìì =====
// Step 1: íì¬ íœì
ì¢í ìœêž°
// gl_FragCoord.xy = (512.5, 256.5) â GPUê° ìë ì ê³µ
// Step 2: ì ê·í ì¢í ê³ì°
vec2 uv = gl_FragCoord.xy / u_resolution * 2.0 - 1.0;
// uv = (512.5, 256.5) / (1024.0, 1024.0) * 2.0 - 1.0
// uv = (1.00098, 0.50098) * 2.0 - 1.0
// uv = (2.00196, 1.00196) - 1.0
// uv â (1.00196, 0.00196)
// Step 3: ì¢
í¡ë¹ 볎ì (ì ì¬ê°íìŽë¯ë¡ ìí¥ìì)
uv.x *= u_resolution.x / u_resolution.y;
// uv.x *= 1024.0 / 1024.0 = 1.0 (ë³íìì)
// Step 4: 거늬 ê³ì°
float sdf = circleSDF(uv, 0.3);
// sdf = length((1.00196, 0.00196)) - 0.3
// sdf = â(1.00196² + 0.00196²) - 0.3
// sdf = â1.00394 - 0.3
// sdf â 1.00196 - 0.3
// sdf â 0.70196 (ìžë¶)
// Step 5: ê²œê³ ì²ëЬ
float edge = fwidth(sdf) * 1.5;
// fwidth: ìžì íœì
ê° ë¯žë¶ê°
// í멎 íŽìëì ë°ëŒ ëì ê³ì°
// Step 6: smoothstepìŒë¡ 볎ê°
float fill = smoothstep(edge, -edge, sdf);
// edge â 0.001 ìŽëŒ ê°ì
// smoothstep(0.001, -0.001, 0.70196)
// sdf > edgeìŽë¯ë¡ â fill = 0.0
// Step 7: ìì ê²°ì
vec3 mintColor = vec3(0.0, 0.85, 0.64);
vec3 color = mix(vec3(0.0), mintColor, fill);
// color = mix((0.0, 0.0, 0.0), (0.0, 0.85, 0.64), 0.0)
// color = (0.0, 0.0, 0.0) â ê²ì ì
// Step 8: ì¶ë ¥
outColor = vec4(color, 1.0);
// outColor = (0.0, 0.0, 0.0, 1.0) â ìì ë¶í¬ëª
í ê²ì ì
}
ì²ëЬ ìê°: íœì ë¹ ìœ 200~500 ëë žìŽ (ìì² ê²ìŽíž ì°ì°)
ëìì ì€íëë Fragment Shader:
GPU ìœìŽ ê·žë£¹ 1: íœì
(0, 0), (1, 0), (2, 0), (3, 0) ëì ì€í
GPU ìœìŽ ê·žë£¹ 2: íœì
(4, 0), (5, 0), (6, 0), (7, 0) ëì ì€í
GPU ìœìŽ ê·žë£¹ 3: íœì
(8, 0), (9, 0), (10, 0), (11, 0) ëì ì€í
...
GPU ìœìŽ ê·žë£¹ N: íœì
(1020, 1023), (1021, 1023), (1022, 1023), (1023, 1023) ëì ì€í
ìŽ 1,048,576ê° íœì
ì ìœ 262,144ê°ì "ìí(warp)"ë¡ ëëìŽ ì²ëЬ
(NVIDIA GPU êž°ì€ í ìí = 32ê° ì€ë ë)
결곌ì ìŒë¡ 몚ë íœì
ì ìììŽ ìœ 16ms ëŽì ê³ì°ëš
uv = (256.5, 512.5) / 1024.0 * 2.0 - 1.0
â (-0.499, 0.001)
sdf = length((-0.499, 0.001)) - 0.3
= â(0.249 + 0.000001) - 0.3
â 0.499 - 0.3
â 0.199 (ê²œê³ ê·Œì²)
fill = smoothstep(0.001, -0.001, 0.199)
â 0.8 (ë¶ë¶ì ìŒë¡ ì±ìì§)
color = mix((0.0, 0.0, 0.0), (0.0, 0.85, 0.64), 0.8)
â (0.0, 0.68, 0.512) â ì§í 믌ížì
uv â (0.0, 0.0)
sdf = length((0.0, 0.0)) - 0.3
= 0.0 - 0.3
= -0.3 (ëŽë¶)
fill = smoothstep(0.001, -0.001, -0.3)
= 1.0 (ìì í ì±ìì§)
color = mix((0.0, 0.0, 0.0), (0.0, 0.85, 0.64), 1.0)
= (0.0, 0.85, 0.64) â ë°ì 믌ížì
uv â (0.501, 0.501)
sdf = length((0.501, 0.501)) - 0.3
= â(0.502) - 0.3
â 0.709 - 0.3
= 0.409 (ìžë¶)
fill = smoothstep(0.001, -0.001, 0.409)
= 0.0 (ì±ìì§ì§ ìì)
color = (0.0, 0.0, 0.0) â ê²ì ì
ê° Fragment Shaderê° outColor륌 ë°íí멎, GPUì Output Merger ëšê³ê° ìŽ ê°ì íë ìë²íŒ(Framebuffer)ì êž°ë¡í©ëë€.
íœì
(512, 256):
outColor = (0.0, 0.0, 0.0, 1.0)
â íë ìë²íŒ[512][256] = (0.0, 0.0, 0.0, 1.0)
íœì
(256, 512):
outColor â (0.0, 0.68, 0.512, 1.0)
â íë ìë²íŒ[256][512] = (0.0, 0.68, 0.512, 1.0)
íœì
(512, 512):
outColor = (0.0, 0.85, 0.64, 1.0)
â íë ìë²íŒ[512][512] = (0.0, 0.85, 0.64, 1.0)
ë©ëªšëЬ ìì¹: GPU VRAM (íë ìë²íŒ ë©ëªšëЬ)
Blending (ìí ëžë ë©)
if (gl_FragCoordê° ìŽë¯ž ë€ë¥ž ë¬Œì²Žë¡ ì±ìì§) {
ìµì¢
ì = Ʞ졎ì * (1 - alpha) + ìì * alpha
}
Depth Test (ê¹ìŽ í ì€íž)
if (íì¬ íœì
ì ê¹ìŽ < íë ìë²íŒì ê¹ìŽ) {
íë ìë²íŒì êž°ë¡
} else {
ë²ëŠŒ (ë€ì ììŒë¯ë¡ 볎ìŽì§ ìì)
}
íì¬ ìì ë ê¹ìŽ í ì€íž ììŒë¯ë¡ 몚ë íœì ìŽ êž°ë¡ë©ëë€.
GPU íë ìë²íŒ (VRAM)
â (PCIe ë²ì€)
ëì€íë ìŽ ì ìŽêž°
â
몚ëí° ë©ëªšëЬ
â
í멎 ë ëë§
ìê°: ìœ 1ms (ê³ ì ì ì¡)
몚ëí° ê°±ì ìš: 60 Hz (16.67msë§ë€)
ìê°ì¶:
t=0ms: íë ì 1 ë ëë§ ìì
t=15ms: íë ì 1 íë ìë²íŒ ìì±
t=16.67ms: 몚ëí°ê° íë ì 1 íì ìì
íë ì 2 ë ëë§ ìì (ëì)
t=32ms: íë ì 2 íë ìë²íŒ ìì±
t=33.33ms: 몚ëí°ê° íë ì 2 íì ìì
ì¬ì©ìê° ë³Žë ê²:
t=0ms
Vertex Shader (4ê° ì ì ) ìë£ â ë§€ì° ë¹ ëŠ
t=0.1ms
Rasterization ìë£ â íœì
ìì±
t=0.2ms
Fragment Shader ìì
ââ GPU ìœìŽ ê·žë£¹ 1~256: ëì ì€í
ââ ê° ê·žë£¹: ìœ 4,096ê° íœì
ì²ëЬ
ââ ìŽ 1,048,576ê° íœì
ë³ë ¬ ì²ëЬ
t=5ms
몚ë Fragment Shader ìë£
(1,048,576ê° íœì
à 200ëë
žìŽ / 256ê° ë³ë ¬ ì²ëЬ)
t=5.5ms
Output Merger ëšê³ (ìì êž°ë¡)
t=6ms
íë ì ìì± (íë ìë²íŒ ì¬ì© ê°ë¥)
t=15ms
GPU ì íŽ ìí (CPUê° ë€ì íë ì ì€ë¹)
t=16.67ms
몚ëí° ê°±ì , ë€ì íë ì ìì
GPU íŽë: ìœ 1.5~2.0 GHz (íë GPU)
íŽë 죌Ʞ: ìœ 0.5~0.67 ëë
žìŽ
í íœì
ì Fragment Shader ì€í:
- ëª
ë ¹ìŽ ê°ì: ìœ 200~300ê°
- íŽë 죌Ʞ: ìœ 400~600 íŽë
- ì€ì ìê°: ìœ 200~400 ëë
žìŽ
1,048,576ê° íœì
ì²ëЬ:
- ìì°š ì²ëЬ ìê°: ìœ 209ms (ë¶ê°ë¥)
- 256ê° ëì ì²ëЬ: ìœ 4ms (ì€ì )
- 1024ê° ëì ì²ëЬ: ìœ 1ms (ìµì GPU)
âââââââââââââââââââââââââââââââââââââââââââ
â CPU (Main Memory) â
â Shader source code â
â Canvas context â
â Uniform values (u_resolution) â
â Vertex positions â
âââââââââââââââââ¬ââââââââââââââââââââââââââ
â (glDrawArrays ížì¶)
â
âââââââââââââââââââââââââââââââââââââââââââ
â GPU Command Queue â
â (PCIe Bus륌 íµíŽ ì ì¡) â
ââââââââââââââââ¬âââââââââââââââââââââââââââ
â
â
âââââââââââââââââââââââââââââââââââââââââââ
â GPU VRAM (Video Memory) â
â ââ Vertex Buffer â
â ââ Compiled Shaders â
â ââ Uniforms (ìì ë©ëªšëЬ) â
â ââ Framebuffer (ì¶ë ¥ ë²íŒ) â
â ââ íë ì ìì: ê²ì ìë¡ ìŽêž°í â
â ââ íë ì ì€: ê° íœì
ìì êž°ë¡ â
â ââ íë ì ì¢
ë£: ìì±ë ìŽë¯žì§ â
ââââââââââââââââ¬âââââââââââââââââââââââââââ
â
â
âââââââââââââââââââââââââââââââââââââââââââ
â Display Memory (VRAMì ìŒë¶) â
â (íë ìë²íŒ ë³µì¬ë³ž) â
ââââââââââââââââ¬âââââââââââââââââââââââââââ
â
â
âââââââââââââââââââââââââââââââââââââââââââ
â Monitor (Display) â
â (60 Hzë¡ ê°±ì ) â
âââââââââââââââââââââââââââââââââââââââââââ
íë ì í¬êž°: 1024 à 1024 à 4 ë°ìŽíž (RGBA) = 4MB
íë ìë²íŒ ì°êž°:
- 1,048,576ê° íœì
à 4 ë°ìŽíž = 4MB
- ë©ëªšëЬ ëìí: ìœ 200~300 GB/s (íë GPU)
- ì ì¡ ìê°: ìœ 13~20 ëë
žìŽ (ë§€ì° ë¹ ëŠ)
ì 첎 ë©ëªšëЬ ì ê·Œ ìê°:
- Vertex buffer ìœêž°: 0.1ms
- Uniform ìœêž°: ë§€ì° ë¹ ëŠ (ìºì)
- Framebuffer ì°êž°: ìœ 3ms
- ìŽí©: ìœ 3.5ms
// íë ì 1
gl.drawArrays(...); // GPU ëª
ë ¹ ë°í (ë¹ëêž°)
// CPUë ìŠì ë°í (GPUê° ì²ëЬ ì€)
// ë§ìœ ì¬êž°ì ëêž°í륌 ìí멎:
gl.finish(); // GPU ìì
ìŽ ëªšë ìë£ë ëê¹ì§ ëêž°
// â ì±ë¥ ì í (ë³ë ¬ ì²ëЬ ë¶ê°)
// ì¬ë°ë¥ž ë°©ë²:
gl.drawArrays(...); // GPU ëª
ë ¹ ë°í
// CPUë ë€ì íë ì ì€ë¹ ìì (ë³ë ¬ ì²ëЬ)
Vertex Shader ìë£
â
[ëêž°í]
â
Rasterization ìì
â
Fragment Shader ìì
â
[ëêž°í]
â
Output Merger ìì
GPUë ìŽ ëêž°í륌 ìëìŒë¡ ì²ëЬí©ëë€. ê°ë°ìë ëª ìì ìŒë¡ ì ìŽí íì ììµëë€.
ìŒìŽì€ 1: Fragment Shader ê³ì° ë³µì¡ë ëì
âââââââââââââââââââââââ
â Vertex: 0.1ms â
â Rasterize: 0.1ms â
â Fragment: 12ms â â ë³ëª©
â Merge: 1ms â
â ìŽí©: 13.2ms â (60 FPS ì ì§)
âââââââââââââââââââââââ
ìŒìŽì€ 2: Framebuffer ì°êž° ìë ì í
âââââââââââââââââââââââ
â Vertex: 0.1ms â
â Rasterize: 0.1ms â
â Fragment: 3ms â
â Merge: 8ms â â ë³ëª©
â ìŽí©: 11.2ms â (60 FPS ì ì§)
âââââââââââââââââââââââ
ìŒìŽì€ 3: ì ì ê°ì ë§ì
âââââââââââââââââââââââ
â Vertex: 5ms â â ë³ëª©
â Rasterize: 2ms â
â Fragment: 3ms â
â Merge: 1ms â
â ìŽí©: 11ms â (60 FPS ì ì§)
âââââââââââââââââââââââ
Fragment Shader ìµì í:
- ë¶íìí ê³ì° ì ê±°
- ì ë°ë ë®ì¶€ (highp â mediump)
- 룚í ìžë¡€ë§
ë©ëªšëЬ ìµì í:
- í
ì€ì² ìì¶
- ë©ëªšëЬ ì ë ¬ ê°ì
ë³ë ¬ ì²ëЬ íì©:
- ì ì /íœì
ëì ì²ëЬ
- ì¬ë¬ íë ì íìŽíëŒìž
let frameTime = 0;
function renderLoop() {
const frameStart = performance.now();
// Fragment Shader ì€í
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
// GPU ìì
ëêž° (ì±ë¥ ìž¡ì ì©)
gl.finish(); // íë¡ëì
ììë ì¬ì© êžì§
const frameEnd = performance.now();
frameTime = frameEnd - frameStart;
console.log(`Frame time: ${frameTime.toFixed(2)}ms`);
console.log(`FPS: ${(1000 / frameTime).toFixed(1)}`);
requestAnimationFrame(renderLoop);
}
const query = gl.createQuery();
gl.beginQuery(gl.TIME_ELAPSED, query);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
gl.endQuery(gl.TIME_ELAPSED);
// ëì€ì 결곌 íìž
setTimeout(() => {
const gpuTime = gl.getQueryParameter(query, gl.QUERY_RESULT);
console.log(`GPU time: ${gpuTime / 1000000}ms`);
}, 1);
t=0ms
ââ JavaScript: ë°ìŽí° ì€ë¹
ââ gl.clear(gl.COLOR_BUFFER_BIT) ížì¶
ââ gl.drawArrays(...) ížì¶ (GPU ëª
ë ¹ ë°í)
t=0.05ms
ââ GPU: Vertex Shader ì€í (4ê° ì ì )
ââ 결곌: íŽëŠœ ê³µê° ì¢í 4ê°
t=0.1ms
ââ GPU: Rasterization
ââ 결곌: 1,048,576ê° Fragment ìì±
t=0.15ms
ââ GPU: Fragment Shader ìì (256ê° ë³ë ¬)
ââ íœì
(512, 256):
1. gl_FragCoord ìœêž°
2. uv ì ê·í
3. sdf ê³ì°
4. fill ê³ì°
5. color ê²°ì
6. outColor êž°ë¡
t=5ms
ââ GPU: 몚ë íœì
ê³ì° ìë£
t=5.5ms
ââ GPU: Output Merger
ââ íë ìë²íŒì 몚ë ìì êž°ë¡ ìë£
t=6ms
ââ íë ì ë ëë§ ìë£ (CPUë ë€ì íë ì ì€ë¹)
t=16.67ms
ââ 몚ëí°: ìŽ íë ì íì ìì (60 Hz)
ââ GPU: ë€ì íë ì ë ëë§ ìì
| ì©ìŽ | ì ì |
|---|---|
| Fragment | íœì 곌 ì ì¬íì§ë§, ìµì¢ ìì ê²°ì ì ì ì€ê° ë°ìŽí° ëšì |
| Framebuffer | GPU VRAMì ìììŒë¡, 몚ë íœì ì ìì ë°ìŽí°ë¥Œ ì ì¥ |
| Rasterization | 3D êž°íí ë°ìŽí°ë¥Œ 2D íœì ë¡ ë³ííë 곌ì |
| Warp | GPUì 32ê° ì€ë ë 묶ì (ë³ë ¬ ì²ëЬ ëšì) |
| fwidth() | ìžì íœì ê°ì 믞ë¶ê° (í멎 íŽìë ë 늜ì ê³ì°ì©) |
| smoothstep() | ì í ë³Žê° íšì (ê²œê³ ë¶ëëœê² ì²ëЬ) |
| Uniform | 몚ë íœì ìì ëìŒí ê° (ìœêž° ì ì©) |