diff options
Diffstat (limited to 'drivers/gles3/storage')
-rw-r--r-- | drivers/gles3/storage/config.cpp | 2 | ||||
-rw-r--r-- | drivers/gles3/storage/config.h | 2 | ||||
-rw-r--r-- | drivers/gles3/storage/light_storage.cpp | 131 | ||||
-rw-r--r-- | drivers/gles3/storage/light_storage.h | 90 | ||||
-rw-r--r-- | drivers/gles3/storage/material_storage.cpp | 12 | ||||
-rw-r--r-- | drivers/gles3/storage/material_storage.h | 2 | ||||
-rw-r--r-- | drivers/gles3/storage/texture_storage.cpp | 404 | ||||
-rw-r--r-- | drivers/gles3/storage/texture_storage.h | 100 | ||||
-rw-r--r-- | drivers/gles3/storage/utilities.cpp | 1 |
9 files changed, 595 insertions, 149 deletions
diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp index 6cc65e7bb2..242c1ce0a9 100644 --- a/drivers/gles3/storage/config.cpp +++ b/drivers/gles3/storage/config.cpp @@ -86,6 +86,8 @@ Config::Config() { glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &max_uniform_buffer_size); + glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_offset_alignment); + // the use skeleton software path should be used if either float texture is not supported, // OR max_vertex_texture_image_units is zero use_skeleton_software = (float_texture_supported == false) || (max_vertex_texture_image_units == 0); diff --git a/drivers/gles3/storage/config.h b/drivers/gles3/storage/config.h index b83c83f425..fe18345775 100644 --- a/drivers/gles3/storage/config.h +++ b/drivers/gles3/storage/config.h @@ -64,6 +64,8 @@ public: int max_renderable_lights = 0; int max_lights_per_object = 0; + int uniform_buffer_offset_alignment = 0; + // TODO implement wireframe in OpenGL // bool generate_wireframes; diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp index 6411590aee..b6bd4a2760 100644 --- a/drivers/gles3/storage/light_storage.cpp +++ b/drivers/gles3/storage/light_storage.cpp @@ -333,6 +333,46 @@ AABB LightStorage::light_get_aabb(RID p_light) const { ERR_FAIL_V(AABB()); } +/* LIGHT INSTANCE API */ + +RID LightStorage::light_instance_create(RID p_light) { + RID li = light_instance_owner.make_rid(LightInstance()); + + LightInstance *light_instance = light_instance_owner.get_or_null(li); + + light_instance->self = li; + light_instance->light = p_light; + light_instance->light_type = light_get_type(p_light); + + return li; +} + +void LightStorage::light_instance_free(RID p_light_instance) { + LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance); + ERR_FAIL_COND(!light_instance); + light_instance_owner.free(p_light_instance); +} + +void LightStorage::light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) { + LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance); + ERR_FAIL_COND(!light_instance); + + light_instance->transform = p_transform; +} + +void LightStorage::light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) { + LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance); + ERR_FAIL_COND(!light_instance); + + light_instance->aabb = p_aabb; +} + +void LightStorage::light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) { +} + +void LightStorage::light_instance_mark_visible(RID p_light_instance) { +} + /* PROBE API */ RID LightStorage::reflection_probe_allocate() { @@ -419,6 +459,53 @@ float LightStorage::reflection_probe_get_mesh_lod_threshold(RID p_probe) const { return 0.0; } +/* REFLECTION ATLAS */ + +RID LightStorage::reflection_atlas_create() { + return RID(); +} + +void LightStorage::reflection_atlas_free(RID p_ref_atlas) { +} + +int LightStorage::reflection_atlas_get_size(RID p_ref_atlas) const { + return 0; +} + +void LightStorage::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) { +} + +/* REFLECTION PROBE INSTANCE */ + +RID LightStorage::reflection_probe_instance_create(RID p_probe) { + return RID(); +} + +void LightStorage::reflection_probe_instance_free(RID p_instance) { +} + +void LightStorage::reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) { +} + +void LightStorage::reflection_probe_release_atlas_index(RID p_instance) { +} + +bool LightStorage::reflection_probe_instance_needs_redraw(RID p_instance) { + return false; +} + +bool LightStorage::reflection_probe_instance_has_reflection(RID p_instance) { + return false; +} + +bool LightStorage::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) { + return false; +} + +bool LightStorage::reflection_probe_instance_postprocess_step(RID p_instance) { + return true; +} + /* LIGHTMAP CAPTURE */ RID LightStorage::lightmap_allocate() { @@ -484,6 +571,18 @@ float LightStorage::lightmap_get_probe_capture_update_speed() const { return 0; } +/* LIGHTMAP INSTANCE */ + +RID LightStorage::lightmap_instance_create(RID p_lightmap) { + return RID(); +} + +void LightStorage::lightmap_instance_free(RID p_lightmap) { +} + +void LightStorage::lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) { +} + /* LIGHT SHADOW MAPPING */ /* @@ -584,4 +683,36 @@ void LightStorage::canvas_light_occluder_set_polylines(RID p_occluder, const Poo } */ +/* SHADOW ATLAS API */ + +RID LightStorage::shadow_atlas_create() { + return RID(); +} + +void LightStorage::shadow_atlas_free(RID p_atlas) { +} + +void LightStorage::shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits) { +} + +void LightStorage::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) { +} + +bool LightStorage::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) { + return false; +} + +void LightStorage::shadow_atlas_update(RID p_atlas) { +} + +void LightStorage::directional_shadow_atlas_set_size(int p_size, bool p_16_bits) { +} + +int LightStorage::get_directional_light_shadow_size(RID p_light_intance) { + return 0; +} + +void LightStorage::set_directional_shadow_count(int p_count) { +} + #endif // !GLES3_ENABLED diff --git a/drivers/gles3/storage/light_storage.h b/drivers/gles3/storage/light_storage.h index 8b708116ac..12cb2c4393 100644 --- a/drivers/gles3/storage/light_storage.h +++ b/drivers/gles3/storage/light_storage.h @@ -76,6 +76,33 @@ struct Light { Dependency dependency; }; +/* Light instance */ +struct LightInstance { + RS::LightType light_type = RS::LIGHT_DIRECTIONAL; + + AABB aabb; + RID self; + RID light; + Transform3D transform; + + Vector3 light_vector; + Vector3 spot_vector; + float linear_att = 0.0; + + uint64_t shadow_pass = 0; + uint64_t last_scene_pass = 0; + uint64_t last_scene_shadow_pass = 0; + uint64_t last_pass = 0; + uint32_t cull_mask = 0; + uint32_t light_directional_index = 0; + + Rect2 directional_rect; + + uint32_t gl_id = -1; + + LightInstance() {} +}; + /* REFLECTION PROBE */ struct ReflectionProbe { @@ -128,6 +155,9 @@ private: /* LIGHT */ mutable RID_Owner<Light, true> light_owner; + /* Light instance */ + mutable RID_Owner<LightInstance> light_instance_owner; + /* REFLECTION PROBE */ mutable RID_Owner<ReflectionProbe, true> reflection_probe_owner; @@ -268,6 +298,28 @@ public: virtual uint32_t light_get_max_sdfgi_cascade(RID p_light) override { return 0; } virtual uint64_t light_get_version(RID p_light) const override; + /* LIGHT INSTANCE API */ + + LightInstance *get_light_instance(RID p_rid) { return light_instance_owner.get_or_null(p_rid); }; + bool owns_light_instance(RID p_rid) { return light_instance_owner.owns(p_rid); }; + + virtual RID light_instance_create(RID p_light) override; + virtual void light_instance_free(RID p_light_instance) override; + + virtual void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override; + virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override; + virtual void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override; + virtual void light_instance_mark_visible(RID p_light_instance) override; + + _FORCE_INLINE_ RS::LightType light_instance_get_type(RID p_light_instance) { + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + return li->light_type; + } + _FORCE_INLINE_ uint32_t light_instance_get_gl_id(RID p_light_instance) { + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); + return li->gl_id; + } + /* PROBE API */ virtual RID reflection_probe_allocate() override; @@ -298,6 +350,24 @@ public: virtual float reflection_probe_get_origin_max_distance(RID p_probe) const override; virtual bool reflection_probe_renders_shadows(RID p_probe) const override; + /* REFLECTION ATLAS */ + + virtual RID reflection_atlas_create() override; + virtual void reflection_atlas_free(RID p_ref_atlas) override; + virtual int reflection_atlas_get_size(RID p_ref_atlas) const override; + virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override; + + /* REFLECTION PROBE INSTANCE */ + + virtual RID reflection_probe_instance_create(RID p_probe) override; + virtual void reflection_probe_instance_free(RID p_instance) override; + virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override; + virtual void reflection_probe_release_atlas_index(RID p_instance) override; + virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override; + virtual bool reflection_probe_instance_has_reflection(RID p_instance) override; + virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override; + virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override; + /* LIGHTMAP CAPTURE */ Lightmap *get_lightmap(RID p_rid) { return lightmap_owner.get_or_null(p_rid); }; @@ -338,6 +408,26 @@ public: RID canvas_light_occluder_create(); void canvas_light_occluder_set_polylines(RID p_occluder, const LocalVector<Vector2> &p_lines); */ + + /* LIGHTMAP INSTANCE */ + + virtual RID lightmap_instance_create(RID p_lightmap) override; + virtual void lightmap_instance_free(RID p_lightmap) override; + virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override; + + /* SHADOW ATLAS API */ + + virtual RID shadow_atlas_create() override; + virtual void shadow_atlas_free(RID p_atlas) override; + virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) override; + virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override; + virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) override; + + virtual void shadow_atlas_update(RID p_atlas) override; + + virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override; + virtual int get_directional_light_shadow_size(RID p_light_intance) override; + virtual void set_directional_shadow_count(int p_count) override; }; } // namespace GLES3 diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp index 687e98ba58..f5241e33ab 100644 --- a/drivers/gles3/storage/material_storage.cpp +++ b/drivers/gles3/storage/material_storage.cpp @@ -714,7 +714,7 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy Projection v = value; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { - gui[i * 4 + j] = v.matrix[i][j]; + gui[i * 4 + j] = v.columns[i][j]; } } } @@ -897,7 +897,9 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, case ShaderLanguage::TYPE_BVEC3: case ShaderLanguage::TYPE_IVEC3: case ShaderLanguage::TYPE_UVEC3: - case ShaderLanguage::TYPE_VEC3: + case ShaderLanguage::TYPE_VEC3: { + memset(data, 0, 12 * p_array_size); + } break; case ShaderLanguage::TYPE_BVEC4: case ShaderLanguage::TYPE_IVEC4: case ShaderLanguage::TYPE_UVEC4: @@ -1393,7 +1395,7 @@ MaterialStorage::MaterialStorage() { actions.renames["NORMAL_MAP"] = "normal_map"; actions.renames["NORMAL_MAP_DEPTH"] = "normal_map_depth"; actions.renames["TEXTURE"] = "color_texture"; - actions.renames["TEXTURE_PIXEL_SIZE"] = "draw_data.color_texture_pixel_size"; + actions.renames["TEXTURE_PIXEL_SIZE"] = "color_texture_pixel_size"; actions.renames["NORMAL_TEXTURE"] = "normal_texture"; actions.renames["SPECULAR_SHININESS_TEXTURE"] = "specular_texture"; actions.renames["SPECULAR_SHININESS"] = "specular_shininess"; @@ -1406,6 +1408,8 @@ MaterialStorage::MaterialStorage() { actions.renames["VERTEX_ID"] = "gl_VertexIndex"; actions.renames["LIGHT_POSITION"] = "light_position"; + actions.renames["LIGHT_DIRECTION"] = "light_direction"; + actions.renames["LIGHT_IS_DIRECTIONAL"] = "is_directional"; actions.renames["LIGHT_COLOR"] = "light_color"; actions.renames["LIGHT_ENERGY"] = "light_energy"; actions.renames["LIGHT"] = "light"; @@ -1654,7 +1658,7 @@ ShaderCompiler::DefaultIdentifierActions actions; actions.render_mode_defines["disable_force"] = "#define DISABLE_FORCE\n"; actions.render_mode_defines["disable_velocity"] = "#define DISABLE_VELOCITY\n"; actions.render_mode_defines["keep_data"] = "#define ENABLE_KEEP_DATA\n"; - actions.render_mode_defines["collision_use_scale"] = "#define USE_COLLISON_SCALE\n"; + actions.render_mode_defines["collision_use_scale"] = "#define USE_COLLISION_SCALE\n"; actions.sampler_array_name = "material_samplers"; actions.base_texture_binding_index = 1; diff --git a/drivers/gles3/storage/material_storage.h b/drivers/gles3/storage/material_storage.h index 65c46631ed..6504c7748c 100644 --- a/drivers/gles3/storage/material_storage.h +++ b/drivers/gles3/storage/material_storage.h @@ -494,7 +494,7 @@ public: static _FORCE_INLINE_ void store_camera(const Projection &p_mtx, float *p_array) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { - p_array[i * 4 + j] = p_mtx.matrix[i][j]; + p_array[i * 4 + j] = p_mtx.columns[i][j]; } } } diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp index a801b3285a..48f460f995 100644 --- a/drivers/gles3/storage/texture_storage.cpp +++ b/drivers/gles3/storage/texture_storage.cpp @@ -197,6 +197,22 @@ TextureStorage::TextureStorage() { glBindTexture(GL_TEXTURE_2D, 0); + { // Atlas Texture initialize. + uint8_t pixel_data[4 * 4 * 4]; + for (int i = 0; i < 16; i++) { + pixel_data[i * 4 + 0] = 0; + pixel_data[i * 4 + 1] = 0; + pixel_data[i * 4 + 2] = 0; + pixel_data[i * 4 + 3] = 255; + } + + glGenTextures(1, &texture_atlas.texture); + glBindTexture(GL_TEXTURE_2D, texture_atlas.texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel_data); + } + + glBindTexture(GL_TEXTURE_2D, 0); + #ifdef GLES_OVER_GL glEnable(GL_PROGRAM_POINT_SIZE); #endif @@ -207,6 +223,11 @@ TextureStorage::~TextureStorage() { for (int i = 0; i < DEFAULT_GL_TEXTURE_MAX; i++) { texture_free(default_gl_textures[i]); } + + glDeleteTextures(1, &texture_atlas.texture); + texture_atlas.texture = 0; + glDeleteFramebuffers(1, &texture_atlas.framebuffer); + texture_atlas.framebuffer = 0; } //TODO, move back to storage @@ -653,7 +674,7 @@ void TextureStorage::texture_free(RID p_texture) { } } - //decal_atlas_remove_texture(p_texture); + texture_atlas_remove_texture(p_texture); for (int i = 0; i < t->proxies.size(); i++) { Texture *p = texture_owner.get_or_null(t->proxies[i]); @@ -666,6 +687,8 @@ void TextureStorage::texture_free(RID p_texture) { } void TextureStorage::texture_2d_initialize(RID p_texture, const Ref<Image> &p_image) { + ERR_FAIL_COND(p_image.is_null()); + Texture texture; texture.width = p_image->get_width(); texture.height = p_image->get_height(); @@ -873,7 +896,7 @@ void TextureStorage::texture_replace(RID p_texture, RID p_by_texture) { //delete last, so proxies can be updated texture_owner.free(p_by_texture); - //decal_atlas_mark_dirty_on_texture(p_texture); + texture_atlas_mark_dirty_on_texture(p_texture); } void TextureStorage::texture_set_size_override(RID p_texture, int p_width, int p_height) { @@ -1141,6 +1164,217 @@ RID TextureStorage::texture_create_radiance_cubemap(RID p_source, int p_resoluti return RID(); } +/* TEXTURE ATLAS API */ + +void TextureStorage::texture_add_to_texture_atlas(RID p_texture) { + if (!texture_atlas.textures.has(p_texture)) { + TextureAtlas::Texture t; + t.users = 1; + texture_atlas.textures[p_texture] = t; + texture_atlas.dirty = true; + } else { + TextureAtlas::Texture *t = texture_atlas.textures.getptr(p_texture); + t->users++; + } +} + +void TextureStorage::texture_remove_from_texture_atlas(RID p_texture) { + TextureAtlas::Texture *t = texture_atlas.textures.getptr(p_texture); + ERR_FAIL_COND(!t); + t->users--; + if (t->users == 0) { + texture_atlas.textures.erase(p_texture); + // Do not mark it dirty, there is no need to since it remains working. + } +} + +void TextureStorage::texture_atlas_mark_dirty_on_texture(RID p_texture) { + if (texture_atlas.textures.has(p_texture)) { + texture_atlas.dirty = true; // Mark it dirty since it was most likely modified. + } +} + +void TextureStorage::texture_atlas_remove_texture(RID p_texture) { + if (texture_atlas.textures.has(p_texture)) { + texture_atlas.textures.erase(p_texture); + // There is not much a point of making it dirty, texture can be removed next time the atlas is updated. + } +} + +GLuint TextureStorage::texture_atlas_get_texture() const { + return texture_atlas.texture; +} + +void TextureStorage::update_texture_atlas() { + CopyEffects *copy_effects = CopyEffects::get_singleton(); + ERR_FAIL_NULL(copy_effects); + + if (!texture_atlas.dirty) { + return; //nothing to do + } + + texture_atlas.dirty = false; + + if (texture_atlas.texture != 0) { + glDeleteTextures(1, &texture_atlas.texture); + texture_atlas.texture = 0; + glDeleteFramebuffers(1, &texture_atlas.framebuffer); + texture_atlas.framebuffer = 0; + } + + const int border = 2; + + if (texture_atlas.textures.size()) { + //generate atlas + Vector<TextureAtlas::SortItem> itemsv; + itemsv.resize(texture_atlas.textures.size()); + int base_size = 8; + + int idx = 0; + + for (const KeyValue<RID, TextureAtlas::Texture> &E : texture_atlas.textures) { + TextureAtlas::SortItem &si = itemsv.write[idx]; + + Texture *src_tex = get_texture(E.key); + + si.size.width = (src_tex->width / border) + 1; + si.size.height = (src_tex->height / border) + 1; + si.pixel_size = Size2i(src_tex->width, src_tex->height); + + if (base_size < si.size.width) { + base_size = nearest_power_of_2_templated(si.size.width); + } + + si.texture = E.key; + idx++; + } + + //sort items by size + itemsv.sort(); + + //attempt to create atlas + int item_count = itemsv.size(); + TextureAtlas::SortItem *items = itemsv.ptrw(); + + int atlas_height = 0; + + while (true) { + Vector<int> v_offsetsv; + v_offsetsv.resize(base_size); + + int *v_offsets = v_offsetsv.ptrw(); + memset(v_offsets, 0, sizeof(int) * base_size); + + int max_height = 0; + + for (int i = 0; i < item_count; i++) { + //best fit + TextureAtlas::SortItem &si = items[i]; + int best_idx = -1; + int best_height = 0x7FFFFFFF; + for (int j = 0; j <= base_size - si.size.width; j++) { + int height = 0; + for (int k = 0; k < si.size.width; k++) { + int h = v_offsets[k + j]; + if (h > height) { + height = h; + if (height > best_height) { + break; //already bad + } + } + } + + if (height < best_height) { + best_height = height; + best_idx = j; + } + } + + //update + for (int k = 0; k < si.size.width; k++) { + v_offsets[k + best_idx] = best_height + si.size.height; + } + + si.pos.x = best_idx; + si.pos.y = best_height; + + if (si.pos.y + si.size.height > max_height) { + max_height = si.pos.y + si.size.height; + } + } + + if (max_height <= base_size * 2) { + atlas_height = max_height; + break; //good ratio, break; + } + + base_size *= 2; + } + + texture_atlas.size.width = base_size * border; + texture_atlas.size.height = nearest_power_of_2_templated(atlas_height * border); + + for (int i = 0; i < item_count; i++) { + TextureAtlas::Texture *t = texture_atlas.textures.getptr(items[i].texture); + t->uv_rect.position = items[i].pos * border + Vector2i(border / 2, border / 2); + t->uv_rect.size = items[i].pixel_size; + + t->uv_rect.position /= Size2(texture_atlas.size); + t->uv_rect.size /= Size2(texture_atlas.size); + } + } else { + texture_atlas.size.width = 4; + texture_atlas.size.height = 4; + } + + { // Atlas Texture initialize. + // TODO validate texture atlas size with maximum texture size + glGenTextures(1, &texture_atlas.texture); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture_atlas.texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texture_atlas.size.width, texture_atlas.size.height, 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_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); + + glGenFramebuffers(1, &texture_atlas.framebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, texture_atlas.framebuffer); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_atlas.texture, 0); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + + if (status != GL_FRAMEBUFFER_COMPLETE) { + glDeleteFramebuffers(1, &texture_atlas.framebuffer); + texture_atlas.framebuffer = 0; + glDeleteTextures(1, &texture_atlas.texture); + texture_atlas.texture = 0; + WARN_PRINT("Could not create texture atlas, status: " + get_framebuffer_error(status)); + return; + } + glViewport(0, 0, texture_atlas.size.width, texture_atlas.size.height); + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT); + glBindTexture(GL_TEXTURE_2D, 0); + } + + glDisable(GL_BLEND); + + if (texture_atlas.textures.size()) { + for (const KeyValue<RID, TextureAtlas::Texture> &E : texture_atlas.textures) { + TextureAtlas::Texture *t = texture_atlas.textures.getptr(E.key); + Texture *src_tex = get_texture(E.key); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, src_tex->tex_id); + copy_effects->copy_to_rect(t->uv_rect); + } + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + /* DECAL API */ RID TextureStorage::decal_allocate() { @@ -1181,6 +1415,18 @@ AABB TextureStorage::decal_get_aabb(RID p_decal) const { return AABB(); } +/* DECAL INSTANCE API */ + +RID TextureStorage::decal_instance_create(RID p_decal) { + return RID(); +} + +void TextureStorage::decal_instance_free(RID p_decal_instance) { +} + +void TextureStorage::decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) { +} + /* RENDER TARGET API */ GLuint TextureStorage::system_fbo = 0; @@ -1329,24 +1575,6 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) { rt->fbo = 0; rt->color = 0; } - /* - if (rt->external.fbo != 0) { - // free this - glDeleteFramebuffers(1, &rt->external.fbo); - - // clean up our texture - Texture *t = get_texture(rt->external.texture); - t->alloc_height = 0; - t->alloc_width = 0; - t->width = 0; - t->height = 0; - t->active = false; - texture_free(rt->external.texture); - memdelete(t); - - rt->external.fbo = 0; - } - */ Texture *tex = get_texture(rt->texture); tex->alloc_height = 0; @@ -1398,6 +1626,13 @@ void TextureStorage::render_target_set_position(RID p_render_target, int p_x, in rt->position = Point2i(p_x, p_y); } +Point2i TextureStorage::render_target_get_position(RID p_render_target) const { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND_V(!rt, Point2i()); + + return rt->position; +}; + void TextureStorage::render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND(!rt); @@ -1414,9 +1649,9 @@ void TextureStorage::render_target_set_size(RID p_render_target, int p_width, in } // TODO: convert to Size2i internally -Size2i TextureStorage::render_target_get_size(RID p_render_target) { +Size2i TextureStorage::render_target_get_size(RID p_render_target) const { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); - ERR_FAIL_COND_V(!rt, Size2()); + ERR_FAIL_COND_V(!rt, Size2i()); return rt->size; } @@ -1425,105 +1660,7 @@ RID TextureStorage::render_target_get_texture(RID p_render_target) { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND_V(!rt, RID()); - if (rt->external.fbo == 0) { - return rt->texture; - } else { - return rt->external.texture; - } -} - -void TextureStorage::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) { - RenderTarget *rt = render_target_owner.get_or_null(p_render_target); - ERR_FAIL_COND(!rt); - - if (p_texture_id == 0) { - if (rt->external.fbo != 0) { - // free this - glDeleteFramebuffers(1, &rt->external.fbo); - - // and this - if (rt->external.depth != 0) { - glDeleteRenderbuffers(1, &rt->external.depth); - } - - // clean up our texture - Texture *t = get_texture(rt->external.texture); - t->alloc_height = 0; - t->alloc_width = 0; - t->width = 0; - t->height = 0; - t->active = false; - texture_free(rt->external.texture); - //memdelete(t); - - rt->external.fbo = 0; - rt->external.color = 0; - rt->external.depth = 0; - } - } else { - Texture *t; - - if (rt->external.fbo == 0) { - // create our fbo - glGenFramebuffers(1, &rt->external.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, rt->external.fbo); - - // allocate a texture - t = memnew(Texture); - - t->type = Texture::TYPE_2D; - t->width = 0; - t->height = 0; - t->alloc_height = 0; - t->alloc_width = 0; - t->format = Image::FORMAT_RGBA8; - t->target = GL_TEXTURE_2D; - t->gl_format_cache = 0; - t->gl_internal_format_cache = 0; - t->gl_type_cache = 0; - t->total_data_size = 0; - t->mipmaps = 1; - t->active = true; - t->tex_id = 0; - t->render_target = rt; - t->is_render_target = true; - - //rt->external.texture = make_rid(t); - - } else { - // bind our frame buffer - glBindFramebuffer(GL_FRAMEBUFFER, rt->external.fbo); - - // find our texture - t = get_texture(rt->external.texture); - } - - // set our texture - t->tex_id = p_texture_id; - rt->external.color = p_texture_id; - - // size shouldn't be different - t->width = rt->size.x; - t->height = rt->size.y; - t->alloc_height = rt->size.x; - t->alloc_width = rt->size.y; - - // Switch our texture on our frame buffer - { - // set our texture as the destination for our framebuffer - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_texture_id, 0); - } - - // check status and unbind - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); - - if (status != GL_FRAMEBUFFER_COMPLETE) { - WARN_PRINT("framebuffer fail, status: " + get_framebuffer_error(status)); - } - - ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE); - } + return rt->texture; } void TextureStorage::render_target_set_transparent(RID p_render_target, bool p_transparent) { @@ -1536,6 +1673,13 @@ void TextureStorage::render_target_set_transparent(RID p_render_target, bool p_t _update_render_target(rt); } +bool TextureStorage::render_target_get_transparent(RID p_render_target) const { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND_V(!rt, false); + + return rt->is_transparent; +} + void TextureStorage::render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND(!rt); @@ -1550,7 +1694,14 @@ void TextureStorage::render_target_set_direct_to_screen(RID p_render_target, boo _update_render_target(rt); } -bool TextureStorage::render_target_was_used(RID p_render_target) { +bool TextureStorage::render_target_get_direct_to_screen(RID p_render_target) const { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND_V(!rt, false); + + return rt->direct_to_screen; +} + +bool TextureStorage::render_target_was_used(RID p_render_target) const { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND_V(!rt, false); @@ -1577,6 +1728,13 @@ void TextureStorage::render_target_set_msaa(RID p_render_target, RS::ViewportMSA _update_render_target(rt); } +RS::ViewportMSAA TextureStorage::render_target_get_msaa(RID p_render_target) const { + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND_V(!rt, RS::VIEWPORT_MSAA_DISABLED); + + return rt->msaa; +} + void TextureStorage::render_target_request_clear(RID p_render_target, const Color &p_clear_color) { RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND(!rt); @@ -1607,9 +1765,11 @@ void TextureStorage::render_target_do_clear_request(RID p_render_target) { if (!rt->clear_requested) { return; } + glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo); glClearBufferfv(GL_COLOR, 0, rt->clear_color.components); rt->clear_requested = false; + glBindFramebuffer(GL_FRAMEBUFFER, system_fbo); } void TextureStorage::render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) { diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h index 4f4032723b..39a74236e5 100644 --- a/drivers/gles3/storage/texture_storage.h +++ b/drivers/gles3/storage/texture_storage.h @@ -126,11 +126,6 @@ struct CanvasTexture { RS::CanvasItemTextureFilter texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT; RS::CanvasItemTextureRepeat texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT; - - Size2i size_cache = Size2i(1, 1); - bool use_normal_cache = false; - bool use_specular_cache = false; - bool cleared_cache = true; }; /* CANVAS SHADOW */ @@ -327,16 +322,6 @@ private: }; struct RenderTarget { - struct External { - GLuint fbo = 0; - GLuint color = 0; - GLuint depth = 0; - RID texture; - - External() { - } - } external; - Point2i position = Point2i(0, 0); Size2i size = Size2i(0, 0); int mipmap_count = 1; @@ -386,6 +371,38 @@ private: Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_force_decompress) const; + /* TEXTURE ATLAS API */ + + struct TextureAtlas { + struct Texture { + int users; + Rect2 uv_rect; + }; + + struct SortItem { + RID texture; + Size2i pixel_size; + Size2i size; + Point2i pos; + + bool operator<(const SortItem &p_item) const { + //sort larger to smaller + if (size.height == p_item.size.height) { + return size.width > p_item.size.width; + } else { + return size.height > p_item.size.height; + } + } + }; + + HashMap<RID, Texture> textures; + bool dirty = true; + + GLuint texture = 0; + GLuint framebuffer = 0; + Size2i size; + } texture_atlas; + /* Render Target API */ mutable RID_Owner<RenderTarget> render_target_owner; @@ -488,6 +505,25 @@ public: void texture_bind(RID p_texture, uint32_t p_texture_no); RID texture_create_radiance_cubemap(RID p_source, int p_resolution = -1) const; + /* TEXTURE ATLAS API */ + + void update_texture_atlas(); + + GLuint texture_atlas_get_texture() const; + _FORCE_INLINE_ Rect2 texture_atlas_get_texture_rect(RID p_texture) { + TextureAtlas::Texture *t = texture_atlas.textures.getptr(p_texture); + if (!t) { + return Rect2(); + } + + return t->uv_rect; + } + + void texture_add_to_texture_atlas(RID p_texture); + void texture_remove_from_texture_atlas(RID p_texture); + void texture_atlas_mark_dirty_on_texture(RID p_texture); + void texture_atlas_remove_texture(RID p_texture); + /* DECAL API */ virtual RID decal_allocate() override; @@ -509,6 +545,12 @@ public: virtual void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {} virtual void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {} + /* DECAL INSTANCE */ + + virtual RID decal_instance_create(RID p_decal) override; + virtual void decal_instance_free(RID p_decal_instance) override; + virtual void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override; + /* RENDER TARGET API */ static GLuint system_fbo; @@ -518,17 +560,19 @@ public: virtual RID render_target_create() override; virtual void render_target_free(RID p_rid) override; + virtual void render_target_set_position(RID p_render_target, int p_x, int p_y) override; + virtual Point2i render_target_get_position(RID p_render_target) const override; virtual void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) override; - Size2i render_target_get_size(RID p_render_target); - virtual RID render_target_get_texture(RID p_render_target) override; - virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) override; - + virtual Size2i render_target_get_size(RID p_render_target) const override; virtual void render_target_set_transparent(RID p_render_target, bool p_is_transparent) override; + virtual bool render_target_get_transparent(RID p_render_target) const override; virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) override; - virtual bool render_target_was_used(RID p_render_target) override; + virtual bool render_target_get_direct_to_screen(RID p_render_target) const override; + virtual bool render_target_was_used(RID p_render_target) const override; void render_target_clear_used(RID p_render_target); virtual void render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) override; + virtual RS::ViewportMSAA render_target_get_msaa(RID p_render_target) const override; // new void render_target_set_as_unused(RID p_render_target) override { @@ -548,8 +592,20 @@ public: void render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps); void render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color); void render_target_gen_back_buffer_mipmaps(RID p_render_target, const Rect2i &p_region); - virtual void render_target_set_vrs_mode(RID p_render_target, RS::ViewportVRSMode p_mode) override{}; - virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override{}; + + virtual void render_target_set_vrs_mode(RID p_render_target, RS::ViewportVRSMode p_mode) override {} + virtual RS::ViewportVRSMode render_target_get_vrs_mode(RID p_render_target) const override { return RS::VIEWPORT_VRS_DISABLED; } + virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override {} + virtual RID render_target_get_vrs_texture(RID p_render_target) const override { return RID(); } + + virtual void render_target_set_override_color(RID p_render_target, RID p_texture) override {} + virtual RID render_target_get_override_color(RID p_render_target) const override { return RID(); } + virtual void render_target_set_override_depth(RID p_render_target, RID p_texture) override {} + virtual RID render_target_get_override_depth(RID p_render_target) const override { return RID(); } + virtual void render_target_set_override_velocity(RID p_render_target, RID p_texture) override {} + virtual RID render_target_get_override_velocity(RID p_render_target) const override { return RID(); } + + virtual RID render_target_get_texture(RID p_render_target) override; void bind_framebuffer(GLuint framebuffer) { glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); diff --git a/drivers/gles3/storage/utilities.cpp b/drivers/gles3/storage/utilities.cpp index 16bacf1829..6e91f38050 100644 --- a/drivers/gles3/storage/utilities.cpp +++ b/drivers/gles3/storage/utilities.cpp @@ -302,6 +302,7 @@ void Utilities::update_dirty_resources() { MaterialStorage::get_singleton()->_update_queued_materials(); //MeshStorage::get_singleton()->_update_dirty_skeletons(); MeshStorage::get_singleton()->_update_dirty_multimeshes(); + TextureStorage::get_singleton()->update_texture_atlas(); } void Utilities::set_debug_generate_wireframes(bool p_generate) { |