C++ programming question related to Vulkan

#1

Graphics pipelines in Vulkan are tied to both a shader and context. I want to store a map of these in the context, using the shader as the map key. I can use a weak_ptr to the shader for the key so it does not create a circular reference. This is what the third parameter in the map definition below does:

class Context
{
public:
	std::map<weak_ptr<Shader>, shared_ptr<Pipeline>, std::owner_less<std::weak_ptr<Shader> > pipelines;

	void Draw(shared_ptr<Shader> shader)
	{
		auto iter = pipelines.find(shader);
		if (iter == pipelines.end()) pipelines[shader] = CreatePipeline(shader);
		auto pipeline = iter->second;

		//Begin drawing...

	}
};

When the shader goes out of scope and is deleted the associated pipelines in each context will still be stored in the map. Is there any way I can set this up so that the shader being deleted automatically clears all the map values associated with that key, in each context? The only solution I can think of is to loop through a list of all contexts and remove the values in the shader destructor. You could also store the pipeline in the shader class, but you will have multiple pipelines, one for each context.

One possible solution is a cleanup method that gets run periodically:

void Context::Cleanup()
{
	for (auto it = pipelines.begin(); it != pipelines.end(); ++it)
	{
		it (it->first.lock() == nullptr)
		{
			pipelines.erase(it++);
		}
	}
}

This all feels very backwards, like the kind of stuff I used to have to do for raw pointers. Is there any neater solution?

#2

Solution to what, exactly? It’s hard to offer a solution when you haven’t presented the problem.

Oh, you’ve shown us the code and said that it’s clunky. But the problem isn’t the code; the problem is whatever led you to write that code in the first place.

Why do you need a map from weak shaders to pipelines? Why does this map need to own the pipeline? Isn’t that just a clunkier way of having the shader own the pipeline? And if the shader owned the pipeline… you wouldn’t need a map, since you could just ask the shader.

Indeed, I find that the most puzzling bit of your code is that you feel the need to make Draw take ownership of a Shader, even though it clearly does no such thing. It uses a Shader for a while, but it doesn’t own it.

Overall, I question your overuse of shared ownership here.

#3

A weak pointer is used because otherwise the key object would never go out of scope.

I think somewhere in that blob of Vulkan code, the swap chain images are being referenced by the graphics pipeline object, which would mean a different graphics pipeline is needed for each shader / “context” combination. Maybe not. It will take a while to trace all the way through it.

#4

Okay, I am looking more carefully through this, and although the image formats are referenced, I don’t see anything that references the swap chain images themselves. So it looks like you can create the pipeline with a couple of dynamic states for the viewport and scissor, and then use VkCmdSetViewport and VkCmdSetScissor to adjust the pipeline as you render to different windows.

#5

I’ve got a RenderPass and RenderPipeline class worked out that is independent from the swap chain, using dynamic states for the viewport and scissor settings. So this “dual ownership” is fortunately not necessary.

Thanks for the input.