浏览代码

[REFACTORING] Start the work of TextureViews on GL

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

+ 49 - 0
src/anki/gr/Texture.h

@@ -50,6 +50,48 @@ public:
 				+ sizeof(U8));
 		return anki::computeHash(first, size);
 	}
+
+	Bool isValid() const
+	{
+#define ANKI_CHECK_VAL_VALIDITY(x) \
+	do                             \
+	{                              \
+		if(!(x))                   \
+		{                          \
+			return false;          \
+		}                          \
+	} while(0)
+
+		ANKI_CHECK_VAL_VALIDITY(m_usage != TextureUsageBit::NONE);
+		ANKI_CHECK_VAL_VALIDITY(m_mipmapsCount > 0);
+		ANKI_CHECK_VAL_VALIDITY(m_width > 0);
+		ANKI_CHECK_VAL_VALIDITY(m_height > 0);
+		switch(m_type)
+		{
+		case TextureType::_2D:
+			ANKI_CHECK_VAL_VALIDITY(m_depth == 1);
+			ANKI_CHECK_VAL_VALIDITY(m_layerCount == 1);
+			break;
+		case TextureType::CUBE:
+			ANKI_CHECK_VAL_VALIDITY(m_depth == 1);
+			ANKI_CHECK_VAL_VALIDITY(m_layerCount == 1);
+			break;
+		case TextureType::_3D:
+			ANKI_CHECK_VAL_VALIDITY(m_depth > 0);
+			ANKI_CHECK_VAL_VALIDITY(m_layerCount == 1);
+			break;
+		case TextureType::_2D_ARRAY:
+		case TextureType::CUBE_ARRAY:
+			ANKI_CHECK_VAL_VALIDITY(m_depth == 1);
+			ANKI_CHECK_VAL_VALIDITY(m_layerCount > 0);
+			break;
+		default:
+			ANKI_CHECK_VAL_VALIDITY(0);
+		};
+
+		return true;
+#undef ANKI_CHECK_VAL_VALIDITY
+	}
 };
 
 /// GPU texture.
@@ -194,6 +236,13 @@ public:
 			&& subresource.m_depthStencilAspect == DepthStencilAspectBit::NONE;
 	}
 
+	/// Return true if the subresource can be used as Framebuffer attachment.
+	Bool isSubresourceGoodForFramebufferAttachment(const TextureSubresourceInfo& subresource) const
+	{
+		ANKI_ASSERT(isSubresourceValid(subresource));
+		return subresource.m_faceCount == 1 && subresource.m_mipmapCount == 1 && subresource.m_layerCount == 1;
+	}
+
 protected:
 	U32 m_width = 0;
 	U32 m_height = 0;

+ 0 - 42
src/anki/gr/common/Misc.cpp

@@ -47,48 +47,6 @@ void logShaderErrorCode(const CString& error, const CString& source, GenericMemo
 		&error[0]);
 }
 
-Bool textureInitInfoValid(const TextureInitInfo& inf)
-{
-#define ANKI_CHECK_VAL_VALIDITY(x) \
-	do                             \
-	{                              \
-		if(!(x))                   \
-		{                          \
-			return false;          \
-		}                          \
-	} while(0)
-
-	ANKI_CHECK_VAL_VALIDITY(inf.m_usage != TextureUsageBit::NONE);
-	ANKI_CHECK_VAL_VALIDITY(inf.m_mipmapsCount > 0);
-	ANKI_CHECK_VAL_VALIDITY(inf.m_width > 0);
-	ANKI_CHECK_VAL_VALIDITY(inf.m_height > 0);
-	switch(inf.m_type)
-	{
-	case TextureType::_2D:
-		ANKI_CHECK_VAL_VALIDITY(inf.m_depth == 1);
-		ANKI_CHECK_VAL_VALIDITY(inf.m_layerCount == 1);
-		break;
-	case TextureType::CUBE:
-		ANKI_CHECK_VAL_VALIDITY(inf.m_depth == 1);
-		ANKI_CHECK_VAL_VALIDITY(inf.m_layerCount == 1);
-		break;
-	case TextureType::_3D:
-		ANKI_CHECK_VAL_VALIDITY(inf.m_depth > 0);
-		ANKI_CHECK_VAL_VALIDITY(inf.m_layerCount == 1);
-		break;
-	case TextureType::_2D_ARRAY:
-	case TextureType::CUBE_ARRAY:
-		ANKI_CHECK_VAL_VALIDITY(inf.m_depth == 1);
-		ANKI_CHECK_VAL_VALIDITY(inf.m_layerCount > 0);
-		break;
-	default:
-		ANKI_CHECK_VAL_VALIDITY(0);
-	};
-
-	return true;
-#undef ANKI_CHECK_VAL_VALIDITY
-}
-
 void getFormatInfo(const PixelFormat& fmt, U& texelComponents, U& texelBytes, U& blockSize, U& blockBytes)
 {
 	blockSize = 0;

+ 0 - 3
src/anki/gr/common/Misc.h

@@ -38,9 +38,6 @@ inline void checkTextureSurface(TextureType type, U depth, U mipCount, U layerCo
 	};
 }
 
