diff options
author | sarbes <sarbes@kodi.tv> | 2024-05-05 19:55:29 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-05 19:55:29 +0200 |
commit | caa22c102501cee860ceb8ee22c3955c579ae325 (patch) | |
tree | eea45a3940212f8bf87ae0e4985cd0e013c371fb | |
parent | 222259a067633679d027bfa227f55d9879d2a290 (diff) | |
parent | 8c29d2ec8a84654cf5d38b428a7d4be98f2d2e91 (diff) | |
download | xbmc-caa22c102501cee860ceb8ee22c3955c579ae325.tar.xz |
Merge pull request #24508 from sarbes/texture-refactor
Refactoring Texture Handling
-rw-r--r-- | xbmc/guilib/CMakeLists.txt | 2 | ||||
-rw-r--r-- | xbmc/guilib/Texture.cpp | 194 | ||||
-rw-r--r-- | xbmc/guilib/Texture.h | 75 | ||||
-rw-r--r-- | xbmc/guilib/TextureBase.cpp | 413 | ||||
-rw-r--r-- | xbmc/guilib/TextureBase.h | 117 | ||||
-rw-r--r-- | xbmc/guilib/TextureFormats.h | 155 |
6 files changed, 700 insertions, 256 deletions
diff --git a/xbmc/guilib/CMakeLists.txt b/xbmc/guilib/CMakeLists.txt index 3e936cd9b9..a4c3957f55 100644 --- a/xbmc/guilib/CMakeLists.txt +++ b/xbmc/guilib/CMakeLists.txt @@ -66,6 +66,7 @@ set(SOURCES DDSImage.cpp TextureBundle.cpp TextureBundleXBT.cpp Texture.cpp + TextureBase.cpp TextureManager.cpp VisibleEffect.cpp XBTF.cpp @@ -148,6 +149,7 @@ set(HEADERS DDSImage.h LocalizeStrings.h StereoscopicsManager.h Texture.h + TextureBase.h TextureBundle.h TextureBundleXBT.h TextureManager.h diff --git a/xbmc/guilib/Texture.cpp b/xbmc/guilib/Texture.cpp index cfc506d48c..af97003663 100644 --- a/xbmc/guilib/Texture.cpp +++ b/xbmc/guilib/Texture.cpp @@ -15,6 +15,7 @@ #include "filesystem/File.h" #include "filesystem/ResourceFile.h" #include "filesystem/XbtFile.h" +#include "guilib/TextureBase.h" #include "guilib/iimage.h" #include "guilib/imagefactory.h" #include "utils/URIUtils.h" @@ -50,70 +51,6 @@ CTexture::~CTexture() m_pixels = NULL; } -void CTexture::Allocate(unsigned int width, unsigned int height, XB_FMT format) -{ - m_imageWidth = m_originalWidth = width; - m_imageHeight = m_originalHeight = height; - m_format = format; - m_orientation = 0; - - m_textureWidth = m_imageWidth; - m_textureHeight = m_imageHeight; - - if (m_format & XB_FMT_DXT_MASK) - { - while (GetPitch() < CServiceBroker::GetRenderSystem()->GetMinDXTPitch()) - m_textureWidth += GetBlockSize(); - } - - if (!CServiceBroker::GetRenderSystem()->SupportsNPOT((m_format & XB_FMT_DXT_MASK) != 0)) - { - m_textureWidth = PadPow2(m_textureWidth); - m_textureHeight = PadPow2(m_textureHeight); - } - - if (m_format & XB_FMT_DXT_MASK) - { - // DXT textures must be a multiple of 4 in width and height - m_textureWidth = ((m_textureWidth + 3) / 4) * 4; - m_textureHeight = ((m_textureHeight + 3) / 4) * 4; - } - else - { - // align all textures so that they have an even width - // in some circumstances when we downsize a thumbnail - // which has an uneven number of pixels in width - // we crash in CPicture::ScaleImage in ffmpegs swscale - // because it tries to access beyond the source memory - // (happens on osx and ios) - // UPDATE: don't just update to be on an even width; - // ffmpegs swscale relies on a 16-byte stride on some systems - // so the textureWidth needs to be a multiple of 16. see ffmpeg - // swscale headers for more info. - m_textureWidth = ((m_textureWidth + 15) / 16) * 16; - } - - // check for max texture size - #define CLAMP(x, y) { if (x > y) x = y; } - CLAMP(m_textureWidth, CServiceBroker::GetRenderSystem()->GetMaxTextureSize()); - CLAMP(m_textureHeight, CServiceBroker::GetRenderSystem()->GetMaxTextureSize()); - CLAMP(m_imageWidth, m_textureWidth); - CLAMP(m_imageHeight, m_textureHeight); - - KODI::MEMORY::AlignedFree(m_pixels); - m_pixels = NULL; - if (GetPitch() * GetRows() > 0) - { - size_t size = GetPitch() * GetRows(); - m_pixels = static_cast<unsigned char*>(KODI::MEMORY::AlignedMalloc(size, 32)); - - if (m_pixels == nullptr) - { - CLog::Log(LOGERROR, "{} - Could not allocate {} bytes. Out of memory.", __FUNCTION__, size); - } - } -} - void CTexture::Update(unsigned int width, unsigned int height, unsigned int pitch, @@ -156,39 +93,6 @@ void CTexture::Update(unsigned int width, LoadToGPU(); } -void CTexture::ClampToEdge() -{ - if (m_pixels == nullptr) - return; - - unsigned int imagePitch = GetPitch(m_imageWidth); - unsigned int imageRows = GetRows(m_imageHeight); - unsigned int texturePitch = GetPitch(m_textureWidth); - unsigned int textureRows = GetRows(m_textureHeight); - if (imagePitch < texturePitch) - { - unsigned int blockSize = GetBlockSize(); - unsigned char *src = m_pixels + imagePitch - blockSize; - unsigned char *dst = m_pixels; - for (unsigned int y = 0; y < imageRows; y++) - { - for (unsigned int x = imagePitch; x < texturePitch; x += blockSize) - memcpy(dst + x, src, blockSize); - dst += texturePitch; - } - } - - if (imageRows < textureRows) - { - unsigned char *dst = m_pixels + imageRows * texturePitch; - for (unsigned int y = imageRows; y < textureRows; y++) - { - memcpy(dst, dst - texturePitch, texturePitch); - dst += texturePitch; - } - } -} - std::unique_ptr<CTexture> CTexture::LoadFromFile(const std::string& texturePath, unsigned int idealWidth, unsigned int idealHeight, @@ -397,99 +301,3 @@ bool CTexture::LoadPaletted(unsigned int width, ClampToEdge(); return true; } - -unsigned int CTexture::PadPow2(unsigned int x) -{ - --x; - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - return ++x; -} - -bool CTexture::SwapBlueRed(unsigned char* pixels, - unsigned int height, - unsigned int pitch, - unsigned int elements, - unsigned int offset) -{ - if (!pixels) return false; - unsigned char *dst = pixels; - for (unsigned int y = 0; y < height; y++) - { - dst = pixels + (y * pitch); - for (unsigned int x = 0; x < pitch; x+=elements) - std::swap(dst[x+offset], dst[x+2+offset]); - } - return true; -} - -unsigned int CTexture::GetPitch(unsigned int width) const -{ - switch (m_format) - { - case XB_FMT_DXT1: - return ((width + 3) / 4) * 8; - case XB_FMT_DXT3: - case XB_FMT_DXT5: - case XB_FMT_DXT5_YCoCg: - return ((width + 3) / 4) * 16; - case XB_FMT_A8: - return width; - case XB_FMT_RGB8: - return (((width + 1)* 3 / 4) * 4); - case XB_FMT_RGBA8: - case XB_FMT_A8R8G8B8: - default: - return width*4; - } -} - -unsigned int CTexture::GetRows(unsigned int height) const -{ - switch (m_format) - { - case XB_FMT_DXT1: - return (height + 3) / 4; - case XB_FMT_DXT3: - case XB_FMT_DXT5: - case XB_FMT_DXT5_YCoCg: - return (height + 3) / 4; - default: - return height; - } -} - -unsigned int CTexture::GetBlockSize() const -{ - switch (m_format) - { - case XB_FMT_DXT1: - return 8; - case XB_FMT_DXT3: - case XB_FMT_DXT5: - case XB_FMT_DXT5_YCoCg: - return 16; - case XB_FMT_A8: - return 1; - default: - return 4; - } -} - -bool CTexture::HasAlpha() const -{ - return m_hasAlpha; -} - -void CTexture::SetMipmapping() -{ - m_mipmapping = true; -} - -bool CTexture::IsMipmapped() const -{ - return m_mipmapping; -} diff --git a/xbmc/guilib/Texture.h b/xbmc/guilib/Texture.h index 5e32e60f8f..605d56b380 100644 --- a/xbmc/guilib/Texture.h +++ b/xbmc/guilib/Texture.h @@ -8,6 +8,7 @@ #pragma once +#include "guilib/TextureBase.h" #include "guilib/TextureFormats.h" #include <cstddef> @@ -21,17 +22,11 @@ class IImage; struct COLOR {unsigned char b,g,r,x;}; // Windows GDI expects 4bytes per color #pragma pack() -enum class TEXTURE_SCALING -{ - LINEAR, - NEAREST, -}; - /*! \ingroup textures -\brief Base texture class, subclasses of which depend on the render spec (DX, GL etc.) +\brief Texture loader class, subclasses of which depend on the render spec (DX, GL etc.) */ -class CTexture +class CTexture : public CTextureBase { public: @@ -86,47 +81,17 @@ public: const unsigned char* pixels, const COLOR* palette); - bool HasAlpha() const; - void SetAlpha(bool hasAlpha) { m_hasAlpha = hasAlpha; } - - void SetMipmapping(); - bool IsMipmapped() const; - void SetScalingMethod(TEXTURE_SCALING scalingMethod) { m_scalingMethod = scalingMethod; } - TEXTURE_SCALING GetScalingMethod() const { return m_scalingMethod; } - void SetCacheMemory(bool bCacheMemory) { m_bCacheMemory = bCacheMemory; } - bool GetCacheMemory() const { return m_bCacheMemory; } - - virtual void CreateTextureObject() = 0; - virtual void DestroyTextureObject() = 0; - virtual void LoadToGPU() = 0; - virtual void BindToUnit(unsigned int unit) = 0; - - unsigned char* GetPixels() const { return m_pixels; } - unsigned int GetPitch() const { return GetPitch(m_textureWidth); } - unsigned int GetRows() const { return GetRows(m_textureHeight); } - unsigned int GetTextureWidth() const { return m_textureWidth; } - unsigned int GetTextureHeight() const { return m_textureHeight; } - unsigned int GetWidth() const { return m_imageWidth; } - unsigned int GetHeight() const { return m_imageHeight; } - /*! \brief return the original width of the image, before scaling/cropping */ - unsigned int GetOriginalWidth() const { return m_originalWidth; } - /*! \brief return the original height of the image, before scaling/cropping */ - unsigned int GetOriginalHeight() const { return m_originalHeight; } - - int GetOrientation() const { return m_orientation; } - void SetOrientation(int orientation) { m_orientation = orientation; } - void Update(unsigned int width, unsigned int height, unsigned int pitch, XB_FMT format, const unsigned char* pixels, bool loadToGPU); - void Allocate(unsigned int width, unsigned int height, XB_FMT format); - void ClampToEdge(); - static unsigned int PadPow2(unsigned int x); - static bool SwapBlueRed(unsigned char *pixels, unsigned int height, unsigned int pitch, unsigned int elements = 4, unsigned int offset=0); + virtual void CreateTextureObject() = 0; + virtual void DestroyTextureObject() = 0; + virtual void LoadToGPU() = 0; + virtual void BindToUnit(unsigned int unit) = 0; private: // no copy constructor @@ -136,25 +101,9 @@ protected: bool LoadFromFileInMem(unsigned char* buffer, size_t size, const std::string& mimeType, unsigned int maxWidth, unsigned int maxHeight); bool LoadFromFileInternal(const std::string& texturePath, unsigned int maxWidth, unsigned int maxHeight, bool requirePixels, const std::string& strMimeType = ""); - bool LoadIImage(IImage* pImage, unsigned char* buffer, unsigned int bufSize, unsigned int width, unsigned int height); - // helpers for computation of texture parameters for compressed textures - unsigned int GetPitch(unsigned int width) const; - unsigned int GetRows(unsigned int height) const; - unsigned int GetBlockSize() const; - - unsigned int m_imageWidth; - unsigned int m_imageHeight; - unsigned int m_textureWidth; - unsigned int m_textureHeight; - unsigned int m_originalWidth; ///< original image width before scaling or cropping - unsigned int m_originalHeight; ///< original image height before scaling or cropping - - unsigned char* m_pixels; - bool m_loadedToGPU; - XB_FMT m_format; - int m_orientation; - bool m_hasAlpha = true ; - bool m_mipmapping = false ; - TEXTURE_SCALING m_scalingMethod = TEXTURE_SCALING::LINEAR; - bool m_bCacheMemory = false; + bool LoadIImage(IImage* pImage, + unsigned char* buffer, + unsigned int bufSize, + unsigned int width, + unsigned int height); }; diff --git a/xbmc/guilib/TextureBase.cpp b/xbmc/guilib/TextureBase.cpp new file mode 100644 index 0000000000..5c2c01e22b --- /dev/null +++ b/xbmc/guilib/TextureBase.cpp @@ -0,0 +1,413 @@ +/* + * 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 "TextureBase.h" + +#include "ServiceBroker.h" +#include "commons/ilog.h" +#include "guilib/TextureFormats.h" +#include "rendering/RenderSystem.h" +#include "utils/MemUtils.h" +#include "utils/log.h" + +#include <algorithm> +#include <cstdint> +#include <cstring> +#include <exception> +#include <utility> + +void CTextureBase::Allocate(uint32_t width, uint32_t height, XB_FMT format) +{ + SetKDFormat(format); + m_imageWidth = m_originalWidth = width; + m_imageHeight = m_originalHeight = height; + m_format = format; + m_orientation = 0; + + m_textureWidth = m_imageWidth; + m_textureHeight = m_imageHeight; + + if (!CServiceBroker::GetRenderSystem()->SupportsNPOT((m_textureFormat & KD_TEX_FMT_TYPE_MASK) != + KD_TEX_FMT_S3TC)) + { + m_textureWidth = PadPow2(m_textureWidth); + m_textureHeight = PadPow2(m_textureHeight); + } + + if ((m_textureFormat & KD_TEX_FMT_TYPE_MASK) == KD_TEX_FMT_S3TC) + { + // DXT textures must be a multiple of 4 in width and height + m_textureWidth = ((m_textureWidth + 3) / 4) * 4; + m_textureHeight = ((m_textureHeight + 3) / 4) * 4; + } + else + { + // align all textures so that they have an even width + // in some circumstances when we downsize a thumbnail + // which has an uneven number of pixels in width + // we crash in CPicture::ScaleImage in ffmpegs swscale + // because it tries to access beyond the source memory + // (happens on osx and ios) + // UPDATE: don't just update to be on an even width; + // ffmpegs swscale relies on a 16-byte stride on some systems + // so the textureWidth needs to be a multiple of 16. see ffmpeg + // swscale headers for more info. + m_textureWidth = ((m_textureWidth + 15) / 16) * 16; + } + + // check for max texture size + m_textureWidth = std::min(m_textureWidth, CServiceBroker::GetRenderSystem()->GetMaxTextureSize()); + m_textureHeight = + std::min(m_textureHeight, CServiceBroker::GetRenderSystem()->GetMaxTextureSize()); + m_imageWidth = std::min(m_imageWidth, m_textureWidth); + m_imageHeight = std::min(m_imageHeight, m_textureHeight); + + KODI::MEMORY::AlignedFree(m_pixels); + m_pixels = NULL; + + size_t size = GetPitch() * GetRows(); + + if (size == 0) + return; + + m_pixels = static_cast<unsigned char*>(KODI::MEMORY::AlignedMalloc(size, 32)); + + if (m_pixels == nullptr) + CLog::Log(LOGERROR, "{} - Could not allocate {} bytes. Out of memory.", __FUNCTION__, size); +} + +uint32_t CTextureBase::PadPow2(uint32_t x) +{ + --x; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return ++x; +} + +bool CTextureBase::SwapBlueRed( + uint8_t* pixels, uint32_t height, uint32_t pitch, uint32_t elements, uint32_t offset) +{ + if (!pixels) + return false; + uint8_t* dst = pixels; + for (uint32_t y = 0; y < height; y++) + { + dst = pixels + (y * pitch); + for (uint32_t x = 0; x < pitch; x += elements) + std::swap(dst[x + offset], dst[x + 2 + offset]); + } + return true; +} + +void CTextureBase::ClampToEdge() +{ + if (m_pixels == nullptr) + return; + + uint32_t imagePitch = GetPitch(m_imageWidth); + uint32_t imageRows = GetRows(m_imageHeight); + uint32_t texturePitch = GetPitch(m_textureWidth); + uint32_t textureRows = GetRows(m_textureHeight); + + if (imagePitch < texturePitch) + { + uint32_t blockSize = GetBlockSize(); + unsigned char* src = m_pixels + imagePitch - blockSize; + unsigned char* dst = m_pixels; + for (uint32_t y = 0; y < imageRows; y++) + { + for (uint32_t x = imagePitch; x < texturePitch; x += blockSize) + memcpy(dst + x, src, blockSize); + dst += texturePitch; + } + } + + if (imageRows < textureRows) + { + unsigned char* dst = m_pixels + imageRows * texturePitch; + for (uint32_t y = imageRows; y < textureRows; y++) + { + memcpy(dst, dst - texturePitch, texturePitch); + dst += texturePitch; + } + } +} + +uint32_t CTextureBase::GetPitch(uint32_t width) const +{ + uint32_t blockWidth = GetBlockWidth(); + uint32_t pitch = ((width + blockWidth - 1) / blockWidth) * GetBlockSize(); + + // For the GPU, RGB8 needs to be aligned to 32 bit + if (m_textureFormat == KD_TEX_FMT_SDR_RGB8) + pitch = ((pitch + 3) / 4) * 4; + + return pitch; +} + +uint32_t CTextureBase::GetRows(uint32_t height) const +{ + uint32_t blockHeight = GetBlockHeight(); + return (height + blockHeight - 1) / blockHeight; +} + +uint32_t CTextureBase::GetBlockWidth() const +{ + switch (m_textureFormat) + { + case KD_TEX_FMT_SDR_R8: + case KD_TEX_FMT_SDR_RG8: + case KD_TEX_FMT_SDR_R5G6B5: + case KD_TEX_FMT_SDR_RGB5_A1: + case KD_TEX_FMT_SDR_RGBA4: + case KD_TEX_FMT_SDR_RGB8: + case KD_TEX_FMT_SDR_RGBA8: + case KD_TEX_FMT_SDR_BGRA8: + case KD_TEX_FMT_HDR_R16f: + case KD_TEX_FMT_HDR_RG16f: + case KD_TEX_FMT_HDR_R11F_G11F_B10F: + case KD_TEX_FMT_HDR_RGB9_E5: + case KD_TEX_FMT_HDR_RGB10_A2: + case KD_TEX_FMT_HDR_RGBA16f: + return 1; + case KD_TEX_FMT_YUV_YUYV8: + return 2; + case KD_TEX_FMT_S3TC_RGB8: + case KD_TEX_FMT_S3TC_RGB8_A1: + case KD_TEX_FMT_S3TC_RGB8_A4: + case KD_TEX_FMT_S3TC_RGBA8: + case KD_TEX_FMT_RGTC_R11: + case KD_TEX_FMT_RGTC_RG11: + case KD_TEX_FMT_BPTC_RGB16F: + case KD_TEX_FMT_BPTC_RGBA8: + case KD_TEX_FMT_ETC1: + case KD_TEX_FMT_ETC2_RGB8: + case KD_TEX_FMT_ETC2_RGB8_A1: + case KD_TEX_FMT_ETC2_RGBA8: + case KD_TEX_FMT_ETC2_R11: + case KD_TEX_FMT_ETC2_RG11: + case KD_TEX_FMT_ASTC_LDR_4x4: + case KD_TEX_FMT_ASTC_HDR_4x4: + return 4; + case KD_TEX_FMT_ASTC_LDR_5x4: + case KD_TEX_FMT_ASTC_LDR_5x5: + case KD_TEX_FMT_ASTC_HDR_5x4: + case KD_TEX_FMT_ASTC_HDR_5x5: + return 5; + case KD_TEX_FMT_ASTC_LDR_6x5: + case KD_TEX_FMT_ASTC_LDR_6x6: + case KD_TEX_FMT_ASTC_HDR_6x5: + case KD_TEX_FMT_ASTC_HDR_6x6: + return 6; + case KD_TEX_FMT_ASTC_LDR_8x5: + case KD_TEX_FMT_ASTC_LDR_8x6: + case KD_TEX_FMT_ASTC_LDR_8x8: + case KD_TEX_FMT_ASTC_HDR_8x5: + case KD_TEX_FMT_ASTC_HDR_8x6: + case KD_TEX_FMT_ASTC_HDR_8x8: + return 8; + case KD_TEX_FMT_ASTC_LDR_10x5: + case KD_TEX_FMT_ASTC_LDR_10x6: + case KD_TEX_FMT_ASTC_LDR_10x8: + case KD_TEX_FMT_ASTC_LDR_10x10: + case KD_TEX_FMT_ASTC_HDR_10x5: + case KD_TEX_FMT_ASTC_HDR_10x6: + case KD_TEX_FMT_ASTC_HDR_10x8: + case KD_TEX_FMT_ASTC_HDR_10x10: + return 10; + case KD_TEX_FMT_ASTC_LDR_12x10: + case KD_TEX_FMT_ASTC_LDR_12x12: + case KD_TEX_FMT_ASTC_HDR_12x10: + case KD_TEX_FMT_ASTC_HDR_12x12: + return 12; + default: + return 1; + } +} + +uint32_t CTextureBase::GetBlockHeight() const +{ + switch (m_textureFormat) + { + case KD_TEX_FMT_SDR_R8: + case KD_TEX_FMT_SDR_RG8: + case KD_TEX_FMT_SDR_R5G6B5: + case KD_TEX_FMT_SDR_RGB5_A1: + case KD_TEX_FMT_SDR_RGBA4: + case KD_TEX_FMT_SDR_RGB8: + case KD_TEX_FMT_SDR_RGBA8: + case KD_TEX_FMT_SDR_BGRA8: + case KD_TEX_FMT_HDR_R16f: + case KD_TEX_FMT_HDR_RG16f: + case KD_TEX_FMT_HDR_R11F_G11F_B10F: + case KD_TEX_FMT_HDR_RGB9_E5: + case KD_TEX_FMT_HDR_RGB10_A2: + case KD_TEX_FMT_HDR_RGBA16f: + case KD_TEX_FMT_YUV_YUYV8: + return 1; + case KD_TEX_FMT_S3TC_RGB8: + case KD_TEX_FMT_S3TC_RGB8_A1: + case KD_TEX_FMT_S3TC_RGB8_A4: + case KD_TEX_FMT_S3TC_RGBA8: + case KD_TEX_FMT_RGTC_R11: + case KD_TEX_FMT_RGTC_RG11: + case KD_TEX_FMT_BPTC_RGB16F: + case KD_TEX_FMT_BPTC_RGBA8: + case KD_TEX_FMT_ETC1: + case KD_TEX_FMT_ETC2_RGB8: + case KD_TEX_FMT_ETC2_RGB8_A1: + case KD_TEX_FMT_ETC2_RGBA8: + case KD_TEX_FMT_ETC2_R11: + case KD_TEX_FMT_ETC2_RG11: + case KD_TEX_FMT_ASTC_LDR_4x4: + case KD_TEX_FMT_ASTC_LDR_5x4: + case KD_TEX_FMT_ASTC_HDR_4x4: + case KD_TEX_FMT_ASTC_HDR_5x4: + return 4; + case KD_TEX_FMT_ASTC_LDR_5x5: + case KD_TEX_FMT_ASTC_LDR_6x5: + case KD_TEX_FMT_ASTC_LDR_8x5: + case KD_TEX_FMT_ASTC_LDR_10x5: + case KD_TEX_FMT_ASTC_HDR_5x5: + case KD_TEX_FMT_ASTC_HDR_6x5: + case KD_TEX_FMT_ASTC_HDR_8x5: + case KD_TEX_FMT_ASTC_HDR_10x5: + return 5; + case KD_TEX_FMT_ASTC_LDR_6x6: + case KD_TEX_FMT_ASTC_LDR_8x6: + case KD_TEX_FMT_ASTC_LDR_10x6: + case KD_TEX_FMT_ASTC_HDR_6x6: + case KD_TEX_FMT_ASTC_HDR_8x6: + case KD_TEX_FMT_ASTC_HDR_10x6: + return 6; + case KD_TEX_FMT_ASTC_LDR_8x8: + case KD_TEX_FMT_ASTC_LDR_10x8: + case KD_TEX_FMT_ASTC_HDR_8x8: + case KD_TEX_FMT_ASTC_HDR_10x8: + return 8; + case KD_TEX_FMT_ASTC_LDR_10x10: + case KD_TEX_FMT_ASTC_LDR_12x10: + case KD_TEX_FMT_ASTC_HDR_10x10: + case KD_TEX_FMT_ASTC_HDR_12x10: + return 10; + case KD_TEX_FMT_ASTC_LDR_12x12: + case KD_TEX_FMT_ASTC_HDR_12x12: + return 12; + default: + return 4; + } +} + +uint32_t CTextureBase::GetBlockSize() const +{ + switch (m_textureFormat) + { + case KD_TEX_FMT_SDR_R8: + return 1; + case KD_TEX_FMT_SDR_RG8: + case KD_TEX_FMT_SDR_R5G6B5: + case KD_TEX_FMT_SDR_RGB5_A1: + case KD_TEX_FMT_SDR_RGBA4: + case KD_TEX_FMT_HDR_R16f: + return 2; + case KD_TEX_FMT_SDR_RGB8: + return 3; + case KD_TEX_FMT_SDR_RGBA8: + case KD_TEX_FMT_SDR_BGRA8: + case KD_TEX_FMT_HDR_RG16f: + case KD_TEX_FMT_HDR_R11F_G11F_B10F: + case KD_TEX_FMT_HDR_RGB9_E5: + case KD_TEX_FMT_HDR_RGB10_A2: + case KD_TEX_FMT_YUV_YUYV8: + return 4; + case KD_TEX_FMT_HDR_RGBA16f: + case KD_TEX_FMT_S3TC_RGB8: + case KD_TEX_FMT_S3TC_RGB8_A1: + case KD_TEX_FMT_RGTC_R11: + case KD_TEX_FMT_ETC1: + case KD_TEX_FMT_ETC2_RGB8: + case KD_TEX_FMT_ETC2_RGB8_A1: + case KD_TEX_FMT_ETC2_R11: + return 8; + case KD_TEX_FMT_S3TC_RGB8_A4: + case KD_TEX_FMT_S3TC_RGBA8: + case KD_TEX_FMT_RGTC_RG11: + case KD_TEX_FMT_BPTC_RGB16F: + case KD_TEX_FMT_BPTC_RGBA8: + case KD_TEX_FMT_ETC2_RG11: + case KD_TEX_FMT_ETC2_RGBA8: + case KD_TEX_FMT_ASTC_LDR_4x4: + case KD_TEX_FMT_ASTC_LDR_5x4: + case KD_TEX_FMT_ASTC_LDR_5x5: + case KD_TEX_FMT_ASTC_LDR_6x5: + case KD_TEX_FMT_ASTC_LDR_6x6: + case KD_TEX_FMT_ASTC_LDR_8x5: + case KD_TEX_FMT_ASTC_LDR_8x6: + case KD_TEX_FMT_ASTC_LDR_8x8: + case KD_TEX_FMT_ASTC_LDR_10x5: + case KD_TEX_FMT_ASTC_LDR_10x6: + case KD_TEX_FMT_ASTC_LDR_10x8: + case KD_TEX_FMT_ASTC_LDR_10x10: + case KD_TEX_FMT_ASTC_LDR_12x10: + case KD_TEX_FMT_ASTC_LDR_12x12: + case KD_TEX_FMT_ASTC_HDR_4x4: + case KD_TEX_FMT_ASTC_HDR_5x4: + case KD_TEX_FMT_ASTC_HDR_5x5: + case KD_TEX_FMT_ASTC_HDR_6x5: + case KD_TEX_FMT_ASTC_HDR_6x6: + case KD_TEX_FMT_ASTC_HDR_8x5: + case KD_TEX_FMT_ASTC_HDR_8x6: + case KD_TEX_FMT_ASTC_HDR_8x8: + case KD_TEX_FMT_ASTC_HDR_10x5: + case KD_TEX_FMT_ASTC_HDR_10x6: + case KD_TEX_FMT_ASTC_HDR_10x8: + case KD_TEX_FMT_ASTC_HDR_10x10: + case KD_TEX_FMT_ASTC_HDR_12x10: + case KD_TEX_FMT_ASTC_HDR_12x12: + return 16; + default: + return 4; + } +} + +void CTextureBase::SetKDFormat(XB_FMT xbFMT) +{ + switch (xbFMT) + { + case XB_FMT_DXT1: + m_textureFormat = KD_TEX_FMT_S3TC_RGB8; + return; + case XB_FMT_DXT3: + m_textureFormat = KD_TEX_FMT_S3TC_RGB8_A4; + return; + case XB_FMT_DXT5: + m_textureFormat = KD_TEX_FMT_S3TC_RGBA8; + return; + case XB_FMT_A8R8G8B8: + m_textureFormat = KD_TEX_FMT_SDR_BGRA8; + return; + case XB_FMT_A8: + m_textureFormat = KD_TEX_FMT_SDR_R8; + m_textureSwizzle = KD_TEX_SWIZ_111R; + return; + case XB_FMT_RGBA8: + m_textureFormat = KD_TEX_FMT_SDR_RGBA8; + return; + case XB_FMT_RGB8: + m_textureFormat = KD_TEX_FMT_SDR_RGB8; + return; + case XB_FMT_UNKNOWN: + case XB_FMT_DXT5_YCoCg: + default: + m_textureFormat = KD_TEX_FMT_UNKNOWN; + return; + } +} diff --git a/xbmc/guilib/TextureBase.h b/xbmc/guilib/TextureBase.h new file mode 100644 index 0000000000..bbabe2ae46 --- /dev/null +++ b/xbmc/guilib/TextureBase.h @@ -0,0 +1,117 @@ +/* + * 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. + */ + +#pragma once + +#include "guilib/TextureFormats.h" + +#include <memory> +#include <string> + +enum class TEXTURE_SCALING +{ + LINEAR, + NEAREST, +}; + +/*! +\ingroup textures +\brief Base texture class, which holds the state of the texture, as well as all conversion functions. +*/ +class CTextureBase +{ + +public: + CTextureBase() = default; + ~CTextureBase() = default; + + bool HasAlpha() const { return m_hasAlpha; } + void SetAlpha(bool hasAlpha) { m_hasAlpha = hasAlpha; } + + /*! \brief sets mipmapping. do not use in new code. will be replaced with proper scaling. */ + void SetMipmapping() { m_mipmapping = true; } + /*! \brief return true if we want to mipmap */ + bool IsMipmapped() const { return m_mipmapping; } + + /*! \brief sets the scaling method. scanout systems might support more than NN/linear. */ + void SetScalingMethod(TEXTURE_SCALING scalingMethod) { m_scalingMethod = scalingMethod; } + /*! \brief returns the scaling method. */ + TEXTURE_SCALING GetScalingMethod() const { return m_scalingMethod; } + + int32_t GetOrientation() const { return m_orientation; } + void SetOrientation(int orientation) { m_orientation = orientation; } + + /*! \brief retains a shadow copy of the texture on the CPU side. */ + void SetCacheMemory(bool bCacheMemory) { m_bCacheMemory = bCacheMemory; } + /*! \brief returns true if a shadow copy is kept on the CPU side. */ + bool GetCacheMemory() const { return m_bCacheMemory; } + + /*! \brief returns a pointer to the staging texture. */ + uint8_t* GetPixels() const { return m_pixels; } + + /*! \brief return the size of one row in bytes. */ + uint32_t GetPitch() const { return GetPitch(m_textureWidth); } + /*! \brief return the number of rows (number of blocks in the Y direction). */ + uint32_t GetRows() const { return GetRows(m_textureHeight); } + /*! \brief return the total width of the texture, which might be scaled to fit its displayed size. */ + uint32_t GetTextureWidth() const { return m_textureWidth; } + /*! \brief return the total height of the texture, which might be scaled to fit its displayed size. */ + uint32_t GetTextureHeight() const { return m_textureHeight; } + /*! \brief return the total width of "active" area, which might be equal or lower than the texture width due to alignment. */ + uint32_t GetWidth() const { return m_imageWidth; } + /*! \brief return the total height of "active" area, which might be equal or lower than the texture height due to alignment. */ + uint32_t GetHeight() const { return m_imageHeight; } + /*! \brief return the original width of the image, before scaling/cropping */ + uint32_t GetOriginalWidth() const { return m_originalWidth; } + /*! \brief return the original height of the image, before scaling/cropping */ + uint32_t GetOriginalHeight() const { return m_originalHeight; } + + // allocates staging texture space. + void Allocate(uint32_t width, uint32_t height, XB_FMT format); + void ClampToEdge(); + + /*! \brief rounds to power of two. deprecated. */ + static uint32_t PadPow2(uint32_t x); + /*! \brief swaps the blue/red channel. deprecated in this form. */ + static bool SwapBlueRed( + uint8_t* pixels, uint32_t height, uint32_t pitch, uint32_t elements = 4, uint32_t offset = 0); + +protected: + // helpers for computation of texture parameters for compressed textures + uint32_t GetPitch(uint32_t width) const; + uint32_t GetRows(uint32_t height) const; + uint32_t GetBlockWidth() const; + uint32_t GetBlockHeight() const; + /*! \brief return the size of a compression block (tile) in bytes. */ + uint32_t GetBlockSize() const; + + void SetKDFormat(XB_FMT xbFMT); + + uint32_t m_imageWidth{0}; + uint32_t m_imageHeight{0}; + uint32_t m_textureWidth{0}; + uint32_t m_textureHeight{0}; + uint32_t m_originalWidth{0}; ///< original image width before scaling or cropping + uint32_t m_originalHeight{0}; ///< original image height before scaling or cropping + + uint8_t* m_pixels{nullptr}; + bool m_loadedToGPU{false}; + + KD_TEX_FMT m_textureFormat{KD_TEX_FMT_UNKNOWN}; // new Kodi texture format + KD_TEX_SWIZ m_textureSwizzle{KD_TEX_SWIZ_RGBA}; + KD_TEX_COL m_textureColorspace{KD_TEX_COL_REC709}; + KD_TEX_TRANSFER m_textureTransfer{KD_TEX_TRANSFER_SRGB}; + KD_TEX_ALPHA m_textureAlpha{KD_TEX_ALPHA_STRAIGHT}; + + XB_FMT m_format{XB_FMT_UNKNOWN}; // legacy XB format, deprecated + int32_t m_orientation{0}; + bool m_hasAlpha{true}; + bool m_mipmapping{false}; + TEXTURE_SCALING m_scalingMethod{TEXTURE_SCALING::LINEAR}; + bool m_bCacheMemory{false}; +}; diff --git a/xbmc/guilib/TextureFormats.h b/xbmc/guilib/TextureFormats.h index 2aab71a947..5b7d87c5fb 100644 --- a/xbmc/guilib/TextureFormats.h +++ b/xbmc/guilib/TextureFormats.h @@ -25,4 +25,159 @@ enum XB_FMT XB_FMT_MASK = 0xFFFF, XB_FMT_OPAQUE = 0x10000, }; + +enum KD_TEX_FMT +{ + KD_TEX_FMT_UNKNOWN = 0x0000, + + // Legacy XB_FMT formats family + KD_TEX_FMT_LEGACY = 0x0000, + + // SDR texture family + KD_TEX_FMT_SDR = 0x1000, + KD_TEX_FMT_SDR_R8 = 0x1000, // 8bpp, single channel + KD_TEX_FMT_SDR_RG8 = 0x1100, // 16bpp, dual channel + KD_TEX_FMT_SDR_R5G6B5 = 0x1200, // 16bpp, 5/6 bit per color channel + KD_TEX_FMT_SDR_RGB5_A1 = 0x1300, // 16bpp, 5 bit per color channel, pt-alpha + KD_TEX_FMT_SDR_RGBA4 = 0x1400, // 16bpp, 4 bit per channel + KD_TEX_FMT_SDR_RGB8 = 0x1500, // 24bpp, 8 bit per channel, no alpha (unsuitable for GPUs!) + KD_TEX_FMT_SDR_RGBA8 = 0x1600, // 32bpp, 8 bit per channel, RGBA order + KD_TEX_FMT_SDR_BGRA8 = 0x1700, // 32bpp, 8 bit per channel, BGRA order + + // HDR texture family + KD_TEX_FMT_HDR = 0x2000, + KD_TEX_FMT_HDR_R16f = 0x2100, // 16bpp, single channel float + KD_TEX_FMT_HDR_RG16f = 0x2200, // 32bpp, dual channel float + KD_TEX_FMT_HDR_R11F_G11F_B10F = 0x2300, // 32bpp, 6e5/5e5 per color channel + KD_TEX_FMT_HDR_RGB9_E5 = 0x2400, // 32bpp, 9 bit color, shared 5 bit exponent + KD_TEX_FMT_HDR_RGB10_A2 = 0x2500, // 32bpp, 10 bit color, 2 bit alpha + KD_TEX_FMT_HDR_RGBA16f = 0x2600, // 64bpp, four channel float + + // YUV texture family + KD_TEX_FMT_YUV = 0x3000, + KD_TEX_FMT_YUV_YUYV8 = 0x3000, // 16bpp, 4:2:2 packed + + // S3TC texture family + KD_TEX_FMT_S3TC = 0x4000, + KD_TEX_FMT_S3TC_RGB8 = 0x4000, // 4bpp, RGB (BC1) + KD_TEX_FMT_S3TC_RGB8_A1 = 0x4100, // 4bpp, RGB, pt-alpha (BC1) + KD_TEX_FMT_S3TC_RGB8_A4 = 0x4200, // 8bpp, RGB, 4 bit alpha (BC2) + KD_TEX_FMT_S3TC_RGBA8 = 0x4300, // 8bpp, RGBA (BC3) + + // RGTC (LATC) texture family + KD_TEX_FMT_RGTC = 0x5000, + KD_TEX_FMT_RGTC_R11 = 0x5000, // 4bpp, single channel (BC4) + KD_TEX_FMT_RGTC_RG11 = 0x5100, // 8bpp, dual channel (BC5) + + // BPTC texture family + KD_TEX_FMT_BPTC = 0x6000, + KD_TEX_FMT_BPTC_RGB16F = 0x6000, // 8bpp, HDR (BC6H float) + KD_TEX_FMT_BPTC_RGBA8 = 0x6100, // 8bpp, LDR (BC7 unorm) + + // ETC1 texture family + KD_TEX_FMT_ETC1 = 0x7000, + KD_TEX_FMT_ETC1_RGB8 = 0x7000, // 4bpp, RGB + + // ETC2 texture family + KD_TEX_FMT_ETC2 = 0x8000, + KD_TEX_FMT_ETC2_R11 = 0x8100, // 4bpp, single channel (EAC) + KD_TEX_FMT_ETC2_RG11 = 0x8200, // 8bpp, dual channel (EAC) + KD_TEX_FMT_ETC2_RGB8 = 0x8300, // 4bpp, RGB + KD_TEX_FMT_ETC2_RGB8_A1 = 0x8400, // 4bpp, RGB, pt-alpha + KD_TEX_FMT_ETC2_RGBA8 = 0x8500, // 8bpp, RGB, alpha EAC + + // ASTC LDR texture family + // Bitrate varies from 8bpp (4x4 tile) to 0.89bpp (12x12 tile). + KD_TEX_FMT_ASTC_LDR = 0x9000, + KD_TEX_FMT_ASTC_LDR_4x4 = 0x9000, + KD_TEX_FMT_ASTC_LDR_5x4 = 0x9100, + KD_TEX_FMT_ASTC_LDR_5x5 = 0x9200, + KD_TEX_FMT_ASTC_LDR_6x5 = 0x9300, + KD_TEX_FMT_ASTC_LDR_6x6 = 0x9400, + KD_TEX_FMT_ASTC_LDR_8x5 = 0x9500, + KD_TEX_FMT_ASTC_LDR_8x6 = 0x9600, + KD_TEX_FMT_ASTC_LDR_8x8 = 0x9700, + KD_TEX_FMT_ASTC_LDR_10x5 = 0x9800, + KD_TEX_FMT_ASTC_LDR_10x6 = 0x9900, + KD_TEX_FMT_ASTC_LDR_10x8 = 0x9A00, + KD_TEX_FMT_ASTC_LDR_10x10 = 0x9B00, + KD_TEX_FMT_ASTC_LDR_12x10 = 0x9C00, + KD_TEX_FMT_ASTC_LDR_12x12 = 0x9D00, + + // ASTC HDR texture family + // Bitrate varies from 8bpp (4x4 tile) to 0.89bpp (12x12 tile). + KD_TEX_FMT_ASTC_HDR = 0xA000, + KD_TEX_FMT_ASTC_HDR_4x4 = 0xA000, + KD_TEX_FMT_ASTC_HDR_5x4 = 0xA100, + KD_TEX_FMT_ASTC_HDR_5x5 = 0xA200, + KD_TEX_FMT_ASTC_HDR_6x5 = 0xA300, + KD_TEX_FMT_ASTC_HDR_6x6 = 0xA400, + KD_TEX_FMT_ASTC_HDR_8x5 = 0xA500, + KD_TEX_FMT_ASTC_HDR_8x6 = 0xA600, + KD_TEX_FMT_ASTC_HDR_8x8 = 0xA700, + KD_TEX_FMT_ASTC_HDR_10x5 = 0xA800, + KD_TEX_FMT_ASTC_HDR_10x6 = 0xA900, + KD_TEX_FMT_ASTC_HDR_10x8 = 0xAA00, + KD_TEX_FMT_ASTC_HDR_10x10 = 0xAB00, + KD_TEX_FMT_ASTC_HDR_12x10 = 0xAC00, + KD_TEX_FMT_ASTC_HDR_12x12 = 0xAD00, + + KD_TEX_FMT_TYPE_MASK = 0xF000, + + KD_TEX_FMT_MASK = 0xFFFF, +}; + +// Alpha handling +enum KD_TEX_ALPHA +{ + KD_TEX_ALPHA_STRAIGHT = 0x00000, // Straight (unmultiplied) alpha + KD_TEX_ALPHA_OPAQUE = 0x10000, // No alpha + KD_TEX_ALPHA_PREMULTIPLIED = 0x20000, // Premultiplied alpha + + KD_TEX_ALPHA_MASK = 0xF0000, +}; + +// Texture component swizzle or effect +enum KD_TEX_SWIZ +{ + KD_TEX_SWIZ_RGBA = 0x000000, // No swizzling + KD_TEX_SWIZ_RGB1 = 0x100000, // Normal swizzle, ignoring alpha + KD_TEX_SWIZ_RRR1 = 0x200000, // Luminance + KD_TEX_SWIZ_111R = 0x300000, // Alpha + KD_TEX_SWIZ_RRRG = 0x400000, // Luminance-Alpha + KD_TEX_SWIZ_RRRR = 0x500000, // Intensity + KD_TEX_SWIZ_GGG1 = 0x600000, // Luminance (ETC1/BC1) + KD_TEX_SWIZ_111G = 0x700000, // Alpha (ETC1/BC1) + KD_TEX_SWIZ_GGGA = 0x800000, // Luminance-Alpha (BC2/BC3) + KD_TEX_SWIZ_GGGG = 0x900000, // Intensity (ETC1/BC1) + + KD_TEX_SWIZ_SDF = 0xa00000, // Red channel contains a SDF + KD_TEX_SWIZ_RGB_SDF = 0xb00000, // RGB8 texture with a SDF packed in the alpha channel + KD_TEX_SWIZ_MSDF = 0xc00000, // Encoded MSDF in the color channels, Alpha is ignored + + KD_TEX_SWIZ_MASK = 0xF00000, +}; + +// Color space +enum KD_TEX_COL +{ + KD_TEX_COL_REC709 = 0x0000000, // REC709/sRGB color space + KD_TEX_COL_REC2020 = 0x1000000, // REC2020 color space + + KD_TEX_COL_MASK = 0xF000000, +}; + +// Transfer function +enum KD_TEX_TRANSFER +{ + KD_TEX_TRANSFER_SRGB = 0x00000000, + KD_TEX_TRANSFER_REC709 = 0x10000000, + KD_TEX_TRANSFER_HLG = 0x20000000, + KD_TEX_TRANSFER_LINEAR = 0x30000000, + KD_TEX_TRANSFER_SQUARED = 0x40000000, + KD_TEX_TRANSFER_PQ = 0x50000000, + + KD_TEX_TRANSFER_MASK = 0xF0000000, +}; + // clang-format on |