/* * 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 #include #include #include #include #include #include #include #include #include namespace AZ { namespace RPI { void BufferSystem::Reflect(ReflectContext* context) { BufferAsset::Reflect(context); BufferAssetView::Reflect(context); } void BufferSystem::GetAssetHandlers(AssetHandlerPtrList& assetHandlers) { assetHandlers.emplace_back(MakeAssetHandler()); } void BufferSystem::Init() { RHI::Ptr device = RHI::RHISystemInterface::Get()->GetDevice(); { Data::InstanceHandler handler; handler.m_createFunction = [](Data::AssetData* bufferAsset) { return Buffer::CreateInternal(*(azrtti_cast(bufferAsset))); }; Data::InstanceDatabase::Create(azrtti_typeid(), handler); } { Data::InstanceHandler handler; handler.m_createFunction = [device](Data::AssetData* poolAsset) { return BufferPool::CreateInternal(*device, *(azrtti_cast(poolAsset))); }; Data::InstanceDatabase::Create(azrtti_typeid(), handler); } Interface::Register(this); m_initialized = true; } void BufferSystem::Shutdown() { if (!m_initialized) { return; } for (uint8_t index = 0; index < static_cast(CommonBufferPoolType::Count); index++) { m_commonPools[index] = nullptr; } Interface::Unregister(this); Data::InstanceDatabase::Destroy(); Data::InstanceDatabase::Destroy(); m_initialized = false; } RHI::Ptr BufferSystem::GetCommonBufferPool(CommonBufferPoolType poolType) { const uint8_t index = static_cast(poolType); if (!m_commonPools[index]) { CreateCommonBufferPool(poolType); } return m_commonPools[index]; } bool BufferSystem::CreateCommonBufferPool(CommonBufferPoolType poolType) { if (!m_initialized) { return false; } auto* device = RHI::RHISystemInterface::Get()->GetDevice(); RHI::Ptr bufferPool = RHI::Factory::Get().CreateBufferPool(); RHI::BufferPoolDescriptor bufferPoolDesc; switch (poolType) { case CommonBufferPoolType::Constant: bufferPoolDesc.m_bindFlags = RHI::BufferBindFlags::Constant; bufferPoolDesc.m_heapMemoryLevel = RHI::HeapMemoryLevel::Device; bufferPoolDesc.m_hostMemoryAccess = RHI::HostMemoryAccess::Write; break; case CommonBufferPoolType::StaticInputAssembly: bufferPoolDesc.m_bindFlags = RHI::BufferBindFlags::InputAssembly | RHI::BufferBindFlags::ShaderRead; bufferPoolDesc.m_heapMemoryLevel = RHI::HeapMemoryLevel::Device; bufferPoolDesc.m_hostMemoryAccess = RHI::HostMemoryAccess::Write; break; case CommonBufferPoolType::DynamicInputAssembly: bufferPoolDesc.m_bindFlags = RHI::BufferBindFlags::DynamicInputAssembly | RHI::BufferBindFlags::ShaderRead; bufferPoolDesc.m_heapMemoryLevel = RHI::HeapMemoryLevel::Host; bufferPoolDesc.m_hostMemoryAccess = RHI::HostMemoryAccess::Write; break; case CommonBufferPoolType::ReadBack: bufferPoolDesc.m_bindFlags = RHI::BufferBindFlags::CopyWrite; bufferPoolDesc.m_heapMemoryLevel = RHI::HeapMemoryLevel::Host; bufferPoolDesc.m_hostMemoryAccess = RHI::HostMemoryAccess::Read; break; case CommonBufferPoolType::ReadWrite: bufferPoolDesc.m_bindFlags = RHI::BufferBindFlags::ShaderWrite | RHI::BufferBindFlags::ShaderRead; bufferPoolDesc.m_heapMemoryLevel = RHI::HeapMemoryLevel::Device; bufferPoolDesc.m_hostMemoryAccess = RHI::HostMemoryAccess::Write; break; case CommonBufferPoolType::ReadOnly: bufferPoolDesc.m_bindFlags = RHI::BufferBindFlags::ShaderRead; bufferPoolDesc.m_heapMemoryLevel = RHI::HeapMemoryLevel::Device; bufferPoolDesc.m_hostMemoryAccess = RHI::HostMemoryAccess::Write; break; default: AZ_Error("BufferSystem", false, "Unknown common buffer pool type: %d", poolType); return false; } bufferPool->SetName(Name(AZStd::string::format("RPI::CommonBufferPool_%i", static_cast(poolType)))); RHI::ResultCode resultCode = bufferPool->Init(*device, bufferPoolDesc); if (resultCode != RHI::ResultCode::Success) { AZ_Error("BufferSystem", false, "Failed to create buffer pool: %d", poolType); return false; } m_commonPools[static_cast(poolType)] = bufferPool; return true; } Data::Instance BufferSystem::CreateBufferFromCommonPool(const CommonBufferDescriptor& descriptor) { Uuid bufferId; if (descriptor.m_isUniqueName) { bufferId = Uuid::CreateName(descriptor.m_bufferName.c_str()); // Report error if there is a buffer with same name. // Note: this shouldn't return the existing buffer because users are expecting a newly created buffer. if (Data::InstanceDatabase::Instance().Find(Data::InstanceId(bufferId))) { AZ_Error("BufferSystem", false, "Buffer with same name '%s' already exist", descriptor.m_bufferName.c_str()); return nullptr; } } else { bufferId = Uuid::CreateRandom(); } RHI::Ptr bufferPool = GetCommonBufferPool(descriptor.m_poolType); if (!bufferPool) { AZ_Error("BufferSystem", false, "Common buffer pool type %d doesn't exist", descriptor.m_poolType); return nullptr; } RHI::BufferDescriptor bufferDesc; bufferDesc.m_alignment = descriptor.m_elementSize; bufferDesc.m_bindFlags = bufferPool->GetDescriptor().m_bindFlags; bufferDesc.m_byteCount = descriptor.m_byteCount; Data::Asset bufferAsset; BufferAssetCreator creator; creator.Begin(bufferId); creator.SetBufferName(descriptor.m_bufferName); creator.SetBuffer(descriptor.m_bufferData, descriptor.m_bufferData? descriptor.m_byteCount : 0, bufferDesc); creator.SetUseCommonPool(descriptor.m_poolType); RHI::BufferViewDescriptor viewDescriptor; if (descriptor.m_elementFormat != RHI::Format::Unknown) { viewDescriptor = RHI::BufferViewDescriptor::CreateTyped( 0, aznumeric_cast(bufferDesc.m_byteCount / descriptor.m_elementSize), descriptor.m_elementFormat); } else { viewDescriptor = RHI::BufferViewDescriptor::CreateStructured( 0, aznumeric_cast(bufferDesc.m_byteCount / descriptor.m_elementSize), descriptor.m_elementSize); } creator.SetBufferViewDescriptor(viewDescriptor); if (creator.End(bufferAsset)) { Data::Instance bufferInst = Buffer::FindOrCreate(bufferAsset); return bufferInst; } return nullptr; } Data::Instance BufferSystem::FindCommonBuffer(AZStd::string_view uniqueBufferName) { Uuid bufferId = Uuid::CreateName(uniqueBufferName.data()); return Data::InstanceDatabase::Instance().Find(Data::InstanceId(bufferId)); } } // namespace RPI } // namespace AZ