diff options
Diffstat (limited to 'xbmc/guilib/TextureGL.cpp')
-rw-r--r-- | xbmc/guilib/TextureGL.cpp | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/xbmc/guilib/TextureGL.cpp b/xbmc/guilib/TextureGL.cpp new file mode 100644 index 0000000..ef01bdf --- /dev/null +++ b/xbmc/guilib/TextureGL.cpp @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "TextureGL.h" + +#include "ServiceBroker.h" +#include "guilib/TextureManager.h" +#include "rendering/RenderSystem.h" +#include "settings/AdvancedSettings.h" +#include "utils/GLUtils.h" +#include "utils/MemUtils.h" +#include "utils/log.h" + +#include <memory> + +std::unique_ptr<CTexture> CTexture::CreateTexture(unsigned int width, + unsigned int height, + unsigned int format) +{ + return std::make_unique<CGLTexture>(width, height, format); +} + +CGLTexture::CGLTexture(unsigned int width, unsigned int height, unsigned int format) + : CTexture(width, height, format) +{ + unsigned int major, minor; + CServiceBroker::GetRenderSystem()->GetRenderVersion(major, minor); + if (major >= 3) + m_isOglVersion3orNewer = true; +} + +CGLTexture::~CGLTexture() +{ + DestroyTextureObject(); +} + +void CGLTexture::CreateTextureObject() +{ + glGenTextures(1, (GLuint*) &m_texture); +} + +void CGLTexture::DestroyTextureObject() +{ + if (m_texture) + CServiceBroker::GetGUI()->GetTextureManager().ReleaseHwTexture(m_texture); +} + +void CGLTexture::LoadToGPU() +{ + if (!m_pixels) + { + // nothing to load - probably same image (no change) + return; + } + if (m_texture == 0) + { + // Have OpenGL generate a texture object handle for us + // this happens only one time - the first time the texture is loaded + CreateTextureObject(); + } + + // Bind the texture object + glBindTexture(GL_TEXTURE_2D, m_texture); + + GLenum filter = (m_scalingMethod == TEXTURE_SCALING::NEAREST ? GL_NEAREST : GL_LINEAR); + + // Set the texture's stretching properties + if (IsMipmapped()) + { + GLenum mipmapFilter = (m_scalingMethod == TEXTURE_SCALING::NEAREST ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mipmapFilter); + +#ifndef HAS_GLES + // Lower LOD bias equals more sharpness, but less smooth animation + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -0.5f); + if (!m_isOglVersion3orNewer) + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); +#endif + } + else + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + unsigned int maxSize = CServiceBroker::GetRenderSystem()->GetMaxTextureSize(); + if (m_textureHeight > maxSize) + { + CLog::Log(LOGERROR, + "GL: Image height {} too big to fit into single texture unit, truncating to {}", + m_textureHeight, maxSize); + m_textureHeight = maxSize; + } + if (m_textureWidth > maxSize) + { + CLog::Log(LOGERROR, + "GL: Image width {} too big to fit into single texture unit, truncating to {}", + m_textureWidth, maxSize); +#ifndef HAS_GLES + glPixelStorei(GL_UNPACK_ROW_LENGTH, m_textureWidth); +#endif + m_textureWidth = maxSize; + } + +#ifndef HAS_GLES + GLenum format = GL_BGRA; + GLint numcomponents = GL_RGBA; + + switch (m_format) + { + case XB_FMT_DXT1: + format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + break; + case XB_FMT_DXT3: + format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + break; + case XB_FMT_DXT5: + case XB_FMT_DXT5_YCoCg: + format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + break; + case XB_FMT_RGB8: + format = GL_RGB; + numcomponents = GL_RGB; + break; + case XB_FMT_A8R8G8B8: + default: + break; + } + + if ((m_format & XB_FMT_DXT_MASK) == 0) + { + glTexImage2D(GL_TEXTURE_2D, 0, numcomponents, + m_textureWidth, m_textureHeight, 0, + format, GL_UNSIGNED_BYTE, m_pixels); + } + else + { + glCompressedTexImage2D(GL_TEXTURE_2D, 0, format, + m_textureWidth, m_textureHeight, 0, + GetPitch() * GetRows(), m_pixels); + } + + if (IsMipmapped() && m_isOglVersion3orNewer) + { + glGenerateMipmap(GL_TEXTURE_2D); + } + + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + +#else // GLES version + + // All incoming textures are BGRA, which GLES does not necessarily support. + // Some (most?) hardware supports BGRA textures via an extension. + // If not, we convert to RGBA first to avoid having to swizzle in shaders. + // Explicitly define GL_BGRA_EXT here in the case that it's not defined by + // system headers, and trust the extension list instead. +#ifndef GL_BGRA_EXT +#define GL_BGRA_EXT 0x80E1 +#endif + + GLint internalformat; + GLenum pixelformat; + + switch (m_format) + { + default: + case XB_FMT_RGBA8: + internalformat = pixelformat = GL_RGBA; + break; + case XB_FMT_RGB8: + internalformat = pixelformat = GL_RGB; + break; + case XB_FMT_A8R8G8B8: + if (CServiceBroker::GetRenderSystem()->IsExtSupported("GL_EXT_texture_format_BGRA8888") || + CServiceBroker::GetRenderSystem()->IsExtSupported("GL_IMG_texture_format_BGRA8888")) + { + internalformat = pixelformat = GL_BGRA_EXT; + } + else if (CServiceBroker::GetRenderSystem()->IsExtSupported("GL_APPLE_texture_format_BGRA8888")) + { + // Apple's implementation does not conform to spec. Instead, they require + // differing format/internalformat, more like GL. + internalformat = GL_RGBA; + pixelformat = GL_BGRA_EXT; + } + else + { + SwapBlueRed(m_pixels, m_textureHeight, GetPitch()); + internalformat = pixelformat = GL_RGBA; + } + break; + } + glTexImage2D(GL_TEXTURE_2D, 0, internalformat, m_textureWidth, m_textureHeight, 0, + pixelformat, GL_UNSIGNED_BYTE, m_pixels); + + if (IsMipmapped()) + { + glGenerateMipmap(GL_TEXTURE_2D); + } + +#endif + VerifyGLState(); + + if (!m_bCacheMemory) + { + KODI::MEMORY::AlignedFree(m_pixels); + m_pixels = NULL; + } + + m_loadedToGPU = true; +} + +void CGLTexture::BindToUnit(unsigned int unit) +{ + glActiveTexture(GL_TEXTURE0 + unit); + glBindTexture(GL_TEXTURE_2D, m_texture); +} + |