-/// Check the validity of the structure.
-Bool textureInitInfoValid(const TextureInitInfo& inf);
-
 /// Compute the size of a single surface.
 void getFormatInfo(const PixelFormat& fmt, U& texelComponents, U& texelBytes, U& blockSize, U& blockBytes);
 

+ 42 - 57
src/anki/gr/gl/FramebufferImpl.cpp

@@ -5,7 +5,7 @@
 
 #include <anki/gr/gl/FramebufferImpl.h>
 #include <anki/gr/Texture.h>
-#include <anki/gr/gl/TextureImpl.h>
+#include <anki/gr/gl/TextureViewImpl.h>
 #include <anki/gr/gl/GlState.h>
 #include <anki/gr/GrManager.h>
 #include <anki/gr/gl/GrManagerImpl.h>
@@ -20,7 +20,7 @@ Error FramebufferImpl::init(const FramebufferInitInfo& init)
 	ANKI_ASSERT(!isCreated());
 	m_in = init;
 
-	if(m_in.m_colorAttachmentCount == 1 && !m_in.m_colorAttachments[0].m_texture.isCreated())
+	if(init.refersToDefaultFramebuffer())
 	{
 		m_fbSize[0] = m_fbSize[1] = MAX_U16;
 		m_bindDefault = true;
@@ -38,9 +38,12 @@ Error FramebufferImpl::init(const FramebufferInitInfo& init)
 	for(U i = 0; i < m_in.m_colorAttachmentCount; i++)
 	{
 		const FramebufferAttachmentInfo& att = m_in.m_colorAttachments[i];
+		const TextureViewImpl& viewImpl = static_cast<const TextureViewImpl&>(*att.m_textureView);
+		ANKI_ASSERT(viewImpl.m_tex->isSubresourceGoodForFramebufferAttachment(viewImpl.getSubresource()));
+
 		const GLenum binding = GL_COLOR_ATTACHMENT0 + i;
 
-		attachTextureInternal(binding, static_cast<const TextureImpl&>(*att.m_texture), att);
+		attachTextureInternal(binding, viewImpl, att);
 
 		m_drawBuffers[i] = binding;
 
@@ -51,59 +54,39 @@ Error FramebufferImpl::init(const FramebufferInitInfo& init)
 
 		if(m_fbSize[0] == 0)
 		{
-			m_fbSize[0] = att.m_texture->getWidth();
-			m_fbSize[1] = att.m_texture->getHeight();
+			m_fbSize[0] = viewImpl.m_tex->getWidth() >> viewImpl.getBaseMipmap();
+			m_fbSize[1] = viewImpl.m_tex->getHeight() >> viewImpl.getBaseMipmap();
 		}
 		else
 		{
-			ANKI_ASSERT(m_fbSize[0] == att.m_texture->getWidth());
-			ANKI_ASSERT(m_fbSize[1] == att.m_texture->getHeight());
+			ANKI_ASSERT(m_fbSize[0] == (viewImpl.m_tex->getWidth() >> viewImpl.getBaseMipmap()));
+			ANKI_ASSERT(m_fbSize[1] == (viewImpl.m_tex->getHeight() >> viewImpl.getBaseMipmap()));
 		}
 	}
 
 	// Attach depth/stencil
-	if(m_in.m_depthStencilAttachment.m_texture.isCreated())
+	if(m_in.m_depthStencilAttachment.m_textureView.isCreated())
 	{
 		const FramebufferAttachmentInfo& att = m_in.m_depthStencilAttachment;
-		const TextureImpl& tex = static_cast<const TextureImpl&>(*att.m_texture);
+		const TextureViewImpl& viewImpl = static_cast<const TextureViewImpl&>(*att.m_textureView);
+		ANKI_ASSERT(viewImpl.m_tex->isSubresourceGoodForFramebufferAttachment(viewImpl.getSubresource()));
 
 		GLenum binding;
-		if(tex.m_glFormat == GL_DEPTH_COMPONENT)
+		if(viewImpl.getDepthStencilAspect() == DepthStencilAspectBit::DEPTH)
 		{
 			binding = GL_DEPTH_ATTACHMENT;
-			m_dsAspect = DepthStencilAspectBit::DEPTH;
 		}
-		else if(tex.m_glFormat == GL_STENCIL_INDEX)
+		else if(viewImpl.getDepthStencilAspect() == DepthStencilAspectBit::STENCIL)
 		{
 			binding = GL_STENCIL_ATTACHMENT;
-			m_dsAspect = DepthStencilAspectBit::STENCIL;
 		}
 		else
 		{
-			ANKI_ASSERT(tex.m_glFormat == GL_DEPTH_STENCIL);
-
-			if(att.m_aspect == DepthStencilAspectBit::DEPTH)
-			{
-				binding = GL_DEPTH_ATTACHMENT;
-			}
-			else if(att.m_aspect == DepthStencilAspectBit::STENCIL)
-			{
-				binding = GL_STENCIL_ATTACHMENT;
-			}
-			else if(att.m_aspect == DepthStencilAspectBit::DEPTH_STENCIL)
-			{
-				binding = GL_DEPTH_STENCIL_ATTACHMENT;
-			}
-			else
-			{
-				ANKI_ASSERT(!"Need to set FramebufferAttachmentInfo::m_aspect");
-				binding = 0;
-			}
-
-			m_dsAspect = att.m_aspect;
+			ANKI_ASSERT(viewImpl.getDepthStencilAspect() == DepthStencilAspectBit::DEPTH_STENCIL);
+			binding = GL_DEPTH_STENCIL_ATTACHMENT;
 		}
 
-		attachTextureInternal(binding, tex, att);
+		attachTextureInternal(binding, viewImpl, att);
 
 		if(att.m_loadOperation == AttachmentLoadOperation::DONT_CARE)
 		{
@@ -112,14 +95,21 @@ Error FramebufferImpl::init(const FramebufferInitInfo& init)
 
 		if(m_fbSize[0] == 0)
 		{
-			m_fbSize[0] = att.m_texture->getWidth();
-			m_fbSize[1] = att.m_texture->getHeight();
+			m_fbSize[0] = viewImpl.m_tex->getWidth() >> viewImpl.getBaseMipmap();
+			m_fbSize[1] = viewImpl.m_tex->getHeight() >> viewImpl.getBaseMipmap();
 		}
 		else
 		{
-			ANKI_ASSERT(m_fbSize[0] == att.m_texture->getWidth());
-			ANKI_ASSERT(m_fbSize[1] == att.m_texture->getHeight());
+			ANKI_ASSERT(m_fbSize[0] == (viewImpl.m_tex->getWidth() >> viewImpl.getBaseMipmap()));
+			ANKI_ASSERT(m_fbSize[1] == (viewImpl.m_tex->getHeight() >> viewImpl.getBaseMipmap()));
 		}
+
+		// Misc
+		m_clearDepth = !!(viewImpl.getDepthStencilAspect() & DepthStencilAspectBit::DEPTH)
+			&& att.m_loadOperation == AttachmentLoadOperation::CLEAR;
+
+		m_clearStencil = !!(viewImpl.getDepthStencilAspect() & DepthStencilAspectBit::STENCIL)
+			&& att.m_stencilLoadOperation == AttachmentLoadOperation::CLEAR;
 	}
 
 	// Check completeness
@@ -135,38 +125,35 @@ Error FramebufferImpl::init(const FramebufferInitInfo& init)
 }
 
 void FramebufferImpl::attachTextureInternal(
-	GLenum attachment, const TextureImpl& tex, const FramebufferAttachmentInfo& info)
+	GLenum attachment, const TextureViewImpl& view, const FramebufferAttachmentInfo& info)
 {
-	tex.checkSurfaceOrVolume(info.m_surface);
-
 	const GLenum target = GL_FRAMEBUFFER;
+	const TextureImpl& tex = static_cast<const TextureImpl&>(*view.m_tex);
+
 	switch(tex.m_target)
 	{
 	case GL_TEXTURE_2D:
 #if ANKI_GL == ANKI_GL_DESKTOP
 	case GL_TEXTURE_2D_MULTISAMPLE:
 #endif
-		glFramebufferTexture2D(target, attachment, tex.m_target, tex.getGlName(), info.m_surface.m_level);
+		glFramebufferTexture2D(target, attachment, tex.m_target, tex.getGlName(), view.getBaseMipmap());
 		break;
 	case GL_TEXTURE_CUBE_MAP:
 		glFramebufferTexture2D(target,
 			attachment,
-			GL_TEXTURE_CUBE_MAP_POSITIVE_X + info.m_surface.m_face,
-			tex.getGlName(),
-			info.m_surface.m_level);
+			GL_TEXTURE_CUBE_MAP_POSITIVE_X + view.getBaseFace(),
+			view.getGlName(),
+			view.getBaseMipmap());
 		break;
 	case GL_TEXTURE_2D_ARRAY:
-		glFramebufferTextureLayer(target, attachment, tex.getGlName(), info.m_surface.m_level, info.m_surface.m_layer);
+		glFramebufferTextureLayer(target, attachment, view.getGlName(), view.getBaseMipmap(), view.getBaseLayer());
 		break;
 	case GL_TEXTURE_3D:
-		glFramebufferTextureLayer(target, attachment, tex.getGlName(), info.m_surface.m_level, info.m_surface.m_depth);
+		ANKI_ASSERT(!"TODO");
 		break;
 	case GL_TEXTURE_CUBE_MAP_ARRAY:
-		glFramebufferTextureLayer(target,
-			attachment,
-			tex.getGlName(),
-			info.m_surface.m_level,
-			info.m_surface.m_layer * 6 + info.m_surface.m_face);
+		glFramebufferTextureLayer(
+			target, attachment, view.getGlName(), view.getBaseMipmap(), view.getBaseLayer() * 6 + view.getBaseFace());
 		break;
 	default:
 		ANKI_ASSERT(0);
@@ -258,8 +245,7 @@ void FramebufferImpl::bind(const GlState& state, U32 minx, U32 miny, U32 width,
 		}
 
 		// Clear depth
-		if(!!(m_dsAspect & DepthStencilAspectBit::DEPTH) && m_in.m_depthStencilAttachment.m_texture.isCreated()
-			&& m_in.m_depthStencilAttachment.m_loadOperation == AttachmentLoadOperation::CLEAR)
+		if(m_clearDepth)
 		{
 			// Enable write mask in case a pipeline changed it (else no clear will happen) and then restore state
 			if(state.m_depthWriteMask == false)
@@ -276,8 +262,7 @@ void FramebufferImpl::bind(const GlState& state, U32 minx, U32 miny, U32 width,
 		}
 
 		// Clear stencil
-		if(!!(m_dsAspect & DepthStencilAspectBit::STENCIL) && m_in.m_depthStencilAttachment.m_texture.isCreated()
-			&& m_in.m_depthStencilAttachment.m_stencilLoadOperation == AttachmentLoadOperation::CLEAR)
+		if(m_clearStencil)
 		{
 			// Enable write mask in case a pipeline changed it (else no clear will happen) and then restore state
 			// From the spec: The clear operation always uses the front stencil write mask when clearing the stencil

+ 4 - 14
src/anki/gr/gl/FramebufferImpl.h

@@ -42,18 +42,6 @@ public:
 		return m_in.m_colorAttachmentCount;
 	}
 
-	Bool hasDepthBuffer() const
-	{
-		return m_in.m_depthStencilAttachment.m_texture.isCreated()
-			&& !!(m_in.m_depthStencilAttachment.m_aspect & DepthStencilAspectBit::DEPTH);
-	}
-
-	Bool hasStencilBuffer() const
-	{
-		return m_in.m_depthStencilAttachment.m_texture.isCreated()
-			&& !!(m_in.m_depthStencilAttachment.m_aspect & DepthStencilAspectBit::STENCIL);
-	}
-
 private:
 	FramebufferInitInfo m_in;
 
@@ -62,10 +50,12 @@ private:
 	Array<GLenum, MAX_COLOR_ATTACHMENTS + 1> m_invalidateBuffers;
 	U8 m_invalidateBuffersCount = 0;
 	Bool8 m_bindDefault = false;
-	DepthStencilAspectBit m_dsAspect = DepthStencilAspectBit::NONE;
+	Bool8 m_clearDepth = false;
+	Bool8 m_clearStencil = false;
 
 	/// Attach a texture
-	static void attachTextureInternal(GLenum attachment, const TextureImpl& tex, const FramebufferAttachmentInfo& info);
+	static void attachTextureInternal(
+		GLenum attachment, const TextureViewImpl& view, const FramebufferAttachmentInfo& info);
 
 	/// Create the FBO
 	ANKI_USE_RESULT Error createFbo(const Array<U, MAX_COLOR_ATTACHMENTS + 1>& layers, GLenum depthStencilBindingPoint);

+ 58 - 10
src/anki/gr/gl/TextureImpl.cpp

@@ -50,10 +50,10 @@ class DeleteTextureCommand final : public GlCommand
 {
 public:
 	GLuint m_tex;
-	DynamicArray<GLuint> m_views;
+	HashMap<TextureSubresourceInfo, MicroTextureView> m_views;
 	GrAllocator<U8> m_alloc;
 
-	DeleteTextureCommand(GLuint tex, DynamicArray<GLuint>& views, GrAllocator<U8> alloc)
+	DeleteTextureCommand(GLuint tex, HashMap<TextureSubresourceInfo, MicroTextureView>& views, GrAllocator<U8> alloc)
 		: m_tex(tex)
 		, m_views(std::move(views))
 		, m_alloc(alloc)
@@ -63,16 +63,15 @@ public:
 	Error operator()(GlState& state)
 	{
 		// Delete views
-		if(m_views.getSize() > 0)
+		auto it = m_views.getBegin();
+		auto end = m_views.getEnd();
+		while(it != end)
 		{
-			for(GLuint name : m_views)
-			{
-				if(name != 0)
-				{
-					glDeleteTextures(1, &name);
-				}
-			}
+			const MicroTextureView& view = *it;
+			glDeleteTextures(1, &view.m_glName);
+			++it;
 		}
+
 		m_views.destroy(m_alloc);
 
 		// Delete texture
@@ -433,4 +432,53 @@ U TextureImpl::computeSurfaceIdx(const TextureSurfaceInfo& surf) const
 	return out;
 }
 
+MicroTextureView TextureImpl::getOrCreateView(const TextureSubresourceInfo& subresource) const
+{
+	LockGuard<Mutex> lock(m_viewsMapMtx);
+	auto it = m_viewsMap.find(subresource);
+
+	if(it != m_viewsMap.getEnd())
+	{
+		return *it;
+	}
+	else
+	{
+		// Create a new view
+
+		// Compute the new target if needed
+		const TextureType newTexType = computeNewTexTypeOfSubresource(subresource);
+		GLenum glTarget = m_target;
+		if(newTexType == TextureType::_2D)
+		{
+			// Change that anyway
+			glTarget = GL_TEXTURE_2D;
+		}
+
+		const U firstSurf = computeSurfaceIdx(
+			TextureSurfaceInfo(subresource.m_baseMipmap, 0, subresource.m_baseFace, subresource.m_baseLayer));
+		const U lastSurf = computeSurfaceIdx(TextureSurfaceInfo(subresource.m_baseMipmap,
+			0,
+			subresource.m_baseFace + subresource.m_faceCount - 1,
+			subresource.m_baseLayer + subresource.m_layerCount - 1));
+		ANKI_ASSERT(firstSurf < lastSurf);
+
+		MicroTextureView view;
+		view.m_aspect = subresource.m_depthStencilAspect;
+
+		glGenTextures(1, &view.m_glName);
+		glTextureView(view.m_glName,
+			glTarget,
+			m_glName,
+			m_internalFormat,
+			subresource.m_baseMipmap,
+			subresource.m_mipmapCount,
+			firstSurf,
+			lastSurf - firstSurf + 1);
+
+		m_viewsMap.emplace(getAllocator(), subresource, view);
+
+		return view;
+	}
+}
+
 } // end namespace anki

+ 23 - 17
src/anki/gr/gl/TextureImpl.h

@@ -8,7 +8,7 @@
 #include <anki/gr/Texture.h>
 #include <anki/gr/gl/GlObject.h>
 #include <anki/gr/common/Misc.h>
-#include <anki/util/DynamicArray.h>
+#include <anki/util/HashMap.h>
 
 namespace anki
 {
@@ -16,19 +16,24 @@ namespace anki
 /// @addtogroup opengl
 /// @{
 
+/// Small wrapper on top of a texture view and its aspect.
+struct MicroTextureView
+{
+	GLuint m_glName;
+	DepthStencilAspectBit m_aspect;
+};
+
 /// Texture container.
 class TextureImpl final : public Texture, public GlObject
 {
 public:
-	GLenum m_target = GL_NONE; ///< GL_TEXTURE_2D, GL_TEXTURE_3D... etc
-	GLenum m_internalFormat = GL_NONE; ///< GL_COMPRESSED_RED, GL_RGB16 etc
+	GLenum m_target = GL_NONE; ///< GL_TEXTURE_2D, GL_TEXTURE_3D... etc.
+	GLenum m_internalFormat = GL_NONE; ///< GL_COMPRESSED_RED, GL_RGB16 etc.
 	GLenum m_glFormat = GL_NONE;
 	GLenum m_glType = GL_NONE;
 	U32 m_surfaceCountPerLevel = 0;
-	U8 m_faceCount = 0; ///< 6 for cubes and 1 for the rest
+	U8 m_faceCount = 0; ///< 6 for cubes and 1 for the rest.
 	Bool8 m_compressed = false;
-	DynamicArray<GLuint> m_texViews; ///< Temp views for gen mips.
-	DepthStencilAspectBit m_dsAspect = DepthStencilAspectBit::NONE;
 
 	TextureImpl(GrManager* manager)
 		: Texture(manager)
@@ -37,17 +42,6 @@ public:
 
 	~TextureImpl();
 
-	void checkSurfaceOrVolume(const TextureSurfaceInfo& surf) const
-	{
-		checkTextureSurface(m_texType, m_depth, m_mipCount, m_layerCount, surf);
-	}
-
-	void checkSurfaceOrVolume(const TextureVolumeInfo& vol) const
-	{
-		ANKI_ASSERT(m_texType == TextureType::_3D);
-		ANKI_ASSERT(vol.m_level < m_mipCount);
-	}
-
 	/// Init some stuff.
 	void preInit(const TextureInitInfo& init);
 
@@ -74,6 +68,18 @@ public:
 	void clear(const TextureSurfaceInfo& surf, const ClearValue& clearValue, DepthStencilAspectBit aspect);
 
 	U computeSurfaceIdx(const TextureSurfaceInfo& surf) const;
+
+	MicroTextureView getOrCreateView(const TextureSubresourceInfo& subresource) const;
+
+	TextureType computeNewTexTypeOfSubresource(const TextureSubresourceInfo& subresource) const
+	{
+		ANKI_ASSERT(isSubresourceValid(subresource));
+		return (textureTypeIsCube(m_texType) && subresource.m_faceCount != 6) ? TextureType::_2D : m_texType;
+	}
+
+private:
+	mutable HashMap<TextureSubresourceInfo, MicroTextureView> m_viewsMap;
+	mutable Mutex m_viewsMapMtx;
 };
 /// @}
 

+ 52 - 0
src/anki/gr/gl/TextureView.cpp

@@ -0,0 +1,52 @@
+// Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/gr/TextureView.h>
+#include <anki/gr/gl/TextureViewImpl.h>
+#include <anki/gr/gl/CommandBufferImpl.h>
+#include <anki/gr/GrManager.h>
+
+namespace anki
+{
+
+TextureView* TextureView::newInstance(GrManager* manager, const TextureViewInitInfo& init)
+{
+	class CreateTextureViewCommand final : public GlCommand
+	{
+	public:
+		TextureViewPtr m_tex;
+
+		CreateTextureCommand(TextureView* tex)
+			: m_tex(tex)
+		{
+		}
+
+		Error operator()(GlState&)
+		{
+			TextureImpl& impl = static_cast<TextureImpl&>(*m_tex);
+
+			impl.init();
+
+			GlObject::State oldState = impl.setStateAtomically(GlObject::State::CREATED);
+			ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
+			(void)oldState;
+
+			return Error::NONE;
+		}
+	};
+
+	TextureViewImpl* impl = manager->getAllocator().newInstance<TextureViewImpl>(manager);
+
+	// Need to pre-init because some funcs ask for members and we don't want to serialize
+	impl->preInit(init);
+
+	CommandBufferPtr cmdb = manager->newCommandBuffer(CommandBufferInitInfo());
+	static_cast<CommandBufferImpl&>(*cmdb).pushBackNewCommand<CreateTextureViewCommand>(impl);
+	static_cast<CommandBufferImpl&>(*cmdb).flush();
+
+	return impl;
+}
+
+} // end namespace anki

+ 31 - 0
src/anki/gr/gl/TextureViewImpl.cpp

@@ -0,0 +1,31 @@
+// Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/gr/gl/TextureViewImpl.h>
+
+namespace anki
+{
+
+void TextureViewImpl::preInit(const TextureViewInitInfo& inf)
+{
+	ANKI_ASSERT(inf.isValid());
+
+	// Store some stuff
+	m_aspect = inf.m_depthStencilAspect;
+	m_baseMip = inf.m_baseMipmap;
+	m_mipCount = inf.m_mipmapCount;
+	m_baseLayer = inf.m_baseLayer;
+	m_layerCount = inf.m_layerCount;
+	m_baseFace = inf.m_baseFace;
+	m_faceCount = inf.m_faceCount;
+
+	m_tex = inf.m_texture;
+	const TextureImpl& tex = static_cast<const TextureImpl&>(*m_tex);
+	ANKI_ASSERT(tex.isSubresourceValid(inf));
+
+	m_texType = tex.computeNewTexTypeOfSubresource(inf);
+}
+
+} // end namespace anki

+ 56 - 0
src/anki/gr/gl/TextureViewImpl.h

@@ -0,0 +1,56 @@
+// Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <anki/gr/TextureView.h>
+#include <anki/gr/gl/GlObject.h>
+#include <anki/gr/gl/TextureImpl.h>
+
+namespace anki
+{
+
+/// @addtogroup opengl
+/// @{
+
+/// Texture view implementation.
+class TextureViewImpl final : public TextureView, public GlObject
+{
+public:
+	MicroTextureView m_view = {};
+	TexturePtr m_tex; ///< Hold a reference.
+
+	TextureViewImpl(GrManager* manager)
+		: TextureView(manager)
+	{
+	}
+
+	~TextureViewImpl()
+	{
+	}
+
+	void preInit(const TextureViewInitInfo& inf);
+
+	void init()
+	{
+		m_view = static_cast<const TextureImpl&>(*m_tex).getOrCreateView(getSubresource());
+	}
+
+	TextureSubresourceInfo getSubresource() const
+	{
+		TextureSubresourceInfo out;
+		out.m_baseMipmap = m_baseMip;
+		out.m_mipmapCount = m_mipCount;
+		out.m_baseLayer = m_baseLayer;
+		out.m_layerCount = m_layerCount;
+		out.m_baseFace = m_baseFace;
+		out.m_faceCount = m_faceCount;
+		out.m_depthStencilAspect = m_aspect;
+		return out;
+	}
+};
+/// @}
+
+} // end namespace anki

+ 1 - 1
src/anki/gr/vulkan/TextureImpl.cpp

@@ -45,7 +45,7 @@ TextureImpl::~TextureImpl()
 Error TextureImpl::init(const TextureInitInfo& init_)
 {
 	TextureInitInfo init = init_;
-	ANKI_ASSERT(textureInitInfoValid(init));
+	ANKI_ASSERT(init.isValid());
 
 	// Set some stuff
 	m_width = init.m_width;

+ 1 - 1
tools/format_source.sh

@@ -13,7 +13,7 @@ do
 	count=$((${count}+1))
 
 	# Throttle the parallel commands
-	if !((count % 8)); then
+	if !((count % 16)); then
 		wait
 	fi
 done