GPU Memory Tracking

Overview

In version 1.40, Prysm introduces GPU memory tracking. This comes with the ability to extract detailed information about the allocated GPU memory in the Library and the ability to reset the GPU memory peaks. That makes it easier to check the memory statistics of the allocated resources.

NOTE This API is only available in a Developer configuration.

This page provides details about the feature, a list of everything we track, a sample of how to obtain the information, as well as a few general considerations for extracting the information.

How to extract GPU memory information

We have developed a structure to hold the GPU memory data called GPUMemoryInfo, which can be filled with all the tracked information using the help of the GetGPUMemoryStats() method found in the Library. As for user textures, which are tracked separately from the rest of the GPU memory, the cohtml::UserGPUMemoryInfo* Library::GetUserGPUMemoryStats() method can be used to retrieve their information, which is encapsulated in a different structure called UserGPUMemoryInfo. The GPUMemoryInfo::Release() method must be called on the returned cohtml::GPUMemoryInfo* or cohtml::UserGPUMemoryInfo* pointer to free its allocated memory. The statistics from the Library include all shared resources across the Views. A list of every member in the GPUMemoryInfo and UserGPUMemoryInfo structures along with a description of what each member tracks is provided below.

How to reset GPU memory peaks

In order to reset the accumulated memory peaks to match the current state, the ResetGPUMemoryTrackerPeaks() method of the Library needs to be invoked. Resetting the peaks of the Library will also reset the user textures' peaks.

A list of all the monitored GPU memory data

GPUMemoryInfo structure

MemberDescription
size_t TotalBytes;The total GPU memory
size_t PeakBytes;The highest GPU memory reached
TextureInfo TexturesInformation[renoir::domains::TextureType::TT_Count];An array of TextureInfo objects containing all tracked textures' information separated by their TextureType
BufferInfo BuffersInformation[renoir::domains::BufferType::BT_Count];An array of BufferInfo objects containing all tracked buffers' information separated by their BufferType
ExtraColorImageTexturesInfo ExtraColorImageTexturesInformation;An array of additional information about the texture, like it’s name and which views it is used in. The ArraySize member is equal to TexturesInformation[renoir::domains::TextureType::TT_ColorTexture].ResourceArray[renoir::domains::TextureDomain::T_ImageTexture].ArraySize, so the index used to iterate the image color textures can be directly used to iterate the extra information.

In-depth description of TexturesInformation’s members

MemberDescription
TexturesInformation[TextureType]Texture statistics by TextureType. Array size is TextureType::TT_Count
TexturesInformation[TextureType].Total.BytesThe total GPU memory of all textures from the specified TextureType
TexturesInformation[TextureType].Total.CountThe count of all current textures from the specified TextureType
TexturesInformation[TextureType].Peak.BytesThe highest reached GPU memory of all textures from the specified TextureType
TexturesInformation[TextureType].Peak.CountThe highest reached count of all textures from the specified TextureType
TexturesInformation[TextureType].ResourceArray[TextureDomain]Texture statistics by TextureDomain. Array size is TextureDomain::T_Count
TexturesInformation[TextureType].ResourceArray[TextureDomain].Total.BytesThe total GPU memory of all textures from the specified TextureDomain and TextureType
TexturesInformation[TextureType].ResourceArray[TextureDomain].Total.CountThe count of all current textures from the specified TextureDomain and TextureType
TexturesInformation[TextureType].ResourceArray[TextureDomain].Peak.BytesThe highest reached GPU memory of all textures from the specified TextureDomain and TextureType
TexturesInformation[TextureType].ResourceArray[TextureDomain].Peak.CountThe highest reached count of all textures from the specified TextureDomain and TextureType
TexturesInformation[TextureType].ResourceArray[TextureDomain].ArrayTexture statistics of all current textures from the specified TextureDomain and TextureType
TexturesInformation[TextureType].ResourceArray[TextureDomain].ArraySizeThe Array size. Same as TexturesInformation[TextureType].ResourceArray[TextureDomain].Total.Count
TexturesInformation[TextureType].ResourceArray[TextureDomain].Array[ind].IdThe texture’s ID
TexturesInformation[TextureType].ResourceArray[TextureDomain].Array[ind].BytesThe texture’s size
TexturesInformation[TextureType].ResourceArray[TextureDomain].Array[ind].OwnerIdThe texture’s scene ID. If it instead belongs to the Library, the ID will equal unsigned(-1) aka RENOIR_INVALID

