Reworked Texture.

This commit is contained in:
Relintai 2023-12-31 02:10:01 +01:00
parent fe18833bc6
commit 885c07d2c3
5 changed files with 121 additions and 255 deletions

View File

@ -355,174 +355,11 @@ Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_
} }
*/ */
/* void Texture::texture_update() {
void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer) {
Texture *texture = texture_owner.getornull(p_texture);
ERR_FAIL_COND(!texture);
if (texture->target == GL_TEXTURE_3D) {
// Target is set to a 3D texture or array texture, exit early to avoid spamming errors
return;
}
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(texture->type == RS::TEXTURE_TYPE_EXTERNAL);
GLenum type;
GLenum format;
GLenum internal_format;
bool compressed = false;
if (config.keep_original_textures && !(texture->flags & RS::TEXTURE_FLAG_USED_FOR_STREAMING)) {
texture->images.write[p_layer] = p_image;
}
Image::Format real_format;
Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, real_format, format, internal_format, type, compressed, texture->resize_to_po2);
if (texture->resize_to_po2) {
if (p_image->is_compressed()) {
ERR_PRINT("Texture '" + texture->path + "' is required to be a power of 2 because it uses either mipmaps or repeat, so it was decompressed. This will hurt performance and memory usage.");
}
if (img == p_image) {
img = img->duplicate();
}
img->resize_to_po2(false, texture->flags & RS::TEXTURE_FLAG_FILTER ? Image::INTERPOLATE_BILINEAR : Image::INTERPOLATE_NEAREST);
}
if (config.shrink_textures_x2 && (p_image->has_mipmaps() || !p_image->is_compressed()) && !(texture->flags & RS::TEXTURE_FLAG_USED_FOR_STREAMING)) {
texture->alloc_height = MAX(1, texture->alloc_height / 2);
texture->alloc_width = MAX(1, texture->alloc_width / 2);
if (texture->alloc_width == img->get_width() / 2 && texture->alloc_height == img->get_height() / 2) {
img->shrink_x2();
} else if (img->get_format() <= Image::FORMAT_RGBA8) {
img->resize(texture->alloc_width, texture->alloc_height, Image::INTERPOLATE_BILINEAR);
}
}
GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_layer] : GL_TEXTURE_2D;
texture->data_size = img->get_data().size();
PoolVector<uint8_t>::Read read = img->get_data().read();
ERR_FAIL_COND(!read.ptr());
gl_wrapper.gl_active_texture(GL_TEXTURE0);
glBindTexture(texture->target, texture->tex_id);
texture->ignore_mipmaps = compressed && !img->has_mipmaps();
if ((texture->flags & RS::TEXTURE_FLAG_MIPMAPS) && !texture->ignore_mipmaps) {
if (texture->flags & RS::TEXTURE_FLAG_FILTER) {
glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, config.use_fast_texture_filter ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR_MIPMAP_LINEAR);
} else {
glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, config.use_fast_texture_filter ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST_MIPMAP_LINEAR);
}
} else {
if (texture->flags & RS::TEXTURE_FLAG_FILTER) {
glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
} else {
glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
}
if (texture->flags & RS::TEXTURE_FLAG_FILTER) {
glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Linear Filtering
} else {
glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // raw Filtering
}
if (((texture->flags & RS::TEXTURE_FLAG_REPEAT) || (texture->flags & RS::TEXTURE_FLAG_MIRRORED_REPEAT)) && texture->target != GL_TEXTURE_CUBE_MAP) {
if (texture->flags & RS::TEXTURE_FLAG_MIRRORED_REPEAT) {
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
} else {
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
}
} else {
//glTexParameterf( texture->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE );
glTexParameterf(texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
if (config.use_anisotropic_filter) {
if (texture->flags & RS::TEXTURE_FLAG_ANISOTROPIC_FILTER) {
glTexParameterf(texture->target, _GL_TEXTURE_MAX_ANISOTROPY_EXT, config.anisotropic_level);
} else {
glTexParameterf(texture->target, _GL_TEXTURE_MAX_ANISOTROPY_EXT, 1);
}
}
int mipmaps = ((texture->flags & RS::TEXTURE_FLAG_MIPMAPS) && img->has_mipmaps()) ? img->get_mipmap_count() + 1 : 1;
int w = img->get_width();
int h = img->get_height();
int tsize = 0;
for (int i = 0; i < mipmaps; i++) {
int size, ofs;
img->get_mipmap_offset_and_size(i, ofs, size);
if (compressed) {
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
int bw = w;
int bh = h;
glCompressedTexImage2D(blit_target, i, internal_format, bw, bh, 0, size, &read[ofs]);
} else {
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
if (texture->flags & RS::TEXTURE_FLAG_USED_FOR_STREAMING) {
glTexSubImage2D(blit_target, i, 0, 0, w, h, format, type, &read[ofs]);
} else {
glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]);
}
}
tsize += size;
w = MAX(1, w >> 1);
h = MAX(1, h >> 1);
}
info.texture_mem -= texture->total_data_size;
texture->total_data_size = tsize;
info.texture_mem += texture->total_data_size;
// printf("texture: %i x %i - size: %i - total: %i\n", texture->width, texture->height, tsize, info.texture_mem);
texture->stored_cube_sides |= (1 << p_layer);
if ((texture->flags & RS::TEXTURE_FLAG_MIPMAPS) && mipmaps == 1 && !texture->ignore_mipmaps && (texture->type != RS::TEXTURE_TYPE_CUBEMAP || texture->stored_cube_sides == (1 << 6) - 1)) {
//generate mipmaps if they were requested and the image does not contain them
glGenerateMipmap(texture->target);
}
texture->mipmaps = mipmaps;
}
*/
void Texture::texture_update(int flags) {
if (!_image.is_valid()) { if (!_image.is_valid()) {
return; return;
} }
//if (t && !t->id) {
// glGenTextures(1, &t->id);
// return texture_update(t, w, h, n, pixels, flags);
//}
//ASSERT(t && t->id);
//ASSERT(n <= 4);
//GLuint pixel_types[] = { GL_RED, GL_RED, GL_RG, GL_RGB, GL_RGBA, GL_R32F, GL_R32F, GL_RG32F, GL_RGB32F, GL_RGBA32F }; //GLuint pixel_types[] = { GL_RED, GL_RED, GL_RG, GL_RGB, GL_RGBA, GL_R32F, GL_R32F, GL_RG32F, GL_RGB32F, GL_RGBA32F };
//GLenum pixel_storage = flags & TEXTURE_FLOAT ? GL_FLOAT : GL_UNSIGNED_BYTE; //GLenum pixel_storage = flags & TEXTURE_FLOAT ? GL_FLOAT : GL_UNSIGNED_BYTE;
GLenum pixel_storage = GL_UNSIGNED_BYTE; GLenum pixel_storage = GL_UNSIGNED_BYTE;
@ -531,10 +368,6 @@ void Texture::texture_update(int flags) {
//GLuint texel_type = t->texel_type = pixel_types[n + 5 * !!(flags & TEXTURE_FLOAT)]; //GLuint texel_type = t->texel_type = pixel_types[n + 5 * !!(flags & TEXTURE_FLOAT)];
GLuint texel_type = GL_RGBA; GLuint texel_type = GL_RGBA;
GLenum wrap = GL_CLAMP_TO_EDGE;
GLenum min_filter = GL_NEAREST, mag_filter = GL_NEAREST;
// GLfloat color = (flags&7)/7.f, border_color[4] = { color, color, color, 1.f };
/* /*
if (flags & TEXTURE_BGR) if (flags & TEXTURE_BGR)
if (pixel_type == GL_RGB) if (pixel_type == GL_RGB)
@ -571,99 +404,127 @@ void Texture::texture_update(int flags) {
mag_filter = flags & TEXTURE_LINEAR ? GL_LINEAR : GL_NEAREST; mag_filter = flags & TEXTURE_LINEAR ? GL_LINEAR : GL_NEAREST;
*/ */
//GLenum texture_type = t->flags & TEXTURE_ARRAY ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D; // @fixme: test GL_TEXTURE_2D_ARRAY _data_size = _image->get_data().size();
GLenum texture_type = GL_TEXTURE_2D; // @fixme: test GL_TEXTURE_2D_ARRAY Vector<uint8_t> image_data = _image->get_data();
//glPixelStorei( GL_UNPACK_ALIGNMENT, n < 4 ? 1 : 4 ); // for framebuffer reading if (image_data.size() == 0) {
//glActiveTexture(GL_TEXTURE0 + (flags&7));
glBindTexture(texture_type, texture);
//glTexImage2D(texture_type, 0, texel_type, w, h, 0, pixel_type, pixel_storage, pixels);
glTexParameteri(texture_type, GL_TEXTURE_WRAP_S, wrap);
glTexParameteri(texture_type, GL_TEXTURE_WRAP_T, wrap);
glTexParameteri(texture_type, GL_TEXTURE_MIN_FILTER, min_filter);
glTexParameteri(texture_type, GL_TEXTURE_MAG_FILTER, mag_filter);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(texture_type, 0, texel_type, _image_width, _image_height, 0, pixel_type, pixel_storage, _image_data.ptr());
// if( flags & TEXTURE_BORDER ) glTexParameterfv(texture_type, GL_TEXTURE_BORDER_COLOR, border_color);
/*
if (flags & TEXTURE_MIPMAPS)
glGenerateMipmap(texture_type);
if (flags & TEXTURE_MIPMAPS) {
GLfloat max_aniso = 0;
// glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &max_aniso);
max_aniso = 4;
// glTexParameterf(texture_type, GL_TEXTURE_MAX_ANISOTROPY, max_aniso);
}
*/
// glBindTexture(texture_type, 0); // do not unbind. current code expects texture to be bound at function exit
/*
t->w = w;
t->h = h;
t->n = n;
t->flags = flags;
t->filename = t->filename ? t->filename : "";
*/
}
void Texture::apply_filter() {
if (!texture) {
return; return;
} }
GLint params = GL_NEAREST; if (!_texture) {
glGenTextures(1, &_texture);
if (filter == TEXTURE_FILTER_LINEAR) {
params = GL_LINEAR;
} }
glBindTexture(GL_TEXTURE_2D, texture); const uint8_t *read = image_data.ptr();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, params); ERR_FAIL_COND(!read);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, params);
glActiveTexture(GL_TEXTURE0 + _texture_index);
if ((_flags | TEXTURE_FLAG_MIP_MAPS)) {
if ((_flags | TEXTURE_FLAG_FILTER)) {
glTexParameteri(_texture, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
} else {
glTexParameteri(_texture, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
}
} else {
if ((_flags | TEXTURE_FLAG_FILTER)) {
glTexParameteri(_texture, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
} else {
glTexParameteri(_texture, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
}
if ((_flags | TEXTURE_FLAG_FILTER)) {
glTexParameteri(_texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Linear Filtering
} else {
glTexParameteri(_texture, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // raw Filtering
}
if ((_flags & TEXTURE_FLAG_REPEAT) || (_flags & TEXTURE_FLAG_MIRRORED_REPEAT)) {
if (_flags & TEXTURE_FLAG_MIRRORED_REPEAT) {
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
} else {
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
}
} else {
glTexParameterf(_texture, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(_texture, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
GLenum texture_type = GL_TEXTURE_2D;
glBindTexture(texture_type, _texture);
int mipmaps = ((_flags | TEXTURE_FLAG_MIP_MAPS) && _image->has_mipmaps()) ? _image->get_mipmap_count() + 1 : 1;
_texture_width = _image->get_width();
_texture_height = _image->get_height();
int w = _texture_width;
int h = _texture_height;
int tsize = 0;
for (int i = 0; i < mipmaps; i++) {
int size;
int ofs;
_image->get_mipmap_offset_and_size(i, ofs, size);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(texture_type, i, texel_type, w, h, 0, pixel_type, pixel_storage, &read[ofs]);
tsize += size;
w = MAX(1, w >> 1);
h = MAX(1, h >> 1);
}
if ((_flags | TEXTURE_FLAG_MIP_MAPS) && mipmaps == 1) {
//generate mipmaps if they were requested and the image does not contain them
glGenerateMipmap(texture_type);
}
_mipmaps = mipmaps;
glBindTexture(texture_type, 0);
} }
void Texture::set_image(const Ref<Image> &img) { void Texture::set_image(const Ref<Image> &img) {
if (_image == img) {
return;
}
_image = img; _image = img;
if (texture) { _texture_width = 0;
glDeleteTextures(1, &texture); _texture_height = 0;
}
if (!_image.is_valid()) { if (!_image.is_valid()) {
if (_texture) {
glDeleteTextures(1, &_texture);
_texture = 0;
}
return; return;
} }
_image_data = _image->get_data(); texture_update();
_image_format = _image->get_format();
_image_width = _image->get_width();
_image_height = _image->get_height();
_image_mip_maps = _image->has_mipmaps();
if (_image_data.size() == 0) {
return;
}
glGenTextures(1, &texture);
texture_update(0);
} }
Texture::Texture() { Texture::Texture() {
filter = TEXTURE_FILTER_NEAREST; _texture = 0;
texture = 0; _texture_width = 0;
_image_width = 0; _texture_height = 0;
_image_height = 0; _mipmaps = 1;
_image_format = Image::FORMAT_RGBA8; _data_size = 0;
_image_mip_maps = false; _texture_index = 0;
_flags = 0;
} }
Texture::~Texture() { Texture::~Texture() {
if (texture) { if (_texture) {
glDeleteTextures(1, &texture); glDeleteTextures(1, &_texture);
} }
} }

View File

@ -6,16 +6,18 @@
class Texture { class Texture {
public: public:
enum TextureFilter { enum TextureFlags {
TEXTURE_FILTER_NEAREST = 0, TEXTURE_FLAG_FILTER = 1 << 0,
TEXTURE_FILTER_LINEAR, TEXTURE_FLAG_REPEAT = 1 << 1,
TEXTURE_FLAG_MIRRORED_REPEAT = 1 << 2,
TEXTURE_FLAG_MIP_MAPS = 1 << 3,
}; };
TextureFilter filter; _FORCE_INLINE_ GLuint get_gl_texture() {
GLuint texture; return _texture;
}
void apply_filter(); void texture_update();
void texture_update(int flags);
void set_image(const Ref<Image> &img); void set_image(const Ref<Image> &img);
@ -23,12 +25,15 @@ public:
virtual ~Texture(); virtual ~Texture();
protected: protected:
int _image_width; int _texture_width;
int _image_height; int _texture_height;
Ref<Image> _image; Ref<Image> _image;
Vector<uint8_t> _image_data;
Image::Format _image_format; int _flags;
bool _image_mip_maps; int _texture_index;
int _data_size;
int _mipmaps;
GLuint _texture;
}; };
#endif // TEXTURE_H #endif // TEXTURE_H

View File

@ -19,7 +19,7 @@ public:
if (texture) { if (texture) {
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture->texture); glBindTexture(GL_TEXTURE_2D, texture->get_gl_texture());
glUniform1i(texture_location, 0); glUniform1i(texture_location, 0);
} }
} }

View File

@ -18,7 +18,7 @@ public:
if (texture) { if (texture) {
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture->texture); glBindTexture(GL_TEXTURE_2D, texture->get_gl_texture());
glUniform1i(texture_location, 0); glUniform1i(texture_location, 0);
} }
} }

View File

@ -21,7 +21,7 @@ public:
if (texture) { if (texture) {
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture->texture); glBindTexture(GL_TEXTURE_2D, texture->get_gl_texture());
glUniform1i(texture_location, 0); glUniform1i(texture_location, 0);
} }
} }