axmol/core/renderer/backend/opengl/TextureGL.cpp

382 lines
12 KiB
C++
Raw Normal View History

2019-11-23 20:27:39 +08:00
/****************************************************************************
Copyright (c) 2018-2019 Xiamen Yaji Software Co., Ltd.
2022-10-01 16:24:52 +08:00
https://axmolengine.github.io/
2019-11-23 20:27:39 +08:00
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
2021-12-25 10:04:45 +08:00
2019-11-23 20:27:39 +08:00
#include "TextureGL.h"
#include "base/EventListenerCustom.h"
#include "base/EventDispatcher.h"
#include "base/EventType.h"
#include "base/Director.h"
#include "platform/PlatformConfig.h"
#include "renderer/backend/opengl/MacrosGL.h"
2019-11-23 20:27:39 +08:00
#include "renderer/backend/opengl/UtilsGL.h"
NS_AX_BACKEND_BEGIN
2019-11-23 20:27:39 +08:00
2021-12-25 10:04:45 +08:00
#define ISPOW2(n) (((n) & (n - 1)) == 0)
2019-11-23 20:27:39 +08:00
2021-12-25 10:04:45 +08:00
namespace
{
bool isMipmapEnabled(GLint filter)
{
switch (filter)
2019-11-23 20:27:39 +08:00
{
2021-12-25 10:04:45 +08:00
case GL_LINEAR_MIPMAP_LINEAR:
case GL_LINEAR_MIPMAP_NEAREST:
case GL_NEAREST_MIPMAP_NEAREST:
case GL_NEAREST_MIPMAP_LINEAR:
return true;
default:
break;
2019-11-23 20:27:39 +08:00
}
2021-12-25 10:04:45 +08:00
return false;
2019-11-23 20:27:39 +08:00
}
2021-12-25 10:04:45 +08:00
} // namespace
2019-11-23 20:27:39 +08:00
/// CLASS TextureInfoGL
2020-02-15 02:36:02 +08:00
void TextureInfoGL::applySampler(const SamplerDescriptor& descriptor, bool isPow2, bool hasMipmaps, GLenum target)
2019-11-23 20:27:39 +08:00
{
if (descriptor.magFilter != SamplerFilter::DONT_CARE)
{
magFilterGL = UtilsGL::toGLMagFilter(descriptor.magFilter);
}
if (descriptor.minFilter != SamplerFilter::DONT_CARE)
{
minFilterGL = UtilsGL::toGLMinFilter(descriptor.minFilter, hasMipmaps, isPow2);
}
if (descriptor.sAddressMode != SamplerAddressMode::DONT_CARE)
{
sAddressModeGL = UtilsGL::toGLAddressMode(descriptor.sAddressMode, isPow2);
}
if (descriptor.tAddressMode != SamplerAddressMode::DONT_CARE)
{
tAddressModeGL = UtilsGL::toGLAddressMode(descriptor.tAddressMode, isPow2);
}
2020-02-15 02:36:02 +08:00
// apply sampler for all internal textures
2023-03-28 00:07:33 +08:00
foreachTextures([this, target](GLuint texID, int index) {
2023-08-31 18:59:12 +08:00
glBindTexture(target, textures[index]);
2020-02-15 02:36:02 +08:00
setCurrentTexParameters(target);
2023-08-31 18:59:12 +08:00
glBindTexture(target, 0); // unbind
2023-03-28 00:07:33 +08:00
});
2019-11-23 20:27:39 +08:00
}
2020-02-15 02:36:02 +08:00
void TextureInfoGL::setCurrentTexParameters(GLenum target)
2019-11-23 20:27:39 +08:00
{
2020-02-15 02:36:02 +08:00
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, minFilterGL);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, magFilterGL);
glTexParameteri(target, GL_TEXTURE_WRAP_S, sAddressModeGL);
glTexParameteri(target, GL_TEXTURE_WRAP_T, tAddressModeGL);
}
2020-08-29 16:56:48 +08:00
void TextureInfoGL::apply(int slot, int index, GLenum target) const
2020-02-15 02:36:02 +08:00
{
2023-08-31 18:59:12 +08:00
glActiveTexture(GL_TEXTURE0 + slot);
glBindTexture(target, index < AX_META_TEXTURES ? textures[index] : textures[0]);
2020-02-15 02:36:02 +08:00
}
GLuint TextureInfoGL::ensure(int index, GLenum target)
{
2022-07-16 10:43:05 +08:00
if (index >= AX_META_TEXTURES)
2021-12-25 10:04:45 +08:00
return 0;
2020-08-29 16:56:48 +08:00
// glActiveTexture(GL_TEXTURE0 + index);
2020-02-15 02:36:02 +08:00
auto& texID = this->textures[index];
if (!texID)
glGenTextures(1, &texID);
2023-08-31 18:59:12 +08:00
glBindTexture(target, texID);
2020-02-15 02:36:02 +08:00
2021-12-25 10:04:45 +08:00
setCurrentTexParameters(target); // set once
2020-02-15 02:36:02 +08:00
2021-12-25 10:04:45 +08:00
if (this->maxIdx < index)
this->maxIdx = index;
2019-11-23 20:27:39 +08:00
2020-02-15 02:36:02 +08:00
return texID;
}
void TextureInfoGL::recreateAll(GLenum target)
{
int idx = 0;
for (auto&& texID : textures)
2021-12-25 10:04:45 +08:00
{
if (texID)
{
glDeleteTextures(1, &texID);
texID = 0;
ensure(idx, target);
}
++idx;
}
}
/// CLASS Texture2DGL
2020-02-15 02:58:41 +08:00
Texture2DGL::Texture2DGL(const TextureDescriptor& descriptor)
2020-02-15 02:36:02 +08:00
{
2019-11-23 20:27:39 +08:00
updateTextureDescriptor(descriptor);
2022-07-16 10:43:05 +08:00
#if AX_ENABLE_CACHE_TEXTURE_DATA
2019-11-23 20:27:39 +08:00
// Listen this event to restored texture id after coming to foreground on Android.
2021-12-25 10:04:45 +08:00
_backToForegroundListener = EventListenerCustom::create(EVENT_RENDERER_RECREATED, [this](EventCustom*) {
_textureInfo.recreateAll(GL_TEXTURE_2D);
this->initWithZeros();
2019-11-23 20:27:39 +08:00
});
Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(_backToForegroundListener, -1);
#endif
}
2022-08-08 18:02:17 +08:00
void Texture2DGL::updateTextureDescriptor(const ax::backend::TextureDescriptor& descriptor, int index)
{
TextureBackend::updateTextureDescriptor(descriptor, index);
2021-12-25 10:04:45 +08:00
UtilsGL::toGLTypes(descriptor.textureFormat, _textureInfo.internalFormat, _textureInfo.format, _textureInfo.type,
_isCompressed);
updateSamplerDescriptor(descriptor.samplerDescriptor);
if (descriptor.textureUsage == TextureUsage::RENDER_TARGET)
initWithZeros();
2019-11-23 20:27:39 +08:00
}
void Texture2DGL::initWithZeros()
{
// !!!Only used for depth stencil render buffer
2021-12-25 10:04:45 +08:00
// For example, a texture used as depth buffer will not invoke updateData(), see cpp-tests 'Effect Basic/Effects
// Advanced'.
// FIXME: Don't call at Texture2DGL::updateTextureDescriptor, when the texture is compressed, initWithZeros will
// cause GL Error: 0x501 We call at here once to ensure depth buffer works well. Ensure the final data size at least
// 4 byte
_width = (std::max)(_width, (uint32_t)1);
_height = (std::max)(_height, (uint32_t)1);
_bitsPerPixel = (std::max)(_bitsPerPixel, (uint8_t)(8 * 4));
2021-12-25 10:04:45 +08:00
auto size = _width * _height * _bitsPerPixel / 8;
2019-11-23 20:27:39 +08:00
uint8_t* data = (uint8_t*)malloc(size);
memset(data, 0, size);
updateData(data, _width, _height, 0);
free(data);
}
Texture2DGL::~Texture2DGL()
{
2022-07-16 10:43:05 +08:00
#if AX_ENABLE_CACHE_TEXTURE_DATA
2019-11-23 20:27:39 +08:00
Director::getInstance()->getEventDispatcher()->removeEventListener(_backToForegroundListener);
#endif
}
2021-12-25 10:04:45 +08:00
void Texture2DGL::updateSamplerDescriptor(const SamplerDescriptor& sampler)
{
2019-11-23 20:27:39 +08:00
bool isPow2 = ISPOW2(_width) && ISPOW2(_height);
2020-02-15 02:36:02 +08:00
_textureInfo.applySampler(sampler, isPow2, _hasMipmaps, GL_TEXTURE_2D);
2019-11-23 20:27:39 +08:00
}
2021-12-25 10:04:45 +08:00
void Texture2DGL::updateData(uint8_t* data, std::size_t width, std::size_t height, std::size_t level, int index)
2019-11-23 20:27:39 +08:00
{
2021-12-25 10:04:45 +08:00
if (!_textureInfo.ensure(index, GL_TEXTURE_2D))
return;
2020-02-14 15:18:56 +08:00
2021-12-25 10:04:45 +08:00
// Set the row align only when mipmapsNum == 1 and the data is uncompressed
2019-11-23 20:27:39 +08:00
auto mipmapEnalbed = isMipmapEnabled(_textureInfo.minFilterGL) || isMipmapEnabled(_textureInfo.magFilterGL);
2021-12-25 10:04:45 +08:00
if (!mipmapEnalbed)
2019-11-23 20:27:39 +08:00
{
unsigned int bytesPerRow = width * _bitsPerPixel / 8;
2019-11-23 20:27:39 +08:00
2021-12-25 10:04:45 +08:00
if (bytesPerRow % 8 == 0)
2019-11-23 20:27:39 +08:00
{
glPixelStorei(GL_UNPACK_ALIGNMENT, 8);
}
2021-12-25 10:04:45 +08:00
else if (bytesPerRow % 4 == 0)
2019-11-23 20:27:39 +08:00
{
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
}
2021-12-25 10:04:45 +08:00
else if (bytesPerRow % 2 == 0)
2019-11-23 20:27:39 +08:00
{
glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
}
else
{
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
}
}
else
{
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
}
2021-12-25 10:04:45 +08:00
glTexImage2D(GL_TEXTURE_2D, level, _textureInfo.internalFormat, width, height,
0, // border
_textureInfo.format, _textureInfo.type, data);
2019-11-23 20:27:39 +08:00
CHECK_GL_ERROR_DEBUG();
2021-12-25 10:04:45 +08:00
if (!_hasMipmaps && level > 0)
2019-11-23 20:27:39 +08:00
_hasMipmaps = true;
}
2021-12-25 10:04:45 +08:00
void Texture2DGL::updateCompressedData(uint8_t* data,
std::size_t width,
std::size_t height,
std::size_t dataLen,
std::size_t level,
int index)
2019-11-23 20:27:39 +08:00
{
2021-12-25 10:04:45 +08:00
if (!_textureInfo.ensure(index, GL_TEXTURE_2D))
return;
2019-11-23 20:27:39 +08:00
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
2021-12-25 10:04:45 +08:00
glCompressedTexImage2D(GL_TEXTURE_2D, level, _textureInfo.internalFormat, (GLsizei)width, (GLsizei)height,
0, // border
dataLen, data);
2019-11-23 20:27:39 +08:00
CHECK_GL_ERROR_DEBUG();
2021-12-25 10:04:45 +08:00
if (!_hasMipmaps && level > 0)
2019-11-23 20:27:39 +08:00
_hasMipmaps = true;
}
2021-12-25 10:04:45 +08:00
void Texture2DGL::updateSubData(std::size_t xoffset,
std::size_t yoffset,
std::size_t width,
std::size_t height,
std::size_t level,
uint8_t* data,
int index)
2019-11-23 20:27:39 +08:00
{
2021-12-25 10:04:45 +08:00
if (!_textureInfo.ensure(index, GL_TEXTURE_2D))
return;
glTexSubImage2D(GL_TEXTURE_2D, level, xoffset, yoffset, width, height, _textureInfo.format, _textureInfo.type,
2019-11-23 20:27:39 +08:00
data);
CHECK_GL_ERROR_DEBUG();
2021-12-25 10:04:45 +08:00
if (!_hasMipmaps && level > 0)
2019-11-23 20:27:39 +08:00
_hasMipmaps = true;
}
2021-12-25 10:04:45 +08:00
void Texture2DGL::updateCompressedSubData(std::size_t xoffset,
std::size_t yoffset,
std::size_t width,
std::size_t height,
std::size_t dataLen,
std::size_t level,
uint8_t* data,
int index)
2019-11-23 20:27:39 +08:00
{
2021-12-25 10:04:45 +08:00
if (!_textureInfo.ensure(index, GL_TEXTURE_2D))
return;
glCompressedTexSubImage2D(GL_TEXTURE_2D, level, xoffset, yoffset, width, height, _textureInfo.internalFormat,
dataLen, data);
2019-11-23 20:27:39 +08:00
CHECK_GL_ERROR_DEBUG();
2021-12-25 10:04:45 +08:00
if (!_hasMipmaps && level > 0)
2019-11-23 20:27:39 +08:00
_hasMipmaps = true;
}
void Texture2DGL::generateMipmaps()
{
if (TextureUsage::RENDER_TARGET == _textureUsage)
return;
2021-12-25 10:04:45 +08:00
if (!_hasMipmaps)
2019-11-23 20:27:39 +08:00
{
_hasMipmaps = true;
2023-08-31 18:59:12 +08:00
glBindTexture(GL_TEXTURE_2D, this->getHandler());
2019-11-23 20:27:39 +08:00
glGenerateMipmap(GL_TEXTURE_2D);
}
}
/// CLASS TextureCubeGL
2019-11-23 20:27:39 +08:00
TextureCubeGL::TextureCubeGL(const TextureDescriptor& descriptor)
{
assert(_width == _height);
_textureType = TextureType::TEXTURE_CUBE;
2020-02-15 02:58:41 +08:00
updateTextureDescriptor(descriptor);
2019-11-23 20:27:39 +08:00
2022-07-16 10:43:05 +08:00
#if AX_ENABLE_CACHE_TEXTURE_DATA
2019-11-23 20:27:39 +08:00
// Listen this event to restored texture id after coming to foreground on Android.
2021-12-25 10:04:45 +08:00
_backToForegroundListener = EventListenerCustom::create(
EVENT_COME_TO_FOREGROUND, [this](EventCustom*) { _textureInfo.recreateAll(GL_TEXTURE_CUBE_MAP); });
2019-11-23 20:27:39 +08:00
Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(_backToForegroundListener, -1);
#endif
CHECK_GL_ERROR_DEBUG();
}
2022-08-08 18:02:17 +08:00
void TextureCubeGL::updateTextureDescriptor(const ax::backend::TextureDescriptor& descriptor, int index)
2019-11-23 20:27:39 +08:00
{
2020-02-15 02:58:41 +08:00
backend::TextureCubemapBackend::updateTextureDescriptor(descriptor, index);
2021-12-25 10:04:45 +08:00
UtilsGL::toGLTypes(descriptor.textureFormat, _textureInfo.internalFormat, _textureInfo.format, _textureInfo.type,
_isCompressed);
2020-02-15 02:36:02 +08:00
updateSamplerDescriptor(descriptor.samplerDescriptor);
2019-11-23 20:27:39 +08:00
}
TextureCubeGL::~TextureCubeGL()
{
2022-07-16 10:43:05 +08:00
#if AX_ENABLE_CACHE_TEXTURE_DATA
2019-11-23 20:27:39 +08:00
Director::getInstance()->getEventDispatcher()->removeEventListener(_backToForegroundListener);
#endif
}
2021-12-25 10:04:45 +08:00
void TextureCubeGL::updateSamplerDescriptor(const SamplerDescriptor& sampler)
2019-11-23 20:27:39 +08:00
{
2020-02-15 02:36:02 +08:00
_textureInfo.applySampler(sampler, true, _hasMipmaps, GL_TEXTURE_CUBE_MAP);
2019-11-23 20:27:39 +08:00
}
2021-12-25 10:04:45 +08:00
void TextureCubeGL::updateFaceData(TextureCubeFace side, void* data, int index)
{
if (!_textureInfo.ensure(index, GL_TEXTURE_CUBE_MAP))
return;
2019-11-23 20:27:39 +08:00
CHECK_GL_ERROR_DEBUG();
int i = static_cast<int>(side);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
2021-12-25 10:04:45 +08:00
0, // level
_textureInfo.internalFormat, _width, _height,
0, // border
_textureInfo.format, _textureInfo.type, data);
2019-11-23 20:27:39 +08:00
CHECK_GL_ERROR_DEBUG();
2023-08-31 18:59:12 +08:00
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
2019-11-23 20:27:39 +08:00
}
void TextureCubeGL::generateMipmaps()
{
if (TextureUsage::RENDER_TARGET == _textureUsage)
return;
2021-12-25 10:04:45 +08:00
if (!_hasMipmaps)
2019-11-23 20:27:39 +08:00
{
_hasMipmaps = true;
2023-08-31 18:59:12 +08:00
glBindTexture(GL_TEXTURE_CUBE_MAP, this->getHandler());
2019-11-23 20:27:39 +08:00
glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
}
}
NS_AX_BACKEND_END