Skip to content

Commit 9a4e9a1

Browse files
Texture loader: added GetTextureLoaderMemoryRequirement function
1 parent 209bdce commit 9a4e9a1

File tree

4 files changed

+158
-54
lines changed

4 files changed

+158
-54
lines changed

TextureLoader/interface/Image.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ struct Image : public ObjectBase<IObject>
171171

172172
static IMAGE_FILE_FORMAT GetFileFormat(const Uint8* pData, size_t Size, const char* FilePath = nullptr);
173173

174+
static ImageDesc GetDesc(IMAGE_FILE_FORMAT FileFormat, const void* pSrcData, size_t SrcDataSize);
175+
174176
/// Returns true if the image is uniform, i.e. all pixels have the same value
175177
bool IsUniform() const;
176178

TextureLoader/interface/TextureLoader.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,24 @@ void CreateTextureLoaderFromDataBlob(RefCntAutoPtr<IDataBlob> pDataBlob,
281281
ITextureLoader** ppLoader);
282282
#endif
283283

284+
285+
/// Returns the memory requirement for the texture loader.
286+
///
287+
/// \param [in] pData - Pointer to the source image data.
288+
/// \param [in] Size - The data size.
289+
/// \param [in] TexLoadInfo - Texture loading information, see Diligent::TextureLoadInfo.
290+
/// \return The memory requirement in bytes.
291+
///
292+
/// \remarks This function can be used to estimate the memory requirement for the texture loader.
293+
/// The memory requirement includes the size of the texture data plus the size of the
294+
/// intermediate data structures used by the loader. It does not include the size of
295+
/// the source image data.
296+
/// The actual memory used by the loader may be slightly different.
297+
size_t DILIGENT_GLOBAL_FUNCTION(GetTextureLoaderMemoryRequirement)(const void* pData,
298+
size_t Size,
299+
const TextureLoadInfo REF TexLoadInfo);
300+
301+
284302
/// Writes texture data as DDS file.
285303

286304
/// \param [in] FilePath - DDS file path.

TextureLoader/src/Image.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,13 @@ bool Image::Load(IMAGE_FILE_FORMAT FileFormat, const void* pSrcData, size_t SrcD
433433
return Result;
434434
}
435435

