2022-03-12 11:19:59 +00:00
/*************************************************************************/
/* texture_storage.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
# ifdef GLES3_ENABLED
# include "texture_storage.h"
# include "config.h"
using namespace GLES3 ;
TextureStorage * TextureStorage : : singleton = nullptr ;
TextureStorage * TextureStorage : : get_singleton ( ) {
return singleton ;
}
TextureStorage : : TextureStorage ( ) {
singleton = this ;
2022-04-07 14:00:51 +00:00
system_fbo = 0 ;
frame . count = 0 ;
frame . delta = 0 ;
frame . current_rt = nullptr ;
frame . clear_request = false ;
Config * config = Config : : get_singleton ( ) ;
//determine formats for depth textures (or renderbuffers)
if ( config - > support_depth_texture ) {
// Will use texture for depth
// have to manually see if we can create a valid framebuffer texture using UNSIGNED_INT,
// as there is no extension to test for this.
GLuint fbo ;
glGenFramebuffers ( 1 , & fbo ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , fbo ) ;
GLuint depth ;
glGenTextures ( 1 , & depth ) ;
glBindTexture ( GL_TEXTURE_2D , depth ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , config - > depth_internalformat , 32 , 32 , 0 , GL_DEPTH_COMPONENT , config - > depth_type , 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 ) ;
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_TEXTURE_2D , depth , 0 ) ;
GLenum status = glCheckFramebufferStatus ( GL_FRAMEBUFFER ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , GLES3 : : TextureStorage : : system_fbo ) ;
glDeleteFramebuffers ( 1 , & fbo ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
glDeleteTextures ( 1 , & depth ) ;
if ( status ! = GL_FRAMEBUFFER_COMPLETE ) {
// If it fails, test to see if it supports a framebuffer texture using UNSIGNED_SHORT
// This is needed because many OSX devices don't support either UNSIGNED_INT or UNSIGNED_SHORT
# ifdef GLES_OVER_GL
config - > depth_internalformat = GL_DEPTH_COMPONENT16 ;
# else
// OES_depth_texture extension only specifies GL_DEPTH_COMPONENT.
config - > depth_internalformat = GL_DEPTH_COMPONENT ;
# endif
config - > depth_type = GL_UNSIGNED_SHORT ;
glGenFramebuffers ( 1 , & fbo ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , fbo ) ;
glGenTextures ( 1 , & depth ) ;
glBindTexture ( GL_TEXTURE_2D , depth ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , config - > depth_internalformat , 32 , 32 , 0 , GL_DEPTH_COMPONENT , GL_UNSIGNED_SHORT , 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 ) ;
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_TEXTURE_2D , depth , 0 ) ;
status = glCheckFramebufferStatus ( GL_FRAMEBUFFER ) ;
if ( status ! = GL_FRAMEBUFFER_COMPLETE ) {
//if it fails again depth textures aren't supported, use rgba shadows and renderbuffer for depth
config - > support_depth_texture = false ;
config - > use_rgba_3d_shadows = true ;
}
glBindFramebuffer ( GL_FRAMEBUFFER , GLES3 : : TextureStorage : : system_fbo ) ;
glDeleteFramebuffers ( 1 , & fbo ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
glDeleteTextures ( 1 , & depth ) ;
}
}
2022-03-12 11:19:59 +00:00
}
TextureStorage : : ~ TextureStorage ( ) {
singleton = nullptr ;
}
void TextureStorage : : set_main_thread_id ( Thread : : ID p_id ) {
_main_thread_id = p_id ;
}
bool TextureStorage : : _is_main_thread ( ) {
//#if defined DEBUG_ENABLED && defined TOOLS_ENABLED
// must be called from main thread in OpenGL
bool is_main_thread = _main_thread_id = = Thread : : get_caller_id ( ) ;
//#endif
return is_main_thread ;
}
bool TextureStorage : : can_create_resources_async ( ) const {
return false ;
}
2022-04-07 14:00:51 +00:00
/* Canvas Texture API */
RID TextureStorage : : canvas_texture_allocate ( ) {
return canvas_texture_owner . allocate_rid ( ) ;
}
void TextureStorage : : canvas_texture_initialize ( RID p_rid ) {
canvas_texture_owner . initialize_rid ( p_rid ) ;
}
void TextureStorage : : canvas_texture_free ( RID p_rid ) {
canvas_texture_owner . free ( p_rid ) ;
}
void TextureStorage : : canvas_texture_set_channel ( RID p_canvas_texture , RS : : CanvasTextureChannel p_channel , RID p_texture ) {
CanvasTexture * ct = canvas_texture_owner . get_or_null ( p_canvas_texture ) ;
switch ( p_channel ) {
case RS : : CANVAS_TEXTURE_CHANNEL_DIFFUSE : {
ct - > diffuse = p_texture ;
} break ;
case RS : : CANVAS_TEXTURE_CHANNEL_NORMAL : {
ct - > normal_map = p_texture ;
} break ;
case RS : : CANVAS_TEXTURE_CHANNEL_SPECULAR : {
ct - > specular = p_texture ;
} break ;
}
}
void TextureStorage : : canvas_texture_set_shading_parameters ( RID p_canvas_texture , const Color & p_specular_color , float p_shininess ) {
CanvasTexture * ct = canvas_texture_owner . get_or_null ( p_canvas_texture ) ;
ct - > specular_color . r = p_specular_color . r ;
ct - > specular_color . g = p_specular_color . g ;
ct - > specular_color . b = p_specular_color . b ;
ct - > specular_color . a = p_shininess ;
}
void TextureStorage : : canvas_texture_set_texture_filter ( RID p_canvas_texture , RS : : CanvasItemTextureFilter p_filter ) {
CanvasTexture * ct = canvas_texture_owner . get_or_null ( p_canvas_texture ) ;
ct - > texture_filter = p_filter ;
}
void TextureStorage : : canvas_texture_set_texture_repeat ( RID p_canvas_texture , RS : : CanvasItemTextureRepeat p_repeat ) {
CanvasTexture * ct = canvas_texture_owner . get_or_null ( p_canvas_texture ) ;
ct - > texture_repeat = p_repeat ;
}
/* Texture API */
2022-03-12 11:19:59 +00:00
static const GLenum _cube_side_enum [ 6 ] = {
GL_TEXTURE_CUBE_MAP_NEGATIVE_X ,
GL_TEXTURE_CUBE_MAP_POSITIVE_X ,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y ,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y ,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z ,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z ,
} ;
Ref < Image > TextureStorage : : _get_gl_image_and_format ( const Ref < Image > & p_image , Image : : Format p_format , uint32_t p_flags , 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 {
Config * config = Config : : get_singleton ( ) ;
r_gl_format = 0 ;
Ref < Image > image = p_image ;
r_compressed = false ;
r_real_format = p_format ;
bool need_decompress = false ;
switch ( p_format ) {
case Image : : FORMAT_L8 : {
# ifdef GLES_OVER_GL
r_gl_internal_format = GL_R8 ;
r_gl_format = GL_RED ;
r_gl_type = GL_UNSIGNED_BYTE ;
# else
r_gl_internal_format = GL_LUMINANCE ;
r_gl_format = GL_LUMINANCE ;
r_gl_type = GL_UNSIGNED_BYTE ;
# endif
} break ;
case Image : : FORMAT_LA8 : {
# ifdef GLES_OVER_GL
r_gl_internal_format = GL_RG8 ;
r_gl_format = GL_RG ;
r_gl_type = GL_UNSIGNED_BYTE ;
# else
r_gl_internal_format = GL_LUMINANCE_ALPHA ;
r_gl_format = GL_LUMINANCE_ALPHA ;
r_gl_type = GL_UNSIGNED_BYTE ;
# endif
} break ;
case Image : : FORMAT_R8 : {
r_gl_internal_format = GL_R8 ;
r_gl_format = GL_RED ;
r_gl_type = GL_UNSIGNED_BYTE ;
} break ;
case Image : : FORMAT_RG8 : {
r_gl_internal_format = GL_RG8 ;
r_gl_format = GL_RG ;
r_gl_type = GL_UNSIGNED_BYTE ;
} break ;
case Image : : FORMAT_RGB8 : {
r_gl_internal_format = GL_RGB8 ;
r_gl_format = GL_RGB ;
r_gl_type = GL_UNSIGNED_BYTE ;
//r_srgb = true;
} break ;
case Image : : FORMAT_RGBA8 : {
r_gl_format = GL_RGBA ;
r_gl_internal_format = GL_RGBA8 ;
r_gl_type = GL_UNSIGNED_BYTE ;
//r_srgb = true;
} break ;
case Image : : FORMAT_RGBA4444 : {
r_gl_internal_format = GL_RGBA4 ;
r_gl_format = GL_RGBA ;
r_gl_type = GL_UNSIGNED_SHORT_4_4_4_4 ;
} break ;
//case Image::FORMAT_RGBA5551: {
// r_gl_internal_format = GL_RGB5_A1;
// r_gl_format = GL_RGBA;
// r_gl_type = GL_UNSIGNED_SHORT_5_5_5_1;
//
//} break;
case Image : : FORMAT_RF : {
r_gl_internal_format = GL_R32F ;
r_gl_format = GL_RED ;
r_gl_type = GL_FLOAT ;
} break ;
case Image : : FORMAT_RGF : {
r_gl_internal_format = GL_RG32F ;
r_gl_format = GL_RG ;
r_gl_type = GL_FLOAT ;
} break ;
case Image : : FORMAT_RGBF : {
r_gl_internal_format = GL_RGB32F ;
r_gl_format = GL_RGB ;
r_gl_type = GL_FLOAT ;
} break ;
case Image : : FORMAT_RGBAF : {
r_gl_internal_format = GL_RGBA32F ;
r_gl_format = GL_RGBA ;
r_gl_type = GL_FLOAT ;
} break ;
case Image : : FORMAT_RH : {
r_gl_internal_format = GL_R16F ;
r_gl_format = GL_RED ;
r_gl_type = GL_HALF_FLOAT ;
} break ;
case Image : : FORMAT_RGH : {
r_gl_internal_format = GL_RG16F ;
r_gl_format = GL_RG ;
r_gl_type = GL_HALF_FLOAT ;
} break ;
case Image : : FORMAT_RGBH : {
r_gl_internal_format = GL_RGB16F ;
r_gl_format = GL_RGB ;
r_gl_type = GL_HALF_FLOAT ;
} break ;
case Image : : FORMAT_RGBAH : {
r_gl_internal_format = GL_RGBA16F ;
r_gl_format = GL_RGBA ;
r_gl_type = GL_HALF_FLOAT ;
} break ;
case Image : : FORMAT_RGBE9995 : {
r_gl_internal_format = GL_RGB9_E5 ;
r_gl_format = GL_RGB ;
r_gl_type = GL_UNSIGNED_INT_5_9_9_9_REV ;
} break ;
case Image : : FORMAT_DXT1 : {
if ( config - > s3tc_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT1_EXT ;
r_gl_format = GL_RGBA ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
//r_srgb = true;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_DXT3 : {
if ( config - > s3tc_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT3_EXT ;
r_gl_format = GL_RGBA ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
//r_srgb = true;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_DXT5 : {
if ( config - > s3tc_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT ;
r_gl_format = GL_RGBA ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
//r_srgb = true;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_RGTC_R : {
if ( config - > rgtc_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_RED_RGTC1_EXT ;
r_gl_format = GL_RGBA ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_RGTC_RG : {
if ( config - > rgtc_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_RED_GREEN_RGTC2_EXT ;
r_gl_format = GL_RGBA ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_BPTC_RGBA : {
if ( config - > bptc_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_RGBA_BPTC_UNORM ;
r_gl_format = GL_RGBA ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
//r_srgb = true;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_BPTC_RGBF : {
if ( config - > bptc_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_RGB_BPTC_SIGNED_FLOAT ;
r_gl_format = GL_RGB ;
r_gl_type = GL_FLOAT ;
r_compressed = true ;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_BPTC_RGBFU : {
if ( config - > bptc_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT ;
r_gl_format = GL_RGB ;
r_gl_type = GL_FLOAT ;
r_compressed = true ;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_ETC : {
if ( config - > etc_supported ) {
r_gl_internal_format = _EXT_ETC1_RGB8_OES ;
r_gl_format = GL_RGBA ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
} else {
need_decompress = true ;
}
} break ;
/*
case Image : : FORMAT_ETC2_R11 : {
if ( config - > etc2_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_R11_EAC ;
r_gl_format = GL_RED ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_ETC2_R11S : {
if ( config - > etc2_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_SIGNED_R11_EAC ;
r_gl_format = GL_RED ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_ETC2_RG11 : {
if ( config - > etc2_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_RG11_EAC ;
r_gl_format = GL_RG ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_ETC2_RG11S : {
if ( config - > etc2_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_SIGNED_RG11_EAC ;
r_gl_format = GL_RG ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_ETC2_RGB8 : {
if ( config - > etc2_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_RGB8_ETC2 ;
r_gl_format = GL_RGB ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
//r_srgb = true;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_ETC2_RGBA8 : {
if ( config - > etc2_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_RGBA8_ETC2_EAC ;
r_gl_format = GL_RGBA ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
//r_srgb = true;
} else {
need_decompress = true ;
}
} break ;
case Image : : FORMAT_ETC2_RGB8A1 : {
if ( config - > etc2_supported ) {
r_gl_internal_format = _EXT_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 ;
r_gl_format = GL_RGBA ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_compressed = true ;
//r_srgb = true;
} else {
need_decompress = true ;
}
} break ;
*/
default : {
ERR_FAIL_V ( Ref < Image > ( ) ) ;
}
}
if ( need_decompress | | p_force_decompress ) {
if ( ! image . is_null ( ) ) {
image = image - > duplicate ( ) ;
image - > decompress ( ) ;
ERR_FAIL_COND_V ( image - > is_compressed ( ) , image ) ;
switch ( image - > get_format ( ) ) {
case Image : : FORMAT_RGB8 : {
r_gl_format = GL_RGB ;
r_gl_internal_format = GL_RGB ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_real_format = Image : : FORMAT_RGB8 ;
r_compressed = false ;
} break ;
case Image : : FORMAT_RGBA8 : {
r_gl_format = GL_RGBA ;
r_gl_internal_format = GL_RGBA ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_real_format = Image : : FORMAT_RGBA8 ;
r_compressed = false ;
} break ;
default : {
image - > convert ( Image : : FORMAT_RGBA8 ) ;
r_gl_format = GL_RGBA ;
r_gl_internal_format = GL_RGBA ;
r_gl_type = GL_UNSIGNED_BYTE ;
r_real_format = Image : : FORMAT_RGBA8 ;
r_compressed = false ;
} break ;
}
}
return image ;
}
return p_image ;
}
void TextureStorage : : _texture_set_state_from_flags ( Texture * p_tex ) {
// Config *config = Config::get_singleton();
if ( ( p_tex - > flags & TEXTURE_FLAG_MIPMAPS ) & & ! p_tex - > ignore_mipmaps ) {
if ( p_tex - > flags & TEXTURE_FLAG_FILTER ) {
// these do not exactly correspond ...
p_tex - > GLSetFilter ( p_tex - > target , RS : : CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS ) ;
//texture->glTexParam_MinFilter(texture->target, config->use_fast_texture_filter ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR_MIPMAP_LINEAR);
} else {
p_tex - > GLSetFilter ( p_tex - > target , RS : : CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS ) ;
//texture->glTexParam_MinFilter(texture->target, config->use_fast_texture_filter ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST_MIPMAP_LINEAR);
}
} else {
if ( p_tex - > flags & TEXTURE_FLAG_FILTER ) {
p_tex - > GLSetFilter ( p_tex - > target , RS : : CANVAS_ITEM_TEXTURE_FILTER_LINEAR ) ;
//texture->glTexParam_MinFilter(texture->target, GL_LINEAR);
} else {
p_tex - > GLSetFilter ( p_tex - > target , RS : : CANVAS_ITEM_TEXTURE_FILTER_NEAREST ) ;
//texture->glTexParam_MinFilter(texture->target, GL_NEAREST);
}
}
if ( ( ( p_tex - > flags & TEXTURE_FLAG_REPEAT ) | | ( p_tex - > flags & TEXTURE_FLAG_MIRRORED_REPEAT ) ) & & p_tex - > target ! = GL_TEXTURE_CUBE_MAP ) {
if ( p_tex - > flags & TEXTURE_FLAG_MIRRORED_REPEAT ) {
p_tex - > GLSetRepeat ( p_tex - > target , RS : : CANVAS_ITEM_TEXTURE_REPEAT_MIRROR ) ;
} else {
p_tex - > GLSetRepeat ( p_tex - > target , RS : : CANVAS_ITEM_TEXTURE_REPEAT_ENABLED ) ;
}
} else {
p_tex - > GLSetRepeat ( p_tex - > target , RS : : CANVAS_ITEM_TEXTURE_REPEAT_DISABLED ) ;
}
}
void TextureStorage : : _texture_allocate_internal ( RID p_texture , int p_width , int p_height , int p_depth_3d , Image : : Format p_format , RenderingDevice : : TextureType p_type , uint32_t p_flags ) {
// GLenum format;
// GLenum internal_format;
// GLenum type;
// bool compressed = false;
// Config *config = Config::get_singleton();
if ( p_flags & TEXTURE_FLAG_USED_FOR_STREAMING ) {
p_flags & = ~ TEXTURE_FLAG_MIPMAPS ; // no mipies for video
}
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND ( ! texture ) ;
texture - > width = p_width ;
texture - > height = p_height ;
texture - > format = p_format ;
texture - > flags = p_flags ;
texture - > stored_cube_sides = 0 ;
texture - > type = p_type ;
switch ( p_type ) {
case RenderingDevice : : TEXTURE_TYPE_2D : {
texture - > target = GL_TEXTURE_2D ;
texture - > images . resize ( 1 ) ;
} break ;
// case RenderingDevice::TEXTURE_TYPE_EXTERNAL: {
//#ifdef ANDROID_ENABLED
// texture->target = _GL_TEXTURE_EXTERNAL_OES;
//#else
// texture->target = GL_TEXTURE_2D;
//#endif
// texture->images.resize(0);
// } break;
case RenderingDevice : : TEXTURE_TYPE_CUBE : {
texture - > target = GL_TEXTURE_CUBE_MAP ;
texture - > images . resize ( 6 ) ;
} break ;
case RenderingDevice : : TEXTURE_TYPE_2D_ARRAY :
case RenderingDevice : : TEXTURE_TYPE_3D : {
texture - > target = GL_TEXTURE_3D ;
ERR_PRINT ( " 3D textures and Texture Arrays are not supported in OpenGL. Please switch to the Vulkan backend. " ) ;
return ;
} break ;
default : {
ERR_PRINT ( " Unknown texture type! " ) ;
return ;
}
}
#if 0
// if (p_type != RS::TEXTURE_TYPE_EXTERNAL) {
if ( p_type = = RenderingDevice : : TEXTURE_TYPE_2D ) {
texture - > alloc_width = texture - > width ;
texture - > alloc_height = texture - > height ;
texture - > resize_to_po2 = false ;
if ( ! config - > support_npot_repeat_mipmap ) {
int po2_width = next_power_of_2 ( p_width ) ;
int po2_height = next_power_of_2 ( p_height ) ;
bool is_po2 = p_width = = po2_width & & p_height = = po2_height ;
if ( ! is_po2 & & ( p_flags & TEXTURE_FLAG_REPEAT | | p_flags & TEXTURE_FLAG_MIPMAPS ) ) {
if ( p_flags & TEXTURE_FLAG_USED_FOR_STREAMING ) {
//not supported
ERR_PRINT ( " Streaming texture for non power of 2 or has mipmaps on this hardware: " + texture - > path + " '. Mipmaps and repeat disabled. " ) ;
texture - > flags & = ~ ( TEXTURE_FLAG_REPEAT | TEXTURE_FLAG_MIPMAPS ) ;
} else {
texture - > alloc_height = po2_height ;
texture - > alloc_width = po2_width ;
texture - > resize_to_po2 = true ;
}
}
}
GLenum format ;
GLenum internal_format ;
GLenum type ;
bool compressed = false ;
Image : : Format real_format ;
_get_gl_image_and_format ( Ref < Image > ( ) ,
texture - > format ,
texture - > flags ,
real_format ,
format ,
internal_format ,
type ,
compressed ,
texture - > resize_to_po2 ) ;
texture - > gl_format_cache = format ;
texture - > gl_type_cache = type ;
texture - > gl_internal_format_cache = internal_format ;
texture - > data_size = 0 ;
texture - > mipmaps = 1 ;
texture - > compressed = compressed ;
}
# endif
glActiveTexture ( GL_TEXTURE0 ) ;
glBindTexture ( texture - > target , texture - > tex_id ) ;
// if (p_type == RS::TEXTURE_TYPE_EXTERNAL) {
// glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// glTexParameteri(texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
// glTexParameteri(texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// } else if (p_flags & TEXTURE_FLAG_USED_FOR_STREAMING) {
// //prealloc if video
// glTexImage2D(texture->target, 0, internal_format, texture->alloc_width, texture->alloc_height, 0, format, type, NULL);
// }
texture - > active = true ;
}
RID TextureStorage : : texture_create ( ) {
ERR_FAIL_COND_V ( ! _is_main_thread ( ) , RID ( ) ) ;
Texture * texture = memnew ( Texture ) ;
ERR_FAIL_COND_V ( ! texture , RID ( ) ) ;
glGenTextures ( 1 , & texture - > tex_id ) ;
texture - > active = false ;
texture - > total_data_size = 0 ;
return texture_owner . make_rid ( texture ) ;
}
RID TextureStorage : : texture_allocate ( ) {
RID id = texture_create ( ) ;
ERR_FAIL_COND_V ( id = = RID ( ) , id ) ;
return id ;
}
void TextureStorage : : texture_free ( RID p_rid ) {
Texture * t = texture_owner . get_or_null ( p_rid ) ;
// can't free a render target texture
ERR_FAIL_COND ( t - > render_target ) ;
if ( t - > canvas_texture ) {
memdelete ( t - > canvas_texture ) ;
}
// info.texture_mem -= t->total_data_size; // TODO make this work again!!
texture_owner . free ( p_rid ) ;
memdelete ( t ) ;
}
void TextureStorage : : texture_2d_initialize ( RID p_texture , const Ref < Image > & p_image ) {
Texture * tex = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND ( ! tex ) ;
int w = p_image - > get_width ( ) ;
int h = p_image - > get_height ( ) ;
_texture_allocate_internal ( p_texture , w , h , 1 , p_image - > get_format ( ) , RenderingDevice : : TEXTURE_TYPE_2D , 0 ) ;
texture_set_data ( p_texture , p_image ) ;
}
void TextureStorage : : texture_2d_layered_initialize ( RID p_texture , const Vector < Ref < Image > > & p_layers , RS : : TextureLayeredType p_layered_type ) {
}
void TextureStorage : : 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 ) {
}
void TextureStorage : : texture_proxy_initialize ( RID p_texture , RID p_base ) {
texture_set_proxy ( p_texture , p_base ) ;
}
//RID TextureStorage::texture_2d_create(const Ref<Image> &p_image) {
// RID id = texture_create();
// ERR_FAIL_COND_V(id == RID(), id);
// int w = p_image->get_width();
// int h = p_image->get_height();
// texture_allocate(id, w, h, 1, p_image->get_format(), RenderingDevice::TEXTURE_TYPE_2D, 0);
// texture_set_data(id, p_image);
// return id;
//}
//RID TextureStorage::texture_2d_layered_create(const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) {
// return RID();
//}
//void TextureStorage::texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer) {
// // only 1 layer so far
// texture_set_data(p_texture, p_image);
//}
void TextureStorage : : texture_2d_update ( RID p_texture , const Ref < Image > & p_image , int p_layer ) {
// only 1 layer so far
texture_set_data ( p_texture , p_image ) ;
}
void TextureStorage : : texture_2d_placeholder_initialize ( RID p_texture ) {
}
void TextureStorage : : texture_2d_layered_placeholder_initialize ( RID p_texture , RenderingServer : : TextureLayeredType p_layered_type ) {
}
void TextureStorage : : texture_3d_placeholder_initialize ( RID p_texture ) {
}
Ref < Image > TextureStorage : : texture_2d_get ( RID p_texture ) const {
Texture * tex = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND_V ( ! tex , Ref < Image > ( ) ) ;
/*
# ifdef TOOLS_ENABLED
if ( tex - > image_cache_2d . is_valid ( ) ) {
return tex - > image_cache_2d ;
}
# endif
Vector < uint8_t > data = RD : : get_singleton ( ) - > texture_get_data ( tex - > rd_texture , 0 ) ;
ERR_FAIL_COND_V ( data . size ( ) = = 0 , Ref < Image > ( ) ) ;
Ref < Image > image ;
image . instance ( ) ;
image - > create ( tex - > width , tex - > height , tex - > mipmaps > 1 , tex - > validated_format , data ) ;
ERR_FAIL_COND_V ( image - > empty ( ) , Ref < Image > ( ) ) ;
if ( tex - > format ! = tex - > validated_format ) {
image - > convert ( tex - > format ) ;
}
# ifdef TOOLS_ENABLED
if ( Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
tex - > image_cache_2d = image ;
}
# endif
*/
ERR_FAIL_COND_V ( ! tex - > images . size ( ) , Ref < Image > ( ) ) ;
return tex - > images [ 0 ] ;
// return image;
// return Ref<Image>();
}
void TextureStorage : : texture_replace ( RID p_texture , RID p_by_texture ) {
Texture * tex_to = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND ( ! tex_to ) ;
Texture * tex_from = texture_owner . get_or_null ( p_by_texture ) ;
ERR_FAIL_COND ( ! tex_from ) ;
tex_to - > destroy ( ) ;
tex_to - > copy_from ( * tex_from ) ;
// copy image data and upload to GL
tex_to - > images . resize ( tex_from - > images . size ( ) ) ;
for ( int n = 0 ; n < tex_from - > images . size ( ) ; n + + ) {
texture_set_data ( p_texture , tex_from - > images [ n ] , n ) ;
}
texture_free ( p_by_texture ) ;
}
void TextureStorage : : texture_set_size_override ( RID p_texture , int p_width , int p_height ) {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND ( ! texture ) ;
ERR_FAIL_COND ( texture - > render_target ) ;
ERR_FAIL_COND ( p_width < = 0 | | p_width > 16384 ) ;
ERR_FAIL_COND ( p_height < = 0 | | p_height > 16384 ) ;
//real texture size is in alloc width and height
texture - > width = p_width ;
texture - > height = p_height ;
}
void TextureStorage : : texture_set_path ( RID p_texture , const String & p_path ) {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND ( ! texture ) ;
texture - > path = p_path ;
}
String TextureStorage : : texture_get_path ( RID p_texture ) const {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND_V ( ! texture , " " ) ;
return texture - > path ;
}
void TextureStorage : : texture_set_detect_3d_callback ( RID p_texture , RS : : TextureDetectCallback p_callback , void * p_userdata ) {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND ( ! texture ) ;
texture - > detect_3d = p_callback ;
texture - > detect_3d_ud = p_userdata ;
}
void TextureStorage : : texture_set_detect_srgb_callback ( RID p_texture , RS : : TextureDetectCallback p_callback , void * p_userdata ) {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND ( ! texture ) ;
texture - > detect_srgb = p_callback ;
texture - > detect_srgb_ud = p_userdata ;
}
void TextureStorage : : texture_set_detect_normal_callback ( RID p_texture , RS : : TextureDetectCallback p_callback , void * p_userdata ) {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND ( ! texture ) ;
texture - > detect_normal = p_callback ;
texture - > detect_normal_ud = p_userdata ;
}
void TextureStorage : : texture_debug_usage ( List < RS : : TextureInfo > * r_info ) {
List < RID > textures ;
texture_owner . get_owned_list ( & textures ) ;
for ( List < RID > : : Element * E = textures . front ( ) ; E ; E = E - > next ( ) ) {
Texture * t = texture_owner . get_or_null ( E - > get ( ) ) ;
if ( ! t ) {
continue ;
}
RS : : TextureInfo tinfo ;
tinfo . path = t - > path ;
tinfo . format = t - > format ;
tinfo . width = t - > alloc_width ;
tinfo . height = t - > alloc_height ;
tinfo . depth = 0 ;
tinfo . bytes = t - > total_data_size ;
r_info - > push_back ( tinfo ) ;
}
}
void TextureStorage : : texture_set_force_redraw_if_visible ( RID p_texture , bool p_enable ) {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND ( ! texture ) ;
texture - > redraw_if_visible = p_enable ;
}
Size2 TextureStorage : : texture_size_with_proxy ( RID p_texture ) {
const Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND_V ( ! texture , Size2 ( ) ) ;
if ( texture - > proxy ) {
return Size2 ( texture - > proxy - > width , texture - > proxy - > height ) ;
} else {
return Size2 ( texture - > width , texture - > height ) ;
}
}
// example use in 3.2
// VS::get_singleton()->texture_set_proxy(default_texture->proxy, texture_rid);
// p_proxy is the source (pre-existing) texture?
// and p_texture is the one that is being made into a proxy?
//This naming is confusing. Comments!!!
// The naming of the parameters seemed to be reversed?
// The p_proxy is the source texture
// and p_texture is actually the proxy????
void TextureStorage : : texture_set_proxy ( RID p_texture , RID p_proxy ) {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND ( ! texture ) ;
if ( texture - > proxy ) {
texture - > proxy - > proxy_owners . erase ( texture ) ;
texture - > proxy = nullptr ;
}
if ( p_proxy . is_valid ( ) ) {
Texture * proxy = texture_owner . get_or_null ( p_proxy ) ;
ERR_FAIL_COND ( ! proxy ) ;
ERR_FAIL_COND ( proxy = = texture ) ;
proxy - > proxy_owners . insert ( texture ) ;
texture - > proxy = proxy ;
}
}
void TextureStorage : : texture_set_data ( RID p_texture , const Ref < Image > & p_image , int p_layer ) {
Config * config = Config : : get_singleton ( ) ;
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND ( ! _is_main_thread ( ) ) ;
ERR_FAIL_COND ( ! texture ) ;
if ( texture - > target = = GL_TEXTURE_3D ) {
// Target is set to a 3D texture or array texture, exit early to avoid spamming errors
return ;
}
ERR_FAIL_COND ( ! texture - > active ) ;
ERR_FAIL_COND ( texture - > render_target ) ;
ERR_FAIL_COND ( p_image . is_null ( ) ) ;
ERR_FAIL_COND ( texture - > format ! = p_image - > get_format ( ) ) ;
ERR_FAIL_COND ( ! p_image - > get_width ( ) ) ;
ERR_FAIL_COND ( ! p_image - > get_height ( ) ) ;
// ERR_FAIL_COND(texture->type == RS::TEXTURE_TYPE_EXTERNAL);
GLenum type ;
GLenum format ;
GLenum internal_format ;
bool compressed = false ;
if ( config - > keep_original_textures & & ! ( texture - > flags & TEXTURE_FLAG_USED_FOR_STREAMING ) ) {
texture - > images . write [ p_layer ] = p_image ;
}
// print_line("texture_set_data width " + itos (p_image->get_width()) + " height " + itos(p_image->get_height()));
Image : : Format real_format ;
Ref < Image > img = _get_gl_image_and_format ( p_image , p_image - > get_format ( ) , texture - > flags , real_format , format , internal_format , type , compressed , texture - > resize_to_po2 ) ;
if ( texture - > resize_to_po2 ) {
if ( p_image - > is_compressed ( ) ) {
ERR_PRINT ( " Texture ' " + texture - > path + " ' is required to be a power of 2 because it uses either mipmaps or repeat, so it was decompressed. This will hurt performance and memory usage. " ) ;
}
if ( img = = p_image ) {
img = img - > duplicate ( ) ;
}
img - > resize_to_po2 ( false ) ;
}
if ( config - > shrink_textures_x2 & & ( p_image - > has_mipmaps ( ) | | ! p_image - > is_compressed ( ) ) & & ! ( texture - > flags & TEXTURE_FLAG_USED_FOR_STREAMING ) ) {
texture - > alloc_height = MAX ( 1 , texture - > alloc_height / 2 ) ;
texture - > alloc_width = MAX ( 1 , texture - > alloc_width / 2 ) ;
if ( texture - > alloc_width = = img - > get_width ( ) / 2 & & texture - > alloc_height = = img - > get_height ( ) / 2 ) {
img - > shrink_x2 ( ) ;
} else if ( img - > get_format ( ) < = Image : : FORMAT_RGBA8 ) {
img - > resize ( texture - > alloc_width , texture - > alloc_height , Image : : INTERPOLATE_BILINEAR ) ;
}
}
GLenum blit_target = ( texture - > target = = GL_TEXTURE_CUBE_MAP ) ? _cube_side_enum [ p_layer ] : GL_TEXTURE_2D ;
texture - > data_size = img - > get_data ( ) . size ( ) ;
Vector < uint8_t > read = img - > get_data ( ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
glBindTexture ( texture - > target , texture - > tex_id ) ;
texture - > ignore_mipmaps = compressed & & ! img - > has_mipmaps ( ) ;
// set filtering and repeat state
_texture_set_state_from_flags ( texture ) ;
//set swizle for older format compatibility
# ifdef GLES_OVER_GL
switch ( texture - > format ) {
case Image : : FORMAT_L8 : {
glTexParameteri ( texture - > target , GL_TEXTURE_SWIZZLE_R , GL_RED ) ;
glTexParameteri ( texture - > target , GL_TEXTURE_SWIZZLE_G , GL_RED ) ;
glTexParameteri ( texture - > target , GL_TEXTURE_SWIZZLE_B , GL_RED ) ;
glTexParameteri ( texture - > target , GL_TEXTURE_SWIZZLE_A , GL_ONE ) ;
} break ;
case Image : : FORMAT_LA8 : {
glTexParameteri ( texture - > target , GL_TEXTURE_SWIZZLE_R , GL_RED ) ;
glTexParameteri ( texture - > target , GL_TEXTURE_SWIZZLE_G , GL_RED ) ;
glTexParameteri ( texture - > target , GL_TEXTURE_SWIZZLE_B , GL_RED ) ;
glTexParameteri ( texture - > target , GL_TEXTURE_SWIZZLE_A , GL_GREEN ) ;
} break ;
default : {
glTexParameteri ( texture - > target , GL_TEXTURE_SWIZZLE_R , GL_RED ) ;
glTexParameteri ( texture - > target , GL_TEXTURE_SWIZZLE_G , GL_GREEN ) ;
glTexParameteri ( texture - > target , GL_TEXTURE_SWIZZLE_B , GL_BLUE ) ;
glTexParameteri ( texture - > target , GL_TEXTURE_SWIZZLE_A , GL_ALPHA ) ;
} break ;
}
# endif
int mipmaps = ( ( texture - > flags & TEXTURE_FLAG_MIPMAPS ) & & img - > has_mipmaps ( ) ) ? img - > get_mipmap_count ( ) + 1 : 1 ;
int w = img - > get_width ( ) ;
int h = img - > get_height ( ) ;
int tsize = 0 ;
for ( int i = 0 ; i < mipmaps ; i + + ) {
int size , ofs ;
img - > get_mipmap_offset_and_size ( i , ofs , size ) ;
if ( compressed ) {
glPixelStorei ( GL_UNPACK_ALIGNMENT , 4 ) ;
int bw = w ;
int bh = h ;
glCompressedTexImage2D ( blit_target , i , internal_format , bw , bh , 0 , size , & read [ ofs ] ) ;
} else {
glPixelStorei ( GL_UNPACK_ALIGNMENT , 1 ) ;
if ( texture - > flags & TEXTURE_FLAG_USED_FOR_STREAMING ) {
glTexSubImage2D ( blit_target , i , 0 , 0 , w , h , format , type , & read [ ofs ] ) ;
} else {
glTexImage2D ( blit_target , i , internal_format , w , h , 0 , format , type , & read [ ofs ] ) ;
}
}
tsize + = size ;
w = MAX ( 1 , w > > 1 ) ;
h = MAX ( 1 , h > > 1 ) ;
}
// info.texture_mem -= texture->total_data_size; // TODO make this work again!!
texture - > total_data_size = tsize ;
// info.texture_mem += texture->total_data_size; // TODO make this work again!!
// printf("texture: %i x %i - size: %i - total: %i\n", texture->width, texture->height, tsize, info.texture_mem);
texture - > stored_cube_sides | = ( 1 < < p_layer ) ;
if ( ( texture - > flags & TEXTURE_FLAG_MIPMAPS ) & & mipmaps = = 1 & & ! texture - > ignore_mipmaps & & ( texture - > type ! = RenderingDevice : : TEXTURE_TYPE_CUBE | | texture - > stored_cube_sides = = ( 1 < < 6 ) - 1 ) ) {
//generate mipmaps if they were requested and the image does not contain them
glGenerateMipmap ( texture - > target ) ;
}
texture - > mipmaps = mipmaps ;
}
void TextureStorage : : texture_set_data_partial ( RID p_texture , const Ref < Image > & p_image , int src_x , int src_y , int src_w , int src_h , int dst_x , int dst_y , int p_dst_mip , int p_layer ) {
// TODO
ERR_PRINT ( " Not implemented (ask Karroffel to do it :p) " ) ;
}
/*
Ref < Image > TextureStorage : : texture_get_data ( RID p_texture , int p_layer ) const {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND_V ( ! texture , Ref < Image > ( ) ) ;
ERR_FAIL_COND_V ( ! texture - > active , Ref < Image > ( ) ) ;
ERR_FAIL_COND_V ( texture - > data_size = = 0 & & ! texture - > render_target , Ref < Image > ( ) ) ;
if ( texture - > type = = RS : : TEXTURE_TYPE_CUBEMAP & & p_layer < 6 & & p_layer > = 0 & & ! texture - > images [ p_layer ] . is_null ( ) ) {
return texture - > images [ p_layer ] ;
}
# ifdef GLES_OVER_GL
Image : : Format real_format ;
GLenum gl_format ;
GLenum gl_internal_format ;
GLenum gl_type ;
bool compressed ;
_get_gl_image_and_format ( Ref < Image > ( ) , texture - > format , texture - > flags , real_format , gl_format , gl_internal_format , gl_type , compressed , false ) ;
PoolVector < uint8_t > data ;
int data_size = Image : : get_image_data_size ( texture - > alloc_width , texture - > alloc_height , real_format , texture - > mipmaps > 1 ) ;
data . resize ( data_size * 2 ) ; //add some memory at the end, just in case for buggy drivers
PoolVector < uint8_t > : : Write wb = data . write ( ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
glBindTexture ( texture - > target , texture - > tex_id ) ;
glBindBuffer ( GL_PIXEL_PACK_BUFFER , 0 ) ;
for ( int i = 0 ; i < texture - > mipmaps ; i + + ) {
int ofs = Image : : get_image_mipmap_offset ( texture - > alloc_width , texture - > alloc_height , real_format , i ) ;
if ( texture - > compressed ) {
glPixelStorei ( GL_PACK_ALIGNMENT , 4 ) ;
glGetCompressedTexImage ( texture - > target , i , & wb [ ofs ] ) ;
} else {
glPixelStorei ( GL_PACK_ALIGNMENT , 1 ) ;
glGetTexImage ( texture - > target , i , texture - > gl_format_cache , texture - > gl_type_cache , & wb [ ofs ] ) ;
}
}
wb . release ( ) ;
data . resize ( data_size ) ;
Image * img = memnew ( Image ( texture - > alloc_width , texture - > alloc_height , texture - > mipmaps > 1 , real_format , data ) ) ;
return Ref < Image > ( img ) ;
# else
Image : : Format real_format ;
GLenum gl_format ;
GLenum gl_internal_format ;
GLenum gl_type ;
bool compressed ;
_get_gl_image_and_format ( Ref < Image > ( ) , texture - > format , texture - > flags , real_format , gl_format , gl_internal_format , gl_type , compressed , texture - > resize_to_po2 ) ;
PoolVector < uint8_t > data ;
int data_size = Image : : get_image_data_size ( texture - > alloc_width , texture - > alloc_height , Image : : FORMAT_RGBA8 , false ) ;
data . resize ( data_size * 2 ) ; //add some memory at the end, just in case for buggy drivers
PoolVector < uint8_t > : : Write wb = data . write ( ) ;
GLuint temp_framebuffer ;
glGenFramebuffers ( 1 , & temp_framebuffer ) ;
GLuint temp_color_texture ;
glGenTextures ( 1 , & temp_color_texture ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , temp_framebuffer ) ;
glBindTexture ( GL_TEXTURE_2D , temp_color_texture ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , texture - > alloc_width , texture - > alloc_height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , NULL ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , temp_color_texture , 0 ) ;
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 , texture - > tex_id ) ;
glViewport ( 0 , 0 , texture - > alloc_width , texture - > alloc_height ) ;
shaders . copy . bind ( ) ;
glClearColor ( 0.0 , 0.0 , 0.0 , 0.0 ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
bind_quad_array ( ) ;
glDrawArrays ( GL_TRIANGLE_FAN , 0 , 4 ) ;
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
glReadPixels ( 0 , 0 , texture - > alloc_width , texture - > alloc_height , GL_RGBA , GL_UNSIGNED_BYTE , & wb [ 0 ] ) ;
glDeleteTextures ( 1 , & temp_color_texture ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
glDeleteFramebuffers ( 1 , & temp_framebuffer ) ;
wb . release ( ) ;
data . resize ( data_size ) ;
Image * img = memnew ( Image ( texture - > alloc_width , texture - > alloc_height , false , Image : : FORMAT_RGBA8 , data ) ) ;
if ( ! texture - > compressed ) {
img - > convert ( real_format ) ;
}
return Ref < Image > ( img ) ;
# endif
}
*/
void TextureStorage : : texture_set_flags ( RID p_texture , uint32_t p_flags ) {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND ( ! texture ) ;
bool had_mipmaps = texture - > flags & TEXTURE_FLAG_MIPMAPS ;
texture - > flags = p_flags ;
glActiveTexture ( GL_TEXTURE0 ) ;
glBindTexture ( texture - > target , texture - > tex_id ) ;
// set filtering and repeat state
_texture_set_state_from_flags ( texture ) ;
if ( ( texture - > flags & TEXTURE_FLAG_MIPMAPS ) & & ! texture - > ignore_mipmaps ) {
if ( ! had_mipmaps & & texture - > mipmaps = = 1 ) {
glGenerateMipmap ( texture - > target ) ;
}
}
}
uint32_t TextureStorage : : texture_get_flags ( RID p_texture ) const {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND_V ( ! texture , 0 ) ;
return texture - > flags ;
}
Image : : Format TextureStorage : : texture_get_format ( RID p_texture ) const {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND_V ( ! texture , Image : : FORMAT_L8 ) ;
return texture - > format ;
}
RenderingDevice : : TextureType TextureStorage : : texture_get_type ( RID p_texture ) const {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND_V ( ! texture , RenderingDevice : : TEXTURE_TYPE_2D ) ;
return texture - > type ;
}
uint32_t TextureStorage : : texture_get_texid ( RID p_texture ) const {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND_V ( ! texture , 0 ) ;
return texture - > tex_id ;
}
uint32_t TextureStorage : : texture_get_width ( RID p_texture ) const {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND_V ( ! texture , 0 ) ;
return texture - > width ;
}
uint32_t TextureStorage : : texture_get_height ( RID p_texture ) const {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND_V ( ! texture , 0 ) ;
return texture - > height ;
}
uint32_t TextureStorage : : texture_get_depth ( RID p_texture ) const {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND_V ( ! texture , 0 ) ;
return texture - > depth ;
}
void TextureStorage : : texture_bind ( RID p_texture , uint32_t p_texture_no ) {
Texture * texture = texture_owner . get_or_null ( p_texture ) ;
ERR_FAIL_COND ( ! texture ) ;
glActiveTexture ( GL_TEXTURE0 + p_texture_no ) ;
glBindTexture ( texture - > target , texture - > tex_id ) ;
}
void TextureStorage : : texture_set_shrink_all_x2_on_set_data ( bool p_enable ) {
Config : : get_singleton ( ) - > shrink_textures_x2 = p_enable ;
}
RID TextureStorage : : texture_create_radiance_cubemap ( RID p_source , int p_resolution ) const {
return RID ( ) ;
}
void TextureStorage : : textures_keep_original ( bool p_enable ) {
Config : : get_singleton ( ) - > keep_original_textures = p_enable ;
}
2022-04-07 14:00:51 +00:00
/* DECAL API */
RID TextureStorage : : decal_allocate ( ) {
return RID ( ) ;
}
void TextureStorage : : decal_initialize ( RID p_rid ) {
}
void TextureStorage : : decal_set_extents ( RID p_decal , const Vector3 & p_extents ) {
}
void TextureStorage : : decal_set_texture ( RID p_decal , RS : : DecalTexture p_type , RID p_texture ) {
}
void TextureStorage : : decal_set_emission_energy ( RID p_decal , float p_energy ) {
}
void TextureStorage : : decal_set_albedo_mix ( RID p_decal , float p_mix ) {
}
void TextureStorage : : decal_set_modulate ( RID p_decal , const Color & p_modulate ) {
}
void TextureStorage : : decal_set_cull_mask ( RID p_decal , uint32_t p_layers ) {
}
void TextureStorage : : decal_set_distance_fade ( RID p_decal , bool p_enabled , float p_begin , float p_length ) {
}
void TextureStorage : : decal_set_fade ( RID p_decal , float p_above , float p_below ) {
}
void TextureStorage : : decal_set_normal_fade ( RID p_decal , float p_fade ) {
}
AABB TextureStorage : : decal_get_aabb ( RID p_decal ) const {
return AABB ( ) ;
}
/* RENDER TARGET API */
GLuint TextureStorage : : system_fbo = 0 ;
void TextureStorage : : _set_current_render_target ( RID p_render_target ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
if ( rt ) {
if ( rt - > allocate_is_dirty ) {
rt - > allocate_is_dirty = false ;
_render_target_allocate ( rt ) ;
}
frame . current_rt = rt ;
ERR_FAIL_COND ( ! rt ) ;
frame . clear_request = false ;
glViewport ( 0 , 0 , rt - > width , rt - > height ) ;
_dims . rt_width = rt - > width ;
_dims . rt_height = rt - > height ;
_dims . win_width = rt - > width ;
_dims . win_height = rt - > height ;
} else {
frame . current_rt = nullptr ;
frame . clear_request = false ;
glBindFramebuffer ( GL_FRAMEBUFFER , GLES3 : : TextureStorage : : system_fbo ) ;
}
}
void TextureStorage : : _render_target_allocate ( RenderTarget * rt ) {
Config * config = Config : : get_singleton ( ) ;
// do not allocate a render target with no size
if ( rt - > width < = 0 | | rt - > height < = 0 ) {
return ;
}
// do not allocate a render target that is attached to the screen
if ( rt - > flags [ RENDER_TARGET_DIRECT_TO_SCREEN ] ) {
rt - > fbo = system_fbo ;
return ;
}
GLuint color_internal_format ;
GLuint color_format ;
GLuint color_type = GL_UNSIGNED_BYTE ;
Image : : Format image_format ;
if ( rt - > flags [ TextureStorage : : RENDER_TARGET_TRANSPARENT ] ) {
# ifdef GLES_OVER_GL
color_internal_format = GL_RGBA8 ;
# else
color_internal_format = GL_RGBA ;
# endif
color_format = GL_RGBA ;
image_format = Image : : FORMAT_RGBA8 ;
} else {
# ifdef GLES_OVER_GL
color_internal_format = GL_RGB8 ;
# else
color_internal_format = GL_RGB ;
# endif
color_format = GL_RGB ;
image_format = Image : : FORMAT_RGB8 ;
}
rt - > used_dof_blur_near = false ;
rt - > mip_maps_allocated = false ;
{
/* Front FBO */
Texture * texture = get_texture ( rt - > texture ) ;
ERR_FAIL_COND ( ! texture ) ;
// framebuffer
glGenFramebuffers ( 1 , & rt - > fbo ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , rt - > fbo ) ;
// color
glGenTextures ( 1 , & rt - > color ) ;
glBindTexture ( GL_TEXTURE_2D , rt - > color ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , color_internal_format , rt - > width , rt - > height , 0 , color_format , color_type , nullptr ) ;
if ( texture - > flags & TEXTURE_FLAG_FILTER ) {
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
} else {
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
}
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , rt - > color , 0 ) ;
// depth
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 , 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 ) ;
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_TEXTURE_2D , rt - > depth , 0 ) ;
} else {
glGenRenderbuffers ( 1 , & rt - > depth ) ;
glBindRenderbuffer ( GL_RENDERBUFFER , rt - > depth ) ;
glRenderbufferStorage ( GL_RENDERBUFFER , config - > depth_buffer_internalformat , rt - > width , rt - > height ) ;
glFramebufferRenderbuffer ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_RENDERBUFFER , rt - > depth ) ;
}
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 ;
texture - > gl_format_cache = color_format ;
texture - > gl_type_cache = GL_UNSIGNED_BYTE ;
texture - > gl_internal_format_cache = color_internal_format ;
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 ) ;
}
/* BACK FBO */
/* For MSAA */
# ifndef JAVASCRIPT_ENABLED
if ( rt - > msaa > = RS : : VIEWPORT_MSAA_2X & & rt - > msaa < = RS : : VIEWPORT_MSAA_8X ) {
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_PRINT ( " MSAA must be <= GL_MAX_SAMPLES, falling-back to GL_MAX_SAMPLES = " + itos ( max_samples ) ) ;
msaa = max_samples ;
}
//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_buffer_internalformat , rt - > width , rt - > height ) ;
glFramebufferRenderbuffer ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_RENDERBUFFER , rt - > multisample_depth ) ;
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 ) ;
GLenum status = glCheckFramebufferStatus ( GL_FRAMEBUFFER ) ;
if ( status ! = GL_FRAMEBUFFER_COMPLETE ) {
// Delete allocated resources and default to no MSAA
WARN_PRINT_ONCE ( " Cannot allocate back framebuffer for MSAA " ) ;
printf ( " err status: %x \n " , status ) ;
rt - > multisample_active = false ;
glDeleteFramebuffers ( 1 , & rt - > multisample_fbo ) ;
rt - > multisample_fbo = 0 ;
glDeleteRenderbuffers ( 1 , & rt - > multisample_depth ) ;
rt - > multisample_depth = 0 ;
glDeleteRenderbuffers ( 1 , & rt - > multisample_color ) ;
rt - > multisample_color = 0 ;
}
glBindRenderbuffer ( GL_RENDERBUFFER , 0 ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
} else
# endif // JAVASCRIPT_ENABLED
{
rt - > multisample_active = false ;
}
glClearColor ( 0 , 0 , 0 , 0 ) ;
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
// copy texscreen buffers
// if (!(rt->flags[TextureStorage::RENDER_TARGET_NO_SAMPLING])) {
if ( true ) {
glGenTextures ( 1 , & rt - > copy_screen_effect . color ) ;
glBindTexture ( GL_TEXTURE_2D , rt - > copy_screen_effect . color ) ;
if ( rt - > flags [ TextureStorage : : RENDER_TARGET_TRANSPARENT ] ) {
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , rt - > width , rt - > height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , nullptr ) ;
} else {
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGB , rt - > width , rt - > height , 0 , GL_RGB , GL_UNSIGNED_BYTE , 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 ) ;
glGenFramebuffers ( 1 , & rt - > copy_screen_effect . fbo ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , rt - > copy_screen_effect . fbo ) ;
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , rt - > copy_screen_effect . color , 0 ) ;
glClearColor ( 0 , 0 , 0 , 0 ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
GLenum status = glCheckFramebufferStatus ( GL_FRAMEBUFFER ) ;
if ( status ! = GL_FRAMEBUFFER_COMPLETE ) {
_render_target_clear ( rt ) ;
ERR_FAIL_COND ( status ! = GL_FRAMEBUFFER_COMPLETE ) ;
}
}
// Allocate mipmap chains for post_process effects
// if (!rt->flags[RendererStorage::RENDER_TARGET_NO_3D] && rt->width >= 2 && rt->height >= 2) {
if ( rt - > width > = 2 & & rt - > height > = 2 ) {
for ( int i = 0 ; i < 2 ; i + + ) {
ERR_FAIL_COND ( rt - > mip_maps [ i ] . sizes . size ( ) ) ;
int w = rt - > width ;
int h = rt - > height ;
if ( i > 0 ) {
w > > = 1 ;
h > > = 1 ;
}
int level = 0 ;
int fb_w = w ;
int fb_h = h ;
while ( true ) {
RenderTarget : : MipMaps : : Size mm ;
mm . width = w ;
mm . height = h ;
rt - > mip_maps [ i ] . sizes . push_back ( mm ) ;
w > > = 1 ;
h > > = 1 ;
if ( w < 2 | | h < 2 ) {
break ;
}
level + + ;
}
GLsizei width = fb_w ;
GLsizei height = fb_h ;
if ( config - > render_to_mipmap_supported ) {
glGenTextures ( 1 , & rt - > mip_maps [ i ] . color ) ;
glBindTexture ( GL_TEXTURE_2D , rt - > mip_maps [ i ] . color ) ;
for ( int l = 0 ; l < level + 1 ; l + + ) {
glTexImage2D ( GL_TEXTURE_2D , l , color_internal_format , width , height , 0 , color_format , color_type , nullptr ) ;
width = MAX ( 1 , ( width / 2 ) ) ;
height = MAX ( 1 , ( height / 2 ) ) ;
}
# ifdef GLES_OVER_GL
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_BASE_LEVEL , 0 ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAX_LEVEL , level ) ;
# endif
} else {
// Can't render to specific levels of a mipmap in ES 2.0 or Webgl so create a texture for each level
for ( int l = 0 ; l < level + 1 ; l + + ) {
glGenTextures ( 1 , & rt - > mip_maps [ i ] . sizes . write [ l ] . color ) ;
glBindTexture ( GL_TEXTURE_2D , rt - > mip_maps [ i ] . sizes [ l ] . color ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , color_internal_format , width , height , 0 , color_format , color_type , nullptr ) ;
width = MAX ( 1 , ( width / 2 ) ) ;
height = MAX ( 1 , ( height / 2 ) ) ;
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 ) ;
}
}
glDisable ( GL_SCISSOR_TEST ) ;
glColorMask ( 1 , 1 , 1 , 1 ) ;
glDepthMask ( GL_TRUE ) ;
for ( int j = 0 ; j < rt - > mip_maps [ i ] . sizes . size ( ) ; j + + ) {
RenderTarget : : MipMaps : : Size & mm = rt - > mip_maps [ i ] . sizes . write [ j ] ;
glGenFramebuffers ( 1 , & mm . fbo ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , mm . fbo ) ;
if ( config - > render_to_mipmap_supported ) {
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , rt - > mip_maps [ i ] . color , j ) ;
} else {
glBindTexture ( GL_TEXTURE_2D , rt - > mip_maps [ i ] . sizes [ j ] . color ) ;
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , rt - > mip_maps [ i ] . sizes [ j ] . color , 0 ) ;
}
bool used_depth = false ;
if ( j = = 0 & & i = = 0 ) { //use always
if ( config - > support_depth_texture ) {
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_TEXTURE_2D , rt - > depth , 0 ) ;
} else {
glFramebufferRenderbuffer ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_RENDERBUFFER , rt - > depth ) ;
}
used_depth = true ;
}
GLenum status = glCheckFramebufferStatus ( GL_FRAMEBUFFER ) ;
if ( status ! = GL_FRAMEBUFFER_COMPLETE ) {
WARN_PRINT_ONCE ( " Cannot allocate mipmaps for 3D post processing effects " ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , GLES3 : : TextureStorage : : system_fbo ) ;
return ;
}
glClearColor ( 1.0 , 0.0 , 1.0 , 0.0 ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
if ( used_depth ) {
glClearDepth ( 1.0 ) ;
glClear ( GL_DEPTH_BUFFER_BIT ) ;
}
}
rt - > mip_maps [ i ] . levels = level ;
if ( config - > render_to_mipmap_supported ) {
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR_MIPMAP_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 ) ;
}
}
rt - > mip_maps_allocated = true ;
}
glBindFramebuffer ( GL_FRAMEBUFFER , GLES3 : : TextureStorage : : system_fbo ) ;
}
void TextureStorage : : _render_target_clear ( RenderTarget * rt ) {
Config * config = Config : : get_singleton ( ) ;
// there is nothing to clear when DIRECT_TO_SCREEN is used
if ( rt - > flags [ RENDER_TARGET_DIRECT_TO_SCREEN ] ) {
return ;
}
if ( rt - > fbo ) {
glDeleteFramebuffers ( 1 , & rt - > fbo ) ;
glDeleteTextures ( 1 , & rt - > color ) ;
rt - > fbo = 0 ;
}
if ( rt - > external . fbo ! = 0 ) {
// free this
glDeleteFramebuffers ( 1 , & rt - > external . fbo ) ;
// clean up our texture
Texture * t = get_texture ( rt - > external . texture ) ;
t - > alloc_height = 0 ;
t - > alloc_width = 0 ;
t - > width = 0 ;
t - > height = 0 ;
t - > active = false ;
texture_free ( rt - > external . texture ) ;
memdelete ( t ) ;
rt - > external . fbo = 0 ;
}
if ( rt - > depth ) {
if ( config - > support_depth_texture ) {
glDeleteTextures ( 1 , & rt - > depth ) ;
} else {
glDeleteRenderbuffers ( 1 , & rt - > depth ) ;
}
rt - > depth = 0 ;
}
Texture * tex = get_texture ( rt - > texture ) ;
tex - > alloc_height = 0 ;
tex - > alloc_width = 0 ;
tex - > width = 0 ;
tex - > height = 0 ;
tex - > active = false ;
if ( rt - > copy_screen_effect . color ) {
glDeleteFramebuffers ( 1 , & rt - > copy_screen_effect . fbo ) ;
rt - > copy_screen_effect . fbo = 0 ;
glDeleteTextures ( 1 , & rt - > copy_screen_effect . color ) ;
rt - > copy_screen_effect . color = 0 ;
}
for ( int i = 0 ; i < 2 ; i + + ) {
if ( rt - > mip_maps [ i ] . sizes . size ( ) ) {
for ( int j = 0 ; j < rt - > mip_maps [ i ] . sizes . size ( ) ; j + + ) {
glDeleteFramebuffers ( 1 , & rt - > mip_maps [ i ] . sizes [ j ] . fbo ) ;
glDeleteTextures ( 1 , & rt - > mip_maps [ i ] . sizes [ j ] . color ) ;
}
glDeleteTextures ( 1 , & rt - > mip_maps [ i ] . color ) ;
rt - > mip_maps [ i ] . sizes . clear ( ) ;
rt - > mip_maps [ i ] . levels = 0 ;
rt - > mip_maps [ i ] . color = 0 ;
}
}
if ( rt - > multisample_active ) {
glDeleteFramebuffers ( 1 , & rt - > multisample_fbo ) ;
rt - > multisample_fbo = 0 ;
glDeleteRenderbuffers ( 1 , & rt - > multisample_depth ) ;
rt - > multisample_depth = 0 ;
glDeleteRenderbuffers ( 1 , & rt - > multisample_color ) ;
rt - > multisample_color = 0 ;
}
}
RID TextureStorage : : render_target_create ( ) {
RenderTarget * rt = memnew ( RenderTarget ) ;
Texture * t = memnew ( Texture ) ;
t - > type = RenderingDevice : : TEXTURE_TYPE_2D ;
t - > flags = 0 ;
t - > width = 0 ;
t - > height = 0 ;
t - > alloc_height = 0 ;
t - > alloc_width = 0 ;
t - > format = Image : : FORMAT_R8 ;
t - > target = GL_TEXTURE_2D ;
t - > gl_format_cache = 0 ;
t - > gl_internal_format_cache = 0 ;
t - > gl_type_cache = 0 ;
t - > data_size = 0 ;
t - > total_data_size = 0 ;
t - > ignore_mipmaps = false ;
t - > compressed = false ;
t - > mipmaps = 1 ;
t - > active = true ;
t - > tex_id = 0 ;
t - > render_target = rt ;
rt - > texture = make_rid ( t ) ;
return render_target_owner . make_rid ( rt ) ;
}
void TextureStorage : : render_target_free ( RID p_rid ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_rid ) ;
_render_target_clear ( rt ) ;
Texture * t = get_texture ( rt - > texture ) ;
if ( t ) {
texture_free ( rt - > texture ) ;
memdelete ( t ) ;
}
render_target_owner . free ( p_rid ) ;
memdelete ( rt ) ;
}
void TextureStorage : : render_target_set_position ( RID p_render_target , int p_x , int p_y ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND ( ! rt ) ;
rt - > x = p_x ;
rt - > y = p_y ;
}
void TextureStorage : : render_target_set_size ( RID p_render_target , int p_width , int p_height , uint32_t p_view_count ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND ( ! rt ) ;
if ( p_width = = rt - > width & & p_height = = rt - > height ) {
return ;
}
_render_target_clear ( rt ) ;
rt - > width = p_width ;
rt - > height = p_height ;
// print_line("render_target_set_size " + itos(p_render_target.get_id()) + ", w " + itos(p_width) + " h " + itos(p_height));
rt - > allocate_is_dirty = true ;
//_render_target_allocate(rt);
}
// TODO: convert to Size2i internally
Size2i TextureStorage : : render_target_get_size ( RID p_render_target ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND_V ( ! rt , Size2 ( ) ) ;
return Size2i ( rt - > width , rt - > height ) ;
}
RID TextureStorage : : render_target_get_texture ( RID p_render_target ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND_V ( ! rt , RID ( ) ) ;
if ( rt - > external . fbo = = 0 ) {
return rt - > texture ;
} else {
return rt - > external . texture ;
}
}
void TextureStorage : : render_target_set_external_texture ( RID p_render_target , unsigned int p_texture_id ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND ( ! rt ) ;
Config * config = Config : : get_singleton ( ) ;
if ( p_texture_id = = 0 ) {
if ( rt - > external . fbo ! = 0 ) {
// free this
glDeleteFramebuffers ( 1 , & rt - > external . fbo ) ;
// and this
if ( rt - > external . depth ! = 0 ) {
glDeleteRenderbuffers ( 1 , & rt - > external . depth ) ;
}
// clean up our texture
Texture * t = get_texture ( rt - > external . texture ) ;
t - > alloc_height = 0 ;
t - > alloc_width = 0 ;
t - > width = 0 ;
t - > height = 0 ;
t - > active = false ;
texture_free ( rt - > external . texture ) ;
memdelete ( t ) ;
rt - > external . fbo = 0 ;
rt - > external . color = 0 ;
rt - > external . depth = 0 ;
}
} else {
Texture * t ;
if ( rt - > external . fbo = = 0 ) {
// create our fbo
glGenFramebuffers ( 1 , & rt - > external . fbo ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , rt - > external . fbo ) ;
// allocate a texture
t = memnew ( Texture ) ;
t - > type = RenderingDevice : : TEXTURE_TYPE_2D ;
t - > flags = 0 ;
t - > width = 0 ;
t - > height = 0 ;
t - > alloc_height = 0 ;
t - > alloc_width = 0 ;
t - > format = Image : : FORMAT_RGBA8 ;
t - > target = GL_TEXTURE_2D ;
t - > gl_format_cache = 0 ;
t - > gl_internal_format_cache = 0 ;
t - > gl_type_cache = 0 ;
t - > data_size = 0 ;
t - > compressed = false ;
t - > srgb = false ;
t - > total_data_size = 0 ;
t - > ignore_mipmaps = false ;
t - > mipmaps = 1 ;
t - > active = true ;
t - > tex_id = 0 ;
t - > render_target = rt ;
rt - > external . texture = make_rid ( t ) ;
} else {
// bind our frame buffer
glBindFramebuffer ( GL_FRAMEBUFFER , rt - > external . fbo ) ;
// find our texture
t = get_texture ( rt - > external . texture ) ;
}
// set our texture
t - > tex_id = p_texture_id ;
rt - > external . color = p_texture_id ;
// size shouldn't be different
t - > width = rt - > width ;
t - > height = rt - > height ;
t - > alloc_height = rt - > width ;
t - > alloc_width = rt - > height ;
// Switch our texture on our frame buffer
{
// set our texture as the destination for our framebuffer
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , p_texture_id , 0 ) ;
// seeing we're rendering into this directly, better also use our depth buffer, just use our existing one :)
if ( config - > support_depth_texture ) {
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_TEXTURE_2D , rt - > depth , 0 ) ;
} else {
glFramebufferRenderbuffer ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_RENDERBUFFER , rt - > depth ) ;
}
}
// check status and unbind
GLenum status = glCheckFramebufferStatus ( GL_FRAMEBUFFER ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , GLES3 : : TextureStorage : : system_fbo ) ;
if ( status ! = GL_FRAMEBUFFER_COMPLETE ) {
printf ( " framebuffer fail, status: %x \n " , status ) ;
}
ERR_FAIL_COND ( status ! = GL_FRAMEBUFFER_COMPLETE ) ;
}
}
void TextureStorage : : render_target_set_flag ( RID p_render_target , RenderTargetFlags p_flag , bool p_value ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND ( ! rt ) ;
// When setting DIRECT_TO_SCREEN, you need to clear before the value is set, but allocate after as
// those functions change how they operate depending on the value of DIRECT_TO_SCREEN
if ( p_flag = = RENDER_TARGET_DIRECT_TO_SCREEN & & p_value ! = rt - > flags [ RENDER_TARGET_DIRECT_TO_SCREEN ] ) {
_render_target_clear ( rt ) ;
rt - > flags [ p_flag ] = p_value ;
_render_target_allocate ( rt ) ;
}
rt - > flags [ p_flag ] = p_value ;
switch ( p_flag ) {
case RENDER_TARGET_TRANSPARENT :
/*
case RENDER_TARGET_HDR :
case RENDER_TARGET_NO_3D :
case RENDER_TARGET_NO_SAMPLING :
case RENDER_TARGET_NO_3D_EFFECTS : */
{
//must reset for these formats
_render_target_clear ( rt ) ;
_render_target_allocate ( rt ) ;
}
break ;
default : {
}
}
}
bool TextureStorage : : render_target_was_used ( RID p_render_target ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND_V ( ! rt , false ) ;
return rt - > used_in_frame ;
}
void TextureStorage : : render_target_clear_used ( RID p_render_target ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND ( ! rt ) ;
rt - > used_in_frame = false ;
}
void TextureStorage : : render_target_set_msaa ( RID p_render_target , RS : : ViewportMSAA p_msaa ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND ( ! rt ) ;
if ( rt - > msaa = = p_msaa ) {
return ;
}
_render_target_clear ( rt ) ;
rt - > msaa = p_msaa ;
_render_target_allocate ( rt ) ;
}
void TextureStorage : : render_target_set_use_fxaa ( RID p_render_target , bool p_fxaa ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND ( ! rt ) ;
rt - > use_fxaa = p_fxaa ;
}
void TextureStorage : : render_target_set_use_debanding ( RID p_render_target , bool p_debanding ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND ( ! rt ) ;
if ( p_debanding ) {
WARN_PRINT_ONCE ( " Debanding is not supported in the OpenGL backend. Switch to the Vulkan backend and make sure HDR is enabled. " ) ;
}
rt - > use_debanding = p_debanding ;
}
void TextureStorage : : render_target_request_clear ( RID p_render_target , const Color & p_clear_color ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND ( ! rt ) ;
rt - > clear_requested = true ;
rt - > clear_color = p_clear_color ;
// ERR_FAIL_COND(!frame.current_rt);
// frame.clear_request = true;
// frame.clear_request_color = p_color;
}
bool TextureStorage : : render_target_is_clear_requested ( RID p_render_target ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND_V ( ! rt , false ) ;
return rt - > clear_requested ;
}
Color TextureStorage : : render_target_get_clear_request_color ( RID p_render_target ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND_V ( ! rt , Color ( ) ) ;
return rt - > clear_color ;
}
void TextureStorage : : render_target_disable_clear_request ( RID p_render_target ) {
RenderTarget * rt = render_target_owner . get_or_null ( p_render_target ) ;
ERR_FAIL_COND ( ! rt ) ;
rt - > clear_requested = false ;
}
void TextureStorage : : render_target_do_clear_request ( RID p_render_target ) {
}
void TextureStorage : : render_target_set_sdf_size_and_scale ( RID p_render_target , RS : : ViewportSDFOversize p_size , RS : : ViewportSDFScale p_scale ) {
}
Rect2i TextureStorage : : render_target_get_sdf_rect ( RID p_render_target ) const {
return Rect2i ( ) ;
}
void TextureStorage : : render_target_mark_sdf_enabled ( RID p_render_target , bool p_enabled ) {
}
2022-03-12 11:19:59 +00:00
# endif // GLES3_ENABLED