Merge branch 'development' into Atom/dmcdiar/ATOM-5702
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
+5
-1
@@ -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];
|
||||
|
||||
+1
-3
@@ -12,7 +12,5 @@
|
||||
"type": "Compute"
|
||||
}
|
||||
]
|
||||
},
|
||||
"DisabledRHIBackends": ["metal"]
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+4
-6
@@ -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
|
||||
|
||||
+3
-1
@@ -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;
|
||||
|
||||
|
||||
+4
@@ -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
|
||||
|
||||
+14
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -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();
|
||||
|
||||
+12
@@ -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);
|
||||
|
||||
+1
-1
@@ -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");
|
||||
}
|
||||
|
||||
+3
@@ -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);
|
||||
|
||||
|
||||
+58
@@ -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
|
||||
+43
@@ -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)
|
||||
|
||||
+7
-3
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
|
||||
+1
-2
@@ -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()
|
||||
|
||||
+4
-4
@@ -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)
|
||||
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ namespace AZ
|
||||
|
||||
static void Reflect(ReflectContext* context);
|
||||
|
||||
DiffuseGlobalIlluminationQualityLevel m_qualityLevel;
|
||||
DiffuseGlobalIlluminationQualityLevel m_qualityLevel = DiffuseGlobalIlluminationQualityLevel::Low;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
+7
@@ -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,
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user