In-depth description of BuffersInformation’s members

MemberDescription
BuffersInformation[BufferType]Buffer statistics by BufferType. Array size is BufferType::BT_Count
BuffersInformation[BufferType].Total.BytesThe total GPU memory of all buffers from the specified BufferType
BuffersInformation[BufferType].Total.CountThe count of all current buffers from the specified BufferType
BuffersInformation[BufferType].Peak.BytesThe highest reached GPU memory of all buffers from the specified BufferType
BuffersInformation[BufferType].Peak.CountThe highest reached count of all buffers from the specified BufferType
BuffersInformation[BufferType].ResourceArray[MAX_BUFFER_DOMAIN_COUNT]Buffer statistics by domain for the specified BufferType. Size is indicated by the buffer domain’s count (IB_Count, VB_Count, CB_Count)
BuffersInformation[BufferType].ResourceArray[BufferDomain].Total.BytesThe total GPU memory of all buffers from the specified BufferDomain and BufferType
BuffersInformation[BufferType].ResourceArray[BufferDomain].Total.CountThe count of all current buffers from the specified BufferDomain and BufferType
BuffersInformation[BufferType].ResourceArray[BufferDomain].Peak.BytesThe highest reached allocated GPU memory of all buffers from the specified BufferDomain and BufferType
BuffersInformation[BufferType].ResourceArray[BufferDomain].Peak.CountThe highest reached count of all buffers from the specified BufferDomain and BufferType
BuffersInformation[BufferType].ResourceArray[BufferDomain].ArrayBuffer statistics of all current buffers from the specified BufferDomain and BufferType
BuffersInformation[BufferType].ResourceArray[BufferDomain].ArraySizeThe Array size. Same as TexturesInformation[TextureType].ResourceArray[TextureDomain].Total.Count
BuffersInformation[BufferType].ResourceArray[BufferDomain].Array[ind].IdThe buffer’s ID
BuffersInformation[BufferType].ResourceArray[BufferDomain].Array[ind].BytesThe buffer’s allocated size
BuffersInformation[BufferType].ResourceArray[BufferDomain].Array[ind].PeakUsageBytesThe highest amount of bytes used from the buffer’s allocated memory
BuffersInformation[BufferType].ResourceArray[BufferDomain].Array[ind].OwnerIdThe buffer’s scene ID. If it instead belongs to the Library, the ID will equal unsigned(-1) aka RENOIR_INVALID

In-depth description of ExtraColorImageTexturesInformation’s members

MemberDescription
ExtraColorImageTexturesInformation.Array[ind].NameThe name of the texture
ExtraColorImageTexturesInformation.Array[ind].ViewClientsCountThe total amount of views this texture is registered in
ExtraColorImageTexturesInformation.Array[ind].ViewClientsThe array of views this texture is registered in

UserGPUMemoryInfo structure

MemberDescription
UserTexturesInfo UserTextureInformationContains information for all tracked user textures
RenderTargetInfo RenderTargetInformation[renoir::domains::TextureType::TT_Count]An array of RenderTargetInfo objects containing all tracked render targets' information separated by their TextureType
ExtraUserImageInfo ExtraUserImageInformationContains additional information about an image, such as it’s name and how many views it is used in

In-depth description of the UserTexturesInfo’s members

MemberDescription
GPUMemoryInfo::MemoryInfo TotalUsageTotal GPU memory used by user images
GPUMemoryInfo::MemoryInfo PeakUsagePeak GPU memory used by user images
GPUMemoryInfo::MemoryInfo TotalTotal GPU memory used by user objects (explanation here)
GPUMemoryInfo::MemoryInfo PeakPeak GPU memory used by user objects (explanation here)
size_t ArraySizeSize of Array
UserTextureInformation.Array[ind].IdThe user texture’s ID
UserTextureInformation.Array[ind].OwnerIdThe user texture’s owner. All user textures belong to the Library, so the ID equals unsigned(-1) aka RENOIR_INVALID
UserTextureInformation.Array[ind].BytesThe size of the user texture in bytes
UserTextureInformation.Array[ind].UserObjectThe user object data itself
UserTextureInformation.Array[ind].UserObjectBytesThe size of the user object data in bytes

In-depth description of the RenderTargetInfo’s members

