diff --git a/TextureLoader/interface/Image.h b/TextureLoader/interface/Image.h index 1e7f4284..5cbe91d9 100644 --- a/TextureLoader/interface/Image.h +++ b/TextureLoader/interface/Image.h @@ -164,6 +164,9 @@ struct Image : public ObjectBase static IMAGE_FILE_FORMAT GetFileFormat(const Uint8* pData, size_t Size, const char* FilePath = nullptr); + /// Returns true if the image is uniform, i.e. all pixels have the same value + bool IsUniform() const; + private: template friend class MakeNewRCObj; diff --git a/TextureLoader/interface/TextureLoader.h b/TextureLoader/interface/TextureLoader.h index 04bd854c..285b7894 100644 --- a/TextureLoader/interface/TextureLoader.h +++ b/TextureLoader/interface/TextureLoader.h @@ -1,5 +1,5 @@ /* - * Copyright 2019-2023 Diligent Graphics LLC + * Copyright 2019-2024 Diligent Graphics LLC * Copyright 2015-2019 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -136,6 +136,13 @@ struct TextureLoadInfo /// - Two-channel source image is replicated to RG channels, B channel is set to 0. TextureComponentMapping Swizzle DEFAULT_INITIALIZER(TextureComponentMapping::Identity()); + /// When non-zero, specifies the dimension that uniform images should be clipped to. + /// + /// \remarks When this parameter is non-zero, the loader will check if all pixels + /// in the image have the same value. If this is the case, the image will + /// be clipped to the specified dimension. + Uint32 UniformImageClipDim DEFAULT_INITIALIZER(0); + #if DILIGENT_CPP_INTERFACE explicit TextureLoadInfo(const Char* _Name, USAGE _Usage = TextureLoadInfo{}.Usage, diff --git a/TextureLoader/src/Image.cpp b/TextureLoader/src/Image.cpp index b41f3760..7ee26589 100644 --- a/TextureLoader/src/Image.cpp +++ b/TextureLoader/src/Image.cpp @@ -589,6 +589,59 @@ IMAGE_FILE_FORMAT Image::GetFileFormat(const Uint8* pData, size_t Size, const ch return IMAGE_FILE_FORMAT_UNKNOWN; } +template +bool IsImageUniform(const void* pData, Uint32 Width, Uint32 Height, Uint32 NumComponents, Uint32 RowStride) +{ + if (Width == 0 || Height == 0 || NumComponents == 0) + return false; + + const T* pFirstPixel = static_cast(pData); + for (Uint32 Pass = 0; Pass < 2; ++Pass) + { + // On the first pass, sparsely sample the image to quickly detect non-uniform images + const Uint32 Step = (Pass == 0) ? 32 : 1; + for (Uint32 y = 0; y < Height; y += Step) + { + const T* pRow = reinterpret_cast(static_cast(pData) + y * RowStride); + for (Uint32 x = 0; x < Width; x += Step) + { + for (Uint32 c = 0; c < NumComponents; ++c) + { + if (pRow[x * NumComponents + c] != pFirstPixel[c]) + return false; + } + } + } + } + + return true; +} + +bool Image::IsUniform() const +{ + if (!m_pData) + return false; + + Uint32 ComponentSize = GetValueSize(m_Desc.ComponentType); + switch (ComponentSize) + { + case 1: + return IsImageUniform(m_pData->GetConstDataPtr(), m_Desc.Width, m_Desc.Height, m_Desc.NumComponents, m_Desc.RowStride); + + case 2: + return IsImageUniform(m_pData->GetConstDataPtr(), m_Desc.Width, m_Desc.Height, m_Desc.NumComponents, m_Desc.RowStride); + + case 4: + return IsImageUniform(m_pData->GetConstDataPtr(), m_Desc.Width, m_Desc.Height, m_Desc.NumComponents, m_Desc.RowStride); + + case 8: + return IsImageUniform(m_pData->GetConstDataPtr(), m_Desc.Width, m_Desc.Height, m_Desc.NumComponents, m_Desc.RowStride); + + default: + UNEXPECTED("Unexpected component size (", ComponentSize, ")"); + return false; + } +} IMAGE_FILE_FORMAT CreateImageFromFile(const Char* FilePath, Image** ppImage, diff --git a/TextureLoader/src/TextureLoaderImpl.cpp b/TextureLoader/src/TextureLoaderImpl.cpp index 598e33de..753240cf 100644 --- a/TextureLoader/src/TextureLoaderImpl.cpp +++ b/TextureLoader/src/TextureLoaderImpl.cpp @@ -199,8 +199,12 @@ void TextureLoaderImpl::LoadFromImage(Image* pImage, const TextureLoadInfo& TexL { VERIFY_EXPR(pImage != nullptr); - const ImageDesc& ImgDesc = pImage->GetDesc(); - const Uint32 CompSize = GetValueSize(ImgDesc.ComponentType); + ImageDesc ImgDesc = pImage->GetDesc(); + if (TexLoadInfo.UniformImageClipDim != 0 && pImage->IsUniform()) + { + ImgDesc.Width = std::min(ImgDesc.Width, TexLoadInfo.UniformImageClipDim); + ImgDesc.Height = std::min(ImgDesc.Height, TexLoadInfo.UniformImageClipDim); + } m_TexDesc.Type = RESOURCE_DIM_TEX_2D; m_TexDesc.Width = ImgDesc.Width; @@ -209,6 +213,8 @@ void TextureLoaderImpl::LoadFromImage(Image* pImage, const TextureLoadInfo& TexL if (TexLoadInfo.MipLevels > 0) m_TexDesc.MipLevels = std::min(m_TexDesc.MipLevels, TexLoadInfo.MipLevels); + const Uint32 CompSize = GetValueSize(ImgDesc.ComponentType); + if (m_TexDesc.Format == TEX_FORMAT_UNKNOWN) { Uint32 NumComponents = ImgDesc.NumComponents;