Browse Source

Vulkan: Adding vertex input support

Panagiotis Christopoulos Charitos 9 years ago
parent
commit
0c55a1941a

+ 17 - 0
include/anki/gr/vulkan/ResourceGroupImpl.h

@@ -26,14 +26,31 @@ public:
 
 	ANKI_USE_RESULT Error init(const ResourceGroupInitInfo& init);
 
+	Bool hasDescriptorSet() const
+	{
+		return m_handle != VK_NULL_HANDLE;
+	}
+
 	VkDescriptorSet getHandle() const
 	{
 		ANKI_ASSERT(m_handle);
 		return m_handle;
 	}
 
+	void getVertexBindingInfo(const VkBuffer*& buffers,
+		const VkDeviceSize*& offsets,
+		U& bindingCount) const
+	{
+		buffers = &m_vertBuffs[0];
+		offsets = &m_offsets[0];
+		bindingCount = m_bindingCount;
+	}
+
 private:
 	VkDescriptorSet m_handle = VK_NULL_HANDLE;
+	Array<VkBuffer, MAX_VERTEX_ATTRIBUTES> m_vertBuffs = {{}};
+	Array<VkDeviceSize, MAX_VERTEX_ATTRIBUTES> m_offsets = {{}};
+	U32 m_bindingCount = 0;
 
 	/// Holds the references to the resources. Used to release the references
 	/// gracefully

+ 33 - 13
src/gr/vulkan/CommandBufferImpl.cpp

@@ -232,21 +232,41 @@ void CommandBufferImpl::flush(CommandBuffer* cmdb)
 void CommandBufferImpl::bindResourceGroup(
 	ResourceGroupPtr rc, U slot, const TransientMemoryInfo* dynInfo)
 {
-	commandCommon();
 	// TODO set the correct binding point
-	Array<U32, MAX_UNIFORM_BUFFER_BINDINGS + MAX_STORAGE_BUFFER_BINDINGS>
-		dynOffsets = {{}};
-
-	VkDescriptorSet dset = rc->getImplementation().getHandle();
-	vkCmdBindDescriptorSets(m_handle,
-		VK_PIPELINE_BIND_POINT_GRAPHICS,
-		getGrManagerImpl().getGlobalPipelineLayout(),
-		slot,
-		1,
-		&dset,
-		dynOffsets.getSize(),
-		&dynOffsets[0]);
 
+	commandCommon();
+	const ResourceGroupImpl& impl = rc->getImplementation();
+
+	if(impl.hasDescriptorSet())
+	{
+		Array<U32, MAX_UNIFORM_BUFFER_BINDINGS + MAX_STORAGE_BUFFER_BINDINGS>
+			dynOffsets = {{}};
+
+		VkDescriptorSet dset = impl.getHandle();
+		vkCmdBindDescriptorSets(m_handle,
+			VK_PIPELINE_BIND_POINT_GRAPHICS,
+			getGrManagerImpl().getGlobalPipelineLayout(),
+			slot,
+			1,
+			&dset,
+			dynOffsets.getSize(),
+			&dynOffsets[0]);
+	}
+
+	// Bind vertex buffers only in the first set
+	if(slot == 0)
+	{
+		const VkBuffer* buffers = nullptr;
+		const VkDeviceSize* offsets = nullptr;
+		U bindingCount = 0;
+		impl.getVertexBindingInfo(buffers, offsets, bindingCount);
+		if(bindingCount)
+		{
+			vkCmdBindVertexBuffers(m_handle, 0, bindingCount, buffers, offsets);
+		}
+	}
+
+	// Hold the reference
 	m_rcList.pushBack(m_alloc, rc);
 }
 

+ 2 - 0
src/gr/vulkan/PipelineImpl.cpp

@@ -47,6 +47,8 @@ public:
 
 		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;

+ 48 - 6
src/gr/vulkan/ResourceGroupImpl.cpp

@@ -41,6 +41,18 @@ U ResourceGroupImpl::calcRefCount(
 		}
 	}
 
+	for(U i = 0; i < MAX_VERTEX_ATTRIBUTES; ++i)
+	{
+		if(init.m_vertexBuffers[i].m_buffer)
+		{
+			++count;
+		}
+		else if(init.m_vertexBuffers[i].m_uploadedMemory)
+		{
+			hasUploaded = true;
+		}
+	}
+
 	// TODO: The rest of the resources
 
 	return count;
