diff options
author | sarbes <sarbes@kodi.tv> | 2024-09-17 22:21:51 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-17 22:21:51 +0200 |
commit | 51bef9501591cc8a753c91f97b8f554ad73049cb (patch) | |
tree | 29efb4ae2c5930b3c0536b46e2bdfe72abbd03f1 | |
parent | c782fe5150828dbb99f0ab75546f9db425a9f8e7 (diff) |
Add single/dual channel texture support to XBT textures (#25714)
Add single/dual channel texture support to XBT textures
-rw-r--r-- | tools/depends/native/TexturePacker/src/TexturePacker.cpp | 167 | ||||
-rw-r--r-- | tools/depends/native/TexturePacker/src/decoder/IDecoder.h | 7 | ||||
-rw-r--r-- | xbmc/filesystem/XbtFile.cpp | 37 | ||||
-rw-r--r-- | xbmc/filesystem/XbtFile.h | 4 | ||||
-rw-r--r-- | xbmc/guilib/Texture.cpp | 80 | ||||
-rw-r--r-- | xbmc/guilib/Texture.h | 28 | ||||
-rw-r--r-- | xbmc/guilib/TextureBase.cpp | 74 | ||||
-rw-r--r-- | xbmc/guilib/TextureBase.h | 12 | ||||
-rw-r--r-- | xbmc/guilib/TextureBundleXBT.cpp | 14 | ||||
-rw-r--r-- | xbmc/guilib/TextureGL.cpp | 7 | ||||
-rw-r--r-- | xbmc/guilib/TextureGL.h | 5 | ||||
-rw-r--r-- | xbmc/guilib/TextureGLES.cpp | 29 | ||||
-rw-r--r-- | xbmc/guilib/TextureGLES.h | 1 | ||||
-rw-r--r-- | xbmc/guilib/XBTF.cpp | 24 | ||||
-rw-r--r-- | xbmc/guilib/XBTF.h | 12 | ||||
-rw-r--r-- | xbmc/guilib/XBTFReader.cpp | 17 |
16 files changed, 466 insertions, 52 deletions
diff --git a/tools/depends/native/TexturePacker/src/TexturePacker.cpp b/tools/depends/native/TexturePacker/src/TexturePacker.cpp index 5c8304c5cb..9d4f270b23 100644 --- a/tools/depends/native/TexturePacker/src/TexturePacker.cpp +++ b/tools/depends/native/TexturePacker/src/TexturePacker.cpp @@ -56,40 +56,30 @@ namespace { -const char *GetFormatString(unsigned int format) +const char* GetFormatString(KD_TEX_FMT format) { switch (format) { - case XB_FMT_DXT1: - return "DXT1 "; - case XB_FMT_DXT3: - return "DXT3 "; - case XB_FMT_DXT5: - return "DXT5 "; - case XB_FMT_DXT5_YCoCg: - return "YCoCg"; - case XB_FMT_A8R8G8B8: - return "ARGB "; - case XB_FMT_A8: - return "A8 "; - default: - return "?????"; + case KD_TEX_FMT_SDR_R8: + return "R8 "; + case KD_TEX_FMT_SDR_RG8: + return "RG8 "; + case KD_TEX_FMT_SDR_RGBA8: + return "RGBA8"; + case KD_TEX_FMT_SDR_BGRA8: + return "BGRA8"; + default: + return "?????"; } } -bool HasAlpha(unsigned char* argb, unsigned int width, unsigned int height) -{ - unsigned char* p = argb + 3; // offset of alpha - for (unsigned int i = 0; i < 4 * width * height; i += 4) - { - if (p[i] != 0xff) - return true; - } - return false; -} - void Usage() { + puts("Texture Packer Version 3"); + puts(""); + puts("Tool to pack XBT 3 texture files, used in Kodi Piers (v22)."); + puts("Accepts the following file formats as input: PNG (preferred), JPG and GIF."); + puts(""); puts("Usage:"); puts(" -help Show this screen."); puts(" -input <dir> Input directory. Default: current dir"); @@ -122,6 +112,10 @@ private: bool CheckDupe(MD5Context* ctx, unsigned int pos); + void ConvertToSingleChannel(RGBAImage& image, uint32_t channel); + void ConvertToDualChannel(RGBAImage& image); + void ReduceChannels(RGBAImage& image); + DecoderManager decoderManager; std::map<std::string, unsigned int> m_hashes; @@ -196,12 +190,13 @@ CXBTFFrame TexturePacker::CreateXBTFFrame(DecodedFrame& decodedFrame, CXBTFWrite const unsigned int delay = decodedFrame.delay; const unsigned int width = decodedFrame.rgbaImage.width; const unsigned int height = decodedFrame.rgbaImage.height; - const unsigned int size = width * height * 4; - const XB_FMT format = XB_FMT_A8R8G8B8; + const uint32_t bpp = decodedFrame.rgbaImage.bbp; + const unsigned int size = width * height * (bpp / 8); + const uint32_t format = static_cast<uint32_t>(decodedFrame.rgbaImage.textureFormat) | + static_cast<uint32_t>(decodedFrame.rgbaImage.textureAlpha) | + static_cast<uint32_t>(decodedFrame.rgbaImage.textureSwizzle); unsigned char* data = (unsigned char*)decodedFrame.rgbaImage.pixels.data(); - const bool hasAlpha = HasAlpha(data, width, height); - CXBTFFrame frame; lzo_uint packedSize = size; @@ -246,7 +241,7 @@ CXBTFFrame TexturePacker::CreateXBTFFrame(DecodedFrame& decodedFrame, CXBTFWrite frame.SetUnpackedSize(size); frame.SetWidth(width); frame.SetHeight(height); - frame.SetFormat(hasAlpha ? format : static_cast<XB_FMT>(format | XB_FMT_OPAQUE)); + frame.SetFormat(format); frame.SetDuration(delay); return frame; } @@ -278,6 +273,111 @@ bool TexturePacker::CheckDupe(MD5Context* ctx, return false; } +void TexturePacker::ConvertToSingleChannel(RGBAImage& image, uint32_t channel) +{ + uint32_t size = (image.width * image.height); + for (uint32_t i = 0; i < size; i++) + { + image.pixels[i] = image.pixels[i * 4 + channel]; + } + + image.textureFormat = KD_TEX_FMT_SDR_R8; + + image.bbp = 8; + image.pitch = 1 * image.width; +} + +void TexturePacker::ConvertToDualChannel(RGBAImage& image) +{ + uint32_t size = (image.width * image.height); + for (uint32_t i = 0; i < size; i++) + { + image.pixels[i * 2] = image.pixels[i * 4]; + image.pixels[i * 2 + 1] = image.pixels[i * 4 + 3]; + } + image.textureFormat = KD_TEX_FMT_SDR_RG8; + image.bbp = 16; + image.pitch = 2 * image.width; +} + +void TexturePacker::ReduceChannels(RGBAImage& image) +{ + if (image.textureFormat != KD_TEX_FMT_SDR_BGRA8) + return; + + uint32_t size = (image.width * image.height); + uint8_t red = image.pixels[0]; + uint8_t green = image.pixels[1]; + uint8_t blue = image.pixels[2]; + uint8_t alpha = image.pixels[3]; + bool uniformRed = true; + bool uniformGreen = true; + bool uniformBlue = true; + bool uniformAlpha = true; + bool isGrey = true; + bool isIntensity = true; + + // Checks each pixel for various properties. + for (uint32_t i = 0; i < size; i++) + { + if (image.pixels[i * 4] != red) + uniformRed = false; + if (image.pixels[i * 4 + 1] != green) + uniformGreen = false; + if (image.pixels[i * 4 + 2] != blue) + uniformBlue = false; + if (image.pixels[i * 4 + 3] != alpha) + uniformAlpha = false; + if (image.pixels[i * 4] != image.pixels[i * 4 + 1] || + image.pixels[i * 4] != image.pixels[i * 4 + 2]) + isGrey = false; + if (image.pixels[i * 4] != image.pixels[i * 4 + 1] || + image.pixels[i * 4] != image.pixels[i * 4 + 2] || + image.pixels[i * 4] != image.pixels[i * 4 + 3]) + isIntensity = false; + } + + if (uniformAlpha && alpha != 0xff) + printf("WARNING: uniform alpha detected! Consider using diffusecolor!\n"); + + bool isWhite = red == 0xff && green == 0xff && blue == 0xff; + if (uniformRed && uniformGreen && uniformBlue && !isWhite) + printf("WARNING: uniform color detected! Consider using diffusecolor!\n"); + + if (isIntensity) + { + // this is an intensity (GL_INTENSITY) texture + ConvertToSingleChannel(image, 0); + image.textureSwizzle = KD_TEX_SWIZ_RRRR; + } + else if (uniformAlpha && alpha == 0xff) + { + // we have a opaque texture, L or RGBX + if (isGrey) + { + ConvertToSingleChannel(image, 1); + image.textureSwizzle = KD_TEX_SWIZ_RRR1; + } + image.textureAlpha = KD_TEX_ALPHA_OPAQUE; + } + else if (uniformRed && uniformGreen && uniformBlue && isWhite) + { + // an alpha only texture + ConvertToSingleChannel(image, 3); + image.textureSwizzle = KD_TEX_SWIZ_111R; + } + else if (isGrey) + { + // a LA texture + ConvertToDualChannel(image); + image.textureSwizzle = KD_TEX_SWIZ_RRRG; + } + else + { + // BGRA + } +} + int TexturePacker::createBundle(const std::string& InputDir, const std::string& OutputFile) { CXBTFWriter writer(OutputFile); @@ -312,6 +412,9 @@ int TexturePacker::createBundle(const std::string& InputDir, const std::string& continue; } + for (unsigned int j = 0; j < frames.frameList.size(); j++) + ReduceChannels(frames.frameList[j].rgbaImage); + printf("%s\n", output.c_str()); bool skip=false; if (m_dupecheck) @@ -342,7 +445,7 @@ int TexturePacker::createBundle(const std::string& InputDir, const std::string& file.GetFrames().push_back(frame); printf(" frame %4i (delay:%4i) %s%c (%d,%d @ %" PRIu64 " bytes)\n", - j, frame.GetDuration(), GetFormatString(frame.GetFormat()), + j, frame.GetDuration(), GetFormatString(frame.GetKDFormat()), frame.HasAlpha() ? ' ' : '*', frame.GetWidth(), frame.GetHeight(), frame.GetUnpackedSize()); } diff --git a/tools/depends/native/TexturePacker/src/decoder/IDecoder.h b/tools/depends/native/TexturePacker/src/decoder/IDecoder.h index 5bc06f2f96..63b5dd8607 100644 --- a/tools/depends/native/TexturePacker/src/decoder/IDecoder.h +++ b/tools/depends/native/TexturePacker/src/decoder/IDecoder.h @@ -20,6 +20,8 @@ #pragma once +#include "guilib/TextureFormats.h" + #include <cstdint> #include <string> #include <vector> @@ -52,8 +54,11 @@ public: std::vector<uint8_t> pixels; int width = 0; // width int height = 0; // height - int bbp = 0; // bits per pixel + int bbp = 32; // bits per pixel int pitch = 0; // rowsize in bytes + KD_TEX_FMT textureFormat{KD_TEX_FMT_SDR_BGRA8}; + KD_TEX_ALPHA textureAlpha{KD_TEX_ALPHA_STRAIGHT}; + KD_TEX_SWIZ textureSwizzle{KD_TEX_SWIZ_RGBA}; }; class DecodedFrame diff --git a/xbmc/filesystem/XbtFile.cpp b/xbmc/filesystem/XbtFile.cpp index 3f4061ea04..34860dac43 100644 --- a/xbmc/filesystem/XbtFile.cpp +++ b/xbmc/filesystem/XbtFile.cpp @@ -12,6 +12,7 @@ #include "filesystem/File.h" #include "filesystem/XbtManager.h" #include "guilib/TextureBundleXBT.h" +#include "guilib/TextureFormats.h" #include "guilib/XBTFReader.h" #include "utils/StringUtils.h" @@ -314,6 +315,42 @@ XB_FMT CXbtFile::GetImageFormat() const return frame.GetFormat(); } +KD_TEX_FMT CXbtFile::GetKDFormat() const +{ + CXBTFFrame frame; + if (!GetFirstFrame(frame)) + return KD_TEX_FMT_UNKNOWN; + + return frame.GetKDFormat(); +} + +KD_TEX_FMT CXbtFile::GetKDFormatType() const +{ + CXBTFFrame frame; + if (!GetFirstFrame(frame)) + return KD_TEX_FMT_UNKNOWN; + + return frame.GetKDFormatType(); +} + +KD_TEX_ALPHA CXbtFile::GetKDAlpha() const +{ + CXBTFFrame frame; + if (!GetFirstFrame(frame)) + return KD_TEX_ALPHA_OPAQUE; + + return frame.GetKDAlpha(); +} + +KD_TEX_SWIZ CXbtFile::GetKDSwizzle() const +{ + CXBTFFrame frame; + if (!GetFirstFrame(frame)) + return KD_TEX_SWIZ_RGBA; + + return frame.GetKDSwizzle(); +} + bool CXbtFile::HasImageAlpha() const { CXBTFFrame frame; diff --git a/xbmc/filesystem/XbtFile.h b/xbmc/filesystem/XbtFile.h index 6da937c907..ff36fc809d 100644 --- a/xbmc/filesystem/XbtFile.h +++ b/xbmc/filesystem/XbtFile.h @@ -43,6 +43,10 @@ public: uint32_t GetImageWidth() const; uint32_t GetImageHeight() const; XB_FMT GetImageFormat() const; + KD_TEX_FMT GetKDFormat() const; + KD_TEX_FMT GetKDFormatType() const; + KD_TEX_ALPHA GetKDAlpha() const; + KD_TEX_SWIZ GetKDSwizzle() const; bool HasImageAlpha() const; private: diff --git a/xbmc/guilib/Texture.cpp b/xbmc/guilib/Texture.cpp index 31a6029636..b59e3588e5 100644 --- a/xbmc/guilib/Texture.cpp +++ b/xbmc/guilib/Texture.cpp @@ -16,8 +16,10 @@ #include "filesystem/ResourceFile.h" #include "filesystem/XbtFile.h" #include "guilib/TextureBase.h" +#include "guilib/TextureFormats.h" #include "guilib/iimage.h" #include "guilib/imagefactory.h" +#include "messaging/ApplicationMessenger.h" #include "utils/URIUtils.h" #include "utils/log.h" #include "windowing/WinSystem.h" @@ -184,9 +186,21 @@ bool CTexture::LoadFromFileInternal(const std::string& texturePath, XFILE::CXbtFile xbtFile; if (!xbtFile.Open(url)) return false; - - return LoadFromMemory(xbtFile.GetImageWidth(), xbtFile.GetImageHeight(), 0, - xbtFile.GetImageFormat(), xbtFile.HasImageAlpha(), buf.data()); + if (xbtFile.GetKDFormatType()) + { + return UploadFromMemory(xbtFile.GetImageWidth(), xbtFile.GetImageHeight(), 0, buf.data(), + xbtFile.GetKDFormat(), xbtFile.GetKDAlpha(), xbtFile.GetKDSwizzle()); + } + else if (xbtFile.GetImageFormat() == XB_FMT_A8R8G8B8) + { + KD_TEX_ALPHA alpha = xbtFile.HasImageAlpha() ? KD_TEX_ALPHA_STRAIGHT : KD_TEX_ALPHA_OPAQUE; + return UploadFromMemory(xbtFile.GetImageWidth(), xbtFile.GetImageHeight(), 0, buf.data(), + KD_TEX_FMT_SDR_BGRA8, alpha, KD_TEX_SWIZ_RGBA); + } + else + { + return false; + } } IImage* pImage; @@ -271,7 +285,7 @@ bool CTexture::LoadIImage(IImage* pImage, if (pImage->Orientation()) m_orientation = pImage->Orientation() - 1; - m_hasAlpha = pImage->hasAlpha(); + m_textureAlpha = pImage->hasAlpha() ? KD_TEX_ALPHA_STRAIGHT : KD_TEX_ALPHA_OPAQUE; m_originalWidth = pImage->originalWidth(); m_originalHeight = pImage->originalHeight(); m_imageWidth = pImage->Width(); @@ -308,11 +322,67 @@ bool CTexture::LoadFromMemory(unsigned int width, m_imageWidth = m_originalWidth = width; m_imageHeight = m_originalHeight = height; m_format = format; - m_hasAlpha = hasAlpha; + m_textureAlpha = hasAlpha ? KD_TEX_ALPHA_STRAIGHT : KD_TEX_ALPHA_OPAQUE; Update(width, height, pitch, format, pixels, false); return true; } +bool CTexture::UploadFromMemory(unsigned int width, + unsigned int height, + unsigned int pitch, + unsigned char* pixels, + KD_TEX_FMT format, + KD_TEX_ALPHA alpha, + KD_TEX_SWIZ swizzle) +{ + m_imageWidth = m_textureWidth = m_originalWidth = width; + m_imageHeight = m_textureHeight = m_originalHeight = height; + m_textureFormat = format; + m_textureAlpha = alpha; + m_textureSwizzle = swizzle; + + if (!SupportsFormat(m_textureFormat, m_textureSwizzle) && !ConvertToLegacy(width, height, pixels)) + { + CLog::LogF( + LOGERROR, + "Failed to upload texture. Format {} and swizzle {} not supported by the texture pipeline.", + m_textureFormat, m_textureSwizzle); + + m_loadedToGPU = true; + return false; + } + + if (CServiceBroker::GetAppMessenger()->IsProcessThread()) + { + if (m_pixels) + { + LoadToGPU(); + } + else + { + // just a borrowed buffer + m_pixels = pixels; + m_bCacheMemory = true; + LoadToGPU(); + m_bCacheMemory = false; + m_pixels = nullptr; + } + } + else if (!m_pixels) + { + size_t size = GetPitch() * GetRows(); + m_pixels = static_cast<unsigned char*>(KODI::MEMORY::AlignedMalloc(size, 32)); + if (m_pixels == nullptr) + { + CLog::LogF(LOGERROR, "Could not allocate {} bytes. Out of memory.", size); + return false; + } + std::memcpy(m_pixels, pixels, size); + } + + return true; +} + bool CTexture::LoadPaletted(unsigned int width, unsigned int height, unsigned int pitch, diff --git a/xbmc/guilib/Texture.h b/xbmc/guilib/Texture.h index 6e5a4ff1a5..09b9577a7e 100644 --- a/xbmc/guilib/Texture.h +++ b/xbmc/guilib/Texture.h @@ -74,6 +74,24 @@ public: XB_FMT format, bool hasAlpha, const unsigned char* pixels); + /*! \brief Attempts to upload a texture directly from a provided buffer + Unlike LoadFromMemory() which copies the texture into an intermediate buffer, the texture gets uploaded directly to + the GPU if circumstances allow. + \param width the width of the texture. + \param height the height of the texture. + \param pitch the pitch of the texture. + \param pixels pointer to the texture buffer. + \param format the format of the texture. + \param alpha the alpha type of the texture. + \param swizzle the swizzle pattern of the texture. + */ + bool UploadFromMemory(unsigned int width, + unsigned int height, + unsigned int pitch, + unsigned char* pixels, + KD_TEX_FMT format = KD_TEX_FMT_SDR_RGBA8, + KD_TEX_ALPHA alpha = KD_TEX_ALPHA_OPAQUE, + KD_TEX_SWIZ swizzle = KD_TEX_SWIZ_RGBA); bool LoadPaletted(unsigned int width, unsigned int height, unsigned int pitch, @@ -102,6 +120,16 @@ public: virtual void SyncGPU(){}; virtual void BindToUnit(unsigned int unit) = 0; + /*! + * \brief Checks if the processing pipeline can handle the texture format/swizzle + \param format the format of the texture. + \return true if the texturing pipeline supports the format + */ + virtual bool SupportsFormat(KD_TEX_FMT textureFormat, KD_TEX_SWIZ textureSwizzle) + { + return !(textureFormat & KD_TEX_FMT_TYPE_MASK) && textureSwizzle == KD_TEX_SWIZ_RGBA; + } + private: // no copy constructor CTexture(const CTexture& copy) = delete; diff --git a/xbmc/guilib/TextureBase.cpp b/xbmc/guilib/TextureBase.cpp index e6154ac624..5f2aff8bf7 100644 --- a/xbmc/guilib/TextureBase.cpp +++ b/xbmc/guilib/TextureBase.cpp @@ -398,3 +398,77 @@ void CTextureBase::SetKDFormat(XB_FMT xbFMT) return; } } + +bool CTextureBase::ConvertToLegacy(uint32_t width, uint32_t height, uint8_t* src) +{ + if (m_textureFormat == KD_TEX_FMT_SDR_BGRA8 && m_textureSwizzle == KD_TEX_SWIZ_RGBA) + { + m_format = XB_FMT_A8R8G8B8; + return true; + } + + if (m_textureFormat == KD_TEX_FMT_SDR_R8) + { + if (m_textureSwizzle != KD_TEX_SWIZ_111R && m_textureSwizzle != KD_TEX_SWIZ_RRR1 && + m_textureSwizzle != KD_TEX_SWIZ_RRRR) + return false; + } + else if (m_textureFormat == KD_TEX_FMT_SDR_RG8) + { + if (m_textureSwizzle != KD_TEX_SWIZ_RRRG) + return false; + } + else + { + return false; + } + + size_t size = GetPitch() * GetRows(); + + Allocate(width, height, XB_FMT_A8R8G8B8); + + if (m_textureSwizzle == KD_TEX_SWIZ_111R) + { + for (int32_t i = size - 1; i >= 0; i--) + { + m_pixels[i * 4 + 3] = src[i]; + m_pixels[i * 4 + 2] = 0xff; + m_pixels[i * 4 + 1] = 0xff; + m_pixels[i * 4] = 0xff; + } + } + else if (m_textureSwizzle == KD_TEX_SWIZ_RRR1) + { + for (int32_t i = size - 1; i >= 0; i--) + { + m_pixels[i * 4 + 3] = 0xff; + m_pixels[i * 4 + 2] = src[i]; + m_pixels[i * 4 + 1] = src[i]; + m_pixels[i * 4] = src[i]; + } + } + else if (m_textureSwizzle == KD_TEX_SWIZ_RRRR) + { + for (int32_t i = size - 1; i >= 0; i--) + { + m_pixels[i * 4 + 3] = src[i]; + m_pixels[i * 4 + 2] = src[i]; + m_pixels[i * 4 + 1] = src[i]; + m_pixels[i * 4] = src[i]; + } + } + else if (m_textureSwizzle == KD_TEX_SWIZ_RRRG) + { + for (int32_t i = size / 2 - 1; i >= 0; i--) + { + m_pixels[i * 4 + 3] = src[i * 2 + 1]; + m_pixels[i * 4 + 2] = src[i * 2]; + m_pixels[i * 4 + 1] = src[i * 2]; + m_pixels[i * 4] = src[i * 2]; + } + } + + m_textureFormat = KD_TEX_FMT_SDR_BGRA8; + m_textureSwizzle = KD_TEX_SWIZ_RGBA; + return true; +} diff --git a/xbmc/guilib/TextureBase.h b/xbmc/guilib/TextureBase.h index bbabe2ae46..51f8caeb20 100644 --- a/xbmc/guilib/TextureBase.h +++ b/xbmc/guilib/TextureBase.h @@ -30,8 +30,11 @@ public: CTextureBase() = default; ~CTextureBase() = default; - bool HasAlpha() const { return m_hasAlpha; } - void SetAlpha(bool hasAlpha) { m_hasAlpha = hasAlpha; } + bool HasAlpha() const { return m_textureAlpha != KD_TEX_ALPHA_OPAQUE; } + void SetAlpha(bool hasAlpha) + { + m_textureAlpha = hasAlpha ? KD_TEX_ALPHA_STRAIGHT : KD_TEX_ALPHA_OPAQUE; + } /*! \brief sets mipmapping. do not use in new code. will be replaced with proper scaling. */ void SetMipmapping() { m_mipmapping = true; } @@ -92,6 +95,10 @@ protected: void SetKDFormat(XB_FMT xbFMT); + /*! \brief Textures might be in a single/dual channel format with L/A/I/LA swizzle. DX and GLES 2.0 don't + handle some/all at the moment. This function can convert the texture into a traditional BGRA format.*/ + bool ConvertToLegacy(uint32_t width, uint32_t height, uint8_t* src); + uint32_t m_imageWidth{0}; uint32_t m_imageHeight{0}; uint32_t m_textureWidth{0}; @@ -110,7 +117,6 @@ protected: 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/TextureBundleXBT.cpp b/xbmc/guilib/TextureBundleXBT.cpp index f557d28a26..e3a6f8e60e 100644 --- a/xbmc/guilib/TextureBundleXBT.cpp +++ b/xbmc/guilib/TextureBundleXBT.cpp @@ -16,6 +16,7 @@ #include "commons/ilog.h" #include "filesystem/SpecialProtocol.h" #include "filesystem/XbtManager.h" +#include "guilib/TextureFormats.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" #include "utils/StringUtils.h" @@ -237,9 +238,18 @@ std::unique_ptr<CTexture> CTextureBundleXBT::ConvertFrameToTexture(const std::st // create an xbmc texture std::unique_ptr<CTexture> texture = CTexture::CreateTexture(); - texture->LoadFromMemory(frame.GetWidth(), frame.GetHeight(), 0, frame.GetFormat(), - frame.HasAlpha(), buffer.data()); + if (frame.GetKDFormatType()) + { + texture->UploadFromMemory(frame.GetWidth(), frame.GetHeight(), 0, buffer.data(), + frame.GetKDFormat(), frame.GetKDAlpha(), frame.GetKDSwizzle()); + } + else if (frame.GetFormat() == XB_FMT_A8R8G8B8) + { + KD_TEX_ALPHA alpha = frame.HasAlpha() ? KD_TEX_ALPHA_STRAIGHT : KD_TEX_ALPHA_OPAQUE; + texture->UploadFromMemory(frame.GetWidth(), frame.GetHeight(), 0, buffer.data(), + KD_TEX_FMT_SDR_BGRA8, alpha, KD_TEX_SWIZ_RGBA); + } return texture; } diff --git a/xbmc/guilib/TextureGL.cpp b/xbmc/guilib/TextureGL.cpp index 28da1cc000..df4e2304aa 100644 --- a/xbmc/guilib/TextureGL.cpp +++ b/xbmc/guilib/TextureGL.cpp @@ -234,6 +234,13 @@ void CGLTexture::LoadToGPU() m_textureWidth = maxSize; } + // there might not be any padding for the following formats, so we have to + // read one/two bytes at the time. + if (m_textureFormat == KD_TEX_FMT_SDR_R8) + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + if (m_textureFormat == KD_TEX_FMT_SDR_RG8) + glPixelStorei(GL_UNPACK_ALIGNMENT, 2); + SetSwizzle(); TextureFormat glFormat = GetFormatGL(m_textureFormat); diff --git a/xbmc/guilib/TextureGL.h b/xbmc/guilib/TextureGL.h index e3f68bc421..cc3e41b179 100644 --- a/xbmc/guilib/TextureGL.h +++ b/xbmc/guilib/TextureGL.h @@ -43,6 +43,11 @@ public: void SyncGPU() override; void BindToUnit(unsigned int unit) override; + bool SupportsFormat(KD_TEX_FMT textureFormat, KD_TEX_SWIZ textureSwizzle) override + { + return true; + } + protected: void SetSwizzle(); TextureFormat GetFormatGL(KD_TEX_FMT textureFormat); diff --git a/xbmc/guilib/TextureGLES.cpp b/xbmc/guilib/TextureGLES.cpp index bf0785cc77..e475fecf47 100644 --- a/xbmc/guilib/TextureGLES.cpp +++ b/xbmc/guilib/TextureGLES.cpp @@ -182,7 +182,9 @@ CGLESTexture::CGLESTexture(unsigned int width, unsigned int height, XB_FMT forma { unsigned int major, minor; CServiceBroker::GetRenderSystem()->GetRenderVersion(major, minor); +#if defined(GL_ES_VERSION_3_0) m_isGLESVersion30orNewer = major >= 3; +#endif } CGLESTexture::~CGLESTexture() @@ -276,6 +278,13 @@ void CGLESTexture::LoadToGPU() } } + // there might not be any padding for the following formats, so we have to + // read one/two bytes at the time. + if (m_textureFormat == KD_TEX_FMT_SDR_R8) + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + if (m_textureFormat == KD_TEX_FMT_SDR_RG8) + glPixelStorei(GL_UNPACK_ALIGNMENT, 2); + TextureFormat glesFormat; if (m_isGLESVersion30orNewer) { @@ -338,6 +347,24 @@ void CGLESTexture::BindToUnit(unsigned int unit) glBindTexture(GL_TEXTURE_2D, m_texture); } +bool CGLESTexture::SupportsFormat(KD_TEX_FMT textureFormat, KD_TEX_SWIZ textureSwizzle) +{ + // GLES 3.0 supports swizzles + if (m_isGLESVersion30orNewer) + return true; + + // GL_LUMINANCE; + if (textureFormat == KD_TEX_FMT_SDR_R8 && textureSwizzle == KD_TEX_SWIZ_RRR1) + return true; + + // GL_LUMINANCE_ALPHA; + if (textureFormat == KD_TEX_FMT_SDR_RG8 && textureSwizzle == KD_TEX_SWIZ_RRRG) + return true; + + // all other GLES 2.0 swizzles would need separate shaders + return textureSwizzle == KD_TEX_SWIZ_RGBA; +} + void CGLESTexture::SetSwizzle(bool swapRB) { #if defined(GL_ES_VERSION_3_0) @@ -428,7 +455,7 @@ TextureFormat CGLESTexture::GetFormatGLES30(KD_TEX_FMT textureFormat) if (textureFormat & KD_TEX_FMT_SDR || textureFormat & KD_TEX_FMT_HDR) { #if defined(GL_ES_VERSION_3_0) - const auto it = TextureMappingGLES30.find(KD_TEX_FMT_SDR_RGBA8); + const auto it = TextureMappingGLES30.find(textureFormat); if (it != TextureMappingGLES30.cend()) glFormat = it->second; #else diff --git a/xbmc/guilib/TextureGLES.h b/xbmc/guilib/TextureGLES.h index 92089506c5..fe7af24917 100644 --- a/xbmc/guilib/TextureGLES.h +++ b/xbmc/guilib/TextureGLES.h @@ -38,6 +38,7 @@ public: void DestroyTextureObject() override; void LoadToGPU() override; void BindToUnit(unsigned int unit) override; + bool SupportsFormat(KD_TEX_FMT textureFormat, KD_TEX_SWIZ textureSwizzle) override; protected: void SetSwizzle(bool swapRB); diff --git a/xbmc/guilib/XBTF.cpp b/xbmc/guilib/XBTF.cpp index fb89c97889..92848bd69e 100644 --- a/xbmc/guilib/XBTF.cpp +++ b/xbmc/guilib/XBTF.cpp @@ -72,14 +72,14 @@ void CXBTFFrame::SetUnpackedSize(uint64_t size) m_unpackedSize = size; } -void CXBTFFrame::SetFormat(XB_FMT format) +void CXBTFFrame::SetFormat(uint32_t format) { m_format = format; } XB_FMT CXBTFFrame::GetFormat(bool raw) const { - return raw ? m_format : static_cast<XB_FMT>(m_format & XB_FMT_MASK); + return static_cast<XB_FMT>(raw ? m_format : m_format & XB_FMT_MASK); } uint64_t CXBTFFrame::GetOffset() const @@ -116,6 +116,26 @@ uint64_t CXBTFFrame::GetHeaderSize() const return result; } +KD_TEX_FMT CXBTFFrame::GetKDFormat() const +{ + return static_cast<KD_TEX_FMT>(m_format & KD_TEX_FMT_MASK); +} + +KD_TEX_FMT CXBTFFrame::GetKDFormatType() const +{ + return static_cast<KD_TEX_FMT>(m_format & KD_TEX_FMT_TYPE_MASK); +} + +KD_TEX_ALPHA CXBTFFrame::GetKDAlpha() const +{ + return static_cast<KD_TEX_ALPHA>(m_format & KD_TEX_ALPHA_MASK); +} + +KD_TEX_SWIZ CXBTFFrame::GetKDSwizzle() const +{ + return static_cast<KD_TEX_SWIZ>(m_format & KD_TEX_SWIZ_MASK); +} + CXBTFFile::CXBTFFile() : m_path(), m_frames() diff --git a/xbmc/guilib/XBTF.h b/xbmc/guilib/XBTF.h index 588ba6234d..af6b77c205 100644 --- a/xbmc/guilib/XBTF.h +++ b/xbmc/guilib/XBTF.h @@ -16,7 +16,8 @@ #include <stdint.h> static const std::string XBTF_MAGIC = "XBTF"; -static const std::string XBTF_VERSION = "2"; +static const std::string XBTF_VERSION = "3"; +static const char XBTF_VERSION_MIN = '2'; #include "TextureFormats.h" @@ -29,7 +30,7 @@ public: void SetWidth(uint32_t width); XB_FMT GetFormat(bool raw = false) const; - void SetFormat(XB_FMT format); + void SetFormat(uint32_t format); uint32_t GetHeight() const; void SetHeight(uint32_t height); @@ -51,10 +52,15 @@ public: bool IsPacked() const; bool HasAlpha() const; + KD_TEX_FMT GetKDFormat() const; + KD_TEX_FMT GetKDFormatType() const; + KD_TEX_ALPHA GetKDAlpha() const; + KD_TEX_SWIZ GetKDSwizzle() const; + private: uint32_t m_width; uint32_t m_height; - XB_FMT m_format; + uint32_t m_format; uint64_t m_packedSize; uint64_t m_unpackedSize; uint64_t m_offset; diff --git a/xbmc/guilib/XBTFReader.cpp b/xbmc/guilib/XBTFReader.cpp index 6d74f46b0d..b4f561f615 100644 --- a/xbmc/guilib/XBTFReader.cpp +++ b/xbmc/guilib/XBTFReader.cpp @@ -29,6 +29,17 @@ static bool ReadString(FILE* file, char* str, size_t max_length) return (fread(str, max_length, 1, file) == 1); } +static bool ReadChar(FILE* file, char& value) +{ + if (file == nullptr) + return false; + + if (fread(&value, sizeof(char), 1, file) != 1) + return false; + + return true; +} + static bool ReadUInt32(FILE* file, uint32_t& value) { if (file == nullptr) @@ -89,11 +100,11 @@ bool CXBTFReader::Open(const std::string& path) return false; // read the version - char version[1]; - if (!ReadString(m_file, version, sizeof(version))) + char version; + if (!ReadChar(m_file, version)) return false; - if (strncmp(XBTF_VERSION.c_str(), version, sizeof(version)) != 0) + if (version < XBTF_VERSION_MIN) return false; unsigned int nofFiles; |