DX10 : change the sampler variable in the shader from the app

Started by
8 comments, last by Jalibr 16 years, 1 month ago
Hi there, i used the search but did not see anything that could help me right now i have a shader with a samplerstate in it SamplerState samLinear { Filter = MIN_MAG_MIP_LINEAR; AddressU = Wrap; AddressV = Wrap; }; and i call the sampler in the PS like this return diffuse_text.Sample( samLinear, input.uv ); i also have some other variables and textures in the shader like this Texture2D diffuse_text; and i can change this texture2d from the application in run-time with ID3D10EffectShaderResourceVariable* diffuse_text_variable =dx10_effect->GetVariableByName("diffuse_text")->AsShaderResource(); diffuse_text_variable->SetResource((ID3D10ShaderResourceView *) material.diffuse_texture); when trying to change the sampler i do this ID3D10EffectSamplerVariable *sampler = dx10_effect->GetVariableByName("samLinear")->AsSampler(); so now i have a pointer to the shader sampler and i can know it´s structure but don´t see any methods to change the sampler variable with another sampler state (ID3D10SamplerState), which i´ve already created. Any ideas??? thanks
Advertisement
Have you tried with ID3D10EffectVariable::SetRawValue()?
Unfortunately, we don't have any way to do this in Effects10, but we do allow you to change the state block inside of the effect by using variables to set the individual states. Note that this isn't terribly performant, since if any variables referred to in the state block change, we have to create a new state block object.

We do know this is a problem though, we can't fix it in Effects10 without a QFE, since the runtime is part of windows, but we're looking at fixing this in the next revision of Effects.
To XVincentX: yep, i tried with no good results

To Jalibr:

Could you give me a simple example to show me what you´re saying?? i´m afraid i´m new into DX10 and haven´t got all the knowledge i would like to have about it. How can i change a state block with a shader variable??

i also was reading about ID3D10Device::PSSetSamplers and how to set a set of samplers in the PS with this function, but i have no idea of how to use them later in the Shader because as far as i know in this code

return diffuse_text.Sample( samLinear, input.uv );

i have to pass the sampler variable as the first parameter. How can i pass a sampler set by ID3D10Device::PSSetSamplers to the diffuse_text.Sample function????

sorry if some of these questions are obvious, but as i said i´m new in DX10

thanks in advance

edit: having an "if" type statement in the PS to know which sampler to use would be very expensive in terms of performance???

edit2: i also found this -> http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=844986&SiteID=1 which maybe works for me if each slot is represented by a sampler variable and changing the slot is changing the sampler variable. I´ll give it a try.
Quote:Original post by a24710
Could you give me a simple example to show me what you´re saying?? i´m afraid i´m new into DX10 and haven´t got all the knowledge i would like to have about it. How can i change a state block with a shader variable??

You can't. The best you can do is call ID3D10SamplerState::GetDesc() to get the description for a particular sampler. Then, modify that description and create a new sampler using ID3D10Device::CreateSamplerState(). Once you've done that, you need to circumvent the Effects framework and manually set your newly created custom sampler state. I'm not exactly sure how you'd do that, though. But it'd involve modifying the device (probably with a call to ID3D10Device::PSSetSamplers()) after you've called ID3D10EffectPass::Apply().

But, as Jalibr mentioned, this isn't going to be very fast. The Effects framework isn't perfect. There are a few holes here and there, particularly in regards to retrieving/modifying states in the shaders. I recently ran into this problem myself:
http://www.gamedev.net/community/forums/topic.asp?topic_id=480424
NextWar: The Quest for Earth available now for Windows Phone 7.
all my samplers are created at loading time, what i want is to change which one is active whenever i want

doing a little more research, i think that the correct method is the one which is showed in the link i posted above

use the ID3D10Device::PSSetSamplers() after ID3D10EffectPass::Apply()

the main problem with that is knowing which slot is being used by every sampler variable, or blender variables or whatever variables. But the link gives a method to do that, although it´s a little complex

as you said in your link, it´s a little strange and not elegant, but dude, that´s what we´ve got right now :)

as i said before i´m new to DX10 and i like it a lot, but it would be nice to be able to change these things through the effects interface. i´m looking forward to the next revision

here is some code i wrote to know which input slot is used by the sampler variable "samLinear", i took out some things of the original code to make it a little easier to read, so don´t expect it to compile. Also it´s not 100% correct, but it´s ok to get the general idea

unsigned int slot_index;
D3D10_TECHNIQUE_DESC tech_desc;
ID3D10EffectTechnique *et = dx10_effect->GetTechniqueByName("Render");
et->GetDesc(&tech_desc);

for (unsigned int i=0; i<tech_desc.Passes; i++)
{
ID3D10ShaderReflection *shader_reflection;
D3D10_PASS_SHADER_DESC psd;
D3D10_EFFECT_SHADER_DESC esd;
D3D10_SHADER_DESC sd;
D3D10_SHADER_INPUT_BIND_DESC sibd;

et->GetPassByIndex(i)->GetPixelShaderDesc(&psd);
psd.pShaderVariable->GetShaderDesc(0, &esd);

HRESULT hr = D3D10ReflectShader(esd.pBytecode, esd.BytecodeLength, &shader_reflection);

if (FAILED(hr))
return false;

shader_reflection->GetDesc(&sd);

for (unsigned int j=0; j<sd.BoundResources; j++)
{
std::string variable_name;
shader_reflection->GetResourceBindingDesc(j, &sibd);
variable_name = sibd.Name;

if (variable_name == std::string("samLinear"))
{
slot_index = sibd.BindPoint;
}
}
}



so that´s how to know which input_slot is samLinear using, so i guess i can call now to ID3D10Device::PSSetSamplers and put the samplers in their correct input slots

what do you think???
To do this from within effects, you would do:

cbuffer sampler_states
{
uint sampler_filter;
};

sampler MySampler
{
Filter = <sampler_filter>;
};

Then effects would propagate any changes to sampler states that you want to make into the sampler object. You can do this for any of the sampler states you're interested in. The reason I put it in its own cbuffer is to ensure that these variables are only used in the sampler objects, since there is some overhead to adding these to a constant buffer that's actually used in the shader.
your method is clearly easier to implement

the code i wrote in the previous message just executes once after the effect creation, so no speed penalty occurs

in every frame, which method is faster???? to call ID3D10Device::PSSetSamplers() and set the previously created samplers or to update the sampler variables???





Well, presumably you won't be changing your sampler settings every frame, otherwise that might suggest you should actually be using a different technique, which will avoid the extra creates happening at runtime (creates are considered a "low frequency" event in DX10, and are considerably more costly in terms of API overhead than sets).

In the case where nothing is changing, doing it from within Effects will be faster, since you will avoid the overhead of hitting the API twice for that sampler state. If it really is changing every frame, then overriding Effects' settings will be faster.

This topic is closed to new replies.

Advertisement