浏览代码

GL: Add support for texture buffers

Panagiotis Christopoulos Charitos 8 年之前
父节点
当前提交
a71449d7fb

+ 1 - 0
src/anki/core/Config.cpp

@@ -83,6 +83,7 @@ Config::Config()
 	newOption("core.storagePerFrameMemorySize", 1024 * 1024 * 16);
 	newOption("core.vertexPerFrameMemorySize", 1024 * 1024 * 10);
 	newOption("core.transferPerFrameMemorySize", 1024 * 1024 * 128);
+	newOption("core.textureBufferPerFrameMemorySize", 1024 * 1024 * 1);
 }
 
 Config::~Config()

+ 4 - 0
src/anki/core/StagingGpuMemoryManager.cpp

@@ -30,6 +30,7 @@ Error StagingGpuMemoryManager::init(GrManager* gr, const ConfigSet& cfg)
 	m_perFrameBuffers[StagingGpuMemoryType::STORAGE].m_size = cfg.getNumber("core.storagePerFrameMemorySize");
 	m_perFrameBuffers[StagingGpuMemoryType::VERTEX].m_size = cfg.getNumber("core.vertexPerFrameMemorySize");
 	m_perFrameBuffers[StagingGpuMemoryType::TRANSFER].m_size = cfg.getNumber("core.transferPerFrameMemorySize");
+	m_perFrameBuffers[StagingGpuMemoryType::TEXTURE].m_size = cfg.getNumber("core.textureBufferPerFrameMemorySize");
 
 	U32 alignment;
 	PtrSize maxSize;
@@ -47,6 +48,9 @@ Error StagingGpuMemoryManager::init(GrManager* gr, const ConfigSet& cfg)
 		BufferUsageBit::BUFFER_UPLOAD_SOURCE | BufferUsageBit::TEXTURE_UPLOAD_SOURCE,
 		*gr);
 
+	gr->getTextureBufferInfo(alignment, maxSize);
+	initBuffer(StagingGpuMemoryType::TEXTURE, alignment, maxSize, BufferUsageBit::TEXTURE_ALL, *gr);
+
 	return ErrorCode::NONE;
 }
 

+ 1 - 0
src/anki/core/StagingGpuMemoryManager.h

@@ -23,6 +23,7 @@ enum class StagingGpuMemoryType
 	STORAGE,
 	VERTEX,
 	TRANSFER,
+	TEXTURE,
 	COUNT
 };
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(StagingGpuMemoryType, inline)

+ 3 - 0
src/anki/gr/CommandBuffer.h

@@ -251,6 +251,9 @@ public:
 	/// Bind load/store image.
 	void bindImage(U32 set, U32 binding, TexturePtr img, U32 level);
 
+	/// Bind texture buffer.
+	void bindTextureBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset, PtrSize range, PixelFormat fmt);
+
 	/// Bind a program.
 	void bindShaderProgram(ShaderProgramPtr prog);
 

+ 4 - 2
src/anki/gr/Common.h

@@ -157,6 +157,7 @@ const U MAX_TEXTURE_BINDINGS = 10;
 const U MAX_UNIFORM_BUFFER_BINDINGS = 5;
 const U MAX_STORAGE_BUFFER_BINDINGS = 4;
 const U MAX_IMAGE_BINDINGS = 4;
+const U MAX_TEXTURE_BUFFER_BINDINGS = 4;
 
 enum class DescriptorType : U8
 {
@@ -164,12 +165,13 @@ enum class DescriptorType : U8
 	UNIFORM_BUFFER,
 	STORAGE_BUFFER,
 	IMAGE,
+	TEXTURE_BUFFER,
 
 	COUNT
 };
 
