From 6cbcaf877f0be27b4d921d1c182f5e21d4662268 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sat, 6 Feb 2021 15:27:53 +0200 Subject: [PATCH] Support samplers as independent objects --- source/sampler.cpp | 65 +++++++++++++++++++++++++++++++++++++------- source/sampler.h | 4 +++ source/texture.cpp | 6 +++- source/texture3d.cpp | 19 +++---------- source/texturing.cpp | 60 ++++++++++++++++++++++++++++++---------- source/texturing.h | 13 +++++++-- source/texunit.cpp | 11 +++++++- source/texunit.h | 6 ++-- 8 files changed, 137 insertions(+), 47 deletions(-) diff --git a/source/sampler.cpp b/source/sampler.cpp index 9476ffe9..cc54901b 100644 --- a/source/sampler.cpp +++ b/source/sampler.cpp @@ -14,6 +14,18 @@ using namespace std; namespace Msp { namespace GL { +Sampler::Sampler(): + owner(0) +{ + init(); + + Require _req(ARB_sampler_objects); + if(ARB_direct_state_access) + glCreateSamplers(1, &id); + else + glGenSamplers(1, &id); +} + Sampler::Sampler(const Texture &tex): id(0), owner(&tex) @@ -39,16 +51,25 @@ void Sampler::init() void Sampler::update_parameter(int mask) const { - if(!owner->get_id() || (!ARB_direct_state_access && TexUnit::current().get_texture()!=owner)) + if(owner) { - TexUnit *unit = TexUnit::find_unit(owner); - if(!unit) + if(!owner->get_id()) { dirty_params |= mask; return; } - unit->bind(); + if(!ARB_direct_state_access && TexUnit::current().get_texture()!=owner) + { + TexUnit *unit = TexUnit::find_unit(owner); + if(!unit) + { + dirty_params |= mask; + return; + } + + unit->bind(); + } } if(mask&MIN_FILTER) @@ -73,7 +94,9 @@ void Sampler::update_parameter(int mask) const void Sampler::set_parameter_i(unsigned param, int value) const { - if(ARB_direct_state_access) + if(id) + glSamplerParameteri(id, param, value); + else if(ARB_direct_state_access) glTextureParameteri(owner->get_id(), param, value); else glTexParameteri(owner->get_target(), param, value); @@ -81,7 +104,9 @@ void Sampler::set_parameter_i(unsigned param, int value) const void Sampler::set_parameter_f(unsigned param, float value) const { - if(ARB_direct_state_access) + if(id) + glSamplerParameterf(id, param, value); + else if(ARB_direct_state_access) glTextureParameterf(owner->get_id(), param, value); else glTexParameterf(owner->get_target(), param, value); @@ -160,16 +185,36 @@ void Sampler::set_compare(Predicate f) void Sampler::bind_to(unsigned i) const { TexUnit &unit = TexUnit::get_unit(i); - if(owner!=unit.get_texture()) + if(owner && owner!=unit.get_texture()) throw invalid_operation("Sampler::bind_to"); - if(dirty_params) + const Sampler *cur = unit.get_sampler(); + if(unit.set_sampler(this)) { - update_parameter(dirty_params); - dirty_params = 0; + if(!owner || (cur && cur->id)) + glBindSampler(i, id); + + if(dirty_params) + { + update_parameter(dirty_params); + dirty_params = 0; + } } } +const Sampler *Sampler::current(unsigned i) +{ + return TexUnit::get_unit(i).get_sampler(); +} + +void Sampler::unbind_from(unsigned i) +{ + TexUnit &unit = TexUnit::get_unit(i); + const Sampler *cur = unit.get_sampler(); + if(unit.set_sampler(0) && cur->id) + glBindSampler(i, 0); +} + void Sampler::unload() { // TODO check which params actually need refreshing diff --git a/source/sampler.h b/source/sampler.h index 255d1da4..e1e9bec5 100644 --- a/source/sampler.h +++ b/source/sampler.h @@ -149,6 +149,10 @@ public: void bind() const { bind_to(0); } void bind_to(unsigned) const; + static const Sampler *current(unsigned = 0); + static void unbind() { unbind_from(0); } + static void unbind_from(unsigned); + void unload(); }; diff --git a/source/texture.cpp b/source/texture.cpp index ab570048..381a0a59 100644 --- a/source/texture.cpp +++ b/source/texture.cpp @@ -238,7 +238,8 @@ void Texture::bind_to(unsigned i) const glBindTexture(target, id); } - default_sampler.bind_to(i); + if(!unit.get_sampler()) + default_sampler.bind_to(i); } } @@ -260,6 +261,9 @@ void Texture::unbind_from(unsigned i) unit.bind(); glBindTexture(cur->target, 0); } + + if(unit.get_sampler()==&cur->default_sampler) + Sampler::unbind_from(i); } } diff --git a/source/texture3d.cpp b/source/texture3d.cpp index 667f8c31..1f62e050 100644 --- a/source/texture3d.cpp +++ b/source/texture3d.cpp @@ -142,22 +142,11 @@ void Texture3D::image(const Graphics::Image &img, unsigned lv) { unsigned w = img.get_width(); unsigned h = img.get_height(); - unsigned d = 1; - if(depth) - { - if(h%depth) - throw incompatible_data("Texture3D::load_image"); - h /= depth; - d = depth; - } - else - { - if(h%w) - throw incompatible_data("Texture3D::load_image"); - d = h/w; - h = w; - } + if(h%w) + throw incompatible_data("Texture3D::load_image"); + unsigned d = h/w; + h = w; PixelFormat fmt = pixelformat_from_image(img); if(width==0) diff --git a/source/texturing.cpp b/source/texturing.cpp index c30216f1..ab5d39b4 100644 --- a/source/texturing.cpp +++ b/source/texturing.cpp @@ -21,7 +21,7 @@ int Texturing::find_free_unit(const string &name_hint) const max_unit -= min(max_unit/4, 8U); unsigned initial_unit = (name_hint.empty() ? 0 : hash32(name_hint)%max_unit); unsigned unit = initial_unit; - while(get_attached_texture(unit)) + while(get_attached_texture(unit) || get_attached_sampler(unit)) { unit = (unit+1)%max_unit; if(unit==initial_unit) @@ -31,34 +31,40 @@ int Texturing::find_free_unit(const string &name_hint) const return unit; } -void Texturing::attach(unsigned attch, const Texture &tex) +void Texturing::attach(unsigned attch, const Texture &tex, const Sampler *samp) { - set_attachment(attch, &tex); + set_attachment(attch, &tex, samp); +} + +void Texturing::attach(unsigned attch, const Sampler &samp) +{ + set_attachment(attch, 0, &samp); } void Texturing::detach(unsigned attch) { - set_attachment(attch, 0); + set_attachment(attch, 0, 0); } -void Texturing::set_attachment(unsigned unit, const Texture *tex) +void Texturing::set_attachment(unsigned unit, const Texture *tex, const Sampler *samp) { if(unit>=TexUnit::get_n_units()) throw out_of_range("Texturing::set_attachment"); - if(tex) + if(tex || samp) { vector::iterator i; for(i=attachments.begin(); (i!=attachments.end() && i->unit<=unit); ++i) if(i->unit==unit) { i->texture = tex; + i->sampler = samp; if(current()==this) - tex->bind_to(unit); + bind_attachment(*i); return; } - attachments.insert(i, Attachment(unit, tex)); + attachments.insert(i, Attachment(unit, tex, samp)); if(current()==this) tex->bind_to(unit); } @@ -69,7 +75,7 @@ void Texturing::set_attachment(unsigned unit, const Texture *tex) { attachments.erase(i); if(current()==this) - Texture::unbind_from(unit); + unbind_attachment(unit); return; } } @@ -83,6 +89,14 @@ const Texture *Texturing::get_attached_texture(unsigned unit) const return 0; } +const Sampler *Texturing::get_attached_sampler(unsigned unit) const +{ + for(vector::const_iterator i=attachments.begin(); (i!=attachments.end() && i->unit<=unit); ++i) + if(i->unit==unit) + return i->sampler; + return 0; +} + void Texturing::bind() const { const Texturing *old = current(); @@ -96,14 +110,14 @@ void Texturing::bind() const { if(i!=attachments.end() && (j==old->attachments.end() || i->unit<=j->unit)) { - i->texture->bind_to(i->unit); + bind_attachment(*i); if(j!=old->attachments.end() && j->unit==i->unit) ++j; ++i; } else { - Texture::unbind_from(j->unit); + unbind_attachment(j->unit); ++j; } } @@ -111,25 +125,41 @@ void Texturing::bind() const else { for(vector::const_iterator i=attachments.begin(); i!=attachments.end(); ++i) - i->texture->bind_to(i->unit); + bind_attachment(*i); } } } +void Texturing::bind_attachment(const Attachment &attch) const +{ + if(attch.sampler) + attch.sampler->bind_to(attch.unit); + else + Sampler::unbind_from(attch.unit); + attch.texture->bind_to(attch.unit); +} + void Texturing::unbind() { const Texturing *old = current(); if(set_current(0)) { for(vector::const_iterator i=old->attachments.begin(); i!=old->attachments.end(); ++i) - Texture::unbind_from(i->unit); + unbind_attachment(i->unit); } } +void Texturing::unbind_attachment(unsigned unit) +{ + Texture::unbind_from(unit); + Sampler::unbind_from(unit); +} + -Texturing::Attachment::Attachment(unsigned u, const Texture *t): +Texturing::Attachment::Attachment(unsigned u, const Texture *t, const Sampler *s): unit(u), - texture(t) + texture(t), + sampler(s) { } } // namespace GL diff --git a/source/texturing.h b/source/texturing.h index cba77e3f..0da3eae4 100644 --- a/source/texturing.h +++ b/source/texturing.h @@ -16,8 +16,9 @@ private: { unsigned unit; const Texture *texture; + const Sampler *sampler; - Attachment(unsigned, const Texture *); + Attachment(unsigned, const Texture *, const Sampler *); }; std::vector attachments; @@ -26,16 +27,22 @@ public: ~Texturing(); int find_free_unit(const std::string & = std::string()) const; - void attach(unsigned, const Texture &); + void attach(unsigned, const Texture &, const Sampler * = 0); + void attach(unsigned, const Sampler &); void detach(unsigned); private: - void set_attachment(unsigned, const Texture *); + void set_attachment(unsigned, const Texture *, const Sampler *); public: const Texture *get_attached_texture(unsigned) const; + const Sampler *get_attached_sampler(unsigned) const; void bind() const; static void unbind(); + +private: + void bind_attachment(const Attachment &) const; + static void unbind_attachment(unsigned); }; } // namespace GL diff --git a/source/texunit.cpp b/source/texunit.cpp index 493a7611..0659d615 100644 --- a/source/texunit.cpp +++ b/source/texunit.cpp @@ -3,6 +3,7 @@ #include #include "gl.h" #include "misc.h" +#include "texture.h" #include "texunit.h" using namespace std; @@ -14,7 +15,8 @@ vector TexUnit::units; TexUnit *TexUnit::cur_unit = 0; TexUnit::TexUnit(): - texture(0) + texture(0), + sampler(0) { } bool TexUnit::set_texture(const Texture *tex) @@ -24,6 +26,13 @@ bool TexUnit::set_texture(const Texture *tex) return result; } +bool TexUnit::set_sampler(const Sampler *samp) +{ + bool result = (samp!=sampler); + sampler = samp; + return result; +} + void TexUnit::bind() { if(cur_unit!=this && (cur_unit || index)) diff --git a/source/texunit.h b/source/texunit.h index 6bd2f82d..6253d8d9 100644 --- a/source/texunit.h +++ b/source/texunit.h @@ -6,8 +6,7 @@ namespace Msp { namespace GL { -class TexEnv; -class TexGen; +class Sampler; class Texture; /** @@ -18,6 +17,7 @@ class TexUnit private: unsigned index; const Texture *texture; + const Sampler *sampler; static std::vector units; static TexUnit *cur_unit; @@ -28,6 +28,8 @@ public: unsigned get_index() const { return index; } bool set_texture(const Texture *); const Texture *get_texture() const { return texture; } + bool set_sampler(const Sampler *); + const Sampler *get_sampler() const { return sampler; } void bind(); static unsigned get_n_units(); -- 2.43.0