News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Directx 9 last shot (at least for now)

Started by felipe, April 17, 2018, 04:50:01 AM

Previous topic - Next topic

jj2007

Quote from: aw27 on April 19, 2018, 08:12:29 PMSince you are not using macros you might be able to save a few bytes and cycles across repeated calls

Now you make me curious, José! How exactly can you save bytes, or gain speed, as compared to a coinvoke macro?

aw27

You save two instructions on a second call:

1st call
push    0                   ; push the parameters
push    FLT4(1.0)
push    BackgroundColor
push    D3DCLEAR_TARGET
push    NULL
push    0
mov     edi,g_pD3DDevice    ; load the com interface
push    edi                 ; push it
mov     ebx,[edi]           ; get the pointer from the interface pointer
call    dword ptr[ebx+IDirect3DDevice9_Clear] ; call the com interface method

2nd call
push    0                   ; push the parameters
push    FLT4(1.0)
push    BackgroundColor
push    D3DCLEAR_TARGET
push    NULL
push    0
; NOT NEEDED NOW mov     edi,g_pD3DDevice    ; load the com interface
push    edi                 ; push it
;NOT NEEDED NOW mov     ebx,[edi]           ; get the pointer from the interface pointer
call    dword ptr[ebx+IDirect3DDevice9_Clear] ; call the com interface method

jj2007

OK, I see. I've tested another example with my current CoInvoke macro:
pInterface equ esi
INT 3
CoInvoke pInterface, IWebBrowserVtbl.put_MenuBar, VARIANT_TRUE ; false = no menu
nops 4


This translates to:
int3
push 0FFFF                  ; VARIANT_TRUE
push esi                    ; pInterface
mov eax, [esi]
call near [eax+0C4]         ; method
nop


So, when using the interface a second time, one could save the mov eax, [esi] step and use once mov ebx, [esi] instead. That saves two bytes, but you need a non-volatile register like ebx, so two bytes for push+pop. Which means you can save two bytes each for the third, fourth, ... use of the interface. In short: You are right, one can save some bytes by coding this stuff by hand :t

Siekmanski

This technique is commonly used in the Demo scene to save bytes when coding size limited executables.
Group everything that's possible and use one pointer for the same interface.  8)
Creative coders use backward thinking techniques as a strategy.

Siekmanski

Not every COM model is the same.
ASIO audio COM interface wants the pointer from the interface pointer in ECX


    mov ecx,pASIO_Device
    mov ecx,[ecx]
    mov eax,[ecx]
    call dword ptr[eax+Function]
Creative coders use backward thinking techniques as a strategy.

felipe

I guess i understand what you say aw27, but my question still remains in this form:

;1st call
mov     edi,g_pD3DDevice    ; load the com interface
push    edi                 ; push it here because is not a parameter for this method.

push    0                   ; push the parameters
push    FLT4(1.0)
push    BackgroundColor
push    D3DCLEAR_TARGET
push    NULL
push    0

mov     ebx,[edi]           ; get the pointer from the interface pointer
call    dword ptr[ebx+IDirect3DDevice9_Clear] ; call the com interface method

;2nd call
; NOT NEEDED NOW mov     edi,g_pD3DDevice    ; load the com interface
;push    edi                 ; No need to push it here, if you don't trash the register.

push    0                   ; push the parameters
push    FLT4(1.0)
push    BackgroundColor
push    D3DCLEAR_TARGET
push    NULL
push    0

;NOT NEEDED NOW mov     ebx,[edi]           ; get the pointer from the interface pointer
call    dword ptr[ebx+IDirect3DDevice9_Clear] ; call the com interface method

Isn't this right? What i'm missing of the call to the methods here?

aw27

Quote
push it here because is not a parameter for this method.

No, no, you are not pushing it to preserve edi. You can do that elsewhere, in the beginning of the function for example, or don't preserve at all if you know what you are doing because it is a standalone ASM application not called from anywhere.