-const U MAX_BINDINGS_PER_DESCRIPTOR_SET =
-	MAX_TEXTURE_BINDINGS + MAX_UNIFORM_BUFFER_BINDINGS + MAX_STORAGE_BUFFER_BINDINGS + MAX_IMAGE_BINDINGS;
+const U MAX_BINDINGS_PER_DESCRIPTOR_SET = MAX_TEXTURE_BINDINGS + MAX_UNIFORM_BUFFER_BINDINGS
+	+ MAX_STORAGE_BUFFER_BINDINGS + MAX_IMAGE_BINDINGS + MAX_TEXTURE_BUFFER_BINDINGS;
 
 const U MAX_FRAMES_IN_FLIGHT = 3; ///< Triple buffering.
 const U MAX_DESCRIPTOR_SETS = 2; ///< Groups that can be bound at the same time.

+ 21 - 10
src/anki/gr/Enums.h

@@ -341,7 +341,7 @@ enum class AttachmentStoreOperation : U8
 };
 
 /// Buffer usage modes.
-enum class BufferUsageBit : U32
+enum class BufferUsageBit : U64
 {
 	NONE = 0,
 
@@ -385,15 +385,26 @@ enum class BufferUsageBit : U32
 		| STORAGE_FRAGMENT_WRITE,
 	STORAGE_ALL = STORAGE_ALL_GRAPHICS | STORAGE_COMPUTE_READ_WRITE,
 
-	INDEX = 1 << 18,
-	VERTEX = 1 << 19,
-	INDIRECT = 1 << 20,
-
-	FILL = 1 << 21,
-	BUFFER_UPLOAD_SOURCE = 1 << 22,
-	BUFFER_UPLOAD_DESTINATION = 1 << 23, ///< Destination of buffer upload.
-	TEXTURE_UPLOAD_SOURCE = 1 << 24, ///< Source for texture upload.
-	QUERY_RESULT = 1 << 24, ///< Source to store query results.
+	TEXTURE_VERTEX_READ = 1 << 18,
+	TEXTURE_TESSELLATION_EVALUATION_READ = 1 << 19,
+	TEXTURE_TESSELLATION_CONTROL_READ = 1 << 20,
+	TEXTURE_GEOMETRY_READ = 1 << 21,
+	TEXTURE_FRAGMENT_READ = 1 << 22,
+	TEXTURE_COMPUTE_READ = 1 << 23,
+	TEXTURE_ALL = TEXTURE_VERTEX_READ | TEXTURE_TESSELLATION_EVALUATION_READ | TEXTURE_TESSELLATION_CONTROL_READ
+		| TEXTURE_GEOMETRY_READ
+		| TEXTURE_FRAGMENT_READ
+		| TEXTURE_COMPUTE_READ,
+
+	INDEX = 1 << 24,
+	VERTEX = 1 << 25,
+	INDIRECT = 1 << 26,
+
+	FILL = 1 << 27,
+	BUFFER_UPLOAD_SOURCE = 1 << 28,
+	BUFFER_UPLOAD_DESTINATION = 1 << 29, ///< Destination of buffer upload.
+	TEXTURE_UPLOAD_SOURCE = 1 << 30, ///< Source for texture upload.
+	QUERY_RESULT = 1u << 31u, ///< Source to store query results.
 	TRANSFER_ALL = FILL | BUFFER_UPLOAD_SOURCE | BUFFER_UPLOAD_DESTINATION | TEXTURE_UPLOAD_SOURCE | QUERY_RESULT,
 };
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(BufferUsageBit, inline)

+ 3 - 0
src/anki/gr/GrManager.h

@@ -94,6 +94,9 @@ public:
 	/// Get some buffer alignment info.
 	void getStorageBufferInfo(U32& bindOffsetAlignment, PtrSize& maxStorageBlockSize) const;
 
+	/// Get some buffer alignment info.
+	void getTextureBufferInfo(U32& bindOffsetAlignment, PtrSize& maxRange) const;
+
 anki_internal:
 	GrAllocator<U8>& getAllocator()
 	{

+ 48 - 0
src/anki/gr/gl/CommandBuffer.cpp

@@ -758,6 +758,54 @@ void CommandBuffer::bindImage(U32 set, U32 binding, TexturePtr img, U32 level)
 	}
 }
 
