Atom starter game ios fixes (#3297)

* Various fixes for AtomStarterGame on ios
 - Use low end pipeline on ioos by default for BoootStrapComponent
 - Track the need to bind null heap within Argument buffers
 - Only bind the null heap if its needed
 - Track its usage for Vertex/Fragment stages
 - Increase null dummy buffer to 1K to address GPU crash oon thee first frame

Signed-off-by: moudgils <moudgils@amazon.com>
monroegm-disable-blank-issue-2
moudgils 4 years ago committed by GitHub
parent b0fe07158c
commit aa68122002
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -6,6 +6,8 @@
#
#
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME})
ly_add_target(
NAME Atom_Bootstrap.Headers HEADERONLY
NAMESPACE Gem
@ -21,9 +23,12 @@ ly_add_target(
NAMESPACE Gem
FILES_CMAKE
bootstrap_files.cmake
${pal_dir}/bootstrap_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
PLATFORM_INCLUDE_FILES
INCLUDE_DIRECTORIES
PRIVATE
Source
${pal_dir}
PUBLIC
Include
BUILD_DEPENDENCIES

@ -38,6 +38,10 @@
#include <Atom/Bootstrap/BootstrapNotificationBus.h>
#include <Atom/RPI.Reflect/System/AnyAsset.h>
#include <AzCore/Console/IConsole.h>
#include <BootstrapSystemComponent_Traits_Platform.h>
AZ_CVAR(AZ::CVarFixedString, r_default_pipeline_name, AZ_TRAIT_BOOTSTRAPSYSTEMCOMPONENT_PIPELINE_NAME, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Default Render pipeline name");
namespace AZ
{
@ -50,8 +54,7 @@ namespace AZ
if (SerializeContext* serialize = azrtti_cast<SerializeContext*>(context))
{
serialize->Class<BootstrapSystemComponent, Component>()
->Version(0)
->Field("DefaultRenderPipelineAssetFile", &BootstrapSystemComponent::m_defaultPipelineAssetPath)
->Version(1)
;
if (EditContext* ec = serialize->GetEditContext())
@ -60,8 +63,6 @@ namespace AZ
->ClassElement(Edit::ClassElements::EditorData, "")
->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b))
->Attribute(Edit::Attributes::AutoExpand, true)
->DataElement(Edit::UIHandlers::Default, &BootstrapSystemComponent::m_defaultPipelineAssetPath, "Default RenderPipeline Asset",
"The asset file path of default render pipeline for default window")
;
}
}
@ -314,13 +315,15 @@ namespace AZ
// Create a render pipeline from the specified asset for the window context and add the pipeline to the scene.
// When running with no Asset Processor (for example in release), CompileAssetSync will return AssetStatus_Unknown.
AzFramework::AssetSystem::AssetStatus status = AzFramework::AssetSystem::AssetStatus_Unknown;
AzFramework::AssetSystemRequestBus::BroadcastResult(
status, &AzFramework::AssetSystemRequestBus::Events::CompileAssetSync, m_defaultPipelineAssetPath);
AZ_Assert(status == AzFramework::AssetSystem::AssetStatus_Compiled || status == AzFramework::AssetSystem::AssetStatus_Unknown, "Could not compile the default render pipeline at '%s'", m_defaultPipelineAssetPath.c_str());
const AZ::CVarFixedString pipelineName = static_cast<AZ::CVarFixedString>(r_default_pipeline_name);
AzFramework::AssetSystemRequestBus::BroadcastResult(status, &AzFramework::AssetSystemRequestBus::Events::CompileAssetSync, pipelineName.data());
AZ_Assert(status == AzFramework::AssetSystem::AssetStatus_Compiled || status == AzFramework::AssetSystem::AssetStatus_Unknown, "Could not compile the default render pipeline at '%s'", pipelineName.c_str());
Data::Asset<RPI::AnyAsset> pipelineAsset = RPI::AssetUtils::LoadAssetByProductPath<RPI::AnyAsset>(m_defaultPipelineAssetPath.c_str(), RPI::AssetUtils::TraceLevel::Error);
Data::Asset<RPI::AnyAsset> pipelineAsset = RPI::AssetUtils::LoadAssetByProductPath<RPI::AnyAsset>(pipelineName.data(), RPI::AssetUtils::TraceLevel::Error);
RPI::RenderPipelineDescriptor renderPipelineDescriptor = *RPI::GetDataFromAnyAsset<RPI::RenderPipelineDescriptor>(pipelineAsset);
renderPipelineDescriptor.m_name = AZStd::string::format("%s_%i", renderPipelineDescriptor.m_name.c_str(), viewportContext->GetId());
if (!scene->GetRenderPipeline(AZ::Name(renderPipelineDescriptor.m_name)))
{
RPI::RenderPipelinePtr renderPipeline = RPI::RenderPipeline::CreateRenderPipelineForWindow(renderPipelineDescriptor, *viewportContext->GetWindowContext().get());

@ -112,10 +112,7 @@ namespace AZ
// The id of the render pipeline created by this component
RPI::RenderPipelineId m_renderPipelineId;
// Variables which are system component configuration
AZStd::string m_defaultPipelineAssetPath = "passes/MainRenderPipeline.azasset";
// Save a reference to the image created by the BRDF pipeline so it doesn't get auto deleted if it's ref count goes to zero
// For example, if we delete all the passes, we won't have to recreate the BRDF pipeline to recreate the BRDF texture
Data::Instance<RPI::AttachmentImage> m_brdfTexture;

@ -0,0 +1,9 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#define AZ_TRAIT_BOOTSTRAPSYSTEMCOMPONENT_PIPELINE_NAME "passes/LowEndRenderPipeline.azasset"

@ -0,0 +1,12 @@
#
# Copyright (c) Contributors to the Open 3D Engine Project.
# For complete copyright and license terms please see the LICENSE at the root of this distribution.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
#
set(FILES
BootstrapSystemComponent_Traits_Platform.h
)

@ -0,0 +1,9 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#define AZ_TRAIT_BOOTSTRAPSYSTEMCOMPONENT_PIPELINE_NAME "passes/MainRenderPipeline.azasset"

@ -0,0 +1,12 @@
#
# Copyright (c) Contributors to the Open 3D Engine Project.
# For complete copyright and license terms please see the LICENSE at the root of this distribution.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
#
set(FILES
BootstrapSystemComponent_Traits_Platform.h
)

@ -0,0 +1,9 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#define AZ_TRAIT_BOOTSTRAPSYSTEMCOMPONENT_PIPELINE_NAME "passes/MainRenderPipeline.azasset"

@ -0,0 +1,12 @@
#
# Copyright (c) Contributors to the Open 3D Engine Project.
# For complete copyright and license terms please see the LICENSE at the root of this distribution.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
#
set(FILES
BootstrapSystemComponent_Traits_Platform.h
)

@ -0,0 +1,9 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#define AZ_TRAIT_BOOTSTRAPSYSTEMCOMPONENT_PIPELINE_NAME "passes/MainRenderPipeline.azasset"

@ -0,0 +1,12 @@
#
# Copyright (c) Contributors to the Open 3D Engine Project.
# For complete copyright and license terms please see the LICENSE at the root of this distribution.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
#
set(FILES
BootstrapSystemComponent_Traits_Platform.h
)

@ -0,0 +1,9 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#define AZ_TRAIT_BOOTSTRAPSYSTEMCOMPONENT_PIPELINE_NAME "passes/LowEndRenderPipeline.azasset"

@ -0,0 +1,12 @@
#
# Copyright (c) Contributors to the Open 3D Engine Project.
# For complete copyright and license terms please see the LICENSE at the root of this distribution.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
#
set(FILES
BootstrapSystemComponent_Traits_Platform.h
)

@ -0,0 +1,15 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "RenderPipelineDescriptor",
"ClassData": {
"Name": "LowEndPipeline",
"MainViewTag": "MainCamera",
"RootPassTemplate": "LowEndPipelineTemplate",
"RenderSettings": {
"MultisampleState": {
"samples": 1
}
}
}
}

@ -204,6 +204,7 @@ namespace AZ
{
RHI::Ptr<Memory> nullMtlImagePtr = m_device->GetNullDescriptorManager().GetNullImage(shaderInputImage.m_type).GetMemory();
mtlTextures[imageArrayLen] = nullMtlImagePtr->GetGpuAddress<id<MTLTexture>>();
m_useNullDescriptorHeap = true;
}
imageArrayLen++;
}
@ -282,12 +283,16 @@ namespace AZ
{
RHI::Ptr<Memory> nullMtlBufferMemPtr = nullDescriptorManager.GetNullImageBuffer().GetMemory();
mtlTextures[bufferArrayLen] = nullMtlBufferMemPtr->GetGpuAddress<id<MTLTexture>>();
m_useNullDescriptorHeap = true;
}
else
{
RHI::Ptr<Memory> nullMtlBufferMemPtr = nullDescriptorManager.GetNullBuffer().GetMemory();
mtlBuffers[bufferArrayLen] = nullMtlBufferMemPtr->GetGpuAddress<id<MTLBuffer>>();
mtlBufferOffsets[bufferArrayLen] = nullDescriptorManager.GetNullBuffer().GetOffset();
m_resourceBindings[shaderInputBuffer.m_name].insert(
ResourceBindingData{nullMtlBufferMemPtr, .m_bufferAccess = shaderInputBuffer.m_access}
);
}
}
@ -499,5 +504,26 @@ namespace AZ
resourcesToMakeResidentMap[key].emplace(mtlResourceToBind);
}
}
bool ArgumentBuffer::IsNullHeapNeededForVertexStage(const ShaderResourceGroupVisibility& srgResourcesVisInfo) const
{
bool isUsedByVertexStage = false;
//Iterate over all the SRG entries
for (const auto& it : srgResourcesVisInfo.m_resourcesStageMask)
{
//Only the ones not added to m_resourceBindings would require null heap
if( m_resourceBindings.find(it.first) == m_resourceBindings.end())
{
isUsedByVertexStage |= RHI::CheckBitsAny(it.second, RHI::ShaderStageMask::Vertex);
}
}
return isUsedByVertexStage;
}
bool ArgumentBuffer::IsNullDescHeapNeeded() const
{
return m_useNullDescriptorHeap;
}
}
}

