1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 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,
XB_FMT format)
{
return std::make_unique<CGLTexture>(width, height, format);
}
CGLTexture::CGLTexture(unsigned int width, unsigned int height, XB_FMT 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);
}
|