From ffbc9823d933e2ef84a899ac3335f51d138c7d7f Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Sat, 27 Jul 2019 10:23:24 -0300 Subject: [PATCH] Custom material support seems complete. --- core/image.cpp | 16 +- core/image.h | 3 +- drivers/dummy/rasterizer_dummy.h | 2 +- drivers/gles2/rasterizer_canvas_gles2.h | 2 +- drivers/gles2/rasterizer_gles2.h | 2 +- drivers/gles2/rasterizer_storage_gles2.h | 2 +- drivers/gles3/rasterizer_canvas_gles3.h | 2 +- drivers/gles3/rasterizer_gles3.h | 2 +- drivers/gles3/rasterizer_storage_gles3.h | 2 +- drivers/vulkan/rendering_device_vulkan.cpp | 468 ++++++++++++++---- drivers/vulkan/rendering_device_vulkan.h | 171 +++++-- gles_builders.py | 2 +- platform/android/os_android.h | 2 +- platform/iphone/os_iphone.h | 2 +- platform/javascript/os_javascript.h | 2 +- platform/osx/os_osx.h | 2 +- platform/server/os_server.h | 2 +- platform/uwp/os_uwp.h | 2 +- platform/windows/os_windows.h | 2 +- platform/x11/os_x11.cpp | 2 +- platform/x11/os_x11.h | 2 +- servers/visual/SCsub | 2 +- .../visual/{rasterizer => }/rasterizer.cpp | 0 servers/visual/{rasterizer => }/rasterizer.h | 0 .../{rasterizer => rasterizer_rd}/SCsub | 0 servers/visual/rasterizer_rd/effects_rd.cpp | 142 ++++++ servers/visual/rasterizer_rd/effects_rd.h | 87 ++++ .../rasterizer_canvas_rd.cpp | 43 +- .../rasterizer_canvas_rd.h | 18 +- .../rasterizer_rd.cpp | 0 .../rasterizer_rd.h | 8 +- .../rasterizer_scene_forward_rd.cpp | 0 .../rasterizer_scene_forward_rd.h | 2 +- .../rasterizer_storage_rd.cpp | 133 ++++- .../rasterizer_storage_rd.h | 28 +- ...render_pipeline_vertex_format_cache_rd.cpp | 3 +- .../render_pipeline_vertex_format_cache_rd.h | 0 .../shader_compiler_rd.cpp | 1 + .../shader_compiler_rd.h | 0 .../shader_rd.cpp | 11 + .../{rasterizer => rasterizer_rd}/shader_rd.h | 2 + .../shaders/SCsub | 1 + .../visual/rasterizer_rd/shaders/blur.glsl | 274 ++++++++++ .../rasterizer_rd/shaders/blur_inc.glsl | 35 ++ .../shaders/canvas.glsl | 8 +- .../shaders/canvas_occlusion.glsl | 0 .../shaders/canvas_uniforms_inc.glsl | 12 +- servers/visual/rendering_device.h | 32 +- servers/visual/visual_server_canvas.h | 2 +- servers/visual/visual_server_globals.h | 2 +- servers/visual/visual_server_raster.h | 2 +- servers/visual/visual_server_scene.h | 2 +- servers/visual/visual_server_viewport.h | 2 +- 53 files changed, 1339 insertions(+), 205 deletions(-) rename servers/visual/{rasterizer => }/rasterizer.cpp (100%) rename servers/visual/{rasterizer => }/rasterizer.h (100%) rename servers/visual/{rasterizer => rasterizer_rd}/SCsub (100%) create mode 100644 servers/visual/rasterizer_rd/effects_rd.cpp create mode 100644 servers/visual/rasterizer_rd/effects_rd.h rename servers/visual/{rasterizer => rasterizer_rd}/rasterizer_canvas_rd.cpp (98%) rename servers/visual/{rasterizer => rasterizer_rd}/rasterizer_canvas_rd.h (96%) rename servers/visual/{rasterizer => rasterizer_rd}/rasterizer_rd.cpp (100%) rename servers/visual/{rasterizer => rasterizer_rd}/rasterizer_rd.h (84%) rename servers/visual/{rasterizer => rasterizer_rd}/rasterizer_scene_forward_rd.cpp (100%) rename servers/visual/{rasterizer => rasterizer_rd}/rasterizer_scene_forward_rd.h (99%) rename servers/visual/{rasterizer => rasterizer_rd}/rasterizer_storage_rd.cpp (93%) rename servers/visual/{rasterizer => rasterizer_rd}/rasterizer_storage_rd.h (97%) rename servers/visual/{rasterizer => rasterizer_rd}/render_pipeline_vertex_format_cache_rd.cpp (97%) rename servers/visual/{rasterizer => rasterizer_rd}/render_pipeline_vertex_format_cache_rd.h (100%) rename servers/visual/{rasterizer => rasterizer_rd}/shader_compiler_rd.cpp (99%) rename servers/visual/{rasterizer => rasterizer_rd}/shader_compiler_rd.h (100%) rename servers/visual/{rasterizer => rasterizer_rd}/shader_rd.cpp (98%) rename servers/visual/{rasterizer => rasterizer_rd}/shader_rd.h (99%) rename servers/visual/{rasterizer => rasterizer_rd}/shaders/SCsub (82%) create mode 100644 servers/visual/rasterizer_rd/shaders/blur.glsl create mode 100644 servers/visual/rasterizer_rd/shaders/blur_inc.glsl rename servers/visual/{rasterizer => rasterizer_rd}/shaders/canvas.glsl (99%) rename servers/visual/{rasterizer => rasterizer_rd}/shaders/canvas_occlusion.glsl (100%) rename servers/visual/{rasterizer => rasterizer_rd}/shaders/canvas_uniforms_inc.glsl (90%) diff --git a/core/image.cpp b/core/image.cpp index 74706535b35..66a5f9e1631 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -1213,7 +1213,7 @@ void Image::flip_x() { } } -int Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps) { +int Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps, int *r_mm_width, int *r_mm_height) { int size = 0; int w = p_width; @@ -1240,6 +1240,13 @@ int Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int & size += s; + if (r_mm_width) { + *r_mm_width = bw; + } + if (r_mm_height) { + *r_mm_height = bh; + } + if (p_mipmaps >= 0 && mm == p_mipmaps) break; @@ -1912,6 +1919,13 @@ int Image::get_image_required_mipmaps(int p_width, int p_height, Format p_format return mm; } +Size2i Image::get_image_mipmap_size(int p_width, int p_height, Format p_format, int p_mipmap) { + int mm; + Size2i ret; + _get_dst_image_size(p_width, p_height, p_format, mm, p_mipmap, &ret.x, &ret.y); + return ret; +} + int Image::get_image_mipmap_offset(int p_width, int p_height, Format p_format, int p_mipmap) { if (p_mipmap <= 0) { diff --git a/core/image.h b/core/image.h index 94ee8a2c332..bb4166d30b0 100644 --- a/core/image.h +++ b/core/image.h @@ -177,7 +177,7 @@ private: _FORCE_INLINE_ void _get_mipmap_offset_and_size(int p_mipmap, int &r_offset, int &r_width, int &r_height) const; //get where the mipmap begins in data - static int _get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps = -1); + static int _get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps = -1, int *r_mm_width = NULL, int *r_mm_height = NULL); bool _can_modify(Format p_format) const; _FORCE_INLINE_ void _put_pixelb(int p_x, int p_y, uint32_t p_pixelsize, uint8_t *p_data, const uint8_t *p_pixel); @@ -290,6 +290,7 @@ public: static int get_image_data_size(int p_width, int p_height, Format p_format, bool p_mipmaps = false); static int get_image_required_mipmaps(int p_width, int p_height, Format p_format); + static Size2i get_image_mipmap_size(int p_width, int p_height, Format p_format, int p_mipmap); static int get_image_mipmap_offset(int p_width, int p_height, Format p_format, int p_mipmap); enum CompressMode { diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h index 4d2c929e83d..5d955e97a7a 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 d09e9c26c52..5df5b10f3c7 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 6306ca5e4ed..4d0d961ae4f 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 b99d7aa3eb4..b45034c6501 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 5b430d05f41..60aaf666528 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 403dba28d4d..8fa208a1aa1 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 09ce216c225..e8d75e494af 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 c7315c576bc..5eb1667b6b9 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 RenderingDeviceVulkan::texture_get_data(RID p_texture, uint3 ERR_FAIL_COND_V_MSG(tex->bound, PoolVector(), "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(), - "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(), + "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 > &bindings, Vector > &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 > &bindings, Vector > &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(VectorgetQualifier().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 > bindings; - Vector > uniform_info; + Vector > 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::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); } } @@ -3874,7 +4083,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector &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 writes; DescriptorPoolKey pool_key; @@ -3887,7 +4096,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector &p_uniforms, Vector 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) { @@ -4192,9 +4401,10 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector &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 @@ -4593,19 +4803,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, @@ -4619,8 +4832,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 @@ -4757,6 +4970,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(); @@ -5083,51 +5298,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 - ERR_FAIL_COND(pipeline->framebuffer_format != dl->validation.framebuffer_format); + if (p_render_pipeline == dl->state.pipeline) { + return; //redundant state, return. + } + + 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(); @@ -5140,38 +5401,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); } @@ -5188,10 +5464,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; } @@ -5199,8 +5480,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) { @@ -5220,30 +5504,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) { @@ -5254,37 +5547,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); - ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); + 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; @@ -5304,7 +5602,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 3b7477c54df..2420e62aabb 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 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 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 uniform_info; @@ -439,12 +488,13 @@ class RenderingDeviceVulkan : public RenderingDevice { int max_output; Vector sets; - Vector set_hashes; + Vector set_formats; Vector pipeline_stages; VkPipelineLayout pipeline_layout; }; - bool _uniform_add_binding(Vector > &bindings, Vector > &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 > &bindings, Vector > &uniform_infos, const glslang::TObjectReflection &reflection, RenderingDevice::ShaderStage p_stage, Shader::PushConstant &push_constant, String *r_error); RID_Owner 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 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 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 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 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 set_hashes; + Vector set_formats; + Vector set_bound; + Vector 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 pipeline_set_hashes; - VkPipelineLayout pipeline_push_constant_layout; + Vector 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 > &p_data = Vector >()); 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 &p_data, bool p_sync_with_draw = false); virtual PoolVector 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 ****/ /*********************/ diff --git a/gles_builders.py b/gles_builders.py index c68f67bbda8..cde41a8f363 100644 --- a/gles_builders.py +++ b/gles_builders.py @@ -591,7 +591,7 @@ def build_rd_header(filename): out_file_class = out_file_base.replace(".glsl.gen.h", "").title().replace("_", "").replace(".", "") + "ShaderRD" fd.write("\n\n") - fd.write("#include \"servers/visual/rasterizer/shader_rd.h\"\n\n\n") + fd.write("#include \"servers/visual/rasterizer_rd/shader_rd.h\"\n\n\n") fd.write("class " + out_file_class + " : public ShaderRD {\n\n") fd.write("public:\n\n") diff --git a/platform/android/os_android.h b/platform/android/os_android.h index ae11c21a423..16b5c8c3a3e 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -39,7 +39,7 @@ #include "main/input_default.h" //#include "power_android.h" #include "servers/audio_server.h" -#include "servers/visual/rasterizer/rasterizer.h" +#include "servers/visual/rasterizer.h" class GodotJavaWrapper; class GodotIOJavaWrapper; diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h index 1a604628b86..1f49062cfca 100644 --- a/platform/iphone/os_iphone.h +++ b/platform/iphone/os_iphone.h @@ -43,7 +43,7 @@ #include "ios.h" #include "main/input_default.h" #include "servers/audio_server.h" -#include "servers/visual/rasterizer/rasterizer.h" +#include "servers/visual/rasterizer.h" #include "servers/visual_server.h" class OSIPhone : public OS_Unix { diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h index 6543cf52346..7c97e302e92 100644 --- a/platform/javascript/os_javascript.h +++ b/platform/javascript/os_javascript.h @@ -35,7 +35,7 @@ #include "drivers/unix/os_unix.h" #include "main/input_default.h" #include "servers/audio_server.h" -#include "servers/visual/rasterizer/rasterizer.h" +#include "servers/visual/rasterizer.h" #include diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index 1403e17b004..78e1aa6c0ac 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -42,7 +42,7 @@ #include "main/input_default.h" #include "power_osx.h" #include "servers/audio_server.h" -#include "servers/visual/rasterizer/rasterizer.h" +#include "servers/visual/rasterizer.h" #include "servers/visual/visual_server_wrap_mt.h" #include "servers/visual_server.h" diff --git a/platform/server/os_server.h b/platform/server/os_server.h index eae1be8afc0..6d975ca7e06 100644 --- a/platform/server/os_server.h +++ b/platform/server/os_server.h @@ -43,7 +43,7 @@ #include "platform/x11/power_x11.h" #endif #include "servers/audio_server.h" -#include "servers/visual/rasterizer/rasterizer.h" +#include "servers/visual/rasterizer.h" #include "servers/visual_server.h" #undef CursorShape diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index 2adee958517..adca7d18ccd 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -41,7 +41,7 @@ #include "main/input_default.h" #include "power_uwp.h" #include "servers/audio_server.h" -#include "servers/visual/rasterizer/rasterizer.h" +#include "servers/visual/rasterizer.h" #include "servers/visual_server.h" #include diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 55707a9033f..28fec272165 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -43,7 +43,7 @@ #include "main/input_default.h" #include "power_windows.h" #include "servers/audio_server.h" -#include "servers/visual/rasterizer/rasterizer.h" +#include "servers/visual/rasterizer.h" #include "servers/visual_server.h" #ifdef XAUDIO2_ENABLED #include "drivers/xaudio2/audio_driver_xaudio2.h" diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 06de584c156..1507e146a0d 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -37,7 +37,7 @@ //#include "drivers/gles3/rasterizer_gles3.h" #include "errno.h" #include "key_mapping_x11.h" -#include "servers/visual/rasterizer/rasterizer_rd.h" +#include "servers/visual/rasterizer_rd/rasterizer_rd.h" #include "servers/visual/visual_server_raster.h" #include "servers/visual/visual_server_wrap_mt.h" diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h index deeda1f11d8..381ee2f0a90 100644 --- a/platform/x11/os_x11.h +++ b/platform/x11/os_x11.h @@ -42,7 +42,7 @@ #include "main/input_default.h" #include "power_x11.h" #include "servers/audio_server.h" -#include "servers/visual/rasterizer/rasterizer.h" +#include "servers/visual/rasterizer.h" #include "servers/visual_server.h" //#include "servers/visual/visual_server_wrap_mt.h" #include "drivers/vulkan/rendering_device_vulkan.h" diff --git a/servers/visual/SCsub b/servers/visual/SCsub index 9aa395db700..fca18bfea09 100644 --- a/servers/visual/SCsub +++ b/servers/visual/SCsub @@ -4,4 +4,4 @@ Import('env') env.add_source_files(env.servers_sources, "*.cpp") -SConscript("rasterizer/SCsub") +SConscript("rasterizer_rd/SCsub") diff --git a/servers/visual/rasterizer/rasterizer.cpp b/servers/visual/rasterizer.cpp similarity index 100% rename from servers/visual/rasterizer/rasterizer.cpp rename to servers/visual/rasterizer.cpp diff --git a/servers/visual/rasterizer/rasterizer.h b/servers/visual/rasterizer.h similarity index 100% rename from servers/visual/rasterizer/rasterizer.h rename to servers/visual/rasterizer.h diff --git a/servers/visual/rasterizer/SCsub b/servers/visual/rasterizer_rd/SCsub similarity index 100% rename from servers/visual/rasterizer/SCsub rename to servers/visual/rasterizer_rd/SCsub diff --git a/servers/visual/rasterizer_rd/effects_rd.cpp b/servers/visual/rasterizer_rd/effects_rd.cpp new file mode 100644 index 00000000000..1566fac5b0a --- /dev/null +++ b/servers/visual/rasterizer_rd/effects_rd.cpp @@ -0,0 +1,142 @@ +#include "effects_rd.h" + +RID EffectsRD::_get_uniform_set_from_texture(RID p_texture) { + + if (texture_to_uniform_set_cache.has(p_texture)) { + RID uniform_set = texture_to_uniform_set_cache[p_texture]; + if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + return uniform_set; + } + } + + Vector uniforms; + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.binding = 0; + u.ids.push_back(default_sampler); + u.ids.push_back(p_texture); + uniforms.push_back(u); + //any thing with the same configuration (one texture in binding 0 for set 0), is good + RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, blur.shader.version_get_shader(blur.shader_version, 0), 0); + + texture_to_uniform_set_cache[p_texture] = uniform_set; + + return uniform_set; +} + +void EffectsRD::copy(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_region) { + + zeromem(&blur.push_constant, sizeof(BlurPushConstant)); + + if (p_region != Rect2()) { + blur.push_constant.flags = BLUR_FLAG_USE_BLUR_SECTION; + blur.push_constant.section[0] = p_region.position.x; + blur.push_constant.section[1] = p_region.position.y; + blur.push_constant.section[2] = p_region.size.width; + blur.push_constant.section[3] = p_region.size.height; + } + + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_SIMPLY_COPY].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0); + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur.push_constant, sizeof(BlurPushConstant)); + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); +} + +void EffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, const Rect2 &p_region) { + + zeromem(&blur.push_constant, sizeof(BlurPushConstant)); + + uint32_t base_flags = 0; + if (p_region != Rect2()) { + base_flags = BLUR_FLAG_USE_BLUR_SECTION; + blur.push_constant.section[0] = p_region.position.x; + blur.push_constant.section[1] = p_region.position.y; + blur.push_constant.section[2] = p_region.size.width; + blur.push_constant.section[3] = p_region.size.height; + } + + blur.push_constant.pixel_size[0] = p_pixel_size.x; + blur.push_constant.pixel_size[1] = p_pixel_size.y; + + //HORIZONTAL + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer_half, RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_GAUSSIAN_BLUR].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer_half))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0); + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + + blur.push_constant.flags = base_flags | BLUR_FLAG_HORIZONTAL; + RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur.push_constant, sizeof(BlurPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); + + //VERTICAL + draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_GAUSSIAN_BLUR].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_rd_texture_half), 0); + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + + blur.push_constant.flags = base_flags; + RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur.push_constant, sizeof(BlurPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); +} + +EffectsRD::EffectsRD() { + + // Initialize blur + Vector blur_modes; + blur_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n"); + blur_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n"); + blur_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n#define GLOW_USE_AUTO_EXPOSURE\n"); + blur_modes.push_back("\n#define MODE_DOF_NEAR_BLUR\n#define DOF_QUALITY_LOW\n"); + blur_modes.push_back("\n#define MODE_DOF_NEAR_BLUR\n#define DOF_QUALITY_MEDIUM\n"); + blur_modes.push_back("\n#define MODE_DOF_NEAR_BLUR\n#define DOF_QUALITY_HIGH\n"); + blur_modes.push_back("\n#define MODE_DOF_NEAR_BLUR\n#define DOF_QUALITY_LOW\n#define DOF_NEAR_BLUR_MERGE\n"); + blur_modes.push_back("\n#define MODE_DOF_NEAR_BLUR\n#define DOF_QUALITY_MEDIUM\n#define DOF_NEAR_BLUR_MERGE\n"); + blur_modes.push_back("\n#define MODE_DOF_NEAR_BLUR\n#define DOF_QUALITY_HIGH\n#define DOF_NEAR_BLUR_MERGE\n"); + blur_modes.push_back("\n#define MODE_DOF_FAR_BLUR\n#define DOF_QUALITY_LOW\n"); + blur_modes.push_back("\n#define MODE_DOF_FAR_BLUR\n#define DOF_QUALITY_MEDIUM\n"); + blur_modes.push_back("\n#define MODE_DOF_FAR_BLUR\n#define DOF_QUALITY_HIGH\n"); + blur_modes.push_back("\n#define MODE_SSAO_MERGE\n"); + blur_modes.push_back("\n#define MODE_SIMPLE_COPY\n"); + + blur.shader.initialize(blur_modes); + zeromem(&blur.push_constant, sizeof(BlurPushConstant)); + blur.shader_version = blur.shader.version_create(); + + for (int i = 0; i < BLUR_MODE_MAX; i++) { + blur.pipelines[i].setup(blur.shader.version_get_shader(blur.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); + } + + RD::SamplerState sampler; + sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR; + sampler.min_filter = RD::SAMPLER_FILTER_LINEAR; + sampler.max_lod = 0; + + default_sampler = RD::get_singleton()->sampler_create(sampler); + + { //create index array for copy shaders + PoolVector pv; + pv.resize(6 * 4); + { + PoolVector::Write w = pv.write(); + int *p32 = (int *)w.ptr(); + p32[0] = 0; + p32[1] = 1; + p32[2] = 2; + p32[3] = 0; + p32[4] = 2; + p32[5] = 3; + } + index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, pv); + index_array = RD::get_singleton()->index_array_create(index_buffer, 0, 6); + } +} + +EffectsRD::~EffectsRD() { +} diff --git a/servers/visual/rasterizer_rd/effects_rd.h b/servers/visual/rasterizer_rd/effects_rd.h new file mode 100644 index 00000000000..ed1bc288de0 --- /dev/null +++ b/servers/visual/rasterizer_rd/effects_rd.h @@ -0,0 +1,87 @@ +#ifndef EFFECTS_RD_H +#define EFFECTS_RD_H + +#include "render_pipeline_vertex_format_cache_rd.h" +#include "shaders/blur.glsl.gen.h" + +class EffectsRD { + + enum BlurMode { + BLUR_MODE_GAUSSIAN_BLUR, + BLUR_MODE_GAUSSIAN_GLOW, + BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE, + BLUR_MODE_DOF_NEAR_LOW, + BLUR_MODE_DOF_NEAR_MEDIUM, + BLUR_MODE_DOF_NEAR_HIGH, + BLUR_MODE_DOF_NEAR_MERGE_LOW, + BLUR_MODE_DOF_NEAR_MERGE_MEDIUM, + BLUR_MODE_DOF_NEAR_MERGE_HIGH, + BLUR_MODE_DOF_FAR_LOW, + BLUR_MODE_DOF_FAR_MEDIUM, + BLUR_MODE_DOF_FAR_HIGH, + BLUR_MODE_SSAO_MERGE, + BLUR_MODE_SIMPLY_COPY, + BLUR_MODE_MAX, + + }; + + enum { + BLUR_FLAG_HORIZONTAL = (1 << 0), + BLUR_FLAG_USE_BLUR_SECTION = (1 << 1), + BLUR_FLAG_USE_ORTHOGONAL_PROJECTION = (1 << 2), + BLUR_FLAG_DOF_NEAR_FIRST_TAP = (1 << 3), + BLUR_FLAG_GLOW_FIRST_PASS = (1 << 4) + }; + + struct BlurPushConstant { + float section[4]; + float pixel_size[2]; + uint32_t flags; + uint32_t pad; + //glow + float glow_strength; + float glow_bloom; + float glow_hdr_threshold; + float glow_hdr_scale; + float glow_exposure; + float glow_white; + float glow_luminance_cap; + float glow_auto_exposure_grey; + //dof + float dof_begin; + float dof_end; + float dof_radius; + float dof_pad; + + float dof_dir[2]; + float camera_z_far; + float camera_z_near; + + float ssao_color[4]; + }; + + struct Blur { + BlurPushConstant push_constant; + BlurShaderRD shader; + RID shader_version; + RenderPipelineVertexFormatCacheRD pipelines[BLUR_MODE_MAX]; + + } blur; + + RID default_sampler; + RID index_buffer; + RID index_array; + + Map texture_to_uniform_set_cache; + + RID _get_uniform_set_from_texture(RID p_texture); + +public: + void copy(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_region); + void gaussian_blur(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, const Rect2 &p_region); + + EffectsRD(); + ~EffectsRD(); +}; + +#endif // EFFECTS_RD_H diff --git a/servers/visual/rasterizer/rasterizer_canvas_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp similarity index 98% rename from servers/visual/rasterizer/rasterizer_canvas_rd.cpp rename to servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp index d9cd19e0cbe..9dd8f7ce50b 100644 --- a/servers/visual/rasterizer/rasterizer_canvas_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp @@ -1303,7 +1303,7 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ } } -void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights) { +void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, RID p_screen_uniform_set) { Item *current_clip = NULL; @@ -1323,6 +1323,9 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, clear_colors); + if (p_screen_uniform_set.is_valid()) { + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_screen_uniform_set, 3); + } RID prev_material; PipelineVariants *pipeline_variants = &shader.pipeline_variants; @@ -1348,18 +1351,16 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, if (ci->material != prev_material) { - MaterialData *material_data; + MaterialData *material_data = NULL; if (ci->material.is_valid()) { material_data = (MaterialData *)storage->material_get_data(ci->material, RasterizerStorageRD::SHADER_TYPE_2D); - print_line("has material data"); } if (material_data) { - if (material_data->shader_data->version.is_valid()) { + if (material_data->shader_data->version.is_valid() && material_data->shader_data->valid) { pipeline_variants = &material_data->shader_data->pipeline_variants; if (material_data->uniform_set.is_valid()) { - print_line("bound uniform set"); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_data->uniform_set, 1); } } else { @@ -1370,7 +1371,6 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, } } - print_line("go render"); _render_item(draw_list, ci, fb_format, canvas_transform_inverse, current_clip, p_lights, pipeline_variants); prev_material = ci->material; @@ -1410,6 +1410,10 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite state_buffer.canvas_modulate[2] = p_modulate.b; state_buffer.canvas_modulate[3] = p_modulate.a; + Size2 render_target_size = storage->render_target_get_size(p_to_render_target); + state_buffer.screen_pixel_size[0] = 1.0 / render_target_size.x; + state_buffer.screen_pixel_size[1] = 1.0 / render_target_size.y; + state_buffer.time = state.time; RD::get_singleton()->buffer_update(state.canvas_state_buffer, 0, sizeof(State::Buffer), &state_buffer, true); } @@ -1480,6 +1484,7 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite Item *ci = p_item_list; Rect2 back_buffer_rect; bool backbuffer_copy = false; + RID screen_uniform_set; while (ci) { @@ -1493,19 +1498,27 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite } } - if (!material_screen_texture_found && ci->material.is_valid()) { + if (ci->material.is_valid()) { MaterialData *md = (MaterialData *)storage->material_get_data(ci->material, RasterizerStorageRD::SHADER_TYPE_2D); - if (md->shader_data->uses_screen_texture) { - backbuffer_copy = true; - back_buffer_rect = Rect2(); + if (md && md->shader_data->valid && md->shader_data->uses_screen_texture) { + if (!material_screen_texture_found) { + backbuffer_copy = true; + back_buffer_rect = Rect2(); + } + if (screen_uniform_set.is_null()) { + RID backbuffer_shader = shader.canvas_shader.version_get_shader(md->shader_data->version, 0); //any version is fine + screen_uniform_set = storage->render_target_get_back_buffer_uniform_set(p_to_render_target, backbuffer_shader); + } } } if (backbuffer_copy) { //render anything pending, including clearing if no items - _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list); + _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, screen_uniform_set); item_count = 0; + storage->render_target_copy_to_back_buffer(p_to_render_target, back_buffer_rect); + backbuffer_copy = false; material_screen_texture_found = true; //after a backbuffer copy, screen texture makes no further copies } @@ -1513,7 +1526,7 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_ite items[item_count++] = ci; if (!ci->next || item_count == MAX_RENDER_ITEMS - 1) { - _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list); + _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, screen_uniform_set); //then reset item_count = 0; } @@ -1771,7 +1784,6 @@ void RasterizerCanvasRD::occluder_polygon_set_cull_mode(RID p_occluder, VS::Canv void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) { //compile - print_line("shader set code?"); code = p_code; valid = false; ubo_size = 0; @@ -1787,7 +1799,7 @@ void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) { int light_mode = LIGHT_MODE_NORMAL; int blend_mode = BLEND_MODE_MIX; - bool uses_screen_texture = false; + uses_screen_texture = false; ShaderCompilerRD::IdentifierActions actions; @@ -1833,6 +1845,7 @@ void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) { print_line("\n**light_code:\n" + gen_code.light); #endif canvas_singleton->shader.canvas_shader.version_set_code(version, gen_code.uniforms, gen_code.vertex_global, gen_code.vertex, gen_code.fragment_global, gen_code.light, gen_code.fragment, gen_code.defines); + ERR_FAIL_COND(!canvas_singleton->shader.canvas_shader.version_is_valid(version)); ubo_size = gen_code.uniform_total_size; ubo_offsets = gen_code.uniform_offsets; @@ -2304,6 +2317,8 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { actions.base_texture_binding_index = 2; actions.texture_layout_set = 1; actions.base_uniform_string = "material."; + actions.default_filter = ShaderLanguage::FILTER_LINEAR; + actions.default_repeat = ShaderLanguage::REPEAT_DISABLE; shader.compiler.initialize(actions); } diff --git a/servers/visual/rasterizer/rasterizer_canvas_rd.h b/servers/visual/rasterizer_rd/rasterizer_canvas_rd.h similarity index 96% rename from servers/visual/rasterizer/rasterizer_canvas_rd.h rename to servers/visual/rasterizer_rd/rasterizer_canvas_rd.h index 851b891ec40..edb8007f5cc 100644 --- a/servers/visual/rasterizer/rasterizer_canvas_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_canvas_rd.h @@ -1,13 +1,13 @@ #ifndef RASTERIZER_CANVAS_RD_H #define RASTERIZER_CANVAS_RD_H -#include "servers/visual/rasterizer/rasterizer.h" -#include "servers/visual/rasterizer/rasterizer_storage_rd.h" -#include "servers/visual/rasterizer/render_pipeline_vertex_format_cache_rd.h" -#include "servers/visual/rasterizer/shader_compiler_rd.h" -#include "servers/visual/rasterizer/shaders/canvas.glsl.gen.h" -#include "servers/visual/rasterizer/shaders/canvas_occlusion.glsl.gen.h" +#include "servers/visual/rasterizer.h" +#include "servers/visual/rasterizer_rd/rasterizer_storage_rd.h" +#include "servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h" #include "servers/visual/rendering_device.h" +#include "servers/visual/rasterizer_rd/shader_compiler_rd.h" +#include "servers/visual/rasterizer_rd/shaders/canvas.glsl.gen.h" +#include "servers/visual/rasterizer_rd/shaders/canvas_occlusion.glsl.gen.h" class RasterizerCanvasRD : public RasterizerCanvas { @@ -382,8 +382,10 @@ class RasterizerCanvasRD : public RasterizerCanvas { float screen_transform[16]; float canvas_normal_transform[16]; float canvas_modulate[4]; + float screen_pixel_size[2]; float time; - float pad[3]; + float pad; + //uint32_t light_count; //uint32_t pad[3]; }; @@ -433,7 +435,7 @@ class RasterizerCanvasRD : public RasterizerCanvas { Size2i _bind_texture_binding(TextureBindingID p_binding, RenderingDevice::DrawListID p_draw_list, uint32_t &flags); void _render_item(RenderingDevice::DrawListID p_draw_list, const Item *p_item, RenderingDevice::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, PipelineVariants *p_pipeline_variants); - void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights); + void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, RID p_screen_uniform_set); _FORCE_INLINE_ void _update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4); _FORCE_INLINE_ void _update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3); diff --git a/servers/visual/rasterizer/rasterizer_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_rd.cpp similarity index 100% rename from servers/visual/rasterizer/rasterizer_rd.cpp rename to servers/visual/rasterizer_rd/rasterizer_rd.cpp diff --git a/servers/visual/rasterizer/rasterizer_rd.h b/servers/visual/rasterizer_rd/rasterizer_rd.h similarity index 84% rename from servers/visual/rasterizer/rasterizer_rd.h rename to servers/visual/rasterizer_rd/rasterizer_rd.h index 2c51dc73005..749d5c23ada 100644 --- a/servers/visual/rasterizer/rasterizer_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_rd.h @@ -2,10 +2,10 @@ #define RASTERIZER_RD_H #include "core/os/os.h" -#include "servers/visual/rasterizer/rasterizer.h" -#include "servers/visual/rasterizer/rasterizer_canvas_rd.h" -#include "servers/visual/rasterizer/rasterizer_scene_forward_rd.h" -#include "servers/visual/rasterizer/rasterizer_storage_rd.h" +#include "servers/visual/rasterizer.h" +#include "servers/visual/rasterizer_rd/rasterizer_canvas_rd.h" +#include "servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h" +#include "servers/visual/rasterizer_rd/rasterizer_storage_rd.h" class RasterizerRD : public Rasterizer { protected: RasterizerCanvasRD *canvas; diff --git a/servers/visual/rasterizer/rasterizer_scene_forward_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp similarity index 100% rename from servers/visual/rasterizer/rasterizer_scene_forward_rd.cpp rename to servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp diff --git a/servers/visual/rasterizer/rasterizer_scene_forward_rd.h b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h similarity index 99% rename from servers/visual/rasterizer/rasterizer_scene_forward_rd.h rename to servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h index 03cadb5ba48..264de6e4a18 100644 --- a/servers/visual/rasterizer/rasterizer_scene_forward_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h @@ -1,7 +1,7 @@ #ifndef RASTERIZER_SCENE_FORWARD_RD_H #define RASTERIZER_SCENE_FORWARD_RD_H -#include "servers/visual/rasterizer/rasterizer.h" +#include "servers/visual/rasterizer.h" class RasterizerSceneForwardRD : public RasterizerScene { public: diff --git a/servers/visual/rasterizer/rasterizer_storage_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp similarity index 93% rename from servers/visual/rasterizer/rasterizer_storage_rd.cpp rename to servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp index 5783379738d..fef3418d535 100644 --- a/servers/visual/rasterizer/rasterizer_storage_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp @@ -507,7 +507,7 @@ RID RasterizerStorageRD::texture_2d_create(const Ref &p_image) { rd_format.mipmaps = texture.mipmaps; rd_format.type = texture.rd_type; rd_format.samples = RD::TEXTURE_SAMPLES_1; - rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_CAN_RETRIEVE_BIT; + rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) { rd_format.shareable_formats.push_back(texture.rd_format); rd_format.shareable_formats.push_back(texture.rd_format_srgb); @@ -792,7 +792,6 @@ void RasterizerStorageRD::shader_set_code(RID p_shader, const String &p_code) { Shader *shader = shader_owner.getornull(p_shader); ERR_FAIL_COND(!shader); - print_line("yey set code?"); shader->code = p_code; String mode_string = ShaderLanguage::get_shader_type(p_code); @@ -1662,6 +1661,21 @@ void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) { RD::get_singleton()->free(rt->color); } + if (rt->backbuffer.is_valid()) { + RD::get_singleton()->free(rt->backbuffer); + rt->backbuffer = RID(); + rt->backbuffer_fb = RID(); + for (int i = 0; i < rt->backbuffer_mipmaps.size(); i++) { + //just erase copies, since the rest are erased by dependency + RD::get_singleton()->free(rt->backbuffer_mipmaps[i].mipmap_copy); + } + rt->backbuffer_mipmaps.clear(); + if (rt->backbuffer_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rt->backbuffer_uniform_set)) { + RD::get_singleton()->free(rt->backbuffer_uniform_set); + } + rt->backbuffer_uniform_set = RID(); + } + rt->framebuffer = RID(); rt->color = RID(); } @@ -1696,7 +1710,7 @@ void RasterizerStorageRD::_update_render_target(RenderTarget *rt) { rd_format.mipmaps = 1; rd_format.type = RD::TEXTURE_TYPE_2D; rd_format.samples = RD::TEXTURE_SAMPLES_1; - rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_RETRIEVE_BIT; + rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; rd_format.shareable_formats.push_back(rt->color_format); rd_format.shareable_formats.push_back(rt->color_format_srgb); } @@ -1755,6 +1769,56 @@ void RasterizerStorageRD::_update_render_target(RenderTarget *rt) { } } +void RasterizerStorageRD::_create_render_target_backbuffer(RenderTarget *rt) { + ERR_FAIL_COND(rt->backbuffer.is_valid()); + + uint32_t mipmaps_required = Image::get_image_required_mipmaps(rt->size.width, rt->size.height, Image::FORMAT_RGBA8); + RD::TextureFormat tf; + tf.format = rt->color_format; + tf.width = rt->size.width; + tf.height = rt->size.height; + tf.type = RD::TEXTURE_TYPE_2D; + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + tf.mipmaps = mipmaps_required; + + rt->backbuffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + { + Vector backbuffer_att; + RID backbuffer_fb_tex = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rt->backbuffer, 0, 0); + backbuffer_att.push_back(backbuffer_fb_tex); + rt->backbuffer_fb = RD::get_singleton()->framebuffer_create(backbuffer_att); + } + + //create mipmaps + for (uint32_t i = 1; i < mipmaps_required; i++) { + + RenderTarget::BackbufferMipmap mm; + { + mm.mipmap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rt->backbuffer, 0, i); + Vector mm_fb_at; + mm_fb_at.push_back(mm.mipmap); + mm.mipmap_fb = RD::get_singleton()->framebuffer_create(mm_fb_at); + } + + { + Size2 mm_size = Image::get_image_mipmap_size(tf.width, tf.height, Image::FORMAT_RGBA8, i); + + RD::TextureFormat mmtf = tf; + mmtf.width = mm_size.width; + mmtf.height = mm_size.height; + mmtf.mipmaps = 1; + + mm.mipmap_copy = RD::get_singleton()->texture_create(mmtf, RD::TextureView()); + Vector mm_fb_at; + mm_fb_at.push_back(mm.mipmap_copy); + mm.mipmap_copy_fb = RD::get_singleton()->framebuffer_create(mm_fb_at); + } + + rt->backbuffer_mipmaps.push_back(mm); + } +} + RID RasterizerStorageRD::render_target_create() { RenderTarget render_target; @@ -1866,6 +1930,65 @@ void RasterizerStorageRD::render_target_do_clear_request(RID p_render_target) { rt->clear_requested = false; } +void RasterizerStorageRD::render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + if (!rt->backbuffer.is_valid()) { + _create_render_target_backbuffer(rt); + } + + Rect2i region = p_region; + Rect2 blur_region; + if (region == Rect2i()) { + region.size = rt->size; + } else { + blur_region = region; + blur_region.position /= rt->size; + blur_region.size /= rt->size; + } + + //single texture copy for backbuffer + RD::get_singleton()->texture_copy(rt->color, rt->backbuffer, Vector3(region.position.x, region.position.y, 0), Vector3(region.position.x, region.position.y, 0), Vector3(region.size.x, region.size.y, 1), 0, 0, 0, 0, true); + //effects.copy(rt->color, rt->backbuffer_fb, blur_region); + + //then mipmap blur + RID prev_texture = rt->color; //use color, not backbuffer, as bb has mipmaps. + Vector2 pixel_size = Vector2(1.0 / rt->size.width, 1.0 / rt->size.height); + + for (int i = 0; i < rt->backbuffer_mipmaps.size(); i++) { + pixel_size *= 2.0; //go halfway + const RenderTarget::BackbufferMipmap &mm = rt->backbuffer_mipmaps[i]; + effects.gaussian_blur(prev_texture, mm.mipmap_copy_fb, mm.mipmap_copy, mm.mipmap_fb, pixel_size, blur_region); + prev_texture = mm.mipmap; + } +} + +RID RasterizerStorageRD::render_target_get_back_buffer_uniform_set(RID p_render_target, RID p_base_shader) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, RID()); + + if (!rt->backbuffer.is_valid()) { + _create_render_target_backbuffer(rt); + } + + if (rt->backbuffer_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rt->backbuffer_uniform_set)) { + return rt->backbuffer_uniform_set; //if still valid, return/reuse it. + } + + //create otherwise + Vector uniforms; + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 0; + u.ids.push_back(rt->backbuffer); + uniforms.push_back(u); + + rt->backbuffer_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, p_base_shader, 3); + ERR_FAIL_COND_V(!rt->backbuffer_uniform_set.is_valid(), RID()); + + return rt->backbuffer_uniform_set; +} + void RasterizerStorageRD::update_dirty_resources() { _update_queued_materials(); } @@ -1930,6 +2053,10 @@ bool RasterizerStorageRD::free(RID p_rid) { return true; } +EffectsRD *RasterizerStorageRD::get_effects() { + return &effects; +} + RasterizerStorageRD::RasterizerStorageRD() { material_update_list = NULL; diff --git a/servers/visual/rasterizer/rasterizer_storage_rd.h b/servers/visual/rasterizer_rd/rasterizer_storage_rd.h similarity index 97% rename from servers/visual/rasterizer/rasterizer_storage_rd.h rename to servers/visual/rasterizer_rd/rasterizer_storage_rd.h index 2344c54ab60..317066538e4 100644 --- a/servers/visual/rasterizer/rasterizer_storage_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_storage_rd.h @@ -2,9 +2,11 @@ #define RASTERIZER_STORAGE_RD_H #include "core/rid_owner.h" -#include "servers/visual/rasterizer/rasterizer.h" -#include "servers/visual/rasterizer/shader_compiler_rd.h" +#include "servers/visual/rasterizer.h" +#include "servers/visual/rasterizer_rd/effects_rd.h" #include "servers/visual/rendering_device.h" +#include "servers/visual/rasterizer_rd/shader_compiler_rd.h" + class RasterizerStorageRD : public RasterizerStorage { public: enum ShaderType { @@ -168,6 +170,19 @@ private: bool flags[RENDER_TARGET_FLAG_MAX]; + RID backbuffer; //used for effects + RID backbuffer_fb; + + struct BackbufferMipmap { + RID mipmap; + RID mipmap_fb; + RID mipmap_copy; + RID mipmap_copy_fb; + }; + + Vector backbuffer_mipmaps; + RID backbuffer_uniform_set; + //texture generated for this owner (nor RD). RID texture; bool was_used; @@ -181,6 +196,11 @@ private: void _clear_render_target(RenderTarget *rt); void _update_render_target(RenderTarget *rt); + void _create_render_target_backbuffer(RenderTarget *rt); + + /* EFFECTS */ + + EffectsRD effects; public: /* TEXTURE API */ @@ -687,6 +707,8 @@ public: void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value); bool render_target_was_used(RID p_render_target); void render_target_set_as_unused(RID p_render_target); + void render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region); + RID render_target_get_back_buffer_uniform_set(RID p_render_target, RID p_base_shader); virtual void render_target_request_clear(RID p_render_target, const Color &p_clear_color); virtual bool render_target_is_clear_requested(RID p_render_target); @@ -721,6 +743,8 @@ public: static RasterizerStorage *base_singleton; + EffectsRD *get_effects(); + RasterizerStorageRD(); ~RasterizerStorageRD(); }; diff --git a/servers/visual/rasterizer/render_pipeline_vertex_format_cache_rd.cpp b/servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.cpp similarity index 97% rename from servers/visual/rasterizer/render_pipeline_vertex_format_cache_rd.cpp rename to servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.cpp index 2c2d6e9ca09..2108d14b2e6 100644 --- a/servers/visual/rasterizer/render_pipeline_vertex_format_cache_rd.cpp +++ b/servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.cpp @@ -10,7 +10,7 @@ RID RenderPipelineVertexFormatCacheRD::_generate_version(RD::VertexFormatID p_ve ERR_FAIL_COND_V(pipeline.is_null(), RID()); versions = (Version *)memrealloc(versions, sizeof(Version) * (version_count + 1)); versions[version_count].framebuffer_id = p_framebuffer_format_id; - versions[version_count].vertex_id= p_vertex_format_id; + versions[version_count].vertex_id = p_vertex_format_id; versions[version_count].pipeline = pipeline; version_count++; return pipeline; @@ -33,6 +33,7 @@ void RenderPipelineVertexFormatCacheRD::_clear() { void RenderPipelineVertexFormatCacheRD::setup(RID p_shader, RD::RenderPrimitive p_primitive, const RD::PipelineRasterizationState &p_rasterization_state, RD::PipelineMultisampleState p_multisample, const RD::PipelineDepthStencilState &p_depth_stencil_state, const RD::PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags) { ERR_FAIL_COND(p_shader.is_null()); + _clear(); shader = p_shader; render_primitive = p_primitive; rasterization_state = p_rasterization_state; diff --git a/servers/visual/rasterizer/render_pipeline_vertex_format_cache_rd.h b/servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h similarity index 100% rename from servers/visual/rasterizer/render_pipeline_vertex_format_cache_rd.h rename to servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h diff --git a/servers/visual/rasterizer/shader_compiler_rd.cpp b/servers/visual/rasterizer_rd/shader_compiler_rd.cpp similarity index 99% rename from servers/visual/rasterizer/shader_compiler_rd.cpp rename to servers/visual/rasterizer_rd/shader_compiler_rd.cpp index 789e4ca0573..76b1a288e66 100644 --- a/servers/visual/rasterizer/shader_compiler_rd.cpp +++ b/servers/visual/rasterizer_rd/shader_compiler_rd.cpp @@ -681,6 +681,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge sampler_name = actions.custom_samplers[texture_uniform]; } else { if (shader->uniforms.has(texture_uniform)) { + print_line("shader from texture uniform " + itos(shader->uniforms[texture_uniform].filter) + ", " + itos(shader->uniforms[texture_uniform].repeat)); sampler_name = _get_sampler_name(shader->uniforms[texture_uniform].filter, shader->uniforms[texture_uniform].repeat); } else { bool found = false; diff --git a/servers/visual/rasterizer/shader_compiler_rd.h b/servers/visual/rasterizer_rd/shader_compiler_rd.h similarity index 100% rename from servers/visual/rasterizer/shader_compiler_rd.h rename to servers/visual/rasterizer_rd/shader_compiler_rd.h diff --git a/servers/visual/rasterizer/shader_rd.cpp b/servers/visual/rasterizer_rd/shader_rd.cpp similarity index 98% rename from servers/visual/rasterizer/shader_rd.cpp rename to servers/visual/rasterizer_rd/shader_rd.cpp index a5eaec0a62b..2a910616b54 100644 --- a/servers/visual/rasterizer/shader_rd.cpp +++ b/servers/visual/rasterizer_rd/shader_rd.cpp @@ -303,6 +303,17 @@ void ShaderRD::version_set_code(RID p_version, const String &p_uniforms, const S } } +bool ShaderRD::version_is_valid(RID p_version) { + Version *version = version_owner.getornull(p_version); + ERR_FAIL_COND_V(!version, false); + + if (version->dirty) { + _compile_version(version); + } + + return version->valid; +} + bool ShaderRD::version_free(RID p_version) { if (version_owner.owns(p_version)) { diff --git a/servers/visual/rasterizer/shader_rd.h b/servers/visual/rasterizer_rd/shader_rd.h similarity index 99% rename from servers/visual/rasterizer/shader_rd.h rename to servers/visual/rasterizer_rd/shader_rd.h index c7a8cdaa378..558675935d4 100644 --- a/servers/visual/rasterizer/shader_rd.h +++ b/servers/visual/rasterizer_rd/shader_rd.h @@ -113,6 +113,8 @@ public: return version->variants[p_variant]; } + bool version_is_valid(RID p_version); + bool version_free(RID p_version); void initialize(const Vector &p_variant_defines, const String &p_general_defines = ""); diff --git a/servers/visual/rasterizer/shaders/SCsub b/servers/visual/rasterizer_rd/shaders/SCsub similarity index 82% rename from servers/visual/rasterizer/shaders/SCsub rename to servers/visual/rasterizer_rd/shaders/SCsub index 37290e997f8..a8e1dafb473 100644 --- a/servers/visual/rasterizer/shaders/SCsub +++ b/servers/visual/rasterizer_rd/shaders/SCsub @@ -5,3 +5,4 @@ Import('env') if 'RD_GLSL' in env['BUILDERS']: env.RD_GLSL('canvas.glsl'); env.RD_GLSL('canvas_occlusion.glsl'); + env.RD_GLSL('blur.glsl'); diff --git a/servers/visual/rasterizer_rd/shaders/blur.glsl b/servers/visual/rasterizer_rd/shaders/blur.glsl new file mode 100644 index 00000000000..830d4d7d944 --- /dev/null +++ b/servers/visual/rasterizer_rd/shaders/blur.glsl @@ -0,0 +1,274 @@ +/* clang-format off */ +[vertex] +/* clang-format on */ + +#version 450 + +/* clang-format off */ +VERSION_DEFINES +/* clang-format on */ + +#include "blur_inc.glsl" + +layout(location =0) out vec2 uv_interp; + +void main() { + + vec2 base_arr[4] = vec2[](vec2(0.0,0.0),vec2(0.0,1.0),vec2(1.0,1.0),vec2(1.0,0.0)); + uv_interp = base_arr[gl_VertexIndex]; + + if (bool(blur.flags&FLAG_USE_BLUR_SECTION)) { + uv_interp = blur.section.xy + uv_interp * blur.section.zw; + } + + gl_Position = vec4( uv_interp *2.0 - 1.0, 0.0, 1.0); + +} + +/* clang-format off */ +[fragment] +/* clang-format on */ + +#version 450 + +/* clang-format off */ +VERSION_DEFINES +/* clang-format on */ + +#include "blur_inc.glsl" + +layout(location =0) in vec2 uv_interp; + +layout( set=0, binding=0 ) uniform sampler2D source_color; + +#ifdef MODE_SSAO_MERGE +layout( set=1, binding=0 ) uniform sampler2D source_ssao; +#endif + +#ifdef GLOW_USE_AUTO_EXPOSURE +layout( set=1, binding=0 ) uniform sampler2D source_auto_exposure; +#endif + + +layout(location = 0) out vec4 frag_color; + +//DOF +#if defined(MODE_DOF_FAR_BLUR) || defined(MODE_DOF_NEAR_BLUR) + +layout( set=1, binding=0 ) uniform sampler2D dof_source_depth; + +#ifdef DOF_NEAR_BLUR_MERGE +layout( set=2, binding=0 ) uniform sampler2D source_dof_original; +#endif + +#ifdef DOF_QUALITY_LOW +const int dof_kernel_size = 5; +const int dof_kernel_from = 2; +const float dof_kernel[5] = float[](0.153388, 0.221461, 0.250301, 0.221461, 0.153388); +#endif + +#ifdef DOF_QUALITY_MEDIUM +const int dof_kernel_size = 11; +const int dof_kernel_from = 5; +const float dof_kernel[11] = float[](0.055037, 0.072806, 0.090506, 0.105726, 0.116061, 0.119726, 0.116061, 0.105726, 0.090506, 0.072806, 0.055037); + +#endif + +#ifdef DOF_QUALITY_HIGH +const int dof_kernel_size = 21; +const int dof_kernel_from = 10; +const float dof_kernel[21] = float[](0.028174, 0.032676, 0.037311, 0.041944, 0.046421, 0.050582, 0.054261, 0.057307, 0.059587, 0.060998, 0.061476, 0.060998, 0.059587, 0.057307, 0.054261, 0.050582, 0.046421, 0.041944, 0.037311, 0.032676, 0.028174); +#endif + +#endif + + +void main() { + +#ifdef MODE_GAUSSIAN_BLUR + + //Simpler blur uses SIGMA2 for the gaussian kernel for a stronger effect + + if (bool(blur.flags&FLAG_HORIZONTAL)) { + + vec2 pix_size = blur.pixel_size; + pix_size *= 0.5; //reading from larger buffer, so use more samples + vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.214607; + color += texture(source_color, uv_interp + vec2(1.0, 0.0) * pix_size) * 0.189879; + color += texture(source_color, uv_interp + vec2(2.0, 0.0) * pix_size) * 0.131514; + color += texture(source_color, uv_interp + vec2(3.0, 0.0) * pix_size) * 0.071303; + color += texture(source_color, uv_interp + vec2(-1.0, 0.0) * pix_size) * 0.189879; + color += texture(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size) * 0.131514; + color += texture(source_color, uv_interp + vec2(-3.0, 0.0) * pix_size) * 0.071303; + frag_color = color; + } else { + + vec2 pix_size = blur.pixel_size; + vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.38774; + color += texture(source_color, uv_interp + vec2(0.0, 1.0) * pix_size) * 0.24477; + color += texture(source_color, uv_interp + vec2(0.0, 2.0) * pix_size) * 0.06136; + color += texture(source_color, uv_interp + vec2(0.0, -1.0) * pix_size) * 0.24477; + color += texture(source_color, uv_interp + vec2(0.0, -2.0) * pix_size) * 0.06136; + frag_color = color; + } +#endif + + + +#ifdef MODE_GAUSSIAN_GLOW + + //Glow uses larger sigma 1 for a more rounded blur effect + + if (bool(blur.flags&FLAG_HORIZONTAL)) { + + vec2 pix_size = blur.pixel_size; + pix_size *= 0.5; //reading from larger buffer, so use more samples + vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.174938; + color += texture(source_color, uv_interp + vec2(1.0, 0.0) * pix_size) * 0.165569; + color += texture(source_color, uv_interp + vec2(2.0, 0.0) * pix_size) * 0.140367; + color += texture(source_color, uv_interp + vec2(3.0, 0.0) * pix_size) * 0.106595; + color += texture(source_color, uv_interp + vec2(-1.0, 0.0) * pix_size) * 0.165569; + color += texture(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size) * 0.140367; + color += texture(source_color, uv_interp + vec2(-3.0, 0.0) * pix_size) * 0.106595; + color *= blur.glow_strength; + frag_color = color; + } else { + + vec2 pix_size = blur.pixel_size; + vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.288713; + color += texture(source_color, uv_interp + vec2(0.0, 1.0) * pix_size) * 0.233062; + color += texture(source_color, uv_interp + vec2(0.0, 2.0) * pix_size) * 0.122581; + color += texture(source_color, uv_interp + vec2(0.0, -1.0) * pix_size) * 0.233062; + color += texture(source_color, uv_interp + vec2(0.0, -2.0) * pix_size) * 0.122581; + color *= blur.glow_strength; + frag_color = color; + } + + + if (bool(blur.flags&FLAG_GLOW_FIRST_PASS)) { +#ifdef GLOW_USE_AUTO_EXPOSURE + + frag_color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / blur.glow_auto_exposure_grey; +#endif + frag_color *= blur.glow_exposure; + + float luminance = max(frag_color.r, max(frag_color.g, frag_color.b)); + float feedback = max(smoothstep(blur.glow_hdr_threshold, blur.glow_hdr_threshold + blur.glow_hdr_scale, luminance), blur.glow_bloom); + + frag_color = min(frag_color * feedback, vec4(blur.glow_luminance_cap)); + } + + +#endif + +#ifdef MODE_DOF_FAR_BLUR + + vec4 color_accum = vec4(0.0); + + float depth = texture(dof_source_depth, uv_interp, 0.0).r; + depth = depth * 2.0 - 1.0; + + if (bool(blur.flags&FLAG_USE_ORTHOGONAL_PROJECTION)) { + depth = ((depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0; + } else { + depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - depth * (blur.camera_z_far - blur.camera_z_near)); + } + + float amount = smoothstep(blur.dof_begin, blur.dof_end, depth); + float k_accum = 0.0; + + for (int i = 0; i < dof_kernel_size; i++) { + + int int_ofs = i - dof_kernel_from; + vec2 tap_uv = uv_interp + blur.dof_dir * float(int_ofs) * amount * blur.dof_radius; + + float tap_k = dof_kernel[i]; + + float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r; + tap_depth = tap_depth * 2.0 - 1.0; + + if (bool(blur.flags&FLAG_USE_ORTHOGONAL_PROJECTION)) { + + tap_depth = ((tap_depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0; + } else { + tap_depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - tap_depth * (blur.camera_z_far - blur.camera_z_near)); + } + + float tap_amount = mix(smoothstep(blur.dof_begin, blur.dof_end, tap_depth), 1.0, int_ofs == 0); + tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect + + vec4 tap_color = texture(source_color, tap_uv, 0.0) * tap_k; + + k_accum += tap_k * tap_amount; + color_accum += tap_color * tap_amount; + } + + if (k_accum > 0.0) { + color_accum /= k_accum; + } + + frag_color = color_accum; ///k_accum; + +#endif + +#ifdef MODE_DOF_NEAR_BLUR + + vec4 color_accum = vec4(0.0); + + float max_accum = 0.0; + + for (int i = 0; i < dof_kernel_size; i++) { + + int int_ofs = i - dof_kernel_from; + vec2 tap_uv = uv_interp + blur.dof_dir * float(int_ofs) * blur.dof_radius; + float ofs_influence = max(0.0, 1.0 - float(abs(int_ofs)) / float(dof_kernel_from)); + + float tap_k = dof_kernel[i]; + + vec4 tap_color = texture(source_color, tap_uv, 0.0); + + float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r; + tap_depth = tap_depth * 2.0 - 1.0; + if (bool(blur.flags&FLAG_USE_ORTHOGONAL_PROJECTION)) { + + tap_depth = ((tap_depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0; + } else { + tap_depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - tap_depth * (blur.camera_z_far - blur.camera_z_near)); + } + float tap_amount = 1.0 - smoothstep(blur.dof_end, blur.dof_begin, tap_depth); + tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect + + if (bool(blur.flags&FLAG_DOF_NEAR_FIRST_TAP)) { + tap_color.a = 1.0 - smoothstep(blur.dof_end, blur.dof_begin, tap_depth); + } + + max_accum = max(max_accum, tap_amount * ofs_influence); + + color_accum += tap_color * tap_k; + } + + color_accum.a = max(color_accum.a, sqrt(max_accum)); + +#ifdef DOF_NEAR_BLUR_MERGE + { + vec4 original = texture(source_dof_original, uv_interp, 0.0); + color_accum = mix(original, color_accum, color_accum.a); + } +#endif + + if (bool(blur.flags&FLAG_DOF_NEAR_FIRST_TAP)) { + frag_color = color_accum; + } +#endif + +#ifdef MODE_SIMPLE_COPY + vec4 color = texture(source_color, uv_interp, 0.0); + frag_color = color; +#endif + +#ifdef MODE_SSAO_MERGE + vec4 color = texture(source_color, uv_interp, 0.0); + float ssao = texture(source_ssao, uv_interp, 0.0).r; + frag_color = vec4(mix(color.rgb, color.rgb * mix(blur.ssao_color.rgb, vec3(1.0), ssao), color.a), 1.0); +#endif +} diff --git a/servers/visual/rasterizer_rd/shaders/blur_inc.glsl b/servers/visual/rasterizer_rd/shaders/blur_inc.glsl new file mode 100644 index 00000000000..ea932130aa0 --- /dev/null +++ b/servers/visual/rasterizer_rd/shaders/blur_inc.glsl @@ -0,0 +1,35 @@ +#define FLAG_HORIZONTAL (1<<0) +#define FLAG_USE_BLUR_SECTION (1<<1) +#define FLAG_USE_ORTHOGONAL_PROJECTION (1<<2) +#define FLAG_DOF_NEAR_FIRST_TAP (1<<3) +#define FLAG_GLOW_FIRST_PASS (1<<4) + +layout(push_constant, binding = 1, std430) uniform Blur { + vec4 section; + vec2 pixel_size; + uint flags; + uint pad; + //glow + float glow_strength; + float glow_bloom; + float glow_hdr_threshold; + float glow_hdr_scale; + float glow_exposure; + float glow_white; + float glow_luminance_cap; + float glow_auto_exposure_grey; + //dof + float dof_begin; + float dof_end; + float dof_radius; + float dof_pad; + + vec2 dof_dir; + float camera_z_far; + float camera_z_near; + + vec4 ssao_color; + + + +} blur; diff --git a/servers/visual/rasterizer/shaders/canvas.glsl b/servers/visual/rasterizer_rd/shaders/canvas.glsl similarity index 99% rename from servers/visual/rasterizer/shaders/canvas.glsl rename to servers/visual/rasterizer_rd/shaders/canvas.glsl index 00889f7345c..63d2251465a 100644 --- a/servers/visual/rasterizer/shaders/canvas.glsl +++ b/servers/visual/rasterizer_rd/shaders/canvas.glsl @@ -354,14 +354,8 @@ void main() { #endif -#if !defined(COLOR_USED) - //default behavior, texture by color - color *= texture(sampler2D(color_texture,texture_sampler), uv); -#endif - - uint light_count = (draw_data.flags>>FLAGS_LIGHT_COUNT_SHIFT)&0xF; //max 16 lights @@ -402,7 +396,7 @@ void main() { #if defined(SCREEN_UV_USED) - vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size; + vec2 screen_uv = gl_FragCoord.xy * canvas_data.screen_pixel_size; #else vec2 screen_uv = vec2(0.0); #endif diff --git a/servers/visual/rasterizer/shaders/canvas_occlusion.glsl b/servers/visual/rasterizer_rd/shaders/canvas_occlusion.glsl similarity index 100% rename from servers/visual/rasterizer/shaders/canvas_occlusion.glsl rename to servers/visual/rasterizer_rd/shaders/canvas_occlusion.glsl diff --git a/servers/visual/rasterizer/shaders/canvas_uniforms_inc.glsl b/servers/visual/rasterizer_rd/shaders/canvas_uniforms_inc.glsl similarity index 90% rename from servers/visual/rasterizer/shaders/canvas_uniforms_inc.glsl rename to servers/visual/rasterizer_rd/shaders/canvas_uniforms_inc.glsl index c8972a34bc9..400c13ba680 100644 --- a/servers/visual/rasterizer/shaders/canvas_uniforms_inc.glsl +++ b/servers/visual/rasterizer_rd/shaders/canvas_uniforms_inc.glsl @@ -1,5 +1,5 @@ -/* SET0: Draw Primitive */ + #define M_PI 3.14159265359 @@ -25,6 +25,14 @@ #define FLAGS_DEFAULT_NORMAL_MAP_USED (1 << 26) #define FLAGS_DEFAULT_SPECULAR_MAP_USED (1 << 27) +// In vulkan, sets should always be ordered using the following logic: +// Lower Sets: Sets that change format and layout less often +// Higher sets: Sets that change format and layout very often +// This is because changing a set for another with a different layout or format, +// invalidates all the upper ones. + +/* SET0: Draw Primitive */ + layout(push_constant, binding = 0, std430) uniform DrawData { vec2 world_x; vec2 world_y; @@ -132,6 +140,6 @@ layout(set = 2, binding = 6) uniform sampler shadow_sampler; #ifdef SCREEN_TEXTURE_USED -layout(set = 3, binding = 1) uniform texture2D screen_texture; +layout(set = 3, binding = 0) uniform texture2D screen_texture; #endif diff --git a/servers/visual/rendering_device.h b/servers/visual/rendering_device.h index c9e2b9f820f..fed2b0e79dd 100644 --- a/servers/visual/rendering_device.h +++ b/servers/visual/rendering_device.h @@ -294,8 +294,9 @@ public: TEXTURE_USAGE_STORAGE_ATOMIC_BIT = (1 << 4), TEXTURE_USAGE_CPU_READ_BIT = (1 << 5), TEXTURE_USAGE_CAN_UPDATE_BIT = (1 << 6), - TEXTURE_USAGE_CAN_RETRIEVE_BIT = (1 << 7), - TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT = (1 << 8), + TEXTURE_USAGE_CAN_COPY_FROM_BIT = (1 << 7), + TEXTURE_USAGE_CAN_COPY_TO_BIT = (1 << 8), + TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT = (1 << 9), }; enum TextureSwizzle { @@ -328,13 +329,12 @@ public: depth = 1; array_layers = 1; mipmaps = 1; - type = TEXTURE_TYPE_1D; + type = TEXTURE_TYPE_2D; samples = TEXTURE_SAMPLES_1; usage_bits = 0; } }; - struct TextureView { DataFormat format_override; TextureSwizzle swizzle_r; @@ -353,15 +353,16 @@ public: virtual RID texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector > &p_data = Vector >()) = 0; virtual RID texture_create_shared(const TextureView &p_view, RID p_with_texture) = 0; - virtual RID texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture,int p_layer,int p_mipmap) = 0; + virtual RID texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap) = 0; virtual Error texture_update(RID p_texture, uint32_t p_layer, const PoolVector &p_data, bool p_sync_with_draw = false) = 0; //this function can be used from any thread and it takes effect at the begining of the frame, unless sync with draw is used, which is used to mix updates with draw calls virtual PoolVector texture_get_data(RID p_texture, uint32_t p_layer) = 0; // CPU textures will return immediately, while GPU textures will most likely force a flush virtual bool texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const = 0; - virtual bool texture_is_shared(RID p_texture) =0; + virtual bool texture_is_shared(RID p_texture) = 0; virtual bool texture_is_valid(RID p_texture) = 0; + 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) = 0; /*********************/ /**** FRAMEBUFFER ****/ /*********************/ @@ -371,9 +372,9 @@ public: TextureSamples samples; uint32_t usage_flags; AttachmentFormat() { - format=DATA_FORMAT_R8G8B8A8_UNORM; - samples=TEXTURE_SAMPLES_1; - usage_flags=0; + format = DATA_FORMAT_R8G8B8A8_UNORM; + samples = TEXTURE_SAMPLES_1; + usage_flags = 0; } }; @@ -381,7 +382,7 @@ public: // This ID is warranted to be unique for the same formats, does not need to be freed virtual FramebufferFormatID framebuffer_format_create(const Vector &p_format) = 0; - virtual TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format) =0; + virtual TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format) = 0; virtual RID framebuffer_create(const Vector &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID) = 0; @@ -563,7 +564,7 @@ public: virtual RID uniform_set_create(const Vector &p_uniforms, RID p_shader, uint32_t p_shader_set) = 0; virtual bool uniform_set_is_valid(RID p_uniform_set) = 0; - virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size,const void *p_data, bool p_sync_with_draw = false) = 0; //this function can be used from any thread and it takes effect at the begining of the frame, unless sync with draw is used, which is used to mix updates with draw calls + virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, bool p_sync_with_draw = false) = 0; //this function can be used from any thread and it takes effect at the begining of the frame, unless sync with draw is used, which is used to mix updates with draw calls /*************************/ /**** RENDER PIPELINE ****/ @@ -824,7 +825,7 @@ public: }; 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) = 0; - virtual bool render_pipeline_is_valid(RID p_pipeline) =0; + virtual bool render_pipeline_is_valid(RID p_pipeline) = 0; /****************/ /**** SCREEN ****/ @@ -874,7 +875,6 @@ public: virtual void draw_list_end() = 0; - /***************/ /**** FREE! ****/ /***************/ @@ -912,13 +912,13 @@ public: LIMIT_MAX_VERTEX_INPUT_ATTRIBUTES, LIMIT_MAX_VERTEX_INPUT_BINDINGS, LIMIT_MAX_VERTEX_INPUT_BINDING_STRIDE, - LIMIT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT , + LIMIT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT, }; - virtual int limit_get(Limit p_limit) =0; + virtual int limit_get(Limit p_limit) = 0; //methods below not exposed, used by RenderingDeviceRD - virtual void prepare_screen_for_drawing() =0; + virtual void prepare_screen_for_drawing() = 0; virtual void finalize_frame() = 0; virtual void advance_frame() = 0; diff --git a/servers/visual/visual_server_canvas.h b/servers/visual/visual_server_canvas.h index e508d5a8b12..13c9cd1167d 100644 --- a/servers/visual/visual_server_canvas.h +++ b/servers/visual/visual_server_canvas.h @@ -31,7 +31,7 @@ #ifndef VISUALSERVERCANVAS_H #define VISUALSERVERCANVAS_H -#include "rasterizer/rasterizer.h" +#include "rasterizer.h" #include "visual_server_viewport.h" class VisualServerCanvas { diff --git a/servers/visual/visual_server_globals.h b/servers/visual/visual_server_globals.h index 6d99b3daa57..04d52aa1eb3 100644 --- a/servers/visual/visual_server_globals.h +++ b/servers/visual/visual_server_globals.h @@ -31,7 +31,7 @@ #ifndef VISUAL_SERVER_GLOBALS_H #define VISUAL_SERVER_GLOBALS_H -#include "rasterizer/rasterizer.h" +#include "rasterizer.h" class VisualServerCanvas; class VisualServerViewport; diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index f39a2fc46e6..5abb51ef4cb 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -32,7 +32,7 @@ #define VISUAL_SERVER_RASTER_H #include "core/math/octree.h" -#include "servers/visual/rasterizer/rasterizer.h" +#include "servers/visual/rasterizer.h" #include "servers/visual_server.h" #include "visual_server_canvas.h" #include "visual_server_globals.h" diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h index 0cfa993ffe0..fffa14a7428 100644 --- a/servers/visual/visual_server_scene.h +++ b/servers/visual/visual_server_scene.h @@ -31,7 +31,7 @@ #ifndef VISUALSERVERSCENE_H #define VISUALSERVERSCENE_H -#include "servers/visual/rasterizer/rasterizer.h" +#include "servers/visual/rasterizer.h" #include "core/math/geometry.h" #include "core/math/octree.h" diff --git a/servers/visual/visual_server_viewport.h b/servers/visual/visual_server_viewport.h index b727f218907..9c1248e63ae 100644 --- a/servers/visual/visual_server_viewport.h +++ b/servers/visual/visual_server_viewport.h @@ -33,7 +33,7 @@ #include "core/rid_owner.h" #include "core/self_list.h" -#include "rasterizer/rasterizer.h" +#include "rasterizer.h" #include "servers/arvr/arvr_interface.h" #include "servers/visual_server.h"