@ -104,6 +104,8 @@ namespace AZ
GraphicsResourcesToMakeResidentMap& resourcesToMakeResidentGraphics) const;
void ClearResourceTracking();
bool IsNullHeapNeededForVertexStage(const ShaderResourceGroupVisibility& srgResourcesVisInfo) const;
bool IsNullDescHeapNeeded() const;
//////////////////////////////////////////////////////////////////////////
// RHI::DeviceObject
@ -153,6 +155,7 @@ namespace AZ
MemoryView m_argumentBuffer;
MemoryView m_constantBuffer;
#endif
bool m_useNullDescriptorHeap = false;
};
}
}

@ -245,6 +245,8 @@ namespace AZ
bool CommandList::SetArgumentBuffers(const PipelineState* pipelineState, RHI::PipelineStateType stateType)
{
bool bindNullDescriptorHeap = false;
MTLRenderStages mtlRenderStagesForNullDescHeap = 0;
ShaderResourceBindings& bindings = GetShaderResourceBindingsByPipelineType(stateType);
const PipelineLayout& pipelineLayout = pipelineState->GetPipelineLayout();
@ -280,7 +282,8 @@ namespace AZ
uint32_t srgVisIndex = pipelineLayout.GetIndexBySlot(shaderResourceGroup->GetBindingSlot());
const RHI::ShaderStageMask& srgVisInfo = pipelineLayout.GetSrgVisibility(srgVisIndex);
const ShaderResourceGroupVisibility& srgResourcesVisInfo = pipelineLayout.GetSrgResourcesVisibility(srgVisIndex);
bool isSrgUpdatd = bindings.m_srgsByIndex[slot] != shaderResourceGroup;
if(isSrgUpdatd)
{
@ -291,6 +294,9 @@ namespace AZ
if(srgVisInfo != RHI::ShaderStageMask::None)
{
bool isNullDescHeapNeeded = compiledArgBuffer.IsNullDescHeapNeeded();
bindNullDescriptorHeap |= isNullDescHeapNeeded;
//For graphics and compute shader stages, cache all the argument buffers, offsets and track the min/max indices
if(m_commandEncoderType == CommandEncoderType::Render)
{
@ -300,7 +306,9 @@ namespace AZ
mtlVertexArgBuffers[slotIndex] = argBuffer;
mtlVertexArgBufferOffsets[slotIndex] = argBufferOffset;
bufferVertexRegisterIdMin = AZStd::min(slotIndex, bufferVertexRegisterIdMin);
bufferVertexRegisterIdMax = AZStd::max(slotIndex, bufferVertexRegisterIdMax);
bufferVertexRegisterIdMax = AZStd::max(slotIndex, bufferVertexRegisterIdMax);
mtlRenderStagesForNullDescHeap = shaderResourceGroup->IsNullHeapNeededForVertexStage(srgResourcesVisInfo) ?
mtlRenderStagesForNullDescHeap | MTLRenderStageVertex : mtlRenderStagesForNullDescHeap;
}
if( numBitsSet > 1 || srgVisInfo == RHI::ShaderStageMask::Fragment)
@ -309,6 +317,7 @@ namespace AZ
mtlFragmentOrComputeArgBufferOffsets[slotIndex] = argBufferOffset;
bufferFragmentOrComputeRegisterIdMin = AZStd::min(slotIndex, bufferFragmentOrComputeRegisterIdMin);
bufferFragmentOrComputeRegisterIdMax = AZStd::max(slotIndex, bufferFragmentOrComputeRegisterIdMax);
mtlRenderStagesForNullDescHeap = isNullDescHeapNeeded ? mtlRenderStagesForNullDescHeap | MTLRenderStageFragment : mtlRenderStagesForNullDescHeap;
}
}
else if(m_commandEncoderType == CommandEncoderType::Compute)
@ -329,7 +338,7 @@ namespace AZ
bindings.m_srgVisHashByIndex[slot] = srgResourcesVisHash;
if(srgVisInfo != RHI::ShaderStageMask::None)
{
const ShaderResourceGroupVisibility& srgResourcesVisInfo = pipelineLayout.GetSrgResourcesVisibility(srgVisIndex);
//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
@ -396,6 +405,10 @@ namespace AZ
stages: key.first.second];
}
if(bindNullDescriptorHeap)
{
MakeHeapsResident(mtlRenderStagesForNullDescHeap);
}
return true;
}

