Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Metal: Do I need multiple RenderPipelines to have multiple shaders?

I am very new to metal so bear with me as I am transitioning from the ugly state machine calls of OpenGL to modern graphics frameworks. I really want to make sure I understand how everything works and works together.

I have read most of Apples documentation but it does a better job describing the function of individual components than how they come together.

I am trying to understand essentially whether I should have multiple renderPipelines and renderEncoders are needed in my situation.

To describe my pipeline at a high level here is what goes on:

  1. Retrieve the previous frame's contents from an offscreen texture that was rendered to and draw some new contents onto it.
  2. Swith to rendering on the screen. Draw the texture from step 1 to the screen.
  3. Do some post processing (in native resolution).
  4. Draw the UI ontop as quads. (essentailly a repeat of 2)

So in essence there will be the following vertex/fragment shader pairs

  • Draw the entities (step 1)
  • Draw quads on a specefied area (step 2 and 4)
  • Post processing shader 1 (step 3) uses different inputs than D and cant be done in the same shader
  • Post processing shader 2 (step 3) uses different inputs than C and can't be done in the same shader

There will be the following texture groups

  • Texture for each UI element
  • Texture for the offscreen drawing done in step 1
  • Potentially more offscreen textures will be used in post processing depening on metals preformance

Ultimately my confusions are this:

  • Q1. Render Pipelines take only one vertex and one fragment function so does this mean I need have 4 render pipelines even though I only have 3 unique steps to my drawing procedure?
  • Q2. How am I supposed to use multiple pipelines in one encoder? Wouldn't each sucessive call on .setRenderPipelineState override the previous one?
  • Q3. Would you recommend keeping all of my .setFragmentTexture calls right after creating my encoder or do I need to set those only right before they are needed.
  • Q4. Is it valid to keep my depthState constant even as I switch between pipelineStates? How do I ensure that my entities on step 1 are rendered with depth but make sure depth information is lost between frames so entities are all on top of the previous contents?
  • Q5. What do I do with render step 3 where I have two post processing steps? Do those have to be seperate pipelines?
  • Q6. How can I efficiently build my pipeline knowing that steps 2 and 4 are essentially the same just with different inputs?

I guess it would help me if someone would walk me through what renderPipelineObjects I will need and for what. It would also be useful to understand what some of the renderCommandEncoder commands might look like at a psuedocode level.

like image 337
J.Doe Avatar asked Nov 24 '17 07:11

J.Doe


People also ask

Can you use multiple shaders?

You can have as many shader objects (shaders loaded into memory and compiled) as you want; only one can be bound (active) at a time.

What is a shader pipeline?

A Shader is a user-defined program designed to run on some stage of a graphics processor. Shaders provide the code for certain programmable stages of the rendering pipeline. They can also be used in a slightly more limited form for general, on-GPU computation.

Why the process in rendering pipeline need a buffer?

The stencil buffer is used to control how pixels are rendered to achieve different effects such as masking.

What is rendering pipeline in game programming?

The rendering pipeline is the process by which images are prepared and output onto the screen. The graphics rendering pipeline takes the 3D objects built from primitives described using vertices, applies processing, calculates the fragments and renders them on the 2D screen as pixels.


1 Answers

Q1. Render Pipelines take only one vertex and one fragment function so does this mean I need have 4 render pipelines even though I only have 3 unique steps to my drawing procedure?

If there are 4 unique combinations of shader functions, then it's not correct that you "only have 3 unique steps to my drawing procedure". In any case, yes, you need a separate render pipeline state object for each unique combination of shader functions (as well as for any other attribute of the render pipeline state descriptor that you need to change).

Q2. How am I supposed to use multiple pipelines in one encoder? Wouldn't each sucessive call on .setRenderPipelineState override the previous one?

When you send a draw method to the render command encoder, that draw command is encoded with all of the relevant current state and written to the command buffer. If you later change the render pipeline state associated with the encoder that doesn't affect previously-encoded commands, it only affects subsequently-encoded commands.

Q3. Would you recommend keeping all of my .setFragmentTexture calls right after creating my encoder or do I need to set those only right before they are needed.

You only need to set them before the draw command that uses them is encoded. Beyond that, it doesn't much matter when you set them. I'd do whatever makes for the clearest, most readable code.

Q4. Is it valid to keep my depthState constant even as I switch between pipelineStates?

Yes, or there wouldn't be separate methods to set them independently. There would be a method to set both.

How do I ensure that my entities on step 1 are rendered with depth but make sure depth information is lost between frames so entities are all on top of the previous contents?

Configure the loadAction for the depth attachment in the render pass descriptor to clear with an appropriate value (e.g. 1.0). If you're using multiple render command encoders, only do this for the first one, of course. Likewise, the render pass descriptor of the last (or only) render command encoder can/should use a storeAction of .dontCare.

Q5. What do I do with render step 3 where I have two post processing steps? Do those have to be seperate pipelines?

Well, the description of your scenario is kind of vague. But, if you want to use a different shader function, then, yes, you need to use a different render pipeline state object.

Q6. How can I efficiently build my pipeline knowing that steps 2 and 4 are essentially the same just with different inputs?

Again, your description is entirely too vague to know how to answer this. In what ways are those steps the same? In what ways are they different? What do you mean about different inputs?

In any case, just do what seems like the simplest, most direct way even if it seems like it might be inefficient. Worry about optimizations later. When that time comes, open a new question and show your actual working code and ask specifically about that.

like image 156
Ken Thomases Avatar answered Oct 27 '22 00:10

Ken Thomases