Sfoglia il codice sorgente

[REFACTORING] Complete the GL texture view implementation

Panagiotis Christopoulos Charitos 8 anni fa
parent
commit
698dab2b31

+ 55 - 128
src/anki/gr/gl/CommandBuffer.cpp

@@ -10,18 +10,13 @@
 #include <anki/gr/gl/RenderingThread.h>
 #include <anki/gr/gl/GlState.h>
 
-#include <anki/gr/Framebuffer.h>
 #include <anki/gr/gl/FramebufferImpl.h>
-#include <anki/gr/OcclusionQuery.h>
 #include <anki/gr/gl/OcclusionQueryImpl.h>
-#include <anki/gr/Texture.h>
 #include <anki/gr/gl/TextureImpl.h>
-#include <anki/gr/Buffer.h>
 #include <anki/gr/gl/BufferImpl.h>
-#include <anki/gr/Sampler.h>
 #include <anki/gr/gl/SamplerImpl.h>
-#include <anki/gr/ShaderProgram.h>
 #include <anki/gr/gl/ShaderProgramImpl.h>
+#include <anki/gr/gl/TextureViewImpl.h>
 
 #include <anki/core/Trace.h>
 
@@ -631,35 +626,38 @@ void CommandBuffer::setBlendOperation(U32 attachment, BlendOperation funcRgb, Bl
 }
 
 void CommandBuffer::bindTextureAndSampler(
-	U32 set, U32 binding, TexturePtr tex, SamplerPtr sampler, TextureUsageBit usage, DepthStencilAspectBit aspect)
+	U32 set, U32 binding, TextureViewPtr texView, SamplerPtr sampler, TextureUsageBit usage)
 {
 	class Cmd final : public GlCommand
 	{
 	public:
 		U32 m_unit;
-		TexturePtr m_tex;
+		TextureViewPtr m_texView;
 		SamplerPtr m_sampler;
 
-		Cmd(U32 unit, TexturePtr tex, SamplerPtr sampler)
+		Cmd(U32 unit, TextureViewPtr texView, SamplerPtr sampler)
 			: m_unit(unit)
-			, m_tex(tex)
+			, m_texView(texView)
 			, m_sampler(sampler)
 		{
 		}
 
 		Error operator()(GlState&)
 		{
-			glBindTextureUnit(m_unit, static_cast<const TextureImpl&>(*m_tex).getGlName());
+			glBindTextureUnit(m_unit, static_cast<const TextureViewImpl&>(*m_texView).m_view.m_glName);
 			glBindSampler(m_unit, static_cast<const SamplerImpl&>(*m_sampler).getGlName());
 			return Error::NONE;
 		}
 	};
 
 	ANKI_GL_SELF(CommandBufferImpl);
-	if(self.m_state.bindTextureAndSampler(set, binding, tex, sampler, aspect))
+	ANKI_ASSERT(static_cast<const TextureViewImpl&>(*texView).m_tex->isSubresourceGoodForSampling(
+		static_cast<const TextureViewImpl&>(*texView).getSubresource()));
+
+	if(self.m_state.bindTextureViewAndSampler(set, binding, texView, sampler))
 	{
 		U unit = binding + MAX_TEXTURE_BINDINGS * set;
-		self.pushBackNewCommand<Cmd>(unit, tex, sampler);
+		self.pushBackNewCommand<Cmd>(unit, texView, sampler);
 	}
 }
 
@@ -735,42 +733,44 @@ void CommandBuffer::bindStorageBuffer(U32 set, U32 binding, BufferPtr buff, PtrS
 	}
 }
 
-void CommandBuffer::bindImage(U32 set, U32 binding, TexturePtr img, U32 level)
+void CommandBuffer::bindImage(U32 set, U32 binding, TextureViewPtr img)
 {
 	class Cmd final : public GlCommand
 	{
 	public:
-		TexturePtr m_img;
+		TextureViewPtr m_img;
 		U16 m_unit;
-		U8 m_level;
 
-		Cmd(U32 unit, TexturePtr img, U32 level)
+		Cmd(U32 unit, TextureViewPtr img)
 			: m_img(img)
 			, m_unit(unit)
-			, m_level(level)
 		{
 		}
 
 		Error operator()(GlState&)
 		{
+			const TextureViewImpl& view = static_cast<const TextureViewImpl&>(*m_img);
+
 			glBindImageTexture(m_unit,
-				static_cast<const TextureImpl&>(*m_img).getGlName(),
-				m_level,
+				view.m_view.m_glName,
+				m_img->getBaseMipmap(),
 				GL_TRUE,
 				0,
 				GL_READ_WRITE,
-				static_cast<const TextureImpl&>(*m_img).m_internalFormat);
+				static_cast<const TextureImpl&>(*view.m_tex).m_internalFormat);
 			return Error::NONE;
 		}
 	};
 
 	ANKI_ASSERT(img);
 	ANKI_GL_SELF(CommandBufferImpl);
