diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Framebuffer.hpp b/include/Nazara/OpenGLRenderer/Wrapper/Framebuffer.hpp index c59e639e8..be231577a 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Framebuffer.hpp +++ b/include/Nazara/OpenGLRenderer/Wrapper/Framebuffer.hpp @@ -27,6 +27,7 @@ namespace Nz::GL inline void DrawBuffers(GLsizei n, const GLenum* bufs); inline void Renderbuffer(GLenum attachment, GLenum renderbuffer); inline void Texture2D(GLenum attachment, GLenum textarget, GLuint texture, GLint level = 0); + inline void TextureLayer(GLenum attachment, GLuint texture, GLint level = 0, GLint layer = 0); Framebuffer& operator=(const Framebuffer&) = delete; Framebuffer& operator=(Framebuffer&&) noexcept = default; diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Framebuffer.inl b/include/Nazara/OpenGLRenderer/Wrapper/Framebuffer.inl index 171f3eab8..ec56792b7 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Framebuffer.inl +++ b/include/Nazara/OpenGLRenderer/Wrapper/Framebuffer.inl @@ -44,6 +44,15 @@ namespace Nz::GL context.glFramebufferTexture2D(target, attachment, textarget, texture, level); } + inline void Framebuffer::TextureLayer(GLenum attachment, GLuint texture, GLint level, GLint layer) + { + assert(m_objectId); + + const Context& context = EnsureContext(); + GLenum target = context.BindFramebuffer(m_objectId); + context.glFramebufferTextureLayer(target, attachment, texture, level, layer); + } + inline GLuint Framebuffer::CreateHelper(const Context& context) { GLuint fbo = 0; diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Texture.hpp b/include/Nazara/OpenGLRenderer/Wrapper/Texture.hpp index f53cd8bb0..4f58b47cf 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Texture.hpp +++ b/include/Nazara/OpenGLRenderer/Wrapper/Texture.hpp @@ -39,7 +39,7 @@ namespace Nz::GL inline void TexStorage3D(TextureTarget target, GLint levels, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth); inline void TexSubImage2D(TextureTarget target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* data); inline void TexSubImage3D(TextureTarget target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* data); - inline void TextureView(GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); + inline void TextureView(TextureTarget target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); Texture& operator=(const Texture&) = delete; Texture& operator=(Texture&&) noexcept = default; diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Texture.inl b/include/Nazara/OpenGLRenderer/Wrapper/Texture.inl index 1658ff55a..4d856b05b 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Texture.inl +++ b/include/Nazara/OpenGLRenderer/Wrapper/Texture.inl @@ -111,10 +111,12 @@ namespace Nz::GL //< TODO: Handle errors } - inline void Texture::TextureView(GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers) + inline void Texture::TextureView(TextureTarget target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers) { + m_target = target; + const Context& context = EnsureDeviceContext(); - context.glTextureView(m_objectId, target, origtexture, internalformat, minlevel, numlevels, minlayer, numlayers); + context.glTextureView(m_objectId, ToOpenGL(target), origtexture, internalformat, minlevel, numlevels, minlayer, numlayers); } inline GLuint Texture::CreateHelper(OpenGLDevice& /*device*/, const Context& context) diff --git a/include/Nazara/Renderer/Texture.inl b/include/Nazara/Renderer/Texture.inl index 7d2c68a17..68dfad0d0 100644 --- a/include/Nazara/Renderer/Texture.inl +++ b/include/Nazara/Renderer/Texture.inl @@ -14,8 +14,8 @@ namespace Nz textureInfo.width = GetLevelSize(textureInfo.width, viewInfo.baseMipLevel); textureInfo.height = GetLevelSize(textureInfo.height, viewInfo.baseMipLevel); textureInfo.depth = GetLevelSize(textureInfo.depth, viewInfo.baseMipLevel); - textureInfo.levelCount = (textureInfo.levelCount > viewInfo.baseMipLevel) ? (textureInfo.levelCount - viewInfo.baseMipLevel) : 1; - textureInfo.layerCount = (textureInfo.layerCount > viewInfo.baseArrayLayer) ? (textureInfo.layerCount - viewInfo.baseArrayLayer) : 1; + textureInfo.levelCount = viewInfo.levelCount; + textureInfo.layerCount = viewInfo.layerCount; return textureInfo; } diff --git a/src/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.cpp b/src/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.cpp index c99e5250e..82ef9a64f 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.cpp @@ -78,7 +78,40 @@ namespace Nz throw std::runtime_error("unhandled pixel format " + PixelFormatInfo::GetName(textureFormat)); } - m_framebuffer.Texture2D(attachment, ToOpenGL(OpenGLTexture::ToTextureTarget(glTexture.GetType())), glTexture.GetTexture().GetObjectId()); + if (glTexture.RequiresTextureViewEmulation()) + { + const TextureViewInfo& texViewInfo = glTexture.GetTextureViewInfo(); + if (texViewInfo.viewType != ImageType::E2D) + throw std::runtime_error("unrestricted texture views can only be used as 2D texture attachment"); + + const OpenGLTexture& parentTexture = *glTexture.GetParentTexture(); + + switch (parentTexture.GetType()) + { + case ImageType::Cubemap: + { + constexpr std::array faceTargets = { GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z }; + assert(texViewInfo.baseArrayLayer < faceTargets.size()); + + GLenum texTarget = faceTargets[texViewInfo.baseArrayLayer]; + m_framebuffer.Texture2D(GL_COLOR_ATTACHMENT0, texTarget, parentTexture.GetTexture().GetObjectId(), texViewInfo.baseMipLevel); + break; + } + + case ImageType::E1D: + case ImageType::E2D: + m_framebuffer.Texture2D(GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, parentTexture.GetTexture().GetObjectId(), texViewInfo.baseMipLevel); + break; + + case ImageType::E1D_Array: + case ImageType::E2D_Array: + case ImageType::E3D: + m_framebuffer.TextureLayer(GL_COLOR_ATTACHMENT0, parentTexture.GetTexture().GetObjectId(), texViewInfo.baseArrayLayer, texViewInfo.baseMipLevel); + break; + } + } + else + m_framebuffer.Texture2D(attachment, ToOpenGL(OpenGLTexture::ToTextureTarget(glTexture.GetType())), glTexture.GetTexture().GetObjectId()); } GLenum status = m_framebuffer.Check(); diff --git a/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp b/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp index 0d117244e..1f578fde7 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp @@ -69,6 +69,7 @@ namespace Nz NazaraAssert(viewInfo.layerCount <= m_parentTexture->m_textureInfo.layerCount - viewInfo.baseArrayLayer, "layer count exceeds number of layers"); NazaraAssert(viewInfo.levelCount <= m_parentTexture->m_textureInfo.levelCount - viewInfo.baseMipLevel, "level count exceeds number of levels"); + m_textureInfo = ApplyView(m_parentTexture->m_textureInfo, viewInfo); m_viewInfo = viewInfo; // Try to use texture views if supported (core in GL 4.3 or extension) @@ -77,11 +78,10 @@ namespace Nz if (m_texture.Create(*m_parentTexture->m_texture.GetDevice())) { auto format = DescribeTextureFormat(viewInfo.reinterpretFormat); - GLenum target = ToOpenGL(ToTextureTarget(viewInfo.viewType)); context.ClearErrorStack(); - m_texture.TextureView(target, m_parentTexture->m_texture.GetObjectId(), format->internalFormat, viewInfo.baseMipLevel, viewInfo.levelCount, viewInfo.baseArrayLayer, viewInfo.layerCount); + m_texture.TextureView(ToTextureTarget(viewInfo.viewType), m_parentTexture->m_texture.GetObjectId(), format->internalFormat, viewInfo.baseMipLevel, viewInfo.levelCount, viewInfo.baseArrayLayer, viewInfo.layerCount); if (!context.DidLastCallSucceed()) m_texture.Destroy(); diff --git a/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp b/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp index eef6e4ffa..80247c192 100644 --- a/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp +++ b/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp @@ -294,28 +294,39 @@ namespace Nz::GL if (texture.RequiresTextureViewEmulation()) { const TextureViewInfo& texViewInfo = texture.GetTextureViewInfo(); + if (texViewInfo.viewType != ImageType::E2D) + throw std::runtime_error("unrestricted texture views can only be used as 2D texture attachment"); - GLenum texTarget; - if (texture.GetType() == ImageType::Cubemap) + const OpenGLTexture& parentTexture = *texture.GetParentTexture(); + + switch (parentTexture.GetType()) { - constexpr std::array faceTargets = { GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z }; - assert(texViewInfo.baseArrayLayer < faceTargets.size()); - texTarget = faceTargets[texViewInfo.baseArrayLayer]; + case ImageType::Cubemap: + { + constexpr std::array faceTargets = { GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z }; + assert(texViewInfo.baseArrayLayer < faceTargets.size()); + + GLenum texTarget = faceTargets[texViewInfo.baseArrayLayer]; + framebuffer.Texture2D(GL_COLOR_ATTACHMENT0, texTarget, parentTexture.GetTexture().GetObjectId(), texViewInfo.baseMipLevel); + break; + } + + case ImageType::E1D: + case ImageType::E2D: + framebuffer.Texture2D(GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, parentTexture.GetTexture().GetObjectId(), texViewInfo.baseMipLevel); + break; + + case ImageType::E1D_Array: + case ImageType::E2D_Array: + case ImageType::E3D: + framebuffer.TextureLayer(GL_COLOR_ATTACHMENT0, parentTexture.GetTexture().GetObjectId(), texViewInfo.baseArrayLayer, texViewInfo.baseMipLevel); + break; } - else if (texture.GetType() == ImageType::E2D) - texTarget = GL_TEXTURE_2D; - else - throw std::runtime_error("unrestricted texture views are not supported on this device, blit is only permitted from/to a cubemap face or a 2D texture"); - - //TODO: Support texture arrays (one slice at a time) - - framebuffer.Texture2D(GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.GetParentTexture()->GetTexture().GetObjectId(), texture.GetTextureViewInfo().baseMipLevel); - } else { if (texture.GetTexture().GetTarget() != TextureTarget::Target2D) - throw std::runtime_error("blit is not yet supported from other texture type than 2D textures"); + throw std::runtime_error("blit is not yet supported from/to other texture type than 2D textures"); framebuffer.Texture2D(GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.GetTexture().GetObjectId(), 0); } diff --git a/src/Nazara/Renderer/Texture.cpp b/src/Nazara/Renderer/Texture.cpp index a760ad921..044e2c662 100644 --- a/src/Nazara/Renderer/Texture.cpp +++ b/src/Nazara/Renderer/Texture.cpp @@ -37,13 +37,32 @@ namespace Nz NazaraAssert(params.IsValid(), "Invalid TextureParams"); Nz::TextureInfo texParams; - texParams.depth = image.GetDepth(); texParams.height = image.GetHeight(); texParams.pixelFormat = image.GetFormat(); texParams.type = image.GetType(); texParams.width = image.GetWidth(); texParams.usageFlags = params.usageFlags; + switch (image.GetType()) + { + case ImageType::E1D: + case ImageType::E2D: + case ImageType::E3D: + break; + + case ImageType::E1D_Array: + texParams.layerCount = image.GetHeight(); + break; + + case ImageType::E2D_Array: + texParams.layerCount = image.GetDepth(); + break; + + case ImageType::Cubemap: + texParams.layerCount = 6; + break; + } + std::shared_ptr texture = params.renderDevice->InstantiateTexture(texParams); if (!texture->Update(image.GetConstPixels())) {