From eb07056e707d56599f3443e5b59fcd92ffd79e95 Mon Sep 17 00:00:00 2001 From: clayjohn Date: Tue, 1 Nov 2022 13:40:23 -0700 Subject: Add texture reading code to OpenGL3 renderer for web and mobile This allows using texture_2d_get on all platforms which is needed for the get_image function This commit also fixes some OpenGL warnings on the Web platform that came from attempting to map a buffer with zero length --- drivers/gles3/rasterizer_canvas_gles3.cpp | 7 ++++ drivers/gles3/storage/mesh_storage.cpp | 4 +- drivers/gles3/storage/texture_storage.cpp | 62 ++++++++++++++++++++++++++++++- drivers/gles3/storage/utilities.cpp | 5 +++ 4 files changed, 74 insertions(+), 4 deletions(-) (limited to 'drivers/gles3') diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 5d0edda6c5..aa96703d80 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -587,6 +587,13 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou _record_item_commands(ci, p_canvas_transform_inverse, current_clip, blend_mode, p_lights, index, batch_broken); } + if (r_last_index >= index) { + // Nothing to render, just return. + state.current_batch_index = 0; + state.canvas_instance_batches.clear(); + return; + } + // Copy over all data needed for rendering. glBindBuffer(GL_UNIFORM_BUFFER, state.canvas_instance_data_buffers[state.current_buffer].ubo); #ifdef WEB_ENABLED diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp index 11ce31856d..9ec0fc0286 100644 --- a/drivers/gles3/storage/mesh_storage.cpp +++ b/drivers/gles3/storage/mesh_storage.cpp @@ -1004,7 +1004,7 @@ void MeshStorage::multimesh_set_mesh(RID p_multimesh, RID p_mesh) { #define MULTIMESH_DIRTY_REGION_SIZE 512 void MeshStorage::_multimesh_make_local(MultiMesh *multimesh) const { - if (multimesh->data_cache.size() > 0) { + if (multimesh->data_cache.size() > 0 || multimesh->instances == 0) { return; //already local } ERR_FAIL_COND(multimesh->data_cache.size() > 0); @@ -1421,7 +1421,7 @@ Vector MeshStorage::multimesh_get_buffer(RID p_multimesh) const { MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); ERR_FAIL_COND_V(!multimesh, Vector()); Vector ret; - if (multimesh->buffer == 0) { + if (multimesh->buffer == 0 || multimesh->instances == 0) { return Vector(); } else if (multimesh->data_cache.size()) { ret = multimesh->data_cache; diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp index 524ff14cc9..076225adf4 100644 --- a/drivers/gles3/storage/texture_storage.cpp +++ b/drivers/gles3/storage/texture_storage.cpp @@ -790,6 +790,7 @@ Ref TextureStorage::texture_2d_get(RID p_texture) const { #ifdef GLES_OVER_GL // OpenGL 3.3 supports glGetTexImage which is faster and simpler than glReadPixels. + // It also allows for reading compressed textures, mipmaps, and more formats. Vector data; int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, texture->real_format, texture->mipmaps > 1); @@ -826,8 +827,65 @@ Ref TextureStorage::texture_2d_get(RID p_texture) const { image->convert(texture->format); } #else - // Support for Web and Mobile will come later. - Ref image; + + Vector data; + + // On web and mobile we always read an RGBA8 image with no mipmaps. + int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, Image::FORMAT_RGBA8, false); + + data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers + uint8_t *w = data.ptrw(); + + GLuint temp_framebuffer; + glGenFramebuffers(1, &temp_framebuffer); + + GLuint temp_color_texture; + glGenTextures(1, &temp_color_texture); + + glBindFramebuffer(GL_FRAMEBUFFER, temp_framebuffer); + + glBindTexture(GL_TEXTURE_2D, temp_color_texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, temp_color_texture, 0); + + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_BLEND); + glDepthFunc(GL_LEQUAL); + glColorMask(1, 1, 1, 1); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture->tex_id); + + glViewport(0, 0, texture->alloc_width, texture->alloc_height); + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT); + + CopyEffects::get_singleton()->copy_to_rect(Rect2i(0, 0, 1.0, 1.0)); + + glReadPixels(0, 0, texture->alloc_width, texture->alloc_height, GL_RGBA, GL_UNSIGNED_BYTE, &w[0]); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDeleteTextures(1, &temp_color_texture); + glDeleteFramebuffers(1, &temp_framebuffer); + + data.resize(data_size); + + ERR_FAIL_COND_V(data.size() == 0, Ref()); + Ref image = Image::create_from_data(texture->width, texture->height, false, Image::FORMAT_RGBA8, data); + ERR_FAIL_COND_V(image->is_empty(), Ref()); + + if (texture->format != Image::FORMAT_RGBA8) { + image->convert(texture->format); + } + + if (texture->mipmaps > 1) { + image->generate_mipmaps(); + } + #endif #ifdef TOOLS_ENABLED diff --git a/drivers/gles3/storage/utilities.cpp b/drivers/gles3/storage/utilities.cpp index a2d1ba376a..7b70ed74be 100644 --- a/drivers/gles3/storage/utilities.cpp +++ b/drivers/gles3/storage/utilities.cpp @@ -71,6 +71,11 @@ Utilities::~Utilities() { Vector Utilities::buffer_get_data(GLenum p_target, GLuint p_buffer, uint32_t p_buffer_size) { Vector ret; + + if (p_buffer_size == 0) { + return ret; + } + ret.resize(p_buffer_size); glBindBuffer(p_target, p_buffer); -- cgit v1.2.3