+	ANKI_ASSERT(static_cast<const TextureViewImpl&>(*img).m_tex->isSubresourceGoodForImageLoadStore(
+		static_cast<const TextureViewImpl&>(*img).getSubresource()));
 
-	if(self.m_state.bindImage(set, binding, img, level))
+	if(self.m_state.bindImage(set, binding, img))
 	{
 		binding = binding + set * MAX_IMAGE_BINDINGS;
-		self.pushBackNewCommand<Cmd>(binding, img, level);
+		self.pushBackNewCommand<Cmd>(binding, img);
 	}
 }
 
@@ -1172,8 +1172,7 @@ void CommandBuffer::endOcclusionQuery(OcclusionQueryPtr query)
 	self.pushBackNewCommand<OqEndCommand>(query);
 }
 
-void CommandBuffer::copyBufferToTextureSurface(
-	BufferPtr buff, PtrSize offset, PtrSize range, TexturePtr tex, const TextureSurfaceInfo& surf)
+void CommandBuffer::copyBufferToTextureView(BufferPtr buff, PtrSize offset, PtrSize range, TextureViewPtr texView)
 {
 	class TexSurfUploadCommand final : public GlCommand
 	{
@@ -1181,72 +1180,34 @@ void CommandBuffer::copyBufferToTextureSurface(
 		BufferPtr m_buff;
 		PtrSize m_offset;
 		PtrSize m_range;
-		TexturePtr m_tex;
-		TextureSurfaceInfo m_surf;
+		TextureViewPtr m_texView;
 
-		TexSurfUploadCommand(
-			BufferPtr buff, PtrSize offset, PtrSize range, TexturePtr tex, const TextureSurfaceInfo& surf)
+		TexSurfUploadCommand(BufferPtr buff, PtrSize offset, PtrSize range, TextureViewPtr texView)
 			: m_buff(buff)
 			, m_offset(offset)
 			, m_range(range)
-			, m_tex(tex)
-			, m_surf(surf)
-		{
-		}
-
-		Error operator()(GlState& state)
+			, m_texView(texView)
 		{
-			static_cast<TextureImpl&>(*m_tex).writeSurface(
-				m_surf, static_cast<const BufferImpl&>(*m_buff).getGlName(), m_offset, m_range);
-			return Error::NONE;
 		}
-	};
-
-	ANKI_ASSERT(tex);
-	ANKI_ASSERT(buff);
-	ANKI_ASSERT(range > 0);
-	ANKI_GL_SELF(CommandBufferImpl);
-	ANKI_ASSERT(!self.m_state.insideRenderPass());
-
-	self.pushBackNewCommand<TexSurfUploadCommand>(buff, offset, range, tex, surf);
-}
-
-void CommandBuffer::copyBufferToTextureVolume(
-	BufferPtr buff, PtrSize offset, PtrSize range, TexturePtr tex, const TextureVolumeInfo& vol)
-{
-	class TexVolUploadCommand final : public GlCommand
-	{
-	public:
-		BufferPtr m_buff;
-		PtrSize m_offset;
-		PtrSize m_range;
-		TexturePtr m_tex;
-		TextureVolumeInfo m_vol;
 
-		TexVolUploadCommand(BufferPtr buff, PtrSize offset, PtrSize range, TexturePtr tex, const TextureVolumeInfo& vol)
-			: m_buff(buff)
-			, m_offset(offset)
-			, m_range(range)
-			, m_tex(tex)
-			, m_vol(vol)
+		Error operator()(GlState&)
 		{
-		}
+			const TextureViewImpl& viewImpl = static_cast<TextureViewImpl&>(*m_texView);
+			const TextureImpl& texImpl = static_cast<TextureImpl&>(*viewImpl.m_tex);
 
-		Error operator()(GlState& state)
-		{
-			static_cast<const TextureImpl&>(*m_tex).writeVolume(
-				m_vol, static_cast<const BufferImpl&>(*m_buff).getGlName(), m_offset, m_range);
+			texImpl.copyFromBuffer(
+				viewImpl.getSubresource(), static_cast<const BufferImpl&>(*m_buff).getGlName(), m_offset, m_range);
 			return Error::NONE;
 		}
 	};
 
-	ANKI_ASSERT(tex);
+	ANKI_ASSERT(texView);
 	ANKI_ASSERT(buff);
 	ANKI_ASSERT(range > 0);
 	ANKI_GL_SELF(CommandBufferImpl);
 	ANKI_ASSERT(!self.m_state.insideRenderPass());
 
-	self.pushBackNewCommand<TexVolUploadCommand>(buff, offset, range, tex, vol);
+	self.pushBackNewCommand<TexSurfUploadCommand>(buff, offset, range, texView);
 }
 
 void CommandBuffer::copyBufferToBuffer(
@@ -1287,35 +1248,34 @@ void CommandBuffer::copyBufferToBuffer(
 	self.pushBackNewCommand<Cmd>(src, srcOffset, dst, dstOffset, range);
 }
 
-void CommandBuffer::generateMipmaps2d(TexturePtr tex, U face, U layer)
+void CommandBuffer::generateMipmaps2d(TextureViewPtr texView)
 {
 	class GenMipsCommand final : public GlCommand
 	{
 	public:
-		TexturePtr m_tex;
-		U8 m_face;
-		U32 m_layer;
+		TextureViewPtr m_texView;
 
-		GenMipsCommand(const TexturePtr& tex, U face, U layer)
-			: m_tex(tex)
-			, m_face(face)
-			, m_layer(layer)
+		GenMipsCommand(const TextureViewPtr& view)
+			: m_texView(view)
 		{
 		}
 
 		Error operator()(GlState&)
 		{
-			static_cast<TextureImpl&>(*m_tex).generateMipmaps2d(m_face, m_layer);
+			const TextureViewImpl& viewImpl = static_cast<TextureViewImpl&>(*m_texView);
+			const TextureImpl& texImpl = static_cast<TextureImpl&>(*viewImpl.m_tex);
+
+			texImpl.generateMipmaps2d(viewImpl);
 			return Error::NONE;
 		}
 	};
 
 	ANKI_GL_SELF(CommandBufferImpl);
 	ANKI_ASSERT(!self.m_state.insideRenderPass());
-	self.pushBackNewCommand<GenMipsCommand>(tex, face, layer);
+	self.pushBackNewCommand<GenMipsCommand>(texView);
 }
 
-void CommandBuffer::generateMipmaps3d(TexturePtr tex)
+void CommandBuffer::generateMipmaps3d(TextureViewPtr tex)
 {
 	ANKI_ASSERT(!!"TODO");
 }
@@ -1356,39 +1316,9 @@ Bool CommandBuffer::isEmpty() const
 	return self.isEmpty();
 }
 
-void CommandBuffer::copyTextureSurfaceToTextureSurface(
-	TexturePtr src, const TextureSurfaceInfo& srcSurf, TexturePtr dest, const TextureSurfaceInfo& destSurf)
+void CommandBuffer::blitTextureViews(TextureViewPtr srcView, TextureViewPtr destView)
 {
-	class CopyTexCommand final : public GlCommand
-	{
-	public:
-		TexturePtr m_src;
-		TextureSurfaceInfo m_srcSurf;
-		TexturePtr m_dest;
-		TextureSurfaceInfo m_destSurf;
-
-		CopyTexCommand(
-			TexturePtr src, const TextureSurfaceInfo& srcSurf, TexturePtr dest, const TextureSurfaceInfo& destSurf)
-			: m_src(src)
-			, m_srcSurf(srcSurf)
-			, m_dest(dest)
-			, m_destSurf(destSurf)
-		{
-		}
-
-		Error operator()(GlState&)
-		{
-			TextureImpl::copy(static_cast<const TextureImpl&>(*m_src),
-				m_srcSurf,
-				static_cast<const TextureImpl&>(*m_dest),
-				m_destSurf);
-			return Error::NONE;
-		}
-	};
-
-	ANKI_GL_SELF(CommandBufferImpl);
-	ANKI_ASSERT(!self.m_state.insideRenderPass());
-	self.pushBackNewCommand<CopyTexCommand>(src, srcSurf, dest, destSurf);
+	ANKI_ASSERT(!"TODO");
 }
 
 void CommandBuffer::setBufferBarrier(
@@ -1467,36 +1397,33 @@ void CommandBuffer::setTextureVolumeBarrier(
 	// Do nothing
 }
 
-void CommandBuffer::clearTextureSurface(
-	TexturePtr tex, const TextureSurfaceInfo& surf, const ClearValue& clearValue, DepthStencilAspectBit aspect)
+void CommandBuffer::clearTextureView(TextureViewPtr texView, const ClearValue& clearValue)
 {
 	class ClearTextCommand final : public GlCommand
 	{
 	public:
-		TexturePtr m_tex;
+		TextureViewPtr m_texView;
 		ClearValue m_val;
-		TextureSurfaceInfo m_surf;
-		DepthStencilAspectBit m_aspect;
 
-		ClearTextCommand(
-			TexturePtr tex, const TextureSurfaceInfo& surf, const ClearValue& val, DepthStencilAspectBit aspect)
-			: m_tex(tex)
+		ClearTextCommand(TextureViewPtr texView, const ClearValue& val)
+			: m_texView(texView)
 			, m_val(val)
-			, m_surf(surf)
-			, m_aspect(aspect)
 		{
 		}
 
 		Error operator()(GlState&)
 		{
-			static_cast<TextureImpl&>(*m_tex).clear(m_surf, m_val, m_aspect);
+			const TextureViewImpl& viewImpl = static_cast<TextureViewImpl&>(*m_texView);
+			const TextureImpl& texImpl = static_cast<TextureImpl&>(*viewImpl.m_tex);
+
+			texImpl.clear(viewImpl.getSubresource(), m_val);
 			return Error::NONE;
 		}
 	};
 
 	ANKI_GL_SELF(CommandBufferImpl);
 	ANKI_ASSERT(!self.m_state.insideRenderPass());
-	self.pushBackNewCommand<ClearTextCommand>(tex, surf, clearValue, aspect);
+	self.pushBackNewCommand<ClearTextCommand>(texView, clearValue);
 }
 
 void CommandBuffer::fillBuffer(BufferPtr buff, PtrSize offset, PtrSize size, U32 value)

+ 7 - 2
src/anki/gr/gl/GrManager.cpp

@@ -91,6 +91,11 @@ TexturePtr GrManager::newTexture(const TextureInitInfo& init)
 	return TexturePtr(Texture::newInstance(this, init));
 }
 
+TextureViewPtr GrManager::newTextureView(const TextureViewInitInfo& init)
+{
+	return TextureViewPtr(TextureView::newInstance(this, init));
+}
+
 SamplerPtr GrManager::newSampler(const SamplerInitInfo& init)
 {
 	return SamplerPtr(Sampler::newInstance(this, init));
@@ -129,7 +134,7 @@ RenderGraphPtr GrManager::newRenderGraph()
 void GrManager::getTextureSurfaceUploadInfo(TexturePtr tex, const TextureSurfaceInfo& surf, PtrSize& allocationSize)
 {
 	const TextureImpl& impl = static_cast<const TextureImpl&>(*tex);
-	impl.checkSurfaceOrVolume(surf);
+	// TODO impl.checkSurfaceOrVolume(surf);
 
 	U width = impl.m_width >> surf.m_level;
 	U height = impl.m_height >> surf.m_level;
@@ -139,7 +144,7 @@ void GrManager::getTextureSurfaceUploadInfo(TexturePtr tex, const TextureSurface
 void GrManager::getTextureVolumeUploadInfo(TexturePtr tex, const TextureVolumeInfo& vol, PtrSize& allocationSize)
 {
 	const TextureImpl& impl = static_cast<const TextureImpl&>(*tex);
-	impl.checkSurfaceOrVolume(vol);
+	// TODO impl.checkSurfaceOrVolume(vol);
 
 	U width = impl.m_width >> vol.m_level;
 	U height = impl.m_height >> vol.m_level;

+ 9 - 16
src/anki/gr/gl/StateTracker.h

@@ -447,26 +447,21 @@ public:
 	class TextureBinding
 	{
 	public:
-		TextureImpl* m_tex = nullptr;
-		SamplerImpl* m_sampler = reinterpret_cast<SamplerImpl*>(0x1);
-		DepthStencilAspectBit m_aspect;
+		U64 m_texViewUuid = 0;
+		U64 m_samplerUuid = 0;
 	};
 
 	Array2d<TextureBinding, MAX_DESCRIPTOR_SETS, MAX_TEXTURE_BINDINGS> m_textures;
 
-	Bool bindTextureAndSampler(U32 set, U32 binding, TexturePtr tex, SamplerPtr sampler, DepthStencilAspectBit aspect)
+	Bool bindTextureViewAndSampler(U32 set, U32 binding, const TextureViewPtr& texView, const SamplerPtr& sampler)
 	{
 		TextureBinding& b = m_textures[set][binding];
 
-		TextureImpl* teximpl = static_cast<TextureImpl*>(tex.get());
-		SamplerImpl* samplerimpl = static_cast<SamplerImpl*>(sampler.get());
-
 		Bool dirty;
-		if(b.m_tex != teximpl || b.m_sampler != samplerimpl || b.m_aspect != aspect)
+		if(b.m_texViewUuid != texView->getUuid() || b.m_samplerUuid != sampler->getUuid())
 		{
-			b.m_tex = teximpl;
-			b.m_sampler = samplerimpl;
-			b.m_aspect = aspect;
+			b.m_texViewUuid = texView->getUuid();
+			b.m_samplerUuid = sampler->getUuid();
 			dirty = true;
 		}
 		else
@@ -510,17 +505,15 @@ public:
 	class ImageBinding
 	{
 	public:
-		TextureImpl* m_tex = nullptr;
-		U8 m_level;
+		U64 m_texViewUuid = 0;
 	};
 
 	Array2d<ImageBinding, MAX_DESCRIPTOR_SETS, MAX_IMAGE_BINDINGS> m_images;
 
-	Bool bindImage(U32 set, U32 binding, TexturePtr img, U32 level)
+	Bool bindImage(U32 set, U32 binding, const TextureViewPtr& img)
 	{
 		ImageBinding& b = m_images[set][binding];
-		b.m_tex = static_cast<TextureImpl*>(img.get());
-		b.m_level = level;
+		b.m_texViewUuid = img->getUuid();
 		return true;
 	}
 

+ 51 - 118
src/anki/gr/gl/TextureImpl.cpp

@@ -9,8 +9,8 @@
 #include <anki/util/Functions.h>
 #include <anki/gr/GrManager.h>
 #include <anki/gr/gl/GrManagerImpl.h>
+#include <anki/gr/gl/TextureViewImpl.h>
 #include <anki/gr/gl/RenderingThread.h>
-#include <anki/gr/CommandBuffer.h>
 #include <anki/gr/gl/CommandBufferImpl.h>
 
 namespace anki
@@ -95,12 +95,12 @@ TextureImpl::~TextureImpl()
 
 		commands = manager.newCommandBuffer(CommandBufferInitInfo());
 		static_cast<CommandBufferImpl&>(*commands).pushBackNewCommand<DeleteTextureCommand>(
-			m_glName, m_texViews, getAllocator());
+			m_glName, m_viewsMap, getAllocator());
 		static_cast<CommandBufferImpl&>(*commands).flush();
 	}
 	else
 	{
-		DeleteTextureCommand cmd(m_glName, m_texViews, getAllocator());
+		DeleteTextureCommand cmd(m_glName, m_viewsMap, getAllocator());
 		cmd(static_cast<GrManagerImpl&>(manager).getState());
 	}
 
@@ -115,7 +115,7 @@ void TextureImpl::bind() const
 
 void TextureImpl::preInit(const TextureInitInfo& init)
 {
-	ANKI_ASSERT(textureInitInfoValid(init));
+	ANKI_ASSERT(init.isValid());
 
 	m_width = init.m_width;
 	m_height = init.m_height;
@@ -125,7 +125,7 @@ void TextureImpl::preInit(const TextureInitInfo& init)
 	m_texType = init.m_type;
 	m_format = init.m_format;
 
-	convertTextureInformation(init.m_format, m_compressed, m_glFormat, m_internalFormat, m_glType, m_dsAspect);
+	convertTextureInformation(init.m_format, m_compressed, m_glFormat, m_internalFormat, m_glType, m_aspect);
 
 	if(m_target != GL_TEXTURE_3D)
 	{
@@ -208,15 +208,16 @@ void TextureImpl::init(const TextureInitInfo& init)
 	ANKI_CHECK_GL_ERROR();
 }
 
-void TextureImpl::writeSurface(const TextureSurfaceInfo& surf, GLuint pbo, PtrSize offset, PtrSize dataSize)
+void TextureImpl::copyFromBuffer(
+	const TextureSubresourceInfo& subresource, GLuint pbo, PtrSize offset, PtrSize dataSize) const
 {
-	checkSurfaceOrVolume(surf);
+	ANKI_ASSERT(isSubresourceGoodForCopyFromBuffer(subresource));
 	ANKI_ASSERT(dataSize > 0);
 
-	U mipmap = surf.m_level;
-	U surfIdx = computeSurfaceIdx(surf);
-	U w = m_width >> mipmap;
-	U h = m_height >> mipmap;
+	const U mipmap = subresource.m_baseMipmap;
+	const U w = m_width >> mipmap;
+	const U h = m_height >> mipmap;
+	const U d = m_depth >> mipmap;
 	ANKI_ASSERT(w > 0);
 	ANKI_ASSERT(h > 0);
 
@@ -237,6 +238,8 @@ void TextureImpl::writeSurface(const TextureSurfaceInfo& surf, GLuint pbo, PtrSi
 		}
 		break;
 	case GL_TEXTURE_CUBE_MAP:
+	{
+		const U surfIdx = computeSurfaceIdx(TextureSurfaceInfo(mipmap, 0, subresource.m_baseFace, 0));
 		if(!m_compressed)
 		{
 			glTexSubImage2D(
@@ -248,8 +251,10 @@ void TextureImpl::writeSurface(const TextureSurfaceInfo& surf, GLuint pbo, PtrSi
 				GL_TEXTURE_CUBE_MAP_POSITIVE_X + surfIdx, mipmap, 0, 0, w, h, m_glFormat, dataSize, ptrOffset);
 		}
 		break;
+	}
 	case GL_TEXTURE_2D_ARRAY:
-	case GL_TEXTURE_3D:
+	{
+		const U surfIdx = computeSurfaceIdx(TextureSurfaceInfo(mipmap, 0, 0, subresource.m_baseLayer));
 		if(!m_compressed)
 		{
 			glTexSubImage3D(m_target, mipmap, 0, 0, surfIdx, w, h, 1, m_glFormat, m_glType, ptrOffset);
@@ -259,6 +264,18 @@ void TextureImpl::writeSurface(const TextureSurfaceInfo& surf, GLuint pbo, PtrSi
 			glCompressedTexSubImage3D(m_target, mipmap, 0, 0, surfIdx, w, h, 1, m_glFormat, dataSize, ptrOffset);
 		}
 		break;
+	}
+	case GL_TEXTURE_3D:
+		ANKI_ASSERT(d > 0);
+		if(!m_compressed)
+		{
+			glTexSubImage3D(m_target, mipmap, 0, 0, 0, w, h, d, m_glFormat, m_glType, ptrOffset);
+		}
+		else
+		{
+			glCompressedTexSubImage3D(m_target, mipmap, 0, 0, 0, w, h, d, m_glFormat, dataSize, ptrOffset);
+		}
+		break;
 	default:
 		ANKI_ASSERT(0);
 	}
@@ -267,73 +284,15 @@ void TextureImpl::writeSurface(const TextureSurfaceInfo& surf, GLuint pbo, PtrSi
 	ANKI_CHECK_GL_ERROR();
 }
 
-void TextureImpl::writeVolume(const TextureVolumeInfo& vol, GLuint pbo, PtrSize offset, PtrSize dataSize) const
-{
-	checkSurfaceOrVolume(vol);
-	ANKI_ASSERT(dataSize > 0);
-	ANKI_ASSERT(m_texType == TextureType::_3D);
-
-	U mipmap = vol.m_level;
-	U w = m_width >> mipmap;
-	U h = m_height >> mipmap;
-	U d = m_depth >> mipmap;
-	ANKI_ASSERT(w > 0);
-	ANKI_ASSERT(h > 0);
-	ANKI_ASSERT(d > 0);
-
-	bind();
-	glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
-	const void* ptrOffset = numberToPtr<const void*>(offset);
-
-	if(!m_compressed)
-	{
-		glTexSubImage3D(m_target, mipmap, 0, 0, 0, w, h, d, m_glFormat, m_glType, ptrOffset);
-	}
-	else
-	{
-		glCompressedTexSubImage3D(m_target, mipmap, 0, 0, 0, w, h, d, m_glFormat, dataSize, ptrOffset);
-	}
-
-	glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
-	ANKI_CHECK_GL_ERROR();
-}
-
-void TextureImpl::generateMipmaps2d(U face, U layer)
+void TextureImpl::generateMipmaps2d(const TextureViewImpl& view) const
 {
-	U surface = computeSurfaceIdx(TextureSurfaceInfo(0, 0, face, layer));
+	ANKI_ASSERT(view.m_tex.get() == this);
+	ANKI_ASSERT(isSubresourceGoodForMipmapGeneration(view.getSubresource()));
 	ANKI_ASSERT(!m_compressed);
 
 	if(m_surfaceCountPerLevel > 1)
 	{
-		// Lazily create the view array
-		if(m_texViews.getSize() == 0)
-		{
-			m_texViews.create(getAllocator(), m_surfaceCountPerLevel);
-			memset(&m_texViews[0], 0, m_texViews.getSize() * sizeof(GLuint));
-		}
-
-		// Lazily create the view
-		if(m_texViews[surface] == 0)
-		{
-			glGenTextures(1, &m_texViews[surface]);
-
-			// Get the target
-			GLenum target = GL_NONE;
-			switch(m_target)
-			{
-			case GL_TEXTURE_CUBE_MAP:
-			case GL_TEXTURE_2D_ARRAY:
-			case GL_TEXTURE_CUBE_MAP_ARRAY:
-				target = GL_TEXTURE_2D;
-				break;
-			default:
-				ANKI_ASSERT(0);
-			}
-
-			glTextureView(m_texViews[surface], target, m_glName, m_internalFormat, 0, m_mipCount, surface, 1);
-		}
-
-		glGenerateTextureMipmap(m_texViews[surface]);
+		glGenerateTextureMipmap(view.m_view.m_glName);
 	}
 	else
 	{
@@ -341,48 +300,14 @@ void TextureImpl::generateMipmaps2d(U face, U layer)
 	}
 }
 
-void TextureImpl::copy(const TextureImpl& src,
-	const TextureSurfaceInfo& srcSurf,
-	const TextureImpl& dest,
-	const TextureSurfaceInfo& destSurf)
-{
-	ANKI_ASSERT(src.m_internalFormat == dest.m_internalFormat);
-	ANKI_ASSERT(src.m_glFormat == dest.m_glFormat);
-	ANKI_ASSERT(src.m_glType == dest.m_glType);
-
-	U width = src.m_width >> srcSurf.m_level;
-	U height = src.m_height >> srcSurf.m_level;
-
-	ANKI_ASSERT(width > 0 && height > 0);
-	ANKI_ASSERT(width == (dest.m_width >> destSurf.m_level) && height == (dest.m_height >> destSurf.m_level));
-
-	U srcSurfaceIdx = src.computeSurfaceIdx(srcSurf);
-	U destSurfaceIdx = dest.computeSurfaceIdx(destSurf);
-
-	glCopyImageSubData(src.getGlName(),
-		src.m_target,
-		srcSurf.m_level,
-		0,
-		0,
-		srcSurfaceIdx,
-		dest.getGlName(),
-		dest.m_target,
-		destSurf.m_level,
-		0,
-		0,
-		destSurfaceIdx,
-		width,
-		height,
-		1);
-}
-
-void TextureImpl::clear(const TextureSurfaceInfo& surf, const ClearValue& clearValue, DepthStencilAspectBit aspect)
+void TextureImpl::clear(const TextureSubresourceInfo& subresource, const ClearValue& clearValue) const
 {
 	ANKI_ASSERT(isCreated());
-	ANKI_ASSERT(surf.m_level < m_mipCount);
-	ANKI_ASSERT((aspect & m_dsAspect) == aspect);
+	ANKI_ASSERT(isSubresourceValid(subresource));
+	ANKI_ASSERT(m_texType != TextureType::_3D && "TODO");
 
 	// Find the aspect to clear
+	const DepthStencilAspectBit aspect = subresource.m_depthStencilAspect;
 	GLenum format;
 	if(aspect == DepthStencilAspectBit::DEPTH)
 	{
@@ -404,17 +329,25 @@ void TextureImpl::clear(const TextureSurfaceInfo& surf, const ClearValue& clearV
 		format = m_glFormat;
 	}
 
-	U surfaceIdx = computeSurfaceIdx(surf);
-	U width = m_width >> surf.m_level;
-	U height = m_height >> surf.m_level;
+	for(U mip = subresource.m_baseMipmap; mip < subresource.m_baseMipmap + subresource.m_mipmapCount; ++mip)
+	{
+		for(U face = subresource.m_baseFace; face < subresource.m_baseFace + subresource.m_faceCount; ++face)
+		{
+			for(U layer = subresource.m_baseLayer; layer < subresource.m_baseLayer + subresource.m_layerCount; ++layer)
+			{
+				const U surfaceIdx = computeSurfaceIdx(TextureSurfaceInfo(mip, 0, face, layer));
+				const U width = m_width >> mip;
+				const U height = m_height >> mip;
 
-	glClearTexSubImage(
-		m_glName, surf.m_level, 0, 0, surfaceIdx, width, height, 1, format, GL_FLOAT, &clearValue.m_colorf[0]);
+				glClearTexSubImage(
+					m_glName, mip, 0, 0, surfaceIdx, width, height, 1, format, GL_FLOAT, &clearValue.m_colorf[0]);
+			}
+		}
+	}
 }
 
 U TextureImpl::computeSurfaceIdx(const TextureSurfaceInfo& surf) const
 {
-	checkSurfaceOrVolume(surf);
 	U out;
 
 	if(m_target == GL_TEXTURE_3D)

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

@@ -49,23 +49,14 @@ public:
 	void init(const TextureInitInfo& init);
 
 	/// Write texture data.
-	void writeSurface(const TextureSurfaceInfo& surf, GLuint pbo, PtrSize offset, PtrSize dataSize);
-
-	/// Write texture data.
-	void writeVolume(const TextureVolumeInfo& vol, GLuint pbo, PtrSize offset, PtrSize dataSize) const;
+	void copyFromBuffer(const TextureSubresourceInfo& subresource, GLuint pbo, PtrSize offset, PtrSize dataSize) const;
 
 	/// Generate mipmaps.
-	void generateMipmaps2d(U face, U layer);
-
-	/// Copy a single surface from one texture to another.
-	static void copy(const TextureImpl& src,
-		const TextureSurfaceInfo& srcSurf,
-		const TextureImpl& dest,
-		const TextureSurfaceInfo& destSurf);
+	void generateMipmaps2d(const TextureViewImpl& view) const;
 
 	void bind() const;
 
-	void clear(const TextureSurfaceInfo& surf, const ClearValue& clearValue, DepthStencilAspectBit aspect);
+	void clear(const TextureSubresourceInfo& subresource, const ClearValue& clearValue) const;
 
 	U computeSurfaceIdx(const TextureSurfaceInfo& surf) const;
 

+ 4 - 4
src/anki/gr/gl/TextureView.cpp

@@ -16,16 +16,16 @@ TextureView* TextureView::newInstance(GrManager* manager, const TextureViewInitI
 	class CreateTextureViewCommand final : public GlCommand
 	{
 	public:
-		TextureViewPtr m_tex;
+		TextureViewPtr m_view;
 
-		CreateTextureCommand(TextureView* tex)
-			: m_tex(tex)
+		CreateTextureViewCommand(TextureView* view)
+			: m_view(view)
 		{
 		}
 
 		Error operator()(GlState&)
 		{
-			TextureImpl& impl = static_cast<TextureImpl&>(*m_tex);
+			TextureViewImpl& impl = static_cast<TextureViewImpl&>(*m_view);
 
 			impl.init();
 

+ 1 - 0
src/anki/gr/vulkan/CommandBufferImpl.cpp

@@ -666,6 +666,7 @@ void CommandBufferImpl::copyBufferToTextureViewInternal(
 	const TextureViewImpl& view = static_cast<const TextureViewImpl&>(*texView);
 	const TextureImpl& tex = static_cast<const TextureImpl&>(*view.m_tex);
 	ANKI_ASSERT(tex.usageValid(TextureUsageBit::TRANSFER_DESTINATION));
+	ANKI_ASSERT(tex.isSubresourceGoodForCopyFromBuffer(view.getSubresource()));
 	const VkImageLayout layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
 	const Bool is3D = tex.getTextureType() == TextureType::_3D;
 	const VkImageAspectFlags aspect = convertImageAspect(view.getDepthStencilAspect());