Path: blob/master/drivers/gles3/effects/copy_effects.cpp
10005 views
/**************************************************************************/1/* copy_effects.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#ifdef GLES3_ENABLED3132#include "copy_effects.h"33#include "../storage/texture_storage.h"3435using namespace GLES3;3637CopyEffects *CopyEffects::singleton = nullptr;3839CopyEffects *CopyEffects::get_singleton() {40return singleton;41}4243CopyEffects::CopyEffects() {44singleton = this;4546copy.shader.initialize();47copy.shader_version = copy.shader.version_create();48copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_DEFAULT);4950{ // Screen Triangle.51glGenBuffers(1, &screen_triangle);52glBindBuffer(GL_ARRAY_BUFFER, screen_triangle);5354const float qv[6] = {55-1.0f,56-1.0f,573.0f,58-1.0f,59-1.0f,603.0f,61};6263glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6, qv, GL_STATIC_DRAW);64glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind6566glGenVertexArrays(1, &screen_triangle_array);67glBindVertexArray(screen_triangle_array);68glBindBuffer(GL_ARRAY_BUFFER, screen_triangle);69glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, nullptr);70glEnableVertexAttribArray(RS::ARRAY_VERTEX);71glBindVertexArray(0);72glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind73}7475{ // Screen Quad7677glGenBuffers(1, &quad);78glBindBuffer(GL_ARRAY_BUFFER, quad);7980const float qv[12] = {81-1.0f,82-1.0f,831.0f,84-1.0f,851.0f,861.0f,87-1.0f,88-1.0f,891.0f,901.0f,91-1.0f,921.0f,93};9495glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 12, qv, GL_STATIC_DRAW);96glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind9798glGenVertexArrays(1, &quad_array);99glBindVertexArray(quad_array);100glBindBuffer(GL_ARRAY_BUFFER, quad);101glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, nullptr);102glEnableVertexAttribArray(RS::ARRAY_VERTEX);103glBindVertexArray(0);104glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind105}106}107108CopyEffects::~CopyEffects() {109singleton = nullptr;110glDeleteBuffers(1, &screen_triangle);111glDeleteVertexArrays(1, &screen_triangle_array);112glDeleteBuffers(1, &quad);113glDeleteVertexArrays(1, &quad_array);114copy.shader.version_free(copy.shader_version);115}116117void CopyEffects::copy_to_rect(const Rect2 &p_rect, bool p_linear_to_srgb) {118uint64_t specializations = p_linear_to_srgb ? CopyShaderGLES3::CONVERT_LINEAR_TO_SRGB : 0;119120bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION, specializations);121if (!success) {122return;123}124125copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y, copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION, specializations);126draw_screen_quad();127}128129void CopyEffects::copy_to_rect_3d(const Rect2 &p_rect, float p_layer, int p_type, float p_lod, bool p_linear_to_srgb) {130ERR_FAIL_COND(p_type != Texture::TYPE_LAYERED && p_type != Texture::TYPE_3D);131132CopyShaderGLES3::ShaderVariant variant = p_type == Texture::TYPE_LAYERED133? CopyShaderGLES3::MODE_COPY_SECTION_2D_ARRAY134: CopyShaderGLES3::MODE_COPY_SECTION_3D;135uint64_t specializations = p_linear_to_srgb ? CopyShaderGLES3::CONVERT_LINEAR_TO_SRGB : 0;136137bool success = copy.shader.version_bind_shader(copy.shader_version, variant, specializations);138if (!success) {139return;140}141142copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y, copy.shader_version, variant, specializations);143copy.shader.version_set_uniform(CopyShaderGLES3::LAYER, p_layer, copy.shader_version, variant, specializations);144copy.shader.version_set_uniform(CopyShaderGLES3::LOD, p_lod, copy.shader_version, variant, specializations);145draw_screen_quad();146}147148void CopyEffects::copy_with_lens_distortion(const Rect2 &p_rect, float p_layer, const Vector2 &p_eye_center, float p_k1, float p_k2, float p_upscale, float p_aspect_ration, bool p_linear_to_srgb) {149CopyShaderGLES3::ShaderVariant variant = CopyShaderGLES3::MODE_LENS_DISTORTION;150151uint64_t specializations = p_linear_to_srgb ? CopyShaderGLES3::CONVERT_LINEAR_TO_SRGB : 0;152153bool success = copy.shader.version_bind_shader(copy.shader_version, variant, specializations);154if (!success) {155return;156}157158copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y, copy.shader_version, variant, specializations);159copy.shader.version_set_uniform(CopyShaderGLES3::LAYER, p_layer, copy.shader_version, variant, specializations);160copy.shader.version_set_uniform(CopyShaderGLES3::LOD, 0.0, copy.shader_version, variant, specializations);161copy.shader.version_set_uniform(CopyShaderGLES3::EYE_CENTER, p_eye_center.x, p_eye_center.y, copy.shader_version, variant, specializations);162copy.shader.version_set_uniform(CopyShaderGLES3::K1, p_k1, copy.shader_version, variant, specializations);163copy.shader.version_set_uniform(CopyShaderGLES3::K2, p_k1, copy.shader_version, variant, specializations);164copy.shader.version_set_uniform(CopyShaderGLES3::UPSCALE, p_upscale, copy.shader_version, variant, specializations);165copy.shader.version_set_uniform(CopyShaderGLES3::ASPECT_RATIO, p_aspect_ration, copy.shader_version, variant, specializations);166167draw_screen_quad();168}169170void CopyEffects::copy_to_and_from_rect(const Rect2 &p_rect) {171bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION_SOURCE);172if (!success) {173return;174}175176copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y, copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION_SOURCE);177copy.shader.version_set_uniform(CopyShaderGLES3::SOURCE_SECTION, p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y, copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION_SOURCE);178179draw_screen_quad();180}181182void CopyEffects::copy_screen(float p_multiply) {183bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_SCREEN);184if (!success) {185return;186}187188copy.shader.version_set_uniform(CopyShaderGLES3::MULTIPLY, p_multiply, copy.shader_version, CopyShaderGLES3::MODE_SCREEN);189190draw_screen_triangle();191}192193void CopyEffects::copy_cube_to_rect(const Rect2 &p_rect) {194bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_CUBE_TO_OCTAHEDRAL);195if (!success) {196return;197}198199copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y, copy.shader_version, CopyShaderGLES3::MODE_CUBE_TO_OCTAHEDRAL);200draw_screen_quad();201}202203void CopyEffects::copy_cube_to_panorama(float p_mip_level) {204bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_CUBE_TO_PANORAMA);205if (!success) {206return;207}208209copy.shader.version_set_uniform(CopyShaderGLES3::MIP_LEVEL, p_mip_level, copy.shader_version, CopyShaderGLES3::MODE_CUBE_TO_PANORAMA);210draw_screen_quad();211}212213// Intended for efficiently mipmapping textures.214void CopyEffects::bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region) {215GLuint framebuffers[2];216glGenFramebuffers(2, framebuffers);217glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffers[0]);218glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_source_texture, 0);219220Rect2i source_region = p_region;221Rect2i dest_region = p_region;222for (int i = 1; i < p_mipmap_count; i++) {223dest_region.position.x >>= 1;224dest_region.position.y >>= 1;225dest_region.size = Size2i(dest_region.size.x >> 1, dest_region.size.y >> 1).maxi(1);226glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffers[i % 2]);227glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_source_texture, i);228glBlitFramebuffer(source_region.position.x, source_region.position.y, source_region.position.x + source_region.size.x, source_region.position.y + source_region.size.y,229dest_region.position.x, dest_region.position.y, dest_region.position.x + dest_region.size.x, dest_region.position.y + dest_region.size.y, GL_COLOR_BUFFER_BIT, GL_LINEAR);230glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffers[i % 2]);231source_region = dest_region;232}233glBindFramebuffer(GL_READ_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);234glBindFramebuffer(GL_DRAW_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);235glDeleteFramebuffers(2, framebuffers);236}237238// Intended for approximating a gaussian blur. Used for 2D backbuffer mipmaps. Slightly less efficient than bilinear_blur().239void CopyEffects::gaussian_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region, const Size2i &p_size) {240GLuint framebuffer;241glGenFramebuffers(1, &framebuffer);242glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);243244glActiveTexture(GL_TEXTURE0);245glBindTexture(GL_TEXTURE_2D, p_source_texture);246glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);247glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);248glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);249glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);250251Size2i base_size = p_size;252253Rect2i source_region = p_region;254Rect2i dest_region = p_region;255256Size2 float_size = Size2(p_size);257Rect2 normalized_source_region = Rect2(p_region);258normalized_source_region.position = normalized_source_region.position / float_size;259normalized_source_region.size = normalized_source_region.size / float_size;260Rect2 normalized_dest_region = Rect2(p_region);261for (int i = 1; i < p_mipmap_count; i++) {262dest_region.position.x >>= 1;263dest_region.position.y >>= 1;264dest_region.size = Size2i(dest_region.size.x >> 1, dest_region.size.y >> 1).maxi(1);265base_size.x >>= 1;266base_size.y >>= 1;267268glBindTexture(GL_TEXTURE_2D, p_source_texture);269glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, i - 1);270glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, i);271glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_source_texture, i);272#ifdef DEV_ENABLED273GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);274if (status != GL_FRAMEBUFFER_COMPLETE) {275WARN_PRINT("Could not bind Gaussian blur framebuffer, status: " + GLES3::TextureStorage::get_singleton()->get_framebuffer_error(status));276}277#endif278279glViewport(0, 0, base_size.x, base_size.y);280281bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_GAUSSIAN_BLUR);282if (!success) {283return;284}285286float_size = Size2(base_size);287normalized_dest_region.position = Size2(dest_region.position) / float_size;288normalized_dest_region.size = Size2(dest_region.size) / float_size;289290copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, normalized_dest_region.position.x, normalized_dest_region.position.y, normalized_dest_region.size.x, normalized_dest_region.size.y, copy.shader_version, CopyShaderGLES3::MODE_GAUSSIAN_BLUR);291copy.shader.version_set_uniform(CopyShaderGLES3::SOURCE_SECTION, normalized_source_region.position.x, normalized_source_region.position.y, normalized_source_region.size.x, normalized_source_region.size.y, copy.shader_version, CopyShaderGLES3::MODE_GAUSSIAN_BLUR);292copy.shader.version_set_uniform(CopyShaderGLES3::PIXEL_SIZE, 1.0 / float_size.x, 1.0 / float_size.y, copy.shader_version, CopyShaderGLES3::MODE_GAUSSIAN_BLUR);293294draw_screen_quad();295296source_region = dest_region;297normalized_source_region = normalized_dest_region;298}299glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);300glDeleteFramebuffers(1, &framebuffer);301302glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);303glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);304glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);305glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, p_mipmap_count - 1);306glBindTexture(GL_TEXTURE_2D, 0);307308glViewport(0, 0, p_size.x, p_size.y);309}310311void CopyEffects::set_color(const Color &p_color, const Rect2i &p_region) {312bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_SIMPLE_COLOR);313if (!success) {314return;315}316317copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_region.position.x, p_region.position.y, p_region.size.x, p_region.size.y, copy.shader_version, CopyShaderGLES3::MODE_SIMPLE_COLOR);318copy.shader.version_set_uniform(CopyShaderGLES3::COLOR_IN, p_color, copy.shader_version, CopyShaderGLES3::MODE_SIMPLE_COLOR);319draw_screen_quad();320}321322void CopyEffects::draw_screen_triangle() {323glBindVertexArray(screen_triangle_array);324glDrawArrays(GL_TRIANGLES, 0, 3);325glBindVertexArray(0);326}327328void CopyEffects::draw_screen_quad() {329glBindVertexArray(quad_array);330glDrawArrays(GL_TRIANGLES, 0, 6);331glBindVertexArray(0);332}333334#endif // GLES3_ENABLED335336337