diff --git a/BuildTools/.NET/dotnet-build-package.py b/BuildTools/.NET/dotnet-build-package.py index 28fce01b8..6ecd06bdf 100644 --- a/BuildTools/.NET/dotnet-build-package.py +++ b/BuildTools/.NET/dotnet-build-package.py @@ -230,6 +230,7 @@ def dotnet_run_native_tests(config, settings, arch, gapi): def dotnet_run_managed_tests(config, arch, gapi): os.environ["DILIGENT_GAPI"] = gapi + os.environ["DOTNET_ROLL_FORWARD"] = "Major" subprocess.run(f"dotnet test -c {config} -p:Platform={arch} {project_paths['dotnet-tests']}", check=True) diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp index 02caea7f8..44a748e03 100644 --- a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp +++ b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp @@ -301,6 +301,16 @@ class DeviceContextBase : public ObjectBase CustomGetSignature = nullptr) const; #else // clang-format off - void DvpVerifyDrawArguments (const DrawAttribs& Attribs) const {} - void DvpVerifyDrawIndexedArguments (const DrawIndexedAttribs& Attribs) const {} - void DvpVerifyDrawMeshArguments (const DrawMeshAttribs& Attribs) const {} - void DvpVerifyDrawIndirectArguments (const DrawIndirectAttribs& Attribs) const {} - void DvpVerifyDrawIndexedIndirectArguments (const DrawIndexedIndirectAttribs& Attribs) const {} - void DvpVerifyDrawMeshIndirectArguments (const DrawMeshIndirectAttribs& Attribs) const {} - - void DvpVerifyDispatchArguments (const DispatchComputeAttribs& Attribs) const {} - void DvpVerifyDispatchIndirectArguments(const DispatchComputeIndirectAttribs& Attribs) const {} - void DvpVerifyDispatchTileArguments(const DispatchTileAttribs& Attribs) const {} void DvpVerifyRenderTargets()const {} @@ -561,15 +551,24 @@ class DeviceContextBase : public ObjectBase::SetVertexBuffers( // Remove null buffers from the end of the array while (m_NumVertexStreams > 0 && !m_VertexStreams[m_NumVertexStreams - 1].pBuffer) m_VertexStreams[m_NumVertexStreams--] = VertexStreamInfo{}; + + ++m_Stats.CommandCounters.SetVertexBuffers; } template @@ -762,6 +765,7 @@ inline void DeviceContextBase::SetPipelineState( "PSO '", pPipelineState->GetDesc().Name, "' can't be used in device context '", m_Desc.Name, "'."); m_pPipelineState = std::move(pPipelineState); + ++m_Stats.CommandCounters.SetPipelineState; } template @@ -776,6 +780,8 @@ inline void DeviceContextBase::CommitShaderResources( "Do not use RESOURCE_STATE_TRANSITION_MODE_TRANSITION or end the render pass first."); DEV_CHECK_ERR(pShaderResourceBinding != nullptr, "pShaderResourceBinding must not be null"); + + ++m_Stats.CommandCounters.CommitShaderResources; } template @@ -809,6 +815,8 @@ inline void DeviceContextBase::SetIndexBuffer( "Buffer '", BuffDesc.Name ? BuffDesc.Name : "", "' being bound as index buffer was not created with BIND_INDEX_BUFFER flag"); } #endif + + ++m_Stats.CommandCounters.SetIndexBuffer; } @@ -843,6 +851,9 @@ inline bool DeviceContextBase::SetBlendFactors(const float FactorsDiffer = true; m_BlendFactors[f] = BlendFactors[f]; } + if (FactorsDiffer) + ++m_Stats.CommandCounters.SetBlendFactors; + return FactorsDiffer; } @@ -854,6 +865,7 @@ inline bool DeviceContextBase::SetStencilRef(Uint32 Stenci if (m_StencilRef != StencilRef) { m_StencilRef = StencilRef; + ++m_Stats.CommandCounters.SetStencilRef; return true; } return false; @@ -897,6 +909,8 @@ inline void DeviceContextBase::SetViewports( DEV_CHECK_ERR(m_Viewports[vp].Height >= 0, "Incorrect viewport height (", m_Viewports[vp].Height, ")"); DEV_CHECK_ERR(m_Viewports[vp].MaxDepth >= m_Viewports[vp].MinDepth, "Incorrect viewport depth range [", m_Viewports[vp].MinDepth, ", ", m_Viewports[vp].MaxDepth, "]"); } + + ++m_Stats.CommandCounters.SetViewports; } template @@ -939,6 +953,8 @@ inline void DeviceContextBase::SetScissorRects( DEV_CHECK_ERR(m_ScissorRects[sr].left <= m_ScissorRects[sr].right, "Incorrect horizontal bounds for a scissor rect [", m_ScissorRects[sr].left, ", ", m_ScissorRects[sr].right, ")"); DEV_CHECK_ERR(m_ScissorRects[sr].top <= m_ScissorRects[sr].bottom, "Incorrect vertical bounds for a scissor rect [", m_ScissorRects[sr].top, ", ", m_ScissorRects[sr].bottom, ")"); } + + ++m_Stats.CommandCounters.SetScissorRects; } template @@ -1134,6 +1150,9 @@ inline bool DeviceContextBase::SetRenderTargets(const SetR } #endif + if (bBindRenderTargets) + ++m_Stats.CommandCounters.SetRenderTargets; + return bBindRenderTargets; } @@ -1547,6 +1566,8 @@ inline void DeviceContextBase::ClearDepthStencil(ITextureV } } #endif + + ++m_Stats.CommandCounters.ClearDepthStencil; } template @@ -1590,6 +1611,8 @@ inline void DeviceContextBase::ClearRenderTarget(ITextureV } } #endif + + ++m_Stats.CommandCounters.ClearRenderTarget; } template @@ -1605,6 +1628,8 @@ inline void DeviceContextBase::BeginQuery(IQuery* pQuery, DVP_CHECK_QUEUE_TYPE_COMPATIBILITY(QueueType, "BeginQuery for query type ", GetQueryTypeString(QueryType)); ClassPtrCast(pQuery)->OnBeginQuery(static_cast(this)); + + ++m_Stats.CommandCounters.BeginQuery; } template @@ -1653,6 +1678,8 @@ inline void DeviceContextBase::UpdateBuffer( DEV_CHECK_ERR(Size + Offset <= BuffDesc.Size, "Unable to update buffer '", BuffDesc.Name, "': Update region [", Offset, ",", Size + Offset, ") is out of buffer bounds [0,", BuffDesc.Size, ")"); } #endif + + ++m_Stats.CommandCounters.UpdateBuffer; } template @@ -1677,6 +1704,8 @@ inline void DeviceContextBase::CopyBuffer( DEV_CHECK_ERR(SrcOffset + Size <= SrcBufferDesc.Size, "Failed to copy buffer '", SrcBufferDesc.Name, "' to '", DstBufferDesc.Name, "': Source range [", SrcOffset, ",", SrcOffset + Size, ") is out of buffer bounds [0,", SrcBufferDesc.Size, ")"); } #endif + + ++m_Stats.CommandCounters.CopyBuffer; } template @@ -1735,6 +1764,8 @@ inline void DeviceContextBase::MapBuffer( DEV_CHECK_ERR(BuffDesc.Usage == USAGE_DYNAMIC || BuffDesc.Usage == USAGE_STAGING, "Only dynamic and staging buffers can be mapped with discard flag"); DEV_CHECK_ERR(MapType == MAP_WRITE, "MAP_FLAG_DISCARD is only valid when mapping buffer for writing"); } + + ++m_Stats.CommandCounters.MapBuffer; } template @@ -1767,6 +1798,7 @@ inline void DeviceContextBase::UpdateTexture( DEV_CHECK_ERR(m_pActiveRenderPass == nullptr, "UpdateTexture command must be used outside of render pass."); ValidateUpdateTextureParams(pTexture->GetDesc(), MipLevel, Slice, DstBox, SubresData); + ++m_Stats.CommandCounters.UpdateTexture; } template @@ -1778,6 +1810,7 @@ inline void DeviceContextBase::CopyTexture(const CopyTextu DEV_CHECK_ERR(m_pActiveRenderPass == nullptr, "CopyTexture command must be used outside of render pass."); ValidateCopyTextureParams(CopyAttribs); + ++m_Stats.CommandCounters.CopyTexture; } template @@ -1792,6 +1825,7 @@ inline void DeviceContextBase::MapTextureSubresource( { DEV_CHECK_ERR(pTexture, "pTexture must not be null"); ValidateMapTextureParams(pTexture->GetDesc(), MipLevel, ArraySlice, MapType, MapFlags, pMapRegion); + ++m_Stats.CommandCounters.MapTextureSubresource; } template @@ -1820,6 +1854,7 @@ inline void DeviceContextBase::GenerateMips(ITextureView* "' was not created with TEXTURE_VIEW_FLAG_ALLOW_MIP_MAP_GENERATION flag and can't be used to generate mipmaps."); } #endif + ++m_Stats.CommandCounters.GenerateMips; } @@ -1839,66 +1874,79 @@ void DeviceContextBase::ResolveTextureSubresource( VerifyResolveTextureSubresourceAttribs(ResolveAttribs, SrcTexDesc, DstTexDesc); #endif + ++m_Stats.CommandCounters.ResolveTextureSubresource; } template -void DeviceContextBase::BuildBLAS(const BuildBLASAttribs& Attribs, int) const +void DeviceContextBase::BuildBLAS(const BuildBLASAttribs& Attribs, int) { DVP_CHECK_QUEUE_TYPE_COMPATIBILITY(COMMAND_QUEUE_TYPE_COMPUTE, "BuildBLAS"); DEV_CHECK_ERR(m_pDevice->GetFeatures().RayTracing, "IDeviceContext::BuildBLAS: ray tracing is not supported by this device"); DEV_CHECK_ERR(m_pActiveRenderPass == nullptr, "IDeviceContext::BuildBLAS command must be performed outside of render pass"); DEV_CHECK_ERR(VerifyBuildBLASAttribs(Attribs, m_pDevice), "BuildBLASAttribs are invalid"); + + ++m_Stats.CommandCounters.BuildBLAS; } template -void DeviceContextBase::BuildTLAS(const BuildTLASAttribs& Attribs, int) const +void DeviceContextBase::BuildTLAS(const BuildTLASAttribs& Attribs, int) { DVP_CHECK_QUEUE_TYPE_COMPATIBILITY(COMMAND_QUEUE_TYPE_COMPUTE, "BuildTLAS"); DEV_CHECK_ERR(m_pDevice->GetFeatures().RayTracing, "IDeviceContext::BuildTLAS: ray tracing is not supported by this device"); DEV_CHECK_ERR(m_pActiveRenderPass == nullptr, "IDeviceContext::BuildTLAS command must be performed outside of render pass"); DEV_CHECK_ERR(VerifyBuildTLASAttribs(Attribs, m_pDevice->GetAdapterInfo().RayTracing), "BuildTLASAttribs are invalid"); + + ++m_Stats.CommandCounters.BuildTLAS; } template -void DeviceContextBase::CopyBLAS(const CopyBLASAttribs& Attribs, int) const +void DeviceContextBase::CopyBLAS(const CopyBLASAttribs& Attribs, int) { DVP_CHECK_QUEUE_TYPE_COMPATIBILITY(COMMAND_QUEUE_TYPE_COMPUTE, "CopyBLAS"); DEV_CHECK_ERR(m_pDevice->GetFeatures().RayTracing, "IDeviceContext::CopyBLAS: ray tracing is not supported by this device"); DEV_CHECK_ERR(m_pActiveRenderPass == nullptr, "IDeviceContext::CopyBLAS command must be performed outside of render pass"); DEV_CHECK_ERR(VerifyCopyBLASAttribs(m_pDevice, Attribs), "CopyBLASAttribs are invalid"); + + ++m_Stats.CommandCounters.CopyBLAS; } template -void DeviceContextBase::CopyTLAS(const CopyTLASAttribs& Attribs, int) const +void DeviceContextBase::CopyTLAS(const CopyTLASAttribs& Attribs, int) { DVP_CHECK_QUEUE_TYPE_COMPATIBILITY(COMMAND_QUEUE_TYPE_COMPUTE, "CopyTLAS"); DEV_CHECK_ERR(m_pDevice->GetFeatures().RayTracing, "IDeviceContext::CopyTLAS: ray tracing is not supported by this device"); DEV_CHECK_ERR(m_pActiveRenderPass == nullptr, "IDeviceContext::CopyTLAS command must be performed outside of render pass"); DEV_CHECK_ERR(VerifyCopyTLASAttribs(Attribs), "CopyTLASAttribs are invalid"); DEV_CHECK_ERR(ClassPtrCast(Attribs.pSrc)->ValidateContent(), "IDeviceContext::CopyTLAS: pSrc acceleration structure is not valid"); + + ++m_Stats.CommandCounters.CopyTLAS; } template -void DeviceContextBase::WriteBLASCompactedSize(const WriteBLASCompactedSizeAttribs& Attribs, int) const +void DeviceContextBase::WriteBLASCompactedSize(const WriteBLASCompactedSizeAttribs& Attribs, int) { DVP_CHECK_QUEUE_TYPE_COMPATIBILITY(COMMAND_QUEUE_TYPE_COMPUTE, "WriteBLASCompactedSize"); DEV_CHECK_ERR(m_pDevice->GetFeatures().RayTracing, "IDeviceContext::WriteBLASCompactedSize: ray tracing is not supported by this device"); DEV_CHECK_ERR(m_pActiveRenderPass == nullptr, "IDeviceContext::WriteBLASCompactedSize: command must be performed outside of render pass"); DEV_CHECK_ERR(VerifyWriteBLASCompactedSizeAttribs(m_pDevice, Attribs), "WriteBLASCompactedSizeAttribs are invalid"); + + ++m_Stats.CommandCounters.WriteBLASCompactedSize; } template -void DeviceContextBase::WriteTLASCompactedSize(const WriteTLASCompactedSizeAttribs& Attribs, int) const +void DeviceContextBase::WriteTLASCompactedSize(const WriteTLASCompactedSizeAttribs& Attribs, int) { DVP_CHECK_QUEUE_TYPE_COMPATIBILITY(COMMAND_QUEUE_TYPE_COMPUTE, "WriteTLASCompactedSize"); DEV_CHECK_ERR(m_pDevice->GetFeatures().RayTracing, "IDeviceContext::WriteTLASCompactedSize: ray tracing is not supported by this device"); DEV_CHECK_ERR(m_pActiveRenderPass == nullptr, "IDeviceContext::WriteTLASCompactedSize: command must be performed outside of render pass"); DEV_CHECK_ERR(VerifyWriteTLASCompactedSizeAttribs(m_pDevice, Attribs), "WriteTLASCompactedSizeAttribs are invalid"); + + ++m_Stats.CommandCounters.WriteTLASCompactedSize; } template -void DeviceContextBase::TraceRays(const TraceRaysAttribs& Attribs, int) const +void DeviceContextBase::TraceRays(const TraceRaysAttribs& Attribs, int) { DVP_CHECK_QUEUE_TYPE_COMPATIBILITY(COMMAND_QUEUE_TYPE_COMPUTE, "TraceRays"); @@ -1934,10 +1982,12 @@ void DeviceContextBase::TraceRays(const TraceRaysAttribs& DEV_CHECK_ERR((Attribs.DimensionX * Attribs.DimensionY * Attribs.DimensionZ) <= RTProps.MaxRayGenThreads, "IDeviceContext::TraceRays command arguments are invalid: the dimension must not exceed the ", RTProps.MaxRayGenThreads, " threads"); + + ++m_Stats.CommandCounters.TraceRays; } template -void DeviceContextBase::TraceRaysIndirect(const TraceRaysIndirectAttribs& Attribs, int) const +void DeviceContextBase::TraceRaysIndirect(const TraceRaysIndirectAttribs& Attribs, int) { DVP_CHECK_QUEUE_TYPE_COMPATIBILITY(COMMAND_QUEUE_TYPE_COMPUTE, "TraceRaysIndirect"); @@ -1973,10 +2023,12 @@ void DeviceContextBase::TraceRaysIndirect(const TraceRaysI VERIFY(pSBTImpl->GetInternalBuffer()->CheckState(RESOURCE_STATE_RAY_TRACING), "SBT '", pSBTImpl->GetDesc().Name, "' internal buffer is expected to be in RESOURCE_STATE_RAY_TRACING, but current state is ", GetResourceStateString(pSBTImpl->GetInternalBuffer()->GetState())); + + ++m_Stats.CommandCounters.TraceRaysIndirect; } template -void DeviceContextBase::UpdateSBT(IShaderBindingTable* pSBT, const UpdateIndirectRTBufferAttribs* pUpdateIndirectBufferAttribs, int) const +void DeviceContextBase::UpdateSBT(IShaderBindingTable* pSBT, const UpdateIndirectRTBufferAttribs* pUpdateIndirectBufferAttribs, int) { DEV_CHECK_ERR(m_pDevice->GetFeatures().RayTracing, "IDeviceContext::UpdateSBT: ray tracing is not supported by this device"); DEV_CHECK_ERR((m_pDevice->GetAdapterInfo().RayTracing.CapFlags & RAY_TRACING_CAP_FLAG_STANDALONE_SHADERS) != 0, @@ -1989,6 +2041,8 @@ void DeviceContextBase::UpdateSBT(IShaderBindingTable* pSB DEV_CHECK_ERR(pUpdateIndirectBufferAttribs->pAttribsBuffer != nullptr, "IDeviceContext::UpdateSBT command arguments are invalid: pUpdateIndirectBufferAttribs->pAttribsBuffer must not be null"); } + + ++m_Stats.CommandCounters.UpdateSBT; } template @@ -2049,7 +2103,7 @@ void DeviceContextBase::SetShadingRate(SHADING_RATE BaseRa } template -void DeviceContextBase::BindSparseResourceMemory(const BindSparseResourceMemoryAttribs& Attribs, int) const +void DeviceContextBase::BindSparseResourceMemory(const BindSparseResourceMemoryAttribs& Attribs, int) { DVP_CHECK_QUEUE_TYPE_COMPATIBILITY(COMMAND_QUEUE_TYPE_SPARSE_BINDING, "BindSparseResourceMemory"); @@ -2057,6 +2111,8 @@ void DeviceContextBase::BindSparseResourceMemory(const Bin DEV_CHECK_ERR(m_pDevice->GetDeviceInfo().Features.SparseResources, "IDeviceContext::BindSparseResourceMemory: SparseResources feature must be enabled"); DEV_CHECK_ERR(m_pActiveRenderPass == nullptr, "Can not bind sparse memory inside an active render pass."); DEV_CHECK_ERR(VerifyBindSparseResourceMemoryAttribs(m_pDevice, Attribs), "BindSparseResourceMemoryAttribs are invalid"); + + ++m_Stats.CommandCounters.BindSparseResourceMemory; } template @@ -2119,137 +2175,195 @@ inline void DeviceContextBase::PrepareCommittedResources(C #endif } -#ifdef DILIGENT_DEVELOPMENT +inline Uint32 GetPrimitiveCount(PRIMITIVE_TOPOLOGY Topology, Uint32 Elements) +{ + if (Topology >= PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST && Topology <= PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST) + { + return Elements / (Topology - PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + 1); + } + else + { + switch (Topology) + { + case PRIMITIVE_TOPOLOGY_UNDEFINED: + UNEXPECTED("Undefined primitive topology"); + return 0; + + // clang-format off + case PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: return Elements / 3; + case PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: return std::max(Elements, 2u) - 2; + case PRIMITIVE_TOPOLOGY_POINT_LIST: return Elements; + case PRIMITIVE_TOPOLOGY_LINE_LIST: return Elements / 2; + case PRIMITIVE_TOPOLOGY_LINE_STRIP: return std::max(Elements, 1u) - 1; + case PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_ADJ: return Elements / 6; + case PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_ADJ: return std::max(Elements, 4u) - 4; + case PRIMITIVE_TOPOLOGY_LINE_LIST_ADJ: return Elements / 4; + case PRIMITIVE_TOPOLOGY_LINE_STRIP_ADJ: return std::max(Elements, 3u) - 3; + // clang-format on + default: UNEXPECTED("Unexpected primitive topology"); return 0; + } + } +} template -inline void DeviceContextBase::DvpVerifyDrawArguments(const DrawAttribs& Attribs) const +inline void DeviceContextBase::Draw(const DrawAttribs& Attribs, int) { - if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) == 0) - return; - - DVP_CHECK_QUEUE_TYPE_COMPATIBILITY(COMMAND_QUEUE_TYPE_GRAPHICS, "Draw"); +#ifdef DILIGENT_DEVELOPMENT + if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) != 0) + { + DVP_CHECK_QUEUE_TYPE_COMPATIBILITY(COMMAND_QUEUE_TYPE_GRAPHICS, "Draw"); - DEV_CHECK_ERR(m_pPipelineState, "Draw command arguments are invalid: no pipeline state is bound."); + DEV_CHECK_ERR(m_pPipelineState, "Draw command arguments are invalid: no pipeline state is bound."); - DEV_CHECK_ERR(m_pPipelineState->GetDesc().PipelineType == PIPELINE_TYPE_GRAPHICS, - "Draw command arguments are invalid: pipeline state '", m_pPipelineState->GetDesc().Name, "' is not a graphics pipeline."); + DEV_CHECK_ERR(m_pPipelineState->GetDesc().PipelineType == PIPELINE_TYPE_GRAPHICS, + "Draw command arguments are invalid: pipeline state '", m_pPipelineState->GetDesc().Name, "' is not a graphics pipeline."); - DEV_CHECK_ERR(VerifyDrawAttribs(Attribs), "DrawAttribs are invalid"); + DEV_CHECK_ERR(VerifyDrawAttribs(Attribs), "DrawAttribs are invalid"); + } +#endif + if (m_pPipelineState) + { + const auto Topology = m_pPipelineState->GetGraphicsPipelineDesc().PrimitiveTopology; + m_Stats.PrimitiveCounts[Topology] += GetPrimitiveCount(Topology, Attribs.NumVertices); + } + ++m_Stats.CommandCounters.Draw; } template -inline void DeviceContextBase::DvpVerifyDrawIndexedArguments(const DrawIndexedAttribs& Attribs) const +inline void DeviceContextBase::DrawIndexed(const DrawIndexedAttribs& Attribs, int) { - if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) == 0) - return; - - DVP_CHECK_QUEUE_TYPE_COMPATIBILITY(COMMAND_QUEUE_TYPE_GRAPHICS, "DrawIndexed"); +#ifdef DILIGENT_DEVELOPMENT + if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) != 0) + { + DVP_CHECK_QUEUE_TYPE_COMPATIBILITY(COMMAND_QUEUE_TYPE_GRAPHICS, "DrawIndexed"); - DEV_CHECK_ERR(m_pPipelineState, "DrawIndexed command arguments are invalid: no pipeline state is bound."); + DEV_CHECK_ERR(m_pPipelineState, "DrawIndexed command arguments are invalid: no pipeline state is bound."); - DEV_CHECK_ERR(m_pPipelineState->GetDesc().PipelineType == PIPELINE_TYPE_GRAPHICS, - "DrawIndexed command arguments are invalid: pipeline state '", - m_pPipelineState->GetDesc().Name, "' is not a graphics pipeline."); + DEV_CHECK_ERR(m_pPipelineState->GetDesc().PipelineType == PIPELINE_TYPE_GRAPHICS, + "DrawIndexed command arguments are invalid: pipeline state '", + m_pPipelineState->GetDesc().Name, "' is not a graphics pipeline."); - DEV_CHECK_ERR(m_pIndexBuffer, "DrawIndexed command arguments are invalid: no index buffer is bound."); + DEV_CHECK_ERR(m_pIndexBuffer, "DrawIndexed command arguments are invalid: no index buffer is bound."); - DEV_CHECK_ERR(VerifyDrawIndexedAttribs(Attribs), "DrawIndexedAttribs are invalid"); + DEV_CHECK_ERR(VerifyDrawIndexedAttribs(Attribs), "DrawIndexedAttribs are invalid"); + } +#endif + if (m_pPipelineState) + { + const auto Topology = m_pPipelineState->GetGraphicsPipelineDesc().PrimitiveTopology; + m_Stats.PrimitiveCounts[Topology] += GetPrimitiveCount(Topology, Attribs.NumIndices); + } + ++m_Stats.CommandCounters.DrawIndexed; } template -inline void DeviceContextBase::DvpVerifyDrawMeshArguments(const DrawMeshAttribs& Attribs) const +inline void DeviceContextBase::DrawMesh(const DrawMeshAttribs& Attribs, int) { - if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) == 0) - return; - - DVP_CHECK_QUEUE_TYPE_COMPATIBILITY(COMMAND_QUEUE_TYPE_GRAPHICS, "DrawMesh"); +#ifdef DILIGENT_DEVELOPMENT + if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) != 0) + { + DVP_CHECK_QUEUE_TYPE_COMPATIBILITY(COMMAND_QUEUE_TYPE_GRAPHICS, "DrawMesh"); - DEV_CHECK_ERR(m_pDevice->GetFeatures().MeshShaders, "DrawMesh: mesh shaders are not supported by this device"); + DEV_CHECK_ERR(m_pDevice->GetFeatures().MeshShaders, "DrawMesh: mesh shaders are not supported by this device"); - DEV_CHECK_ERR(m_pPipelineState, "DrawMesh command arguments are invalid: no pipeline state is bound."); + DEV_CHECK_ERR(m_pPipelineState, "DrawMesh command arguments are invalid: no pipeline state is bound."); - DEV_CHECK_ERR(m_pPipelineState->GetDesc().PipelineType == PIPELINE_TYPE_MESH, - "DrawMesh command arguments are invalid: pipeline state '", - m_pPipelineState->GetDesc().Name, "' is not a mesh pipeline."); + DEV_CHECK_ERR(m_pPipelineState->GetDesc().PipelineType == PIPELINE_TYPE_MESH, + "DrawMesh command arguments are invalid: pipeline state '", + m_pPipelineState->GetDesc().Name, "' is not a mesh pipeline."); - DEV_CHECK_ERR(VerifyDrawMeshAttribs(m_pDevice->GetAdapterInfo().MeshShader, Attribs), "DrawMeshAttribs are invalid"); + DEV_CHECK_ERR(VerifyDrawMeshAttribs(m_pDevice->GetAdapterInfo().MeshShader, Attribs), "DrawMeshAttribs are invalid"); + } +#endif + ++m_Stats.CommandCounters.DrawMesh; } template -inline void DeviceContextBase::DvpVerifyDrawIndirectArguments(const DrawIndirectAttribs& Attribs) const +inline void DeviceContextBase::DrawIndirect(const DrawIndirectAttribs& Attribs, int) { - if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) == 0) - return; - - DVP_CHECK_QUEUE_TYPE_COMPATIBILITY(COMMAND_QUEUE_TYPE_GRAPHICS, "DrawIndirect"); +#ifdef DILIGENT_DEVELOPMENT + if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) != 0) + { + DVP_CHECK_QUEUE_TYPE_COMPATIBILITY(COMMAND_QUEUE_TYPE_GRAPHICS, "DrawIndirect"); - DEV_CHECK_ERR(Attribs.pCounterBuffer == nullptr || (m_pDevice->GetAdapterInfo().DrawCommand.CapFlags & DRAW_COMMAND_CAP_FLAG_DRAW_INDIRECT_COUNTER_BUFFER) != 0, - "DrawIndirect command arguments are invalid: counter buffer requires DRAW_COMMAND_CAP_FLAG_DRAW_INDIRECT_COUNTER_BUFFER capability"); - // There is no need to check DRAW_COMMAND_CAP_FLAG_DRAW_INDIRECT because an indirect buffer can only be created if this capability is supported. + DEV_CHECK_ERR(Attribs.pCounterBuffer == nullptr || (m_pDevice->GetAdapterInfo().DrawCommand.CapFlags & DRAW_COMMAND_CAP_FLAG_DRAW_INDIRECT_COUNTER_BUFFER) != 0, + "DrawIndirect command arguments are invalid: counter buffer requires DRAW_COMMAND_CAP_FLAG_DRAW_INDIRECT_COUNTER_BUFFER capability"); + // There is no need to check DRAW_COMMAND_CAP_FLAG_DRAW_INDIRECT because an indirect buffer can only be created if this capability is supported. - DEV_CHECK_ERR(m_pPipelineState, "DrawIndirect command arguments are invalid: no pipeline state is bound."); + DEV_CHECK_ERR(m_pPipelineState, "DrawIndirect command arguments are invalid: no pipeline state is bound."); - DEV_CHECK_ERR(m_pPipelineState->GetDesc().PipelineType == PIPELINE_TYPE_GRAPHICS, - "DrawIndirect command arguments are invalid: pipeline state '", - m_pPipelineState->GetDesc().Name, "' is not a graphics pipeline."); + DEV_CHECK_ERR(m_pPipelineState->GetDesc().PipelineType == PIPELINE_TYPE_GRAPHICS, + "DrawIndirect command arguments are invalid: pipeline state '", + m_pPipelineState->GetDesc().Name, "' is not a graphics pipeline."); - DEV_CHECK_ERR(m_pActiveRenderPass == nullptr || Attribs.AttribsBufferStateTransitionMode != RESOURCE_STATE_TRANSITION_MODE_TRANSITION, - "Resource state transitions are not allowed inside a render pass and may result in an undefined behavior. " - "Do not use RESOURCE_STATE_TRANSITION_MODE_TRANSITION or end the render pass first."); + DEV_CHECK_ERR(m_pActiveRenderPass == nullptr || Attribs.AttribsBufferStateTransitionMode != RESOURCE_STATE_TRANSITION_MODE_TRANSITION, + "Resource state transitions are not allowed inside a render pass and may result in an undefined behavior. " + "Do not use RESOURCE_STATE_TRANSITION_MODE_TRANSITION or end the render pass first."); - DEV_CHECK_ERR(VerifyDrawIndirectAttribs(Attribs), "DrawIndirectAttribs are invalid"); + DEV_CHECK_ERR(VerifyDrawIndirectAttribs(Attribs), "DrawIndirectAttribs are invalid"); + } +#endif + ++m_Stats.CommandCounters.DrawIndirect; } + template -inline void DeviceContextBase::DvpVerifyDrawIndexedIndirectArguments(const DrawIndexedIndirectAttribs& Attribs) const +inline void DeviceContextBase::DrawIndexedIndirect(const DrawIndexedIndirectAttribs& Attribs, int) { - if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) == 0) - return; - - DVP_CHECK_QUEUE_TYPE_COMPATIBILITY(COMMAND_QUEUE_TYPE_GRAPHICS, "DrawIndexedIndirect"); +#ifdef DILIGENT_DEVELOPMENT + if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) != 0) + { + DVP_CHECK_QUEUE_TYPE_COMPATIBILITY(COMMAND_QUEUE_TYPE_GRAPHICS, "DrawIndexedIndirect"); - DEV_CHECK_ERR(Attribs.pCounterBuffer == nullptr || (m_pDevice->GetAdapterInfo().DrawCommand.CapFlags & DRAW_COMMAND_CAP_FLAG_DRAW_INDIRECT_COUNTER_BUFFER) != 0, - "DrawIndexedIndirect command arguments are invalid: counter buffer requires DRAW_COMMAND_CAP_FLAG_DRAW_INDIRECT_COUNTER_BUFFER capability"); - // There is no need to check DRAW_COMMAND_CAP_FLAG_DRAW_INDIRECT because an indirect buffer can only be created if this capability is supported. + DEV_CHECK_ERR(Attribs.pCounterBuffer == nullptr || (m_pDevice->GetAdapterInfo().DrawCommand.CapFlags & DRAW_COMMAND_CAP_FLAG_DRAW_INDIRECT_COUNTER_BUFFER) != 0, + "DrawIndexedIndirect command arguments are invalid: counter buffer requires DRAW_COMMAND_CAP_FLAG_DRAW_INDIRECT_COUNTER_BUFFER capability"); + // There is no need to check DRAW_COMMAND_CAP_FLAG_DRAW_INDIRECT because an indirect buffer can only be created if this capability is supported. - DEV_CHECK_ERR(m_pPipelineState, "DrawIndexedIndirect command arguments are invalid: no pipeline state is bound."); + DEV_CHECK_ERR(m_pPipelineState, "DrawIndexedIndirect command arguments are invalid: no pipeline state is bound."); - DEV_CHECK_ERR(m_pPipelineState->GetDesc().PipelineType == PIPELINE_TYPE_GRAPHICS, - "DrawIndexedIndirect command arguments are invalid: pipeline state '", - m_pPipelineState->GetDesc().Name, "' is not a graphics pipeline."); + DEV_CHECK_ERR(m_pPipelineState->GetDesc().PipelineType == PIPELINE_TYPE_GRAPHICS, + "DrawIndexedIndirect command arguments are invalid: pipeline state '", + m_pPipelineState->GetDesc().Name, "' is not a graphics pipeline."); - DEV_CHECK_ERR(m_pIndexBuffer, "DrawIndexedIndirect command arguments are invalid: no index buffer is bound."); + DEV_CHECK_ERR(m_pIndexBuffer, "DrawIndexedIndirect command arguments are invalid: no index buffer is bound."); - DEV_CHECK_ERR(m_pActiveRenderPass == nullptr || Attribs.AttribsBufferStateTransitionMode != RESOURCE_STATE_TRANSITION_MODE_TRANSITION, - "Resource state transitions are not allowed inside a render pass and may result in an undefined behavior. " - "Do not use RESOURCE_STATE_TRANSITION_MODE_TRANSITION or end the render pass first."); + DEV_CHECK_ERR(m_pActiveRenderPass == nullptr || Attribs.AttribsBufferStateTransitionMode != RESOURCE_STATE_TRANSITION_MODE_TRANSITION, + "Resource state transitions are not allowed inside a render pass and may result in an undefined behavior. " + "Do not use RESOURCE_STATE_TRANSITION_MODE_TRANSITION or end the render pass first."); - DEV_CHECK_ERR(VerifyDrawIndexedIndirectAttribs(Attribs), "DrawIndexedIndirectAttribs are invalid"); + DEV_CHECK_ERR(VerifyDrawIndexedIndirectAttribs(Attribs), "DrawIndexedIndirectAttribs are invalid"); + } +#endif + ++m_Stats.CommandCounters.DrawIndexedIndirect; } template -inline void DeviceContextBase::DvpVerifyDrawMeshIndirectArguments(const DrawMeshIndirectAttribs& Attribs) const +inline void DeviceContextBase::DrawMeshIndirect(const DrawMeshIndirectAttribs& Attribs, int) { - if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) == 0) - return; - - DVP_CHECK_QUEUE_TYPE_COMPATIBILITY(COMMAND_QUEUE_TYPE_GRAPHICS, "DrawMeshIndirect"); +#ifdef DILIGENT_DEVELOPMENT + if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) != 0) + { + DVP_CHECK_QUEUE_TYPE_COMPATIBILITY(COMMAND_QUEUE_TYPE_GRAPHICS, "DrawMeshIndirect"); - DEV_CHECK_ERR(m_pDevice->GetFeatures().MeshShaders, "DrawMeshIndirect: mesh shaders are not supported by this device"); + DEV_CHECK_ERR(m_pDevice->GetFeatures().MeshShaders, "DrawMeshIndirect: mesh shaders are not supported by this device"); - DEV_CHECK_ERR(Attribs.pCounterBuffer == nullptr || (m_pDevice->GetAdapterInfo().DrawCommand.CapFlags & DRAW_COMMAND_CAP_FLAG_DRAW_INDIRECT_COUNTER_BUFFER) != 0, - "DrawMeshIndirect command arguments are invalid: counter buffer requires DRAW_COMMAND_CAP_FLAG_DRAW_INDIRECT_COUNTER_BUFFER capability"); - // There is no need to check DRAW_COMMAND_CAP_FLAG_DRAW_INDIRECT because an indirect buffer can only be created if this capability is supported. + DEV_CHECK_ERR(Attribs.pCounterBuffer == nullptr || (m_pDevice->GetAdapterInfo().DrawCommand.CapFlags & DRAW_COMMAND_CAP_FLAG_DRAW_INDIRECT_COUNTER_BUFFER) != 0, + "DrawMeshIndirect command arguments are invalid: counter buffer requires DRAW_COMMAND_CAP_FLAG_DRAW_INDIRECT_COUNTER_BUFFER capability"); + // There is no need to check DRAW_COMMAND_CAP_FLAG_DRAW_INDIRECT because an indirect buffer can only be created if this capability is supported. - DEV_CHECK_ERR(m_pPipelineState, "DrawMeshIndirect command arguments are invalid: no pipeline state is bound."); + DEV_CHECK_ERR(m_pPipelineState, "DrawMeshIndirect command arguments are invalid: no pipeline state is bound."); - DEV_CHECK_ERR(m_pPipelineState->GetDesc().PipelineType == PIPELINE_TYPE_MESH, - "DrawMeshIndirect command arguments are invalid: pipeline state '", - m_pPipelineState->GetDesc().Name, "' is not a mesh pipeline."); + DEV_CHECK_ERR(m_pPipelineState->GetDesc().PipelineType == PIPELINE_TYPE_MESH, + "DrawMeshIndirect command arguments are invalid: pipeline state '", + m_pPipelineState->GetDesc().Name, "' is not a mesh pipeline."); - DEV_CHECK_ERR(VerifyDrawMeshIndirectAttribs(Attribs, DrawMeshIndirectCommandStride), "DrawMeshIndirectAttribs are invalid"); + DEV_CHECK_ERR(VerifyDrawMeshIndirectAttribs(Attribs, DrawMeshIndirectCommandStride), "DrawMeshIndirectAttribs are invalid"); + } +#endif + ++m_Stats.CommandCounters.DrawMeshIndirect; } +#ifdef DILIGENT_DEVELOPMENT template inline void DeviceContextBase::DvpVerifyRenderTargets() const { @@ -2341,11 +2455,11 @@ inline void DeviceContextBase::DvpVerifyRenderTargets() co } } } - +#endif template -inline void DeviceContextBase::DvpVerifyDispatchArguments(const DispatchComputeAttribs& Attribs) const +inline void DeviceContextBase::DispatchCompute(const DispatchComputeAttribs& Attribs, int) { DEV_CHECK_ERR(m_pPipelineState, "DispatchCompute command arguments are invalid: no pipeline state is bound."); @@ -2357,10 +2471,12 @@ inline void DeviceContextBase::DvpVerifyDispatchArguments( "DispatchCompute command must be performed outside of render pass"); DEV_CHECK_ERR(VerifyDispatchComputeAttribs(Attribs), "DispatchComputeAttribs attribs"); + + ++m_Stats.CommandCounters.DispatchCompute; } template -inline void DeviceContextBase::DvpVerifyDispatchIndirectArguments(const DispatchComputeIndirectAttribs& Attribs) const +inline void DeviceContextBase::DispatchComputeIndirect(const DispatchComputeIndirectAttribs& Attribs, int) { DEV_CHECK_ERR(m_pPipelineState, "DispatchComputeIndirect command arguments are invalid: no pipeline state is bound."); @@ -2371,8 +2487,11 @@ inline void DeviceContextBase::DvpVerifyDispatchIndirectAr DEV_CHECK_ERR(m_pActiveRenderPass == nullptr, "DispatchComputeIndirect command must be performed outside of render pass"); DEV_CHECK_ERR(VerifyDispatchComputeIndirectAttribs(Attribs), "DispatchComputeIndirectAttribs are invalid"); + + ++m_Stats.CommandCounters.DispatchComputeIndirect; } +#ifdef DILIGENT_DEVELOPMENT template inline void DeviceContextBase::DvpVerifyDispatchTileArguments(const DispatchTileAttribs& Attribs) const { diff --git a/Graphics/GraphicsEngine/interface/APIInfo.h b/Graphics/GraphicsEngine/interface/APIInfo.h index 3fde9f0d3..8a741e867 100644 --- a/Graphics/GraphicsEngine/interface/APIInfo.h +++ b/Graphics/GraphicsEngine/interface/APIInfo.h @@ -30,7 +30,7 @@ /// \file /// Diligent API information -#define DILIGENT_API_VERSION 254001 +#define DILIGENT_API_VERSION 254002 #include "../../../Primitives/interface/BasicTypes.h" diff --git a/Graphics/GraphicsEngine/interface/DeviceContext.h b/Graphics/GraphicsEngine/interface/DeviceContext.h index 88f036433..5d2c789da 100644 --- a/Graphics/GraphicsEngine/interface/DeviceContext.h +++ b/Graphics/GraphicsEngine/interface/DeviceContext.h @@ -2078,6 +2078,160 @@ struct StateTransitionDesc }; typedef struct StateTransitionDesc StateTransitionDesc; +/// Device context command counters. +struct DeviceContextCommandCounters +{ + /// The total number of SetPipelineState calls. + Uint32 SetPipelineState DEFAULT_INITIALIZER(0); + + /// The total number of CommitShaderResources calls. + Uint32 CommitShaderResources DEFAULT_INITIALIZER(0); + + /// The total number of SetVertexBuffers calls. + Uint32 SetVertexBuffers DEFAULT_INITIALIZER(0); + + /// The total number of SetIndexBuffer calls. + Uint32 SetIndexBuffer DEFAULT_INITIALIZER(0); + + /// The total number of SetRenderTargets calls. + Uint32 SetRenderTargets DEFAULT_INITIALIZER(0); + + /// The total number of SetBlendFactors calls. + Uint32 SetBlendFactors DEFAULT_INITIALIZER(0); + + /// The total number of SetStencilRef calls. + Uint32 SetStencilRef DEFAULT_INITIALIZER(0); + + /// The total number of SetViewports calls. + Uint32 SetViewports DEFAULT_INITIALIZER(0); + + /// The total number of SetScissorRects calls. + Uint32 SetScissorRects DEFAULT_INITIALIZER(0); + + /// The total number of ClearRenderTarget calls. + Uint32 ClearRenderTarget DEFAULT_INITIALIZER(0); + + /// The total number of ClearDepthStencil calls. + Uint32 ClearDepthStencil DEFAULT_INITIALIZER(0); + + /// The total number of Draw calls. + Uint32 Draw DEFAULT_INITIALIZER(0); + + /// The total number of DrawIndexed calls. + Uint32 DrawIndexed DEFAULT_INITIALIZER(0); + + /// The total number of indirect DrawIndirect calls. + Uint32 DrawIndirect DEFAULT_INITIALIZER(0); + + /// The total number of indexed indirect DrawIndexedIndirect calls. + Uint32 DrawIndexedIndirect DEFAULT_INITIALIZER(0); + + /// The total number of DispatchCompute calls. + Uint32 DispatchCompute DEFAULT_INITIALIZER(0); + + /// The total number of DispatchComputeIndirect calls. + Uint32 DispatchComputeIndirect DEFAULT_INITIALIZER(0); + + /// The total number of DispatchTile calls. + Uint32 DispatchTile DEFAULT_INITIALIZER(0); + + /// The total number of DrawMesh calls. + Uint32 DrawMesh DEFAULT_INITIALIZER(0); + + /// The total number of DrawMeshIndirect calls. + Uint32 DrawMeshIndirect DEFAULT_INITIALIZER(0); + + /// The total number of BuildBLAS calls. + Uint32 BuildBLAS DEFAULT_INITIALIZER(0); + + /// The total number of BuildTLAS calls. + Uint32 BuildTLAS DEFAULT_INITIALIZER(0); + + /// The total number of CopyBLAS calls. + Uint32 CopyBLAS DEFAULT_INITIALIZER(0); + + /// The total number of CopyTLAS calls. + Uint32 CopyTLAS DEFAULT_INITIALIZER(0); + + /// The total number of WriteBLASCompactedSize calls. + Uint32 WriteBLASCompactedSize DEFAULT_INITIALIZER(0); + + /// The total number of WriteTLASCompactedSize calls. + Uint32 WriteTLASCompactedSize DEFAULT_INITIALIZER(0); + + /// The total number of TraceRays calls. + Uint32 TraceRays DEFAULT_INITIALIZER(0); + + /// The total number of TraceRaysIndirect calls. + Uint32 TraceRaysIndirect DEFAULT_INITIALIZER(0); + + /// The total number of UpdateSBT calls. + Uint32 UpdateSBT DEFAULT_INITIALIZER(0); + + /// The total number of UpdateBuffer calls. + Uint32 UpdateBuffer DEFAULT_INITIALIZER(0); + + /// The total number of CopyBuffer calls. + Uint32 CopyBuffer DEFAULT_INITIALIZER(0); + + /// The total number of MapBuffer calls. + Uint32 MapBuffer DEFAULT_INITIALIZER(0); + + /// The total number of UpdateTexture calls. + Uint32 UpdateTexture DEFAULT_INITIALIZER(0); + + /// The total number of CopyTexture calls. + Uint32 CopyTexture DEFAULT_INITIALIZER(0); + + /// The total number of MapTextureSubresource calls. + Uint32 MapTextureSubresource DEFAULT_INITIALIZER(0); + + /// The total number of BeginQuery calls. + Uint32 BeginQuery DEFAULT_INITIALIZER(0); + + /// The total number of GenerateMips calls. + Uint32 GenerateMips DEFAULT_INITIALIZER(0); + + /// The total number of ResolveTextureSubresource calls. + Uint32 ResolveTextureSubresource DEFAULT_INITIALIZER(0); + + /// The total number of BindSparseResourceMemory calls. + Uint32 BindSparseResourceMemory DEFAULT_INITIALIZER(0); +}; +typedef struct DeviceContextCommandCounters DeviceContextCommandCounters; + +/// Device context statistics. +struct DeviceContextStats +{ + /// The total number of primitives rendered, for each primitive topology. + Uint32 PrimitiveCounts[PRIMITIVE_TOPOLOGY_NUM_TOPOLOGIES] DEFAULT_INITIALIZER({}); + + /// Command counters, see Diligent::DeviceContextCommandCounters. + DeviceContextCommandCounters CommandCounters DEFAULT_INITIALIZER({}); + +#if DILIGENT_CPP_INTERFACE + constexpr Uint32 GetTotalTriangleCount() const noexcept + { + return PrimitiveCounts[PRIMITIVE_TOPOLOGY_TRIANGLE_LIST] + + PrimitiveCounts[PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP] + + PrimitiveCounts[PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_ADJ]; + } + + constexpr Uint32 GetTotalLineCount() const noexcept + { + return PrimitiveCounts[PRIMITIVE_TOPOLOGY_LINE_LIST] + + PrimitiveCounts[PRIMITIVE_TOPOLOGY_LINE_STRIP] + + PrimitiveCounts[PRIMITIVE_TOPOLOGY_LINE_STRIP_ADJ]; + } + + constexpr Uint32 GetTotalPointCount() const noexcept + { + return PrimitiveCounts[PRIMITIVE_TOPOLOGY_POINT_LIST]; + } +#endif +}; +typedef struct DeviceContextStats DeviceContextStats; + #define DILIGENT_INTERFACE_NAME IDeviceContext #include "../../../Primitives/interface/DefineInterfaceHelperMacros.h" @@ -3243,6 +3397,12 @@ DILIGENT_BEGIN_INTERFACE(IDeviceContext, IObject) /// internal queue supports COMMAND_QUEUE_TYPE_SPARSE_BINDING. VIRTUAL void METHOD(BindSparseResourceMemory)(THIS_ const BindSparseResourceMemoryAttribs REF Attribs) PURE; + + /// Clears the device context statistics. + VIRTUAL void METHOD(ClearStats)(THIS) PURE; + + /// Returns the device context statistics, see Diligent::DeviceContextStats. + VIRTUAL const DeviceContextStats REF METHOD(GetStats)(THIS) CONST PURE; }; DILIGENT_END_INTERFACE @@ -3320,6 +3480,8 @@ DILIGENT_END_INTERFACE # define IDeviceContext_UnlockCommandQueue(This) CALL_IFACE_METHOD(DeviceContext, UnlockCommandQueue, This) # define IDeviceContext_SetShadingRate(This, ...) CALL_IFACE_METHOD(DeviceContext, SetShadingRate, This, __VA_ARGS__) # define IDeviceContext_BindSparseResourceMemory(This, ...) CALL_IFACE_METHOD(DeviceContext, BindSparseResourceMemory, This, __VA_ARGS__) +# define IDeviceContext_ClearStats(This) CALL_IFACE_METHOD(DeviceContext, ClearStats, This) +# define IDeviceContext_GetStats(This) CALL_IFACE_METHOD(DeviceContext, GetStats, This) // clang-format on diff --git a/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp index 31cee15d3..5d0286655 100755 --- a/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp +++ b/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp @@ -659,7 +659,7 @@ void DeviceContextD3D11Impl::PrepareForIndexedDraw(DRAW_FLAGS Flags, VALUE_TYPE void DeviceContextD3D11Impl::Draw(const DrawAttribs& Attribs) { - DvpVerifyDrawArguments(Attribs); + TDeviceContextBase::Draw(Attribs, 0); PrepareForDraw(Attribs.Flags); @@ -674,7 +674,7 @@ void DeviceContextD3D11Impl::Draw(const DrawAttribs& Attribs) void DeviceContextD3D11Impl::DrawIndexed(const DrawIndexedAttribs& Attribs) { - DvpVerifyDrawIndexedArguments(Attribs); + TDeviceContextBase::DrawIndexed(Attribs, 0); PrepareForIndexedDraw(Attribs.Flags, Attribs.IndexType); @@ -689,7 +689,7 @@ void DeviceContextD3D11Impl::DrawIndexed(const DrawIndexedAttribs& Attribs) void DeviceContextD3D11Impl::DrawIndirect(const DrawIndirectAttribs& Attribs) { - DvpVerifyDrawIndirectArguments(Attribs); + TDeviceContextBase::DrawIndirect(Attribs, 0); DEV_CHECK_ERR(Attribs.pCounterBuffer == nullptr, "Direct3D11 does not support indirect counter buffer"); PrepareForDraw(Attribs.Flags); @@ -726,7 +726,7 @@ void DeviceContextD3D11Impl::DrawIndirect(const DrawIndirectAttribs& Attribs) void DeviceContextD3D11Impl::DrawIndexedIndirect(const DrawIndexedIndirectAttribs& Attribs) { - DvpVerifyDrawIndexedIndirectArguments(Attribs); + TDeviceContextBase::DrawIndexedIndirect(Attribs, 0); DEV_CHECK_ERR(Attribs.pCounterBuffer == nullptr, "Direct3D11 does not support indirect counter buffer"); PrepareForIndexedDraw(Attribs.Flags, Attribs.IndexType); @@ -772,7 +772,7 @@ void DeviceContextD3D11Impl::DrawMeshIndirect(const DrawMeshIndirectAttribs& Att void DeviceContextD3D11Impl::DispatchCompute(const DispatchComputeAttribs& Attribs) { - DvpVerifyDispatchArguments(Attribs); + TDeviceContextBase::DispatchCompute(Attribs, 0); if (Uint32 BindSRBMask = m_BindInfo.GetCommitMask()) { @@ -802,7 +802,7 @@ void DeviceContextD3D11Impl::DispatchCompute(const DispatchComputeAttribs& Attri void DeviceContextD3D11Impl::DispatchComputeIndirect(const DispatchComputeIndirectAttribs& Attribs) { - DvpVerifyDispatchIndirectArguments(Attribs); + TDeviceContextBase::DispatchComputeIndirect(Attribs, 0); if (Uint32 BindSRBMask = m_BindInfo.GetCommitMask()) { diff --git a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp index 6eb107cef..03acca65a 100644 --- a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp @@ -667,7 +667,7 @@ void DeviceContextD3D12Impl::PrepareForIndexedDraw(GraphicsContext& GraphCtx, DR void DeviceContextD3D12Impl::Draw(const DrawAttribs& Attribs) { - DvpVerifyDrawArguments(Attribs); + TDeviceContextBase::Draw(Attribs, 0); auto& GraphCtx = GetCmdContext().AsGraphicsContext(); PrepareForDraw(GraphCtx, Attribs.Flags); @@ -680,7 +680,7 @@ void DeviceContextD3D12Impl::Draw(const DrawAttribs& Attribs) void DeviceContextD3D12Impl::DrawIndexed(const DrawIndexedAttribs& Attribs) { - DvpVerifyDrawIndexedArguments(Attribs); + TDeviceContextBase::DrawIndexed(Attribs, 0); auto& GraphCtx = GetCmdContext().AsGraphicsContext(); PrepareForIndexedDraw(GraphCtx, Attribs.Flags, Attribs.IndexType); @@ -715,7 +715,7 @@ void DeviceContextD3D12Impl::PrepareIndirectAttribsBuffer(CommandContext& void DeviceContextD3D12Impl::DrawIndirect(const DrawIndirectAttribs& Attribs) { - DvpVerifyDrawIndirectArguments(Attribs); + TDeviceContextBase::DrawIndirect(Attribs, 0); auto& GraphCtx = GetCmdContext().AsGraphicsContext(); PrepareForDraw(GraphCtx, Attribs.Flags); @@ -751,7 +751,7 @@ void DeviceContextD3D12Impl::DrawIndirect(const DrawIndirectAttribs& Attribs) void DeviceContextD3D12Impl::DrawIndexedIndirect(const DrawIndexedIndirectAttribs& Attribs) { - DvpVerifyDrawIndexedIndirectArguments(Attribs); + TDeviceContextBase::DrawIndexedIndirect(Attribs, 0); auto& GraphCtx = GetCmdContext().AsGraphicsContext(); PrepareForIndexedDraw(GraphCtx, Attribs.Flags, Attribs.IndexType); @@ -788,7 +788,7 @@ void DeviceContextD3D12Impl::DrawIndexedIndirect(const DrawIndexedIndirectAttrib void DeviceContextD3D12Impl::DrawMesh(const DrawMeshAttribs& Attribs) { - DvpVerifyDrawMeshArguments(Attribs); + TDeviceContextBase::DrawMesh(Attribs, 0); auto& GraphCtx = GetCmdContext().AsGraphicsContext6(); PrepareForDraw(GraphCtx, Attribs.Flags); @@ -802,7 +802,7 @@ void DeviceContextD3D12Impl::DrawMesh(const DrawMeshAttribs& Attribs) void DeviceContextD3D12Impl::DrawMeshIndirect(const DrawMeshIndirectAttribs& Attribs) { - DvpVerifyDrawMeshIndirectArguments(Attribs); + TDeviceContextBase::DrawMeshIndirect(Attribs, 0); auto& GraphCtx = GetCmdContext().AsGraphicsContext(); PrepareForDraw(GraphCtx, Attribs.Flags); @@ -859,7 +859,7 @@ void DeviceContextD3D12Impl::PrepareForDispatchRays(GraphicsContext& GraphCtx) void DeviceContextD3D12Impl::DispatchCompute(const DispatchComputeAttribs& Attribs) { - DvpVerifyDispatchArguments(Attribs); + TDeviceContextBase::DispatchCompute(Attribs, 0); auto& ComputeCtx = GetCmdContext().AsComputeContext(); PrepareForDispatchCompute(ComputeCtx); @@ -872,7 +872,7 @@ void DeviceContextD3D12Impl::DispatchCompute(const DispatchComputeAttribs& Attri void DeviceContextD3D12Impl::DispatchComputeIndirect(const DispatchComputeIndirectAttribs& Attribs) { - DvpVerifyDispatchIndirectArguments(Attribs); + TDeviceContextBase::DispatchComputeIndirect(Attribs, 0); auto& ComputeCtx = GetCmdContext().AsComputeContext(); PrepareForDispatchCompute(ComputeCtx); diff --git a/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp index 35b02c381..a3c61ec37 100644 --- a/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp @@ -837,7 +837,7 @@ void DeviceContextGLImpl::PostDraw() void DeviceContextGLImpl::Draw(const DrawAttribs& Attribs) { - DvpVerifyDrawArguments(Attribs); + TDeviceContextBase::Draw(Attribs, 0); GLenum GlTopology; PrepareForDraw(Attribs.Flags, false, GlTopology); @@ -863,7 +863,7 @@ void DeviceContextGLImpl::Draw(const DrawAttribs& Attribs) void DeviceContextGLImpl::DrawIndexed(const DrawIndexedAttribs& Attribs) { - DvpVerifyDrawIndexedArguments(Attribs); + TDeviceContextBase::DrawIndexed(Attribs, 0); GLenum GlTopology; PrepareForDraw(Attribs.Flags, true, GlTopology); @@ -948,7 +948,7 @@ void DeviceContextGLImpl::PrepareForIndirectDrawCount(IBuffer* pCountBuffer) void DeviceContextGLImpl::DrawIndirect(const DrawIndirectAttribs& Attribs) { - DvpVerifyDrawIndirectArguments(Attribs); + TDeviceContextBase::DrawIndirect(Attribs, 0); GLenum GlTopology; PrepareForDraw(Attribs.Flags, true, GlTopology); @@ -1022,7 +1022,7 @@ void DeviceContextGLImpl::DrawIndirect(const DrawIndirectAttribs& Attribs) void DeviceContextGLImpl::DrawIndexedIndirect(const DrawIndexedIndirectAttribs& Attribs) { - DvpVerifyDrawIndexedIndirectArguments(Attribs); + TDeviceContextBase::DrawIndexedIndirect(Attribs, 0); GLenum GlTopology; PrepareForDraw(Attribs.Flags, true, GlTopology); @@ -1114,7 +1114,7 @@ void DeviceContextGLImpl::DrawMeshIndirect(const DrawMeshIndirectAttribs& Attrib void DeviceContextGLImpl::DispatchCompute(const DispatchComputeAttribs& Attribs) { - DvpVerifyDispatchArguments(Attribs); + TDeviceContextBase::DispatchCompute(Attribs, 0); #if GL_ARB_compute_shader // The program might have changed since the last SetPipelineState call if a shader was @@ -1144,7 +1144,7 @@ void DeviceContextGLImpl::DispatchCompute(const DispatchComputeAttribs& Attribs) void DeviceContextGLImpl::DispatchComputeIndirect(const DispatchComputeIndirectAttribs& Attribs) { - DvpVerifyDispatchIndirectArguments(Attribs); + TDeviceContextBase::DispatchComputeIndirect(Attribs, 0); #if GL_ARB_compute_shader // The program might have changed since the last SetPipelineState call if a shader was diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index 685e87b6d..dd25da498 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -825,7 +825,7 @@ void DeviceContextVkImpl::PrepareForIndexedDraw(DRAW_FLAGS Flags, VALUE_TYPE Ind void DeviceContextVkImpl::Draw(const DrawAttribs& Attribs) { - DvpVerifyDrawArguments(Attribs); + TDeviceContextBase::Draw(Attribs, 0); PrepareForDraw(Attribs.Flags); @@ -838,7 +838,7 @@ void DeviceContextVkImpl::Draw(const DrawAttribs& Attribs) void DeviceContextVkImpl::DrawIndexed(const DrawIndexedAttribs& Attribs) { - DvpVerifyDrawIndexedArguments(Attribs); + TDeviceContextBase::DrawIndexed(Attribs, 0); PrepareForIndexedDraw(Attribs.Flags, Attribs.IndexType); @@ -851,7 +851,7 @@ void DeviceContextVkImpl::DrawIndexed(const DrawIndexedAttribs& Attribs) void DeviceContextVkImpl::DrawIndirect(const DrawIndirectAttribs& Attribs) { - DvpVerifyDrawIndirectArguments(Attribs); + TDeviceContextBase::DrawIndirect(Attribs, 0); // We must prepare indirect draw attribs buffer first because state transitions must // be performed outside of render pass, and PrepareForDraw commits render pass @@ -886,7 +886,7 @@ void DeviceContextVkImpl::DrawIndirect(const DrawIndirectAttribs& Attribs) void DeviceContextVkImpl::DrawIndexedIndirect(const DrawIndexedIndirectAttribs& Attribs) { - DvpVerifyDrawIndexedIndirectArguments(Attribs); + TDeviceContextBase::DrawIndexedIndirect(Attribs, 0); // We must prepare indirect draw attribs buffer first because state transitions must // be performed outside of render pass, and PrepareForDraw commits render pass @@ -921,7 +921,7 @@ void DeviceContextVkImpl::DrawIndexedIndirect(const DrawIndexedIndirectAttribs& void DeviceContextVkImpl::DrawMesh(const DrawMeshAttribs& Attribs) { - DvpVerifyDrawMeshArguments(Attribs); + TDeviceContextBase::DrawMesh(Attribs, 0); PrepareForDraw(Attribs.Flags); @@ -934,7 +934,7 @@ void DeviceContextVkImpl::DrawMesh(const DrawMeshAttribs& Attribs) void DeviceContextVkImpl::DrawMeshIndirect(const DrawMeshIndirectAttribs& Attribs) { - DvpVerifyDrawMeshIndirectArguments(Attribs); + TDeviceContextBase::DrawMeshIndirect(Attribs, 0); // We must prepare indirect draw attribs buffer first because state transitions must // be performed outside of render pass, and PrepareForDraw commits render pass @@ -1006,7 +1006,7 @@ void DeviceContextVkImpl::PrepareForRayTracing() void DeviceContextVkImpl::DispatchCompute(const DispatchComputeAttribs& Attribs) { - DvpVerifyDispatchArguments(Attribs); + TDeviceContextBase::DispatchCompute(Attribs, 0); PrepareForDispatchCompute(); @@ -1019,7 +1019,7 @@ void DeviceContextVkImpl::DispatchCompute(const DispatchComputeAttribs& Attribs) void DeviceContextVkImpl::DispatchComputeIndirect(const DispatchComputeIndirectAttribs& Attribs) { - DvpVerifyDispatchIndirectArguments(Attribs); + TDeviceContextBase::DispatchComputeIndirect(Attribs, 0); PrepareForDispatchCompute(); diff --git a/Graphics/GraphicsTools/src/DynamicBuffer.cpp b/Graphics/GraphicsTools/src/DynamicBuffer.cpp index eb1a51f63..3e6aa5e85 100644 --- a/Graphics/GraphicsTools/src/DynamicBuffer.cpp +++ b/Graphics/GraphicsTools/src/DynamicBuffer.cpp @@ -274,10 +274,11 @@ void DynamicBuffer::CommitResize(IRenderDevice* pDevice, else ResizeDefaultBuffer(pContext); - m_Desc.Size = m_PendingSize; + LOG_INFO_MESSAGE("Dynamic buffer: expanding dynamic buffer '", m_Desc.Name, "' from ", + FormatMemorySize(m_Desc.Size, 1), " to ", FormatMemorySize(m_PendingSize, 1), + ". Version: ", GetVersion()); - LOG_INFO_MESSAGE("Dynamic buffer: expanding dynamic buffer '", m_Desc.Name, - "' to ", FormatMemorySize(m_Desc.Size, 1), ". Version: ", GetVersion()); + m_Desc.Size = m_PendingSize; } else { diff --git a/Graphics/GraphicsTools/src/VertexPool.cpp b/Graphics/GraphicsTools/src/VertexPool.cpp index c77a25d5b..36489a8b1 100644 --- a/Graphics/GraphicsTools/src/VertexPool.cpp +++ b/Graphics/GraphicsTools/src/VertexPool.cpp @@ -216,6 +216,8 @@ class VertexPoolImpl final : public ObjectBase // We must use atomic because this value is read in another thread, // while m_Buffer internally does not use mutex or other synchronization. BufferSize.store(Buffer.GetDesc().Size); + + UpdateCommittedMemorySize(); } return Buffer.Update(pDevice, pContext); } @@ -353,6 +355,10 @@ class VertexPoolImpl final : public ObjectBase { m_AllocatedVertexCount.store(m_Mgr.GetUsedSize()); m_TotalVertexCount.store(m_Mgr.GetMaxSize()); + UpdateCommittedMemorySize(); + } + void UpdateCommittedMemorySize() + { Uint64 CommittedMemorySize = 0; for (const auto& BuffSize : m_BufferSizes) CommittedMemorySize += BuffSize.load(); diff --git a/Primitives/interface/FormatString.hpp b/Primitives/interface/FormatString.hpp index 8dda1925c..d3586eff6 100644 --- a/Primitives/interface/FormatString.hpp +++ b/Primitives/interface/FormatString.hpp @@ -107,6 +107,14 @@ StreamType& operator<<(StreamType& Stream, const MemorySizeFormatter& Arg) return Stream; } +template +std::string GetMemorySizeString(Type _size, int _precision = 0, Type _ref_size = 0) +{ + std::stringstream ss; + ss << FormatMemorySize(_size, _precision, _ref_size); + return ss.str(); +} + namespace TextColorCode { static constexpr char Default[] = "\033[39m"; diff --git a/ReleaseHistory.md b/ReleaseHistory.md index 90a15fd2e..8b1584c66 100644 --- a/ReleaseHistory.md +++ b/ReleaseHistory.md @@ -1,5 +1,8 @@ ## Current progress +* Added device context rendering statistics (API254002) + * Added `DeviceContextStats` struct + * Added `IDeviceContext::ClearStats` and `IDeviceContext::GetStats` methods * `IDeviceContext::TransitionShaderResources`: removed unused `pPipelineState` parameter (API254001) ## v2.5.4 diff --git a/Tests/GPUTestFramework/src/GPUTestingEnvironment.cpp b/Tests/GPUTestFramework/src/GPUTestingEnvironment.cpp index adbce462e..846c3f80f 100644 --- a/Tests/GPUTestFramework/src/GPUTestingEnvironment.cpp +++ b/Tests/GPUTestFramework/src/GPUTestingEnvironment.cpp @@ -576,6 +576,61 @@ GPUTestingEnvironment::~GPUTestingEnvironment() auto* pCtx = GetDeviceContext(i); pCtx->Flush(); pCtx->FinishFrame(); + + if (i == 0) + { + const auto& Stats = pCtx->GetStats(); + const auto& CmdCounters = Stats.CommandCounters; + LOG_INFO_MESSAGE( + "Device context stats" + "\n Command counters", + "\n SetPipelineState ", CmdCounters.SetPipelineState, + "\n CommitShaderResources ", CmdCounters.CommitShaderResources, + "\n SetVertexBuffers ", CmdCounters.SetVertexBuffers, + "\n SetIndexBuffer ", CmdCounters.SetIndexBuffer, + "\n SetRenderTargets ", CmdCounters.SetRenderTargets, + "\n SetBlendFactors ", CmdCounters.SetBlendFactors, + "\n SetStencilRef ", CmdCounters.SetStencilRef, + "\n SetViewports ", CmdCounters.SetViewports, + "\n SetScissorRects ", CmdCounters.SetScissorRects, + "\n ClearRenderTarget ", CmdCounters.ClearRenderTarget, + "\n ClearDepthStencil ", CmdCounters.ClearDepthStencil, + "\n Draw ", CmdCounters.Draw, + "\n DrawIndexed ", CmdCounters.DrawIndexed, + "\n DrawIndirect ", CmdCounters.DrawIndirect, + "\n DrawIndexedIndirect ", CmdCounters.DrawIndexedIndirect, + "\n DispatchCompute ", CmdCounters.DispatchCompute, + "\n DispatchComputeIndirect ", CmdCounters.DispatchComputeIndirect, + "\n DispatchTile ", CmdCounters.DispatchTile, + "\n DrawMesh ", CmdCounters.DrawMesh, + "\n DrawMeshIndirect ", CmdCounters.DrawMeshIndirect, + "\n BuildBLAS ", CmdCounters.BuildBLAS, + "\n BuildTLAS ", CmdCounters.BuildTLAS, + "\n CopyBLAS ", CmdCounters.CopyBLAS, + "\n CopyTLAS ", CmdCounters.CopyTLAS, + "\n WriteBLASCompactedSize ", CmdCounters.WriteBLASCompactedSize, + "\n WriteTLASCompactedSize ", CmdCounters.WriteTLASCompactedSize, + "\n TraceRays ", CmdCounters.TraceRays, + "\n TraceRaysIndirect ", CmdCounters.TraceRaysIndirect, + "\n UpdateSBT ", CmdCounters.UpdateSBT, + "\n UpdateBuffer ", CmdCounters.UpdateBuffer, + "\n CopyBuffer ", CmdCounters.CopyBuffer, + "\n MapBuffer ", CmdCounters.MapBuffer, + "\n UpdateTexture ", CmdCounters.UpdateTexture, + "\n CopyTexture ", CmdCounters.CopyTexture, + "\n MapTextureSubresource ", CmdCounters.MapTextureSubresource, + "\n BeginQuery ", CmdCounters.BeginQuery, + "\n GenerateMips ", CmdCounters.GenerateMips, + "\n ResolveTextureSubresource ", CmdCounters.ResolveTextureSubresource, + "\n BindSparseResourceMemory ", CmdCounters.BindSparseResourceMemory, + "\n Primitives", + "\n TRIANGLE_LIST ", Stats.PrimitiveCounts[PRIMITIVE_TOPOLOGY_TRIANGLE_LIST], + "\n TRIANGLE_STRIP ", Stats.PrimitiveCounts[PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP], + "\n POINT_LIST ", Stats.PrimitiveCounts[PRIMITIVE_TOPOLOGY_POINT_LIST], + "\n LINE_LIST ", Stats.PrimitiveCounts[PRIMITIVE_TOPOLOGY_LINE_LIST], + "\n LINE_STRIP ", Stats.PrimitiveCounts[PRIMITIVE_TOPOLOGY_LINE_STRIP], + "\n 1_CONTROL_POINT_PATCHLIST ", Stats.PrimitiveCounts[PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST]); + } } } diff --git a/Tests/IncludeTest/GraphicsEngine/DeviceContextH_test.c b/Tests/IncludeTest/GraphicsEngine/DeviceContextH_test.c index 8401fc98d..eb7fba4d9 100644 --- a/Tests/IncludeTest/GraphicsEngine/DeviceContextH_test.c +++ b/Tests/IncludeTest/GraphicsEngine/DeviceContextH_test.c @@ -121,4 +121,8 @@ void TestDeviceContextCInterface(struct IDeviceContext* pCtx) IDeviceContext_SetShadingRate(pCtx, SHADING_RATE_1X1, SHADING_RATE_COMBINER_PASSTHROUGH, SHADING_RATE_COMBINER_PASSTHROUGH); IDeviceContext_BindSparseResourceMemory(pCtx, (const BindSparseResourceMemoryAttribs*)NULL); + + IDeviceContext_ClearStats(pCtx); + const struct DeviceContextStats* pStats = IDeviceContext_GetStats(pCtx); + (void)pStats; }