Implement asynchronous transfer queues, thread guards on RenderingDevice. Add ubershaders and rework pipeline caches for Forward+ and Mobile.

- Implements asynchronous transfer queues from PR #87590.
- Adds ubershaders that can run with specialization constants specified as push constants.
- Pipelines with specialization constants can compile in the background.
- Added monitoring for pipeline compilations.
- Materials and shaders can now be created asynchronously on background threads.
- Meshes that are loaded on background threads can also compile pipelines as part of the loading process.
This commit is contained in:
Dario
2024-03-15 14:13:31 -03:00
parent 1917bc3454
commit e2c6daf7ef
78 changed files with 5218 additions and 2544 deletions

View File

@ -129,32 +129,32 @@ public:
#define ServerName RendererTextureStorage
#define server_name RSG::texture_storage
#define FUNCRIDTEX0(m_type) \
virtual RID m_type##_create() override { \
RID ret = RSG::texture_storage->texture_allocate(); \
if (Thread::get_caller_id() == server_thread || RSG::texture_storage->can_create_resources_async()) { \
RSG::texture_storage->m_type##_initialize(ret); \
} else { \
command_queue.push(RSG::texture_storage, &RendererTextureStorage::m_type##_initialize, ret); \
} \
return ret; \
#define FUNCRIDTEX0(m_type) \
virtual RID m_type##_create() override { \
RID ret = RSG::texture_storage->texture_allocate(); \
if (Thread::get_caller_id() == server_thread || RSG::rasterizer->can_create_resources_async()) { \
RSG::texture_storage->m_type##_initialize(ret); \
} else { \
command_queue.push(RSG::texture_storage, &RendererTextureStorage::m_type##_initialize, ret); \
} \
return ret; \
}
#define FUNCRIDTEX1(m_type, m_type1) \
virtual RID m_type##_create(m_type1 p1) override { \
RID ret = RSG::texture_storage->texture_allocate(); \
if (Thread::get_caller_id() == server_thread || RSG::texture_storage->can_create_resources_async()) { \
RSG::texture_storage->m_type##_initialize(ret, p1); \
} else { \
command_queue.push(RSG::texture_storage, &RendererTextureStorage::m_type##_initialize, ret, p1); \
} \
return ret; \
#define FUNCRIDTEX1(m_type, m_type1) \
virtual RID m_type##_create(m_type1 p1) override { \
RID ret = RSG::texture_storage->texture_allocate(); \
if (Thread::get_caller_id() == server_thread || RSG::rasterizer->can_create_resources_async()) { \
RSG::texture_storage->m_type##_initialize(ret, p1); \
} else { \
command_queue.push(RSG::texture_storage, &RendererTextureStorage::m_type##_initialize, ret, p1); \
} \
return ret; \
}
#define FUNCRIDTEX2(m_type, m_type1, m_type2) \
virtual RID m_type##_create(m_type1 p1, m_type2 p2) override { \
RID ret = RSG::texture_storage->texture_allocate(); \
if (Thread::get_caller_id() == server_thread || RSG::texture_storage->can_create_resources_async()) { \
if (Thread::get_caller_id() == server_thread || RSG::rasterizer->can_create_resources_async()) { \
RSG::texture_storage->m_type##_initialize(ret, p1, p2); \
} else { \
command_queue.push(RSG::texture_storage, &RendererTextureStorage::m_type##_initialize, ret, p1, p2); \
@ -165,7 +165,7 @@ public:
#define FUNCRIDTEX3(m_type, m_type1, m_type2, m_type3) \
virtual RID m_type##_create(m_type1 p1, m_type2 p2, m_type3 p3) override { \
RID ret = RSG::texture_storage->texture_allocate(); \
if (Thread::get_caller_id() == server_thread || RSG::texture_storage->can_create_resources_async()) { \
if (Thread::get_caller_id() == server_thread || RSG::rasterizer->can_create_resources_async()) { \
RSG::texture_storage->m_type##_initialize(ret, p1, p2, p3); \
} else { \
command_queue.push(RSG::texture_storage, &RendererTextureStorage::m_type##_initialize, ret, p1, p2, p3); \
@ -176,7 +176,7 @@ public:
#define FUNCRIDTEX6(m_type, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6) \
virtual RID m_type##_create(m_type1 p1, m_type2 p2, m_type3 p3, m_type4 p4, m_type5 p5, m_type6 p6) override { \
RID ret = RSG::texture_storage->texture_allocate(); \
if (Thread::get_caller_id() == server_thread || RSG::texture_storage->can_create_resources_async()) { \
if (Thread::get_caller_id() == server_thread || RSG::rasterizer->can_create_resources_async()) { \
RSG::texture_storage->m_type##_initialize(ret, p1, p2, p3, p4, p5, p6); \
} else { \
command_queue.push(RSG::texture_storage, &RendererTextureStorage::m_type##_initialize, ret, p1, p2, p3, p4, p5, p6); \
@ -245,6 +245,26 @@ public:
FUNCRIDSPLIT(shader)
virtual RID shader_create_from_code(const String &p_code, const String &p_path_hint = String()) override {
RID shader = RSG::material_storage->shader_allocate();
bool using_server_thread = Thread::get_caller_id() == server_thread;
if (using_server_thread || RSG::rasterizer->can_create_resources_async()) {
if (using_server_thread) {
command_queue.flush_if_pending();
}
RSG::material_storage->shader_initialize(shader);
RSG::material_storage->shader_set_code(shader, p_code);
RSG::material_storage->shader_set_path_hint(shader, p_path_hint);
} else {
command_queue.push(RSG::material_storage, &RendererMaterialStorage::shader_initialize, shader);
command_queue.push(RSG::material_storage, &RendererMaterialStorage::shader_set_code, shader, p_code);
command_queue.push(RSG::material_storage, &RendererMaterialStorage::shader_set_path_hint, shader, p_path_hint);
}
return shader;
}
FUNC2(shader_set_code, RID, const String &)
FUNC2(shader_set_path_hint, RID, const String &)
FUNC1RC(String, shader_get_code, RID)
@ -261,6 +281,28 @@ public:
FUNCRIDSPLIT(material)
virtual RID material_create_from_shader(RID p_next_pass, int p_render_priority, RID p_shader) override {
RID material = RSG::material_storage->material_allocate();
bool using_server_thread = Thread::get_caller_id() == server_thread;
if (using_server_thread || RSG::rasterizer->can_create_resources_async()) {
if (using_server_thread) {
command_queue.flush_if_pending();
}
RSG::material_storage->material_initialize(material);
RSG::material_storage->material_set_next_pass(material, p_next_pass);
RSG::material_storage->material_set_render_priority(material, p_render_priority);
RSG::material_storage->material_set_shader(material, p_shader);
} else {
command_queue.push(RSG::material_storage, &RendererMaterialStorage::material_initialize, material);
command_queue.push(RSG::material_storage, &RendererMaterialStorage::material_set_next_pass, material, p_next_pass);
command_queue.push(RSG::material_storage, &RendererMaterialStorage::material_set_render_priority, material, p_render_priority);
command_queue.push(RSG::material_storage, &RendererMaterialStorage::material_set_shader, material, p_shader);
}
return material;
}
FUNC2(material_set_shader, RID, RID)
FUNC3(material_set_param, RID, const StringName &, const Variant &)
@ -281,10 +323,9 @@ public:
virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces, int p_blend_shape_count = 0) override {
RID mesh = RSG::mesh_storage->mesh_allocate();
// TODO once we have RSG::mesh_storage, add can_create_resources_async and call here instead of texture_storage!!
if (Thread::get_caller_id() == server_thread || RSG::texture_storage->can_create_resources_async()) {
if (Thread::get_caller_id() == server_thread) {
bool using_server_thread = Thread::get_caller_id() == server_thread;
if (using_server_thread || RSG::rasterizer->can_create_resources_async()) {
if (using_server_thread) {
command_queue.flush_if_pending();
}
RSG::mesh_storage->mesh_initialize(mesh);
@ -292,12 +333,14 @@ public:
for (int i = 0; i < p_surfaces.size(); i++) {
RSG::mesh_storage->mesh_add_surface(mesh, p_surfaces[i]);
}
RSG::scene->mesh_generate_pipelines(mesh, using_server_thread);
} else {
command_queue.push(RSG::mesh_storage, &RendererMeshStorage::mesh_initialize, mesh);
command_queue.push(RSG::mesh_storage, &RendererMeshStorage::mesh_set_blend_shape_count, mesh, p_blend_shape_count);
for (int i = 0; i < p_surfaces.size(); i++) {
command_queue.push(RSG::mesh_storage, &RendererMeshStorage::mesh_add_surface, mesh, p_surfaces[i]);
}
command_queue.push(RSG::scene, &RenderingMethod::mesh_generate_pipelines, mesh, true);
}
return mesh;