+void CommandBuffer::bindTextureBuffer(
+	U32 set, U32 binding, BufferPtr buff, PtrSize offset, PtrSize range, PixelFormat fmt)
+{
+	class Cmd final : public GlCommand
+	{
+	public:
+		U32 m_set;
+		U32 m_binding;
+		BufferPtr m_buff;
+		PtrSize m_offset;
+		PtrSize m_range;
+		GLenum m_fmt;
+
+		Cmd(U32 set, U32 binding, BufferPtr buff, PtrSize offset, PtrSize range, GLenum fmt)
+			: m_set(set)
+			, m_binding(binding)
+			, m_buff(buff)
+			, m_offset(offset)
+			, m_range(range)
+			, m_fmt(fmt)
+		{
+		}
+
+		Error operator()(GlState& state)
+		{
+			ANKI_ASSERT(m_offset + m_range <= m_buff->m_impl->m_size);
+
+			const GLuint tex = state.m_texBuffTextures[m_set][m_binding];
+			glTextureBufferRange(tex, m_fmt, m_buff->m_impl->getGlName(), m_offset, m_range);
+
+			return ErrorCode::NONE;
+		}
+	};
+
+	Bool8 compressed;
+	GLenum format;
+	GLenum internalFormat;
+	GLenum type;
+	DepthStencilAspectBit dsAspect;
+	convertTextureInformation(fmt, compressed, format, internalFormat, type, dsAspect);
+	(void)compressed;
+	(void)format;
+	(void)type;
+	(void)dsAspect;
+
+	m_impl->pushBackNewCommand<Cmd>(set, binding, buff, offset, range, internalFormat);
+}
+
 void CommandBuffer::bindShaderProgram(ShaderProgramPtr prog)
 {
 	class Cmd final : public GlCommand

+ 266 - 0
src/anki/gr/gl/Common.cpp

@@ -259,4 +259,270 @@ GLenum convertBlendFactor(BlendFactor in)
 	return out;
 }
 