It is indeed a parameter for the method as you can see from the http://masm32.com/board/index.php?topic=7078.msg76110#msg76110
mov     eax,g_pD3DDevice    ; load the com interface
push    eax

I replaced eax with edi because I know that the call to the interface method will not corrupt edi since it has the obligation to preserve non-volatile registers.




felipe

It's a little confusing this  documentation from the directx 9 sdk (this method call as an example):

Quote
IDirect3DDevice9::BeginScene Method
Begins a scene.

Syntax
HRESULT BeginScene();

Parameters
This method has no parameters.
Return Value
HRESULT

And siekmanski code even confirm the no parameters for this method call:
Quote

; no parameters
    mov     eax,g_pD3DDevice    ; load the com interface
    push    eax                 ; push it
    mov     eax,[eax]           ; get the pointer from the interface pointer
    call    dword ptr[eax+IDirect3DDevice9_BeginScene] ; call the com interface method


And in this sdk documentation i haven't seen the pointer to the interface as a parameter yet in any method call. It's something only know to assembly language programmers  :biggrin:? I can't find the explanation of this in that link either. Thanks for all the help, seriously.  :greenclp:

felipe

Is something related to the headers file from the sdk? I'm not well versed in that idiom, but i have found lines like this (probably for every method):
Quote#define IDirect3D9_CreateDevice(p,a,b,c,d,e,f) (p)->lpVtbl->CreateDevice(p,a,b,c,d,e,f)
So that p is the pointer defined implicitly?

aw27

You need pass a "THIS" pointer, so you need as a minimum (according to my example, 2nd call):
push    edi                 ; push it
call    dword ptr[ebx+IDirect3DDevice9_BeginScene] ; call the com interface method

Have a look here and see if it makes some light. If not, keep trying this is not easy at all.


jj2007

Ernie explains lots of things. If you have less time, try Mysteries of COM 8)

daydreamer

I have seen Hitchhikers 1k demos in old forum, so to be able to save size I could make a minimum .inc file like that, so I could be able to post some real d3d9-11 game, so instead of having large lib files included in 512kb I have place for textures instead
but what about you initialize dx adresses to your .data section with most used first and least used last, the 20 most used


my none asm creations
https://masm32.com/board/index.php?topic=6937.msg74303#msg74303
I am an Invoker
"An Invoker is a mage who specializes in the manipulation of raw and elemental energies."
Like SIMD coding

felipe

 :greenclp: Now this comment:
Quote; get the pointer from the interface pointer
has finally perfectly sense to me.  :bgrin:

Quote from: jj2007 on April 20, 2018, 03:40:19 AM
Now one might ask the developers of COM why CoCreateInstance needs the address of a variable to deliver pInterface, instead of simply returning it in eax. The answer will be "it's by design" or "why do something simple if there is a more complicated way?". Redmond speaking... 8)

I was asking me the same from the article above. Well now, thanks to the genius programmers from the best forum in the world, it really doesn't matter. :greensml:

Siekmanski

I should have commented it like this,

    mov     eax,g_pD3DDevice    ; load the com interface
    push    eax                          ; push it
    mov     eax,[eax]                 ; get the vtable pointer from the interface pointer
    call      dword ptr[eax+IDirect3DDevice9_BeginScene]      ; call the com interface method function.
Creative coders use backward thinking techniques as a strategy.

Siekmanski

Hi daydreamer,
You have to set up the screen first and it delivers you the interface address in return.
Setting up the video device, same story etc.
No need to use CoCreateInstance in DX.
For the function Direct3DCreate9 there is no GUID available to get the interface address with CoCreateInstance.

QuoteI have seen Hitchhikers 1k demos in old forum, so to be able to save size I could make a minimum .inc file like that, so I could be able to post some real d3d9-11 game, so instead of having large lib files included in 512kb I have place for textures instead
but what about you initialize dx adresses to your .data section with most used first and least used last, the 20 most used

We don't use static libs anymore.
Do you trust Microsoft the addresses will be the same in next operating systems?
Creative coders use backward thinking techniques as a strategy.