Implement Specialization Constants
* Added support to our local copy of SpirV Reflect (which does not support it). * Pass them on render or compute pipeline creation. * Not implemented in our shaders yet.
This commit is contained in:
parent
fb3961b2ef
commit
b2f6db7aa8
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="RDPipelineSpecializationConstant" inherits="RefCounted" version="4.0">
|
||||
<brief_description>
|
||||
</brief_description>
|
||||
<description>
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="constant_id" type="int" setter="set_constant_id" getter="get_constant_id" default="0">
|
||||
</member>
|
||||
<member name="value" type="Variant" setter="set_value" getter="get_value">
|
||||
</member>
|
||||
</members>
|
||||
<constants>
|
||||
</constants>
|
||||
</class>
|
|
@ -140,6 +140,8 @@
|
|||
</return>
|
||||
<argument index="0" name="shader" type="RID">
|
||||
</argument>
|
||||
<argument index="1" name="specialization_constants" type="RDPipelineSpecializationConstant[]" default="[]">
|
||||
</argument>
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
|
@ -580,6 +582,8 @@
|
|||
</argument>
|
||||
<argument index="9" name="for_render_pass" type="int" default="0">
|
||||
</argument>
|
||||
<argument index="10" name="specialization_constants" type="RDPipelineSpecializationConstant[]" default="[]">
|
||||
</argument>
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
|
@ -1709,6 +1713,12 @@
|
|||
</constant>
|
||||
<constant name="SHADER_LANGUAGE_HLSL" value="1" enum="ShaderLanguage">
|
||||
</constant>
|
||||
<constant name="PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL" value="0" enum="PipelineSpecializationConstantType">
|
||||
</constant>
|
||||
<constant name="PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT" value="1" enum="PipelineSpecializationConstantType">
|
||||
</constant>
|
||||
<constant name="PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT" value="2" enum="PipelineSpecializationConstantType">
|
||||
</constant>
|
||||
<constant name="LIMIT_MAX_BOUND_UNIFORM_SETS" value="0" enum="Limit">
|
||||
</constant>
|
||||
<constant name="LIMIT_MAX_FRAMEBUFFER_COLOR_ATTACHMENTS" value="1" enum="Limit">
|
||||
|
|
|
@ -4374,6 +4374,8 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages
|
|||
|
||||
uint32_t stages_processed = 0;
|
||||
|
||||
Vector<Shader::SpecializationConstant> specialization_constants;
|
||||
|
||||
bool is_compute = false;
|
||||
|
||||
uint32_t compute_local_size[3] = { 0, 0, 0 };
|
||||
|
@ -4560,6 +4562,62 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages
|
|||
}
|
||||
}
|
||||
|
||||
{
|
||||
//specialization constants
|
||||
|
||||
uint32_t sc_count = 0;
|
||||
result = spvReflectEnumerateSpecializationConstants(&module, &sc_count, nullptr);
|
||||
ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(),
|
||||
"Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed enumerating specialization constants.");
|
||||
|
||||
if (sc_count) {
|
||||
Vector<SpvReflectSpecializationConstant *> spec_constants;
|
||||
spec_constants.resize(sc_count);
|
||||
|
||||
result = spvReflectEnumerateSpecializationConstants(&module, &sc_count, spec_constants.ptrw());
|
||||
ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(),
|
||||
"Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed obtaining specialization constants.");
|
||||
|
||||
for (uint32_t j = 0; j < sc_count; j++) {
|
||||
int32_t existing = -1;
|
||||
Shader::SpecializationConstant sconst;
|
||||
sconst.constant.constant_id = spec_constants[j]->constant_id;
|
||||
switch (spec_constants[j]->constant_type) {
|
||||
case SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL: {
|
||||
sconst.constant.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
|
||||
sconst.constant.bool_value = spec_constants[j]->default_value.int_bool_value != 0;
|
||||
} break;
|
||||
case SPV_REFLECT_SPECIALIZATION_CONSTANT_INT: {
|
||||
sconst.constant.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT;
|
||||
sconst.constant.int_value = spec_constants[j]->default_value.int_bool_value;
|
||||
} break;
|
||||
case SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT: {
|
||||
sconst.constant.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT;
|
||||
sconst.constant.float_value = spec_constants[j]->default_value.float_value;
|
||||
} break;
|
||||
}
|
||||
sconst.stage_flags = 1 << p_stages[i].shader_stage;
|
||||
|
||||
print_line("spec constant " + itos(i) + ": " + String(spec_constants[j]->name) + " type " + itos(spec_constants[j]->constant_type) + " id " + itos(spec_constants[j]->constant_id));
|
||||
|
||||
for (int k = 0; k < specialization_constants.size(); k++) {
|
||||
if (specialization_constants[k].constant.constant_id == sconst.constant.constant_id) {
|
||||
ERR_FAIL_COND_V_MSG(specialization_constants[k].constant.type != sconst.constant.type, RID(), "More than one specialization constant used for id (" + itos(sconst.constant.constant_id) + "), but their types differ.");
|
||||
ERR_FAIL_COND_V_MSG(specialization_constants[k].constant.int_value != sconst.constant.int_value, RID(), "More than one specialization constant used for id (" + itos(sconst.constant.constant_id) + "), but their default values differ.");
|
||||
existing = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (existing > 0) {
|
||||
specialization_constants.write[existing].stage_flags |= sconst.stage_flags;
|
||||
} else {
|
||||
specialization_constants.push_back(sconst);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stage == SHADER_STAGE_VERTEX) {
|
||||
uint32_t iv_count = 0;
|
||||
result = spvReflectEnumerateInputVariables(&module, &iv_count, nullptr);
|
||||
|
@ -4656,6 +4714,7 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages
|
|||
shader.compute_local_size[0] = compute_local_size[0];
|
||||
shader.compute_local_size[1] = compute_local_size[1];
|
||||
shader.compute_local_size[2] = compute_local_size[2];
|
||||
shader.specialization_constants = specialization_constants;
|
||||
|
||||
String error_text;
|
||||
|
||||
|
@ -5651,7 +5710,7 @@ Vector<uint8_t> RenderingDeviceVulkan::buffer_get_data(RID p_buffer) {
|
|||
/**** RENDER PIPELINE ****/
|
||||
/*************************/
|
||||
|
||||
RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags, uint32_t p_for_render_pass) {
|
||||
RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags, uint32_t p_for_render_pass, const Vector<PipelineSpecializationConstant> &p_specialization_constants) {
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
//needs a shader
|
||||
|
@ -5969,8 +6028,63 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
|
|||
graphics_pipeline_create_info.pNext = nullptr;
|
||||
graphics_pipeline_create_info.flags = 0;
|
||||
|
||||
graphics_pipeline_create_info.stageCount = shader->pipeline_stages.size();
|
||||
graphics_pipeline_create_info.pStages = shader->pipeline_stages.ptr();
|
||||
Vector<VkPipelineShaderStageCreateInfo> pipeline_stages = shader->pipeline_stages;
|
||||
Vector<VkSpecializationInfo> specialization_info;
|
||||
Vector<Vector<VkSpecializationMapEntry>> specialization_map_entries;
|
||||
Vector<uint32_t> specialization_constant_data;
|
||||
|
||||
if (shader->specialization_constants.size()) {
|
||||
specialization_constant_data.resize(shader->specialization_constants.size());
|
||||
uint32_t *data_ptr = specialization_constant_data.ptrw();
|
||||
specialization_info.resize(pipeline_stages.size());
|
||||
specialization_map_entries.resize(pipeline_stages.size());
|
||||
for (int i = 0; i < shader->specialization_constants.size(); i++) {
|
||||
//see if overriden
|
||||
const Shader::SpecializationConstant &sc = shader->specialization_constants[i];
|
||||
data_ptr[i] = sc.constant.int_value; //just copy the 32 bits
|
||||
|
||||
for (int j = 0; j < p_specialization_constants.size(); j++) {
|
||||
const PipelineSpecializationConstant &psc = p_specialization_constants[j];
|
||||
if (psc.constant_id == sc.constant.constant_id) {
|
||||
ERR_FAIL_COND_V_MSG(psc.type != sc.constant.type, RID(), "Specialization constant provided for id (" + itos(sc.constant.constant_id) + ") is of the wrong type.");
|
||||
data_ptr[i] = sc.constant.int_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VkSpecializationMapEntry entry;
|
||||
|
||||
entry.constantID = sc.constant.constant_id;
|
||||
entry.offset = i * sizeof(uint32_t);
|
||||
entry.size = sizeof(uint32_t);
|
||||
|
||||
for (int j = 0; j < SHADER_STAGE_MAX; j++) {
|
||||
if (sc.stage_flags & (1 << j)) {
|
||||
VkShaderStageFlagBits stage = shader_stage_masks[j];
|
||||
for (int k = 0; k < pipeline_stages.size(); k++) {
|
||||
if (pipeline_stages[k].stage == stage) {
|
||||
specialization_map_entries.write[k].push_back(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = 0; k < pipeline_stages.size(); k++) {
|
||||
if (specialization_map_entries[k].size()) {
|
||||
specialization_info.write[k].dataSize = specialization_constant_data.size() * sizeof(uint32_t);
|
||||
specialization_info.write[k].pData = data_ptr;
|
||||
specialization_info.write[k].mapEntryCount = specialization_map_entries[k].size();
|
||||
specialization_info.write[k].pMapEntries = specialization_map_entries[k].ptr();
|
||||
|
||||
pipeline_stages.write[k].pSpecializationInfo = specialization_info.ptr();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
graphics_pipeline_create_info.stageCount = pipeline_stages.size();
|
||||
graphics_pipeline_create_info.pStages = pipeline_stages.ptr();
|
||||
|
||||
graphics_pipeline_create_info.pVertexInputState = &pipeline_vertex_input_state_create_info;
|
||||
graphics_pipeline_create_info.pInputAssemblyState = &input_assembly_create_info;
|
||||
graphics_pipeline_create_info.pTessellationState = &tessellation_create_info;
|
||||
|
@ -6039,7 +6153,7 @@ bool RenderingDeviceVulkan::render_pipeline_is_valid(RID p_pipeline) {
|
|||
/**** COMPUTE PIPELINE ****/
|
||||
/**************************/
|
||||
|
||||
RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader) {
|
||||
RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader, const Vector<PipelineSpecializationConstant> &p_specialization_constants) {
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
//needs a shader
|
||||
|
@ -6061,6 +6175,44 @@ RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader) {
|
|||
compute_pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE;
|
||||
compute_pipeline_create_info.basePipelineIndex = 0;
|
||||
|
||||
VkSpecializationInfo specialization_info;
|
||||
Vector<VkSpecializationMapEntry> specialization_map_entries;
|
||||
Vector<uint32_t> specialization_constant_data;
|
||||
|
||||
if (shader->specialization_constants.size()) {
|
||||
specialization_constant_data.resize(shader->specialization_constants.size());
|
||||
uint32_t *data_ptr = specialization_constant_data.ptrw();
|
||||
for (int i = 0; i < shader->specialization_constants.size(); i++) {
|
||||
//see if overriden
|
||||
const Shader::SpecializationConstant &sc = shader->specialization_constants[i];
|
||||
data_ptr[i] = sc.constant.int_value; //just copy the 32 bits
|
||||
|
||||
for (int j = 0; j < p_specialization_constants.size(); j++) {
|
||||
const PipelineSpecializationConstant &psc = p_specialization_constants[j];
|
||||
if (psc.constant_id == sc.constant.constant_id) {
|
||||
ERR_FAIL_COND_V_MSG(psc.type != sc.constant.type, RID(), "Specialization constant provided for id (" + itos(sc.constant.constant_id) + ") is of the wrong type.");
|
||||
data_ptr[i] = sc.constant.int_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VkSpecializationMapEntry entry;
|
||||
|
||||
entry.constantID = sc.constant.constant_id;
|
||||
entry.offset = i * sizeof(uint32_t);
|
||||
entry.size = sizeof(uint32_t);
|
||||
|
||||
specialization_map_entries.push_back(entry);
|
||||
}
|
||||
|
||||
specialization_info.dataSize = specialization_constant_data.size() * sizeof(uint32_t);
|
||||
specialization_info.pData = data_ptr;
|
||||
specialization_info.mapEntryCount = specialization_map_entries.size();
|
||||
specialization_info.pMapEntries = specialization_map_entries.ptr();
|
||||
|
||||
compute_pipeline_create_info.stage.pSpecializationInfo = &specialization_info;
|
||||
}
|
||||
|
||||
ComputePipeline pipeline;
|
||||
VkResult err = vkCreateComputePipelines(device, VK_NULL_HANDLE, 1, &compute_pipeline_create_info, nullptr, &pipeline.pipeline);
|
||||
ERR_FAIL_COND_V_MSG(err, RID(), "vkCreateComputePipelines failed with error " + itos(err) + ".");
|
||||
|
|
|
@ -623,11 +623,17 @@ class RenderingDeviceVulkan : public RenderingDevice {
|
|||
|
||||
uint32_t compute_local_size[3] = { 0, 0, 0 };
|
||||
|
||||
struct SpecializationConstant {
|
||||
PipelineSpecializationConstant constant;
|
||||
uint32_t stage_flags = 0;
|
||||
};
|
||||
|
||||
bool is_compute = false;
|
||||
int max_output = 0;
|
||||
Vector<Set> sets;
|
||||
Vector<uint32_t> set_formats;
|
||||
Vector<VkPipelineShaderStageCreateInfo> pipeline_stages;
|
||||
Vector<SpecializationConstant> specialization_constants;
|
||||
VkPipelineLayout pipeline_layout = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
|
@ -1100,14 +1106,14 @@ public:
|
|||
/**** RENDER PIPELINE ****/
|
||||
/*************************/
|
||||
|
||||
virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0, uint32_t p_for_render_pass = 0);
|
||||
virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0, uint32_t p_for_render_pass = 0, const Vector<PipelineSpecializationConstant> &p_specialization_constants = Vector<PipelineSpecializationConstant>());
|
||||
virtual bool render_pipeline_is_valid(RID p_pipeline);
|
||||
|
||||
/**************************/
|
||||
/**** COMPUTE PIPELINE ****/
|
||||
/**************************/
|
||||
|
||||
virtual RID compute_pipeline_create(RID p_shader);
|
||||
virtual RID compute_pipeline_create(RID p_shader, const Vector<PipelineSpecializationConstant> &p_specialization_constants = Vector<PipelineSpecializationConstant>());
|
||||
virtual bool compute_pipeline_is_valid(RID p_pipeline);
|
||||
|
||||
/****************/
|
||||
|
|
|
@ -207,6 +207,7 @@ void register_server_types() {
|
|||
ClassDB::register_class<RDShaderSource>();
|
||||
ClassDB::register_class<RDShaderBytecode>();
|
||||
ClassDB::register_class<RDShaderFile>();
|
||||
ClassDB::register_class<RDPipelineSpecializationConstant>();
|
||||
|
||||
ClassDB::register_class<CameraFeed>();
|
||||
|
||||
|
|
|
@ -221,7 +221,36 @@ Error RenderingDevice::_buffer_update(RID p_buffer, uint32_t p_offset, uint32_t
|
|||
return buffer_update(p_buffer, p_offset, p_size, p_data.ptr(), p_post_barrier);
|
||||
}
|
||||
|
||||
RID RenderingDevice::_render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, int p_dynamic_state_flags, uint32_t p_for_render_pass) {
|
||||
static Vector<RenderingDevice::PipelineSpecializationConstant> _get_spec_constants(const TypedArray<RDPipelineSpecializationConstant> &p_constants) {
|
||||
Vector<RenderingDevice::PipelineSpecializationConstant> ret;
|
||||
ret.resize(p_constants.size());
|
||||
for (int i = 0; i < p_constants.size(); i++) {
|
||||
Ref<RDPipelineSpecializationConstant> c = p_constants[i];
|
||||
ERR_CONTINUE(c.is_null());
|
||||
RenderingDevice::PipelineSpecializationConstant &sc = ret.write[i];
|
||||
Variant value = c->get_value();
|
||||
switch (value.get_type()) {
|
||||
case Variant::BOOL: {
|
||||
sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
|
||||
sc.bool_value = value;
|
||||
} break;
|
||||
case Variant::INT: {
|
||||
sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT;
|
||||
sc.int_value = value;
|
||||
} break;
|
||||
case Variant::FLOAT: {
|
||||
sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT;
|
||||
sc.float_value = value;
|
||||
} break;
|
||||
default: {
|
||||
}
|
||||
}
|
||||
|
||||
sc.constant_id = c->get_constant_id();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
RID RenderingDevice::_render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, int p_dynamic_state_flags, uint32_t p_for_render_pass, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants) {
|
||||
PipelineRasterizationState rasterization_state;
|
||||
if (p_rasterization_state.is_valid()) {
|
||||
rasterization_state = p_rasterization_state->base;
|
||||
|
@ -252,7 +281,11 @@ RID RenderingDevice::_render_pipeline_create(RID p_shader, FramebufferFormatID p
|
|||
}
|
||||
}
|
||||
|
||||
return render_pipeline_create(p_shader, p_framebuffer_format, p_vertex_format, p_render_primitive, rasterization_state, multisample_state, depth_stencil_state, color_blend_state, p_dynamic_state_flags, p_for_render_pass);
|
||||
return render_pipeline_create(p_shader, p_framebuffer_format, p_vertex_format, p_render_primitive, rasterization_state, multisample_state, depth_stencil_state, color_blend_state, p_dynamic_state_flags, p_for_render_pass, _get_spec_constants(p_specialization_constants));
|
||||
}
|
||||
|
||||
RID RenderingDevice::_compute_pipeline_create(RID p_shader, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants = TypedArray<RDPipelineSpecializationConstant>()) {
|
||||
return compute_pipeline_create(p_shader, _get_spec_constants(p_specialization_constants));
|
||||
}
|
||||
|
||||
Vector<int64_t> RenderingDevice::_draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const TypedArray<RID> &p_storage_textures) {
|
||||
|
@ -348,10 +381,10 @@ void RenderingDevice::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("buffer_clear", "buffer", "offset", "size_bytes", "post_barrier"), &RenderingDevice::buffer_clear, DEFVAL(BARRIER_MASK_ALL));
|
||||
ClassDB::bind_method(D_METHOD("buffer_get_data", "buffer"), &RenderingDevice::buffer_get_data);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("render_pipeline_create", "shader", "framebuffer_format", "vertex_format", "primitive", "rasterization_state", "multisample_state", "stencil_state", "color_blend_state", "dynamic_state_flags", "for_render_pass"), &RenderingDevice::_render_pipeline_create, DEFVAL(0), DEFVAL(0));
|
||||
ClassDB::bind_method(D_METHOD("render_pipeline_create", "shader", "framebuffer_format", "vertex_format", "primitive", "rasterization_state", "multisample_state", "stencil_state", "color_blend_state", "dynamic_state_flags", "for_render_pass", "specialization_constants"), &RenderingDevice::_render_pipeline_create, DEFVAL(0), DEFVAL(0), DEFVAL(TypedArray<RDPipelineSpecializationConstant>()));
|
||||
ClassDB::bind_method(D_METHOD("render_pipeline_is_valid", "render_pipeline"), &RenderingDevice::render_pipeline_is_valid);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("compute_pipeline_create", "shader"), &RenderingDevice::compute_pipeline_create);
|
||||
ClassDB::bind_method(D_METHOD("compute_pipeline_create", "shader", "specialization_constants"), &RenderingDevice::_compute_pipeline_create, DEFVAL(TypedArray<RDPipelineSpecializationConstant>()));
|
||||
ClassDB::bind_method(D_METHOD("compute_pipeline_is_valid", "compute_pieline"), &RenderingDevice::compute_pipeline_is_valid);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("screen_get_width", "screen"), &RenderingDevice::screen_get_width, DEFVAL(DisplayServer::MAIN_WINDOW_ID));
|
||||
|
@ -853,6 +886,10 @@ void RenderingDevice::_bind_methods() {
|
|||
BIND_ENUM_CONSTANT(SHADER_LANGUAGE_GLSL);
|
||||
BIND_ENUM_CONSTANT(SHADER_LANGUAGE_HLSL);
|
||||
|
||||
BIND_ENUM_CONSTANT(PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL);
|
||||
BIND_ENUM_CONSTANT(PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT);
|
||||
BIND_ENUM_CONSTANT(PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT);
|
||||
|
||||
BIND_ENUM_CONSTANT(LIMIT_MAX_BOUND_UNIFORM_SETS);
|
||||
BIND_ENUM_CONSTANT(LIMIT_MAX_FRAMEBUFFER_COLOR_ATTACHMENTS);
|
||||
BIND_ENUM_CONSTANT(LIMIT_MAX_TEXTURES_PER_UNIFORM_SET);
|
||||
|
|
|
@ -48,6 +48,7 @@ class RDPipelineMultisampleState;
|
|||
class RDPipelineDepthStencilState;
|
||||
class RDPipelineColorBlendState;
|
||||
class RDFramebufferPass;
|
||||
class RDPipelineSpecializationConstant;
|
||||
|
||||
class RenderingDevice : public Object {
|
||||
GDCLASS(RenderingDevice, Object)
|
||||
|
@ -722,6 +723,32 @@ public:
|
|||
virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0;
|
||||
virtual Vector<uint8_t> buffer_get_data(RID p_buffer) = 0; //this causes stall, only use to retrieve large buffers for saving
|
||||
|
||||
/******************************************/
|
||||
/**** PIPELINE SPECIALIZATION CONSTANT ****/
|
||||
/******************************************/
|
||||
|
||||
enum PipelineSpecializationConstantType {
|
||||
PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL,
|
||||
PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT,
|
||||
PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT,
|
||||
};
|
||||
|
||||
struct PipelineSpecializationConstant {
|
||||
PipelineSpecializationConstantType type;
|
||||
uint32_t constant_id;
|
||||
union {
|
||||
uint32_t int_value;
|
||||
float float_value;
|
||||
bool bool_value;
|
||||
};
|
||||
|
||||
PipelineSpecializationConstant() {
|
||||
type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
|
||||
constant_id = 0;
|
||||
int_value = 0;
|
||||
}
|
||||
};
|
||||
|
||||
/*************************/
|
||||
/**** RENDER PIPELINE ****/
|
||||
/*************************/
|
||||
|
@ -978,13 +1005,13 @@ public:
|
|||
};
|
||||
|
||||
virtual bool render_pipeline_is_valid(RID p_pipeline) = 0;
|
||||
virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0, uint32_t p_for_render_pass = 0) = 0;
|
||||
virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0, uint32_t p_for_render_pass = 0, const Vector<PipelineSpecializationConstant> &p_specialization_constants = Vector<PipelineSpecializationConstant>()) = 0;
|
||||
|
||||
/**************************/
|
||||
/**** COMPUTE PIPELINE ****/
|
||||
/**************************/
|
||||
|
||||
virtual RID compute_pipeline_create(RID p_shader) = 0;
|
||||
virtual RID compute_pipeline_create(RID p_shader, const Vector<PipelineSpecializationConstant> &p_specialization_constants = Vector<PipelineSpecializationConstant>()) = 0;
|
||||
virtual bool compute_pipeline_is_valid(RID p_pipeline) = 0;
|
||||
|
||||
/****************/
|
||||
|
@ -1173,7 +1200,8 @@ protected:
|
|||
|
||||
Error _buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL);
|
||||
|
||||
RID _render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, int p_dynamic_state_flags = 0, uint32_t p_for_render_pass = 0);
|
||||
RID _render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, int p_dynamic_state_flags, uint32_t p_for_render_pass, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants);
|
||||
RID _compute_pipeline_create(RID p_shader, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants);
|
||||
|
||||
Vector<int64_t> _draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const TypedArray<RID> &p_storage_textures = TypedArray<RID>());
|
||||
void _draw_list_set_push_constant(DrawListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size);
|
||||
|
@ -1205,6 +1233,7 @@ VARIANT_ENUM_CAST(RenderingDevice::LogicOperation)
|
|||
VARIANT_ENUM_CAST(RenderingDevice::BlendFactor)
|
||||
VARIANT_ENUM_CAST(RenderingDevice::BlendOperation)
|
||||
VARIANT_ENUM_CAST(RenderingDevice::PipelineDynamicStateFlags)
|
||||
VARIANT_ENUM_CAST(RenderingDevice::PipelineSpecializationConstantType)
|
||||
VARIANT_ENUM_CAST(RenderingDevice::InitialAction)
|
||||
VARIANT_ENUM_CAST(RenderingDevice::FinalAction)
|
||||
VARIANT_ENUM_CAST(RenderingDevice::Limit)
|
||||
|
|
|
@ -452,6 +452,41 @@ protected:
|
|||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_ids", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_ids", "get_ids");
|
||||
}
|
||||
};
|
||||
|
||||
class RDPipelineSpecializationConstant : public RefCounted {
|
||||
GDCLASS(RDPipelineSpecializationConstant, RefCounted)
|
||||
friend class RenderingDevice;
|
||||
|
||||
Variant value = false;
|
||||
uint32_t constant_id;
|
||||
|
||||
public:
|
||||
void set_value(const Variant &p_value) {
|
||||
ERR_FAIL_COND(p_value.get_type() != Variant::BOOL && p_value.get_type() != Variant::INT && p_value.get_type() != Variant::FLOAT);
|
||||
value = p_value;
|
||||
}
|
||||
Variant get_value() const { return value; }
|
||||
|
||||
void set_constant_id(uint32_t p_id) {
|
||||
constant_id = p_id;
|
||||
}
|
||||
uint32_t get_constant_id() const {
|
||||
return constant_id;
|
||||
}
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_value", "value"), &RDPipelineSpecializationConstant::set_value);
|
||||
ClassDB::bind_method(D_METHOD("get_value"), &RDPipelineSpecializationConstant::get_value);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_constant_id", "constant_id"), &RDPipelineSpecializationConstant::set_constant_id);
|
||||
ClassDB::bind_method(D_METHOD("get_constant_id"), &RDPipelineSpecializationConstant::get_constant_id);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "set_value", "get_value");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "constant_id", PROPERTY_HINT_RANGE, "0,65535,0"), "set_constant_id", "get_constant_id");
|
||||
}
|
||||
};
|
||||
|
||||
class RDPipelineRasterizationState : public RefCounted {
|
||||
GDCLASS(RDPipelineRasterizationState, RefCounted)
|
||||
friend class RenderingDevice;
|
||||
|
|
|
@ -616,6 +616,11 @@ Files extracted from upstream source:
|
|||
- `include` folder
|
||||
- `LICENSE`
|
||||
|
||||
Some downstream changes have been made and are identified by
|
||||
`// -- GODOT begin --` and `// -- GODOT end --` comments.
|
||||
They can be reapplied using the patch included in the `patches`
|
||||
folder.
|
||||
|
||||
|
||||
## squish
|
||||
|
||||
|
|
|
@ -0,0 +1,293 @@
|
|||
diff --git a/thirdparty/spirv-reflect/spirv_reflect.c b/thirdparty/spirv-reflect/spirv_reflect.c
|
||||
index 0fc979a8a4..3e3643717a 100644
|
||||
--- a/thirdparty/spirv-reflect/spirv_reflect.c
|
||||
+++ b/thirdparty/spirv-reflect/spirv_reflect.c
|
||||
@@ -124,6 +124,9 @@ typedef struct Decorations {
|
||||
NumberDecoration location;
|
||||
NumberDecoration offset;
|
||||
NumberDecoration uav_counter_buffer;
|
||||
+// -- GODOT begin --
|
||||
+ NumberDecoration specialization_constant;
|
||||
+// -- GODOT end --
|
||||
StringDecoration semantic;
|
||||
uint32_t array_stride;
|
||||
uint32_t matrix_stride;
|
||||
@@ -610,6 +613,9 @@ static SpvReflectResult ParseNodes(Parser* p_parser)
|
||||
p_parser->nodes[i].decorations.offset.value = (uint32_t)INVALID_VALUE;
|
||||
p_parser->nodes[i].decorations.uav_counter_buffer.value = (uint32_t)INVALID_VALUE;
|
||||
p_parser->nodes[i].decorations.built_in = (SpvBuiltIn)INVALID_VALUE;
|
||||
+// -- GODOT begin --
|
||||
+ p_parser->nodes[i].decorations.specialization_constant.value = (SpvBuiltIn)INVALID_VALUE;
|
||||
+// -- GODOT end --
|
||||
}
|
||||
// Mark source file id node
|
||||
p_parser->source_file_id = (uint32_t)INVALID_VALUE;
|
||||
@@ -800,10 +806,16 @@ static SpvReflectResult ParseNodes(Parser* p_parser)
|
||||
CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id);
|
||||
}
|
||||
break;
|
||||
-
|
||||
+// -- GODOT begin --
|
||||
case SpvOpSpecConstantTrue:
|
||||
case SpvOpSpecConstantFalse:
|
||||
- case SpvOpSpecConstant:
|
||||
+ case SpvOpSpecConstant: {
|
||||
+ CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id);
|
||||
+ CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id);
|
||||
+ p_node->is_type = true;
|
||||
+ }
|
||||
+ break;
|
||||
+// -- GODOT end --
|
||||
case SpvOpSpecConstantComposite:
|
||||
case SpvOpSpecConstantOp: {
|
||||
CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id);
|
||||
@@ -1309,6 +1321,9 @@ static SpvReflectResult ParseDecorations(Parser* p_parser)
|
||||
skip = true;
|
||||
}
|
||||
break;
|
||||
+// -- GODOT begin --
|
||||
+ case SpvDecorationSpecId:
|
||||
+// -- GODOT end --
|
||||
case SpvDecorationBlock:
|
||||
case SpvDecorationBufferBlock:
|
||||
case SpvDecorationColMajor:
|
||||
@@ -1441,7 +1456,14 @@ static SpvReflectResult ParseDecorations(Parser* p_parser)
|
||||
p_target_decorations->input_attachment_index.word_offset = word_offset;
|
||||
}
|
||||
break;
|
||||
-
|
||||
+// -- GODOT begin --
|
||||
+ case SpvDecorationSpecId: {
|
||||
+ uint32_t word_offset = p_node->word_offset + member_offset+ 3;
|
||||
+ CHECKED_READU32(p_parser, word_offset, p_target_decorations->specialization_constant.value);
|
||||
+ p_target_decorations->specialization_constant.word_offset = word_offset;
|
||||
+ }
|
||||
+ break;
|
||||
+// -- GODOT end --
|
||||
case SpvReflectDecorationHlslCounterBufferGOOGLE: {
|
||||
uint32_t word_offset = p_node->word_offset + member_offset+ 3;
|
||||
CHECKED_READU32(p_parser, word_offset, p_target_decorations->uav_counter_buffer.value);
|
||||
@@ -1731,6 +1753,13 @@ static SpvReflectResult ParseType(
|
||||
p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_EXTERNAL_ACCELERATION_STRUCTURE;
|
||||
}
|
||||
break;
|
||||
+// -- GODOT begin --
|
||||
+ case SpvOpSpecConstantTrue:
|
||||
+ case SpvOpSpecConstantFalse:
|
||||
+ case SpvOpSpecConstant: {
|
||||
+ }
|
||||
+ break;
|
||||
+// -- GODOT end --
|
||||
}
|
||||
|
||||
if (result == SPV_REFLECT_RESULT_SUCCESS) {
|
||||
@@ -3187,6 +3216,69 @@ static SpvReflectResult ParseExecutionModes(Parser* p_parser, SpvReflectShaderMo
|
||||
return SPV_REFLECT_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
+// -- GODOT begin --
|
||||
+static SpvReflectResult ParseSpecializationConstants(Parser* p_parser, SpvReflectShaderModule* p_module)
|
||||
+{
|
||||
+ p_module->specialization_constant_count = 0;
|
||||
+ p_module->specialization_constants = NULL;
|
||||
+ for (size_t i = 0; i < p_parser->node_count; ++i) {
|
||||
+ Node* p_node = &(p_parser->nodes[i]);
|
||||
+ if (p_node->op == SpvOpSpecConstantTrue || p_node->op == SpvOpSpecConstantFalse || p_node->op == SpvOpSpecConstant) {
|
||||
+ p_module->specialization_constant_count++;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (p_module->specialization_constant_count == 0) {
|
||||
+ return SPV_REFLECT_RESULT_SUCCESS;
|
||||
+ }
|
||||
+
|
||||
+ p_module->specialization_constants = (SpvReflectSpecializationConstant*)calloc(p_module->specialization_constant_count, sizeof(SpvReflectSpecializationConstant));
|
||||
+
|
||||
+ uint32_t index = 0;
|
||||
+
|
||||
+ for (size_t i = 0; i < p_parser->node_count; ++i) {
|
||||
+ Node* p_node = &(p_parser->nodes[i]);
|
||||
+ switch(p_node->op) {
|
||||
+ default: continue;
|
||||
+ case SpvOpSpecConstantTrue: {
|
||||
+ p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL;
|
||||
+ p_module->specialization_constants[index].default_value.int_bool_value = 1;
|
||||
+ } break;
|
||||
+ case SpvOpSpecConstantFalse: {
|
||||
+ p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL;
|
||||
+ p_module->specialization_constants[index].default_value.int_bool_value = 0;
|
||||
+ } break;
|
||||
+ case SpvOpSpecConstant: {
|
||||
+ SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS;
|
||||
+ uint32_t element_type_id = (uint32_t)INVALID_VALUE;
|
||||
+ uint32_t default_value = 0;
|
||||
+ IF_READU32(result, p_parser, p_node->word_offset + 1, element_type_id);
|
||||
+ IF_READU32(result, p_parser, p_node->word_offset + 3, default_value);
|
||||
+
|
||||
+ Node* p_next_node = FindNode(p_parser, element_type_id);
|
||||
+
|
||||
+ if (p_next_node->op == SpvOpTypeInt) {
|
||||
+ p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_INT;
|
||||
+ } else if (p_next_node->op == SpvOpTypeFloat) {
|
||||
+ p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT;
|
||||
+ } else {
|
||||
+ return SPV_REFLECT_RESULT_ERROR_PARSE_FAILED;
|
||||
+ }
|
||||
+
|
||||
+ p_module->specialization_constants[index].default_value.int_bool_value = default_value; //bits are the same for int and float
|
||||
+ } break;
|
||||
+ }
|
||||
+
|
||||
+ p_module->specialization_constants[index].name = p_node->name;
|
||||
+ p_module->specialization_constants[index].constant_id = p_node->decorations.specialization_constant.value;
|
||||
+ p_module->specialization_constants[index].spirv_id = p_node->result_id;
|
||||
+ index++;
|
||||
+ }
|
||||
+
|
||||
+ return SPV_REFLECT_RESULT_SUCCESS;
|
||||
+}
|
||||
+// -- GODOT end --
|
||||
+
|
||||
static SpvReflectResult ParsePushConstantBlocks(Parser* p_parser, SpvReflectShaderModule* p_module)
|
||||
{
|
||||
for (size_t i = 0; i < p_parser->node_count; ++i) {
|
||||
@@ -3562,6 +3654,12 @@ SpvReflectResult spvReflectCreateShaderModule(
|
||||
result = ParsePushConstantBlocks(&parser, p_module);
|
||||
SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
|
||||
}
|
||||
+// -- GODOT begin --
|
||||
+ if (result == SPV_REFLECT_RESULT_SUCCESS) {
|
||||
+ result = ParseSpecializationConstants(&parser, p_module);
|
||||
+ SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
|
||||
+ }
|
||||
+// -- GODOT end --
|
||||
if (result == SPV_REFLECT_RESULT_SUCCESS) {
|
||||
result = ParseEntryPoints(&parser, p_module);
|
||||
SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
|
||||
@@ -3691,6 +3789,9 @@ void spvReflectDestroyShaderModule(SpvReflectShaderModule* p_module)
|
||||
SafeFree(p_entry->used_push_constants);
|
||||
}
|
||||
SafeFree(p_module->entry_points);
|
||||
+// -- GODOT begin --
|
||||
+ SafeFree(p_module->specialization_constants);
|
||||
+// -- GODOT end --
|
||||
|
||||
// Push constants
|
||||
for (size_t i = 0; i < p_module->push_constant_block_count; ++i) {
|
||||
@@ -3959,6 +4060,38 @@ SpvReflectResult spvReflectEnumerateEntryPointInterfaceVariables(
|
||||
return SPV_REFLECT_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
+// -- GODOT begin --
|
||||
+SpvReflectResult spvReflectEnumerateSpecializationConstants(
|
||||
+ const SpvReflectShaderModule* p_module,
|
||||
+ uint32_t* p_count,
|
||||
+ SpvReflectSpecializationConstant** pp_constants
|
||||
+)
|
||||
+{
|
||||
+ if (IsNull(p_module)) {
|
||||
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
|
||||
+ }
|
||||
+ if (IsNull(p_count)) {
|
||||
+ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
|
||||
+ }
|
||||
+
|
||||
+ if (IsNotNull(pp_constants)) {
|
||||
+ if (*p_count != p_module->specialization_constant_count) {
|
||||
+ return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
|
||||
+ }
|
||||
+
|
||||
+ for (uint32_t index = 0; index < *p_count; ++index) {
|
||||
+ SpvReflectSpecializationConstant *p_const = &p_module->specialization_constants[index];
|
||||
+ pp_constants[index] = p_const;
|
||||
+ }
|
||||
+ }
|
||||
+ else {
|
||||
+ *p_count = p_module->specialization_constant_count;
|
||||
+ }
|
||||
+
|
||||
+ return SPV_REFLECT_RESULT_SUCCESS;
|
||||
+}
|
||||
+// -- GODOT end --
|
||||
+
|
||||
SpvReflectResult spvReflectEnumerateInputVariables(
|
||||
const SpvReflectShaderModule* p_module,
|
||||
uint32_t* p_count,
|
||||
diff --git a/thirdparty/spirv-reflect/spirv_reflect.h b/thirdparty/spirv-reflect/spirv_reflect.h
|
||||
index a5a956e9e8..21f8160770 100644
|
||||
--- a/thirdparty/spirv-reflect/spirv_reflect.h
|
||||
+++ b/thirdparty/spirv-reflect/spirv_reflect.h
|
||||
@@ -292,6 +292,28 @@ typedef struct SpvReflectTypeDescription {
|
||||
struct SpvReflectTypeDescription* members;
|
||||
} SpvReflectTypeDescription;
|
||||
|
||||
+// -- GODOT begin --
|
||||
+/*! @struct SpvReflectSpecializationConstant
|
||||
+
|
||||
+*/
|
||||
+
|
||||
+typedef enum SpvReflectSpecializationConstantType {
|
||||
+ SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL = 0,
|
||||
+ SPV_REFLECT_SPECIALIZATION_CONSTANT_INT = 1,
|
||||
+ SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT = 2,
|
||||
+} SpvReflectSpecializationConstantType;
|
||||
+
|
||||
+typedef struct SpvReflectSpecializationConstant {
|
||||
+ const char* name;
|
||||
+ uint32_t spirv_id;
|
||||
+ uint32_t constant_id;
|
||||
+ SpvReflectSpecializationConstantType constant_type;
|
||||
+ union {
|
||||
+ float float_value;
|
||||
+ uint32_t int_bool_value;
|
||||
+ } default_value;
|
||||
+} SpvReflectSpecializationConstant;
|
||||
+// -- GODOT end --
|
||||
|
||||
/*! @struct SpvReflectInterfaceVariable
|
||||
|
||||
@@ -439,6 +461,10 @@ typedef struct SpvReflectShaderModule {
|
||||
SpvReflectInterfaceVariable* interface_variables;
|
||||
uint32_t push_constant_block_count;
|
||||
SpvReflectBlockVariable* push_constant_blocks;
|
||||
+ // -- GODOT begin --
|
||||
+ uint32_t specialization_constant_count;
|
||||
+ SpvReflectSpecializationConstant* specialization_constants;
|
||||
+ // -- GODOT end --
|
||||
|
||||
struct Internal {
|
||||
size_t spirv_size;
|
||||
@@ -694,6 +720,33 @@ SpvReflectResult spvReflectEnumerateInputVariables(
|
||||
SpvReflectInterfaceVariable** pp_variables
|
||||
);
|
||||
|
||||
+// -- GOODT begin --
|
||||
+/*! @fn spvReflectEnumerateSpecializationConstants
|
||||
+ @brief If the module contains multiple entry points, this will only get
|
||||
+ the specialization constants for the first one.
|
||||
+ @param p_module Pointer to an instance of SpvReflectShaderModule.
|
||||
+ @param p_count If pp_constants is NULL, the module's specialization constant
|
||||
+ count will be stored here.
|
||||
+ If pp_variables is not NULL, *p_count must contain
|
||||
+ the module's specialization constant count.
|
||||
+ @param pp_variables If NULL, the module's specialization constant count will be
|
||||
+ written to *p_count.
|
||||
+ If non-NULL, pp_constants must point to an array with
|
||||
+ *p_count entries, where pointers to the module's
|
||||
+ specialization constants will be written. The caller must not
|
||||
+ free the specialization constants written to this array.
|
||||
+ @return If successful, returns SPV_REFLECT_RESULT_SUCCESS.
|
||||
+ Otherwise, the error code indicates the cause of the
|
||||
+ failure.
|
||||
+
|
||||
+*/
|
||||
+SpvReflectResult spvReflectEnumerateSpecializationConstants(
|
||||
+ const SpvReflectShaderModule* p_module,
|
||||
+ uint32_t* p_count,
|
||||
+ SpvReflectSpecializationConstant** pp_constants
|
||||
+);
|
||||
+// -- GODOT end --
|
||||
+
|
||||
/*! @fn spvReflectEnumerateEntryPointInputVariables
|
||||
@brief Enumerate the input variables for a given entry point.
|
||||
@param entry_point The name of the entry point to get the input variables for.
|
|
@ -124,6 +124,9 @@ typedef struct Decorations {
|
|||
NumberDecoration location;
|
||||
NumberDecoration offset;
|
||||
NumberDecoration uav_counter_buffer;
|
||||
// -- GODOT begin --
|
||||
NumberDecoration specialization_constant;
|
||||
// -- GODOT end --
|
||||
StringDecoration semantic;
|
||||
uint32_t array_stride;
|
||||
uint32_t matrix_stride;
|
||||
|
@ -610,6 +613,9 @@ static SpvReflectResult ParseNodes(Parser* p_parser)
|
|||
p_parser->nodes[i].decorations.offset.value = (uint32_t)INVALID_VALUE;
|
||||
p_parser->nodes[i].decorations.uav_counter_buffer.value = (uint32_t)INVALID_VALUE;
|
||||
p_parser->nodes[i].decorations.built_in = (SpvBuiltIn)INVALID_VALUE;
|
||||
// -- GODOT begin --
|
||||
p_parser->nodes[i].decorations.specialization_constant.value = (SpvBuiltIn)INVALID_VALUE;
|
||||
// -- GODOT end --
|
||||
}
|
||||
// Mark source file id node
|
||||
p_parser->source_file_id = (uint32_t)INVALID_VALUE;
|
||||
|
@ -800,10 +806,16 @@ static SpvReflectResult ParseNodes(Parser* p_parser)
|
|||
CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id);
|
||||
}
|
||||
break;
|
||||
|
||||
// -- GODOT begin --
|
||||
case SpvOpSpecConstantTrue:
|
||||
case SpvOpSpecConstantFalse:
|
||||
case SpvOpSpecConstant:
|
||||
case SpvOpSpecConstant: {
|
||||
CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id);
|
||||
CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id);
|
||||
p_node->is_type = true;
|
||||
}
|
||||
break;
|
||||
// -- GODOT end --
|
||||
case SpvOpSpecConstantComposite:
|
||||
case SpvOpSpecConstantOp: {
|
||||
CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id);
|
||||
|
@ -1309,6 +1321,9 @@ static SpvReflectResult ParseDecorations(Parser* p_parser)
|
|||
skip = true;
|
||||
}
|
||||
break;
|
||||
// -- GODOT begin --
|
||||
case SpvDecorationSpecId:
|
||||
// -- GODOT end --
|
||||
case SpvDecorationBlock:
|
||||
case SpvDecorationBufferBlock:
|
||||
case SpvDecorationColMajor:
|
||||
|
@ -1441,7 +1456,14 @@ static SpvReflectResult ParseDecorations(Parser* p_parser)
|
|||
p_target_decorations->input_attachment_index.word_offset = word_offset;
|
||||
}
|
||||
break;
|
||||
|
||||
// -- GODOT begin --
|
||||
case SpvDecorationSpecId: {
|
||||
uint32_t word_offset = p_node->word_offset + member_offset+ 3;
|
||||
CHECKED_READU32(p_parser, word_offset, p_target_decorations->specialization_constant.value);
|
||||
p_target_decorations->specialization_constant.word_offset = word_offset;
|
||||
}
|
||||
break;
|
||||
// -- GODOT end --
|
||||
case SpvReflectDecorationHlslCounterBufferGOOGLE: {
|
||||
uint32_t word_offset = p_node->word_offset + member_offset+ 3;
|
||||
CHECKED_READU32(p_parser, word_offset, p_target_decorations->uav_counter_buffer.value);
|
||||
|
@ -1731,6 +1753,13 @@ static SpvReflectResult ParseType(
|
|||
p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_EXTERNAL_ACCELERATION_STRUCTURE;
|
||||
}
|
||||
break;
|
||||
// -- GODOT begin --
|
||||
case SpvOpSpecConstantTrue:
|
||||
case SpvOpSpecConstantFalse:
|
||||
case SpvOpSpecConstant: {
|
||||
}
|
||||
break;
|
||||
// -- GODOT end --
|
||||
}
|
||||
|
||||
if (result == SPV_REFLECT_RESULT_SUCCESS) {
|
||||
|
@ -3187,6 +3216,69 @@ static SpvReflectResult ParseExecutionModes(Parser* p_parser, SpvReflectShaderMo
|
|||
return SPV_REFLECT_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
// -- GODOT begin --
|
||||
static SpvReflectResult ParseSpecializationConstants(Parser* p_parser, SpvReflectShaderModule* p_module)
|
||||
{
|
||||
p_module->specialization_constant_count = 0;
|
||||
p_module->specialization_constants = NULL;
|
||||
for (size_t i = 0; i < p_parser->node_count; ++i) {
|
||||
Node* p_node = &(p_parser->nodes[i]);
|
||||
if (p_node->op == SpvOpSpecConstantTrue || p_node->op == SpvOpSpecConstantFalse || p_node->op == SpvOpSpecConstant) {
|
||||
p_module->specialization_constant_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_module->specialization_constant_count == 0) {
|
||||
return SPV_REFLECT_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
p_module->specialization_constants = (SpvReflectSpecializationConstant*)calloc(p_module->specialization_constant_count, sizeof(SpvReflectSpecializationConstant));
|
||||
|
||||
uint32_t index = 0;
|
||||
|
||||
for (size_t i = 0; i < p_parser->node_count; ++i) {
|
||||
Node* p_node = &(p_parser->nodes[i]);
|
||||
switch(p_node->op) {
|
||||
default: continue;
|
||||
case SpvOpSpecConstantTrue: {
|
||||
p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL;
|
||||
p_module->specialization_constants[index].default_value.int_bool_value = 1;
|
||||
} break;
|
||||
case SpvOpSpecConstantFalse: {
|
||||
p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL;
|
||||
p_module->specialization_constants[index].default_value.int_bool_value = 0;
|
||||
} break;
|
||||
case SpvOpSpecConstant: {
|
||||
SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS;
|
||||
uint32_t element_type_id = (uint32_t)INVALID_VALUE;
|
||||
uint32_t default_value = 0;
|
||||
IF_READU32(result, p_parser, p_node->word_offset + 1, element_type_id);
|
||||
IF_READU32(result, p_parser, p_node->word_offset + 3, default_value);
|
||||
|
||||
Node* p_next_node = FindNode(p_parser, element_type_id);
|
||||
|
||||
if (p_next_node->op == SpvOpTypeInt) {
|
||||
p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_INT;
|
||||
} else if (p_next_node->op == SpvOpTypeFloat) {
|
||||
p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT;
|
||||
} else {
|
||||
return SPV_REFLECT_RESULT_ERROR_PARSE_FAILED;
|
||||
}
|
||||
|
||||
p_module->specialization_constants[index].default_value.int_bool_value = default_value; //bits are the same for int and float
|
||||
} break;
|
||||
}
|
||||
|
||||
p_module->specialization_constants[index].name = p_node->name;
|
||||
p_module->specialization_constants[index].constant_id = p_node->decorations.specialization_constant.value;
|
||||
p_module->specialization_constants[index].spirv_id = p_node->result_id;
|
||||
index++;
|
||||
}
|
||||
|
||||
return SPV_REFLECT_RESULT_SUCCESS;
|
||||
}
|
||||
// -- GODOT end --
|
||||
|
||||
static SpvReflectResult ParsePushConstantBlocks(Parser* p_parser, SpvReflectShaderModule* p_module)
|
||||
{
|
||||
for (size_t i = 0; i < p_parser->node_count; ++i) {
|
||||
|
@ -3562,6 +3654,12 @@ SpvReflectResult spvReflectCreateShaderModule(
|
|||
result = ParsePushConstantBlocks(&parser, p_module);
|
||||
SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
|
||||
}
|
||||
// -- GODOT begin --
|
||||
if (result == SPV_REFLECT_RESULT_SUCCESS) {
|
||||
result = ParseSpecializationConstants(&parser, p_module);
|
||||
SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
|
||||
}
|
||||
// -- GODOT end --
|
||||
if (result == SPV_REFLECT_RESULT_SUCCESS) {
|
||||
result = ParseEntryPoints(&parser, p_module);
|
||||
SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
|
||||
|
@ -3691,6 +3789,9 @@ void spvReflectDestroyShaderModule(SpvReflectShaderModule* p_module)
|
|||
SafeFree(p_entry->used_push_constants);
|
||||
}
|
||||
SafeFree(p_module->entry_points);
|
||||
// -- GODOT begin --
|
||||
SafeFree(p_module->specialization_constants);
|
||||
// -- GODOT end --
|
||||
|
||||
// Push constants
|
||||
for (size_t i = 0; i < p_module->push_constant_block_count; ++i) {
|
||||
|
@ -3959,6 +4060,38 @@ SpvReflectResult spvReflectEnumerateEntryPointInterfaceVariables(
|
|||
return SPV_REFLECT_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
// -- GODOT begin --
|
||||
SpvReflectResult spvReflectEnumerateSpecializationConstants(
|
||||
const SpvReflectShaderModule* p_module,
|
||||
uint32_t* p_count,
|
||||
SpvReflectSpecializationConstant** pp_constants
|
||||
)
|
||||
{
|
||||
if (IsNull(p_module)) {
|
||||
return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
|
||||
}
|
||||
if (IsNull(p_count)) {
|
||||
return SPV_REFLECT_RESULT_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
if (IsNotNull(pp_constants)) {
|
||||
if (*p_count != p_module->specialization_constant_count) {
|
||||
return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH;
|
||||
}
|
||||
|
||||
for (uint32_t index = 0; index < *p_count; ++index) {
|
||||
SpvReflectSpecializationConstant *p_const = &p_module->specialization_constants[index];
|
||||
pp_constants[index] = p_const;
|
||||
}
|
||||
}
|
||||
else {
|
||||
*p_count = p_module->specialization_constant_count;
|
||||
}
|
||||
|
||||
return SPV_REFLECT_RESULT_SUCCESS;
|
||||
}
|
||||
// -- GODOT end --
|
||||
|
||||
SpvReflectResult spvReflectEnumerateInputVariables(
|
||||
const SpvReflectShaderModule* p_module,
|
||||
uint32_t* p_count,
|
||||
|
|
|
@ -292,6 +292,28 @@ typedef struct SpvReflectTypeDescription {
|
|||
struct SpvReflectTypeDescription* members;
|
||||
} SpvReflectTypeDescription;
|
||||
|
||||
// -- GODOT begin --
|
||||
/*! @struct SpvReflectSpecializationConstant
|
||||
|
||||
*/
|
||||
|
||||
typedef enum SpvReflectSpecializationConstantType {
|
||||
SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL = 0,
|
||||
SPV_REFLECT_SPECIALIZATION_CONSTANT_INT = 1,
|
||||
SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT = 2,
|
||||
} SpvReflectSpecializationConstantType;
|
||||
|
||||
typedef struct SpvReflectSpecializationConstant {
|
||||
const char* name;
|
||||
uint32_t spirv_id;
|
||||
uint32_t constant_id;
|
||||
SpvReflectSpecializationConstantType constant_type;
|
||||
union {
|
||||
float float_value;
|
||||
uint32_t int_bool_value;
|
||||
} default_value;
|
||||
} SpvReflectSpecializationConstant;
|
||||
// -- GODOT end --
|
||||
|
||||
/*! @struct SpvReflectInterfaceVariable
|
||||
|
||||
|
@ -439,6 +461,10 @@ typedef struct SpvReflectShaderModule {
|
|||
SpvReflectInterfaceVariable* interface_variables;
|
||||
uint32_t push_constant_block_count;
|
||||
SpvReflectBlockVariable* push_constant_blocks;
|
||||
// -- GODOT begin --
|
||||
uint32_t specialization_constant_count;
|
||||
SpvReflectSpecializationConstant* specialization_constants;
|
||||
// -- GODOT end --
|
||||
|
||||
struct Internal {
|
||||
size_t spirv_size;
|
||||
|
@ -694,6 +720,33 @@ SpvReflectResult spvReflectEnumerateInputVariables(
|
|||
SpvReflectInterfaceVariable** pp_variables
|
||||
);
|
||||
|
||||
// -- GOODT begin --
|
||||
/*! @fn spvReflectEnumerateSpecializationConstants
|
||||
@brief If the module contains multiple entry points, this will only get
|
||||
the specialization constants for the first one.
|
||||
@param p_module Pointer to an instance of SpvReflectShaderModule.
|
||||
@param p_count If pp_constants is NULL, the module's specialization constant
|
||||
count will be stored here.
|
||||
If pp_variables is not NULL, *p_count must contain
|
||||
the module's specialization constant count.
|
||||
@param pp_variables If NULL, the module's specialization constant count will be
|
||||
written to *p_count.
|
||||
If non-NULL, pp_constants must point to an array with
|
||||
*p_count entries, where pointers to the module's
|
||||
specialization constants will be written. The caller must not
|
||||
free the specialization constants written to this array.
|
||||
@return If successful, returns SPV_REFLECT_RESULT_SUCCESS.
|
||||
Otherwise, the error code indicates the cause of the
|
||||
failure.
|
||||
|
||||
*/
|
||||
SpvReflectResult spvReflectEnumerateSpecializationConstants(
|
||||
const SpvReflectShaderModule* p_module,
|
||||
uint32_t* p_count,
|
||||
SpvReflectSpecializationConstant** pp_constants
|
||||
);
|
||||
// -- GODOT end --
|
||||
|
||||
/*! @fn spvReflectEnumerateEntryPointInputVariables
|
||||
@brief Enumerate the input variables for a given entry point.
|
||||
@param entry_point The name of the entry point to get the input variables for.
|
||||
|
|
Loading…
Reference in New Issue