Merge branch 'development' into Atom/santorac/OrderOnceDependencyForPassBuilder

This commit is contained in:
santorac
2022-01-12 11:26:11 -08:00
6060 changed files with 481813 additions and 192037 deletions
@@ -177,7 +177,7 @@ float ComputeLerpBetweenInnerOuterAABBs(float3 innerAabbMin, float3 innerAabbMax
bool ObbContainsPoint(float4x4 obbTransformInverse, float3 obbHalfExtents, float3 testPoint)
{
// get the position in Obb local space, force to positive quadrant with abs()
float4 p = abs(mul(obbTransformInverse, float4(testPoint, 1.0f)));
float3 p = abs(mul(obbTransformInverse, float4(testPoint, 1.0f)).xyz);
return AabbContainsPoint(-obbHalfExtents, obbHalfExtents, p);
}
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:fb91c050a829ff03b972202cf8c90034e4f252d972332224791d135c07d9d528
size 796
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7028c8db4f935f23aa4396668278a67691d92fe345cc9d417a9f47bd9a4af32b
size 8130
@@ -0,0 +1,91 @@
<ObjectStream version="3">
<Class name="TextureSettings" version="2" type="{980132FF-C450-425D-8AE0-BD96A8486177}">
<Class name="AZ::Uuid" field="PresetID" value="{00000000-0000-0000-0000-000000000000}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="Name" field="Preset" value="ReferenceImage" type="{3D2B920C-9EFD-40D5-AAE0-DF131C3D4931}"/>
<Class name="unsigned int" field="SizeReduceLevel" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="bool" field="EngineReduce" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="bool" field="EnableMipmap" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="bool" field="MaintainAlphaCoverage" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="AZStd::vector" field="MipMapAlphaAdjustments" type="{3349AACD-BE04-50BC-9478-528BF2ACFD55}">
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="MipMapGenEval" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="ImageProcessingAtom::MipGenType" field="MipMapGenType" value="1" type="{8524F650-1417-44DA-BBB0-C707A7A1A709}"/>
<Class name="AZStd::map" field="PlatformSpecificOverrides" type="{74E4843B-0924-583D-8C6E-A37B09BD51FE}">
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="android" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}"/>
</Class>
</Class>
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="ios" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}">
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#0·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
</Class>
</Class>
</Class>
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="linux" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}">
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#0·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#1·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
</Class>
</Class>
</Class>
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="mac" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}">
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#2·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#1·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#0·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
</Class>
</Class>
</Class>
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="pc" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}"/>
</Class>
</Class>
</Class>
<Class name="AZStd::string" field="OverridingPlatform" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
</ObjectStream>
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a7d94b9c0a77741736b93d8ed4d2b22bc9ae4cf649f3d8b3f10cbaf595a3ed31
size 8336
@@ -0,0 +1,148 @@
<ObjectStream version="3">
<Class name="TextureSettings" version="2" type="{980132FF-C450-425D-8AE0-BD96A8486177}">
<Class name="AZ::Uuid" field="PresetID" value="{00000000-0000-0000-0000-000000000000}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="Name" field="Preset" value="ReferenceImage" type="{3D2B920C-9EFD-40D5-AAE0-DF131C3D4931}"/>
<Class name="unsigned int" field="SizeReduceLevel" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="bool" field="EngineReduce" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="bool" field="EnableMipmap" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="bool" field="MaintainAlphaCoverage" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="AZStd::vector" field="MipMapAlphaAdjustments" type="{3349AACD-BE04-50BC-9478-528BF2ACFD55}">
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="MipMapGenEval" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="ImageProcessingAtom::MipGenType" field="MipMapGenType" value="1" type="{8524F650-1417-44DA-BBB0-C707A7A1A709}"/>
<Class name="AZStd::map" field="PlatformSpecificOverrides" type="{74E4843B-0924-583D-8C6E-A37B09BD51FE}">
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="android" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}">
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#4·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#2·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#3·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#0·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#1·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
</Class>
</Class>
</Class>
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="ios" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}">
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#4·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#2·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#3·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#0·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#1·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
</Class>
</Class>
</Class>
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="linux" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}">
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#4·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#2·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#3·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#0·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#1·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
</Class>
</Class>
</Class>
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="mac" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}">
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#4·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#2·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#3·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#0·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#1·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
</Class>
</Class>
</Class>
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="pc" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}"/>
</Class>
</Class>
</Class>
<Class name="AZStd::string" field="OverridingPlatform" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
</ObjectStream>
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3bbd45e3ef81850da81d1cc01775930a53c424e64e287b00990af3e7e6a682ba
size 9701
@@ -0,0 +1,148 @@
<ObjectStream version="3">
<Class name="TextureSettings" version="2" type="{980132FF-C450-425D-8AE0-BD96A8486177}">
<Class name="AZ::Uuid" field="PresetID" value="{00000000-0000-0000-0000-000000000000}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="Name" field="Preset" value="ReferenceImage" type="{3D2B920C-9EFD-40D5-AAE0-DF131C3D4931}"/>
<Class name="unsigned int" field="SizeReduceLevel" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="bool" field="EngineReduce" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="bool" field="EnableMipmap" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="bool" field="MaintainAlphaCoverage" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="AZStd::vector" field="MipMapAlphaAdjustments" type="{3349AACD-BE04-50BC-9478-528BF2ACFD55}">
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="element" value="50" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="MipMapGenEval" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="ImageProcessingAtom::MipGenType" field="MipMapGenType" value="1" type="{8524F650-1417-44DA-BBB0-C707A7A1A709}"/>
<Class name="AZStd::map" field="PlatformSpecificOverrides" type="{74E4843B-0924-583D-8C6E-A37B09BD51FE}">
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="android" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}">
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#4·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#2·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#3·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#0·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#1·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
</Class>
</Class>
</Class>
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="ios" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}">
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#4·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#2·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#0·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#3·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#1·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
</Class>
</Class>
</Class>
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="linux" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}">
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#4·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#2·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#3·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#0·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#1·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
</Class>
</Class>
</Class>
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="mac" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}">
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#4·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#2·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#3·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#0·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{FED51EB4-F646-51FF-9646-9852CF90F353}">
<Class name="AddressType" field="value1" value="AZStd::map({74E4843B-0924-583D-8C6E-A37B09BD51FE})::PlatformSpecificOverrides·0/AZStd::pair({CAC4E67F-D626-5452-A057-ACB57D53F549})#1·0/" version="1" type="{90752F2D-CBD3-4EE9-9CDD-447E797C8408}"/>
<Class name="any" field="value2" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}"/>
</Class>
</Class>
</Class>
</Class>
<Class name="AZStd::pair" field="element" type="{CAC4E67F-D626-5452-A057-ACB57D53F549}">
<Class name="AZStd::string" field="value1" value="pc" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="DataPatch" field="value2" type="{BFF7A3F5-9014-4000-92C7-9B2BC7913DA9}">
<Class name="AZ::Uuid" field="m_targetClassId" value="{980132FF-C450-425D-8AE0-BD96A8486177}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="m_targetClassVersion" value="2" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::unordered_map" field="m_patch" type="{CEA836FC-77E0-5E46-BD0F-2E5A39D845E9}"/>
</Class>
</Class>
</Class>
<Class name="AZStd::string" field="OverridingPlatform" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
</ObjectStream>
+45
View File
@@ -0,0 +1,45 @@
<ObjectStream version="3">
<Class name="AZStd::vector" type="{82FC5264-88D0-57CD-9307-FC52E4DAD550}">
<Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
<Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
<Class name="AZ::Uuid" field="guid" value="{454C374E-E2FA-5DD3-81D8-08BE5904112C}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="platformFlags" value="3" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::string" field="pathHint" value="shader/decomposemsimage.azshader" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
<Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
<Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
<Class name="AZ::Uuid" field="guid" value="{7DCE2AC7-7EDA-5C04-A1E3-C7465B4CD8B7}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="platformFlags" value="3" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::string" field="pathHint" value="shader/imagepreview.azshader" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
<Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
<Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
<Class name="AZ::Uuid" field="guid" value="{A1B7396F-7D03-5A88-B71E-29441B04C123}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="subId" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="platformFlags" value="3" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::string" field="pathHint" value="shader/sceneandviewsrgs.azshader" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
<Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
<Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
<Class name="AZ::Uuid" field="guid" value="{FFF65E99-3A75-5734-BC40-E7D6796B1789}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="subId" value="1000" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="platformFlags" value="3" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::string" field="pathHint" value="textures/defaults/defaultfallback.png.streamingimage" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
<Class name="SeedInfo" field="element" version="2" type="{FACC3682-2ACA-4AA4-B85A-07AD276D18A0}">
<Class name="AssetId" field="assetId" version="1" type="{652ED536-3402-439B-AEBE-4A5DBC554085}">
<Class name="AZ::Uuid" field="guid" value="{BBA1FB65-974C-55D2-B549-806FA42A2115}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
<Class name="unsigned int" field="subId" value="1000" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
<Class name="unsigned int" field="platformFlags" value="3" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZStd::string" field="pathHint" value="textures/defaults/missing.png.streamingimage" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
</Class>
</ObjectStream>
+1
View File
@@ -160,6 +160,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
Gem::Atom_RPI.Public
Gem::Atom_RHI.Public
Gem::Atom_RPI.Edit
Gem::Atom_Utils.TestUtils.Static
)
ly_add_googletest(
NAME Gem::Atom_RPI.Tests
@@ -12,6 +12,7 @@
#include <AzCore/JSON/document.h>
#include <Atom/RPI.Reflect/Image/StreamingImageAsset.h>
#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
namespace AZ
{
@@ -21,21 +22,24 @@ namespace AZ
{
// Declarations...
Outcome<Data::AssetId> MakeAssetId(const AZStd::string& sourcePath, uint32_t productSubId);
// Note that these functions default to TraceLevel::Error to preserve legacy behavior of these APIs. It would be nice to make the default match
// RPI.Reflect/Asset/AssetUtils.h which is TraceLevel::Warning, but we are close to a release so it isn't worth the risk at this time.
Outcome<Data::AssetId> MakeAssetId(const AZStd::string& originatingSourcePath, const AZStd::string& referencedSourceFilePath, uint32_t productSubId);
Outcome<Data::AssetId> MakeAssetId(const AZStd::string& sourcePath, uint32_t productSubId, TraceLevel reporting = TraceLevel::Error);
Outcome<Data::AssetId> MakeAssetId(const AZStd::string& originatingSourcePath, const AZStd::string& referencedSourceFilePath, uint32_t productSubId, TraceLevel reporting = TraceLevel::Error);
template<typename AssetDataT>
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZStd::string& sourcePath, uint32_t productSubId = 0);
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZStd::string& sourcePath, uint32_t productSubId = 0, TraceLevel reporting = TraceLevel::Error);
template<typename AssetDataT>
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZStd::string& originatingSourcePath, const AZStd::string& referencedSourceFilePath, uint32_t productSubId = 0);
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZStd::string& originatingSourcePath, const AZStd::string& referencedSourceFilePath, uint32_t productSubId = 0, TraceLevel reporting = TraceLevel::Error);
template<typename AssetDataT>
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZ::Data::AssetId& assetId, const char* sourcePathForDebug);
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZ::Data::AssetId& assetId, const char* sourcePathForDebug, TraceLevel reporting = TraceLevel::Error);
template<typename AssetDataT>
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZ::Data::AssetId& assetId);
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZ::Data::AssetId& assetId, TraceLevel reporting = TraceLevel::Error);
//! Attempts to resolve the full path to a product asset given its ID
AZStd::string GetProductPathByAssetId(const AZ::Data::AssetId& assetId);
@@ -65,12 +69,12 @@ namespace AZ
// Definitions...
template<typename AssetDataT>
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZStd::string& sourcePath, uint32_t productSubId)
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZStd::string& sourcePath, uint32_t productSubId, TraceLevel reporting)
{
auto assetId = MakeAssetId(sourcePath, productSubId);
auto assetId = MakeAssetId(sourcePath, productSubId, reporting);
if (assetId.IsSuccess())
{
return LoadAsset<AssetDataT>(assetId.GetValue(), sourcePath.c_str());
return LoadAsset<AssetDataT>(assetId.GetValue(), sourcePath.c_str(), reporting);
}
else
{
@@ -79,20 +83,20 @@ namespace AZ
}
template<typename AssetDataT>
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZStd::string& originatingSourcePath, const AZStd::string& referencedSourceFilePath, uint32_t productSubId)
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZStd::string& originatingSourcePath, const AZStd::string& referencedSourceFilePath, uint32_t productSubId, TraceLevel reporting)
{
AZStd::string resolvedPath = ResolvePathReference(originatingSourcePath, referencedSourceFilePath);
return LoadAsset<AssetDataT>(resolvedPath, productSubId);
return LoadAsset<AssetDataT>(resolvedPath, productSubId, reporting);
}
template<typename AssetDataT>
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZ::Data::AssetId& assetId)
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZ::Data::AssetId& assetId, TraceLevel reporting)
{
return LoadAsset<AssetDataT>(assetId, nullptr);
return LoadAsset<AssetDataT>(assetId, nullptr, reporting);
}
template<typename AssetDataT>
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZ::Data::AssetId& assetId, [[maybe_unused]] const char* sourcePathForDebug)
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZ::Data::AssetId& assetId, [[maybe_unused]] const char* sourcePathForDebug, TraceLevel reporting)
{
if (nullptr == AZ::IO::FileIOBase::GetInstance()->GetAlias("@products@"))
{
@@ -111,11 +115,11 @@ namespace AZ
}
else
{
AZ_Error("AssetUtils", false, "Could not load %s [Source='%s' Cache='%s' AssetID=%s] ",
AssetUtilsInternal::ReportIssue(reporting, AZStd::string::format("Could not load %s [Source='%s' Cache='%s' AssetID=%s] ",
AzTypeInfo<AssetDataT>::Name(),
sourcePathForDebug ? sourcePathForDebug : "<unknown>",
asset.GetHint().empty() ? "<unknown>" : asset.GetHint().c_str(),
assetId.ToString<AZStd::string>().c_str());
assetId.ToString<AZStd::string>().c_str()).c_str());
return AZ::Failure();
}
@@ -19,6 +19,8 @@ namespace AZ
//[GFX TODO][ATOM-4462] Replace this to use data driven color management system
//! Return a ColorEditorConfiguration for editing a Linear sRGB color in sRGB space.
AzToolsFramework::ColorEditorConfiguration GetLinearRgbEditorConfig();
//! Return a ColorEditorConfiguration for editing a sRGB color in sRGB space.
AzToolsFramework::ColorEditorConfiguration GetRgbEditorConfig();
} // namespace PropertyColorConfigs
} // namespace RPI
@@ -31,6 +31,7 @@ namespace AZ
static constexpr const char UvGroupName[] = "uvSets";
class MaterialAsset;
class MaterialAssetCreator;
//! This is a simple data structure for serializing in/out material source files.
class MaterialSourceData final
@@ -78,15 +79,33 @@ namespace AZ
//! Creates a MaterialAsset from the MaterialSourceData content.
//! @param assetId ID for the MaterialAsset
//! @param materialSourceFilePath Indicates the path of the .material file that the MaterialSourceData represents. Used for resolving file-relative paths.
//! @param materialSourceFilePath Indicates the path of the .material file that the MaterialSourceData represents. Used for
//! resolving file-relative paths.
//! @param elevateWarnings Indicates whether to treat warnings as errors
//! @param includeMaterialPropertyNames Indicates whether to save material property names into the material asset file
Outcome<Data::Asset<MaterialAsset>> CreateMaterialAsset(
Data::AssetId assetId,
AZStd::string_view materialSourceFilePath = "",
bool elevateWarnings = true,
bool includeMaterialPropertyNames = true
) const;
bool includeMaterialPropertyNames = true) const;
//! Creates a MaterialAsset from the MaterialSourceData content.
//! @param assetId ID for the MaterialAsset
//! @param materialSourceFilePath Indicates the path of the .material file that the MaterialSourceData represents. Used for
//! resolving file-relative paths.
//! @param elevateWarnings Indicates whether to treat warnings as errors
//! @param includeMaterialPropertyNames Indicates whether to save material property names into the material asset file
//! @param sourceDependencies if not null, will be populated with a set of all of the loaded material and material type paths
Outcome<Data::Asset<MaterialAsset>> CreateMaterialAssetFromSourceData(
Data::AssetId assetId,
AZStd::string_view materialSourceFilePath = "",
bool elevateWarnings = true,
bool includeMaterialPropertyNames = true,
AZStd::unordered_set<AZStd::string>* sourceDependencies = nullptr) const;
private:
void ApplyPropertiesToAssetCreator(
AZ::RPI::MaterialAssetCreator& materialAssetCreator, const AZStd::string_view& materialSourceFilePath) const;
};
} // namespace RPI
} // namespace AZ
@@ -209,10 +209,6 @@ namespace AZ
//! Traversal will stop once all properties have been enumerated or the callback function returns false
void EnumeratePropertiesInDisplayOrder(const EnumeratePropertiesCallback& callback) const;
//! Convert the property value into the format that will be stored in the source data
//! This is primarily needed to support conversions of special types like enums and images
bool ConvertPropertyValueToSourceDataFormat(const PropertyDefinition& propertyDefinition, MaterialPropertyValue& propertyValue) const;
Outcome<Data::Asset<MaterialTypeAsset>> CreateMaterialTypeAsset(Data::AssetId assetId, AZStd::string_view materialTypeSourceFilePath = "", bool elevateWarnings = true) const;
//! Possibly renames @propertyId based on the material version update steps.
@@ -28,7 +28,18 @@ namespace AZ
namespace MaterialUtils
{
Outcome<Data::Asset<ImageAsset>> GetImageAssetReference(AZStd::string_view materialSourceFilePath, const AZStd::string imageFilePath);
enum class GetImageAssetResult
{
Empty, //! No image was actually requested, the path was empty
Found, //! The requested asset was found
Missing //! The requested asset was not found, and a placeholder asset was used instead
};
//! Finds an ImageAsset referenced by a material file (or a placeholder)
//! @param imageAsset the resulting ImageAsset
//! @param materialSourceFilePath the full path to a material source file that is referenfing an image file
//! @param imageFilePath the path to an image source file, which could be relative to the asset root or relative to the material file
GetImageAssetResult GetImageAssetReference(Data::Asset<ImageAsset>& imageAsset, AZStd::string_view materialSourceFilePath, const AZStd::string imageFilePath);
//! Resolve an enum to a uint32_t given its name and definition array (in MaterialPropertyDescriptor).
//! @param propertyDescriptor it contains the definition of all enum names in an array.
@@ -37,7 +37,7 @@ namespace AZ
ResourcePoolAssetType m_poolType = ResourcePoolAssetType::Unknown;
AZStd::string m_poolName = "Unknown";
size_t m_budgetInBytes = 0;
uint32_t m_budgetInBytes = 0;
// Configuration for buffer pool
RHI::HeapMemoryLevel m_heapMemoryLevel = RHI::HeapMemoryLevel::Device;
@@ -40,7 +40,7 @@ namespace AZ
//! Set the timestamp value when the ProcessJob() started.
//! This is needed to synchronize between the ShaderAsset and ShaderVariantAsset when hot-reloading shaders.
//! The idea is that this timestamp must be greater or equal than the ShaderAsset.
void SetBuildTimestamp(AZStd::sys_time_t buildTimestamp);
void SetBuildTimestamp(AZ::u64 buildTimestamp);
//! Assigns a shaderStageFunction, which contains the byte code, to the slot dictated by the shader stage.
void SetShaderFunction(RHI::ShaderStage shaderStage, RHI::Ptr<RHI::ShaderStageFunction> shaderStageFunction);
@@ -147,6 +147,30 @@ namespace AZ
//! @param viewProjOverrideIndex Which view projection override entry to use, -1 if unused
virtual void DrawSphere( const AZ::Vector3& center, float radius, const AZ::Color& color, DrawStyle style = DrawStyle::Shaded, DepthTest depthTest = DepthTest::On, DepthWrite depthWrite = DepthWrite::On, FaceCullMode faceCull = FaceCullMode::Back, int32_t viewProjOverrideIndex = -1) = 0;
//! Draw a sphere.
//! @param center The center of the sphere.
//! @param direction The direction vector. The Pole of the hemisphere will point along this vector.
//! @param radius The radius.
//! @param color The color to draw the sphere.
//! @param style The draw style (point, wireframe, solid, shaded etc).
//! @param depthTest If depth testing should be enabled
//! @param depthWrite If depth writing should be enabled
//! @param faceCull Which (if any) facing triangles should be culled
//! @param viewProjOverrideIndex Which view projection override entry to use, -1 if unused
virtual void DrawSphere(const AZ::Vector3& center, const AZ::Vector3& direction, float radius, const AZ::Color& color, DrawStyle style = DrawStyle::Shaded, DepthTest depthTest = DepthTest::On, DepthWrite depthWrite = DepthWrite::On, FaceCullMode faceCull = FaceCullMode::Back, int32_t viewProjOverrideIndex = -1) = 0;
//! Draw a hemisphere.
//! @param center The center of the sphere.
//! @param direction The direction vector. The Pole of the hemisphere will point along this vector.
//! @param radius The radius.
//! @param color The color to draw the sphere.
//! @param style The draw style (point, wireframe, solid, shaded etc).
//! @param depthTest If depth testing should be enabled
//! @param depthWrite If depth writing should be enabled
//! @param faceCull Which (if any) facing triangles should be culled
//! @param viewProjOverrideIndex Which view projection override entry to use, -1 if unused
virtual void DrawHemisphere( const AZ::Vector3& center, const AZ::Vector3& direction, float radius, const AZ::Color& color, DrawStyle style = DrawStyle::Shaded, DepthTest depthTest = DepthTest::On, DepthWrite depthWrite = DepthWrite::On, FaceCullMode faceCull = FaceCullMode::Back, int32_t viewProjOverrideIndex = -1) = 0;
//! Draw a disk.
//! @param center The center of the disk.
//! @param direction The direction vector. The disk will be orthogonal this vector.
@@ -172,7 +196,7 @@ namespace AZ
//! @param viewProjOverrideIndex Which view projection override entry to use, -1 if unused
virtual void DrawCone(const AZ::Vector3& center, const AZ::Vector3& direction, float radius, float height, const AZ::Color& color, DrawStyle style = DrawStyle::Shaded, DepthTest depthTest = DepthTest::On, DepthWrite depthWrite = DepthWrite::On, FaceCullMode faceCull = FaceCullMode::Back, int32_t viewProjOverrideIndex = -1) = 0;
//! Draw a cylinder.
//! Draw a cylinder (with flat disks on the end).
//! @param center The center of the base circle.
//! @param direction The direction vector. The top end cap of the cylinder will face along this vector.
//! @param radius The radius.
@@ -185,6 +209,19 @@ namespace AZ
//! @param viewProjOverrideIndex Which view projection override entry to use, -1 if unused
virtual void DrawCylinder(const AZ::Vector3& center, const AZ::Vector3& direction, float radius, float height, const AZ::Color& color, DrawStyle style = DrawStyle::Shaded, DepthTest depthTest = DepthTest::On, DepthWrite depthWrite = DepthWrite::On, FaceCullMode faceCull = FaceCullMode::Back, int32_t viewProjOverrideIndex = -1) = 0;
//! Draw a cylinder without flat disk on the end.
//! @param center The center of the base circle.
//! @param direction The direction vector. The top end cap of the cylinder will face along this vector.
//! @param radius The radius.
//! @param height The height of the cylinder.
//! @param color The color to draw the cylinder.
//! @param style The draw style (point, wireframe, solid, shaded etc).
//! @param depthTest If depth testing should be enabled
//! @param depthWrite If depth writing should be enabled
//! @param faceCull Which (if any) facing triangles should be culled
//! @param viewProjOverrideIndex Which view projection override entry to use, -1 if unused
virtual void DrawCylinderNoEnds(const AZ::Vector3& center, const AZ::Vector3& direction, float radius, float height, const AZ::Color& color, DrawStyle style = DrawStyle::Shaded, DepthTest depthTest = DepthTest::On, DepthWrite depthWrite = DepthWrite::On, FaceCullMode faceCull = FaceCullMode::Back, int32_t viewProjOverrideIndex = -1) = 0;
//! Draw an axis-aligned bounding box with no transform.
//! @param aabb The AABB (typically the bounding box of a set of world space points).
//! @param color The color to draw the box.
@@ -15,6 +15,7 @@
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/Asset/AssetManagerBus.h>
#include <AzCore/Debug/Budget.h>
#include <AzCore/EBus/Event.h>
#include <AzCore/Name/Name.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <AzCore/std/containers/fixed_vector.h>
@@ -24,6 +25,8 @@ AZ_DECLARE_BUDGET(RPI);
namespace AZ
{
class Matrix4x4;
namespace RHI
{
class ShaderResourceGroup;
@@ -52,6 +55,8 @@ namespace AZ
using ViewportContextPtr = AZStd::shared_ptr<ViewportContext>;
using ConstViewportContextPtr = AZStd::shared_ptr<const ViewportContext>;
using MatrixChangedEvent = Event<const AZ::Matrix4x4&>;
//! The name used to identify a View within in a Scene.
//! Note that the same View could have different tags in different RenderPipelines.
using PipelineViewTag = AZ::Name;
@@ -38,6 +38,8 @@
namespace AZ
{
class Job;
class TaskGraphActiveInterface;
class TaskGraph;
namespace RHI
{
@@ -256,7 +258,13 @@ namespace AZ
//! Must be called between BeginCulling() and EndCulling(), once for each active scene/view pair.
//! Will create child jobs under the parentJob to do the processing in parallel.
//! Can be called in parallel (i.e. to perform culling on multiple views at the same time).
void ProcessCullables(const Scene& scene, View& view, AZ::Job& parentJob);
void ProcessCullablesJobs(const Scene& scene, View& view, AZ::Job& parentJob);
//! Performs render culling and lod selection for a View, then adds the visible renderpackets to that View.
//! Must be called between BeginCulling() and EndCulling(), once for each active scene/view pair.
//! Will create child task graphs that signal the TaskGraphEvent to do the processing in parallel.
//! Can be called in parallel (i.e. to perform culling on multiple views at the same time).
void ProcessCullablesTG(const Scene& scene, View& view, AZ::TaskGraph& taskGraph);
//! Adds a Cullable to the underlying visibility system(s).
//! Must be called at least once on initialization and whenever a Cullable's position or bounds is changed.
@@ -276,17 +284,20 @@ namespace AZ
return m_debugCtx;
}
static const size_t WorkListCapacity = 5;
using WorkListType = AZStd::fixed_vector<AzFramework::IVisibilityScene::NodeData, WorkListCapacity>;
protected:
size_t CountObjectsInScene();
private:
void BeginCullingTaskGraph(const AZStd::vector<ViewPtr>& views);
void BeginCullingJobs(const AZStd::vector<ViewPtr>& views);
void ProcessCullablesCommon(const Scene& scene, View& view, AZ::Frustum& frustum, void*& maskedOcclusionCulling);
const Scene* m_parentScene = nullptr;
AzFramework::IVisibilityScene* m_visScene = nullptr;
CullingDebugContext m_debugCtx;
AZStd::concurrency_checker m_cullDataConcurrencyCheck;
OcclusionPlaneVector m_occlusionPlanes;
AZ::TaskGraphActiveInterface* m_taskGraphActive = nullptr;
};
@@ -22,10 +22,12 @@
#include <AzCore/base.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/Component/EntityId.h>
#include <AzCore/Jobs/JobCompletion.h>
namespace AZ
{
// forward declares
class Job;
namespace RPI
{
//! @class FeatureProcessor
@@ -51,6 +53,7 @@ namespace AZ
struct SimulatePacket
{
AZ::Job* m_parentJob = nullptr;
};
struct RenderPacket
@@ -29,6 +29,14 @@ namespace AZ
Count
};
namespace DefaultImageAssetPaths
{
static constexpr char DefaultFallback[] = "textures/defaults/defaultfallback.png.streamingimage";
static constexpr char Processing[] = "textures/defaults/processing.png.streamingimage";
static constexpr char ProcessingFailed[] = "textures/defaults/processingfailed.png.streamingimage";
static constexpr char Missing[] = "textures/defaults/missing.png.streamingimage";
}
class ImageSystemInterface
{
public:
@@ -11,6 +11,7 @@
#include <AzCore/std/parallel/atomic.h>
#include <AzCore/std/smart_ptr/intrusive_base.h>
#include <AzCore/Memory/PoolAllocator.h>
#include <AzCore/std/containers/intrusive_list.h>
#include <Atom/RHI.Reflect/Limits.h>
@@ -131,6 +131,19 @@ namespace AZ
// Generates child passes from source PassTemplate
void CreatePassesFromTemplate();
// Generates child clear passes to clear input and input/output attachments
// TODO: These two functions are a workaround for a complicated edge case:
// Let Parent Pass P1 have two children, C1 and C2. C1 writes to an attachment that C2 reads,
// but C1 can be disabled, in which case we just want C2 to read the cleared texture.
// Because of this, the attachment is owned by the parent pass, that way it is always available for C2
// to read even when C1 is disabled. However we still want to clear the attachment before C2 reads it.
// We tried overriding the LoadStoreAction to clear on C2's slot when C1 is disabled, but the RHI
// doesn't allow for clears on Input only slots. Changing the slot to InputOutput was in conflict with
// the texture definition in the SRG, and it couldn't be changed to RW because it was an MSAA texture.
// So now we detect clear actions on parent slots and generate a clear pass for them.
void CreateClearPassFromBinding(PassAttachmentBinding& binding, PassRequest& clearRequest);
void CreateClearPassesFromBindings();
};
template<typename PassType>
@@ -43,6 +43,10 @@ namespace AZ
// Rendering -> Idle
// -> Queued (Rendering will transition to Queued if a pass was queued with the PassSystem during Rendering)
//
// Any State -> Orphaned (transition to Orphaned state can be outside the jurisdiction of the pass and so can happen from any state)
// Orphaned -> Queued (When coming out of Orphaned state, pass will queue itself for build. In practice this
// (almost?) never happens as orphaned passes are re-created in most if not all cases.)
//
enum class PassState : u8
{
// Default value, you should only ever see this in the Pass constructor
@@ -92,7 +96,10 @@ namespace AZ
// |
// V
// Pass is currently rendering. Pass must be in Idle state before entering this state
Rendering
Rendering,
// Special state: Orphaned State, pass was removed from it's parent and is awaiting deletion
Orphaned
};
// This enum keeps track of what actions the pass is queued for with the pass system
@@ -56,8 +56,8 @@ namespace AZ
OwnerRenderPipeline = AZ_BIT(5)
};
void SetOwenrScene(const Scene* scene);
void SetOwenrRenderPipeline(const RenderPipeline* renderPipeline);
void SetOwnerScene(const Scene* scene);
void SetOwnerRenderPipeline(const RenderPipeline* renderPipeline);
void SetPassName(Name passName);
void SetTemplateName(Name passTemplateName);
void SetPassClass(TypeId passClassTypeId);
@@ -62,6 +62,10 @@ namespace AZ
//! It may return nullptr if this pass is independent with any views.
ViewPtr GetView() const;
// Add a srg to srg list to be bound for this pass
void BindSrg(const RHI::ShaderResourceGroup* srg);
protected:
explicit RenderPass(const PassDescriptor& descriptor);
@@ -95,9 +99,6 @@ namespace AZ
// Clear the srg list
void ResetSrgs();
// Add a srg to srg list to be bound for this pass
void BindSrg(const RHI::ShaderResourceGroup* srg);
// Set srgs for pass's execution
void SetSrgsForDraw(RHI::CommandList* commandList);
void SetSrgsForDispatch(RHI::CommandList* commandList);
@@ -0,0 +1,42 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Memory/SystemAllocator.h>
#include <Atom/RPI.Public/Pass/RenderPass.h>
namespace AZ
{
namespace RPI
{
//! Only use this for debug purposes and edge cases
//! The correct and efficient way to clear a pass is through the LoadStoreAction on the pass slot
//! This will clear a given image attachment to the specified clear value.
class SlowClearPass
: public RenderPass
{
AZ_RPI_PASS(SlowClearPass);
public:
AZ_RTTI(SlowClearPass, "{31CBAD6C-108F-4F3F-B498-ED968DFCFCE2}", RenderPass);
AZ_CLASS_ALLOCATOR(SlowClearPass, SystemAllocator, 0);
virtual ~SlowClearPass() = default;
//! Creates a SlowClearPass
static Ptr<SlowClearPass> Create(const PassDescriptor& descriptor);
protected:
SlowClearPass(const PassDescriptor& descriptor);
void InitializeInternal() override;
private:
RHI::ClearValue m_clearValue;
};
} // namespace RPI
} // namespace AZ
@@ -97,8 +97,7 @@ namespace AZ
// SystemTickBus::OnTick
void OnSystemTick() override;
// Fill system time and game time information for simulation or rendering
void FillTickTimeInfo();
float GetCurrentTime() const;
// The set of core asset handlers registered by the system.
AZStd::vector<AZStd::unique_ptr<Data::AssetHandler>> m_assetHandlers;
@@ -124,7 +123,7 @@ namespace AZ
// The job policy used for feature processor's rendering prepare
RHI::JobPolicy m_prepareRenderJobPolicy = RHI::JobPolicy::Parallel;
TickTimeInfo m_tickTime;
float m_currentSimulationTime = 0.0f;
RPISystemDescriptor m_descriptor;
@@ -34,8 +34,7 @@ namespace AZ
RPISystemInterface() = default;
virtual ~RPISystemInterface() = default;
//! Pre-load some system assets. This should be called once the asset catalog is ready and before create any RPI instances.
//! Note: can't rely on the AzFramework::AssetCatalogEventBus's OnCatalogLoaded since the order of calling handlers is undefined.
//! Pre-load some system assets. This should be called once Critical Asset have compiled ready and before create any RPI instances.
virtual void InitializeSystemAssets() = 0;
//! Was the RPI system initialized properly
@@ -32,7 +32,6 @@ namespace AZ
namespace RPI
{
class Scene;
struct TickTimeInfo;
class ShaderResourceGroup;
class AnyAsset;
class WindowContext;
@@ -203,7 +202,7 @@ namespace AZ
void OnRemovedFromScene(Scene* scene);
// Called when this pipeline is about to be rendered
void OnStartFrame(const TickTimeInfo& tick);
void OnStartFrame(float time);
// Called when the rendering of current frame is finished.
void OnFrameEnd();
@@ -48,14 +48,6 @@ namespace AZ
// Callback function to modify values of a ShaderResourceGroup
using ShaderResourceGroupCallback = AZStd::function<void(ShaderResourceGroup*)>;
//! A structure for ticks which contains system time and game time.
struct TickTimeInfo
{
float m_currentGameTime;
float m_gameDeltaTime = 0;
};
class Scene final
: public SceneRequestBus::Handler
{
@@ -179,12 +171,14 @@ namespace AZ
// Cpu simulation which runs all active FeatureProcessor Simulate() functions.
// @param jobPolicy if it's JobPolicy::Parallel, the function will spawn a job thread for each FeatureProcessor's simulation.
void Simulate(const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy);
// @param simulationTime the number of seconds since the application started
void Simulate(RHI::JobPolicy jobPolicy, float simulationTime);
// Collect DrawPackets from FeatureProcessors
// @param jobPolicy if it's JobPolicy::Parallel, the function will spawn a job thread for each FeatureProcessor's
// PrepareRender.
void PrepareRender(const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy);
// @param simulationTime the number of seconds since the application started; this is the same time value that was passed to Simulate()
void PrepareRender(RHI::JobPolicy jobPolicy, float simulationTime);
// Function called when the current frame is finished rendering.
void OnFrameEnd();
@@ -200,8 +194,8 @@ namespace AZ
// This function is called every time scene's render pipelines change.
void RebuildPipelineStatesLookup();
// Helper function to wait for end of TaskGraph
void WaitTGEvent(AZ::TaskGraphEvent& completionTGEvent, AZStd::atomic_bool* workToWaitOn = nullptr);
// Helper function to wait for end of TaskGraph and then delete the TaskGraphEvent
void WaitAndCleanTGEvent(AZStd::unique_ptr<AZ::TaskGraphEvent>&& completionTGEvent);
// Helper function for wait and clean up a completion job
void WaitAndCleanCompletionJob(AZ::JobCompletion*& completionJob);
@@ -230,8 +224,7 @@ namespace AZ
AZStd::vector<RenderPipelinePtr> m_pipelines;
// CPU simulation TaskGraphEvent to wait for completion of all the simulation tasks
AZ::TaskGraphEvent m_simulationFinishedTGEvent;
AZStd::atomic_bool m_simulationFinishedWorkActive = false;
AZStd::unique_ptr<AZ::TaskGraphEvent> m_simulationFinishedTGEvent;
// CPU simulation job completion for track all feature processors' simulation jobs
AZ::JobCompletion* m_simulationCompletion = nullptr;
@@ -267,6 +260,7 @@ namespace AZ
// Registry which allocates draw filter tag for RenderPipeline
RHI::Ptr<RHI::DrawFilterTagRegistry> m_drawFilterTagRegistry;
RHI::ShaderInputConstantIndex m_timeInputIndex;
float m_simulationTime;
};
@@ -52,9 +52,8 @@ namespace AZ
*/
class Shader final
: public Data::InstanceData
, public Data::AssetBus::Handler
, public Data::AssetBus::MultiHandler
, public ShaderVariantFinderNotificationBus::Handler
, public ShaderReloadNotificationBus::Handler
{
friend class ShaderSystem;
public:
@@ -154,6 +153,8 @@ namespace AZ
ConstPtr<RHI::PipelineLibraryData> LoadPipelineLibrary() const;
void SavePipelineLibrary() const;
const ShaderVariant& GetVariantInternal(ShaderVariantStableId shaderVariantStableId);
///////////////////////////////////////////////////////////////////
/// AssetBus overrides
@@ -165,15 +166,6 @@ namespace AZ
void OnShaderVariantTreeAssetReady(Data::Asset<ShaderVariantTreeAsset> /*shaderVariantTreeAsset*/, bool /*isError*/) override {};
void OnShaderVariantAssetReady(Data::Asset<ShaderVariantAsset> shaderVariantAsset, bool IsError) override;
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
// ShaderReloadNotificationBus overrides...
void OnShaderAssetReinitialized(const Data::Asset<ShaderAsset>& shaderAsset) override;
// Note we don't need OnShaderVariantReinitialized because the Shader class doesn't do anything with the data inside
// the ShaderVariant object. The only thing we might want to do is propagate the message upward, but that's unnecessary
// because the ShaderReloadNotificationBus uses the Shader's AssetId as the ID for all messages including those from the variants.
// And of course we don't need to handle OnShaderReinitialized because this *is* this Shader.
///////////////////////////////////////////////////////////////////
//! A strong reference to the shader asset.
Data::Asset<ShaderAsset> m_asset;
@@ -206,6 +198,12 @@ namespace AZ
//! PipelineLibrary file name
char m_pipelineLibraryPath[AZ_MAX_PATH_LEN] = { 0 };
//! During OnAssetReloaded, the internal references to ShaderVariantAsset inside
//! ShaderAsset are not updated correctly. We store here a reference to the root ShaderVariantAsset
//! when it got reloaded, later when We get OnAssetReloaded for the ShaderAsset We update its internal
//! reference to the root variant asset.
Data::Asset<ShaderVariantAsset> m_reloadedRootShaderVariantAsset;
};
}
}
@@ -24,6 +24,9 @@ namespace AZ
class ShaderReloadDebugTracker final
{
public:
static void Init();
static void Shutdown();
static bool IsEnabled();
//! Begin a code section. Will print a "[BEGIN] <sectionName>" header, and all subsequent calls will be indented.
@@ -34,8 +37,8 @@ namespace AZ
if (IsEnabled())
{
const AZStd::string sectionName = AZStd::string::format(sectionNameFormat, args...);
AZ_TracePrintf("ShaderReloadDebug", "%*s [BEGIN] %s \n", s_indent, "", sectionName.c_str());
s_indent += IndentSpaces;
AZ_TracePrintf("ShaderReloadDebug", "%*s [BEGIN] %s \n", GetIndent(), "", sectionName.c_str());
AddIndent();
}
#endif
}
@@ -48,8 +51,8 @@ namespace AZ
if (IsEnabled())
{
const AZStd::string sectionName = AZStd::string::format(sectionNameFormat, args...);
s_indent -= IndentSpaces;
AZ_TracePrintf("ShaderReloadDebug", "%*s [_END_] %s \n", s_indent, "", sectionName.c_str());
RemoveIndent();
AZ_TracePrintf("ShaderReloadDebug", "%*s [_END_] %s \n", GetIndent(), "", sectionName.c_str());
}
#endif
}
@@ -63,7 +66,7 @@ namespace AZ
{
const AZStd::string message = AZStd::string::format(format, args...);
AZ_TracePrintf("ShaderReloadDebug", "%*s %s \n", s_indent, "", message.c_str());
AZ_TracePrintf("ShaderReloadDebug", "%*s %s \n", GetIndent(), "", message.c_str());
}
#endif
}
@@ -86,9 +89,12 @@ namespace AZ
};
private:
static bool s_enabled;
static int s_indent;
static constexpr int IndentSpaces = 4;
static void MakeReady();
static void AddIndent();
static void RemoveIndent();
static int GetIndent();
};
} // namespace RPI
@@ -19,7 +19,6 @@ namespace AZ
//! the RHI::PipelineStateType of the parent Shader instance. For shaders on the raster
//! pipeline, the RHI::DrawFilterTag is also provided.
class ShaderVariant final
: public Data::AssetBus::MultiHandler
{
friend class Shader;
public:
@@ -58,9 +57,6 @@ namespace AZ
const Data::Asset<ShaderVariantAsset>& shaderVariantAsset,
SupervariantIndex supervariantIndex);
// AssetBus overrides...
void OnAssetReloaded(Data::Asset<Data::AssetData> asset) override;
//! A reference to the shader asset that this is a variant of.
Data::Asset<ShaderAsset> m_shaderAsset;
@@ -24,6 +24,9 @@ class MaskedOcclusionCulling;
namespace AZ
{
// forward declares
class Job;
class TaskGraphEvent;
namespace RHI
{
class FrameScheduler;
@@ -92,12 +95,18 @@ namespace AZ
const AZ::Matrix4x4& GetViewToWorldMatrix() const;
const AZ::Matrix4x4& GetViewToClipMatrix() const;
const AZ::Matrix4x4& GetWorldToClipMatrix() const;
const AZ::Matrix4x4& GetClipToWorldMatrix() const;
AZ::Matrix3x4 GetWorldToViewMatrixAsMatrix3x4() const;
AZ::Matrix3x4 GetViewToWorldMatrixAsMatrix3x4() const;
//! Get the camera's world transform, converted from the viewToWorld matrix's native y-up to z-up
AZ::Transform GetCameraTransform() const;
//! Finalize draw lists in this view. This function should only be called when all
//! draw packets for current frame are added.
void FinalizeDrawLists();
void FinalizeDrawListsJob(AZ::Job* parentJob);
void FinalizeDrawListsTG(AZ::TaskGraphEvent& finalizeDrawListsTGEvent);
bool HasDrawListTag(RHI::DrawListTag drawListTag);
@@ -118,7 +127,6 @@ namespace AZ
//! Update View's SRG values and compile. This should only be called once per frame before execute command lists.
void UpdateSrg();
using MatrixChangedEvent = AZ::Event<const AZ::Matrix4x4&>;
//! Notifies consumers when the world to view matrix has changed.
void ConnectWorldToViewMatrixChangedHandler(MatrixChangedEvent::Handler& handler);
//! Notifies consumers when the world to clip matrix has changed.
@@ -130,17 +138,23 @@ namespace AZ
//! Returns the masked occlusion culling interface
MaskedOcclusionCulling* GetMaskedOcclusionCulling();
//! This is called by RenderPipeline when this view is added to the pipeline.
void OnAddToRenderPipeline();
private:
View() = delete;
View(const AZ::Name& name, UsageFlags usage);
//! Sorts the finalized draw lists in this view
void SortFinalizedDrawLists();
void SortFinalizedDrawListsJob(AZ::Job* parentJob);
void SortFinalizedDrawListsTG(AZ::TaskGraphEvent& finalizeDrawListsTGEvent);
//! Sorts a drawList using the sort function from a pass with the corresponding drawListTag
void SortDrawList(RHI::DrawList& drawList, RHI::DrawListTag tag);
//! Attempt to create a shader resource group.
void TryCreateShaderResourceGroup();
AZ::Name m_name;
UsageFlags m_usageFlags;
@@ -13,7 +13,6 @@
#include <Atom/RPI.Public/WindowContext.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom/RPI.Public/SceneBus.h>
#include <AzCore/EBus/Event.h>
namespace AZ
{
@@ -98,7 +97,6 @@ namespace AZ
//! Alternatively, connect to ViewportContextNotificationsBus and listen to ViewportContextNotifications::OnViewportDpiScalingChanged.
void ConnectDpiScalingFactorChangedHandler(ScalarChangedEvent::Handler& handler);
using MatrixChangedEvent = AZ::Event<const AZ::Matrix4x4&>;
//! Notifies consumers when the view matrix has changed.
void ConnectViewMatrixChangedHandler(MatrixChangedEvent::Handler& handler);
//! Notifies consumers when the projection matrix has changed.
@@ -121,17 +119,12 @@ namespace AZ
void ConnectAboutToBeDestroyedHandler(ViewportIdEvent::Handler& handler);
// ViewportRequestBus interface overrides...
//! Gets the current camera's view matrix.
const AZ::Matrix4x4& GetCameraViewMatrix() const override;
//! Sets the current camera's view matrix.
AZ::Matrix3x4 GetCameraViewMatrixAsMatrix3x4() const override;
void SetCameraViewMatrix(const AZ::Matrix4x4& matrix) override;
//! Gets the current camera's projection matrix.
const AZ::Matrix4x4& GetCameraProjectionMatrix() const override;
//! Sets the current camera's projection matrix.
void SetCameraProjectionMatrix(const AZ::Matrix4x4& matrix) override;
//! Convenience method, gets the AZ::Transform corresponding to this camera's view matrix.
AZ::Transform GetCameraTransform() const override;
//! Convenience method, sets the camera's view matrix from this AZ::Transform.
void SetCameraTransform(const AZ::Transform& transform) override;
private:
@@ -67,6 +67,9 @@ namespace AZ
virtual ViewportContextPtr GetViewportContextByName(const Name& contextName) const = 0;
//! Gets the registered ViewportContext with the corresponding ID, if any.
virtual ViewportContextPtr GetViewportContextById(AzFramework::ViewportId id) const = 0;
//! Gets the registered ViewportContext with matching RPI::Scene, if any.
//! This function will return the first result.
virtual ViewportContextPtr GetViewportContextByScene(const Scene* scene) const = 0;
//! Maps a ViewportContext to a new name, inheriting the View stack (if any) registered to that context name.
//! This can be used to switch "default" viewports by registering a viewport with the default ViewportContext name
//! but note that only one ViewportContext can be mapped to a context name at a time.
@@ -41,6 +41,7 @@ namespace AZ
bool PopView(const Name& contextName, ViewPtr view) override;
ViewPtr GetCurrentView(const Name& contextName) const override;
ViewportContextPtr GetDefaultViewportContext() const override;
ViewportContextPtr GetViewportContextByScene(const Scene* scene) const override;
private:
void RegisterViewportContext(const Name& contextName, ViewportContextPtr viewportContext);
@@ -118,7 +118,7 @@ namespace AZ
ResetIssueCounts(); // Because the asset creator can be used multiple times
m_asset = Data::AssetManager::Instance().CreateAsset<AssetDataT>(assetId, AZ::Data::AssetLoadBehavior::PreLoad);
m_asset = Data::Asset<AssetDataT>(assetId, aznew AssetDataT, AZ::Data::AssetLoadBehavior::PreLoad);
m_beginCalled = true;
if (!m_asset)
@@ -138,6 +138,7 @@ namespace AZ
}
else
{
Data::AssetManager::Instance().AssignAssetData(m_asset);
result = AZStd::move(m_asset);
success = true;
}
@@ -25,6 +25,9 @@ namespace AZ
const Data::Asset<Data::AssetData>& asset,
AZStd::shared_ptr<Data::AssetDataStream> stream,
const Data::AssetFilterCB& assetLoadFilterCB) override;
// Return a default fallback image if an asset is missing
Data::AssetId AssetMissingInCatalog(const Data::Asset<Data::AssetData>& /*asset*/) override;
};
}
}
@@ -0,0 +1,43 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <Atom/RHI.Reflect/ClearValue.h>
#include <Atom/RPI.Reflect/Pass/RenderPassData.h>
namespace AZ
{
namespace RPI
{
//! Custom data for the SlowClearPass. Should be specified in the PassRequest.
struct SlowClearPassData
: public RenderPassData
{
AZ_RTTI(SlowClearPassData, "{5F2C24A4-62D0-4E60-91EC-C207C10D15C6}", RenderPassData);
AZ_CLASS_ALLOCATOR(SlowClearPassData, SystemAllocator, 0);
SlowClearPassData() = default;
virtual ~SlowClearPassData() = default;
static void Reflect(ReflectContext* context)
{
if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
{
serializeContext->Class<SlowClearPassData, RenderPassData>()
->Version(0)
->Field("ClearValue", &SlowClearPassData::m_clearValue)
;
}
}
RHI::ClearValue m_clearValue;
};
} // namespace RPI
} // namespace AZ
@@ -53,12 +53,12 @@ namespace AZ
class ShaderAsset final
: public Data::AssetData
, public ShaderVariantFinderNotificationBus::Handler
, public Data::AssetBus::Handler
, public AssetInitBus::Handler
{
friend class ShaderAssetCreator;
friend class ShaderAssetHandler;
friend class ShaderAssetTester;
friend class Shader;
public:
AZ_RTTI(ShaderAsset, "{823395A3-D570-49F4-99A9-D820CD1DEF98}", Data::AssetData);
static void Reflect(ReflectContext* context);
@@ -96,7 +96,7 @@ namespace AZ
//! Return the timestamp when the shader asset was built.
//! This is used to synchronize versions of the ShaderAsset and ShaderVariantTreeAsset, especially during hot-reload.
AZStd::sys_time_t GetShaderAssetBuildTimestamp() const;
AZStd::sys_time_t GetBuildTimestamp() const;
//! Returns the shader option group layout.
const ShaderOptionGroupLayout* GetShaderOptionGroupLayout() const;
@@ -212,22 +212,19 @@ namespace AZ
return GetAttribute(shaderStage, attributeName, DefaultSupervariantIndex);
}
private:
///////////////////////////////////////////////////////////////////
/// AssetBus overrides
void OnAssetReloaded(Data::Asset<Data::AssetData> asset) override;
void OnAssetReady(Data::Asset<Data::AssetData> asset) override;
///////////////////////////////////////////////////////////////////
void ReinitializeRootShaderVariant(Data::Asset<Data::AssetData> asset);
///////////////////////////////////////////////////////////////////
/// ShaderVariantFinderNotificationBus overrides
void OnShaderVariantTreeAssetReady(Data::Asset<ShaderVariantTreeAsset> shaderVariantTreeAsset, bool isError) override;
void OnShaderVariantAssetReady(Data::Asset<ShaderVariantAsset> /*shaderVariantAsset*/, bool /*isError*/) override {};
///////////////////////////////////////////////////////////////////
// Only Shader::OnAssetReloaded() should call this function, because it is pointless for an Asset to
// to refresh its own "serialized references" to other assets during OnAssetReloaded().
// The problem is that OnAssetReloaded() doesn't do a good job at updating "serialized references" to other assets,
// So some other class must update the reference and that's why Shader() is the best class to do it.
void UpdateRootShaderVariantAsset(SupervariantIndex SupervariantIndex, Data::Asset<ShaderVariantAsset> newRootVariant);
//! A Supervariant represents a set of static shader compilation parameters.
//! Those parameters can be predefined c-preprocessor macros or specific arguments
//! for AZSLc.
@@ -297,7 +294,7 @@ namespace AZ
Name m_drawListName;
//! Use to synchronize versions of the ShaderAsset and ShaderVariantTreeAsset, especially during hot-reload.
AZStd::sys_time_t m_shaderAssetBuildTimestamp = 0;
AZ::u64 m_buildTimestamp = 0;
///////////////////////////////////////////////////////////////////
@@ -61,7 +61,7 @@ namespace AZ
//! Return the timestamp when this asset was built, and it must be >= than the timestamp of the main ShaderAsset.
//! This is used to synchronize versions of the ShaderAsset and ShaderVariantAsset, especially during hot-reload.
AZStd::sys_time_t GetBuildTimestamp() const;
AZ::u64 GetBuildTimestamp() const;
bool IsRootVariant() const { return m_stableId == RPI::RootShaderVariantStableId; }
@@ -80,7 +80,7 @@ namespace AZ
AZStd::array<RHI::Ptr<RHI::ShaderStageFunction>, RHI::ShaderStageCount> m_functionsByStage;
//! Used to synchronize versions of the ShaderAsset and ShaderVariantAsset, especially during hot-reload.
AZStd::sys_time_t m_buildTimestamp = 0;
AZ::u64 m_buildTimestamp = 0;
};
class ShaderVariantAssetHandler final
@@ -63,11 +63,21 @@ namespace AZ
{
BusDisconnect();
}
bool MaterialBuilder::ReportMaterialAssetWarningsAsErrors() const
{
bool warningsAsErrors = false;
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
{
settingsRegistry->Get(warningsAsErrors, "/O3DE/Atom/RPI/MaterialBuilder/WarningsAsErrors");
}
return warningsAsErrors;
}
//! Adds all relevant dependencies for a referenced source file, considering that the path might be relative to the original file location or a full asset path.
//! This will usually include multiple source dependencies and a single job dependency, but will include only source dependencies if the file is not found.
//! Note the AssetBuilderSDK::JobDependency::m_platformIdentifier will not be set by this function. The calling code must set this value before passing back
//! to the AssetBuilderSDK::CreateJobsResponse. If isOrderedOnceForMaterialTypes is true and the dependency is a materialtype file, the job dependency type
//! to the AssetBuilderSDK::CreateJobsResponse. If isOrderedOnceForMaterialTypes is true and the dependency is a .materialtype file, the job dependency type
//! will be set to JobDependencyType::OrderOnce.
void AddPossibleDependencies(AZStd::string_view currentFilePath,
AZStd::string_view referencedParentPath,
@@ -277,8 +287,8 @@ namespace AZ
return materialTypeAssetOutcome.GetValue();
}
AZ::Data::Asset<MaterialAsset> CreateMaterialAsset(AZStd::string_view materialSourceFilePath, const rapidjson::Value& json)
AZ::Data::Asset<MaterialAsset> MaterialBuilder::CreateMaterialAsset(AZStd::string_view materialSourceFilePath, const rapidjson::Value& json) const
{
auto material = LoadSourceData<MaterialSourceData>(json, materialSourceFilePath);
@@ -292,7 +302,7 @@ namespace AZ
return {};
}
auto materialAssetOutcome = material.GetValue().CreateMaterialAsset(Uuid::CreateRandom(), materialSourceFilePath, true);
auto materialAssetOutcome = material.GetValue().CreateMaterialAsset(Uuid::CreateRandom(), materialSourceFilePath, ReportMaterialAssetWarningsAsErrors());
if (!materialAssetOutcome.IsSuccess())
{
return {};
@@ -9,6 +9,8 @@
#pragma once
#include <AssetBuilderSDK/AssetBuilderBusses.h>
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
#include <AzCore/JSON/document.h>
namespace AZ
{
@@ -37,6 +39,9 @@ namespace AZ
private:
AZ::Data::Asset<MaterialAsset> CreateMaterialAsset(AZStd::string_view materialSourceFilePath, const rapidjson::Value& json) const;
bool ReportMaterialAssetWarningsAsErrors() const;
bool m_isShuttingDown = false;
};
@@ -948,19 +948,17 @@ namespace AZ
{
AZStd::vector<uint16_t>& skinJointIndices = productMesh.m_skinJointIndices;
AZStd::vector<float>& skinWeights = productMesh.m_skinWeights;
const auto& sourceMeshData = sourceMesh.m_meshData;
size_t numInfluencesAdded = 0;
for (const auto& skinData : sourceMesh.m_skinData)
{
const AZ::u32 controlPointIndex = sourceMeshData->GetControlPointIndex(static_cast<int>(vertexIndex));
const size_t numSkinInfluences = skinData->GetLinkCount(controlPointIndex);
const size_t numSkinInfluences = skinData->GetLinkCount(vertexIndex);
size_t numInfluencesExcess = 0;
for (size_t influenceIndex = 0; influenceIndex < numSkinInfluences; ++influenceIndex)
{
const AZ::SceneAPI::DataTypes::ISkinWeightData::Link& link = skinData->GetLink(controlPointIndex, influenceIndex);
const AZ::SceneAPI::DataTypes::ISkinWeightData::Link& link = skinData->GetLink(vertexIndex, influenceIndex);
const float weight = link.weight;
const AZStd::string& boneName = skinData->GetBoneName(link.boneId);
@@ -2088,7 +2086,7 @@ namespace AZ
AZ::Vector3 vpos; //note: it seems to be fastest to reuse a local Vector3 rather than constructing new ones each loop iteration
for (uint32_t i = 0; i < elementCount; ++i)
{
vpos.Set(const_cast<float*>(reinterpret_cast<const float*>(&buffer[i])));
vpos.Set(reinterpret_cast<const float*>(&buffer[i]));
aabb.AddPoint(vpos);
}
}
@@ -25,7 +25,7 @@ namespace AZ
namespace RPI
{
/**
* This is the central component that drive the process of exporting a scene to Model
* This is the central component that drive the process of exporting a scene to Model
* and Material assets. It delegates asset-build duties to other components like
* ModelAssetBuilderComponent and MaterialAssetBuilderComponent via export events.
*/
@@ -55,7 +55,7 @@ namespace AZ
AZStd::string_view m_relativeFileName;
AZStd::string_view m_extension;
const Uuid m_sourceUuid;
const Uuid m_sourceUuid = Uuid::CreateNull();
const DataStream::StreamType m_dataStreamType = DataStream::ST_BINARY;
};
@@ -10,6 +10,7 @@
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzCore/IO/IOUtils.h>
#include <AzCore/IO/Path/Path.h>
namespace AZ
{
@@ -46,6 +47,12 @@ namespace AZ
AZStd::string ResolvePathReference(const AZStd::string& originatingSourceFilePath, const AZStd::string& referencedSourceFilePath)
{
// The IsAbsolute part prevents "second join parameter is an absolute path" warnings in StringFunc::Path::Join below
if (referencedSourceFilePath.empty() || AZ::IO::PathView{referencedSourceFilePath}.IsAbsolute())
{
return referencedSourceFilePath;
}
AZStd::string normalizedReferencedPath = referencedSourceFilePath;
AzFramework::StringFunc::Path::Normalize(normalizedReferencedPath);
@@ -113,7 +120,7 @@ namespace AZ
return results;
}
Outcome<Data::AssetId> MakeAssetId(const AZStd::string& sourcePath, uint32_t productSubId)
Outcome<Data::AssetId> MakeAssetId(const AZStd::string& sourcePath, uint32_t productSubId, TraceLevel reporting)
{
bool assetFound = false;
AZ::Data::AssetInfo sourceInfo;
@@ -122,7 +129,7 @@ namespace AZ
if (!assetFound)
{
AZ_Error("AssetUtils", false, "Could not find asset [%s]", sourcePath.c_str());
AssetUtilsInternal::ReportIssue(reporting, AZStd::string::format("Could not find asset [%s]", sourcePath.c_str()).c_str());
return AZ::Failure();
}
else
@@ -131,10 +138,10 @@ namespace AZ
}
}
Outcome<Data::AssetId> MakeAssetId(const AZStd::string& originatingSourcePath, const AZStd::string& referencedSourceFilePath, uint32_t productSubId)
Outcome<Data::AssetId> MakeAssetId(const AZStd::string& originatingSourcePath, const AZStd::string& referencedSourceFilePath, uint32_t productSubId, TraceLevel reporting)
{
AZStd::string resolvedPath = ResolvePathReference(originatingSourcePath, referencedSourceFilePath);
return MakeAssetId(resolvedPath, productSubId);
return MakeAssetId(resolvedPath, productSubId, reporting);
}
} // namespace AssetUtils
} // namespace RPI
@@ -14,14 +14,14 @@ namespace AZ
{
namespace ColorUtils
{
enum ColorSpace : uint32_t
{
LinearSRGB,
SRGB
};
AzToolsFramework::ColorEditorConfiguration GetLinearRgbEditorConfig()
{
enum ColorSpace : uint32_t
{
LinearSRGB,
SRGB
};
AzToolsFramework::ColorEditorConfiguration configuration;
configuration.m_colorPickerDialogConfiguration = AzQtComponents::ColorPicker::Configuration::RGB;
@@ -59,6 +59,15 @@ namespace AZ
return configuration;
}
AzToolsFramework::ColorEditorConfiguration GetRgbEditorConfig()
{
AzToolsFramework::ColorEditorConfiguration configuration = GetLinearRgbEditorConfig();
configuration.m_propertyColorSpaceId = ColorSpace::SRGB;
return configuration;
}
} // namespace ColorPropertyEditorConfigurations
} // namespace RPI
} // namespace AZ
@@ -137,7 +137,10 @@ namespace AZ
}
else if (!m_luaSourceFile.empty())
{
auto loadOutcome = RPI::AssetUtils::LoadAsset<ScriptAsset>(materialTypeSourceFilePath, m_luaSourceFile);
// The sub ID for script assets must be explicit.
// LUA source files output a compiled as well as an uncompiled asset, sub Ids of 1 and 2.
auto loadOutcome =
RPI::AssetUtils::LoadAsset<ScriptAsset>(materialTypeSourceFilePath, m_luaSourceFile, ScriptAsset::CompiledAssetSubId);
if (!loadOutcome)
{
AZ_Error("LuaMaterialFunctorSourceData", false, "Could not load script file '%s'", m_luaSourceFile.c_str());
@@ -17,6 +17,7 @@
#include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
#include <Atom/RPI.Edit/Common/JsonReportingHelper.h>
#include <Atom/RPI.Edit/Common/JsonUtils.h>
#include <Atom/RPI.Reflect/Material/MaterialAssetCreator.h>
#include <Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h>
@@ -115,10 +116,11 @@ namespace AZ
{
m_properties = AZStd::move(newPropertyGroups);
AZ_Warning("MaterialSourceData", false,
AZ_Warning(
"MaterialSourceData", false,
"This material is based on version '%u' of '%s', but the material type is now at version '%u'. "
"Automatic updates are available. Consider updating the .material source file.",
m_materialTypeVersion, m_materialType.c_str(), materialTypeSourceData.m_version);
"Automatic updates are available. Consider updating the .material source file: '%s'.",
m_materialTypeVersion, materialTypeFullPath.c_str(), materialTypeSourceData.m_version, materialSourceFilePath.data());
}
m_materialTypeVersion = materialTypeSourceData.m_version;
@@ -126,7 +128,8 @@ namespace AZ
return changesWereApplied ? ApplyVersionUpdatesResult::UpdatesApplied : ApplyVersionUpdatesResult::NoUpdates;
}
Outcome<Data::Asset<MaterialAsset> > MaterialSourceData::CreateMaterialAsset(Data::AssetId assetId, AZStd::string_view materialSourceFilePath, bool elevateWarnings, bool includeMaterialPropertyNames) const
Outcome<Data::Asset<MaterialAsset>> MaterialSourceData::CreateMaterialAsset(
Data::AssetId assetId, AZStd::string_view materialSourceFilePath, bool elevateWarnings, bool includeMaterialPropertyNames) const
{
MaterialAssetCreator materialAssetCreator;
materialAssetCreator.SetElevateWarnings(elevateWarnings);
@@ -172,66 +175,7 @@ namespace AZ
materialAssetCreator.Begin(assetId, *parentMaterialAsset.GetValue().Get(), includeMaterialPropertyNames);
}
for (auto& group : m_properties)
{
for (auto& property : group.second)
{
MaterialPropertyId propertyId{ group.first, property.first };
if (!property.second.m_value.IsValid())
{
AZ_Warning("Material source data", false, "Source data for material property value is invalid.");
}
else
{
MaterialPropertyIndex propertyIndex = materialAssetCreator.m_materialPropertiesLayout->FindPropertyIndex(propertyId.GetFullName());
if (propertyIndex.IsValid())
{
const MaterialPropertyDescriptor* propertyDescriptor = materialAssetCreator.m_materialPropertiesLayout->GetPropertyDescriptor(propertyIndex);
switch (propertyDescriptor->GetDataType())
{
case MaterialPropertyDataType::Image:
{
Outcome<Data::Asset<ImageAsset>> imageAssetResult = MaterialUtils::GetImageAssetReference(materialSourceFilePath, property.second.m_value.GetValue<AZStd::string>());
if (imageAssetResult.IsSuccess())
{
auto& imageAsset = imageAssetResult.GetValue();
// Load referenced images when load material
imageAsset.SetAutoLoadBehavior(Data::AssetLoadBehavior::PreLoad);
materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset);
}
else
{
materialAssetCreator.ReportError("Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(), property.second.m_value.GetValue<AZStd::string>().data());
}
}
break;
case MaterialPropertyDataType::Enum:
{
AZ::Name enumName = AZ::Name(property.second.m_value.GetValue<AZStd::string>());
uint32_t enumValue = propertyDescriptor->GetEnumValue(enumName);
if (enumValue == MaterialPropertyDescriptor::InvalidEnumValue)
{
materialAssetCreator.ReportError("Enum value '%s' couldn't be found in the 'enumValues' list", enumName.GetCStr());
}
else
{
materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), enumValue);
}
}
break;
default:
materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), property.second.m_value);
break;
}
}
else
{
materialAssetCreator.ReportWarning("Can not find property id '%s' in MaterialPropertyLayout", propertyId.GetFullName().GetStringView().data());
}
}
}
}
ApplyPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath);
Data::Asset<MaterialAsset> material;
if (materialAssetCreator.End(material))
@@ -244,5 +188,181 @@ namespace AZ
}
}
Outcome<Data::Asset<MaterialAsset>> MaterialSourceData::CreateMaterialAssetFromSourceData(
Data::AssetId assetId,
AZStd::string_view materialSourceFilePath,
bool elevateWarnings,
bool includeMaterialPropertyNames,
AZStd::unordered_set<AZStd::string>* sourceDependencies) const
{
const auto materialTypeSourcePath = AssetUtils::ResolvePathReference(materialSourceFilePath, m_materialType);
const auto materialTypeAssetId = AssetUtils::MakeAssetId(materialTypeSourcePath, 0);
if (!materialTypeAssetId.IsSuccess())
{
AZ_Error("MaterialSourceData", false, "Failed to create material type asset ID: '%s'.", materialTypeSourcePath.c_str());
return Failure();
}
MaterialTypeSourceData materialTypeSourceData;
if (!AZ::RPI::JsonUtils::LoadObjectFromFile(materialTypeSourcePath, materialTypeSourceData))
{
AZ_Error("MaterialSourceData", false, "Failed to load MaterialTypeSourceData: '%s'.", materialTypeSourcePath.c_str());
return Failure();
}
materialTypeSourceData.ResolveUvEnums();
const auto materialTypeAsset =
materialTypeSourceData.CreateMaterialTypeAsset(materialTypeAssetId.GetValue(), materialTypeSourcePath, elevateWarnings);
if (!materialTypeAsset.IsSuccess())
{
AZ_Error("MaterialSourceData", false, "Failed to create material type asset from source data: '%s'.", materialTypeSourcePath.c_str());
return Failure();
}
// Track all of the material and material type assets loaded while trying to create a material asset from source data. This will
// be used for evaluating circular dependencies and returned for external monitoring or other use.
AZStd::unordered_set<AZStd::string> dependencies;
dependencies.insert(materialSourceFilePath);
dependencies.insert(materialTypeSourcePath);
// Load and build a stack of MaterialSourceData from all of the parent materials in the hierarchy. Properties from the source
// data will be applied in reverse to the asset creator.
AZStd::vector<MaterialSourceData> parentSourceDataStack;
AZStd::string parentSourceRelPath = m_parentMaterial;
AZStd::string parentSourceAbsPath = AssetUtils::ResolvePathReference(materialSourceFilePath, parentSourceRelPath);
while (!parentSourceRelPath.empty())
{
if (!dependencies.insert(parentSourceAbsPath).second)
{
AZ_Error("MaterialSourceData", false, "Detected circular dependency between materials: '%s' and '%s'.", materialSourceFilePath.data(), parentSourceAbsPath.c_str());
return Failure();
}
MaterialSourceData parentSourceData;
if (!AZ::RPI::JsonUtils::LoadObjectFromFile(parentSourceAbsPath, parentSourceData))
{
AZ_Error("MaterialSourceData", false, "Failed to load MaterialSourceData for parent material: '%s'.", parentSourceAbsPath.c_str());
return Failure();
}
// Make sure that all materials in the hierarchy share the same material type
const auto parentTypeAssetId = AssetUtils::MakeAssetId(parentSourceAbsPath, parentSourceData.m_materialType, 0);
if (!parentTypeAssetId)
{
AZ_Error("MaterialSourceData", false, "Parent material asset ID wasn't found: '%s'.", parentSourceAbsPath.c_str());
return Failure();
}
if (parentTypeAssetId.GetValue() != materialTypeAssetId.GetValue())
{
AZ_Error("MaterialSourceData", false, "This material and its parent material do not share the same material type.");
return Failure();
}
// Get the location of the next parent material and push the source data onto the stack
parentSourceRelPath = parentSourceData.m_parentMaterial;
parentSourceAbsPath = AssetUtils::ResolvePathReference(parentSourceAbsPath, parentSourceRelPath);
parentSourceDataStack.emplace_back(AZStd::move(parentSourceData));
}
// Create the material asset from all the previously loaded source data
MaterialAssetCreator materialAssetCreator;
materialAssetCreator.SetElevateWarnings(elevateWarnings);
materialAssetCreator.Begin(assetId, *materialTypeAsset.GetValue().Get(), includeMaterialPropertyNames);
while (!parentSourceDataStack.empty())
{
parentSourceDataStack.back().ApplyPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath);
parentSourceDataStack.pop_back();
}
ApplyPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath);
Data::Asset<MaterialAsset> material;
if (materialAssetCreator.End(material))
{
if (sourceDependencies)
{
sourceDependencies->insert(dependencies.begin(), dependencies.end());
}
return Success(material);
}
return Failure();
}
void MaterialSourceData::ApplyPropertiesToAssetCreator(
AZ::RPI::MaterialAssetCreator& materialAssetCreator, const AZStd::string_view& materialSourceFilePath) const
{
for (auto& group : m_properties)
{
for (auto& property : group.second)
{
MaterialPropertyId propertyId{ group.first, property.first };
if (!property.second.m_value.IsValid())
{
materialAssetCreator.ReportWarning("Source data for material property value is invalid.");
}
else
{
MaterialPropertyIndex propertyIndex =
materialAssetCreator.m_materialPropertiesLayout->FindPropertyIndex(propertyId.GetFullName());
if (propertyIndex.IsValid())
{
const MaterialPropertyDescriptor* propertyDescriptor =
materialAssetCreator.m_materialPropertiesLayout->GetPropertyDescriptor(propertyIndex);
switch (propertyDescriptor->GetDataType())
{
case MaterialPropertyDataType::Image:
{
Data::Asset<ImageAsset> imageAsset;
MaterialUtils::GetImageAssetResult result = MaterialUtils::GetImageAssetReference(
imageAsset, materialSourceFilePath, property.second.m_value.GetValue<AZStd::string>());
if (result == MaterialUtils::GetImageAssetResult::Missing)
{
materialAssetCreator.ReportWarning(
"Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(),
property.second.m_value.GetValue<AZStd::string>().data());
}
imageAsset.SetAutoLoadBehavior(Data::AssetLoadBehavior::PreLoad);
materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset);
}
break;
case MaterialPropertyDataType::Enum:
{
AZ::Name enumName = AZ::Name(property.second.m_value.GetValue<AZStd::string>());
uint32_t enumValue = propertyDescriptor->GetEnumValue(enumName);
if (enumValue == MaterialPropertyDescriptor::InvalidEnumValue)
{
materialAssetCreator.ReportError(
"Enum value '%s' couldn't be found in the 'enumValues' list", enumName.GetCStr());
}
else
{
materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), enumValue);
}
}
break;
default:
materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), property.second.m_value);
break;
}
}
else
{
materialAssetCreator.ReportWarning(
"Can not find property id '%s' in MaterialPropertyLayout", propertyId.GetFullName().GetStringView().data());
}
}
}
}
}
} // namespace RPI
} // namespace AZ
@@ -300,48 +300,6 @@ namespace AZ
}
}
bool MaterialTypeSourceData::ConvertPropertyValueToSourceDataFormat(const PropertyDefinition& propertyDefinition, MaterialPropertyValue& propertyValue) const
{
if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Enum && propertyValue.Is<uint32_t>())
{
const uint32_t index = propertyValue.GetValue<uint32_t>();
if (index >= propertyDefinition.m_enumValues.size())
{
AZ_Error("Material source data", false, "Invalid value for material enum property: '%s'.", propertyDefinition.m_name.c_str());
return false;
}
propertyValue = propertyDefinition.m_enumValues[index];
return true;
}
// Image asset references must be converted from asset IDs to a relative source file path
if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Image && propertyValue.Is<Data::Asset<ImageAsset>>())
{
const Data::Asset<ImageAsset>& imageAsset = propertyValue.GetValue<Data::Asset<ImageAsset>>();
Data::AssetInfo imageAssetInfo;
if (imageAsset.GetId().IsValid())
{
bool result = false;
AZStd::string rootFilePath;
const AZStd::string platformName = ""; // Empty for default
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(result, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetAssetInfoById,
imageAsset.GetId(), imageAsset.GetType(), platformName, imageAssetInfo, rootFilePath);
if (!result)
{
AZ_Error("Material source data", false, "Image asset could not be found for property: '%s'.", propertyDefinition.m_name.c_str());
return false;
}
}
propertyValue = imageAssetInfo.m_relativePath;
return true;
}
return true;
}
Outcome<Data::Asset<MaterialTypeAsset>> MaterialTypeSourceData::CreateMaterialTypeAsset(Data::AssetId assetId, AZStd::string_view materialTypeSourceFilePath, bool elevateWarnings) const
{
MaterialTypeAssetCreator materialTypeAssetCreator;
@@ -393,11 +351,12 @@ namespace AZ
for (const ShaderVariantReferenceData& shaderRef : m_shaderCollection)
{
const auto& shaderFile = shaderRef.m_shaderFilePath;
const auto& shaderAsset = AssetUtils::LoadAsset<ShaderAsset>(materialTypeSourceFilePath, shaderFile, 0);
auto shaderAssetResult = AssetUtils::LoadAsset<ShaderAsset>(materialTypeSourceFilePath, shaderFile, 0);
if (shaderAsset)
if (shaderAssetResult)
{
auto optionsLayout = shaderAsset.GetValue()->GetShaderOptionGroupLayout();
auto shaderAsset = shaderAssetResult.GetValue();
auto optionsLayout = shaderAsset->GetShaderOptionGroupLayout();
ShaderOptionGroup options{ optionsLayout };
for (auto& iter : shaderRef.m_shaderOptionValues)
{
@@ -408,12 +367,11 @@ namespace AZ
}
materialTypeAssetCreator.AddShader(
shaderAsset.GetValue(), options.GetShaderVariantId(),
shaderRef.m_shaderTag.IsEmpty() ? Uuid::CreateRandom().ToString<AZ::Name>() : shaderRef.m_shaderTag
);
shaderAsset, options.GetShaderVariantId(),
shaderRef.m_shaderTag.IsEmpty() ? Uuid::CreateRandom().ToString<AZ::Name>() : shaderRef.m_shaderTag);
// Gather UV names
const ShaderInputContract& shaderInputContract = shaderAsset.GetValue()->GetInputContract();
const ShaderInputContract& shaderInputContract = shaderAsset->GetInputContract();
for (const ShaderInputContract::StreamChannelInfo& channel : shaderInputContract.m_streamChannels)
{
const RHI::ShaderSemantic& semantic = channel.m_semantic;
@@ -493,15 +451,20 @@ namespace AZ
{
case MaterialPropertyDataType::Image:
{
Outcome<Data::Asset<ImageAsset>> imageAssetResult = MaterialUtils::GetImageAssetReference(materialTypeSourceFilePath, property.m_value.GetValue<AZStd::string>());
Data::Asset<ImageAsset> imageAsset;
if (imageAssetResult.IsSuccess())
MaterialUtils::GetImageAssetResult result = MaterialUtils::GetImageAssetReference(
imageAsset, materialTypeSourceFilePath, property.m_value.GetValue<AZStd::string>());
if (result == MaterialUtils::GetImageAssetResult::Missing)
{
materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAssetResult.GetValue());
materialTypeAssetCreator.ReportError(
"Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(),
property.m_value.GetValue<AZStd::string>().data());
}
else
{
materialTypeAssetCreator.ReportError("Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(), property.m_value.GetValue<AZStd::string>().data());
materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset);
}
}
break;
@@ -28,25 +28,36 @@ namespace AZ
{
namespace MaterialUtils
{
Outcome<Data::Asset<ImageAsset>> GetImageAssetReference(AZStd::string_view materialSourceFilePath, const AZStd::string imageFilePath)
GetImageAssetResult GetImageAssetReference(Data::Asset<ImageAsset>& imageAsset, AZStd::string_view materialSourceFilePath, const AZStd::string imageFilePath)
{
imageAsset = {};
if (imageFilePath.empty())
{
// The image value was present but specified an empty string, meaning the texture asset should be explicitly cleared.
return AZ::Success(Data::Asset<ImageAsset>());
return GetImageAssetResult::Empty;
}
else
{
Outcome<Data::AssetId> imageAssetId = AssetUtils::MakeAssetId(materialSourceFilePath, imageFilePath, StreamingImageAsset::GetImageAssetSubId());
// We use TraceLevel::None because fallback textures are available and we'll return GetImageAssetResult::Missing below in that case.
// Callers of GetImageAssetReference will be responsible for logging warnings or errors as needed.
Outcome<Data::AssetId> imageAssetId = AssetUtils::MakeAssetId(materialSourceFilePath, imageFilePath, StreamingImageAsset::GetImageAssetSubId(), AssetUtils::TraceLevel::None);
if (!imageAssetId.IsSuccess())
{
return AZ::Failure();
}
else
{
Data::Asset<ImageAsset> unloadedImageAssetReference(imageAssetId.GetValue(), azrtti_typeid<StreamingImageAsset>(), imageFilePath);
return AZ::Success(unloadedImageAssetReference);
// When the AssetId cannot be found, we don't want to outright fail, because the runtime has mechanisms for displaying fallback textures which gives the
// user a better recovery workflow. On the other hand we can't just provide an empty/invalid Asset<ImageAsset> because that would be interpreted as simply
// no value was present and result in using no texture, and this would amount to a silent failure.
// So we use a randomly generated (well except for the "BADA55E7" bit ;) UUID which the runtime and tools will interpret as a missing asset and represent
// it as such.
static const Uuid InvalidAssetPlaceholderId = "{BADA55E7-1A1D-4940-B655-9D08679BD62F}";
imageAsset = Data::Asset<ImageAsset>{InvalidAssetPlaceholderId, azrtti_typeid<StreamingImageAsset>(), imageFilePath};
return GetImageAssetResult::Missing;
}
imageAsset = Data::Asset<ImageAsset>{imageAssetId.GetValue(), azrtti_typeid<StreamingImageAsset>(), imageFilePath};
return GetImageAssetResult::Found;
}
}
@@ -92,7 +92,7 @@ namespace AZ
/////////////////////////////////////////////////////////////////////
// Methods for all shader variant types
void ShaderVariantAssetCreator::SetBuildTimestamp(AZStd::sys_time_t buildTimestamp)
void ShaderVariantAssetCreator::SetBuildTimestamp(AZ::u64 buildTimestamp)
{
if (ValidateIsReady())
{
@@ -17,7 +17,8 @@
#include <Atom/RPI.Public/Buffer/BufferSystemInterface.h>
#include <AtomCore/Instance/InstanceDatabase.h>
#include <AzCore/Component/TickBus.h>
#include <AzCore/Debug/EventTrace.h>
AZ_DECLARE_BUDGET(RPI);
namespace AZ
{
@@ -90,7 +91,7 @@ namespace AZ
RHI::ResultCode Buffer::Init(BufferAsset& bufferAsset)
{
AZ_TRACE_METHOD();
AZ_PROFILE_FUNCTION(RPI);
RHI::ResultCode resultCode = RHI::ResultCode::Fail;
@@ -140,7 +141,7 @@ namespace AZ
if (bufferAsset.GetBuffer().size() > 0 && !initWithData)
{
AZ_TRACE_METHOD_NAME("Stream Upload");
AZ_PROFILE_SCOPE(RPI, "Stream Upload");
m_streamFence = RHI::Factory::Get().CreateFence();
if (m_streamFence)
{
@@ -16,7 +16,6 @@
#include <Atom/RPI.Reflect/Buffer/BufferAssetCreator.h>
#include <Atom/RPI.Reflect/Buffer/BufferAssetView.h>
#include <AzCore/Debug/EventTrace.h>
#include <AtomCore/Instance/InstanceDatabase.h>
#include <AzCore/Interface/Interface.h>
+356 -222
View File
@@ -19,10 +19,10 @@
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/std/parallel/lock.h>
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/Debug/EventTrace.h>
#include <AzCore/Debug/Timer.h>
#include <AzCore/Jobs/JobFunction.h>
#include <AzCore/Jobs/Job.h>
#include <AzCore/Task/TaskGraph.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <Atom_RPI_Traits_Platform.h>
#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
@@ -34,7 +34,7 @@
//Enables more detailed profiling descriptions within the culling system, but adds some performance overhead.
//Enable this to more easily see which jobs are associated with which view.
//#define AZ_CULL_PROFILE_VERBOSE
//#define AZ_CULL_PROFILE_VERBOSE
namespace AZ
{
@@ -43,6 +43,7 @@ namespace AZ
AZ_CVAR(bool, r_CullInParallel, true, nullptr, ConsoleFunctorFlags::Null, "");
AZ_CVAR(uint32_t, r_CullWorkPerBatch, 500, nullptr, ConsoleFunctorFlags::Null, "");
#ifdef AZ_CULL_DEBUG_ENABLED
void DebugDrawWorldCoordinateAxes(AuxGeomDraw* auxGeom)
{
auxGeom->DrawCylinder(Vector3(.5, .0, .0), Vector3(1, 0, 0), 0.02f, 1.0f, Colors::Red, AuxGeomDraw::DrawStyle::Solid, AuxGeomDraw::DepthTest::Off);
@@ -198,6 +199,7 @@ namespace AZ
AZ_Assert(false, "invalid frustum, cannot draw");
}
}
#endif //AZ_CULL_DEBUG_ENABLED
CullingDebugContext::~CullingDebugContext()
{
@@ -265,89 +267,73 @@ namespace AZ
return m_visScene->GetEntryCount();
}
class AddObjectsToViewJob final
: public Job
struct WorklistData
{
public:
AZ_CLASS_ALLOCATOR(AddObjectsToViewJob, ThreadPoolAllocator, 0);
struct JobData
{
CullingDebugContext* m_debugCtx = nullptr;
const Scene* m_scene = nullptr;
View* m_view = nullptr;
Frustum m_frustum;
CullingDebugContext* m_debugCtx = nullptr;
const Scene* m_scene = nullptr;
View* m_view = nullptr;
Frustum m_frustum;
#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
MaskedOcclusionCulling* m_maskedOcclusionCulling = nullptr;
MaskedOcclusionCulling* m_maskedOcclusionCulling = nullptr;
#endif
};
};
private:
const AZStd::shared_ptr<JobData> m_jobData;
CullingScene::WorkListType m_worklist;
static AZStd::shared_ptr<WorklistData> MakeWorklistData(
CullingDebugContext& debugCtx,
const Scene& scene,
View& view,
Frustum& frustum,
[[maybe_unused]] void* maskedOcclusionCulling)
{
AZStd::shared_ptr<WorklistData> worklistData = AZStd::make_shared<WorklistData>();
worklistData->m_debugCtx = &debugCtx;
worklistData->m_scene = &scene;
worklistData->m_view = &view;
worklistData->m_frustum = frustum;
#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
worklistData->m_maskedOcclusionCulling = static_cast<MaskedOcclusionCulling*>(maskedOcclusionCulling);
#endif
return worklistData;
}
constexpr size_t WorkListCapacity = 5;
using WorkListType = AZStd::fixed_vector<AzFramework::IVisibilityScene::NodeData, WorkListCapacity>;
public:
AddObjectsToViewJob(const AZStd::shared_ptr<AddObjectsToViewJob::JobData>& jobData, CullingScene::WorkListType& worklist)
: Job(true, nullptr) //auto-deletes, no JobContext
, m_jobData(jobData)
, m_worklist(worklist)
#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
static MaskedOcclusionCulling::CullingResult TestOcclusionCulling(
const AZStd::shared_ptr<WorklistData>& worklistData,
AzFramework::VisibilityEntry* visibleEntry);
#endif
static void ProcessWorklist(const AZStd::shared_ptr<WorklistData>& worklistData, const WorkListType& worklist)
{
AZ_PROFILE_SCOPE(RPI, "AddObjectsToViewJob: Process");
const View::UsageFlags viewFlags = worklistData->m_view->GetUsageFlags();
const RHI::DrawListMask drawListMask = worklistData->m_view->GetDrawListMask();
uint32_t numDrawPackets = 0;
uint32_t numVisibleCullables = 0;
AZ_Assert(worklist.size() > 0, "Received empty worklist in ProcessWorklist");
for (const AzFramework::IVisibilityScene::NodeData& nodeData : worklist)
{
}
//work function
void Process() override
{
AZ_PROFILE_SCOPE(RPI, "AddObjectsToViewJob: Process");
const View::UsageFlags viewFlags = m_jobData->m_view->GetUsageFlags();
const RHI::DrawListMask drawListMask = m_jobData->m_view->GetDrawListMask();
uint32_t numDrawPackets = 0;
uint32_t numVisibleCullables = 0;
for (const AzFramework::IVisibilityScene::NodeData& nodeData : m_worklist)
{
//If a node is entirely contained within the frustum, then we can skip the fine grained culling.
bool nodeIsContainedInFrustum = ShapeIntersection::Contains(m_jobData->m_frustum, nodeData.m_bounds);
//If a node is entirely contained within the frustum, then we can skip the fine grained culling.
bool nodeIsContainedInFrustum =
!worklistData->m_debugCtx->m_enableFrustumCulling ||
ShapeIntersection::Contains(worklistData->m_frustum, nodeData.m_bounds);
#ifdef AZ_CULL_PROFILE_VERBOSE
AZ_PROFILE_SCOPE(RPI, "process node (view: %s, skip fine cull: %d",
m_view->GetName().GetCStr(), nodeIsContainedInFrustum ? 1 : 0);
AZ_PROFILE_SCOPE(RPI, "process node (view: %s, skip fine cull: %ds",
worklistData->m_view->GetName().GetCStr(), nodeIsContainedInFrustum ? "true" : "false");
#endif
if (nodeIsContainedInFrustum || !m_jobData->m_debugCtx->m_enableFrustumCulling)
if (nodeIsContainedInFrustum)
{
//Add all objects within this node to the view, without any extra culling
for (AzFramework::VisibilityEntry* visibleEntry : nodeData.m_entries)
{
//Add all objects within this node to the view, without any extra culling
for (AzFramework::VisibilityEntry* visibleEntry : nodeData.m_entries)
{
{
if (visibleEntry->m_typeFlags & AzFramework::VisibilityEntry::TYPE_RPI_Cullable)
{
Cullable* c = static_cast<Cullable*>(visibleEntry->m_userData);
if ((c->m_cullData.m_drawListMask & drawListMask).none() ||
c->m_cullData.m_hideFlags & viewFlags ||
c->m_cullData.m_scene != m_jobData->m_scene || //[GFX_TODO][ATOM-13796] once the IVisibilitySystem supports multiple octree scenes, remove this
c->m_isHidden)
{
continue;
}
#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
if (TestOcclusionCulling(visibleEntry) == MaskedOcclusionCulling::CullingResult::VISIBLE)
#endif
{
numDrawPackets += AddLodDataToView(c->m_cullData.m_boundingSphere.GetCenter(), c->m_lodData, *m_jobData->m_view);
++numVisibleCullables;
c->m_isVisible = true;
}
}
}
}
}
else
{
//Do fine-grained culling before adding objects to the view
for (AzFramework::VisibilityEntry* visibleEntry : nodeData.m_entries)
{
if (visibleEntry->m_typeFlags & AzFramework::VisibilityEntry::TYPE_RPI_Cullable)
{
@@ -355,160 +341,200 @@ namespace AZ
if ((c->m_cullData.m_drawListMask & drawListMask).none() ||
c->m_cullData.m_hideFlags & viewFlags ||
c->m_cullData.m_scene != m_jobData->m_scene || //[GFX_TODO][ATOM-13796] once the IVisibilitySystem supports multiple octree scenes, remove this
c->m_cullData.m_scene != worklistData->m_scene || //[GFX_TODO][ATOM-13796] once the IVisibilitySystem supports multiple octree scenes, remove this
c->m_isHidden)
{
continue;
}
IntersectResult res = ShapeIntersection::Classify(m_jobData->m_frustum, c->m_cullData.m_boundingSphere);
if (res == IntersectResult::Exterior)
{
continue;
}
else if (res == IntersectResult::Interior || ShapeIntersection::Overlaps(m_jobData->m_frustum, c->m_cullData.m_boundingObb))
{
#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
if (TestOcclusionCulling(visibleEntry) == MaskedOcclusionCulling::CullingResult::VISIBLE)
if (TestOcclusionCulling(worklistData, visibleEntry) == MaskedOcclusionCulling::CullingResult::VISIBLE)
#endif
{
numDrawPackets += AddLodDataToView(c->m_cullData.m_boundingSphere.GetCenter(), c->m_lodData, *m_jobData->m_view);
++numVisibleCullables;
c->m_isVisible = true;
}
}
}
}
}
if (m_jobData->m_debugCtx->m_debugDraw && (m_jobData->m_view->GetName() == m_jobData->m_debugCtx->m_currentViewSelectionName))
{
AZ_PROFILE_SCOPE(RPI, "debug draw culling");
AuxGeomDrawPtr auxGeomPtr = AuxGeomFeatureProcessorInterface::GetDrawQueueForScene(m_jobData->m_scene);
if (auxGeomPtr)
{
//Draw the node bounds
// "Fully visible" nodes are nodes that are fully inside the frustum. "Partially visible" nodes intersect the edges of the frustum.
// Since the nodes of an octree have lots of overlapping boxes with coplanar edges, it's easier to view these separately, so
// we have a few debug booleans to toggle which ones to draw.
if (nodeIsContainedInFrustum && m_jobData->m_debugCtx->m_drawFullyVisibleNodes)
{
auxGeomPtr->DrawAabb(nodeData.m_bounds, Colors::Lime, RPI::AuxGeomDraw::DrawStyle::Line, RPI::AuxGeomDraw::DepthTest::Off);
}
else if (!nodeIsContainedInFrustum && m_jobData->m_debugCtx->m_drawPartiallyVisibleNodes)
{
auxGeomPtr->DrawAabb(nodeData.m_bounds, Colors::Yellow, RPI::AuxGeomDraw::DrawStyle::Line, RPI::AuxGeomDraw::DepthTest::Off);
}
//Draw bounds on individual objects
if (m_jobData->m_debugCtx->m_drawBoundingBoxes || m_jobData->m_debugCtx->m_drawBoundingSpheres || m_jobData->m_debugCtx->m_drawLodRadii)
{
for (AzFramework::VisibilityEntry* visibleEntry : nodeData.m_entries)
{
if (visibleEntry->m_typeFlags & AzFramework::VisibilityEntry::TYPE_RPI_Cullable)
numDrawPackets += AddLodDataToView(c->m_cullData.m_boundingSphere.GetCenter(), c->m_lodData, *worklistData->m_view);
++numVisibleCullables;
c->m_isVisible = true;
}
}
}
}
}
else
{
//Do fine-grained culling before adding objects to the view
for (AzFramework::VisibilityEntry* visibleEntry : nodeData.m_entries)
{
if (visibleEntry->m_typeFlags & AzFramework::VisibilityEntry::TYPE_RPI_Cullable)
{
Cullable* c = static_cast<Cullable*>(visibleEntry->m_userData);
if ((c->m_cullData.m_drawListMask & drawListMask).none() ||
c->m_cullData.m_hideFlags & viewFlags ||
c->m_cullData.m_scene != worklistData->m_scene || //[GFX_TODO][ATOM-13796] once the IVisibilitySystem supports multiple octree scenes, remove this
c->m_isHidden)
{
continue;
}
IntersectResult res = ShapeIntersection::Classify(worklistData->m_frustum, c->m_cullData.m_boundingSphere);
if (res == IntersectResult::Exterior)
{
continue;
}
else if (res == IntersectResult::Interior || ShapeIntersection::Overlaps(worklistData->m_frustum, c->m_cullData.m_boundingObb))
{
#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
if (TestOcclusionCulling(worklistData, visibleEntry) == MaskedOcclusionCulling::CullingResult::VISIBLE)
#endif
{
numDrawPackets += AddLodDataToView(c->m_cullData.m_boundingSphere.GetCenter(), c->m_lodData, *worklistData->m_view);
++numVisibleCullables;
c->m_isVisible = true;
}
}
}
}
}
#ifdef AZ_CULL_DEBUG_ENABLED
if (worklistData->m_debugCtx->m_debugDraw && (worklistData->m_view->GetName() == worklistData->m_debugCtx->m_currentViewSelectionName))
{
AZ_PROFILE_SCOPE(RPI, "debug draw culling");
AuxGeomDrawPtr auxGeomPtr = AuxGeomFeatureProcessorInterface::GetDrawQueueForScene(worklistData->m_scene);
if (auxGeomPtr)
{
//Draw the node bounds
// "Fully visible" nodes are nodes that are fully inside the frustum. "Partially visible" nodes intersect the edges of the frustum.
// Since the nodes of an octree have lots of overlapping boxes with coplanar edges, it's easier to view these separately, so
// we have a few debug booleans to toggle which ones to draw.
if (nodeIsContainedInFrustum && worklistData->m_debugCtx->m_drawFullyVisibleNodes)
{
auxGeomPtr->DrawAabb(nodeData.m_bounds, Colors::Lime, RPI::AuxGeomDraw::DrawStyle::Line, RPI::AuxGeomDraw::DepthTest::Off);
}
else if (!nodeIsContainedInFrustum && worklistData->m_debugCtx->m_drawPartiallyVisibleNodes)
{
auxGeomPtr->DrawAabb(nodeData.m_bounds, Colors::Yellow, RPI::AuxGeomDraw::DrawStyle::Line, RPI::AuxGeomDraw::DepthTest::Off);
}
//Draw bounds on individual objects
if (worklistData->m_debugCtx->m_drawBoundingBoxes || worklistData->m_debugCtx->m_drawBoundingSpheres || worklistData->m_debugCtx->m_drawLodRadii)
{
for (AzFramework::VisibilityEntry* visibleEntry : nodeData.m_entries)
{
if (visibleEntry->m_typeFlags & AzFramework::VisibilityEntry::TYPE_RPI_Cullable)
{
Cullable* c = static_cast<Cullable*>(visibleEntry->m_userData);
if (worklistData->m_debugCtx->m_drawBoundingBoxes)
{
Cullable* c = static_cast<Cullable*>(visibleEntry->m_userData);
if (m_jobData->m_debugCtx->m_drawBoundingBoxes)
{
auxGeomPtr->DrawObb(c->m_cullData.m_boundingObb, Matrix3x4::Identity(),
nodeIsContainedInFrustum ? Colors::Lime : Colors::Yellow, AuxGeomDraw::DrawStyle::Line);
}
auxGeomPtr->DrawObb(c->m_cullData.m_boundingObb, Matrix3x4::Identity(),
nodeIsContainedInFrustum ? Colors::Lime : Colors::Yellow, AuxGeomDraw::DrawStyle::Line);
}
if (m_jobData->m_debugCtx->m_drawBoundingSpheres)
{
auxGeomPtr->DrawSphere(c->m_cullData.m_boundingSphere.GetCenter(), c->m_cullData.m_boundingSphere.GetRadius(),
Color(0.5f, 0.5f, 0.5f, 0.3f), AuxGeomDraw::DrawStyle::Shaded);
}
if (worklistData->m_debugCtx->m_drawBoundingSpheres)
{
auxGeomPtr->DrawSphere(c->m_cullData.m_boundingSphere.GetCenter(), c->m_cullData.m_boundingSphere.GetRadius(),
Color(0.5f, 0.5f, 0.5f, 0.3f), AuxGeomDraw::DrawStyle::Shaded);
}
if (m_jobData->m_debugCtx->m_drawLodRadii)
{
auxGeomPtr->DrawSphere(c->m_cullData.m_boundingSphere.GetCenter(),
c->m_lodData.m_lodSelectionRadius,
Color(1.0f, 0.5f, 0.0f, 0.3f), RPI::AuxGeomDraw::DrawStyle::Shaded);
}
if (worklistData->m_debugCtx->m_drawLodRadii)
{
auxGeomPtr->DrawSphere(c->m_cullData.m_boundingSphere.GetCenter(),
c->m_lodData.m_lodSelectionRadius,
Color(1.0f, 0.5f, 0.0f, 0.3f), RPI::AuxGeomDraw::DrawStyle::Shaded);
}
}
}
}
}
}
if (m_jobData->m_debugCtx->m_enableStats)
{
CullingDebugContext::CullStats& cullStats = m_jobData->m_debugCtx->GetCullStatsForView(m_jobData->m_view);
//no need for mutex here since these are all atomics
cullStats.m_numVisibleDrawPackets += numDrawPackets;
cullStats.m_numVisibleCullables += numVisibleCullables;
++cullStats.m_numJobs;
}
#endif
}
#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
MaskedOcclusionCulling::CullingResult TestOcclusionCulling(AzFramework::VisibilityEntry* visibleEntry)
#ifdef AZ_CULL_DEBUG_ENABLED
if (worklistData->m_debugCtx->m_enableStats)
{
if (!m_jobData->m_maskedOcclusionCulling)
{
return MaskedOcclusionCulling::CullingResult::VISIBLE;
}
CullingDebugContext::CullStats& cullStats = worklistData->m_debugCtx->GetCullStatsForView(worklistData->m_view);
if (visibleEntry->m_boundingVolume.Contains(m_jobData->m_view->GetCameraTransform().GetTranslation()))
{
// camera is inside bounding volume
return MaskedOcclusionCulling::CullingResult::VISIBLE;
}
//no need for mutex here since these are all atomics
cullStats.m_numVisibleDrawPackets += numDrawPackets;
cullStats.m_numVisibleCullables += numVisibleCullables;
++cullStats.m_numJobs;
}
#endif //AZ_CULL_DEBUG_ENABLED
}
const Vector3& minBound = visibleEntry->m_boundingVolume.GetMin();
const Vector3& maxBound = visibleEntry->m_boundingVolume.GetMax();
#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
static MaskedOcclusionCulling::CullingResult TestOcclusionCulling(
const AZStd::shared_ptr<WorklistData>& worklistData,
AzFramework::VisibilityEntry* visibleEntry)
{
if (!worklistData->m_maskedOcclusionCulling)
{
return MaskedOcclusionCulling::CullingResult::VISIBLE;
}
// compute bounding volume corners
Vector4 corners[8];
corners[0] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(minBound.GetX(), minBound.GetY(), minBound.GetZ(), 1.0f);
corners[1] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(minBound.GetX(), minBound.GetY(), maxBound.GetZ(), 1.0f);
corners[2] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(maxBound.GetX(), minBound.GetY(), maxBound.GetZ(), 1.0f);
corners[3] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(maxBound.GetX(), minBound.GetY(), minBound.GetZ(), 1.0f);
corners[4] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(minBound.GetX(), maxBound.GetY(), minBound.GetZ(), 1.0f);
corners[5] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(minBound.GetX(), maxBound.GetY(), maxBound.GetZ(), 1.0f);
corners[6] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(maxBound.GetX(), maxBound.GetY(), maxBound.GetZ(), 1.0f);
corners[7] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(maxBound.GetX(), maxBound.GetY(), minBound.GetZ(), 1.0f);
#ifdef AZ_CULL_PROFILE_VERBOSE
AZ_PROFILE_SCOPE(RPI, "TestOcclusionCulling");
#endif
// find min clip-space depth and NDC min/max
float minDepth = FLT_MAX;
float ndcMinX = FLT_MAX;
float ndcMinY = FLT_MAX;
float ndcMaxX = -FLT_MAX;
float ndcMaxY = -FLT_MAX;
for (uint32_t index = 0; index < 8; ++index)
{
minDepth = AZStd::min(minDepth, corners[index].GetW());
if (visibleEntry->m_boundingVolume.Contains(worklistData->m_view->GetCameraTransform().GetTranslation()))
{
// camera is inside bounding volume
return MaskedOcclusionCulling::CullingResult::VISIBLE;
}
// convert to NDC
corners[index] /= corners[index].GetW();
const Vector3& minBound = visibleEntry->m_boundingVolume.GetMin();
const Vector3& maxBound = visibleEntry->m_boundingVolume.GetMax();
ndcMinX = AZStd::min(ndcMinX, corners[index].GetX());
ndcMinY = AZStd::min(ndcMinY, corners[index].GetY());
ndcMaxX = AZStd::max(ndcMaxX, corners[index].GetX());
ndcMaxY = AZStd::max(ndcMaxY, corners[index].GetY());
}
// compute bounding volume corners
Vector4 corners[8];
corners[0] = worklistData->m_view->GetWorldToClipMatrix() * Vector4(minBound.GetX(), minBound.GetY(), minBound.GetZ(), 1.0f);
corners[1] = worklistData->m_view->GetWorldToClipMatrix() * Vector4(minBound.GetX(), minBound.GetY(), maxBound.GetZ(), 1.0f);
corners[2] = worklistData->m_view->GetWorldToClipMatrix() * Vector4(maxBound.GetX(), minBound.GetY(), maxBound.GetZ(), 1.0f);
corners[3] = worklistData->m_view->GetWorldToClipMatrix() * Vector4(maxBound.GetX(), minBound.GetY(), minBound.GetZ(), 1.0f);
corners[4] = worklistData->m_view->GetWorldToClipMatrix() * Vector4(minBound.GetX(), maxBound.GetY(), minBound.GetZ(), 1.0f);
corners[5] = worklistData->m_view->GetWorldToClipMatrix() * Vector4(minBound.GetX(), maxBound.GetY(), maxBound.GetZ(), 1.0f);
corners[6] = worklistData->m_view->GetWorldToClipMatrix() * Vector4(maxBound.GetX(), maxBound.GetY(), maxBound.GetZ(), 1.0f);
corners[7] = worklistData->m_view->GetWorldToClipMatrix() * Vector4(maxBound.GetX(), maxBound.GetY(), minBound.GetZ(), 1.0f);
// find min clip-space depth and NDC min/max
float minDepth = FLT_MAX;
float ndcMinX = FLT_MAX;
float ndcMinY = FLT_MAX;
float ndcMaxX = -FLT_MAX;
float ndcMaxY = -FLT_MAX;
for (uint32_t index = 0; index < 8; ++index)
{
minDepth = AZStd::min(minDepth, corners[index].GetW());
if (minDepth < 0.00000001f)
{
return MaskedOcclusionCulling::VISIBLE;
return MaskedOcclusionCulling::CullingResult::VISIBLE;
}
// test against the occlusion buffer, which contains only the manually placed occlusion planes
return m_jobData->m_maskedOcclusionCulling->TestRect(ndcMinX, ndcMinY, ndcMaxX, ndcMaxY, minDepth);
// convert to NDC
corners[index] /= corners[index].GetW();
ndcMinX = AZStd::min(ndcMinX, corners[index].GetX());
ndcMinY = AZStd::min(ndcMinY, corners[index].GetY());
ndcMaxX = AZStd::max(ndcMaxX, corners[index].GetX());
ndcMaxY = AZStd::max(ndcMaxY, corners[index].GetY());
}
// test against the occlusion buffer, which contains only the manually placed occlusion planes
return worklistData->m_maskedOcclusionCulling->TestRect(ndcMinX, ndcMinY, ndcMaxX, ndcMaxY, minDepth);
}
#endif
};
void CullingScene::ProcessCullables(const Scene& scene, View& view, AZ::Job& parentJob)
void CullingScene::ProcessCullablesCommon(
const Scene& scene [[maybe_unused]],
View& view,
AZ::Frustum& frustum [[maybe_unused]],
void*& maskedOcclusionCulling [[maybe_unused]])
{
AZ_PROFILE_SCOPE(RPI, "CullingScene::ProcessCullables() - %s", view.GetName().GetCStr());
AZ_PROFILE_SCOPE(RPI, "CullingScene::ProcessCullablesCommon() - %s", view.GetName().GetCStr());
const Matrix4x4& worldToClip = view.GetWorldToClipMatrix();
Frustum frustum = Frustum::CreateFromMatrixColumnMajor(worldToClip);
#ifdef AZ_CULL_DEBUG_ENABLED
if (m_debugCtx.m_freezeFrustums)
{
AZStd::lock_guard<AZStd::mutex> lock(m_debugCtx.m_frozenFrustumsMutex);
@@ -533,10 +559,10 @@ namespace AZ
CullingDebugContext::CullStats& cullStats = m_debugCtx.GetCullStatsForView(&view);
cullStats.m_cameraViewToWorld = view.GetViewToWorldMatrix();
}
#endif //AZ_CULL_DEBUG_ENABLED
#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
// setup occlusion culling, if necessary
MaskedOcclusionCulling* maskedOcclusionCulling = m_occlusionPlanes.empty() ? nullptr : view.GetMaskedOcclusionCulling();
maskedOcclusionCulling = m_occlusionPlanes.empty() ? nullptr : view.GetMaskedOcclusionCulling();
if (maskedOcclusionCulling)
{
// frustum cull occlusion planes
@@ -578,23 +604,27 @@ namespace AZ
static uint32_t indices[6] = { 0, 1, 2, 2, 3, 0 };
// render into the occlusion buffer, specifying BACKFACE_NONE so it functions as a double-sided occluder
maskedOcclusionCulling->RenderTriangles((float*)verts, indices, 2, nullptr, MaskedOcclusionCulling::BACKFACE_NONE);
static_cast<MaskedOcclusionCulling*>(maskedOcclusionCulling)->RenderTriangles(verts, indices, 2, nullptr, MaskedOcclusionCulling::BACKFACE_NONE);
}
}
#endif
}
void CullingScene::ProcessCullablesJobs(const Scene& scene, View& view, AZ::Job& parentJob)
{
AZ_PROFILE_SCOPE(RPI, "CullingScene::ProcessCullablesJobs() - %s", view.GetName().GetCStr());
const Matrix4x4& worldToClip = view.GetWorldToClipMatrix();
AZ::Frustum frustum = Frustum::CreateFromMatrixColumnMajor(worldToClip);
void* maskedOcclusionCulling = nullptr;
ProcessCullablesCommon(scene, view, frustum, maskedOcclusionCulling);
WorkListType worklist;
AZStd::shared_ptr<AddObjectsToViewJob::JobData> jobData = AZStd::make_shared<AddObjectsToViewJob::JobData>();
jobData->m_debugCtx = &m_debugCtx;
jobData->m_scene = &scene;
jobData->m_view = &view;
jobData->m_frustum = frustum;
#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
jobData->m_maskedOcclusionCulling = maskedOcclusionCulling;
#endif
AZStd::shared_ptr<WorklistData> worklistData = MakeWorklistData(m_debugCtx, scene, view, frustum, maskedOcclusionCulling);
auto nodeVisitorLambda = [jobData, &parentJob, &worklist](const AzFramework::IVisibilityScene::NodeData& nodeData) -> void
auto nodeVisitorLambda = [worklistData, &parentJob, &worklist](const AzFramework::IVisibilityScene::NodeData& nodeData) -> void
{
AZ_PROFILE_SCOPE(RPI, "nodeVisitorLambda()");
AZ_Assert(nodeData.m_entries.size() > 0, "should not get called with 0 entries");
@@ -606,8 +636,13 @@ namespace AZ
if (worklist.size() == worklist.capacity())
{
// capture worklistData & worklist by value
auto processWorklist = [worklistData, worklist]()
{
ProcessWorklist(worklistData, worklist);
};
//Kick off a job to process the (full) worklist
AddObjectsToViewJob* job = aznew AddObjectsToViewJob(jobData, worklist); //pool allocated (cheap), auto-deletes when job finishes
AZ::Job* job = AZ::CreateJobFunction(processWorklist, true);
worklist.clear();
parentJob.SetContinuation(job);
job->Start();
@@ -616,7 +651,7 @@ namespace AZ
if (m_debugCtx.m_enableFrustumCulling)
{
m_visScene->Enumerate(frustum, nodeVisitorLambda);
m_visScene->Enumerate(frustum, nodeVisitorLambda);
}
else
{
@@ -625,21 +660,76 @@ namespace AZ
if (worklist.size() > 0)
{
AZStd::shared_ptr<AddObjectsToViewJob::JobData> remainingJobData = AZStd::make_shared<AddObjectsToViewJob::JobData>();
remainingJobData->m_debugCtx = &m_debugCtx;
remainingJobData->m_scene = &scene;
remainingJobData->m_view = &view;
remainingJobData->m_frustum = frustum;
#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
remainingJobData->m_maskedOcclusionCulling = maskedOcclusionCulling;
#endif
//Kick off a job to process any remaining workitems
AddObjectsToViewJob* job = aznew AddObjectsToViewJob(remainingJobData, worklist); //pool allocated (cheap), auto-deletes when job finishes
// capture worklistData & worklist by value
auto processWorklist = [worklistData, worklist]()
{
ProcessWorklist(worklistData, worklist);
};
//Kick off a job to process the (full) worklist
AZ::Job* job = AZ::CreateJobFunction(processWorklist, true);
parentJob.SetContinuation(job);
job->Start();
}
}
void CullingScene::ProcessCullablesTG(const Scene& scene, View& view, AZ::TaskGraph& taskGraph)
{
AZ_PROFILE_SCOPE(RPI, "CullingScene::ProcessCullablesTG() - %s", view.GetName().GetCStr());
const Matrix4x4& worldToClip = view.GetWorldToClipMatrix();
AZ::Frustum frustum = Frustum::CreateFromMatrixColumnMajor(worldToClip);
void* maskedOcclusionCulling = nullptr;
ProcessCullablesCommon(scene, view, frustum, maskedOcclusionCulling);
AZStd::unique_ptr<WorkListType> worklist = AZStd::make_unique<WorkListType>();
AZStd::shared_ptr<WorklistData> worklistData = MakeWorklistData(m_debugCtx, scene, view, frustum, maskedOcclusionCulling);
static const AZ::TaskDescriptor descriptor{ "AZ::RPI::ProcessWorklist", "Graphics" };
auto nodeVisitorLambda = [worklistData, &taskGraph, &worklist](const AzFramework::IVisibilityScene::NodeData& nodeData) -> void
{
AZ_PROFILE_SCOPE(RPI, "nodeVisitorLambda()");
AZ_Assert(nodeData.m_entries.size() > 0, "should not get called with 0 entries");
AZ_Assert(worklist->size() < worklist->capacity(), "we should always have room to push a node on the queue");
//Queue up a small list of work items (NodeData*) which will be pushed to a worker task once the queue is full.
//This reduces the number of tasks in flight, reducing task-system overhead.
worklist->emplace_back(AZStd::move(nodeData));
if (worklist->size() == worklist->capacity())
{
//Task takes ownership of the worklist unique ptr
taskGraph.AddTask( descriptor, [worklistData, worklist = AZStd::move(worklist)]()
{
ProcessWorklist(worklistData, *worklist.get());
// allow worklist to go out of scope and be deleted
});
worklist = AZStd::make_unique<WorkListType>();
}
};
if (m_debugCtx.m_enableFrustumCulling)
{
m_visScene->Enumerate(frustum, nodeVisitorLambda);
}
else
{
m_visScene->EnumerateNoCull(nodeVisitorLambda);
}
if (worklist->size() > 0)
{
//Task takes ownership of the worklist unique ptr
taskGraph.AddTask( descriptor, [worklistData, worklist = AZStd::move(worklist)]()
{
ProcessWorklist(worklistData, *worklist.get());
// allow worklist to go out of scope and be deleted
});
}
}
uint32_t AddLodDataToView(const Vector3& pos, const Cullable::LodData& lodData, RPI::View& view)
{
#ifdef AZ_CULL_PROFILE_DETAILED
@@ -702,6 +792,8 @@ namespace AZ
AZ::Name visSceneName(AZStd::string::format("RenderCullScene[%s]", m_parentScene->GetName().GetCStr()));
m_visScene = AZ::Interface<AzFramework::IVisibilitySystem>::Get()->CreateVisibilityScene(visSceneName);
m_taskGraphActive = AZ::Interface<AZ::TaskGraphActiveInterface>::Get();
#ifdef AZ_CULL_DEBUG_ENABLED
AZ_Assert(CountObjectsInScene() == 0, "The culling system should start with 0 entries in this scene.");
#endif
@@ -719,19 +811,35 @@ namespace AZ
}
}
void CullingScene::BeginCulling(const AZStd::vector<ViewPtr>& views)
void CullingScene::BeginCullingTaskGraph(const AZStd::vector<ViewPtr>& views)
{
AZ_PROFILE_SCOPE(RPI, "CullingScene: BeginCulling");
m_cullDataConcurrencyCheck.soft_lock();
AZ::TaskGraph taskGraph;
AZ::TaskDescriptor beginCullingDescriptor{"RPI_CullingScene_BeginCullingView", "Graphics"};
for (auto& view : views)
{
taskGraph.AddTask(
beginCullingDescriptor,
[&view]()
{
AZ_PROFILE_SCOPE(RPI, "CullingScene: BeginCullingTaskGraph");
view->BeginCulling();
});
}
m_debugCtx.ResetCullStats();
m_debugCtx.m_numCullablesInScene = GetNumCullables();
AZ::TaskGraphEvent waitForCompletion;
taskGraph.Submit(&waitForCompletion);
waitForCompletion.Wait();
}
void CullingScene::BeginCullingJobs(const AZStd::vector<ViewPtr>& views)
{
AZ::JobCompletion beginCullingCompletion;
for (auto& view : views)
{
const auto cullingLambda = [&view]()
{
AZ_PROFILE_SCOPE(RPI, "CullingScene: BeginCullingJob");
view->BeginCulling();
};
@@ -741,7 +849,32 @@ namespace AZ
}
beginCullingCompletion.StartAndWaitForCompletion();
}
void CullingScene::BeginCulling(const AZStd::vector<ViewPtr>& views)
{
AZ_PROFILE_SCOPE(RPI, "CullingScene: BeginCulling");
m_cullDataConcurrencyCheck.soft_lock();
m_debugCtx.ResetCullStats();
m_debugCtx.m_numCullablesInScene = GetNumCullables();
m_taskGraphActive = AZ::Interface<AZ::TaskGraphActiveInterface>::Get();
if(views.size() == 1) // avoid job overhead when only 1 job
{
views[0]->BeginCulling();
}
else if (m_taskGraphActive && m_taskGraphActive->IsTaskGraphActive())
{
BeginCullingTaskGraph(views);
}
else
{
BeginCullingJobs(views);
}
#ifdef AZ_CULL_DEBUG_ENABLED
AuxGeomDrawPtr auxGeom;
if (m_debugCtx.m_debugDraw)
{
@@ -774,6 +907,7 @@ namespace AZ
m_debugCtx.m_frozenFrustums.clear();
}
}
#endif
}
void CullingScene::EndCulling()
@@ -141,6 +141,7 @@ namespace AZ
void DynamicDrawContext::InitVertexFormat(const AZStd::vector<VertexChannel>& vertexChannels)
{
AZ_Assert(!m_initialized, "Can't call InitVertexFormat after context was initialized (EndInit was called)");
AZ_Assert(m_pipelineState, "Can't call InitVertexFormat before InitShader is called with a valid shader");
m_perVertexDataSize = 0;
RHI::InputStreamLayoutBuilder layoutBuilder;
@@ -150,7 +151,10 @@ namespace AZ
bufferBuilder->Channel(channel.m_channel, channel.m_format);
m_perVertexDataSize += RHI::GetFormatSize(channel.m_format);
}
m_pipelineState->InputStreamLayout() = layoutBuilder.End();
if (m_pipelineState)
{
m_pipelineState->InputStreamLayout() = layoutBuilder.End();
}
}
void DynamicDrawContext::InitDrawListTag(RHI::DrawListTag drawListTag)
@@ -27,7 +27,6 @@
#include <AtomCore/Instance/InstanceDatabase.h>
#include <AzCore/Debug/EventTrace.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/Asset/AssetManager.h>
@@ -16,12 +16,13 @@
#include <Atom/RHI/Factory.h>
#include <AzCore/Debug/EventTrace.h>
#include <AtomCore/Instance/InstanceDatabase.h>
// Enable this define to debug output streaming image initialization and expanding process.
//#define AZ_RPI_STREAMING_IMAGE_DEBUG_LOG
AZ_DECLARE_BUDGET(RPI);
namespace AZ
{
namespace RPI
@@ -111,7 +112,7 @@ namespace AZ
RHI::ResultCode StreamingImage::Init(StreamingImageAsset& imageAsset)
{
AZ_TRACE_METHOD();
AZ_PROFILE_FUNCTION(RPI);
Data::Instance<StreamingImagePool> pool;
if (imageAsset.GetPoolAssetId().IsValid())
@@ -12,9 +12,10 @@
#include <AtomCore/Instance/InstanceDatabase.h>
#include <AzCore/Debug/EventTrace.h>
#include <AzCore/Jobs/Job.h>
AZ_DECLARE_BUDGET(RPI);
namespace AZ
{
namespace RPI
@@ -34,7 +35,7 @@ namespace AZ
void StreamingImageController::AttachImage(StreamingImage* image)
{
AZ_TRACE_METHOD();
AZ_PROFILE_FUNCTION(RPI);
AZ_Assert(image, "Image must not be null");
@@ -69,7 +70,7 @@ namespace AZ
void StreamingImageController::Update()
{
AZ_TRACE_METHOD();
AZ_PROFILE_FUNCTION(RPI);
AZStd::lock_guard<AZStd::mutex> lock(m_mutex);
UpdateInternal(m_timestamp, m_contexts);
@@ -14,7 +14,6 @@
#include <Atom/RHI/Factory.h>
#include <AzCore/Debug/EventTrace.h>
#include <AtomCore/Instance/InstanceDatabase.h>
namespace AZ
@@ -43,7 +42,7 @@ namespace AZ
RHI::ResultCode StreamingImagePool::Init(RHI::Device& device, StreamingImagePoolAsset& poolAsset)
{
AZ_TRACE_METHOD();
AZ_PROFILE_FUNCTION(RPI);
if (Validation::IsEnabled())
{
@@ -18,7 +18,6 @@
#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
#include <Atom/RPI.Reflect/Material/MaterialFunctor.h>
#include <AzCore/Debug/EventTrace.h>
#include <AtomCore/Instance/InstanceDatabase.h>
#include <AtomCore/Utils/ScopedValue.h>
@@ -57,7 +56,7 @@ namespace AZ
RHI::ResultCode Material::Init(MaterialAsset& materialAsset)
{
AZ_TRACE_METHOD();
AZ_PROFILE_FUNCTION(RPI);
ScopedValue isInitializing(&m_isInitializing, true, false);
@@ -234,7 +233,7 @@ namespace AZ
{
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->Material::OnAssetReloaded %s", this, asset.GetHint().c_str());
Data::Asset<MaterialAsset> newMaterialAsset = { asset.GetAs<MaterialAsset>(), AZ::Data::AssetLoadBehavior::PreLoad };
Data::Asset<MaterialAsset> newMaterialAsset = Data::static_pointer_cast<MaterialAsset>(asset);
if (newMaterialAsset)
{
@@ -320,7 +319,7 @@ namespace AZ
bool Material::Compile()
{
AZ_TRACE_METHOD();
AZ_PROFILE_FUNCTION(RPI);
if (NeedsCompile() && CanCompile())
{
@@ -610,7 +609,7 @@ namespace AZ
}
}
if (Data::Asset<StreamingImageAsset> streamingImageAsset = { imageAsset.GetAs<StreamingImageAsset>(), AZ::Data::AssetLoadBehavior::PreLoad })
if (Data::Asset<StreamingImageAsset> streamingImageAsset = Data::static_pointer_cast<StreamingImageAsset>(imageAsset))
{
Data::Instance<Image> image = StreamingImage::FindOrCreate(streamingImageAsset);
if (!image)
@@ -11,7 +11,6 @@
#include <Atom/RHI/Factory.h>
#include <AzCore/Debug/EventTrace.h>
#include <AtomCore/Instance/InstanceDatabase.h>
#include <AzCore/Debug/Timer.h>
#include <AzCore/Jobs/JobFunction.h>
@@ -12,7 +12,6 @@
#include <Atom/RHI/Factory.h>
#include <Atom/RHI.Reflect/InputStreamLayoutBuilder.h>
#include <AzCore/Debug/EventTrace.h>
#include <AtomCore/Instance/InstanceDatabase.h>
namespace AZ
@@ -52,7 +51,7 @@ namespace AZ
RHI::ResultCode ModelLod::Init(const Data::Asset<ModelLodAsset>& lodAsset, const Data::Asset<ModelAsset>& modelAsset)
{
AZ_TRACE_METHOD();
AZ_PROFILE_FUNCTION(RPI);
for (const ModelLodAsset::Mesh& mesh : lodAsset->GetMeshes())
{
@@ -389,7 +388,7 @@ namespace AZ
const ModelLodAsset::Mesh::StreamBufferInfo& streamBufferInfo,
Mesh& meshInstance)
{
AZ_TRACE_METHOD();
AZ_PROFILE_FUNCTION(RPI);
const Data::Asset<BufferAsset>& streamBufferAsset = streamBufferInfo.m_bufferAssetView.GetBufferAsset();
const Data::Instance<Buffer>& streamBuffer = Buffer::FindOrCreate(streamBufferAsset);
@@ -9,6 +9,7 @@
#include <Atom/RPI.Public/Pass/FullscreenTrianglePass.h>
#include <Atom/RPI.Public/Pass/PassUtils.h>
#include <Atom/RPI.Public/RPIUtils.h>
#include <Atom/RPI.Public/Shader/ShaderReloadDebugTracker.h>
#include <Atom/RPI.Reflect/Pass/FullscreenTrianglePassData.h>
#include <Atom/RPI.Reflect/Pass/PassTemplate.h>
@@ -46,16 +47,19 @@ namespace AZ
void FullscreenTrianglePass::OnShaderReinitialized(const Shader&)
{
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->FullscreenTrianglePass::OnShaderReinitialized", this);
LoadShader();
}
void FullscreenTrianglePass::OnShaderAssetReinitialized(const Data::Asset<ShaderAsset>&)
{
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->FullscreenTrianglePass::OnShaderAssetReinitialized", this);
LoadShader();
}
void FullscreenTrianglePass::OnShaderVariantReinitialized(const ShaderVariant&)
{
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->FullscreenTrianglePass::OnShaderVariantReinitialized", this);
LoadShader();
}
@@ -129,6 +133,8 @@ namespace AZ
void FullscreenTrianglePass::InitializeInternal()
{
RenderPass::InitializeInternal();
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->FullscreenTrianglePass::InitializeInternal", this);
// This draw item purposefully does not reference any geometry buffers.
// Instead it's expected that the extended class uses a vertex shader
@@ -136,6 +142,12 @@ namespace AZ
RHI::DrawLinear draw = RHI::DrawLinear();
draw.m_vertexCount = 3;
if (m_shader == nullptr)
{
AZ_Error("PassSystem", false, "[FullscreenTrianglePass]: Shader not loaded!");
return;
}
RHI::PipelineStateDescriptorForDraw pipelineStateDescriptor;
// [GFX TODO][ATOM-872] The pass should be able to drive the shader variant
@@ -9,11 +9,15 @@
#include <AtomCore/Instance/InstanceDatabase.h>
#include <AtomCore/std/containers/vector_set.h>
#include <Atom/RPI.Public/Pass/SlowClearPass.h>
#include <Atom/RPI.Public/Pass/ParentPass.h>
#include <Atom/RPI.Public/Pass/PassAttachment.h>
#include <Atom/RPI.Public/Pass/PassDefines.h>
#include <Atom/RPI.Public/Pass/PassSystemInterface.h>
#include <Atom/RPI.Public/RenderPipeline.h>
#include <Atom/RPI.Reflect/Pass/SlowClearPassData.h>
#include <Atom/RPI.Reflect/Pass/PassName.h>
#include <Atom/RPI.Reflect/Pass/PassRequest.h>
namespace AZ
@@ -196,7 +200,7 @@ namespace AZ
}
}
// --- PassTemplate related functions ---
// --- Child creation ---
void ParentPass::CreatePassesFromTemplate()
{
@@ -217,6 +221,49 @@ namespace AZ
}
}
void ParentPass::CreateClearPassFromBinding(PassAttachmentBinding& binding, PassRequest& clearRequest)
{
if (binding.m_unifiedScopeDesc.m_loadStoreAction.m_loadAction == RHI::AttachmentLoadAction::Clear ||
binding.m_unifiedScopeDesc.m_loadStoreAction.m_loadActionStencil == RHI::AttachmentLoadAction::Clear)
{
// Set the name of the child clear pass as well as the binding it's connected to
clearRequest.m_passName = ConcatPassName(Name("Clear"), binding.m_name);
clearRequest.m_connections[0].m_attachmentRef.m_attachment = binding.m_name;
// Set the pass clear value to the clear value of the attachment binding
SlowClearPassData* clearData = static_cast<SlowClearPassData*>(clearRequest.m_passData.get());
clearData->m_clearValue = binding.m_unifiedScopeDesc.m_loadStoreAction.m_clearValue;
// Create and add the pass
Ptr<Pass> clearPass = PassSystemInterface::Get()->CreatePassFromRequest(&clearRequest);
if (clearPass)
{
AddChild(clearPass);
}
}
}
void ParentPass::CreateClearPassesFromBindings()
{
PassRequest clearRequest;
clearRequest.m_templateName = Name("SlowClearPassTemplate");
clearRequest.m_passData = AZStd::make_shared<SlowClearPassData>();
clearRequest.m_connections.push_back();
clearRequest.m_connections[0].m_localSlot = Name("ClearInputOutput");
clearRequest.m_connections[0].m_attachmentRef.m_pass = Name("Parent");
for (uint32_t idx = 0; idx < GetInputCount(); ++idx)
{
CreateClearPassFromBinding(GetInputBinding(idx), clearRequest);
}
for (uint32_t idx = 0; idx < GetInputOutputCount(); ++idx)
{
CreateClearPassFromBinding(GetInputOutputBinding(idx), clearRequest);
}
}
// --- Pass behavior functions ---
void ParentPass::CreateChildPasses()
@@ -229,6 +276,7 @@ namespace AZ
m_flags.m_alreadyCreatedChildren = true;
RemoveChildren();
CreateClearPassesFromBindings();
CreatePassesFromTemplate();
CreateChildPassesInternal();
@@ -147,6 +147,11 @@ namespace AZ
m_treeDepth = m_parent->m_treeDepth + 1;
m_path = ConcatPassName(m_parent->m_path, m_name);
m_flags.m_partOfHierarchy = m_parent->m_flags.m_partOfHierarchy;
if (m_state == PassState::Orphaned)
{
QueueForBuildAndInitialization();
}
}
void Pass::RemoveFromParent()
@@ -154,7 +159,7 @@ namespace AZ
AZ_RPI_PASS_ASSERT(m_parent != nullptr, "Trying to remove pass from parent but pointer to the parent pass is null.");
m_parent->RemoveChild(Ptr<Pass>(this));
m_queueState = PassQueueState::NoQueue;
m_state = PassState::Idle;
m_state = PassState::Orphaned;
}
void Pass::OnOrphan()
@@ -162,6 +167,8 @@ namespace AZ
m_parent = nullptr;
m_flags.m_partOfHierarchy = false;
m_treeDepth = 0;
m_queueState = PassQueueState::NoQueue;
m_state = PassState::Orphaned;
}
// --- Getters & Setters ---
@@ -1281,6 +1288,7 @@ namespace AZ
void Pass::FrameBegin(FramePrepareParams params)
{
AZ_PROFILE_SCOPE(RPI, "Pass::FrameBegin() - %s", m_path.GetCStr());
AZ_RPI_BREAK_ON_TARGET_PASS;
if (!IsEnabled())
@@ -1303,7 +1311,10 @@ namespace AZ
// FrameBeginInternal needs to be the last function be called in FrameBegin because its implementation expects
// all the attachments are imported to database (for example, ImageAttachmentPreview)
FrameBeginInternal(params);
{
AZ_PROFILE_SCOPE(RPI, "Pass::FrameBeginInternal()");
FrameBeginInternal(params);
}
// readback attachment with output state
UpdateReadbackAttachment(params, false);
@@ -19,6 +19,7 @@
#include <Atom/RPI.Public/Pass/PassFilter.h>
#include <Atom/RPI.Public/Pass/RasterPass.h>
#include <Atom/RPI.Public/Pass/MSAAResolvePass.h>
#include <Atom/RPI.Public/Pass/SlowClearPass.h>
#include <Atom/RPI.Public/Pass/Specific/MSAAResolveFullScreenPass.h>
#include <Atom/RPI.Public/Pass/Specific/EnvironmentCubeMapPass.h>
#include <Atom/RPI.Public/Pass/Specific/RenderToTexturePass.h>
@@ -60,6 +61,7 @@ namespace AZ
{
AddPassCreator(Name("ParentPass"), &ParentPass::Create);
AddPassCreator(Name("RasterPass"), &RasterPass::Create);
AddPassCreator(Name("SlowClearPass"), &SlowClearPass::Create);
AddPassCreator(Name("CopyPass"), &CopyPass::Create);
AddPassCreator(Name("FullScreenTriangle"), &FullscreenTrianglePass::Create);
AddPassCreator(Name("ComputePass"), &ComputePass::Create);
@@ -90,13 +90,13 @@ namespace AZ
return filter;
}
void PassFilter::SetOwenrScene(const Scene* scene)
void PassFilter::SetOwnerScene(const Scene* scene)
{
m_ownerScene = scene;
UpdateFilterOptions();
}
void PassFilter::SetOwenrRenderPipeline(const RenderPipeline* renderPipeline)
void PassFilter::SetOwnerRenderPipeline(const RenderPipeline* renderPipeline)
{
m_ownerRenderPipeline = renderPipeline;
UpdateFilterOptions();
@@ -294,7 +294,7 @@ namespace AZ
void PassLibrary::OnAssetReloaded(Data::Asset<Data::AssetData> asset)
{
// Handle pass asset reload
Data::Asset<PassAsset> passAsset = { asset.GetAs<PassAsset>(), AZ::Data::AssetLoadBehavior::PreLoad };
Data::Asset<PassAsset> passAsset = Data::static_pointer_cast<PassAsset>(asset);
if (passAsset && passAsset->GetPassTemplate())
{
LoadPassAsset(passAsset->GetPassTemplate()->m_name, passAsset, true);
@@ -9,7 +9,6 @@
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/Asset/AssetManagerBus.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/Debug/EventTrace.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/IO/SystemFile.h>
#include <AzCore/Serialization/Utils.h>
@@ -40,6 +39,7 @@
#include <Atom/RPI.Reflect/Pass/PassTemplate.h>
#include <Atom/RPI.Reflect/Pass/RasterPassData.h>
#include <Atom/RPI.Reflect/Pass/RenderPassData.h>
#include <Atom/RPI.Reflect/Pass/SlowClearPassData.h>
namespace AZ
{
@@ -68,6 +68,7 @@ namespace AZ
PassSlot::Reflect(context);
PassData::Reflect(context);
SlowClearPassData::Reflect(context);
CopyPassData::Reflect(context);
RenderPassData::Reflect(context);
ComputePassData::Reflect(context);
@@ -312,7 +313,6 @@ namespace AZ
Pass::FramePrepareParams params{ &frameGraphBuilder };
{
AZ_PROFILE_SCOPE(RPI, "Pass: FrameBegin");
m_rootPass->FrameBegin(params);
}
}
@@ -146,6 +146,7 @@ namespace AZ
void RasterPass::UpdateDrawList()
{
AZ_PROFILE_SCOPE(RPI, "RasterPass::UpdateDrawList");
// DrawLists from dynamic draw
AZStd::vector<RHI::DrawListView> drawLists = DynamicDrawInterface::Get()->GetDrawListsForPass(this);
@@ -216,8 +217,6 @@ namespace AZ
void RasterPass::CompileResources(const RHI::FrameGraphCompileContext& context)
{
AZ_PROFILE_SCOPE(RPI, "RasterPass: CompileResources");
if (m_shaderResourceGroup == nullptr)
{
return;
@@ -276,7 +276,8 @@ namespace AZ
{
inputIndex = imageIndex;
}
const RHI::ImageView* imageView = context.GetImageView(attachment->GetAttachmentId(), binding.m_attachmentUsageIndex);
const RHI::ImageView* imageView =
context.GetImageView(attachment->GetAttachmentId(), binding.m_unifiedScopeDesc.GetImageViewDescriptor(), binding.m_scopeAttachmentUsage);
if (binding.m_shaderImageDimensionsNameIndex.HasName())
{
@@ -315,7 +316,7 @@ namespace AZ
{
inputIndex = bufferIndex;
}
const RHI::BufferView* bufferView = context.GetBufferView(attachment->GetAttachmentId(), binding.m_attachmentUsageIndex);
const RHI::BufferView* bufferView = context.GetBufferView(attachment->GetAttachmentId(), binding.m_scopeAttachmentUsage);
m_shaderResourceGroup->SetBufferView(RHI::ShaderInputBufferIndex(inputIndex), bufferView, arrayIndex);
++bufferIndex;
}
@@ -0,0 +1,45 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <Atom/RPI.Public/Pass/SlowClearPass.h>
#include <Atom/RPI.Public/Pass/PassUtils.h>
#include <Atom/RPI.Reflect/Pass/SlowClearPassData.h>
namespace AZ
{
namespace RPI
{
Ptr<SlowClearPass> SlowClearPass::Create(const PassDescriptor& descriptor)
{
Ptr<SlowClearPass> pass = aznew SlowClearPass(descriptor);
return pass;
}
SlowClearPass::SlowClearPass(const PassDescriptor& descriptor)
: RenderPass(descriptor)
{
const SlowClearPassData* passData = PassUtils::GetPassData<SlowClearPassData>(descriptor);
if (passData != nullptr)
{
m_clearValue = passData->m_clearValue;
}
}
void SlowClearPass::InitializeInternal()
{
RenderPass::InitializeInternal();
// Set clear value
AZ_Assert(GetInputOutputCount() > 0, "SlowClearPass: Missing InputOutput binding!");
RPI::PassAttachmentBinding& binding = GetInputOutputBinding(0);
binding.m_unifiedScopeDesc.m_loadStoreAction.m_clearValue = m_clearValue;
}
} // namespace RPI
} // namespace AZ
@@ -231,7 +231,7 @@ namespace AZ
void ImageAttachmentPreviewPass::OnAssetReloaded(Data::Asset<Data::AssetData> asset)
{
Data::Asset<ShaderAsset> shaderAsset = { asset.GetAs<ShaderAsset>(), AZ::Data::AssetLoadBehavior::PreLoad };
Data::Asset<ShaderAsset> shaderAsset = Data::static_pointer_cast<ShaderAsset>(asset);
if (shaderAsset)
{
m_needsShaderLoad = true;
@@ -31,8 +31,8 @@
#include <Atom/RHI/Device.h>
#include <Atom/RHI.Reflect/PlatformLimitsDescriptor.h>
#include <AzCore/Debug/EventTrace.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/Time/ITime.h>
#include <AzFramework/Asset/AssetSystemBus.h>
@@ -268,21 +268,18 @@ namespace AZ
AssetInitBus::Broadcast(&AssetInitBus::Events::PostLoadInit);
// Update tick time info
FillTickTimeInfo();
m_currentSimulationTime = GetCurrentTime();
for (auto& scene : m_scenes)
{
scene->Simulate(m_tickTime, m_simulationJobPolicy);
scene->Simulate(m_simulationJobPolicy, m_currentSimulationTime);
}
}
void RPISystem::FillTickTimeInfo()
float RPISystem::GetCurrentTime() const
{
AZ::TickRequestBus::BroadcastResult(m_tickTime.m_gameDeltaTime, &AZ::TickRequestBus::Events::GetTickDeltaTime);
ScriptTimePoint currentTime;
AZ::TickRequestBus::BroadcastResult(currentTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
m_tickTime.m_currentGameTime = static_cast<float>(currentTime.GetSeconds());
const AZ::TimeUs currentSimulationTimeUs = AZ::GetRealElapsedTimeUs();
return AZ::TimeUsToSeconds(currentSimulationTimeUs);
}
void RPISystem::RenderTick()
@@ -301,7 +298,7 @@ namespace AZ
// [GFX TODO] We may parallel scenes' prepare render.
for (auto& scenePtr : m_scenes)
{
scenePtr->PrepareRender(m_tickTime, m_prepareRenderJobPolicy);
scenePtr->PrepareRender(m_prepareRenderJobPolicy, m_currentSimulationTime);
}
m_rhiSystem.FrameUpdate(
@@ -178,6 +178,10 @@ namespace AZ
pipelineViews.m_views.resize(1);
}
ViewPtr previousView = pipelineViews.m_views[0];
if (view)
{
view->OnAddToRenderPipeline();
}
pipelineViews.m_views[0] = view;
if (previousView)
@@ -238,6 +242,7 @@ namespace AZ
pipelineViews.m_type = PipelineViewType::Transient;
}
view->SetPassesByDrawList(&pipelineViews.m_passesByDrawList);
view->OnAddToRenderPipeline();
pipelineViews.m_views.push_back(view);
}
}
@@ -375,7 +380,7 @@ namespace AZ
m_scene->RemoveRenderPipeline(m_nameId);
}
void RenderPipeline::OnStartFrame([[maybe_unused]] const TickTimeInfo& tick)
void RenderPipeline::OnStartFrame([[maybe_unused]] float time)
{
AZ_PROFILE_SCOPE(RPI, "RenderPipeline: OnStartFrame");
+78 -60
View File
@@ -18,7 +18,6 @@
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
#include <Atom/RPI.Public/View.h>
#include <AzCore/Debug/EventTrace.h>
#include <AzCore/Debug/Profiler.h>
#include <AzCore/Jobs/JobFunction.h>
#include <AzCore/Jobs/JobEmpty.h>
@@ -44,6 +43,9 @@ namespace AZ
{
auto shaderAsset = RPISystemInterface::Get()->GetCommonShaderAssetForSrgs();
scene->m_srg = ShaderResourceGroup::Create(shaderAsset, sceneSrgLayout->GetName());
// Set value for constants defined in SceneTimeSrg.azsli
scene->m_timeInputIndex = scene->m_srg->FindShaderInputConstantIndex(Name{ "m_time" });
}
scene->m_name = sceneDescriptor.m_nameId;
@@ -111,7 +113,8 @@ namespace AZ
{
if (m_taskGraphActive)
{
WaitTGEvent(m_simulationFinishedTGEvent, &m_simulationFinishedWorkActive);
WaitAndCleanTGEvent(AZStd::move(m_simulationFinishedTGEvent));
m_simulationFinishedTGEvent.reset();
}
else
{
@@ -381,12 +384,14 @@ namespace AZ
simulationTGDesc,
[this, featureProcessor]()
{
featureProcessor->Simulate(m_simulatePacket);
FeatureProcessor::SimulatePacket jobPacket = m_simulatePacket;
jobPacket.m_parentJob = nullptr;
featureProcessor->Simulate(jobPacket);
});
}
simulationTG.Detach();
m_simulationFinishedWorkActive = true;
simulationTG.Submit(&m_simulationFinishedTGEvent);
m_simulationFinishedTGEvent = AZStd::make_unique<TaskGraphEvent>();
simulationTG.Submit(m_simulationFinishedTGEvent.get());
}
void Scene::SimulateJobs()
@@ -397,10 +402,11 @@ namespace AZ
for (FeatureProcessorPtr& fp : m_featureProcessors)
{
FeatureProcessor* featureProcessor = fp.get();
const auto jobLambda = [this, featureProcessor]()
const auto jobLambda = [this, featureProcessor](AZ::Job& owner)
{
featureProcessor->Simulate(m_simulatePacket);
FeatureProcessor::SimulatePacket jobPacket = m_simulatePacket;
jobPacket.m_parentJob = &owner;
featureProcessor->Simulate(jobPacket);
};
AZ::Job* simulationJob = AZ::CreateJobFunction(AZStd::move(jobLambda), true, nullptr); //auto-deletes
@@ -410,16 +416,17 @@ namespace AZ
//[GFX TODO]: the completion job should start here
}
void Scene::Simulate([[maybe_unused]] const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy)
void Scene::Simulate(RHI::JobPolicy jobPolicy, float simulationTime)
{
AZ_PROFILE_SCOPE(RPI, "Scene: Simulate");
m_simulationTime = tickInfo.m_currentGameTime;
m_simulationTime = simulationTime;
// If previous simulation job wasn't done, wait for it to finish.
if (m_taskGraphActive)
{
WaitTGEvent(m_simulationFinishedTGEvent, &m_simulationFinishedWorkActive);
WaitAndCleanTGEvent(AZStd::move(m_simulationFinishedTGEvent));
m_simulationFinishedTGEvent.reset();
}
else
{
@@ -449,17 +456,14 @@ namespace AZ
}
}
void Scene::WaitTGEvent(AZ::TaskGraphEvent& completionTGEvent, AZStd::atomic_bool* workToWaitOn )
void Scene::WaitAndCleanTGEvent(AZStd::unique_ptr<AZ::TaskGraphEvent>&& completionTGEvent)
{
AZ_PROFILE_SCOPE(RPI, "Scene: WaitAndCleanCompletionJob");
if (!workToWaitOn || workToWaitOn->load())
AZ_PROFILE_SCOPE(RPI, "Scene: WaitAndCleanTGEvent");
if (completionTGEvent)
{
completionTGEvent.Wait();
}
if (workToWaitOn)
{
workToWaitOn->store(false);
completionTGEvent->Wait();
}
// allow completionTGEvent to go out of scope and be deleted
}
void Scene::WaitAndCleanCompletionJob(AZ::JobCompletion*& completionJob)
@@ -483,11 +487,9 @@ namespace AZ
{
if (m_srg)
{
// Set value for constants defined in SceneTimeSrg.azsli
RHI::ShaderInputConstantIndex timeIndex = m_srg->FindShaderInputConstantIndex(Name{ "m_time" });
if (timeIndex.IsValid())
if (m_timeInputIndex.IsValid())
{
m_srg->SetConstant(timeIndex, m_simulationTime);
m_srg->SetConstant(m_timeInputIndex, m_simulationTime);
}
// signal any handlers to update values for their partial scene srg
@@ -499,12 +501,12 @@ namespace AZ
void Scene::CollectDrawPacketsTaskGraph()
{
AZ_PROFILE_SCOPE(RPI, "CollectDrawPackets");
AZ_PROFILE_SCOPE(RPI, "CollectDrawPacketsTaskGraph");
AZ::TaskGraphEvent collectDrawPacketsTGEvent;
static const AZ::TaskDescriptor collectDrawPacketsTGDesc{"RPI_Scene_PrepareRender_CollectDrawPackets", "Graphics"};
AZ::TaskGraph collectDrawPacketsTG;
// Launch FeatureProcessor::Render() jobs
// Launch FeatureProcessor::Render() taskgraphs
for (auto& fp : m_featureProcessors)
{
collectDrawPacketsTG.AddTask(
@@ -518,34 +520,50 @@ namespace AZ
collectDrawPacketsTG.Submit(&collectDrawPacketsTGEvent);
// Launch CullingSystem::ProcessCullables() jobs (will run concurrently with FeatureProcessor::Render() jobs if m_parallelOctreeTraversal)
bool parallelOctreeTraversal = m_cullingScene->GetDebugContext().m_parallelOctreeTraversal;
const bool parallelOctreeTraversal = m_cullingScene->GetDebugContext().m_parallelOctreeTraversal;
m_cullingScene->BeginCulling(m_renderPacket.m_views);
AZ::JobCompletion processCullablesCompletion;
for (ViewPtr& viewPtr : m_renderPacket.m_views)
static const AZ::TaskDescriptor processCullablesDescriptor{"AZ::RPI::Scene::ProcessCullables", "Graphics"};
AZ::TaskGraphEvent processCullablesTGEvent;
AZ::TaskGraph processCullablesTG;
if (parallelOctreeTraversal)
{
AZ::Job* processCullablesJob = AZ::CreateJobFunction([this, &viewPtr](AZ::Job& thisJob)
{
m_cullingScene->ProcessCullables(*this, *viewPtr, thisJob); // can't call directly because ProcessCullables needs a parent job
},
true, nullptr); //auto-deletes
if (parallelOctreeTraversal)
for (ViewPtr& viewPtr : m_renderPacket.m_views)
{
processCullablesJob->SetDependent(&processCullablesCompletion);
processCullablesJob->Start();
}
else
{
processCullablesJob->StartAndWaitForCompletion();
processCullablesTG.AddTask(processCullablesDescriptor, [this, &viewPtr, &processCullablesTGEvent]()
{
AZ::TaskGraph subTaskGraph;
m_cullingScene->ProcessCullablesTG(*this, *viewPtr, subTaskGraph);
if (!subTaskGraph.IsEmpty())
{
subTaskGraph.Detach();
subTaskGraph.Submit(&processCullablesTGEvent);
}
});
}
}
else
{
for (ViewPtr& viewPtr : m_renderPacket.m_views)
{
m_cullingScene->ProcessCullablesTG(*this, *viewPtr, processCullablesTG);
}
}
bool processCullablesHasWork = !processCullablesTG.IsEmpty();
if (processCullablesHasWork)
{
processCullablesTG.Submit(&processCullablesTGEvent);
}
WaitTGEvent(collectDrawPacketsTGEvent);
processCullablesCompletion.StartAndWaitForCompletion();
collectDrawPacketsTGEvent.Wait();
if (processCullablesHasWork) // skip the wait if there is no work to do
{
processCullablesTGEvent.Wait();
}
}
void Scene::CollectDrawPacketsJobs()
{
AZ_PROFILE_SCOPE(RPI, "CollectDrawPackets");
AZ_PROFILE_SCOPE(RPI, "CollectDrawPacketsJobs");
AZ::JobCompletion* collectDrawPacketsCompletion = aznew AZ::JobCompletion();
// Launch FeatureProcessor::Render() jobs
@@ -562,15 +580,16 @@ namespace AZ
}
// Launch CullingSystem::ProcessCullables() jobs (will run concurrently with FeatureProcessor::Render() jobs)
const bool parallelOctreeTraversal = m_cullingScene->GetDebugContext().m_parallelOctreeTraversal;
m_cullingScene->BeginCulling(m_renderPacket.m_views);
for (ViewPtr& viewPtr : m_renderPacket.m_views)
{
AZ::Job* processCullablesJob = AZ::CreateJobFunction([this, &viewPtr](AZ::Job& thisJob)
{
m_cullingScene->ProcessCullables(*this, *viewPtr, thisJob); // can't call directly because ProcessCullables needs a parent job
m_cullingScene->ProcessCullablesJobs(*this, *viewPtr, thisJob); // can't call directly because ProcessCullables needs a parent job
},
true, nullptr); //auto-deletes
if (m_cullingScene->GetDebugContext().m_parallelOctreeTraversal)
if (parallelOctreeTraversal)
{
processCullablesJob->SetDependent(collectDrawPacketsCompletion);
processCullablesJob->Start();
@@ -594,13 +613,13 @@ namespace AZ
{
finalizeDrawListsTG.AddTask(
finalizeDrawListsTGDesc,
[view]()
[view, &finalizeDrawListsTGEvent]()
{
view->FinalizeDrawLists();
view->FinalizeDrawListsTG(finalizeDrawListsTGEvent);
});
}
finalizeDrawListsTG.Submit(&finalizeDrawListsTGEvent);
WaitTGEvent(finalizeDrawListsTGEvent);
finalizeDrawListsTGEvent.Wait();
}
void Scene::FinalizeDrawListsJobs()
@@ -608,9 +627,9 @@ namespace AZ
AZ::JobCompletion* finalizeDrawListsCompletion = aznew AZ::JobCompletion();
for (auto& view : m_renderPacket.m_views)
{
const auto finalizeDrawListsLambda = [view]()
const auto finalizeDrawListsLambda = [view](AZ::Job& job)
{
view->FinalizeDrawLists();
view->FinalizeDrawListsJob(&job);
};
AZ::Job* finalizeDrawListsJob = AZ::CreateJobFunction(AZStd::move(finalizeDrawListsLambda), true, nullptr); //auto-deletes
@@ -620,13 +639,14 @@ namespace AZ
WaitAndCleanCompletionJob(finalizeDrawListsCompletion);
}
void Scene::PrepareRender(const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy)
void Scene::PrepareRender(RHI::JobPolicy jobPolicy, float simulationTime)
{
AZ_PROFILE_SCOPE(RPI, "Scene: PrepareRender");
if (m_taskGraphActive)
{
WaitTGEvent(m_simulationFinishedTGEvent, &m_simulationFinishedWorkActive);
WaitAndCleanTGEvent(AZStd::move(m_simulationFinishedTGEvent));
m_simulationFinishedTGEvent.reset();
}
else
{
@@ -644,7 +664,7 @@ namespace AZ
if (pipeline->NeedsRender())
{
activePipelines.push_back(pipeline);
pipeline->OnStartFrame(tickInfo);
pipeline->OnStartFrame(simulationTime);
}
}
}
@@ -717,20 +737,19 @@ namespace AZ
// Add dynamic draw data for all the views
if (m_dynamicDrawSystem)
{
AZ_PROFILE_SCOPE(RPI, "DynamicDraw SubmitDrawData");
m_dynamicDrawSystem->SubmitDrawData(this, m_renderPacket.m_views);
}
}
{
AZ_PROFILE_BEGIN(RPI, "FinalizeDrawLists");
if (jobPolicy == RHI::JobPolicy::Serial)
AZ_PROFILE_SCOPE(RPI, "FinalizeDrawLists");
if (jobPolicy == RHI::JobPolicy::Serial ||
m_renderPacket.m_views.size() <= 1) // FinalizeDrawListsX both immediately wait for the job to complete, skip job if only 1 job would be generated
{
for (auto& view : m_renderPacket.m_views)
{
view->FinalizeDrawLists();
view->FinalizeDrawListsJob(nullptr);
}
AZ_PROFILE_END(RPI);
}
else
{
@@ -742,7 +761,6 @@ namespace AZ
{
FinalizeDrawListsJobs();
}
AZ_PROFILE_END(RPI);
}
}
@@ -15,6 +15,8 @@
#include <Atom/RPI.Public/Shader/ShaderSystemInterface.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/Component/TickBus.h>
namespace AZ
{
@@ -96,8 +98,7 @@ namespace AZ
RHI::ResultCode Shader::Init(ShaderAsset& shaderAsset)
{
Data::AssetBus::Handler::BusDisconnect();
ShaderReloadNotificationBus::Handler::BusDisconnect();
Data::AssetBus::MultiHandler::BusDisconnect();
ShaderVariantFinderNotificationBus::Handler::BusDisconnect();
RHI::RHISystemInterface* rhiSystem = RHI::RHISystemInterface::Get();
@@ -112,7 +113,8 @@ namespace AZ
AZStd::unique_lock<decltype(m_variantCacheMutex)> lock(m_variantCacheMutex);
m_shaderVariants.clear();
}
m_rootVariant.Init(Data::Asset<ShaderAsset>{&shaderAsset, AZ::Data::AssetLoadBehavior::PreLoad}, shaderAsset.GetRootVariant(m_supervariantIndex), m_supervariantIndex);
auto rootShaderVariantAsset = shaderAsset.GetRootVariant(m_supervariantIndex);
m_rootVariant.Init(m_asset, rootShaderVariantAsset, m_supervariantIndex);
if (m_pipelineLibraryHandle.IsNull())
{
@@ -146,8 +148,8 @@ namespace AZ
}
ShaderVariantFinderNotificationBus::Handler::BusConnect(m_asset.GetId());
Data::AssetBus::Handler::BusConnect(m_asset.GetId());
ShaderReloadNotificationBus::Handler::BusConnect(m_asset.GetId());
Data::AssetBus::MultiHandler::BusConnect(rootShaderVariantAsset.GetId());
Data::AssetBus::MultiHandler::BusConnect(m_asset.GetId());
return RHI::ResultCode::Success;
}
@@ -155,8 +157,7 @@ namespace AZ
void Shader::Shutdown()
{
ShaderVariantFinderNotificationBus::Handler::BusDisconnect();
Data::AssetBus::Handler::BusDisconnect();
ShaderReloadNotificationBus::Handler::BusDisconnect();
Data::AssetBus::MultiHandler::BusDisconnect();
if (m_pipelineLibraryHandle.IsValid())
{
@@ -181,14 +182,52 @@ namespace AZ
{
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->Shader::OnAssetReloaded %s", this, asset.GetHint().c_str());
if (asset->GetId() == m_asset->GetId())
if (asset.GetAs<ShaderVariantAsset>())
{
Data::Asset<ShaderAsset> newAsset = { asset.GetAs<ShaderAsset>(), AZ::Data::AssetLoadBehavior::PreLoad };
AZ_Assert(newAsset, "Reloaded ShaderAsset is null");
m_reloadedRootShaderVariantAsset = Data::static_pointer_cast<ShaderVariantAsset>(asset);
if (m_asset->m_buildTimestamp == m_reloadedRootShaderVariantAsset->GetBuildTimestamp())
{
Init(*m_asset.Get());
ShaderReloadNotificationBus::Event(asset.GetId(), &ShaderReloadNotificationBus::Events::OnShaderReinitialized, *this);
}
return;
}
Init(*newAsset.Get());
if (asset.GetAs<ShaderAsset>())
{
m_asset = Data::static_pointer_cast<ShaderAsset>(asset);
if (!m_reloadedRootShaderVariantAsset.IsReady())
{
// Do nothing, as We should not re-initilize until the root shader variant asset has been reloaded.
return;
}
AZ_Assert(m_asset->m_buildTimestamp == m_reloadedRootShaderVariantAsset->GetBuildTimestamp(),
"shaderAsset '%s' timeStamp=%lld, but Root ShaderVariantAsset timeStamp=%lld", m_asset.GetHint().c_str(),
m_asset->m_buildTimestamp, m_reloadedRootShaderVariantAsset->GetBuildTimestamp());
m_asset->UpdateRootShaderVariantAsset(m_supervariantIndex, m_reloadedRootShaderVariantAsset);
m_reloadedRootShaderVariantAsset = {}; // Clear the temporary reference.
if (ShaderReloadDebugTracker::IsEnabled())
{
auto makeTimeString = [](AZ::u64 timestamp, AZ::u64 now)
{
AZ::u64 elapsedMillis = now - timestamp;
double elapsedSeconds = aznumeric_cast<double>(elapsedMillis / 1'000);
AZStd::string timeString = AZStd::string::format("%lld (%f seconds ago)", timestamp, elapsedSeconds);
return timeString;
};
AZStd::sys_time_t now = AZStd::GetTimeNowMicroSecond();
const auto shaderVariantAsset = m_asset->GetRootVariant();
ShaderReloadDebugTracker::Printf("{%p}->Shader::OnAssetReloaded for shader '%s' [build time %s] found variant '%s' [build time %s]", this,
m_asset.GetHint().c_str(), makeTimeString(m_asset->m_buildTimestamp, now).c_str(),
shaderVariantAsset.GetHint().c_str(), makeTimeString(shaderVariantAsset->GetBuildTimestamp(), now).c_str());
}
Init(*m_asset.Get());
ShaderReloadNotificationBus::Event(asset.GetId(), &ShaderReloadNotificationBus::Events::OnShaderReinitialized, *this);
}
}
///////////////////////////////////////////////////////////////////////
@@ -253,23 +292,6 @@ namespace AZ
ShaderReloadNotificationBus::Event(m_asset.GetId(), &ShaderReloadNotificationBus::Events::OnShaderVariantReinitialized, updatedVariant);
}
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
// ShaderReloadNotificationBus overrides...
void Shader::OnShaderAssetReinitialized(const Data::Asset<ShaderAsset>& shaderAsset)
{
// When reloads occur, it's possible for old Asset objects to hang around and report reinitialization,
// so we can reduce unnecessary reinitialization in that case.
if (shaderAsset.Get() == m_asset.Get())
{
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->Shader::OnShaderAssetReinitialized %s", this, shaderAsset.GetHint().c_str());
Init(*m_asset.Get());
ShaderReloadNotificationBus::Event(shaderAsset.GetId(), &ShaderReloadNotificationBus::Events::OnShaderReinitialized, *this);
}
}
///////////////////////////////////////////////////////////////////
ConstPtr<RHI::PipelineLibraryData> Shader::LoadPipelineLibrary() const
{
@@ -320,6 +342,30 @@ namespace AZ
}
const ShaderVariant& Shader::GetVariant(ShaderVariantStableId shaderVariantStableId)
{
const ShaderVariant& variant = GetVariantInternal(shaderVariantStableId);
if (ShaderReloadDebugTracker::IsEnabled())
{
auto makeTimeString = [](AZStd::sys_time_t timestamp, AZStd::sys_time_t now)
{
AZStd::sys_time_t elapsedMicroseconds = now - timestamp;
double elapsedSeconds = aznumeric_cast<double>(elapsedMicroseconds / 1'000'000);
AZStd::string timeString = AZStd::string::format("%lld (%f seconds ago)", timestamp, elapsedSeconds);
return timeString;
};
AZStd::sys_time_t now = AZStd::GetTimeNowMicroSecond();
ShaderReloadDebugTracker::Printf("{%p}->Shader::GetVariant for shader '%s' [build time %s] found variant '%s' [build time %s]", this,
m_asset.GetHint().c_str(), makeTimeString(m_asset->GetBuildTimestamp(), now).c_str(),
variant.GetShaderVariantAsset().GetHint().c_str(), makeTimeString(variant.GetShaderVariantAsset()->GetBuildTimestamp(), now).c_str());
}
return variant;
}
const ShaderVariant& Shader::GetVariantInternal(ShaderVariantStableId shaderVariantStableId)
{
if (!shaderVariantStableId.IsValid() || shaderVariantStableId == ShaderAsset::RootShaderVariantStableId)
{
@@ -336,7 +382,7 @@ namespace AZ
// reloaded, but some (or all) shader variants haven't been built yet. Since we want to use the latest version of the
// shader code, ignore the old variants and fall back to the newer root variant instead. There's no need to report a
// warning here because m_asset->GetVariant below will report one.
if (findIt->second.GetBuildTimestamp() >= m_asset->GetShaderAssetBuildTimestamp())
if (findIt->second.GetBuildTimestamp() >= m_asset->GetBuildTimestamp())
{
return findIt->second;
}
@@ -359,7 +405,7 @@ namespace AZ
auto findIt = m_shaderVariants.find(shaderVariantStableId);
if (findIt != m_shaderVariants.end())
{
if (findIt->second.GetBuildTimestamp() >= m_asset->GetShaderAssetBuildTimestamp())
if (findIt->second.GetBuildTimestamp() >= m_asset->GetBuildTimestamp())
{
return findIt->second;
}
@@ -7,24 +7,71 @@
*/
#include <Atom/RPI.Public/Shader/ShaderReloadDebugTracker.h>
#include <AzCore/Module/Environment.h>
namespace AZ
{
namespace RPI
{
bool ShaderReloadDebugTracker::s_enabled = false;
int ShaderReloadDebugTracker::s_indent = 0;
namespace ShaderReloadDebugTrackerInternal
{
static constexpr char EnabledVariableName[] = "ShaderReloadDebugTracker enabled";
static constexpr char IndentVariableName[] = "ShaderReloadDebugTracker indent";
static EnvironmentVariable<bool> s_enabled;
static EnvironmentVariable<int> s_indent;
}
void ShaderReloadDebugTracker::Init()
{
MakeReady();
}
void ShaderReloadDebugTracker::Shutdown()
{
ShaderReloadDebugTrackerInternal::s_enabled.Reset();
ShaderReloadDebugTrackerInternal::s_indent.Reset();
}
void ShaderReloadDebugTracker::MakeReady()
{
if (!ShaderReloadDebugTrackerInternal::s_enabled.IsValid())
{
ShaderReloadDebugTrackerInternal::s_enabled = AZ::Environment::CreateVariable<bool>(AZ::Crc32(ShaderReloadDebugTrackerInternal::EnabledVariableName), false);
ShaderReloadDebugTrackerInternal::s_indent = AZ::Environment::CreateVariable<int>(AZ::Crc32(ShaderReloadDebugTrackerInternal::IndentVariableName), 0);
}
}
bool ShaderReloadDebugTracker::IsEnabled()
{
#ifdef AZ_ENABLE_SHADER_RELOAD_DEBUG_TRACKER
MakeReady();
// Set this to true in the debugger to turn on hot reload tracing.
// If needed, we could hook this up to a CVar.
return s_enabled;
return ShaderReloadDebugTrackerInternal::s_enabled.Get();
#else
return false;
#endif
}
void ShaderReloadDebugTracker::AddIndent()
{
MakeReady();
ShaderReloadDebugTrackerInternal::s_indent.Get() += IndentSpaces;
}
void ShaderReloadDebugTracker::RemoveIndent()
{
MakeReady();
ShaderReloadDebugTrackerInternal::s_indent.Get() -= IndentSpaces;
}
int ShaderReloadDebugTracker::GetIndent()
{
MakeReady();
return ShaderReloadDebugTrackerInternal::s_indent.Get();
}
ShaderReloadDebugTracker::ScopedSection::~ScopedSection()
{
@@ -10,7 +10,6 @@
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
#include <AzCore/Debug/EventTrace.h>
#include <AtomCore/Instance/InstanceDatabase.h>
namespace AZ
@@ -75,8 +74,6 @@ namespace AZ
RHI::ResultCode ShaderResourceGroup::Init(ShaderAsset& shaderAsset, const SupervariantIndex& supervariantIndex, const AZ::Name& srgName)
{
AZ_TRACE_METHOD();
const auto& lay = shaderAsset.FindShaderResourceGroupLayout(srgName, supervariantIndex);
m_layout = lay.get();
@@ -10,6 +10,7 @@
#include <Atom/RPI.Public/Shader/Shader.h>
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
#include <Atom/RPI.Public/Shader/ShaderResourceGroupPool.h>
#include <Atom/RPI.Public/Shader/ShaderReloadDebugTracker.h>
#include <Atom/RPI.Reflect/Asset/AssetHandler.h>
#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
@@ -86,10 +87,13 @@ namespace AZ
};
Data::InstanceDatabase<ShaderResourceGroupPool>::Create(azrtti_typeid<ShaderResourceGroupPool>(), handler, false);
}
ShaderReloadDebugTracker::Init();
}
void ShaderSystem::Shutdown()
{
ShaderReloadDebugTracker::Shutdown();
Data::InstanceDatabase<Shader>::Destroy();
Data::InstanceDatabase<ShaderResourceGroup>::Destroy();
Data::InstanceDatabase<ShaderResourceGroupPool>::Destroy();
@@ -22,24 +22,20 @@ namespace AZ
const Data::Asset<ShaderAsset>& shaderAsset,
const Data::Asset<ShaderVariantAsset>& shaderVariantAsset,
SupervariantIndex supervariantIndex)
{
{
m_shaderAsset = shaderAsset;
m_shaderVariantAsset = shaderVariantAsset;
m_supervariantIndex = supervariantIndex;
m_pipelineStateType = shaderAsset->GetPipelineStateType();
m_pipelineLayoutDescriptor = shaderAsset->GetPipelineLayoutDescriptor(supervariantIndex);
m_shaderVariantAsset = shaderVariantAsset;
m_renderStates = &shaderAsset->GetRenderStates(supervariantIndex);
m_supervariantIndex = supervariantIndex;
Data::AssetBus::MultiHandler::BusDisconnect();
Data::AssetBus::MultiHandler::BusConnect(shaderAsset.GetId());
Data::AssetBus::MultiHandler::BusConnect(shaderVariantAsset.GetId());
m_shaderAsset = shaderAsset;
return true;
}
ShaderVariant::~ShaderVariant()
{
Data::AssetBus::MultiHandler::BusDisconnect();
}
void ShaderVariant::ConfigurePipelineState(RHI::PipelineStateDescriptor& descriptor) const
@@ -82,25 +78,5 @@ namespace AZ
}
}
void ShaderVariant::OnAssetReloaded(Data::Asset<Data::AssetData> asset)
{
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->ShaderVariant::OnAssetReloaded %s", this, asset.GetHint().c_str());
if (asset.GetAs<ShaderVariantAsset>())
{
Data::Asset<ShaderVariantAsset> shaderVariantAsset = { asset.GetAs<ShaderVariantAsset>(), AZ::Data::AssetLoadBehavior::PreLoad };
Init(m_shaderAsset, shaderVariantAsset, m_supervariantIndex);
ShaderReloadNotificationBus::Event(m_shaderAsset.GetId(), &ShaderReloadNotificationBus::Events::OnShaderVariantReinitialized, *this);
}
if (asset.GetAs<ShaderAsset>())
{
Data::Asset<ShaderAsset> shaderAsset = { asset.GetAs<ShaderAsset>(), AZ::Data::AssetLoadBehavior::PreLoad };
Init(shaderAsset, m_shaderVariantAsset, m_supervariantIndex);
ShaderReloadNotificationBus::Event(m_shaderAsset.GetId(), &ShaderReloadNotificationBus::Events::OnShaderVariantReinitialized, *this);
}
}
} // namespace RPI
} // namespace AZ
+139 -32
View File
@@ -19,6 +19,9 @@
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Math/MatrixUtils.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Jobs/JobCompletion.h>
#include <AzCore/Jobs/JobFunction.h>
#include <AzCore/Task/TaskGraph.h>
#include <Atom_RPI_Traits_Platform.h>
#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
@@ -47,18 +50,14 @@ namespace AZ
{
AZ_Assert(!name.IsEmpty(), "invalid name");
// Set default matrixes.
// Set default matrices
SetWorldToViewMatrix(AZ::Matrix4x4::CreateIdentity());
AZ::Matrix4x4 viewToClipMatrix;
AZ::MakePerspectiveFovMatrixRH(viewToClipMatrix, AZ::Constants::HalfPi, 1, 0.1f, 1000.f, true);
SetViewToClipMatrix(viewToClipMatrix);
Data::Asset<ShaderAsset> viewSrgShaderAsset = RPISystemInterface::Get()->GetCommonShaderAssetForSrgs();
TryCreateShaderResourceGroup();
if (viewSrgShaderAsset.IsReady())
{
m_shaderResourceGroup = ShaderResourceGroup::Create(viewSrgShaderAsset, RPISystemInterface::Get()->GetViewSrgLayout()->GetName());
}
#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
m_maskedOcclusionCulling = MaskedOcclusionCulling::Create();
m_maskedOcclusionCulling->SetResolution(MaskedSoftwareOcclusionCullingWidth, MaskedSoftwareOcclusionCullingHeight);
@@ -125,6 +124,7 @@ namespace AZ
m_worldToViewMatrix = worldToView;
m_worldToClipMatrix = m_viewToClipMatrix * m_worldToViewMatrix;
m_clipToWorldMatrix = m_worldToClipMatrix.GetInverseFull();
m_onWorldToViewMatrixChange.Signal(m_worldToViewMatrix);
m_onWorldToClipMatrixChange.Signal(m_worldToClipMatrix);
@@ -162,6 +162,7 @@ namespace AZ
m_worldToViewMatrix = m_viewToWorldMatrix.GetInverseFast();
m_worldToClipMatrix = m_viewToClipMatrix * m_worldToViewMatrix;
m_clipToWorldMatrix = m_worldToClipMatrix.GetInverseFull();
// Only signal an update when there is a change, otherwise this might block
// user input from changing the value.
@@ -177,6 +178,7 @@ namespace AZ
m_viewToClipMatrix = viewToClip;
m_worldToClipMatrix = m_viewToClipMatrix * m_worldToViewMatrix;
m_clipToWorldMatrix = m_worldToClipMatrix.GetInverseFull();
// Update z depth constant simultaneously
// zNear -> n, zFar -> f
@@ -217,6 +219,16 @@ namespace AZ
return m_viewToWorldMatrix;
}
AZ::Matrix3x4 View::GetWorldToViewMatrixAsMatrix3x4() const
{
return AZ::Matrix3x4::UnsafeCreateFromMatrix4x4(m_worldToViewMatrix);
}
AZ::Matrix3x4 View::GetViewToWorldMatrixAsMatrix3x4() const
{
return AZ::Matrix3x4::UnsafeCreateFromMatrix4x4(m_viewToWorldMatrix);
}
const AZ::Matrix4x4& View::GetViewToClipMatrix() const
{
return m_viewToClipMatrix;
@@ -227,6 +239,11 @@ namespace AZ
return m_worldToClipMatrix;
}
const AZ::Matrix4x4& View::GetClipToWorldMatrix() const
{
return m_clipToWorldMatrix;
}
bool View::HasDrawListTag(RHI::DrawListTag drawListTag)
{
return drawListTag.IsValid() && m_drawListMask[drawListTag.GetIndex()];
@@ -237,24 +254,79 @@ namespace AZ
return m_drawListContext.GetList(drawListTag);
}
void View::FinalizeDrawLists()
void View::FinalizeDrawListsTG(AZ::TaskGraphEvent& finalizeDrawListsTGEvent)
{
AZ_PROFILE_SCOPE(RPI, "View: FinalizeDrawLists");
m_drawListContext.FinalizeLists();
SortFinalizedDrawLists();
SortFinalizedDrawListsTG(finalizeDrawListsTGEvent);
}
void View::FinalizeDrawListsJob(AZ::Job* parentJob)
{
AZ_PROFILE_SCOPE(RPI, "View: FinalizeDrawLists");
m_drawListContext.FinalizeLists();
SortFinalizedDrawListsJob(parentJob);
}
void View::SortFinalizedDrawLists()
void View::SortFinalizedDrawListsTG(AZ::TaskGraphEvent& finalizeDrawListsTGEvent)
{
AZ_PROFILE_SCOPE(RPI, "View: SortFinalizedDrawLists");
RHI::DrawListsByTag& drawListsByTag = m_drawListContext.GetMergedDrawListsByTag();
AZ::TaskGraph drawListSortTG;
AZ::TaskDescriptor drawListSortTGDescriptor{"RPI_View_SortFinalizedDrawLists", "Graphics"};
for (size_t idx = 0; idx < drawListsByTag.size(); ++idx)
{
if (drawListsByTag[idx].size() > 1)
{
SortDrawList(drawListsByTag[idx], RHI::DrawListTag(idx));
drawListSortTG.AddTask(drawListSortTGDescriptor, [this, &drawListsByTag, idx]()
{
AZ_PROFILE_SCOPE(RPI, "View: SortDrawList Task");
SortDrawList(drawListsByTag[idx], RHI::DrawListTag(idx));
});
}
}
if (!drawListSortTG.IsEmpty())
{
drawListSortTG.Detach();
drawListSortTG.Submit(&finalizeDrawListsTGEvent);
}
}
void View::SortFinalizedDrawListsJob(AZ::Job* parentJob)
{
AZ_PROFILE_SCOPE(RPI, "View: SortFinalizedDrawLists");
RHI::DrawListsByTag& drawListsByTag = m_drawListContext.GetMergedDrawListsByTag();
AZ::JobCompletion jobCompletion;
for (size_t idx = 0; idx < drawListsByTag.size(); ++idx)
{
if (drawListsByTag[idx].size() > 1)
{
auto jobLambda = [this, &drawListsByTag, idx]()
{
AZ_PROFILE_SCOPE(RPI, "View: SortDrawList Job");
SortDrawList(drawListsByTag[idx], RHI::DrawListTag(idx));
};
Job* jobSortDrawList = aznew JobFunction<decltype(jobLambda)>(jobLambda, true, nullptr); // Auto-deletes
if (parentJob)
{
parentJob->StartAsChild(jobSortDrawList);
}
else
{
jobSortDrawList->SetDependent(&jobCompletion);
jobSortDrawList->Start();
}
}
}
if (parentJob)
{
parentJob->WaitForChildren();
}
else
{
jobCompletion.StartAndWaitForCompletion();
}
}
void View::SortDrawList(RHI::DrawList& drawList, RHI::DrawListTag tag)
@@ -263,12 +335,12 @@ namespace AZ
passWithDrawListTag->SortDrawList(drawList);
}
void View::ConnectWorldToViewMatrixChangedHandler(View::MatrixChangedEvent::Handler& handler)
void View::ConnectWorldToViewMatrixChangedHandler(MatrixChangedEvent::Handler& handler)
{
handler.Connect(m_onWorldToViewMatrixChange);
}
void View::ConnectWorldToClipMatrixChangedHandler(View::MatrixChangedEvent::Handler& handler)
void View::ConnectWorldToClipMatrixChangedHandler(MatrixChangedEvent::Handler& handler)
{
handler.Connect(m_onWorldToClipMatrixChange);
}
@@ -361,16 +433,19 @@ namespace AZ
{
if (m_clipSpaceOffset.IsZero())
{
Matrix4x4 worldToClipPrevMatrix = m_viewToClipPrevMatrix * m_worldToViewPrevMatrix;
m_shaderResourceGroup->SetConstant(m_worldToClipPrevMatrixConstantIndex, worldToClipPrevMatrix);
m_shaderResourceGroup->SetConstant(m_viewProjectionMatrixConstantIndex, m_worldToClipMatrix);
m_shaderResourceGroup->SetConstant(m_projectionMatrixConstantIndex, m_viewToClipMatrix);
m_shaderResourceGroup->SetConstant(m_clipToWorldMatrixConstantIndex, m_clipToWorldMatrix);
m_shaderResourceGroup->SetConstant(m_projectionMatrixInverseConstantIndex, m_viewToClipMatrix.GetInverseFull());
if (m_shaderResourceGroup)
{
Matrix4x4 worldToClipPrevMatrix = m_viewToClipPrevMatrix * m_worldToViewPrevMatrix;
m_shaderResourceGroup->SetConstant(m_worldToClipPrevMatrixConstantIndex, worldToClipPrevMatrix);
m_shaderResourceGroup->SetConstant(m_viewProjectionMatrixConstantIndex, m_worldToClipMatrix);
m_shaderResourceGroup->SetConstant(m_projectionMatrixConstantIndex, m_viewToClipMatrix);
m_shaderResourceGroup->SetConstant(m_clipToWorldMatrixConstantIndex, m_clipToWorldMatrix);
m_shaderResourceGroup->SetConstant(m_projectionMatrixInverseConstantIndex, m_viewToClipMatrix.GetInverseFull());
}
}
else
{
// Offset the current and previous frame clip matricies
// Offset the current and previous frame clip matrices
Matrix4x4 offsetViewToClipMatrix = m_viewToClipMatrix;
offsetViewToClipMatrix.SetElement(0, 2, m_clipSpaceOffset.GetX());
offsetViewToClipMatrix.SetElement(1, 2, m_clipSpaceOffset.GetY());
@@ -379,27 +454,33 @@ namespace AZ
offsetViewToClipPrevMatrix.SetElement(0, 2, m_clipSpaceOffset.GetX());
offsetViewToClipPrevMatrix.SetElement(1, 2, m_clipSpaceOffset.GetY());
// Build other matricies dependent on the view to clip matricies
// Build other matrices dependent on the view to clip matrices
Matrix4x4 offsetWorldToClipMatrix = offsetViewToClipMatrix * m_worldToViewMatrix;
Matrix4x4 offsetWorldToClipPrevMatrix = offsetViewToClipPrevMatrix * m_worldToViewPrevMatrix;
Matrix4x4 offsetClipToViewMatrix = offsetViewToClipMatrix.GetInverseFull();
Matrix4x4 offsetClipToWorldMatrix = m_viewToWorldMatrix * offsetClipToViewMatrix;
m_shaderResourceGroup->SetConstant(m_worldToClipPrevMatrixConstantIndex, offsetWorldToClipPrevMatrix);
m_shaderResourceGroup->SetConstant(m_viewProjectionMatrixConstantIndex, offsetWorldToClipMatrix);
m_shaderResourceGroup->SetConstant(m_projectionMatrixConstantIndex, offsetViewToClipMatrix);
m_shaderResourceGroup->SetConstant(m_clipToWorldMatrixConstantIndex, offsetClipToWorldMatrix);
m_shaderResourceGroup->SetConstant(m_projectionMatrixInverseConstantIndex, offsetViewToClipMatrix.GetInverseFull());
if (m_shaderResourceGroup)
{
m_shaderResourceGroup->SetConstant(m_worldToClipPrevMatrixConstantIndex, offsetWorldToClipPrevMatrix);
m_shaderResourceGroup->SetConstant(m_viewProjectionMatrixConstantIndex, offsetWorldToClipMatrix);
m_shaderResourceGroup->SetConstant(m_projectionMatrixConstantIndex, offsetViewToClipMatrix);
m_shaderResourceGroup->SetConstant(m_clipToWorldMatrixConstantIndex, offsetClipToWorldMatrix);
m_shaderResourceGroup->SetConstant(m_projectionMatrixInverseConstantIndex, offsetViewToClipMatrix.GetInverseFull());
}
}
m_shaderResourceGroup->SetConstant(m_worldPositionConstantIndex, m_position);
m_shaderResourceGroup->SetConstant(m_viewMatrixConstantIndex, m_worldToViewMatrix);
m_shaderResourceGroup->SetConstant(m_viewMatrixInverseConstantIndex, m_worldToViewMatrix.GetInverseFull());
m_shaderResourceGroup->SetConstant(m_zConstantsConstantIndex, m_nearZ_farZ_farZTimesNearZ_farZMinusNearZ);
m_shaderResourceGroup->SetConstant(m_unprojectionConstantsIndex, m_unprojectionConstants);
if (m_shaderResourceGroup)
{
m_shaderResourceGroup->SetConstant(m_worldPositionConstantIndex, m_position);
m_shaderResourceGroup->SetConstant(m_viewMatrixConstantIndex, m_worldToViewMatrix);
m_shaderResourceGroup->SetConstant(m_viewMatrixInverseConstantIndex, m_worldToViewMatrix.GetInverseFull());
m_shaderResourceGroup->SetConstant(m_zConstantsConstantIndex, m_nearZ_farZ_farZTimesNearZ_farZMinusNearZ);
m_shaderResourceGroup->SetConstant(m_unprojectionConstantsIndex, m_unprojectionConstants);
m_shaderResourceGroup->Compile();
m_shaderResourceGroup->Compile();
}
m_viewToClipPrevMatrix = m_viewToClipMatrix;
m_worldToViewPrevMatrix = m_worldToViewMatrix;
@@ -410,6 +491,7 @@ namespace AZ
void View::BeginCulling()
{
#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
AZ_PROFILE_SCOPE(RPI, "View: ClearMaskedOcclusionBuffer");
m_maskedOcclusionCulling->ClearBuffer();
#endif
}
@@ -418,5 +500,30 @@ namespace AZ
{
return m_maskedOcclusionCulling;
}
void View::TryCreateShaderResourceGroup()
{
if (!m_shaderResourceGroup)
{
if (auto rpiSystemInterface = RPISystemInterface::Get())
{
if (Data::Asset<ShaderAsset> viewSrgShaderAsset = rpiSystemInterface->GetCommonShaderAssetForSrgs();
viewSrgShaderAsset.IsReady())
{
m_shaderResourceGroup =
ShaderResourceGroup::Create(viewSrgShaderAsset, rpiSystemInterface->GetViewSrgLayout()->GetName());
}
}
}
}
void View::OnAddToRenderPipeline()
{
TryCreateShaderResourceGroup();
if (!m_shaderResourceGroup)
{
AZ_Warning("RPI::View", false, "Shader Resource Group failed to initialize");
}
}
} // namespace RPI
} // namespace AZ
@@ -36,12 +36,12 @@ namespace AZ
AzFramework::WindowNotificationBus::Handler::BusConnect(nativeWindow);
AzFramework::ViewportRequestBus::Handler::BusConnect(id);
m_onProjectionMatrixChangedHandler = ViewportContext::MatrixChangedEvent::Handler([this](const AZ::Matrix4x4& matrix)
m_onProjectionMatrixChangedHandler = MatrixChangedEvent::Handler([this](const AZ::Matrix4x4& matrix)
{
m_projectionMatrixChangedEvent.Signal(matrix);
});
m_onViewMatrixChangedHandler = ViewportContext::MatrixChangedEvent::Handler([this](const AZ::Matrix4x4& matrix)
m_onViewMatrixChangedHandler = MatrixChangedEvent::Handler([this](const AZ::Matrix4x4& matrix)
{
m_viewMatrixChangedEvent.Signal(matrix);
});
@@ -203,6 +203,11 @@ namespace AZ
return GetDefaultView()->GetWorldToViewMatrix();
}
AZ::Matrix3x4 ViewportContext::GetCameraViewMatrixAsMatrix3x4() const
{
return GetDefaultView()->GetWorldToViewMatrixAsMatrix3x4();
}
void ViewportContext::SetCameraViewMatrix(const AZ::Matrix4x4& matrix)
{
GetDefaultView()->SetWorldToViewMatrix(matrix);
@@ -176,6 +176,20 @@ namespace AZ
return {};
}
ViewportContextPtr ViewportContextManager::GetViewportContextByScene(const Scene* scene) const
{
AZStd::lock_guard lock(m_containerMutex);
for (const auto& viewportData : m_viewportContexts)
{
ViewportContextPtr viewportContext = viewportData.second.context.lock();
if (viewportContext && viewportContext->GetRenderScene().get() == scene)
{
return viewportContext;
}
}
return {};
}
void ViewportContextManager::RenameViewportContext(ViewportContextPtr viewportContext, const Name& newContextName)
{
auto currentAssignedViewportContext = GetViewportContextByName(newContextName);
@@ -7,6 +7,9 @@
*/
#include <Atom/RPI.Reflect/Image/StreamingImageAssetHandler.h>
#include <Atom/RPI.Public/Image/ImageSystemInterface.h>
#include <AzCore/Settings/SettingsRegistry.h>
#include <AzFramework/Asset/AssetSystemBus.h>
namespace AZ
{
@@ -40,5 +43,56 @@ namespace AZ
return loadResult;
}
}
}
Data::AssetId StreamingImageAssetHandler::AssetMissingInCatalog(const Data::Asset<Data::AssetData>& asset)
{
// Find out if the asset is missing completely, or just still processing
// and escalate the asset to the top of the list
AzFramework::AssetSystem::AssetStatus missingAssetStatus;
AzFramework::AssetSystemRequestBus::BroadcastResult(
missingAssetStatus, &AzFramework::AssetSystem::AssetSystemRequests::GetAssetStatusById, asset.GetId().m_guid);
// Determine which fallback image to use
const char* relativePath = DefaultImageAssetPaths::DefaultFallback;
bool useDebugFallbackImages = true;
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
{
settingsRegistry->GetObject(useDebugFallbackImages, "/O3DE/Atom/RPI/UseDebugFallbackImages");
}
if (useDebugFallbackImages)
{
switch (missingAssetStatus)
{
case AzFramework::AssetSystem::AssetStatus::AssetStatus_Queued:
case AzFramework::AssetSystem::AssetStatus::AssetStatus_Compiling:
relativePath = DefaultImageAssetPaths::Processing;
break;
case AzFramework::AssetSystem::AssetStatus::AssetStatus_Failed:
relativePath = DefaultImageAssetPaths::ProcessingFailed;
break;
case AzFramework::AssetSystem::AssetStatus::AssetStatus_Missing:
case AzFramework::AssetSystem::AssetStatus::AssetStatus_Unknown:
case AzFramework::AssetSystem::AssetStatus::AssetStatus_Compiled:
relativePath = DefaultImageAssetPaths::Missing;
break;
}
}
// Make sure the fallback image has been processed
AzFramework::AssetSystem::AssetStatus status = AzFramework::AssetSystem::AssetStatus_Unknown;
AzFramework::AssetSystemRequestBus::BroadcastResult(
status, &AzFramework::AssetSystemRequestBus::Events::CompileAssetSync, relativePath);
// Return the asset id of the fallback image
Data::AssetId assetId{};
bool autoRegisterIfNotFound = false;
Data::AssetCatalogRequestBus::BroadcastResult(
assetId, &Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, relativePath,
azrtti_typeid<AZ::RPI::StreamingImageAsset>(), autoRegisterIfNotFound);
return assetId;
}
} // namespace RPI
} // namespace AZ
@@ -18,8 +18,6 @@
#include <AzCore/Math/Vector3.h>
#include <AzCore/Math/Vector4.h>
#include <AzCore/Math/Color.h>
#include <AzCore/Debug/EventTrace.h>
namespace AZ
{
namespace RPI
@@ -123,7 +121,7 @@ namespace AZ
void LuaMaterialFunctor::Process(RuntimeContext& context)
{
AZ_TRACE_METHOD();
AZ_PROFILE_FUNCTION(RPI);
InitScriptContext();
@@ -141,7 +139,7 @@ namespace AZ
void LuaMaterialFunctor::Process(EditorContext& context)
{
AZ_TRACE_METHOD();
AZ_PROFILE_FUNCTION(RPI);
InitScriptContext();
@@ -226,10 +226,12 @@ namespace AZ
if (changesWereApplied)
{
AZ_Warning("MaterialAsset", false,
AZ_Warning(
"MaterialAsset", false,
"This material is based on version '%u' of %s, but the material type is now at version '%u'. "
"Automatic updates are available. Consider updating the .material source file.",
originalVersion, m_materialTypeAsset.ToString<AZStd::string>().c_str(), m_materialTypeAsset->GetVersion());
"Automatic updates are available. Consider updating the .material source file for '%s'.",
originalVersion, m_materialTypeAsset.ToString<AZStd::string>().c_str(), m_materialTypeAsset->GetVersion(),
GetId().ToString<AZStd::string>().c_str());
}
m_materialTypeVersion = m_materialTypeAsset->GetVersion();
@@ -237,7 +239,7 @@ namespace AZ
void MaterialAsset::ReinitializeMaterialTypeAsset(Data::Asset<Data::AssetData> asset)
{
Data::Asset<MaterialTypeAsset> newMaterialTypeAsset = { asset.GetAs<MaterialTypeAsset>(), AZ::Data::AssetLoadBehavior::PreLoad };
Data::Asset<MaterialTypeAsset> newMaterialTypeAsset = Data::static_pointer_cast<MaterialTypeAsset>(asset);
if (newMaterialTypeAsset)
{
@@ -118,12 +118,16 @@ namespace AZ
else if (value.is<Data::Asset<Data::AssetData>>())
{
result.m_value = Data::Asset<RPI::ImageAsset>(
AZStd::any_cast<Data::Asset<Data::AssetData>>(value).GetId(), azrtti_typeid<RPI::StreamingImageAsset>());
AZStd::any_cast<Data::Asset<Data::AssetData>>(value).GetId(),
azrtti_typeid<RPI::StreamingImageAsset>(),
AZStd::any_cast<Data::Asset<Data::AssetData>>(value).GetHint());
}
else if (value.is<Data::Asset<StreamingImageAsset>>())
{
result.m_value = Data::Asset<RPI::ImageAsset>(
AZStd::any_cast<Data::Asset<StreamingImageAsset>>(value).GetId(), azrtti_typeid<RPI::StreamingImageAsset>());
AZStd::any_cast<Data::Asset<StreamingImageAsset>>(value).GetId(),
azrtti_typeid<RPI::StreamingImageAsset>(),
AZStd::any_cast<Data::Asset<StreamingImageAsset>>(value).GetHint());
}
else if (value.is<Data::Asset<ImageAsset>>())
{
@@ -188,6 +188,10 @@ namespace AZ
void MaterialTypeAsset::SetReady()
{
m_status = AssetStatus::Ready;
// If this was created dynamically using MaterialTypeAssetCreator (which is what calls SetReady()),
// we need to connect to the AssetBus for reloads.
PostLoadInit();
}
bool MaterialTypeAsset::PostLoadInit()
@@ -126,8 +126,8 @@ namespace AZ
}
ShaderCollection::Item::Item()
: m_renderStatesOverlay(RHI::GetInvalidRenderStates())
{
m_renderStatesOverlay = RHI::GetInvalidRenderStates();
}
ShaderCollection::Item& ShaderCollection::operator[](size_t i)
@@ -156,7 +156,8 @@ namespace AZ
}
ShaderCollection::Item::Item(const Data::Asset<ShaderAsset>& shaderAsset, const AZ::Name& shaderTag, ShaderVariantId variantId)
: m_shaderAsset(shaderAsset)
: m_renderStatesOverlay(RHI::GetInvalidRenderStates())
, m_shaderAsset(shaderAsset)
, m_shaderVariantId(variantId)
, m_shaderTag(shaderTag)
, m_shaderOptionGroup(shaderAsset->GetShaderOptionGroupLayout(), variantId)
@@ -164,7 +165,8 @@ namespace AZ
}
ShaderCollection::Item::Item(Data::Asset<ShaderAsset>&& shaderAsset, const AZ::Name& shaderTag, ShaderVariantId variantId)
: m_shaderAsset(AZStd::move(shaderAsset))
: m_renderStatesOverlay(RHI::GetInvalidRenderStates())
, m_shaderAsset(AZStd::move(shaderAsset))
, m_shaderVariantId(variantId)
, m_shaderTag(shaderTag)
, m_shaderOptionGroup(shaderAsset->GetShaderOptionGroupLayout(), variantId)
@@ -9,7 +9,6 @@
#include <Atom/RPI.Reflect/Model/ModelAsset.h>
#include <Atom/RPI.Reflect/Model/ModelKdTree.h>
#include <AzCore/Asset/AssetSerializer.h>
#include <AzCore/Debug/EventTrace.h>
#include <AzCore/Jobs/JobFunction.h>
#include <AzCore/Math/IntersectSegment.h>
#include <AzCore/std/limits.h>
@@ -137,7 +136,7 @@ namespace AZ
// For runtime approach is to do this during asset processing and serialized spatial information alongside with mesh model assets
const auto jobLambda = [&]() -> void
{
AZ_TRACE_METHOD();
AZ_PROFILE_FUNCTION(RPI);
AZStd::unique_ptr<ModelKdTree> tree = AZStd::make_unique<ModelKdTree>();
tree->Build(this);
@@ -201,23 +200,11 @@ namespace AZ
AZ::Vector3& normal) const
{
const BufferAssetView& indexBufferView = mesh.GetIndexBufferAssetView();
const AZStd::array_view<ModelLodAsset::Mesh::StreamBufferInfo>& streamBufferList = mesh.GetStreamBufferInfoList();
const BufferAssetView* positionBufferView = mesh.GetSemanticBufferAssetView(m_positionName);
// find position semantic
const ModelLodAsset::Mesh::StreamBufferInfo* positionBuffer = nullptr;
for (const ModelLodAsset::Mesh::StreamBufferInfo& bufferInfo : streamBufferList)
if (positionBufferView && positionBufferView->GetBufferAsset().Get())
{
if (bufferInfo.m_semantic.m_name == m_positionName)
{
positionBuffer = &bufferInfo;
break;
}
}
if (positionBuffer && positionBuffer->m_bufferAssetView.GetBufferAsset().Get())
{
BufferAsset* bufferAssetViewPtr = positionBuffer->m_bufferAssetView.GetBufferAsset().Get();
BufferAsset* bufferAssetViewPtr = positionBufferView->GetBufferAsset().Get();
BufferAsset* indexAssetViewPtr = indexBufferView.GetBufferAsset().Get();
if (!bufferAssetViewPtr || !indexAssetViewPtr)
@@ -225,7 +212,7 @@ namespace AZ
return false;
}
RHI::BufferViewDescriptor positionBufferViewDesc = bufferAssetViewPtr->GetBufferViewDescriptor();
RHI::BufferViewDescriptor positionBufferViewDesc = positionBufferView->GetBufferViewDescriptor();
AZStd::array_view<uint8_t> positionRawBuffer = bufferAssetViewPtr->GetBuffer();
const uint32_t positionElementSize = positionBufferViewDesc.m_elementSize;
@@ -234,22 +221,28 @@ namespace AZ
// Position is 3 floats
if (positionElementSize != sizeof(float) * 3)
{
AZ_Warning("ModelAsset", false, "unsupported mesh posiiton format, only full 3 floats per vertex are supported at the moment");
AZ_Warning(
"ModelAsset", false, "unsupported mesh posiiton format, only full 3 floats per vertex are supported at the moment");
return false;
}
RHI::BufferViewDescriptor indexBufferViewDesc = indexBufferView.GetBufferViewDescriptor();
AZStd::array_view<uint8_t> indexRawBuffer = indexAssetViewPtr->GetBuffer();
RHI::BufferViewDescriptor indexRawDesc = indexAssetViewPtr->GetBufferViewDescriptor();
bool anyHit = false;
const AZ::Vector3 rayEnd = rayStart + rayDir;
AZ::Vector3 a, b, c;
AZ::Vector3 intersectionNormal;
bool anyHit = false;
float shortestDistanceNormalized = AZStd::numeric_limits<float>::max();
const AZ::u32* indexPtr = reinterpret_cast<const AZ::u32*>(indexRawBuffer.data());
for (uint32_t indexIter = 0; indexIter <= indexRawDesc.m_elementCount - 3; indexIter += 3, indexPtr += 3)
const AZ::u32* indexPtr = reinterpret_cast<const AZ::u32*>(
indexRawBuffer.data() + (indexBufferViewDesc.m_elementOffset * indexBufferViewDesc.m_elementSize));
const float* positionPtr = reinterpret_cast<const float*>(
positionRawBuffer.data() + (positionBufferViewDesc.m_elementOffset * positionBufferViewDesc.m_elementSize));
constexpr int StepSize = 3; // number of values per vertex (x, y, z)
for (uint32_t indexIter = 0; indexIter < indexBufferViewDesc.m_elementCount; indexIter += StepSize, indexPtr += StepSize)
{
AZ::u32 index0 = indexPtr[0];
AZ::u32 index1 = indexPtr[1];
@@ -261,17 +254,17 @@ namespace AZ
return false;
}
const float* p = reinterpret_cast<const float*>(&positionRawBuffer[index0 * positionElementSize]);
a.Set(const_cast<float*>(p)); // faster than AZ::Vector3 c-tor
p = reinterpret_cast<const float*>(&positionRawBuffer[index1 * positionElementSize]);
b.Set(const_cast<float*>(p));
p = reinterpret_cast<const float*>(&positionRawBuffer[index2 * positionElementSize]);
c.Set(const_cast<float*>(p));
// faster than AZ::Vector3 c-tor
const float* aRef = &positionPtr[index0 * StepSize];
a.Set(aRef);
const float* bRef = &positionPtr[index1 * StepSize];
b.Set(bRef);
const float* cRef = &positionPtr[index2 * StepSize];
c.Set(cRef);
float currentDistanceNormalized;
if (AZ::Intersect::IntersectSegmentTriangleCCW(rayStart, rayEnd, a, b, c, intersectionNormal, currentDistanceNormalized))
if (AZ::Intersect::IntersectSegmentTriangleCCW(
rayStart, rayEnd, a, b, c, intersectionNormal, currentDistanceNormalized))
{
anyHit = true;
@@ -100,7 +100,7 @@ namespace AZ
->Field("pipelineStateType", &ShaderAsset::m_pipelineStateType)
->Field("shaderOptionGroupLayout", &ShaderAsset::m_shaderOptionGroupLayout)
->Field("drawListName", &ShaderAsset::m_drawListName)
->Field("shaderAssetBuildTimestamp", &ShaderAsset::m_shaderAssetBuildTimestamp)
->Field("shaderAssetBuildTimestamp", &ShaderAsset::m_buildTimestamp)
->Field("perAPIShaderData", &ShaderAsset::m_perAPIShaderData)
;
}
@@ -108,7 +108,6 @@ namespace AZ
ShaderAsset::~ShaderAsset()
{
Data::AssetBus::Handler::BusDisconnect();
ShaderVariantFinderNotificationBus::Handler::BusDisconnect();
AssetInitBus::Handler::BusDisconnect();
}
@@ -134,11 +133,11 @@ namespace AZ
return m_drawListName;
}
AZStd::sys_time_t ShaderAsset::GetShaderAssetBuildTimestamp() const
AZStd::sys_time_t ShaderAsset::GetBuildTimestamp() const
{
return m_shaderAssetBuildTimestamp;
return m_buildTimestamp;
}
void ShaderAsset::SetReady()
{
m_status = AssetStatus::Ready;
@@ -256,7 +255,7 @@ namespace AZ
}
return GetRootVariant(supervariantIndex);
}
else if (variant->GetBuildTimestamp() >= m_shaderAssetBuildTimestamp)
else if (variant->GetBuildTimestamp() >= m_buildTimestamp)
{
return variant;
}
@@ -570,46 +569,16 @@ namespace AZ
bool ShaderAsset::PostLoadInit()
{
// Once the ShaderAsset is loaded, it is necessary to listen for changes in the Root Variant Asset.
Data::AssetBus::Handler::BusConnect(GetRootVariant().GetId());
ShaderVariantFinderNotificationBus::Handler::BusConnect(GetId());
AssetInitBus::Handler::BusDisconnect();
return true;
}
void ShaderAsset::ReinitializeRootShaderVariant(Data::Asset<Data::AssetData> asset)
{
Data::Asset<ShaderVariantAsset> shaderVariantAsset = { asset.GetAs<ShaderVariantAsset>(), AZ::Data::AssetLoadBehavior::PreLoad };
AZ_Assert(shaderVariantAsset->GetStableId() == RootShaderVariantStableId, "Was expecting to update the root variant");
SupervariantIndex supervariantIndex = GetSupervariantIndexFromAssetId(asset.GetId());
GetCurrentShaderApiData().m_supervariants[supervariantIndex.GetIndex()].m_rootShaderVariantAsset = asset;
ShaderReloadNotificationBus::Event(GetId(), &ShaderReloadNotificationBus::Events::OnShaderAssetReinitialized, Data::Asset<ShaderAsset>{ this, AZ::Data::AssetLoadBehavior::PreLoad } );
}
///////////////////////////////////////////////////////////////////////
// AssetBus overrides...
void ShaderAsset::OnAssetReloaded(Data::Asset<Data::AssetData> asset)
void ShaderAsset::UpdateRootShaderVariantAsset(SupervariantIndex supervariantIndex, Data::Asset<ShaderVariantAsset> newRootVariant)
{
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->ShaderAsset::OnAssetReloaded %s", this, asset.GetHint().c_str());
ReinitializeRootShaderVariant(asset);
GetCurrentShaderApiData().m_supervariants[supervariantIndex.GetIndex()].m_rootShaderVariantAsset = newRootVariant;
}
void ShaderAsset::OnAssetReady(Data::Asset<Data::AssetData> asset)
{
// We have to listen to OnAssetReady, OnAssetReloaded isn't enough, because of the following scenario:
// The user changes a .shader file, which causes the AP to rebuild the ShaderAsset and root ShaderVariantAsset.
// 1) Thread A creates the new ShaderAsset, loads it, and gets the old ShaderVariantAsset.
// 2) Thread B creates the new ShaderVariantAsset, loads it, and calls OnAssetReloaded.
// 3) Main thread calls ShaderAsset::PostLoadInit which connects to the AssetBus but it's too late to receive OnAssetReloaded,
// so it continues using the old ShaderVariantAsset instead of the new one.
// The OnAssetReady bus function is called automatically whenever a connection to AssetBus is made, so listening to this gives
// us the opportunity to assign the appropriate ShaderVariantAsset.
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->ShaderAsset::OnAssetReady %s", this, asset.GetHint().c_str());
ReinitializeRootShaderVariant(asset);
}
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
/// ShaderVariantFinderNotificationBus overrides
@@ -628,7 +597,6 @@ namespace AZ
m_shaderVariantTree = shaderVariantTreeAsset;
}
lock.unlock();
ShaderReloadNotificationBus::Event(GetId(), &ShaderReloadNotificationBus::Events::OnShaderAssetReinitialized, Data::Asset<ShaderAsset>{ this, AZ::Data::AssetLoadBehavior::PreLoad });
}
///////////////////////////////////////////////////////////////////
@@ -21,7 +21,7 @@ namespace AZ
{
if (ValidateIsReady())
{
m_asset->m_shaderAssetBuildTimestamp = shaderAssetBuildTimestamp;
m_asset->m_buildTimestamp = shaderAssetBuildTimestamp;
}
}
@@ -390,7 +390,7 @@ namespace AZ
m_asset->m_pipelineStateType = sourceShaderAsset.m_pipelineStateType;
m_asset->m_drawListName = sourceShaderAsset.m_drawListName;
m_asset->m_shaderOptionGroupLayout = sourceShaderAsset.m_shaderOptionGroupLayout;
m_asset->m_shaderAssetBuildTimestamp = sourceShaderAsset.m_shaderAssetBuildTimestamp;
m_asset->m_buildTimestamp = sourceShaderAsset.m_buildTimestamp;
// copy root variant assets
for (auto& perAPIShaderData : sourceShaderAsset.m_perAPIShaderData)
@@ -60,7 +60,7 @@ namespace AZ
}
}
AZStd::sys_time_t ShaderVariantAsset::GetBuildTimestamp() const
AZ::u64 ShaderVariantAsset::GetBuildTimestamp() const
{
return m_buildTimestamp;
}
@@ -10,6 +10,7 @@
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/IO/Streamer/Streamer.h>
#include <AzCore/IO/SystemFile.h>
#include <AzCore/Serialization/Json/JsonSerialization.h>
#include <AzCore/Serialization/Json/JsonSystemComponent.h>
#include <AzCore/Serialization/Json/RegistrationContext.h>
@@ -46,7 +47,6 @@ namespace UnitTest
bool DeleteEntity(const AZ::EntityId&) override { return false; }
AZ::Entity* FindEntity(const AZ::EntityId&) override { return nullptr; }
AZ::BehaviorContext* GetBehaviorContext() override { return nullptr; }
const char* GetAppRoot() const override { return nullptr; }
const char* GetEngineRoot() const override { return nullptr; }
const char* GetExecutableFolder() const override { return nullptr; }
void EnumerateEntities(const EntityCallback& /*callback*/) override {}
@@ -44,7 +44,6 @@ namespace UnitTest
AZ::Entity* FindEntity(const AZ::EntityId&) override { return nullptr; }
AZ::BehaviorContext* GetBehaviorContext() override { return nullptr; }
AZ::JsonRegistrationContext* GetJsonRegistrationContext() override { return nullptr; }
const char* GetAppRoot() const override { return nullptr; }
const char* GetEngineRoot() const override { return nullptr; }
const char* GetExecutableFolder() const override { return nullptr; }
void EnumerateEntities(const EntityCallback& /*callback*/) override {}

Some files were not shown because too many files have changed in this diff Show More