Browse Source

Vulkan: Some work on the mip generation

Panagiotis Christopoulos Charitos 9 years ago
parent
commit
d99cbe35bd

+ 2 - 0
include/anki/gr/vulkan/CommandBufferImpl.h

@@ -76,6 +76,8 @@ public:
 		const TextureSurfaceInfo& surf,
 		const TransientMemoryToken& token);
 
+	void generateMipmaps(TexturePtr tex, U depth, U face, U layer);
+
 	void endRecording();
 
 	void setImageBarrier(VkPipelineStageFlags srcStage,

+ 8 - 0
include/anki/gr/vulkan/CommandBufferImpl.inl.h

@@ -86,6 +86,14 @@ inline void CommandBufferImpl::setImageBarrier(TexturePtr tex,
 	TextureUsageBit nextUsage,
 	const TextureSurfaceInfo& surf)
 {
+	if(surf.m_level > 0)
+	{
+		ANKI_ASSERT((nextUsage & TextureUsageBit::GENERATE_MIPMAPS)
+				== TextureUsageBit::NONE
+			&& "This transition happens inside "
+			   "CommandBufferImpl::generateMipmaps");
+	}
+
 	const TextureImpl& impl = tex->getImplementation();
 	tex->getImplementation().checkSurface(surf);
 	Bool isDepthStencil = formatIsDepthStencil(impl.m_format);

+ 1 - 0
src/gr/vulkan/CommandBuffer.cpp

@@ -138,6 +138,7 @@ void CommandBuffer::dispatchCompute(
 //==============================================================================
 void CommandBuffer::generateMipmaps(TexturePtr tex, U depth, U face, U layer)
 {
+	m_impl->generateMipmaps(tex, depth, face, layer);
 }
 
 //==============================================================================

+ 84 - 0
src/gr/vulkan/CommandBufferImpl.cpp

@@ -271,4 +271,88 @@ void CommandBufferImpl::bindResourceGroup(
 	m_rcList.pushBack(m_alloc, rc);
 }
 
+//==============================================================================
+void CommandBufferImpl::generateMipmaps(
+	TexturePtr tex, U depth, U face, U layer)
+{
+	commandCommon();
+	const TextureImpl& impl = tex->getImplementation();
+	ANKI_ASSERT(impl.m_type != TextureType::_3D && "Not design for that ATM");
+
+	U mipCount = computeMaxMipmapCount(impl.m_width, impl.m_height);
+
+	for(U i = 0; i < mipCount - 1; ++i)
+	{
+		// Transition source
+		if(i > 0)
+		{
+			VkImageSubresourceRange range;
+			impl.computeSubResourceRange(
+				TextureSurfaceInfo(i, depth, face, layer), range);
+
+			setImageBarrier(impl.m_imageHandle,
+				VK_PIPELINE_STAGE_TRANSFER_BIT,
+				VK_ACCESS_TRANSFER_WRITE_BIT,
+				VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+				VK_PIPELINE_STAGE_TRANSFER_BIT,
+				VK_ACCESS_TRANSFER_READ_BIT,
+				VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+				range);
+		}
+
+		// Transition destination
+		{
+			VkImageSubresourceRange range;
+			impl.computeSubResourceRange(
+				TextureSurfaceInfo(i + 1, depth, face, layer), range);
+
+			setImageBarrier(impl.m_imageHandle,
+				0,
+				0,
+				VK_IMAGE_LAYOUT_UNDEFINED,
+				VK_PIPELINE_STAGE_TRANSFER_BIT,
+				VK_ACCESS_TRANSFER_WRITE_BIT,
+				VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+				range);
+		}
+
+		// Setup the blit struct
+		U srcWidth = impl.m_width >> i;
+		U srcHeight = impl.m_height >> i;
+
+		U dstWidth = impl.m_width >> i;
+		U dstHeight = impl.m_height >> i;
+
+		ANKI_ASSERT(
+			srcWidth > 0 && srcHeight > 0 && dstWidth > 0 && dstHeight > 0);
+
+		VkImageBlit blit;
+		blit.srcSubresource.aspectMask = impl.m_aspect;
+		blit.srcSubresource.baseArrayLayer = layer;
+		blit.srcSubresource.layerCount = 1;
+		blit.srcSubresource.mipLevel = i;
+		blit.srcOffsets[0] = {0, 0, 0};
+		blit.srcOffsets[1] = {srcWidth, srcHeight, 1};
+
+		blit.dstSubresource.aspectMask = impl.m_aspect;
+		blit.dstSubresource.baseArrayLayer = layer;
+		blit.dstSubresource.layerCount = 1;
+		blit.dstSubresource.mipLevel = i + 1;
+		blit.dstOffsets[0] = {0, 0, 0};
+		blit.dstOffsets[1] = {dstWidth, dstHeight, 1};
+
+		vkCmdBlitImage(m_handle,
+			impl.m_imageHandle,
+			VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+			impl.m_imageHandle,
+			VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+			1,
+			&blit,
+			VK_FILTER_LINEAR);
+	}
+
+	// Hold the reference
+	m_texList.pushBack(m_alloc, tex);
+}
+
 } // end namespace anki

+ 130 - 13
tests/gr/Gr.cpp

@@ -142,12 +142,21 @@ static const char* FRAG_TEX_SRC = R"(layout (location = 0) out vec4 out_color;
 
 layout(location = 0) in vec2 in_uv;
 
-layout(ANKI_TEX_BINDING(0, 0)) uniform sampler2D u_tex;
+layout(ANKI_UBO_BINDING(0, 0)) uniform u0_
+{
+	vec4 u_factor;
+};
+
+layout(ANKI_TEX_BINDING(0, 0)) uniform sampler2D u_tex0;
+layout(ANKI_TEX_BINDING(0, 1)) uniform sampler2D u_tex1;
 
 void main()
 {
 	float factor = in_uv.x;
-	out_color = vec4(textureLod(u_tex, in_uv, factor).rgb, 1.0);
+	vec3 col0 = textureLod(u_tex0, in_uv, factor).rgb;
+	vec3 col1 = textureLod(u_tex1, in_uv, factor * 2.0).rgb;
+	
+	out_color = vec4((col1 + col1) * 0.5, 1.0);
 })";
 
 #define COMMON_BEGIN()                                                         \
@@ -592,7 +601,7 @@ ANKI_TEST(Gr, DrawWithTexture)
 
 	{
 		//
-		// Create the texture
+		// Create texture A
 		//
 		TextureInitInfo init;
 		init.m_depth = 1;
@@ -608,35 +617,117 @@ ANKI_TEST(Gr, DrawWithTexture)
 		init.m_depth = 1;
 		init.m_layerCount = 1;
 		init.m_sampling.m_repeat = false;
-		init.m_sampling.m_minMagFilter = SamplingFilter::LINEAR;
+		init.m_sampling.m_minMagFilter = SamplingFilter::NEAREST;
 		init.m_sampling.m_mipmapFilter = SamplingFilter::LINEAR;
 		init.m_type = TextureType::_2D;
 
+		TexturePtr a = gr->newInstance<Texture>(init);
+
+		//
+		// Create texture B
+		//
+		init.m_width = 4;
+		init.m_height = 4;
+		init.m_mipmapsCount = 3;
+		init.m_usage = TextureUsageBit::FRAGMENT_SHADER_SAMPLED
+			| TextureUsageBit::UPLOAD | TextureUsageBit::GENERATE_MIPMAPS;
+		init.m_initialUsage = TextureUsageBit::NONE;
+
 		TexturePtr b = gr->newInstance<Texture>(init);
 
 		//
-		// Upload
+		// Upload all textures
 		//
 		Array<U8, 2 * 2 * 4> mip0 = {
 			{255, 0, 0, 0, 0, 255, 0, 0, 0, 0, 255, 0, 255, 0, 255, 0}};
 
 		Array<U8, 4> mip1 = {{128, 128, 128, 0}};
 
+		Array<U8, 4 * 4 * 4> bmip0 = {{255,
+			0,
+			0,
+			0,
+			0,
+			255,
+			0,
+			0,
+			0,
+			0,
+			255,
+			0,
+			255,
+			255,
+			0,
+			0,
+			255,
+			0,
+			255,
+			0,
+			0,
+			255,
+			255,
+			0,
+			255,
+			255,
+			255,
+			0,
+			128,
+			0,
+			0,
+			0,
+			0,
+			128,
+			0,
+			0,
+			0,
+			0,
+			128,
+			0,
+			128,
+			128,
+			0,
+			0,
+			128,
+			0,
+			128,
+			0,
+			0,
+			128,
+			128,
+			0,
+			128,
+			128,
+			128,
+			0,
+			255,
+			128,
+			0,
+			0,
+			0,
+			128,
+			255,
+			0}};
+
 		CommandBufferInitInfo cmdbinit;
 		cmdbinit.m_flags = CommandBufferFlag::TRANSFER_WORK;
 		CommandBufferPtr cmdb = gr->newInstance<CommandBuffer>(cmdbinit);
 
 		// Set barriers
-		cmdb->setTextureBarrier(b,
+		cmdb->setTextureBarrier(a,
 			TextureUsageBit::FRAGMENT_SHADER_SAMPLED,
 			TextureUsageBit::UPLOAD,
 			TextureSurfaceInfo(0, 0, 0, 0));
 
-		cmdb->setTextureBarrier(b,
+		cmdb->setTextureBarrier(a,
 			TextureUsageBit::FRAGMENT_SHADER_SAMPLED,
 			TextureUsageBit::UPLOAD,
 			TextureSurfaceInfo(1, 0, 0, 0));
 
+		cmdb->setTextureBarrier(b,
+			TextureUsageBit::NONE,
+			TextureUsageBit::UPLOAD,
+			TextureSurfaceInfo(0, 0, 0, 0));
+
 		Error err = ErrorCode::NONE;
 		TransientMemoryToken token;
 		void* ptr = gr->allocateFrameTransientMemory(
@@ -645,7 +736,7 @@ ANKI_TEST(Gr, DrawWithTexture)
 		ANKI_TEST_EXPECT_NO_ERR(err);
 		memcpy(ptr, &mip0[0], sizeof(mip0));
 
-		cmdb->uploadTextureSurface(b, TextureSurfaceInfo(0, 0, 0, 0), token);
+		cmdb->uploadTextureSurface(a, TextureSurfaceInfo(0, 0, 0, 0), token);
 
 		ptr = gr->allocateFrameTransientMemory(
 			sizeof(mip1), BufferUsage::TRANSFER, token, &err);
@@ -653,26 +744,51 @@ ANKI_TEST(Gr, DrawWithTexture)
 		ANKI_TEST_EXPECT_NO_ERR(err);
 		memcpy(ptr, &mip1[0], sizeof(mip1));
 
-		cmdb->uploadTextureSurface(b, TextureSurfaceInfo(1, 0, 0, 0), token);
+		cmdb->uploadTextureSurface(a, TextureSurfaceInfo(1, 0, 0, 0), token);
 
-		// Set barriers
+		ptr = gr->allocateFrameTransientMemory(
+			sizeof(bmip0), BufferUsage::TRANSFER, token, &err);
+		ANKI_TEST_EXPECT_NEQ(ptr, nullptr);
+		ANKI_TEST_EXPECT_NO_ERR(err);
+		memcpy(ptr, &bmip0[0], sizeof(bmip0));
+
+		cmdb->uploadTextureSurface(b, TextureSurfaceInfo(0, 0, 0, 0), token);
+
+		// Gen mips
 		cmdb->setTextureBarrier(b,
+			TextureUsageBit::UPLOAD,
+			TextureUsageBit::GENERATE_MIPMAPS,
+			TextureSurfaceInfo(0, 0, 0, 0));
+
+		cmdb->generateMipmaps(b, 0, 0, 0);
+
+		// Set barriers
+		cmdb->setTextureBarrier(a,
 			TextureUsageBit::UPLOAD,
 			TextureUsageBit::FRAGMENT_SHADER_SAMPLED,
 			TextureSurfaceInfo(0, 0, 0, 0));
 
-		cmdb->setTextureBarrier(b,
+		cmdb->setTextureBarrier(a,
 			TextureUsageBit::UPLOAD,
 			TextureUsageBit::FRAGMENT_SHADER_SAMPLED,
 			TextureSurfaceInfo(1, 0, 0, 0));
 
+		for(U i = 0; i < 3; ++i)
+		{
+			cmdb->setTextureBarrier(b,
+				TextureUsageBit::GENERATE_MIPMAPS,
+				TextureUsageBit::FRAGMENT_SHADER_SAMPLED,
+				TextureSurfaceInfo(i, 0, 0, 0));
+		}
+
 		cmdb->flush();
 
 		//
 		// Create resource group
 		//
 		ResourceGroupInitInfo rcinit;
-		rcinit.m_textures[0].m_texture = b;
+		rcinit.m_textures[0].m_texture = a;
+		rcinit.m_textures[1].m_texture = b;
 		ResourceGroupPtr rc = gr->newInstance<ResourceGroup>(rcinit);
 
 		//
@@ -689,7 +805,8 @@ ANKI_TEST(Gr, DrawWithTexture)
 		//
 		// Draw
 		//
-		U iterations = 100;
+		const U ITERATION_COUNT = 200;
+		U iterations = ITERATION_COUNT;
 		while(iterations--)
 		{
 			HighRezTimer timer;