0

I'm trying to implement billboarded quads in a geomerty shader to render particle effects. The geometry shader input is points (vec3), and its output is a triangle strip with position and UV coordinates (vec3, vec2). I've tried two variations of vertex input bindings, but neither work.

If I set up the vertex binding like this:

VkVertexInputBindingDescription binding_desc[2] = {};
binding_desc[0].binding = 0;
binding_desc[0].stride = sizeof(glm::vec3);
binding_desc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;

binding_desc[1].binding = 1;
binding_desc[1].stride = sizeof(glm::vec2);
binding_desc[1].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;

VkVertexInputAttributeDescription attribute_desc[2] = {};
attribute_desc[0].location = 0;
attribute_desc[0].binding = binding_desc[0].binding;
attribute_desc[0].format = VK_FORMAT_R32G32B32_SFLOAT;
attribute_desc[0].offset = offsetof(vert_shader_vertex, pos);

attribute_desc[1].location = 1;
attribute_desc[1].binding = binding_desc[1].binding;
attribute_desc[1].format = VK_FORMAT_R32G32_SFLOAT;
attribute_desc[1].offset = offsetof(vert_shader_vertex, uv);

I get the following error when calling vkCmdDraw:

ERROR [default] DS: (OBJECT 0) (CODE 24) The Pipeline State Object (0x3c) expects that this Command Buffer's vertex binding Index 1 should be set via vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct at index 1 of pVertexBindingDescriptions has a binding value of 1.

However, if I set it up as this:

VkVertexInputBindingDescription binding_desc[1] = {};
binding_desc[0].binding = 0;
binding_desc[0].stride = sizeof(glm::vec3);
binding_desc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;

VkVertexInputAttributeDescription attribute_desc[1] = {};
attribute_desc[0].location = 0;
attribute_desc[0].binding = binding_desc[0].binding;
attribute_desc[0].format = VK_FORMAT_R32G32B32_SFLOAT;
attribute_desc[0].offset = offsetof(vert_shader_vertex, pos);

I get this error when calling vkCreateGraphicsPipelines:

ERROR [default] SC: (OBJECT 0) (CODE 3) Vertex shader consumes input at location 1 but not provided

  • Does the VkVertexInputBindingDescription describe the input to the geometry shader, or the vertex shader?
  • Do I need "dummy" UV coordinates in my vertex buffer as a place holder?
  • Is it possible my geometry shader is not activated, and how can I confirm?
  • Which ever of the two approaches is correct, how do I address the corresponding error?
  • As an aside, I'm new to Vulkan so comments on the shaders are welcome.

Geometry shader

#version 450

#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable

layout (points) in;
layout (triangle_strip, max_vertices = 4) out;

layout (location = 0) in vec3 inPos[];

layout (location = 0) out vec3 outPos;
layout (location = 1) out vec2 outUV;

layout (push_constant) uniform constants_t {
    vec3 up;
    vec3 right;
    mat4x4 world;
    mat4x4 projection;
} constants;

void main(void)
{
    const vec3 pos = gl_in[0].gl_Position.xyz;
    const vec3 up = constants.up;
    const vec3 right = constants.right;

    outPos = pos + up - right;
    outUV = vec2(0, 0);
    EmitVertex();

    outPos = pos + up + right;
    outUV = vec2(1, 0);
    EmitVertex();

    outPos = pos - up - right;
    outUV = vec2(0, 1);
    EmitVertex();

    outPos = pos - up + right;
    outUV = vec2(1, 1);
    EmitVertex();

    EndPrimitive();
}

Vertex shader

#version 450

#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable

layout (location = 0) in vec3 inPos;
layout (location = 1) in vec2 inUV;

layout (location = 0) out vec4 outPos;
layout (location = 1) out vec2 outUV;

layout (push_constant) uniform constants_t {
    vec3 up;
    vec3 right;
    mat4x4 world;
    mat4x4 projection;
} constants;

void main(void) {
    outUV = inUV;
    outPos = vec4(inPos.xyz, 1.0) * constants.world * constants.projection;
}

vkCmdBindVertexBuffers

VkBuffer vertex_buffers[1] = {vertexBuffer};
VkDeviceSize vertex_offset[1] = {0};
vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertex_buffers, vertex_offset);
Brent
  • 4,153
  • 4
  • 30
  • 63
  • "*I get the following error when calling vkCmdDraw:*" In order to tell what's going on, we need to see the actual commands you send *before* you render. – Nicol Bolas Feb 20 '17 at 20:32
  • I think vkCmdBindVertexBuffers will be very important for the first variant – ratchet freak Feb 20 '17 at 20:34
  • @NicolBolas Do you really? My post contains bullet-pointed questions that are pretty general. Besides, I don't have permission to dump all the code somewhere for you to see. – Brent Feb 20 '17 at 20:36
  • @ratchetfreak I added it to the end of the post, but it doesn't add much. Anything else specifically that I could add to make for a better post? – Brent Feb 20 '17 at 20:43
  • 1
    The first variant expects 2 buffers to be bound, you give it only 1 buffer. – ratchet freak Feb 20 '17 at 21:26

1 Answers1

4
vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertex_buffers, vertex_offset);

This says that you're binding one buffer to index 0. Yet you told the pipeline when you created it that you would have two buffers bound.

Do not lie to Vulkan; it always knows (when you're using validation layers ;) ).

It is rather likely that you intended to have both vertex attributes use the same buffer object. I deduce this from the fact that you used offsetof to compute the relative offsets for them. If that is your intent, then you should have two vertex attributes that use the same buffer binding.

Does the VkVertexInputBindingDescription describe the input to the geometry shader, or the vertex shader?

It cannot describe the input to the GS because the first pipeline shader stage is the vertex shader. And creating a graphics pipeline without a VS is not possible.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982