Add runtime material buffer bindings
This commit is contained in:
@@ -45,6 +45,8 @@ inline bool TryBuildBuiltinPassResourceBindingPlan(
|
||||
case BuiltinPassResourceSemantic::Material:
|
||||
location = &outPlan.material;
|
||||
break;
|
||||
case BuiltinPassResourceSemantic::MaterialBuffer:
|
||||
break;
|
||||
case BuiltinPassResourceSemantic::Lighting:
|
||||
location = &outPlan.lighting;
|
||||
break;
|
||||
@@ -83,10 +85,10 @@ inline bool TryBuildBuiltinPassResourceBindingPlan(
|
||||
break;
|
||||
}
|
||||
|
||||
if (location == nullptr) {
|
||||
if (semantic != BuiltinPassResourceSemantic::MaterialBuffer && location == nullptr) {
|
||||
return fail("Builtin pass resource semantic could not be mapped");
|
||||
}
|
||||
if (location->IsValid()) {
|
||||
if (location != nullptr && location->IsValid()) {
|
||||
return fail("Builtin pass resource semantic appears more than once");
|
||||
}
|
||||
|
||||
@@ -97,13 +99,21 @@ inline bool TryBuildBuiltinPassResourceBindingPlan(
|
||||
}
|
||||
}
|
||||
|
||||
*location = { binding.set, binding.binding };
|
||||
const PassResourceBindingLocation resolvedLocation = { binding.set, binding.binding };
|
||||
if (location != nullptr) {
|
||||
*location = resolvedLocation;
|
||||
}
|
||||
|
||||
BuiltinPassResourceBindingDesc resolvedBinding = {};
|
||||
resolvedBinding.name = binding.name;
|
||||
resolvedBinding.semantic = semantic;
|
||||
resolvedBinding.resourceType = binding.type;
|
||||
resolvedBinding.location = *location;
|
||||
resolvedBinding.location = resolvedLocation;
|
||||
outPlan.bindings.PushBack(resolvedBinding);
|
||||
if (semantic == BuiltinPassResourceSemantic::MaterialBuffer) {
|
||||
outPlan.materialBufferBindings.PushBack(resolvedBinding);
|
||||
outPlan.usesMaterialBuffers = true;
|
||||
}
|
||||
|
||||
outPlan.maxSetIndex = std::max(outPlan.maxSetIndex, binding.set);
|
||||
minBoundSet = std::min(minBoundSet, binding.set);
|
||||
@@ -512,6 +522,10 @@ inline bool TryBuildBuiltinPassSetLayouts(
|
||||
case BuiltinPassResourceSemantic::Material:
|
||||
setLayout.usesMaterial = true;
|
||||
break;
|
||||
case BuiltinPassResourceSemantic::MaterialBuffer:
|
||||
setLayout.usesMaterialBuffers = true;
|
||||
setLayout.materialBufferBindings.push_back(binding);
|
||||
break;
|
||||
case BuiltinPassResourceSemantic::Lighting:
|
||||
setLayout.usesLighting = true;
|
||||
break;
|
||||
|
||||
@@ -111,6 +111,10 @@ inline BuiltinPassResourceSemantic ResolveBuiltinPassResourceSemantic(
|
||||
return BuiltinPassResourceSemantic::Material;
|
||||
}
|
||||
|
||||
if (semantic == Containers::String("materialbuffer")) {
|
||||
return BuiltinPassResourceSemantic::MaterialBuffer;
|
||||
}
|
||||
|
||||
if (semantic == Containers::String("lighting") ||
|
||||
semantic == Containers::String("lightingconstants")) {
|
||||
return BuiltinPassResourceSemantic::Lighting;
|
||||
@@ -163,6 +167,16 @@ inline BuiltinPassResourceSemantic ResolveBuiltinPassResourceSemantic(
|
||||
return BuiltinPassResourceSemantic::ShadowMapSampler;
|
||||
}
|
||||
|
||||
switch (binding.type) {
|
||||
case Resources::ShaderResourceType::StructuredBuffer:
|
||||
case Resources::ShaderResourceType::RawBuffer:
|
||||
case Resources::ShaderResourceType::RWStructuredBuffer:
|
||||
case Resources::ShaderResourceType::RWRawBuffer:
|
||||
return BuiltinPassResourceSemantic::MaterialBuffer;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return BuiltinPassResourceSemantic::Unknown;
|
||||
}
|
||||
|
||||
@@ -172,6 +186,8 @@ inline const char* BuiltinPassResourceSemanticToString(BuiltinPassResourceSemant
|
||||
return "PerObject";
|
||||
case BuiltinPassResourceSemantic::Material:
|
||||
return "Material";
|
||||
case BuiltinPassResourceSemantic::MaterialBuffer:
|
||||
return "MaterialBuffer";
|
||||
case BuiltinPassResourceSemantic::Lighting:
|
||||
return "Lighting";
|
||||
case BuiltinPassResourceSemantic::ShadowReceiver:
|
||||
@@ -260,6 +276,11 @@ inline bool IsBuiltinPassResourceTypeCompatible(
|
||||
case BuiltinPassResourceSemantic::Environment:
|
||||
case BuiltinPassResourceSemantic::PassConstants:
|
||||
return type == Resources::ShaderResourceType::ConstantBuffer;
|
||||
case BuiltinPassResourceSemantic::MaterialBuffer:
|
||||
return type == Resources::ShaderResourceType::StructuredBuffer ||
|
||||
type == Resources::ShaderResourceType::RawBuffer ||
|
||||
type == Resources::ShaderResourceType::RWStructuredBuffer ||
|
||||
type == Resources::ShaderResourceType::RWRawBuffer;
|
||||
case BuiltinPassResourceSemantic::BaseColorTexture:
|
||||
case BuiltinPassResourceSemantic::SourceColorTexture:
|
||||
case BuiltinPassResourceSemantic::SkyboxPanoramicTexture:
|
||||
|
||||
@@ -37,6 +37,7 @@ enum class BuiltinPassResourceSemantic : Core::uint8 {
|
||||
Unknown = 0,
|
||||
PerObject,
|
||||
Material,
|
||||
MaterialBuffer,
|
||||
Lighting,
|
||||
ShadowReceiver,
|
||||
Environment,
|
||||
@@ -51,6 +52,7 @@ enum class BuiltinPassResourceSemantic : Core::uint8 {
|
||||
};
|
||||
|
||||
struct BuiltinPassResourceBindingDesc {
|
||||
Containers::String name;
|
||||
BuiltinPassResourceSemantic semantic = BuiltinPassResourceSemantic::Unknown;
|
||||
Resources::ShaderResourceType resourceType = Resources::ShaderResourceType::ConstantBuffer;
|
||||
PassResourceBindingLocation location = {};
|
||||
@@ -58,12 +60,14 @@ struct BuiltinPassResourceBindingDesc {
|
||||
|
||||
struct BuiltinPassResourceBindingPlan {
|
||||
Containers::Array<BuiltinPassResourceBindingDesc> bindings;
|
||||
Containers::Array<BuiltinPassResourceBindingDesc> materialBufferBindings;
|
||||
Core::uint32 maxSetIndex = 0;
|
||||
Core::uint32 firstDescriptorSet = 0;
|
||||
Core::uint32 descriptorSetCount = 0;
|
||||
bool usesConstantBuffers = false;
|
||||
bool usesTextures = false;
|
||||
bool usesSamplers = false;
|
||||
bool usesMaterialBuffers = false;
|
||||
PassResourceBindingLocation perObject = {};
|
||||
PassResourceBindingLocation material = {};
|
||||
PassResourceBindingLocation lighting = {};
|
||||
@@ -91,6 +95,7 @@ struct BuiltinPassResourceBindingPlan {
|
||||
|
||||
struct BuiltinPassSetLayoutMetadata {
|
||||
std::vector<RHI::DescriptorSetLayoutBinding> bindings;
|
||||
std::vector<BuiltinPassResourceBindingDesc> materialBufferBindings;
|
||||
RHI::DescriptorSetLayoutDesc layout = {};
|
||||
RHI::DescriptorHeapType heapType = RHI::DescriptorHeapType::CBV_SRV_UAV;
|
||||
bool shaderVisible = false;
|
||||
@@ -100,6 +105,7 @@ struct BuiltinPassSetLayoutMetadata {
|
||||
bool usesShadowReceiver = false;
|
||||
bool usesEnvironment = false;
|
||||
bool usesPassConstants = false;
|
||||
bool usesMaterialBuffers = false;
|
||||
bool usesTexture = false;
|
||||
bool usesBaseColorTexture = false;
|
||||
bool usesSourceColorTexture = false;
|
||||
|
||||
@@ -32,19 +32,61 @@ public:
|
||||
uint32_t height = 0;
|
||||
};
|
||||
|
||||
struct CachedBufferView {
|
||||
RHI::RHIResourceView* resourceView = nullptr;
|
||||
};
|
||||
|
||||
~RenderResourceCache();
|
||||
|
||||
void Shutdown();
|
||||
|
||||
const CachedMesh* GetOrCreateMesh(RHI::RHIDevice* device, const Resources::Mesh* mesh);
|
||||
const CachedTexture* GetOrCreateTexture(RHI::RHIDevice* device, const Resources::Texture* texture);
|
||||
const CachedBufferView* GetOrCreateBufferView(
|
||||
RHI::RHIDevice* device,
|
||||
RHI::RHIBuffer* buffer,
|
||||
RHI::ResourceViewType viewType,
|
||||
const RHI::ResourceViewDesc& viewDesc);
|
||||
|
||||
private:
|
||||
struct BufferViewCacheKey {
|
||||
const RHI::RHIBuffer* buffer = nullptr;
|
||||
RHI::ResourceViewType viewType = RHI::ResourceViewType::ShaderResource;
|
||||
uint32_t format = 0;
|
||||
RHI::ResourceViewDimension dimension = RHI::ResourceViewDimension::Unknown;
|
||||
uint64_t bufferLocation = 0;
|
||||
uint32_t firstElement = 0;
|
||||
uint32_t elementCount = 0;
|
||||
uint32_t structureByteStride = 0;
|
||||
|
||||
bool operator==(const BufferViewCacheKey& other) const {
|
||||
return buffer == other.buffer &&
|
||||
viewType == other.viewType &&
|
||||
format == other.format &&
|
||||
dimension == other.dimension &&
|
||||
bufferLocation == other.bufferLocation &&
|
||||
firstElement == other.firstElement &&
|
||||
elementCount == other.elementCount &&
|
||||
structureByteStride == other.structureByteStride;
|
||||
}
|
||||
};
|
||||
|
||||
struct BufferViewCacheKeyHash {
|
||||
size_t operator()(const BufferViewCacheKey& key) const noexcept;
|
||||
};
|
||||
|
||||
bool UploadMesh(RHI::RHIDevice* device, const Resources::Mesh* mesh, CachedMesh& cachedMesh);
|
||||
bool UploadTexture(RHI::RHIDevice* device, const Resources::Texture* texture, CachedTexture& cachedTexture);
|
||||
bool CreateBufferView(
|
||||
RHI::RHIDevice* device,
|
||||
RHI::RHIBuffer* buffer,
|
||||
RHI::ResourceViewType viewType,
|
||||
const RHI::ResourceViewDesc& viewDesc,
|
||||
CachedBufferView& cachedBufferView);
|
||||
|
||||
std::unordered_map<const Resources::Mesh*, CachedMesh> m_meshCache;
|
||||
std::unordered_map<const Resources::Texture*, CachedTexture> m_textureCache;
|
||||
std::unordered_map<BufferViewCacheKey, CachedBufferView, BufferViewCacheKeyHash> m_bufferViewCache;
|
||||
};
|
||||
|
||||
} // namespace Rendering
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
#include <XCEngine/Components/MeshRendererComponent.h>
|
||||
#include <XCEngine/Core/Types.h>
|
||||
#include <XCEngine/RHI/RHIBuffer.h>
|
||||
#include <XCEngine/RHI/RHIEnums.h>
|
||||
#include <XCEngine/RHI/RHITypes.h>
|
||||
#include <XCEngine/Resources/Material/Material.h>
|
||||
#include <XCEngine/Resources/Mesh/Mesh.h>
|
||||
#include <XCEngine/Rendering/Builtin/BuiltinPassMetadataUtils.h>
|
||||
@@ -46,6 +49,31 @@ struct MaterialConstantPayloadView {
|
||||
}
|
||||
};
|
||||
|
||||
struct MaterialBufferResourceView {
|
||||
RHI::RHIBuffer* buffer = nullptr;
|
||||
RHI::ResourceViewType viewType = RHI::ResourceViewType::ShaderResource;
|
||||
RHI::ResourceViewDesc viewDesc = {};
|
||||
|
||||
bool IsValid() const {
|
||||
return buffer != nullptr &&
|
||||
(viewType == RHI::ResourceViewType::ShaderResource ||
|
||||
viewType == RHI::ResourceViewType::UnorderedAccess) &&
|
||||
viewDesc.dimension != RHI::ResourceViewDimension::Unknown;
|
||||
}
|
||||
};
|
||||
|
||||
inline bool IsMaterialBufferResourceType(Resources::ShaderResourceType type) {
|
||||
switch (type) {
|
||||
case Resources::ShaderResourceType::StructuredBuffer:
|
||||
case Resources::ShaderResourceType::RawBuffer:
|
||||
case Resources::ShaderResourceType::RWStructuredBuffer:
|
||||
case Resources::ShaderResourceType::RWRawBuffer:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline const Resources::ShaderPropertyDesc* FindShaderPropertyBySemantic(
|
||||
const Resources::Material* material,
|
||||
const Containers::String& semantic) {
|
||||
@@ -249,6 +277,62 @@ inline MaterialConstantPayloadView ResolveSchemaMaterialConstantPayload(const Re
|
||||
return { constantBufferData.Data(), constantBufferData.Size(), layoutView };
|
||||
}
|
||||
|
||||
inline bool TryResolveMaterialBufferResourceView(
|
||||
const Resources::Material* material,
|
||||
const BuiltinPassResourceBindingDesc& binding,
|
||||
MaterialBufferResourceView& outView) {
|
||||
outView = {};
|
||||
if (material == nullptr || !IsMaterialBufferResourceType(binding.resourceType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const Resources::MaterialBufferBinding* materialBinding = material->FindBufferBinding(binding.name);
|
||||
if (materialBinding == nullptr || materialBinding->buffer == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outView.buffer = materialBinding->buffer;
|
||||
outView.viewDesc.firstElement = materialBinding->viewDesc.firstElement;
|
||||
outView.viewDesc.elementCount = materialBinding->viewDesc.elementCount;
|
||||
|
||||
switch (binding.resourceType) {
|
||||
case Resources::ShaderResourceType::StructuredBuffer:
|
||||
outView.viewType = RHI::ResourceViewType::ShaderResource;
|
||||
outView.viewDesc.dimension = RHI::ResourceViewDimension::StructuredBuffer;
|
||||
outView.viewDesc.structureByteStride =
|
||||
materialBinding->viewDesc.structureByteStride > 0
|
||||
? materialBinding->viewDesc.structureByteStride
|
||||
: materialBinding->buffer->GetStride();
|
||||
break;
|
||||
case Resources::ShaderResourceType::RawBuffer:
|
||||
outView.viewType = RHI::ResourceViewType::ShaderResource;
|
||||
outView.viewDesc.dimension = RHI::ResourceViewDimension::RawBuffer;
|
||||
break;
|
||||
case Resources::ShaderResourceType::RWStructuredBuffer:
|
||||
outView.viewType = RHI::ResourceViewType::UnorderedAccess;
|
||||
outView.viewDesc.dimension = RHI::ResourceViewDimension::StructuredBuffer;
|
||||
outView.viewDesc.structureByteStride =
|
||||
materialBinding->viewDesc.structureByteStride > 0
|
||||
? materialBinding->viewDesc.structureByteStride
|
||||
: materialBinding->buffer->GetStride();
|
||||
break;
|
||||
case Resources::ShaderResourceType::RWRawBuffer:
|
||||
outView.viewType = RHI::ResourceViewType::UnorderedAccess;
|
||||
outView.viewDesc.dimension = RHI::ResourceViewDimension::RawBuffer;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (outView.viewDesc.dimension == RHI::ResourceViewDimension::StructuredBuffer &&
|
||||
outView.viewDesc.structureByteStride == 0) {
|
||||
outView = {};
|
||||
return false;
|
||||
}
|
||||
|
||||
return outView.IsValid();
|
||||
}
|
||||
|
||||
inline const Resources::Material* ResolveMaterial(
|
||||
const Components::MeshRendererComponent* meshRenderer,
|
||||
const Resources::Mesh* mesh,
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
#include <vector>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace RHI {
|
||||
class RHIBuffer;
|
||||
}
|
||||
namespace Resources {
|
||||
|
||||
enum class MaterialRenderQueue : Core::int32 {
|
||||
@@ -77,6 +80,18 @@ struct MaterialTextureBinding {
|
||||
std::shared_ptr<PendingTextureLoadState> pendingLoad;
|
||||
};
|
||||
|
||||
struct MaterialBufferBindingViewDesc {
|
||||
Core::uint32 firstElement = 0;
|
||||
Core::uint32 elementCount = 0;
|
||||
Core::uint32 structureByteStride = 0;
|
||||
};
|
||||
|
||||
struct MaterialBufferBinding {
|
||||
Containers::String name;
|
||||
RHI::RHIBuffer* buffer = nullptr;
|
||||
MaterialBufferBindingViewDesc viewDesc = {};
|
||||
};
|
||||
|
||||
class Material : public IResource {
|
||||
public:
|
||||
Material();
|
||||
@@ -128,6 +143,11 @@ public:
|
||||
void SetInt(const Containers::String& name, Core::int32 value);
|
||||
void SetBool(const Containers::String& name, bool value);
|
||||
void SetTexture(const Containers::String& name, const ResourceHandle<Texture>& texture);
|
||||
void SetBuffer(const Containers::String& name, RHI::RHIBuffer* buffer);
|
||||
void SetBuffer(
|
||||
const Containers::String& name,
|
||||
RHI::RHIBuffer* buffer,
|
||||
const MaterialBufferBindingViewDesc& viewDesc);
|
||||
void SetTextureAssetRef(const Containers::String& name,
|
||||
const AssetRef& textureRef,
|
||||
const Containers::String& texturePath = Containers::String());
|
||||
@@ -140,13 +160,17 @@ public:
|
||||
Core::int32 GetInt(const Containers::String& name) const;
|
||||
bool GetBool(const Containers::String& name) const;
|
||||
ResourceHandle<Texture> GetTexture(const Containers::String& name) const;
|
||||
RHI::RHIBuffer* GetBuffer(const Containers::String& name) const;
|
||||
const MaterialBufferBinding* FindBufferBinding(const Containers::String& name) const;
|
||||
Core::uint32 GetTextureBindingCount() const { return static_cast<Core::uint32>(m_textureBindings.Size()); }
|
||||
Core::uint32 GetBufferBindingCount() const { return static_cast<Core::uint32>(m_bufferBindings.Size()); }
|
||||
Containers::String GetTextureBindingName(Core::uint32 index) const;
|
||||
AssetRef GetTextureBindingAssetRef(Core::uint32 index) const;
|
||||
Containers::String GetTextureBindingPath(Core::uint32 index) const;
|
||||
ResourceHandle<Texture> GetTextureBindingLoadedTexture(Core::uint32 index) const;
|
||||
ResourceHandle<Texture> GetTextureBindingTexture(Core::uint32 index) const;
|
||||
const Containers::Array<MaterialTextureBinding>& GetTextureBindings() const { return m_textureBindings; }
|
||||
const Containers::Array<MaterialBufferBinding>& GetBufferBindings() const { return m_bufferBindings; }
|
||||
std::vector<MaterialProperty> GetProperties() const;
|
||||
|
||||
const Containers::Array<Core::uint8>& GetConstantBufferData() const { return m_constantBufferData; }
|
||||
@@ -159,12 +183,15 @@ public:
|
||||
bool HasProperty(const Containers::String& name) const;
|
||||
void RemoveProperty(const Containers::String& name);
|
||||
void ClearAllProperties();
|
||||
void RemoveBufferBinding(const Containers::String& name);
|
||||
void ClearBufferBindings();
|
||||
|
||||
private:
|
||||
const ShaderPropertyDesc* FindShaderPropertyDesc(const Containers::String& name) const;
|
||||
bool CanAssignPropertyType(const Containers::String& name, MaterialPropertyType type) const;
|
||||
bool ResetPropertyToShaderDefault(const Containers::String& name);
|
||||
void SyncShaderSchemaProperties(bool removeUnknownProperties);
|
||||
void SyncShaderRuntimeBufferBindings(bool removeUnknownBindings);
|
||||
void BeginAsyncTextureLoad(Core::uint32 index);
|
||||
void ResolvePendingTextureBinding(Core::uint32 index);
|
||||
void ResolvePendingTextureBindings();
|
||||
@@ -182,6 +209,7 @@ private:
|
||||
Containers::Array<MaterialConstantFieldDesc> m_constantLayout;
|
||||
Containers::Array<Core::uint8> m_constantBufferData;
|
||||
Containers::Array<MaterialTextureBinding> m_textureBindings;
|
||||
Containers::Array<MaterialBufferBinding> m_bufferBindings;
|
||||
Core::uint64 m_changeVersion = 1;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user