diff options
Diffstat (limited to 'drivers')
37 files changed, 2169 insertions, 1623 deletions
diff --git a/drivers/gles3/SCsub b/drivers/gles3/SCsub index 5760fd714e..506312df80 100644 --- a/drivers/gles3/SCsub +++ b/drivers/gles3/SCsub @@ -7,3 +7,4 @@ env.add_source_files(env.drivers_sources, "*.cpp") SConscript("shaders/SCsub") SConscript("storage/SCsub") SConscript("effects/SCsub") +SConscript("environment/SCsub") diff --git a/drivers/gles3/environment/SCsub b/drivers/gles3/environment/SCsub new file mode 100644 index 0000000000..91e1140b75 --- /dev/null +++ b/drivers/gles3/environment/SCsub @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +Import("env") + +env.add_source_files(env.drivers_sources, "*.cpp") diff --git a/drivers/gles3/environment/fog.cpp b/drivers/gles3/environment/fog.cpp new file mode 100644 index 0000000000..02d88f6871 --- /dev/null +++ b/drivers/gles3/environment/fog.cpp @@ -0,0 +1,66 @@ +/*************************************************************************/ +/* fog.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifdef GLES3_ENABLED + +#include "fog.h" + +using namespace GLES3; + +/* FOG */ + +RID Fog::fog_volume_allocate() { + return RID(); +} + +void Fog::fog_volume_initialize(RID p_rid) { +} + +void Fog::fog_free(RID p_rid) { +} + +void Fog::fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) { +} + +void Fog::fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) { +} + +void Fog::fog_volume_set_material(RID p_fog_volume, RID p_material) { +} + +AABB Fog::fog_volume_get_aabb(RID p_fog_volume) const { + return AABB(); +} + +RS::FogVolumeShape Fog::fog_volume_get_shape(RID p_fog_volume) const { + return RS::FOG_VOLUME_SHAPE_BOX; +} + +#endif // GLES3_ENABLED diff --git a/drivers/gles3/environment/fog.h b/drivers/gles3/environment/fog.h new file mode 100644 index 0000000000..22bf3bb017 --- /dev/null +++ b/drivers/gles3/environment/fog.h @@ -0,0 +1,62 @@ +/*************************************************************************/ +/* fog.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef FOG_GLES3_H +#define FOG_GLES3_H + +#ifdef GLES3_ENABLED + +#include "core/templates/local_vector.h" +#include "core/templates/rid_owner.h" +#include "core/templates/self_list.h" +#include "servers/rendering/environment/renderer_fog.h" + +namespace GLES3 { + +class Fog : public RendererFog { +public: + /* FOG VOLUMES */ + + virtual RID fog_volume_allocate() override; + virtual void fog_volume_initialize(RID p_rid) override; + virtual void fog_free(RID p_rid) override; + + virtual void fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) override; + virtual void fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) override; + virtual void fog_volume_set_material(RID p_fog_volume, RID p_material) override; + virtual AABB fog_volume_get_aabb(RID p_fog_volume) const override; + virtual RS::FogVolumeShape fog_volume_get_shape(RID p_fog_volume) const override; +}; + +} // namespace GLES3 + +#endif // GLES3_ENABLED + +#endif // !FOG_GLES3_H diff --git a/drivers/gles3/environment/gi.cpp b/drivers/gles3/environment/gi.cpp new file mode 100644 index 0000000000..84cdb81d35 --- /dev/null +++ b/drivers/gles3/environment/gi.cpp @@ -0,0 +1,133 @@ +/*************************************************************************/ +/* gi.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifdef GLES3_ENABLED + +#include "gi.h" + +using namespace GLES3; + +/* VOXEL GI API */ + +RID GI::voxel_gi_allocate() { + return RID(); +} + +void GI::voxel_gi_free(RID p_rid) { +} + +void GI::voxel_gi_initialize(RID p_rid) { +} + +void GI::voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) { +} + +AABB GI::voxel_gi_get_bounds(RID p_voxel_gi) const { + return AABB(); +} + +Vector3i GI::voxel_gi_get_octree_size(RID p_voxel_gi) const { + return Vector3i(); +} + +Vector<uint8_t> GI::voxel_gi_get_octree_cells(RID p_voxel_gi) const { + return Vector<uint8_t>(); +} + +Vector<uint8_t> GI::voxel_gi_get_data_cells(RID p_voxel_gi) const { + return Vector<uint8_t>(); +} + +Vector<uint8_t> GI::voxel_gi_get_distance_field(RID p_voxel_gi) const { + return Vector<uint8_t>(); +} + +Vector<int> GI::voxel_gi_get_level_counts(RID p_voxel_gi) const { + return Vector<int>(); +} + +Transform3D GI::voxel_gi_get_to_cell_xform(RID p_voxel_gi) const { + return Transform3D(); +} + +void GI::voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) { +} + +float GI::voxel_gi_get_dynamic_range(RID p_voxel_gi) const { + return 0; +} + +void GI::voxel_gi_set_propagation(RID p_voxel_gi, float p_range) { +} + +float GI::voxel_gi_get_propagation(RID p_voxel_gi) const { + return 0; +} + +void GI::voxel_gi_set_energy(RID p_voxel_gi, float p_range) { +} + +float GI::voxel_gi_get_energy(RID p_voxel_gi) const { + return 0.0; +} + +void GI::voxel_gi_set_bias(RID p_voxel_gi, float p_range) { +} + +float GI::voxel_gi_get_bias(RID p_voxel_gi) const { + return 0.0; +} + +void GI::voxel_gi_set_normal_bias(RID p_voxel_gi, float p_range) { +} + +float GI::voxel_gi_get_normal_bias(RID p_voxel_gi) const { + return 0.0; +} + +void GI::voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) { +} + +bool GI::voxel_gi_is_interior(RID p_voxel_gi) const { + return false; +} + +void GI::voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) { +} + +bool GI::voxel_gi_is_using_two_bounces(RID p_voxel_gi) const { + return false; +} + +uint32_t GI::voxel_gi_get_version(RID p_voxel_gi) const { + return 0; +} + +#endif // GLES3_ENABLED diff --git a/drivers/gles3/environment/gi.h b/drivers/gles3/environment/gi.h new file mode 100644 index 0000000000..b633520784 --- /dev/null +++ b/drivers/gles3/environment/gi.h @@ -0,0 +1,96 @@ +/*************************************************************************/ +/* gi.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef GI_GLES3_H +#define GI_GLES3_H + +#ifdef GLES3_ENABLED + +#include "core/templates/local_vector.h" +#include "core/templates/rid_owner.h" +#include "core/templates/self_list.h" +#include "servers/rendering/environment/renderer_gi.h" + +#include "platform_config.h" +#ifndef OPENGL_INCLUDE_H +#include <GLES3/gl3.h> +#else +#include OPENGL_INCLUDE_H +#endif + +namespace GLES3 { + +class GI : public RendererGI { +public: + /* VOXEL GI API */ + + virtual RID voxel_gi_allocate() override; + virtual void voxel_gi_free(RID p_rid) override; + virtual void voxel_gi_initialize(RID p_rid) override; + virtual void voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) override; + + virtual AABB voxel_gi_get_bounds(RID p_voxel_gi) const override; + virtual Vector3i voxel_gi_get_octree_size(RID p_voxel_gi) const override; + virtual Vector<uint8_t> voxel_gi_get_octree_cells(RID p_voxel_gi) const override; + virtual Vector<uint8_t> voxel_gi_get_data_cells(RID p_voxel_gi) const override; + virtual Vector<uint8_t> voxel_gi_get_distance_field(RID p_voxel_gi) const override; + + virtual Vector<int> voxel_gi_get_level_counts(RID p_voxel_gi) const override; + virtual Transform3D voxel_gi_get_to_cell_xform(RID p_voxel_gi) const override; + + virtual void voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) override; + virtual float voxel_gi_get_dynamic_range(RID p_voxel_gi) const override; + + virtual void voxel_gi_set_propagation(RID p_voxel_gi, float p_range) override; + virtual float voxel_gi_get_propagation(RID p_voxel_gi) const override; + + virtual void voxel_gi_set_energy(RID p_voxel_gi, float p_range) override; + virtual float voxel_gi_get_energy(RID p_voxel_gi) const override; + + virtual void voxel_gi_set_bias(RID p_voxel_gi, float p_range) override; + virtual float voxel_gi_get_bias(RID p_voxel_gi) const override; + + virtual void voxel_gi_set_normal_bias(RID p_voxel_gi, float p_range) override; + virtual float voxel_gi_get_normal_bias(RID p_voxel_gi) const override; + + virtual void voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) override; + virtual bool voxel_gi_is_interior(RID p_voxel_gi) const override; + + virtual void voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) override; + virtual bool voxel_gi_is_using_two_bounces(RID p_voxel_gi) const override; + + virtual uint32_t voxel_gi_get_version(RID p_voxel_gi) const override; +}; + +}; // namespace GLES3 + +#endif // GLES3_ENABLED + +#endif // !GI_GLES3_H diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 32d279a635..82f7450bc2 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -34,12 +34,12 @@ #include "core/os/os.h" #include "rasterizer_scene_gles3.h" -#include "rasterizer_storage_gles3.h" #include "core/config/project_settings.h" #include "servers/rendering/rendering_server_default.h" #include "storage/config.h" #include "storage/material_storage.h" +#include "storage/mesh_storage.h" #include "storage/texture_storage.h" #ifndef GLES_OVER_GL @@ -689,6 +689,10 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item _bind_instance_data_buffer(1); glBindVertexArray(pb->vertex_array); + if (pb->color_disabled) { + glVertexAttrib4f(RS::ARRAY_COLOR, pb->color.r, pb->color.g, pb->color.b, pb->color.a); + } + if (pb->index_buffer != 0) { glDrawElements(prim[polygon->primitive], pb->count, GL_UNSIGNED_INT, nullptr); } else { @@ -698,6 +702,11 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item state.fences[state.current_buffer] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); state.current_buffer = (state.current_buffer + 1) % state.canvas_instance_data_buffers.size(); + + if (pb->color_disabled) { + // Reset so this doesn't pollute other draw calls. + glVertexAttrib4f(RS::ARRAY_COLOR, 1.0, 1.0, 1.0, 1.0); + } } break; case Item::Command::TYPE_PRIMITIVE: { @@ -758,7 +767,6 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item GLuint multimesh_buffer = 0; uint32_t multimesh_stride = 0; uint32_t multimesh_color_offset = 0; - uint32_t multimesh_custom_data_offset = 0; bool multimesh_uses_color = false; bool multimesh_uses_custom_data = false; @@ -788,7 +796,6 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item multimesh_buffer = mesh_storage->multimesh_get_gl_buffer(multimesh); multimesh_stride = mesh_storage->multimesh_get_stride(multimesh); multimesh_color_offset = mesh_storage->multimesh_get_color_offset(multimesh); - multimesh_custom_data_offset = mesh_storage->multimesh_get_custom_data_offset(multimesh); multimesh_uses_color = mesh_storage->multimesh_uses_colors(multimesh); multimesh_uses_custom_data = mesh_storage->multimesh_uses_custom_data(multimesh); } @@ -854,22 +861,17 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item if (instance_count > 1) { // Bind instance buffers. glBindBuffer(GL_ARRAY_BUFFER, multimesh_buffer); - glEnableVertexAttribArray(5); - glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(0)); - glVertexAttribDivisor(5, 1); - glEnableVertexAttribArray(6); - glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(4 * 4)); - glVertexAttribDivisor(6, 1); - - if (multimesh_uses_color) { - glEnableVertexAttribArray(7); - glVertexAttribPointer(7, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(multimesh_color_offset * sizeof(float))); - glVertexAttribDivisor(7, 1); - } - if (multimesh_uses_custom_data) { - glEnableVertexAttribArray(8); - glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(multimesh_custom_data_offset * sizeof(float))); - glVertexAttribDivisor(8, 1); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(0)); + glVertexAttribDivisor(1, 1); + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(4 * 4)); + glVertexAttribDivisor(2, 1); + + if (multimesh_uses_color || multimesh_uses_custom_data) { + glEnableVertexAttribArray(5); + glVertexAttribIPointer(5, 4, GL_UNSIGNED_INT, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(multimesh_color_offset * sizeof(float))); + glVertexAttribDivisor(5, 1); } } @@ -1268,11 +1270,7 @@ RendererCanvasRender::PolygonID RasterizerCanvasGLES3::request_polygon(const Vec } // Next add colors - if (p_colors.size() == 1) { - glDisableVertexAttribArray(RS::ARRAY_COLOR); - Color m = p_colors[0]; - glVertexAttrib4f(RS::ARRAY_COLOR, m.r, m.g, m.b, m.a); - } else if ((uint32_t)p_colors.size() == vertex_count) { + if ((uint32_t)p_colors.size() == vertex_count) { glEnableVertexAttribArray(RS::ARRAY_COLOR); glVertexAttribPointer(RS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(base_offset * sizeof(float))); @@ -1287,7 +1285,8 @@ RendererCanvasRender::PolygonID RasterizerCanvasGLES3::request_polygon(const Vec base_offset += 4; } else { glDisableVertexAttribArray(RS::ARRAY_COLOR); - glVertexAttrib4f(RS::ARRAY_COLOR, 1.0, 1.0, 1.0, 1.0); + pb.color_disabled = true; + pb.color = p_colors.size() == 1 ? p_colors[0] : Color(1.0, 1.0, 1.0, 1.0); } if ((uint32_t)p_uvs.size() == vertex_count) { @@ -1417,9 +1416,8 @@ RasterizerCanvasGLES3 *RasterizerCanvasGLES3::get_singleton() { return singleton; } -RasterizerCanvasGLES3::RasterizerCanvasGLES3(RasterizerStorageGLES3 *p_storage) { +RasterizerCanvasGLES3::RasterizerCanvasGLES3() { singleton = this; - storage = p_storage; GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton(); GLES3::Config *config = GLES3::Config::get_singleton(); diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h index 31e82401f9..caf649aaf6 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.h +++ b/drivers/gles3/rasterizer_canvas_gles3.h @@ -34,7 +34,6 @@ #ifdef GLES3_ENABLED #include "rasterizer_scene_gles3.h" -#include "rasterizer_storage_gles3.h" #include "servers/rendering/renderer_canvas_render.h" #include "servers/rendering/renderer_compositor.h" #include "storage/material_storage.h" @@ -204,8 +203,6 @@ public: typedef void Texture; - RasterizerStorageGLES3 *storage = nullptr; - void canvas_begin(RID p_to_render_target, bool p_to_backbuffer); //virtual void draw_window_margins(int *black_margin, RID *black_image) override; @@ -238,6 +235,8 @@ public: GLuint vertex_array; GLuint index_buffer; int count; + bool color_disabled = false; + Color color; }; struct { @@ -258,7 +257,7 @@ public: void set_time(double p_time); static RasterizerCanvasGLES3 *get_singleton(); - RasterizerCanvasGLES3(RasterizerStorageGLES3 *p_storage); + RasterizerCanvasGLES3(); ~RasterizerCanvasGLES3(); }; diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index c8705dc8c8..613a7f37d9 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "rasterizer_gles3.h" +#include "storage/utilities.h" #ifdef GLES3_ENABLED @@ -99,8 +100,9 @@ void RasterizerGLES3::begin_frame(double frame_step) { canvas->set_time(time_total); scene->set_time(time_total, frame_step); - storage->info.render_final = storage->info.render; - storage->info.render.reset(); + GLES3::Utilities *utilities = GLES3::Utilities::get_singleton(); + utilities->info.render_final = utilities->info.render; + utilities->info.render.reset(); //scene->iteration(); } @@ -197,12 +199,15 @@ void RasterizerGLES3::initialize() { void RasterizerGLES3::finalize() { memdelete(scene); memdelete(canvas); - memdelete(storage); + memdelete(gi); + memdelete(fog); + memdelete(copy_effects); memdelete(light_storage); memdelete(particles_storage); memdelete(mesh_storage); memdelete(material_storage); memdelete(texture_storage); + memdelete(utilities); memdelete(config); } @@ -263,15 +268,17 @@ RasterizerGLES3::RasterizerGLES3() { // OpenGL needs to be initialized before initializing the Rasterizers config = memnew(GLES3::Config); + utilities = memnew(GLES3::Utilities); texture_storage = memnew(GLES3::TextureStorage); material_storage = memnew(GLES3::MaterialStorage); mesh_storage = memnew(GLES3::MeshStorage); particles_storage = memnew(GLES3::ParticlesStorage); light_storage = memnew(GLES3::LightStorage); copy_effects = memnew(GLES3::CopyEffects); - storage = memnew(RasterizerStorageGLES3); - canvas = memnew(RasterizerCanvasGLES3(storage)); - scene = memnew(RasterizerSceneGLES3(storage)); + gi = memnew(GLES3::GI); + fog = memnew(GLES3::Fog); + canvas = memnew(RasterizerCanvasGLES3()); + scene = memnew(RasterizerSceneGLES3()); } RasterizerGLES3::~RasterizerGLES3() { diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h index 5f1cbab849..e842b6d70c 100644 --- a/drivers/gles3/rasterizer_gles3.h +++ b/drivers/gles3/rasterizer_gles3.h @@ -34,9 +34,10 @@ #ifdef GLES3_ENABLED #include "effects/copy_effects.h" +#include "environment/fog.h" +#include "environment/gi.h" #include "rasterizer_canvas_gles3.h" #include "rasterizer_scene_gles3.h" -#include "rasterizer_storage_gles3.h" #include "servers/rendering/renderer_compositor.h" #include "storage/config.h" #include "storage/light_storage.h" @@ -44,6 +45,7 @@ #include "storage/mesh_storage.h" #include "storage/particles_storage.h" #include "storage/texture_storage.h" +#include "storage/utilities.h" class RasterizerGLES3 : public RendererCompositor { private: @@ -54,25 +56,29 @@ private: protected: GLES3::Config *config = nullptr; + GLES3::Utilities *utilities = nullptr; GLES3::TextureStorage *texture_storage = nullptr; GLES3::MaterialStorage *material_storage = nullptr; GLES3::MeshStorage *mesh_storage = nullptr; GLES3::ParticlesStorage *particles_storage = nullptr; GLES3::LightStorage *light_storage = nullptr; + GLES3::GI *gi = nullptr; + GLES3::Fog *fog = nullptr; GLES3::CopyEffects *copy_effects = nullptr; - RasterizerStorageGLES3 *storage = nullptr; RasterizerCanvasGLES3 *canvas = nullptr; RasterizerSceneGLES3 *scene = nullptr; void _blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect); public: + RendererUtilities *get_utilities() { return utilities; } RendererLightStorage *get_light_storage() { return light_storage; } RendererMaterialStorage *get_material_storage() { return material_storage; } RendererMeshStorage *get_mesh_storage() { return mesh_storage; } RendererParticlesStorage *get_particles_storage() { return particles_storage; } RendererTextureStorage *get_texture_storage() { return texture_storage; } - RendererStorage *get_storage() { return storage; } + RendererGI *get_gi() { return gi; } + RendererFog *get_fog() { return fog; } RendererCanvasRender *get_canvas() { return canvas; } RendererSceneRender *get_scene() { return scene; } diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 7ce1300d07..eee303a2ca 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -33,6 +33,9 @@ #include "core/templates/sort_array.h" #include "servers/rendering/rendering_server_default.h" #include "storage/config.h" +#include "storage/light_storage.h" +#include "storage/mesh_storage.h" +#include "storage/texture_storage.h" #ifdef GLES3_ENABLED @@ -45,7 +48,7 @@ RasterizerSceneGLES3 *RasterizerSceneGLES3::get_singleton() { } RendererSceneRender::GeometryInstance *RasterizerSceneGLES3::geometry_instance_create(RID p_base) { - RS::InstanceType type = storage->get_base_type(p_base); + RS::InstanceType type = RSG::utilities->get_base_type(p_base); ERR_FAIL_COND_V(!((1 << type) & RS::INSTANCE_GEOMETRY_MASK), nullptr); GeometryInstanceGLES3 *ginstance = geometry_instance_alloc.alloc(); @@ -285,16 +288,16 @@ void RasterizerSceneGLES3::_update_dirty_geometry_instances() { } } -void RasterizerSceneGLES3::_geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker) { +void RasterizerSceneGLES3::_geometry_instance_dependency_changed(Dependency::DependencyChangedNotification p_notification, DependencyTracker *p_tracker) { switch (p_notification) { - case RendererStorage::DEPENDENCY_CHANGED_MATERIAL: - case RendererStorage::DEPENDENCY_CHANGED_MESH: - case RendererStorage::DEPENDENCY_CHANGED_PARTICLES: - case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH: - case RendererStorage::DEPENDENCY_CHANGED_SKELETON_DATA: { + case Dependency::DEPENDENCY_CHANGED_MATERIAL: + case Dependency::DEPENDENCY_CHANGED_MESH: + case Dependency::DEPENDENCY_CHANGED_PARTICLES: + case Dependency::DEPENDENCY_CHANGED_MULTIMESH: + case Dependency::DEPENDENCY_CHANGED_SKELETON_DATA: { static_cast<RasterizerSceneGLES3 *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata)); } break; - case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES: { + case Dependency::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES: { GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_tracker->userdata); if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) { ginstance->instance_count = GLES3::MeshStorage::get_singleton()->multimesh_get_instances_to_draw(ginstance->data->base); @@ -306,7 +309,7 @@ void RasterizerSceneGLES3::_geometry_instance_dependency_changed(RendererStorage } } -void RasterizerSceneGLES3::_geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker) { +void RasterizerSceneGLES3::_geometry_instance_dependency_deleted(const RID &p_dependency, DependencyTracker *p_tracker) { static_cast<RasterizerSceneGLES3 *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata)); } @@ -376,7 +379,7 @@ void RasterizerSceneGLES3::_geometry_instance_add_surface_with_material(Geometry sdcache->surface_index = p_surface; if (ginstance->data->dirty_dependencies) { - storage->base_update_dependency(p_mesh, &ginstance->data->dependency_tracker); + RSG::utilities->base_update_dependency(p_mesh, &ginstance->data->dependency_tracker); } //shadow @@ -491,7 +494,7 @@ void RasterizerSceneGLES3::_geometry_instance_update(GeometryInstance *p_geometr } } - ginstance->instance_count = 1; + ginstance->instance_count = -1; } break; @@ -1310,10 +1313,10 @@ void RasterizerSceneGLES3::camera_effects_set_dof_blur(RID p_camera_effects, boo void RasterizerSceneGLES3::camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) { } -void RasterizerSceneGLES3::shadows_quality_set(RS::ShadowQuality p_quality) { +void RasterizerSceneGLES3::positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) { } -void RasterizerSceneGLES3::directional_shadow_quality_set(RS::ShadowQuality p_quality) { +void RasterizerSceneGLES3::directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) { } RID RasterizerSceneGLES3::light_instance_create(RID p_light) { @@ -1609,10 +1612,10 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da correction.set_depth_correction(p_flip_y); CameraMatrix projection = correction * p_render_data->cam_projection; //store camera into ubo - RasterizerStorageGLES3::store_camera(projection, scene_state.ubo.projection_matrix); - RasterizerStorageGLES3::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix); - RasterizerStorageGLES3::store_transform(p_render_data->cam_transform, scene_state.ubo.inv_view_matrix); - RasterizerStorageGLES3::store_transform(p_render_data->inv_cam_transform, scene_state.ubo.view_matrix); + GLES3::MaterialStorage::store_camera(projection, scene_state.ubo.projection_matrix); + GLES3::MaterialStorage::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix); + GLES3::MaterialStorage::store_transform(p_render_data->cam_transform, scene_state.ubo.inv_view_matrix); + GLES3::MaterialStorage::store_transform(p_render_data->inv_cam_transform, scene_state.ubo.view_matrix); scene_state.ubo.directional_light_count = p_render_data->directional_light_count; @@ -1659,7 +1662,7 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da Basis sky_transform = env->sky_orientation; sky_transform = sky_transform.inverse() * p_render_data->cam_transform.basis; - RasterizerStorageGLES3::store_transform_3x3(sky_transform, scene_state.ubo.radiance_inverse_xform); + GLES3::MaterialStorage::store_transform_3x3(sky_transform, scene_state.ubo.radiance_inverse_xform); scene_state.ubo.use_ambient_cubemap = (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ambient_src == RS::ENV_AMBIENT_SOURCE_SKY; scene_state.ubo.use_ambient_light = scene_state.ubo.use_ambient_cubemap || ambient_src == RS::ENV_AMBIENT_SOURCE_COLOR; } @@ -1902,7 +1905,7 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b glBindBuffer(GL_UNIFORM_BUFFER, 0); } -void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RendererScene::RenderInfo *r_render_info) { +void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RendererScene::RenderInfo *r_render_info) { GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); GLES3::Config *config = GLES3::Config::get_singleton(); RENDER_TIMESTAMP("Setup 3D Scene"); @@ -1923,11 +1926,11 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData * render_data.cam_transform = p_camera_data->main_transform; render_data.inv_cam_transform = render_data.cam_transform.affine_inverse(); render_data.cam_projection = p_camera_data->main_projection; - render_data.view_projection[0] = p_camera_data->main_projection; render_data.cam_orthogonal = p_camera_data->is_orthogonal; render_data.view_count = p_camera_data->view_count; for (uint32_t v = 0; v < p_camera_data->view_count; v++) { + render_data.view_eye_offset[v] = p_camera_data->view_offset[v].origin; render_data.view_projection[v] = p_camera_data->view_projection[v]; } @@ -1974,7 +1977,7 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData * if (p_render_buffers.is_valid()) { clear_color = texture_storage->render_target_get_clear_request_color(rb->render_target); } else { - clear_color = storage->get_default_clear_color(); + clear_color = texture_storage->get_default_clear_color(); } Environment *env = environment_owner.get_or_null(p_environment); @@ -2200,6 +2203,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, GLES3::SceneMaterialData *prev_material_data = nullptr; GLES3::SceneShaderData *prev_shader = nullptr; GeometryInstanceGLES3 *prev_inst = nullptr; + SceneShaderGLES3::ShaderVariant prev_variant = SceneShaderGLES3::ShaderVariant::MODE_COLOR; SceneShaderGLES3::ShaderVariant shader_variant = SceneShaderGLES3::MODE_COLOR; // Assigned to silence wrong -Wmaybe-initialized. @@ -2386,12 +2390,11 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, prev_vertex_array_gl = vertex_array_gl; } - bool use_index_buffer = false; + bool use_index_buffer = index_array_gl != 0; if (prev_index_array_gl != index_array_gl) { if (index_array_gl != 0) { // Bind index each time so we can use LODs glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_array_gl); - use_index_buffer = true; } prev_index_array_gl = index_array_gl; } @@ -2406,8 +2409,13 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, prev_material_data = material_data; } - if (prev_shader != shader) { - material_storage->shaders.scene_shader.version_bind_shader(shader->version, shader_variant); + SceneShaderGLES3::ShaderVariant instance_variant = shader_variant; + if (inst->instance_count > 0) { + instance_variant = SceneShaderGLES3::ShaderVariant(1 + int(shader_variant)); + } + + if (prev_shader != shader || prev_variant != instance_variant) { + material_storage->shaders.scene_shader.version_bind_shader(shader->version, instance_variant); float opaque_prepass_threshold = 0.0; if (p_pass_mode == PASS_MODE_DEPTH) { opaque_prepass_threshold = 0.99; @@ -2415,33 +2423,69 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, opaque_prepass_threshold = 0.1; } - material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OPAQUE_PREPASS_THRESHOLD, opaque_prepass_threshold, shader->version, shader_variant); + material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OPAQUE_PREPASS_THRESHOLD, opaque_prepass_threshold, shader->version, instance_variant); prev_shader = shader; + prev_variant = instance_variant; } - if (prev_inst != inst) { + if (prev_inst != inst || prev_shader != shader || prev_variant != instance_variant) { // Rebind the light indices. - material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OMNI_LIGHT_COUNT, inst->omni_light_count, shader->version, shader_variant); - material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::SPOT_LIGHT_COUNT, inst->spot_light_count, shader->version, shader_variant); + material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OMNI_LIGHT_COUNT, inst->omni_light_count, shader->version, instance_variant); + material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::SPOT_LIGHT_COUNT, inst->spot_light_count, shader->version, instance_variant); if (inst->omni_light_count) { - glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::OMNI_LIGHT_INDICES, shader->version, shader_variant), inst->omni_light_count, inst->omni_light_gl_cache.ptr()); + glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::OMNI_LIGHT_INDICES, shader->version, instance_variant), inst->omni_light_count, inst->omni_light_gl_cache.ptr()); } if (inst->spot_light_count) { - glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::SPOT_LIGHT_INDICES, shader->version, shader_variant), inst->spot_light_count, inst->spot_light_gl_cache.ptr()); + glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::SPOT_LIGHT_INDICES, shader->version, instance_variant), inst->spot_light_count, inst->spot_light_gl_cache.ptr()); } prev_inst = inst; } - material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, world_transform, shader->version, shader_variant); - - if (use_index_buffer) { - glDrawElements(primitive_gl, mesh_storage->mesh_surface_get_vertices_drawn_count(mesh_surface), mesh_storage->mesh_surface_get_index_type(mesh_surface), 0); + material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, world_transform, shader->version, instance_variant); + if (inst->instance_count > 0) { + // Using MultiMesh. + // Bind instance buffers. + + GLuint multimesh_buffer = mesh_storage->multimesh_get_gl_buffer(inst->data->base); + glBindBuffer(GL_ARRAY_BUFFER, multimesh_buffer); + uint32_t multimesh_stride = mesh_storage->multimesh_get_stride(inst->data->base); + glEnableVertexAttribArray(12); + glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(0)); + glVertexAttribDivisor(12, 1); + glEnableVertexAttribArray(13); + glVertexAttribPointer(13, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(4 * 4)); + glVertexAttribDivisor(13, 1); + glEnableVertexAttribArray(14); + glVertexAttribPointer(14, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(4 * 8)); + glVertexAttribDivisor(14, 1); + + if (mesh_storage->multimesh_uses_colors(inst->data->base) || mesh_storage->multimesh_uses_custom_data(inst->data->base)) { + glEnableVertexAttribArray(15); + glVertexAttribIPointer(15, 4, GL_UNSIGNED_INT, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(mesh_storage->multimesh_get_color_offset(inst->data->base) * sizeof(float))); + glVertexAttribDivisor(15, 1); + } + if (use_index_buffer) { + glDrawElementsInstanced(primitive_gl, mesh_storage->mesh_surface_get_vertices_drawn_count(mesh_surface), mesh_storage->mesh_surface_get_index_type(mesh_surface), 0, inst->instance_count); + } else { + glDrawArraysInstanced(primitive_gl, 0, mesh_storage->mesh_surface_get_vertices_drawn_count(mesh_surface), inst->instance_count); + } } else { - glDrawArrays(primitive_gl, 0, mesh_storage->mesh_surface_get_vertices_drawn_count(mesh_surface)); + // Using regular Mesh. + if (use_index_buffer) { + glDrawElements(primitive_gl, mesh_storage->mesh_surface_get_vertices_drawn_count(mesh_surface), mesh_storage->mesh_surface_get_index_type(mesh_surface), 0); + } else { + glDrawArrays(primitive_gl, 0, mesh_storage->mesh_surface_get_vertices_drawn_count(mesh_surface)); + } + } + if (inst->instance_count > 0) { + glDisableVertexAttribArray(12); + glDisableVertexAttribArray(13); + glDisableVertexAttribArray(14); + glDisableVertexAttribArray(15); } } } @@ -2466,7 +2510,7 @@ RID RasterizerSceneGLES3::render_buffers_create() { return render_buffers_owner.make_rid(rb); } -void RasterizerSceneGLES3::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) { +void RasterizerSceneGLES3::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) { GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); @@ -2616,12 +2660,10 @@ void RasterizerSceneGLES3::decals_set_filter(RS::DecalFilter p_filter) { void RasterizerSceneGLES3::light_projectors_set_filter(RS::LightProjectorFilter p_filter) { } -RasterizerSceneGLES3::RasterizerSceneGLES3(RasterizerStorageGLES3 *p_storage) { +RasterizerSceneGLES3::RasterizerSceneGLES3() { GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton(); GLES3::Config *config = GLES3::Config::get_singleton(); - storage = p_storage; - { // Setup Lights @@ -2811,6 +2853,9 @@ void sky() { #ifdef GLES_OVER_GL glEnable(_EXT_TEXTURE_CUBE_MAP_SEAMLESS); #endif + + // MultiMesh may read from color when color is disabled, so make sure that the color defaults to white instead of black; + glVertexAttrib4f(RS::ARRAY_COLOR, 1.0, 1.0, 1.0, 1.0); } RasterizerSceneGLES3::~RasterizerSceneGLES3() { @@ -2826,15 +2871,15 @@ RasterizerSceneGLES3::~RasterizerSceneGLES3() { // Scene Shader GLES3::MaterialStorage::get_singleton()->shaders.scene_shader.version_free(scene_globals.shader_default_version); GLES3::MaterialStorage::get_singleton()->shaders.cubemap_filter_shader.version_free(scene_globals.cubemap_filter_shader_version); - storage->free(scene_globals.default_material); - storage->free(scene_globals.default_shader); + RSG::material_storage->material_free(scene_globals.default_material); + RSG::material_storage->shader_free(scene_globals.default_shader); // Sky Shader GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_free(sky_globals.shader_default_version); - storage->free(sky_globals.default_material); - storage->free(sky_globals.default_shader); - storage->free(sky_globals.fog_material); - storage->free(sky_globals.fog_shader); + RSG::material_storage->material_free(sky_globals.default_material); + RSG::material_storage->shader_free(sky_globals.default_shader); + RSG::material_storage->material_free(sky_globals.fog_material); + RSG::material_storage->shader_free(sky_globals.fog_shader); glDeleteBuffers(1, &sky_globals.screen_triangle); glDeleteVertexArrays(1, &sky_globals.screen_triangle_array); glDeleteTextures(1, &sky_globals.radical_inverse_vdc_cache_tex); diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index ea6145d2a8..4222743cec 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -37,7 +37,6 @@ #include "core/templates/paged_allocator.h" #include "core/templates/rid_owner.h" #include "core/templates/self_list.h" -#include "rasterizer_storage_gles3.h" #include "scene/resources/mesh.h" #include "servers/rendering/renderer_compositor.h" #include "servers/rendering/renderer_scene_render.h" @@ -45,6 +44,8 @@ #include "shader_gles3.h" #include "shaders/cubemap_filter.glsl.gen.h" #include "shaders/sky.glsl.gen.h" +#include "storage/material_storage.h" +#include "storage/utilities.h" enum RenderListType { RENDER_LIST_OPAQUE, //used for opaque objects @@ -100,6 +101,7 @@ struct RenderDataGLES3 { // For stereo rendering uint32_t view_count = 1; + Vector3 view_eye_offset[RendererSceneRender::MAX_RENDER_VIEWS]; CameraMatrix view_projection[RendererSceneRender::MAX_RENDER_VIEWS]; float z_near = 0.0; @@ -124,7 +126,6 @@ struct RenderDataGLES3 { RendererScene::RenderInfo *render_info = nullptr; }; -class RasterizerStorageGLES3; class RasterizerCanvasGLES3; class RasterizerSceneGLES3 : public RendererSceneRender { @@ -277,7 +278,7 @@ private: int32_t shader_parameters_offset = -1; uint32_t layer_mask = 1; - uint32_t instance_count = 0; + int32_t instance_count = 0; RID mesh_instance; bool can_sdfgi = false; @@ -322,7 +323,7 @@ private: bool mirror = false; bool dirty_dependencies = false; - RendererStorage::DependencyTracker dependency_tracker; + DependencyTracker dependency_tracker; }; Data *data = nullptr; @@ -344,8 +345,8 @@ private: INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA = 1 << 15, }; - static void _geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker); - static void _geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker); + static void _geometry_instance_dependency_changed(Dependency::DependencyChangedNotification p_notification, DependencyTracker *p_tracker); + static void _geometry_instance_dependency_deleted(const RID &p_dependency, DependencyTracker *p_tracker); SelfList<GeometryInstanceGLES3>::List geometry_instance_dirty_list; @@ -738,7 +739,6 @@ protected: void _free_sky_data(Sky *p_sky); public: - RasterizerStorageGLES3 *storage; RasterizerCanvasGLES3 *canvas; GeometryInstance *geometry_instance_create(RID p_base) override; @@ -855,8 +855,8 @@ public: void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) override; void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) override; - void shadows_quality_set(RS::ShadowQuality p_quality) override; - void directional_shadow_quality_set(RS::ShadowQuality p_quality) override; + void positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override; + void directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override; RID light_instance_create(RID p_light) override; void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override; @@ -904,7 +904,7 @@ public: void voxel_gi_set_quality(RS::VoxelGIQuality) override; - void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) override; + void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) override; void render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override; void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<GeometryInstance *> &p_instances) override; @@ -923,7 +923,7 @@ public: } RID render_buffers_create() override; - void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) override; + void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override; void gi_set_use_half_resolution(bool p_enable) override; void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_curve) override; @@ -942,7 +942,7 @@ public: void light_projectors_set_filter(RS::LightProjectorFilter p_filter) override; static RasterizerSceneGLES3 *get_singleton(); - RasterizerSceneGLES3(RasterizerStorageGLES3 *p_storage); + RasterizerSceneGLES3(); ~RasterizerSceneGLES3(); }; diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp deleted file mode 100644 index 49c5045453..0000000000 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ /dev/null @@ -1,640 +0,0 @@ -/*************************************************************************/ -/* rasterizer_storage_gles3.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "rasterizer_storage_gles3.h" - -#ifdef GLES3_ENABLED - -#include "core/config/project_settings.h" -#include "core/math/transform_3d.h" -// #include "rasterizer_canvas_gles3.h" -#include "rasterizer_scene_gles3.h" -#include "servers/rendering/shader_language.h" - -void RasterizerStorageGLES3::base_update_dependency(RID p_base, DependencyTracker *p_instance) { - if (GLES3::MeshStorage::get_singleton()->owns_mesh(p_base)) { - GLES3::Mesh *mesh = GLES3::MeshStorage::get_singleton()->get_mesh(p_base); - p_instance->update_dependency(&mesh->dependency); - } else if (GLES3::MeshStorage::get_singleton()->owns_multimesh(p_base)) { - GLES3::MultiMesh *multimesh = GLES3::MeshStorage::get_singleton()->get_multimesh(p_base); - p_instance->update_dependency(&multimesh->dependency); - if (multimesh->mesh.is_valid()) { - base_update_dependency(multimesh->mesh, p_instance); - } - } else if (GLES3::LightStorage::get_singleton()->owns_light(p_base)) { - GLES3::Light *l = GLES3::LightStorage::get_singleton()->get_light(p_base); - p_instance->update_dependency(&l->dependency); - } -} - -/* VOXEL GI API */ - -RID RasterizerStorageGLES3::voxel_gi_allocate() { - return RID(); -} - -void RasterizerStorageGLES3::voxel_gi_initialize(RID p_rid) { -} - -void RasterizerStorageGLES3::voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) { -} - -AABB RasterizerStorageGLES3::voxel_gi_get_bounds(RID p_voxel_gi) const { - return AABB(); -} - -Vector3i RasterizerStorageGLES3::voxel_gi_get_octree_size(RID p_voxel_gi) const { - return Vector3i(); -} - -Vector<uint8_t> RasterizerStorageGLES3::voxel_gi_get_octree_cells(RID p_voxel_gi) const { - return Vector<uint8_t>(); -} - -Vector<uint8_t> RasterizerStorageGLES3::voxel_gi_get_data_cells(RID p_voxel_gi) const { - return Vector<uint8_t>(); -} - -Vector<uint8_t> RasterizerStorageGLES3::voxel_gi_get_distance_field(RID p_voxel_gi) const { - return Vector<uint8_t>(); -} - -Vector<int> RasterizerStorageGLES3::voxel_gi_get_level_counts(RID p_voxel_gi) const { - return Vector<int>(); -} - -Transform3D RasterizerStorageGLES3::voxel_gi_get_to_cell_xform(RID p_voxel_gi) const { - return Transform3D(); -} - -void RasterizerStorageGLES3::voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) { -} - -float RasterizerStorageGLES3::voxel_gi_get_dynamic_range(RID p_voxel_gi) const { - return 0; -} - -void RasterizerStorageGLES3::voxel_gi_set_propagation(RID p_voxel_gi, float p_range) { -} - -float RasterizerStorageGLES3::voxel_gi_get_propagation(RID p_voxel_gi) const { - return 0; -} - -void RasterizerStorageGLES3::voxel_gi_set_energy(RID p_voxel_gi, float p_range) { -} - -float RasterizerStorageGLES3::voxel_gi_get_energy(RID p_voxel_gi) const { - return 0.0; -} - -void RasterizerStorageGLES3::voxel_gi_set_bias(RID p_voxel_gi, float p_range) { -} - -float RasterizerStorageGLES3::voxel_gi_get_bias(RID p_voxel_gi) const { - return 0.0; -} - -void RasterizerStorageGLES3::voxel_gi_set_normal_bias(RID p_voxel_gi, float p_range) { -} - -float RasterizerStorageGLES3::voxel_gi_get_normal_bias(RID p_voxel_gi) const { - return 0.0; -} - -void RasterizerStorageGLES3::voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) { -} - -bool RasterizerStorageGLES3::voxel_gi_is_interior(RID p_voxel_gi) const { - return false; -} - -void RasterizerStorageGLES3::voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) { -} - -bool RasterizerStorageGLES3::voxel_gi_is_using_two_bounces(RID p_voxel_gi) const { - return false; -} - -void RasterizerStorageGLES3::voxel_gi_set_anisotropy_strength(RID p_voxel_gi, float p_strength) { -} - -float RasterizerStorageGLES3::voxel_gi_get_anisotropy_strength(RID p_voxel_gi) const { - return 0; -} - -uint32_t RasterizerStorageGLES3::voxel_gi_get_version(RID p_voxel_gi) { - return 0; -} - -/* OCCLUDER */ - -void RasterizerStorageGLES3::occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) { -} - -/* FOG */ - -RID RasterizerStorageGLES3::fog_volume_allocate() { - return RID(); -} - -void RasterizerStorageGLES3::fog_volume_initialize(RID p_rid) { -} - -void RasterizerStorageGLES3::fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) { -} - -void RasterizerStorageGLES3::fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) { -} - -void RasterizerStorageGLES3::fog_volume_set_material(RID p_fog_volume, RID p_material) { -} - -AABB RasterizerStorageGLES3::fog_volume_get_aabb(RID p_fog_volume) const { - return AABB(); -} - -RS::FogVolumeShape RasterizerStorageGLES3::fog_volume_get_shape(RID p_fog_volume) const { - return RS::FOG_VOLUME_SHAPE_BOX; -} - -/* VISIBILITY NOTIFIER */ -RID RasterizerStorageGLES3::visibility_notifier_allocate() { - return RID(); -} - -void RasterizerStorageGLES3::visibility_notifier_initialize(RID p_notifier) { -} - -void RasterizerStorageGLES3::visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) { -} - -void RasterizerStorageGLES3::visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) { -} - -AABB RasterizerStorageGLES3::visibility_notifier_get_aabb(RID p_notifier) const { - return AABB(); -} - -void RasterizerStorageGLES3::visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) { -} - -/* CANVAS SHADOW */ - -RID RasterizerStorageGLES3::canvas_light_shadow_buffer_create(int p_width) { - CanvasLightShadow *cls = memnew(CanvasLightShadow); - - if (p_width > config->max_texture_size) { - p_width = config->max_texture_size; - } - - cls->size = p_width; - cls->height = 16; - - glActiveTexture(GL_TEXTURE0); - - glGenFramebuffers(1, &cls->fbo); - glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo); - - glGenRenderbuffers(1, &cls->depth); - glBindRenderbuffer(GL_RENDERBUFFER, cls->depth); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, cls->size, cls->height); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, cls->depth); - - glGenTextures(1, &cls->distance); - glBindTexture(GL_TEXTURE_2D, cls->distance); - if (config->use_rgba_2d_shadows) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, cls->size, cls->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - } else { - glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, cls->size, cls->height, 0, GL_RED, GL_FLOAT, nullptr); - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, cls->distance, 0); - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - //printf("errnum: %x\n",status); - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); - - if (status != GL_FRAMEBUFFER_COMPLETE) { - memdelete(cls); - ERR_FAIL_COND_V(status != GL_FRAMEBUFFER_COMPLETE, RID()); - } - - return canvas_light_shadow_owner.make_rid(cls); -} - -/* LIGHT SHADOW MAPPING */ -/* - -RID RasterizerStorageGLES3::canvas_light_occluder_create() { - CanvasOccluder *co = memnew(CanvasOccluder); - co->index_id = 0; - co->vertex_id = 0; - co->len = 0; - - return canvas_occluder_owner.make_rid(co); -} - -void RasterizerStorageGLES3::canvas_light_occluder_set_polylines(RID p_occluder, const PoolVector<Vector2> &p_lines) { - CanvasOccluder *co = canvas_occluder_owner.get(p_occluder); - ERR_FAIL_COND(!co); - - co->lines = p_lines; - - if (p_lines.size() != co->len) { - if (co->index_id) { - glDeleteBuffers(1, &co->index_id); - } if (co->vertex_id) { - glDeleteBuffers(1, &co->vertex_id); - } - - co->index_id = 0; - co->vertex_id = 0; - co->len = 0; - } - - if (p_lines.size()) { - PoolVector<float> geometry; - PoolVector<uint16_t> indices; - int lc = p_lines.size(); - - geometry.resize(lc * 6); - indices.resize(lc * 3); - - PoolVector<float>::Write vw = geometry.write(); - PoolVector<uint16_t>::Write iw = indices.write(); - - PoolVector<Vector2>::Read lr = p_lines.read(); - - const int POLY_HEIGHT = 16384; - - for (int i = 0; i < lc / 2; i++) { - vw[i * 12 + 0] = lr[i * 2 + 0].x; - vw[i * 12 + 1] = lr[i * 2 + 0].y; - vw[i * 12 + 2] = POLY_HEIGHT; - - vw[i * 12 + 3] = lr[i * 2 + 1].x; - vw[i * 12 + 4] = lr[i * 2 + 1].y; - vw[i * 12 + 5] = POLY_HEIGHT; - - vw[i * 12 + 6] = lr[i * 2 + 1].x; - vw[i * 12 + 7] = lr[i * 2 + 1].y; - vw[i * 12 + 8] = -POLY_HEIGHT; - - vw[i * 12 + 9] = lr[i * 2 + 0].x; - vw[i * 12 + 10] = lr[i * 2 + 0].y; - vw[i * 12 + 11] = -POLY_HEIGHT; - - iw[i * 6 + 0] = i * 4 + 0; - iw[i * 6 + 1] = i * 4 + 1; - iw[i * 6 + 2] = i * 4 + 2; - - iw[i * 6 + 3] = i * 4 + 2; - iw[i * 6 + 4] = i * 4 + 3; - iw[i * 6 + 5] = i * 4 + 0; - } - - //if same buffer len is being set, just use BufferSubData to avoid a pipeline flush - - if (!co->vertex_id) { - glGenBuffers(1, &co->vertex_id); - glBindBuffer(GL_ARRAY_BUFFER, co->vertex_id); - glBufferData(GL_ARRAY_BUFFER, lc * 6 * sizeof(real_t), vw.ptr(), GL_STATIC_DRAW); - } else { - glBindBuffer(GL_ARRAY_BUFFER, co->vertex_id); - glBufferSubData(GL_ARRAY_BUFFER, 0, lc * 6 * sizeof(real_t), vw.ptr()); - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind - - if (!co->index_id) { - glGenBuffers(1, &co->index_id); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, co->index_id); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, lc * 3 * sizeof(uint16_t), iw.ptr(), GL_DYNAMIC_DRAW); - } else { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, co->index_id); - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, lc * 3 * sizeof(uint16_t), iw.ptr()); - } - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //unbind - - co->len = lc; - } -} -*/ - -RS::InstanceType RasterizerStorageGLES3::get_base_type(RID p_rid) const { - if (GLES3::MeshStorage::get_singleton()->owns_mesh(p_rid)) { - return RS::INSTANCE_MESH; - } else if (GLES3::MeshStorage::get_singleton()->owns_multimesh(p_rid)) { - return RS::INSTANCE_MULTIMESH; - } else if (GLES3::LightStorage::get_singleton()->owns_light(p_rid)) { - return RS::INSTANCE_LIGHT; - } - return RS::INSTANCE_NONE; -} - -bool RasterizerStorageGLES3::free(RID p_rid) { - if (GLES3::TextureStorage::get_singleton()->owns_render_target(p_rid)) { - GLES3::TextureStorage::get_singleton()->render_target_free(p_rid); - return true; - } else if (GLES3::TextureStorage::get_singleton()->owns_texture(p_rid)) { - GLES3::TextureStorage::get_singleton()->texture_free(p_rid); - return true; - } else if (GLES3::TextureStorage::get_singleton()->owns_canvas_texture(p_rid)) { - GLES3::TextureStorage::get_singleton()->canvas_texture_free(p_rid); - return true; - } else if (GLES3::MaterialStorage::get_singleton()->owns_shader(p_rid)) { - GLES3::MaterialStorage::get_singleton()->shader_free(p_rid); - return true; - } else if (GLES3::MaterialStorage::get_singleton()->owns_material(p_rid)) { - GLES3::MaterialStorage::get_singleton()->material_free(p_rid); - return true; - } else if (GLES3::MeshStorage::get_singleton()->owns_mesh(p_rid)) { - GLES3::MeshStorage::get_singleton()->mesh_free(p_rid); - return true; - } else if (GLES3::MeshStorage::get_singleton()->owns_multimesh(p_rid)) { - GLES3::MeshStorage::get_singleton()->multimesh_free(p_rid); - return true; - } else if (GLES3::MeshStorage::get_singleton()->owns_mesh_instance(p_rid)) { - GLES3::MeshStorage::get_singleton()->mesh_instance_free(p_rid); - return true; - } else if (GLES3::LightStorage::get_singleton()->owns_light(p_rid)) { - GLES3::LightStorage::get_singleton()->light_free(p_rid); - return true; - } else { - return false; - } - /* - else if (reflection_probe_owner.owns(p_rid)) { - // delete the texture - ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_rid); - reflection_probe->instance_remove_deps(); - - reflection_probe_owner.free(p_rid); - memdelete(reflection_probe); - - return true; - } else if (lightmap_capture_data_owner.owns(p_rid)) { - // delete the texture - LightmapCapture *lightmap_capture = lightmap_capture_data_owner.get_or_null(p_rid); - lightmap_capture->instance_remove_deps(); - - lightmap_capture_data_owner.free(p_rid); - memdelete(lightmap_capture); - return true; - - } else if (canvas_occluder_owner.owns(p_rid)) { - CanvasOccluder *co = canvas_occluder_owner.get_or_null(p_rid); - if (co->index_id) { - glDeleteBuffers(1, &co->index_id); - } - if (co->vertex_id) { - glDeleteBuffers(1, &co->vertex_id); - } - - canvas_occluder_owner.free(p_rid); - memdelete(co); - - return true; - - } else if (canvas_light_shadow_owner.owns(p_rid)) { - CanvasLightShadow *cls = canvas_light_shadow_owner.get_or_null(p_rid); - glDeleteFramebuffers(1, &cls->fbo); - glDeleteRenderbuffers(1, &cls->depth); - glDeleteTextures(1, &cls->distance); - canvas_light_shadow_owner.free(p_rid); - memdelete(cls); - - return true; - */ -} - -bool RasterizerStorageGLES3::has_os_feature(const String &p_feature) const { - if (p_feature == "rgtc") { - return config->rgtc_supported; - } - - if (p_feature == "s3tc") { - return config->s3tc_supported; - } - - if (p_feature == "bptc") { - return config->bptc_supported; - } - - if (p_feature == "etc" || p_feature == "etc2") { - return config->etc2_supported; - } - - return false; -} - -//////////////////////////////////////////// - -void RasterizerStorageGLES3::set_debug_generate_wireframes(bool p_generate) { -} - -//void RasterizerStorageGLES3::render_info_begin_capture() { -// info.snap = info.render; -//} - -//void RasterizerStorageGLES3::render_info_end_capture() { -// info.snap.object_count = info.render.object_count - info.snap.object_count; -// info.snap.draw_call_count = info.render.draw_call_count - info.snap.draw_call_count; -// info.snap.material_switch_count = info.render.material_switch_count - info.snap.material_switch_count; -// info.snap.surface_switch_count = info.render.surface_switch_count - info.snap.surface_switch_count; -// info.snap.shader_rebind_count = info.render.shader_rebind_count - info.snap.shader_rebind_count; -// info.snap.vertices_count = info.render.vertices_count - info.snap.vertices_count; -// info.snap._2d_item_count = info.render._2d_item_count - info.snap._2d_item_count; -// info.snap._2d_draw_call_count = info.render._2d_draw_call_count - info.snap._2d_draw_call_count; -//} - -//int RasterizerStorageGLES3::get_captured_render_info(RS::RenderInfo p_info) { -// switch (p_info) { -// case RS::INFO_OBJECTS_IN_FRAME: { -// return info.snap.object_count; -// } break; -// case RS::INFO_VERTICES_IN_FRAME: { -// return info.snap.vertices_count; -// } break; -// case RS::INFO_MATERIAL_CHANGES_IN_FRAME: { -// return info.snap.material_switch_count; -// } break; -// case RS::INFO_SHADER_CHANGES_IN_FRAME: { -// return info.snap.shader_rebind_count; -// } break; -// case RS::INFO_SURFACE_CHANGES_IN_FRAME: { -// return info.snap.surface_switch_count; -// } break; -// case RS::INFO_DRAW_CALLS_IN_FRAME: { -// return info.snap.draw_call_count; -// } break; -// /* -// case RS::INFO_2D_ITEMS_IN_FRAME: { -// return info.snap._2d_item_count; -// } break; -// case RS::INFO_2D_DRAW_CALLS_IN_FRAME: { -// return info.snap._2d_draw_call_count; -// } break; -// */ -// default: { -// return get_render_info(p_info); -// } -// } -//} - -//int RasterizerStorageGLES3::get_render_info(RS::RenderInfo p_info) { -// switch (p_info) { -// case RS::INFO_OBJECTS_IN_FRAME: -// return info.render_final.object_count; -// case RS::INFO_VERTICES_IN_FRAME: -// return info.render_final.vertices_count; -// case RS::INFO_MATERIAL_CHANGES_IN_FRAME: -// return info.render_final.material_switch_count; -// case RS::INFO_SHADER_CHANGES_IN_FRAME: -// return info.render_final.shader_rebind_count; -// case RS::INFO_SURFACE_CHANGES_IN_FRAME: -// return info.render_final.surface_switch_count; -// case RS::INFO_DRAW_CALLS_IN_FRAME: -// return info.render_final.draw_call_count; -// /* -// case RS::INFO_2D_ITEMS_IN_FRAME: -// return info.render_final._2d_item_count; -// case RS::INFO_2D_DRAW_CALLS_IN_FRAME: -// return info.render_final._2d_draw_call_count; -//*/ -// case RS::INFO_USAGE_VIDEO_MEM_TOTAL: -// return 0; //no idea -// case RS::INFO_VIDEO_MEM_USED: -// return info.vertex_mem + info.texture_mem; -// case RS::INFO_TEXTURE_MEM_USED: -// return info.texture_mem; -// case RS::INFO_VERTEX_MEM_USED: -// return info.vertex_mem; -// default: -// return 0; //no idea either -// } -//} - -String RasterizerStorageGLES3::get_video_adapter_name() const { - return (const char *)glGetString(GL_RENDERER); -} - -String RasterizerStorageGLES3::get_video_adapter_vendor() const { - return (const char *)glGetString(GL_VENDOR); -} - -RenderingDevice::DeviceType RasterizerStorageGLES3::get_video_adapter_type() const { - return RenderingDevice::DeviceType::DEVICE_TYPE_OTHER; -} - -String RasterizerStorageGLES3::get_video_adapter_api_version() const { - return (const char *)glGetString(GL_VERSION); -} - -void RasterizerStorageGLES3::initialize() { - config = GLES3::Config::get_singleton(); - - // skeleton buffer - { - resources.skeleton_transform_buffer_size = 0; - glGenBuffers(1, &resources.skeleton_transform_buffer); - } - - // radical inverse vdc cache texture - // used for cubemap filtering - glGenTextures(1, &resources.radical_inverse_vdc_cache_tex); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, resources.radical_inverse_vdc_cache_tex); - /* - uint8_t radical_inverse[512]; - - for (uint32_t i = 0; i < 512; i++) { - uint32_t bits = i; - - bits = (bits << 16) | (bits >> 16); - bits = ((bits & 0x55555555) << 1) | ((bits & 0xAAAAAAAA) >> 1); - bits = ((bits & 0x33333333) << 2) | ((bits & 0xCCCCCCCC) >> 2); - bits = ((bits & 0x0F0F0F0F) << 4) | ((bits & 0xF0F0F0F0) >> 4); - bits = ((bits & 0x00FF00FF) << 8) | ((bits & 0xFF00FF00) >> 8); - - float value = float(bits) * 2.3283064365386963e-10; - radical_inverse[i] = uint8_t(CLAMP(value * 255.0, 0, 255)); - } - - //glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 512, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, radical_inverse); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //need this for proper sampling - */ - glBindTexture(GL_TEXTURE_2D, 0); - - { - glGenFramebuffers(1, &resources.mipmap_blur_fbo); - glGenTextures(1, &resources.mipmap_blur_color); - } - -#ifdef GLES_OVER_GL - glEnable(GL_PROGRAM_POINT_SIZE); -#endif -} - -void RasterizerStorageGLES3::finalize() { -} - -void RasterizerStorageGLES3::update_memory_info() { -} - -uint64_t RasterizerStorageGLES3::get_rendering_info(RS::RenderingInfo p_info) { - return 0; -} - -void RasterizerStorageGLES3::update_dirty_resources() { - GLES3::MaterialStorage::get_singleton()->_update_global_variables(); - GLES3::MaterialStorage::get_singleton()->_update_queued_materials(); - //GLES3::MeshStorage::get_singleton()->_update_dirty_skeletons(); - GLES3::MeshStorage::get_singleton()->_update_dirty_multimeshes(); -} - -RasterizerStorageGLES3::RasterizerStorageGLES3() { - initialize(); -} - -RasterizerStorageGLES3::~RasterizerStorageGLES3() { -} - -#endif // GLES3_ENABLED diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h deleted file mode 100644 index 7ac3db4537..0000000000 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ /dev/null @@ -1,322 +0,0 @@ -/*************************************************************************/ -/* rasterizer_storage_gles3.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef RASTERIZER_STORAGE_OPENGL_H -#define RASTERIZER_STORAGE_OPENGL_H - -#ifdef GLES3_ENABLED - -#include "core/templates/local_vector.h" -#include "core/templates/rid_owner.h" -#include "core/templates/self_list.h" -#include "servers/rendering/renderer_compositor.h" -#include "servers/rendering/renderer_storage.h" -#include "servers/rendering/shader_compiler.h" -#include "servers/rendering/shader_language.h" -#include "storage/config.h" -#include "storage/light_storage.h" -#include "storage/material_storage.h" -#include "storage/mesh_storage.h" -#include "storage/texture_storage.h" - -// class RasterizerCanvasGLES3; -// class RasterizerSceneGLES3; - -class RasterizerStorageGLES3 : public RendererStorage { -public: - // RasterizerCanvasGLES3 *canvas; - // RasterizerSceneGLES3 *scene; - - GLES3::Config *config = nullptr; - - static _FORCE_INLINE_ void store_transform(const Transform3D &p_mtx, float *p_array) { - p_array[0] = p_mtx.basis.rows[0][0]; - p_array[1] = p_mtx.basis.rows[1][0]; - p_array[2] = p_mtx.basis.rows[2][0]; - p_array[3] = 0; - p_array[4] = p_mtx.basis.rows[0][1]; - p_array[5] = p_mtx.basis.rows[1][1]; - p_array[6] = p_mtx.basis.rows[2][1]; - p_array[7] = 0; - p_array[8] = p_mtx.basis.rows[0][2]; - p_array[9] = p_mtx.basis.rows[1][2]; - p_array[10] = p_mtx.basis.rows[2][2]; - p_array[11] = 0; - p_array[12] = p_mtx.origin.x; - p_array[13] = p_mtx.origin.y; - p_array[14] = p_mtx.origin.z; - p_array[15] = 1; - } - - static _FORCE_INLINE_ void store_transform_3x3(const Basis &p_mtx, float *p_array) { - p_array[0] = p_mtx.rows[0][0]; - p_array[1] = p_mtx.rows[1][0]; - p_array[2] = p_mtx.rows[2][0]; - p_array[3] = 0; - p_array[4] = p_mtx.rows[0][1]; - p_array[5] = p_mtx.rows[1][1]; - p_array[6] = p_mtx.rows[2][1]; - p_array[7] = 0; - p_array[8] = p_mtx.rows[0][2]; - p_array[9] = p_mtx.rows[1][2]; - p_array[10] = p_mtx.rows[2][2]; - p_array[11] = 0; - } - - static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_array) { - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - p_array[i * 4 + j] = p_mtx.matrix[i][j]; - } - } - } - - struct Resources { - GLuint mipmap_blur_fbo; - GLuint mipmap_blur_color; - - GLuint radical_inverse_vdc_cache_tex; - bool use_rgba_2d_shadows; - - size_t skeleton_transform_buffer_size; - GLuint skeleton_transform_buffer; - LocalVector<float> skeleton_transform_cpu_buffer; - - } resources; - - struct Info { - uint64_t texture_mem = 0; - uint64_t vertex_mem = 0; - - struct Render { - uint32_t object_count; - uint32_t draw_call_count; - uint32_t material_switch_count; - uint32_t surface_switch_count; - uint32_t shader_rebind_count; - uint32_t vertices_count; - uint32_t _2d_item_count; - uint32_t _2d_draw_call_count; - - void reset() { - object_count = 0; - draw_call_count = 0; - material_switch_count = 0; - surface_switch_count = 0; - shader_rebind_count = 0; - vertices_count = 0; - _2d_item_count = 0; - _2d_draw_call_count = 0; - } - } render, render_final, snap; - - Info() { - render.reset(); - render_final.reset(); - } - - } info; - - ///////////////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////API//////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////////////// - -public: - virtual void base_update_dependency(RID p_base, DependencyTracker *p_instance) override; - - /* VOXEL GI API */ - - RID voxel_gi_allocate() override; - void voxel_gi_initialize(RID p_rid) override; - void voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) override; - - AABB voxel_gi_get_bounds(RID p_voxel_gi) const override; - Vector3i voxel_gi_get_octree_size(RID p_voxel_gi) const override; - Vector<uint8_t> voxel_gi_get_octree_cells(RID p_voxel_gi) const override; - Vector<uint8_t> voxel_gi_get_data_cells(RID p_voxel_gi) const override; - Vector<uint8_t> voxel_gi_get_distance_field(RID p_voxel_gi) const override; - - Vector<int> voxel_gi_get_level_counts(RID p_voxel_gi) const override; - Transform3D voxel_gi_get_to_cell_xform(RID p_voxel_gi) const override; - - void voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) override; - float voxel_gi_get_dynamic_range(RID p_voxel_gi) const override; - - void voxel_gi_set_propagation(RID p_voxel_gi, float p_range) override; - float voxel_gi_get_propagation(RID p_voxel_gi) const override; - - void voxel_gi_set_energy(RID p_voxel_gi, float p_range) override; - float voxel_gi_get_energy(RID p_voxel_gi) const override; - - void voxel_gi_set_bias(RID p_voxel_gi, float p_range) override; - float voxel_gi_get_bias(RID p_voxel_gi) const override; - - void voxel_gi_set_normal_bias(RID p_voxel_gi, float p_range) override; - float voxel_gi_get_normal_bias(RID p_voxel_gi) const override; - - void voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) override; - bool voxel_gi_is_interior(RID p_voxel_gi) const override; - - void voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) override; - bool voxel_gi_is_using_two_bounces(RID p_voxel_gi) const override; - - void voxel_gi_set_anisotropy_strength(RID p_voxel_gi, float p_strength) override; - float voxel_gi_get_anisotropy_strength(RID p_voxel_gi) const override; - - uint32_t voxel_gi_get_version(RID p_voxel_gi) override; - - /* OCCLUDER */ - - void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices); - - /* FOG VOLUMES */ - - RID fog_volume_allocate() override; - void fog_volume_initialize(RID p_rid) override; - - void fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) override; - void fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) override; - void fog_volume_set_material(RID p_fog_volume, RID p_material) override; - AABB fog_volume_get_aabb(RID p_fog_volume) const override; - RS::FogVolumeShape fog_volume_get_shape(RID p_fog_volume) const override; - - /* VISIBILITY NOTIFIER */ - RID visibility_notifier_allocate() override; - void visibility_notifier_initialize(RID p_notifier) override; - void visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) override; - void visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) override; - - AABB visibility_notifier_get_aabb(RID p_notifier) const override; - void visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) override; - - // access from canvas - // GLES3::RenderTarget * render_target_get(RID p_render_target); - - /* CANVAS SHADOW */ - - struct CanvasLightShadow { - RID self; - int size; - int height; - GLuint fbo; - GLuint depth; - GLuint distance; //for older devices - }; - - RID_PtrOwner<CanvasLightShadow> canvas_light_shadow_owner; - - RID canvas_light_shadow_buffer_create(int p_width); - - /* LIGHT SHADOW MAPPING */ - /* - struct CanvasOccluder { - RID self; - - GLuint vertex_id; // 0 means, unconfigured - GLuint index_id; // 0 means, unconfigured - LocalVector<Vector2> lines; - int len; - }; - - RID_Owner<CanvasOccluder> canvas_occluder_owner; - - RID canvas_light_occluder_create(); - void canvas_light_occluder_set_polylines(RID p_occluder, const LocalVector<Vector2> &p_lines); -*/ - - RS::InstanceType get_base_type(RID p_rid) const override; - - bool free(RID p_rid) override; - - void initialize(); - void finalize(); - - void update_memory_info() override; - uint64_t get_rendering_info(RS::RenderingInfo p_info) override; - - bool has_os_feature(const String &p_feature) const override; - - void update_dirty_resources() override; - - void set_debug_generate_wireframes(bool p_generate) override; - - // void render_info_begin_capture() override; - // void render_info_end_capture() override; - // int get_captured_render_info(RS::RenderInfo p_info) override; - - // int get_render_info(RS::RenderInfo p_info) override; - String get_video_adapter_name() const override; - String get_video_adapter_vendor() const override; - RenderingDevice::DeviceType get_video_adapter_type() const override; - String get_video_adapter_api_version() const override; - - void capture_timestamps_begin() override {} - void capture_timestamp(const String &p_name) override {} - uint32_t get_captured_timestamps_count() const override { - return 0; - } - uint64_t get_captured_timestamps_frame() const override { - return 0; - } - uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const override { - return 0; - } - uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const override { - return 0; - } - String get_captured_timestamp_name(uint32_t p_index) const override { - return String(); - } - - //bool validate_framebuffer(); // Validate currently bound framebuffer, does not touch global state - String get_framebuffer_error(GLenum p_status); - - RasterizerStorageGLES3(); - ~RasterizerStorageGLES3(); -}; - -inline String RasterizerStorageGLES3::get_framebuffer_error(GLenum p_status) { -#if defined(DEBUG_ENABLED) && defined(GLES_OVER_GL) - if (p_status == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT) { - return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; - } else if (p_status == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT) { - return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; - } else if (p_status == GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER) { - return "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER"; - } else if (p_status == GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER) { - return "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER"; - } -#endif - return itos(p_status); -} - -#endif // GLES3_ENABLED - -#endif // RASTERIZER_STORAGE_OPENGL_H diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub index d8dd573f57..83ffe8b1e1 100644 --- a/drivers/gles3/shaders/SCsub +++ b/drivers/gles3/shaders/SCsub @@ -10,7 +10,7 @@ if "GLES3_GLSL" in env["BUILDERS"]: glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files] # make sure we recompile shaders if include files change - env.Depends([f + ".gen.h" for f in glsl_files], gl_include_files) + env.Depends([f + ".gen.h" for f in glsl_files], gl_include_files + ["#gles3_builders.py"]) env.GLES3_GLSL("canvas.glsl") env.GLES3_GLSL("copy.glsl") diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl index 9c426dd3ef..4df818cd4c 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -23,10 +23,9 @@ layout(location = 11) in vec4 weight_attrib; #ifdef USE_INSTANCING -layout(location = 5) in highp vec4 instance_xform0; -layout(location = 6) in highp vec4 instance_xform1; -layout(location = 7) in lowp vec4 instance_color; -layout(location = 8) in highp vec4 instance_custom_data; +layout(location = 1) in highp vec4 instance_xform0; +layout(location = 2) in highp vec4 instance_xform1; +layout(location = 5) in highp uvec4 instance_color_custom_data; // Color packed into xy, custom_data packed into zw for compatibility with 3D #endif @@ -98,8 +97,9 @@ void main() { vec4 bone_weights = weight_attrib; #ifdef USE_INSTANCING + vec4 instance_color = vec4(unpackHalf2x16(instance_color_custom_data.x), unpackHalf2x16(instance_color_custom_data.y)); color *= instance_color; - instance_custom = instance_custom_data; + instance_custom = vec4(unpackHalf2x16(instance_color_custom_data.z), unpackHalf2x16(instance_color_custom_data.w)); #endif #else diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index fbea4bdbe4..4f2be8bf60 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -2,8 +2,11 @@ #[modes] mode_color = #define BASE_PASS +mode_color_instancing = #define BASE_PASS \n#define USE_INSTANCING mode_additive = #define USE_ADDITIVE_LIGHTING +mode_additive_instancing = #define USE_ADDITIVE_LIGHTING \n#define USE_INSTANCING mode_depth = #define MODE_RENDER_DEPTH +mode_depth_instancing = #define MODE_RENDER_DEPTH \n#define USE_INSTANCING #[specializations] @@ -43,8 +46,6 @@ ARRAY_CUSTOM2 = 8, ARRAY_CUSTOM3 = 9, ARRAY_BONES = 10, // RGBA16UI (x2 if 8 weights) ARRAY_WEIGHTS = 11, // RGBA16UNORM (x2 if 8 weights) -ARRAY_INDEX = 12, // 16 or 32 bits depending on length > 0xFFFF. -ARRAY_MAX = 13 */ /* INPUT ATTRIBS */ @@ -96,6 +97,13 @@ layout(location = 10) in uvec4 bone_attrib; layout(location = 11) in vec4 weight_attrib; #endif +#ifdef USE_INSTANCING +layout(location = 12) in highp vec4 instance_xform0; +layout(location = 13) in highp vec4 instance_xform1; +layout(location = 14) in highp vec4 instance_xform2; +layout(location = 15) in highp uvec4 instance_color_custom_data; // Color packed into xy, Custom data into zw. +#endif + layout(std140) uniform GlobalVariableData { //ubo:1 vec4 global_variables[MAX_GLOBAL_VARIABLES]; }; @@ -195,6 +203,10 @@ void main() { highp vec3 vertex = vertex_attrib; highp mat4 model_matrix = world_transform; +#ifdef USE_INSTANCING + highp mat4 m = mat4(instance_xform0, instance_xform1, instance_xform2, vec4(0.0, 0.0, 0.0, 1.0)); + model_matrix = model_matrix * transpose(m); +#endif #ifdef NORMAL_USED vec3 normal = normal_attrib * 2.0 - 1.0; @@ -209,6 +221,10 @@ void main() { #if defined(COLOR_USED) color_interp = color_attrib; +#ifdef USE_INSTANCING + vec4 instance_color = vec4(unpackHalf2x16(instance_color_custom_data.x), unpackHalf2x16(instance_color_custom_data.y)); + color_interp *= instance_color; +#endif #endif #if defined(UV_USED) @@ -229,7 +245,11 @@ void main() { highp mat4 projection_matrix = scene_data.projection_matrix; highp mat4 inv_projection_matrix = scene_data.inv_projection_matrix; +#ifdef USE_INSTANCING + vec4 instance_custom = vec4(unpackHalf2x16(instance_color_custom_data.z), unpackHalf2x16(instance_color_custom_data.w)); +#else vec4 instance_custom = vec4(0.0); +#endif // Using world coordinates #if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED) diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp index 954aa11c0d..22578c9e91 100644 --- a/drivers/gles3/storage/light_storage.cpp +++ b/drivers/gles3/storage/light_storage.cpp @@ -139,12 +139,12 @@ void LightStorage::light_set_param(RID p_light, RS::LightParam p_param, float p_ case RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE: case RS::LIGHT_PARAM_SHADOW_BIAS: { light->version++; - light->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_LIGHT); + light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT); } break; case RS::LIGHT_PARAM_SIZE: { if ((light->param[p_param] > CMP_EPSILON) != (p_value > CMP_EPSILON)) { //changing from no size to size and the opposite - light->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_LIGHT_SOFT_SHADOW_AND_PROJECTOR); + light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT_SOFT_SHADOW_AND_PROJECTOR); } } break; default: { @@ -160,7 +160,7 @@ void LightStorage::light_set_shadow(RID p_light, bool p_enabled) { light->shadow = p_enabled; light->version++; - light->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_LIGHT); + light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT); } void LightStorage::light_set_projector(RID p_light, RID p_texture) { @@ -182,7 +182,7 @@ void LightStorage::light_set_projector(RID p_light, RID p_texture) { if (light->projector.is_valid()) { texture_storage->texture_add_to_decal_atlas(light->projector, light->type == RS::LIGHT_OMNI); } - light->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_LIGHT_SOFT_SHADOW_AND_PROJECTOR); + light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT_SOFT_SHADOW_AND_PROJECTOR); } } @@ -200,7 +200,7 @@ void LightStorage::light_set_cull_mask(RID p_light, uint32_t p_mask) { light->cull_mask = p_mask; light->version++; - light->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_LIGHT); + light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT); } void LightStorage::light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) { @@ -220,7 +220,7 @@ void LightStorage::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) light->reverse_cull = p_enabled; light->version++; - light->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_LIGHT); + light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT); } void LightStorage::light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) { @@ -230,7 +230,7 @@ void LightStorage::light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mod light->bake_mode = p_bake_mode; light->version++; - light->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_LIGHT); + light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT); } void LightStorage::light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) { @@ -240,7 +240,7 @@ void LightStorage::light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMo light->omni_shadow_mode = p_mode; light->version++; - light->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_LIGHT); + light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT); } RS::LightOmniShadowMode LightStorage::light_omni_get_shadow_mode(RID p_light) { @@ -256,7 +256,7 @@ void LightStorage::light_directional_set_shadow_mode(RID p_light, RS::LightDirec light->directional_shadow_mode = p_mode; light->version++; - light->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_LIGHT); + light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT); } void LightStorage::light_directional_set_blend_splits(RID p_light, bool p_enable) { @@ -265,7 +265,7 @@ void LightStorage::light_directional_set_blend_splits(RID p_light, bool p_enable light->directional_blend_splits = p_enable; light->version++; - light->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_LIGHT); + light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT); } bool LightStorage::light_directional_get_blend_splits(RID p_light) const { @@ -476,4 +476,104 @@ float LightStorage::lightmap_get_probe_capture_update_speed() const { return 0; } +/* LIGHT SHADOW MAPPING */ +/* + +RID LightStorage::canvas_light_occluder_create() { + CanvasOccluder *co = memnew(CanvasOccluder); + co->index_id = 0; + co->vertex_id = 0; + co->len = 0; + + return canvas_occluder_owner.make_rid(co); +} + +void LightStorage::canvas_light_occluder_set_polylines(RID p_occluder, const PoolVector<Vector2> &p_lines) { + CanvasOccluder *co = canvas_occluder_owner.get(p_occluder); + ERR_FAIL_COND(!co); + + co->lines = p_lines; + + if (p_lines.size() != co->len) { + if (co->index_id) { + glDeleteBuffers(1, &co->index_id); + } if (co->vertex_id) { + glDeleteBuffers(1, &co->vertex_id); + } + + co->index_id = 0; + co->vertex_id = 0; + co->len = 0; + } + + if (p_lines.size()) { + PoolVector<float> geometry; + PoolVector<uint16_t> indices; + int lc = p_lines.size(); + + geometry.resize(lc * 6); + indices.resize(lc * 3); + + PoolVector<float>::Write vw = geometry.write(); + PoolVector<uint16_t>::Write iw = indices.write(); + + PoolVector<Vector2>::Read lr = p_lines.read(); + + const int POLY_HEIGHT = 16384; + + for (int i = 0; i < lc / 2; i++) { + vw[i * 12 + 0] = lr[i * 2 + 0].x; + vw[i * 12 + 1] = lr[i * 2 + 0].y; + vw[i * 12 + 2] = POLY_HEIGHT; + + vw[i * 12 + 3] = lr[i * 2 + 1].x; + vw[i * 12 + 4] = lr[i * 2 + 1].y; + vw[i * 12 + 5] = POLY_HEIGHT; + + vw[i * 12 + 6] = lr[i * 2 + 1].x; + vw[i * 12 + 7] = lr[i * 2 + 1].y; + vw[i * 12 + 8] = -POLY_HEIGHT; + + vw[i * 12 + 9] = lr[i * 2 + 0].x; + vw[i * 12 + 10] = lr[i * 2 + 0].y; + vw[i * 12 + 11] = -POLY_HEIGHT; + + iw[i * 6 + 0] = i * 4 + 0; + iw[i * 6 + 1] = i * 4 + 1; + iw[i * 6 + 2] = i * 4 + 2; + + iw[i * 6 + 3] = i * 4 + 2; + iw[i * 6 + 4] = i * 4 + 3; + iw[i * 6 + 5] = i * 4 + 0; + } + + //if same buffer len is being set, just use BufferSubData to avoid a pipeline flush + + if (!co->vertex_id) { + glGenBuffers(1, &co->vertex_id); + glBindBuffer(GL_ARRAY_BUFFER, co->vertex_id); + glBufferData(GL_ARRAY_BUFFER, lc * 6 * sizeof(real_t), vw.ptr(), GL_STATIC_DRAW); + } else { + glBindBuffer(GL_ARRAY_BUFFER, co->vertex_id); + glBufferSubData(GL_ARRAY_BUFFER, 0, lc * 6 * sizeof(real_t), vw.ptr()); + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind + + if (!co->index_id) { + glGenBuffers(1, &co->index_id); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, co->index_id); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, lc * 3 * sizeof(uint16_t), iw.ptr(), GL_DYNAMIC_DRAW); + } else { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, co->index_id); + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, lc * 3 * sizeof(uint16_t), iw.ptr()); + } + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //unbind + + co->len = lc; + } +} +*/ + #endif // !GLES3_ENABLED diff --git a/drivers/gles3/storage/light_storage.h b/drivers/gles3/storage/light_storage.h index 5acaf45aa3..575ab93eab 100644 --- a/drivers/gles3/storage/light_storage.h +++ b/drivers/gles3/storage/light_storage.h @@ -37,8 +37,8 @@ #include "core/templates/rid_owner.h" #include "core/templates/self_list.h" #include "servers/rendering/renderer_compositor.h" -#include "servers/rendering/renderer_storage.h" #include "servers/rendering/storage/light_storage.h" +#include "servers/rendering/storage/utilities.h" #include "platform_config.h" #ifndef OPENGL_INCLUDE_H @@ -72,7 +72,7 @@ struct Light { RS::LightDirectionalSkyMode directional_sky_mode = RS::LIGHT_DIRECTIONAL_SKY_MODE_LIGHT_AND_SKY; uint64_t version = 0; - RendererStorage::Dependency dependency; + Dependency dependency; }; /* REFLECTION PROBE */ @@ -93,7 +93,7 @@ struct ReflectionProbe { uint32_t cull_mask = (1 << 20) - 1; float mesh_lod_threshold = 0.01; - RendererStorage::Dependency dependency; + Dependency dependency; }; /* LIGHTMAP */ @@ -115,7 +115,7 @@ struct Lightmap { int32_t over = EMPTY_LEAF, under = EMPTY_LEAF; }; - RendererStorage::Dependency dependency; + Dependency dependency; }; class LightStorage : public RendererLightStorage { @@ -321,6 +321,23 @@ public: virtual bool lightmap_is_interior(RID p_lightmap) const override; virtual void lightmap_set_probe_capture_update_speed(float p_speed) override; virtual float lightmap_get_probe_capture_update_speed() const override; + + /* LIGHT SHADOW MAPPING */ + /* + struct CanvasOccluder { + RID self; + + GLuint vertex_id; // 0 means, unconfigured + GLuint index_id; // 0 means, unconfigured + LocalVector<Vector2> lines; + int len; + }; + + RID_Owner<CanvasOccluder> canvas_occluder_owner; + + RID canvas_light_occluder_create(); + void canvas_light_occluder_set_polylines(RID p_occluder, const LocalVector<Vector2> &p_lines); + */ }; } // namespace GLES3 diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp index fd50bdedbd..8a8d79b3f7 100644 --- a/drivers/gles3/storage/material_storage.cpp +++ b/drivers/gles3/storage/material_storage.cpp @@ -1378,6 +1378,7 @@ MaterialStorage::MaterialStorage() { actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n"; actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n"; actions.usage_defines["LIGHT"] = "#define LIGHT_SHADER_CODE_USED\n"; + actions.usage_defines["SPECULAR_SHININESS"] = "#define SPECULAR_SHININESS_USED\n"; actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n"; @@ -2456,7 +2457,7 @@ void MaterialStorage::shader_set_code(RID p_shader, const String &p_code) { for (Material *E : shader->owners) { Material *material = E; - material->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_MATERIAL); + material->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MATERIAL); _material_queue_update(material, true, true); } } @@ -2593,7 +2594,7 @@ void MaterialStorage::material_set_shader(RID p_material, RID p_shader) { } if (p_shader.is_null()) { - material->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_MATERIAL); + material->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MATERIAL); material->shader_id = 0; return; } @@ -2616,7 +2617,7 @@ void MaterialStorage::material_set_shader(RID p_material, RID p_shader) { material->data->set_next_pass(material->next_pass); material->data->set_render_priority(material->priority); //updating happens later - material->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_MATERIAL); + material->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MATERIAL); _material_queue_update(material, true, true); } @@ -2662,7 +2663,7 @@ void MaterialStorage::material_set_next_pass(RID p_material, RID p_next_material material->data->set_next_pass(p_next_material); } - material->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_MATERIAL); + material->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MATERIAL); } void MaterialStorage::material_set_render_priority(RID p_material, int priority) { @@ -2715,7 +2716,7 @@ void MaterialStorage::material_get_instance_shader_parameters(RID p_material, Li } } -void MaterialStorage::material_update_dependency(RID p_material, RendererStorage::DependencyTracker *p_instance) { +void MaterialStorage::material_update_dependency(RID p_material, DependencyTracker *p_instance) { Material *material = material_owner.get_or_null(p_material); ERR_FAIL_COND(!material); p_instance->update_dependency(&material->dependency); diff --git a/drivers/gles3/storage/material_storage.h b/drivers/gles3/storage/material_storage.h index 09f6680bec..6ad277c2b9 100644 --- a/drivers/gles3/storage/material_storage.h +++ b/drivers/gles3/storage/material_storage.h @@ -37,10 +37,10 @@ #include "core/templates/rid_owner.h" #include "core/templates/self_list.h" #include "servers/rendering/renderer_compositor.h" -#include "servers/rendering/renderer_storage.h" #include "servers/rendering/shader_compiler.h" #include "servers/rendering/shader_language.h" #include "servers/rendering/storage/material_storage.h" +#include "servers/rendering/storage/utilities.h" #include "../shaders/canvas.glsl.gen.h" #include "../shaders/cubemap_filter.glsl.gen.h" @@ -125,7 +125,7 @@ struct Material { RID next_pass; SelfList<Material> update_element; - RendererStorage::Dependency dependency; + Dependency dependency; Material() : update_element(this) {} @@ -453,6 +453,48 @@ public: MaterialStorage(); virtual ~MaterialStorage(); + static _FORCE_INLINE_ void store_transform(const Transform3D &p_mtx, float *p_array) { + p_array[0] = p_mtx.basis.rows[0][0]; + p_array[1] = p_mtx.basis.rows[1][0]; + p_array[2] = p_mtx.basis.rows[2][0]; + p_array[3] = 0; + p_array[4] = p_mtx.basis.rows[0][1]; + p_array[5] = p_mtx.basis.rows[1][1]; + p_array[6] = p_mtx.basis.rows[2][1]; + p_array[7] = 0; + p_array[8] = p_mtx.basis.rows[0][2]; + p_array[9] = p_mtx.basis.rows[1][2]; + p_array[10] = p_mtx.basis.rows[2][2]; + p_array[11] = 0; + p_array[12] = p_mtx.origin.x; + p_array[13] = p_mtx.origin.y; + p_array[14] = p_mtx.origin.z; + p_array[15] = 1; + } + + static _FORCE_INLINE_ void store_transform_3x3(const Basis &p_mtx, float *p_array) { + p_array[0] = p_mtx.rows[0][0]; + p_array[1] = p_mtx.rows[1][0]; + p_array[2] = p_mtx.rows[2][0]; + p_array[3] = 0; + p_array[4] = p_mtx.rows[0][1]; + p_array[5] = p_mtx.rows[1][1]; + p_array[6] = p_mtx.rows[2][1]; + p_array[7] = 0; + p_array[8] = p_mtx.rows[0][2]; + p_array[9] = p_mtx.rows[1][2]; + p_array[10] = p_mtx.rows[2][2]; + p_array[11] = 0; + } + + static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_array) { + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + p_array[i * 4 + j] = p_mtx.matrix[i][j]; + } + } + } + struct Shaders { CanvasShaderGLES3 canvas_shader; SkyShaderGLES3 sky_shader; @@ -534,7 +576,7 @@ public: virtual void material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) override; - virtual void material_update_dependency(RID p_material, RendererStorage::DependencyTracker *p_instance) override; + virtual void material_update_dependency(RID p_material, DependencyTracker *p_instance) override; _FORCE_INLINE_ uint32_t material_get_shader_id(RID p_material) { Material *material = material_owner.get_or_null(p_material); diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp index 822be25337..88b81805fa 100644 --- a/drivers/gles3/storage/mesh_storage.cpp +++ b/drivers/gles3/storage/mesh_storage.cpp @@ -32,6 +32,7 @@ #include "mesh_storage.h" #include "material_storage.h" +#include "utilities.h" using namespace GLES3; @@ -63,6 +64,8 @@ void MeshStorage::mesh_free(RID p_rid) { mesh_clear(p_rid); mesh_set_shadow_mesh(p_rid, RID()); Mesh *mesh = mesh_owner.get_or_null(p_rid); + ERR_FAIL_COND(!mesh); + mesh->dependency.deleted_notify(p_rid); if (mesh->instances.size()) { ERR_PRINT("deleting mesh with active instances"); @@ -71,7 +74,7 @@ void MeshStorage::mesh_free(RID p_rid) { for (Mesh *E : mesh->shadow_owners) { Mesh *shadow_owner = E; shadow_owner->shadow_mesh = RID(); - shadow_owner->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_MESH); + shadow_owner->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MESH); } } mesh_owner.free(p_rid); @@ -230,6 +233,7 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //unbind s->lods[i].edge_length = p_surface.lods[i].edge_length; s->lods[i].index_count = p_surface.lods[i].index_data.size() / (is_index_16 ? 2 : 4); + s->lods[i].index_buffer_size = p_surface.lods[i].index_data.size(); } } } @@ -266,12 +270,12 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) _mesh_instance_add_surface(mi, mesh, mesh->surface_count - 1); } - mesh->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_MESH); + mesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MESH); for (Mesh *E : mesh->shadow_owners) { Mesh *shadow_owner = E; shadow_owner->shadow_mesh = RID(); - shadow_owner->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_MESH); + shadow_owner->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MESH); } mesh->material_cache.clear(); @@ -312,7 +316,7 @@ void MeshStorage::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_mat ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count); mesh->surfaces[p_surface]->material = p_material; - mesh->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_MATERIAL); + mesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MATERIAL); mesh->material_cache.clear(); } @@ -333,48 +337,10 @@ RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const { RS::SurfaceData sd; sd.format = s.format; - { - Vector<uint8_t> ret; - ret.resize(s.vertex_buffer_size); - glBindBuffer(GL_ARRAY_BUFFER, s.vertex_buffer); - -#if defined(__EMSCRIPTEN__) - { - uint8_t *w = ret.ptrw(); - glGetBufferSubData(GL_ARRAY_BUFFER, 0, s.vertex_buffer_size, w); - } -#else - void *data = glMapBufferRange(GL_ARRAY_BUFFER, 0, s.vertex_buffer_size, GL_MAP_READ_BIT); - ERR_FAIL_NULL_V(data, RS::SurfaceData()); - { - uint8_t *w = ret.ptrw(); - memcpy(w, data, s.vertex_buffer_size); - } - glUnmapBuffer(GL_ARRAY_BUFFER); -#endif - sd.vertex_data = ret; - } + sd.vertex_data = Utilities::buffer_get_data(GL_ARRAY_BUFFER, s.vertex_buffer, s.vertex_buffer_size); if (s.attribute_buffer != 0) { - Vector<uint8_t> ret; - ret.resize(s.attribute_buffer_size); - glBindBuffer(GL_ARRAY_BUFFER, s.attribute_buffer); - -#if defined(__EMSCRIPTEN__) - { - uint8_t *w = ret.ptrw(); - glGetBufferSubData(GL_ARRAY_BUFFER, 0, s.attribute_buffer_size, w); - } -#else - void *data = glMapBufferRange(GL_ARRAY_BUFFER, 0, s.attribute_buffer_size, GL_MAP_READ_BIT); - ERR_FAIL_NULL_V(data, RS::SurfaceData()); - { - uint8_t *w = ret.ptrw(); - memcpy(w, data, s.attribute_buffer_size); - } - glUnmapBuffer(GL_ARRAY_BUFFER); -#endif - sd.attribute_data = ret; + sd.attribute_data = Utilities::buffer_get_data(GL_ARRAY_BUFFER, s.attribute_buffer, s.attribute_buffer_size); } sd.vertex_count = s.vertex_count; @@ -382,33 +348,14 @@ RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const { sd.primitive = s.primitive; if (sd.index_count) { - Vector<uint8_t> ret; - ret.resize(s.index_buffer_size); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s.index_buffer); - -#if defined(__EMSCRIPTEN__) - { - uint8_t *w = ret.ptrw(); - glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, s.index_buffer_size, w); - } -#else - void *data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, s.index_buffer_size, GL_MAP_READ_BIT); - ERR_FAIL_NULL_V(data, RS::SurfaceData()); - { - uint8_t *w = ret.ptrw(); - memcpy(w, data, s.index_buffer_size); - } - glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); -#endif - sd.index_data = ret; - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + sd.index_data = Utilities::buffer_get_data(GL_ELEMENT_ARRAY_BUFFER, s.index_buffer, s.index_buffer_size); } sd.aabb = s.aabb; for (uint32_t i = 0; i < s.lod_count; i++) { RS::SurfaceData::LOD lod; lod.edge_length = s.lods[i].edge_length; - //lod.index_data = RD::get_singleton()->buffer_get_data(s.lods[i].index_buffer); + lod.index_data = Utilities::buffer_get_data(GL_ELEMENT_ARRAY_BUFFER, s.lods[i].index_buffer, s.lods[i].index_buffer_size); sd.lods.push_back(lod); } @@ -559,7 +506,7 @@ void MeshStorage::mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) { shadow_mesh->shadow_owners.insert(mesh); } - mesh->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_MESH); + mesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MESH); } void MeshStorage::mesh_clear(RID p_mesh) { @@ -608,12 +555,12 @@ void MeshStorage::mesh_clear(RID p_mesh) { _mesh_instance_clear(mi); } mesh->has_bone_weights = false; - mesh->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_MESH); + mesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MESH); for (Mesh *E : mesh->shadow_owners) { Mesh *shadow_owner = E; shadow_owner->shadow_mesh = RID(); - shadow_owner->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_MESH); + shadow_owner->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MESH); } } @@ -723,17 +670,6 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V for (int i = 0; i < RS::ARRAY_INDEX; i++) { if (!attribs[i].enabled) { glDisableVertexAttribArray(i); - if (s->format & RS::ARRAY_FLAG_USE_2D_VERTICES) { - if (i == RS::ARRAY_COLOR) { - glVertexAttrib4f(i, 1, 1, 1, 1); - } else if (i == RS::ARRAY_TEX_UV) { - glVertexAttrib2f(i, 1, 1); - } else if (i == RS::ARRAY_BONES) { - glVertexAttrib4f(i, 1, 1, 1, 1); - } else if (i == RS::ARRAY_WEIGHTS) { - glVertexAttrib4f(i, 1, 1, 1, 1); - } - } continue; } if (i <= RS::ARRAY_TANGENT) { @@ -949,8 +885,8 @@ void MeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instances, RS:: multimesh->uses_colors = p_use_colors; multimesh->color_offset_cache = p_transform_format == RS::MULTIMESH_TRANSFORM_2D ? 8 : 12; multimesh->uses_custom_data = p_use_custom_data; - multimesh->custom_data_offset_cache = multimesh->color_offset_cache + (p_use_colors ? 4 : 0); - multimesh->stride_cache = multimesh->custom_data_offset_cache + (p_use_custom_data ? 4 : 0); + multimesh->custom_data_offset_cache = multimesh->color_offset_cache + (p_use_colors ? 2 : 0); + multimesh->stride_cache = multimesh->custom_data_offset_cache + (p_use_custom_data ? 2 : 0); multimesh->buffer_set = false; multimesh->data_cache = Vector<float>(); @@ -965,7 +901,7 @@ void MeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instances, RS:: glBindBuffer(GL_ARRAY_BUFFER, 0); } - multimesh->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_MULTIMESH); + multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MULTIMESH); } int MeshStorage::multimesh_get_instance_count(RID p_multimesh) const { @@ -977,7 +913,7 @@ int MeshStorage::multimesh_get_instance_count(RID p_multimesh) const { void MeshStorage::multimesh_set_mesh(RID p_multimesh, RID p_mesh) { MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); ERR_FAIL_COND(!multimesh); - if (multimesh->mesh == p_mesh) { + if (multimesh->mesh == p_mesh || p_mesh.is_null()) { return; } multimesh->mesh = p_mesh; @@ -990,17 +926,16 @@ void MeshStorage::multimesh_set_mesh(RID p_multimesh, RID p_mesh) { //we have a data cache, just mark it dirty _multimesh_mark_all_dirty(multimesh, false, true); } else if (multimesh->instances) { - //need to re-create AABB unfortunately, calling this has a penalty + // Need to re-create AABB. Unfortunately, calling this has a penalty. if (multimesh->buffer_set) { - // TODO add a function to RasterizerStorage to get data from a buffer - //Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer); - //const uint8_t *r = buffer.ptr(); - //const float *data = (const float *)r; - //_multimesh_re_create_aabb(multimesh, data, multimesh->instances); + Vector<uint8_t> buffer = Utilities::buffer_get_data(GL_ARRAY_BUFFER, multimesh->buffer, multimesh->instances * multimesh->stride_cache * sizeof(float)); + const uint8_t *r = buffer.ptr(); + const float *data = (const float *)r; + _multimesh_re_create_aabb(multimesh, data, multimesh->instances); } } - multimesh->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_MESH); + multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MESH); } #define MULTIMESH_DIRTY_REGION_SIZE 512 @@ -1017,10 +952,11 @@ void MeshStorage::_multimesh_make_local(MultiMesh *multimesh) const { float *w = multimesh->data_cache.ptrw(); if (multimesh->buffer_set) { - //Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer); + Vector<uint8_t> buffer = Utilities::buffer_get_data(GL_ARRAY_BUFFER, multimesh->buffer, multimesh->instances * multimesh->stride_cache * sizeof(float)); + { - // const uint8_t *r = buffer.ptr(); - // memcpy(w, r, buffer.size()); + const uint8_t *r = buffer.ptr(); + memcpy(w, r, buffer.size()); } } else { memset(w, 0, (size_t)multimesh->instances * multimesh->stride_cache * sizeof(float)); @@ -1186,14 +1122,12 @@ void MeshStorage::multimesh_instance_set_color(RID p_multimesh, int p_index, con _multimesh_make_local(multimesh); { + // Colors are packed into 2 floats. float *w = multimesh->data_cache.ptrw(); float *dataptr = w + p_index * multimesh->stride_cache + multimesh->color_offset_cache; - - dataptr[0] = p_color.r; - dataptr[1] = p_color.g; - dataptr[2] = p_color.b; - dataptr[3] = p_color.a; + uint16_t val[4] = { Math::make_half_float(p_color.r), Math::make_half_float(p_color.g), Math::make_half_float(p_color.b), Math::make_half_float(p_color.a) }; + memcpy(dataptr, val, 2 * 4); } _multimesh_mark_dirty(multimesh, p_index, false); @@ -1211,11 +1145,8 @@ void MeshStorage::multimesh_instance_set_custom_data(RID p_multimesh, int p_inde float *w = multimesh->data_cache.ptrw(); float *dataptr = w + p_index * multimesh->stride_cache + multimesh->custom_data_offset_cache; - - dataptr[0] = p_color.r; - dataptr[1] = p_color.g; - dataptr[2] = p_color.b; - dataptr[3] = p_color.a; + uint16_t val[4] = { Math::make_half_float(p_color.r), Math::make_half_float(p_color.g), Math::make_half_float(p_color.b), Math::make_half_float(p_color.a) }; + memcpy(dataptr, val, 2 * 4); } _multimesh_mark_dirty(multimesh, p_index, false); @@ -1306,11 +1237,12 @@ Color MeshStorage::multimesh_instance_get_color(RID p_multimesh, int p_index) co const float *r = multimesh->data_cache.ptr(); const float *dataptr = r + p_index * multimesh->stride_cache + multimesh->color_offset_cache; - - c.r = dataptr[0]; - c.g = dataptr[1]; - c.b = dataptr[2]; - c.a = dataptr[3]; + uint16_t raw_data[4]; + memcpy(raw_data, dataptr, 2 * 4); + c.r = Math::half_to_float(raw_data[0]); + c.g = Math::half_to_float(raw_data[1]); + c.b = Math::half_to_float(raw_data[2]); + c.a = Math::half_to_float(raw_data[3]); } return c; @@ -1329,11 +1261,12 @@ Color MeshStorage::multimesh_instance_get_custom_data(RID p_multimesh, int p_ind const float *r = multimesh->data_cache.ptr(); const float *dataptr = r + p_index * multimesh->stride_cache + multimesh->custom_data_offset_cache; - - c.r = dataptr[0]; - c.g = dataptr[1]; - c.b = dataptr[2]; - c.a = dataptr[3]; + uint16_t raw_data[4]; + memcpy(raw_data, dataptr, 2 * 4); + c.r = Math::half_to_float(raw_data[0]); + c.g = Math::half_to_float(raw_data[1]); + c.b = Math::half_to_float(raw_data[2]); + c.a = Math::half_to_float(raw_data[3]); } return c; @@ -1342,19 +1275,66 @@ Color MeshStorage::multimesh_instance_get_custom_data(RID p_multimesh, int p_ind void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) { MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); ERR_FAIL_COND(!multimesh); - ERR_FAIL_COND(p_buffer.size() != (multimesh->instances * (int)multimesh->stride_cache)); - { + if (multimesh->uses_colors || multimesh->uses_custom_data) { + // Color and custom need to be packed so copy buffer to data_cache and pack. + + _multimesh_make_local(multimesh); + multimesh->data_cache = p_buffer; + + float *w = multimesh->data_cache.ptrw(); + uint32_t old_stride = multimesh->xform_format == RS::MULTIMESH_TRANSFORM_2D ? 8 : 12; + old_stride += multimesh->uses_colors ? 4 : 0; + old_stride += multimesh->uses_custom_data ? 4 : 0; + for (int i = 0; i < multimesh->instances; i++) { + { + float *dataptr = w + i * old_stride; + float *newptr = w + i * multimesh->stride_cache; + float vals[8] = { dataptr[0], dataptr[1], dataptr[2], dataptr[3], dataptr[4], dataptr[5], dataptr[6], dataptr[7] }; + memcpy(newptr, vals, 8 * 4); + } + + if (multimesh->xform_format == RS::MULTIMESH_TRANSFORM_3D) { + float *dataptr = w + i * old_stride + 8; + float *newptr = w + i * multimesh->stride_cache + 8; + float vals[8] = { dataptr[0], dataptr[1], dataptr[2], dataptr[3] }; + memcpy(newptr, vals, 4 * 4); + } + + if (multimesh->uses_colors) { + float *dataptr = w + i * old_stride + (multimesh->xform_format == RS::MULTIMESH_TRANSFORM_2D ? 8 : 12); + float *newptr = w + i * multimesh->stride_cache + multimesh->color_offset_cache; + uint16_t val[4] = { Math::make_half_float(dataptr[0]), Math::make_half_float(dataptr[1]), Math::make_half_float(dataptr[2]), Math::make_half_float(dataptr[3]) }; + memcpy(newptr, val, 2 * 4); + } + if (multimesh->uses_custom_data) { + float *dataptr = w + i * old_stride + (multimesh->xform_format == RS::MULTIMESH_TRANSFORM_2D ? 8 : 12) + (multimesh->uses_colors ? 4 : 0); + float *newptr = w + i * multimesh->stride_cache + multimesh->custom_data_offset_cache; + uint16_t val[4] = { Math::make_half_float(dataptr[0]), Math::make_half_float(dataptr[1]), Math::make_half_float(dataptr[2]), Math::make_half_float(dataptr[3]) }; + memcpy(newptr, val, 2 * 4); + } + } + + multimesh->data_cache.resize(multimesh->instances * (int)multimesh->stride_cache); + const float *r = multimesh->data_cache.ptr(); + glBindBuffer(GL_ARRAY_BUFFER, multimesh->buffer); + glBufferData(GL_ARRAY_BUFFER, multimesh->data_cache.size() * sizeof(float), r, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + } else { + // Only Transform is being used, so we can upload directly. + ERR_FAIL_COND(p_buffer.size() != (multimesh->instances * (int)multimesh->stride_cache)); const float *r = p_buffer.ptr(); glBindBuffer(GL_ARRAY_BUFFER, multimesh->buffer); glBufferData(GL_ARRAY_BUFFER, p_buffer.size() * sizeof(float), r, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); - multimesh->buffer_set = true; } - if (multimesh->data_cache.size()) { + multimesh->buffer_set = true; + + if (multimesh->data_cache.size() || multimesh->uses_colors || multimesh->uses_custom_data) { //if we have a data cache, just update it - multimesh->data_cache = p_buffer; + multimesh->data_cache = multimesh->data_cache; { //clear dirty since nothing will be dirty anymore uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; @@ -1367,32 +1347,81 @@ void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_b _multimesh_mark_all_dirty(multimesh, false, true); //update AABB } else if (multimesh->mesh.is_valid()) { //if we have a mesh set, we need to re-generate the AABB from the new data - const float *data = p_buffer.ptr(); + const float *data = multimesh->data_cache.ptr(); _multimesh_re_create_aabb(multimesh, data, multimesh->instances); - multimesh->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_AABB); + multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB); } } Vector<float> MeshStorage::multimesh_get_buffer(RID p_multimesh) const { MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); ERR_FAIL_COND_V(!multimesh, Vector<float>()); + Vector<float> ret; if (multimesh->buffer == 0) { return Vector<float>(); } else if (multimesh->data_cache.size()) { - return multimesh->data_cache; + ret = multimesh->data_cache; } else { - //get from memory + // Buffer not cached, so fetch from GPU memory. This can be a stalling operation, avoid whenever possible. - //Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer); - Vector<float> ret; + Vector<uint8_t> buffer = Utilities::buffer_get_data(GL_ARRAY_BUFFER, multimesh->buffer, multimesh->instances * multimesh->stride_cache * sizeof(float)); ret.resize(multimesh->instances * multimesh->stride_cache); - //{ - // float *w = ret.ptrw(); - // const uint8_t *r = buffer.ptr(); - // memcpy(w, r, buffer.size()); - //} + { + float *w = ret.ptrw(); + const uint8_t *r = buffer.ptr(); + memcpy(w, r, buffer.size()); + } + } + if (multimesh->uses_colors || multimesh->uses_custom_data) { + // Need to decompress buffer. + uint32_t new_stride = multimesh->xform_format == RS::MULTIMESH_TRANSFORM_2D ? 8 : 12; + new_stride += multimesh->uses_colors ? 4 : 0; + new_stride += multimesh->uses_custom_data ? 4 : 0; + + Vector<float> decompressed; + decompressed.resize(multimesh->instances * (int)new_stride); + float *w = decompressed.ptrw(); + const float *r = ret.ptr(); + + for (int i = 0; i < multimesh->instances; i++) { + { + float *newptr = w + i * new_stride; + const float *oldptr = r + i * multimesh->stride_cache; + float vals[8] = { oldptr[0], oldptr[1], oldptr[2], oldptr[3], oldptr[4], oldptr[5], oldptr[6], oldptr[7] }; + memcpy(newptr, vals, 8 * 4); + } + + if (multimesh->xform_format == RS::MULTIMESH_TRANSFORM_3D) { + float *newptr = w + i * new_stride + 8; + const float *oldptr = r + i * multimesh->stride_cache + 8; + float vals[8] = { oldptr[0], oldptr[1], oldptr[2], oldptr[3] }; + memcpy(newptr, vals, 4 * 4); + } + if (multimesh->uses_colors) { + float *newptr = w + i * new_stride + (multimesh->xform_format == RS::MULTIMESH_TRANSFORM_2D ? 8 : 12); + const float *oldptr = r + i * multimesh->stride_cache + multimesh->color_offset_cache; + uint16_t raw_data[4]; + memcpy(raw_data, oldptr, 2 * 4); + newptr[0] = Math::half_to_float(raw_data[0]); + newptr[1] = Math::half_to_float(raw_data[1]); + newptr[2] = Math::half_to_float(raw_data[2]); + newptr[3] = Math::half_to_float(raw_data[3]); + } + if (multimesh->uses_custom_data) { + float *newptr = w + i * new_stride + (multimesh->xform_format == RS::MULTIMESH_TRANSFORM_2D ? 8 : 12) + (multimesh->uses_colors ? 4 : 0); + const float *oldptr = r + i * multimesh->stride_cache + multimesh->custom_data_offset_cache; + uint16_t raw_data[4]; + memcpy(raw_data, oldptr, 2 * 4); + newptr[0] = Math::half_to_float(raw_data[0]); + newptr[1] = Math::half_to_float(raw_data[1]); + newptr[2] = Math::half_to_float(raw_data[2]); + newptr[3] = Math::half_to_float(raw_data[3]); + } + } + return decompressed; + } else { return ret; } } @@ -1412,7 +1441,7 @@ void MeshStorage::multimesh_set_visible_instances(RID p_multimesh, int p_visible multimesh->visible_instances = p_visible; - multimesh->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES); + multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES); } int MeshStorage::multimesh_get_visible_instances(RID p_multimesh) const { @@ -1439,7 +1468,7 @@ void MeshStorage::_update_dirty_multimeshes() { if (multimesh->data_cache_used_dirty_regions > 32 || multimesh->data_cache_used_dirty_regions > visible_region_count / 2) { // If there too many dirty regions, or represent the majority of regions, just copy all, else transfer cost piles up too much glBindBuffer(GL_ARRAY_BUFFER, multimesh->buffer); - glBufferData(GL_ARRAY_BUFFER, MIN(visible_region_count * region_size, multimesh->instances * (uint32_t)multimesh->stride_cache * (uint32_t)sizeof(float)), data, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, MIN(visible_region_count * region_size, multimesh->instances * multimesh->stride_cache * sizeof(float)), data, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); } else { // Not that many regions? update them all @@ -1463,11 +1492,10 @@ void MeshStorage::_update_dirty_multimeshes() { multimesh->data_cache_used_dirty_regions = 0; } - if (multimesh->aabb_dirty) { - //aabb is dirty.. + if (multimesh->aabb_dirty && multimesh->mesh.is_valid()) { _multimesh_re_create_aabb(multimesh, data, visible_instances); multimesh->aabb_dirty = false; - multimesh->dependency.changed_notify(RendererStorage::DEPENDENCY_CHANGED_AABB); + multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB); } } @@ -1516,7 +1544,12 @@ Transform2D MeshStorage::skeleton_bone_get_transform_2d(RID p_skeleton, int p_bo return Transform2D(); } -void MeshStorage::skeleton_update_dependency(RID p_base, RendererStorage::DependencyTracker *p_instance) { +void MeshStorage::skeleton_update_dependency(RID p_base, DependencyTracker *p_instance) { +} + +/* OCCLUDER */ + +void MeshStorage::occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) { } #endif // GLES3_ENABLED diff --git a/drivers/gles3/storage/mesh_storage.h b/drivers/gles3/storage/mesh_storage.h index 068aa2fe40..c51cd5dcd6 100644 --- a/drivers/gles3/storage/mesh_storage.h +++ b/drivers/gles3/storage/mesh_storage.h @@ -37,6 +37,7 @@ #include "core/templates/rid_owner.h" #include "core/templates/self_list.h" #include "servers/rendering/storage/mesh_storage.h" +#include "servers/rendering/storage/utilities.h" #include "platform_config.h" #ifndef OPENGL_INCLUDE_H @@ -90,6 +91,7 @@ struct Mesh { struct LOD { float edge_length = 0.0; uint32_t index_count = 0; + uint32_t index_buffer_size = 0; GLuint index_buffer; }; @@ -125,7 +127,7 @@ struct Mesh { RID shadow_mesh; HashSet<Mesh *> shadow_owners; - RendererStorage::Dependency dependency; + Dependency dependency; }; /* Mesh Instance */ @@ -178,7 +180,7 @@ struct MultiMesh { bool dirty = false; MultiMesh *dirty_list = nullptr; - RendererStorage::Dependency dependency; + Dependency dependency; }; struct Skeleton { @@ -193,7 +195,7 @@ struct Skeleton { uint64_t version = 1; - RendererStorage::Dependency dependency; + Dependency dependency; }; class MeshStorage : public RendererMeshStorage { @@ -530,7 +532,11 @@ public: virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) override; virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const override; - virtual void skeleton_update_dependency(RID p_base, RendererStorage::DependencyTracker *p_instance) override; + virtual void skeleton_update_dependency(RID p_base, DependencyTracker *p_instance) override; + + /* OCCLUDER */ + + void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices); }; } // namespace GLES3 diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp index 42c80da39a..c05f516548 100644 --- a/drivers/gles3/storage/texture_storage.cpp +++ b/drivers/gles3/storage/texture_storage.cpp @@ -183,6 +183,12 @@ TextureStorage::TextureStorage() { texture.gl_set_filter(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST); } } + + glBindTexture(GL_TEXTURE_2D, 0); + +#ifdef GLES_OVER_GL + glEnable(GL_PROGRAM_POINT_SIZE); +#endif } TextureStorage::~TextureStorage() { @@ -244,6 +250,55 @@ void TextureStorage::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS: ct->texture_repeat = p_repeat; } +/* CANVAS SHADOW */ + +RID TextureStorage::canvas_light_shadow_buffer_create(int p_width) { + Config *config = Config::get_singleton(); + CanvasLightShadow *cls = memnew(CanvasLightShadow); + + if (p_width > config->max_texture_size) { + p_width = config->max_texture_size; + } + + cls->size = p_width; + cls->height = 16; + + glActiveTexture(GL_TEXTURE0); + + glGenFramebuffers(1, &cls->fbo); + glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo); + + glGenRenderbuffers(1, &cls->depth); + glBindRenderbuffer(GL_RENDERBUFFER, cls->depth); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, cls->size, cls->height); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, cls->depth); + + glGenTextures(1, &cls->distance); + glBindTexture(GL_TEXTURE_2D, cls->distance); + if (config->use_rgba_2d_shadows) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, cls->size, cls->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + } else { + glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, cls->size, cls->height, 0, GL_RED, GL_FLOAT, nullptr); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, cls->distance, 0); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + //printf("errnum: %x\n",status); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); + + if (status != GL_FRAMEBUFFER_COMPLETE) { + memdelete(cls); + ERR_FAIL_COND_V(status != GL_FRAMEBUFFER_COMPLETE, RID()); + } + + return canvas_light_shadow_owner.make_rid(cls); +} + /* Texture API */ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_force_decompress) const { diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h index d6d04e45a1..b5d5641086 100644 --- a/drivers/gles3/storage/texture_storage.h +++ b/drivers/gles3/storage/texture_storage.h @@ -132,6 +132,17 @@ struct CanvasTexture { bool cleared_cache = true; }; +/* CANVAS SHADOW */ + +struct CanvasLightShadow { + RID self; + int size; + int height; + GLuint fbo; + GLuint depth; + GLuint distance; //for older devices +}; + struct RenderTarget; struct Texture { @@ -364,6 +375,10 @@ private: RID_Owner<CanvasTexture, true> canvas_texture_owner; + /* CANVAS SHADOW */ + + RID_PtrOwner<CanvasLightShadow> canvas_light_shadow_owner; + /* Texture API */ mutable RID_Owner<Texture> texture_owner; @@ -403,6 +418,10 @@ public: virtual void canvas_texture_set_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) override; virtual void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) override; + /* CANVAS SHADOW */ + + RID canvas_light_shadow_buffer_create(int p_width); + /* Texture API */ Texture *get_texture(RID p_rid) { @@ -527,6 +546,16 @@ public: void render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps); void render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color); void render_target_gen_back_buffer_mipmaps(RID p_render_target, const Rect2i &p_region); + virtual void render_target_set_vrs_mode(RID p_render_target, RS::ViewportVRSMode p_mode) override{}; + virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override{}; + + void bind_framebuffer(GLuint framebuffer) { + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); + } + + void bind_framebuffer_system() { + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); + } String get_framebuffer_error(GLenum p_status); }; diff --git a/drivers/gles3/storage/utilities.cpp b/drivers/gles3/storage/utilities.cpp new file mode 100644 index 0000000000..a00210a2ab --- /dev/null +++ b/drivers/gles3/storage/utilities.cpp @@ -0,0 +1,353 @@ +/*************************************************************************/ +/* utilities.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifdef GLES3_ENABLED + +#include "utilities.h" +#include "config.h" +#include "light_storage.h" +#include "material_storage.h" +#include "mesh_storage.h" +#include "particles_storage.h" +#include "texture_storage.h" + +using namespace GLES3; + +Utilities *Utilities::singleton = nullptr; + +Utilities::Utilities() { + singleton = this; +} + +Utilities::~Utilities() { + singleton = nullptr; +} + +Vector<uint8_t> Utilities::buffer_get_data(GLenum p_target, GLuint p_buffer, uint32_t p_buffer_size) { + Vector<uint8_t> ret; + ret.resize(p_buffer_size); + glBindBuffer(p_target, p_buffer); + +#if defined(__EMSCRIPTEN__) + { + uint8_t *w = ret.ptrw(); + glGetBufferSubData(p_target, 0, p_buffer_size, w); + } +#else + void *data = glMapBufferRange(p_target, 0, p_buffer_size, GL_MAP_READ_BIT); + ERR_FAIL_NULL_V(data, Vector<uint8_t>()); + { + uint8_t *w = ret.ptrw(); + memcpy(w, data, p_buffer_size); + } + glUnmapBuffer(p_target); +#endif + glBindBuffer(p_target, 0); + return ret; +} + +/* INSTANCES */ + +RS::InstanceType Utilities::get_base_type(RID p_rid) const { + if (GLES3::MeshStorage::get_singleton()->owns_mesh(p_rid)) { + return RS::INSTANCE_MESH; + } else if (GLES3::MeshStorage::get_singleton()->owns_multimesh(p_rid)) { + return RS::INSTANCE_MULTIMESH; + } else if (GLES3::LightStorage::get_singleton()->owns_light(p_rid)) { + return RS::INSTANCE_LIGHT; + } + return RS::INSTANCE_NONE; +} + +bool Utilities::free(RID p_rid) { + if (GLES3::TextureStorage::get_singleton()->owns_render_target(p_rid)) { + GLES3::TextureStorage::get_singleton()->render_target_free(p_rid); + return true; + } else if (GLES3::TextureStorage::get_singleton()->owns_texture(p_rid)) { + GLES3::TextureStorage::get_singleton()->texture_free(p_rid); + return true; + } else if (GLES3::TextureStorage::get_singleton()->owns_canvas_texture(p_rid)) { + GLES3::TextureStorage::get_singleton()->canvas_texture_free(p_rid); + return true; + } else if (GLES3::MaterialStorage::get_singleton()->owns_shader(p_rid)) { + GLES3::MaterialStorage::get_singleton()->shader_free(p_rid); + return true; + } else if (GLES3::MaterialStorage::get_singleton()->owns_material(p_rid)) { + GLES3::MaterialStorage::get_singleton()->material_free(p_rid); + return true; + } else if (GLES3::MeshStorage::get_singleton()->owns_mesh(p_rid)) { + GLES3::MeshStorage::get_singleton()->mesh_free(p_rid); + return true; + } else if (GLES3::MeshStorage::get_singleton()->owns_multimesh(p_rid)) { + GLES3::MeshStorage::get_singleton()->multimesh_free(p_rid); + return true; + } else if (GLES3::MeshStorage::get_singleton()->owns_mesh_instance(p_rid)) { + GLES3::MeshStorage::get_singleton()->mesh_instance_free(p_rid); + return true; + } else if (GLES3::LightStorage::get_singleton()->owns_light(p_rid)) { + GLES3::LightStorage::get_singleton()->light_free(p_rid); + return true; + } else { + return false; + } + /* + else if (reflection_probe_owner.owns(p_rid)) { + // delete the texture + ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_rid); + reflection_probe->instance_remove_deps(); + + reflection_probe_owner.free(p_rid); + memdelete(reflection_probe); + + return true; + } else if (lightmap_capture_data_owner.owns(p_rid)) { + // delete the texture + LightmapCapture *lightmap_capture = lightmap_capture_data_owner.get_or_null(p_rid); + lightmap_capture->instance_remove_deps(); + + lightmap_capture_data_owner.free(p_rid); + memdelete(lightmap_capture); + return true; + + } else if (canvas_occluder_owner.owns(p_rid)) { + CanvasOccluder *co = canvas_occluder_owner.get_or_null(p_rid); + if (co->index_id) { + glDeleteBuffers(1, &co->index_id); + } + if (co->vertex_id) { + glDeleteBuffers(1, &co->vertex_id); + } + + canvas_occluder_owner.free(p_rid); + memdelete(co); + + return true; + + } else if (canvas_light_shadow_owner.owns(p_rid)) { + CanvasLightShadow *cls = canvas_light_shadow_owner.get_or_null(p_rid); + glDeleteFramebuffers(1, &cls->fbo); + glDeleteRenderbuffers(1, &cls->depth); + glDeleteTextures(1, &cls->distance); + canvas_light_shadow_owner.free(p_rid); + memdelete(cls); + + return true; + } + */ +} + +/* DEPENDENCIES */ + +void Utilities::base_update_dependency(RID p_base, DependencyTracker *p_instance) { + if (MeshStorage::get_singleton()->owns_mesh(p_base)) { + Mesh *mesh = MeshStorage::get_singleton()->get_mesh(p_base); + p_instance->update_dependency(&mesh->dependency); + } else if (MeshStorage::get_singleton()->owns_multimesh(p_base)) { + MultiMesh *multimesh = MeshStorage::get_singleton()->get_multimesh(p_base); + p_instance->update_dependency(&multimesh->dependency); + if (multimesh->mesh.is_valid()) { + base_update_dependency(multimesh->mesh, p_instance); + } + } else if (LightStorage::get_singleton()->owns_light(p_base)) { + Light *l = LightStorage::get_singleton()->get_light(p_base); + p_instance->update_dependency(&l->dependency); + } +} + +/* VISIBILITY NOTIFIER */ + +RID Utilities::visibility_notifier_allocate() { + return RID(); +} + +void Utilities::visibility_notifier_initialize(RID p_notifier) { +} + +void Utilities::visibility_notifier_free(RID p_notifier) { +} + +void Utilities::visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) { +} + +void Utilities::visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) { +} + +AABB Utilities::visibility_notifier_get_aabb(RID p_notifier) const { + return AABB(); +} + +void Utilities::visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) { +} + +/* TIMING */ + +//void Utilities::render_info_begin_capture() { +// info.snap = info.render; +//} + +//void Utilities::render_info_end_capture() { +// info.snap.object_count = info.render.object_count - info.snap.object_count; +// info.snap.draw_call_count = info.render.draw_call_count - info.snap.draw_call_count; +// info.snap.material_switch_count = info.render.material_switch_count - info.snap.material_switch_count; +// info.snap.surface_switch_count = info.render.surface_switch_count - info.snap.surface_switch_count; +// info.snap.shader_rebind_count = info.render.shader_rebind_count - info.snap.shader_rebind_count; +// info.snap.vertices_count = info.render.vertices_count - info.snap.vertices_count; +// info.snap._2d_item_count = info.render._2d_item_count - info.snap._2d_item_count; +// info.snap._2d_draw_call_count = info.render._2d_draw_call_count - info.snap._2d_draw_call_count; +//} + +//int Utilities::get_captured_render_info(RS::RenderInfo p_info) { +// switch (p_info) { +// case RS::INFO_OBJECTS_IN_FRAME: { +// return info.snap.object_count; +// } break; +// case RS::INFO_VERTICES_IN_FRAME: { +// return info.snap.vertices_count; +// } break; +// case RS::INFO_MATERIAL_CHANGES_IN_FRAME: { +// return info.snap.material_switch_count; +// } break; +// case RS::INFO_SHADER_CHANGES_IN_FRAME: { +// return info.snap.shader_rebind_count; +// } break; +// case RS::INFO_SURFACE_CHANGES_IN_FRAME: { +// return info.snap.surface_switch_count; +// } break; +// case RS::INFO_DRAW_CALLS_IN_FRAME: { +// return info.snap.draw_call_count; +// } break; +// /* +// case RS::INFO_2D_ITEMS_IN_FRAME: { +// return info.snap._2d_item_count; +// } break; +// case RS::INFO_2D_DRAW_CALLS_IN_FRAME: { +// return info.snap._2d_draw_call_count; +// } break; +// */ +// default: { +// return get_render_info(p_info); +// } +// } +//} + +//int Utilities::get_render_info(RS::RenderInfo p_info) { +// switch (p_info) { +// case RS::INFO_OBJECTS_IN_FRAME: +// return info.render_final.object_count; +// case RS::INFO_VERTICES_IN_FRAME: +// return info.render_final.vertices_count; +// case RS::INFO_MATERIAL_CHANGES_IN_FRAME: +// return info.render_final.material_switch_count; +// case RS::INFO_SHADER_CHANGES_IN_FRAME: +// return info.render_final.shader_rebind_count; +// case RS::INFO_SURFACE_CHANGES_IN_FRAME: +// return info.render_final.surface_switch_count; +// case RS::INFO_DRAW_CALLS_IN_FRAME: +// return info.render_final.draw_call_count; +// /* +// case RS::INFO_2D_ITEMS_IN_FRAME: +// return info.render_final._2d_item_count; +// case RS::INFO_2D_DRAW_CALLS_IN_FRAME: +// return info.render_final._2d_draw_call_count; +//*/ +// case RS::INFO_USAGE_VIDEO_MEM_TOTAL: +// return 0; //no idea +// case RS::INFO_VIDEO_MEM_USED: +// return info.vertex_mem + info.texture_mem; +// case RS::INFO_TEXTURE_MEM_USED: +// return info.texture_mem; +// case RS::INFO_VERTEX_MEM_USED: +// return info.vertex_mem; +// default: +// return 0; //no idea either +// } +//} + +/* MISC */ + +void Utilities::update_dirty_resources() { + MaterialStorage::get_singleton()->_update_global_variables(); + MaterialStorage::get_singleton()->_update_queued_materials(); + //MeshStorage::get_singleton()->_update_dirty_skeletons(); + MeshStorage::get_singleton()->_update_dirty_multimeshes(); +} + +void Utilities::set_debug_generate_wireframes(bool p_generate) { +} + +bool Utilities::has_os_feature(const String &p_feature) const { + Config *config = Config::get_singleton(); + if (!config) { + return false; + } + + if (p_feature == "rgtc") { + return config->rgtc_supported; + } + + if (p_feature == "s3tc") { + return config->s3tc_supported; + } + + if (p_feature == "bptc") { + return config->bptc_supported; + } + + if (p_feature == "etc" || p_feature == "etc2") { + return config->etc2_supported; + } + + return false; +} + +void Utilities::update_memory_info() { +} + +uint64_t Utilities::get_rendering_info(RS::RenderingInfo p_info) { + return 0; +} + +String Utilities::get_video_adapter_name() const { + return (const char *)glGetString(GL_RENDERER); +} + +String Utilities::get_video_adapter_vendor() const { + return (const char *)glGetString(GL_VENDOR); +} + +RenderingDevice::DeviceType Utilities::get_video_adapter_type() const { + return RenderingDevice::DeviceType::DEVICE_TYPE_OTHER; +} + +String Utilities::get_video_adapter_api_version() const { + return (const char *)glGetString(GL_VERSION); +} + +#endif // GLES3_ENABLED diff --git a/drivers/gles3/storage/utilities.h b/drivers/gles3/storage/utilities.h new file mode 100644 index 0000000000..523033886c --- /dev/null +++ b/drivers/gles3/storage/utilities.h @@ -0,0 +1,159 @@ +/*************************************************************************/ +/* utilities.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef UTILITIES_GLES3_H +#define UTILITIES_GLES3_H + +#ifdef GLES3_ENABLED + +#include "servers/rendering/storage/utilities.h" + +#include "platform_config.h" +#ifndef OPENGL_INCLUDE_H +#include <GLES3/gl3.h> +#else +#include OPENGL_INCLUDE_H +#endif + +namespace GLES3 { + +class Utilities : public RendererUtilities { +private: + static Utilities *singleton; + +public: + static Utilities *get_singleton() { return singleton; } + + Utilities(); + ~Utilities(); + + // Buffer size is specified in bytes + static Vector<uint8_t> buffer_get_data(GLenum p_target, GLuint p_buffer, uint32_t p_buffer_size); + + /* INSTANCES */ + + virtual RS::InstanceType get_base_type(RID p_rid) const override; + virtual bool free(RID p_rid) override; + + /* DEPENDENCIES */ + + virtual void base_update_dependency(RID p_base, DependencyTracker *p_instance) override; + + /* VISIBILITY NOTIFIER */ + virtual RID visibility_notifier_allocate() override; + virtual void visibility_notifier_initialize(RID p_notifier) override; + virtual void visibility_notifier_free(RID p_notifier) override; + + virtual void visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) override; + virtual void visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) override; + + virtual AABB visibility_notifier_get_aabb(RID p_notifier) const override; + virtual void visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) override; + + /* TIMING */ + + struct Info { + uint64_t texture_mem = 0; + uint64_t vertex_mem = 0; + + struct Render { + uint32_t object_count; + uint32_t draw_call_count; + uint32_t material_switch_count; + uint32_t surface_switch_count; + uint32_t shader_rebind_count; + uint32_t vertices_count; + uint32_t _2d_item_count; + uint32_t _2d_draw_call_count; + + void reset() { + object_count = 0; + draw_call_count = 0; + material_switch_count = 0; + surface_switch_count = 0; + shader_rebind_count = 0; + vertices_count = 0; + _2d_item_count = 0; + _2d_draw_call_count = 0; + } + } render, render_final, snap; + + Info() { + render.reset(); + render_final.reset(); + } + + } info; + + virtual void capture_timestamps_begin() override {} + virtual void capture_timestamp(const String &p_name) override {} + virtual uint32_t get_captured_timestamps_count() const override { + return 0; + } + virtual uint64_t get_captured_timestamps_frame() const override { + return 0; + } + virtual uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const override { + return 0; + } + virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const override { + return 0; + } + virtual String get_captured_timestamp_name(uint32_t p_index) const override { + return String(); + } + + // void render_info_begin_capture() override; + // void render_info_end_capture() override; + // int get_captured_render_info(RS::RenderInfo p_info) override; + + // int get_render_info(RS::RenderInfo p_info) override; + + /* MISC */ + + virtual void update_dirty_resources() override; + virtual void set_debug_generate_wireframes(bool p_generate) override; + + virtual bool has_os_feature(const String &p_feature) const override; + + virtual void update_memory_info() override; + + virtual uint64_t get_rendering_info(RS::RenderingInfo p_info) override; + virtual String get_video_adapter_name() const override; + virtual String get_video_adapter_vendor() const override; + virtual RenderingDevice::DeviceType get_video_adapter_type() const override; + virtual String get_video_adapter_api_version() const override; +}; + +} // namespace GLES3 + +#endif // GLES3_ENABLED + +#endif // !UTILITIES_GLES3_H diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp index 7e6105f033..39dbadf3cd 100644 --- a/drivers/unix/dir_access_unix.cpp +++ b/drivers/unix/dir_access_unix.cpp @@ -33,6 +33,7 @@ #if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) #include "core/os/memory.h" +#include "core/os/os.h" #include "core/string/print_string.h" #include "core/templates/list.h" @@ -49,10 +50,6 @@ #include <mntent.h> #endif -Ref<DirAccess> DirAccessUnix::create_fs() { - return memnew(DirAccessUnix); -} - Error DirAccessUnix::list_dir_begin() { list_dir_end(); //close any previous dir opening! @@ -216,10 +213,11 @@ static bool _filter_drive(struct mntent *mnt) { #endif static void _get_drives(List<String> *list) { + // Add root. list->push_back("/"); #if defined(HAVE_MNTENT) && defined(X11_ENABLED) - // Check /etc/mtab for the list of mounted partitions + // Check /etc/mtab for the list of mounted partitions. FILE *mtab = setmntent("/etc/mtab", "r"); if (mtab) { struct mntent mnt; @@ -239,7 +237,7 @@ static void _get_drives(List<String> *list) { } #endif - // Add $HOME + // Add $HOME. const char *home = getenv("HOME"); if (home) { // Only add if it's not a duplicate @@ -248,7 +246,8 @@ static void _get_drives(List<String> *list) { list->push_back(home_name); } - // Check $HOME/.config/gtk-3.0/bookmarks + // Check GTK+3 bookmarks for both XDG locations (Documents, Downloads, etc.) + // and potential user-defined bookmarks. char path[1024]; snprintf(path, 1024, "%s/.config/gtk-3.0/bookmarks", home); FILE *fd = fopen(path, "r"); @@ -257,7 +256,7 @@ static void _get_drives(List<String> *list) { while (fgets(string, 1024, fd)) { // Parse only file:// links if (strncmp(string, "file://", 7) == 0) { - // Strip any unwanted edges on the strings and push_back if it's not a duplicate + // Strip any unwanted edges on the strings and push_back if it's not a duplicate. String fpath = String::utf8(string + 7).strip_edges().split_spaces()[0].uri_decode(); if (!list->find(fpath)) { list->push_back(fpath); @@ -267,6 +266,12 @@ static void _get_drives(List<String> *list) { fclose(fd); } + + // Add Desktop dir. + String dpath = OS::get_singleton()->get_system_dir(OS::SystemDir::SYSTEM_DIR_DESKTOP); + if (dpath.length() > 0 && !list->find(dpath)) { + list->push_back(dpath); + } } list->sort(); @@ -338,7 +343,7 @@ Error DirAccessUnix::change_dir(String p_dir) { String prev_dir; char real_current_dir_name[2048]; ERR_FAIL_COND_V(getcwd(real_current_dir_name, 2048) == nullptr, ERR_BUG); - if (prev_dir.parse_utf8(real_current_dir_name)) { + if (prev_dir.parse_utf8(real_current_dir_name) != OK) { prev_dir = real_current_dir_name; //no utf8, maybe latin? } @@ -500,7 +505,7 @@ DirAccessUnix::DirAccessUnix() { // set current directory to an absolute path of the current directory char real_current_dir_name[2048]; ERR_FAIL_COND(getcwd(real_current_dir_name, 2048) == nullptr); - if (current_dir.parse_utf8(real_current_dir_name)) { + if (current_dir.parse_utf8(real_current_dir_name) != OK) { current_dir = real_current_dir_name; } diff --git a/drivers/unix/dir_access_unix.h b/drivers/unix/dir_access_unix.h index 69530de337..5e2129b74a 100644 --- a/drivers/unix/dir_access_unix.h +++ b/drivers/unix/dir_access_unix.h @@ -43,13 +43,11 @@ class DirAccessUnix : public DirAccess { DIR *dir_stream = nullptr; - static Ref<DirAccess> create_fs(); - - String current_dir; bool _cisdir = false; bool _cishidden = false; protected: + String current_dir; virtual String fix_unicode_name(const char *p_name) const { return String::utf8(p_name); } virtual bool is_hidden(const String &p_name); diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp index e0b2994b63..99836b7bea 100644 --- a/drivers/unix/file_access_unix.cpp +++ b/drivers/unix/file_access_unix.cpp @@ -333,10 +333,6 @@ Error FileAccessUnix::_set_unix_permissions(const String &p_file, uint32_t p_per return FAILED; } -Ref<FileAccess> FileAccessUnix::create_libc() { - return memnew(FileAccessUnix); -} - CloseNotificationFunc FileAccessUnix::close_notification_func = nullptr; FileAccessUnix::~FileAccessUnix() { diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h index 4340bbbc82..0261b8be53 100644 --- a/drivers/unix/file_access_unix.h +++ b/drivers/unix/file_access_unix.h @@ -49,7 +49,6 @@ class FileAccessUnix : public FileAccess { String path; String path_src; - static Ref<FileAccess> create_libc(); void _close(); public: diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 52a4d538e1..091287c652 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -313,7 +313,12 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, St if (p_pipe_mutex) { p_pipe_mutex->lock(); } - (*r_pipe) += String::utf8(buf); + String pipe_out; + if (pipe_out.parse_utf8(buf) == OK) { + (*r_pipe) += pipe_out; + } else { + (*r_pipe) += String(buf); // If not valid UTF-8 try decode as Latin-1 + } if (p_pipe_mutex) { p_pipe_mutex->unlock(); } diff --git a/drivers/vulkan/SCsub b/drivers/vulkan/SCsub index b6ceb1cdea..f7de2c4a7e 100644 --- a/drivers/vulkan/SCsub +++ b/drivers/vulkan/SCsub @@ -17,7 +17,7 @@ if env["platform"] == "android": env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_ANDROID_KHR"]) elif env["platform"] == "iphone": env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_IOS_MVK"]) -elif env["platform"] == "linuxbsd": +elif env["platform"] == "linuxbsd" and env["x11"]: env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_XLIB_KHR"]) elif env["platform"] == "osx": env.AppendUnique(CPPDEFINES=["VK_USE_PLATFORM_MACOS_MVK"]) diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 77aab72d40..7843bbe91a 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -36,6 +36,7 @@ #include "core/io/marshalls.h" #include "core/os/os.h" #include "core/templates/hashfuncs.h" +#include "core/version.h" #include "drivers/vulkan/vulkan_context.h" #include "thirdparty/misc/smolv.h" @@ -106,7 +107,7 @@ RenderingDeviceVulkan::Buffer *RenderingDeviceVulkan::_get_buffer_from_owner(RID return buffer; } -static void update_external_dependency_for_store(VkSubpassDependency &dependency, bool is_sampled, bool is_storage, bool is_depth) { +static void update_external_dependency_for_store(VkSubpassDependency2KHR &dependency, bool is_sampled, bool is_storage, bool is_depth) { // Transitioning from write to read, protect the shaders that may use this next // Allow for copies/image layout transitions dependency.dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT; @@ -1400,7 +1401,7 @@ Error RenderingDeviceVulkan::_insert_staging_block() { return OK; } -Error RenderingDeviceVulkan::_staging_buffer_allocate(uint32_t p_amount, uint32_t p_required_align, uint32_t &r_alloc_offset, uint32_t &r_alloc_size, bool p_can_segment, bool p_on_draw_command_buffer) { +Error RenderingDeviceVulkan::_staging_buffer_allocate(uint32_t p_amount, uint32_t p_required_align, uint32_t &r_alloc_offset, uint32_t &r_alloc_size, bool p_can_segment) { //determine a block to use r_alloc_size = p_amount; @@ -1542,7 +1543,7 @@ Error RenderingDeviceVulkan::_buffer_update(Buffer *p_buffer, size_t p_offset, c uint32_t block_write_offset; uint32_t block_write_amount; - Error err = _staging_buffer_allocate(MIN(to_submit, staging_buffer_block_size), p_required_align, block_write_offset, block_write_amount, p_use_draw_command_buffer); + Error err = _staging_buffer_allocate(MIN(to_submit, staging_buffer_block_size), p_required_align, block_write_offset, block_write_amount); if (err) { return err; } @@ -1758,6 +1759,10 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T image_create_info.usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; } + if (p_format.usage_bits & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) { + image_create_info.usage |= VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR; + } + if (p_format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT) { image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; } @@ -2314,6 +2319,12 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; } + if (p_slice_type == TEXTURE_SLICE_2D) { + texture.type = TEXTURE_TYPE_2D; + } else if (p_slice_type == TEXTURE_SLICE_3D) { + texture.type = TEXTURE_TYPE_3D; + } + if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) { image_view_create_info.format = vulkan_formats[texture.format]; } else { @@ -2370,6 +2381,22 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con return _texture_update(p_texture, p_layer, p_data, p_post_barrier, false); } +static _ALWAYS_INLINE_ void _copy_region(uint8_t const *__restrict p_src, uint8_t *__restrict p_dst, uint32_t p_src_x, uint32_t p_src_y, uint32_t p_src_w, uint32_t p_src_h, uint32_t p_src_full_w, uint32_t p_unit_size) { + uint32_t src_offset = (p_src_y * p_src_full_w + p_src_x) * p_unit_size; + uint32_t dst_offset = 0; + for (uint32_t y = p_src_h; y > 0; y--) { + uint8_t const *__restrict src = p_src + src_offset; + uint8_t *__restrict dst = p_dst + dst_offset; + for (uint32_t x = p_src_w * p_unit_size; x > 0; x--) { + *dst = *src; + src++; + dst++; + } + src_offset += p_src_full_w * p_unit_size; + dst_offset += p_src_w * p_unit_size; + } +} + Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, uint32_t p_post_barrier, bool p_use_setup_queue) { _THREAD_SAFE_METHOD_ @@ -2455,8 +2482,8 @@ Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, co const uint8_t *read_ptr = read_ptr_mipmap + image_size * z / depth; - for (uint32_t x = 0; x < width; x += region_size) { - for (uint32_t y = 0; y < height; y += region_size) { + for (uint32_t y = 0; y < height; y += region_size) { + for (uint32_t x = 0; x < width; x += region_size) { uint32_t region_w = MIN(region_size, width - x); uint32_t region_h = MIN(region_size, height - y); @@ -2468,7 +2495,7 @@ Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, co to_allocate >>= get_compressed_image_format_pixel_rshift(texture->format); uint32_t alloc_offset, alloc_size; - Error err = _staging_buffer_allocate(to_allocate, required_align, alloc_offset, alloc_size, false, !p_use_setup_queue); + Error err = _staging_buffer_allocate(to_allocate, required_align, alloc_offset, alloc_size, false); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); uint8_t *write_ptr; @@ -2499,31 +2526,11 @@ Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, co //uint32_t hb = height / block_h; uint32_t region_wb = region_w / block_w; uint32_t region_hb = region_h / block_h; - for (uint32_t xr = 0; xr < region_wb; xr++) { - for (uint32_t yr = 0; yr < region_hb; yr++) { - uint32_t src_offset = ((yr + yb) * wb + xr + xb) * block_size; - uint32_t dst_offset = (yr * region_wb + xr) * block_size; - //copy block - for (uint32_t i = 0; i < block_size; i++) { - write_ptr[dst_offset + i] = read_ptr[src_offset + i]; - } - } - } - + _copy_region(read_ptr, write_ptr, xb, yb, region_wb, region_hb, wb, block_size); } else { //regular image (pixels) //must copy a pixel region - - for (uint32_t xr = 0; xr < region_w; xr++) { - for (uint32_t yr = 0; yr < region_h; yr++) { - uint32_t src_offset = ((yr + y) * width + xr + x) * pixel_size; - uint32_t dst_offset = (yr * region_w + xr) * pixel_size; - //copy block - for (uint32_t i = 0; i < pixel_size; i++) { - write_ptr[dst_offset + i] = read_ptr[src_offset + i]; - } - } - } + _copy_region(read_ptr, write_ptr, x, y, region_w, region_h, width, pixel_size); } { //unmap @@ -2566,11 +2573,11 @@ Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, co uint32_t access_flags = 0; if (p_post_barrier & BARRIER_MASK_COMPUTE) { barrier_flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - access_flags |= VK_ACCESS_SHADER_READ_BIT; + access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; } if (p_post_barrier & BARRIER_MASK_RASTER) { barrier_flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - access_flags |= VK_ACCESS_SHADER_READ_BIT; + access_flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; } if (p_post_barrier & BARRIER_MASK_TRANSFER) { barrier_flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; @@ -2984,7 +2991,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, image_memory_barrier.subresourceRange.baseArrayLayer = p_src_layer; image_memory_barrier.subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, barrier_flags, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, barrier_flags, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); } { //make dst readable @@ -3010,6 +3017,13 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, } } + if (dst_tex->used_in_frame != frames_drawn) { + dst_tex->used_in_raster = false; + dst_tex->used_in_compute = false; + dst_tex->used_in_frame = frames_drawn; + } + dst_tex->used_in_transfer = true; + return OK; } @@ -3353,17 +3367,24 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; // From Section 7.1 of Vulkan API Spec v1.1.148 + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | // From Section 7.1 of Vulkan API Spec v1.1.148 + VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR; VkPipelineStageFlags reading_stages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT; - VkSubpassDependency dependencies[2] = { { VK_SUBPASS_EXTERNAL, 0, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0, default_access_mask, 0 }, - { 0, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, default_access_mask, 0, 0 } }; - VkSubpassDependency &dependency_from_external = dependencies[0]; - VkSubpassDependency &dependency_to_external = dependencies[1]; + VkSubpassDependency2KHR dependencies[2] = { + { VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR, nullptr, VK_SUBPASS_EXTERNAL, 0, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0, default_access_mask, 0, 0 }, + { VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR, nullptr, 0, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, default_access_mask, 0, 0, 0 } + }; + VkSubpassDependency2KHR &dependency_from_external = dependencies[0]; + VkSubpassDependency2KHR &dependency_to_external = dependencies[1]; LocalVector<int32_t> attachment_last_pass; attachment_last_pass.resize(p_attachments.size()); - Vector<VkAttachmentDescription> attachments; + // These are only used if we use multiview but we need to define them in scope. + const uint32_t view_mask = (1 << p_view_count) - 1; + const uint32_t correlation_mask = (1 << p_view_count) - 1; + + Vector<VkAttachmentDescription2KHR> attachments; Vector<int> attachment_remap; for (int i = 0; i < p_attachments.size(); i++) { @@ -3374,10 +3395,12 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF ERR_FAIL_INDEX_V(p_attachments[i].format, DATA_FORMAT_MAX, VK_NULL_HANDLE); ERR_FAIL_INDEX_V(p_attachments[i].samples, TEXTURE_SAMPLES_MAX, VK_NULL_HANDLE); - ERR_FAIL_COND_V_MSG(!(p_attachments[i].usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT)), + ERR_FAIL_COND_V_MSG(!(p_attachments[i].usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT | TEXTURE_USAGE_VRS_ATTACHMENT_BIT)), VK_NULL_HANDLE, "Texture format for index (" + itos(i) + ") requires an attachment (color, depth, input or stencil) bit set."); - VkAttachmentDescription description = {}; + VkAttachmentDescription2KHR description = {}; + description.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR; + description.pNext = nullptr; description.flags = 0; description.format = vulkan_formats[p_attachments[i].format]; description.samples = rasterization_sample_count[p_attachments[i].samples]; @@ -3386,83 +3409,95 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF bool is_storage = p_attachments[i].usage_flags & TEXTURE_USAGE_STORAGE_BIT; bool is_depth = p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - // For each UNDEFINED, assume the prior use was a *read*, as we'd be discarding the output of a write - // Also, each UNDEFINED will do an immediate layout transition (write), s.t. we must ensure execution synchronization vs. - // the read. If this is a performance issue, one could track the actual last accessor of each resource, adding only that - // stage - - switch (is_depth ? p_initial_depth_action : p_initial_action) { - case INITIAL_ACTION_CLEAR_REGION: - case INITIAL_ACTION_CLEAR: { - if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { - description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { - description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - dependency_from_external.srcStageMask |= reading_stages; - } else { - description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there - dependency_from_external.srcStageMask |= reading_stages; - } - } break; - case INITIAL_ACTION_KEEP: { - if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { - description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { - description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - dependency_from_external.srcStageMask |= reading_stages; - } else { - description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there - dependency_from_external.srcStageMask |= reading_stages; - } - } break; - case INITIAL_ACTION_DROP: { - if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { - description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { - description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there - description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - dependency_from_external.srcStageMask |= reading_stages; - } else { - description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there - dependency_from_external.srcStageMask |= reading_stages; - } - } break; - case INITIAL_ACTION_CLEAR_REGION_CONTINUE: - case INITIAL_ACTION_CONTINUE: { - if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { - description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - description.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { - description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - description.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - } else { - description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there - dependency_from_external.srcStageMask |= reading_stages; + // We can setup a framebuffer where we write to our VRS texture to set it up. + // We make the assumption here that if our texture is actually used as our VRS attachment, + // it is used as such for each subpass. This is fairly certain seeing the restrictions on subpasses. + bool is_vrs = p_attachments[i].usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT && i == p_passes[0].vrs_attachment; + + if (is_vrs) { + // For VRS we only read, there is no writing to this texture + description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + description.initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + } else { + // For each UNDEFINED, assume the prior use was a *read*, as we'd be discarding the output of a write + // Also, each UNDEFINED will do an immediate layout transition (write), s.t. we must ensure execution synchronization vs. + // the read. If this is a performance issue, one could track the actual last accessor of each resource, adding only that + // stage + + switch (is_depth ? p_initial_depth_action : p_initial_action) { + case INITIAL_ACTION_CLEAR_REGION: + case INITIAL_ACTION_CLEAR: { + if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + dependency_from_external.srcStageMask |= reading_stages; + } else { + description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + dependency_from_external.srcStageMask |= reading_stages; + } + } break; + case INITIAL_ACTION_KEEP: { + if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + dependency_from_external.srcStageMask |= reading_stages; + } else { + description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + dependency_from_external.srcStageMask |= reading_stages; + } + } break; + case INITIAL_ACTION_DROP: { + if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + dependency_from_external.srcStageMask |= reading_stages; + } else { + description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + dependency_from_external.srcStageMask |= reading_stages; + } + } break; + case INITIAL_ACTION_CLEAR_REGION_CONTINUE: + case INITIAL_ACTION_CONTINUE: { + if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + description.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + description.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + } else { + description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + dependency_from_external.srcStageMask |= reading_stages; + } + } break; + default: { + ERR_FAIL_V(VK_NULL_HANDLE); //should never reach here } - } break; - default: { - ERR_FAIL_V(VK_NULL_HANDLE); //should never reach here } } @@ -3476,6 +3511,10 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF if (p_passes[last_pass].depth_attachment == i) { used_last = true; } + } else if (is_vrs) { + if (p_passes[last_pass].vrs_attachment == i) { + used_last = true; + } } else { if (p_passes[last_pass].resolve_attachments.size()) { //if using resolve attachments, check resolve attachments @@ -3517,58 +3556,69 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF } } - switch (is_depth ? final_depth_action : final_action) { - case FINAL_ACTION_READ: { - if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { - description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - update_external_dependency_for_store(dependency_to_external, is_sampled, is_storage, false); - } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { - description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; - description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - update_external_dependency_for_store(dependency_to_external, is_sampled, is_storage, true); - } else { - description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there - // TODO: What does this mean about the next usage (and thus appropriate dependency masks - } - } break; - case FINAL_ACTION_DISCARD: { - if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { - description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { - description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - } else { - description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there - } - } break; - case FINAL_ACTION_CONTINUE: { - if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { - description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - description.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { - description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; - description.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - } else { - description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there - } + if (is_vrs) { + // We don't change our VRS texture during this process - } break; - default: { - ERR_FAIL_V(VK_NULL_HANDLE); //should never reach here + description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + // TODO do we need to update our external dependency ? + // update_external_dependency_for_store(dependency_to_external, is_sampled, is_storage, false); + } else { + switch (is_depth ? final_depth_action : final_action) { + case FINAL_ACTION_READ: { + if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + update_external_dependency_for_store(dependency_to_external, is_sampled, is_storage, false); + } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + update_external_dependency_for_store(dependency_to_external, is_sampled, is_storage, true); + } else { + description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + // TODO: What does this mean about the next usage (and thus appropriate dependency masks + } + } break; + case FINAL_ACTION_DISCARD: { + if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + } else { + description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.finalLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + } + } break; + case FINAL_ACTION_CONTINUE: { + if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + description.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + } else { + description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.finalLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + } + + } break; + default: { + ERR_FAIL_V(VK_NULL_HANDLE); //should never reach here + } } } @@ -3577,12 +3627,14 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF attachments.push_back(description); } - LocalVector<VkSubpassDescription> subpasses; - LocalVector<LocalVector<VkAttachmentReference>> color_reference_array; - LocalVector<LocalVector<VkAttachmentReference>> input_reference_array; - LocalVector<LocalVector<VkAttachmentReference>> resolve_reference_array; + LocalVector<VkSubpassDescription2KHR> subpasses; + LocalVector<LocalVector<VkAttachmentReference2KHR>> color_reference_array; + LocalVector<LocalVector<VkAttachmentReference2KHR>> input_reference_array; + LocalVector<LocalVector<VkAttachmentReference2KHR>> resolve_reference_array; LocalVector<LocalVector<uint32_t>> preserve_reference_array; - LocalVector<VkAttachmentReference> depth_reference_array; + LocalVector<VkAttachmentReference2KHR> depth_reference_array; + LocalVector<VkAttachmentReference2KHR> vrs_reference_array; + LocalVector<VkFragmentShadingRateAttachmentInfoKHR> vrs_attachment_info_array; subpasses.resize(p_passes.size()); color_reference_array.resize(p_passes.size()); @@ -3590,20 +3642,25 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF resolve_reference_array.resize(p_passes.size()); preserve_reference_array.resize(p_passes.size()); depth_reference_array.resize(p_passes.size()); + vrs_reference_array.resize(p_passes.size()); + vrs_attachment_info_array.resize(p_passes.size()); - LocalVector<VkSubpassDependency> subpass_dependencies; + LocalVector<VkSubpassDependency2KHR> subpass_dependencies; for (int i = 0; i < p_passes.size(); i++) { const FramebufferPass *pass = &p_passes[i]; - LocalVector<VkAttachmentReference> &color_references = color_reference_array[i]; + LocalVector<VkAttachmentReference2KHR> &color_references = color_reference_array[i]; TextureSamples texture_samples = TEXTURE_SAMPLES_1; bool is_multisample_first = true; + void *subpass_nextptr = nullptr; for (int j = 0; j < pass->color_attachments.size(); j++) { int32_t attachment = pass->color_attachments[j]; - VkAttachmentReference reference; + VkAttachmentReference2KHR reference; + reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR; + reference.pNext = nullptr; if (attachment == FramebufferPass::ATTACHMENT_UNUSED) { reference.attachment = VK_ATTACHMENT_UNUSED; reference.layout = VK_IMAGE_LAYOUT_UNDEFINED; @@ -3622,14 +3679,17 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; attachment_last_pass[attachment] = i; } + reference.aspectMask = 0; color_references.push_back(reference); } - LocalVector<VkAttachmentReference> &input_references = input_reference_array[i]; + LocalVector<VkAttachmentReference2KHR> &input_references = input_reference_array[i]; for (int j = 0; j < pass->input_attachments.size(); j++) { int32_t attachment = pass->input_attachments[j]; - VkAttachmentReference reference; + VkAttachmentReference2KHR reference; + reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR; + reference.pNext = nullptr; if (attachment == FramebufferPass::ATTACHMENT_UNUSED) { reference.attachment = VK_ATTACHMENT_UNUSED; reference.layout = VK_IMAGE_LAYOUT_UNDEFINED; @@ -3641,10 +3701,11 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF reference.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; attachment_last_pass[attachment] = i; } + reference.aspectMask = 0; // TODO we need to set this here, possibly VK_IMAGE_ASPECT_COLOR_BIT ?? input_references.push_back(reference); } - LocalVector<VkAttachmentReference> &resolve_references = resolve_reference_array[i]; + LocalVector<VkAttachmentReference2KHR> &resolve_references = resolve_reference_array[i]; if (pass->resolve_attachments.size() > 0) { ERR_FAIL_COND_V_MSG(pass->resolve_attachments.size() != pass->color_attachments.size(), VK_NULL_HANDLE, "The amount of resolve attachments (" + itos(pass->resolve_attachments.size()) + ") must match the number of color attachments (" + itos(pass->color_attachments.size()) + ")."); @@ -3652,7 +3713,9 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF } for (int j = 0; j < pass->resolve_attachments.size(); j++) { int32_t attachment = pass->resolve_attachments[j]; - VkAttachmentReference reference; + VkAttachmentReference2KHR reference; + reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR; + reference.pNext = nullptr; if (attachment == FramebufferPass::ATTACHMENT_UNUSED) { reference.attachment = VK_ATTACHMENT_UNUSED; reference.layout = VK_IMAGE_LAYOUT_UNDEFINED; @@ -3667,10 +3730,13 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; attachment_last_pass[attachment] = i; } + reference.aspectMask = 0; resolve_references.push_back(reference); } - VkAttachmentReference &depth_stencil_reference = depth_reference_array[i]; + VkAttachmentReference2KHR &depth_stencil_reference = depth_reference_array[i]; + depth_stencil_reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR; + depth_stencil_reference.pNext = nullptr; if (pass->depth_attachment != FramebufferPass::ATTACHMENT_UNUSED) { int32_t attachment = pass->depth_attachment; @@ -3679,6 +3745,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass."); depth_stencil_reference.attachment = attachment_remap[attachment]; depth_stencil_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + depth_stencil_reference.aspectMask = 0; attachment_last_pass[attachment] = i; if (is_multisample_first) { @@ -3693,6 +3760,32 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF depth_stencil_reference.layout = VK_IMAGE_LAYOUT_UNDEFINED; } + if (context->get_vrs_capabilities().attachment_vrs_supported && pass->vrs_attachment != FramebufferPass::ATTACHMENT_UNUSED) { + int32_t attachment = pass->vrs_attachment; + ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), depth attachment."); + ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as vrs, but it's not a vrs attachment."); + ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer vrs attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass."); + + VkAttachmentReference2KHR &vrs_reference = vrs_reference_array[i]; + vrs_reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR; + vrs_reference.pNext = nullptr; + vrs_reference.attachment = attachment_remap[attachment]; + vrs_reference.layout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; + vrs_reference.aspectMask = 0; + + Size2i texel_size = context->get_vrs_capabilities().max_texel_size; + + VkFragmentShadingRateAttachmentInfoKHR &vrs_attachment_info = vrs_attachment_info_array[i]; + vrs_attachment_info.sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR; + vrs_attachment_info.pNext = nullptr; + vrs_attachment_info.pFragmentShadingRateAttachment = &vrs_reference; + vrs_attachment_info.shadingRateAttachmentTexelSize = { uint32_t(texel_size.x), uint32_t(texel_size.y) }; + + attachment_last_pass[attachment] = i; + + subpass_nextptr = &vrs_attachment_info; + } + LocalVector<uint32_t> &preserve_references = preserve_reference_array[i]; for (int j = 0; j < pass->preserve_attachments.size(); j++) { @@ -3709,9 +3802,12 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF } } - VkSubpassDescription &subpass = subpasses[i]; + VkSubpassDescription2KHR &subpass = subpasses[i]; + subpass.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR; + subpass.pNext = subpass_nextptr; subpass.flags = 0; subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.viewMask = view_mask; subpass.inputAttachmentCount = input_references.size(); if (input_references.size()) { subpass.pInputAttachments = input_references.ptr(); @@ -3748,7 +3844,9 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF } if (i > 0) { - VkSubpassDependency dependency; + VkSubpassDependency2KHR dependency; + dependency.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR; + dependency.pNext = nullptr; dependency.srcSubpass = i - 1; dependency.dstSubpass = i; dependency.srcStageMask = 0; @@ -3758,6 +3856,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF dependency.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; dependency.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + dependency.viewOffset = 0; subpass_dependencies.push_back(dependency); } /* @@ -3775,10 +3874,11 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF */ } - VkRenderPassCreateInfo render_pass_create_info; - render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + VkRenderPassCreateInfo2KHR render_pass_create_info; + render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR; render_pass_create_info.pNext = nullptr; render_pass_create_info.flags = 0; + render_pass_create_info.attachmentCount = attachments.size(); render_pass_create_info.pAttachments = attachments.ptr(); render_pass_create_info.subpassCount = subpasses.size(); @@ -3795,13 +3895,15 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF render_pass_create_info.pDependencies = nullptr; } - // These are only used if we use multiview but we need to define them in scope. - const uint32_t view_mask = (1 << p_view_count) - 1; - const uint32_t correlation_mask = (1 << p_view_count) - 1; + render_pass_create_info.correlatedViewMaskCount = 1; + render_pass_create_info.pCorrelatedViewMasks = &correlation_mask; + Vector<uint32_t> view_masks; VkRenderPassMultiviewCreateInfo render_pass_multiview_create_info; if (p_view_count > 1) { + // this may no longer be needed with the new settings already including this + const VulkanContext::MultiviewCapabilities capabilities = context->get_multiview_capabilities(); // For now this only works with multiview! @@ -3828,8 +3930,8 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF } VkRenderPass render_pass; - VkResult res = vkCreateRenderPass(device, &render_pass_create_info, nullptr, &render_pass); - ERR_FAIL_COND_V_MSG(res, VK_NULL_HANDLE, "vkCreateRenderPass failed with error " + itos(res) + "."); + VkResult res = context->vkCreateRenderPass2KHR(device, &render_pass_create_info, nullptr, &render_pass); + ERR_FAIL_COND_V_MSG(res, VK_NULL_HANDLE, "vkCreateRenderPass2KHR failed with error " + itos(res) + "."); return render_pass; } @@ -3890,7 +3992,9 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c return E->get(); } - VkSubpassDescription subpass; + VkSubpassDescription2KHR subpass; + subpass.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR; + subpass.pNext = nullptr; subpass.flags = 0; subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass.inputAttachmentCount = 0; //unsupported for now @@ -3902,8 +4006,8 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c subpass.preserveAttachmentCount = 0; subpass.pPreserveAttachments = nullptr; - VkRenderPassCreateInfo render_pass_create_info; - render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + VkRenderPassCreateInfo2KHR render_pass_create_info; + render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR; render_pass_create_info.pNext = nullptr; render_pass_create_info.flags = 0; render_pass_create_info.attachmentCount = 0; @@ -3912,11 +4016,13 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c render_pass_create_info.pSubpasses = &subpass; render_pass_create_info.dependencyCount = 0; render_pass_create_info.pDependencies = nullptr; + render_pass_create_info.correlatedViewMaskCount = 0; + render_pass_create_info.pCorrelatedViewMasks = nullptr; VkRenderPass render_pass; - VkResult res = vkCreateRenderPass(device, &render_pass_create_info, nullptr, &render_pass); + VkResult res = context->vkCreateRenderPass2KHR(device, &render_pass_create_info, nullptr, &render_pass); - ERR_FAIL_COND_V_MSG(res, 0, "vkCreateRenderPass for empty fb failed with error " + itos(res) + "."); + ERR_FAIL_COND_V_MSG(res, 0, "vkCreateRenderPass2KHR for empty fb failed with error " + itos(res) + "."); if (render_pass == VK_NULL_HANDLE) { //was likely invalid return INVALID_ID; @@ -3969,6 +4075,8 @@ RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attac if (texture && texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { pass.depth_attachment = i; + } else if (texture && texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) { + pass.vrs_attachment = i; } else { pass.color_attachments.push_back(texture ? i : FramebufferPass::ATTACHMENT_UNUSED); } @@ -3999,6 +4107,10 @@ RID RenderingDeviceVulkan::framebuffer_create_multipass(const Vector<RID> &p_tex size.width = texture->width; size.height = texture->height; size_set = true; + } else if (texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) { + // If this is not the first attachement we assume this is used as the VRS attachment + // in this case this texture will be 1/16th the size of the color attachement. + // So we skip the size check } else { ERR_FAIL_COND_V_MSG((uint32_t)size.width != texture->width || (uint32_t)size.height != texture->height, RID(), "All textures in a framebuffer should be the same size."); @@ -4342,7 +4454,7 @@ String RenderingDeviceVulkan::_shader_uniform_debug(RID p_shader, int p_set) { if (!ret.is_empty()) { ret += "\n"; } - ret += "Set: " + itos(i) + " Binding: " + itos(ui.binding) + " Type: " + shader_uniform_names[ui.type] + " Length: " + itos(ui.length); + ret += "Set: " + itos(i) + " Binding: " + itos(ui.binding) + " Type: " + shader_uniform_names[ui.type] + " Writable: " + (ui.writable ? "Y" : "N") + " Length: " + itos(ui.length); } } return ret; @@ -4542,11 +4654,12 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa //version 1: initial //version 2: Added shader name +//version 3: Added writable -#define SHADER_BINARY_VERSION 2 +#define SHADER_BINARY_VERSION 3 String RenderingDeviceVulkan::shader_get_binary_cache_key() const { - return "Vulkan-SV" + itos(SHADER_BINARY_VERSION); + return "Vulkan-SV" + itos(SHADER_BINARY_VERSION) + "-" + String(VERSION_NUMBER) + "-" + String(VERSION_HASH); } struct RenderingDeviceVulkanShaderBinaryDataBinding { @@ -4554,6 +4667,7 @@ struct RenderingDeviceVulkanShaderBinaryDataBinding { uint32_t binding; uint32_t stages; uint32_t length; //size of arrays (in total elements), or ubos (in bytes * total elements) + uint32_t writable; }; struct RenderingDeviceVulkanShaderBinarySpecializationConstant { @@ -4643,6 +4757,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve bool need_array_dimensions = false; bool need_block_size = false; + bool may_be_writable = false; switch (binding.descriptor_type) { case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLER: { @@ -4660,6 +4775,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE: { info.type = UNIFORM_TYPE_IMAGE; need_array_dimensions = true; + may_be_writable = true; } break; case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: { info.type = UNIFORM_TYPE_TEXTURE_BUFFER; @@ -4668,6 +4784,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: { info.type = UNIFORM_TYPE_IMAGE_BUFFER; need_array_dimensions = true; + may_be_writable = true; } break; case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER: { info.type = UNIFORM_TYPE_UNIFORM_BUFFER; @@ -4676,6 +4793,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER: { info.type = UNIFORM_TYPE_STORAGE_BUFFER; need_block_size = true; + may_be_writable = true; } break; case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: { ERR_PRINT("Dynamic uniform buffer not supported."); @@ -4714,6 +4832,12 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve info.length = 0; } + if (may_be_writable) { + info.writable = !(binding.type_description->decoration_flags & SPV_REFLECT_DECORATION_NON_WRITABLE) && !(binding.block.decoration_flags & SPV_REFLECT_DECORATION_NON_WRITABLE); + } else { + info.writable = false; + } + info.binding = binding.binding; uint32_t set = binding.set; @@ -4736,9 +4860,14 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve ERR_FAIL_COND_V_MSG(uniform_info[set][k].length != info.length, Vector<uint8_t>(), "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different uniform size."); + //also, verify that it has the same writability + ERR_FAIL_COND_V_MSG(uniform_info[set][k].writable != info.writable, Vector<uint8_t>(), + "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different writability."); + //just append stage mask and return uniform_info.write[set].write[k].stages |= 1 << stage; exists = true; + break; } } @@ -5034,7 +5163,7 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_ ERR_FAIL_COND_V(binptr[0] != 'G' || binptr[1] != 'V' || binptr[2] != 'B' || binptr[3] != 'D', RID()); uint32_t bin_version = decode_uint32(binptr + 4); - ERR_FAIL_COND_V(bin_version > SHADER_BINARY_VERSION, RID()); + ERR_FAIL_COND_V(bin_version != SHADER_BINARY_VERSION, RID()); uint32_t bin_data_size = decode_uint32(binptr + 8); @@ -5081,6 +5210,7 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_ for (uint32_t j = 0; j < set_count; j++) { UniformInfo info; info.type = UniformType(set_ptr[j].type); + info.writable = set_ptr[j].writable; info.length = set_ptr[j].length; info.binding = set_ptr[j].binding; info.stages = set_ptr[j].stages; @@ -5404,7 +5534,6 @@ RID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const Ve ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID()); Buffer buffer; - buffer.usage = p_usage; uint32_t flags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; if (p_usage & STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT) { flags |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; @@ -6530,11 +6659,28 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma dynamic_state_create_info.dynamicStateCount = dynamic_states.size(); dynamic_state_create_info.pDynamicStates = dynamic_states.ptr(); + void *graphics_pipeline_nextptr = nullptr; + + VkPipelineFragmentShadingRateStateCreateInfoKHR vrs_create_info; + if (context->get_vrs_capabilities().attachment_vrs_supported) { + // If VRS is used, this defines how the different VRS types are combined. + // combinerOps[0] decides how we use the output of pipeline and primitive (drawcall) VRS + // combinerOps[1] decides how we use the output of combinerOps[0] and our attachment VRS + + vrs_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR; + vrs_create_info.pNext = nullptr; + vrs_create_info.fragmentSize = { 4, 4 }; + vrs_create_info.combinerOps[0] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; // We don't use pipeline/primitive VRS so this really doesn't matter + vrs_create_info.combinerOps[1] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR; // always use the outcome of attachment VRS if enabled + + graphics_pipeline_nextptr = &vrs_create_info; + } + //finally, pipeline create info VkGraphicsPipelineCreateInfo graphics_pipeline_create_info; graphics_pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - graphics_pipeline_create_info.pNext = nullptr; + graphics_pipeline_create_info.pNext = graphics_pipeline_nextptr; graphics_pipeline_create_info.flags = 0; Vector<VkPipelineShaderStageCreateInfo> pipeline_stages = shader->pipeline_stages; @@ -6699,7 +6845,7 @@ RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader, const Vector<Pi const PipelineSpecializationConstant &psc = p_specialization_constants[j]; if (psc.constant_id == sc.constant.constant_id) { ERR_FAIL_COND_V_MSG(psc.type != sc.constant.type, RID(), "Specialization constant provided for id (" + itos(sc.constant.constant_id) + ") is of the wrong type."); - data_ptr[i] = sc.constant.int_value; + data_ptr[i] = psc.int_value; break; } } @@ -6883,8 +7029,10 @@ Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebu Texture *texture = texture_owner.get_or_null(p_framebuffer->texture_ids[i]); if (texture) { 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); + if (!(texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT)) { // VRS attachment will be a different size. + 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(); @@ -7019,7 +7167,6 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff } void RenderingDeviceVulkan::_draw_list_insert_clear_region(DrawList *draw_list, Framebuffer *framebuffer, Point2i viewport_offset, Point2i viewport_size, bool p_clear_color, const Vector<Color> &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil) { - ERR_FAIL_COND_MSG(p_clear_color && p_clear_colors.size() != framebuffer->texture_ids.size(), "Clear color values supplied (" + itos(p_clear_colors.size()) + ") differ from the amount required for framebuffer color attachments (" + itos(framebuffer->texture_ids.size()) + ")."); Vector<VkClearAttachment> clear_attachments; int color_index = 0; int texture_index = 0; @@ -7108,11 +7255,14 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu } } - if (p_initial_color_action == INITIAL_ACTION_CLEAR) { //check clear values + if (p_initial_color_action == INITIAL_ACTION_CLEAR || needs_clear_color) { //check clear values int color_count = 0; for (int i = 0; i < framebuffer->texture_ids.size(); i++) { Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]); - if (!texture || !(texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { + // We only check for our VRS usage bit if this is not the first texture id. + // If it is the first we're likely populating our VRS texture. + // Bit dirty but.. + if (!texture || (!(texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) && !(i != 0 && texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT))) { color_count++; } } @@ -7169,6 +7319,9 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) { _THREAD_SAFE_METHOD_ + ERR_FAIL_COND_V_MSG(draw_list != nullptr, ERR_BUSY, "Only one draw list can be active at the same time."); + ERR_FAIL_COND_V_MSG(compute_list != nullptr && !compute_list->state.allow_draw_overlap, ERR_BUSY, "Only one draw/compute list can be active at the same time."); + ERR_FAIL_COND_V(p_splits < 1, ERR_INVALID_DECLARATION); Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer); @@ -7202,7 +7355,7 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p } } - if (p_initial_color_action == INITIAL_ACTION_CLEAR) { //check clear values + if (p_initial_color_action == INITIAL_ACTION_CLEAR || needs_clear_color) { //check clear values int color_count = 0; for (int i = 0; i < framebuffer->texture_ids.size(); i++) { @@ -7893,10 +8046,6 @@ void RenderingDeviceVulkan::draw_list_end(uint32_t p_post_barrier) { // * Some buffer is copied // * Another render pass happens (since we may be done) -#ifdef FORCE_FULL_BARRIER - _full_barrier(true); -#else - VkMemoryBarrier mem_barrier; mem_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; mem_barrier.pNext = nullptr; @@ -7907,6 +8056,8 @@ void RenderingDeviceVulkan::draw_list_end(uint32_t p_post_barrier) { vkCmdPipelineBarrier(frames[frame].draw_command_buffer, src_stage, barrier_flags, 0, 1, &mem_barrier, 0, nullptr, image_barrier_count, image_barriers); } +#ifdef FORCE_FULL_BARRIER + _full_barrier(true); #endif } @@ -8261,7 +8412,7 @@ void RenderingDeviceVulkan::compute_list_dispatch_indirect(ComputeListID p_list, Buffer *buffer = storage_buffer_owner.get_or_null(p_buffer); ERR_FAIL_COND(!buffer); - ERR_FAIL_COND_MSG(!(buffer->usage & STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT), "Buffer provided was not created to do indirect dispatch."); + ERR_FAIL_COND_MSG(!(buffer->usage & VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT), "Buffer provided was not created to do indirect dispatch."); ERR_FAIL_COND_MSG(p_offset + 12 > buffer->size, "Offset provided (+12) is past the end of buffer."); @@ -8377,9 +8528,6 @@ void RenderingDeviceVulkan::compute_list_end(uint32_t p_post_barrier) { } } -#ifdef FORCE_FULL_BARRIER - _full_barrier(true); -#else VkMemoryBarrier mem_barrier; mem_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; mem_barrier.pNext = nullptr; @@ -8390,6 +8538,8 @@ void RenderingDeviceVulkan::compute_list_end(uint32_t p_post_barrier) { vkCmdPipelineBarrier(compute_list->command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, barrier_flags, 0, 1, &mem_barrier, 0, nullptr, image_barrier_count, image_barriers); } +#ifdef FORCE_FULL_BARRIER + _full_barrier(true); #endif memdelete(compute_list); @@ -8717,7 +8867,7 @@ void RenderingDeviceVulkan::_begin_frame() { } if (frames[frame].timestamp_count) { - vkGetQueryPoolResults(device, frames[frame].timestamp_pool, 0, frames[frame].timestamp_count, sizeof(uint64_t) * max_timestamp_query_elements, frames[frame].timestamp_result_values, sizeof(uint64_t), VK_QUERY_RESULT_64_BIT); + vkGetQueryPoolResults(device, frames[frame].timestamp_pool, 0, frames[frame].timestamp_count, sizeof(uint64_t) * max_timestamp_query_elements, frames[frame].timestamp_result_values.ptr(), sizeof(uint64_t), VK_QUERY_RESULT_64_BIT); vkCmdResetQueryPool(frames[frame].setup_command_buffer, frames[frame].timestamp_pool, 0, frames[frame].timestamp_count); SWAP(frames[frame].timestamp_names, frames[frame].timestamp_result_names); SWAP(frames[frame].timestamp_cpu_values, frames[frame].timestamp_cpu_result_values); @@ -8973,17 +9123,6 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de { device_capabilities.version_major = p_context->get_vulkan_major(); device_capabilities.version_minor = p_context->get_vulkan_minor(); - - // get info about subgroups - VulkanContext::SubgroupCapabilities subgroup_capabilities = p_context->get_subgroup_capabilities(); - device_capabilities.subgroup_size = subgroup_capabilities.size; - device_capabilities.subgroup_in_shaders = subgroup_capabilities.supported_stages_flags_rd(); - device_capabilities.subgroup_operations = subgroup_capabilities.supported_operations_flags_rd(); - - // get info about further features - VulkanContext::MultiviewCapabilities multiview_capabilies = p_context->get_multiview_capabilities(); - device_capabilities.supports_multiview = multiview_capabilies.is_supported && multiview_capabilies.max_view_count > 1; - device_capabilities.supports_fsr_half_float = p_context->get_shader_capabilities().shader_float16_is_supported && p_context->get_storage_buffer_capabilities().storage_buffer_16_bit_access_is_supported; } context = p_context; @@ -9008,7 +9147,7 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de vmaCreateAllocator(&allocatorInfo, &allocator); } - frames = memnew_arr(Frame, frame_count); + frames.resize(frame_count); frame = 0; //create setup and frame buffers for (int i = 0; i < frame_count; i++) { @@ -9054,12 +9193,12 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de vkCreateQueryPool(device, &query_pool_create_info, nullptr, &frames[i].timestamp_pool); - frames[i].timestamp_names = memnew_arr(String, max_timestamp_query_elements); - frames[i].timestamp_cpu_values = memnew_arr(uint64_t, max_timestamp_query_elements); + frames[i].timestamp_names.resize(max_timestamp_query_elements); + frames[i].timestamp_cpu_values.resize(max_timestamp_query_elements); frames[i].timestamp_count = 0; - frames[i].timestamp_result_names = memnew_arr(String, max_timestamp_query_elements); - frames[i].timestamp_cpu_result_values = memnew_arr(uint64_t, max_timestamp_query_elements); - frames[i].timestamp_result_values = memnew_arr(uint64_t, max_timestamp_query_elements); + frames[i].timestamp_result_names.resize(max_timestamp_query_elements); + frames[i].timestamp_cpu_result_values.resize(max_timestamp_query_elements); + frames[i].timestamp_result_values.resize(max_timestamp_query_elements); frames[i].timestamp_result_count = 0; } } @@ -9332,7 +9471,7 @@ String RenderingDeviceVulkan::get_captured_timestamp_name(uint32_t p_index) cons return frames[frame].timestamp_result_names[p_index]; } -uint64_t RenderingDeviceVulkan::limit_get(Limit p_limit) { +uint64_t RenderingDeviceVulkan::limit_get(Limit p_limit) const { switch (p_limit) { case LIMIT_MAX_BOUND_UNIFORM_SETS: return limits.maxBoundDescriptorSets; @@ -9402,7 +9541,18 @@ uint64_t RenderingDeviceVulkan::limit_get(Limit p_limit) { return limits.maxComputeWorkGroupSize[1]; case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z: return limits.maxComputeWorkGroupSize[2]; - + case LIMIT_SUBGROUP_SIZE: { + VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities(); + return subgroup_capabilities.size; + } + case LIMIT_SUBGROUP_IN_SHADERS: { + VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities(); + return subgroup_capabilities.supported_stages_flags_rd(); + } + case LIMIT_SUBGROUP_OPERATIONS: { + VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities(); + return subgroup_capabilities.supported_operations_flags_rd(); + } default: ERR_FAIL_V(0); } @@ -9460,18 +9610,13 @@ void RenderingDeviceVulkan::finalize() { _free_pending_resources(f); vkDestroyCommandPool(device, frames[i].command_pool, nullptr); vkDestroyQueryPool(device, frames[i].timestamp_pool, nullptr); - memdelete_arr(frames[i].timestamp_names); - memdelete_arr(frames[i].timestamp_cpu_values); - memdelete_arr(frames[i].timestamp_result_names); - memdelete_arr(frames[i].timestamp_result_values); - memdelete_arr(frames[i].timestamp_cpu_result_values); } for (int i = 0; i < split_draw_list_allocators.size(); i++) { vkDestroyCommandPool(device, split_draw_list_allocators[i].command_pool, nullptr); } - memdelete_arr(frames); + frames.clear(); for (int i = 0; i < staging_buffer_blocks.size(); i++) { vmaDestroyBuffer(allocator, staging_buffer_blocks[i].buffer, staging_buffer_blocks[i].allocation); @@ -9507,6 +9652,25 @@ RenderingDevice *RenderingDeviceVulkan::create_local_device() { return rd; } +bool RenderingDeviceVulkan::has_feature(const Features p_feature) const { + switch (p_feature) { + case SUPPORTS_MULTIVIEW: { + VulkanContext::MultiviewCapabilities multiview_capabilies = context->get_multiview_capabilities(); + return multiview_capabilies.is_supported && multiview_capabilies.max_view_count > 1; + } break; + case SUPPORTS_FSR_HALF_FLOAT: { + return context->get_shader_capabilities().shader_float16_is_supported && context->get_storage_buffer_capabilities().storage_buffer_16_bit_access_is_supported; + } break; + case SUPPORTS_ATTACHMENT_VRS: { + VulkanContext::VRSCapabilities vrs_capabilities = context->get_vrs_capabilities(); + return vrs_capabilities.attachment_vrs_supported; + } break; + default: { + return false; + } + } +} + RenderingDeviceVulkan::RenderingDeviceVulkan() { device_capabilities.device_family = DEVICE_VULKAN; } diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h index 903a39b3d0..7c8021251f 100644 --- a/drivers/vulkan/rendering_device_vulkan.h +++ b/drivers/vulkan/rendering_device_vulkan.h @@ -206,7 +206,7 @@ class RenderingDeviceVulkan : public RenderingDevice { uint64_t staging_buffer_max_size = 0; bool staging_buffer_used = false; - Error _staging_buffer_allocate(uint32_t p_amount, uint32_t p_required_align, uint32_t &r_alloc_offset, uint32_t &r_alloc_size, bool p_can_segment = true, bool p_on_draw_command_buffer = false); + Error _staging_buffer_allocate(uint32_t p_amount, uint32_t p_required_align, uint32_t &r_alloc_offset, uint32_t &r_alloc_size, bool p_can_segment = true); Error _insert_staging_block(); struct Buffer { @@ -241,6 +241,7 @@ class RenderingDeviceVulkan : public RenderingDevice { Vector<AttachmentFormat> attachments; Vector<FramebufferPass> passes; uint32_t view_count = 1; + bool operator<(const FramebufferFormatKey &p_key) const { if (view_count != p_key.view_count) { return view_count < p_key.view_count; @@ -457,17 +458,17 @@ class RenderingDeviceVulkan : public RenderingDevice { uint32_t hash() const { int vdc = vertex_formats.size(); - uint32_t h = hash_djb2_one_32(vdc); + uint32_t h = hash_murmur3_one_32(vdc); const VertexAttribute *ptr = vertex_formats.ptr(); for (int i = 0; i < vdc; i++) { const VertexAttribute &vd = ptr[i]; - h = hash_djb2_one_32(vd.location, h); - h = hash_djb2_one_32(vd.offset, h); - h = hash_djb2_one_32(vd.format, h); - h = hash_djb2_one_32(vd.stride, h); - h = hash_djb2_one_32(vd.frequency, h); + h = hash_murmur3_one_32(vd.location, h); + h = hash_murmur3_one_32(vd.offset, h); + h = hash_murmur3_one_32(vd.format, h); + h = hash_murmur3_one_32(vd.stride, h); + h = hash_murmur3_one_32(vd.frequency, h); } - return h; + return hash_fmix32(h); } }; @@ -544,12 +545,13 @@ class RenderingDeviceVulkan : public RenderingDevice { struct UniformInfo { UniformType type = UniformType::UNIFORM_TYPE_MAX; + bool writable = false; int binding = 0; uint32_t stages = 0; int length = 0; //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); + return (binding != p_info.binding || type != p_info.type || writable != p_info.writable || stages != p_info.stages || length != p_info.length); } bool operator<(const UniformInfo &p_info) const { @@ -559,6 +561,9 @@ class RenderingDeviceVulkan : public RenderingDevice { if (type != p_info.type) { return type < p_info.type; } + if (writable != p_info.writable) { + return writable < p_info.writable; + } if (stages != p_info.stages) { return stages < p_info.stages; } @@ -633,7 +638,6 @@ class RenderingDeviceVulkan : public RenderingDevice { }; bool is_compute = false; - int max_output = 0; Vector<Set> sets; Vector<uint32_t> set_formats; Vector<VkPipelineShaderStageCreateInfo> pipeline_stages; @@ -866,11 +870,9 @@ class RenderingDeviceVulkan : public RenderingDevice { uint32_t pipeline_dynamic_state = 0; VertexFormatID pipeline_vertex_format = INVALID_ID; RID pipeline_shader; - uint32_t invalid_set_from = 0; bool pipeline_uses_restart_indices = false; uint32_t pipeline_primitive_divisor = 0; uint32_t pipeline_primitive_minimum = 0; - Vector<uint32_t> pipeline_set_formats; uint32_t pipeline_push_constant_size = 0; bool pipeline_push_constant_supplied = false; } validation; @@ -944,7 +946,6 @@ class RenderingDeviceVulkan : public RenderingDevice { bool pipeline_active = false; RID pipeline_shader; uint32_t invalid_set_from = 0; - Vector<uint32_t> pipeline_set_formats; uint32_t pipeline_push_constant_size = 0; bool pipeline_push_constant_supplied = false; } validation; @@ -994,19 +995,19 @@ class RenderingDeviceVulkan : public RenderingDevice { VkQueryPool timestamp_pool; - String *timestamp_names = nullptr; - uint64_t *timestamp_cpu_values = nullptr; + TightLocalVector<String> timestamp_names; + TightLocalVector<uint64_t> timestamp_cpu_values; uint32_t timestamp_count = 0; - String *timestamp_result_names = nullptr; - uint64_t *timestamp_cpu_result_values = nullptr; - uint64_t *timestamp_result_values = nullptr; + TightLocalVector<String> timestamp_result_names; + TightLocalVector<uint64_t> timestamp_cpu_result_values; + TightLocalVector<uint64_t> timestamp_result_values; uint32_t timestamp_result_count = 0; uint64_t index = 0; }; uint32_t max_timestamp_query_elements = 0; - Frame *frames = nullptr; //frames available, for main device they are cycled (usually 3), for local devices only 1 + TightLocalVector<Frame> frames; //frames available, for main device they are cycled (usually 3), for local devices only 1 int frame = 0; //current frame int frame_count = 0; //total amount of frames uint64_t frames_drawn = 0; @@ -1203,7 +1204,7 @@ public: /**** Limits ****/ /****************/ - virtual uint64_t limit_get(Limit p_limit); + virtual uint64_t limit_get(Limit p_limit) const; virtual void prepare_screen_for_drawing(); void initialize(VulkanContext *p_context, bool p_local_device = false); @@ -1234,6 +1235,8 @@ public: virtual uint64_t get_driver_resource(DriverResource p_resource, RID p_rid = RID(), uint64_t p_index = 0); + virtual bool has_feature(const Features p_feature) const; + RenderingDeviceVulkan(); ~RenderingDeviceVulkan(); }; diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp index 7944057041..814cec2ec0 100644 --- a/drivers/vulkan/vulkan_context.cpp +++ b/drivers/vulkan/vulkan_context.cpp @@ -48,6 +48,18 @@ VulkanHooks *VulkanContext::vulkan_hooks = nullptr; +VkResult VulkanContext::vkCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2 *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) { + if (fpCreateRenderPass2KHR == nullptr) { + fpCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetInstanceProcAddr(inst, "vkCreateRenderPass2KHR"); + } + + if (fpCreateRenderPass2KHR == nullptr) { + return VK_ERROR_EXTENSION_NOT_PRESENT; + } else { + return (fpCreateRenderPass2KHR)(device, pCreateInfo, pAllocator, pRenderPass); + } +} + VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_messenger_callback( VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, @@ -72,20 +84,20 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_messenger_callback( strstr(pCallbackData->pMessage, "must be a memory object") != nullptr) { return VK_FALSE; } - /* - // This is a valid warning because its illegal in Vulkan, but in practice it should work according to VK_KHR_maintenance2 - if (strstr(pCallbackData->pMessage, "VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 with tiling VK_IMAGE_TILING_OPTIMAL does not support usage that includes VK_IMAGE_USAGE_STORAGE_BIT") != nullptr) { - return VK_FALSE; - } - if (strstr(pCallbackData->pMessage, "VK_FORMAT_R4G4B4A4_UNORM_PACK16 with tiling VK_IMAGE_TILING_OPTIMAL does not support usage that includes VK_IMAGE_USAGE_STORAGE_BIT") != nullptr) { - return VK_FALSE; - } -*/ // Workaround for Vulkan-Loader usability bug: https://github.com/KhronosGroup/Vulkan-Loader/issues/262. if (strstr(pCallbackData->pMessage, "wrong ELF class: ELFCLASS32") != nullptr) { return VK_FALSE; } + +#ifdef WINDOWS_ENABLED + // Some software installs Vulkan overlays in Windows registry and never cleans them up on uninstall. + // So we get spammy error level messages from the loader about those - make them verbose instead. + if (strstr(pCallbackData->pMessage, "loader_get_json: Failed to open JSON file") != nullptr) { + messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT; + } +#endif + if (pCallbackData->pMessageIdName && strstr(pCallbackData->pMessageIdName, "UNASSIGNED-CoreValidation-DrawState-ClearCmdBeforeDraw") != nullptr) { return VK_FALSE; } @@ -215,13 +227,13 @@ VkBool32 VulkanContext::_check_layers(uint32_t check_count, const char *const *c Error VulkanContext::_get_preferred_validation_layers(uint32_t *count, const char *const **names) { static const LocalVector<LocalVector<const char *>> instance_validation_layers_alt{ - // Preferred set of validation layers + // Preferred set of validation layers. { "VK_LAYER_KHRONOS_validation" }, - // Alternative (deprecated, removed in SDK 1.1.126.0) set of validation layers + // Alternative (deprecated, removed in SDK 1.1.126.0) set of validation layers. { "VK_LAYER_LUNARG_standard_validation" }, - // Alternative (deprecated, removed in SDK 1.1.121.1) set of validation layers + // Alternative (deprecated, removed in SDK 1.1.121.1) set of validation layers. { "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", "VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_core_validation", "VK_LAYER_GOOGLE_unique_objects" } }; @@ -269,7 +281,7 @@ typedef VkResult(VKAPI_PTR *_vkEnumerateInstanceVersion)(uint32_t *); Error VulkanContext::_obtain_vulkan_version() { // https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkApplicationInfo.html#_description - // for Vulkan 1.0 vkEnumerateInstanceVersion is not available, including not in the loader we compile against on Android. + // For Vulkan 1.0 vkEnumerateInstanceVersion is not available, including not in the loader we compile against on Android. _vkEnumerateInstanceVersion func = (_vkEnumerateInstanceVersion)vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceVersion"); if (func != nullptr) { uint32_t api_version; @@ -279,15 +291,15 @@ Error VulkanContext::_obtain_vulkan_version() { vulkan_minor = VK_API_VERSION_MINOR(api_version); vulkan_patch = VK_API_VERSION_PATCH(api_version); } else { - // according to the documentation this shouldn't fail with anything except a memory allocation error - // in which case we're in deep trouble anyway + // According to the documentation this shouldn't fail with anything except a memory allocation error + // in which case we're in deep trouble anyway. ERR_FAIL_V(ERR_CANT_CREATE); } } else { print_line("vkEnumerateInstanceVersion not available, assuming Vulkan 1.0."); } - // we don't go above 1.2 + // We don't go above 1.2. if ((vulkan_major > 1) || (vulkan_major == 1 && vulkan_minor > 2)) { vulkan_major = 1; vulkan_minor = 2; @@ -303,7 +315,7 @@ Error VulkanContext::_initialize_extensions() { enabled_extension_count = 0; enabled_debug_utils = false; enabled_debug_report = false; - /* Look for instance extensions */ + // Look for instance extensions. VkBool32 surfaceExtFound = 0; VkBool32 platformSurfaceExtFound = 0; memset(extension_names, 0, sizeof(extension_names)); @@ -403,7 +415,7 @@ String VulkanContext::SubgroupCapabilities::supported_stages_desc() const { res += ", STAGE_COMPUTE"; } - /* these are not defined on Android GRMBL */ + // These are not defined on Android GRMBL. if (supportedStages & 0x00000100 /* VK_SHADER_STAGE_RAYGEN_BIT_KHR */) { res += ", STAGE_RAYGEN_KHR"; } @@ -429,7 +441,7 @@ String VulkanContext::SubgroupCapabilities::supported_stages_desc() const { res += ", STAGE_MESH_NV"; } - return res.substr(2); // remove first ", " + return res.substr(2); // Remove first ", " } uint32_t VulkanContext::SubgroupCapabilities::supported_operations_flags_rd() const { @@ -494,19 +506,22 @@ String VulkanContext::SubgroupCapabilities::supported_operations_desc() const { res += ", FEATURE_PARTITIONED_NV"; } - return res.substr(2); // remove first ", " + return res.substr(2); // Remove first ", " } Error VulkanContext::_check_capabilities() { // https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_multiview.html // https://www.khronos.org/blog/vulkan-subgroup-tutorial - // for Vulkan 1.0 vkGetPhysicalDeviceProperties2 is not available, including not in the loader we compile against on Android. + // For Vulkan 1.0 vkGetPhysicalDeviceProperties2 is not available, including not in the loader we compile against on Android. - // so we check if the functions are accessible by getting their function pointers and skipping if not - // (note that the desktop loader does a better job here but the android loader doesn't) + // So we check if the functions are accessible by getting their function pointers and skipping if not + // (note that the desktop loader does a better job here but the android loader doesn't.) - // assume not supported until proven otherwise + // Assume not supported until proven otherwise. + vrs_capabilities.pipeline_vrs_supported = false; + vrs_capabilities.primitive_vrs_supported = false; + vrs_capabilities.attachment_vrs_supported = false; multiview_capabilities.is_supported = false; multiview_capabilities.geometry_shader_is_supported = false; multiview_capabilities.tessellation_shader_is_supported = false; @@ -523,17 +538,25 @@ Error VulkanContext::_check_capabilities() { storage_buffer_capabilities.storage_push_constant_16_is_supported = false; storage_buffer_capabilities.storage_input_output_16 = false; - // check for extended features + // Check for extended features. PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2"); if (vkGetPhysicalDeviceFeatures2_func == nullptr) { - // In Vulkan 1.0 might be accessible under its original extension name + // In Vulkan 1.0 might be accessible under its original extension name. vkGetPhysicalDeviceFeatures2_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2KHR"); } if (vkGetPhysicalDeviceFeatures2_func != nullptr) { - // check our extended features + // Check our extended features. + VkPhysicalDeviceFragmentShadingRateFeaturesKHR vrs_features = { + /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR, + /*pNext*/ nullptr, + /*pipelineFragmentShadingRate*/ false, + /*primitiveFragmentShadingRate*/ false, + /*attachmentFragmentShadingRate*/ false, + }; + VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader_features = { /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR, - /*pNext*/ nullptr, + /*pNext*/ &vrs_features, /*shaderFloat16*/ false, /*shaderInt8*/ false, }; @@ -561,6 +584,10 @@ Error VulkanContext::_check_capabilities() { vkGetPhysicalDeviceFeatures2_func(gpu, &device_features); + vrs_capabilities.pipeline_vrs_supported = vrs_features.pipelineFragmentShadingRate; + vrs_capabilities.primitive_vrs_supported = vrs_features.primitiveFragmentShadingRate; + vrs_capabilities.attachment_vrs_supported = vrs_features.attachmentFragmentShadingRate; + multiview_capabilities.is_supported = multiview_features.multiview; multiview_capabilities.geometry_shader_is_supported = multiview_features.multiviewGeometryShader; multiview_capabilities.tessellation_shader_is_supported = multiview_features.multiviewTessellationShader; @@ -574,31 +601,40 @@ Error VulkanContext::_check_capabilities() { storage_buffer_capabilities.storage_input_output_16 = storage_feature.storageInputOutput16; } - // check extended properties + // Check extended properties. PFN_vkGetPhysicalDeviceProperties2 device_properties_func = (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceProperties2"); if (device_properties_func == nullptr) { - // In Vulkan 1.0 might be accessible under its original extension name + // In Vulkan 1.0 might be accessible under its original extension name. device_properties_func = (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceProperties2KHR"); } if (device_properties_func != nullptr) { + VkPhysicalDeviceFragmentShadingRatePropertiesKHR vrsProperties; VkPhysicalDeviceMultiviewProperties multiviewProperties; VkPhysicalDeviceSubgroupProperties subgroupProperties; VkPhysicalDeviceProperties2 physicalDeviceProperties; + void *nextptr = nullptr; subgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES; - subgroupProperties.pNext = nullptr; - - physicalDeviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + subgroupProperties.pNext = nextptr; + nextptr = &subgroupProperties; if (multiview_capabilities.is_supported) { multiviewProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES; - multiviewProperties.pNext = &subgroupProperties; + multiviewProperties.pNext = nextptr; - physicalDeviceProperties.pNext = &multiviewProperties; - } else { - physicalDeviceProperties.pNext = &subgroupProperties; + nextptr = &multiviewProperties; } + if (vrs_capabilities.attachment_vrs_supported) { + vrsProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR; + vrsProperties.pNext = nextptr; + + nextptr = &vrsProperties; + } + + physicalDeviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + physicalDeviceProperties.pNext = nextptr; + device_properties_func(gpu, &physicalDeviceProperties); subgroup_capabilities.size = subgroupProperties.subgroupSize; @@ -609,6 +645,28 @@ Error VulkanContext::_check_capabilities() { // - supportedOperations has VK_SUBGROUP_FEATURE_QUAD_BIT subgroup_capabilities.quadOperationsInAllStages = subgroupProperties.quadOperationsInAllStages; + if (vrs_capabilities.pipeline_vrs_supported || vrs_capabilities.primitive_vrs_supported || vrs_capabilities.attachment_vrs_supported) { + print_verbose("- Vulkan Varying Shading Rates supported:"); + if (vrs_capabilities.pipeline_vrs_supported) { + print_verbose(" Pipeline fragment shading rate"); + } + if (vrs_capabilities.primitive_vrs_supported) { + print_verbose(" Primitive fragment shading rate"); + } + if (vrs_capabilities.attachment_vrs_supported) { + // TODO expose these somehow to the end user + vrs_capabilities.min_texel_size.x = vrsProperties.minFragmentShadingRateAttachmentTexelSize.width; + vrs_capabilities.min_texel_size.y = vrsProperties.minFragmentShadingRateAttachmentTexelSize.height; + vrs_capabilities.max_texel_size.x = vrsProperties.maxFragmentShadingRateAttachmentTexelSize.width; + vrs_capabilities.max_texel_size.y = vrsProperties.maxFragmentShadingRateAttachmentTexelSize.height; + + print_verbose(String(" Attachment fragment shading rate") + String(", min texel size: (") + itos(vrs_capabilities.min_texel_size.x) + String(", ") + itos(vrs_capabilities.min_texel_size.y) + String(")") + String(", max texel size: (") + itos(vrs_capabilities.max_texel_size.x) + String(", ") + itos(vrs_capabilities.max_texel_size.y) + String(")")); + } + + } else { + print_verbose("- Vulkan Varying Shading Rates not supported"); + } + if (multiview_capabilities.is_supported) { multiview_capabilities.max_view_count = multiviewProperties.maxMultiviewViewCount; multiview_capabilities.max_instance_count = multiviewProperties.maxMultiviewInstanceIndex; @@ -635,10 +693,10 @@ Error VulkanContext::_check_capabilities() { } Error VulkanContext::_create_instance() { - /* obtain version */ + // Obtain Vulkan version. _obtain_vulkan_version(); - /* initialise extensions */ + // Initialize extensions. { Error err = _initialize_extensions(); if (err != OK) { @@ -726,8 +784,7 @@ Error VulkanContext::_create_instance() { #endif if (enabled_debug_utils) { - // Setup VK_EXT_debug_utils function pointers always (we use them for - // debug labels and names). + // Setup VK_EXT_debug_utils function pointers always (we use them for debug labels and names). CreateDebugUtilsMessengerEXT = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(inst, "vkCreateDebugUtilsMessengerEXT"); DestroyDebugUtilsMessengerEXT = @@ -800,7 +857,7 @@ Error VulkanContext::_create_instance() { } Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) { - /* Make initial call to query gpu_count, then second call for gpu info*/ + // Make initial call to query gpu_count, then second call for gpu info. uint32_t gpu_count = 0; VkResult err = vkEnumeratePhysicalDevices(inst, &gpu_count, nullptr); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); @@ -836,7 +893,7 @@ Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) { return ERR_CANT_CREATE; } - // not really needed but nice to print the correct entry + // Not really needed but nice to print the correct entry. for (uint32_t i = 0; i < gpu_count; ++i) { if (physical_devices[i] == gpu) { device_index = i; @@ -948,13 +1005,13 @@ Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) { free(physical_devices); - /* Look for device extensions */ + // Look for device extensions. uint32_t device_extension_count = 0; VkBool32 swapchainExtFound = 0; enabled_extension_count = 0; memset(extension_names, 0, sizeof(extension_names)); - /* Get identifier properties */ + // Get identifier properties. vkGetPhysicalDeviceProperties(gpu, &gpu_props); device_name = gpu_props.deviceName; @@ -996,9 +1053,16 @@ Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) { extension_names[enabled_extension_count++] = VK_KHR_SWAPCHAIN_EXTENSION_NAME; } if (!strcmp(VK_KHR_MULTIVIEW_EXTENSION_NAME, device_extensions[i].extensionName)) { - // if multiview is supported, enable it + // If multiview is supported, enable it. extension_names[enabled_extension_count++] = VK_KHR_MULTIVIEW_EXTENSION_NAME; } + if (!strcmp(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME, device_extensions[i].extensionName)) { + // if shading rate image is supported, enable it + extension_names[enabled_extension_count++] = VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME; + } + if (!strcmp(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME, device_extensions[i].extensionName)) { + extension_names[enabled_extension_count++] = VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME; + } if (enabled_extension_count >= MAX_EXTENSIONS) { free(device_extensions); ERR_FAIL_V_MSG(ERR_BUG, "Enabled extension count reaches MAX_EXTENSIONS, BUG"); @@ -1049,19 +1113,18 @@ Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) { " extension.\n\nDo you have a compatible Vulkan installable client driver (ICD) installed?\n" "vkCreateInstance Failure"); - /* Call with nullptr data to get count */ + // Call with nullptr data to get count. vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_family_count, nullptr); ERR_FAIL_COND_V(queue_family_count == 0, ERR_CANT_CREATE); queue_props = (VkQueueFamilyProperties *)malloc(queue_family_count * sizeof(VkQueueFamilyProperties)); vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_family_count, queue_props); - // Query fine-grained feature support for this device. // If app has specific feature requirements it should check supported // features based on this query vkGetPhysicalDeviceFeatures(gpu, &physical_device_features); - physical_device_features.robustBufferAccess = false; //turn off robust buffer access, which can hamper performance on some hardware + physical_device_features.robustBufferAccess = false; // Turn off robust buffer access, which can hamper performance on some hardware. #define GET_INSTANCE_PROC_ADDR(inst, entrypoint) \ { \ @@ -1076,7 +1139,7 @@ Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) { GET_INSTANCE_PROC_ADDR(inst, GetPhysicalDeviceSurfacePresentModesKHR); GET_INSTANCE_PROC_ADDR(inst, GetSwapchainImagesKHR); - // get info about what our vulkan driver is capable off + // Gets capability info for current Vulkan driver. { Error res = _check_capabilities(); if (res != OK) { @@ -1110,11 +1173,23 @@ Error VulkanContext::_create_device() { }; nextptr = &shader_features; + VkPhysicalDeviceFragmentShadingRateFeaturesKHR vrs_features; + if (vrs_capabilities.pipeline_vrs_supported || vrs_capabilities.primitive_vrs_supported || vrs_capabilities.attachment_vrs_supported) { + // insert into our chain to enable these features if they are available + vrs_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR; + vrs_features.pNext = nextptr; + vrs_features.pipelineFragmentShadingRate = vrs_capabilities.pipeline_vrs_supported; + vrs_features.primitiveFragmentShadingRate = vrs_capabilities.primitive_vrs_supported; + vrs_features.attachmentFragmentShadingRate = vrs_capabilities.attachment_vrs_supported; + + nextptr = &vrs_features; + } + VkPhysicalDeviceVulkan11Features vulkan11features; VkPhysicalDevice16BitStorageFeaturesKHR storage_feature; VkPhysicalDeviceMultiviewFeatures multiview_features; if (vulkan_major > 1 || vulkan_minor >= 2) { - // In Vulkan 1.2 and newer we use a newer struct to enable various features + // In Vulkan 1.2 and newer we use a newer struct to enable various features. vulkan11features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; vulkan11features.pNext = nextptr; @@ -1132,7 +1207,7 @@ Error VulkanContext::_create_device() { vulkan11features.shaderDrawParameters = 0; nextptr = &vulkan11features; } else { - // On Vulkan 1.0 and 1.1 we use our older structs to initialise these features + // On Vulkan 1.0 and 1.1 we use our older structs to initialise these features. storage_feature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR; storage_feature.pNext = nextptr; storage_feature.storageBuffer16BitAccess = storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported; @@ -1161,7 +1236,7 @@ Error VulkanContext::_create_device() { /*ppEnabledLayerNames*/ nullptr, /*enabledExtensionCount*/ enabled_extension_count, /*ppEnabledExtensionNames*/ (const char *const *)extension_names, - /*pEnabledFeatures*/ &physical_device_features, // If specific features are required, pass them in here + /*pEnabledFeatures*/ &physical_device_features, // If specific features are required, pass them in here. }; if (separate_present_queue) { queues[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; @@ -1193,7 +1268,7 @@ Error VulkanContext::_initialize_queues(VkSurfaceKHR p_surface) { } // Search for a graphics and a present queue in the array of queue - // families, try to find one that supports both + // families, try to find one that supports both. uint32_t graphicsQueueFamilyIndex = UINT32_MAX; uint32_t presentQueueFamilyIndex = UINT32_MAX; for (uint32_t i = 0; i < queue_family_count; i++) { @@ -1223,7 +1298,7 @@ Error VulkanContext::_initialize_queues(VkSurfaceKHR p_surface) { free(supportsPresent); - // Generate error if could not find both a graphics and a present queue + // Generate error if could not find both a graphics and a present queue. ERR_FAIL_COND_V_MSG(graphicsQueueFamilyIndex == UINT32_MAX || presentQueueFamilyIndex == UINT32_MAX, ERR_CANT_CREATE, "Could not find both graphics and present queues\n"); @@ -1279,7 +1354,7 @@ Error VulkanContext::_initialize_queues(VkSurfaceKHR p_surface) { color_space = surfFormats[0].colorSpace; } else { // These should be ordered with the ones we want to use on top and fallback modes further down - // we want an 32bit RGBA unsigned normalised buffer or similar + // we want a 32bit RGBA unsigned normalised buffer or similar. const VkFormat allowed_formats[] = { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM @@ -1291,7 +1366,7 @@ Error VulkanContext::_initialize_queues(VkSurfaceKHR p_surface) { ERR_FAIL_V_MSG(ERR_CANT_CREATE, "formatCount less than 1"); } - // Find the first format that we support + // Find the first format that we support. format = VK_FORMAT_UNDEFINED; for (uint32_t af = 0; af < allowed_formats_count && format == VK_FORMAT_UNDEFINED; af++) { for (uint32_t sf = 0; sf < formatCount && format == VK_FORMAT_UNDEFINED; sf++) { @@ -1323,7 +1398,7 @@ Error VulkanContext::_create_semaphores() { VkResult err; // Create semaphores to synchronize acquiring presentable buffers before - // rendering and waiting for drawing to be complete before presenting + // rendering and waiting for drawing to be complete before presenting. VkSemaphoreCreateInfo semaphoreCreateInfo = { /*sType*/ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, /*pNext*/ nullptr, @@ -1331,7 +1406,7 @@ Error VulkanContext::_create_semaphores() { }; // Create fences that we can use to throttle if we get too far - // ahead of the image presents + // ahead of the image presents. VkFenceCreateInfo fence_ci = { /*sType*/ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, /*pNext*/ nullptr, @@ -1351,7 +1426,7 @@ Error VulkanContext::_create_semaphores() { } frame_index = 0; - // Get Memory information and properties + // Get Memory information and properties. vkGetPhysicalDeviceMemoryProperties(gpu, &memory_properties); return OK; @@ -1426,7 +1501,7 @@ bool VulkanContext::window_is_valid_swapchain(DisplayServer::WindowID p_window) VkRenderPass VulkanContext::window_get_render_pass(DisplayServer::WindowID p_window) { ERR_FAIL_COND_V(!windows.has(p_window), VK_NULL_HANDLE); Window *w = &windows[p_window]; - //vulkan use of currentbuffer + // Vulkan use of currentbuffer. return w->render_pass; } @@ -1434,7 +1509,7 @@ VkFramebuffer VulkanContext::window_get_framebuffer(DisplayServer::WindowID p_wi ERR_FAIL_COND_V(!windows.has(p_window), VK_NULL_HANDLE); ERR_FAIL_COND_V(!buffers_prepared, VK_NULL_HANDLE); Window *w = &windows[p_window]; - //vulkan use of currentbuffer + // Vulkan use of currentbuffer. if (w->swapchain_image_resources != VK_NULL_HANDLE) { return w->swapchain_image_resources[w->current_buffer].framebuffer; } else { @@ -1459,7 +1534,7 @@ Error VulkanContext::_clean_up_swap_chain(Window *window) { } vkDeviceWaitIdle(device); - //this destroys images associated it seems + // This destroys images associated it seems. fpDestroySwapchainKHR(device, window->swapchain, nullptr); window->swapchain = VK_NULL_HANDLE; vkDestroyRenderPass(device, window->render_pass, nullptr); @@ -1485,7 +1560,7 @@ Error VulkanContext::_update_swap_chain(Window *window) { _clean_up_swap_chain(window); } - // Check the surface capabilities and formats + // Check the surface capabilities and formats. VkSurfaceCapabilitiesKHR surfCapabilities; err = fpGetPhysicalDeviceSurfaceCapabilitiesKHR(gpu, window->surface, &surfCapabilities); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); @@ -1502,7 +1577,7 @@ Error VulkanContext::_update_swap_chain(Window *window) { } VkExtent2D swapchainExtent; - // width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF. + // Width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF. if (surfCapabilities.currentExtent.width == 0xFFFFFFFF) { // If the surface size is undefined, the size is set to the size // of the images requested, which must fit within the minimum and @@ -1522,7 +1597,7 @@ Error VulkanContext::_update_swap_chain(Window *window) { swapchainExtent.height = surfCapabilities.maxImageExtent.height; } } else { - // If the surface size is defined, the swap chain size must match + // If the surface size is defined, the swap chain size must match. swapchainExtent = surfCapabilities.currentExtent; window->width = surfCapabilities.currentExtent.width; window->height = surfCapabilities.currentExtent.height; @@ -1530,7 +1605,7 @@ Error VulkanContext::_update_swap_chain(Window *window) { if (window->width == 0 || window->height == 0) { free(presentModes); - //likely window minimized, no swapchain created + // Likely window minimized, no swapchain created. return OK; } // The FIFO present mode is guaranteed by the spec to be supported @@ -1592,7 +1667,7 @@ Error VulkanContext::_update_swap_chain(Window *window) { window->presentMode = requested_present_mode; } else { WARN_PRINT("Requested VSync mode is not available!"); - window->vsync_mode = DisplayServer::VSYNC_ENABLED; //Set to default + window->vsync_mode = DisplayServer::VSYNC_ENABLED; // Set to default. } print_verbose("Using present mode: " + String(string_VkPresentModeKHR(window->presentMode))); @@ -1601,13 +1676,13 @@ Error VulkanContext::_update_swap_chain(Window *window) { // Determine the number of VkImages to use in the swap chain. // Application desires to acquire 3 images at a time for triple - // buffering + // buffering. uint32_t desiredNumOfSwapchainImages = 3; if (desiredNumOfSwapchainImages < surfCapabilities.minImageCount) { desiredNumOfSwapchainImages = surfCapabilities.minImageCount; } // If maxImageCount is 0, we can ask for as many images as we want; - // otherwise we're limited to maxImageCount + // otherwise we're limited to maxImageCount. if ((surfCapabilities.maxImageCount > 0) && (desiredNumOfSwapchainImages > surfCapabilities.maxImageCount)) { // Application must settle for fewer images than desired: desiredNumOfSwapchainImages = surfCapabilities.maxImageCount; @@ -1620,7 +1695,7 @@ Error VulkanContext::_update_swap_chain(Window *window) { preTransform = surfCapabilities.currentTransform; } - // Find a supported composite alpha mode - one of these is guaranteed to be set + // Find a supported composite alpha mode - one of these is guaranteed to be set. VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; VkCompositeAlphaFlagBitsKHR compositeAlphaFlags[4] = { VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, @@ -1667,7 +1742,7 @@ Error VulkanContext::_update_swap_chain(Window *window) { ERR_FAIL_COND_V(err, ERR_CANT_CREATE); if (swapchainImageCount == 0) { - //assign here for the first time. + // Assign here for the first time. swapchainImageCount = sp_image_count; } else { ERR_FAIL_COND_V(swapchainImageCount != sp_image_count, ERR_BUG); @@ -1725,7 +1800,9 @@ Error VulkanContext::_update_swap_chain(Window *window) { /******** FRAMEBUFFER ************/ { - const VkAttachmentDescription attachment = { + const VkAttachmentDescription2KHR attachment = { + /*sType*/ VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR, + /*pNext*/ nullptr, /*flags*/ 0, /*format*/ format, /*samples*/ VK_SAMPLE_COUNT_1_BIT, @@ -1737,14 +1814,20 @@ Error VulkanContext::_update_swap_chain(Window *window) { /*finalLayout*/ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, }; - const VkAttachmentReference color_reference = { + const VkAttachmentReference2KHR color_reference = { + /*sType*/ VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR, + /*pNext*/ nullptr, /*attachment*/ 0, /*layout*/ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + /*aspectMask*/ 0, }; - const VkSubpassDescription subpass = { + const VkSubpassDescription2KHR subpass = { + /*sType*/ VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR, + /*pNext*/ nullptr, /*flags*/ 0, /*pipelineBindPoint*/ VK_PIPELINE_BIND_POINT_GRAPHICS, + /*viewMask*/ 1, /*inputAttachmentCount*/ 0, /*pInputAttachments*/ nullptr, /*colorAttachmentCount*/ 1, @@ -1754,8 +1837,10 @@ Error VulkanContext::_update_swap_chain(Window *window) { /*preserveAttachmentCount*/ 0, /*pPreserveAttachments*/ nullptr, }; - const VkRenderPassCreateInfo rp_info = { - /*sTyp*/ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + + uint32_t view_masks = 1; + const VkRenderPassCreateInfo2KHR rp_info = { + /*sType*/ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR, /*pNext*/ nullptr, /*flags*/ 0, /*attachmentCount*/ 1, @@ -1764,9 +1849,11 @@ Error VulkanContext::_update_swap_chain(Window *window) { /*pSubpasses*/ &subpass, /*dependencyCount*/ 0, /*pDependencies*/ nullptr, + /*correlatedViewMaskCount*/ 1, + /*pCorrelatedViewMasks*/ &view_masks, }; - err = vkCreateRenderPass(device, &rp_info, nullptr, &window->render_pass); + err = vkCreateRenderPass2KHR(device, &rp_info, nullptr, &window->render_pass); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); for (uint32_t i = 0; i < swapchainImageCount; i++) { @@ -1839,7 +1926,7 @@ Error VulkanContext::_update_swap_chain(Window *window) { } } - //reset current buffer + // Reset current buffer. window->current_buffer = 0; return OK; @@ -1860,27 +1947,30 @@ Error VulkanContext::initialize() { return OK; } -void VulkanContext::set_setup_buffer(const VkCommandBuffer &pCommandBuffer) { - command_buffer_queue.write[0] = pCommandBuffer; +void VulkanContext::set_setup_buffer(VkCommandBuffer p_command_buffer) { + command_buffer_queue.write[0] = p_command_buffer; } -void VulkanContext::append_command_buffer(const VkCommandBuffer &pCommandBuffer) { +void VulkanContext::append_command_buffer(VkCommandBuffer p_command_buffer) { if (command_buffer_queue.size() <= command_buffer_count) { command_buffer_queue.resize(command_buffer_count + 1); } - command_buffer_queue.write[command_buffer_count] = pCommandBuffer; + command_buffer_queue.write[command_buffer_count] = p_command_buffer; command_buffer_count++; } void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) { - // ensure everything else pending is executed + // Ensure everything else pending is executed. vkDeviceWaitIdle(device); - //flush the pending setup buffer + // Flush the pending setup buffer. + + bool setup_flushable = p_flush_setup && command_buffer_queue[0]; + bool pending_flushable = p_flush_pending && command_buffer_count > 1; - if (p_flush_setup && command_buffer_queue[0]) { - //use a fence to wait for everything done + if (setup_flushable) { + // Use a fence to wait for everything done. VkSubmitInfo submit_info; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.pNext = nullptr; @@ -1889,33 +1979,33 @@ void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) { submit_info.pWaitSemaphores = nullptr; submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = command_buffer_queue.ptr(); - submit_info.signalSemaphoreCount = 0; - submit_info.pSignalSemaphores = nullptr; + submit_info.signalSemaphoreCount = pending_flushable ? 1 : 0; + submit_info.pSignalSemaphores = pending_flushable ? &draw_complete_semaphores[frame_index] : nullptr; VkResult err = vkQueueSubmit(graphics_queue, 1, &submit_info, VK_NULL_HANDLE); command_buffer_queue.write[0] = nullptr; ERR_FAIL_COND(err); - vkDeviceWaitIdle(device); } - if (p_flush_pending && command_buffer_count > 1) { - //use a fence to wait for everything done + if (pending_flushable) { + // Use a fence to wait for everything to finish. VkSubmitInfo submit_info; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.pNext = nullptr; - submit_info.pWaitDstStageMask = nullptr; - submit_info.waitSemaphoreCount = 0; - submit_info.pWaitSemaphores = nullptr; + VkPipelineStageFlags wait_stage_mask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + submit_info.pWaitDstStageMask = setup_flushable ? &wait_stage_mask : nullptr; + submit_info.waitSemaphoreCount = setup_flushable ? 1 : 0; + submit_info.pWaitSemaphores = setup_flushable ? &draw_complete_semaphores[frame_index] : nullptr; submit_info.commandBufferCount = command_buffer_count - 1; submit_info.pCommandBuffers = command_buffer_queue.ptr() + 1; submit_info.signalSemaphoreCount = 0; submit_info.pSignalSemaphores = nullptr; VkResult err = vkQueueSubmit(graphics_queue, 1, &submit_info, VK_NULL_HANDLE); - ERR_FAIL_COND(err); - vkDeviceWaitIdle(device); - command_buffer_count = 1; + ERR_FAIL_COND(err); } + + vkDeviceWaitIdle(device); } Error VulkanContext::prepare_buffers() { @@ -1925,7 +2015,7 @@ Error VulkanContext::prepare_buffers() { VkResult err; - // Ensure no more than FRAME_LAG renderings are outstanding + // Ensure no more than FRAME_LAG renderings are outstanding. vkWaitForFences(device, 1, &fences[frame_index], VK_TRUE, UINT64_MAX); vkResetFences(device, 1, &fences[frame_index]); @@ -1945,13 +2035,13 @@ Error VulkanContext::prepare_buffers() { w->image_acquired_semaphores[frame_index], VK_NULL_HANDLE, &w->current_buffer); if (err == VK_ERROR_OUT_OF_DATE_KHR) { - // swapchain is out of date (e.g. the window was resized) and + // Swapchain is out of date (e.g. the window was resized) and // must be recreated: print_verbose("Vulkan: Early out of date swapchain, recreating."); - //resize_notify(); + // resize_notify(); _update_swap_chain(w); } else if (err == VK_SUBOPTIMAL_KHR) { - // swapchain is not as optimal as it could be, but the platform's + // Swapchain is not as optimal as it could be, but the platform's // presentation engine will still present the image correctly. print_verbose("Vulkan: Early suboptimal swapchain."); break; @@ -1998,7 +2088,7 @@ Error VulkanContext::swap_buffers() { uint32_t commands_to_submit = 0; if (command_buffer_queue[0] == nullptr) { - //no setup command, but commands to submit, submit from the first and skip command + // No setup command, but commands to submit, submit from the first and skip command. if (command_buffer_count > 1) { commands_ptr = command_buffer_queue.ptr() + 1; commands_to_submit = command_buffer_count - 1; @@ -2041,7 +2131,7 @@ Error VulkanContext::swap_buffers() { if (separate_present_queue) { // If we are using separate queues, change image ownership to the // present queue before presenting, waiting for the draw complete - // semaphore and signalling the ownership released semaphore when finished + // semaphore and signalling the ownership released semaphore when finished. VkFence nullFence = VK_NULL_HANDLE; pipe_stage_flags[0] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; submit_info.waitSemaphoreCount = 1; @@ -2068,7 +2158,7 @@ Error VulkanContext::swap_buffers() { } // If we are using separate queues, we have to wait for image ownership, - // otherwise wait for draw complete + // otherwise wait for draw complete. VkPresentInfoKHR present = { /*sType*/ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, /*pNext*/ nullptr, @@ -2173,12 +2263,12 @@ Error VulkanContext::swap_buffers() { frame_index %= FRAME_LAG; if (err == VK_ERROR_OUT_OF_DATE_KHR) { - // swapchain is out of date (e.g. the window was resized) and + // Swapchain is out of date (e.g. the window was resized) and // must be recreated: print_verbose("Vulkan: Swapchain is out of date, recreating."); resize_notify(); } else if (err == VK_SUBOPTIMAL_KHR) { - // swapchain is not as optimal as it could be, but the platform's + // Swapchain is not as optimal as it could be, but the platform's // presentation engine will still present the image correctly. print_verbose("Vulkan: Swapchain is suboptimal."); } else { @@ -2223,7 +2313,7 @@ VkPhysicalDeviceLimits VulkanContext::get_device_limits() const { RID VulkanContext::local_device_create() { LocalDevice ld; - { //create device + { // Create device. VkResult err; float queue_priorities[1] = { 0.0 }; VkDeviceQueueCreateInfo queues[2]; @@ -2244,13 +2334,13 @@ RID VulkanContext::local_device_create() { /*ppEnabledLayerNames */ nullptr, /*enabledExtensionCount */ enabled_extension_count, /*ppEnabledExtensionNames */ (const char *const *)extension_names, - /*pEnabledFeatures */ &physical_device_features, // If specific features are required, pass them in here + /*pEnabledFeatures */ &physical_device_features, // If specific features are required, pass them in here. }; err = vkCreateDevice(gpu, &sdevice, nullptr, &ld.device); ERR_FAIL_COND_V(err, RID()); } - { //create graphics queue + { // Create graphics queue. vkGetDeviceQueue(ld.device, graphics_queue_family_index, 0, &ld.queue); } diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h index 236e3bf35f..b2eb43975f 100644 --- a/drivers/vulkan/vulkan_context.h +++ b/drivers/vulkan/vulkan_context.h @@ -69,6 +69,15 @@ public: uint32_t max_instance_count; }; + struct VRSCapabilities { + bool pipeline_vrs_supported; // We can specify our fragment rate on a pipeline level + bool primitive_vrs_supported; // We can specify our fragment rate on each drawcall + bool attachment_vrs_supported; // We can provide a density map attachment on our framebuffer + + Size2i min_texel_size; + Size2i max_texel_size; + }; + struct ShaderCapabilities { bool shader_float16_is_supported; bool shader_int8_is_supported; @@ -104,6 +113,7 @@ private: uint32_t vulkan_patch = 0; SubgroupCapabilities subgroup_capabilities; MultiviewCapabilities multiview_capabilities; + VRSCapabilities vrs_capabilities; ShaderCapabilities shader_capabilities; StorageBufferCapabilities storage_buffer_capabilities; @@ -117,8 +127,8 @@ private: // Present queue. bool queues_initialized = false; - uint32_t graphics_queue_family_index = 0; - uint32_t present_queue_family_index = 0; + uint32_t graphics_queue_family_index = UINT32_MAX; + uint32_t present_queue_family_index = UINT32_MAX; bool separate_present_queue = false; VkQueue graphics_queue = VK_NULL_HANDLE; VkQueue present_queue = VK_NULL_HANDLE; @@ -206,6 +216,7 @@ private: PFN_vkQueuePresentKHR fpQueuePresentKHR = nullptr; PFN_vkGetRefreshCycleDurationGOOGLE fpGetRefreshCycleDurationGOOGLE = nullptr; PFN_vkGetPastPresentationTimingGOOGLE fpGetPastPresentationTimingGOOGLE = nullptr; + PFN_vkCreateRenderPass2KHR fpCreateRenderPass2KHR = nullptr; VkDebugUtilsMessengerEXT dbg_messenger = VK_NULL_HANDLE; VkDebugReportCallbackEXT dbg_debug_report = VK_NULL_HANDLE; @@ -256,10 +267,14 @@ protected: Error _get_preferred_validation_layers(uint32_t *count, const char *const **names); public: + // Extension calls + VkResult vkCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2 *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass); + uint32_t get_vulkan_major() const { return vulkan_major; }; uint32_t get_vulkan_minor() const { return vulkan_minor; }; SubgroupCapabilities get_subgroup_capabilities() const { return subgroup_capabilities; }; MultiviewCapabilities get_multiview_capabilities() const { return multiview_capabilities; }; + VRSCapabilities get_vrs_capabilities() const { return vrs_capabilities; }; ShaderCapabilities get_shader_capabilities() const { return shader_capabilities; }; StorageBufferCapabilities get_storage_buffer_capabilities() const { return storage_buffer_capabilities; }; @@ -289,8 +304,8 @@ public: VkFormat get_screen_format() const; VkPhysicalDeviceLimits get_device_limits() const; - void set_setup_buffer(const VkCommandBuffer &pCommandBuffer); - void append_command_buffer(const VkCommandBuffer &pCommandBuffer); + void set_setup_buffer(VkCommandBuffer p_command_buffer); + void append_command_buffer(VkCommandBuffer p_command_buffer); void resize_notify(); void flush(bool p_flush_setup = false, bool p_flush_pending = false); Error prepare_buffers(); |