initial commit, 4.5 stable
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled
This commit is contained in:
6
drivers/gles3/storage/SCsub
Normal file
6
drivers/gles3/storage/SCsub
Normal file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
from misc.utility.scons_hints import *
|
||||
|
||||
Import("env")
|
||||
|
||||
env.add_source_files(env.drivers_sources, "*.cpp")
|
251
drivers/gles3/storage/config.cpp
Normal file
251
drivers/gles3/storage/config.cpp
Normal file
@@ -0,0 +1,251 @@
|
||||
/**************************************************************************/
|
||||
/* config.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "config.h"
|
||||
|
||||
#include "../rasterizer_gles3.h"
|
||||
|
||||
#ifdef WEB_ENABLED
|
||||
#include <emscripten/html5_webgl.h>
|
||||
#endif
|
||||
|
||||
using namespace GLES3;
|
||||
|
||||
#define _GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
|
||||
|
||||
Config *Config::singleton = nullptr;
|
||||
|
||||
Config::Config() {
|
||||
singleton = this;
|
||||
|
||||
#ifdef WEB_ENABLED
|
||||
// Starting with Emscripten 3.1.51, glGetStringi(GL_EXTENSIONS, i) will only ever return
|
||||
// a fixed list of extensions, regardless of what additional extensions are enabled. This
|
||||
// isn't very useful for us in determining which extensions we can rely on here. So, instead
|
||||
// we use emscripten_webgl_get_supported_extensions() to get all supported extensions, which
|
||||
// is what Emscripten 3.1.50 and earlier do.
|
||||
{
|
||||
char *extension_array_string = emscripten_webgl_get_supported_extensions();
|
||||
PackedStringArray extension_array = String((const char *)extension_array_string).split(" ");
|
||||
extensions.reserve(extension_array.size() * 2);
|
||||
for (const String &s : extension_array) {
|
||||
extensions.insert(s);
|
||||
extensions.insert("GL_" + s);
|
||||
}
|
||||
free(extension_array_string);
|
||||
}
|
||||
#else
|
||||
{
|
||||
GLint max_extensions = 0;
|
||||
glGetIntegerv(GL_NUM_EXTENSIONS, &max_extensions);
|
||||
for (int i = 0; i < max_extensions; i++) {
|
||||
const GLubyte *s = glGetStringi(GL_EXTENSIONS, i);
|
||||
if (!s) {
|
||||
break;
|
||||
}
|
||||
extensions.insert((const char *)s);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bptc_supported = extensions.has("GL_ARB_texture_compression_bptc") || extensions.has("GL_EXT_texture_compression_bptc");
|
||||
astc_hdr_supported = extensions.has("GL_KHR_texture_compression_astc_hdr");
|
||||
astc_supported = astc_hdr_supported || extensions.has("GL_KHR_texture_compression_astc") || extensions.has("GL_OES_texture_compression_astc") || extensions.has("GL_KHR_texture_compression_astc_ldr") || extensions.has("WEBGL_compressed_texture_astc");
|
||||
astc_layered_supported = extensions.has("GL_KHR_texture_compression_astc_sliced_3d");
|
||||
|
||||
if (RasterizerGLES3::is_gles_over_gl()) {
|
||||
float_texture_supported = true;
|
||||
float_texture_linear_supported = true;
|
||||
etc2_supported = false;
|
||||
s3tc_supported = true;
|
||||
rgtc_supported = true; //RGTC - core since OpenGL version 3.0
|
||||
srgb_framebuffer_supported = true;
|
||||
} else {
|
||||
float_texture_supported = extensions.has("GL_EXT_color_buffer_float");
|
||||
float_texture_linear_supported = extensions.has("GL_OES_texture_float_linear");
|
||||
etc2_supported = true;
|
||||
#if defined(ANDROID_ENABLED) || defined(IOS_ENABLED)
|
||||
// Some Android devices report support for S3TC but we don't expect that and don't export the textures.
|
||||
// This could be fixed but so few devices support it that it doesn't seem useful (and makes bigger APKs).
|
||||
// For good measure we do the same hack for iOS, just in case.
|
||||
s3tc_supported = false;
|
||||
#else
|
||||
s3tc_supported = extensions.has("GL_EXT_texture_compression_dxt1") || extensions.has("GL_EXT_texture_compression_s3tc") || extensions.has("WEBGL_compressed_texture_s3tc");
|
||||
#endif
|
||||
rgtc_supported = extensions.has("GL_EXT_texture_compression_rgtc") || extensions.has("GL_ARB_texture_compression_rgtc");
|
||||
srgb_framebuffer_supported = extensions.has("GL_EXT_sRGB_write_control");
|
||||
}
|
||||
|
||||
glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &max_vertex_texture_image_units);
|
||||
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_image_units);
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
|
||||
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, max_viewport_size);
|
||||
glGetInteger64v(GL_MAX_UNIFORM_BLOCK_SIZE, &max_uniform_buffer_size);
|
||||
GLint max_vertex_output;
|
||||
glGetIntegerv(GL_MAX_VERTEX_OUTPUT_COMPONENTS, &max_vertex_output);
|
||||
GLint max_fragment_input;
|
||||
glGetIntegerv(GL_MAX_FRAGMENT_INPUT_COMPONENTS, &max_fragment_input);
|
||||
max_shader_varyings = (uint32_t)MIN(max_vertex_output, max_fragment_input) / 4;
|
||||
|
||||
// sanity clamp buffer size to 16K..1MB
|
||||
max_uniform_buffer_size = CLAMP(max_uniform_buffer_size, 16384, 1048576);
|
||||
|
||||
support_anisotropic_filter = extensions.has("GL_EXT_texture_filter_anisotropic");
|
||||
if (support_anisotropic_filter) {
|
||||
glGetFloatv(_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropic_level);
|
||||
anisotropic_level = MIN(float(1 << int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level"))), anisotropic_level);
|
||||
}
|
||||
|
||||
glGetIntegerv(GL_MAX_SAMPLES, &msaa_max_samples);
|
||||
#ifdef WEB_ENABLED
|
||||
msaa_supported = (msaa_max_samples > 0);
|
||||
#else
|
||||
msaa_supported = true;
|
||||
#endif
|
||||
#ifndef IOS_ENABLED
|
||||
#ifdef WEB_ENABLED
|
||||
msaa_multiview_supported = extensions.has("OCULUS_multiview");
|
||||
rt_msaa_multiview_supported = msaa_multiview_supported;
|
||||
#else
|
||||
msaa_multiview_supported = extensions.has("GL_EXT_multiview_texture_multisample");
|
||||
#endif
|
||||
|
||||
multiview_supported = extensions.has("OCULUS_multiview") || extensions.has("GL_OVR_multiview2") || extensions.has("GL_OVR_multiview");
|
||||
#endif
|
||||
|
||||
#ifdef ANDROID_ENABLED
|
||||
// These are GLES only
|
||||
rt_msaa_supported = extensions.has("GL_EXT_multisampled_render_to_texture");
|
||||
rt_msaa_multiview_supported = extensions.has("GL_OVR_multiview_multisampled_render_to_texture");
|
||||
external_texture_supported = extensions.has("GL_OES_EGL_image_external_essl3");
|
||||
|
||||
if (multiview_supported) {
|
||||
eglFramebufferTextureMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)eglGetProcAddress("glFramebufferTextureMultiviewOVR");
|
||||
if (eglFramebufferTextureMultiviewOVR == nullptr) {
|
||||
multiview_supported = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (msaa_multiview_supported) {
|
||||
eglTexStorage3DMultisample = (PFNGLTEXSTORAGE3DMULTISAMPLEPROC)eglGetProcAddress("glTexStorage3DMultisample");
|
||||
if (eglTexStorage3DMultisample == nullptr) {
|
||||
msaa_multiview_supported = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (rt_msaa_supported) {
|
||||
eglFramebufferTexture2DMultisampleEXT = (PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC)eglGetProcAddress("glFramebufferTexture2DMultisampleEXT");
|
||||
if (eglFramebufferTexture2DMultisampleEXT == nullptr) {
|
||||
rt_msaa_supported = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (rt_msaa_multiview_supported) {
|
||||
eglFramebufferTextureMultisampleMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC)eglGetProcAddress("glFramebufferTextureMultisampleMultiviewOVR");
|
||||
if (eglFramebufferTextureMultisampleMultiviewOVR == nullptr) {
|
||||
rt_msaa_multiview_supported = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (external_texture_supported) {
|
||||
eglEGLImageTargetTexture2DOES = (PFNEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress("glEGLImageTargetTexture2DOES");
|
||||
if (eglEGLImageTargetTexture2DOES == nullptr) {
|
||||
external_texture_supported = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
force_vertex_shading = GLOBAL_GET("rendering/shading/overrides/force_vertex_shading");
|
||||
specular_occlusion = GLOBAL_GET("rendering/reflections/specular_occlusion/enabled");
|
||||
use_nearest_mip_filter = GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter");
|
||||
|
||||
use_depth_prepass = bool(GLOBAL_GET("rendering/driver/depth_prepass/enable"));
|
||||
if (use_depth_prepass) {
|
||||
String vendors = GLOBAL_GET("rendering/driver/depth_prepass/disable_for_vendors");
|
||||
Vector<String> vendor_match = vendors.split(",");
|
||||
const String &renderer = String::utf8((const char *)glGetString(GL_RENDERER));
|
||||
for (int i = 0; i < vendor_match.size(); i++) {
|
||||
String v = vendor_match[i].strip_edges();
|
||||
if (v == String()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (renderer.containsn(v)) {
|
||||
use_depth_prepass = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
max_renderable_elements = GLOBAL_GET("rendering/limits/opengl/max_renderable_elements");
|
||||
max_renderable_lights = GLOBAL_GET("rendering/limits/opengl/max_renderable_lights");
|
||||
max_lights_per_object = GLOBAL_GET("rendering/limits/opengl/max_lights_per_object");
|
||||
|
||||
//Adreno 3xx Compatibility
|
||||
const String rendering_device_name = String::utf8((const char *)glGetString(GL_RENDERER));
|
||||
if (rendering_device_name.left(13) == "Adreno (TM) 3") {
|
||||
disable_particles_workaround = true;
|
||||
|
||||
// ignore driver version 331+
|
||||
const String gl_version = String::utf8((const char *)glGetString(GL_VERSION));
|
||||
// Adreno 3xx examples (https://opengles.gpuinfo.org/listreports.php):
|
||||
// ===========================================================================
|
||||
// OpenGL ES 3.0 V@84.0 AU@ (CL@)
|
||||
// OpenGL ES 3.0 V@127.0 AU@ (GIT@I96aee987eb)
|
||||
// OpenGL ES 3.0 V@140.0 AU@ (GIT@Ifd751822f5)
|
||||
// OpenGL ES 3.0 V@251.0 AU@08.00.00.312.030 (GIT@Ie4790512f3)
|
||||
// OpenGL ES 3.0 V@269.0 AU@ (GIT@I109c45a694)
|
||||
// OpenGL ES 3.0 V@331.0 (GIT@35e467f, Ice9844a736) (Date:04/15/19)
|
||||
// OpenGL ES 3.0 V@415.0 (GIT@d39f783, I79de86aa2c, 1591296226) (Date:06/04/20)
|
||||
// OpenGL ES 3.0 V@0502.0 (GIT@09fef447e8, I1fe547a144, 1661493934) (Date:08/25/22)
|
||||
String driver_version = gl_version.get_slice("V@", 1).get_slicec(' ', 0);
|
||||
if (driver_version.is_valid_float() && driver_version.to_float() >= 331.0) {
|
||||
//TODO: also 'GPUParticles'?
|
||||
//https://github.com/godotengine/godot/issues/92662#issuecomment-2161199477
|
||||
//disable_particles_workaround = false;
|
||||
}
|
||||
} else if (rendering_device_name == "PowerVR Rogue GE8320") {
|
||||
disable_transform_feedback_shader_cache = true;
|
||||
}
|
||||
|
||||
if (OS::get_singleton()->get_current_rendering_driver_name() == "opengl3_angle") {
|
||||
polyfill_half2float = false;
|
||||
}
|
||||
#ifdef WEB_ENABLED
|
||||
polyfill_half2float = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
Config::~Config() {
|
||||
singleton = nullptr;
|
||||
}
|
||||
|
||||
#endif // GLES3_ENABLED
|
124
drivers/gles3/storage/config.h
Normal file
124
drivers/gles3/storage/config.h
Normal file
@@ -0,0 +1,124 @@
|
||||
/**************************************************************************/
|
||||
/* config.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef GLES3_ENABLED
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/string/ustring.h"
|
||||
#include "core/templates/hash_set.h"
|
||||
|
||||
#include "platform_gl.h"
|
||||
|
||||
#ifdef ANDROID_ENABLED
|
||||
typedef void (*PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)(GLenum, GLenum, GLuint, GLint, GLint, GLsizei);
|
||||
typedef void (*PFNGLTEXSTORAGE3DMULTISAMPLEPROC)(GLenum, GLsizei, GLenum, GLsizei, GLsizei, GLsizei, GLboolean);
|
||||
typedef void (*PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC)(GLenum, GLenum, GLenum, GLuint, GLint, GLsizei);
|
||||
typedef void (*PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC)(GLenum, GLenum, GLuint, GLint, GLsizei, GLint, GLsizei);
|
||||
typedef void (*PFNEGLIMAGETARGETTEXTURE2DOESPROC)(GLenum, void *);
|
||||
#endif
|
||||
|
||||
namespace GLES3 {
|
||||
|
||||
class Config {
|
||||
private:
|
||||
static Config *singleton;
|
||||
|
||||
public:
|
||||
bool use_nearest_mip_filter = false;
|
||||
bool use_depth_prepass = true;
|
||||
|
||||
GLint max_vertex_texture_image_units = 0;
|
||||
GLint max_texture_image_units = 0;
|
||||
GLint max_texture_size = 0;
|
||||
GLint max_viewport_size[2] = { 0, 0 };
|
||||
GLint64 max_uniform_buffer_size = 0;
|
||||
uint32_t max_shader_varyings = 0;
|
||||
|
||||
int64_t max_renderable_elements = 0;
|
||||
int64_t max_renderable_lights = 0;
|
||||
int64_t max_lights_per_object = 0;
|
||||
|
||||
bool generate_wireframes = false;
|
||||
|
||||
HashSet<String> extensions;
|
||||
|
||||
bool float_texture_supported = false;
|
||||
bool float_texture_linear_supported = false;
|
||||
bool s3tc_supported = false;
|
||||
bool rgtc_supported = false;
|
||||
bool bptc_supported = false;
|
||||
bool etc2_supported = false;
|
||||
bool astc_supported = false;
|
||||
bool astc_hdr_supported = false;
|
||||
bool astc_layered_supported = false;
|
||||
bool srgb_framebuffer_supported = false;
|
||||
|
||||
bool force_vertex_shading = false;
|
||||
bool specular_occlusion = false;
|
||||
|
||||
bool support_anisotropic_filter = false;
|
||||
float anisotropic_level = 0.0f;
|
||||
|
||||
GLint msaa_max_samples = 0;
|
||||
bool msaa_supported = false;
|
||||
bool msaa_multiview_supported = false;
|
||||
bool rt_msaa_supported = false;
|
||||
bool rt_msaa_multiview_supported = false;
|
||||
bool multiview_supported = false;
|
||||
bool external_texture_supported = false;
|
||||
|
||||
// Adreno 3XX compatibility.
|
||||
bool disable_particles_workaround = false; // Set to 'true' to disable 'GPUParticles'.
|
||||
|
||||
// PowerVR GE 8320 workaround.
|
||||
bool disable_transform_feedback_shader_cache = false;
|
||||
|
||||
// ANGLE shader workaround.
|
||||
bool polyfill_half2float = true;
|
||||
|
||||
#ifdef ANDROID_ENABLED
|
||||
PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC eglFramebufferTextureMultiviewOVR = nullptr;
|
||||
PFNGLTEXSTORAGE3DMULTISAMPLEPROC eglTexStorage3DMultisample = nullptr;
|
||||
PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC eglFramebufferTexture2DMultisampleEXT = nullptr;
|
||||
PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC eglFramebufferTextureMultisampleMultiviewOVR = nullptr;
|
||||
PFNEGLIMAGETARGETTEXTURE2DOESPROC eglEGLImageTargetTexture2DOES = nullptr;
|
||||
#endif
|
||||
|
||||
static Config *get_singleton() { return singleton; }
|
||||
|
||||
Config();
|
||||
~Config();
|
||||
};
|
||||
|
||||
} // namespace GLES3
|
||||
|
||||
#endif // GLES3_ENABLED
|
1736
drivers/gles3/storage/light_storage.cpp
Normal file
1736
drivers/gles3/storage/light_storage.cpp
Normal file
File diff suppressed because it is too large
Load Diff
910
drivers/gles3/storage/light_storage.h
Normal file
910
drivers/gles3/storage/light_storage.h
Normal file
@@ -0,0 +1,910 @@
|
||||
/**************************************************************************/
|
||||
/* light_storage.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef GLES3_ENABLED
|
||||
|
||||
#include "platform_gl.h"
|
||||
#include "render_scene_buffers_gles3.h"
|
||||
|
||||
#include "core/templates/local_vector.h"
|
||||
#include "core/templates/rid_owner.h"
|
||||
#include "drivers/gles3/storage/texture_storage.h"
|
||||
#include "servers/rendering/storage/light_storage.h"
|
||||
#include "servers/rendering/storage/utilities.h"
|
||||
|
||||
namespace GLES3 {
|
||||
|
||||
/* LIGHT */
|
||||
|
||||
struct Light {
|
||||
RS::LightType type;
|
||||
float param[RS::LIGHT_PARAM_MAX];
|
||||
Color color = Color(1, 1, 1, 1);
|
||||
RID projector;
|
||||
bool shadow = false;
|
||||
bool negative = false;
|
||||
bool reverse_cull = false;
|
||||
RS::LightBakeMode bake_mode = RS::LIGHT_BAKE_DYNAMIC;
|
||||
uint32_t max_sdfgi_cascade = 2;
|
||||
uint32_t cull_mask = 0xFFFFFFFF;
|
||||
uint32_t shadow_caster_mask = 0xFFFFFFFF;
|
||||
bool distance_fade = false;
|
||||
real_t distance_fade_begin = 40.0;
|
||||
real_t distance_fade_shadow = 50.0;
|
||||
real_t distance_fade_length = 10.0;
|
||||
RS::LightOmniShadowMode omni_shadow_mode = RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID;
|
||||
RS::LightDirectionalShadowMode directional_shadow_mode = RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL;
|
||||
bool directional_blend_splits = false;
|
||||
RS::LightDirectionalSkyMode directional_sky_mode = RS::LIGHT_DIRECTIONAL_SKY_MODE_LIGHT_AND_SKY;
|
||||
uint64_t version = 0;
|
||||
|
||||
Dependency dependency;
|
||||
};
|
||||
|
||||
/* Light instance */
|
||||
struct LightInstance {
|
||||
struct ShadowTransform {
|
||||
Projection camera;
|
||||
Transform3D transform;
|
||||
float farplane;
|
||||
float split;
|
||||
float bias_scale;
|
||||
float shadow_texel_size;
|
||||
float range_begin;
|
||||
Rect2 atlas_rect;
|
||||
Vector2 uv_scale;
|
||||
};
|
||||
|
||||
ShadowTransform shadow_transform[6];
|
||||
RS::LightType light_type = RS::LIGHT_DIRECTIONAL;
|
||||
|
||||
AABB aabb;
|
||||
RID self;
|
||||
RID light;
|
||||
Transform3D transform;
|
||||
|
||||
uint64_t shadow_pass = 0;
|
||||
uint64_t last_scene_pass = 0;
|
||||
uint64_t last_scene_shadow_pass = 0;
|
||||
uint64_t last_pass = 0;
|
||||
uint32_t cull_mask = 0;
|
||||
uint32_t light_directional_index = 0;
|
||||
|
||||
Rect2 directional_rect;
|
||||
|
||||
HashSet<RID> shadow_atlases; // Shadow atlases where this light is registered.
|
||||
|
||||
int32_t gl_id = -1;
|
||||
int32_t shadow_id = -1;
|
||||
|
||||
LightInstance() {}
|
||||
};
|
||||
|
||||
/* REFLECTION PROBE */
|
||||
|
||||
struct ReflectionProbe {
|
||||
RS::ReflectionProbeUpdateMode update_mode = RS::REFLECTION_PROBE_UPDATE_ONCE;
|
||||
int resolution = 256;
|
||||
float intensity = 1.0;
|
||||
float blend_distance = 1.0;
|
||||
RS::ReflectionProbeAmbientMode ambient_mode = RS::REFLECTION_PROBE_AMBIENT_ENVIRONMENT;
|
||||
Color ambient_color;
|
||||
float ambient_color_energy = 1.0;
|
||||
float max_distance = 0;
|
||||
Vector3 size = Vector3(20, 20, 20);
|
||||
Vector3 origin_offset;
|
||||
bool interior = false;
|
||||
bool box_projection = false;
|
||||
bool enable_shadows = false;
|
||||
uint32_t cull_mask = (1 << 20) - 1;
|
||||
uint32_t reflection_mask = (1 << 20) - 1;
|
||||
float mesh_lod_threshold = 0.01;
|
||||
float baked_exposure = 1.0;
|
||||
|
||||
Dependency dependency;
|
||||
};
|
||||
|
||||
/* REFLECTION ATLAS */
|
||||
|
||||
struct ReflectionAtlas {
|
||||
int count = 0;
|
||||
int size = 0;
|
||||
|
||||
int mipmap_count = 1; // number of mips, including original
|
||||
int mipmap_size[8];
|
||||
GLuint depth = 0;
|
||||
|
||||
struct Reflection {
|
||||
RID owner;
|
||||
GLuint color = 0;
|
||||
GLuint radiance = 0;
|
||||
GLuint fbos[7];
|
||||
};
|
||||
Vector<Reflection> reflections;
|
||||
|
||||
Ref<RenderSceneBuffersGLES3> render_buffers; // Further render buffers used.
|
||||
};
|
||||
|
||||
/* REFLECTION PROBE INSTANCE */
|
||||
|
||||
struct ReflectionProbeInstance {
|
||||
RID probe;
|
||||
int atlas_index = -1;
|
||||
RID atlas;
|
||||
|
||||
bool dirty = true;
|
||||
bool rendering = false;
|
||||
int processing_layer = 0;
|
||||
|
||||
uint64_t last_pass = 0;
|
||||
uint32_t cull_mask = 0;
|
||||
|
||||
Transform3D transform;
|
||||
};
|
||||
|
||||
/* LIGHTMAP */
|
||||
|
||||
struct Lightmap {
|
||||
RID light_texture;
|
||||
RID shadow_texture;
|
||||
bool uses_spherical_harmonics = false;
|
||||
bool interior = false;
|
||||
AABB bounds = AABB(Vector3(), Vector3(1, 1, 1));
|
||||
float baked_exposure = 1.0;
|
||||
Vector2i light_texture_size;
|
||||
int32_t array_index = -1; //unassigned
|
||||
RS::ShadowmaskMode shadowmask_mode = RS::SHADOWMASK_MODE_NONE;
|
||||
PackedVector3Array points;
|
||||
PackedColorArray point_sh;
|
||||
PackedInt32Array tetrahedra;
|
||||
PackedInt32Array bsp_tree;
|
||||
|
||||
struct BSP {
|
||||
static const int32_t EMPTY_LEAF = INT32_MIN;
|
||||
float plane[4];
|
||||
int32_t over = EMPTY_LEAF, under = EMPTY_LEAF;
|
||||
};
|
||||
|
||||
Dependency dependency;
|
||||
};
|
||||
|
||||
struct LightmapInstance {
|
||||
RID lightmap;
|
||||
Transform3D transform;
|
||||
};
|
||||
|
||||
class LightStorage : public RendererLightStorage {
|
||||
public:
|
||||
enum ShadowAtlastQuadrant : uint32_t {
|
||||
QUADRANT_SHIFT = 27,
|
||||
OMNI_LIGHT_FLAG = 1 << 26,
|
||||
SHADOW_INDEX_MASK = OMNI_LIGHT_FLAG - 1,
|
||||
SHADOW_INVALID = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
private:
|
||||
static LightStorage *singleton;
|
||||
|
||||
/* LIGHT */
|
||||
mutable RID_Owner<Light, true> light_owner;
|
||||
|
||||
/* Light instance */
|
||||
mutable RID_Owner<LightInstance> light_instance_owner;
|
||||
|
||||
/* REFLECTION PROBE */
|
||||
mutable RID_Owner<ReflectionProbe, true> reflection_probe_owner;
|
||||
|
||||
/* REFLECTION ATLAS */
|
||||
mutable RID_Owner<ReflectionAtlas> reflection_atlas_owner;
|
||||
|
||||
/* REFLECTION PROBE INSTANCE */
|
||||
|
||||
mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner;
|
||||
|
||||
/* LIGHTMAP */
|
||||
float lightmap_probe_capture_update_speed = 4;
|
||||
|
||||
mutable RID_Owner<Lightmap, true> lightmap_owner;
|
||||
|
||||
/* LIGHTMAP INSTANCE */
|
||||
|
||||
mutable RID_Owner<LightmapInstance> lightmap_instance_owner;
|
||||
|
||||
/* SHADOW ATLAS */
|
||||
|
||||
// Note: The ShadowAtlas in the OpenGL is virtual. Each light gets assigned its
|
||||
// own texture which is the same size as it would be if it were in a real atlas.
|
||||
// This allows us to maintain the same behavior as the other renderers.
|
||||
|
||||
struct ShadowAtlas {
|
||||
struct Quadrant {
|
||||
uint32_t subdivision = 0;
|
||||
|
||||
struct Shadow {
|
||||
RID owner;
|
||||
bool owner_is_omni = false;
|
||||
uint64_t version = 0;
|
||||
uint64_t alloc_tick = 0;
|
||||
|
||||
Shadow() {}
|
||||
};
|
||||
|
||||
Vector<Shadow> shadows;
|
||||
LocalVector<GLuint> textures;
|
||||
LocalVector<GLuint> fbos;
|
||||
|
||||
Quadrant() {}
|
||||
} quadrants[4];
|
||||
|
||||
// Ordered from smallest (worst) shadow size to largest (best).
|
||||
int size_order[4] = { 0, 1, 2, 3 };
|
||||
uint32_t smallest_subdiv = 0;
|
||||
|
||||
int size = 0;
|
||||
bool use_16_bits = true;
|
||||
|
||||
GLuint debug_texture = 0;
|
||||
GLuint debug_fbo = 0;
|
||||
|
||||
HashMap<RID, uint32_t> shadow_owners;
|
||||
};
|
||||
|
||||
uint64_t shadow_atlas_realloc_tolerance_msec = 500;
|
||||
RID_Owner<ShadowAtlas> shadow_atlas_owner;
|
||||
|
||||
void _shadow_atlas_invalidate_shadow(ShadowAtlas::Quadrant::Shadow *p_shadow, RID p_atlas, ShadowAtlas *p_shadow_atlas, uint32_t p_quadrant, uint32_t p_shadow_idx);
|
||||
bool _shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, bool p_omni, int &r_quadrant, int &r_shadow);
|
||||
|
||||
/* DIRECTIONAL SHADOW */
|
||||
|
||||
struct DirectionalShadow {
|
||||
GLuint depth = 0;
|
||||
GLuint fbo = 0;
|
||||
|
||||
int light_count = 0;
|
||||
int size = 0;
|
||||
bool use_16_bits = true;
|
||||
int current_light = 0;
|
||||
} directional_shadow;
|
||||
|
||||
public:
|
||||
static LightStorage *get_singleton();
|
||||
|
||||
LightStorage();
|
||||
virtual ~LightStorage();
|
||||
|
||||
/* Light API */
|
||||
|
||||
Light *get_light(RID p_rid) { return light_owner.get_or_null(p_rid); }
|
||||
bool owns_light(RID p_rid) { return light_owner.owns(p_rid); }
|
||||
|
||||
void _light_initialize(RID p_rid, RS::LightType p_type);
|
||||
|
||||
virtual RID directional_light_allocate() override;
|
||||
virtual void directional_light_initialize(RID p_rid) override;
|
||||
virtual RID omni_light_allocate() override;
|
||||
virtual void omni_light_initialize(RID p_rid) override;
|
||||
virtual RID spot_light_allocate() override;
|
||||
virtual void spot_light_initialize(RID p_rid) override;
|
||||
|
||||
virtual void light_free(RID p_rid) override;
|
||||
|
||||
virtual void light_set_color(RID p_light, const Color &p_color) override;
|
||||
virtual void light_set_param(RID p_light, RS::LightParam p_param, float p_value) override;
|
||||
virtual void light_set_shadow(RID p_light, bool p_enabled) override;
|
||||
virtual void light_set_projector(RID p_light, RID p_texture) override;
|
||||
virtual void light_set_negative(RID p_light, bool p_enable) override;
|
||||
virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) override;
|
||||
virtual void light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) override;
|
||||
virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) override;
|
||||
virtual void light_set_shadow_caster_mask(RID p_light, uint32_t p_caster_mask) override;
|
||||
virtual uint32_t light_get_shadow_caster_mask(RID p_light) const override;
|
||||
virtual void light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) override;
|
||||
virtual void light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) override {}
|
||||
|
||||
virtual void light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) override;
|
||||
|
||||
virtual void light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) override;
|
||||
virtual void light_directional_set_blend_splits(RID p_light, bool p_enable) override;
|
||||
virtual bool light_directional_get_blend_splits(RID p_light) const override;
|
||||
virtual void light_directional_set_sky_mode(RID p_light, RS::LightDirectionalSkyMode p_mode) override;
|
||||
virtual RS::LightDirectionalSkyMode light_directional_get_sky_mode(RID p_light) const override;
|
||||
|
||||
virtual RS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light) override;
|
||||
virtual RS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) override;
|
||||
virtual RS::LightType light_get_type(RID p_light) const override {
|
||||
const Light *light = light_owner.get_or_null(p_light);
|
||||
ERR_FAIL_NULL_V(light, RS::LIGHT_DIRECTIONAL);
|
||||
|
||||
return light->type;
|
||||
}
|
||||
virtual AABB light_get_aabb(RID p_light) const override;
|
||||
|
||||
virtual float light_get_param(RID p_light, RS::LightParam p_param) override {
|
||||
const Light *light = light_owner.get_or_null(p_light);
|
||||
ERR_FAIL_NULL_V(light, 0);
|
||||
|
||||
return light->param[p_param];
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ RID light_get_projector(RID p_light) {
|
||||
const Light *light = light_owner.get_or_null(p_light);
|
||||
ERR_FAIL_NULL_V(light, RID());
|
||||
|
||||
return light->projector;
|
||||
}
|
||||
|
||||
virtual Color light_get_color(RID p_light) override {
|
||||
const Light *light = light_owner.get_or_null(p_light);
|
||||
ERR_FAIL_NULL_V(light, Color());
|
||||
|
||||
return light->color;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool light_is_distance_fade_enabled(RID p_light) {
|
||||
const Light *light = light_owner.get_or_null(p_light);
|
||||
return light->distance_fade;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ float light_get_distance_fade_begin(RID p_light) {
|
||||
const Light *light = light_owner.get_or_null(p_light);
|
||||
return light->distance_fade_begin;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ float light_get_distance_fade_shadow(RID p_light) {
|
||||
const Light *light = light_owner.get_or_null(p_light);
|
||||
return light->distance_fade_shadow;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ float light_get_distance_fade_length(RID p_light) {
|
||||
const Light *light = light_owner.get_or_null(p_light);
|
||||
return light->distance_fade_length;
|
||||
}
|
||||
|
||||
virtual bool light_has_shadow(RID p_light) const override {
|
||||
const Light *light = light_owner.get_or_null(p_light);
|
||||
ERR_FAIL_NULL_V(light, RS::LIGHT_DIRECTIONAL);
|
||||
|
||||
return light->shadow;
|
||||
}
|
||||
|
||||
virtual bool light_has_projector(RID p_light) const override {
|
||||
const Light *light = light_owner.get_or_null(p_light);
|
||||
ERR_FAIL_NULL_V(light, RS::LIGHT_DIRECTIONAL);
|
||||
|
||||
return TextureStorage::get_singleton()->owns_texture(light->projector);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool light_is_negative(RID p_light) const {
|
||||
const Light *light = light_owner.get_or_null(p_light);
|
||||
ERR_FAIL_NULL_V(light, RS::LIGHT_DIRECTIONAL);
|
||||
|
||||
return light->negative;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ float light_get_transmittance_bias(RID p_light) const {
|
||||
const Light *light = light_owner.get_or_null(p_light);
|
||||
ERR_FAIL_NULL_V(light, 0.0);
|
||||
|
||||
return light->param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS];
|
||||
}
|
||||
|
||||
virtual bool light_get_reverse_cull_face_mode(RID p_light) const override {
|
||||
const Light *light = light_owner.get_or_null(p_light);
|
||||
ERR_FAIL_NULL_V(light, false);
|
||||
|
||||
return light->reverse_cull;
|
||||
}
|
||||
|
||||
virtual RS::LightBakeMode light_get_bake_mode(RID p_light) override;
|
||||
virtual uint32_t light_get_max_sdfgi_cascade(RID p_light) override { return 0; }
|
||||
virtual uint64_t light_get_version(RID p_light) const override;
|
||||
virtual uint32_t light_get_cull_mask(RID p_light) const override;
|
||||
|
||||
/* LIGHT INSTANCE API */
|
||||
|
||||
LightInstance *get_light_instance(RID p_rid) { return light_instance_owner.get_or_null(p_rid); }
|
||||
bool owns_light_instance(RID p_rid) { return light_instance_owner.owns(p_rid); }
|
||||
|
||||
virtual RID light_instance_create(RID p_light) override;
|
||||
virtual void light_instance_free(RID p_light_instance) override;
|
||||
|
||||
virtual void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override;
|
||||
virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override;
|
||||
virtual void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override;
|
||||
virtual void light_instance_mark_visible(RID p_light_instance) override;
|
||||
|
||||
virtual bool light_instance_is_shadow_visible_at_position(RID p_light_instance, const Vector3 &p_position) const override {
|
||||
const LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
|
||||
ERR_FAIL_NULL_V(light_instance, false);
|
||||
const Light *light = light_owner.get_or_null(light_instance->light);
|
||||
ERR_FAIL_NULL_V(light, false);
|
||||
|
||||
if (!light->shadow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!light->distance_fade) {
|
||||
return true;
|
||||
}
|
||||
|
||||
real_t distance = p_position.distance_to(light_instance->transform.origin);
|
||||
|
||||
if (distance > light->distance_fade_shadow + light->distance_fade_length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ RID light_instance_get_base_light(RID p_light_instance) {
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
return li->light;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Transform3D light_instance_get_base_transform(RID p_light_instance) {
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
return li->transform;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ AABB light_instance_get_base_aabb(RID p_light_instance) {
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
return li->aabb;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void light_instance_set_cull_mask(RID p_light_instance, uint32_t p_cull_mask) {
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
li->cull_mask = p_cull_mask;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t light_instance_get_cull_mask(RID p_light_instance) {
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
return li->cull_mask;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ GLuint light_instance_get_shadow_texture(RID p_light_instance, RID p_shadow_atlas) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
ERR_FAIL_COND_V(!li->shadow_atlases.has(p_shadow_atlas), 0);
|
||||
#endif
|
||||
ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas);
|
||||
ERR_FAIL_NULL_V(shadow_atlas, 0);
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_COND_V(!shadow_atlas->shadow_owners.has(p_light_instance), 0);
|
||||
#endif
|
||||
uint32_t key = shadow_atlas->shadow_owners[p_light_instance];
|
||||
|
||||
uint32_t quadrant = (key >> QUADRANT_SHIFT) & 0x3;
|
||||
uint32_t shadow = key & SHADOW_INDEX_MASK;
|
||||
|
||||
ERR_FAIL_COND_V(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size(), 0);
|
||||
|
||||
return shadow_atlas_get_quadrant_shadow_texture(p_shadow_atlas, quadrant, shadow);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool light_instance_has_shadow_atlas(RID p_light_instance, RID p_shadow_atlas) {
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
return li->shadow_atlases.has(p_shadow_atlas);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ float light_instance_get_shadow_texel_size(RID p_light_instance, RID p_shadow_atlas) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
ERR_FAIL_COND_V(!li->shadow_atlases.has(p_shadow_atlas), 0);
|
||||
#endif
|
||||
ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas);
|
||||
ERR_FAIL_NULL_V(shadow_atlas, 0);
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_COND_V(!shadow_atlas->shadow_owners.has(p_light_instance), 0);
|
||||
#endif
|
||||
uint32_t key = shadow_atlas->shadow_owners[p_light_instance];
|
||||
|
||||
uint32_t quadrant = (key >> QUADRANT_SHIFT) & 0x3;
|
||||
|
||||
uint32_t quadrant_size = shadow_atlas->size >> 1;
|
||||
|
||||
uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision);
|
||||
|
||||
return float(1.0) / shadow_size;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Projection light_instance_get_shadow_camera(RID p_light_instance, int p_index) {
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
return li->shadow_transform[p_index].camera;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Transform3D light_instance_get_shadow_transform(RID p_light_instance, int p_index) {
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
return li->shadow_transform[p_index].transform;
|
||||
}
|
||||
_FORCE_INLINE_ float light_instance_get_shadow_bias_scale(RID p_light_instance, int p_index) {
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
return li->shadow_transform[p_index].bias_scale;
|
||||
}
|
||||
_FORCE_INLINE_ float light_instance_get_shadow_range(RID p_light_instance, int p_index) {
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
return li->shadow_transform[p_index].farplane;
|
||||
}
|
||||
_FORCE_INLINE_ float light_instance_get_shadow_range_begin(RID p_light_instance, int p_index) {
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
return li->shadow_transform[p_index].range_begin;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Vector2 light_instance_get_shadow_uv_scale(RID p_light_instance, int p_index) {
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
return li->shadow_transform[p_index].uv_scale;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void light_instance_set_directional_shadow_atlas_rect(RID p_light_instance, int p_index, const Rect2 p_atlas_rect) {
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
li->shadow_transform[p_index].atlas_rect = p_atlas_rect;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Rect2 light_instance_get_directional_shadow_atlas_rect(RID p_light_instance, int p_index) {
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
return li->shadow_transform[p_index].atlas_rect;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ float light_instance_get_directional_shadow_split(RID p_light_instance, int p_index) {
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
return li->shadow_transform[p_index].split;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ float light_instance_get_directional_shadow_texel_size(RID p_light_instance, int p_index) {
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
return li->shadow_transform[p_index].shadow_texel_size;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void light_instance_set_render_pass(RID p_light_instance, uint64_t p_pass) {
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
li->last_pass = p_pass;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint64_t light_instance_get_render_pass(RID p_light_instance) {
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
return li->last_pass;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void light_instance_set_shadow_pass(RID p_light_instance, uint64_t p_pass) {
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
li->last_scene_shadow_pass = p_pass;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint64_t light_instance_get_shadow_pass(RID p_light_instance) {
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
return li->last_scene_shadow_pass;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void light_instance_set_directional_rect(RID p_light_instance, const Rect2 &p_directional_rect) {
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
li->directional_rect = p_directional_rect;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Rect2 light_instance_get_directional_rect(RID p_light_instance) {
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
return li->directional_rect;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ RS::LightType light_instance_get_type(RID p_light_instance) {
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
return li->light_type;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int32_t light_instance_get_gl_id(RID p_light_instance) {
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
return li->gl_id;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int32_t light_instance_get_shadow_id(RID p_light_instance) {
|
||||
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
|
||||
return li->shadow_id;
|
||||
}
|
||||
|
||||
/* PROBE API */
|
||||
|
||||
ReflectionProbe *get_reflection_probe(RID p_rid) { return reflection_probe_owner.get_or_null(p_rid); }
|
||||
bool owns_reflection_probe(RID p_rid) { return reflection_probe_owner.owns(p_rid); }
|
||||
|
||||
virtual RID reflection_probe_allocate() override;
|
||||
virtual void reflection_probe_initialize(RID p_rid) override;
|
||||
virtual void reflection_probe_free(RID p_rid) override;
|
||||
|
||||
virtual void reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) override;
|
||||
virtual void reflection_probe_set_intensity(RID p_probe, float p_intensity) override;
|
||||
virtual void reflection_probe_set_blend_distance(RID p_probe, float p_blend_distance) override;
|
||||
virtual void reflection_probe_set_ambient_mode(RID p_probe, RS::ReflectionProbeAmbientMode p_mode) override;
|
||||
virtual void reflection_probe_set_ambient_color(RID p_probe, const Color &p_color) override;
|
||||
virtual void reflection_probe_set_ambient_energy(RID p_probe, float p_energy) override;
|
||||
virtual void reflection_probe_set_max_distance(RID p_probe, float p_distance) override;
|
||||
virtual void reflection_probe_set_size(RID p_probe, const Vector3 &p_size) override;
|
||||
virtual void reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) override;
|
||||
virtual void reflection_probe_set_as_interior(RID p_probe, bool p_enable) override;
|
||||
virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) override;
|
||||
virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) override;
|
||||
virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) override;
|
||||
virtual void reflection_probe_set_reflection_mask(RID p_probe, uint32_t p_layers) override;
|
||||
virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution) override;
|
||||
virtual void reflection_probe_set_mesh_lod_threshold(RID p_probe, float p_ratio) override;
|
||||
virtual float reflection_probe_get_mesh_lod_threshold(RID p_probe) const override;
|
||||
|
||||
virtual AABB reflection_probe_get_aabb(RID p_probe) const override;
|
||||
virtual RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const override;
|
||||
virtual uint32_t reflection_probe_get_cull_mask(RID p_probe) const override;
|
||||
virtual uint32_t reflection_probe_get_reflection_mask(RID p_probe) const override;
|
||||
virtual Vector3 reflection_probe_get_size(RID p_probe) const override;
|
||||
virtual Vector3 reflection_probe_get_origin_offset(RID p_probe) const override;
|
||||
virtual float reflection_probe_get_origin_max_distance(RID p_probe) const override;
|
||||
virtual bool reflection_probe_renders_shadows(RID p_probe) const override;
|
||||
|
||||
Dependency *reflection_probe_get_dependency(RID p_probe) const;
|
||||
|
||||
/* REFLECTION ATLAS */
|
||||
|
||||
bool owns_reflection_atlas(RID p_rid) { return reflection_atlas_owner.owns(p_rid); }
|
||||
|
||||
virtual RID reflection_atlas_create() override;
|
||||
virtual void reflection_atlas_free(RID p_ref_atlas) override;
|
||||
virtual int reflection_atlas_get_size(RID p_ref_atlas) const override;
|
||||
virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override;
|
||||
|
||||
/* REFLECTION PROBE INSTANCE */
|
||||
|
||||
bool owns_reflection_probe_instance(RID p_rid) { return reflection_probe_instance_owner.owns(p_rid); }
|
||||
|
||||
virtual RID reflection_probe_instance_create(RID p_probe) override;
|
||||
virtual void reflection_probe_instance_free(RID p_instance) override;
|
||||
virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override;
|
||||
virtual bool reflection_probe_has_atlas_index(RID p_instance) override;
|
||||
virtual void reflection_probe_release_atlas_index(RID p_instance) override;
|
||||
virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override;
|
||||
virtual bool reflection_probe_instance_has_reflection(RID p_instance) override;
|
||||
virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override;
|
||||
virtual Ref<RenderSceneBuffers> reflection_probe_atlas_get_render_buffers(RID p_reflection_atlas) override;
|
||||
virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override;
|
||||
|
||||
_FORCE_INLINE_ RID reflection_probe_instance_get_probe(RID p_instance) {
|
||||
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
|
||||
ERR_FAIL_NULL_V(rpi, RID());
|
||||
|
||||
return rpi->probe;
|
||||
}
|
||||
_FORCE_INLINE_ RID reflection_probe_instance_get_atlas(RID p_instance) {
|
||||
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
|
||||
ERR_FAIL_NULL_V(rpi, RID());
|
||||
|
||||
return rpi->atlas;
|
||||
}
|
||||
Transform3D reflection_probe_instance_get_transform(RID p_instance) {
|
||||
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
|
||||
ERR_FAIL_NULL_V(rpi, Transform3D());
|
||||
|
||||
return rpi->transform;
|
||||
}
|
||||
GLuint reflection_probe_instance_get_texture(RID p_instance);
|
||||
GLuint reflection_probe_instance_get_framebuffer(RID p_instance, int p_index);
|
||||
|
||||
/* LIGHTMAP CAPTURE */
|
||||
|
||||
Lightmap *get_lightmap(RID p_rid) { return lightmap_owner.get_or_null(p_rid); }
|
||||
bool owns_lightmap(RID p_rid) { return lightmap_owner.owns(p_rid); }
|
||||
|
||||
virtual RID lightmap_allocate() override;
|
||||
virtual void lightmap_initialize(RID p_rid) override;
|
||||
virtual void lightmap_free(RID p_rid) override;
|
||||
|
||||
virtual void lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) override;
|
||||
virtual void lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) override;
|
||||
virtual void lightmap_set_probe_interior(RID p_lightmap, bool p_interior) override;
|
||||
virtual void lightmap_set_probe_capture_data(RID p_lightmap, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) override;
|
||||
virtual void lightmap_set_baked_exposure_normalization(RID p_lightmap, float p_exposure) override;
|
||||
virtual PackedVector3Array lightmap_get_probe_capture_points(RID p_lightmap) const override;
|
||||
virtual PackedColorArray lightmap_get_probe_capture_sh(RID p_lightmap) const override;
|
||||
virtual PackedInt32Array lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const override;
|
||||
virtual PackedInt32Array lightmap_get_probe_capture_bsp_tree(RID p_lightmap) const override;
|
||||
virtual AABB lightmap_get_aabb(RID p_lightmap) const override;
|
||||
virtual void lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_point, Color *r_sh) override;
|
||||
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;
|
||||
|
||||
virtual void lightmap_set_shadowmask_textures(RID p_lightmap, RID p_shadow) override;
|
||||
virtual RS::ShadowmaskMode lightmap_get_shadowmask_mode(RID p_lightmap) override;
|
||||
virtual void lightmap_set_shadowmask_mode(RID p_lightmap, RS::ShadowmaskMode p_mode) override;
|
||||
|
||||
/* LIGHTMAP INSTANCE */
|
||||
|
||||
LightmapInstance *get_lightmap_instance(RID p_rid) { return lightmap_instance_owner.get_or_null(p_rid); }
|
||||
bool owns_lightmap_instance(RID p_rid) { return lightmap_instance_owner.owns(p_rid); }
|
||||
|
||||
virtual RID lightmap_instance_create(RID p_lightmap) override;
|
||||
virtual void lightmap_instance_free(RID p_lightmap) override;
|
||||
virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override;
|
||||
|
||||
/* SHADOW ATLAS API */
|
||||
bool owns_shadow_atlas(RID p_rid) { return shadow_atlas_owner.owns(p_rid); }
|
||||
|
||||
virtual RID shadow_atlas_create() override;
|
||||
virtual void shadow_atlas_free(RID p_atlas) override;
|
||||
virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) override;
|
||||
virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override;
|
||||
virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_instance, float p_coverage, uint64_t p_light_version) override;
|
||||
|
||||
_FORCE_INLINE_ bool shadow_atlas_owns_light_instance(RID p_atlas, RID p_light_instance) {
|
||||
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||
ERR_FAIL_NULL_V(atlas, false);
|
||||
return atlas->shadow_owners.has(p_light_instance);
|
||||
}
|
||||
_FORCE_INLINE_ uint32_t shadow_atlas_get_light_instance_key(RID p_atlas, RID p_light_instance) {
|
||||
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||
ERR_FAIL_NULL_V(atlas, -1);
|
||||
return atlas->shadow_owners[p_light_instance];
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int shadow_atlas_get_size(RID p_atlas) {
|
||||
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||
ERR_FAIL_NULL_V(atlas, 0);
|
||||
return atlas->size;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ GLuint shadow_atlas_get_debug_fb(RID p_atlas) {
|
||||
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||
ERR_FAIL_NULL_V(atlas, 0);
|
||||
|
||||
if (atlas->debug_fbo != 0) {
|
||||
return atlas->debug_fbo;
|
||||
}
|
||||
glGenFramebuffers(1, &atlas->debug_fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, atlas->debug_fbo);
|
||||
|
||||
if (atlas->debug_texture == 0) {
|
||||
atlas->debug_texture = shadow_atlas_get_debug_texture(p_atlas);
|
||||
}
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, atlas->debug_texture);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, atlas->debug_texture, 0);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
|
||||
|
||||
return atlas->debug_fbo;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ GLuint shadow_atlas_get_debug_texture(RID p_atlas) {
|
||||
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||
ERR_FAIL_NULL_V(atlas, 0);
|
||||
|
||||
if (atlas->debug_texture != 0) {
|
||||
return atlas->debug_texture;
|
||||
}
|
||||
|
||||
glGenTextures(1, &atlas->debug_texture);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, atlas->debug_texture);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, atlas->size, atlas->size, 0, GL_RED, GL_UNSIGNED_INT, nullptr);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_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);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
return atlas->debug_texture;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int shadow_atlas_get_quadrant_shadows_length(RID p_atlas, uint32_t p_quadrant) {
|
||||
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||
ERR_FAIL_NULL_V(atlas, 0);
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, 0);
|
||||
return atlas->quadrants[p_quadrant].shadows.size();
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t shadow_atlas_get_quadrant_shadows_allocated(RID p_atlas, uint32_t p_quadrant) {
|
||||
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||
ERR_FAIL_NULL_V(atlas, 0);
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, 0);
|
||||
return atlas->quadrants[p_quadrant].textures.size();
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t shadow_atlas_get_quadrant_subdivision(RID p_atlas, uint32_t p_quadrant) {
|
||||
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||
ERR_FAIL_NULL_V(atlas, 0);
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, 0);
|
||||
return atlas->quadrants[p_quadrant].subdivision;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ GLuint shadow_atlas_get_quadrant_shadow_texture(RID p_atlas, uint32_t p_quadrant, uint32_t p_shadow) {
|
||||
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||
ERR_FAIL_NULL_V(atlas, 0);
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, 0);
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_shadow, atlas->quadrants[p_quadrant].textures.size(), 0);
|
||||
return atlas->quadrants[p_quadrant].textures[p_shadow];
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ GLuint shadow_atlas_get_quadrant_shadow_fb(RID p_atlas, uint32_t p_quadrant, uint32_t p_shadow) {
|
||||
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||
ERR_FAIL_NULL_V(atlas, 0);
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, 0);
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_shadow, atlas->quadrants[p_quadrant].fbos.size(), 0);
|
||||
return atlas->quadrants[p_quadrant].fbos[p_shadow];
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int shadow_atlas_get_quadrant_shadow_size(RID p_atlas, uint32_t p_quadrant) {
|
||||
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||
ERR_FAIL_NULL_V(atlas, 0);
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, 0);
|
||||
return (atlas->size >> 1) / atlas->quadrants[p_quadrant].subdivision;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool shadow_atlas_get_quadrant_shadow_is_omni(RID p_atlas, uint32_t p_quadrant, uint32_t p_shadow) {
|
||||
ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
|
||||
ERR_FAIL_NULL_V(atlas, false);
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, false);
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_shadow, (uint32_t)atlas->quadrants[p_quadrant].shadows.size(), false);
|
||||
return atlas->quadrants[p_quadrant].shadows[p_shadow].owner_is_omni;
|
||||
}
|
||||
|
||||
virtual void shadow_atlas_update(RID p_atlas) override;
|
||||
|
||||
virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override;
|
||||
virtual int get_directional_light_shadow_size(RID p_light_instance) override;
|
||||
virtual void set_directional_shadow_count(int p_count) override;
|
||||
|
||||
Rect2i get_directional_shadow_rect();
|
||||
void update_directional_shadow_atlas();
|
||||
|
||||
_FORCE_INLINE_ GLuint directional_shadow_get_texture() {
|
||||
return directional_shadow.depth;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int directional_shadow_get_size() {
|
||||
return directional_shadow.size;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ GLuint direction_shadow_get_fb() {
|
||||
return directional_shadow.fbo;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void directional_shadow_increase_current_light() {
|
||||
directional_shadow.current_light++;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace GLES3
|
||||
|
||||
#endif // GLES3_ENABLED
|
3313
drivers/gles3/storage/material_storage.cpp
Normal file
3313
drivers/gles3/storage/material_storage.cpp
Normal file
File diff suppressed because it is too large
Load Diff
663
drivers/gles3/storage/material_storage.h
Normal file
663
drivers/gles3/storage/material_storage.h
Normal file
@@ -0,0 +1,663 @@
|
||||
/**************************************************************************/
|
||||
/* material_storage.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef GLES3_ENABLED
|
||||
|
||||
#include "core/templates/rid_owner.h"
|
||||
#include "core/templates/self_list.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 "drivers/gles3/shaders/canvas.glsl.gen.h"
|
||||
#include "drivers/gles3/shaders/particles.glsl.gen.h"
|
||||
#include "drivers/gles3/shaders/scene.glsl.gen.h"
|
||||
#include "drivers/gles3/shaders/sky.glsl.gen.h"
|
||||
|
||||
namespace GLES3 {
|
||||
|
||||
/* Shader Structs */
|
||||
|
||||
struct ShaderData {
|
||||
String path;
|
||||
HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
|
||||
HashMap<StringName, HashMap<int, RID>> default_texture_params;
|
||||
|
||||
virtual void set_path_hint(const String &p_hint);
|
||||
virtual void set_default_texture_parameter(const StringName &p_name, RID p_texture, int p_index);
|
||||
virtual Variant get_default_parameter(const StringName &p_parameter) const;
|
||||
virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
|
||||
virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
|
||||
virtual bool is_parameter_texture(const StringName &p_param) const;
|
||||
|
||||
virtual void set_code(const String &p_Code) = 0;
|
||||
virtual bool is_animated() const = 0;
|
||||
virtual bool casts_shadows() const = 0;
|
||||
virtual RS::ShaderNativeSourceCode get_native_source_code() const { return RS::ShaderNativeSourceCode(); }
|
||||
|
||||
virtual ~ShaderData() {}
|
||||
};
|
||||
|
||||
typedef ShaderData *(*ShaderDataRequestFunction)();
|
||||
|
||||
struct Material;
|
||||
|
||||
struct Shader {
|
||||
ShaderData *data = nullptr;
|
||||
String code;
|
||||
String path_hint;
|
||||
RS::ShaderMode mode;
|
||||
HashMap<StringName, HashMap<int, RID>> default_texture_parameter;
|
||||
HashSet<Material *> owners;
|
||||
};
|
||||
|
||||
/* Material structs */
|
||||
|
||||
struct MaterialData {
|
||||
void update_uniform_buffer(const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const HashMap<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size);
|
||||
void update_textures(const HashMap<StringName, Variant> &p_parameters, const HashMap<StringName, HashMap<int, RID>> &p_default_textures, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color);
|
||||
|
||||
virtual void set_render_priority(int p_priority) = 0;
|
||||
virtual void set_next_pass(RID p_pass) = 0;
|
||||
virtual void update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) = 0;
|
||||
virtual void bind_uniforms() = 0;
|
||||
virtual ~MaterialData();
|
||||
|
||||
// Used internally by all Materials
|
||||
void update_parameters_internal(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, const HashMap<StringName, HashMap<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, bool p_is_3d_shader_type);
|
||||
|
||||
protected:
|
||||
Vector<uint8_t> ubo_data;
|
||||
GLuint uniform_buffer = GLuint(0);
|
||||
Vector<RID> texture_cache;
|
||||
|
||||
private:
|
||||
friend class MaterialStorage;
|
||||
RID self;
|
||||
List<RID>::Element *global_buffer_E = nullptr;
|
||||
List<RID>::Element *global_texture_E = nullptr;
|
||||
uint64_t global_textures_pass = 0;
|
||||
HashMap<StringName, uint64_t> used_global_textures;
|
||||
};
|
||||
|
||||
typedef MaterialData *(*MaterialDataRequestFunction)(ShaderData *);
|
||||
|
||||
struct Material {
|
||||
RID self;
|
||||
MaterialData *data = nullptr;
|
||||
Shader *shader = nullptr;
|
||||
//shortcut to shader data and type
|
||||
RS::ShaderMode shader_mode = RS::SHADER_MAX;
|
||||
uint32_t shader_id = 0;
|
||||
bool uniform_dirty = false;
|
||||
bool texture_dirty = false;
|
||||
HashMap<StringName, Variant> params;
|
||||
int32_t priority = 0;
|
||||
RID next_pass;
|
||||
SelfList<Material> update_element;
|
||||
|
||||
Dependency dependency;
|
||||
|
||||
Material() :
|
||||
update_element(this) {}
|
||||
};
|
||||
|
||||
/* CanvasItem Materials */
|
||||
|
||||
struct CanvasShaderData : public ShaderData {
|
||||
enum BlendMode { // Used internally.
|
||||
BLEND_MODE_MIX,
|
||||
BLEND_MODE_ADD,
|
||||
BLEND_MODE_SUB,
|
||||
BLEND_MODE_MUL,
|
||||
BLEND_MODE_PMALPHA,
|
||||
BLEND_MODE_DISABLED,
|
||||
BLEND_MODE_LCD,
|
||||
};
|
||||
|
||||
// All these members are (re)initialized in `set_code`.
|
||||
// Make sure to add the init to `set_code` whenever adding new members.
|
||||
|
||||
bool valid;
|
||||
RID version;
|
||||
|
||||
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
|
||||
|
||||
Vector<uint32_t> ubo_offsets;
|
||||
uint32_t ubo_size;
|
||||
|
||||
String code;
|
||||
|
||||
BlendMode blend_mode;
|
||||
|
||||
bool uses_screen_texture;
|
||||
bool uses_screen_texture_mipmaps;
|
||||
bool uses_sdf;
|
||||
bool uses_time;
|
||||
bool uses_custom0;
|
||||
bool uses_custom1;
|
||||
|
||||
uint64_t vertex_input_mask;
|
||||
|
||||
virtual void set_code(const String &p_Code);
|
||||
virtual bool is_animated() const;
|
||||
virtual bool casts_shadows() const;
|
||||
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
|
||||
|
||||
CanvasShaderData();
|
||||
virtual ~CanvasShaderData();
|
||||
};
|
||||
|
||||
ShaderData *_create_canvas_shader_func();
|
||||
|
||||
struct CanvasMaterialData : public MaterialData {
|
||||
CanvasShaderData *shader_data = nullptr;
|
||||
|
||||
virtual void set_render_priority(int p_priority) {}
|
||||
virtual void set_next_pass(RID p_pass) {}
|
||||
virtual void update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
|
||||
virtual void bind_uniforms();
|
||||
virtual ~CanvasMaterialData();
|
||||
};
|
||||
|
||||
MaterialData *_create_canvas_material_func(ShaderData *p_shader);
|
||||
|
||||
/* Sky Materials */
|
||||
|
||||
struct SkyShaderData : public ShaderData {
|
||||
// All these members are (re)initialized in `set_code`.
|
||||
// Make sure to add the init to `set_code` whenever adding new members.
|
||||
|
||||
bool valid;
|
||||
RID version;
|
||||
|
||||
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
|
||||
|
||||
Vector<uint32_t> ubo_offsets;
|
||||
uint32_t ubo_size;
|
||||
|
||||
String code;
|
||||
|
||||
bool uses_time;
|
||||
bool uses_position;
|
||||
bool uses_half_res;
|
||||
bool uses_quarter_res;
|
||||
bool uses_light;
|
||||
|
||||
virtual void set_code(const String &p_Code);
|
||||
virtual bool is_animated() const;
|
||||
virtual bool casts_shadows() const;
|
||||
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
|
||||
SkyShaderData();
|
||||
virtual ~SkyShaderData();
|
||||
};
|
||||
|
||||
ShaderData *_create_sky_shader_func();
|
||||
|
||||
struct SkyMaterialData : public MaterialData {
|
||||
SkyShaderData *shader_data = nullptr;
|
||||
bool uniform_set_updated = false;
|
||||
|
||||
virtual void set_render_priority(int p_priority) {}
|
||||
virtual void set_next_pass(RID p_pass) {}
|
||||
virtual void update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
|
||||
virtual void bind_uniforms();
|
||||
virtual ~SkyMaterialData();
|
||||
};
|
||||
|
||||
MaterialData *_create_sky_material_func(ShaderData *p_shader);
|
||||
|
||||
/* Scene Materials */
|
||||
|
||||
struct SceneShaderData : public ShaderData {
|
||||
enum BlendMode { // Used internally.
|
||||
BLEND_MODE_MIX,
|
||||
BLEND_MODE_ADD,
|
||||
BLEND_MODE_SUB,
|
||||
BLEND_MODE_MUL,
|
||||
BLEND_MODE_PREMULT_ALPHA,
|
||||
BLEND_MODE_ALPHA_TO_COVERAGE
|
||||
};
|
||||
|
||||
enum DepthDraw {
|
||||
DEPTH_DRAW_DISABLED,
|
||||
DEPTH_DRAW_OPAQUE,
|
||||
DEPTH_DRAW_ALWAYS
|
||||
};
|
||||
|
||||
enum DepthTest {
|
||||
DEPTH_TEST_DISABLED,
|
||||
DEPTH_TEST_ENABLED,
|
||||
DEPTH_TEST_ENABLED_INVERTED,
|
||||
};
|
||||
|
||||
enum StencilCompare {
|
||||
STENCIL_COMPARE_LESS,
|
||||
STENCIL_COMPARE_EQUAL,
|
||||
STENCIL_COMPARE_LESS_OR_EQUAL,
|
||||
STENCIL_COMPARE_GREATER,
|
||||
STENCIL_COMPARE_NOT_EQUAL,
|
||||
STENCIL_COMPARE_GREATER_OR_EQUAL,
|
||||
STENCIL_COMPARE_ALWAYS,
|
||||
STENCIL_COMPARE_MAX // not an actual operator, just the amount of operators
|
||||
};
|
||||
|
||||
enum StencilFlags {
|
||||
STENCIL_FLAG_READ = 1,
|
||||
STENCIL_FLAG_WRITE = 2,
|
||||
STENCIL_FLAG_WRITE_DEPTH_FAIL = 4,
|
||||
};
|
||||
|
||||
enum AlphaAntiAliasing {
|
||||
ALPHA_ANTIALIASING_OFF,
|
||||
ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE,
|
||||
ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE
|
||||
};
|
||||
|
||||
// All these members are (re)initialized in `set_code`.
|
||||
// Make sure to add the init to `set_code` whenever adding new members.
|
||||
|
||||
bool valid;
|
||||
RID version;
|
||||
|
||||
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
|
||||
|
||||
Vector<uint32_t> ubo_offsets;
|
||||
uint32_t ubo_size;
|
||||
|
||||
String code;
|
||||
|
||||
BlendMode blend_mode;
|
||||
AlphaAntiAliasing alpha_antialiasing_mode;
|
||||
DepthDraw depth_draw;
|
||||
DepthTest depth_test;
|
||||
RS::CullMode cull_mode;
|
||||
|
||||
StencilCompare stencil_compare;
|
||||
uint32_t stencil_flags;
|
||||
int32_t stencil_reference;
|
||||
bool stencil_enabled;
|
||||
|
||||
bool uses_point_size;
|
||||
bool uses_alpha;
|
||||
bool uses_alpha_clip;
|
||||
bool uses_blend_alpha;
|
||||
bool uses_depth_prepass_alpha;
|
||||
bool uses_discard;
|
||||
bool uses_roughness;
|
||||
bool uses_normal;
|
||||
bool uses_particle_trails;
|
||||
bool wireframe;
|
||||
|
||||
bool unshaded;
|
||||
bool uses_vertex;
|
||||
bool uses_position;
|
||||
bool uses_sss;
|
||||
bool uses_transmittance;
|
||||
bool uses_screen_texture;
|
||||
bool uses_screen_texture_mipmaps;
|
||||
bool uses_depth_texture;
|
||||
bool uses_normal_texture;
|
||||
bool uses_bent_normal_texture;
|
||||
bool uses_time;
|
||||
bool uses_vertex_time;
|
||||
bool uses_fragment_time;
|
||||
bool writes_modelview_or_projection;
|
||||
bool uses_world_coordinates;
|
||||
bool uses_tangent;
|
||||
bool uses_color;
|
||||
bool uses_uv;
|
||||
bool uses_uv2;
|
||||
bool uses_custom0;
|
||||
bool uses_custom1;
|
||||
bool uses_custom2;
|
||||
bool uses_custom3;
|
||||
bool uses_bones;
|
||||
bool uses_weights;
|
||||
|
||||
uint64_t vertex_input_mask;
|
||||
|
||||
virtual void set_code(const String &p_Code);
|
||||
virtual bool is_animated() const;
|
||||
virtual bool casts_shadows() const;
|
||||
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
|
||||
|
||||
SceneShaderData();
|
||||
virtual ~SceneShaderData();
|
||||
};
|
||||
|
||||
ShaderData *_create_scene_shader_func();
|
||||
|
||||
struct SceneMaterialData : public MaterialData {
|
||||
SceneShaderData *shader_data = nullptr;
|
||||
uint64_t last_pass = 0;
|
||||
uint32_t index = 0;
|
||||
RID next_pass;
|
||||
uint8_t priority = 0;
|
||||
virtual void set_render_priority(int p_priority);
|
||||
virtual void set_next_pass(RID p_pass);
|
||||
virtual void update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
|
||||
virtual void bind_uniforms();
|
||||
virtual ~SceneMaterialData();
|
||||
};
|
||||
|
||||
MaterialData *_create_scene_material_func(ShaderData *p_shader);
|
||||
|
||||
/* Particle Shader */
|
||||
|
||||
enum {
|
||||
PARTICLES_MAX_USERDATAS = 6
|
||||
};
|
||||
|
||||
struct ParticlesShaderData : public ShaderData {
|
||||
// All these members are (re)initialized in `set_code`.
|
||||
// Make sure to add the init to `set_code` whenever adding new members.
|
||||
|
||||
bool valid;
|
||||
RID version;
|
||||
|
||||
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
|
||||
|
||||
Vector<uint32_t> ubo_offsets;
|
||||
uint32_t ubo_size;
|
||||
|
||||
String code;
|
||||
|
||||
bool uses_collision;
|
||||
bool uses_time;
|
||||
|
||||
bool userdatas_used[PARTICLES_MAX_USERDATAS] = {};
|
||||
uint32_t userdata_count;
|
||||
|
||||
virtual void set_code(const String &p_Code);
|
||||
virtual bool is_animated() const;
|
||||
virtual bool casts_shadows() const;
|
||||
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
|
||||
|
||||
ParticlesShaderData() {}
|
||||
virtual ~ParticlesShaderData();
|
||||
};
|
||||
|
||||
ShaderData *_create_particles_shader_func();
|
||||
|
||||
struct ParticleProcessMaterialData : public MaterialData {
|
||||
ParticlesShaderData *shader_data = nullptr;
|
||||
RID uniform_set;
|
||||
|
||||
virtual void set_render_priority(int p_priority) {}
|
||||
virtual void set_next_pass(RID p_pass) {}
|
||||
virtual void update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
|
||||
virtual void bind_uniforms();
|
||||
virtual ~ParticleProcessMaterialData();
|
||||
};
|
||||
|
||||
MaterialData *_create_particles_material_func(ShaderData *p_shader);
|
||||
|
||||
/* Global shader uniform structs */
|
||||
struct GlobalShaderUniforms {
|
||||
enum {
|
||||
BUFFER_DIRTY_REGION_SIZE = 1024
|
||||
};
|
||||
struct Variable {
|
||||
HashSet<RID> texture_materials; // materials using this
|
||||
|
||||
RS::GlobalShaderParameterType type;
|
||||
Variant value;
|
||||
Variant override;
|
||||
int32_t buffer_index; //for vectors
|
||||
int32_t buffer_elements; //for vectors
|
||||
};
|
||||
|
||||
HashMap<StringName, Variable> variables;
|
||||
|
||||
struct Value {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float w;
|
||||
};
|
||||
|
||||
struct ValueInt {
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
int32_t z;
|
||||
int32_t w;
|
||||
};
|
||||
|
||||
struct ValueUInt {
|
||||
uint32_t x;
|
||||
uint32_t y;
|
||||
uint32_t z;
|
||||
uint32_t w;
|
||||
};
|
||||
|
||||
struct ValueUsage {
|
||||
uint32_t elements = 0;
|
||||
};
|
||||
|
||||
List<RID> materials_using_buffer;
|
||||
List<RID> materials_using_texture;
|
||||
|
||||
GLuint buffer = GLuint(0);
|
||||
Value *buffer_values = nullptr;
|
||||
ValueUsage *buffer_usage = nullptr;
|
||||
bool *buffer_dirty_regions = nullptr;
|
||||
uint32_t buffer_dirty_region_count = 0;
|
||||
|
||||
uint32_t buffer_size;
|
||||
|
||||
bool must_update_texture_materials = false;
|
||||
bool must_update_buffer_materials = false;
|
||||
|
||||
HashMap<RID, int32_t> instance_buffer_pos;
|
||||
};
|
||||
|
||||
class MaterialStorage : public RendererMaterialStorage {
|
||||
private:
|
||||
friend struct MaterialData;
|
||||
static MaterialStorage *singleton;
|
||||
|
||||
/* GLOBAL SHADER UNIFORM API */
|
||||
|
||||
GlobalShaderUniforms global_shader_uniforms;
|
||||
|
||||
int32_t _global_shader_uniform_allocate(uint32_t p_elements);
|
||||
void _global_shader_uniform_store_in_buffer(int32_t p_index, RS::GlobalShaderParameterType p_type, const Variant &p_value);
|
||||
void _global_shader_uniform_mark_buffer_dirty(int32_t p_index, int32_t p_elements);
|
||||
|
||||
/* SHADER API */
|
||||
|
||||
ShaderDataRequestFunction shader_data_request_func[RS::SHADER_MAX];
|
||||
mutable RID_Owner<Shader, true> shader_owner;
|
||||
|
||||
/* MATERIAL API */
|
||||
MaterialDataRequestFunction material_data_request_func[RS::SHADER_MAX];
|
||||
mutable RID_Owner<Material, true> material_owner;
|
||||
|
||||
SelfList<Material>::List material_update_list;
|
||||
HashSet<RID> dummy_embedded_set;
|
||||
|
||||
public:
|
||||
static MaterialStorage *get_singleton();
|
||||
|
||||
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 Projection &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.columns[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Shaders {
|
||||
CanvasShaderGLES3 canvas_shader;
|
||||
SkyShaderGLES3 sky_shader;
|
||||
SceneShaderGLES3 scene_shader;
|
||||
ParticlesShaderGLES3 particles_process_shader;
|
||||
|
||||
ShaderCompiler compiler_canvas;
|
||||
ShaderCompiler compiler_scene;
|
||||
ShaderCompiler compiler_particles;
|
||||
ShaderCompiler compiler_sky;
|
||||
} shaders;
|
||||
|
||||
/* GLOBAL SHADER UNIFORM API */
|
||||
|
||||
void _update_global_shader_uniforms();
|
||||
|
||||
virtual void global_shader_parameter_add(const StringName &p_name, RS::GlobalShaderParameterType p_type, const Variant &p_value) override;
|
||||
virtual void global_shader_parameter_remove(const StringName &p_name) override;
|
||||
virtual Vector<StringName> global_shader_parameter_get_list() const override;
|
||||
|
||||
virtual void global_shader_parameter_set(const StringName &p_name, const Variant &p_value) override;
|
||||
virtual void global_shader_parameter_set_override(const StringName &p_name, const Variant &p_value) override;
|
||||
virtual Variant global_shader_parameter_get(const StringName &p_name) const override;
|
||||
virtual RS::GlobalShaderParameterType global_shader_parameter_get_type(const StringName &p_name) const override;
|
||||
RS::GlobalShaderParameterType global_shader_parameter_get_type_internal(const StringName &p_name) const;
|
||||
|
||||
virtual void global_shader_parameters_load_settings(bool p_load_textures = true) override;
|
||||
virtual void global_shader_parameters_clear() override;
|
||||
|
||||
virtual int32_t global_shader_parameters_instance_allocate(RID p_instance) override;
|
||||
virtual void global_shader_parameters_instance_free(RID p_instance) override;
|
||||
virtual void global_shader_parameters_instance_update(RID p_instance, int p_index, const Variant &p_value, int p_flags_count = 0) override;
|
||||
|
||||
GLuint global_shader_parameters_get_uniform_buffer() const;
|
||||
|
||||
/* SHADER API */
|
||||
|
||||
Shader *get_shader(RID p_rid) { return shader_owner.get_or_null(p_rid); }
|
||||
bool owns_shader(RID p_rid) { return shader_owner.owns(p_rid); }
|
||||
|
||||
void _shader_make_dirty(Shader *p_shader);
|
||||
|
||||
virtual RID shader_allocate() override;
|
||||
virtual void shader_initialize(RID p_rid, bool p_embedded = true) override;
|
||||
virtual void shader_free(RID p_rid) override;
|
||||
|
||||
virtual void shader_set_code(RID p_shader, const String &p_code) override;
|
||||
virtual void shader_set_path_hint(RID p_shader, const String &p_path) override;
|
||||
virtual String shader_get_code(RID p_shader) const override;
|
||||
virtual void get_shader_parameter_list(RID p_shader, List<PropertyInfo> *p_param_list) const override;
|
||||
|
||||
virtual void shader_set_default_texture_parameter(RID p_shader, const StringName &p_name, RID p_texture, int p_index) override;
|
||||
virtual RID shader_get_default_texture_parameter(RID p_shader, const StringName &p_name, int p_index) const override;
|
||||
virtual Variant shader_get_parameter_default(RID p_shader, const StringName &p_name) const override;
|
||||
|
||||
virtual RS::ShaderNativeSourceCode shader_get_native_source_code(RID p_shader) const override;
|
||||
virtual void shader_embedded_set_lock() override {}
|
||||
virtual const HashSet<RID> &shader_embedded_set_get() const override { return dummy_embedded_set; }
|
||||
virtual void shader_embedded_set_unlock() override {}
|
||||
|
||||
/* MATERIAL API */
|
||||
|
||||
Material *get_material(RID p_rid) { return material_owner.get_or_null(p_rid); }
|
||||
bool owns_material(RID p_rid) { return material_owner.owns(p_rid); }
|
||||
|
||||
void _material_queue_update(Material *material, bool p_uniform, bool p_texture);
|
||||
void _update_queued_materials();
|
||||
|
||||
virtual RID material_allocate() override;
|
||||
virtual void material_initialize(RID p_rid) override;
|
||||
virtual void material_free(RID p_rid) override;
|
||||
|
||||
virtual void material_set_shader(RID p_material, RID p_shader) override;
|
||||
|
||||
virtual void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) override;
|
||||
virtual Variant material_get_param(RID p_material, const StringName &p_param) const override;
|
||||
|
||||
virtual void material_set_next_pass(RID p_material, RID p_next_material) override;
|
||||
virtual void material_set_render_priority(RID p_material, int priority) override;
|
||||
|
||||
virtual bool material_is_animated(RID p_material) override;
|
||||
virtual bool material_casts_shadows(RID p_material) override;
|
||||
virtual RS::CullMode material_get_cull_mode(RID p_material) const override;
|
||||
|
||||
virtual void material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) 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);
|
||||
return material->shader_id;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ MaterialData *material_get_data(RID p_material, RS::ShaderMode p_shader_mode) {
|
||||
Material *material = material_owner.get_or_null(p_material);
|
||||
if (!material || material->shader_mode != p_shader_mode) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return material->data;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace GLES3
|
||||
|
||||
#endif // GLES3_ENABLED
|
2441
drivers/gles3/storage/mesh_storage.cpp
Normal file
2441
drivers/gles3/storage/mesh_storage.cpp
Normal file
File diff suppressed because it is too large
Load Diff
615
drivers/gles3/storage/mesh_storage.h
Normal file
615
drivers/gles3/storage/mesh_storage.h
Normal file
@@ -0,0 +1,615 @@
|
||||
/**************************************************************************/
|
||||
/* mesh_storage.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef GLES3_ENABLED
|
||||
|
||||
#include "core/templates/local_vector.h"
|
||||
#include "core/templates/rid_owner.h"
|
||||
#include "core/templates/self_list.h"
|
||||
#include "drivers/gles3/shaders/skeleton.glsl.gen.h"
|
||||
#include "servers/rendering/storage/mesh_storage.h"
|
||||
#include "servers/rendering/storage/utilities.h"
|
||||
|
||||
#include "platform_gl.h"
|
||||
|
||||
namespace GLES3 {
|
||||
|
||||
struct MeshInstance;
|
||||
|
||||
struct Mesh {
|
||||
struct Surface {
|
||||
struct Attrib {
|
||||
bool enabled;
|
||||
bool integer;
|
||||
GLint size;
|
||||
GLenum type;
|
||||
GLboolean normalized;
|
||||
GLsizei stride;
|
||||
uint32_t offset;
|
||||
};
|
||||
RS::PrimitiveType primitive = RS::PRIMITIVE_POINTS;
|
||||
uint64_t format = 0;
|
||||
|
||||
GLuint vertex_buffer = 0;
|
||||
GLuint attribute_buffer = 0;
|
||||
GLuint skin_buffer = 0;
|
||||
uint32_t vertex_count = 0;
|
||||
uint32_t vertex_buffer_size = 0;
|
||||
uint32_t attribute_buffer_size = 0;
|
||||
uint32_t skin_buffer_size = 0;
|
||||
|
||||
// Cache vertex arrays so they can be created
|
||||
struct Version {
|
||||
uint32_t input_mask = 0;
|
||||
GLuint vertex_array = 0;
|
||||
|
||||
Attrib attribs[RS::ARRAY_MAX];
|
||||
};
|
||||
|
||||
SpinLock version_lock; //needed to access versions
|
||||
Version *versions = nullptr; //allocated on demand
|
||||
uint32_t version_count = 0;
|
||||
|
||||
GLuint index_buffer = 0;
|
||||
uint32_t index_count = 0;
|
||||
uint32_t index_buffer_size = 0;
|
||||
|
||||
struct Wireframe {
|
||||
GLuint index_buffer = 0;
|
||||
uint32_t index_count = 0;
|
||||
uint32_t index_buffer_size = 0;
|
||||
};
|
||||
|
||||
Wireframe *wireframe = nullptr;
|
||||
|
||||
struct LOD {
|
||||
float edge_length = 0.0;
|
||||
uint32_t index_count = 0;
|
||||
uint32_t index_buffer_size = 0;
|
||||
GLuint index_buffer = 0;
|
||||
};
|
||||
|
||||
LOD *lods = nullptr;
|
||||
uint32_t lod_count = 0;
|
||||
|
||||
AABB aabb;
|
||||
|
||||
Vector<AABB> bone_aabbs;
|
||||
|
||||
// Transform used in runtime bone AABBs compute.
|
||||
// As bone AABBs are saved in Mesh space, but bones animation is in Skeleton space.
|
||||
Transform3D mesh_to_skeleton_xform;
|
||||
|
||||
Vector4 uv_scale;
|
||||
|
||||
struct BlendShape {
|
||||
GLuint vertex_buffer = 0;
|
||||
GLuint vertex_array = 0;
|
||||
};
|
||||
|
||||
BlendShape *blend_shapes = nullptr;
|
||||
GLuint skeleton_vertex_array = 0;
|
||||
|
||||
RID material;
|
||||
};
|
||||
|
||||
uint32_t blend_shape_count = 0;
|
||||
RS::BlendShapeMode blend_shape_mode = RS::BLEND_SHAPE_MODE_NORMALIZED;
|
||||
|
||||
Surface **surfaces = nullptr;
|
||||
uint32_t surface_count = 0;
|
||||
|
||||
bool has_bone_weights = false;
|
||||
|
||||
AABB aabb;
|
||||
AABB custom_aabb;
|
||||
uint64_t skeleton_aabb_version = 0;
|
||||
|
||||
Vector<RID> material_cache;
|
||||
|
||||
List<MeshInstance *> instances;
|
||||
|
||||
RID shadow_mesh;
|
||||
HashSet<Mesh *> shadow_owners;
|
||||
|
||||
String path;
|
||||
|
||||
Dependency dependency;
|
||||
};
|
||||
|
||||
/* Mesh Instance */
|
||||
|
||||
struct MeshInstance {
|
||||
Mesh *mesh = nullptr;
|
||||
RID skeleton;
|
||||
struct Surface {
|
||||
GLuint vertex_buffers[2] = { 0, 0 };
|
||||
GLuint vertex_arrays[2] = { 0, 0 };
|
||||
GLuint vertex_buffer = 0;
|
||||
int vertex_stride_cache = 0;
|
||||
int vertex_size_cache = 0;
|
||||
int vertex_normal_offset_cache = 0;
|
||||
int vertex_tangent_offset_cache = 0;
|
||||
uint64_t format_cache = 0;
|
||||
|
||||
Mesh::Surface::Version *versions = nullptr; //allocated on demand
|
||||
uint32_t version_count = 0;
|
||||
};
|
||||
LocalVector<Surface> surfaces;
|
||||
LocalVector<float> blend_weights;
|
||||
|
||||
List<MeshInstance *>::Element *I = nullptr; //used to erase itself
|
||||
uint64_t skeleton_version = 0;
|
||||
bool dirty = false;
|
||||
bool weights_dirty = false;
|
||||
SelfList<MeshInstance> weight_update_list;
|
||||
SelfList<MeshInstance> array_update_list;
|
||||
Transform2D canvas_item_transform_2d;
|
||||
MeshInstance() :
|
||||
weight_update_list(this), array_update_list(this) {}
|
||||
};
|
||||
|
||||
/* MultiMesh */
|
||||
|
||||
struct MultiMesh {
|
||||
RID mesh;
|
||||
int instances = 0;
|
||||
RS::MultimeshTransformFormat xform_format = RS::MULTIMESH_TRANSFORM_3D;
|
||||
bool uses_colors = false;
|
||||
bool uses_custom_data = false;
|
||||
int visible_instances = -1;
|
||||
AABB aabb;
|
||||
AABB custom_aabb;
|
||||
bool aabb_dirty = false;
|
||||
bool buffer_set = false;
|
||||
uint32_t stride_cache = 0;
|
||||
uint32_t color_offset_cache = 0;
|
||||
uint32_t custom_data_offset_cache = 0;
|
||||
|
||||
Vector<float> data_cache; //used if individual setting is used
|
||||
bool *data_cache_dirty_regions = nullptr;
|
||||
uint32_t data_cache_used_dirty_regions = 0;
|
||||
|
||||
GLuint buffer = 0;
|
||||
|
||||
bool dirty = false;
|
||||
MultiMesh *dirty_list = nullptr;
|
||||
|
||||
RendererMeshStorage::MultiMeshInterpolator interpolator;
|
||||
|
||||
Dependency dependency;
|
||||
};
|
||||
|
||||
struct Skeleton {
|
||||
bool use_2d = false;
|
||||
int size = 0;
|
||||
int height = 0;
|
||||
LocalVector<float> data;
|
||||
|
||||
bool dirty = false;
|
||||
Skeleton *dirty_list = nullptr;
|
||||
Transform2D base_transform_2d;
|
||||
|
||||
GLuint transforms_texture = 0;
|
||||
|
||||
uint64_t version = 1;
|
||||
|
||||
Dependency dependency;
|
||||
};
|
||||
|
||||
class MeshStorage : public RendererMeshStorage {
|
||||
private:
|
||||
static MeshStorage *singleton;
|
||||
|
||||
struct {
|
||||
SkeletonShaderGLES3 shader;
|
||||
RID shader_version;
|
||||
} skeleton_shader;
|
||||
|
||||
/* Mesh */
|
||||
|
||||
mutable RID_Owner<Mesh, true> mesh_owner;
|
||||
|
||||
void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint64_t p_input_mask, MeshInstance::Surface *mis = nullptr);
|
||||
void _mesh_surface_clear(Mesh *mesh, int p_surface);
|
||||
|
||||
/* Mesh Instance API */
|
||||
|
||||
mutable RID_Owner<MeshInstance> mesh_instance_owner;
|
||||
|
||||
void _mesh_instance_clear(MeshInstance *mi);
|
||||
void _mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface);
|
||||
void _mesh_instance_remove_surface(MeshInstance *mi, int p_surface);
|
||||
void _blend_shape_bind_mesh_instance_buffer(MeshInstance *p_mi, uint32_t p_surface);
|
||||
SelfList<MeshInstance>::List dirty_mesh_instance_weights;
|
||||
SelfList<MeshInstance>::List dirty_mesh_instance_arrays;
|
||||
|
||||
/* MultiMesh */
|
||||
|
||||
mutable RID_Owner<MultiMesh, true> multimesh_owner;
|
||||
|
||||
MultiMesh *multimesh_dirty_list = nullptr;
|
||||
|
||||
_FORCE_INLINE_ void _multimesh_make_local(MultiMesh *multimesh) const;
|
||||
_FORCE_INLINE_ void _multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb);
|
||||
_FORCE_INLINE_ void _multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, bool p_aabb);
|
||||
_FORCE_INLINE_ void _multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances);
|
||||
|
||||
/* Skeleton */
|
||||
|
||||
mutable RID_Owner<Skeleton, true> skeleton_owner;
|
||||
|
||||
_FORCE_INLINE_ void _skeleton_make_dirty(Skeleton *skeleton);
|
||||
void _compute_skeleton(MeshInstance *p_mi, Skeleton *p_sk, uint32_t p_surface);
|
||||
|
||||
Skeleton *skeleton_dirty_list = nullptr;
|
||||
|
||||
public:
|
||||
static MeshStorage *get_singleton();
|
||||
|
||||
MeshStorage();
|
||||
virtual ~MeshStorage();
|
||||
|
||||
/* MESH API */
|
||||
|
||||
Mesh *get_mesh(RID p_rid) { return mesh_owner.get_or_null(p_rid); }
|
||||
bool owns_mesh(RID p_rid) { return mesh_owner.owns(p_rid); }
|
||||
|
||||
virtual RID mesh_allocate() override;
|
||||
virtual void mesh_initialize(RID p_rid) override;
|
||||
virtual void mesh_free(RID p_rid) override;
|
||||
|
||||
virtual void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) override;
|
||||
virtual bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) override;
|
||||
|
||||
virtual void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) override;
|
||||
|
||||
virtual int mesh_get_blend_shape_count(RID p_mesh) const override;
|
||||
|
||||
virtual void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) override;
|
||||
virtual RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const override;
|
||||
|
||||
virtual void mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override;
|
||||
virtual void mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override;
|
||||
virtual void mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override;
|
||||
virtual void mesh_surface_update_index_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override;
|
||||
|
||||
virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) override;
|
||||
virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const override;
|
||||
|
||||
virtual RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const override;
|
||||
virtual int mesh_get_surface_count(RID p_mesh) const override;
|
||||
|
||||
virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) override;
|
||||
virtual AABB mesh_get_custom_aabb(RID p_mesh) const override;
|
||||
virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) override;
|
||||
|
||||
virtual void mesh_set_path(RID p_mesh, const String &p_path) override;
|
||||
virtual String mesh_get_path(RID p_mesh) const override;
|
||||
|
||||
virtual void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) override;
|
||||
|
||||
virtual void mesh_clear(RID p_mesh) override;
|
||||
virtual void mesh_surface_remove(RID p_mesh, int p_surface) override;
|
||||
virtual void mesh_debug_usage(List<RS::MeshInfo> *r_info) override {}
|
||||
|
||||
_FORCE_INLINE_ const RID *mesh_get_surface_count_and_materials(RID p_mesh, uint32_t &r_surface_count) {
|
||||
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
|
||||
ERR_FAIL_NULL_V(mesh, nullptr);
|
||||
r_surface_count = mesh->surface_count;
|
||||
if (r_surface_count == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
if (mesh->material_cache.is_empty()) {
|
||||
mesh->material_cache.resize(mesh->surface_count);
|
||||
for (uint32_t i = 0; i < r_surface_count; i++) {
|
||||
mesh->material_cache.write[i] = mesh->surfaces[i]->material;
|
||||
}
|
||||
}
|
||||
|
||||
return mesh->material_cache.ptr();
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void *mesh_get_surface(RID p_mesh, uint32_t p_surface_index) {
|
||||
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
|
||||
ERR_FAIL_NULL_V(mesh, nullptr);
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_surface_index, mesh->surface_count, nullptr);
|
||||
|
||||
return mesh->surfaces[p_surface_index];
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ RID mesh_get_shadow_mesh(RID p_mesh) {
|
||||
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
|
||||
ERR_FAIL_NULL_V(mesh, RID());
|
||||
|
||||
return mesh->shadow_mesh;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ RS::PrimitiveType mesh_surface_get_primitive(void *p_surface) {
|
||||
Mesh::Surface *surface = reinterpret_cast<Mesh::Surface *>(p_surface);
|
||||
return surface->primitive;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool mesh_surface_has_lod(void *p_surface) const {
|
||||
Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
|
||||
return s->lod_count > 0;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t mesh_surface_get_vertices_drawn_count(void *p_surface) const {
|
||||
Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
|
||||
return s->index_count ? s->index_count : s->vertex_count;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t mesh_surface_get_lod(void *p_surface, float p_model_scale, float p_distance_threshold, float p_mesh_lod_threshold, uint32_t &r_index_count) const {
|
||||
Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
|
||||
ERR_FAIL_NULL_V(s, 0);
|
||||
|
||||
int32_t current_lod = -1;
|
||||
r_index_count = s->index_count;
|
||||
|
||||
for (uint32_t i = 0; i < s->lod_count; i++) {
|
||||
float screen_size = s->lods[i].edge_length * p_model_scale / p_distance_threshold;
|
||||
if (screen_size > p_mesh_lod_threshold) {
|
||||
break;
|
||||
}
|
||||
current_lod = i;
|
||||
}
|
||||
if (current_lod == -1) {
|
||||
return 0;
|
||||
} else {
|
||||
r_index_count = s->lods[current_lod].index_count;
|
||||
return current_lod + 1;
|
||||
}
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ GLuint mesh_surface_get_index_buffer(void *p_surface, uint32_t p_lod) const {
|
||||
Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
|
||||
|
||||
if (p_lod == 0) {
|
||||
return s->index_buffer;
|
||||
} else {
|
||||
return s->lods[p_lod - 1].index_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ GLuint mesh_surface_get_index_buffer_wireframe(void *p_surface) const {
|
||||
Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
|
||||
|
||||
if (s->wireframe) {
|
||||
return s->wireframe->index_buffer;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ GLenum mesh_surface_get_index_type(void *p_surface) const {
|
||||
Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
|
||||
|
||||
return (s->vertex_count <= 65536 && s->vertex_count > 0) ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
|
||||
}
|
||||
|
||||
// Use this to cache Vertex Array Objects so they are only generated once
|
||||
_FORCE_INLINE_ void mesh_surface_get_vertex_arrays_and_format(void *p_surface, uint64_t p_input_mask, GLuint &r_vertex_array_gl) {
|
||||
Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
|
||||
|
||||
s->version_lock.lock();
|
||||
|
||||
// There will never be more than 3 or 4 versions, so iterating is the fastest way.
|
||||
|
||||
for (uint32_t i = 0; i < s->version_count; i++) {
|
||||
if (s->versions[i].input_mask != p_input_mask) {
|
||||
continue;
|
||||
}
|
||||
// We have this version, hooray.
|
||||
r_vertex_array_gl = s->versions[i].vertex_array;
|
||||
s->version_lock.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t version = s->version_count;
|
||||
s->version_count++;
|
||||
s->versions = (Mesh::Surface::Version *)memrealloc(s->versions, sizeof(Mesh::Surface::Version) * s->version_count);
|
||||
|
||||
_mesh_surface_generate_version_for_input_mask(s->versions[version], s, p_input_mask);
|
||||
|
||||
r_vertex_array_gl = s->versions[version].vertex_array;
|
||||
|
||||
s->version_lock.unlock();
|
||||
}
|
||||
|
||||
/* MESH INSTANCE API */
|
||||
|
||||
MeshInstance *get_mesh_instance(RID p_rid) { return mesh_instance_owner.get_or_null(p_rid); }
|
||||
bool owns_mesh_instance(RID p_rid) { return mesh_instance_owner.owns(p_rid); }
|
||||
|
||||
virtual RID mesh_instance_create(RID p_base) override;
|
||||
virtual void mesh_instance_free(RID p_rid) override;
|
||||
virtual void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) override;
|
||||
virtual void mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) override;
|
||||
virtual void mesh_instance_check_for_update(RID p_mesh_instance) override;
|
||||
virtual void mesh_instance_set_canvas_item_transform(RID p_mesh_instance, const Transform2D &p_transform) override;
|
||||
virtual void update_mesh_instances() override;
|
||||
|
||||
// TODO: considering hashing versions with multimesh buffer RID.
|
||||
// Doing so would allow us to avoid specifying multimesh buffer pointers every frame and may improve performance.
|
||||
_FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint32_t p_surface_index, uint64_t p_input_mask, GLuint &r_vertex_array_gl) {
|
||||
MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
|
||||
ERR_FAIL_NULL(mi);
|
||||
Mesh *mesh = mi->mesh;
|
||||
ERR_FAIL_UNSIGNED_INDEX(p_surface_index, mesh->surface_count);
|
||||
|
||||
MeshInstance::Surface *mis = &mi->surfaces[p_surface_index];
|
||||
Mesh::Surface *s = mesh->surfaces[p_surface_index];
|
||||
|
||||
s->version_lock.lock();
|
||||
|
||||
//there will never be more than, at much, 3 or 4 versions, so iterating is the fastest way
|
||||
|
||||
for (uint32_t i = 0; i < mis->version_count; i++) {
|
||||
if (mis->versions[i].input_mask != p_input_mask) {
|
||||
continue;
|
||||
}
|
||||
//we have this version, hooray
|
||||
r_vertex_array_gl = mis->versions[i].vertex_array;
|
||||
s->version_lock.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t version = mis->version_count;
|
||||
mis->version_count++;
|
||||
mis->versions = (Mesh::Surface::Version *)memrealloc(mis->versions, sizeof(Mesh::Surface::Version) * mis->version_count);
|
||||
|
||||
_mesh_surface_generate_version_for_input_mask(mis->versions[version], s, p_input_mask, mis);
|
||||
|
||||
r_vertex_array_gl = mis->versions[version].vertex_array;
|
||||
|
||||
s->version_lock.unlock();
|
||||
}
|
||||
|
||||
/* MULTIMESH API */
|
||||
|
||||
MultiMesh *get_multimesh(RID p_rid) { return multimesh_owner.get_or_null(p_rid); }
|
||||
bool owns_multimesh(RID p_rid) { return multimesh_owner.owns(p_rid); }
|
||||
|
||||
virtual RID _multimesh_allocate() override;
|
||||
virtual void _multimesh_initialize(RID p_rid) override;
|
||||
virtual void _multimesh_free(RID p_rid) override;
|
||||
virtual void _multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false, bool p_use_indirect = false) override;
|
||||
virtual int _multimesh_get_instance_count(RID p_multimesh) const override;
|
||||
|
||||
virtual void _multimesh_set_mesh(RID p_multimesh, RID p_mesh) override;
|
||||
virtual void _multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) override;
|
||||
virtual void _multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) override;
|
||||
virtual void _multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) override;
|
||||
virtual void _multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) override;
|
||||
|
||||
virtual RID _multimesh_get_mesh(RID p_multimesh) const override;
|
||||
virtual void _multimesh_set_custom_aabb(RID p_multimesh, const AABB &p_aabb) override;
|
||||
virtual AABB _multimesh_get_custom_aabb(RID p_multimesh) const override;
|
||||
virtual AABB _multimesh_get_aabb(RID p_multimesh) override;
|
||||
|
||||
virtual Transform3D _multimesh_instance_get_transform(RID p_multimesh, int p_index) const override;
|
||||
virtual Transform2D _multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const override;
|
||||
virtual Color _multimesh_instance_get_color(RID p_multimesh, int p_index) const override;
|
||||
virtual Color _multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override;
|
||||
virtual void _multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) override;
|
||||
virtual RID _multimesh_get_command_buffer_rd_rid(RID p_multimesh) const override;
|
||||
virtual RID _multimesh_get_buffer_rd_rid(RID p_multimesh) const override;
|
||||
virtual Vector<float> _multimesh_get_buffer(RID p_multimesh) const override;
|
||||
|
||||
virtual void _multimesh_set_visible_instances(RID p_multimesh, int p_visible) override;
|
||||
virtual int _multimesh_get_visible_instances(RID p_multimesh) const override;
|
||||
|
||||
virtual MultiMeshInterpolator *_multimesh_get_interpolator(RID p_multimesh) const override;
|
||||
|
||||
void _update_dirty_multimeshes();
|
||||
|
||||
_FORCE_INLINE_ RS::MultimeshTransformFormat multimesh_get_transform_format(RID p_multimesh) const {
|
||||
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
|
||||
ERR_FAIL_NULL_V(multimesh, RS::MULTIMESH_TRANSFORM_3D);
|
||||
return multimesh->xform_format;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool multimesh_uses_colors(RID p_multimesh) const {
|
||||
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
|
||||
ERR_FAIL_NULL_V(multimesh, false);
|
||||
return multimesh->uses_colors;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool multimesh_uses_custom_data(RID p_multimesh) const {
|
||||
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
|
||||
ERR_FAIL_NULL_V(multimesh, false);
|
||||
return multimesh->uses_custom_data;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t multimesh_get_instances_to_draw(RID p_multimesh) const {
|
||||
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
|
||||
ERR_FAIL_NULL_V(multimesh, 0);
|
||||
if (multimesh->visible_instances >= 0) {
|
||||
return multimesh->visible_instances;
|
||||
}
|
||||
return multimesh->instances;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ GLuint multimesh_get_gl_buffer(RID p_multimesh) const {
|
||||
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
|
||||
ERR_FAIL_NULL_V(multimesh, 0);
|
||||
return multimesh->buffer;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t multimesh_get_stride(RID p_multimesh) const {
|
||||
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
|
||||
ERR_FAIL_NULL_V(multimesh, 0);
|
||||
return multimesh->stride_cache;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t multimesh_get_color_offset(RID p_multimesh) const {
|
||||
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
|
||||
ERR_FAIL_NULL_V(multimesh, 0);
|
||||
return multimesh->color_offset_cache;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t multimesh_get_custom_data_offset(RID p_multimesh) const {
|
||||
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
|
||||
ERR_FAIL_NULL_V(multimesh, 0);
|
||||
return multimesh->custom_data_offset_cache;
|
||||
}
|
||||
|
||||
/* SKELETON API */
|
||||
|
||||
Skeleton *get_skeleton(RID p_rid) { return skeleton_owner.get_or_null(p_rid); }
|
||||
bool owns_skeleton(RID p_rid) { return skeleton_owner.owns(p_rid); }
|
||||
|
||||
virtual RID skeleton_allocate() override;
|
||||
virtual void skeleton_initialize(RID p_rid) override;
|
||||
virtual void skeleton_free(RID p_rid) override;
|
||||
|
||||
virtual void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) override;
|
||||
virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) override;
|
||||
virtual int skeleton_get_bone_count(RID p_skeleton) const override;
|
||||
virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) override;
|
||||
virtual Transform3D skeleton_bone_get_transform(RID p_skeleton, int p_bone) const override;
|
||||
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, DependencyTracker *p_instance) override;
|
||||
|
||||
void _update_dirty_skeletons();
|
||||
|
||||
_FORCE_INLINE_ bool skeleton_is_valid(RID p_skeleton) {
|
||||
return skeleton_owner.get_or_null(p_skeleton) != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace GLES3
|
||||
|
||||
#endif // GLES3_ENABLED
|
1473
drivers/gles3/storage/particles_storage.cpp
Normal file
1473
drivers/gles3/storage/particles_storage.cpp
Normal file
File diff suppressed because it is too large
Load Diff
462
drivers/gles3/storage/particles_storage.h
Normal file
462
drivers/gles3/storage/particles_storage.h
Normal file
@@ -0,0 +1,462 @@
|
||||
/**************************************************************************/
|
||||
/* particles_storage.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef GLES3_ENABLED
|
||||
|
||||
#include "core/templates/rid_owner.h"
|
||||
#include "core/templates/self_list.h"
|
||||
#include "drivers/gles3/shaders/particles_copy.glsl.gen.h"
|
||||
#include "servers/rendering/storage/particles_storage.h"
|
||||
#include "servers/rendering/storage/utilities.h"
|
||||
|
||||
#include "platform_gl.h"
|
||||
|
||||
namespace GLES3 {
|
||||
|
||||
enum ParticlesUniformLocation {
|
||||
PARTICLES_FRAME_UNIFORM_LOCATION,
|
||||
PARTICLES_GLOBALS_UNIFORM_LOCATION,
|
||||
PARTICLES_MATERIAL_UNIFORM_LOCATION,
|
||||
};
|
||||
|
||||
class ParticlesStorage : public RendererParticlesStorage {
|
||||
private:
|
||||
static ParticlesStorage *singleton;
|
||||
|
||||
/* PARTICLES */
|
||||
|
||||
struct ParticleInstanceData3D {
|
||||
float xform[12];
|
||||
float color[2]; // Color and custom are packed together into one vec4;
|
||||
float custom[2];
|
||||
};
|
||||
|
||||
struct ParticleInstanceData2D {
|
||||
float xform[8];
|
||||
float color[2]; // Color and custom are packed together into one vec4;
|
||||
float custom[2];
|
||||
};
|
||||
|
||||
struct ParticlesViewSort {
|
||||
Vector3 z_dir;
|
||||
bool operator()(const ParticleInstanceData3D &p_a, const ParticleInstanceData3D &p_b) const {
|
||||
return z_dir.dot(Vector3(p_a.xform[3], p_a.xform[7], p_a.xform[11])) < z_dir.dot(Vector3(p_b.xform[3], p_b.xform[7], p_b.xform[11]));
|
||||
}
|
||||
};
|
||||
|
||||
struct ParticlesFrameParams {
|
||||
enum {
|
||||
MAX_ATTRACTORS = 32,
|
||||
MAX_COLLIDERS = 32,
|
||||
MAX_3D_TEXTURES = 0 // GLES3 renderer doesn't support using 3D textures for flow field or collisions.
|
||||
};
|
||||
|
||||
enum AttractorType {
|
||||
ATTRACTOR_TYPE_SPHERE,
|
||||
ATTRACTOR_TYPE_BOX,
|
||||
ATTRACTOR_TYPE_VECTOR_FIELD,
|
||||
};
|
||||
|
||||
struct Attractor {
|
||||
float transform[16];
|
||||
float extents[4]; // Extents or radius. w-channel is padding.
|
||||
|
||||
uint32_t type;
|
||||
float strength;
|
||||
float attenuation;
|
||||
float directionality;
|
||||
};
|
||||
|
||||
enum CollisionType {
|
||||
COLLISION_TYPE_SPHERE,
|
||||
COLLISION_TYPE_BOX,
|
||||
COLLISION_TYPE_SDF,
|
||||
COLLISION_TYPE_HEIGHT_FIELD,
|
||||
COLLISION_TYPE_2D_SDF,
|
||||
|
||||
};
|
||||
|
||||
struct Collider {
|
||||
float transform[16];
|
||||
float extents[4]; // Extents or radius. w-channel is padding.
|
||||
|
||||
uint32_t type;
|
||||
float scale;
|
||||
float pad0;
|
||||
float pad1;
|
||||
};
|
||||
|
||||
uint32_t emitting;
|
||||
uint32_t cycle;
|
||||
float system_phase;
|
||||
float prev_system_phase;
|
||||
|
||||
float explosiveness;
|
||||
float randomness;
|
||||
float time;
|
||||
float delta;
|
||||
|
||||
float particle_size;
|
||||
float amount_ratio;
|
||||
float pad1;
|
||||
float pad2;
|
||||
|
||||
uint32_t random_seed;
|
||||
uint32_t attractor_count;
|
||||
uint32_t collider_count;
|
||||
uint32_t frame;
|
||||
|
||||
float emission_transform[16];
|
||||
float emitter_velocity[3];
|
||||
float interp_to_end;
|
||||
|
||||
Attractor attractors[MAX_ATTRACTORS];
|
||||
Collider colliders[MAX_COLLIDERS];
|
||||
};
|
||||
|
||||
static_assert(sizeof(ParticlesFrameParams) % 16 == 0, "ParticlesFrameParams size must be a multiple of 16 bytes");
|
||||
static_assert(sizeof(ParticlesFrameParams) < 16384, "ParticlesFrameParams must be 16384 bytes or smaller");
|
||||
|
||||
struct Particles {
|
||||
RS::ParticlesMode mode = RS::PARTICLES_MODE_3D;
|
||||
bool inactive = true;
|
||||
double inactive_time = 0.0;
|
||||
bool emitting = false;
|
||||
bool one_shot = false;
|
||||
float amount_ratio = 1.0;
|
||||
int amount = 0;
|
||||
double lifetime = 1.0;
|
||||
double pre_process_time = 0.0;
|
||||
real_t request_process_time = 0.0;
|
||||
real_t explosiveness = 0.0;
|
||||
real_t randomness = 0.0;
|
||||
bool restart_request = false;
|
||||
AABB custom_aabb = AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8));
|
||||
bool use_local_coords = false;
|
||||
bool has_collision_cache = false;
|
||||
|
||||
bool has_sdf_collision = false;
|
||||
Transform2D sdf_collision_transform;
|
||||
Rect2 sdf_collision_to_screen;
|
||||
GLuint sdf_collision_texture = 0;
|
||||
|
||||
RID process_material;
|
||||
uint32_t frame_counter = 0;
|
||||
RS::ParticlesTransformAlign transform_align = RS::PARTICLES_TRANSFORM_ALIGN_DISABLED;
|
||||
|
||||
RS::ParticlesDrawOrder draw_order = RS::PARTICLES_DRAW_ORDER_INDEX;
|
||||
|
||||
Vector<RID> draw_passes;
|
||||
|
||||
GLuint frame_params_ubo = 0;
|
||||
|
||||
// We may process particles multiple times each frame (if they have a fixed FPS higher than the game FPS).
|
||||
// Unfortunately, this means we can't just use a round-robin system of 3 buffers.
|
||||
// To ensure the sort buffer is accurate, we copy the last frame instance buffer just before processing.
|
||||
|
||||
// Transform Feedback buffer and VAO for rendering.
|
||||
// Each frame we render to this one.
|
||||
GLuint front_vertex_array = 0; // Binds process buffer. Used for processing.
|
||||
GLuint front_process_buffer = 0; // Transform + color + custom data + userdata + velocity + flags. Only needed for processing.
|
||||
GLuint front_instance_buffer = 0; // Transform + color + custom data. In packed format needed for rendering.
|
||||
|
||||
// VAO for transform feedback, contains last frame's data.
|
||||
// Read from this one for particles process and then copy to last frame buffer.
|
||||
GLuint back_vertex_array = 0; // Binds process buffer. Used for processing.
|
||||
GLuint back_process_buffer = 0; // Transform + color + custom data + userdata + velocity + flags. Only needed for processing.
|
||||
GLuint back_instance_buffer = 0; // Transform + color + custom data. In packed format needed for rendering.
|
||||
|
||||
uint32_t instance_buffer_size_cache = 0;
|
||||
uint32_t instance_buffer_stride_cache = 0;
|
||||
uint32_t num_attrib_arrays_cache = 0;
|
||||
uint32_t process_buffer_stride_cache = 0;
|
||||
|
||||
// Only ever copied to, holds last frame's instance data, then swaps with sort_buffer.
|
||||
GLuint last_frame_buffer = 0;
|
||||
bool last_frame_buffer_filled = false;
|
||||
float last_frame_phase = 0.0;
|
||||
|
||||
// The frame-before-last's instance buffer.
|
||||
// Use this to copy data back for sorting or computing AABB.
|
||||
GLuint sort_buffer = 0;
|
||||
bool sort_buffer_filled = false;
|
||||
float sort_buffer_phase = 0.0;
|
||||
|
||||
uint32_t userdata_count = 0;
|
||||
|
||||
bool dirty = false;
|
||||
SelfList<Particles> update_list;
|
||||
|
||||
double phase = 0.0;
|
||||
double prev_phase = 0.0;
|
||||
uint64_t prev_ticks = 0;
|
||||
uint32_t random_seed = 0;
|
||||
|
||||
uint32_t cycle_number = 0;
|
||||
|
||||
double speed_scale = 1.0;
|
||||
|
||||
int fixed_fps = 30;
|
||||
bool interpolate = true;
|
||||
bool fractional_delta = false;
|
||||
double frame_remainder = 0;
|
||||
real_t collision_base_size = 0.01;
|
||||
|
||||
bool clear = true;
|
||||
|
||||
Transform3D emission_transform;
|
||||
Vector3 emitter_velocity;
|
||||
float interp_to_end = 0.0;
|
||||
|
||||
HashSet<RID> collisions;
|
||||
|
||||
Dependency dependency;
|
||||
|
||||
double trail_length = 1.0;
|
||||
bool trails_enabled = false;
|
||||
|
||||
Particles() :
|
||||
update_list(this) {
|
||||
random_seed = Math::rand();
|
||||
}
|
||||
};
|
||||
|
||||
void _particles_process(Particles *p_particles, double p_delta);
|
||||
void _particles_free_data(Particles *particles);
|
||||
void _particles_update_buffers(Particles *particles);
|
||||
void _particles_allocate_history_buffers(Particles *particles);
|
||||
void _particles_update_instance_buffer(Particles *particles, const Vector3 &p_axis, const Vector3 &p_up_axis);
|
||||
|
||||
template <typename T>
|
||||
void _particles_reverse_lifetime_sort(Particles *particles);
|
||||
|
||||
struct ParticlesShader {
|
||||
RID default_shader;
|
||||
RID default_material;
|
||||
RID default_shader_version;
|
||||
|
||||
ParticlesCopyShaderGLES3 copy_shader;
|
||||
RID copy_shader_version;
|
||||
} particles_shader;
|
||||
|
||||
SelfList<Particles>::List particle_update_list;
|
||||
|
||||
mutable RID_Owner<Particles, true> particles_owner;
|
||||
|
||||
/* Particles Collision */
|
||||
|
||||
struct ParticlesCollision {
|
||||
RS::ParticlesCollisionType type = RS::PARTICLES_COLLISION_TYPE_SPHERE_ATTRACT;
|
||||
uint32_t cull_mask = 0xFFFFFFFF;
|
||||
float radius = 1.0;
|
||||
Vector3 extents = Vector3(1, 1, 1);
|
||||
float attractor_strength = 1.0;
|
||||
float attractor_attenuation = 1.0;
|
||||
float attractor_directionality = 0.0;
|
||||
GLuint field_texture = 0;
|
||||
GLuint heightfield_texture = 0;
|
||||
GLuint heightfield_fb = 0;
|
||||
Size2i heightfield_fb_size;
|
||||
uint32_t heightfield_mask = (1 << 20) - 1;
|
||||
|
||||
RS::ParticlesCollisionHeightfieldResolution heightfield_resolution = RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_1024;
|
||||
|
||||
Dependency dependency;
|
||||
};
|
||||
|
||||
struct ParticlesCollisionInstance {
|
||||
RID collision;
|
||||
Transform3D transform;
|
||||
bool active = false;
|
||||
};
|
||||
|
||||
mutable RID_Owner<ParticlesCollision, true> particles_collision_owner;
|
||||
|
||||
mutable RID_Owner<ParticlesCollisionInstance> particles_collision_instance_owner;
|
||||
|
||||
public:
|
||||
static ParticlesStorage *get_singleton();
|
||||
|
||||
ParticlesStorage();
|
||||
virtual ~ParticlesStorage();
|
||||
|
||||
bool free(RID p_rid);
|
||||
|
||||
/* PARTICLES */
|
||||
|
||||
bool owns_particles(RID p_rid) { return particles_owner.owns(p_rid); }
|
||||
|
||||
virtual RID particles_allocate() override;
|
||||
virtual void particles_initialize(RID p_rid) override;
|
||||
virtual void particles_free(RID p_rid) override;
|
||||
|
||||
virtual void particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) override;
|
||||
virtual void particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) override;
|
||||
virtual void particles_set_emitting(RID p_particles, bool p_emitting) override;
|
||||
virtual void particles_set_amount(RID p_particles, int p_amount) override;
|
||||
virtual void particles_set_amount_ratio(RID p_particles, float p_amount_ratio) override;
|
||||
virtual void particles_set_lifetime(RID p_particles, double p_lifetime) override;
|
||||
virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) override;
|
||||
virtual void particles_set_pre_process_time(RID p_particles, double p_time) override;
|
||||
virtual void particles_request_process_time(RID p_particles, real_t p_request_process_time) override;
|
||||
virtual void particles_set_explosiveness_ratio(RID p_particles, real_t p_ratio) override;
|
||||
virtual void particles_set_randomness_ratio(RID p_particles, real_t p_ratio) override;
|
||||
virtual void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) override;
|
||||
virtual void particles_set_speed_scale(RID p_particles, double p_scale) override;
|
||||
virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable) override;
|
||||
virtual void particles_set_process_material(RID p_particles, RID p_material) override;
|
||||
virtual RID particles_get_process_material(RID p_particles) const override;
|
||||
virtual void particles_set_fixed_fps(RID p_particles, int p_fps) override;
|
||||
virtual void particles_set_interpolate(RID p_particles, bool p_enable) override;
|
||||
virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) override;
|
||||
virtual void particles_set_subemitter(RID p_particles, RID p_subemitter_particles) override;
|
||||
virtual void particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) override;
|
||||
virtual void particles_set_collision_base_size(RID p_particles, real_t p_size) override;
|
||||
|
||||
virtual void particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) override;
|
||||
virtual void particles_set_seed(RID p_particles, uint32_t p_seed) override;
|
||||
|
||||
virtual void particles_set_trails(RID p_particles, bool p_enable, double p_length) override;
|
||||
virtual void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform3D> &p_bind_poses) override;
|
||||
|
||||
virtual void particles_restart(RID p_particles) override;
|
||||
|
||||
virtual void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) override;
|
||||
|
||||
virtual void particles_set_draw_passes(RID p_particles, int p_count) override;
|
||||
virtual void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) override;
|
||||
|
||||
virtual void particles_request_process(RID p_particles) override;
|
||||
virtual AABB particles_get_current_aabb(RID p_particles) override;
|
||||
virtual AABB particles_get_aabb(RID p_particles) const override;
|
||||
|
||||
virtual void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) override;
|
||||
virtual void particles_set_emitter_velocity(RID p_particles, const Vector3 &p_velocity) override;
|
||||
virtual void particles_set_interp_to_end(RID p_particles, float p_interp) override;
|
||||
|
||||
virtual bool particles_get_emitting(RID p_particles) override;
|
||||
virtual int particles_get_draw_passes(RID p_particles) const override;
|
||||
virtual RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const override;
|
||||
|
||||
virtual void particles_add_collision(RID p_particles, RID p_instance) override;
|
||||
virtual void particles_remove_collision(RID p_particles, RID p_instance) override;
|
||||
|
||||
void particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, GLuint p_texture);
|
||||
|
||||
virtual void update_particles() override;
|
||||
virtual bool particles_is_inactive(RID p_particles) const override;
|
||||
|
||||
_FORCE_INLINE_ RS::ParticlesMode particles_get_mode(RID p_particles) {
|
||||
Particles *particles = particles_owner.get_or_null(p_particles);
|
||||
ERR_FAIL_NULL_V(particles, RS::PARTICLES_MODE_2D);
|
||||
return particles->mode;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t particles_get_amount(RID p_particles) {
|
||||
Particles *particles = particles_owner.get_or_null(p_particles);
|
||||
ERR_FAIL_NULL_V(particles, 0);
|
||||
|
||||
return particles->amount;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ GLuint particles_get_gl_buffer(RID p_particles) {
|
||||
Particles *particles = particles_owner.get_or_null(p_particles);
|
||||
|
||||
if ((particles->draw_order == RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH || particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME) && particles->sort_buffer_filled) {
|
||||
return particles->sort_buffer;
|
||||
}
|
||||
return particles->back_instance_buffer;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool particles_has_collision(RID p_particles) {
|
||||
Particles *particles = particles_owner.get_or_null(p_particles);
|
||||
ERR_FAIL_NULL_V(particles, false);
|
||||
|
||||
return particles->has_collision_cache;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t particles_is_using_local_coords(RID p_particles) {
|
||||
Particles *particles = particles_owner.get_or_null(p_particles);
|
||||
ERR_FAIL_NULL_V(particles, false);
|
||||
|
||||
return particles->use_local_coords;
|
||||
}
|
||||
|
||||
Dependency *particles_get_dependency(RID p_particles) const;
|
||||
|
||||
/* PARTICLES COLLISION */
|
||||
bool owns_particles_collision(RID p_rid) { return particles_collision_owner.owns(p_rid); }
|
||||
|
||||
virtual RID particles_collision_allocate() override;
|
||||
virtual void particles_collision_initialize(RID p_rid) override;
|
||||
virtual void particles_collision_free(RID p_rid) override;
|
||||
|
||||
virtual void particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) override;
|
||||
virtual void particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) override;
|
||||
virtual void particles_collision_set_sphere_radius(RID p_particles_collision, real_t p_radius) override;
|
||||
virtual void particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) override;
|
||||
virtual void particles_collision_set_attractor_strength(RID p_particles_collision, real_t p_strength) override;
|
||||
virtual void particles_collision_set_attractor_directionality(RID p_particles_collision, real_t p_directionality) override;
|
||||
virtual void particles_collision_set_attractor_attenuation(RID p_particles_collision, real_t p_curve) override;
|
||||
virtual void particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) override;
|
||||
virtual void particles_collision_height_field_update(RID p_particles_collision) override;
|
||||
virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) override;
|
||||
virtual AABB particles_collision_get_aabb(RID p_particles_collision) const override;
|
||||
Vector3 particles_collision_get_extents(RID p_particles_collision) const;
|
||||
virtual bool particles_collision_is_heightfield(RID p_particles_collision) const override;
|
||||
GLuint particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const;
|
||||
virtual uint32_t particles_collision_get_height_field_mask(RID p_particles_collision) const override;
|
||||
virtual void particles_collision_set_height_field_mask(RID p_particles_collision, uint32_t p_heightfield_mask) override;
|
||||
virtual uint32_t particles_collision_get_cull_mask(RID p_particles_collision) const override;
|
||||
|
||||
_FORCE_INLINE_ Size2i particles_collision_get_heightfield_size(RID p_particles_collision) const {
|
||||
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
|
||||
ERR_FAIL_NULL_V(particles_collision, Size2i());
|
||||
ERR_FAIL_COND_V(particles_collision->type != RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE, Size2i());
|
||||
|
||||
return particles_collision->heightfield_fb_size;
|
||||
}
|
||||
|
||||
Dependency *particles_collision_get_dependency(RID p_particles) const;
|
||||
|
||||
/* PARTICLES COLLISION INSTANCE*/
|
||||
bool owns_particles_collision_instance(RID p_rid) { return particles_collision_instance_owner.owns(p_rid); }
|
||||
|
||||
virtual RID particles_collision_instance_create(RID p_collision) override;
|
||||
virtual void particles_collision_instance_free(RID p_rid) override;
|
||||
virtual void particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) override;
|
||||
virtual void particles_collision_instance_set_active(RID p_collision_instance, bool p_active) override;
|
||||
};
|
||||
|
||||
} // namespace GLES3
|
||||
|
||||
#endif // GLES3_ENABLED
|
675
drivers/gles3/storage/render_scene_buffers_gles3.cpp
Normal file
675
drivers/gles3/storage/render_scene_buffers_gles3.cpp
Normal file
@@ -0,0 +1,675 @@
|
||||
/**************************************************************************/
|
||||
/* render_scene_buffers_gles3.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "render_scene_buffers_gles3.h"
|
||||
#include "config.h"
|
||||
#include "texture_storage.h"
|
||||
#include "utilities.h"
|
||||
|
||||
#ifdef ANDROID_ENABLED
|
||||
#define glFramebufferTextureMultiviewOVR GLES3::Config::get_singleton()->eglFramebufferTextureMultiviewOVR
|
||||
#define glTexStorage3DMultisample GLES3::Config::get_singleton()->eglTexStorage3DMultisample
|
||||
#define glFramebufferTexture2DMultisampleEXT GLES3::Config::get_singleton()->eglFramebufferTexture2DMultisampleEXT
|
||||
#define glFramebufferTextureMultisampleMultiviewOVR GLES3::Config::get_singleton()->eglFramebufferTextureMultisampleMultiviewOVR
|
||||
#endif // ANDROID_ENABLED
|
||||
|
||||
// Will only be defined if GLES 3.2 headers are included
|
||||
#ifndef GL_TEXTURE_2D_MULTISAMPLE_ARRAY
|
||||
#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102
|
||||
#endif
|
||||
|
||||
RenderSceneBuffersGLES3::RenderSceneBuffersGLES3() {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
glow.levels[i].color = 0;
|
||||
glow.levels[i].fbo = 0;
|
||||
}
|
||||
}
|
||||
|
||||
RenderSceneBuffersGLES3::~RenderSceneBuffersGLES3() {
|
||||
free_render_buffer_data();
|
||||
}
|
||||
|
||||
void RenderSceneBuffersGLES3::_rt_attach_textures(GLuint p_color, GLuint p_depth, GLsizei p_samples, uint32_t p_view_count, bool p_depth_has_stencil) {
|
||||
if (p_view_count > 1) {
|
||||
if (p_samples > 1) {
|
||||
#if defined(ANDROID_ENABLED) || defined(WEB_ENABLED)
|
||||
glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, p_color, 0, p_samples, 0, p_view_count);
|
||||
glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, p_depth_has_stencil ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT, p_depth, 0, p_samples, 0, p_view_count);
|
||||
#else
|
||||
ERR_PRINT_ONCE("Multiview MSAA isn't supported on this platform.");
|
||||
#endif
|
||||
} else {
|
||||
#ifndef IOS_ENABLED
|
||||
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, p_color, 0, 0, p_view_count);
|
||||
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, p_depth_has_stencil ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT, p_depth, 0, 0, p_view_count);
|
||||
#else
|
||||
ERR_PRINT_ONCE("Multiview isn't supported on this platform.");
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
if (p_samples > 1) {
|
||||
#ifdef ANDROID_ENABLED
|
||||
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_color, 0, p_samples);
|
||||
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, p_depth_has_stencil ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, p_depth, 0, p_samples);
|
||||
#else
|
||||
ERR_PRINT_ONCE("MSAA via EXT_multisampled_render_to_texture isn't supported on this platform.");
|
||||
#endif
|
||||
} else {
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_color, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, p_depth_has_stencil ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, p_depth, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GLuint RenderSceneBuffersGLES3::_rt_get_cached_fbo(GLuint p_color, GLuint p_depth, GLsizei p_samples, uint32_t p_view_count) {
|
||||
FBDEF new_fbo;
|
||||
|
||||
#if defined(ANDROID_ENABLED) || defined(WEB_ENABLED)
|
||||
// There shouldn't be more then 3 entries in this...
|
||||
for (const FBDEF &cached_fbo : msaa3d.cached_fbos) {
|
||||
if (cached_fbo.color == p_color && cached_fbo.depth == p_depth) {
|
||||
return cached_fbo.fbo;
|
||||
}
|
||||
}
|
||||
|
||||
new_fbo.color = p_color;
|
||||
new_fbo.depth = p_depth;
|
||||
|
||||
glGenFramebuffers(1, &new_fbo.fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, new_fbo.fbo);
|
||||
|
||||
_rt_attach_textures(p_color, p_depth, p_samples, p_view_count, true);
|
||||
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||
WARN_PRINT("Could not create 3D MSAA framebuffer, status: " + GLES3::TextureStorage::get_singleton()->get_framebuffer_error(status));
|
||||
|
||||
glDeleteFramebuffers(1, &new_fbo.fbo);
|
||||
|
||||
new_fbo.fbo = 0;
|
||||
} else {
|
||||
// cache it!
|
||||
msaa3d.cached_fbos.push_back(new_fbo);
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
|
||||
#endif
|
||||
|
||||
return new_fbo.fbo;
|
||||
}
|
||||
|
||||
void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p_config) {
|
||||
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
|
||||
GLES3::Config *config = GLES3::Config::get_singleton();
|
||||
|
||||
free_render_buffer_data();
|
||||
|
||||
internal_size = p_config->get_internal_size();
|
||||
target_size = p_config->get_target_size();
|
||||
scaling_3d_mode = p_config->get_scaling_3d_mode();
|
||||
//fsr_sharpness = p_config->get_fsr_sharpness();
|
||||
//texture_mipmap_bias = p_config->get_texture_mipmap_bias();
|
||||
//anisotropic_filtering_level = p_config->get_anisotropic_filtering_level();
|
||||
render_target = p_config->get_render_target();
|
||||
msaa3d.mode = p_config->get_msaa_3d();
|
||||
//screen_space_aa = p_config->get_screen_space_aa();
|
||||
//use_debanding = p_config->get_use_debanding();
|
||||
view_count = config->multiview_supported ? p_config->get_view_count() : 1;
|
||||
|
||||
bool use_multiview = view_count > 1;
|
||||
|
||||
// Get color format data from our render target so we match those
|
||||
if (render_target.is_valid()) {
|
||||
color_internal_format = texture_storage->render_target_get_color_internal_format(render_target);
|
||||
color_format = texture_storage->render_target_get_color_format(render_target);
|
||||
color_type = texture_storage->render_target_get_color_type(render_target);
|
||||
color_format_size = texture_storage->render_target_get_color_format_size(render_target);
|
||||
} else {
|
||||
// reflection probe? or error?
|
||||
color_internal_format = GL_RGBA8;
|
||||
color_format = GL_RGBA;
|
||||
color_type = GL_UNSIGNED_BYTE;
|
||||
color_format_size = 4;
|
||||
}
|
||||
|
||||
// Check our scaling mode
|
||||
if (scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_OFF && internal_size.x == 0 && internal_size.y == 0) {
|
||||
// Disable, no size set.
|
||||
scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF;
|
||||
} else if (scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_OFF && internal_size == target_size) {
|
||||
// If size matches, we won't use scaling.
|
||||
scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF;
|
||||
} else if (scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_OFF && scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_BILINEAR) {
|
||||
// We only support bilinear scaling atm.
|
||||
WARN_PRINT_ONCE("GLES only supports bilinear scaling.");
|
||||
scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_BILINEAR;
|
||||
}
|
||||
|
||||
// Check if we support MSAA.
|
||||
if (msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED && internal_size.x == 0 && internal_size.y == 0) {
|
||||
// Disable, no size set.
|
||||
msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
|
||||
} else if (!use_multiview && msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED && !config->msaa_supported && !config->rt_msaa_supported) {
|
||||
WARN_PRINT_ONCE("MSAA is not supported on this device.");
|
||||
msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
|
||||
} else if (use_multiview && msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED && !config->msaa_multiview_supported && !config->rt_msaa_multiview_supported) {
|
||||
WARN_PRINT_ONCE("Multiview MSAA is not supported on this device.");
|
||||
msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
|
||||
}
|
||||
|
||||
// We don't create our buffers right away because post effects can be made active at any time and change our buffer configuration.
|
||||
}
|
||||
|
||||
void RenderSceneBuffersGLES3::_check_render_buffers() {
|
||||
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
|
||||
GLES3::Config *config = GLES3::Config::get_singleton();
|
||||
|
||||
ERR_FAIL_COND(view_count == 0);
|
||||
|
||||
bool use_internal_buffer = scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_OFF || apply_color_adjustments_in_post;
|
||||
GLenum depth_format = GL_DEPTH24_STENCIL8;
|
||||
uint32_t depth_format_size = 4;
|
||||
bool use_multiview = view_count > 1;
|
||||
|
||||
if ((!use_internal_buffer || internal3d.color != 0) && (msaa3d.mode == RS::VIEWPORT_MSAA_DISABLED || msaa3d.color != 0)) {
|
||||
// already setup!
|
||||
return;
|
||||
}
|
||||
|
||||
if (use_internal_buffer && internal3d.color == 0) {
|
||||
// Setup our internal buffer.
|
||||
GLenum texture_target = use_multiview ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
|
||||
|
||||
// Create our color buffer.
|
||||
glGenTextures(1, &internal3d.color);
|
||||
glBindTexture(texture_target, internal3d.color);
|
||||
|
||||
if (use_multiview) {
|
||||
glTexImage3D(texture_target, 0, color_internal_format, internal_size.x, internal_size.y, view_count, 0, color_format, color_type, nullptr);
|
||||
} else {
|
||||
glTexImage2D(texture_target, 0, color_internal_format, internal_size.x, internal_size.y, 0, color_format, color_type, nullptr);
|
||||
}
|
||||
|
||||
glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
GLES3::Utilities::get_singleton()->texture_allocated_data(internal3d.color, internal_size.x * internal_size.y * view_count * color_format_size, "3D color texture");
|
||||
|
||||
// Create our depth buffer.
|
||||
glGenTextures(1, &internal3d.depth);
|
||||
glBindTexture(texture_target, internal3d.depth);
|
||||
|
||||
if (use_multiview) {
|
||||
glTexImage3D(texture_target, 0, depth_format, internal_size.x, internal_size.y, view_count, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr);
|
||||
} else {
|
||||
glTexImage2D(texture_target, 0, depth_format, internal_size.x, internal_size.y, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr);
|
||||
}
|
||||
|
||||
glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
GLES3::Utilities::get_singleton()->texture_allocated_data(internal3d.depth, internal_size.x * internal_size.y * view_count * depth_format_size, "3D depth texture");
|
||||
|
||||
// Create our internal 3D FBO.
|
||||
// Note that if MSAA is used and our rt_msaa_* extensions are available, this is only used for blitting and effects.
|
||||
glGenFramebuffers(1, &internal3d.fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, internal3d.fbo);
|
||||
|
||||
#ifndef IOS_ENABLED
|
||||
if (use_multiview) {
|
||||
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, internal3d.color, 0, 0, view_count);
|
||||
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, internal3d.depth, 0, 0, view_count);
|
||||
} else {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture_target, internal3d.color, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, texture_target, internal3d.depth, 0);
|
||||
}
|
||||
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||
_clear_intermediate_buffers();
|
||||
WARN_PRINT("Could not create 3D internal buffers, status: " + texture_storage->get_framebuffer_error(status));
|
||||
}
|
||||
|
||||
glBindTexture(texture_target, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
|
||||
}
|
||||
|
||||
if (msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED && msaa3d.color == 0) {
|
||||
// Setup MSAA.
|
||||
const GLsizei samples[] = { 1, 2, 4, 8 };
|
||||
msaa3d.samples = samples[msaa3d.mode];
|
||||
|
||||
// Constrain by limits of OpenGL driver.
|
||||
if (msaa3d.samples > config->msaa_max_samples) {
|
||||
msaa3d.samples = config->msaa_max_samples;
|
||||
}
|
||||
|
||||
if (!use_multiview && !config->rt_msaa_supported) {
|
||||
// Render to texture extensions not supported? fall back to MSAA framebuffer through GL_EXT_framebuffer_multisample.
|
||||
// Note, if 2D MSAA matches 3D MSAA and we're not scaling, it would be ideal if we reuse our 2D MSAA buffer here.
|
||||
// We can't however because we don't trigger a change in configuration if 2D MSAA changes.
|
||||
// We'll accept the overhead in this situation.
|
||||
|
||||
msaa3d.needs_resolve = true;
|
||||
msaa3d.check_fbo_cache = false;
|
||||
|
||||
// Create our color buffer.
|
||||
glGenRenderbuffers(1, &msaa3d.color);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, msaa3d.color);
|
||||
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa3d.samples, color_internal_format, internal_size.x, internal_size.y);
|
||||
GLES3::Utilities::get_singleton()->render_buffer_allocated_data(msaa3d.color, internal_size.x * internal_size.y * view_count * 4 * msaa3d.samples, "MSAA 3D color render buffer");
|
||||
|
||||
// Create our depth buffer.
|
||||
glGenRenderbuffers(1, &msaa3d.depth);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, msaa3d.depth);
|
||||
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa3d.samples, depth_format, internal_size.x, internal_size.y);
|
||||
GLES3::Utilities::get_singleton()->render_buffer_allocated_data(msaa3d.depth, internal_size.x * internal_size.y * view_count * depth_format_size * msaa3d.samples, "MSAA 3D depth render buffer");
|
||||
|
||||
// Create our MSAA 3D FBO.
|
||||
glGenFramebuffers(1, &msaa3d.fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, msaa3d.fbo);
|
||||
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, msaa3d.color);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, msaa3d.depth);
|
||||
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||
_clear_msaa3d_buffers();
|
||||
msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
|
||||
WARN_PRINT("Could not create 3D MSAA buffers, status: " + texture_storage->get_framebuffer_error(status));
|
||||
}
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
|
||||
#if !defined(IOS_ENABLED) && !defined(WEB_ENABLED)
|
||||
} else if (use_multiview && !config->rt_msaa_multiview_supported) {
|
||||
// Render to texture extensions not supported? fall back to MSAA textures through GL_EXT_multiview_texture_multisample.
|
||||
msaa3d.needs_resolve = true;
|
||||
msaa3d.check_fbo_cache = false;
|
||||
|
||||
// Create our color buffer.
|
||||
glGenTextures(1, &msaa3d.color);
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, msaa3d.color);
|
||||
|
||||
#ifdef ANDROID_ENABLED
|
||||
glTexStorage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, msaa3d.samples, color_internal_format, internal_size.x, internal_size.y, view_count, GL_TRUE);
|
||||
#else
|
||||
glTexImage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, msaa3d.samples, color_internal_format, internal_size.x, internal_size.y, view_count, GL_TRUE);
|
||||
#endif
|
||||
|
||||
GLES3::Utilities::get_singleton()->texture_allocated_data(msaa3d.color, internal_size.x * internal_size.y * view_count * color_format_size * msaa3d.samples, "MSAA 3D color texture");
|
||||
|
||||
// Create our depth buffer.
|
||||
glGenTextures(1, &msaa3d.depth);
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, msaa3d.depth);
|
||||
|
||||
#ifdef ANDROID_ENABLED
|
||||
glTexStorage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, msaa3d.samples, depth_format, internal_size.x, internal_size.y, view_count, GL_TRUE);
|
||||
#else
|
||||
glTexImage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, msaa3d.samples, depth_format, internal_size.x, internal_size.y, view_count, GL_TRUE);
|
||||
#endif
|
||||
|
||||
GLES3::Utilities::get_singleton()->texture_allocated_data(msaa3d.depth, internal_size.x * internal_size.y * view_count * depth_format_size * msaa3d.samples, "MSAA 3D depth texture");
|
||||
|
||||
// Create our MSAA 3D FBO.
|
||||
glGenFramebuffers(1, &msaa3d.fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, msaa3d.fbo);
|
||||
|
||||
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, msaa3d.color, 0, 0, view_count);
|
||||
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, msaa3d.depth, 0, 0, view_count);
|
||||
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||
_clear_msaa3d_buffers();
|
||||
msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
|
||||
WARN_PRINT("Could not create 3D MSAA buffers, status: " + texture_storage->get_framebuffer_error(status));
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
|
||||
#endif
|
||||
#if defined(ANDROID_ENABLED) || defined(WEB_ENABLED) // Only supported on OpenGLES!
|
||||
} else if (!use_internal_buffer) {
|
||||
// We are going to render directly into our render target textures,
|
||||
// these can change from frame to frame as we cycle through swapchains,
|
||||
// hence we'll use our FBO cache here.
|
||||
msaa3d.needs_resolve = false;
|
||||
msaa3d.check_fbo_cache = true;
|
||||
} else if (use_internal_buffer) {
|
||||
// We can combine MSAA and scaling/effects.
|
||||
msaa3d.needs_resolve = false;
|
||||
msaa3d.check_fbo_cache = false;
|
||||
|
||||
// We render to our internal textures, MSAA is only done in tile memory only.
|
||||
// On mobile this means MSAA never leaves tile memory = efficiency!
|
||||
glGenFramebuffers(1, &msaa3d.fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, msaa3d.fbo);
|
||||
|
||||
_rt_attach_textures(internal3d.color, internal3d.depth, msaa3d.samples, view_count, true);
|
||||
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||
_clear_msaa3d_buffers();
|
||||
msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
|
||||
WARN_PRINT("Could not create 3D MSAA framebuffer, status: " + texture_storage->get_framebuffer_error(status));
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
|
||||
#endif
|
||||
} else {
|
||||
// HUH? how did we get here?
|
||||
WARN_PRINT_ONCE("MSAA is not supported on this device.");
|
||||
msaa3d.mode = RS::VIEWPORT_MSAA_DISABLED;
|
||||
msaa3d.samples = 1;
|
||||
msaa3d.check_fbo_cache = false;
|
||||
}
|
||||
} else {
|
||||
msaa3d.samples = 1;
|
||||
msaa3d.check_fbo_cache = false;
|
||||
}
|
||||
}
|
||||
|
||||
void RenderSceneBuffersGLES3::configure_for_probe(Size2i p_size) {
|
||||
internal_size = p_size;
|
||||
target_size = p_size;
|
||||
scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF;
|
||||
view_count = 1;
|
||||
}
|
||||
|
||||
void RenderSceneBuffersGLES3::_clear_msaa3d_buffers() {
|
||||
for (const FBDEF &cached_fbo : msaa3d.cached_fbos) {
|
||||
GLuint fbo = cached_fbo.fbo;
|
||||
glDeleteFramebuffers(1, &fbo);
|
||||
}
|
||||
msaa3d.cached_fbos.clear();
|
||||
|
||||
if (msaa3d.fbo) {
|
||||
glDeleteFramebuffers(1, &msaa3d.fbo);
|
||||
msaa3d.fbo = 0;
|
||||
}
|
||||
|
||||
if (msaa3d.color != 0) {
|
||||
if (view_count == 1) {
|
||||
GLES3::Utilities::get_singleton()->render_buffer_free_data(msaa3d.color);
|
||||
} else {
|
||||
GLES3::Utilities::get_singleton()->texture_free_data(msaa3d.color);
|
||||
}
|
||||
msaa3d.color = 0;
|
||||
}
|
||||
|
||||
if (msaa3d.depth != 0) {
|
||||
if (view_count == 1) {
|
||||
GLES3::Utilities::get_singleton()->render_buffer_free_data(msaa3d.depth);
|
||||
} else {
|
||||
GLES3::Utilities::get_singleton()->texture_free_data(msaa3d.depth);
|
||||
}
|
||||
msaa3d.depth = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void RenderSceneBuffersGLES3::_clear_intermediate_buffers() {
|
||||
if (internal3d.fbo) {
|
||||
glDeleteFramebuffers(1, &internal3d.fbo);
|
||||
internal3d.fbo = 0;
|
||||
}
|
||||
|
||||
if (internal3d.color != 0) {
|
||||
GLES3::Utilities::get_singleton()->texture_free_data(internal3d.color);
|
||||
internal3d.color = 0;
|
||||
}
|
||||
|
||||
if (internal3d.depth != 0) {
|
||||
GLES3::Utilities::get_singleton()->texture_free_data(internal3d.depth);
|
||||
internal3d.depth = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void RenderSceneBuffersGLES3::check_backbuffer(bool p_need_color, bool p_need_depth) {
|
||||
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
|
||||
|
||||
// Setup our back buffer
|
||||
|
||||
if (backbuffer3d.fbo == 0) {
|
||||
glGenFramebuffers(1, &backbuffer3d.fbo);
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, backbuffer3d.fbo);
|
||||
|
||||
bool use_multiview = view_count > 1 && GLES3::Config::get_singleton()->multiview_supported;
|
||||
GLenum texture_target = use_multiview ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
|
||||
GLenum depth_format = GL_DEPTH24_STENCIL8;
|
||||
uint32_t depth_format_size = 4;
|
||||
|
||||
if (backbuffer3d.color == 0 && p_need_color) {
|
||||
glGenTextures(1, &backbuffer3d.color);
|
||||
glBindTexture(texture_target, backbuffer3d.color);
|
||||
|
||||
if (use_multiview) {
|
||||
glTexImage3D(texture_target, 0, color_internal_format, internal_size.x, internal_size.y, view_count, 0, color_format, color_type, nullptr);
|
||||
} else {
|
||||
glTexImage2D(texture_target, 0, color_internal_format, internal_size.x, internal_size.y, 0, color_format, color_type, nullptr);
|
||||
}
|
||||
|
||||
glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
GLES3::Utilities::get_singleton()->texture_allocated_data(backbuffer3d.color, internal_size.x * internal_size.y * view_count * color_format_size, "3D Back buffer color texture");
|
||||
|
||||
#ifndef IOS_ENABLED
|
||||
if (use_multiview) {
|
||||
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, backbuffer3d.color, 0, 0, view_count);
|
||||
} else {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture_target, backbuffer3d.color, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (backbuffer3d.depth == 0 && p_need_depth) {
|
||||
glGenTextures(1, &backbuffer3d.depth);
|
||||
glBindTexture(texture_target, backbuffer3d.depth);
|
||||
|
||||
if (use_multiview) {
|
||||
glTexImage3D(texture_target, 0, depth_format, internal_size.x, internal_size.y, view_count, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT, nullptr);
|
||||
} else {
|
||||
glTexImage2D(texture_target, 0, depth_format, internal_size.x, internal_size.y, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT, nullptr);
|
||||
}
|
||||
|
||||
glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
GLES3::Utilities::get_singleton()->texture_allocated_data(backbuffer3d.depth, internal_size.x * internal_size.y * view_count * depth_format_size, "3D back buffer depth texture");
|
||||
|
||||
#ifndef IOS_ENABLED
|
||||
if (use_multiview) {
|
||||
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, backbuffer3d.depth, 0, 0, view_count);
|
||||
} else {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, texture_target, backbuffer3d.depth, 0);
|
||||
}
|
||||
}
|
||||
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||
_clear_back_buffers();
|
||||
WARN_PRINT("Could not create 3D back buffers, status: " + texture_storage->get_framebuffer_error(status));
|
||||
}
|
||||
|
||||
glBindTexture(texture_target, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
|
||||
}
|
||||
|
||||
void RenderSceneBuffersGLES3::_clear_back_buffers() {
|
||||
if (backbuffer3d.fbo) {
|
||||
glDeleteFramebuffers(1, &backbuffer3d.fbo);
|
||||
backbuffer3d.fbo = 0;
|
||||
}
|
||||
|
||||
if (backbuffer3d.color != 0) {
|
||||
GLES3::Utilities::get_singleton()->texture_free_data(backbuffer3d.color);
|
||||
backbuffer3d.color = 0;
|
||||
}
|
||||
|
||||
if (backbuffer3d.depth != 0) {
|
||||
GLES3::Utilities::get_singleton()->texture_free_data(backbuffer3d.depth);
|
||||
backbuffer3d.depth = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void RenderSceneBuffersGLES3::set_apply_color_adjustments_in_post(bool p_apply_in_post) {
|
||||
apply_color_adjustments_in_post = p_apply_in_post;
|
||||
}
|
||||
|
||||
void RenderSceneBuffersGLES3::check_glow_buffers() {
|
||||
if (glow.levels[0].color != 0) {
|
||||
// already have these setup..
|
||||
return;
|
||||
}
|
||||
|
||||
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
|
||||
Size2i level_size = internal_size;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
level_size = Size2i(level_size.x >> 1, level_size.y >> 1).maxi(4);
|
||||
|
||||
glow.levels[i].size = level_size;
|
||||
|
||||
// Create our texture
|
||||
glGenTextures(1, &glow.levels[i].color);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, glow.levels[i].color);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, level_size.x, level_size.y, 0, color_format, color_type, nullptr);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
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_BASE_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
|
||||
GLES3::Utilities::get_singleton()->texture_allocated_data(glow.levels[i].color, level_size.x * level_size.y * color_format_size, String("Glow buffer ") + String::num_int64(i));
|
||||
|
||||
// Create our FBO
|
||||
glGenFramebuffers(1, &glow.levels[i].fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, glow.levels[i].fbo);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glow.levels[i].color, 0);
|
||||
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||
WARN_PRINT("Could not create glow buffers, status: " + texture_storage->get_framebuffer_error(status));
|
||||
_clear_glow_buffers();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
|
||||
}
|
||||
|
||||
void RenderSceneBuffersGLES3::_clear_glow_buffers() {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (glow.levels[i].fbo != 0) {
|
||||
glDeleteFramebuffers(1, &glow.levels[i].fbo);
|
||||
glow.levels[i].fbo = 0;
|
||||
}
|
||||
|
||||
if (glow.levels[i].color != 0) {
|
||||
GLES3::Utilities::get_singleton()->texture_free_data(glow.levels[i].color);
|
||||
glow.levels[i].color = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderSceneBuffersGLES3::free_render_buffer_data() {
|
||||
_clear_msaa3d_buffers();
|
||||
_clear_intermediate_buffers();
|
||||
_clear_back_buffers();
|
||||
_clear_glow_buffers();
|
||||
}
|
||||
|
||||
GLuint RenderSceneBuffersGLES3::get_render_fbo() {
|
||||
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
|
||||
GLuint rt_fbo = 0;
|
||||
|
||||
_check_render_buffers();
|
||||
|
||||
if (msaa3d.check_fbo_cache) {
|
||||
GLuint color = texture_storage->render_target_get_color(render_target);
|
||||
GLuint depth = texture_storage->render_target_get_depth(render_target);
|
||||
|
||||
rt_fbo = _rt_get_cached_fbo(color, depth, msaa3d.samples, view_count);
|
||||
if (rt_fbo == 0) {
|
||||
// Somehow couldn't obtain this? Just render without MSAA.
|
||||
rt_fbo = texture_storage->render_target_get_fbo(render_target);
|
||||
}
|
||||
} else if (msaa3d.fbo != 0) {
|
||||
// We have an MSAA fbo, render to our MSAA buffer
|
||||
return msaa3d.fbo;
|
||||
} else if (internal3d.fbo != 0) {
|
||||
// We have an internal buffer, render to our internal buffer!
|
||||
return internal3d.fbo;
|
||||
} else {
|
||||
rt_fbo = texture_storage->render_target_get_fbo(render_target);
|
||||
}
|
||||
|
||||
if (texture_storage->render_target_is_reattach_textures(render_target)) {
|
||||
GLuint color = texture_storage->render_target_get_color(render_target);
|
||||
GLuint depth = texture_storage->render_target_get_depth(render_target);
|
||||
bool depth_has_stencil = texture_storage->render_target_get_depth_has_stencil(render_target);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, rt_fbo);
|
||||
_rt_attach_textures(color, depth, msaa3d.samples, view_count, depth_has_stencil);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, texture_storage->system_fbo);
|
||||
}
|
||||
|
||||
return rt_fbo;
|
||||
}
|
||||
|
||||
#endif // GLES3_ENABLED
|
165
drivers/gles3/storage/render_scene_buffers_gles3.h
Normal file
165
drivers/gles3/storage/render_scene_buffers_gles3.h
Normal file
@@ -0,0 +1,165 @@
|
||||
/**************************************************************************/
|
||||
/* render_scene_buffers_gles3.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef GLES3_ENABLED
|
||||
|
||||
#include "drivers/gles3/effects/glow.h"
|
||||
#include "servers/rendering/storage/render_scene_buffers.h"
|
||||
|
||||
#include "platform_gl.h"
|
||||
|
||||
class RenderSceneBuffersGLES3 : public RenderSceneBuffers {
|
||||
GDCLASS(RenderSceneBuffersGLES3, RenderSceneBuffers);
|
||||
|
||||
public:
|
||||
Size2i internal_size; // Size of the buffer we render 3D content to.
|
||||
Size2i target_size; // Size of our output buffer (render target).
|
||||
RS::ViewportScaling3DMode scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF;
|
||||
//float fsr_sharpness = 0.2f;
|
||||
//RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
|
||||
//bool use_taa = false;
|
||||
//bool use_debanding = false;
|
||||
uint32_t view_count = 1;
|
||||
bool apply_color_adjustments_in_post = false;
|
||||
|
||||
RID render_target;
|
||||
|
||||
// Color format details from our render target
|
||||
GLuint color_internal_format = GL_RGBA8;
|
||||
GLuint color_format = GL_RGBA;
|
||||
GLuint color_type = GL_UNSIGNED_BYTE;
|
||||
uint32_t color_format_size = 4;
|
||||
|
||||
struct FBDEF {
|
||||
GLuint color = 0;
|
||||
GLuint depth = 0;
|
||||
GLuint fbo = 0;
|
||||
};
|
||||
|
||||
struct RTMSAA3D {
|
||||
RS::ViewportMSAA mode = RS::VIEWPORT_MSAA_DISABLED;
|
||||
bool needs_resolve = false;
|
||||
GLsizei samples = 1;
|
||||
GLuint color = 0;
|
||||
GLuint depth = 0;
|
||||
GLuint fbo = 0;
|
||||
|
||||
bool check_fbo_cache = false;
|
||||
Vector<FBDEF> cached_fbos;
|
||||
} msaa3d; // MSAA buffers used to render 3D
|
||||
|
||||
FBDEF internal3d; // buffers used to either render 3D (scaled/post) or to resolve MSAA into
|
||||
|
||||
FBDEF backbuffer3d; // our back buffer
|
||||
|
||||
// Buffers for our glow implementation
|
||||
struct GLOW {
|
||||
GLES3::Glow::GLOWLEVEL levels[4];
|
||||
} glow;
|
||||
|
||||
private:
|
||||
void _check_render_buffers();
|
||||
void _clear_msaa3d_buffers();
|
||||
void _clear_intermediate_buffers();
|
||||
void _clear_back_buffers();
|
||||
void _clear_glow_buffers();
|
||||
|
||||
void _rt_attach_textures(GLuint p_color, GLuint p_depth, GLsizei p_samples, uint32_t p_view_count, bool p_depth_has_stencil);
|
||||
GLuint _rt_get_cached_fbo(GLuint p_color, GLuint p_depth, GLsizei p_samples, uint32_t p_view_count);
|
||||
|
||||
public:
|
||||
RenderSceneBuffersGLES3();
|
||||
virtual ~RenderSceneBuffersGLES3();
|
||||
virtual void configure(const RenderSceneBuffersConfiguration *p_config) override;
|
||||
void configure_for_probe(Size2i p_size);
|
||||
|
||||
virtual void set_anisotropic_filtering_level(RS::ViewportAnisotropicFiltering p_anisotropic_filtering_level) override {}
|
||||
virtual void set_fsr_sharpness(float p_fsr_sharpness) override {}
|
||||
virtual void set_texture_mipmap_bias(float p_texture_mipmap_bias) override {}
|
||||
virtual void set_use_debanding(bool p_use_debanding) override {}
|
||||
void set_apply_color_adjustments_in_post(bool p_apply_in_post);
|
||||
|
||||
void free_render_buffer_data();
|
||||
|
||||
void check_backbuffer(bool p_need_color, bool p_need_depth); // Check if we need to initialize our backbuffer.
|
||||
void check_glow_buffers(); // Check if we need to initialize our glow buffers.
|
||||
|
||||
GLuint get_render_fbo();
|
||||
GLuint get_msaa3d_fbo() {
|
||||
_check_render_buffers();
|
||||
return msaa3d.fbo;
|
||||
}
|
||||
GLuint get_msaa3d_color() {
|
||||
_check_render_buffers();
|
||||
return msaa3d.color;
|
||||
}
|
||||
GLuint get_msaa3d_depth() {
|
||||
_check_render_buffers();
|
||||
return msaa3d.depth;
|
||||
}
|
||||
bool get_msaa_needs_resolve() {
|
||||
_check_render_buffers();
|
||||
return msaa3d.needs_resolve;
|
||||
}
|
||||
GLuint get_internal_fbo() {
|
||||
_check_render_buffers();
|
||||
return internal3d.fbo;
|
||||
}
|
||||
GLuint get_internal_color() {
|
||||
_check_render_buffers();
|
||||
return internal3d.color;
|
||||
}
|
||||
GLuint get_internal_depth() {
|
||||
_check_render_buffers();
|
||||
return internal3d.depth;
|
||||
}
|
||||
GLuint get_backbuffer_fbo() const { return backbuffer3d.fbo; }
|
||||
GLuint get_backbuffer() const { return backbuffer3d.color; }
|
||||
GLuint get_backbuffer_depth() const { return backbuffer3d.depth; }
|
||||
|
||||
const GLES3::Glow::GLOWLEVEL *get_glow_buffers() const { return &glow.levels[0]; }
|
||||
|
||||
// Getters
|
||||
|
||||
_FORCE_INLINE_ RID get_render_target() const { return render_target; }
|
||||
_FORCE_INLINE_ uint32_t get_view_count() const { return view_count; }
|
||||
_FORCE_INLINE_ Size2i get_internal_size() const { return internal_size; }
|
||||
_FORCE_INLINE_ Size2i get_target_size() const { return target_size; }
|
||||
_FORCE_INLINE_ RS::ViewportScaling3DMode get_scaling_3d_mode() const { return scaling_3d_mode; }
|
||||
//_FORCE_INLINE_ float get_fsr_sharpness() const { return fsr_sharpness; }
|
||||
_FORCE_INLINE_ RS::ViewportMSAA get_msaa_3d() const { return msaa3d.mode; }
|
||||
//_FORCE_INLINE_ RS::ViewportScreenSpaceAA get_screen_space_aa() const { return screen_space_aa; }
|
||||
//_FORCE_INLINE_ bool get_use_taa() const { return use_taa; }
|
||||
//_FORCE_INLINE_ bool get_use_debanding() const { return use_debanding; }
|
||||
};
|
||||
|
||||
#endif // GLES3_ENABLED
|
3252
drivers/gles3/storage/texture_storage.cpp
Normal file
3252
drivers/gles3/storage/texture_storage.cpp
Normal file
File diff suppressed because it is too large
Load Diff
737
drivers/gles3/storage/texture_storage.h
Normal file
737
drivers/gles3/storage/texture_storage.h
Normal file
@@ -0,0 +1,737 @@
|
||||
/**************************************************************************/
|
||||
/* texture_storage.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef GLES3_ENABLED
|
||||
|
||||
#include "platform_gl.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "core/io/image.h"
|
||||
#include "core/os/os.h"
|
||||
#include "core/templates/rid_owner.h"
|
||||
#include "servers/rendering/renderer_compositor.h"
|
||||
#include "servers/rendering/storage/texture_storage.h"
|
||||
|
||||
#include "drivers/gles3/shaders/canvas_sdf.glsl.gen.h"
|
||||
|
||||
namespace GLES3 {
|
||||
|
||||
#define _GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
|
||||
#define _GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
|
||||
|
||||
#define _EXT_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
|
||||
#define _EXT_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
|
||||
#define _EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
|
||||
|
||||
#define _EXT_COMPRESSED_RED_RGTC1_EXT 0x8DBB
|
||||
#define _EXT_COMPRESSED_RED_RGTC1 0x8DBB
|
||||
#define _EXT_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC
|
||||
#define _EXT_COMPRESSED_RG_RGTC2 0x8DBD
|
||||
#define _EXT_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE
|
||||
#define _EXT_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC
|
||||
#define _EXT_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD
|
||||
#define _EXT_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE
|
||||
#define _EXT_ETC1_RGB8_OES 0x8D64
|
||||
|
||||
#define _EXT_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C
|
||||
#define _EXT_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D
|
||||
#define _EXT_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E
|
||||
#define _EXT_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F
|
||||
|
||||
#define _EXT_COMPRESSED_R11_EAC 0x9270
|
||||
#define _EXT_COMPRESSED_SIGNED_R11_EAC 0x9271
|
||||
#define _EXT_COMPRESSED_RG11_EAC 0x9272
|
||||
#define _EXT_COMPRESSED_SIGNED_RG11_EAC 0x9273
|
||||
#define _EXT_COMPRESSED_RGB8_ETC2 0x9274
|
||||
#define _EXT_COMPRESSED_SRGB8_ETC2 0x9275
|
||||
#define _EXT_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276
|
||||
#define _EXT_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277
|
||||
#define _EXT_COMPRESSED_RGBA8_ETC2_EAC 0x9278
|
||||
#define _EXT_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279
|
||||
|
||||
#define _EXT_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0
|
||||
#define _EXT_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1
|
||||
#define _EXT_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2
|
||||
#define _EXT_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3
|
||||
#define _EXT_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4
|
||||
#define _EXT_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5
|
||||
#define _EXT_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6
|
||||
#define _EXT_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7
|
||||
#define _EXT_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8
|
||||
#define _EXT_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9
|
||||
#define _EXT_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA
|
||||
#define _EXT_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB
|
||||
#define _EXT_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC
|
||||
#define _EXT_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD
|
||||
|
||||
#define _EXT_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0
|
||||
#define _EXT_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1
|
||||
#define _EXT_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2
|
||||
#define _EXT_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3
|
||||
#define _EXT_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4
|
||||
#define _EXT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5
|
||||
#define _EXT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6
|
||||
#define _EXT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7
|
||||
#define _EXT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8
|
||||
#define _EXT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9
|
||||
#define _EXT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA
|
||||
#define _EXT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB
|
||||
#define _EXT_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC
|
||||
#define _EXT_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD
|
||||
|
||||
#define _GL_TEXTURE_EXTERNAL_OES 0x8D65
|
||||
|
||||
#define _EXT_TEXTURE_CUBE_MAP_SEAMLESS 0x884F
|
||||
|
||||
enum DefaultGLTexture {
|
||||
DEFAULT_GL_TEXTURE_WHITE,
|
||||
DEFAULT_GL_TEXTURE_BLACK,
|
||||
DEFAULT_GL_TEXTURE_TRANSPARENT,
|
||||
DEFAULT_GL_TEXTURE_NORMAL,
|
||||
DEFAULT_GL_TEXTURE_ANISO,
|
||||
DEFAULT_GL_TEXTURE_DEPTH,
|
||||
DEFAULT_GL_TEXTURE_CUBEMAP_BLACK,
|
||||
//DEFAULT_GL_TEXTURE_CUBEMAP_ARRAY_BLACK, // Cubemap Arrays not supported in GL 3.3 or GL ES 3.0
|
||||
DEFAULT_GL_TEXTURE_CUBEMAP_WHITE,
|
||||
DEFAULT_GL_TEXTURE_3D_WHITE,
|
||||
DEFAULT_GL_TEXTURE_3D_BLACK,
|
||||
DEFAULT_GL_TEXTURE_2D_ARRAY_WHITE,
|
||||
DEFAULT_GL_TEXTURE_2D_UINT,
|
||||
DEFAULT_GL_TEXTURE_EXT,
|
||||
DEFAULT_GL_TEXTURE_MAX
|
||||
};
|
||||
|
||||
struct CanvasTexture {
|
||||
RID diffuse;
|
||||
RID normal_map;
|
||||
RID specular;
|
||||
Color specular_color = Color(1, 1, 1, 1);
|
||||
float shininess = 1.0;
|
||||
|
||||
RS::CanvasItemTextureFilter texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT;
|
||||
RS::CanvasItemTextureRepeat texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT;
|
||||
};
|
||||
|
||||
struct RenderTarget;
|
||||
|
||||
struct Texture {
|
||||
RID self;
|
||||
|
||||
bool is_proxy = false;
|
||||
bool is_from_native_handle = false;
|
||||
bool is_render_target = false;
|
||||
|
||||
RID proxy_to;
|
||||
Vector<RID> proxies;
|
||||
|
||||
String path;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int depth = 0;
|
||||
int mipmaps = 1;
|
||||
int layers = 1;
|
||||
int alloc_width = 0;
|
||||
int alloc_height = 0;
|
||||
Image::Format format = Image::FORMAT_R8;
|
||||
Image::Format real_format = Image::FORMAT_R8;
|
||||
|
||||
enum Type {
|
||||
TYPE_2D,
|
||||
TYPE_LAYERED,
|
||||
TYPE_3D
|
||||
};
|
||||
|
||||
Type type = TYPE_2D;
|
||||
RS::TextureLayeredType layered_type = RS::TEXTURE_LAYERED_2D_ARRAY;
|
||||
|
||||
GLenum target = GL_TEXTURE_2D;
|
||||
GLenum gl_format_cache = 0;
|
||||
GLenum gl_internal_format_cache = 0;
|
||||
GLenum gl_type_cache = 0;
|
||||
|
||||
int total_data_size = 0;
|
||||
|
||||
bool compressed = false;
|
||||
|
||||
bool resize_to_po2 = false;
|
||||
|
||||
bool active = false;
|
||||
GLuint tex_id = 0;
|
||||
|
||||
uint16_t stored_cube_sides = 0;
|
||||
|
||||
RenderTarget *render_target = nullptr;
|
||||
|
||||
Ref<Image> image_cache_2d;
|
||||
Vector<Ref<Image>> image_cache_3d;
|
||||
|
||||
bool redraw_if_visible = false;
|
||||
|
||||
RS::TextureDetectCallback detect_3d_callback = nullptr;
|
||||
void *detect_3d_callback_ud = nullptr;
|
||||
|
||||
RS::TextureDetectCallback detect_normal_callback = nullptr;
|
||||
void *detect_normal_callback_ud = nullptr;
|
||||
|
||||
RS::TextureDetectRoughnessCallback detect_roughness_callback = nullptr;
|
||||
void *detect_roughness_callback_ud = nullptr;
|
||||
|
||||
CanvasTexture *canvas_texture = nullptr;
|
||||
|
||||
void copy_from(const Texture &o) {
|
||||
proxy_to = o.proxy_to;
|
||||
is_proxy = o.is_proxy;
|
||||
is_from_native_handle = o.is_from_native_handle;
|
||||
width = o.width;
|
||||
height = o.height;
|
||||
alloc_width = o.alloc_width;
|
||||
alloc_height = o.alloc_height;
|
||||
format = o.format;
|
||||
type = o.type;
|
||||
layered_type = o.layered_type;
|
||||
target = o.target;
|
||||
total_data_size = o.total_data_size;
|
||||
compressed = o.compressed;
|
||||
mipmaps = o.mipmaps;
|
||||
resize_to_po2 = o.resize_to_po2;
|
||||
active = o.active;
|
||||
tex_id = o.tex_id;
|
||||
stored_cube_sides = o.stored_cube_sides;
|
||||
render_target = o.render_target;
|
||||
is_render_target = o.is_render_target;
|
||||
redraw_if_visible = o.redraw_if_visible;
|
||||
detect_3d_callback = o.detect_3d_callback;
|
||||
detect_3d_callback_ud = o.detect_3d_callback_ud;
|
||||
detect_normal_callback = o.detect_normal_callback;
|
||||
detect_normal_callback_ud = o.detect_normal_callback_ud;
|
||||
detect_roughness_callback = o.detect_roughness_callback;
|
||||
detect_roughness_callback_ud = o.detect_roughness_callback_ud;
|
||||
}
|
||||
|
||||
// texture state
|
||||
void gl_set_filter(RS::CanvasItemTextureFilter p_filter) {
|
||||
if (p_filter == state_filter) {
|
||||
return;
|
||||
}
|
||||
Config *config = Config::get_singleton();
|
||||
state_filter = p_filter;
|
||||
GLenum pmin = GL_NEAREST;
|
||||
GLenum pmag = GL_NEAREST;
|
||||
GLint max_lod = 0;
|
||||
GLfloat anisotropy = 1.0f;
|
||||
switch (state_filter) {
|
||||
case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST: {
|
||||
pmin = GL_NEAREST;
|
||||
pmag = GL_NEAREST;
|
||||
max_lod = 0;
|
||||
} break;
|
||||
case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR: {
|
||||
pmin = GL_LINEAR;
|
||||
pmag = GL_LINEAR;
|
||||
max_lod = 0;
|
||||
} break;
|
||||
case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC: {
|
||||
anisotropy = config->anisotropic_level;
|
||||
};
|
||||
[[fallthrough]];
|
||||
case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: {
|
||||
pmag = GL_NEAREST;
|
||||
if (mipmaps <= 1) {
|
||||
pmin = GL_NEAREST;
|
||||
max_lod = 0;
|
||||
} else if (config->use_nearest_mip_filter) {
|
||||
pmin = GL_NEAREST_MIPMAP_NEAREST;
|
||||
max_lod = 1000;
|
||||
} else {
|
||||
pmin = GL_NEAREST_MIPMAP_LINEAR;
|
||||
max_lod = 1000;
|
||||
}
|
||||
} break;
|
||||
case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC: {
|
||||
anisotropy = config->anisotropic_level;
|
||||
};
|
||||
[[fallthrough]];
|
||||
case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: {
|
||||
pmag = GL_LINEAR;
|
||||
if (mipmaps <= 1) {
|
||||
pmin = GL_LINEAR;
|
||||
max_lod = 0;
|
||||
} else if (config->use_nearest_mip_filter) {
|
||||
pmin = GL_LINEAR_MIPMAP_NEAREST;
|
||||
max_lod = 1000;
|
||||
} else {
|
||||
pmin = GL_LINEAR_MIPMAP_LINEAR;
|
||||
max_lod = 1000;
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
return;
|
||||
} break;
|
||||
}
|
||||
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, pmin);
|
||||
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, pmag);
|
||||
glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, max_lod);
|
||||
if (config->support_anisotropic_filter) {
|
||||
glTexParameterf(target, _GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy);
|
||||
}
|
||||
}
|
||||
void gl_set_repeat(RS::CanvasItemTextureRepeat p_repeat) {
|
||||
if (p_repeat == state_repeat) {
|
||||
return;
|
||||
}
|
||||
state_repeat = p_repeat;
|
||||
GLenum prep = GL_CLAMP_TO_EDGE;
|
||||
switch (state_repeat) {
|
||||
case RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED: {
|
||||
prep = GL_CLAMP_TO_EDGE;
|
||||
} break;
|
||||
case RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: {
|
||||
prep = GL_REPEAT;
|
||||
} break;
|
||||
case RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: {
|
||||
prep = GL_MIRRORED_REPEAT;
|
||||
} break;
|
||||
default: {
|
||||
return;
|
||||
} break;
|
||||
}
|
||||
glTexParameteri(target, GL_TEXTURE_WRAP_T, prep);
|
||||
glTexParameteri(target, GL_TEXTURE_WRAP_R, prep);
|
||||
glTexParameteri(target, GL_TEXTURE_WRAP_S, prep);
|
||||
}
|
||||
|
||||
private:
|
||||
RS::CanvasItemTextureFilter state_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_MAX;
|
||||
RS::CanvasItemTextureRepeat state_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX;
|
||||
};
|
||||
|
||||
struct RenderTarget {
|
||||
Point2i position = Point2i(0, 0);
|
||||
Size2i size = Size2i(0, 0);
|
||||
uint32_t view_count = 1;
|
||||
int mipmap_count = 1;
|
||||
RID self;
|
||||
GLuint fbo = 0;
|
||||
GLuint color = 0;
|
||||
GLuint depth = 0;
|
||||
GLuint backbuffer_fbo = 0;
|
||||
GLuint backbuffer = 0;
|
||||
GLuint backbuffer_depth = 0;
|
||||
bool depth_has_stencil = true;
|
||||
|
||||
bool hdr = false; // For Compatibility this effects both 2D and 3D rendering!
|
||||
GLuint color_internal_format = GL_RGBA8;
|
||||
GLuint color_format = GL_RGBA;
|
||||
GLuint color_type = GL_UNSIGNED_BYTE;
|
||||
uint32_t color_format_size = 4;
|
||||
Image::Format image_format = Image::FORMAT_RGBA8;
|
||||
|
||||
GLuint sdf_texture_write = 0;
|
||||
GLuint sdf_texture_write_fb = 0;
|
||||
GLuint sdf_texture_process[2] = { 0, 0 };
|
||||
GLuint sdf_texture_read = 0;
|
||||
RS::ViewportSDFOversize sdf_oversize = RS::VIEWPORT_SDF_OVERSIZE_120_PERCENT;
|
||||
RS::ViewportSDFScale sdf_scale = RS::VIEWPORT_SDF_SCALE_50_PERCENT;
|
||||
Size2i process_size;
|
||||
bool sdf_enabled = false;
|
||||
|
||||
bool is_transparent = false;
|
||||
bool direct_to_screen = false;
|
||||
|
||||
bool used_in_frame = false;
|
||||
RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
|
||||
bool reattach_textures = false;
|
||||
|
||||
Rect2i render_region;
|
||||
|
||||
struct RTOverridden {
|
||||
bool is_overridden = false;
|
||||
bool depth_has_stencil = false;
|
||||
RID color;
|
||||
RID depth;
|
||||
RID velocity;
|
||||
|
||||
struct FBOCacheEntry {
|
||||
GLuint fbo;
|
||||
GLuint color;
|
||||
GLuint depth;
|
||||
Size2i size;
|
||||
Vector<GLuint> allocated_textures;
|
||||
bool depth_has_stencil;
|
||||
};
|
||||
RBMap<uint32_t, FBOCacheEntry> fbo_cache;
|
||||
} overridden;
|
||||
|
||||
RID texture;
|
||||
|
||||
Color clear_color = Color(1, 1, 1, 1);
|
||||
bool clear_requested = false;
|
||||
|
||||
RenderTarget() {
|
||||
}
|
||||
};
|
||||
|
||||
class TextureStorage : public RendererTextureStorage {
|
||||
private:
|
||||
static TextureStorage *singleton;
|
||||
|
||||
RID default_gl_textures[DEFAULT_GL_TEXTURE_MAX];
|
||||
|
||||
/* Canvas Texture API */
|
||||
|
||||
RID_Owner<CanvasTexture, true> canvas_texture_owner;
|
||||
|
||||
/* Texture API */
|
||||
// Textures can be created from threads, so this RID_Owner is thread safe.
|
||||
mutable RID_Owner<Texture, true> texture_owner;
|
||||
|
||||
Ref<Image> _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;
|
||||
|
||||
/* TEXTURE ATLAS API */
|
||||
|
||||
struct TextureAtlas {
|
||||
struct Texture {
|
||||
int users;
|
||||
Rect2 uv_rect;
|
||||
};
|
||||
|
||||
struct SortItem {
|
||||
RID texture;
|
||||
Size2i pixel_size;
|
||||
Size2i size;
|
||||
Point2i pos;
|
||||
|
||||
bool operator<(const SortItem &p_item) const {
|
||||
//sort larger to smaller
|
||||
if (size.height == p_item.size.height) {
|
||||
return size.width > p_item.size.width;
|
||||
} else {
|
||||
return size.height > p_item.size.height;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
HashMap<RID, Texture> textures;
|
||||
bool dirty = true;
|
||||
|
||||
GLuint texture = 0;
|
||||
GLuint framebuffer = 0;
|
||||
Size2i size;
|
||||
} texture_atlas;
|
||||
|
||||
/* Render Target API */
|
||||
|
||||
mutable RID_Owner<RenderTarget> render_target_owner;
|
||||
|
||||
void _clear_render_target(RenderTarget *rt);
|
||||
void _update_render_target(RenderTarget *rt);
|
||||
void _create_render_target_backbuffer(RenderTarget *rt);
|
||||
void _render_target_allocate_sdf(RenderTarget *rt);
|
||||
void _render_target_clear_sdf(RenderTarget *rt);
|
||||
Rect2i _render_target_get_sdf_rect(const RenderTarget *rt) const;
|
||||
|
||||
void _texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer, bool p_initialize);
|
||||
void _texture_set_3d_data(RID p_texture, const Vector<Ref<Image>> &p_data, bool p_initialize);
|
||||
void _texture_set_swizzle(Texture *p_texture, Image::Format p_real_format);
|
||||
Vector<Ref<Image>> _texture_3d_read_framebuffer(Texture *p_texture) const;
|
||||
|
||||
struct RenderTargetSDF {
|
||||
CanvasSdfShaderGLES3 shader;
|
||||
RID shader_version;
|
||||
} sdf_shader;
|
||||
|
||||
public:
|
||||
static TextureStorage *get_singleton();
|
||||
|
||||
TextureStorage();
|
||||
virtual ~TextureStorage();
|
||||
|
||||
_FORCE_INLINE_ RID texture_gl_get_default(DefaultGLTexture p_texture) {
|
||||
return default_gl_textures[p_texture];
|
||||
}
|
||||
|
||||
/* Canvas Texture API */
|
||||
|
||||
CanvasTexture *get_canvas_texture(RID p_rid) { return canvas_texture_owner.get_or_null(p_rid); }
|
||||
bool owns_canvas_texture(RID p_rid) { return canvas_texture_owner.owns(p_rid); }
|
||||
|
||||
virtual RID canvas_texture_allocate() override;
|
||||
virtual void canvas_texture_initialize(RID p_rid) override;
|
||||
virtual void canvas_texture_free(RID p_rid) override;
|
||||
|
||||
virtual void canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) override;
|
||||
virtual void canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess) override;
|
||||
|
||||
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;
|
||||
|
||||
/* Texture API */
|
||||
|
||||
Texture *get_texture(RID p_rid) const {
|
||||
Texture *texture = texture_owner.get_or_null(p_rid);
|
||||
if (texture && texture->is_proxy) {
|
||||
return texture_owner.get_or_null(texture->proxy_to);
|
||||
}
|
||||
return texture;
|
||||
}
|
||||
bool owns_texture(RID p_rid) { return texture_owner.owns(p_rid); }
|
||||
|
||||
void texture_2d_initialize_from_texture(RID p_texture, Texture &p_tex) {
|
||||
texture_owner.initialize_rid(p_texture, p_tex);
|
||||
}
|
||||
|
||||
virtual RID texture_allocate() override;
|
||||
virtual void texture_free(RID p_rid) override;
|
||||
|
||||
virtual void texture_2d_initialize(RID p_texture, const Ref<Image> &p_image) override;
|
||||
virtual void texture_2d_layered_initialize(RID p_texture, const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) override;
|
||||
virtual void texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) override;
|
||||
virtual void texture_external_initialize(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) override;
|
||||
virtual void texture_proxy_initialize(RID p_texture, RID p_base) override; //all slices, then all the mipmaps, must be coherent
|
||||
|
||||
virtual RID texture_create_from_native_handle(RS::TextureType p_type, Image::Format p_format, uint64_t p_native_handle, int p_width, int p_height, int p_depth, int p_layers = 1, RS::TextureLayeredType p_layered_type = RS::TEXTURE_LAYERED_2D_ARRAY) override;
|
||||
|
||||
virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) override;
|
||||
virtual void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) override;
|
||||
virtual void texture_external_update(RID p_texture, int p_width, int p_height, uint64_t p_external_buffer) override;
|
||||
virtual void texture_proxy_update(RID p_proxy, RID p_base) override;
|
||||
|
||||
Ref<Image> texture_2d_placeholder;
|
||||
Vector<Ref<Image>> texture_2d_array_placeholder;
|
||||
Vector<Ref<Image>> cubemap_placeholder;
|
||||
Vector<Ref<Image>> texture_3d_placeholder;
|
||||
|
||||
//these two APIs can be used together or in combination with the others.
|
||||
virtual void texture_2d_placeholder_initialize(RID p_texture) override;
|
||||
virtual void texture_2d_layered_placeholder_initialize(RID p_texture, RenderingServer::TextureLayeredType p_layered_type) override;
|
||||
virtual void texture_3d_placeholder_initialize(RID p_texture) override;
|
||||
|
||||
virtual Ref<Image> texture_2d_get(RID p_texture) const override;
|
||||
virtual Ref<Image> texture_2d_layer_get(RID p_texture, int p_layer) const override;
|
||||
virtual Vector<Ref<Image>> texture_3d_get(RID p_texture) const override;
|
||||
|
||||
virtual void texture_replace(RID p_texture, RID p_by_texture) override;
|
||||
virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) override;
|
||||
|
||||
virtual void texture_set_path(RID p_texture, const String &p_path) override;
|
||||
virtual String texture_get_path(RID p_texture) const override;
|
||||
|
||||
virtual void texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) override;
|
||||
void texture_set_detect_srgb_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata);
|
||||
virtual void texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) override;
|
||||
virtual void texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) override;
|
||||
|
||||
virtual void texture_debug_usage(List<RS::TextureInfo> *r_info) override;
|
||||
|
||||
virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) override;
|
||||
|
||||
virtual Size2 texture_size_with_proxy(RID p_proxy) override;
|
||||
|
||||
virtual void texture_rd_initialize(RID p_texture, const RID &p_rd_texture, const RS::TextureLayeredType p_layer_type = RS::TEXTURE_LAYERED_2D_ARRAY) override;
|
||||
virtual RID texture_get_rd_texture(RID p_texture, bool p_srgb = false) const override;
|
||||
virtual uint64_t texture_get_native_handle(RID p_texture, bool p_srgb = false) const override;
|
||||
|
||||
void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer = 0);
|
||||
virtual Image::Format texture_get_format(RID p_texture) const override;
|
||||
uint32_t texture_get_texid(RID p_texture) const;
|
||||
Vector3i texture_get_size(RID p_texture) const;
|
||||
uint32_t texture_get_width(RID p_texture) const;
|
||||
uint32_t texture_get_height(RID p_texture) const;
|
||||
uint32_t texture_get_depth(RID p_texture) const;
|
||||
void texture_bind(RID p_texture, uint32_t p_texture_no);
|
||||
|
||||
/* TEXTURE ATLAS API */
|
||||
|
||||
void update_texture_atlas();
|
||||
|
||||
GLuint texture_atlas_get_texture() const;
|
||||
_FORCE_INLINE_ Rect2 texture_atlas_get_texture_rect(RID p_texture) {
|
||||
TextureAtlas::Texture *t = texture_atlas.textures.getptr(p_texture);
|
||||
if (!t) {
|
||||
return Rect2();
|
||||
}
|
||||
|
||||
return t->uv_rect;
|
||||
}
|
||||
|
||||
void texture_add_to_texture_atlas(RID p_texture);
|
||||
void texture_remove_from_texture_atlas(RID p_texture);
|
||||
void texture_atlas_mark_dirty_on_texture(RID p_texture);
|
||||
void texture_atlas_remove_texture(RID p_texture);
|
||||
|
||||
/* DECAL API */
|
||||
|
||||
virtual RID decal_allocate() override;
|
||||
virtual void decal_initialize(RID p_rid) override;
|
||||
virtual void decal_free(RID p_rid) override {}
|
||||
|
||||
virtual void decal_set_size(RID p_decal, const Vector3 &p_size) override;
|
||||
virtual void decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) override;
|
||||
virtual void decal_set_emission_energy(RID p_decal, float p_energy) override;
|
||||
virtual void decal_set_albedo_mix(RID p_decal, float p_mix) override;
|
||||
virtual void decal_set_modulate(RID p_decal, const Color &p_modulate) override;
|
||||
virtual void decal_set_cull_mask(RID p_decal, uint32_t p_layers) override;
|
||||
virtual void decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) override;
|
||||
virtual void decal_set_fade(RID p_decal, float p_above, float p_below) override;
|
||||
virtual void decal_set_normal_fade(RID p_decal, float p_fade) override;
|
||||
|
||||
virtual AABB decal_get_aabb(RID p_decal) const override;
|
||||
virtual uint32_t decal_get_cull_mask(RID p_decal) const override { return 0; }
|
||||
|
||||
virtual void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {}
|
||||
virtual void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {}
|
||||
|
||||
/* DECAL INSTANCE */
|
||||
|
||||
virtual RID decal_instance_create(RID p_decal) override { return RID(); }
|
||||
virtual void decal_instance_free(RID p_decal_instance) override {}
|
||||
virtual void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override {}
|
||||
virtual void decal_instance_set_sorting_offset(RID p_decal_instance, float p_sorting_offset) override {}
|
||||
|
||||
/* RENDER TARGET API */
|
||||
|
||||
static GLuint system_fbo;
|
||||
|
||||
RenderTarget *get_render_target(RID p_rid) { return render_target_owner.get_or_null(p_rid); }
|
||||
bool owns_render_target(RID p_rid) { return render_target_owner.owns(p_rid); }
|
||||
|
||||
void check_backbuffer(RenderTarget *rt, const bool uses_screen_texture, const bool uses_depth_texture);
|
||||
|
||||
virtual RID render_target_create() override;
|
||||
virtual void render_target_free(RID p_rid) override;
|
||||
|
||||
virtual void render_target_set_position(RID p_render_target, int p_x, int p_y) override;
|
||||
virtual Point2i render_target_get_position(RID p_render_target) const override;
|
||||
virtual void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) override;
|
||||
virtual Size2i render_target_get_size(RID p_render_target) const override;
|
||||
virtual void render_target_set_transparent(RID p_render_target, bool p_is_transparent) override;
|
||||
virtual bool render_target_get_transparent(RID p_render_target) const override;
|
||||
virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) override;
|
||||
virtual bool render_target_get_direct_to_screen(RID p_render_target) const override;
|
||||
virtual bool render_target_was_used(RID p_render_target) const override;
|
||||
void render_target_clear_used(RID p_render_target);
|
||||
virtual void render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) override;
|
||||
virtual RS::ViewportMSAA render_target_get_msaa(RID p_render_target) const override;
|
||||
virtual void render_target_set_msaa_needs_resolve(RID p_render_target, bool p_needs_resolve) override {}
|
||||
virtual bool render_target_get_msaa_needs_resolve(RID p_render_target) const override { return false; }
|
||||
virtual void render_target_do_msaa_resolve(RID p_render_target) override {}
|
||||
virtual void render_target_set_use_hdr(RID p_render_target, bool p_use_hdr_2d) override;
|
||||
virtual bool render_target_is_using_hdr(RID p_render_target) const override;
|
||||
virtual void render_target_set_use_debanding(RID p_render_target, bool p_use_debanding) override {}
|
||||
virtual bool render_target_is_using_debanding(RID p_render_target) const override { return false; }
|
||||
|
||||
// new
|
||||
void render_target_set_as_unused(RID p_render_target) override {
|
||||
render_target_clear_used(p_render_target);
|
||||
}
|
||||
|
||||
GLuint render_target_get_color_internal_format(RID p_render_target) const;
|
||||
GLuint render_target_get_color_format(RID p_render_target) const;
|
||||
GLuint render_target_get_color_type(RID p_render_target) const;
|
||||
uint32_t render_target_get_color_format_size(RID p_render_target) const;
|
||||
|
||||
void render_target_request_clear(RID p_render_target, const Color &p_clear_color) override;
|
||||
bool render_target_is_clear_requested(RID p_render_target) override;
|
||||
Color render_target_get_clear_request_color(RID p_render_target) override;
|
||||
void render_target_disable_clear_request(RID p_render_target) override;
|
||||
void render_target_do_clear_request(RID p_render_target) override;
|
||||
|
||||
GLuint render_target_get_fbo(RID p_render_target) const;
|
||||
GLuint render_target_get_color(RID p_render_target) const;
|
||||
GLuint render_target_get_depth(RID p_render_target) const;
|
||||
bool render_target_get_depth_has_stencil(RID p_render_target) const;
|
||||
void render_target_set_reattach_textures(RID p_render_target, bool p_reattach_textures) const;
|
||||
bool render_target_is_reattach_textures(RID p_render_target) const;
|
||||
|
||||
virtual void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) override;
|
||||
virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const override;
|
||||
GLuint render_target_get_sdf_texture(RID p_render_target);
|
||||
GLuint render_target_get_sdf_framebuffer(RID p_render_target);
|
||||
void render_target_sdf_process(RID p_render_target);
|
||||
virtual void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) override;
|
||||
bool render_target_is_sdf_enabled(RID p_render_target) const;
|
||||
|
||||
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 RS::ViewportVRSMode render_target_get_vrs_mode(RID p_render_target) const override { return RS::VIEWPORT_VRS_DISABLED; }
|
||||
virtual void render_target_set_vrs_update_mode(RID p_render_target, RS::ViewportVRSUpdateMode p_mode) override {}
|
||||
virtual RS::ViewportVRSUpdateMode render_target_get_vrs_update_mode(RID p_render_target) const override { return RS::VIEWPORT_VRS_UPDATE_DISABLED; }
|
||||
virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override {}
|
||||
virtual RID render_target_get_vrs_texture(RID p_render_target) const override { return RID(); }
|
||||
|
||||
virtual void render_target_set_override(RID p_render_target, RID p_color_texture, RID p_depth_texture, RID p_velocity_texture, RID p_velocity_depth_texture) override;
|
||||
virtual RID render_target_get_override_color(RID p_render_target) const override;
|
||||
virtual RID render_target_get_override_depth(RID p_render_target) const override;
|
||||
virtual RID render_target_get_override_velocity(RID p_render_target) const override;
|
||||
virtual RID render_target_get_override_velocity_depth(RID p_render_target) const override { return RID(); }
|
||||
|
||||
virtual void render_target_set_render_region(RID p_render_target, const Rect2i &p_render_region) override;
|
||||
virtual Rect2i render_target_get_render_region(RID p_render_target) const override;
|
||||
|
||||
virtual RID render_target_get_texture(RID p_render_target) override;
|
||||
|
||||
virtual void render_target_set_velocity_target_size(RID p_render_target, const Size2i &p_target_size) override {}
|
||||
virtual Size2i render_target_get_velocity_target_size(RID p_render_target) const override { return Size2i(); }
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
inline String TextureStorage::get_framebuffer_error(GLenum p_status) {
|
||||
#if defined(DEBUG_ENABLED) && defined(GL_API_ENABLED)
|
||||
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);
|
||||
}
|
||||
|
||||
} // namespace GLES3
|
||||
|
||||
#endif // GLES3_ENABLED
|
483
drivers/gles3/storage/utilities.cpp
Normal file
483
drivers/gles3/storage/utilities.cpp
Normal file
@@ -0,0 +1,483 @@
|
||||
/**************************************************************************/
|
||||
/* utilities.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "../rasterizer_gles3.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;
|
||||
frame = 0;
|
||||
for (int i = 0; i < FRAME_COUNT; i++) {
|
||||
frames[i].index = 0;
|
||||
glGenQueries(max_timestamp_query_elements, frames[i].queries);
|
||||
|
||||
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.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;
|
||||
}
|
||||
}
|
||||
|
||||
Utilities::~Utilities() {
|
||||
singleton = nullptr;
|
||||
for (int i = 0; i < FRAME_COUNT; i++) {
|
||||
glDeleteQueries(max_timestamp_query_elements, frames[i].queries);
|
||||
}
|
||||
|
||||
if (texture_mem_cache) {
|
||||
uint32_t leaked_data_size = 0;
|
||||
for (const KeyValue<GLuint, ResourceAllocation> &E : texture_allocs_cache) {
|
||||
#ifdef DEV_ENABLED
|
||||
ERR_PRINT(E.value.name + ": leaked " + itos(E.value.size) + " bytes.");
|
||||
#else
|
||||
ERR_PRINT("Texture with GL ID of " + itos(E.key) + ": leaked " + itos(E.value.size) + " bytes.");
|
||||
#endif
|
||||
leaked_data_size += E.value.size;
|
||||
}
|
||||
if (leaked_data_size < texture_mem_cache) {
|
||||
ERR_PRINT("Texture cache is not empty. There may be an additional texture leak of " + itos(texture_mem_cache - leaked_data_size) + " bytes.");
|
||||
}
|
||||
}
|
||||
|
||||
if (render_buffer_mem_cache) {
|
||||
uint32_t leaked_data_size = 0;
|
||||
for (const KeyValue<GLuint, ResourceAllocation> &E : render_buffer_allocs_cache) {
|
||||
#ifdef DEV_ENABLED
|
||||
ERR_PRINT(E.value.name + ": leaked " + itos(E.value.size) + " bytes.");
|
||||
#else
|
||||
ERR_PRINT("Render buffer with GL ID of " + itos(E.key) + ": leaked " + itos(E.value.size) + " bytes.");
|
||||
#endif
|
||||
leaked_data_size += E.value.size;
|
||||
}
|
||||
if (leaked_data_size < render_buffer_mem_cache) {
|
||||
ERR_PRINT("Render buffer cache is not empty. There may be an additional render buffer leak of " + itos(render_buffer_mem_cache - leaked_data_size) + " bytes.");
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer_mem_cache) {
|
||||
uint32_t leaked_data_size = 0;
|
||||
|
||||
for (const KeyValue<GLuint, ResourceAllocation> &E : buffer_allocs_cache) {
|
||||
#ifdef DEV_ENABLED
|
||||
ERR_PRINT(E.value.name + ": leaked " + itos(E.value.size) + " bytes.");
|
||||
#else
|
||||
ERR_PRINT("Buffer with GL ID of " + itos(E.key) + ": leaked " + itos(E.value.size) + " bytes.");
|
||||
#endif
|
||||
leaked_data_size += E.value.size;
|
||||
}
|
||||
if (leaked_data_size < buffer_mem_cache) {
|
||||
ERR_PRINT("Buffer cache is not empty. There may be an additional buffer leak of " + itos(buffer_mem_cache - leaked_data_size) + " bytes.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vector<uint8_t> Utilities::buffer_get_data(GLenum p_target, GLuint p_buffer, uint32_t p_buffer_size) {
|
||||
Vector<uint8_t> ret;
|
||||
|
||||
if (p_buffer_size == 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret.resize(p_buffer_size);
|
||||
glBindBuffer(p_target, p_buffer);
|
||||
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
{
|
||||
uint8_t *w = ret.ptrw();
|
||||
godot_webgl2_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;
|
||||
} else if (GLES3::LightStorage::get_singleton()->owns_lightmap(p_rid)) {
|
||||
return RS::INSTANCE_LIGHTMAP;
|
||||
} else if (GLES3::ParticlesStorage::get_singleton()->owns_particles(p_rid)) {
|
||||
return RS::INSTANCE_PARTICLES;
|
||||
} else if (GLES3::LightStorage::get_singleton()->owns_reflection_probe(p_rid)) {
|
||||
return RS::INSTANCE_REFLECTION_PROBE;
|
||||
} else if (GLES3::ParticlesStorage::get_singleton()->owns_particles_collision(p_rid)) {
|
||||
return RS::INSTANCE_PARTICLES_COLLISION;
|
||||
} else if (owns_visibility_notifier(p_rid)) {
|
||||
return RS::INSTANCE_VISIBLITY_NOTIFIER;
|
||||
}
|
||||
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 if (GLES3::LightStorage::get_singleton()->owns_lightmap(p_rid)) {
|
||||
GLES3::LightStorage::get_singleton()->lightmap_free(p_rid);
|
||||
return true;
|
||||
} else if (GLES3::LightStorage::get_singleton()->owns_reflection_probe(p_rid)) {
|
||||
GLES3::LightStorage::get_singleton()->reflection_probe_free(p_rid);
|
||||
return true;
|
||||
} else if (GLES3::LightStorage::get_singleton()->owns_reflection_atlas(p_rid)) {
|
||||
GLES3::LightStorage::get_singleton()->reflection_atlas_free(p_rid);
|
||||
return true;
|
||||
} else if (GLES3::LightStorage::get_singleton()->owns_reflection_probe_instance(p_rid)) {
|
||||
GLES3::LightStorage::get_singleton()->reflection_probe_instance_free(p_rid);
|
||||
return true;
|
||||
} else if (GLES3::ParticlesStorage::get_singleton()->owns_particles(p_rid)) {
|
||||
GLES3::ParticlesStorage::get_singleton()->particles_free(p_rid);
|
||||
return true;
|
||||
} else if (GLES3::ParticlesStorage::get_singleton()->owns_particles_collision(p_rid)) {
|
||||
GLES3::ParticlesStorage::get_singleton()->particles_collision_free(p_rid);
|
||||
return true;
|
||||
} else if (GLES3::ParticlesStorage::get_singleton()->owns_particles_collision_instance(p_rid)) {
|
||||
GLES3::ParticlesStorage::get_singleton()->particles_collision_instance_free(p_rid);
|
||||
return true;
|
||||
} else if (GLES3::MeshStorage::get_singleton()->owns_skeleton(p_rid)) {
|
||||
GLES3::MeshStorage::get_singleton()->skeleton_free(p_rid);
|
||||
return true;
|
||||
} else if (owns_visibility_notifier(p_rid)) {
|
||||
visibility_notifier_free(p_rid);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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_reflection_probe(p_base)) {
|
||||
Dependency *dependency = LightStorage::get_singleton()->reflection_probe_get_dependency(p_base);
|
||||
p_instance->update_dependency(dependency);
|
||||
} else if (LightStorage::get_singleton()->owns_light(p_base)) {
|
||||
Light *l = LightStorage::get_singleton()->get_light(p_base);
|
||||
p_instance->update_dependency(&l->dependency);
|
||||
} else if (ParticlesStorage::get_singleton()->owns_particles(p_base)) {
|
||||
Dependency *dependency = ParticlesStorage::get_singleton()->particles_get_dependency(p_base);
|
||||
p_instance->update_dependency(dependency);
|
||||
} else if (ParticlesStorage::get_singleton()->owns_particles_collision(p_base)) {
|
||||
Dependency *dependency = ParticlesStorage::get_singleton()->particles_collision_get_dependency(p_base);
|
||||
p_instance->update_dependency(dependency);
|
||||
} else if (owns_visibility_notifier(p_base)) {
|
||||
VisibilityNotifier *vn = get_visibility_notifier(p_base);
|
||||
p_instance->update_dependency(&vn->dependency);
|
||||
}
|
||||
}
|
||||
|
||||
/* VISIBILITY NOTIFIER */
|
||||
|
||||
RID Utilities::visibility_notifier_allocate() {
|
||||
return visibility_notifier_owner.allocate_rid();
|
||||
}
|
||||
|
||||
void Utilities::visibility_notifier_initialize(RID p_notifier) {
|
||||
visibility_notifier_owner.initialize_rid(p_notifier, VisibilityNotifier());
|
||||
}
|
||||
|
||||
void Utilities::visibility_notifier_free(RID p_notifier) {
|
||||
VisibilityNotifier *vn = visibility_notifier_owner.get_or_null(p_notifier);
|
||||
vn->dependency.deleted_notify(p_notifier);
|
||||
visibility_notifier_owner.free(p_notifier);
|
||||
}
|
||||
|
||||
void Utilities::visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) {
|
||||
VisibilityNotifier *vn = visibility_notifier_owner.get_or_null(p_notifier);
|
||||
ERR_FAIL_NULL(vn);
|
||||
vn->aabb = p_aabb;
|
||||
vn->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
|
||||
}
|
||||
|
||||
void Utilities::visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) {
|
||||
VisibilityNotifier *vn = visibility_notifier_owner.get_or_null(p_notifier);
|
||||
ERR_FAIL_NULL(vn);
|
||||
vn->enter_callback = p_enter_callbable;
|
||||
vn->exit_callback = p_exit_callable;
|
||||
}
|
||||
|
||||
AABB Utilities::visibility_notifier_get_aabb(RID p_notifier) const {
|
||||
const VisibilityNotifier *vn = visibility_notifier_owner.get_or_null(p_notifier);
|
||||
ERR_FAIL_NULL_V(vn, AABB());
|
||||
return vn->aabb;
|
||||
}
|
||||
|
||||
void Utilities::visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) {
|
||||
VisibilityNotifier *vn = visibility_notifier_owner.get_or_null(p_notifier);
|
||||
ERR_FAIL_NULL(vn);
|
||||
|
||||
if (p_enter) {
|
||||
if (vn->enter_callback.is_valid()) {
|
||||
if (p_deferred) {
|
||||
vn->enter_callback.call_deferred();
|
||||
} else {
|
||||
vn->enter_callback.call();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (vn->exit_callback.is_valid()) {
|
||||
if (p_deferred) {
|
||||
vn->exit_callback.call_deferred();
|
||||
} else {
|
||||
vn->exit_callback.call();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* TIMING */
|
||||
|
||||
void Utilities::capture_timestamps_begin() {
|
||||
capture_timestamp("Frame Begin");
|
||||
}
|
||||
|
||||
void Utilities::capture_timestamp(const String &p_name) {
|
||||
ERR_FAIL_COND(frames[frame].timestamp_count >= max_timestamp_query_elements);
|
||||
|
||||
#ifdef GL_API_ENABLED
|
||||
if (RasterizerGLES3::is_gles_over_gl()) {
|
||||
glQueryCounter(frames[frame].queries[frames[frame].timestamp_count], GL_TIMESTAMP);
|
||||
}
|
||||
#endif // GL_API_ENABLED
|
||||
|
||||
frames[frame].timestamp_names[frames[frame].timestamp_count] = p_name;
|
||||
frames[frame].timestamp_cpu_values[frames[frame].timestamp_count] = OS::get_singleton()->get_ticks_usec();
|
||||
frames[frame].timestamp_count++;
|
||||
}
|
||||
|
||||
void Utilities::_capture_timestamps_begin() {
|
||||
// frame is incremented at the end of the frame so this gives us the queries for frame - 2. By then they should be ready.
|
||||
if (frames[frame].timestamp_count) {
|
||||
#ifdef GL_API_ENABLED
|
||||
if (RasterizerGLES3::is_gles_over_gl()) {
|
||||
for (uint32_t i = 0; i < frames[frame].timestamp_count; i++) {
|
||||
uint64_t temp = 0;
|
||||
glGetQueryObjectui64v(frames[frame].queries[i], GL_QUERY_RESULT, &temp);
|
||||
frames[frame].timestamp_result_values[i] = temp;
|
||||
}
|
||||
}
|
||||
#endif // GL_API_ENABLED
|
||||
SWAP(frames[frame].timestamp_names, frames[frame].timestamp_result_names);
|
||||
SWAP(frames[frame].timestamp_cpu_values, frames[frame].timestamp_cpu_result_values);
|
||||
}
|
||||
|
||||
frames[frame].timestamp_result_count = frames[frame].timestamp_count;
|
||||
frames[frame].timestamp_count = 0;
|
||||
frames[frame].index = Engine::get_singleton()->get_frames_drawn();
|
||||
capture_timestamp("Internal Begin");
|
||||
}
|
||||
|
||||
void Utilities::capture_timestamps_end() {
|
||||
capture_timestamp("Internal End");
|
||||
frame = (frame + 1) % FRAME_COUNT;
|
||||
}
|
||||
|
||||
uint32_t Utilities::get_captured_timestamps_count() const {
|
||||
return frames[frame].timestamp_result_count;
|
||||
}
|
||||
|
||||
uint64_t Utilities::get_captured_timestamps_frame() const {
|
||||
return frames[frame].index;
|
||||
}
|
||||
|
||||
uint64_t Utilities::get_captured_timestamp_gpu_time(uint32_t p_index) const {
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0);
|
||||
return frames[frame].timestamp_result_values[p_index];
|
||||
}
|
||||
|
||||
uint64_t Utilities::get_captured_timestamp_cpu_time(uint32_t p_index) const {
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0);
|
||||
return frames[frame].timestamp_cpu_result_values[p_index];
|
||||
}
|
||||
|
||||
String Utilities::get_captured_timestamp_name(uint32_t p_index) const {
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, String());
|
||||
return frames[frame].timestamp_result_names[p_index];
|
||||
}
|
||||
|
||||
/* MISC */
|
||||
|
||||
void Utilities::update_dirty_resources() {
|
||||
MaterialStorage::get_singleton()->_update_global_shader_uniforms();
|
||||
MaterialStorage::get_singleton()->_update_queued_materials();
|
||||
MeshStorage::get_singleton()->_update_dirty_skeletons();
|
||||
MeshStorage::get_singleton()->_update_dirty_multimeshes();
|
||||
TextureStorage::get_singleton()->update_texture_atlas();
|
||||
}
|
||||
|
||||
void Utilities::set_debug_generate_wireframes(bool p_generate) {
|
||||
Config *config = Config::get_singleton();
|
||||
config->generate_wireframes = 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 == "astc") {
|
||||
return config->astc_supported;
|
||||
}
|
||||
if (p_feature == "etc2") {
|
||||
return config->etc2_supported;
|
||||
}
|
||||
if (p_feature == "astc_hdr") {
|
||||
return config->astc_hdr_supported;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Utilities::update_memory_info() {
|
||||
}
|
||||
|
||||
uint64_t Utilities::get_rendering_info(RS::RenderingInfo p_info) {
|
||||
if (p_info == RS::RENDERING_INFO_TEXTURE_MEM_USED) {
|
||||
return texture_mem_cache + render_buffer_mem_cache; // Add render buffer memory to our texture mem.
|
||||
} else if (p_info == RS::RENDERING_INFO_BUFFER_MEM_USED) {
|
||||
return buffer_mem_cache;
|
||||
} else if (p_info == RS::RENDERING_INFO_VIDEO_MEM_USED) {
|
||||
return texture_mem_cache + buffer_mem_cache + render_buffer_mem_cache;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
String Utilities::get_video_adapter_name() const {
|
||||
const String rendering_device_name = String::utf8((const char *)glGetString(GL_RENDERER));
|
||||
// NVIDIA suffixes all GPU model names with "/PCIe/SSE2" in OpenGL (but not Vulkan). This isn't necessary to display nowadays, so it can be trimmed.
|
||||
return rendering_device_name.trim_suffix("/PCIe/SSE2");
|
||||
}
|
||||
|
||||
String Utilities::get_video_adapter_vendor() const {
|
||||
const String rendering_device_vendor = String::utf8((const char *)glGetString(GL_VENDOR));
|
||||
// NVIDIA suffixes its vendor name with " Corporation". This is neither necessary to process nor display.
|
||||
return rendering_device_vendor.trim_suffix(" Corporation");
|
||||
}
|
||||
|
||||
RenderingDevice::DeviceType Utilities::get_video_adapter_type() const {
|
||||
return RenderingDevice::DeviceType::DEVICE_TYPE_OTHER;
|
||||
}
|
||||
|
||||
String Utilities::get_video_adapter_api_version() const {
|
||||
return String::utf8((const char *)glGetString(GL_VERSION));
|
||||
}
|
||||
|
||||
Size2i Utilities::get_maximum_viewport_size() const {
|
||||
Config *config = Config::get_singleton();
|
||||
ERR_FAIL_NULL_V(config, Size2i());
|
||||
return Size2i(config->max_viewport_size[0], config->max_viewport_size[1]);
|
||||
}
|
||||
|
||||
uint32_t Utilities::get_maximum_shader_varyings() const {
|
||||
Config *config = Config::get_singleton();
|
||||
ERR_FAIL_NULL_V(config, 31);
|
||||
return config->max_shader_varyings;
|
||||
}
|
||||
|
||||
uint64_t Utilities::get_maximum_uniform_buffer_size() const {
|
||||
Config *config = Config::get_singleton();
|
||||
ERR_FAIL_NULL_V(config, 65536);
|
||||
return uint64_t(config->max_uniform_buffer_size);
|
||||
}
|
||||
|
||||
#endif // GLES3_ENABLED
|
234
drivers/gles3/storage/utilities.h
Normal file
234
drivers/gles3/storage/utilities.h
Normal file
@@ -0,0 +1,234 @@
|
||||
/**************************************************************************/
|
||||
/* utilities.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef GLES3_ENABLED
|
||||
|
||||
#include "servers/rendering/storage/utilities.h"
|
||||
|
||||
#include "platform_gl.h"
|
||||
|
||||
namespace GLES3 {
|
||||
|
||||
/* VISIBILITY NOTIFIER */
|
||||
|
||||
struct VisibilityNotifier {
|
||||
AABB aabb;
|
||||
Callable enter_callback;
|
||||
Callable exit_callback;
|
||||
Dependency dependency;
|
||||
};
|
||||
|
||||
class Utilities : public RendererUtilities {
|
||||
private:
|
||||
static Utilities *singleton;
|
||||
|
||||
/* VISIBILITY NOTIFIER */
|
||||
|
||||
mutable RID_Owner<VisibilityNotifier> visibility_notifier_owner;
|
||||
|
||||
/* MISC */
|
||||
|
||||
struct ResourceAllocation {
|
||||
#ifdef DEV_ENABLED
|
||||
String name;
|
||||
#endif
|
||||
uint32_t size = 0;
|
||||
};
|
||||
HashMap<GLuint, ResourceAllocation> buffer_allocs_cache;
|
||||
HashMap<GLuint, ResourceAllocation> render_buffer_allocs_cache;
|
||||
HashMap<GLuint, ResourceAllocation> texture_allocs_cache;
|
||||
|
||||
uint64_t buffer_mem_cache = 0;
|
||||
uint64_t render_buffer_mem_cache = 0;
|
||||
uint64_t texture_mem_cache = 0;
|
||||
|
||||
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);
|
||||
|
||||
// Allocate memory with glBufferData. Does not handle resizing.
|
||||
_FORCE_INLINE_ void buffer_allocate_data(GLenum p_target, GLuint p_id, uint32_t p_size, const void *p_data, GLenum p_usage, String p_name = "") {
|
||||
glBufferData(p_target, p_size, p_data, p_usage);
|
||||
buffer_mem_cache += p_size;
|
||||
|
||||
#ifdef DEV_ENABLED
|
||||
ERR_FAIL_COND_MSG(buffer_allocs_cache.has(p_id), "trying to allocate buffer with name " + p_name + " but ID already used by " + buffer_allocs_cache[p_id].name);
|
||||
#endif
|
||||
|
||||
ResourceAllocation resource_allocation;
|
||||
resource_allocation.size = p_size;
|
||||
#ifdef DEV_ENABLED
|
||||
resource_allocation.name = p_name + ": " + itos((uint64_t)p_id);
|
||||
#endif
|
||||
buffer_allocs_cache[p_id] = resource_allocation;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void buffer_free_data(GLuint p_id) {
|
||||
ERR_FAIL_COND(!buffer_allocs_cache.has(p_id));
|
||||
glDeleteBuffers(1, &p_id);
|
||||
buffer_mem_cache -= buffer_allocs_cache[p_id].size;
|
||||
buffer_allocs_cache.erase(p_id);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void render_buffer_allocated_data(GLuint p_id, uint32_t p_size, String p_name = "") {
|
||||
render_buffer_mem_cache += p_size;
|
||||
#ifdef DEV_ENABLED
|
||||
ERR_FAIL_COND_MSG(render_buffer_allocs_cache.has(p_id), "trying to allocate render buffer with name " + p_name + " but ID already used by " + render_buffer_allocs_cache[p_id].name);
|
||||
#endif
|
||||
ResourceAllocation resource_allocation;
|
||||
resource_allocation.size = p_size;
|
||||
#ifdef DEV_ENABLED
|
||||
resource_allocation.name = p_name + ": " + itos((uint64_t)p_id);
|
||||
#endif
|
||||
render_buffer_allocs_cache[p_id] = resource_allocation;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void render_buffer_free_data(GLuint p_id) {
|
||||
ERR_FAIL_COND(!render_buffer_allocs_cache.has(p_id));
|
||||
glDeleteRenderbuffers(1, &p_id);
|
||||
render_buffer_mem_cache -= render_buffer_allocs_cache[p_id].size;
|
||||
render_buffer_allocs_cache.erase(p_id);
|
||||
}
|
||||
|
||||
// Records that data was allocated for state tracking purposes.
|
||||
// Size is measured in bytes.
|
||||
_FORCE_INLINE_ void texture_allocated_data(GLuint p_id, uint32_t p_size, String p_name = "") {
|
||||
texture_mem_cache += p_size;
|
||||
#ifdef DEV_ENABLED
|
||||
ERR_FAIL_COND_MSG(texture_allocs_cache.has(p_id), "trying to allocate texture with name " + p_name + " but ID already used by " + texture_allocs_cache[p_id].name);
|
||||
#endif
|
||||
ResourceAllocation resource_allocation;
|
||||
resource_allocation.size = p_size;
|
||||
#ifdef DEV_ENABLED
|
||||
resource_allocation.name = p_name + ": " + itos((uint64_t)p_id);
|
||||
#endif
|
||||
texture_allocs_cache[p_id] = resource_allocation;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void texture_free_data(GLuint p_id) {
|
||||
ERR_FAIL_COND(!texture_allocs_cache.has(p_id));
|
||||
glDeleteTextures(1, &p_id);
|
||||
texture_mem_cache -= texture_allocs_cache[p_id].size;
|
||||
texture_allocs_cache.erase(p_id);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void texture_resize_data(GLuint p_id, uint32_t p_size) {
|
||||
ERR_FAIL_COND(!texture_allocs_cache.has(p_id));
|
||||
texture_mem_cache -= texture_allocs_cache[p_id].size;
|
||||
texture_mem_cache += p_size;
|
||||
texture_allocs_cache[p_id].size = p_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 */
|
||||
|
||||
VisibilityNotifier *get_visibility_notifier(RID p_rid) { return visibility_notifier_owner.get_or_null(p_rid); }
|
||||
bool owns_visibility_notifier(RID p_rid) const { return visibility_notifier_owner.owns(p_rid); }
|
||||
|
||||
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 */
|
||||
|
||||
#define MAX_QUERIES 256
|
||||
#define FRAME_COUNT 3
|
||||
|
||||
struct Frame {
|
||||
GLuint queries[MAX_QUERIES];
|
||||
TightLocalVector<String> timestamp_names;
|
||||
TightLocalVector<uint64_t> timestamp_cpu_values;
|
||||
uint32_t timestamp_count = 0;
|
||||
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;
|
||||
};
|
||||
|
||||
const uint32_t max_timestamp_query_elements = MAX_QUERIES;
|
||||
|
||||
Frame frames[FRAME_COUNT]; // Frames for capturing timestamps. We use 3 so we don't need to wait for commands to complete
|
||||
uint32_t frame = 0;
|
||||
|
||||
virtual void capture_timestamps_begin() override;
|
||||
virtual void capture_timestamp(const String &p_name) override;
|
||||
virtual uint32_t get_captured_timestamps_count() const override;
|
||||
virtual uint64_t get_captured_timestamps_frame() const override;
|
||||
virtual uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const override;
|
||||
virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const override;
|
||||
virtual String get_captured_timestamp_name(uint32_t p_index) const override;
|
||||
void _capture_timestamps_begin();
|
||||
void capture_timestamps_end();
|
||||
|
||||
/* 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;
|
||||
|
||||
virtual Size2i get_maximum_viewport_size() const override;
|
||||
virtual uint32_t get_maximum_shader_varyings() const override;
|
||||
virtual uint64_t get_maximum_uniform_buffer_size() const override;
|
||||
};
|
||||
|
||||
} // namespace GLES3
|
||||
|
||||
#endif // GLES3_ENABLED
|
Reference in New Issue
Block a user