when do you load new shaders?

Started by
9 comments, last by dave 7 years, 10 months ago

I'm a hobbyist learning DirectX. I'm using C# with SharpDX. I'm a strong developer, pretty good with the graphics and math but still wrapping my brain around how to use the shaders and the order of things.

I'm not clear on when you are supposed to load a new shader.

lets say I have two boxes, each with different texture (from a bitmap for example)

I see that I can load the texture into the card and I see how its referenced in the shader.

I also see how you can load multiple textures into the card and refer to them in the shaders.

However, what's the flow for having the shader pick one texture vs. another?

A related question is that I see how rich the shader coding world is. Does a typical design use different shader code for different objects? If I have one shiny object, one thing that is water, and something else that has a matte finish these would seem to be different shaders. Is the rendering flow to 'load shader for object/draw object'?

thanks,

john

Advertisement
However, what's the flow for having the shader pick one texture vs. another?

A shader does not directly use a given texture. A shader has a slot or binding point, to which you can assign any texture you want, in your application code. Note that you don't actually bind the textures to the shader, but rather to the device (so if you change shaders, the texture still stay bound).


Texture2D BoundByApplication;


float4 pixel = BoundByApplication.Sample(Sampler, vTexCoords); 

As to how this is done, each shader stage (vertex, pixel, ...) has its own binding points, and you can assign a "shader resource view" generated from the texture-object to that. For SharpDX, have a look at this code:

https://gist.github.com/axefrog/b51b4e149c329608eae6

Line 145, SetShaderResource(slot, resource). This should give you the right idea.

Thank you, that helps.

How do you deal with shaders that might have different hlsl code? If cube 1 is shiny and cube 2 is flat that would require different shaders, correct? Can you load multiple shader code, or do you do that? Its really a workflow question, how do you manage it when there are a lot of shaders? Do you load each one before calling draw?
How do you deal with shaders that might have different hlsl code? If cube 1 is shiny and cube 2 is flat that would require different shaders, correct? Can you load multiple shader code, or do you do that? Its really a workflow question, how do you manage it when there are a lot of shaders? Do you load each one before calling draw?

Okay, so for your question: Yes, you can load as many shaders as you want. You usually do this at load-up time, doing it before drawing would be ungodly aweful for performance.

Shaders are just like textures, they are resources being bound to the device. So you load & compile the shader once, and for each object that needs a certain shader, you bind this shader before drawing.

Perfect, thank you! It's hard to see the forest for the trees when you are learning

Ok, I got that and immediately my head started swimming again. I see how shaders can select textures and how the shaders are loaded into a slot. How do you bind to a particular shader when you draw? Is it the call to SetVertexBuffers?

thanks,

john

Ok, I got that and immediately my head started swimming again. I see how shaders can select textures and how the shaders are loaded into a slot. How do you bind to a particular shader when you draw? Is it the call to SetVertexBuffers?

What do you mean by "how do you bind to a particular shader"? As I explained, you don't. You bind all types of resources (shader, textures, vertexbuffer), ... to the device, which acts like a state-machine. And then when you draw, the GPU executes the shader with all the other resources that are currently bound as input :)

Thank you for your patience. I don't have a clear picture in my head of the relationship between the slots, the shader code and which shader code will be called for a given call to Draw(). I've been looking through the sample code to try to connect the dots. I see these calls on the device context. Are these calls where the current shaders are set?

DeviceContext.VertexShader.Set(VertexShader);
DeviceContext.PixelShader.Set(PixelShader);

If this is how the shader code is set, would I use VertexShader_ONE and VertexShader_TWO like this?

// Set the first shader

DeviceContext.VertexShader.Set(VertexShader_ONE);

// Draw the first shape

DeviceContext.Draw(Shape1Triangle)

// Set the second shader

DeviceContext.VertexShader.Set(VertexShader_TWO);

// Draw the second shape

DeviceContext.Draw(Shape2Triangle)

John

Yep thats basically it.

The cost of switching shaders like this is generally non-free so be wary of doing thousands of shader switches per frame. It's best to batch them, for example.

Thank you! This suggests that a render loop should be based on the shaders first. Although a shader is a property of a mesh you should think about it in terms of meshes being a list associated with the shader, like this:

foreach (shader s in ListOfShaders) {

s.SetAsCurrentShader();

foreach (Mesh m in s.ListOfMeshes) {

m.Draw();

}

}

This topic is closed to new replies.

Advertisement