436+
ImageDesc Image::GetDesc(IMAGE_FILE_FORMAT FileFormat, const void* pSrcData, size_t SrcDataSize)
437+
{
438+
ImageDesc Desc;
439+
Load(FileFormat, pSrcData, SrcDataSize, nullptr, Desc);
440+
return Desc;
441+
}
442+
436443
Image::Image(IReferenceCounters* pRefCounters,
437444
const void* pSrcData,
438445
size_t SrcDataSize,

TextureLoader/src/TextureLoaderImpl.cpp

Lines changed: 131 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -144,12 +144,7 @@ TextureLoaderImpl::TextureLoaderImpl(IReferenceCounters* pRefCounters,
144144
LOG_ERROR_AND_THROW("Unable to derive image format.");
145145
}
146146

147-
if (ImgFileFormat == IMAGE_FILE_FORMAT_PNG ||
148-
ImgFileFormat == IMAGE_FILE_FORMAT_JPEG ||
149-
ImgFileFormat == IMAGE_FILE_FORMAT_TIFF ||
150-
ImgFileFormat == IMAGE_FILE_FORMAT_SGI ||
151-
ImgFileFormat == IMAGE_FILE_FORMAT_HDR ||
152-
ImgFileFormat == IMAGE_FILE_FORMAT_TGA)
147+
if (Image::IsSupportedFileFormat(ImgFileFormat))
153148
{
154149
ImageLoadInfo ImgLoadInfo;
155150
ImgLoadInfo.Format = ImgFileFormat;
@@ -160,16 +155,13 @@ TextureLoaderImpl::TextureLoaderImpl(IReferenceCounters* pRefCounters,
160155
Image::CreateFromMemory(pData, DataSize, ImgLoadInfo, &pImage);
161156
LoadFromImage(std::move(pImage), TexLoadInfo);
162157
}
163-
else
158+
else if (ImgFileFormat == IMAGE_FILE_FORMAT_DDS)
164159
{
165-
if (ImgFileFormat == IMAGE_FILE_FORMAT_DDS)
166-
{
167-
LoadFromDDS(TexLoadInfo, pData, DataSize);
168-
}
169-
else if (ImgFileFormat == IMAGE_FILE_FORMAT_KTX)
170-
{
171-
LoadFromKTX(TexLoadInfo, pData, DataSize);
172-
}
160+
LoadFromDDS(TexLoadInfo, pData, DataSize);
161+
}
162+
else if (ImgFileFormat == IMAGE_FILE_FORMAT_KTX)
163+
{
164+
LoadFromKTX(TexLoadInfo, pData, DataSize);
173165
}
174166

175167
if (TexLoadInfo.IsSRGB)
@@ -195,27 +187,16 @@ void TextureLoaderImpl::CreateTexture(IRenderDevice* pDevice,
195187
pDevice->CreateTexture(m_TexDesc, &InitData, ppTexture);
196188
}
197189

198-
void TextureLoaderImpl::LoadFromImage(RefCntAutoPtr<Image> pImage, const TextureLoadInfo& TexLoadInfo)
190+
static void TexDescFromImageDesc(const ImageDesc& ImgDesc, const TextureLoadInfo& TexLoadInfo, TextureDesc& TexDesc)
199191
{
200-
VERIFY_EXPR(pImage != nullptr);
201-
202-
ImageDesc ImgDesc = pImage->GetDesc();
203-
if (TexLoadInfo.UniformImageClipDim != 0 && pImage->IsUniform())
204-
{
205-
ImgDesc.Width = std::min(ImgDesc.Width, TexLoadInfo.UniformImageClipDim);
206-
ImgDesc.Height = std::min(ImgDesc.Height, TexLoadInfo.UniformImageClipDim);
207-
}
208-
209-
m_TexDesc.Type = RESOURCE_DIM_TEX_2D;
210-
m_TexDesc.Width = ImgDesc.Width;
211-
m_TexDesc.Height = ImgDesc.Height;
212-
m_TexDesc.MipLevels = ComputeMipLevelsCount(m_TexDesc.Width, m_TexDesc.Height);
192+
TexDesc.Type = RESOURCE_DIM_TEX_2D;
193+
TexDesc.Width = ImgDesc.Width;
194+
TexDesc.Height = ImgDesc.Height;
195+
TexDesc.MipLevels = ComputeMipLevelsCount(TexDesc.Width, TexDesc.Height);
213196
if (TexLoadInfo.MipLevels > 0)
214-
m_TexDesc.MipLevels = std::min(m_TexDesc.MipLevels, TexLoadInfo.MipLevels);
197+
TexDesc.MipLevels = std::min(TexDesc.MipLevels, TexLoadInfo.MipLevels);
215198

216-
const Uint32 CompSize = GetValueSize(ImgDesc.ComponentType);
217-
218-
if (m_TexDesc.Format == TEX_FORMAT_UNKNOWN)
199+
if (TexDesc.Format == TEX_FORMAT_UNKNOWN)
219200
{
220201
const COMPONENT_TYPE CompType = ValueTypeToComponentType(ImgDesc.ComponentType, /*IsNormalized = */ true, TexLoadInfo.IsSRGB);
221202

@@ -227,26 +208,47 @@ void TextureLoaderImpl::LoadFromImage(RefCntAutoPtr<Image> pImage, const Texture
227208
}
228209
DEV_CHECK_ERR(CompType != COMPONENT_TYPE_UNDEFINED, "Failed to deduce component type from image component type ", GetValueTypeString(ImgDesc.ComponentType), " and sRGB flag ", TexLoadInfo.IsSRGB);
229210

230-
m_TexDesc.Format = TextureComponentAttribsToTextureFormat(CompType, CompSize, NumComponents);
231-
if (m_TexDesc.Format == TEX_FORMAT_UNKNOWN)
211+
const Uint32 CompSize = GetValueSize(ImgDesc.ComponentType);
212+
213+
TexDesc.Format = TextureComponentAttribsToTextureFormat(CompType, CompSize, NumComponents);
214+
if (TexDesc.Format == TEX_FORMAT_UNKNOWN)
232215
{
233216
LOG_ERROR_AND_THROW("Failed to deduce texture format from image component type ", GetValueTypeString(ImgDesc.ComponentType), " and number of components ", ImgDesc.NumComponents);
234217
}
235218
}
236-
const auto& TexFmtDesc = GetTextureFormatAttribs(m_TexDesc.Format);
237-
const Uint32 NumComponents = TexFmtDesc.NumComponents;
219+
}
238220

239-
m_SubResources.resize(m_TexDesc.MipLevels);
240-
m_Mips.resize(m_TexDesc.MipLevels);
221+
inline bool GetSwizzleRequired(Uint32 NumComponents, const TextureComponentMapping& Swizzle)
222+
{
223+
return ((NumComponents >= 1 && Swizzle.R != TEXTURE_COMPONENT_SWIZZLE_IDENTITY && Swizzle.R != TEXTURE_COMPONENT_SWIZZLE_R) ||
224+
(NumComponents >= 2 && Swizzle.G != TEXTURE_COMPONENT_SWIZZLE_IDENTITY && Swizzle.G != TEXTURE_COMPONENT_SWIZZLE_G) ||
225+
(NumComponents >= 3 && Swizzle.B != TEXTURE_COMPONENT_SWIZZLE_IDENTITY && Swizzle.B != TEXTURE_COMPONENT_SWIZZLE_B) ||
226+
(NumComponents >= 4 && Swizzle.A != TEXTURE_COMPONENT_SWIZZLE_IDENTITY && Swizzle.A != TEXTURE_COMPONENT_SWIZZLE_A));
227+
}
228+
229+
void TextureLoaderImpl::LoadFromImage(RefCntAutoPtr<Image> pImage, const TextureLoadInfo& TexLoadInfo)
230+
{
231+
VERIFY_EXPR(pImage != nullptr);
241232

242-
const bool SwizzleRequired =
243-
(NumComponents >= 1 && TexLoadInfo.Swizzle.R != TEXTURE_COMPONENT_SWIZZLE_IDENTITY && TexLoadInfo.Swizzle.R != TEXTURE_COMPONENT_SWIZZLE_R) ||
244-
(NumComponents >= 2 && TexLoadInfo.Swizzle.G != TEXTURE_COMPONENT_SWIZZLE_IDENTITY && TexLoadInfo.Swizzle.G != TEXTURE_COMPONENT_SWIZZLE_G) ||
245-
(NumComponents >= 3 && TexLoadInfo.Swizzle.B != TEXTURE_COMPONENT_SWIZZLE_IDENTITY && TexLoadInfo.Swizzle.B != TEXTURE_COMPONENT_SWIZZLE_B) ||
246-
(NumComponents >= 4 && TexLoadInfo.Swizzle.A != TEXTURE_COMPONENT_SWIZZLE_IDENTITY && TexLoadInfo.Swizzle.A != TEXTURE_COMPONENT_SWIZZLE_A);
233+
ImageDesc ImgDesc = pImage->GetDesc();
234+
if (TexLoadInfo.UniformImageClipDim != 0 && pImage->IsUniform())
235+
{
236+
ImgDesc.Width = std::min(ImgDesc.Width, TexLoadInfo.UniformImageClipDim);
237+
ImgDesc.Height = std::min(ImgDesc.Height, TexLoadInfo.UniformImageClipDim);
238+
}
239+
240+
// Note: do not override Name field in m_TexDesc
241+
TexDescFromImageDesc(ImgDesc, TexLoadInfo, m_TexDesc);
247242

243+
const TextureFormatAttribs& TexFmtDesc = GetTextureFormatAttribs(m_TexDesc.Format);
244+
const Uint32 NumComponents = TexFmtDesc.NumComponents;
245+
const Uint32 SrcCompSize = GetValueSize(ImgDesc.ComponentType);
246+
const bool SwizzleRequired = GetSwizzleRequired(NumComponents, TexLoadInfo.Swizzle);
247+
248+
m_SubResources.resize(m_TexDesc.MipLevels);
249+
m_Mips.resize(m_TexDesc.MipLevels);
248250
if (ImgDesc.NumComponents != NumComponents ||
249-
TexFmtDesc.ComponentSize != CompSize ||
251+
TexFmtDesc.ComponentSize != SrcCompSize ||
250252
TexLoadInfo.FlipVertically ||
251253
SwizzleRequired)
252254
{
@@ -259,7 +261,7 @@ void TextureLoaderImpl::LoadFromImage(RefCntAutoPtr<Image> pImage, const Texture
259261
CopyPixelsAttribs CopyAttribs;
260262
CopyAttribs.Width = ImgDesc.Width;
261263
CopyAttribs.Height = ImgDesc.Height;
262-
CopyAttribs.SrcComponentSize = CompSize;
264+
CopyAttribs.SrcComponentSize = SrcCompSize;
263265
CopyAttribs.pSrcPixels = pImage->GetData()->GetConstDataPtr();
264266
CopyAttribs.SrcStride = ImgDesc.RowStride;
265267
CopyAttribs.SrcCompCount = ImgDesc.NumComponents;
@@ -356,30 +358,32 @@ void TextureLoaderImpl::LoadFromImage(RefCntAutoPtr<Image> pImage, const Texture
356358
}
357359
}
358360

359-
void TextureLoaderImpl::CompressSubresources(Uint32 NumComponents, Uint32 NumSrcComponents, const TextureLoadInfo& TexLoadInfo)
361+
inline TEXTURE_FORMAT GetCompressedTextureFormat(Uint32 NumComponents, Uint32 NumSrcComponents, bool IsSRGB)
360362
{
361-
TEXTURE_FORMAT CompressedFormat = TEX_FORMAT_UNKNOWN;
362363
switch (NumComponents)
363364
{
364365
case 1:
365-
CompressedFormat = TEX_FORMAT_BC4_UNORM;
366-
break;
366+
return TEX_FORMAT_BC4_UNORM;
367367

368368
case 2:
369-
CompressedFormat = TEX_FORMAT_BC5_UNORM;
370-
break;
369+
return TEX_FORMAT_BC5_UNORM;
371370

372371
case 4:
373372
if (NumSrcComponents == 4)
374-
CompressedFormat = TexLoadInfo.IsSRGB ? TEX_FORMAT_BC3_UNORM_SRGB : TEX_FORMAT_BC3_UNORM;
373+
return IsSRGB ? TEX_FORMAT_BC3_UNORM_SRGB : TEX_FORMAT_BC3_UNORM;
375374
else
376-
CompressedFormat = TexLoadInfo.IsSRGB ? TEX_FORMAT_BC1_UNORM_SRGB : TEX_FORMAT_BC1_UNORM;
375+
return IsSRGB ? TEX_FORMAT_BC1_UNORM_SRGB : TEX_FORMAT_BC1_UNORM;
377376
break;
378377

379378
default:
380379
UNEXPECTED("Unexpected number of components ", NumComponents);
380+
return TEX_FORMAT_UNKNOWN;
381381
}
382+
}
382383

384+
void TextureLoaderImpl::CompressSubresources(Uint32 NumComponents, Uint32 NumSrcComponents, const TextureLoadInfo& TexLoadInfo)
385+
{
386+
const TEXTURE_FORMAT CompressedFormat = GetCompressedTextureFormat(NumComponents, NumSrcComponents, TexLoadInfo.IsSRGB);
383387
if (CompressedFormat == TEX_FORMAT_UNKNOWN)
384388
return;
385389

@@ -567,6 +571,71 @@ void CreateTextureLoaderFromImage(Image* pSrcImage,
567571
}
568572
}
569573

574+
size_t GetTextureLoaderMemoryRequirement(const void* pData,
575+
size_t Size,
576+
const TextureLoadInfo& TexLoadInfo)
577+
{
578+
const IMAGE_FILE_FORMAT ImgFileFormat = Image::GetFileFormat(static_cast<const Uint8*>(pData), Size);
579+
if (ImgFileFormat == IMAGE_FILE_FORMAT_UNKNOWN)
580+
{
581+
return 0;
582+
}
583+
584+
if (Image::IsSupportedFileFormat(ImgFileFormat))
585+
{
586+
const ImageDesc ImgDesc = Image::GetDesc(ImgFileFormat, pData, Size);
587+
const Uint32 ImgCompSize = GetValueSize(ImgDesc.ComponentType);
588+
589+
TextureDesc TexDesc;
590+
TexDescFromImageDesc(ImgDesc, TexLoadInfo, TexDesc);
591+
const TextureFormatAttribs& TexFmtDesc = GetTextureFormatAttribs(TexDesc.Format);
592+
const bool SwizzleRequired = GetSwizzleRequired(TexFmtDesc.NumComponents, TexLoadInfo.Swizzle);
593+
594+
const size_t SrcImageDataSize = size_t{ImgDesc.Width} * ImgDesc.Height * ImgDesc.NumComponents * ImgCompSize;
595+
596+
// Step 1 - decode image data
597+
size_t RequiredMemory = SrcImageDataSize;
598+
599+
// Step 2 - convert image data if needed
600+
if (ImgDesc.NumComponents != TexFmtDesc.NumComponents ||
601+
TexFmtDesc.ComponentSize != ImgCompSize ||
602+
TexLoadInfo.FlipVertically ||
603+
SwizzleRequired)
604+
{
605+
const size_t ConvertedImageDataSize = size_t{TexDesc.Width} * TexDesc.Height * TexFmtDesc.NumComponents * TexFmtDesc.ComponentSize;
606+
// Original and converted data exist simultaneously
607+
RequiredMemory += ConvertedImageDataSize;
608+
// After conversion is done, original data is released
609+
}
610+
611+
// Step 3 - generate mip levels
612+
// Mip level 0 uses either the original image data or converted data
613+
const size_t TextureDataSize = static_cast<size_t>(GetStagingTextureDataSize(TexDesc));
614+
RequiredMemory = std::max(RequiredMemory, TextureDataSize);
615+
616+
if (TexLoadInfo.CompressMode != TEXTURE_LOAD_COMPRESS_MODE_NONE)
617+
{
618+
TexDesc.Format = GetCompressedTextureFormat(TexFmtDesc.NumComponents, ImgDesc.NumComponents, TexLoadInfo.IsSRGB);
619+
if (TexDesc.Format != TEX_FORMAT_UNKNOWN)
620+
{
621+
const size_t CompressedTextureDataSize = static_cast<size_t>(GetStagingTextureDataSize(TexDesc));
622+
// Uncompressed and compressed data exist simultaneously
623+
RequiredMemory = std::max(RequiredMemory, TextureDataSize + CompressedTextureDataSize);
624+
}
625+
}
626+
627+
return RequiredMemory;
628+
}
629+
else if (ImgFileFormat == IMAGE_FILE_FORMAT_DDS ||
630+
ImgFileFormat == IMAGE_FILE_FORMAT_KTX)
631+
{
632+
// The loader does not require any memory as the source data is used directly
633+
return 0;
634+
}
635+
636+
return 0;
637+
}
638+
570639
} // namespace Diligent
571640

572641
extern "C"
@@ -594,4 +663,12 @@ extern "C"
594663
{
595664
Diligent::CreateTextureLoaderFromImage(pSrcImage, TexLoadInfo, ppLoader);
596665
}
666+
667+
668+
size_t Diligent_GetTextureLoaderMemoryRequirement(const void* pData,
669+
size_t Size,
670+
const Diligent::TextureLoadInfo& TexLoadInfo)
671+
{
672+
return Diligent::GetTextureLoaderMemoryRequirement(pData, Size, TexLoadInfo);
673+
}
597674
}

0 commit comments

Comments
 (0)