+void convertTextureInformation(const PixelFormat& pf,
+	Bool8& compressed,
+	GLenum& format,
+	GLenum& internalFormat,
+	GLenum& type,
+	DepthStencilAspectBit& dsAspect)
+{
+	compressed =
+		pf.m_components >= ComponentFormat::FIRST_COMPRESSED && pf.m_components <= ComponentFormat::LAST_COMPRESSED;
+
+	switch(pf.m_components)
+	{
+#if ANKI_GL == ANKI_GL_DESKTOP
+	case ComponentFormat::R8G8B8_S3TC:
+		format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
+		internalFormat = format;
+		type = GL_UNSIGNED_BYTE;
+		break;
+	case ComponentFormat::R8G8B8A8_S3TC:
+		format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+		internalFormat = format;
+		type = GL_UNSIGNED_BYTE;
+		break;
+#else
+	case ComponentFormat::R8G8B8_ETC2:
+		format = GL_COMPRESSED_RGB8_ETC2;
+		internalFormat = format;
+		type = GL_UNSIGNED_BYTE;
+		break;
+	case ComponentFormat::R8G8B8A8_ETC2:
+		format = GL_COMPRESSED_RGBA8_ETC2_EAC;
+		internalFormat = format;
+		type = GL_UNSIGNED_BYTE;
+		break;
+#endif
+	case ComponentFormat::R8:
+		format = GL_RED;
+
+		if(pf.m_transform == TransformFormat::UNORM)
+		{
+			internalFormat = GL_R8;
+			type = GL_UNSIGNED_BYTE;
+		}
+		else
+		{
+			ANKI_ASSERT(pf.m_transform == TransformFormat::SNORM);
+			internalFormat = GL_R8_SNORM;
+			type = GL_BYTE;
+		}
+		break;
+	case ComponentFormat::R8G8:
+		format = GL_RG;
+
+		if(pf.m_transform == TransformFormat::UNORM)
+		{
+			internalFormat = GL_RG8;
+			type = GL_UNSIGNED_BYTE;
+		}
+		else
+		{
+			ANKI_ASSERT(pf.m_transform == TransformFormat::SNORM);
+			internalFormat = GL_RG8_SNORM;
+			type = GL_BYTE;
+		}
+		break;
+	case ComponentFormat::R8G8B8:
+		format = GL_RGB;
+
+		if(pf.m_transform == TransformFormat::UNORM)
+		{
+			internalFormat = GL_RGB8;
+			type = GL_UNSIGNED_BYTE;
+		}
+		else
+		{
+			ANKI_ASSERT(pf.m_transform == TransformFormat::SNORM);
+			internalFormat = GL_RGB8_SNORM;
+			type = GL_BYTE;
+		}
+		break;
+	case ComponentFormat::R8G8B8A8:
+		format = GL_RGBA;
+
+		if(pf.m_transform == TransformFormat::UNORM)
+		{
+			internalFormat = GL_RGBA8;
+			type = GL_UNSIGNED_BYTE;
+		}
+		else
+		{
+			ANKI_ASSERT(pf.m_transform == TransformFormat::SNORM);
+			internalFormat = GL_RGBA8_SNORM;
+			type = GL_BYTE;
+		}
+		break;
+	case ComponentFormat::R16:
+		if(pf.m_transform == TransformFormat::FLOAT)
+		{
+			format = GL_R;
+			internalFormat = GL_R16F;
+			type = GL_FLOAT;
+		}
+		else if(pf.m_transform == TransformFormat::UINT)
+		{
+			format = GL_R;
+			internalFormat = GL_R16UI;
+			type = GL_UNSIGNED_INT;
+		}
+		else
+		{
+			ANKI_ASSERT(!"TODO");
+		}
+		break;
+	case ComponentFormat::R16G16B16:
+		if(pf.m_transform == TransformFormat::FLOAT)
+		{
+			format = GL_RGB;
+			internalFormat = GL_RGB16F;
+			type = GL_FLOAT;
+		}
+		else if(pf.m_transform == TransformFormat::UINT)
+		{
+			format = GL_RGB_INTEGER;
+			internalFormat = GL_RGB16UI;
+			type = GL_UNSIGNED_INT;
+		}
+		else
+		{
+			ANKI_ASSERT(0 && "TODO");
+		}
+		break;
+	case ComponentFormat::R16G16B16A16:
+		if(pf.m_transform == TransformFormat::FLOAT)
+		{
+			format = GL_RGBA;
+			internalFormat = GL_RGBA16F;
+			type = GL_FLOAT;
+		}
+		else if(pf.m_transform == TransformFormat::UINT)
+		{
+			ANKI_ASSERT(!"TODO");
+		}
+		else
+		{
+			ANKI_ASSERT(!"TODO");
+		}
+		break;
+	case ComponentFormat::R32:
+		if(pf.m_transform == TransformFormat::FLOAT)
+		{
+			format = GL_R;
+			internalFormat = GL_R32F;
+			type = GL_FLOAT;
+		}
+		else if(pf.m_transform == TransformFormat::UINT)
+		{
+			format = GL_RG_INTEGER;
+			internalFormat = GL_R32UI;
+			type = GL_UNSIGNED_INT;
+		}
+		else
+		{
+			ANKI_ASSERT(0 && "TODO");
+		}
+		break;
+	case ComponentFormat::R32G32:
+		if(pf.m_transform == TransformFormat::FLOAT)
+		{
+			format = GL_RG;
+			internalFormat = GL_RG32F;
+			type = GL_FLOAT;
+		}
+		else if(pf.m_transform == TransformFormat::UINT)
+		{
+			format = GL_RG_INTEGER;
+			internalFormat = GL_RG32UI;
+			type = GL_UNSIGNED_INT;
+		}
+		else
+		{
+			ANKI_ASSERT(0 && "TODO");
+		}
+		break;
+	case ComponentFormat::R32G32B32:
+		if(pf.m_transform == TransformFormat::FLOAT)
+		{
+			format = GL_RGB;
+			internalFormat = GL_RGB32F;
+			type = GL_FLOAT;
+		}
+		else if(pf.m_transform == TransformFormat::UINT)
+		{
+			format = GL_RGB_INTEGER;
+			internalFormat = GL_RGB32UI;
+			type = GL_UNSIGNED_INT;
+		}
+		else
+		{
+			ANKI_ASSERT(!"TODO");
+		}
+		break;
+	case ComponentFormat::R32G32B32A32:
+		if(pf.m_transform == TransformFormat::FLOAT)
+		{
+			format = GL_RGBA;
+			internalFormat = GL_RGBA32F;
+			type = GL_FLOAT;
+		}
+		else if(pf.m_transform == TransformFormat::UINT)
+		{
+			format = GL_RGBA_INTEGER;
+			internalFormat = GL_RGBA32UI;
+			type = GL_UNSIGNED_INT;
+		}
+		else
+		{
+			ANKI_ASSERT(!"TODO");
+		}
+		break;
+	case ComponentFormat::R11G11B10:
+		if(pf.m_transform == TransformFormat::FLOAT)
+		{
+			format = GL_RGB;
+			internalFormat = GL_R11F_G11F_B10F;
+			type = GL_FLOAT;
+		}
+		else
+		{
+			ANKI_ASSERT(0 && "TODO");
+		}
+		break;
+	case ComponentFormat::R10G10B10A2:
+		if(pf.m_transform == TransformFormat::UNORM)
+		{
+			format = GL_RGBA;
+			internalFormat = GL_RGB10_A2;
+			type = GL_UNSIGNED_INT;
+		}
+		else
+		{
+			ANKI_ASSERT(0 && "TODO");
+		}
+		break;
+	case ComponentFormat::D24S8:
+		format = GL_DEPTH_STENCIL;
+		internalFormat = GL_DEPTH24_STENCIL8;
+		type = GL_UNSIGNED_INT;
+		dsAspect = DepthStencilAspectBit::DEPTH_STENCIL;
+		break;
+	case ComponentFormat::D16:
+		format = GL_DEPTH_COMPONENT;
+		internalFormat = GL_DEPTH_COMPONENT16;
+		type = GL_UNSIGNED_SHORT;
+		dsAspect = DepthStencilAspectBit::DEPTH;
+		break;
+	case ComponentFormat::S8:
+		format = GL_STENCIL_INDEX;
+		internalFormat = GL_STENCIL_INDEX8;
+		type = GL_BYTE;
+		dsAspect = DepthStencilAspectBit::STENCIL;
+		break;
+	default:
+		ANKI_ASSERT(0);
+	}
+}
+
 } // end namespace anki

