aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsarbes <sarbes@kodi.tv>2024-09-17 22:21:51 +0200
committerGitHub <noreply@github.com>2024-09-17 22:21:51 +0200
commit51bef9501591cc8a753c91f97b8f554ad73049cb (patch)
tree29efb4ae2c5930b3c0536b46e2bdfe72abbd03f1
parentc782fe5150828dbb99f0ab75546f9db425a9f8e7 (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.cpp167
-rw-r--r--tools/depends/native/TexturePacker/src/decoder/IDecoder.h7
-rw-r--r--xbmc/filesystem/XbtFile.cpp37
-rw-r--r--xbmc/filesystem/XbtFile.h4
-rw-r--r--xbmc/guilib/Texture.cpp80
-rw-r--r--xbmc/guilib/Texture.h28
-rw-r--r--xbmc/guilib/TextureBase.cpp74
-rw-r--r--xbmc/guilib/TextureBase.h12
-rw-r--r--xbmc/guilib/TextureBundleXBT.cpp14
-rw-r--r--xbmc/guilib/TextureGL.cpp7
-rw-r--r--xbmc/guilib/TextureGL.h5
-rw-r--r--xbmc/guilib/TextureGLES.cpp29
-rw-r--r--xbmc/guilib/TextureGLES.h1
-rw-r--r--xbmc/guilib/XBTF.cpp24
-rw-r--r--xbmc/guilib/XBTF.h12
-rw-r--r--xbmc/guilib/XBTFReader.cpp17
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;