From 0586e184490fd132f99acb1a67c788959cfdbade 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 09b07bba13..6283b93f25 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -1215,7 +1215,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; @@ -1242,6 +1242,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; @@ -1914,6 +1921,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 c15cfc9f6f..87387ec38e 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 796e276418..990a0dc455 100644 --- a/drivers/dummy/rasterizer_dummy.h +++ b/drivers/dummy/rasterizer_dummy.h @@ -35,7 +35,7 @@ #include "core/rid_owner.h" #include "core/self_list.h" #include "scene/resources/mesh.h" -#include "servers/visual/rasterizer/rasterizer.h" +#include "servers/visual/rasterizer.h" #include "servers/visual_server.h" class RasterizerSceneDummy : public RasterizerScene { diff --git a/drivers/gles2/rasterizer_canvas_gles2.h b/drivers/gles2/rasterizer_canvas_gles2.h index ce8761b448..f6ae6a60c0 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.h +++ b/drivers/gles2/rasterizer_canvas_gles2.h @@ -32,7 +32,7 @@ #define RASTERIZERCANVASGLES2_H #include "rasterizer_storage_gles2.h" -#include "servers/visual/rasterizer/rasterizer.h" +#include "servers/visual/rasterizer.h" #include "shaders/canvas.glsl.gen.h" #include "shaders/lens_distorted.glsl.gen.h" diff --git a/drivers/gles2/rasterizer_gles2.h b/drivers/gles2/rasterizer_gles2.h index 3d0debc0ed..9a5501f13d 100644 --- a/drivers/gles2/rasterizer_gles2.h +++ b/drivers/gles2/rasterizer_gles2.h @@ -34,7 +34,7 @@ #include "rasterizer_canvas_gles2.h" #include "rasterizer_scene_gles2.h" #include "rasterizer_storage_gles2.h" -#include "servers/visual/rasterizer/rasterizer.h" +#include "servers/visual/rasterizer.h" class RasterizerGLES2 : public Rasterizer { diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h index 79e3f610ea..a6aae400ca 100644 --- a/drivers/gles2/rasterizer_storage_gles2.h +++ b/drivers/gles2/rasterizer_storage_gles2.h @@ -33,7 +33,7 @@ #include "core/pool_vector.h" #include "core/self_list.h" -#include "servers/visual/rasterizer/rasterizer.h" +#include "servers/visual/rasterizer.h" #include "servers/visual/shader_language.h" #include "shader_compiler_gles2.h" #include "shader_gles2.h" diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h index b25fbd97f0..8e7a3ae873 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.h +++ b/drivers/gles3/rasterizer_canvas_gles3.h @@ -32,7 +32,7 @@ #define RASTERIZERCANVASGLES3_H #include "rasterizer_storage_gles3.h" -#include "servers/visual/rasterizer/rasterizer.h" +#include "servers/visual/rasterizer.h" #include "shaders/canvas_shadow.glsl.gen.h" #include "shaders/lens_distorted.glsl.gen.h" diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h index 6b5ce683a4..de7c1ab7e1 100644 --- a/drivers/gles3/rasterizer_gles3.h +++ b/drivers/gles3/rasterizer_gles3.h @@ -34,7 +34,7 @@ #include "rasterizer_canvas_gles3.h" #include "rasterizer_scene_gles3.h" #include "rasterizer_storage_gles3.h" -#include "servers/visual/rasterizer/rasterizer.h" +#include "servers/visual/rasterizer.h" class RasterizerGLES3 : public Rasterizer { diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index c4e4ac87e4..54c2e2b884 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -32,7 +32,7 @@ #define RASTERIZERSTORAGEGLES3_H #include "core/self_list.h" -#include "servers/visual/rasterizer/rasterizer.h" +#include "servers/visual/rasterizer.h" #include "servers/visual/shader_language.h" #include "shader_compiler_gles3.h" #include "shader_gles3.h" diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index abbfde0b59..b2d5a3781c 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -1009,6 +1009,7 @@ uint32_t RenderingDeviceVulkan::get_compressed_image_format_pixel_rshift(DataFor uint32_t RenderingDeviceVulkan::get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmaps, uint32_t *r_blockw, uint32_t *r_blockh, uint32_t *r_depth) { + ERR_FAIL_COND_V(p_mipmaps == 0, 0); uint32_t w = p_width; uint32_t h = p_height; uint32_t d = p_depth; @@ -1559,10 +1560,14 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T if (p_format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT) { image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; } - if (p_format.usage_bits & TEXTURE_USAGE_CAN_RETRIEVE_BIT) { + if (p_format.usage_bits & TEXTURE_USAGE_CAN_COPY_FROM_BIT) { image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; } + if (p_format.usage_bits & TEXTURE_USAGE_CAN_COPY_TO_BIT) { + image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; + } + image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; image_create_info.queueFamilyIndexCount = 0; image_create_info.pQueueFamilyIndices = NULL; @@ -1866,7 +1871,7 @@ RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID return id; } -RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, int p_layer, int p_mipmap) { +RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap) { Texture *src_texture = texture_owner.getornull(p_with_texture); ERR_FAIL_COND_V(!src_texture, RID()); @@ -1879,12 +1884,18 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p //create view - Texture texture = *src_texture; + ERR_FAIL_INDEX_V(p_mipmap, src_texture->mipmaps, RID()); uint32_t array_layer_multiplier = 1; - if (texture.type == TEXTURE_TYPE_CUBE_ARRAY || texture.type == TEXTURE_TYPE_CUBE) { + if (src_texture->type == TEXTURE_TYPE_CUBE_ARRAY || src_texture->type == TEXTURE_TYPE_CUBE) { array_layer_multiplier = 6; } + ERR_FAIL_INDEX_V(p_layer, src_texture->layers * array_layer_multiplier, RID()); + + Texture texture = *src_texture; + get_image_format_required_size(texture.format, texture.width, texture.height, texture.depth, p_mipmap + 1, &texture.width, &texture.height); + texture.mipmaps = 1; + texture.layers = 1; VkImageViewCreateInfo image_view_create_info; image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; @@ -1928,7 +1939,6 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p image_view_create_info.components.b = component_swizzles[p_view.swizzle_b]; image_view_create_info.components.a = component_swizzles[p_view.swizzle_a]; - ERR_FAIL_INDEX_V(p_mipmap, texture.mipmaps, RID()); image_view_create_info.subresourceRange.baseMipLevel = p_mipmap; image_view_create_info.subresourceRange.levelCount = 1; image_view_create_info.subresourceRange.layerCount = 1; @@ -2237,8 +2247,8 @@ PoolVector 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); } } @@ -3873,7 +4082,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; @@ -3886,7 +4095,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) { @@ -4191,9 +4400,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 @@ -4592,19 +4802,22 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma VkResult err = vkCreateGraphicsPipelines(device, NULL, 1, &graphics_pipeline_create_info, NULL, &pipeline.pipeline); ERR_FAIL_COND_V(err, RID()); - pipeline.dynamic_state = p_dynamic_state_flags; - pipeline.framebuffer_format = p_framebuffer_format; - pipeline.vertex_format = p_vertex_format; - pipeline.uses_restart_indices = input_assembly_create_info.primitiveRestartEnable; - pipeline.set_hashes = shader->set_hashes; - pipeline.push_constant_size = shader->push_constant.push_constant_size; + pipeline.set_formats = shader->set_formats; pipeline.push_constant_stages = shader->push_constant.push_constants_vk_stage; pipeline.pipeline_layout = shader->pipeline_layout; + pipeline.shader = p_shader; + pipeline.push_constant_size = shader->push_constant.push_constant_size; + +#ifdef DEBUG_ENABLED + pipeline.validation.dynamic_state = p_dynamic_state_flags; + pipeline.validation.framebuffer_format = p_framebuffer_format; + pipeline.validation.vertex_format = p_vertex_format; + pipeline.validation.uses_restart_indices = input_assembly_create_info.primitiveRestartEnable; static const uint32_t primitive_divisor[RENDER_PRIMITIVE_MAX] = { 1, 2, 1, 1, 1, 3, 1, 1, 1, 1, 1 }; - pipeline.primitive_divisor = primitive_divisor[p_render_primitive]; + pipeline.validation.primitive_divisor = primitive_divisor[p_render_primitive]; static const uint32_t primitive_minimum[RENDER_PRIMITIVE_MAX] = { 1, 2, @@ -4618,8 +4831,8 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma 3, 1, }; - pipeline.primitive_minimum = primitive_minimum[p_render_primitive]; - + pipeline.validation.primitive_minimum = primitive_minimum[p_render_primitive]; +#endif //create ID to associate with this pipeline RID id = pipeline_owner.make_rid(pipeline); //now add aall the dependencies @@ -4756,6 +4969,8 @@ Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebu Texture *texture = texture_owner.getornull(p_framebuffer->texture_ids[i]); ERR_FAIL_COND_V(!texture, ERR_BUG); attachments.push_back(texture->view); + ERR_FAIL_COND_V(texture->width != p_framebuffer->size.width, ERR_BUG); + ERR_FAIL_COND_V(texture->height != p_framebuffer->size.height, ERR_BUG); } framebuffer_create_info.attachmentCount = attachments.size(); framebuffer_create_info.pAttachments = attachments.ptr(); @@ -5082,51 +5297,97 @@ void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RI DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif const RenderPipeline *pipeline = pipeline_owner.getornull(p_render_pipeline); ERR_FAIL_COND(!pipeline); +#ifdef DEBUG_ENABLED + ERR_FAIL_COND(pipeline->validation.framebuffer_format != dl->validation.framebuffer_format); +#endif - 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(); @@ -5139,38 +5400,53 @@ void RenderingDeviceVulkan::draw_list_bind_uniform_set(DrawListID p_list, RID p_ } } } - - dl->validation.set_hashes.write[p_index] = uniform_set->hash; - - vkCmdBindDescriptorSets(dl->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, uniform_set->pipeline_layout, p_index, 1, &uniform_set->descriptor_set, 0, NULL); +#endif } void RenderingDeviceVulkan::draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array) { DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif const VertexArray *vertex_array = vertex_array_owner.getornull(p_vertex_array); ERR_FAIL_COND(!vertex_array); + + if (dl->state.vertex_array == p_vertex_array) { + return; //already set + } + + dl->state.vertex_array = p_vertex_array; + +#ifdef DEBUG_ENABLED dl->validation.vertex_format = vertex_array->description; dl->validation.vertex_array_size = vertex_array->vertex_count; dl->validation.vertex_max_instances_allowed = vertex_array->max_instances_allowed; - +#endif vkCmdBindVertexBuffers(dl->command_buffer, 0, vertex_array->buffers.size(), vertex_array->buffers.ptr(), vertex_array->offsets.ptr()); } void RenderingDeviceVulkan::draw_list_bind_index_array(DrawListID p_list, RID p_index_array) { DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif const IndexArray *index_array = index_array_owner.getornull(p_index_array); ERR_FAIL_COND(!index_array); + if (dl->state.index_array == p_index_array) { + return; //already set + } + + dl->state.index_array = p_index_array; +#ifdef DEBUG_ENABLED dl->validation.index_array_size = index_array->indices; dl->validation.index_array_max_index = index_array->max_index; dl->validation.index_array_offset = index_array->offset; - +#endif vkCmdBindIndexBuffer(dl->command_buffer, index_array->buffer, index_array->offset, index_array->index_type); } @@ -5187,10 +5463,15 @@ void RenderingDeviceVulkan::draw_list_set_push_constant(DrawListID p_list, void DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif + +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(p_data_size != dl->validation.pipeline_push_constant_size, "This render pipeline requires (" + itos(dl->validation.pipeline_push_constant_size) + ") bytes of push constant data, supplied: (" + itos(p_data_size) + ")"); - - vkCmdPushConstants(dl->command_buffer, dl->validation.pipeline_push_constant_layout, dl->validation.pipeline_push_constant_stages, 0, p_data_size, p_data); +#endif + vkCmdPushConstants(dl->command_buffer, dl->state.pipeline_layout, dl->state.pipeline_push_constant_stages, 0, p_data_size, p_data); dl->validation.pipeline_push_constant_suppplied = true; } @@ -5198,8 +5479,11 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(!dl->validation.pipeline_active, "No render pipeline was set before attempting to draw."); if (dl->validation.pipeline_vertex_format != INVALID_ID) { @@ -5219,30 +5503,39 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices ERR_FAIL_COND_MSG(!dl->validation.pipeline_push_constant_suppplied, "The shader in this pipeline requires a push constant to be set before drawing, but it's not present."); } - //compare hashes - if (dl->validation.pipeline_set_hashes.size()) { - ERR_FAIL_COND_MSG(dl->validation.pipeline_set_hashes.size() > dl->validation.set_hashes.size(), - "Render pipeline requires uniform sets which were not set at the time of drawing."); - uint32_t hash_count = dl->validation.pipeline_set_hashes.size(); - const uint32_t *phashes = dl->validation.pipeline_set_hashes.ptr(); - const uint32_t *shashes = dl->validation.set_hashes.ptr(); +#endif - for (uint32_t i = 0; i < hash_count; i++) { - if (phashes[i] == 0) { - continue; //not used by pipeline, no need to check - } - if (phashes[i] != shashes[i]) { - if (shashes[i] == 0) { - ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline"); - } else { - ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ") are not the same format as required by the pipeline shader."); - } + //Bind descriptor sets + + for (uint32_t i = 0; i < dl->state.set_count; i++) { + + if (dl->state.sets[i].pipeline_expected_format == 0) { + continue; //nothing expected by this pipeline + } +#ifdef DEBUG_ENABLED + if (dl->state.sets[i].pipeline_expected_format != dl->state.sets[i].uniform_set_format) { + + if (dl->state.sets[i].uniform_set_format == 0) { + ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline"); + } else if (uniform_set_owner.owns(dl->state.sets[i].uniform_set)) { + UniformSet *us = uniform_set_owner.getornull(dl->state.sets[i].uniform_set); + ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + "):\n" + _shader_uniform_debug(us->shader_id, us->shader_set) + "\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(dl->state.pipeline_shader)); + } else { + ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(dl->state.pipeline_shader)); } } +#endif + if (!dl->state.sets[i].bound) { + //All good, see if this requires re-binding + vkCmdBindDescriptorSets(dl->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, dl->state.pipeline_layout, i, 1, &dl->state.sets[i].descriptor_set, 0, NULL); + dl->state.sets[i].bound = true; + } } if (p_use_indices) { + +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(!dl->validation.index_array_size, "Draw command requested indices, but no index buffer was set."); if (dl->validation.pipeline_vertex_format != INVALID_ID) { @@ -5253,37 +5546,42 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices ERR_FAIL_COND_MSG(dl->validation.pipeline_uses_restart_indices != dl->validation.index_buffer_uses_restart_indices, "The usage of restart indices in index buffer does not match the render primitive in the pipeline."); - +#endif uint32_t to_draw = dl->validation.index_array_size; +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(to_draw < dl->validation.pipeline_primitive_minimum, "Too few indices (" + itos(to_draw) + ") for the render primitive set in the render pipeline (" + itos(dl->validation.pipeline_primitive_minimum) + ")."); ERR_FAIL_COND_MSG((to_draw % dl->validation.pipeline_primitive_divisor) != 0, "Index amount (" + itos(to_draw) + ") must be a multiple of the amount of indices required by the render primitive (" + itos(dl->validation.pipeline_primitive_divisor) + ")."); - +#endif vkCmdDrawIndexed(dl->command_buffer, to_draw, p_instances, dl->validation.index_array_offset, 0, 0); } else { +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format == INVALID_ID, "Draw command lacks indices, but pipeline format does not use vertices."); - +#endif uint32_t to_draw = dl->validation.vertex_array_size; +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(to_draw < dl->validation.pipeline_primitive_minimum, "Too few vertices (" + itos(to_draw) + ") for the render primitive set in the render pipeline (" + itos(dl->validation.pipeline_primitive_minimum) + ")."); ERR_FAIL_COND_MSG((to_draw % dl->validation.pipeline_primitive_divisor) != 0, "Vertex amount (" + itos(to_draw) + ") must be a multiple of the amount of vertices required by the render primitive (" + itos(dl->validation.pipeline_primitive_divisor) + ")."); - +#endif vkCmdDraw(dl->command_buffer, to_draw, p_instances, 0, 0); } } void RenderingDeviceVulkan::draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) { DrawList *dl = _get_draw_list_ptr(p_list); - ERR_FAIL_COND(!dl); - 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; @@ -5303,7 +5601,9 @@ void RenderingDeviceVulkan::draw_list_enable_scissor(DrawListID p_list, const Re void RenderingDeviceVulkan::draw_list_disable_scissor(DrawListID p_list) { DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif VkRect2D scissor; scissor.offset.x = dl->viewport.position.x; diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h index 3b7477c54d..2420e62aab 100644 --- a/drivers/vulkan/rendering_device_vulkan.h +++ b/drivers/vulkan/rendering_device_vulkan.h @@ -385,6 +385,74 @@ class RenderingDeviceVulkan : public RenderingDevice { /**** SHADER ****/ /****************/ + // Vulkan specifies a really complex behavior for the application + // in order to tell when descriptor sets need to be re-bound (or not). + // "When binding a descriptor set (see Descriptor Set Binding) to set + // number N, if the previously bound descriptor sets for sets zero + // through N-1 were all bound using compatible pipeline layouts, + // then performing this binding does not disturb any of the lower numbered sets. + // If, additionally, the previous bound descriptor set for set N was + // bound using a pipeline layout compatible for set N, then the bindings + // in sets numbered greater than N are also not disturbed." + // As a result, we need to figure out quickly when something is no longer "compatible". + // in order to avoid costly rebinds. + + enum { + MAX_UNIFORM_SETS = 16 + }; + + struct UniformInfo { + UniformType type; + int binding; + uint32_t stages; + int length; //size of arrays (in total elements), or ubos (in bytes * total elements) + + bool operator!=(const UniformInfo &p_info) const { + return (binding != p_info.binding || type != p_info.type || stages != p_info.stages || length != p_info.length); + } + + bool operator<(const UniformInfo &p_info) const { + if (binding != p_info.binding) { + return binding < p_info.binding; + } + if (type != p_info.type) { + return type < p_info.type; + } + if (stages != p_info.stages) { + return stages < p_info.stages; + } + return length < p_info.length; + } + }; + + struct UniformSetFormat { + Vector 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 c68f67bbda..cde41a8f36 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 2979037adc..c2f9a0992f 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 456b0ea8b7..d2d96181f5 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 96ec7e8541..65a18830ed 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 abd8a252f8..190dbcf662 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 7e931180e9..46ca9cb6d1 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 11f30552da..fb43ab382e 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 5c6b09629f..cf16295a70 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 cfd3cea4ec..5776a45042 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 171f68783c..5999e2840e 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 9aa395db70..fca18bfea0 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 0000000000..1566fac5b0 --- /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 0000000000..ed1bc288de --- /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 d9cd19e0cb..9dd8f7ce50 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 851b891ec4..edb8007f5c 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 2c51dc7300..749d5c23ad 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 03cadb5ba4..264de6e4a1 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 5783379738..fef3418d53 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 d875738481..c2f60c08b3 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); @@ -723,6 +745,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 2c2d6e9ca0..2108d14b2e 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 789e4ca057..76b1a288e6 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 f210908e39..d4b3db60ac 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 c7a8cdaa37..558675935d 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 37290e997f..a8e1dafb47 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 0000000000..830d4d7d94 --- /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 0000000000..ea932130aa --- /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 00889f7345..63d2251465 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 c8972a34bc..400c13ba68 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 c9e2b9f820..fed2b0e79d 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 d87d40739f..c120a90314 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 5bc76afe4c..5a9d365eca 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 08d4b7dc52..2122587304 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 a4c3499359..d04cbf343a 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 4af22a4ad8..f701e3612a 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"