Sign in to follow this  
Streamlet

How to set HLSL constant table without D3DX in D3D9

Recommended Posts

As the title

D3DXCompileShader is too slow.

IDirect3DDevice9::CreatePixelShader from .cso file works. But I still need to use IDirect3DPixelShader9::GetFunction?D3DXGetShaderConstantTable to get ID3DXConstantTable.

Since D3DX static library in Summer 2004 version is a little large, and later version will introduce dependency of d3dx9_xx.dll, is there any way to set HLSL constant table without D3DX in D3D9

Share this post


Link to post
Share on other sites

The HLSL constant table is at a much higher level of abstraction than is provided by the raw API: the constant table doesn't actually really "exist" at all in a shader.

 

In reality the D3DX stuff is just an elaborate software wrapper around:

 

float4 myConstant : register(c0); // HLSL declaration, this constant is using register 0

Device->SetVertexShaderConstantF (0, data, 1); // C++ code to set the constant

 

Where the "0" in SetVertexShaderConstantF matches the "c0" in the HLSL declaration, "data" is an array of 4 floats and "1" is the number of float4s to set.

 

When working without D3DX you need to forget about all of the helper infrastructure it builds around a shader and just do it this way instead.

Share this post


Link to post
Share on other sites

The HLSL constant table is at a much higher level of abstraction than is provided by the raw API: the constant table doesn't actually really "exist" at all in a shader.
 
In reality the D3DX stuff is just an elaborate software wrapper around:


float4 myConstant : register(c0); // HLSL declaration, this constant is using register 0

Device->SetVertexShaderConstantF (0, data, 1); // C++ code to set the constant

 
Where the "0" in SetVertexShaderConstantF matches the "c0" in the HLSL declaration, "data" is an array of 4 floats and "1" is the number of float4s to set.
 
When working without D3DX you need to forget about all of the helper infrastructure it builds around a shader and just do it this way instead.


Thank you very much. I will try it.
So, setting constant has nothing to do with the shader buffer?
Device->SetVertexShaderConstantF will directlt set the value to GPU register?

But another question:
What does the first parameter of D3DXGetShaderConstantTable do?
ID3DXConstantTable->SetFloat could be implemented like Device->SetVertexShaderConstantF, What is pFunction?
Why not modify D3DXGetShaderConstantTable to D3DXGetShaderConstantTable(IDirect3DDevice9 *, ID3DXConstantTable **)?

Share this post


Link to post
Share on other sites
another another question:

How to draw text without D3DX?
What does D3DXFont do?

I have an idea:

1, Create GDI bitmap;
2, Draw text by GDI; (draw onto white backgound and then onto black background to calculate alpha if neccessary)
3, Create D3D9 texture and copy the bits;
4, Draw the texture in D3D9, adjust the alignment by DT_*.

Will it be OK?

Share this post


Link to post
Share on other sites
That is essentially what D3DXFont does under the hood.

As an alternative, you can pre-generate a "font texture" that contains all of the glyphs that you need. You can then render your strings by drawing a one quad per character, with each quad having the appropriate texture coordinates for whichever character that they represent. There are even free tools available for generating these font textures:

https://github.com/andryblack/fontbuilder

http://www.angelcode.com/products/bmfont/

https://github.com/nothings/stb/blob/master/stb_truetype.h

Share this post


Link to post
Share on other sites

An alternative to dumping D3DX is to dynamically link to it instead.  For the most part the API remains the same, so your expectation should be that more recent versions of the D3DX DLLs primarily contain bugfixes and performance improvements.  With that in mind, your procedure is:

  • Begin a loop counting from 43 down to 24 (this is based on the D3DX DLLs on my own PC; 23 and below were the static library versions).
  • Construct the DLL name from loop counter: sprintf (dllname, "d3dx9_%i.dll", version);
  • Call LoadLibrary on it, if LoadLibrary fails then go to the next iteration (if there is no next iteration error out), otherwise continue.
  • Call GetProcAddress on the D3DX entry points you need to use using the HINSTANCE of the successfully loaded library.

There's a bit more work involved in this as you'll need to declare types for your GetProcAddress returns, but it will let your program be quite D3DX-version-agnostic, and is also future-proofed a little better in that you'll be able to successfully upgrade your project to newer versions of Visual Studio which don't come with the D3DX libs (and which may fail to compile when linking against the old SDKs).

Share this post


Link to post
Share on other sites

That is essentially what D3DXFont does under the hood.

As an alternative, you can pre-generate a "font texture" that contains all of the glyphs that you need. You can then render your strings by drawing a one quad per character, with each quad having the appropriate texture coordinates for whichever character that they represent. There are even free tools available for generating these font textures:

https://github.com/andryblack/fontbuilder

http://www.angelcode.com/products/bmfont/

https://github.com/nothings/stb/blob/master/stb_truetype.h


It seems to be a good method on English language. Unfortunately most of my target system is in Chinese language (zh-cn). It is not a simple task to render each character to textures. That's a too large collection.

Share this post


Link to post
Share on other sites

An alternative to dumping D3DX is to dynamically link to it instead.  For the most part the API remains the same, so your expectation should be that more recent versions of the D3DX DLLs primarily contain bugfixes and performance improvements.  With that in mind, your procedure is:

  • Begin a loop counting from 43 down to 24 (this is based on the D3DX DLLs on my own PC; 23 and below were the static library versions).
  • Construct the DLL name from loop counter: sprintf (dllname, "d3dx9_%i.dll", version);
  • Call LoadLibrary on it, if LoadLibrary fails then go to the next iteration (if there is no next iteration error out), otherwise continue.
  • Call GetProcAddress on the D3DX entry points you need to use using the HINSTANCE of the successfully loaded library.
There's a bit more work involved in this as you'll need to declare types for your GetProcAddress returns, but it will let your program be quite D3DX-version-agnostic, and is also future-proofed a little better in that you'll be able to successfully upgrade your project to newer versions of Visual Studio which don't come with the D3DX libs (and which may fail to compile when linking against the old SDKs).

 


d3d9_xx.dll does not exists in Windows XP SP3...

Share this post


Link to post
Share on other sites

d3d9_xx.dll does not exists in Windows XP SP3...

 

Options:

  • Instruct your users to update their DirectX, which will bring down them all.
  • Don't support XP.

Neither is unreasonable.

Edited by mhagain

Share this post


Link to post
Share on other sites

Given that D3DX has been deprecated, I would think for new development, the OP's time would be better spent going with the flow (DirectX Tool Kit, DirectXMath, D3DCompile), rather than finding ways to keep using it. Keeping a dependency to a deprecated and, in later versions obsolete, library won't make porting to newer versions of D3D any easier.

Edited by Dave Hunt

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this