MemberDescription
GPUMemoryInfo::MemoryInfo TotalThe total render targets' GPU memory (Total.Bytes) and their current count (Total.Count)
GPUMemoryInfo::MemoryInfo PeakThe highest reached render targets' GPU memory (Peak.Bytes) and the hightest reached peaks count (Peak.Count)
size_t ArraySize;Size of Array
RenderTargetInformation.Array[ind].IdThe render target’s ID
RenderTargetInformation.Array[ind].OwnerIdThe render target’s owner
RenderTargetInformation.Array[ind].BytesThe size of the render target in bytes
RenderTargetInformation.Array[ind].UserObjectThe actual data
RenderTargetInformation.Array[ind].WidthThe width of the render target
RenderTargetInformation.Array[ind].HeightThe height of the render target
RenderTargetInformation.Array[ind].SamplesCountThe sample count

In-depth description of the ExtraUserImageInfo’s members

MemberDescription
size_t ArraySize;Size of Array
ExtraUserImageInformation.Array[ind].NameThe name of the user image
ExtraUserImageInformation.Array[ind].ViewClientsCountThe total amount of views this user image is registered in
ExtraUserImageInformation.Array[ind].ViewClientsThe array of views this user image is registered in

Resource domains

namespace domains
{
	enum TextureType
	{
		TT_ColorTexture = 0,
		TT_DepthTexture,
		TT_Count
	};

	enum BufferType
	{
		BT_IndexBuffer = 0,
		BT_VertexBuffer,
		BT_ConstantBuffer,
		BT_Count
	};

	enum TextureDomain
	{
		T_ScratchTexture = 0,
		T_LayerTexture,
		T_ImageTexture,
		T_SurfaceTexture,
		T_CompositorTexture,
		T_GlyphAtlas,
		T_GradientCacheTexture,
		T_Count
	};

	enum VBDomain                           // Vertex Buffer Domain
	{
		VB_GeometryBuffer = 0,
		VB_PathBuffer,
		VB_GlyphBuffer,
		VB_Count
	};

	enum IBDomain                           // Index Buffer Domain
	{
		IB_GeometryBuffer = 0,
		IB_PathBuffer,
		IB_GlyphBuffer,
		IB_Count
	};

	enum CBDomain                           // Constant Buffer Domain (same as CBType)
	{
		// Vertex shader CBs
		CB_DataVS,

		// Pixel shader CBs
		CB_DataPS,

		CB_Count
	};
}

Example GPU memory information extraction and display

Below are example functions that show how to display GPU memory information.

