From 0d5247be345493fb699e54dc0eaad41af35fa87b Mon Sep 17 00:00:00 2001 From: moudgils Date: Tue, 1 Jun 2021 09:58:45 -0700 Subject: [PATCH 01/73] Fix metal shader pipeline crashes for LuminanceHistogramGenerator and MorphTargetCS due to the use of atomic operations with typed buffers. Switching them to use Structured buffers. Plus misc cleanup --- .../Common/Assets/Shaders/MorphTargets/MorphTargetCS.shader | 4 +--- .../Common/Assets/Shaders/MorphTargets/MorphTargetSRG.azsli | 2 +- .../Assets/Shaders/PostProcessing/LuminanceHeatmap.azsl | 4 ++-- .../Shaders/PostProcessing/LuminanceHistogramGenerator.azsl | 2 +- .../PostProcessing/LuminanceHistogramGenerator.shader | 4 +--- .../Assets/Shaders/SkinnedMesh/LinearSkinningPassSRG.azsli | 2 +- .../PostProcessing/LuminanceHistogramGeneratorPass.cpp | 2 +- .../Source/SkinnedMesh/SkinnedMeshOutputStreamManager.cpp | 4 ++-- .../RHI/Code/Include/Atom/RHI/ShaderResourceGroupData.h | 1 - Gems/Atom/RHI/DX12/Code/Source/RHI/CommandList.h | 6 ++++++ 10 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/MorphTargets/MorphTargetCS.shader b/Gems/Atom/Feature/Common/Assets/Shaders/MorphTargets/MorphTargetCS.shader index 95ffc36a11..08b1e7c298 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/MorphTargets/MorphTargetCS.shader +++ b/Gems/Atom/Feature/Common/Assets/Shaders/MorphTargets/MorphTargetCS.shader @@ -10,7 +10,5 @@ "type": "Compute" } ] - }, - "DisabledRHIBackends": ["metal"] - + } } diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/MorphTargets/MorphTargetSRG.azsli b/Gems/Atom/Feature/Common/Assets/Shaders/MorphTargets/MorphTargetSRG.azsli index 7ec5b43368..171e803c2c 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/MorphTargets/MorphTargetSRG.azsli +++ b/Gems/Atom/Feature/Common/Assets/Shaders/MorphTargets/MorphTargetSRG.azsli @@ -16,7 +16,7 @@ ShaderResourceGroup MorphTargetPassSrg : SRG_PerPass { - RWBuffer m_accumulatedDeltas; + RWStruturedBuffer m_accumulatedDeltas; } // This class represents the data that is passed to the morph target compute shader of an individual delta diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/LuminanceHeatmap.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/LuminanceHeatmap.azsl index df92e36f9a..4559b6c9ef 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/LuminanceHeatmap.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/LuminanceHeatmap.azsl @@ -1,4 +1,4 @@ -/* + /* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * @@ -37,7 +37,7 @@ ShaderResourceGroup PassSrg : SRG_PerPass Texture2D m_sceneLuminance; // This should be of size NUM_HISTOGRAM_BINS. - Buffer m_histogram; + StructuredBuffer m_histogram; Sampler LinearSampler { diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/LuminanceHistogramGenerator.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/LuminanceHistogramGenerator.azsl index 05cc870eea..9d01a12fd6 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/LuminanceHistogramGenerator.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/LuminanceHistogramGenerator.azsl @@ -20,7 +20,7 @@ ShaderResourceGroup PassSrg : SRG_PerPass { Texture2D m_inputTexture; - RWBuffer m_outputTexture; + RWStructuredBuffer m_outputTexture; } groupshared uint shared_histogramBins[NUM_HISTOGRAM_BINS]; diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/LuminanceHistogramGenerator.shader b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/LuminanceHistogramGenerator.shader index 566144bab8..f3dd11e11a 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/LuminanceHistogramGenerator.shader +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/LuminanceHistogramGenerator.shader @@ -12,7 +12,5 @@ "type": "Compute" } ] - }, - "DisabledRHIBackends": ["metal"] - + } } diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/SkinnedMesh/LinearSkinningPassSRG.azsli b/Gems/Atom/Feature/Common/Assets/Shaders/SkinnedMesh/LinearSkinningPassSRG.azsli index 5a9e44bade..e5407d2d9e 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/SkinnedMesh/LinearSkinningPassSRG.azsli +++ b/Gems/Atom/Feature/Common/Assets/Shaders/SkinnedMesh/LinearSkinningPassSRG.azsli @@ -16,7 +16,7 @@ ShaderResourceGroup PassSrg : SRG_PerPass { - RWBuffer m_skinnedMeshOutputStream; + RWStructuredBuffer m_skinnedMeshOutputStream; } ShaderResourceGroup InstanceSrg : SRG_PerDraw diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LuminanceHistogramGeneratorPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LuminanceHistogramGeneratorPass.cpp index 758c21bc4e..a3c494dee9 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LuminanceHistogramGeneratorPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LuminanceHistogramGeneratorPass.cpp @@ -72,7 +72,7 @@ namespace AZ desc.m_bufferName = AZStd::string::format("LuminanceHistogramBuffer_%s", uuidString.c_str()); desc.m_elementSize = sizeof(uint32_t); desc.m_byteCount = NumHistogramBins * sizeof(uint32_t); - desc.m_elementFormat = RHI::Format::R32_UINT; + desc.m_elementFormat = RHI::Format::Unknown; m_histogram = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); AZ_Assert(m_histogram != nullptr, "Unable to allocate buffer"); } diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshOutputStreamManager.cpp b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshOutputStreamManager.cpp index 1cb782d8b1..1b14611e84 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshOutputStreamManager.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshOutputStreamManager.cpp @@ -67,8 +67,8 @@ namespace AZ creator.SetBuffer(nullptr, 0, bufferDescriptor); RHI::BufferViewDescriptor viewDescriptor; - viewDescriptor.m_elementFormat = RHI::Format::R32_FLOAT; - viewDescriptor.m_elementSize = RHI::GetFormatSize(viewDescriptor.m_elementFormat); + viewDescriptor.m_elementFormat = RHI::Format::Unknown; + viewDescriptor.m_elementSize = sizeof(float); viewDescriptor.m_elementCount = aznumeric_cast(m_sizeInBytes) / viewDescriptor.m_elementSize; viewDescriptor.m_elementOffset = 0; creator.SetBufferViewDescriptor(viewDescriptor); diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupData.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupData.h index ce2c6c77ec..afcab28a1d 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupData.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupData.h @@ -410,7 +410,6 @@ namespace AZ // For any other type the buffer view's element size should match the stride. if (shaderInputBuffer.m_strideSize != bufferViewDescriptor.m_elementSize) { - // [GFX TODO][ATOM-5735][AZSL] ByteAddressBuffer shader input is setting a stride of 16 instead of 4 AZ_Error("ShaderResourceGroupData", false, "Buffer Input '%s[%d]': Does not match expected stride size %d", shaderInputBuffer.m_name.GetCStr(), arrayIndex, bufferViewDescriptor.m_elementSize); return false; diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandList.h b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandList.h index a6fe57f6d8..6f09ea1d5f 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandList.h +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandList.h @@ -271,6 +271,12 @@ namespace AZ ShaderResourceBindings& bindings = GetShaderResourceBindingsByPipelineType(pipelineType); const PipelineState* pipelineState = static_cast(item.m_pipelineState); + if(!pipelineState) + { + AZ_Assert(false, "Pipeline state not provided"); + return false; + } + bool updatePipelineState = m_state.m_pipelineState != pipelineState; // The pipeline state gets set first. if (updatePipelineState) From 0e4a632417625d1dceb28a2d62d14a0aa8d277e9 Mon Sep 17 00:00:00 2001 From: moudgils Date: Thu, 3 Jun 2021 22:45:50 -0700 Subject: [PATCH 02/73] Add support for re-binding SRG entries if the drawItem has a new pso which changes how a srg is used in the shader. Also optimized api usage to use single call for UseResource and for setting stream buffers. --- .../Shaders/MorphTargets/MorphTargetSRG.azsli | 2 +- .../Metal/Code/Source/RHI/ArgumentBuffer.cpp | 85 ++++++++++--------- .../Metal/Code/Source/RHI/ArgumentBuffer.h | 15 +++- .../RHI/Metal/Code/Source/RHI/CommandList.cpp | 56 ++++++++---- .../RHI/Metal/Code/Source/RHI/CommandList.h | 1 + .../Metal/Code/Source/RHI/PipelineLayout.cpp | 7 ++ .../Metal/Code/Source/RHI/PipelineLayout.h | 6 ++ 7 files changed, 110 insertions(+), 62 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/MorphTargets/MorphTargetSRG.azsli b/Gems/Atom/Feature/Common/Assets/Shaders/MorphTargets/MorphTargetSRG.azsli index 171e803c2c..83193c8559 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/MorphTargets/MorphTargetSRG.azsli +++ b/Gems/Atom/Feature/Common/Assets/Shaders/MorphTargets/MorphTargetSRG.azsli @@ -16,7 +16,7 @@ ShaderResourceGroup MorphTargetPassSrg : SRG_PerPass { - RWStruturedBuffer m_accumulatedDeltas; + RWStructuredBuffer m_accumulatedDeltas; } // This class represents the data that is passed to the morph target compute shader of an individual delta diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp index 6ffd15e0bc..1e2edc6520 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp @@ -386,6 +386,11 @@ namespace AZ void ArgumentBuffer::AddUntrackedResourcesToEncoder(id commandEncoder, const ShaderResourceGroupVisibility& srgResourcesVisInfo) const { + + ComputeResourcesToMakeResidentMap resourcesToMakeResidentCompute; + GraphicsResourcesToMakeResidentMap resourcesToMakeResidentGraphics; + + //Cache the constant buffer associated with a srg if (m_constantBufferSize) { uint8_t numBitsSet = RHI::CountBitsSet(static_cast(srgResourcesVisInfo.m_constantDataStageMask)); @@ -393,28 +398,19 @@ namespace AZ { if(RHI::CheckBitsAny(srgResourcesVisInfo.m_constantDataStageMask, RHI::ShaderStageMask::Compute)) { - [static_cast>(commandEncoder) useResource:m_constantBuffer.GetGpuAddress>() usage:MTLResourceUsageRead]; + resourcesToMakeResidentCompute[MTLResourceUsageRead].m_resourceArray[resourcesToMakeResidentCompute[MTLResourceUsageRead].m_resourceArrayLen++] = m_constantBuffer.GetGpuAddress>(); } else { MTLRenderStages mtlRenderStages = GetRenderStages(srgResourcesVisInfo.m_constantDataStageMask); - [static_cast>(commandEncoder) useResource:m_constantBuffer.GetGpuAddress>() - usage:MTLResourceUsageRead - stages:mtlRenderStages]; + AZStd::pair key = AZStd::make_pair(MTLResourceUsageRead, mtlRenderStages); + resourcesToMakeResidentGraphics[key].m_resourceArray[resourcesToMakeResidentGraphics[key].m_resourceArrayLen++] = m_constantBuffer.GetGpuAddress>(); } - } } - ApplyUseResource(commandEncoder, m_resourceBindings, srgResourcesVisInfo); - } - - void ArgumentBuffer::ApplyUseResource(id encoder, - const ResourceBindingsMap& resourceMap, - const ShaderResourceGroupVisibility& srgResourcesVisInfo) const - { - - CommandEncoderType encodeType = CommandEncoderType::Invalid; - for (const auto& it : resourceMap) + + //Cach all the resources within a srg that are used by the shader based on the visibility information + for (const auto& it : m_resourceBindings) { //Extract the visibility mask for the give resource auto visMaskIt = srgResourcesVisInfo.m_resourcesStageMask.find(it.first); @@ -426,40 +422,50 @@ namespace AZ { if(RHI::CheckBitsAny(visMaskIt->second, RHI::ShaderStageMask::Compute)) { - //Call UseResource on all resources for Compute stage - ApplyUseResourceToCompute(encoder, it.second); - encodeType = CommandEncoderType::Compute; + ApplyUseResourceToCompute(commandEncoder, it.second, resourcesToMakeResidentCompute); } else { - //Call UseResource on all resources for Vertex and Fragment stages AZ_Assert(RHI::CheckBitsAny(visMaskIt->second, RHI::ShaderStageMask::Vertex) || RHI::CheckBitsAny(visMaskIt->second, RHI::ShaderStageMask::Fragment), "The visibility mask %i is not set for Vertex or fragment stage", visMaskIt->second); - ApplyUseResourceToGraphic(encoder, visMaskIt->second, it.second); - encodeType = CommandEncoderType::Render; + ApplyUseResourceToGraphic(commandEncoder, visMaskIt->second, it.second, resourcesToMakeResidentGraphics); } } } + + //Call UseResource on all resources for Compute stage + for (const auto& key : resourcesToMakeResidentCompute) + { + [static_cast>(commandEncoder) useResources: key.second.m_resourceArray.data() + count: key.second.m_resourceArrayLen + usage: key.first]; + } + + //Call UseResource on all resources for Vertex and Fragment stages + for (const auto& key : resourcesToMakeResidentGraphics) + { + [static_cast>(commandEncoder) useResources: key.second.m_resourceArray.data() + count: key.second.m_resourceArrayLen + usage: key.first.first + stages: key.first.second]; + } } - - void ArgumentBuffer::ApplyUseResourceToCompute(id encoder, const ResourceBindingsSet& resourceBindingDataSet) const + + void ArgumentBuffer::ApplyUseResourceToCompute(id encoder, const ResourceBindingsSet& resourceBindingDataSet, ComputeResourcesToMakeResidentMap& resourcesToMakeResidentMap) const { for (const auto& resourceBindingData : resourceBindingDataSet) { ResourceType rescType = resourceBindingData.m_resourcPtr->GetResourceType(); + MTLResourceUsage resourceUsage = MTLResourceUsageRead; switch(rescType) { case ResourceType::MtlTextureType: { - MTLResourceUsage resourceUsage = GetImageResourceUsage(resourceBindingData.m_imageAccess); - [static_cast>(encoder) useResource:resourceBindingData.m_resourcPtr->GetGpuAddress>() usage:resourceUsage]; - + resourceUsage |= GetImageResourceUsage(resourceBindingData.m_imageAccess); break; } case ResourceType::MtlBufferType: { - MTLResourceUsage resourceUsage = GetBufferResourceUsage(resourceBindingData.m_bufferAccess); - [static_cast>(encoder) useResource:resourceBindingData.m_resourcPtr->GetGpuAddress>() usage:resourceUsage]; - + resourceUsage |= GetBufferResourceUsage(resourceBindingData.m_bufferAccess); break; } default: @@ -467,13 +473,15 @@ namespace AZ AZ_Assert(false, "Undefined Resource type"); } } + resourcesToMakeResidentMap[resourceUsage].m_resourceArray[resourcesToMakeResidentMap[resourceUsage].m_resourceArrayLen++] = resourceBindingData.m_resourcPtr->GetGpuAddress>(); } } - void ArgumentBuffer::ApplyUseResourceToGraphic(id encoder, RHI::ShaderStageMask visShaderMask, const ResourceBindingsSet& resourceBindingDataSet) const + void ArgumentBuffer::ApplyUseResourceToGraphic(id encoder, RHI::ShaderStageMask visShaderMask, const ResourceBindingsSet& resourceBindingDataSet, GraphicsResourcesToMakeResidentMap& resourcesToMakeResidentMap) const { - + MTLRenderStages mtlRenderStages = GetRenderStages(visShaderMask); + MTLResourceUsage resourceUsage = MTLResourceUsageRead; for (const auto& resourceBindingData : resourceBindingDataSet) { ResourceType rescType = resourceBindingData.m_resourcPtr->GetResourceType(); @@ -481,20 +489,12 @@ namespace AZ { case ResourceType::MtlTextureType: { - MTLResourceUsage resourceUsage = GetImageResourceUsage(resourceBindingData.m_imageAccess); - [static_cast>(encoder) useResource:resourceBindingData.m_resourcPtr->GetGpuAddress>() - usage:resourceUsage - stages:mtlRenderStages]; - + resourceUsage |= GetImageResourceUsage(resourceBindingData.m_imageAccess); break; } case ResourceType::MtlBufferType: { - MTLResourceUsage resourceUsage = GetBufferResourceUsage(resourceBindingData.m_bufferAccess); - [static_cast>(encoder) useResource:resourceBindingData.m_resourcPtr->GetGpuAddress>() - usage:resourceUsage - stages:mtlRenderStages]; - + resourceUsage |= GetBufferResourceUsage(resourceBindingData.m_bufferAccess); break; } default: @@ -502,8 +502,9 @@ namespace AZ AZ_Assert(false, "Undefined Resource type"); } } + AZStd::pair key = AZStd::make_pair(resourceUsage, mtlRenderStages); + resourcesToMakeResidentMap[key].m_resourceArray[resourcesToMakeResidentMap[key].m_resourceArrayLen++] = resourceBindingData.m_resourcPtr->GetGpuAddress>(); } } - } } diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h index a5a8e00e69..2434b8312d 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h @@ -119,8 +119,17 @@ namespace AZ using ResourceBindingsMap = AZStd::unordered_map; ResourceBindingsMap m_resourceBindings; - void ApplyUseResourceToCompute(id encoder, const ResourceBindingsSet& resourceBindingData) const; - void ApplyUseResourceToGraphic(id encoder, RHI::ShaderStageMask visShaderMask, const ResourceBindingsSet& resourceBindingDataSet) const; + static const int MaxEntriesInArgTable = 31; + struct MetalResourceArray + { + AZStd::array, MaxEntriesInArgTable> m_resourceArray; + int m_resourceArrayLen = 0; + }; + using ComputeResourcesToMakeResidentMap = AZStd::unordered_map; + using GraphicsResourcesToMakeResidentMap = AZStd::unordered_map, MetalResourceArray>; + + void ApplyUseResourceToCompute(id encoder, const ResourceBindingsSet& resourceBindingData, ComputeResourcesToMakeResidentMap& resourcesToMakeResidentMap) const; + void ApplyUseResourceToGraphic(id encoder, RHI::ShaderStageMask visShaderMask, const ResourceBindingsSet& resourceBindingDataSet, GraphicsResourcesToMakeResidentMap& resourcesToMakeResidentMap) const; //! Use visibility information to call UseResource on all resources for this Argument Buffer void ApplyUseResource(id encoder, const ResourceBindingsMap& resourceMap, @@ -144,8 +153,6 @@ namespace AZ #endif ShaderResourceGroupPool* m_srgPool = nullptr; - - static const int MaxEntriesInArgTable = 31; NSCache* m_samplerCache; }; } diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp index 3eca8dabd8..10fbe372b1 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp @@ -258,24 +258,19 @@ namespace AZ continue; } + uint32_t srgVisIndex = pipelineLayout.GetSlotByIndex(shaderResourceGroup->GetBindingSlot()); + const RHI::ShaderStageMask& srgVisInfo = pipelineLayout.GetSrgVisibility(srgVisIndex); + if (bindings.m_srgsByIndex[srgIndex] != shaderResourceGroup) { bindings.m_srgsByIndex[srgIndex] = shaderResourceGroup; auto& compiledArgBuffer = shaderResourceGroup->GetCompiledArgumentBuffer(); - id argBuffer = compiledArgBuffer.GetArgEncoderBuffer(); size_t argBufferOffset = compiledArgBuffer.GetOffset(); - - uint32_t srgVisIndex = pipelineLayout.GetSlotByIndex(shaderResourceGroup->GetBindingSlot()); - const RHI::ShaderStageMask& srgVisInfo = pipelineLayout.GetSrgVisibility(srgVisIndex); - + if(srgVisInfo != RHI::ShaderStageMask::None) { - const ShaderResourceGroupVisibility& srgResourcesVisInfo = pipelineLayout.GetSrgResourcesVisibility(srgVisIndex); - - //For graphics and compute encoder bind the argument buffer and - //make the resource resident for the duration of the work associated with the current scope - //and ensure that it's in a format compatible with the appropriate metal function. + //For graphics and compute encoder bind the argument buffer if(m_commandEncoderType == CommandEncoderType::Render) { id renderEncoder = GetEncoder>(); @@ -293,7 +288,6 @@ namespace AZ offset:argBufferOffset atIndex:slotIndex]; } - shaderResourceGroup->AddUntrackedResourcesToEncoder(m_encoder, srgResourcesVisInfo); } else if(m_commandEncoderType == CommandEncoderType::Compute) { @@ -301,6 +295,28 @@ namespace AZ [computeEncoder setBuffer:argBuffer offset:argBufferOffset atIndex:pipelineLayout.GetSlotByIndex(srgIndex)]; + } + } + } + + //Check againgst the srg resources visibility hash as it is possible for draw items to have different PSO in the same pass. + const AZ::HashValue64 srgResourcesVisHash = pipelineLayout.GetSrgResourcesVisibilityHash(srgVisIndex); + if(bindings.m_srgVisHashByIndex[srgIndex] != srgResourcesVisHash) + { + bindings.m_srgVisHashByIndex[srgIndex] = srgResourcesVisHash; + if(srgVisInfo != RHI::ShaderStageMask::None) + { + const ShaderResourceGroupVisibility& srgResourcesVisInfo = pipelineLayout.GetSrgResourcesVisibility(srgVisIndex); + + //For graphics and compute encoder bind the argument buffer and + //make the resource resident for the duration of the work associated with the current scope + //and ensure that it's in a format compatible with the appropriate metal function. + if(m_commandEncoderType == CommandEncoderType::Render) + { + shaderResourceGroup->AddUntrackedResourcesToEncoder(m_encoder, srgResourcesVisInfo); + } + else if(m_commandEncoderType == CommandEncoderType::Compute) + { shaderResourceGroup->AddUntrackedResourcesToEncoder(m_encoder, srgResourcesVisInfo); } } @@ -447,6 +463,7 @@ namespace AZ for (size_t i = 0; i < bindings.m_srgsByIndex.size(); ++i) { bindings.m_srgsByIndex[i] = nullptr; + bindings.m_srgVisHashByIndex[i] = AZ::HashValue64{0}; } const PipelineLayout& pipelineLayout = pipelineState->GetPipelineLayout(); @@ -469,6 +486,10 @@ namespace AZ void CommandList::SetStreamBuffers(const RHI::StreamBufferView* streams, uint32_t count) { + int bufferArrayLen = 0; + AZStd::array, METAL_MAX_ENTRIES_BUFFER_ARG_TABLE> mtlStreamBuffers; + AZStd::array mtlStreamBufferOffsets; + AZ::HashValue64 streamsHash = AZ::HashValue64{0}; for (uint32_t i = 0; i < count; ++i) { @@ -479,18 +500,23 @@ namespace AZ { m_state.m_streamsHash = streamsHash; AZ_Assert(count <= METAL_MAX_ENTRIES_BUFFER_ARG_TABLE , "Slots needed cannot exceed METAL_MAX_ENTRIES_BUFFER_ARG_TABLE"); - for (uint32_t i = 0; i < count; ++i) + + NSRange range = {METAL_MAX_ENTRIES_BUFFER_ARG_TABLE - count, count}; + //For metal the stream buffers are populated from bottom to top as the top slots are taken by argument buffers + for (int i = count-1; i >= 0; --i) { if (streams[i].GetBuffer()) { const Buffer * buff = static_cast(streams[i].GetBuffer()); id mtlBuff = buff->GetMemoryView().GetGpuAddress>(); - uint32_t VBIndex = (METAL_MAX_ENTRIES_BUFFER_ARG_TABLE - 1) - i; uint32_t offset = streams[i].GetByteOffset() + buff->GetMemoryView().GetOffset(); - id renderEncoder = GetEncoder>(); - [renderEncoder setVertexBuffer: mtlBuff offset: offset atIndex: VBIndex]; + mtlStreamBuffers[bufferArrayLen] = mtlBuff; + mtlStreamBufferOffsets[bufferArrayLen] = offset; + bufferArrayLen++; } } + id renderEncoder = GetEncoder>(); + [renderEncoder setVertexBuffers: mtlStreamBuffers.data() offsets: mtlStreamBufferOffsets.data() withRange: range]; } } diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.h b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.h index 6660beb2c4..dd4e382471 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.h +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.h @@ -99,6 +99,7 @@ namespace AZ { AZStd::array m_srgsByIndex; AZStd::array m_srgsBySlot; + AZStd::array m_srgVisHashByIndex; }; ShaderResourceBindings& GetShaderResourceBindingsByPipelineType(RHI::PipelineStateType pipelineType); diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/PipelineLayout.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/PipelineLayout.cpp index f237884aab..70d36f8d6d 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/PipelineLayout.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/PipelineLayout.cpp @@ -70,6 +70,7 @@ namespace AZ m_srgVisibilities.resize(RHI::Limits::Pipeline::ShaderResourceGroupCountMax); m_srgResourcesVisibility.resize(RHI::Limits::Pipeline::ShaderResourceGroupCountMax); + m_srgResourcesVisibilityHash.resize(RHI::Limits::Pipeline::ShaderResourceGroupCountMax); for (uint32_t srgLayoutIdx = 0; srgLayoutIdx < groupLayoutCount; ++srgLayoutIdx) { const RHI::ShaderResourceGroupLayout& srgLayout = *descriptor.GetShaderResourceGroupLayout(srgLayoutIdx); @@ -111,6 +112,7 @@ namespace AZ m_srgVisibilities[srgIndex] = mask; m_srgResourcesVisibility[srgIndex] = srgVis; + m_srgResourcesVisibilityHash[srgIndex] = srgVis.GetHash(); } // Cache the inline constant size and slot index @@ -141,6 +143,11 @@ namespace AZ return m_srgResourcesVisibility[index]; } + const AZ::HashValue64 PipelineLayout::GetSrgResourcesVisibilityHash(uint32_t index) const + { + return m_srgResourcesVisibilityHash[index]; + } + uint32_t PipelineLayout::GetRootConstantsSize() const { return m_rootConstantsSize; diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/PipelineLayout.h b/Gems/Atom/RHI/Metal/Code/Source/RHI/PipelineLayout.h index e8cd249393..6fd06ea29b 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/PipelineLayout.h +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/PipelineLayout.h @@ -57,6 +57,9 @@ namespace AZ /// Returns srgVisibility data const ShaderResourceGroupVisibility& GetSrgResourcesVisibility(uint32_t index) const; + /// Returns srgVisibility hash + const AZ::HashValue64 GetSrgResourcesVisibilityHash(uint32_t index) const; + /// Returns the root constant specific layout information uint32_t GetRootConstantsSize() const; uint32_t GetRootConstantsSlotIndex() const; @@ -84,6 +87,9 @@ namespace AZ /// Cache Visibility across all the resources within the SRG AZStd::fixed_vector m_srgResourcesVisibility; + /// Cache Visibility hash across all the resources within the SRG + AZStd::fixed_vector m_srgResourcesVisibilityHash; + uint32_t m_rootConstantSlotIndex = (uint32_t)-1; uint32_t m_rootConstantsSize = 0; }; From 0f90ccc0b4e78b57a07001a94f8ef219dac3fb7e Mon Sep 17 00:00:00 2001 From: antonmic Date: Fri, 4 Jun 2021 09:38:28 -0700 Subject: [PATCH 03/73] initial changes compiling --- .../DisplayMapperFullScreenPass.h | 2 +- .../Feature/DisplayMapper/DisplayMapperPass.h | 2 +- .../Atom/Feature/LuxCore/LuxCoreTexturePass.h | 2 +- .../Atom/Feature/LuxCore/RenderTexturePass.h | 2 +- .../CheckerboardColorResolvePass.cpp | 6 +- .../CheckerboardColorResolvePass.h | 2 +- .../Source/Checkerboard/CheckerboardPass.cpp | 4 +- .../Source/Checkerboard/CheckerboardPass.h | 2 +- .../CoreLights/CascadedShadowmapsPass.cpp | 8 +- .../CoreLights/CascadedShadowmapsPass.h | 2 +- .../DirectionalLightFeatureProcessor.cpp | 2 +- .../Source/CoreLights/LightCullingPass.cpp | 3 +- .../Code/Source/CoreLights/LightCullingPass.h | 3 +- .../Source/CoreLights/LightCullingRemap.cpp | 2 +- .../Source/CoreLights/LightCullingRemap.h | 2 +- .../LightCullingTilePreparePass.cpp | 25 ++--- .../CoreLights/LightCullingTilePreparePass.h | 3 +- .../CoreLights/ProjectedShadowmapsPass.cpp | 6 +- .../CoreLights/ProjectedShadowmapsPass.h | 2 +- .../Code/Source/CoreLights/ShadowmapPass.cpp | 4 +- .../Code/Source/CoreLights/ShadowmapPass.h | 2 +- .../DisplayMapperFullScreenPass.cpp | 2 +- .../DisplayMapper/DisplayMapperPass.cpp | 6 +- .../Common/Code/Source/ImGui/ImGuiPass.cpp | 4 +- .../Common/Code/Source/ImGui/ImGuiPass.h | 2 +- .../Source/LuxCore/LuxCoreTexturePass.cpp | 6 +- .../Code/Source/LuxCore/RenderTexturePass.cpp | 6 +- .../MorphTargets/MorphTargetComputePass.cpp | 2 +- .../MorphTargets/MorphTargetComputePass.h | 2 +- .../Source/PostProcessing/BloomBlurPass.cpp | 4 +- .../Source/PostProcessing/BloomBlurPass.h | 2 +- .../PostProcessing/BloomCompositePass.cpp | 4 +- .../PostProcessing/BloomCompositePass.h | 2 +- .../PostProcessing/BloomDownsamplePass.cpp | 4 +- .../PostProcessing/BloomDownsamplePass.h | 2 +- .../DepthOfFieldCopyFocusDepthToCpuPass.cpp | 2 +- .../DepthOfFieldCopyFocusDepthToCpuPass.h | 2 +- ...DepthOfFieldWriteFocusDepthFromGpuPass.cpp | 4 +- .../DepthOfFieldWriteFocusDepthFromGpuPass.h | 2 +- .../PostProcessing/EyeAdaptationPass.cpp | 2 +- .../Source/PostProcessing/EyeAdaptationPass.h | 2 +- .../LookModificationTransformPass.cpp | 4 +- .../LookModificationTransformPass.h | 2 +- .../LuminanceHistogramGeneratorPass.cpp | 2 +- .../LuminanceHistogramGeneratorPass.h | 2 +- .../Code/Source/PostProcessing/SsaoPasses.cpp | 4 +- .../Code/Source/PostProcessing/SsaoPasses.h | 2 +- .../RayTracingAccelerationStructurePass.cpp | 2 +- .../RayTracingAccelerationStructurePass.h | 2 +- .../ReflectionCopyFrameBufferPass.cpp | 4 +- .../ReflectionCopyFrameBufferPass.h | 2 +- .../ReflectionScreenSpaceBlurPass.cpp | 6 +- .../ReflectionScreenSpaceBlurPass.h | 2 +- .../ProjectedShadowFeatureProcessor.cpp | 2 +- .../Include/Atom/RPI.Public/Pass/CopyPass.h | 2 +- .../Atom/RPI.Public/Pass/MSAAResolvePass.h | 2 +- .../Include/Atom/RPI.Public/Pass/ParentPass.h | 5 +- .../Code/Include/Atom/RPI.Public/Pass/Pass.h | 50 +++++---- .../Atom/RPI.Public/Pass/PassDefines.h | 25 +++++ .../Include/Atom/RPI.Public/Pass/PassSystem.h | 21 ++-- .../RPI.Public/Pass/PassSystemInterface.h | 24 +++- .../Include/Atom/RPI.Public/Pass/RenderPass.h | 2 +- .../Pass/Specific/DownsampleMipChainPass.h | 2 +- .../Pass/Specific/EnvironmentCubeMapPass.h | 2 +- .../Pass/Specific/RenderToTexturePass.h | 2 +- .../RPI.Public/Pass/Specific/SelectorPass.h | 2 +- .../RPI.Public/Pass/Specific/SwapChainPass.h | 2 +- .../Code/Source/RPI.Public/Pass/CopyPass.cpp | 2 +- .../RPI.Public/Pass/MSAAResolvePass.cpp | 2 +- .../Source/RPI.Public/Pass/ParentPass.cpp | 25 +++-- .../RPI/Code/Source/RPI.Public/Pass/Pass.cpp | 105 +++++++++++------- .../Source/RPI.Public/Pass/PassSystem.cpp | 89 +++++++++++---- .../Source/RPI.Public/Pass/RenderPass.cpp | 2 +- .../Pass/Specific/DownsampleMipChainPass.cpp | 4 +- .../Pass/Specific/EnvironmentCubeMapPass.cpp | 6 +- .../Pass/Specific/RenderToTexturePass.cpp | 6 +- .../RPI.Public/Pass/Specific/SelectorPass.cpp | 6 +- .../Pass/Specific/SwapChainPass.cpp | 8 +- .../Code/Source/RPI.Public/RenderPipeline.cpp | 3 +- Gems/Atom/RPI/Code/Tests/Pass/PassTests.cpp | 14 +-- 80 files changed, 360 insertions(+), 237 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperFullScreenPass.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperFullScreenPass.h index 94e52d41b0..23c4cd1a0a 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperFullScreenPass.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperFullScreenPass.h @@ -42,7 +42,7 @@ namespace AZ void SetInputReferenceAttachmentName(const Name& attachmentName); // Pass behavior overrides - virtual void BuildAttachmentsInternal() override; + virtual void BuildInternal() override; protected: explicit DisplayMapperFullScreenPass(const RPI::PassDescriptor& descriptor); diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperPass.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperPass.h index 67d9eae9ae..15ada4dd94 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperPass.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperPass.h @@ -76,7 +76,7 @@ namespace AZ DisplayMapperPass(const RPI::PassDescriptor& descriptor); // Pass behavior overrides - void BuildAttachmentsInternal() final; + void BuildInternal() final; void FrameBeginInternal(FramePrepareParams params) final; void FrameEndInternal() final; void CreateChildPassesInternal() final; diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/LuxCore/LuxCoreTexturePass.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/LuxCore/LuxCoreTexturePass.h index 23e9c220b2..2ad2af3efd 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/LuxCore/LuxCoreTexturePass.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/LuxCore/LuxCoreTexturePass.h @@ -42,7 +42,7 @@ namespace AZ protected: // Pass behavior overrides void CreateChildPassesInternal() final; - void BuildAttachmentsInternal() final; + void BuildInternal() final; void FrameBeginInternal(FramePrepareParams params) final; private: diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/LuxCore/RenderTexturePass.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/LuxCore/RenderTexturePass.h index 5ae5008a92..cd148d3452 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/LuxCore/RenderTexturePass.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/LuxCore/RenderTexturePass.h @@ -46,7 +46,7 @@ namespace AZ private: - void BuildAttachmentsInternal() override; + void BuildInternal() override; void FrameBeginInternal(FramePrepareParams params) override; void UpdataAttachment(); diff --git a/Gems/Atom/Feature/Common/Code/Source/Checkerboard/CheckerboardColorResolvePass.cpp b/Gems/Atom/Feature/Common/Code/Source/Checkerboard/CheckerboardColorResolvePass.cpp index 3ebb6b370c..a6c440cf39 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Checkerboard/CheckerboardColorResolvePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Checkerboard/CheckerboardColorResolvePass.cpp @@ -60,7 +60,7 @@ namespace AZ Base::FrameBeginInternal(params); } - void CheckerboardColorResolvePass::BuildAttachmentsInternal() + void CheckerboardColorResolvePass::BuildInternal() { // For each bound attachments they are the inputs from current frame. // We use them to get their owner CheckerboardPass then find the render targets from last frame @@ -99,7 +99,7 @@ namespace AZ // reset frame offset to 0 since attachments are rebuilt m_frameOffset = 0; - Base::BuildAttachmentsInternal(); + Base::BuildInternal(); } void CheckerboardColorResolvePass::CompileResources(const RHI::FrameGraphCompileContext& context) @@ -135,7 +135,7 @@ namespace AZ void CheckerboardColorResolvePass::FrameEndInternal() { // For the input slots for current frame, they always get updated when CheckerboardPass updates the render targets - // But for the input slots for previous frame, we need to manually update them since they were manually attached in BuildAttachmentsInternal() + // But for the input slots for previous frame, we need to manually update them since they were manually attached in BuildInternal() // // When pass attachment was built, CheckerboardPass creates two resources for each render target. // For example, diffuse_0 and diffuse_1 which diffuse_0 is for even frame and diffuse_1 is for odd frame. diff --git a/Gems/Atom/Feature/Common/Code/Source/Checkerboard/CheckerboardColorResolvePass.h b/Gems/Atom/Feature/Common/Code/Source/Checkerboard/CheckerboardColorResolvePass.h index 8cb15d5f49..93930e2bbc 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Checkerboard/CheckerboardColorResolvePass.h +++ b/Gems/Atom/Feature/Common/Code/Source/Checkerboard/CheckerboardColorResolvePass.h @@ -52,7 +52,7 @@ namespace AZ protected: // Pass overrides... void FrameBeginInternal(FramePrepareParams params) override; - void BuildAttachmentsInternal() override; + void BuildInternal() override; void FrameEndInternal() override; // Scope producer functions... diff --git a/Gems/Atom/Feature/Common/Code/Source/Checkerboard/CheckerboardPass.cpp b/Gems/Atom/Feature/Common/Code/Source/Checkerboard/CheckerboardPass.cpp index 09c69dfe18..a781c460f5 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Checkerboard/CheckerboardPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Checkerboard/CheckerboardPass.cpp @@ -50,7 +50,7 @@ namespace AZ Base::FrameBeginInternal(params); } - void CheckerboardPass::BuildAttachmentsInternal() + void CheckerboardPass::BuildInternal() { Data::Instance pool = RPI::ImageSystemInterface::Get()->GetSystemAttachmentPool(); @@ -101,7 +101,7 @@ namespace AZ // reset frame offset to 0 since attachments are rebuilt m_frameOffset = 0; - Base::BuildAttachmentsInternal(); + Base::BuildInternal(); } diff --git a/Gems/Atom/Feature/Common/Code/Source/Checkerboard/CheckerboardPass.h b/Gems/Atom/Feature/Common/Code/Source/Checkerboard/CheckerboardPass.h index 3b905cc3db..02429bb837 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Checkerboard/CheckerboardPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/Checkerboard/CheckerboardPass.h @@ -40,7 +40,7 @@ namespace AZ protected: // Pass overrides... void FrameBeginInternal(FramePrepareParams params); - void BuildAttachmentsInternal() override; + void BuildInternal() override; void FrameEndInternal() override; private: diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/CascadedShadowmapsPass.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/CascadedShadowmapsPass.cpp index d83201533c..4c7e69f2ae 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/CascadedShadowmapsPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/CascadedShadowmapsPass.cpp @@ -100,7 +100,7 @@ namespace AZ m_arraySize = arraySize; m_updateChildren = true; - QueueForBuildAttachments(); + QueueForBuild(); m_atlas.Initialize(); for (size_t cascadeIndex = 0; cascadeIndex < m_arraySize; ++cascadeIndex) @@ -149,7 +149,7 @@ namespace AZ return m_atlas; } - void CascadedShadowmapsPass::BuildAttachmentsInternal() + void CascadedShadowmapsPass::BuildInternal() { UpdateChildren(); @@ -159,7 +159,7 @@ namespace AZ } UpdateShadowmapImageSize(); - Base::BuildAttachmentsInternal(); + Base::BuildInternal(); } void CascadedShadowmapsPass::GetPipelineViewTags(RPI::SortedPipelineViewTags& outTags) const @@ -215,7 +215,7 @@ namespace AZ AZ_RPI_PASS_WARNING(child, "CascadedShadowmapsPass child Pass creation failed for %d", cascadeIndex); if (child) { - child->QueueForBuildAttachments(); + child->QueueForBuild(); AddChild(child); } } diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/CascadedShadowmapsPass.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/CascadedShadowmapsPass.h index aa95e0af44..772be9466d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/CascadedShadowmapsPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/CascadedShadowmapsPass.h @@ -53,7 +53,7 @@ namespace AZ explicit CascadedShadowmapsPass(const RPI::PassDescriptor& descriptor); // RPI::Pass overrides... - void BuildAttachmentsInternal() override; + void BuildInternal() override; void GetPipelineViewTags(RPI::SortedPipelineViewTags& outTags) const override; void GetViewDrawListInfo(RHI::DrawListMask& outDrawListMask, RPI::PassesByDrawList& outPassesByDrawList, const RPI::PipelineViewTag& viewTag) const override; diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp index 9b40097716..cdbe431949 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp @@ -1106,7 +1106,7 @@ namespace AZ { for (EsmShadowmapsPass* pass : it.second) { - pass->QueueForBuildAttachments(); + pass->QueueForBuild(); } } } diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingPass.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingPass.cpp index 987ed299b3..88a063b499 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingPass.cpp @@ -163,7 +163,6 @@ namespace AZ void LightCullingPass::ResetInternal() { - m_initialized = false; m_tileDataIndex = -1; m_constantDataIndex.Reset(); @@ -260,7 +259,7 @@ namespace AZ return gridPixelSize; } - void LightCullingPass::BuildAttachmentsInternal() + void LightCullingPass::BuildInternal() { m_tileDataIndex = FindInputBinding(AZ::Name("TileLightData")); CreateLightList(); diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingPass.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingPass.h index d8699ea0c7..8080379716 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingPass.h @@ -50,7 +50,7 @@ namespace AZ // Pass behavior overrides... void ResetInternal()override; - void BuildAttachmentsInternal() override; + void BuildInternal() override; // Scope producer functions... void CompileResources(const RHI::FrameGraphCompileContext& context) override; @@ -96,7 +96,6 @@ namespace AZ AZ::RHI::ShaderInputNameIndex m_constantDataIndex = "m_constantData"; - bool m_initialized = false; Data::Instance m_lightList; uint32_t m_tileDataIndex = -1; diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingRemap.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingRemap.cpp index 42882cec6e..a12ba48751 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingRemap.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingRemap.cpp @@ -108,7 +108,7 @@ namespace AZ return -1; } - void LightCullingRemap::BuildAttachmentsInternal() + void LightCullingRemap::BuildInternal() { m_tileDataIndex = FindInputOutputBinding(AZ::Name("TileLightData")); m_tileDim = GetTileDataBufferResolution(); diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingRemap.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingRemap.h index 0738acd459..6d60f93a64 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingRemap.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingRemap.h @@ -55,7 +55,7 @@ namespace AZ // Pass behavior overrides... void ResetInternal()override; - void BuildAttachmentsInternal() override; + void BuildInternal() override; // RHI::ScopeProducer overrides... void SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) override; diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.cpp index 816ef25bc6..c144525cec 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.cpp @@ -167,37 +167,36 @@ namespace AZ AZ_Assert(setOk, "LightCullingTilePreparePass::SetConstantData() - could not set constant data"); } - void LightCullingTilePreparePass::BuildAttachmentsInternal() + void LightCullingTilePreparePass::BuildInternal() { ChooseShaderVariant(); } - void LightCullingTilePreparePass::OnShaderReinitialized(const AZ::RPI::Shader&) + void LightCullingTilePreparePass::OnShaderReloaded() { LoadShader(); - if (!m_flags.m_queuedForBuildAttachment && !m_flags.m_isBuildingAttachments) + AZ_Assert(GetPassState() != RPI::PassState::Rendering, "LightCullingTilePreparePass: Trying to reload shader during rendering"); + if (GetPassState() == RPI::PassState::Initialized) { ChooseShaderVariant(); } } + + void LightCullingTilePreparePass::OnShaderReinitialized(const AZ::RPI::Shader&) + { + OnShaderReloaded(); + } + void LightCullingTilePreparePass::OnShaderAssetReinitialized(const Data::Asset&) { - LoadShader(); - if (!m_flags.m_queuedForBuildAttachment && !m_flags.m_isBuildingAttachments) - { - ChooseShaderVariant(); - } + OnShaderReloaded(); } void LightCullingTilePreparePass::OnShaderVariantReinitialized( const AZ::RPI::Shader&, const AZ::RPI::ShaderVariantId&, AZ::RPI::ShaderVariantStableId) { - LoadShader(); - if (!m_flags.m_queuedForBuildAttachment && !m_flags.m_isBuildingAttachments) - { - ChooseShaderVariant(); - } + OnShaderReloaded(); } } // namespace Render diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.h index efba105912..0febb66e3d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.h @@ -50,7 +50,7 @@ namespace AZ LightCullingTilePreparePass(const RPI::PassDescriptor& descriptor); // Pass behavior overrides... - void BuildAttachmentsInternal() override; + void BuildInternal() override; /////////////////////////////////////////////////////////////////// // ShaderReloadNotificationBus overrides... @@ -73,6 +73,7 @@ namespace AZ const AZ::RPI::ShaderVariant& CreateShaderVariant(); void CreatePipelineStateFromShaderVariant(const RPI::ShaderVariant& shaderVariant); void SetConstantData(); + void OnShaderReloaded(); AZ::RHI::ShaderInputNameIndex m_constantDataIndex = "m_constantData"; diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/ProjectedShadowmapsPass.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/ProjectedShadowmapsPass.cpp index d77419fe8f..87cacbb345 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/ProjectedShadowmapsPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/ProjectedShadowmapsPass.cpp @@ -73,7 +73,7 @@ namespace AZ { m_sizes = sizes; m_updateChildren = true; - QueueForBuildAttachments(); + QueueForBuild(); m_atlas.Initialize(); for (const auto& it : m_sizes) @@ -156,7 +156,7 @@ namespace AZ return m_atlas; } - void ProjectedShadowmapsPass::BuildAttachmentsInternal() + void ProjectedShadowmapsPass::BuildInternal() { UpdateChildren(); @@ -177,7 +177,7 @@ namespace AZ imageDescriptor.m_size = RHI::Size(shadowmapWidth, shadowmapWidth, 1); imageDescriptor.m_arraySize = m_atlas.GetArraySliceCount(); - Base::BuildAttachmentsInternal(); + Base::BuildInternal(); } void ProjectedShadowmapsPass::GetPipelineViewTags(RPI::SortedPipelineViewTags& outTags) const diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/ProjectedShadowmapsPass.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/ProjectedShadowmapsPass.h index 63640d22c6..f1963cc885 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/ProjectedShadowmapsPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/ProjectedShadowmapsPass.h @@ -71,7 +71,7 @@ namespace AZ explicit ProjectedShadowmapsPass(const RPI::PassDescriptor& descriptor); // RPI::Pass overrides... - void BuildAttachmentsInternal() override; + void BuildInternal() override; void GetPipelineViewTags(RPI::SortedPipelineViewTags& outTags) const override; void GetViewDrawListInfo(RHI::DrawListMask& outDrawListMask, RPI::PassesByDrawList& outPassesByDrawList, const RPI::PipelineViewTag& viewTag) const override; diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/ShadowmapPass.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/ShadowmapPass.cpp index 087a73a94d..d31947da5a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/ShadowmapPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/ShadowmapPass.cpp @@ -107,7 +107,7 @@ namespace AZ m_scissorState = scissor; } - void ShadowmapPass::BuildAttachmentsInternal() + void ShadowmapPass::BuildInternal() { RPI::Ptr parentPass = GetParent(); if (!parentPass) @@ -135,7 +135,7 @@ namespace AZ action.m_loadAction = m_clearEnabled ? RHI::AttachmentLoadAction::Clear : RHI::AttachmentLoadAction::DontCare; binding.m_unifiedScopeDesc = RHI::UnifiedScopeAttachmentDescriptor(attachmentId, imageViewDescriptor, action); - Base::BuildAttachmentsInternal(); + Base::BuildInternal(); } } // namespace Render diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/ShadowmapPass.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/ShadowmapPass.h index 9c308dc4df..2814761a69 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/ShadowmapPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/ShadowmapPass.h @@ -58,7 +58,7 @@ namespace AZ explicit ShadowmapPass(const RPI::PassDescriptor& descriptor); // RHI::Pass overrides... - void BuildAttachmentsInternal() override; + void BuildInternal() override; uint16_t m_arraySlice = 0; bool m_clearEnabled = true; diff --git a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperFullScreenPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperFullScreenPass.cpp index ba83fabed3..096179d5b6 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperFullScreenPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperFullScreenPass.cpp @@ -34,7 +34,7 @@ namespace AZ { } - void DisplayMapperFullScreenPass::BuildAttachmentsInternal() + void DisplayMapperFullScreenPass::BuildInternal() { RPI::PassConnection inConnection; inConnection.m_localSlot = InputAttachmentName; diff --git a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp index 8ae790e12c..be3e05163a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp @@ -46,8 +46,6 @@ namespace AZ DisplayMapperPass::DisplayMapperPass(const RPI::PassDescriptor& descriptor) : RPI::ParentPass(descriptor) { - m_flags.m_alreadyCreated = false; - AzFramework::NativeWindowHandle windowHandle = nullptr; AzFramework::WindowSystemRequestBus::BroadcastResult( windowHandle, @@ -137,7 +135,7 @@ namespace AZ } } - void DisplayMapperPass::BuildAttachmentsInternal() + void DisplayMapperPass::BuildInternal() { const Name outputName = Name{ "Output" }; Name inputPass = Name{ "Parent" }; @@ -187,7 +185,7 @@ namespace AZ m_swapChainAttachmentBinding = FindAttachmentBinding(Name("SwapChainOutput")); - ParentPass::BuildAttachmentsInternal(); + ParentPass::BuildInternal(); } void DisplayMapperPass::FrameBeginInternal(FramePrepareParams params) diff --git a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.cpp b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.cpp index a29354f723..fe5d9a16fe 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.cpp @@ -519,13 +519,13 @@ namespace AZ io.Fonts->TexID = reinterpret_cast(m_fontAtlas.get()); } - void ImGuiPass::OnBuildAttachmentsFinishedInternal() + void ImGuiPass::OnBuildFinishedInternal() { // Set output format and finalize pipeline state m_pipelineState->SetOutputFromPass(this); m_pipelineState->Finalize(); - Base::OnBuildAttachmentsFinishedInternal(); + Base::OnBuildFinishedInternal(); } void ImGuiPass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) diff --git a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.h b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.h index c8be0d7ee6..30449820bb 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.h @@ -94,7 +94,7 @@ namespace AZ explicit ImGuiPass(const RPI::PassDescriptor& descriptor); // Pass Behaviour Overrides... - void OnBuildAttachmentsFinishedInternal() override; + void OnBuildFinishedInternal() override; void FrameBeginInternal(FramePrepareParams params) override; // Scope producer functions diff --git a/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreTexturePass.cpp b/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreTexturePass.cpp index 9a921205ab..3c7233e747 100644 --- a/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreTexturePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreTexturePass.cpp @@ -28,8 +28,6 @@ namespace AZ LuxCoreTexturePass::LuxCoreTexturePass(const RPI::PassDescriptor& descriptor) : ParentPass(descriptor) { - m_flags.m_alreadyCreated = false; - RPI::PassSystemInterface* passSystem = RPI::PassSystemInterface::Get(); // Create render target pass @@ -61,9 +59,9 @@ namespace AZ AddChild(m_renderTargetPass); } - void LuxCoreTexturePass::BuildAttachmentsInternal() + void LuxCoreTexturePass::BuildInternal() { - ParentPass::BuildAttachmentsInternal(); + ParentPass::BuildInternal(); } void LuxCoreTexturePass::FrameBeginInternal(FramePrepareParams params) diff --git a/Gems/Atom/Feature/Common/Code/Source/LuxCore/RenderTexturePass.cpp b/Gems/Atom/Feature/Common/Code/Source/LuxCore/RenderTexturePass.cpp index 0782e12278..aa991e270a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/LuxCore/RenderTexturePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/LuxCore/RenderTexturePass.cpp @@ -38,13 +38,13 @@ namespace AZ m_attachmentSize = image->GetRHIImage()->GetDescriptor().m_size; m_attachmentFormat = format; m_shaderResourceGroup->SetImage(m_textureIndex, image); - QueueForBuildAttachments(); + QueueForBuild(); } - void RenderTexturePass::BuildAttachmentsInternal() + void RenderTexturePass::BuildInternal() { UpdataAttachment(); - FullscreenTrianglePass::BuildAttachmentsInternal(); + FullscreenTrianglePass::BuildInternal(); } void RenderTexturePass::FrameBeginInternal(FramePrepareParams params) diff --git a/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetComputePass.cpp b/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetComputePass.cpp index 1bb537ecef..42acd5c447 100644 --- a/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetComputePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetComputePass.cpp @@ -44,7 +44,7 @@ namespace AZ m_skinnedMeshFeatureProcessor = skinnedMeshFeatureProcessor; } - void MorphTargetComputePass::BuildAttachmentsInternal() + void MorphTargetComputePass::BuildInternal() { // The same buffer that skinning writes to is used to manage the computed vertex deltas that are passed from the // morph target pass to the skinning pass. This simplifies things by only requiring one class to manage the memory diff --git a/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetComputePass.h b/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetComputePass.h index 61fa485fbc..d346edd908 100644 --- a/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetComputePass.h +++ b/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetComputePass.h @@ -37,7 +37,7 @@ namespace AZ void SetFeatureProcessor(SkinnedMeshFeatureProcessor* m_skinnedMeshFeatureProcessor); private: - void BuildAttachmentsInternal() override; + void BuildInternal() override; void BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context) override; SkinnedMeshFeatureProcessor* m_skinnedMeshFeatureProcessor = nullptr; diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BloomBlurPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BloomBlurPass.cpp index 1427adeb08..af95a76718 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BloomBlurPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BloomBlurPass.cpp @@ -252,10 +252,10 @@ namespace AZ } } - void BloomBlurPass::BuildAttachmentsInternal() + void BloomBlurPass::BuildInternal() { BuildChildPasses(); - ParentPass::BuildAttachmentsInternal(); + ParentPass::BuildInternal(); } void BloomBlurPass::FrameBeginInternal(FramePrepareParams params) diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BloomBlurPass.h b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BloomBlurPass.h index e87d831382..4c65368506 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BloomBlurPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BloomBlurPass.h @@ -47,7 +47,7 @@ namespace AZ BloomBlurPass(const RPI::PassDescriptor& descriptor); // Pass behaviour overrides... - void BuildAttachmentsInternal() override; + void BuildInternal() override; void FrameBeginInternal(FramePrepareParams params) override; void GetInputInfo(); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BloomCompositePass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BloomCompositePass.cpp index fbb020cbf3..810353aab1 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BloomCompositePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BloomCompositePass.cpp @@ -56,10 +56,10 @@ namespace AZ m_passData = *passData; } - void BloomCompositePass::BuildAttachmentsInternal() + void BloomCompositePass::BuildInternal() { BuildChildPasses(); - ParentPass::BuildAttachmentsInternal(); + ParentPass::BuildInternal(); } void BloomCompositePass::FrameBeginInternal(FramePrepareParams params) diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BloomCompositePass.h b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BloomCompositePass.h index 86d897ae7d..a19947e1d0 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BloomCompositePass.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BloomCompositePass.h @@ -44,7 +44,7 @@ namespace AZ BloomCompositePass(const RPI::PassDescriptor& descriptor); // Pass behaviour overrides... - void BuildAttachmentsInternal() override; + void BuildInternal() override; void FrameBeginInternal(FramePrepareParams params) override; void GetAttachmentInfo(); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BloomDownsamplePass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BloomDownsamplePass.cpp index 647177a1ce..63779beb16 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BloomDownsamplePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BloomDownsamplePass.cpp @@ -74,10 +74,10 @@ namespace AZ AddAttachmentBinding(outBinding); } - ComputePass::BuildAttachmentsInternal(); + ComputePass::BuildInternal(); } - void BloomDownsamplePass::BuildAttachmentsInternal() + void BloomDownsamplePass::BuildInternal() { BuildOutAttachmentBinding(); } diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BloomDownsamplePass.h b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BloomDownsamplePass.h index 824f703417..3eb0ac8740 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BloomDownsamplePass.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BloomDownsamplePass.h @@ -37,7 +37,7 @@ namespace AZ BloomDownsamplePass(const RPI::PassDescriptor& descriptor); // Pass Behaviour Overrides... - void BuildAttachmentsInternal() override; + void BuildInternal() override; void FrameBeginInternal(FramePrepareParams params) override; void BuildOutAttachmentBinding(); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldCopyFocusDepthToCpuPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldCopyFocusDepthToCpuPass.cpp index d64bba1957..00d5ad93c3 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldCopyFocusDepthToCpuPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldCopyFocusDepthToCpuPass.cpp @@ -52,7 +52,7 @@ namespace AZ return depth; } - void DepthOfFieldCopyFocusDepthToCpuPass::BuildAttachmentsInternal() + void DepthOfFieldCopyFocusDepthToCpuPass::BuildInternal() { SetScopeId(RHI::ScopeId(GetPathName())); } diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldCopyFocusDepthToCpuPass.h b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldCopyFocusDepthToCpuPass.h index 64301b6e0c..7e8d041e96 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldCopyFocusDepthToCpuPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldCopyFocusDepthToCpuPass.h @@ -48,7 +48,7 @@ namespace AZ void BuildCommandList(const RHI::FrameGraphExecuteContext& context) override; // Pass overrides - void BuildAttachmentsInternal() override; + void BuildInternal() override; void FrameBeginInternal(FramePrepareParams params) override; RPI::Ptr m_bufferRef; diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldWriteFocusDepthFromGpuPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldWriteFocusDepthFromGpuPass.cpp index e7ac891198..4aaf936426 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldWriteFocusDepthFromGpuPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldWriteFocusDepthFromGpuPass.cpp @@ -62,9 +62,9 @@ namespace AZ m_bufferRef = bufferRef; } - void DepthOfFieldWriteFocusDepthFromGpuPass::BuildAttachmentsInternal() + void DepthOfFieldWriteFocusDepthFromGpuPass::BuildInternal() { - AZ_Assert(m_bufferRef != nullptr, "%s has a null buffer when calling BuildAttachmentsInternal.", GetPathName().GetCStr()); + AZ_Assert(m_bufferRef != nullptr, "%s has a null buffer when calling BuildInternal.", GetPathName().GetCStr()); AttachBufferToSlot(Name("DofDepthInputOutput"), m_bufferRef); } diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldWriteFocusDepthFromGpuPass.h b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldWriteFocusDepthFromGpuPass.h index 592ab64c01..881ef9df94 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldWriteFocusDepthFromGpuPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldWriteFocusDepthFromGpuPass.h @@ -51,7 +51,7 @@ namespace AZ void CompileResources(const RHI::FrameGraphCompileContext& context) override; // Pass overrides - void BuildAttachmentsInternal() override; + void BuildInternal() override; }; } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.cpp index e7d4c47f02..879abf6418 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.cpp @@ -62,7 +62,7 @@ namespace AZ m_buffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); } - void EyeAdaptationPass::BuildAttachmentsInternal() + void EyeAdaptationPass::BuildInternal() { if (!m_buffer) { diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.h b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.h index cef168a122..d53569a9f9 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.h @@ -58,7 +58,7 @@ namespace AZ float m_exposureValue = 1.0f; }; - void BuildAttachmentsInternal() override; + void BuildInternal() override; void FrameBeginInternal(FramePrepareParams params) override; diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationTransformPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationTransformPass.cpp index 98c842042b..9f792370fc 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationTransformPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationTransformPass.cpp @@ -36,10 +36,10 @@ namespace AZ &AzFramework::WindowSystemRequestBus::Events::GetDefaultWindowHandle); } - void LookModificationPass::BuildAttachmentsInternal() + void LookModificationPass::BuildInternal() { m_swapChainAttachmentBinding = FindAttachmentBinding(Name("SwapChainOutput")); - ParentPass::BuildAttachmentsInternal(); + ParentPass::BuildInternal(); } void LookModificationPass::FrameBeginInternal([[maybe_unused]] FramePrepareParams params) diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationTransformPass.h b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationTransformPass.h index 5102015e82..8203530918 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationTransformPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationTransformPass.h @@ -52,7 +52,7 @@ namespace AZ //! Pass overrides ... void FrameBeginInternal(FramePrepareParams params) override; - void BuildAttachmentsInternal() override; + void BuildInternal() override; private: const RPI::PassAttachmentBinding* m_swapChainAttachmentBinding = nullptr; diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LuminanceHistogramGeneratorPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LuminanceHistogramGeneratorPass.cpp index 758c21bc4e..2fe8b01089 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LuminanceHistogramGeneratorPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LuminanceHistogramGeneratorPass.cpp @@ -86,7 +86,7 @@ namespace AZ return colorBuffer->m_descriptor.m_image.m_size; } - void LuminanceHistogramGeneratorPass::BuildAttachmentsInternal() + void LuminanceHistogramGeneratorPass::BuildInternal() { CreateHistogramBuffer(); AttachHistogramBuffer(); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LuminanceHistogramGeneratorPass.h b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LuminanceHistogramGeneratorPass.h index ee8a10fe16..9691daab6f 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LuminanceHistogramGeneratorPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LuminanceHistogramGeneratorPass.h @@ -42,7 +42,7 @@ namespace AZ protected: LuminanceHistogramGeneratorPass(const RPI::PassDescriptor& descriptor); - virtual void BuildAttachmentsInternal() override; + virtual void BuildInternal() override; void CreateHistogramBuffer(); void AttachHistogramBuffer(); AZ::RHI::Size GetColorBufferResolution(); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SsaoPasses.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SsaoPasses.cpp index 68472115ce..1aa16a4417 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SsaoPasses.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SsaoPasses.cpp @@ -41,9 +41,9 @@ namespace AZ return ParentPass::IsEnabled(); } - void SsaoParentPass::OnBuildAttachmentsFinishedInternal() + void SsaoParentPass::OnBuildFinishedInternal() { - ParentPass::OnBuildAttachmentsFinishedInternal(); + ParentPass::OnBuildFinishedInternal(); m_blurParentPass = FindChildPass(Name("SsaoBlur"))->AsParent(); AZ_Assert(m_blurParentPass, "[SsaoParentPass] Could not retrieve parent blur pass."); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SsaoPasses.h b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SsaoPasses.h index 9abd04e306..20aa554414 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SsaoPasses.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SsaoPasses.h @@ -36,7 +36,7 @@ namespace AZ protected: // Behavior functions override... - void OnBuildAttachmentsFinishedInternal() override; + void OnBuildFinishedInternal() override; void FrameBeginInternal(FramePrepareParams params) override; private: diff --git a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingAccelerationStructurePass.cpp b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingAccelerationStructurePass.cpp index 92cd41b4e8..f1fcd2de35 100644 --- a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingAccelerationStructurePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingAccelerationStructurePass.cpp @@ -42,7 +42,7 @@ namespace AZ } } - void RayTracingAccelerationStructurePass::BuildAttachmentsInternal() + void RayTracingAccelerationStructurePass::BuildInternal() { SetScopeId(RHI::ScopeId(GetPathName())); } diff --git a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingAccelerationStructurePass.h b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingAccelerationStructurePass.h index 6d90d752e3..127669301e 100644 --- a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingAccelerationStructurePass.h +++ b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingAccelerationStructurePass.h @@ -44,7 +44,7 @@ namespace AZ void BuildCommandList(const RHI::FrameGraphExecuteContext& context) override; // Pass overrides - void BuildAttachmentsInternal() override; + void BuildInternal() override; void FrameBeginInternal(FramePrepareParams params) override; // buffer view descriptor for the TLAS diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.cpp index 5137b66bf9..9a9064bdf7 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.cpp @@ -30,7 +30,7 @@ namespace AZ { } - void ReflectionCopyFrameBufferPass::BuildAttachmentsInternal() + void ReflectionCopyFrameBufferPass::BuildInternal() { RPI::PassHierarchyFilter passFilter(AZ::Name("ReflectionScreenSpaceBlurPass")); const AZStd::vector& passes = RPI::PassSystemInterface::Get()->FindPasses(passFilter); @@ -43,7 +43,7 @@ namespace AZ AttachImageToSlot(outputBinding.m_name, frameBufferAttachment); } - FullscreenTrianglePass::BuildAttachmentsInternal(); + FullscreenTrianglePass::BuildInternal(); } } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.h b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.h index 2a2fecea40..f0b8c80d72 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.h @@ -37,7 +37,7 @@ namespace AZ explicit ReflectionCopyFrameBufferPass(const RPI::PassDescriptor& descriptor); // Pass Overrides... - void BuildAttachmentsInternal() override; + void BuildInternal() override; }; } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp index 883686ac5b..680d117b98 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp @@ -113,7 +113,7 @@ namespace AZ } } - void ReflectionScreenSpaceBlurPass::BuildAttachmentsInternal() + void ReflectionScreenSpaceBlurPass::BuildInternal() { RemoveChildren(); @@ -166,9 +166,9 @@ namespace AZ // create child passes, one vertical and one horizontal blur per mip level CreateChildPasses(mipLevels - 1); - // call ParentPass::BuildAttachmentsInternal() first to configure the slots and auto-add the empty bindings, + // call ParentPass::BuildInternal() first to configure the slots and auto-add the empty bindings, // then we will assign attachments to the bindings - ParentPass::BuildAttachmentsInternal(); + ParentPass::BuildInternal(); // setup attachment bindings on vertical blur child passes uint32_t attachmentIndex = 0; diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.h b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.h index 53f4026aef..f344fc8e9b 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.h @@ -44,7 +44,7 @@ namespace AZ // Pass Overrides... void ResetInternal() override; - void BuildAttachmentsInternal() override; + void BuildInternal() override; AZStd::vector> m_verticalBlurChildPasses; AZStd::vector> m_horizontalBlurChildPasses; diff --git a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp index 216a126953..8484fdddc2 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp @@ -526,7 +526,7 @@ namespace AZ::Render for (EsmShadowmapsPass* esmPass : m_esmShadowmapsPasses) { - esmPass->QueueForBuildAttachments(); + esmPass->QueueForBuild(); } for (ProjectedShadowmapsPass* shadowPass : m_projectedShadowmapsPasses) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/CopyPass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/CopyPass.h index ede14564cd..fd5cdabc83 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/CopyPass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/CopyPass.h @@ -49,7 +49,7 @@ namespace AZ void CopyImageToBuffer(const RHI::FrameGraphCompileContext& context); // Pass behavior overrides - void BuildAttachmentsInternal() override; + void BuildInternal() override; // Scope producer functions... void SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) override; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/MSAAResolvePass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/MSAAResolvePass.h index 91ae1536c3..71776982b3 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/MSAAResolvePass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/MSAAResolvePass.h @@ -40,7 +40,7 @@ namespace AZ MSAAResolvePass(const PassDescriptor& descriptor); // Pass behavior overrides... - void BuildAttachmentsInternal() override; + void BuildInternal() override; void FrameBeginInternal(FramePrepareParams params) override; private: diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h index b4f63a7099..0e1e12e620 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h @@ -109,8 +109,9 @@ namespace AZ // --- Pass Behaviour Overrides --- void ResetInternal() override; - void BuildAttachmentsInternal() override; - void OnBuildAttachmentsFinishedInternal() override; + void BuildInternal() override; + void OnBuildFinishedInternal() override; + void InitializeInternal() override; void FrameBeginInternal(FramePrepareParams params) override; void FrameEndInternal() override; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h index 1cba71ae7e..ee7f850d27 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h @@ -80,7 +80,7 @@ namespace AZ //! ending with 'Internal' to define the behavior of your passes. These virtual are recursively //! called in Preorder order throughout the pass tree. Only FramePrepare and FrameEnd are //! guaranteed to be called per frame. The other override-able functions are called as needed - //! when scheduled with the PassSystem. See QueueForBuildAttachments and QueueForRemoval. + //! when scheduled with the PassSystem. See QueueForBuild and QueueForRemoval. //! //! Passes are created by the PassFactory. They can be created using either Pass Name, //! a PassTemplate, or a PassRequest. To register your pass class with the PassFactory, @@ -153,11 +153,14 @@ namespace AZ // --- Utility functions --- - //! Queues the pass to have BuildAttachments() called by the PassSystem on frame update - void QueueForBuildAttachments(); + //! Queues the pass to have Build() called by the PassSystem on frame update + void QueueForBuild(); //! Queues the pass to have RemoveFromParent() called by the PassSystem on frame update - void QueueForRemoval(bool needsDeletion = false); + void QueueForRemoval(); + + //! Queues the pass to have Initialize() called by the PassSystem on frame update + void QueueForInitialization(); //! Adds an attachment binding to the list of this Pass' attachment bindings void AddAttachmentBinding(PassAttachmentBinding attachmentBinding); @@ -173,8 +176,8 @@ namespace AZ //! Attach an external buffer resource as attachment to specified slot //! The buffer will be added as a pass attachment then attach to the pass slot - //! Note: the pass attachment and binding will be removed after the general BuildAttachments call. - //! you can add this call in pass' BuildAttachmentsInternal so it will be added whenever attachments get rebuilt + //! Note: the pass attachment and binding will be removed after the general Build call. + //! you can add this call in pass' BuildInternal so it will be added whenever attachments get rebuilt void AttachBufferToSlot(AZStd::string_view slot, Data::Instance buffer); void AttachBufferToSlot(const Name& slot, Data::Instance buffer); void AttachImageToSlot(const Name& slot, Data::Instance image); @@ -256,6 +259,8 @@ namespace AZ //! Returns pointer to the parent pass ParentPass* GetParent() const; + PassState GetPassState() const; + protected: explicit Pass(const PassDescriptor& descriptor); @@ -309,18 +314,23 @@ namespace AZ // customize it's behavior, hence why these functions are called the pass behavior functions. // Resets everything in the pass (like Attachments). - // Called from PassSystem when pass is QueueForBuildAttachments. + // Called from PassSystem when pass is QueueForBuild. void Reset(); virtual void ResetInternal() { } // Builds and sets up any attachments and input/output connections the pass needs. - // Called from PassSystem when pass is QueueForBuildAttachments. - void BuildAttachments(); - virtual void BuildAttachmentsInternal() { } + // Called from PassSystem when pass is QueueForBuild. + void Build(); + virtual void BuildInternal() { } // Called after the pass build phase has finished. Allows passes to reset build flags. - void OnBuildAttachmentsFinished(); - virtual void OnBuildAttachmentsFinishedInternal() { }; + void OnBuildFinished(); + virtual void OnBuildFinishedInternal() { }; + + // Allows for additional pass initialization between building and rendering + // Can be queued independently of Build so as to only invoke Initialize without Build + void Initialize(); + virtual void InitializeInternal() { }; // The Pass's 'Render' function. Called every frame, here the pass sets up it's rendering logic with // the FrameGraphBuilder. This is where your derived pass needs to call ImportScopeProducer on @@ -379,20 +389,16 @@ namespace AZ struct { uint64_t m_createdByPassRequest : 1; - uint64_t m_initialized : 1; uint64_t m_enabled : 1; uint64_t m_parentEnabled : 1; - uint64_t m_alreadyCreated : 1; - uint64_t m_alreadyReset : 1; - uint64_t m_alreadyPrepared : 1; + + uint64_t m_initialized : 1; + uint64_t m_partOfHierarchy : 1; uint64_t m_hasDrawListTag : 1; uint64_t m_hasPipelineViewTag : 1; - uint64_t m_queuedForBuildAttachment : 1; uint64_t m_timestampQueryEnabled : 1; uint64_t m_pipelineStatisticsQueryEnabled : 1; - uint64_t m_isBuildingAttachments : 1; - uint64_t m_isRendering : 1; }; uint64_t m_allFlags = 0; }; @@ -510,6 +516,12 @@ namespace AZ // Depth of the tree hierarchy this pass is at. // Example: Root would be depth 0, Root.Ssao.Downsample depth 2 uint32_t m_treeDepth = 0; + + // Used to track what phase of build/execution the pass is in + PassState m_state = PassState::Uninitialized; + + // Used to track what phases of build/initialization the pass is queued for + PassQueueState m_queueState = PassQueueState::NoQueue; }; //! Struct used to return results from Pass hierarchy validation diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassDefines.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassDefines.h index d536104768..7c55944603 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassDefines.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassDefines.h @@ -21,3 +21,28 @@ // Set this to 1 locally on your machine to facilitate pass debugging and get extra information // about passes in the output window. DO NOT SUBMIT with value set to 1 #define AZ_RPI_ENABLE_PASS_DEBUGGING 0 + +namespace AZ +{ + namespace RPI + { + enum class PassState : u8 + { + Uninitialized, + Queued, + Resetting, + Building, + Initializing, + Initialized, + Rendering + }; + + enum class PassQueueState : u8 + { + NoQueue, + QueuedForRemoval, + QueuedForBuild, + QueuedForInitialization, + }; + } +} diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h index fd30f4f406..534bf211dd 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h @@ -73,12 +73,12 @@ namespace AZ bool LoadPassTemplateMappings(const AZStd::string& templateMappingPath) override; void WriteTemplateToFile(const PassTemplate& passTemplate, AZStd::string_view assetFilePath) override; void DebugPrintPassHierarchy() override; - bool IsBuilding() const override; bool IsHotReloading() const override; void SetHotReloading(bool hotReloading) override; void SetTargetedPassDebuggingName(const AZ::Name& targetPassName) override; const AZ::Name& GetTargetedPassDebuggingName() const override; void ConnectEvent(OnReadyLoadTemplatesEvent::Handler& handler) override; + PassSystemState GetState() const override; // PassSystemInterface factory related functions... void AddPassCreator(Name className, PassCreator createFunction) override; @@ -103,8 +103,11 @@ namespace AZ // Returns the root of the pass tree hierarchy const Ptr& GetRootPass() override; - // Calls BuildAttachments() on passes queued in m_buildAttachmentsList - void BuildPassAttachments(); + // Calls Build() on passes queued in m_buildPassList + void BuildPasses(); + + // Calls Initialize() on passes queued in m_initializePassList + void InitializePasses(); // Validates Pass Hierarchy after building void Validate(); @@ -113,13 +116,15 @@ namespace AZ void RemovePasses(); // Functions for queuing passes in the lists below - void QueueForBuildAttachments(Pass* pass) override; + void QueueForBuild(Pass* pass) override; void QueueForRemoval(Pass* pass) override; + void QueueForInitialization(Pass* pass) override; // Lists for queuing passes for various function calls // Name of the list reflects the pass function it will call - AZStd::vector< Ptr > m_buildAttachmentsList; + AZStd::vector< Ptr > m_buildPassList; AZStd::vector< Ptr > m_removePassList; + AZStd::vector< Ptr > m_initializePassList; // Library of pass descriptors that can be instantiated through data driven pass requests PassLibrary m_passLibrary; @@ -133,9 +138,6 @@ namespace AZ // Whether the Pass Hierarchy changed bool m_passHierarchyChanged = true; - // Whether the Pass System is currently in it's building phase - bool m_isBuilding = false; - // Whether the Pass System is currently hot reloading passes bool m_isHotReloading = false; @@ -147,6 +149,9 @@ namespace AZ // Events OnReadyLoadTemplatesEvent m_loadTemplatesEvent; + + // Used to track what phase of execution the pass system is in + PassSystemState m_state = PassSystemState::Unitialized; }; } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h index 1224bf9545..788d00c8eb 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h @@ -40,6 +40,18 @@ namespace AZ using PassCreator = AZStd::function(const PassDescriptor& descriptor)>; + enum class PassSystemState : u32 + { + Unitialized, + Idle, + RemovingPasses, + Building, + Initializing, + Validating, + Rendering, + FrameEnd, + }; + class PassSystemInterface { friend class Pass; @@ -77,9 +89,6 @@ namespace AZ //! Prints the entire pass hierarchy from the root virtual void DebugPrintPassHierarchy() = 0; - //! Returns whether the Pass System is currently in it's build phase - virtual bool IsBuilding() const = 0; - //! Returns whether the Pass System is currently hot reloading virtual bool IsHotReloading() const = 0; @@ -157,15 +166,20 @@ namespace AZ //! The handler can add new pass templates or load pass template mappings from assets virtual void ConnectEvent(OnReadyLoadTemplatesEvent::Handler& handler) = 0; + virtual PassSystemState GetState() const = 0; + private: // These functions are only meant to be used by the Pass class - // Schedules a pass to have it's BuildAttachments() function called during frame update - virtual void QueueForBuildAttachments(Pass* pass) = 0; + // Schedules a pass to have it's Build() function called during frame update + virtual void QueueForBuild(Pass* pass) = 0; // Schedules a pass to be deleted during frame update virtual void QueueForRemoval(Pass* pass) = 0; + // Schedules a pass to be initialized during frame update + virtual void QueueForInitialization(Pass* pass) = 0; + //! Registers the pass with the pass library. Called in the Pass constructor. virtual void RegisterPass(Pass* pass) = 0; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RenderPass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RenderPass.h index 5cd917e841..5f222d8bba 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RenderPass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RenderPass.h @@ -96,7 +96,7 @@ namespace AZ void BindPassSrg(const RHI::FrameGraphCompileContext& context, Data::Instance& shaderResourceGroup); // Pass behavior overrides... - void OnBuildAttachmentsFinishedInternal() override; + void OnBuildFinishedInternal() override; void FrameBeginInternal(FramePrepareParams params) override; void FrameEndInternal() override; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/DownsampleMipChainPass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/DownsampleMipChainPass.h index 71c1fe4c49..eb4c4ed0aa 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/DownsampleMipChainPass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/DownsampleMipChainPass.h @@ -46,7 +46,7 @@ namespace AZ // Pass Behaviour Overrides... void ResetInternal() override; - void BuildAttachmentsInternal() override; + void BuildInternal() override; void FrameBeginInternal(FramePrepareParams params) override; private: diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/EnvironmentCubeMapPass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/EnvironmentCubeMapPass.h index 293a750f38..235871df83 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/EnvironmentCubeMapPass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/EnvironmentCubeMapPass.h @@ -61,7 +61,7 @@ namespace AZ // Pass overrides void CreateChildPassesInternal() override; - void BuildAttachmentsInternal() override; + void BuildInternal() override; void FrameBeginInternal(FramePrepareParams params) override; void FrameEndInternal() override; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/RenderToTexturePass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/RenderToTexturePass.h index c8daab8ef8..c86203b79b 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/RenderToTexturePass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/RenderToTexturePass.h @@ -47,7 +47,7 @@ namespace AZ protected: // Pass behavior overrides - void BuildAttachmentsInternal() override; + void BuildInternal() override; void FrameBeginInternal(FramePrepareParams params) override; // Function to be called when output size changed diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/SelectorPass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/SelectorPass.h index fe0ce231eb..2d876c6040 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/SelectorPass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/SelectorPass.h @@ -49,7 +49,7 @@ namespace AZ SelectorPass(const PassDescriptor& descriptor); // Pass behavior overrides - void BuildAttachmentsInternal() final; + void BuildInternal() final; // the input slot index each output slot connect to AZStd::vector m_connections; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/SwapChainPass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/SwapChainPass.h index 9aa00c99c2..7eac0d366d 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/SwapChainPass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/SwapChainPass.h @@ -64,7 +64,7 @@ namespace AZ protected: // Pass behavior overrides void CreateChildPassesInternal() override final; - void BuildAttachmentsInternal() override final; + void BuildInternal() override final; void FrameBeginInternal(FramePrepareParams params) override final; // WindowNotificationBus::Handler overrides ... diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/CopyPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/CopyPass.cpp index 4a6c883584..9648a47fd6 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/CopyPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/CopyPass.cpp @@ -74,7 +74,7 @@ namespace AZ // --- Pass behavior overrides --- - void CopyPass::BuildAttachmentsInternal() + void CopyPass::BuildInternal() { AZ_Assert(GetInputCount() == 1 && GetOutputCount() == 1, "CopyPass has %d inputs and %d outputs. It should have exactly one of each.", diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/MSAAResolvePass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/MSAAResolvePass.cpp index c889f367b7..e457cb4992 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/MSAAResolvePass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/MSAAResolvePass.cpp @@ -38,7 +38,7 @@ namespace AZ { } - void MSAAResolvePass::BuildAttachmentsInternal() + void MSAAResolvePass::BuildInternal() { AZ_Assert(GetOutputCount() != 0, "MSAAResolvePass %s has no outputs to render to.", GetPathName().GetCStr()); } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp index 106ef82bf1..7244510fbd 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp @@ -59,7 +59,7 @@ namespace AZ child->m_parent = this; child->OnHierarchyChange(); - QueueForBuildAttachments(); + QueueForBuild(); // Notify pipeline if (m_pipeline) @@ -248,13 +248,6 @@ namespace AZ void ParentPass::CreateChildPasses() { - // Flag prevents the function from executing multiple times a frame. Can happen - // as pass system has a list of passes for which it needs to call this function. - if (m_flags.m_alreadyCreated) - { - return; - } - m_flags.m_alreadyCreated = true; RemoveChildren(); CreatePassesFromTemplate(); CreateChildPassesInternal(); @@ -277,19 +270,27 @@ namespace AZ } } - void ParentPass::BuildAttachmentsInternal() + void ParentPass::BuildInternal() + { + for (const Ptr& child : m_children) + { + child->Build(); + } + } + + void ParentPass::OnBuildFinishedInternal() { for (const Ptr& child : m_children) { - child->BuildAttachments(); + child->OnBuildFinished(); } } - void ParentPass::OnBuildAttachmentsFinishedInternal() + void ParentPass::InitializeInternal() { for (const Ptr& child : m_children) { - child->OnBuildAttachmentsFinished(); + child->Initialize(); } } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp index 8d613eb2bb..da9022b655 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp @@ -71,7 +71,7 @@ namespace AZ } PassSystemInterface::Get()->RegisterPass(this); - QueueForBuildAttachments(); + QueueForBuild(); } Pass::~Pass() @@ -162,6 +162,11 @@ namespace AZ // --- Getters & Setters --- + PassState Pass::GetPassState() const + { + return m_state; + } + ParentPass* Pass::GetParent() const { return m_parent; @@ -350,28 +355,49 @@ namespace AZ // --- Queuing functions with PassSystem --- - void Pass::QueueForBuildAttachments() + void Pass::QueueForBuild() { // Don't queue if we're in building phase - if (!PassSystemInterface::Get()->IsBuilding()) + if (PassSystemInterface::Get()->GetState() != PassSystemState::Building && + (m_queueState == PassQueueState::NoQueue || m_queueState == PassQueueState::QueuedForInitialization)) { - // m_queuedForBuildAttachment makes sure the pass only be queue for once - if (!m_flags.m_queuedForBuildAttachment) + PassSystemInterface::Get()->QueueForBuild(this); + m_queueState = PassQueueState::QueuedForBuild; + + if (m_state != PassState::Rendering) { - PassSystemInterface::Get()->QueueForBuildAttachments(this); - m_flags.m_queuedForBuildAttachment = true; + m_state = PassState::Queued; + } + } + } + + void Pass::QueueForInitialization() + { + // Don't queue if we're in initialization phase + if (PassSystemInterface::Get()->GetState() != PassSystemState::Initializing && m_queueState == PassQueueState::NoQueue) + { + PassSystemInterface::Get()->QueueForInitialization(this); + m_queueState = PassQueueState::QueuedForInitialization; - // Set these two flags to false since when queue build attachments request, they should all be already be false except one use - // case that the pass system processed all queued requests when active a scene. - m_flags.m_alreadyPrepared = false; - m_flags.m_alreadyReset = false; + if(m_state != PassState::Rendering) + { + m_state = PassState::Queued; } } } - void Pass::QueueForRemoval([[maybe_unused]] bool needsDeletion) + void Pass::QueueForRemoval() { - PassSystemInterface::Get()->QueueForRemoval(this); + if (m_queueState != PassQueueState::QueuedForRemoval) + { + PassSystemInterface::Get()->QueueForRemoval(this); + m_queueState = PassQueueState::QueuedForRemoval; + + if (m_state != PassState::Rendering) + { + m_state = PassState::Queued; + } + } } // --- PassTemplate related functions --- @@ -990,7 +1016,7 @@ namespace AZ { Ptr targetAttachment = nullptr; - if (!m_flags.m_isBuildingAttachments && !IsEnabled() && binding.m_slotType == PassSlotType::Output && binding.m_fallbackBinding) + if (m_state != PassState::Building && !IsEnabled() && binding.m_slotType == PassSlotType::Output && binding.m_fallbackBinding) { targetAttachment = binding.m_fallbackBinding->m_attachment; } @@ -1037,13 +1063,11 @@ namespace AZ void Pass::Reset() { - // Flag prevents the function from executing multiple times a frame. Can happen - // as pass system has a list of passes for which it needs to call this function. - if (m_flags.m_alreadyReset) + if (m_queueState != PassQueueState::QueuedForBuild || m_state != PassState::Queued) { return; } - m_flags.m_alreadyReset = true; + m_state = PassState::Resetting; // Store references to imported attachments to underlying images and buffers aren't deleted during attachment building StoreImportedAttachmentReferences(); @@ -1060,18 +1084,13 @@ namespace AZ ResetInternal(); } - void Pass::BuildAttachments() + void Pass::Build() { - m_flags.m_queuedForBuildAttachment = false; - - // Flag prevents the function from executing multiple times a frame. Can happen - // as pass system has a list of passes for which it needs to call this function. - if (m_flags.m_alreadyPrepared) + if (m_queueState != PassQueueState::QueuedForBuild || m_state != PassState::Resetting) { return; } - m_flags.m_alreadyPrepared = true; - m_flags.m_isBuildingAttachments = true; + m_state = PassState::Building; AZ_RPI_BREAK_ON_TARGET_PASS; @@ -1084,7 +1103,7 @@ namespace AZ SetupInputsFromTemplate(); // Custom pass behavior - BuildAttachmentsInternal(); + BuildInternal(); // Outputs SetupOutputsFromTemplate(); @@ -1095,21 +1114,29 @@ namespace AZ UpdateOwnedAttachments(); UpdateAttachmentUsageIndices(); - m_flags.m_isBuildingAttachments = false; + // Queue for Initialization + m_queueState = PassQueueState::NoQueue; + QueueForInitialization(); } - void Pass::OnBuildAttachmentsFinished() + void Pass::OnBuildFinished() { AZ_RPI_BREAK_ON_TARGET_PASS; - // These flags are to prevent a pass from being built multiple times. - // We reset them after each build phase. - m_flags.m_alreadyCreated = false; - m_flags.m_alreadyPrepared = false; - m_flags.m_alreadyReset = false; - m_flags.m_queuedForBuildAttachment = false; m_importedAttachmentStore.clear(); - OnBuildAttachmentsFinishedInternal(); + OnBuildFinishedInternal(); + } + + void Pass::Initialize() + { + if (m_queueState != PassQueueState::QueuedForInitialization || m_state != PassState::Queued) + { + return; + } + + m_state = PassState::Initializing; + InitializeInternal(); + m_state = PassState::Initialized; } void Pass::Validate(PassValidationResults& validationResults) @@ -1165,7 +1192,7 @@ namespace AZ UpdateConnectedBindings(); return; } - m_flags.m_isRendering = true; + m_state = PassState::Rendering; UpdateConnectedBindings(); UpdateOwnedAttachments(); @@ -1180,10 +1207,10 @@ namespace AZ void Pass::FrameEnd() { - if (m_flags.m_isRendering) + if (m_state == PassState::Rendering) { FrameEndInternal(); - m_flags.m_isRendering = false; + m_state = (m_queueState == PassQueueState::NoQueue) ? PassState::Initialized : PassState::Queued; } } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp index 448c28f202..3dabd88fff 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp @@ -93,11 +93,15 @@ namespace AZ void PassSystem::Init() { + m_state = PassSystemState::Initializing; + Interface::Register(this); m_passLibrary.Init(); m_passFactory.Init(&m_passLibrary); m_rootPass = CreatePass(Name{"Root"}); m_rootPass->m_flags.m_partOfHierarchy = true; + + m_state = PassSystemState::Idle; } void PassSystem::InitPassTemplates() @@ -118,10 +122,10 @@ namespace AZ JsonSerializationUtils::SaveObjectToFile(&passAsset, assetFilePath); } - void PassSystem::QueueForBuildAttachments(Pass* pass) + void PassSystem::QueueForBuild(Pass* pass) { - AZ_Assert(pass != nullptr, "Queuing nullptr pass in PassSystem::QueueForBuildAttachments"); - m_buildAttachmentsList.push_back(pass); + AZ_Assert(pass != nullptr, "Queuing nullptr pass in PassSystem::QueueForBuild"); + m_buildPassList.push_back(pass); } void PassSystem::QueueForRemoval(Pass* pass) @@ -130,6 +134,12 @@ namespace AZ m_removePassList.push_back(pass); } + void PassSystem::QueueForInitialization(Pass* pass) + { + AZ_Assert(pass != nullptr, "Queuing nullptr pass in PassSystem::QueueForInitialization"); + m_initializePassList.push_back(pass); + } + // Sort so passes with less depth (closer to the root) are first. Used when changes // in the parent passes can affect the child passes, like with attachment building. void SortPassListAscending(AZStd::vector< Ptr >& passList) @@ -155,6 +165,7 @@ namespace AZ void PassSystem::RemovePasses() { + m_state = PassSystemState::RemovingPasses; AZ_ATOM_PROFILE_FUNCTION("RPI", "PassSystem: RemovePasses"); if (!m_removePassList.empty()) @@ -168,24 +179,25 @@ namespace AZ m_removePassList.clear(); } + + m_state = PassSystemState::Idle; } - void PassSystem::BuildPassAttachments() + void PassSystem::BuildPasses() { + m_state = PassSystemState::Building; AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzRender); AZ_ATOM_PROFILE_FUNCTION("RPI", "PassSystem: BuildPassAttachments"); - m_isBuilding = true; - - m_passHierarchyChanged = !m_buildAttachmentsList.empty(); + m_passHierarchyChanged = !m_buildPassList.empty(); - // While loop is for the event in which passes being built add more pass to m_buildAttachmentsList - while(!m_buildAttachmentsList.empty()) + // While loop is for the event in which passes being built add more pass to m_buildPassList + while(!m_buildPassList.empty()) { AZ_Assert(m_removePassList.empty(), "Passes shouldn't be queued removal during build attachment process"); - AZStd::vector< Ptr > buildListCopy = m_buildAttachmentsList; - m_buildAttachmentsList.clear(); + AZStd::vector< Ptr > buildListCopy = m_buildPassList; + m_buildPassList.clear(); // Erase passes which were removed from pass tree already (which parent is empty) auto unused = AZStd::remove_if(buildListCopy.begin(), buildListCopy.end(), @@ -203,15 +215,15 @@ namespace AZ } for (const Ptr& pass : buildListCopy) { - pass->BuildAttachments(); + pass->Build(); } - - // Signal all passes that we have finished building - m_rootPass->OnBuildAttachmentsFinished(); } if (m_passHierarchyChanged) { + // Signal all passes that we have finished building + m_rootPass->OnBuildFinished(); + #if AZ_RPI_ENABLE_PASS_DEBUGGING if (!m_isHotReloading) { @@ -221,11 +233,39 @@ namespace AZ #endif } - m_isBuilding = false; + m_state = PassSystemState::Idle; + } + + void PassSystem::InitializePasses() + { + m_state = PassSystemState::Initializing; + AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzRender); + AZ_ATOM_PROFILE_FUNCTION("RPI", "PassSystem: BuildPassAttachments"); + + if(!m_initializePassList.empty()) + { + // Erase passes which were removed from pass tree already (which parent is empty) + auto unused = AZStd::remove_if(m_initializePassList.begin(), m_initializePassList.end(), + [](const RHI::Ptr& currentPass) + { + return !currentPass->m_flags.m_partOfHierarchy; + }); + m_initializePassList.erase(unused, m_initializePassList.end()); + + SortPassListAscending(m_initializePassList); + + for (const Ptr& pass : m_initializePassList) + { + pass->Initialize(); + } + } + + m_state = PassSystemState::Idle; } void PassSystem::Validate() { + m_state = PassSystemState::Validating; AZ_ATOM_PROFILE_FUNCTION("RPI", "PassSystem: Validate"); if (PassValidation::IsEnabled()) @@ -241,12 +281,15 @@ namespace AZ m_rootPass->Validate(validationResults); validationResults.PrintValidationIfError(); } + + m_state = PassSystemState::Idle; } void PassSystem::ProcessQueuedChanges() { RemovePasses(); - BuildPassAttachments(); + BuildPasses(); + InitializePasses(); Validate(); } @@ -256,6 +299,8 @@ namespace AZ AZ_ATOM_PROFILE_FUNCTION("RPI", "PassSystem: FrameUpdate"); ProcessQueuedChanges(); + + m_state = PassSystemState::Rendering; Pass::FramePrepareParams params{ &frameGraphBuilder }; m_rootPass->FrameBegin(params); } @@ -264,6 +309,8 @@ namespace AZ { AZ_ATOM_PROFILE_FUNCTION("RHI", "PassSystem: FrameEnd"); + m_state = PassSystemState::FrameEnd; + m_rootPass->FrameEnd(); // remove any pipelines that are marked as ExecuteOnce @@ -278,12 +325,14 @@ namespace AZ } m_passHierarchyChanged = false; + + m_state = PassSystemState::Idle; } void PassSystem::Shutdown() { RemovePasses(); - m_buildAttachmentsList.clear(); + m_buildPassList.clear(); m_rootPass = nullptr; m_passFactory.Shutdown(); m_passLibrary.Shutdown(); @@ -296,9 +345,9 @@ namespace AZ return m_rootPass; } - bool PassSystem::IsBuilding() const + PassSystemState PassSystem::GetState() const { - return m_isBuilding; + return m_state; } bool PassSystem::IsHotReloading() const diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp index 3a2a556429..12989fb873 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp @@ -128,7 +128,7 @@ namespace AZ } - void RenderPass::OnBuildAttachmentsFinishedInternal() + void RenderPass::OnBuildFinishedInternal() { if (m_shaderResourceGroup != nullptr) { diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/DownsampleMipChainPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/DownsampleMipChainPass.cpp index 0e0ebf445e..329247d4eb 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/DownsampleMipChainPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/DownsampleMipChainPass.cpp @@ -181,12 +181,12 @@ namespace AZ // Pass behavior functions... - void DownsampleMipChainPass::BuildAttachmentsInternal() + void DownsampleMipChainPass::BuildInternal() { GetInputInfo(); BuildChildPasses(); UpdateChildren(); - ParentPass::BuildAttachmentsInternal(); + ParentPass::BuildInternal(); } void DownsampleMipChainPass::FrameBeginInternal(FramePrepareParams params) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/EnvironmentCubeMapPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/EnvironmentCubeMapPass.cpp index c72712bce5..672e5509ee 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/EnvironmentCubeMapPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/EnvironmentCubeMapPass.cpp @@ -37,8 +37,6 @@ namespace AZ EnvironmentCubeMapPass::EnvironmentCubeMapPass(const PassDescriptor& passDescriptor) : ParentPass(passDescriptor) { - m_flags.m_alreadyCreated = false; - // load pass data const EnvironmentCubeMapPassData* passData = PassUtils::GetPassData(passDescriptor); if (passData == nullptr) @@ -113,7 +111,7 @@ namespace AZ AddChild(m_childPass); } - void EnvironmentCubeMapPass::BuildAttachmentsInternal() + void EnvironmentCubeMapPass::BuildInternal() { // create output image descriptor m_outputImageDesc = RHI::ImageDescriptor::Create2D(RHI::ImageBindFlags::Color | RHI::ImageBindFlags::CopyRead, CubeMapFaceSize, CubeMapFaceSize, RHI::Format::R16G16B16A16_FLOAT); @@ -135,7 +133,7 @@ namespace AZ m_attachmentBindings.push_back(outputAttachment); - ParentPass::BuildAttachmentsInternal(); + ParentPass::BuildInternal(); } void EnvironmentCubeMapPass::FrameBeginInternal(FramePrepareParams params) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/RenderToTexturePass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/RenderToTexturePass.cpp index 4356a56622..c0a4785365 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/RenderToTexturePass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/RenderToTexturePass.cpp @@ -50,7 +50,7 @@ namespace AZ { } - void RenderToTexturePass::BuildAttachmentsInternal() + void RenderToTexturePass::BuildInternal() { m_outputAttachment = aznew PassAttachment(); m_outputAttachment->m_name = "RenderTarget"; @@ -73,7 +73,7 @@ namespace AZ m_attachmentBindings.push_back(outputBinding); - Base::BuildAttachmentsInternal(); + Base::BuildInternal(); } void RenderToTexturePass::FrameBeginInternal(FramePrepareParams params) @@ -100,7 +100,7 @@ namespace AZ m_passData.m_width = width; m_passData.m_height = height; OnUpdateOutputSize(); - QueueForBuildAttachments(); + QueueForBuild(); } void RenderToTexturePass::OnUpdateOutputSize() diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SelectorPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SelectorPass.cpp index 8e8c67393d..90390b78d7 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SelectorPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SelectorPass.cpp @@ -44,7 +44,7 @@ namespace AZ } } - void SelectorPass::BuildAttachmentsInternal() + void SelectorPass::BuildInternal() { // Update output connections based on m_connections // This need to be done after BuildAttachment is finished @@ -72,7 +72,7 @@ namespace AZ m_connections[outputSlotIndex] = inputSlotIndex; // Queue to rebuild attachment connections - QueueForBuildAttachments(); + QueueForBuild(); } void SelectorPass::Connect(const AZ::Name& inputSlot, const AZ::Name& outputSlot) @@ -113,7 +113,7 @@ namespace AZ m_connections[outputIdx] = inputIdx; // Queue to rebuild attachment connections - QueueForBuildAttachments(); + QueueForBuild(); } } // namespace RPI diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SwapChainPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SwapChainPass.cpp index 5bcec87df0..e6f65e997c 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SwapChainPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SwapChainPass.cpp @@ -26,8 +26,6 @@ namespace AZ , m_windowContext(windowContext) , m_childTemplateName(childTemplateName) { - m_flags.m_alreadyCreated = false; - PassSystemInterface* passSystem = PassSystemInterface::Get(); // Create child pass @@ -112,7 +110,7 @@ namespace AZ AddChild(m_childPass); } - void SwapChainPass::BuildAttachmentsInternal() + void SwapChainPass::BuildInternal() { if (m_windowContext->GetSwapChain() == nullptr) { @@ -124,7 +122,7 @@ namespace AZ SetupSwapChainAttachment(); - ParentPass::BuildAttachmentsInternal(); + ParentPass::BuildInternal(); } void SwapChainPass::FrameBeginInternal(FramePrepareParams params) @@ -154,7 +152,7 @@ namespace AZ void SwapChainPass::OnWindowResized([[maybe_unused]] uint32_t width, [[maybe_unused]] uint32_t height) { - QueueForBuildAttachments(); + QueueForBuild(); } void SwapChainPass::ReadbackSwapChain(AZStd::shared_ptr readback) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp index cc0cefd082..86d76287bb 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp @@ -329,9 +329,8 @@ namespace AZ if (validation.IsValid()) { // Remove old pass - bool deletePass = true; m_rootPass->SetRenderPipeline(nullptr); - m_rootPass->QueueForRemoval(deletePass); + m_rootPass->QueueForRemoval(); // Set new root m_rootPass = newRoot; diff --git a/Gems/Atom/RPI/Code/Tests/Pass/PassTests.cpp b/Gems/Atom/RPI/Code/Tests/Pass/PassTests.cpp index 96a21f8c9b..f9a2bc4493 100644 --- a/Gems/Atom/RPI/Code/Tests/Pass/PassTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Pass/PassTests.cpp @@ -329,7 +329,7 @@ namespace UnitTest Ptr parentPass = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("ParentPass")); parentPass->Reset(); - parentPass->BuildAttachments(); + parentPass->Build(); PassValidationResults validationResults; parentPass->Validate(validationResults); @@ -351,7 +351,7 @@ namespace UnitTest Ptr parentPass = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("ParentPass")); parentPass->Reset(); - parentPass->BuildAttachments(); + parentPass->Build(); PassValidationResults validationResults; parentPass->Validate(validationResults); @@ -373,7 +373,7 @@ namespace UnitTest Ptr parentPass = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("ParentPass")); parentPass->Reset(); - parentPass->BuildAttachments(); + parentPass->Build(); PassValidationResults validationResults; parentPass->Validate(validationResults); @@ -397,7 +397,7 @@ namespace UnitTest parentPass->m_flags.m_partOfHierarchy = true; parentPass->OnHierarchyChange(); parentPass->Reset(); - parentPass->BuildAttachments(); + parentPass->Build(); PassValidationResults validationResults; parentPass->Validate(validationResults); @@ -421,7 +421,7 @@ namespace UnitTest parentPass->m_flags.m_partOfHierarchy = true; parentPass->OnHierarchyChange(); parentPass->Reset(); - parentPass->BuildAttachments(); + parentPass->Build(); PassValidationResults validationResults; parentPass->Validate(validationResults); @@ -445,7 +445,7 @@ namespace UnitTest parentPass->m_flags.m_partOfHierarchy = true; parentPass->OnHierarchyChange(); parentPass->Reset(); - parentPass->BuildAttachments(); + parentPass->Build(); PassValidationResults validationResults; parentPass->Validate(validationResults); @@ -469,7 +469,7 @@ namespace UnitTest parentPass->m_flags.m_partOfHierarchy = true; parentPass->OnHierarchyChange(); parentPass->Reset(); - parentPass->BuildAttachments(); + parentPass->Build(); PassValidationResults validationResults; parentPass->Validate(validationResults); From 52b306eb3ef53ea01080c9670985d893d8ef73d1 Mon Sep 17 00:00:00 2001 From: antonmic Date: Fri, 4 Jun 2021 14:59:27 -0700 Subject: [PATCH 04/73] Pass changes now building and working --- .../Code/Source/DisplayMapper/DisplayMapperPass.cpp | 2 ++ .../Code/Source/LuxCore/LuxCoreTexturePass.cpp | 2 ++ .../RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h | 1 + .../RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp | 6 ++++++ Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp | 11 +++++++---- .../RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp | 13 ++++++++----- .../Pass/Specific/EnvironmentCubeMapPass.cpp | 2 ++ .../RPI.Public/Pass/Specific/SwapChainPass.cpp | 2 ++ 8 files changed, 30 insertions(+), 9 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp index be3e05163a..b6fa0b5c41 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp @@ -46,6 +46,8 @@ namespace AZ DisplayMapperPass::DisplayMapperPass(const RPI::PassDescriptor& descriptor) : RPI::ParentPass(descriptor) { + m_flags.m_alreadyCreated = false; + AzFramework::NativeWindowHandle windowHandle = nullptr; AzFramework::WindowSystemRequestBus::BroadcastResult( windowHandle, diff --git a/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreTexturePass.cpp b/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreTexturePass.cpp index 3c7233e747..7708605e29 100644 --- a/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreTexturePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreTexturePass.cpp @@ -28,6 +28,8 @@ namespace AZ LuxCoreTexturePass::LuxCoreTexturePass(const RPI::PassDescriptor& descriptor) : ParentPass(descriptor) { + m_flags.m_alreadyCreated = false; + RPI::PassSystemInterface* passSystem = RPI::PassSystemInterface::Get(); // Create render target pass diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h index ee7f850d27..b71016f30a 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h @@ -393,6 +393,7 @@ namespace AZ uint64_t m_parentEnabled : 1; uint64_t m_initialized : 1; + uint64_t m_alreadyCreated : 1; uint64_t m_partOfHierarchy : 1; uint64_t m_hasDrawListTag : 1; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp index 7244510fbd..ebdfa7cf55 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp @@ -248,6 +248,12 @@ namespace AZ void ParentPass::CreateChildPasses() { + if (m_flags.m_alreadyCreated) + { + return; + } + m_flags.m_alreadyCreated = true; + RemoveChildren(); CreatePassesFromTemplate(); CreateChildPassesInternal(); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp index da9022b655..726d702a72 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp @@ -151,6 +151,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(this)); + m_queueState = PassQueueState::NoQueue; } void Pass::OnOrphan() @@ -358,7 +359,7 @@ namespace AZ void Pass::QueueForBuild() { // Don't queue if we're in building phase - if (PassSystemInterface::Get()->GetState() != PassSystemState::Building && + if (m_state != PassState::Building && (m_queueState == PassQueueState::NoQueue || m_queueState == PassQueueState::QueuedForInitialization)) { PassSystemInterface::Get()->QueueForBuild(this); @@ -374,7 +375,7 @@ namespace AZ void Pass::QueueForInitialization() { // Don't queue if we're in initialization phase - if (PassSystemInterface::Get()->GetState() != PassSystemState::Initializing && m_queueState == PassQueueState::NoQueue) + if (m_queueState == PassQueueState::NoQueue) { PassSystemInterface::Get()->QueueForInitialization(this); m_queueState = PassQueueState::QueuedForInitialization; @@ -1086,11 +1087,12 @@ namespace AZ void Pass::Build() { - if (m_queueState != PassQueueState::QueuedForBuild || m_state != PassState::Resetting) + if (m_queueState != PassQueueState::QueuedForBuild || (m_state != PassState::Queued && m_state != PassState::Resetting)) { return; } m_state = PassState::Building; + m_queueState = PassQueueState::NoQueue; AZ_RPI_BREAK_ON_TARGET_PASS; @@ -1115,7 +1117,6 @@ namespace AZ UpdateAttachmentUsageIndices(); // Queue for Initialization - m_queueState = PassQueueState::NoQueue; QueueForInitialization(); } @@ -1123,6 +1124,7 @@ namespace AZ { AZ_RPI_BREAK_ON_TARGET_PASS; + m_flags.m_alreadyCreated = false; m_importedAttachmentStore.clear(); OnBuildFinishedInternal(); } @@ -1133,6 +1135,7 @@ namespace AZ { return; } + m_queueState = PassQueueState::NoQueue; m_state = PassState::Initializing; InitializeInternal(); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp index 3dabd88fff..0c38b228f5 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp @@ -242,19 +242,22 @@ namespace AZ AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzRender); AZ_ATOM_PROFILE_FUNCTION("RPI", "PassSystem: BuildPassAttachments"); - if(!m_initializePassList.empty()) + while (!m_initializePassList.empty()) { + AZStd::vector< Ptr > initListCopy = m_initializePassList; + m_initializePassList.clear(); + // Erase passes which were removed from pass tree already (which parent is empty) - auto unused = AZStd::remove_if(m_initializePassList.begin(), m_initializePassList.end(), + auto unused = AZStd::remove_if(initListCopy.begin(), initListCopy.end(), [](const RHI::Ptr& currentPass) { return !currentPass->m_flags.m_partOfHierarchy; }); - m_initializePassList.erase(unused, m_initializePassList.end()); + initListCopy.erase(unused, initListCopy.end()); - SortPassListAscending(m_initializePassList); + SortPassListAscending(initListCopy); - for (const Ptr& pass : m_initializePassList) + for (const Ptr& pass : initListCopy) { pass->Initialize(); } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/EnvironmentCubeMapPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/EnvironmentCubeMapPass.cpp index 672e5509ee..be06343ab9 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/EnvironmentCubeMapPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/EnvironmentCubeMapPass.cpp @@ -37,6 +37,8 @@ namespace AZ EnvironmentCubeMapPass::EnvironmentCubeMapPass(const PassDescriptor& passDescriptor) : ParentPass(passDescriptor) { + m_flags.m_alreadyCreated = false; + // load pass data const EnvironmentCubeMapPassData* passData = PassUtils::GetPassData(passDescriptor); if (passData == nullptr) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SwapChainPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SwapChainPass.cpp index e6f65e997c..45fb890e91 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SwapChainPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SwapChainPass.cpp @@ -26,6 +26,8 @@ namespace AZ , m_windowContext(windowContext) , m_childTemplateName(childTemplateName) { + m_flags.m_alreadyCreated = false; + PassSystemInterface* passSystem = PassSystemInterface::Get(); // Create child pass From ed759612dd198ae463c6af0b8b6b92ba2c51c563 Mon Sep 17 00:00:00 2001 From: antonmic Date: Sat, 5 Jun 2021 19:12:45 -0700 Subject: [PATCH 05/73] Atom Pass changes WIP: ASV screenshot tests passing now --- .../Common/Code/Source/ImGui/ImGuiPass.cpp | 4 +- .../Common/Code/Source/ImGui/ImGuiPass.h | 2 +- .../Code/Source/PostProcessing/SsaoPasses.cpp | 4 +- .../Code/Source/PostProcessing/SsaoPasses.h | 2 +- .../Atom/RPI.Public/Pass/AttachmentReadback.h | 2 +- .../Include/Atom/RPI.Public/Pass/ParentPass.h | 2 +- .../Code/Include/Atom/RPI.Public/Pass/Pass.h | 12 +- .../Atom/RPI.Public/Pass/PassDefines.h | 5 +- .../Include/Atom/RPI.Public/Pass/RenderPass.h | 2 +- .../RPI.Public/Pass/AttachmentReadback.cpp | 15 +- .../Source/RPI.Public/Pass/ParentPass.cpp | 12 +- .../RPI/Code/Source/RPI.Public/Pass/Pass.cpp | 226 ++++++++++++------ .../Source/RPI.Public/Pass/PassSystem.cpp | 28 ++- .../Source/RPI.Public/Pass/RenderPass.cpp | 2 +- 14 files changed, 207 insertions(+), 111 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.cpp b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.cpp index fe5d9a16fe..750402ada8 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.cpp @@ -519,13 +519,13 @@ namespace AZ io.Fonts->TexID = reinterpret_cast(m_fontAtlas.get()); } - void ImGuiPass::OnBuildFinishedInternal() + void ImGuiPass::InitializeInternal() { // Set output format and finalize pipeline state m_pipelineState->SetOutputFromPass(this); m_pipelineState->Finalize(); - Base::OnBuildFinishedInternal(); + Base::InitializeInternal(); } void ImGuiPass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) diff --git a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.h b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.h index 30449820bb..f63b515536 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.h @@ -94,7 +94,7 @@ namespace AZ explicit ImGuiPass(const RPI::PassDescriptor& descriptor); // Pass Behaviour Overrides... - void OnBuildFinishedInternal() override; + void InitializeInternal() override; void FrameBeginInternal(FramePrepareParams params) override; // Scope producer functions diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SsaoPasses.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SsaoPasses.cpp index 1aa16a4417..8954584886 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SsaoPasses.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SsaoPasses.cpp @@ -41,9 +41,9 @@ namespace AZ return ParentPass::IsEnabled(); } - void SsaoParentPass::OnBuildFinishedInternal() + void SsaoParentPass::InitializeInternal() { - ParentPass::OnBuildFinishedInternal(); + ParentPass::InitializeInternal(); m_blurParentPass = FindChildPass(Name("SsaoBlur"))->AsParent(); AZ_Assert(m_blurParentPass, "[SsaoParentPass] Could not retrieve parent blur pass."); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SsaoPasses.h b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SsaoPasses.h index 20aa554414..9fc5448f65 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SsaoPasses.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SsaoPasses.h @@ -36,7 +36,7 @@ namespace AZ protected: // Behavior functions override... - void OnBuildFinishedInternal() override; + void InitializeInternal() override; void FrameBeginInternal(FramePrepareParams params) override; private: diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/AttachmentReadback.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/AttachmentReadback.h index 539e1a5398..3c00ce4e4c 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/AttachmentReadback.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/AttachmentReadback.h @@ -99,7 +99,7 @@ namespace AZ void DecomposeExecute(const RHI::FrameGraphExecuteContext& context); // copy data from the read back buffer (m_readbackBuffer) to the data buffer (m_dataBuffer) - void CopyBufferData(uint32_t readbackBufferIndex); + bool CopyBufferData(uint32_t readbackBufferIndex); // Get read back data in a structure ReadbackResult GetReadbackResult() const; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h index 0e1e12e620..ca7baf1a0f 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h @@ -110,7 +110,7 @@ namespace AZ void ResetInternal() override; void BuildInternal() override; - void OnBuildFinishedInternal() override; + void OnInitializationFinishedInternal() override; void InitializeInternal() override; void FrameBeginInternal(FramePrepareParams params) override; void FrameEndInternal() override; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h index b71016f30a..3cab5b36e4 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h @@ -320,12 +320,12 @@ namespace AZ // Builds and sets up any attachments and input/output connections the pass needs. // Called from PassSystem when pass is QueueForBuild. - void Build(); + void Build(bool calledFromPassSystem = false); virtual void BuildInternal() { } // Called after the pass build phase has finished. Allows passes to reset build flags. - void OnBuildFinished(); - virtual void OnBuildFinishedInternal() { }; + void OnInitializationFinished(); + virtual void OnInitializationFinishedInternal() { }; // Allows for additional pass initialization between building and rendering // Can be queued independently of Build so as to only invoke Initialize without Build @@ -395,6 +395,12 @@ namespace AZ uint64_t m_initialized : 1; uint64_t m_alreadyCreated : 1; + // OLD SCHOOL + uint64_t m_alreadyReset : 1; + uint64_t m_alreadyPrepared : 1; + uint64_t m_queuedForBuildAttachment : 1; + + uint64_t m_partOfHierarchy : 1; uint64_t m_hasDrawListTag : 1; uint64_t m_hasPipelineViewTag : 1; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassDefines.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassDefines.h index 7c55944603..7ba7f1be4e 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassDefines.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassDefines.h @@ -20,7 +20,7 @@ // Enables debugging of the pass system // Set this to 1 locally on your machine to facilitate pass debugging and get extra information // about passes in the output window. DO NOT SUBMIT with value set to 1 -#define AZ_RPI_ENABLE_PASS_DEBUGGING 0 +#define AZ_RPI_ENABLE_PASS_DEBUGGING 1 namespace AZ { @@ -31,9 +31,12 @@ namespace AZ Uninitialized, Queued, Resetting, + Reset, Building, + Built, Initializing, Initialized, + Idle, Rendering }; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RenderPass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RenderPass.h index 5f222d8bba..8f8267393e 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RenderPass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RenderPass.h @@ -96,7 +96,7 @@ namespace AZ void BindPassSrg(const RHI::FrameGraphCompileContext& context, Data::Instance& shaderResourceGroup); // Pass behavior overrides... - void OnBuildFinishedInternal() override; + void InitializeInternal() override; void FrameBeginInternal(FramePrepareParams params) override; void FrameEndInternal() override; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/AttachmentReadback.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/AttachmentReadback.cpp index 6435ae9570..88d3eb27fd 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/AttachmentReadback.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/AttachmentReadback.cpp @@ -320,8 +320,14 @@ namespace AZ { if (m_state == ReadbackState::Reading) { - CopyBufferData(readbackBufferCurrentIndex); - m_state = ReadbackState::Success; + if (CopyBufferData(readbackBufferCurrentIndex)) + { + m_state = ReadbackState::Success; + } + else + { + m_state = ReadbackState::Failed; + } } if (m_callback) { @@ -498,13 +504,13 @@ namespace AZ return result; } - void AttachmentReadback::CopyBufferData(uint32_t readbackBufferIndex) + bool AttachmentReadback::CopyBufferData(uint32_t readbackBufferIndex) { Data::Instance readbackBufferCurrent = m_readbackBufferArray[readbackBufferIndex]; if (!readbackBufferCurrent) { - return; + return false; } auto bufferSize = readbackBufferCurrent->GetBufferSize(); @@ -537,6 +543,7 @@ namespace AZ } m_isReadbackComplete[readbackBufferIndex] = true; + return true; } } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp index ebdfa7cf55..ad361bdf42 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp @@ -270,10 +270,10 @@ namespace AZ void ParentPass::ResetInternal() { - for (const Ptr& child : m_children) - { - child->Reset(); - } + //for (const Ptr& child : m_children) + //{ + // child->Reset(); + //} } void ParentPass::BuildInternal() @@ -284,11 +284,11 @@ namespace AZ } } - void ParentPass::OnBuildFinishedInternal() + void ParentPass::OnInitializationFinishedInternal() { for (const Ptr& child : m_children) { - child->OnBuildFinished(); + child->OnInitializationFinished(); } } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp index 726d702a72..790a1e767f 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp @@ -37,10 +37,13 @@ #include #include + namespace AZ { namespace RPI { +#pragma optimize("", off) + // --- Constructors --- Pass::Pass(const PassDescriptor& descriptor) @@ -152,6 +155,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(this)); m_queueState = PassQueueState::NoQueue; + m_state = PassState::Idle; } void Pass::OnOrphan() @@ -354,53 +358,6 @@ namespace AZ return nullptr; } - // --- Queuing functions with PassSystem --- - - void Pass::QueueForBuild() - { - // Don't queue if we're in building phase - if (m_state != PassState::Building && - (m_queueState == PassQueueState::NoQueue || m_queueState == PassQueueState::QueuedForInitialization)) - { - PassSystemInterface::Get()->QueueForBuild(this); - m_queueState = PassQueueState::QueuedForBuild; - - if (m_state != PassState::Rendering) - { - m_state = PassState::Queued; - } - } - } - - void Pass::QueueForInitialization() - { - // Don't queue if we're in initialization phase - if (m_queueState == PassQueueState::NoQueue) - { - PassSystemInterface::Get()->QueueForInitialization(this); - m_queueState = PassQueueState::QueuedForInitialization; - - if(m_state != PassState::Rendering) - { - m_state = PassState::Queued; - } - } - } - - void Pass::QueueForRemoval() - { - if (m_queueState != PassQueueState::QueuedForRemoval) - { - PassSystemInterface::Get()->QueueForRemoval(this); - m_queueState = PassQueueState::QueuedForRemoval; - - if (m_state != PassState::Rendering) - { - m_state = PassState::Queued; - } - } - } - // --- PassTemplate related functions --- void Pass::CreateBindingsFromTemplate() @@ -430,7 +387,7 @@ namespace AZ PassAttachmentBinding* localBinding = FindAttachmentBinding(slot); if (!localBinding) { - AZ_RPI_PASS_ERROR(false, "Pass::AttachBufferToSlot - Pass %s failed to find slot %s.", + AZ_RPI_PASS_ERROR(false, "Pass::AttachBufferToSlot - Pass [%s] failed to find slot [%s].", m_path.GetCStr(), slot.GetCStr()); return; } @@ -440,7 +397,7 @@ namespace AZ // handle the connected bindings if (localBinding->m_attachment) { - AZ_RPI_PASS_ERROR(false, "Pass::AttachBufferToSlot - Slot %s already has attachment %s.", + AZ_RPI_PASS_ERROR(false, "Pass::AttachBufferToSlot - Slot [%s] already has attachment [%s].", slot.GetCStr(), localBinding->m_attachment->m_name.GetCStr()); return; } @@ -462,7 +419,7 @@ namespace AZ PassAttachmentBinding* localBinding = FindAttachmentBinding(slot); if (!localBinding) { - AZ_RPI_PASS_ERROR(false, "Pass::AttachImageToSlot - Pass %s failed to find slot %s.", + AZ_RPI_PASS_ERROR(false, "Pass::AttachImageToSlot - Pass [%s] failed to find slot [%s].", m_path.GetCStr(), slot.GetCStr()); return; } @@ -472,7 +429,7 @@ namespace AZ // handle the connected bindings if (localBinding->m_attachment) { - AZ_RPI_PASS_ERROR(false, "Pass::AttachImageToSlot - Slot %s already has attachment %s.", + AZ_RPI_PASS_ERROR(false, "Pass::AttachImageToSlot - Slot [%s] already has attachment [%s].", slot.GetCStr(), localBinding->m_attachment->m_name.GetCStr()); return; } @@ -495,7 +452,7 @@ namespace AZ PassAttachmentBinding* localBinding = FindAttachmentBinding(connection.m_localSlot); if (!localBinding) { - AZ_RPI_PASS_ERROR(false, "Pass::ProcessConnection - Pass %s failed to find slot %s.", + AZ_RPI_PASS_ERROR(false, "Pass::ProcessConnection - Pass [%s] failed to find slot [%s].", m_path.GetCStr(), connection.m_localSlot.GetCStr()); return; @@ -517,7 +474,7 @@ namespace AZ { foundPass = true; const Ptr attachment = FindOwnedAttachment(connectedSlotName); - AZ_RPI_PASS_ERROR(attachment, "Pass::ProcessConnection - Pass %s doesn't own an attachment named %s.", + AZ_RPI_PASS_ERROR(attachment, "Pass::ProcessConnection - Pass [%s] doesn't own an attachment named [%s].", m_path.GetCStr(), connectedSlotName.GetCStr()); localBinding->SetAttachment(attachment); @@ -628,10 +585,10 @@ namespace AZ if (!outputBinding || !inputBinding) { - AZ_RPI_PASS_ERROR(inputBinding, "Pass::ProcessFallbackConnection - Pass %s failed to find input slot %s.", + AZ_RPI_PASS_ERROR(inputBinding, "Pass::ProcessFallbackConnection - Pass [%s] failed to find input slot [%s].", m_path.GetCStr(), connection.m_inputSlotName.GetCStr()); - AZ_RPI_PASS_ERROR(outputBinding, "Pass::ProcessFallbackConnection - Pass %s failed to find output slot %s.", + AZ_RPI_PASS_ERROR(outputBinding, "Pass::ProcessFallbackConnection - Pass [%s] failed to find output slot [%s].", m_path.GetCStr(), connection.m_outputSlotName.GetCStr()); return; @@ -641,10 +598,10 @@ namespace AZ if (!typesAreValid) { - AZ_RPI_PASS_ERROR(inputBinding->m_slotType == PassSlotType::Input, "Pass::ProcessFallbackConnection - Pass %s specifies fallback connection input %s, which is not an input.", + AZ_RPI_PASS_ERROR(inputBinding->m_slotType == PassSlotType::Input, "Pass::ProcessFallbackConnection - Pass [%s] specifies fallback connection input [%s], which is not an input.", m_path.GetCStr(), connection.m_inputSlotName.GetCStr()); - AZ_RPI_PASS_ERROR(outputBinding->m_slotType == PassSlotType::Output, "Pass::ProcessFallbackConnection - Pass %s specifies fallback connection output %s, which is not an output.", + AZ_RPI_PASS_ERROR(outputBinding->m_slotType == PassSlotType::Output, "Pass::ProcessFallbackConnection - Pass [%s] specifies fallback connection output [%s], which is not an output.", m_path.GetCStr(), connection.m_inputSlotName.GetCStr()); return; @@ -1038,7 +995,7 @@ namespace AZ // Check whether the template's slot allows this attachment if (m_template && !m_template->AttachmentFitsSlot(targetAttachment->m_descriptor, binding.m_name)) { - AZ_RPI_PASS_ERROR(false, "Pass::UpdateConnectedBinding - Attachment %s did not match the filters of input slot %s on pass %s.", + AZ_RPI_PASS_ERROR(false, "Pass::UpdateConnectedBinding - Attachment [%s] did not match the filters of input slot [%s] on pass [%s].", targetAttachment->m_name.GetCStr(), binding.m_name.GetCStr(), m_path.GetCStr()); @@ -1060,14 +1017,86 @@ namespace AZ } } - // --- Pass behavior functions --- + // --- Queuing functions with PassSystem --- - void Pass::Reset() +#define OLD_SCHOOL 1 + + void Pass::QueueForBuild() { - if (m_queueState != PassQueueState::QueuedForBuild || m_state != PassState::Queued) +#if OLD_SCHOOL + // Don't queue if we're in building phase + //if (PassSystemInterface::Get()->GetState() != RPI::PassSystemState::Building) { - return; + if (!m_flags.m_queuedForBuildAttachment) + { + PassSystemInterface::Get()->QueueForBuild(this); + m_flags.m_queuedForBuildAttachment = true; + + // Set these two flags to false since when queue build attachments request, they should all be already be false except one use + // case that the pass system processed all queued requests when active a scene. + // m_flags.m_alreadyPrepared = false; + + m_queueState = PassQueueState::QueuedForBuild; + + if (m_state != PassState::Rendering) + { + m_state = PassState::Queued; + } + + } + } +#else + // Don't queue if we're in building phase + if (m_state != PassState::Building && + (m_queueState == PassQueueState::NoQueue || m_queueState == PassQueueState::QueuedForInitialization)) + { + //if (PassSystemInterface::Get()->GetState() != RPI::PassSystemState::Building) + { + PassSystemInterface::Get()->QueueForBuild(this); + } + m_queueState = PassQueueState::QueuedForBuild; + + if (m_state != PassState::Rendering) + { + m_state = PassState::Queued; + } + } +#endif + } + + void Pass::QueueForInitialization() + { + // Only queue if the pass is not in any other queue + if (m_queueState == PassQueueState::NoQueue) + { + PassSystemInterface::Get()->QueueForInitialization(this); + m_queueState = PassQueueState::QueuedForInitialization; + + if (m_state != PassState::Rendering && m_state != PassState::Built) + { + m_state = PassState::Queued; + } + } + } + + void Pass::QueueForRemoval() + { + if (m_queueState != PassQueueState::QueuedForRemoval) + { + PassSystemInterface::Get()->QueueForRemoval(this); + m_queueState = PassQueueState::QueuedForRemoval; + + if (m_state != PassState::Rendering) + { + m_state = PassState::Queued; + } } + } + + // --- Pass behavior functions --- + + void Pass::Reset() + { m_state = PassState::Resetting; // Store references to imported attachments to underlying images and buffers aren't deleted during attachment building @@ -1083,19 +1112,37 @@ namespace AZ m_executeBeforePasses.clear(); ResetInternal(); + + m_state = PassState::Reset; } - void Pass::Build() + void Pass::Build(bool calledFromPassSystem) { - if (m_queueState != PassQueueState::QueuedForBuild || (m_state != PassState::Queued && m_state != PassState::Resetting)) + AZ_RPI_BREAK_ON_TARGET_PASS; + + bool execute = (m_state == PassState::Idle); + execute = execute || (m_state == PassState::Queued && m_queueState == PassQueueState::QueuedForBuild); + execute = execute || (m_state == PassState::Queued && m_queueState == PassQueueState::QueuedForInitialization); + +#if OLD_SCHOOL + AZ_Assert(!execute == m_flags.m_alreadyPrepared, "ANTON - EARLY OUT FLAGS do not match for pass BUILD!!"); + if (m_flags.m_alreadyPrepared) { return; } + m_flags.m_alreadyPrepared = true; +#else + if (!execute) + { + return; + } +#endif + + Reset(); + m_state = PassState::Building; m_queueState = PassQueueState::NoQueue; - AZ_RPI_BREAK_ON_TARGET_PASS; - // Bindings, inputs and attachments CreateBindingsFromTemplate(); SetupInputsFromRequest(); @@ -1116,32 +1163,51 @@ namespace AZ UpdateOwnedAttachments(); UpdateAttachmentUsageIndices(); - // Queue for Initialization - QueueForInitialization(); + m_state = PassState::Built; + + // If this pass's Build() wasn't called from the Pass System, then it was called by it's parent pass + // In which case we don't need to queue for initialization because the parent will already be queued + if (calledFromPassSystem) + { + // Queue for Initialization + QueueForInitialization(); + } } - void Pass::OnBuildFinished() + void Pass::Initialize() { AZ_RPI_BREAK_ON_TARGET_PASS; - m_flags.m_alreadyCreated = false; - m_importedAttachmentStore.clear(); - OnBuildFinishedInternal(); - } + bool execute = (m_state == PassState::Idle || m_state == PassState::Built); + execute = execute || (m_state == PassState::Queued && m_queueState == PassQueueState::QueuedForInitialization); - void Pass::Initialize() - { - if (m_queueState != PassQueueState::QueuedForInitialization || m_state != PassState::Queued) + if (!execute) { return; } - m_queueState = PassQueueState::NoQueue; m_state = PassState::Initializing; + m_queueState = PassQueueState::NoQueue; + InitializeInternal(); + m_state = PassState::Initialized; } + void Pass::OnInitializationFinished() + { + AZ_RPI_BREAK_ON_TARGET_PASS; + + m_flags.m_alreadyPrepared = false; + m_flags.m_queuedForBuildAttachment = false; + + m_flags.m_alreadyCreated = false; + m_importedAttachmentStore.clear(); + OnInitializationFinishedInternal(); + + m_state = PassState::Idle; + } + void Pass::Validate(PassValidationResults& validationResults) { if (PassValidation::IsEnabled()) @@ -1195,6 +1261,8 @@ namespace AZ UpdateConnectedBindings(); return; } + + AZ_Assert(m_state == PassState::Idle, "Pass::FrameBegin - Pass [%s] is attempting to render, but is not in the Idle state.", m_path.GetCStr()); m_state = PassState::Rendering; UpdateConnectedBindings(); @@ -1213,7 +1281,7 @@ namespace AZ if (m_state == PassState::Rendering) { FrameEndInternal(); - m_state = (m_queueState == PassQueueState::NoQueue) ? PassState::Initialized : PassState::Queued; + m_state = (m_queueState == PassQueueState::NoQueue) ? PassState::Idle : PassState::Queued; } } @@ -1578,6 +1646,8 @@ namespace AZ } } +#pragma optimize("", on) + } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp index 0c38b228f5..abcaa181d8 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp @@ -50,6 +50,8 @@ namespace AZ { namespace RPI { +#pragma optimize("", off) + PassSystemInterface* PassSystemInterface::Get() { return Interface::Get(); @@ -101,6 +103,8 @@ namespace AZ m_rootPass = CreatePass(Name{"Root"}); m_rootPass->m_flags.m_partOfHierarchy = true; + //m_targetedPassDebugName = "RPISamplePipeline"; + m_state = PassSystemState::Idle; } @@ -189,7 +193,8 @@ namespace AZ AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzRender); AZ_ATOM_PROFILE_FUNCTION("RPI", "PassSystem: BuildPassAttachments"); - m_passHierarchyChanged = !m_buildPassList.empty(); + m_passHierarchyChanged = m_passHierarchyChanged || !m_buildPassList.empty(); + u32 loopCounter = 0; // While loop is for the event in which passes being built add more pass to m_buildPassList while(!m_buildPassList.empty()) @@ -211,19 +216,13 @@ namespace AZ for (const Ptr& pass : buildListCopy) { - pass->Reset(); - } - for (const Ptr& pass : buildListCopy) - { - pass->Build(); + pass->Build(true); } + loopCounter++; } if (m_passHierarchyChanged) { - // Signal all passes that we have finished building - m_rootPass->OnBuildFinished(); - #if AZ_RPI_ENABLE_PASS_DEBUGGING if (!m_isHotReloading) { @@ -242,6 +241,9 @@ namespace AZ AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzRender); AZ_ATOM_PROFILE_FUNCTION("RPI", "PassSystem: BuildPassAttachments"); + m_passHierarchyChanged = m_passHierarchyChanged || !m_initializePassList.empty(); + u32 loopCounter = 0; + while (!m_initializePassList.empty()) { AZStd::vector< Ptr > initListCopy = m_initializePassList; @@ -261,6 +263,13 @@ namespace AZ { pass->Initialize(); } + loopCounter++; + } + + if (m_passHierarchyChanged) + { + // Signal all passes that we have finished initialization + m_rootPass->OnInitializationFinished(); } m_state = PassSystemState::Idle; @@ -474,5 +483,6 @@ namespace AZ return nullptr; } +#pragma optimize("", on) } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp index 12989fb873..3e52130f6f 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp @@ -128,7 +128,7 @@ namespace AZ } - void RenderPass::OnBuildFinishedInternal() + void RenderPass::InitializeInternal() { if (m_shaderResourceGroup != nullptr) { From c6d0887210c367f58b086d90f5f20759887d5e72 Mon Sep 17 00:00:00 2001 From: moudgils Date: Sun, 6 Jun 2021 10:24:42 -0700 Subject: [PATCH 06/73] Minor method name changes --- Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp | 8 ++++---- Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp index 1e2edc6520..5d6c275184 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp @@ -422,12 +422,12 @@ namespace AZ { if(RHI::CheckBitsAny(visMaskIt->second, RHI::ShaderStageMask::Compute)) { - ApplyUseResourceToCompute(commandEncoder, it.second, resourcesToMakeResidentCompute); + CollectResourcesForCompute(commandEncoder, it.second, resourcesToMakeResidentCompute); } else { AZ_Assert(RHI::CheckBitsAny(visMaskIt->second, RHI::ShaderStageMask::Vertex) || RHI::CheckBitsAny(visMaskIt->second, RHI::ShaderStageMask::Fragment), "The visibility mask %i is not set for Vertex or fragment stage", visMaskIt->second); - ApplyUseResourceToGraphic(commandEncoder, visMaskIt->second, it.second, resourcesToMakeResidentGraphics); + CollectResourcesForGraphics(commandEncoder, visMaskIt->second, it.second, resourcesToMakeResidentGraphics); } } } @@ -450,7 +450,7 @@ namespace AZ } } - void ArgumentBuffer::ApplyUseResourceToCompute(id encoder, const ResourceBindingsSet& resourceBindingDataSet, ComputeResourcesToMakeResidentMap& resourcesToMakeResidentMap) const + void ArgumentBuffer::CollectResourcesForCompute(id encoder, const ResourceBindingsSet& resourceBindingDataSet, ComputeResourcesToMakeResidentMap& resourcesToMakeResidentMap) const { for (const auto& resourceBindingData : resourceBindingDataSet) { @@ -477,7 +477,7 @@ namespace AZ } } - void ArgumentBuffer::ApplyUseResourceToGraphic(id encoder, RHI::ShaderStageMask visShaderMask, const ResourceBindingsSet& resourceBindingDataSet, GraphicsResourcesToMakeResidentMap& resourcesToMakeResidentMap) const + void ArgumentBuffer::CollectResourcesForGraphics(id encoder, RHI::ShaderStageMask visShaderMask, const ResourceBindingsSet& resourceBindingDataSet, GraphicsResourcesToMakeResidentMap& resourcesToMakeResidentMap) const { MTLRenderStages mtlRenderStages = GetRenderStages(visShaderMask); diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h index 2434b8312d..06380162b6 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h @@ -128,8 +128,8 @@ namespace AZ using ComputeResourcesToMakeResidentMap = AZStd::unordered_map; using GraphicsResourcesToMakeResidentMap = AZStd::unordered_map, MetalResourceArray>; - void ApplyUseResourceToCompute(id encoder, const ResourceBindingsSet& resourceBindingData, ComputeResourcesToMakeResidentMap& resourcesToMakeResidentMap) const; - void ApplyUseResourceToGraphic(id encoder, RHI::ShaderStageMask visShaderMask, const ResourceBindingsSet& resourceBindingDataSet, GraphicsResourcesToMakeResidentMap& resourcesToMakeResidentMap) const; + void CollectResourcesForCompute(id encoder, const ResourceBindingsSet& resourceBindingData, ComputeResourcesToMakeResidentMap& resourcesToMakeResidentMap) const; + void CollectResourcesForGraphics(id encoder, RHI::ShaderStageMask visShaderMask, const ResourceBindingsSet& resourceBindingDataSet, GraphicsResourcesToMakeResidentMap& resourcesToMakeResidentMap) const; //! Use visibility information to call UseResource on all resources for this Argument Buffer void ApplyUseResource(id encoder, const ResourceBindingsMap& resourceMap, From 9d7119a7f84a8f19db2d60da6ba3ea174e8c6461 Mon Sep 17 00:00:00 2001 From: antonmic Date: Sun, 6 Jun 2021 21:51:49 -0700 Subject: [PATCH 07/73] Pass Changes WIP: fixed bloom pass --- .../Code/Include/Atom/RPI.Public/Pass/Pass.h | 2 +- .../Source/RPI.Public/Pass/ParentPass.cpp | 8 ++--- .../RPI/Code/Source/RPI.Public/Pass/Pass.cpp | 33 +++++++++++++++++-- .../Source/RPI.Public/Pass/PassSystem.cpp | 4 +++ 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h index 3cab5b36e4..64daf1006d 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h @@ -396,8 +396,8 @@ namespace AZ uint64_t m_alreadyCreated : 1; // OLD SCHOOL - uint64_t m_alreadyReset : 1; uint64_t m_alreadyPrepared : 1; + uint64_t m_alreadyReset : 1; uint64_t m_queuedForBuildAttachment : 1; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp index ad361bdf42..6b95a6e17a 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp @@ -270,10 +270,10 @@ namespace AZ void ParentPass::ResetInternal() { - //for (const Ptr& child : m_children) - //{ - // child->Reset(); - //} + for (const Ptr& child : m_children) + { + child->Reset(); + } } void ParentPass::BuildInternal() diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp index 790a1e767f..391db8361d 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp @@ -75,6 +75,10 @@ namespace AZ PassSystemInterface::Get()->RegisterPass(this); QueueForBuild(); + + // Skip reset since the pass just got created + m_state = PassState::Reset; + m_flags.m_alreadyReset = true; } Pass::~Pass() @@ -1034,6 +1038,7 @@ namespace AZ // Set these two flags to false since when queue build attachments request, they should all be already be false except one use // case that the pass system processed all queued requests when active a scene. + // m_flags.m_alreadyReset = false; // m_flags.m_alreadyPrepared = false; m_queueState = PassQueueState::QueuedForBuild; @@ -1097,6 +1102,24 @@ namespace AZ void Pass::Reset() { + bool execute = (m_state == PassState::Idle); + execute = execute || (m_state == PassState::Queued && m_queueState == PassQueueState::QueuedForBuild); + execute = execute || (m_state == PassState::Queued && m_queueState == PassQueueState::QueuedForInitialization); + +#if OLD_SCHOOL + AZ_Assert(!execute == m_flags.m_alreadyReset, "ANTON - EARLY OUT FLAGS do not match for pass BUILD!!"); + if (m_flags.m_alreadyReset) + { + return; + } + m_flags.m_alreadyReset = true; +#else + if (!execute) + { + return; + } +#endif + m_state = PassState::Resetting; // Store references to imported attachments to underlying images and buffers aren't deleted during attachment building @@ -1120,7 +1143,7 @@ namespace AZ { AZ_RPI_BREAK_ON_TARGET_PASS; - bool execute = (m_state == PassState::Idle); + bool execute = (m_state == PassState::Idle || m_state == PassState::Reset); execute = execute || (m_state == PassState::Queued && m_queueState == PassQueueState::QueuedForBuild); execute = execute || (m_state == PassState::Queued && m_queueState == PassQueueState::QueuedForInitialization); @@ -1138,7 +1161,7 @@ namespace AZ } #endif - Reset(); + //Reset(); m_state = PassState::Building; m_queueState = PassQueueState::NoQueue; @@ -1189,6 +1212,11 @@ namespace AZ m_state = PassState::Initializing; m_queueState = PassQueueState::NoQueue; + // Update +// UpdateConnectedBindings(); +// UpdateOwnedAttachments(); +// UpdateAttachmentUsageIndices(); + InitializeInternal(); m_state = PassState::Initialized; @@ -1198,6 +1226,7 @@ namespace AZ { AZ_RPI_BREAK_ON_TARGET_PASS; + m_flags.m_alreadyReset = false; m_flags.m_alreadyPrepared = false; m_flags.m_queuedForBuildAttachment = false; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp index abcaa181d8..bbd9ac7df8 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp @@ -214,6 +214,10 @@ namespace AZ SortPassListAscending(buildListCopy); + for (const Ptr& pass : buildListCopy) + { + pass->Reset(); + } for (const Ptr& pass : buildListCopy) { pass->Build(true); From bd7c5f4ee2aa2a8f98d32c9a8df767ded2e7ca9f Mon Sep 17 00:00:00 2001 From: antonmic Date: Mon, 7 Jun 2021 08:39:08 -0700 Subject: [PATCH 08/73] Pass changes WIP: small improvements --- .../RPI/Code/Source/RPI.Public/Pass/Pass.cpp | 10 ++++----- .../Source/RPI.Public/Pass/PassSystem.cpp | 21 ++++++++++++++++--- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp index 391db8361d..e53ffbf122 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp @@ -1027,7 +1027,7 @@ namespace AZ void Pass::QueueForBuild() { -#if OLD_SCHOOL +#if 0//OLD_SCHOOL // Don't queue if we're in building phase //if (PassSystemInterface::Get()->GetState() != RPI::PassSystemState::Building) { @@ -1107,7 +1107,7 @@ namespace AZ execute = execute || (m_state == PassState::Queued && m_queueState == PassQueueState::QueuedForInitialization); #if OLD_SCHOOL - AZ_Assert(!execute == m_flags.m_alreadyReset, "ANTON - EARLY OUT FLAGS do not match for pass BUILD!!"); + AZ_Assert(!execute == m_flags.m_alreadyReset, "ANTON - EARLY OUT FLAGS do not match for pass RESET!!"); if (m_flags.m_alreadyReset) { return; @@ -1143,6 +1143,8 @@ namespace AZ { AZ_RPI_BREAK_ON_TARGET_PASS; + AZ_Assert(m_state == PassState::Reset, "ANTON - BUILDING PASS BUT STATE IS NOT RESET!!"); + bool execute = (m_state == PassState::Idle || m_state == PassState::Reset); execute = execute || (m_state == PassState::Queued && m_queueState == PassQueueState::QueuedForBuild); execute = execute || (m_state == PassState::Queued && m_queueState == PassQueueState::QueuedForInitialization); @@ -1161,10 +1163,7 @@ namespace AZ } #endif - //Reset(); - m_state = PassState::Building; - m_queueState = PassQueueState::NoQueue; // Bindings, inputs and attachments CreateBindingsFromTemplate(); @@ -1187,6 +1186,7 @@ namespace AZ UpdateAttachmentUsageIndices(); m_state = PassState::Built; + m_queueState = PassQueueState::NoQueue; // If this pass's Build() wasn't called from the Pass System, then it was called by it's parent pass // In which case we don't need to queue for initialization because the parent will already be queued diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp index bbd9ac7df8..a7021ee6fd 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp @@ -214,13 +214,23 @@ namespace AZ SortPassListAscending(buildListCopy); + Pass* previousPassInList = nullptr; for (const Ptr& pass : buildListCopy) { - pass->Reset(); + if (pass.get() != previousPassInList); + { + pass->Reset(); + previousPassInList = pass.get(); + } } + previousPassInList = nullptr; for (const Ptr& pass : buildListCopy) { - pass->Build(true); + if (pass.get() != previousPassInList); + { + pass->Build(true); + previousPassInList = pass.get(); + } } loopCounter++; } @@ -263,9 +273,14 @@ namespace AZ SortPassListAscending(initListCopy); + Pass* previousPassInList = nullptr; for (const Ptr& pass : initListCopy) { - pass->Initialize(); + if (pass.get() != previousPassInList); + { + pass->Initialize(); + previousPassInList = pass.get(); + } } loopCounter++; } From a30d9621d5e930d66fc6ed7fda4fdb2b288866ae Mon Sep 17 00:00:00 2001 From: antonmic Date: Mon, 7 Jun 2021 23:05:36 -0700 Subject: [PATCH 09/73] Pass changes WIP: various fixes, exposure sample now works --- .../Code/Source/CoreLights/LightCullingTilePreparePass.cpp | 2 +- .../Feature/Common/Code/Source/PostProcessing/TaaPass.cpp | 4 ++-- .../Feature/Common/Code/Source/PostProcessing/TaaPass.h | 2 +- Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp | 3 +-- Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp | 6 +++--- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.cpp index c144525cec..4f2a4f0346 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.cpp @@ -176,7 +176,7 @@ namespace AZ { LoadShader(); AZ_Assert(GetPassState() != RPI::PassState::Rendering, "LightCullingTilePreparePass: Trying to reload shader during rendering"); - if (GetPassState() == RPI::PassState::Initialized) + if (GetPassState() == RPI::PassState::Idle) { ChooseShaderVariant(); } diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/TaaPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/TaaPass.cpp index 9f885ede70..38e03ab156 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/TaaPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/TaaPass.cpp @@ -108,7 +108,7 @@ namespace AZ::Render Base::ResetInternal(); } - void TaaPass::BuildAttachmentsInternal() + void TaaPass::BuildInternal() { m_accumulationAttachments[0] = FindAttachment(Name("Accumulation1")); m_accumulationAttachments[1] = FindAttachment(Name("Accumulation2")); @@ -143,7 +143,7 @@ namespace AZ::Render m_outputColorBinding->SetAttachment(m_accumulationAttachments[1]); } - Base::BuildAttachmentsInternal(); + Base::BuildInternal(); } void TaaPass::UpdateAttachmentImage(RPI::Ptr& attachment) diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/TaaPass.h b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/TaaPass.h index 6133720691..e8f4796e7b 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/TaaPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/TaaPass.h @@ -63,7 +63,7 @@ namespace AZ::Render // Pass behavior overrides... void FrameBeginInternal(FramePrepareParams params) override; void ResetInternal() override; - void BuildAttachmentsInternal() override; + void BuildInternal() override; void UpdateAttachmentImage(RPI::Ptr& attachment); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp index 4002216361..78e30e7176 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp @@ -1160,8 +1160,6 @@ namespace AZ { AZ_RPI_BREAK_ON_TARGET_PASS; - AZ_Assert(m_state == PassState::Reset, "ANTON - BUILDING PASS BUT STATE IS NOT RESET!!"); - bool execute = (m_state == PassState::Idle || m_state == PassState::Reset); execute = execute || (m_state == PassState::Queued && m_queueState == PassQueueState::QueuedForBuild); execute = execute || (m_state == PassState::Queued && m_queueState == PassQueueState::QueuedForInitialization); @@ -1180,6 +1178,7 @@ namespace AZ } #endif + AZ_Assert(m_state == PassState::Reset, "ANTON - BUILDING PASS BUT STATE IS NOT RESET!!"); m_state = PassState::Building; // Bindings, inputs and attachments diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp index a7021ee6fd..76ea52b4a3 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp @@ -217,7 +217,7 @@ namespace AZ Pass* previousPassInList = nullptr; for (const Ptr& pass : buildListCopy) { - if (pass.get() != previousPassInList); + if (pass.get() != previousPassInList) { pass->Reset(); previousPassInList = pass.get(); @@ -226,7 +226,7 @@ namespace AZ previousPassInList = nullptr; for (const Ptr& pass : buildListCopy) { - if (pass.get() != previousPassInList); + if (pass.get() != previousPassInList) { pass->Build(true); previousPassInList = pass.get(); @@ -276,7 +276,7 @@ namespace AZ Pass* previousPassInList = nullptr; for (const Ptr& pass : initListCopy) { - if (pass.get() != previousPassInList); + if (pass.get() != previousPassInList) { pass->Initialize(); previousPassInList = pass.get(); From 6973d9c7a3c4593b66aadea908d8c097248f3c20 Mon Sep 17 00:00:00 2001 From: antonmic Date: Tue, 8 Jun 2021 12:03:58 -0700 Subject: [PATCH 10/73] Pass changes WIP: moved child pass creation to Build phase --- .../DisplayMapper/DisplayMapperPass.cpp | 68 ++++--------------- .../Source/LuxCore/LuxCoreTexturePass.cpp | 4 -- .../DepthOfFieldReadBackFocusDepthPass.cpp | 33 +++++---- .../DepthOfFieldReadBackFocusDepthPass.h | 1 + .../ReflectionScreenSpaceBlurPass.cpp | 8 +-- .../ReflectionScreenSpaceBlurPass.h | 3 +- .../Include/Atom/RPI.Public/Pass/ParentPass.h | 2 +- .../Code/Include/Atom/RPI.Public/Pass/Pass.h | 2 + .../Source/RPI.Public/Pass/ParentPass.cpp | 15 ++-- .../Pass/Specific/EnvironmentCubeMapPass.cpp | 4 -- .../Pass/Specific/SwapChainPass.cpp | 4 -- .../Code/Source/RPI.Public/RenderPipeline.cpp | 2 + 12 files changed, 49 insertions(+), 97 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp index b6fa0b5c41..f5b301ca5c 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp @@ -46,8 +46,6 @@ namespace AZ DisplayMapperPass::DisplayMapperPass(const RPI::PassDescriptor& descriptor) : RPI::ParentPass(descriptor) { - m_flags.m_alreadyCreated = false; - AzFramework::NativeWindowHandle windowHandle = nullptr; AzFramework::WindowSystemRequestBus::BroadcastResult( windowHandle, @@ -61,8 +59,6 @@ namespace AZ { m_displayMapperConfigurationDescriptor = passData->m_config; } - - m_needToRebuildChildren = true; } DisplayMapperPass::~DisplayMapperPass() @@ -199,24 +195,14 @@ namespace AZ void DisplayMapperPass::FrameEndInternal() { GetDisplayMapperConfiguration(); - if (m_needToRebuildChildren) - { - ClearChildren(); - BuildGradingLutTemplate(); - CreateGradingAndAcesPasses(); - } ParentPass::FrameEndInternal(); } void DisplayMapperPass::CreateChildPassesInternal() { - if (m_needToRebuildChildren) - { - ClearChildren(); - BuildGradingLutTemplate(); - CreateGradingAndAcesPasses(); - } - ParentPass::CreateChildPassesInternal(); + ClearChildren(); + BuildGradingLutTemplate(); + CreateGradingAndAcesPasses(); } AZStd::shared_ptr CreatePassTemplateHelper( @@ -485,7 +471,6 @@ namespace AZ { AddChild(m_ldrGradingLookupTablePass); } - m_needToRebuildChildren = false; } void DisplayMapperPass::GetDisplayMapperConfiguration() @@ -513,7 +498,8 @@ namespace AZ desc.m_ldrColorGradingLut != m_displayMapperConfigurationDescriptor.m_ldrColorGradingLut || desc.m_acesParameterOverrides.m_overrideDefaults != m_displayMapperConfigurationDescriptor.m_acesParameterOverrides.m_overrideDefaults) { - m_needToRebuildChildren = true; + m_flags.m_createChildren = true; + QueueForBuild(); } m_displayMapperConfigurationDescriptor = desc; } @@ -527,41 +513,15 @@ namespace AZ void DisplayMapperPass::ClearChildren() { - if (m_acesOutputTransformPass) - { - RemoveChild(m_acesOutputTransformPass); - m_acesOutputTransformPass = nullptr; - } - if (m_bakeAcesOutputTransformLutPass) - { - RemoveChild(m_bakeAcesOutputTransformLutPass); - m_bakeAcesOutputTransformLutPass = nullptr; - } - if (m_acesOutputTransformLutPass) - { - RemoveChild(m_acesOutputTransformLutPass); - m_acesOutputTransformLutPass = nullptr; - } - if (m_displayMapperPassthroughPass) - { - RemoveChild(m_displayMapperPassthroughPass); - m_displayMapperPassthroughPass = nullptr; - } - if (m_displayMapperOnlyGammaCorrectionPass) - { - RemoveChild(m_displayMapperOnlyGammaCorrectionPass); - m_displayMapperOnlyGammaCorrectionPass = nullptr; - } - if (m_ldrGradingLookupTablePass) - { - RemoveChild(m_ldrGradingLookupTablePass); - m_ldrGradingLookupTablePass = nullptr; - } - if (m_outputTransformPass) - { - RemoveChild(m_outputTransformPass); - m_outputTransformPass = nullptr; - } + RemoveChildren(); + + m_acesOutputTransformPass = nullptr; + m_bakeAcesOutputTransformLutPass = nullptr; + m_acesOutputTransformLutPass = nullptr; + m_displayMapperPassthroughPass = nullptr; + m_displayMapperOnlyGammaCorrectionPass = nullptr; + m_ldrGradingLookupTablePass = nullptr; + m_outputTransformPass = nullptr; } } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreTexturePass.cpp b/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreTexturePass.cpp index 7708605e29..724511b355 100644 --- a/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreTexturePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreTexturePass.cpp @@ -28,8 +28,6 @@ namespace AZ LuxCoreTexturePass::LuxCoreTexturePass(const RPI::PassDescriptor& descriptor) : ParentPass(descriptor) { - m_flags.m_alreadyCreated = false; - RPI::PassSystemInterface* passSystem = RPI::PassSystemInterface::Get(); // Create render target pass @@ -41,8 +39,6 @@ namespace AZ // Create readback m_readback = AZStd::make_shared(AZ::RHI::ScopeId{ Uuid::CreateRandom().ToString() }); - - CreateChildPasses(); } LuxCoreTexturePass::~LuxCoreTexturePass() diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldReadBackFocusDepthPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldReadBackFocusDepthPass.cpp index c355b7c8a7..6050ac2b2e 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldReadBackFocusDepthPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldReadBackFocusDepthPass.cpp @@ -34,18 +34,6 @@ namespace AZ DepthOfFieldReadBackFocusDepthPass::DepthOfFieldReadBackFocusDepthPass(const RPI::PassDescriptor& descriptor) : ParentPass(descriptor) { - RPI::PassSystemInterface* passSystem = RPI::PassSystemInterface::Get(); - - // Create read back pass - m_readbackPass = passSystem->CreatePass(AZ::Name("DepthOfFieldReadBackPass")); - AZ_Assert(m_readbackPass, "DepthOfFieldReadBackFocusDepthPass : read back pass is invalid"); - - AddChild(m_readbackPass); - - // Find GetDepth pass on template - auto pass = FindChildPass(Name("DepthOfFieldWriteFocusDepthFromGpu")); - m_getDepthPass = static_cast(pass.get()); - // Create buffer for read back focus depth. We append static counter to avoid name conflicts. RPI::CommonBufferDescriptor desc; desc.m_bufferName = "DepthOfFieldReadBackAutoFocusDepthBuffer"; @@ -55,9 +43,6 @@ namespace AZ desc.m_bufferData = nullptr; desc.m_elementFormat = RHI::Format::R32_FLOAT; m_buffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); - - m_getDepthPass->SetBufferRef(m_buffer); - m_readbackPass->SetBufferRef(m_buffer); } DepthOfFieldReadBackFocusDepthPass::~DepthOfFieldReadBackFocusDepthPass() @@ -85,6 +70,24 @@ namespace AZ } } + void DepthOfFieldReadBackFocusDepthPass::CreateChildPassesInternal() + { + RPI::PassSystemInterface* passSystem = RPI::PassSystemInterface::Get(); + + // Create read back pass + m_readbackPass = passSystem->CreatePass(AZ::Name("DepthOfFieldReadBackPass")); + AZ_Assert(m_readbackPass, "DepthOfFieldReadBackFocusDepthPass : read back pass is invalid"); + + AddChild(m_readbackPass); + + // Find GetDepth pass on template + auto pass = FindChildPass(Name("DepthOfFieldWriteFocusDepthFromGpu")); + m_getDepthPass = static_cast(pass.get()); + + m_getDepthPass->SetBufferRef(m_buffer); + m_readbackPass->SetBufferRef(m_buffer); + } + void DepthOfFieldReadBackFocusDepthPass::FrameBeginInternal(FramePrepareParams params) { RPI::Scene* scene = GetScene(); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldReadBackFocusDepthPass.h b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldReadBackFocusDepthPass.h index 75842fb67a..db29576d22 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldReadBackFocusDepthPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldReadBackFocusDepthPass.h @@ -43,6 +43,7 @@ namespace AZ protected: // Pass behavior overrides... + void CreateChildPassesInternal() override; void FrameBeginInternal(FramePrepareParams params) override; private: diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp index 680d117b98..631ff803dd 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp @@ -47,7 +47,7 @@ namespace AZ RemoveChildren(); } - void ReflectionScreenSpaceBlurPass::CreateChildPasses(uint32_t numBlurMips) + void ReflectionScreenSpaceBlurPass::CreateChildPassesInternal() { RPI::PassSystemInterface* passSystem = RPI::PassSystemInterface::Get(); @@ -83,7 +83,7 @@ namespace AZ horizontalBlurChildDesc.m_passTemplate = blurHorizontalPassTemplate; // add child passes to perform the vertical and horizontal Gaussian blur for each roughness mip level - for (uint32_t mip = 0; mip < numBlurMips; ++mip) + for (uint32_t mip = 0; mip < m_numBlurMips; ++mip) { // create Vertical blur child passes { @@ -116,6 +116,7 @@ namespace AZ void ReflectionScreenSpaceBlurPass::BuildInternal() { RemoveChildren(); + m_flags.m_createChildren = true; Data::Instance pool = RPI::ImageSystemInterface::Get()->GetSystemAttachmentPool(); @@ -163,8 +164,7 @@ namespace AZ m_ownedAttachments.push_back(transientPassAttachment); } - // create child passes, one vertical and one horizontal blur per mip level - CreateChildPasses(mipLevels - 1); + m_numBlurMips = mipLevels - 1; // call ParentPass::BuildInternal() first to configure the slots and auto-add the empty bindings, // then we will assign attachments to the bindings diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.h b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.h index f344fc8e9b..4a2ccce1d4 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.h @@ -40,7 +40,7 @@ namespace AZ private: explicit ReflectionScreenSpaceBlurPass(const RPI::PassDescriptor& descriptor); - void CreateChildPasses(uint32_t numBlurMips); + void CreateChildPassesInternal() override; // Pass Overrides... void ResetInternal() override; @@ -50,6 +50,7 @@ namespace AZ AZStd::vector> m_horizontalBlurChildPasses; Data::Instance m_frameBufferImageAttachment; + uint32_t m_numBlurMips = 0; }; } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h index ca7baf1a0f..727398040d 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h @@ -118,7 +118,7 @@ namespace AZ // Finds the pass in m_children and removes it void RemoveChild(Ptr pass); - // Orphans all children from clearing m_children. + // Orphans all children by clearing m_children. void RemoveChildren(); private: diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h index a184e8ed32..1cfd2e759e 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h @@ -40,6 +40,7 @@ friend class PassSystem; \ friend class PassFactory; \ friend class ParentPass; \ + friend class RenderPipeline; \ friend class UnitTest::PassTests; \ namespace UnitTest @@ -394,6 +395,7 @@ namespace AZ uint64_t m_initialized : 1; uint64_t m_alreadyCreated : 1; + uint64_t m_createChildren : 1; // OLD SCHOOL uint64_t m_alreadyPrepared : 1; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp index 6b95a6e17a..e06ffca556 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp @@ -40,7 +40,7 @@ namespace AZ ParentPass::ParentPass(const PassDescriptor& descriptor) : Pass(descriptor) { - CreateChildPasses(); + m_flags.m_createChildren = true; } ParentPass::~ParentPass() @@ -248,7 +248,7 @@ namespace AZ void ParentPass::CreateChildPasses() { - if (m_flags.m_alreadyCreated) + if (!m_flags.m_createChildren || m_flags.m_alreadyCreated) { return; } @@ -258,14 +258,7 @@ namespace AZ CreatePassesFromTemplate(); CreateChildPassesInternal(); - for (Ptr& child : m_children) - { - ParentPass* asParent = child->AsParent(); - if (asParent != nullptr) - { - asParent->CreateChildPasses(); - } - } + m_flags.m_createChildren = false; } void ParentPass::ResetInternal() @@ -278,6 +271,8 @@ namespace AZ void ParentPass::BuildInternal() { + CreateChildPasses(); + for (const Ptr& child : m_children) { child->Build(); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/EnvironmentCubeMapPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/EnvironmentCubeMapPass.cpp index be06343ab9..28a03de297 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/EnvironmentCubeMapPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/EnvironmentCubeMapPass.cpp @@ -37,8 +37,6 @@ namespace AZ EnvironmentCubeMapPass::EnvironmentCubeMapPass(const PassDescriptor& passDescriptor) : ParentPass(passDescriptor) { - m_flags.m_alreadyCreated = false; - // load pass data const EnvironmentCubeMapPassData* passData = PassUtils::GetPassData(passDescriptor); if (passData == nullptr) @@ -88,8 +86,6 @@ namespace AZ AZ::Matrix4x4 viewToClipMatrix; MakePerspectiveFovMatrixRH(viewToClipMatrix, AZ::Constants::HalfPi, 1.0f, 0.1f, 100.0f, true); m_view->SetViewToClipMatrix(viewToClipMatrix); - - CreateChildPasses(); } EnvironmentCubeMapPass::~EnvironmentCubeMapPass() diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SwapChainPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SwapChainPass.cpp index 45fb890e91..a7add17042 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SwapChainPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SwapChainPass.cpp @@ -26,8 +26,6 @@ namespace AZ , m_windowContext(windowContext) , m_childTemplateName(childTemplateName) { - m_flags.m_alreadyCreated = false; - PassSystemInterface* passSystem = PassSystemInterface::Get(); // Create child pass @@ -44,8 +42,6 @@ namespace AZ m_childPass = passSystem->CreatePassFromRequest(&childRequest); AZ_Assert(m_childPass, "SwapChain child pass is invalid: check your passs pipeline, run configuration and your AssetProcessor set project (project_path)"); - - CreateChildPasses(); AzFramework::WindowNotificationBus::Handler::BusConnect(m_windowContext->GetWindowHandle()); } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp index 86d76287bb..2c4c61f5aa 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp @@ -107,6 +107,8 @@ namespace AZ pipeline->m_originalRenderSettings = desc.m_renderSettings; pipeline->m_activeRenderSettings = desc.m_renderSettings; pipeline->m_rootPass->SetRenderPipeline(pipeline); + pipeline->m_rootPass->Build(); + pipeline->m_rootPass->Initialize(); pipeline->BuildPipelineViews(); } From dba1832821adac79d9fecc55b77e3cfff1cad5d9 Mon Sep 17 00:00:00 2001 From: AMZN-koppersr <82230785+AMZN-koppersr@users.noreply.github.com> Date: Mon, 7 Jun 2021 16:58:08 -0700 Subject: [PATCH 11/73] Improved reporting on unsupported types by the Json Serialization The Json Serialization currently doesn't support AZStd::any, AZStd::variant and AZStd::optional due to various JSON formatting concerns. This wasn't properly reported resulting in confusion about whether the missing functionality is intentional or a bug. This change makes this explicit with an error message. As this solution uses a custom json serializer to report the issue, an option was added so it's possible to overwrite a serializer for a specific type. This doesn't mean that the three listed types will never be supported. If/when a suitable format is found an implementation will be added. --- .../Json/JsonSystemComponent.cpp | 15 +- .../Json/RegistrationContext.cpp | 38 ++--- .../Serialization/Json/RegistrationContext.h | 32 ++-- .../Json/UnsupportedTypesSerializer.cpp | 56 +++++++ .../Json/UnsupportedTypesSerializer.h | 72 +++++++++ .../AzCore/AzCore/azcore_files.cmake | 2 + .../Json/JsonRegistrationContextTests.cpp | 30 ++++ .../Json/UnsupportedTypesSerializerTests.cpp | 143 ++++++++++++++++++ .../AzCore/Tests/azcoretests_files.cmake | 1 + 9 files changed, 353 insertions(+), 36 deletions(-) create mode 100644 Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.cpp create mode 100644 Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.h create mode 100644 Code/Framework/AzCore/Tests/Serialization/Json/UnsupportedTypesSerializerTests.cpp diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSystemComponent.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSystemComponent.cpp index 6e3c8cec60..8fe1bf50e2 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSystemComponent.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSystemComponent.cpp @@ -24,7 +24,12 @@ #include #include #include +#include #include +#include +#include +#include +#include #include #include #include @@ -33,12 +38,11 @@ #include #include #include +#include #include #include #include #include -#include -#include namespace AZ { @@ -98,6 +102,13 @@ namespace AZ jsonContext->Serializer() ->HandlesType(); + jsonContext->Serializer() + ->HandlesType(); + jsonContext->Serializer() + ->HandlesType(); + jsonContext->Serializer() + ->HandlesType(); + MathReflect(jsonContext); } else if (SerializeContext* serializeContext = azrtti_cast(reflectContext)) diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/RegistrationContext.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/RegistrationContext.cpp index 552b16a731..50ea08e0a0 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/RegistrationContext.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/RegistrationContext.cpp @@ -33,34 +33,38 @@ namespace AZ , m_serializerIter(serializerMapIter) {} - JsonRegistrationContext::SerializerBuilder* JsonRegistrationContext::SerializerBuilder::HandlesTypeId(const Uuid& uuid) + JsonRegistrationContext::SerializerBuilder* JsonRegistrationContext::SerializerBuilder::HandlesTypeId( + const Uuid& uuid, bool overwriteExisting) { if (!m_context->IsRemovingReflection()) { auto serializer = m_serializerIter->second.get(); if (uuid.IsNull()) { - AZ_Error("Serialization", false, - "Could not register Json serializer %s. Its Uuid is null.", - serializer->RTTI_GetTypeName() - ); + AZ_Assert(false, "Could not register Json serializer %s. Its Uuid is null.", serializer->RTTI_GetTypeName()); return this; } - auto serializerIter = m_context->m_handledTypesMap.find(uuid); - - if (serializerIter == m_context->m_handledTypesMap.end()) + if (!overwriteExisting) { - m_context->m_handledTypesMap.emplace(uuid, serializer); - return this; + auto serializerIter = m_context->m_handledTypesMap.find(uuid); + if (serializerIter == m_context->m_handledTypesMap.end()) + { + m_context->m_handledTypesMap.emplace(uuid, serializer); + } + else + { + AZ_Assert( + false, + "Couldn't register Json serializer %s. Another serializer (%s) has already been registered for the same Uuid (%s).", + serializer->RTTI_GetTypeName(), serializerIter->second->RTTI_GetTypeName(), + serializerIter->first.ToString().c_str()); + } + } + else + { + m_context->m_handledTypesMap.insert_or_assign(uuid, serializer); } - - AZ_Error("Serialization", false, - "Couldn't register Json serializer %s. Another serializer (%s) has already been registered for the same Uuid (%s).", - serializer->RTTI_GetTypeName(), - serializerIter->second->RTTI_GetTypeName(), - serializerIter->first.ToString().c_str() - ); } else { diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/RegistrationContext.h b/Code/Framework/AzCore/AzCore/Serialization/Json/RegistrationContext.h index 89d69e223f..fa1575a916 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/RegistrationContext.h +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/RegistrationContext.h @@ -63,52 +63,50 @@ namespace AZ SerializerBuilder* operator->(); template - SerializerBuilder* HandlesType() + SerializerBuilder* HandlesType(bool overwriteExisting = false) { - return HandlesTypeId(azrtti_typeid()); + return HandlesTypeId(azrtti_typeid(), overwriteExisting); } template class T> - SerializerBuilder* HandlesType() + SerializerBuilder* HandlesType(bool overwriteExisting = false) { - return HandlesTypeId(azrtti_typeid()); + return HandlesTypeId(azrtti_typeid(), overwriteExisting); } template class T> - SerializerBuilder* HandlesType() + SerializerBuilder* HandlesType(bool overwriteExisting = false) { - return HandlesTypeId(azrtti_typeid()); + return HandlesTypeId(azrtti_typeid(), overwriteExisting); } template class T> - SerializerBuilder* HandlesType() + SerializerBuilder* HandlesType(bool overwriteExisting = false) { - return HandlesTypeId(azrtti_typeid()); + return HandlesTypeId(azrtti_typeid(), overwriteExisting); } template class T> - SerializerBuilder* HandlesType() + SerializerBuilder* HandlesType(bool overwriteExisting = false) { - return HandlesTypeId(azrtti_typeid()); + return HandlesTypeId(azrtti_typeid(), overwriteExisting); } template class T> - SerializerBuilder* HandlesType() + SerializerBuilder* HandlesType(bool overwriteExisting = false) { - return HandlesTypeId(azrtti_typeid()); + return HandlesTypeId(azrtti_typeid(), overwriteExisting); } template class T> - SerializerBuilder* HandlesType() + SerializerBuilder* HandlesType(bool overwriteExisting = false) { - return HandlesTypeId(azrtti_typeid()); + return HandlesTypeId(azrtti_typeid(), overwriteExisting); } protected: - struct Placeholder { AZ_TYPE_INFO(PlaceHolder, "{4425191C-F497-411A-A7C3-52928E720B0A}"); }; - SerializerBuilder(JsonRegistrationContext* context, SerializerMap::const_iterator serializerMapIter); - SerializerBuilder* HandlesTypeId(const AZ::Uuid& uuid); + SerializerBuilder* HandlesTypeId(const AZ::Uuid& uuid, bool overwriteExisting); JsonRegistrationContext* m_context = nullptr; SerializerMap::const_iterator m_serializerIter; diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.cpp new file mode 100644 index 0000000000..b03215dd75 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.cpp @@ -0,0 +1,56 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include +#include + +namespace AZ +{ + AZ_CLASS_ALLOCATOR_IMPL(JsonUnsupportedTypesSerializer, SystemAllocator, 0); + AZ_CLASS_ALLOCATOR_IMPL(JsonAnySerializer, SystemAllocator, 0); + AZ_CLASS_ALLOCATOR_IMPL(JsonVariantSerializer, SystemAllocator, 0); + AZ_CLASS_ALLOCATOR_IMPL(JsonOptionalSerializer, SystemAllocator, 0); + + JsonSerializationResult::Result JsonUnsupportedTypesSerializer::Load(void*, const Uuid&, const rapidjson::Value&, + JsonDeserializerContext& context) + { + namespace JSR = JsonSerializationResult; + return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Invalid, GetMessage()); + } + + JsonSerializationResult::Result JsonUnsupportedTypesSerializer::Store(rapidjson::Value&, const void*, const void*, const Uuid&, + JsonSerializerContext& context) + { + namespace JSR = JsonSerializationResult; + return context.Report(JSR::Tasks::WriteValue, JSR::Outcomes::Invalid, GetMessage()); + } + + AZStd::string_view JsonAnySerializer::GetMessage() const + { + return "The Json Serialization doesn't support AZStd::any by design. The Json Serialization attempts to minimize the use of $type, " + "in particular the guid version, but no way has yet been found to use AZStd::any without explicitly and always requiring " + "one."; + } + + AZStd::string_view JsonVariantSerializer::GetMessage() const + { + return "The Json Serialization doesn't support AZStd::variant by design. The Json Serialization attempts to minimize the use of " + "$type, in particular the guid version. While combinations of AZStd::variant can be constructed that don't require a $type, " + "this cannot be guaranteed in general."; + } + + AZStd::string_view JsonOptionalSerializer::GetMessage() const + { + return "The Json Serialization doesn't support AZStd::optional by design. No JSON format has yet been found that wasn't deemed too " + "complex or overly verbose."; + } +} // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.h b/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.h new file mode 100644 index 0000000000..882b479e5d --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.h @@ -0,0 +1,72 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#pragma once + +#include +#include +#include + +namespace AZ +{ + class JsonUnsupportedTypesSerializer : public BaseJsonSerializer + { + public: + AZ_RTTI(JsonUnsupportedTypesSerializer, "{AFCC76B9-1F28-429D-8B4E-020BFD95ADAC}", BaseJsonSerializer); + AZ_CLASS_ALLOCATOR_DECL; + + JsonSerializationResult::Result Load( + void* outputValue, + const Uuid& outputValueTypeId, + const rapidjson::Value& inputValue, + JsonDeserializerContext& context) override; + JsonSerializationResult::Result Store( + rapidjson::Value& outputValue, + const void* inputValue, + const void* defaultValue, + const Uuid& valueTypeId, + JsonSerializerContext& context) override; + + protected: + virtual AZStd::string_view GetMessage() const = 0; + }; + + class JsonAnySerializer : public JsonUnsupportedTypesSerializer + { + public: + AZ_RTTI(JsonAnySerializer, "{699A0864-C4E2-4266-8141-99793C76870F}", JsonUnsupportedTypesSerializer); + AZ_CLASS_ALLOCATOR_DECL; + + protected: + AZStd::string_view GetMessage() const override; + }; + + class JsonVariantSerializer : public JsonUnsupportedTypesSerializer + { + public: + AZ_RTTI(JsonVariantSerializer, "{08F8E746-F8A4-4E83-8902-713E90F3F498}", JsonUnsupportedTypesSerializer); + AZ_CLASS_ALLOCATOR_DECL; + + protected: + AZStd::string_view GetMessage() const override; + }; + + class JsonOptionalSerializer : public JsonUnsupportedTypesSerializer + { + public: + AZ_RTTI(JsonOptionalSerializer, "{F8AF1C95-BD1B-44D2-9B4A-F5726133A104}", JsonUnsupportedTypesSerializer); + AZ_CLASS_ALLOCATOR_DECL; + + protected: + AZStd::string_view GetMessage() const override; + }; +} // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake index dc0fb13f00..ca5b8cb7f2 100644 --- a/Code/Framework/AzCore/AzCore/azcore_files.cmake +++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake @@ -544,6 +544,8 @@ set(FILES Serialization/Json/TupleSerializer.cpp Serialization/Json/UnorderedSetSerializer.h Serialization/Json/UnorderedSetSerializer.cpp + Serialization/Json/UnsupportedTypesSerializer.h + Serialization/Json/UnsupportedTypesSerializer.cpp Serialization/std/VariantReflection.inl Settings/CommandLine.cpp Settings/CommandLine.h diff --git a/Code/Framework/AzCore/Tests/Serialization/Json/JsonRegistrationContextTests.cpp b/Code/Framework/AzCore/Tests/Serialization/Json/JsonRegistrationContextTests.cpp index b10b569a42..6012a824c7 100644 --- a/Code/Framework/AzCore/Tests/Serialization/Json/JsonRegistrationContextTests.cpp +++ b/Code/Framework/AzCore/Tests/Serialization/Json/JsonRegistrationContextTests.cpp @@ -95,6 +95,20 @@ namespace JsonSerializationTests } }; + class SerializerWithOneDuplicatedTypeWithOverride + : public JsonSerializerTemplatedMock + { + public: + AZ_RTTI(SerializerWithOneDuplicatedTypeWithOverride, "{4218D591-E578-499B-B578-ACA70C9944AB}", BaseJsonSerializer); + ~SerializerWithOneDuplicatedTypeWithOverride() override = default; + + static void Reflect(AZ::JsonRegistrationContext* context) + { + context->Serializer() + ->HandlesType(true); + } + }; + // Attempts to register the same type twice class SerializerWithTwoSameTypes : public JsonSerializerTemplatedMock @@ -278,6 +292,22 @@ namespace JsonSerializationTests SerializerWithOneDuplicatedType::Unreflect(m_jsonRegistrationContext.get()); } + TEST_F(JsonRegistrationContextTests, OverwriteRegisterSameUuidWithMultipleSerializers_Succeeds) + { + EXPECT_NE(AZ::AzTypeInfo::Uuid(), AZ::AzTypeInfo::Uuid()); + + SerializerWithOneType::Reflect(m_jsonRegistrationContext.get()); + SerializerWithOneDuplicatedTypeWithOverride::Reflect(m_jsonRegistrationContext.get()); + + EXPECT_EQ(1, m_jsonRegistrationContext->GetRegisteredSerializers().size()); + AZ::BaseJsonSerializer* mockSerializer = m_jsonRegistrationContext->GetSerializerForType(azrtti_typeid()); + EXPECT_NE(mockSerializer, nullptr); + EXPECT_EQ(AZ::AzTypeInfo::Uuid(), mockSerializer->RTTI_GetType()); + + SerializerWithOneType::Unreflect(m_jsonRegistrationContext.get()); + SerializerWithOneDuplicatedTypeWithOverride::Unreflect(m_jsonRegistrationContext.get()); + } + TEST_F(JsonRegistrationContextTests, RegisterSameUuidWithSameSerializers_Fails) { AZ_TEST_START_ASSERTTEST; diff --git a/Code/Framework/AzCore/Tests/Serialization/Json/UnsupportedTypesSerializerTests.cpp b/Code/Framework/AzCore/Tests/Serialization/Json/UnsupportedTypesSerializerTests.cpp new file mode 100644 index 0000000000..8c9f5d0d3d --- /dev/null +++ b/Code/Framework/AzCore/Tests/Serialization/Json/UnsupportedTypesSerializerTests.cpp @@ -0,0 +1,143 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include +#include +#include +#include +#include + +namespace JsonSerializationTests +{ + struct AnyInfo + { + using Type = AZStd::any; + using Serializer = AZ::JsonAnySerializer; + }; + + struct VariantInfo + { + using Type = AZStd::variant; + using Serializer = AZ::JsonVariantSerializer; + }; + + struct OptionalInfo + { + using Type = AZStd::optional; + using Serializer = AZ::JsonVariantSerializer; + }; + + template + class JsonUnsupportedTypesSerializerTests : public BaseJsonSerializerFixture + { + public: + using Type = typename Info::Type; + using Serializer = typename Info::Serializer; + + void SetUp() override + { + BaseJsonSerializerFixture::SetUp(); + m_serializer = AZStd::make_unique(); + } + + void TearDown() override + { + m_serializer.reset(); + BaseJsonSerializerFixture::TearDown(); + } + + protected: + AZStd::unique_ptr m_serializer; + }; + + using UnsupportedTypesTestTypes = ::testing::Types; + TYPED_TEST_CASE(JsonUnsupportedTypesSerializerTests, UnsupportedTypesTestTypes); + + TYPED_TEST(JsonUnsupportedTypesSerializerTests, Load_CallDirectly_ReportsIssueAndHalts) + { + using namespace AZ::JsonSerializationResult; + + bool hasMessage = false; + auto callback = [&hasMessage](AZStd::string_view message, ResultCode result, AZStd::string_view) -> ResultCode + { + hasMessage = !message.empty(); + return result; + }; + m_jsonDeserializationContext->PushReporter(AZStd::move(callback)); + + Type instance{}; + Result result = m_serializer->Load(&instance, azrtti_typeid(), *m_jsonDocument, *m_jsonDeserializationContext); + m_jsonDeserializationContext->PopReporter(); + + EXPECT_EQ(Processing::Halted, result.GetResultCode().GetProcessing()); + EXPECT_TRUE(hasMessage); + } + + TYPED_TEST(JsonUnsupportedTypesSerializerTests, Load_CallThroughFrontEnd_ReportsIssueAndHalts) + { + using namespace AZ::JsonSerializationResult; + + bool hasMessage = false; + auto callback = [&hasMessage](AZStd::string_view message, ResultCode result, AZStd::string_view) -> ResultCode + { + hasMessage = !message.empty(); + return result; + }; + m_deserializationSettings->m_reporting = AZStd::move(callback); + + Type instance{}; + ResultCode result = AZ::JsonSerialization::Load(instance, *m_jsonDocument, *m_deserializationSettings); + + EXPECT_EQ(Processing::Halted, result.GetProcessing()); + EXPECT_TRUE(hasMessage); + } + + TYPED_TEST(JsonUnsupportedTypesSerializerTests, Save_CallDirectly_ReportsIssueAndHalts) + { + using namespace AZ::JsonSerializationResult; + + bool hasMessage = false; + auto callback = [&hasMessage](AZStd::string_view message, ResultCode result, AZStd::string_view) -> ResultCode + { + hasMessage = !message.empty(); + return result; + }; + m_jsonSerializationContext->PushReporter(AZStd::move(callback)); + + Type instance{}; + Result result = m_serializer->Store(*m_jsonDocument, &instance, nullptr, azrtti_typeid(), *m_jsonSerializationContext); + m_jsonSerializationContext->PopReporter(); + + EXPECT_EQ(Processing::Halted, result.GetResultCode().GetProcessing()); + EXPECT_TRUE(hasMessage); + } + + TYPED_TEST(JsonUnsupportedTypesSerializerTests, Save_CallThroughFrontEnd_ReportsIssueAndHalts) + { + using namespace AZ::JsonSerializationResult; + + bool hasMessage = false; + auto callback = [&hasMessage](AZStd::string_view message, ResultCode result, AZStd::string_view) -> ResultCode + { + hasMessage = !message.empty(); + return result; + }; + m_serializationSettings->m_reporting = AZStd::move(callback); + + Type instance{}; + ResultCode result = + AZ::JsonSerialization::Store(*m_jsonDocument, m_jsonDocument->GetAllocator(), instance, *m_serializationSettings); + + EXPECT_EQ(Processing::Halted, result.GetProcessing()); + EXPECT_TRUE(hasMessage); + } +} // namespace JsonSerializationTests diff --git a/Code/Framework/AzCore/Tests/azcoretests_files.cmake b/Code/Framework/AzCore/Tests/azcoretests_files.cmake index 78b2701d92..ffbfb75f6b 100644 --- a/Code/Framework/AzCore/Tests/azcoretests_files.cmake +++ b/Code/Framework/AzCore/Tests/azcoretests_files.cmake @@ -128,6 +128,7 @@ set(FILES Serialization/Json/TransformSerializerTests.cpp Serialization/Json/TupleSerializerTests.cpp Serialization/Json/UnorderedSetSerializerTests.cpp + Serialization/Json/UnsupportedTypesSerializerTests.cpp Serialization/Json/UuidSerializerTests.cpp Math/AabbTests.cpp Math/ColorTests.cpp From e85b5a8c48c1e47ad00eab7c13f4be2bffef84e6 Mon Sep 17 00:00:00 2001 From: guthadam Date: Wed, 9 Jun 2021 00:35:31 -0500 Subject: [PATCH 12/73] Fixing material editor startup and critical asset issues Added builder and tool aliases Added dependency to Atom Bridge --- Gems/Atom/Tools/MaterialEditor/Code/CMakeLists.txt | 5 +++++ Gems/Atom/Tools/MaterialEditor/gem.json | 10 ++++++++++ Gems/AtomLyIntegration/AtomBridge/Code/CMakeLists.txt | 1 + 3 files changed, 16 insertions(+) create mode 100644 Gems/Atom/Tools/MaterialEditor/gem.json diff --git a/Gems/Atom/Tools/MaterialEditor/Code/CMakeLists.txt b/Gems/Atom/Tools/MaterialEditor/Code/CMakeLists.txt index 134f605200..dddb339cfb 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/CMakeLists.txt +++ b/Gems/Atom/Tools/MaterialEditor/Code/CMakeLists.txt @@ -113,6 +113,11 @@ ly_add_target( Gem::MaterialEditor.Document ) +# Add a 'builders' alias to allow the MaterialEditor root gem path to be added to the generated +# cmake_dependencies..assetprocessor.setreg to allow the asset scan folder for it to be added +ly_create_alias(NAME MaterialEditor.Builders NAMESPACE Gem) +ly_create_alias(NAME MaterialEditor.Tools NAMESPACE Gem) + # Add build dependency to Editor for the MaterialEditor application since # Editor opens up the MaterialEditor ly_add_dependencies(Editor Gem::MaterialEditor) diff --git a/Gems/Atom/Tools/MaterialEditor/gem.json b/Gems/Atom/Tools/MaterialEditor/gem.json new file mode 100644 index 0000000000..5113effc0a --- /dev/null +++ b/Gems/Atom/Tools/MaterialEditor/gem.json @@ -0,0 +1,10 @@ +{ + "gem_name": "MaterialEditor", + "display_name": "Atom Material Editor", + "summary": "Editor for creating, modifying, and previewing materials", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + ] +} diff --git a/Gems/AtomLyIntegration/AtomBridge/Code/CMakeLists.txt b/Gems/AtomLyIntegration/AtomBridge/Code/CMakeLists.txt index 4df40e3d13..abc4dfb2c6 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Code/CMakeLists.txt +++ b/Gems/AtomLyIntegration/AtomBridge/Code/CMakeLists.txt @@ -111,6 +111,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::AtomToolsFramework.Editor Gem::AtomViewportDisplayInfo Gem::AtomViewportDisplayIcons.Editor + Gem::MaterialEditor.Builders ) From e795dd5210b1da9d689b4ce34c9eb155be868d5b Mon Sep 17 00:00:00 2001 From: moudgils Date: Tue, 8 Jun 2021 22:35:48 -0700 Subject: [PATCH 13/73] - Added enums for write mask and adding suppooort for that across all backends. - Batch calls to bind argument buffers - Fix swapchain creation for Editor --- .../Include/Atom/RHI.Reflect/RenderStates.h | 18 +++ .../RHI/DX12/Code/Source/RHI/Conversions.cpp | 25 ++- .../RHI/DX12/Code/Source/RHI/Conversions.h | 2 + .../RHI/Metal/Code/Source/RHI/CommandList.cpp | 143 +++++++++++++++--- .../RHI/Metal/Code/Source/RHI/CommandList.h | 4 + .../RHI/Metal/Code/Source/RHI/Conversions.cpp | 22 ++- .../Metal/Code/Source/RHI/PipelineLayout.cpp | 4 +- .../RHI/Metal/Code/Source/RHI/SwapChain.cpp | 29 ++-- .../RHI/Metal/Code/Source/RHI/SwapChain.h | 2 + .../RHI/Vulkan/Code/Source/RHI/Conversion.cpp | 8 +- 10 files changed, 213 insertions(+), 44 deletions(-) diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/RenderStates.h b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/RenderStates.h index 51b15c4bcf..d5c55e2c7f 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/RenderStates.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/RenderStates.h @@ -160,6 +160,24 @@ namespace AZ StencilState m_stencil; }; + enum class WriteChannel : uint32_t + { + ColorWriteMaskRed = 0, + ColorWriteMaskGreen, + ColorWriteMaskBlue, + ColorWriteMaskAlpha, + }; + + enum class WriteChannelMask : uint32_t + { + ColorWriteMaskNone = 0, + ColorWriteMaskRed = AZ_BIT(static_cast(WriteChannel::ColorWriteMaskRed)), + ColorWriteMaskGreen = AZ_BIT(static_cast(WriteChannel::ColorWriteMaskGreen)), + ColorWriteMaskBlue = AZ_BIT(static_cast(WriteChannel::ColorWriteMaskBlue)), + ColorWriteMaskAlpha = AZ_BIT(static_cast(WriteChannel::ColorWriteMaskAlpha)), + ColorWriteMaskAll = ColorWriteMaskRed | ColorWriteMaskGreen | ColorWriteMaskBlue | ColorWriteMaskAlpha + }; + struct TargetBlendState { AZ_TYPE_INFO(TargetBlendState, "{2CDF00FE-614D-44FC-929F-E6B50C348578}"); diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.cpp index a3d14e3803..73d80ed78c 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.cpp @@ -10,6 +10,7 @@ * */ #include "RHI/Atom_RHI_DX12_precompiled.h" +#include #include #include #include @@ -1268,7 +1269,7 @@ namespace AZ dst.BlendOpAlpha = ConvertBlendOp(src.m_blendAlphaOp); dst.DestBlend = ConvertBlendFactor(src.m_blendDest); dst.DestBlendAlpha = ConvertBlendFactor(src.m_blendAlphaDest); - dst.RenderTargetWriteMask = src.m_writeMask; + dst.RenderTargetWriteMask = ConvertColorWriteMask(src.m_writeMask); dst.SrcBlend = ConvertBlendFactor(src.m_blendSource); dst.SrcBlendAlpha = ConvertBlendFactor(src.m_blendAlphaSource); dst.LogicOp = D3D12_LOGIC_OP_CLEAR; @@ -1355,6 +1356,28 @@ namespace AZ }; return table[(uint32_t)mask]; } + + uint32_t ConvertColorWriteMask(uint8_t writeMask) + { + uint32_t dflags = 0; + if (RHI::CheckBitsAny(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskRed))) + { + dflags |= D3D12_COLOR_WRITE_ENABLE_RED; + } + if (RHI::CheckBitsAny(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskGreen))) + { + dflags |= D3D12_COLOR_WRITE_ENABLE_GREEN; + } + if (RHI::CheckBitsAny(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskBlue))) + { + dflags |= D3D12_COLOR_WRITE_ENABLE_BLUE; + } + if (RHI::CheckBitsAny(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskAlpha))) + { + dflags |= D3D12_COLOR_WRITE_ENABLE_ALPHA; + } + return dflags; + } D3D12_DEPTH_STENCIL_DESC ConvertDepthStencilState(const RHI::DepthStencilState& depthStencil) { diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.h b/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.h index d8385203f8..887598de79 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.h +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.h @@ -164,5 +164,7 @@ namespace AZ uint32_t shaderRegisterSpace, D3D12_SHADER_VISIBILITY shaderVisibility, D3D12_STATIC_SAMPLER_DESC& staticSamplerDesc); + + uint32_t ConvertColorWriteMask(uint8_t writeMask); } } diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp index 10fbe372b1..7df8f1e547 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -249,68 +250,88 @@ namespace AZ ShaderResourceBindings& bindings = GetShaderResourceBindingsByPipelineType(stateType); const PipelineLayout& pipelineLayout = pipelineState->GetPipelineLayout(); - for (uint32_t srgIndex = 0; srgIndex < RHI::Limits::Pipeline::ShaderResourceGroupCountMax; ++srgIndex) + uint32_t bufferVertexRegisterIdMin = RHI::Limits::Pipeline::ShaderResourceGroupCountMax; + uint32_t bufferFragmentOrComputeRegisterIdMin = RHI::Limits::Pipeline::ShaderResourceGroupCountMax; + uint32_t bufferVertexRegisterIdMax = 0; + uint32_t bufferFragmentOrComputeRegisterIdMax = 0; + + MetalArgumentBufferArray mtlVertexArgBuffers; + MetalArgumentBufferArrayOffsets mtlVertexArgBufferOffsets; + MetalArgumentBufferArray mtlFragmentOrComputeArgBuffers; + MetalArgumentBufferArrayOffsets mtlFragmentOrComputeArgBufferOffsets; + + mtlVertexArgBuffers.fill(nil); + mtlFragmentOrComputeArgBuffers.fill(nil); + mtlVertexArgBufferOffsets.fill(0); + mtlFragmentOrComputeArgBufferOffsets.fill(0); + + for (uint32_t slot = 0; slot < RHI::Limits::Pipeline::ShaderResourceGroupCountMax; ++slot) { - const ShaderResourceGroup* shaderResourceGroup = bindings.m_srgsBySlot[srgIndex]; - uint32_t slotIndex = pipelineLayout.GetSlotByIndex(srgIndex); + const ShaderResourceGroup* shaderResourceGroup = bindings.m_srgsBySlot[slot]; + uint32_t slotIndex = pipelineLayout.GetIndexBySlot(slot); if(!shaderResourceGroup || slotIndex == RHI::Limits::Pipeline::ShaderResourceGroupCountMax) { continue; } - uint32_t srgVisIndex = pipelineLayout.GetSlotByIndex(shaderResourceGroup->GetBindingSlot()); + uint32_t srgVisIndex = pipelineLayout.GetIndexBySlot(shaderResourceGroup->GetBindingSlot()); const RHI::ShaderStageMask& srgVisInfo = pipelineLayout.GetSrgVisibility(srgVisIndex); - if (bindings.m_srgsByIndex[srgIndex] != shaderResourceGroup) + bool isSrgUpdatd = bindings.m_srgsByIndex[slot] != shaderResourceGroup; + if(isSrgUpdatd) { - bindings.m_srgsByIndex[srgIndex] = shaderResourceGroup; + bindings.m_srgsByIndex[slot] = shaderResourceGroup; auto& compiledArgBuffer = shaderResourceGroup->GetCompiledArgumentBuffer(); id argBuffer = compiledArgBuffer.GetArgEncoderBuffer(); size_t argBufferOffset = compiledArgBuffer.GetOffset(); if(srgVisInfo != RHI::ShaderStageMask::None) { - //For graphics and compute encoder bind the argument buffer + //For graphics and compute shader stages, cache all the argument buffers, offsets and track the min/max indices if(m_commandEncoderType == CommandEncoderType::Render) { id renderEncoder = GetEncoder>(); uint8_t numBitsSet = RHI::CountBitsSet(static_cast(srgVisInfo)); if( numBitsSet > 1 || srgVisInfo == RHI::ShaderStageMask::Vertex) { - [renderEncoder setVertexBuffer:argBuffer - offset:argBufferOffset - atIndex:slotIndex]; + mtlVertexArgBuffers[slotIndex] = argBuffer; + mtlVertexArgBufferOffsets[slotIndex] = argBufferOffset; + bufferVertexRegisterIdMin = AZStd::min(slotIndex, bufferVertexRegisterIdMin); + bufferVertexRegisterIdMax = AZStd::max(slotIndex, bufferVertexRegisterIdMax); + } if( numBitsSet > 1 || srgVisInfo == RHI::ShaderStageMask::Fragment) { - [renderEncoder setFragmentBuffer:argBuffer - offset:argBufferOffset - atIndex:slotIndex]; + mtlFragmentOrComputeArgBuffers[slotIndex] = argBuffer; + mtlFragmentOrComputeArgBufferOffsets[slotIndex] = argBufferOffset; + bufferFragmentOrComputeRegisterIdMin = AZStd::min(slotIndex, bufferFragmentOrComputeRegisterIdMin); + bufferFragmentOrComputeRegisterIdMax = AZStd::max(slotIndex, bufferFragmentOrComputeRegisterIdMax); } } else if(m_commandEncoderType == CommandEncoderType::Compute) { - id computeEncoder = GetEncoder>(); - [computeEncoder setBuffer:argBuffer - offset:argBufferOffset - atIndex:pipelineLayout.GetSlotByIndex(srgIndex)]; + mtlFragmentOrComputeArgBuffers[slotIndex] = argBuffer; + mtlFragmentOrComputeArgBufferOffsets[slotIndex] = argBufferOffset; + bufferFragmentOrComputeRegisterIdMin = AZStd::min(slotIndex, bufferFragmentOrComputeRegisterIdMin); + bufferFragmentOrComputeRegisterIdMax = AZStd::max(slotIndex, bufferFragmentOrComputeRegisterIdMax); } } } - //Check againgst the srg resources visibility hash as it is possible for draw items to have different PSO in the same pass. + //Check if the srg has been updated or if the srg resources visibility hash has been updated + //as it is possible for draw items to have different PSOs in the same pass. const AZ::HashValue64 srgResourcesVisHash = pipelineLayout.GetSrgResourcesVisibilityHash(srgVisIndex); - if(bindings.m_srgVisHashByIndex[srgIndex] != srgResourcesVisHash) + if(bindings.m_srgVisHashByIndex[slot] != srgResourcesVisHash || isSrgUpdatd) { - bindings.m_srgVisHashByIndex[srgIndex] = srgResourcesVisHash; + bindings.m_srgVisHashByIndex[slot] = srgResourcesVisHash; if(srgVisInfo != RHI::ShaderStageMask::None) { const ShaderResourceGroupVisibility& srgResourcesVisInfo = pipelineLayout.GetSrgResourcesVisibility(srgVisIndex); - //For graphics and compute encoder bind the argument buffer and - //make the resource resident for the duration of the work associated with the current scope - //and ensure that it's in a format compatible with the appropriate metal function. + //For graphics and compute encoder make the resource resident (call UseResource) for the duration + //of the work associated with the current scope and ensure that it's in a + //format compatible with the appropriate metal function. if(m_commandEncoderType == CommandEncoderType::Render) { shaderResourceGroup->AddUntrackedResourcesToEncoder(m_encoder, srgResourcesVisInfo); @@ -322,9 +343,81 @@ namespace AZ } } } - + + //For graphics and compute encoder bind all the argument buffers + if(m_commandEncoderType == CommandEncoderType::Render) + { + BindArgumentBuffers(RHI::ShaderStage::Vertex, bufferVertexRegisterIdMin, bufferVertexRegisterIdMax, mtlVertexArgBuffers, mtlVertexArgBufferOffsets); + BindArgumentBuffers(RHI::ShaderStage::Fragment, bufferFragmentOrComputeRegisterIdMin, bufferFragmentOrComputeRegisterIdMax, mtlFragmentOrComputeArgBuffers, mtlFragmentOrComputeArgBufferOffsets); + } + else if(m_commandEncoderType == CommandEncoderType::Compute) + { + BindArgumentBuffers(RHI::ShaderStage::Compute, bufferFragmentOrComputeRegisterIdMin, bufferFragmentOrComputeRegisterIdMax, mtlFragmentOrComputeArgBuffers, mtlFragmentOrComputeArgBufferOffsets); + } + return true; } + + void CommandList::BindArgumentBuffers(RHI::ShaderStage shaderStage, uint16_t registerIdMin, uint16_t registerIdMax, MetalArgumentBufferArray& mtlArgBuffers, MetalArgumentBufferArrayOffsets mtlArgBufferOffsets) + { + //Metal Api only lets you bind multiple argument buffers in an array as long as there are no gaps in the array + //In order to accomodate that we break up the calls when a gap is noticed in the array and reconfigure the NSRange. + uint16_t startingIndex = registerIdMin; + bool trackingRange = true; + for(int i = registerIdMin; i <= registerIdMax+1; i++) + { + if(trackingRange) + { + if(mtlArgBuffers[i] == nil) + { + NSRange range = { startingIndex, i-startingIndex }; + + switch(shaderStage) + { + case RHI::ShaderStage::Vertex: + { + id renderEncoder = GetEncoder>(); + [renderEncoder setVertexBuffers:&mtlArgBuffers[startingIndex] + offsets:&mtlArgBufferOffsets[startingIndex] + withRange:range]; + break; + } + case RHI::ShaderStage::Fragment: + { + id renderEncoder = GetEncoder>(); + [renderEncoder setFragmentBuffers:&mtlArgBuffers[startingIndex] + offsets:&mtlArgBufferOffsets[startingIndex] + withRange:range]; + break; + } + case RHI::ShaderStage::Compute: + { + id computeEncoder = GetEncoder>(); + [computeEncoder setBuffers:&mtlArgBuffers[startingIndex] + offsets:&mtlArgBufferOffsets[startingIndex] + withRange:range]; + break; + } + default: + { + AZ_Assert(false, "Not supported"); + } + } + + trackingRange = false; + + } + } + else + { + if(mtlArgBuffers[i] != nil) + { + startingIndex = i; + trackingRange = true; + } + } + } + } void CommandList::Submit(const RHI::DrawItem& drawItem) { @@ -486,7 +579,7 @@ namespace AZ void CommandList::SetStreamBuffers(const RHI::StreamBufferView* streams, uint32_t count) { - int bufferArrayLen = 0; + uint16_t bufferArrayLen = 0; AZStd::array, METAL_MAX_ENTRIES_BUFFER_ARG_TABLE> mtlStreamBuffers; AZStd::array mtlStreamBufferOffsets; diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.h b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.h index dd4e382471..9dd14cd175 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.h +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.h @@ -102,6 +102,10 @@ namespace AZ AZStd::array m_srgVisHashByIndex; }; + using MetalArgumentBufferArray = AZStd::array, RHI::Limits::Pipeline::ShaderResourceGroupCountMax>; + using MetalArgumentBufferArrayOffsets = AZStd::array; + void BindArgumentBuffers(RHI::ShaderStage shaderStage, uint16_t registerIdMin, uint16_t registerIdMax, MetalArgumentBufferArray& mtlArgBuffers, MetalArgumentBufferArrayOffsets mtlArgBufferOffsets); + ShaderResourceBindings& GetShaderResourceBindingsByPipelineType(RHI::PipelineStateType pipelineType); //! This is kept as a separate struct so that we can robustly reset it. Every property diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/Conversions.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/Conversions.cpp index f95e871d33..e41ba9bf2a 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/Conversions.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/Conversions.cpp @@ -12,6 +12,7 @@ #include "Atom_RHI_Metal_precompiled.h" #include +#include #include #include #include @@ -456,8 +457,25 @@ namespace AZ MTLColorWriteMask ConvertColorWriteMask(AZ::u8 writeMask) { - //todo::Based on the mask set the correct writemask - return MTLColorWriteMaskAll; + MTLColorWriteMask colorMask = MTLColorWriteMaskNone; + if (RHI::CheckBitsAny(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskRed))) + { + colorMask |= MTLColorWriteMaskRed; + } + if (RHI::CheckBitsAny(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskGreen))) + { + colorMask |= MTLColorWriteMaskGreen; + } + if (RHI::CheckBitsAny(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskBlue))) + { + colorMask |= MTLColorWriteMaskBlue; + } + if (RHI::CheckBitsAny(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskAlpha))) + { + colorMask |= MTLColorWriteMaskAlpha; + } + + return colorMask; } MTLVertexFormat ConvertVertexFormat(RHI::Format format) diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/PipelineLayout.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/PipelineLayout.cpp index 70d36f8d6d..9a30a04deb 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/PipelineLayout.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/PipelineLayout.cpp @@ -125,12 +125,12 @@ namespace AZ size_t PipelineLayout::GetSlotByIndex(size_t index) const { - return m_slotToIndexTable[index]; + return m_indexToSlotTable[index]; } size_t PipelineLayout::GetIndexBySlot(size_t slot) const { - return m_indexToSlotTable[slot]; + return m_slotToIndexTable[slot]; } const RHI::ShaderStageMask& PipelineLayout::GetSrgVisibility(uint32_t index) const diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/SwapChain.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/SwapChain.cpp index 1f870548cc..94599bc390 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/SwapChain.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/SwapChain.cpp @@ -73,6 +73,10 @@ namespace AZ m_metalView.metalLayer.drawableSize = CGSizeMake(descriptor.m_dimensions.m_imageWidth, descriptor.m_dimensions.m_imageHeight); } + else + { + AddSubView(); + } m_drawables.resize(descriptor.m_dimensions.m_imageCount); @@ -83,6 +87,20 @@ namespace AZ return RHI::ResultCode::Success; } + void SwapChain::AddSubView() + { + NativeViewType* superView = reinterpret_cast(m_nativeWindow); + + CGFloat screenScale = Platform::GetScreenScale(); + CGRect screenBounds = [superView bounds]; + m_metalView = [[RHIMetalView alloc] initWithFrame: screenBounds + scale: screenScale + device: m_mtlDevice]; + + [m_metalView retain]; + [superView addSubview: m_metalView]; + } + void SwapChain::ShutdownInternal() { if (m_viewController) @@ -161,16 +179,7 @@ namespace AZ } else { - NativeViewType* superView = reinterpret_cast(m_nativeWindow); - - CGFloat screenScale = Platform::GetScreenScale(); - CGRect screenBounds = [superView bounds]; - m_metalView = [[RHIMetalView alloc] initWithFrame: screenBounds - scale: screenScale - device: m_mtlDevice]; - - [m_metalView retain]; - [superView addSubview: m_metalView]; + AddSubView(); } } return RHI::ResultCode::Success; diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/SwapChain.h b/Gems/Atom/RHI/Metal/Code/Source/RHI/SwapChain.h index d455f3dd0c..dfe8b3365d 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/SwapChain.h +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/SwapChain.h @@ -49,6 +49,8 @@ namespace AZ RHI::ResultCode ResizeInternal(const RHI::SwapChainDimensions& dimensions, RHI::SwapChainDimensions* nativeDimensions) override; ////////////////////////////////////////////////////////////////////////// + void AddSubView(); + id m_mtlCommandBuffer; RHIMetalView* m_metalView = nullptr; NativeViewControllerType* m_viewController = nullptr; diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp index accc18b5ec..7945dd2894 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp @@ -334,19 +334,19 @@ namespace AZ VkColorComponentFlags ConvertComponentFlags(uint8_t sflags) { VkColorComponentFlags dflags = 0; - if (RHI::CheckBitsAny(sflags, static_cast(1))) + if (RHI::CheckBitsAny(sflags, static_cast(RHI::WriteChannelMask::ColorWriteMaskRed))) { dflags |= VK_COLOR_COMPONENT_R_BIT; } - if (RHI::CheckBitsAny(sflags, static_cast(2))) + if (RHI::CheckBitsAny(sflags, static_cast(RHI::WriteChannelMask::ColorWriteMaskGreen))) { dflags |= VK_COLOR_COMPONENT_G_BIT; } - if (RHI::CheckBitsAny(sflags, static_cast(4))) + if (RHI::CheckBitsAny(sflags, static_cast(RHI::WriteChannelMask::ColorWriteMaskBlue))) { dflags |= VK_COLOR_COMPONENT_B_BIT; } - if (RHI::CheckBitsAny(sflags, static_cast(8))) + if (RHI::CheckBitsAny(sflags, static_cast(RHI::WriteChannelMask::ColorWriteMaskAlpha))) { dflags |= VK_COLOR_COMPONENT_A_BIT; } From 702356007ca716330a541ef0ce36e65c3fee6b0b Mon Sep 17 00:00:00 2001 From: antonmic Date: Tue, 8 Jun 2021 22:36:54 -0700 Subject: [PATCH 14/73] Pass changes WIP: standardized usage of new pass initialization functions --- .../AcesOutputTransformLutPass.h | 4 +++- .../DisplayMapper/AcesOutputTransformPass.h | 4 +++- .../ApplyShaperLookupTablePass.h | 4 +++- .../BakeAcesOutputTransformLutPass.h | 4 +--- .../DisplayMapperFullScreenPass.h | 7 ++----- .../Feature/DisplayMapper/DisplayMapperPass.h | 1 + .../DisplayMapper/OutputTransformPass.h | 4 +++- .../AcesOutputTransformLutPass.cpp | 4 ++-- .../DisplayMapper/AcesOutputTransformPass.cpp | 4 ++-- .../ApplyShaperLookupTablePass.cpp | 4 ++-- .../BakeAcesOutputTransformLutPass.cpp | 13 +----------- .../DisplayMapperFullScreenPass.cpp | 4 ---- .../DisplayMapper/DisplayMapperPass.cpp | 14 ++++++++++++- .../DisplayMapper/OutputTransformPass.cpp | 4 ++-- .../BlendColorGradingLutsPass.cpp | 15 ++------------ .../BlendColorGradingLutsPass.h | 4 +--- .../DepthOfFieldBokehBlurPass.cpp | 4 ++-- .../DepthOfFieldBokehBlurPass.h | 2 +- .../DepthOfFieldCompositePass.cpp | 4 ++-- .../DepthOfFieldCompositePass.h | 2 +- .../PostProcessing/DepthOfFieldMaskPass.cpp | 4 ++-- .../PostProcessing/DepthOfFieldMaskPass.h | 2 +- .../LookModificationCompositePass.cpp | 4 ++-- .../LookModificationCompositePass.h | 2 +- .../Source/PostProcessing/SMAABasePass.cpp | 4 ++-- .../Code/Source/PostProcessing/SMAABasePass.h | 5 ++++- .../SMAABlendingWeightCalculationPass.cpp | 4 ++-- .../SMAABlendingWeightCalculationPass.h | 4 +++- .../PostProcessing/SMAAEdgeDetectionPass.cpp | 4 ++-- .../PostProcessing/SMAAEdgeDetectionPass.h | 4 +++- .../SMAANeighborhoodBlendingPass.cpp | 4 ++-- .../SMAANeighborhoodBlendingPass.h | 4 +++- .../Source/ScreenSpace/DeferredFogPass.cpp | 4 ++-- .../Code/Source/ScreenSpace/DeferredFogPass.h | 12 ++++++----- .../RPI.Public/Pass/FullscreenTrianglePass.h | 5 +---- .../Code/Include/Atom/RPI.Public/Pass/Pass.h | 19 ++++++++++++++---- .../Pass/FullscreenTrianglePass.cpp | 20 ++++++------------- .../RPI/Code/Source/RPI.Public/Pass/Pass.cpp | 16 +++++++++++++++ .../Source/RPI.Public/Pass/PassSystem.cpp | 2 +- .../Code/Source/RPI.Public/RenderPipeline.cpp | 5 +++++ 40 files changed, 127 insertions(+), 107 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/AcesOutputTransformLutPass.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/AcesOutputTransformLutPass.h index bc8673a64b..a6c7615574 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/AcesOutputTransformLutPass.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/AcesOutputTransformLutPass.h @@ -48,7 +48,9 @@ namespace AZ void SetShaperParams(const ShaperParams& shaperParams); private: explicit AcesOutputTransformLutPass(const RPI::PassDescriptor& descriptor); - void Init() override; + + // Pass behavior overrides... + void InitializeInternal() override; // Scope producer functions... void SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) override; diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/AcesOutputTransformPass.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/AcesOutputTransformPass.h index 5a0ccdb32a..350b178cfa 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/AcesOutputTransformPass.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/AcesOutputTransformPass.h @@ -50,7 +50,9 @@ namespace AZ private: explicit AcesOutputTransformPass(const RPI::PassDescriptor& descriptor); - void Init() override; + + // Pass behavior overrides + void InitializeInternal() override; // Scope producer functions... void CompileResources(const RHI::FrameGraphCompileContext& context) override; diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/ApplyShaperLookupTablePass.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/ApplyShaperLookupTablePass.h index 35d2fcf603..3b6d7f7c27 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/ApplyShaperLookupTablePass.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/ApplyShaperLookupTablePass.h @@ -45,7 +45,9 @@ namespace AZ protected: explicit ApplyShaperLookupTablePass(const RPI::PassDescriptor& descriptor); - void Init() override; + + // Pass behavior overrides... + void InitializeInternal() override; RHI::ShaderInputImageIndex m_shaderInputLutImageIndex; diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/BakeAcesOutputTransformLutPass.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/BakeAcesOutputTransformLutPass.h index 60505653b7..0f6f1aa954 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/BakeAcesOutputTransformLutPass.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/BakeAcesOutputTransformLutPass.h @@ -57,15 +57,13 @@ namespace AZ explicit BakeAcesOutputTransformLutPass(const RPI::PassDescriptor& descriptor); // Pass behavior overrides... - void FrameBeginInternal(FramePrepareParams params) override; + void InitializeInternal() override; // RHI::ScopeProducer overrides... void SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) override; void CompileResources(const RHI::FrameGraphCompileContext& context) override; void BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context) override; - void Init(); - void AcquireLutImage(); void ReleaseLutImage(); diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperFullScreenPass.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperFullScreenPass.h index 23c4cd1a0a..59c02accdd 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperFullScreenPass.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperFullScreenPass.h @@ -41,14 +41,11 @@ namespace AZ void SetInputReferencePassName(const Name& passName); void SetInputReferenceAttachmentName(const Name& attachmentName); - // Pass behavior overrides - virtual void BuildInternal() override; - protected: explicit DisplayMapperFullScreenPass(const RPI::PassDescriptor& descriptor); - // FullscreenTrianglePass behavior overrides - virtual void Init(); + // Pass behavior overrides... + virtual void BuildInternal() override; private: Name m_inputReferencePassName = Name{ "Parent" }; diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperPass.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperPass.h index 15ada4dd94..b741a10953 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperPass.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperPass.h @@ -77,6 +77,7 @@ namespace AZ // Pass behavior overrides void BuildInternal() final; + void InitializeInternal() final; void FrameBeginInternal(FramePrepareParams params) final; void FrameEndInternal() final; void CreateChildPassesInternal() final; diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/OutputTransformPass.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/OutputTransformPass.h index b266eab14b..caee7ae3dd 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/OutputTransformPass.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/OutputTransformPass.h @@ -49,7 +49,9 @@ namespace AZ protected: explicit OutputTransformPass(const RPI::PassDescriptor& descriptor); - void Init() override; + + // Pass behavior overrides + void InitializeInternal() override; private: // Scope producer functions... diff --git a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/AcesOutputTransformLutPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/AcesOutputTransformLutPass.cpp index 104a91174d..5e3bde94e9 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/AcesOutputTransformLutPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/AcesOutputTransformLutPass.cpp @@ -42,9 +42,9 @@ namespace AZ ReleaseLutImage(); } - void AcesOutputTransformLutPass::Init() + void AcesOutputTransformLutPass::InitializeInternal() { - DisplayMapperFullScreenPass::Init(); + DisplayMapperFullScreenPass::InitializeInternal(); AZ_Assert(m_shaderResourceGroup != nullptr, "AcesOutputTransformLutPass %s has a null shader resource group when calling Init.", GetPathName().GetCStr()); diff --git a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/AcesOutputTransformPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/AcesOutputTransformPass.cpp index 6fe38ff032..ec34d40ea6 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/AcesOutputTransformPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/AcesOutputTransformPass.cpp @@ -44,9 +44,9 @@ namespace AZ { } - void AcesOutputTransformPass::Init() + void AcesOutputTransformPass::InitializeInternal() { - DisplayMapperFullScreenPass::Init(); + DisplayMapperFullScreenPass::InitializeInternal(); AZ_Assert(m_shaderResourceGroup != nullptr, "AcesOutputTransformPass %s has a null shader resource group when calling Init.", GetPathName().GetCStr()); diff --git a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/ApplyShaperLookupTablePass.cpp b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/ApplyShaperLookupTablePass.cpp index 496b4dcc8f..ff910a4b81 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/ApplyShaperLookupTablePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/ApplyShaperLookupTablePass.cpp @@ -38,9 +38,9 @@ namespace AZ ReleaseLutImage(); } - void ApplyShaperLookupTablePass::Init() + void ApplyShaperLookupTablePass::InitializeInternal() { - DisplayMapperFullScreenPass::Init(); + DisplayMapperFullScreenPass::InitializeInternal(); AZ_Assert(m_shaderResourceGroup != nullptr, "ApplyShaperLookupTablePass %s has a null shader resource group when calling Init.", GetPathName().GetCStr()); diff --git a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/BakeAcesOutputTransformLutPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/BakeAcesOutputTransformLutPass.cpp index 3322b82ff7..7a32925e93 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/BakeAcesOutputTransformLutPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/BakeAcesOutputTransformLutPass.cpp @@ -38,17 +38,7 @@ namespace AZ ReleaseLutImage(); } - void BakeAcesOutputTransformLutPass::FrameBeginInternal(FramePrepareParams params) - { - if (!m_flags.m_initialized) - { - Init(); - } - - ComputePass::FrameBeginInternal(params); - } - - void BakeAcesOutputTransformLutPass::Init() + void BakeAcesOutputTransformLutPass::InitializeInternal() { AZ_Assert(m_shaderResourceGroup != nullptr, "BakeAcesOutputTransformLutPass %s has a null shader resource group when calling Init.", GetPathName().GetCStr()); @@ -67,7 +57,6 @@ namespace AZ m_shaderInputShaperBiasIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name{ "m_shaperBias" }); m_shaderInputShaperScaleIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name{ "m_shaperScale" }); } - m_flags.m_initialized = true; } void BakeAcesOutputTransformLutPass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) diff --git a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperFullScreenPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperFullScreenPass.cpp index 096179d5b6..03fcfbe71d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperFullScreenPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperFullScreenPass.cpp @@ -53,9 +53,5 @@ namespace AZ m_inputReferenceAttachmentName = attachmentName; } - void DisplayMapperFullScreenPass::Init() - { - FullscreenTrianglePass::Init(); - } } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp index f5b301ca5c..0a6a2a59c7 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp @@ -82,7 +82,7 @@ namespace AZ const Name& passName = fullscreenTrianglePass->GetName(); if (passName.GetStringView() == "CopyToSwapChain") { - fullscreenTrianglePass->Invalidate(); + fullscreenTrianglePass->QueueForInitialization(); } } } @@ -186,6 +186,18 @@ namespace AZ ParentPass::BuildInternal(); } + void DisplayMapperPass::InitializeInternal() + { + // Force update on bindings because children of display mapper pass have their outputs connect + // to their parent's output, which is a non-conventional and non-standard workflow + for (const RPI::Ptr& child : m_children) + { + child->UpdateConnectedBindings(); + } + + RPI::ParentPass::InitializeInternal(); + } + void DisplayMapperPass::FrameBeginInternal(FramePrepareParams params) { ConfigureDisplayParameters(); diff --git a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/OutputTransformPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/OutputTransformPass.cpp index a6b23171a5..5937f9ee49 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/OutputTransformPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/OutputTransformPass.cpp @@ -39,9 +39,9 @@ namespace AZ { } - void OutputTransformPass::Init() + void OutputTransformPass::InitializeInternal() { - DisplayMapperFullScreenPass::Init(); + DisplayMapperFullScreenPass::InitializeInternal(); AZ_Assert(m_shaderResourceGroup != nullptr, "OutputTransformPass %s has a null shader resource group when calling Init.", GetPathName().GetCStr()); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BlendColorGradingLutsPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BlendColorGradingLutsPass.cpp index e0ff253301..433f9c0276 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BlendColorGradingLutsPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BlendColorGradingLutsPass.cpp @@ -43,14 +43,9 @@ namespace AZ ReleaseLutImage(); } - void BlendColorGradingLutsPass::FrameBeginInternal(FramePrepareParams params) + void BlendColorGradingLutsPass::InitializeInternal() { - if (!m_flags.m_initialized) - { - Init(); - } - - ComputePass::FrameBeginInternal(params); + InitializeShaderVariant(); } void BlendColorGradingLutsPass::InitializeShaderVariant() @@ -106,12 +101,6 @@ namespace AZ m_needToUpdateShaderVariant = false; } - void BlendColorGradingLutsPass::Init() - { - InitializeShaderVariant(); - m_flags.m_initialized = true; - } - void BlendColorGradingLutsPass::SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) { ComputePass::SetupFrameGraphDependencies(frameGraph); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BlendColorGradingLutsPass.h b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BlendColorGradingLutsPass.h index c131a3cb38..048d0069f4 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BlendColorGradingLutsPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BlendColorGradingLutsPass.h @@ -56,7 +56,7 @@ namespace AZ explicit BlendColorGradingLutsPass(const RPI::PassDescriptor& descriptor); // Pass behavior overrides... - void FrameBeginInternal(FramePrepareParams params) override; + void InitializeInternal() override; // Scope producer functions... void SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) override; @@ -66,8 +66,6 @@ namespace AZ void InitializeShaderVariant(); void UpdateCurrentShaderVariant(); - void Init(); - void AcquireLutImage(); void ReleaseLutImage(); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldBokehBlurPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldBokehBlurPass.cpp index 4a4a8a8b76..090d87e048 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldBokehBlurPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldBokehBlurPass.cpp @@ -43,9 +43,9 @@ namespace AZ { } - void DepthOfFieldBokehBlurPass::Init() + void DepthOfFieldBokehBlurPass::InitializeInternal() { - FullscreenTrianglePass::Init(); + FullscreenTrianglePass::InitializeInternal(); m_sampleNumberIndex.Reset(); m_radiusMinIndex.Reset(); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldBokehBlurPass.h b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldBokehBlurPass.h index 688138fff0..c9b2dc6be2 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldBokehBlurPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldBokehBlurPass.h @@ -39,11 +39,11 @@ namespace AZ protected: // Behaviour functions override... + void InitializeInternal() override; void FrameBeginInternal(FramePrepareParams params) override; private: DepthOfFieldBokehBlurPass(const RPI::PassDescriptor& descriptor); - void Init() override; void InitializeShaderVariant(); void UpdateCurrentShaderVariant(); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldCompositePass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldCompositePass.cpp index 30c92963d0..bf88f8f8fb 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldCompositePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldCompositePass.cpp @@ -40,9 +40,9 @@ namespace AZ { } - void DepthOfFieldCompositePass::Init() + void DepthOfFieldCompositePass::InitializeInternal() { - FullscreenTrianglePass::Init(); + FullscreenTrianglePass::InitializeInternal(); m_backBlendFactorDivision2Index.Reset(); m_backBlendFactorDivision4Index.Reset(); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldCompositePass.h b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldCompositePass.h index fe4d60e679..00afdd0b0b 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldCompositePass.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldCompositePass.h @@ -37,11 +37,11 @@ namespace AZ protected: // Pass behavior overrides... + void InitializeInternal() override; void FrameBeginInternal(FramePrepareParams params) override; private: DepthOfFieldCompositePass(const RPI::PassDescriptor& descriptor); - void Init() override; void InitializeShaderVariant(); void UpdateCurrentShaderVariant(); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldMaskPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldMaskPass.cpp index 3f9c09c88c..93c19e5484 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldMaskPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldMaskPass.cpp @@ -33,9 +33,9 @@ namespace AZ { } - void DepthOfFieldMaskPass::Init() + void DepthOfFieldMaskPass::InitializeInternal() { - FullscreenTrianglePass::Init(); + FullscreenTrianglePass::InitializeInternal(); m_blendFactorIndex.Reset(); m_inputResolutionInverseIndex.Reset(); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldMaskPass.h b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldMaskPass.h index 09bb08a22c..7e21f87af7 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldMaskPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldMaskPass.h @@ -37,11 +37,11 @@ namespace AZ protected: // Pass behavior overrides... + void InitializeInternal() override; void FrameBeginInternal(FramePrepareParams params) override; private: DepthOfFieldMaskPass(const RPI::PassDescriptor& descriptor); - virtual void Init() override; // SRG binding indices... RHI::ShaderInputNameIndex m_blendFactorIndex = "m_blendFactor"; diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationCompositePass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationCompositePass.cpp index aff01d5bf1..45d3e0c39a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationCompositePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationCompositePass.cpp @@ -48,9 +48,9 @@ namespace AZ } } - void LookModificationCompositePass::Init() + void LookModificationCompositePass::InitializeInternal() { - FullscreenTrianglePass::Init(); + FullscreenTrianglePass::InitializeInternal(); m_shaderColorGradingLutImageIndex.Reset(); m_shaderColorGradingShaperTypeIndex.Reset(); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationCompositePass.h b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationCompositePass.h index fb6c968436..8292330a2d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationCompositePass.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationCompositePass.h @@ -60,9 +60,9 @@ namespace AZ protected: LookModificationCompositePass(const RPI::PassDescriptor& descriptor); - void Init() override; //! Pass behavior overrides + void InitializeInternal() override; void FrameBeginInternal(FramePrepareParams params) final; private: diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAABasePass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAABasePass.cpp index d2424e24fd..f95637e824 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAABasePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAABasePass.cpp @@ -43,9 +43,9 @@ namespace AZ { } - void SMAABasePass::Init() + void SMAABasePass::InitializeInternal() { - FullscreenTrianglePass::Init(); + FullscreenTrianglePass::InitializeInternal(); AZ_Assert(m_shaderResourceGroup != nullptr, "SMAABasePass %s has a null shader resource group when calling Init.", GetPathName().GetCStr()); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAABasePass.h b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAABasePass.h index 0484b7d430..3a18d587b5 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAABasePass.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAABasePass.h @@ -41,9 +41,12 @@ namespace AZ protected: SMAABasePass(const RPI::PassDescriptor& descriptor); - void Init() override; + // Pass behavior overrides... + void InitializeInternal() override; + // An interface to update pass srg. virtual void UpdateSRG() = 0; + // An interface to get current shader variation option. virtual void GetCurrentShaderOption(AZ::RPI::ShaderOptionGroup& shaderOption) const = 0; diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAABlendingWeightCalculationPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAABlendingWeightCalculationPass.cpp index 39d9e51c86..7776bc3904 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAABlendingWeightCalculationPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAABlendingWeightCalculationPass.cpp @@ -94,9 +94,9 @@ namespace AZ } } - void SMAABlendingWeightCalculationPass::Init() + void SMAABlendingWeightCalculationPass::InitializeInternal() { - SMAABasePass::Init(); + SMAABasePass::InitializeInternal(); AZ_Assert(m_shaderResourceGroup != nullptr, "SMAABlendingWeightCalculationPass %s has a null shader resource group when calling Init.", GetPathName().GetCStr()); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAABlendingWeightCalculationPass.h b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAABlendingWeightCalculationPass.h index b968a9c2d9..2f589a7ae6 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAABlendingWeightCalculationPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAABlendingWeightCalculationPass.h @@ -43,7 +43,9 @@ namespace AZ private: SMAABlendingWeightCalculationPass(const RPI::PassDescriptor& descriptor); - void Init() override; + + // Pass behavior overrides... + void InitializeInternal() override; // SMAABasePass functions... void UpdateSRG() override; diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAEdgeDetectionPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAEdgeDetectionPass.cpp index 68485f3280..bb8069d0de 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAEdgeDetectionPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAEdgeDetectionPass.cpp @@ -48,9 +48,9 @@ namespace AZ { } - void SMAAEdgeDetectionPass::Init() + void SMAAEdgeDetectionPass::InitializeInternal() { - SMAABasePass::Init(); + SMAABasePass::InitializeInternal(); m_renderTargetMetricsShaderInputIndex.Reset(); m_chromaThresholdShaderInputIndex.Reset(); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAEdgeDetectionPass.h b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAEdgeDetectionPass.h index f8302c55ca..f2c85297b6 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAEdgeDetectionPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAEdgeDetectionPass.h @@ -45,7 +45,9 @@ namespace AZ private: SMAAEdgeDetectionPass(const RPI::PassDescriptor& descriptor); - void Init() override; + + // Pass behavior overrides + void InitializeInternal() override; // SMAABasePass functions... void UpdateSRG() override; diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAANeighborhoodBlendingPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAANeighborhoodBlendingPass.cpp index 777e4d7d95..b2307de714 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAANeighborhoodBlendingPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAANeighborhoodBlendingPass.cpp @@ -47,9 +47,9 @@ namespace AZ { } - void SMAANeighborhoodBlendingPass::Init() + void SMAANeighborhoodBlendingPass::InitializeInternal() { - SMAABasePass::Init(); + SMAABasePass::InitializeInternal(); m_renderTargetMetricsShaderInputIndex.Reset(); } diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAANeighborhoodBlendingPass.h b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAANeighborhoodBlendingPass.h index 86386a0545..f54ff30575 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAANeighborhoodBlendingPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAANeighborhoodBlendingPass.h @@ -37,7 +37,9 @@ namespace AZ private: SMAANeighborhoodBlendingPass(const RPI::PassDescriptor& descriptor); - void Init() override; + + // Pass behavior overrides + void InitializeInternal() override; // SMAABasePass functions... void UpdateSRG() override; diff --git a/Gems/Atom/Feature/Common/Code/Source/ScreenSpace/DeferredFogPass.cpp b/Gems/Atom/Feature/Common/Code/Source/ScreenSpace/DeferredFogPass.cpp index 477040b74a..70e17a28d3 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ScreenSpace/DeferredFogPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ScreenSpace/DeferredFogPass.cpp @@ -46,9 +46,9 @@ namespace AZ } - void DeferredFogPass::Init() + void DeferredFogPass::InitializeInternal() { - FullscreenTrianglePass::Init(); + FullscreenTrianglePass::InitializeInternal(); // The following will ensure that in the case of data driven pass, the settings will get // updated by the pass enable state. diff --git a/Gems/Atom/Feature/Common/Code/Source/ScreenSpace/DeferredFogPass.h b/Gems/Atom/Feature/Common/Code/Source/ScreenSpace/DeferredFogPass.h index e2740850de..78b7d25bff 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ScreenSpace/DeferredFogPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/ScreenSpace/DeferredFogPass.h @@ -43,13 +43,11 @@ namespace AZ { AZ_RPI_PASS(DeferredFogPass); - public: AZ_RTTI(DeferredFogPass, "{0406C8AB-E95D-43A7-AF53-BDEE22D36746}", RPI::FullscreenTrianglePass); AZ_CLASS_ALLOCATOR(DeferredFogPass, SystemAllocator, 0); ~DeferredFogPass() = default; - void Init() override; static RPI::Ptr Create(const RPI::PassDescriptor& descriptor); @@ -57,12 +55,16 @@ namespace AZ virtual bool IsEnabled() const override; - void SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) override; - void CompileResources(const RHI::FrameGraphCompileContext& context) override; - protected: DeferredFogPass(const RPI::PassDescriptor& descriptor); + // Pass behavior overrides... + void InitializeInternal() override; + + // Scope producer functions... + void SetupFrameGraphDependencies(RHI::FrameGraphInterface frameGraph) override; + void CompileResources(const RHI::FrameGraphCompileContext& context) override; + //! Set the binding indices of all members of the SRG void SetSrgBindIndices(); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/FullscreenTrianglePass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/FullscreenTrianglePass.h index fdb3241b44..616fc4639a 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/FullscreenTrianglePass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/FullscreenTrianglePass.h @@ -44,14 +44,11 @@ namespace AZ //! Creates a FullscreenTrianglePass static Ptr Create(const PassDescriptor& descriptor); - // Clears the initialized flag so that the next time PrepareFrameInternal is called, it will update the pipeline state - void Invalidate(); - protected: FullscreenTrianglePass(const PassDescriptor& descriptor); - virtual void Init(); // Pass behavior overrides... + void InitializeInternal() override; void FrameBeginInternal(FramePrepareParams params) override; RHI::Viewport m_viewportState; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h index 1cfd2e759e..70af161e18 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h @@ -262,6 +262,15 @@ namespace AZ PassState GetPassState() const; + + + + // Update all bindings on this pass that are connected to bindings on other passes + void UpdateConnectedBindings(); + + + + protected: explicit Pass(const PassDescriptor& descriptor); @@ -393,7 +402,6 @@ namespace AZ uint64_t m_enabled : 1; uint64_t m_parentEnabled : 1; - uint64_t m_initialized : 1; uint64_t m_alreadyCreated : 1; uint64_t m_createChildren : 1; @@ -427,6 +435,12 @@ namespace AZ // fully custom sort implementations by overriding the SortDrawList() function. RHI::DrawListSortType m_drawListSortType = RHI::DrawListSortType::KeyThenDepth; + + + + + + private: // Return the Timestamp result of this pass virtual TimestampResult GetTimestampResultInternal() const; @@ -475,9 +489,6 @@ namespace AZ // This sets the binding's attachment pointer to the connected binding's attachment void UpdateConnectedBinding(PassAttachmentBinding& binding); - // Update all bindings on this pass that are connected to bindings on other passes - void UpdateConnectedBindings(); - // Process a PassFallbackConnection to connect an output to an input to act as a short-circuit for when Pass is disabled void ProcessFallbackConnection(const PassFallbackConnection& connection); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp index 1f8f361b8b..a854867998 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp @@ -64,6 +64,8 @@ namespace AZ void FullscreenTrianglePass::LoadShader() { + AZ_Assert(GetPassState() != PassState::Rendering, "FullscreenTrianglePass - Reloading shader during Rendering phase!"); + // Load FullscreenTrianglePassData const FullscreenTrianglePassData* passData = PassUtils::GetPassData(m_passDescriptor); if (passData == nullptr) @@ -121,14 +123,16 @@ namespace AZ // Store stencil reference value for the draw call m_stencilRef = passData->m_stencilRef; - m_flags.m_initialized = false; + QueueForInitialization(); ShaderReloadNotificationBus::Handler::BusDisconnect(); ShaderReloadNotificationBus::Handler::BusConnect(shaderAsset.GetId()); } - void FullscreenTrianglePass::Init() + void FullscreenTrianglePass::InitializeInternal() { + RenderPass::InitializeInternal(); + // This draw item purposefully does not reference any geometry buffers. // Instead it's expected that the extended class uses a vertex shader // that generates a full-screen triangle completely from vertex ids. @@ -155,17 +159,10 @@ namespace AZ m_item.m_arguments = RHI::DrawArguments(draw); m_item.m_pipelineState = m_shader->AcquirePipelineState(pipelineStateDescriptor); m_item.m_stencilRef = m_stencilRef; - - m_flags.m_initialized = true; } void FullscreenTrianglePass::FrameBeginInternal(FramePrepareParams params) { - if (!m_flags.m_initialized) - { - Init(); - } - const PassAttachment* outputAttachment = nullptr; if (GetOutputCount() > 0) @@ -225,11 +222,6 @@ namespace AZ commandList->Submit(m_item); } - - void FullscreenTrianglePass::Invalidate() - { - m_flags.m_initialized = false; - } } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp index 78e30e7176..d03405dafd 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp @@ -1088,6 +1088,12 @@ namespace AZ void Pass::QueueForInitialization() { + // Pass::FrameBegin - Pass [Root.LowEndPipeline.LowEndPipelineTemplate.LightAdaptation.LookModificationTransformPass.LookModificationComposite] is attempting to render, but is not in the Idle state. + if (m_path == Name("Root.LowEndPipeline.LowEndPipelineTemplate.LightAdaptation.LookModificationTransformPass.LookModificationComposite")) + { + __nop(); + } + // Only queue if the pass is not in any other queue if (m_queueState == PassQueueState::NoQueue) { @@ -1119,6 +1125,11 @@ namespace AZ void Pass::Reset() { + if (m_path == Name("Root.LowEndPipeline.LowEndPipelineTemplate.LightAdaptation.LookModificationTransformPass.LookModificationComposite")) + { + __nop(); + } + bool execute = (m_state == PassState::Idle); execute = execute || (m_state == PassState::Queued && m_queueState == PassQueueState::QueuedForBuild); execute = execute || (m_state == PassState::Queued && m_queueState == PassQueueState::QueuedForInitialization); @@ -1158,6 +1169,11 @@ namespace AZ void Pass::Build(bool calledFromPassSystem) { + if (m_path == Name("Root.LowEndPipeline.LowEndPipelineTemplate.LightAdaptation.LookModificationTransformPass.LookModificationComposite")) + { + __nop(); + } + AZ_RPI_BREAK_ON_TARGET_PASS; bool execute = (m_state == PassState::Idle || m_state == PassState::Reset); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp index 76ea52b4a3..50a2c0db91 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp @@ -103,7 +103,7 @@ namespace AZ m_rootPass = CreatePass(Name{"Root"}); m_rootPass->m_flags.m_partOfHierarchy = true; - //m_targetedPassDebugName = "RPISamplePipeline"; + //m_targetedPassDebugName = "AcesOutputTransform"; m_state = PassSystemState::Idle; } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp index 2c4c61f5aa..8e624abe13 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp @@ -107,8 +107,13 @@ namespace AZ pipeline->m_originalRenderSettings = desc.m_renderSettings; pipeline->m_activeRenderSettings = desc.m_renderSettings; pipeline->m_rootPass->SetRenderPipeline(pipeline); + + // Manually create the pipeline so we can gather the view tags from it's passes + pipeline->m_rootPass->Reset(); pipeline->m_rootPass->Build(); pipeline->m_rootPass->Initialize(); + pipeline->m_rootPass->OnInitializationFinished(); + pipeline->BuildPipelineViews(); } From c996b348356a0960befc7efd28407c5138924c10 Mon Sep 17 00:00:00 2001 From: antonmic Date: Tue, 8 Jun 2021 23:13:40 -0700 Subject: [PATCH 15/73] Pass changes WIP: small optimization --- Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp | 1 - Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp index 8e624abe13..4e565895e9 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp @@ -109,7 +109,6 @@ namespace AZ pipeline->m_rootPass->SetRenderPipeline(pipeline); // Manually create the pipeline so we can gather the view tags from it's passes - pipeline->m_rootPass->Reset(); pipeline->m_rootPass->Build(); pipeline->m_rootPass->Initialize(); pipeline->m_rootPass->OnInitializationFinished(); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp index 7e33750eb5..5f9ba38c88 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp @@ -291,7 +291,6 @@ namespace AZ pipeline->OnAddedToScene(this); // Force to update the lookup table since adding render pipeline would effect any pipeline states created before pass system tick - AZ::RPI::PassSystemInterface::Get()->ProcessQueuedChanges(); RebuildPipelineStatesLookup(); AZ_Assert(!m_id.IsNull(), "RPI::Scene needs to have a valid uuid."); From 1ddb94ada1f91cb7853cab155116923f8675814c Mon Sep 17 00:00:00 2001 From: antonmic Date: Wed, 9 Jun 2021 08:55:57 -0700 Subject: [PATCH 16/73] Pass changes: final cleanup --- .../DisplayMapper/DisplayMapperPass.cpp | 6 +- .../Code/Include/Atom/RPI.Public/Pass/Pass.h | 48 +++++----- .../Atom/RPI.Public/Pass/PassDefines.h | 42 ++++++++- .../RPI.Public/Pass/PassSystemInterface.h | 27 +++++- .../RPI/Code/Source/RPI.Public/Pass/Pass.cpp | 94 ++----------------- .../Source/RPI.Public/Pass/PassSystem.cpp | 38 +++----- .../Code/Source/RPI.Public/RenderPipeline.cpp | 8 +- 7 files changed, 119 insertions(+), 144 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp index 0a6a2a59c7..219d673ece 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp @@ -188,8 +188,10 @@ namespace AZ void DisplayMapperPass::InitializeInternal() { - // Force update on bindings because children of display mapper pass have their outputs connect - // to their parent's output, which is a non-conventional and non-standard workflow + // Force update on bindings because children of display mapper pass have their outputs connect to + // their parent's output, which is a non-conventional and non-standard workflow. Parent outputs are + // updated after child outputs, so post-build the child outputs do not yet point to the attachments on + // the parent bindings they are connected to. Forcing this refresh sets the attachment on the child output. for (const RPI::Ptr& child : m_children) { child->UpdateConnectedBindings(); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h index 70af161e18..b154b031c2 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h @@ -79,9 +79,9 @@ namespace AZ //! //! When authoring a new pass class, inherit from Pass and override any of the virtual functions //! ending with 'Internal' to define the behavior of your passes. These virtual are recursively - //! called in Preorder order throughout the pass tree. Only FramePrepare and FrameEnd are + //! called in preorder traversal throughout the pass tree. Only FrameBegin and FrameEnd are //! guaranteed to be called per frame. The other override-able functions are called as needed - //! when scheduled with the PassSystem. See QueueForBuild and QueueForRemoval. + //! when scheduled with the PassSystem. See QueueForBuild, QueueForRemoval and QueueForInitialization. //! //! Passes are created by the PassFactory. They can be created using either Pass Name, //! a PassTemplate, or a PassRequest. To register your pass class with the PassFactory, @@ -262,15 +262,10 @@ namespace AZ PassState GetPassState() const; - - - // Update all bindings on this pass that are connected to bindings on other passes void UpdateConnectedBindings(); - - protected: explicit Pass(const PassDescriptor& descriptor); @@ -333,15 +328,15 @@ namespace AZ void Build(bool calledFromPassSystem = false); virtual void BuildInternal() { } - // Called after the pass build phase has finished. Allows passes to reset build flags. - void OnInitializationFinished(); - virtual void OnInitializationFinishedInternal() { }; - // Allows for additional pass initialization between building and rendering - // Can be queued independently of Build so as to only invoke Initialize without Build + // Can be queued independently of Build so as to only invoke Initialize() without Build() void Initialize(); virtual void InitializeInternal() { }; + // Called after the pass initialization phase has finished. Allows passes to reset various states and flags. + void OnInitializationFinished(); + virtual void OnInitializationFinishedInternal() { }; + // The Pass's 'Render' function. Called every frame, here the pass sets up it's rendering logic with // the FrameGraphBuilder. This is where your derived pass needs to call ImportScopeProducer on // the FrameGraphBuilder if it's a ScopeProducer (see ForwardPass::FrameBeginInternal for example). @@ -398,23 +393,34 @@ namespace AZ { struct { + // Whether this pass was created with a PassRequest (in which case m_request holds valid data) uint64_t m_createdByPassRequest : 1; + + // Whether the pass is enabled (behavior can be customized by overriding IsEnabled() ) uint64_t m_enabled : 1; + + // False if parent or one of it's ancestors is disabled uint64_t m_parentEnabled : 1; + // If this is a parent pass, indicates if the pass has already created children this frame uint64_t m_alreadyCreated : 1; - uint64_t m_createChildren : 1; - - // OLD SCHOOL - uint64_t m_alreadyPrepared : 1; - uint64_t m_alreadyReset : 1; - uint64_t m_queuedForBuildAttachment : 1; + // If this is a parent pass, indicates whether the pass needs to create child passes + uint64_t m_createChildren : 1; + // Whether this pass belongs to the pass hierarchy, i.e. if you can trace it's parents up to the Root pass uint64_t m_partOfHierarchy : 1; + + // Whether this pass has a DrawListTag uint64_t m_hasDrawListTag : 1; + + // Whether this pass has a PipelineViewTag uint64_t m_hasPipelineViewTag : 1; + + // Whether the pass should gather timestamp query metrics uint64_t m_timestampQueryEnabled : 1; + + // Whether the pass should gather pipeline statics uint64_t m_pipelineStatisticsQueryEnabled : 1; }; uint64_t m_allFlags = 0; @@ -436,11 +442,6 @@ namespace AZ RHI::DrawListSortType m_drawListSortType = RHI::DrawListSortType::KeyThenDepth; - - - - - private: // Return the Timestamp result of this pass virtual TimestampResult GetTimestampResultInternal() const; @@ -528,6 +529,7 @@ namespace AZ // buffers and images don't get deleted during attachment build phase AZStd::vector> m_importedAttachmentStore; + // Name of the pass. Will be concatenated with parent names to form a unique path Name m_name; // Path of the pass in the hierarchy. Example: Root.Ssao.Downsample diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassDefines.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassDefines.h index 7ba7f1be4e..e34c61e3aa 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassDefines.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassDefines.h @@ -20,31 +20,71 @@ // Enables debugging of the pass system // Set this to 1 locally on your machine to facilitate pass debugging and get extra information // about passes in the output window. DO NOT SUBMIT with value set to 1 -#define AZ_RPI_ENABLE_PASS_DEBUGGING 1 +#define AZ_RPI_ENABLE_PASS_DEBUGGING 0 namespace AZ { namespace RPI { + // This enum tracks the state of passes across build, initialization and rendering enum class PassState : u8 { + // Default value, you should only ever see this in the Pass constructor + // Once the constructor is done, the Pass will set it's state to Reset Uninitialized, + + // Pass is queued with the Pass System for an update (see PassQueueState below) + // From Queued, the pass can transition into Resetting, Building or Initializing depending on the PassQueueState Queued, + + // Pass is currently in the process of resetting + // From Resetting, the pass can transition into Resetting, + + // Pass has been reset and is await build + // From Reset, the pass can transition to Building Reset, + + // Pass is currently building + // From Building, the pass can transition to Built Building, + + // Pass has been built and is awaiting initialization + // From Built, the pass can transition to Initializing Built, + + // Pass is currently being initialized + // From Initializing, the pass can transition to Initialized Initializing, + + // Pass has been initialized + // From Initialized, the pass can transition to Idle Initialized, + + // Idle state, pass is awaiting rendering + // From Idle, the pass can transition to Queued, Resetting, Building, Initializing or Rendering Idle, + + // Pass is currently rendering. Pass must be in Idle state before entering this state + // From Rendering, the pass can transition to Idle or Queue if the pass was queued with the Pass System during Rendering Rendering }; + // This enum keeps track of what actions the pass is queued for with the pass system enum class PassQueueState : u8 { + // The pass is currently not in any queued state and may therefore transition to any queued state NoQueue, + + // The pass is queued for Removal at the start of the next frame. Cannot be overridden by any other queue state QueuedForRemoval, + + // The pass is queued for Build at the start of the frame. Note that any pass built at the start of the frame will also be initialized. + // This state can be overridden by QueuedForRemoval QueuedForBuild, + + // The pass is queued for Initialization at the start of the frame. + // This state has the lowest priority and can therefore be overridden by QueueForBuild or QueueForRemoval QueuedForInitialization, }; } diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h index 788d00c8eb..72501fc61c 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h @@ -40,15 +40,34 @@ namespace AZ using PassCreator = AZStd::function(const PassDescriptor& descriptor)>; + // Enum to track the different execution phases of the Pass System enum class PassSystemState : u32 { + // Default state, Unitialized, - Idle, + + // Initial Pass System setup. Transitions to Idle + InitializingPassSystem, + + // Pass System is processing passes queued for Removal. Transitions to Idle RemovingPasses, - Building, - Initializing, - Validating, + + // Pass System is processing passes queued for Build (and their child passes). Transitions to Idle + BuildingPasses, + + // Pass System is processing passes queued for Initialization (and their child passes). Transitions to Idle + InitializingPasses, + + // Pass System is validating that the Pass hierarchy is in a valid state after Build and Initialization. Transitions to Idle + ValidatingPasses, + + // Pass System is idle and can transition to any other state (except FrameEnd) + Idle, + + // Pass System is currently rendering a frame. Transitions to FrameEnd Rendering, + + // Pass System is finishing rendering a frame. Transitions to Idle FrameEnd, }; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp index d03405dafd..f36673221b 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp @@ -78,7 +78,6 @@ namespace AZ // Skip reset since the pass just got created m_state = PassState::Reset; - m_flags.m_alreadyReset = true; } Pass::~Pass() @@ -1040,42 +1039,13 @@ namespace AZ // --- Queuing functions with PassSystem --- -#define OLD_SCHOOL 1 - void Pass::QueueForBuild() { -#if 0//OLD_SCHOOL - // Don't queue if we're in building phase - //if (PassSystemInterface::Get()->GetState() != RPI::PassSystemState::Building) - { - if (!m_flags.m_queuedForBuildAttachment) - { - PassSystemInterface::Get()->QueueForBuild(this); - m_flags.m_queuedForBuildAttachment = true; - - // Set these two flags to false since when queue build attachments request, they should all be already be false except one use - // case that the pass system processed all queued requests when active a scene. - // m_flags.m_alreadyReset = false; - // m_flags.m_alreadyPrepared = false; - - m_queueState = PassQueueState::QueuedForBuild; - - if (m_state != PassState::Rendering) - { - m_state = PassState::Queued; - } - - } - } -#else - // Don't queue if we're in building phase + // Queue if not already queued or if queued for initialization only. Don't queue if we're currently building. if (m_state != PassState::Building && (m_queueState == PassQueueState::NoQueue || m_queueState == PassQueueState::QueuedForInitialization)) { - //if (PassSystemInterface::Get()->GetState() != RPI::PassSystemState::Building) - { - PassSystemInterface::Get()->QueueForBuild(this); - } + PassSystemInterface::Get()->QueueForBuild(this); m_queueState = PassQueueState::QueuedForBuild; if (m_state != PassState::Rendering) @@ -1083,19 +1053,12 @@ namespace AZ m_state = PassState::Queued; } } -#endif } void Pass::QueueForInitialization() { - // Pass::FrameBegin - Pass [Root.LowEndPipeline.LowEndPipelineTemplate.LightAdaptation.LookModificationTransformPass.LookModificationComposite] is attempting to render, but is not in the Idle state. - if (m_path == Name("Root.LowEndPipeline.LowEndPipelineTemplate.LightAdaptation.LookModificationTransformPass.LookModificationComposite")) - { - __nop(); - } - - // Only queue if the pass is not in any other queue - if (m_queueState == PassQueueState::NoQueue) + // Only queue if the pass is not in any other queue. Don't queue if we're currently initializing. + if (m_queueState == PassQueueState::NoQueue && m_state != PassState::Initializing) { PassSystemInterface::Get()->QueueForInitialization(this); m_queueState = PassQueueState::QueuedForInitialization; @@ -1109,6 +1072,8 @@ namespace AZ void Pass::QueueForRemoval() { + // Skip only if we're already queued for removal, otherwise proceed. + // QueuedForRemoval overrides QueuedForBuild and QueuedForInitialization. if (m_queueState != PassQueueState::QueuedForRemoval) { PassSystemInterface::Get()->QueueForRemoval(this); @@ -1125,28 +1090,15 @@ namespace AZ void Pass::Reset() { - if (m_path == Name("Root.LowEndPipeline.LowEndPipelineTemplate.LightAdaptation.LookModificationTransformPass.LookModificationComposite")) - { - __nop(); - } - + // Ensure we're in a valid state to reset. This ensures the pass won't be reset multiple times in the same frame. bool execute = (m_state == PassState::Idle); execute = execute || (m_state == PassState::Queued && m_queueState == PassQueueState::QueuedForBuild); execute = execute || (m_state == PassState::Queued && m_queueState == PassQueueState::QueuedForInitialization); -#if OLD_SCHOOL - AZ_Assert(!execute == m_flags.m_alreadyReset, "ANTON - EARLY OUT FLAGS do not match for pass RESET!!"); - if (m_flags.m_alreadyReset) - { - return; - } - m_flags.m_alreadyReset = true; -#else if (!execute) { return; } -#endif m_state = PassState::Resetting; @@ -1169,32 +1121,16 @@ namespace AZ void Pass::Build(bool calledFromPassSystem) { - if (m_path == Name("Root.LowEndPipeline.LowEndPipelineTemplate.LightAdaptation.LookModificationTransformPass.LookModificationComposite")) - { - __nop(); - } - AZ_RPI_BREAK_ON_TARGET_PASS; - bool execute = (m_state == PassState::Idle || m_state == PassState::Reset); - execute = execute || (m_state == PassState::Queued && m_queueState == PassQueueState::QueuedForBuild); - execute = execute || (m_state == PassState::Queued && m_queueState == PassQueueState::QueuedForInitialization); + // Ensure we're in a valid state to build. This ensures the pass won't be built multiple times in the same frame. + bool execute = (m_state == PassState::Reset); -#if OLD_SCHOOL - AZ_Assert(!execute == m_flags.m_alreadyPrepared, "ANTON - EARLY OUT FLAGS do not match for pass BUILD!!"); - if (m_flags.m_alreadyPrepared) - { - return; - } - m_flags.m_alreadyPrepared = true; -#else if (!execute) { return; } -#endif - AZ_Assert(m_state == PassState::Reset, "ANTON - BUILDING PASS BUT STATE IS NOT RESET!!"); m_state = PassState::Building; // Bindings, inputs and attachments @@ -1233,6 +1169,7 @@ namespace AZ { AZ_RPI_BREAK_ON_TARGET_PASS; + // Ensure we're in a valid state to initialize. This ensures the pass won't be initialized multiple times in the same frame. bool execute = (m_state == PassState::Idle || m_state == PassState::Built); execute = execute || (m_state == PassState::Queued && m_queueState == PassQueueState::QueuedForInitialization); @@ -1244,11 +1181,6 @@ namespace AZ m_state = PassState::Initializing; m_queueState = PassQueueState::NoQueue; - // Update -// UpdateConnectedBindings(); -// UpdateOwnedAttachments(); -// UpdateAttachmentUsageIndices(); - InitializeInternal(); m_state = PassState::Initialized; @@ -1256,12 +1188,6 @@ namespace AZ void Pass::OnInitializationFinished() { - AZ_RPI_BREAK_ON_TARGET_PASS; - - m_flags.m_alreadyReset = false; - m_flags.m_alreadyPrepared = false; - m_flags.m_queuedForBuildAttachment = false; - m_flags.m_alreadyCreated = false; m_importedAttachmentStore.clear(); OnInitializationFinishedInternal(); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp index 50a2c0db91..d209d03580 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp @@ -95,7 +95,7 @@ namespace AZ void PassSystem::Init() { - m_state = PassSystemState::Initializing; + m_state = PassSystemState::InitializingPassSystem; Interface::Register(this); m_passLibrary.Init(); @@ -103,7 +103,10 @@ namespace AZ m_rootPass = CreatePass(Name{"Root"}); m_rootPass->m_flags.m_partOfHierarchy = true; - //m_targetedPassDebugName = "AcesOutputTransform"; + // Here you can specify the name of a pass you would like to break into during execution + // If you enable AZ_RPI_ENABLE_PASS_DEBUGGING, then any pass matching the specified name will debug + // break on any instance of the AZ_RPI_BREAK_ON_TARGET_PASS macro. See Pass::Build for an example + // m_targetedPassDebugName = "MyPassName"; m_state = PassSystemState::Idle; } @@ -189,12 +192,11 @@ namespace AZ void PassSystem::BuildPasses() { - m_state = PassSystemState::Building; + m_state = PassSystemState::BuildingPasses; AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzRender); AZ_ATOM_PROFILE_FUNCTION("RPI", "PassSystem: BuildPassAttachments"); m_passHierarchyChanged = m_passHierarchyChanged || !m_buildPassList.empty(); - u32 loopCounter = 0; // While loop is for the event in which passes being built add more pass to m_buildPassList while(!m_buildPassList.empty()) @@ -214,25 +216,14 @@ namespace AZ SortPassListAscending(buildListCopy); - Pass* previousPassInList = nullptr; for (const Ptr& pass : buildListCopy) { - if (pass.get() != previousPassInList) - { - pass->Reset(); - previousPassInList = pass.get(); - } + pass->Reset(); } - previousPassInList = nullptr; for (const Ptr& pass : buildListCopy) { - if (pass.get() != previousPassInList) - { - pass->Build(true); - previousPassInList = pass.get(); - } + pass->Build(true); } - loopCounter++; } if (m_passHierarchyChanged) @@ -251,12 +242,11 @@ namespace AZ void PassSystem::InitializePasses() { - m_state = PassSystemState::Initializing; + m_state = PassSystemState::InitializingPasses; AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzRender); AZ_ATOM_PROFILE_FUNCTION("RPI", "PassSystem: BuildPassAttachments"); m_passHierarchyChanged = m_passHierarchyChanged || !m_initializePassList.empty(); - u32 loopCounter = 0; while (!m_initializePassList.empty()) { @@ -273,16 +263,10 @@ namespace AZ SortPassListAscending(initListCopy); - Pass* previousPassInList = nullptr; for (const Ptr& pass : initListCopy) { - if (pass.get() != previousPassInList) - { - pass->Initialize(); - previousPassInList = pass.get(); - } + pass->Initialize(); } - loopCounter++; } if (m_passHierarchyChanged) @@ -296,7 +280,7 @@ namespace AZ void PassSystem::Validate() { - m_state = PassSystemState::Validating; + m_state = PassSystemState::ValidatingPasses; AZ_ATOM_PROFILE_FUNCTION("RPI", "PassSystem: Validate"); if (PassValidation::IsEnabled()) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp index 4e565895e9..051282a7b0 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp @@ -108,7 +108,7 @@ namespace AZ pipeline->m_activeRenderSettings = desc.m_renderSettings; pipeline->m_rootPass->SetRenderPipeline(pipeline); - // Manually create the pipeline so we can gather the view tags from it's passes + // Manually build the pipeline so we can gather the view tags from it's passes pipeline->m_rootPass->Build(); pipeline->m_rootPass->Initialize(); pipeline->m_rootPass->OnInitializationFinished(); @@ -326,8 +326,10 @@ namespace AZ Ptr newRoot = m_rootPass->Recreate(); newRoot->SetRenderPipeline(this); - // Force processing of queued changes so we can validate the new pipeline - passSystem->ProcessQueuedChanges(); + // Manually build the pipeline + newRoot->Build(); + newRoot->Initialize(); + newRoot->OnInitializationFinished(); // Validate the new root PassValidationResults validation; From 886931f2a930b3080ba034e2d6f83cfa100d9b7c Mon Sep 17 00:00:00 2001 From: antonmic Date: Wed, 9 Jun 2021 09:24:34 -0700 Subject: [PATCH 17/73] Pass changes: minor fixes misses previously --- Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp | 1 + Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp | 3 --- Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp | 2 -- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp index e06ffca556..773deafe68 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp @@ -248,6 +248,7 @@ namespace AZ void ParentPass::CreateChildPasses() { + // The already created flag prevents this function from executing multiple times a frame if (!m_flags.m_createChildren || m_flags.m_alreadyCreated) { return; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp index f36673221b..7ae3559e38 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp @@ -42,7 +42,6 @@ namespace AZ { namespace RPI { -#pragma optimize("", off) // --- Constructors --- @@ -1633,8 +1632,6 @@ namespace AZ } } -#pragma optimize("", on) - } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp index d209d03580..ad3d6d31ca 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp @@ -50,7 +50,6 @@ namespace AZ { namespace RPI { -#pragma optimize("", off) PassSystemInterface* PassSystemInterface::Get() { @@ -486,6 +485,5 @@ namespace AZ return nullptr; } -#pragma optimize("", on) } // namespace RPI } // namespace AZ From 258741b4c9f08322bff3fc4ae72260f7ba8479e7 Mon Sep 17 00:00:00 2001 From: evanchia Date: Wed, 9 Jun 2021 09:50:46 -0700 Subject: [PATCH 18/73] enabling smoke test --- AutomatedTesting/Gem/PythonTests/smoke/CMakeLists.txt | 2 +- .../PythonTests/smoke/test_Editor_NewExistingLevels_Works.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/smoke/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/smoke/CMakeLists.txt index a3b6e36250..18ffa1944d 100644 --- a/AutomatedTesting/Gem/PythonTests/smoke/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/smoke/CMakeLists.txt @@ -40,6 +40,6 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) AutomatedTesting.GameLauncher AutomatedTesting.Assets COMPONENT - Smoke + Sandbox ) endif() \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/smoke/test_Editor_NewExistingLevels_Works.py b/AutomatedTesting/Gem/PythonTests/smoke/test_Editor_NewExistingLevels_Works.py index e6b072ba58..985740307f 100644 --- a/AutomatedTesting/Gem/PythonTests/smoke/test_Editor_NewExistingLevels_Works.py +++ b/AutomatedTesting/Gem/PythonTests/smoke/test_Editor_NewExistingLevels_Works.py @@ -15,7 +15,7 @@ from automatedtesting_shared.base import TestAutomationBase import ly_test_tools.environment.file_system as file_system -@pytest.mark.SUITE_sandbox +@pytest.mark.SUITE_smoke @pytest.mark.parametrize("launcher_platform", ["windows_editor"]) @pytest.mark.parametrize("project", ["AutomatedTesting"]) @pytest.mark.parametrize("level", ["temp_level"]) From 0fbeec7f176169074ef64535ec81794f0e5ca2b5 Mon Sep 17 00:00:00 2001 From: guthadam Date: Wed, 9 Jun 2021 11:57:21 -0500 Subject: [PATCH 19/73] Enabling linux compilation --- Gems/Atom/Tools/MaterialEditor/Code/CMakeLists.txt | 1 - .../MaterialEditor/Code/Source/Platform/Linux/PAL_linux.cmake | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/CMakeLists.txt b/Gems/Atom/Tools/MaterialEditor/Code/CMakeLists.txt index dddb339cfb..07449fe59f 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/CMakeLists.txt +++ b/Gems/Atom/Tools/MaterialEditor/Code/CMakeLists.txt @@ -116,7 +116,6 @@ ly_add_target( # Add a 'builders' alias to allow the MaterialEditor root gem path to be added to the generated # cmake_dependencies..assetprocessor.setreg to allow the asset scan folder for it to be added ly_create_alias(NAME MaterialEditor.Builders NAMESPACE Gem) -ly_create_alias(NAME MaterialEditor.Tools NAMESPACE Gem) # Add build dependency to Editor for the MaterialEditor application since # Editor opens up the MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Linux/PAL_linux.cmake b/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Linux/PAL_linux.cmake index 70d49fdb2c..77d41d4561 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Linux/PAL_linux.cmake +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Linux/PAL_linux.cmake @@ -9,4 +9,4 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -set(PAL_TRAIT_ATOM_MATERIAL_EDITOR_APPLICATION_SUPPORTED FALSE) +set(PAL_TRAIT_ATOM_MATERIAL_EDITOR_APPLICATION_SUPPORTED TRUE) From 6675d06b677d89c099b2ab933a4c219cb806708c Mon Sep 17 00:00:00 2001 From: guthadam Date: Wed, 9 Jun 2021 12:32:55 -0500 Subject: [PATCH 20/73] Fixing linux build --- .../Window/PerformanceMonitor/PerformanceMonitorWidget.cpp | 2 +- .../Source/Window/PerformanceMonitor/PerformanceMonitorWidget.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PerformanceMonitor/PerformanceMonitorWidget.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PerformanceMonitor/PerformanceMonitorWidget.cpp index 72c8daa63c..70a4361409 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PerformanceMonitor/PerformanceMonitorWidget.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PerformanceMonitor/PerformanceMonitorWidget.cpp @@ -15,7 +15,7 @@ #include #include -#include +#include namespace MaterialEditor { diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PerformanceMonitor/PerformanceMonitorWidget.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PerformanceMonitor/PerformanceMonitorWidget.h index a75e856d83..dd31faef90 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PerformanceMonitor/PerformanceMonitorWidget.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PerformanceMonitor/PerformanceMonitorWidget.h @@ -13,7 +13,7 @@ #pragma once #include -#include +#include namespace Ui { From af42705bc9dd8433a1b04d439de3785f74651bbd Mon Sep 17 00:00:00 2001 From: guthadam Date: Wed, 9 Jun 2021 12:49:35 -0500 Subject: [PATCH 21/73] Fixing linux build --- .../Code/Source/Window/MaterialEditorBrowserInteractions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorBrowserInteractions.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorBrowserInteractions.cpp index 9b79bcb6d9..c4007616c5 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorBrowserInteractions.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorBrowserInteractions.cpp @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include From 6063e3a391651bb8744123ed567cd4e48d7ad5c1 Mon Sep 17 00:00:00 2001 From: AMZN-koppersr <82230785+AMZN-koppersr@users.noreply.github.com> Date: Wed, 9 Jun 2021 11:07:28 -0700 Subject: [PATCH 22/73] Simplified Json Serializer registration code Updated the Json Serializer registeration code in the RegistrationContext.cpp to use try_emplace instead of find + end check + insert. --- .../Serialization/Json/RegistrationContext.cpp | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/RegistrationContext.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/RegistrationContext.cpp index 50ea08e0a0..9aa80a2ef2 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/RegistrationContext.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/RegistrationContext.cpp @@ -47,19 +47,11 @@ namespace AZ if (!overwriteExisting) { - auto serializerIter = m_context->m_handledTypesMap.find(uuid); - if (serializerIter == m_context->m_handledTypesMap.end()) - { - m_context->m_handledTypesMap.emplace(uuid, serializer); - } - else - { - AZ_Assert( - false, - "Couldn't register Json serializer %s. Another serializer (%s) has already been registered for the same Uuid (%s).", - serializer->RTTI_GetTypeName(), serializerIter->second->RTTI_GetTypeName(), - serializerIter->first.ToString().c_str()); - } + auto emplaceResult = m_context->m_handledTypesMap.try_emplace(uuid, serializer); + AZ_Assert( + emplaceResult.second, + "Couldn't register Json serializer %s. Another serializer (%s) has already been registered for the same Uuid (%s).", + serializer->RTTI_GetTypeName(), emplaceResult.first->second->RTTI_GetTypeName(), uuid); } else { From 1339d453fc828879513acd3a2cac48d66df8aff9 Mon Sep 17 00:00:00 2001 From: guthadam Date: Wed, 9 Jun 2021 13:21:59 -0500 Subject: [PATCH 23/73] Adding PAL implementation for Linux --- .../Platform/Linux/MaterialEditor_Linux.cpp | 42 +++++++++++++++++++ .../Linux/MaterialEditor_Traits_Linux.h | 15 +++++++ .../Linux/MaterialEditor_Traits_Platform.h | 14 +++++++ .../Platform/Linux/platform_linux_files.cmake | 3 ++ 4 files changed, 74 insertions(+) create mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Linux/MaterialEditor_Linux.cpp create mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Linux/MaterialEditor_Traits_Linux.h create mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Linux/MaterialEditor_Traits_Platform.h diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Linux/MaterialEditor_Linux.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Linux/MaterialEditor_Linux.cpp new file mode 100644 index 0000000000..6a83c8c6de --- /dev/null +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Linux/MaterialEditor_Linux.cpp @@ -0,0 +1,42 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates, or +* a third party where indicated. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#include +#include +#include + +namespace Platform +{ + void LoadPluginDependencies() + { + AZ_Warning("Material Editor", false, "LoadPluginDependencies() function is not implemented"); + } + + void ProcessInput(void* message) + { + AZ_Warning("Material Editor", false, "ProcessInput() function is not implemented"); + } + + AzFramework::NativeWindowHandle GetWindowHandle(WId winId) + { + AZ_Warning("Material Editor", false, "GetWindowHandle() function is not implemented"); + AZ_UNUSED(winId); + return nullptr; + } + + AzFramework::WindowSize GetClientAreaSize(AzFramework::NativeWindowHandle window) + { + AZ_Warning("Material Editor", false, "GetClientAreaSize() function is not implemented"); + AZ_UNUSED(window); + return AzFramework::WindowSize{1,1}; + } +} diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Linux/MaterialEditor_Traits_Linux.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Linux/MaterialEditor_Traits_Linux.h new file mode 100644 index 0000000000..6f4eee610a --- /dev/null +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Linux/MaterialEditor_Traits_Linux.h @@ -0,0 +1,15 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#pragma once + +#define AZ_TRAIT_MATERIALEDITOR_EXT "" + diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Linux/MaterialEditor_Traits_Platform.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Linux/MaterialEditor_Traits_Platform.h new file mode 100644 index 0000000000..9cd502877d --- /dev/null +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Linux/MaterialEditor_Traits_Platform.h @@ -0,0 +1,14 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#pragma once + +#include diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Linux/platform_linux_files.cmake b/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Linux/platform_linux_files.cmake index 5714be5dfb..038a605109 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Linux/platform_linux_files.cmake +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Linux/platform_linux_files.cmake @@ -10,4 +10,7 @@ # set(FILES + MaterialEditor_Traits_Platform.h + MaterialEditor_Traits_Linux.h + MaterialEditor_Linux.cpp ) From e3fe4705f65d035b5e9a62ff5f9f4cdf8152740b Mon Sep 17 00:00:00 2001 From: AMZN-koppersr <82230785+AMZN-koppersr@users.noreply.github.com> Date: Wed, 9 Jun 2021 13:44:18 -0700 Subject: [PATCH 24/73] Post merge and Linux fixes. --- .../Json/UnsupportedTypesSerializerTests.cpp | 57 +++++++++---------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/Code/Framework/AzCore/Tests/Serialization/Json/UnsupportedTypesSerializerTests.cpp b/Code/Framework/AzCore/Tests/Serialization/Json/UnsupportedTypesSerializerTests.cpp index 8c9f5d0d3d..b7ad6bceae 100644 --- a/Code/Framework/AzCore/Tests/Serialization/Json/UnsupportedTypesSerializerTests.cpp +++ b/Code/Framework/AzCore/Tests/Serialization/Json/UnsupportedTypesSerializerTests.cpp @@ -46,17 +46,18 @@ namespace JsonSerializationTests void SetUp() override { BaseJsonSerializerFixture::SetUp(); - m_serializer = AZStd::make_unique(); + this->m_serializer = AZStd::make_unique(); } void TearDown() override { - m_serializer.reset(); + this->m_serializer.reset(); BaseJsonSerializerFixture::TearDown(); } protected: AZStd::unique_ptr m_serializer; + Type m_instance{}; }; using UnsupportedTypesTestTypes = ::testing::Types; @@ -64,80 +65,78 @@ namespace JsonSerializationTests TYPED_TEST(JsonUnsupportedTypesSerializerTests, Load_CallDirectly_ReportsIssueAndHalts) { - using namespace AZ::JsonSerializationResult; + namespace JSR = AZ::JsonSerializationResult; bool hasMessage = false; - auto callback = [&hasMessage](AZStd::string_view message, ResultCode result, AZStd::string_view) -> ResultCode + auto callback = [&hasMessage](AZStd::string_view message, JSR::ResultCode result, AZStd::string_view) -> JSR::ResultCode { hasMessage = !message.empty(); return result; }; - m_jsonDeserializationContext->PushReporter(AZStd::move(callback)); + this->m_jsonDeserializationContext->PushReporter(AZStd::move(callback)); - Type instance{}; - Result result = m_serializer->Load(&instance, azrtti_typeid(), *m_jsonDocument, *m_jsonDeserializationContext); - m_jsonDeserializationContext->PopReporter(); + JSR::Result result = this->m_serializer->Load( + &this->m_instance, azrtti_typeid(this->m_instance), *this->m_jsonDocument, *this->m_jsonDeserializationContext); + this->m_jsonDeserializationContext->PopReporter(); - EXPECT_EQ(Processing::Halted, result.GetResultCode().GetProcessing()); + EXPECT_EQ(JSR::Processing::Halted, result.GetResultCode().GetProcessing()); EXPECT_TRUE(hasMessage); } TYPED_TEST(JsonUnsupportedTypesSerializerTests, Load_CallThroughFrontEnd_ReportsIssueAndHalts) { - using namespace AZ::JsonSerializationResult; + namespace JSR = AZ::JsonSerializationResult; bool hasMessage = false; - auto callback = [&hasMessage](AZStd::string_view message, ResultCode result, AZStd::string_view) -> ResultCode + auto callback = [&hasMessage](AZStd::string_view message, JSR::ResultCode result, AZStd::string_view) -> JSR::ResultCode { hasMessage = !message.empty(); return result; }; - m_deserializationSettings->m_reporting = AZStd::move(callback); + this->m_deserializationSettings->m_reporting = AZStd::move(callback); - Type instance{}; - ResultCode result = AZ::JsonSerialization::Load(instance, *m_jsonDocument, *m_deserializationSettings); + JSR::ResultCode result = AZ::JsonSerialization::Load(this->m_instance, *this->m_jsonDocument, *this->m_deserializationSettings); - EXPECT_EQ(Processing::Halted, result.GetProcessing()); + EXPECT_EQ(JSR::Processing::Halted, result.GetProcessing()); EXPECT_TRUE(hasMessage); } TYPED_TEST(JsonUnsupportedTypesSerializerTests, Save_CallDirectly_ReportsIssueAndHalts) { - using namespace AZ::JsonSerializationResult; + namespace JSR = AZ::JsonSerializationResult; bool hasMessage = false; - auto callback = [&hasMessage](AZStd::string_view message, ResultCode result, AZStd::string_view) -> ResultCode + auto callback = [&hasMessage](AZStd::string_view message, JSR::ResultCode result, AZStd::string_view) -> JSR::ResultCode { hasMessage = !message.empty(); return result; }; - m_jsonSerializationContext->PushReporter(AZStd::move(callback)); + this->m_jsonSerializationContext->PushReporter(AZStd::move(callback)); - Type instance{}; - Result result = m_serializer->Store(*m_jsonDocument, &instance, nullptr, azrtti_typeid(), *m_jsonSerializationContext); - m_jsonSerializationContext->PopReporter(); + JSR::Result result = this->m_serializer->Store( + *this->m_jsonDocument, &this->m_instance, nullptr, azrtti_typeid(this->m_instance), *this->m_jsonSerializationContext); + this->m_jsonSerializationContext->PopReporter(); - EXPECT_EQ(Processing::Halted, result.GetResultCode().GetProcessing()); + EXPECT_EQ(JSR::Processing::Halted, result.GetResultCode().GetProcessing()); EXPECT_TRUE(hasMessage); } TYPED_TEST(JsonUnsupportedTypesSerializerTests, Save_CallThroughFrontEnd_ReportsIssueAndHalts) { - using namespace AZ::JsonSerializationResult; + namespace JSR = AZ::JsonSerializationResult; bool hasMessage = false; - auto callback = [&hasMessage](AZStd::string_view message, ResultCode result, AZStd::string_view) -> ResultCode + auto callback = [&hasMessage](AZStd::string_view message, JSR::ResultCode result, AZStd::string_view) -> JSR::ResultCode { hasMessage = !message.empty(); return result; }; - m_serializationSettings->m_reporting = AZStd::move(callback); + this->m_serializationSettings->m_reporting = AZStd::move(callback); - Type instance{}; - ResultCode result = - AZ::JsonSerialization::Store(*m_jsonDocument, m_jsonDocument->GetAllocator(), instance, *m_serializationSettings); + JSR::ResultCode result = AZ::JsonSerialization::Store( + *this->m_jsonDocument, this->m_jsonDocument->GetAllocator(), this->m_instance, *this->m_serializationSettings); - EXPECT_EQ(Processing::Halted, result.GetProcessing()); + EXPECT_EQ(JSR::Processing::Halted, result.GetProcessing()); EXPECT_TRUE(hasMessage); } } // namespace JsonSerializationTests From 2eefc08d2e7aab40105b4d863613728d2795ac21 Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 9 Jun 2021 15:21:30 -0700 Subject: [PATCH 25/73] [cpack/stabilization/2106] fixed startup crash in project manager from installer build --- Code/Tools/ProjectManager/Source/PythonBindings.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 3f0af7fa49..824cab4758 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -246,7 +246,7 @@ namespace O3DE::ProjectManager AZStd::string pyBasePath = Platform::GetPythonHomePath(PY_PACKAGE, m_enginePath.c_str()); if (!AZ::IO::SystemFile::Exists(pyBasePath.c_str())) { - AZ_Warning("python", false, "Python home path must exist. path:%s", pyBasePath.c_str()); + AZ_Assert(false, "Python home path must exist. path:%s", pyBasePath.c_str()); return false; } @@ -277,11 +277,9 @@ namespace O3DE::ProjectManager AZStd::lock_guard lock(m_lock); pybind11::gil_scoped_acquire acquire; - // Setup sys.path + // sanity import check int result = PyRun_SimpleString("import sys"); - AZ_Warning("ProjectManagerWindow", result != -1, "Import sys failed"); - result = PyRun_SimpleString(AZStd::string::format("sys.path.append('%s')", m_enginePath.c_str()).c_str()); - AZ_Warning("ProjectManagerWindow", result != -1, "Append to sys path failed"); + AZ_Error("ProjectManagerWindow", result != -1, "Import sys failed"); // import required modules m_cmake = pybind11::module::import("o3de.cmake"); @@ -299,7 +297,7 @@ namespace O3DE::ProjectManager } catch ([[maybe_unused]] const std::exception& e) { - AZ_Warning("ProjectManagerWindow", false, "Py_Initialize() failed with %s", e.what()); + AZ_Assert(false, "Py_Initialize() failed with %s", e.what()); return false; } } From ca475fab80dff4e94fdcfd4334447dc9b2813347 Mon Sep 17 00:00:00 2001 From: moudgils Date: Wed, 9 Jun 2021 15:28:22 -0700 Subject: [PATCH 26/73] Fix Editor crash where the scissor regions is bigger than the metal drawable --- .../RHI/Metal/Code/Source/Platform/Mac/RHI/Metal_RHI_Mac.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Atom/RHI/Metal/Code/Source/Platform/Mac/RHI/Metal_RHI_Mac.cpp b/Gems/Atom/RHI/Metal/Code/Source/Platform/Mac/RHI/Metal_RHI_Mac.cpp index cc8c4c80c0..b81c51a57b 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/Platform/Mac/RHI/Metal_RHI_Mac.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/Platform/Mac/RHI/Metal_RHI_Mac.cpp @@ -94,7 +94,7 @@ namespace Platform void ResizeInternal(RHIMetalView* metalView, CGSize viewSize) { - [metalView resizeSubviewsWithOldSize:viewSize]; + [metalView.metalLayer setDrawableSize: viewSize]; } RHIMetalView* GetMetalView(NativeWindowType* nativeWindow) From 6c056ad56633999cd33cf6129803ec081f4b1780 Mon Sep 17 00:00:00 2001 From: amzn-sj Date: Wed, 9 Jun 2021 15:29:39 -0700 Subject: [PATCH 27/73] Remove duplicate definition of function --- scripts/o3de/o3de/manifest.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py index 074e7f5a9e..8255946cfb 100644 --- a/scripts/o3de/o3de/manifest.py +++ b/scripts/o3de/o3de/manifest.py @@ -401,13 +401,6 @@ def get_templates_for_generic_creation(): # temporary until we have a better wa return list(filter(filter_project_and_gem_templates_out, get_all_templates())) -def get_all_restricted() -> list: - engine_restricted = get_engine_restricted() - restricted_data = get_restricted() - restricted_data.extend(engine_restricted) - return restricted_data - - def find_engine_data(json_data: dict, engine_path: str or pathlib.Path = None) -> dict or None: if not engine_path: From 39d207095ab5fa32b24e194253417400c39007bf Mon Sep 17 00:00:00 2001 From: amzn-sj Date: Wed, 9 Jun 2021 15:31:33 -0700 Subject: [PATCH 28/73] Remove call to ly_get_absolute_pal_filename that's not needed --- cmake/Platform/Common/Install_common.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index a579e3128d..933d64149b 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -374,7 +374,7 @@ function(ly_setup_cmake_install) string(APPEND builtinpackages "ly_associate_package(PACKAGE_NAME ${package_name} TARGETS ${targets} PACKAGE_HASH ${package_hash})\n") endforeach() - ly_get_absolute_pal_filename(pal_builtin_file ${CMAKE_CURRENT_BINARY_DIR}/cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}/BuiltInPackages_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) + set(pal_builtin_file ${CMAKE_CURRENT_BINARY_DIR}/cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}/BuiltInPackages_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) file(GENERATE OUTPUT ${pal_builtin_file} CONTENT ${builtinpackages} ) From 5061241992f69f1d2b0677de84941f13b6f80e44 Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 9 Jun 2021 17:03:13 -0700 Subject: [PATCH 29/73] [cpack/stabilization/2106] early out if sys import fails in PythonBindings::StartPython --- Code/Tools/ProjectManager/Source/PythonBindings.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 824cab4758..bb6c05a472 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -278,8 +278,11 @@ namespace O3DE::ProjectManager pybind11::gil_scoped_acquire acquire; // sanity import check - int result = PyRun_SimpleString("import sys"); - AZ_Error("ProjectManagerWindow", result != -1, "Import sys failed"); + if (PyRun_SimpleString("import sys") != 0) + { + AZ_Assert(false, "Import sys failed"); + return false; + } // import required modules m_cmake = pybind11::module::import("o3de.cmake"); @@ -293,7 +296,7 @@ namespace O3DE::ProjectManager // make sure the engine is registered RegisterThisEngine(); - return result == 0 && !PyErr_Occurred(); + return !PyErr_Occurred(); } catch ([[maybe_unused]] const std::exception& e) { From 2dee4d3ac92fef4268ae313ad06b283a68e548d2 Mon Sep 17 00:00:00 2001 From: sconel Date: Wed, 9 Jun 2021 17:37:41 -0700 Subject: [PATCH 30/73] Add support to export nested container entities. Resolves missing parents in spawnables --- .../AzToolsFramework/Prefab/Instance/Instance.cpp | 5 +++-- .../AzToolsFramework/Prefab/Instance/Instance.h | 9 ++++++++- .../AzToolsFramework/Prefab/Spawnable/SpawnableUtils.cpp | 6 +----- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp index 766a293b4a..83a76aeb01 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp @@ -187,13 +187,14 @@ namespace AzToolsFramework return removedEntity; } - void Instance::DetachNestedEntities(const AZStd::function)>& callback) + void Instance::DetachAllEntitiesInHierarchy(const AZStd::function)>& callback) { + callback(AZStd::move(DetachContainerEntity())); DetachEntities(callback); for (const auto& [instanceAlias, instance] : m_nestedInstances) { - instance->DetachNestedEntities(callback); + instance->DetachAllEntitiesInHierarchy(callback); } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h index d14203e2e5..bba20cbe8a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h @@ -87,7 +87,14 @@ namespace AzToolsFramework bool AddEntity(AZ::Entity& entity, EntityAlias entityAlias); AZStd::unique_ptr DetachEntity(const AZ::EntityId& entityId); void DetachEntities(const AZStd::function)>& callback); - void DetachNestedEntities(const AZStd::function)>& callback); + + /** + * Detaches all entities in the instance hierarchy, including; all direct and nested entities, all container entities. + * Note that without container entities the hierarchy that remains cannot be used further without restoring new ones + * @param callback A user provided callback that can be used to capture ownership and manipulate the detached entities. + */ + void DetachAllEntitiesInHierarchy(const AZStd::function)>& callback); + void RemoveNestedEntities(const AZStd::function&)>& filter); void Reset(); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/SpawnableUtils.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/SpawnableUtils.cpp index 3c91f99b05..241d2a3bd5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/SpawnableUtils.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/SpawnableUtils.cpp @@ -38,11 +38,7 @@ namespace AzToolsFramework::Prefab::SpawnableUtils // going to be used to create clones of the entities. { AzFramework::Spawnable::EntityList& entities = spawnable.GetEntities(); - if (instance.HasContainerEntity()) - { - entities.emplace_back(AZStd::move(instance.DetachContainerEntity())); - } - instance.DetachNestedEntities( + instance.DetachAllEntitiesInHierarchy( [&entities](AZStd::unique_ptr entity) { entities.emplace_back(AZStd::move(entity)); From c46c82079c293477d68233508fda52f711ea3868 Mon Sep 17 00:00:00 2001 From: AMZN-koppersr <82230785+AMZN-koppersr@users.noreply.github.com> Date: Wed, 9 Jun 2021 18:35:04 -0700 Subject: [PATCH 31/73] Fixed string format bug in JsonRegistrationContext --- .../AzCore/AzCore/Serialization/Json/RegistrationContext.cpp | 3 ++- .../Tests/Serialization/Json/JsonRegistrationContextTests.cpp | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/RegistrationContext.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/RegistrationContext.cpp index 9aa80a2ef2..82db4df000 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/RegistrationContext.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/RegistrationContext.cpp @@ -51,7 +51,8 @@ namespace AZ AZ_Assert( emplaceResult.second, "Couldn't register Json serializer %s. Another serializer (%s) has already been registered for the same Uuid (%s).", - serializer->RTTI_GetTypeName(), emplaceResult.first->second->RTTI_GetTypeName(), uuid); + serializer->RTTI_GetTypeName(), emplaceResult.first->second->RTTI_GetTypeName(), + uuid.ToString().c_str()); } else { diff --git a/Code/Framework/AzCore/Tests/Serialization/Json/JsonRegistrationContextTests.cpp b/Code/Framework/AzCore/Tests/Serialization/Json/JsonRegistrationContextTests.cpp index 6012a824c7..7367fd47ff 100644 --- a/Code/Framework/AzCore/Tests/Serialization/Json/JsonRegistrationContextTests.cpp +++ b/Code/Framework/AzCore/Tests/Serialization/Json/JsonRegistrationContextTests.cpp @@ -285,7 +285,7 @@ namespace JsonSerializationTests EXPECT_EQ(1, m_jsonRegistrationContext->GetRegisteredSerializers().size()); AZ::BaseJsonSerializer* mockSerializer = m_jsonRegistrationContext->GetSerializerForType(azrtti_typeid()); - EXPECT_NE(mockSerializer, nullptr); + ASSERT_NE(mockSerializer, nullptr); EXPECT_EQ(AZ::AzTypeInfo::Uuid(), mockSerializer->RTTI_GetType()); SerializerWithOneType::Unreflect(m_jsonRegistrationContext.get()); @@ -301,7 +301,7 @@ namespace JsonSerializationTests EXPECT_EQ(1, m_jsonRegistrationContext->GetRegisteredSerializers().size()); AZ::BaseJsonSerializer* mockSerializer = m_jsonRegistrationContext->GetSerializerForType(azrtti_typeid()); - EXPECT_NE(mockSerializer, nullptr); + ASSERT_NE(mockSerializer, nullptr); EXPECT_EQ(AZ::AzTypeInfo::Uuid(), mockSerializer->RTTI_GetType()); SerializerWithOneType::Unreflect(m_jsonRegistrationContext.get()); From a55edd518ace92f3ef6de5e660271b5d7be49376 Mon Sep 17 00:00:00 2001 From: moudgils Date: Wed, 9 Jun 2021 18:35:52 -0700 Subject: [PATCH 32/73] Update some comments --- Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp | 3 ++- Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h | 2 ++ Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp index 5d6c275184..6bdb5a4aa8 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp @@ -386,8 +386,9 @@ namespace AZ void ArgumentBuffer::AddUntrackedResourcesToEncoder(id commandEncoder, const ShaderResourceGroupVisibility& srgResourcesVisInfo) const { - + //Map tp cache all the resoources based on the usage as we can batch all the resources for a given usage ComputeResourcesToMakeResidentMap resourcesToMakeResidentCompute; + //Map tp cache all the resoources based on the usage and shader stage as we can batch all the resources for a given usage/shader usage GraphicsResourcesToMakeResidentMap resourcesToMakeResidentGraphics; //Cache the constant buffer associated with a srg diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h index 06380162b6..eab9389e9b 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h @@ -125,7 +125,9 @@ namespace AZ AZStd::array, MaxEntriesInArgTable> m_resourceArray; int m_resourceArrayLen = 0; }; + //Map tp cache all the resoources based on the usage as we can batch all the resources for a given usage using ComputeResourcesToMakeResidentMap = AZStd::unordered_map; + //Map tp cache all the resoources based on the usage and shader stage as we can batch all the resources for a given usage/shader usage using GraphicsResourcesToMakeResidentMap = AZStd::unordered_map, MetalResourceArray>; void CollectResourcesForCompute(id encoder, const ResourceBindingsSet& resourceBindingData, ComputeResourcesToMakeResidentMap& resourcesToMakeResidentMap) const; diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp index 7df8f1e547..5546be1bd9 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp @@ -255,6 +255,7 @@ namespace AZ uint32_t bufferVertexRegisterIdMax = 0; uint32_t bufferFragmentOrComputeRegisterIdMax = 0; + //Arrays to cache all the buffers and offsets in order to make batch calls MetalArgumentBufferArray mtlVertexArgBuffers; MetalArgumentBufferArrayOffsets mtlVertexArgBufferOffsets; MetalArgumentBufferArray mtlFragmentOrComputeArgBuffers; @@ -298,7 +299,6 @@ namespace AZ mtlVertexArgBufferOffsets[slotIndex] = argBufferOffset; bufferVertexRegisterIdMin = AZStd::min(slotIndex, bufferVertexRegisterIdMin); bufferVertexRegisterIdMax = AZStd::max(slotIndex, bufferVertexRegisterIdMax); - } if( numBitsSet > 1 || srgVisInfo == RHI::ShaderStageMask::Fragment) @@ -595,7 +595,7 @@ namespace AZ AZ_Assert(count <= METAL_MAX_ENTRIES_BUFFER_ARG_TABLE , "Slots needed cannot exceed METAL_MAX_ENTRIES_BUFFER_ARG_TABLE"); NSRange range = {METAL_MAX_ENTRIES_BUFFER_ARG_TABLE - count, count}; - //For metal the stream buffers are populated from bottom to top as the top slots are taken by argument buffers + //The stream buffers are populated from bottom to top as the top slots are taken by argument buffers for (int i = count-1; i >= 0; --i) { if (streams[i].GetBuffer()) From 8e3a68a34f02903942622ee4863d62433c7bf325 Mon Sep 17 00:00:00 2001 From: moudgils Date: Wed, 9 Jun 2021 18:37:27 -0700 Subject: [PATCH 33/73] Fix comment spelling --- Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp | 4 ++-- Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp index 6bdb5a4aa8..068bc5f162 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp @@ -386,9 +386,9 @@ namespace AZ void ArgumentBuffer::AddUntrackedResourcesToEncoder(id commandEncoder, const ShaderResourceGroupVisibility& srgResourcesVisInfo) const { - //Map tp cache all the resoources based on the usage as we can batch all the resources for a given usage + //Map to cache all the resources based on the usage as we can batch all the resources for a given usage ComputeResourcesToMakeResidentMap resourcesToMakeResidentCompute; - //Map tp cache all the resoources based on the usage and shader stage as we can batch all the resources for a given usage/shader usage + //Map to cache all the resources based on the usage and shader stage as we can batch all the resources for a given usage/shader usage GraphicsResourcesToMakeResidentMap resourcesToMakeResidentGraphics; //Cache the constant buffer associated with a srg diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h index eab9389e9b..7cc77ae478 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h @@ -125,9 +125,9 @@ namespace AZ AZStd::array, MaxEntriesInArgTable> m_resourceArray; int m_resourceArrayLen = 0; }; - //Map tp cache all the resoources based on the usage as we can batch all the resources for a given usage + //Map to cache all the resources based on the usage as we can batch all the resources for a given usage using ComputeResourcesToMakeResidentMap = AZStd::unordered_map; - //Map tp cache all the resoources based on the usage and shader stage as we can batch all the resources for a given usage/shader usage + //Map to cache all the resources based on the usage and shader stage as we can batch all the resources for a given usage/shader usage using GraphicsResourcesToMakeResidentMap = AZStd::unordered_map, MetalResourceArray>; void CollectResourcesForCompute(id encoder, const ResourceBindingsSet& resourceBindingData, ComputeResourcesToMakeResidentMap& resourcesToMakeResidentMap) const; From ac8ee00affc48fe78210a1af1dbbba08f276dc0a Mon Sep 17 00:00:00 2001 From: Vincent Liu <5900509+onecent1101@users.noreply.github.com> Date: Wed, 9 Jun 2021 19:29:34 -0700 Subject: [PATCH 34/73] [LYN-4288] Adding error page if resource mapping tool has invalid setup (#1219) --- .../controller/error_controller.py | 33 +++++++ .../manager/configuration_manager.py | 11 ++- .../manager/controller_manager.py | 26 ++++-- .../manager/thread_manager.py | 11 ++- .../manager/view_manager.py | 30 +++++-- .../model/error_messages.py | 6 ++ .../model/notification_label_text.py | 2 + .../model/view_size_constants.py | 12 +++ .../resource_mapping_tool.py | 20 ++--- .../style/base_style_sheet.qss | 15 ++++ .../manager/test_configuration_manager.py | 15 +++- .../unit/manager/test_controller_manager.py | 11 ++- .../tests/unit/manager/test_thread_manager.py | 8 +- .../tests/unit/manager/test_view_manager.py | 35 +++++++- .../view/common_view_components.py | 4 +- .../ResourceMappingTool/view/error_page.py | 89 +++++++++++++++++++ 16 files changed, 281 insertions(+), 47 deletions(-) create mode 100644 Gems/AWSCore/Code/Tools/ResourceMappingTool/controller/error_controller.py create mode 100644 Gems/AWSCore/Code/Tools/ResourceMappingTool/view/error_page.py diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/controller/error_controller.py b/Gems/AWSCore/Code/Tools/ResourceMappingTool/controller/error_controller.py new file mode 100644 index 0000000000..244245ad57 --- /dev/null +++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/controller/error_controller.py @@ -0,0 +1,33 @@ +""" +All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +its licensors. + +For complete copyright and license terms please see the LICENSE at the root of this +distribution (the "License"). All use of this software is governed by the License, +or, if provided, by the license below or the license accompanying this file. Do not +remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +""" + +from PySide2.QtCore import (QCoreApplication, QObject) + +from manager.view_manager import ViewManager +from view.error_page import ErrorPage + + +class ErrorController(QObject): + """ + ErrorPage Controller + """ + def __init__(self) -> None: + super(ErrorController, self).__init__() + # Initialize manager references + self._view_manager: ViewManager = ViewManager.get_instance() + # Initialize view references + self._error_page: ErrorPage = self._view_manager.get_error_page() + + def _ok(self) -> None: + QCoreApplication.instance().quit() + + def setup(self) -> None: + self._error_page.ok_button.clicked.connect(self._ok) diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/manager/configuration_manager.py b/Gems/AWSCore/Code/Tools/ResourceMappingTool/manager/configuration_manager.py index fc188582c7..7c5ceb6946 100755 --- a/Gems/AWSCore/Code/Tools/ResourceMappingTool/manager/configuration_manager.py +++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/manager/configuration_manager.py @@ -48,11 +48,15 @@ class ConfigurationManager(object): def configuration(self, new_configuration: ConfigurationManager) -> None: self._configuration = new_configuration - def setup(self, config_path: str) -> bool: + def setup(self, profile_name: str, config_path: str) -> bool: result: bool = True - logger.info("Setting up default configuration ...") + logger.debug("Setting up default configuration ...") try: - normalized_config_path: str = file_utils.normalize_file_path(config_path); + logger.debug("Setting up boto3 default session ...") + aws_utils.setup_default_session(profile_name) + + logger.debug("Setting up config directory and files ...") + normalized_config_path: str = file_utils.normalize_file_path(config_path) if normalized_config_path: self._configuration.config_directory = normalized_config_path else: @@ -61,6 +65,7 @@ class ConfigurationManager(object): file_utils.find_files_with_suffix_under_directory(self._configuration.config_directory, constants.RESOURCE_MAPPING_CONFIG_FILE_NAME_SUFFIX) + logger.debug("Setting up aws account id and region ...") self._configuration.account_id = aws_utils.get_default_account_id() self._configuration.region = aws_utils.get_default_region() except (RuntimeError, FileNotFoundError) as e: diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/manager/controller_manager.py b/Gems/AWSCore/Code/Tools/ResourceMappingTool/manager/controller_manager.py index 48c45d0350..61eaaddea2 100755 --- a/Gems/AWSCore/Code/Tools/ResourceMappingTool/manager/controller_manager.py +++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/manager/controller_manager.py @@ -12,6 +12,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. from __future__ import annotations import logging +from controller.error_controller import ErrorController from controller.import_resources_controller import ImportResourcesController from controller.view_edit_controller import ViewEditController from model import error_messages @@ -33,8 +34,9 @@ class ControllerManager(object): def __init__(self) -> None: if ControllerManager.__instance is None: - self._view_edit_controller: ViewEditController = ViewEditController() - self._import_resources_controller: ImportResourcesController = ImportResourcesController() + self._error_controller: ErrorController = None + self._view_edit_controller: ViewEditController = None + self._import_resources_controller: ImportResourcesController = None ControllerManager.__instance = self else: raise AssertionError(error_messages.SINGLETON_OBJECT_ERROR_MESSAGE.format("ControllerManager")) @@ -47,9 +49,17 @@ class ControllerManager(object): def view_edit_controller(self) -> ViewEditController: return self._view_edit_controller - def setup(self) -> None: - logger.info("Setting up ViewEdit and ImportResource controllers ...") - self._view_edit_controller.setup() - self._import_resources_controller.setup() - self._import_resources_controller.add_import_resources_sender.connect( - self._view_edit_controller.add_import_resources_receiver) + def setup(self, setup_error: bool) -> None: + if setup_error: + logger.debug("Setting up Error controllers ...") + self._error_controller = ErrorController() + self._error_controller.setup() + else: + logger.debug("Setting up ViewEdit and ImportResource controllers ...") + self._view_edit_controller = ViewEditController() + self._import_resources_controller = ImportResourcesController() + + self._view_edit_controller.setup() + self._import_resources_controller.setup() + self._import_resources_controller.add_import_resources_sender.connect( + self._view_edit_controller.add_import_resources_receiver) diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/manager/thread_manager.py b/Gems/AWSCore/Code/Tools/ResourceMappingTool/manager/thread_manager.py index 516a085439..4de928bb1b 100755 --- a/Gems/AWSCore/Code/Tools/ResourceMappingTool/manager/thread_manager.py +++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/manager/thread_manager.py @@ -37,10 +37,13 @@ class ThreadManager(object): else: raise AssertionError(error_messages.SINGLETON_OBJECT_ERROR_MESSAGE.format("ThreadManager")) - def setup(self, thread_count: int = 1) -> None: - # Based on prototype use case, we just need 1 thread - logger.info(f"Setting up thread pool with MaxThreadCount={thread_count} ...") - self._thread_pool.setMaxThreadCount(thread_count) + def setup(self, setup_error: bool, thread_count: int = 1) -> None: + if setup_error: + logger.debug("Skip thread pool creation, as there is major setup error.") + else: + # Based on prototype use case, we just need 1 thread + logger.debug(f"Setting up thread pool with MaxThreadCount={thread_count} ...") + self._thread_pool.setMaxThreadCount(thread_count) """Reserves a thread and uses it to run runnable worker, unless this thread will make the current thread count exceed max thread count. In that case, runnable is added to a run queue instead.""" diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/manager/view_manager.py b/Gems/AWSCore/Code/Tools/ResourceMappingTool/manager/view_manager.py index fff5c4b59a..46158afb39 100755 --- a/Gems/AWSCore/Code/Tools/ResourceMappingTool/manager/view_manager.py +++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/manager/view_manager.py @@ -16,6 +16,7 @@ from PySide2.QtGui import QIcon from PySide2.QtWidgets import (QMainWindow, QStackedWidget, QWidget) from model import (error_messages, view_size_constants) +from view.error_page import ErrorPage from view.import_resources_page import ImportResourcesPage from view.view_edit_page import ViewEditPage @@ -27,6 +28,10 @@ class ViewManagerConstants(object): IMPORT_RESOURCES_PAGE_INDEX: int = 1 +# Error page will be a single page +ERROR_PAGE_INDEX: int = 0 + + class ViewManager(object): """ View manager maintains the main stacked pages for this tool, which @@ -58,21 +63,32 @@ class ViewManager(object): ViewManager.__instance = self else: raise AssertionError(error_messages.SINGLETON_OBJECT_ERROR_MESSAGE.format("ViewManager")) - + + def get_error_page(self) -> QWidget: + return self._resource_mapping_stacked_pages.widget(ERROR_PAGE_INDEX) + def get_view_edit_page(self) -> QWidget: return self._resource_mapping_stacked_pages.widget(ViewManagerConstants.VIEW_AND_EDIT_PAGE_INDEX) def get_import_resources_page(self) -> QWidget: return self._resource_mapping_stacked_pages.widget(ViewManagerConstants.IMPORT_RESOURCES_PAGE_INDEX) - def setup(self) -> None: - logger.debug("Setting up ViewEdit and ImportResources view pages ...") - self._resource_mapping_stacked_pages.addWidget(ViewEditPage()) - self._resource_mapping_stacked_pages.addWidget(ImportResourcesPage()) + def setup(self, setup_error: bool) -> None: + if setup_error: + logger.debug("Setting up Error view pages ...") + self._resource_mapping_stacked_pages.addWidget(ErrorPage()) + self._main_window.adjustSize() # fit error page size + else: + logger.debug("Setting up ViewEdit and ImportResources view pages ...") + self._resource_mapping_stacked_pages.addWidget(ViewEditPage()) + self._resource_mapping_stacked_pages.addWidget(ImportResourcesPage()) - def show(self) -> None: + def show(self, setup_error: bool) -> None: """Show up the tool view by setting default page index and showing main widget""" - self._resource_mapping_stacked_pages.setCurrentIndex(ViewManagerConstants.VIEW_AND_EDIT_PAGE_INDEX) + if setup_error: + self._resource_mapping_stacked_pages.setCurrentIndex(ERROR_PAGE_INDEX) + else: + self._resource_mapping_stacked_pages.setCurrentIndex(ViewManagerConstants.VIEW_AND_EDIT_PAGE_INDEX) self._main_window.show() def switch_to_view_edit_page(self) -> None: diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/model/error_messages.py b/Gems/AWSCore/Code/Tools/ResourceMappingTool/model/error_messages.py index 08ab2a146d..7aef2068a2 100755 --- a/Gems/AWSCore/Code/Tools/ResourceMappingTool/model/error_messages.py +++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/model/error_messages.py @@ -9,6 +9,12 @@ remove or modify any license notices. This file is distributed on an "AS IS" BAS WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. """ +ERROR_PAGE_TOOL_SETUP_ERROR_MESSAGE: str = \ + "AWS credentials are missing or invalid. See " \ + ""\ + "documentation for details." \ + "
Check log file under Gems/AWSCore/Code/Tool/ResourceMappingTool for further information." + VIEW_EDIT_PAGE_SAVING_FAILED_WITH_INVALID_ROW_ERROR_MESSAGE: str = \ "Row {} have errors. Please correct errors or delete the row to proceed." VIEW_EDIT_PAGE_READ_FROM_JSON_FAILED_WITH_UNEXPECTED_FILE_ERROR_MESSAGE: str = \ diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/model/notification_label_text.py b/Gems/AWSCore/Code/Tools/ResourceMappingTool/model/notification_label_text.py index 1819e4c4ce..aecff69fb1 100755 --- a/Gems/AWSCore/Code/Tools/ResourceMappingTool/model/notification_label_text.py +++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/model/notification_label_text.py @@ -11,6 +11,8 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. NOTIFICATION_LOADING_MESSAGE: str = "Loading..." +ERROR_PAGE_OK_TEXT: str = "OK" + VIEW_EDIT_PAGE_CONFIG_FILE_TEXT: str = "Config File" VIEW_EDIT_PAGE_CONFIG_LOCATION_TEXT: str = "Config Location:" VIEW_EDIT_PAGE_ADD_ROW_TEXT: str = "Add Row" diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/model/view_size_constants.py b/Gems/AWSCore/Code/Tools/ResourceMappingTool/model/view_size_constants.py index c01d81b75c..7c0eb55885 100755 --- a/Gems/AWSCore/Code/Tools/ResourceMappingTool/model/view_size_constants.py +++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/model/view_size_constants.py @@ -17,6 +17,18 @@ MAIN_PAGE_LAYOUT_MARGIN_TOPBOTTOM: int = 15 INTERACTION_COMPONENT_HEIGHT: int = 25 +"""error page related constants""" +ERROR_PAGE_LAYOUT_MARGIN_LEFTRIGHT: int = 10 +ERROR_PAGE_LAYOUT_MARGIN_TOPBOTTOM: int = 10 + +ERROR_PAGE_MAIN_WINDOW_WIDTH: int = 600 +ERROR_PAGE_MAIN_WINDOW_HEIGHT: int = 145 + +ERROR_PAGE_NOTIFICATION_AREA_HEIGHT: int = 100 +ERROR_PAGE_FOOTER_AREA_HEIGHT: int = 45 + +OK_BUTTON_WIDTH: int = 90 + """view edit page related constants""" VIEW_EDIT_PAGE_HEADER_AREA_HEIGHT: int = 65 VIEW_EDIT_PAGE_CENTER_AREA_HEIGHT: int = 500 diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/resource_mapping_tool.py b/Gems/AWSCore/Code/Tools/ResourceMappingTool/resource_mapping_tool.py index 6a56491b24..177dae349e 100755 --- a/Gems/AWSCore/Code/Tools/ResourceMappingTool/resource_mapping_tool.py +++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/resource_mapping_tool.py @@ -73,32 +73,22 @@ if __name__ == "__main__": except FileNotFoundError: logger.warning("Failed to load style sheet for resource mapping tool") - logger.info("Initializing boto3 default session ...") - try: - aws_utils.setup_default_session(arguments.profile) - except RuntimeError as error: - logger.error(error) - environment_utils.cleanup_qt_environment() - exit(-1) - logger.info("Initializing configuration manager ...") configuration_manager: ConfigurationManager = ConfigurationManager() - if not configuration_manager.setup(arguments.config_path): - environment_utils.cleanup_qt_environment() - exit(-1) + configuration_error: bool = not configuration_manager.setup(arguments.profile, arguments.config_path) logger.info("Initializing thread manager ...") thread_manager: ThreadManager = ThreadManager() - thread_manager.setup() + thread_manager.setup(configuration_error) logger.info("Initializing view manager ...") view_manager: ViewManager = ViewManager() - view_manager.setup() + view_manager.setup(configuration_error) logger.info("Initializing controller manager ...") controller_manager: ControllerManager = ControllerManager() - controller_manager.setup() + controller_manager.setup(configuration_error) - view_manager.show() + view_manager.show(configuration_error) sys.exit(app.exec_()) diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/style/base_style_sheet.qss b/Gems/AWSCore/Code/Tools/ResourceMappingTool/style/base_style_sheet.qss index c23c3d90bd..2638052e2c 100644 --- a/Gems/AWSCore/Code/Tools/ResourceMappingTool/style/base_style_sheet.qss +++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/style/base_style_sheet.qss @@ -368,3 +368,18 @@ QFrame#NotificationFrame margin: 4px; padding: 4px; } + +QFrame#ErrorPage +{ + background-color: #2d2d2d; + border: 1px solid #4A90E2; + border-radius: 2px; + margin: 0px; + padding: 15px; +} + +QFrame#ErrorPage QLabel#NotificationIcon +{ + padding-left: 15px; + padding-right: 15px; +} diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/manager/test_configuration_manager.py b/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/manager/test_configuration_manager.py index 552f9fff01..7c6ee496a0 100755 --- a/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/manager/test_configuration_manager.py +++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/manager/test_configuration_manager.py @@ -33,6 +33,7 @@ class TestConfigurationManager(TestCase): def test_get_instance_raise_exception(self) -> None: self.assertRaises(Exception, ConfigurationManager) + @patch("utils.aws_utils.setup_default_session") @patch("utils.aws_utils.get_default_region", return_value=_expected_region) @patch("utils.aws_utils.get_default_account_id", return_value=_expected_account_id) @patch("utils.file_utils.find_files_with_suffix_under_directory", return_value=_expected_config_files) @@ -42,8 +43,10 @@ class TestConfigurationManager(TestCase): mock_check_path_exists: MagicMock, mock_find_files_with_suffix_under_directory: MagicMock, mock_get_default_account_id: MagicMock, - mock_get_default_region: MagicMock) -> None: - TestConfigurationManager._expected_configuration_manager.setup("") + mock_get_default_region: MagicMock, + mock_setup_default_session: MagicMock) -> None: + TestConfigurationManager._expected_configuration_manager.setup("", "") + mock_setup_default_session.assert_called_once() mock_get_current_directory_path.assert_called_once() mock_check_path_exists.assert_called_once_with(TestConfigurationManager._expected_directory_path) mock_find_files_with_suffix_under_directory.assert_called_once_with( @@ -59,6 +62,7 @@ class TestConfigurationManager(TestCase): assert TestConfigurationManager._expected_configuration_manager.configuration.region == \ TestConfigurationManager._expected_region + @patch("utils.aws_utils.setup_default_session") @patch("utils.aws_utils.get_default_region", return_value=_expected_region) @patch("utils.aws_utils.get_default_account_id", return_value=_expected_account_id) @patch("utils.file_utils.find_files_with_suffix_under_directory", return_value=_expected_config_files) @@ -68,8 +72,11 @@ class TestConfigurationManager(TestCase): mock_check_path_exists: MagicMock, mock_find_files_with_suffix_under_directory: MagicMock, mock_get_default_account_id: MagicMock, - mock_get_default_region: MagicMock) -> None: - TestConfigurationManager._expected_configuration_manager.setup(TestConfigurationManager._expected_directory_path) + mock_get_default_region: MagicMock, + mock_setup_default_session: MagicMock) -> None: + TestConfigurationManager._expected_configuration_manager.setup( + "", TestConfigurationManager._expected_directory_path) + mock_setup_default_session.assert_called_once() mock_normalize_file_path.assert_called_once() mock_check_path_exists.assert_called_once_with(TestConfigurationManager._expected_directory_path) mock_find_files_with_suffix_under_directory.assert_called_once_with( diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/manager/test_controller_manager.py b/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/manager/test_controller_manager.py index 93e49415ca..7f2f1dd3f2 100755 --- a/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/manager/test_controller_manager.py +++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/manager/test_controller_manager.py @@ -25,6 +25,9 @@ class TestControllerManager(TestCase): @classmethod def setUpClass(cls) -> None: + error_controller_patcher: patch = patch("manager.controller_manager.ErrorController") + cls._mock_error_controller = error_controller_patcher.start() + import_resources_controller_patcher: patch = patch("manager.controller_manager.ImportResourcesController") cls._mock_import_resources_controller = import_resources_controller_patcher.start() @@ -52,8 +55,14 @@ class TestControllerManager(TestCase): mocked_import_resources_controller: MagicMock = \ TestControllerManager._mock_import_resources_controller.return_value - TestControllerManager._expected_controller_manager.setup() + TestControllerManager._expected_controller_manager.setup(False) mocked_view_edit_controller.setup.assert_called_once() mocked_import_resources_controller.setup.assert_called_once() mocked_import_resources_controller.add_import_resources_sender.connect.assert_called_once_with( mocked_view_edit_controller.add_import_resources_receiver) + + def test_setup_error_controller_setup_gets_invoked(self) -> None: + mocked_error_controller: MagicMock = TestControllerManager._mock_error_controller.return_value + + TestControllerManager._expected_controller_manager.setup(True) + mocked_error_controller.setup.assert_called_once() diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/manager/test_thread_manager.py b/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/manager/test_thread_manager.py index 456a17efe2..06e2b4abbd 100755 --- a/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/manager/test_thread_manager.py +++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/manager/test_thread_manager.py @@ -45,9 +45,15 @@ class TestThreadManager(TestCase): def test_setup_thread_pool_setup_with_expected_configuration(self) -> None: mocked_thread_pool: MagicMock = TestThreadManager._mock_thread_pool.return_value - TestThreadManager._expected_thread_manager.setup() + TestThreadManager._expected_thread_manager.setup(False) mocked_thread_pool.setMaxThreadCount.assert_called_once_with(1) + def test_setup_thread_pool_skip_setup(self) -> None: + mocked_thread_pool: MagicMock = TestThreadManager._mock_thread_pool.return_value + + TestThreadManager._expected_thread_manager.setup(True) + mocked_thread_pool.setMaxThreadCount.asset_not_called() + def test_start_thread_pool_start_expected_worker(self) -> None: mocked_thread_pool: MagicMock = TestThreadManager._mock_thread_pool.return_value expected_mocked_worker: MagicMock = MagicMock() diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/manager/test_view_manager.py b/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/manager/test_view_manager.py index e5c84c6579..57ec41ba0a 100755 --- a/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/manager/test_view_manager.py +++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/manager/test_view_manager.py @@ -13,13 +13,14 @@ from typing import List from unittest import TestCase from unittest.mock import (call, MagicMock, patch) -from manager.view_manager import (ViewManager, ViewManagerConstants) +from manager.view_manager import (ERROR_PAGE_INDEX, ViewManager, ViewManagerConstants) class TestViewManager(TestCase): """ ViewManager unit test cases """ + _mock_error_page: MagicMock _mock_import_resources_page: MagicMock _mock_view_edit_page: MagicMock _mock_main_window: MagicMock @@ -28,6 +29,9 @@ class TestViewManager(TestCase): @classmethod def setUpClass(cls) -> None: + error_page_patcher: patch = patch("manager.view_manager.ErrorPage") + cls._mock_error_page = error_page_patcher.start() + import_resources_page_patcher: patch = patch("manager.view_manager.ImportResourcesPage") cls._mock_import_resources_page = import_resources_page_patcher.start() @@ -60,6 +64,15 @@ class TestViewManager(TestCase): def test_get_instance_raise_exception(self) -> None: self.assertRaises(Exception, ViewManager) + def test_get_error_page_return_expected_page(self) -> None: + expected_page: MagicMock = TestViewManager._mock_error_page.return_value + mocked_stacked_pages: MagicMock = TestViewManager._mock_stacked_pages.return_value + mocked_stacked_pages.widget.return_value = expected_page + + actual_page: MagicMock = TestViewManager._expected_view_manager.get_error_page() + mocked_stacked_pages.widget.assert_called_once_with(ERROR_PAGE_INDEX) + assert actual_page == expected_page + def test_get_import_resources_page_return_expected_page(self) -> None: expected_page: MagicMock = TestViewManager._mock_import_resources_page.return_value mocked_stacked_pages: MagicMock = TestViewManager._mock_stacked_pages.return_value @@ -83,18 +96,34 @@ class TestViewManager(TestCase): mocked_import_resources_page: MagicMock = TestViewManager._mock_import_resources_page.return_value mocked_view_edit_page: MagicMock = TestViewManager._mock_view_edit_page.return_value - TestViewManager._expected_view_manager.setup() + TestViewManager._expected_view_manager.setup(False) mocked_calls: List[call] = [call(mocked_view_edit_page), call(mocked_import_resources_page)] mocked_stacked_pages.addWidget.assert_has_calls(mocked_calls) + def test_setup_error_page_only(self) -> None: + mocked_stacked_pages: MagicMock = TestViewManager._mock_stacked_pages.return_value + mocked_error_page: MagicMock = TestViewManager._mock_error_page.return_value + + TestViewManager._expected_view_manager.setup(True) + mocked_calls: List[call] = [call(mocked_error_page)] + mocked_stacked_pages.addWidget.assert_has_calls(mocked_calls) + def test_show_stacked_pages_show_with_expected_index(self) -> None: mocked_stacked_pages: MagicMock = TestViewManager._mock_stacked_pages.return_value mocked_main_window: MagicMock = TestViewManager._mock_main_window.return_value - TestViewManager._expected_view_manager.show() + TestViewManager._expected_view_manager.show(False) mocked_stacked_pages.setCurrentIndex.assert_called_once_with(ViewManagerConstants.VIEW_AND_EDIT_PAGE_INDEX) mocked_main_window.show.assert_called_once() + def test_show_stacked_pages_show_error_plage(self) -> None: + mocked_stacked_pages: MagicMock = TestViewManager._mock_stacked_pages.return_value + mocked_main_window: MagicMock = TestViewManager._mock_main_window.return_value + + TestViewManager._expected_view_manager.show(True) + mocked_stacked_pages.setCurrentIndex.assert_called_once_with(ERROR_PAGE_INDEX) + mocked_main_window.show.assert_called_once() + def test_switch_to_view_edit_page_stacked_pages_switch_to_expected_index(self) -> None: mocked_stacked_pages: MagicMock = TestViewManager._mock_stacked_pages.return_value diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/view/common_view_components.py b/Gems/AWSCore/Code/Tools/ResourceMappingTool/view/common_view_components.py index 8aad0a785c..39c94ccf77 100755 --- a/Gems/AWSCore/Code/Tools/ResourceMappingTool/view/common_view_components.py +++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/view/common_view_components.py @@ -37,10 +37,12 @@ class NotificationFrame(QFrame): self.setFrameStyle(QFrame.StyledPanel | QFrame.Plain) icon_label: QLabel = QLabel(self) + icon_label.setObjectName("NotificationIcon") icon_label.setPixmap(pixmap) self._title_label: QLabel = QLabel(title, self) - self._title_label.setObjectName("Title") + self._title_label.setOpenExternalLinks(True) + self._title_label.setObjectName("NotificationTitle") self._title_label.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)) self._title_label.setWordWrap(True) diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/view/error_page.py b/Gems/AWSCore/Code/Tools/ResourceMappingTool/view/error_page.py new file mode 100644 index 0000000000..2b42d2bfc2 --- /dev/null +++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/view/error_page.py @@ -0,0 +1,89 @@ +""" +All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +its licensors. + +For complete copyright and license terms please see the LICENSE at the root of this +distribution (the "License"). All use of this software is governed by the License, +or, if provided, by the license below or the license accompanying this file. Do not +remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +""" + +from PySide2.QtGui import QPixmap +from PySide2.QtWidgets import (QHBoxLayout, QLayout, QPushButton, QSizePolicy, QSpacerItem, QVBoxLayout, QWidget) + +from model import (error_messages, notification_label_text, view_size_constants) +from view.common_view_components import NotificationFrame + + +class ErrorPage(QWidget): + """ + Error Page + """ + def __init__(self) -> None: + super().__init__() + self.setGeometry(0, 0, + view_size_constants.ERROR_PAGE_MAIN_WINDOW_WIDTH, + view_size_constants.ERROR_PAGE_MAIN_WINDOW_HEIGHT) + + page_vertical_layout: QVBoxLayout = QVBoxLayout(self) + page_vertical_layout.setSizeConstraint(QLayout.SetMinimumSize) + page_vertical_layout.setMargin(0) + + self._setup_notification_area() + page_vertical_layout.addWidget(self._notification_area) + + self._setup_footer_area() + page_vertical_layout.addWidget(self._footer_area) + + def _setup_notification_area(self) -> None: + self._notification_area: QWidget = QWidget(self) + self._notification_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) + self._notification_area.setMinimumSize(view_size_constants.ERROR_PAGE_MAIN_WINDOW_WIDTH, + view_size_constants.ERROR_PAGE_NOTIFICATION_AREA_HEIGHT) + + notification_area_layout: QVBoxLayout = QVBoxLayout(self._notification_area) + notification_area_layout.setSizeConstraint(QLayout.SetMinimumSize) + notification_area_layout.setContentsMargins( + view_size_constants.ERROR_PAGE_LAYOUT_MARGIN_LEFTRIGHT, + view_size_constants.MAIN_PAGE_LAYOUT_MARGIN_TOPBOTTOM, + view_size_constants.ERROR_PAGE_LAYOUT_MARGIN_LEFTRIGHT, 0) + + notification_frame: NotificationFrame = \ + NotificationFrame(self, QPixmap(":/error_report_warning.svg"), + error_messages.ERROR_PAGE_TOOL_SETUP_ERROR_MESSAGE, False) + notification_frame.setObjectName("ErrorPage") + notification_frame.setMinimumSize(view_size_constants.ERROR_PAGE_MAIN_WINDOW_WIDTH, + view_size_constants.ERROR_PAGE_NOTIFICATION_AREA_HEIGHT) + notification_frame.setVisible(True) + notification_area_layout.addWidget(notification_frame) + + def _setup_footer_area(self) -> None: + self._footer_area: QWidget = QWidget(self) + self._footer_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) + self._footer_area.setMaximumSize(view_size_constants.TOOL_APPLICATION_MAIN_WINDOW_WIDTH, + view_size_constants.ERROR_PAGE_FOOTER_AREA_HEIGHT) + + footer_area_layout: QHBoxLayout = QHBoxLayout(self._footer_area) + footer_area_layout.setSizeConstraint(QLayout.SetMinimumSize) + footer_area_layout.setContentsMargins( + view_size_constants.ERROR_PAGE_LAYOUT_MARGIN_LEFTRIGHT, + view_size_constants.ERROR_PAGE_LAYOUT_MARGIN_TOPBOTTOM, + view_size_constants.ERROR_PAGE_LAYOUT_MARGIN_LEFTRIGHT, + view_size_constants.ERROR_PAGE_LAYOUT_MARGIN_TOPBOTTOM) + + footer_area_spacer: QSpacerItem = QSpacerItem(view_size_constants.ERROR_PAGE_MAIN_WINDOW_WIDTH, + view_size_constants.INTERACTION_COMPONENT_HEIGHT, + QSizePolicy.MinimumExpanding, QSizePolicy.Minimum) + footer_area_layout.addItem(footer_area_spacer) + + self._ok_button: QPushButton = QPushButton(self._footer_area) + self._ok_button.setObjectName("Secondary") + self._ok_button.setText(notification_label_text.ERROR_PAGE_OK_TEXT) + self._ok_button.setMinimumSize(view_size_constants.OK_BUTTON_WIDTH, + view_size_constants.INTERACTION_COMPONENT_HEIGHT) + footer_area_layout.addWidget(self._ok_button) + + @property + def ok_button(self) -> QPushButton: + return self._ok_button From adf6d93a06cb8470e59b979d2552b2b3d0ca53ec Mon Sep 17 00:00:00 2001 From: Terry Michaels Date: Wed, 9 Jun 2021 22:37:28 -0500 Subject: [PATCH 35/73] Moved toggle pivot to lower in the context menu, converted all context menu additions to use a singular mechanism (#1209) --- .../API/ToolsApplicationAPI.h | 3 -- .../Editor/EditorContextMenuBus.h | 2 +- .../UI/Outliner/EntityOutlinerWidget.cpp | 4 +-- .../UI/Prefab/PrefabIntegrationManager.cpp | 2 +- .../UI/Prefab/PrefabIntegrationManager.h | 2 +- .../Viewport/EditorContextMenu.cpp | 4 +-- .../EditorTransformComponentSelection.cpp | 28 +++++++++++++------ .../EditorTransformComponentSelection.h | 8 +++++- Code/Sandbox/Editor/RenderViewport.cpp | 9 +++--- Code/Sandbox/Editor/RenderViewport.h | 2 +- .../SandboxIntegration.cpp | 16 +++++------ .../SandboxIntegration.h | 6 ++-- .../UI/Outliner/OutlinerWidget.cpp | 5 ++-- .../Source/CameraEditorSystemComponent.cpp | 2 ++ .../Code/Source/CameraEditorSystemComponent.h | 8 +++++- .../Components/EditorSystemComponent.cpp | 2 ++ .../Source/Components/EditorSystemComponent.h | 6 +++- .../Code/Editor/SystemComponent.cpp | 2 ++ .../Code/Editor/SystemComponent.h | 8 +++++- 19 files changed, 79 insertions(+), 40 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h index 72150b1b57..ab5c58c72a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h @@ -916,9 +916,6 @@ namespace AzToolsFramework eECMF_USE_VIEWPORT_CENTER = 0x2, }; - /// Populate global edit-time context menu. - virtual void PopulateEditorGlobalContextMenu(QMenu * /*menu*/, const AZ::Vector2& /*point*/, int /*flags*/) {} - /// Populate slice portion of edit-time context menu virtual void PopulateEditorGlobalContextMenu_SliceSection(QMenu * /*menu*/, const AZ::Vector2& /*point*/, int /*flags*/) {} diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/EditorContextMenuBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/EditorContextMenuBus.h index 33710e68f3..e8f37be539 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/EditorContextMenuBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/EditorContextMenuBus.h @@ -79,7 +79,7 @@ namespace AzToolsFramework * This is the menu that appears when right clicking the main editor window, * including the Entity Outliner and the Viewport. */ - virtual void PopulateEditorGlobalContextMenu(QMenu* menu) const = 0; + virtual void PopulateEditorGlobalContextMenu(QMenu* menu, const AZ::Vector2& point, int flags) = 0; }; using EditorContextMenuBus = AZ::EBus; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp index 8293614525..d569d266ab 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -544,8 +545,7 @@ namespace AzToolsFramework QMenu* contextMenu = new QMenu(this); // Populate global context menu. - EBUS_EVENT(EditorEvents::Bus, - PopulateEditorGlobalContextMenu, + AzToolsFramework::EditorContextMenuBus::Broadcast(&AzToolsFramework::EditorContextMenuEvents::PopulateEditorGlobalContextMenu, contextMenu, AZ::Vector2::CreateZero(), EditorEvents::eECMF_HIDE_ENTITY_CREATION | EditorEvents::eECMF_USE_VIEWPORT_CENTER); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp index 9d01911532..77918565e4 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp @@ -119,7 +119,7 @@ namespace AzToolsFramework return "Prefabs"; } - void PrefabIntegrationManager::PopulateEditorGlobalContextMenu(QMenu* menu) const + void PrefabIntegrationManager::PopulateEditorGlobalContextMenu(QMenu* menu, [[maybe_unused]] const AZ::Vector2& point, [[maybe_unused]] int flags) { AzToolsFramework::EntityIdList selectedEntities; AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult( diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h index 69ec3013cc..a3a9bc3741 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h @@ -65,7 +65,7 @@ namespace AzToolsFramework // EditorContextMenuBus... int GetMenuPosition() const override; AZStd::string GetMenuIdentifier() const override; - void PopulateEditorGlobalContextMenu(QMenu* menu) const override; + void PopulateEditorGlobalContextMenu(QMenu* menu, const AZ::Vector2& point, int flags) override; // EntityOutlinerSourceDropHandlingBus... void HandleSourceFileType(AZStd::string_view sourceFilePath, AZ::EntityId parentId, AZ::Vector3 position) const override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/EditorContextMenu.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/EditorContextMenu.cpp index 308f0f074f..4521f45783 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/EditorContextMenu.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/EditorContextMenu.cpp @@ -13,6 +13,7 @@ #include "EditorContextMenu.h" #include "AzToolsFramework/Viewport/ViewportMessages.h" +#include "Editor/EditorContextMenuBus.h" namespace AzToolsFramework { @@ -55,8 +56,7 @@ namespace AzToolsFramework // Populate global context menu. const int contextMenuFlag = 0; - EditorEvents::Bus::BroadcastReverse( - &EditorEvents::PopulateEditorGlobalContextMenu, contextMenu.m_menu.data(), + AzToolsFramework::EditorContextMenuBus::Broadcast(&AzToolsFramework::EditorContextMenuEvents::PopulateEditorGlobalContextMenu, contextMenu.m_menu.data(), AzFramework::Vector2FromScreenPoint(mouseInteraction.m_mouseInteraction.m_mousePick.m_screenCoordinates), contextMenuFlag); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp index eadb870563..c503386ab5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp @@ -1018,6 +1018,7 @@ namespace AzToolsFramework EditorEntityVisibilityNotificationBus::Router::BusRouterConnect(); EditorEntityLockComponentNotificationBus::Router::BusRouterConnect(); EditorManipulatorCommandUndoRedoRequestBus::Handler::BusConnect(entityContextId); + EditorContextMenuBus::Handler::BusConnect(); CreateTransformModeSelectionCluster(); CreateSpaceSelectionCluster(); @@ -1038,6 +1039,7 @@ namespace AzToolsFramework m_pivotOverrideFrame.Reset(); + EditorContextMenuBus::Handler::BusConnect(); EditorManipulatorCommandUndoRedoRequestBus::Handler::BusDisconnect(); EditorEntityLockComponentNotificationBus::Router::BusRouterDisconnect(); EditorEntityVisibilityNotificationBus::Router::BusRouterDisconnect(); @@ -3097,15 +3099,25 @@ namespace AzToolsFramework } } - void EditorTransformComponentSelection::PopulateEditorGlobalContextMenu(QMenu* menu, const AZ::Vector2& /*point*/, const int /*flags*/) + int EditorTransformComponentSelection::GetMenuPosition() const { - QAction* action = menu->addAction(QObject::tr(s_togglePivotTitleRightClick)); - QObject::connect( - action, &QAction::triggered, action, - [this]() - { - ToggleCenterPivotSelection(); - }); + return aznumeric_cast(EditorContextMenuOrdering::BOTTOM); + } + + AZStd::string EditorTransformComponentSelection::GetMenuIdentifier() const + { + return "Transform Component"; + } + + void EditorTransformComponentSelection::PopulateEditorGlobalContextMenu(QMenu* menu, [[maybe_unused]] const AZ::Vector2& point, [[maybe_unused]] int flags) + { + QAction* action = menu->addAction(QObject::tr(s_togglePivotTitleRightClick)); + QObject::connect( + action, &QAction::triggered, action, + [this]() + { + ToggleCenterPivotSelection(); + }); } void EditorTransformComponentSelection::BeforeEntitySelectionChanged() diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.h index 2ec7fa2489..1b52911978 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -126,6 +127,7 @@ namespace AzToolsFramework //! Provide a suite of functionality for manipulating entities, primarily through their TransformComponent. class EditorTransformComponentSelection : public ViewportInteraction::ViewportSelectionRequests + , public EditorContextMenuBus::Handler , private EditorEventsBus::Handler , private EditorTransformComponentSelectionRequestBus::Handler , private ToolsApplicationNotificationBus::Handler @@ -238,8 +240,12 @@ namespace AzToolsFramework void UndoRedoEntityManipulatorCommand( AZ::u8 pivotOverride, const AZ::Transform& transform, AZ::EntityId entityId) override; + // EditorContextMenuBus... + void PopulateEditorGlobalContextMenu(QMenu* menu, const AZ::Vector2 & point, int flags) override; + int GetMenuPosition() const override; + AZStd::string GetMenuIdentifier() const override; + // EditorEventsBus ... - void PopulateEditorGlobalContextMenu(QMenu *menu, const AZ::Vector2& point, int flags) override; void OnEscape() override; // ToolsApplicationNotificationBus ... diff --git a/Code/Sandbox/Editor/RenderViewport.cpp b/Code/Sandbox/Editor/RenderViewport.cpp index 8cef9e802c..bd30bc7c79 100644 --- a/Code/Sandbox/Editor/RenderViewport.cpp +++ b/Code/Sandbox/Editor/RenderViewport.cpp @@ -49,6 +49,7 @@ // AzToolsFramework #include #include +#include #include #include #include @@ -112,20 +113,20 @@ static const char TextCantCreateCameraNoLevel[] = "Cannot create camera when no class EditorEntityNotifications : public AzToolsFramework::EditorEntityContextNotificationBus::Handler - , public AzToolsFramework::EditorEvents::Bus::Handler + , public AzToolsFramework::EditorContextMenuBus::Handler { public: EditorEntityNotifications(CRenderViewport& renderViewport) : m_renderViewport(renderViewport) { AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusConnect(); - AzToolsFramework::EditorEvents::Bus::Handler::BusConnect(); + AzToolsFramework::EditorContextMenuBus::Handler::BusConnect(); } ~EditorEntityNotifications() override { AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusDisconnect(); - AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect(); + AzToolsFramework::EditorContextMenuBus::Handler::BusDisconnect(); } // AzToolsFramework::EditorEntityContextNotificationBus @@ -138,7 +139,7 @@ public: m_renderViewport.OnStopPlayInEditor(); } - // AzToolsFramework::EditorEvents::Bus + // AzToolsFramework::EditorContextMenu::Bus void PopulateEditorGlobalContextMenu(QMenu* menu, const AZ::Vector2& point, int flags) override { m_renderViewport.PopulateEditorGlobalContextMenu(menu, point, flags); diff --git a/Code/Sandbox/Editor/RenderViewport.h b/Code/Sandbox/Editor/RenderViewport.h index b45c92b1c8..d7d362fe27 100644 --- a/Code/Sandbox/Editor/RenderViewport.h +++ b/Code/Sandbox/Editor/RenderViewport.h @@ -179,7 +179,7 @@ public: virtual void OnStartPlayInEditor(); virtual void OnStopPlayInEditor(); - // AzToolsFramework::EditorEvents::Bus (handler moved to cpp to resolve link issues in unity builds) + // AzToolsFramework::EditorContextMenu::Bus (handler moved to cpp to resolve link issues in unity builds) // We use this to determine when the viewport context menu is being displayed so we can exit move mode void PopulateEditorGlobalContextMenu(QMenu* /*menu*/, const AZ::Vector2& /*point*/, int /*flags*/); diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp index 694714cc6e..3b04fc70f8 100644 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp +++ b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp @@ -167,7 +167,7 @@ void SandboxIntegrationManager::Setup() AzToolsFramework::ToolsApplicationEvents::Bus::Handler::BusConnect(); AzToolsFramework::EditorRequests::Bus::Handler::BusConnect(); AzToolsFramework::EditorWindowRequests::Bus::Handler::BusConnect(); - AzToolsFramework::EditorEvents::Bus::Handler::BusConnect(); + AzToolsFramework::EditorContextMenuBus::Handler::BusConnect(); AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusConnect(); AzToolsFramework::SliceEditorEntityOwnershipServiceNotificationBus::Handler::BusConnect(); @@ -384,7 +384,7 @@ void SandboxIntegrationManager::Teardown() AzFramework::DisplayContextRequestBus::Handler::BusDisconnect(); AzToolsFramework::SliceEditorEntityOwnershipServiceNotificationBus::Handler::BusDisconnect(); AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusDisconnect(); - AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect(); + AzToolsFramework::EditorContextMenuBus::Handler::BusDisconnect(); AzToolsFramework::EditorWindowRequests::Bus::Handler::BusDisconnect(); AzToolsFramework::EditorRequests::Bus::Handler::BusDisconnect(); AzToolsFramework::ToolsApplicationEvents::Bus::Handler::BusDisconnect(); @@ -589,6 +589,11 @@ void SandboxIntegrationManager::OnSaveLevel() m_unsavedEntities.clear(); } +int SandboxIntegrationManager::GetMenuPosition() const +{ + return aznumeric_cast(AzToolsFramework::EditorContextMenuOrdering::TOP); +} + void SandboxIntegrationManager::PopulateEditorGlobalContextMenu(QMenu* menu, const AZ::Vector2& point, int flags) { if (!IsLevelDocumentOpen()) @@ -662,13 +667,6 @@ void SandboxIntegrationManager::PopulateEditorGlobalContextMenu(QMenu* menu, con SetupSliceContextMenu(menu); } - else - { - menu->addSeparator(); - - // Allow handlers to append menu items to the context menu - AzToolsFramework::EditorContextMenuBus::Broadcast(&AzToolsFramework::EditorContextMenuEvents::PopulateEditorGlobalContextMenu, menu); - } action = menu->addAction(QObject::tr("Duplicate")); QObject::connect(action, &QAction::triggered, action, [this] { ContextMenu_Duplicate(); }); diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h index 6d714b67df..5cb03cc99f 100644 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h +++ b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -97,7 +98,7 @@ class SandboxIntegrationManager : private AzToolsFramework::ToolsApplicationEvents::Bus::Handler , private AzToolsFramework::EditorRequests::Bus::Handler , private AzToolsFramework::EditorPickModeNotificationBus::Handler - , private AzToolsFramework::EditorEvents::Bus::Handler + , private AzToolsFramework::EditorContextMenuBus::Handler , private AzToolsFramework::EditorWindowRequests::Bus::Handler , private AzFramework::AssetCatalogEventBus::Handler , private AzFramework::DisplayContextRequestBus::Handler @@ -184,8 +185,9 @@ private: void OnEntityPickModeStopped() override; ////////////////////////////////////////////////////////////////////////// - // AzToolsFramework::EditorEvents::Bus::Handler overrides + // AzToolsFramework::EditorContextMenu::Bus::Handler overrides void PopulateEditorGlobalContextMenu(QMenu* menu, const AZ::Vector2& point, int flags) override; + int GetMenuPosition() const; ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerWidget.cpp b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerWidget.cpp index fb8084cb6f..33126c7f3e 100644 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerWidget.cpp +++ b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerWidget.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -530,8 +531,8 @@ void OutlinerWidget::contextMenuEvent(QContextMenuEvent* event) QMenu* contextMenu = new QMenu(this); // Populate global context menu. - EBUS_EVENT(AzToolsFramework::EditorEvents::Bus, - PopulateEditorGlobalContextMenu, + + AzToolsFramework::EditorContextMenuBus::Broadcast(&AzToolsFramework::EditorContextMenuEvents::PopulateEditorGlobalContextMenu, contextMenu, AZ::Vector2::CreateZero(), AzToolsFramework::EditorEvents::eECMF_HIDE_ENTITY_CREATION | AzToolsFramework::EditorEvents::eECMF_USE_VIEWPORT_CENTER); diff --git a/Gems/Camera/Code/Source/CameraEditorSystemComponent.cpp b/Gems/Camera/Code/Source/CameraEditorSystemComponent.cpp index 9b6202b6c6..33290b9cfe 100644 --- a/Gems/Camera/Code/Source/CameraEditorSystemComponent.cpp +++ b/Gems/Camera/Code/Source/CameraEditorSystemComponent.cpp @@ -61,6 +61,7 @@ namespace Camera void CameraEditorSystemComponent::Activate() { + AzToolsFramework::EditorContextMenuBus::Handler::BusConnect(); AzToolsFramework::EditorEvents::Bus::Handler::BusConnect(); Camera::EditorCameraSystemRequestBus::Handler::BusConnect(); Camera::CameraViewRegistrationRequestsBus::Handler::BusConnect(); @@ -71,6 +72,7 @@ namespace Camera Camera::CameraViewRegistrationRequestsBus::Handler::BusDisconnect(); Camera::EditorCameraSystemRequestBus::Handler::BusDisconnect(); AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect(); + AzToolsFramework::EditorContextMenuBus::Handler::BusDisconnect(); } void CameraEditorSystemComponent::PopulateEditorGlobalContextMenu(QMenu* menu, const AZ::Vector2&, int flags) diff --git a/Gems/Camera/Code/Source/CameraEditorSystemComponent.h b/Gems/Camera/Code/Source/CameraEditorSystemComponent.h index ec361c1afd..44f23f38e6 100644 --- a/Gems/Camera/Code/Source/CameraEditorSystemComponent.h +++ b/Gems/Camera/Code/Source/CameraEditorSystemComponent.h @@ -15,6 +15,7 @@ #include #include +#include #include "CameraViewRegistrationBus.h" @@ -25,6 +26,7 @@ namespace Camera , private AzToolsFramework::EditorEvents::Bus::Handler , private EditorCameraSystemRequestBus::Handler , private CameraViewRegistrationRequestsBus::Handler + , private AzToolsFramework::EditorContextMenuBus::Handler { public: AZ_COMPONENT(CameraEditorSystemComponent, "{769802EB-722A-4F89-A475-DA396DA1FDCC}"); @@ -40,9 +42,13 @@ namespace Camera ////////////////////////////////////////////////////////////////////////// private: + ////////////////////////////////////////////////////////////////////////// + // AzToolsFramework::EditorContextMenuBus + void PopulateEditorGlobalContextMenu(QMenu* menu, const AZ::Vector2& point, int flags) override; + ////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////// // AzToolsFramework::EditorEvents - void PopulateEditorGlobalContextMenu(QMenu *menu, const AZ::Vector2& point, int flags) override; void NotifyRegisterViews() override; ////////////////////////////////////////////////////////////////////////// diff --git a/Gems/PhysX/Code/Editor/Source/Components/EditorSystemComponent.cpp b/Gems/PhysX/Code/Editor/Source/Components/EditorSystemComponent.cpp index b28bf6ab4a..fff13d2f39 100644 --- a/Gems/PhysX/Code/Editor/Source/Components/EditorSystemComponent.cpp +++ b/Gems/PhysX/Code/Editor/Source/Components/EditorSystemComponent.cpp @@ -134,6 +134,7 @@ namespace PhysX void EditorSystemComponent::Activate() { Physics::EditorWorldBus::Handler::BusConnect(); + AzToolsFramework::EditorContextMenuBus::Handler::BusConnect(); m_onMaterialLibraryLoadErrorEventHandler = AzPhysics::SystemEvents::OnMaterialLibraryLoadErrorEvent::Handler( [this]([[maybe_unused]] AzPhysics::SystemEvents::MaterialLibraryLoadErrorType error) @@ -168,6 +169,7 @@ namespace PhysX { AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusDisconnect(); AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect(); + AzToolsFramework::EditorContextMenuBus::Handler::BusDisconnect(); Physics::EditorWorldBus::Handler::BusDisconnect(); if (auto* physicsSystem = AZ::Interface::Get()) diff --git a/Gems/PhysX/Code/Editor/Source/Components/EditorSystemComponent.h b/Gems/PhysX/Code/Editor/Source/Components/EditorSystemComponent.h index 4bd11a951f..8105709244 100644 --- a/Gems/PhysX/Code/Editor/Source/Components/EditorSystemComponent.h +++ b/Gems/PhysX/Code/Editor/Source/Components/EditorSystemComponent.h @@ -15,6 +15,7 @@ #include #include #include +#include #include namespace AzPhysics @@ -32,6 +33,7 @@ namespace PhysX , public Physics::EditorWorldBus::Handler , private AzToolsFramework::EditorEntityContextNotificationBus::Handler , private AzToolsFramework::EditorEvents::Bus::Handler + , private AzToolsFramework::EditorContextMenuBus::Handler { public: AZ_COMPONENT(EditorSystemComponent, "{560F08DC-94F5-4D29-9AD4-CDFB3B57C654}"); @@ -62,8 +64,10 @@ namespace PhysX void OnStartPlayInEditorBegin() override; void OnStopPlayInEditor() override; - // AztoolsFramework::EditorEvents::Bus::Handler + // AztoolsFramework::EditorContextMenuBus::Handler void PopulateEditorGlobalContextMenu(QMenu* menu, const AZ::Vector2& point, int flags) override; + + // AztoolsFramework::EditorEvents::Bus::Handler void NotifyRegisterViews() override; AZStd::optional> RetrieveDefaultMaterialLibrary(); diff --git a/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp b/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp index 60e8e5f23a..1d4d1e8605 100644 --- a/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp @@ -66,6 +66,7 @@ namespace ScriptCanvasEditor SystemComponent::~SystemComponent() { AzToolsFramework::UnregisterViewPane(LyViewPane::ScriptCanvas); + AzToolsFramework::EditorContextMenuBus::Handler::BusDisconnect(); AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect(); AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); AzToolsFramework::AssetSeedManagerRequests::Bus::Handler::BusDisconnect(); @@ -119,6 +120,7 @@ namespace ScriptCanvasEditor void SystemComponent::Init() { AzToolsFramework::EditorEvents::Bus::Handler::BusConnect(); + AzToolsFramework::EditorContextMenuBus::Handler::BusConnect(); } void SystemComponent::Activate() diff --git a/Gems/ScriptCanvas/Code/Editor/SystemComponent.h b/Gems/ScriptCanvas/Code/Editor/SystemComponent.h index f2ebad38cd..ced5a67a4c 100644 --- a/Gems/ScriptCanvas/Code/Editor/SystemComponent.h +++ b/Gems/ScriptCanvas/Code/Editor/SystemComponent.h @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -42,6 +43,7 @@ namespace ScriptCanvasEditor , private AZ::Data::AssetBus::MultiHandler , private AZ::Interface::Registrar , private AzToolsFramework::AssetSeedManagerRequests::Bus::Handler + , private AzToolsFramework::EditorContextMenuBus::Handler { public: AZ_COMPONENT(SystemComponent, "{1DE7A120-4371-4009-82B5-8140CB1D7B31}"); @@ -71,8 +73,12 @@ namespace ScriptCanvasEditor //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// - // AztoolsFramework::EditorEvents::Bus::Handler... + // AztoolsFramework::EditorContextMenuBus::Handler... void PopulateEditorGlobalContextMenu(QMenu* menu, const AZ::Vector2& point, int flags) override; + //////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////// + // AztoolsFramework::EditorEvents::Bus::Handler... void NotifyRegisterViews() override; //////////////////////////////////////////////////////////////////////// From 9d41954d0e5bdf97b301941279bda966eae67146 Mon Sep 17 00:00:00 2001 From: Aaron Ruiz Mora Date: Thu, 10 Jun 2021 12:22:16 +0100 Subject: [PATCH 36/73] Added configurable physics materials per asset in PhysX group in FBX Settings. (#1186) - Added back the' Physics Materials from Asset' tick in the collider components. - Made physics materials names case insensitive. - Refactored how to gather material information from fbx and used the same code for exporter and physx groups. --- .../AzFramework/Physics/Material.cpp | 7 +- .../AzFramework/Physics/Material.h | 2 + .../Physics/ShapeConfiguration.cpp | 19 +- .../AzFramework/Physics/ShapeConfiguration.h | 2 +- .../Code/Editor/ConfigStringLineEditCtrl.cpp | 12 +- .../Code/Editor/ConfigStringLineEditCtrl.h | 8 +- Gems/PhysX/Code/Editor/MaterialIdWidget.cpp | 8 +- .../Code/Editor/UniqueStringContainer.cpp | 10 +- .../PhysX/Code/Editor/UniqueStringContainer.h | 33 +- Gems/PhysX/Code/Include/PhysX/MeshAsset.h | 4 +- .../Code/Source/EditorColliderComponent.cpp | 14 +- .../Code/Source/EditorColliderComponent.h | 2 +- Gems/PhysX/Code/Source/Material.cpp | 18 +- Gems/PhysX/Code/Source/Material.h | 6 - .../Code/Source/Pipeline/MeshAssetHandler.cpp | 4 +- .../Code/Source/Pipeline/MeshBehavior.cpp | 15 +- .../Code/Source/Pipeline/MeshExporter.cpp | 281 +++++++++--------- .../PhysX/Code/Source/Pipeline/MeshExporter.h | 34 ++- Gems/PhysX/Code/Source/Pipeline/MeshGroup.cpp | 86 +++++- Gems/PhysX/Code/Source/Pipeline/MeshGroup.h | 20 ++ 20 files changed, 364 insertions(+), 221 deletions(-) diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp index 78e0431753..4afbbaa4dc 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp @@ -300,7 +300,7 @@ namespace Physics { auto foundMaterialConfiguration = AZStd::find_if(m_materialLibrary.begin(), m_materialLibrary.end(), [&materialName](const auto& data) { - return data.m_configuration.m_surfaceType == materialName; + return AZ::StringFunc::Equal(data.m_configuration.m_surfaceType, materialName, false/*bCaseSensitive*/); }); if (foundMaterialConfiguration != m_materialLibrary.end()) @@ -377,15 +377,16 @@ namespace Physics if (auto editContext = serializeContext->GetEditContext()) { - editContext->Class("Physics Material", "Select physics material library and which materials to use for the object") + editContext->Class("Physics Materials", "Select which physics materials to use for each element of this object") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(AZ::Edit::UIHandlers::Default, &MaterialSelection::m_materialIdsAssignedToSlots, "Mesh Surfaces", "Specify which Physics Material to use for each element of this object") + ->DataElement(AZ::Edit::UIHandlers::Default, &MaterialSelection::m_materialIdsAssignedToSlots, "", "") ->ElementAttribute(Attributes::MaterialLibraryAssetId, &MaterialSelection::GetMaterialLibraryId) ->Attribute(AZ::Edit::Attributes::IndexedChildNameLabelOverride, &MaterialSelection::GetMaterialSlotLabel) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->ElementAttribute(AZ::Edit::Attributes::ReadOnly, &MaterialSelection::AreMaterialSlotsReadOnly) ->Attribute(AZ::Edit::Attributes::ContainerCanBeModified, false) + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ; } } diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Material.h b/Code/Framework/AzFramework/AzFramework/Physics/Material.h index 69edf3ed25..067f7abe07 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Material.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/Material.h @@ -25,6 +25,8 @@ namespace AZ namespace Physics { + static constexpr AZStd::string_view DefaultPhysicsMaterialLabel = ""; + /// Physics material /// ========================= /// This is the interface to the wrapper around native material type (such as PxMaterial in PhysX gem) diff --git a/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.cpp b/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.cpp index 275103bc28..2c3b113d65 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.cpp @@ -17,21 +17,6 @@ namespace Physics { - namespace Internal - { - bool ShapeConfigurationVersionConverter( - [[maybe_unused]] AZ::SerializeContext& context, - AZ::SerializeContext::DataElementNode& classElement) - { - if (classElement.GetVersion() <= 1) - { - classElement.RemoveElementByName(AZ_CRC_CE("UseMaterialsFromAsset")); - } - - return true; - } - } - void ShapeConfiguration::Reflect(AZ::ReflectContext* context) { if (auto serializeContext = azrtti_cast(context)) @@ -181,9 +166,10 @@ namespace Physics ->RegisterGenericType>(); serializeContext->Class() - ->Version(2, &Internal::ShapeConfigurationVersionConverter) + ->Version(3) ->Field("PhysicsAsset", &PhysicsAssetShapeConfiguration::m_asset) ->Field("AssetScale", &PhysicsAssetShapeConfiguration::m_assetScale) + ->Field("UseMaterialsFromAsset", &PhysicsAssetShapeConfiguration::m_useMaterialsFromAsset) ->Field("SubdivisionLevel", &PhysicsAssetShapeConfiguration::m_subdivisionLevel) ; @@ -196,6 +182,7 @@ namespace Physics ->DataElement(AZ::Edit::UIHandlers::Default, &PhysicsAssetShapeConfiguration::m_assetScale, "Asset Scale", "The scale of the asset shape") ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->Attribute(AZ::Edit::Attributes::Step, 0.01f) + ->DataElement(AZ::Edit::UIHandlers::Default, &PhysicsAssetShapeConfiguration::m_useMaterialsFromAsset, "Physics materials from asset", "Auto-set physics materials using asset's physics material names") ; } } diff --git a/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.h b/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.h index 8234ef9173..b3d04a10c9 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.h @@ -140,7 +140,7 @@ namespace Physics AZ::Data::Asset m_asset{ AZ::Data::AssetLoadBehavior::PreLoad }; AZ::Vector3 m_assetScale = AZ::Vector3::CreateOne(); - bool m_useMaterialsFromAsset = false; // Not reflected or exposed to the user until there is a way to auto-match mesh's materials with physics materials + bool m_useMaterialsFromAsset = true; AZ::u8 m_subdivisionLevel = 4; ///< The level of subdivision if a primitive shape is replaced with a convex mesh due to scaling. }; diff --git a/Gems/PhysX/Code/Editor/ConfigStringLineEditCtrl.cpp b/Gems/PhysX/Code/Editor/ConfigStringLineEditCtrl.cpp index 6aaf45b184..704b538a5f 100644 --- a/Gems/PhysX/Code/Editor/ConfigStringLineEditCtrl.cpp +++ b/Gems/PhysX/Code/Editor/ConfigStringLineEditCtrl.cpp @@ -93,7 +93,7 @@ namespace PhysX } } - void ConfigStringLineEditCtrl::SetForbiddenStrings(const AZStd::unordered_set& forbiddenStrings) + void ConfigStringLineEditCtrl::SetForbiddenStrings(const UniqueStringContainer::StringSet& forbiddenStrings) { m_forbiddenStrings = forbiddenStrings; } @@ -122,7 +122,7 @@ namespace PhysX void ConfigStringLineEditValidator::OnEditStart(AZ::Crc32 stringGroupId , const AZStd::string& stringToEdit - , const AZStd::unordered_set& forbiddenStrings + , const UniqueStringContainer::StringSet& forbiddenStrings , int stringMaxLength , bool removeEditedString) { @@ -229,23 +229,23 @@ namespace PhysX } else if (attrib == Physics::MaterialConfiguration::s_forbiddenStringSet) { - AZStd::unordered_set forbiddenStringsUnorderedSet; + UniqueStringContainer::StringSet forbiddenStringsUnorderedSet; AZStd::set forbiddenStringsSet; AZStd::vector forbiddenStringsVector; - if (attrValue->Read>(forbiddenStringsUnorderedSet)) + if (attrValue->Read(forbiddenStringsUnorderedSet)) { GUI->SetForbiddenStrings(forbiddenStringsUnorderedSet); } else if (attrValue->Read>(forbiddenStringsSet)) { - forbiddenStringsUnorderedSet = AZStd::unordered_set(forbiddenStringsSet.begin() + forbiddenStringsUnorderedSet = UniqueStringContainer::StringSet(forbiddenStringsSet.begin() , forbiddenStringsSet.end()); GUI->SetForbiddenStrings(forbiddenStringsUnorderedSet); } else if (attrValue->Read>(forbiddenStringsVector)) { - forbiddenStringsUnorderedSet = AZStd::unordered_set(forbiddenStringsVector.begin() + forbiddenStringsUnorderedSet = UniqueStringContainer::StringSet(forbiddenStringsVector.begin() , forbiddenStringsVector.end()); GUI->SetForbiddenStrings(forbiddenStringsUnorderedSet); } diff --git a/Gems/PhysX/Code/Editor/ConfigStringLineEditCtrl.h b/Gems/PhysX/Code/Editor/ConfigStringLineEditCtrl.h index e672a9afd8..f9e7b752ec 100644 --- a/Gems/PhysX/Code/Editor/ConfigStringLineEditCtrl.h +++ b/Gems/PhysX/Code/Editor/ConfigStringLineEditCtrl.h @@ -47,7 +47,7 @@ namespace PhysX void OnEditStart(AZ::Crc32 stringGroupId , const AZStd::string& stringToEdit - , const AZStd::unordered_set& forbiddenStrings + , const UniqueStringContainer::StringSet& forbiddenStrings , int stringMaxLength , bool removeEditedString = true); @@ -62,7 +62,7 @@ namespace PhysX private: AZ::Crc32 m_currStringGroup = s_groupStringNotUnique; ///< Group of string field undergoing edit. int m_currStringMaxLen = s_qtLineEditMaxLen; ///< Max length of string field undergoing edit. - AZStd::unordered_set m_forbiddenStrings; ///< Value of string edit widget cannot be any of these strings. + UniqueStringContainer::StringSet m_forbiddenStrings; ///< Value of string edit widget cannot be any of these strings. UniqueStringContainer m_uniqueStringContainer; ///< Collection of groups of unique strings. Serves for validation and fixing of string input. }; @@ -79,7 +79,7 @@ namespace PhysX , ConfigStringLineEditValidator* validator = nullptr); virtual ~ConfigStringLineEditCtrl(); - void SetForbiddenStrings(const AZStd::unordered_set& forbiddenStrings); + void SetForbiddenStrings(const UniqueStringContainer::StringSet& forbiddenStrings); void SetUniqueGroup(AZ::Crc32 uniqueGroup); AZStd::string Value() const; @@ -92,7 +92,7 @@ namespace PhysX protected: void ConnectWidgets() override; - AZStd::unordered_set m_forbiddenStrings; ///< Value of this line edit ctrl cannot be any of these forbidden strings. + UniqueStringContainer::StringSet m_forbiddenStrings; ///< Value of this line edit ctrl cannot be any of these forbidden strings. ConfigStringLineEditValidator* m_pValidator = nullptr; ///< Validator for line edit widget. AZ::Crc32 m_uniqueGroup = ConfigStringLineEditValidator::s_groupStringNotUnique; ///< String group in which line edit value must remain unique. }; diff --git a/Gems/PhysX/Code/Editor/MaterialIdWidget.cpp b/Gems/PhysX/Code/Editor/MaterialIdWidget.cpp index 44787ddd20..30db8aa76d 100644 --- a/Gems/PhysX/Code/Editor/MaterialIdWidget.cpp +++ b/Gems/PhysX/Code/Editor/MaterialIdWidget.cpp @@ -15,12 +15,12 @@ #include +#include + namespace PhysX { namespace Editor { - static const char* const DefaultPhysicsMaterialLabel = ""; - AZ::u32 MaterialIdWidget::GetHandlerName() const { return Physics::Edit::MaterialIdSelector; @@ -74,7 +74,7 @@ namespace PhysX auto lockToDefault = [gui]() { - gui->addItem(DefaultPhysicsMaterialLabel); + gui->addItem(QLatin1String(Physics::DefaultPhysicsMaterialLabel.data(), Physics::DefaultPhysicsMaterialLabel.size())); gui->setCurrentIndex(0); return false; }; @@ -103,7 +103,7 @@ namespace PhysX // Add default physics material first m_libraryIds.push_back(Physics::MaterialId()); - gui->addItem(DefaultPhysicsMaterialLabel); + gui->addItem(QLatin1String(Physics::DefaultPhysicsMaterialLabel.data(), Physics::DefaultPhysicsMaterialLabel.size())); for (const auto& material : materials) { diff --git a/Gems/PhysX/Code/Editor/UniqueStringContainer.cpp b/Gems/PhysX/Code/Editor/UniqueStringContainer.cpp index 6482624dc4..1d92471919 100644 --- a/Gems/PhysX/Code/Editor/UniqueStringContainer.cpp +++ b/Gems/PhysX/Code/Editor/UniqueStringContainer.cpp @@ -23,7 +23,7 @@ namespace PhysX StringGroups::iterator stringGroupsIter = m_stringGroups.find(stringGroupId); if (stringGroupsIter == m_stringGroups.end()) { - m_stringGroups.emplace(stringGroupId, AZStd::unordered_set()); + m_stringGroups.emplace(stringGroupId, StringSet()); } m_stringGroups[stringGroupId].insert(stringIn); } @@ -31,7 +31,7 @@ namespace PhysX AZStd::string UniqueStringContainer::GetUniqueString(AZ::Crc32 stringGroupId , const AZStd::string& stringIn , AZ::u64 maxStringLength - , const AZStd::unordered_set& forbiddenStrings) const + , const StringSet& forbiddenStrings) const { StringGroups::const_iterator stringGroupsIter = m_stringGroups.find(stringGroupId); @@ -45,7 +45,7 @@ namespace PhysX } AZStd::string stringOut; - const AZStd::unordered_set& stringGroup = (stringGroupsIter == m_stringGroups.end())? AZStd::unordered_set():stringGroupsIter->second; + const StringSet& stringGroup = (stringGroupsIter == m_stringGroups.end())? StringSet():stringGroupsIter->second; // Attempts to append a post-fix value, e.g. "_1" etc., to the original string so it is unique. // A unique post-fix index can be found by iterating total number of invalid string plus 1. @@ -86,8 +86,8 @@ namespace PhysX return true; } - const AZStd::unordered_set& stringGroup = stringGroupsIter->second; - return stringGroup.find(stringIn) == stringGroup.end(); + const StringSet& stringSet = stringGroupsIter->second; + return stringSet.find(stringIn) == stringSet.end(); } void UniqueStringContainer::RemoveString(AZ::Crc32 stringGroupId diff --git a/Gems/PhysX/Code/Editor/UniqueStringContainer.h b/Gems/PhysX/Code/Editor/UniqueStringContainer.h index 176063f341..7144137f8a 100644 --- a/Gems/PhysX/Code/Editor/UniqueStringContainer.h +++ b/Gems/PhysX/Code/Editor/UniqueStringContainer.h @@ -16,13 +16,38 @@ #include #include #include +#include namespace PhysX { - /// Class that keeps track of unique strings in groups. + /// Class that keeps track of unique strings (case insensitive) in groups. class UniqueStringContainer { public: + struct CaseInsensitiveStringHash + { + AZ_TYPE_INFO(UniqueStringContainer::CaseInsensitiveStringHash, "{EB80F2A1-2DEB-47CC-ABF7-592F492C20A9}"); + + size_t operator()(const AZStd::string& str) const + { + AZStd::string lowerStr = str; + AZStd::to_lower(lowerStr.begin(), lowerStr.end()); + return AZStd::hash{}(lowerStr); + } + }; + + struct CaseInsensitiveStringEqual + { + AZ_TYPE_INFO(UniqueStringContainer::CaseInsensitiveStringEqual, "{6ADEA1D9-27B8-4C7A-913D-EC8191F1B6A9}"); + + bool operator()(const AZStd::string& arg0, const AZStd::string& arg1) const + { + return AZ::StringFunc::Equal(arg0, arg1, false/*bCaseSensitive*/); + } + }; + + using StringSet = AZStd::unordered_set; + /// Add a unique string to a group of unique strings. void AddString(AZ::Crc32 stringGroupId, const AZStd::string& stringIn); @@ -30,7 +55,7 @@ namespace PhysX AZStd::string GetUniqueString(AZ::Crc32 stringGroupId , const AZStd::string& stringIn , AZ::u64 maxStringLength - , const AZStd::unordered_set& forbiddenStrings) const; + , const StringSet& forbiddenStrings) const; /// Checks if a string would be unique in the identified string group. bool IsStringUnique(AZ::Crc32 stringGroupId, const AZStd::string& stringIn) const; @@ -39,7 +64,7 @@ namespace PhysX void RemoveString(AZ::Crc32 stringGroupId, const AZStd::string& stringIn); private: - using StringGroups = AZStd::unordered_map>; + using StringGroups = AZStd::unordered_map; StringGroups m_stringGroups; ///< Collection of groups of unique strings, each group identified by an ID. }; -} +} // namespace PhysX diff --git a/Gems/PhysX/Code/Include/PhysX/MeshAsset.h b/Gems/PhysX/Code/Include/PhysX/MeshAsset.h index 8467c04359..edfd82439a 100644 --- a/Gems/PhysX/Code/Include/PhysX/MeshAsset.h +++ b/Gems/PhysX/Code/Include/PhysX/MeshAsset.h @@ -62,8 +62,8 @@ namespace PhysX using ShapeConfigurationList = AZStd::vector; ShapeConfigurationList m_colliderShapes; //!< Shapes data with optional collider configuration override. - AZStd::vector m_surfaceNames; //!< List of all surface names. - AZStd::vector m_materialNames; //!< List of all material names. + AZStd::vector m_materialNames; //!< List of material names of the mesh asset. + AZStd::vector m_physicsMaterialNames; //!< List of physics material names associated with each material. AZStd::vector m_materialIndexPerShape; //!< An index of the material in m_materialNames for each shape. }; diff --git a/Gems/PhysX/Code/Source/EditorColliderComponent.cpp b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp index 4454429092..1cb60e0af2 100644 --- a/Gems/PhysX/Code/Source/EditorColliderComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp @@ -698,10 +698,10 @@ namespace PhysX AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree); - ValidateMaterialSurfaces(); + ValidateAssetMaterials(); } - void EditorColliderComponent::ValidateMaterialSurfaces() + void EditorColliderComponent::ValidateAssetMaterials() { const AZ::Data::Asset& physicsAsset = m_shapeConfiguration.m_physicsAsset.m_pxAsset; @@ -712,7 +712,7 @@ namespace PhysX // Here we check the material indices assigned to every shape and validate that every index is used at least once. // It's not an error if the validation fails here but something we want to let the designers know about. - [[maybe_unused]] size_t surfacesNum = physicsAsset->m_assetData.m_surfaceNames.size(); + [[maybe_unused]] size_t materialsNum = physicsAsset->m_assetData.m_materialNames.size(); const AZStd::vector& indexPerShape = physicsAsset->m_assetData.m_materialIndexPerShape; AZStd::unordered_set usedIndices; @@ -728,10 +728,10 @@ namespace PhysX usedIndices.insert(index); } - AZ_Warning("PhysX", usedIndices.size() == surfacesNum, - "EditorColliderComponent::ValidateMaterialSurfaces. Entity: %s. Number of surfaces used by the shape (%d) does not match the " - "total number of surfaces in the asset (%d). Please check that there are no convex meshes with per-face materials. Asset: %s", - GetEntity()->GetName().c_str(), usedIndices.size(), surfacesNum, physicsAsset.GetHint().c_str()) + AZ_Warning("PhysX", usedIndices.size() == materialsNum, + "EditorColliderComponent::ValidateMaterialSurfaces. Entity: %s. Number of materials used by the shape (%d) does not match the " + "total number of materials in the asset (%d). Please check that there are no convex meshes with per-face materials. Asset: %s", + GetEntity()->GetName().c_str(), usedIndices.size(), materialsNum, physicsAsset.GetHint().c_str()) } void EditorColliderComponent::OnAssetReady(AZ::Data::Asset asset) diff --git a/Gems/PhysX/Code/Source/EditorColliderComponent.h b/Gems/PhysX/Code/Source/EditorColliderComponent.h index 07e1131ea9..603e0bf0b3 100644 --- a/Gems/PhysX/Code/Source/EditorColliderComponent.h +++ b/Gems/PhysX/Code/Source/EditorColliderComponent.h @@ -244,7 +244,7 @@ namespace PhysX AZ::Data::AssetId FindMatchingPhysicsAsset(const AZ::Data::Asset& renderMeshAsset, const AZStd::vector& physicsAssets); - void ValidateMaterialSurfaces(); + void ValidateAssetMaterials(); void InitEventHandlers(); DebugDraw::Collider m_colliderDebugDraw; diff --git a/Gems/PhysX/Code/Source/Material.cpp b/Gems/PhysX/Code/Source/Material.cpp index 5e8e3bf759..45a7d64c55 100644 --- a/Gems/PhysX/Code/Source/Material.cpp +++ b/Gems/PhysX/Code/Source/Material.cpp @@ -410,7 +410,7 @@ namespace PhysX } // Set the slots from the mesh asset - materialSelection.SetMaterialSlots(meshAsset->m_assetData.m_surfaceNames); + materialSelection.SetMaterialSlots(meshAsset->m_assetData.m_materialNames); if (!assetConfiguration.m_useMaterialsFromAsset) { @@ -419,12 +419,14 @@ namespace PhysX } // Update material IDs in the selection for each slot - const AZStd::vector& meshMaterialNames = meshAsset->m_assetData.m_materialNames; - for (size_t slotIndex = 0; slotIndex < meshMaterialNames.size(); ++slotIndex) + const AZStd::vector& physicsMaterialNames = meshAsset->m_assetData.m_physicsMaterialNames; + for (size_t slotIndex = 0; slotIndex < physicsMaterialNames.size(); ++slotIndex) { - const AZStd::string& physicsMaterialNameFromPhysicsAsset = meshMaterialNames[slotIndex]; - if (physicsMaterialNameFromPhysicsAsset == DefaultPhysicsMaterialNameFromPhysicsAsset) + const AZStd::string& physicsMaterialNameFromPhysicsAsset = physicsMaterialNames[slotIndex]; + if (physicsMaterialNameFromPhysicsAsset.empty() || + physicsMaterialNameFromPhysicsAsset == Physics::DefaultPhysicsMaterialLabel) { + materialSelection.SetMaterialId(Physics::MaterialId(), slotIndex); continue; } @@ -436,9 +438,9 @@ namespace PhysX else { AZ_Warning("PhysX", false, - "UpdateMaterialSelectionFromPhysicsAsset: Physics material '%s' not found in the material library. Mesh surface '%s' will use the default material.", + "UpdateMaterialSelectionFromPhysicsAsset: Physics material '%s' not found in the material library. Mesh material '%s' will use the default physics material.", physicsMaterialNameFromPhysicsAsset.c_str(), - meshAsset->m_assetData.m_surfaceNames[slotIndex].c_str()); + meshAsset->m_assetData.m_materialNames[slotIndex].c_str()); } } } @@ -516,7 +518,7 @@ namespace PhysX auto it = AZStd::find_if(m_materials.begin(), m_materials.end(), [&materialName](const auto& data) { - return data.second->GetSurfaceTypeName() == materialName; + return AZ::StringFunc::Equal(data.second->GetSurfaceTypeName(), materialName, false/*bCaseSensitive*/); }); if (it != m_materials.end()) { diff --git a/Gems/PhysX/Code/Source/Material.h b/Gems/PhysX/Code/Source/Material.h index 1541d156d8..694c48ea7c 100644 --- a/Gems/PhysX/Code/Source/Material.h +++ b/Gems/PhysX/Code/Source/Material.h @@ -21,12 +21,6 @@ namespace PhysX { - /// Name used by physx asset exporter to indicate that the default - /// physics material should be used for a mesh surface. The exporter - /// will use it as the fallback option when it's not possible to obtain - /// the surface information from the mesh material. - static const char* const DefaultPhysicsMaterialNameFromPhysicsAsset = ""; - /// PhysX implementation of Physics::Material interface /// =================================================== /// diff --git a/Gems/PhysX/Code/Source/Pipeline/MeshAssetHandler.cpp b/Gems/PhysX/Code/Source/Pipeline/MeshAssetHandler.cpp index 430ef7aef3..24fcd9d5e7 100644 --- a/Gems/PhysX/Code/Source/Pipeline/MeshAssetHandler.cpp +++ b/Gems/PhysX/Code/Source/Pipeline/MeshAssetHandler.cpp @@ -151,8 +151,8 @@ namespace PhysX serializeContext->Class() ->Field("ColliderShapes", &MeshAssetData::m_colliderShapes) - ->Field("SurfaceNames", &MeshAssetData::m_surfaceNames) - ->Field("MaterialNames", &MeshAssetData::m_materialNames) + ->Field("SurfaceNames", &MeshAssetData::m_materialNames) + ->Field("MaterialNames", &MeshAssetData::m_physicsMaterialNames) ->Field("MaterialIndexPerShape", &MeshAssetData::m_materialIndexPerShape) ; } diff --git a/Gems/PhysX/Code/Source/Pipeline/MeshBehavior.cpp b/Gems/PhysX/Code/Source/Pipeline/MeshBehavior.cpp index ce46d72fb4..8762349ad1 100644 --- a/Gems/PhysX/Code/Source/Pipeline/MeshBehavior.cpp +++ b/Gems/PhysX/Code/Source/Pipeline/MeshBehavior.cpp @@ -97,6 +97,10 @@ namespace PhysX nodeSelectionList.AddSelectedNode(graph.GetNodeName(nodeIndex).GetPath()); } } + + // Update list of materials slots after the group's node selection list has been gathered + group->SetSceneGraph(&graph); + group->UpdateMaterialSlots(); } AZ::SceneAPI::Events::ProcessingResult MeshBehavior::UpdateManifest(AZ::SceneAPI::Containers::Scene& scene, ManifestAction action, @@ -129,6 +133,8 @@ namespace PhysX // in the same way again. To guarantee the same uuid, generate a stable one instead. group->OverrideId(AZ::SceneAPI::DataTypes::Utilities::CreateStableUuid(scene, MeshGroup::TYPEINFO_Uuid())); + group->SetSceneGraph(&scene.GetGraph()); + EBUS_EVENT(AZ::SceneAPI::Events::ManifestMetaInfoBus, InitializeObject, scene, *group); scene.GetManifest().AddEntry(AZStd::move(group)); @@ -149,10 +155,15 @@ namespace PhysX } AZ::SceneAPI::Utilities::SceneGraphSelector::UpdateNodeSelection(scene.GetGraph(), group.GetSceneNodeSelectionList()); + + // Update list of materials slots after the group's node selection list has been updated + group.SetSceneGraph(&scene.GetGraph()); + group.UpdateMaterialSlots(); + updated = true; } return updated ? AZ::SceneAPI::Events::ProcessingResult::Success : AZ::SceneAPI::Events::ProcessingResult::Ignored; } - } // namespace SceneAPI -} // namespace AZ + } // namespace Pipeline +} // namespace PhysX diff --git a/Gems/PhysX/Code/Source/Pipeline/MeshExporter.cpp b/Gems/PhysX/Code/Source/Pipeline/MeshExporter.cpp index 24e532e2d1..e968e2279a 100644 --- a/Gems/PhysX/Code/Source/Pipeline/MeshExporter.cpp +++ b/Gems/PhysX/Code/Source/Pipeline/MeshExporter.cpp @@ -68,16 +68,6 @@ namespace PhysX } } pxDefaultErrorCallback; - // A struct to store the asset-wide material names shared by multiple shapes - struct AssetMaterialsData - { - // Material names coming from FBX, these will be Mesh Surfaces in the Collider Component - AZStd::vector m_fbxMaterialNames; - - // Look-up table for fbxMaterialNames - AZStd::unordered_map m_materialIndexByName; - }; - // A struct to store the geometry data per FBX node struct NodeCollisionGeomExportData { @@ -153,7 +143,7 @@ namespace PhysX AZ::SerializeContext* serializeContext = azrtti_cast(context); if (serializeContext) { - serializeContext->Class()->Version(4); + serializeContext->Class()->Version(5); } } @@ -182,100 +172,49 @@ namespace PhysX return newIndex; } - // Building a map between FBX material name and the corresponding Cry surface type that is set in the .mtl file. - void BuildMaterialToSurfaceTypeMap(const AZStd::string& materialFilename, - AZStd::unordered_map& materialToSurfaceTypeMap) + bool UpdateAssetPhysicsMaterials( + const AZStd::vector& newMaterials, + AZStd::vector& materials, + AZStd::vector& physicsMaterials) { - AZ::IO::SystemFile mtlFile; - bool fileOpened = mtlFile.Open(materialFilename.c_str(), AZ::IO::SystemFile::SF_OPEN_READ_ONLY); - if (fileOpened && mtlFile.Length() != 0) + if (materials.size() != physicsMaterials.size()) { - //Read material override file into a buffer - AZStd::vector buffer(mtlFile.Length()); - mtlFile.Read(mtlFile.Length(), buffer.data()); - mtlFile.Close(); - - //Apparently in rapidxml if 'parse_no_data_nodes' isn't set it creates both value and data nodes - //with the data nodes having precedence such that updating values doesn't work. - AZ::rapidxml::xml_document document; - document.parse(buffer.data()); - - //Parse MTL file for materials and/or submaterials. - AZ::rapidxml::xml_node* rootMaterialNode = document.first_node(AZ::GFxFramework::MaterialExport::g_materialString); - - AZ::rapidxml::xml_node* subMaterialNode = rootMaterialNode->first_node(AZ::GFxFramework::MaterialExport::g_subMaterialString); - - if (subMaterialNode) - { - for (AZ::rapidxml::xml_node* materialNode = subMaterialNode->first_node(AZ::GFxFramework::MaterialExport::g_materialString); - materialNode; - materialNode = materialNode->next_sibling(AZ::GFxFramework::MaterialExport::g_materialString)) - { - AZ::rapidxml::xml_attribute* nameAttribute = materialNode->first_attribute(AZ::GFxFramework::MaterialExport::g_nameString); - if (nameAttribute) - { - AZStd::string materialName = nameAttribute->value(); - AZStd::string surfaceTypeName = DefaultPhysicsMaterialNameFromPhysicsAsset; - - AZ::rapidxml::xml_attribute* surfaceTypeNode = materialNode->first_attribute("SurfaceType"); - if (surfaceTypeNode && surfaceTypeNode->value_size() != 0) - { - surfaceTypeName = surfaceTypeNode->value(); - } - - materialToSurfaceTypeMap[materialName] = surfaceTypeName; - } - else - { - AZ_TracePrintf(AZ::SceneAPI::Utilities::ErrorWindow, "A SubMaterial without Name found in the .mtl file: %s", materialFilename.c_str()); - } - } - } - else - { - AZ_TracePrintf(AZ::SceneAPI::Utilities::ErrorWindow, "No SubMaterial node in the .mtl file: %s", materialFilename.c_str()); - } + AZ_TracePrintf( + AZ::SceneAPI::Utilities::WarningWindow, + "Materials and Physics Materials have different number of elements. %d materials and %d physics materials.", + materials.size(), physicsMaterials.size()); + return false; } - } - - void UpdateAssetMaterialsFromCrySurfaceTypes(const AZStd::vector& fbxMaterialNames, - const AZStd::unordered_map& materialToSurfaceTypeMap, - MeshAssetData& assetData) - { - AZStd::vector& materialNames = assetData.m_materialNames; - AZ_Assert(materialNames.empty(), - "UpdateAssetMaterialsFromCrySurfaceTypes: Mesh Asset Data should not have materials already assigned."); - materialNames.clear(); - materialNames.reserve(fbxMaterialNames.size()); + AZStd::vector newPhysicsMaterials; + newPhysicsMaterials.reserve(newMaterials.size()); - for (const AZStd::string& fbxMaterial : fbxMaterialNames) + // In the new material list, the materials might have changed slots. + // Form the new list of physics materials by looking at the previous list + // and keeping the same physics materials association when found. + for (const auto& newMaterial : newMaterials) { - AZStd::string materialName; + AZStd::string physicsMaterialName = Physics::DefaultPhysicsMaterialLabel; - // Here we assign the actual engine surface type based on the material name - auto materialToSurfaceIt = materialToSurfaceTypeMap.find(fbxMaterial); - if (materialToSurfaceIt != materialToSurfaceTypeMap.end() - && !materialToSurfaceIt->second.empty()) + for (size_t slotId = 0; slotId < materials.size(); ++slotId) { - materialName = materialToSurfaceIt->second; - - // Remove the mat_ prefix since the material library generated from surface types doesn't have it. - if (materialName.find("mat_") == 0) + if (AZ::StringFunc::Equal(materials[slotId], newMaterial, false/*bCaseSensitive*/)) { - materialName = materialName.substr(4); + if (!physicsMaterials[slotId].empty()) + { + physicsMaterialName = physicsMaterials[slotId]; + } + break; } } - else - { - materialName = DefaultPhysicsMaterialNameFromPhysicsAsset; - } - materialNames.emplace_back(AZStd::move(materialName)); + newPhysicsMaterials.emplace_back(AZStd::move(physicsMaterialName)); } - // Asset mesh surfaces match FBX materials. These are the names that users see in the Collider Component in the Editor. - assetData.m_surfaceNames = fbxMaterialNames; + materials = newMaterials; + physicsMaterials = AZStd::move(newPhysicsMaterials); + + return true; } bool ValidateCookedTriangleMesh(void* assetData, AZ::u32 assetDataSize) @@ -320,6 +259,86 @@ namespace PhysX return materialNames; } + + AZStd::optional GatherMaterialsFromMeshGroup( + const MeshGroup& meshGroup, + const AZ::SceneAPI::Containers::SceneGraph& sceneGraph) + { + AssetMaterialsData assetMaterialData; + + const auto& sceneNodeSelectionList = meshGroup.GetSceneNodeSelectionList(); + size_t selectedNodeCount = sceneNodeSelectionList.GetSelectedNodeCount(); + + for (size_t index = 0; index < selectedNodeCount; index++) + { + AZ::SceneAPI::Containers::SceneGraph::NodeIndex nodeIndex = sceneGraph.Find(sceneNodeSelectionList.GetSelectedNode(index)); + if (!nodeIndex.IsValid()) + { + AZ_TracePrintf( + AZ::SceneAPI::Utilities::WarningWindow, + "Node '%s' was not found in the scene graph.", + sceneNodeSelectionList.GetSelectedNode(index).c_str() + ); + continue; + } + auto nodeMesh = azrtti_cast(*sceneGraph.ConvertToStorageIterator(nodeIndex)); + if (!nodeMesh) + { + continue; + } + + AZStd::string_view nodeName = sceneGraph.GetNodeName(nodeIndex).GetName(); + + const AZStd::vector localFbxMaterialsList = GenerateLocalNodeMaterialMap(sceneGraph, nodeIndex); + if (localFbxMaterialsList.empty()) + { + AZ_TracePrintf( + AZ::SceneAPI::Utilities::WarningWindow, + "Node '%.*s' does not have any material assigned to it. Material '%s' will be used.", + nodeName.size(), nodeName, DefaultMaterialName + ); + } + + const AZ::u32 faceCount = nodeMesh->GetFaceCount(); + + assetMaterialData.m_nodesToPerFaceMaterialIndices.emplace(nodeName, AZStd::vector(faceCount)); + + // Convex and primitive methods can only have 1 material + const bool limitToOneMaterial = meshGroup.GetExportAsConvex() || meshGroup.GetExportAsPrimitive(); + + for (AZ::u32 faceIndex = 0; faceIndex < faceCount; ++faceIndex) + { + AZStd::string materialName = DefaultMaterialName; + if (!localFbxMaterialsList.empty()) + { + int materialId = nodeMesh->GetFaceMaterialId(faceIndex); + if (materialId >= localFbxMaterialsList.size()) + { + AZ_TracePrintf(AZ::SceneAPI::Utilities::ErrorWindow, + "materialId %d for face %d is out of bound for localFbxMaterialsList (size %d).", + materialId, faceIndex, localFbxMaterialsList.size()); + + return AZStd::nullopt; + } + + materialName = localFbxMaterialsList[materialId]; + + // Keep using the first material when it has to be limited to one. + if (limitToOneMaterial && + assetMaterialData.m_fbxMaterialNames.size() == 1 && + assetMaterialData.m_fbxMaterialNames[0] != materialName) + { + materialName = assetMaterialData.m_fbxMaterialNames[0]; + } + } + + AZ::u16 materialIndex = InsertMaterialIndexByName(materialName, assetMaterialData); + assetMaterialData.m_nodesToPerFaceMaterialIndices[nodeName][faceIndex] = materialIndex; + } + } + + return assetMaterialData; + } } static physx::PxMeshMidPhase::Enum GetMidPhaseStructureType(const AZStd::string& platformIdentifier) @@ -468,21 +487,11 @@ namespace PhysX return cookingSuccessful; } - // Utility function finding out the .mtl file for a given FBX (at the moment it's the same name as FBX but with .mtl extension) - static AZStd::string GetAssetMaterialFilename(const AZ::SceneAPI::Events::ExportEventContext& context) - { - const AZ::SceneAPI::Containers::Scene& scene = context.GetScene(); - - AZStd::string materialFilename = scene.GetSourceFilename(); - AzFramework::StringFunc::Path::ReplaceExtension(materialFilename, ".mtl"); - return materialFilename; - } - // Processes the collected data and writes into a file static AZ::SceneAPI::Events::ProcessingResult WritePxMeshAsset( AZ::SceneAPI::Events::ExportEventContext& context, const AZStd::vector& totalExportData, - const AssetMaterialsData &assetMaterialsData, + const Utils::AssetMaterialsData &assetMaterialsData, const MeshGroup& meshGroup) { SceneEvents::ProcessingResult result = SceneEvents::ProcessingResult::Ignored; @@ -492,14 +501,18 @@ namespace PhysX MeshAssetData assetData; - const AZStd::string& materialFilename = GetAssetMaterialFilename(context); - - // Read the information about surface type for each material from the .mtl file - AZStd::unordered_map fbxMaterialToCrySurfaceTypeMap; - Utils::BuildMaterialToSurfaceTypeMap(materialFilename, fbxMaterialToCrySurfaceTypeMap); - // Assign the materials into cooked data - Utils::UpdateAssetMaterialsFromCrySurfaceTypes(assetMaterialsData.m_fbxMaterialNames, fbxMaterialToCrySurfaceTypeMap, assetData); + assetData.m_materialNames = meshGroup.GetMaterialSlots(); + assetData.m_physicsMaterialNames = meshGroup.GetPhysicsMaterials(); + + // Updating materials lists from new materials gathered from fbx + // because this exporter runs when the FBX is being processed, which + // could have a different content from when the mesh group info was + // entered in FBX Settings Editor. + if (!Utils::UpdateAssetPhysicsMaterials(assetMaterialsData.m_fbxMaterialNames, assetData.m_materialNames, assetData.m_physicsMaterialNames)) + { + return SceneEvents::ProcessingResult::Failure; + } for (const NodeCollisionGeomExportData& subMesh : totalExportData) { @@ -714,9 +727,15 @@ namespace PhysX for (const MeshGroup& pxMeshGroup : view) { + // Gather material data from asset for the mesh group + AZStd::optional assetMaterialData = Utils::GatherMaterialsFromMeshGroup(pxMeshGroup, graph); + if (!assetMaterialData) + { + return SceneEvents::ProcessingResult::Failure; + } + // Export data per node AZStd::vector totalExportData; - AssetMaterialsData assetMaterialData; const AZStd::string& groupName = pxMeshGroup.GetName(); @@ -764,7 +783,6 @@ namespace PhysX const AZ::SceneAPI::Containers::SceneGraph::Name& nodeName = graph.GetNodeName(nodeIndex); - const AZStd::vector localFbxMaterialsList = Utils::GenerateLocalNodeMaterialMap(graph, nodeIndex); const AZ::SceneAPI::DataTypes::MatrixType worldTransform = SceneUtil::BuildWorldTransform(graph, nodeIndex); NodeCollisionGeomExportData nodeExportData; @@ -783,53 +801,24 @@ namespace PhysX } nodeExportData.m_indices.resize(faceCount * 3); - nodeExportData.m_perFaceMaterialIndices.resize(faceCount); - if (localFbxMaterialsList.empty()) + nodeExportData.m_perFaceMaterialIndices = assetMaterialData->m_nodesToPerFaceMaterialIndices[nodeExportData.m_nodeName]; + if (nodeExportData.m_perFaceMaterialIndices.size() != faceCount) { AZ_TracePrintf( AZ::SceneAPI::Utilities::WarningWindow, - "Node '%s' does not have any material assigned to it. Material '%s' will be used.", - nodeExportData.m_nodeName.c_str(), DefaultMaterialName + "Node '%s' material information face count %d does not match the node's %d.", + nodeExportData.m_nodeName.c_str(), nodeExportData.m_perFaceMaterialIndices.size(), faceCount ); + return SceneEvents::ProcessingResult::Failure; } - // Convex and primitive methods can only have 1 material - const bool limitToOneMaterial = pxMeshGroup.GetExportAsConvex() || pxMeshGroup.GetExportAsPrimitive(); - for (AZ::u32 faceIndex = 0; faceIndex < faceCount; ++faceIndex) { - AZStd::string materialName = DefaultMaterialName; - if (!localFbxMaterialsList.empty()) - { - int materialId = nodeMesh->GetFaceMaterialId(faceIndex); - if (materialId >= localFbxMaterialsList.size()) - { - AZ_TracePrintf(AZ::SceneAPI::Utilities::ErrorWindow, - "materialId %d for face %d is out of bound for localFbxMaterialsList (size %d).", - materialId, faceIndex, localFbxMaterialsList.size()); - - return SceneEvents::ProcessingResult::Failure; - } - - materialName = localFbxMaterialsList[materialId]; - - // Keep using the first material when it has to be limited to one. - if (limitToOneMaterial && - assetMaterialData.m_fbxMaterialNames.size() == 1 && - assetMaterialData.m_fbxMaterialNames[0] != materialName) - { - materialName = assetMaterialData.m_fbxMaterialNames[0]; - } - } - const AZ::SceneAPI::DataTypes::IMeshData::Face& face = nodeMesh->GetFaceInfo(faceIndex); nodeExportData.m_indices[faceIndex * 3] = face.vertexIndex[0]; nodeExportData.m_indices[faceIndex * 3 + 1] = face.vertexIndex[1]; nodeExportData.m_indices[faceIndex * 3 + 2] = face.vertexIndex[2]; - - AZ::u16 materialIndex = Utils::InsertMaterialIndexByName(materialName, assetMaterialData); - nodeExportData.m_perFaceMaterialIndices[faceIndex] = materialIndex; } if (pxMeshGroup.GetDecomposeMeshes()) @@ -880,7 +869,7 @@ namespace PhysX if (!totalExportData.empty()) { - result += WritePxMeshAsset(context, totalExportData, assetMaterialData, pxMeshGroup); + result += WritePxMeshAsset(context, totalExportData, *assetMaterialData, pxMeshGroup); } } diff --git a/Gems/PhysX/Code/Source/Pipeline/MeshExporter.h b/Gems/PhysX/Code/Source/Pipeline/MeshExporter.h index ef0e58cecb..0593b27301 100644 --- a/Gems/PhysX/Code/Source/Pipeline/MeshExporter.h +++ b/Gems/PhysX/Code/Source/Pipeline/MeshExporter.h @@ -26,6 +26,7 @@ namespace AZ namespace Containers { class Scene; + class SceneGraph; } namespace DataTypes @@ -57,5 +58,34 @@ namespace PhysX private: AZ::SceneAPI::Events::ProcessingResult ExportMeshObject(AZ::SceneAPI::Events::ExportEventContext& context, const AZStd::shared_ptr& meshToExport, const AZStd::string& nodePath, const Pipeline::MeshGroup& pxMeshGroup) const; }; - } -} + + namespace Utils + { + //! A struct to store the materials of the mesh nodes selected in a mesh group. + struct AssetMaterialsData + { + //! Material names coming from FBX. + AZStd::vector m_fbxMaterialNames; + + //! Look-up table for fbxMaterialNames. + AZStd::unordered_map m_materialIndexByName; + + //! Map of mesh nodes to their list of material indices associated to each face. + AZStd::unordered_map> m_nodesToPerFaceMaterialIndices; + }; + + //! Returns the list of materials assigned to the triangles + //! of the mesh nodes selected in a mesh group. + AZStd::optional GatherMaterialsFromMeshGroup( + const MeshGroup& meshGroup, + const AZ::SceneAPI::Containers::SceneGraph& sceneGraph); + + //! Function to update a list of materials and physics materials from a new list. + //! All those new materials not found in the previous list will fallback to default physics material. + bool UpdateAssetPhysicsMaterials( + const AZStd::vector& newMaterials, + AZStd::vector& materials, + AZStd::vector& physicsMaterials); + } // namespace Utils + } // namespace Pipeline +} // namespace PhysX diff --git a/Gems/PhysX/Code/Source/Pipeline/MeshGroup.cpp b/Gems/PhysX/Code/Source/Pipeline/MeshGroup.cpp index db6e7e12e0..4789377852 100644 --- a/Gems/PhysX/Code/Source/Pipeline/MeshGroup.cpp +++ b/Gems/PhysX/Code/Source/Pipeline/MeshGroup.cpp @@ -20,8 +20,11 @@ #include #include #include +#include #include +#include +#include #include @@ -602,6 +605,8 @@ namespace PhysX ->Field("PrimitiveAssetParams", &MeshGroup::m_primitiveAssetParams) ->Field("DecomposeMeshes", &MeshGroup::m_decomposeMeshes) ->Field("ConvexDecompositionParams", &MeshGroup::m_convexDecompositionParams) + ->Field("MaterialSlots", &MeshGroup::m_materialSlots) + ->Field("PhysicsMaterials", &MeshGroup::m_physicsMaterials) ->Field("rules", &MeshGroup::m_rules); if ( @@ -622,6 +627,7 @@ namespace PhysX "Select the meshes to be included in the mesh group.") ->Attribute("FilterName", "meshes") ->Attribute("FilterType", AZ::SceneAPI::DataTypes::IMeshData::TYPEINFO_Uuid()) + ->Attribute(AZ::Edit::Attributes::ChangeNotify, &MeshGroup::OnNodeSelectionChanged) ->DataElement(AZ::Edit::UIHandlers::ComboBox, &MeshGroup::m_exportMethod, "Export As", "The cooking method to be applied to this mesh group. For the asset to be usable as " @@ -629,14 +635,14 @@ namespace PhysX ->EnumAttribute(MeshExportMethod::TriMesh, "Triangle Mesh") ->EnumAttribute(MeshExportMethod::Convex, "Convex") ->EnumAttribute(MeshExportMethod::Primitive, "Primitive") - ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) + ->Attribute(AZ::Edit::Attributes::ChangeNotify, &MeshGroup::OnExportMethodChanged) ->DataElement(AZ_CRC("DecomposeMeshes", 0xe0e2ac1e), &MeshGroup::m_decomposeMeshes, "Decompose Meshes", "If enables, this option will apply the V-HACD algorithm to split each node " "into approximately convex parts. Each part will individually be exported as a convex " "collider using the parameters configured above.") ->Attribute(AZ::Edit::Attributes::Visibility, &MeshGroup::GetDecomposeMeshesVisibility) - ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) + ->Attribute(AZ::Edit::Attributes::ChangeNotify, &MeshGroup::OnDecomposeMeshesChanged) ->DataElement(AZ_CRC("TriangleMeshAssetParams", 0x1a408def), &MeshGroup::m_triangleMeshAssetParams, "Triangle Mesh Asset Parameters", "Configure the parameters controlling the exported triangle mesh asset.") @@ -658,6 +664,12 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::Visibility, &MeshGroup::GetDecomposeMeshes) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ->DataElement(AZ::Edit::UIHandlers::Default, &MeshGroup::m_physicsMaterials, "Physics Materials", + "Configure which physics materials to use for each element.") + ->Attribute(AZ::Edit::Attributes::IndexedChildNameLabelOverride, &MeshGroup::GetMaterialSlotLabel) + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ->Attribute(AZ::Edit::Attributes::ContainerCanBeModified, false) + ->DataElement(AZ::Edit::UIHandlers::Default, &MeshGroup::m_rules, "", "Add or remove rules to fine-tune the export process.") ->Attribute(AZ::Edit::Attributes::Visibility, AZ_CRC("PropertyVisibility_ShowChildrenOnly", 0xef428f20)); @@ -710,6 +722,37 @@ namespace PhysX return (GetExportAsConvex() || GetExportAsPrimitive()) && m_decomposeMeshes; } + const AZStd::vector& MeshGroup::GetPhysicsMaterials() const + { + return m_physicsMaterials; + } + + const AZStd::vector& MeshGroup::GetMaterialSlots() const + { + return m_materialSlots; + } + + void MeshGroup::SetSceneGraph(const AZ::SceneAPI::Containers::SceneGraph* graph) + { + m_graph = graph; + } + + void MeshGroup::UpdateMaterialSlots() + { + if (!m_graph) + { + return; + } + + AZStd::optional assetMaterialData = Utils::GatherMaterialsFromMeshGroup(*this, *m_graph); + if (!assetMaterialData) + { + return; + } + + Utils::UpdateAssetPhysicsMaterials(assetMaterialData->m_fbxMaterialNames, m_materialSlots, m_physicsMaterials); + } + AZ::SceneAPI::Containers::RuleContainer& MeshGroup::GetRuleContainer() { return m_rules; @@ -770,11 +813,50 @@ namespace PhysX return m_convexDecompositionParams; } + AZ::u32 MeshGroup::OnNodeSelectionChanged() + { + UpdateMaterialSlots(); + return AZ::Edit::PropertyRefreshLevels::EntireTree; + } + + AZ::u32 MeshGroup::OnExportMethodChanged() + { + UpdateMaterialSlots(); + return AZ::Edit::PropertyRefreshLevels::EntireTree; + } + + AZ::u32 MeshGroup::OnDecomposeMeshesChanged() + { + UpdateMaterialSlots(); + return AZ::Edit::PropertyRefreshLevels::EntireTree; + } + bool MeshGroup::GetDecomposeMeshesVisibility() const { return GetExportAsConvex() || GetExportAsPrimitive(); } + AZStd::string MeshGroup::GetMaterialSlotLabel(int index) const + { + if (index < m_materialSlots.size()) + { + // When limited to one material, clarify in the label the material + // will be used for the entire object. + if (index == 0 && (GetExportAsConvex() || GetExportAsPrimitive())) + { + return m_materialSlots[index] + " (entire object)"; + } + else + { + return m_materialSlots[index]; + } + } + else + { + return ""; + } + } + bool MeshGroup::VersionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement) { // Remove the material rule. diff --git a/Gems/PhysX/Code/Source/Pipeline/MeshGroup.h b/Gems/PhysX/Code/Source/Pipeline/MeshGroup.h index 0095a3dce2..a2c270234a 100644 --- a/Gems/PhysX/Code/Source/Pipeline/MeshGroup.h +++ b/Gems/PhysX/Code/Source/Pipeline/MeshGroup.h @@ -23,6 +23,11 @@ namespace AZ { class ReflectContext; + + namespace SceneAPI::Containers + { + class SceneGraph; + } } namespace PhysX @@ -185,6 +190,11 @@ namespace PhysX bool GetExportAsTriMesh() const; bool GetExportAsPrimitive() const; bool GetDecomposeMeshes() const; + const AZStd::vector& GetPhysicsMaterials() const; + const AZStd::vector& GetMaterialSlots() const; + + void SetSceneGraph(const AZ::SceneAPI::Containers::SceneGraph* graph); + void UpdateMaterialSlots(); AZ::SceneAPI::Containers::RuleContainer& GetRuleContainer() override; const AZ::SceneAPI::Containers::RuleContainer& GetRuleContainerConst() const override; @@ -207,8 +217,14 @@ namespace PhysX protected: static bool VersionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement); + AZ::u32 OnNodeSelectionChanged(); + AZ::u32 OnExportMethodChanged(); + AZ::u32 OnDecomposeMeshesChanged(); + bool GetDecomposeMeshesVisibility() const; + AZStd::string GetMaterialSlotLabel(int index) const; + AZ::Uuid m_id{}; AZStd::string m_name{}; AZ::SceneAPI::SceneData::SceneNodeSelectionList m_nodeSelectionList{}; @@ -219,6 +235,10 @@ namespace PhysX PrimitiveAssetParams m_primitiveAssetParams{}; ConvexDecompositionParams m_convexDecompositionParams{}; AZ::SceneAPI::Containers::RuleContainer m_rules{}; + AZStd::vector m_materialSlots; + AZStd::vector m_physicsMaterials; + + const AZ::SceneAPI::Containers::SceneGraph* m_graph = nullptr; }; } } From 2ede3c3dc33ab996b904da1c95489c5191bb4258 Mon Sep 17 00:00:00 2001 From: amzn-sean <75276488+amzn-sean@users.noreply.github.com> Date: Thu, 10 Jun 2021 15:56:48 +0100 Subject: [PATCH 37/73] fixed raycast multi SC node to return more then 1 result (#1238) --- Gems/ScriptCanvasPhysics/Code/Source/WorldNodes.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Gems/ScriptCanvasPhysics/Code/Source/WorldNodes.h b/Gems/ScriptCanvasPhysics/Code/Source/WorldNodes.h index 5238c52e0e..14f03aa7c4 100644 --- a/Gems/ScriptCanvasPhysics/Code/Source/WorldNodes.h +++ b/Gems/ScriptCanvasPhysics/Code/Source/WorldNodes.h @@ -165,6 +165,7 @@ namespace ScriptCanvasPhysics request.m_start = worldSpaceTransform.GetTranslation(); request.m_direction = worldSpaceTransform.TransformVector(direction.GetNormalized()); request.m_distance = distance; + request.m_reportMultipleHits = true; request.m_filterCallback = [ignore](const AzPhysics::SimulatedBody* body, [[maybe_unused]] const Physics::Shape* shape) { return body->GetEntityId() != ignore ? AzPhysics::SceneQuery::QueryHitType::Touch : AzPhysics::SceneQuery::QueryHitType::None; From 7a053d82e18e78940ab5cb8ade765c0862ebf2bb Mon Sep 17 00:00:00 2001 From: Aaron Ruiz Mora Date: Thu, 10 Jun 2021 16:36:38 +0100 Subject: [PATCH 38/73] UX Workflow improvements for Physics Materials (#1237) - Added button to PhysX Collider Component in PhysX Mesh's field to open FBX Settings. - Added button Material Selection to open the physics material library in Asset Editor. - Default Material in PhysX configuration is read only and consistent with the text in combo boxes. - Material configuration field "Surface Type" renamed to "Name" - Fixed bug in EditorColliderComponent where the material selection was not updated when changing the library. - Fixed bug where the materials selection was not set to default when a physics material from the asset was not found in the library. - Added attributes 'BrowseButtonEnabled' and 'BrowseButtonVisible' to PropertyAssetCtrl. - Updated physx configuration setreg files of AutomatedTesting project. --- ...4_Collider_CollisionGroups.setreg_override | 3 -- ...9_Material_DynamicFriction.setreg_override | 3 -- ...C4976227_Collider_NewGroup.setreg_override | 3 -- ...ameGroupSameLayerCollision.setreg_override | 3 -- ...ollider_CollisionLayerTest.setreg_override | 3 -- ...ysXCollider_CollisionLayer.setreg_override | 3 -- .../Registry/physxsystemconfiguration.setreg | 3 -- .../Configuration/SystemConfiguration.h | 2 +- .../AzFramework/Physics/Material.cpp | 32 ++++++++++++++++--- .../AzFramework/Physics/Material.h | 28 ++++++++++++++-- .../AzFramework/AzFramework/Physics/Shape.cpp | 2 +- .../AzFramework/AzFramework/Physics/Utils.cpp | 1 + .../UI/PropertyEditor/PropertyAssetCtrl.cpp | 26 +++++++++++++++ .../UI/PropertyEditor/PropertyAssetCtrl.hxx | 2 ++ .../Code/Editor/ConfigStringLineEditCtrl.cpp | 8 +++++ Gems/PhysX/Code/Include/PhysX/MeshAsset.h | 2 ++ .../Code/Source/EditorColliderComponent.cpp | 7 ++-- Gems/PhysX/Code/Source/Material.cpp | 1 + .../Code/Source/Pipeline/MeshAssetHandler.cpp | 22 +++++++++++++ .../Code/Source/Pipeline/MeshExporter.cpp | 6 ++-- Gems/PhysX/Code/Source/SystemComponent.cpp | 2 +- .../PhysX/Code/Tests/PhysXSceneQueryTests.cpp | 2 +- 22 files changed, 127 insertions(+), 37 deletions(-) diff --git a/AutomatedTesting/Registry/C3510644_Collider_CollisionGroups.setreg_override b/AutomatedTesting/Registry/C3510644_Collider_CollisionGroups.setreg_override index 696a0a74da..9fa5e26768 100644 --- a/AutomatedTesting/Registry/C3510644_Collider_CollisionGroups.setreg_override +++ b/AutomatedTesting/Registry/C3510644_Collider_CollisionGroups.setreg_override @@ -119,9 +119,6 @@ ] } }, - "DefaultMaterial": { - "SurfaceType": "Default_1" - }, "MaterialLibrary": { "assetId": { "guid": "{3A055A3F-8CB7-5FEE-B437-EB365FACD0D4}" diff --git a/AutomatedTesting/Registry/C4044459_Material_DynamicFriction.setreg_override b/AutomatedTesting/Registry/C4044459_Material_DynamicFriction.setreg_override index c53b04e5c2..88a7b5c309 100644 --- a/AutomatedTesting/Registry/C4044459_Material_DynamicFriction.setreg_override +++ b/AutomatedTesting/Registry/C4044459_Material_DynamicFriction.setreg_override @@ -101,9 +101,6 @@ ] } }, - "DefaultMaterial": { - "SurfaceType": "Default_1" - }, "MaterialLibrary": { "assetId": { "guid": "{6AA79EE4-7EC3-5717-87AE-EDD7D886FD7F}" diff --git a/AutomatedTesting/Registry/C4976227_Collider_NewGroup.setreg_override b/AutomatedTesting/Registry/C4976227_Collider_NewGroup.setreg_override index 5e98e08ede..afbe6a9d38 100644 --- a/AutomatedTesting/Registry/C4976227_Collider_NewGroup.setreg_override +++ b/AutomatedTesting/Registry/C4976227_Collider_NewGroup.setreg_override @@ -107,9 +107,6 @@ ] } }, - "DefaultMaterial": { - "SurfaceType": "Default_1" - }, "MaterialLibrary": { "assetId": { "guid": "{3A055A3F-8CB7-5FEE-B437-EB365FACD0D4}" diff --git a/AutomatedTesting/Registry/C4976244_Collider_SameGroupSameLayerCollision.setreg_override b/AutomatedTesting/Registry/C4976244_Collider_SameGroupSameLayerCollision.setreg_override index 696a0a74da..9fa5e26768 100644 --- a/AutomatedTesting/Registry/C4976244_Collider_SameGroupSameLayerCollision.setreg_override +++ b/AutomatedTesting/Registry/C4976244_Collider_SameGroupSameLayerCollision.setreg_override @@ -119,9 +119,6 @@ ] } }, - "DefaultMaterial": { - "SurfaceType": "Default_1" - }, "MaterialLibrary": { "assetId": { "guid": "{3A055A3F-8CB7-5FEE-B437-EB365FACD0D4}" diff --git a/AutomatedTesting/Registry/C4976245_PhysXCollider_CollisionLayerTest.setreg_override b/AutomatedTesting/Registry/C4976245_PhysXCollider_CollisionLayerTest.setreg_override index 696a0a74da..9fa5e26768 100644 --- a/AutomatedTesting/Registry/C4976245_PhysXCollider_CollisionLayerTest.setreg_override +++ b/AutomatedTesting/Registry/C4976245_PhysXCollider_CollisionLayerTest.setreg_override @@ -119,9 +119,6 @@ ] } }, - "DefaultMaterial": { - "SurfaceType": "Default_1" - }, "MaterialLibrary": { "assetId": { "guid": "{3A055A3F-8CB7-5FEE-B437-EB365FACD0D4}" diff --git a/AutomatedTesting/Registry/C4982593_PhysXCollider_CollisionLayer.setreg_override b/AutomatedTesting/Registry/C4982593_PhysXCollider_CollisionLayer.setreg_override index 696a0a74da..9fa5e26768 100644 --- a/AutomatedTesting/Registry/C4982593_PhysXCollider_CollisionLayer.setreg_override +++ b/AutomatedTesting/Registry/C4982593_PhysXCollider_CollisionLayer.setreg_override @@ -119,9 +119,6 @@ ] } }, - "DefaultMaterial": { - "SurfaceType": "Default_1" - }, "MaterialLibrary": { "assetId": { "guid": "{3A055A3F-8CB7-5FEE-B437-EB365FACD0D4}" diff --git a/AutomatedTesting/Registry/physxsystemconfiguration.setreg b/AutomatedTesting/Registry/physxsystemconfiguration.setreg index 30e9dced44..02f65b685b 100644 --- a/AutomatedTesting/Registry/physxsystemconfiguration.setreg +++ b/AutomatedTesting/Registry/physxsystemconfiguration.setreg @@ -101,9 +101,6 @@ ] } }, - "DefaultMaterial": { - "SurfaceType": "Default_1" - }, "MaterialLibrary": { "assetId": { "guid": "{3A055A3F-8CB7-5FEE-B437-EB365FACD0D4}" diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/SystemConfiguration.h b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/SystemConfiguration.h index 56fe9a68c4..6119a6f630 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/SystemConfiguration.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/SystemConfiguration.h @@ -46,7 +46,7 @@ namespace AzPhysics //! Each Physics Scene uses this as a base and will override as needed. CollisionConfiguration m_collisionConfig; - Physics::MaterialConfiguration m_defaultMaterialConfiguration; //!< Default material parameters for the project. + Physics::DefaultMaterialConfiguration m_defaultMaterialConfiguration; //!< Default material parameters for the project. AZ::Data::Asset m_materialLibraryAsset = AZ::Data::AssetLoadBehavior::NoLoad; //!< Material Library exposed by the system component SystemBus API. //! Controls whether the Physics System will self register to the TickBus and call StartSimulation / FinishSimulation on each Scene. diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp index 4afbbaa4dc..d84d2739d0 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp @@ -83,14 +83,12 @@ namespace Physics AZ::EditContext* editContext = serializeContext->GetEditContext(); if (editContext) { - AZStd::unordered_set forbiddenSurfaceTypeNames; - forbiddenSurfaceTypeNames.insert("Default"); editContext->Class("", "") ->ClassElement(AZ::Edit::ClassElements::EditorData, "Physics Material") - ->DataElement(MaterialConfiguration::s_configLineEdit, &MaterialConfiguration::m_surfaceType, "Surface type", "Game surface type") // Uses ConfigStringLineEditCtrl in PhysX gem. + ->DataElement(MaterialConfiguration::s_configLineEdit, &MaterialConfiguration::m_surfaceType, "Name", "Name of the physics material") // Uses ConfigStringLineEditCtrl in PhysX gem. ->Attribute(AZ::Edit::Attributes::MaxLength, 64) + ->Attribute(AZ::Edit::Attributes::ReadOnly, &MaterialConfiguration::IsNameReadOnly) ->Attribute(MaterialConfiguration::s_stringGroup, AZ_CRC("LineEditGroupSurfaceType", 0x6670659e)) - ->Attribute(MaterialConfiguration::s_forbiddenStringSet, forbiddenSurfaceTypeNames) ->DataElement(AZ::Edit::UIHandlers::Default, &MaterialConfiguration::m_staticFriction, "Static friction", "Friction coefficient when object is still") ->Attribute(AZ::Edit::Attributes::Min, 0.f) ->DataElement(AZ::Edit::UIHandlers::Default, &MaterialConfiguration::m_dynamicFriction, "Dynamic friction", "Friction coefficient when object is moving") @@ -178,6 +176,23 @@ namespace Physics ////////////////////////////////////////////////////////////////////////// + DefaultMaterialConfiguration::DefaultMaterialConfiguration() + { + m_surfaceType = Physics::DefaultPhysicsMaterialLabel; + } + + void DefaultMaterialConfiguration::Reflect(AZ::ReflectContext* context) + { + if (auto* serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(1) + ; + } + } + + ////////////////////////////////////////////////////////////////////////// + void MaterialLibraryAsset::Reflect(AZ::ReflectContext * context) { AZ::SerializeContext* serializeContext = azrtti_cast(context); @@ -212,7 +227,7 @@ namespace Physics if (serializeContext) { serializeContext->Class() - ->Version(1) + ->Version(2) ->Field("DefaultMaterial", &MaterialInfoReflectionWrapper::m_defaultMaterialConfiguration) ->Field("Asset", &MaterialInfoReflectionWrapper::m_materialLibraryAsset) ; @@ -372,6 +387,7 @@ namespace Physics serializeContext->Class() ->Version(3, &ClassConverters::MaterialSelectionConverter) ->EventHandler() + ->Field("EditContextMaterialLibrary", &MaterialSelection::m_editContextMaterialLibrary) ->Field("MaterialIds", &MaterialSelection::m_materialIdsAssignedToSlots) ; @@ -380,6 +396,12 @@ namespace Physics editContext->Class("Physics Materials", "Select which physics materials to use for each element of this object") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ->DataElement(AZ::Edit::UIHandlers::Default, &MaterialSelection::m_editContextMaterialLibrary, "Library", "Physics material library from PhysX Configuration") + ->Attribute(AZ::Edit::Attributes::ContainerCanBeModified, false) + ->Attribute(AZ_CRC_CE("BrowseButtonEnabled"), false) + ->Attribute(AZ_CRC_CE("EditButton"), "") + ->Attribute(AZ_CRC_CE("EditDescription"), "Open in Asset Editor") + ->Attribute(AZ::Edit::Attributes::DefaultAsset, &MaterialSelection::GetMaterialLibraryId) ->DataElement(AZ::Edit::UIHandlers::Default, &MaterialSelection::m_materialIdsAssignedToSlots, "", "") ->ElementAttribute(Attributes::MaterialLibraryAssetId, &MaterialSelection::GetMaterialLibraryId) ->Attribute(AZ::Edit::Attributes::IndexedChildNameLabelOverride, &MaterialSelection::GetMaterialSlotLabel) diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Material.h b/Code/Framework/AzFramework/AzFramework/Physics/Material.h index 067f7abe07..1e12967945 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Material.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/Material.h @@ -99,10 +99,13 @@ namespace Physics class MaterialConfiguration { public: - AZ_TYPE_INFO(Physics::MaterialConfiguration, "{8807CAA1-AD08-4238-8FDB-2154ADD084A1}"); + AZ_RTTI(Physics::MaterialConfiguration, "{8807CAA1-AD08-4238-8FDB-2154ADD084A1}"); static void Reflect(AZ::ReflectContext* context); + MaterialConfiguration() = default; + virtual ~MaterialConfiguration() = default; + const static AZ::Crc32 s_stringGroup; ///< Edit context data attribute. Identifies a string group instance. String values in the same group are unique. const static AZ::Crc32 s_forbiddenStringSet; ///< Edit context data attribute. A set of strings that are not acceptable as values to the data element. Can be AZStd::unordered_set, AZStd::set, AZStd::vector const static AZ::Crc32 s_configLineEdit; ///< Edit context data element handler. Creates custom line edit widget that allows string values to be unique in a group. @@ -123,11 +126,28 @@ namespace Physics bool operator==(const MaterialConfiguration& other) const; bool operator!=(const MaterialConfiguration& other) const; + protected: + virtual bool IsNameReadOnly() const { return false; } + private: static bool VersionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement); static AZ::Color GenerateDebugColor(const char* materialName); }; + class DefaultMaterialConfiguration + : public MaterialConfiguration + { + public: + AZ_RTTI(Physics::DefaultMaterialConfiguration, "{A1F64C5C-D413-4757-9D42-51DD0EBFC270}", Physics::MaterialConfiguration); + + static void Reflect(AZ::ReflectContext* context); + + DefaultMaterialConfiguration(); + + protected: + bool IsNameReadOnly() const override { return true; } + }; + namespace Attributes { const static AZ::Crc32 MaterialLibraryAssetId = AZ_CRC("MaterialAssetId", 0x4a88a3f5); @@ -239,7 +259,7 @@ namespace Physics AZ_TYPE_INFO(Physics::MaterialInfoReflectionWrapper, "{02AB8CBC-D35B-4E0F-89BA-A96D94DAD4F9}"); static void Reflect(AZ::ReflectContext* context); - Physics::MaterialConfiguration m_defaultMaterialConfiguration; + Physics::DefaultMaterialConfiguration m_defaultMaterialConfiguration; AZ::Data::Asset m_materialLibraryAsset = AZ::Data::AssetLoadBehavior::NoLoad; }; @@ -298,6 +318,10 @@ namespace Physics // EditorContext callbacks AZStd::string GetMaterialSlotLabel(int index); + + // Only used for Edit Context as it requires to have an asset reflected. + // To get the material library use GetMaterialLibraryId() + AZ::Data::Asset m_editContextMaterialLibrary{ AZ::Data::AssetLoadBehavior::NoLoad }; }; /// Editor Bus used to assign material to terrain surface id. diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Shape.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Shape.cpp index 6325b50f4d..910184857b 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Shape.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/Shape.cpp @@ -62,7 +62,7 @@ namespace Physics ->Attribute(AZ::Edit::Attributes::Step, 0.01f) ->DataElement(AZ::Edit::UIHandlers::Default, &ColliderConfiguration::m_rotation, "Rotation", "Local rotation relative to the rigid body") ->Attribute(AZ::Edit::Attributes::Visibility, &ColliderConfiguration::GetOffsetVisibility) - ->DataElement(AZ::Edit::UIHandlers::Default, &ColliderConfiguration::m_materialSelection, "Physics Material", "Select physics material library and which materials to use for the shape") + ->DataElement(AZ::Edit::UIHandlers::Default, &ColliderConfiguration::m_materialSelection, "Physics Materials", "Select which physics materials to use for each element of this shape") ->Attribute(AZ::Edit::Attributes::Visibility, &ColliderConfiguration::GetMaterialSelectionVisibility) ->DataElement(AZ::Edit::UIHandlers::Default, &ColliderConfiguration::m_tag, "Tag", "Tag used to identify colliders from one another") ->DataElement(AZ::Edit::UIHandlers::Default, &ColliderConfiguration::m_restOffset, "Rest offset", diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Utils.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Utils.cpp index 2c3b62bb88..17c09bb6ce 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Utils.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/Utils.cpp @@ -118,6 +118,7 @@ namespace Physics AzPhysics::TriggerEvent::Reflect(context); AzPhysics::SceneConfiguration::Reflect(context); MaterialConfiguration::Reflect(context); + DefaultMaterialConfiguration::Reflect(context); MaterialLibraryAsset::Reflect(context); MaterialInfoReflectionWrapper::Reflect(context); JointLimitConfiguration::Reflect(context); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp index a0b3762123..e8be4be0a2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp @@ -1130,6 +1130,16 @@ namespace AzToolsFramework m_browseEdit->setAttachedButtonIcon(icon); } + void PropertyAssetCtrl::SetBrowseButtonEnabled(bool enabled) + { + m_browseEdit->setEnabled(enabled); + } + + void PropertyAssetCtrl::SetBrowseButtonVisible(bool visible) + { + m_browseEdit->setVisible(visible); + } + const QModelIndex PropertyAssetCtrl::GetSourceIndex(const QModelIndex& index) { if (!index.isValid()) @@ -1360,6 +1370,22 @@ namespace AzToolsFramework GUI->SetBrowseButtonIcon(QIcon(iconPath.c_str())); } } + else if (attrib == AZ_CRC_CE("BrowseButtonEnabled")) + { + bool enabled = true; + if (attrValue->Read(enabled)) + { + GUI->SetBrowseButtonEnabled(enabled); + } + } + else if (attrib == AZ_CRC_CE("BrowseButtonVisible")) + { + bool visible = true; + if (attrValue->Read(visible)) + { + GUI->SetBrowseButtonVisible(visible); + } + } else if (attrib == AZ_CRC_CE("Thumbnail")) { bool showThumbnail = false; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx index 5a6310eb35..fc52a1a9c9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx @@ -208,6 +208,8 @@ namespace AzToolsFramework void SetEditButtonIcon(const QIcon& icon); void SetEditButtonTooltip(QString tooltip); void SetBrowseButtonIcon(const QIcon& icon); + void SetBrowseButtonEnabled(bool enabled); + void SetBrowseButtonVisible(bool visible); void SetClearButtonEnabled(bool enable); void SetClearButtonVisible(bool visible); diff --git a/Gems/PhysX/Code/Editor/ConfigStringLineEditCtrl.cpp b/Gems/PhysX/Code/Editor/ConfigStringLineEditCtrl.cpp index 704b538a5f..a08d566d79 100644 --- a/Gems/PhysX/Code/Editor/ConfigStringLineEditCtrl.cpp +++ b/Gems/PhysX/Code/Editor/ConfigStringLineEditCtrl.cpp @@ -219,6 +219,14 @@ namespace PhysX GUI->setMaxLen(maxLen); } } + else if (attrib == AZ::Edit::Attributes::ReadOnly) + { + bool isReadOnly = false; + if (attrValue->Read(isReadOnly)) + { + GUI->setEnabled(!isReadOnly); + } + } else if (attrib == Physics::MaterialConfiguration::s_stringGroup) { AZ::Crc32 uniqueGroup; diff --git a/Gems/PhysX/Code/Include/PhysX/MeshAsset.h b/Gems/PhysX/Code/Include/PhysX/MeshAsset.h index edfd82439a..fffa8b43b3 100644 --- a/Gems/PhysX/Code/Include/PhysX/MeshAsset.h +++ b/Gems/PhysX/Code/Include/PhysX/MeshAsset.h @@ -75,6 +75,8 @@ namespace PhysX AZ_CLASS_ALLOCATOR(MeshAsset, AZ::SystemAllocator, 0); AZ_RTTI(MeshAsset, "{7A2871B9-5EAB-4DE0-A901-B0D2C6920DDB}", AZ::Data::AssetData); + static void Reflect(AZ::ReflectContext* context); + MeshAssetData m_assetData; }; } // namespace Pipeline diff --git a/Gems/PhysX/Code/Source/EditorColliderComponent.cpp b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp index 1cb60e0af2..0671e3e77e 100644 --- a/Gems/PhysX/Code/Source/EditorColliderComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp @@ -58,10 +58,12 @@ namespace PhysX { editContext->Class("EditorProxyShapeConfig", "PhysX Base shape collider") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") - ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyAssetShapeConfig::m_pxAsset, "PhysX Mesh", "PhysX mesh collider asset") + ->Attribute(AZ_CRC_CE("EditButton"), "") + ->Attribute(AZ_CRC_CE("EditDescription"), "Open in FBX Settings") ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyAssetShapeConfig::m_configuration, "Configuration", "Configuration of asset shape") - ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly); + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly); } } } @@ -356,6 +358,7 @@ namespace PhysX [this](const AZ::Data::AssetId& defaultMaterialLibrary) { m_configuration.m_materialSelection.OnMaterialLibraryChanged(defaultMaterialLibrary); + UpdateMaterialSlotsFromMeshAsset(); AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(&AzToolsFramework::PropertyEditorGUIMessages::RequestRefresh, AzToolsFramework::PropertyModificationRefreshLevel::Refresh_AttributesAndValues); diff --git a/Gems/PhysX/Code/Source/Material.cpp b/Gems/PhysX/Code/Source/Material.cpp index 45a7d64c55..ada01dad48 100644 --- a/Gems/PhysX/Code/Source/Material.cpp +++ b/Gems/PhysX/Code/Source/Material.cpp @@ -441,6 +441,7 @@ namespace PhysX "UpdateMaterialSelectionFromPhysicsAsset: Physics material '%s' not found in the material library. Mesh material '%s' will use the default physics material.", physicsMaterialNameFromPhysicsAsset.c_str(), meshAsset->m_assetData.m_materialNames[slotIndex].c_str()); + materialSelection.SetMaterialId(Physics::MaterialId(), slotIndex); } } } diff --git a/Gems/PhysX/Code/Source/Pipeline/MeshAssetHandler.cpp b/Gems/PhysX/Code/Source/Pipeline/MeshAssetHandler.cpp index 24fcd9d5e7..d909b31c47 100644 --- a/Gems/PhysX/Code/Source/Pipeline/MeshAssetHandler.cpp +++ b/Gems/PhysX/Code/Source/Pipeline/MeshAssetHandler.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -158,6 +159,27 @@ namespace PhysX } } + void MeshAsset::Reflect(AZ::ReflectContext* context) + { + MeshAssetData::Reflect(context); + + if (auto* serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Field("MeshAssetData", &MeshAsset::m_assetData) + ; + + // Note: This class needs to have edit context reflection so PropertyAssetCtrl::OnEditButtonClicked + // can open the asset with the preferred asset editor (FBX Settings). + if (auto* editContext = serializeContext->GetEditContext()) + { + editContext->Class("PhysX Mesh Asset", "") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ; + } + } + } + void AssetColliderConfiguration::Reflect(AZ::ReflectContext* context) { if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) diff --git a/Gems/PhysX/Code/Source/Pipeline/MeshExporter.cpp b/Gems/PhysX/Code/Source/Pipeline/MeshExporter.cpp index e968e2279a..de632c02b5 100644 --- a/Gems/PhysX/Code/Source/Pipeline/MeshExporter.cpp +++ b/Gems/PhysX/Code/Source/Pipeline/MeshExporter.cpp @@ -311,7 +311,7 @@ namespace PhysX AZStd::string materialName = DefaultMaterialName; if (!localFbxMaterialsList.empty()) { - int materialId = nodeMesh->GetFaceMaterialId(faceIndex); + const int materialId = nodeMesh->GetFaceMaterialId(faceIndex); if (materialId >= localFbxMaterialsList.size()) { AZ_TracePrintf(AZ::SceneAPI::Utilities::ErrorWindow, @@ -332,7 +332,7 @@ namespace PhysX } } - AZ::u16 materialIndex = InsertMaterialIndexByName(materialName, assetMaterialData); + const AZ::u16 materialIndex = InsertMaterialIndexByName(materialName, assetMaterialData); assetMaterialData.m_nodesToPerFaceMaterialIndices[nodeName][faceIndex] = materialIndex; } } @@ -729,7 +729,7 @@ namespace PhysX { // Gather material data from asset for the mesh group AZStd::optional assetMaterialData = Utils::GatherMaterialsFromMeshGroup(pxMeshGroup, graph); - if (!assetMaterialData) + if (!assetMaterialData.has_value()) { return SceneEvents::ProcessingResult::Failure; } diff --git a/Gems/PhysX/Code/Source/SystemComponent.cpp b/Gems/PhysX/Code/Source/SystemComponent.cpp index b4c17f672d..eae56967b2 100644 --- a/Gems/PhysX/Code/Source/SystemComponent.cpp +++ b/Gems/PhysX/Code/Source/SystemComponent.cpp @@ -94,7 +94,7 @@ namespace PhysX void SystemComponent::Reflect(AZ::ReflectContext* context) { D6JointLimitConfiguration::Reflect(context); - Pipeline::MeshAssetData::Reflect(context); + Pipeline::MeshAsset::Reflect(context); PhysX::ReflectionUtils::ReflectPhysXOnlyApi(context); diff --git a/Gems/PhysX/Code/Tests/PhysXSceneQueryTests.cpp b/Gems/PhysX/Code/Tests/PhysXSceneQueryTests.cpp index 313565caf2..90a2774ca4 100644 --- a/Gems/PhysX/Code/Tests/PhysXSceneQueryTests.cpp +++ b/Gems/PhysX/Code/Tests/PhysXSceneQueryTests.cpp @@ -172,7 +172,7 @@ namespace PhysX ASSERT_EQ(hit.m_material, rigidBody->GetShape(0).get()->GetMaterial().get()); const AZStd::string& typeName = hit.m_material->GetSurfaceTypeName(); - ASSERT_EQ(typeName, AZStd::string("Default")); + ASSERT_EQ(typeName, Physics::DefaultPhysicsMaterialLabel); } TEST_F(PhysXSceneQueryFixture, RayCast_AgainstStaticObject_ReturnsHit) From 992a37df8d6b3fb3b12dc2f7f9d9d62b80cfe14f Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Thu, 10 Jun 2021 10:42:13 -0500 Subject: [PATCH 39/73] [LYN-3801] Added back log message when entering/exiting game mode. --- Code/Sandbox/Editor/GameEngine.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Code/Sandbox/Editor/GameEngine.cpp b/Code/Sandbox/Editor/GameEngine.cpp index c338a2e28d..6649de1107 100644 --- a/Code/Sandbox/Editor/GameEngine.cpp +++ b/Code/Sandbox/Editor/GameEngine.cpp @@ -627,6 +627,8 @@ void CGameEngine::SwitchToInGame() &AzFramework::InputSystemCursorRequests::SetSystemCursorState, AzFramework::SystemCursorState::ConstrainedAndHidden); } + + Log("Entered game mode"); } void CGameEngine::SwitchToInEditor() @@ -681,6 +683,8 @@ void CGameEngine::SwitchToInEditor() AzFramework::InputSystemCursorRequestBus::Event(AzFramework::InputDeviceMouse::Id, &AzFramework::InputSystemCursorRequests::SetSystemCursorState, AzFramework::SystemCursorState::UnconstrainedAndVisible); + + Log("Exited game mode"); } void CGameEngine::HandleQuitRequest(IConsoleCmdArgs* /*args*/) From 45b2391303da7e5838210ecfbb5d11e7d595fc92 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Thu, 10 Jun 2021 11:18:29 -0500 Subject: [PATCH 40/73] [LYN-4390] Implemented EditorCameraRequestBus::GetActiveCameraState on the EditorViewportWidget so that the "Create camera entity from view" action works again. --- Code/Sandbox/Editor/EditorViewportWidget.cpp | 12 ++++++++++++ Code/Sandbox/Editor/EditorViewportWidget.h | 1 + 2 files changed, 13 insertions(+) diff --git a/Code/Sandbox/Editor/EditorViewportWidget.cpp b/Code/Sandbox/Editor/EditorViewportWidget.cpp index 0d3405f8f0..7e087d452b 100644 --- a/Code/Sandbox/Editor/EditorViewportWidget.cpp +++ b/Code/Sandbox/Editor/EditorViewportWidget.cpp @@ -2664,6 +2664,18 @@ bool EditorViewportWidget::GetActiveCameraPosition(AZ::Vector3& cameraPos) return false; } +bool EditorViewportWidget::GetActiveCameraState(AzFramework::CameraState& cameraState) +{ + if (m_pPrimaryViewport == this) + { + cameraState = GetCameraState(); + + return true; + } + + return false; +} + void EditorViewportWidget::OnStartPlayInEditor() { if (m_viewEntityId.IsValid()) diff --git a/Code/Sandbox/Editor/EditorViewportWidget.h b/Code/Sandbox/Editor/EditorViewportWidget.h index 4062a3c801..5d6f06c9ae 100644 --- a/Code/Sandbox/Editor/EditorViewportWidget.h +++ b/Code/Sandbox/Editor/EditorViewportWidget.h @@ -184,6 +184,7 @@ public: void SetViewAndMovementLockFromEntityPerspective(const AZ::EntityId& entityId, bool lockCameraMovement) override; AZ::EntityId GetCurrentViewEntityId() override { return m_viewEntityId; } bool GetActiveCameraPosition(AZ::Vector3& cameraPos) override; + bool GetActiveCameraState(AzFramework::CameraState& cameraState) override; // AzToolsFramework::EditorEntityContextNotificationBus (handler moved to cpp to resolve link issues in unity builds) virtual void OnStartPlayInEditor(); From 67489d2907254449852cd1916135e605a5f195c7 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Thu, 10 Jun 2021 09:36:16 -0700 Subject: [PATCH 41/73] Remove PAL_TRAIT_BUILD_EDITOR_APPLICATION_TYPE --- Code/Sandbox/Editor/CMakeLists.txt | 4 +--- Code/Sandbox/Editor/Platform/Linux/PAL_linux.cmake | 13 ------------- Code/Sandbox/Editor/Platform/Mac/PAL_mac.cmake | 13 ------------- .../Editor/Platform/Windows/PAL_windows.cmake | 13 ------------- 4 files changed, 1 insertion(+), 42 deletions(-) delete mode 100644 Code/Sandbox/Editor/Platform/Linux/PAL_linux.cmake delete mode 100644 Code/Sandbox/Editor/Platform/Mac/PAL_mac.cmake delete mode 100644 Code/Sandbox/Editor/Platform/Windows/PAL_windows.cmake diff --git a/Code/Sandbox/Editor/CMakeLists.txt b/Code/Sandbox/Editor/CMakeLists.txt index 58d5e86a2f..e1fce97067 100644 --- a/Code/Sandbox/Editor/CMakeLists.txt +++ b/Code/Sandbox/Editor/CMakeLists.txt @@ -13,8 +13,6 @@ if(NOT PAL_TRAIT_BUILD_HOST_TOOLS) return() endif() -include(${CMAKE_CURRENT_SOURCE_DIR}/Platform/${PAL_PLATFORM_NAME}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) - ly_add_target( NAME EditorCore SHARED NAMESPACE Legacy @@ -161,7 +159,7 @@ ly_add_source_properties( # Editor ################################################################################ ly_add_target( - NAME Editor ${PAL_TRAIT_BUILD_EDITOR_APPLICATION_TYPE} # Mac Editor is a bare executable on Atom until we can fix packaging of the shader compilers. DO NOT MERGE BACK TO MAINLINE + NAME Editor APPLICATION NAMESPACE Legacy AUTORCC FILES_CMAKE diff --git a/Code/Sandbox/Editor/Platform/Linux/PAL_linux.cmake b/Code/Sandbox/Editor/Platform/Linux/PAL_linux.cmake deleted file mode 100644 index 5181f4afb7..0000000000 --- a/Code/Sandbox/Editor/Platform/Linux/PAL_linux.cmake +++ /dev/null @@ -1,13 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -set (PAL_TRAIT_BUILD_EDITOR_APPLICATION_TYPE APPLICATION) - diff --git a/Code/Sandbox/Editor/Platform/Mac/PAL_mac.cmake b/Code/Sandbox/Editor/Platform/Mac/PAL_mac.cmake deleted file mode 100644 index 5181f4afb7..0000000000 --- a/Code/Sandbox/Editor/Platform/Mac/PAL_mac.cmake +++ /dev/null @@ -1,13 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -set (PAL_TRAIT_BUILD_EDITOR_APPLICATION_TYPE APPLICATION) - diff --git a/Code/Sandbox/Editor/Platform/Windows/PAL_windows.cmake b/Code/Sandbox/Editor/Platform/Windows/PAL_windows.cmake deleted file mode 100644 index 5181f4afb7..0000000000 --- a/Code/Sandbox/Editor/Platform/Windows/PAL_windows.cmake +++ /dev/null @@ -1,13 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -set (PAL_TRAIT_BUILD_EDITOR_APPLICATION_TYPE APPLICATION) - From 91fb8be5354750c8682d7f13f7988cd6048f6170 Mon Sep 17 00:00:00 2001 From: Terry Michaels Date: Thu, 10 Jun 2021 11:42:25 -0500 Subject: [PATCH 42/73] Added toolbar icons, updated viewport header UX (#1240) --- .../Images/Menu/asset_editor.svg | 7 ++++ .../Images/Menu/audio_editor.svg | 7 ++++ .../Images/Menu/emfx_editor.svg | 7 ++++ .../Images/Menu/landscape_canvas_editor.svg | 7 ++++ .../AzQtComponents/Images/Menu/lua_editor.svg | 13 ++++++++ .../Images/Menu/material_editor.svg | 10 ++++++ .../Images/Menu/script_canvas_editor.svg | 7 ++++ .../Images/Menu/trackview_editor.svg | 7 ++++ .../AzQtComponents/Images/Menu/ui_editor.svg | 7 ++++ .../AzQtComponents/Images/resources.qrc | 9 +++++ .../AzToolsFramework/Viewport/ActionBus.h | 2 +- .../Editor/AssetEditor/AssetEditorWindow.cpp | 2 ++ .../Editor/Core/LevelEditorMenuHandler.cpp | 7 +++- .../Editor/Core/LevelEditorMenuHandler.h | 2 +- .../Editor/TrackView/TrackViewDialog.cpp | 2 ++ Code/Sandbox/Editor/ViewportTitleDlg.cpp | 33 +++---------------- Code/Sandbox/Editor/ViewportTitleDlg.h | 2 -- .../EditorMaterialSystemComponent.cpp | 3 +- .../Integration/System/SystemComponent.cpp | 3 ++ .../Source/LandscapeCanvasSystemComponent.cpp | 3 ++ .../Editor/LyShineEditorSystemComponent.cpp | 2 ++ .../Code/Editor/SystemComponent.cpp | 2 ++ 22 files changed, 109 insertions(+), 35 deletions(-) create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/asset_editor.svg create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/audio_editor.svg create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/emfx_editor.svg create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/landscape_canvas_editor.svg create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/lua_editor.svg create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/material_editor.svg create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/script_canvas_editor.svg create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/trackview_editor.svg create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/ui_editor.svg diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/asset_editor.svg b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/asset_editor.svg new file mode 100644 index 0000000000..b96f27dda7 --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/asset_editor.svg @@ -0,0 +1,7 @@ + + + Asset Editor icon + + + + \ No newline at end of file diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/audio_editor.svg b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/audio_editor.svg new file mode 100644 index 0000000000..1cc863ebcd --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/audio_editor.svg @@ -0,0 +1,7 @@ + + + audio edit + + + + \ No newline at end of file diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/emfx_editor.svg b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/emfx_editor.svg new file mode 100644 index 0000000000..72e67b5170 --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/emfx_editor.svg @@ -0,0 +1,7 @@ + + + EMFX header icon + + + + \ No newline at end of file diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/landscape_canvas_editor.svg b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/landscape_canvas_editor.svg new file mode 100644 index 0000000000..ebf38d15c0 --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/landscape_canvas_editor.svg @@ -0,0 +1,7 @@ + + + Veg editor icon + + + + \ No newline at end of file diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/lua_editor.svg b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/lua_editor.svg new file mode 100644 index 0000000000..76b4ed3da4 --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/lua_editor.svg @@ -0,0 +1,13 @@ + + + Lua icon + + + + + + + + + + \ No newline at end of file diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/material_editor.svg b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/material_editor.svg new file mode 100644 index 0000000000..ed6f477367 --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/material_editor.svg @@ -0,0 +1,10 @@ + + + Material editor icon + + + + + + + \ No newline at end of file diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/script_canvas_editor.svg b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/script_canvas_editor.svg new file mode 100644 index 0000000000..b2a303d237 --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/script_canvas_editor.svg @@ -0,0 +1,7 @@ + + + SC icon + + + + \ No newline at end of file diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/trackview_editor.svg b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/trackview_editor.svg new file mode 100644 index 0000000000..56da550f0e --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/trackview_editor.svg @@ -0,0 +1,7 @@ + + + trackview icon + + + + \ No newline at end of file diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/ui_editor.svg b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/ui_editor.svg new file mode 100644 index 0000000000..8d27f071da --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/ui_editor.svg @@ -0,0 +1,7 @@ + + + UI editor icon + + + + \ No newline at end of file diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc b/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc index 2487917f67..cc66558367 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc +++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc @@ -19,5 +19,14 @@ Menu/resolution.svg Menu/debug.svg Menu/camera.svg + Menu/asset_editor.svg + Menu/audio_editor.svg + Menu/emfx_editor.svg + Menu/landscape_canvas_editor.svg + Menu/lua_editor.svg + Menu/material_editor.svg + Menu/script_canvas_editor.svg + Menu/trackview_editor.svg + Menu/ui_editor.svg diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ActionBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ActionBus.h index 7eaf3da37c..fa43eb422d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ActionBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ActionBus.h @@ -188,7 +188,7 @@ namespace AzToolsFramework virtual void AddEditMenuAction(QAction* action) = 0; /// Add an action to the Editor menu. - virtual void AddMenuAction(AZStd::string_view categoryId, QAction* action) = 0; + virtual void AddMenuAction(AZStd::string_view categoryId, QAction* action, bool addToToolsToolbar) = 0; /// (Re)populate the default EditMenu. /// Restore the EditMenu to its default state (the options available when first opening a level). diff --git a/Code/Sandbox/Editor/AssetEditor/AssetEditorWindow.cpp b/Code/Sandbox/Editor/AssetEditor/AssetEditorWindow.cpp index 53e2884943..9f14e471a3 100644 --- a/Code/Sandbox/Editor/AssetEditor/AssetEditorWindow.cpp +++ b/Code/Sandbox/Editor/AssetEditor/AssetEditorWindow.cpp @@ -117,6 +117,8 @@ void AssetEditorWindow::RegisterViewClass() { AzToolsFramework::ViewPaneOptions options; options.preferedDockingArea = Qt::LeftDockWidgetArea; + options.showOnToolsToolbar = true; + options.toolbarIcon = ":/Menu/asset_editor.svg"; AzToolsFramework::RegisterViewPane(LyViewPane::AssetEditor, LyViewPane::CategoryTools, options); } diff --git a/Code/Sandbox/Editor/Core/LevelEditorMenuHandler.cpp b/Code/Sandbox/Editor/Core/LevelEditorMenuHandler.cpp index 39c7ae43fd..ebc688f9da 100644 --- a/Code/Sandbox/Editor/Core/LevelEditorMenuHandler.cpp +++ b/Code/Sandbox/Editor/Core/LevelEditorMenuHandler.cpp @@ -1292,7 +1292,7 @@ void LevelEditorMenuHandler::AddEditMenuAction(QAction* action) } } -void LevelEditorMenuHandler::AddMenuAction(AZStd::string_view categoryId, QAction* action) +void LevelEditorMenuHandler::AddMenuAction(AZStd::string_view categoryId, QAction* action, bool addToToolsToolbar) { auto menuWrapper = m_actionManager->FindMenu(categoryId.data()); if (menuWrapper.isNull()) @@ -1301,6 +1301,11 @@ void LevelEditorMenuHandler::AddMenuAction(AZStd::string_view categoryId, QActio return; } menuWrapper.Get()->addAction(action); + + if (addToToolsToolbar) + { + m_mainWindow->GetToolbarManager()->AddButtonToEditToolbar(action); + } } void LevelEditorMenuHandler::RestoreEditMenuToDefault() diff --git a/Code/Sandbox/Editor/Core/LevelEditorMenuHandler.h b/Code/Sandbox/Editor/Core/LevelEditorMenuHandler.h index bad689ae67..aaa2c08622 100644 --- a/Code/Sandbox/Editor/Core/LevelEditorMenuHandler.h +++ b/Code/Sandbox/Editor/Core/LevelEditorMenuHandler.h @@ -98,7 +98,7 @@ private: // EditorMenuRequestBus void AddEditMenuAction(QAction* action) override; - void AddMenuAction(AZStd::string_view categoryId, QAction* action) override; + void AddMenuAction(AZStd::string_view categoryId, QAction* action, bool addToToolsToolbar) override; void RestoreEditMenuToDefault() override; MainWindow* m_mainWindow; diff --git a/Code/Sandbox/Editor/TrackView/TrackViewDialog.cpp b/Code/Sandbox/Editor/TrackView/TrackViewDialog.cpp index 0179b779e8..9176520b15 100644 --- a/Code/Sandbox/Editor/TrackView/TrackViewDialog.cpp +++ b/Code/Sandbox/Editor/TrackView/TrackViewDialog.cpp @@ -116,6 +116,8 @@ void CTrackViewDialog::RegisterViewClass() AzToolsFramework::ViewPaneOptions opts; opts.shortcut = QKeySequence(Qt::Key_T); opts.isDisabledInSimMode = true; + opts.showOnToolsToolbar = true; + opts.toolbarIcon = ":/Menu/trackview_editor.svg"; AzToolsFramework::RegisterViewPane(LyViewPane::TrackView, LyViewPane::CategoryTools, opts); GetIEditor()->GetSettingsManager()->AddToolName(s_kTrackViewLayoutSection, LyViewPane::TrackView); diff --git a/Code/Sandbox/Editor/ViewportTitleDlg.cpp b/Code/Sandbox/Editor/ViewportTitleDlg.cpp index 716568b5c7..dc4815eb6a 100644 --- a/Code/Sandbox/Editor/ViewportTitleDlg.cpp +++ b/Code/Sandbox/Editor/ViewportTitleDlg.cpp @@ -154,11 +154,6 @@ void CViewportTitleDlg::SetupCameraDropdownMenu() QAction* gotoPositionAction = new QAction("Go to position", cameraMenu); connect(gotoPositionAction, &QAction::triggered, this, &CViewportTitleDlg::OnBnClickedGotoPosition); cameraMenu->addAction(gotoPositionAction); - m_syncPlayerToCameraAction = new QAction("Sync camera to player", cameraMenu); - m_syncPlayerToCameraAction->setCheckable(true); - connect(m_syncPlayerToCameraAction, &QAction::triggered, this, &CViewportTitleDlg::OnBnClickedSyncplayer); - cameraMenu->addAction(m_syncPlayerToCameraAction); - cameraMenu->addSeparator(); auto cameraSpeedActionWidget = new QWidgetAction(cameraMenu); @@ -238,21 +233,15 @@ void CViewportTitleDlg::SetupOverflowMenu() overFlowMenu->addAction(m_enableGridSnappingAction); m_gridSizeActionWidget = new QWidgetAction(overFlowMenu); - auto gridSizeContainer = new QWidget(overFlowMenu); - auto gridSizeLabel = new QLabel(tr("Grid Size"), overFlowMenu); - m_gridSpinBox = new AzQtComponents::DoubleSpinBox(); m_gridSpinBox->setValue(SandboxEditor::GridSnappingSize()); m_gridSpinBox->setMinimum(1e-2f); + m_gridSpinBox->setToolTip(tr("Grid size")); QObject::connect( m_gridSpinBox, QOverload::of(&AzQtComponents::DoubleSpinBox::valueChanged), this, &CViewportTitleDlg::OnGridSpinBoxChanged); - QHBoxLayout* gridSizeLayout = new QHBoxLayout; - gridSizeLayout->addWidget(gridSizeLabel); - gridSizeLayout->addWidget(m_gridSpinBox); - gridSizeContainer->setLayout(gridSizeLayout); - m_gridSizeActionWidget->setDefaultWidget(gridSizeContainer); + m_gridSizeActionWidget->setDefaultWidget(m_gridSpinBox); overFlowMenu->addAction(m_gridSizeActionWidget); overFlowMenu->addSeparator(); @@ -263,22 +252,16 @@ void CViewportTitleDlg::SetupOverflowMenu() overFlowMenu->addAction(m_enableAngleSnappingAction); m_angleSizeActionWidget = new QWidgetAction(overFlowMenu); - auto angleSizeContainer = new QWidget(overFlowMenu); - auto angleSizeLabel = new QLabel(tr("Angle Snapping"), overFlowMenu); - m_angleSpinBox = new AzQtComponents::DoubleSpinBox(); m_angleSpinBox->setValue(SandboxEditor::AngleSnappingSize()); m_angleSpinBox->setMinimum(1e-2f); + m_angleSpinBox->setToolTip(tr("Angle Snapping")); QObject::connect( m_angleSpinBox, QOverload::of(&AzQtComponents::DoubleSpinBox::valueChanged), this, &CViewportTitleDlg::OnAngleSpinBoxChanged); - QHBoxLayout* angleSizeLayout = new QHBoxLayout; - angleSizeLayout->addWidget(angleSizeLabel); - angleSizeLayout->addWidget(m_angleSpinBox); - angleSizeContainer->setLayout(angleSizeLayout); - m_angleSizeActionWidget->setDefaultWidget(angleSizeContainer); + m_angleSizeActionWidget->setDefaultWidget(m_angleSpinBox); overFlowMenu->addAction(m_angleSizeActionWidget); m_ui->m_overflowBtn->setMenu(overFlowMenu); @@ -850,14 +833,6 @@ bool CViewportTitleDlg::eventFilter(QObject* object, QEvent* event) return QWidget::eventFilter(object, event) || consumeEvent; } -void CViewportTitleDlg::OnBnClickedSyncplayer() -{ - emit ActionTriggered(ID_GAME_SYNCPLAYER); - - bool bSyncPlayer = GetIEditor()->GetGameEngine()->IsSyncPlayerPosition(); - m_syncPlayerToCameraAction->setChecked(!bSyncPlayer); -} - void CViewportTitleDlg::OnBnClickedGotoPosition() { emit ActionTriggered(ID_DISPLAY_GOTOPOSITION); diff --git a/Code/Sandbox/Editor/ViewportTitleDlg.h b/Code/Sandbox/Editor/ViewportTitleDlg.h index dd0816082a..21a54bea0a 100644 --- a/Code/Sandbox/Editor/ViewportTitleDlg.h +++ b/Code/Sandbox/Editor/ViewportTitleDlg.h @@ -143,7 +143,6 @@ protected: void SetFullViewportInfo(); void SetCompactViewportInfo(); - void OnBnClickedSyncplayer(); void OnBnClickedGotoPosition(); void OnBnClickedMuteAudio(); void OnBnClickedEnableVR(); @@ -174,7 +173,6 @@ protected: QAction* m_fullInformationAction = nullptr; QAction* m_compactInformationAction = nullptr; QAction* m_debugHelpersAction = nullptr; - QAction* m_syncPlayerToCameraAction = nullptr; QAction* m_audioMuteAction = nullptr; QAction* m_enableVRAction = nullptr; QAction* m_enableGridSnappingAction = nullptr; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp index e9a81f2e9f..06530b53b2 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp @@ -151,6 +151,7 @@ namespace AZ m_openMaterialEditorAction->setShortcut(QKeySequence(Qt::Key_M)); m_openMaterialEditorAction->setCheckable(false); m_openMaterialEditorAction->setChecked(false); + m_openMaterialEditorAction->setIcon(QIcon(":/Menu/material_editor.svg")); QObject::connect( m_openMaterialEditorAction, &QAction::triggered, m_openMaterialEditorAction, [this]() { @@ -158,7 +159,7 @@ namespace AZ } ); - AzToolsFramework::EditorMenuRequestBus::Broadcast(&AzToolsFramework::EditorMenuRequestBus::Handler::AddMenuAction, "ToolMenu", m_openMaterialEditorAction); + AzToolsFramework::EditorMenuRequestBus::Broadcast(&AzToolsFramework::EditorMenuRequestBus::Handler::AddMenuAction, "ToolMenu", m_openMaterialEditorAction, true); } } diff --git a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp index 8e68c8cb44..61a5e89d80 100644 --- a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp @@ -891,6 +891,9 @@ namespace EMotionFX emotionFXWindowOptions.detachedWindow = true; #endif emotionFXWindowOptions.optionalMenuText = "Animation Editor"; + emotionFXWindowOptions.showOnToolsToolbar = true; + emotionFXWindowOptions.toolbarIcon = ":/Menu/emfx_editor.svg"; + EditorRequests::Bus::Broadcast(&EditorRequests::RegisterViewPane, EMStudio::MainWindow::GetEMotionFXPaneName(), LyViewPane::CategoryTools, emotionFXWindowOptions, windowCreationFunc); } diff --git a/Gems/LandscapeCanvas/Code/Source/LandscapeCanvasSystemComponent.cpp b/Gems/LandscapeCanvas/Code/Source/LandscapeCanvasSystemComponent.cpp index 72f7a65966..9e0129c6fe 100644 --- a/Gems/LandscapeCanvas/Code/Source/LandscapeCanvasSystemComponent.cpp +++ b/Gems/LandscapeCanvas/Code/Source/LandscapeCanvasSystemComponent.cpp @@ -146,6 +146,9 @@ namespace LandscapeCanvas { AzToolsFramework::ViewPaneOptions options; options.paneRect = QRect(100, 100, 1280, 1024); + options.showOnToolsToolbar = true; + options.toolbarIcon = ":/Menu/landscape_canvas_editor.svg"; + AzToolsFramework::RegisterViewPane(LyViewPane::LandscapeCanvas, LyViewPane::CategoryTools, options); } diff --git a/Gems/LyShine/Code/Editor/LyShineEditorSystemComponent.cpp b/Gems/LyShine/Code/Editor/LyShineEditorSystemComponent.cpp index d1c7ce96a4..19a47efdcd 100644 --- a/Gems/LyShine/Code/Editor/LyShineEditorSystemComponent.cpp +++ b/Gems/LyShine/Code/Editor/LyShineEditorSystemComponent.cpp @@ -153,6 +153,8 @@ namespace LyShineEditor opt.isPreview = true; opt.paneRect = QRect(x, y, (int)editorWidth, (int)editorHeight); opt.isDeletable = true; // we're in a plugin; make sure we can be deleted + opt.showOnToolsToolbar = true; + opt.toolbarIcon = ":/Menu/ui_editor.svg"; // opt.canHaveMultipleInstances = true; // uncomment this when CUiAnimViewSequenceManager::CanvasUnloading supports multiple canvases AzToolsFramework::RegisterViewPane(LyViewPane::UiEditor, LyViewPane::CategoryTools, opt); diff --git a/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp b/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp index 1d4d1e8605..1ba9a64083 100644 --- a/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp @@ -167,6 +167,8 @@ namespace ScriptCanvasEditor options.canHaveMultipleInstances = false; options.isPreview = true; options.showInMenu = true; + options.showOnToolsToolbar = true; + options.toolbarIcon = ":/Menu/script_canvas_editor.svg"; AzToolsFramework::RegisterViewPane(LyViewPane::ScriptCanvas, LyViewPane::CategoryTools, options); } From 42cc4214ba92587cea813e931d9e6ee3689f3ef3 Mon Sep 17 00:00:00 2001 From: Aaron Ruiz Mora Date: Thu, 10 Jun 2021 18:39:42 +0100 Subject: [PATCH 43/73] Use dropdown comboboxes in Physics Materials fields' of PhysX Groups in FBX Settings (#1242) --- Gems/PhysX/Code/Source/Pipeline/MeshGroup.cpp | 47 +++++++++++++++++++ Gems/PhysX/Code/Source/Pipeline/MeshGroup.h | 8 +++- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/Gems/PhysX/Code/Source/Pipeline/MeshGroup.cpp b/Gems/PhysX/Code/Source/Pipeline/MeshGroup.cpp index 4789377852..ffae8c449b 100644 --- a/Gems/PhysX/Code/Source/Pipeline/MeshGroup.cpp +++ b/Gems/PhysX/Code/Source/Pipeline/MeshGroup.cpp @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include #include @@ -580,7 +582,21 @@ namespace PhysX MeshGroup::MeshGroup() : m_id(AZ::Uuid::CreateRandom()) + , m_materialLibraryChangedHandler( + [this](const AZ::Data::AssetId& materialLibraryAssetId) + { + OnMaterialLibraryChanged(materialLibraryAssetId); + }) + { + if (auto* physicsSystem = AZ::Interface::Get()) + { + physicsSystem->RegisterOnMaterialLibraryChangedEventHandler(m_materialLibraryChangedHandler); + } + } + + MeshGroup::~MeshGroup() { + m_materialLibraryChangedHandler.Disconnect(); } void MeshGroup::Reflect(AZ::ReflectContext* context) @@ -669,6 +685,8 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::IndexedChildNameLabelOverride, &MeshGroup::GetMaterialSlotLabel) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->Attribute(AZ::Edit::Attributes::ContainerCanBeModified, false) + ->ElementAttribute(AZ::Edit::UIHandlers::Handler, AZ::Edit::UIHandlers::ComboBox) + ->ElementAttribute(AZ::Edit::Attributes::StringList, &MeshGroup::GetPhysicsMaterialNames) ->DataElement(AZ::Edit::UIHandlers::Default, &MeshGroup::m_rules, "", "Add or remove rules to fine-tune the export process.") @@ -857,6 +875,35 @@ namespace PhysX } } + AZStd::vector MeshGroup::GetPhysicsMaterialNames() const + { + if (auto* physicsSystem = AZ::Interface::Get()) + { + if (const auto* physicsConfiguration = physicsSystem->GetConfiguration()) + { + const auto& materials = physicsConfiguration->m_materialLibraryAsset->GetMaterialsData(); + + AZStd::vector physicsMaterialNames; + physicsMaterialNames.reserve(materials.size() + 1); + + physicsMaterialNames.emplace_back(Physics::DefaultPhysicsMaterialLabel); + for (const auto& material : materials) + { + physicsMaterialNames.emplace_back(material.m_configuration.m_surfaceType); + } + + return physicsMaterialNames; + } + } + return {Physics::DefaultPhysicsMaterialLabel}; + } + + void MeshGroup::OnMaterialLibraryChanged([[maybe_unused]] const AZ::Data::AssetId& materialLibraryAssetId) + { + AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(&AzToolsFramework::PropertyEditorGUIMessages::RequestRefresh, + AzToolsFramework::PropertyModificationRefreshLevel::Refresh_AttributesAndValues); + } + bool MeshGroup::VersionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement) { // Remove the material rule. diff --git a/Gems/PhysX/Code/Source/Pipeline/MeshGroup.h b/Gems/PhysX/Code/Source/Pipeline/MeshGroup.h index a2c270234a..5b70ded7ea 100644 --- a/Gems/PhysX/Code/Source/Pipeline/MeshGroup.h +++ b/Gems/PhysX/Code/Source/Pipeline/MeshGroup.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -177,7 +178,7 @@ namespace PhysX AZ_CLASS_ALLOCATOR_DECL MeshGroup(); - ~MeshGroup() override = default; + ~MeshGroup() override; static void Reflect(AZ::ReflectContext* context); @@ -224,6 +225,9 @@ namespace PhysX bool GetDecomposeMeshesVisibility() const; AZStd::string GetMaterialSlotLabel(int index) const; + AZStd::vector GetPhysicsMaterialNames() const; + + void OnMaterialLibraryChanged(const AZ::Data::AssetId& materialLibraryAssetId); AZ::Uuid m_id{}; AZStd::string m_name{}; @@ -239,6 +243,8 @@ namespace PhysX AZStd::vector m_physicsMaterials; const AZ::SceneAPI::Containers::SceneGraph* m_graph = nullptr; + + AzPhysics::SystemEvents::OnMaterialLibraryChangedEvent::Handler m_materialLibraryChangedHandler; }; } } From 856daf1485e816dff21eb6a268a67fbcf41ff5d6 Mon Sep 17 00:00:00 2001 From: sconel Date: Thu, 10 Jun 2021 10:46:36 -0700 Subject: [PATCH 44/73] Addressed PR feedback --- .../AzToolsFramework/Prefab/Instance/Instance.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h index bba20cbe8a..5f36ac10dc 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h @@ -89,8 +89,9 @@ namespace AzToolsFramework void DetachEntities(const AZStd::function)>& callback); /** - * Detaches all entities in the instance hierarchy, including; all direct and nested entities, all container entities. - * Note that without container entities the hierarchy that remains cannot be used further without restoring new ones + * Detaches all entities in the instance hierarchy. + * Includes all direct entities, all nested entities, and all container entities. + * Note that without container entities the hierarchy that remains cannot be used further without restoring new ones. * @param callback A user provided callback that can be used to capture ownership and manipulate the detached entities. */ void DetachAllEntitiesInHierarchy(const AZStd::function)>& callback); From 2ee4d8ff6b822d8f733e5dc1dd4800db43aa4cd7 Mon Sep 17 00:00:00 2001 From: amzn-sj Date: Thu, 10 Jun 2021 11:01:23 -0700 Subject: [PATCH 45/73] Sanitize identifier names before substituting them in C++ template files --- .../Code/Include/${Name}/${Name}Bus.h | 8 ++--- .../Source/${Name}EditorSystemComponent.cpp | 12 +++---- .../Source/${Name}EditorSystemComponent.h | 16 ++++----- .../Template/Code/Source/${Name}Module.cpp | 18 +++++----- .../Code/Source/${Name}SystemComponent.cpp | 34 +++++++++---------- .../Code/Source/${Name}SystemComponent.h | 12 +++---- .../Template/Code/Tests/${Name}EditorTest.cpp | 4 +-- .../Template/Code/Tests/${Name}Test.cpp | 4 +-- .../Code/Include/${Name}/${Name}Bus.h | 8 ++--- .../Template/Code/Source/${Name}Module.cpp | 18 +++++----- .../Code/Source/${Name}SystemComponent.cpp | 30 ++++++++-------- .../Code/Source/${Name}SystemComponent.h | 10 +++--- scripts/o3de/o3de/engine_template.py | 7 ++++ scripts/o3de/o3de/utils.py | 20 +++++++++++ 14 files changed, 114 insertions(+), 87 deletions(-) diff --git a/Templates/DefaultGem/Template/Code/Include/${Name}/${Name}Bus.h b/Templates/DefaultGem/Template/Code/Include/${Name}/${Name}Bus.h index 0e8ab29cc4..1b3b67c241 100644 --- a/Templates/DefaultGem/Template/Code/Include/${Name}/${Name}Bus.h +++ b/Templates/DefaultGem/Template/Code/Include/${Name}/${Name}Bus.h @@ -16,9 +16,9 @@ #include -namespace ${Name} +namespace ${SanitizedCppName} { - class ${Name}Requests + class ${SanitizedCppName}Requests : public AZ::EBusTraits { public: @@ -31,6 +31,6 @@ namespace ${Name} // Put your public methods here }; - using ${Name}RequestBus = AZ::EBus<${Name}Requests>; + using ${SanitizedCppName}RequestBus = AZ::EBus<${SanitizedCppName}Requests>; -} // namespace ${Name} +} // namespace ${SanitizedCppName} diff --git a/Templates/DefaultGem/Template/Code/Source/${Name}EditorSystemComponent.cpp b/Templates/DefaultGem/Template/Code/Source/${Name}EditorSystemComponent.cpp index 5884489904..4fca5e8d3c 100644 --- a/Templates/DefaultGem/Template/Code/Source/${Name}EditorSystemComponent.cpp +++ b/Templates/DefaultGem/Template/Code/Source/${Name}EditorSystemComponent.cpp @@ -15,24 +15,24 @@ #include #include <${Name}EditorSystemComponent.h> -namespace ${Name} +namespace ${SanitizedCppName} { - void ${Name}EditorSystemComponent::Reflect(AZ::ReflectContext* context) + void ${SanitizedCppName}EditorSystemComponent::Reflect(AZ::ReflectContext* context) { if (auto serializeContext = azrtti_cast(context)) { - serializeContext->Class<${Name}EditorSystemComponent, AZ::Component>()->Version(1); + serializeContext->Class<${SanitizedCppName}EditorSystemComponent, AZ::Component>()->Version(1); } } - void ${Name}EditorSystemComponent::Activate() + void ${SanitizedCppName}EditorSystemComponent::Activate() { AzToolsFramework::EditorEvents::Bus::Handler::BusConnect(); } - void ${Name}EditorSystemComponent::Deactivate() + void ${SanitizedCppName}EditorSystemComponent::Deactivate() { AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect(); } -} // namespace ${Name} +} // namespace ${SanitizedCppName} diff --git a/Templates/DefaultGem/Template/Code/Source/${Name}EditorSystemComponent.h b/Templates/DefaultGem/Template/Code/Source/${Name}EditorSystemComponent.h index 1f973651ee..296d2c3bcd 100644 --- a/Templates/DefaultGem/Template/Code/Source/${Name}EditorSystemComponent.h +++ b/Templates/DefaultGem/Template/Code/Source/${Name}EditorSystemComponent.h @@ -18,32 +18,32 @@ #include -namespace ${Name} +namespace ${SanitizedCppName} { - /// System component for ${Name} editor - class ${Name}EditorSystemComponent + /// System component for ${SanitizedCppName} editor + class ${SanitizedCppName}EditorSystemComponent : public AZ::Component , private AzToolsFramework::EditorEvents::Bus::Handler { public: - AZ_COMPONENT(${Name}EditorSystemComponent, "${EditorSysCompClassId}"); + AZ_COMPONENT(${SanitizedCppName}EditorSystemComponent, "${EditorSysCompClassId}"); static void Reflect(AZ::ReflectContext* context); - ${Name}EditorSystemComponent() = default; + ${SanitizedCppName}EditorSystemComponent() = default; private: static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) { - provided.push_back(AZ_CRC("${Name}EditorService")); + provided.push_back(AZ_CRC("${SanitizedCppName}EditorService")); } static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) { - required.push_back(AZ_CRC("${Name}Service")); + required.push_back(AZ_CRC("${SanitizedCppName}Service")); } // AZ::Component void Activate() override; void Deactivate() override; }; -} // namespace ${Name} +} // namespace ${SanitizedCppName} diff --git a/Templates/DefaultGem/Template/Code/Source/${Name}Module.cpp b/Templates/DefaultGem/Template/Code/Source/${Name}Module.cpp index 3c6be88158..ca4a724f49 100644 --- a/Templates/DefaultGem/Template/Code/Source/${Name}Module.cpp +++ b/Templates/DefaultGem/Template/Code/Source/${Name}Module.cpp @@ -17,21 +17,21 @@ #include <${Name}SystemComponent.h> -namespace ${Name} +namespace ${SanitizedCppName} { - class ${Name}Module + class ${SanitizedCppName}Module : public AZ::Module { public: - AZ_RTTI(${Name}Module, "${ModuleClassId}", AZ::Module); - AZ_CLASS_ALLOCATOR(${Name}Module, AZ::SystemAllocator, 0); + AZ_RTTI(${SanitizedCppName}Module, "${ModuleClassId}", AZ::Module); + AZ_CLASS_ALLOCATOR(${SanitizedCppName}Module, AZ::SystemAllocator, 0); - ${Name}Module() + ${SanitizedCppName}Module() : AZ::Module() { // Push results of [MyComponent]::CreateDescriptor() into m_descriptors here. m_descriptors.insert(m_descriptors.end(), { - ${Name}SystemComponent::CreateDescriptor(), + ${SanitizedCppName}SystemComponent::CreateDescriptor(), }); } @@ -41,10 +41,10 @@ namespace ${Name} AZ::ComponentTypeList GetRequiredSystemComponents() const override { return AZ::ComponentTypeList { - azrtti_typeid<${Name}SystemComponent>(), + azrtti_typeid<${SanitizedCppName}SystemComponent>(), }; } }; -}// namespace ${Name} +}// namespace ${SanitizedCppName} -AZ_DECLARE_MODULE_CLASS(Gem_${Name}, ${Name}::${Name}Module) +AZ_DECLARE_MODULE_CLASS(Gem_${SanitizedCppName}, ${SanitizedCppName}::${SanitizedCppName}Module) diff --git a/Templates/DefaultGem/Template/Code/Source/${Name}SystemComponent.cpp b/Templates/DefaultGem/Template/Code/Source/${Name}SystemComponent.cpp index 7f91197e4a..214d2cfe39 100644 --- a/Templates/DefaultGem/Template/Code/Source/${Name}SystemComponent.cpp +++ b/Templates/DefaultGem/Template/Code/Source/${Name}SystemComponent.cpp @@ -18,19 +18,19 @@ #include #include -namespace ${Name} +namespace ${SanitizedCppName} { - void ${Name}SystemComponent::Reflect(AZ::ReflectContext* context) + void ${SanitizedCppName}SystemComponent::Reflect(AZ::ReflectContext* context) { if (AZ::SerializeContext* serialize = azrtti_cast(context)) { - serialize->Class<${Name}SystemComponent, AZ::Component>() + serialize->Class<${SanitizedCppName}SystemComponent, AZ::Component>() ->Version(0) ; if (AZ::EditContext* ec = serialize->GetEditContext()) { - ec->Class<${Name}SystemComponent>("${Name}", "[Description of functionality provided by this System Component]") + ec->Class<${SanitizedCppName}SystemComponent>("${SanitizedCppName}", "[Description of functionality provided by this System Component]") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System")) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) @@ -39,45 +39,45 @@ namespace ${Name} } } - void ${Name}SystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) + void ${SanitizedCppName}SystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) { - provided.push_back(AZ_CRC("${Name}Service")); + provided.push_back(AZ_CRC("${SanitizedCppName}Service")); } - void ${Name}SystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) + void ${SanitizedCppName}SystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) { - incompatible.push_back(AZ_CRC("${Name}Service")); + incompatible.push_back(AZ_CRC("${SanitizedCppName}Service")); } - void ${Name}SystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) + void ${SanitizedCppName}SystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) { AZ_UNUSED(required); } - void ${Name}SystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) + void ${SanitizedCppName}SystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) { AZ_UNUSED(dependent); } - void ${Name}SystemComponent::Init() + void ${SanitizedCppName}SystemComponent::Init() { } - void ${Name}SystemComponent::Activate() + void ${SanitizedCppName}SystemComponent::Activate() { - ${Name}RequestBus::Handler::BusConnect(); + ${SanitizedCppName}RequestBus::Handler::BusConnect(); AZ::TickBus::Handler::BusConnect(); } - void ${Name}SystemComponent::Deactivate() + void ${SanitizedCppName}SystemComponent::Deactivate() { AZ::TickBus::Handler::BusDisconnect(); - ${Name}RequestBus::Handler::BusDisconnect(); + ${SanitizedCppName}RequestBus::Handler::BusDisconnect(); } - void ${Name}SystemComponent::OnTick(float /*deltaTime*/, AZ::ScriptTimePoint /*time*/) + void ${SanitizedCppName}SystemComponent::OnTick(float /*deltaTime*/, AZ::ScriptTimePoint /*time*/) { } -} // namespace ${Name} +} // namespace ${SanitizedCppName} diff --git a/Templates/DefaultGem/Template/Code/Source/${Name}SystemComponent.h b/Templates/DefaultGem/Template/Code/Source/${Name}SystemComponent.h index 5071e7b9c7..5eff2e6430 100644 --- a/Templates/DefaultGem/Template/Code/Source/${Name}SystemComponent.h +++ b/Templates/DefaultGem/Template/Code/Source/${Name}SystemComponent.h @@ -18,15 +18,15 @@ #include #include <${Name}/${Name}Bus.h> -namespace ${Name} +namespace ${SanitizedCppName} { - class ${Name}SystemComponent + class ${SanitizedCppName}SystemComponent : public AZ::Component - , protected ${Name}RequestBus::Handler + , protected ${SanitizedCppName}RequestBus::Handler , public AZ::TickBus::Handler { public: - AZ_COMPONENT(${Name}SystemComponent, "${SysCompClassId}"); + AZ_COMPONENT(${SanitizedCppName}SystemComponent, "${SysCompClassId}"); static void Reflect(AZ::ReflectContext* context); @@ -37,7 +37,7 @@ namespace ${Name} protected: //////////////////////////////////////////////////////////////////////// - // ${Name}RequestBus interface implementation + // ${SanitizedCppName}RequestBus interface implementation //////////////////////////////////////////////////////////////////////// @@ -54,4 +54,4 @@ namespace ${Name} //////////////////////////////////////////////////////////////////////// }; -} // namespace ${Name} +} // namespace ${SanitizedCppName} diff --git a/Templates/DefaultGem/Template/Code/Tests/${Name}EditorTest.cpp b/Templates/DefaultGem/Template/Code/Tests/${Name}EditorTest.cpp index 7fd3fa7cfa..9b36a3aadb 100644 --- a/Templates/DefaultGem/Template/Code/Tests/${Name}EditorTest.cpp +++ b/Templates/DefaultGem/Template/Code/Tests/${Name}EditorTest.cpp @@ -14,7 +14,7 @@ #include -class ${Name}EditorTest +class ${SanitizedCppName}EditorTest : public ::testing::Test { protected: @@ -29,7 +29,7 @@ protected: } }; -TEST_F(${Name}EditorTest, SanityTest) +TEST_F(${SanitizedCppName}EditorTest, SanityTest) { ASSERT_TRUE(true); } diff --git a/Templates/DefaultGem/Template/Code/Tests/${Name}Test.cpp b/Templates/DefaultGem/Template/Code/Tests/${Name}Test.cpp index 8021ca920e..bee38fa9d7 100644 --- a/Templates/DefaultGem/Template/Code/Tests/${Name}Test.cpp +++ b/Templates/DefaultGem/Template/Code/Tests/${Name}Test.cpp @@ -14,7 +14,7 @@ #include -class ${Name}Test +class ${SanitizedCppName}Test : public ::testing::Test { protected: @@ -29,7 +29,7 @@ protected: } }; -TEST_F(${Name}Test, SanityTest) +TEST_F(${SanitizedCppName}Test, SanityTest) { ASSERT_TRUE(true); } diff --git a/Templates/DefaultProject/Template/Code/Include/${Name}/${Name}Bus.h b/Templates/DefaultProject/Template/Code/Include/${Name}/${Name}Bus.h index faa0e8acf6..e6f9dd57bd 100644 --- a/Templates/DefaultProject/Template/Code/Include/${Name}/${Name}Bus.h +++ b/Templates/DefaultProject/Template/Code/Include/${Name}/${Name}Bus.h @@ -16,9 +16,9 @@ #include -namespace ${Name} +namespace ${SanitizedCppName} { - class ${Name}Requests + class ${SanitizedCppName}Requests : public AZ::EBusTraits { public: @@ -30,5 +30,5 @@ namespace ${Name} // Put your public methods here }; - using ${Name}RequestBus = AZ::EBus<${Name}Requests>; -} // namespace ${Name} + using ${SanitizedCppName}RequestBus = AZ::EBus<${SanitizedCppName}Requests>; +} // namespace ${SanitizedCppName} diff --git a/Templates/DefaultProject/Template/Code/Source/${Name}Module.cpp b/Templates/DefaultProject/Template/Code/Source/${Name}Module.cpp index 4f11828366..57b473b317 100644 --- a/Templates/DefaultProject/Template/Code/Source/${Name}Module.cpp +++ b/Templates/DefaultProject/Template/Code/Source/${Name}Module.cpp @@ -17,21 +17,21 @@ #include "${Name}SystemComponent.h" -namespace ${Name} +namespace ${SanitizedCppName} { - class ${Name}Module + class ${SanitizedCppName}Module : public AZ::Module { public: - AZ_RTTI(${Name}Module, "${ModuleClassId}", AZ::Module); - AZ_CLASS_ALLOCATOR(${Name}Module, AZ::SystemAllocator, 0); + AZ_RTTI(${SanitizedCppName}Module, "${ModuleClassId}", AZ::Module); + AZ_CLASS_ALLOCATOR(${SanitizedCppName}Module, AZ::SystemAllocator, 0); - ${Name}Module() + ${SanitizedCppName}Module() : AZ::Module() { // Push results of [MyComponent]::CreateDescriptor() into m_descriptors here. m_descriptors.insert(m_descriptors.end(), { - ${Name}SystemComponent::CreateDescriptor(), + ${SanitizedCppName}SystemComponent::CreateDescriptor(), }); } @@ -41,10 +41,10 @@ namespace ${Name} AZ::ComponentTypeList GetRequiredSystemComponents() const override { return AZ::ComponentTypeList{ - azrtti_typeid<${Name}SystemComponent>(), + azrtti_typeid<${SanitizedCppName}SystemComponent>(), }; } }; -}// namespace ${Name} +}// namespace ${SanitizedCppName} -AZ_DECLARE_MODULE_CLASS(Gem_${Name}, ${Name}::${Name}Module) +AZ_DECLARE_MODULE_CLASS(Gem_${SanitizedCppName}, ${SanitizedCppName}::${SanitizedCppName}Module) diff --git a/Templates/DefaultProject/Template/Code/Source/${Name}SystemComponent.cpp b/Templates/DefaultProject/Template/Code/Source/${Name}SystemComponent.cpp index 1e505f743c..82f7d7d17b 100644 --- a/Templates/DefaultProject/Template/Code/Source/${Name}SystemComponent.cpp +++ b/Templates/DefaultProject/Template/Code/Source/${Name}SystemComponent.cpp @@ -18,19 +18,19 @@ #include "${Name}SystemComponent.h" -namespace ${Name} +namespace ${SanitizedCppName} { - void ${Name}SystemComponent::Reflect(AZ::ReflectContext* context) + void ${SanitizedCppName}SystemComponent::Reflect(AZ::ReflectContext* context) { if (AZ::SerializeContext* serialize = azrtti_cast(context)) { - serialize->Class<${Name}SystemComponent, AZ::Component>() + serialize->Class<${SanitizedCppName}SystemComponent, AZ::Component>() ->Version(0) ; if (AZ::EditContext* ec = serialize->GetEditContext()) { - ec->Class<${Name}SystemComponent>("${Name}", "[Description of functionality provided by this System Component]") + ec->Class<${SanitizedCppName}SystemComponent>("${SanitizedCppName}", "[Description of functionality provided by this System Component]") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System")) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) @@ -39,37 +39,37 @@ namespace ${Name} } } - void ${Name}SystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) + void ${SanitizedCppName}SystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) { - provided.push_back(AZ_CRC("${Name}Service")); + provided.push_back(AZ_CRC("${SanitizedCppName}Service")); } - void ${Name}SystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) + void ${SanitizedCppName}SystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) { - incompatible.push_back(AZ_CRC("${Name}Service")); + incompatible.push_back(AZ_CRC("${SanitizedCppName}Service")); } - void ${Name}SystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) + void ${SanitizedCppName}SystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) { AZ_UNUSED(required); } - void ${Name}SystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) + void ${SanitizedCppName}SystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) { AZ_UNUSED(dependent); } - void ${Name}SystemComponent::Init() + void ${SanitizedCppName}SystemComponent::Init() { } - void ${Name}SystemComponent::Activate() + void ${SanitizedCppName}SystemComponent::Activate() { - ${Name}RequestBus::Handler::BusConnect(); + ${SanitizedCppName}RequestBus::Handler::BusConnect(); } - void ${Name}SystemComponent::Deactivate() + void ${SanitizedCppName}SystemComponent::Deactivate() { - ${Name}RequestBus::Handler::BusDisconnect(); + ${SanitizedCppName}RequestBus::Handler::BusDisconnect(); } } diff --git a/Templates/DefaultProject/Template/Code/Source/${Name}SystemComponent.h b/Templates/DefaultProject/Template/Code/Source/${Name}SystemComponent.h index 39ccbda549..4df74027be 100644 --- a/Templates/DefaultProject/Template/Code/Source/${Name}SystemComponent.h +++ b/Templates/DefaultProject/Template/Code/Source/${Name}SystemComponent.h @@ -18,14 +18,14 @@ #include <${Name}/${Name}Bus.h> -namespace ${Name} +namespace ${SanitizedCppName} { - class ${Name}SystemComponent + class ${SanitizedCppName}SystemComponent : public AZ::Component - , protected ${Name}RequestBus::Handler + , protected ${SanitizedCppName}RequestBus::Handler { public: - AZ_COMPONENT(${Name}SystemComponent, "${SysCompClassId}"); + AZ_COMPONENT(${SanitizedCppName}SystemComponent, "${SysCompClassId}"); static void Reflect(AZ::ReflectContext* context); @@ -36,7 +36,7 @@ namespace ${Name} protected: //////////////////////////////////////////////////////////////////////// - // ${Name}RequestBus interface implementation + // ${SanitizedCppName}RequestBus interface implementation //////////////////////////////////////////////////////////////////////// diff --git a/scripts/o3de/o3de/engine_template.py b/scripts/o3de/o3de/engine_template.py index 9bb62eff35..05d6c5f8b9 100755 --- a/scripts/o3de/o3de/engine_template.py +++ b/scripts/o3de/o3de/engine_template.py @@ -1232,10 +1232,12 @@ def create_from_template(destination_path: str, with_this = replace.pop(0) replacements.append((replace_this, with_this)) + sanitized_cpp_name = utils.sanitize_identifier_for_cpp(destination_name) # dst name is Name replacements.append(("${Name}", destination_name)) replacements.append(("${NameUpper}", destination_name.upper())) replacements.append(("${NameLower}", destination_name.lower())) + replacements.append(("${SanitizedCppName}", sanitized_cpp_name)) if _instantiate_template(template_json_data, destination_name, @@ -1536,10 +1538,12 @@ def create_project(project_path: str, with_this = replace.pop(0) replacements.append((replace_this, with_this)) + sanitized_cpp_name = utils.sanitize_identifier_for_cpp(project_name) # project name replacements.append(("${Name}", project_name)) replacements.append(("${NameUpper}", project_name.upper())) replacements.append(("${NameLower}", project_name.lower())) + replacements.append(("${SanitizedCppName}", sanitized_cpp_name)) # module id is a uuid with { and - if module_id: @@ -1927,10 +1931,13 @@ def create_gem(gem_path: str, with_this = replace.pop(0) replacements.append((replace_this, with_this)) + sanitized_cpp_name = utils.sanitize_identifier_for_cpp(gem_name) # gem name replacements.append(("${Name}", gem_name)) replacements.append(("${NameUpper}", gem_name.upper())) replacements.append(("${NameLower}", gem_name.lower())) + replacements.append(("${SanitizedCppName}", sanitized_cpp_name)) + # module id is a uuid with { and - if module_id: diff --git a/scripts/o3de/o3de/utils.py b/scripts/o3de/o3de/utils.py index 4330de25b8..6bb536f0fd 100755 --- a/scripts/o3de/o3de/utils.py +++ b/scripts/o3de/o3de/utils.py @@ -36,6 +36,26 @@ def validate_identifier(identifier: str) -> bool: return True +def sanitize_identifier_for_cpp(identifier: str) -> str: + """ + Convert the provided identifier to a valid C++ identifier + :param identifier: the name which needs to to sanitized + :return: str: sanitized identifier + """ + if not identifier: + return '' + + sanitized_identifier = list(identifier) + if not (sanitized_identifier[0].isalpha() or sanitized_identifier[0] == '_'): + sanitized_identifier.insert(0, '_') + + for index, character in enumerate(sanitized_identifier): + if not (character.isalnum() or character == '_'): + sanitized_identifier[index] = '_' + + return "".join(sanitized_identifier) + + def validate_uuid4(uuid_string: str) -> bool: """ Determine if the uuid supplied is valid. From 3b249844d538cf10479eee5d869e50c8f225e353 Mon Sep 17 00:00:00 2001 From: moudgils Date: Thu, 10 Jun 2021 11:02:45 -0700 Subject: [PATCH 46/73] Minor formatting cleanup --- .../PostProcessing/LuminanceHeatmap.azsl | 2 +- .../Metal/Code/Source/RHI/ArgumentBuffer.cpp | 28 +++++++++++++----- .../Metal/Code/Source/RHI/ArgumentBuffer.h | 2 +- .../RHI/Metal/Code/Source/RHI/CommandList.cpp | 29 +++++++++++++++---- 4 files changed, 47 insertions(+), 14 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/LuminanceHeatmap.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/LuminanceHeatmap.azsl index 4559b6c9ef..4238392004 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/LuminanceHeatmap.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/LuminanceHeatmap.azsl @@ -1,4 +1,4 @@ - /* +/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp index 068bc5f162..680481d417 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp @@ -399,13 +399,17 @@ namespace AZ { if(RHI::CheckBitsAny(srgResourcesVisInfo.m_constantDataStageMask, RHI::ShaderStageMask::Compute)) { - resourcesToMakeResidentCompute[MTLResourceUsageRead].m_resourceArray[resourcesToMakeResidentCompute[MTLResourceUsageRead].m_resourceArrayLen++] = m_constantBuffer.GetGpuAddress>(); + uint16_t arrayIndex = resourcesToMakeResidentCompute[MTLResourceUsageRead].m_resourceArrayLen; + resourcesToMakeResidentCompute[MTLResourceUsageRead].m_resourceArray[arrayIndex] = m_constantBuffer.GetGpuAddress>(); + resourcesToMakeResidentCompute[MTLResourceUsageRead].m_resourceArrayLen++; } else { MTLRenderStages mtlRenderStages = GetRenderStages(srgResourcesVisInfo.m_constantDataStageMask); AZStd::pair key = AZStd::make_pair(MTLResourceUsageRead, mtlRenderStages); - resourcesToMakeResidentGraphics[key].m_resourceArray[resourcesToMakeResidentGraphics[key].m_resourceArrayLen++] = m_constantBuffer.GetGpuAddress>(); + uint16_t arrayIndex = resourcesToMakeResidentGraphics[key].m_resourceArrayLen; + resourcesToMakeResidentGraphics[key].m_resourceArray[arrayIndex] = m_constantBuffer.GetGpuAddress>(); + resourcesToMakeResidentGraphics[key].m_resourceArrayLen++; } } } @@ -451,7 +455,9 @@ namespace AZ } } - void ArgumentBuffer::CollectResourcesForCompute(id encoder, const ResourceBindingsSet& resourceBindingDataSet, ComputeResourcesToMakeResidentMap& resourcesToMakeResidentMap) const + void ArgumentBuffer::CollectResourcesForCompute(id encoder, + const ResourceBindingsSet& resourceBindingDataSet, + ComputeResourcesToMakeResidentMap& resourcesToMakeResidentMap) const { for (const auto& resourceBindingData : resourceBindingDataSet) { @@ -474,11 +480,16 @@ namespace AZ AZ_Assert(false, "Undefined Resource type"); } } - resourcesToMakeResidentMap[resourceUsage].m_resourceArray[resourcesToMakeResidentMap[resourceUsage].m_resourceArrayLen++] = resourceBindingData.m_resourcPtr->GetGpuAddress>(); + uint16_t arrayIndex = resourcesToMakeResidentMap[resourceUsage].m_resourceArrayLen; + resourcesToMakeResidentMap[resourceUsage].m_resourceArray[arrayIndex] = resourceBindingData.m_resourcPtr->GetGpuAddress>(); + resourcesToMakeResidentMap[resourceUsage].m_resourceArrayLen++; } } - void ArgumentBuffer::CollectResourcesForGraphics(id encoder, RHI::ShaderStageMask visShaderMask, const ResourceBindingsSet& resourceBindingDataSet, GraphicsResourcesToMakeResidentMap& resourcesToMakeResidentMap) const + void ArgumentBuffer::CollectResourcesForGraphics(id encoder, + RHI::ShaderStageMask visShaderMask, + const ResourceBindingsSet& resourceBindingDataSet, + GraphicsResourcesToMakeResidentMap& resourcesToMakeResidentMap) const { MTLRenderStages mtlRenderStages = GetRenderStages(visShaderMask); @@ -503,8 +514,11 @@ namespace AZ AZ_Assert(false, "Undefined Resource type"); } } - AZStd::pair key = AZStd::make_pair(resourceUsage, mtlRenderStages); - resourcesToMakeResidentMap[key].m_resourceArray[resourcesToMakeResidentMap[key].m_resourceArrayLen++] = resourceBindingData.m_resourcPtr->GetGpuAddress>(); + + AZStd::pair key = AZStd::make_pair(resourceUsage, mtlRenderStages); + uint16_t arrayIndex = resourcesToMakeResidentMap[key].m_resourceArrayLen; + resourcesToMakeResidentMap[key].m_resourceArray[arrayIndex] = resourceBindingData.m_resourcPtr->GetGpuAddress>(); + resourcesToMakeResidentMap[key].m_resourceArrayLen++; } } } diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h index 7cc77ae478..0825c07654 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h @@ -123,7 +123,7 @@ namespace AZ struct MetalResourceArray { AZStd::array, MaxEntriesInArgTable> m_resourceArray; - int m_resourceArrayLen = 0; + uint16_t m_resourceArrayLen = 0; }; //Map to cache all the resources based on the usage as we can batch all the resources for a given usage using ComputeResourcesToMakeResidentMap = AZStd::unordered_map; diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp index 5546be1bd9..7f65c9ea47 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp @@ -347,18 +347,35 @@ namespace AZ //For graphics and compute encoder bind all the argument buffers if(m_commandEncoderType == CommandEncoderType::Render) { - BindArgumentBuffers(RHI::ShaderStage::Vertex, bufferVertexRegisterIdMin, bufferVertexRegisterIdMax, mtlVertexArgBuffers, mtlVertexArgBufferOffsets); - BindArgumentBuffers(RHI::ShaderStage::Fragment, bufferFragmentOrComputeRegisterIdMin, bufferFragmentOrComputeRegisterIdMax, mtlFragmentOrComputeArgBuffers, mtlFragmentOrComputeArgBufferOffsets); + BindArgumentBuffers(RHI::ShaderStage::Vertex, + bufferVertexRegisterIdMin, + bufferVertexRegisterIdMax, + mtlVertexArgBuffers, + mtlVertexArgBufferOffsets); + + BindArgumentBuffers(RHI::ShaderStage::Fragment, + bufferFragmentOrComputeRegisterIdMin, + bufferFragmentOrComputeRegisterIdMax, + mtlFragmentOrComputeArgBuffers, + mtlFragmentOrComputeArgBufferOffsets); } else if(m_commandEncoderType == CommandEncoderType::Compute) { - BindArgumentBuffers(RHI::ShaderStage::Compute, bufferFragmentOrComputeRegisterIdMin, bufferFragmentOrComputeRegisterIdMax, mtlFragmentOrComputeArgBuffers, mtlFragmentOrComputeArgBufferOffsets); + BindArgumentBuffers(RHI::ShaderStage::Compute, + bufferFragmentOrComputeRegisterIdMin, + bufferFragmentOrComputeRegisterIdMax, + mtlFragmentOrComputeArgBuffers, + mtlFragmentOrComputeArgBufferOffsets); } return true; } - void CommandList::BindArgumentBuffers(RHI::ShaderStage shaderStage, uint16_t registerIdMin, uint16_t registerIdMax, MetalArgumentBufferArray& mtlArgBuffers, MetalArgumentBufferArrayOffsets mtlArgBufferOffsets) + void CommandList::BindArgumentBuffers(RHI::ShaderStage shaderStage, + uint16_t registerIdMin, + uint16_t registerIdMax, + MetalArgumentBufferArray& mtlArgBuffers, + MetalArgumentBufferArrayOffsets mtlArgBufferOffsets) { //Metal Api only lets you bind multiple argument buffers in an array as long as there are no gaps in the array //In order to accomodate that we break up the calls when a gap is noticed in the array and reconfigure the NSRange. @@ -609,7 +626,9 @@ namespace AZ } } id renderEncoder = GetEncoder>(); - [renderEncoder setVertexBuffers: mtlStreamBuffers.data() offsets: mtlStreamBufferOffsets.data() withRange: range]; + [renderEncoder setVertexBuffers: mtlStreamBuffers.data() + offsets: mtlStreamBufferOffsets.data() + withRange: range]; } } From b2bafc44aba56d80868b9976b10d04a7312d72bf Mon Sep 17 00:00:00 2001 From: Steve Pham <82231385+spham-amzn@users.noreply.github.com> Date: Thu, 10 Jun 2021 11:04:18 -0700 Subject: [PATCH 47/73] LYN-2705: Remove 'AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS' trait for Linux (#1235) * Fix Delete_Real_Readonly_Fails to mark parent directory as read-only as well Read-only files in Windows cannot be deleted. The previous version of this code relied on that fact, and would attempt to delete a file even when `skipReadOnly = true`, relying on the OS to refuse to delete the file if it is read only. On Linux, it is the writable state of the *directory* that determines if a file can be deleted or not. This fixes the test to set up the correct situation where a file deletion would fail. * Remove excluded items from a vector before iterating over it Removing items from the `pathMatches` `QStringList` while iterating over it was causing a segfault on Linux. This change separates out the item removal from the item iteration, which allows the item iteration loop to use a range-for loop instead of directly manipulating iterators. * Remove invalid test that asserts a file's metadata file can have differing file casing This test is asserting that a given source file and its accompanying metadata file can have the the same name but differing case. This is really testing whether or not the underlying filesystem that those files live on is case sensitive or not. The 99% chance is that users are using the default filesystem that their host OS gives them, NTFS on Windows, EXT* on Linux, and APFS on Mac. Even though NTFS is case-insensitive by default, it [can be configured per-directory](https://devblogs.microsoft.com/commandline/improved-per-directory-case-sensitivity-support-in-wsl/). APFS as well can be configured to be case-sensitive. For users with case sensitive filesystems, this test makes no sense. We could extend this test to inspect the case-sensitivity of the underlying filesystem, but then it is just testing the filesystem's behavior, which seems out of scope of this test. * Use a non-priviliged port for the Asset Processor tests From https://www.w3.org/Daemon/User/Installation/PrivilegedPorts.html: > The TCP/IP port numbers below 1024 are special in that normal users are not > allowed to run servers on them. This is a security feaure, in that if you > connect to a service on one of these ports you can be fairly sure that you > have the real thing, and not a fake which some hacker has put up for you. > > When you run a server as a test from a non-priviliged account, you will > normally test it on other ports, such as 2784, 5000, 8001 or 8080. * Fix for `QDir::rmdir(".")` not working in Linux Qt uses `::rmdir` to remove directories on Linux. This comes from [unistd.h](https://pubs.opengroup.org/onlinepubs/007904875/functions/rmdir.html) The documentation for that function states: > If the path argument refers to a path whose final component is either dot > or dot-dot, rmdir() shall fail. So calling `dir.rmdir(".")` will never work on Linux. Instead, get the parent directory, and remove the child directory by name. * Avoid lowercasing source asset paths when resolving dependencies Source asset paths may be case sensitive, so their case must be preserved when doing operations that hit the underlying filesystem. This method was always lowercasing them, which would cause dependencies to not be found. * Correct test to expect product filenames to be lowercase The modtime tests were failing in Linux due to something unrelated to file modtime checking. The Asset Processor Manager does this during AnalyzeJob: ``` if (foundInDatabase && jobs[0].m_fingerprint == jobDetails.m_jobEntry.m_computedFingerprint) { // If the fingerprint hasn't changed, we won't process it.. unless...is it missing a product. ``` In this case, the test was setting up a product whose file case was the same as the source asset, and would write it to the cache dir using mixed case, but use the normal asset processor API to write the product file path to the database, which recorded the path in lowercase. When the manager then went to check if the source asset's products all exist, it checked the lowercase path, which didn't exist. This fixes that test failure, by updating the test to write the product file to the cache using the proper lowercased path. * Update test to define a "not current platform" for Linux This test was failing because it was setting some "not current platform" variable to be set to "pc" on Linux, when `AssetSystem::GetHostAssetPlatform()` is defined to: ```cpp inline const char* GetHostAssetPlatform() { return "mac"; return "pc"; // set this to pc because that's what bootstrap.cfg currently defines the platform to "pc", even on Linux return "pc"; #error Unimplemented Host Asset Platform } ``` The test would go on to assert that "pc" was simultaneously in a list and not in the same list. This fixes the test by updating the code to set the "not the current platform" variable appropriately on Linux. The expectations were also updated to improve the output on test failure. Instead of this: ``` Value of: recogs["rend"].m_platformSpecs.contains(platformWhichIsNotCurrentPlatform) Actual: true Expected: false ``` You now get this: ``` Value of: recogs["rend"].m_platformSpecs.keys() Expected: (has 3 elements and there exists some permutation of elements such that: - element #0 is equal to pc, and - element #1 is equal to es3, and - element #2 is equal to server) and (doesn't contain any element that is equal to pc) Actual: { pc, server, es3 } (of type QList), whose element #0 matches ``` * Prevent windows supported path separators to be included in the test paths for UpdateToCorrectCase_ExistingFile_ReturnsTrue_CorrectsCase * Fix failing linux unit test "PlatformConfigurationUnitTests.TestFailReadConfigFile_RegularScanfolder" caused by static variable not being reset from a different test run when using AssetUtilities::ComputeProjectPath * Fix AZ_RTTI declaration for RequestEscalateAsset Message * Implement FileWatcher for Linux to fix AssetProcessorMessages.All test (RequestAssetStatus) * Split AssetProcessorMessages into 2 tests, one with RequestAssetStatus/ResponseAssetStatus and one without Add The RequestAssetStatus/ResponseAssetStatus as a sandbox test because it relies on FileWatcher thread and seems to be timing related * Remove FileWatcher_win.cpp from the Linux specific folder for FileWatcher * - Fix build error related to non-unity builds - Fixed failed linux test 'Test/LegacyTestAdapter.AllTests/UtilitiesUnitTest' caused by misplaced windows only EXPECT - Remove test trait AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS for linux to expose remaining failed tests * Fixed failed linux test 'Test/LegacyTestAdapter.AllTests/RCcontrollerUnitTests' caused by misplaced windows only EXPECT * - Fix FileWatcher unit test, disable incompatible subtests for Linux - Fix errors in FileWatcher_linux from results of the FileWatcher Unit Test * Remove AZ::AssetProcessor.Tests.Sandbox tests from definition and restore the original AssetProcessorMessages.All tests now that Filewatcher_linux was fixed * Fixes for failed unit tests: AssetProcessorManagerUnitTests and AssetProcessorManagerUnitTests_JobDependencies_Fingerprint - Caused by differences between between case-sensitive files (Linux) and non-case-sensitive Filesystems (Windows) * Update consts in FileWatcher_linux.cpp to constexpr * Fixes related to PR comment suggestions * - Removed std::bind and replaced with lambda in FileWatcher_linux - Replaced String replace functions for path separators to use AZ::IO::Path::LexicallyNormal() instead * Restoring string replace function in PathDependencyManager::ResolveDependencies due to unit test failure Co-authored-by: Chris Burel --- .../Asset/AssetProcessorMessages.h | 2 +- .../Platform/Linux/AzTest_Traits_Linux.h | 2 +- Code/Tools/AssetProcessor/CMakeLists.txt | 3 +- .../native/FileWatcher/FileWatcher_linux.cpp | 197 +++++++++++++++++- .../native/FileWatcher/FileWatcher_win.cpp | 134 ------------ .../AssetManager/PathDependencyManager.cpp | 6 +- .../AssetManager/SourceFileRelocator.cpp | 57 +++-- .../AssetManager/assetProcessorManager.cpp | 5 +- .../tests/AssetProcessorMessagesTests.cpp | 15 +- .../native/tests/SourceFileRelocatorTests.cpp | 58 +++--- .../AssetProcessorManagerTest.cpp | 44 +--- .../platformconfigurationtests.cpp | 94 ++++----- .../native/tests/utilities/assetUtilsTest.cpp | 3 + .../AssetProcessorManagerUnitTests.cpp | 44 +++- .../native/unittests/FileWatcherUnitTests.cpp | 21 +- .../unittests/RCcontrollerUnitTests.cpp | 5 +- .../native/unittests/UtilitiesUnitTests.cpp | 3 +- .../native/utilities/assetUtils.cpp | 7 +- .../native/utilities/assetUtils.h | 3 +- 19 files changed, 375 insertions(+), 328 deletions(-) delete mode 100644 Code/Tools/AssetProcessor/Platform/Linux/native/FileWatcher/FileWatcher_win.cpp diff --git a/Code/Framework/AzFramework/AzFramework/Asset/AssetProcessorMessages.h b/Code/Framework/AzFramework/AzFramework/Asset/AssetProcessorMessages.h index c15f75e3e7..f4ef1a1ca2 100644 --- a/Code/Framework/AzFramework/AzFramework/Asset/AssetProcessorMessages.h +++ b/Code/Framework/AzFramework/AzFramework/Asset/AssetProcessorMessages.h @@ -166,7 +166,7 @@ namespace AzFramework { public: AZ_CLASS_ALLOCATOR(RequestEscalateAsset, AZ::OSAllocator, 0); - AZ_RTTI(RequestAssetStatus, "{E95C5422-5F00-478B-A984-C041DE70484F}", BaseAssetProcessorMessage); + AZ_RTTI(RequestEscalateAsset, "{E95C5422-5F00-478B-A984-C041DE70484F}", BaseAssetProcessorMessage); static void Reflect(AZ::ReflectContext* context); static constexpr unsigned int MessageType = AZ_CRC("AssetSystem::RequestEscalateAsset", 0x1894d94e); diff --git a/Code/Framework/AzTest/AzTest/Platform/Linux/AzTest_Traits_Linux.h b/Code/Framework/AzTest/AzTest/Platform/Linux/AzTest_Traits_Linux.h index 855b4fe416..64816f75b2 100644 --- a/Code/Framework/AzTest/AzTest/Platform/Linux/AzTest_Traits_Linux.h +++ b/Code/Framework/AzTest/AzTest/Platform/Linux/AzTest_Traits_Linux.h @@ -22,7 +22,7 @@ #define AZ_TRAIT_DISABLE_FAILED_AP_CONNECTION_TESTS true #define AZ_TRAIT_DISABLE_FAILED_ASSET_LOAD_TESTS true -#define AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS true + #define AZ_TRAIT_DISABLE_FAILED_ATOM_RPI_TESTS true #define AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS true #define AZ_TRAIT_DISABLE_FAILED_ZERO_COLOR_CONVERSION_TEST true diff --git a/Code/Tools/AssetProcessor/CMakeLists.txt b/Code/Tools/AssetProcessor/CMakeLists.txt index 2db888218b..5e5ede1397 100644 --- a/Code/Tools/AssetProcessor/CMakeLists.txt +++ b/Code/Tools/AssetProcessor/CMakeLists.txt @@ -259,8 +259,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) ly_add_googletest( NAME AZ::AssetProcessor.Tests - TEST_COMMAND $ --unittest + TEST_COMMAND $ --unittest --gtest_filter=-*.SUITE_sandbox* ) - endif() diff --git a/Code/Tools/AssetProcessor/Platform/Linux/native/FileWatcher/FileWatcher_linux.cpp b/Code/Tools/AssetProcessor/Platform/Linux/native/FileWatcher/FileWatcher_linux.cpp index 5029db6603..6e71897ab7 100644 --- a/Code/Tools/AssetProcessor/Platform/Linux/native/FileWatcher/FileWatcher_linux.cpp +++ b/Code/Tools/AssetProcessor/Platform/Linux/native/FileWatcher/FileWatcher_linux.cpp @@ -11,9 +11,127 @@ */ #include +#include +#include +#include + +#include +#include + + +static constexpr int s_handleToFolderMapLockTimeout = 1000; // 1 sec timeout for obtaining the handle to folder map lock +static constexpr size_t s_iNotifyMaxEntries = 1024 * 16; // Control the maximum number of entries (from inotify) that can be read at one time +static constexpr size_t s_iNotifyEventSize = sizeof(struct inotify_event); +static constexpr size_t s_iNotifyReadBufferSize = s_iNotifyMaxEntries * s_iNotifyEventSize; + struct FolderRootWatch::PlatformImplementation { - PlatformImplementation() { } + PlatformImplementation() = default; + + int m_iNotifyHandle = -1; + QMutex m_handleToFolderMapLock; + QHash m_handleToFolderMap; + + bool Initialize() + { + if (m_iNotifyHandle < 0) + { + m_iNotifyHandle = inotify_init(); + } + return (m_iNotifyHandle >= 0); + } + + void Finalize() + { + if (m_iNotifyHandle >= 0) + { + if (!m_handleToFolderMapLock.tryLock(s_handleToFolderMapLockTimeout)) + { + AZ_Error("FileWatcher", false, "Unable to obtain inotify handle lock on thread"); + return; + } + + QHashIterator iter(m_handleToFolderMap); + while (iter.hasNext()) + { + iter.next(); + int watchHandle = iter.key(); + inotify_rm_watch(m_iNotifyHandle, watchHandle); + } + m_handleToFolderMap.clear(); + m_handleToFolderMapLock.unlock(); + + ::close(m_iNotifyHandle); + m_iNotifyHandle = -1; + } + } + + void AddWatchFolder(QString folder) + { + if (m_iNotifyHandle >= 0) + { + // Clean up the path before accepting it as a watch folder + QString cleanPath = QDir::cleanPath(folder); + + // Add the folder to watch and track it + int watchHandle = inotify_add_watch(m_iNotifyHandle, + cleanPath.toUtf8().constData(), + IN_CREATE | IN_CLOSE_WRITE | IN_DELETE | IN_DELETE_SELF | IN_MODIFY); + + if (!m_handleToFolderMapLock.tryLock(s_handleToFolderMapLockTimeout)) + { + AZ_Error("FileWatcher", false, "Unable to obtain inotify handle lock on thread"); + return; + } + m_handleToFolderMap[watchHandle] = cleanPath; + m_handleToFolderMapLock.unlock(); + + // Add all the subfolders to watch and track them + QDirIterator dirIter(folder, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks); + + while (dirIter.hasNext()) + { + QString dirName = dirIter.next(); + if (dirName.endsWith("/.") || dirName.endsWith("/..")) + { + continue; + } + + int watchHandle = inotify_add_watch(m_iNotifyHandle, + dirName.toUtf8().constData(), + IN_CREATE | IN_CLOSE_WRITE | IN_DELETE | IN_DELETE_SELF | IN_MODIFY); + + if (!m_handleToFolderMapLock.tryLock(s_handleToFolderMapLockTimeout)) + { + AZ_Error("FileWatcher", false, "Unable to obtain inotify handle lock on thread"); + return; + } + m_handleToFolderMap[watchHandle] = dirName; + m_handleToFolderMapLock.unlock(); + } + } + } + + void RemoveWatchFolder(int watchHandle) + { + if (m_iNotifyHandle >= 0) + { + if (!m_handleToFolderMapLock.tryLock(s_handleToFolderMapLockTimeout)) + { + AZ_Error("FileWatcher", false, "Unable to obtain inotify handle lock on thread"); + return; + } + + QHash::iterator handleToRemove = m_handleToFolderMap.find(watchHandle); + if (handleToRemove != m_handleToFolderMap.end()) + { + inotify_rm_watch(m_iNotifyHandle, watchHandle); + m_handleToFolderMap.erase(handleToRemove); + } + + m_handleToFolderMapLock.unlock(); + } + } }; ////////////////////////////////////////////////////////////////////////////// @@ -36,17 +154,86 @@ FolderRootWatch::~FolderRootWatch() bool FolderRootWatch::Start() { - // TODO: Implement for Linux - return false; + // inotify will be used by linux to monitor file changes within directories under the root folder + if (!m_platformImpl->Initialize()) + { + return false; + } + m_platformImpl->AddWatchFolder(m_root); + + m_shutdownThreadSignal = false; + m_thread = std::thread([this]() { WatchFolderLoop(); }); + return true; } void FolderRootWatch::Stop() { - // TODO: Implement for Linux + m_shutdownThreadSignal = true; + + m_platformImpl->Finalize(); + + if (m_thread.joinable()) + { + m_thread.join(); // wait for the thread to finish + m_thread = std::thread(); //destroy + } } + void FolderRootWatch::WatchFolderLoop() { - // TODO: Implement for Linux + char eventBuffer[s_iNotifyReadBufferSize]; + while (!m_shutdownThreadSignal) + { + ssize_t bytesRead = ::read(m_platformImpl->m_iNotifyHandle, eventBuffer, s_iNotifyReadBufferSize); + if (bytesRead < 0) + { + // Break out of the loop when the notify handle was closed (outside of this thread) + break; + } + else if (bytesRead > 0) + { + for (size_t index=0; indexname; + + if (event->mask & (IN_CREATE | IN_DELETE | IN_MODIFY | IN_MOVE )) + { + QString pathStr = QString("%1%2%3").arg(m_platformImpl->m_handleToFolderMap[event->wd], QDir::separator(), event->name); + + if (event->mask & (IN_CREATE | IN_MOVED_TO)) + { + if ( event->mask & IN_ISDIR ) + { + // New Directory, add it to the watch + m_platformImpl->AddWatchFolder(pathStr); + } + else + { + ProcessNewFileEvent(pathStr); + } + } + else if (event->mask & (IN_DELETE | IN_MOVED_FROM)) + { + if (event->mask & IN_ISDIR) + { + // Directory Deleted, remove it from the watch + m_platformImpl->RemoveWatchFolder(event->wd); + } + else + { + ProcessDeleteFileEvent(pathStr); + } + } + else if ((event->mask & IN_MODIFY) && ((event->mask & IN_ISDIR) != IN_ISDIR)) + { + ProcessModifyFileEvent(pathStr); + } + } + index += s_iNotifyEventSize + event->len; + } + } + } } diff --git a/Code/Tools/AssetProcessor/Platform/Linux/native/FileWatcher/FileWatcher_win.cpp b/Code/Tools/AssetProcessor/Platform/Linux/native/FileWatcher/FileWatcher_win.cpp deleted file mode 100644 index fbcfe140fd..0000000000 --- a/Code/Tools/AssetProcessor/Platform/Linux/native/FileWatcher/FileWatcher_win.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include - -#include - -struct FolderRootWatch::PlatformImplementation -{ - PlatformImplementation() : m_directoryHandle(nullptr), m_ioHandle(nullptr) { } - HANDLE m_directoryHandle; - HANDLE m_ioHandle; -}; - -////////////////////////////////////////////////////////////////////////////// -/// FolderWatchRoot -FolderRootWatch::FolderRootWatch(const QString rootFolder) - : m_root(rootFolder) - , m_shutdownThreadSignal(false) - , m_fileWatcher(nullptr) - , m_platformImpl(new PlatformImplementation()) -{ -} - -FolderRootWatch::~FolderRootWatch() -{ - // Destructor is required in here since this file contains the definition of struct PlatformImplementation - Stop(); - - delete m_platformImpl; -} - -bool FolderRootWatch::Start() -{ - m_platformImpl->m_directoryHandle = ::CreateFileW(m_root.toStdWString().data(), FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, nullptr); - - if (m_platformImpl->m_directoryHandle != INVALID_HANDLE_VALUE) - { - m_platformImpl->m_ioHandle = ::CreateIoCompletionPort(m_platformImpl->m_directoryHandle, nullptr, 1, 0); - if (m_platformImpl->m_ioHandle != INVALID_HANDLE_VALUE) - { - m_shutdownThreadSignal = false; - m_thread = std::thread(std::bind(&FolderRootWatch::WatchFolderLoop, this)); - return true; - } - } - return false; -} - -void FolderRootWatch::Stop() -{ - m_shutdownThreadSignal = true; - CloseHandle(m_platformImpl->m_ioHandle); - m_platformImpl->m_ioHandle = nullptr; - - if (m_thread.joinable()) - { - m_thread.join(); // wait for the thread to finish - m_thread = std::thread(); //destroy - } - CloseHandle(m_platformImpl->m_directoryHandle); - m_platformImpl->m_directoryHandle = nullptr; -} - -void FolderRootWatch::WatchFolderLoop() -{ - FILE_NOTIFY_INFORMATION aFileNotifyInformationList[50000]; - QString path; - OVERLAPPED aOverlapped; - LPOVERLAPPED pOverlapped; - DWORD dwByteCount; - ULONG_PTR ulKey; - - while (!m_shutdownThreadSignal) - { - ::memset(aFileNotifyInformationList, 0, sizeof(aFileNotifyInformationList)); - ::memset(&aOverlapped, 0, sizeof(aOverlapped)); - - if (::ReadDirectoryChangesW(m_platformImpl->m_directoryHandle, aFileNotifyInformationList, sizeof(aFileNotifyInformationList), true, FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_FILE_NAME, nullptr, &aOverlapped, nullptr)) - { - //wait for up to a second for I/O to signal - dwByteCount = 0; - if (::GetQueuedCompletionStatus(m_platformImpl->m_ioHandle, &dwByteCount, &ulKey, &pOverlapped, INFINITE)) - { - //if we are signaled to shutdown bypass - if (!m_shutdownThreadSignal && ulKey) - { - if (dwByteCount) - { - int offset = 0; - FILE_NOTIFY_INFORMATION* pFileNotifyInformation = aFileNotifyInformationList; - do - { - pFileNotifyInformation = (FILE_NOTIFY_INFORMATION*)((char*)pFileNotifyInformation + offset); - - path.clear(); - path.append(m_root); - path.append(QString::fromWCharArray(pFileNotifyInformation->FileName, pFileNotifyInformation->FileNameLength / 2)); - - QString file = QDir::toNativeSeparators(QDir::cleanPath(path)); - - switch (pFileNotifyInformation->Action) - { - case FILE_ACTION_ADDED: - case FILE_ACTION_RENAMED_NEW_NAME: - ProcessNewFileEvent(file); - break; - case FILE_ACTION_REMOVED: - case FILE_ACTION_RENAMED_OLD_NAME: - ProcessDeleteFileEvent(file); - break; - case FILE_ACTION_MODIFIED: - ProcessModifyFileEvent(file); - break; - } - - offset = pFileNotifyInformation->NextEntryOffset; - } while (offset); - } - } - } - } - } -} - diff --git a/Code/Tools/AssetProcessor/native/AssetManager/PathDependencyManager.cpp b/Code/Tools/AssetProcessor/native/AssetManager/PathDependencyManager.cpp index de8bde9b05..2345c9e285 100644 --- a/Code/Tools/AssetProcessor/native/AssetManager/PathDependencyManager.cpp +++ b/Code/Tools/AssetProcessor/native/AssetManager/PathDependencyManager.cpp @@ -445,10 +445,10 @@ namespace AssetProcessor bool isExcludedDependency = dependencyPathSearch.starts_with(ExcludedDependenciesSymbol); dependencyPathSearch = isExcludedDependency ? dependencyPathSearch.substr(1) : dependencyPathSearch; bool isExactDependency = !AzFramework::StringFunc::Replace(dependencyPathSearch, '*', '%'); - SanitizeForDatabase(dependencyPathSearch); if (cleanedupDependency.m_dependencyType == AssetBuilderSDK::ProductPathDependencyType::ProductFile) { + SanitizeForDatabase(dependencyPathSearch); AzToolsFramework::AssetDatabase::ProductDatabaseEntryContainer productInfoContainer; QString productNameWithPlatform = QString("%1%2%3").arg(platform.c_str(), AZ_CORRECT_DATABASE_SEPARATOR_STRING, dependencyPathSearch.c_str()); @@ -508,6 +508,10 @@ namespace AssetProcessor } else { + // For source assets, the casing of the input path must be maintained. Just fix up the path separators. + AZStd::replace(dependencyPathSearch.begin(), dependencyPathSearch.end(), AZ_WRONG_DATABASE_SEPARATOR, AZ_CORRECT_DATABASE_SEPARATOR); + AzFramework::StringFunc::Replace(dependencyPathSearch, AZ_DOUBLE_CORRECT_DATABASE_SEPARATOR, AZ_CORRECT_DATABASE_SEPARATOR_STRING); + // See if path matches any source files AzToolsFramework::AssetDatabase::SourceDatabaseEntryContainer sourceInfoContainer; diff --git a/Code/Tools/AssetProcessor/native/AssetManager/SourceFileRelocator.cpp b/Code/Tools/AssetProcessor/native/AssetManager/SourceFileRelocator.cpp index 49c7ef7f20..c0300b2b2a 100644 --- a/Code/Tools/AssetProcessor/native/AssetManager/SourceFileRelocator.cpp +++ b/Code/Tools/AssetProcessor/native/AssetManager/SourceFileRelocator.cpp @@ -190,44 +190,55 @@ Please note that only those seed files will get updated that are active for your void SourceFileRelocator::HandleMetaDataFiles(QStringList pathMatches, QHash& sourceIndexMap, const ScanFolderInfo* scanFolderInfo, SourceFileRelocationContainer& metadataFiles, bool excludeMetaDataFiles) const { QSet metaDataFileEntries; - for (QString file : pathMatches) + + // Remove all the metadata files + if (excludeMetaDataFiles) { - for (int idx = 0; idx < m_platformConfig->MetaDataFileTypesCount(); idx++) - { - QPair metaInfo = m_platformConfig->GetMetaDataFileTypeAt(idx); - if (file.endsWith("." + metaInfo.first, Qt::CaseInsensitive)) + pathMatches.erase(AZStd::remove_if(pathMatches.begin(), pathMatches.end(), [this](const QString& file) { - //it is a metadata file - if (excludeMetaDataFiles) - { - AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Metadata file %s will be ignored because --excludeMetadataFiles was specified in the command line.\n", - file.toUtf8().constData()); - break; // don't check it against other metafile entries, we've already ascertained its a metafile. - } - else + for (int idx = 0; idx < m_platformConfig->MetaDataFileTypesCount(); idx++) { - QString normalizedFilePath = AssetUtilities::NormalizeFilePath(file); - if (metaDataFileEntries.find(normalizedFilePath) == metaDataFileEntries.end()) + const auto& [metadataType, extension] = m_platformConfig->GetMetaDataFileTypeAt(idx); + if (file.endsWith("." + metadataType, Qt::CaseInsensitive)) { - SourceFileRelocationInfo metaDataFile(file.toUtf8().data(), scanFolderInfo); - metaDataFile.m_isMetaDataFile = true; - metadataFiles.emplace_back(metaDataFile); - metaDataFileEntries.insert(normalizedFilePath); + AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Metadata file %s will be ignored because --excludeMetadataFiles was specified in the command line.\n", + file.toUtf8().constData()); + return true; } } + return false; + }), + pathMatches.end()); + } + + for (const QString& file : pathMatches) + { + for (int idx = 0; idx < m_platformConfig->MetaDataFileTypesCount(); idx++) + { + const auto& [metadataType, extension] = m_platformConfig->GetMetaDataFileTypeAt(idx); + if (file.endsWith("." + metadataType, Qt::CaseInsensitive)) + { + const QString normalizedFilePath = AssetUtilities::NormalizeFilePath(file); + if (!metaDataFileEntries.contains(normalizedFilePath)) + { + SourceFileRelocationInfo metaDataFile(file.toUtf8().data(), scanFolderInfo); + metaDataFile.m_isMetaDataFile = true; + metadataFiles.emplace_back(metaDataFile); + metaDataFileEntries.insert(normalizedFilePath); + } } - else if (!excludeMetaDataFiles && (file.endsWith("." + metaInfo.second, Qt::CaseInsensitive) || metaInfo.second.isEmpty())) + else if (!excludeMetaDataFiles && (file.endsWith("." + extension, Qt::CaseInsensitive) || extension.isEmpty())) { // if we are here it implies that a metadata file might exists for this source file, // add metadata file only if it exists and is not added already AZStd::string metadataFilePath(file.toUtf8().data()); - if (metaInfo.second.isEmpty()) + if (extension.isEmpty()) { - metadataFilePath.append(AZStd::string::format(".%s", metaInfo.first.toUtf8().data())); + metadataFilePath.append(AZStd::string::format(".%s", metadataType.toUtf8().data())); } else { - AZ::StringFunc::Path::ReplaceExtension(metadataFilePath, metaInfo.first.toUtf8().data()); + AZ::StringFunc::Path::ReplaceExtension(metadataFilePath, metadataType.toUtf8().data()); }; // The metadata file can have a different case than the source file, diff --git a/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp b/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp index 47f79d9709..25ec36c888 100644 --- a/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp +++ b/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp @@ -1697,7 +1697,10 @@ namespace AssetProcessor if(productFileInfo.absoluteDir().entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot).empty()) { - productFileInfo.absoluteDir().rmdir("."); + const QDir productDir = productFileInfo.absoluteDir(); + QDir parentDir = productDir; + parentDir.cdUp(); + successfullyRemoved &= parentDir.rmdir(productDir.dirName()); } if (successfullyRemoved) diff --git a/Code/Tools/AssetProcessor/native/tests/AssetProcessorMessagesTests.cpp b/Code/Tools/AssetProcessor/native/tests/AssetProcessorMessagesTests.cpp index 04949c82a9..8879697faa 100644 --- a/Code/Tools/AssetProcessor/native/tests/AssetProcessorMessagesTests.cpp +++ b/Code/Tools/AssetProcessor/native/tests/AssetProcessorMessagesTests.cpp @@ -28,7 +28,7 @@ namespace AssetProcessorMessagesTests using namespace AssetProcessor; using namespace AssetBuilderSDK; - static constexpr unsigned short AssetProcessorPort = static_cast(888u); + static constexpr unsigned short AssetProcessorPort{65535u}; class AssetProcessorMessages; @@ -85,7 +85,6 @@ namespace AssetProcessorMessagesTests public: void SetUp() override { -#if !AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS AssetUtilities::ResetGameName(); m_temporarySourceDir = QDir(m_temporaryDir.path()); @@ -166,12 +165,10 @@ namespace AssetProcessorMessagesTests }); -#endif // !AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS } void TearDown() override { -#if !AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS QEventLoop eventLoop; QObject::connect(m_batchApplicationManager->m_connectionManager, &ConnectionManager::ReadyToQuit, &eventLoop, &QEventLoop::quit); @@ -182,7 +179,6 @@ namespace AssetProcessorMessagesTests m_assetSystemComponent->Deactivate(); m_batchApplicationManager->Destroy(); -#endif // !AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS } void RunNetworkRequest(AZStd::function func) const @@ -207,6 +203,7 @@ namespace AssetProcessorMessagesTests thread.join(); } + protected: MockAssetRequestHandler* m_assetRequestHandler{}; // Not owned, AP will delete this pointer @@ -226,11 +223,7 @@ namespace AssetProcessorMessagesTests AZStd::unique_ptr m_response; }; -#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS - TEST_F(AssetProcessorMessages, DISABLED_All) -#else TEST_F(AssetProcessorMessages, All) -#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS { // Test that we can successfully send network messages and have them arrive for processing // For messages that have a response, it also verifies the response comes back @@ -311,11 +304,7 @@ namespace AssetProcessorMessagesTests }); } -#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS - TEST_F(AssetProcessorMessages, DISABLED_GetUnresolvedProductReferences_Succeeds) -#else TEST_F(AssetProcessorMessages, GetUnresolvedProductReferences_Succeeds) -#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS { using namespace AzToolsFramework::AssetDatabase; diff --git a/Code/Tools/AssetProcessor/native/tests/SourceFileRelocatorTests.cpp b/Code/Tools/AssetProcessor/native/tests/SourceFileRelocatorTests.cpp index 2731aa6c5a..e9f18a442a 100644 --- a/Code/Tools/AssetProcessor/native/tests/SourceFileRelocatorTests.cpp +++ b/Code/Tools/AssetProcessor/native/tests/SourceFileRelocatorTests.cpp @@ -112,7 +112,6 @@ namespace UnitTests SourceDatabaseEntry sourceFile8 = { m_data->m_scanFolder1.m_scanFolderID, "test.txt", AZ::Uuid::CreateRandom(), "AnalysisFingerprint" }; SourceDatabaseEntry sourceFile9 = { m_data->m_scanFolder1.m_scanFolderID, "duplicate/folder/file1.tif", AZ::Uuid::CreateRandom(), "AnalysisFingerprint" }; SourceDatabaseEntry sourceFile10 = { m_data->m_scanFolder1.m_scanFolderID, "folder/file.foo", AZ::Uuid::CreateRandom(), "AnalysisFingerprint" }; - SourceDatabaseEntry sourceFile11 = { m_data->m_scanFolder1.m_scanFolderID, "testfolder/file.foo", AZ::Uuid::CreateRandom(), "AnalysisFingerprint" }; ASSERT_TRUE(m_data->m_connection->SetSource(sourceFile1)); ASSERT_TRUE(m_data->m_connection->SetSource(sourceFile2)); ASSERT_TRUE(m_data->m_connection->SetSource(sourceFile3)); @@ -123,7 +122,6 @@ namespace UnitTests ASSERT_TRUE(m_data->m_connection->SetSource(sourceFile8)); ASSERT_TRUE(m_data->m_connection->SetSource(sourceFile9)); ASSERT_TRUE(m_data->m_connection->SetSource(sourceFile10)); - ASSERT_TRUE(m_data->m_connection->SetSource(sourceFile11)); SourceFileDependencyEntry dependency1 = { AZ::Uuid::CreateRandom(), "subfolder1/somefile.tif", "subfolder1/otherfile.tif", SourceFileDependencyEntry::TypeOfDependency::DEP_SourceToSource, false }; SourceFileDependencyEntry dependency2 = { AZ::Uuid::CreateRandom(), "subfolder1/otherfile.tif", "otherfile.tif", SourceFileDependencyEntry::TypeOfDependency::DEP_JobToJob, false }; @@ -176,8 +174,6 @@ namespace UnitTests ASSERT_TRUE(UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("dev/dummy/foo.metadataextension"))); ASSERT_TRUE(UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("dev/folder/file.foo"))); ASSERT_TRUE(UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("dev/folder/file.bar"))); - ASSERT_TRUE(UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("dev/testfolder/file.foo"))); - ASSERT_TRUE(UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("dev/testfolder/File.bar"))); if (AZ::IO::FileIOBase::GetInstance() == nullptr) { @@ -487,20 +483,12 @@ namespace UnitTests TestGetSourcesByPath("dev/", { }, false); } -#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS - TEST_F(SourceFileRelocatorTest, DISABLED_GetSources_MultipleScanFolders_Fails) -#else TEST_F(SourceFileRelocatorTest, GetSources_MultipleScanFolders_Fails) -#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS { TestGetSourcesByPath("*", { }, false); } -#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS - TEST_F(SourceFileRelocatorTest, DISABLED_GetSources_PartialPath_FailsWithNoResults) -#else TEST_F(SourceFileRelocatorTest, GetSources_PartialPath_FailsWithNoResults) -#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS { TestGetSourcesByPath("older/*", { }, false); } @@ -547,18 +535,6 @@ namespace UnitTests TestGetSourcesByPath(filePath.toUtf8().constData(), { "folder/file.foo" }, true, true); } -#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS - TEST_F(SourceFileRelocatorTest, DISABLED_GetSources_HaveMetadataDifferentFileCase_AbsolutePath_Succeeds) -#else - TEST_F(SourceFileRelocatorTest, GetSources_HaveMetadataDifferentFileCase_AbsolutePath_Succeeds) -#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS - { - QDir tempPath(m_tempDir.path()); - - auto filePath = QDir(tempPath.absoluteFilePath(m_data->m_scanFolder1.m_scanFolder.c_str())).absoluteFilePath("testfolder/file.foo"); - TestGetSourcesByPath(filePath.toUtf8().constData(), { "testfolder/file.foo", "testfolder/File.bar" }, true, false); - } - TEST_F(SourceFileRelocatorTest, GetMetaDataFile_SingleFileWildcard_Succeeds) { QDir tempPath(m_tempDir.path()); @@ -921,32 +897,46 @@ namespace UnitTests ASSERT_FALSE(AZ::IO::FileIOBase::GetInstance()->Exists(filePath.toUtf8().constData())); } -#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS - TEST_F(SourceFileRelocatorTest, DISABLED_Delete_Real_Readonly_Fails) -#else TEST_F(SourceFileRelocatorTest, Delete_Real_Readonly_Fails) -#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS { + struct AutoResetDirectoryReadOnlyState + { + AutoResetDirectoryReadOnlyState(QString dirName) + : m_dirName(AZStd::move(dirName)) + { + AZ::IO::SystemFile::SetWritable(m_dirName.toUtf8().constData(), false); + } + ~AutoResetDirectoryReadOnlyState() + { + AZ::IO::SystemFile::SetWritable(m_dirName.toUtf8().constData(), true); + } + AZ_DISABLE_COPY_MOVE(AutoResetDirectoryReadOnlyState) + private: + QString m_dirName; + }; + QDir tempPath(m_tempDir.path()); auto filePath = QDir(tempPath.absoluteFilePath(m_data->m_scanFolder1.m_scanFolder.c_str())).absoluteFilePath("duplicate/file1.tif"); ASSERT_TRUE(AZ::IO::FileIOBase::GetInstance()->Exists(filePath.toUtf8().constData())); + AutoResetDirectoryReadOnlyState readOnlyResetter(QFileInfo(filePath).absoluteDir().absolutePath()); + AZ::IO::SystemFile::SetWritable(filePath.toUtf8().constData(), false); auto result = m_data->m_reporter->Delete(filePath.toUtf8().constData(), false); - ASSERT_TRUE(result.IsSuccess()); + EXPECT_TRUE(result.IsSuccess()); RelocationSuccess successResult = result.TakeValue(); - ASSERT_EQ(successResult.m_moveSuccessCount, 0); - ASSERT_EQ(successResult.m_moveFailureCount, 1); - ASSERT_EQ(successResult.m_moveTotalCount, 1); - ASSERT_EQ(successResult.m_updateTotalCount, 0); + EXPECT_EQ(successResult.m_moveSuccessCount, 0); + EXPECT_EQ(successResult.m_moveFailureCount, 1); + EXPECT_EQ(successResult.m_moveTotalCount, 1); + EXPECT_EQ(successResult.m_updateTotalCount, 0); - ASSERT_TRUE(AZ::IO::FileIOBase::GetInstance()->Exists(filePath.toUtf8().constData())); + EXPECT_TRUE(AZ::IO::FileIOBase::GetInstance()->Exists(filePath.toUtf8().constData())); } TEST_F(SourceFileRelocatorTest, Delete_Real_WithDependencies_Fails) diff --git a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp index bd99cf7a94..6cd18d534b 100644 --- a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp +++ b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp @@ -30,11 +30,7 @@ public: friend class GTEST_TEST_CLASS_NAME_(MultiplatformPathDependencyTest, AssetProcessed_Impl_MultiplatformDependencies); friend class GTEST_TEST_CLASS_NAME_(MultiplatformPathDependencyTest, AssetProcessed_Impl_MultiplatformDependencies_DeferredResolution); -#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS - friend class GTEST_TEST_CLASS_NAME_(MultiplatformPathDependencyTest, DISABLED_AssetProcessed_Impl_MultiplatformDependencies_SourcePath); -#else friend class GTEST_TEST_CLASS_NAME_(MultiplatformPathDependencyTest, AssetProcessed_Impl_MultiplatformDependencies_SourcePath); -#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, DeleteFolder_SignalsDeleteOfContainedFiles); @@ -70,19 +66,11 @@ public: friend class GTEST_TEST_CLASS_NAME_(AbsolutePathProductDependencyTest, UnresolvedProductPathDependency_AssetProcessedTwice_ValidatePathDependenciesMap); friend class GTEST_TEST_CLASS_NAME_(AbsolutePathProductDependencyTest, UnresolvedSourceFileTypeProductPathDependency_DependencyHasNoProductOutput_ValidatePathDependenciesMap); -#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS - friend class GTEST_TEST_CLASS_NAME_(ModtimeScanningTest, DISABLED_ModtimeSkipping_FileUnchanged_WithoutModtimeSkipping); -#else friend class GTEST_TEST_CLASS_NAME_(ModtimeScanningTest, ModtimeSkipping_FileUnchanged_WithoutModtimeSkipping); -#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS friend class GTEST_TEST_CLASS_NAME_(ModtimeScanningTest, ModtimeSkipping_FileUnchanged); -#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS - friend class GTEST_TEST_CLASS_NAME_(ModtimeScanningTest, DISABLED_ModtimeSkipping_EnablePlatform_ShouldProcessFilesForPlatform); -#else friend class GTEST_TEST_CLASS_NAME_(ModtimeScanningTest, ModtimeSkipping_EnablePlatform_ShouldProcessFilesForPlatform); -#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS friend class GTEST_TEST_CLASS_NAME_(ModtimeScanningTest, ModtimeSkipping_ModifyFile); friend class GTEST_TEST_CLASS_NAME_(ModtimeScanningTest, ModtimeSkipping_ModifyFile_AndThenRevert_ProcessesAgain); @@ -2362,11 +2350,7 @@ TEST_F(PathDependencyTest, ChangeDependencies_Existing_ResolveCorrectly) ); } -#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS -TEST_F(PathDependencyTest, DISABLED_MixedPathDependencies_Existing_ResolveCorrectly) -#else TEST_F(PathDependencyTest, MixedPathDependencies_Existing_ResolveCorrectly) -#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS { using namespace AssetProcessor; using namespace AssetBuilderSDK; @@ -2661,11 +2645,7 @@ TEST_F(MultiplatformPathDependencyTest, AssetProcessed_Impl_MultiplatformDepende ASSERT_NE(SearchDependencies(dependencyContainer, asset1.m_products[0]), SearchDependencies(dependencyContainer, asset1.m_products[1])); } -#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS -TEST_F(MultiplatformPathDependencyTest, DISABLED_AssetProcessed_Impl_MultiplatformDependencies_SourcePath) -#else TEST_F(MultiplatformPathDependencyTest, AssetProcessed_Impl_MultiplatformDependencies_SourcePath) -#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS { // One product will be pc, one will be console (order is non-deterministic) TestAsset asset1("testAsset1"); @@ -3894,7 +3874,7 @@ void ModtimeScanningTest::ProcessAssetJobs() for (const auto& processResult : m_data->m_processResults) { - auto file = QDir(processResult.m_destinationPath).absoluteFilePath(processResult.m_jobEntry.m_databaseSourceName + ".arc1"); + auto file = QDir(processResult.m_destinationPath).absoluteFilePath(processResult.m_jobEntry.m_databaseSourceName.toLower() + ".arc1"); m_data->m_productPaths.emplace( QDir(processResult.m_jobEntry.m_watchFolderPath) .absoluteFilePath(processResult.m_jobEntry.m_databaseSourceName) @@ -3943,11 +3923,11 @@ void ModtimeScanningTest::ExpectWork(int createJobs, int processJobs) { ASSERT_TRUE(BlockUntilIdle(5000)); - ASSERT_EQ(m_data->m_mockBuilderInfoHandler.m_createJobsCount, createJobs); - ASSERT_EQ(m_data->m_processResults.size(), processJobs); - ASSERT_FALSE(m_data->m_processResults[0].m_autoFail); - ASSERT_FALSE(m_data->m_processResults[1].m_autoFail); - ASSERT_EQ(m_data->m_deletedSources.size(), 0); + EXPECT_EQ(m_data->m_mockBuilderInfoHandler.m_createJobsCount, createJobs); + EXPECT_EQ(m_data->m_processResults.size(), processJobs); + EXPECT_FALSE(m_data->m_processResults[0].m_autoFail); + EXPECT_FALSE(m_data->m_processResults[1].m_autoFail); + EXPECT_EQ(m_data->m_deletedSources.size(), 0); m_isIdling = false; } @@ -3975,11 +3955,7 @@ void ModtimeScanningTest::SetFileContents(QString filePath, QString contents) file.close(); } -#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS -TEST_F(ModtimeScanningTest, DISABLED_ModtimeSkipping_FileUnchanged_WithoutModtimeSkipping) -#else TEST_F(ModtimeScanningTest, ModtimeSkipping_FileUnchanged_WithoutModtimeSkipping) -#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS { using namespace AzToolsFramework::AssetSystem; @@ -4008,11 +3984,7 @@ TEST_F(ModtimeScanningTest, ModtimeSkipping_FileUnchanged) ExpectNoWork(); } -#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS -TEST_F(ModtimeScanningTest, DISABLED_ModtimeSkipping_EnablePlatform_ShouldProcessFilesForPlatform) -#else TEST_F(ModtimeScanningTest, ModtimeSkipping_EnablePlatform_ShouldProcessFilesForPlatform) -#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS { using namespace AzToolsFramework::AssetSystem; @@ -4633,11 +4605,7 @@ TEST_F(AssetProcessorManagerTest, UpdateSourceFileDependenciesDatabase_WildcardM dependList.clear(); } -#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS -TEST_F(AssetProcessorManagerTest, DISABLED_RemoveSource_RemoveCacheFolderIfEmpty_Ok) -#else TEST_F(AssetProcessorManagerTest, RemoveSource_RemoveCacheFolderIfEmpty_Ok) -#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS { using namespace AssetProcessor; using namespace AssetBuilderSDK; diff --git a/Code/Tools/AssetProcessor/native/tests/platformconfiguration/platformconfigurationtests.cpp b/Code/Tools/AssetProcessor/native/tests/platformconfiguration/platformconfigurationtests.cpp index 9c80b267eb..4a8e1a7e1c 100644 --- a/Code/Tools/AssetProcessor/native/tests/platformconfiguration/platformconfigurationtests.cpp +++ b/Code/Tools/AssetProcessor/native/tests/platformconfiguration/platformconfigurationtests.cpp @@ -14,6 +14,7 @@ #include "native/tests/platformconfiguration/platformconfigurationtests.h" #include +#include const char TestAppRoot[] = "@exefolder@/testdata"; const char EmptyDummyProjectName[] = "EmptyDummyProject"; @@ -238,33 +239,6 @@ TEST_F(PlatformConfigurationUnitTests_OnePCHostFixture, GetScanFolderForFile_Sub EXPECT_STREQ(info->GetDisplayName().toUtf8().constData(), "Editor ScanFolder"); } -// note that in the case of GetOverridingFile, this SHOULD return the correct case if an override is found -// because its possible to override a file with another file with different case in a different scan folder -// such a situation is supposed to be very rare, so the cost of correcting the case is mitigated. -TEST_F(PlatformConfigurationUnitTests_OnePCHostFixture, GetOverridingFile_Exists_ReturnsCorrectCase) -{ - using namespace AzToolsFramework::AssetSystem; - using namespace AssetProcessor; - - // create two scan folders, since its order dependent, the ScanFolder1 is the "winner" in tie breakers (when they both contain same file relpath) - QString scanfolder1Path = m_tempPath.filePath("scanfolder1"); - QString scanfolder2Path = m_tempPath.filePath("scanfolder2"); - QString caseSensitiveDummyFileName = m_tempPath.absoluteFilePath("scanfolder1/TestCase.tXt"); - QString differentCaseDummyFileName = m_tempPath.absoluteFilePath("scanfolder2/testcase.txt"); - UnitTestUtils::CreateDummyFile(caseSensitiveDummyFileName, QString("testcase1\n")); - UnitTestUtils::CreateDummyFile(differentCaseDummyFileName, QString("testcase2\n")); - m_config->AddScanFolder(ScanFolderInfo(scanfolder1Path, "ScanFolder1", "sf1", false, true, m_platforms), true); - m_config->AddScanFolder(ScanFolderInfo(scanfolder2Path, "ScanFolder2", "sf2", false, true, m_platforms), true); - - // Perform the test by asking it whether anyone overrides "testcase" (lowercase) in scanfolder 2. - QString overrider = m_config->GetOverridingFile("testcase.txt", scanfolder2Path); - - ASSERT_FALSE(overrider.isEmpty()); - // the result should be the real actual case of the file in scanfolder 1: - EXPECT_STREQ(overrider.toUtf8().constData(), caseSensitiveDummyFileName.toUtf8().constData()); -} - - TEST_F(PlatformConfigurationUnitTests_OnePCHostFixture, GetOverridingFile_ExistsButNotOverridden_ReturnsEmpty) { using namespace AzToolsFramework::AssetSystem; @@ -360,7 +334,7 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_RegularScanfolder) ASSERT_EQ(m_absorber.m_numErrorsAbsorbed, 0); ASSERT_EQ(config.GetScanFolderCount(), 3); // the two, and then the one that has the same data as prior but different identifier. - QString scanName = AssetUtilities::ComputeProjectPath() + " Scan Folder"; + QString scanName = AssetUtilities::ComputeProjectPath(true) + " Scan Folder"; ASSERT_EQ(config.GetScanFolderAt(0).GetDisplayName(), scanName); ASSERT_EQ(config.GetScanFolderAt(0).RecurseSubFolders(), true); ASSERT_EQ(config.GetScanFolderAt(0).GetOrder(), 0); @@ -445,15 +419,11 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_RegularExcludes) ASSERT_FALSE(config.IsFileExcluded("blahblah/Levels/blahblahhold/whatever.test")); } -#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS -TEST_F(PlatformConfigurationUnitTests, DISABLED_TestFailReadConfigFile_Recognizers) -#else TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_Recognizers) -#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS { using namespace AzToolsFramework::AssetSystem; using namespace AssetProcessor; -#if defined(AZ_PLATFORM_WINDOWS) +#if defined(AZ_PLATFORM_WINDOWS) || defined(AZ_PLATFORM_LINUX) const char* platformWhichIsNotCurrentPlatform = "mac"; #else const char* platformWhichIsNotCurrentPlatform = "pc"; @@ -502,31 +472,47 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_Recognizers) // the "rend" test makes sure that even if you dont specify 'params' its still there by default for all enabled platforms. // (but platforms can override it) ASSERT_TRUE(recogs.contains("rend")); - ASSERT_TRUE(recogs["rend"].m_platformSpecs.contains(AzToolsFramework::AssetSystem::GetHostAssetPlatform())); - ASSERT_TRUE(recogs["rend"].m_platformSpecs.contains("android")); - ASSERT_TRUE(recogs["rend"].m_platformSpecs.contains("server")); - ASSERT_FALSE(recogs["rend"].m_platformSpecs.contains(platformWhichIsNotCurrentPlatform)); // this is not an enabled platform and should not be there. - ASSERT_EQ(recogs["rend"].m_platformSpecs.size(), 3); - ASSERT_EQ(recogs["rend"].m_platformSpecs[AzToolsFramework::AssetSystem::GetHostAssetPlatform()].m_extraRCParams, "rendererparams"); - ASSERT_EQ(recogs["rend"].m_platformSpecs["android"].m_extraRCParams, "rendererparams"); - ASSERT_EQ(recogs["rend"].m_platformSpecs["server"].m_extraRCParams, ""); // default if not specified is empty string + EXPECT_THAT( + recogs["rend"].m_platformSpecs.keys(), + testing::AllOf( + testing::UnorderedElementsAre( + QString(AzToolsFramework::AssetSystem::GetHostAssetPlatform()), + QString("android"), + QString("server") + ), + testing::Not(testing::Contains(platformWhichIsNotCurrentPlatform)) // this is not an enabled platform and should not be there. + ) + ); + EXPECT_EQ(recogs["rend"].m_platformSpecs[AzToolsFramework::AssetSystem::GetHostAssetPlatform()].m_extraRCParams, "rendererparams"); + EXPECT_EQ(recogs["rend"].m_platformSpecs["android"].m_extraRCParams, "rendererparams"); + EXPECT_EQ(recogs["rend"].m_platformSpecs["server"].m_extraRCParams, ""); // default if not specified is empty string ASSERT_TRUE(recogs.contains("alldefault")); - ASSERT_TRUE(recogs["alldefault"].m_platformSpecs.contains(AzToolsFramework::AssetSystem::GetHostAssetPlatform())); - ASSERT_TRUE(recogs["alldefault"].m_platformSpecs.contains("android")); - ASSERT_TRUE(recogs["alldefault"].m_platformSpecs.contains("server")); - ASSERT_FALSE(recogs["alldefault"].m_platformSpecs.contains(platformWhichIsNotCurrentPlatform)); // this is not an enabled platform and should not be there. - ASSERT_EQ(recogs["alldefault"].m_platformSpecs.size(), 3); - ASSERT_EQ(recogs["alldefault"].m_platformSpecs[AzToolsFramework::AssetSystem::GetHostAssetPlatform()].m_extraRCParams, ""); - ASSERT_EQ(recogs["alldefault"].m_platformSpecs["android"].m_extraRCParams, ""); - ASSERT_EQ(recogs["alldefault"].m_platformSpecs["server"].m_extraRCParams, ""); + EXPECT_THAT( + recogs["alldefault"].m_platformSpecs.keys(), + testing::AllOf( + testing::UnorderedElementsAre( + QString(AzToolsFramework::AssetSystem::GetHostAssetPlatform()), + QString("android"), + QString("server") + ), + testing::Not(testing::Contains(platformWhichIsNotCurrentPlatform)) // this is not an enabled platform and should not be there. + ) + ); + EXPECT_EQ(recogs["alldefault"].m_platformSpecs[AzToolsFramework::AssetSystem::GetHostAssetPlatform()].m_extraRCParams, ""); + EXPECT_EQ(recogs["alldefault"].m_platformSpecs["android"].m_extraRCParams, ""); + EXPECT_EQ(recogs["alldefault"].m_platformSpecs["server"].m_extraRCParams, ""); ASSERT_TRUE(recogs.contains("skipallbutone")); - ASSERT_FALSE(recogs["skipallbutone"].m_platformSpecs.contains(AzToolsFramework::AssetSystem::GetHostAssetPlatform())); - ASSERT_FALSE(recogs["skipallbutone"].m_platformSpecs.contains("android")); - ASSERT_TRUE(recogs["skipallbutone"].m_platformSpecs.contains("server")); // server is only one enabled (set to copy) - ASSERT_EQ(recogs["skipallbutone"].m_platformSpecs.size(), 1); - ASSERT_EQ(recogs["skipallbutone"].m_platformSpecs["server"].m_extraRCParams, "copy"); + EXPECT_THAT( + recogs["skipallbutone"].m_platformSpecs.keys(), + testing::UnorderedElementsAre( + QString("server") // server is only one enabled (set to copy) + ) + ); + EXPECT_FALSE(recogs["skipallbutone"].m_platformSpecs.contains(AzToolsFramework::AssetSystem::GetHostAssetPlatform())); + EXPECT_FALSE(recogs["skipallbutone"].m_platformSpecs.contains("android")); + EXPECT_EQ(recogs["skipallbutone"].m_platformSpecs["server"].m_extraRCParams, "copy"); } diff --git a/Code/Tools/AssetProcessor/native/tests/utilities/assetUtilsTest.cpp b/Code/Tools/AssetProcessor/native/tests/utilities/assetUtilsTest.cpp index 5ed392d12b..796bca2af2 100644 --- a/Code/Tools/AssetProcessor/native/tests/utilities/assetUtilsTest.cpp +++ b/Code/Tools/AssetProcessor/native/tests/utilities/assetUtilsTest.cpp @@ -137,10 +137,13 @@ TEST_F(AssetUtilitiesTest, UpdateToCorrectCase_ExistingFile_ReturnsTrue_Corrects thingsToTry << "SomeFile.TxT"; thingsToTry << "otherfile.txt"; thingsToTry << "subfolder1/otherfile.txt"; + + #if defined(AZ_PLATFORM_WINDOWS) thingsToTry << "subfolder2\\otherfile.txt"; thingsToTry << "subFolder3\\somefile.txt"; thingsToTry << "subFolder4\\subfolder6\\somefile.txt"; thingsToTry << "subFolder5\\subfolder7/someFile.txt"; + #endif // AZ_PLATFORM_WINDOWS thingsToTry << "specialFileName[.txt"; thingsToTry << "specialFileName].txt"; thingsToTry << "specialFileName!.txt"; diff --git a/Code/Tools/AssetProcessor/native/unittests/AssetProcessorManagerUnitTests.cpp b/Code/Tools/AssetProcessor/native/unittests/AssetProcessorManagerUnitTests.cpp index 079cdb7c66..efeec5d7c1 100644 --- a/Code/Tools/AssetProcessor/native/unittests/AssetProcessorManagerUnitTests.cpp +++ b/Code/Tools/AssetProcessor/native/unittests/AssetProcessorManagerUnitTests.cpp @@ -175,6 +175,16 @@ namespace AssetProcessor UNIT_TEST_EXPECT_FALSE(gameName.isEmpty()); // should create cache folder in the root, and read everything from there. + // There is a sub-case of handling mixed cases, but is only supported on case-insensitive filesystems. +#if defined(AZ_PLATFORM_LINUX) + // Linux is case-sensitive, so 'basefile.txt' will stay the same case as the other subfolder versions + constexpr const char* subfolder3BaseFilePath = "subfolder3/basefile.txt"; + constexpr int expectedLegacyAssetIdCount = 1; +#else + constexpr const char* subfolder3BaseFilePath = "subfolder3/BaseFile.txt"; + constexpr int expectedLegacyAssetIdCount = 2; +#endif + QSet expectedFiles; // set up some interesting files: expectedFiles << tempPath.absoluteFilePath("rootfile2.txt"); @@ -185,7 +195,9 @@ namespace AssetProcessor expectedFiles << tempPath.absoluteFilePath("subfolder2/aaa/bbb/basefile.txt"); expectedFiles << tempPath.absoluteFilePath("subfolder2/aaa/bbb/ccc/basefile.txt"); expectedFiles << tempPath.absoluteFilePath("subfolder2/aaa/bbb/ccc/ddd/basefile.txt"); - expectedFiles << tempPath.absoluteFilePath("subfolder3/BaseFile.txt"); // note the case upper here + + expectedFiles << tempPath.absoluteFilePath(subfolder3BaseFilePath); + expectedFiles << tempPath.absoluteFilePath("subfolder8/a/b/c/test.txt"); // subfolder3 is not recursive so none of these should show up in any scan or override check @@ -1521,7 +1533,8 @@ namespace AssetProcessor // -------------- override test ----------------- // set up by letting it compile basefile.txt from 3: - absolutePath = AssetUtilities::NormalizeFilePath(tempPath.absoluteFilePath("subfolder3/BaseFile.txt")); + + absolutePath = AssetUtilities::NormalizeFilePath(tempPath.absoluteFilePath(subfolder3BaseFilePath)); QMetaObject::invokeMethod(&apm, "AssessModifiedFile", Qt::QueuedConnection, Q_ARG(QString, absolutePath)); UNIT_TEST_EXPECT_TRUE(BlockUntil(idling, 5000)); @@ -1583,8 +1596,7 @@ namespace AssetProcessor UNIT_TEST_EXPECT_TRUE(assetMessages.size() == 4); for (auto element : assetMessages) { - // because the source asset had UPPER CASE in it, we should have multiple legacy IDs - UNIT_TEST_EXPECT_TRUE(element.m_legacyAssetIds.size() == 2); + UNIT_TEST_EXPECT_TRUE(element.m_legacyAssetIds.size() == expectedLegacyAssetIdCount); } // ------------- setup complete, now do the test... @@ -1607,7 +1619,7 @@ namespace AssetProcessor // delete the highest priority override file and ensure that it generates tasks // for the next highest priority! Basically, deleting this file should "reveal" the file underneath it in the other subfolder - QString deletedFile = tempPath.absoluteFilePath("subfolder3/BaseFile.txt"); + QString deletedFile = tempPath.absoluteFilePath(subfolder3BaseFilePath); QString expectedReplacementInputFile = AssetUtilities::NormalizeFilePath(tempPath.absoluteFilePath("subfolder2/basefile.txt")); UNIT_TEST_EXPECT_TRUE(QFile::remove(deletedFile)); @@ -1621,6 +1633,11 @@ namespace AssetProcessor sortAssetToProcessResultList(processResults); +#if defined(AZ_PLATFORM_LINUX) + // On Linux, because of we cannot change the case of the source file, the job fingerprint is not updated due the case-switch so + // there will be actually nothing to process + UNIT_TEST_EXPECT_TRUE(processResults.size() == 0); +#else // --------- same result as above ---------- UNIT_TEST_EXPECT_TRUE(processResults.size() == 4); // 2 each for pc and android,since we have two recognizer for .txt file UNIT_TEST_EXPECT_TRUE(processResults[0].m_jobEntry.m_platformInfo.m_identifier == processResults[1].m_jobEntry.m_platformInfo.m_identifier); @@ -1641,7 +1658,7 @@ namespace AssetProcessor UNIT_TEST_EXPECT_TRUE(processFile1.startsWith(platformFolder)); UNIT_TEST_EXPECT_TRUE(processResults[checkIdx].m_jobEntry.m_computedFingerprint != 0); } - +#endif // defined(AZ_PLATFORM_LINUX) relativePathFromWatchFolder = "somefile.xxx"; watchFolderPath = tempPath.absoluteFilePath("subfolder3"); absolutePath = watchFolderPath + "/" + relativePathFromWatchFolder; @@ -2721,7 +2738,12 @@ namespace AssetProcessor { AssetBuilderSDK::JobDescriptor secondDescriptor = descriptor; secondDescriptor.m_jobKey = "yyy"; + #if defined(AZ_PLATFORM_WINDOWS) sourceFileDependency.m_sourceFileDependencyPath = "some\\random/Folders/FILEa.TxT"; + #else + sourceFileDependency.m_sourceFileDependencyPath = "some/random/folders/FileA.txt"; + #endif // defined(AZ_PLATFORM_WINDOWS) + // ... declare a job dependency on job A ('FileA.txt', 'xxx', platform) AssetBuilderSDK::JobDependency jobDependency("xxx", platformInfo.m_identifier.c_str(), AssetBuilderSDK::JobDependencyType::Fingerprint, sourceFileDependency); secondDescriptor.m_jobDependencyList.push_back(jobDependency); @@ -2805,11 +2827,11 @@ namespace AssetProcessor QDir cacheRoot; UNIT_TEST_EXPECT_TRUE(AssetUtilities::ComputeProjectCacheRoot(cacheRoot)); - QString productFileAPath = cacheRoot.filePath(QString("pc/FileAProduct.txt")); - QString productFileBPath = cacheRoot.filePath(QString("pc/FileBProduct1.txt")); - QString product2FileBPath = cacheRoot.filePath(QString("pc/FileBProduct2.txt")); - QString productFileCPath = cacheRoot.filePath(QString("pc/FileCProduct.txt")); - QString product2FileCPath = cacheRoot.filePath(QString("pc/FileCProduct2.txt")); + QString productFileAPath = cacheRoot.filePath(QString("pc/fileaproduct.txt")); + QString productFileBPath = cacheRoot.filePath(QString("pc/filebproduct1.txt")); + QString product2FileBPath = cacheRoot.filePath(QString("pc/filebproduct2.txt")); + QString productFileCPath = cacheRoot.filePath(QString("pc/filecproduct.txt")); + QString product2FileCPath = cacheRoot.filePath(QString("pc/filecproduct2.txt")); UNIT_TEST_EXPECT_TRUE(CreateDummyFile(sourceFileAPath, "")); UNIT_TEST_EXPECT_TRUE(CreateDummyFile(sourceFileBPath, "")); diff --git a/Code/Tools/AssetProcessor/native/unittests/FileWatcherUnitTests.cpp b/Code/Tools/AssetProcessor/native/unittests/FileWatcherUnitTests.cpp index 785ea8efa6..f6fb21e4e7 100644 --- a/Code/Tools/AssetProcessor/native/unittests/FileWatcherUnitTests.cpp +++ b/Code/Tools/AssetProcessor/native/unittests/FileWatcherUnitTests.cpp @@ -106,7 +106,7 @@ void FileWatcherUnitTestRunner::StartTest() AZ_TracePrintf(AssetProcessor::DebugChannel, "Waiting for remaining notifications: %d \n", outstandingFiles.count()); } - if (outstandingFiles.count() > 0) + if (outstandingFiles.count() > 0) { #if defined(AZ_ENABLE_TRACING) AZ_TracePrintf(AssetProcessor::DebugChannel, "Timed out waiting for file changes: %d / %d missed\n", outstandingFiles.count(), maxFiles); @@ -226,7 +226,9 @@ void FileWatcherUnitTestRunner::StartTest() UNIT_TEST_EXPECT_TRUE(fileAddCalled); UNIT_TEST_EXPECT_TRUE(fileRemoveCalled); - UNIT_TEST_EXPECT_TRUE(fileModifiedCalled); // modified should be called on the folder that the file lives in +#if defined(AZ_PLATFORM_WINDOWS) + UNIT_TEST_EXPECT_TRUE(fileModifiedCalled); // modified should be called on the folder that the file lives in (Only on Windows) +#endif // AZ_PLATFORM_WINDOWS UNIT_TEST_EXPECT_TRUE(QDir::toNativeSeparators(fileRemoveName).toLower() == QDir::toNativeSeparators(originalName).toLower()); UNIT_TEST_EXPECT_TRUE(QDir::toNativeSeparators(fileAddName).toLower() == QDir::toNativeSeparators(newName1).toLower()); @@ -249,7 +251,10 @@ void FileWatcherUnitTestRunner::StartTest() // the new1 was "removed" and the new2 was "added" UNIT_TEST_EXPECT_TRUE(fileAddCalled); UNIT_TEST_EXPECT_TRUE(fileRemoveCalled); - UNIT_TEST_EXPECT_TRUE(fileModifiedCalled); // modified should be called on the folder that the file lives in +#if defined(AZ_PLATFORM_WINDOWS) + UNIT_TEST_EXPECT_TRUE(fileModifiedCalled); // modified should be called on the folder that the file lives in (Only on Windows) +#endif // AZ_PLATFORM_WINDOWS + UNIT_TEST_EXPECT_TRUE(QDir::toNativeSeparators(fileRemoveName).toLower() == QDir::toNativeSeparators(newName1).toLower()); UNIT_TEST_EXPECT_TRUE(QDir::toNativeSeparators(fileAddName).toLower() == QDir::toNativeSeparators(newName2).toLower()); @@ -270,11 +275,15 @@ void FileWatcherUnitTestRunner::StartTest() // the new1 was "removed" and the new2 was "added" UNIT_TEST_EXPECT_TRUE(fileAddCalled); UNIT_TEST_EXPECT_TRUE(fileRemoveCalled); - UNIT_TEST_EXPECT_TRUE(fileModifiedCalled); // modified should be called on the folder that the file lives in +#if defined(AZ_PLATFORM_WINDOWS) + UNIT_TEST_EXPECT_TRUE(fileModifiedCalled); // modified should be called on the folder that the file lives in (Only on Windows) +#endif // AZ_PLATFORM_WINDOWS UNIT_TEST_EXPECT_TRUE(QDir::toNativeSeparators(fileRemoveName).toLower() == QDir::toNativeSeparators(newName2).toLower()); UNIT_TEST_EXPECT_TRUE(QDir::toNativeSeparators(fileAddName).toLower() == QDir::toNativeSeparators(newName3).toLower()); - // final test... make sure that renaming a DIRECTORY works too +#if !defined(AZ_PLATFORM_LINUX) + // final test... make sure that renaming a DIRECTORY works too. + // Note that linux does not get any callbacks if just the directory is renamed (from inotify) QDir renamer; fileAddCalled = false; fileRemoveCalled = false; @@ -297,7 +306,7 @@ void FileWatcherUnitTestRunner::StartTest() UNIT_TEST_EXPECT_TRUE(QDir::toNativeSeparators(fileRemoveName).toLower() == QDir::toNativeSeparators(tempDirPath.absoluteFilePath("dir3")).toLower()); UNIT_TEST_EXPECT_TRUE(QDir::toNativeSeparators(fileAddName).toLower() == QDir::toNativeSeparators(tempDirPath.absoluteFilePath("dir4")).toLower()); - +#endif // AZ_PLATFORM_LINUX QObject::disconnect(connectionRemove); QObject::disconnect(connectionAdd); diff --git a/Code/Tools/AssetProcessor/native/unittests/RCcontrollerUnitTests.cpp b/Code/Tools/AssetProcessor/native/unittests/RCcontrollerUnitTests.cpp index 02b98e5e33..38c1377b46 100644 --- a/Code/Tools/AssetProcessor/native/unittests/RCcontrollerUnitTests.cpp +++ b/Code/Tools/AssetProcessor/native/unittests/RCcontrollerUnitTests.cpp @@ -545,10 +545,13 @@ void RCcontrollerUnitTests::RunRCControllerTests() rcJob.SetCheckExclusiveLock(true); rcJob.Start(); + +#if defined(AZ_PLATFORM_WINDOWS) + // on windows, opening a file for reading locks it + // but on other platforms, this is not the case. // we only expect work to begin when we can gain an exclusive lock on this file. UNIT_TEST_EXPECT_FALSE(UnitTestUtils::BlockUntil(beginWork, 5000)); -#if defined(AZ_PLATFORM_WINDOWS) // Once we release the file, it should process normally lockFileTest.close(); #else diff --git a/Code/Tools/AssetProcessor/native/unittests/UtilitiesUnitTests.cpp b/Code/Tools/AssetProcessor/native/unittests/UtilitiesUnitTests.cpp index 1eada874d9..24433b550c 100644 --- a/Code/Tools/AssetProcessor/native/unittests/UtilitiesUnitTests.cpp +++ b/Code/Tools/AssetProcessor/native/unittests/UtilitiesUnitTests.cpp @@ -227,8 +227,9 @@ void UtilitiesUnitTests::StartTest() #else int handle = open(lockTestFileName.toUtf8().constData(), O_RDONLY | O_EXLOCK | O_NONBLOCK); #endif // AZ_PLATFORM_WINDOWS - UNIT_TEST_EXPECT_FALSE(AssetUtilities::CheckCanLock(lockTestFileName)); + #if defined(AZ_PLATFORM_WINDOWS) + UNIT_TEST_EXPECT_FALSE(AssetUtilities::CheckCanLock(lockTestFileName)); lockTestFile.close(); #else if (handle != -1) diff --git a/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp b/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp index b152e5ed4f..19423358b5 100644 --- a/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp @@ -507,8 +507,13 @@ namespace AssetUtilities return QString::fromUtf8(s_projectName.c_str(), aznumeric_cast(s_projectName.size())); } - QString ComputeProjectPath() + QString ComputeProjectPath(bool resetCachedProjectPath/*=false*/) { + if (resetCachedProjectPath) + { + // Clear any cached value if reset was requested + s_projectPath.clear(); + } if (s_projectPath.empty()) { // Check command-line args first diff --git a/Code/Tools/AssetProcessor/native/utilities/assetUtils.h b/Code/Tools/AssetProcessor/native/utilities/assetUtils.h index 201911eb96..694498e423 100644 --- a/Code/Tools/AssetProcessor/native/utilities/assetUtils.h +++ b/Code/Tools/AssetProcessor/native/utilities/assetUtils.h @@ -104,7 +104,8 @@ namespace AssetUtilities QString ComputeProjectName(QString projectNameOverride = QString(), bool force = false); //! Determine the absolute path of the current project - QString ComputeProjectPath(); + //! The path computed path will be cached on subsequent calls unless resetCachedProjectPath=true + QString ComputeProjectPath(bool resetCachedProjectPath = false); //! Reads the allowed list directly from the bootstrap file QString ReadAllowedlistFromSettingsRegistry(QString initialFolder = QString()); From 39392ec075f651955529d273131ee2c98a9b62f9 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 10 Jun 2021 14:22:35 -0500 Subject: [PATCH 48/73] Updating the DefaultGem ${Name}Bus.h template with AZ::Interface --- .../Template/Code/Include/${Name}/${Name}Bus.h | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Templates/DefaultGem/Template/Code/Include/${Name}/${Name}Bus.h b/Templates/DefaultGem/Template/Code/Include/${Name}/${Name}Bus.h index 1b3b67c241..7501e29796 100644 --- a/Templates/DefaultGem/Template/Code/Include/${Name}/${Name}Bus.h +++ b/Templates/DefaultGem/Template/Code/Include/${Name}/${Name}Bus.h @@ -15,22 +15,30 @@ #pragma once #include +#include namespace ${SanitizedCppName} { class ${SanitizedCppName}Requests + { + public: + AZ_RTTI(${SanitizedCppName}Requests, "${Random_Uuid}"); + virtual ~${SanitizedCppName}Requests = default(); + // Put your public methods here + }; + + class ${SanitizedCppName}BusTraits : public AZ::EBusTraits { public: ////////////////////////////////////////////////////////////////////////// // EBusTraits overrides - static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; - static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; + static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; ////////////////////////////////////////////////////////////////////////// - - // Put your public methods here }; - using ${SanitizedCppName}RequestBus = AZ::EBus<${SanitizedCppName}Requests>; + using ${SanitizedCppName}RequestBus = AZ::EBus<${SanitizedCppName}Requests, ${SanitizedCppName}BusTraits>; + using ${SanitizedCppName}Interface = AZ::Interface<${SanitizedCppName}Requests>; } // namespace ${SanitizedCppName} From 9550ec46b46d969fb839d7a1bdda1b4acad61d17 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 10 Jun 2021 14:23:56 -0500 Subject: [PATCH 49/73] Updating Project ${Name}Bus.h template with AZ::Interface support --- .../Code/Include/${Name}/${Name}Bus.h | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Templates/DefaultProject/Template/Code/Include/${Name}/${Name}Bus.h b/Templates/DefaultProject/Template/Code/Include/${Name}/${Name}Bus.h index e6f9dd57bd..b4a61ccd63 100644 --- a/Templates/DefaultProject/Template/Code/Include/${Name}/${Name}Bus.h +++ b/Templates/DefaultProject/Template/Code/Include/${Name}/${Name}Bus.h @@ -15,20 +15,30 @@ #pragma once #include +#include namespace ${SanitizedCppName} { class ${SanitizedCppName}Requests + { + public: + AZ_RTTI(${SanitizedCppName}Requests, "${Random_Uuid}"); + virtual ~${SanitizedCppName}Requests = default(); + // Put your public methods here + }; + + class ${SanitizedCppName}BusTraits : public AZ::EBusTraits { public: ////////////////////////////////////////////////////////////////////////// // EBusTraits overrides - static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; - static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; + static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; ////////////////////////////////////////////////////////////////////////// - - // Put your public methods here }; - using ${SanitizedCppName}RequestBus = AZ::EBus<${SanitizedCppName}Requests>; + + using ${SanitizedCppName}RequestBus = AZ::EBus<${SanitizedCppName}Requests, ${SanitizedCppName}BusTraits>; + using ${SanitizedCppName}Interface = AZ::Interface<${SanitizedCppName}Requests>; + } // namespace ${SanitizedCppName} From d3be5600c3ca320deae13a2763122e4810d63013 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Thu, 10 Jun 2021 12:30:17 -0700 Subject: [PATCH 50/73] Increase rotation step for Transform (#1244) Using the spinbox on the Transform Component is made very cumbersome by the low rotation step. Increased it to make it more usable. --- .../AzToolsFramework/ToolsComponents/TransformComponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp index 3e13e6226b..bcbe98c3a7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp @@ -1206,7 +1206,7 @@ namespace AzToolsFramework Attribute(AZ::Edit::Attributes::SliceFlags, AZ::Edit::SliceFlags::NotPushableOnSliceRoot)-> Attribute(AZ::Edit::Attributes::ReadOnly, &EditorTransform::m_locked)-> DataElement(AZ::Edit::UIHandlers::Default, &EditorTransform::m_rotate, "Rotate", "Local Rotation (Relative to parent) in degrees.")-> - Attribute(AZ::Edit::Attributes::Step, 0.1f)-> + Attribute(AZ::Edit::Attributes::Step, 1.0f)-> Attribute(AZ::Edit::Attributes::Suffix, " deg")-> Attribute(AZ::Edit::Attributes::ReadOnly, &EditorTransform::m_locked)-> Attribute(AZ::Edit::Attributes::SliceFlags, AZ::Edit::SliceFlags::NotPushableOnSliceRoot)-> From 054dd39e5b19b143982733a77fe303b8883c1432 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 10 Jun 2021 14:37:58 -0500 Subject: [PATCH 51/73] Adding implemented constructor/destructor to Template SystemComponent The System Component now implements a constructor/destructor which is used to initialize/de-initialize the `${SanitizedCppName}Interface` instance --- .../Template/Code/Source/${Name}SystemComponent.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Templates/DefaultProject/Template/Code/Source/${Name}SystemComponent.h b/Templates/DefaultProject/Template/Code/Source/${Name}SystemComponent.h index 4df74027be..10a500aba2 100644 --- a/Templates/DefaultProject/Template/Code/Source/${Name}SystemComponent.h +++ b/Templates/DefaultProject/Template/Code/Source/${Name}SystemComponent.h @@ -34,6 +34,9 @@ namespace ${SanitizedCppName} static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent); + ${SanitizedCppName}SystemComponent(); + ~${SanitizedCppName}SystemComponent(); + protected: //////////////////////////////////////////////////////////////////////// // ${SanitizedCppName}RequestBus interface implementation From 0aba7911a2430995900b88b4bbc1f93d32d4ae18 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 10 Jun 2021 14:44:00 -0500 Subject: [PATCH 52/73] Implemented the DefaultProject Template default constructor and destructor The System Component now implements a constructor/destructor which is used to initialize/de-initialize the `${SanitizedCppName}Interface` instance --- .../Code/Source/${Name}SystemComponent.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Templates/DefaultProject/Template/Code/Source/${Name}SystemComponent.cpp b/Templates/DefaultProject/Template/Code/Source/${Name}SystemComponent.cpp index 82f7d7d17b..0d160bd45a 100644 --- a/Templates/DefaultProject/Template/Code/Source/${Name}SystemComponent.cpp +++ b/Templates/DefaultProject/Template/Code/Source/${Name}SystemComponent.cpp @@ -58,6 +58,22 @@ namespace ${SanitizedCppName} { AZ_UNUSED(dependent); } + + ${SanitizedCppName}SystemComponent::${SanitizedCppName}SystemComponent() + { + if (${SanitizedCppName}Interface::Get() == nullptr) + { + ${SanitizedCppName}Interface::Register(this); + } + } + + ${SanitizedCppName}SystemComponent::~${SanitizedCppName}SystemComponent() + { + if (${SanitizedCppName}Interface::Get() == this) + { + ${SanitizedCppName}Interface::Unregister(this); + } + } void ${SanitizedCppName}SystemComponent::Init() { From 2a982fa4b2e9c8a5d33b6bb4d9753f5eee0299ad Mon Sep 17 00:00:00 2001 From: antonmic Date: Thu, 10 Jun 2021 12:50:38 -0700 Subject: [PATCH 53/73] Pass changes: Addressing PR feedback --- .../CoreLights/CascadedShadowmapsPass.cpp | 4 +- .../DirectionalLightFeatureProcessor.cpp | 2 +- .../CoreLights/ProjectedShadowmapsPass.cpp | 2 +- .../DisplayMapper/DisplayMapperPass.cpp | 2 +- .../Code/Source/LuxCore/RenderTexturePass.cpp | 2 +- .../ProjectedShadowFeatureProcessor.cpp | 2 +- .../Code/Include/Atom/RPI.Public/Pass/Pass.h | 17 ++-- .../Atom/RPI.Public/Pass/PassDefines.h | 77 +++++++++++++------ .../Source/RPI.Public/Pass/ParentPass.cpp | 6 +- .../RPI/Code/Source/RPI.Public/Pass/Pass.cpp | 38 ++++++--- .../Pass/Specific/RenderToTexturePass.cpp | 2 +- .../RPI.Public/Pass/Specific/SelectorPass.cpp | 4 +- .../Pass/Specific/SwapChainPass.cpp | 2 +- .../Code/Source/RPI.Public/RenderPipeline.cpp | 8 +- 14 files changed, 109 insertions(+), 59 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/CascadedShadowmapsPass.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/CascadedShadowmapsPass.cpp index 4c7e69f2ae..b9beac4285 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/CascadedShadowmapsPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/CascadedShadowmapsPass.cpp @@ -100,7 +100,7 @@ namespace AZ m_arraySize = arraySize; m_updateChildren = true; - QueueForBuild(); + QueueForBuildAndInitialization(); m_atlas.Initialize(); for (size_t cascadeIndex = 0; cascadeIndex < m_arraySize; ++cascadeIndex) @@ -215,7 +215,7 @@ namespace AZ AZ_RPI_PASS_WARNING(child, "CascadedShadowmapsPass child Pass creation failed for %d", cascadeIndex); if (child) { - child->QueueForBuild(); + child->QueueForBuildAndInitialization(); AddChild(child); } } diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp index cdbe431949..c4f4bc54b3 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp @@ -1106,7 +1106,7 @@ namespace AZ { for (EsmShadowmapsPass* pass : it.second) { - pass->QueueForBuild(); + pass->QueueForBuildAndInitialization(); } } } diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/ProjectedShadowmapsPass.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/ProjectedShadowmapsPass.cpp index 87cacbb345..2f1badaae7 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/ProjectedShadowmapsPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/ProjectedShadowmapsPass.cpp @@ -73,7 +73,7 @@ namespace AZ { m_sizes = sizes; m_updateChildren = true; - QueueForBuild(); + QueueForBuildAndInitialization(); m_atlas.Initialize(); for (const auto& it : m_sizes) diff --git a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp index 219d673ece..b37c218c21 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp @@ -513,7 +513,7 @@ namespace AZ desc.m_acesParameterOverrides.m_overrideDefaults != m_displayMapperConfigurationDescriptor.m_acesParameterOverrides.m_overrideDefaults) { m_flags.m_createChildren = true; - QueueForBuild(); + QueueForBuildAndInitialization(); } m_displayMapperConfigurationDescriptor = desc; } diff --git a/Gems/Atom/Feature/Common/Code/Source/LuxCore/RenderTexturePass.cpp b/Gems/Atom/Feature/Common/Code/Source/LuxCore/RenderTexturePass.cpp index aa991e270a..6e0444dca4 100644 --- a/Gems/Atom/Feature/Common/Code/Source/LuxCore/RenderTexturePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/LuxCore/RenderTexturePass.cpp @@ -38,7 +38,7 @@ namespace AZ m_attachmentSize = image->GetRHIImage()->GetDescriptor().m_size; m_attachmentFormat = format; m_shaderResourceGroup->SetImage(m_textureIndex, image); - QueueForBuild(); + QueueForBuildAndInitialization(); } void RenderTexturePass::BuildInternal() diff --git a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp index 8484fdddc2..da174ab0d5 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp @@ -526,7 +526,7 @@ namespace AZ::Render for (EsmShadowmapsPass* esmPass : m_esmShadowmapsPasses) { - esmPass->QueueForBuild(); + esmPass->QueueForBuildAndInitialization(); } for (ProjectedShadowmapsPass* shadowPass : m_projectedShadowmapsPasses) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h index b154b031c2..9d0b36d126 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h @@ -81,7 +81,7 @@ namespace AZ //! ending with 'Internal' to define the behavior of your passes. These virtual are recursively //! called in preorder traversal throughout the pass tree. Only FrameBegin and FrameEnd are //! guaranteed to be called per frame. The other override-able functions are called as needed - //! when scheduled with the PassSystem. See QueueForBuild, QueueForRemoval and QueueForInitialization. + //! when scheduled with the PassSystem. See QueueForBuildAndInitialization, QueueForRemoval and QueueForInitialization. //! //! Passes are created by the PassFactory. They can be created using either Pass Name, //! a PassTemplate, or a PassRequest. To register your pass class with the PassFactory, @@ -154,8 +154,8 @@ namespace AZ // --- Utility functions --- - //! Queues the pass to have Build() called by the PassSystem on frame update - void QueueForBuild(); + //! Queues the pass to have Build() and Initilize() called by the PassSystem on frame update + void QueueForBuildAndInitialization(); //! Queues the pass to have RemoveFromParent() called by the PassSystem on frame update void QueueForRemoval(); @@ -319,12 +319,12 @@ namespace AZ // customize it's behavior, hence why these functions are called the pass behavior functions. // Resets everything in the pass (like Attachments). - // Called from PassSystem when pass is QueueForBuild. + // Called from PassSystem when pass is QueueForBuildAndInitialization. void Reset(); virtual void ResetInternal() { } // Builds and sets up any attachments and input/output connections the pass needs. - // Called from PassSystem when pass is QueueForBuild. + // Called from PassSystem when pass is QueueForBuildAndInitialization. void Build(bool calledFromPassSystem = false); virtual void BuildInternal() { } @@ -403,7 +403,8 @@ namespace AZ uint64_t m_parentEnabled : 1; // If this is a parent pass, indicates if the pass has already created children this frame - uint64_t m_alreadyCreated : 1; + // Prevents ParentPass::CreateChildPasses from executing multiple times in the same pass + uint64_t m_alreadyCreatedChildren : 1; // If this is a parent pass, indicates whether the pass needs to create child passes uint64_t m_createChildren : 1; @@ -453,6 +454,10 @@ namespace AZ // buffers and images don't get deleted during attachment build phase void StoreImportedAttachmentReferences(); + // Used by the RenderPipeline to create it's passes immediately instead of waiting on + // the next Pass System update. The function internally build and initializes the pass. + void ManualPipelineBuildAndInitialize(); + // --- Hierarchy related functions --- // Called when the pass gets a new spot in the pass hierarchy diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassDefines.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassDefines.h index e34c61e3aa..a7513cc53c 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassDefines.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassDefines.h @@ -27,46 +27,75 @@ namespace AZ namespace RPI { // This enum tracks the state of passes across build, initialization and rendering + // + // Standard order of state progression: + // + // Uninitialized -> Queued -> Resetting -> Reset -> Building -> Built -> Initializing -> Initialized -> Idle -> Rendering -> Idle ... + // + // Addition state transitions: + // + // Queued -> Resetting + // -> Building + // -> Initializing + // + // Idle -> Queued + // -> Resetting + // -> Building + // -> Initializing + // -> Rendering + // + // Rendering -> Idle + // -> Queued (Rendering will transition to Queued if a pass was queued with the PassSystem during Rendering) + // enum class PassState : u8 { // Default value, you should only ever see this in the Pass constructor // Once the constructor is done, the Pass will set it's state to Reset Uninitialized, - + // | + // | + // V // Pass is queued with the Pass System for an update (see PassQueueState below) - // From Queued, the pass can transition into Resetting, Building or Initializing depending on the PassQueueState Queued, - + // | + // | + // V // Pass is currently in the process of resetting - // From Resetting, the pass can transition into Resetting, - - // Pass has been reset and is await build - // From Reset, the pass can transition to Building + // | + // | + // V + // Pass has been reset and is awaiting build Reset, - + // | + // | + // V // Pass is currently building - // From Building, the pass can transition to Built Building, - + // | + // | + // V // Pass has been built and is awaiting initialization - // From Built, the pass can transition to Initializing Built, - + // | + // | + // V // Pass is currently being initialized - // From Initializing, the pass can transition to Initialized Initializing, - + // | + // | + // V // Pass has been initialized - // From Initialized, the pass can transition to Idle Initialized, - + // | + // | + // V // Idle state, pass is awaiting rendering - // From Idle, the pass can transition to Queued, Resetting, Building, Initializing or Rendering Idle, - + // | + // | + // V // Pass is currently rendering. Pass must be in Idle state before entering this state - // From Rendering, the pass can transition to Idle or Queue if the pass was queued with the Pass System during Rendering Rendering }; @@ -76,15 +105,15 @@ namespace AZ // The pass is currently not in any queued state and may therefore transition to any queued state NoQueue, - // The pass is queued for Removal at the start of the next frame. Cannot be overridden by any other queue state + // The pass is queued for Removal at the start of the next frame. Has the highest priority and cannot be overridden by any other queue state QueuedForRemoval, - // The pass is queued for Build at the start of the frame. Note that any pass built at the start of the frame will also be initialized. - // This state can be overridden by QueuedForRemoval - QueuedForBuild, + // The pass is queued for Build at the start of the frame. Note that any pass built at the start of the frame will also be Initialized. + // This state can be overridden by QueuedForRemoval, as we don't want to build a pass that has been removed. + QueuedForBuildAndInitialization, // The pass is queued for Initialization at the start of the frame. - // This state has the lowest priority and can therefore be overridden by QueueForBuild or QueueForRemoval + // This state has the lowest priority and can therefore be overridden by QueueForBuildAndInitialization or QueueForRemoval. QueuedForInitialization, }; } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp index 773deafe68..cbae56e809 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp @@ -59,7 +59,7 @@ namespace AZ child->m_parent = this; child->OnHierarchyChange(); - QueueForBuild(); + QueueForBuildAndInitialization(); // Notify pipeline if (m_pipeline) @@ -249,11 +249,11 @@ namespace AZ void ParentPass::CreateChildPasses() { // The already created flag prevents this function from executing multiple times a frame - if (!m_flags.m_createChildren || m_flags.m_alreadyCreated) + if (!m_flags.m_createChildren || m_flags.m_alreadyCreatedChildren) { return; } - m_flags.m_alreadyCreated = true; + m_flags.m_alreadyCreatedChildren = true; RemoveChildren(); CreatePassesFromTemplate(); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp index 7ae3559e38..99a6e23914 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp @@ -73,7 +73,7 @@ namespace AZ } PassSystemInterface::Get()->RegisterPass(this); - QueueForBuild(); + QueueForBuildAndInitialization(); // Skip reset since the pass just got created m_state = PassState::Reset; @@ -1038,15 +1038,22 @@ namespace AZ // --- Queuing functions with PassSystem --- - void Pass::QueueForBuild() + void Pass::QueueForBuildAndInitialization() { - // Queue if not already queued or if queued for initialization only. Don't queue if we're currently building. + // Don't queue if we're currently building. Don't queue if we're already queued for Build or Removal if (m_state != PassState::Building && - (m_queueState == PassQueueState::NoQueue || m_queueState == PassQueueState::QueuedForInitialization)) + m_queueState != PassQueueState::QueuedForBuildAndInitialization && + m_queueState != PassQueueState::QueuedForRemoval) { + // NOTE: We only queue for Build here, the queue for Initialization happens at the end of Pass::Build + // (doing it this way is an optimization to minimize the number of passes queued for initialization, + // as many passes will be initialized by their parent passes and thus don't need to be queued) PassSystemInterface::Get()->QueueForBuild(this); - m_queueState = PassQueueState::QueuedForBuild; + m_queueState = PassQueueState::QueuedForBuildAndInitialization; + + // Transition state + // If we are Rendering, the state will transition [Rendering -> Queued] in Pass::FrameEnd if (m_state != PassState::Rendering) { m_state = PassState::Queued; @@ -1056,12 +1063,16 @@ namespace AZ void Pass::QueueForInitialization() { - // Only queue if the pass is not in any other queue. Don't queue if we're currently initializing. + // Only queue if the pass is not in any queue. Don't queue if we're currently initializing. if (m_queueState == PassQueueState::NoQueue && m_state != PassState::Initializing) { PassSystemInterface::Get()->QueueForInitialization(this); m_queueState = PassQueueState::QueuedForInitialization; + // Transition state + // If we are Rendering, the state will transition [Rendering -> Queued] in Pass::FrameEnd + // If the state is Built, preserve the state since [Built -> Initializing] is a valid transition + // Preserving PassState::Built lets the pass ignore subsequent build calls in the same frame if (m_state != PassState::Rendering && m_state != PassState::Built) { m_state = PassState::Queued; @@ -1072,12 +1083,14 @@ namespace AZ void Pass::QueueForRemoval() { // Skip only if we're already queued for removal, otherwise proceed. - // QueuedForRemoval overrides QueuedForBuild and QueuedForInitialization. + // QueuedForRemoval overrides QueuedForBuildAndInitialization and QueuedForInitialization. if (m_queueState != PassQueueState::QueuedForRemoval) { PassSystemInterface::Get()->QueueForRemoval(this); m_queueState = PassQueueState::QueuedForRemoval; + // Transition state + // If we are Rendering, the state will transition [Rendering -> Queued] in Pass::FrameEnd if (m_state != PassState::Rendering) { m_state = PassState::Queued; @@ -1091,7 +1104,7 @@ namespace AZ { // Ensure we're in a valid state to reset. This ensures the pass won't be reset multiple times in the same frame. bool execute = (m_state == PassState::Idle); - execute = execute || (m_state == PassState::Queued && m_queueState == PassQueueState::QueuedForBuild); + execute = execute || (m_state == PassState::Queued && m_queueState == PassQueueState::QueuedForBuildAndInitialization); execute = execute || (m_state == PassState::Queued && m_queueState == PassQueueState::QueuedForInitialization); if (!execute) @@ -1187,7 +1200,7 @@ namespace AZ void Pass::OnInitializationFinished() { - m_flags.m_alreadyCreated = false; + m_flags.m_alreadyCreatedChildren = false; m_importedAttachmentStore.clear(); OnInitializationFinishedInternal(); @@ -1305,6 +1318,13 @@ namespace AZ return m_pipeline; } + void Pass::ManualPipelineBuildAndInitialize() + { + Build(); + Initialize(); + OnInitializationFinished(); + } + Scene* Pass::GetScene() const { if (m_pipeline) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/RenderToTexturePass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/RenderToTexturePass.cpp index c0a4785365..7306bf5b6a 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/RenderToTexturePass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/RenderToTexturePass.cpp @@ -100,7 +100,7 @@ namespace AZ m_passData.m_width = width; m_passData.m_height = height; OnUpdateOutputSize(); - QueueForBuild(); + QueueForBuildAndInitialization(); } void RenderToTexturePass::OnUpdateOutputSize() diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SelectorPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SelectorPass.cpp index 90390b78d7..82cea31ca1 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SelectorPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SelectorPass.cpp @@ -72,7 +72,7 @@ namespace AZ m_connections[outputSlotIndex] = inputSlotIndex; // Queue to rebuild attachment connections - QueueForBuild(); + QueueForBuildAndInitialization(); } void SelectorPass::Connect(const AZ::Name& inputSlot, const AZ::Name& outputSlot) @@ -113,7 +113,7 @@ namespace AZ m_connections[outputIdx] = inputIdx; // Queue to rebuild attachment connections - QueueForBuild(); + QueueForBuildAndInitialization(); } } // namespace RPI diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SwapChainPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SwapChainPass.cpp index a7add17042..7b79efbaec 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SwapChainPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/SwapChainPass.cpp @@ -150,7 +150,7 @@ namespace AZ void SwapChainPass::OnWindowResized([[maybe_unused]] uint32_t width, [[maybe_unused]] uint32_t height) { - QueueForBuild(); + QueueForBuildAndInitialization(); } void SwapChainPass::ReadbackSwapChain(AZStd::shared_ptr readback) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp index 051282a7b0..891190738f 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp @@ -109,9 +109,7 @@ namespace AZ pipeline->m_rootPass->SetRenderPipeline(pipeline); // Manually build the pipeline so we can gather the view tags from it's passes - pipeline->m_rootPass->Build(); - pipeline->m_rootPass->Initialize(); - pipeline->m_rootPass->OnInitializationFinished(); + pipeline->m_rootPass->ManualPipelineBuildAndInitialize(); pipeline->BuildPipelineViews(); } @@ -327,9 +325,7 @@ namespace AZ newRoot->SetRenderPipeline(this); // Manually build the pipeline - newRoot->Build(); - newRoot->Initialize(); - newRoot->OnInitializationFinished(); + newRoot->ManualPipelineBuildAndInitialize(); // Validate the new root PassValidationResults validation; From f61635c32741ee3e39e175b7cd5b9aff22a2219e Mon Sep 17 00:00:00 2001 From: mcgarrah <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 10 Jun 2021 14:59:09 -0500 Subject: [PATCH 54/73] Updated the SystemComponents in the Default Gem and Project Templates to initialize/deinitialize the Interface instance --- .../Code/Source/${Name}EditorSystemComponent.cpp | 16 ++++++++++++++++ .../Code/Source/${Name}EditorSystemComponent.h | 3 ++- .../Code/Source/${Name}SystemComponent.cpp | 16 ++++++++++++++++ .../Code/Source/${Name}SystemComponent.h | 3 +++ .../Code/Source/${Name}SystemComponent.cpp | 2 +- 5 files changed, 38 insertions(+), 2 deletions(-) diff --git a/Templates/DefaultGem/Template/Code/Source/${Name}EditorSystemComponent.cpp b/Templates/DefaultGem/Template/Code/Source/${Name}EditorSystemComponent.cpp index 4fca5e8d3c..fedc37da6b 100644 --- a/Templates/DefaultGem/Template/Code/Source/${Name}EditorSystemComponent.cpp +++ b/Templates/DefaultGem/Template/Code/Source/${Name}EditorSystemComponent.cpp @@ -25,6 +25,22 @@ namespace ${SanitizedCppName} } } + ${SanitizedCppName}EditorSystemComponent::${SanitizedCppName}EditorSystemComponent() + { + if (${SanitizedCppName}Interface::Get() == nullptr) + { + ${SanitizedCppName}Interface::Register(this); + } + } + + ${SanitizedCppName}EditorSystemComponent::~${SanitizedCppName}EditorSystemComponent() + { + if (${SanitizedCppName}Interface::Get() == this) + { + ${SanitizedCppName}Interface::Unregister(this); + } + } + void ${SanitizedCppName}EditorSystemComponent::Activate() { AzToolsFramework::EditorEvents::Bus::Handler::BusConnect(); diff --git a/Templates/DefaultGem/Template/Code/Source/${Name}EditorSystemComponent.h b/Templates/DefaultGem/Template/Code/Source/${Name}EditorSystemComponent.h index 296d2c3bcd..ef7b0a2f2e 100644 --- a/Templates/DefaultGem/Template/Code/Source/${Name}EditorSystemComponent.h +++ b/Templates/DefaultGem/Template/Code/Source/${Name}EditorSystemComponent.h @@ -29,7 +29,8 @@ namespace ${SanitizedCppName} AZ_COMPONENT(${SanitizedCppName}EditorSystemComponent, "${EditorSysCompClassId}"); static void Reflect(AZ::ReflectContext* context); - ${SanitizedCppName}EditorSystemComponent() = default; + ${SanitizedCppName}EditorSystemComponent(); + ~${SanitizedCppName}EditorSystemComponent(); private: static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) diff --git a/Templates/DefaultGem/Template/Code/Source/${Name}SystemComponent.cpp b/Templates/DefaultGem/Template/Code/Source/${Name}SystemComponent.cpp index 214d2cfe39..8f7eabf74e 100644 --- a/Templates/DefaultGem/Template/Code/Source/${Name}SystemComponent.cpp +++ b/Templates/DefaultGem/Template/Code/Source/${Name}SystemComponent.cpp @@ -59,6 +59,22 @@ namespace ${SanitizedCppName} AZ_UNUSED(dependent); } + ${SanitizedCppName}SystemComponent::${SanitizedCppName}SystemComponent() + { + if (${SanitizedCppName}Interface::Get() == nullptr) + { + ${SanitizedCppName}Interface::Register(this); + } + } + + ${SanitizedCppName}SystemComponent::~${SanitizedCppName}SystemComponent() + { + if (${SanitizedCppName}Interface::Get() == this) + { + ${SanitizedCppName}Interface::Unregister(this); + } + } + void ${SanitizedCppName}SystemComponent::Init() { } diff --git a/Templates/DefaultGem/Template/Code/Source/${Name}SystemComponent.h b/Templates/DefaultGem/Template/Code/Source/${Name}SystemComponent.h index 5eff2e6430..8e91650c65 100644 --- a/Templates/DefaultGem/Template/Code/Source/${Name}SystemComponent.h +++ b/Templates/DefaultGem/Template/Code/Source/${Name}SystemComponent.h @@ -35,6 +35,9 @@ namespace ${SanitizedCppName} static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent); + ${SanitizedCppName}SystemComponent(); + ~${SanitizedCppName}SystemComponent(); + protected: //////////////////////////////////////////////////////////////////////// // ${SanitizedCppName}RequestBus interface implementation diff --git a/Templates/DefaultProject/Template/Code/Source/${Name}SystemComponent.cpp b/Templates/DefaultProject/Template/Code/Source/${Name}SystemComponent.cpp index 0d160bd45a..ed0a47d6db 100644 --- a/Templates/DefaultProject/Template/Code/Source/${Name}SystemComponent.cpp +++ b/Templates/DefaultProject/Template/Code/Source/${Name}SystemComponent.cpp @@ -66,7 +66,7 @@ namespace ${SanitizedCppName} ${SanitizedCppName}Interface::Register(this); } } - + ${SanitizedCppName}SystemComponent::~${SanitizedCppName}SystemComponent() { if (${SanitizedCppName}Interface::Get() == this) From 9efcc3a6b59a2adb439f248515f5a3dbb66a9b63 Mon Sep 17 00:00:00 2001 From: sconel Date: Thu, 10 Jun 2021 13:15:53 -0700 Subject: [PATCH 55/73] Fix compilation error and failing unit test --- .../Tests/Prefab/SpawnableCreateTests.cpp | 14 ++++++++++---- .../SpawnableRemoveEditorInfoTestFixture.cpp | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/SpawnableCreateTests.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/SpawnableCreateTests.cpp index af178ec7a4..5cd4cffa35 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/SpawnableCreateTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/SpawnableCreateTests.cpp @@ -15,6 +15,7 @@ #include #include +#pragma optimize("", off) namespace UnitTest { using SpawnableCreateTest = PrefabTestFixture; @@ -71,24 +72,29 @@ namespace UnitTest m_prefabSystemComponent->CreatePrefab({ entitiesCreated[0] }, {}, "test/path1")); ASSERT_TRUE(firstInstance); + ASSERT_TRUE(firstInstance->HasContainerEntity()); + expectedEntityNameSet.insert(firstInstance->GetContainerEntity()->get().GetName()); + AZStd::unique_ptr secondInstance( m_prefabSystemComponent->CreatePrefab({ entitiesCreated[1] }, MakeInstanceList(AZStd::move(firstInstance)), "test/path2")); ASSERT_TRUE(secondInstance); + ASSERT_TRUE(secondInstance->HasContainerEntity()); + expectedEntityNameSet.insert(secondInstance->GetContainerEntity()->get().GetName()); + AZStd::unique_ptr thirdInstance( m_prefabSystemComponent->CreatePrefab({ entitiesCreated[2] }, MakeInstanceList(AZStd::move(secondInstance)), "test/path3")); ASSERT_TRUE(thirdInstance); ASSERT_TRUE(thirdInstance->HasContainerEntity()); - auto& containerEntity = thirdInstance->GetContainerEntity()->get(); - expectedEntityNameSet.insert(containerEntity.GetName()); + expectedEntityNameSet.insert(thirdInstance->GetContainerEntity()->get().GetName()); //Create Spawnable auto& prefabDom = m_prefabSystemComponent->FindTemplateDom(thirdInstance->GetTemplateId()); AzFramework::Spawnable spawnable; AzToolsFramework::Prefab::SpawnableUtils::CreateSpawnable(spawnable, prefabDom); - EXPECT_EQ(spawnable.GetEntities().size() - 1, normalEntityCount); // 1 for container entity + EXPECT_EQ(spawnable.GetEntities().size(), normalEntityCount + 3); // +1 for each container entity const auto& spawnableEntities = spawnable.GetEntities(); AZStd::unordered_set actualEntityNameSet; @@ -97,6 +103,6 @@ namespace UnitTest actualEntityNameSet.insert(spawnableEntity->GetName()); } - EXPECT_EQ(expectedEntityNameSet, actualEntityNameSet); + EXPECT_EQ(actualEntityNameSet, expectedEntityNameSet); } } diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/SpawnableRemoveEditorInfoTestFixture.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/SpawnableRemoveEditorInfoTestFixture.cpp index 152d09e9b7..03ce52cfd0 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/SpawnableRemoveEditorInfoTestFixture.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/SpawnableRemoveEditorInfoTestFixture.cpp @@ -213,7 +213,7 @@ namespace UnitTest AZStd::unique_ptr convertedInstance(aznew Instance()); ASSERT_TRUE(AzToolsFramework::Prefab::PrefabDomUtils::LoadInstanceFromPrefabDom(*convertedInstance, m_prefabDom)); - convertedInstance->DetachNestedEntities( + convertedInstance->DetachAllEntitiesInHierarchy( [this](AZStd::unique_ptr entity) { m_runtimeEntities.emplace_back(entity.release()); From 607f32fae6384bdb655a466a147194477cd706e0 Mon Sep 17 00:00:00 2001 From: amzn-sj Date: Thu, 10 Jun 2021 13:34:16 -0700 Subject: [PATCH 56/73] No need to check if the first character is a number. This is already validated before. --- scripts/o3de/o3de/engine_template.py | 4 ++++ scripts/o3de/o3de/utils.py | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/o3de/o3de/engine_template.py b/scripts/o3de/o3de/engine_template.py index 05d6c5f8b9..06e34cc449 100755 --- a/scripts/o3de/o3de/engine_template.py +++ b/scripts/o3de/o3de/engine_template.py @@ -1894,6 +1894,10 @@ def create_gem(gem_path: str, # gem name is now the last component of the gem_path gem_name = os.path.basename(gem_path) + if not utils.validate_identifier(gem_name): + logger.error(f'Gem name must be fewer than 64 characters, contain only alphanumeric, "_" or "-" characters, and start with a letter. {gem_name}') + return 1 + # gem name cannot be the same as a restricted platform name if gem_name in restricted_platforms: logger.error(f'Gem path cannot be a restricted name. {gem_name}') diff --git a/scripts/o3de/o3de/utils.py b/scripts/o3de/o3de/utils.py index 6bb536f0fd..11c668a37b 100755 --- a/scripts/o3de/o3de/utils.py +++ b/scripts/o3de/o3de/utils.py @@ -46,9 +46,6 @@ def sanitize_identifier_for_cpp(identifier: str) -> str: return '' sanitized_identifier = list(identifier) - if not (sanitized_identifier[0].isalpha() or sanitized_identifier[0] == '_'): - sanitized_identifier.insert(0, '_') - for index, character in enumerate(sanitized_identifier): if not (character.isalnum() or character == '_'): sanitized_identifier[index] = '_' From 829a6fcc8d8e65764b52e2c94955d7afe1f48b09 Mon Sep 17 00:00:00 2001 From: Terry Michaels Date: Thu, 10 Jun 2021 15:42:06 -0500 Subject: [PATCH 57/73] Removed Wireframe menu option since it doesn't work with Atom (#1248) --- Code/Sandbox/Editor/MainWindow.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Code/Sandbox/Editor/MainWindow.cpp b/Code/Sandbox/Editor/MainWindow.cpp index 3753c29064..39a98236c7 100644 --- a/Code/Sandbox/Editor/MainWindow.cpp +++ b/Code/Sandbox/Editor/MainWindow.cpp @@ -833,13 +833,6 @@ void MainWindow::InitActions() .Connect(&QAction::triggered, []() { SandboxEditor::SetAngleSnapping(!SandboxEditor::AngleSnappingEnabled()); }); // Display actions - am->AddAction(ID_WIREFRAME, tr("&Wireframe")) - .SetShortcut(tr("F3")) - .SetToolTip(tr("Wireframe (F3)")) - .SetCheckable(true) - .SetStatusTip(tr("Render in Wireframe Mode.")) - .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateWireframe); - am->AddAction(ID_SWITCHCAMERA_DEFAULTCAMERA, tr("Default Camera")).SetCheckable(true) .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateSwitchToDefaultCamera); am->AddAction(ID_SWITCHCAMERA_SEQUENCECAMERA, tr("Sequence Camera")).SetCheckable(true) From 40fa0a3a46560a0c27212c0671cbd30da2c7dded Mon Sep 17 00:00:00 2001 From: sconel Date: Thu, 10 Jun 2021 13:53:25 -0700 Subject: [PATCH 58/73] Remove optimization pragma --- .../AzToolsFramework/Tests/Prefab/SpawnableCreateTests.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/SpawnableCreateTests.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/SpawnableCreateTests.cpp index 5cd4cffa35..14bd977318 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/SpawnableCreateTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/SpawnableCreateTests.cpp @@ -15,7 +15,6 @@ #include #include -#pragma optimize("", off) namespace UnitTest { using SpawnableCreateTest = PrefabTestFixture; From bf7696369686aceec4a19c704450ccfdf9363658 Mon Sep 17 00:00:00 2001 From: Ken Pruiksma Date: Thu, 10 Jun 2021 16:12:02 -0500 Subject: [PATCH 59/73] [ATOM-15683] StandardPBR shader now makes sure to mark w for no subsurface scattering. Currently all StandardPBR materials are being subject to a 2x2 box blur because the DiffuseSpecalarMerge pass thinks they have samples with subsurface scattering turned on, and this is degrading the quality of diffuse. (#1249) --- .../Assets/Materials/Types/StandardPBR_ForwardPass.azsl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl index b221ee0a33..23e4ef0c10 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl @@ -295,6 +295,10 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float lightingOutput.m_diffuseColor.rgb += lightingOutput.m_specularColor.rgb; // add specular lightingOutput.m_specularColor.rgb = baseColor * (1.0 - lightingOutput.m_diffuseColor.w); } + else + { + lightingOutput.m_diffuseColor.w = -1; // Disable subsurface scattering + } return lightingOutput; } @@ -341,4 +345,3 @@ ForwardPassOutput StandardPbr_ForwardPassPS_EDS(VSOutput IN, bool isFrontFace : #endif return OUT; } - From ffe913a2d61138a1fe4bd9e8a712eed5864db077 Mon Sep 17 00:00:00 2001 From: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> Date: Thu, 10 Jun 2021 16:16:03 -0500 Subject: [PATCH 60/73] Added ability to convert multiply-nested slices (#1239) (#1245) * Addressed feedback from previous PR * Change missing entity aliases to be deterministic. When converting slices, this helps produce the same results on multiple reconversions of the same data. * Exposed the asset filter callback. This allows the slice converter to specifically load nested slices as opposed to not loading *any* referenced assets. * Added support for multiply-nested slice instance conversion. (cherry picked from commit 86136ddfa697fd3d71202be6f5423cf35bf9df4e) --- .../Instance/InstanceEntityIdMapper.cpp | 4 +- .../SerializeContextTools/Application.cpp | 2 +- .../SerializeContextTools/SliceConverter.cpp | 241 +++++++++++++----- .../SerializeContextTools/SliceConverter.h | 30 ++- ...iceConverterEditorEntityContextComponent.h | 2 +- .../Tools/SerializeContextTools/Utilities.cpp | 10 +- Code/Tools/SerializeContextTools/Utilities.h | 6 +- 7 files changed, 223 insertions(+), 72 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceEntityIdMapper.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceEntityIdMapper.cpp index 8a72b221dc..1b28320010 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceEntityIdMapper.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceEntityIdMapper.cpp @@ -154,7 +154,7 @@ namespace AzToolsFramework InstanceOptionalReference owningInstanceReference = m_storingInstance->m_instanceEntityMapper->FindOwningInstance(entityId); // Start with an empty alias to build out our reference path - // If we can't resolve this id we'll return a random new alias instead of a reference path + // If we can't resolve this id we'll return a new alias based on the entity ID instead of a reference path AliasPath relativeEntityAliasPath; if (!owningInstanceReference) { @@ -162,7 +162,7 @@ namespace AzToolsFramework "Prefab - EntityIdMapper: Entity with Id %s has no registered owning instance", entityId.ToString().c_str()); - return Instance::GenerateEntityAlias(); + return AZStd::string::format("Entity_%s", entityId.ToString().c_str()); } Instance* owningInstance = &(owningInstanceReference->get()); diff --git a/Code/Tools/SerializeContextTools/Application.cpp b/Code/Tools/SerializeContextTools/Application.cpp index 918afd731c..274d04e7ce 100644 --- a/Code/Tools/SerializeContextTools/Application.cpp +++ b/Code/Tools/SerializeContextTools/Application.cpp @@ -35,7 +35,7 @@ namespace AZ Application::Application(int argc, char** argv) : AzToolsFramework::ToolsApplication(&argc, &argv) { - // We need a specialized variant of EditorEntityContextCompnent for the SliceConverter, so we register the descriptor here. + // We need a specialized variant of EditorEntityContextComponent for the SliceConverter, so we register the descriptor here. RegisterComponentDescriptor(AzToolsFramework::SliceConverterEditorEntityContextComponent::CreateDescriptor()); AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath(); diff --git a/Code/Tools/SerializeContextTools/SliceConverter.cpp b/Code/Tools/SerializeContextTools/SliceConverter.cpp index 56b3689d6b..9fba060960 100644 --- a/Code/Tools/SerializeContextTools/SliceConverter.cpp +++ b/Code/Tools/SerializeContextTools/SliceConverter.cpp @@ -128,8 +128,7 @@ namespace AZ return result; } - bool SliceConverter::ConvertSliceFile( - AZ::SerializeContext* serializeContext, const AZStd::string& slicePath, bool isDryRun) + bool SliceConverter::ConvertSliceFile(AZ::SerializeContext* serializeContext, const AZStd::string& slicePath, bool isDryRun) { /* To convert a slice file, we read the input file in via ObjectStream, then use the "class ready" callback to convert * the data in memory to a Prefab. @@ -177,11 +176,22 @@ namespace AZ } AZ::Entity* rootEntity = reinterpret_cast(classPtr); - return ConvertSliceToPrefab(context, outputPath, isDryRun, rootEntity); + bool convertResult = ConvertSliceToPrefab(context, outputPath, isDryRun, rootEntity); + // Clear out the references to any nested slices so that the nested assets get unloaded correctly at the end of + // the conversion. + ClearSliceAssetReferences(rootEntity); + return convertResult; }; // Read in the slice file and call the callback on completion to convert the read-in slice to a prefab. - if (!Utilities::InspectSerializedFile(inputPath.c_str(), serializeContext, callback)) + // This will also load dependent slice assets, but no other dependent asset types. + // Since we're not actually initializing any of the entities, we don't need any of the non-slice assets to be loaded. + if (!Utilities::InspectSerializedFile( + inputPath.c_str(), serializeContext, callback, + [](const AZ::Data::AssetFilterInfo& filterInfo) + { + return (filterInfo.m_assetType == azrtti_typeid()); + })) { AZ_Warning("Convert-Slice", false, "Failed to load '%s'. File may not contain an object stream.", inputPath.c_str()); result = false; @@ -256,7 +266,7 @@ namespace AZ for (auto& alias : entityAliases) { auto id = sourceInstance->GetEntityId(alias); - auto result = m_aliasIdMapper.emplace(TemplateEntityIdPair(templateId, id), alias); + auto result = m_aliasIdMapper.emplace(id, SliceEntityMappingInfo(templateId, alias)); if (!result.second) { AZ_Printf("Convert-Slice", " Duplicate entity alias -> entity id entries found, conversion may not be successful.\n"); @@ -342,10 +352,9 @@ namespace AZ // For each nested slice, convert it. for (auto& slice : sliceList) { - // Get the nested slice asset + // Get the nested slice asset. These should already be preloaded due to loading the root asset. auto sliceAsset = slice.GetSliceAsset(); - sliceAsset.QueueLoad(); - sliceAsset.BlockUntilLoadComplete(); + AZ_Assert(sliceAsset.IsReady(), "slice asset hasn't been loaded yet!"); // The slice list gives us asset IDs, and we need to get to the source path. So first we get the asset path from the ID, // then we get the source path from the asset path. @@ -429,6 +438,28 @@ namespace AZ auto instanceToTemplateInterface = AZ::Interface::Get(); auto prefabSystemComponentInterface = AZ::Interface::Get(); + // When creating the new instance, we would like to have deterministic instance aliases. Prefabs that depend on this one + // will have patches that reference the alias, so if we reconvert this slice a second time, we would like it to produce + // the same results. To get a deterministic and unique alias, we rely on the slice instance. The slice instance contains + // a map of slice entity IDs to unique instance entity IDs. We'll just consistently use the first entry in the map as the + // unique instance ID. + AZStd::string instanceAlias; + auto entityIdMap = instance.GetEntityIdMap(); + if (!entityIdMap.empty()) + { + instanceAlias = AZStd::string::format("Instance_%s", entityIdMap.begin()->second.ToString().c_str()); + } + else + { + instanceAlias = AZStd::string::format("Instance_%s", AZ::Entity::MakeId().ToString().c_str()); + } + + // Before processing any further, save off all the known entity IDs from this instance and how they map back to the base + // nested prefab that they've come from (i.e. this one). As we proceed up the chain of nesting, this will build out a + // hierarchical list of owning instances for each entity that we can trace upwards to know where to add the entity into + // our nested prefab instance. + UpdateSliceEntityInstanceMappings(instance.GetEntityIdToBaseMap(), instanceAlias); + // Create a new unmodified prefab Instance for the nested slice instance. auto nestedInstance = AZStd::make_unique(); AzToolsFramework::Prefab::Instance::EntityList newEntities; @@ -465,62 +496,125 @@ namespace AZ auto instantiated = dataPatch.Apply(&sourceObjects, dependentSlice->GetSerializeContext(), filterDesc, sourceDataFlags, targetDataFlags); - // Run through all the instantiated entities and fix up their parent hierarchy: - // - Invalid parents need to get set to the container. - // - Valid parents into the top-level instance mean that the nested slice instance is also child-nested under an entity. - // Prefabs handle this type of nesting differently - we need to set the parent to the container, and the container's - // parent to that other instance. - auto containerEntity = nestedInstance->GetContainerEntity(); - auto containerEntityId = containerEntity->get().GetId(); - for (auto entity : instantiated->m_entities) - { - AzToolsFramework::Components::TransformComponent* transformComponent = - entity->FindComponent(); - if (transformComponent) - { - bool onlySetIfInvalid = true; - auto parentId = transformComponent->GetParentId(); - if (parentId.IsValid()) - { - auto parentAlias = m_aliasIdMapper.find(TemplateEntityIdPair(topLevelInstance->GetTemplateId(), parentId)); - if (parentAlias != m_aliasIdMapper.end()) - { - // Set the container's parent to this entity's parent, and set this entity's parent to the container - // (i.e. go from A->B to A->container->B) - auto newParentId = topLevelInstance->GetEntityId(parentAlias->second); - SetParentEntity(containerEntity->get(), newParentId, false); - onlySetIfInvalid = false; - } - } - - SetParentEntity(*entity, containerEntityId, onlySetIfInvalid); - } - } - - // Replace all the entities in the instance with the new patched ones. + // Replace all the entities in the instance with the new patched ones. To do this, we'll remove all existing entities + // throughout the entire nested hierarchy, then add the new patched entities back in at the appropriate place in the hierarchy. // (This is easier than trying to figure out what the patched data changes are - we can let the JSON patch handle it for us) + nestedInstance->RemoveNestedEntities( [](const AZStd::unique_ptr&) { return true; }); + + AZStd::vector> addedEntityList; + for (auto& entity : instantiated->m_entities) { - auto entityAlias = m_aliasIdMapper.find(TemplateEntityIdPair(nestedInstance->GetTemplateId(), entity->GetId())); - if (entityAlias != m_aliasIdMapper.end()) + auto entityEntry = m_aliasIdMapper.find(entity->GetId()); + if (entityEntry != m_aliasIdMapper.end()) { - nestedInstance->AddEntity(*entity, entityAlias->second); + auto& mappingStruct = entityEntry->second; + + // Starting with the current nested instance, walk downwards through the nesting hierarchy until we're at the + // correct level for this instanced entity ID, then add it. Because we're adding it with the non-instanced alias, + // it doesn't matter what the slice's instanced entity ID is, and the JSON patch will correctly pick up the changes + // we've made for this instance. + AzToolsFramework::Prefab::Instance* addingInstance = nestedInstance.get(); + for (auto it = mappingStruct.m_nestedInstanceAliases.rbegin(); it != mappingStruct.m_nestedInstanceAliases.rend(); it++) + { + auto foundInstance = addingInstance->FindNestedInstance(*it); + if (foundInstance.has_value()) + { + addingInstance = &(foundInstance->get()); + } + else + { + AZ_Assert(false, "Couldn't find nested instance %s", it->c_str()); + } + } + addingInstance->AddEntity(*entity, mappingStruct.m_entityAlias); + addedEntityList.emplace_back(entity, addingInstance); } else { AZ_Assert(false, "Failed to find entity alias."); nestedInstance->AddEntity(*entity); + addedEntityList.emplace_back(entity, nestedInstance.get()); + } + } + + for (auto& [entity, addingInstance] : addedEntityList) + { + // Fix up the parent hierarchy: + // - Invalid parents need to get set to the container. + // - Valid parents into the top-level instance mean that the nested slice instance is also child-nested under an entity. + // Prefabs handle this type of nesting differently - we need to set the parent to the container, and the container's + // parent to that other instance. + auto containerEntity = addingInstance->GetContainerEntity(); + auto containerEntityId = containerEntity->get().GetId(); + AzToolsFramework::Components::TransformComponent* transformComponent = + entity->FindComponent(); + if (transformComponent) + { + bool onlySetIfInvalid = true; + auto parentId = transformComponent->GetParentId(); + if (parentId.IsValid()) + { + // Look to see if the parent ID exists in the same instance (i.e. an entity in the nested slice is a + // child of an entity in the containing slice). If this case exists, we need to adjust the parents so that + // the child entity connects to the prefab container, and the *container* is the child of the entity in the + // containing slice. (i.e. go from A->B to A->container->B) + auto parentEntry = m_aliasIdMapper.find(parentId); + if (parentEntry != m_aliasIdMapper.end()) + { + auto& parentMappingInfo = parentEntry->second; + if (parentMappingInfo.m_templateId != addingInstance->GetTemplateId()) + { + if (topLevelInstance->GetTemplateId() == parentMappingInfo.m_templateId) + { + parentId = topLevelInstance->GetEntityId(parentMappingInfo.m_entityAlias); + } + else + { + AzToolsFramework::Prefab::Instance* parentInstance = addingInstance; + + while ((parentInstance->GetParentInstance().has_value()) && + (parentInstance->GetTemplateId() != parentMappingInfo.m_templateId)) + { + parentInstance = &(parentInstance->GetParentInstance()->get()); + } + + if (parentInstance->GetTemplateId() == parentMappingInfo.m_templateId) + { + parentId = parentInstance->GetEntityId(parentMappingInfo.m_entityAlias); + } + else + { + AZ_Assert(false, "Could not find parent instance"); + } + } + + // Set the container's parent to this entity's parent, and set this entity's parent to the container + // auto newParentId = topLevelInstance->GetEntityId(parentMappingInfo.m_entityAlias); + SetParentEntity(containerEntity->get(), parentId, false); + onlySetIfInvalid = false; + } + } + + // If the parent ID is valid, but NOT in the top-level instance, then it's just a nested hierarchy inside + // the slice and we don't need to adjust anything. "onlySetIfInvalid" will still be true, which means we + // won't change the parent ID below. + } + + SetParentEntity(*entity, containerEntityId, onlySetIfInvalid); } } + // Set the container entity of the nested prefab to have the top-level prefab as the parent if it hasn't already gotten // another entity as its parent. { + auto containerEntity = nestedInstance->GetContainerEntity(); constexpr bool onlySetIfInvalid = true; SetParentEntity(containerEntity->get(), topLevelInstance->GetContainerEntityId(), onlySetIfInvalid); } @@ -531,21 +625,7 @@ namespace AZ AzToolsFramework::Prefab::PrefabDom topLevelInstanceDomBefore; instanceToTemplateInterface->GenerateDomForInstance(topLevelInstanceDomBefore, *topLevelInstance); - // When creating the new instance, we would like to have deterministic instance aliases. Prefabs that depend on this one - // will have patches that reference the alias, so if we reconvert this slice a second time, we would like it to produce - // the same results. To get a deterministic and unique alias, we rely on the slice instance. The slice instance contains - // a map of slice entity IDs to unique instance entity IDs. We'll just consistently use the first entry in the map as the - // unique instance ID. - AZStd::string instanceAlias; - auto entityIdMap = instance.GetEntityIdMap(); - if (!entityIdMap.empty()) - { - instanceAlias = AZStd::string::format("Instance_%s", entityIdMap.begin()->second.ToString().c_str()); - } - else - { - instanceAlias = AZStd::string::format("Instance_%s", AZ::Entity::MakeId().ToString().c_str()); - } + // Use the deterministic instance alias for this new instance AzToolsFramework::Prefab::Instance& addedInstance = topLevelInstance->AddInstance(AZStd::move(nestedInstance), instanceAlias); AzToolsFramework::Prefab::PrefabDom topLevelInstanceDomAfter; @@ -670,5 +750,48 @@ namespace AZ AZ_Error("Convert-Slice", disconnected, "Asset Processor failed to disconnect successfully."); } + void SliceConverter::ClearSliceAssetReferences(AZ::Entity* rootEntity) + { + SliceComponent* sliceComponent = AZ::EntityUtils::FindFirstDerivedComponent(rootEntity); + // Make a copy of the slice list and remove all of them from the loaded component. + AZ::SliceComponent::SliceList slices = sliceComponent->GetSlices(); + for (auto& slice : slices) + { + sliceComponent->RemoveSlice(&slice); + } + } + + void SliceConverter::UpdateSliceEntityInstanceMappings( + const AZ::SliceComponent::EntityIdToEntityIdMap& sliceEntityIdMap, const AZStd::string& currentInstanceAlias) + { + // For each instanced entity, map its ID all the way back to the original prefab template and entity ID that it came from. + // This counts on being run recursively from the leaf nodes upwards, so we first get B->A, + // then C->B which becomes a C->A entry, then D->C which becomes D->A, etc. + for (auto& [newId, oldId] : sliceEntityIdMap) + { + // Try to find the conversion chain from the old ID. if it's there, copy it and use it for the new ID, plus add this + // instance's name to the end of the chain. If it's not there, skip it, since it's probably the slice metadata entity, + // which we didn't convert. + auto parentEntry = m_aliasIdMapper.find(oldId); + if (parentEntry != m_aliasIdMapper.end()) + { + // Only add this instance's name if we don't already have an entry for the new ID. + if (m_aliasIdMapper.find(newId) == m_aliasIdMapper.end()) + { + auto newMappingEntry = m_aliasIdMapper.emplace(newId, parentEntry->second).first; + newMappingEntry->second.m_nestedInstanceAliases.emplace_back(currentInstanceAlias); + } + else + { + // If we already had an entry for the new ID, it might be because the old and new ID are the same. This happens + // when nesting multiple prefabs directly underneath each other without a nesting entity in-between. + // If the IDs are different, it's an unexpected error condition. + AZ_Assert(oldId == newId, "The same entity instance ID has unexpectedly appeared twice in the same nested prefab."); + } + } + } + } + + } // namespace SerializeContextTools } // namespace AZ diff --git a/Code/Tools/SerializeContextTools/SliceConverter.h b/Code/Tools/SerializeContextTools/SliceConverter.h index 82dcf30383..ee0bb0a539 100644 --- a/Code/Tools/SerializeContextTools/SliceConverter.h +++ b/Code/Tools/SerializeContextTools/SliceConverter.h @@ -42,8 +42,6 @@ namespace AZ bool ConvertSliceFiles(Application& application); private: - using TemplateEntityIdPair = AZStd::pair; - bool ConnectToAssetProcessor(); void DisconnectFromAssetProcessor(); @@ -60,10 +58,32 @@ namespace AZ void SetParentEntity(const AZ::Entity& entity, const AZ::EntityId& parentId, bool onlySetIfInvalid); void PrintPrefab(AzToolsFramework::Prefab::TemplateId templateId); bool SavePrefab(AZ::IO::PathView outputPath, AzToolsFramework::Prefab::TemplateId templateId); + void ClearSliceAssetReferences(AZ::Entity* rootEntity); + void UpdateSliceEntityInstanceMappings( + const AZ::SliceComponent::EntityIdToEntityIdMap& sliceEntityIdMap, + const AZStd::string& currentInstanceAlias); + + // When converting slice entities, especially for nested slices, we need to keep track of the original + // entity ID, the entity alias it uses in the prefab, and which template and nested instance path it maps to. + // As we encounter each instanced entity ID, we can look it up in this structure and use this to determine how to properly + // add it to the correct place in the hierarchy. + struct SliceEntityMappingInfo + { + SliceEntityMappingInfo(AzToolsFramework::Prefab::TemplateId templateId, AzToolsFramework::Prefab::EntityAlias entityAlias) + : m_templateId(templateId) + , m_entityAlias(entityAlias) + { + } + + AzToolsFramework::Prefab::TemplateId m_templateId; + AzToolsFramework::Prefab::EntityAlias m_entityAlias; + AZStd::vector m_nestedInstanceAliases; + }; - // Track all of the entity IDs created and the prefab entity aliases that map to them. This mapping is used - // with nested slice conversion to remap parent entity IDs to the correct prefab entity IDs. - AZStd::unordered_map m_aliasIdMapper; + // Track all of the entity IDs created and associate them with enough conversion information to know how to place the + // entities in the correct place in the prefab hierarchy and fix up parent entity ID mappings to work with the nested + // prefab schema. + AZStd::unordered_map m_aliasIdMapper; // Track all of the created prefab template IDs on a slice conversion so that they can get removed at the end of the // conversion for that file. diff --git a/Code/Tools/SerializeContextTools/SliceConverterEditorEntityContextComponent.h b/Code/Tools/SerializeContextTools/SliceConverterEditorEntityContextComponent.h index 166cb2abdf..07246b20a7 100644 --- a/Code/Tools/SerializeContextTools/SliceConverterEditorEntityContextComponent.h +++ b/Code/Tools/SerializeContextTools/SliceConverterEditorEntityContextComponent.h @@ -36,7 +36,7 @@ namespace AzToolsFramework SliceConverterEditorEntityContextComponent() : EditorEntityContextComponent() {} // Simple API to selectively disable this logic *only* when performing slice to prefab conversion. - static void DisableOnContextEntityLogic() + static inline void DisableOnContextEntityLogic() { m_enableOnContextEntityLogic = false; } diff --git a/Code/Tools/SerializeContextTools/Utilities.cpp b/Code/Tools/SerializeContextTools/Utilities.cpp index cfd75a44e7..d39a71dd24 100644 --- a/Code/Tools/SerializeContextTools/Utilities.cpp +++ b/Code/Tools/SerializeContextTools/Utilities.cpp @@ -209,7 +209,11 @@ namespace AZ::SerializeContextTools return result; } - bool Utilities::InspectSerializedFile(const char* filePath, SerializeContext* sc, const ObjectStream::ClassReadyCB& classCallback) + bool Utilities::InspectSerializedFile( + const char* filePath, + SerializeContext* sc, + const ObjectStream::ClassReadyCB& classCallback, + Data::AssetFilterCB assetFilterCallback) { if (!AZ::IO::FileIOBase::GetInstance()->Exists(filePath)) { @@ -248,9 +252,9 @@ namespace AZ::SerializeContextTools AZ::IO::MemoryStream stream(data.data(), fileLength); ObjectStream::FilterDescriptor filter; - // Never load dependencies. That's another file that would need to be processed + // By default, never load dependencies. That's another file that would need to be processed // separately from this one. - filter.m_assetCB = AZ::Data::AssetFilterNoAssetLoading; + filter.m_assetCB = assetFilterCallback; if (!ObjectStream::LoadBlocking(&stream, *sc, classCallback, filter)) { AZ_Printf("Verify", "Failed to deserialize '%s'\n", filePath); diff --git a/Code/Tools/SerializeContextTools/Utilities.h b/Code/Tools/SerializeContextTools/Utilities.h index f08bfc2f64..9c9cd28ac6 100644 --- a/Code/Tools/SerializeContextTools/Utilities.h +++ b/Code/Tools/SerializeContextTools/Utilities.h @@ -39,7 +39,11 @@ namespace AZ static AZStd::vector GetSystemComponents(const Application& application); - static bool InspectSerializedFile(const char* filePath, SerializeContext* sc, const ObjectStream::ClassReadyCB& classCallback); + static bool InspectSerializedFile( + const char* filePath, + SerializeContext* sc, + const ObjectStream::ClassReadyCB& classCallback, + Data::AssetFilterCB assetFilterCallback = AZ::Data::AssetFilterNoAssetLoading); private: Utilities() = delete; From b18b03b8fb8d1a79d14fead2475fea25d1c4b660 Mon Sep 17 00:00:00 2001 From: moudgils Date: Thu, 10 Jun 2021 14:40:52 -0700 Subject: [PATCH 61/73] Added comments and more format fixes --- .../Shaders/MorphTargets/MorphTargetSRG.azsli | 3 +++ .../LuminanceHistogramGenerator.azsl | 4 +++ .../RHI/DX12/Code/Source/RHI/Conversions.cpp | 10 +++++++ .../Metal/Code/Source/RHI/ArgumentBuffer.cpp | 26 +++++++++---------- .../Metal/Code/Source/RHI/ArgumentBuffer.h | 13 +++++++--- .../RHI/Metal/Code/Source/RHI/CommandList.h | 6 ++++- .../RHI/Metal/Code/Source/RHI/Conversions.cpp | 10 +++++++ .../RHI/Vulkan/Code/Source/RHI/Conversion.cpp | 6 +++++ 8 files changed, 60 insertions(+), 18 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/MorphTargets/MorphTargetSRG.azsli b/Gems/Atom/Feature/Common/Assets/Shaders/MorphTargets/MorphTargetSRG.azsli index 83193c8559..f4b1beeb3e 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/MorphTargets/MorphTargetSRG.azsli +++ b/Gems/Atom/Feature/Common/Assets/Shaders/MorphTargets/MorphTargetSRG.azsli @@ -16,6 +16,9 @@ ShaderResourceGroup MorphTargetPassSrg : SRG_PerPass { + //Since we do Interlocked atomic operations on this buffer it can not be RWBuffer due to broken MetalSL generation. + //It stems from the fact that typed buffers gets converted to textures and that breaks with atomic operations. + //In future we can handle this under the hood via our metal shader pipeline RWStructuredBuffer m_accumulatedDeltas; } diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/LuminanceHistogramGenerator.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/LuminanceHistogramGenerator.azsl index 9d01a12fd6..ee95515a2a 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/LuminanceHistogramGenerator.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/LuminanceHistogramGenerator.azsl @@ -20,6 +20,10 @@ ShaderResourceGroup PassSrg : SRG_PerPass { Texture2D m_inputTexture; + + //Since we do Interlocked atomic operations on this buffer it can not be RWBuffer due to broken MetalSL generation. + //It stems from the fact that typed buffers gets converted to textures and that breaks with atomic operations. + //In future we can handle this under the hood via our metal shader pipeline RWStructuredBuffer m_outputTexture; } diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.cpp index 73d80ed78c..9776734158 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.cpp @@ -1360,6 +1360,16 @@ namespace AZ uint32_t ConvertColorWriteMask(uint8_t writeMask) { uint32_t dflags = 0; + if(writeMask == 0) + { + return dflags; + } + + if(RHI::CheckBitsAll(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskAll))) + { + return D3D12_COLOR_WRITE_ENABLE_ALL; + } + if (RHI::CheckBitsAny(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskRed))) { dflags |= D3D12_COLOR_WRITE_ENABLE_RED; diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp index 680481d417..49ff4146fc 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp @@ -397,19 +397,18 @@ namespace AZ uint8_t numBitsSet = RHI::CountBitsSet(static_cast(srgResourcesVisInfo.m_constantDataStageMask)); if( numBitsSet > 0) { + id mtlconstantBufferResource = m_constantBuffer.GetGpuAddress>(); if(RHI::CheckBitsAny(srgResourcesVisInfo.m_constantDataStageMask, RHI::ShaderStageMask::Compute)) { - uint16_t arrayIndex = resourcesToMakeResidentCompute[MTLResourceUsageRead].m_resourceArrayLen; - resourcesToMakeResidentCompute[MTLResourceUsageRead].m_resourceArray[arrayIndex] = m_constantBuffer.GetGpuAddress>(); - resourcesToMakeResidentCompute[MTLResourceUsageRead].m_resourceArrayLen++; + uint16_t arrayIndex = resourcesToMakeResidentCompute[MTLResourceUsageRead].m_resourceArrayLen++; + resourcesToMakeResidentCompute[MTLResourceUsageRead].m_resourceArray[arrayIndex] = mtlconstantBufferResource; } else { MTLRenderStages mtlRenderStages = GetRenderStages(srgResourcesVisInfo.m_constantDataStageMask); AZStd::pair key = AZStd::make_pair(MTLResourceUsageRead, mtlRenderStages); - uint16_t arrayIndex = resourcesToMakeResidentGraphics[key].m_resourceArrayLen; - resourcesToMakeResidentGraphics[key].m_resourceArray[arrayIndex] = m_constantBuffer.GetGpuAddress>(); - resourcesToMakeResidentGraphics[key].m_resourceArrayLen++; + uint16_t arrayIndex = resourcesToMakeResidentGraphics[key].m_resourceArrayLen++; + resourcesToMakeResidentGraphics[key].m_resourceArray[arrayIndex] = mtlconstantBufferResource; } } } @@ -431,7 +430,8 @@ namespace AZ } else { - AZ_Assert(RHI::CheckBitsAny(visMaskIt->second, RHI::ShaderStageMask::Vertex) || RHI::CheckBitsAny(visMaskIt->second, RHI::ShaderStageMask::Fragment), "The visibility mask %i is not set for Vertex or fragment stage", visMaskIt->second); + bool isBoundToGraphics = RHI::CheckBitsAny(visMaskIt->second, RHI::ShaderStageMask::Vertex) || RHI::CheckBitsAny(visMaskIt->second, RHI::ShaderStageMask::Fragment); + AZ_Assert(isBoundToGraphics, "The visibility mask %i is not set for Vertex or fragment stage", visMaskIt->second); CollectResourcesForGraphics(commandEncoder, visMaskIt->second, it.second, resourcesToMakeResidentGraphics); } } @@ -480,9 +480,9 @@ namespace AZ AZ_Assert(false, "Undefined Resource type"); } } - uint16_t arrayIndex = resourcesToMakeResidentMap[resourceUsage].m_resourceArrayLen; - resourcesToMakeResidentMap[resourceUsage].m_resourceArray[arrayIndex] = resourceBindingData.m_resourcPtr->GetGpuAddress>(); - resourcesToMakeResidentMap[resourceUsage].m_resourceArrayLen++; + uint16_t arrayIndex = resourcesToMakeResidentMap[resourceUsage].m_resourceArrayLen++; + id mtlResourceToBind = resourceBindingData.m_resourcPtr->GetGpuAddress>(); + resourcesToMakeResidentMap[resourceUsage].m_resourceArray[arrayIndex] = mtlResourceToBind; } } @@ -516,9 +516,9 @@ namespace AZ } AZStd::pair key = AZStd::make_pair(resourceUsage, mtlRenderStages); - uint16_t arrayIndex = resourcesToMakeResidentMap[key].m_resourceArrayLen; - resourcesToMakeResidentMap[key].m_resourceArray[arrayIndex] = resourceBindingData.m_resourcPtr->GetGpuAddress>(); - resourcesToMakeResidentMap[key].m_resourceArrayLen++; + uint16_t arrayIndex = resourcesToMakeResidentMap[key].m_resourceArrayLen++; + id mtlResourceToBind = resourceBindingData.m_resourcPtr->GetGpuAddress>(); + resourcesToMakeResidentMap[key].m_resourceArray[arrayIndex] = mtlResourceToBind; } } } diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h index 0825c07654..c4cfd17390 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h @@ -126,12 +126,17 @@ namespace AZ uint16_t m_resourceArrayLen = 0; }; //Map to cache all the resources based on the usage as we can batch all the resources for a given usage - using ComputeResourcesToMakeResidentMap = AZStd::unordered_map; + using ComputeResourcesToMakeResidentMap = AZStd::unordered_map; //Map to cache all the resources based on the usage and shader stage as we can batch all the resources for a given usage/shader usage - using GraphicsResourcesToMakeResidentMap = AZStd::unordered_map, MetalResourceArray>; + using GraphicsResourcesToMakeResidentMap = AZStd::unordered_map, MetalResourceArray>; - void CollectResourcesForCompute(id encoder, const ResourceBindingsSet& resourceBindingData, ComputeResourcesToMakeResidentMap& resourcesToMakeResidentMap) const; - void CollectResourcesForGraphics(id encoder, RHI::ShaderStageMask visShaderMask, const ResourceBindingsSet& resourceBindingDataSet, GraphicsResourcesToMakeResidentMap& resourcesToMakeResidentMap) const; + void CollectResourcesForCompute(id encoder, + const ResourceBindingsSet& resourceBindingData, + ComputeResourcesToMakeResidentMap& resourcesToMakeResidentMap) const; + void CollectResourcesForGraphics(id encoder, + RHI::ShaderStageMask visShaderMask, + const ResourceBindingsSet& resourceBindingDataSet, + GraphicsResourcesToMakeResidentMap& resourcesToMakeResidentMap) const; //! Use visibility information to call UseResource on all resources for this Argument Buffer void ApplyUseResource(id encoder, const ResourceBindingsMap& resourceMap, diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.h b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.h index 9dd14cd175..8674124cc2 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.h +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.h @@ -104,7 +104,11 @@ namespace AZ using MetalArgumentBufferArray = AZStd::array, RHI::Limits::Pipeline::ShaderResourceGroupCountMax>; using MetalArgumentBufferArrayOffsets = AZStd::array; - void BindArgumentBuffers(RHI::ShaderStage shaderStage, uint16_t registerIdMin, uint16_t registerIdMax, MetalArgumentBufferArray& mtlArgBuffers, MetalArgumentBufferArrayOffsets mtlArgBufferOffsets); + void BindArgumentBuffers(RHI::ShaderStage shaderStage, + uint16_t registerIdMin, + uint16_t registerIdMax, + MetalArgumentBufferArray& mtlArgBuffers, + MetalArgumentBufferArrayOffsets mtlArgBufferOffsets); ShaderResourceBindings& GetShaderResourceBindingsByPipelineType(RHI::PipelineStateType pipelineType); diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/Conversions.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/Conversions.cpp index e41ba9bf2a..81e589e62e 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/Conversions.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/Conversions.cpp @@ -458,6 +458,16 @@ namespace AZ MTLColorWriteMask ConvertColorWriteMask(AZ::u8 writeMask) { MTLColorWriteMask colorMask = MTLColorWriteMaskNone; + if(writeMask == 0) + { + return colorMask; + } + + if(RHI::CheckBitsAll(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskAll))) + { + return MTLColorWriteMaskAll; + } + if (RHI::CheckBitsAny(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskRed))) { colorMask |= MTLColorWriteMaskRed; diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp index 7945dd2894..5ce9731506 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp @@ -334,6 +334,12 @@ namespace AZ VkColorComponentFlags ConvertComponentFlags(uint8_t sflags) { VkColorComponentFlags dflags = 0; + + if(sflags == 0) + { + return dflags; + } + if (RHI::CheckBitsAny(sflags, static_cast(RHI::WriteChannelMask::ColorWriteMaskRed))) { dflags |= VK_COLOR_COMPONENT_R_BIT; From cf5a73eef8c9efb57c65f700f165ff3f75bbd820 Mon Sep 17 00:00:00 2001 From: amzn-sj Date: Thu, 10 Jun 2021 14:47:16 -0700 Subject: [PATCH 62/73] Fix default destructor declaration --- Templates/DefaultGem/Template/Code/Include/${Name}/${Name}Bus.h | 2 +- .../DefaultProject/Template/Code/Include/${Name}/${Name}Bus.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Templates/DefaultGem/Template/Code/Include/${Name}/${Name}Bus.h b/Templates/DefaultGem/Template/Code/Include/${Name}/${Name}Bus.h index 7501e29796..32f34e309e 100644 --- a/Templates/DefaultGem/Template/Code/Include/${Name}/${Name}Bus.h +++ b/Templates/DefaultGem/Template/Code/Include/${Name}/${Name}Bus.h @@ -23,7 +23,7 @@ namespace ${SanitizedCppName} { public: AZ_RTTI(${SanitizedCppName}Requests, "${Random_Uuid}"); - virtual ~${SanitizedCppName}Requests = default(); + virtual ~${SanitizedCppName}Requests() = default; // Put your public methods here }; diff --git a/Templates/DefaultProject/Template/Code/Include/${Name}/${Name}Bus.h b/Templates/DefaultProject/Template/Code/Include/${Name}/${Name}Bus.h index b4a61ccd63..05e434ec03 100644 --- a/Templates/DefaultProject/Template/Code/Include/${Name}/${Name}Bus.h +++ b/Templates/DefaultProject/Template/Code/Include/${Name}/${Name}Bus.h @@ -23,7 +23,7 @@ namespace ${SanitizedCppName} { public: AZ_RTTI(${SanitizedCppName}Requests, "${Random_Uuid}"); - virtual ~${SanitizedCppName}Requests = default(); + virtual ~${SanitizedCppName}Requests() = default; // Put your public methods here }; From 963894c7e3edbbca9f2891a6412b56a9c92eae31 Mon Sep 17 00:00:00 2001 From: moudgils Date: Thu, 10 Jun 2021 15:00:42 -0700 Subject: [PATCH 63/73] Modified the WriteColoorMask --- Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.cpp | 10 +++++----- Gems/Atom/RHI/Metal/Code/Source/RHI/Conversions.cpp | 10 +++++----- Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp | 13 +++++++++---- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.cpp index 9776734158..8c7b9f4389 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.cpp @@ -1365,24 +1365,24 @@ namespace AZ return dflags; } - if(RHI::CheckBitsAll(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskAll))) + if(RHI::CheckBitsAll(writeMask, RHI::WriteChannelMask::ColorWriteMaskAll)) { return D3D12_COLOR_WRITE_ENABLE_ALL; } - if (RHI::CheckBitsAny(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskRed))) + if (RHI::CheckBitsAny(writeMask, RHI::WriteChannelMask::ColorWriteMaskRed)) { dflags |= D3D12_COLOR_WRITE_ENABLE_RED; } - if (RHI::CheckBitsAny(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskGreen))) + if (RHI::CheckBitsAny(writeMask, RHI::WriteChannelMask::ColorWriteMaskGreen)) { dflags |= D3D12_COLOR_WRITE_ENABLE_GREEN; } - if (RHI::CheckBitsAny(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskBlue))) + if (RHI::CheckBitsAny(writeMask, RHI::WriteChannelMask::ColorWriteMaskBlue)) { dflags |= D3D12_COLOR_WRITE_ENABLE_BLUE; } - if (RHI::CheckBitsAny(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskAlpha))) + if (RHI::CheckBitsAny(writeMask, RHI::WriteChannelMask::ColorWriteMaskAlpha)) { dflags |= D3D12_COLOR_WRITE_ENABLE_ALPHA; } diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/Conversions.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/Conversions.cpp index 81e589e62e..5b153fd648 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/Conversions.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/Conversions.cpp @@ -463,24 +463,24 @@ namespace AZ return colorMask; } - if(RHI::CheckBitsAll(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskAll))) + if(RHI::CheckBitsAll(writeMask, RHI::WriteChannelMask::ColorWriteMaskAll)) { return MTLColorWriteMaskAll; } - if (RHI::CheckBitsAny(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskRed))) + if (RHI::CheckBitsAny(writeMask, RHI::WriteChannelMask::ColorWriteMaskRed)) { colorMask |= MTLColorWriteMaskRed; } - if (RHI::CheckBitsAny(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskGreen))) + if (RHI::CheckBitsAny(writeMask, RHI::WriteChannelMask::ColorWriteMaskGreen)) { colorMask |= MTLColorWriteMaskGreen; } - if (RHI::CheckBitsAny(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskBlue))) + if (RHI::CheckBitsAny(writeMask, RHI::WriteChannelMask::ColorWriteMaskBlue)) { colorMask |= MTLColorWriteMaskBlue; } - if (RHI::CheckBitsAny(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskAlpha))) + if (RHI::CheckBitsAny(writeMask, RHI::WriteChannelMask::ColorWriteMaskAlpha)) { colorMask |= MTLColorWriteMaskAlpha; } diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp index 5ce9731506..1ba002748b 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp @@ -340,19 +340,24 @@ namespace AZ return dflags; } - if (RHI::CheckBitsAny(sflags, static_cast(RHI::WriteChannelMask::ColorWriteMaskRed))) + if(RHI::CheckBitsAll(writeMask, RHI::WriteChannelMask::ColorWriteMaskAll)) + { + return VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + } + + if (RHI::CheckBitsAny(sflags, RHI::WriteChannelMask::ColorWriteMaskRed)) { dflags |= VK_COLOR_COMPONENT_R_BIT; } - if (RHI::CheckBitsAny(sflags, static_cast(RHI::WriteChannelMask::ColorWriteMaskGreen))) + if (RHI::CheckBitsAny(sflags, RHI::WriteChannelMask::ColorWriteMaskGreen)) { dflags |= VK_COLOR_COMPONENT_G_BIT; } - if (RHI::CheckBitsAny(sflags, static_cast(RHI::WriteChannelMask::ColorWriteMaskBlue))) + if (RHI::CheckBitsAny(sflags, RHI::WriteChannelMask::ColorWriteMaskBlue)) { dflags |= VK_COLOR_COMPONENT_B_BIT; } - if (RHI::CheckBitsAny(sflags, static_cast(RHI::WriteChannelMask::ColorWriteMaskAlpha))) + if (RHI::CheckBitsAny(sflags, RHI::WriteChannelMask::ColorWriteMaskAlpha)) { dflags |= VK_COLOR_COMPONENT_A_BIT; } From c0cfe239fe8c4b4aa26a85a34ee188177f6a4bec Mon Sep 17 00:00:00 2001 From: moudgils Date: Thu, 10 Jun 2021 15:03:08 -0700 Subject: [PATCH 64/73] Modify WritecolorMask --- .../Include/Atom/RHI.Reflect/RenderStates.h | 18 +++++------------- .../RHI/DX12/Code/Source/RHI/Conversions.cpp | 10 +++++----- .../RHI/Metal/Code/Source/RHI/Conversions.cpp | 10 +++++----- .../RHI/Vulkan/Code/Source/RHI/Conversion.cpp | 10 +++++----- 4 files changed, 20 insertions(+), 28 deletions(-) diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/RenderStates.h b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/RenderStates.h index d5c55e2c7f..651be829b5 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/RenderStates.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/RenderStates.h @@ -160,21 +160,13 @@ namespace AZ StencilState m_stencil; }; - enum class WriteChannel : uint32_t - { - ColorWriteMaskRed = 0, - ColorWriteMaskGreen, - ColorWriteMaskBlue, - ColorWriteMaskAlpha, - }; - - enum class WriteChannelMask : uint32_t + enum class WriteChannelMask : uint8_t { ColorWriteMaskNone = 0, - ColorWriteMaskRed = AZ_BIT(static_cast(WriteChannel::ColorWriteMaskRed)), - ColorWriteMaskGreen = AZ_BIT(static_cast(WriteChannel::ColorWriteMaskGreen)), - ColorWriteMaskBlue = AZ_BIT(static_cast(WriteChannel::ColorWriteMaskBlue)), - ColorWriteMaskAlpha = AZ_BIT(static_cast(WriteChannel::ColorWriteMaskAlpha)), + ColorWriteMaskRed = AZ_BIT(0), + ColorWriteMaskGreen = AZ_BIT(1), + ColorWriteMaskBlue = AZ_BIT(2), + ColorWriteMaskAlpha = AZ_BIT(3), ColorWriteMaskAll = ColorWriteMaskRed | ColorWriteMaskGreen | ColorWriteMaskBlue | ColorWriteMaskAlpha }; diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.cpp index 8c7b9f4389..9776734158 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.cpp @@ -1365,24 +1365,24 @@ namespace AZ return dflags; } - if(RHI::CheckBitsAll(writeMask, RHI::WriteChannelMask::ColorWriteMaskAll)) + if(RHI::CheckBitsAll(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskAll))) { return D3D12_COLOR_WRITE_ENABLE_ALL; } - if (RHI::CheckBitsAny(writeMask, RHI::WriteChannelMask::ColorWriteMaskRed)) + if (RHI::CheckBitsAny(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskRed))) { dflags |= D3D12_COLOR_WRITE_ENABLE_RED; } - if (RHI::CheckBitsAny(writeMask, RHI::WriteChannelMask::ColorWriteMaskGreen)) + if (RHI::CheckBitsAny(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskGreen))) { dflags |= D3D12_COLOR_WRITE_ENABLE_GREEN; } - if (RHI::CheckBitsAny(writeMask, RHI::WriteChannelMask::ColorWriteMaskBlue)) + if (RHI::CheckBitsAny(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskBlue))) { dflags |= D3D12_COLOR_WRITE_ENABLE_BLUE; } - if (RHI::CheckBitsAny(writeMask, RHI::WriteChannelMask::ColorWriteMaskAlpha)) + if (RHI::CheckBitsAny(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskAlpha))) { dflags |= D3D12_COLOR_WRITE_ENABLE_ALPHA; } diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/Conversions.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/Conversions.cpp index 5b153fd648..81e589e62e 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/Conversions.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/Conversions.cpp @@ -463,24 +463,24 @@ namespace AZ return colorMask; } - if(RHI::CheckBitsAll(writeMask, RHI::WriteChannelMask::ColorWriteMaskAll)) + if(RHI::CheckBitsAll(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskAll))) { return MTLColorWriteMaskAll; } - if (RHI::CheckBitsAny(writeMask, RHI::WriteChannelMask::ColorWriteMaskRed)) + if (RHI::CheckBitsAny(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskRed))) { colorMask |= MTLColorWriteMaskRed; } - if (RHI::CheckBitsAny(writeMask, RHI::WriteChannelMask::ColorWriteMaskGreen)) + if (RHI::CheckBitsAny(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskGreen))) { colorMask |= MTLColorWriteMaskGreen; } - if (RHI::CheckBitsAny(writeMask, RHI::WriteChannelMask::ColorWriteMaskBlue)) + if (RHI::CheckBitsAny(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskBlue))) { colorMask |= MTLColorWriteMaskBlue; } - if (RHI::CheckBitsAny(writeMask, RHI::WriteChannelMask::ColorWriteMaskAlpha)) + if (RHI::CheckBitsAny(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskAlpha))) { colorMask |= MTLColorWriteMaskAlpha; } diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp index 1ba002748b..5a382267bb 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp @@ -340,24 +340,24 @@ namespace AZ return dflags; } - if(RHI::CheckBitsAll(writeMask, RHI::WriteChannelMask::ColorWriteMaskAll)) + if(RHI::CheckBitsAll(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskAll))) { return VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; } - if (RHI::CheckBitsAny(sflags, RHI::WriteChannelMask::ColorWriteMaskRed)) + if (RHI::CheckBitsAny(sflags, static_cast(RHI::WriteChannelMask::ColorWriteMaskRed))) { dflags |= VK_COLOR_COMPONENT_R_BIT; } - if (RHI::CheckBitsAny(sflags, RHI::WriteChannelMask::ColorWriteMaskGreen)) + if (RHI::CheckBitsAny(sflags, static_cast(RHI::WriteChannelMask::ColorWriteMaskGreen))) { dflags |= VK_COLOR_COMPONENT_G_BIT; } - if (RHI::CheckBitsAny(sflags, RHI::WriteChannelMask::ColorWriteMaskBlue)) + if (RHI::CheckBitsAny(sflags, static_cast(RHI::WriteChannelMask::ColorWriteMaskBlue))) { dflags |= VK_COLOR_COMPONENT_B_BIT; } - if (RHI::CheckBitsAny(sflags, RHI::WriteChannelMask::ColorWriteMaskAlpha)) + if (RHI::CheckBitsAny(sflags, static_cast(RHI::WriteChannelMask::ColorWriteMaskAlpha))) { dflags |= VK_COLOR_COMPONENT_A_BIT; } From 7dd98c4e2b12c318d6533e254a52139b108e3589 Mon Sep 17 00:00:00 2001 From: moudgils Date: Thu, 10 Jun 2021 15:17:17 -0700 Subject: [PATCH 65/73] Missed a change --- Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp index 5a382267bb..8cad9b1f56 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp @@ -340,7 +340,7 @@ namespace AZ return dflags; } - if(RHI::CheckBitsAll(writeMask, static_cast(RHI::WriteChannelMask::ColorWriteMaskAll))) + if(RHI::CheckBitsAll(sflags, static_cast(RHI::WriteChannelMask::ColorWriteMaskAll))) { return VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; } From 6fdf7b01a5feb05d5a268d74eb9248edc973d2db Mon Sep 17 00:00:00 2001 From: Terry Michaels Date: Thu, 10 Jun 2021 17:23:39 -0500 Subject: [PATCH 66/73] Updated camera speed display and bounds (#1251) --- Code/Sandbox/Editor/ViewportTitleDlg.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Code/Sandbox/Editor/ViewportTitleDlg.h b/Code/Sandbox/Editor/ViewportTitleDlg.h index 21a54bea0a..255354dcbb 100644 --- a/Code/Sandbox/Editor/ViewportTitleDlg.h +++ b/Code/Sandbox/Editor/ViewportTitleDlg.h @@ -115,10 +115,10 @@ protected: float m_prevMoveSpeed; // Speed combobox/lineEdit settings - double m_minSpeed = 0.1; + double m_minSpeed = 0.01; double m_maxSpeed = 100.0; - double m_speedStep = 0.1; - int m_numDecimals = 1; + double m_speedStep = 0.01; + int m_numDecimals = 3; // Speed presets float m_speedPresetValues[3] = { 0.1f, 1.0f, 10.0f }; From 3ea74e017fd7249250c67ac7621da70caae77154 Mon Sep 17 00:00:00 2001 From: antonmic Date: Thu, 10 Jun 2021 20:06:13 -0700 Subject: [PATCH 67/73] Pass changes: RPI unit test fix --- Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp index ad3d6d31ca..cc51c8760a 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp @@ -101,6 +101,7 @@ namespace AZ m_passFactory.Init(&m_passLibrary); m_rootPass = CreatePass(Name{"Root"}); m_rootPass->m_flags.m_partOfHierarchy = true; + m_rootPass->m_flags.m_createChildren = false; // Here you can specify the name of a pass you would like to break into during execution // If you enable AZ_RPI_ENABLE_PASS_DEBUGGING, then any pass matching the specified name will debug From f6f90ee4c2f4a34b8691bb698760e77f18274718 Mon Sep 17 00:00:00 2001 From: moudgils Date: Thu, 10 Jun 2021 21:45:38 -0700 Subject: [PATCH 68/73] Change ConvertColorWriteMask return type to uint8_t --- Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.cpp | 4 ++-- Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.cpp index 9776734158..a29c7ae402 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.cpp @@ -1357,9 +1357,9 @@ namespace AZ return table[(uint32_t)mask]; } - uint32_t ConvertColorWriteMask(uint8_t writeMask) + uint8_t ConvertColorWriteMask(uint8_t writeMask) { - uint32_t dflags = 0; + uint8_t dflags = 0; if(writeMask == 0) { return dflags; diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.h b/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.h index 887598de79..640a5fef31 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.h +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/Conversions.h @@ -165,6 +165,6 @@ namespace AZ D3D12_SHADER_VISIBILITY shaderVisibility, D3D12_STATIC_SAMPLER_DESC& staticSamplerDesc); - uint32_t ConvertColorWriteMask(uint8_t writeMask); + uint8_t ConvertColorWriteMask(uint8_t writeMask); } } From 2a40010089fb5af2afceba593d2dda6deada7046 Mon Sep 17 00:00:00 2001 From: antonmic Date: Thu, 10 Jun 2021 22:54:12 -0700 Subject: [PATCH 69/73] Pass changes: fixed reflection probe bake --- Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp | 4 ---- Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp | 2 ++ 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp index 891190738f..ad2fc4b19e 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp @@ -107,11 +107,7 @@ namespace AZ pipeline->m_originalRenderSettings = desc.m_renderSettings; pipeline->m_activeRenderSettings = desc.m_renderSettings; pipeline->m_rootPass->SetRenderPipeline(pipeline); - - // Manually build the pipeline so we can gather the view tags from it's passes pipeline->m_rootPass->ManualPipelineBuildAndInitialize(); - - pipeline->BuildPipelineViews(); } RenderPipeline::~RenderPipeline() diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp index 5f9ba38c88..62efc3dccb 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp @@ -289,6 +289,8 @@ namespace AZ } pipeline->OnAddedToScene(this); + PassSystemInterface::Get()->ProcessQueuedChanges(); + pipeline->BuildPipelineViews(); // Force to update the lookup table since adding render pipeline would effect any pipeline states created before pass system tick RebuildPipelineStatesLookup(); From f775ba7df83730870e71644da835a5660cc72be7 Mon Sep 17 00:00:00 2001 From: Steve Pham <82231385+spham-amzn@users.noreply.github.com> Date: Fri, 11 Jun 2021 08:12:49 -0700 Subject: [PATCH 70/73] Provide more informative error messages on android related environment / device related issues (#1261) - If gradle is installed, but JAVA_HOME is not set properly, no detail message is given. Bubble up the error message as part of the description - When deploying a newer API Level APK (30) to an API Level 29 device, a python callstack is given without any detail of the error. Now it will report the actual error that is from the adb call so the user can act upon it --- .../Platform/Android/android_deployment.py | 14 +++++++++----- cmake/Tools/common.py | 18 +++++++++++++----- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/cmake/Tools/Platform/Android/android_deployment.py b/cmake/Tools/Platform/Android/android_deployment.py index eb8361ec18..82d14a2746 100755 --- a/cmake/Tools/Platform/Android/android_deployment.py +++ b/cmake/Tools/Platform/Android/android_deployment.py @@ -184,11 +184,15 @@ class AndroidDeployment(object): call_arguments.extend(arg_list) - output = subprocess.check_output(call_arguments, - shell=True, - stderr=subprocess.DEVNULL).decode(common.DEFAULT_TEXT_READ_ENCODING, - common.ENCODING_ERROR_HANDLINGS) - return output + try: + output = subprocess.check_output(call_arguments, + shell=True, + stderr=subprocess.PIPE).decode(common.DEFAULT_TEXT_READ_ENCODING, + common.ENCODING_ERROR_HANDLINGS) + return output + except subprocess.CalledProcessError as err: + raise common.LmbrCmdError(err.stderr.decode(common.DEFAULT_TEXT_READ_ENCODING, + common.ENCODING_ERROR_HANDLINGS)) def adb_shell(self, command, device_id): """ diff --git a/cmake/Tools/common.py b/cmake/Tools/common.py index 1990041c86..cf4631c227 100755 --- a/cmake/Tools/common.py +++ b/cmake/Tools/common.py @@ -274,6 +274,8 @@ def verify_tool(override_tool_path, tool_name, tool_filename, argument_name, too :return: Tuple of the resolved tool version and the resolved override tool path if provided """ + tool_source = tool_name + try: # Use either the provided gradle override or the gradle in the path environment if override_tool_path: @@ -306,18 +308,17 @@ def verify_tool(override_tool_path, tool_name, tool_filename, argument_name, too tool_desc = f"{tool_name} path provided in the command line argument '{argument_name}={override_tool_path}' " else: resolved_override_tool_path = None - tool_source = tool_name tool_desc = f"installed {tool_name} in the system path" # Extract the version and verify version_output = subprocess.check_output([tool_source, tool_version_argument], - shell=True).decode(DEFAULT_TEXT_READ_ENCODING, - ENCODING_ERROR_HANDLINGS) + shell=True, + stderr=subprocess.PIPE).decode(DEFAULT_TEXT_READ_ENCODING, + ENCODING_ERROR_HANDLINGS) version_match = tool_version_regex.search(version_output) if not version_match: raise RuntimeError() - # Since we are doing a compare, strip out any non-numeric and non . character from the version otherwise we will get a TypeError on the LooseVersion comparison result_version_str = re.sub(r"[^\.0-9]", "", str(version_match.group(1)).strip()) result_version = LooseVersion(result_version_str) @@ -331,7 +332,14 @@ def verify_tool(override_tool_path, tool_name, tool_filename, argument_name, too return result_version, resolved_override_tool_path - except (CalledProcessError, WindowsError, RuntimeError) as e: + except CalledProcessError as e: + error_msg = e.output.decode(DEFAULT_TEXT_READ_ENCODING, + ENCODING_ERROR_HANDLINGS) + raise LmbrCmdError(f"{tool_name} cannot be resolved or there was a problem determining its version number. " + f"Either make sure its in the system path environment or a valid path is passed in " + f"through the {argument_name} argument.\n{error_msg}", + ERROR_CODE_ERROR_NOT_SUPPORTED) + except (WindowsError, RuntimeError) as e: logging.error(f"Call to '{tool_source}' resulted in error: {e}") raise LmbrCmdError(f"{tool_name} cannot be resolved or there was a problem determining its version number. " f"Either make sure its in the system path environment or a valid path is passed in " From 0c7605c9b697522042f3161393d719dc76494ad8 Mon Sep 17 00:00:00 2001 From: Eric Phister <52085794+amzn-phist@users.noreply.github.com> Date: Fri, 11 Jun 2021 12:00:55 -0500 Subject: [PATCH 71/73] Update minimum required CMake version to 3.20 (#1253) * Update the minimum CMake version to 3.20 Sets the cmake_minimum_required calls to version 3.20 and updates the README.md to point at the general CMake download page instead of a stale link. * Remove unnecessary cmake minimum version It was using an old 3.0 version and can be removed. * Additional updates to CMake 3.20, build scripts Updates the version and remove logic to find a CMake in 3rdParty. * Removing backup path to ninja path in the build_ninja_windows.cmd The backup path for finding ninja was coming from the Perforce depot which isn't available for o3de builds. * Removing reference to 3rdParty Android SDK 29 from the build and run unit test script The Android SDK is not part of the new 3rdParty system and users are expected to install the Android SDK on their own in order to build the engine for Android. * Update the get_python scripts and README No longer try to append a CMake path to LY_3RDPARTY_PATH, but do still support LY_CMAKE_PATH because there are still uses of it. Remove mention of an LY_3RDPARTY_PATH-relative CMake path from the README.md. * Removing LY_NINJA_PATH from the build_ninja_windows.cmd Co-authored-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- AutomatedTesting/CMakeLists.txt | 2 +- CMakeLists.txt | 13 ++-------- Code/Framework/AzAutoGen/CMakeLists.txt | 2 -- README.md | 4 ++-- .../DefaultProject/Template/CMakeLists.txt | 2 +- .../Android/generate_android_project.py | 2 +- python/get_python.bat | 13 ++++------ python/get_python.cmake | 2 +- python/get_python.sh | 22 +++++------------ .../Android/build_and_run_unit_tests.cmd | 3 --- scripts/build/Platform/Linux/env_linux.sh | 24 ++++--------------- scripts/build/Platform/Mac/env_mac.sh | 12 ++-------- .../Platform/Windows/build_ninja_windows.cmd | 11 +-------- .../build/Platform/Windows/env_windows.cmd | 13 ++-------- 14 files changed, 28 insertions(+), 97 deletions(-) diff --git a/AutomatedTesting/CMakeLists.txt b/AutomatedTesting/CMakeLists.txt index e239ba7674..9a870b1279 100644 --- a/AutomatedTesting/CMakeLists.txt +++ b/AutomatedTesting/CMakeLists.txt @@ -10,7 +10,7 @@ # if(NOT PROJECT_NAME) - cmake_minimum_required(VERSION 3.19) + cmake_minimum_required(VERSION 3.20) project(AutomatedTesting LANGUAGES C CXX VERSION 1.0.0.0 diff --git a/CMakeLists.txt b/CMakeLists.txt index 6ca9aeacb8..0585089325 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,17 +9,8 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -# Cmake version 3.19 is the minimum version needed for all of Open 3D Engine's supported platforms -cmake_minimum_required(VERSION 3.19) - -# CMP0111 introduced in 3.19 has a bug that produces the policy to warn every time there is an -# INTERFACE IMPORTED library. We use this type of libraries for handling 3rdParty. The rest of -# the documentation states that INTERFACE IMPORTED libraries do not require to set locations, but -# the policy still warns about it. Issue: https://gitlab.kitware.com/cmake/cmake/-/issues/21470 -# The issue was fixed in 3.19.1 so we just disable the policy for 3.19 -if(CMAKE_VERSION VERSION_EQUAL 3.19) - cmake_policy(SET CMP0111 OLD) -endif() +# Cmake version 3.20 is the minimum version needed for all of Open 3D Engine's supported platforms +cmake_minimum_required(VERSION 3.20) include(cmake/LySet.cmake) include(cmake/Version.cmake) diff --git a/Code/Framework/AzAutoGen/CMakeLists.txt b/Code/Framework/AzAutoGen/CMakeLists.txt index 925e7aed29..4c79f268fe 100644 --- a/Code/Framework/AzAutoGen/CMakeLists.txt +++ b/Code/Framework/AzAutoGen/CMakeLists.txt @@ -9,8 +9,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -cmake_minimum_required(VERSION 3.0) - ly_add_target( NAME AzAutoGen HEADERONLY NAMESPACE AZ diff --git a/README.md b/README.md index 0c59837a62..7a9751529f 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ If you have the Git credential manager core or other credential helpers installe * Game Development with C++ * MSVC v142 - VS 2019 C++ x64/x86 * C++ 2019 redistributable update -* CMake 3.19.1 minimum: [https://cmake.org/files/LatestRelease/cmake-3.19.1-win64-x64.msi](https://cmake.org/files/LatestRelease/cmake-3.19.1-win64-x64.msi) +* CMake 3.20 minimum: [https://cmake.org/download/](https://cmake.org/download/) #### Optional @@ -105,7 +105,7 @@ If you have the Git credential manager core or other credential helpers installe 1. Install the following redistributables to the following: - Visual Studio and VC++ redistributable can be installed to any location - - CMake can be installed to any location, as long as it's available in the system path, otherwise it can be installed to: `<3rdParty Path>\CMake\3.19.1` + - CMake can be installed to any location, as long as it's available in the system path - WWise can be installed anywhere, but you will need to set an environment variable for CMake to detect it: `set LY_WWISE_INSTALL_PATH=` 1. Navigate into the repo folder, then download the python runtime with this command diff --git a/Templates/DefaultProject/Template/CMakeLists.txt b/Templates/DefaultProject/Template/CMakeLists.txt index 50e3a528e6..4dcfc5325b 100644 --- a/Templates/DefaultProject/Template/CMakeLists.txt +++ b/Templates/DefaultProject/Template/CMakeLists.txt @@ -12,7 +12,7 @@ # {END_LICENSE} if(NOT PROJECT_NAME) - cmake_minimum_required(VERSION 3.19) + cmake_minimum_required(VERSION 3.20) project(${Name} LANGUAGES C CXX VERSION 1.0.0.0 diff --git a/cmake/Tools/Platform/Android/generate_android_project.py b/cmake/Tools/Platform/Android/generate_android_project.py index d25b62dde8..5a52ac385e 100755 --- a/cmake/Tools/Platform/Android/generate_android_project.py +++ b/cmake/Tools/Platform/Android/generate_android_project.py @@ -48,7 +48,7 @@ def verify_gradle(override_gradle_path=None): CMAKE_ARGUMENT_NAME = '--cmake-install-path' -CMAKE_MIN_VERSION = LooseVersion('3.19.0') +CMAKE_MIN_VERSION = LooseVersion('3.20.0') CMAKE_VERSION_REGEX = re.compile(r'cmake version (\d+.\d+.?\d*)') CMAKE_EXECUTABLE = 'cmake' diff --git a/python/get_python.bat b/python/get_python.bat index e11c4ab92f..b3c3bf9cfb 100644 --- a/python/get_python.bat +++ b/python/get_python.bat @@ -32,18 +32,15 @@ IF !ERRORLEVEL!==0 ( cd /D %CMD_DIR%\.. REM IF you update this logic, update it in scripts/build/Platform/Windows/env_windows.cmd -REM If cmake is not found on path, try a known location, using LY_CMAKE_PATH as the first fallback +REM If cmake is not found on path, try a known location at LY_CMAKE_PATH where /Q cmake IF NOT !ERRORLEVEL!==0 ( IF "%LY_CMAKE_PATH%"=="" ( - IF "%LY_3RDPARTY_PATH%"=="" ( - ECHO ERROR: CMake was not found on the PATH and LY_3RDPARTY_PATH is not defined. - ECHO Please ensure CMake is on the path or set LY_3RDPARTY_PATH or LY_CMAKE_PATH. - EXIT /b 1 - ) - SET LY_CMAKE_PATH=!LY_3RDPARTY_PATH!\CMake\3.19.1\Windows\bin - echo CMake was not found on the path, will use known location: !LY_CMAKE_PATH! + ECHO ERROR: CMake was not found on the PATH and LY_CMAKE_PATH is not defined. + ECHO Please ensure CMake is on the path or set LY_CMAKE_PATH. + EXIT /b 1 ) + PATH !LY_CMAKE_PATH!;!PATH! where /Q cmake if NOT !ERRORLEVEL!==0 ( diff --git a/python/get_python.cmake b/python/get_python.cmake index 5d6bf6fd96..198d3f0ba3 100644 --- a/python/get_python.cmake +++ b/python/get_python.cmake @@ -16,7 +16,7 @@ # example: # cmake -DPAL_PLATFORM_NAME:string=Windows -DLY_3RDPARTY_PATH:string=%CMD_DIR% -P get_python.cmake -cmake_minimum_required(VERSION 3.17) +cmake_minimum_required(VERSION 3.20) if(LY_3RDPARTY_PATH) file(TO_CMAKE_PATH ${LY_3RDPARTY_PATH} LY_3RDPARTY_PATH) diff --git a/python/get_python.sh b/python/get_python.sh index 780f1bbdd8..9b774d91fc 100755 --- a/python/get_python.sh +++ b/python/get_python.sh @@ -42,31 +42,21 @@ then CMAKE_FOLDER_RELATIVE_TO_ROOT=CMake.app/Contents/bin else PAL=Linux - CMAKE_FOLDER_RELATIVE_TO_ROOT=bin + CMAKE_FOLDER_RELATIVE_TO_ROOT=bin fi if ! [ -x "$(command -v cmake)" ]; then - # Note that LY_3RDPARTY_PATH is only required here if you have no cmake in your PATH. if [ -z ${LY_CMAKE_PATH} ]; then - if [ -z ${LY_3RDPARTY_PATH} ]; then - echo "ERROR: Could not find cmake on the PATH and LY_3RDPARTY_PATH is not defined, cannot continue." - echo "Please add cmake to your PATH, or define $LY_3RDPARTY_PATH" - exit 1 - fi - LY_CMAKE_PATH=$LY_3RDPARTY_PATH/CMake/3.19.1/$PAL/$CMAKE_FOLDER_RELATIVE_TO_ROOT - # if you change the version number, change it also in: - # scripts/build/Platform/Mac/env_mac.sh - # and - # scripts/build/Platform/Linux/env_linux.sh + echo "ERROR: Could not find cmake on the PATH and LY_CMAKE_PATH is not defined, cannot continue." + echo "Please add cmake to your PATH, or define LY_CMAKE_PATH" + exit 1 fi - + export PATH=$LY_CMAKE_PATH:$PATH if ! [ -x "$(command -v cmake)" ]; then - echo "ERROR: Could not find cmake on the PATH or at the known location: $CMAKE_KNOWN_LOCATION" + echo "ERROR: Could not find cmake on the PATH or at the known location: $LY_CMAKE_PATH" echo "Please add cmake to the environment PATH or place it at the above known location." exit 1 - else - echo "CMake not found on path, but was found in the known 3rd Party location." fi fi diff --git a/scripts/build/Platform/Android/build_and_run_unit_tests.cmd b/scripts/build/Platform/Android/build_and_run_unit_tests.cmd index fbb31f95ec..5a51621f40 100644 --- a/scripts/build/Platform/Android/build_and_run_unit_tests.cmd +++ b/scripts/build/Platform/Android/build_and_run_unit_tests.cmd @@ -20,9 +20,6 @@ IF NOT EXIST "%LY_3RDPARTY_PATH%" ( GOTO :error ) -IF NOT EXIST "%LY_ANDROID_SDK%" ( - SET LY_ANDROID_SDK=!LY_3RDPARTY_PATH!/android-sdk/platform-29 -) IF NOT EXIST "%LY_ANDROID_SDK%" ( ECHO [ci_build] FAIL: LY_ANDROID_SDK=!LY_ANDROID_SDK! GOTO :error diff --git a/scripts/build/Platform/Linux/env_linux.sh b/scripts/build/Platform/Linux/env_linux.sh index 1d7324778c..85bdf0a745 100755 --- a/scripts/build/Platform/Linux/env_linux.sh +++ b/scripts/build/Platform/Linux/env_linux.sh @@ -13,27 +13,11 @@ set -o errexit # exit on the first failure encountered if ! command -v cmake &> /dev/null; then - if [[ -z $LY_CMAKE_PATH ]]; then LY_CMAKE_PATH=${LY_3RDPARTY_PATH}/CMake/3.19.1/Linux/bin; fi - if [[ ! -d $LY_CMAKE_PATH ]]; then - echo "[ci_build] CMake path not found" - exit 1 - fi - PATH=${LY_CMAKE_PATH}:${PATH} - if ! command -v cmake &> /dev/null; then - echo "[ci_build] CMake not found" - exit 1 - fi + echo "[ci_build] CMake not found" + exit 1 fi if ! command -v ninja &> /dev/null; then - if [[ -z $LY_NINJA_PATH ]]; then LY_NINJA_PATH=${LY_3RDPARTY_PATH}/ninja/1.10.1/Linux; fi - if [[ ! -d $LY_NINJA_PATH ]]; then - echo "[ci_build] Ninja path not found" - exit 1 - fi - PATH=${LY_NINJA_PATH}:${PATH} - if ! command -v ninja &> /dev/null; then - echo "[ci_build] Ninja not found" - exit 1 - fi + echo "[ci_build] Ninja not found" + exit 1 fi diff --git a/scripts/build/Platform/Mac/env_mac.sh b/scripts/build/Platform/Mac/env_mac.sh index 8f38d1d90b..917329b6af 100755 --- a/scripts/build/Platform/Mac/env_mac.sh +++ b/scripts/build/Platform/Mac/env_mac.sh @@ -13,14 +13,6 @@ set -o errexit # exit on the first failure encountered if ! command -v cmake &> /dev/null; then - if [[ -z $LY_CMAKE_PATH ]]; then LY_CMAKE_PATH=${LY_3RDPARTY_PATH}/CMake/3.19.1/Mac/CMake.app/Contents/bin; fi - if [[ ! -d $LY_CMAKE_PATH ]]; then - echo "[ci_build] CMake path not found" - exit 1 - fi - PATH=${LY_CMAKE_PATH}:${PATH} - if ! command -v cmake &> /dev/null; then - echo "[ci_build] CMake not found" - exit 1 - fi + echo "[ci_build] CMake not found" + exit 1 fi diff --git a/scripts/build/Platform/Windows/build_ninja_windows.cmd b/scripts/build/Platform/Windows/build_ninja_windows.cmd index b782cc2357..e1a802e254 100644 --- a/scripts/build/Platform/Windows/build_ninja_windows.cmd +++ b/scripts/build/Platform/Windows/build_ninja_windows.cmd @@ -12,19 +12,10 @@ REM SETLOCAL EnableDelayedExpansion -IF NOT EXIST "%LY_NINJA_PATH%" ( - SET LY_NINJA_PATH=%LY_3RDPARTY_PATH%/ninja/1.10.1/Windows -) -IF NOT EXIST "%LY_NINJA_PATH%" ( - ECHO [ci_build] FAIL: LY_NINJA_PATH=%LY_NINJA_PATH% - GOTO :error -) -PATH %LY_NINJA_PATH%;%PATH% - CALL "%~dp0build_windows.cmd" IF NOT %ERRORLEVEL%==0 GOTO :error EXIT /b 0 :error -EXIT /b 1 \ No newline at end of file +EXIT /b 1 diff --git a/scripts/build/Platform/Windows/env_windows.cmd b/scripts/build/Platform/Windows/env_windows.cmd index 592b2867cd..3ef161c2ef 100644 --- a/scripts/build/Platform/Windows/env_windows.cmd +++ b/scripts/build/Platform/Windows/env_windows.cmd @@ -12,17 +12,8 @@ REM where /Q cmake IF NOT %ERRORLEVEL%==0 ( - IF "%LY_CMAKE_PATH%"=="" (SET LY_CMAKE_PATH=%LY_3RDPARTY_PATH%/CMake/3.19.1/Windows/bin) - IF NOT EXIST !LY_CMAKE_PATH! ( - ECHO [ci_build] CMake path not found - GOTO :error - ) - PATH !LY_CMAKE_PATH!;!PATH! - where /Q cmake - IF NOT !ERRORLEVEL!==0 ( - ECHO [ci_build] CMake not found - GOTO :error - ) + ECHO [ci_build] CMake not found + GOTO :error ) EXIT /b 0 From 6584e1290be6c5c8adbb889da4f780b63ef4e294 Mon Sep 17 00:00:00 2001 From: michabr <82236305+michabr@users.noreply.github.com> Date: Fri, 11 Jun 2021 10:03:06 -0700 Subject: [PATCH 72/73] Reenable LyShine mask support now using Atom (#1218) * Add option to set stencil ref in Dynamic Draw Context * Add depth/stencil attachment slot to UI pass * Rework mask rendering to use Atom * Add missing circle mask image --- .../Common/Assets/Passes/LowEndPipeline.pass | 9 +- .../Common/Assets/Passes/MainPipeline.pass | 7 ++ .../Atom/Feature/Common/Assets/Passes/UI.pass | 17 +++ .../Common/Assets/Passes/UIParent.pass | 12 ++ .../DynamicDraw/DynamicDrawContext.h | 11 +- .../DynamicDraw/DynamicDrawContext.cpp | 13 +++ .../Shaders/LyShineUI.shadervariantlist | 4 +- Gems/LyShine/Code/Source/RenderGraph.cpp | 109 ++++++++---------- Gems/LyShine/Code/Source/RenderGraph.h | 7 +- Gems/LyShine/Code/Source/UiRenderer.cpp | 56 +++++---- Gems/LyShine/Code/Source/UiRenderer.h | 42 ++++++- .../Textures/LyShineExamples/CircleMask.tif | 3 + 12 files changed, 196 insertions(+), 94 deletions(-) create mode 100644 Gems/LyShineExamples/Assets/UI/Textures/LyShineExamples/CircleMask.tif diff --git a/Gems/Atom/Feature/Common/Assets/Passes/LowEndPipeline.pass b/Gems/Atom/Feature/Common/Assets/Passes/LowEndPipeline.pass index 38a4524aa2..849094dd69 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/LowEndPipeline.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/LowEndPipeline.pass @@ -322,7 +322,14 @@ "Pass": "AuxGeomPass", "Attachment": "ColorInputOutput" } - } + }, + { + "LocalSlot": "DepthInputOutput", + "AttachmentRef": { + "Pass": "DepthPrePass", + "Attachment": "Depth" + } + } ] }, { diff --git a/Gems/Atom/Feature/Common/Assets/Passes/MainPipeline.pass b/Gems/Atom/Feature/Common/Assets/Passes/MainPipeline.pass index b2e0cf088e..314d999e4d 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/MainPipeline.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/MainPipeline.pass @@ -427,6 +427,13 @@ "Pass": "DebugOverlayPass", "Attachment": "InputOutput" } + }, + { + "LocalSlot": "DepthInputOutput", + "AttachmentRef": { + "Pass": "DepthPrePass", + "Attachment": "Depth" + } } ] }, diff --git a/Gems/Atom/Feature/Common/Assets/Passes/UI.pass b/Gems/Atom/Feature/Common/Assets/Passes/UI.pass index 569fe1d722..ac43f17c11 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/UI.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/UI.pass @@ -7,6 +7,23 @@ "Name": "UIPassTemplate", "PassClass": "RasterPass", "Slots": [ + { + "Name": "DepthInputOutput", + "SlotType": "InputOutput", + "ScopeAttachmentUsage": "DepthStencil", + "LoadStoreAction": { + "ClearValue": { + "Type": "DepthStencil", + "Value": [ + 0.0, + 0.0, + 0.0, + 0.0 + ] + }, + "LoadActionStencil": "Clear" + } + }, { "Name": "InputOutput", "SlotType": "InputOutput", diff --git a/Gems/Atom/Feature/Common/Assets/Passes/UIParent.pass b/Gems/Atom/Feature/Common/Assets/Passes/UIParent.pass index 0069e89401..4ae67b9b09 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/UIParent.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/UIParent.pass @@ -10,6 +10,11 @@ { "Name": "InputOutput", "SlotType": "InputOutput" + }, + { + "Name": "DepthInputOutput", + "SlotType": "InputOutput", + "ScopeAttachmentUsage": "DepthStencil" } ], "PassRequests": [ @@ -24,6 +29,13 @@ "Pass": "Parent", "Attachment": "InputOutput" } + }, + { + "LocalSlot": "DepthInputOutput", + "AttachmentRef": { + "Pass": "Parent", + "Attachment": "DepthInputOutput" + } } ], "PassData": { diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/DynamicDraw/DynamicDrawContext.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/DynamicDraw/DynamicDrawContext.h index 81b23068a1..94fd20f828 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/DynamicDraw/DynamicDrawContext.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/DynamicDraw/DynamicDrawContext.h @@ -138,6 +138,12 @@ namespace AZ //! Without per draw viewport, the viewport setup in pass is usually used. void UnsetViewport(); + //! Set stencil reference for following draws which are added to this DynamicDrawContext + void SetStencilReference(uint8_t stencilRef); + + //! Get the current stencil reference. + uint8_t GetStencilReference() const; + //! Draw Indexed primitives with vertex and index data and per draw srg //! The per draw srg need to be provided if it's required by shader. void DrawIndexed(void* vertexData, uint32_t vertexCount, void* indexData, uint32_t indexCount, RHI::IndexFormat indexFormat, Data::Instance < ShaderResourceGroup> drawSrg = nullptr); @@ -204,10 +210,13 @@ namespace AZ bool m_useScissor = false; RHI::Scissor m_scissor; - // current scissor + // current viewport bool m_useViewport = false; RHI::Viewport m_viewport; + // Current stencil reference value + uint8_t m_stencilRef = 0; + // Cached RHI pipeline states for different combination of render states AZStd::unordered_map m_cachedRhiPipelineStates; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/DynamicDraw/DynamicDrawContext.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/DynamicDraw/DynamicDrawContext.cpp index 00c2122825..09e3499820 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/DynamicDraw/DynamicDrawContext.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/DynamicDraw/DynamicDrawContext.cpp @@ -382,6 +382,16 @@ namespace AZ m_useViewport = false; } + void DynamicDrawContext::SetStencilReference(uint8_t stencilRef) + { + m_stencilRef = stencilRef; + } + + uint8_t DynamicDrawContext::GetStencilReference() const + { + return m_stencilRef; + } + void DynamicDrawContext::SetShaderVariant(ShaderVariantId shaderVariantId) { AZ_Assert( m_initialized && m_supportShaderVariants, "DynamicDrawContext is not initialized or unable to support shader variants. " @@ -475,6 +485,9 @@ namespace AZ drawItem.m_viewports = &m_viewport; } + // Set stencil reference. Used when stencil is enabled. + drawItem.m_stencilRef = m_stencilRef; + drawItemInfo.m_sortKey = m_sortKey++; m_cachedDrawItems.emplace_back(drawItemInfo); } diff --git a/Gems/AtomLyIntegration/AtomBridge/Assets/Shaders/LyShineUI.shadervariantlist b/Gems/AtomLyIntegration/AtomBridge/Assets/Shaders/LyShineUI.shadervariantlist index 79bb726c9f..c7eddb10f2 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Assets/Shaders/LyShineUI.shadervariantlist +++ b/Gems/AtomLyIntegration/AtomBridge/Assets/Shaders/LyShineUI.shadervariantlist @@ -4,7 +4,7 @@ { "StableId": 1, "Options": { - "o_preMultiplyAlpha": "true", + "o_preMultiplyAlpha": "false", "o_alphaTest": "false", "o_srgbWrite": "true", "o_modulate": "Modulate::None" @@ -14,7 +14,7 @@ "StableId": 2, "Options": { "o_preMultiplyAlpha": "false", - "o_alphaTest": "false", + "o_alphaTest": "true", "o_srgbWrite": "true", "o_modulate": "Modulate::None" } diff --git a/Gems/LyShine/Code/Source/RenderGraph.cpp b/Gems/LyShine/Code/Source/RenderGraph.cpp index d5a1df7b15..ad2c46f8e6 100644 --- a/Gems/LyShine/Code/Source/RenderGraph.cpp +++ b/Gems/LyShine/Code/Source/RenderGraph.cpp @@ -137,7 +137,11 @@ namespace LyShine AZ::RHI::Ptr dynamicDraw = uiRenderer->GetDynamicDrawContext(); const UiRenderer::UiShaderData& uiShaderData = uiRenderer->GetUiShaderData(); - dynamicDraw->SetShaderVariant(uiShaderData.m_shaderVariantDefault); + // Set render state + dynamicDraw->SetStencilState(uiRenderer->GetBaseState().m_stencilState); + dynamicDraw->SetTarget0BlendState(uiRenderer->GetBaseState().m_blendState); + + dynamicDraw->SetShaderVariant(uiRenderer->GetCurrentShaderVariant()); // Set up per draw SRG AZ::Data::Instance drawSrg = dynamicDraw->NewDrawSrg(); @@ -307,7 +311,7 @@ namespace LyShine //////////////////////////////////////////////////////////////////////////////////////////////////// void MaskRenderNode::Render(UiRenderer* uiRenderer) { - int priorBaseState = uiRenderer->GetBaseState(); + UiRenderer::BaseState priorBaseState = uiRenderer->GetBaseState(); if (m_isMaskingEnabled || m_drawBehind) { @@ -369,68 +373,61 @@ namespace LyShine #endif //////////////////////////////////////////////////////////////////////////////////////////////////// - void MaskRenderNode::SetupBeforeRenderingMask(UiRenderer* uiRenderer, bool firstPass, int priorBaseState) + void MaskRenderNode::SetupBeforeRenderingMask(UiRenderer* uiRenderer, bool firstPass, UiRenderer::BaseState priorBaseState) { + UiRenderer::BaseState curBaseState = priorBaseState; + // If using alpha test for drawing the renderable components on this element then we turn on // alpha test as a pre-render step - int alphaTest = 0; - if (m_useAlphaTest) - { - alphaTest = GS_ALPHATEST_GREATER; - } + curBaseState.m_useAlphaTest = m_useAlphaTest; // if either of the draw flags are checked then we may want to draw the renderable component(s) // on this element, otherwise use the color mask to stop them rendering - int colorMask = GS_COLMASK_NONE; + curBaseState.m_blendState.m_enable = false; + curBaseState.m_blendState.m_writeMask = 0x0; if ((m_drawBehind && firstPass) || (m_drawInFront && !firstPass)) { - colorMask = 0; // mask everything, don't write color or alpha, we just write to stencil buffer + curBaseState.m_blendState.m_enable = true; + curBaseState.m_blendState.m_writeMask = 0xF; } - if (m_isMaskingEnabled) + if (m_isMaskingEnabled) { + AZ::RHI::StencilOpState stencilOpState; + stencilOpState.m_func = AZ::RHI::ComparisonFunc::Equal; + // masking is enabled so we want to setup to increment (first pass) or decrement (second pass) // the stencil buff when rendering the renderable component(s) on this element - int passOp = 0; if (firstPass) { - passOp = STENCOP_PASS(FSS_STENCOP_INCR); - gEnv->pRenderer->PushProfileMarker(s_maskIncrProfileMarker); + stencilOpState.m_passOp = AZ::RHI::StencilOp::Increment; } else { - passOp = STENCOP_PASS(FSS_STENCOP_DECR); - gEnv->pRenderer->PushProfileMarker(s_maskDecrProfileMarker); + stencilOpState.m_passOp = AZ::RHI::StencilOp::Decrement; } + curBaseState.m_stencilState.m_frontFace = stencilOpState; + curBaseState.m_stencilState.m_backFace = stencilOpState; + // set up for stencil write - const uint32 stencilRef = uiRenderer->GetStencilRef(); - const uint32 stencilMask = 0xFF; - const uint32 stencilWriteMask = 0xFF; - const int32 stencilState = STENC_FUNC(FSS_STENCFUNC_EQUAL) - | STENCOP_FAIL(FSS_STENCOP_KEEP) | STENCOP_ZFAIL(FSS_STENCOP_KEEP) | passOp; - gEnv->pRenderer->SetStencilState(stencilState, stencilRef, stencilMask, stencilWriteMask); - - // Set the base state that should be used when rendering the renderable component(s) on this - // element - uiRenderer->SetBaseState(priorBaseState | GS_STENCIL | alphaTest | colorMask); + AZ::RHI::Ptr dynamicDraw = uiRenderer->GetDynamicDrawContext(); + dynamicDraw->SetStencilReference(uiRenderer->GetStencilRef()); + curBaseState.m_stencilState.m_enable = true; + curBaseState.m_stencilState.m_writeMask = 0xFF; } else { // masking is not enabled - - // Even if not masking we still use alpha test (if checked). This is primarily to help the user to - // visualize what their alpha tested mask looks like. - if (colorMask || alphaTest) - { - uiRenderer->SetBaseState(priorBaseState | colorMask | alphaTest); - } + curBaseState.m_stencilState.m_enable = false; } + + uiRenderer->SetBaseState(curBaseState); } //////////////////////////////////////////////////////////////////////////////////////////////////// - void MaskRenderNode::SetupAfterRenderingMask(UiRenderer* uiRenderer, bool firstPass, int priorBaseState) + void MaskRenderNode::SetupAfterRenderingMask(UiRenderer* uiRenderer, bool firstPass, UiRenderer::BaseState priorBaseState) { if (m_isMaskingEnabled) { @@ -442,26 +439,29 @@ namespace LyShine if (firstPass) { uiRenderer->IncrementStencilRef(); - gEnv->pRenderer->PopProfileMarker(s_maskIncrProfileMarker); } else { uiRenderer->DecrementStencilRef(); - gEnv->pRenderer->PopProfileMarker(s_maskDecrProfileMarker); } - // turn off stencil write and turn on stencil test - const uint32 stencilRef = uiRenderer->GetStencilRef(); - const uint32 stencilMask = 0xFF; - const uint32 stencilWriteMask = 0x00; - const int32 stencilState = STENC_FUNC(FSS_STENCFUNC_EQUAL) - | STENCOP_FAIL(FSS_STENCOP_KEEP) | STENCOP_ZFAIL(FSS_STENCOP_KEEP) | STENCOP_PASS(FSS_STENCOP_KEEP); - gEnv->pRenderer->SetStencilState(stencilState, stencilRef, stencilMask, stencilWriteMask); + AZ::RHI::Ptr dynamicDraw = uiRenderer->GetDynamicDrawContext(); + dynamicDraw->SetStencilReference(uiRenderer->GetStencilRef()); if (firstPass) { - // first pass, turn on stencil test for drawing children - uiRenderer->SetBaseState(priorBaseState | GS_STENCIL); + UiRenderer::BaseState curBaseState = priorBaseState; + + // turn off stencil write and turn on stencil test + curBaseState.m_stencilState.m_enable = true; + curBaseState.m_stencilState.m_writeMask = 0x00; + + AZ::RHI::StencilOpState stencilOpState; + stencilOpState.m_func = AZ::RHI::ComparisonFunc::Equal; + curBaseState.m_stencilState.m_frontFace = stencilOpState; + curBaseState.m_stencilState.m_backFace = stencilOpState; + + uiRenderer->SetBaseState(curBaseState); } else { @@ -475,7 +475,6 @@ namespace LyShine // remove any color mask or alpha test that we set in pre-render uiRenderer->SetBaseState(priorBaseState); } - } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -637,35 +636,24 @@ namespace LyShine //////////////////////////////////////////////////////////////////////////////////////////////////// void RenderGraph::BeginMask(bool isMaskingEnabled, bool useAlphaTest, bool drawBehind, bool drawInFront) { -#ifdef LYSHINE_ATOM_TODO // keeping this code for future phase (masks and render targets) - // this uses pool allocator MaskRenderNode* maskRenderNode = new MaskRenderNode(m_currentMask, isMaskingEnabled, useAlphaTest, drawBehind, drawInFront); m_currentMask = maskRenderNode; m_renderNodeListStack.push(&maskRenderNode->GetMaskRenderNodeList()); -#else - AZ_UNUSED(drawInFront); - AZ_UNUSED(drawBehind); - AZ_UNUSED(useAlphaTest); - AZ_UNUSED(isMaskingEnabled); -#endif } //////////////////////////////////////////////////////////////////////////////////////////////////// void RenderGraph::StartChildrenForMask() { -#ifdef LYSHINE_ATOM_TODO // keeping this code for future phase (masks and render targets) AZ_Assert(m_currentMask, "Calling StartChildrenForMask while not defining a mask"); m_renderNodeListStack.pop(); m_renderNodeListStack.push(&m_currentMask->GetContentRenderNodeList()); -#endif } //////////////////////////////////////////////////////////////////////////////////////////////////// void RenderGraph::EndMask() { -#ifdef LYSHINE_ATOM_TODO // keeping this code for future phase (masks and render targets) AZ_Assert(m_currentMask, "Calling EndMask while not defining a mask"); if (m_currentMask) { @@ -686,7 +674,6 @@ namespace LyShine m_renderNodeListStack.top()->push_back(newMaskRenderNode); } } -#endif } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -996,6 +983,12 @@ namespace LyShine // LYSHINE_ATOM_TODO - will probably need to support this when converting UI Editor to use Atom AZ_UNUSED(viewportSize); + AZ::RHI::Ptr dynamicDraw = uiRenderer->GetDynamicDrawContext(); + + // Disable stencil and enable blend/color write + dynamicDraw->SetStencilState(uiRenderer->GetBaseState().m_stencilState); + dynamicDraw->SetTarget0BlendState(uiRenderer->GetBaseState().m_blendState); + // First render the render targets, they are sorted so that more deeply nested ones are rendered first. #ifdef LYSHINE_ATOM_TODO // keeping this code for reference for future phase (render targets) diff --git a/Gems/LyShine/Code/Source/RenderGraph.h b/Gems/LyShine/Code/Source/RenderGraph.h index 2f1586e857..355616a29a 100644 --- a/Gems/LyShine/Code/Source/RenderGraph.h +++ b/Gems/LyShine/Code/Source/RenderGraph.h @@ -22,12 +22,11 @@ #include #include +#include "UiRenderer.h" #ifndef _RELEASE #include "LyShineDebug.h" #endif -class UiRenderer; - namespace LyShine { enum RenderNodeType @@ -157,8 +156,8 @@ namespace LyShine #endif private: // functions - void SetupBeforeRenderingMask(UiRenderer* uiRenderer, bool firstPass, int priorBaseState); - void SetupAfterRenderingMask(UiRenderer* uiRenderer, bool firstPass, int priorBaseState); + void SetupBeforeRenderingMask(UiRenderer* uiRenderer, bool firstPass, UiRenderer::BaseState priorBaseState); + void SetupAfterRenderingMask(UiRenderer* uiRenderer, bool firstPass, UiRenderer::BaseState priorBaseState); private: // data AZStd::vector m_maskRenderNodes; //!< The render nodes used to render the mask shape diff --git a/Gems/LyShine/Code/Source/UiRenderer.cpp b/Gems/LyShine/Code/Source/UiRenderer.cpp index 57acbed5d5..e3ded694b5 100644 --- a/Gems/LyShine/Code/Source/UiRenderer.cpp +++ b/Gems/LyShine/Code/Source/UiRenderer.cpp @@ -20,7 +20,6 @@ #include #include #include -#include // LYSHINE_ATOM_TODO - remove when GS_DEPTHFUNC_LEQUAL reference is removed with LyShine render target Atom conversion #include #include @@ -33,9 +32,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// UiRenderer::UiRenderer(AZ::RPI::ViewportContextPtr viewportContext) - : m_baseState(GS_DEPTHFUNC_LEQUAL) - , m_stencilRef(0) - , m_viewportContext(viewportContext) + : m_viewportContext(viewportContext) { // Use bootstrap scene event to indicate when the RPI has fully // initialized with all assets loaded and is ready to be used @@ -127,6 +124,8 @@ void UiRenderer::CreateDynamicDrawContext(AZ::RPI::ScenePtr scene, AZ::Data::Ins { "TEXCOORD", AZ::RHI::Format::R32G32_FLOAT }, { "BLENDINDICES", AZ::RHI::Format::R16G16_UINT } } ); + m_dynamicDraw->AddDrawStateOptions(AZ::RPI::DynamicDrawContext::DrawStateOptions::StencilState + | AZ::RPI::DynamicDrawContext::DrawStateOptions::BlendMode); m_dynamicDraw->EndInit(); } @@ -170,25 +169,24 @@ void UiRenderer::CacheShaderData(const AZ::RHI::Ptr shaderOptionsDefault.push_back(AZ::RPI::ShaderOption(AZ::Name("o_srgbWrite"), AZ::Name("true"))); shaderOptionsDefault.push_back(AZ::RPI::ShaderOption(AZ::Name("o_modulate"), AZ::Name("Modulate::None"))); m_uiShaderData.m_shaderVariantDefault = dynamicDraw->UseShaderVariant(shaderOptionsDefault); + AZ::RPI::ShaderOptionList shaderOptionsAlphaTest; + shaderOptionsAlphaTest.push_back(AZ::RPI::ShaderOption(AZ::Name("o_preMultiplyAlpha"), AZ::Name("false"))); + shaderOptionsAlphaTest.push_back(AZ::RPI::ShaderOption(AZ::Name("o_alphaTest"), AZ::Name("true"))); + shaderOptionsAlphaTest.push_back(AZ::RPI::ShaderOption(AZ::Name("o_srgbWrite"), AZ::Name("true"))); + shaderOptionsAlphaTest.push_back(AZ::RPI::ShaderOption(AZ::Name("o_modulate"), AZ::Name("Modulate::None"))); + m_uiShaderData.m_shaderVariantAlphaTest = dynamicDraw->UseShaderVariant(shaderOptionsAlphaTest); } //////////////////////////////////////////////////////////////////////////////////////////////////// void UiRenderer::BeginUiFrameRender() { -#ifdef LYSHINE_ATOM_TODO - m_renderer = gEnv->pRenderer; - - // we are rendering at the end of the frame, after tone mapping, so we should be writing sRGB values - m_renderer->SetSrgbWrite(true); - #ifndef _RELEASE if (m_debugTextureDataRecordLevel > 0) { m_texturesUsedInFrame.clear(); } #endif -#endif - + // Various platform drivers expect all texture slots used in the shader to be bound BindNullTexture(); } @@ -204,18 +202,10 @@ void UiRenderer::EndUiFrameRender() //////////////////////////////////////////////////////////////////////////////////////////////////// void UiRenderer::BeginCanvasRender() { -#ifdef LYSHINE_ATOM_TODO - m_baseState = GS_NODEPTHTEST; - m_stencilRef = 0; - // Set default starting state - IRenderer* renderer = gEnv->pRenderer; - - renderer->SetCullMode(R_CULL_DISABLE); - renderer->SetColorOp(eCO_MODULATE, eCO_MODULATE, DEF_TEXARG0, DEF_TEXARG0); - renderer->SetState(GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA | GS_NODEPTHTEST); -#endif + // Set base state + m_baseState.ResetToDefault(); } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -229,11 +219,13 @@ AZ::RHI::Ptr UiRenderer::GetDynamicDrawContext() return m_dynamicDraw; } +//////////////////////////////////////////////////////////////////////////////////////////////////// const UiRenderer::UiShaderData& UiRenderer::GetUiShaderData() { return m_uiShaderData; } +//////////////////////////////////////////////////////////////////////////////////////////////////// AZ::Matrix4x4 UiRenderer::GetModelViewProjectionMatrix() { auto viewportContext = GetViewportContext(); @@ -253,6 +245,7 @@ AZ::Matrix4x4 UiRenderer::GetModelViewProjectionMatrix() return modelViewProjMat; } +//////////////////////////////////////////////////////////////////////////////////////////////////// AZ::Vector2 UiRenderer::GetViewportSize() { auto viewportContext = GetViewportContext(); @@ -267,17 +260,30 @@ AZ::Vector2 UiRenderer::GetViewportSize() } //////////////////////////////////////////////////////////////////////////////////////////////////// -int UiRenderer::GetBaseState() +UiRenderer::BaseState UiRenderer::GetBaseState() { return m_baseState; } //////////////////////////////////////////////////////////////////////////////////////////////////// -void UiRenderer::SetBaseState(int state) +void UiRenderer::SetBaseState(BaseState state) { m_baseState = state; } +//////////////////////////////////////////////////////////////////////////////////////////////////// +AZ::RPI::ShaderVariantId UiRenderer::GetCurrentShaderVariant() +{ + AZ::RPI::ShaderVariantId variantId = m_uiShaderData.m_shaderVariantDefault; + + if (m_baseState.m_useAlphaTest) + { + variantId = m_uiShaderData.m_shaderVariantAlphaTest; + } + + return variantId; +} + //////////////////////////////////////////////////////////////////////////////////////////////////// uint32 UiRenderer::GetStencilRef() { @@ -354,6 +360,7 @@ void UiRenderer::DebugDisplayTextureData(int recordingOption) { if (recordingOption > 0) { +#ifdef LYSHINE_ATOM_TODO // Convert debug to use Atom images // compute the total area of all the textures, also create a vector that we can sort by area AZStd::vector textures; int totalArea = 0; @@ -431,6 +438,7 @@ void UiRenderer::DebugDisplayTextureData(int recordingOption) texture->GetWidth(), texture->GetHeight(), texture->GetDataSize(), texture->GetFormatName(), texture->GetName()); WriteLine(buffer, white); } +#endif } } diff --git a/Gems/LyShine/Code/Source/UiRenderer.h b/Gems/LyShine/Code/Source/UiRenderer.h index 888c88586a..413e8c45cf 100644 --- a/Gems/LyShine/Code/Source/UiRenderer.h +++ b/Gems/LyShine/Code/Source/UiRenderer.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #ifndef _RELEASE @@ -38,6 +39,36 @@ public: // types AZ::RHI::ShaderInputConstantIndex m_isClampInputIndex; AZ::RPI::ShaderVariantId m_shaderVariantDefault; + AZ::RPI::ShaderVariantId m_shaderVariantAlphaTest; + }; + + // Base state + struct BaseState + { + BaseState() + { + ResetToDefault(); + } + + void ResetToDefault() + { + // Enable blend/color write + m_blendState.m_enable = true; + m_blendState.m_writeMask = 0xF; + m_blendState.m_blendSource = AZ::RHI::BlendFactor::AlphaSource; + m_blendState.m_blendDest = AZ::RHI::BlendFactor::AlphaSourceInverse; + m_blendState.m_blendOp = AZ::RHI::BlendOp::Add; + + // Disable stencil + m_stencilState = AZ::RHI::StencilState(); + m_stencilState.m_enable = 0; + + m_useAlphaTest = false; + } + + AZ::RHI::TargetBlendState m_blendState; + AZ::RHI::StencilState m_stencilState; + bool m_useAlphaTest = false; }; public: // member functions @@ -74,10 +105,13 @@ public: // member functions AZ::Vector2 GetViewportSize(); //! Get the current base state - int GetBaseState(); + BaseState GetBaseState(); //! Set the base state - void SetBaseState(int state); + void SetBaseState(BaseState state); + + //! Get the shader variant based on current render properties + AZ::RPI::ShaderVariantId GetCurrentShaderVariant(); //! Get the current stencil test reference value uint32 GetStencilRef(); @@ -126,8 +160,8 @@ protected: // attributes static constexpr char LogName[] = "UiRenderer"; - int m_baseState; - uint32 m_stencilRef; + BaseState m_baseState; + uint32 m_stencilRef = 0; UiShaderData m_uiShaderData; AZ::RHI::Ptr m_dynamicDraw; diff --git a/Gems/LyShineExamples/Assets/UI/Textures/LyShineExamples/CircleMask.tif b/Gems/LyShineExamples/Assets/UI/Textures/LyShineExamples/CircleMask.tif new file mode 100644 index 0000000000..fd29516609 --- /dev/null +++ b/Gems/LyShineExamples/Assets/UI/Textures/LyShineExamples/CircleMask.tif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8474b897fe02f70ed8d0e5c47cae8c816c832a7a5739b8c32317737fd275774f +size 1069752 From 4818d1ce809436efd72b4fa51064e60fae565640 Mon Sep 17 00:00:00 2001 From: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Fri, 11 Jun 2021 12:25:45 -0500 Subject: [PATCH 73/73] {LYN-4224} Fix for the file scan slowdown (#1252) * {LYN-4224} Fix for the file scan slowdown (#1183) * {LYN-4224} Fix for the file scan slowdown * Fixed a slowdown in the file scanning logic * Improved the file scanning logic from previous code by 40% Tests: Using Testing\Pytest\AutomatedTesting_BlastTest old code: === 7 passed in 96.13s (0:01:36) === current code: === 7 passed in 160.45s (0:02:40) ==== newest code: === 7 passed in 52.91s === * fixing a unit test compile error * unit test fixes * another file improvement * fix for legacy level loading taking too long * making an enum for the search types * switched the enum to "allow" types to make the input more clear * got rid of orphaned const variables --- Code/CryEngine/CryCommon/Mocks/ICryPakMock.h | 2 +- .../CrySystem/LevelSystem/LevelSystem.cpp | 11 ++-- .../AzFramework/Archive/Archive.cpp | 24 +++++++- .../AzFramework/AzFramework/Archive/Archive.h | 2 +- .../AzFramework/Archive/ArchiveFindData.cpp | 60 ++++++++++--------- .../AzFramework/Archive/ArchiveFindData.h | 7 +-- .../AzFramework/Archive/IArchive.h | 9 ++- Code/Sandbox/Editor/CryEditDoc.cpp | 2 +- .../Code/Tests/AudioSystemEditorTest.cpp | 13 ++-- 9 files changed, 79 insertions(+), 51 deletions(-) diff --git a/Code/CryEngine/CryCommon/Mocks/ICryPakMock.h b/Code/CryEngine/CryCommon/Mocks/ICryPakMock.h index 2d451793bc..072a798985 100644 --- a/Code/CryEngine/CryCommon/Mocks/ICryPakMock.h +++ b/Code/CryEngine/CryCommon/Mocks/ICryPakMock.h @@ -67,7 +67,7 @@ struct CryPakMock MOCK_METHOD1(PoolMalloc, void*(size_t size)); MOCK_METHOD1(PoolFree, void(void* p)); MOCK_METHOD3(PoolAllocMemoryBlock, AZStd::intrusive_ptr (size_t nSize, const char* sUsage, size_t nAlign)); - MOCK_METHOD3(FindFirst, AZ::IO::ArchiveFileIterator(AZStd::string_view pDir, uint32_t nFlags, bool bAllOwUseFileSystem)); + MOCK_METHOD2(FindFirst, AZ::IO::ArchiveFileIterator(AZStd::string_view pDir, AZ::IO::IArchive::EFileSearchType)); MOCK_METHOD1(FindNext, AZ::IO::ArchiveFileIterator(AZ::IO::ArchiveFileIterator handle)); MOCK_METHOD1(FindClose, bool(AZ::IO::ArchiveFileIterator)); MOCK_METHOD1(GetModificationTime, AZ::IO::IArchive::FileTime(AZ::IO::HandleType f)); diff --git a/Code/CryEngine/CrySystem/LevelSystem/LevelSystem.cpp b/Code/CryEngine/CrySystem/LevelSystem/LevelSystem.cpp index c36b9bcee7..08caeeeb70 100644 --- a/Code/CryEngine/CrySystem/LevelSystem/LevelSystem.cpp +++ b/Code/CryEngine/CrySystem/LevelSystem/LevelSystem.cpp @@ -306,8 +306,7 @@ void CLevelSystem::ScanFolder(const char* subfolder, bool modFolder) AZStd::unordered_set pakList; - bool allowFileSystem = true; - AZ::IO::ArchiveFileIterator handle = pPak->FindFirst(search.c_str(), 0, allowFileSystem); + AZ::IO::ArchiveFileIterator handle = pPak->FindFirst(search.c_str(), AZ::IO::IArchive::eFileSearchType_AllowOnDiskOnly); if (handle) { @@ -320,7 +319,7 @@ void CLevelSystem::ScanFolder(const char* subfolder, bool modFolder) { if (AZ::StringFunc::Equal(handle.m_filename.data(), LevelPakName)) { - // level folder contain pak files like 'level.pak' + // level folder contain pak files like 'level.pak' // which we only want to load during level loading. continue; } @@ -351,7 +350,7 @@ void CLevelSystem::ScanFolder(const char* subfolder, bool modFolder) PopulateLevels(search, folder, pPak, modFolder, false); // Load levels outside of the bundles to maintain backward compatibility. PopulateLevels(search, folder, pPak, modFolder, true); - + } void CLevelSystem::PopulateLevels( @@ -360,7 +359,7 @@ void CLevelSystem::PopulateLevels( { // allow this find first to actually touch the file system // (causes small overhead but with minimal amount of levels this should only be around 150ms on actual DVD Emu) - AZ::IO::ArchiveFileIterator handle = pPak->FindFirst(searchPattern.c_str(), 0, fromFileSystemOnly); + AZ::IO::ArchiveFileIterator handle = pPak->FindFirst(searchPattern.c_str(), AZ::IO::IArchive::eFileSearchType_AllowOnDiskOnly); if (handle) { @@ -973,7 +972,7 @@ void CLevelSystem::UnloadLevel() m_lastLevelName.clear(); SAFE_RELEASE(m_pCurrentLevel); - + // Force Lua garbage collection (may no longer be needed now the legacy renderer has been removed). // Normally the GC step is triggered at the end of this method (by the ESYSTEM_EVENT_LEVEL_POST_UNLOAD event). EBUS_EVENT(AZ::ScriptSystemRequestBus, GarbageCollect); diff --git a/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp b/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp index 04573eb2e5..5cb2006447 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp +++ b/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp @@ -1290,7 +1290,7 @@ namespace AZ::IO ////////////////////////////////////////////////////////////////////////// - AZ::IO::ArchiveFileIterator Archive::FindFirst(AZStd::string_view pDir, [[maybe_unused]] uint32_t nPathFlags, bool bAllowUseFileSystem) + AZ::IO::ArchiveFileIterator Archive::FindFirst(AZStd::string_view pDir, EFileSearchType searchType) { auto szFullPath = AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(pDir); if (!szFullPath) @@ -1299,8 +1299,26 @@ namespace AZ::IO return {}; } + bool bScanZips{}; + bool bAllowUseFileSystem{}; + switch (searchType) + { + case IArchive::eFileSearchType_AllowInZipsOnly: + bAllowUseFileSystem = false; + bScanZips = true; + break; + case IArchive::eFileSearchType_AllowOnDiskAndInZips: + bAllowUseFileSystem = true; + bScanZips = true; + break; + case IArchive::eFileSearchType_AllowOnDiskOnly: + bAllowUseFileSystem = true; + bScanZips = false; + break; + } + AZStd::intrusive_ptr pFindData = new AZ::IO::FindData(); - pFindData->Scan(this, szFullPath->Native(), bAllowUseFileSystem); + pFindData->Scan(this, szFullPath->Native(), bAllowUseFileSystem, bScanZips); return pFindData->Fetch(); } @@ -1676,7 +1694,7 @@ namespace AZ::IO return true; } - if (AZ::IO::ArchiveFileIterator fileIterator = FindFirst(pWildcardIn, 0, true); fileIterator) + if (AZ::IO::ArchiveFileIterator fileIterator = FindFirst(pWildcardIn, IArchive::eFileSearchType_AllowOnDiskOnly); fileIterator) { AZStd::vector files; do diff --git a/Code/Framework/AzFramework/AzFramework/Archive/Archive.h b/Code/Framework/AzFramework/AzFramework/Archive/Archive.h index 997b3e3d2c..329beb4291 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/Archive.h +++ b/Code/Framework/AzFramework/AzFramework/Archive/Archive.h @@ -234,7 +234,7 @@ namespace AZ::IO uint64_t FTell(AZ::IO::HandleType handle) override; int FFlush(AZ::IO::HandleType handle) override; int FClose(AZ::IO::HandleType handle) override; - AZ::IO::ArchiveFileIterator FindFirst(AZStd::string_view pDir, uint32_t nPathFlags = 0, bool bAllOwUseFileSystem = false) override; + AZ::IO::ArchiveFileIterator FindFirst(AZStd::string_view pDir, EFileSearchType searchType = eFileSearchType_AllowInZipsOnly) override; AZ::IO::ArchiveFileIterator FindNext(AZ::IO::ArchiveFileIterator fileIterator) override; bool FindClose(AZ::IO::ArchiveFileIterator fileIterator) override; int FEof(AZ::IO::HandleType handle) override; diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFindData.cpp b/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFindData.cpp index 1794ae90e7..05da5f16eb 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFindData.cpp +++ b/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFindData.cpp @@ -77,7 +77,7 @@ namespace AZ::IO return m_findData && m_lastFetchValid; } - void FindData::Scan(IArchive* archive, AZStd::string_view szDir, bool bAllowUseFS) + void FindData::Scan(IArchive* archive, AZStd::string_view szDir, bool bAllowUseFS, bool bScanZips) { // get the priority into local variable to avoid it changing in the course of // this function execution @@ -87,12 +87,18 @@ namespace AZ::IO { // first, find the file system files ScanFS(archive, szDir); - ScanZips(archive, szDir); + if (bScanZips) + { + ScanZips(archive, szDir); + } } else { // first, find the zip files - ScanZips(archive, szDir); + if (bScanZips) + { + ScanZips(archive, szDir); + } if (bAllowUseFS || nVarPakPriority != ArchiveLocationPriority::ePakPriorityPakOnly) { ScanFS(archive, szDir); @@ -111,30 +117,31 @@ namespace AZ::IO } AZ::IO::FileIOBase::GetDirectInstance()->FindFiles(searchDirectory.c_str(), pattern.c_str(), [&](const char* filePath) -> bool { - AZ::IO::FileDesc fileDesc; - AZStd::string filePathEntry{filePath}; + AZ::IO::ArchiveFileIterator fileIterator; + fileIterator.m_filename = AZ::IO::PathView(filePath).Filename().Native(); + fileIterator.m_fileDesc.nAttrib = {}; if (AZ::IO::FileIOBase::GetDirectInstance()->IsDirectory(filePath)) { - fileDesc.nAttrib = fileDesc.nAttrib | AZ::IO::FileDesc::Attribute::Subdirectory; + fileIterator.m_fileDesc.nAttrib = fileIterator.m_fileDesc.nAttrib | AZ::IO::FileDesc::Attribute::Subdirectory; + m_fileStack.emplace_back(AZStd::move(fileIterator)); } else { if (AZ::IO::FileIOBase::GetDirectInstance()->IsReadOnly(filePath)) { - fileDesc.nAttrib = fileDesc.nAttrib | AZ::IO::FileDesc::Attribute::ReadOnly; + fileIterator.m_fileDesc.nAttrib = fileIterator.m_fileDesc.nAttrib | AZ::IO::FileDesc::Attribute::ReadOnly; } AZ::u64 fileSize = 0; AZ::IO::FileIOBase::GetDirectInstance()->Size(filePath, fileSize); - fileDesc.nSize = fileSize; - fileDesc.tWrite = AZ::IO::FileIOBase::GetDirectInstance()->ModificationTime(filePath); + fileIterator.m_fileDesc.nSize = fileSize; + fileIterator.m_fileDesc.tWrite = AZ::IO::FileIOBase::GetDirectInstance()->ModificationTime(filePath); // These times are not supported by our file interface - fileDesc.tAccess = fileDesc.tWrite; - fileDesc.tCreate = fileDesc.tWrite; + fileIterator.m_fileDesc.tAccess = fileIterator.m_fileDesc.tWrite; + fileIterator.m_fileDesc.tCreate = fileIterator.m_fileDesc.tWrite; + m_fileStack.emplace_back(AZStd::move(fileIterator)); } - [[maybe_unused]] auto result = m_mapFiles.emplace(AZStd::move(filePathEntry), fileDesc); - AZ_Assert(result.second, "Failed to insert FindData entry for filePath %s", filePath); return true; }); } @@ -164,7 +171,7 @@ namespace AZ::IO fileDesc.nAttrib = AZ::IO::FileDesc::Attribute::ReadOnly | AZ::IO::FileDesc::Attribute::Archive; fileDesc.nSize = fileEntry->desc.lSizeUncompressed; fileDesc.tWrite = fileEntry->GetModificationTime(); - m_mapFiles.emplace(fname, fileDesc); + m_fileStack.emplace_back(AZ::IO::ArchiveFileIterator{ this, fname, fileDesc }); } ZipDir::FindDir findDirectoryEntry(zipCache); @@ -177,7 +184,7 @@ namespace AZ::IO } AZ::IO::FileDesc fileDesc; fileDesc.nAttrib = AZ::IO::FileDesc::Attribute::ReadOnly | AZ::IO::FileDesc::Attribute::Archive | AZ::IO::FileDesc::Attribute::Subdirectory; - m_mapFiles.emplace(fname, fileDesc); + m_fileStack.emplace_back(AZ::IO::ArchiveFileIterator{ this, fname, fileDesc }); } }; @@ -246,7 +253,7 @@ namespace AZ::IO if (!bindRootIter->empty() && AZStd::wildcard_match(sourcePathRemainder.Native(), bindRootIter->Native())) { AZ::IO::FileDesc fileDesc{ AZ::IO::FileDesc::Attribute::ReadOnly | AZ::IO::FileDesc::Attribute::Archive | AZ::IO::FileDesc::Attribute::Subdirectory }; - m_mapFiles.emplace(bindRootIter->Native(), fileDesc); + m_fileStack.emplace_back(AZ::IO::ArchiveFileIterator{ this, bindRootIter->Native(), fileDesc }); } } else @@ -262,22 +269,19 @@ namespace AZ::IO AZ::IO::ArchiveFileIterator FindData::Fetch() { - AZ::IO::ArchiveFileIterator fileIterator; - fileIterator.m_findData = this; - if (m_mapFiles.empty()) + if (m_fileStack.empty()) { - return fileIterator; + AZ::IO::ArchiveFileIterator emptyFileIterator; + emptyFileIterator.m_lastFetchValid = false; + emptyFileIterator.m_findData = this; + return emptyFileIterator; } - auto pakFileIter = m_mapFiles.begin(); - AZStd::string fullFilePath; - AZ::StringFunc::Path::GetFullFileName(pakFileIter->first.c_str(), fullFilePath); - fileIterator.m_filename = AZStd::move(fullFilePath); - fileIterator.m_fileDesc = pakFileIter->second; - fileIterator.m_lastFetchValid = true; - // Remove Fetched item from the FindData map so that the iteration continues - m_mapFiles.erase(pakFileIter); + AZ::IO::ArchiveFileIterator fileIterator{ m_fileStack.back() }; + fileIterator.m_lastFetchValid = true; + fileIterator.m_findData = this; + m_fileStack.pop_back(); return fileIterator; } } diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFindData.h b/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFindData.h index d5e23779fc..a07e98c81f 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFindData.h +++ b/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFindData.h @@ -15,7 +15,6 @@ #include #include - namespace AZ::IO { struct IArchive; @@ -74,13 +73,13 @@ namespace AZ::IO AZ_CLASS_ALLOCATOR(FindData, AZ::SystemAllocator, 0); FindData() = default; AZ::IO::ArchiveFileIterator Fetch(); - void Scan(IArchive* archive, AZStd::string_view path, bool bAllowUseFS = false); + void Scan(IArchive* archive, AZStd::string_view path, bool bAllowUseFS = false, bool bScanZips = true); protected: void ScanFS(IArchive* archive, AZStd::string_view path); void ScanZips(IArchive* archive, AZStd::string_view path); - using FileMap = AZStd::map; - FileMap m_mapFiles; + using FileStack = AZStd::vector; + FileStack m_fileStack; }; } diff --git a/Code/Framework/AzFramework/AzFramework/Archive/IArchive.h b/Code/Framework/AzFramework/AzFramework/Archive/IArchive.h index ce8403b033..08bd87c334 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/IArchive.h +++ b/Code/Framework/AzFramework/AzFramework/Archive/IArchive.h @@ -197,6 +197,13 @@ namespace AZ::IO eInMemoryPakLocale_PAK, }; + enum EFileSearchType + { + eFileSearchType_AllowInZipsOnly = 0, + eFileSearchType_AllowOnDiskAndInZips, + eFileSearchType_AllowOnDiskOnly + }; + using SignedFileSize = int64_t; virtual ~IArchive() = default; @@ -315,7 +322,7 @@ namespace AZ::IO // Arguments: // nFlags is a combination of EPathResolutionRules flags. - virtual ArchiveFileIterator FindFirst(AZStd::string_view pDir, uint32_t nFlags = 0, bool bAllowUseFileSystem = false) = 0; + virtual ArchiveFileIterator FindFirst(AZStd::string_view pDir, EFileSearchType searchType = eFileSearchType_AllowInZipsOnly) = 0; virtual ArchiveFileIterator FindNext(AZ::IO::ArchiveFileIterator handle) = 0; virtual bool FindClose(AZ::IO::ArchiveFileIterator handle) = 0; //returns file modification time diff --git a/Code/Sandbox/Editor/CryEditDoc.cpp b/Code/Sandbox/Editor/CryEditDoc.cpp index 5b2a4b9a83..77d5794ab3 100644 --- a/Code/Sandbox/Editor/CryEditDoc.cpp +++ b/Code/Sandbox/Editor/CryEditDoc.cpp @@ -1139,7 +1139,7 @@ bool CCryEditDoc::SaveLevel(const QString& filename) const QString oldLevelPattern = QDir(oldLevelFolder).absoluteFilePath("*.*"); const QString oldLevelName = Path::GetFile(GetLevelPathName()); const QString oldLevelXml = Path::ReplaceExtension(oldLevelName, "xml"); - AZ::IO::ArchiveFileIterator findHandle = pIPak->FindFirst(oldLevelPattern.toUtf8().data(), 0, true); + AZ::IO::ArchiveFileIterator findHandle = pIPak->FindFirst(oldLevelPattern.toUtf8().data(), AZ::IO::IArchive::eFileSearchType_AllowOnDiskAndInZips); if (findHandle) { do diff --git a/Gems/AudioSystem/Code/Tests/AudioSystemEditorTest.cpp b/Gems/AudioSystem/Code/Tests/AudioSystemEditorTest.cpp index e086246e29..d7f9b31e25 100644 --- a/Gems/AudioSystem/Code/Tests/AudioSystemEditorTest.cpp +++ b/Gems/AudioSystem/Code/Tests/AudioSystemEditorTest.cpp @@ -36,14 +36,14 @@ namespace CustomMocks : m_levelName(levelName) {} - AZ::IO::ArchiveFileIterator FindFirst([[maybe_unused]] AZStd::string_view dir, [[maybe_unused]] unsigned int flags, [[maybe_unused]] bool allowUseFileSystem) override + AZ::IO::ArchiveFileIterator FindFirst([[maybe_unused]] AZStd::string_view dir, AZ::IO::IArchive::EFileSearchType) override { AZ::IO::FileDesc fileDesc; fileDesc.nSize = sizeof(AZ::IO::FileDesc); // Add a filename and file description reference to the TestFindData map to make sure the file iterator is valid - AZStd::intrusive_ptr findData = new TestFindData{}; - findData->m_mapFiles.emplace(m_levelName, fileDesc); - return findData->Fetch(); + m_findData = new TestFindData(); + m_findData->m_fileStack.emplace_back(AZ::IO::ArchiveFileIterator{ static_cast(m_findData.get()), m_levelName, fileDesc }); + return m_findData->Fetch(); } AZ::IO::ArchiveFileIterator FindNext(AZ::IO::ArchiveFileIterator iter) override @@ -54,13 +54,14 @@ namespace CustomMocks // public: for easy resetting... AZStd::string m_levelName; - // Add an inherited FindData class to control the adding of a mapfile which indicates that a FileIterator is valid struct TestFindData : AZ::IO::FindData { - using AZ::IO::FindData::m_mapFiles; + using AZ::IO::FindData::m_fileStack; }; + + AZStd::intrusive_ptr m_findData; }; } // namespace CustomMocks