Merge pull request #1246 from aws-lumberyard-dev/UpdateIosPipeline
Fix many issues on Mac metal
This commit is contained in:
@@ -10,7 +10,5 @@
|
|||||||
"type": "Compute"
|
"type": "Compute"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
}
|
||||||
"DisabledRHIBackends": ["metal"]
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,10 @@
|
|||||||
|
|
||||||
ShaderResourceGroup MorphTargetPassSrg : SRG_PerPass
|
ShaderResourceGroup MorphTargetPassSrg : SRG_PerPass
|
||||||
{
|
{
|
||||||
RWBuffer<int> m_accumulatedDeltas;
|
//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<int> m_accumulatedDeltas;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This class represents the data that is passed to the morph target compute shader of an individual delta
|
// This class represents the data that is passed to the morph target compute shader of an individual delta
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ ShaderResourceGroup PassSrg : SRG_PerPass
|
|||||||
Texture2D<float4> m_sceneLuminance;
|
Texture2D<float4> m_sceneLuminance;
|
||||||
|
|
||||||
// This should be of size NUM_HISTOGRAM_BINS.
|
// This should be of size NUM_HISTOGRAM_BINS.
|
||||||
Buffer<uint> m_histogram;
|
StructuredBuffer<uint> m_histogram;
|
||||||
|
|
||||||
Sampler LinearSampler
|
Sampler LinearSampler
|
||||||
{
|
{
|
||||||
|
|||||||
+5
-1
@@ -20,7 +20,11 @@
|
|||||||
ShaderResourceGroup PassSrg : SRG_PerPass
|
ShaderResourceGroup PassSrg : SRG_PerPass
|
||||||
{
|
{
|
||||||
Texture2D<float4> m_inputTexture;
|
Texture2D<float4> m_inputTexture;
|
||||||
RWBuffer<uint> m_outputTexture;
|
|
||||||
|
//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<uint> m_outputTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
groupshared uint shared_histogramBins[NUM_HISTOGRAM_BINS];
|
groupshared uint shared_histogramBins[NUM_HISTOGRAM_BINS];
|
||||||
|
|||||||
+1
-3
@@ -12,7 +12,5 @@
|
|||||||
"type": "Compute"
|
"type": "Compute"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
}
|
||||||
"DisabledRHIBackends": ["metal"]
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
ShaderResourceGroup PassSrg : SRG_PerPass
|
ShaderResourceGroup PassSrg : SRG_PerPass
|
||||||
{
|
{
|
||||||
RWBuffer<float> m_skinnedMeshOutputStream;
|
RWStructuredBuffer<float> m_skinnedMeshOutputStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderResourceGroup InstanceSrg : SRG_PerDraw
|
ShaderResourceGroup InstanceSrg : SRG_PerDraw
|
||||||
|
|||||||
+1
-1
@@ -67,7 +67,7 @@ namespace AZ
|
|||||||
desc.m_bufferName = "LuminanceHistogramBuffer";
|
desc.m_bufferName = "LuminanceHistogramBuffer";
|
||||||
desc.m_elementSize = sizeof(uint32_t);
|
desc.m_elementSize = sizeof(uint32_t);
|
||||||
desc.m_byteCount = NumHistogramBins * 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);
|
m_histogram = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
|
||||||
AZ_Assert(m_histogram != nullptr, "Unable to allocate buffer");
|
AZ_Assert(m_histogram != nullptr, "Unable to allocate buffer");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,8 +67,8 @@ namespace AZ
|
|||||||
creator.SetBuffer(nullptr, 0, bufferDescriptor);
|
creator.SetBuffer(nullptr, 0, bufferDescriptor);
|
||||||
|
|
||||||
RHI::BufferViewDescriptor viewDescriptor;
|
RHI::BufferViewDescriptor viewDescriptor;
|
||||||
viewDescriptor.m_elementFormat = RHI::Format::R32_FLOAT;
|
viewDescriptor.m_elementFormat = RHI::Format::Unknown;
|
||||||
viewDescriptor.m_elementSize = RHI::GetFormatSize(viewDescriptor.m_elementFormat);
|
viewDescriptor.m_elementSize = sizeof(float);
|
||||||
viewDescriptor.m_elementCount = aznumeric_cast<uint32_t>(m_sizeInBytes) / viewDescriptor.m_elementSize;
|
viewDescriptor.m_elementCount = aznumeric_cast<uint32_t>(m_sizeInBytes) / viewDescriptor.m_elementSize;
|
||||||
viewDescriptor.m_elementOffset = 0;
|
viewDescriptor.m_elementOffset = 0;
|
||||||
creator.SetBufferViewDescriptor(viewDescriptor);
|
creator.SetBufferViewDescriptor(viewDescriptor);
|
||||||
|
|||||||
@@ -160,6 +160,16 @@ namespace AZ
|
|||||||
StencilState m_stencil;
|
StencilState m_stencil;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class WriteChannelMask : uint8_t
|
||||||
|
{
|
||||||
|
ColorWriteMaskNone = 0,
|
||||||
|
ColorWriteMaskRed = AZ_BIT(0),
|
||||||
|
ColorWriteMaskGreen = AZ_BIT(1),
|
||||||
|
ColorWriteMaskBlue = AZ_BIT(2),
|
||||||
|
ColorWriteMaskAlpha = AZ_BIT(3),
|
||||||
|
ColorWriteMaskAll = ColorWriteMaskRed | ColorWriteMaskGreen | ColorWriteMaskBlue | ColorWriteMaskAlpha
|
||||||
|
};
|
||||||
|
|
||||||
struct TargetBlendState
|
struct TargetBlendState
|
||||||
{
|
{
|
||||||
AZ_TYPE_INFO(TargetBlendState, "{2CDF00FE-614D-44FC-929F-E6B50C348578}");
|
AZ_TYPE_INFO(TargetBlendState, "{2CDF00FE-614D-44FC-929F-E6B50C348578}");
|
||||||
|
|||||||
@@ -410,7 +410,6 @@ namespace AZ
|
|||||||
// For any other type the buffer view's element size should match the stride.
|
// For any other type the buffer view's element size should match the stride.
|
||||||
if (shaderInputBuffer.m_strideSize != bufferViewDescriptor.m_elementSize)
|
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",
|
AZ_Error("ShaderResourceGroupData", false, "Buffer Input '%s[%d]': Does not match expected stride size %d",
|
||||||
shaderInputBuffer.m_name.GetCStr(), arrayIndex, bufferViewDescriptor.m_elementSize);
|
shaderInputBuffer.m_name.GetCStr(), arrayIndex, bufferViewDescriptor.m_elementSize);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -271,6 +271,12 @@ namespace AZ
|
|||||||
ShaderResourceBindings& bindings = GetShaderResourceBindingsByPipelineType(pipelineType);
|
ShaderResourceBindings& bindings = GetShaderResourceBindingsByPipelineType(pipelineType);
|
||||||
|
|
||||||
const PipelineState* pipelineState = static_cast<const PipelineState*>(item.m_pipelineState);
|
const PipelineState* pipelineState = static_cast<const PipelineState*>(item.m_pipelineState);
|
||||||
|
if(!pipelineState)
|
||||||
|
{
|
||||||
|
AZ_Assert(false, "Pipeline state not provided");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool updatePipelineState = m_state.m_pipelineState != pipelineState;
|
bool updatePipelineState = m_state.m_pipelineState != pipelineState;
|
||||||
// The pipeline state gets set first.
|
// The pipeline state gets set first.
|
||||||
if (updatePipelineState)
|
if (updatePipelineState)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include "RHI/Atom_RHI_DX12_precompiled.h"
|
#include "RHI/Atom_RHI_DX12_precompiled.h"
|
||||||
|
#include <Atom/RHI.Reflect/Bits.h>
|
||||||
#include <RHI/Conversions.h>
|
#include <RHI/Conversions.h>
|
||||||
#include <RHI/Buffer.h>
|
#include <RHI/Buffer.h>
|
||||||
#include <RHI/Image.h>
|
#include <RHI/Image.h>
|
||||||
@@ -1268,7 +1269,7 @@ namespace AZ
|
|||||||
dst.BlendOpAlpha = ConvertBlendOp(src.m_blendAlphaOp);
|
dst.BlendOpAlpha = ConvertBlendOp(src.m_blendAlphaOp);
|
||||||
dst.DestBlend = ConvertBlendFactor(src.m_blendDest);
|
dst.DestBlend = ConvertBlendFactor(src.m_blendDest);
|
||||||
dst.DestBlendAlpha = ConvertBlendFactor(src.m_blendAlphaDest);
|
dst.DestBlendAlpha = ConvertBlendFactor(src.m_blendAlphaDest);
|
||||||
dst.RenderTargetWriteMask = src.m_writeMask;
|
dst.RenderTargetWriteMask = ConvertColorWriteMask(src.m_writeMask);
|
||||||
dst.SrcBlend = ConvertBlendFactor(src.m_blendSource);
|
dst.SrcBlend = ConvertBlendFactor(src.m_blendSource);
|
||||||
dst.SrcBlendAlpha = ConvertBlendFactor(src.m_blendAlphaSource);
|
dst.SrcBlendAlpha = ConvertBlendFactor(src.m_blendAlphaSource);
|
||||||
dst.LogicOp = D3D12_LOGIC_OP_CLEAR;
|
dst.LogicOp = D3D12_LOGIC_OP_CLEAR;
|
||||||
@@ -1355,6 +1356,38 @@ namespace AZ
|
|||||||
};
|
};
|
||||||
return table[(uint32_t)mask];
|
return table[(uint32_t)mask];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t ConvertColorWriteMask(uint8_t writeMask)
|
||||||
|
{
|
||||||
|
uint8_t dflags = 0;
|
||||||
|
if(writeMask == 0)
|
||||||
|
{
|
||||||
|
return dflags;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(RHI::CheckBitsAll(writeMask, static_cast<uint8_t>(RHI::WriteChannelMask::ColorWriteMaskAll)))
|
||||||
|
{
|
||||||
|
return D3D12_COLOR_WRITE_ENABLE_ALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RHI::CheckBitsAny(writeMask, static_cast<uint8_t>(RHI::WriteChannelMask::ColorWriteMaskRed)))
|
||||||
|
{
|
||||||
|
dflags |= D3D12_COLOR_WRITE_ENABLE_RED;
|
||||||
|
}
|
||||||
|
if (RHI::CheckBitsAny(writeMask, static_cast<uint8_t>(RHI::WriteChannelMask::ColorWriteMaskGreen)))
|
||||||
|
{
|
||||||
|
dflags |= D3D12_COLOR_WRITE_ENABLE_GREEN;
|
||||||
|
}
|
||||||
|
if (RHI::CheckBitsAny(writeMask, static_cast<uint8_t>(RHI::WriteChannelMask::ColorWriteMaskBlue)))
|
||||||
|
{
|
||||||
|
dflags |= D3D12_COLOR_WRITE_ENABLE_BLUE;
|
||||||
|
}
|
||||||
|
if (RHI::CheckBitsAny(writeMask, static_cast<uint8_t>(RHI::WriteChannelMask::ColorWriteMaskAlpha)))
|
||||||
|
{
|
||||||
|
dflags |= D3D12_COLOR_WRITE_ENABLE_ALPHA;
|
||||||
|
}
|
||||||
|
return dflags;
|
||||||
|
}
|
||||||
|
|
||||||
D3D12_DEPTH_STENCIL_DESC ConvertDepthStencilState(const RHI::DepthStencilState& depthStencil)
|
D3D12_DEPTH_STENCIL_DESC ConvertDepthStencilState(const RHI::DepthStencilState& depthStencil)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -164,5 +164,7 @@ namespace AZ
|
|||||||
uint32_t shaderRegisterSpace,
|
uint32_t shaderRegisterSpace,
|
||||||
D3D12_SHADER_VISIBILITY shaderVisibility,
|
D3D12_SHADER_VISIBILITY shaderVisibility,
|
||||||
D3D12_STATIC_SAMPLER_DESC& staticSamplerDesc);
|
D3D12_STATIC_SAMPLER_DESC& staticSamplerDesc);
|
||||||
|
|
||||||
|
uint8_t ConvertColorWriteMask(uint8_t writeMask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ namespace Platform
|
|||||||
|
|
||||||
void ResizeInternal(RHIMetalView* metalView, CGSize viewSize)
|
void ResizeInternal(RHIMetalView* metalView, CGSize viewSize)
|
||||||
{
|
{
|
||||||
[metalView resizeSubviewsWithOldSize:viewSize];
|
[metalView.metalLayer setDrawableSize: viewSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
RHIMetalView* GetMetalView(NativeWindowType* nativeWindow)
|
RHIMetalView* GetMetalView(NativeWindowType* nativeWindow)
|
||||||
|
|||||||
@@ -386,35 +386,35 @@ namespace AZ
|
|||||||
|
|
||||||
void ArgumentBuffer::AddUntrackedResourcesToEncoder(id<MTLCommandEncoder> commandEncoder, const ShaderResourceGroupVisibility& srgResourcesVisInfo) const
|
void ArgumentBuffer::AddUntrackedResourcesToEncoder(id<MTLCommandEncoder> commandEncoder, const ShaderResourceGroupVisibility& srgResourcesVisInfo) const
|
||||||
{
|
{
|
||||||
|
//Map to cache all the resources based on the usage as we can batch all the resources for a given usage
|
||||||
|
ComputeResourcesToMakeResidentMap resourcesToMakeResidentCompute;
|
||||||
|
//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
|
||||||
if (m_constantBufferSize)
|
if (m_constantBufferSize)
|
||||||
{
|
{
|
||||||
uint8_t numBitsSet = RHI::CountBitsSet(static_cast<uint64_t>(srgResourcesVisInfo.m_constantDataStageMask));
|
uint8_t numBitsSet = RHI::CountBitsSet(static_cast<uint64_t>(srgResourcesVisInfo.m_constantDataStageMask));
|
||||||
if( numBitsSet > 0)
|
if( numBitsSet > 0)
|
||||||
{
|
{
|
||||||
|
id<MTLResource> mtlconstantBufferResource = m_constantBuffer.GetGpuAddress<id<MTLResource>>();
|
||||||
if(RHI::CheckBitsAny(srgResourcesVisInfo.m_constantDataStageMask, RHI::ShaderStageMask::Compute))
|
if(RHI::CheckBitsAny(srgResourcesVisInfo.m_constantDataStageMask, RHI::ShaderStageMask::Compute))
|
||||||
{
|
{
|
||||||
[static_cast<id<MTLComputeCommandEncoder>>(commandEncoder) useResource:m_constantBuffer.GetGpuAddress<id<MTLBuffer>>() usage:MTLResourceUsageRead];
|
uint16_t arrayIndex = resourcesToMakeResidentCompute[MTLResourceUsageRead].m_resourceArrayLen++;
|
||||||
|
resourcesToMakeResidentCompute[MTLResourceUsageRead].m_resourceArray[arrayIndex] = mtlconstantBufferResource;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MTLRenderStages mtlRenderStages = GetRenderStages(srgResourcesVisInfo.m_constantDataStageMask);
|
MTLRenderStages mtlRenderStages = GetRenderStages(srgResourcesVisInfo.m_constantDataStageMask);
|
||||||
[static_cast<id<MTLRenderCommandEncoder>>(commandEncoder) useResource:m_constantBuffer.GetGpuAddress<id<MTLBuffer>>()
|
AZStd::pair <MTLResourceUsage,MTLRenderStages> key = AZStd::make_pair(MTLResourceUsageRead, mtlRenderStages);
|
||||||
usage:MTLResourceUsageRead
|
uint16_t arrayIndex = resourcesToMakeResidentGraphics[key].m_resourceArrayLen++;
|
||||||
stages:mtlRenderStages];
|
resourcesToMakeResidentGraphics[key].m_resourceArray[arrayIndex] = mtlconstantBufferResource;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ApplyUseResource(commandEncoder, m_resourceBindings, srgResourcesVisInfo);
|
|
||||||
}
|
//Cach all the resources within a srg that are used by the shader based on the visibility information
|
||||||
|
for (const auto& it : m_resourceBindings)
|
||||||
void ArgumentBuffer::ApplyUseResource(id<MTLCommandEncoder> encoder,
|
|
||||||
const ResourceBindingsMap& resourceMap,
|
|
||||||
const ShaderResourceGroupVisibility& srgResourcesVisInfo) const
|
|
||||||
{
|
|
||||||
|
|
||||||
CommandEncoderType encodeType = CommandEncoderType::Invalid;
|
|
||||||
for (const auto& it : resourceMap)
|
|
||||||
{
|
{
|
||||||
//Extract the visibility mask for the give resource
|
//Extract the visibility mask for the give resource
|
||||||
auto visMaskIt = srgResourcesVisInfo.m_resourcesStageMask.find(it.first);
|
auto visMaskIt = srgResourcesVisInfo.m_resourcesStageMask.find(it.first);
|
||||||
@@ -426,75 +426,53 @@ namespace AZ
|
|||||||
{
|
{
|
||||||
if(RHI::CheckBitsAny(visMaskIt->second, RHI::ShaderStageMask::Compute))
|
if(RHI::CheckBitsAny(visMaskIt->second, RHI::ShaderStageMask::Compute))
|
||||||
{
|
{
|
||||||
//Call UseResource on all resources for Compute stage
|
CollectResourcesForCompute(commandEncoder, it.second, resourcesToMakeResidentCompute);
|
||||||
ApplyUseResourceToCompute(encoder, it.second);
|
|
||||||
encodeType = CommandEncoderType::Compute;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Call UseResource on all resources for Vertex and Fragment stages
|
bool isBoundToGraphics = RHI::CheckBitsAny(visMaskIt->second, RHI::ShaderStageMask::Vertex) || RHI::CheckBitsAny(visMaskIt->second, RHI::ShaderStageMask::Fragment);
|
||||||
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);
|
AZ_Assert(isBoundToGraphics, "The visibility mask %i is not set for Vertex or fragment stage", visMaskIt->second);
|
||||||
ApplyUseResourceToGraphic(encoder, visMaskIt->second, it.second);
|
CollectResourcesForGraphics(commandEncoder, visMaskIt->second, it.second, resourcesToMakeResidentGraphics);
|
||||||
encodeType = CommandEncoderType::Render;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void ArgumentBuffer::ApplyUseResourceToCompute(id<MTLCommandEncoder> encoder, const ResourceBindingsSet& resourceBindingDataSet) const
|
|
||||||
{
|
|
||||||
for (const auto& resourceBindingData : resourceBindingDataSet)
|
|
||||||
{
|
|
||||||
ResourceType rescType = resourceBindingData.m_resourcPtr->GetResourceType();
|
|
||||||
switch(rescType)
|
|
||||||
{
|
|
||||||
case ResourceType::MtlTextureType:
|
|
||||||
{
|
|
||||||
MTLResourceUsage resourceUsage = GetImageResourceUsage(resourceBindingData.m_imageAccess);
|
|
||||||
[static_cast<id<MTLComputeCommandEncoder>>(encoder) useResource:resourceBindingData.m_resourcPtr->GetGpuAddress<id<MTLTexture>>() usage:resourceUsage];
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ResourceType::MtlBufferType:
|
|
||||||
{
|
|
||||||
MTLResourceUsage resourceUsage = GetBufferResourceUsage(resourceBindingData.m_bufferAccess);
|
|
||||||
[static_cast<id<MTLComputeCommandEncoder>>(encoder) useResource:resourceBindingData.m_resourcPtr->GetGpuAddress<id<MTLBuffer>>() usage:resourceUsage];
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
AZ_Assert(false, "Undefined Resource type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ArgumentBuffer::ApplyUseResourceToGraphic(id<MTLCommandEncoder> encoder, RHI::ShaderStageMask visShaderMask, const ResourceBindingsSet& resourceBindingDataSet) const
|
|
||||||
{
|
|
||||||
|
|
||||||
MTLRenderStages mtlRenderStages = GetRenderStages(visShaderMask);
|
//Call UseResource on all resources for Compute stage
|
||||||
|
for (const auto& key : resourcesToMakeResidentCompute)
|
||||||
|
{
|
||||||
|
[static_cast<id<MTLComputeCommandEncoder>>(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<id<MTLRenderCommandEncoder>>(commandEncoder) useResources: key.second.m_resourceArray.data()
|
||||||
|
count: key.second.m_resourceArrayLen
|
||||||
|
usage: key.first.first
|
||||||
|
stages: key.first.second];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArgumentBuffer::CollectResourcesForCompute(id<MTLCommandEncoder> encoder,
|
||||||
|
const ResourceBindingsSet& resourceBindingDataSet,
|
||||||
|
ComputeResourcesToMakeResidentMap& resourcesToMakeResidentMap) const
|
||||||
|
{
|
||||||
for (const auto& resourceBindingData : resourceBindingDataSet)
|
for (const auto& resourceBindingData : resourceBindingDataSet)
|
||||||
{
|
{
|
||||||
ResourceType rescType = resourceBindingData.m_resourcPtr->GetResourceType();
|
ResourceType rescType = resourceBindingData.m_resourcPtr->GetResourceType();
|
||||||
|
MTLResourceUsage resourceUsage = MTLResourceUsageRead;
|
||||||
switch(rescType)
|
switch(rescType)
|
||||||
{
|
{
|
||||||
case ResourceType::MtlTextureType:
|
case ResourceType::MtlTextureType:
|
||||||
{
|
{
|
||||||
MTLResourceUsage resourceUsage = GetImageResourceUsage(resourceBindingData.m_imageAccess);
|
resourceUsage |= GetImageResourceUsage(resourceBindingData.m_imageAccess);
|
||||||
[static_cast<id<MTLRenderCommandEncoder>>(encoder) useResource:resourceBindingData.m_resourcPtr->GetGpuAddress<id<MTLTexture>>()
|
|
||||||
usage:resourceUsage
|
|
||||||
stages:mtlRenderStages];
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ResourceType::MtlBufferType:
|
case ResourceType::MtlBufferType:
|
||||||
{
|
{
|
||||||
MTLResourceUsage resourceUsage = GetBufferResourceUsage(resourceBindingData.m_bufferAccess);
|
resourceUsage |= GetBufferResourceUsage(resourceBindingData.m_bufferAccess);
|
||||||
[static_cast<id<MTLRenderCommandEncoder>>(encoder) useResource:resourceBindingData.m_resourcPtr->GetGpuAddress<id<MTLBuffer>>()
|
|
||||||
usage:resourceUsage
|
|
||||||
stages:mtlRenderStages];
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -502,8 +480,46 @@ namespace AZ
|
|||||||
AZ_Assert(false, "Undefined Resource type");
|
AZ_Assert(false, "Undefined Resource type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
uint16_t arrayIndex = resourcesToMakeResidentMap[resourceUsage].m_resourceArrayLen++;
|
||||||
|
id<MTLResource> mtlResourceToBind = resourceBindingData.m_resourcPtr->GetGpuAddress<id<MTLResource>>();
|
||||||
|
resourcesToMakeResidentMap[resourceUsage].m_resourceArray[arrayIndex] = mtlResourceToBind;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArgumentBuffer::CollectResourcesForGraphics(id<MTLCommandEncoder> 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();
|
||||||
|
switch(rescType)
|
||||||
|
{
|
||||||
|
case ResourceType::MtlTextureType:
|
||||||
|
{
|
||||||
|
resourceUsage |= GetImageResourceUsage(resourceBindingData.m_imageAccess);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ResourceType::MtlBufferType:
|
||||||
|
{
|
||||||
|
resourceUsage |= GetBufferResourceUsage(resourceBindingData.m_bufferAccess);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
AZ_Assert(false, "Undefined Resource type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AZStd::pair <MTLResourceUsage, MTLRenderStages> key = AZStd::make_pair(resourceUsage, mtlRenderStages);
|
||||||
|
uint16_t arrayIndex = resourcesToMakeResidentMap[key].m_resourceArrayLen++;
|
||||||
|
id<MTLResource> mtlResourceToBind = resourceBindingData.m_resourcPtr->GetGpuAddress<id<MTLResource>>();
|
||||||
|
resourcesToMakeResidentMap[key].m_resourceArray[arrayIndex] = mtlResourceToBind;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,8 +119,24 @@ namespace AZ
|
|||||||
using ResourceBindingsMap = AZStd::unordered_map<AZ::Name, ResourceBindingsSet>;
|
using ResourceBindingsMap = AZStd::unordered_map<AZ::Name, ResourceBindingsSet>;
|
||||||
ResourceBindingsMap m_resourceBindings;
|
ResourceBindingsMap m_resourceBindings;
|
||||||
|
|
||||||
void ApplyUseResourceToCompute(id<MTLCommandEncoder> encoder, const ResourceBindingsSet& resourceBindingData) const;
|
static const int MaxEntriesInArgTable = 31;
|
||||||
void ApplyUseResourceToGraphic(id<MTLCommandEncoder> encoder, RHI::ShaderStageMask visShaderMask, const ResourceBindingsSet& resourceBindingDataSet) const;
|
struct MetalResourceArray
|
||||||
|
{
|
||||||
|
AZStd::array<id <MTLResource>, MaxEntriesInArgTable> m_resourceArray;
|
||||||
|
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<MTLResourceUsage, MetalResourceArray>;
|
||||||
|
//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<AZStd::pair<MTLResourceUsage,MTLRenderStages>, MetalResourceArray>;
|
||||||
|
|
||||||
|
void CollectResourcesForCompute(id<MTLCommandEncoder> encoder,
|
||||||
|
const ResourceBindingsSet& resourceBindingData,
|
||||||
|
ComputeResourcesToMakeResidentMap& resourcesToMakeResidentMap) const;
|
||||||
|
void CollectResourcesForGraphics(id<MTLCommandEncoder> encoder,
|
||||||
|
RHI::ShaderStageMask visShaderMask,
|
||||||
|
const ResourceBindingsSet& resourceBindingDataSet,
|
||||||
|
GraphicsResourcesToMakeResidentMap& resourcesToMakeResidentMap) const;
|
||||||
//! Use visibility information to call UseResource on all resources for this Argument Buffer
|
//! Use visibility information to call UseResource on all resources for this Argument Buffer
|
||||||
void ApplyUseResource(id<MTLCommandEncoder> encoder,
|
void ApplyUseResource(id<MTLCommandEncoder> encoder,
|
||||||
const ResourceBindingsMap& resourceMap,
|
const ResourceBindingsMap& resourceMap,
|
||||||
@@ -144,8 +160,6 @@ namespace AZ
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
ShaderResourceGroupPool* m_srgPool = nullptr;
|
ShaderResourceGroupPool* m_srgPool = nullptr;
|
||||||
|
|
||||||
static const int MaxEntriesInArgTable = 31;
|
|
||||||
NSCache* m_samplerCache;
|
NSCache* m_samplerCache;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include <Atom/RHI.Reflect/Bits.h>
|
#include <Atom/RHI.Reflect/Bits.h>
|
||||||
#include <AzCore/Debug/EventTrace.h>
|
#include <AzCore/Debug/EventTrace.h>
|
||||||
|
#include <AzCore/std/algorithm.h>
|
||||||
#include <RHI/ArgumentBuffer.h>
|
#include <RHI/ArgumentBuffer.h>
|
||||||
#include <RHI/Buffer.h>
|
#include <RHI/Buffer.h>
|
||||||
#include <RHI/BufferMemoryView.h>
|
#include <RHI/BufferMemoryView.h>
|
||||||
@@ -249,66 +250,191 @@ namespace AZ
|
|||||||
ShaderResourceBindings& bindings = GetShaderResourceBindingsByPipelineType(stateType);
|
ShaderResourceBindings& bindings = GetShaderResourceBindingsByPipelineType(stateType);
|
||||||
const PipelineLayout& pipelineLayout = pipelineState->GetPipelineLayout();
|
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;
|
||||||
|
|
||||||
|
//Arrays to cache all the buffers and offsets in order to make batch calls
|
||||||
|
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];
|
const ShaderResourceGroup* shaderResourceGroup = bindings.m_srgsBySlot[slot];
|
||||||
uint32_t slotIndex = pipelineLayout.GetSlotByIndex(srgIndex);
|
uint32_t slotIndex = pipelineLayout.GetIndexBySlot(slot);
|
||||||
if(!shaderResourceGroup || slotIndex == RHI::Limits::Pipeline::ShaderResourceGroupCountMax)
|
if(!shaderResourceGroup || slotIndex == RHI::Limits::Pipeline::ShaderResourceGroupCountMax)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bindings.m_srgsByIndex[srgIndex] != shaderResourceGroup)
|
uint32_t srgVisIndex = pipelineLayout.GetIndexBySlot(shaderResourceGroup->GetBindingSlot());
|
||||||
|
const RHI::ShaderStageMask& srgVisInfo = pipelineLayout.GetSrgVisibility(srgVisIndex);
|
||||||
|
|
||||||
|
bool isSrgUpdatd = bindings.m_srgsByIndex[slot] != shaderResourceGroup;
|
||||||
|
if(isSrgUpdatd)
|
||||||
{
|
{
|
||||||
bindings.m_srgsByIndex[srgIndex] = shaderResourceGroup;
|
bindings.m_srgsByIndex[slot] = shaderResourceGroup;
|
||||||
auto& compiledArgBuffer = shaderResourceGroup->GetCompiledArgumentBuffer();
|
auto& compiledArgBuffer = shaderResourceGroup->GetCompiledArgumentBuffer();
|
||||||
|
|
||||||
id<MTLBuffer> argBuffer = compiledArgBuffer.GetArgEncoderBuffer();
|
id<MTLBuffer> argBuffer = compiledArgBuffer.GetArgEncoderBuffer();
|
||||||
size_t argBufferOffset = compiledArgBuffer.GetOffset();
|
size_t argBufferOffset = compiledArgBuffer.GetOffset();
|
||||||
|
|
||||||
uint32_t srgVisIndex = pipelineLayout.GetSlotByIndex(shaderResourceGroup->GetBindingSlot());
|
|
||||||
const RHI::ShaderStageMask& srgVisInfo = pipelineLayout.GetSrgVisibility(srgVisIndex);
|
|
||||||
|
|
||||||
if(srgVisInfo != RHI::ShaderStageMask::None)
|
if(srgVisInfo != RHI::ShaderStageMask::None)
|
||||||
{
|
{
|
||||||
const ShaderResourceGroupVisibility& srgResourcesVisInfo = pipelineLayout.GetSrgResourcesVisibility(srgVisIndex);
|
//For graphics and compute shader stages, cache all the argument buffers, offsets and track the min/max indices
|
||||||
|
|
||||||
//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)
|
if(m_commandEncoderType == CommandEncoderType::Render)
|
||||||
{
|
{
|
||||||
id<MTLRenderCommandEncoder> renderEncoder = GetEncoder<id<MTLRenderCommandEncoder>>();
|
id<MTLRenderCommandEncoder> renderEncoder = GetEncoder<id<MTLRenderCommandEncoder>>();
|
||||||
uint8_t numBitsSet = RHI::CountBitsSet(static_cast<uint64_t>(srgVisInfo));
|
uint8_t numBitsSet = RHI::CountBitsSet(static_cast<uint64_t>(srgVisInfo));
|
||||||
if( numBitsSet > 1 || srgVisInfo == RHI::ShaderStageMask::Vertex)
|
if( numBitsSet > 1 || srgVisInfo == RHI::ShaderStageMask::Vertex)
|
||||||
{
|
{
|
||||||
[renderEncoder setVertexBuffer:argBuffer
|
mtlVertexArgBuffers[slotIndex] = argBuffer;
|
||||||
offset:argBufferOffset
|
mtlVertexArgBufferOffsets[slotIndex] = argBufferOffset;
|
||||||
atIndex:slotIndex];
|
bufferVertexRegisterIdMin = AZStd::min(slotIndex, bufferVertexRegisterIdMin);
|
||||||
|
bufferVertexRegisterIdMax = AZStd::max(slotIndex, bufferVertexRegisterIdMax);
|
||||||
}
|
}
|
||||||
|
|
||||||
if( numBitsSet > 1 || srgVisInfo == RHI::ShaderStageMask::Fragment)
|
if( numBitsSet > 1 || srgVisInfo == RHI::ShaderStageMask::Fragment)
|
||||||
{
|
{
|
||||||
[renderEncoder setFragmentBuffer:argBuffer
|
mtlFragmentOrComputeArgBuffers[slotIndex] = argBuffer;
|
||||||
offset:argBufferOffset
|
mtlFragmentOrComputeArgBufferOffsets[slotIndex] = argBufferOffset;
|
||||||
atIndex:slotIndex];
|
bufferFragmentOrComputeRegisterIdMin = AZStd::min(slotIndex, bufferFragmentOrComputeRegisterIdMin);
|
||||||
|
bufferFragmentOrComputeRegisterIdMax = AZStd::max(slotIndex, bufferFragmentOrComputeRegisterIdMax);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else if(m_commandEncoderType == CommandEncoderType::Compute)
|
||||||
|
{
|
||||||
|
mtlFragmentOrComputeArgBuffers[slotIndex] = argBuffer;
|
||||||
|
mtlFragmentOrComputeArgBufferOffsets[slotIndex] = argBufferOffset;
|
||||||
|
bufferFragmentOrComputeRegisterIdMin = AZStd::min(slotIndex, bufferFragmentOrComputeRegisterIdMin);
|
||||||
|
bufferFragmentOrComputeRegisterIdMax = AZStd::max(slotIndex, bufferFragmentOrComputeRegisterIdMax);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//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[slot] != srgResourcesVisHash || isSrgUpdatd)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
//format compatible with the appropriate metal function.
|
||||||
|
if(m_commandEncoderType == CommandEncoderType::Render)
|
||||||
|
{
|
||||||
shaderResourceGroup->AddUntrackedResourcesToEncoder(m_encoder, srgResourcesVisInfo);
|
shaderResourceGroup->AddUntrackedResourcesToEncoder(m_encoder, srgResourcesVisInfo);
|
||||||
}
|
}
|
||||||
else if(m_commandEncoderType == CommandEncoderType::Compute)
|
else if(m_commandEncoderType == CommandEncoderType::Compute)
|
||||||
{
|
{
|
||||||
id<MTLComputeCommandEncoder> computeEncoder = GetEncoder<id<MTLComputeCommandEncoder>>();
|
|
||||||
[computeEncoder setBuffer:argBuffer
|
|
||||||
offset:argBufferOffset
|
|
||||||
atIndex:pipelineLayout.GetSlotByIndex(srgIndex)];
|
|
||||||
shaderResourceGroup->AddUntrackedResourcesToEncoder(m_encoder, srgResourcesVisInfo);
|
shaderResourceGroup->AddUntrackedResourcesToEncoder(m_encoder, srgResourcesVisInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//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;
|
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<MTLRenderCommandEncoder> renderEncoder = GetEncoder<id<MTLRenderCommandEncoder>>();
|
||||||
|
[renderEncoder setVertexBuffers:&mtlArgBuffers[startingIndex]
|
||||||
|
offsets:&mtlArgBufferOffsets[startingIndex]
|
||||||
|
withRange:range];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RHI::ShaderStage::Fragment:
|
||||||
|
{
|
||||||
|
id<MTLRenderCommandEncoder> renderEncoder = GetEncoder<id<MTLRenderCommandEncoder>>();
|
||||||
|
[renderEncoder setFragmentBuffers:&mtlArgBuffers[startingIndex]
|
||||||
|
offsets:&mtlArgBufferOffsets[startingIndex]
|
||||||
|
withRange:range];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RHI::ShaderStage::Compute:
|
||||||
|
{
|
||||||
|
id<MTLComputeCommandEncoder> computeEncoder = GetEncoder<id<MTLComputeCommandEncoder>>();
|
||||||
|
[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)
|
void CommandList::Submit(const RHI::DrawItem& drawItem)
|
||||||
{
|
{
|
||||||
@@ -447,6 +573,7 @@ namespace AZ
|
|||||||
for (size_t i = 0; i < bindings.m_srgsByIndex.size(); ++i)
|
for (size_t i = 0; i < bindings.m_srgsByIndex.size(); ++i)
|
||||||
{
|
{
|
||||||
bindings.m_srgsByIndex[i] = nullptr;
|
bindings.m_srgsByIndex[i] = nullptr;
|
||||||
|
bindings.m_srgVisHashByIndex[i] = AZ::HashValue64{0};
|
||||||
}
|
}
|
||||||
|
|
||||||
const PipelineLayout& pipelineLayout = pipelineState->GetPipelineLayout();
|
const PipelineLayout& pipelineLayout = pipelineState->GetPipelineLayout();
|
||||||
@@ -469,6 +596,10 @@ namespace AZ
|
|||||||
|
|
||||||
void CommandList::SetStreamBuffers(const RHI::StreamBufferView* streams, uint32_t count)
|
void CommandList::SetStreamBuffers(const RHI::StreamBufferView* streams, uint32_t count)
|
||||||
{
|
{
|
||||||
|
uint16_t bufferArrayLen = 0;
|
||||||
|
AZStd::array<id<MTLBuffer>, METAL_MAX_ENTRIES_BUFFER_ARG_TABLE> mtlStreamBuffers;
|
||||||
|
AZStd::array<NSUInteger, METAL_MAX_ENTRIES_BUFFER_ARG_TABLE> mtlStreamBufferOffsets;
|
||||||
|
|
||||||
AZ::HashValue64 streamsHash = AZ::HashValue64{0};
|
AZ::HashValue64 streamsHash = AZ::HashValue64{0};
|
||||||
for (uint32_t i = 0; i < count; ++i)
|
for (uint32_t i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
@@ -479,18 +610,25 @@ namespace AZ
|
|||||||
{
|
{
|
||||||
m_state.m_streamsHash = streamsHash;
|
m_state.m_streamsHash = streamsHash;
|
||||||
AZ_Assert(count <= METAL_MAX_ENTRIES_BUFFER_ARG_TABLE , "Slots needed cannot exceed METAL_MAX_ENTRIES_BUFFER_ARG_TABLE");
|
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};
|
||||||
|
//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())
|
if (streams[i].GetBuffer())
|
||||||
{
|
{
|
||||||
const Buffer * buff = static_cast<const Buffer*>(streams[i].GetBuffer());
|
const Buffer * buff = static_cast<const Buffer*>(streams[i].GetBuffer());
|
||||||
id<MTLBuffer> mtlBuff = buff->GetMemoryView().GetGpuAddress<id<MTLBuffer>>();
|
id<MTLBuffer> mtlBuff = buff->GetMemoryView().GetGpuAddress<id<MTLBuffer>>();
|
||||||
uint32_t VBIndex = (METAL_MAX_ENTRIES_BUFFER_ARG_TABLE - 1) - i;
|
|
||||||
uint32_t offset = streams[i].GetByteOffset() + buff->GetMemoryView().GetOffset();
|
uint32_t offset = streams[i].GetByteOffset() + buff->GetMemoryView().GetOffset();
|
||||||
id<MTLRenderCommandEncoder> renderEncoder = GetEncoder<id<MTLRenderCommandEncoder>>();
|
mtlStreamBuffers[bufferArrayLen] = mtlBuff;
|
||||||
[renderEncoder setVertexBuffer: mtlBuff offset: offset atIndex: VBIndex];
|
mtlStreamBufferOffsets[bufferArrayLen] = offset;
|
||||||
|
bufferArrayLen++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
id<MTLRenderCommandEncoder> renderEncoder = GetEncoder<id<MTLRenderCommandEncoder>>();
|
||||||
|
[renderEncoder setVertexBuffers: mtlStreamBuffers.data()
|
||||||
|
offsets: mtlStreamBufferOffsets.data()
|
||||||
|
withRange: range];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -99,8 +99,17 @@ namespace AZ
|
|||||||
{
|
{
|
||||||
AZStd::array<const ShaderResourceGroup*, RHI::Limits::Pipeline::ShaderResourceGroupCountMax> m_srgsByIndex;
|
AZStd::array<const ShaderResourceGroup*, RHI::Limits::Pipeline::ShaderResourceGroupCountMax> m_srgsByIndex;
|
||||||
AZStd::array<const ShaderResourceGroup*, RHI::Limits::Pipeline::ShaderResourceGroupCountMax> m_srgsBySlot;
|
AZStd::array<const ShaderResourceGroup*, RHI::Limits::Pipeline::ShaderResourceGroupCountMax> m_srgsBySlot;
|
||||||
|
AZStd::array<AZ::HashValue64, RHI::Limits::Pipeline::ShaderResourceGroupCountMax> m_srgVisHashByIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using MetalArgumentBufferArray = AZStd::array<id<MTLBuffer>, RHI::Limits::Pipeline::ShaderResourceGroupCountMax>;
|
||||||
|
using MetalArgumentBufferArrayOffsets = AZStd::array<NSUInteger, RHI::Limits::Pipeline::ShaderResourceGroupCountMax>;
|
||||||
|
void BindArgumentBuffers(RHI::ShaderStage shaderStage,
|
||||||
|
uint16_t registerIdMin,
|
||||||
|
uint16_t registerIdMax,
|
||||||
|
MetalArgumentBufferArray& mtlArgBuffers,
|
||||||
|
MetalArgumentBufferArrayOffsets mtlArgBufferOffsets);
|
||||||
|
|
||||||
ShaderResourceBindings& GetShaderResourceBindingsByPipelineType(RHI::PipelineStateType pipelineType);
|
ShaderResourceBindings& GetShaderResourceBindingsByPipelineType(RHI::PipelineStateType pipelineType);
|
||||||
|
|
||||||
//! This is kept as a separate struct so that we can robustly reset it. Every property
|
//! This is kept as a separate struct so that we can robustly reset it. Every property
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "Atom_RHI_Metal_precompiled.h"
|
#include "Atom_RHI_Metal_precompiled.h"
|
||||||
|
|
||||||
#include <Atom/RHI.Reflect/ImageDescriptor.h>
|
#include <Atom/RHI.Reflect/ImageDescriptor.h>
|
||||||
|
#include <Atom/RHI.Reflect/Bits.h>
|
||||||
#include <RHI/Conversions.h>
|
#include <RHI/Conversions.h>
|
||||||
#include <RHI/Conversions_Platform.h>
|
#include <RHI/Conversions_Platform.h>
|
||||||
#include <RHI/Image.h>
|
#include <RHI/Image.h>
|
||||||
@@ -456,8 +457,35 @@ namespace AZ
|
|||||||
|
|
||||||
MTLColorWriteMask ConvertColorWriteMask(AZ::u8 writeMask)
|
MTLColorWriteMask ConvertColorWriteMask(AZ::u8 writeMask)
|
||||||
{
|
{
|
||||||
//todo::Based on the mask set the correct writemask
|
MTLColorWriteMask colorMask = MTLColorWriteMaskNone;
|
||||||
return MTLColorWriteMaskAll;
|
if(writeMask == 0)
|
||||||
|
{
|
||||||
|
return colorMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(RHI::CheckBitsAll(writeMask, static_cast<uint8_t>(RHI::WriteChannelMask::ColorWriteMaskAll)))
|
||||||
|
{
|
||||||
|
return MTLColorWriteMaskAll;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RHI::CheckBitsAny(writeMask, static_cast<uint8_t>(RHI::WriteChannelMask::ColorWriteMaskRed)))
|
||||||
|
{
|
||||||
|
colorMask |= MTLColorWriteMaskRed;
|
||||||
|
}
|
||||||
|
if (RHI::CheckBitsAny(writeMask, static_cast<uint8_t>(RHI::WriteChannelMask::ColorWriteMaskGreen)))
|
||||||
|
{
|
||||||
|
colorMask |= MTLColorWriteMaskGreen;
|
||||||
|
}
|
||||||
|
if (RHI::CheckBitsAny(writeMask, static_cast<uint8_t>(RHI::WriteChannelMask::ColorWriteMaskBlue)))
|
||||||
|
{
|
||||||
|
colorMask |= MTLColorWriteMaskBlue;
|
||||||
|
}
|
||||||
|
if (RHI::CheckBitsAny(writeMask, static_cast<uint8_t>(RHI::WriteChannelMask::ColorWriteMaskAlpha)))
|
||||||
|
{
|
||||||
|
colorMask |= MTLColorWriteMaskAlpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
return colorMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
MTLVertexFormat ConvertVertexFormat(RHI::Format format)
|
MTLVertexFormat ConvertVertexFormat(RHI::Format format)
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ namespace AZ
|
|||||||
|
|
||||||
m_srgVisibilities.resize(RHI::Limits::Pipeline::ShaderResourceGroupCountMax);
|
m_srgVisibilities.resize(RHI::Limits::Pipeline::ShaderResourceGroupCountMax);
|
||||||
m_srgResourcesVisibility.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)
|
for (uint32_t srgLayoutIdx = 0; srgLayoutIdx < groupLayoutCount; ++srgLayoutIdx)
|
||||||
{
|
{
|
||||||
const RHI::ShaderResourceGroupLayout& srgLayout = *descriptor.GetShaderResourceGroupLayout(srgLayoutIdx);
|
const RHI::ShaderResourceGroupLayout& srgLayout = *descriptor.GetShaderResourceGroupLayout(srgLayoutIdx);
|
||||||
@@ -111,6 +112,7 @@ namespace AZ
|
|||||||
|
|
||||||
m_srgVisibilities[srgIndex] = mask;
|
m_srgVisibilities[srgIndex] = mask;
|
||||||
m_srgResourcesVisibility[srgIndex] = srgVis;
|
m_srgResourcesVisibility[srgIndex] = srgVis;
|
||||||
|
m_srgResourcesVisibilityHash[srgIndex] = srgVis.GetHash();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache the inline constant size and slot index
|
// Cache the inline constant size and slot index
|
||||||
@@ -123,12 +125,12 @@ namespace AZ
|
|||||||
|
|
||||||
size_t PipelineLayout::GetSlotByIndex(size_t index) const
|
size_t PipelineLayout::GetSlotByIndex(size_t index) const
|
||||||
{
|
{
|
||||||
return m_slotToIndexTable[index];
|
return m_indexToSlotTable[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t PipelineLayout::GetIndexBySlot(size_t slot) const
|
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
|
const RHI::ShaderStageMask& PipelineLayout::GetSrgVisibility(uint32_t index) const
|
||||||
@@ -141,6 +143,11 @@ namespace AZ
|
|||||||
return m_srgResourcesVisibility[index];
|
return m_srgResourcesVisibility[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AZ::HashValue64 PipelineLayout::GetSrgResourcesVisibilityHash(uint32_t index) const
|
||||||
|
{
|
||||||
|
return m_srgResourcesVisibilityHash[index];
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t PipelineLayout::GetRootConstantsSize() const
|
uint32_t PipelineLayout::GetRootConstantsSize() const
|
||||||
{
|
{
|
||||||
return m_rootConstantsSize;
|
return m_rootConstantsSize;
|
||||||
|
|||||||
@@ -57,6 +57,9 @@ namespace AZ
|
|||||||
/// Returns srgVisibility data
|
/// Returns srgVisibility data
|
||||||
const ShaderResourceGroupVisibility& GetSrgResourcesVisibility(uint32_t index) const;
|
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
|
/// Returns the root constant specific layout information
|
||||||
uint32_t GetRootConstantsSize() const;
|
uint32_t GetRootConstantsSize() const;
|
||||||
uint32_t GetRootConstantsSlotIndex() const;
|
uint32_t GetRootConstantsSlotIndex() const;
|
||||||
@@ -84,6 +87,9 @@ namespace AZ
|
|||||||
/// Cache Visibility across all the resources within the SRG
|
/// Cache Visibility across all the resources within the SRG
|
||||||
AZStd::fixed_vector<ShaderResourceGroupVisibility, RHI::Limits::Pipeline::ShaderResourceGroupCountMax> m_srgResourcesVisibility;
|
AZStd::fixed_vector<ShaderResourceGroupVisibility, RHI::Limits::Pipeline::ShaderResourceGroupCountMax> m_srgResourcesVisibility;
|
||||||
|
|
||||||
|
/// Cache Visibility hash across all the resources within the SRG
|
||||||
|
AZStd::fixed_vector<AZ::HashValue64, RHI::Limits::Pipeline::ShaderResourceGroupCountMax> m_srgResourcesVisibilityHash;
|
||||||
|
|
||||||
uint32_t m_rootConstantSlotIndex = (uint32_t)-1;
|
uint32_t m_rootConstantSlotIndex = (uint32_t)-1;
|
||||||
uint32_t m_rootConstantsSize = 0;
|
uint32_t m_rootConstantsSize = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -73,6 +73,10 @@ namespace AZ
|
|||||||
|
|
||||||
m_metalView.metalLayer.drawableSize = CGSizeMake(descriptor.m_dimensions.m_imageWidth, descriptor.m_dimensions.m_imageHeight);
|
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);
|
m_drawables.resize(descriptor.m_dimensions.m_imageCount);
|
||||||
|
|
||||||
@@ -83,6 +87,20 @@ namespace AZ
|
|||||||
return RHI::ResultCode::Success;
|
return RHI::ResultCode::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SwapChain::AddSubView()
|
||||||
|
{
|
||||||
|
NativeViewType* superView = reinterpret_cast<NativeViewType*>(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()
|
void SwapChain::ShutdownInternal()
|
||||||
{
|
{
|
||||||
if (m_viewController)
|
if (m_viewController)
|
||||||
@@ -161,16 +179,7 @@ namespace AZ
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NativeViewType* superView = reinterpret_cast<NativeViewType*>(m_nativeWindow);
|
AddSubView();
|
||||||
|
|
||||||
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];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return RHI::ResultCode::Success;
|
return RHI::ResultCode::Success;
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ namespace AZ
|
|||||||
RHI::ResultCode ResizeInternal(const RHI::SwapChainDimensions& dimensions, RHI::SwapChainDimensions* nativeDimensions) override;
|
RHI::ResultCode ResizeInternal(const RHI::SwapChainDimensions& dimensions, RHI::SwapChainDimensions* nativeDimensions) override;
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void AddSubView();
|
||||||
|
|
||||||
id <MTLCommandBuffer> m_mtlCommandBuffer;
|
id <MTLCommandBuffer> m_mtlCommandBuffer;
|
||||||
RHIMetalView* m_metalView = nullptr;
|
RHIMetalView* m_metalView = nullptr;
|
||||||
NativeViewControllerType* m_viewController = nullptr;
|
NativeViewControllerType* m_viewController = nullptr;
|
||||||
|
|||||||
@@ -334,19 +334,30 @@ namespace AZ
|
|||||||
VkColorComponentFlags ConvertComponentFlags(uint8_t sflags)
|
VkColorComponentFlags ConvertComponentFlags(uint8_t sflags)
|
||||||
{
|
{
|
||||||
VkColorComponentFlags dflags = 0;
|
VkColorComponentFlags dflags = 0;
|
||||||
if (RHI::CheckBitsAny(sflags, static_cast<uint8_t>(1)))
|
|
||||||
|
if(sflags == 0)
|
||||||
|
{
|
||||||
|
return dflags;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(RHI::CheckBitsAll(sflags, static_cast<uint8_t>(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, static_cast<uint8_t>(RHI::WriteChannelMask::ColorWriteMaskRed)))
|
||||||
{
|
{
|
||||||
dflags |= VK_COLOR_COMPONENT_R_BIT;
|
dflags |= VK_COLOR_COMPONENT_R_BIT;
|
||||||
}
|
}
|
||||||
if (RHI::CheckBitsAny(sflags, static_cast<uint8_t>(2)))
|
if (RHI::CheckBitsAny(sflags, static_cast<uint8_t>(RHI::WriteChannelMask::ColorWriteMaskGreen)))
|
||||||
{
|
{
|
||||||
dflags |= VK_COLOR_COMPONENT_G_BIT;
|
dflags |= VK_COLOR_COMPONENT_G_BIT;
|
||||||
}
|
}
|
||||||
if (RHI::CheckBitsAny(sflags, static_cast<uint8_t>(4)))
|
if (RHI::CheckBitsAny(sflags, static_cast<uint8_t>(RHI::WriteChannelMask::ColorWriteMaskBlue)))
|
||||||
{
|
{
|
||||||
dflags |= VK_COLOR_COMPONENT_B_BIT;
|
dflags |= VK_COLOR_COMPONENT_B_BIT;
|
||||||
}
|
}
|
||||||
if (RHI::CheckBitsAny(sflags, static_cast<uint8_t>(8)))
|
if (RHI::CheckBitsAny(sflags, static_cast<uint8_t>(RHI::WriteChannelMask::ColorWriteMaskAlpha)))
|
||||||
{
|
{
|
||||||
dflags |= VK_COLOR_COMPONENT_A_BIT;
|
dflags |= VK_COLOR_COMPONENT_A_BIT;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user