+ 7 - 0
src/anki/gr/gl/Common.h

@@ -167,6 +167,13 @@ inline GLenum convertPrimitiveTopology(PrimitiveTopology ak)
 
 	return out;
 }
+
+void convertTextureInformation(const PixelFormat& pf,
+	Bool8& compressed,
+	GLenum& format,
+	GLenum& internalFormat,
+	GLenum& type,
+	DepthStencilAspectBit& dsAspect);
 /// @}
 
 } // end namespace anki

+ 18 - 0
src/anki/gr/gl/GlState.cpp

@@ -148,11 +148,29 @@ void GlState::initRenderThread()
 	glGetInteger64v(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &val);
 	m_ssboAlignment = val;
 
+	glGetInteger64v(GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT, &val);
+	m_tboAlignment = val;
+
 	glGetInteger64v(GL_MAX_UNIFORM_BLOCK_SIZE, &val);
 	m_uniBlockMaxSize = val;
 
 	glGetInteger64v(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &val);
 	m_storageBlockMaxSize = val;
+
+	m_tboMaxRange = MAX_U32;
+
+	// Texture buffer textures
+	glGenTextures(MAX_DESCRIPTOR_SETS * MAX_TEXTURE_BUFFER_BINDINGS, &m_texBuffTextures[0][0]);
+	for(U i = 0; i < MAX_DESCRIPTOR_SETS; ++i)
+	{
+		for(U j = 0; j < MAX_TEXTURE_BUFFER_BINDINGS; ++j)
+		{
+			U unit = MAX_TEXTURE_BINDINGS * MAX_DESCRIPTOR_SETS + MAX_TEXTURE_BUFFER_BINDINGS * i + j;
+			glActiveTexture(GL_TEXTURE0 + unit);
+
+			glBindTexture(GL_TEXTURE_BUFFER, m_texBuffTextures[i][j]);
+		}
+	}
 }
 
 void GlState::destroy()

