Merge branch 'development' into Atom/dmcdiar/ATOM-5702

This commit is contained in:
Doug McDiarmid
2021-06-18 17:12:52 -07:00
539 changed files with 30395 additions and 19441 deletions
@@ -46,6 +46,7 @@ namespace AWSCore
void InitializeAWSDocActions();
void InitializeAWSGlobalDocsSubMenu();
void InitializeAWSFeatureGemActions();
void AddSpaceForIcon(QMenu* menu);
// AWSCoreEditorRequestBus interface implementation
void SetAWSClientAuthEnabled() override;
@@ -35,6 +35,9 @@
namespace AWSCore
{
static constexpr int IconSize = 16;
AWSCoreEditorMenu::AWSCoreEditorMenu(const QString& text)
: QMenu(text)
, m_resourceMappingToolWatcher(nullptr)
@@ -43,6 +46,7 @@ namespace AWSCore
InitializeResourceMappingToolAction();
this->addSeparator();
InitializeAWSFeatureGemActions();
AddSpaceForIcon(this);
AWSCoreEditorRequestBus::Handler::BusConnect();
}
@@ -136,6 +140,8 @@ namespace AWSCore
globalDocsMenu->addAction(AddExternalLinkAction(AWSAndScriptCanvasActionText, AWSAndScriptCanvasUrl, ":/Notifications/link.svg"));
globalDocsMenu->addAction(AddExternalLinkAction(AWSAndComponentsActionText, AWSAndComponentsUrl, ":/Notifications/link.svg"));
globalDocsMenu->addAction(AddExternalLinkAction(CallAWSResourcesActionText, CallAWSResourcesUrl, ":/Notifications/link.svg"));
AddSpaceForIcon(globalDocsMenu);
}
void AWSCoreEditorMenu::InitializeAWSFeatureGemActions()
@@ -170,6 +176,8 @@ namespace AWSCore
AWSClientAuthPlatformSpecificActionText, AWSClientAuthPlatformSpecificUrl, ":/Notifications/link.svg"));
subMenu->addAction(AddExternalLinkAction(
AWSClientAuthAPIReferenceActionText, AWSClientAuthAPIReferenceUrl, ":/Notifications/link.svg"));
AddSpaceForIcon(subMenu);
}
void AWSCoreEditorMenu::SetAWSMetricsEnabled()
@@ -197,7 +205,9 @@ namespace AWSCore
[configFilePath](){
QDesktopServices::openUrl(QUrl::fromLocalFile(configFilePath.c_str()));
});
subMenu->addAction(settingsAction);
AddSpaceForIcon(subMenu);
}
QMenu* AWSCoreEditorMenu::SetAWSFeatureSubMenu(const AZStd::string& menuText)
@@ -209,6 +219,7 @@ namespace AWSCore
{
QMenu* subMenu = new QMenu(QObject::tr(menuText.c_str()));
subMenu->setIcon(QIcon(QString(":/Notifications/checkmark.svg")));
subMenu->setProperty("noHover", true);
this->insertMenu(*itr, subMenu);
this->removeAction(*itr);
return subMenu;
@@ -216,4 +227,11 @@ namespace AWSCore
}
return nullptr;
}
void AWSCoreEditorMenu::AddSpaceForIcon(QMenu *menu)
{
QSize size = menu->sizeHint();
size.setWidth(size.width() + IconSize);
menu->setFixedSize(size);
}
} // namespace AWSCore
@@ -122,29 +122,22 @@ namespace AWSMetrics
//! @return Outcome of the operation.
AZ::Outcome<void, AZStd::string> SendMetricsToFile(AZStd::shared_ptr<MetricsQueue> metricsQueue);
//! Check whether the consumer should flush the metrics queue.
//! @return whether the limit is hit.
bool ShouldSendMetrics();
//! Push metrics events to the front of the queue for retry.
//! @param metricsEventsForRetry Metrics events for retry.
void PushMetricsForRetry(MetricsQueue& metricsEventsForRetry);
void SubmitLocalMetricsAsync();
////////////////////////////////////////////
// These data are protected by m_metricsMutex.
AZStd::mutex m_metricsMutex;
AZStd::chrono::system_clock::time_point m_lastSendMetricsTime;
MetricsQueue m_metricsQueue;
////////////////////////////////////////////
AZStd::mutex m_metricsMutex; //!< Mutex to protect the metrics queue
MetricsQueue m_metricsQueue; //!< Queue fo buffering the metrics events
AZStd::mutex m_metricsFileMutex; //!< Local metrics file is protected by m_metricsFileMutex
AZStd::mutex m_metricsFileMutex; //!< Mutex to protect the local metrics file
AZStd::atomic<int> m_sendMetricsId;//!< Request ID for sending metrics
AZStd::thread m_consumerThread; //!< Thread to monitor and consume the metrics queue
AZStd::atomic<bool> m_consumerTerminated;
AZStd::thread m_monitorThread; //!< Thread to monitor and consume the metrics queue
AZStd::atomic<bool> m_monitorTerminated;
AZStd::binary_semaphore m_waitEvent;
// Client Configurations.
AZStd::unique_ptr<ClientConfiguration> m_clientConfiguration;
+28 -37
View File
@@ -29,7 +29,7 @@ namespace AWSMetrics
MetricsManager::MetricsManager()
: m_clientConfiguration(AZStd::make_unique<ClientConfiguration>())
, m_clientIdProvider(IdentityProvider::CreateIdentityProvider())
, m_consumerTerminated(true)
, m_monitorTerminated(true)
, m_sendMetricsId(0)
{
}
@@ -53,31 +53,27 @@ namespace AWSMetrics
void MetricsManager::StartMetrics()
{
if (!m_consumerTerminated)
if (!m_monitorTerminated)
{
// The background thread has been started.
return;
}
m_consumerTerminated = false;
AZStd::lock_guard<AZStd::mutex> lock(m_metricsMutex);
m_lastSendMetricsTime = AZStd::chrono::system_clock::now();
m_monitorTerminated = false;
// Start a separate thread to monitor and consume the metrics queue.
// Avoid using the job system since the worker is long-running over multiple frames
m_consumerThread = AZStd::thread(AZStd::bind(&MetricsManager::MonitorMetricsQueue, this));
m_monitorThread = AZStd::thread(AZStd::bind(&MetricsManager::MonitorMetricsQueue, this));
}
void MetricsManager::MonitorMetricsQueue()
{
while (!m_consumerTerminated)
// Continue to loop until the monitor is terminated.
while (!m_monitorTerminated)
{
if (ShouldSendMetrics())
{
// Flush the metrics queue when the accumulated metrics size or time period hits the limit
FlushMetricsAsync();
}
// The thread will wake up either when the metrics event queue is full (try_acquire_for call returns true),
// or the flush period limit is hit (try_acquire_for call returns false).
m_waitEvent.try_acquire_for(AZStd::chrono::seconds(m_clientConfiguration->GetQueueFlushPeriodInSeconds()));
FlushMetricsAsync();
}
}
@@ -114,6 +110,12 @@ namespace AWSMetrics
AZStd::lock_guard<AZStd::mutex> lock(m_metricsMutex);
m_metricsQueue.AddMetrics(metricsEvent);
if (m_metricsQueue.GetSizeInBytes() >= m_clientConfiguration->GetMaxQueueSizeInBytes())
{
// Flush the metrics queue when the accumulated metrics size hits the limit
m_waitEvent.release();
}
return true;
}
@@ -348,9 +350,6 @@ namespace AWSMetrics
void MetricsManager::FlushMetricsAsync()
{
AZStd::lock_guard<AZStd::mutex> lock(m_metricsMutex);
m_lastSendMetricsTime = AZStd::chrono::system_clock::now();
if (m_metricsQueue.GetNumMetrics() == 0)
{
return;
@@ -363,34 +362,20 @@ namespace AWSMetrics
SendMetricsAsync(metricsToFlush);
}
bool MetricsManager::ShouldSendMetrics()
{
AZStd::lock_guard<AZStd::mutex> lock(m_metricsMutex);
auto secondsSinceLastFlush = AZStd::chrono::duration_cast<AZStd::chrono::seconds>(AZStd::chrono::system_clock::now() - m_lastSendMetricsTime);
if (secondsSinceLastFlush >= AZStd::chrono::seconds(m_clientConfiguration->GetQueueFlushPeriodInSeconds()) ||
m_metricsQueue.GetSizeInBytes() >= m_clientConfiguration->GetMaxQueueSizeInBytes())
{
return true;
}
return false;
}
void MetricsManager::ShutdownMetrics()
{
if (m_consumerTerminated)
if (m_monitorTerminated)
{
return;
}
// Terminate the consumer thread
m_consumerTerminated = true;
FlushMetricsAsync();
// Terminate the monitor thread
m_monitorTerminated = true;
m_waitEvent.release();
if (m_consumerThread.joinable())
if (m_monitorThread.joinable())
{
m_consumerThread.join();
m_monitorThread.join();
}
}
@@ -449,6 +434,12 @@ namespace AWSMetrics
{
AZStd::lock_guard<AZStd::mutex> lock(m_metricsMutex);
m_metricsQueue.AddMetrics(offlineRecords[index]);
if (m_metricsQueue.GetSizeInBytes() >= m_clientConfiguration->GetMaxQueueSizeInBytes())
{
// Flush the metrics queue when the accumulated metrics size hits the limit
m_waitEvent.release();
}
}
// Remove the local metrics file after reading all its content.
@@ -355,6 +355,9 @@ namespace AWSMetrics
TEST_F(MetricsManagerTest, FlushMetrics_NonEmptyQueue_Success)
{
ResetClientConfig(true, (double)TestMetricsEventSizeInBytes * (MaxNumMetricsEvents + 1) / MbToBytes,
DefaultFlushPeriodInSeconds, 1);
for (int index = 0; index < MaxNumMetricsEvents; ++index)
{
AZStd::vector<MetricsAttribute> metricsAttributes;
@@ -377,7 +380,7 @@ namespace AWSMetrics
TEST_F(MetricsManagerTest, ResetOfflineRecordingStatus_ResubmitLocalMetrics_Success)
{
// Disable offline recording in the config file.
ResetClientConfig(false, 0.0, 0, 0);
ResetClientConfig(false, (double)TestMetricsEventSizeInBytes * 2 / MbToBytes, 0, 0);
// Enable offline recording after initialize the metric manager.
m_metricsManager->UpdateOfflineRecordingStatus(true);
@@ -63,7 +63,7 @@ namespace ImageProcessingAtom
void ImageThumbnail::LoadThread()
{
AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::QueueEvent(
AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::Event(
AZ::RPI::StreamingImageAsset::RTTI_Type(), &AzToolsFramework::Thumbnailer::ThumbnailerRendererRequests::RenderThumbnail,
m_key,
ImageThumbnailSize);
@@ -8,7 +8,7 @@
"$type": "DX12::PlatformLimitsDescriptor",
"m_descriptorHeapLimits": {
"DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV": [16384, 262144],
"DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV": [1000000, 1000000],
"DESCRIPTOR_HEAP_TYPE_SAMPLER": [2048, 2048],
"DESCRIPTOR_HEAP_TYPE_RTV": [2048, 0],
"DESCRIPTOR_HEAP_TYPE_DSV": [2048, 0]
@@ -322,7 +322,14 @@
"Pass": "AuxGeomPass",
"Attachment": "ColorInputOutput"
}
}
},
{
"LocalSlot": "DepthInputOutput",
"AttachmentRef": {
"Pass": "DepthPrePass",
"Attachment": "Depth"
}
}
]
},
{
@@ -427,6 +427,13 @@
"Pass": "DebugOverlayPass",
"Attachment": "InputOutput"
}
},
{
"LocalSlot": "DepthInputOutput",
"AttachmentRef": {
"Pass": "DepthPrePass",
"Attachment": "Depth"
}
}
]
},
@@ -24,9 +24,9 @@
},
"ImageDescriptor": {
"Format": "R16G16B16A16_FLOAT",
"MipLevels": "8",
"SharedQueueMask": "Graphics"
}
},
"GenerateFullMipChain": true
}
],
"Connections": [
@@ -5,7 +5,7 @@
"ClassData": {
"PassTemplate": {
"Name": "ReflectionScreenSpaceCompositePassTemplate",
"PassClass": "FullScreenTriangle",
"PassClass": "ReflectionScreenSpaceCompositePass",
"Slots": [
{
"Name": "TraceInput",
@@ -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",
@@ -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": {
@@ -0,0 +1,62 @@
#!/usr/bin/env python
"""
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 genericpath import isdir
from argparse import ArgumentParser
import json
from pathlib import Path
import os
# this allows us to add additional data if necessary, e.g. frame_test_timestamps.json
is_timestamp_file = lambda file: file.name.startswith('frame') and file.name.endswith('_timestamps.json')
ns_to_ms = lambda time: time / 1e6
def main(logs_dir):
count = 0
total = 0
maximum = 0
print(f'Analyzing frame timestamp logs in {logs_dir}')
# go through files in alphabetical order (remove sorted() if not necessary)
for file in sorted(logs_dir.iterdir(), key=lambda file: len(file.name)):
if file.is_dir() or not is_timestamp_file(file):
continue
data = json.loads(file.read_text())
entries = data['ClassData']['timestampEntries']
timestamps = [entry['timestampResultInNanoseconds'] for entry in entries]
frame_time = sum(timestamps)
frame_name = file.name.split('_')[0]
print(f'- Total time for frame {frame_name}: {ns_to_ms(frame_time)}ms')
maximum = max(maximum, frame_time)
total += frame_time
count += 1
if count < 1:
print(f'No logs were found in {base_dir}')
exit(1)
print(f'Avg. time across {count} frames: {ns_to_ms(total / count)}ms')
print(f'Max frame time: {ns_to_ms(maximum)}ms')
if __name__ == '__main__':
parser = ArgumentParser(description='Gathers statistics from a group of pass timestamp logs')
parser.add_argument('path', help='Path to the directory containing the pass timestamp logs')
args = parser.parse_args()
base_dir = Path(args.path)
if not base_dir.exists():
raise FileNotFoundError('Invalid path provided')
main(base_dir)
@@ -10,7 +10,5 @@
"type": "Compute"
}
]
},
"DisabledRHIBackends": ["metal"]
}
}
@@ -16,7 +16,10 @@
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
@@ -37,7 +37,7 @@ ShaderResourceGroup PassSrg : SRG_PerPass
Texture2D<float4> m_sceneLuminance;
// This should be of size NUM_HISTOGRAM_BINS.
Buffer<uint> m_histogram;
StructuredBuffer<uint> m_histogram;
Sampler LinearSampler
{
@@ -20,7 +20,11 @@
ShaderResourceGroup PassSrg : SRG_PerPass
{
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];
@@ -12,7 +12,5 @@
"type": "Compute"
}
]
},
"DisabledRHIBackends": ["metal"]
}
}
@@ -37,6 +37,9 @@ ShaderResourceGroup PassSrg : SRG_PerPass
AddressV = Clamp;
AddressW = Clamp;
};
// the max roughness mip level for sampling the previous frame image
uint m_maxMipLevel;
}
#include <Atom/RPI/ShaderResourceGroups/DefaultDrawSrg.azsli>
@@ -69,10 +72,6 @@ PSOutput MainPS(VSOutput IN, in uint sampleIndex : SV_SampleIndex)
float4 positionWS = mul(ViewSrg::m_viewProjectionInverseMatrix, projectedPos);
positionWS /= positionWS.w;
//float4 positionVS = mul(ViewSrg::m_projectionMatrixInverse, projectedPos);
//positionVS /= positionVS.w;
//float4 positionWS = mul(ViewSrg::m_viewMatrixInverse, positionVS);
// compute ray from camera to surface position
float3 cameraToPositionWS = normalize(positionWS.xyz - ViewSrg::m_worldPosition);
@@ -103,8 +102,7 @@ PSOutput MainPS(VSOutput IN, in uint sampleIndex : SV_SampleIndex)
// compute the roughness mip to use in the previous frame image
// remap the roughness mip into a lower range to more closely match the material roughness values
const float MaxRoughness = 0.5f;
const float MaxRoughnessMip = 7;
float mip = saturate(roughness / MaxRoughness) * MaxRoughnessMip;
float mip = saturate(roughness / MaxRoughness) * PassSrg::m_maxMipLevel;
// sample reflection value from the roughness mip
float4 reflectionColor = float4(PassSrg::m_previousFrame.SampleLevel(PassSrg::LinearSampler, tracePrevUV, mip).rgb, 1.0f);
@@ -16,7 +16,7 @@
ShaderResourceGroup PassSrg : SRG_PerPass
{
RWBuffer<float> m_skinnedMeshOutputStream;
RWStructuredBuffer<float> m_skinnedMeshOutputStream;
}
ShaderResourceGroup InstanceSrg : SRG_PerDraw
@@ -23,7 +23,9 @@ namespace AZ
{
Low,
Medium,
High
High,
Count
};
//! This class provides general features and configuration for the diffuse global illumination environment,
@@ -95,6 +95,8 @@ namespace AZ
TransformServiceFeatureProcessorInterface::ObjectId m_objectId;
Aabb m_aabb = Aabb::CreateNull();
bool m_cullBoundsNeedsUpdate = false;
bool m_cullableNeedsRebuild = false;
bool m_objectSrgNeedsUpdate = true;
@@ -160,6 +162,9 @@ namespace AZ
Transform GetTransform(const MeshHandle& meshHandle) override;
Vector3 GetNonUniformScale(const MeshHandle& meshHandle) override;
void SetLocalAabb(const MeshHandle& meshHandle, const AZ::Aabb& localAabb) override;
AZ::Aabb GetLocalAabb(const MeshHandle& meshHandle) const override;
void SetSortKey(const MeshHandle& meshHandle, RHI::DrawItemSortKey sortKey) override;
RHI::DrawItemSortKey GetSortKey(const MeshHandle& meshHandle) override;
@@ -86,6 +86,10 @@ namespace AZ
virtual Transform GetTransform(const MeshHandle& meshHandle) = 0;
//! Gets the non-uniform scale for a given mesh handle.
virtual Vector3 GetNonUniformScale(const MeshHandle& meshHandle) = 0;
//! Sets the local space bbox for a given mesh handle. You don't need to call this for static models, only skinned/animated models
virtual void SetLocalAabb(const MeshHandle& meshHandle, const AZ::Aabb& localAabb) = 0;
//! Gets the local space bbox for a given mesh handle. Unless SetLocalAabb has been called before, this will be the bbox of the model asset
virtual AZ::Aabb GetLocalAabb(const MeshHandle& meshHandle) const = 0;
//! Sets the sort key for a given mesh handle.
virtual void SetSortKey(const MeshHandle& meshHandle, RHI::DrawItemSortKey sortKey) = 0;
//! Gets the sort key for a given mesh handle.
@@ -33,6 +33,8 @@ namespace UnitTest
MOCK_METHOD2(SetMaterialAssignmentMap, void(const MeshHandle&, const AZ::Render::MaterialAssignmentMap&));
MOCK_METHOD1(GetTransform, AZ::Transform(const MeshHandle&));
MOCK_METHOD1(GetNonUniformScale, AZ::Vector3(const MeshHandle&));
MOCK_METHOD2(SetLocalAabb, void(const MeshHandle&, const AZ::Aabb&));
MOCK_CONST_METHOD1(GetLocalAabb, AZ::Aabb(const MeshHandle&));
MOCK_METHOD2(SetSortKey, void (const MeshHandle&, AZ::RHI::DrawItemSortKey));
MOCK_METHOD1(GetSortKey, AZ::RHI::DrawItemSortKey(const MeshHandle&));
MOCK_METHOD2(SetLodOverride, void(const MeshHandle&, AZ::RPI::Cullable::LodOverride));
@@ -103,6 +103,7 @@
#include <DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.h>
#include <ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.h>
#include <ReflectionScreenSpace/ReflectionScreenSpaceBlurChildPass.h>
#include <ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.h>
#include <ReflectionScreenSpace/ReflectionCopyFrameBufferPass.h>
#include <OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.h>
@@ -283,6 +284,7 @@ namespace AZ
// Add Reflection passes
passSystem->AddPassCreator(Name("ReflectionScreenSpaceBlurPass"), &Render::ReflectionScreenSpaceBlurPass::Create);
passSystem->AddPassCreator(Name("ReflectionScreenSpaceBlurChildPass"), &Render::ReflectionScreenSpaceBlurChildPass::Create);
passSystem->AddPassCreator(Name("ReflectionScreenSpaceCompositePass"), &Render::ReflectionScreenSpaceCompositePass::Create);
passSystem->AddPassCreator(Name("ReflectionCopyFrameBufferPass"), &Render::ReflectionCopyFrameBufferPass::Create);
// Add RayTracing pas
@@ -20,6 +20,8 @@
#include <Atom/RPI.Public/AuxGeom/AuxGeomDraw.h>
#include <Atom/RPI.Public/ColorManagement/TransformColor.h>
#include <Atom/RPI.Public/Pass/PassSystemInterface.h>
#include <Atom/RPI.Public/Pass/PassFilter.h>
#include <Atom/RPI.Public/Pass/Specific/EnvironmentCubeMapPass.h>
#include <Atom/RPI.Public/RenderPipeline.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom/RPI.Public/View.h>
@@ -1070,7 +1072,18 @@ namespace AZ
segment.m_pipelineViewTag = viewTag;
if (!segment.m_view || segment.m_view->GetName() != viewName)
{
segment.m_view = RPI::View::CreateView(viewName, RPI::View::UsageShadow);
RPI::View::UsageFlags usageFlags = RPI::View::UsageShadow;
// if the shadow is rendering in an EnvironmentCubeMapPass it also needs to be a ReflectiveCubeMap view,
// to filter out shadows from objects that are excluded from the cubemap
RPI::PassClassFilter<RPI::EnvironmentCubeMapPass> passFilter;
AZStd::vector<AZ::RPI::Pass*> cubeMapPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passFilter);
if (!cubeMapPasses.empty())
{
usageFlags |= RPI::View::UsageReflectiveCubeMap;
}
segment.m_view = RPI::View::CreateView(viewName, usageFlags);
}
}
}
@@ -43,6 +43,12 @@ namespace AZ
void DiffuseGlobalIlluminationFeatureProcessor::SetQualityLevel(DiffuseGlobalIlluminationQualityLevel qualityLevel)
{
if (qualityLevel >= DiffuseGlobalIlluminationQualityLevel::Count)
{
AZ_Assert(false, "SetQualityLevel called with invalid quality level [%d]", qualityLevel);
return;
}
m_qualityLevel = qualityLevel;
UpdatePasses();
@@ -50,6 +50,8 @@ namespace AZ
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->Class<OutputDeviceTransformType>("OutputDeviceTransformType");
behaviorContext->Class<AcesParameterOverrides>("AcesParameterOverrides")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Category, "render")
@@ -58,6 +60,16 @@ namespace AZ
->Method("LoadPreset", &AcesParameterOverrides::LoadPreset)
->Property("overrideDefaults", BehaviorValueProperty(&AcesParameterOverrides::m_overrideDefaults))
->Property("preset", BehaviorValueProperty(&AcesParameterOverrides::m_preset))
->Enum<aznumeric_cast<int>(OutputDeviceTransformType::NumOutputDeviceTransformTypes)>(
"OutputDeviceTransformType_NumOutputDeviceTransformTypes")
->Enum<aznumeric_cast<int>(OutputDeviceTransformType::OutputDeviceTransformType_48Nits)>(
"OutputDeviceTransformType_48Nits")
->Enum<aznumeric_cast<int>(OutputDeviceTransformType::OutputDeviceTransformType_1000Nits)>(
"OutputDeviceTransformType_1000Nits")
->Enum<aznumeric_cast<int>(OutputDeviceTransformType::OutputDeviceTransformType_2000Nits)>(
"OutputDeviceTransformType_2000Nits")
->Enum<aznumeric_cast<int>(OutputDeviceTransformType::OutputDeviceTransformType_4000Nits)>(
"OutputDeviceTransformType_4000Nits")
->Property("alterSurround", BehaviorValueProperty(&AcesParameterOverrides::m_alterSurround))
->Property("applyDesaturation", BehaviorValueProperty(&AcesParameterOverrides::m_applyDesaturation))
->Property("applyCATD60toD65", BehaviorValueProperty(&AcesParameterOverrides::m_applyCATD60toD65))
@@ -304,6 +304,30 @@ namespace AZ
}
}
void MeshFeatureProcessor::SetLocalAabb(const MeshHandle& meshHandle, const AZ::Aabb& localAabb)
{
if (meshHandle.IsValid())
{
MeshDataInstance& meshData = *meshHandle;
meshData.m_aabb = localAabb;
meshData.m_cullBoundsNeedsUpdate = true;
meshData.m_objectSrgNeedsUpdate = true;
}
};
AZ::Aabb MeshFeatureProcessor::GetLocalAabb(const MeshHandle& meshHandle) const
{
if (meshHandle.IsValid())
{
return meshHandle->m_aabb;
}
else
{
AZ_Assert(false, "Invalid mesh handle");
return Aabb::CreateNull();
}
}
Transform MeshFeatureProcessor::GetTransform(const MeshHandle& meshHandle)
{
if (meshHandle.IsValid())
@@ -603,6 +627,8 @@ namespace AZ
SetRayTracingData();
}
m_aabb = model->GetModelAsset()->GetAabb();
m_cullableNeedsRebuild = true;
m_cullBoundsNeedsUpdate = true;
m_objectSrgNeedsUpdate = true;
@@ -996,7 +1022,7 @@ namespace AZ
RPI::Cullable::CullData& cullData = m_cullable.m_cullData;
RPI::Cullable::LodData& lodData = m_cullable.m_lodData;
const Aabb& localAabb = m_model->GetAabb();
const Aabb& localAabb = m_aabb;
lodData.m_lodSelectionRadius = 0.5f*localAabb.GetExtents().GetMaxElement();
const size_t modelLodCount = m_model->GetLodCount();
@@ -1077,7 +1103,7 @@ namespace AZ
Vector3 center;
float radius;
Aabb localAabb = m_model->GetAabb();
Aabb localAabb = m_aabb;
localAabb.MultiplyByScale(nonUniformScale);
localAabb.GetTransformedAabb(localToWorld).GetAsSphere(center, radius);
@@ -67,7 +67,7 @@ namespace AZ
desc.m_bufferName = "LuminanceHistogramBuffer";
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");
}
@@ -37,6 +37,9 @@ namespace AZ
//! to store the previous frame image
Data::Instance<RPI::AttachmentImage>& GetFrameBufferImageAttachment() { return m_frameBufferImageAttachment; }
//! Returns the number of mip levels in the blur
uint32_t GetNumBlurMips() const { return m_numBlurMips; }
private:
explicit ReflectionScreenSpaceBlurPass(const RPI::PassDescriptor& descriptor);
@@ -0,0 +1,58 @@
/*
* 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 "ReflectionScreenSpaceCompositePass.h"
#include "ReflectionScreenSpaceBlurPass.h"
#include <Atom/RPI.Public/Pass/PassSystemInterface.h>
#include <Atom/RPI.Public/Pass/PassFilter.h>
namespace AZ
{
namespace Render
{
RPI::Ptr<ReflectionScreenSpaceCompositePass> ReflectionScreenSpaceCompositePass::Create(const RPI::PassDescriptor& descriptor)
{
RPI::Ptr<ReflectionScreenSpaceCompositePass> pass = aznew ReflectionScreenSpaceCompositePass(descriptor);
return AZStd::move(pass);
}
ReflectionScreenSpaceCompositePass::ReflectionScreenSpaceCompositePass(const RPI::PassDescriptor& descriptor)
: RPI::FullscreenTrianglePass(descriptor)
{
}
void ReflectionScreenSpaceCompositePass::CompileResources([[maybe_unused]] const RHI::FrameGraphCompileContext& context)
{
if (!m_shaderResourceGroup)
{
return;
}
RPI::PassHierarchyFilter passFilter(AZ::Name("ReflectionScreenSpaceBlurPass"));
const AZStd::vector<RPI::Pass*>& passes = RPI::PassSystemInterface::Get()->FindPasses(passFilter);
if (!passes.empty())
{
Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast<ReflectionScreenSpaceBlurPass*>(passes.front());
// compute the max mip level based on the available mips in the previous frame image, and capping it
// to stay within a range that has reasonable data
const uint32_t MaxNumRoughnessMips = 8;
uint32_t maxMipLevel = AZStd::min(MaxNumRoughnessMips, blurPass->GetNumBlurMips()) - 1;
auto constantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_maxMipLevel"));
m_shaderResourceGroup->SetConstant(constantIndex, maxMipLevel);
}
FullscreenTrianglePass::CompileResources(context);
}
} // namespace RPI
} // namespace AZ
@@ -0,0 +1,43 @@
/*
* 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 <Atom/RPI.Public/Pass/Pass.h>
#include <Atom/RPI.Public/Pass/FullscreenTrianglePass.h>
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
#include <Atom/RPI.Public/Shader/Shader.h>
namespace AZ
{
namespace Render
{
//! This pass composites the screenspace reflection trace onto the reflection buffer.
class ReflectionScreenSpaceCompositePass
: public RPI::FullscreenTrianglePass
{
AZ_RPI_PASS(ReflectionScreenSpaceCompositePass);
public:
AZ_RTTI(Render::ReflectionScreenSpaceCompositePass, "{88739CC9-C3F1-413A-A527-9916C697D93A}", FullscreenTrianglePass);
AZ_CLASS_ALLOCATOR(Render::ReflectionScreenSpaceCompositePass, SystemAllocator, 0);
//! Creates a new pass without a PassTemplate
static RPI::Ptr<ReflectionScreenSpaceCompositePass> Create(const RPI::PassDescriptor& descriptor);
private:
explicit ReflectionScreenSpaceCompositePass(const RPI::PassDescriptor& descriptor);
// Pass Overrides...
void CompileResources(const RHI::FrameGraphCompileContext& context) override;
};
} // namespace RPI
} // namespace AZ
@@ -629,6 +629,11 @@ namespace AZ
Data::Asset<RPI::ModelLodAsset> lodAsset;
modelLodCreator.End(lodAsset);
if (!lodAsset.IsReady())
{
// [GFX TODO] During mesh reload the modelLodCreator could report errors and result in the lodAsset not ready.
return nullptr;
}
modelCreator.AddLodAsset(AZStd::move(lodAsset));
lodIndex++;
@@ -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<uint32_t>(m_sizeInBytes) / viewDescriptor.m_elementSize;
viewDescriptor.m_elementOffset = 0;
creator.SetBufferViewDescriptor(viewDescriptor);
@@ -267,6 +267,8 @@ set(FILES
Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.h
Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurChildPass.cpp
Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurChildPass.h
Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp
Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.h
Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.cpp
Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.h
Source/ScreenSpace/DeferredFogSettings.cpp
@@ -160,6 +160,16 @@ namespace AZ
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
{
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.
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;
@@ -271,6 +271,12 @@ namespace AZ
ShaderResourceBindings& bindings = GetShaderResourceBindingsByPipelineType(pipelineType);
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;
// The pipeline state gets set first.
if (updatePipelineState)
@@ -10,6 +10,7 @@
*
*/
#include "RHI/Atom_RHI_DX12_precompiled.h"
#include <Atom/RHI.Reflect/Bits.h>
#include <RHI/Conversions.h>
#include <RHI/Buffer.h>
#include <RHI/Image.h>
@@ -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,38 @@ namespace AZ
};
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)
{
@@ -164,5 +164,7 @@ namespace AZ
uint32_t shaderRegisterSpace,
D3D12_SHADER_VISIBILITY shaderVisibility,
D3D12_STATIC_SAMPLER_DESC& staticSamplerDesc);
uint8_t ConvertColorWriteMask(uint8_t writeMask);
}
}
@@ -94,7 +94,7 @@ namespace Platform
void ResizeInternal(RHIMetalView* metalView, CGSize viewSize)
{
[metalView resizeSubviewsWithOldSize:viewSize];
[metalView.metalLayer setDrawableSize: viewSize];
}
RHIMetalView* GetMetalView(NativeWindowType* nativeWindow)
@@ -386,35 +386,33 @@ namespace AZ
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)
{
uint8_t numBitsSet = RHI::CountBitsSet(static_cast<uint64_t>(srgResourcesVisInfo.m_constantDataStageMask));
if( numBitsSet > 0)
{
id<MTLResource> mtlconstantBufferResource = m_constantBuffer.GetGpuAddress<id<MTLResource>>();
if(RHI::CheckBitsAny(srgResourcesVisInfo.m_constantDataStageMask, RHI::ShaderStageMask::Compute))
{
[static_cast<id<MTLComputeCommandEncoder>>(commandEncoder) useResource:m_constantBuffer.GetGpuAddress<id<MTLBuffer>>() usage:MTLResourceUsageRead];
resourcesToMakeResidentCompute[MTLResourceUsageRead].emplace(mtlconstantBufferResource);
}
else
{
MTLRenderStages mtlRenderStages = GetRenderStages(srgResourcesVisInfo.m_constantDataStageMask);
[static_cast<id<MTLRenderCommandEncoder>>(commandEncoder) useResource:m_constantBuffer.GetGpuAddress<id<MTLBuffer>>()
usage:MTLResourceUsageRead
stages:mtlRenderStages];
AZStd::pair <MTLResourceUsage,MTLRenderStages> key = AZStd::make_pair(MTLResourceUsageRead, mtlRenderStages);
resourcesToMakeResidentGraphics[key].emplace(mtlconstantBufferResource);
}
}
}
ApplyUseResource(commandEncoder, m_resourceBindings, srgResourcesVisInfo);
}
void ArgumentBuffer::ApplyUseResource(id<MTLCommandEncoder> 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,75 +424,55 @@ 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;
CollectResourcesForCompute(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;
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);
}
}
}
}
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)
{
AZStd::vector<id <MTLResource>> resourcesToProcessVec(key.second.begin(), key.second.end());
[static_cast<id<MTLComputeCommandEncoder>>(commandEncoder) useResources: &resourcesToProcessVec[0]
count: resourcesToProcessVec.size()
usage: key.first];
}
//Call UseResource on all resources for Vertex and Fragment stages
for (const auto& key : resourcesToMakeResidentGraphics)
{
AZStd::vector<id <MTLResource>> resourcesToProcessVec(key.second.begin(), key.second.end());
[static_cast<id<MTLRenderCommandEncoder>>(commandEncoder) useResources: &resourcesToProcessVec[0]
count: resourcesToProcessVec.size()
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)
{
ResourceType rescType = resourceBindingData.m_resourcPtr->GetResourceType();
MTLResourceUsage resourceUsage = MTLResourceUsageRead;
switch(rescType)
{
case ResourceType::MtlTextureType:
{
MTLResourceUsage resourceUsage = GetImageResourceUsage(resourceBindingData.m_imageAccess);
[static_cast<id<MTLRenderCommandEncoder>>(encoder) useResource:resourceBindingData.m_resourcPtr->GetGpuAddress<id<MTLTexture>>()
usage:resourceUsage
stages:mtlRenderStages];
resourceUsage |= GetImageResourceUsage(resourceBindingData.m_imageAccess);
break;
}
case ResourceType::MtlBufferType:
{
MTLResourceUsage resourceUsage = GetBufferResourceUsage(resourceBindingData.m_bufferAccess);
[static_cast<id<MTLRenderCommandEncoder>>(encoder) useResource:resourceBindingData.m_resourcPtr->GetGpuAddress<id<MTLBuffer>>()
usage:resourceUsage
stages:mtlRenderStages];
resourceUsage |= GetBufferResourceUsage(resourceBindingData.m_bufferAccess);
break;
}
default:
@@ -502,8 +480,45 @@ namespace AZ
AZ_Assert(false, "Undefined Resource type");
}
}
id<MTLResource> mtlResourceToBind = resourceBindingData.m_resourcPtr->GetGpuAddress<id<MTLResource>>();
resourcesToMakeResidentMap[resourceUsage].emplace(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);
id<MTLResource> mtlResourceToBind = resourceBindingData.m_resourcPtr->GetGpuAddress<id<MTLResource>>();
resourcesToMakeResidentMap[key].emplace(mtlResourceToBind);
}
}
}
}
@@ -119,8 +119,19 @@ namespace AZ
using ResourceBindingsMap = AZStd::unordered_map<AZ::Name, ResourceBindingsSet>;
ResourceBindingsMap m_resourceBindings;
void ApplyUseResourceToCompute(id<MTLCommandEncoder> encoder, const ResourceBindingsSet& resourceBindingData) const;
void ApplyUseResourceToGraphic(id<MTLCommandEncoder> encoder, RHI::ShaderStageMask visShaderMask, const ResourceBindingsSet& resourceBindingDataSet) const;
static const int MaxEntriesInArgTable = 31;
//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, AZStd::unordered_set<id <MTLResource>>>;
//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>, AZStd::unordered_set<id <MTLResource>>>;
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
void ApplyUseResource(id<MTLCommandEncoder> encoder,
const ResourceBindingsMap& resourceMap,
@@ -144,8 +155,6 @@ namespace AZ
#endif
ShaderResourceGroupPool* m_srgPool = nullptr;
static const int MaxEntriesInArgTable = 31;
NSCache* m_samplerCache;
};
}
@@ -85,16 +85,36 @@ namespace AZ
uint64_t AsyncUploadQueue::QueueUpload(const RHI::BufferStreamRequest& uploadRequest)
{
uint64_t queueValue = m_uploadFence.Increment();
Buffer& destBuffer = static_cast<Buffer&>(*uploadRequest.m_buffer);
const MemoryView& destMemoryView = destBuffer.GetMemoryView();
MTLStorageMode mtlStorageMode = destBuffer.GetMemoryView().GetStorageMode();
RHI::BufferPool& bufferPool = static_cast<RHI::BufferPool&>(*destBuffer.GetPool());
// No need to use staging buffers since it's host memory.
// We just map, copy and then unmap.
if(mtlStorageMode == MTLStorageModeShared || mtlStorageMode == GetCPUGPUMemoryMode())
{
RHI::BufferMapRequest mapRequest;
mapRequest.m_buffer = uploadRequest.m_buffer;
mapRequest.m_byteCount = uploadRequest.m_byteCount;
mapRequest.m_byteOffset = uploadRequest.m_byteOffset;
RHI::BufferMapResponse mapResponse;
bufferPool.MapBuffer(mapRequest, mapResponse);
::memcpy(mapResponse.m_data, uploadRequest.m_sourceData, uploadRequest.m_byteCount);
bufferPool.UnmapBuffer(*uploadRequest.m_buffer);
if (uploadRequest.m_fenceToSignal)
{
uploadRequest.m_fenceToSignal->SignalOnCpu();
}
return m_uploadFence.GetPendingValue();
}
const MemoryView& memoryView = static_cast<Buffer&>(*uploadRequest.m_buffer).GetMemoryView();
RHI::Ptr<Memory> buffer = memoryView.GetMemory();
Fence* fenceToSignal = nullptr;
uint64_t fenceToSignalValue = 0;
size_t byteCount = uploadRequest.m_byteCount;
size_t byteOffset = memoryView.GetOffset() + uploadRequest.m_byteOffset;
size_t byteOffset = destMemoryView.GetOffset() + uploadRequest.m_byteOffset;
uint64_t queueValue = m_uploadFence.Increment();
const uint8_t* sourceData = reinterpret_cast<const uint8_t*>(uploadRequest.m_sourceData);
if (uploadRequest.m_fenceToSignal)
@@ -125,11 +145,11 @@ namespace AZ
}
id<MTLBlitCommandEncoder> blitEncoder = [framePacket->m_mtlCommandBuffer blitCommandEncoder];
[blitEncoder copyFromBuffer:framePacket->m_stagingResource
sourceOffset:0
toBuffer:buffer->GetGpuAddress<id<MTLBuffer>>()
destinationOffset:byteOffset + pendingByteOffset
size:bytesToCopy];
[blitEncoder copyFromBuffer: framePacket->m_stagingResource
sourceOffset: 0
toBuffer: destMemoryView.GetGpuAddress<id<MTLBuffer>>()
destinationOffset: byteOffset + pendingByteOffset
size: bytesToCopy];
[blitEncoder endEncoding];
blitEncoder = nil;
@@ -40,9 +40,8 @@ namespace AZ
buffer->m_pendingResolves++;
uploadRequest.m_attachmentBuffer = buffer;
uploadRequest.m_byteOffset = request.m_byteOffset;
uploadRequest.m_byteOffset = buffer->GetMemoryView().GetOffset() + request.m_byteOffset;
uploadRequest.m_stagingBuffer = stagingBuffer;
uploadRequest.m_byteSize = request.m_byteCount;
return stagingBuffer->GetMemoryView().GetCpuAddress();
}
@@ -64,12 +63,15 @@ namespace AZ
AZ_Assert(stagingBuffer, "Staging Buffer is null.");
AZ_Assert(destBuffer, "Attachment Buffer is null.");
//Inform the GPU that the CPU has modified the staging buffer.
Platform::SynchronizeBufferOnCPU(stagingBuffer->GetMemoryView().GetGpuAddress<id<MTLBuffer>>(), stagingBuffer->GetMemoryView().GetOffset(), stagingBuffer->GetMemoryView().GetSize());
RHI::CopyBufferDescriptor copyDescriptor;
copyDescriptor.m_sourceBuffer = stagingBuffer;
copyDescriptor.m_sourceOffset = 0;
copyDescriptor.m_sourceOffset = stagingBuffer->GetMemoryView().GetOffset();
copyDescriptor.m_destinationBuffer = destBuffer;
copyDescriptor.m_destinationOffset = static_cast<uint32_t>(packet.m_byteOffset);
copyDescriptor.m_size = static_cast<uint32_t>(packet.m_byteSize);
copyDescriptor.m_size = stagingBuffer->GetMemoryView().GetSize();
commandList.Submit(RHI::CopyItem(copyDescriptor));
device.QueueForRelease(stagingBuffer->GetMemoryView());
@@ -54,7 +54,6 @@ namespace AZ
Buffer* m_attachmentBuffer = nullptr;
RHI::Ptr<Buffer> m_stagingBuffer;
size_t m_byteOffset = 0;
size_t m_byteSize = 0;
};
AZStd::mutex m_uploadPacketsLock;
@@ -13,6 +13,7 @@
#include <Atom/RHI.Reflect/Bits.h>
#include <AzCore/Debug/EventTrace.h>
#include <AzCore/std/algorithm.h>
#include <RHI/ArgumentBuffer.h>
#include <RHI/Buffer.h>
#include <RHI/BufferMemoryView.h>
@@ -249,66 +250,191 @@ 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;
//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];
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;
}
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();
id<MTLBuffer> 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 shader stages, cache all the argument buffers, offsets and track the min/max indices
if(m_commandEncoderType == CommandEncoderType::Render)
{
id<MTLRenderCommandEncoder> renderEncoder = GetEncoder<id<MTLRenderCommandEncoder>>();
uint8_t numBitsSet = RHI::CountBitsSet(static_cast<uint64_t>(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)
{
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);
}
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);
}
}
}
}
//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<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)
{
@@ -447,6 +573,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 +596,10 @@ namespace AZ
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};
for (uint32_t i = 0; i < count; ++i)
{
@@ -479,18 +610,25 @@ 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};
//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<const Buffer*>(streams[i].GetBuffer());
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();
id<MTLRenderCommandEncoder> renderEncoder = GetEncoder<id<MTLRenderCommandEncoder>>();
[renderEncoder setVertexBuffer: mtlBuff offset: offset atIndex: VBIndex];
mtlStreamBuffers[bufferArrayLen] = mtlBuff;
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_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);
//! 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.Reflect/ImageDescriptor.h>
#include <Atom/RHI.Reflect/Bits.h>
#include <RHI/Conversions.h>
#include <RHI/Conversions_Platform.h>
#include <RHI/Image.h>
@@ -456,8 +457,35 @@ namespace AZ
MTLColorWriteMask ConvertColorWriteMask(AZ::u8 writeMask)
{
//todo::Based on the mask set the correct writemask
return MTLColorWriteMaskAll;
MTLColorWriteMask colorMask = MTLColorWriteMaskNone;
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)
@@ -44,7 +44,7 @@ namespace AZ
if (memoryView.IsValid())
{
heapMemoryUsage.m_residentInBytes += m_descriptor.m_pageSizeInBytes;
memoryView.SetName("BufferPage");
memoryView.SetName(AZStd::string::format("BufferPage_%s", AZ::Uuid::CreateRandom().ToString<AZStd::string>().c_str()));
}
else
{
@@ -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
@@ -123,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
@@ -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;
@@ -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<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_rootConstantsSize = 0;
};
@@ -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<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()
{
if (m_viewController)
@@ -161,16 +179,7 @@ namespace AZ
}
else
{
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];
AddSubView();
}
}
return RHI::ResultCode::Success;
@@ -49,6 +49,8 @@ namespace AZ
RHI::ResultCode ResizeInternal(const RHI::SwapChainDimensions& dimensions, RHI::SwapChainDimensions* nativeDimensions) override;
//////////////////////////////////////////////////////////////////////////
void AddSubView();
id <MTLCommandBuffer> m_mtlCommandBuffer;
RHIMetalView* m_metalView = nullptr;
NativeViewControllerType* m_viewController = nullptr;
@@ -334,19 +334,30 @@ namespace AZ
VkColorComponentFlags ConvertComponentFlags(uint8_t sflags)
{
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;
}
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;
}
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;
}
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;
}
@@ -55,7 +55,11 @@ namespace AZ
const auto& image = static_cast<const Image&>(resourceBase);
const RHI::ImageViewDescriptor& descriptor = GetDescriptor();
AZ_Assert(image.GetNativeImage() != VK_NULL_HANDLE, "Image has not been initialized.");
// this can happen when image has been invalidated/released right before re-compiling the image
if (image.GetNativeImage() == VK_NULL_HANDLE)
{
return RHI::ResultCode::Fail;
}
RHI::Format viewFormat = descriptor.m_overrideFormat;
// If an image is not owner of native image, it is a swapchain image.
@@ -12691,8 +12691,7 @@ static int glad_vk_find_extensions_vulkan( VkPhysicalDevice physical_device) {
#endif
GLAD_VK_KHR_push_descriptor = glad_vk_has_extension("VK_KHR_push_descriptor", extension_count, extensions);
GLAD_VK_KHR_ray_tracing = (glad_vk_has_extension("VK_KHR_acceleration_structure", extension_count, extensions)
&& glad_vk_has_extension("VK_KHR_ray_tracing_pipeline", extension_count, extensions)
&& glad_vk_has_extension("VK_KHR_ray_query", extension_count, extensions));
&& glad_vk_has_extension("VK_KHR_ray_tracing_pipeline", extension_count, extensions));
GLAD_VK_KHR_relaxed_block_layout = glad_vk_has_extension("VK_KHR_relaxed_block_layout", extension_count, extensions);
GLAD_VK_KHR_sampler_mirror_clamp_to_edge = glad_vk_has_extension("VK_KHR_sampler_mirror_clamp_to_edge", extension_count, extensions);
GLAD_VK_KHR_sampler_ycbcr_conversion = glad_vk_has_extension("VK_KHR_sampler_ycbcr_conversion", extension_count, extensions);
@@ -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<HashValue64, const RHI::PipelineState*> m_cachedRhiPipelineStates;
@@ -32,6 +32,7 @@ namespace AZ
: public Data::InstanceData
{
friend class ModelSystem;
public:
AZ_INSTANCE_DATA(Model, "{C30F5522-B381-4B38-BBAF-6E0B1885C8B9}");
AZ_CLASS_ALLOCATOR(Model, AZ::SystemAllocator, 0);
@@ -53,8 +54,6 @@ namespace AZ
//! Returns whether a buffer upload is pending.
bool IsUploadPending() const;
const AZ::Aabb& GetAabb() const;
const Data::Asset<ModelAsset>& GetModelAsset() const;
//! Checks a ray for intersection against this model. The ray must be in the same coordinate space as the model.
@@ -105,8 +104,6 @@ namespace AZ
// Tracks whether buffers have all been streamed up to the GPU.
bool m_isUploadPending = false;
AZ::Aabb m_aabb;
};
} // namespace RPI
} // namespace AZ
@@ -265,6 +265,12 @@ namespace AZ
// Update all bindings on this pass that are connected to bindings on other passes
void UpdateConnectedBindings();
// Update input and input/output bindings on this pass that are connected to bindings on other passes
void UpdateConnectedInputBindings();
// Update output bindings on this pass that are connected to bindings on other passes
void UpdateConnectedOutputBindings();
protected:
explicit Pass(const PassDescriptor& descriptor);
@@ -57,6 +57,20 @@ namespace AZ
}
#endif
}
//! Prints a generic message at the appropriate indent level.
template<typename ... Args>
static void Printf([[maybe_unused]] const char* format, [[maybe_unused]] Args... args)
{
#ifdef AZ_ENABLE_SHADER_RELOAD_DEBUG_TRACKER
if (IsEnabled())
{
const AZStd::string message = AZStd::string::format(format, args...);
AZ_TracePrintf("ShaderReloadDebug", "%*s %s \n", s_indent, "", message.c_str());
}
#endif
}
//! Use this utility to call BeginSection(), and automatically call EndSection() when the object goes out of scope.
class ScopedSection final
@@ -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);
}
@@ -97,6 +97,7 @@ namespace AZ
ShaderReloadNotificationBus::MultiHandler::BusDisconnect();
for (auto& shaderItem : m_shaderCollection)
{
ShaderReloadDebugTracker::Printf("(Material has ShaderAsset %p)", shaderItem.GetShaderAsset().Get());
ShaderReloadNotificationBus::MultiHandler::BusConnect(shaderItem.GetShaderAsset().GetId());
}
@@ -226,7 +227,7 @@ namespace AZ
// AssetBus overrides...
void Material::OnAssetReloaded(Data::Asset<Data::AssetData> asset)
{
ShaderReloadDebugTracker::ScopedSection reloadSection("Material::OnAssetReloaded %s", asset.GetHint().c_str());
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->Material::OnAssetReloaded %s", this, asset.GetHint().c_str());
Data::Asset<MaterialAsset> newMaterialAsset = { asset.GetAs<MaterialAsset>(), AZ::Data::AssetLoadBehavior::PreLoad };
@@ -241,7 +242,7 @@ namespace AZ
// MaterialReloadNotificationBus overrides...
void Material::OnMaterialAssetReinitialized(const Data::Asset<MaterialAsset>& materialAsset)
{
ShaderReloadDebugTracker::ScopedSection reloadSection("Material::OnMaterialAssetReinitialized %s", materialAsset.GetHint().c_str());
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->Material::OnMaterialAssetReinitialized %s", this, materialAsset.GetHint().c_str());
OnAssetReloaded(materialAsset);
}
@@ -249,7 +250,7 @@ namespace AZ
// ShaderReloadNotificationBus overrides...
void Material::OnShaderReinitialized([[maybe_unused]] const Shader& shader)
{
ShaderReloadDebugTracker::ScopedSection reloadSection("Material::OnShaderReinitialized %s", shader.GetAsset().GetHint().c_str());
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->Material::OnShaderReinitialized %s", this, shader.GetAsset().GetHint().c_str());
// Note that it might not be strictly necessary to reinitialize the entire material, we might be able to get away with
// just bumping the m_currentChangeId or some other minor updates. But it's pretty hard to know what exactly needs to be
// updated to correctly handle the reload, so it's safer to just reinitialize the whole material.
@@ -260,7 +261,7 @@ namespace AZ
{
// TODO: I think we should make Shader handle OnShaderAssetReinitialized and treat it just like the shader reloaded.
ShaderReloadDebugTracker::ScopedSection reloadSection("Material::OnShaderAssetReinitialized %s", shaderAsset.GetHint().c_str());
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->Material::OnShaderAssetReinitialized %s", this, shaderAsset.GetHint().c_str());
// Note that it might not be strictly necessary to reinitialize the entire material, we might be able to get away with
// just bumping the m_currentChangeId or some other minor updates. But it's pretty hard to know what exactly needs to be
// updated to correctly handle the reload, so it's safer to just reinitialize the whole material.
@@ -269,7 +270,7 @@ namespace AZ
void Material::OnShaderVariantReinitialized(const Shader& shader, const ShaderVariantId& /*shaderVariantId*/, ShaderVariantStableId shaderVariantStableId)
{
ShaderReloadDebugTracker::ScopedSection reloadSection("Material::OnShaderVariantReinitialized %s variant %u", shader.GetAsset().GetHint().c_str(), shaderVariantStableId.GetIndex());
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->Material::OnShaderVariantReinitialized %s variant %u", this, shader.GetAsset().GetHint().c_str(), shaderVariantStableId.GetIndex());
// Note that it would be better to check the shaderVariantId to see if that variant is relevant to this particular material before reinitializing it.
// There could be hundreds or even thousands of variants for a shader, but only one of those variants will be used by any given material. So we could
@@ -62,8 +62,6 @@ namespace AZ
{
AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender);
m_aabb = modelAsset.GetAabb();
m_lods.resize(modelAsset.GetLodAssets().size());
for (size_t lodIndex = 0; lodIndex < m_lods.size(); ++lodIndex)
@@ -127,11 +125,6 @@ namespace AZ
return m_isUploadPending;
}
const AZ::Aabb& Model::GetAabb() const
{
return m_aabb;
}
const Data::Asset<ModelAsset>& Model::GetModelAsset() const
{
return m_modelAsset;
@@ -140,9 +133,16 @@ namespace AZ
bool Model::LocalRayIntersection(const AZ::Vector3& rayStart, const AZ::Vector3& rayDir, float& distanceNormalized, AZ::Vector3& normal) const
{
AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender);
if (!GetModelAsset())
{
AZ_Assert(false, "Invalid Model - not created from a ModelAsset?");
return false;
}
float start;
float end;
const int result = Intersect::IntersectRayAABB2(rayStart, rayDir.GetReciprocal(), m_aabb, start, end);
const int result = Intersect::IntersectRayAABB2(rayStart, rayDir.GetReciprocal(), GetModelAsset()->GetAabb(), start, end);
if (Intersect::ISECT_RAY_AABB_NONE != result)
{
if (ModelAsset* modelAssetPtr = m_modelAsset.Get())
@@ -49,7 +49,7 @@ namespace AZ
With that percentage we can determine which Lod we want to use.
*/
Aabb modelAabb = model.GetAabb();
Aabb modelAabb = model.GetModelAsset()->GetAabb();
modelAabb.Translate(position);
Vector3 center;
@@ -1036,6 +1036,26 @@ namespace AZ
}
}
void Pass::UpdateConnectedInputBindings()
{
for (uint8_t idx : m_inputBindingIndices)
{
UpdateConnectedBinding(m_attachmentBindings[idx]);
}
for (uint8_t idx : m_inputOutputBindingIndices)
{
UpdateConnectedBinding(m_attachmentBindings[idx]);
}
}
void Pass::UpdateConnectedOutputBindings()
{
for (uint8_t idx : m_outputBindingIndices)
{
UpdateConnectedBinding(m_attachmentBindings[idx]);
}
}
// --- Queuing functions with PassSystem ---
void Pass::QueueForBuildAndInitialization()
@@ -1264,7 +1284,7 @@ namespace AZ
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();
UpdateConnectedInputBindings();
UpdateOwnedAttachments();
CreateTransientAttachments(params.m_frameGraphBuilder->GetAttachmentDatabase());
@@ -1273,6 +1293,8 @@ namespace AZ
// FrameBeginInternal needs to be the last function be called in FrameBegin because its implementation expects
// all the attachments are imported to database (for example, ImageAttachmentPreview)
FrameBeginInternal(params);
UpdateConnectedOutputBindings();
}
void Pass::FrameEnd()
@@ -159,7 +159,7 @@ namespace AZ
// AssetBus overrides
void Shader::OnAssetReloaded(Data::Asset<Data::AssetData> asset)
{
ShaderReloadDebugTracker::ScopedSection reloadSection("Shader::OnAssetReloaded %s", asset.GetHint().c_str());
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->Shader::OnAssetReloaded %s", this, asset.GetHint().c_str());
if (asset->GetId() == m_asset->GetId())
{
@@ -139,7 +139,7 @@ namespace AZ
void MaterialAsset::OnAssetReloaded(Data::Asset<Data::AssetData> asset)
{
ShaderReloadDebugTracker::ScopedSection reloadSection("MaterialAsset::OnAssetReloaded %s", asset.GetHint().c_str());
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->MaterialAsset::OnAssetReloaded %s", this, asset.GetHint().c_str());
Data::Asset<MaterialTypeAsset> newMaterialTypeAsset = { asset.GetAs<MaterialTypeAsset>(), AZ::Data::AssetLoadBehavior::PreLoad };
@@ -189,7 +189,7 @@ namespace AZ
void MaterialTypeAsset::OnAssetReloaded(Data::Asset<Data::AssetData> asset)
{
ShaderReloadDebugTracker::ScopedSection reloadSection("MaterialTypeAsset::OnAssetReloaded %s", asset.GetHint().c_str());
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->MaterialTypeAsset::OnAssetReloaded %s", this, asset.GetHint().c_str());
// The order of asset reloads is non-deterministic. If the MaterialTypeAsset reloads before these
// dependency assets, this will make sure the MaterialTypeAsset gets the latest ones when they reload.
@@ -581,7 +581,7 @@ namespace AZ
// AssetBus overrides...
void ShaderAsset::OnAssetReloaded(Data::Asset<Data::AssetData> asset)
{
ShaderReloadDebugTracker::ScopedSection reloadSection("ShaderAsset::OnAssetReloaded %s", asset.GetHint().c_str());
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->ShaderAsset::OnAssetReloaded %s", this, asset.GetHint().c_str());
Data::Asset<ShaderVariantAsset> shaderVariantAsset = { asset.GetAs<ShaderVariantAsset>(), AZ::Data::AssetLoadBehavior::PreLoad };
AZ_Assert(shaderVariantAsset->GetStableId() == RootShaderVariantStableId,
@@ -597,7 +597,7 @@ namespace AZ
/// ShaderVariantFinderNotificationBus overrides
void ShaderAsset::OnShaderVariantTreeAssetReady(Data::Asset<ShaderVariantTreeAsset> shaderVariantTreeAsset, bool isError)
{
ShaderReloadDebugTracker::ScopedSection reloadSection("ShaderAsset::OnShaderVariantTreeAssetReady %s", shaderVariantTreeAsset.GetHint().c_str());
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->ShaderAsset::OnShaderVariantTreeAssetReady %s", this, shaderVariantTreeAsset.GetHint().c_str());
AZStd::unique_lock<decltype(m_variantTreeMutex)> lock(m_variantTreeMutex);
if (isError)
@@ -14,13 +14,14 @@
},
"clearCoat": {
"enable": true,
"normalMap": "EngineAssets/Textures/perlinNoiseNormal_ddn.tif"
"normalMap": "EngineAssets/Textures/perlinNoiseNormal_ddn.tif",
"normalStrength": 0.10000000149011612
},
"general": {
"applySpecularAA": true
},
"metallic": {
"factor": 0.5
"factor": 0.10000000149011612
},
"normal": {
"factor": 0.05000000074505806,
@@ -31,6 +32,9 @@
},
"roughness": {
"factor": 0.0
},
"specularF0": {
"enableMultiScatterCompensation": true
}
}
}
}
+1 -1
View File
@@ -8,7 +8,7 @@
"Gem"
],
"user_tags": [
"AtomConent"
"AtomContent"
],
"icon_path": "preview.png"
}
@@ -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"
}
@@ -960,7 +960,7 @@
<Class name="AZ::u64" field="id" value="4294967295" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
</Class>
<Class name="float" field="ShadowFarClipDistance" value="100.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
<Class name="Render::ShadowmapSize" field="ShadowmapSize" value="2048" type="{3EC1CE83-483D-41FD-9909-D22B03E56F4E}"/>
<Class name="Render::ShadowmapSize" field="ShadowmapSize" value="1024" type="{3EC1CE83-483D-41FD-9909-D22B03E56F4E}"/>
<Class name="unsigned int" field="CascadeCount" value="4" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="bool" field="SplitAutomatic" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="float" field="SplitRatio" value="0.9000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
@@ -968,10 +968,11 @@
<Class name="float" field="GroundHeight" value="0.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
<Class name="bool" field="IsCascadeCorrectionEnabled" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="bool" field="IsDebugColoringEnabled" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
<Class name="unsigned int" field="ShadowFilterMethod" value="3" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="ShadowFilterMethod" value="1" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="float" field="SofteningBoundaryWidth" value="0.0300000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
<Class name="unsigned short" field="PcfPredictionSampleCount" value="4" type="{ECA0B403-C4F8-4B86-95FC-81688D046E40}"/>
<Class name="unsigned short" field="PcfFilteringSampleCount" value="32" type="{ECA0B403-C4F8-4B86-95FC-81688D046E40}"/>
<Class name="unsigned short" field="Pcf Method" value="1" type="{ECA0B403-C4F8-4B86-95FC-81688D046E40}"/>
</Class>
</Class>
</Class>
@@ -1109,4 +1110,3 @@
<Class name="bool" field="IsRuntimeActive" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
</Class>
</ObjectStream>
@@ -118,8 +118,7 @@ namespace AZ
void EditorAttachmentComponent::Activate()
{
Base::Activate();
m_boneFollower.Activate(GetEntity(), CreateAttachmentConfiguration(),
false); // Entity's don't animate in Editor
m_boneFollower.Activate(GetEntity(), CreateAttachmentConfiguration(), /*targetCanAnimate=*/true);
}
void EditorAttachmentComponent::Deactivate()
@@ -112,13 +112,13 @@ namespace AZ
->DataElement(Edit::UIHandlers::Default, &AreaLightComponentConfig::m_enableShutters, "Enable shutters", "Restrict the light to a specific beam angle depending on shape.")
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::ShuttersMustBeEnabled)
->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_innerShutterAngleDegrees, "Inner angle", "The inner angle of the shutters where the light beam begins to be occluded.")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 180.0f)
->Attribute(Edit::Attributes::Min, 0.5f)
->Attribute(Edit::Attributes::Max, 90.0f)
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShutters)
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShuttersDisabled)
->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_outerShutterAngleDegrees, "Outer angle", "The outer angle of the shutters where the light beam is completely occluded.")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 180.0f)
->Attribute(Edit::Attributes::Min, 0.5f)
->Attribute(Edit::Attributes::Max, 90.0f)
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShutters)
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShuttersDisabled)
@@ -29,7 +29,7 @@ namespace AZ
static void Reflect(ReflectContext* context);
DiffuseGlobalIlluminationQualityLevel m_qualityLevel;
DiffuseGlobalIlluminationQualityLevel m_qualityLevel = DiffuseGlobalIlluminationQualityLevel::Low;
};
}
}
@@ -36,7 +36,7 @@ namespace AZ
->Attribute(Edit::Attributes::Category, "Atom")
->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/Component_Placeholder.svg")
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.png")
->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZStd::vector<AZ::Crc32>({ AZ_CRC("Level", 0x9aeacc13), AZ_CRC("Game", 0x232b318c) }))
->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZStd::vector<AZ::Crc32>({ AZ_CRC("Level", 0x9aeacc13) }))
->Attribute(Edit::Attributes::AutoExpand, true)
->Attribute(Edit::Attributes::HelpPageURL, "https://")
;
@@ -460,10 +460,10 @@ namespace AZ
Aabb MeshComponentController::GetLocalBounds()
{
const Data::Instance<RPI::Model> model = GetModel();
if (model)
if (m_meshHandle.IsValid() && m_meshFeatureProcessor)
{
Aabb aabb = model->GetAabb();
Aabb aabb = m_meshFeatureProcessor->GetLocalAabb(m_meshHandle);
aabb.MultiplyByScale(m_cachedNonUniformScale);
return aabb;
}
@@ -96,6 +96,13 @@ namespace AZ
RPI::AttachmentReadback::CallbackFunction readbackCallback = [&](const RPI::AttachmentReadback::ReadbackResult& result)
{
if (!result.m_dataBuffer)
{
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event(
m_context->GetData()->m_thumbnailKeyRendered,
&AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender);
return;
}
uchar* data = result.m_dataBuffer.get()->data();
QImage image(
data, result.m_imageDescriptor.m_size.m_width, result.m_imageDescriptor.m_size.m_height, QImage::Format_RGBA8888);
@@ -311,7 +311,8 @@ namespace AZ
Data::Asset<RPI::ModelAsset> modelAsset = actor->GetMeshAsset();
if (!modelAsset.IsReady())
{
AZ_Error("CreateSkinnedMeshInputFromActor", false, "Attempting to create skinned mesh input buffers for an actor that doesn't have a loaded model.");
AZ_Warning("CreateSkinnedMeshInputFromActor", false, "Check if the actor has a mesh added. Right click the source file in the asset browser, click edit settings, "
"and navigate to the Meshes tab. Add a mesh if it's missing.");
return nullptr;
}
@@ -83,12 +83,20 @@ namespace AZ
void AtomActorInstance::UpdateBounds()
{
// Update RenderActorInstance world bounding box
// The bounding box is moving with the actor instance. It is static in the way that it does not change shape.
// The bounding box is moving with the actor instance.
// The entity and actor transforms are kept in sync already.
m_worldAABB = AZ::Aabb::CreateFromMinMax(m_actorInstance->GetAABB().GetMin(), m_actorInstance->GetAABB().GetMax());
// Update RenderActorInstance local bounding box
m_localAABB = AZ::Aabb::CreateFromMinMax(m_actorInstance->GetStaticBasedAABB().GetMin(), m_actorInstance->GetStaticBasedAABB().GetMax());
// NB: computing the local bbox from the world bbox makes the local bbox artifically larger than it should be
// instead EMFX should support getting the local bbox from the actor instance directly
m_localAABB = m_worldAABB.GetTransformedAabb(m_transformInterface->GetWorldTM().GetInverse());
// Update bbox on mesh instance if it exists
if (m_meshFeatureProcessor && m_meshHandle && m_meshHandle->IsValid() && m_skinnedMeshInstance)
{
m_meshFeatureProcessor->SetLocalAabb(*m_meshHandle, m_localAABB);
}
AZ::Interface<AzFramework::IEntityBoundsUnion>::Get()->RefreshEntityLocalBoundsUnion(m_entityId);
}
@@ -456,9 +464,8 @@ namespace AZ
void AtomActorInstance::Create()
{
Destroy();
m_skinnedMeshInputBuffers = GetRenderActor()->FindOrCreateSkinnedMeshInputBuffers();
AZ_Error("AtomActorInstance", m_skinnedMeshInputBuffers, "Failed to get SkinnedMeshInputBuffers from Actor.");
AZ_Warning("AtomActorInstance", m_skinnedMeshInputBuffers, "Failed to create SkinnedMeshInputBuffers from Actor. It is likely that this actor doesn't have any meshes");
if (m_skinnedMeshInputBuffers)
{
m_boneTransforms = CreateBoneTransformBufferFromActorInstance(m_actorInstance, GetSkinningMethod());
@@ -69,10 +69,16 @@ proj.launch-config = {loc('../../SDK/Atom/Scripts/Python/DCC_Materials/maya_mate
loc('../../azpy/__init__.py'): ('custom',
(u'',
'launch-oobMrvXFf1SwtYBg')),
loc('../../azpy/constants.py'): ('custom',
(u'',
'launch-GeaM41WYMGA1sEfm')),
loc('../../azpy/env_base.py'): ('project',
(u'',
'launch-GeaM41WYMGA1sEfm')),
loc('../../azpy/maya/callbacks/node_message_callback_handler.py'): ('c'\
'ustom',
(u'',
'launch-GeaM41WYMGA1sEfm')),
loc('../../config.py'): ('custom',
(u'',
'launch-GeaM41WYMGA1sEfm'))}
@@ -165,12 +165,14 @@ def get_current_project():
bootstrap_box = None
try:
bootstrap_box = Box.from_json(filename=PATH_USER_O3DE_BOOTSTRAP,
bootstrap_box = Box.from_json(filename=str(Path(PATH_USER_O3DE_BOOTSTRAP).resolve()),
encoding="utf-8",
errors="strict",
object_pairs_hook=OrderedDict)
except FileExistsError as e:
_LOGGER.error('File does not exist: {}'.format(PATH_USER_O3DE_BOOTSTRAP))
except Exception as e:
# this file runs in py2.7 for Maya 2020, FileExistsError is not defined
_LOGGER.error('FileExistsError: {}'.format(PATH_USER_O3DE_BOOTSTRAP))
_LOGGER.error('exception is: {}'.format(e))
if bootstrap_box:
# this seems fairly hard coded - what if the data changes?
@@ -226,7 +226,18 @@ TAG_DEFAULT_PY = str('Launch_pyBASE.bat')
FILENAME_DEFAULT_CONFIG = str('DCCSI_config.json')
# new o3de related paths
PATH_USER_O3DE = str('{home}\\{o3de}').format(home=expanduser("~"),
# os.path.expanduser("~") returns different values in py2.7 vs 3
PATH_USER_HOME = expanduser("~")
_LOGGER.debug('user home: {}'.format(PATH_USER_HOME))
# special case, make sure didn't return <user>\documents
parts = os.path.split(PATH_USER_HOME)
if str(parts[1].lower()) == 'documents':
PATH_USER_HOME = parts[0]
_LOGGER.debug('user home CORRECTED: {}'.format(PATH_USER_HOME))
PATH_USER_O3DE = str('{home}\\{o3de}').format(home=PATH_USER_HOME,
o3de=TAG_O3DE_FOLDER)
PATH_USER_O3DE_REGISTRY = str('{0}\\Registry').format(PATH_USER_O3DE)
PATH_USER_O3DE_BOOTSTRAP = str('{reg}\\{file}').format(reg=PATH_USER_O3DE_REGISTRY,
@@ -44,7 +44,7 @@ namespace Blast
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
->Attribute(
AZ::Edit::Attributes::HelpPageURL,
"https://docs.aws.amazon.com/lumberyard/latest/userguide/component-blast-actor.html")
"https://docs.o3de.org/docs/user-guide/components/reference/blast-family/")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(
AZ::Edit::UIHandlers::Default, &EditorBlastFamilyComponent::m_blastAsset, "Blast asset",
@@ -67,7 +67,7 @@ namespace Blast
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
->Attribute(
AZ::Edit::Attributes::HelpPageURL,
"https://docs.aws.amazon.com/lumberyard/latest/userguide/component-blast-actor.html")
"https://docs.o3de.org/docs/user-guide/components/reference/blast-family-mesh-data/")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(
AZ::Edit::UIHandlers::CheckBox, &EditorBlastMeshDataComponent::m_showMeshAssets,
-18
View File
@@ -15,7 +15,6 @@
#include <AzCore/Component/TransformBus.h>
#include <AzFramework/Entity/GameEntityContextBus.h>
#include <AzFramework/Physics/Common/PhysicsSceneQueries.h>
#include <AzFramework/Physics/Joint.h>
#include <AzFramework/Physics/RigidBodyBus.h>
#include <AzFramework/Physics/Shape.h>
#include <AzFramework/Physics/SystemBus.h>
@@ -221,23 +220,6 @@ namespace Blast
AZStd::vector<AZStd::shared_ptr<Physics::Material>>(const Physics::MaterialSelection&));
MOCK_METHOD2(
UpdateMaterialSelection, bool(const Physics::ShapeConfiguration&, Physics::ColliderConfiguration&));
MOCK_METHOD0(GetSupportedJointTypes, AZStd::vector<AZ::TypeId>());
MOCK_METHOD1(CreateJointLimitConfiguration, AZStd::shared_ptr<Physics::JointLimitConfiguration>(AZ::TypeId));
MOCK_METHOD3(
CreateJoint,
AZStd::shared_ptr<Physics::Joint>(
const AZStd::shared_ptr<Physics::JointLimitConfiguration>&, AzPhysics::SimulatedBody*, AzPhysics::SimulatedBody*));
MOCK_METHOD10(
GenerateJointLimitVisualizationData,
void(
const Physics::JointLimitConfiguration&, const AZ::Quaternion&, const AZ::Quaternion&, float, AZ::u32,
AZ::u32, AZStd::vector<AZ::Vector3>&, AZStd::vector<AZ::u32>&, AZStd::vector<AZ::Vector3>&,
AZStd::vector<bool>&));
MOCK_METHOD5(
ComputeInitialJointLimitConfiguration,
AZStd::unique_ptr<Physics::JointLimitConfiguration>(
const AZ::TypeId&, const AZ::Quaternion&, const AZ::Quaternion&, const AZ::Vector3&,
const AZStd::vector<AZ::Quaternion>&));
MOCK_METHOD3(CookConvexMeshToFile, bool(const AZStd::string&, const AZ::Vector3*, AZ::u32));
MOCK_METHOD3(CookConvexMeshToMemory, bool(const AZ::Vector3*, AZ::u32, AZStd::vector<AZ::u8>&));
MOCK_METHOD5(
@@ -71,12 +71,7 @@ namespace EMotionFX
newNodeConfig.m_debugName = jointName;
// Create joint limit on default.
AZStd::vector<AZ::TypeId> supportedJointLimitTypes;
Physics::SystemRequestBus::BroadcastResult(supportedJointLimitTypes, &Physics::SystemRequests::GetSupportedJointTypes);
if (!supportedJointLimitTypes.empty())
{
newNodeConfig.m_jointLimit = CommandRagdollHelpers::CreateJointLimitByType(supportedJointLimitTypes[0], skeleton, joint);
}
newNodeConfig.m_jointConfig = CommandRagdollHelpers::CreateJointLimitByType(AzPhysics::JointType::D6Joint, skeleton, joint);
if (index)
{
@@ -91,8 +86,8 @@ namespace EMotionFX
}
}
AZStd::unique_ptr<Physics::JointLimitConfiguration> CommandRagdollHelpers::CreateJointLimitByType(
const AZ::TypeId& typeId, const Skeleton* skeleton, const Node* node)
AZStd::unique_ptr<AzPhysics::JointConfiguration> CommandRagdollHelpers::CreateJointLimitByType(
AzPhysics::JointType jointType, const Skeleton* skeleton, const Node* node)
{
const Pose* bindPose = skeleton->GetBindPose();
const Transform& nodeBindTransform = bindPose->GetModelSpaceTransform(node->GetNodeIndex());
@@ -105,12 +100,20 @@ namespace EMotionFX
AZ::Vector3 boneDirection = GetBoneDirection(skeleton, node);
AZStd::vector<AZ::Quaternion> exampleRotationsLocal;
AZStd::unique_ptr<Physics::JointLimitConfiguration> jointLimitConfig =
AZ::Interface<Physics::System>::Get()->ComputeInitialJointLimitConfiguration(
typeId, parentBindRotationWorld, nodeBindRotationWorld, boneDirection, exampleRotationsLocal);
if (auto* jointHelpers = AZ::Interface<AzPhysics::JointHelpersInterface>::Get())
{
if (AZStd::optional<const AZ::TypeId> jointTypeId = jointHelpers->GetSupportedJointTypeId(jointType);
jointTypeId.has_value())
{
AZStd::unique_ptr<AzPhysics::JointConfiguration> jointLimitConfig = jointHelpers->ComputeInitialJointLimitConfiguration(
*jointTypeId, parentBindRotationWorld, nodeBindRotationWorld, boneDirection, exampleRotationsLocal);
AZ_Assert(jointLimitConfig, "Could not create joint limit configuration with type '%s'.", typeId.ToString<AZStd::string>().c_str());
return jointLimitConfig;
AZ_Assert(jointLimitConfig, "Could not create joint limit configuration.");
return jointLimitConfig;
}
}
AZ_Assert(false, "Could not create joint limit configuration.");
return nullptr;
}
void CommandRagdollHelpers::AddJointsToRagdoll(AZ::u32 actorId, const AZStd::vector<AZStd::string>& jointNames,
@@ -532,7 +535,7 @@ namespace EMotionFX
if (m_serializedJointLimits)
{
AZ::Outcome<AZStd::string> oldSerializedJointLimits = SerializeJointLimits(nodeConfig);
success |= MCore::ReflectionSerializer::DeserializeMembers(nodeConfig->m_jointLimit.get(), m_serializedJointLimits.value());
success |= MCore::ReflectionSerializer::DeserializeMembers(nodeConfig->m_jointConfig.get(), m_serializedJointLimits.value());
if (success && oldSerializedJointLimits.IsSuccess())
{
m_oldSerializedJointLimits = oldSerializedJointLimits.GetValue();
@@ -565,7 +568,7 @@ namespace EMotionFX
AZ::Outcome<AZStd::string> CommandAdjustRagdollJoint::SerializeJointLimits(const Physics::RagdollNodeConfiguration* ragdollNodeConfig)
{
return MCore::ReflectionSerializer::SerializeMembersExcept(
ragdollNodeConfig->m_jointLimit.get(),
ragdollNodeConfig->m_jointConfig.get(),
{"ParentLocalRotation", "ParentLocalPosition", "ChildLocalRotation", "ChildLocalPosition", }
);
}
@@ -45,8 +45,8 @@ namespace EMotionFX
Physics::RagdollConfiguration& ragdollConfig, const AZStd::optional<size_t>& index,
AZStd::string& outResult);
static AZStd::unique_ptr<Physics::JointLimitConfiguration> CreateJointLimitByType(const AZ::TypeId& typeId,
const Skeleton* skeleton, const Node* node);
static AZStd::unique_ptr<AzPhysics::JointConfiguration> CreateJointLimitByType(
AzPhysics::JointType jointType, const Skeleton* skeleton, const Node* node);
static void AddJointsToRagdoll(AZ::u32 actorId, const AZStd::vector<AZStd::string>& jointNames,
MCore::CommandGroup* commandGroup = nullptr, bool executeInsideCommand = false, bool addDefaultCollider = true);
@@ -90,12 +90,15 @@ namespace EMotionFX
if (serializeContext)
{
AZStd::vector<AZ::TypeId> supportedJointLimitTypes;
Physics::SystemRequestBus::BroadcastResult(supportedJointLimitTypes, &Physics::SystemRequests::GetSupportedJointTypes);
for (const AZ::TypeId& jointLimitType : supportedJointLimitTypes)
//D6 joint is the only currently supported joint for ragdoll
if (auto* jointHelpers = AZ::Interface<AzPhysics::JointHelpersInterface>::Get())
{
const char* jointLimitName = serializeContext->FindClassData(jointLimitType)->m_editData->m_name;
m_typeComboBox->addItem(jointLimitName, jointLimitType.ToString<AZStd::string>().c_str());
if (AZStd::optional<const AZ::TypeId> d6jointTypeId = jointHelpers->GetSupportedJointTypeId(AzPhysics::JointType::D6Joint);
d6jointTypeId.has_value())
{
const char* jointLimitName = serializeContext->FindClassData(*d6jointTypeId)->m_editData->m_name;
m_typeComboBox->addItem(jointLimitName, (*d6jointTypeId).ToString<AZStd::string>().c_str());
}
}
// Reflected property editor for joint limit
@@ -134,7 +137,7 @@ namespace EMotionFX
Physics::RagdollNodeConfiguration* ragdollNodeConfig = GetRagdollNodeConfig();
if (ragdollNodeConfig)
{
Physics::JointLimitConfiguration* jointLimitConfig = ragdollNodeConfig->m_jointLimit.get();
AzPhysics::JointConfiguration* jointLimitConfig = ragdollNodeConfig->m_jointConfig.get();
if (jointLimitConfig)
{
const AZ::TypeId& jointTypeId = jointLimitConfig->RTTI_GetType();
@@ -262,13 +265,14 @@ namespace EMotionFX
{
if (type.IsNull())
{
ragdollNodeConfig->m_jointLimit = nullptr;
ragdollNodeConfig->m_jointConfig = nullptr;
}
else
{
const Node* node = m_nodeIndex.data(SkeletonModel::ROLE_POINTER).value<Node*>();
const Skeleton* skeleton = m_nodeIndex.data(SkeletonModel::ROLE_ACTOR_POINTER).value<Actor*>()->GetSkeleton();
ragdollNodeConfig->m_jointLimit = CommandRagdollHelpers::CreateJointLimitByType(type, skeleton, node);
ragdollNodeConfig->m_jointConfig =
CommandRagdollHelpers::CreateJointLimitByType(AzPhysics::JointType::D6Joint, skeleton, node);
}
Update();
@@ -13,7 +13,6 @@
#pragma once
#if !defined(Q_MOC_RUN)
#include <AzFramework/Physics/Joint.h>
#include <AzFramework/Physics/Ragdoll.h>
#include <AzQtComponents/Components/Widgets/Card.h>
#include <QModelIndex>
@@ -514,7 +514,7 @@ namespace EMotionFX
if (renderJointLimits && jointSelected)
{
const AZStd::shared_ptr<Physics::JointLimitConfiguration>& jointLimitConfig = ragdollNode.m_jointLimit;
const AZStd::shared_ptr<AzPhysics::JointConfiguration>& jointLimitConfig = ragdollNode.m_jointConfig;
if (jointLimitConfig)
{
const Node* ragdollParentNode = physicsSetup->FindRagdollParentNode(joint);
@@ -528,7 +528,8 @@ namespace EMotionFX
}
}
void RagdollNodeInspectorPlugin::RenderJointLimit(const Physics::JointLimitConfiguration& configuration,
void RagdollNodeInspectorPlugin::RenderJointLimit(
const AzPhysics::JointConfiguration& configuration,
const ActorInstance* actorInstance,
const Node* node,
const Node* parentNode,
@@ -549,9 +550,12 @@ namespace EMotionFX
m_indexBuffer.clear();
m_lineBuffer.clear();
m_lineValidityBuffer.clear();
Physics::SystemRequestBus::Broadcast(&Physics::SystemRequests::GenerateJointLimitVisualizationData,
configuration, parentOrientation, childOrientation, s_scale, s_angularSubdivisions, s_radialSubdivisions,
m_vertexBuffer, m_indexBuffer, m_lineBuffer, m_lineValidityBuffer);
if(auto* jointHelpers = AZ::Interface<AzPhysics::JointHelpersInterface>::Get())
{
jointHelpers->GenerateJointLimitVisualizationData(
configuration, parentOrientation, childOrientation, s_scale, s_angularSubdivisions, s_radialSubdivisions, m_vertexBuffer,
m_indexBuffer, m_lineBuffer, m_lineValidityBuffer);
}
Transform jointModelSpaceTransform = currentPose->GetModelSpaceTransform(parentNodeIndex);
jointModelSpaceTransform.mPosition = currentPose->GetModelSpaceTransform(nodeIndex).mPosition;
@@ -572,7 +576,8 @@ namespace EMotionFX
}
}
void RagdollNodeInspectorPlugin::RenderJointFrame(const Physics::JointLimitConfiguration& configuration,
void RagdollNodeInspectorPlugin::RenderJointFrame(
const AzPhysics::JointConfiguration& configuration,
const ActorInstance* actorInstance,
const Node* node,
const Node* parentNode,
@@ -60,14 +60,16 @@ namespace EMotionFX
void Render(EMStudio::RenderPlugin* renderPlugin, RenderInfo* renderInfo) override;
void RenderRagdoll(ActorInstance* actorInstance, bool renderColliders, bool renderJointLimits, EMStudio::RenderPlugin* renderPlugin, RenderInfo* renderInfo);
void RenderJointLimit(const Physics::JointLimitConfiguration& jointConfiguration,
void RenderJointLimit(
const AzPhysics::JointConfiguration& jointConfiguration,
const ActorInstance* actorInstance,
const Node* node,
const Node* parentNode,
EMStudio::RenderPlugin* renderPlugin,
EMStudio::EMStudioPlugin::RenderInfo* renderInfo,
const MCore::RGBAColor& color);
void RenderJointFrame(const Physics::JointLimitConfiguration& jointConfiguration,
void RenderJointFrame(
const AzPhysics::JointConfiguration& jointConfiguration,
const ActorInstance* actorInstance,
const Node* node,
const Node* parentNode,
@@ -508,8 +508,7 @@ namespace EMotionFX
void EditorActorComponent::OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset)
{
m_actorAsset = asset;
Actor* actor = m_actorAsset->GetActor();
AZ_Assert(m_actorAsset.IsReady() && actor, "Actor asset should be loaded and actor valid.");
AZ_Assert(m_actorAsset.IsReady() && m_actorAsset->GetActor(), "Actor asset should be loaded and actor valid.");
CheckActorCreation();
}
@@ -19,7 +19,7 @@ namespace EMotionFX
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<D6JointLimitConfiguration, Physics::JointLimitConfiguration>()
serializeContext->Class<D6JointLimitConfiguration, AzPhysics::JointConfiguration>()
->Version(1)
->Field("SwingLimitY", &D6JointLimitConfiguration::m_swingLimitY)
->Field("SwingLimitZ", &D6JointLimitConfiguration::m_swingLimitZ)
@@ -12,23 +12,22 @@
#pragma once
#include <AzFramework/Physics/Joint.h>
#include <AzFramework/Physics/Configuration/JointConfiguration.h>
namespace EMotionFX
{
// Add so that RagdollNodeInspectorPlugin::PhysXCharactersGemAvailable() will return the correct value
// We duplicated the D6JointLimitConfiguration because it doesn't exist in the test environment.
class D6JointLimitConfiguration
: public Physics::JointLimitConfiguration
: public AzPhysics::JointConfiguration
{
public:
AZ_CLASS_ALLOCATOR(D6JointLimitConfiguration, AZ::SystemAllocator, 0);
// This uses the same uuid as the production D6JointLimitConfiguration.
// The Ragdoll UI uses this UUID to see if physx is available.
AZ_RTTI(D6JointLimitConfiguration, "{90C5C23D-16C0-4F23-AD50-A190E402388E}", Physics::JointLimitConfiguration);
AZ_RTTI(D6JointLimitConfiguration, "{90C5C23D-16C0-4F23-AD50-A190E402388E}", AzPhysics::JointConfiguration);
static void Reflect(AZ::ReflectContext* context);
const char* GetTypeName() override { return "D6 Joint"; }
float m_swingLimitY = 45.0f; ///< Maximum angle in degrees from the Y axis of the joint frame.
float m_swingLimitZ = 45.0f; ///< Maximum angle in degrees from the Z axis of the joint frame.
@@ -35,11 +35,6 @@ namespace Physics
MOCK_METHOD2(CreateShape, AZStd::shared_ptr<Physics::Shape>(const Physics::ColliderConfiguration& colliderConfiguration, const Physics::ShapeConfiguration& configuration));
MOCK_METHOD1(ReleaseNativeMeshObject, void(void* nativeMeshObject));
MOCK_METHOD1(CreateMaterial, AZStd::shared_ptr<Physics::Material>(const Physics::MaterialConfiguration& materialConfiguration));
MOCK_METHOD0(GetSupportedJointTypes, AZStd::vector<AZ::TypeId>());
MOCK_METHOD1(CreateJointLimitConfiguration, AZStd::shared_ptr<Physics::JointLimitConfiguration>(AZ::TypeId jointType));
MOCK_METHOD3(CreateJoint, AZStd::shared_ptr<Physics::Joint>(const AZStd::shared_ptr<Physics::JointLimitConfiguration>& configuration, AzPhysics::SimulatedBody* parentBody, AzPhysics::SimulatedBody* childBody));
MOCK_METHOD10(GenerateJointLimitVisualizationData, void(const Physics::JointLimitConfiguration& configuration, const AZ::Quaternion& parentRotation, const AZ::Quaternion& childRotation, float scale, AZ::u32 angularSubdivisions, AZ::u32 radialSubdivisions, AZStd::vector<AZ::Vector3>& vertexBufferOut, AZStd::vector<AZ::u32>& indexBufferOut, AZStd::vector<AZ::Vector3>& lineBufferOut, AZStd::vector<bool>& lineValidityBufferOut));
MOCK_METHOD5(ComputeInitialJointLimitConfiguration, AZStd::unique_ptr<Physics::JointLimitConfiguration>(const AZ::TypeId& jointLimitTypeId, const AZ::Quaternion& parentWorldRotation, const AZ::Quaternion& childWorldRotation, const AZ::Vector3& axis, const AZStd::vector<AZ::Quaternion>& exampleLocalRotations));
MOCK_METHOD3(CookConvexMeshToFile, bool(const AZStd::string& filePath, const AZ::Vector3* vertices, AZ::u32 vertexCount));
MOCK_METHOD3(CookConvexMeshToMemory, bool(const AZ::Vector3* vertices, AZ::u32 vertexCount, AZStd::vector<AZ::u8>& result));
MOCK_METHOD5(CookTriangleMeshToFile, bool(const AZStd::string& filePath, const AZ::Vector3* vertices, AZ::u32 vertexCount, const AZ::u32* indices, AZ::u32 indexCount));
@@ -72,6 +67,36 @@ namespace Physics
MOCK_CONST_METHOD0(GetDefaultSceneConfiguration, const AzPhysics::SceneConfiguration& ());
};
class MockJointHelpersInterface : AZ::Interface<AzPhysics::JointHelpersInterface>::Registrar
{
public:
MOCK_CONST_METHOD0(GetSupportedJointTypeIds, const AZStd::vector<AZ::TypeId>());
MOCK_CONST_METHOD1(GetSupportedJointTypeId, AZStd::optional<const AZ::TypeId>(AzPhysics::JointType typeEnum));
MOCK_METHOD5(
ComputeInitialJointLimitConfiguration,
AZStd::unique_ptr<AzPhysics::JointConfiguration>(
const AZ::TypeId& jointLimitTypeId,
const AZ::Quaternion& parentWorldRotation,
const AZ::Quaternion& childWorldRotation,
const AZ::Vector3& axis,
const AZStd::vector<AZ::Quaternion>& exampleLocalRotations));
MOCK_METHOD10(
GenerateJointLimitVisualizationData,
void(
const AzPhysics::JointConfiguration& configuration,
const AZ::Quaternion& parentRotation,
const AZ::Quaternion& childRotation,
float scale,
AZ::u32 angularSubdivisions,
AZ::u32 radialSubdivisions,
AZStd::vector<AZ::Vector3>& vertexBufferOut,
AZStd::vector<AZ::u32>& indexBufferOut,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut));
};
//Mocked of the AzPhysics Scene Interface. To keep things simple just mocked functions that have a return value OR required for a test.
class MockPhysicsSceneInterface
: AZ::Interface<AzPhysics::SceneInterface>::Registrar
@@ -97,6 +122,9 @@ namespace Physics
void DisableSimulationOfBody(
[[maybe_unused]] AzPhysics::SceneHandle sceneHandle,
[[maybe_unused]] AzPhysics::SimulatedBodyHandle bodyHandle) override {}
void RemoveJoint(
[[maybe_unused]]AzPhysics::SceneHandle sceneHandle,
[[maybe_unused]] AzPhysics::JointHandle jointHandle) override {}
void SuppressCollisionEvents(
[[maybe_unused]] AzPhysics::SceneHandle sceneHandle,
[[maybe_unused]] const AzPhysics::SimulatedBodyHandle& bodyHandleA,
@@ -145,6 +173,9 @@ namespace Physics
MOCK_METHOD2(AddSimulatedBodies, AzPhysics::SimulatedBodyHandleList(AzPhysics::SceneHandle sceneHandle, const AzPhysics::SimulatedBodyConfigurationList& simulatedBodyConfigs));
MOCK_METHOD2(GetSimulatedBodyFromHandle, AzPhysics::SimulatedBody* (AzPhysics::SceneHandle sceneHandle, AzPhysics::SimulatedBodyHandle bodyHandle));
MOCK_METHOD2(GetSimulatedBodiesFromHandle, AzPhysics::SimulatedBodyList(AzPhysics::SceneHandle sceneHandle, const AzPhysics::SimulatedBodyHandleList& bodyHandles));
MOCK_METHOD4(AddJoint, AzPhysics::JointHandle(AzPhysics::SceneHandle sceneHandle, const AzPhysics::JointConfiguration* jointConfig,
AzPhysics::SimulatedBodyHandle parentBody, AzPhysics::SimulatedBodyHandle childBody));
MOCK_METHOD2(GetJointFromHandle, AzPhysics::Joint* (AzPhysics::SceneHandle sceneHandle, AzPhysics::JointHandle bodyHandle));
MOCK_CONST_METHOD1(GetGravity, AZ::Vector3(AzPhysics::SceneHandle sceneHandle));
MOCK_METHOD2(RegisterSceneSimulationFinishHandler, void(AzPhysics::SceneHandle sceneHandle, AzPhysics::SceneEvents::OnSceneSimulationFinishHandler& handler));
MOCK_CONST_METHOD2(GetLegacyBody, AzPhysics::SimulatedBody* (AzPhysics::SceneHandle sceneHandle, AzPhysics::SimulatedBodyHandle handle));

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