Jump to content

  • Log In with Google      Sign In   
  • Create Account


Render queue texture clearing


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
15 replies to this topic

#1 Juliean   GDNet+   -  Reputation: 2365

Like
0Likes
Like

Posted 15 April 2013 - 09:16 AM

Hello,

 

I've got a conceptual question concering a render queue as discussed in the "frostbite render architecture" thread in the forums. I've basically implemented such a queue, much like Hodgman descibed it there. I've just got some concerns about how clearing textures and/or the depth buffer is normally handled in such render queues. What would this be? Would this even be handled by the queue? If yes, what "type" would it be? Would it be a render state (like set vertex buffer, set index buffer, set texture...) ? Or would it be a DrawCall, therefore its own render instance? Should it rather be part of the Model, Material, Effect ? If it should better not be part of the render queue, how else is it "normally" handled? How do you handle it, for example if you need to clear the z-buffer for different shadow caster, or generally at the begin/end of a frame?

 

I'd really be glad to hear some of your opinions, I'm sure a lot of people have worked with such a render queue before...?



Sponsor:

#2 TiagoCosta   Crossbones+   -  Reputation: 1929

Like
1Likes
Like

Posted 15 April 2013 - 11:26 AM

Hi,

 

I also implemented a render queue like discussed in "frostbite render architecture".

 

have commands called ClearRenderTarget and ClearDepthStencilTarget that I put inside a "Stage" state group that is executed at the beginning of the corresponding stage.

 

I don't think Models, Materials or Effects have anything to do with clearing render targets that's why I have the Stage state group.

 