+ 4 - 0
src/anki/gr/gl/GlState.h

@@ -32,6 +32,8 @@ public:
 	U32 m_ssboAlignment = 0;
 	U32 m_uniBlockMaxSize = 0;
 	U32 m_storageBlockMaxSize = 0;
+	U32 m_tboAlignment = 0;
+	U32 m_tboMaxRange = 0;
 
 	/// @name FB
 	/// @{
@@ -45,6 +47,8 @@ public:
 	Array<U32, 2> m_stencilWriteMask = {{MAX_U32, MAX_U32}};
 	/// @}
 
+	Array2d<GLuint, MAX_DESCRIPTOR_SETS, MAX_TEXTURE_BUFFER_BINDINGS> m_texBuffTextures = {};
+
 	GlState(GrManager* manager)
 		: m_manager(manager)
 	{

+ 8 - 0
src/anki/gr/gl/GrManager.cpp

@@ -89,4 +89,12 @@ void GrManager::getStorageBufferInfo(U32& bindOffsetAlignment, PtrSize& maxStora
 	ANKI_ASSERT(bindOffsetAlignment > 0 && maxStorageBlockSize > 0);
 }
 
+void GrManager::getTextureBufferInfo(U32& bindOffsetAlignment, PtrSize& maxRange) const
+{
+	bindOffsetAlignment = m_impl->getState().m_tboAlignment;
+	maxRange = m_impl->getState().m_tboMaxRange;
+
+	ANKI_ASSERT(bindOffsetAlignment > 0 && maxRange > 0);
+}
+
 } // end namespace anki

+ 3 - 0
src/anki/gr/gl/ShaderImpl.cpp

@@ -36,6 +36,7 @@ static const char* SHADER_HEADER = R"(#version %u %s
 #define ANKI_SS_BINDING(set_, binding_) binding = set_ * %u + binding_
 #define ANKI_TEX_BINDING(set_, binding_) binding = set_ * %u + binding_
 #define ANKI_IMAGE_BINDING(set_, binding_) binding = set_ * %u + binding_
+#define ANKI_TBO_BINDING(set_, binding_) binding = %u + set_ * %u + binding_
 
 #if defined(FRAGMENT_SHADER)
 #define ANKI_USING_FRAG_COORD(height_) vec4 anki_fragCoord = gl_FragCoord;
@@ -101,6 +102,8 @@ Error ShaderImpl::init(ShaderType type, const CString& source)
 		MAX_STORAGE_BUFFER_BINDINGS,
 		MAX_TEXTURE_BINDINGS,
 		MAX_IMAGE_BINDINGS,
+		MAX_TEXTURE_BINDINGS * MAX_DESCRIPTOR_SETS,
+		MAX_TEXTURE_BUFFER_BINDINGS,
 		&source[0]);
 
 	// 2) Gen name, create, compile and link

+ 0 - 260
src/anki/gr/gl/TextureImpl.cpp

@@ -44,266 +44,6 @@ static GLenum convertTextureType(TextureType type)
 	return out;
 }
 