@@ -49,10 +61,6 @@ U ResourceGroupImpl::calcRefCount(
 //==============================================================================
 Error ResourceGroupImpl::init(const ResourceGroupInitInfo& init)
 {
-	// Create
-	//
-	ANKI_CHECK(getGrManagerImpl().allocateDescriptorSet(m_handle));
-
 	// Store the references
 	//
 	Bool hasUploaded = false;
@@ -96,6 +104,11 @@ Error ResourceGroupImpl::init(const ResourceGroupInitInfo& init)
 
 	if(uniCount)
 	{
+		if(m_handle == VK_NULL_HANDLE)
+		{
+			ANKI_CHECK(getGrManagerImpl().allocateDescriptorSet(m_handle));
+		}
+
 		VkWriteDescriptorSet& w = write[writeCount++];
 		w.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
 		w.descriptorCount = uniCount;
@@ -105,8 +118,37 @@ Error ResourceGroupImpl::init(const ResourceGroupInitInfo& init)
 		w.dstSet = m_handle;
 	}
 
-	ANKI_ASSERT(writeCount > 0);
-	vkUpdateDescriptorSets(getDevice(), writeCount, &write[0], 0, nullptr);
+	// Check if it was created. It's not created only if the rc group contains
+	// only vertex info.
+	if(m_handle)
+	{
+		vkUpdateDescriptorSets(getDevice(), writeCount, &write[0], 0, nullptr);
+	}
+
+	// Vertex stuff
+	//
+	for(U i = 0; i < init.m_vertexBuffers.getSize(); ++i)
+	{
+		if(init.m_vertexBuffers[i].m_buffer)
+		{
+			m_vertBuffs[i] = init.m_vertexBuffers[i]
+								 .m_buffer->getImplementation()
+								 .getHandle();
+			m_offsets[i] = init.m_vertexBuffers[i].m_offset;
+			++m_bindingCount;
+
+			m_refs[refCount++] = init.m_vertexBuffers[i].m_buffer;
+		}
+		else if(init.m_vertexBuffers[i].m_uploadedMemory)
+		{
+			ANKI_ASSERT(0 && "TODO");
+			++m_bindingCount;
+		}
+		else
+		{
+			break;
+		}
+	}
 
 	return ErrorCode::NONE;
 }

+ 157 - 1
tests/gr/Gr.cpp

@@ -58,6 +58,30 @@ void main()
 #endif
 })";
 
+static const char* VERT_INP_SRC = R"(
+layout(location = 0) in vec3 in_position;
+layout(location = 1) in vec3 in_color0;
+layout(location = 2) in vec3 in_color1;
+
+out gl_PerVertex
+{
+	vec4 gl_Position;
+};
+
+layout(location = 0) out vec3 out_color0;
+layout(location = 1) out vec3 out_color1;
+
+void main()
+{
+	gl_Position = vec4(in_position, 1.0);
+#if defined(ANKI_VK)
+	gl_Position.y = -gl_Position.y;
+#endif
+
+	out_color0 = in_color0;
+	out_color1 = in_color1;
+})";
+
 static const char* FRAG_SRC = R"(layout (location = 0) out vec4 out_color;
 
 void main()
@@ -67,13 +91,23 @@ void main()
 
 static const char* FRAG_UBO_SRC = R"(layout (location = 0) out vec4 out_color;
 
-in vec3 in_color;
+layout(location = 0) in vec3 in_color;
 
 void main()
 {
 	out_color = vec4(in_color, 1.0);
 })";
 
+static const char* FRAG_INP_SRC = R"(layout (location = 0) out vec4 out_color;
+
+layout(location = 0) in vec3 in_color0;
+layout(location = 1) in vec3 in_color1;
+
+void main()
+{
+	out_color = vec4(in_color0 + in_color1, 1.0);
+})";
+
 #define COMMON_BEGIN()                                                         \
 	NativeWindow* win = nullptr;                                               \
 	GrManager* gr = nullptr;                                                   \
@@ -349,4 +383,126 @@ ANKI_TEST(Gr, DrawWithUniforms)
 	COMMON_END();
 }
 
