Browse Source

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
clayjohn 2 years ago
parent
commit
eb07056e70

+ 7 - 0
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);
 		_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.
 	// Copy over all data needed for rendering.
 	glBindBuffer(GL_UNIFORM_BUFFER, state.canvas_instance_data_buffers[state.current_buffer].ubo);
 	glBindBuffer(GL_UNIFORM_BUFFER, state.canvas_instance_data_buffers[state.current_buffer].ubo);
 #ifdef WEB_ENABLED
 #ifdef WEB_ENABLED

+ 2 - 2
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
 #define MULTIMESH_DIRTY_REGION_SIZE 512
 
 
 void MeshStorage::_multimesh_make_local(MultiMesh *multimesh) const {
 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
 		return; //already local
 	}
 	}
 	ERR_FAIL_COND(multimesh->data_cache.size() > 0);
 	ERR_FAIL_COND(multimesh->data_cache.size() > 0);
@@ -1421,7 +1421,7 @@ Vector<float> MeshStorage::multimesh_get_buffer(RID p_multimesh) const {
 	MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
 	MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
 	ERR_FAIL_COND_V(!multimesh, Vector<float>());
 	ERR_FAIL_COND_V(!multimesh, Vector<float>());
 	Vector<float> ret;
 	Vector<float> ret;
-	if (multimesh->buffer == 0) {
+	if (multimesh->buffer == 0 || multimesh->instances == 0) {
 		return Vector<float>();
 		return Vector<float>();
 	} else if (multimesh->data_cache.size()) {
 	} else if (multimesh->data_cache.size()) {
 		ret = multimesh->data_cache;
 		ret = multimesh->data_cache;

+ 60 - 2
drivers/gles3/storage/texture_storage.cpp

@@ -790,6 +790,7 @@ Ref<Image> TextureStorage::texture_2d_get(RID p_texture) const {
 
 
 #ifdef GLES_OVER_GL
 #ifdef GLES_OVER_GL
 	// OpenGL 3.3 supports glGetTexImage which is faster and simpler than glReadPixels.
 	// OpenGL 3.3 supports glGetTexImage which is faster and simpler than glReadPixels.
+	// It also allows for reading compressed textures, mipmaps, and more formats.
 	Vector<uint8_t> data;
 	Vector<uint8_t> data;
 
 
 	int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, texture->real_format, texture->mipmaps > 1);
 	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<Image> TextureStorage::texture_2d_get(RID p_texture) const {
 		image->convert(texture->format);
 		image->convert(texture->format);
 	}
 	}
 #else
 #else
-	// Support for Web and Mobile will come later.
-	Ref<Image> image;
+
+	Vector<uint8_t> 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<Image>());
+	Ref<Image> image = Image::create_from_data(texture->width, texture->height, false, Image::FORMAT_RGBA8, data);
+	ERR_FAIL_COND_V(image->is_empty(), Ref<Image>());
+
+	if (texture->format != Image::FORMAT_RGBA8) {
+		image->convert(texture->format);
+	}
+
+	if (texture->mipmaps > 1) {
+		image->generate_mipmaps();
+	}
+
 #endif
 #endif
 
 
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED

+ 5 - 0
drivers/gles3/storage/utilities.cpp

@@ -71,6 +71,11 @@ Utilities::~Utilities() {
 
 
 Vector<uint8_t> Utilities::buffer_get_data(GLenum p_target, GLuint p_buffer, uint32_t p_buffer_size) {
 Vector<uint8_t> Utilities::buffer_get_data(GLenum p_target, GLuint p_buffer, uint32_t p_buffer_size) {
 	Vector<uint8_t> ret;
 	Vector<uint8_t> ret;
+
+	if (p_buffer_size == 0) {
+		return ret;
+	}
+
 	ret.resize(p_buffer_size);
 	ret.resize(p_buffer_size);
 	glBindBuffer(p_target, p_buffer);
 	glBindBuffer(p_target, p_buffer);