summaryrefslogtreecommitdiff
path: root/drivers/gles2
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gles2')
-rw-r--r--drivers/gles2/rasterizer_gles2.cpp4
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.cpp92
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.h2
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.cpp279
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.h12
-rw-r--r--drivers/gles2/shaders/scene.glsl42
6 files changed, 345 insertions, 86 deletions
diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp
index d3c6b041a8..f49f52e47b 100644
--- a/drivers/gles2/rasterizer_gles2.cpp
+++ b/drivers/gles2/rasterizer_gles2.cpp
@@ -202,6 +202,10 @@ Error RasterizerGLES2::is_viable() {
return ERR_UNAVAILABLE;
}
}
+
+ if (GLAD_GL_EXT_framebuffer_multisample) {
+ glRenderbufferStorageMultisample = glRenderbufferStorageMultisampleEXT;
+ }
#endif // GLES_OVER_GL
#endif // GLAD_ENABLED
diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp
index 99eb0665d6..3b3fbf9ed5 100644
--- a/drivers/gles2/rasterizer_scene_gles2.cpp
+++ b/drivers/gles2/rasterizer_scene_gles2.cpp
@@ -42,6 +42,16 @@
#define glClearDepth glClearDepthf
#endif
+#ifndef GLES_OVER_GL
+#ifdef IPHONE_ENABLED
+#include <OpenGLES/ES2/glext.h>
+//void *glResolveMultisampleFramebufferAPPLE;
+
+#define GL_READ_FRAMEBUFFER 0x8CA8
+#define GL_DRAW_FRAMEBUFFER 0x8CA9
+#endif
+#endif
+
static const GLenum _cube_side_enum[6] = {
GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
@@ -1148,6 +1158,30 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G
}
}
+void RasterizerSceneGLES2::_copy_texture_to_front_buffer(GLuint p_texture) {
+
+ //copy to front buffer
+ glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo);
+
+ glDepthMask(GL_FALSE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_BLEND);
+ glDepthFunc(GL_LEQUAL);
+ glColorMask(1, 1, 1, 1);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, p_texture);
+
+ glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height);
+
+ storage->shaders.copy.bind();
+
+ storage->bind_quad_array();
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
+
void RasterizerSceneGLES2::_fill_render_list(InstanceBase **p_cull_result, int p_cull_count, bool p_depth_pass, bool p_shadow_pass) {
render_pass++;
@@ -2435,6 +2469,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
if (p_env) {
state.scene_shader.set_uniform(SceneShaderGLES2::BG_ENERGY, p_env->bg_energy);
+ state.scene_shader.set_uniform(SceneShaderGLES2::BG_COLOR, p_env->bg_color);
state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_SKY_CONTRIBUTION, p_env->ambient_sky_contribution);
state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_COLOR, p_env->ambient_color);
@@ -2442,6 +2477,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
} else {
state.scene_shader.set_uniform(SceneShaderGLES2::BG_ENERGY, 1.0);
+ state.scene_shader.set_uniform(SceneShaderGLES2::BG_COLOR, state.default_bg);
state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_SKY_CONTRIBUTION, 1.0);
state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_COLOR, state.default_ambient);
state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_ENERGY, 1.0);
@@ -2544,7 +2580,6 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTMAP_CAPTURE, false);
state.scene_shader.set_conditional(SceneShaderGLES2::FOG_DEPTH_ENABLED, false);
state.scene_shader.set_conditional(SceneShaderGLES2::FOG_HEIGHT_ENABLED, false);
- state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, false);
state.scene_shader.set_conditional(SceneShaderGLES2::USE_DEPTH_PREPASS, false);
}
@@ -2689,7 +2724,11 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
if (storage->frame.current_rt->external.fbo != 0) {
current_fb = storage->frame.current_rt->external.fbo;
} else {
- current_fb = storage->frame.current_rt->fbo;
+ if (storage->frame.current_rt->multisample_active) {
+ current_fb = storage->frame.current_rt->multisample_fbo;
+ } else {
+ current_fb = storage->frame.current_rt->fbo;
+ }
}
env = environment_owner.getornull(p_environment);
@@ -2791,6 +2830,7 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
}
state.default_ambient = Color(clear_color.r, clear_color.g, clear_color.b, 1.0);
+ state.default_bg = Color(clear_color.r, clear_color.g, clear_color.b, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@@ -2830,6 +2870,7 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
if (probe_interior) {
env_radiance_tex = 0; //do not use radiance texture on interiors
state.default_ambient = Color(0, 0, 0, 1); //black as default ambient for interior
+ state.default_bg = Color(0, 0, 0, 1); //black as default background for interior
}
// render opaque things first
@@ -2838,7 +2879,38 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
if (storage->frame.current_rt && state.used_screen_texture) {
//copy screen texture
+
+ if (storage->frame.current_rt && storage->frame.current_rt->multisample_active) {
+ // Resolve framebuffer to front buffer before copying
+#ifdef GLES_OVER_GL
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->multisample_fbo);
+ glReadBuffer(GL_COLOR_ATTACHMENT0);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->fbo);
+ glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+#elif IPHONE_ENABLED
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->multisample_fbo);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->fbo);
+ glResolveMultisampleFramebufferAPPLE();
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+#else
+ // In GLES2 Blit is not available, so just copy color texture manually
+ _copy_texture_to_front_buffer(storage->frame.current_rt->multisample_color);
+#endif
+ }
+
storage->canvas->_copy_screen(Rect2());
+
+ if (storage->frame.current_rt && storage->frame.current_rt->multisample_active) {
+ // Rebind the current framebuffer
+ glBindFramebuffer(GL_FRAMEBUFFER, current_fb);
+ glViewport(0, 0, viewport_width, viewport_height);
+ }
}
// alpha pass
@@ -2851,6 +2923,22 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
glDisable(GL_DEPTH_TEST);
+ if (storage->frame.current_rt && storage->frame.current_rt->multisample_active) {
+#ifdef GLES_OVER_GL
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->multisample_fbo);
+ glReadBuffer(GL_COLOR_ATTACHMENT0);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->fbo);
+ glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+#else
+ // In GLES2 Blit is not available, so just copy color texture manually
+ _copy_texture_to_front_buffer(storage->frame.current_rt->multisample_color);
+#endif
+ }
+
//#define GLES2_SHADOW_ATLAS_DEBUG_VIEW
#ifdef GLES2_SHADOW_ATLAS_DEBUG_VIEW
diff --git a/drivers/gles2/rasterizer_scene_gles2.h b/drivers/gles2/rasterizer_scene_gles2.h
index 48672991d1..d805984dca 100644
--- a/drivers/gles2/rasterizer_scene_gles2.h
+++ b/drivers/gles2/rasterizer_scene_gles2.h
@@ -104,6 +104,7 @@ public:
GLuint immediate_buffer;
Color default_ambient;
+ Color default_bg;
// ResolveShaderGLES3 resolve_shader;
// ScreenSpaceReflectionShaderGLES3 ssr_shader;
@@ -670,6 +671,7 @@ public:
void _add_geometry(RasterizerStorageGLES2::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES2::GeometryOwner *p_owner, int p_material, bool p_depth_pass, bool p_shadow_pass);
void _add_geometry_with_material(RasterizerStorageGLES2::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES2::GeometryOwner *p_owner, RasterizerStorageGLES2::Material *p_material, bool p_depth_pass, bool p_shadow_pass);
+ void _copy_texture_to_front_buffer(GLuint texture);
void _fill_render_list(InstanceBase **p_cull_result, int p_cull_count, bool p_depth_pass, bool p_shadow_pass);
void _render_render_list(RenderList::Element **p_elements, int p_element_count,
const Transform &p_view_transform,
diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp
index 13fdd1db73..d709056709 100644
--- a/drivers/gles2/rasterizer_storage_gles2.cpp
+++ b/drivers/gles2/rasterizer_storage_gles2.cpp
@@ -81,6 +81,28 @@ GLuint RasterizerStorageGLES2::system_fbo = 0;
#define _DEPTH_COMPONENT24_OES 0x81A6
+#ifndef GLES_OVER_GL
+// enable extensions manually for android and ios
+#include <dlfcn.h> // needed to load extensions
+
+#ifdef IPHONE_ENABLED
+
+#include <OpenGLES/ES2/glext.h>
+//void *glRenderbufferStorageMultisampleAPPLE;
+//void *glResolveMultisampleFramebufferAPPLE;
+#define glRenderbufferStorageMultisample glRenderbufferStorageMultisampleAPPLE
+#else
+
+#include <GLES2/gl2ext.h>
+PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT;
+PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC glFramebufferTexture2DMultisampleEXT;
+#define glRenderbufferStorageMultisample glRenderbufferStorageMultisampleEXT
+#define glFramebufferTexture2DMultisample glFramebufferTexture2DMultisampleEXT
+#endif
+
+#define GL_MAX_SAMPLES 0x8D57
+#endif //!GLES_OVER_GL
+
void RasterizerStorageGLES2::bind_quad_array() const {
glBindBuffer(GL_ARRAY_BUFFER, resources.quadie);
glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0);
@@ -774,10 +796,7 @@ Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, int p_layer)
for (int i = 0; i < texture->mipmaps; i++) {
- int ofs = 0;
- if (i > 0) {
- ofs = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, real_format, i - 1);
- }
+ int ofs = Image::get_image_mipmap_offset(texture->alloc_width, texture->alloc_height, real_format, i);
if (texture->compressed) {
glPixelStorei(GL_PACK_ALIGNMENT, 4);
@@ -4552,95 +4571,174 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) {
if (rt->width <= 0 || rt->height <= 0)
return;
- Texture *texture = texture_owner.getornull(rt->texture);
- ERR_FAIL_COND(!texture);
-
- // create fbo
-
- glGenFramebuffers(1, &rt->fbo);
- glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
-
- // color
-
- glGenTextures(1, &rt->color);
- glBindTexture(GL_TEXTURE_2D, rt->color);
+ GLuint color_internal_format;
+ GLuint color_format;
+ GLuint color_type = GL_UNSIGNED_BYTE;
if (rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) {
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rt->width, rt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ color_internal_format = GL_RGBA;
+ color_format = GL_RGBA;
} else {
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, rt->width, rt->height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
+ color_internal_format = GL_RGB;
+ color_format = GL_RGB;
}
- if (texture->flags & VS::TEXTURE_FLAG_FILTER) {
+ {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- } else {
+ /* Front FBO */
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- }
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ Texture *texture = texture_owner.getornull(rt->texture);
+ ERR_FAIL_COND(!texture);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
+ // framebuffer
+ glGenFramebuffers(1, &rt->fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
- // depth
+ // color
+ glGenTextures(1, &rt->color);
+ glBindTexture(GL_TEXTURE_2D, rt->color);
- if (config.support_depth_texture) {
- glGenTextures(1, &rt->depth);
- glBindTexture(GL_TEXTURE_2D, rt->depth);
- glTexImage2D(GL_TEXTURE_2D, 0, config.depth_internalformat, rt->width, rt->height, 0, GL_DEPTH_COMPONENT, config.depth_type, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, rt->width, rt->height, 0, color_format, color_type, NULL);
- 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);
+ if (texture->flags & VS::TEXTURE_FLAG_FILTER) {
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0);
- } else {
- glGenRenderbuffers(1, &rt->depth);
- glBindRenderbuffer(GL_RENDERBUFFER, rt->depth);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ } else {
- glRenderbufferStorage(GL_RENDERBUFFER, config.depth_internalformat, rt->width, rt->height);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ }
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth);
- }
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
- if (status != GL_FRAMEBUFFER_COMPLETE) {
+ // depth
- glDeleteFramebuffers(1, &rt->fbo);
if (config.support_depth_texture) {
- glDeleteTextures(1, &rt->depth);
+
+ glGenTextures(1, &rt->depth);
+ glBindTexture(GL_TEXTURE_2D, rt->depth);
+ glTexImage2D(GL_TEXTURE_2D, 0, config.depth_internalformat, rt->width, rt->height, 0, GL_DEPTH_COMPONENT, config.depth_type, NULL);
+
+ 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);
+
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0);
} else {
- glDeleteRenderbuffers(1, &rt->depth);
+
+ glGenRenderbuffers(1, &rt->depth);
+ glBindRenderbuffer(GL_RENDERBUFFER, rt->depth);
+
+ glRenderbufferStorage(GL_RENDERBUFFER, config.depth_internalformat, rt->width, rt->height);
+
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth);
}
- glDeleteTextures(1, &rt->color);
- rt->fbo = 0;
- rt->width = 0;
- rt->height = 0;
- rt->color = 0;
- rt->depth = 0;
- texture->tex_id = 0;
- texture->active = false;
- WARN_PRINT("Could not create framebuffer!!");
- return;
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+
+ glDeleteFramebuffers(1, &rt->fbo);
+ if (config.support_depth_texture) {
+
+ glDeleteTextures(1, &rt->depth);
+ } else {
+
+ glDeleteRenderbuffers(1, &rt->depth);
+ }
+
+ glDeleteTextures(1, &rt->color);
+ rt->fbo = 0;
+ rt->width = 0;
+ rt->height = 0;
+ rt->color = 0;
+ rt->depth = 0;
+ texture->tex_id = 0;
+ texture->active = false;
+ WARN_PRINT("Could not create framebuffer!!");
+ return;
+ }
+
+ texture->format = Image::FORMAT_RGBA8;
+ texture->gl_format_cache = GL_RGBA;
+ texture->gl_type_cache = GL_UNSIGNED_BYTE;
+ texture->gl_internal_format_cache = GL_RGBA;
+ texture->tex_id = rt->color;
+ texture->width = rt->width;
+ texture->alloc_width = rt->width;
+ texture->height = rt->height;
+ texture->alloc_height = rt->height;
+ texture->active = true;
+
+ texture_set_flags(rt->texture, texture->flags);
}
- texture->format = Image::FORMAT_RGBA8;
- texture->gl_format_cache = GL_RGBA;
- texture->gl_type_cache = GL_UNSIGNED_BYTE;
- texture->gl_internal_format_cache = GL_RGBA;
- texture->tex_id = rt->color;
- texture->width = rt->width;
- texture->alloc_width = rt->width;
- texture->height = rt->height;
- texture->alloc_height = rt->height;
- texture->active = true;
+ /* BACK FBO */
+ /* For MSAA */
+
+ if (rt->msaa != VS::VIEWPORT_MSAA_DISABLED && config.multisample_supported) {
+
+ rt->multisample_active = true;
+
+ static const int msaa_value[] = { 0, 2, 4, 8, 16 };
+ int msaa = msaa_value[rt->msaa];
+
+ int max_samples = 0;
+ glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
+ if (msaa > max_samples) {
+ WARN_PRINTS("MSAA must be <= GL_MAX_SAMPLES, falling-back to GL_MAX_SAMPLES = " + itos(max_samples));
+ msaa = max_samples;
+ }
- texture_set_flags(rt->texture, texture->flags);
+ //regular fbo
+ glGenFramebuffers(1, &rt->multisample_fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->multisample_fbo);
+
+ glGenRenderbuffers(1, &rt->multisample_depth);
+ glBindRenderbuffer(GL_RENDERBUFFER, rt->multisample_depth);
+ glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, config.depth_internalformat, rt->width, rt->height);
+
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->multisample_depth);
+
+#if defined(GLES_OVER_GL) || defined(IPHONE_ENABLED)
+
+ glGenRenderbuffers(1, &rt->multisample_color);
+ glBindRenderbuffer(GL_RENDERBUFFER, rt->multisample_color);
+ glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, color_internal_format, rt->width, rt->height);
+
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rt->multisample_color);
+#else
+ // Render to a texture in android
+ glGenTextures(1, &rt->multisample_color);
+ glBindTexture(GL_TEXTURE_2D, rt->multisample_color);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, rt->width, rt->height, 0, color_format, color_type, NULL);
+
+ // multisample buffer is same size as front buffer, so just use nearest
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+ glFramebufferTexture2DMultisample(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0, msaa);
+#endif
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ printf("err status: %x\n", status);
+ _render_target_clear(rt);
+ ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE);
+ }
+
+ glBindRenderbuffer(GL_RENDERBUFFER, 0);
+
+ } else {
+ rt->multisample_active = false;
+ }
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@@ -4669,7 +4767,7 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) {
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
- status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
_render_target_clear(rt);
ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE);
@@ -4728,6 +4826,20 @@ void RasterizerStorageGLES2::_render_target_clear(RenderTarget *rt) {
glDeleteTextures(1, &rt->copy_screen_effect.color);
rt->copy_screen_effect.color = 0;
}
+
+ if (rt->multisample_active) {
+ glDeleteFramebuffers(1, &rt->multisample_fbo);
+ rt->multisample_fbo = 0;
+
+ glDeleteRenderbuffers(1, &rt->multisample_depth);
+ rt->multisample_depth = 0;
+#ifdef GLES_OVER_GL
+ glDeleteRenderbuffers(1, &rt->multisample_color);
+#else
+ glDeleteTextures(1, &rt->multisample_color);
+#endif
+ rt->multisample_color = 0;
+ }
}
RID RasterizerStorageGLES2::render_target_create() {
@@ -4929,6 +5041,11 @@ void RasterizerStorageGLES2::render_target_set_msaa(RID p_render_target, VS::Vie
if (rt->msaa == p_msaa)
return;
+ if (!config.multisample_supported) {
+ ERR_PRINT("MSAA not supported on this hardware.");
+ return;
+ }
+
_render_target_clear(rt);
rt->msaa = p_msaa;
_render_target_allocate(rt);
@@ -5452,6 +5569,26 @@ void RasterizerStorageGLES2::initialize() {
config.support_npot_repeat_mipmap = config.extensions.has("GL_OES_texture_npot");
#endif
+
+#ifndef GLES_OVER_GL
+ //Manually load extensions for android and ios
+
+#ifdef IPHONE_ENABLED
+
+ //void *gles2_lib = dlopen(NULL, RTLD_LAZY);
+ //glRenderbufferStorageMultisampleAPPLE = dlsym(gles2_lib, "glRenderbufferStorageMultisampleAPPLE");
+ //glResolveMultisampleFramebufferAPPLE = dlsym(gles2_lib, "glResolveMultisampleFramebufferAPPLE");
+#else
+
+ void *gles2_lib = dlopen("libGLESv2.so", RTLD_LAZY);
+ glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)dlsym(gles2_lib, "glRenderbufferStorageMultisampleEXT");
+ glFramebufferTexture2DMultisampleEXT = (PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC)dlsym(gles2_lib, "glFramebufferTexture2DMultisampleEXT");
+#endif
+#endif
+
+ // Check for multisample support
+ config.multisample_supported = config.extensions.has("GL_EXT_framebuffer_multisample") || config.extensions.has("GL_EXT_multisampled_render_to_texture") || config.extensions.has("GL_APPLE_framebuffer_multisample");
+
#ifdef GLES_OVER_GL
config.use_rgba_2d_shadows = false;
config.support_depth_texture = true;
diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h
index d6130849fb..3134082e2a 100644
--- a/drivers/gles2/rasterizer_storage_gles2.h
+++ b/drivers/gles2/rasterizer_storage_gles2.h
@@ -92,6 +92,8 @@ public:
bool support_shadow_cubemaps;
+ bool multisample_supported;
+
GLuint depth_internalformat;
GLuint depth_type;
@@ -1132,10 +1134,14 @@ public:
struct RenderTarget : public RID_Data {
GLuint fbo;
-
GLuint color;
GLuint depth;
+ GLuint multisample_fbo;
+ GLuint multisample_color;
+ GLuint multisample_depth;
+ bool multisample_active;
+
// TODO post processing effects?
// TODO HDR?
@@ -1182,6 +1188,10 @@ public:
fbo(0),
color(0),
depth(0),
+ multisample_fbo(0),
+ multisample_color(0),
+ multisample_depth(0),
+ multisample_active(false),
width(0),
height(0),
used_in_frame(false),
diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl
index 1c35b455c4..0fa290e57c 100644
--- a/drivers/gles2/shaders/scene.glsl
+++ b/drivers/gles2/shaders/scene.glsl
@@ -424,9 +424,12 @@ void main() {
#endif
+ mat4 local_projection_matrix = projection_matrix;
+
mat4 modelview = camera_inverse_matrix * world_matrix;
float roughness = 1.0;
+#define projection_matrix local_projection_matrix
#define world_transform world_matrix
{
@@ -911,6 +914,7 @@ uniform mat4 radiance_inverse_xform;
#endif
+uniform vec4 bg_color;
uniform float bg_energy;
uniform float ambient_sky_contribution;
@@ -1558,7 +1562,6 @@ FRAGMENT_SHADER_CODE
ref_vec.z *= -1.0;
specular_light = textureCubeLod(radiance_map, ref_vec, roughness * RADIANCE_MAX_LOD).xyz * bg_energy;
-
{
vec3 ambient_dir = normalize((radiance_inverse_xform * vec4(normal, 0.0)).xyz);
vec3 env_ambient = textureCubeLod(radiance_map, ambient_dir, RADIANCE_MAX_LOD).xyz * bg_energy;
@@ -1569,6 +1572,7 @@ FRAGMENT_SHADER_CODE
#else
ambient_light = ambient_color.rgb;
+ specular_light = bg_color.rgb * bg_energy;
#endif
@@ -1628,6 +1632,19 @@ FRAGMENT_SHADER_CODE
#endif // defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2)
+ // scales the specular reflections, needs to be be computed before lighting happens,
+ // but after environment and reflection probes are added
+ //TODO: this curve is not really designed for gammaspace, should be adjusted
+ const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
+ const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
+ vec4 r = roughness * c0 + c1;
+ float ndotv = clamp(dot(normal, eye_position), 0.0, 1.0);
+ float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y;
+ vec2 env = vec2(-1.04, 1.04) * a004 + r.zw;
+
+ vec3 f0 = F0(metallic, specular, albedo);
+ specular_light *= env.x * f0 + env.y;
+
#ifdef USE_LIGHTMAP
//ambient light will come entirely from lightmap is lightmap is used
ambient_light = texture2D(lightmap, uv2_interp).rgb * lightmap_energy;
@@ -1699,6 +1716,8 @@ FRAGMENT_SHADER_CODE
#endif
+#if !defined(SHADOWS_DISABLED)
+
#ifdef USE_SHADOW
{
highp vec4 splane = shadow_coord;
@@ -1729,6 +1748,8 @@ FRAGMENT_SHADER_CODE
}
#endif
+#endif //SHADOWS_DISABLED
+
#endif //type omni
#ifdef LIGHT_MODE_DIRECTIONAL
@@ -1739,6 +1760,8 @@ FRAGMENT_SHADER_CODE
#endif
float depth_z = -vertex.z;
+#if !defined(SHADOWS_DISABLED)
+
#ifdef USE_SHADOW
#ifdef USE_VERTEX_LIGHTING
@@ -1957,6 +1980,8 @@ FRAGMENT_SHADER_CODE
#endif //use shadow
+#endif // SHADOWS_DISABLED
+
#endif
#ifdef LIGHT_MODE_SPOT
@@ -1993,6 +2018,8 @@ FRAGMENT_SHADER_CODE
#endif
+#if !defined(SHADOWS_DISABLED)
+
#ifdef USE_SHADOW
{
highp vec4 splane = shadow_coord;
@@ -2002,6 +2029,8 @@ FRAGMENT_SHADER_CODE
}
#endif
+#endif // SHADOWS_DISABLED
+
#endif // LIGHT_MODE_SPOT
#ifdef USE_VERTEX_LIGHTING
@@ -2065,17 +2094,6 @@ FRAGMENT_SHADER_CODE
#if defined(DIFFUSE_TOON)
//simplify for toon, as
specular_light *= specular * metallic * albedo * 2.0;
-#else
- //TODO: this curve is not really designed for gammaspace, should be adjusted
- const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
- const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
- vec4 r = roughness * c0 + c1;
- float ndotv = clamp(dot(normal, eye_position), 0.0, 1.0);
- float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y;
- vec2 env = vec2(-1.04, 1.04) * a004 + r.zw;
-
- vec3 f0 = F0(metallic, specular, albedo);
- specular_light *= env.x * f0 + env.y;
#endif
}