Jump to content

  • Log In with Google      Sign In   
  • Create Account

FREE SOFTWARE GIVEAWAY

We have 4 x Pro Licences (valued at $59 each) for 2d modular animation software Spriter to give away in this Thursday's GDNet Direct email newsletter.


Read more in this forum topic or make sure you're signed up (from the right-hand sidebar on the homepage) and read Thursday's newsletter to get in the running!


Tips on abstracting rendering interfaces for multiple renderers?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
11 replies to this topic

#1 Flimflam   Members   -  Reputation: 657

Like
0Likes
Like

Posted 29 July 2012 - 04:58 AM

Greetings!

I've long used D3D9 directly in my coding for years, and thought I'd like to undertake learning D3D11, and what better way to do this than to work out a small game idea I've been toying with. But even though XP is on it's way out, I still want my friends and others on XP to be able to run my projects, so I thought I'd like to abstract away the actual rendering calls so I could more or less use either one in my code without specifically targeting one or the other. I've been programming for years now, but to be honest, I'm still a bit green when it comes to situations like this. D3D9 and 11 seem largely different enough that I'm not sure how I could efficiently do this. I'd also be interesting in taking what I've learned and applying it to OpenGL so that some day in the (far) future I could consider cross-platform releases.

I stumbled across this page http://troylawlor.co...enderer-part-1/ -- It seemed to be everything I was hoping for but to my dismay it seems they either haven't finished the next installment or have abandoned it, given that several months has passed since part 1.

Does anyone have any tips, resources, articles, or anything they can share on doing this sort of thing, abstracting away rendering API? I do a lot of work through SlimDX but I'm not afraid of C/C++ (used that for years before I got in bed with C#) so I'm not really afraid of the language used in the articles or what have you. Anything would help. Thanks!

Sponsor:

#2 AgentC   Members   -  Reputation: 1417

Like
1Likes
Like

Posted 29 July 2012 - 10:21 AM

D3D11 is a stricter API than D3D9 (or OpenGL for that matter), as instead of a large, free-form state machine you have a rather limited set of state objects. Therefore, to make sure you're using D3D11 performantly and can take full advantage of its features in the future I'd recommend basing your abstract API on the D3D11 model (state objects, constant buffers) and emulating it on D3D9 and OpenGL as needed, instead of the other way around.

Here's one example of an abstracted rendering API which provides implementations on D3D11, OpenGL 3 and OpenGL ES 2 (the implementation is not open source, though):

http://clb.demon.fi/gfxapi/

Edited by AgentC, 29 July 2012 - 10:21 AM.

Every time you add a boolean member variable, God kills a kitten. Every time you create a Manager class, God kills a kitten. Every time you create a Singleton...

Urho3D (engine)  Hessian (C64 game project)


#3 M6dEEp   Members   -  Reputation: 897

Like
0Likes
Like

Posted 30 July 2012 - 11:26 AM

Take a look at Tesla Engine: http://www.tesla-engine.net/

