From 7e9e15a12fb398798f2719545cc8553354c1e389 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sun, 4 Jul 2010 11:28:36 +0000 Subject: [PATCH] Get rid of the generic Texture::parameter method Add distinct methods for setting texture attributes Don't bind textures for setting attributes, cache the changes instead Restore previous binding after uploading texture images Some improvements for choosing texture unit --- source/bloom.cpp | 7 +-- source/shadowmap.cpp | 12 ++-- source/texture.cpp | 141 ++++++++++++++++++++++++++++++++++--------- source/texture.h | 67 +++++++++++++++----- source/texture2d.cpp | 13 ++-- source/texture3d.cpp | 14 +++-- source/texunit.cpp | 31 +++++++--- source/texunit.h | 15 +++-- 8 files changed, 215 insertions(+), 85 deletions(-) diff --git a/source/bloom.cpp b/source/bloom.cpp index 5f2adc85..3993c8c9 100644 --- a/source/bloom.cpp +++ b/source/bloom.cpp @@ -75,9 +75,9 @@ Bloom::Bloom(unsigned w, unsigned h): for(unsigned i=0; i<2; ++i) { blur_shdata[i].uniform(loc, 0); + tex[i].set_min_filter(NEAREST); tex[i].storage(RGB16F, w, h, 0); tex[i].image(0, RGB, UNSIGNED_BYTE, 0); - tex[i].set_min_filter(NEAREST); } combine_shdata.uniform(combine_shader.get_uniform_location("source"), 1); @@ -153,9 +153,8 @@ void Bloom::render(const Texture2D &src) src.bind_to(1); quad.draw(); Program::unbind(); - Texture::unbind(); - TexUnit::activate(0); - Texture::unbind(); + Texture::unbind_from(1); + Texture::unbind_from(0); // XXX Should check if the modes were enabled in the first place enable(DEPTH_TEST); enable(BLEND); diff --git a/source/shadowmap.cpp b/source/shadowmap.cpp index 7a761e7a..25b0d6d6 100644 --- a/source/shadowmap.cpp +++ b/source/shadowmap.cpp @@ -28,17 +28,14 @@ ShadowMap::ShadowMap(unsigned s, const Scene &c, const Light &l): radius(1) { depth_buf.set_min_filter(LINEAR); + depth_buf.set_compare_enabled(true); + depth_buf.set_compare_func(LEQUAL); + depth_buf.set_wrap(CLAMP_TO_EDGE); depth_buf.storage(DEPTH_COMPONENT, size, size, 0); depth_buf.image(0, DEPTH_COMPONENT, UNSIGNED_BYTE, 0); - depth_buf.parameter(GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE); - depth_buf.parameter(GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); - depth_buf.parameter(GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); - depth_buf.parameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - depth_buf.parameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); fbo.attach(DEPTH_ATTACHMENT, depth_buf, 0); draw_buffer(NO_BUFFER); Framebuffer::unbind(); - Texture::unbind(); } void ShadowMap::set_target(const Vector3 &t, float r) @@ -146,8 +143,7 @@ void ShadowMap::prepare() void ShadowMap::cleanup() { - TexUnit::activate(unit); - Texture::unbind(); + Texture::unbind_from(unit); disable(GL_TEXTURE_GEN_S); disable(GL_TEXTURE_GEN_T); disable(GL_TEXTURE_GEN_R); diff --git a/source/texture.cpp b/source/texture.cpp index 40f18d45..eca03347 100644 --- a/source/texture.cpp +++ b/source/texture.cpp @@ -38,10 +38,110 @@ istream &operator>>(istream &in, TextureFilter &tf) } +Texture::Texture(GLenum t): + target(t), + min_filter(NEAREST_MIPMAP_LINEAR), + mag_filter(LINEAR), + wrap_s(REPEAT), + wrap_t(REPEAT), + wrap_r(REPEAT), + gen_mipmap(false), + compare(false), + cmp_func(LEQUAL), + dirty_params(0) +{ + glGenTextures(1, &id); +} + +Texture::~Texture() +{ + glDeleteTextures(1, &id); +} + +void Texture::update_parameter(int mask) const +{ + if(TexUnit::current().get_texture()==this) + { + if(mask&MIN_FILTER) + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, min_filter); + if(mask&MAG_FILTER) + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, mag_filter); + if(mask&WRAP_S) + glTexParameteri(target, GL_TEXTURE_WRAP_S, wrap_s); + if(mask&WRAP_T) + glTexParameteri(target, GL_TEXTURE_WRAP_T, wrap_t); + if(mask&WRAP_R) + glTexParameteri(target, GL_TEXTURE_WRAP_R, wrap_r); + if(mask&GENERATE_MIPMAP) + glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, gen_mipmap); + if(mask&COMPARE) + glTexParameteri(target, GL_TEXTURE_COMPARE_MODE, (compare ? GL_COMPARE_R_TO_TEXTURE : GL_NONE)); + if(mask&cmp_func) + glTexParameteri(target, GL_TEXTURE_COMPARE_FUNC, cmp_func); + } + else + dirty_params |= mask; +} + +void Texture::set_min_filter(TextureFilter f) +{ + min_filter = f; + update_parameter(MIN_FILTER); +} + +void Texture::set_mag_filter(TextureFilter f) +{ + mag_filter = f; + update_parameter(MAG_FILTER); +} + +void Texture::set_wrap(TextureWrap w) +{ + set_wrap_s(w); + set_wrap_t(w); + set_wrap_r(w); +} + +void Texture::set_wrap_s(TextureWrap w) +{ + wrap_s = w; + update_parameter(WRAP_S); +} + +void Texture::set_wrap_t(TextureWrap w) +{ + wrap_t = w; + update_parameter(WRAP_T); +} + +void Texture::set_wrap_r(TextureWrap w) +{ + wrap_r = w; + update_parameter(WRAP_R); +} + +void Texture::set_generate_mipmap(bool gm) +{ + gen_mipmap = gm; + update_parameter(GENERATE_MIPMAP); +} + +void Texture::set_compare_enabled(bool c) +{ + compare = c; + update_parameter(COMPARE); +} + +void Texture::set_compare_func(Predicate f) +{ + cmp_func = f; + update_parameter(COMPARE_FUNC); +} + void Texture::bind() const { if(!target) - throw InvalidState("Attempt to bind a texture without target"); + throw InvalidState("Attempt to bind a texture without target (should never happen)"); const Texture *cur = TexUnit::current().get_texture(); if(cur!=this) @@ -50,8 +150,15 @@ void Texture::bind() const glDisable(cur->target); if(!cur || cur->target!=target) glEnable(target); + glBindTexture(target, id); TexUnit::current().set_texture(this); + + if(dirty_params) + { + update_parameter(dirty_params); + dirty_params = 0; + } } } @@ -61,23 +168,9 @@ void Texture::bind_to(unsigned i) const bind(); } -void Texture::parameter(GLenum param, int value) -{ - maybe_bind(); - - glTexParameteri(target, param, value); -} - -void Texture::parameter(GLenum param, float value) -{ - maybe_bind(); - - glTexParameterf(target, param, value); -} - -Texture::~Texture() +const Texture *Texture::current() { - glDeleteTextures(1, &id); + return TexUnit::current().get_texture(); } void Texture::unbind() @@ -97,18 +190,6 @@ void Texture::unbind_from(unsigned i) unbind(); } -Texture::Texture(): - target(0) -{ - glGenTextures(1, &id); -} - -void Texture::maybe_bind() const -{ - if(TexUnit::current().get_texture()!=this) - bind(); -} - Texture::Loader::Loader(Texture &t): DataFile::ObjectLoader(t) @@ -130,7 +211,7 @@ void Texture::Loader::mag_filter(TextureFilter f) void Texture::Loader::generate_mipmap(bool gm) { - obj.parameter(GL_GENERATE_MIPMAP_SGIS, gm); + obj.set_generate_mipmap(gm); } } // namespace GL diff --git a/source/texture.h b/source/texture.h index 848517eb..35f70ad6 100644 --- a/source/texture.h +++ b/source/texture.h @@ -11,6 +11,7 @@ Distributed under the LGPL #include #include #include "gl.h" +#include "predicate.h" namespace Msp { namespace GL { @@ -28,6 +29,15 @@ enum TextureFilter std::istream &operator>>(std::istream &, TextureFilter &); +enum TextureWrap +{ + REPEAT = GL_REPEAT, + CLAMP_TO_EDGE = GL_CLAMP_TO_EDGE, + CLAMP_TO_BORDER = GL_CLAMP_TO_BORDER, + MIRRORED_REPEAT = GL_MIRRORED_REPEAT +}; + + /** Base class for textures. This class only defines operations common for all texture types and is not instantiable. For specifying images for textures, see @@ -45,28 +55,57 @@ protected: void generate_mipmap(bool); }; + enum ParameterMask + { + MIN_FILTER = 1, + MAG_FILTER = 2, + WRAP_S = 4, + WRAP_T = 8, + WRAP_R = 16, + GENERATE_MIPMAP = 32, + COMPARE = 64, + COMPARE_FUNC = 128 + }; + + unsigned id; + GLenum target; + TextureFilter min_filter; + TextureFilter mag_filter; + TextureWrap wrap_s; + TextureWrap wrap_t; + TextureWrap wrap_r; + bool gen_mipmap; + bool compare; + Predicate cmp_func; + mutable int dirty_params; + + Texture(GLenum); + Texture(const Texture &); + Texture &operator=(const Texture &); public: ~Texture(); +protected: + void update_parameter(int) const; +public: + void set_min_filter(TextureFilter); + void set_mag_filter(TextureFilter); + void set_wrap(TextureWrap); + void set_wrap_s(TextureWrap); + void set_wrap_t(TextureWrap); + void set_wrap_r(TextureWrap); + void set_generate_mipmap(bool); + void set_compare_enabled(bool); + void set_compare_func(Predicate); + GLenum get_target() const { return target; } + unsigned get_id() const { return id; } + void bind() const; void bind_to(unsigned) const; - void parameter(GLenum, int); - void parameter(GLenum, float); - void set_min_filter(TextureFilter f) { parameter(GL_TEXTURE_MIN_FILTER, f); } - void set_mag_filter(TextureFilter f) { parameter(GL_TEXTURE_MAG_FILTER, f); } - GLenum get_target() const { return target; } - unsigned get_id() const { return id; } + static const Texture *current(); static void unbind(); static void unbind_from(unsigned); -protected: - unsigned id; - GLenum target; - - Texture(); - Texture(const Texture &); - Texture &operator=(const Texture &); - void maybe_bind() const; }; } // namespace GL diff --git a/source/texture2d.cpp b/source/texture2d.cpp index 197e04df..8935933f 100644 --- a/source/texture2d.cpp +++ b/source/texture2d.cpp @@ -5,6 +5,7 @@ Copyright © 2007 Mikko Rasa, Mikkosoft Productions Distributed under the LGPL */ +#include "bindable.h" #include "except.h" #include "texture2d.h" @@ -14,12 +15,10 @@ namespace Msp { namespace GL { Texture2D::Texture2D(): + Texture(GL_TEXTURE_2D), width(0), height(0) -{ - target = GL_TEXTURE_2D; - bind(); -} +{ } void Texture2D::storage(PixelFormat fmt, unsigned wd, unsigned ht, int brd) { @@ -39,8 +38,7 @@ void Texture2D::image(int level, PixelFormat fmt, DataType type, const void *dat if(width==0) throw InvalidState("Texture storage has not been specified"); - maybe_bind(); - + Bind _bind(this, true); glTexImage2D(target, level, ifmt, width, height, border, fmt, type, data); } @@ -49,8 +47,7 @@ void Texture2D::sub_image(int level, int x, int y, unsigned wd, unsigned ht, Pix if(width==0) throw InvalidState("Texture storage has not been specified"); - maybe_bind(); - + Bind _bind(this, true); glTexSubImage2D(target, level, x, y, wd, ht, fmt, type, data); } diff --git a/source/texture3d.cpp b/source/texture3d.cpp index 183bede5..7edc9080 100644 --- a/source/texture3d.cpp +++ b/source/texture3d.cpp @@ -7,6 +7,7 @@ Distributed under the LGPL #include #include +#include "bindable.h" #include "except.h" #include "extension.h" #include "texture3d.h" @@ -18,20 +19,18 @@ namespace Msp { namespace GL { Texture3D::Texture3D(): + Texture(GL_TEXTURE_3D), width(0), height(0), depth(0) { - static RequireVersion _ver(1, 3); - - target = GL_TEXTURE_3D; - bind(); + static RequireVersion _ver(1, 2); } void Texture3D::storage(PixelFormat f, unsigned w, unsigned h, unsigned d, int b) { if(width>0) - throw InvalidState("Textures may only be created once"); + throw InvalidState("Textures storage may only be specified once"); if(w==0 || h==0 || d==0) throw InvalidParameterValue("Invalid texture dimensions"); @@ -46,7 +45,10 @@ void Texture3D::storage(PixelFormat f, unsigned w, unsigned h, unsigned d, int b void Texture3D::image(int level, PixelFormat fmt, DataType type, const void *data) { - maybe_bind(); + if(width==0) + throw InvalidState("Texture storage has not been specified"); + + Bind _bind(this, true); glTexImage3D(target, level, ifmt, width, height, depth, border, fmt, type, data); } diff --git a/source/texunit.cpp b/source/texunit.cpp index 1155fa96..a5427965 100644 --- a/source/texunit.cpp +++ b/source/texunit.cpp @@ -15,10 +15,13 @@ using namespace std; namespace Msp { namespace GL { +vector TexUnit::units; +TexUnit *TexUnit::cur_unit = 0; + TexUnit::TexUnit(): - texture(0) -{ -} + texture(0), + texenv(0) +{ } bool TexUnit::set_texture(const Texture *tex) { @@ -34,16 +37,29 @@ bool TexUnit::set_texenv(const TexEnv *env) return result; } +unsigned TexUnit::get_n_units() +{ + static int count = -1; + if(count<0) + // XXX Should use GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS since GL 2.0 + glGetIntegerv(GL_MAX_TEXTURE_UNITS, &count); + return count; +} + TexUnit &TexUnit::activate(unsigned n) { + if(n>0) + { + static RequireVersion _ver(1, 3); + if(n>=get_n_units()) + throw InvalidParameterValue("Invalid texture unit number"); + } + if(units.size()<=n) units.resize(n+1); if(cur_unit!=&units[n] && (cur_unit || n)) - { - static RequireVersion _ver(1, 3); glActiveTexture(GL_TEXTURE0+n); - } cur_unit = &units[n]; return units[n]; @@ -56,8 +72,5 @@ TexUnit &TexUnit::current() return *cur_unit; } -vector TexUnit::units; -TexUnit *TexUnit::cur_unit = 0; - } // namespace GL } // namespace Msp diff --git a/source/texunit.h b/source/texunit.h index 1b616505..1a4111e6 100644 --- a/source/texunit.h +++ b/source/texunit.h @@ -18,21 +18,24 @@ class Texture; class TexUnit { +private: + const Texture *texture; + const TexEnv *texenv; + + static std::vector units; + static TexUnit *cur_unit; + public: TexUnit(); + bool set_texture(const Texture *); const Texture *get_texture() const { return texture; } bool set_texenv(const TexEnv *); const TexEnv *get_texenv() const { return texenv; } + static unsigned get_n_units(); static TexUnit &activate(unsigned); static TexUnit ¤t(); -private: - const Texture *texture; - const TexEnv *texenv; - - static std::vector units; - static TexUnit *cur_unit; }; } // namespace GL -- 2.43.0