void PrintToLog(const cohtml::GPUMemoryInfo* memoryStats)
{
	std::ostringstream oss;
	oss << "---------- Total GPU Memory Stats ----------" << std::endl;
	oss << "\tTotal GPU Memory: " << memoryStats->TotalBytes << " bytes" << std::endl;
	oss << "\tPeak GPU Memory: " << memoryStats->PeakBytes << " bytes" << std::endl;

	oss << "\t> Main textures memory info:" << std::endl;
	oss << "\tTotal color textures memory: " << memoryStats->TexturesInformation[renoir::domains::TT_ColorTexture].Total.Bytes << " bytes" << std::endl;
	oss << "\tTotal depth textures memory: " << memoryStats->TexturesInformation[renoir::domains::TT_DepthTexture].Total.Bytes << " bytes" << std::endl;
	oss << "\tPeak color textures memory: " << memoryStats->TexturesInformation[renoir::domains::TT_ColorTexture].Peak.Bytes << " bytes" << std::endl;
	oss << "\tPeak depth textures memory: " << memoryStats->TexturesInformation[renoir::domains::TT_DepthTexture].Peak.Bytes << " bytes" << std::endl;

	oss << "\t> Main buffers memory info:" << std::endl;
	oss << "\tTotal Index Buffers memory: " << memoryStats->BuffersInformation[renoir::domains::BT_IndexBuffer].Total.Bytes << " bytes" << std::endl;
	oss << "\tTotal Vertex Buffers memory: " << memoryStats->BuffersInformation[renoir::domains::BT_VertexBuffer].Total.Bytes << " bytes" << std::endl;
	oss << "\tTotal Constant Buffers memory: " << memoryStats->BuffersInformation[renoir::domains::BT_ConstantBuffer].Total.Bytes << " bytes" << std::endl;
	oss << "\tPeak Index Buffers memory: " << memoryStats->BuffersInformation[renoir::domains::BT_IndexBuffer].Peak.Bytes << " bytes" << std::endl;
	oss << "\tPeak Vertex Buffers memory: " << memoryStats->BuffersInformation[renoir::domains::BT_VertexBuffer].Peak.Bytes << " bytes" << std::endl;
	oss << "\tPeak Constant Buffers memory: " << memoryStats->BuffersInformation[renoir::domains::BT_ConstantBuffer].Peak.Bytes << " bytes" << std::endl;

	oss << "\t> Textures count info:" << std::endl;
	oss << "\tTotal count of color textures: " << memoryStats->TexturesInformation[renoir::domains::TT_ColorTexture].Total.Count << std::endl;
	oss << "\tTotal count of depth textures: " << memoryStats->TexturesInformation[renoir::domains::TT_DepthTexture].Total.Count << std::endl;
	oss << "\tPeak count of color textures: " << memoryStats->TexturesInformation[renoir::domains::TT_ColorTexture].Peak.Count << std::endl;
	oss << "\tPeak count of depth textures: " << memoryStats->TexturesInformation[renoir::domains::TT_DepthTexture].Peak.Count << std::endl;

	oss << "\t> Buffers count info:" << std::endl;
	oss << "\tTotal count of Index Buffers: " << memoryStats->BuffersInformation[renoir::domains::BT_IndexBuffer].Total.Count << std::endl;
	oss << "\tTotal count of Vertex Buffers: " << memoryStats->BuffersInformation[renoir::domains::BT_VertexBuffer].Total.Count << std::endl;
	oss << "\tTotal count of Constant Buffers: " << memoryStats->BuffersInformation[renoir::domains::BT_ConstantBuffer].Total.Count << std::endl;
	oss << "\tPeak count of Index Buffers: " << memoryStats->BuffersInformation[renoir::domains::BT_IndexBuffer].Peak.Count << std::endl;
	oss << "\tPeak count of Vertex Buffers: " << memoryStats->BuffersInformation[renoir::domains::BT_VertexBuffer].Peak.Count << std::endl;
	oss << "\tPeak count of Constant Buffers: " << memoryStats->BuffersInformation[renoir::domains::BT_ConstantBuffer].Peak.Count << std::endl;

	const char* textureTypeStrings[] = { "Color", "Depth" };
	const char* textureStrings[] = { "Scratch Texture", "Layer Texture", "Image Texture", "Surface Texture", "Compositor Texture", "Glyph Atlase", "Gradient Cache Texture" };
	const char* bufferStrings[] = { "Index Geometry Buffer", "Index Path Buffer", "Index Glyph Buffer",
									"Vertex Geometry Buffer", "Vertex Path Buffer", "Vertex Path Instance Data Buffer", "Vertex Glyph Buffer",
									"VS Data Constant Buffer", "PS Data Constant Buffer" };

	APP_LOG(Info, oss.str().c_str());
	oss.str("");

	for (size_t texType = 0; texType < renoir::domains::TextureType::TT_Count; ++texType)
	{
		for (size_t texDomain = 0; texDomain < renoir::domains::TextureDomain::T_Count; ++texDomain)
		{
			oss << "\t> " << textureTypeStrings[texType] << " " << textureStrings[texDomain] << "s:" << std::endl;

			auto& domainInfo = memoryStats->TexturesInformation[texType].ResourceArray[texDomain];

			oss << "\tTotal memory: " << domainInfo.Total.Bytes << " bytes" << std::endl;
			oss << "\tTotal count: " << domainInfo.Total.Count << std::endl;
			oss << "\tPeak memory: " << domainInfo.Peak.Bytes << " bytes" << std::endl;
			oss << "\tPeak count: " << domainInfo.Peak.Count << std::endl;

			for (size_t i = 0; i < domainInfo.ArraySize; i++)
			{
				oss << "\tID: " << domainInfo.Array[i].Id << "; Owner: ";
				if (domainInfo.Array[i].OwnerId == RENOIR_INVALID)
				{
					oss << "Shared";
				}
				else
				{
					oss << domainInfo.Array[i].OwnerId;
				}
				oss << "; Size: " << domainInfo.Array[i].Bytes << " bytes";
				if (texType == renoir::domains::TextureType::TT_ColorTexture &&
					texDomain == renoir::domains::TextureDomain::T_ImageTexture &&
					memoryStats->ExtraColorImageTexturesInformation.Array[i].Name)
				{
					oss << "; View client IDs:";
					for (size_t viewCount = 0; viewCount < memoryStats->ExtraColorImageTexturesInformation.Array[i].ViewClientsCount; ++viewCount)
					{
						oss << " " << memoryStats->ExtraColorImageTexturesInformation.Array[i].ViewClients[viewCount];
					}
					oss << std::endl << "\t\tTexture Name: " << memoryStats->ExtraColorImageTexturesInformation.Array[i].Name << std::endl;
				}
				else
				{
					oss << std::endl;
				}
			}

			APP_LOG(Info, oss.str().c_str());
			oss.str("");
		}

	}

	for (size_t buffType = 0; buffType < renoir::domains::BufferType::BT_Count; ++buffType)
	{
		size_t buffDomainSize = buffType == renoir::domains::BufferType::BT_IndexBuffer ? renoir::domains::IB_Count :
			buffType == renoir::domains::BufferType::BT_VertexBuffer ? renoir::domains::VB_Count : renoir::CB_Count;

		size_t buffStringsStart = buffType == renoir::domains::BufferType::BT_IndexBuffer ? 0 :
			buffType == renoir::domains::BufferType::BT_VertexBuffer ? renoir::domains::IB_Count : renoir::domains::IB_Count + renoir::domains::VB_Count;

		for (size_t buffDomain = 0; buffDomain < buffDomainSize; buffDomain++)
		{
			oss << "\t> " << bufferStrings[buffStringsStart + buffDomain] << "s:" << std::endl;
			auto& domainInfo = memoryStats->BuffersInformation[buffType].ResourceArray[buffDomain];

			oss << "\tTotal memory: " << domainInfo.Total.Bytes << " bytes" << std::endl;
			oss << "\tTotal count: " << domainInfo.Total.Count << std::endl;
			oss << "\tPeak memory: " << domainInfo.Peak.Bytes << " bytes" << std::endl;
			oss << "\tPeak count: " << domainInfo.Peak.Count << std::endl;

			for (size_t i = 0; i < domainInfo.ArraySize; i++)
			{
				oss << "\tID: " << domainInfo.Array[i].Id << "; Owner: ";
				if (domainInfo.Array[i].OwnerId == RENOIR_INVALID)
				{
					oss << "Shared";
				}
				else
				{
					oss << domainInfo.Array[i].OwnerId;
				}
				oss << "; Size: " << domainInfo.Array[i].Bytes << " bytes";
				oss << "; Peak usage: " << domainInfo.Array[i].PeakUsageBytes << " bytes" << std::endl;
			}

			APP_LOG(Info, oss.str().c_str());
			oss.str("");
		}
	}
}

