Preferences about languages and graphics APIs.

Hi everyone,

Recently I watched some Handmade Hero episodes where Casey says that there is no more reason to Vulkan exists because we have D3D12 on Windows and Mac has its own library, Metal.

In some extent I agreed with that. But, there is something to consider here. D3D12 requires you to compile as C++, since we have to deal with the COM (Component Object Model) stuff and a lot of D3D12 functions requests a __uuidof(some type) parameter, which retrieves some GUID.

Personally, I don't like to compile as C++, even writing C in the cpp file, I don't know what the compiler can do behind my back. I know that Casey compiles as C++ but writes mostly C, and he knows what he is doing, and this is even something that I wanted to know also. Is there something wrong about that? Can optimization be affected?

So, considering someone who wants to use one of these modern graphics APIs, would want to compile as pure C code, without have to deal it the COM stuff, be a good reason to use Vulkan instead of D3D12?

I tried to compile D3D12 code in C and I always get that the __uuidof is C++ only.

Also, I want to start using Clang on Windows, and I'm not sure if there is this __uuidof stuff in Clang.

My point is... there are some options out there when it comes to graphics APIs. Personal development preferences, like programming languages and compilers, are good reasons to choose one over the other?

PS.: Sorry for any english grammar mistake.

Edited by Leonardo on
You can use D3D12 from C, here's an example project on Github.

You don't need the __uuidof() macro, you can find declarations for the ids in the D3D12 header files, e.g.
1
EXTERN_C const IID IID_ID3D12Object;
Wow!

Ok... this is awesome.

I searched for D3D12 on github but I didn't find this repository.

Thanks man!
maverick1013
D3D12 requires you to compile as C++, since we have to deal with the COM (Component Object Model) stuff

This is not true. Any Microsoft COM stuff compiles as C code. This is by design. This includes D3D9, D3D11, D3D12 and all other COM API's.

COM declarations always generate code that works for both C and C++ code.

For example if in C++ you need to do this:
1
2
IObject* obj;
obj->Call(arg1);


Then in C you need to do this:
1
2
IObject* obj;
obj->vtbl->Call(obj, arg1);


This works for all COM classes.

It gets even better. If you do #define COBJMACROS before any of windows includes, then you get access to nice C macros, which you use like this:
1
2
IObject* obj;
IObject_Call(obj, arg1);


For IID/CLSID stuff - as marcc already said - they all are available in header files. That's also standard COM stuff, nothing special for D3D12.
Sometimes though the IID's are only declared, and do not have corresponding static .lib library to link to. No idea why they do that, but you can fix it by including <initguid.h> header file as first include (before any windows header). This will make all IID_* variables to be defined in header files, not only declared.

Clang supports __uuidof just fine (in C++ mode).
Yeah, I was reading about COM on MSDN. Found about the ->lpVtbl->. When following Handmade Hero, in the beginning, where we initialize DirectSound, I did everything in pure C. DirectSound functions also requires this virtual table of functions, so I assume that DirectSound is also part of the COM, as well as Xaudio2. This answers all my questions. Thanks guys!

Edited by Leonardo on
Anything that inherits IUnknown is COM. You can check that it in headerfiles or in MSDN docs if they inherit IUnknown. Which provides QueryInterface/AddRef/Release methods.
Hey guys,

I'm not able to use any IID_ID3D12***** GUID in any function that requires one.

NOTE: Any EXTERN_C bellow doesn't work in a unity build project. It expands to extern when compiling in C. I removed the EXTERN_C's
and it works.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// In d3d12sdklayers.h...

EXTERN_C const IID IID_ID3D12Debug;

DEFINE_GUID(IID_ID3D12Debug,0x344488b7,0x6846,0x474b,0xb9,0x89,0xf0,0x27,0x44,0x82,0x45,0xe0);

.   .   .

// In guiddef.h

typedef struct _GUID {
    unsigned long  Data1;
    unsigned short Data2;
    unsigned short Data3;
    unsigned char  Data4[ 8 ];
} GUID;

typedef GUID IID;

#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
    EXTERN_C const GUID FAR name

.   .   .


HRESULT dx_result;
ID3D12Debug* debug_interface;

dx_result = D3D12GetDebugInterface(&IID_ID3D12Debug, (void**)&debug_interface);
if(SUCCEEDED(dx_result))
{
  debug_interface->lpVtbl->EnableDebugLayer(debug_interface);
}


The function D3D12GetDebugInterface fails and debug_interface becomes NULL.
I'm assuming it is because this values defined at DEFINE_GUID does not get into the struct GUID, probably.
These are all the definitions I found.
Does any one knows why this is happening? Why the function fails?

Thanks for everything for now!

Edited by Leonardo on
You missed this part in my reply above:

Sometimes though the IID's are only declared, and do not have corresponding static .lib library to link to. No idea why they do that, but you can fix it by including <initguid.h> header file as first include (before any windows header). This will make all IID_* variables to be defined in header files, not only declared.


Either link to static lib where this GUID is (dxguid.lib) or do #include <initguid.h> as first header.
Do not edit header files in Windows SDK, that does not make sense.

Edited by Mārtiņš Možeiko on
Ohh that's right. I missed this part. Thanks again! Now everything is working fine.

Oh I'm not editing the Windows header files, I'm cuting and pasting the things I need from them. In the case of EXTERN_C I just didn't defined it.

Actually... this is a topic for another thread, avoiding including the Windows.h and any other header, as Casey saids right in the beginning of Handmade Hero, in the Intro to C actually. I'm doing that. It's going perfectly for know, with one exception: I not defining the SAL Annotations stuff, like _In_, _Out_, etc. I just can't get it working on Clang, don't know why. For now I'm just ignoring it and assuming that it's just for the sake of readability, but maybe I completely wrong. Am I? Can the SAL stuff affect how to compiler generates code?

This process is a little bit tough to start but once it gets working, it becomes easier to do. For now, I don't know if it's worth it, but what I can tell is that the compilation time is noticeable faster and the preprocessor output is muuuchhh smaller, it gots only the things actually needed. (compiling with /P option generates a file that is the actual preprocessor output.)

Edited by Leonardo on
Wow!

Just saw that you talked about the same thing here, mmozeiko.

What a coincidence!

Edited by Leonardo on
SAL annotations are defined in sal.h file. windows.h includes it, that's why it works with clang. If you are copy&pasting declarations from windows headers to your own files, you'll need to fix them or copy & paste SAL declarations from sal.h file. If you don't enable SAL analysis, then all these definitions define to nothing / empty token.
maverick1013
Hi everyone,

Recently I watched some Handmade Hero episodes where Casey says that there is no more reason to Vulkan exists because we have D3D12 on Windows and Mac has its own library, Metal.


Does D3D12 compiles on linux? Does it run in Android? Does it run in MacOs?

If doesn't. No. Thanks. I will keep GL/Vulkan.
You need to take into account the context where that was said.
It was about shipping desktop games. Where is the market for desktop games? Windows. And a bit of Mac. Thus the D3D and Metal. Not sure why not having D3D on macOS is an issue for you. macOS has it's own GPU api called Metal. Vulkan does not exist on macOS (except as a wrapper around Metal).

Edited by Mārtiņš Možeiko on