You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/AtomTressFX/Code/Rendering/HairCommon.cpp

196 lines
8.5 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/Factory.h>
#include <Atom/RHI/RHIUtils.h>
#include <Atom/RPI.Public/Shader/Shader.h>
#include <Atom/RPI.Public/Image/StreamingImage.h>
#include <Atom/RPI.Reflect/Buffer/BufferAssetView.h>
// Hair specific
#include <Rendering/HairCommon.h>
namespace AZ
{
namespace Render
{
namespace Hair
{
//!=====================================================================================
//!
//! Utility Functions
//!
//!=====================================================================================
// [To Do] examine if most of these functions can become global in RPI
//! Utility function to generate the Srg given the shader and the desired Srg name to be associated to.
//! If several shaders are sharing the same Srg (for example perView, perScene), it is enough to
//! create the Srg by associating it with a single shader and since the GPU signature and the data
//! are referring to the same shared description (preferable set in an [SrgDeclaration].aszli file)
//! The association with all shaders will work properly.
Data::Instance<RPI::ShaderResourceGroup> UtilityClass::CreateShaderResourceGroup(
Data::Instance<RPI::Shader> shader,
const char* shaderResourceGroupId,
[[maybe_unused]] const char* moduleName)
{
Data::Instance<RPI::ShaderResourceGroup> srg = RPI::ShaderResourceGroup::Create(shader->GetAsset(), AZ::Name{ shaderResourceGroupId });
if (!srg)
{
AZ_Error(moduleName, false, "Failed to create shader resource group");
return nullptr;
}
return srg;
}
//! If srg is nullptr the index handle will NOT be set.
//! This can be useful when creating a constant buffer or an image.
Data::Instance<RPI::Buffer> UtilityClass::CreateBuffer(
[[maybe_unused]] const char* warningHeader,
SrgBufferDescriptor& bufferDesc,
Data::Instance<RPI::ShaderResourceGroup> srg)
{
// If srg is provided, match the shader Srg bind index (returned via the descriptor)
if (srg)
{ // Not always do we want to associate Srg when creating a buffer
bufferDesc.m_resourceShaderIndex = srg->FindShaderInputBufferIndex(bufferDesc.m_paramNameInSrg).GetIndex();
if (bufferDesc.m_resourceShaderIndex == uint32_t(-1))
{
AZ_Error(warningHeader, false, "Failed to find shader input index for [%s] in the SRG.",
bufferDesc.m_paramNameInSrg.GetCStr());
return nullptr;
}
}
// Descriptor setting
RPI::CommonBufferDescriptor desc;
desc.m_elementFormat = bufferDesc.m_elementFormat;
desc.m_poolType = bufferDesc.m_poolType;;
desc.m_elementSize = bufferDesc.m_elementSize;
desc.m_bufferName = bufferDesc.m_bufferName.GetCStr();
desc.m_byteCount = (uint64_t)bufferDesc.m_elementCount * bufferDesc.m_elementSize;
desc.m_bufferData = nullptr; // set during asset load - use Update
// Buffer creation
return RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
}
bool UtilityClass::BindBufferToSrg(
[[maybe_unused]] const char* warningHeader,
Data::Instance<RPI::Buffer> buffer,
SrgBufferDescriptor& bufferDesc,
Data::Instance<RPI::ShaderResourceGroup> srg)
{
if (!buffer)
{
AZ_Error(warningHeader, false, "Trying to bind a null buffer");
return false;
}
RHI::ShaderInputBufferIndex bufferIndex = srg->FindShaderInputBufferIndex(bufferDesc.m_paramNameInSrg);
if (!bufferIndex.IsValid())
{
AZ_Error(warningHeader, false, "Failed to find shader input index for [%s] in the SRG.",
bufferDesc.m_paramNameInSrg.GetCStr());
return false;
}
if (!srg->SetBufferView(bufferIndex, buffer->GetBufferView()))
{
AZ_Error(warningHeader, false, "Failed to bind buffer view for [%s]", bufferDesc.m_bufferName.GetCStr());
return false;
}
return true;
}
Data::Instance<RPI::Buffer> UtilityClass::CreateBufferAndBindToSrg(
const char* warningHeader,
SrgBufferDescriptor& bufferDesc,
Data::Instance<RPI::ShaderResourceGroup> srg)
{
// Buffer creation
Data::Instance<RPI::Buffer> buffer = CreateBuffer(warningHeader, bufferDesc, srg);
if (!BindBufferToSrg(warningHeader, buffer, bufferDesc, srg))
{
return nullptr;
}
return buffer;
}
Data::Instance<RHI::ImagePool> UtilityClass::CreateImagePool(RHI::ImagePoolDescriptor& imagePoolDesc)
{
RHI::Ptr<RHI::Device> device = RHI::GetRHIDevice();
Data::Instance<RHI::ImagePool> imagePool = RHI::Factory::Get().CreateImagePool();
RHI::ResultCode result = imagePool->Init(*device, imagePoolDesc);
if (result != RHI::ResultCode::Success)
{
AZ_Error("CreateImagePool", false, "Failed to create or initialize image pool");
return nullptr;
}
return imagePool;
}
Data::Instance<RHI::Image> UtilityClass::CreateImage2D(RHI::ImagePool* imagePool, RHI::ImageDescriptor& imageDesc)
{
Data::Instance<RHI::Image> rhiImage = RHI::Factory::Get().CreateImage();
RHI::ImageInitRequest request;
request.m_image = rhiImage.get();
request.m_descriptor = imageDesc;
RHI::ResultCode result = imagePool->InitImage(request);
if (result != RHI::ResultCode::Success)
{
AZ_Error("CreateImage2D", false, "Failed to create or initialize image");
return nullptr;
}
return rhiImage;
}
Data::Instance<RPI::StreamingImage> UtilityClass::LoadStreamingImage(
const char* textureFilePath, [[maybe_unused]] const char* sampleName)
{
Data::AssetId streamingImageAssetId;
Data::AssetCatalogRequestBus::BroadcastResult(
streamingImageAssetId, &Data::AssetCatalogRequestBus::Events::GetAssetIdByPath,
textureFilePath, azrtti_typeid<RPI::StreamingImageAsset>(), false);
if (!streamingImageAssetId.IsValid())
{
AZ_Error(sampleName, false, "Failed to get streaming image asset id with path %s", textureFilePath);
return nullptr;
}
auto streamingImageAsset = Data::AssetManager::Instance().GetAsset<RPI::StreamingImageAsset>(
streamingImageAssetId,
Data::AssetLoadBehavior::PreLoad);
streamingImageAsset.BlockUntilLoadComplete();
if (!streamingImageAsset.IsReady())
{
AZ_Error(sampleName, false, "Failed to get streaming image asset '%s'", textureFilePath);
return nullptr;
}
auto image = RPI::StreamingImage::FindOrCreate(streamingImageAsset);
if (!image)
{
AZ_Error(sampleName, false, "Failed to find or create an image instance from image asset '%s'", textureFilePath);
return nullptr;
}
return image;
}
} // namespace Hair
} // namespace Render
} // namespace AZ