void PrintToLog(const cohtml::UserGPUMemoryInfo* memoryStats)
{
	TmpOSStream oss;
	oss << "\t---------- User GPU Memory Stats ----------" << std::endl;
	oss << "\tTotal GPU Memory: " << memoryStats->Total.Bytes << " bytes" << std::endl;
	oss << "\tPeak GPU Memory: " << memoryStats->Peak.Bytes << " bytes" << std::endl;
	oss << "\tTotal texture count: " << memoryStats->Total.Count << std::endl;
	oss << "\tPeak texture count: " << memoryStats->Peak.Count << std::endl;

	if (memoryStats->ArraySize > 0)
	{
		oss << "\t---------- Textures ----------" << std::endl;
	}

	for (size_t i = 0; i < memoryStats->ArraySize; i++)
	{
		const auto& texture = memoryStats->Array[i];
		oss << "\tID: " << texture.Id << ";\tSize: " << texture.Bytes << " bytes" << std::endl;
		oss << "\tName: " << texture.Name << std::endl;
		oss << "\tView Clients Count: " << texture.ViewClientsCount << std::endl;
		for (size_t viewCount = 0; viewCount < texture.ViewClientsCount; ++viewCount)
		{
			oss << "\tView Client Id: " << texture.ViewClients[viewCount] << std::endl;
		}
	}

	APP_LOG(Info, oss.str().c_str());
}

We have already implemented them and they can be used like this

void PrintGPUMemoryStats()
{
	auto combinedMemoryStats = m_CohtmlApp->GetLibrary()->GetGPUMemoryStats();
	if (combinedMemoryStats)
	{
		combinedMemoryStats->PrintToLog();
		combinedMemoryStats->Release();
	}
}

void PrintUserGPUMemoryStats()
{
	auto userMemoryStats = m_CohtmlApp->GetLibrary()->GetUserGPUMemoryStats();
	if (userMemoryStats)
	{
		userMemoryStats->PrintToLog();
		userMemoryStats->Release();
	}
}