From c755cced832a8e574c79f5fbd8e8e53f0ca62087 Mon Sep 17 00:00:00 2001 From: Marc Gilleron Date: Sun, 29 Apr 2018 01:23:55 +0200 Subject: [PATCH] Added partial texture update to VisualServer --- drivers/gles2/rasterizer_storage_gles2.cpp | 5 +++ drivers/gles2/rasterizer_storage_gles2.h | 1 + drivers/gles3/rasterizer_storage_gles3.cpp | 52 ++++++++++++++++++++++ drivers/gles3/rasterizer_storage_gles3.h | 1 + servers/visual/rasterizer.h | 1 + servers/visual/visual_server_raster.h | 1 + servers/visual/visual_server_wrap_mt.h | 1 + servers/visual_server.cpp | 1 + servers/visual_server.h | 1 + 9 files changed, 64 insertions(+) diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index 5bca3ee548f..271d4ef8c02 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -452,6 +452,11 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref &p texture->mipmaps = mipmaps; } +void RasterizerStorageGLES2::texture_set_data_partial(RID p_texture, const Ref &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, VS::CubeMapSide p_cube_side) { + // TODO + ERR_PRINT("Not implemented (ask Karroffel to do it :p)"); +} + Ref RasterizerStorageGLES2::texture_get_data(RID p_texture, VS::CubeMapSide p_cube_side) const { Texture *texture = texture_owner.getornull(p_texture); diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h index 9f8d8d100bd..60600b57154 100644 --- a/drivers/gles2/rasterizer_storage_gles2.h +++ b/drivers/gles2/rasterizer_storage_gles2.h @@ -237,6 +237,7 @@ public: virtual RID texture_create(); virtual void texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT); virtual void texture_set_data(RID p_texture, const Ref &p_image, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT); + virtual void texture_set_data_partial(RID p_texture, const Ref &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT); virtual Ref texture_get_data(RID p_texture, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) const; virtual void texture_set_flags(RID p_texture, uint32_t p_flags); virtual uint32_t texture_get_flags(RID p_texture) const; diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index f91ed35331a..a8380b55183 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -828,6 +828,58 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref &p //texture_set_flags(p_texture,texture->flags); } +// Uploads pixel data to a sub-region of a texture, for the specified mipmap. +// The texture pixels must have been allocated before, because most features seen in texture_set_data() make no sense in a partial update. +// TODO If we want this to be usable without pre-filling pixels with a full image, we have to call glTexImage2D() with null data. +void RasterizerStorageGLES3::texture_set_data_partial(RID p_texture, const Ref &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, VS::CubeMapSide p_cube_side) { + + Texture *texture = texture_owner.get(p_texture); + + ERR_FAIL_COND(!texture); + ERR_FAIL_COND(!texture->active); + ERR_FAIL_COND(texture->render_target); + ERR_FAIL_COND(texture->format != p_image->get_format()); + ERR_FAIL_COND(p_image.is_null()); + ERR_FAIL_COND(src_w <= 0 || src_h <= 0); + ERR_FAIL_COND(src_x < 0 || src_y < 0 || src_x + src_w > p_image->get_width() || src_y + src_h > p_image->get_height()); + ERR_FAIL_COND(dst_x < 0 || dst_y < 0 || dst_x + src_w > texture->alloc_width || dst_y + src_h > texture->alloc_height); + ERR_FAIL_COND(p_dst_mip < 0 || p_dst_mip >= texture->mipmaps); + + GLenum type; + GLenum format; + GLenum internal_format; + bool compressed; + bool srgb; + + // Because OpenGL wants data as a dense array, we have to extract the sub-image if the source rect isn't the full image + Ref p_sub_img = p_image; + if (src_x > 0 || src_y > 0 || src_w != p_image->get_width() || src_h != p_image->get_height()) { + p_sub_img = p_image->get_rect(Rect2(src_x, src_y, src_w, src_h)); + } + + Ref img = _get_gl_image_and_format(p_sub_img, p_sub_img->get_format(), texture->flags, format, internal_format, type, compressed, srgb); + + GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_cube_side] : GL_TEXTURE_2D; + + PoolVector::Read read = img->get_data().read(); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(texture->target, texture->tex_id); + + int src_data_size = img->get_data().size(); + int src_ofs = 0; + + if (texture->compressed) { + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glCompressedTexSubImage2D(blit_target, p_dst_mip, dst_x, dst_y, src_w, src_h, internal_format, src_data_size, &read[src_ofs]); + + } else { + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + // `format` has to match the internal_format used when the texture was created + glTexSubImage2D(blit_target, p_dst_mip, dst_x, dst_y, src_w, src_h, format, type, &read[src_ofs]); + } +} + Ref RasterizerStorageGLES3::texture_get_data(RID p_texture, VS::CubeMapSide p_cube_side) const { Texture *texture = texture_owner.get(p_texture); diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index ef2b2472660..d96b5a3ca6f 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -340,6 +340,7 @@ public: virtual RID texture_create(); virtual void texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT); virtual void texture_set_data(RID p_texture, const Ref &p_image, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT); + virtual void texture_set_data_partial(RID p_texture, const Ref &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT); virtual Ref texture_get_data(RID p_texture, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) const; virtual void texture_set_flags(RID p_texture, uint32_t p_flags); virtual uint32_t texture_get_flags(RID p_texture) const; diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 8bf112b0de0..9b67566f604 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -175,6 +175,7 @@ public: virtual RID texture_create() = 0; virtual void texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT) = 0; virtual void texture_set_data(RID p_texture, const Ref &p_image, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) = 0; + virtual void texture_set_data_partial(RID p_texture, const Ref &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) = 0; virtual Ref texture_get_data(RID p_texture, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) const = 0; virtual void texture_set_flags(RID p_texture, uint32_t p_flags) = 0; virtual uint32_t texture_get_flags(RID p_texture) const = 0; diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index a94e110b5d5..5f28a82eb8b 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -148,6 +148,7 @@ public: BIND0R(RID, texture_create) BIND5(texture_allocate, RID, int, int, Image::Format, uint32_t) BIND3(texture_set_data, RID, const Ref &, CubeMapSide) + BIND10(texture_set_data_partial, RID, const Ref &, int, int, int, int, int, int, int, CubeMapSide) BIND2RC(Ref, texture_get_data, RID, CubeMapSide) BIND2(texture_set_flags, RID, uint32_t) BIND1RC(uint32_t, texture_get_flags, RID) diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index b91f80d137b..b61cdb2809b 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -84,6 +84,7 @@ public: FUNCRID(texture) FUNC5(texture_allocate, RID, int, int, Image::Format, uint32_t) FUNC3(texture_set_data, RID, const Ref &, CubeMapSide) + FUNC10(texture_set_data_partial, RID, const Ref &, int, int, int, int, int, int, int, CubeMapSide) FUNC2RC(Ref, texture_get_data, RID, CubeMapSide) FUNC2(texture_set_flags, RID, uint32_t) FUNC1RC(uint32_t, texture_get_flags, RID) diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index f8640720cbb..67428f01299 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -1528,6 +1528,7 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("texture_create_from_image", "image", "flags"), &VisualServer::texture_create_from_image, DEFVAL(TEXTURE_FLAGS_DEFAULT)); ClassDB::bind_method(D_METHOD("texture_allocate", "texture", "width", "height", "format", "flags"), &VisualServer::texture_allocate, DEFVAL(TEXTURE_FLAGS_DEFAULT)); ClassDB::bind_method(D_METHOD("texture_set_data", "texture", "image", "cube_side"), &VisualServer::texture_set_data, DEFVAL(CUBEMAP_LEFT)); + ClassDB::bind_method(D_METHOD("texture_set_data_partial", "texture", "image", "src_x", "src_y", "src_w", "src_h", "dst_x", "dst_y", "dst_mip", "cube_side"), &VisualServer::texture_set_data_partial, DEFVAL(CUBEMAP_LEFT)); ClassDB::bind_method(D_METHOD("texture_get_data", "texture", "cube_side"), &VisualServer::texture_get_data, DEFVAL(CUBEMAP_LEFT)); ClassDB::bind_method(D_METHOD("texture_set_flags", "texture", "flags"), &VisualServer::texture_set_flags); ClassDB::bind_method(D_METHOD("texture_get_flags", "texture"), &VisualServer::texture_get_flags); diff --git a/servers/visual_server.h b/servers/visual_server.h index 537588fd6f8..1328483fa21 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -109,6 +109,7 @@ public: RID texture_create_from_image(const Ref &p_image, uint32_t p_flags = TEXTURE_FLAGS_DEFAULT); // helper virtual void texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags = TEXTURE_FLAGS_DEFAULT) = 0; virtual void texture_set_data(RID p_texture, const Ref &p_image, CubeMapSide p_cube_side = CUBEMAP_LEFT) = 0; + virtual void texture_set_data_partial(RID p_texture, const Ref &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, CubeMapSide p_cube_side = CUBEMAP_LEFT) = 0; virtual Ref texture_get_data(RID p_texture, CubeMapSide p_cube_side = CUBEMAP_LEFT) const = 0; virtual void texture_set_flags(RID p_texture, uint32_t p_flags) = 0; virtual uint32_t texture_get_flags(RID p_texture) const = 0;