Jump to content

  • Log In with Google      Sign In   
  • Create Account


Member Since 14 Feb 2007
Offline Last Active Private

Posts I've Made

In Topic: DXT Texture compression for DX11

Yesterday, 06:57 AM

Some links :)







At the moment, I'm using the NV texture tools library from C# to generate DXT-compressed DDS files.

In Topic: [D3D12] Multiple command queues

25 June 2016 - 06:45 PM

For future reference too, I couldn't find it at the time, but I guess the function for CPU-driven CPU->GPU copies on Intel/UMA GPUs is ID3D12Resource::WriteToSubresource.

In Topic: Mesh format?

25 June 2016 - 08:32 AM

Different shaders will use different vertex buffer layouts, and different input assembler layouts / vertex descriptors.


The file format is irrelevant at runtime except during loading. The most efficient format for loading is to use the exact same layout as the vertex buffers, so that you can simply memcpy the data into them.


Usually you have the artists export into a bloated interchange format such as FBX or DAE, and then write your own tool that extracts the necessary data and converts it into something very similar to what you'll be using at runtime, in your D3D/GL structures.

In Topic: Is there any reason to prefer procedural programming over OOP

24 June 2016 - 09:02 PM

Considering the amount of religious wars fought about what OO really means
No, you don't know what you are talking about.

