Browse Source

Vulkan: Add stencil support

Panagiotis Christopoulos Charitos 9 years ago
parent
commit
5076452bd8

+ 16 - 0
shaders/Functions.glsl

@@ -53,4 +53,20 @@ vec4 projectPerspective(in vec4 vec, in float m00, in float m11, in float m22, i
 	return o;
 	return o;
 }
 }
 
 
+// Stolen from shadertoy.com/view/4tyGDD
+vec4 textureCatmullRom4Samples(sampler2D tex, vec2 uv, vec2 texSize)
+{
+	vec2 halff = 2.0 * fract(0.5 * uv * texSize - 0.25) - 1.0;
+	vec2 f = fract(halff);
+	vec2 sum0 = (2.0 * f - 3.5) * f + 0.5;
+	vec2 sum1 = (2.0 * f - 2.5) * f - 0.5;
+	vec4 w = vec4(f * sum0 + 1.0, f * sum1);
+	vec4 pos = vec4((((-2.0 * f + 3.0) * f + 0.5) * f - 1.5) * f / (w.xy * texSize) + uv,
+		(((-2.0 * f + 5.0) * f - 2.5) * f - 0.5) / (sum1 * texSize) + uv);
+	w.xz *= halff.x * halff.y > 0.0 ? 1.0 : -1.0;
+
+	return (texture(tex, pos.xy) * w.x + texture(tex, pos.zy) * w.z) * w.y
+		+ (texture(tex, pos.xw) * w.x + texture(tex, pos.zw) * w.z) * w.w;
+}
+
 #endif
 #endif

+ 9 - 33
src/anki/gr/CommandBuffer.h

@@ -178,14 +178,11 @@ public:
 	/// @param tex The texture to generate mips.
 	/// @param tex The texture to generate mips.
 	/// @param face The face of a cube texture or zero.
 	/// @param face The face of a cube texture or zero.
 	/// @param layer The layer of an array texture or zero.
 	/// @param layer The layer of an array texture or zero.
-	/// @param aspect The aspect of the depth stencil texture. Relevant only for depth stencil textures.
-	void generateMipmaps2d(
-		TexturePtr tex, U face, U layer, DepthStencilAspectMask aspect = DepthStencilAspectMask::NONE);
+	void generateMipmaps2d(TexturePtr tex, U face, U layer);
 
 
 	/// Generate mipmaps only for 3D textures.
 	/// Generate mipmaps only for 3D textures.
 	/// @param tex The texture to generate mips.
 	/// @param tex The texture to generate mips.
