Even for simple GLSL -> SPIR-V shaders, I'm getting "error: invalid vertex program header&qu

All of my GLSL vertex and fragment shaders compile to SPIR-V just fine using glslangValidator.exe, and they run just fine on another system I have with an ATI GPU, but when I try to create a Vulkan pipeline with them on my GTX 960 (driver version 368.81), I get “error: invalid vertex program header” for some of my shaders.

#version 400
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
#define MAX_GUI_INSTANCES 10000   // Max number of GUI object instances per render pass
#define MAX_TEXT_INSTANCES 10000  // Max number of text character instances per render pass

struct SceneData {
	// Shared viewport settings (generally remains static during each render pass)
	vec4 vSize;			// The current viewport size (NOTE: packing will round it up to vec4)

	// Shared transformation matrices (generally remains static during each render pass)
	mat4 mProjection;	// The perspective projection matrix
	mat4 mOrtho;		// The orthographic projection matrix
	mat4 mView;			// The view matrix
	mat4 mViewProj;		// Memory vs. speed trade-off (when working in world space)
};

struct GUIData {
	vec4 vGUIRect;
	vec4 vGUIColor;
	vec4 vGUIOptions;
};

struct TextData {
	vec4 vCharPos;
	vec4 vCharColor;
};

// Cubic smoothing, yields C1 continuous curve from 0..1
float cubic(float r) { return r*r*(3.0-2.0*r); }
vec2 cubic(vec2 r) { return r*r*(3.0-2.0*r); }
vec3 cubic(vec3 r) { return r*r*(3.0-2.0*r); }
vec4 cubic(vec4 r) { return r*r*(3.0-2.0*r); }


layout(std140, set=0, binding=0) uniform SceneBuffer {
	SceneData scene;
};
layout(std140, set=1, binding=0) uniform GUIBuffer {
	GUIData gui[MAX_GUI_INSTANCES];
};
layout(std140, set=2, binding=0) uniform TextBuffer {
	TextData text[MAX_TEXT_INSTANCES];
};

layout(location=0) in vec3 attr0;
layout(location=0) out vec4 vary0;
out gl_PerVertex { vec4 gl_Position; float gl_PointSize; };

void main() {
	vary0 = text[gl_InstanceIndex].vCharColor;
	vec3 v = text[gl_InstanceIndex].vCharPos.xyz + attr0 * text[gl_InstanceIndex].vCharPos.www;
	gl_Position = scene.mViewProj * vec4(v, 1.0);
}

I’ve tried changing the version, the extensions (including enabling GL_KHR_vulkan_glsl), and a number of other things, but I get that error every time for this simple shader. Can anyone else spot what’s wrong with this vertex shader?

Thanks,
Sean

I have not tested this, and the error might be somewhere else, but this shader violates the limits of the NVIDIA driver:

On my GTX 970 the limit for maxUniformBufferRange is 64kB and i am pretty certain its the same for the GTX 960. Each GUIData is 48 byte, each TextData is 32 byte. So with your array sizes of 10k for GUIBuffer and TextBuffer, they are 480kB and 320kB, clearly above 64kB. AMD cards have a 4GB limit on this range. The minimum guaranteed limit is 16kB.

Use a storage buffer instead of a uniform buffer, which have a minimum guaranteed limit of 128MB. On the GTX 970 the actual limit is 2GB for me. This also allows you to not hardcode a limit on the range, like this:

layout(std140, set=1, binding=0) buffer GUIBuffer {
	GUIData gui[]; // Runtime bound buffer
};

The actual valid range is then determined at runtime based on the buffer range you bound in the descriptor set. This allows you to change the bound buffer size on demand without changes to the shader.

Regards

Thanks, I did a quick test by dropping the max instance counts, and it seems to have gotten me past that error (on to newer and more exciting errors). I will take a look at the storage buffer when I get a chance.

My next error is a memory access violation in vkCreateGraphicsPipelines (trying to read address 0x54) for a different shader program that uses vertex+geometry+fragment stages. That one also works fine on AMD hardware, and the debug callback and validator layers aren’t giving me any clues. Any tips to try besides pulling out pieces until it compiles and runs, then trying to put them back in one piece at a time?