-static void convertTextureInformation(const PixelFormat& pf,
-	Bool8& compressed,
-	GLenum& format,
-	GLenum& internalFormat,
-	GLenum& type,
-	DepthStencilAspectBit& dsAspect)
-{
-	compressed =
-		pf.m_components >= ComponentFormat::FIRST_COMPRESSED && pf.m_components <= ComponentFormat::LAST_COMPRESSED;
-
-	switch(pf.m_components)
-	{
-#if ANKI_GL == ANKI_GL_DESKTOP
-	case ComponentFormat::R8G8B8_S3TC:
-		format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
-		internalFormat = format;
-		type = GL_UNSIGNED_BYTE;
-		break;
-	case ComponentFormat::R8G8B8A8_S3TC:
-		format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
-		internalFormat = format;
-		type = GL_UNSIGNED_BYTE;
-		break;
-#else
-	case ComponentFormat::R8G8B8_ETC2:
-		format = GL_COMPRESSED_RGB8_ETC2;
-		internalFormat = format;
-		type = GL_UNSIGNED_BYTE;
-		break;
-	case ComponentFormat::R8G8B8A8_ETC2:
-		format = GL_COMPRESSED_RGBA8_ETC2_EAC;
-		internalFormat = format;
-		type = GL_UNSIGNED_BYTE;
-		break;
-#endif
-	case ComponentFormat::R8:
-		format = GL_RED;
-
-		if(pf.m_transform == TransformFormat::UNORM)
-		{
-			internalFormat = GL_R8;
-			type = GL_UNSIGNED_BYTE;
-		}
-		else
-		{
-			ANKI_ASSERT(pf.m_transform == TransformFormat::SNORM);
-			internalFormat = GL_R8_SNORM;
-			type = GL_BYTE;
-		}
-		break;
-	case ComponentFormat::R8G8:
-		format = GL_RG;
-
-		if(pf.m_transform == TransformFormat::UNORM)
-		{
-			internalFormat = GL_RG8;
-			type = GL_UNSIGNED_BYTE;
-		}
-		else
-		{
-			ANKI_ASSERT(pf.m_transform == TransformFormat::SNORM);
-			internalFormat = GL_RG8_SNORM;
-			type = GL_BYTE;
-		}
-		break;
-	case ComponentFormat::R8G8B8:
-		format = GL_RGB;
-
-		if(pf.m_transform == TransformFormat::UNORM)
-		{
-			internalFormat = GL_RGB8;
-			type = GL_UNSIGNED_BYTE;
-		}
-		else
-		{
-			ANKI_ASSERT(pf.m_transform == TransformFormat::SNORM);
-			internalFormat = GL_RGB8_SNORM;
-			type = GL_BYTE;
-		}
-		break;
-	case ComponentFormat::R8G8B8A8:
-		format = GL_RGBA;
-
-		if(pf.m_transform == TransformFormat::UNORM)
-		{
-			internalFormat = GL_RGBA8;
-			type = GL_UNSIGNED_BYTE;
-		}
-		else
-		{
-			ANKI_ASSERT(pf.m_transform == TransformFormat::SNORM);
-			internalFormat = GL_RGBA8_SNORM;
-			type = GL_BYTE;
-		}
-		break;
-	case ComponentFormat::R32:
-		if(pf.m_transform == TransformFormat::FLOAT)
-		{
-			format = GL_R;
-			internalFormat = GL_R32F;
-			type = GL_FLOAT;
-		}
-		else if(pf.m_transform == TransformFormat::UINT)
-		{
-			format = GL_RG_INTEGER;
-			internalFormat = GL_R32UI;
-			type = GL_UNSIGNED_INT;
-		}
-		else
-		{
-			ANKI_ASSERT(0 && "TODO");
-		}
-		break;
-	case ComponentFormat::R32G32:
-		if(pf.m_transform == TransformFormat::FLOAT)
-		{
-			format = GL_RG;
-			internalFormat = GL_RG32F;
-			type = GL_FLOAT;
-		}
-		else if(pf.m_transform == TransformFormat::UINT)
-		{
-			format = GL_RG_INTEGER;
-			internalFormat = GL_RG32UI;
-			type = GL_UNSIGNED_INT;
-		}
-		else
-		{
-			ANKI_ASSERT(0 && "TODO");
-		}
-		break;
-	case ComponentFormat::R32G32B32:
-		if(pf.m_transform == TransformFormat::FLOAT)
-		{
-			format = GL_RGB;
-			internalFormat = GL_RGB32F;
-			type = GL_FLOAT;
-		}
-		else if(pf.m_transform == TransformFormat::UINT)
-		{
-			format = GL_RGB_INTEGER;
-			internalFormat = GL_RGB32UI;
-			type = GL_UNSIGNED_INT;
-		}
-		else
-		{
-			ANKI_ASSERT(!"TODO");
-		}
-		break;
-	case ComponentFormat::R32G32B32A32:
-		if(pf.m_transform == TransformFormat::FLOAT)
-		{
-			format = GL_RGBA;
-			internalFormat = GL_RGBA32F;
-			type = GL_FLOAT;
-		}
-		else if(pf.m_transform == TransformFormat::UINT)
-		{
-			format = GL_RGBA_INTEGER;
-			internalFormat = GL_RGBA32UI;
-			type = GL_UNSIGNED_INT;
-		}
-		else
-		{
-			ANKI_ASSERT(!"TODO");
-		}
-		break;
-	case ComponentFormat::R16:
-		if(pf.m_transform == TransformFormat::FLOAT)
-		{
-			format = GL_R;
-			internalFormat = GL_R16F;
-			type = GL_FLOAT;
-		}
-		else
-		{
-			ANKI_ASSERT(0 && "TODO");
-		}
-		break;
-	case ComponentFormat::R16G16B16:
-		if(pf.m_transform == TransformFormat::FLOAT)
-		{
-			format = GL_RGB;
-			internalFormat = GL_RGB16F;
-			type = GL_FLOAT;
-		}
-		else if(pf.m_transform == TransformFormat::UINT)
-		{
-			format = GL_RGB_INTEGER;
-			internalFormat = GL_RGB16UI;
-			type = GL_UNSIGNED_INT;
-		}
-		else
-		{
-			ANKI_ASSERT(0 && "TODO");
-		}
-		break;
-	case ComponentFormat::R16G16B16A16:
-		if(pf.m_transform == TransformFormat::FLOAT)
-		{
-			format = GL_RGBA;
-			internalFormat = GL_RGBA16F;
-			type = GL_FLOAT;
-		}
-		else if(pf.m_transform == TransformFormat::UINT)
-		{
-			ANKI_ASSERT(!"TODO");
-		}
-		else
-		{
-			ANKI_ASSERT(!"TODO");
-		}
-		break;
-	case ComponentFormat::R11G11B10:
-		if(pf.m_transform == TransformFormat::FLOAT)
-		{
-			format = GL_RGB;
-			internalFormat = GL_R11F_G11F_B10F;
-			type = GL_FLOAT;
-		}
-		else
-		{
-			ANKI_ASSERT(0 && "TODO");
-		}
-		break;
-	case ComponentFormat::R10G10B10A2:
-		if(pf.m_transform == TransformFormat::UNORM)
-		{
-			format = GL_RGBA;
-			internalFormat = GL_RGB10_A2;
-			type = GL_UNSIGNED_INT;
-		}
-		else
-		{
-			ANKI_ASSERT(0 && "TODO");
-		}
-		break;
-	case ComponentFormat::D24S8:
-		format = GL_DEPTH_STENCIL;
-		internalFormat = GL_DEPTH24_STENCIL8;
-		type = GL_UNSIGNED_INT;
-		dsAspect = DepthStencilAspectBit::DEPTH_STENCIL;
-		break;
-	case ComponentFormat::D16:
-		format = GL_DEPTH_COMPONENT;
-		internalFormat = GL_DEPTH_COMPONENT16;
-		type = GL_UNSIGNED_SHORT;
-		dsAspect = DepthStencilAspectBit::DEPTH;
-		break;
-	case ComponentFormat::S8:
-		format = GL_STENCIL_INDEX;
-		internalFormat = GL_STENCIL_INDEX8;
-		type = GL_BYTE;
-		dsAspect = DepthStencilAspectBit::STENCIL;
-		break;
-	default:
-		ANKI_ASSERT(0);
-	}
-}
-
 class DeleteTextureCommand final : public GlCommand
 {
 public: