2020-11-18 18:11:30 +00:00
/*************************************************************************/
2021-10-26 15:18:39 +00:00
/* rasterizer_canvas_gles3.cpp */
2020-11-18 18:11:30 +00:00
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
2022-01-03 20:27:34 +00:00
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
2020-11-18 18:11:30 +00:00
/* */
/* 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. */
/*************************************************************************/
2021-10-26 15:18:39 +00:00
# include "rasterizer_canvas_gles3.h"
2021-11-16 15:25:42 +00:00
# ifdef GLES3_ENABLED
2020-11-18 18:11:30 +00:00
# include "core/os/os.h"
2021-10-26 15:18:39 +00:00
# include "rasterizer_scene_gles3.h"
2020-11-18 18:11:30 +00:00
# include "core/config/project_settings.h"
2022-10-19 00:59:31 +00:00
# include "core/math/geometry_2d.h"
2020-11-18 18:11:30 +00:00
# include "servers/rendering/rendering_server_default.h"
2022-03-12 11:19:59 +00:00
# include "storage/config.h"
2022-03-21 11:25:25 +00:00
# include "storage/material_storage.h"
2022-06-21 00:08:33 +00:00
# include "storage/mesh_storage.h"
2022-11-08 06:40:03 +00:00
# include "storage/particles_storage.h"
2022-04-07 14:00:51 +00:00
# include "storage/texture_storage.h"
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
void RasterizerCanvasGLES3 : : _update_transform_2d_to_mat4 ( const Transform2D & p_transform , float * p_mat4 ) {
2022-04-24 21:59:24 +00:00
p_mat4 [ 0 ] = p_transform . columns [ 0 ] [ 0 ] ;
p_mat4 [ 1 ] = p_transform . columns [ 0 ] [ 1 ] ;
2021-11-16 15:25:42 +00:00
p_mat4 [ 2 ] = 0 ;
p_mat4 [ 3 ] = 0 ;
2022-04-24 21:59:24 +00:00
p_mat4 [ 4 ] = p_transform . columns [ 1 ] [ 0 ] ;
p_mat4 [ 5 ] = p_transform . columns [ 1 ] [ 1 ] ;
2021-11-16 15:25:42 +00:00
p_mat4 [ 6 ] = 0 ;
p_mat4 [ 7 ] = 0 ;
p_mat4 [ 8 ] = 0 ;
p_mat4 [ 9 ] = 0 ;
p_mat4 [ 10 ] = 1 ;
p_mat4 [ 11 ] = 0 ;
2022-04-24 21:59:24 +00:00
p_mat4 [ 12 ] = p_transform . columns [ 2 ] [ 0 ] ;
p_mat4 [ 13 ] = p_transform . columns [ 2 ] [ 1 ] ;
2021-11-16 15:25:42 +00:00
p_mat4 [ 14 ] = 0 ;
p_mat4 [ 15 ] = 1 ;
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
void RasterizerCanvasGLES3 : : _update_transform_2d_to_mat2x4 ( const Transform2D & p_transform , float * p_mat2x4 ) {
2022-04-24 21:59:24 +00:00
p_mat2x4 [ 0 ] = p_transform . columns [ 0 ] [ 0 ] ;
p_mat2x4 [ 1 ] = p_transform . columns [ 1 ] [ 0 ] ;
2021-11-16 15:25:42 +00:00
p_mat2x4 [ 2 ] = 0 ;
2022-04-24 21:59:24 +00:00
p_mat2x4 [ 3 ] = p_transform . columns [ 2 ] [ 0 ] ;
2020-11-18 18:11:30 +00:00
2022-04-24 21:59:24 +00:00
p_mat2x4 [ 4 ] = p_transform . columns [ 0 ] [ 1 ] ;
p_mat2x4 [ 5 ] = p_transform . columns [ 1 ] [ 1 ] ;
2021-11-16 15:25:42 +00:00
p_mat2x4 [ 6 ] = 0 ;
2022-04-24 21:59:24 +00:00
p_mat2x4 [ 7 ] = p_transform . columns [ 2 ] [ 1 ] ;
2021-11-16 15:25:42 +00:00
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
void RasterizerCanvasGLES3 : : _update_transform_2d_to_mat2x3 ( const Transform2D & p_transform , float * p_mat2x3 ) {
2022-04-24 21:59:24 +00:00
p_mat2x3 [ 0 ] = p_transform . columns [ 0 ] [ 0 ] ;
p_mat2x3 [ 1 ] = p_transform . columns [ 0 ] [ 1 ] ;
p_mat2x3 [ 2 ] = p_transform . columns [ 1 ] [ 0 ] ;
p_mat2x3 [ 3 ] = p_transform . columns [ 1 ] [ 1 ] ;
p_mat2x3 [ 4 ] = p_transform . columns [ 2 ] [ 0 ] ;
p_mat2x3 [ 5 ] = p_transform . columns [ 2 ] [ 1 ] ;
2021-11-16 15:25:42 +00:00
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
void RasterizerCanvasGLES3 : : _update_transform_to_mat4 ( const Transform3D & p_transform , float * p_mat4 ) {
2022-04-24 22:07:35 +00:00
p_mat4 [ 0 ] = p_transform . basis . rows [ 0 ] [ 0 ] ;
p_mat4 [ 1 ] = p_transform . basis . rows [ 1 ] [ 0 ] ;
p_mat4 [ 2 ] = p_transform . basis . rows [ 2 ] [ 0 ] ;
2021-11-16 15:25:42 +00:00
p_mat4 [ 3 ] = 0 ;
2022-04-24 22:07:35 +00:00
p_mat4 [ 4 ] = p_transform . basis . rows [ 0 ] [ 1 ] ;
p_mat4 [ 5 ] = p_transform . basis . rows [ 1 ] [ 1 ] ;
p_mat4 [ 6 ] = p_transform . basis . rows [ 2 ] [ 1 ] ;
2021-11-16 15:25:42 +00:00
p_mat4 [ 7 ] = 0 ;
2022-04-24 22:07:35 +00:00
p_mat4 [ 8 ] = p_transform . basis . rows [ 0 ] [ 2 ] ;
p_mat4 [ 9 ] = p_transform . basis . rows [ 1 ] [ 2 ] ;
p_mat4 [ 10 ] = p_transform . basis . rows [ 2 ] [ 2 ] ;
2021-11-16 15:25:42 +00:00
p_mat4 [ 11 ] = 0 ;
p_mat4 [ 12 ] = p_transform . origin . x ;
p_mat4 [ 13 ] = p_transform . origin . y ;
p_mat4 [ 14 ] = p_transform . origin . z ;
p_mat4 [ 15 ] = 1 ;
2020-11-18 18:11:30 +00:00
}
2022-10-13 00:55:01 +00:00
void RasterizerCanvasGLES3 : : canvas_render_items ( RID p_to_render_target , Item * p_item_list , const Color & p_modulate , Light * p_light_list , Light * p_directional_light_list , const Transform2D & p_canvas_transform , RS : : CanvasItemTextureFilter p_default_filter , RS : : CanvasItemTextureRepeat p_default_repeat , bool p_snap_2d_vertices_to_pixel , bool & r_sdf_used ) {
2022-04-07 14:00:51 +00:00
GLES3 : : TextureStorage * texture_storage = GLES3 : : TextureStorage : : get_singleton ( ) ;
2022-02-20 00:08:53 +00:00
GLES3 : : MaterialStorage * material_storage = GLES3 : : MaterialStorage : : get_singleton ( ) ;
2022-11-25 23:30:36 +00:00
GLES3 : : MeshStorage * mesh_storage = GLES3 : : MeshStorage : : get_singleton ( ) ;
2022-04-07 14:00:51 +00:00
2021-11-16 15:25:42 +00:00
Transform2D canvas_transform_inverse = p_canvas_transform . affine_inverse ( ) ;
2020-11-18 18:11:30 +00:00
2022-05-18 15:04:41 +00:00
// Clear out any state that may have been left from the 3D pass.
reset_canvas ( ) ;
2022-06-21 04:56:26 +00:00
if ( state . canvas_instance_data_buffers [ state . current_buffer ] . fence ! = GLsync ( ) ) {
GLint syncStatus ;
glGetSynciv ( state . canvas_instance_data_buffers [ state . current_buffer ] . fence , GL_SYNC_STATUS , sizeof ( GLint ) , nullptr , & syncStatus ) ;
if ( syncStatus = = GL_UNSIGNALED ) {
// If older than 2 frames, wait for sync OpenGL can have up to 3 frames in flight, any more and we need to sync anyway.
if ( state . canvas_instance_data_buffers [ state . current_buffer ] . last_frame_used < RSG : : rasterizer - > get_frame_number ( ) - 2 ) {
2022-10-14 18:18:27 +00:00
# ifndef WEB_ENABLED
// On web, we do nothing as the glSubBufferData will force a sync anyway and WebGL does not like waiting.
2022-06-21 04:56:26 +00:00
glClientWaitSync ( state . canvas_instance_data_buffers [ state . current_buffer ] . fence , 0 , 100000000 ) ; // wait for up to 100ms
2022-10-14 18:18:27 +00:00
# endif
2022-06-21 04:56:26 +00:00
} else {
// Used in last frame or frame before that. OpenGL can get up to two frames behind, so these buffers may still be in use
// Allocate a new buffer and use that.
_allocate_instance_data_buffer ( ) ;
}
} else {
// Already finished all rendering commands, we can use it.
state . canvas_instance_data_buffers [ state . current_buffer ] . last_frame_used = RSG : : rasterizer - > get_frame_number ( ) ;
glDeleteSync ( state . canvas_instance_data_buffers [ state . current_buffer ] . fence ) ;
state . canvas_instance_data_buffers [ state . current_buffer ] . fence = GLsync ( ) ;
}
}
2022-10-13 00:55:01 +00:00
//setup directional lights if exist
2020-11-18 18:11:30 +00:00
2022-10-13 00:55:01 +00:00
uint32_t light_count = 0 ;
uint32_t directional_light_count = 0 ;
{
Light * l = p_directional_light_list ;
uint32_t index = 0 ;
while ( l ) {
if ( index = = data . max_lights_per_render ) {
l - > render_index_cache = - 1 ;
l = l - > next_ptr ;
continue ;
}
CanvasLight * clight = canvas_light_owner . get_or_null ( l - > light_internal ) ;
if ( ! clight ) { //unused or invalid texture
l - > render_index_cache = - 1 ;
l = l - > next_ptr ;
ERR_CONTINUE ( ! clight ) ;
}
Vector2 canvas_light_dir = l - > xform_cache . columns [ 1 ] . normalized ( ) ;
state . light_uniforms [ index ] . position [ 0 ] = - canvas_light_dir . x ;
state . light_uniforms [ index ] . position [ 1 ] = - canvas_light_dir . y ;
2022-10-19 00:59:31 +00:00
_update_transform_2d_to_mat2x4 ( clight - > shadow . directional_xform , state . light_uniforms [ index ] . shadow_matrix ) ;
2022-10-13 00:55:01 +00:00
state . light_uniforms [ index ] . height = l - > height ; //0..1 here
for ( int i = 0 ; i < 4 ; i + + ) {
state . light_uniforms [ index ] . shadow_color [ i ] = uint8_t ( CLAMP ( int32_t ( l - > shadow_color [ i ] * 255.0 ) , 0 , 255 ) ) ;
state . light_uniforms [ index ] . color [ i ] = l - > color [ i ] ;
}
state . light_uniforms [ index ] . color [ 3 ] = l - > energy ; //use alpha for energy, so base color can go separate
2022-10-19 00:59:31 +00:00
if ( state . shadow_fb ! = 0 ) {
2022-10-13 00:55:01 +00:00
state . light_uniforms [ index ] . shadow_pixel_size = ( 1.0 / state . shadow_texture_size ) * ( 1.0 + l - > shadow_smooth ) ;
state . light_uniforms [ index ] . shadow_z_far_inv = 1.0 / clight - > shadow . z_far ;
state . light_uniforms [ index ] . shadow_y_ofs = clight - > shadow . y_offset ;
} else {
state . light_uniforms [ index ] . shadow_pixel_size = 1.0 ;
state . light_uniforms [ index ] . shadow_z_far_inv = 1.0 ;
state . light_uniforms [ index ] . shadow_y_ofs = 0 ;
}
state . light_uniforms [ index ] . flags = l - > blend_mode < < LIGHT_FLAGS_BLEND_SHIFT ;
state . light_uniforms [ index ] . flags | = l - > shadow_filter < < LIGHT_FLAGS_FILTER_SHIFT ;
2022-10-19 00:59:31 +00:00
2022-10-13 00:55:01 +00:00
if ( clight - > shadow . enabled ) {
state . light_uniforms [ index ] . flags | = LIGHT_FLAGS_HAS_SHADOW ;
}
l - > render_index_cache = index ;
index + + ;
l = l - > next_ptr ;
}
light_count = index ;
directional_light_count = light_count ;
state . using_directional_lights = directional_light_count > 0 ;
}
//setup lights if exist
{
Light * l = p_light_list ;
uint32_t index = light_count ;
while ( l ) {
if ( index = = data . max_lights_per_render ) {
l - > render_index_cache = - 1 ;
l = l - > next_ptr ;
continue ;
}
CanvasLight * clight = canvas_light_owner . get_or_null ( l - > light_internal ) ;
if ( ! clight ) { //unused or invalid texture
l - > render_index_cache = - 1 ;
l = l - > next_ptr ;
ERR_CONTINUE ( ! clight ) ;
}
Transform2D to_light_xform = ( p_canvas_transform * l - > light_shader_xform ) . affine_inverse ( ) ;
Vector2 canvas_light_pos = p_canvas_transform . xform ( l - > xform . get_origin ( ) ) ; //convert light position to canvas coordinates, as all computation is done in canvas coords to avoid precision loss
state . light_uniforms [ index ] . position [ 0 ] = canvas_light_pos . x ;
state . light_uniforms [ index ] . position [ 1 ] = canvas_light_pos . y ;
_update_transform_2d_to_mat2x4 ( to_light_xform , state . light_uniforms [ index ] . matrix ) ;
_update_transform_2d_to_mat2x4 ( l - > xform_cache . affine_inverse ( ) , state . light_uniforms [ index ] . shadow_matrix ) ;
state . light_uniforms [ index ] . height = l - > height * ( p_canvas_transform . columns [ 0 ] . length ( ) + p_canvas_transform . columns [ 1 ] . length ( ) ) * 0.5 ; //approximate height conversion to the canvas size, since all calculations are done in canvas coords to avoid precision loss
for ( int i = 0 ; i < 4 ; i + + ) {
state . light_uniforms [ index ] . shadow_color [ i ] = uint8_t ( CLAMP ( int32_t ( l - > shadow_color [ i ] * 255.0 ) , 0 , 255 ) ) ;
state . light_uniforms [ index ] . color [ i ] = l - > color [ i ] ;
}
state . light_uniforms [ index ] . color [ 3 ] = l - > energy ; //use alpha for energy, so base color can go separate
2022-10-19 00:59:31 +00:00
if ( state . shadow_fb ! = 0 ) {
state . light_uniforms [ index ] . shadow_pixel_size = ( 1.0 / state . shadow_texture_size ) * ( 1.0 + l - > shadow_smooth ) ;
state . light_uniforms [ index ] . shadow_z_far_inv = 1.0 / clight - > shadow . z_far ;
state . light_uniforms [ index ] . shadow_y_ofs = clight - > shadow . y_offset ;
} else {
state . light_uniforms [ index ] . shadow_pixel_size = 1.0 ;
state . light_uniforms [ index ] . shadow_z_far_inv = 1.0 ;
state . light_uniforms [ index ] . shadow_y_ofs = 0 ;
}
2022-10-13 00:55:01 +00:00
state . light_uniforms [ index ] . flags = l - > blend_mode < < LIGHT_FLAGS_BLEND_SHIFT ;
state . light_uniforms [ index ] . flags | = l - > shadow_filter < < LIGHT_FLAGS_FILTER_SHIFT ;
2022-10-19 00:59:31 +00:00
2022-10-13 00:55:01 +00:00
if ( clight - > shadow . enabled ) {
state . light_uniforms [ index ] . flags | = LIGHT_FLAGS_HAS_SHADOW ;
}
if ( clight - > texture . is_valid ( ) ) {
Rect2 atlas_rect = GLES3 : : TextureStorage : : get_singleton ( ) - > texture_atlas_get_texture_rect ( clight - > texture ) ;
state . light_uniforms [ index ] . atlas_rect [ 0 ] = atlas_rect . position . x ;
state . light_uniforms [ index ] . atlas_rect [ 1 ] = atlas_rect . position . y ;
state . light_uniforms [ index ] . atlas_rect [ 2 ] = atlas_rect . size . width ;
state . light_uniforms [ index ] . atlas_rect [ 3 ] = atlas_rect . size . height ;
} else {
state . light_uniforms [ index ] . atlas_rect [ 0 ] = 0 ;
state . light_uniforms [ index ] . atlas_rect [ 1 ] = 0 ;
state . light_uniforms [ index ] . atlas_rect [ 2 ] = 0 ;
state . light_uniforms [ index ] . atlas_rect [ 3 ] = 0 ;
}
l - > render_index_cache = index ;
index + + ;
l = l - > next_ptr ;
}
light_count = index ;
}
if ( light_count > 0 ) {
glBindBufferBase ( GL_UNIFORM_BUFFER , LIGHT_UNIFORM_LOCATION , state . canvas_instance_data_buffers [ state . current_buffer ] . light_ubo ) ;
# ifdef WEB_ENABLED
glBufferSubData ( GL_UNIFORM_BUFFER , 0 , sizeof ( LightUniform ) * light_count , state . light_uniforms ) ;
# else
// On Desktop and mobile we map the memory without synchronizing for maximum speed.
void * ubo = glMapBufferRange ( GL_UNIFORM_BUFFER , 0 , sizeof ( LightUniform ) * light_count , GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT ) ;
memcpy ( ubo , state . light_uniforms , sizeof ( LightUniform ) * light_count ) ;
glUnmapBuffer ( GL_UNIFORM_BUFFER ) ;
# endif
GLuint texture_atlas = texture_storage - > texture_atlas_get_texture ( ) ;
if ( texture_atlas = = 0 ) {
GLES3 : : Texture * tex = texture_storage - > get_texture ( texture_storage - > texture_gl_get_default ( GLES3 : : DEFAULT_GL_TEXTURE_WHITE ) ) ;
texture_atlas = tex - > tex_id ;
}
glActiveTexture ( GL_TEXTURE0 + GLES3 : : Config : : get_singleton ( ) - > max_texture_image_units - 2 ) ;
glBindTexture ( GL_TEXTURE_2D , texture_atlas ) ;
2022-10-19 00:59:31 +00:00
GLuint shadow_tex = state . shadow_texture ;
if ( shadow_tex = = 0 ) {
GLES3 : : Texture * tex = texture_storage - > get_texture ( texture_storage - > texture_gl_get_default ( GLES3 : : DEFAULT_GL_TEXTURE_WHITE ) ) ;
shadow_tex = tex - > tex_id ;
}
glActiveTexture ( GL_TEXTURE0 + GLES3 : : Config : : get_singleton ( ) - > max_texture_image_units - 3 ) ;
glBindTexture ( GL_TEXTURE_2D , shadow_tex ) ;
2022-10-13 00:55:01 +00:00
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
{
//update canvas state uniform buffer
StateBuffer state_buffer ;
2020-11-18 18:11:30 +00:00
2022-04-07 14:00:51 +00:00
Size2i ssize = texture_storage - > render_target_get_size ( p_to_render_target ) ;
2020-11-18 18:11:30 +00:00
2022-11-19 02:43:11 +00:00
// If we've overridden the render target's color texture, then we need
// to invert the Y axis, so 2D texture appear right side up.
// We're probably rendering directly to an XR device.
float y_scale = texture_storage - > render_target_get_override_color ( p_to_render_target ) . is_valid ( ) ? - 2.0f : 2.0f ;
2021-11-16 15:25:42 +00:00
Transform3D screen_transform ;
2022-07-16 09:47:54 +00:00
screen_transform . translate_local ( - ( ssize . width / 2.0f ) , - ( ssize . height / 2.0f ) , 0.0f ) ;
2022-11-19 02:43:11 +00:00
screen_transform . scale ( Vector3 ( 2.0f / ssize . width , y_scale / ssize . height , 1.0f ) ) ;
2021-11-16 15:25:42 +00:00
_update_transform_to_mat4 ( screen_transform , state_buffer . screen_transform ) ;
_update_transform_2d_to_mat4 ( p_canvas_transform , state_buffer . canvas_transform ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
Transform2D normal_transform = p_canvas_transform ;
2022-04-24 21:59:24 +00:00
normal_transform . columns [ 0 ] . normalize ( ) ;
normal_transform . columns [ 1 ] . normalize ( ) ;
normal_transform . columns [ 2 ] = Vector2 ( ) ;
2021-11-16 15:25:42 +00:00
_update_transform_2d_to_mat4 ( normal_transform , state_buffer . canvas_normal_transform ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
state_buffer . canvas_modulate [ 0 ] = p_modulate . r ;
state_buffer . canvas_modulate [ 1 ] = p_modulate . g ;
state_buffer . canvas_modulate [ 2 ] = p_modulate . b ;
state_buffer . canvas_modulate [ 3 ] = p_modulate . a ;
2020-11-18 18:11:30 +00:00
2022-04-07 14:00:51 +00:00
Size2 render_target_size = texture_storage - > render_target_get_size ( p_to_render_target ) ;
2021-11-16 15:25:42 +00:00
state_buffer . screen_pixel_size [ 0 ] = 1.0 / render_target_size . x ;
state_buffer . screen_pixel_size [ 1 ] = 1.0 / render_target_size . y ;
2020-11-18 18:11:30 +00:00
2022-02-20 00:08:53 +00:00
state_buffer . time = state . time ;
2021-11-16 15:25:42 +00:00
state_buffer . use_pixel_snap = p_snap_2d_vertices_to_pixel ;
2020-11-18 18:11:30 +00:00
2022-10-13 00:55:01 +00:00
state_buffer . directional_light_count = directional_light_count ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
Vector2 canvas_scale = p_canvas_transform . get_scale ( ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
state_buffer . sdf_to_screen [ 0 ] = render_target_size . width / canvas_scale . x ;
state_buffer . sdf_to_screen [ 1 ] = render_target_size . height / canvas_scale . y ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
state_buffer . screen_to_sdf [ 0 ] = 1.0 / state_buffer . sdf_to_screen [ 0 ] ;
state_buffer . screen_to_sdf [ 1 ] = 1.0 / state_buffer . sdf_to_screen [ 1 ] ;
2020-11-18 18:11:30 +00:00
2022-04-07 14:00:51 +00:00
Rect2 sdf_rect = texture_storage - > render_target_get_sdf_rect ( p_to_render_target ) ;
2021-11-16 15:25:42 +00:00
Rect2 sdf_tex_rect ( sdf_rect . position / canvas_scale , sdf_rect . size / canvas_scale ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
state_buffer . sdf_to_tex [ 0 ] = 1.0 / sdf_tex_rect . size . width ;
state_buffer . sdf_to_tex [ 1 ] = 1.0 / sdf_tex_rect . size . height ;
state_buffer . sdf_to_tex [ 2 ] = - sdf_tex_rect . position . x / sdf_tex_rect . size . width ;
state_buffer . sdf_to_tex [ 3 ] = - sdf_tex_rect . position . y / sdf_tex_rect . size . height ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
state_buffer . tex_to_sdf = 1.0 / ( ( canvas_scale . x + canvas_scale . y ) * 0.5 ) ;
2022-10-19 00:59:31 +00:00
2022-10-13 00:55:01 +00:00
glBindBufferBase ( GL_UNIFORM_BUFFER , BASE_UNIFORM_LOCATION , state . canvas_instance_data_buffers [ state . current_buffer ] . state_ubo ) ;
2021-11-16 15:25:42 +00:00
glBufferData ( GL_UNIFORM_BUFFER , sizeof ( StateBuffer ) , & state_buffer , GL_STREAM_DRAW ) ;
2022-02-20 00:08:53 +00:00
2022-08-27 09:22:43 +00:00
GLuint global_buffer = material_storage - > global_shader_parameters_get_uniform_buffer ( ) ;
2022-02-20 00:08:53 +00:00
2022-05-10 17:02:44 +00:00
glBindBufferBase ( GL_UNIFORM_BUFFER , GLOBAL_UNIFORM_LOCATION , global_buffer ) ;
2021-11-16 15:25:42 +00:00
glBindBuffer ( GL_UNIFORM_BUFFER , 0 ) ;
2020-11-18 18:11:30 +00:00
}
2022-10-19 00:59:31 +00:00
glActiveTexture ( GL_TEXTURE0 + GLES3 : : Config : : get_singleton ( ) - > max_texture_image_units - 5 ) ;
glBindTexture ( GL_TEXTURE_2D , texture_storage - > render_target_get_sdf_texture ( p_to_render_target ) ) ;
2021-11-16 15:25:42 +00:00
{
state . default_filter = p_default_filter ;
state . default_repeat = p_default_repeat ;
}
2020-11-18 18:11:30 +00:00
2022-10-19 00:59:31 +00:00
Size2 render_target_size = texture_storage - > render_target_get_size ( p_to_render_target ) ;
glViewport ( 0 , 0 , render_target_size . x , render_target_size . y ) ;
2021-11-16 15:25:42 +00:00
r_sdf_used = false ;
int item_count = 0 ;
2022-05-18 15:04:41 +00:00
bool backbuffer_cleared = false ;
bool time_used = false ;
2022-09-15 00:36:39 +00:00
bool material_screen_texture_cached = false ;
bool material_screen_texture_mipmaps_cached = false ;
2022-05-18 15:04:41 +00:00
Rect2 back_buffer_rect ;
bool backbuffer_copy = false ;
2022-08-09 16:29:49 +00:00
bool backbuffer_gen_mipmaps = false ;
2022-11-25 23:30:36 +00:00
bool update_skeletons = false ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
Item * ci = p_item_list ;
2022-05-18 15:04:41 +00:00
Item * canvas_group_owner = nullptr ;
2022-06-21 04:56:26 +00:00
uint32_t starting_index = 0 ;
2021-11-16 15:25:42 +00:00
while ( ci ) {
2022-05-18 15:04:41 +00:00
if ( ci - > copy_back_buffer & & canvas_group_owner = = nullptr ) {
backbuffer_copy = true ;
if ( ci - > copy_back_buffer - > full ) {
back_buffer_rect = Rect2 ( ) ;
} else {
back_buffer_rect = ci - > copy_back_buffer - > rect ;
}
}
// Check material for something that may change flow of rendering, but do not bind for now.
RID material = ci - > material_owner = = nullptr ? ci - > material : ci - > material_owner - > material ;
if ( material . is_valid ( ) ) {
GLES3 : : CanvasMaterialData * md = static_cast < GLES3 : : CanvasMaterialData * > ( material_storage - > material_get_data ( material , RS : : SHADER_CANVAS_ITEM ) ) ;
if ( md & & md - > shader_data - > valid ) {
if ( md - > shader_data - > uses_screen_texture & & canvas_group_owner = = nullptr ) {
2022-09-15 00:36:39 +00:00
if ( ! material_screen_texture_cached ) {
2022-05-18 15:04:41 +00:00
backbuffer_copy = true ;
back_buffer_rect = Rect2 ( ) ;
2022-08-09 16:29:49 +00:00
backbuffer_gen_mipmaps = md - > shader_data - > uses_screen_texture_mipmaps ;
2022-09-15 00:36:39 +00:00
} else if ( ! material_screen_texture_mipmaps_cached ) {
backbuffer_gen_mipmaps = md - > shader_data - > uses_screen_texture_mipmaps ;
2022-05-18 15:04:41 +00:00
}
}
if ( md - > shader_data - > uses_sdf ) {
r_sdf_used = true ;
}
if ( md - > shader_data - > uses_time ) {
time_used = true ;
}
}
}
2022-11-25 23:30:36 +00:00
if ( ci - > skeleton . is_valid ( ) ) {
const Item : : Command * c = ci - > commands ;
while ( c ) {
if ( c - > type = = Item : : Command : : TYPE_MESH ) {
const Item : : CommandMesh * cm = static_cast < const Item : : CommandMesh * > ( c ) ;
if ( cm - > mesh_instance . is_valid ( ) ) {
mesh_storage - > mesh_instance_check_for_update ( cm - > mesh_instance ) ;
update_skeletons = true ;
}
}
c = c - > next ;
}
}
2022-05-18 15:04:41 +00:00
if ( ci - > canvas_group_owner ! = nullptr ) {
if ( canvas_group_owner = = nullptr ) {
2022-11-25 23:30:36 +00:00
if ( update_skeletons ) {
mesh_storage - > update_mesh_instances ( ) ;
update_skeletons = false ;
}
2022-05-18 15:04:41 +00:00
// Canvas group begins here, render until before this item
2022-06-21 04:56:26 +00:00
_render_items ( p_to_render_target , item_count , canvas_transform_inverse , p_light_list , starting_index , false ) ;
2022-05-18 15:04:41 +00:00
item_count = 0 ;
2022-10-12 19:45:47 +00:00
if ( ci - > canvas_group_owner - > canvas_group - > mode ! = RS : : CANVAS_GROUP_MODE_TRANSPARENT ) {
2022-10-06 22:27:11 +00:00
Rect2i group_rect = ci - > canvas_group_owner - > global_rect_cache ;
2022-05-18 15:04:41 +00:00
texture_storage - > render_target_copy_to_back_buffer ( p_to_render_target , group_rect , false ) ;
2022-10-12 19:45:47 +00:00
if ( ci - > canvas_group_owner - > canvas_group - > mode = = RS : : CANVAS_GROUP_MODE_CLIP_AND_DRAW ) {
items [ item_count + + ] = ci - > canvas_group_owner ;
}
2022-05-18 15:04:41 +00:00
} else if ( ! backbuffer_cleared ) {
texture_storage - > render_target_clear_back_buffer ( p_to_render_target , Rect2i ( ) , Color ( 0 , 0 , 0 , 0 ) ) ;
backbuffer_cleared = true ;
}
backbuffer_copy = false ;
canvas_group_owner = ci - > canvas_group_owner ; //continue until owner found
}
ci - > canvas_group_owner = nullptr ; //must be cleared
}
if ( ! backbuffer_cleared & & canvas_group_owner = = nullptr & & ci - > canvas_group ! = nullptr & & ! backbuffer_copy ) {
texture_storage - > render_target_clear_back_buffer ( p_to_render_target , Rect2i ( ) , Color ( 0 , 0 , 0 , 0 ) ) ;
backbuffer_cleared = true ;
}
if ( ci = = canvas_group_owner ) {
2022-11-25 23:30:36 +00:00
if ( update_skeletons ) {
mesh_storage - > update_mesh_instances ( ) ;
update_skeletons = false ;
}
2022-06-21 04:56:26 +00:00
_render_items ( p_to_render_target , item_count , canvas_transform_inverse , p_light_list , starting_index , true ) ;
2022-05-18 15:04:41 +00:00
item_count = 0 ;
if ( ci - > canvas_group - > blur_mipmaps ) {
texture_storage - > render_target_gen_back_buffer_mipmaps ( p_to_render_target , ci - > global_rect_cache ) ;
}
canvas_group_owner = nullptr ;
2022-10-07 21:13:40 +00:00
// Backbuffer is dirty now and needs to be re-cleared if another CanvasGroup needs it.
backbuffer_cleared = false ;
2022-05-18 15:04:41 +00:00
}
if ( backbuffer_copy ) {
2022-11-25 23:30:36 +00:00
if ( update_skeletons ) {
mesh_storage - > update_mesh_instances ( ) ;
update_skeletons = false ;
}
2022-05-18 15:04:41 +00:00
//render anything pending, including clearing if no items
2022-06-21 04:56:26 +00:00
_render_items ( p_to_render_target , item_count , canvas_transform_inverse , p_light_list , starting_index , false ) ;
2022-05-18 15:04:41 +00:00
item_count = 0 ;
2022-08-09 16:29:49 +00:00
texture_storage - > render_target_copy_to_back_buffer ( p_to_render_target , back_buffer_rect , backbuffer_gen_mipmaps ) ;
2022-05-18 15:04:41 +00:00
backbuffer_copy = false ;
2022-09-15 00:36:39 +00:00
backbuffer_gen_mipmaps = false ;
material_screen_texture_cached = true ; // After a backbuffer copy, screen texture makes no further copies.
material_screen_texture_mipmaps_cached = backbuffer_gen_mipmaps ;
}
if ( backbuffer_gen_mipmaps ) {
texture_storage - > render_target_gen_back_buffer_mipmaps ( p_to_render_target , back_buffer_rect ) ;
backbuffer_gen_mipmaps = false ;
material_screen_texture_mipmaps_cached = true ;
2022-05-18 15:04:41 +00:00
}
2021-11-16 15:25:42 +00:00
// just add all items for now
items [ item_count + + ] = ci ;
if ( ! ci - > next | | item_count = = MAX_RENDER_ITEMS - 1 ) {
2022-11-25 23:30:36 +00:00
if ( update_skeletons ) {
mesh_storage - > update_mesh_instances ( ) ;
update_skeletons = false ;
}
2022-06-21 04:56:26 +00:00
_render_items ( p_to_render_target , item_count , canvas_transform_inverse , p_light_list , starting_index , false ) ;
2021-11-16 15:25:42 +00:00
//then reset
item_count = 0 ;
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
ci = ci - > next ;
2020-11-18 18:11:30 +00:00
}
2022-05-18 15:04:41 +00:00
if ( time_used ) {
RenderingServerDefault : : redraw_request ( ) ;
}
2022-06-21 04:56:26 +00:00
state . canvas_instance_data_buffers [ state . current_buffer ] . fence = glFenceSync ( GL_SYNC_GPU_COMMANDS_COMPLETE , 0 ) ;
2022-05-18 15:04:41 +00:00
// Clear out state used in 2D pass
reset_canvas ( ) ;
2022-06-21 04:56:26 +00:00
state . current_buffer = ( state . current_buffer + 1 ) % state . canvas_instance_data_buffers . size ( ) ;
2021-11-16 15:25:42 +00:00
}
2020-11-18 18:11:30 +00:00
2022-06-21 04:56:26 +00:00
void RasterizerCanvasGLES3 : : _render_items ( RID p_to_render_target , int p_item_count , const Transform2D & p_canvas_transform_inverse , Light * p_lights , uint32_t & r_last_index , bool p_to_backbuffer ) {
2022-03-21 11:25:25 +00:00
GLES3 : : MaterialStorage * material_storage = GLES3 : : MaterialStorage : : get_singleton ( ) ;
2020-11-18 18:11:30 +00:00
2022-05-18 15:04:41 +00:00
canvas_begin ( p_to_render_target , p_to_backbuffer ) ;
2020-11-18 18:11:30 +00:00
2022-06-21 04:56:26 +00:00
if ( p_item_count < = 0 ) {
// Nothing to draw, just call canvas_begin() to clear the render target and return.
return ;
}
2021-11-16 15:25:42 +00:00
uint32_t index = 0 ;
2022-06-21 04:56:26 +00:00
Item * current_clip = nullptr ;
// Record Batches.
// First item always forms its own batch.
bool batch_broken = false ;
_new_batch ( batch_broken , index ) ;
2020-11-18 18:11:30 +00:00
2022-06-21 04:56:26 +00:00
// Override the start position and index as we want to start from where we finished off last time.
state . canvas_instance_batches [ state . current_batch_index ] . start = r_last_index * sizeof ( InstanceData ) ;
index = 0 ;
_align_instance_data_buffer ( index ) ;
2022-02-20 00:08:53 +00:00
2021-11-16 15:25:42 +00:00
for ( int i = 0 ; i < p_item_count ; i + + ) {
Item * ci = items [ i ] ;
2020-11-18 18:11:30 +00:00
2022-06-21 04:56:26 +00:00
if ( ci - > final_clip_owner ! = state . canvas_instance_batches [ state . current_batch_index ] . clip ) {
_new_batch ( batch_broken , index ) ;
state . canvas_instance_batches [ state . current_batch_index ] . clip = ci - > final_clip_owner ;
2022-05-18 15:04:41 +00:00
current_clip = ci - > final_clip_owner ;
}
2021-11-16 15:25:42 +00:00
RID material = ci - > material_owner = = nullptr ? ci - > material : ci - > material_owner - > material ;
2022-10-06 22:27:11 +00:00
if ( ci - > canvas_group ! = nullptr ) {
2022-10-12 19:45:47 +00:00
if ( ci - > canvas_group - > mode = = RS : : CANVAS_GROUP_MODE_CLIP_AND_DRAW ) {
2022-10-06 22:27:11 +00:00
if ( ! p_to_backbuffer ) {
material = default_clip_children_material ;
}
} else {
2022-10-12 19:45:47 +00:00
if ( ci - > canvas_group - > mode = = RS : : CANVAS_GROUP_MODE_CLIP_ONLY ) {
material = default_clip_children_material ;
} else {
2022-10-06 22:27:11 +00:00
material = default_canvas_group_material ;
}
}
2021-11-16 15:25:42 +00:00
}
2020-11-18 18:11:30 +00:00
2022-06-21 04:56:26 +00:00
GLES3 : : CanvasShaderData * shader_data_cache = nullptr ;
if ( material ! = state . canvas_instance_batches [ state . current_batch_index ] . material ) {
_new_batch ( batch_broken , index ) ;
2022-02-20 00:08:53 +00:00
GLES3 : : CanvasMaterialData * material_data = nullptr ;
if ( material . is_valid ( ) ) {
material_data = static_cast < GLES3 : : CanvasMaterialData * > ( material_storage - > material_get_data ( material , RS : : SHADER_CANVAS_ITEM ) ) ;
2021-11-16 15:25:42 +00:00
}
2022-06-21 04:56:26 +00:00
shader_data_cache = nullptr ;
2022-02-20 00:08:53 +00:00
if ( material_data ) {
if ( material_data - > shader_data - > version . is_valid ( ) & & material_data - > shader_data - > valid ) {
2022-05-18 15:04:41 +00:00
shader_data_cache = material_data - > shader_data ;
2021-11-16 15:25:42 +00:00
}
}
2022-06-21 04:56:26 +00:00
state . canvas_instance_batches [ state . current_batch_index ] . material = material ;
state . canvas_instance_batches [ state . current_batch_index ] . material_data = material_data ;
2021-11-16 15:25:42 +00:00
}
2020-11-18 18:11:30 +00:00
2022-05-18 15:04:41 +00:00
GLES3 : : CanvasShaderData : : BlendMode blend_mode = shader_data_cache ? shader_data_cache - > blend_mode : GLES3 : : CanvasShaderData : : BLEND_MODE_MIX ;
2022-11-08 06:40:03 +00:00
_record_item_commands ( ci , p_to_render_target , p_canvas_transform_inverse , current_clip , blend_mode , p_lights , index , batch_broken ) ;
2022-08-12 11:03:28 +00:00
}
2022-11-04 20:04:20 +00:00
if ( index = = 0 ) {
2022-11-01 20:40:23 +00:00
// Nothing to render, just return.
state . current_batch_index = 0 ;
state . canvas_instance_batches . clear ( ) ;
return ;
}
2022-06-21 04:56:26 +00:00
// Copy over all data needed for rendering.
glBindBuffer ( GL_UNIFORM_BUFFER , state . canvas_instance_data_buffers [ state . current_buffer ] . ubo ) ;
# ifdef WEB_ENABLED
glBufferSubData ( GL_UNIFORM_BUFFER , r_last_index * sizeof ( InstanceData ) , sizeof ( InstanceData ) * index , state . instance_data_array ) ;
# else
// On Desktop and mobile we map the memory without synchronizing for maximum speed.
void * ubo = glMapBufferRange ( GL_UNIFORM_BUFFER , r_last_index * sizeof ( InstanceData ) , index * sizeof ( InstanceData ) , GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT ) ;
memcpy ( ubo , state . instance_data_array , index * sizeof ( InstanceData ) ) ;
glUnmapBuffer ( GL_UNIFORM_BUFFER ) ;
# endif
2022-08-12 11:03:28 +00:00
2022-06-21 04:56:26 +00:00
glDisable ( GL_SCISSOR_TEST ) ;
current_clip = nullptr ;
2022-08-12 11:03:28 +00:00
2022-06-21 04:56:26 +00:00
GLES3 : : CanvasShaderData : : BlendMode last_blend_mode = GLES3 : : CanvasShaderData : : BLEND_MODE_MIX ;
2022-08-12 11:03:28 +00:00
2022-06-21 04:56:26 +00:00
state . current_tex = RID ( ) ;
2022-08-12 11:03:28 +00:00
2022-06-21 04:56:26 +00:00
for ( uint32_t i = 0 ; i < = state . current_batch_index ; i + + ) {
//setup clip
if ( current_clip ! = state . canvas_instance_batches [ i ] . clip ) {
current_clip = state . canvas_instance_batches [ i ] . clip ;
if ( current_clip ) {
glEnable ( GL_SCISSOR_TEST ) ;
glScissor ( current_clip - > final_clip_rect . position . x , current_clip - > final_clip_rect . position . y , current_clip - > final_clip_rect . size . x , current_clip - > final_clip_rect . size . y ) ;
} else {
glDisable ( GL_SCISSOR_TEST ) ;
2022-08-12 11:03:28 +00:00
}
}
2022-06-21 04:56:26 +00:00
GLES3 : : CanvasMaterialData * material_data = state . canvas_instance_batches [ i ] . material_data ;
CanvasShaderGLES3 : : ShaderVariant variant = state . canvas_instance_batches [ i ] . shader_variant ;
2022-10-13 00:55:01 +00:00
uint64_t specialization = 0 ;
specialization | = uint64_t ( state . canvas_instance_batches [ i ] . lights_disabled ) ;
2022-10-19 00:59:31 +00:00
specialization | = uint64_t ( ! GLES3 : : Config : : get_singleton ( ) - > float_texture_supported ) < < 1 ;
2022-11-08 06:40:03 +00:00
bool success = _bind_material ( material_data , variant , specialization ) ;
if ( ! success ) {
continue ;
}
2022-08-12 11:03:28 +00:00
2022-06-21 04:56:26 +00:00
GLES3 : : CanvasShaderData : : BlendMode blend_mode = state . canvas_instance_batches [ i ] . blend_mode ;
if ( last_blend_mode ! = blend_mode ) {
if ( last_blend_mode = = GLES3 : : CanvasShaderData : : BLEND_MODE_DISABLED ) {
2022-05-18 15:04:41 +00:00
// re-enable it
glEnable ( GL_BLEND ) ;
} else if ( blend_mode = = GLES3 : : CanvasShaderData : : BLEND_MODE_DISABLED ) {
// disable it
glDisable ( GL_BLEND ) ;
}
switch ( blend_mode ) {
case GLES3 : : CanvasShaderData : : BLEND_MODE_DISABLED : {
// Nothing to do here.
2022-08-12 11:03:28 +00:00
} break ;
case GLES3 : : CanvasShaderData : : BLEND_MODE_LCD : {
glBlendEquation ( GL_FUNC_ADD ) ;
if ( state . transparent_render_target ) {
glBlendFuncSeparate ( GL_CONSTANT_COLOR , GL_ONE_MINUS_SRC_COLOR , GL_ONE , GL_ONE_MINUS_SRC_ALPHA ) ;
} else {
glBlendFuncSeparate ( GL_CONSTANT_COLOR , GL_ONE_MINUS_SRC_COLOR , GL_ZERO , GL_ONE ) ;
}
2022-06-21 04:56:26 +00:00
Color blend_color = state . canvas_instance_batches [ state . current_batch_index ] . blend_color ;
2022-08-12 11:03:28 +00:00
glBlendColor ( blend_color . r , blend_color . g , blend_color . b , blend_color . a ) ;
2022-05-18 15:04:41 +00:00
} break ;
case GLES3 : : CanvasShaderData : : BLEND_MODE_MIX : {
glBlendEquation ( GL_FUNC_ADD ) ;
if ( state . transparent_render_target ) {
glBlendFuncSeparate ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA , GL_ONE , GL_ONE_MINUS_SRC_ALPHA ) ;
} else {
glBlendFuncSeparate ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA , GL_ZERO , GL_ONE ) ;
}
} break ;
case GLES3 : : CanvasShaderData : : BLEND_MODE_ADD : {
glBlendEquation ( GL_FUNC_ADD ) ;
if ( state . transparent_render_target ) {
glBlendFuncSeparate ( GL_SRC_ALPHA , GL_ONE , GL_SRC_ALPHA , GL_ONE ) ;
} else {
glBlendFuncSeparate ( GL_SRC_ALPHA , GL_ONE , GL_ZERO , GL_ONE ) ;
}
} break ;
case GLES3 : : CanvasShaderData : : BLEND_MODE_SUB : {
glBlendEquation ( GL_FUNC_REVERSE_SUBTRACT ) ;
if ( state . transparent_render_target ) {
glBlendFuncSeparate ( GL_SRC_ALPHA , GL_ONE , GL_SRC_ALPHA , GL_ONE ) ;
} else {
glBlendFuncSeparate ( GL_SRC_ALPHA , GL_ONE , GL_ZERO , GL_ONE ) ;
}
} break ;
case GLES3 : : CanvasShaderData : : BLEND_MODE_MUL : {
glBlendEquation ( GL_FUNC_ADD ) ;
if ( state . transparent_render_target ) {
glBlendFuncSeparate ( GL_DST_COLOR , GL_ZERO , GL_DST_ALPHA , GL_ZERO ) ;
} else {
glBlendFuncSeparate ( GL_DST_COLOR , GL_ZERO , GL_ZERO , GL_ONE ) ;
}
} break ;
case GLES3 : : CanvasShaderData : : BLEND_MODE_PMALPHA : {
glBlendEquation ( GL_FUNC_ADD ) ;
if ( state . transparent_render_target ) {
glBlendFuncSeparate ( GL_ONE , GL_ONE_MINUS_SRC_ALPHA , GL_ONE , GL_ONE_MINUS_SRC_ALPHA ) ;
} else {
glBlendFuncSeparate ( GL_ONE , GL_ONE_MINUS_SRC_ALPHA , GL_ZERO , GL_ONE ) ;
}
} break ;
}
2022-06-21 04:56:26 +00:00
last_blend_mode = blend_mode ;
}
_render_batch ( p_lights , i ) ;
}
state . current_batch_index = 0 ;
state . canvas_instance_batches . clear ( ) ;
r_last_index + = index ;
}
2022-11-08 06:40:03 +00:00
void RasterizerCanvasGLES3 : : _record_item_commands ( const Item * p_item , RID p_render_target , const Transform2D & p_canvas_transform_inverse , Item * & current_clip , GLES3 : : CanvasShaderData : : BlendMode p_blend_mode , Light * p_lights , uint32_t & r_index , bool & r_batch_broken ) {
2022-06-21 04:56:26 +00:00
RenderingServer : : CanvasItemTextureFilter texture_filter = p_item - > texture_filter = = RS : : CANVAS_ITEM_TEXTURE_FILTER_DEFAULT ? state . default_filter : p_item - > texture_filter ;
if ( texture_filter ! = state . canvas_instance_batches [ state . current_batch_index ] . filter ) {
_new_batch ( r_batch_broken , r_index ) ;
state . canvas_instance_batches [ state . current_batch_index ] . filter = texture_filter ;
}
RenderingServer : : CanvasItemTextureRepeat texture_repeat = p_item - > texture_repeat = = RS : : CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT ? state . default_repeat : p_item - > texture_repeat ;
if ( texture_repeat ! = state . canvas_instance_batches [ state . current_batch_index ] . repeat ) {
_new_batch ( r_batch_broken , r_index ) ;
state . canvas_instance_batches [ state . current_batch_index ] . repeat = texture_repeat ;
}
Transform2D base_transform = p_canvas_transform_inverse * p_item - > final_transform ;
Transform2D draw_transform ; // Used by transform command
Color base_color = p_item - > final_modulate ;
uint32_t base_flags = 0 ;
Size2 texpixel_size ;
bool reclip = false ;
bool skipping = false ;
2022-10-13 00:55:01 +00:00
// TODO: consider making lights a per-batch property and then baking light operations in the shader for better performance.
uint32_t lights [ 4 ] = { 0 , 0 , 0 , 0 } ;
uint16_t light_count = 0 ;
{
Light * light = p_lights ;
while ( light ) {
if ( light - > render_index_cache > = 0 & & p_item - > light_mask & light - > item_mask & & p_item - > z_final > = light - > z_min & & p_item - > z_final < = light - > z_max & & p_item - > global_rect_cache . intersects_transformed ( light - > xform_cache , light - > rect_cache ) ) {
uint32_t light_index = light - > render_index_cache ;
lights [ light_count > > 2 ] | = light_index < < ( ( light_count & 3 ) * 8 ) ;
light_count + + ;
if ( light_count = = data . max_lights_per_item ) {
break ;
}
}
light = light - > next_ptr ;
}
base_flags | = light_count < < FLAGS_LIGHT_COUNT_SHIFT ;
}
bool lights_disabled = light_count = = 0 & & ! state . using_directional_lights ;
if ( lights_disabled ! = state . canvas_instance_batches [ state . current_batch_index ] . lights_disabled ) {
_new_batch ( r_batch_broken , r_index ) ;
state . canvas_instance_batches [ state . current_batch_index ] . lights_disabled = lights_disabled ;
}
2022-06-21 04:56:26 +00:00
const Item : : Command * c = p_item - > commands ;
while ( c ) {
if ( skipping & & c - > type ! = Item : : Command : : TYPE_ANIMATION_SLICE ) {
c = c - > next ;
continue ;
}
if ( c - > type ! = Item : : Command : : TYPE_MESH ) {
// For Meshes, this gets updated below.
_update_transform_2d_to_mat2x3 ( base_transform * draw_transform , state . instance_data_array [ r_index ] . world ) ;
}
// Zero out most fields.
for ( int i = 0 ; i < 4 ; i + + ) {
state . instance_data_array [ r_index ] . modulation [ i ] = 0.0 ;
state . instance_data_array [ r_index ] . ninepatch_margins [ i ] = 0.0 ;
state . instance_data_array [ r_index ] . src_rect [ i ] = 0.0 ;
state . instance_data_array [ r_index ] . dst_rect [ i ] = 0.0 ;
state . instance_data_array [ r_index ] . lights [ i ] = uint32_t ( 0 ) ;
}
state . instance_data_array [ r_index ] . color_texture_pixel_size [ 0 ] = 0.0 ;
state . instance_data_array [ r_index ] . color_texture_pixel_size [ 1 ] = 0.0 ;
state . instance_data_array [ r_index ] . pad [ 0 ] = 0.0 ;
state . instance_data_array [ r_index ] . pad [ 1 ] = 0.0 ;
2022-10-13 00:55:01 +00:00
state . instance_data_array [ r_index ] . lights [ 0 ] = lights [ 0 ] ;
state . instance_data_array [ r_index ] . lights [ 1 ] = lights [ 1 ] ;
state . instance_data_array [ r_index ] . lights [ 2 ] = lights [ 2 ] ;
state . instance_data_array [ r_index ] . lights [ 3 ] = lights [ 3 ] ;
2022-06-21 04:56:26 +00:00
state . instance_data_array [ r_index ] . flags = base_flags | ( state . instance_data_array [ r_index = = 0 ? 0 : r_index - 1 ] . flags & ( FLAGS_DEFAULT_NORMAL_MAP_USED | FLAGS_DEFAULT_SPECULAR_MAP_USED ) ) ; //reset on each command for sanity, keep canvastexture binding config
Color blend_color ;
if ( c - > type = = Item : : Command : : TYPE_RECT ) {
const Item : : CommandRect * rect = static_cast < const Item : : CommandRect * > ( c ) ;
if ( rect - > flags & CANVAS_RECT_LCD ) {
p_blend_mode = GLES3 : : CanvasShaderData : : BLEND_MODE_LCD ;
blend_color = rect - > modulate * base_color ;
}
}
if ( p_blend_mode ! = state . canvas_instance_batches [ state . current_batch_index ] . blend_mode | | blend_color ! = state . canvas_instance_batches [ state . current_batch_index ] . blend_color ) {
_new_batch ( r_batch_broken , r_index ) ;
state . canvas_instance_batches [ state . current_batch_index ] . blend_mode = p_blend_mode ;
state . canvas_instance_batches [ state . current_batch_index ] . blend_color = blend_color ;
2022-05-25 20:19:45 +00:00
}
2021-11-16 15:25:42 +00:00
switch ( c - > type ) {
case Item : : Command : : TYPE_RECT : {
const Item : : CommandRect * rect = static_cast < const Item : : CommandRect * > ( c ) ;
2020-11-18 18:11:30 +00:00
2022-06-21 04:56:26 +00:00
if ( rect - > flags & CANVAS_RECT_TILE & & state . canvas_instance_batches [ state . current_batch_index ] . repeat ! = RenderingServer : : CanvasItemTextureRepeat : : CANVAS_ITEM_TEXTURE_REPEAT_ENABLED ) {
_new_batch ( r_batch_broken , r_index ) ;
state . canvas_instance_batches [ state . current_batch_index ] . repeat = RenderingServer : : CanvasItemTextureRepeat : : CANVAS_ITEM_TEXTURE_REPEAT_ENABLED ;
2021-11-16 15:25:42 +00:00
}
2020-11-18 18:11:30 +00:00
2022-06-21 04:56:26 +00:00
if ( rect - > texture ! = state . canvas_instance_batches [ state . current_batch_index ] . tex | | state . canvas_instance_batches [ state . current_batch_index ] . command_type ! = Item : : Command : : TYPE_RECT ) {
_new_batch ( r_batch_broken , r_index ) ;
state . canvas_instance_batches [ state . current_batch_index ] . tex = rect - > texture ;
state . canvas_instance_batches [ state . current_batch_index ] . command_type = Item : : Command : : TYPE_RECT ;
state . canvas_instance_batches [ state . current_batch_index ] . command = c ;
state . canvas_instance_batches [ state . current_batch_index ] . shader_variant = CanvasShaderGLES3 : : MODE_QUAD ;
2021-11-16 15:25:42 +00:00
}
2022-06-21 04:56:26 +00:00
_prepare_canvas_texture ( rect - > texture , state . canvas_instance_batches [ state . current_batch_index ] . filter , state . canvas_instance_batches [ state . current_batch_index ] . repeat , r_index , texpixel_size ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
Rect2 src_rect ;
Rect2 dst_rect ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
if ( rect - > texture ! = RID ( ) ) {
2022-06-21 04:56:26 +00:00
src_rect = ( rect - > flags & CANVAS_RECT_REGION ) ? Rect2 ( rect - > source . position * texpixel_size , rect - > source . size * texpixel_size ) : Rect2 ( 0 , 0 , 1 , 1 ) ;
2021-11-16 15:25:42 +00:00
dst_rect = Rect2 ( rect - > rect . position , rect - > rect . size ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
if ( dst_rect . size . width < 0 ) {
dst_rect . position . x + = dst_rect . size . width ;
dst_rect . size . width * = - 1 ;
}
if ( dst_rect . size . height < 0 ) {
dst_rect . position . y + = dst_rect . size . height ;
dst_rect . size . height * = - 1 ;
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
if ( rect - > flags & CANVAS_RECT_FLIP_H ) {
src_rect . size . x * = - 1 ;
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
if ( rect - > flags & CANVAS_RECT_FLIP_V ) {
src_rect . size . y * = - 1 ;
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
if ( rect - > flags & CANVAS_RECT_TRANSPOSE ) {
dst_rect . size . x * = - 1 ; // Encoding in the dst_rect.z uniform
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
if ( rect - > flags & CANVAS_RECT_CLIP_UV ) {
state . instance_data_array [ r_index ] . flags | = FLAGS_CLIP_RECT_UV ;
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
} else {
dst_rect = Rect2 ( rect - > rect . position , rect - > rect . size ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
if ( dst_rect . size . width < 0 ) {
dst_rect . position . x + = dst_rect . size . width ;
dst_rect . size . width * = - 1 ;
}
if ( dst_rect . size . height < 0 ) {
dst_rect . position . y + = dst_rect . size . height ;
dst_rect . size . height * = - 1 ;
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
src_rect = Rect2 ( 0 , 0 , 1 , 1 ) ;
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
if ( rect - > flags & CANVAS_RECT_MSDF ) {
state . instance_data_array [ r_index ] . flags | = FLAGS_USE_MSDF ;
state . instance_data_array [ r_index ] . msdf [ 0 ] = rect - > px_range ; // Pixel range.
state . instance_data_array [ r_index ] . msdf [ 1 ] = rect - > outline ; // Outline size.
state . instance_data_array [ r_index ] . msdf [ 2 ] = 0.f ; // Reserved.
state . instance_data_array [ r_index ] . msdf [ 3 ] = 0.f ; // Reserved.
2022-08-12 11:03:28 +00:00
} else if ( rect - > flags & CANVAS_RECT_LCD ) {
state . instance_data_array [ r_index ] . flags | = FLAGS_USE_LCD ;
2021-11-16 15:25:42 +00:00
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
state . instance_data_array [ r_index ] . modulation [ 0 ] = rect - > modulate . r * base_color . r ;
state . instance_data_array [ r_index ] . modulation [ 1 ] = rect - > modulate . g * base_color . g ;
state . instance_data_array [ r_index ] . modulation [ 2 ] = rect - > modulate . b * base_color . b ;
state . instance_data_array [ r_index ] . modulation [ 3 ] = rect - > modulate . a * base_color . a ;
state . instance_data_array [ r_index ] . src_rect [ 0 ] = src_rect . position . x ;
state . instance_data_array [ r_index ] . src_rect [ 1 ] = src_rect . position . y ;
state . instance_data_array [ r_index ] . src_rect [ 2 ] = src_rect . size . width ;
state . instance_data_array [ r_index ] . src_rect [ 3 ] = src_rect . size . height ;
state . instance_data_array [ r_index ] . dst_rect [ 0 ] = dst_rect . position . x ;
state . instance_data_array [ r_index ] . dst_rect [ 1 ] = dst_rect . position . y ;
state . instance_data_array [ r_index ] . dst_rect [ 2 ] = dst_rect . size . width ;
state . instance_data_array [ r_index ] . dst_rect [ 3 ] = dst_rect . size . height ;
2022-05-25 23:51:40 +00:00
2022-06-21 04:56:26 +00:00
_add_to_batch ( r_index , r_batch_broken ) ;
2021-11-16 15:25:42 +00:00
} break ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
case Item : : Command : : TYPE_NINEPATCH : {
const Item : : CommandNinePatch * np = static_cast < const Item : : CommandNinePatch * > ( c ) ;
2020-11-18 18:11:30 +00:00
2022-06-21 04:56:26 +00:00
if ( np - > texture ! = state . canvas_instance_batches [ state . current_batch_index ] . tex | | state . canvas_instance_batches [ state . current_batch_index ] . command_type ! = Item : : Command : : TYPE_NINEPATCH ) {
_new_batch ( r_batch_broken , r_index ) ;
state . canvas_instance_batches [ state . current_batch_index ] . tex = np - > texture ;
state . canvas_instance_batches [ state . current_batch_index ] . command_type = Item : : Command : : TYPE_NINEPATCH ;
state . canvas_instance_batches [ state . current_batch_index ] . command = c ;
state . canvas_instance_batches [ state . current_batch_index ] . shader_variant = CanvasShaderGLES3 : : MODE_NINEPATCH ;
2021-11-16 15:25:42 +00:00
}
2020-11-18 18:11:30 +00:00
2022-06-21 04:56:26 +00:00
_prepare_canvas_texture ( np - > texture , state . canvas_instance_batches [ state . current_batch_index ] . filter , state . canvas_instance_batches [ state . current_batch_index ] . repeat , r_index , texpixel_size ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
Rect2 src_rect ;
Rect2 dst_rect ( np - > rect . position . x , np - > rect . position . y , np - > rect . size . x , np - > rect . size . y ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
if ( np - > texture = = RID ( ) ) {
2022-06-21 04:56:26 +00:00
texpixel_size = Size2 ( 1 , 1 ) ;
2021-11-16 15:25:42 +00:00
src_rect = Rect2 ( 0 , 0 , 1 , 1 ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
} else {
if ( np - > source ! = Rect2 ( ) ) {
2022-06-21 04:56:26 +00:00
src_rect = Rect2 ( np - > source . position . x * texpixel_size . width , np - > source . position . y * texpixel_size . height , np - > source . size . x * texpixel_size . width , np - > source . size . y * texpixel_size . height ) ;
2021-11-16 15:25:42 +00:00
state . instance_data_array [ r_index ] . color_texture_pixel_size [ 0 ] = 1.0 / np - > source . size . width ;
state . instance_data_array [ r_index ] . color_texture_pixel_size [ 1 ] = 1.0 / np - > source . size . height ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
} else {
src_rect = Rect2 ( 0 , 0 , 1 , 1 ) ;
}
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
state . instance_data_array [ r_index ] . modulation [ 0 ] = np - > color . r * base_color . r ;
state . instance_data_array [ r_index ] . modulation [ 1 ] = np - > color . g * base_color . g ;
state . instance_data_array [ r_index ] . modulation [ 2 ] = np - > color . b * base_color . b ;
state . instance_data_array [ r_index ] . modulation [ 3 ] = np - > color . a * base_color . a ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
state . instance_data_array [ r_index ] . src_rect [ 0 ] = src_rect . position . x ;
state . instance_data_array [ r_index ] . src_rect [ 1 ] = src_rect . position . y ;
state . instance_data_array [ r_index ] . src_rect [ 2 ] = src_rect . size . width ;
state . instance_data_array [ r_index ] . src_rect [ 3 ] = src_rect . size . height ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
state . instance_data_array [ r_index ] . dst_rect [ 0 ] = dst_rect . position . x ;
state . instance_data_array [ r_index ] . dst_rect [ 1 ] = dst_rect . position . y ;
state . instance_data_array [ r_index ] . dst_rect [ 2 ] = dst_rect . size . width ;
state . instance_data_array [ r_index ] . dst_rect [ 3 ] = dst_rect . size . height ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
state . instance_data_array [ r_index ] . flags | = int ( np - > axis_x ) < < FLAGS_NINEPATCH_H_MODE_SHIFT ;
state . instance_data_array [ r_index ] . flags | = int ( np - > axis_y ) < < FLAGS_NINEPATCH_V_MODE_SHIFT ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
if ( np - > draw_center ) {
state . instance_data_array [ r_index ] . flags | = FLAGS_NINEPACH_DRAW_CENTER ;
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
state . instance_data_array [ r_index ] . ninepatch_margins [ 0 ] = np - > margin [ SIDE_LEFT ] ;
state . instance_data_array [ r_index ] . ninepatch_margins [ 1 ] = np - > margin [ SIDE_TOP ] ;
state . instance_data_array [ r_index ] . ninepatch_margins [ 2 ] = np - > margin [ SIDE_RIGHT ] ;
state . instance_data_array [ r_index ] . ninepatch_margins [ 3 ] = np - > margin [ SIDE_BOTTOM ] ;
2020-11-18 18:11:30 +00:00
2022-06-21 04:56:26 +00:00
_add_to_batch ( r_index , r_batch_broken ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
// Restore if overridden.
2022-06-21 04:56:26 +00:00
state . instance_data_array [ r_index ] . color_texture_pixel_size [ 0 ] = texpixel_size . x ;
state . instance_data_array [ r_index ] . color_texture_pixel_size [ 1 ] = texpixel_size . y ;
2021-11-16 15:25:42 +00:00
} break ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
case Item : : Command : : TYPE_POLYGON : {
const Item : : CommandPolygon * polygon = static_cast < const Item : : CommandPolygon * > ( c ) ;
2020-11-18 18:11:30 +00:00
2022-06-21 04:56:26 +00:00
// Polygon's can't be batched, so always create a new batch
_new_batch ( r_batch_broken , r_index ) ;
2020-11-18 18:11:30 +00:00
2022-06-21 04:56:26 +00:00
state . canvas_instance_batches [ state . current_batch_index ] . tex = polygon - > texture ;
state . canvas_instance_batches [ state . current_batch_index ] . command_type = Item : : Command : : TYPE_POLYGON ;
state . canvas_instance_batches [ state . current_batch_index ] . command = c ;
state . canvas_instance_batches [ state . current_batch_index ] . shader_variant = CanvasShaderGLES3 : : MODE_ATTRIBUTES ;
2020-11-18 18:11:30 +00:00
2022-06-21 04:56:26 +00:00
_prepare_canvas_texture ( polygon - > texture , state . canvas_instance_batches [ state . current_batch_index ] . filter , state . canvas_instance_batches [ state . current_batch_index ] . repeat , r_index , texpixel_size ) ;
2021-11-16 15:25:42 +00:00
state . instance_data_array [ r_index ] . modulation [ 0 ] = base_color . r ;
state . instance_data_array [ r_index ] . modulation [ 1 ] = base_color . g ;
state . instance_data_array [ r_index ] . modulation [ 2 ] = base_color . b ;
state . instance_data_array [ r_index ] . modulation [ 3 ] = base_color . a ;
for ( int j = 0 ; j < 4 ; j + + ) {
state . instance_data_array [ r_index ] . src_rect [ j ] = 0 ;
state . instance_data_array [ r_index ] . dst_rect [ j ] = 0 ;
state . instance_data_array [ r_index ] . ninepatch_margins [ j ] = 0 ;
}
2020-11-18 18:11:30 +00:00
2022-06-21 04:56:26 +00:00
_add_to_batch ( r_index , r_batch_broken ) ;
2021-11-16 15:25:42 +00:00
} break ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
case Item : : Command : : TYPE_PRIMITIVE : {
const Item : : CommandPrimitive * primitive = static_cast < const Item : : CommandPrimitive * > ( c ) ;
2020-11-18 18:11:30 +00:00
2022-06-21 04:56:26 +00:00
if ( primitive - > point_count ! = state . canvas_instance_batches [ state . current_batch_index ] . primitive_points | | state . canvas_instance_batches [ state . current_batch_index ] . command_type ! = Item : : Command : : TYPE_PRIMITIVE ) {
_new_batch ( r_batch_broken , r_index ) ;
2022-10-13 23:27:58 +00:00
state . canvas_instance_batches [ state . current_batch_index ] . tex = primitive - > texture ;
2022-06-21 04:56:26 +00:00
state . canvas_instance_batches [ state . current_batch_index ] . primitive_points = primitive - > point_count ;
state . canvas_instance_batches [ state . current_batch_index ] . command_type = Item : : Command : : TYPE_PRIMITIVE ;
state . canvas_instance_batches [ state . current_batch_index ] . command = c ;
state . canvas_instance_batches [ state . current_batch_index ] . shader_variant = CanvasShaderGLES3 : : MODE_PRIMITIVE ;
2021-11-16 15:25:42 +00:00
}
2022-10-13 23:27:58 +00:00
_prepare_canvas_texture ( state . canvas_instance_batches [ state . current_batch_index ] . tex , state . canvas_instance_batches [ state . current_batch_index ] . filter , state . canvas_instance_batches [ state . current_batch_index ] . repeat , r_index , texpixel_size ) ;
2022-03-08 14:10:48 +00:00
for ( uint32_t j = 0 ; j < MIN ( 3u , primitive - > point_count ) ; j + + ) {
2021-11-16 15:25:42 +00:00
state . instance_data_array [ r_index ] . points [ j * 2 + 0 ] = primitive - > points [ j ] . x ;
state . instance_data_array [ r_index ] . points [ j * 2 + 1 ] = primitive - > points [ j ] . y ;
state . instance_data_array [ r_index ] . uvs [ j * 2 + 0 ] = primitive - > uvs [ j ] . x ;
state . instance_data_array [ r_index ] . uvs [ j * 2 + 1 ] = primitive - > uvs [ j ] . y ;
Color col = primitive - > colors [ j ] * base_color ;
state . instance_data_array [ r_index ] . colors [ j * 2 + 0 ] = ( uint32_t ( Math : : make_half_float ( col . g ) ) < < 16 ) | Math : : make_half_float ( col . r ) ;
state . instance_data_array [ r_index ] . colors [ j * 2 + 1 ] = ( uint32_t ( Math : : make_half_float ( col . a ) ) < < 16 ) | Math : : make_half_float ( col . b ) ;
}
2022-06-21 04:56:26 +00:00
_add_to_batch ( r_index , r_batch_broken ) ;
2021-11-16 15:25:42 +00:00
if ( primitive - > point_count = = 4 ) {
2022-10-14 22:57:00 +00:00
// Reset base data.
2021-11-16 15:25:42 +00:00
_update_transform_2d_to_mat2x3 ( base_transform * draw_transform , state . instance_data_array [ r_index ] . world ) ;
state . instance_data_array [ r_index ] . color_texture_pixel_size [ 0 ] = 0.0 ;
state . instance_data_array [ r_index ] . color_texture_pixel_size [ 1 ] = 0.0 ;
2022-06-21 04:56:26 +00:00
state . instance_data_array [ r_index ] . flags = base_flags | ( state . instance_data_array [ r_index - 1 ] . flags & ( FLAGS_DEFAULT_NORMAL_MAP_USED | FLAGS_DEFAULT_SPECULAR_MAP_USED ) ) ; //reset on each command for sanity, keep canvastexture binding config
2021-11-16 15:25:42 +00:00
for ( uint32_t j = 0 ; j < 3 ; j + + ) {
2022-10-14 22:57:00 +00:00
int offset = j = = 0 ? 0 : 1 ;
// Second triangle in the quad. Uses vertices 0, 2, 3.
state . instance_data_array [ r_index ] . points [ j * 2 + 0 ] = primitive - > points [ j + offset ] . x ;
state . instance_data_array [ r_index ] . points [ j * 2 + 1 ] = primitive - > points [ j + offset ] . y ;
state . instance_data_array [ r_index ] . uvs [ j * 2 + 0 ] = primitive - > uvs [ j + offset ] . x ;
state . instance_data_array [ r_index ] . uvs [ j * 2 + 1 ] = primitive - > uvs [ j + offset ] . y ;
Color col = primitive - > colors [ j + offset ] * base_color ;
2021-11-16 15:25:42 +00:00
state . instance_data_array [ r_index ] . colors [ j * 2 + 0 ] = ( uint32_t ( Math : : make_half_float ( col . g ) ) < < 16 ) | Math : : make_half_float ( col . r ) ;
state . instance_data_array [ r_index ] . colors [ j * 2 + 1 ] = ( uint32_t ( Math : : make_half_float ( col . a ) ) < < 16 ) | Math : : make_half_float ( col . b ) ;
}
2022-06-21 04:56:26 +00:00
_add_to_batch ( r_index , r_batch_broken ) ;
2021-11-16 15:25:42 +00:00
}
} break ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
case Item : : Command : : TYPE_MESH :
case Item : : Command : : TYPE_MULTIMESH :
case Item : : Command : : TYPE_PARTICLES : {
2022-06-21 04:56:26 +00:00
// Mesh's can't be batched, so always create a new batch
_new_batch ( r_batch_broken , r_index ) ;
2021-11-16 15:25:42 +00:00
2022-06-21 04:56:26 +00:00
Color modulate ( 1 , 1 , 1 , 1 ) ;
state . canvas_instance_batches [ state . current_batch_index ] . shader_variant = CanvasShaderGLES3 : : MODE_ATTRIBUTES ;
2021-11-16 15:25:42 +00:00
if ( c - > type = = Item : : Command : : TYPE_MESH ) {
const Item : : CommandMesh * m = static_cast < const Item : : CommandMesh * > ( c ) ;
2022-06-21 04:56:26 +00:00
state . canvas_instance_batches [ state . current_batch_index ] . tex = m - > texture ;
2021-11-16 15:25:42 +00:00
_update_transform_2d_to_mat2x3 ( base_transform * draw_transform * m - > transform , state . instance_data_array [ r_index ] . world ) ;
2022-06-21 04:56:26 +00:00
modulate = m - > modulate ;
2022-11-08 06:40:03 +00:00
2021-11-16 15:25:42 +00:00
} else if ( c - > type = = Item : : Command : : TYPE_MULTIMESH ) {
const Item : : CommandMultiMesh * mm = static_cast < const Item : : CommandMultiMesh * > ( c ) ;
2022-06-21 04:56:26 +00:00
state . canvas_instance_batches [ state . current_batch_index ] . tex = mm - > texture ;
2022-11-08 06:40:03 +00:00
state . canvas_instance_batches [ state . current_batch_index ] . shader_variant = CanvasShaderGLES3 : : MODE_INSTANCED ;
2022-06-21 04:56:26 +00:00
} else if ( c - > type = = Item : : Command : : TYPE_PARTICLES ) {
2022-11-08 06:40:03 +00:00
GLES3 : : ParticlesStorage * particles_storage = GLES3 : : ParticlesStorage : : get_singleton ( ) ;
GLES3 : : TextureStorage * texture_storage = GLES3 : : TextureStorage : : get_singleton ( ) ;
const Item : : CommandParticles * pt = static_cast < const Item : : CommandParticles * > ( c ) ;
RID particles = pt - > particles ;
state . canvas_instance_batches [ state . current_batch_index ] . tex = pt - > texture ;
state . canvas_instance_batches [ state . current_batch_index ] . shader_variant = CanvasShaderGLES3 : : MODE_INSTANCED ;
bool local_coords = particles_storage - > particles_is_using_local_coords ( particles ) ;
if ( particles_storage - > particles_has_collision ( particles ) & & texture_storage - > render_target_is_sdf_enabled ( p_render_target ) ) {
// Pass collision information.
Transform2D xform ;
if ( local_coords ) {
xform = p_item - > final_transform ;
} else {
xform = p_canvas_transform_inverse ;
}
GLuint sdf_texture = texture_storage - > render_target_get_sdf_texture ( p_render_target ) ;
Rect2 to_screen ;
{
Rect2 sdf_rect = texture_storage - > render_target_get_sdf_rect ( p_render_target ) ;
to_screen . size = Vector2 ( 1.0 / sdf_rect . size . width , 1.0 / sdf_rect . size . height ) ;
to_screen . position = - sdf_rect . position * to_screen . size ;
}
particles_storage - > particles_set_canvas_sdf_collision ( pt - > particles , true , xform , to_screen , sdf_texture ) ;
} else {
particles_storage - > particles_set_canvas_sdf_collision ( pt - > particles , false , Transform2D ( ) , Rect2 ( ) , 0 ) ;
}
2021-11-16 15:25:42 +00:00
}
2020-11-18 18:11:30 +00:00
2022-06-21 04:56:26 +00:00
state . canvas_instance_batches [ state . current_batch_index ] . command = c ;
state . canvas_instance_batches [ state . current_batch_index ] . command_type = c - > type ;
2020-11-18 18:11:30 +00:00
2022-06-21 04:56:26 +00:00
_prepare_canvas_texture ( state . canvas_instance_batches [ state . current_batch_index ] . tex , state . canvas_instance_batches [ state . current_batch_index ] . filter , state . canvas_instance_batches [ state . current_batch_index ] . repeat , r_index , texpixel_size ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
state . instance_data_array [ r_index ] . modulation [ 0 ] = base_color . r * modulate . r ;
state . instance_data_array [ r_index ] . modulation [ 1 ] = base_color . g * modulate . g ;
state . instance_data_array [ r_index ] . modulation [ 2 ] = base_color . b * modulate . b ;
state . instance_data_array [ r_index ] . modulation [ 3 ] = base_color . a * modulate . a ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
for ( int j = 0 ; j < 4 ; j + + ) {
state . instance_data_array [ r_index ] . src_rect [ j ] = 0 ;
state . instance_data_array [ r_index ] . dst_rect [ j ] = 0 ;
state . instance_data_array [ r_index ] . ninepatch_margins [ j ] = 0 ;
}
2022-06-21 04:56:26 +00:00
_add_to_batch ( r_index , r_batch_broken ) ;
2021-11-16 15:25:42 +00:00
} break ;
2022-06-21 04:56:26 +00:00
2021-11-16 15:25:42 +00:00
case Item : : Command : : TYPE_TRANSFORM : {
const Item : : CommandTransform * transform = static_cast < const Item : : CommandTransform * > ( c ) ;
draw_transform = transform - > xform ;
} break ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
case Item : : Command : : TYPE_CLIP_IGNORE : {
const Item : : CommandClipIgnore * ci = static_cast < const Item : : CommandClipIgnore * > ( c ) ;
if ( current_clip ) {
if ( ci - > ignore ! = reclip ) {
2022-06-21 04:56:26 +00:00
_new_batch ( r_batch_broken , r_index ) ;
2021-11-16 15:25:42 +00:00
if ( ci - > ignore ) {
2022-06-21 04:56:26 +00:00
state . canvas_instance_batches [ state . current_batch_index ] . clip = nullptr ;
2021-11-16 15:25:42 +00:00
reclip = true ;
} else {
2022-06-21 04:56:26 +00:00
state . canvas_instance_batches [ state . current_batch_index ] . clip = current_clip ;
2021-11-16 15:25:42 +00:00
reclip = false ;
}
2020-11-18 18:11:30 +00:00
}
}
2021-11-16 15:25:42 +00:00
} break ;
2022-06-21 04:56:26 +00:00
2021-11-16 15:25:42 +00:00
case Item : : Command : : TYPE_ANIMATION_SLICE : {
const Item : : CommandAnimationSlice * as = static_cast < const Item : : CommandAnimationSlice * > ( c ) ;
2022-06-21 04:56:26 +00:00
double current_time = RSG : : rasterizer - > get_total_time ( ) ;
2021-11-16 15:25:42 +00:00
double local_time = Math : : fposmod ( current_time - as - > offset , as - > animation_length ) ;
skipping = ! ( local_time > = as - > slice_begin & & local_time < as - > slice_end ) ;
RenderingServerDefault : : redraw_request ( ) ; // animation visible means redraw request
} break ;
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
c = c - > next ;
2022-06-21 04:56:26 +00:00
r_batch_broken = false ;
2021-11-16 15:25:42 +00:00
}
2022-05-18 15:04:41 +00:00
if ( current_clip & & reclip ) {
//will make it re-enable clipping if needed afterwards
current_clip = nullptr ;
}
2021-11-16 15:25:42 +00:00
}
2022-06-21 04:56:26 +00:00
void RasterizerCanvasGLES3 : : _render_batch ( Light * p_lights , uint32_t p_index ) {
ERR_FAIL_COND ( ! state . canvas_instance_batches [ state . current_batch_index ] . command ) ;
2021-11-16 15:25:42 +00:00
2022-06-21 04:56:26 +00:00
// Used by Polygon and Mesh.
static const GLenum prim [ 5 ] = { GL_POINTS , GL_LINES , GL_LINE_STRIP , GL_TRIANGLES , GL_TRIANGLE_STRIP } ;
2021-11-16 15:25:42 +00:00
2022-06-21 04:56:26 +00:00
_bind_canvas_texture ( state . canvas_instance_batches [ p_index ] . tex , state . canvas_instance_batches [ p_index ] . filter , state . canvas_instance_batches [ p_index ] . repeat ) ;
// Bind the region of the UBO used by this batch.
// If region exceeds the boundary of the UBO, just ignore.
uint32_t range_bytes = data . max_instances_per_batch * sizeof ( InstanceData ) ;
if ( state . canvas_instance_batches [ p_index ] . start > = ( data . max_instances_per_ubo - 1 ) * sizeof ( InstanceData ) ) {
return ;
} else if ( state . canvas_instance_batches [ p_index ] . start > = ( data . max_instances_per_ubo - data . max_instances_per_batch ) * sizeof ( InstanceData ) ) {
// If we have less than a full batch at the end, we can just draw it anyway.
// OpenGL will complain about the UBO being smaller than expected, but it should render fine.
range_bytes = ( data . max_instances_per_ubo - 1 ) * sizeof ( InstanceData ) - state . canvas_instance_batches [ p_index ] . start ;
}
uint32_t range_start = state . canvas_instance_batches [ p_index ] . start ;
glBindBufferRange ( GL_UNIFORM_BUFFER , INSTANCE_UNIFORM_LOCATION , state . canvas_instance_data_buffers [ state . current_buffer ] . ubo , range_start , range_bytes ) ;
switch ( state . canvas_instance_batches [ p_index ] . command_type ) {
case Item : : Command : : TYPE_RECT :
case Item : : Command : : TYPE_NINEPATCH : {
glBindVertexArray ( data . indexed_quad_array ) ;
glDrawElements ( GL_TRIANGLES , state . canvas_instance_batches [ p_index ] . instance_count * 6 , GL_UNSIGNED_INT , 0 ) ;
glBindBuffer ( GL_UNIFORM_BUFFER , 0 ) ;
glBindVertexArray ( 0 ) ;
} break ;
case Item : : Command : : TYPE_POLYGON : {
const Item : : CommandPolygon * polygon = static_cast < const Item : : CommandPolygon * > ( state . canvas_instance_batches [ p_index ] . command ) ;
PolygonBuffers * pb = polygon_buffers . polygons . getptr ( polygon - > polygon . polygon_id ) ;
ERR_FAIL_COND ( ! pb ) ;
glBindVertexArray ( pb - > vertex_array ) ;
if ( pb - > color_disabled & & pb - > color ! = Color ( 1.0 , 1.0 , 1.0 , 1.0 ) ) {
glVertexAttrib4f ( RS : : ARRAY_COLOR , pb - > color . r , pb - > color . g , pb - > color . b , pb - > color . a ) ;
}
if ( pb - > index_buffer ! = 0 ) {
glDrawElements ( prim [ polygon - > primitive ] , pb - > count , GL_UNSIGNED_INT , nullptr ) ;
} else {
glDrawArrays ( prim [ polygon - > primitive ] , 0 , pb - > count ) ;
}
glBindVertexArray ( 0 ) ;
glBindBuffer ( GL_UNIFORM_BUFFER , 0 ) ;
if ( pb - > color_disabled & & pb - > color ! = Color ( 1.0 , 1.0 , 1.0 , 1.0 ) ) {
// Reset so this doesn't pollute other draw calls.
glVertexAttrib4f ( RS : : ARRAY_COLOR , 1.0 , 1.0 , 1.0 , 1.0 ) ;
}
} break ;
case Item : : Command : : TYPE_PRIMITIVE : {
glBindVertexArray ( data . canvas_quad_array ) ;
const GLenum primitive [ 5 ] = { GL_POINTS , GL_POINTS , GL_LINES , GL_TRIANGLES , GL_TRIANGLES } ;
int instance_count = state . canvas_instance_batches [ p_index ] . instance_count ;
if ( instance_count > 1 ) {
glDrawArraysInstanced ( primitive [ state . canvas_instance_batches [ p_index ] . primitive_points ] , 0 , state . canvas_instance_batches [ p_index ] . primitive_points , instance_count ) ;
} else {
glDrawArrays ( primitive [ state . canvas_instance_batches [ p_index ] . primitive_points ] , 0 , state . canvas_instance_batches [ p_index ] . primitive_points ) ;
}
glBindBuffer ( GL_UNIFORM_BUFFER , 0 ) ;
} break ;
case Item : : Command : : TYPE_MESH :
case Item : : Command : : TYPE_MULTIMESH :
case Item : : Command : : TYPE_PARTICLES : {
GLES3 : : MeshStorage * mesh_storage = GLES3 : : MeshStorage : : get_singleton ( ) ;
2022-11-08 06:40:03 +00:00
GLES3 : : ParticlesStorage * particles_storage = GLES3 : : ParticlesStorage : : get_singleton ( ) ;
2022-06-21 04:56:26 +00:00
RID mesh ;
RID mesh_instance ;
uint32_t instance_count = 1 ;
2022-11-08 06:40:03 +00:00
GLuint instance_buffer = 0 ;
uint32_t instance_stride = 0 ;
uint32_t instance_color_offset = 0 ;
bool instance_uses_color = false ;
bool instance_uses_custom_data = false ;
2022-06-21 04:56:26 +00:00
if ( state . canvas_instance_batches [ p_index ] . command_type = = Item : : Command : : TYPE_MESH ) {
const Item : : CommandMesh * m = static_cast < const Item : : CommandMesh * > ( state . canvas_instance_batches [ p_index ] . command ) ;
mesh = m - > mesh ;
mesh_instance = m - > mesh_instance ;
2022-11-08 06:40:03 +00:00
2022-06-21 04:56:26 +00:00
} else if ( state . canvas_instance_batches [ p_index ] . command_type = = Item : : Command : : TYPE_MULTIMESH ) {
const Item : : CommandMultiMesh * mm = static_cast < const Item : : CommandMultiMesh * > ( state . canvas_instance_batches [ p_index ] . command ) ;
RID multimesh = mm - > multimesh ;
mesh = mesh_storage - > multimesh_get_mesh ( multimesh ) ;
if ( mesh_storage - > multimesh_get_transform_format ( multimesh ) ! = RS : : MULTIMESH_TRANSFORM_2D ) {
break ;
}
instance_count = mesh_storage - > multimesh_get_instances_to_draw ( multimesh ) ;
if ( instance_count = = 0 ) {
break ;
}
2022-11-08 06:40:03 +00:00
instance_buffer = mesh_storage - > multimesh_get_gl_buffer ( multimesh ) ;
instance_stride = mesh_storage - > multimesh_get_stride ( multimesh ) ;
instance_color_offset = mesh_storage - > multimesh_get_color_offset ( multimesh ) ;
instance_uses_color = mesh_storage - > multimesh_uses_colors ( multimesh ) ;
instance_uses_custom_data = mesh_storage - > multimesh_uses_custom_data ( multimesh ) ;
2022-06-21 04:56:26 +00:00
} else if ( state . canvas_instance_batches [ p_index ] . command_type = = Item : : Command : : TYPE_PARTICLES ) {
2022-11-08 06:40:03 +00:00
const Item : : CommandParticles * pt = static_cast < const Item : : CommandParticles * > ( state . canvas_instance_batches [ p_index ] . command ) ;
RID particles = pt - > particles ;
mesh = particles_storage - > particles_get_draw_pass_mesh ( particles , 0 ) ;
ERR_BREAK ( particles_storage - > particles_get_mode ( particles ) ! = RS : : PARTICLES_MODE_2D ) ;
particles_storage - > particles_request_process ( particles ) ;
if ( particles_storage - > particles_is_inactive ( particles ) ) {
break ;
}
RenderingServerDefault : : redraw_request ( ) ; // Active particles means redraw request.
int dpc = particles_storage - > particles_get_draw_passes ( particles ) ;
if ( dpc = = 0 ) {
break ; // Nothing to draw.
}
instance_count = particles_storage - > particles_get_amount ( particles ) ;
instance_buffer = particles_storage - > particles_get_gl_buffer ( particles ) ;
instance_stride = 12 ; // 8 bytes for instance transform and 4 bytes for packed color and custom.
instance_color_offset = 8 ; // 8 bytes for instance transform.
instance_uses_color = true ;
instance_uses_custom_data = true ;
}
2022-06-21 04:56:26 +00:00
ERR_FAIL_COND ( mesh . is_null ( ) ) ;
uint32_t surf_count = mesh_storage - > mesh_get_surface_count ( mesh ) ;
for ( uint32_t j = 0 ; j < surf_count ; j + + ) {
void * surface = mesh_storage - > mesh_get_surface ( mesh , j ) ;
RS : : PrimitiveType primitive = mesh_storage - > mesh_surface_get_primitive ( surface ) ;
ERR_CONTINUE ( primitive < 0 | | primitive > = RS : : PRIMITIVE_MAX ) ;
GLuint vertex_array_gl = 0 ;
GLuint index_array_gl = 0 ;
uint32_t input_mask = 0 ; // 2D meshes always use the same vertex format
if ( mesh_instance . is_valid ( ) ) {
mesh_storage - > mesh_instance_surface_get_vertex_arrays_and_format ( mesh_instance , j , input_mask , vertex_array_gl ) ;
} else {
mesh_storage - > mesh_surface_get_vertex_arrays_and_format ( surface , input_mask , vertex_array_gl ) ;
}
index_array_gl = mesh_storage - > mesh_surface_get_index_buffer ( surface , 0 ) ;
bool use_index_buffer = false ;
glBindVertexArray ( vertex_array_gl ) ;
if ( index_array_gl ! = 0 ) {
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , index_array_gl ) ;
use_index_buffer = true ;
}
if ( instance_count > 1 ) {
2022-11-24 20:58:22 +00:00
if ( instance_buffer = = 0 ) {
break ;
}
2022-06-21 04:56:26 +00:00
// Bind instance buffers.
2022-11-08 06:40:03 +00:00
glBindBuffer ( GL_ARRAY_BUFFER , instance_buffer ) ;
2022-06-21 04:56:26 +00:00
glEnableVertexAttribArray ( 1 ) ;
2022-11-08 06:40:03 +00:00
glVertexAttribPointer ( 1 , 4 , GL_FLOAT , GL_FALSE , instance_stride * sizeof ( float ) , CAST_INT_TO_UCHAR_PTR ( 0 ) ) ;
2022-06-21 04:56:26 +00:00
glVertexAttribDivisor ( 1 , 1 ) ;
glEnableVertexAttribArray ( 2 ) ;
2022-11-08 06:40:03 +00:00
glVertexAttribPointer ( 2 , 4 , GL_FLOAT , GL_FALSE , instance_stride * sizeof ( float ) , CAST_INT_TO_UCHAR_PTR ( 4 * 4 ) ) ;
2022-06-21 04:56:26 +00:00
glVertexAttribDivisor ( 2 , 1 ) ;
2022-11-08 06:40:03 +00:00
if ( instance_uses_color | | instance_uses_custom_data ) {
2022-06-21 04:56:26 +00:00
glEnableVertexAttribArray ( 5 ) ;
2022-11-08 06:40:03 +00:00
glVertexAttribIPointer ( 5 , 4 , GL_UNSIGNED_INT , instance_stride * sizeof ( float ) , CAST_INT_TO_UCHAR_PTR ( instance_color_offset * sizeof ( float ) ) ) ;
2022-06-21 04:56:26 +00:00
glVertexAttribDivisor ( 5 , 1 ) ;
}
}
GLenum primitive_gl = prim [ int ( primitive ) ] ;
if ( instance_count = = 1 ) {
if ( use_index_buffer ) {
glDrawElements ( primitive_gl , mesh_storage - > mesh_surface_get_vertices_drawn_count ( surface ) , mesh_storage - > mesh_surface_get_index_type ( surface ) , 0 ) ;
} else {
glDrawArrays ( primitive_gl , 0 , mesh_storage - > mesh_surface_get_vertices_drawn_count ( surface ) ) ;
}
} else if ( instance_count > 1 ) {
if ( use_index_buffer ) {
glDrawElementsInstanced ( primitive_gl , mesh_storage - > mesh_surface_get_vertices_drawn_count ( surface ) , mesh_storage - > mesh_surface_get_index_type ( surface ) , 0 , instance_count ) ;
} else {
glDrawArraysInstanced ( primitive_gl , 0 , mesh_storage - > mesh_surface_get_vertices_drawn_count ( surface ) , instance_count ) ;
}
}
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , 0 ) ;
if ( instance_count > 1 ) {
glDisableVertexAttribArray ( 5 ) ;
glDisableVertexAttribArray ( 6 ) ;
glDisableVertexAttribArray ( 7 ) ;
glDisableVertexAttribArray ( 8 ) ;
}
}
} break ;
case Item : : Command : : TYPE_TRANSFORM :
case Item : : Command : : TYPE_CLIP_IGNORE :
case Item : : Command : : TYPE_ANIMATION_SLICE : {
// Can ignore these as they only impact batch creation.
} break ;
2020-11-18 18:11:30 +00:00
}
}
2022-06-21 04:56:26 +00:00
void RasterizerCanvasGLES3 : : _add_to_batch ( uint32_t & r_index , bool & r_batch_broken ) {
if ( r_index > = data . max_instances_per_ubo - 1 ) {
2022-11-04 20:04:20 +00:00
ERR_PRINT_ONCE ( " Trying to draw too many items. Please increase maximum number of items in the project settings 'rendering/gl_compatibility/item_buffer_size' " ) ;
2022-05-25 20:19:45 +00:00
return ;
}
2022-06-21 04:56:26 +00:00
if ( state . canvas_instance_batches [ state . current_batch_index ] . instance_count > = data . max_instances_per_batch ) {
_new_batch ( r_batch_broken , r_index ) ;
}
state . canvas_instance_batches [ state . current_batch_index ] . instance_count + + ;
r_index + + ;
}
void RasterizerCanvasGLES3 : : _new_batch ( bool & r_batch_broken , uint32_t & r_index ) {
if ( state . canvas_instance_batches . size ( ) = = 0 ) {
state . canvas_instance_batches . push_back ( Batch ( ) ) ;
return ;
}
if ( r_batch_broken | | state . canvas_instance_batches [ state . current_batch_index ] . instance_count = = 0 ) {
return ;
}
r_batch_broken = true ;
// Copy the properties of the current batch, we will manually update the things that changed.
Batch new_batch = state . canvas_instance_batches [ state . current_batch_index ] ;
new_batch . instance_count = 0 ;
new_batch . start = state . canvas_instance_batches [ state . current_batch_index ] . start + state . canvas_instance_batches [ state . current_batch_index ] . instance_count * sizeof ( InstanceData ) ;
state . current_batch_index + + ;
state . canvas_instance_batches . push_back ( new_batch ) ;
_align_instance_data_buffer ( r_index ) ;
}
2022-11-08 06:40:03 +00:00
bool RasterizerCanvasGLES3 : : _bind_material ( GLES3 : : CanvasMaterialData * p_material_data , CanvasShaderGLES3 : : ShaderVariant p_variant , uint64_t p_specialization ) {
2022-06-21 04:56:26 +00:00
if ( p_material_data ) {
if ( p_material_data - > shader_data - > version . is_valid ( ) & & p_material_data - > shader_data - > valid ) {
// Bind uniform buffer and textures
p_material_data - > bind_uniforms ( ) ;
2022-11-08 06:40:03 +00:00
return GLES3 : : MaterialStorage : : get_singleton ( ) - > shaders . canvas_shader . version_bind_shader ( p_material_data - > shader_data - > version , p_variant , p_specialization ) ;
2022-05-25 20:19:45 +00:00
} else {
2022-11-08 06:40:03 +00:00
return GLES3 : : MaterialStorage : : get_singleton ( ) - > shaders . canvas_shader . version_bind_shader ( data . canvas_shader_default_version , p_variant , p_specialization ) ;
2022-05-25 20:19:45 +00:00
}
2022-06-21 04:56:26 +00:00
} else {
2022-11-08 06:40:03 +00:00
return GLES3 : : MaterialStorage : : get_singleton ( ) - > shaders . canvas_shader . version_bind_shader ( data . canvas_shader_default_version , p_variant , p_specialization ) ;
2022-05-25 20:19:45 +00:00
}
}
2021-11-16 15:25:42 +00:00
RID RasterizerCanvasGLES3 : : light_create ( ) {
2022-10-13 00:55:01 +00:00
CanvasLight canvas_light ;
return canvas_light_owner . make_rid ( canvas_light ) ;
2020-11-18 18:11:30 +00:00
}
2021-11-16 15:25:42 +00:00
void RasterizerCanvasGLES3 : : light_set_texture ( RID p_rid , RID p_texture ) {
2022-10-13 00:55:01 +00:00
GLES3 : : TextureStorage * texture_storage = GLES3 : : TextureStorage : : get_singleton ( ) ;
CanvasLight * cl = canvas_light_owner . get_or_null ( p_rid ) ;
ERR_FAIL_COND ( ! cl ) ;
if ( cl - > texture = = p_texture ) {
return ;
}
if ( cl - > texture . is_valid ( ) ) {
texture_storage - > texture_remove_from_texture_atlas ( cl - > texture ) ;
}
cl - > texture = p_texture ;
if ( cl - > texture . is_valid ( ) ) {
texture_storage - > texture_add_to_texture_atlas ( cl - > texture ) ;
}
2020-11-18 18:11:30 +00:00
}
2021-11-16 15:25:42 +00:00
void RasterizerCanvasGLES3 : : light_set_use_shadow ( RID p_rid , bool p_enable ) {
2022-10-19 00:59:31 +00:00
CanvasLight * cl = canvas_light_owner . get_or_null ( p_rid ) ;
ERR_FAIL_COND ( ! cl ) ;
cl - > shadow . enabled = p_enable ;
2020-11-18 18:11:30 +00:00
}
2021-11-16 15:25:42 +00:00
void RasterizerCanvasGLES3 : : light_update_shadow ( RID p_rid , int p_shadow_index , const Transform2D & p_light_xform , int p_light_mask , float p_near , float p_far , LightOccluderInstance * p_occluders ) {
2022-10-19 00:59:31 +00:00
GLES3 : : Config * config = GLES3 : : Config : : get_singleton ( ) ;
CanvasLight * cl = canvas_light_owner . get_or_null ( p_rid ) ;
ERR_FAIL_COND ( ! cl - > shadow . enabled ) ;
_update_shadow_atlas ( ) ;
cl - > shadow . z_far = p_far ;
cl - > shadow . y_offset = float ( p_shadow_index * 2 + 1 ) / float ( data . max_lights_per_render * 2 ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , state . shadow_fb ) ;
glViewport ( 0 , p_shadow_index * 2 , state . shadow_texture_size , 2 ) ;
glDepthMask ( GL_TRUE ) ;
glEnable ( GL_DEPTH_TEST ) ;
glDepthFunc ( GL_LESS ) ;
glDisable ( GL_BLEND ) ;
glEnable ( GL_SCISSOR_TEST ) ;
glScissor ( 0 , p_shadow_index * 2 , state . shadow_texture_size , 2 ) ;
glClearColor ( p_far , p_far , p_far , 1.0 ) ;
glClearDepth ( 1.0 ) ;
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
glCullFace ( GL_BACK ) ;
glDisable ( GL_CULL_FACE ) ;
RS : : CanvasOccluderPolygonCullMode cull_mode = RS : : CANVAS_OCCLUDER_POLYGON_CULL_DISABLED ;
CanvasOcclusionShaderGLES3 : : ShaderVariant variant = config - > float_texture_supported ? CanvasOcclusionShaderGLES3 : : MODE_SHADOW : CanvasOcclusionShaderGLES3 : : MODE_SHADOW_RGBA ;
2022-11-08 06:40:03 +00:00
bool success = shadow_render . shader . version_bind_shader ( shadow_render . shader_version , variant ) ;
if ( ! success ) {
return ;
}
2022-10-19 00:59:31 +00:00
for ( int i = 0 ; i < 4 ; i + + ) {
glViewport ( ( state . shadow_texture_size / 4 ) * i , p_shadow_index * 2 , ( state . shadow_texture_size / 4 ) , 2 ) ;
Projection projection ;
{
real_t fov = 90 ;
real_t nearp = p_near ;
real_t farp = p_far ;
real_t aspect = 1.0 ;
real_t ymax = nearp * Math : : tan ( Math : : deg_to_rad ( fov * 0.5 ) ) ;
real_t ymin = - ymax ;
real_t xmin = ymin * aspect ;
real_t xmax = ymax * aspect ;
projection . set_frustum ( xmin , xmax , ymin , ymax , nearp , farp ) ;
}
Vector3 cam_target = Basis : : from_euler ( Vector3 ( 0 , 0 , Math_TAU * ( ( i + 3 ) / 4.0 ) ) ) . xform ( Vector3 ( 0 , 1 , 0 ) ) ;
projection = projection * Projection ( Transform3D ( ) . looking_at ( cam_target , Vector3 ( 0 , 0 , - 1 ) ) . affine_inverse ( ) ) ;
shadow_render . shader . version_set_uniform ( CanvasOcclusionShaderGLES3 : : PROJECTION , projection , shadow_render . shader_version , variant ) ;
static const Vector2 directions [ 4 ] = { Vector2 ( 1 , 0 ) , Vector2 ( 0 , 1 ) , Vector2 ( - 1 , 0 ) , Vector2 ( 0 , - 1 ) } ;
shadow_render . shader . version_set_uniform ( CanvasOcclusionShaderGLES3 : : DIRECTION , directions [ i ] . x , directions [ i ] . y , shadow_render . shader_version , variant ) ;
shadow_render . shader . version_set_uniform ( CanvasOcclusionShaderGLES3 : : Z_FAR , p_far , shadow_render . shader_version , variant ) ;
LightOccluderInstance * instance = p_occluders ;
while ( instance ) {
OccluderPolygon * co = occluder_polygon_owner . get_or_null ( instance - > occluder ) ;
if ( ! co | | co - > vertex_array = = 0 | | ! ( p_light_mask & instance - > light_mask ) ) {
instance = instance - > next ;
continue ;
}
Transform2D modelview = p_light_xform * instance - > xform_cache ;
shadow_render . shader . version_set_uniform ( CanvasOcclusionShaderGLES3 : : MODELVIEW1 , modelview . columns [ 0 ] [ 0 ] , modelview . columns [ 1 ] [ 0 ] , 0 , modelview . columns [ 2 ] [ 0 ] , shadow_render . shader_version , variant ) ;
shadow_render . shader . version_set_uniform ( CanvasOcclusionShaderGLES3 : : MODELVIEW2 , modelview . columns [ 0 ] [ 1 ] , modelview . columns [ 1 ] [ 1 ] , 0 , modelview . columns [ 2 ] [ 1 ] , shadow_render . shader_version , variant ) ;
if ( co - > cull_mode ! = cull_mode ) {
if ( co - > cull_mode = = RS : : CANVAS_OCCLUDER_POLYGON_CULL_DISABLED ) {
glDisable ( GL_CULL_FACE ) ;
} else {
if ( cull_mode = = RS : : CANVAS_OCCLUDER_POLYGON_CULL_DISABLED ) {
// Last time was disabled, so enable and set proper face.
glEnable ( GL_CULL_FACE ) ;
}
glCullFace ( co - > cull_mode = = RS : : CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE ? GL_FRONT : GL_BACK ) ;
}
cull_mode = co - > cull_mode ;
}
glBindVertexArray ( co - > vertex_array ) ;
glDrawElements ( GL_TRIANGLES , 3 * co - > line_point_count , GL_UNSIGNED_SHORT , 0 ) ;
instance = instance - > next ;
}
}
glBindVertexArray ( 0 ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
glDepthMask ( GL_FALSE ) ;
glDisable ( GL_DEPTH_TEST ) ;
glDisable ( GL_SCISSOR_TEST ) ;
2021-11-16 15:25:42 +00:00
}
2021-09-26 23:07:10 +00:00
2021-11-16 15:25:42 +00:00
void RasterizerCanvasGLES3 : : light_update_directional_shadow ( RID p_rid , int p_shadow_index , const Transform2D & p_light_xform , int p_light_mask , float p_cull_distance , const Rect2 & p_clip_rect , LightOccluderInstance * p_occluders ) {
2022-10-19 00:59:31 +00:00
GLES3 : : Config * config = GLES3 : : Config : : get_singleton ( ) ;
CanvasLight * cl = canvas_light_owner . get_or_null ( p_rid ) ;
ERR_FAIL_COND ( ! cl - > shadow . enabled ) ;
_update_shadow_atlas ( ) ;
Vector2 light_dir = p_light_xform . columns [ 1 ] . normalized ( ) ;
Vector2 center = p_clip_rect . get_center ( ) ;
float to_edge_distance = ABS ( light_dir . dot ( p_clip_rect . get_support ( light_dir ) ) - light_dir . dot ( center ) ) ;
Vector2 from_pos = center - light_dir * ( to_edge_distance + p_cull_distance ) ;
float distance = to_edge_distance * 2.0 + p_cull_distance ;
float half_size = p_clip_rect . size . length ( ) * 0.5 ; //shadow length, must keep this no matter the angle
cl - > shadow . z_far = distance ;
cl - > shadow . y_offset = float ( p_shadow_index * 2 + 1 ) / float ( data . max_lights_per_render * 2 ) ;
Transform2D to_light_xform ;
to_light_xform [ 2 ] = from_pos ;
to_light_xform [ 1 ] = light_dir ;
to_light_xform [ 0 ] = - light_dir . orthogonal ( ) ;
to_light_xform . invert ( ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , state . shadow_fb ) ;
glViewport ( 0 , p_shadow_index * 2 , state . shadow_texture_size , 2 ) ;
glDepthMask ( GL_TRUE ) ;
glEnable ( GL_DEPTH_TEST ) ;
glDepthFunc ( GL_LESS ) ;
glDisable ( GL_BLEND ) ;
glEnable ( GL_SCISSOR_TEST ) ;
glScissor ( 0 , p_shadow_index * 2 , state . shadow_texture_size , 2 ) ;
glClearColor ( 1.0 , 1.0 , 1.0 , 1.0 ) ;
glClearDepth ( 1.0 ) ;
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
glCullFace ( GL_BACK ) ;
glDisable ( GL_CULL_FACE ) ;
RS : : CanvasOccluderPolygonCullMode cull_mode = RS : : CANVAS_OCCLUDER_POLYGON_CULL_DISABLED ;
CanvasOcclusionShaderGLES3 : : ShaderVariant variant = config - > float_texture_supported ? CanvasOcclusionShaderGLES3 : : MODE_SHADOW : CanvasOcclusionShaderGLES3 : : MODE_SHADOW_RGBA ;
2022-11-08 06:40:03 +00:00
bool success = shadow_render . shader . version_bind_shader ( shadow_render . shader_version , variant ) ;
if ( ! success ) {
return ;
}
2022-10-19 00:59:31 +00:00
Projection projection ;
projection . set_orthogonal ( - half_size , half_size , - 0.5 , 0.5 , 0.0 , distance ) ;
projection = projection * Projection ( Transform3D ( ) . looking_at ( Vector3 ( 0 , 1 , 0 ) , Vector3 ( 0 , 0 , - 1 ) ) . affine_inverse ( ) ) ;
shadow_render . shader . version_set_uniform ( CanvasOcclusionShaderGLES3 : : PROJECTION , projection , shadow_render . shader_version , variant ) ;
shadow_render . shader . version_set_uniform ( CanvasOcclusionShaderGLES3 : : DIRECTION , 0.0 , 1.0 , shadow_render . shader_version , variant ) ;
shadow_render . shader . version_set_uniform ( CanvasOcclusionShaderGLES3 : : Z_FAR , distance , shadow_render . shader_version , variant ) ;
LightOccluderInstance * instance = p_occluders ;
while ( instance ) {
OccluderPolygon * co = occluder_polygon_owner . get_or_null ( instance - > occluder ) ;
if ( ! co | | co - > vertex_array = = 0 | | ! ( p_light_mask & instance - > light_mask ) ) {
instance = instance - > next ;
continue ;
}
Transform2D modelview = to_light_xform * instance - > xform_cache ;
shadow_render . shader . version_set_uniform ( CanvasOcclusionShaderGLES3 : : MODELVIEW1 , modelview . columns [ 0 ] [ 0 ] , modelview . columns [ 1 ] [ 0 ] , 0 , modelview . columns [ 2 ] [ 0 ] , shadow_render . shader_version , variant ) ;
shadow_render . shader . version_set_uniform ( CanvasOcclusionShaderGLES3 : : MODELVIEW2 , modelview . columns [ 0 ] [ 1 ] , modelview . columns [ 1 ] [ 1 ] , 0 , modelview . columns [ 2 ] [ 1 ] , shadow_render . shader_version , variant ) ;
if ( co - > cull_mode ! = cull_mode ) {
if ( co - > cull_mode = = RS : : CANVAS_OCCLUDER_POLYGON_CULL_DISABLED ) {
glDisable ( GL_CULL_FACE ) ;
} else {
if ( cull_mode = = RS : : CANVAS_OCCLUDER_POLYGON_CULL_DISABLED ) {
// Last time was disabled, so enable and set proper face.
glEnable ( GL_CULL_FACE ) ;
}
glCullFace ( co - > cull_mode = = RS : : CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE ? GL_FRONT : GL_BACK ) ;
}
cull_mode = co - > cull_mode ;
}
glBindVertexArray ( co - > vertex_array ) ;
glDrawElements ( GL_TRIANGLES , 3 * co - > line_point_count , GL_UNSIGNED_SHORT , 0 ) ;
instance = instance - > next ;
}
Transform2D to_shadow ;
to_shadow . columns [ 0 ] . x = 1.0 / - ( half_size * 2.0 ) ;
to_shadow . columns [ 2 ] . x = 0.5 ;
cl - > shadow . directional_xform = to_shadow * to_light_xform ;
glBindVertexArray ( 0 ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
glDepthMask ( GL_FALSE ) ;
glDisable ( GL_DEPTH_TEST ) ;
glDisable ( GL_SCISSOR_TEST ) ;
glDisable ( GL_CULL_FACE ) ;
}
void RasterizerCanvasGLES3 : : _update_shadow_atlas ( ) {
GLES3 : : Config * config = GLES3 : : Config : : get_singleton ( ) ;
if ( state . shadow_fb = = 0 ) {
glActiveTexture ( GL_TEXTURE0 ) ;
glGenFramebuffers ( 1 , & state . shadow_fb ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , state . shadow_fb ) ;
glGenRenderbuffers ( 1 , & state . shadow_depth_buffer ) ;
glBindRenderbuffer ( GL_RENDERBUFFER , state . shadow_depth_buffer ) ;
glRenderbufferStorage ( GL_RENDERBUFFER , GL_DEPTH_COMPONENT24 , state . shadow_texture_size , data . max_lights_per_render * 2 ) ;
glFramebufferRenderbuffer ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_RENDERBUFFER , state . shadow_depth_buffer ) ;
glGenTextures ( 1 , & state . shadow_texture ) ;
glBindTexture ( GL_TEXTURE_2D , state . shadow_texture ) ;
if ( config - > float_texture_supported ) {
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_R32F , state . shadow_texture_size , data . max_lights_per_render * 2 , 0 , GL_RED , GL_FLOAT , nullptr ) ;
} else {
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA8 , state . shadow_texture_size , data . max_lights_per_render * 2 , 0 , GL_RGBA , 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_REPEAT ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_REPEAT ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_BASE_LEVEL , 0 ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAX_LEVEL , 1 ) ;
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , state . shadow_texture , 0 ) ;
GLenum status = glCheckFramebufferStatus ( GL_FRAMEBUFFER ) ;
if ( status ! = GL_FRAMEBUFFER_COMPLETE ) {
glDeleteFramebuffers ( 1 , & state . shadow_fb ) ;
glDeleteTextures ( 1 , & state . shadow_texture ) ;
glDeleteRenderbuffers ( 1 , & state . shadow_depth_buffer ) ;
state . shadow_fb = 0 ;
state . shadow_texture = 0 ;
state . shadow_depth_buffer = 0 ;
WARN_PRINT ( " Could not create CanvasItem shadow atlas, status: " + GLES3 : : TextureStorage : : get_singleton ( ) - > get_framebuffer_error ( status ) ) ;
}
glBindFramebuffer ( GL_FRAMEBUFFER , GLES3 : : TextureStorage : : system_fbo ) ;
}
2021-11-16 15:25:42 +00:00
}
2021-09-26 23:07:10 +00:00
2021-11-16 15:25:42 +00:00
void RasterizerCanvasGLES3 : : render_sdf ( RID p_render_target , LightOccluderInstance * p_occluders ) {
2022-10-19 00:59:31 +00:00
GLES3 : : TextureStorage * texture_storage = GLES3 : : TextureStorage : : get_singleton ( ) ;
GLuint fb = texture_storage - > render_target_get_sdf_framebuffer ( p_render_target ) ;
Rect2i rect = texture_storage - > render_target_get_sdf_rect ( p_render_target ) ;
Transform2D to_sdf ;
to_sdf . columns [ 0 ] * = rect . size . width ;
to_sdf . columns [ 1 ] * = rect . size . height ;
to_sdf . columns [ 2 ] = rect . position ;
Transform2D to_clip ;
to_clip . columns [ 0 ] * = 2.0 ;
to_clip . columns [ 1 ] * = 2.0 ;
to_clip . columns [ 2 ] = - Vector2 ( 1.0 , 1.0 ) ;
to_clip = to_clip * to_sdf . affine_inverse ( ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , fb ) ;
glViewport ( 0 , 0 , rect . size . width , rect . size . height ) ;
glDepthMask ( GL_FALSE ) ;
glDisable ( GL_DEPTH_TEST ) ;
glDisable ( GL_BLEND ) ;
glDisable ( GL_CULL_FACE ) ;
glDisable ( GL_SCISSOR_TEST ) ;
glClearColor ( 0.0 , 0.0 , 0.0 , 0.0 ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
CanvasOcclusionShaderGLES3 : : ShaderVariant variant = CanvasOcclusionShaderGLES3 : : MODE_SDF ;
2022-11-08 06:40:03 +00:00
bool success = shadow_render . shader . version_bind_shader ( shadow_render . shader_version , variant ) ;
if ( ! success ) {
return ;
}
2022-10-19 00:59:31 +00:00
shadow_render . shader . version_set_uniform ( CanvasOcclusionShaderGLES3 : : PROJECTION , Projection ( ) , shadow_render . shader_version , variant ) ;
shadow_render . shader . version_set_uniform ( CanvasOcclusionShaderGLES3 : : DIRECTION , 0.0 , 0.0 , shadow_render . shader_version , variant ) ;
shadow_render . shader . version_set_uniform ( CanvasOcclusionShaderGLES3 : : Z_FAR , 0.0 , shadow_render . shader_version , variant ) ;
LightOccluderInstance * instance = p_occluders ;
while ( instance ) {
OccluderPolygon * oc = occluder_polygon_owner . get_or_null ( instance - > occluder ) ;
if ( ! oc | | oc - > sdf_vertex_array = = 0 ) {
instance = instance - > next ;
continue ;
}
Transform2D modelview = to_clip * instance - > xform_cache ;
shadow_render . shader . version_set_uniform ( CanvasOcclusionShaderGLES3 : : MODELVIEW1 , modelview . columns [ 0 ] [ 0 ] , modelview . columns [ 1 ] [ 0 ] , 0 , modelview . columns [ 2 ] [ 0 ] , shadow_render . shader_version , variant ) ;
shadow_render . shader . version_set_uniform ( CanvasOcclusionShaderGLES3 : : MODELVIEW2 , modelview . columns [ 0 ] [ 1 ] , modelview . columns [ 1 ] [ 1 ] , 0 , modelview . columns [ 2 ] [ 1 ] , shadow_render . shader_version , variant ) ;
glBindVertexArray ( oc - > sdf_vertex_array ) ;
glDrawElements ( oc - > sdf_is_lines ? GL_LINES : GL_TRIANGLES , oc - > sdf_index_count , GL_UNSIGNED_INT , 0 ) ;
instance = instance - > next ;
}
texture_storage - > render_target_sdf_process ( p_render_target ) ; //done rendering, process it
glBindVertexArray ( 0 ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
2021-11-16 15:25:42 +00:00
}
2021-09-26 23:07:10 +00:00
2021-11-16 15:25:42 +00:00
RID RasterizerCanvasGLES3 : : occluder_polygon_create ( ) {
2022-10-19 00:59:31 +00:00
OccluderPolygon occluder ;
return occluder_polygon_owner . make_rid ( occluder ) ;
2021-11-16 15:25:42 +00:00
}
2021-09-26 23:07:10 +00:00
2021-11-16 15:25:42 +00:00
void RasterizerCanvasGLES3 : : occluder_polygon_set_shape ( RID p_occluder , const Vector < Vector2 > & p_points , bool p_closed ) {
2022-10-19 00:59:31 +00:00
OccluderPolygon * oc = occluder_polygon_owner . get_or_null ( p_occluder ) ;
ERR_FAIL_COND ( ! oc ) ;
Vector < Vector2 > lines ;
if ( p_points . size ( ) ) {
int lc = p_points . size ( ) * 2 ;
lines . resize ( lc - ( p_closed ? 0 : 2 ) ) ;
{
Vector2 * w = lines . ptrw ( ) ;
const Vector2 * r = p_points . ptr ( ) ;
int max = lc / 2 ;
if ( ! p_closed ) {
max - - ;
}
for ( int i = 0 ; i < max ; i + + ) {
Vector2 a = r [ i ] ;
Vector2 b = r [ ( i + 1 ) % ( lc / 2 ) ] ;
w [ i * 2 + 0 ] = a ;
w [ i * 2 + 1 ] = b ;
}
}
}
if ( oc - > line_point_count ! = lines . size ( ) & & oc - > vertex_array ! = 0 ) {
glDeleteVertexArrays ( 1 , & oc - > vertex_array ) ;
glDeleteBuffers ( 1 , & oc - > vertex_buffer ) ;
glDeleteBuffers ( 1 , & oc - > index_buffer ) ;
oc - > vertex_array = 0 ;
oc - > vertex_buffer = 0 ;
oc - > index_buffer = 0 ;
}
if ( lines . size ( ) ) {
Vector < uint8_t > geometry ;
Vector < uint8_t > indices ;
int lc = lines . size ( ) ;
geometry . resize ( lc * 6 * sizeof ( float ) ) ;
indices . resize ( lc * 3 * sizeof ( uint16_t ) ) ;
{
uint8_t * vw = geometry . ptrw ( ) ;
float * vwptr = reinterpret_cast < float * > ( vw ) ;
uint8_t * iw = indices . ptrw ( ) ;
uint16_t * iwptr = ( uint16_t * ) iw ;
const Vector2 * lr = lines . ptr ( ) ;
const int POLY_HEIGHT = 16384 ;
for ( int i = 0 ; i < lc / 2 ; i + + ) {
vwptr [ i * 12 + 0 ] = lr [ i * 2 + 0 ] . x ;
vwptr [ i * 12 + 1 ] = lr [ i * 2 + 0 ] . y ;
vwptr [ i * 12 + 2 ] = POLY_HEIGHT ;
vwptr [ i * 12 + 3 ] = lr [ i * 2 + 1 ] . x ;
vwptr [ i * 12 + 4 ] = lr [ i * 2 + 1 ] . y ;
vwptr [ i * 12 + 5 ] = POLY_HEIGHT ;
vwptr [ i * 12 + 6 ] = lr [ i * 2 + 1 ] . x ;
vwptr [ i * 12 + 7 ] = lr [ i * 2 + 1 ] . y ;
vwptr [ i * 12 + 8 ] = - POLY_HEIGHT ;
vwptr [ i * 12 + 9 ] = lr [ i * 2 + 0 ] . x ;
vwptr [ i * 12 + 10 ] = lr [ i * 2 + 0 ] . y ;
vwptr [ i * 12 + 11 ] = - POLY_HEIGHT ;
iwptr [ i * 6 + 0 ] = i * 4 + 0 ;
iwptr [ i * 6 + 1 ] = i * 4 + 1 ;
iwptr [ i * 6 + 2 ] = i * 4 + 2 ;
iwptr [ i * 6 + 3 ] = i * 4 + 2 ;
iwptr [ i * 6 + 4 ] = i * 4 + 3 ;
iwptr [ i * 6 + 5 ] = i * 4 + 0 ;
}
}
if ( oc - > vertex_array = = 0 ) {
oc - > line_point_count = lc ;
glGenVertexArrays ( 1 , & oc - > vertex_array ) ;
glBindVertexArray ( oc - > vertex_array ) ;
glGenBuffers ( 1 , & oc - > vertex_buffer ) ;
glBindBuffer ( GL_ARRAY_BUFFER , oc - > vertex_buffer ) ;
glBufferData ( GL_ARRAY_BUFFER , lc * 6 * sizeof ( float ) , geometry . ptr ( ) , GL_STATIC_DRAW ) ;
glEnableVertexAttribArray ( RS : : ARRAY_VERTEX ) ;
glVertexAttribPointer ( RS : : ARRAY_VERTEX , 3 , GL_FLOAT , GL_FALSE , 3 * sizeof ( float ) , nullptr ) ;
glGenBuffers ( 1 , & oc - > index_buffer ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , oc - > index_buffer ) ;
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , 3 * lc * sizeof ( uint16_t ) , indices . ptr ( ) , GL_STATIC_DRAW ) ;
glBindVertexArray ( 0 ) ;
} else {
glBindVertexArray ( oc - > vertex_array ) ;
glBindBuffer ( GL_ARRAY_BUFFER , oc - > vertex_buffer ) ;
glBufferData ( GL_ARRAY_BUFFER , lc * 6 * sizeof ( float ) , geometry . ptr ( ) , GL_STATIC_DRAW ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , oc - > index_buffer ) ;
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , 3 * lc * sizeof ( uint16_t ) , indices . ptr ( ) , GL_STATIC_DRAW ) ;
}
}
// sdf
Vector < int > sdf_indices ;
if ( p_points . size ( ) ) {
if ( p_closed ) {
sdf_indices = Geometry2D : : triangulate_polygon ( p_points ) ;
oc - > sdf_is_lines = false ;
} else {
int max = p_points . size ( ) ;
sdf_indices . resize ( max * 2 ) ;
int * iw = sdf_indices . ptrw ( ) ;
for ( int i = 0 ; i < max ; i + + ) {
iw [ i * 2 + 0 ] = i ;
iw [ i * 2 + 1 ] = ( i + 1 ) % max ;
}
oc - > sdf_is_lines = true ;
}
}
if ( oc - > sdf_index_count ! = sdf_indices . size ( ) & & oc - > sdf_point_count ! = p_points . size ( ) & & oc - > sdf_vertex_array ! = 0 ) {
glDeleteVertexArrays ( 1 , & oc - > sdf_vertex_array ) ;
glDeleteBuffers ( 1 , & oc - > sdf_vertex_buffer ) ;
glDeleteBuffers ( 1 , & oc - > sdf_index_buffer ) ;
oc - > sdf_vertex_array = 0 ;
oc - > sdf_vertex_buffer = 0 ;
oc - > sdf_index_buffer = 0 ;
oc - > sdf_index_count = sdf_indices . size ( ) ;
oc - > sdf_point_count = p_points . size ( ) ;
}
if ( sdf_indices . size ( ) ) {
if ( oc - > sdf_vertex_array = = 0 ) {
oc - > sdf_index_count = sdf_indices . size ( ) ;
oc - > sdf_point_count = p_points . size ( ) ;
glGenVertexArrays ( 1 , & oc - > sdf_vertex_array ) ;
glBindVertexArray ( oc - > sdf_vertex_array ) ;
glGenBuffers ( 1 , & oc - > sdf_vertex_buffer ) ;
glBindBuffer ( GL_ARRAY_BUFFER , oc - > sdf_vertex_buffer ) ;
glBufferData ( GL_ARRAY_BUFFER , p_points . size ( ) * 2 * sizeof ( float ) , p_points . to_byte_array ( ) . ptr ( ) , GL_STATIC_DRAW ) ;
glEnableVertexAttribArray ( RS : : ARRAY_VERTEX ) ;
glVertexAttribPointer ( RS : : ARRAY_VERTEX , 2 , GL_FLOAT , GL_FALSE , 2 * sizeof ( float ) , nullptr ) ;
glGenBuffers ( 1 , & oc - > sdf_index_buffer ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , oc - > sdf_index_buffer ) ;
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , sdf_indices . size ( ) * sizeof ( uint32_t ) , sdf_indices . to_byte_array ( ) . ptr ( ) , GL_STATIC_DRAW ) ;
glBindVertexArray ( 0 ) ;
} else {
glBindBuffer ( GL_ARRAY_BUFFER , oc - > sdf_vertex_buffer ) ;
glBufferData ( GL_ARRAY_BUFFER , p_points . size ( ) * 2 * sizeof ( float ) , p_points . to_byte_array ( ) . ptr ( ) , GL_STATIC_DRAW ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , oc - > sdf_index_buffer ) ;
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , sdf_indices . size ( ) * sizeof ( uint32_t ) , sdf_indices . to_byte_array ( ) . ptr ( ) , GL_STATIC_DRAW ) ;
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , 0 ) ;
}
}
2021-11-16 15:25:42 +00:00
}
2021-09-26 23:07:10 +00:00
2021-11-16 15:25:42 +00:00
void RasterizerCanvasGLES3 : : occluder_polygon_set_cull_mode ( RID p_occluder , RS : : CanvasOccluderPolygonCullMode p_mode ) {
2022-10-19 00:59:31 +00:00
OccluderPolygon * oc = occluder_polygon_owner . get_or_null ( p_occluder ) ;
ERR_FAIL_COND ( ! oc ) ;
oc - > cull_mode = p_mode ;
2021-09-26 23:07:10 +00:00
}
2021-11-16 15:25:42 +00:00
void RasterizerCanvasGLES3 : : set_shadow_texture_size ( int p_size ) {
2022-10-19 00:59:31 +00:00
GLES3 : : Config * config = GLES3 : : Config : : get_singleton ( ) ;
p_size = nearest_power_of_2_templated ( p_size ) ;
if ( p_size = = state . shadow_texture_size ) {
return ;
}
if ( p_size > config - > max_texture_size ) {
p_size = config - > max_texture_size ;
WARN_PRINT ( " Attempting to set CanvasItem shadow atlas size to " + itos ( p_size ) + " which is beyond limit of " + itos ( config - > max_texture_size ) + " supported by hardware. " ) ;
}
state . shadow_texture_size = p_size ;
2021-11-16 15:25:42 +00:00
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
bool RasterizerCanvasGLES3 : : free ( RID p_rid ) {
2022-10-13 00:55:01 +00:00
if ( canvas_light_owner . owns ( p_rid ) ) {
CanvasLight * cl = canvas_light_owner . get_or_null ( p_rid ) ;
ERR_FAIL_COND_V ( ! cl , false ) ;
canvas_light_owner . free ( p_rid ) ;
2022-10-19 00:59:31 +00:00
} else if ( occluder_polygon_owner . owns ( p_rid ) ) {
occluder_polygon_set_shape ( p_rid , Vector < Vector2 > ( ) , false ) ;
occluder_polygon_owner . free ( p_rid ) ;
2022-10-13 00:55:01 +00:00
} else {
return false ;
}
2021-11-16 15:25:42 +00:00
return true ;
2020-11-18 18:11:30 +00:00
}
2021-11-16 15:25:42 +00:00
void RasterizerCanvasGLES3 : : update ( ) {
}
2020-11-18 18:11:30 +00:00
2022-05-18 15:04:41 +00:00
void RasterizerCanvasGLES3 : : canvas_begin ( RID p_to_render_target , bool p_to_backbuffer ) {
2022-04-07 14:00:51 +00:00
GLES3 : : TextureStorage * texture_storage = GLES3 : : TextureStorage : : get_singleton ( ) ;
2022-05-18 15:04:41 +00:00
GLES3 : : Config * config = GLES3 : : Config : : get_singleton ( ) ;
2022-04-07 14:00:51 +00:00
2022-05-18 15:04:41 +00:00
GLES3 : : RenderTarget * render_target = texture_storage - > get_render_target ( p_to_render_target ) ;
2020-11-18 18:11:30 +00:00
2022-05-18 15:04:41 +00:00
if ( p_to_backbuffer ) {
glBindFramebuffer ( GL_FRAMEBUFFER , render_target - > backbuffer_fbo ) ;
glActiveTexture ( GL_TEXTURE0 + config - > max_texture_image_units - 4 ) ;
GLES3 : : Texture * tex = texture_storage - > get_texture ( texture_storage - > texture_gl_get_default ( GLES3 : : DEFAULT_GL_TEXTURE_WHITE ) ) ;
glBindTexture ( GL_TEXTURE_2D , tex - > tex_id ) ;
} else {
glBindFramebuffer ( GL_FRAMEBUFFER , render_target - > fbo ) ;
glActiveTexture ( GL_TEXTURE0 + config - > max_texture_image_units - 4 ) ;
glBindTexture ( GL_TEXTURE_2D , render_target - > backbuffer ) ;
}
2022-06-21 04:56:26 +00:00
if ( render_target - > is_transparent | | p_to_backbuffer ) {
2022-05-18 15:04:41 +00:00
state . transparent_render_target = true ;
glBlendFuncSeparate ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA , GL_ONE , GL_ONE_MINUS_SRC_ALPHA ) ;
} else {
state . transparent_render_target = false ;
2022-06-21 04:56:26 +00:00
glBlendFuncSeparate ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA , GL_ZERO , GL_ONE ) ;
2021-11-16 15:25:42 +00:00
}
2022-05-18 15:04:41 +00:00
if ( render_target & & render_target - > clear_requested ) {
const Color & col = render_target - > clear_color ;
2021-11-16 15:25:42 +00:00
glClearColor ( col . r , col . g , col . b , col . a ) ;
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ) ;
2022-05-18 15:04:41 +00:00
render_target - > clear_requested = false ;
2021-11-16 15:25:42 +00:00
}
2020-11-18 18:11:30 +00:00
glActiveTexture ( GL_TEXTURE0 ) ;
2022-02-20 00:08:53 +00:00
GLES3 : : Texture * tex = texture_storage - > get_texture ( texture_storage - > texture_gl_get_default ( GLES3 : : DEFAULT_GL_TEXTURE_WHITE ) ) ;
glBindTexture ( GL_TEXTURE_2D , tex - > tex_id ) ;
2021-11-16 15:25:42 +00:00
}
2020-11-18 18:11:30 +00:00
2022-06-21 04:56:26 +00:00
void RasterizerCanvasGLES3 : : _bind_canvas_texture ( RID p_texture , RS : : CanvasItemTextureFilter p_base_filter , RS : : CanvasItemTextureRepeat p_base_repeat ) {
2022-03-21 11:25:25 +00:00
GLES3 : : TextureStorage * texture_storage = GLES3 : : TextureStorage : : get_singleton ( ) ;
2022-05-18 15:04:41 +00:00
GLES3 : : Config * config = GLES3 : : Config : : get_singleton ( ) ;
2022-03-21 11:25:25 +00:00
2021-11-16 15:25:42 +00:00
if ( p_texture = = RID ( ) ) {
2022-06-21 04:56:26 +00:00
p_texture = default_canvas_texture ;
2020-11-18 18:11:30 +00:00
}
2022-06-21 04:56:26 +00:00
if ( state . current_tex = = p_texture & & state . current_filter_mode = = p_base_filter & & state . current_repeat_mode = = p_base_repeat ) {
return ;
2020-11-18 18:11:30 +00:00
}
2022-06-21 04:56:26 +00:00
2022-05-18 15:04:41 +00:00
state . current_tex = p_texture ;
2022-06-21 04:56:26 +00:00
state . current_filter_mode = p_base_filter ;
state . current_repeat_mode = p_base_repeat ;
2020-11-18 18:11:30 +00:00
2022-03-12 11:19:59 +00:00
GLES3 : : CanvasTexture * ct = nullptr ;
2020-11-18 18:11:30 +00:00
2022-03-12 11:19:59 +00:00
GLES3 : : Texture * t = texture_storage - > get_texture ( p_texture ) ;
2021-11-16 15:25:42 +00:00
if ( t ) {
2022-06-21 04:56:26 +00:00
ERR_FAIL_COND ( ! t - > canvas_texture ) ;
2021-11-16 15:25:42 +00:00
ct = t - > canvas_texture ;
} else {
2022-05-18 15:04:41 +00:00
ct = texture_storage - > get_canvas_texture ( p_texture ) ;
2020-11-18 18:11:30 +00:00
}
2021-11-16 15:25:42 +00:00
if ( ! ct ) {
// Invalid Texture RID.
2022-06-21 04:56:26 +00:00
_bind_canvas_texture ( default_canvas_texture , p_base_filter , p_base_repeat ) ;
2021-11-16 15:25:42 +00:00
return ;
2020-11-18 18:11:30 +00:00
}
2021-11-16 15:25:42 +00:00
RS : : CanvasItemTextureFilter filter = ct - > texture_filter ! = RS : : CANVAS_ITEM_TEXTURE_FILTER_DEFAULT ? ct - > texture_filter : p_base_filter ;
ERR_FAIL_COND ( filter = = RS : : CANVAS_ITEM_TEXTURE_FILTER_DEFAULT ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
RS : : CanvasItemTextureRepeat repeat = ct - > texture_repeat ! = RS : : CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT ? ct - > texture_repeat : p_base_repeat ;
ERR_FAIL_COND ( repeat = = RS : : CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT ) ;
2022-03-12 11:19:59 +00:00
GLES3 : : Texture * texture = texture_storage - > get_texture ( ct - > diffuse ) ;
2021-11-16 15:25:42 +00:00
if ( ! texture ) {
2022-06-21 04:56:26 +00:00
GLES3 : : Texture * tex = texture_storage - > get_texture ( texture_storage - > texture_gl_get_default ( GLES3 : : DEFAULT_GL_TEXTURE_WHITE ) ) ;
2021-11-16 15:25:42 +00:00
glActiveTexture ( GL_TEXTURE0 ) ;
2022-02-20 00:08:53 +00:00
glBindTexture ( GL_TEXTURE_2D , tex - > tex_id ) ;
2021-11-16 15:25:42 +00:00
} else {
glActiveTexture ( GL_TEXTURE0 ) ;
glBindTexture ( GL_TEXTURE_2D , texture - > tex_id ) ;
2022-02-20 00:08:53 +00:00
texture - > gl_set_filter ( filter ) ;
texture - > gl_set_repeat ( repeat ) ;
2020-11-18 18:11:30 +00:00
}
2022-03-12 11:19:59 +00:00
GLES3 : : Texture * normal_map = texture_storage - > get_texture ( ct - > normal_map ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
if ( ! normal_map ) {
2022-06-21 04:56:26 +00:00
glActiveTexture ( GL_TEXTURE0 + config - > max_texture_image_units - 6 ) ;
2022-02-20 00:08:53 +00:00
GLES3 : : Texture * tex = texture_storage - > get_texture ( texture_storage - > texture_gl_get_default ( GLES3 : : DEFAULT_GL_TEXTURE_NORMAL ) ) ;
glBindTexture ( GL_TEXTURE_2D , tex - > tex_id ) ;
2021-11-16 15:25:42 +00:00
} else {
2022-05-18 15:04:41 +00:00
glActiveTexture ( GL_TEXTURE0 + config - > max_texture_image_units - 6 ) ;
2021-11-16 15:25:42 +00:00
glBindTexture ( GL_TEXTURE_2D , normal_map - > tex_id ) ;
2022-06-21 04:56:26 +00:00
normal_map - > gl_set_filter ( filter ) ;
normal_map - > gl_set_repeat ( repeat ) ;
2020-11-18 18:11:30 +00:00
}
2022-03-12 11:19:59 +00:00
GLES3 : : Texture * specular_map = texture_storage - > get_texture ( ct - > specular ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
if ( ! specular_map ) {
2022-05-18 15:04:41 +00:00
glActiveTexture ( GL_TEXTURE0 + config - > max_texture_image_units - 7 ) ;
2022-02-20 00:08:53 +00:00
GLES3 : : Texture * tex = texture_storage - > get_texture ( texture_storage - > texture_gl_get_default ( GLES3 : : DEFAULT_GL_TEXTURE_WHITE ) ) ;
glBindTexture ( GL_TEXTURE_2D , tex - > tex_id ) ;
2021-11-16 15:25:42 +00:00
} else {
2022-05-18 15:04:41 +00:00
glActiveTexture ( GL_TEXTURE0 + config - > max_texture_image_units - 7 ) ;
2021-11-16 15:25:42 +00:00
glBindTexture ( GL_TEXTURE_2D , specular_map - > tex_id ) ;
2022-06-21 04:56:26 +00:00
specular_map - > gl_set_filter ( filter ) ;
specular_map - > gl_set_repeat ( repeat ) ;
2021-11-16 15:25:42 +00:00
}
2022-06-21 04:56:26 +00:00
}
2020-11-18 18:11:30 +00:00
2022-06-21 04:56:26 +00:00
void RasterizerCanvasGLES3 : : _prepare_canvas_texture ( RID p_texture , RS : : CanvasItemTextureFilter p_base_filter , RS : : CanvasItemTextureRepeat p_base_repeat , uint32_t & r_index , Size2 & r_texpixel_size ) {
GLES3 : : TextureStorage * texture_storage = GLES3 : : TextureStorage : : get_singleton ( ) ;
if ( p_texture = = RID ( ) ) {
p_texture = default_canvas_texture ;
}
GLES3 : : CanvasTexture * ct = nullptr ;
GLES3 : : Texture * t = texture_storage - > get_texture ( p_texture ) ;
if ( t ) {
//regular texture
if ( ! t - > canvas_texture ) {
t - > canvas_texture = memnew ( GLES3 : : CanvasTexture ) ;
t - > canvas_texture - > diffuse = p_texture ;
}
ct = t - > canvas_texture ;
} else {
ct = texture_storage - > get_canvas_texture ( p_texture ) ;
}
if ( ! ct ) {
// Invalid Texture RID.
_prepare_canvas_texture ( default_canvas_texture , p_base_filter , p_base_repeat , r_index , r_texpixel_size ) ;
return ;
}
GLES3 : : Texture * texture = texture_storage - > get_texture ( ct - > diffuse ) ;
Size2i size_cache ;
if ( ! texture ) {
ct - > diffuse = texture_storage - > texture_gl_get_default ( GLES3 : : DEFAULT_GL_TEXTURE_WHITE ) ;
GLES3 : : Texture * tex = texture_storage - > get_texture ( ct - > diffuse ) ;
size_cache = Size2i ( tex - > width , tex - > height ) ;
} else {
size_cache = Size2i ( texture - > width , texture - > height ) ;
}
GLES3 : : Texture * normal_map = texture_storage - > get_texture ( ct - > normal_map ) ;
if ( ct - > specular_color . a < 0.999 ) {
2021-11-16 15:25:42 +00:00
state . instance_data_array [ r_index ] . flags | = FLAGS_DEFAULT_SPECULAR_MAP_USED ;
} else {
state . instance_data_array [ r_index ] . flags & = ~ FLAGS_DEFAULT_SPECULAR_MAP_USED ;
2020-11-18 18:11:30 +00:00
}
2022-10-13 00:55:01 +00:00
if ( normal_map ) {
2021-11-16 15:25:42 +00:00
state . instance_data_array [ r_index ] . flags | = FLAGS_DEFAULT_NORMAL_MAP_USED ;
} else {
state . instance_data_array [ r_index ] . flags & = ~ FLAGS_DEFAULT_NORMAL_MAP_USED ;
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
state . instance_data_array [ r_index ] . specular_shininess = uint32_t ( CLAMP ( ct - > specular_color . a * 255.0 , 0 , 255 ) ) < < 24 ;
state . instance_data_array [ r_index ] . specular_shininess | = uint32_t ( CLAMP ( ct - > specular_color . b * 255.0 , 0 , 255 ) ) < < 16 ;
state . instance_data_array [ r_index ] . specular_shininess | = uint32_t ( CLAMP ( ct - > specular_color . g * 255.0 , 0 , 255 ) ) < < 8 ;
state . instance_data_array [ r_index ] . specular_shininess | = uint32_t ( CLAMP ( ct - > specular_color . r * 255.0 , 0 , 255 ) ) ;
2020-11-18 18:11:30 +00:00
2022-06-21 04:56:26 +00:00
r_texpixel_size . x = 1.0 / float ( size_cache . x ) ;
r_texpixel_size . y = 1.0 / float ( size_cache . y ) ;
2020-11-18 18:11:30 +00:00
2022-06-21 04:56:26 +00:00
state . instance_data_array [ r_index ] . color_texture_pixel_size [ 0 ] = r_texpixel_size . x ;
state . instance_data_array [ r_index ] . color_texture_pixel_size [ 1 ] = r_texpixel_size . y ;
2021-11-16 15:25:42 +00:00
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
void RasterizerCanvasGLES3 : : reset_canvas ( ) {
glDisable ( GL_CULL_FACE ) ;
glDisable ( GL_DEPTH_TEST ) ;
glDisable ( GL_SCISSOR_TEST ) ;
glEnable ( GL_BLEND ) ;
2022-05-18 15:04:41 +00:00
glBlendFuncSeparate ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA , GL_ZERO , GL_ONE ) ;
2021-11-16 15:25:42 +00:00
2022-10-19 00:59:31 +00:00
glActiveTexture ( GL_TEXTURE0 + GLES3 : : Config : : get_singleton ( ) - > max_texture_image_units - 2 ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
glActiveTexture ( GL_TEXTURE0 + GLES3 : : Config : : get_singleton ( ) - > max_texture_image_units - 3 ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
2021-11-16 15:25:42 +00:00
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , 0 ) ;
}
void RasterizerCanvasGLES3 : : draw_lens_distortion_rect ( const Rect2 & p_rect , float p_k1 , float p_k2 , const Vector2 & p_eye_center , float p_oversample ) {
}
RendererCanvasRender : : PolygonID RasterizerCanvasGLES3 : : request_polygon ( const Vector < int > & p_indices , const Vector < Point2 > & p_points , const Vector < Color > & p_colors , const Vector < Point2 > & p_uvs , const Vector < int > & p_bones , const Vector < float > & p_weights ) {
// We interleave the vertex data into one big VBO to improve cache coherence
uint32_t vertex_count = p_points . size ( ) ;
uint32_t stride = 2 ;
if ( ( uint32_t ) p_colors . size ( ) = = vertex_count ) {
stride + = 4 ;
}
if ( ( uint32_t ) p_uvs . size ( ) = = vertex_count ) {
stride + = 2 ;
}
if ( ( uint32_t ) p_bones . size ( ) = = vertex_count * 4 & & ( uint32_t ) p_weights . size ( ) = = vertex_count * 4 ) {
stride + = 4 ;
}
PolygonBuffers pb ;
glGenBuffers ( 1 , & pb . vertex_buffer ) ;
glGenVertexArrays ( 1 , & pb . vertex_array ) ;
glBindVertexArray ( pb . vertex_array ) ;
pb . count = vertex_count ;
pb . index_buffer = 0 ;
uint32_t buffer_size = stride * p_points . size ( ) ;
Vector < uint8_t > polygon_buffer ;
polygon_buffer . resize ( buffer_size * sizeof ( float ) ) ;
{
glBindBuffer ( GL_ARRAY_BUFFER , pb . vertex_buffer ) ;
2022-04-07 10:23:40 +00:00
uint8_t * r = polygon_buffer . ptrw ( ) ;
float * fptr = reinterpret_cast < float * > ( r ) ;
2021-11-16 15:25:42 +00:00
uint32_t * uptr = ( uint32_t * ) r ;
uint32_t base_offset = 0 ;
{
// Always uses vertex positions
glEnableVertexAttribArray ( RS : : ARRAY_VERTEX ) ;
2022-01-27 16:34:33 +00:00
glVertexAttribPointer ( RS : : ARRAY_VERTEX , 2 , GL_FLOAT , GL_FALSE , stride * sizeof ( float ) , nullptr ) ;
2021-11-16 15:25:42 +00:00
const Vector2 * points_ptr = p_points . ptr ( ) ;
for ( uint32_t i = 0 ; i < vertex_count ; i + + ) {
fptr [ base_offset + i * stride + 0 ] = points_ptr [ i ] . x ;
fptr [ base_offset + i * stride + 1 ] = points_ptr [ i ] . y ;
2020-11-18 18:11:30 +00:00
}
2021-11-16 15:25:42 +00:00
base_offset + = 2 ;
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
// Next add colors
2022-06-15 03:55:07 +00:00
if ( ( uint32_t ) p_colors . size ( ) = = vertex_count ) {
2021-11-16 15:25:42 +00:00
glEnableVertexAttribArray ( RS : : ARRAY_COLOR ) ;
glVertexAttribPointer ( RS : : ARRAY_COLOR , 4 , GL_FLOAT , GL_FALSE , stride * sizeof ( float ) , CAST_INT_TO_UCHAR_PTR ( base_offset * sizeof ( float ) ) ) ;
const Color * color_ptr = p_colors . ptr ( ) ;
for ( uint32_t i = 0 ; i < vertex_count ; i + + ) {
fptr [ base_offset + i * stride + 0 ] = color_ptr [ i ] . r ;
fptr [ base_offset + i * stride + 1 ] = color_ptr [ i ] . g ;
fptr [ base_offset + i * stride + 2 ] = color_ptr [ i ] . b ;
fptr [ base_offset + i * stride + 3 ] = color_ptr [ i ] . a ;
2020-11-18 18:11:30 +00:00
}
2021-11-16 15:25:42 +00:00
base_offset + = 4 ;
} else {
glDisableVertexAttribArray ( RS : : ARRAY_COLOR ) ;
2022-06-15 03:55:07 +00:00
pb . color_disabled = true ;
pb . color = p_colors . size ( ) = = 1 ? p_colors [ 0 ] : Color ( 1.0 , 1.0 , 1.0 , 1.0 ) ;
2021-11-16 15:25:42 +00:00
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
if ( ( uint32_t ) p_uvs . size ( ) = = vertex_count ) {
glEnableVertexAttribArray ( RS : : ARRAY_TEX_UV ) ;
glVertexAttribPointer ( RS : : ARRAY_TEX_UV , 2 , GL_FLOAT , GL_FALSE , stride * sizeof ( float ) , CAST_INT_TO_UCHAR_PTR ( base_offset * sizeof ( float ) ) ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
const Vector2 * uv_ptr = p_uvs . ptr ( ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
for ( uint32_t i = 0 ; i < vertex_count ; i + + ) {
fptr [ base_offset + i * stride + 0 ] = uv_ptr [ i ] . x ;
fptr [ base_offset + i * stride + 1 ] = uv_ptr [ i ] . y ;
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
base_offset + = 2 ;
} else {
glDisableVertexAttribArray ( RS : : ARRAY_TEX_UV ) ;
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
if ( ( uint32_t ) p_indices . size ( ) = = vertex_count * 4 & & ( uint32_t ) p_weights . size ( ) = = vertex_count * 4 ) {
glEnableVertexAttribArray ( RS : : ARRAY_BONES ) ;
glVertexAttribPointer ( RS : : ARRAY_BONES , 4 , GL_UNSIGNED_INT , GL_FALSE , stride * sizeof ( float ) , CAST_INT_TO_UCHAR_PTR ( base_offset * sizeof ( float ) ) ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
const int * bone_ptr = p_bones . ptr ( ) ;
for ( uint32_t i = 0 ; i < vertex_count ; i + + ) {
uint16_t * bone16w = ( uint16_t * ) & uptr [ base_offset + i * stride ] ;
bone16w [ 0 ] = bone_ptr [ i * 4 + 0 ] ;
bone16w [ 1 ] = bone_ptr [ i * 4 + 1 ] ;
bone16w [ 2 ] = bone_ptr [ i * 4 + 2 ] ;
bone16w [ 3 ] = bone_ptr [ i * 4 + 3 ] ;
2020-11-18 18:11:30 +00:00
}
2021-11-16 15:25:42 +00:00
base_offset + = 2 ;
2020-11-18 18:11:30 +00:00
} else {
2021-11-16 15:25:42 +00:00
glDisableVertexAttribArray ( RS : : ARRAY_BONES ) ;
2020-11-18 18:11:30 +00:00
}
2021-11-16 15:25:42 +00:00
if ( ( uint32_t ) p_weights . size ( ) = = vertex_count * 4 ) {
glEnableVertexAttribArray ( RS : : ARRAY_WEIGHTS ) ;
glVertexAttribPointer ( RS : : ARRAY_WEIGHTS , 4 , GL_FLOAT , GL_FALSE , stride * sizeof ( float ) , CAST_INT_TO_UCHAR_PTR ( base_offset * sizeof ( float ) ) ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
const float * weight_ptr = p_weights . ptr ( ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
for ( uint32_t i = 0 ; i < vertex_count ; i + + ) {
uint16_t * weight16w = ( uint16_t * ) & uptr [ base_offset + i * stride ] ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
weight16w [ 0 ] = CLAMP ( weight_ptr [ i * 4 + 0 ] * 65535 , 0 , 65535 ) ;
weight16w [ 1 ] = CLAMP ( weight_ptr [ i * 4 + 1 ] * 65535 , 0 , 65535 ) ;
weight16w [ 2 ] = CLAMP ( weight_ptr [ i * 4 + 2 ] * 65535 , 0 , 65535 ) ;
weight16w [ 3 ] = CLAMP ( weight_ptr [ i * 4 + 3 ] * 65535 , 0 , 65535 ) ;
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
base_offset + = 2 ;
} else {
glDisableVertexAttribArray ( RS : : ARRAY_WEIGHTS ) ;
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
ERR_FAIL_COND_V ( base_offset ! = stride , 0 ) ;
glBufferData ( GL_ARRAY_BUFFER , vertex_count * stride * sizeof ( float ) , polygon_buffer . ptr ( ) , GL_STATIC_DRAW ) ;
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
if ( p_indices . size ( ) ) {
//create indices, as indices were requested
Vector < uint8_t > index_buffer ;
index_buffer . resize ( p_indices . size ( ) * sizeof ( int32_t ) ) ;
{
uint8_t * w = index_buffer . ptrw ( ) ;
memcpy ( w , p_indices . ptr ( ) , sizeof ( int32_t ) * p_indices . size ( ) ) ;
2020-11-18 18:11:30 +00:00
}
2021-11-16 15:25:42 +00:00
glGenBuffers ( 1 , & pb . index_buffer ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , pb . index_buffer ) ;
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , p_indices . size ( ) * 4 , index_buffer . ptr ( ) , GL_STATIC_DRAW ) ;
pb . count = p_indices . size ( ) ;
2020-11-18 18:11:30 +00:00
}
2021-11-16 15:25:42 +00:00
glBindVertexArray ( 0 ) ;
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , 0 ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
PolygonID id = polygon_buffers . last_id + + ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
polygon_buffers . polygons [ id ] = pb ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
return id ;
}
void RasterizerCanvasGLES3 : : free_polygon ( PolygonID p_polygon ) {
PolygonBuffers * pb_ptr = polygon_buffers . polygons . getptr ( p_polygon ) ;
ERR_FAIL_COND ( ! pb_ptr ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
PolygonBuffers & pb = * pb_ptr ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
if ( pb . index_buffer ! = 0 ) {
glDeleteBuffers ( 1 , & pb . index_buffer ) ;
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
glDeleteVertexArrays ( 1 , & pb . vertex_array ) ;
glDeleteBuffers ( 1 , & pb . vertex_buffer ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
polygon_buffers . polygons . erase ( p_polygon ) ;
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
// Creates a new uniform buffer and uses it right away
// This expands the instance buffer continually
2022-06-21 04:56:26 +00:00
// In theory allocations can reach as high as number of windows * 3 frames
2021-11-16 15:25:42 +00:00
// because OpenGL can start rendering subsequent frames before finishing the current one
void RasterizerCanvasGLES3 : : _allocate_instance_data_buffer ( ) {
2022-10-13 00:55:01 +00:00
GLuint new_buffers [ 3 ] ;
glGenBuffers ( 3 , new_buffers ) ;
// Batch UBO.
glBindBuffer ( GL_UNIFORM_BUFFER , new_buffers [ 0 ] ) ;
glBufferData ( GL_UNIFORM_BUFFER , data . max_instance_buffer_size , nullptr , GL_STREAM_DRAW ) ;
// Light uniform buffer.
glBindBuffer ( GL_UNIFORM_BUFFER , new_buffers [ 1 ] ) ;
glBufferData ( GL_UNIFORM_BUFFER , sizeof ( LightUniform ) * data . max_lights_per_render , nullptr , GL_STREAM_DRAW ) ;
// State buffer.
glBindBuffer ( GL_UNIFORM_BUFFER , new_buffers [ 2 ] ) ;
glBufferData ( GL_UNIFORM_BUFFER , sizeof ( StateBuffer ) , nullptr , GL_STREAM_DRAW ) ;
2021-11-16 15:25:42 +00:00
state . current_buffer = ( state . current_buffer + 1 ) ;
2022-06-21 04:56:26 +00:00
DataBuffer db ;
2022-10-13 00:55:01 +00:00
db . ubo = new_buffers [ 0 ] ;
db . light_ubo = new_buffers [ 1 ] ;
db . state_ubo = new_buffers [ 2 ] ;
2022-06-21 04:56:26 +00:00
db . last_frame_used = RSG : : rasterizer - > get_frame_number ( ) ;
state . canvas_instance_data_buffers . insert ( state . current_buffer , db ) ;
2021-11-16 15:25:42 +00:00
state . current_buffer = state . current_buffer % state . canvas_instance_data_buffers . size ( ) ;
glBindBuffer ( GL_UNIFORM_BUFFER , 0 ) ;
}
2020-11-18 18:11:30 +00:00
2022-06-21 04:56:26 +00:00
// Batch start positions need to be aligned to the device's GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT.
// This needs to be called anytime a new batch is created.
void RasterizerCanvasGLES3 : : _align_instance_data_buffer ( uint32_t & r_index ) {
if ( GLES3 : : Config : : get_singleton ( ) - > uniform_buffer_offset_alignment > int ( sizeof ( InstanceData ) ) ) {
uint32_t offset = state . canvas_instance_batches [ state . current_batch_index ] . start % GLES3 : : Config : : get_singleton ( ) - > uniform_buffer_offset_alignment ;
if ( offset > 0 ) {
// uniform_buffer_offset_alignment can be 4, 16, 32, or 256. Our instance batches are 128 bytes.
// Accordingly, this branch is only triggered if we are 128 bytes off.
uint32_t offset_bytes = GLES3 : : Config : : get_singleton ( ) - > uniform_buffer_offset_alignment - offset ;
state . canvas_instance_batches [ state . current_batch_index ] . start + = offset_bytes ;
// Offset the instance array so it stays in sync with batch start points.
// This creates gaps in the instance buffer with wasted space, but we can't help it.
r_index + = offset_bytes / sizeof ( InstanceData ) ;
if ( r_index > 0 ) {
// In this case we need to copy over the basic data.
state . instance_data_array [ r_index ] = state . instance_data_array [ r_index - 1 ] ;
}
}
}
}
2022-02-20 00:08:53 +00:00
void RasterizerCanvasGLES3 : : set_time ( double p_time ) {
state . time = p_time ;
}
RasterizerCanvasGLES3 * RasterizerCanvasGLES3 : : singleton = nullptr ;
RasterizerCanvasGLES3 * RasterizerCanvasGLES3 : : get_singleton ( ) {
return singleton ;
}
2022-06-21 00:08:33 +00:00
RasterizerCanvasGLES3 : : RasterizerCanvasGLES3 ( ) {
2022-02-20 00:08:53 +00:00
singleton = this ;
2022-06-21 04:56:26 +00:00
GLES3 : : TextureStorage * texture_storage = GLES3 : : TextureStorage : : get_singleton ( ) ;
2022-03-21 11:25:25 +00:00
GLES3 : : MaterialStorage * material_storage = GLES3 : : MaterialStorage : : get_singleton ( ) ;
2022-05-18 15:04:41 +00:00
GLES3 : : Config * config = GLES3 : : Config : : get_singleton ( ) ;
2022-03-12 11:19:59 +00:00
2022-06-21 04:56:26 +00:00
polygon_buffers . last_id = 1 ;
2021-11-16 15:25:42 +00:00
// quad buffer
{
glGenBuffers ( 1 , & data . canvas_quad_vertices ) ;
glBindBuffer ( GL_ARRAY_BUFFER , data . canvas_quad_vertices ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
const float qv [ 8 ] = {
0 , 0 ,
0 , 1 ,
1 , 1 ,
1 , 0
} ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 8 , qv , GL_STATIC_DRAW ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
glGenVertexArrays ( 1 , & data . canvas_quad_array ) ;
glBindVertexArray ( data . canvas_quad_array ) ;
glBindBuffer ( GL_ARRAY_BUFFER , data . canvas_quad_vertices ) ;
glVertexAttribPointer ( 0 , 2 , GL_FLOAT , GL_FALSE , sizeof ( float ) * 2 , nullptr ) ;
glEnableVertexAttribArray ( 0 ) ;
glBindVertexArray ( 0 ) ;
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ; //unbind
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
{
//particle quad buffers
glGenBuffers ( 1 , & data . particle_quad_vertices ) ;
glBindBuffer ( GL_ARRAY_BUFFER , data . particle_quad_vertices ) ;
{
//quad of size 1, with pivot on the center for particles, then regular UVS. Color is general plus fetched from particle
const float qv [ 16 ] = {
- 0.5 , - 0.5 ,
0.0 , 0.0 ,
- 0.5 , 0.5 ,
0.0 , 1.0 ,
0.5 , 0.5 ,
1.0 , 1.0 ,
0.5 , - 0.5 ,
1.0 , 0.0
} ;
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * 16 , qv , GL_STATIC_DRAW ) ;
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ; //unbind
glGenVertexArrays ( 1 , & data . particle_quad_array ) ;
glBindVertexArray ( data . particle_quad_array ) ;
glBindBuffer ( GL_ARRAY_BUFFER , data . particle_quad_vertices ) ;
glEnableVertexAttribArray ( RS : : ARRAY_VERTEX ) ;
glVertexAttribPointer ( RS : : ARRAY_VERTEX , 2 , GL_FLOAT , GL_FALSE , sizeof ( float ) * 4 , nullptr ) ;
glEnableVertexAttribArray ( RS : : ARRAY_TEX_UV ) ;
glVertexAttribPointer ( RS : : ARRAY_TEX_UV , 2 , GL_FLOAT , GL_FALSE , sizeof ( float ) * 4 , CAST_INT_TO_UCHAR_PTR ( 8 ) ) ;
glBindVertexArray ( 0 ) ;
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ; //unbind
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
// ninepatch buffers
{
// array buffer
glGenBuffers ( 1 , & data . ninepatch_vertices ) ;
glBindBuffer ( GL_ARRAY_BUFFER , data . ninepatch_vertices ) ;
2020-11-18 18:11:30 +00:00
2022-01-27 16:34:33 +00:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( float ) * ( 16 + 16 ) * 2 , nullptr , GL_DYNAMIC_DRAW ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
// element buffer
glGenBuffers ( 1 , & data . ninepatch_elements ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , data . ninepatch_elements ) ;
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
# define _EIDX(y, x) (y * 4 + x)
uint8_t elems [ 3 * 2 * 9 ] = {
// first row
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
_EIDX ( 0 , 0 ) , _EIDX ( 0 , 1 ) , _EIDX ( 1 , 1 ) ,
_EIDX ( 1 , 1 ) , _EIDX ( 1 , 0 ) , _EIDX ( 0 , 0 ) ,
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
_EIDX ( 0 , 1 ) , _EIDX ( 0 , 2 ) , _EIDX ( 1 , 2 ) ,
_EIDX ( 1 , 2 ) , _EIDX ( 1 , 1 ) , _EIDX ( 0 , 1 ) ,
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
_EIDX ( 0 , 2 ) , _EIDX ( 0 , 3 ) , _EIDX ( 1 , 3 ) ,
_EIDX ( 1 , 3 ) , _EIDX ( 1 , 2 ) , _EIDX ( 0 , 2 ) ,
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
// second row
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
_EIDX ( 1 , 0 ) , _EIDX ( 1 , 1 ) , _EIDX ( 2 , 1 ) ,
_EIDX ( 2 , 1 ) , _EIDX ( 2 , 0 ) , _EIDX ( 1 , 0 ) ,
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
// the center one would be here, but we'll put it at the end
// so it's easier to disable the center and be able to use
// one draw call for both
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
_EIDX ( 1 , 2 ) , _EIDX ( 1 , 3 ) , _EIDX ( 2 , 3 ) ,
_EIDX ( 2 , 3 ) , _EIDX ( 2 , 2 ) , _EIDX ( 1 , 2 ) ,
// third row
_EIDX ( 2 , 0 ) , _EIDX ( 2 , 1 ) , _EIDX ( 3 , 1 ) ,
_EIDX ( 3 , 1 ) , _EIDX ( 3 , 0 ) , _EIDX ( 2 , 0 ) ,
_EIDX ( 2 , 1 ) , _EIDX ( 2 , 2 ) , _EIDX ( 3 , 2 ) ,
_EIDX ( 3 , 2 ) , _EIDX ( 3 , 1 ) , _EIDX ( 2 , 1 ) ,
_EIDX ( 2 , 2 ) , _EIDX ( 2 , 3 ) , _EIDX ( 3 , 3 ) ,
_EIDX ( 3 , 3 ) , _EIDX ( 3 , 2 ) , _EIDX ( 2 , 2 ) ,
// center field
_EIDX ( 1 , 1 ) , _EIDX ( 1 , 2 ) , _EIDX ( 2 , 2 ) ,
_EIDX ( 2 , 2 ) , _EIDX ( 2 , 1 ) , _EIDX ( 1 , 1 )
} ;
# undef _EIDX
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , sizeof ( elems ) , elems , GL_STATIC_DRAW ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , 0 ) ;
2020-11-18 18:11:30 +00:00
}
2022-05-18 15:04:41 +00:00
int uniform_max_size = config - > max_uniform_buffer_size ;
2021-11-16 15:25:42 +00:00
if ( uniform_max_size < 65536 ) {
2022-06-21 04:56:26 +00:00
data . max_lights_per_render = 64 ;
data . max_instances_per_batch = 128 ;
2021-11-16 15:25:42 +00:00
} else {
2022-06-21 04:56:26 +00:00
data . max_lights_per_render = 256 ;
data . max_instances_per_batch = 512 ;
2020-11-18 18:11:30 +00:00
}
2022-06-21 04:56:26 +00:00
// Reserve 3 Uniform Buffers for instance data Frame N, N+1 and N+2
data . max_instances_per_ubo = MAX ( data . max_instances_per_batch , uint32_t ( GLOBAL_GET ( " rendering/gl_compatibility/item_buffer_size " ) ) ) ;
data . max_instance_buffer_size = data . max_instances_per_ubo * sizeof ( InstanceData ) ; // 16,384 instances * 128 bytes = 2,097,152 bytes = 2,048 kb
state . canvas_instance_data_buffers . resize ( 3 ) ;
state . canvas_instance_batches . reserve ( 200 ) ;
for ( int i = 0 ; i < 3 ; i + + ) {
2022-10-13 00:55:01 +00:00
GLuint new_buffers [ 3 ] ;
glGenBuffers ( 3 , new_buffers ) ;
// Batch UBO.
glBindBuffer ( GL_UNIFORM_BUFFER , new_buffers [ 0 ] ) ;
glBufferData ( GL_UNIFORM_BUFFER , data . max_instance_buffer_size , nullptr , GL_STREAM_DRAW ) ;
// Light uniform buffer.
glBindBuffer ( GL_UNIFORM_BUFFER , new_buffers [ 1 ] ) ;
glBufferData ( GL_UNIFORM_BUFFER , sizeof ( LightUniform ) * data . max_lights_per_render , nullptr , GL_STREAM_DRAW ) ;
// State buffer.
glBindBuffer ( GL_UNIFORM_BUFFER , new_buffers [ 2 ] ) ;
glBufferData ( GL_UNIFORM_BUFFER , sizeof ( StateBuffer ) , nullptr , GL_STREAM_DRAW ) ;
2022-06-21 04:56:26 +00:00
DataBuffer db ;
2022-10-13 00:55:01 +00:00
db . ubo = new_buffers [ 0 ] ;
db . light_ubo = new_buffers [ 1 ] ;
db . state_ubo = new_buffers [ 2 ] ;
2022-06-21 04:56:26 +00:00
db . last_frame_used = 0 ;
db . fence = glFenceSync ( GL_SYNC_GPU_COMMANDS_COMPLETE , 0 ) ;
state . canvas_instance_data_buffers [ i ] = db ;
2021-11-16 15:25:42 +00:00
}
glBindBuffer ( GL_UNIFORM_BUFFER , 0 ) ;
2020-11-18 18:11:30 +00:00
2022-06-21 04:56:26 +00:00
state . instance_data_array = memnew_arr ( InstanceData , data . max_instances_per_ubo ) ;
2022-10-13 00:55:01 +00:00
state . light_uniforms = memnew_arr ( LightUniform , data . max_lights_per_render ) ;
2022-06-21 04:56:26 +00:00
{
const uint32_t no_of_instances = data . max_instances_per_batch ;
glGenVertexArrays ( 1 , & data . indexed_quad_array ) ;
glBindVertexArray ( data . indexed_quad_array ) ;
glBindBuffer ( GL_ARRAY_BUFFER , data . canvas_quad_vertices ) ;
const uint32_t num_indices = 6 ;
const uint32_t quad_indices [ num_indices ] = { 0 , 2 , 1 , 3 , 2 , 0 } ;
const uint32_t total_indices = no_of_instances * num_indices ;
uint32_t * indices = new uint32_t [ total_indices ] ;
for ( uint32_t i = 0 ; i < total_indices ; i + + ) {
uint32_t quad = i / num_indices ;
uint32_t quad_local = i % num_indices ;
indices [ i ] = quad_indices [ quad_local ] + quad * num_indices ;
}
glGenBuffers ( 1 , & data . indexed_quad_buffer ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , data . indexed_quad_buffer ) ;
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , sizeof ( uint32_t ) * total_indices , indices , GL_STATIC_DRAW ) ;
glBindVertexArray ( 0 ) ;
delete [ ] indices ;
}
2020-11-18 18:11:30 +00:00
2021-11-16 15:25:42 +00:00
String global_defines ;
2022-04-03 16:56:43 +00:00
global_defines + = " #define MAX_GLOBAL_SHADER_UNIFORMS 256 \n " ; // TODO: this is arbitrary for now
2022-10-13 00:55:01 +00:00
global_defines + = " #define MAX_LIGHTS " + itos ( data . max_lights_per_render ) + " \n " ;
2022-06-21 04:56:26 +00:00
global_defines + = " #define MAX_DRAW_DATA_INSTANCES " + itos ( data . max_instances_per_batch ) + " \n " ;
2020-11-18 18:11:30 +00:00
2022-02-20 00:08:53 +00:00
GLES3 : : MaterialStorage : : get_singleton ( ) - > shaders . canvas_shader . initialize ( global_defines ) ;
2022-06-21 04:56:26 +00:00
data . canvas_shader_default_version = GLES3 : : MaterialStorage : : get_singleton ( ) - > shaders . canvas_shader . version_create ( ) ;
2020-11-18 18:11:30 +00:00
2022-10-19 00:59:31 +00:00
shadow_render . shader . initialize ( ) ;
shadow_render . shader_version = shadow_render . shader . version_create ( ) ;
2021-11-16 15:25:42 +00:00
{
2022-03-21 11:25:25 +00:00
default_canvas_group_shader = material_storage - > shader_allocate ( ) ;
material_storage - > shader_initialize ( default_canvas_group_shader ) ;
2021-11-16 15:25:42 +00:00
2022-03-21 11:25:25 +00:00
material_storage - > shader_set_code ( default_canvas_group_shader , R " (
2021-11-16 15:25:42 +00:00
// Default CanvasGroup shader.
shader_type canvas_item ;
void fragment ( ) {
vec4 c = textureLod ( SCREEN_TEXTURE , SCREEN_UV , 0.0 ) ;
if ( c . a > 0.0001 ) {
c . rgb / = c . a ;
}
COLOR * = c ;
}
) " );
2022-03-21 11:25:25 +00:00
default_canvas_group_material = material_storage - > material_allocate ( ) ;
material_storage - > material_initialize ( default_canvas_group_material ) ;
2021-11-16 15:25:42 +00:00
2022-03-21 11:25:25 +00:00
material_storage - > material_set_shader ( default_canvas_group_material , default_canvas_group_shader ) ;
2021-11-16 15:25:42 +00:00
}
2022-10-06 22:27:11 +00:00
{
default_clip_children_shader = material_storage - > shader_allocate ( ) ;
material_storage - > shader_initialize ( default_clip_children_shader ) ;
material_storage - > shader_set_code ( default_clip_children_shader , R " (
// Default clip children shader.
shader_type canvas_item ;
void fragment ( ) {
vec4 c = textureLod ( SCREEN_TEXTURE , SCREEN_UV , 0.0 ) ;
COLOR . rgb = c . rgb ;
}
) " );
default_clip_children_material = material_storage - > material_allocate ( ) ;
material_storage - > material_initialize ( default_clip_children_material ) ;
material_storage - > material_set_shader ( default_clip_children_material , default_clip_children_shader ) ;
}
2022-06-21 04:56:26 +00:00
default_canvas_texture = texture_storage - > canvas_texture_allocate ( ) ;
texture_storage - > canvas_texture_initialize ( default_canvas_texture ) ;
2022-02-20 00:08:53 +00:00
state . time = 0.0 ;
2021-11-16 15:25:42 +00:00
}
2022-03-21 11:25:25 +00:00
2021-11-16 15:25:42 +00:00
RasterizerCanvasGLES3 : : ~ RasterizerCanvasGLES3 ( ) {
2022-10-19 00:59:31 +00:00
singleton = nullptr ;
2022-03-21 11:25:25 +00:00
2022-10-19 00:59:31 +00:00
GLES3 : : MaterialStorage * material_storage = GLES3 : : MaterialStorage : : get_singleton ( ) ;
2022-06-21 04:56:26 +00:00
material_storage - > shaders . canvas_shader . version_free ( data . canvas_shader_default_version ) ;
2022-10-19 00:59:31 +00:00
shadow_render . shader . version_free ( shadow_render . shader_version ) ;
2022-03-21 11:25:25 +00:00
material_storage - > material_free ( default_canvas_group_material ) ;
material_storage - > shader_free ( default_canvas_group_shader ) ;
2022-10-06 22:27:11 +00:00
material_storage - > material_free ( default_clip_children_material ) ;
material_storage - > shader_free ( default_clip_children_shader ) ;
2022-03-21 11:25:25 +00:00
singleton = nullptr ;
2021-11-16 15:25:42 +00:00
glDeleteBuffers ( 1 , & data . canvas_quad_vertices ) ;
glDeleteVertexArrays ( 1 , & data . canvas_quad_array ) ;
glDeleteBuffers ( 1 , & data . canvas_quad_vertices ) ;
glDeleteVertexArrays ( 1 , & data . canvas_quad_array ) ;
2022-06-21 04:56:26 +00:00
GLES3 : : TextureStorage : : get_singleton ( ) - > canvas_texture_free ( default_canvas_texture ) ;
2022-10-13 00:55:01 +00:00
memdelete_arr ( state . instance_data_array ) ;
memdelete_arr ( state . light_uniforms ) ;
2022-10-19 00:59:31 +00:00
if ( state . shadow_fb ! = 0 ) {
glDeleteFramebuffers ( 1 , & state . shadow_fb ) ;
glDeleteTextures ( 1 , & state . shadow_texture ) ;
glDeleteRenderbuffers ( 1 , & state . shadow_depth_buffer ) ;
state . shadow_fb = 0 ;
state . shadow_texture = 0 ;
state . shadow_depth_buffer = 0 ;
}
2020-11-18 18:11:30 +00:00
}
2021-11-16 15:25:42 +00:00
# endif // GLES3_ENABLED