Thanks again,
Sean

Well, without the code i can’t really help you. I don’t think the validation layers have extended shader validation yet. Since you ran into the limits problem once, and again it works on AMD, that’s the first one i would look at. In OpenGL, the driver would simply replace or emulate or rearrange what you did to make it work, for example in your first shader replace the constant buffers with storage buffers under the hood. Vulkan doesn’t, you get what you write, so you really need to know all the limits. Ad-hoc doesn’t really work in Vulkan. Of course it could be a driver bug, but to verify that means to check all the limits first. Seeing that you used 3 descriptor sets for the last shader, maxBoundDescriptorSets is the first one i would check. It’s 8 on newer NVIDIA drivers (it was 4 at the beginning), and 32 on AMD.

Regards

Thanks again. I was just looking for tips/suggestions, and I believe you’ve given me what I need to track the problem down. I got the storage buffers working last night, and I managed to get everything else working except for that one shader, so I’m almost there.

I’ve been tinkering with OpenGL (part-time) since I purchased an nVidia Riva 128 in the late 90’s, so I’m a bit old-school. ;-) I was stuck on the fixed-function pipeline until I started working on this article: http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html

As a tinkerer, I probably shouldn’t be messing with Vulkan, but the rendering calls in OpenGL were always too slow for what I wanted to do.

Thanks again for all your help.

Oh no, you can definitely tinker with Vulkan, it just requires some minimal framework with lots of utility/builders around it. With the direct C interface most calls requires dozens of lines of boilerplate. Sure even then it misses the OpenGL convenience of just changing something last minute right before the drawcall, but with the right abstraction setting up things like vertex layout, descriptor layout, render pass and pipeline state just take a couple lines (if you format it pretty). And the rendering later doesn’t take much more. Convenience functions are key.

In fact i found that once you embrace the Vulkan style, it’s easier to program with than OpenGL. With OpenGL you can mix and match all types of calls all the time, with Vulkan there is a more strict order to when you can do what. But that naturally makes Vulkan more linear to program with. I especially find the pipeline state objects, descriptor sets and the (also available in new OpenGL) permanent mapped buffers a great simplification.

As for drawcalls being slow: They are not anymore on the CPU! From my own code i can tell you that recording 10k drawcalls (seperate drawcalls, not instancing) with changing pipelines is as fast as 1ms on one core on a relatively old and slow CPU. Submitting them is as fast as 25-50µs! Combined with recording in multiple threads, instancing, indirect draw and command buffer resubmission, you can easily max your GPU with more drawcalls than it can handle.

Regards

Oh, I know. I really do like the additional control and performance it gives, and when I say “shouldn’t”, it doesn’t mean “wouldn’t”. I just don’t have as much spare time to tinker as I used to, and Vulkan requires a good deal of extra time to get comfortable. It might be a while before I consider it to be “easier” than OpenGL. ;-)

If you’re interested at all, the full source is currently on: https://github.com/sponeil/VKSandbox (it has a Visual Studio 2015 project file). It includes some third-party libraries (e.g. zlib, libzip, sqlite3, libjpeg, libpng, code from glslangValidator), but all of the code/shaders I wrote myself are public domain, so anyone is free to take and tweak any useful parts they want and leave the rest.

If you do take a look at it, comments/criticism are always welcome. I don’t like everything about the wrapper classes I have. I ported them from an older wrapper library I wrote for OpenGL, but I feel like I’m still just getting my feet wet with Vulkan. I do like the ShaderTechnique, which allows me to define fx-style shader files that allow me to change both shader code and pipeline states (e.g. blending, depth, culling) in the fx files, combine several shader programs into the same FX file, include headers and glsl files, and so on.

Based on your comments, you probably have a better Vulkan library in place already, but you still might get some ideas from it. If not, someone else reading this might. The only test app I have in that project implements one flavor of spherical clip-maps for dynamic LOD planets I’ve been kicking around. (The colors are randomly-generated plates for a plate tectonic implementation I hope to write in shaders to generate more realistic planetary terrain).

Thanks again for all your help.