Generally speaking, passes in higher-level shader/material systems (yes, higher than GLSL/Cg/HLSL) like this one are a way of setting up states necessary for multi-pass rendering. If you were dealing directly with GLSL, Cg or HLSL, there is no such thing as a "pass."
In this case, you have two different types of passes because one establishes the base lighting contribution and each successive pass adds to it. In other words, they have different blend functions. The first pass replaces anything in the framebuffer (effectively glBlendFunc (GL_ONE, GL_ZERO)
if you are familiar with OpenGL), the second pass adds the computed light to all previous passes (glBlendFunc (GL_ONE, GL_ONE)
).
Do not think of _LightColor0 as if it referred to the first light in your scene. Actually, it is the first light in the set of lights (in this case, 1 pass per-light) handled by the lighting pass. If this shader were able to handle multiple lights per-pass, you might see _LightColor0 - _LightColorN and the number of passes required would be something along the lines of: 1 + ceil ((NumLights-1)/(_LightColorN+1)).
This ugly shader requires does lighting per-vertex and requires 1 pass per-light. Even for forward rendering, this is highly inefficient. I could understand requiring multiple passes if shadow maps were being used, but this is about as simple a lighting shader as you can get and it still requires 1 pass per-light. Even ancient fixed-function hardware can do 8 lights per-pass.
Update:
Since there was some confusion regarding how each light is related to a pass in this shader, and you have updated your question to include a diagram, I will explain this using the diagram.
In this diagram, there are three light sources. To apply these three lights using this shader requires three passes.
Pass 0: <Yellow Light>
Blend Function: Framebuffer = (1 * Light) + (0 * Framebuffer)
Pass Type: "ForwardBase"
Pass 1: <Red Light>
Blend Function: Framebuffer = (1 * Light) + (1 * Framebuffer)
Pass Type: "ForwardAdd"
Pass 2: <Green Light>
Blend Function: Framebuffer = (1 * Light) + (1 * Framebuffer)
Pass Type: "ForwardAdd"
What this works out to in the end is this:
Final Color = Light0 + Light1 + Light2
If you had any more lights, they would all use the ForwardAdd
pass from your shader. By the way, since color values are clamped to 0.0 - 1.0 after blending and each light adds its intensity to all previous lights, it does not take very many lights before lighting becomes pure white. You have to be very careful when using additive lighting unless you use HDR (high dynamic range) to fix this problem.
Regarding the process of drawing the cube multiple times, the GPU has nothing to do with this. The graphics engine itself is what changes the states for each shader pass and re-draws the cube. Since state changes like the blending function cannot be changed per-instance, the engine literally has draw your cube once, change a few states and then draw it again using this shader. This process is known as batching and it gets a lot more complicated when you start drawing more than a simple cube.
Reducing the number of times the cube has to be drawn is very important for achieving high performance. When many lights are used, engines usually switch from forward shading to deferred. This draws the cube one time into multiple textures and each texture stores one or more properties needed to compute lighting such as the position, shininess, albedo, normal, material ID, etc. When it comes time to apply lights, instead of drawing the cube over and over, the properties are looked up from the pre-computed textures (G-Buffers) in a fragment/compute shader.
The thing is, deferred shading is not used for per-vertex lighting and the overall added complexity / memory requirements involved can make it impractical when only 2 or 3 lights are used.