News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

VC++ Directx Calling Pattern

Started by Fredericvo, April 16, 2012, 02:30:39 PM

Previous topic - Next topic

Fredericvo

Hello,

I've been looking at a lot of compiler generated DirectX code lately as I'm interested in how things work under the hood.
The usual call pattern to a DX function will be something like this

mov   edx, D[?v_buffer@@3PAUIDirect3DVertexBuffer9@@A] ; v_buffer
mov   eax, D[edx]
mov   ecx, D[?v_buffer@@3PAUIDirect3DVertexBuffer9@@A] ; v_buffer (no again, really?)
push   ecx
mov   edx, D[eax+48] ; offset to actual function in what I assume is a vtable for a vertexbuffer object (C++)
call   edx

What immediately caught my eye was how memory was referenced twice rather than doing something like this:

mov   edx, D[?v_buffer@@3PAUIDirect3DVertexBuffer9@@A] ; v_buffer (mem only referenced once)
push   edx
mov   eax, D[edx]
mov   edx, D[eax+48]
call   edx

I understand that it might have to do with parallelism and super-scalarity but to the point of loading more often from memory (even if, granted,  from L1 cache) and spilling one more register? Optimisation is truly the hardest thing in the world. LOL

zemtex

If the compiler is doing that, it means it is up to something. A compiler will not output anything random. Maybe it is preparing the next call and filling in gaps in the pipeline as well. Who knows what "Harry" is up to, the guy who wrote the compiler. He is an evil office rat, and he have high blood pressure too  :lol
I have been puzzling with lego bricks all my life. I know how to do this. When Peter, at age 6 is competing with me, I find it extremely neccessary to show him that I can puzzle bricks better than him, because he is so damn talented that all that is called rational has gone haywire.

dedndave

my guess is that it's using a standard "template" for that function
in other cases, the 2 values may be different
it just so happens that, the way you are using it, they are the same

qWord

Quote from: Fredericvo on April 16, 2012, 02:30:39 PMWhat immediately caught my eye was how memory was referenced twice rather than doing something like this:
most compilers have options for optimization - do you use them?
FPU in a trice: SmplMath
It's that simple!

baltoro

FREDERICVO,
I used to do DirectX programming in Visual Studio (C++). The Vertex Buffers for your 3D Mesh objects are used both from the perspective of writing the coordinate data to the Vertex Buffer and then providing the address of the Vertex Buffer to a DirectX rendering function call,...for example, to draw a 3D mesh using the Vertex Buffer to read the list of vertex data and attributes to the drawing function. The Vertex Buffers are always locked when writing data into them (a Vertex Buffer, as you probably know, is allocated memory for the vertex data) to prevent corruption of the data when the DirectX subsystem is either altering the data (when a perspective or view matrix multiplication transforms the data for the next scene), or, when actually reading the vertex buffer data for a drawing call. And, because, DirectX derives its speed from directly accessing the graphics hardware, I think the address of the Vertex Buffer is supplied to the graphics driver. Seems like I read this somewhere,...but, it may depend on the capabilities of the graphics card, or the graphics subsystem configuration,...
Here is a general overview of: Direct3D Vertex Buffers
You might find this interesting: ID3DXBaseMesh::LockVertexBuffer method
Baltoro

Farabi

Talking about DirectX, it was twice as fast as OpenGL, but it doesnot support C Interface, if only it use C interface, I rather to use DirectX.
Those who had universe knowledges can control the world by a micro processor.
http://www.wix.com/farabio/firstpage

"Etos siperi elegi"

vanjast

That looks like it might be a 'callback pointer' with parameters to indicate unlocking/cleanups

dedndave

man, we are all over the place on this one   :P

Fredericvo

Quote from: qWord on April 16, 2012, 06:30:06 PM
Quote from: Fredericvo on April 16, 2012, 02:30:39 PMWhat immediately caught my eye was how memory was referenced twice rather than doing something like this:
most compilers have options for optimization - do you use them?


As a matter of fact, since I used the CMD-line to get the ASM output I didn't have them on.
My optimisation was close but not totally correct:

using  /O2 I got this

mov   eax, DWORD PTR ?d3ddev@@3PAUIDirect3DDevice9@@A ; d3ddev
        ; I had put the push here...
   mov   ecx, DWORD PTR [eax] ; get pointer to instance of object
   mov   edx, DWORD PTR [ecx+168] ; get pointer to function in vtable
   push   eax ; ...but the optimisation puts it here
   call   edx ; and call it


qWord

Quote from: Fredericvo on April 17, 2012, 04:41:14 PMpush   eax ; ...but the optimisation puts it here
the position of the push doesn't matter: for both positions the CPU must wait for the data bus.
FPU in a trice: SmplMath
It's that simple!

Fredericvo

Quote from: Farabi on April 17, 2012, 06:12:11 AM
Talking about DirectX, it was twice as fast as OpenGL, but it doesnot support C Interface, if only it use C interface, I rather to use DirectX.

I know what you mean but even though I'm more of a C coder than a C++ one I simply compile it as a C++ program for DX's requirements but code mostly procedurally in C.
After all it isn't all that hard to type something like v_buf->Release(); rather than, say, VBufferRelease(&v_buf); if it existed like that. Oh that and matrix multiplication. I kind of succumbed to the C++ operator overload ease of doing MatC = MatA * MatB;
But if I wrote an entire game like that I think I'd be tempted to make sure it's all SSE in the end. I would not release ASM code I didn't entirely check LOL.