The guy there (I think he's Starnick from around the forums here) has a great design for a multi API renderer that is really interesting to look at.

#4 MJP   Moderators   -  Reputation: 11786

Like
5Likes
Like

Posted 30 July 2012 - 12:32 PM

Ugh, abstract bases classes. Not a fan.

For the most part I prefer low-level implementation functions and simple data structs, with the implementation of both being determined at compile time based on the platform I'm building for. So there might be a Texture.h with a function "CreateTexture", then a Texture_win.cpp that creates a D3D11 ID3D11Texture2D, then a Texture_ps3.cpp that does the PS3 equivalent, and so on.Then if you want you can build high-level classes on top of those functions.

You can actually use the same approach for more than just graphics, if you want. For instance file IO, threads, and other system-level stuff.

#5 Flimflam   Members   -  Reputation: 657

Like
0Likes
Like

Posted 31 July 2012 - 02:25 AM

Ugh, abstract bases classes. Not a fan.

For the most part I prefer low-level implementation functions and simple data structs, with the implementation of both being determined at compile time based on the platform I'm building for. So there might be a Texture.h with a function "CreateTexture", then a Texture_win.cpp that creates a D3D11 ID3D11Texture2D, then a Texture_ps3.cpp that does the PS3 equivalent, and so on.Then if you want you can build high-level classes on top of those functions.

You can actually use the same approach for more than just graphics, if you want. For instance file IO, threads, and other system-level stuff.


That's actually an interesting idea.

Thank you everyone for your replies! I'm going to go over what I've got in front of me and if I have any more questions, I'll come back.

#6 Seabolt   Members   -  Reputation: 633

Like
0Likes
Like

Posted 01 August 2012 - 11:10 AM

Ugh, abstract bases classes. Not a fan.

For the most part I prefer low-level implementation functions and simple data structs, with the implementation of both being determined at compile time based on the platform I'm building for. So there might be a Texture.h with a function "CreateTexture", then a Texture_win.cpp that creates a D3D11 ID3D11Texture2D, then a Texture_ps3.cpp that does the PS3 equivalent, and so on.Then if you want you can build high-level classes on top of those functions.

You can actually use the same approach for more than just graphics, if you want. For instance file IO, threads, and other system-level stuff.


I've made a platform agnostic renderer using your method and abstract base classes, I found that it was a giant pain managing all the platform defines to make sure that the proper helper structures get included, and I found that it was really difficult to abstract around all of the strange features of each renderer using the compile time solution. While I've also started working on a new project using abstract base classes. Why do your prefer compile time to abstract base classes, and how do you handle platform scaling, like D3D11 feature levels or OGL levels?
Perception is when one imagination clashes with another

#7 MJP   Moderators   -  Reputation: 11786

Like
1Likes
Like

Posted 01 August 2012 - 11:46 AM

I've made a platform agnostic renderer using your method and abstract base classes, I found that it was a giant pain managing all the platform defines to make sure that the proper helper structures get included


We have our structures in one header file, with one other header file that includes the right header based on the platform. I can't imagine why you'd need more than that.

and I found that it was really difficult to abstract around all of the strange features of each renderer using the compile time solution.


How does compile-time polymorphism at all limit you in terms of your ability to abstract out higher-level features? You can do all of the same things you can do with abstract base classes (if not more), the only difference is you don't eat a virtual function call every time you need to do something. I mentioned dealing with the small, low-level building blocks of a renderer but you can also have different platform implementations of higher-level features.

Why do your prefer compile time to abstract base classes, and


Like I already mentioned, I prefer not having virtual function calls and indirections all over the place.

how do you handle platform scaling, like D3D11 feature levels or OGL levels?


I don't, because I don't care about them. I mainly deal with consoles, which obviously skews my preferences quite a bit.

#8 Seabolt   Members   -  Reputation: 633

Like
0Likes
Like

Posted 01 August 2012 - 11:52 AM

Ah I see, I had my helper structures in their own namespaces in their own files, like texture would be in TextureDX11.h and it would define a structure and any sort of DX11 specific functionality, so I had multiple files.

On your second point, I see your point. My problem was the way I had the actual architecture structured, not the compile time vs abstract base class approach, so oops.

And on the third point; fair enough.

Thanks for your insight.
Perception is when one imagination clashes with another

#9 JohnnyCode   Members   -  Reputation: 312

Like
0Likes
Like

Posted 01 August 2012 - 07:33 PM

With dx9 you can run at most pixel shader model 3.0. If you are fine with that, there is no strong reason for you to migrate. I myself am using a deffered renderer, that does not need higher shader model, for my shaders have few instructions but run very often before target is rendered. Actualy, with deffered rendering, your shaders are very strict but passes often. I have been thinking that I would need to move onto higher pixel shader model, but since I moved onto deffered rendring, I can do miracles without long shaders.

#10 Ingenu   Members   -  Reputation: 931

Like
0Likes
Like

Posted 02 August 2012 - 03:07 AM

Wrote a D3D8/9/10 GL2/3 engine years ago, and a GLES2/3+D3D11 one recently.
In both instances I decided to follow D3D10/11 API as it made the most sense, and like MJP I just include the right files for a given config to avoid virtuals.

The benefit of doing that over getting to a higher level of abstraction on top of the API is that I can write the abstraction layer for all of them at once, with very little API specific code.
(Of course if you want to write something that runs on all the API then you need to make sure that you use features common to them all.)

The only thing I've not taken care of is converting D3D11 HLSL to GLSL (seems to be the best way around as they carry more meaning than GLSL).
-* So many things to do, so little time to spend. *-

#11 L. Spiro   Crossbones+   -  Reputation: 14375

Like
0Likes
Like

Posted 02 August 2012 - 05:09 AM

With dx9 you can run at most pixel shader model 3.0. If you are fine with that, there is no strong reason for you to migrate.

Except the part of about being left behind and becoming obsolete.

The difference between DirectX 11 and DirectX 9 is far more than “shader model 3”.
DirectX 11 is better designed and provides vastly superior performance even without taking advantage of its extra features such as multi-threaded rendering. My engine functions equally in DirectX 9 and in DirectX 11, not taking advantage of any special feature of DirectX 11 to gain performance, and just with this it is literally twice as fast as DirectX 9.

Then of course you get more texture slots/stages/units in DirectX 11, you can read the depth buffer directly (without hacks), 8 simultaneous render targets instead of 4 and a more efficient pipeline allowing to actually use that extra transfer bandwidth.

Then of course geometry shaders to allow faster environment mapping (and a few other things), compute shaders to open up a world of who-knows-what to you, etc.
But I guess you don’t need that if you are fine with shader model 3.0.

Then there are features levels and guaranteed feature sets, instead of each individual feature being potentially unsupported causing you to have to write fall-back code everywhere.



Did I mention obsolete?
The future is DirectX 11. PC games are already heading there and the next generation of consoles will have same (Xbox 720 uses 64-bit DirectX 11) or similar-level custom API’s.



As for the original topic, I posted an article on the subject and explained a clean way to do this. Similar to what MJP proposed.
Organization for Multi-platform Support


L. Spiro
It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

#12 phantom   Moderators   -  Reputation: 7591

Like
1Likes
Like

Posted 02 August 2012 - 06:32 AM

since I moved onto deffered rendring, I can do miracles without long shaders.


And with regards to the state of the art you are behind the curve.

Most people are now refocusing to hybrid solutions such as those presented in AMD's Leo demo where deferred and forward lighting combine to give you the best of both worlds; many lights and complicated BRDFs with good performance.

Which uses DX11 features including higher Shader models and compute shaders.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS