Internally, GPUs never run one instance of a pixel shader at a time. At the finest level of granularity, they are always running 32-64 pixels at the same time using a SIMD architecture. Within this, the pixels are further organized into 2x2 quads, so each group of 4 consecutive pixels in the SIMD vector corresponds to a 2x2 block of pixels on screen.
Derivatives are calculated by taking differences between the pixels in a quad. For instance, ddx
will subtract the values in the pixels on the left side of the quad from the values on the right side, and ddy
will subtract the bottom pixels from the top ones. The differences can then be returned as the derivative to all four pixels in the quad.
Since the pixel shader is running in SIMD, it's guaranteed that the corresponding value is in the same register at the same time for all the pixels in the quad. So whatever expression or value you put into ddx
or ddy
, it will be evaluated in all four pixels of the quad, then the values from different pixels subtracted as described above.
So taking the derivative of a constant value will give zero (as you'd expect from calculus, right?) because it's the same constant value in all four pixels.
Also note that there are "coarse" and "fine" derivatives, ddx_coarse
/ddy_coarse
and ddx_fine
/ddy_fine
. An explanation of the distinction is given here. Just plain ddx
/ddy
are aliases for the coarse versions.
BTW, the reason this functionality exists is that GPUs internally have to take derivatives of texture coordinates in order to do mipmap selection and anisotropic filtering. Since the hardware needs the capability anyway (you can use any arbitrary expression for texture coordinates in a shader), it was easy enough to also expose it to shader programmers directly.
ddx
andddy
do magic that you cannot do yourself. They have access to additional information from the rasterization pipeline that you can't acquire from within a pixel shader. I'm unsure exactly which formula they use; I've been led to believe they use an estimation technique, but I don't know for sure. \$\endgroup\$ – Sean Middleditch Sep 24 '13 at 17:33ddx(5)
is kind of pointless. Use it with an input value, and that will give you the derivative of that value with respect to neighboring pixels in a block. Again, I don't know how precisely it calculates values, but asking for the derivative of a non-input may well just be undefined behavior and produce garbage. See fgiesen.wordpress.com/2011/07/10/… for more information than I can provide. \$\endgroup\$ – Sean Middleditch Sep 24 '13 at 17:41