-	/// @param aspect The aspect of the depth stencil texture. Relevant only for depth stencil textures.
-	void generateMipmaps3d(TexturePtr tex, DepthStencilAspectMask aspect = DepthStencilAspectMask::NONE);
+	void generateMipmaps3d(TexturePtr tex);
 
 
 	// TODO Rename to blit
 	// TODO Rename to blit
 	void copyTextureSurfaceToTextureSurface(
 	void copyTextureSurfaceToTextureSurface(
@@ -232,47 +229,26 @@ public:
 	/// @{
 	/// @{
 
 
 	/// Upload data to a texture surface. It's the base of all texture surface upload methods.
 	/// Upload data to a texture surface. It's the base of all texture surface upload methods.
-	void uploadTextureSurface(TexturePtr tex,
-		const TextureSurfaceInfo& surf,
-		const TransientMemoryToken& token,
-		DepthStencilAspectMask aspect = DepthStencilAspectMask::NONE);
+	void uploadTextureSurface(TexturePtr tex, const TextureSurfaceInfo& surf, const TransientMemoryToken& token);
 
 
 	/// Same as uploadTextureSurface but it will perform the transient allocation as well. If that allocation fails
 	/// Same as uploadTextureSurface but it will perform the transient allocation as well. If that allocation fails
 	/// expect the defaul OOM behaviour (crash).
 	/// expect the defaul OOM behaviour (crash).
-	void uploadTextureSurfaceData(TexturePtr tex,
-		const TextureSurfaceInfo& surf,
-		void*& data,
-		PtrSize& dataSize,
-		DepthStencilAspectMask aspect = DepthStencilAspectMask::NONE);
+	void uploadTextureSurfaceData(TexturePtr tex, const TextureSurfaceInfo& surf, void*& data, PtrSize& dataSize);
 
 
 	/// Same as uploadTextureSurfaceData but it will return a nullptr in @a data if there is a OOM condition.
 	/// Same as uploadTextureSurfaceData but it will return a nullptr in @a data if there is a OOM condition.
-	void tryUploadTextureSurfaceData(TexturePtr tex,
-		const TextureSurfaceInfo& surf,
-		void*& data,
-		PtrSize& dataSize,
-		DepthStencilAspectMask aspect = DepthStencilAspectMask::NONE);
+	void tryUploadTextureSurfaceData(TexturePtr tex, const TextureSurfaceInfo& surf, void*& data, PtrSize& dataSize);
 
 
 	/// Same as uploadTextureSurface but it will perform the transient allocation and copy to it the @a data. If that
 	/// Same as uploadTextureSurface but it will perform the transient allocation and copy to it the @a data. If that
 	/// allocation fails expect the defaul OOM behaviour (crash).
 	/// allocation fails expect the defaul OOM behaviour (crash).
-	void uploadTextureSurfaceCopyData(TexturePtr tex,
-		const TextureSurfaceInfo& surf,
-		const void* data,
-		PtrSize dataSize,
-		DepthStencilAspectMask aspect = DepthStencilAspectMask::NONE);
+	void uploadTextureSurfaceCopyData(
+		TexturePtr tex, const TextureSurfaceInfo& surf, const void* data, PtrSize dataSize);
 
 
 	/// Upload data to a texture volume. It's the base of all texture volume upload methods.
 	/// Upload data to a texture volume. It's the base of all texture volume upload methods.
-	void uploadTextureVolume(TexturePtr tex,
-		const TextureVolumeInfo& vol,
-		const TransientMemoryToken& token,
-		DepthStencilAspectMask aspect = DepthStencilAspectMask::NONE);
+	void uploadTextureVolume(TexturePtr tex, const TextureVolumeInfo& vol, const TransientMemoryToken& token);
 
 
 	/// Same as uploadTextureVolume but it will perform the transient allocation and copy to it the @a data. If that
 	/// Same as uploadTextureVolume but it will perform the transient allocation and copy to it the @a data. If that
 	/// allocation fails expect the defaul OOM behaviour (crash).
 	/// allocation fails expect the defaul OOM behaviour (crash).
-	void uploadTextureVolumeCopyData(TexturePtr tex,
-		const TextureVolumeInfo& surf,
-		const void* data,
-		PtrSize dataSize,
-		DepthStencilAspectMask aspect = DepthStencilAspectMask::NONE);
+	void uploadTextureVolumeCopyData(TexturePtr tex, const TextureVolumeInfo& surf, const void* data, PtrSize dataSize);
 
 
 	/// Upload data to a buffer.
 	/// Upload data to a buffer.
 	void uploadBuffer(BufferPtr buff, PtrSize offset, const TransientMemoryToken& token);
 	void uploadBuffer(BufferPtr buff, PtrSize offset, const TransientMemoryToken& token);

+ 8 - 8
src/anki/gr/CommandBuffer.inl.h

@@ -10,7 +10,7 @@ namespace anki
 {
 {
 
 
 inline void CommandBuffer::uploadTextureSurfaceData(
 inline void CommandBuffer::uploadTextureSurfaceData(
-	TexturePtr tex, const TextureSurfaceInfo& surf, void*& data, PtrSize& dataSize, DepthStencilAspectMask aspect)
+	TexturePtr tex, const TextureSurfaceInfo& surf, void*& data, PtrSize& dataSize)
 {
 {
 	PtrSize allocationSize;
 	PtrSize allocationSize;
 	const BufferUsageBit usage = BufferUsageBit::TEXTURE_UPLOAD_SOURCE;
 	const BufferUsageBit usage = BufferUsageBit::TEXTURE_UPLOAD_SOURCE;
@@ -20,11 +20,11 @@ inline void CommandBuffer::uploadTextureSurfaceData(
 	TransientMemoryToken token;
 	TransientMemoryToken token;
 	data = getManager().allocateFrameTransientMemory(allocationSize, usage, token);
 	data = getManager().allocateFrameTransientMemory(allocationSize, usage, token);
 
 
-	uploadTextureSurface(tex, surf, token, aspect);
+	uploadTextureSurface(tex, surf, token);
 }
 }
 
 
 inline void CommandBuffer::tryUploadTextureSurfaceData(
 inline void CommandBuffer::tryUploadTextureSurfaceData(
-	TexturePtr tex, const TextureSurfaceInfo& surf, void*& data, PtrSize& dataSize, DepthStencilAspectMask aspect)
+	TexturePtr tex, const TextureSurfaceInfo& surf, void*& data, PtrSize& dataSize)
 {
 {
 	PtrSize allocationSize;
 	PtrSize allocationSize;
 	const BufferUsageBit usage = BufferUsageBit::TEXTURE_UPLOAD_SOURCE;
 	const BufferUsageBit usage = BufferUsageBit::TEXTURE_UPLOAD_SOURCE;
@@ -36,12 +36,12 @@ inline void CommandBuffer::tryUploadTextureSurfaceData(
 
 
 	if(data)
 	if(data)
 	{
 	{
-		uploadTextureSurface(tex, surf, token, aspect);
+		uploadTextureSurface(tex, surf, token);
 	}
 	}
 }
 }
 
 
 inline void CommandBuffer::uploadTextureSurfaceCopyData(
 inline void CommandBuffer::uploadTextureSurfaceCopyData(
-	TexturePtr tex, const TextureSurfaceInfo& surf, const void* data, PtrSize dataSize, DepthStencilAspectMask aspect)
+	TexturePtr tex, const TextureSurfaceInfo& surf, const void* data, PtrSize dataSize)
 {
 {
 	PtrSize allocationSize;
 	PtrSize allocationSize;
 	const BufferUsageBit usage = BufferUsageBit::TEXTURE_UPLOAD_SOURCE;
 	const BufferUsageBit usage = BufferUsageBit::TEXTURE_UPLOAD_SOURCE;
@@ -52,11 +52,11 @@ inline void CommandBuffer::uploadTextureSurfaceCopyData(
 	void* ptr = getManager().allocateFrameTransientMemory(allocationSize, usage, token);
 	void* ptr = getManager().allocateFrameTransientMemory(allocationSize, usage, token);
 	memcpy(ptr, data, dataSize);
 	memcpy(ptr, data, dataSize);
 
 
-	uploadTextureSurface(tex, surf, token, aspect);
+	uploadTextureSurface(tex, surf, token);
 }
 }
 
 
 inline void CommandBuffer::uploadTextureVolumeCopyData(
 inline void CommandBuffer::uploadTextureVolumeCopyData(
-	TexturePtr tex, const TextureVolumeInfo& vol, const void* data, PtrSize dataSize, DepthStencilAspectMask aspect)
+	TexturePtr tex, const TextureVolumeInfo& vol, const void* data, PtrSize dataSize)
 {
 {
 	PtrSize allocationSize;
 	PtrSize allocationSize;
 	const BufferUsageBit usage = BufferUsageBit::TEXTURE_UPLOAD_SOURCE;
 	const BufferUsageBit usage = BufferUsageBit::TEXTURE_UPLOAD_SOURCE;
@@ -67,7 +67,7 @@ inline void CommandBuffer::uploadTextureVolumeCopyData(
 	void* ptr = getManager().allocateFrameTransientMemory(allocationSize, usage, token);
 	void* ptr = getManager().allocateFrameTransientMemory(allocationSize, usage, token);
 	memcpy(ptr, data, dataSize);
 	memcpy(ptr, data, dataSize);
 
 
-	uploadTextureVolume(tex, vol, token, aspect);
+	uploadTextureVolume(tex, vol, token);
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 1 - 1
src/anki/gr/ResourceGroup.h

@@ -23,7 +23,7 @@ public:
 	TexturePtr m_texture;
 	TexturePtr m_texture;
 	SamplerPtr m_sampler; ///< Use it to override texture's sampler.
 	SamplerPtr m_sampler; ///< Use it to override texture's sampler.
 	TextureUsageBit m_usage = TextureUsageBit::SAMPLED_FRAGMENT;
 	TextureUsageBit m_usage = TextureUsageBit::SAMPLED_FRAGMENT;
-	DepthStencilAspectMask m_aspect = DepthStencilAspectMask::NONE; ///< Relevant only for depth stencil textures.
+	DepthStencilAspectMask m_aspect = DepthStencilAspectMask::DEPTH; ///< Relevant only for depth stencil textures.
 };
 };
 
 
 /// Buffer binding info.
 /// Buffer binding info.

+ 13 - 26
src/anki/gr/gl/CommandBuffer.cpp

@@ -300,7 +300,7 @@ void CommandBuffer::endOcclusionQuery(OcclusionQueryPtr query)
 }
 }
 
 
 void CommandBuffer::uploadTextureSurface(
 void CommandBuffer::uploadTextureSurface(
-	TexturePtr tex, const TextureSurfaceInfo& surf, const TransientMemoryToken& token, DepthStencilAspectMask aspect)
+	TexturePtr tex, const TextureSurfaceInfo& surf, const TransientMemoryToken& token)
 {
 {
 	class TexSurfUploadCommand final : public GlCommand
 	class TexSurfUploadCommand final : public GlCommand
 	{
 	{
@@ -308,16 +308,11 @@ void CommandBuffer::uploadTextureSurface(
 		TexturePtr m_handle;
 		TexturePtr m_handle;
 		TextureSurfaceInfo m_surf;
 		TextureSurfaceInfo m_surf;
 		TransientMemoryToken m_token;
 		TransientMemoryToken m_token;
-		DepthStencilAspectMask m_aspect;
 
 
-		TexSurfUploadCommand(const TexturePtr& handle,
-			TextureSurfaceInfo surf,
-			const TransientMemoryToken& token,
-			DepthStencilAspectMask aspect)
+		TexSurfUploadCommand(const TexturePtr& handle, TextureSurfaceInfo surf, const TransientMemoryToken& token)
 			: m_handle(handle)
 			: m_handle(handle)
 			, m_surf(surf)
 			, m_surf(surf)
 			, m_token(token)
 			, m_token(token)
-			, m_aspect(aspect)
 		{
 		{
 		}
 		}
 
 
@@ -326,7 +321,7 @@ void CommandBuffer::uploadTextureSurface(
 			void* data = state.m_manager->getImplementation().getTransientMemoryManager().getBaseAddress(m_token);
 			void* data = state.m_manager->getImplementation().getTransientMemoryManager().getBaseAddress(m_token);
 			data = static_cast<void*>(static_cast<U8*>(data) + m_token.m_offset);
 			data = static_cast<void*>(static_cast<U8*>(data) + m_token.m_offset);
 
 
-			m_handle->getImplementation().writeSurface(m_surf, data, m_token.m_range, m_aspect);
+			m_handle->getImplementation().writeSurface(m_surf, data, m_token.m_range);
 
 
 			if(m_token.m_lifetime == TransientMemoryTokenLifetime::PERSISTENT)
 			if(m_token.m_lifetime == TransientMemoryTokenLifetime::PERSISTENT)
 			{
 			{
@@ -341,11 +336,10 @@ void CommandBuffer::uploadTextureSurface(
 	ANKI_ASSERT(token.m_range > 0);
 	ANKI_ASSERT(token.m_range > 0);
 	ANKI_ASSERT(!m_impl->m_dbg.m_insideRenderPass);
 	ANKI_ASSERT(!m_impl->m_dbg.m_insideRenderPass);
 
 
-	m_impl->pushBackNewCommand<TexSurfUploadCommand>(tex, surf, token, aspect);
+	m_impl->pushBackNewCommand<TexSurfUploadCommand>(tex, surf, token);
 }
 }
 
 
-void CommandBuffer::uploadTextureVolume(
-	TexturePtr tex, const TextureVolumeInfo& vol, const TransientMemoryToken& token, DepthStencilAspectMask aspect)
+void CommandBuffer::uploadTextureVolume(TexturePtr tex, const TextureVolumeInfo& vol, const TransientMemoryToken& token)
 {
 {
 	class TexVolUploadCommand final : public GlCommand
 	class TexVolUploadCommand final : public GlCommand
 	{
 	{
@@ -353,16 +347,11 @@ void CommandBuffer::uploadTextureVolume(
 		TexturePtr m_handle;
 		TexturePtr m_handle;
 		TextureVolumeInfo m_vol;
 		TextureVolumeInfo m_vol;
 		TransientMemoryToken m_token;
 		TransientMemoryToken m_token;
-		DepthStencilAspectMask m_aspect;
 
 
-		TexVolUploadCommand(const TexturePtr& handle,
-			TextureVolumeInfo vol,
-			const TransientMemoryToken& token,
-			DepthStencilAspectMask aspect)
+		TexVolUploadCommand(const TexturePtr& handle, TextureVolumeInfo vol, const TransientMemoryToken& token)
 			: m_handle(handle)
 			: m_handle(handle)
 			, m_vol(vol)
 			, m_vol(vol)
 			, m_token(token)
 			, m_token(token)
-			, m_aspect(aspect)
 		{
 		{
 		}
 		}
 
 
@@ -371,7 +360,7 @@ void CommandBuffer::uploadTextureVolume(
 			void* data = state.m_manager->getImplementation().getTransientMemoryManager().getBaseAddress(m_token);
 			void* data = state.m_manager->getImplementation().getTransientMemoryManager().getBaseAddress(m_token);
 			data = static_cast<void*>(static_cast<U8*>(data) + m_token.m_offset);
 			data = static_cast<void*>(static_cast<U8*>(data) + m_token.m_offset);
 
 
-			m_handle->getImplementation().writeVolume(m_vol, data, m_token.m_range, m_aspect);
+			m_handle->getImplementation().writeVolume(m_vol, data, m_token.m_range);
 
 
 			if(m_token.m_lifetime == TransientMemoryTokenLifetime::PERSISTENT)
 			if(m_token.m_lifetime == TransientMemoryTokenLifetime::PERSISTENT)
 			{
 			{
@@ -386,7 +375,7 @@ void CommandBuffer::uploadTextureVolume(
 	ANKI_ASSERT(token.m_range > 0);
 	ANKI_ASSERT(token.m_range > 0);
 	ANKI_ASSERT(!m_impl->m_dbg.m_insideRenderPass);
 	ANKI_ASSERT(!m_impl->m_dbg.m_insideRenderPass);
 
 
-	m_impl->pushBackNewCommand<TexVolUploadCommand>(tex, vol, token, aspect);
+	m_impl->pushBackNewCommand<TexVolUploadCommand>(tex, vol, token);
 }
 }
 
 
 void CommandBuffer::uploadBuffer(BufferPtr buff, PtrSize offset, const TransientMemoryToken& token)
 void CommandBuffer::uploadBuffer(BufferPtr buff, PtrSize offset, const TransientMemoryToken& token)
@@ -428,7 +417,7 @@ void CommandBuffer::uploadBuffer(BufferPtr buff, PtrSize offset, const Transient
 	m_impl->pushBackNewCommand<BuffWriteCommand>(buff, offset, token);
 	m_impl->pushBackNewCommand<BuffWriteCommand>(buff, offset, token);
 }
 }
 
 
-void CommandBuffer::generateMipmaps2d(TexturePtr tex, U face, U layer, DepthStencilAspectMask aspect)
+void CommandBuffer::generateMipmaps2d(TexturePtr tex, U face, U layer)
 {
 {
 	class GenMipsCommand final : public GlCommand
 	class GenMipsCommand final : public GlCommand
 	{
 	{
@@ -436,28 +425,26 @@ void CommandBuffer::generateMipmaps2d(TexturePtr tex, U face, U layer, DepthSten
 		TexturePtr m_tex;
 		TexturePtr m_tex;
 		U8 m_face;
 		U8 m_face;
 		U32 m_layer;
 		U32 m_layer;
-		DepthStencilAspectMask m_aspect;
 
 
-		GenMipsCommand(const TexturePtr& tex, U face, U layer, DepthStencilAspectMask aspect)
+		GenMipsCommand(const TexturePtr& tex, U face, U layer)
 			: m_tex(tex)
 			: m_tex(tex)
 			, m_face(face)
 			, m_face(face)
 			, m_layer(layer)
 			, m_layer(layer)
-			, m_aspect(aspect)
 		{
 		{
 		}
 		}
 
 
 		Error operator()(GlState&)
 		Error operator()(GlState&)
 		{
 		{
-			m_tex->getImplementation().generateMipmaps2d(m_face, m_layer, m_aspect);
+			m_tex->getImplementation().generateMipmaps2d(m_face, m_layer);
 			return ErrorCode::NONE;
 			return ErrorCode::NONE;
 		}
 		}
 	};
 	};
 
 
 	ANKI_ASSERT(!m_impl->m_dbg.m_insideRenderPass);
 	ANKI_ASSERT(!m_impl->m_dbg.m_insideRenderPass);
-	m_impl->pushBackNewCommand<GenMipsCommand>(tex, face, layer, aspect);
+	m_impl->pushBackNewCommand<GenMipsCommand>(tex, face, layer);
 }
 }
 
 
-void CommandBuffer::generateMipmaps3d(TexturePtr tex, DepthStencilAspectMask aspect)
+void CommandBuffer::generateMipmaps3d(TexturePtr tex)
 {
 {
 	ANKI_ASSERT(!!"TODO");
 	ANKI_ASSERT(!!"TODO");
 }
 }

+ 3 - 7
src/anki/gr/gl/TextureImpl.cpp

@@ -462,13 +462,11 @@ void TextureImpl::init(const TextureInitInfo& init)
 	ANKI_CHECK_GL_ERROR();
 	ANKI_CHECK_GL_ERROR();
 }
 }
 
 
-void TextureImpl::writeSurface(
-	const TextureSurfaceInfo& surf, void* data, PtrSize dataSize, DepthStencilAspectMask aspect)
+void TextureImpl::writeSurface(const TextureSurfaceInfo& surf, void* data, PtrSize dataSize)
 {
 {
 	checkSurface(surf);
 	checkSurface(surf);
 	ANKI_ASSERT(data);
 	ANKI_ASSERT(data);
 	ANKI_ASSERT(dataSize > 0);
 	ANKI_ASSERT(dataSize > 0);
-	ANKI_ASSERT(!aspect && "TODO");
 
 
 	U mipmap = surf.m_level;
 	U mipmap = surf.m_level;
 	U surfIdx = computeSurfaceIdx(surf);
 	U surfIdx = computeSurfaceIdx(surf);
@@ -520,13 +518,12 @@ void TextureImpl::writeSurface(
 	ANKI_CHECK_GL_ERROR();
 	ANKI_CHECK_GL_ERROR();
 }
 }
 
 
-void TextureImpl::writeVolume(const TextureVolumeInfo& vol, void* data, PtrSize dataSize, DepthStencilAspectMask aspect)
+void TextureImpl::writeVolume(const TextureVolumeInfo& vol, void* data, PtrSize dataSize)
 {
 {
 	checkVolume(vol);
 	checkVolume(vol);
 	ANKI_ASSERT(data);
 	ANKI_ASSERT(data);
 	ANKI_ASSERT(dataSize > 0);
 	ANKI_ASSERT(dataSize > 0);
 	ANKI_ASSERT(m_texType == TextureType::_3D);
 	ANKI_ASSERT(m_texType == TextureType::_3D);
-	ANKI_ASSERT(!aspect && "TODO");
 
 
 	U mipmap = vol.m_level;
 	U mipmap = vol.m_level;
 	U w = m_width >> mipmap;
 	U w = m_width >> mipmap;
@@ -550,11 +547,10 @@ void TextureImpl::writeVolume(const TextureVolumeInfo& vol, void* data, PtrSize
 	ANKI_CHECK_GL_ERROR();
 	ANKI_CHECK_GL_ERROR();
 }
 }
 
 
-void TextureImpl::generateMipmaps2d(U face, U layer, DepthStencilAspectMask aspect)
+void TextureImpl::generateMipmaps2d(U face, U layer)
 {
 {
 	U surface = computeSurfaceIdx(TextureSurfaceInfo(0, 0, face, layer));
 	U surface = computeSurfaceIdx(TextureSurfaceInfo(0, 0, face, layer));
 	ANKI_ASSERT(!m_compressed);
 	ANKI_ASSERT(!m_compressed);
-	ANKI_ASSERT(aspect == m_dsAspect && "For now");
 
 
 	if(m_surfaceCountPerLevel > 1)
 	if(m_surfaceCountPerLevel > 1)
 	{
 	{

+ 3 - 3
src/anki/gr/gl/TextureImpl.h

@@ -61,13 +61,13 @@ public:
 	void init(const TextureInitInfo& init);
 	void init(const TextureInitInfo& init);
 
 
 	/// Write texture data.
 	/// Write texture data.
-	void writeSurface(const TextureSurfaceInfo& surf, void* data, PtrSize dataSize, DepthStencilAspectMask aspect);
+	void writeSurface(const TextureSurfaceInfo& surf, void* data, PtrSize dataSize);
 
 
 	/// Write texture data.
 	/// Write texture data.
-	void writeVolume(const TextureVolumeInfo& vol, void* data, PtrSize dataSize, DepthStencilAspectMask aspect);
+	void writeVolume(const TextureVolumeInfo& vol, void* data, PtrSize dataSize);
 
 
 	/// Generate mipmaps.
 	/// Generate mipmaps.
-	void generateMipmaps2d(U face, U layer, DepthStencilAspectMask aspect);
+	void generateMipmaps2d(U face, U layer);
 
 
 	/// Copy a single surface from one texture to another.
 	/// Copy a single surface from one texture to another.
 	static void copy(const TextureImpl& src,
 	static void copy(const TextureImpl& src,

+ 24 - 12
src/anki/gr/vulkan/CommandBuffer.cpp

@@ -121,34 +121,31 @@ void CommandBuffer::generateMipmaps2d(TexturePtr tex, U face, U layer)
 
 
 void CommandBuffer::generateMipmaps3d(TexturePtr tex)
 void CommandBuffer::generateMipmaps3d(TexturePtr tex)
 {
 {
-	ANKI_ASSERT(0 && "TODO");
+	ANKI_ASSERT(!"TODO");
 }
 }
 
 
 void CommandBuffer::copyTextureSurfaceToTextureSurface(
 void CommandBuffer::copyTextureSurfaceToTextureSurface(
 	TexturePtr src, const TextureSurfaceInfo& srcSurf, TexturePtr dest, const TextureSurfaceInfo& destSurf)
 	TexturePtr src, const TextureSurfaceInfo& srcSurf, TexturePtr dest, const TextureSurfaceInfo& destSurf)
 {
 {
-	ANKI_ASSERT(0 && "TODO");
+	ANKI_ASSERT(!"TODO");
 }
 }
 
 
 void CommandBuffer::copyTextureVolumeToTextureVolume(
 void CommandBuffer::copyTextureVolumeToTextureVolume(
 	TexturePtr src, const TextureVolumeInfo& srcVol, TexturePtr dest, const TextureVolumeInfo& destVol)
 	TexturePtr src, const TextureVolumeInfo& srcVol, TexturePtr dest, const TextureVolumeInfo& destVol)
 {
 {
-	ANKI_ASSERT(0 && "TODO");
+	ANKI_ASSERT(!"TODO");
 }
 }
 
 
-void CommandBuffer::clearTexture(TexturePtr tex, const ClearValue& clearValue)
+void CommandBuffer::clearTextureSurface(
+	TexturePtr tex, const TextureSurfaceInfo& surf, const ClearValue& clearValue, DepthStencilAspectMask aspect)
 {
 {
-	m_impl->clearTexture(tex, clearValue);
+	m_impl->clearTextureSurface(tex, surf, clearValue, aspect);
 }
 }
 
 
-void CommandBuffer::clearTextureSurface(TexturePtr tex, const TextureSurfaceInfo& surf, const ClearValue& clearValue)
+void CommandBuffer::clearTextureVolume(
+	TexturePtr tex, const TextureVolumeInfo& vol, const ClearValue& clearValue, DepthStencilAspectMask aspect)
 {
 {
-	m_impl->clearTextureSurface(tex, surf, clearValue);
-}
-
-void CommandBuffer::clearTextureVolume(TexturePtr tex, const TextureVolumeInfo& vol, const ClearValue& clearValue)
-{
-	m_impl->clearTextureVolume(tex, vol, clearValue);
+	m_impl->clearTextureVolume(tex, vol, clearValue, aspect);
 }
 }
 
 
 void CommandBuffer::uploadTextureSurface(
 void CommandBuffer::uploadTextureSurface(
@@ -220,4 +217,19 @@ void CommandBuffer::writeOcclusionQueryResultToBuffer(OcclusionQueryPtr query, P
 	m_impl->writeOcclusionQueryResultToBuffer(query, offset, buff);
 	m_impl->writeOcclusionQueryResultToBuffer(query, offset, buff);
 }
 }
 
 
+void CommandBuffer::setStencilCompareMask(FaceSelectionMask face, U32 mask)
+{
+	m_impl->setStencilCompareMask(face, mask);
+}
+
+void CommandBuffer::setStencilWriteMask(FaceSelectionMask face, U32 mask)
+{
+	m_impl->setStencilWriteMask(face, mask);
+}
+
+void CommandBuffer::setStencilReference(FaceSelectionMask face, U32 ref)
+{
+	m_impl->setStencilReference(face, ref);
+}
+
 } // end namespace anki
 } // end namespace anki

+ 4 - 4
src/anki/gr/vulkan/CommandBufferImpl.cpp

@@ -259,7 +259,7 @@ void CommandBufferImpl::generateMipmaps2d(TexturePtr tex, U face, U layer)
 		if(i > 0)
 		if(i > 0)
 		{
 		{
 			VkImageSubresourceRange range;
 			VkImageSubresourceRange range;
-			impl.computeSubResourceRange(TextureSurfaceInfo(i, 0, face, layer), range);
+			impl.computeSubResourceRange(TextureSurfaceInfo(i, 0, face, layer), impl.m_akAspect, range);
 
 
 			setImageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
 			setImageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
 				VK_ACCESS_TRANSFER_WRITE_BIT,
 				VK_ACCESS_TRANSFER_WRITE_BIT,
@@ -274,7 +274,7 @@ void CommandBufferImpl::generateMipmaps2d(TexturePtr tex, U face, U layer)
 		// Transition destination
 		// Transition destination
 		{
 		{
 			VkImageSubresourceRange range;
 			VkImageSubresourceRange range;
-			impl.computeSubResourceRange(TextureSurfaceInfo(i + 1, 0, face, layer), range);
+			impl.computeSubResourceRange(TextureSurfaceInfo(i + 1, 0, face, layer), impl.m_akAspect, range);
 
 
 			setImageBarrier(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
 			setImageBarrier(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
 				0,
 				0,
@@ -313,14 +313,14 @@ void CommandBufferImpl::generateMipmaps2d(TexturePtr tex, U face, U layer)
 		}
 		}
 
 
 		VkImageBlit blit;
 		VkImageBlit blit;
-		blit.srcSubresource.aspectMask = impl.m_aspect & (~VK_IMAGE_ASPECT_STENCIL_BIT);
+		blit.srcSubresource.aspectMask = impl.m_aspect;
 		blit.srcSubresource.baseArrayLayer = vkLayer;
 		blit.srcSubresource.baseArrayLayer = vkLayer;
 		blit.srcSubresource.layerCount = 1;
 		blit.srcSubresource.layerCount = 1;
 		blit.srcSubresource.mipLevel = i;
 		blit.srcSubresource.mipLevel = i;
 		blit.srcOffsets[0] = {0, 0, 0};
 		blit.srcOffsets[0] = {0, 0, 0};
 		blit.srcOffsets[1] = {srcWidth, srcHeight, 1};
 		blit.srcOffsets[1] = {srcWidth, srcHeight, 1};
 
 
-		blit.dstSubresource.aspectMask = impl.m_aspect & (~VK_IMAGE_ASPECT_STENCIL_BIT);
+		blit.dstSubresource.aspectMask = impl.m_aspect;
 		blit.dstSubresource.baseArrayLayer = vkLayer;
 		blit.dstSubresource.baseArrayLayer = vkLayer;
 		blit.dstSubresource.layerCount = 1;
 		blit.dstSubresource.layerCount = 1;
 		blit.dstSubresource.mipLevel = i + 1;
 		blit.dstSubresource.mipLevel = i + 1;

+ 20 - 4
src/anki/gr/vulkan/CommandBufferImpl.h

@@ -65,6 +65,12 @@ public:
 
 
 	void setPolygonOffset(F32 factor, F32 units);
 	void setPolygonOffset(F32 factor, F32 units);
 
 
+	void setStencilCompareMask(FaceSelectionMask face, U32 mask);
+
+	void setStencilWriteMask(FaceSelectionMask face, U32 mask);
+
+	void setStencilReference(FaceSelectionMask face, U32 ref);
+
 	void bindPipeline(PipelinePtr ppline);
 	void bindPipeline(PipelinePtr ppline);
 
 
 	void beginRenderPass(FramebufferPtr fb);
 	void beginRenderPass(FramebufferPtr fb);
@@ -95,11 +101,11 @@ public:
 
 
 	void generateMipmaps2d(TexturePtr tex, U face, U layer);
 	void generateMipmaps2d(TexturePtr tex, U face, U layer);
 
 
-	void clearTexture(TexturePtr tex, const ClearValue& clearValue);
-
-	void clearTextureSurface(TexturePtr tex, const TextureSurfaceInfo& surf, const ClearValue& clearValue);
+	void clearTextureSurface(
+		TexturePtr tex, const TextureSurfaceInfo& surf, const ClearValue& clearValue, DepthStencilAspectMask aspect);
 
 
-	void clearTextureVolume(TexturePtr tex, const TextureVolumeInfo& volume, const ClearValue& clearValue);
+	void clearTextureVolume(
+		TexturePtr tex, const TextureVolumeInfo& volume, const ClearValue& clearValue, DepthStencilAspectMask aspect);
 
 
 	void uploadBuffer(BufferPtr buff, PtrSize offset, const TransientMemoryToken& token);
 	void uploadBuffer(BufferPtr buff, PtrSize offset, const TransientMemoryToken& token);
 
 
@@ -177,6 +183,16 @@ private:
 
 
 	CommandBufferCommandType m_lastCmdType = CommandBufferCommandType::ANY_OTHER_COMMAND;
 	CommandBufferCommandType m_lastCmdType = CommandBufferCommandType::ANY_OTHER_COMMAND;
 
 
+	/// @name state_opts
+	/// @{
+	Array<U16, 4> m_viewport = {{0, 0, 0, 0}};
+	F32 m_polygonOffsetFactor = MAX_F32;
+	F32 m_polygonOffsetUnits = MAX_F32;
+	Array<U32, 2> m_stencilCompareMasks = {{0x5A5A5A5A, 0x5A5A5A5A}}; ///< Use a stupid number to initialize.
+	Array<U32, 2> m_stencilWriteMasks = {{0x5A5A5A5A, 0x5A5A5A5A}};
+	Array<U32, 2> m_stencilReferenceMasks = {{0x5A5A5A5A, 0x5A5A5A5A}};
+	/// @}
+
 	/// @name barrier_batch
 	/// @name barrier_batch
 	/// @{
 	/// @{
 	DynamicArray<VkImageMemoryBarrier> m_imgBarriers;
 	DynamicArray<VkImageMemoryBarrier> m_imgBarriers;

+ 119 - 35
src/anki/gr/vulkan/CommandBufferImpl.inl.h

@@ -17,29 +17,125 @@ namespace anki
 
 
 inline void CommandBufferImpl::setViewport(U16 minx, U16 miny, U16 maxx, U16 maxy)
 inline void CommandBufferImpl::setViewport(U16 minx, U16 miny, U16 maxx, U16 maxy)
 {
 {
-	commandCommon();
 	ANKI_ASSERT(minx < maxx && miny < maxy);
 	ANKI_ASSERT(minx < maxx && miny < maxy);
-	VkViewport s;
-	s.x = minx;
-	s.y = miny;
-	s.width = maxx - minx;
-	s.height = maxy - miny;
-	s.minDepth = 0.0;
-	s.maxDepth = 1.0;
-	ANKI_CMD(vkCmdSetViewport(m_handle, 0, 1, &s), ANY_OTHER_COMMAND);
-
-	VkRect2D scissor = {};
-	scissor.extent.width = maxx - minx;
-	scissor.extent.height = maxy - miny;
-	scissor.offset.x = minx;
-	scissor.offset.y = miny;
-	ANKI_CMD(vkCmdSetScissor(m_handle, 0, 1, &scissor), ANY_OTHER_COMMAND);
+	commandCommon();
+
+	if(m_viewport[0] != minx || m_viewport[1] != miny || m_viewport[2] != maxx || m_viewport[3] != maxy)
+	{
+		VkViewport s;
+		s.x = minx;
+		s.y = miny;
+		s.width = maxx - minx;
+		s.height = maxy - miny;
+		s.minDepth = 0.0;
+		s.maxDepth = 1.0;
+		ANKI_CMD(vkCmdSetViewport(m_handle, 0, 1, &s), ANY_OTHER_COMMAND);
+
+		VkRect2D scissor = {};
+		scissor.extent.width = maxx - minx;
+		scissor.extent.height = maxy - miny;
+		scissor.offset.x = minx;
+		scissor.offset.y = miny;
+		ANKI_CMD(vkCmdSetScissor(m_handle, 0, 1, &scissor), ANY_OTHER_COMMAND);
+
+		m_viewport[0] = minx;
+		m_viewport[1] = miny;
+		m_viewport[2] = maxx;
+		m_viewport[3] = maxy;
+	}
+	else
+	{
+		// Skip
+	}
 }
 }
 
 
 inline void CommandBufferImpl::setPolygonOffset(F32 factor, F32 units)
 inline void CommandBufferImpl::setPolygonOffset(F32 factor, F32 units)
 {
 {
 	commandCommon();
 	commandCommon();
-	ANKI_CMD(vkCmdSetDepthBias(m_handle, units, 0.0, factor), ANY_OTHER_COMMAND);
+
+	if(m_polygonOffsetFactor != factor || m_polygonOffsetUnits != units)
+	{
+		ANKI_CMD(vkCmdSetDepthBias(m_handle, units, 0.0, factor), ANY_OTHER_COMMAND);
+
+		m_polygonOffsetFactor = factor;
+		m_polygonOffsetUnits = units;
+	}
+	else
+	{
+		// Skip
+	}
+}
+
+inline void CommandBufferImpl::setStencilCompareMask(FaceSelectionMask face, U32 mask)
+{
+	commandCommon();
+
+	VkStencilFaceFlags flags = 0;
+
+	if(!!(face & FaceSelectionMask::FRONT) && m_stencilCompareMasks[0] != mask)
+	{
+		m_stencilCompareMasks[0] = mask;
+		flags = VK_STENCIL_FACE_FRONT_BIT;
+	}
+
+	if(!!(face & FaceSelectionMask::BACK) && m_stencilCompareMasks[1] != mask)
+	{
+		m_stencilCompareMasks[1] = mask;
+		flags |= VK_STENCIL_FACE_BACK_BIT;
+	}
+
+	if(flags)
+	{
+		ANKI_CMD(vkCmdSetStencilCompareMask(m_handle, flags, mask), ANY_OTHER_COMMAND);
+	}
+}
+
+inline void CommandBufferImpl::setStencilWriteMask(FaceSelectionMask face, U32 mask)
+{
+	commandCommon();
+
+	VkStencilFaceFlags flags = 0;
+
+	if(!!(face & FaceSelectionMask::FRONT) && m_stencilWriteMasks[0] != mask)
+	{
+		m_stencilWriteMasks[0] = mask;
+		flags = VK_STENCIL_FACE_FRONT_BIT;
+	}
+
+	if(!!(face & FaceSelectionMask::BACK) && m_stencilWriteMasks[1] != mask)
+	{
+		m_stencilWriteMasks[1] = mask;
+		flags |= VK_STENCIL_FACE_BACK_BIT;
+	}
+
+	if(flags)
+	{
+		ANKI_CMD(vkCmdSetStencilWriteMask(m_handle, flags, mask), ANY_OTHER_COMMAND);
+	}
+}
+
+inline void CommandBufferImpl::setStencilReference(FaceSelectionMask face, U32 ref)
+{
+	commandCommon();
+
+	VkStencilFaceFlags flags = 0;
+
+	if(!!(face & FaceSelectionMask::FRONT) && m_stencilReferenceMasks[0] != ref)
+	{
+		m_stencilReferenceMasks[0] = ref;
+		flags = VK_STENCIL_FACE_FRONT_BIT;
+	}
+
+	if(!!(face & FaceSelectionMask::BACK) && m_stencilReferenceMasks[1] != ref)
+	{
+		m_stencilWriteMasks[1] = ref;
+		flags |= VK_STENCIL_FACE_BACK_BIT;
+	}
+
+	if(flags)
+	{
+		ANKI_CMD(vkCmdSetStencilReference(m_handle, flags, ref), ANY_OTHER_COMMAND);
+	}
 }
 }
 
 
 inline void CommandBufferImpl::setImageBarrier(VkPipelineStageFlags srcStage,
 inline void CommandBufferImpl::setImageBarrier(VkPipelineStageFlags srcStage,
@@ -131,7 +227,7 @@ inline void CommandBufferImpl::setTextureSurfaceBarrier(
 	impl.checkSurface(surf);
 	impl.checkSurface(surf);
 
 
 	VkImageSubresourceRange range;
 	VkImageSubresourceRange range;
-	impl.computeSubResourceRange(surf, range);
+	impl.computeSubResourceRange(surf, impl.m_akAspect, range);
 	setTextureBarrierInternal(tex, prevUsage, nextUsage, range);
 	setTextureBarrierInternal(tex, prevUsage, nextUsage, range);
 }
 }
 
 
@@ -148,7 +244,7 @@ inline void CommandBufferImpl::setTextureVolumeBarrier(
 	impl.checkVolume(vol);
 	impl.checkVolume(vol);
 
 
 	VkImageSubresourceRange range;
 	VkImageSubresourceRange range;
-	impl.computeSubResourceRange(vol, range);
+	impl.computeSubResourceRange(vol, impl.m_akAspect, range);
 	setTextureBarrierInternal(tex, prevUsage, nextUsage, range);
 	setTextureBarrierInternal(tex, prevUsage, nextUsage, range);
 }
 }
 
 
@@ -328,37 +424,25 @@ inline void CommandBufferImpl::clearTextureInternal(
 	m_texList.pushBack(m_alloc, tex);
 	m_texList.pushBack(m_alloc, tex);
 }
 }
 
 
-inline void CommandBufferImpl::clearTexture(TexturePtr tex, const ClearValue& clearValue)
-{
-	VkImageSubresourceRange range;
-	range.aspectMask = tex->getImplementation().m_aspect;
-	range.baseMipLevel = 0;
-	range.levelCount = VK_REMAINING_MIP_LEVELS;
-	range.baseArrayLayer = 0;
-	range.layerCount = VK_REMAINING_ARRAY_LAYERS;
-
-	clearTextureInternal(tex, clearValue, range);
-}
-
 inline void CommandBufferImpl::clearTextureSurface(
 inline void CommandBufferImpl::clearTextureSurface(
-	TexturePtr tex, const TextureSurfaceInfo& surf, const ClearValue& clearValue)
+	TexturePtr tex, const TextureSurfaceInfo& surf, const ClearValue& clearValue, DepthStencilAspectMask aspect)
 {
 {
 	const TextureImpl& impl = tex->getImplementation();
 	const TextureImpl& impl = tex->getImplementation();
 	ANKI_ASSERT(impl.m_type != TextureType::_3D && "Not for 3D");
 	ANKI_ASSERT(impl.m_type != TextureType::_3D && "Not for 3D");
 
 
 	VkImageSubresourceRange range;
 	VkImageSubresourceRange range;
-	impl.computeSubResourceRange(surf, range);
+	impl.computeSubResourceRange(surf, aspect, range);
 	clearTextureInternal(tex, clearValue, range);
 	clearTextureInternal(tex, clearValue, range);
 }
 }
 
 
 inline void CommandBufferImpl::clearTextureVolume(
 inline void CommandBufferImpl::clearTextureVolume(
-	TexturePtr tex, const TextureVolumeInfo& vol, const ClearValue& clearValue)
+	TexturePtr tex, const TextureVolumeInfo& vol, const ClearValue& clearValue, DepthStencilAspectMask aspect)
 {
 {
 	const TextureImpl& impl = tex->getImplementation();
 	const TextureImpl& impl = tex->getImplementation();
 	ANKI_ASSERT(impl.m_type == TextureType::_3D && "Only for 3D");
 	ANKI_ASSERT(impl.m_type == TextureType::_3D && "Only for 3D");
 
 
 	VkImageSubresourceRange range;
 	VkImageSubresourceRange range;
-	impl.computeSubResourceRange(vol, range);
+	impl.computeSubResourceRange(vol, aspect, range);
 	clearTextureInternal(tex, clearValue, range);
 	clearTextureInternal(tex, clearValue, range);
 }
 }
 
 

+ 43 - 6
src/anki/gr/vulkan/Common.cpp

@@ -197,9 +197,9 @@ static const ConvertFormat CONVERT_FORMAT_TABLE[] = {ANKI_FMT(NONE, NONE, VK_FOR
 	ANKI_FMT(D16, UNORM, VK_FORMAT_D16_UNORM, D),
 	ANKI_FMT(D16, UNORM, VK_FORMAT_D16_UNORM, D),
 	ANKI_FMT(NONE, NONE, VK_FORMAT_X8_D24_UNORM_PACK32, DS),
 	ANKI_FMT(NONE, NONE, VK_FORMAT_X8_D24_UNORM_PACK32, DS),
 	ANKI_FMT(D32, FLOAT, VK_FORMAT_D32_SFLOAT, D),
 	ANKI_FMT(D32, FLOAT, VK_FORMAT_D32_SFLOAT, D),
-	ANKI_FMT(NONE, NONE, VK_FORMAT_S8_UINT, S),
+	ANKI_FMT(S8, UINT, VK_FORMAT_S8_UINT, S),
 	ANKI_FMT(NONE, NONE, VK_FORMAT_D16_UNORM_S8_UINT, DS),
 	ANKI_FMT(NONE, NONE, VK_FORMAT_D16_UNORM_S8_UINT, DS),
-	ANKI_FMT(D24, UNORM, VK_FORMAT_D24_UNORM_S8_UINT, DS),
+	ANKI_FMT(D24S8, UNORM, VK_FORMAT_D24_UNORM_S8_UINT, DS),
 	ANKI_FMT(NONE, NONE, VK_FORMAT_D32_SFLOAT_S8_UINT, C),
 	ANKI_FMT(NONE, NONE, VK_FORMAT_D32_SFLOAT_S8_UINT, C),
 	ANKI_FMT(R8G8B8_S3TC, UNORM, VK_FORMAT_BC1_RGB_UNORM_BLOCK, C),
 	ANKI_FMT(R8G8B8_S3TC, UNORM, VK_FORMAT_BC1_RGB_UNORM_BLOCK, C),
 	ANKI_FMT(NONE, NONE, VK_FORMAT_BC1_RGB_SRGB_BLOCK, C),
 	ANKI_FMT(NONE, NONE, VK_FORMAT_BC1_RGB_SRGB_BLOCK, C),
@@ -346,18 +346,18 @@ VkPolygonMode convertFillMode(FillMode ak)
 	return out;
 	return out;
 }
 }
 
 
-VkCullModeFlags convertCullMode(CullMode ak)
+VkCullModeFlags convertCullMode(FaceSelectionMask ak)
 {
 {
 	VkCullModeFlags out = 0;
 	VkCullModeFlags out = 0;
 	switch(ak)
 	switch(ak)
 	{
 	{
-	case CullMode::FRONT:
+	case FaceSelectionMask::FRONT:
 		out = VK_CULL_MODE_FRONT_BIT;
 		out = VK_CULL_MODE_FRONT_BIT;
 		break;
 		break;
-	case CullMode::BACK:
+	case FaceSelectionMask::BACK:
 		out = VK_CULL_MODE_BACK_BIT;
 		out = VK_CULL_MODE_BACK_BIT;
 		break;
 		break;
-	case CullMode::FRONT_AND_BACK:
+	case FaceSelectionMask::FRONT_AND_BACK:
 		out = VK_CULL_MODE_FRONT_BIT | VK_CULL_MODE_BACK_BIT;
 		out = VK_CULL_MODE_FRONT_BIT | VK_CULL_MODE_BACK_BIT;
 		break;
 		break;
 	default:
 	default:
@@ -649,4 +649,41 @@ VkImageUsageFlags convertTextureUsage(TextureUsageBit ak, const PixelFormat& for
 	return out;
 	return out;
 }
 }
 
 
+VkStencilOp convertStencilOp(StencilOperation ak)
+{
+	VkStencilOp out = VK_STENCIL_OP_MAX_ENUM;
+
+	switch(ak)
+	{
+	case StencilOperation::KEEP:
+		out = VK_STENCIL_OP_KEEP;
+		break;
+	case StencilOperation::ZERO:
+		out = VK_STENCIL_OP_ZERO;
+		break;
+	case StencilOperation::REPLACE:
+		out = VK_STENCIL_OP_REPLACE;
+		break;
+	case StencilOperation::INCREMENT_AND_CLAMP:
+		out = VK_STENCIL_OP_INCREMENT_AND_CLAMP;
+		break;
+	case StencilOperation::DECREMENT_AND_CLAMP:
+		out = VK_STENCIL_OP_DECREMENT_AND_CLAMP;
+		break;
+	case StencilOperation::INVERT:
+		out = VK_STENCIL_OP_INVERT;
+		break;
+	case StencilOperation::INCREMENT_AND_WRAP:
+		out = VK_STENCIL_OP_INCREMENT_AND_WRAP;
+		break;
+	case StencilOperation::DECREMENT_AND_WRAP:
+		out = VK_STENCIL_OP_DECREMENT_AND_WRAP;
+		break;
+	default:
+		ANKI_ASSERT(0);
+	}
+
+	return out;
+}
+
 } // end namespace anki
 } // end namespace anki

+ 9 - 14
src/anki/gr/vulkan/Common.h

@@ -55,19 +55,6 @@ class GrManagerImpl;
 		}                                                                                                              \
 		}                                                                                                              \
 	} while(0)
 	} while(0)
 
 
-ANKI_USE_RESULT inline Bool formatIsDepthStencil(PixelFormat fmt)
-{
-	if(fmt.m_components == ComponentFormat::D16 || fmt.m_components == ComponentFormat::D24
-		|| fmt.m_components == ComponentFormat::D32)
-	{
-		return true;
-	}
-	else
-	{
-		return false;
-	}
-}
-
 /// Convert compare op.
 /// Convert compare op.
 ANKI_USE_RESULT VkCompareOp convertCompareOp(CompareOperation ak);
 ANKI_USE_RESULT VkCompareOp convertCompareOp(CompareOperation ak);
 
 
@@ -77,6 +64,12 @@ ANKI_USE_RESULT VkFormat convertFormat(PixelFormat ak);
 /// Get format aspect mask.
 /// Get format aspect mask.
 ANKI_USE_RESULT VkImageAspectFlags convertImageAspect(PixelFormat ak);
 ANKI_USE_RESULT VkImageAspectFlags convertImageAspect(PixelFormat ak);
 
 
+ANKI_USE_RESULT inline Bool formatIsDepthStencil(PixelFormat fmt)
+{
+	VkImageAspectFlags aspect = convertImageAspect(fmt);
+	return !!(aspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT));
+}
+
 /// Convert topology.
 /// Convert topology.
 ANKI_USE_RESULT VkPrimitiveTopology convertTopology(PrimitiveTopology ak);
 ANKI_USE_RESULT VkPrimitiveTopology convertTopology(PrimitiveTopology ak);
 
 
@@ -84,7 +77,7 @@ ANKI_USE_RESULT VkPrimitiveTopology convertTopology(PrimitiveTopology ak);
 ANKI_USE_RESULT VkPolygonMode convertFillMode(FillMode ak);
 ANKI_USE_RESULT VkPolygonMode convertFillMode(FillMode ak);
 
 
 /// Convert cull mode.
 /// Convert cull mode.
-ANKI_USE_RESULT VkCullModeFlags convertCullMode(CullMode ak);
+ANKI_USE_RESULT VkCullModeFlags convertCullMode(FaceSelectionMask ak);
 
 
 /// Convert blend method.
 /// Convert blend method.
 ANKI_USE_RESULT VkBlendFactor convertBlendMethod(BlendMethod ak);
 ANKI_USE_RESULT VkBlendFactor convertBlendMethod(BlendMethod ak);
@@ -112,6 +105,8 @@ ANKI_USE_RESULT VkImageType convertTextureType(TextureType ak);
 ANKI_USE_RESULT VkImageViewType convertTextureViewType(TextureType ak);
 ANKI_USE_RESULT VkImageViewType convertTextureViewType(TextureType ak);
 
 
 ANKI_USE_RESULT VkImageUsageFlags convertTextureUsage(TextureUsageBit ak, const PixelFormat& format);
 ANKI_USE_RESULT VkImageUsageFlags convertTextureUsage(TextureUsageBit ak, const PixelFormat& format);
+
+ANKI_USE_RESULT VkStencilOp convertStencilOp(StencilOperation ak);
 /// @}
 /// @}
 
 
 } // end namespace anki
 } // end namespace anki

+ 32 - 6
src/anki/gr/vulkan/FramebufferImpl.cpp

@@ -29,7 +29,7 @@ FramebufferImpl::~FramebufferImpl()
 
 
 Error FramebufferImpl::init(const FramebufferInitInfo& init)
 Error FramebufferImpl::init(const FramebufferInitInfo& init)
 {
 {
-	ANKI_ASSERT(framebufferInitInfoValid(init));
+	ANKI_ASSERT(initInfoValid(init));
 	m_defaultFramebuffer = init.refersToDefaultFramebuffer();
 	m_defaultFramebuffer = init.refersToDefaultFramebuffer();
 
 
 	ANKI_CHECK(initRenderPass(init));
 	ANKI_CHECK(initRenderPass(init));
@@ -57,10 +57,14 @@ Error FramebufferImpl::init(const FramebufferInitInfo& init)
 
 
 	if(init.m_depthStencilAttachment.m_texture.isCreated())
 	if(init.m_depthStencilAttachment.m_texture.isCreated())
 	{
 	{
-		if(init.m_depthStencilAttachment.m_loadOperation == AttachmentLoadOperation::CLEAR)
+		if(init.m_depthStencilAttachment.m_loadOperation == AttachmentLoadOperation::CLEAR
+			|| init.m_depthStencilAttachment.m_stencilLoadOperation == AttachmentLoadOperation::CLEAR)
 		{
 		{
 			m_clearVals[m_attachmentCount].depthStencil.depth =
 			m_clearVals[m_attachmentCount].depthStencil.depth =
 				init.m_depthStencilAttachment.m_clearValue.m_depthStencil.m_depth;
 				init.m_depthStencilAttachment.m_clearValue.m_depthStencil.m_depth;
+
+			m_clearVals[m_attachmentCount].depthStencil.stencil =
+				init.m_depthStencilAttachment.m_clearValue.m_depthStencil.m_stencil;
 		}
 		}
 		else
 		else
 		{
 		{
@@ -73,6 +77,28 @@ Error FramebufferImpl::init(const FramebufferInitInfo& init)
 	return ErrorCode::NONE;
 	return ErrorCode::NONE;
 }
 }
 
 
+Bool FramebufferImpl::initInfoValid(const FramebufferInitInfo& inf)
+{
+	if(!framebufferInitInfoValid(inf))
+	{
+		return false;
+	}
+
+	if(inf.m_depthStencilAttachment.m_texture)
+	{
+		const TextureImpl& impl = inf.m_depthStencilAttachment.m_texture->getImplementation();
+		if(impl.m_akAspect == DepthStencilAspectMask::DEPTH_STENCIL)
+		{
+			if(inf.m_depthStencilAttachment.m_aspect == DepthStencilAspectMask::NONE)
+			{
+				return false;
+			}
+		}
+	}
+
+	return true;
+}
+
 void FramebufferImpl::setupAttachmentDescriptor(const FramebufferAttachmentInfo& att, VkAttachmentDescription& desc)
 void FramebufferImpl::setupAttachmentDescriptor(const FramebufferAttachmentInfo& att, VkAttachmentDescription& desc)
 {
 {
 	// TODO This func won't work if it's default but this is a depth attachment
 	// TODO This func won't work if it's default but this is a depth attachment
@@ -93,8 +119,8 @@ void FramebufferImpl::setupAttachmentDescriptor(const FramebufferAttachmentInfo&
 	desc.samples = VK_SAMPLE_COUNT_1_BIT;
 	desc.samples = VK_SAMPLE_COUNT_1_BIT;
 	desc.loadOp = convertLoadOp(att.m_loadOperation);
 	desc.loadOp = convertLoadOp(att.m_loadOperation);
 	desc.storeOp = convertStoreOp(att.m_storeOperation);
 	desc.storeOp = convertStoreOp(att.m_storeOperation);
-	desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-	desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+	desc.stencilLoadOp = convertLoadOp(att.m_stencilLoadOperation);
+	desc.stencilStoreOp = convertStoreOp(att.m_stencilStoreOperation);
 	desc.initialLayout = layout;
 	desc.initialLayout = layout;
 	desc.finalLayout = layout;
 	desc.finalLayout = layout;
 }
 }
@@ -190,7 +216,7 @@ Error FramebufferImpl::initFramebuffer(const FramebufferInitInfo& init)
 			const FramebufferAttachmentInfo& att = init.m_colorAttachments[i];
 			const FramebufferAttachmentInfo& att = init.m_colorAttachments[i];
 			TextureImpl& tex = att.m_texture->getImplementation();
 			TextureImpl& tex = att.m_texture->getImplementation();
 
 
-			attachments[count] = tex.getOrCreateSingleSurfaceView(att.m_surface);
+			attachments[count] = tex.getOrCreateSingleSurfaceView(att.m_surface, att.m_aspect);
 
 
 			if(m_width == 0)
 			if(m_width == 0)
 			{
 			{
@@ -206,7 +232,7 @@ Error FramebufferImpl::initFramebuffer(const FramebufferInitInfo& init)
 			const FramebufferAttachmentInfo& att = init.m_depthStencilAttachment;
 			const FramebufferAttachmentInfo& att = init.m_depthStencilAttachment;
 			TextureImpl& tex = att.m_texture->getImplementation();
 			TextureImpl& tex = att.m_texture->getImplementation();
 
 
-			attachments[count] = tex.getOrCreateSingleSurfaceView(att.m_surface);
+			attachments[count] = tex.getOrCreateSingleSurfaceView(att.m_surface, att.m_aspect);
 
 
 			if(m_width == 0)
 			if(m_width == 0)
 			{
 			{

+ 1 - 0
src/anki/gr/vulkan/FramebufferImpl.h

@@ -79,6 +79,7 @@ private:
 	void setupAttachmentDescriptor(const FramebufferAttachmentInfo& in, VkAttachmentDescription& out);
 	void setupAttachmentDescriptor(const FramebufferAttachmentInfo& in, VkAttachmentDescription& out);
 
 
 	ANKI_USE_RESULT Error initFramebuffer(const FramebufferInitInfo& init);
 	ANKI_USE_RESULT Error initFramebuffer(const FramebufferInitInfo& init);
+	static Bool initInfoValid(const FramebufferInitInfo& inf);
 };
 };
 /// @}
 /// @}
 
 

+ 20 - 12
src/anki/gr/vulkan/PipelineImpl.cpp

@@ -41,9 +41,6 @@ public:
 		}
 		}
 
 
 		m_vertex.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
 		m_vertex.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
-		m_vertex.pVertexBindingDescriptions = &m_bindings[0];
-		m_vertex.pVertexAttributeDescriptions = &m_attribs[0];
-
 		m_ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
 		m_ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
 		m_tess.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
 		m_tess.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
 		m_vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
 		m_vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
@@ -51,7 +48,6 @@ public:
 		m_ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
 		m_ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
 		m_ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
 		m_ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
 		m_color.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
 		m_color.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
-		m_color.pAttachments = &m_attachments[0];
 		m_dyn.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
 		m_dyn.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
 	}
 	}
 };
 };
@@ -69,8 +65,11 @@ PipelineImpl::~PipelineImpl()
 Error PipelineImpl::initGraphics(const PipelineInitInfo& init)
 Error PipelineImpl::initGraphics(const PipelineInitInfo& init)
 {
 {
 	FilledGraphicsPipelineCreateInfo ci = FILLED;
 	FilledGraphicsPipelineCreateInfo ci = FILLED;
-
+	ci.m_vertex.pVertexBindingDescriptions = &ci.m_bindings[0];
+	ci.m_vertex.pVertexAttributeDescriptions = &ci.m_attribs[0];
+	ci.m_color.pAttachments = &ci.m_attachments[0];
 	ci.pStages = &ci.m_stages[0];
 	ci.pStages = &ci.m_stages[0];
+
 	initShaders(init, ci);
 	initShaders(init, ci);
 
 
 	// Init sub-states
 	// Init sub-states
@@ -215,7 +214,7 @@ VkPipelineRasterizationStateCreateInfo* PipelineImpl::initRasterizerState(
 	ci.polygonMode = convertFillMode(r.m_fillMode);
 	ci.polygonMode = convertFillMode(r.m_fillMode);
 	ci.cullMode = convertCullMode(r.m_cullMode);
 	ci.cullMode = convertCullMode(r.m_cullMode);
 	ci.frontFace = VK_FRONT_FACE_CLOCKWISE; // Use CW to workaround Vulkan's y flip
 	ci.frontFace = VK_FRONT_FACE_CLOCKWISE; // Use CW to workaround Vulkan's y flip
-	ci.depthBiasEnable = VK_TRUE; // TODO
+	ci.depthBiasEnable = VK_TRUE;
 	ci.lineWidth = 1.0;
 	ci.lineWidth = 1.0;
 
 
 	return &ci;
 	return &ci;
@@ -230,20 +229,29 @@ VkPipelineMultisampleStateCreateInfo* PipelineImpl::initMsState(VkPipelineMultis
 VkPipelineDepthStencilStateCreateInfo* PipelineImpl::initDsState(
 VkPipelineDepthStencilStateCreateInfo* PipelineImpl::initDsState(
 	const DepthStencilStateInfo& ds, VkPipelineDepthStencilStateCreateInfo& ci)
 	const DepthStencilStateInfo& ds, VkPipelineDepthStencilStateCreateInfo& ci)
 {
 {
+	VkPipelineDepthStencilStateCreateInfo* out = nullptr;
+
 	if(ds.isInUse())
 	if(ds.isInUse())
 	{
 	{
 		ci.depthTestEnable = (ds.m_depthCompareFunction != CompareOperation::ALWAYS) || ds.m_depthWriteEnabled;
 		ci.depthTestEnable = (ds.m_depthCompareFunction != CompareOperation::ALWAYS) || ds.m_depthWriteEnabled;
 		ci.depthWriteEnable = ds.m_depthWriteEnabled;
 		ci.depthWriteEnable = ds.m_depthWriteEnabled;
 		ci.depthCompareOp = convertCompareOp(ds.m_depthCompareFunction);
 		ci.depthCompareOp = convertCompareOp(ds.m_depthCompareFunction);
 		ci.depthBoundsTestEnable = VK_FALSE;
 		ci.depthBoundsTestEnable = VK_FALSE;
-		ci.stencilTestEnable = VK_FALSE; // For now no stencil
 
 
-		return &ci;
-	}
-	else
-	{
-		return nullptr;
+		ci.stencilTestEnable = !(stencilTestDisabled(ds.m_stencilFront) && stencilTestDisabled(ds.m_stencilBack));
+		ci.front.failOp = convertStencilOp(ds.m_stencilFront.m_stencilFailOperation);
+		ci.front.passOp = convertStencilOp(ds.m_stencilFront.m_stencilPassDepthPassOperation);
+		ci.front.depthFailOp = convertStencilOp(ds.m_stencilFront.m_stencilPassDepthFailOperation);
+		ci.front.compareOp = convertCompareOp(ds.m_stencilFront.m_compareFunction);
+		ci.back.failOp = convertStencilOp(ds.m_stencilBack.m_stencilFailOperation);
+		ci.back.passOp = convertStencilOp(ds.m_stencilBack.m_stencilPassDepthPassOperation);
+		ci.back.depthFailOp = convertStencilOp(ds.m_stencilBack.m_stencilPassDepthFailOperation);
+		ci.back.compareOp = convertCompareOp(ds.m_stencilBack.m_compareFunction);
+
+		out = &ci;
 	}
 	}
+
+	return out;
 }
 }
 
 
 VkPipelineColorBlendStateCreateInfo* PipelineImpl::initColorState(
 VkPipelineColorBlendStateCreateInfo* PipelineImpl::initColorState(

+ 2 - 2
src/anki/gr/vulkan/ResourceGroupImpl.cpp

@@ -216,7 +216,7 @@ Error ResourceGroupImpl::init(const ResourceGroupInitInfo& init)
 			TextureImpl& teximpl = init.m_textures[i].m_texture->getImplementation();
 			TextureImpl& teximpl = init.m_textures[i].m_texture->getImplementation();
 
 
 			VkDescriptorImageInfo& inf = texes[i];
 			VkDescriptorImageInfo& inf = texes[i];
-			inf.imageView = teximpl.getOrCreateResourceGroupView();
+			inf.imageView = teximpl.getOrCreateResourceGroupView(init.m_textures[i].m_aspect);
 
 
 			m_refs[refCount++] = init.m_textures[i].m_texture;
 			m_refs[refCount++] = init.m_textures[i].m_texture;
 
 
@@ -365,7 +365,7 @@ Error ResourceGroupImpl::init(const ResourceGroupInitInfo& init)
 			VkDescriptorImageInfo& inf = images[i];
 			VkDescriptorImageInfo& inf = images[i];
 			TextureImpl& tex = binding.m_texture->getImplementation();
 			TextureImpl& tex = binding.m_texture->getImplementation();
 
 
-			inf.imageView = tex.getOrCreateSingleLevelView(binding.m_level);
+			inf.imageView = tex.getOrCreateSingleLevelView(binding.m_level, tex.m_akAspect);
 			inf.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
 			inf.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
 
 
 			m_refs[refCount++] = binding.m_texture;
 			m_refs[refCount++] = binding.m_texture;

+ 15 - 5
src/anki/gr/vulkan/TextureImpl.cpp

@@ -137,6 +137,15 @@ Error TextureImpl::init(const TextureInitInfo& init_, Texture* tex)
 	m_aspect = convertImageAspect(m_format);
 	m_aspect = convertImageAspect(m_format);
 	m_usage = init.m_usage;
 	m_usage = init.m_usage;
 
 
+	if(m_aspect & VK_IMAGE_ASPECT_DEPTH_BIT)
+	{
+		m_akAspect |= DepthStencilAspectMask::DEPTH;
+	}
+	if(m_aspect & VK_IMAGE_ASPECT_STENCIL_BIT)
+	{
+		m_akAspect |= DepthStencilAspectMask::STENCIL;
+	}
+
 	ANKI_CHECK(initImage(init));
 	ANKI_CHECK(initImage(init));
 
 
 	// Init the template
 	// Init the template
@@ -578,32 +587,33 @@ VkImageLayout TextureImpl::computeLayout(TextureUsageBit usage, U level) const
 	return out;
 	return out;
 }
 }
 
 
-VkImageView TextureImpl::getOrCreateSingleSurfaceView(const TextureSurfaceInfo& surf)
+VkImageView TextureImpl::getOrCreateSingleSurfaceView(const TextureSurfaceInfo& surf, DepthStencilAspectMask aspect)
 {
 {
 	checkSurface(surf);
 	checkSurface(surf);
 
 
 	VkImageViewCreateInfo ci = m_viewCreateInfoTemplate;
 	VkImageViewCreateInfo ci = m_viewCreateInfoTemplate;
 	ci.viewType = VK_IMAGE_VIEW_TYPE_2D;
 	ci.viewType = VK_IMAGE_VIEW_TYPE_2D;
-	computeSubResourceRange(surf, ci.subresourceRange);
+	computeSubResourceRange(surf, aspect, ci.subresourceRange);
 
 
 	return getOrCreateView(ci);
 	return getOrCreateView(ci);
 }
 }
 
 
-VkImageView TextureImpl::getOrCreateSingleLevelView(U level)
+VkImageView TextureImpl::getOrCreateSingleLevelView(U level, DepthStencilAspectMask aspect)
 {
 {
 	ANKI_ASSERT(level < m_mipCount);
 	ANKI_ASSERT(level < m_mipCount);
 
 
 	VkImageViewCreateInfo ci = m_viewCreateInfoTemplate;
 	VkImageViewCreateInfo ci = m_viewCreateInfoTemplate;
 	ci.subresourceRange.baseMipLevel = level;
 	ci.subresourceRange.baseMipLevel = level;
 	ci.subresourceRange.levelCount = 1;
 	ci.subresourceRange.levelCount = 1;
+	ci.subresourceRange.aspectMask = convertAspect(aspect);
 
 
 	return getOrCreateView(ci);
 	return getOrCreateView(ci);
 }
 }
 
 
-VkImageView TextureImpl::getOrCreateResourceGroupView()
+VkImageView TextureImpl::getOrCreateResourceGroupView(DepthStencilAspectMask aspect)
 {
 {
 	VkImageViewCreateInfo ci = m_viewCreateInfoTemplate;
 	VkImageViewCreateInfo ci = m_viewCreateInfoTemplate;
-	ci.subresourceRange.aspectMask = m_aspect & (~VK_IMAGE_ASPECT_STENCIL_BIT);
+	ci.subresourceRange.aspectMask = convertAspect(aspect);
 
 
 	return getOrCreateView(ci);
 	return getOrCreateView(ci);
 }
 }

+ 12 - 73
src/anki/gr/vulkan/TextureImpl.h

@@ -41,6 +41,7 @@ public:
 	U8 m_mipCount = 0;
 	U8 m_mipCount = 0;
 	U32 m_layerCount = 0;
 	U32 m_layerCount = 0;
 	VkImageAspectFlags m_aspect = 0;
 	VkImageAspectFlags m_aspect = 0;
+	DepthStencilAspectMask m_akAspect = DepthStencilAspectMask::NONE;
 	TextureUsageBit m_usage = TextureUsageBit::NONE;
 	TextureUsageBit m_usage = TextureUsageBit::NONE;
 	PixelFormat m_format;
 	PixelFormat m_format;
 	VkFormat m_vkFormat = VK_FORMAT_UNDEFINED;
 	VkFormat m_vkFormat = VK_FORMAT_UNDEFINED;
@@ -65,9 +66,11 @@ public:
 		ANKI_ASSERT(vol.m_level < m_mipCount);
 		ANKI_ASSERT(vol.m_level < m_mipCount);
 	}
 	}
 
 
-	void computeSubResourceRange(const TextureSurfaceInfo& surf, VkImageSubresourceRange& range) const;
+	void computeSubResourceRange(
+		const TextureSurfaceInfo& surf, DepthStencilAspectMask aspect, VkImageSubresourceRange& range) const;
 
 
-	void computeSubResourceRange(const TextureVolumeInfo& vol, VkImageSubresourceRange& range) const;
+	void computeSubResourceRange(
+		const TextureVolumeInfo& vol, DepthStencilAspectMask aspect, VkImageSubresourceRange& range) const;
 
 
 	/// Compute the layer as defined by Vulkan.
 	/// Compute the layer as defined by Vulkan.
 	U computeVkArrayLayer(const TextureSurfaceInfo& surf) const;
 	U computeVkArrayLayer(const TextureSurfaceInfo& surf) const;
@@ -82,12 +85,12 @@ public:
 		return (usage & m_usage) == usage;
 		return (usage & m_usage) == usage;
 	}
 	}
 
 
-	VkImageView getOrCreateSingleSurfaceView(const TextureSurfaceInfo& surf);
+	VkImageView getOrCreateSingleSurfaceView(const TextureSurfaceInfo& surf, DepthStencilAspectMask aspect);
 
 
-	VkImageView getOrCreateSingleLevelView(U level);
+	VkImageView getOrCreateSingleLevelView(U level, DepthStencilAspectMask aspect);
 
 
 	/// That view will be used in descriptor sets.
 	/// That view will be used in descriptor sets.
-	VkImageView getOrCreateResourceGroupView();
+	VkImageView getOrCreateResourceGroupView(DepthStencilAspectMask aspect);
 
 
 	/// By knowing the previous and new texture usage calculate the relavant info for a ppline barrier.
 	/// By knowing the previous and new texture usage calculate the relavant info for a ppline barrier.
 	void computeBarrierInfo(TextureUsageBit before,
 	void computeBarrierInfo(TextureUsageBit before,
@@ -101,6 +104,8 @@ public:
 	/// Predict the image layout.
 	/// Predict the image layout.
 	VkImageLayout computeLayout(TextureUsageBit usage, U level) const;
 	VkImageLayout computeLayout(TextureUsageBit usage, U level) const;
 
 
+	VkImageAspectFlags convertAspect(DepthStencilAspectMask ak) const;
+
 private:
 private:
 	class ViewHasher
 	class ViewHasher
 	{
 	{
@@ -134,74 +139,8 @@ private:
 
 
 	VkImageView getOrCreateView(const VkImageViewCreateInfo& ci);
 	VkImageView getOrCreateView(const VkImageViewCreateInfo& ci);
 };
 };
-
-inline void TextureImpl::computeSubResourceRange(const TextureSurfaceInfo& surf, VkImageSubresourceRange& range) const
-{
-	checkSurface(surf);
-	range.aspectMask = m_aspect;
-	range.baseMipLevel = surf.m_level;
-	range.levelCount = 1;
-	switch(m_type)
-	{
-	case TextureType::_2D:
-		range.baseArrayLayer = 0;
-		break;
-	case TextureType::_3D:
-		range.baseArrayLayer = 0;
-		break;
-	case TextureType::CUBE:
-		range.baseArrayLayer = surf.m_face;
-		break;
-	case TextureType::_2D_ARRAY:
-		range.baseArrayLayer = surf.m_layer;
-		break;
-	case TextureType::CUBE_ARRAY:
-		range.baseArrayLayer = surf.m_layer * 6 + surf.m_face;
-		break;
-	default:
-		ANKI_ASSERT(0);
-		range.baseArrayLayer = 0;
-	}
-	range.layerCount = 1;
-}
-
-inline void TextureImpl::computeSubResourceRange(const TextureVolumeInfo& vol, VkImageSubresourceRange& range) const
-{
-	checkVolume(vol);
-	range.aspectMask = m_aspect;
-	range.baseMipLevel = vol.m_level;
-	range.levelCount = 1;
-	range.baseArrayLayer = 0;
-	range.layerCount = 1;
-}
-
-inline U TextureImpl::computeVkArrayLayer(const TextureSurfaceInfo& surf) const
-{
-	checkSurface(surf);
-	U layer = 0;
-	switch(m_type)
-	{
-	case TextureType::_2D:
-		layer = 0;
-		break;
-	case TextureType::_3D:
-		layer = 0;
-		break;
-	case TextureType::CUBE:
-		layer = surf.m_face;
-		break;
-	case TextureType::_2D_ARRAY:
-		layer = surf.m_layer;
-		break;
-	case TextureType::CUBE_ARRAY:
-		layer = surf.m_layer * 6 + surf.m_face;
-		break;
-	default:
-		ANKI_ASSERT(0);
-	}
-
-	return layer;
-}
 /// @}
 /// @}
 
 
 } // end namespace anki
 } // end namespace anki
+
+#include <anki/gr/vulkan/TextureImpl.inl.h>