diff --git a/renderdoc/api/replay/data_types.h b/renderdoc/api/replay/data_types.h index 42510ec85..f7e50bc94 100644 --- a/renderdoc/api/replay/data_types.h +++ b/renderdoc/api/replay/data_types.h @@ -134,6 +134,115 @@ struct DebugMessage rdctype::str description; }; +enum BucketRecordType +{ + BUCKET_RECORD_TYPE_LINEAR, + BUCKET_RECORD_TYPE_POW2, + + BUCKET_RECORD_TYPE_COUNT, +}; + +struct FetchFrameConstantBindStats +{ + enum Constants + { + BUCKET_TYPE = BUCKET_RECORD_TYPE_POW2, + BUCKET_COUNT = 31, + }; + uint32_t calls; + uint32_t sets; + uint32_t nulls; + rdctype::array slots; + rdctype::array sizes; +}; + +struct FetchFrameSamplerBindStats +{ + uint32_t calls; + uint32_t sets; + uint32_t nulls; + rdctype::array slots; +}; + +struct FetchFrameResourceBindStats +{ + uint32_t calls; + uint32_t sets; + uint32_t nulls; + rdctype::array types; + rdctype::array slots; +}; + +struct FetchFrameUpdateStats +{ + enum Constants + { + BUCKET_TYPE = BUCKET_RECORD_TYPE_POW2, + BUCKET_COUNT = 31, + }; + uint32_t calls; + uint32_t clients; + uint32_t servers; + rdctype::array types; + rdctype::array sizes; +}; + +struct FetchFrameDrawStats +{ + enum Constants + { + BUCKET_TYPE = BUCKET_RECORD_TYPE_LINEAR, + BUCKET_SIZE = 1, + BUCKET_COUNT = 16, + }; + uint32_t calls; + uint32_t instanced; + uint32_t indirect; + rdctype::array counts; +}; + +struct FetchFrameDispatchStats +{ + uint32_t calls; + uint32_t indirect; +}; + +struct FetchFrameIndexBindStats +{ + uint32_t calls; + uint32_t sets; + uint32_t nulls; +}; + +struct FetchFrameVertexBindStats +{ + uint32_t calls; + uint32_t sets; + uint32_t nulls; + rdctype::array slots; +}; + +struct FetchFrameLayoutBindStats +{ + uint32_t calls; + uint32_t sets; + uint32_t nulls; +}; + +struct FetchFrameStatistics +{ + uint32_t recorded; + FetchFrameConstantBindStats constants[eShaderStage_Count]; + FetchFrameSamplerBindStats samplers[eShaderStage_Count]; + FetchFrameResourceBindStats resources[eShaderStage_Count]; + FetchFrameUpdateStats updates; + FetchFrameDrawStats draws; + FetchFrameDispatchStats dispatches; + FetchFrameIndexBindStats indices; + FetchFrameVertexBindStats vertices; + FetchFrameLayoutBindStats layouts; +}; + struct FetchFrameInfo { uint32_t frameNumber; @@ -141,6 +250,7 @@ struct FetchFrameInfo uint64_t fileOffset; uint64_t captureTime; ResourceId immContextId; + FetchFrameStatistics stats; rdctype::array debugMessages; }; diff --git a/renderdoc/api/replay/replay_enums.h b/renderdoc/api/replay/replay_enums.h index 8714f82cd..1110454a8 100644 --- a/renderdoc/api/replay/replay_enums.h +++ b/renderdoc/api/replay/replay_enums.h @@ -73,6 +73,7 @@ enum ShaderResourceType eResType_Texture3D, eResType_TextureCube, eResType_TextureCubeArray, + eResType_Count, }; enum ShaderBindType @@ -286,6 +287,7 @@ enum TextureCreationFlags enum ShaderStageType { eShaderStage_Vertex = 0, + eShaderStage_First = eShaderStage_Vertex, eShaderStage_Hull, eShaderStage_Tess_Control = eShaderStage_Hull, @@ -299,6 +301,8 @@ enum ShaderStageType eShaderStage_Fragment = eShaderStage_Pixel, eShaderStage_Compute, + + eShaderStage_Count, }; enum ShaderStageBits diff --git a/renderdoc/common/common.cpp b/renderdoc/common/common.cpp index 390bfc4fa..9894b64ad 100644 --- a/renderdoc/common/common.cpp +++ b/renderdoc/common/common.cpp @@ -239,6 +239,20 @@ uint32_t CalcNumMips(int w, int h, int d) return mipLevels; } +uint32_t Log2Floor(uint32_t value) +{ + RDCASSERT(value > 0); + return 31 - Bits::CountLeadingZeroes(value); +} + +#if RDC64BIT +uint64_t Log2Floor(uint64_t value) +{ + RDCASSERT(value > 0); + return 63 - Bits::CountLeadingZeroes(value); +} +#endif + static string &logfile() { static string fn; diff --git a/renderdoc/common/common.h b/renderdoc/common/common.h index b90f06577..3654c411e 100644 --- a/renderdoc/common/common.h +++ b/renderdoc/common/common.h @@ -95,6 +95,11 @@ inline T AlignUpPtr(T x, A a) { return (T)AlignUp( (uintptr_t)x, (uin bool FindDiffRange(void *a, void *b, size_t bufSize, size_t &diffStart, size_t &diffEnd); uint32_t CalcNumMips(int Width, int Height, int Depth); +uint32_t Log2Floor(uint32_t value); +#if RDC64BIT +uint64_t Log2Floor(uint64_t value); +#endif + ///////////////////////////////////////////////// // Debugging features diff --git a/renderdoc/common/globalconfig.h b/renderdoc/common/globalconfig.h index 71c3b7514..dd6da35a3 100644 --- a/renderdoc/common/globalconfig.h +++ b/renderdoc/common/globalconfig.h @@ -26,6 +26,12 @@ #pragma once +///////////////////////////////////////////////// +// Build/machine configuration +#if defined(__LP64__) || defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) +#define RDC64BIT 1 +#endif + ///////////////////////////////////////////////// // Global constants enum diff --git a/renderdoc/core/replay_proxy.cpp b/renderdoc/core/replay_proxy.cpp index c1dc1bf29..5ecab69cb 100644 --- a/renderdoc/core/replay_proxy.cpp +++ b/renderdoc/core/replay_proxy.cpp @@ -1049,6 +1049,128 @@ void Serialiser::Serialise(const char *name, FetchDrawcall &el) SIZE_CHECK(FetchDrawcall, 216); } +template<> +void Serialiser::Serialise(const char *name, FetchFrameConstantBindStats &el) +{ + Serialise("", el.calls); + Serialise("", el.sets); + Serialise("", el.nulls); + Serialise("", el.slots); + Serialise("", el.sizes); + + SIZE_CHECK(FetchFrameConstantBindStats, 28); +} + +template<> +void Serialiser::Serialise(const char *name, FetchFrameSamplerBindStats &el) +{ + Serialise("", el.calls); + Serialise("", el.sets); + Serialise("", el.nulls); + Serialise("", el.slots); + + SIZE_CHECK(FetchFrameSamplerBindStats, 20); +} + +template<> +void Serialiser::Serialise(const char *name, FetchFrameResourceBindStats &el) +{ + Serialise("", el.calls); + Serialise("", el.sets); + Serialise("", el.nulls); + Serialise("", el.types); + Serialise("", el.slots); + + SIZE_CHECK(FetchFrameResourceBindStats, 28); +} + +template<> +void Serialiser::Serialise(const char *name, FetchFrameUpdateStats &el) +{ + Serialise("", el.calls); + Serialise("", el.clients); + Serialise("", el.servers); + Serialise("", el.types); + Serialise("", el.sizes); + + SIZE_CHECK(FetchFrameUpdateStats, 28); +} + +template<> +void Serialiser::Serialise(const char *name, FetchFrameDrawStats &el) +{ + Serialise("", el.calls); + Serialise("", el.instanced); + Serialise("", el.indirect); + Serialise("", el.counts); + + SIZE_CHECK(FetchFrameDrawStats, 20); +} + +template<> +void Serialiser::Serialise(const char *name, FetchFrameDispatchStats &el) +{ + Serialise("", el.calls); + Serialise("", el.indirect); + + SIZE_CHECK(FetchFrameDispatchStats, 8); +} + +template<> +void Serialiser::Serialise(const char *name, FetchFrameIndexBindStats &el) +{ + Serialise("", el.calls); + Serialise("", el.sets); + Serialise("", el.nulls); + + SIZE_CHECK(FetchFrameIndexBindStats, 12); +} + +template<> +void Serialiser::Serialise(const char *name, FetchFrameVertexBindStats &el) +{ + Serialise("", el.calls); + Serialise("", el.sets); + Serialise("", el.nulls); + Serialise("", el.slots); + + SIZE_CHECK(FetchFrameVertexBindStats, 20); +} + +template<> +void Serialiser::Serialise(const char *name, FetchFrameLayoutBindStats &el) +{ + Serialise("", el.calls); + Serialise("", el.sets); + Serialise("", el.nulls); + + SIZE_CHECK(FetchFrameLayoutBindStats, 12); +} + +template<> +void Serialiser::Serialise(const char *name, FetchFrameStatistics &el) +{ + Serialise("", el.recorded); + // #mivance note this is technically error-prone from the perspective + // that we're passing references to pointers, but as we're really + // dealing with arrays,t hey'll never be NULL and need to be assigned + // to, so this is fine + FetchFrameConstantBindStats* constants = el.constants; + SerialiseComplexArray("", constants); + FetchFrameSamplerBindStats* samplers = el.samplers; + SerialiseComplexArray("", samplers); + FetchFrameResourceBindStats* resources = el.resources; + SerialiseComplexArray("", resources); + Serialise("", el.updates); + Serialise("", el.draws); + Serialise("", el.dispatches); + Serialise("", el.indices); + Serialise("", el.vertices); + Serialise("", el.layouts); + + SIZE_CHECK(FetchFrameStatistics, 560); +} + template<> void Serialiser::Serialise(const char *name, FetchFrameInfo &el) { @@ -1057,9 +1179,10 @@ void Serialiser::Serialise(const char *name, FetchFrameInfo &el) Serialise("", el.fileOffset); Serialise("", el.captureTime); Serialise("", el.immContextId); + Serialise("", el.stats); Serialise("", el.debugMessages); - SIZE_CHECK(FetchFrameInfo, 40); + SIZE_CHECK(FetchFrameInfo, 600); } template<> @@ -1068,7 +1191,7 @@ void Serialiser::Serialise(const char *name, FetchFrameRecord &el) Serialise("", el.frameInfo); Serialise("", el.drawcallList); - SIZE_CHECK(FetchFrameRecord, 56); + SIZE_CHECK(FetchFrameRecord, 616); } template<> diff --git a/renderdoc/driver/d3d11/d3d11_context.cpp b/renderdoc/driver/d3d11/d3d11_context.cpp index 4141d8ba4..627c544ea 100644 --- a/renderdoc/driver/d3d11/d3d11_context.cpp +++ b/renderdoc/driver/d3d11/d3d11_context.cpp @@ -1385,3 +1385,205 @@ HRESULT STDMETHODCALLTYPE WrappedID3D11DeviceContext::QueryInterface( REFIID rii return RefCounter::QueryInterface(riid, ppvObject); } + +#pragma region Record Statistics + +void WrappedID3D11DeviceContext::RecordIndexBindStats(ID3D11Buffer* Buffer) +{ + FetchFrameRecord& record = m_pDevice->GetFrameRecord().back(); + FetchFrameStatistics& stats = record.frameInfo.stats; + FetchFrameIndexBindStats& indices = stats.indices; + indices.calls += 1; + indices.sets += (Buffer != NULL); + indices.nulls += (Buffer == NULL); +} + +void WrappedID3D11DeviceContext::RecordVertexBindStats(UINT NumBuffers, ID3D11Buffer* Buffers[]) +{ + FetchFrameRecord& record = m_pDevice->GetFrameRecord().back(); + FetchFrameStatistics& stats = record.frameInfo.stats; + FetchFrameVertexBindStats& vertices = stats.vertices; + vertices.calls += 1; + RDCASSERT(NumBuffers < vertices.slots.size()); + vertices.slots[NumBuffers] += 1; + + for (UINT i = 0; i < NumBuffers; i++) + { + if (Buffers[i]) + vertices.sets += 1; + else + vertices.nulls += 1; + } +} + +void WrappedID3D11DeviceContext::RecordLayoutBindStats(ID3D11InputLayout* Layout) +{ + FetchFrameRecord& record = m_pDevice->GetFrameRecord().back(); + FetchFrameStatistics& stats = record.frameInfo.stats; + FetchFrameLayoutBindStats& layouts = stats.layouts; + layouts.calls += 1; + layouts.sets += (Layout != NULL); + layouts.nulls += (Layout == NULL); +} + +void WrappedID3D11DeviceContext::RecordConstantStats(ShaderStageType stage, UINT NumBuffers, ID3D11Buffer* Buffers[]) +{ + FetchFrameRecord& record = m_pDevice->GetFrameRecord().back(); + FetchFrameStatistics& stats = record.frameInfo.stats; + RDCASSERT(stage < ARRAY_COUNT( stats.constants)); + FetchFrameConstantBindStats& constants = stats.constants[stage]; + constants.calls += 1; + RDCASSERT(NumBuffers < constants.slots.size()); + constants.slots[NumBuffers] += 1; + + for (UINT i = 0; i < NumBuffers; i++) + { + if (Buffers[i]) + { + constants.sets += 1; + + D3D11_BUFFER_DESC desc; + Buffers[i]->GetDesc(&desc); + uint32_t bufferSize = desc.ByteWidth; + size_t bucket = BucketForRecordPow2(bufferSize); + RDCASSERT(bucket < constants.sizes.size()); + constants.sizes[bucket] += 1; + } + else + { + constants.nulls += 1; + } + } +} + +void WrappedID3D11DeviceContext::RecordResourceStats(ShaderStageType stage, UINT NumResources, ID3D11ShaderResourceView* Resources[]) +{ + FetchFrameRecord& record = m_pDevice->GetFrameRecord().back(); + FetchFrameStatistics& stats = record.frameInfo.stats; + RDCASSERT(stage < ARRAY_COUNT(stats.resources)); + FetchFrameResourceBindStats& resources = stats.resources[stage]; + resources.calls += 1; + RDCASSERT(NumResources < resources.slots.size()); + resources.slots[NumResources] += 1; + + const ShaderResourceType mapping[] = { + eResType_None, + eResType_Buffer, + eResType_Texture1D, + eResType_Texture1DArray, + eResType_Texture2D, + eResType_Texture2DArray, + eResType_Texture2DMS, + eResType_Texture2DMSArray, + eResType_Texture3D, + eResType_TextureCube, + eResType_TextureCubeArray, + eResType_Buffer, + }; + RDCCOMPILE_ASSERT(ARRAY_COUNT(mapping) == D3D_SRV_DIMENSION_BUFFEREX + 1, "Update mapping table."); + + for (UINT i = 0; i < NumResources; i++) + { + if (Resources[i]) + { + resources.sets += 1; + + D3D11_SHADER_RESOURCE_VIEW_DESC desc; + Resources[i]->GetDesc(&desc); + RDCASSERT(desc.ViewDimension < ARRAY_COUNT(mapping)); + ShaderResourceType type = mapping[desc.ViewDimension]; + // #mivance surprisingly this is not asserted in operator[] for + // rdctype::array so I'm being paranoid + RDCASSERT((int)type < (int)resources.types.size()); + resources.types[type] += 1; + } + else + { + resources.nulls += 1; + } + } +} + +void WrappedID3D11DeviceContext::RecordSamplerStats(ShaderStageType stage, UINT NumSamplers, ID3D11SamplerState* Samplers[]) +{ + FetchFrameRecord& record = m_pDevice->GetFrameRecord().back(); + FetchFrameStatistics& stats = record.frameInfo.stats; + RDCASSERT(stage < ARRAY_COUNT(stats.samplers)); + FetchFrameSamplerBindStats& samplers = stats.samplers[stage]; + samplers.calls += 1; + RDCASSERT(NumSamplers < samplers.slots.size()); + samplers.slots[NumSamplers] += 1; + + for (UINT i = 0; i < NumSamplers; i++) + { + if (Samplers[i]) + samplers.sets += 1; + else + samplers.nulls += 1; + } +} + +void WrappedID3D11DeviceContext::RecordUpdateStats(ID3D11Resource* res, uint32_t Size, bool Server) +{ + FetchFrameRecord& record = m_pDevice->GetFrameRecord().back(); + FetchFrameStatistics& stats = record.frameInfo.stats; + FetchFrameUpdateStats& updates = stats.updates; + + if (res == NULL) + return; + + updates.calls += 1; + updates.clients += (Server == false); + updates.servers += (Server == true); + + const ShaderResourceType mapping[] = { + eResType_None, // D3D11_RESOURCE_DIMENSION_UNKNOWN = 0, + eResType_Buffer, // D3D11_RESOURCE_DIMENSION_BUFFER = 1, + eResType_Texture1D, // D3D11_RESOURCE_DIMENSION_TEXTURE1D = 2, + eResType_Texture2D, // D3D11_RESOURCE_DIMENSION_TEXTURE2D = 3, + eResType_Texture3D, // D3D11_RESOURCE_DIMENSION_TEXTURE3D = 4 + }; + + D3D11_RESOURCE_DIMENSION dim; + res->GetType(&dim); + RDCASSERT(dim < ARRAY_COUNT(mapping)); + ShaderResourceType type = mapping[dim]; + RDCASSERT((int)type < (int)updates.types.size()); + updates.types[type] += 1; + + // #mivance it might be nice to query the buffer to differentiate + // between bindings for constant buffers + + size_t bucket = BucketForRecordPow2( Size ); + updates.sizes[bucket] += 1; +} + +void WrappedID3D11DeviceContext::RecordDrawStats(bool instanced, bool indirect, UINT InstanceCount) +{ + FetchFrameRecord& record = m_pDevice->GetFrameRecord().back(); + FetchFrameStatistics& stats = record.frameInfo.stats; + FetchFrameDrawStats& draws = stats.draws; + + draws.calls += 1; + draws.instanced += (uint32_t)instanced; + draws.indirect += (uint32_t)indirect; + + if (instanced) + { + size_t bucket = BucketForRecordLinear(InstanceCount); + RDCASSERT(bucket < draws.counts.size()); + draws.counts[bucket] += 1; + } +} + +void WrappedID3D11DeviceContext::RecordDispatchStats(bool indirect) +{ + FetchFrameRecord& record = m_pDevice->GetFrameRecord().back(); + FetchFrameStatistics& stats = record.frameInfo.stats; + FetchFrameDispatchStats& dispatches = stats.dispatches; + + dispatches.calls += 1; + dispatches.indirect += (uint32_t)indirect; +} + +#pragma endregion diff --git a/renderdoc/driver/d3d11/d3d11_context.h b/renderdoc/driver/d3d11/d3d11_context.h index 74f553a9f..24292138d 100644 --- a/renderdoc/driver/d3d11/d3d11_context.h +++ b/renderdoc/driver/d3d11/d3d11_context.h @@ -124,6 +124,28 @@ struct DrawcallTreeNode } }; +template +size_t BucketForRecordLinear(size_t value) +{ + RDCCOMPILE_ASSERT( T::BUCKET_TYPE == BUCKET_RECORD_TYPE_LINEAR, "Incorrect bucket type for record query." ); + const size_t size = T::BUCKET_SIZE; + const size_t count = T::BUCKET_COUNT; + const size_t maximum = size * count; + const size_t index = (value < maximum) ? (value / size) : (count - 1); + return index; +} + +template +size_t BucketForRecordPow2(size_t value) +{ + RDCCOMPILE_ASSERT( T::BUCKET_TYPE == BUCKET_RECORD_TYPE_POW2, "Incorrect bucket type for record query." ); + const size_t count = T::BUCKET_COUNT; + RDCCOMPILE_ASSERT(count <= (sizeof(size_t) * 8), "Unexpected correspondence between bucket size and sizeof(size_t)"); + const size_t maximum = (size_t)1 << count; + const size_t index = (value < maximum) ? (size_t)(Log2Floor(value)) : (count - 1); + return index; +} + class WrappedID3D11DeviceContext : public RefCounter, public ID3D11DeviceContext2 { private: @@ -222,6 +244,16 @@ private: void AddDrawcall(FetchDrawcall draw, bool hasEvents); void RefreshDrawcallIDs(DrawcallTreeNode &node); + void RecordIndexBindStats(ID3D11Buffer* Buffer); + void RecordVertexBindStats(UINT NumBuffers, ID3D11Buffer* Buffers[]); + void RecordLayoutBindStats(ID3D11InputLayout* Layout); + void RecordConstantStats(ShaderStageType stage, UINT NumBuffers, ID3D11Buffer* Buffers[]); + void RecordResourceStats(ShaderStageType stage, UINT NumResources, ID3D11ShaderResourceView* Resources[]); + void RecordSamplerStats(ShaderStageType stage, UINT NumSamplers, ID3D11SamplerState* Samplers[]); + void RecordUpdateStats(ID3D11Resource* res, uint32_t Size, bool Server); + void RecordDrawStats(bool instanced, bool indirect, UINT InstanceCount); + void RecordDispatchStats(bool indirect); + //////////////////////////////////////////////////////////////// // implement InterceptorSystem privately, since it is not thread safe (like all other context functions) IMPLEMENT_FUNCTION_SERIALISED(void, SetMarker(uint32_t col, const wchar_t *name)); diff --git a/renderdoc/driver/d3d11/d3d11_context1_wrap.cpp b/renderdoc/driver/d3d11/d3d11_context1_wrap.cpp index 1c54af644..83beb92f7 100644 --- a/renderdoc/driver/d3d11/d3d11_context1_wrap.cpp +++ b/renderdoc/driver/d3d11/d3d11_context1_wrap.cpp @@ -137,6 +137,9 @@ bool WrappedID3D11DeviceContext::Serialise_UpdateSubresource1(ID3D11Resource *pD if(HasDestBox) pBox = &box; + if(m_State == READING) + RecordUpdateStats(DestResource, SourceDataLength, true); + if(flags == 0) { m_pRealContext->UpdateSubresource(m_pDevice->GetResourceManager()->UnwrapResource(DestResource), DestSubresource, pBox, @@ -223,6 +226,9 @@ bool WrappedID3D11DeviceContext::Serialise_UpdateSubresource1(ID3D11Resource *pD UINT SourceRowPitch = GetByteSize(subWidth, 1, 1, fmt, 0); UINT SourceDepthPitch = GetByteSize(subWidth, subHeight, 1, fmt, 0); + if(m_State == READING) + RecordUpdateStats(DestResource, SourceRowPitch * subHeight + SourceDepthPitch * subWidth * subHeight, true); + if(flags == 0) { m_pRealContext->UpdateSubresource(m_pDevice->GetResourceManager()->UnwrapResource(DestResource), DestSubresource, NULL, diff --git a/renderdoc/driver/d3d11/d3d11_context_wrap.cpp b/renderdoc/driver/d3d11/d3d11_context_wrap.cpp index 65b72e8da..ec50000bd 100644 --- a/renderdoc/driver/d3d11/d3d11_context_wrap.cpp +++ b/renderdoc/driver/d3d11/d3d11_context_wrap.cpp @@ -342,6 +342,10 @@ bool WrappedID3D11DeviceContext::Serialise_IASetInputLayout(ID3D11InputLayout *p pInputLayout = NULL; if(m_pDevice->GetResourceManager()->HasLiveResource(InputLayout)) pInputLayout = (ID3D11InputLayout *)m_pDevice->GetResourceManager()->GetLiveResource(InputLayout); + + if(m_State == READING) + RecordLayoutBindStats(pInputLayout); + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->IA.Layout, pInputLayout); m_pRealContext->IASetInputLayout(UNWRAP(WrappedID3D11InputLayout, pInputLayout)); VerifyState(); @@ -404,6 +408,9 @@ bool WrappedID3D11DeviceContext::Serialise_IASetVertexBuffers(UINT StartSlot_, U if(m_State <= EXECUTING) { + if(m_State == READING) + RecordVertexBindStats(NumBuffers, Buffers); + m_CurrentPipelineState->Change(m_CurrentPipelineState->IA.Strides, Strides, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->IA.Offsets, Offsets, StartSlot, NumBuffers); m_pRealContext->IASetVertexBuffers(StartSlot, NumBuffers, Buffers, Strides, Offsets); @@ -459,6 +466,10 @@ bool WrappedID3D11DeviceContext::Serialise_IASetIndexBuffer(ID3D11Buffer *pIndex pIndexBuffer = NULL; if(m_pDevice->GetResourceManager()->HasLiveResource(Buffer)) pIndexBuffer = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetLiveResource(Buffer); + + if(m_State == READING) + RecordIndexBindStats(pIndexBuffer); + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->IA.IndexBuffer, pIndexBuffer); m_CurrentPipelineState->Change(m_CurrentPipelineState->IA.IndexFormat, Format); m_CurrentPipelineState->Change(m_CurrentPipelineState->IA.IndexOffset, Offset); @@ -619,6 +630,9 @@ bool WrappedID3D11DeviceContext::Serialise_VSSetConstantBuffers(UINT StartSlot_, for(UINT i=0; i < NumBuffers; i++) Buffers[i] = UNWRAP(WrappedID3D11Buffer, Buffers[i]); + if(m_State == READING) + RecordConstantStats(eShaderStage_Vertex, NumBuffers, Buffers); + m_pRealContext->VSSetConstantBuffers(StartSlot, NumBuffers, Buffers); VerifyState(); } @@ -682,6 +696,9 @@ bool WrappedID3D11DeviceContext::Serialise_VSSetShaderResources(UINT StartSlot_, for(UINT i=0; i < NumViews; i++) Views[i] = UNWRAP(WrappedID3D11ShaderResourceView, Views[i]); + if(m_State == READING) + RecordResourceStats(eShaderStage_Vertex, NumViews, Views); + m_pRealContext->VSSetShaderResources(StartSlot, NumViews, Views); VerifyState(); } @@ -732,30 +749,33 @@ bool WrappedID3D11DeviceContext::Serialise_VSSetSamplers(UINT StartSlot_, UINT N SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); SERIALISE_ELEMENT(uint32_t, NumSamplers, NumSamplers_); - ID3D11SamplerState **Sampler = new ID3D11SamplerState *[NumSamplers]; + ID3D11SamplerState **Samplers = new ID3D11SamplerState *[NumSamplers]; for(UINT i=0; i < NumSamplers; i++) { SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppSamplers[i])); if(m_State <= EXECUTING && m_pDevice->GetResourceManager()->HasLiveResource(id)) - Sampler[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetLiveResource(id); + Samplers[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetLiveResource(id); else - Sampler[i] = NULL; + Samplers[i] = NULL; } if(m_State <= EXECUTING) { - m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->VS.Samplers, Sampler, StartSlot, NumSamplers); + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->VS.Samplers, Samplers, StartSlot, NumSamplers); for(UINT i=0; i < NumSamplers; i++) - Sampler[i] = UNWRAP(WrappedID3D11SamplerState, Sampler[i]); + Samplers[i] = UNWRAP(WrappedID3D11SamplerState, Samplers[i]); - m_pRealContext->VSSetSamplers(StartSlot, NumSamplers, Sampler); + if(m_State == READING) + RecordSamplerStats(eShaderStage_Vertex, NumSamplers, Samplers); + + m_pRealContext->VSSetSamplers(StartSlot, NumSamplers, Samplers); VerifyState(); } - SAFE_DELETE_ARRAY(Sampler); + SAFE_DELETE_ARRAY(Samplers); return true; } @@ -978,6 +998,9 @@ bool WrappedID3D11DeviceContext::Serialise_HSSetConstantBuffers(UINT StartSlot_, for(UINT i=0; i < NumBuffers; i++) Buffers[i] = UNWRAP(WrappedID3D11Buffer, Buffers[i]); + if(m_State == READING) + RecordConstantStats(eShaderStage_Hull, NumBuffers, Buffers); + if(m_State <= EXECUTING) m_pRealContext->HSSetConstantBuffers(StartSlot, NumBuffers, Buffers); VerifyState(); @@ -1044,6 +1067,9 @@ bool WrappedID3D11DeviceContext::Serialise_HSSetShaderResources(UINT StartSlot_, for(UINT i=0; i < NumViews; i++) Views[i] = UNWRAP(WrappedID3D11ShaderResourceView, Views[i]); + if(m_State == READING) + RecordResourceStats(eShaderStage_Hull, NumViews, Views); + m_pRealContext->HSSetShaderResources(StartSlot, NumViews, Views); VerifyState(); } @@ -1094,30 +1120,33 @@ bool WrappedID3D11DeviceContext::Serialise_HSSetSamplers(UINT StartSlot_, UINT N SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); SERIALISE_ELEMENT(uint32_t, NumSamplers, NumSamplers_); - ID3D11SamplerState **Sampler = new ID3D11SamplerState *[NumSamplers]; + ID3D11SamplerState **Samplers = new ID3D11SamplerState *[NumSamplers]; for(UINT i=0; i < NumSamplers; i++) { SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppSamplers[i])); if(m_State <= EXECUTING && m_pDevice->GetResourceManager()->HasLiveResource(id)) - Sampler[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetLiveResource(id); + Samplers[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetLiveResource(id); else - Sampler[i] = NULL; + Samplers[i] = NULL; } if(m_State <= EXECUTING) { - m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->HS.Samplers, Sampler, StartSlot, NumSamplers); + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->HS.Samplers, Samplers, StartSlot, NumSamplers); for(UINT i=0; i < NumSamplers; i++) - Sampler[i] = UNWRAP(WrappedID3D11SamplerState, Sampler[i]); + Samplers[i] = UNWRAP(WrappedID3D11SamplerState, Samplers[i]); - m_pRealContext->HSSetSamplers(StartSlot, NumSamplers, Sampler); + if(m_State == READING) + RecordSamplerStats(eShaderStage_Hull, NumSamplers, Samplers); + + m_pRealContext->HSSetSamplers(StartSlot, NumSamplers, Samplers); VerifyState(); } - SAFE_DELETE_ARRAY(Sampler); + SAFE_DELETE_ARRAY(Samplers); return true; } @@ -1340,6 +1369,9 @@ bool WrappedID3D11DeviceContext::Serialise_DSSetConstantBuffers(UINT StartSlot_, for(UINT i=0; i < NumBuffers; i++) Buffers[i] = UNWRAP(WrappedID3D11Buffer, Buffers[i]); + if(m_State == READING) + RecordConstantStats(eShaderStage_Domain, NumBuffers, Buffers); + m_pRealContext->DSSetConstantBuffers(StartSlot, NumBuffers, Buffers); VerifyState(); } @@ -1405,6 +1437,9 @@ bool WrappedID3D11DeviceContext::Serialise_DSSetShaderResources(UINT StartSlot_, for(UINT i=0; i < NumViews; i++) Views[i] = UNWRAP(WrappedID3D11ShaderResourceView, Views[i]); + if(m_State == READING) + RecordResourceStats(eShaderStage_Domain, NumViews, Views); + m_pRealContext->DSSetShaderResources(StartSlot, NumViews, Views); VerifyState(); } @@ -1455,30 +1490,33 @@ bool WrappedID3D11DeviceContext::Serialise_DSSetSamplers(UINT StartSlot_, UINT N SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); SERIALISE_ELEMENT(uint32_t, NumSamplers, NumSamplers_); - ID3D11SamplerState **Sampler = new ID3D11SamplerState *[NumSamplers]; + ID3D11SamplerState **Samplers = new ID3D11SamplerState *[NumSamplers]; for(UINT i=0; i < NumSamplers; i++) { SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppSamplers[i])); if(m_State <= EXECUTING && m_pDevice->GetResourceManager()->HasLiveResource(id)) - Sampler[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetLiveResource(id); + Samplers[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetLiveResource(id); else - Sampler[i] = NULL; + Samplers[i] = NULL; } if(m_State <= EXECUTING) { - m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->DS.Samplers, Sampler, StartSlot, NumSamplers); + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->DS.Samplers, Samplers, StartSlot, NumSamplers); for(UINT i=0; i < NumSamplers; i++) - Sampler[i] = UNWRAP(WrappedID3D11SamplerState, Sampler[i]); + Samplers[i] = UNWRAP(WrappedID3D11SamplerState, Samplers[i]); - m_pRealContext->DSSetSamplers(StartSlot, NumSamplers, Sampler); + if(m_State == READING) + RecordSamplerStats(eShaderStage_Domain, NumSamplers, Samplers); + + m_pRealContext->DSSetSamplers(StartSlot, NumSamplers, Samplers); VerifyState(); } - SAFE_DELETE_ARRAY(Sampler); + SAFE_DELETE_ARRAY(Samplers); return true; } @@ -1701,6 +1739,9 @@ bool WrappedID3D11DeviceContext::Serialise_GSSetConstantBuffers(UINT StartSlot_, for(UINT i=0; i < NumBuffers; i++) Buffers[i] = UNWRAP(WrappedID3D11Buffer, Buffers[i]); + if(m_State == READING) + RecordConstantStats(eShaderStage_Geometry, NumBuffers, Buffers); + m_pRealContext->GSSetConstantBuffers(StartSlot, NumBuffers, Buffers); VerifyState(); } @@ -1766,6 +1807,9 @@ bool WrappedID3D11DeviceContext::Serialise_GSSetShaderResources(UINT StartSlot_, for(UINT i=0; i < NumViews; i++) Views[i] = UNWRAP(WrappedID3D11ShaderResourceView, Views[i]); + if(m_State == READING) + RecordResourceStats(eShaderStage_Geometry, NumViews, Views); + m_pRealContext->GSSetShaderResources(StartSlot, NumViews, Views); VerifyState(); } @@ -1816,30 +1860,33 @@ bool WrappedID3D11DeviceContext::Serialise_GSSetSamplers(UINT StartSlot_, UINT N SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); SERIALISE_ELEMENT(uint32_t, NumSamplers, NumSamplers_); - ID3D11SamplerState **Sampler = new ID3D11SamplerState *[NumSamplers]; + ID3D11SamplerState **Samplers = new ID3D11SamplerState *[NumSamplers]; for(UINT i=0; i < NumSamplers; i++) { SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppSamplers[i])); if(m_State <= EXECUTING && m_pDevice->GetResourceManager()->HasLiveResource(id)) - Sampler[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetLiveResource(id); + Samplers[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetLiveResource(id); else - Sampler[i] = NULL; + Samplers[i] = NULL; } if(m_State <= EXECUTING) { - m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->GS.Samplers, Sampler, StartSlot, NumSamplers); + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->GS.Samplers, Samplers, StartSlot, NumSamplers); for(UINT i=0; i < NumSamplers; i++) - Sampler[i] = UNWRAP(WrappedID3D11SamplerState, Sampler[i]); + Samplers[i] = UNWRAP(WrappedID3D11SamplerState, Samplers[i]); - m_pRealContext->GSSetSamplers(StartSlot, NumSamplers, Sampler); + if(m_State == READING) + RecordSamplerStats(eShaderStage_Geometry, NumSamplers, Samplers); + + m_pRealContext->GSSetSamplers(StartSlot, NumSamplers, Samplers); VerifyState(); } - SAFE_DELETE_ARRAY(Sampler); + SAFE_DELETE_ARRAY(Samplers); return true; } @@ -2467,6 +2514,9 @@ bool WrappedID3D11DeviceContext::Serialise_PSSetConstantBuffers(UINT StartSlot_, for(UINT i=0; i < NumBuffers; i++) Buffers[i] = UNWRAP(WrappedID3D11Buffer, Buffers[i]); + if(m_State == READING) + RecordConstantStats(eShaderStage_Pixel, NumBuffers, Buffers); + m_pRealContext->PSSetConstantBuffers(StartSlot, NumBuffers, Buffers); VerifyState(); } @@ -2530,6 +2580,9 @@ bool WrappedID3D11DeviceContext::Serialise_PSSetShaderResources(UINT StartSlot_, for(UINT i=0; i < NumViews; i++) Views[i] = UNWRAP(WrappedID3D11ShaderResourceView, Views[i]); + if(m_State == READING) + RecordResourceStats(eShaderStage_Pixel, NumViews, Views); + m_pRealContext->PSSetShaderResources(StartSlot, NumViews, Views); VerifyState(); } @@ -2578,26 +2631,29 @@ bool WrappedID3D11DeviceContext::Serialise_PSSetSamplers(UINT StartSlot_, UINT N SERIALISE_ELEMENT(uint32_t, StartSlot, StartSlot_); SERIALISE_ELEMENT(uint32_t, NumSamplers, NumSamplers_); - ID3D11SamplerState *Sampler[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT]; + ID3D11SamplerState *Samplers[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT]; for(UINT i=0; i < NumSamplers; i++) { SERIALISE_ELEMENT(ResourceId, id, GetIDForResource(ppSamplers[i])); if(m_State <= EXECUTING && m_pDevice->GetResourceManager()->HasLiveResource(id)) - Sampler[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetLiveResource(id); + Samplers[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetLiveResource(id); else - Sampler[i] = NULL; + Samplers[i] = NULL; } if(m_State <= EXECUTING) { - m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->PS.Samplers, Sampler, StartSlot, NumSamplers); + m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->PS.Samplers, Samplers, StartSlot, NumSamplers); for(UINT i=0; i < NumSamplers; i++) - Sampler[i] = UNWRAP(WrappedID3D11SamplerState, Sampler[i]); + Samplers[i] = UNWRAP(WrappedID3D11SamplerState, Samplers[i]); - m_pRealContext->PSSetSamplers(StartSlot, NumSamplers, Sampler); + if(m_State == READING) + RecordSamplerStats(eShaderStage_Pixel, NumSamplers, Samplers); + + m_pRealContext->PSSetSamplers(StartSlot, NumSamplers, Samplers); VerifyState(); } @@ -3429,6 +3485,9 @@ bool WrappedID3D11DeviceContext::Serialise_DrawIndexedInstanced(UINT IndexCountP if(m_State <= EXECUTING) { + if(m_State == READING) + RecordDrawStats(true, false, InstanceCount); + m_pRealContext->DrawIndexedInstanced(IndexCountPerInstance, InstanceCount, StartIndexLocation, BaseVertexLocation, StartInstanceLocation); } @@ -3492,6 +3551,9 @@ bool WrappedID3D11DeviceContext::Serialise_DrawInstanced(UINT VertexCountPerInst if(m_State <= EXECUTING) { + if(m_State == READING) + RecordDrawStats(true, false, InstanceCount); + m_pRealContext->DrawInstanced(VertexCountPerInstance, InstanceCount, StartVertexLocation, StartInstanceLocation); } @@ -3552,6 +3614,9 @@ bool WrappedID3D11DeviceContext::Serialise_DrawIndexed(UINT IndexCount_, UINT St if(m_State <= EXECUTING) { + if(m_State == READING) + RecordDrawStats(false, false, 1); + m_pRealContext->DrawIndexed(IndexCount, StartIndexLocation, BaseVertexLocation); } @@ -3609,6 +3674,9 @@ bool WrappedID3D11DeviceContext::Serialise_Draw(UINT VertexCount_, UINT StartVer if(m_State <= EXECUTING) { + if(m_State == READING) + RecordDrawStats(false, false, 1); + m_pRealContext->Draw(VertexCount, StartVertexLocation); } @@ -3664,6 +3732,9 @@ bool WrappedID3D11DeviceContext::Serialise_DrawAuto() if(m_State <= EXECUTING) { + if(m_State == READING) + RecordDrawStats(false, false, 1); + // spec says that only the first vertex buffer is used if(m_CurrentPipelineState->IA.VBs[0] == NULL) { @@ -3808,6 +3879,8 @@ bool WrappedID3D11DeviceContext::Serialise_DrawIndexedInstancedIndirect(ID3D11Bu draw.baseVertex = args->BaseVertexLocation; draw.instanceOffset = args->StartInstanceLocation; + RecordDrawStats(true, true, draw.numInstances); + name = "DrawIndexedInstancedIndirect(<" + ToStr::Get(draw.numIndices) + ", " + ToStr::Get(draw.numInstances) + ">)"; } @@ -3885,6 +3958,8 @@ bool WrappedID3D11DeviceContext::Serialise_DrawInstancedIndirect(ID3D11Buffer *p draw.numInstances = uargs[1]; draw.vertexOffset = uargs[2]; draw.instanceOffset = uargs[3]; + + RecordDrawStats(true, true, draw.numInstances); } draw.name = name; @@ -4065,6 +4140,9 @@ bool WrappedID3D11DeviceContext::Serialise_CSSetConstantBuffers(UINT StartSlot_, for(UINT i=0; i < NumBuffers; i++) Buffers[i] = UNWRAP(WrappedID3D11Buffer, Buffers[i]); + if(m_State == READING) + RecordConstantStats(eShaderStage_Compute, NumBuffers, Buffers); + m_pRealContext->CSSetConstantBuffers(StartSlot, NumBuffers, Buffers); VerifyState(); } @@ -4492,6 +4570,9 @@ bool WrappedID3D11DeviceContext::Serialise_Dispatch(UINT ThreadGroupCountX_, UIN if(m_State <= EXECUTING) { + if(m_State == READING) + RecordDispatchStats(false); + m_pRealContext->Dispatch(ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ); } @@ -4562,6 +4643,9 @@ bool WrappedID3D11DeviceContext::Serialise_DispatchIndirect(ID3D11Buffer *pBuffe if(m_State <= EXECUTING && m_pDevice->GetResourceManager()->HasLiveResource(BufferForArgs)) { + if(m_State == READING) + RecordDispatchStats(true); + m_pRealContext->DispatchIndirect(UNWRAP(WrappedID3D11Buffer, m_pDevice->GetResourceManager()->GetLiveResource(BufferForArgs)), AlignedByteOffsetForArgs); } @@ -6971,6 +7055,9 @@ bool WrappedID3D11DeviceContext::Serialise_Unmap(ID3D11Resource *pResource, UINT ID3D11Resource *res = (ID3D11Resource *)m_pDevice->GetResourceManager()->GetLiveResource(mapIdx.resource); + if((m_State == READING) && (DiffStart < DiffEnd)) + RecordUpdateStats(res, DiffEnd - DiffStart, false); + if(DiffStart >= DiffEnd) { // do nothing diff --git a/renderdoc/driver/d3d11/d3d11_device.cpp b/renderdoc/driver/d3d11/d3d11_device.cpp index e9bbf07cf..a024dadf2 100644 --- a/renderdoc/driver/d3d11/d3d11_device.cpp +++ b/renderdoc/driver/d3d11/d3d11_device.cpp @@ -1004,6 +1004,31 @@ void WrappedID3D11Device::Serialise_CaptureScope(uint64_t offset) record.frameInfo.firstEvent = m_pImmediateContext->GetEventID(); record.frameInfo.frameNumber = FrameNumber; record.frameInfo.immContextId = GetResourceManager()->GetOriginalID(m_pImmediateContext->GetResourceID()); + + FetchFrameStatistics& stats = record.frameInfo.stats; + RDCEraseEl(stats); + + // #mivance GL/Vulkan don't set this so don't get stats in window + stats.recorded = 1; + + for(uint32_t stage = eShaderStage_First; stage < eShaderStage_Count; stage++) + { + create_array(stats.constants[stage].slots, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT + 1); + create_array(stats.constants[stage].sizes, FetchFrameConstantBindStats::BUCKET_COUNT); + + create_array(stats.samplers[stage].slots, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT + 1); + + create_array(stats.resources[stage].types, eResType_Count); + create_array(stats.resources[stage].slots, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT + 1); + } + + create_array(stats.updates.types, eResType_Count); + create_array(stats.updates.sizes, FetchFrameUpdateStats::BUCKET_COUNT); + + create_array(stats.draws.counts, FetchFrameDrawStats::BUCKET_COUNT); + + create_array(stats.vertices.slots, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT + 1); + m_FrameRecord.push_back(record); GetResourceManager()->CreateInitialContents(); diff --git a/renderdoc/driver/gl/gl_driver.cpp b/renderdoc/driver/gl/gl_driver.cpp index 470aa4ce3..e40a1b156 100644 --- a/renderdoc/driver/gl/gl_driver.cpp +++ b/renderdoc/driver/gl/gl_driver.cpp @@ -2353,6 +2353,7 @@ void WrappedOpenGL::StartFrameCapture(void *dev, void *wnd) FetchFrameRecord record; record.frameInfo.frameNumber = m_FrameCounter+1; record.frameInfo.captureTime = Timing::GetUnixTimestamp(); + RDCEraseEl(record.frameInfo.stats); m_FrameRecord.push_back(record); GetResourceManager()->ClearReferencedResources(); diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index 256f9969f..08969481f 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -724,6 +724,7 @@ void WrappedVulkan::StartFrameCapture(void *dev, void *wnd) FetchFrameRecord record; record.frameInfo.frameNumber = m_FrameCounter+1; record.frameInfo.captureTime = Timing::GetUnixTimestamp(); + RDCEraseEl(record.frameInfo.stats); m_FrameRecord.push_back(record); GetResourceManager()->ClearReferencedResources(); diff --git a/renderdoc/os/linux_specific.h b/renderdoc/os/linux_specific.h index 6d7bd0f2b..3a7d89d4d 100644 --- a/renderdoc/os/linux_specific.h +++ b/renderdoc/os/linux_specific.h @@ -55,3 +55,17 @@ namespace Threading typedef CriticalSectionTemplate CriticalSection; }; +namespace Bits +{ + inline uint32_t CountLeadingZeroes(uint32_t value) + { + return __builtin_clz(value); + } + +#if RDC64BIT + inline uint64_t CountLeadingZeroes(uint64_t value) + { + return __builtin_clzl(value); + } +#endif +}; diff --git a/renderdoc/os/os_specific.h b/renderdoc/os/os_specific.h index 4502f35c1..1be88e3a4 100644 --- a/renderdoc/os/os_specific.h +++ b/renderdoc/os/os_specific.h @@ -40,6 +40,7 @@ #include #include #include + using std::string; using std::vector; using std::map; @@ -314,6 +315,14 @@ namespace OSUtility void WriteOutput(int channel, const char *str); }; +namespace Bits +{ + inline uint32_t CountLeadingZeroes(uint32_t value); +#if RDC64BIT + inline uint64_t CountLeadingZeroes(uint64_t value); +#endif +}; + // must #define: // __PRETTY_FUNCTION_SIGNATURE__ - undecorated function signature // GetEmbeddedResource(name_with_underscores_ext) - function/inline that returns the given file in a std::string diff --git a/renderdoc/os/win32_specific.h b/renderdoc/os/win32_specific.h index 34b1cfb91..2b87d18a0 100644 --- a/renderdoc/os/win32_specific.h +++ b/renderdoc/os/win32_specific.h @@ -27,6 +27,7 @@ #pragma once #include +#include #include "data/resource.h" #define __PRETTY_FUNCTION_SIGNATURE__ __FUNCSIG__ @@ -54,3 +55,22 @@ namespace Threading { typedef CriticalSectionTemplate CriticalSection; }; + +namespace Bits +{ + inline uint32_t CountLeadingZeroes(uint32_t value) + { + DWORD index; + BOOLEAN result = _BitScanReverse(&index, value); + return (result == TRUE) ? (index ^ 31) : 32; + } + +#if RDC64BIT + inline uint64_t CountLeadingZeroes(uint64_t value) + { + DWORD index; + BOOLEAN result = _BitScanReverse64(&index, value); + return (result == TRUE) ? (index ^ 63) : 64; + } +#endif +}; diff --git a/renderdoc/serialise/serialiser.h b/renderdoc/serialise/serialiser.h index e61d8f124..788a98639 100644 --- a/renderdoc/serialise/serialiser.h +++ b/renderdoc/serialise/serialiser.h @@ -388,6 +388,13 @@ class Serialiser // // If serialising in, el will either be set to NULL or allocated, the // existing value will be overwritten. + template + void SerialiseComplexArray(const char* name, T *&el) + { + uint32_t n = (uint32_t)Num; + SerialiseComplexArray(name, el, n); + } + template void SerialiseComplexArray(const char *name, T *&el, uint32_t &Num) { diff --git a/renderdocui/Code/Core.cs b/renderdocui/Code/Core.cs index 7ac4ef9eb..3a8086bc5 100644 --- a/renderdocui/Code/Core.cs +++ b/renderdocui/Code/Core.cs @@ -89,6 +89,7 @@ namespace renderdocui.Code private TimelineBar m_TimelineBar = null; private TextureViewer m_TextureViewer = null; private PipelineStateViewer m_PipelineStateViewer = null; + private StatisticsViewer m_StatisticsViewer = null; #endregion @@ -809,7 +810,18 @@ namespace renderdocui.Code return m_TimelineBar; } - public void AddLogProgressListener(ILogLoadProgressListener p) + public StatisticsViewer GetStatisticsViewer() + { + if (m_StatisticsViewer == null || m_StatisticsViewer.IsDisposed) + { + m_StatisticsViewer = new StatisticsViewer(this); + AddLogViewer(m_StatisticsViewer); + } + + return m_StatisticsViewer; + } + + public void AddLogProgressListener(ILogLoadProgressListener p) { m_ProgressListeners.Add(p); } diff --git a/renderdocui/Interop/Enums.cs b/renderdocui/Interop/Enums.cs index 59f87958f..be80c682a 100644 --- a/renderdocui/Interop/Enums.cs +++ b/renderdocui/Interop/Enums.cs @@ -283,6 +283,7 @@ namespace renderdoc public enum ShaderStageType { Vertex = 0, + First = Vertex, Hull, Tess_Control = Hull, @@ -296,6 +297,8 @@ namespace renderdoc Fragment = Pixel, Compute, + + Count, }; [Flags] diff --git a/renderdocui/Interop/FetchInfo.cs b/renderdocui/Interop/FetchInfo.cs index 03e3b9fd1..720a1f480 100644 --- a/renderdocui/Interop/FetchInfo.cs +++ b/renderdocui/Interop/FetchInfo.cs @@ -277,6 +277,119 @@ namespace renderdoc }; [StructLayout(LayoutKind.Sequential)] + public class FetchFrameConstantBindStats + { + public UInt32 calls; + public UInt32 sets; + public UInt32 nulls; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public UInt32[] slots; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public UInt32[] sizes; + }; + + [StructLayout(LayoutKind.Sequential)] + public class FetchFrameSamplerBindStats + { + public UInt32 calls; + public UInt32 sets; + public UInt32 nulls; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public UInt32[] slots; + }; + + [StructLayout(LayoutKind.Sequential)] + public class FetchFrameResourceBindStats + { + public UInt32 calls; + public UInt32 sets; + public UInt32 nulls; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public UInt32[] types; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public UInt32[] slots; + }; + + [StructLayout(LayoutKind.Sequential)] + public class FetchFrameUpdateStats + { + public UInt32 calls; + public UInt32 clients; + public UInt32 servers; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public UInt32[] types; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public UInt32[] sizes; + }; + + [StructLayout(LayoutKind.Sequential)] + public class FetchFrameDrawStats + { + public UInt32 calls; + public UInt32 instanced; + public UInt32 indirect; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public UInt32[] counts; + }; + + [StructLayout(LayoutKind.Sequential)] + public class FetchFrameDispatchStats + { + public UInt32 calls; + public UInt32 indirect; + }; + + [StructLayout(LayoutKind.Sequential)] + public class FetchFrameIndexBindStats + { + public UInt32 calls; + public UInt32 sets; + public UInt32 nulls; + }; + + [StructLayout(LayoutKind.Sequential)] + public class FetchFrameVertexBindStats + { + public UInt32 calls; + public UInt32 sets; + public UInt32 nulls; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] + public UInt32[] slots; + }; + + [StructLayout(LayoutKind.Sequential)] + public class FetchFrameLayoutBindStats + { + public UInt32 calls; + public UInt32 sets; + public UInt32 nulls; + }; + + [StructLayout(LayoutKind.Sequential)] + public class FetchFrameStatistics + { + public UInt32 recorded; + [CustomMarshalAs(CustomUnmanagedType.FixedArray, FixedLength = (int)ShaderStageType.Count)] + public FetchFrameConstantBindStats[] constants; + [CustomMarshalAs(CustomUnmanagedType.FixedArray, FixedLength = (int)ShaderStageType.Count)] + public FetchFrameSamplerBindStats[] samplers; + [CustomMarshalAs(CustomUnmanagedType.FixedArray, FixedLength = (int)ShaderStageType.Count)] + public FetchFrameResourceBindStats[] resources; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public FetchFrameUpdateStats updates; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public FetchFrameDrawStats draws; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public FetchFrameDispatchStats dispatches; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public FetchFrameIndexBindStats indices; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public FetchFrameVertexBindStats vertices; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public FetchFrameLayoutBindStats layouts; + }; + +[StructLayout(LayoutKind.Sequential)] public class FetchFrameInfo { public UInt32 frameNumber; @@ -284,6 +397,8 @@ namespace renderdoc public UInt64 fileOffset; public UInt64 captureTime; public ResourceId immContextId; + [CustomMarshalAs(CustomUnmanagedType.CustomClass)] + public FetchFrameStatistics stats; [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] public DebugMessage[] debugMessages; diff --git a/renderdocui/Windows/MainWindow.Designer.cs b/renderdocui/Windows/MainWindow.Designer.cs index 38fa9a751..119f85a5d 100644 --- a/renderdocui/Windows/MainWindow.Designer.cs +++ b/renderdocui/Windows/MainWindow.Designer.cs @@ -89,15 +89,17 @@ this.meshOutputToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.debugMessagesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.timelineToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.statisticsViewerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.resolveSymbolsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.logStatisticsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator11 = new System.Windows.Forms.ToolStripSeparator(); this.optionsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.manageReplayDevicesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.viewDocsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.viewLogFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.showTipsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator12 = new System.Windows.Forms.ToolStripSeparator(); this.sendErrorReportToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator9 = new System.Windows.Forms.ToolStripSeparator(); this.checkForUpdatesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -114,8 +116,6 @@ this.statusProgress = new System.Windows.Forms.ToolStripProgressBar(); this.dockPanel = new WeifenLuo.WinFormsUI.Docking.DockPanel(); this.saveDialog = new System.Windows.Forms.SaveFileDialog(); - this.toolStripSeparator12 = new System.Windows.Forms.ToolStripSeparator(); - this.showTipsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.menuStrip1.SuspendLayout(); this.toolStripContainer1.BottomToolStripPanel.SuspendLayout(); this.toolStripContainer1.ContentPanel.SuspendLayout(); @@ -154,41 +154,41 @@ this.toolStripSeparator5, this.exitToolStripMenuItem}); this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; - this.fileToolStripMenuItem.Size = new System.Drawing.Size(35, 20); + this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); this.fileToolStripMenuItem.Text = "&File"; // // captureLogToolStripMenuItem // this.captureLogToolStripMenuItem.Name = "captureLogToolStripMenuItem"; this.captureLogToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.N))); - this.captureLogToolStripMenuItem.Size = new System.Drawing.Size(206, 22); + this.captureLogToolStripMenuItem.Size = new System.Drawing.Size(218, 22); this.captureLogToolStripMenuItem.Text = "&Capture Log"; this.captureLogToolStripMenuItem.Click += new System.EventHandler(this.captureLogToolStripMenuItem_Click); // // attachToInstanceToolStripMenuItem // this.attachToInstanceToolStripMenuItem.Name = "attachToInstanceToolStripMenuItem"; - this.attachToInstanceToolStripMenuItem.Size = new System.Drawing.Size(206, 22); + this.attachToInstanceToolStripMenuItem.Size = new System.Drawing.Size(218, 22); this.attachToInstanceToolStripMenuItem.Text = "&Attach to Running Instance"; this.attachToInstanceToolStripMenuItem.Click += new System.EventHandler(this.attachToInstanceToolStripMenuItem_Click); // // injectIntoProcessToolStripMenuItem // this.injectIntoProcessToolStripMenuItem.Name = "injectIntoProcessToolStripMenuItem"; - this.injectIntoProcessToolStripMenuItem.Size = new System.Drawing.Size(206, 22); + this.injectIntoProcessToolStripMenuItem.Size = new System.Drawing.Size(218, 22); this.injectIntoProcessToolStripMenuItem.Text = "&Inject into Process"; this.injectIntoProcessToolStripMenuItem.Click += new System.EventHandler(this.injectIntoProcessToolStripMenuItem_Click); // // toolStripSeparator10 // this.toolStripSeparator10.Name = "toolStripSeparator10"; - this.toolStripSeparator10.Size = new System.Drawing.Size(203, 6); + this.toolStripSeparator10.Size = new System.Drawing.Size(215, 6); // // openLogToolStripMenuItem // this.openLogToolStripMenuItem.Name = "openLogToolStripMenuItem"; this.openLogToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.O))); - this.openLogToolStripMenuItem.Size = new System.Drawing.Size(206, 22); + this.openLogToolStripMenuItem.Size = new System.Drawing.Size(218, 22); this.openLogToolStripMenuItem.Text = "&Open Log"; this.openLogToolStripMenuItem.Click += new System.EventHandler(this.openLogToolStripMenuItem_Click); // @@ -197,7 +197,7 @@ this.saveLogToolStripMenuItem.Enabled = false; this.saveLogToolStripMenuItem.Name = "saveLogToolStripMenuItem"; this.saveLogToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.S))); - this.saveLogToolStripMenuItem.Size = new System.Drawing.Size(206, 22); + this.saveLogToolStripMenuItem.Size = new System.Drawing.Size(218, 22); this.saveLogToolStripMenuItem.Text = "&Save Log"; this.saveLogToolStripMenuItem.Click += new System.EventHandler(this.saveLogToolStripMenuItem_Click); // @@ -205,14 +205,14 @@ // this.closeLogToolStripMenuItem.Name = "closeLogToolStripMenuItem"; this.closeLogToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.W))); - this.closeLogToolStripMenuItem.Size = new System.Drawing.Size(206, 22); + this.closeLogToolStripMenuItem.Size = new System.Drawing.Size(218, 22); this.closeLogToolStripMenuItem.Text = "C&lose Log"; this.closeLogToolStripMenuItem.Click += new System.EventHandler(this.closeLogToolStripMenuItem_Click); // // toolStripSeparator4 // this.toolStripSeparator4.Name = "toolStripSeparator4"; - this.toolStripSeparator4.Size = new System.Drawing.Size(203, 6); + this.toolStripSeparator4.Size = new System.Drawing.Size(215, 6); // // recentFilesToolStripMenuItem // @@ -220,18 +220,18 @@ this.toolStripSeparator6, this.clearHistoryToolStripMenuItem}); this.recentFilesToolStripMenuItem.Name = "recentFilesToolStripMenuItem"; - this.recentFilesToolStripMenuItem.Size = new System.Drawing.Size(206, 22); + this.recentFilesToolStripMenuItem.Size = new System.Drawing.Size(218, 22); this.recentFilesToolStripMenuItem.Text = "&Recent Logs"; // // toolStripSeparator6 // this.toolStripSeparator6.Name = "toolStripSeparator6"; - this.toolStripSeparator6.Size = new System.Drawing.Size(133, 6); + this.toolStripSeparator6.Size = new System.Drawing.Size(139, 6); // // clearHistoryToolStripMenuItem // this.clearHistoryToolStripMenuItem.Name = "clearHistoryToolStripMenuItem"; - this.clearHistoryToolStripMenuItem.Size = new System.Drawing.Size(136, 22); + this.clearHistoryToolStripMenuItem.Size = new System.Drawing.Size(142, 22); this.clearHistoryToolStripMenuItem.Text = "&Clear History"; this.clearHistoryToolStripMenuItem.Click += new System.EventHandler(this.clearHistoryToolStripMenuItem_Click); // @@ -241,31 +241,31 @@ this.toolStripSeparator7, this.clearHistoryToolStripMenuItem1}); this.recentCapturesToolStripMenuItem.Name = "recentCapturesToolStripMenuItem"; - this.recentCapturesToolStripMenuItem.Size = new System.Drawing.Size(206, 22); + this.recentCapturesToolStripMenuItem.Size = new System.Drawing.Size(218, 22); this.recentCapturesToolStripMenuItem.Text = "R&ecent Capture Settings"; // // toolStripSeparator7 // this.toolStripSeparator7.Name = "toolStripSeparator7"; - this.toolStripSeparator7.Size = new System.Drawing.Size(133, 6); + this.toolStripSeparator7.Size = new System.Drawing.Size(139, 6); // // clearHistoryToolStripMenuItem1 // this.clearHistoryToolStripMenuItem1.Name = "clearHistoryToolStripMenuItem1"; - this.clearHistoryToolStripMenuItem1.Size = new System.Drawing.Size(136, 22); + this.clearHistoryToolStripMenuItem1.Size = new System.Drawing.Size(142, 22); this.clearHistoryToolStripMenuItem1.Text = "&Clear History"; this.clearHistoryToolStripMenuItem1.Click += new System.EventHandler(this.clearHistoryToolStripMenuItem1_Click); // // toolStripSeparator5 // this.toolStripSeparator5.Name = "toolStripSeparator5"; - this.toolStripSeparator5.Size = new System.Drawing.Size(203, 6); + this.toolStripSeparator5.Size = new System.Drawing.Size(215, 6); // // exitToolStripMenuItem // this.exitToolStripMenuItem.Name = "exitToolStripMenuItem"; this.exitToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.F4))); - this.exitToolStripMenuItem.Size = new System.Drawing.Size(206, 22); + this.exitToolStripMenuItem.Size = new System.Drawing.Size(218, 22); this.exitToolStripMenuItem.Text = "E&xit"; this.exitToolStripMenuItem.Click += new System.EventHandler(this.exitToolStripMenuItem_Click); // @@ -282,9 +282,10 @@ this.aPIInspectorToolStripMenuItem, this.meshOutputToolStripMenuItem, this.debugMessagesToolStripMenuItem, - this.timelineToolStripMenuItem}); + this.timelineToolStripMenuItem, + this.statisticsViewerToolStripMenuItem}); this.windowToolStripMenuItem.Name = "windowToolStripMenuItem"; - this.windowToolStripMenuItem.Size = new System.Drawing.Size(57, 20); + this.windowToolStripMenuItem.Size = new System.Drawing.Size(63, 20); this.windowToolStripMenuItem.Text = "&Window"; // // toolStripMenuItem1 @@ -299,13 +300,13 @@ this.layoutSave5, this.layoutSave6}); this.toolStripMenuItem1.Name = "toolStripMenuItem1"; - this.toolStripMenuItem1.Size = new System.Drawing.Size(192, 22); + this.toolStripMenuItem1.Size = new System.Drawing.Size(203, 22); this.toolStripMenuItem1.Text = "&Save Layout"; // // layoutSaveDefault // this.layoutSaveDefault.Name = "layoutSaveDefault"; - this.layoutSaveDefault.Size = new System.Drawing.Size(145, 22); + this.layoutSaveDefault.Size = new System.Drawing.Size(151, 22); this.layoutSaveDefault.Tag = "0"; this.layoutSaveDefault.Text = "&Default Layout"; this.layoutSaveDefault.Click += new System.EventHandler(this.saveLayout_Click); @@ -313,12 +314,12 @@ // toolStripSeparator3 // this.toolStripSeparator3.Name = "toolStripSeparator3"; - this.toolStripSeparator3.Size = new System.Drawing.Size(142, 6); + this.toolStripSeparator3.Size = new System.Drawing.Size(148, 6); // // layoutSave1 // this.layoutSave1.Name = "layoutSave1"; - this.layoutSave1.Size = new System.Drawing.Size(145, 22); + this.layoutSave1.Size = new System.Drawing.Size(151, 22); this.layoutSave1.Tag = "1"; this.layoutSave1.Text = "Layout &1"; this.layoutSave1.Click += new System.EventHandler(this.saveLayout_Click); @@ -326,7 +327,7 @@ // layoutSave2 // this.layoutSave2.Name = "layoutSave2"; - this.layoutSave2.Size = new System.Drawing.Size(145, 22); + this.layoutSave2.Size = new System.Drawing.Size(151, 22); this.layoutSave2.Tag = "2"; this.layoutSave2.Text = "Layout &2"; this.layoutSave2.Click += new System.EventHandler(this.saveLayout_Click); @@ -334,7 +335,7 @@ // layoutSave3 // this.layoutSave3.Name = "layoutSave3"; - this.layoutSave3.Size = new System.Drawing.Size(145, 22); + this.layoutSave3.Size = new System.Drawing.Size(151, 22); this.layoutSave3.Tag = "3"; this.layoutSave3.Text = "Layout &3"; this.layoutSave3.Click += new System.EventHandler(this.saveLayout_Click); @@ -342,7 +343,7 @@ // layoutSave4 // this.layoutSave4.Name = "layoutSave4"; - this.layoutSave4.Size = new System.Drawing.Size(145, 22); + this.layoutSave4.Size = new System.Drawing.Size(151, 22); this.layoutSave4.Tag = "4"; this.layoutSave4.Text = "Layout &4"; this.layoutSave4.Click += new System.EventHandler(this.saveLayout_Click); @@ -350,7 +351,7 @@ // layoutSave5 // this.layoutSave5.Name = "layoutSave5"; - this.layoutSave5.Size = new System.Drawing.Size(145, 22); + this.layoutSave5.Size = new System.Drawing.Size(151, 22); this.layoutSave5.Tag = "5"; this.layoutSave5.Text = "Layout &5"; this.layoutSave5.Click += new System.EventHandler(this.saveLayout_Click); @@ -358,7 +359,7 @@ // layoutSave6 // this.layoutSave6.Name = "layoutSave6"; - this.layoutSave6.Size = new System.Drawing.Size(145, 22); + this.layoutSave6.Size = new System.Drawing.Size(151, 22); this.layoutSave6.Tag = "6"; this.layoutSave6.Text = "Layout &6"; this.layoutSave6.Click += new System.EventHandler(this.saveLayout_Click); @@ -375,13 +376,13 @@ this.layoutLoad5, this.layoutLoad6}); this.saveLayoutToolStripMenuItem.Name = "saveLayoutToolStripMenuItem"; - this.saveLayoutToolStripMenuItem.Size = new System.Drawing.Size(192, 22); + this.saveLayoutToolStripMenuItem.Size = new System.Drawing.Size(203, 22); this.saveLayoutToolStripMenuItem.Text = "&Load Layout"; // // layoutLoadDefault // this.layoutLoadDefault.Name = "layoutLoadDefault"; - this.layoutLoadDefault.Size = new System.Drawing.Size(145, 22); + this.layoutLoadDefault.Size = new System.Drawing.Size(151, 22); this.layoutLoadDefault.Tag = "0"; this.layoutLoadDefault.Text = "&Default Layout"; this.layoutLoadDefault.Click += new System.EventHandler(this.loadLayout_Click); @@ -389,12 +390,12 @@ // toolStripSeparator2 // this.toolStripSeparator2.Name = "toolStripSeparator2"; - this.toolStripSeparator2.Size = new System.Drawing.Size(142, 6); + this.toolStripSeparator2.Size = new System.Drawing.Size(148, 6); // // layoutLoad1 // this.layoutLoad1.Name = "layoutLoad1"; - this.layoutLoad1.Size = new System.Drawing.Size(145, 22); + this.layoutLoad1.Size = new System.Drawing.Size(151, 22); this.layoutLoad1.Tag = "1"; this.layoutLoad1.Text = "Layout &1"; this.layoutLoad1.Click += new System.EventHandler(this.loadLayout_Click); @@ -402,7 +403,7 @@ // layoutLoad2 // this.layoutLoad2.Name = "layoutLoad2"; - this.layoutLoad2.Size = new System.Drawing.Size(145, 22); + this.layoutLoad2.Size = new System.Drawing.Size(151, 22); this.layoutLoad2.Tag = "2"; this.layoutLoad2.Text = "Layout &2"; this.layoutLoad2.Click += new System.EventHandler(this.loadLayout_Click); @@ -410,7 +411,7 @@ // layoutLoad3 // this.layoutLoad3.Name = "layoutLoad3"; - this.layoutLoad3.Size = new System.Drawing.Size(145, 22); + this.layoutLoad3.Size = new System.Drawing.Size(151, 22); this.layoutLoad3.Tag = "3"; this.layoutLoad3.Text = "Layout &3"; this.layoutLoad3.Click += new System.EventHandler(this.loadLayout_Click); @@ -418,7 +419,7 @@ // layoutLoad4 // this.layoutLoad4.Name = "layoutLoad4"; - this.layoutLoad4.Size = new System.Drawing.Size(145, 22); + this.layoutLoad4.Size = new System.Drawing.Size(151, 22); this.layoutLoad4.Tag = "4"; this.layoutLoad4.Text = "Layout &4"; this.layoutLoad4.Click += new System.EventHandler(this.loadLayout_Click); @@ -426,7 +427,7 @@ // layoutLoad5 // this.layoutLoad5.Name = "layoutLoad5"; - this.layoutLoad5.Size = new System.Drawing.Size(145, 22); + this.layoutLoad5.Size = new System.Drawing.Size(151, 22); this.layoutLoad5.Tag = "5"; this.layoutLoad5.Text = "Layout &5"; this.layoutLoad5.Click += new System.EventHandler(this.loadLayout_Click); @@ -434,7 +435,7 @@ // layoutLoad6 // this.layoutLoad6.Name = "layoutLoad6"; - this.layoutLoad6.Size = new System.Drawing.Size(145, 22); + this.layoutLoad6.Size = new System.Drawing.Size(151, 22); this.layoutLoad6.Tag = "6"; this.layoutLoad6.Text = "Layout &6"; this.layoutLoad6.Click += new System.EventHandler(this.loadLayout_Click); @@ -442,106 +443,105 @@ // toolStripSeparator1 // this.toolStripSeparator1.Name = "toolStripSeparator1"; - this.toolStripSeparator1.Size = new System.Drawing.Size(189, 6); + this.toolStripSeparator1.Size = new System.Drawing.Size(200, 6); // // pythonShellToolStripMenuItem // this.pythonShellToolStripMenuItem.Name = "pythonShellToolStripMenuItem"; - this.pythonShellToolStripMenuItem.Size = new System.Drawing.Size(192, 22); + this.pythonShellToolStripMenuItem.Size = new System.Drawing.Size(203, 22); this.pythonShellToolStripMenuItem.Text = "P&ython Shell"; this.pythonShellToolStripMenuItem.Click += new System.EventHandler(this.pythonShellToolStripMenuItem_Click); // // eventViewerToolStripMenuItem // this.eventViewerToolStripMenuItem.Name = "eventViewerToolStripMenuItem"; - this.eventViewerToolStripMenuItem.Size = new System.Drawing.Size(192, 22); + this.eventViewerToolStripMenuItem.Size = new System.Drawing.Size(203, 22); this.eventViewerToolStripMenuItem.Text = "&Event Viewer"; this.eventViewerToolStripMenuItem.Click += new System.EventHandler(this.eventViewerToolStripMenuItem_Click); // // textureToolStripMenuItem // this.textureToolStripMenuItem.Name = "textureToolStripMenuItem"; - this.textureToolStripMenuItem.Size = new System.Drawing.Size(192, 22); + this.textureToolStripMenuItem.Size = new System.Drawing.Size(203, 22); this.textureToolStripMenuItem.Text = "&Texture Viewer"; this.textureToolStripMenuItem.Click += new System.EventHandler(this.textureToolStripMenuItem_Click); // // D3D11PipelineStateToolStripMenuItem // this.D3D11PipelineStateToolStripMenuItem.Name = "D3D11PipelineStateToolStripMenuItem"; - this.D3D11PipelineStateToolStripMenuItem.Size = new System.Drawing.Size(192, 22); + this.D3D11PipelineStateToolStripMenuItem.Size = new System.Drawing.Size(203, 22); this.D3D11PipelineStateToolStripMenuItem.Text = "&Pipeline State"; this.D3D11PipelineStateToolStripMenuItem.Click += new System.EventHandler(this.PipelineStateToolStripMenuItem_Click); // // aPIInspectorToolStripMenuItem // this.aPIInspectorToolStripMenuItem.Name = "aPIInspectorToolStripMenuItem"; - this.aPIInspectorToolStripMenuItem.Size = new System.Drawing.Size(192, 22); + this.aPIInspectorToolStripMenuItem.Size = new System.Drawing.Size(203, 22); this.aPIInspectorToolStripMenuItem.Text = "&API Inspector"; this.aPIInspectorToolStripMenuItem.Click += new System.EventHandler(this.APIInspectorToolStripMenuItem_Click); // // meshOutputToolStripMenuItem // this.meshOutputToolStripMenuItem.Name = "meshOutputToolStripMenuItem"; - this.meshOutputToolStripMenuItem.Size = new System.Drawing.Size(192, 22); + this.meshOutputToolStripMenuItem.Size = new System.Drawing.Size(203, 22); this.meshOutputToolStripMenuItem.Text = "&Mesh Output"; this.meshOutputToolStripMenuItem.Click += new System.EventHandler(this.meshOutputToolStripMenuItem_Click); // // debugMessagesToolStripMenuItem // this.debugMessagesToolStripMenuItem.Name = "debugMessagesToolStripMenuItem"; - this.debugMessagesToolStripMenuItem.Size = new System.Drawing.Size(192, 22); + this.debugMessagesToolStripMenuItem.Size = new System.Drawing.Size(203, 22); this.debugMessagesToolStripMenuItem.Text = "Log Errors and &Warnings"; this.debugMessagesToolStripMenuItem.Click += new System.EventHandler(this.debugMessagesToolStripMenuItem_Click); // // timelineToolStripMenuItem // this.timelineToolStripMenuItem.Name = "timelineToolStripMenuItem"; - this.timelineToolStripMenuItem.Size = new System.Drawing.Size(192, 22); + this.timelineToolStripMenuItem.Size = new System.Drawing.Size(203, 22); this.timelineToolStripMenuItem.Text = "T&imeline"; this.timelineToolStripMenuItem.Click += new System.EventHandler(this.timelineToolStripMenuItem_Click); // + // statisticsViewerToolStripMenuItem + // + this.statisticsViewerToolStripMenuItem.Name = "statisticsViewerToolStripMenuItem"; + this.statisticsViewerToolStripMenuItem.Size = new System.Drawing.Size(203, 22); + this.statisticsViewerToolStripMenuItem.Text = "Statisti&cs Viewer"; + this.statisticsViewerToolStripMenuItem.Click += new System.EventHandler(this.statisticsViewerToolStripMenuItem_Click); + // // toolsToolStripMenuItem // this.toolsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.resolveSymbolsToolStripMenuItem, - this.logStatisticsToolStripMenuItem, this.toolStripSeparator11, this.optionsToolStripMenuItem, this.manageReplayDevicesToolStripMenuItem}); this.toolsToolStripMenuItem.Name = "toolsToolStripMenuItem"; - this.toolsToolStripMenuItem.Size = new System.Drawing.Size(44, 20); + this.toolsToolStripMenuItem.Size = new System.Drawing.Size(48, 20); this.toolsToolStripMenuItem.Text = "&Tools"; // // resolveSymbolsToolStripMenuItem // this.resolveSymbolsToolStripMenuItem.Name = "resolveSymbolsToolStripMenuItem"; - this.resolveSymbolsToolStripMenuItem.Size = new System.Drawing.Size(188, 22); + this.resolveSymbolsToolStripMenuItem.Size = new System.Drawing.Size(198, 22); this.resolveSymbolsToolStripMenuItem.Text = "&Resolve Symbols"; this.resolveSymbolsToolStripMenuItem.Click += new System.EventHandler(this.resolveSymbolsToolStripMenuItem_Click); // - // logStatisticsToolStripMenuItem - // - this.logStatisticsToolStripMenuItem.Name = "logStatisticsToolStripMenuItem"; - this.logStatisticsToolStripMenuItem.Size = new System.Drawing.Size(188, 22); - this.logStatisticsToolStripMenuItem.Text = "&Log Statistics"; - this.logStatisticsToolStripMenuItem.Click += new System.EventHandler(this.logStatisticsToolStripMenuItem_Click); - // // toolStripSeparator11 // this.toolStripSeparator11.Name = "toolStripSeparator11"; - this.toolStripSeparator11.Size = new System.Drawing.Size(185, 6); + this.toolStripSeparator11.Size = new System.Drawing.Size(195, 6); // // optionsToolStripMenuItem // this.optionsToolStripMenuItem.Name = "optionsToolStripMenuItem"; - this.optionsToolStripMenuItem.Size = new System.Drawing.Size(188, 22); + this.optionsToolStripMenuItem.Size = new System.Drawing.Size(198, 22); this.optionsToolStripMenuItem.Text = "&Options"; this.optionsToolStripMenuItem.Click += new System.EventHandler(this.optionsToolStripMenuItem_Click); // // manageReplayDevicesToolStripMenuItem // this.manageReplayDevicesToolStripMenuItem.Name = "manageReplayDevicesToolStripMenuItem"; - this.manageReplayDevicesToolStripMenuItem.Size = new System.Drawing.Size(188, 22); + this.manageReplayDevicesToolStripMenuItem.Size = new System.Drawing.Size(198, 22); this.manageReplayDevicesToolStripMenuItem.Text = "&Manage Replay Devices"; this.manageReplayDevicesToolStripMenuItem.Click += new System.EventHandler(this.manageReplayDevicesToolStripMenuItem_Click); // @@ -693,7 +693,7 @@ // this.statusText.DoubleClickEnabled = true; this.statusText.Name = "statusText"; - this.statusText.Size = new System.Drawing.Size(63, 17); + this.statusText.Size = new System.Drawing.Size(64, 17); this.statusText.Text = "Status Text"; this.statusText.DoubleClick += new System.EventHandler(this.status_DoubleClick); // @@ -873,7 +873,6 @@ private System.Windows.Forms.ToolStripProgressBar statusProgress; private System.Windows.Forms.ToolStripMenuItem sendErrorReportToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem viewDocsToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem logStatisticsToolStripMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator9; private System.Windows.Forms.ToolStripMenuItem updateToolStripMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator8; @@ -889,6 +888,6 @@ private System.Windows.Forms.ToolStripMenuItem checkForUpdatesToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem showTipsToolStripMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator12; - + private System.Windows.Forms.ToolStripMenuItem statisticsViewerToolStripMenuItem; } } \ No newline at end of file diff --git a/renderdocui/Windows/MainWindow.cs b/renderdocui/Windows/MainWindow.cs index 030efba79..f9a6fce4f 100644 --- a/renderdocui/Windows/MainWindow.cs +++ b/renderdocui/Windows/MainWindow.cs @@ -160,8 +160,6 @@ namespace renderdocui.Windows m_InitRemoteIdent = remoteIdent; OwnTemporaryLog = temp; - logStatisticsToolStripMenuItem.Enabled = false; - resolveSymbolsToolStripMenuItem.Enabled = false; resolveSymbolsToolStripMenuItem.Text = "Resolve Symbols"; @@ -264,8 +262,6 @@ namespace renderdocui.Windows m_MessageTick.Dispose(); m_MessageTick = null; - logStatisticsToolStripMenuItem.Enabled = false; - resolveSymbolsToolStripMenuItem.Enabled = false; resolveSymbolsToolStripMenuItem.Text = "Resolve Symbols"; @@ -366,8 +362,6 @@ namespace renderdocui.Windows })); }); - logStatisticsToolStripMenuItem.Enabled = true; - saveLogToolStripMenuItem.Enabled = true; SetTitle(); @@ -1356,139 +1350,6 @@ namespace renderdocui.Windows } } - private void CountDrawsDispatches(FetchDrawcall draw, ref int numDraws, ref int numDispatches) - { - if ((draw.flags & DrawcallFlags.Drawcall) != 0) - { - numDraws++; - } - if ((draw.flags & DrawcallFlags.Dispatch) != 0) - { - numDraws++; - numDispatches++; - } - - if(draw.children != null) - { - foreach (var d in draw.children) - CountDrawsDispatches(d, ref numDraws, ref numDispatches); - } - } - - private void logStatisticsToolStripMenuItem_Click(object sender, EventArgs e) - { - long fileSize = (new FileInfo(m_Core.LogFileName)).Length; - - int firstIdx = 0; - - var firstDrawcall = m_Core.CurDrawcalls[firstIdx]; - while (firstDrawcall.children != null && firstDrawcall.children.Length > 0) - firstDrawcall = firstDrawcall.children[0]; - - while (firstDrawcall.events.Length == 0) - { - if (firstDrawcall.next != null) - { - firstDrawcall = firstDrawcall.next; - while (firstDrawcall.children != null && firstDrawcall.children.Length > 0) - firstDrawcall = firstDrawcall.children[0]; - } - else - { - firstDrawcall = m_Core.CurDrawcalls[++firstIdx]; - while (firstDrawcall.children != null && firstDrawcall.children.Length > 0) - firstDrawcall = firstDrawcall.children[0]; - } - } - - UInt64 persistantData = (UInt64)fileSize - firstDrawcall.events[0].fileOffset; - - var lastDraw = m_Core.CurDrawcalls[m_Core.CurDrawcalls.Length - 1]; - while (lastDraw.children != null && lastDraw.children.Length > 0) - lastDraw = lastDraw.children[lastDraw.children.Length - 1]; - - uint numAPIcalls = lastDraw.eventID; - - int numDrawcalls = 0; - int numDispatches = 0; - - foreach(var d in m_Core.CurDrawcalls) - CountDrawsDispatches(d, ref numDrawcalls, ref numDispatches); - - int numTextures = m_Core.CurTextures.Length; - int numBuffers = m_Core.CurBuffers.Length; - - ulong IBBytes = 0; - ulong VBBytes = 0; - ulong BufBytes = 0; - foreach(var b in m_Core.CurBuffers) - { - BufBytes += b.byteSize; - - if((b.creationFlags & BufferCreationFlags.IB) != 0) - IBBytes += b.byteSize; - if((b.creationFlags & BufferCreationFlags.VB) != 0) - VBBytes += b.byteSize; - } - - ulong RTBytes = 0; - ulong TexBytes = 0; - ulong LargeTexBytes = 0; - - int numRTs = 0; - float texW = 0, texH = 0; - float largeTexW = 0, largeTexH = 0; - int texCount = 0, largeTexCount = 0; - foreach (var t in m_Core.CurTextures) - { - if ((t.creationFlags & (TextureCreationFlags.RTV|TextureCreationFlags.DSV)) != 0) - { - numRTs++; - - RTBytes += t.byteSize; - } - else - { - texW += (float)t.width; - texH += (float)t.height; - texCount++; - - TexBytes += t.byteSize; - - if (t.width > 32 && t.height > 32) - { - largeTexW += (float)t.width; - largeTexH += (float)t.height; - largeTexCount++; - - LargeTexBytes += t.byteSize; - } - } - } - - texW /= texCount; - texH /= texCount; - - largeTexW /= largeTexCount; - largeTexH /= largeTexCount; - - string msg = - String.Format("Stats for {0}.\n\nFile size: {1:N2}MB\nPersistant Data (approx): {2:N2}MB\n\n", - Path.GetFileName(m_Core.LogFileName), - (float)fileSize / (1024.0f * 1024.0f), (float)persistantData / (1024.0f * 1024.0f)) + - String.Format("Draw calls: {0} ({1} of them are dispatches)\nAPI calls: {2}\nAPI:Draw call ratio: {3}\n\n", - numDrawcalls, numDispatches, numAPIcalls, (float)numAPIcalls / (float)numDrawcalls) + - String.Format("{0} Textures - {1:N2} MB ({2:N2} MB over 32x32), {3} RTs - {4:N2} MB.\nAvg. tex dimension: {5}x{6} ({7}x{8} over 32x32)\n", - numTextures, (float)TexBytes / (1024.0f * 1024.0f), (float)LargeTexBytes / (1024.0f * 1024.0f), - numRTs, (float)RTBytes / (1024.0f * 1024.0f), - texW, texH, largeTexW, largeTexH) + - String.Format("{0} Buffers - {1:N2} MB total {2:N2} MB IBs {3:N2} MB VBs.\n", - numBuffers, (float)BufBytes / (1024.0f * 1024.0f), (float)IBBytes / (1024.0f * 1024.0f), (float)VBBytes / (1024.0f * 1024.0f)) + - String.Format("{0} MB - Grand total GPU buffer + texture load", (float)(TexBytes + BufBytes + RTBytes) / (1024.0f * 1024.0f)); - - MessageBox.Show(msg); - } - private void recentLogMenuItem_Click(object sender, EventArgs e) { ToolStripDropDownItem item = (ToolStripDropDownItem)sender; @@ -1664,6 +1525,11 @@ namespace renderdocui.Windows m_Core.GetTimelineBar().Show(dockPanel); } + private void statisticsViewerToolStripMenuItem_Click(object sender, EventArgs e) + { + m_Core.GetStatisticsViewer().Show(dockPanel); + } + #endregion #region Symbol resolving @@ -1732,6 +1598,6 @@ namespace renderdocui.Windows e.Effect = DragDropEffects.None; } - #endregion + #endregion } } diff --git a/renderdocui/Windows/StatisticsViewer.Designer.cs b/renderdocui/Windows/StatisticsViewer.Designer.cs new file mode 100644 index 000000000..09d38c04c --- /dev/null +++ b/renderdocui/Windows/StatisticsViewer.Designer.cs @@ -0,0 +1,63 @@ +namespace renderdocui.Windows +{ + partial class StatisticsViewer + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.statisticsLog = new System.Windows.Forms.RichTextBox(); + this.SuspendLayout(); + // + // statisticsLog + // + this.statisticsLog.BackColor = System.Drawing.SystemColors.ControlLightLight; + this.statisticsLog.Dock = System.Windows.Forms.DockStyle.Fill; + this.statisticsLog.Location = new System.Drawing.Point(0, 0); + this.statisticsLog.Name = "statisticsLog"; + this.statisticsLog.ReadOnly = true; + this.statisticsLog.Size = new System.Drawing.Size(812, 482); + this.statisticsLog.TabIndex = 0; + this.statisticsLog.Text = ""; + // + // StatisticsViewer + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(812, 482); + this.Controls.Add(this.statisticsLog); + this.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Name = "StatisticsViewer"; + this.Text = "Statistics"; + this.Load += new System.EventHandler(this.StatisticsViewer_Load); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.RichTextBox statisticsLog; + } +} \ No newline at end of file diff --git a/renderdocui/Windows/StatisticsViewer.cs b/renderdocui/Windows/StatisticsViewer.cs new file mode 100644 index 000000000..1366bc997 --- /dev/null +++ b/renderdocui/Windows/StatisticsViewer.cs @@ -0,0 +1,785 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using WeifenLuo.WinFormsUI.Docking; +using renderdocui.Code; +using renderdoc; + +namespace renderdocui.Windows +{ + public partial class StatisticsViewer : DockContent, ILogViewerForm + { + private Core m_Core; + + public StatisticsViewer(Core core) + { + InitializeComponent(); + + Icon = global::renderdocui.Properties.Resources.icon; + + m_Core = core; + + statisticsLog.Font = new System.Drawing.Font("Consolas", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + } + + public void OnLogfileClosed() + { + statisticsLog.Clear(); + } + + private static readonly int HistogramWidth = 128; + private static readonly string Stars = String.Concat(Enumerable.Repeat("*", HistogramWidth)); + + private string Pow2IndexAsReadable(int index) + { + long value = 1L << index; + + if (value >= (1024 * 1024)) + { + float slice = (float)value / (1024 * 1024); + return String.Format("{0}MB", Formatter.Format(slice)); + } + else if (value >= 1024) + { + float slice = (float)value / 1024; + return String.Format("{0}KB", Formatter.Format(slice)); + } + else + { + return String.Format("{0}B", Formatter.Format(value)); + } + } + + private int SliceForString(string s, UInt32 value, UInt32 maximum) + { + if (value == 0) + return 0; + + float ratio = (float)value / maximum; + int slice = (int)(ratio * s.Length); + return Math.Max(1, slice); + } + + private string CountOrEmpty(UInt32 count) + { + if (count == 0) + return ""; + else + return String.Format("({0})", count); + } + + private void AppendDrawStatistics(FetchFrameInfo[] frameList) + { + // #mivance see AppendConstantBindStatistics + FetchFrameDrawStats template = frameList[0].stats.draws; + + FetchFrameDrawStats totalUpdates = new FetchFrameDrawStats(); + totalUpdates.counts = new UInt32[template.counts.Length]; + + foreach (var f in frameList) + { + FetchFrameDrawStats draws = f.stats.draws; + + totalUpdates.calls += draws.calls; + totalUpdates.instanced += draws.instanced; + totalUpdates.indirect += draws.indirect; + + System.Diagnostics.Debug.Assert(totalUpdates.counts.Length == draws.counts.Length); + for (var t = 0; t < draws.counts.Length; t++) + totalUpdates.counts[t] += draws.counts[t]; + } + + statisticsLog.AppendText("\n*** Draw Statistics ***\n\n"); + + statisticsLog.AppendText(String.Format("Total calls: {0}, instanced: {1}, indirect: {2}\n", totalUpdates.calls, totalUpdates.instanced, totalUpdates.indirect)); + + if ( totalUpdates.instanced > 0 ) + { + statisticsLog.AppendText("\nHistogram of instance counts:\n"); + UInt32 maxCount = 0; + int maxWithValue = 0; + int maximum = totalUpdates.counts.Length; + for (var s = 1; s < maximum; s++) + { + UInt32 value = totalUpdates.counts[s]; + if (value > 0) + maxWithValue = s; + maxCount = Math.Max(maxCount, value); + } + + for (var s = 1; s <= maxWithValue; s++) + { + UInt32 count = totalUpdates.counts[s]; + int slice = SliceForString(Stars, count, maxCount); + statisticsLog.AppendText(String.Format("{0,2}{1,2}: {2} {3}\n", (s == maximum - 1) ? ">=" : "", s, Stars.Substring(0, slice), CountOrEmpty(count))); + } + } + } + + private void AppendDispatchStatistics(FetchFrameInfo[] frameList) + { + FetchFrameDispatchStats totalUpdates = new FetchFrameDispatchStats(); + + foreach (var f in frameList) + { + FetchFrameDispatchStats dispatches = f.stats.dispatches; + + totalUpdates.calls += dispatches.calls; + totalUpdates.indirect += dispatches.indirect; + } + + statisticsLog.AppendText("\n*** Dispatch Statistics ***\n\n"); + + statisticsLog.AppendText(String.Format("Total calls: {0}, indirect: {1}\n", totalUpdates.calls, totalUpdates.indirect)); + } + + private void AppendInputAssemblerStatistics(FetchFrameInfo[] frameList) + { + FetchFrameIndexBindStats totalIndexStats = new FetchFrameIndexBindStats(); + + foreach (var f in frameList) + { + FetchFrameIndexBindStats indices = f.stats.indices; + + totalIndexStats.calls += indices.calls; + totalIndexStats.sets += indices.sets; + totalIndexStats.nulls += indices.nulls; + } + + FetchFrameLayoutBindStats totalLayoutStats = new FetchFrameLayoutBindStats(); + + foreach (var f in frameList) + { + FetchFrameLayoutBindStats layouts = f.stats.layouts; + + totalLayoutStats.calls += layouts.calls; + totalLayoutStats.sets += layouts.sets; + totalLayoutStats.nulls += layouts.nulls; + } + + // #mivance see AppendConstantBindStatistics + FetchFrameVertexBindStats template = frameList[0].stats.vertices; + FetchFrameVertexBindStats totalVertexStats = new FetchFrameVertexBindStats(); + totalVertexStats.slots = new UInt32[template.slots.Length]; + + foreach (var f in frameList) + { + FetchFrameVertexBindStats vertices = f.stats.vertices; + + totalVertexStats.calls += vertices.calls; + totalVertexStats.sets += vertices.sets; + totalVertexStats.nulls += vertices.nulls; + + System.Diagnostics.Debug.Assert(totalVertexStats.slots.Length == vertices.slots.Length); + for (var s = 0; s < vertices.slots.Length; s++) + { + totalVertexStats.slots[s] += vertices.slots[s]; + } + } + + statisticsLog.AppendText("\n*** Input Assembler Statistics ***\n\n"); + + statisticsLog.AppendText(String.Format("Total index calls: {0}, non-null index sets: {1}, null index sets: {2}\n", totalIndexStats.calls, totalIndexStats.sets, totalIndexStats.nulls)); + statisticsLog.AppendText(String.Format("Total layout calls: {0}, non-null layout sets: {1}, null layout sets: {2}\n", totalLayoutStats.calls, totalLayoutStats.sets, totalLayoutStats.nulls)); + statisticsLog.AppendText(String.Format("Total vertex calls: {0}, non-null vertex sets: {1}, null vertex sets: {2}\n", totalVertexStats.calls, totalVertexStats.sets, totalVertexStats.nulls)); + + statisticsLog.AppendText("\nHistogram of aggregate vertex slot counts per invocation:\n"); + UInt32 maxCount = 0; + int maxWithValue = 0; + for (var s = 1; s < totalVertexStats.slots.Length; s++) + { + UInt32 value = totalVertexStats.slots[s]; + if (value > 0) + maxWithValue = s; + maxCount = Math.Max(maxCount, value); + } + + for (var s = 1; s <= maxWithValue; s++) + { + UInt32 count = totalVertexStats.slots[s]; + int slice = SliceForString(Stars, count, maxCount); + statisticsLog.AppendText(String.Format("{0,2}: {1} {2}\n", s, Stars.Substring(0, slice), CountOrEmpty(count))); + } + } + + private void AppendConstantBindStatistics(FetchFrameInfo[] frameList) + { + System.Diagnostics.Debug.Assert(frameList.Length > 0); + + // #mivance C++-side we guarantee all stages will have the same slots + // and sizes count, so pattern off of the first frame's first stage + FetchFrameConstantBindStats template = frameList[0].stats.constants[0]; + + // #mivance there is probably a way to iterate the fields via + // GetType()/GetField() and build a sort of dynamic min/max/average + // structure for a given type with known integral types (or arrays + // thereof), but given we're heading for a Qt/C++ rewrite of the UI + // perhaps best not to dwell too long on that + FetchFrameConstantBindStats[] totalConstantsPerStage = new FetchFrameConstantBindStats[(int)ShaderStageType.Count]; + for (var s = (int)ShaderStageType.First; s < (int)ShaderStageType.Count; s++) + { + totalConstantsPerStage[s] = new FetchFrameConstantBindStats(); + totalConstantsPerStage[s].slots = new UInt32[template.slots.Length]; + totalConstantsPerStage[s].sizes = new UInt32[template.sizes.Length]; + } + + foreach (var f in frameList) + { + FetchFrameConstantBindStats[] constants = f.stats.constants; + for (var s = (int)ShaderStageType.First; s < (int)ShaderStageType.Count; s++) + { + totalConstantsPerStage[s].calls += constants[s].calls; + totalConstantsPerStage[s].sets += constants[s].sets; + totalConstantsPerStage[s].nulls += constants[s].nulls; + + System.Diagnostics.Debug.Assert(totalConstantsPerStage[s].slots.Length == constants[s].slots.Length); + for (var l = 0; l < constants[s].slots.Length; l++) + { + totalConstantsPerStage[s].slots[l] += constants[s].slots[l]; + } + + System.Diagnostics.Debug.Assert(totalConstantsPerStage[s].sizes.Length == constants[s].sizes.Length); + for (var z = 0; z < constants[s].sizes.Length; z++) + { + totalConstantsPerStage[s].sizes[z] += constants[s].sizes[z]; + } + } + } + + FetchFrameConstantBindStats totalConstantsForAllStages = new FetchFrameConstantBindStats(); + totalConstantsForAllStages.slots = new UInt32[totalConstantsPerStage[0].slots.Length]; + totalConstantsForAllStages.sizes = new UInt32[totalConstantsPerStage[0].sizes.Length]; + + for (var s = (int)ShaderStageType.First; s < (int)ShaderStageType.Count; s++) + { + FetchFrameConstantBindStats perStage = totalConstantsPerStage[s]; + totalConstantsForAllStages.calls += perStage.calls; + totalConstantsForAllStages.sets += perStage.sets; + totalConstantsForAllStages.nulls += perStage.nulls; + for (var l = 0; l < perStage.slots.Length; l++) + { + totalConstantsForAllStages.slots[l] += perStage.slots[l]; + } + for (var z = 0; z < perStage.sizes.Length; z++) + { + totalConstantsForAllStages.sizes[z] += perStage.sizes[z]; + } + } + + statisticsLog.AppendText("\n*** Constant Bind Statistics ***\n\n"); + + for (var s = (int)ShaderStageType.First; s < (int)ShaderStageType.Count; s++) + { + statisticsLog.AppendText(String.Format("{0} calls: {1}, non-null buffer sets: {2}, null buffer sets: {3}\n", + m_Core.CurPipelineState.Abbrev((ShaderStageType)s), totalConstantsPerStage[s].calls, + totalConstantsPerStage[s].sets, totalConstantsPerStage[s].nulls)); + } + + statisticsLog.AppendText(String.Format("Total calls: {0}, non-null buffer sets: {1}, null buffer sets: {2}\n", + totalConstantsForAllStages.calls, totalConstantsForAllStages.sets, totalConstantsForAllStages.nulls)); + + statisticsLog.AppendText("\nHistogram of aggregate slot counts per invocation across all stages:\n"); + UInt32 maxCount = 0; + int maxWithValue = 0; + for (var s = 1; s < totalConstantsForAllStages.slots.Length; s++) + { + UInt32 value = totalConstantsForAllStages.slots[s]; + if (value > 0) + maxWithValue = s; + maxCount = Math.Max(maxCount, value); + } + + for (var s = 1; s <= maxWithValue; s++) + { + UInt32 count = totalConstantsForAllStages.slots[s]; + int slice = SliceForString(Stars, count, maxCount); + statisticsLog.AppendText(String.Format("{0,2}: {1} {2}\n", s, Stars.Substring(0, slice), CountOrEmpty(count))); + } + + statisticsLog.AppendText("\nHistogram of aggregate constant buffer sizes across all stages:\n"); + maxCount = 0; + maxWithValue = 0; + for (var s = 0; s < totalConstantsForAllStages.sizes.Length; s++) + { + UInt32 value = totalConstantsForAllStages.sizes[s]; + if (value > 0) + maxWithValue = s; + maxCount = Math.Max(maxCount, value); + } + + for (var s = 0; s <= maxWithValue; s++) + { + UInt32 count = totalConstantsForAllStages.sizes[s]; + int slice = SliceForString(Stars, count, maxCount); + statisticsLog.AppendText(String.Format("{0,8}: {1} {2}\n", Pow2IndexAsReadable(s), Stars.Substring(0, slice), CountOrEmpty(count))); + } + } + + private void AppendSamplerBindStatistics(FetchFrameInfo[] frameList) + { + // #mivance see AppendConstantBindStatistics + FetchFrameSamplerBindStats template = frameList[0].stats.samplers[0]; + + FetchFrameSamplerBindStats[] totalSamplersPerStage = new FetchFrameSamplerBindStats[(int)ShaderStageType.Count]; + for (var s = (int)ShaderStageType.First; s < (int)ShaderStageType.Count; s++) + { + totalSamplersPerStage[s] = new FetchFrameSamplerBindStats(); + totalSamplersPerStage[s].slots = new UInt32[template.slots.Length]; + } + + foreach (var f in frameList) + { + FetchFrameSamplerBindStats[] resources = f.stats.samplers; + for (var s = (int)ShaderStageType.First; s < (int)ShaderStageType.Count; s++) + { + totalSamplersPerStage[s].calls += resources[s].calls; + totalSamplersPerStage[s].sets += resources[s].sets; + totalSamplersPerStage[s].nulls += resources[s].nulls; + + System.Diagnostics.Debug.Assert(totalSamplersPerStage[s].slots.Length == resources[s].slots.Length); + for (var l = 0; l < resources[s].slots.Length; l++) + { + totalSamplersPerStage[s].slots[l] += resources[s].slots[l]; + } + } + } + + FetchFrameSamplerBindStats totalSamplersForAllStages = new FetchFrameSamplerBindStats(); + totalSamplersForAllStages.slots = new UInt32[totalSamplersPerStage[0].slots.Length]; + + for (var s = (int)ShaderStageType.First; s < (int)ShaderStageType.Count; s++) + { + FetchFrameSamplerBindStats perStage = totalSamplersPerStage[s]; + totalSamplersForAllStages.calls += perStage.calls; + totalSamplersForAllStages.sets += perStage.sets; + totalSamplersForAllStages.nulls += perStage.nulls; + for (var l = 0; l < perStage.slots.Length; l++) + { + totalSamplersForAllStages.slots[l] += perStage.slots[l]; + } + } + + statisticsLog.AppendText("\n*** Sampler Bind Statistics ***\n\n"); + + for (var s = (int)ShaderStageType.First; s < (int)ShaderStageType.Count; s++) + { + statisticsLog.AppendText(String.Format("{0} calls: {1}, non-null sampler sets: {2}, null sampler sets: {3}\n", + m_Core.CurPipelineState.Abbrev((ShaderStageType)s), totalSamplersPerStage[s].calls, + totalSamplersPerStage[s].sets, totalSamplersPerStage[s].nulls)); + } + + statisticsLog.AppendText(String.Format("Total calls: {0}, non-null sampler sets: {1}, null sampler sets: {2}\n", + totalSamplersForAllStages.calls, totalSamplersForAllStages.sets, totalSamplersForAllStages.nulls)); + + statisticsLog.AppendText("\nHistogram of aggregate slot counts per invocation across all stages:\n"); + UInt32 maxCount = 0; + int maxWithValue = 0; + for (var s = 1; s < totalSamplersForAllStages.slots.Length; s++) + { + UInt32 value = totalSamplersForAllStages.slots[s]; + if (value > 0) + maxWithValue = s; + maxCount = Math.Max(maxCount, value); + } + + for (var s = 1; s <= maxWithValue; s++) + { + UInt32 count = totalSamplersForAllStages.slots[s]; + int slice = SliceForString(Stars, count, maxCount); + statisticsLog.AppendText(String.Format("{0,2}: {1} {2}\n", s, Stars.Substring(0, slice), CountOrEmpty(count))); + } + } + + private void AppendResourceBindStatistics(FetchFrameInfo[] frameList) + { + System.Diagnostics.Debug.Assert(frameList.Length > 0); + + // #mivance see AppendConstantBindStatistics + FetchFrameResourceBindStats template = frameList[0].stats.resources[0]; + + FetchFrameResourceBindStats[] totalResourcesPerStage = new FetchFrameResourceBindStats[(int)ShaderStageType.Count]; + for (var s = (int)ShaderStageType.First; s < (int)ShaderStageType.Count; s++) + { + totalResourcesPerStage[s] = new FetchFrameResourceBindStats(); + totalResourcesPerStage[s].types = new UInt32[template.types.Length]; + totalResourcesPerStage[s].slots = new UInt32[template.slots.Length]; + } + + foreach (var f in frameList) + { + FetchFrameResourceBindStats[] resources = f.stats.resources; + for (var s = (int)ShaderStageType.First; s < (int)ShaderStageType.Count; s++) + { + totalResourcesPerStage[s].calls += resources[s].calls; + totalResourcesPerStage[s].sets += resources[s].sets; + totalResourcesPerStage[s].nulls += resources[s].nulls; + + System.Diagnostics.Debug.Assert(totalResourcesPerStage[s].types.Length == resources[s].types.Length); + for (var z = 0; z < resources[s].types.Length; z++) + { + totalResourcesPerStage[s].types[z] += resources[s].types[z]; + } + + System.Diagnostics.Debug.Assert(totalResourcesPerStage[s].slots.Length == resources[s].slots.Length); + for (var l = 0; l < resources[s].slots.Length; l++) + { + totalResourcesPerStage[s].slots[l] += resources[s].slots[l]; + } + } + } + + FetchFrameResourceBindStats totalResourcesForAllStages = new FetchFrameResourceBindStats(); + totalResourcesForAllStages.types = new UInt32[totalResourcesPerStage[0].types.Length]; + totalResourcesForAllStages.slots = new UInt32[totalResourcesPerStage[0].slots.Length]; + + for (var s = (int)ShaderStageType.First; s < (int)ShaderStageType.Count; s++) + { + FetchFrameResourceBindStats perStage = totalResourcesPerStage[s]; + totalResourcesForAllStages.calls += perStage.calls; + totalResourcesForAllStages.sets += perStage.sets; + totalResourcesForAllStages.nulls += perStage.nulls; + for (var t = 0; t < perStage.types.Length; t++) + { + totalResourcesForAllStages.types[t] += perStage.types[t]; + } + for (var l = 0; l < perStage.slots.Length; l++) + { + totalResourcesForAllStages.slots[l] += perStage.slots[l]; + } + } + + statisticsLog.AppendText("\n*** Resource Bind Statistics ***\n\n"); + + for (var s = (int)ShaderStageType.First; s < (int)ShaderStageType.Count; s++) + { + statisticsLog.AppendText(String.Format("{0} calls: {1} non-null resource sets: {2} null resource sets: {3}\n", + m_Core.CurPipelineState.Abbrev((ShaderStageType)s), totalResourcesPerStage[s].calls, + totalResourcesPerStage[s].sets, totalResourcesPerStage[s].nulls)); + } + + statisticsLog.AppendText(String.Format("Total calls: {0} non-null resource sets: {1} null resource sets: {2}\n", + totalResourcesForAllStages.calls, totalResourcesForAllStages.sets, + totalResourcesForAllStages.nulls)); + + UInt32 maxCount = 0; + int maxWithCount = 0; + + statisticsLog.AppendText("\nHistogram of resource types across all stages:\n"); + for (var s = 0; s < totalResourcesForAllStages.types.Length; s++) + { + UInt32 count = totalResourcesForAllStages.types[s]; + if (count > 0) + maxWithCount = s; + maxCount = Math.Max(maxCount, count); + } + + for (var s = 0; s <= maxWithCount; s++) + { + UInt32 count = totalResourcesForAllStages.types[s]; + int slice = SliceForString(Stars, count, maxCount); + ShaderResourceType type = (ShaderResourceType)s; + statisticsLog.AppendText(String.Format("{0,16}: {1} {2}\n", type.ToString(), Stars.Substring(0, slice), CountOrEmpty(count))); + } + + maxCount = 0; + maxWithCount = 0; + + statisticsLog.AppendText("\nHistogram of aggregate slot counts per invocation across all stages:\n"); + for (var s = 1; s < totalResourcesForAllStages.slots.Length; s++) + { + UInt32 count = totalResourcesForAllStages.slots[s]; + if (count > 0) + maxWithCount = s; + maxCount = Math.Max(maxCount, count); + } + + for (var s = 1; s <= maxWithCount; s++) + { + UInt32 count = totalResourcesForAllStages.slots[s]; + int slice = SliceForString(Stars, count, maxCount); + statisticsLog.AppendText(String.Format("{0,3}: {1} {2}\n", s, Stars.Substring(0, slice), CountOrEmpty(count))); + } + } + + private void AppendUpdateStatistics(FetchFrameInfo[] frameList) + { + // #mivance see AppendConstantBindStatistics + FetchFrameUpdateStats template = frameList[0].stats.updates; + + FetchFrameUpdateStats totalUpdates = new FetchFrameUpdateStats(); + totalUpdates.types = new UInt32[template.types.Length]; + totalUpdates.sizes = new UInt32[template.sizes.Length]; + + foreach (var f in frameList) + { + FetchFrameUpdateStats updates = f.stats.updates; + + totalUpdates.calls += updates.calls; + totalUpdates.clients += updates.clients; + totalUpdates.servers += updates.servers; + + System.Diagnostics.Debug.Assert(totalUpdates.types.Length == updates.types.Length); + for (var t = 0; t < updates.types.Length; t++) + totalUpdates.types[t] += updates.types[t]; + + System.Diagnostics.Debug.Assert(totalUpdates.sizes.Length == updates.sizes.Length); + for (var t = 0; t < updates.sizes.Length; t++) + totalUpdates.sizes[t] += updates.sizes[t]; + } + + statisticsLog.AppendText("\n*** Resource Update Statistics ***\n\n"); + + statisticsLog.AppendText(String.Format("Total calls: {0}, client-updated memory: {1}, server-updated memory: {2}\n", totalUpdates.calls, totalUpdates.clients, totalUpdates.servers)); + + statisticsLog.AppendText("\nHistogram of updated resource type:\n"); + UInt32 maxCount = 0; + int maxWithValue = 0; + for (var s = 1; s < totalUpdates.types.Length; s++) + { + UInt32 value = totalUpdates.types[s]; + if (value > 0) + maxWithValue = s; + maxCount = Math.Max(maxCount, value); + } + + for (var s = 1; s <= maxWithValue; s++) + { + UInt32 count = totalUpdates.types[s]; + int slice = SliceForString(Stars, count, maxCount); + ShaderResourceType type = (ShaderResourceType)s; + statisticsLog.AppendText(String.Format("{0,16}: {1} {2}\n", type.ToString(), Stars.Substring(0, slice), CountOrEmpty(count))); + } + + statisticsLog.AppendText("\nHistogram of updated resource size:\n"); + maxCount = 0; + maxWithValue = 0; + for (var s = 0; s < totalUpdates.sizes.Length; s++) + { + UInt32 value = totalUpdates.sizes[s]; + if (value > 0) + maxWithValue = s; + maxCount = Math.Max(maxCount, value); + } + + for (var s = 0; s <= maxWithValue; s++) + { + UInt32 count = totalUpdates.sizes[s]; + int slice = SliceForString(Stars, count, maxCount); + statisticsLog.AppendText(String.Format("{0,8}: {1} {2}\n", Pow2IndexAsReadable(s), Stars.Substring(0, slice), CountOrEmpty(count))); + } + } + + private void AppendDetailedInformation(FetchFrameInfo[] frameList) + { + AppendDrawStatistics(frameList); + AppendDispatchStatistics(frameList); + AppendInputAssemblerStatistics(frameList); + AppendConstantBindStatistics(frameList); + AppendSamplerBindStatistics(frameList); + AppendResourceBindStatistics(frameList); + AppendUpdateStatistics(frameList); + } + + private void CountContributingEvents(FetchDrawcall draw, ref uint drawCount, ref uint dispatchCount, ref uint diagnosticCount) + { + const uint diagnosticMask = (uint)DrawcallFlags.SetMarker | (uint)DrawcallFlags.PushMarker | (uint)DrawcallFlags.PopMarker; + uint diagnosticMasked = (uint)draw.flags & diagnosticMask; + + if (diagnosticMasked != 0) + diagnosticCount += 1; + + if ((draw.flags & DrawcallFlags.Drawcall) != 0) + drawCount += 1; + + if ((draw.flags & DrawcallFlags.Dispatch) != 0) + dispatchCount += 1; + + if (draw.children != null) + { + foreach (var c in draw.children) + CountContributingEvents(c, ref drawCount, ref dispatchCount, ref diagnosticCount); + } + } + + public void OnLogfileLoaded() + { + statisticsLog.Clear(); + + long fileSize = (new FileInfo(m_Core.LogFileName)).Length; + + int firstIdx = 0; + + var firstDrawcall = m_Core.CurDrawcalls[firstIdx]; + while (firstDrawcall.children != null && firstDrawcall.children.Length > 0) + firstDrawcall = firstDrawcall.children[0]; + + while (firstDrawcall.events.Length == 0) + { + if (firstDrawcall.next != null) + { + firstDrawcall = firstDrawcall.next; + while (firstDrawcall.children != null && firstDrawcall.children.Length > 0) + firstDrawcall = firstDrawcall.children[0]; + } + else + { + firstDrawcall = m_Core.CurDrawcalls[++firstIdx]; + while (firstDrawcall.children != null && firstDrawcall.children.Length > 0) + firstDrawcall = firstDrawcall.children[0]; + } + } + + UInt64 persistentData = (UInt64)fileSize - firstDrawcall.events[0].fileOffset; + + var lastDraw = m_Core.CurDrawcalls[m_Core.CurDrawcalls.Length - 1]; + while (lastDraw.children != null && lastDraw.children.Length > 0) + lastDraw = lastDraw.children[lastDraw.children.Length - 1]; + + uint drawCount = 0; + uint dispatchCount = 0; + uint diagnosticCount = 0; + foreach (var d in m_Core.CurDrawcalls) + CountContributingEvents(d, ref drawCount, ref dispatchCount, ref diagnosticCount); + + uint numAPIcalls = lastDraw.eventID - diagnosticCount; + + // #mivance only recording this for comparison vis a vis draw call + // iteration, we want to preserve the old stats data for the + // backends which aren't recording statistics + bool statsRecorded = false; + uint numDraws = 0; + uint numDispatches = 0; + uint numIndexVertexSets = 0; + uint numConstantSets = 0; + uint numSamplerSets = 0; + uint numResourceSets = 0; + uint numResourceUpdates = 0; + + FetchFrameInfo[] frameList = m_Core.FrameInfo; + + foreach (var f in frameList) + { + if (f.stats.recorded == 0) + continue; + + statsRecorded = true; + + for (var s = (int)ShaderStageType.First; s < (int)ShaderStageType.Count; s++) + { + numConstantSets += f.stats.constants[s].calls; + numSamplerSets += f.stats.samplers[s].calls; + numResourceSets += f.stats.resources[s].calls; + } + + numResourceUpdates += f.stats.updates.calls; + numIndexVertexSets += (f.stats.indices.calls + f.stats.vertices.calls + f.stats.layouts.calls); + numDraws += f.stats.draws.calls; + numDispatches += f.stats.dispatches.calls; + } + + int numTextures = m_Core.CurTextures.Length; + int numBuffers = m_Core.CurBuffers.Length; + + ulong IBBytes = 0; + ulong VBBytes = 0; + ulong BufBytes = 0; + foreach (var b in m_Core.CurBuffers) + { + BufBytes += b.byteSize; + + if ((b.creationFlags & BufferCreationFlags.IB) != 0) + IBBytes += b.byteSize; + if ((b.creationFlags & BufferCreationFlags.VB) != 0) + VBBytes += b.byteSize; + } + + ulong RTBytes = 0; + ulong TexBytes = 0; + ulong LargeTexBytes = 0; + + int numRTs = 0; + float texW = 0, texH = 0; + float largeTexW = 0, largeTexH = 0; + int texCount = 0, largeTexCount = 0; + foreach (var t in m_Core.CurTextures) + { + if ((t.creationFlags & (TextureCreationFlags.RTV | TextureCreationFlags.DSV)) != 0) + { + numRTs++; + + RTBytes += t.byteSize; + } + else + { + texW += (float)t.width; + texH += (float)t.height; + texCount++; + + TexBytes += t.byteSize; + + if (t.width > 32 && t.height > 32) + { + largeTexW += (float)t.width; + largeTexH += (float)t.height; + largeTexCount++; + + LargeTexBytes += t.byteSize; + } + } + } + + texW /= texCount; + texH /= texCount; + + largeTexW /= largeTexCount; + largeTexH /= largeTexCount; + + string header = String.Format("Stats for {0}.\n\nFile size: {1:N2}MB\nPersistent Data (approx): {2:N2}MB\n", + Path.GetFileName(m_Core.LogFileName), + (float)fileSize / (1024.0f * 1024.0f), (float)persistentData / (1024.0f * 1024.0f)); + string draws = String.Format("Draw calls: {0}\nDispatch calls: {1}\n", + drawCount, dispatchCount); + string calls = statsRecorded ? String.Format("API calls: {0}\n\tIndex/vertex bind calls: {1}\n\tConstant bind calls: {2}\n\tSampler bind calls: {3}\n\tResource bind calls: {4}\n\tResource update calls: {5}\n", + numAPIcalls, numIndexVertexSets, numConstantSets, numSamplerSets, numResourceSets, numResourceUpdates) : ""; + string ratio = String.Format("API:Draw call ratio: {0}\n\n", (float)numAPIcalls / (float)drawCount); + string textures = String.Format("{0} Textures - {1:N2} MB ({2:N2} MB over 32x32), {3} RTs - {4:N2} MB.\nAvg. tex dimension: {5}x{6} ({7}x{8} over 32x32)\n", + numTextures, (float)TexBytes / (1024.0f * 1024.0f), (float)LargeTexBytes / (1024.0f * 1024.0f), + numRTs, (float)RTBytes / (1024.0f * 1024.0f), + texW, texH, largeTexW, largeTexH); + string buffers = String.Format("{0} Buffers - {1:N2} MB total {2:N2} MB IBs {3:N2} MB VBs.\n", + numBuffers, (float)BufBytes / (1024.0f * 1024.0f), (float)IBBytes / (1024.0f * 1024.0f), (float)VBBytes / (1024.0f * 1024.0f)); + string load = String.Format("{0} MB - Grand total GPU buffer + texture load.\n", (float)(TexBytes + BufBytes + RTBytes) / (1024.0f * 1024.0f)); + + statisticsLog.AppendText(header); + + statisticsLog.AppendText("\n*** Summary ***\n\n"); + statisticsLog.AppendText(draws); + statisticsLog.AppendText(calls); + statisticsLog.AppendText(ratio); + statisticsLog.AppendText(textures); + statisticsLog.AppendText(buffers); + statisticsLog.AppendText(load); + + if (statsRecorded) + AppendDetailedInformation(frameList); + + statisticsLog.Select(0, 0); + } + + public void OnEventSelected(UInt32 frameID, UInt32 eventID) + { + + } + + private void StatisticsViewer_Load(object sender, EventArgs e) + { + + } + } +} diff --git a/renderdocui/Windows/StatisticsViewer.resx b/renderdocui/Windows/StatisticsViewer.resx new file mode 100644 index 000000000..1af7de150 --- /dev/null +++ b/renderdocui/Windows/StatisticsViewer.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/renderdocui/renderdocui.csproj b/renderdocui/renderdocui.csproj index 0b3845a4e..618e13199 100644 --- a/renderdocui/renderdocui.csproj +++ b/renderdocui/renderdocui.csproj @@ -325,6 +325,12 @@ ShaderViewer.cs + + Form + + + StatisticsViewer.cs + Form @@ -433,6 +439,9 @@ ShaderViewer.cs + + StatisticsViewer.cs + TextureViewer.cs