+//==============================================================================
+ANKI_TEST(Gr, DrawWithVertex)
+{
+	COMMON_BEGIN();
+
+	{
+		// The buffers
+		struct Vert
+		{
+			Vec3 m_pos;
+			Array<U8, 4> m_color;
+		};
+		static_assert(sizeof(Vert) == sizeof(Vec4), "See file");
+
+		BufferPtr b = gr->newInstance<Buffer>(sizeof(Vert) * 3,
+			BufferUsageBit::VERTEX,
+			BufferAccessBit::CLIENT_MAP_WRITE);
+
+		Vert* ptr = static_cast<Vert*>(
+			b->map(0, sizeof(Vert) * 3, BufferAccessBit::CLIENT_MAP_WRITE));
+		ANKI_TEST_EXPECT_NEQ(ptr, nullptr);
+
+		ptr[0].m_pos = Vec3(-1.0, 1.0, 0.0);
+		ptr[1].m_pos = Vec3(0.0, -1.0, 0.0);
+		ptr[2].m_pos = Vec3(1.0, 1.0, 0.0);
+
+		ptr[0].m_color = {255, 0, 0};
+		ptr[1].m_color = {0, 255, 0};
+		ptr[2].m_color = {0, 0, 255};
+		b->unmap();
+
+		BufferPtr c = gr->newInstance<Buffer>(sizeof(Vec3) * 3,
+			BufferUsageBit::VERTEX,
+			BufferAccessBit::CLIENT_MAP_WRITE);
+
+		Vec3* otherColor = static_cast<Vec3*>(
+			c->map(0, sizeof(Vec3) * 3, BufferAccessBit::CLIENT_MAP_WRITE));
+
+		otherColor[0] = Vec3(0.0, 1.0, 1.0);
+		otherColor[1] = Vec3(1.0, 0.0, 1.0);
+		otherColor[2] = Vec3(1.0, 1.0, 0.0);
+		c->unmap();
+
+		// Resource group
+		ResourceGroupInitInfo rcinit;
+		rcinit.m_vertexBuffers[0].m_buffer = b;
+		rcinit.m_vertexBuffers[1].m_buffer = c;
+		ResourceGroupPtr rc = gr->newInstance<ResourceGroup>(rcinit);
+
+		// Shaders
+		ShaderPtr vert =
+			gr->newInstance<Shader>(ShaderType::VERTEX, VERT_INP_SRC);
+		ShaderPtr frag =
+			gr->newInstance<Shader>(ShaderType::FRAGMENT, FRAG_INP_SRC);
+
+		// Ppline
+		PipelineInitInfo init;
+		init.m_shaders[ShaderType::VERTEX] = vert;
+		init.m_shaders[ShaderType::FRAGMENT] = frag;
+		init.m_color.m_drawsToDefaultFramebuffer = true;
+		init.m_color.m_attachmentCount = 1;
+		init.m_depthStencil.m_depthWriteEnabled = false;
+
+		init.m_vertex.m_attributeCount = 3;
+		init.m_vertex.m_attributes[0].m_format =
+			PixelFormat(ComponentFormat::R32G32B32, TransformFormat::FLOAT);
+		init.m_vertex.m_attributes[1].m_format =
+			PixelFormat(ComponentFormat::R8G8B8, TransformFormat::UNORM);
+		init.m_vertex.m_attributes[1].m_offset = sizeof(Vec3);
+		init.m_vertex.m_attributes[2].m_format =
+			PixelFormat(ComponentFormat::R32G32B32, TransformFormat::FLOAT);
+		init.m_vertex.m_attributes[2].m_binding = 1;
+
+		init.m_vertex.m_bindingCount = 2;
+		init.m_vertex.m_bindings[0].m_stride = sizeof(Vert);
+		init.m_vertex.m_bindings[1].m_stride = sizeof(Vec3);
+
+		PipelinePtr ppline = gr->newInstance<Pipeline>(init);
+
+		// FB
+		FramebufferInitInfo fbinit;
+		fbinit.m_colorAttachmentCount = 1;
+		fbinit.m_colorAttachments[0].m_clearValue.m_colorf = {
+			1.0, 0.0, 1.0, 1.0};
+		FramebufferPtr fb = gr->newInstance<Framebuffer>(fbinit);
+
+		U iterations = 100;
+		while(--iterations)
+		{
+			HighRezTimer timer;
+			timer.start();
+
+			gr->beginFrame();
+
+			CommandBufferInitInfo cinit;
+			cinit.m_frameFirstCommandBuffer = true;
+			cinit.m_frameLastCommandBuffer = true;
+			CommandBufferPtr cmdb = gr->newInstance<CommandBuffer>(cinit);
+
+			cmdb->setViewport(0, 0, WIDTH, HEIGHT);
+			cmdb->setPolygonOffset(0.0, 0.0);
+			cmdb->bindPipeline(ppline);
+			cmdb->beginRenderPass(fb);
+			cmdb->bindResourceGroup(rc, 0, nullptr);
+			cmdb->drawArrays(3);
+			cmdb->endRenderPass();
+			cmdb->flush();
+
+			gr->swapBuffers();
+
+			timer.stop();
+			const F32 TICK = 1.0 / 30.0;
+			if(timer.getElapsedTime() < TICK)
+			{
+				HighRezTimer::sleep(TICK - timer.getElapsedTime());
+			}
+		}
+	}
+
+	COMMON_END();
+}
+
 } // end namespace anki