diff options
author | Juan Linietsky <reduzio@gmail.com> | 2019-07-27 10:23:24 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2020-02-11 11:53:29 +0100 |
commit | 0586e184490fd132f99acb1a67c788959cfdbade (patch) | |
tree | 194972ba608705445c9ee084f908e183a9792760 /drivers | |
parent | 8bbbb973361f367a4888629c571fb6f43581269d (diff) |
Custom material support seems complete.
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/dummy/rasterizer_dummy.h | 2 | ||||
-rw-r--r-- | drivers/gles2/rasterizer_canvas_gles2.h | 2 | ||||
-rw-r--r-- | drivers/gles2/rasterizer_gles2.h | 2 | ||||
-rw-r--r-- | drivers/gles2/rasterizer_storage_gles2.h | 2 | ||||
-rw-r--r-- | drivers/gles3/rasterizer_canvas_gles3.h | 2 | ||||
-rw-r--r-- | drivers/gles3/rasterizer_gles3.h | 2 | ||||
-rw-r--r-- | drivers/gles3/rasterizer_storage_gles3.h | 2 | ||||
-rw-r--r-- | drivers/vulkan/rendering_device_vulkan.cpp | 466 | ||||
-rw-r--r-- | drivers/vulkan/rendering_device_vulkan.h | 171 |
9 files changed, 523 insertions, 128 deletions
diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h index 796e276418..990a0dc455 100644 --- a/drivers/dummy/rasterizer_dummy.h +++ b/drivers/dummy/rasterizer_dummy.h @@ -35,7 +35,7 @@ #include "core/rid_owner.h" #include "core/self_list.h" #include "scene/resources/mesh.h" -#include "servers/visual/rasterizer/rasterizer.h" +#include "servers/visual/rasterizer.h" #include "servers/visual_server.h" class RasterizerSceneDummy : public RasterizerScene { diff --git a/drivers/gles2/rasterizer_canvas_gles2.h b/drivers/gles2/rasterizer_canvas_gles2.h index ce8761b448..f6ae6a60c0 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.h +++ b/drivers/gles2/rasterizer_canvas_gles2.h @@ -32,7 +32,7 @@ #define RASTERIZERCANVASGLES2_H #include "rasterizer_storage_gles2.h" -#include "servers/visual/rasterizer/rasterizer.h" +#include "servers/visual/rasterizer.h" #include "shaders/canvas.glsl.gen.h" #include "shaders/lens_distorted.glsl.gen.h" diff --git a/drivers/gles2/rasterizer_gles2.h b/drivers/gles2/rasterizer_gles2.h index 3d0debc0ed..9a5501f13d 100644 --- a/drivers/gles2/rasterizer_gles2.h +++ b/drivers/gles2/rasterizer_gles2.h @@ -34,7 +34,7 @@ #include "rasterizer_canvas_gles2.h" #include "rasterizer_scene_gles2.h" #include "rasterizer_storage_gles2.h" -#include "servers/visual/rasterizer/rasterizer.h" +#include "servers/visual/rasterizer.h" class RasterizerGLES2 : public Rasterizer { diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h index 79e3f610ea..a6aae400ca 100644 --- a/drivers/gles2/rasterizer_storage_gles2.h +++ b/drivers/gles2/rasterizer_storage_gles2.h @@ -33,7 +33,7 @@ #include "core/pool_vector.h" #include "core/self_list.h" -#include "servers/visual/rasterizer/rasterizer.h" +#include "servers/visual/rasterizer.h" #include "servers/visual/shader_language.h" #include "shader_compiler_gles2.h" #include "shader_gles2.h" diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h index b25fbd97f0..8e7a3ae873 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.h +++ b/drivers/gles3/rasterizer_canvas_gles3.h @@ -32,7 +32,7 @@ #define RASTERIZERCANVASGLES3_H #include "rasterizer_storage_gles3.h" -#include "servers/visual/rasterizer/rasterizer.h" +#include "servers/visual/rasterizer.h" #include "shaders/canvas_shadow.glsl.gen.h" #include "shaders/lens_distorted.glsl.gen.h" diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h index 6b5ce683a4..de7c1ab7e1 100644 --- a/drivers/gles3/rasterizer_gles3.h +++ b/drivers/gles3/rasterizer_gles3.h @@ -34,7 +34,7 @@ #include "rasterizer_canvas_gles3.h" #include "rasterizer_scene_gles3.h" #include "rasterizer_storage_gles3.h" -#include "servers/visual/rasterizer/rasterizer.h" +#include "servers/visual/rasterizer.h" class RasterizerGLES3 : public Rasterizer { diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index c4e4ac87e4..54c2e2b884 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -32,7 +32,7 @@ #define RASTERIZERSTORAGEGLES3_H #include "core/self_list.h" -#include "servers/visual/rasterizer/rasterizer.h" +#include "servers/visual/rasterizer.h" #include "servers/visual/shader_language.h" #include "shader_compiler_gles3.h" #include "shader_gles3.h" diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index abbfde0b59..b2d5a3781c 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -1009,6 +1009,7 @@ uint32_t RenderingDeviceVulkan::get_compressed_image_format_pixel_rshift(DataFor uint32_t RenderingDeviceVulkan::get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmaps, uint32_t *r_blockw, uint32_t *r_blockh, uint32_t *r_depth) { + ERR_FAIL_COND_V(p_mipmaps == 0, 0); uint32_t w = p_width; uint32_t h = p_height; uint32_t d = p_depth; @@ -1559,10 +1560,14 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T if (p_format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT) { image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; } - if (p_format.usage_bits & TEXTURE_USAGE_CAN_RETRIEVE_BIT) { + if (p_format.usage_bits & TEXTURE_USAGE_CAN_COPY_FROM_BIT) { image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; } + if (p_format.usage_bits & TEXTURE_USAGE_CAN_COPY_TO_BIT) { + image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; + } + image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; image_create_info.queueFamilyIndexCount = 0; image_create_info.pQueueFamilyIndices = NULL; @@ -1866,7 +1871,7 @@ RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID return id; } -RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, int p_layer, int p_mipmap) { +RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap) { Texture *src_texture = texture_owner.getornull(p_with_texture); ERR_FAIL_COND_V(!src_texture, RID()); @@ -1879,12 +1884,18 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p //create view - Texture texture = *src_texture; + ERR_FAIL_INDEX_V(p_mipmap, src_texture->mipmaps, RID()); uint32_t array_layer_multiplier = 1; - if (texture.type == TEXTURE_TYPE_CUBE_ARRAY || texture.type == TEXTURE_TYPE_CUBE) { + if (src_texture->type == TEXTURE_TYPE_CUBE_ARRAY || src_texture->type == TEXTURE_TYPE_CUBE) { array_layer_multiplier = 6; } + ERR_FAIL_INDEX_V(p_layer, src_texture->layers * array_layer_multiplier, RID()); + + Texture texture = *src_texture; + get_image_format_required_size(texture.format, texture.width, texture.height, texture.depth, p_mipmap + 1, &texture.width, &texture.height); + texture.mipmaps = 1; + texture.layers = 1; VkImageViewCreateInfo image_view_create_info; image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; @@ -1928,7 +1939,6 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p image_view_create_info.components.b = component_swizzles[p_view.swizzle_b]; image_view_create_info.components.a = component_swizzles[p_view.swizzle_a]; - ERR_FAIL_INDEX_V(p_mipmap, texture.mipmaps, RID()); image_view_create_info.subresourceRange.baseMipLevel = p_mipmap; image_view_create_info.subresourceRange.levelCount = 1; image_view_create_info.subresourceRange.layerCount = 1; @@ -2237,8 +2247,8 @@ PoolVector<uint8_t> RenderingDeviceVulkan::texture_get_data(RID p_texture, uint3 ERR_FAIL_COND_V_MSG(tex->bound, PoolVector<uint8_t>(), "Texture can't be retrieved while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture."); - ERR_FAIL_COND_V_MSG(!(tex->usage_flags & TEXTURE_USAGE_CAN_RETRIEVE_BIT), PoolVector<uint8_t>(), - "Texture requires the TEXTURE_USAGE_CAN_RETRIEVE_BIT in order to be retrieved."); + ERR_FAIL_COND_V_MSG(!(tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), PoolVector<uint8_t>(), + "Texture requires the TEXTURE_USAGE_CAN_COPY_FROM_BIT in order to be retrieved."); uint32_t layer_count = tex->layers; if (tex->type == TEXTURE_TYPE_CUBE || tex->type == TEXTURE_TYPE_CUBE_ARRAY) { @@ -2428,6 +2438,173 @@ bool RenderingDeviceVulkan::texture_is_valid(RID p_texture) { return texture_owner.owns(p_texture); } +Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, bool p_sync_with_draw) { + + Texture *src_tex = texture_owner.getornull(p_from_texture); + ERR_FAIL_COND_V(!src_tex, ERR_INVALID_PARAMETER); + + ERR_FAIL_COND_V_MSG(p_sync_with_draw && src_tex->bound, ERR_INVALID_PARAMETER, + "Source texture can't be copied while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture."); + ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), ERR_INVALID_PARAMETER, + "Source texture requires the TEXTURE_USAGE_CAN_COPY_FROM_BIT in order to be retrieved."); + + uint32_t src_layer_count = src_tex->layers; + uint32_t src_width, src_height, src_depth; + get_image_format_required_size(src_tex->format, src_tex->width, src_tex->height, src_tex->depth, p_src_mipmap + 1, &src_width, &src_height, &src_depth); + if (src_tex->type == TEXTURE_TYPE_CUBE || src_tex->type == TEXTURE_TYPE_CUBE_ARRAY) { + src_layer_count *= 6; + } + + ERR_FAIL_COND_V(p_from.x < 0 || p_from.x + p_size.x > src_width, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_from.y < 0 || p_from.y + p_size.y > src_height, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_from.z < 0 || p_from.z + p_size.z > src_depth, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_src_mipmap >= src_tex->mipmaps, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_src_layer >= src_layer_count, ERR_INVALID_PARAMETER); + + Texture *dst_tex = texture_owner.getornull(p_to_texture); + ERR_FAIL_COND_V(!dst_tex, ERR_INVALID_PARAMETER); + + ERR_FAIL_COND_V_MSG(p_sync_with_draw && dst_tex->bound, ERR_INVALID_PARAMETER, + "Destination texture can't be copied while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture."); + ERR_FAIL_COND_V_MSG(!(dst_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER, + "Destination texture requires the TEXTURE_USAGE_CAN_COPY_TO_BIT in order to be retrieved."); + + uint32_t dst_layer_count = dst_tex->layers; + uint32_t dst_width, dst_height, dst_depth; + get_image_format_required_size(dst_tex->format, dst_tex->width, dst_tex->height, dst_tex->depth, p_dst_mipmap + 1, &dst_width, &dst_height, &dst_depth); + if (dst_tex->type == TEXTURE_TYPE_CUBE || dst_tex->type == TEXTURE_TYPE_CUBE_ARRAY) { + dst_layer_count *= 6; + } + + ERR_FAIL_COND_V(p_to.x < 0 || p_to.x + p_size.x > dst_width, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_to.y < 0 || p_to.y + p_size.y > dst_height, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_to.z < 0 || p_to.z + p_size.z > dst_depth, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_dst_mipmap >= dst_tex->mipmaps, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_dst_layer >= dst_layer_count, ERR_INVALID_PARAMETER); + + VkCommandBuffer command_buffer = p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer; + + { + + //PRE Copy the image + + { //Source + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = 0; + image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + image_memory_barrier.oldLayout = src_tex->unbound_layout; + image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = src_tex->image; + image_memory_barrier.subresourceRange.aspectMask = src_tex->aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = p_src_mipmap; + image_memory_barrier.subresourceRange.levelCount = 1; + image_memory_barrier.subresourceRange.baseArrayLayer = p_src_layer; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + { //Dest + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = 0; + image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + image_memory_barrier.oldLayout = dst_tex->unbound_layout; + image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = dst_tex->image; + image_memory_barrier.subresourceRange.aspectMask = dst_tex->aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = p_dst_mipmap; + image_memory_barrier.subresourceRange.levelCount = 1; + image_memory_barrier.subresourceRange.baseArrayLayer = p_dst_layer; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + + //COPY + + { + + VkImageCopy image_copy_region; + image_copy_region.srcSubresource.aspectMask = src_tex->aspect_mask; + image_copy_region.srcSubresource.baseArrayLayer = p_src_layer; + image_copy_region.srcSubresource.layerCount = 1; + image_copy_region.srcSubresource.mipLevel = p_src_mipmap; + image_copy_region.srcOffset.x = p_from.x; + image_copy_region.srcOffset.y = p_from.y; + image_copy_region.srcOffset.z = p_from.z; + + image_copy_region.dstSubresource.aspectMask = src_tex->aspect_mask; + image_copy_region.dstSubresource.baseArrayLayer = p_dst_layer; + image_copy_region.dstSubresource.layerCount = 1; + image_copy_region.dstSubresource.mipLevel = p_dst_mipmap; + image_copy_region.dstOffset.x = p_to.x; + image_copy_region.dstOffset.y = p_to.y; + image_copy_region.dstOffset.z = p_to.z; + + image_copy_region.extent.width = p_size.x; + image_copy_region.extent.height = p_size.y; + image_copy_region.extent.depth = p_size.z; + + vkCmdCopyImage(command_buffer, src_tex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_tex->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy_region); + } + + // RESTORE LAYOUT for SRC and DST + + { //restore src + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + image_memory_barrier.newLayout = src_tex->unbound_layout; + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = src_tex->image; + image_memory_barrier.subresourceRange.aspectMask = src_tex->aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = p_src_mipmap; + image_memory_barrier.subresourceRange.levelCount = src_tex->mipmaps; + image_memory_barrier.subresourceRange.baseArrayLayer = p_src_layer; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + + { //make dst readable + + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + image_memory_barrier.newLayout = dst_tex->unbound_layout; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = dst_tex->image; + image_memory_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + image_memory_barrier.subresourceRange.baseMipLevel = p_src_mipmap; + image_memory_barrier.subresourceRange.levelCount = 1; + image_memory_barrier.subresourceRange.baseArrayLayer = p_src_layer; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + } + + return OK; +} + bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const { ERR_FAIL_INDEX_V(p_format, DATA_FORMAT_MAX, false); @@ -3152,10 +3329,29 @@ 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, Shader::PushConstant &push_constant, String *r_error) { +String RenderingDeviceVulkan::_shader_uniform_debug(RID p_shader, int p_set) { + String ret; + const Shader *shader = shader_owner.getornull(p_shader); + ERR_FAIL_COND_V(!shader, String()); + for (int i = 0; i < shader->sets.size(); i++) { + if (p_set >= 0 && i != p_set) { + continue; + } + for (int j = 0; j < shader->sets[i].uniform_info.size(); j++) { + const UniformInfo &ui = shader->sets[i].uniform_info[j]; + if (ret != String()) { + ret += "\n"; + } + ret += "Set: " + itos(i) + " Binding: " + itos(ui.binding) + " Type: " + shader_uniform_names[ui.type] + " Length: " + itos(ui.length); + } + } + return ret; +} + +bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLayoutBinding> > &bindings, Vector<Vector<UniformInfo> > &uniform_infos, const glslang::TObjectReflection &reflection, RenderingDevice::ShaderStage p_stage, Shader::PushConstant &push_constant, String *r_error) { VkDescriptorSetLayoutBinding layout_binding; - Shader::UniformInfo info; + UniformInfo info; switch (reflection.getType()->getBasicType()) { case glslang::EbtSampler: { @@ -3285,6 +3481,13 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa uint32_t set = reflection.getType()->getQualifier().hasSet() ? reflection.getType()->getQualifier().layoutSet : 0; + if (set >= MAX_UNIFORM_SETS) { + if (r_error) { + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' uses a set (" + itos(set) + ") index larger than what is supported (" + itos(MAX_UNIFORM_SETS) + ")."; + } + return false; + } + if (set >= limits.maxBoundDescriptorSets) { if (r_error) { *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' uses a set (" + itos(set) + ") index larger than what is supported by the hardware (" + itos(limits.maxBoundDescriptorSets) + ")."; @@ -3366,7 +3569,7 @@ RID RenderingDeviceVulkan::shader_create_from_source(const Vector<ShaderStageSou //descriptor layouts Vector<Vector<VkDescriptorSetLayoutBinding> > bindings; - Vector<Vector<Shader::UniformInfo> > uniform_info; + Vector<Vector<UniformInfo> > uniform_info; Shader::PushConstant push_constant; push_constant.push_constant_size = 0; push_constant.push_constants_vk_stage = 0; @@ -3451,7 +3654,7 @@ RID RenderingDeviceVulkan::shader_create_from_source(const Vector<ShaderStageSou //obtain bindings for descriptor layout program.mapIO(); - program.buildReflection(); + program.buildReflection(EShReflectionAllBlockVariables); //program.dumpReflection(); for (int j = 0; j < program.getNumUniformVariables(); j++) { @@ -3579,17 +3782,23 @@ RID RenderingDeviceVulkan::shader_create_from_source(const Vector<ShaderStageSou //sort and hash set.uniform_info.sort(); - uint32_t h = set.uniform_info.size() ? hash_djb2_one_32(0) : 0; - for (int j = 0; j < set.uniform_info.size(); j++) { - const Shader::UniformInfo &ui = set.uniform_info[j]; - h = hash_djb2_one_32(ui.type, h); - h = hash_djb2_one_32(ui.binding, h); - h = hash_djb2_one_32(ui.length, h); - h = hash_djb2_one_32(ui.stages, h); + uint32_t format = 0; //no format, default + + if (set.uniform_info.size()) { + //has data, needs an actual format; + UniformSetFormat usformat; + usformat.uniform_info = set.uniform_info; + Map<UniformSetFormat, uint32_t>::Element *E = uniform_set_format_cache.find(usformat); + if (E) { + format = E->get(); + } else { + format = uniform_set_format_cache.size() + 1; + uniform_set_format_cache.insert(usformat, format); + } } shader.sets.push_back(set); - shader.set_hashes.push_back(h); + shader.set_formats.push_back(format); } } @@ -3873,7 +4082,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, const Uniform *uniforms = p_uniforms.ptr(); uint32_t set_uniform_count = set.uniform_info.size(); - const Shader::UniformInfo *set_uniforms = set.uniform_info.ptr(); + const UniformInfo *set_uniforms = set.uniform_info.ptr(); Vector<VkWriteDescriptorSet> writes; DescriptorPoolKey pool_key; @@ -3886,7 +4095,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, Vector<RID> attachable_textures; for (uint32_t i = 0; i < set_uniform_count; i++) { - const Shader::UniformInfo &set_uniform = set_uniforms[i]; + const UniformInfo &set_uniform = set_uniforms[i]; int uniform_idx = -1; for (int j = 0; j < (int)uniform_count; j++) { if (uniforms[j].binding == set_uniform.binding) { @@ -4191,9 +4400,10 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, uniform_set.pool = pool; uniform_set.pool_key = pool_key; uniform_set.descriptor_set = descriptor_set; - uniform_set.pipeline_layout = shader->pipeline_layout; - uniform_set.hash = shader->set_hashes[p_shader_set]; + uniform_set.format = shader->set_formats[p_shader_set]; uniform_set.attachable_textures = attachable_textures; + uniform_set.shader_set = p_shader_set; + uniform_set.shader_id = p_shader; RID id = uniform_set_owner.make_rid(uniform_set); //add dependencies @@ -4592,19 +4802,22 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma VkResult err = vkCreateGraphicsPipelines(device, NULL, 1, &graphics_pipeline_create_info, NULL, &pipeline.pipeline); ERR_FAIL_COND_V(err, RID()); - pipeline.dynamic_state = p_dynamic_state_flags; - pipeline.framebuffer_format = p_framebuffer_format; - pipeline.vertex_format = p_vertex_format; - 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.set_formats = shader->set_formats; pipeline.push_constant_stages = shader->push_constant.push_constants_vk_stage; pipeline.pipeline_layout = shader->pipeline_layout; + pipeline.shader = p_shader; + pipeline.push_constant_size = shader->push_constant.push_constant_size; + +#ifdef DEBUG_ENABLED + pipeline.validation.dynamic_state = p_dynamic_state_flags; + pipeline.validation.framebuffer_format = p_framebuffer_format; + pipeline.validation.vertex_format = p_vertex_format; + pipeline.validation.uses_restart_indices = input_assembly_create_info.primitiveRestartEnable; static const uint32_t primitive_divisor[RENDER_PRIMITIVE_MAX] = { 1, 2, 1, 1, 1, 3, 1, 1, 1, 1, 1 }; - pipeline.primitive_divisor = primitive_divisor[p_render_primitive]; + pipeline.validation.primitive_divisor = primitive_divisor[p_render_primitive]; static const uint32_t primitive_minimum[RENDER_PRIMITIVE_MAX] = { 1, 2, @@ -4618,8 +4831,8 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma 3, 1, }; - pipeline.primitive_minimum = primitive_minimum[p_render_primitive]; - + pipeline.validation.primitive_minimum = primitive_minimum[p_render_primitive]; +#endif //create ID to associate with this pipeline RID id = pipeline_owner.make_rid(pipeline); //now add aall the dependencies @@ -4756,6 +4969,8 @@ Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebu Texture *texture = texture_owner.getornull(p_framebuffer->texture_ids[i]); ERR_FAIL_COND_V(!texture, ERR_BUG); attachments.push_back(texture->view); + ERR_FAIL_COND_V(texture->width != p_framebuffer->size.width, ERR_BUG); + ERR_FAIL_COND_V(texture->height != p_framebuffer->size.height, ERR_BUG); } framebuffer_create_info.attachmentCount = attachments.size(); framebuffer_create_info.pAttachments = attachments.ptr(); @@ -5082,51 +5297,97 @@ void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RI DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif const RenderPipeline *pipeline = pipeline_owner.getornull(p_render_pipeline); ERR_FAIL_COND(!pipeline); +#ifdef DEBUG_ENABLED + ERR_FAIL_COND(pipeline->validation.framebuffer_format != dl->validation.framebuffer_format); +#endif + + if (p_render_pipeline == dl->state.pipeline) { + return; //redundant state, return. + } - ERR_FAIL_COND(pipeline->framebuffer_format != dl->validation.framebuffer_format); + dl->state.pipeline = p_render_pipeline; + dl->state.pipeline_layout = pipeline->pipeline_layout; vkCmdBindPipeline(dl->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline); + if (dl->state.pipeline_shader != pipeline->shader) { + // shader changed, so descriptor sets may become incompatible. + + //go through ALL sets, and unbind them (and all those above) if the format is different + + uint32_t pcount = pipeline->set_formats.size(); //formats count in this pipeline + dl->state.set_count = MAX(dl->state.set_count, pcount); + const uint32_t *pformats = pipeline->set_formats.ptr(); //pipeline set formats + + bool sets_valid = true; //once invalid, all above become invalid + for (uint32_t i = 0; i < pcount; i++) { + //if a part of the format is different, invalidate it (and the rest) + if (!sets_valid || dl->state.sets[i].pipeline_expected_format != pformats[i]) { + dl->state.sets[i].bound = false; + dl->state.sets[i].pipeline_expected_format = pformats[i]; + sets_valid = false; + } + } + + for (uint32_t i = pcount; i < dl->state.set_count; i++) { + //unbind the ones above (not used) if exist + dl->state.sets[i].bound = false; + } + + dl->state.set_count = pcount; //update set count + + if (pipeline->push_constant_size) { + dl->state.pipeline_push_constant_stages = pipeline->push_constant_stages; +#ifdef DEBUG_ENABLED + dl->validation.pipeline_push_constant_suppplied = false; +#endif + } + } + +#ifdef DEBUG_ENABLED //update render pass pipeline info dl->validation.pipeline_active = true; - dl->validation.pipeline_dynamic_state = pipeline->dynamic_state; - dl->validation.pipeline_vertex_format = pipeline->vertex_format; - dl->validation.pipeline_uses_restart_indices = pipeline->uses_restart_indices; - dl->validation.pipeline_primitive_divisor = pipeline->primitive_divisor; - - dl->validation.pipeline_primitive_minimum = pipeline->primitive_minimum; - dl->validation.pipeline_set_hashes = pipeline->set_hashes; + dl->validation.pipeline_dynamic_state = pipeline->validation.dynamic_state; + dl->validation.pipeline_vertex_format = pipeline->validation.vertex_format; + dl->validation.pipeline_uses_restart_indices = pipeline->validation.uses_restart_indices; + dl->validation.pipeline_primitive_divisor = pipeline->validation.primitive_divisor; + dl->validation.pipeline_primitive_minimum = pipeline->validation.primitive_minimum; 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; - } +#endif } void RenderingDeviceVulkan::draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index) { - ERR_FAIL_COND_MSG(p_index >= limits.maxBoundDescriptorSets, + +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(p_index >= limits.maxBoundDescriptorSets || p_index > MAX_UNIFORM_SETS, "Attempting to bind a descriptor set (" + itos(p_index) + ") greater than what the hardware supports (" + itos(limits.maxBoundDescriptorSets) + ")."); +#endif DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); + +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif const UniformSet *uniform_set = uniform_set_owner.getornull(p_uniform_set); ERR_FAIL_COND(!uniform_set); - if ((uint32_t)dl->validation.set_hashes.size() <= p_index) { - uint32_t csize = dl->validation.set_hashes.size(); - uint32_t new_size = p_index + 1; - dl->validation.set_hashes.resize(new_size); - for (uint32_t i = csize; i < new_size; i++) { - dl->validation.set_hashes.write[i] = 0; - } + if (p_index > dl->state.set_count) { + dl->state.set_count = p_index; } + dl->state.sets[p_index].descriptor_set = uniform_set->descriptor_set; //update set pointer + dl->state.sets[p_index].bound = false; //needs rebind + dl->state.sets[p_index].uniform_set_format = uniform_set->format; + dl->state.sets[p_index].uniform_set = p_uniform_set; + +#ifdef DEBUG_ENABLED { //validate that textures bound are not attached as framebuffer bindings uint32_t attachable_count = uniform_set->attachable_textures.size(); const RID *attachable_ptr = uniform_set->attachable_textures.ptr(); @@ -5139,38 +5400,53 @@ void RenderingDeviceVulkan::draw_list_bind_uniform_set(DrawListID p_list, RID p_ } } } - - dl->validation.set_hashes.write[p_index] = uniform_set->hash; - - vkCmdBindDescriptorSets(dl->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, uniform_set->pipeline_layout, p_index, 1, &uniform_set->descriptor_set, 0, NULL); +#endif } void RenderingDeviceVulkan::draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array) { DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif const VertexArray *vertex_array = vertex_array_owner.getornull(p_vertex_array); ERR_FAIL_COND(!vertex_array); + + if (dl->state.vertex_array == p_vertex_array) { + return; //already set + } + + dl->state.vertex_array = p_vertex_array; + +#ifdef DEBUG_ENABLED dl->validation.vertex_format = vertex_array->description; dl->validation.vertex_array_size = vertex_array->vertex_count; dl->validation.vertex_max_instances_allowed = vertex_array->max_instances_allowed; - +#endif vkCmdBindVertexBuffers(dl->command_buffer, 0, vertex_array->buffers.size(), vertex_array->buffers.ptr(), vertex_array->offsets.ptr()); } void RenderingDeviceVulkan::draw_list_bind_index_array(DrawListID p_list, RID p_index_array) { DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif const IndexArray *index_array = index_array_owner.getornull(p_index_array); ERR_FAIL_COND(!index_array); + if (dl->state.index_array == p_index_array) { + return; //already set + } + + dl->state.index_array = p_index_array; +#ifdef DEBUG_ENABLED dl->validation.index_array_size = index_array->indices; dl->validation.index_array_max_index = index_array->max_index; dl->validation.index_array_offset = index_array->offset; - +#endif vkCmdBindIndexBuffer(dl->command_buffer, index_array->buffer, index_array->offset, index_array->index_type); } @@ -5187,10 +5463,15 @@ void RenderingDeviceVulkan::draw_list_set_push_constant(DrawListID p_list, void DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif + +#ifdef DEBUG_ENABLED 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); +#endif + vkCmdPushConstants(dl->command_buffer, dl->state.pipeline_layout, dl->state.pipeline_push_constant_stages, 0, p_data_size, p_data); dl->validation.pipeline_push_constant_suppplied = true; } @@ -5198,8 +5479,11 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(!dl->validation.pipeline_active, "No render pipeline was set before attempting to draw."); if (dl->validation.pipeline_vertex_format != INVALID_ID) { @@ -5219,30 +5503,39 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices 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(), - "Render pipeline requires uniform sets which were not set at the time of drawing."); - uint32_t hash_count = dl->validation.pipeline_set_hashes.size(); - const uint32_t *phashes = dl->validation.pipeline_set_hashes.ptr(); - const uint32_t *shashes = dl->validation.set_hashes.ptr(); +#endif - for (uint32_t i = 0; i < hash_count; i++) { - if (phashes[i] == 0) { - continue; //not used by pipeline, no need to check - } - if (phashes[i] != shashes[i]) { - if (shashes[i] == 0) { - ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline"); - } else { - ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ") are not the same format as required by the pipeline shader."); - } + //Bind descriptor sets + + for (uint32_t i = 0; i < dl->state.set_count; i++) { + + if (dl->state.sets[i].pipeline_expected_format == 0) { + continue; //nothing expected by this pipeline + } +#ifdef DEBUG_ENABLED + if (dl->state.sets[i].pipeline_expected_format != dl->state.sets[i].uniform_set_format) { + + if (dl->state.sets[i].uniform_set_format == 0) { + ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline"); + } else if (uniform_set_owner.owns(dl->state.sets[i].uniform_set)) { + UniformSet *us = uniform_set_owner.getornull(dl->state.sets[i].uniform_set); + ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + "):\n" + _shader_uniform_debug(us->shader_id, us->shader_set) + "\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(dl->state.pipeline_shader)); + } else { + ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(dl->state.pipeline_shader)); } } +#endif + if (!dl->state.sets[i].bound) { + //All good, see if this requires re-binding + vkCmdBindDescriptorSets(dl->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, dl->state.pipeline_layout, i, 1, &dl->state.sets[i].descriptor_set, 0, NULL); + dl->state.sets[i].bound = true; + } } if (p_use_indices) { + +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(!dl->validation.index_array_size, "Draw command requested indices, but no index buffer was set."); if (dl->validation.pipeline_vertex_format != INVALID_ID) { @@ -5253,37 +5546,42 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices ERR_FAIL_COND_MSG(dl->validation.pipeline_uses_restart_indices != dl->validation.index_buffer_uses_restart_indices, "The usage of restart indices in index buffer does not match the render primitive in the pipeline."); - +#endif uint32_t to_draw = dl->validation.index_array_size; +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(to_draw < dl->validation.pipeline_primitive_minimum, "Too few indices (" + itos(to_draw) + ") for the render primitive set in the render pipeline (" + itos(dl->validation.pipeline_primitive_minimum) + ")."); ERR_FAIL_COND_MSG((to_draw % dl->validation.pipeline_primitive_divisor) != 0, "Index amount (" + itos(to_draw) + ") must be a multiple of the amount of indices required by the render primitive (" + itos(dl->validation.pipeline_primitive_divisor) + ")."); - +#endif vkCmdDrawIndexed(dl->command_buffer, to_draw, p_instances, dl->validation.index_array_offset, 0, 0); } else { +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format == INVALID_ID, "Draw command lacks indices, but pipeline format does not use vertices."); - +#endif uint32_t to_draw = dl->validation.vertex_array_size; +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(to_draw < dl->validation.pipeline_primitive_minimum, "Too few vertices (" + itos(to_draw) + ") for the render primitive set in the render pipeline (" + itos(dl->validation.pipeline_primitive_minimum) + ")."); ERR_FAIL_COND_MSG((to_draw % dl->validation.pipeline_primitive_divisor) != 0, "Vertex amount (" + itos(to_draw) + ") must be a multiple of the amount of vertices required by the render primitive (" + itos(dl->validation.pipeline_primitive_divisor) + ")."); - +#endif vkCmdDraw(dl->command_buffer, to_draw, p_instances, 0, 0); } } void RenderingDeviceVulkan::draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) { DrawList *dl = _get_draw_list_ptr(p_list); + ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); - +#endif Rect2i rect = p_rect; rect.position += dl->viewport.position; @@ -5303,7 +5601,9 @@ void RenderingDeviceVulkan::draw_list_enable_scissor(DrawListID p_list, const Re void RenderingDeviceVulkan::draw_list_disable_scissor(DrawListID p_list) { DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif VkRect2D scissor; scissor.offset.x = dl->viewport.position.x; diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h index 3b7477c54d..2420e62aab 100644 --- a/drivers/vulkan/rendering_device_vulkan.h +++ b/drivers/vulkan/rendering_device_vulkan.h @@ -385,6 +385,74 @@ class RenderingDeviceVulkan : public RenderingDevice { /**** SHADER ****/ /****************/ + // Vulkan specifies a really complex behavior for the application + // in order to tell when descriptor sets need to be re-bound (or not). + // "When binding a descriptor set (see Descriptor Set Binding) to set + // number N, if the previously bound descriptor sets for sets zero + // through N-1 were all bound using compatible pipeline layouts, + // then performing this binding does not disturb any of the lower numbered sets. + // If, additionally, the previous bound descriptor set for set N was + // bound using a pipeline layout compatible for set N, then the bindings + // in sets numbered greater than N are also not disturbed." + // As a result, we need to figure out quickly when something is no longer "compatible". + // in order to avoid costly rebinds. + + enum { + MAX_UNIFORM_SETS = 16 + }; + + struct UniformInfo { + UniformType type; + int binding; + uint32_t stages; + int length; //size of arrays (in total elements), or ubos (in bytes * total elements) + + bool operator!=(const UniformInfo &p_info) const { + return (binding != p_info.binding || type != p_info.type || stages != p_info.stages || length != p_info.length); + } + + bool operator<(const UniformInfo &p_info) const { + if (binding != p_info.binding) { + return binding < p_info.binding; + } + if (type != p_info.type) { + return type < p_info.type; + } + if (stages != p_info.stages) { + return stages < p_info.stages; + } + return length < p_info.length; + } + }; + + struct UniformSetFormat { + Vector<UniformInfo> uniform_info; + bool operator<(const UniformSetFormat &p_format) const { + uint32_t size = uniform_info.size(); + uint32_t psize = p_format.uniform_info.size(); + + if (size != psize) { + return size < psize; + } + + const UniformInfo *infoptr = uniform_info.ptr(); + const UniformInfo *pinfoptr = p_format.uniform_info.ptr(); + + for (uint32_t i = 0; i < size; i++) { + if (infoptr[i] != pinfoptr[i]) { + return infoptr[i] < pinfoptr[i]; + } + } + + return false; + } + }; + + // Always grows, never shrinks, ensuring unique IDs, but we assume + // the amount of formats will never be a problem, as the amount of shaders + // in a game is limited. + Map<UniformSetFormat, uint32_t> uniform_set_format_cache; + // Shaders in Vulkan are just pretty much // precompiled blocks of SPIR-V bytecode. They // are most likely not really compiled to host @@ -402,25 +470,6 @@ class RenderingDeviceVulkan : public RenderingDevice { struct Shader { - struct UniformInfo { - UniformType type; - int binding; - uint32_t stages; - int length; //size of arrays (in total elements), or ubos (in bytes * total elements) - bool operator<(const UniformInfo &p_info) const { - if (type != p_info.type) { - return type < p_info.type; - } - if (binding != p_info.binding) { - return binding < p_info.binding; - } - if (stages != p_info.stages) { - return stages < p_info.stages; - } - return length < p_info.length; - } - }; - struct Set { Vector<UniformInfo> uniform_info; @@ -439,12 +488,13 @@ class RenderingDeviceVulkan : public RenderingDevice { int max_output; Vector<Set> sets; - Vector<uint32_t> set_hashes; + Vector<uint32_t> set_formats; Vector<VkPipelineShaderStageCreateInfo> pipeline_stages; 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, Shader::PushConstant &push_constant, String *r_error); + String _shader_uniform_debug(RID p_shader, int p_set = -1); + bool _uniform_add_binding(Vector<Vector<VkDescriptorSetLayoutBinding> > &bindings, Vector<Vector<UniformInfo> > &uniform_infos, const glslang::TObjectReflection &reflection, RenderingDevice::ShaderStage p_stage, Shader::PushConstant &push_constant, String *r_error); RID_Owner<Shader> shader_owner; @@ -530,12 +580,13 @@ class RenderingDeviceVulkan : public RenderingDevice { // the above restriction is not too serious. struct UniformSet { - uint32_t hash; + uint32_t format; RID shader_id; + uint32_t shader_set; DescriptorPool *pool; DescriptorPoolKey pool_key; VkDescriptorSet descriptor_set; - VkPipelineLayout pipeline_layout; //not owned, inherited from shader + //VkPipelineLayout pipeline_layout; //not owned, inherited from shader Vector<RID> attachable_textures; //used for validation }; @@ -558,18 +609,23 @@ class RenderingDeviceVulkan : public RenderingDevice { struct RenderPipeline { //Cached values for validation - FramebufferFormatID framebuffer_format; - uint32_t dynamic_state; - VertexFormatID vertex_format; - bool uses_restart_indices; - uint32_t primitive_minimum; - uint32_t primitive_divisor; - Vector<uint32_t> set_hashes; - uint32_t push_constant_size; - uint32_t push_constant_stages; +#ifdef DEBUG_ENABLED + struct Validation { + FramebufferFormatID framebuffer_format; + uint32_t dynamic_state; + VertexFormatID vertex_format; + bool uses_restart_indices; + uint32_t primitive_minimum; + uint32_t primitive_divisor; + } validation; +#endif //Actual pipeline + RID shader; + Vector<uint32_t> set_formats; VkPipelineLayout pipeline_layout; // not owned, needed for push constants VkPipeline pipeline; + uint32_t push_constant_size; + uint32_t push_constant_stages; }; RID_Owner<RenderPipeline> pipeline_owner; @@ -600,6 +656,39 @@ class RenderingDeviceVulkan : public RenderingDevice { VkCommandBuffer command_buffer; //if persistent, this is owned, otherwise it's shared with the ringbuffer Rect2i viewport; + + struct SetState { + uint32_t pipeline_expected_format; + uint32_t uniform_set_format; + VkDescriptorSet descriptor_set; + RID uniform_set; + bool bound; + SetState() { + bound = false; + pipeline_expected_format = 0; + uniform_set_format = 0; + descriptor_set = VK_NULL_HANDLE; + } + }; + + struct State { + SetState sets[MAX_UNIFORM_SETS]; + uint32_t set_count; + RID pipeline; + RID pipeline_shader; + VkPipelineLayout pipeline_layout; + RID vertex_array; + RID index_array; + uint32_t pipeline_push_constant_stages; + + State() { + set_count = 0; + pipeline_layout = VK_NULL_HANDLE; + pipeline_push_constant_stages = 0; + } + } state; +#ifdef DEBUG_ENABLED + struct Validation { bool active; //means command buffer was not closes, so you can keep adding things FramebufferFormatID framebuffer_format; @@ -612,18 +701,20 @@ class RenderingDeviceVulkan : public RenderingDevice { uint32_t index_array_size; //0 if index buffer not set uint32_t index_array_max_index; uint32_t index_array_offset; - Vector<uint32_t> set_hashes; + Vector<uint32_t> set_formats; + Vector<bool> set_bound; + Vector<RID> set_rids; //last pipeline set values bool pipeline_active; uint32_t pipeline_dynamic_state; VertexFormatID pipeline_vertex_format; + RID pipeline_shader; + uint32_t invalid_set_from; bool pipeline_uses_restart_indices; uint32_t pipeline_primitive_divisor; uint32_t pipeline_primitive_minimum; - Vector<uint32_t> pipeline_set_hashes; - VkPipelineLayout pipeline_push_constant_layout; + Vector<uint32_t> pipeline_set_formats; uint32_t pipeline_push_constant_size; - uint32_t pipeline_push_constant_stages; bool pipeline_push_constant_suppplied; Validation() { @@ -636,6 +727,7 @@ class RenderingDeviceVulkan : public RenderingDevice { index_array_size = 0; //not sent index_array_max_index = 0; //not set index_buffer_uses_restart_indices = false; + invalid_set_from = 0; //pipeline state initalize pipeline_active = false; @@ -643,10 +735,11 @@ class RenderingDeviceVulkan : public RenderingDevice { 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; + +#endif }; DrawList *draw_list; //one for regular draw lists, multiple for split. @@ -715,7 +808,7 @@ class RenderingDeviceVulkan : public RenderingDevice { public: virtual RID texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<PoolVector<uint8_t> > &p_data = Vector<PoolVector<uint8_t> >()); virtual RID texture_create_shared(const TextureView &p_view, RID p_with_texture); - virtual RID texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, int p_layer, int p_mipmap); + virtual RID texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap); virtual Error texture_update(RID p_texture, uint32_t p_layer, const PoolVector<uint8_t> &p_data, bool p_sync_with_draw = false); virtual PoolVector<uint8_t> texture_get_data(RID p_texture, uint32_t p_layer); @@ -723,6 +816,8 @@ public: virtual bool texture_is_shared(RID p_texture); virtual bool texture_is_valid(RID p_texture); + virtual Error texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, bool p_sync_with_draw = false); + /*********************/ /**** FRAMEBUFFER ****/ /*********************/ |