My opinion was not that of my own.  I really don't care what its called, OO, procedural, imperative, all these definitions are useless as far as I'm concerned and just hinder things more than help.  Its what my professors and the books we used in school stated (yes I have a degree, no I don't think it matters).  Its a pretty common notion that OO without inheritance isn't 'true' OO.  Whether you agree or disagree, just shutting down dissenting opinions with nothing other than a 'you're wrong I'm right' isn't constructive.  State why OO doesn't need inheritance, or how OO without inheritance is still OO and not just procedural with structs (and I'm not implying those are the only arguments, or good ones at that).  In computer science the 'why' is always far more important that the 'what'.
and yet in true gamedev fashion yet another interesting conversation is shut down by the standard 'my way is the right way' argument.  I try... I really do try to get these posts to be more than a simple 'do X not Y' type conversation and to get into why we do what we do.  And yet time and time again I am repeatedly shut down for simply attempting a real conversation.  
I will refrain from posting in the future...

He was using a farcical extreme point of view in an attempt to poke fun at yours, and get you to critique a his caricature -- I guess he was trying to say that your point of view was extreme and provided without evidence - the critique you've just offered... Yes, not the most helpful posting style, but anyway...

It's also up to you to present some evidence as to why inheritance is a core pillar of OO, rather than just asserting that everyone knows this to be true. If you go an google "inheritance vs composition", you'll find endless articles warning against using inheritance as a default choice, including the wikipedia page on OO's rule of preferring composition over inheritance.
When I was taught OO in university, it was by someone who had not enough knowledge to be teaching it, yet who was held up as an expert by the local academia due to their industry experience... and when I first used OO in industry, it was among people who'd learnt the same garbage as me at university... a viscous cycle of popular misinformation.
The mnemonic to remember the core rules of OO (which I was not taught in school) is SOLID:

Inheritance and polymorphism are not listed. They are tools that you can use -- just like functions, structures, pointers -- but not the goal.
Many of the examples that we were given in school actually violate these rules -- e.g.

struct Square { float width; virtual float Area() const { return width*width; } };
struct Rectangle : Square { float height; virtual float Area() const { return width*height; }  };

This violates Liskov substitution, because there's algorithms that work on the base class (Square) which would be invalid for the derived class (Rectangle).
So maybe you rearrange it to:

struct Rectangle { 
  virtual void SetWidth(float); 
  virtual voidSetHeight(float); 
  float Area() const { return width*width; } };
struct Square : Rectangle { 
  virtual void SetWidth(float x) { Rectangle::SetWidth(x); Rectangle::SetHeight(x); }
  virtual void SetHeight(float y) { Rectangle::SetWidth(y); Rectangle::SetHeight(y); }

But this still violates Liskov substitution, as the derived type is forcing invariants onto the base type, again breaking algorithms that work on the base type if they're used with this derived type.

OO in school basically just teaches you *how* to use the tools in general, but nothing about *why* or *when* you should use them, or how they should be used correctly in real situations, or with real OO designs.
The greatest example of this is the exercises like "say we've got a dog and a cat, how would we represent them?" followed by the whiteboard code of:

class Animal {};
class Dog : public Animal {};
class Cat : public Animal {};

While that's fine in showing how to use the tool of inheritance, it's also complete nonsense. It's building a data model without a use case. What does the user of a 'Dog' object do? Are there any algorithms that have to work on both 'Dogs' and 'Cats'? What data do those algorithms need as inputs and outputs? Without this kind of information, you can't build a data model... yet in OO class, you often get exercises to build data models "of the real world" with no use case for them.

Do you have any examples?  Certainly most of the container classes seem very non-OO to me.  Vectors don't know how to iterate over themselves.  Rather, the algorithms to do things with vectors are kept at arms length and divorced from the containers.  That's not in the slightest how OO designs tend to work.  In fact, it's the complete opposite.  OO is about coupling code and data.  The C++ containers are all about decoupling code and data.  Much of the standard library following the STL stuff has followed a similar pattern.

std::vector is a great OO example of a well designed class!

It follows the SRP -- it just implements only the logic required for the vector container, and no other superfluous responsibilities such as for-each loops. They do know how to iterate over themselves though -- std::vector is a Container, and a Container has a member type named iterator, which is a ForwardIterator, which implements the increment(++) and dereference (*) operators. A Container has a begin and end method that return an iterator, which can be used to iterate over the container.
This is all perfect OO so far. On the other hand, if vector had a foreach member function, it would violate the rules of OO and be bad code™!
Vector meets Open/closed because it has a very stable public interface that declares exactly how it can be used while hiding the actual implementation entirely, yet can be easily extended by the user by substituting the template argument of the contained type, or composing it into larger objects, such as a std::stack< T, std::vector<T> >.
Vector meets Liskov substitution because it complies with the requirements of the many interfaces that it implements (Container, AllocatorAwareContainer, SequenceContainer , ContiguousContainer and ReversibleContainer) allowing algorithms designed to operate on those interfaces to work perfectly when a std::vector implementation is provided in their place.
Vector meets Interface Segregation because it itself doesn't require any knowledge of the algorithms that are performed on it, nor knowledge of the T type that it contains.
Vector meets Dependency Inversion because the high level T types and high level algorithms do not need to depend (or "know about") the vector itself. Instead, common interfaces are defined that both the high-level user code, and the low-level vector code both depend on.
e.g. vector doesn't need to know what T is, it just needs to know that T is a CopyAssignable and T is a CopyConstructible. High level code doesn't need to know that it's operating on a vector, it might just know that it's operating on a Container.


Vector also does some other neat things, such as using dependency injection to allow the user to construct it's internal allocator member themselves.
Note that throughout this, I've used is a in the OOD sense, not in the common OOP sense of "inherits from". In this particular case, Tvector and vector::iterator implement the mentioned interfaces via duck typing, not inheritance! This is the perfect example that OO is not about any one tool, such as inheritance. Again, inheritance is just a tool, but it's the concepts that make something "OO", not the use of certain tools.


This is also the proof that Ryan_001 just asked for -- std::vector implements many interfaces in true OO style, without the need to use inheritance.


So, if you think that std::vector is very non-OO, then chances are, your "OO" code is probably perfectly fine OOP code, but terrible OO. You should strive to make your code more like std::vector -- correctly complying with OO's SOLID rules.

In Topic: Job Based Rendering

24 June 2016 - 09:05 AM

What platforms are you targeting? PC and game consoles have got you covered. I'm not experienced with threaded resource creation on mobile, so I'm not sure there.


D3D11/12 is fine and Vulkan is fine. I assume metal is fine. OpenGL (do you really have a linux port?) also supports it, but in a very roundabout way. You've got to make a second GL context, and follow some very strict rules about which GL functions you ever call on the secondary context. You can use a mutex to share this second context among your threads. If you implement it right, the drivers will actually make use of their DMA controllers ("Copy queue" in d3d12 terms) and do fancy async uploads of your resource data. Sorry, I've forgotten where to find the info on how to do this properly though.


On D3D9, I actually just emulate free-threaded resource creation. I return a texture/buffer object back to the user immediately, but copy all the creation arguments (including initial pixel data) into a queue for the main/submit thread to execute later.


However... resource *creation* should be done ahead of time, not as part of the main rendering loop. You should only be updating data within resources that have already been created. Do you have a link to this method that you're copying?