The reason it works either way is due to the legacy way constants were handled in Direct3D 8/Direct3D 9. Back then, there was only a single shared array of constants for the entire shader (one for VS and one for PS). This required that you had to change the constant array every single time you called Draw
.
In Direct3D 10, constants were reorganized into one or more Constant Buffers to make it easier to update some constants while leaving others alone, and thus sending less data to the GPU.
See the classic presentation Windows to Reality: Getting the Most out of Direct3D 10 Graphics in Your Games for a lot of details on the impacts of constant update.
The up-shot of which here is that if you don't specify cbuffer
, all the constants get put into a single implicit constant buffer bound to register b0
to emulate the old 'one constants array' behavior.
There are compiler flags to control the acceptance of legacy constructs: /Gec
for backwards compatibility mode to support old Direct3D 8/9 intrinsics, and /Ges
to enable a more strict compilation to weed out older constructs. That said, the HLSL compiler will pretty much always accept global constants without cbuffer
and stick them into a single implicit constant buffer because this pattern is extremely common in shader code.