Files
XCEngine/engine/include/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h

263 lines
9.7 KiB
C++

#pragma once
#include <XCEngine/Rendering/RenderMaterialUtility.h>
#include <XCEngine/Rendering/RenderPass.h>
#include <XCEngine/Rendering/RenderPipeline.h>
#include <XCEngine/Rendering/RenderPipelineAsset.h>
#include <XCEngine/Rendering/RenderResourceCache.h>
#include <XCEngine/RHI/RHIDescriptorPool.h>
#include <XCEngine/RHI/RHIDescriptorSet.h>
#include <XCEngine/RHI/RHIPipelineLayout.h>
#include <XCEngine/RHI/RHIPipelineState.h>
#include <XCEngine/RHI/RHIResourceView.h>
#include <XCEngine/RHI/RHISampler.h>
#include <XCEngine/RHI/RHITexture.h>
#include <array>
#include <functional>
#include <unordered_map>
#include <vector>
namespace XCEngine {
namespace Components {
class GameObject;
} // namespace Components
namespace Resources {
class Material;
class Shader;
class Texture;
} // namespace Resources
namespace Rendering {
class RenderSurface;
namespace Pipelines {
namespace Detail {
class BuiltinForwardOpaquePass;
} // namespace Detail
class BuiltinForwardPipeline : public RenderPipeline {
public:
BuiltinForwardPipeline();
~BuiltinForwardPipeline() override;
static RHI::InputLayoutDesc BuildInputLayout();
bool Initialize(const RenderContext& context) override;
void Shutdown() override;
bool Render(
const RenderContext& context,
const RenderSurface& surface,
const RenderSceneData& sceneData) override;
private:
friend class Detail::BuiltinForwardOpaquePass;
struct OwnedDescriptorSet {
RHI::RHIDescriptorPool* pool = nullptr;
RHI::RHIDescriptorSet* set = nullptr;
};
struct PerObjectConstants {
Math::Matrix4x4 projection = Math::Matrix4x4::Identity();
Math::Matrix4x4 view = Math::Matrix4x4::Identity();
Math::Matrix4x4 model = Math::Matrix4x4::Identity();
Math::Matrix4x4 normalMatrix = Math::Matrix4x4::Identity();
};
static constexpr Core::uint32 kMaxLightingAdditionalLightCount =
RenderLightingData::kMaxAdditionalLightCount;
struct AdditionalLightConstants {
Math::Vector4 colorAndIntensity = Math::Vector4::Zero();
Math::Vector4 positionAndRange = Math::Vector4::Zero();
Math::Vector4 directionAndType = Math::Vector4::Zero();
Math::Vector4 spotAnglesAndFlags = Math::Vector4::Zero();
};
struct LightingConstants {
Math::Vector4 mainLightDirectionAndIntensity = Math::Vector4::Zero();
Math::Vector4 mainLightColorAndFlags = Math::Vector4::Zero();
Math::Vector4 lightingParams = Math::Vector4::Zero();
std::array<AdditionalLightConstants, kMaxLightingAdditionalLightCount> additionalLights = {};
};
struct ShadowReceiverConstants {
Math::Matrix4x4 worldToShadow = Math::Matrix4x4::Identity();
Math::Vector4 shadowBiasAndTexelSize = Math::Vector4::Zero();
Math::Vector4 shadowOptions = Math::Vector4::Zero();
};
struct FallbackPerMaterialConstants {
Math::Vector4 baseColorFactor = Math::Vector4::One();
};
struct PassLayoutKey {
const Resources::Shader* shader = nullptr;
Containers::String passName;
bool operator==(const PassLayoutKey& other) const {
return shader == other.shader && passName == other.passName;
}
};
struct PassLayoutKeyHash {
size_t operator()(const PassLayoutKey& key) const noexcept {
size_t hash = reinterpret_cast<size_t>(key.shader);
hash ^= std::hash<Containers::String>{}(key.passName) + 0x9e3779b9u + (hash << 6) + (hash >> 2);
return hash;
}
};
struct PassResourceLayout {
RHI::RHIPipelineLayout* pipelineLayout = nullptr;
Core::uint32 firstDescriptorSet = 0;
Core::uint32 descriptorSetCount = 0;
std::vector<BuiltinPassSetLayoutMetadata> setLayouts;
std::vector<OwnedDescriptorSet> staticDescriptorSets;
PassResourceBindingLocation perObject = {};
PassResourceBindingLocation material = {};
PassResourceBindingLocation lighting = {};
PassResourceBindingLocation shadowReceiver = {};
PassResourceBindingLocation baseColorTexture = {};
PassResourceBindingLocation linearClampSampler = {};
PassResourceBindingLocation shadowMapTexture = {};
PassResourceBindingLocation shadowMapSampler = {};
};
struct DynamicDescriptorSetKey {
PassLayoutKey passLayout = {};
Core::uint32 setIndex = 0;
Core::uint64 objectId = 0;
const Resources::Material* material = nullptr;
bool operator==(const DynamicDescriptorSetKey& other) const {
return passLayout == other.passLayout &&
setIndex == other.setIndex &&
objectId == other.objectId &&
material == other.material;
}
};
struct DynamicDescriptorSetKeyHash {
size_t operator()(const DynamicDescriptorSetKey& key) const noexcept {
size_t hash = PassLayoutKeyHash()(key.passLayout);
auto combine = [&hash](size_t value) {
hash ^= value + 0x9e3779b9u + (hash << 6) + (hash >> 2);
};
combine(std::hash<Core::uint32>{}(key.setIndex));
combine(std::hash<Core::uint64>{}(key.objectId));
combine(reinterpret_cast<size_t>(key.material));
return hash;
}
};
struct CachedDescriptorSet {
OwnedDescriptorSet descriptorSet = {};
Core::uint64 materialVersion = 0;
RHI::RHIResourceView* baseColorTextureView = nullptr;
RHI::RHIResourceView* shadowMapTextureView = nullptr;
};
struct ResolvedShaderPass {
const Resources::Shader* shader = nullptr;
const Resources::ShaderPass* pass = nullptr;
Containers::String passName;
};
struct PipelineStateKey {
Resources::MaterialRenderState renderState;
const Resources::Shader* shader = nullptr;
Containers::String passName;
bool operator==(const PipelineStateKey& other) const {
return renderState == other.renderState &&
shader == other.shader &&
passName == other.passName;
}
};
struct PipelineStateKeyHash {
size_t operator()(const PipelineStateKey& key) const noexcept {
size_t hash = MaterialRenderStateHash()(key.renderState);
auto combine = [&hash](size_t value) {
hash ^= value + 0x9e3779b9u + (hash << 6) + (hash >> 2);
};
combine(reinterpret_cast<size_t>(key.shader));
combine(std::hash<Containers::String>{}(key.passName));
return hash;
}
};
bool EnsureInitialized(const RenderContext& context);
bool CreatePipelineResources(const RenderContext& context);
void DestroyPipelineResources();
ResolvedShaderPass ResolveSurfaceShaderPass(const Resources::Material* material) const;
PassResourceLayout* GetOrCreatePassResourceLayout(
const RenderContext& context,
const ResolvedShaderPass& resolvedShaderPass);
RHI::RHIPipelineState* GetOrCreatePipelineState(
const RenderContext& context,
const Resources::Material* material);
bool CreateOwnedDescriptorSet(
const BuiltinPassSetLayoutMetadata& setLayout,
OwnedDescriptorSet& descriptorSet);
RHI::RHIDescriptorSet* GetOrCreateStaticDescriptorSet(
PassResourceLayout& passLayout,
Core::uint32 setIndex);
CachedDescriptorSet* GetOrCreateDynamicDescriptorSet(
const PassLayoutKey& passLayoutKey,
const PassResourceLayout& passLayout,
const BuiltinPassSetLayoutMetadata& setLayout,
Core::uint32 setIndex,
Core::uint64 objectId,
const Resources::Material* material,
const MaterialConstantPayloadView& materialConstants,
const LightingConstants& lightingConstants,
const ShadowReceiverConstants& shadowReceiverConstants,
RHI::RHIResourceView* baseColorTextureView,
RHI::RHIResourceView* shadowMapTextureView);
void DestroyOwnedDescriptorSet(OwnedDescriptorSet& descriptorSet);
void DestroyPassResourceLayout(PassResourceLayout& passLayout);
const Resources::Texture* ResolveTexture(const Resources::Material* material) const;
RHI::RHIResourceView* ResolveTextureView(const VisibleRenderItem& visibleItem);
static LightingConstants BuildLightingConstants(const RenderLightingData& lightingData);
static AdditionalLightConstants BuildAdditionalLightConstants(const RenderAdditionalLightData& lightData);
bool ExecuteForwardOpaquePass(const RenderPassContext& context);
bool DrawVisibleItem(
const RenderContext& context,
const RenderSceneData& sceneData,
const VisibleRenderItem& visibleItem);
RHI::RHIDevice* m_device = nullptr;
RHI::RHIType m_backendType = RHI::RHIType::D3D12;
bool m_initialized = false;
Resources::ResourceHandle<Resources::Shader> m_builtinForwardShader;
Resources::ResourceHandle<Resources::Shader> m_builtinUnlitShader;
RenderResourceCache m_resourceCache;
std::unordered_map<PassLayoutKey, PassResourceLayout, PassLayoutKeyHash> m_passResourceLayouts;
std::unordered_map<PipelineStateKey, RHI::RHIPipelineState*, PipelineStateKeyHash> m_pipelineStates;
std::unordered_map<DynamicDescriptorSetKey, CachedDescriptorSet, DynamicDescriptorSetKeyHash> m_dynamicDescriptorSets;
RHI::RHISampler* m_sampler = nullptr;
RHI::RHISampler* m_shadowSampler = nullptr;
RHI::RHITexture* m_fallbackTexture = nullptr;
RHI::RHIResourceView* m_fallbackTextureView = nullptr;
RenderPassSequence m_passSequence;
};
class BuiltinForwardPipelineAsset final : public RenderPipelineAsset {
public:
std::unique_ptr<RenderPipeline> CreatePipeline() const override;
};
} // namespace Pipelines
} // namespace Rendering
} // namespace XCEngine