OpenGLRenderer: Implement TextureSampler (and texture units)

This commit is contained in:
Lynix 2020-04-26 16:29:31 +02:00
parent cbd81e3abf
commit e9f0b01e02
13 changed files with 244 additions and 66 deletions

View File

@ -40,6 +40,7 @@ namespace Nz
std::unique_ptr<Texture> InstantiateTexture(const TextureInfo& params) override; std::unique_ptr<Texture> InstantiateTexture(const TextureInfo& params) override;
std::unique_ptr<TextureSampler> InstantiateTextureSampler(const TextureSamplerInfo& params) override; std::unique_ptr<TextureSampler> InstantiateTextureSampler(const TextureSamplerInfo& params) override;
inline void NotifySamplerDestruction(GLuint texture) const;
inline void NotifyTextureDestruction(GLuint texture) const; inline void NotifyTextureDestruction(GLuint texture) const;
OpenGLDevice& operator=(const OpenGLDevice&) = delete; OpenGLDevice& operator=(const OpenGLDevice&) = delete;

View File

@ -12,6 +12,12 @@ namespace Nz
return *m_referenceContext; return *m_referenceContext;
} }
inline void OpenGLDevice::NotifySamplerDestruction(GLuint texture) const
{
for (const GL::Context* context : m_contexts)
context->NotifySamplerDestruction(texture);
}
inline void OpenGLDevice::NotifyTextureDestruction(GLuint texture) const inline void OpenGLDevice::NotifyTextureDestruction(GLuint texture) const
{ {
for (const GL::Context* context : m_contexts) for (const GL::Context* context : m_contexts)

View File

@ -9,6 +9,7 @@
#include <Nazara/Prerequisites.hpp> #include <Nazara/Prerequisites.hpp>
#include <Nazara/Renderer/TextureSampler.hpp> #include <Nazara/Renderer/TextureSampler.hpp>
#include <Nazara/OpenGLRenderer/Wrapper/Context.hpp>
#include <Nazara/OpenGLRenderer/Wrapper/Sampler.hpp> #include <Nazara/OpenGLRenderer/Wrapper/Sampler.hpp>
namespace Nz namespace Nz
@ -16,18 +17,18 @@ namespace Nz
class NAZARA_OPENGLRENDERER_API OpenGLTextureSampler : public TextureSampler class NAZARA_OPENGLRENDERER_API OpenGLTextureSampler : public TextureSampler
{ {
public: public:
OpenGLTextureSampler(Vk::Device& device, TextureSamplerInfo samplerInfo); OpenGLTextureSampler(OpenGLDevice& device, TextureSamplerInfo samplerInfo);
OpenGLTextureSampler(const OpenGLTextureSampler&) = default; OpenGLTextureSampler(const OpenGLTextureSampler&) = default;
OpenGLTextureSampler(OpenGLTextureSampler&&) noexcept = default; OpenGLTextureSampler(OpenGLTextureSampler&&) noexcept = default;
~OpenGLTextureSampler() = default; ~OpenGLTextureSampler() = default;
inline VkSampler GetSampler() const; inline const GL::Sampler& GetSampler() const;
OpenGLTextureSampler& operator=(const OpenGLTextureSampler&) = delete; OpenGLTextureSampler& operator=(const OpenGLTextureSampler&) = delete;
OpenGLTextureSampler& operator=(OpenGLTextureSampler&&) = delete; OpenGLTextureSampler& operator=(OpenGLTextureSampler&&) = delete;
private: private:
Vk::Sampler m_sampler; GL::Sampler m_sampler;
}; };
} }

View File