@ -64,6 +64,7 @@ namespace AZ
{
[m_encoder endEncoding];
m_encoder = nil;
m_isNullDescHeapBound = false;
#if AZ_TRAIT_ATOM_METAL_COUNTER_SAMPLING
if (m_supportsInterDrawTimestamps)
{
@ -73,18 +74,25 @@ namespace AZ
}
}
void CommandListBase::MakeHeapsResident()
void CommandListBase::MakeHeapsResident(MTLRenderStages renderStages)
{
if(m_isNullDescHeapBound)
{
return;
}
switch(m_commandEncoderType)
{
case CommandEncoderType::Render:
{
id<MTLRenderCommandEncoder> renderEncoder = GetEncoder<id<MTLRenderCommandEncoder>>();
for (id<MTLHeap> residentHeap : *m_residentHeaps)
if(renderStages != 0)
{
//MTLRenderStageVertex is not added to this as it was causing an immediate gpu crash on ios (first buffer commit)
[renderEncoder useHeap : residentHeap
stages : MTLRenderStageFragment];
id<MTLRenderCommandEncoder> renderEncoder = GetEncoder<id<MTLRenderCommandEncoder>>();
for (id<MTLHeap> residentHeap : *m_residentHeaps)
{
[renderEncoder useHeap : residentHeap
stages : renderStages];
}
}
break;
}
@ -102,6 +110,7 @@ namespace AZ
AZ_Assert(false, "Encoder Type not supported");
}
}
m_isNullDescHeapBound = true;
}
void CommandListBase::CreateEncoder(CommandEncoderType encoderType)
@ -119,16 +128,12 @@ namespace AZ
m_commandEncoderType = CommandEncoderType::Render;
m_encoder = [m_mtlCommandBuffer renderCommandEncoderWithDescriptor : m_renderPassDescriptor];
m_renderPassDescriptor = nil;
MakeHeapsResident();
break;
}
case CommandEncoderType::Compute:
{
m_commandEncoderType = CommandEncoderType::Compute;
m_encoder = [m_mtlCommandBuffer computeCommandEncoder];
MakeHeapsResident();
break;
}
case CommandEncoderType::Blit:

@ -89,12 +89,14 @@ namespace AZ
/// Cache multisample state. Used mainly to validate the MSAA image descriptor against the one passed into the pipelinestate
RHI::MultisampleState m_renderPassMultiSampleState;
//! Go through all the heaps and call UseHeap on them to make them resident for the upcoming pass.
void MakeHeapsResident(MTLRenderStages renderStages);
private:
//! Go through all the heaps and call UseHeap on them to make them resident for the upcoming pass.
void MakeHeapsResident();
bool m_isEncoded = false;
bool m_isNullDescHeapBound = false;
RHI::HardwareQueueClass m_hardwareQueueClass = RHI::HardwareQueueClass::Graphics;
NSString* m_encoderScopeName = nullptr;
id <MTLCommandBuffer> m_mtlCommandBuffer = nil;

@ -126,10 +126,10 @@ namespace AZ
Device& device = static_cast<Device&>(GetDevice());
m_nullBuffer.m_name = "NULL_DESCRIPTOR_BUFFER";
m_nullBuffer.m_bufferDescriptor.m_byteCount = 64;
m_nullBuffer.m_bufferDescriptor.m_byteCount = 1024;
m_nullBuffer.m_bufferDescriptor.m_bindFlags = RHI::BufferBindFlags::ShaderWrite;
m_nullBuffer.m_memoryView = device.CreateBufferCommitted(m_nullBuffer.m_bufferDescriptor);
m_nullBuffer.m_memoryView.SetName( m_nullBuffer.m_name.c_str());
if(!m_nullBuffer.m_memoryView.IsValid())
{
AZ_Assert(false, "Couldnt create a null buffer for ArgumentTable");

@ -36,5 +36,10 @@ namespace AZ
{
GetCompiledArgumentBuffer().CollectUntrackedResources(commandEncoder, srgResourcesVisInfo, resourcesToMakeResidentCompute, resourcesToMakeResidentGraphics);
}
bool ShaderResourceGroup::IsNullHeapNeededForVertexStage(const ShaderResourceGroupVisibility& srgResourcesVisInfo) const
{
return GetCompiledArgumentBuffer().IsNullHeapNeededForVertexStage(srgResourcesVisInfo);
}
}
}

@ -47,7 +47,8 @@ namespace AZ
const ShaderResourceGroupVisibility& srgResourcesVisInfo,
ArgumentBuffer::ComputeResourcesToMakeResidentMap& resourcesToMakeResidentCompute,
ArgumentBuffer::GraphicsResourcesToMakeResidentMap& resourcesToMakeResidentGraphics) const;
bool IsNullHeapNeededForVertexStage(const ShaderResourceGroupVisibility& srgResourcesVisInfo) const;
private:
ShaderResourceGroup() = default;

Loading…
Cancel
Save