2727#include " RadientMaterials.h"
2828#include " Assets/RadientMaterialAssetManager.hpp"
2929#include " Assets/RadientMaterialImpl.hpp"
30+ #include " Assets/RadientTextureAssetManager.hpp"
3031
3132#include " DebugUtilities.hpp"
3233#include " EngineMemory.h"
3738
3839#include < algorithm>
3940#include < atomic>
41+ #include < cstddef>
4042#include < cstring>
4143#include < exception>
4244#include < limits>
@@ -115,6 +117,22 @@ bool GetMaterialParameterDataSize(const RadientMaterialParameterDesc& Desc, Uint
115117 return true ;
116118}
117119
120+ using ShaderTextureAttribs = GLTF ::Material::TextureShaderAttribs;
121+
122+ static_assert (static_cast <Uint32>(RADIENT_MATERIAL_TEXTURE_ADDRESS_MODE_WRAP ) == static_cast <Uint32>(TEXTURE_ADDRESS_WRAP ));
123+ static_assert (static_cast <Uint32>(RADIENT_MATERIAL_TEXTURE_ADDRESS_MODE_CLAMP ) == static_cast <Uint32>(TEXTURE_ADDRESS_CLAMP ));
124+ static_assert (sizeof (ShaderTextureAttribs) <= std::numeric_limits<Uint32>::max());
125+
126+ static constexpr Uint32 ShaderTexturePackedPropsOffset = static_cast <Uint32>(offsetof(ShaderTextureAttribs, PackedProps));
127+ static constexpr Uint32 ShaderTextureSliceOffset = static_cast <Uint32>(offsetof(ShaderTextureAttribs, TextureSlice));
128+ static constexpr Uint32 ShaderTextureAtlasUVOffset = static_cast <Uint32>(offsetof(ShaderTextureAttribs, AtlasUVScaleAndBias));
129+ static constexpr Uint32 ShaderTextureDataSize = static_cast <Uint32>(sizeof (ShaderTextureAttribs));
130+
131+ bool RangesOverlap (Uint32 LhsOffset, Uint32 LhsSize, Uint32 RhsOffset, Uint32 RhsSize) noexcept
132+ {
133+ return LhsOffset < RhsOffset + RhsSize && RhsOffset < LhsOffset + LhsSize;
134+ }
135+
118136RADIENT_STATUS ValidateMaterialDefinitionDesc (const RadientMaterialDefinitionDesc& Desc)
119137{
120138 if (Desc.Domain >= RADIENT_MATERIAL_DOMAIN_COUNT )
@@ -208,6 +226,12 @@ RADIENT_STATUS ValidateMaterialShaderDataLayout(
208226 " mappings, but pMappings is null" );
209227 return RADIENT_STATUS_INVALID_ARGUMENT ;
210228 }
229+ if (ShaderDataLayout.TexturePackingCount != 0 && ShaderDataLayout.pTexturePackings == nullptr )
230+ {
231+ LOG_ERROR_MESSAGE (" Material shader data layout declares " , ShaderDataLayout.TexturePackingCount ,
232+ " texture packings, but pTexturePackings is null" );
233+ return RADIENT_STATUS_INVALID_ARGUMENT ;
234+ }
211235
212236 for (Uint32 MappingIndex = 0 ; MappingIndex < ShaderDataLayout.MappingCount ; ++MappingIndex)
213237 {
@@ -264,6 +288,101 @@ RADIENT_STATUS ValidateMaterialShaderDataLayout(
264288 }
265289 }
266290
291+ for (Uint32 PackingIndex = 0 ; PackingIndex < ShaderDataLayout.TexturePackingCount ; ++PackingIndex)
292+ {
293+ const RadientMaterialShaderTexturePacking& Packing = ShaderDataLayout.pTexturePackings [PackingIndex];
294+
295+ const auto GetParameter = [&](Uint32 ParameterIndex, const char * Role) -> const RadientMaterialParameterDesc* {
296+ if (ParameterIndex >= DefinitionDesc.ParameterCount )
297+ {
298+ LOG_ERROR_MESSAGE (" Material shader texture packing " , PackingIndex, " references " , Role,
299+ " parameter index " , ParameterIndex, " , but the definition only has " ,
300+ DefinitionDesc.ParameterCount , " parameters" );
301+ return nullptr ;
302+ }
303+ return &DefinitionDesc.pParameters [ParameterIndex];
304+ };
305+
306+ const RadientMaterialParameterDesc* const pTexture = GetParameter (Packing.TextureParameterIndex , " texture" );
307+ if (pTexture == nullptr )
308+ return RADIENT_STATUS_INVALID_ARGUMENT ;
309+ if (!IsTextureParameter (pTexture->Type ) || pTexture->ArraySize != 1 )
310+ {
311+ LOG_ERROR_MESSAGE (" Material shader texture packing " , PackingIndex, " texture parameter '" ,
312+ pTexture->Name , " ' must be a scalar texture" );
313+ return RADIENT_STATUS_INVALID_ARGUMENT ;
314+ }
315+
316+ const auto ValidateScalarParameter = [&](Uint32 ParameterIndex,
317+ const char * Role,
318+ RADIENT_MATERIAL_PARAMETER_TYPE ExpectedType) -> bool {
319+ const RadientMaterialParameterDesc* const pParameter = GetParameter (ParameterIndex, Role);
320+ if (pParameter == nullptr )
321+ return false ;
322+ if (pParameter->Type != ExpectedType || pParameter->ArraySize != 1 )
323+ {
324+ LOG_ERROR_MESSAGE (" Material shader texture packing " , PackingIndex, ' ' , Role, " parameter '" ,
325+ pParameter->Name , " ' has an incompatible type or array size" );
326+ return false ;
327+ }
328+ return true ;
329+ };
330+
331+ if (!ValidateScalarParameter (Packing.UVSelectorParameterIndex , " UV selector" , RADIENT_MATERIAL_PARAMETER_TYPE_INT ) ||
332+ !ValidateScalarParameter (Packing.WrapUParameterIndex , " wrap U" , RADIENT_MATERIAL_PARAMETER_TYPE_UINT ) ||
333+ !ValidateScalarParameter (Packing.WrapVParameterIndex , " wrap V" , RADIENT_MATERIAL_PARAMETER_TYPE_UINT ))
334+ {
335+ return RADIENT_STATUS_INVALID_ARGUMENT ;
336+ }
337+
338+ if (Packing.Offset > ShaderDataLayout.Size ||
339+ ShaderTextureDataSize > ShaderDataLayout.Size - Packing.Offset )
340+ {
341+ LOG_ERROR_MESSAGE (" Material shader texture packing " , PackingIndex, " uses byte range [" ,
342+ Packing.Offset , " , " , Uint64{Packing.Offset } + ShaderTextureDataSize,
343+ " ), which exceeds the shader data size " , ShaderDataLayout.Size );
344+ return RADIENT_STATUS_INVALID_ARGUMENT ;
345+ }
346+
347+ for (Uint32 MappingIndex = 0 ; MappingIndex < ShaderDataLayout.MappingCount ; ++MappingIndex)
348+ {
349+ const RadientMaterialShaderParameterPacking& Mapping = ShaderDataLayout.pMappings [MappingIndex];
350+ const RadientMaterialParameterDesc& Parameter = DefinitionDesc.pParameters [Mapping.ParameterIndex ];
351+ Uint32 ParameterDataSize = 0 ;
352+ const bool IsValidDataSize = GetMaterialParameterDataSize (Parameter, ParameterDataSize);
353+ VERIFY_EXPR (IsValidDataSize);
354+ (void )IsValidDataSize;
355+
356+ const bool OverlapsPackedProperties =
357+ RangesOverlap (Mapping.Offset , ParameterDataSize,
358+ Packing.Offset + ShaderTexturePackedPropsOffset,
359+ ShaderTextureSliceOffset + sizeof (Float32) - ShaderTexturePackedPropsOffset);
360+ const bool OverlapsAtlasData =
361+ RangesOverlap (Mapping.Offset , ParameterDataSize,
362+ Packing.Offset + ShaderTextureAtlasUVOffset,
363+ sizeof (RadientFloat4));
364+ if (OverlapsPackedProperties || OverlapsAtlasData)
365+ {
366+ LOG_ERROR_MESSAGE (" Material shader data mapping " , MappingIndex,
367+ " overlaps data written by texture packing " , PackingIndex);
368+ return RADIENT_STATUS_INVALID_ARGUMENT ;
369+ }
370+ }
371+
372+ for (Uint32 PreviousIndex = 0 ; PreviousIndex < PackingIndex; ++PreviousIndex)
373+ {
374+ const RadientMaterialShaderTexturePacking& PreviousPacking =
375+ ShaderDataLayout.pTexturePackings [PreviousIndex];
376+ if (RangesOverlap (Packing.Offset , ShaderTextureDataSize,
377+ PreviousPacking.Offset , ShaderTextureDataSize))
378+ {
379+ LOG_ERROR_MESSAGE (" Material shader texture packings " , PreviousIndex, " and " , PackingIndex,
380+ " overlap in the destination data block" );
381+ return RADIENT_STATUS_INVALID_ARGUMENT ;
382+ }
383+ }
384+ }
385+
267386 return RADIENT_STATUS_OK ;
268387}
269388
@@ -278,6 +397,7 @@ RadientMaterialDefinitionImpl::PackedData RadientMaterialDefinitionImpl::PackDat
278397 FixedLinearAllocator Allocator{GetRawAllocator ()};
279398 Allocator.AddSpace <RadientMaterialParameterDesc>(Desc.ParameterCount );
280399 Allocator.AddSpace <ShaderDataCopyCommand>(ShaderDataLayout.MappingCount );
400+ Allocator.AddSpace <RadientMaterialShaderTexturePacking>(ShaderDataLayout.TexturePackingCount );
281401 Allocator.AddSpaceForString (DefinitionName);
282402 Allocator.AddSpaceForString (Desc.Reference .URI );
283403
@@ -305,15 +425,19 @@ RadientMaterialDefinitionImpl::PackedData RadientMaterialDefinitionImpl::PackDat
305425 Writer.ConstructArray <RadientMaterialParameterDesc>(Desc.ParameterCount );
306426 ShaderDataCopyCommand* const pShaderDataCopyCommands =
307427 Writer.ConstructArray <ShaderDataCopyCommand>(ShaderDataLayout.MappingCount );
308-
309- Data.Desc = Desc;
310- Data.Desc .Name = Writer.CopyString (DefinitionName);
311- Data.Desc .Reference = Desc.Reference ;
312- Data.Desc .Reference .URI = Writer.CopyString (Desc.Reference .URI );
313- Data.Desc .pParameters = pParameters;
314- Data.PackingPlan .Size = ShaderDataLayout.Size ;
315- Data.PackingPlan .CopyCommandCount = ShaderDataLayout.MappingCount ;
316- Data.PackingPlan .pCopyCommands = pShaderDataCopyCommands;
428+ RadientMaterialShaderTexturePacking* const pShaderDataTextureCommands =
429+ Writer.ConstructArray <RadientMaterialShaderTexturePacking>(ShaderDataLayout.TexturePackingCount );
430+
431+ Data.Desc = Desc;
432+ Data.Desc .Name = Writer.CopyString (DefinitionName);
433+ Data.Desc .Reference = Desc.Reference ;
434+ Data.Desc .Reference .URI = Writer.CopyString (Desc.Reference .URI );
435+ Data.Desc .pParameters = pParameters;
436+ Data.PackingPlan .Size = ShaderDataLayout.Size ;
437+ Data.PackingPlan .CopyCommandCount = ShaderDataLayout.MappingCount ;
438+ Data.PackingPlan .pCopyCommands = pShaderDataCopyCommands;
439+ Data.PackingPlan .TextureCommandCount = ShaderDataLayout.TexturePackingCount ;
440+ Data.PackingPlan .pTextureCommands = pShaderDataTextureCommands;
317441
318442 for (Uint32 MappingIndex = 0 ; MappingIndex < ShaderDataLayout.MappingCount ; ++MappingIndex)
319443 {
@@ -332,6 +456,9 @@ RadientMaterialDefinitionImpl::PackedData RadientMaterialDefinitionImpl::PackDat
332456 };
333457 }
334458
459+ for (Uint32 PackingIndex = 0 ; PackingIndex < ShaderDataLayout.TexturePackingCount ; ++PackingIndex)
460+ pShaderDataTextureCommands[PackingIndex] = ShaderDataLayout.pTexturePackings [PackingIndex];
461+
335462 for (Uint32 Index = 0 ; Index < Desc.ParameterCount ; ++Index)
336463 {
337464 const RadientMaterialParameterDesc& Src = Desc.pParameters [Index];
@@ -950,6 +1077,44 @@ void RadientMaterialDefinitionImpl::WriteShaderData(
9501077 InstanceImpl.m_Data .GetValueData (Command.ParameterIndex ),
9511078 Command.Size );
9521079 }
1080+
1081+ for (Uint32 CommandIndex = 0 ; CommandIndex < m_Data.PackingPlan .TextureCommandCount ; ++CommandIndex)
1082+ {
1083+ const RadientMaterialShaderTexturePacking& Command =
1084+ m_Data.PackingPlan .pTextureCommands [CommandIndex];
1085+
1086+ const Int32 UVSelector =
1087+ *static_cast <const Int32*>(InstanceImpl.m_Data .GetValueData (Command.UVSelectorParameterIndex ));
1088+ const Uint32 WrapU =
1089+ *static_cast <const Uint32*>(InstanceImpl.m_Data .GetValueData (Command.WrapUParameterIndex ));
1090+ const Uint32 WrapV =
1091+ *static_cast <const Uint32*>(InstanceImpl.m_Data .GetValueData (Command.WrapVParameterIndex ));
1092+ ShaderTextureAttribs TextureAttribs{};
1093+ TextureAttribs.SetUVSelector (UVSelector);
1094+ TextureAttribs.SetWrapUMode (static_cast <TEXTURE_ADDRESS_MODE >(WrapU));
1095+ TextureAttribs.SetWrapVMode (static_cast <TEXTURE_ADDRESS_MODE >(WrapV));
1096+ std::memcpy (pShaderData + Command.Offset + ShaderTexturePackedPropsOffset,
1097+ &TextureAttribs.PackedProps ,
1098+ sizeof (TextureAttribs.PackedProps ));
1099+
1100+ IRadientTextureAsset* const pTexture = InstanceImpl.m_Data .GetTexture (Command.TextureParameterIndex , 0 );
1101+ if (pTexture != nullptr )
1102+ {
1103+ RadientTextureSamplingInfo SamplingInfo{};
1104+ const bool SamplingInfoAvailable =
1105+ RadientTextureAssetManager::GetTextureSamplingInfo (pTexture, SamplingInfo);
1106+ VERIFY_EXPR (SamplingInfoAvailable);
1107+ if (SamplingInfoAvailable)
1108+ {
1109+ std::memcpy (pShaderData + Command.Offset + ShaderTextureSliceOffset,
1110+ &SamplingInfo.TextureSlice ,
1111+ sizeof (SamplingInfo.TextureSlice ));
1112+ std::memcpy (pShaderData + Command.Offset + ShaderTextureAtlasUVOffset,
1113+ &SamplingInfo.UVScaleBias ,
1114+ sizeof (SamplingInfo.UVScaleBias ));
1115+ }
1116+ }
1117+ }
9531118}
9541119
9551120RADIENT_STATUS DILIGENT_CALL_TYPE RadientMaterialDefinitionImpl::CreateInstance (
0 commit comments