Jump to content
  • Advertisement
Sign in to follow this  
MysteryX

ConstantTable Doesn't Follow when Switching Pixel Shaders

This topic is 1069 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have this code that instantiate pixel shaders. I'll call it 3 times to load 3 different pixel shaders. When rendering each scene, I call SetPixelShader with the pixel shader that I need.

HRESULT D3D9RenderImpl::InitPixelShader(CommandStruct* cmd, IScriptEnvironment* env) {
	ShaderItem* Shader = &m_Shaders[cmd->CommandIndex];
	CComPtr<ID3DXBuffer> code;
	unsigned char* ShaderBuf = NULL;
	DWORD* CodeBuffer = NULL;

	if (cmd->ShaderModel == NULL || cmd->ShaderModel[0] == '\0') {
		// Precompiled shader
		ShaderBuf = ReadBinaryFile(cmd->Path);
		if (ShaderBuf == NULL)
			return E_FAIL;
		HR(D3DXGetShaderConstantTable((DWORD*)ShaderBuf, &Shader->ConstantTable));
		// HR(D3DXGetShaderConstantTableEx((DWORD*)ShaderBuf, D3DXCONSTTABLE_LARGEADDRESSAWARE, &Shader->ConstantTable));
		CodeBuffer = (DWORD*)ShaderBuf;
	}
	else {
		// Compile HLSL shader code
		HR(D3DXCompileShaderFromFile(cmd->Path, NULL, NULL, cmd->EntryPoint, cmd->ShaderModel, 0, &code, NULL, &Shader->ConstantTable));
		CodeBuffer = (DWORD*)code->GetBufferPointer();
	}

	HR(m_pDevice->CreatePixelShader(CodeBuffer, &Shader->Shader))

	if (ShaderBuf != NULL)
		free(ShaderBuf);
	return S_OK;
}

Now here's the problem. All 3 pixel shaders are running with the last ConstantTable! Which means the 2 first ones aren't being configured right. Since the ConstantTable is directly associated with the PixelShader instance, I assumed it would automatically switch the ConstantTable when I call SetPixelShader. That's not the case.

 

How can I handle my various instances of Pixel Shaders to also keep their respective configurations?

Share this post


Link to post
Share on other sites
Advertisement
Sorry, I overlooked the fact that you use D3D9. Constant buffers are D3D10+ feature.

I would check the logic with which you store the constant table references. Trivially, you can check if the constant table addresses are same. If the three pixel shaders differ significantly, you should get three significantly different constant tables.

Note that if the shaders use the same constant set, the constant table contents can effectively be same, but the tables still reside in their own addresses.

Share this post


Link to post
Share on other sites

D3DXGetShaderConstantTable needs to be called for each pixel shader, and I checked: it returns different addresses and I keep all 3 references. You might execute any number of pixel shaders with various configurations.

 

I configure all constant tables one at a time, and at the end of the day, after calling SetPixelShader on the desired shader for the current pass, only the constant table that was configured last takes effect.

Share this post


Link to post
Share on other sites

Constant tables are merely a mechanism for setting shader constants given symbolic constant names. A constant table does not remember what constants have been set through it.

Share this post


Link to post
Share on other sites

That still doesn't answer the question. When I set the constants, it fills a memory buffer (container) with configuration values (content).

 

I need to either

A) Have several containers and switch the device to the right one when needed.

B) Have one container and set its content when needed.

 

Which of these 2 approaches should I look for? Right now I'm re-parsing and re-setting the values into the last constant table when processing each scene. It is not ideal but it "works".

 

I might be running 3 shaders over each frame of a video. In which case, there are 3 sets of configurations, and these same configurations will remain the same for every frame that needs processing.

Edited by MysteryX

Share this post


Link to post
Share on other sites

Question: How does DirectX9 decide which ConstantTable it is using? It doesn't have any reference to it except through the shader. The only link to the ConstantTable is by calling D3DXGetShaderConstantTable on the shader, and that function has no reference to the device. Other than that, the only reference is when setting parameter values, it requires a pointer to the device.

 

Another question. Where does the ConstantTable reside to begin with, and when is it created? D3DXGetShaderConstantTable doesn't take the Shader object but rather its raw memory address, which indicates that it returns a pointer to an address space within the shader code itself. Thus, the ConstantTable is created when loading the shader file, and then we just get the pointer to it.

 

I'm reviewing my code. All the shaders get configured properly. At this point, none is set on the device.

 

Then when creating the scene, I call SetPixelShader. If the ConstantTable really is contained within the shader code, I would expect it to take that constant table. Instead, it takes the last ConstantTable created. How does the device even know which one got previously created? The only way it could even know is when calling LPD3DXCONSTANTTABLE->SetVector, which takes the device as a parameter.

 

This is kind of screwed up. Is my logic flawed somewhere in the process? If so, how can that be solved?

Share this post


Link to post
Share on other sites

Constant table is just a map of shader symbols to their corresponding registers. It, by itself does not remember the values you set through it at all. When you call Set* on the interface, the implementation will call Set*ShaderConstants immediately on the associated device, by using its map to determine which constant registers correspond to the symbolic constant name you give to it.

 

The point is, the buffer of the constant table is not a buffer of the constant values you set through it - the buffer just holds the mapping between constant registers and constant names (and the default values).

Edited by Nik02

Share this post


Link to post
Share on other sites
I'm not sure I'm on the same tree here, but whenever I call device->SetPixelShader or device->SetVertexShader, I follow it with a call to SetDefaults, e.g:

void GraphicsDevice::setVertexShader(VertexShader &shader)
{
    if(currentVertexShader != &shader)
    {
        currentVertexShader = &shader;

        device->SetVertexShader(shader.getVertexShader());
        shader.getConstantTable()->SetDefaults(device);
    }
}

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!