Added support for push constants

This commit is contained in:
Juan Linietsky 2019-06-08 17:10:52 -03:00
parent edb6966024
commit 1522d8c3ee
4 changed files with 84 additions and 12 deletions

View file

@ -2753,7 +2753,7 @@ static VkShaderStageFlagBits shader_stage_masks[RenderingDevice::SHADER_STAGE_MA
VK_SHADER_STAGE_COMPUTE_BIT,
};
bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLayoutBinding> > &bindings, Vector<Vector<Shader::UniformInfo> > &uniform_infos, const glslang::TObjectReflection &reflection, RenderingDevice::ShaderStage p_stage, String *r_error) {
bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLayoutBinding> > &bindings, Vector<Vector<Shader::UniformInfo> > &uniform_infos, const glslang::TObjectReflection &reflection, RenderingDevice::ShaderStage p_stage, Shader::PushConstant &push_constant, String *r_error) {
VkDescriptorSetLayoutBinding layout_binding;
Shader::UniformInfo info;
@ -2825,17 +2825,26 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
case glslang::EbtBlock: {
print_line("DEBUG: Block");
if (reflection.getType()->getQualifier().storage == glslang::EvqUniform) {
if (reflection.getType()->getQualifier().layoutPushConstant) {
uint32_t len = reflection.size;
if (push_constant.push_constant_size != 0 && push_constant.push_constant_size != len) {
*r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' push constants for different stages should all be the same size.";
return false;
}
push_constant.push_constant_size = len;
push_constant.push_constants_vk_stage |= shader_stage_masks[p_stage];
return true;
}
print_line("DEBUG: Uniform buffer");
layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
info.type = UNIFORM_TYPE_UNIFORM_BUFFER;
} else if (reflection.getType()->getQualifier().storage == glslang::EvqBuffer) {
layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
info.type = UNIFORM_TYPE_STORAGE_BUFFER;
print_line("DEBUG: Storage buffer");
} else {
if (r_error) {
*r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' is of unsupported block type.";
*r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' is of unsupported block type: (" + itos(reflection.getType()->getQualifier().storage) + ").";
}
return false;
}
@ -2959,6 +2968,10 @@ RenderingDevice::ID RenderingDeviceVulkan::shader_create_from_source(const Vecto
//descriptor layouts
Vector<Vector<VkDescriptorSetLayoutBinding> > bindings;
Vector<Vector<Shader::UniformInfo> > uniform_info;
Shader::PushConstant push_constant;
push_constant.push_constant_size = 0;
push_constant.push_constants_vk_stage = 0;
Vector<int> vertex_input_locations;
int fragment_outputs = 0;
@ -3031,25 +3044,25 @@ RenderingDevice::ID RenderingDeviceVulkan::shader_create_from_source(const Vecto
program.dumpReflection();
for (int j = 0; j < program.getNumUniformVariables(); j++) {
if (!_uniform_add_binding(bindings, uniform_info, program.getUniform(j), p_stages[i].shader_stage, r_error)) {
if (!_uniform_add_binding(bindings, uniform_info, program.getUniform(j), p_stages[i].shader_stage, push_constant, r_error)) {
return INVALID_ID;
}
}
for (int j = 0; j < program.getNumUniformBlocks(); j++) {
if (!_uniform_add_binding(bindings, uniform_info, program.getUniformBlock(j), p_stages[i].shader_stage, r_error)) {
if (!_uniform_add_binding(bindings, uniform_info, program.getUniformBlock(j), p_stages[i].shader_stage, push_constant, r_error)) {
return INVALID_ID;
}
}
for (int j = 0; j < program.getNumBufferVariables(); j++) {
if (!_uniform_add_binding(bindings, uniform_info, program.getBufferVariable(j), p_stages[i].shader_stage, r_error)) {
if (!_uniform_add_binding(bindings, uniform_info, program.getBufferVariable(j), p_stages[i].shader_stage, push_constant, r_error)) {
return INVALID_ID;
}
}
for (int j = 0; j < program.getNumBufferBlocks(); j++) {
if (!_uniform_add_binding(bindings, uniform_info, program.getBufferBlock(j), p_stages[i].shader_stage, r_error)) {
if (!_uniform_add_binding(bindings, uniform_info, program.getBufferBlock(j), p_stages[i].shader_stage, push_constant, r_error)) {
return INVALID_ID;
}
}
@ -3087,6 +3100,7 @@ RenderingDevice::ID RenderingDeviceVulkan::shader_create_from_source(const Vecto
shader.vertex_input_locations = vertex_input_locations;
shader.fragment_outputs = fragment_outputs;
shader.push_constant = push_constant;
bool success = true;
for (int i = 0; i < p_stages.size(); i++) {
@ -3181,10 +3195,19 @@ RenderingDevice::ID RenderingDeviceVulkan::shader_create_from_source(const Vecto
layouts.write[i] = shader.sets[i].descriptor_set_layout;
}
//unsupported for now
pipeline_layout_create_info.pSetLayouts = layouts.ptr();
pipeline_layout_create_info.pushConstantRangeCount = 0;
pipeline_layout_create_info.pPushConstantRanges = NULL;
if (push_constant.push_constant_size) {
VkPushConstantRange push_constant_range;
push_constant_range.stageFlags = push_constant.push_constants_vk_stage;
push_constant_range.offset = 0;
push_constant_range.size = push_constant.push_constant_size;
pipeline_layout_create_info.pushConstantRangeCount = 1;
pipeline_layout_create_info.pPushConstantRanges = &push_constant_range;
} else {
pipeline_layout_create_info.pushConstantRangeCount = 0;
pipeline_layout_create_info.pPushConstantRanges = NULL;
}
VkResult err = vkCreatePipelineLayout(device, &pipeline_layout_create_info, NULL, &shader.pipeline_layout);
@ -4118,6 +4141,9 @@ RenderingDevice::ID RenderingDeviceVulkan::render_pipeline_create(ID p_shader, I
pipeline.vertex_format = p_vertex_description;
pipeline.uses_restart_indices = input_assembly_create_info.primitiveRestartEnable;
pipeline.set_hashes = shader->set_hashes;
pipeline.push_constant_size = shader->push_constant.push_constant_size;
pipeline.push_constant_stages = shader->push_constant.push_constants_vk_stage;
pipeline.pipeline_layout = shader->pipeline_layout;
static const uint32_t primitive_divisor[RENDER_PRIMITIVE_MAX] = {
1, 2, 1, 1, 1, 3, 1, 1, 1, 1, 1
@ -4610,6 +4636,12 @@ void RenderingDeviceVulkan::draw_list_bind_render_pipeline(ID p_list, ID p_rende
dl->validation.pipeline_primitive_minimum = pipeline->primitive_minimum;
dl->validation.pipeline_set_hashes = pipeline->set_hashes;
dl->validation.pipeline_push_constant_size = pipeline->push_constant_size;
if (pipeline->push_constant_size) {
dl->validation.pipeline_push_constant_stages = pipeline->push_constant_stages;
dl->validation.pipeline_push_constant_suppplied = false;
dl->validation.pipeline_push_constant_layout = pipeline->pipeline_layout;
}
}
void RenderingDeviceVulkan::draw_list_bind_uniform_set(ID p_list, ID p_uniform_set, uint32_t p_index) {
@ -4678,6 +4710,17 @@ void RenderingDeviceVulkan::draw_list_bind_index_array(ID p_list, ID p_index_arr
vkCmdBindIndexBuffer(dl->command_buffer, index_array->buffer, index_array->offset, index_array->index_type);
}
void RenderingDeviceVulkan::draw_list_set_push_constant(ID p_list, void *p_data, uint32_t p_data_size) {
DrawList *dl = _get_draw_list_ptr(p_list);
ERR_FAIL_COND(!dl);
ERR_FAIL_COND_MSG(p_data_size != dl->validation.pipeline_push_constant_size,
"This render pipeline requires (" + itos(dl->validation.pipeline_push_constant_size) + ") bytes of push constant data, supplied: (" + itos(p_data_size) + ")");
vkCmdPushConstants(dl->command_buffer, dl->validation.pipeline_push_constant_layout, dl->validation.pipeline_push_constant_stages, 0, p_data_size, p_data);
dl->validation.pipeline_push_constant_suppplied = true;
}
void RenderingDeviceVulkan::draw_list_draw(ID p_list, bool p_use_indices, uint32_t p_instances) {
DrawList *dl = _get_draw_list_ptr(p_list);
@ -4697,6 +4740,12 @@ void RenderingDeviceVulkan::draw_list_draw(ID p_list, bool p_use_indices, uint32
ERR_FAIL_COND_MSG(p_instances > dl->validation.vertex_max_instances_allowed,
"Amount of instances requested (" + itos(p_instances) + " is larger than the maximum amount suported by the bound vertex array (" + itos(dl->validation.vertex_max_instances_allowed) + ").");
}
if (dl->validation.pipeline_push_constant_size > 0) {
//using push constants, check that they were supplied
ERR_FAIL_COND_MSG(!dl->validation.pipeline_push_constant_suppplied,
"The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");
}
//compare hashes
if (dl->validation.pipeline_set_hashes.size()) {
ERR_FAIL_COND_MSG(dl->validation.pipeline_set_hashes.size() > dl->validation.set_hashes.size(),

View file

@ -464,6 +464,13 @@ class RenderingDeviceVulkan : public RenderingDevice {
Vector<int> vertex_input_locations; //inputs used, this is mostly for validation
int fragment_outputs;
struct PushConstant {
uint32_t push_constant_size;
uint32_t push_constants_vk_stage;
};
PushConstant push_constant;
int max_output;
Vector<Set> sets;
Vector<uint32_t> set_hashes;
@ -471,7 +478,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
VkPipelineLayout pipeline_layout;
};
bool _uniform_add_binding(Vector<Vector<VkDescriptorSetLayoutBinding> > &bindings, Vector<Vector<Shader::UniformInfo> > &uniform_infos, const glslang::TObjectReflection &reflection, RenderingDevice::ShaderStage p_stage, String *r_error);
bool _uniform_add_binding(Vector<Vector<VkDescriptorSetLayoutBinding> > &bindings, Vector<Vector<Shader::UniformInfo> > &uniform_infos, const glslang::TObjectReflection &reflection, RenderingDevice::ShaderStage p_stage, Shader::PushConstant &push_constant, String *r_error);
ID_Pool<Shader, ID_TYPE_SHADER> shader_owner;
@ -592,7 +599,10 @@ class RenderingDeviceVulkan : public RenderingDevice {
uint32_t primitive_minimum;
uint32_t primitive_divisor;
Vector<uint32_t> set_hashes;
uint32_t push_constant_size;
uint32_t push_constant_stages;
//Actual pipeline
VkPipelineLayout pipeline_layout; // not owned, needed for push constants
VkPipeline pipeline;
};
@ -645,6 +655,10 @@ class RenderingDeviceVulkan : public RenderingDevice {
uint32_t pipeline_primitive_divisor;
uint32_t pipeline_primitive_minimum;
Vector<uint32_t> pipeline_set_hashes;
VkPipelineLayout pipeline_push_constant_layout;
uint32_t pipeline_push_constant_size;
uint32_t pipeline_push_constant_stages;
bool pipeline_push_constant_suppplied;
Validation() {
active = true;
@ -662,6 +676,9 @@ class RenderingDeviceVulkan : public RenderingDevice {
pipeline_dynamic_state = 0;
pipeline_vertex_format = INVALID_ID;
pipeline_uses_restart_indices = false;
pipeline_push_constant_size = 0;
pipeline_push_constant_stages = 0;
pipeline_push_constant_suppplied = false;
}
} validation;
};
@ -804,6 +821,7 @@ public:
virtual void draw_list_bind_uniform_set(ID p_list, ID p_uniform_set, uint32_t p_index);
virtual void draw_list_bind_vertex_array(ID p_list, ID p_vertex_array);
virtual void draw_list_bind_index_array(ID p_list, ID p_index_array);
virtual void draw_list_set_push_constant(ID p_list, void *p_data, uint32_t p_data_size);
virtual void draw_list_draw(ID p_list, bool p_use_indices, uint32_t p_instances = 1);

View file

@ -427,7 +427,8 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
"layout (location = 0) in vec2 uv_interp;\n"
"layout (location = 0) out vec4 uFragColor;\n"
"layout (binding = 0) uniform sampler2D t;\n"
"void main() { uFragColor=texture(t,uv_interp); }\n";
"layout (push_constant, binding=1) uniform ColorMultiplier { vec4 color_mult; } color_multiplier;\n"
"void main() { uFragColor=texture(t,uv_interp) * color_multiplier.color_mult; }\n";
Vector<RenderingDevice::ShaderStageSource> source;
source.push_back(vert);
@ -3415,12 +3416,14 @@ void OS_X11::swap_buffers() {
#endif
Vector<Color> clear;
float color[4] = { 1, 0, 1, 1 };
clear.push_back(Color(0.5, 0.8, 0.2));
RenderingDevice::ID cmd_list = rendering_device->draw_list_begin(test_framebuffer, RenderingDevice::INITIAL_ACTION_CLEAR, RenderingDevice::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, clear);
rendering_device->draw_list_bind_render_pipeline(cmd_list, test_pipeline);
rendering_device->draw_list_bind_index_array(cmd_list, test_index_array);
rendering_device->draw_list_bind_vertex_array(cmd_list, test_vertex_array);
rendering_device->draw_list_bind_uniform_set(cmd_list, test_uniform_set, 0);
rendering_device->draw_list_set_push_constant(cmd_list, color, 4 * 4);
rendering_device->draw_list_draw(cmd_list, true);
rendering_device->draw_list_end();
@ -3429,6 +3432,7 @@ void OS_X11::swap_buffers() {
rendering_device->draw_list_bind_index_array(cmd_list, test_index_array);
rendering_device->draw_list_bind_vertex_array(cmd_list, test_vertex_array);
rendering_device->draw_list_bind_uniform_set(cmd_list, test_framebuffer_uniform_set, 0);
rendering_device->draw_list_set_push_constant(cmd_list, color, 4 * 4);
rendering_device->draw_list_draw(cmd_list, true);
rendering_device->draw_list_end();
rendering_device->finalize_frame();

View file

@ -830,6 +830,7 @@ public:
virtual void draw_list_bind_uniform_set(ID p_list, ID p_uniform_set, uint32_t p_index) =0;
virtual void draw_list_bind_vertex_array(ID p_list, ID p_vertex_array) = 0;
virtual void draw_list_bind_index_array(ID p_list, ID p_index_array) = 0;
virtual void draw_list_set_push_constant(ID p_list, void *p_data,uint32_t p_data_size) =0;
virtual void draw_list_draw(ID p_list, bool p_use_indices, uint32_t p_instances=1) = 0;