9786d63596
* Hair - First introduction of Hair gem to Atom and O3DE - The hair technology is based off TressFX 4.1 - These are some of the areas we enhanced the original TressFX implementation: - Lighting model was replaced and we now use a modified Marschner model - Blending is done directly with the back buffer removing the silhouette of the original implementation - Hair depth / thickness is now calculated to remove incorrect back lighting (TT lobe in the Marschner model) - Thickness corrected to handle hair gaps hence introducing better light passage for the TT - The hair is fully integrated into the Atom pipeline and structure design - Usage of single shared buffer for the computer buffers reduces barriers sync overhead Remarks: - Collisions via SDF compute are to be introduced soon - Improved shortcut rendering method ala Eidos Montreal to be introduced soon Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - code clean pass Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - EMFX Actor visibility implementation Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - COnnecting hair passes to Atom's MainPipeline.pass Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - adding dedicated thumbnail pipeline that does not include the hair gem Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - changed Atom shader files to allow hooking the hair to the lighting data structures Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - fixed a few headers to have the latest O3DE license + verification fixes Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - enabling editor component only when tool pipline is built + default texture add Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - fixing Linux and Android compilation builds Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - another files change to make Linux compile Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - more Linux and Android build fixes Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - Adding usage of fallback white texture - Removing invalid null assignments into vectors - Removing redundant mutex preventing deletion on some platforms Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - Shame: removed forgoten #pragma optimize - Adding header complained by Android Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - removing the Hair Gem connection in the active project. - This submission removes the connection to the active project hence allowing to run without the Gem. Enable the passes in MainPipeline.pass and declare them again when you want to use the Gem. Remark: the gem file PassTemplates.azasset was renamed and will be connected via code in the future to avoid the need to declare in the global pass template. Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - registrating gem pass templates through the gem templates file (#198) * Hair - registrating gem pass templates through the gem templates file Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - adding handler disconnect for the pass template registration. Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - PPLLIndexCounter buffer going data driven via the pass declarations (#202) * Hair - PPLLIndexCounter buffer going data driven via the pass declaration - Moving PPLLIndexCounter from code allocation and attachment to be data driven - Fixed RPI typo bug that can prevent using buffers like that Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - fixing UI Editor (LYShine) crash (#209) Signed-off-by: Adi-Amazon <barlev@amazon.com> * [Hair - resolved the multi pipeline mismatches and crashes + cleaned initialization & leftovers (#222) * [Hair] - multiple render pipelines handling Signed-off-by: Adi-Amazon <barlev@amazon.com> * [Hair] - Shut down order is handle to allow hair feature processor be deregistered only after the bootstrap component has disabled it Signed-off-by: Adi-Amazon <barlev@amazon.com> * [Hair] - minor cleanups Signed-off-by: Adi-Amazon <barlev@amazon.com> * [Hair] - followups from review nits Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - code fixes based on the CR remarks for the Hair merge to Dev (#248) * Hair - First introduction of Hair gem to Atom and O3DE - The hair technology is based off TressFX 4.1 - These are some of the areas we enhanced the original TressFX implementation: - Lighting model was replaced and we now use a modified Marschner model - Blending is done directly with the back buffer removing the silhouette of the original implementation - Hair depth / thickness is now calculated to remove incorrect back lighting (TT lobe in the Marschner model) - Thickness corrected to handle hair gaps hence introducing better light passage for the TT - The hair is fully integrated into the Atom pipeline and structure design - Usage of single shared buffer for the computer buffers reduces barriers sync overhead Remarks: - Collisions via SDF compute are to be introduced soon - Improved shortcut rendering method ala Eidos Montreal to be introduced soon Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - code clean pass Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - EMFX Actor visibility implementation Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - COnnecting hair passes to Atom's MainPipeline.pass Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - adding dedicated thumbnail pipeline that does not include the hair gem Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - changed Atom shader files to allow hooking the hair to the lighting data structures Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - fixed a few headers to have the latest O3DE license + verification fixes Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - enabling editor component only when tool pipline is built + default texture add Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - fixing Linux and Android compilation builds Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - another files change to make Linux compile Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - more Linux and Android build fixes Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - Adding usage of fallback white texture - Removing invalid null assignments into vectors - Removing redundant mutex preventing deletion on some platforms Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - Shame: removed forgoten #pragma optimize - Adding header complained by Android Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - removing the Hair Gem connection in the active project. - This submission removes the connection to the active project hence allowing to run without the Gem. Enable the passes in MainPipeline.pass and declare them again when you want to use the Gem. Remark: the gem file PassTemplates.azasset was renamed and will be connected via code in the future to avoid the need to declare in the global pass template. Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - registrating gem pass templates through the gem templates file (#198) * Hair - registrating gem pass templates through the gem templates file Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - adding handler disconnect for the pass template registration. Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - PPLLIndexCounter buffer going data driven via the pass declarations (#202) * Hair - PPLLIndexCounter buffer going data driven via the pass declaration - Moving PPLLIndexCounter from code allocation and attachment to be data driven - Fixed RPI typo bug that can prevent using buffers like that Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - fixing UI Editor (LYShine) crash (#209) Signed-off-by: Adi-Amazon <barlev@amazon.com> * [Hair - resolved the multi pipeline mismatches and crashes + cleaned initialization & leftovers (#222) * [Hair] - multiple render pipelines handling Signed-off-by: Adi-Amazon <barlev@amazon.com> * [Hair] - Shut down order is handle to allow hair feature processor be deregistered only after the bootstrap component has disabled it Signed-off-by: Adi-Amazon <barlev@amazon.com> * [Hair] - minor cleanups Signed-off-by: Adi-Amazon <barlev@amazon.com> * [Hair] - followups from review nits Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - last fixes based on CR remarks Signed-off-by: Adi-Amazon <barlev@amazon.com> * Hair - fixing AR Signed-off-by: Adi-Amazon <barlev@amazon.com>
259 lines
10 KiB
C++
259 lines
10 KiB
C++
/*
|
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
*
|
|
*/
|
|
|
|
#include <Atom/RHI.Reflect/ShaderSemantic.h>
|
|
#include <Atom/RHI/RHIUtils.h>
|
|
#include <Atom/RHI/Factory.h>
|
|
|
|
#include <Atom/RPI.Reflect/Buffer/BufferAssetCreator.h>
|
|
#include <Atom/RPI.Reflect/ResourcePoolAssetCreator.h>
|
|
|
|
#include <Rendering/SharedBuffer.h>
|
|
#include <Rendering/HairCommon.h>
|
|
|
|
namespace AZ
|
|
{
|
|
namespace Render
|
|
{
|
|
//! Setting the constructor as private will create compile error to remind the developer to set
|
|
//! the buffer Init in the FeatureProcessor and initialize properly
|
|
|
|
SharedBuffer::SharedBuffer()
|
|
{
|
|
AZ_Warning("SharedBuffer", false, "Missing information to properly create SharedBuffer. Init is required");
|
|
}
|
|
|
|
SharedBuffer::SharedBuffer(AZStd::string bufferName, AZStd::vector<SrgBufferDescriptor>& buffersDescriptors)
|
|
{
|
|
m_bufferName = bufferName;
|
|
Init(bufferName, buffersDescriptors);
|
|
}
|
|
|
|
SharedBuffer::~SharedBuffer()
|
|
{
|
|
m_bufferAsset = {};
|
|
}
|
|
|
|
//! Crucial method that will ensure that the alignment for the BufferViews is always kept.
|
|
//! This is important when requesting a BufferView as the offset needs to be aligned according
|
|
//! to the element type of the buffer.
|
|
void SharedBuffer::CalculateAlignment(AZStd::vector<SrgBufferDescriptor>& buffersDescriptors)
|
|
{
|
|
m_alignment = 1;
|
|
for (uint8_t bufferIndex = 0; bufferIndex < buffersDescriptors.size() ; ++bufferIndex)
|
|
{
|
|
// Using the least common multiple enables resource views to be typed and ensures they can get
|
|
// an offset in bytes that is a multiple of an element count
|
|
m_alignment = std::lcm(m_alignment, buffersDescriptors[bufferIndex].m_elementSize);
|
|
}
|
|
}
|
|
|
|
void SharedBuffer::InitAllocator()
|
|
{
|
|
RHI::FreeListAllocator::Descriptor allocatorDescriptor;
|
|
allocatorDescriptor.m_alignmentInBytes = m_alignment;
|
|
allocatorDescriptor.m_capacityInBytes = m_sizeInBytes;
|
|
allocatorDescriptor.m_policy = RHI::FreeListAllocatorPolicy::BestFit;
|
|
allocatorDescriptor.m_garbageCollectLatency = 0;
|
|
m_freeListAllocator.Init(allocatorDescriptor);
|
|
}
|
|
|
|
void SharedBuffer::CreateBuffer()
|
|
{
|
|
SrgBufferDescriptor descriptor = SrgBufferDescriptor(
|
|
RPI::CommonBufferPoolType::ReadWrite, RHI::Format::Unknown,
|
|
sizeof(float), uint32_t(m_sizeInBytes / sizeof(float)),
|
|
Name{ "HairSharedDynamicBuffer" }, Name{ "m_skinnedHairSharedBuffer" }, 0, 0
|
|
);
|
|
m_buffer = Hair::UtilityClass::CreateBuffer("Hair Gem", descriptor, nullptr);
|
|
}
|
|
|
|
void SharedBuffer::CreateBufferAsset()
|
|
{
|
|
// Create the shared buffer pool
|
|
{
|
|
auto bufferPoolDesc = AZStd::make_unique<RHI::BufferPoolDescriptor>();
|
|
// Output buffers are both written to during skinning and used as input assembly buffers
|
|
bufferPoolDesc->m_bindFlags = RHI::BufferBindFlags::ShaderReadWrite | RHI::BufferBindFlags::Indirect;
|
|
bufferPoolDesc->m_heapMemoryLevel = RHI::HeapMemoryLevel::Device;
|
|
bufferPoolDesc->m_hostMemoryAccess = RHI::HostMemoryAccess::Write;
|
|
|
|
RPI::ResourcePoolAssetCreator creator;
|
|
creator.Begin(Uuid::CreateRandom());
|
|
creator.SetPoolDescriptor(AZStd::move(bufferPoolDesc));
|
|
creator.SetPoolName("SharedBufferPool");
|
|
creator.End(m_bufferPoolAsset);
|
|
}
|
|
|
|
// Create the shared buffer
|
|
{
|
|
RPI::BufferAssetCreator creator;
|
|
Uuid uuid = Uuid::CreateRandom();
|
|
creator.Begin(uuid);
|
|
creator.SetBufferName(m_bufferName);
|
|
creator.SetPoolAsset(m_bufferPoolAsset);
|
|
|
|
RHI::BufferDescriptor bufferDescriptor;
|
|
bufferDescriptor.m_bindFlags = RHI::BufferBindFlags::ShaderReadWrite | RHI::BufferBindFlags::Indirect;
|
|
bufferDescriptor.m_byteCount = m_sizeInBytes;
|
|
bufferDescriptor.m_alignment = m_alignment;
|
|
creator.SetBuffer(nullptr, 0, bufferDescriptor);
|
|
|
|
RHI::BufferViewDescriptor viewDescriptor;
|
|
viewDescriptor.m_elementFormat = RHI::Format::Unknown;
|
|
|
|
// [To Do] - set this as AZ::Vector4 for offset approach shader code optimization
|
|
viewDescriptor.m_elementSize = sizeof(float);
|
|
viewDescriptor.m_elementCount = aznumeric_cast<uint32_t>(m_sizeInBytes) / sizeof(float);
|
|
viewDescriptor.m_elementOffset = 0;
|
|
creator.SetBufferViewDescriptor(viewDescriptor);
|
|
|
|
creator.End(m_bufferAsset);
|
|
}
|
|
}
|
|
|
|
void SharedBuffer::Init(AZStd::string bufferName, AZStd::vector<SrgBufferDescriptor>& buffersDescriptors)
|
|
{
|
|
m_bufferName = bufferName;
|
|
// m_sizeInBytes = 256u * (1024u * 1024u);
|
|
//
|
|
// [To Do] replace this with max size request for allocation that can be given by the calling function
|
|
// This has the following problems:
|
|
// 1. The need to have this aggregated size in advance
|
|
// 2. The size might grow dynamically between frames
|
|
// 3. Due to having several stream buffers (position, tangent, structured), alignment padding
|
|
// size calculation must be added.
|
|
// Requirement: the buffer already has an assert on allocation beyond the memory. In the future it should
|
|
// support greedy memory allocation when memory has reached its end. This must not invalidate the buffer during
|
|
// the current frame, hence allocation of second buffer, fence and a copy must take place.
|
|
|
|
CalculateAlignment(buffersDescriptors);
|
|
|
|
InitAllocator();
|
|
|
|
CreateBuffer();
|
|
|
|
SystemTickBus::Handler::BusConnect();
|
|
}
|
|
|
|
AZStd::intrusive_ptr<HairSharedBufferAllocation> SharedBuffer::Allocate(size_t byteCount)
|
|
{
|
|
RHI::VirtualAddress result;
|
|
{
|
|
AZStd::lock_guard<AZStd::mutex> lock(m_allocatorMutex);
|
|
result = m_freeListAllocator.Allocate(byteCount, m_alignment);
|
|
}
|
|
|
|
if (result.IsValid())
|
|
{
|
|
return aznew HairSharedBufferAllocation(result);
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void SharedBuffer::DeAllocate(RHI::VirtualAddress allocation)
|
|
{
|
|
if (allocation.IsValid())
|
|
{
|
|
{
|
|
AZStd::lock_guard<AZStd::mutex> lock(m_allocatorMutex);
|
|
m_freeListAllocator.DeAllocate(allocation);
|
|
}
|
|
|
|
m_memoryWasFreed = true;
|
|
m_broadcastMemoryAvailableEvent = true;
|
|
}
|
|
}
|
|
|
|
void SharedBuffer::DeAllocateNoSignal(RHI::VirtualAddress allocation)
|
|
{
|
|
if (allocation.IsValid())
|
|
{
|
|
{
|
|
AZStd::lock_guard<AZStd::mutex> lock(m_allocatorMutex);
|
|
m_freeListAllocator.DeAllocate(allocation);
|
|
}
|
|
m_memoryWasFreed = true;
|
|
}
|
|
}
|
|
|
|
Data::Asset<RPI::BufferAsset> SharedBuffer::GetBufferAsset() const
|
|
{
|
|
return m_bufferAsset;
|
|
}
|
|
|
|
Data::Instance<RPI::Buffer> SharedBuffer::GetBuffer()
|
|
{
|
|
if (!m_buffer)
|
|
{
|
|
m_buffer = RPI::Buffer::FindOrCreate(m_bufferAsset);
|
|
}
|
|
return m_buffer;
|
|
}
|
|
|
|
//! Update buffer's content with sourceData at an offset of bufferByteOffset
|
|
bool SharedBuffer::UpdateData(const void* sourceData, uint64_t sourceDataSizeInBytes, uint64_t bufferByteOffset)
|
|
{
|
|
AZStd::lock_guard<AZStd::mutex> lock(m_allocatorMutex);
|
|
if (m_buffer.get())
|
|
{
|
|
return m_buffer->UpdateData(sourceData, sourceDataSizeInBytes, bufferByteOffset);
|
|
}
|
|
AZ_Assert(false, "SharedBuffer error in data allocation - the buffer doesn't exist yet");
|
|
return false;
|
|
}
|
|
|
|
void SharedBuffer::OnSystemTick()
|
|
{
|
|
GarbageCollect();
|
|
}
|
|
|
|
void SharedBuffer::GarbageCollect()
|
|
{
|
|
if (m_memoryWasFreed)
|
|
{
|
|
m_memoryWasFreed = false;
|
|
{
|
|
AZStd::lock_guard<AZStd::mutex> lock(m_allocatorMutex);
|
|
m_freeListAllocator.GarbageCollect();
|
|
}
|
|
if (m_broadcastMemoryAvailableEvent)
|
|
{
|
|
SharedBufferNotificationBus::Broadcast(&SharedBufferNotificationBus::Events::OnSharedBufferMemoryAvailable);
|
|
m_broadcastMemoryAvailableEvent = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
//! Utility function to create a resource view of different type than the shared buffer data.
|
|
//! Since this class is sub-buffer container, this method should be used after creating
|
|
//! a new allocation to be used as a sub-buffer.
|
|
//! Notice the alignment required according to the element size - this might need
|
|
RHI::BufferViewDescriptor SharedBuffer::CreateResourceViewWithDifferentFormat(
|
|
uint32_t offsetInBytes, uint32_t elementCount, uint32_t elementSize,
|
|
RHI::Format format, RHI::BufferBindFlags overrideBindFlags)
|
|
{
|
|
RHI::BufferViewDescriptor viewDescriptor;
|
|
|
|
// In the following line I use the element size and not the size based of the
|
|
// element format since in the more interesting case of structured buffer, the
|
|
// size will result in an error.
|
|
uint32_t elementOffset = offsetInBytes / elementSize;
|
|
viewDescriptor.m_elementOffset = elementOffset;
|
|
viewDescriptor.m_elementCount = elementCount;
|
|
viewDescriptor.m_elementFormat = format;
|
|
viewDescriptor.m_elementSize = elementSize;
|
|
viewDescriptor.m_overrideBindFlags = overrideBindFlags;
|
|
return viewDescriptor;
|
|
}
|
|
|
|
}// namespace Render
|
|
}// namespace AZ
|
|
|