(I also have a command for updating buffers, etc in case you're wondering).


Tiago Costa
Aqua Engine - my DirectX 11 game "engine" - In development

#3 Juliean   GDNet+   -  Reputation: 2365

Like
0Likes
Like

Posted 15 April 2013 - 11:42 AM

Thanks for your comment,

 

 

I don't think Models, Materials or Effects have anything to do with clearing render targets that's why I have the Stage state group.

 

Thats interesing though. I do also have stage groups, probably a lot like yours. As in one of Hodgmans posts, my model, material and effect all holds their own state group, which the model puts together and submits to the queue. Its somewhere on the second page I quess, some poorly formated code (forums fault, I quess).

 

Now that you say "models, materials and effects should not have anything to do" with clearing render targets - how do you set the stage group anyway? Since each of those entities have their own stage groups, command injection has to go through them, at some point, right? E.g. my model has a "SetVertexConstant"-method that adds a VertexConstantX-command to the stage. How do you handle this? Thats a question I was going to ask anyway at some point, because I was really unsure how this is normally done.


Edited by Juliean, 15 April 2013 - 11:45 AM.


#4 TiagoCosta   Crossbones+   -  Reputation: 1929

Like
1Likes
Like

Posted 15 April 2013 - 12:08 PM

I do also have stage groups, probably a lot like yours. As in one of Hodgmans posts, my model, material and effect all holds their own state group, which the model puts together and submits to the queue.

 

In my implementation the models don't have access to the render queue, (in my opinion the model class should be independent on the Renderer), instead the model class has a method getStateGroups() an array containing the effect, material, mesh, model state groups.

 

for(Model model : models)
{
    queue.submit(model.getStageGroups(), model.getNumStateGroups();
}

 

 

Now that you say "models, materials and effects should not have anything to do" with clearing render targets - how do you set the stage group anyway? Since each of those entities have their own stage groups, command injection has to go through them, at some point, right? E.g. my model has a "SetVertexConstant"-method that adds a VertexConstantX-command to the stage. How do you handle this? Thats a question I was going to ask anyway at some point, because I was really unsure how this is normally done.

 

The Stage group is submitted individually before the models. How do you bind render targets/depth stencil buffers?

 

I don't have commands to set individual constants, instead I work with constant buffers, the model "SetVertexConstant"-method will change the value of the constant in a POD buffer then the model uses two commands, UpdateCBuffer (that fills a D3D buffer with the contents of the POD buffer containing the constants) and VSBindCBuffer0 (that binds the D3D buffer to the constant buffer slot 0 of the vertex stage)


Edited by TiagoCosta, 15 April 2013 - 12:11 PM.

Tiago Costa
Aqua Engine - my DirectX 11 game "engine" - In development

#5 Juliean   GDNet+   -  Reputation: 2365

Like
0Likes
Like

Posted 15 April 2013 - 12:36 PM

In my implementation the models don't have access to the render queue, (in my opinion the model class should be independent on the Renderer), instead the model class has a method getStateGroups() an array containing the effect, material, mesh, model state groups.

 

My implementation isn't that different. I just gave the model a "Render"-method where I pass the render queue and let it submit its sort key, state groups and draw command.

 

void Model::Draw(render::IRenderer& render) const
{
	const render::StateGroup* pInstanceStates = &m_states;
	const render::StateGroup* pMaterialStates = &m_pMaterial->GetState();
	const render::StateGroup* pEffectStates = &m_pMaterial->GetEffect().GetState();
	const render::StateGroup* pMeshStates = &m_pMesh->GetState();
	const render::StateGroup* groupArr[4] = { pInstanceStates, pMaterialStates, pEffectStates, pMeshStates };

	render.Render(m_sortKey, &m_pMesh->GetDraw(), groupArr, 4); 
}

I do agree that the model probably should be completely independand of the renderer, but for now, it works OK (going to change that somewhen). Note that I've adapted Hodgmans method of having draw calls seperated from state groups, and create an "render instance" out of all this data...

 

 

The Stage group is submitted individually before the models. How do you bind render targets/depth stencil buffers?

Right now the bound render targets are determined by the effect only:

 

void Effect::RenderTarget(unsigned int index, const Texture* pTexture)
{
	const D3DTexture* pD3DTexture = nullptr;

	if(pTexture != nullptr)
		pD3DTexture = &pTexture->GetD3DTexture();

	switch(index)
	{
	case 0:
		m_states.Add<render::BindRenderTarget0>(*pD3DTexture);
		break;
	case 1:
		m_states.Add<render::BindRenderTarget1>(*pD3DTexture);
		break;
	case 2:
		m_states.Add<render::BindRenderTarget2>(*pD3DTexture);
		break;
	case 3:
		m_states.Add<render::BindRenderTarget2>(*pD3DTexture);
		break;
	}
}

I don't really know what else I'm going to need (probably per-material/per-instance/per-pass render targets too?), but as far as this is concerned, would you say this is ok? As far as clearing render targets goes, it obviously can't be per-effect, since that would clear the target every time I e.g. render another one of my lights, etc...

 

 

I don't have commands to set individual constants, instead I work with constant buffers, the model "SetVertexConstant"-method will change the value of the constant in a POD buffer then the model uses two commands, UpdateCBuffer (that fills a D3D buffer with the contents of the POD buffer containing the constants) and VSBindCBuffer0 (that binds the D3D buffer to the constant buffer slot 0 of the vertex stage)

 

I quess you are working with DirectX 11? does this concept of constant buffers also translate to DirectX9? In DX9 I've got up to 256 (I quess) constant registeres, and I figured the best direct way for now was to simply adress the register directly (when I'm going to implement shader permutations etc.. I'm going to think about another solution anyway)...

 

But as for the render target clearing, where'd you say this would fit here?


Edited by Juliean, 15 April 2013 - 12:36 PM.


#6 phantom   Moderators   -  Reputation: 6906

Like
0Likes
Like

Posted 15 April 2013 - 01:19 PM

In our engine at work the submission is largely based around 'scenes' which are, effectively, a set of draw calls with a particular set of shaders in use (determined by flags on the scene).

The 'scene' description also has flags which allow you to declare if certain actions happen as they are executed;
- begin
- end
- clear

The first two being a chance for a scene to do something before rendering starts, the final one indicates if the buffers for a scene should be cleared or not (other parameters dictate clear modes, colours etc). This allows you have a number of scenes render to the same targets (targets are named and shared as required, although each scene has its own 'render target' setup structure) without clearing in between them.

Effective rendering;
for each scene in scene list
- if(scene:hasflag(begin)) -> call 'begin' function
- bind render targets
- if(scene:hasflag(clear)) -> do clear functionality
- render each visible model
- if(scene:hasflag(end)) -> call 'end' function

#7 Juliean   GDNet+   -  Reputation: 2365

Like
0Likes
Like

Posted 15 April 2013 - 04:27 PM

@phantom:

 

So is this how your entire rendering architecture works, or is it some part put on top of everything? It doesn't seem like a bad idea, but it appears to not being really compatible to my current rendering architecture, which works by submitting a render instance (state changes + sort key + draw call), but I'm not sure...



#8 Hodgman   Moderators   -  Reputation: 28614

Like
1Likes
Like

Posted 15 April 2013 - 09:56 PM

I do pretty much the same thing as Phantom, but call them 'stages' instead of 'scenes', like Tiago.
I put items (draw + state) into groups, and then put groups in / submit a group along with, a stage.
Some states can't be put into StateGroups (e.g. Render-targets/depth stencil) and are instead specified in the stage. The stage also says whether the targets should be cleared at the start and resolved / extra copies made at the end.

#9 Juliean   GDNet+   -  Reputation: 2365

Like
0Likes
Like

Posted 16 April 2013 - 01:20 AM

Ah, I think I get it. So if I was to adapt that design, I would put my models into stages, and submit them along with the stage/scene, right? How does this conceptually work? Is there some external RenderQueue::SetStageState-like function, that is called before the "models" are submitted? Like I said, you can imagine my render system be based somewhat along the lines of your second page posts + the render queue code thats somewhere in the middle of the third page in the "frostbite" thread (don't think it would be too helpfull if I posted my whole code).



#10 TiagoCosta   Crossbones+   -  Reputation: 1929

Like
1Likes
Like

Posted 16 April 2013 - 05:48 AM

IMO, you should create a new class, let's call it Stage along with a new StateGroup, and move the render target binding/clearing to it (now the Effects state group will only bind the hardware shaders and set default shader values).

 

In my renderer, models can have more than one RenderItem (draw call/state groups pair) each one is assigned to a Stage. Example: the RenderItem assigned to the Shadow Mapping stage doesn't need the material state group to be executed)

 

As you can read in this topic, the renderer has multiple buckets (lists of RenderItems) each bucket is associated with a Stage. Before rendering the renderer goes through the Scene (a list of model instances, etc) finds all the model instances and puts its RenderItems in the appropriate bucket.

 

Then Stages are executed according to the order defined in the renderer_config file: the bucket associated with each stage is sorted (if needed), the state group of that stage (containing the render target clearing/binding commands) is submitted and only then the RenderItems inside the bucket are submitted.


Edited by TiagoCosta, 16 April 2013 - 05:49 AM.

Tiago Costa
Aqua Engine - my DirectX 11 game "engine" - In development

#11 Juliean   GDNet+   -  Reputation: 2365

Like
0Likes
Like

Posted 16 April 2013 - 07:05 AM

Ah, so would it be somehow along those lines?

 

class Stage
{
SetRenderTarget(int, texture) { state.add<RenderTarget>(texture) }

private: 
StateGroup stageState;
}

class Model
{
AddRenderInstance(Stage&, Mesh&, Effect&, Material*) { m_vInstances.push_back(new RenderInstance(stage, mesh, effect, material); 
}
private:
vector<RenderInstance>
}

 

Then before the actual render loop, I'd have a scene graph thingy that holds pointer to all modes sort out the respective render instances to their stage bucket. After that I'd submit the buckets stage group, then submit all the render instances inside that bucket to the actual render queue. Correct? If so,

 

the bucket associated with each stage is sorted (if needed), the state group of that stage (containing the render target clearing/binding commands) is submitted

 

Do I need a seperate command for submitting a state group only for my render queue (because now I only support render instance submitting), or do you mean "submit" here more like explicitely set those states here?



#12 phantom   Moderators   -  Reputation: 6906

Like
1Likes
Like

Posted 16 April 2013 - 12:31 PM

@phantom:
 
So is this how your entire rendering architecture works, or is it some part put on top of everything? It doesn't seem like a bad idea, but it appears to not being really compatible to my current rendering architecture, which works by submitting a render instance (state changes + sort key + draw call), but I'm not sure...

Ah yes, I should have been a bit more clear about that; we build the same kind of list too and its that which is processed in side the "render each visible model" bit (by 'render' it means 'record these draw calls into a command list to execute on the device later'), this list is just established per unique camera in the world and used with the scenes which require it.

#13 TiagoCosta   Crossbones+   -  Reputation: 1929

Like
1Likes
Like

Posted 16 April 2013 - 01:05 PM

Do I need a seperate command for submitting a state group only for my render queue (because now I only support render instance submitting), or do you mean "submit" here more like explicitely set those states here?

 

Can't you simply submit the state group in a RenderItem with the draw call as null?
Or you could explicitely set those states... Anyway should work fine.


Tiago Costa
Aqua Engine - my DirectX 11 game "engine" - In development

#14 Juliean   GDNet+   -  Reputation: 2365

Like
0Likes
Like

Posted 16 April 2013 - 03:29 PM

Ah yes, I should have been a bit more clear about that; we build the same kind of list too and its that which is processed in side the "render each visible model" bit (by 'render' it means 'record these draw calls into a command list to execute on the device later'), this list is just established per unique camera in the world and used with the scenes which require it.

 

So I see it right that you have one list per scene? Therefore one "render queue" that gets sorted and submitted one after another, completely independand of all the other stages lists/queues?

 

 

Can't you simply submit the state group in a RenderItem with the draw call as null?
Or you could explicitely set those states... Anyway should work fine.

 

Yeah, that would work, just need to add a check for null-draw calls. But I think I prefer to make a seperate "SetStageGroup"-method, since those commands (render target set/clear) etc... would probably need to be seperated somehow anyway. I'm quessing if I were to submit it as a normal RenderInstance with a null draw kell, I'll give it the highest possible sorting key, so it would always be executed first?


Edited by Juliean, 16 April 2013 - 04:44 PM.


#15 phantom   Moderators   -  Reputation: 6906

Like
0Likes
Like

Posted 16 April 2013 - 05:20 PM

So I see it right that you have one list per scene? Therefore one "render queue" that gets sorted and submitted one after another, completely independand of all the other stages lists/queues?

Well, technically its per unique camera (scenes can share cameras) and then filtered per scene (using various masks such as 'techniques' to define groups of shaders) to get a final rendering list for that scene.

#16 Juliean   GDNet+   -  Reputation: 2365

Like
0Likes
Like

Posted 18 April 2013 - 12:36 PM

Hello,

 

so I've followed your advices and implemented a basic Stage class:

 

		class Stage
		{
		public:
			Stage(UINT queueId, render::IRenderer& renderer);
			~Stage(void);

			void SubmitInstance(const render::RenderInstance& instance) const;

			void SetRenderTarget(unsigned int index, const Texture* pTexture);
			void ClearTargetState(bool bClear);

			void Submit(void) const;

		private:

			render::StateGroup m_stageStates;
			render::IRenderQueue* m_pQueue;
		};

I'd still like to know what you say about some details:

 

- Since visibility has been mentioned, what is the best relationship between model, render instance and stage? Should I store the model in the stage, and pass the camera to the stage to cull the models? Or pass a render instance + a bounding volume pointer, still have culling in the stage? Or should I store a pointer to the stage inside the model/render instance, and have it submit to this stage after an external culling phase? Or something completely different?

 

- Where do you store your stages? Do you just create a stage wherever needed, or is there some "manager" or list, where all stages are held?

 

Thanks in advance!






Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS