Jump to content

Expanding the render functionality


Recommended Posts

Hello all together,

on february, I will finish my bachelor thesis. Then I want to contribute development content for 0 A.D.

I am thinking about to expand the render engine with Vulkan Support.

I read in Preparation a lot of threads, like https://wildfiregames.com/forum/index.php?/topic/21256-vulkan-api/&tab=comments#comment-320810 and https://wildfiregames.com/forum/index.php?/topic/24694-0-ad-the-next-steps/&tab=comments#comment-359754.

I read out the following requirements:

  • 0 A.D. shall support older hardware, too

  • Vulkan should be GPL Compatible -> I have no idea about this 

Finally I thought about implementing the functionality as a wrapper (adapter pattern)

In addition, I analyzed which classes uses OpenGL Code, which I have attached as a Pdf file.

On the basis of the analysis, I found out that a lot of Opengl Code is used in other Solutions like atlas, lowlevel, GUI and so on. Often are these render or draw methods like:

  • GuiRenderer::Draw

  • CminiMap::Draw

  • AtlasViewGame::Render

  • and so on

What do you think about encapsulte API Functions in the Graphics Solution? 

So for example AtlasViewGame::Render calls an render function of the Graphics Solution.

Here is an example, how a adapter pattern of the Renderer Component can look like:

#include <iostream>

using namespace std;



// use GL or Vulkan

#define _USEGL 1



// Renderer Interface

class IRenderer

{

public:

//bool init();

virtual void draw() = 0;

};



#ifdef _USEGL

// Opengl Renderer

class GlRenderer : public IRenderer

{

public:

void draw()

{

cout << "GlRenderer draw method called!" << endl;

}

};



#elif _USEVULKAN



// Vulkan Renderer

class VulkanRenderer : public IRenderer

{

public:

void draw()

{

cout << "VulkanRenderer draw method called!" << endl;

}

};

#endif





int main()

{

#ifdef _USEGL

IRenderer *rend = new GlRenderer();

rend->draw();

#elif _USEVULKAN

IRenderer *rend = new VulkanRenderer();

rend->draw();

#endif

return 0;

}

 

What do you think about my plan?

Do you have any suggestions?

 

Best regards

 

Pixma

VulkanImplConcept.pdf

  • Like 2
Link to comment
Share on other sites

I think implementing a Vulcan backend is a good idea, and it could support windows, linux and OSX (through MoltenVK). I'm not extremely up to date on the details of the renderer, but in principle we will need to keep an OGL renderer too so that older hardware is supported.

My main question is if there are libraries that could allow us to implement a single low-ish level renderer and that takes care of switching to OGL, Vulkan, Metal or DX.

  • Like 1
Link to comment
Share on other sites

@stanislas69 Thanks :) 

@wraitii yes, i think Support for OpenGl is important. I don't know any library which can do this. But I think with the adapter pattern we could implement a low-level renderer. Furthermore we can think of using define statements or variables to switch the Graphi api. The variant with the variable, we could create an entry in an configuration file. The disadvantage of using variables is that all api libraries are needed to built.

The idea of implementing an adapter pattern with #ifdef and #elif is shown in my first thread. 

This could be an example of an adapter pattern with variables:

#include <iostream>
using namespace std;

enum RenderAPI {GL, VULKAN, METAL};

// Configuration File
//////////////////////////////////
int renderApi = GL;

// Cpp and H File
//////////////////////////////////

// Renderer Interface
class IRenderer
{
public:
	//bool init();
	virtual void draw() = 0;
};

// Opengl Renderer
class GlRenderer : public IRenderer
{
public:
	void draw()
	{
		cout << "GlRenderer draw method called!" << endl;
	}
};

// Vulkan Renderer
class VulkanRenderer : public IRenderer
{
public:
	void draw()
	{
		cout << "VulkanRenderer draw method called!" << endl;
	}
};



int main()
{
	if (renderApi == GL)
	{
		IRenderer *rend = new GlRenderer();
		rend->draw();
	}
	else if (renderApi == VULKAN)
	{
		IRenderer *rend = new VulkanRenderer();
		rend->draw();
	}
	return 0;
}

Finally, I can research for an GPL library that could allow us this type of implementation.

  • Like 2
Link to comment
Share on other sites

Hi @Pixma!

As I said on Discord, #ifdef isn't needed if you use adapters. And vice versa.

I know only few low-level libraries for that kind of things. The problem of abstractions (of libraries that I know), is that they mostly have only core things and sometimes visible performance differences. If you want to use some specific stuff (e.g. we use post-processing only if the render to texture is supported by driver), we need to modify the third-party library or do an ugly workaround.

So if a library that fits in our requirements doesn't exist, then the adapter model is the best for us, I think. In that case we don't need many APIs. I'd prefer to support only OpenGL and Vulkan, it means less duplication of shader code and more compatible things (like many GLSL > SPIR-V translators).

Why the performance is important? Because we support old machines (e.g. with GL 1 & 2), and it means we may don't notice some performance difference, that can be noticeable on slower machines.

  • Like 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...