@ -2,12 +2,12 @@
// This file is part of the "Nazara Engine - OpenGL Renderer" // This file is part of the "Nazara Engine - OpenGL Renderer"
// For conditions of distribution and use, see copyright notice in Config.hpp // For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/OpenGLRenderer/OpenGLShaderBinding.hpp> #include <Nazara/OpenGLRenderer/OpenGLTextureSampler.hpp>
#include <Nazara/OpenGLRenderer/Debug.hpp> #include <Nazara/OpenGLRenderer/Debug.hpp>
namespace Nz namespace Nz
{ {
inline VkSampler OpenGLTextureSampler::GetSampler() const inline const GL::Sampler& OpenGLTextureSampler::GetSampler() const
{ {
return m_sampler; return m_sampler;
} }

View File

@ -16,6 +16,9 @@
namespace Nz namespace Nz
{ {
inline GLenum ToOpenGL(SamplerFilter filter);
inline GLenum ToOpenGL(SamplerFilter minFilter, SamplerMipmapMode mipmapFilter);
inline GLenum ToOpenGL(SamplerWrap wrapMode);
inline GLenum ToOpenGL(ShaderStageType stageType); inline GLenum ToOpenGL(ShaderStageType stageType);
//NAZARA_OPENGLRENDERER_API std::string TranslateOpenGLError(GLenum code); //NAZARA_OPENGLRENDERER_API std::string TranslateOpenGLError(GLenum code);

View File

@ -10,6 +10,64 @@
namespace Nz namespace Nz
{ {
GLenum ToOpenGL(SamplerFilter filter)
{
switch (filter)
{
case SamplerFilter::SamplerFilter_Linear: return GL_LINEAR;
case SamplerFilter::SamplerFilter_Nearest: return GL_NEAREST;
}
NazaraError("Unhandled SamplerFilter 0x" + String::Number(UnderlyingCast(filter), 16));
return {};
}
GLenum ToOpenGL(SamplerFilter minFilter, SamplerMipmapMode mipmapFilter)
{
switch (minFilter)
{
case SamplerFilter::SamplerFilter_Linear:
{
switch (mipmapFilter)
{
case SamplerMipmapMode_Linear: return GL_LINEAR_MIPMAP_LINEAR;
case SamplerMipmapMode_Nearest: return GL_LINEAR_MIPMAP_NEAREST;
}
NazaraError("Unhandled SamplerFilter 0x" + String::Number(UnderlyingCast(mipmapFilter), 16));
return {};
}
case SamplerFilter::SamplerFilter_Nearest:
{
switch (mipmapFilter)
{
case SamplerMipmapMode_Linear: return GL_NEAREST_MIPMAP_LINEAR;
case SamplerMipmapMode_Nearest: return GL_NEAREST_MIPMAP_NEAREST;
}
NazaraError("Unhandled SamplerFilter 0x" + String::Number(UnderlyingCast(mipmapFilter), 16));
return {};
}
}
NazaraError("Unhandled SamplerFilter 0x" + String::Number(UnderlyingCast(minFilter), 16));
return {};
}
GLenum ToOpenGL(SamplerWrap wrapMode)
{
switch (wrapMode)
{
case SamplerWrap::SamplerWrap_Clamp: return GL_CLAMP_TO_EDGE;
case SamplerWrap::SamplerWrap_MirroredRepeat: return GL_MIRRORED_REPEAT;
case SamplerWrap::SamplerWrap_Repeat: return GL_REPEAT;
}
NazaraError("Unhandled SamplerWrap 0x" + String::Number(UnderlyingCast(wrapMode), 16));
return {};
}
GLenum ToOpenGL(ShaderStageType stageType) GLenum ToOpenGL(ShaderStageType stageType)
{ {
switch (stageType) switch (stageType)

View File

@ -30,8 +30,9 @@ namespace Nz::GL
enum class Extension enum class Extension
{ {
SpirV, SpirV,
TextureFilterAnisotropic,
Max = SpirV Max = TextureFilterAnisotropic
}; };
enum class ExtensionStatus enum class ExtensionStatus
@ -73,7 +74,9 @@ namespace Nz::GL
inline Context(const OpenGLDevice* device); inline Context(const OpenGLDevice* device);
virtual ~Context(); virtual ~Context();
void BindSampler(UInt32 textureUnit, GLuint sampler) const;
void BindTexture(TextureTarget target, GLuint texture) const; void BindTexture(TextureTarget target, GLuint texture) const;
void BindTexture(UInt32 textureUnit, TextureTarget target, GLuint texture) const;
virtual void EnableVerticalSync(bool enabled) = 0; virtual void EnableVerticalSync(bool enabled) = 0;
@ -86,8 +89,11 @@ namespace Nz::GL
bool Initialize(const ContextParams& params); bool Initialize(const ContextParams& params);
inline void NotifySamplerDestruction(GLuint sampler) const;
inline void NotifyTextureDestruction(GLuint texture) const; inline void NotifyTextureDestruction(GLuint texture) const;
inline void SetCurrentTextureUnit(UInt32 textureUnit) const;
virtual void SwapBuffers() = 0; virtual void SwapBuffers() = 0;
#define NAZARA_OPENGLRENDERER_FUNC(name, sig) sig name = nullptr; #define NAZARA_OPENGLRENDERER_FUNC(name, sig) sig name = nullptr;
@ -113,7 +119,14 @@ namespace Nz::GL
struct State struct State
{ {
std::array<GLuint, UnderlyingCast(TextureTarget::Max) + 1> boundTextures; struct TextureUnit
{
GLuint sampler = 0;
std::array<GLuint, UnderlyingCast(TextureTarget::Max) + 1> textureTargets = { 0 };
};
std::vector<TextureUnit> textureUnits;
UInt32 currentTextureUnit = 0;
}; };
std::array<ExtensionStatus, UnderlyingCast(Extension::Max) + 1> m_extensionStatus; std::array<ExtensionStatus, UnderlyingCast(Extension::Max) + 1> m_extensionStatus;

View File

@ -37,9 +37,20 @@ namespace Nz::GL
return m_supportedExtensions.find(extension) != m_supportedExtensions.end(); return m_supportedExtensions.find(extension) != m_supportedExtensions.end();
} }
inline void Context::NotifySamplerDestruction(GLuint sampler) const
{
for (auto& unit : m_state.textureUnits)
{
if (unit.sampler == sampler)
unit.sampler = 0;
}
}
inline void Context::NotifyTextureDestruction(GLuint texture) const inline void Context::NotifyTextureDestruction(GLuint texture) const
{ {
for (GLuint& boundTexture : m_state.boundTextures) for (auto& unit : m_state.textureUnits)
{
for (GLuint& boundTexture : unit.textureTargets)
{ {
if (boundTexture == texture) if (boundTexture == texture)
boundTexture = 0; boundTexture = 0;
@ -47,4 +58,14 @@ namespace Nz::GL
} }
} }
inline void Context::SetCurrentTextureUnit(UInt32 textureUnit) const
{
if (m_state.currentTextureUnit != textureUnit)
{
glActiveTexture(GL_TEXTURE0 + textureUnit);
m_state.currentTextureUnit = textureUnit;
}
}
}
#include <Nazara/OpenGLRenderer/DebugOff.hpp> #include <Nazara/OpenGLRenderer/DebugOff.hpp>

View File

@ -110,7 +110,9 @@ typedef void (GL_APIENTRYP PFNGLSPECIALIZESHADERARBPROC) (GLuint shader, const G
cb(glReadPixels, PFNGLREADPIXELSPROC) \ cb(glReadPixels, PFNGLREADPIXELSPROC) \
cb(glRenderbufferStorage, PFNGLRENDERBUFFERSTORAGEPROC) \ cb(glRenderbufferStorage, PFNGLRENDERBUFFERSTORAGEPROC) \
cb(glSamplerParameterf, PFNGLSAMPLERPARAMETERFPROC) \ cb(glSamplerParameterf, PFNGLSAMPLERPARAMETERFPROC) \
cb(glSamplerParameterfv, PFNGLSAMPLERPARAMETERFVPROC) \
cb(glSamplerParameteri, PFNGLSAMPLERPARAMETERIPROC) \ cb(glSamplerParameteri, PFNGLSAMPLERPARAMETERIPROC) \
cb(glSamplerParameteriv, PFNGLSAMPLERPARAMETERIVPROC) \
cb(glScissor, PFNGLSCISSORPROC) \ cb(glScissor, PFNGLSCISSORPROC) \
cb(glShaderBinary, PFNGLSHADERBINARYPROC) \ cb(glShaderBinary, PFNGLSHADERBINARYPROC) \
cb(glShaderSource, PFNGLSHADERSOURCEPROC) \ cb(glShaderSource, PFNGLSHADERSOURCEPROC) \

View File

@ -4,36 +4,40 @@
#pragma once #pragma once
#ifndef NAZARA_OPENGLRENDERER_VKSAMPLER_HPP #ifndef NAZARA_OPENGLRENDERER_GLSAMPLER_HPP
#define NAZARA_OPENGLRENDERER_VKSAMPLER_HPP #define NAZARA_OPENGLRENDERER_GLSAMPLER_HPP
#include <Nazara/Prerequisites.hpp> #include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/MovableValue.hpp>
#include <Nazara/OpenGLRenderer/OpenGLDevice.hpp>
#include <Nazara/OpenGLRenderer/Wrapper/DeviceObject.hpp> #include <Nazara/OpenGLRenderer/Wrapper/DeviceObject.hpp>
namespace Nz namespace Nz::GL
{ {
namespace Vk class Sampler : public DeviceObject<Sampler, GL_SAMPLER>
{
class Sampler : public DeviceObject<Sampler, VkSampler, VkSamplerCreateInfo, VK_OBJECT_TYPE_SAMPLER>
{ {
friend DeviceObject; friend DeviceObject;
public: public:
Sampler() = default; Sampler() = default;
Sampler(const Sampler&) = delete; Sampler(const Sampler&) = delete;
Sampler(Sampler&&) = default; Sampler(Sampler&&) noexcept = default;
~Sampler() = default; ~Sampler() = default;
inline void SetParameterf(GLenum pname, GLfloat param);
inline void SetParameteri(GLenum pname, GLint param);
inline void SetParameterfv(GLenum pname, const GLfloat* param);
inline void SetParameteriv(GLenum pname, const GLint* param);
Sampler& operator=(const Sampler&) = delete; Sampler& operator=(const Sampler&) = delete;
Sampler& operator=(Sampler&&) = delete; Sampler& operator=(Sampler&&) noexcept = default;
private: private:
static inline VkResult CreateHelper(Device& device, const VkSamplerCreateInfo* createInfo, const VkAllocationCallbacks* allocator, VkSampler* handle); static inline GLuint CreateHelper(OpenGLDevice& device, const Context& context);
static inline void DestroyHelper(Device& device, VkSampler handle, const VkAllocationCallbacks* allocator); static inline void DestroyHelper(OpenGLDevice& device, const Context& context, GLuint objectId);
}; };
} }
}
#include <Nazara/OpenGLRenderer/Wrapper/Sampler.inl> #include <Nazara/OpenGLRenderer/Wrapper/Sampler.inl>
#endif // NAZARA_OPENGLRENDERER_VKSAMPLER_HPP #endif

View File

@ -5,19 +5,53 @@
#include <Nazara/OpenGLRenderer/Wrapper/Sampler.hpp> #include <Nazara/OpenGLRenderer/Wrapper/Sampler.hpp>
#include <Nazara/OpenGLRenderer/Debug.hpp> #include <Nazara/OpenGLRenderer/Debug.hpp>
namespace Nz namespace Nz::GL
{ {
namespace Vk inline void Sampler::SetParameterf(GLenum pname, GLfloat param)
{ {
inline VkResult Sampler::CreateHelper(Device& device, const VkSamplerCreateInfo* createInfo, const VkAllocationCallbacks* allocator, VkSampler* handle) assert(m_objectId);
{
return device.vkCreateSampler(device, createInfo, allocator, handle); const Context& context = EnsureDeviceContext();
context.glSamplerParameterf(m_objectId, pname, param);
} }
inline void Sampler::DestroyHelper(Device& device, VkSampler handle, const VkAllocationCallbacks* allocator) inline void Sampler::SetParameteri(GLenum pname, GLint param)
{ {
return device.vkDestroySampler(device, handle, allocator); assert(m_objectId);
const Context& context = EnsureDeviceContext();
context.glSamplerParameteri(m_objectId, pname, param);
} }
inline void Sampler::SetParameterfv(GLenum pname, const GLfloat* param)
{
assert(m_objectId);
const Context& context = EnsureDeviceContext();
context.glSamplerParameterfv(m_objectId, pname, param);
}
inline void Sampler::SetParameteriv(GLenum pname, const GLint* param)
{
assert(m_objectId);
const Context& context = EnsureDeviceContext();
context.glSamplerParameteriv(m_objectId, pname, param);
}
inline GLuint Sampler::CreateHelper(OpenGLDevice& device, const Context& context)
{
GLuint sampler = 0;
context.glGenSamplers(1U, &sampler);
return sampler;
}
inline void Sampler::DestroyHelper(OpenGLDevice& device, const Context& context, GLuint objectId)
{
context.glDeleteSamplers(1U, &objectId);
device.NotifySamplerDestruction(objectId);
} }
} }

View File

@ -2,34 +2,28 @@
// This file is part of the "Nazara Engine - OpenGL Renderer" // This file is part of the "Nazara Engine - OpenGL Renderer"
// For conditions of distribution and use, see copyright notice in Config.hpp // For conditions of distribution and use, see copyright notice in Config.hpp
#if 0
#include <Nazara/OpenGLRenderer/OpenGLTextureSampler.hpp> #include <Nazara/OpenGLRenderer/OpenGLTextureSampler.hpp>
#include <Nazara/OpenGLRenderer/Utils.hpp>
#include <stdexcept> #include <stdexcept>
#include <Nazara/OpenGLRenderer/Debug.hpp> #include <Nazara/OpenGLRenderer/Debug.hpp>
namespace Nz namespace Nz
{ {
OpenGLTextureSampler::OpenGLTextureSampler(Vk::Device& device, TextureSamplerInfo samplerInfo) OpenGLTextureSampler::OpenGLTextureSampler(OpenGLDevice& device, TextureSamplerInfo samplerInfo)
{ {
VkSamplerCreateInfo createInfo = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; if (!m_sampler.Create(device))
createInfo.magFilter = ToOpenGL(samplerInfo.magFilter); throw std::runtime_error("failed to create sampler object");
createInfo.minFilter = ToOpenGL(samplerInfo.minFilter);
createInfo.addressModeU = ToOpenGL(samplerInfo.wrapModeU);
createInfo.addressModeV = ToOpenGL(samplerInfo.wrapModeV);
createInfo.addressModeW = ToOpenGL(samplerInfo.wrapModeW);
createInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
createInfo.mipmapMode = ToOpenGL(samplerInfo.mipmapMode);
if (samplerInfo.anisotropyLevel > 0.f) // In OpenGL, min and mipmap sampler are part of the same enum
{
createInfo.anisotropyEnable = VK_TRUE;
createInfo.maxAnisotropy = samplerInfo.anisotropyLevel;
}
if (!m_sampler.Create(device, createInfo)) m_sampler.SetParameteri(GL_TEXTURE_MIN_FILTER, ToOpenGL(samplerInfo.minFilter, samplerInfo.mipmapMode));
throw std::runtime_error("Failed to create sampler: " + TranslateOpenGLError(m_sampler.GetLastErrorCode())); m_sampler.SetParameteri(GL_TEXTURE_MAG_FILTER, ToOpenGL(samplerInfo.magFilter));
m_sampler.SetParameteri(GL_TEXTURE_WRAP_S, ToOpenGL(samplerInfo.wrapModeU));
m_sampler.SetParameteri(GL_TEXTURE_WRAP_T, ToOpenGL(samplerInfo.wrapModeV));
m_sampler.SetParameteri(GL_TEXTURE_WRAP_R, ToOpenGL(samplerInfo.wrapModeW));
if (samplerInfo.anisotropyLevel > 1.f)
m_sampler.SetParameterf(GL_TEXTURE_MAX_ANISOTROPY_EXT, samplerInfo.anisotropyLevel);
} }
} }
#endif

View File

@ -22,13 +22,40 @@ namespace Nz::GL
m_device->NotifyContextDestruction(*this); m_device->NotifyContextDestruction(*this);
} }
void Context::BindTexture(TextureTarget target, GLuint texture) const void Context::BindSampler(UInt32 textureUnit, GLuint sampler) const
{
if (textureUnit >= m_state.textureUnits.size())
throw std::runtime_error("unsupported texture unit #" + std::to_string(textureUnit));
auto& unit = m_state.textureUnits[textureUnit];
if (unit.sampler != sampler)
{ {
if (!SetCurrentContext(this)) if (!SetCurrentContext(this))
throw std::runtime_error("failed to activate context"); throw std::runtime_error("failed to activate context");
if (m_state.boundTextures[UnderlyingCast(target)] != texture) glBindSampler(textureUnit, sampler);
unit.sampler = sampler;
}
}
void Context::BindTexture(TextureTarget target, GLuint texture) const
{ {
BindTexture(m_state.currentTextureUnit, target, texture);
}
void Context::BindTexture(UInt32 textureUnit, TextureTarget target, GLuint texture) const
{
if (textureUnit >= m_state.textureUnits.size())
throw std::runtime_error("unsupported texture unit #" + std::to_string(textureUnit));
auto& unit = m_state.textureUnits[textureUnit];
if (unit.textureTargets[UnderlyingCast(target)] != texture)
{
if (!SetCurrentContext(this))
throw std::runtime_error("failed to activate context");
SetCurrentTextureUnit(textureUnit);
GLenum glTarget; GLenum glTarget;
switch (target) switch (target)
{ {
@ -54,7 +81,7 @@ namespace Nz::GL
glBindTexture(glTarget, texture); glBindTexture(glTarget, texture);
m_state.boundTextures[UnderlyingCast(target)] = texture; unit.textureTargets[UnderlyingCast(target)] = texture;
} }
} }
@ -66,8 +93,6 @@ namespace Nz::GL
return false; return false;
} }
m_state.boundTextures.fill(0);
const Loader& loader = GetLoader(); const Loader& loader = GetLoader();
auto LoadSymbol = [&](auto& func, const char* funcName, bool mandatory) auto LoadSymbol = [&](auto& func, const char* funcName, bool mandatory)
@ -118,6 +143,14 @@ namespace Nz::GL
}); });
m_extensionStatus.fill(ExtensionStatus::NotSupported); m_extensionStatus.fill(ExtensionStatus::NotSupported);
// TextureFilterAnisotropic
if (m_supportedExtensions.count("GL_ARB_texture_filter_anisotropic"))
m_extensionStatus[UnderlyingCast(Extension::TextureFilterAnisotropic)] = ExtensionStatus::ARB;
else if (m_supportedExtensions.count("GL_EXT_texture_filter_anisotropic"))
m_extensionStatus[UnderlyingCast(Extension::TextureFilterAnisotropic)] = ExtensionStatus::EXT;
// SpirV
if (m_supportedExtensions.count("GL_ARB_gl_spirv")) if (m_supportedExtensions.count("GL_ARB_gl_spirv"))
m_extensionStatus[UnderlyingCast(Extension::SpirV)] = ExtensionStatus::ARB; m_extensionStatus[UnderlyingCast(Extension::SpirV)] = ExtensionStatus::ARB;
@ -162,6 +195,14 @@ namespace Nz::GL
}, this); }, this);
} }
GLint maxTextureUnits = -1;
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
if (maxTextureUnits < 32) //< OpenGL ES 3.0 requires at least 32 textures units
NazaraWarning("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS is " + std::to_string(maxTextureUnits) + ", >= 32 expected");
assert(maxTextureUnits > 0);
m_state.textureUnits.resize(maxTextureUnits);
return true; return true;
} }