check if ID3DXEFFECT has begun? (mEffect->Begin())

Started by
16 comments, last by cozzie 10 years, 2 months ago

Hi,

I was wondering, is there a way to check if a ID3DXEFFECT has begun / if ->Begin() was executed without a call to ->End().

In the member functions of ID3DXEFFECT / ID3DXBASEEFFECT I didn't find any member function who returns this.

Ofcourse I want to prevent creating a bool for tracking this myself.

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

Advertisement
Anyone?

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

Is your rendering code really so complicated, that you need to have a way how to remember this? What's the reason why you have so many lines of code between Begin() and End(), or even have them (probably) in completely different places (methods)?

Try to inspect your code ;)

Anyway, I don't know of any way other than storing it in your own bool variable.

Thanks. It's not very complicated, the reason is that I can clean my code up quitely if I know if an efffect has begun or not.

I'll add a bool in my shader class to check if it's active (begin called without end).

The initial bindings were to prevent that I end an effect (1st iteration of the loop) which isn't active yet.

Here's the code:


bool CD3d::RenderScene(const char *pTechnique, const CD3dcam &pCam, std::vector<Q_RENDERABLE>& pRenderBucket)
{
	// retrieve the 1st element from bucket and do all bindings
	Q_RENDERABLE *last = &pRenderBucket[0];

	ShaderSetTechnique(last->Effect, pTechnique);
	mD3dscene->mShaders[last->Effect].Begin();
	mD3dscene->ShaderSelectMaterial(last->Material, last->Effect);
	mD3dscene->mMeshes[last->Mesh].SetBuffers();
	mD3dscene->ShaderSetWorld(last.Instance, lastId);
	
	bool bucketDone = false;
	int renderable = 0;

	while(!bucketDone)
	{
		auto next = &pRenderBucket[renderable];
		if(next->Effect != last->Effect) 
		{
			mD3dscene->mShaders[last->Effect].End();

			mD3dscene->mShaders[next->Effect].SetTechnique(pTechnique);
			mD3dscene->mShaders[next->Effect].Begin();
		}

		for(unsigned int p=0;p<mD3dscene->mShaders[next->Effect].GetNumPasses();++p)
		{
			mD3dscene->mShaders[next->Effect].BeginPass(p);

			if(next->Material	!= last->Material)	mD3dscene->ShaderSelectMaterial(next->Material, last->Effect);
			if(next->Mesh		!= last->Mesh)		mD3dscene->mMeshes[next->Mesh].SetBuffers();

			mD3dscene->ShaderSetWorld(next.Instance, next.Id);
			mD3dscene->mShaders[next->Effect].Commit();

			mD3dscene->mMeshes[next->Mesh].RenderSubMesh(next->Id, LIST);	// does the draw call
			mD3dscene->mShaders[next->Effect].EndPass();
		}
		last = &pRenderBucket[renderable];	
		++renderable;

		if(renderable == (int)pRenderBucket.size()) bucketDone = true;
	}
	return true;
}

Gonna be working on it now to 'clean it up'.

I'll probably set the initial value of last to a null pointer and then add || NULL to the comparions of last and next.

If you have any ideas how to do this otherwise/ properly, all input welcome

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

You do not have an equal pairing of Begin() and End() here. You never End() the last one you Begin()’ed.

Why don’t you use RAII?


struct EFFECT_RAII {
    EFFECT_RAII( ID3DXEffect * _peEffect ) {
        peEffect = _peEffect;
        if ( peEffect ) { peEffect->Begin(); }
    }
    ~EFFECT_RAII() {
        if ( peEffect ) { peEffect->End(); }
    }


    EFFECT_RAII & operator = ( const ID3DXEffect * _peEffect ) {
        if ( peEffect != _peEffect ) {
            if ( peEffect ) { peEffect->End(); }
            peEffect = _peEffect;
            if ( peEffect ) { peEffect->Begin(); }
        }
        return (*this);
    }
protected :
    ID3DXEffect * peEffect;
};






bool CD3d::RenderScene(const char *pTechnique, const CD3dcam &pCam, std::vector<Q_RENDERABLE>& pRenderBucket)
{
	// retrieve the 1st element from bucket and do all bindings
	Q_RENDERABLE *last = &pRenderBucket[0];

	ShaderSetTechnique(last->Effect, pTechnique);
        EFFECT_RAII erEffect( &mD3dscene->mShaders[last->Effect] );
	//mD3dscene->mShaders[last->Effect].Begin();
	mD3dscene->ShaderSelectMaterial(last->Material, last->Effect);
	mD3dscene->mMeshes[last->Mesh].SetBuffers();
	mD3dscene->ShaderSetWorld(last.Instance, lastId);
	
	bool bucketDone = false;
	int renderable = 0;

	while(!bucketDone)
	{
		auto next = &pRenderBucket[renderable];
		if(next->Effect != last->Effect) 
		{
			//mD3dscene->mShaders[last->Effect].End();

			mD3dscene->mShaders[next->Effect].SetTechnique(pTechnique);
                        erEffect = &mD3dscene->mShaders[next->Effect];
			//mD3dscene->mShaders[next->Effect].Begin();
		}

		for(unsigned int p=0;p<mD3dscene->mShaders[next->Effect].GetNumPasses();++p)
		{
			mD3dscene->mShaders[next->Effect].BeginPass(p);

			if(next->Material	!= last->Material)	mD3dscene->ShaderSelectMaterial(next->Material, last->Effect);
			if(next->Mesh		!= last->Mesh)		mD3dscene->mMeshes[next->Mesh].SetBuffers();

			mD3dscene->ShaderSetWorld(next.Instance, next.Id);
			mD3dscene->mShaders[next->Effect].Commit();

			mD3dscene->mMeshes[next->Mesh].RenderSubMesh(next->Id, LIST);	// does the draw call
			mD3dscene->mShaders[next->Effect].EndPass();
		}
		last = &pRenderBucket[renderable];	
		++renderable;

		if(renderable == (int)pRenderBucket.size()) bucketDone = true;
	}
	return true;
        //~erEffect == LASTSETEFFECT.End() and Begin() and End() are now properly paired.
}

You should be using RAII any time you have to pair calls to an object, not just for Begin()/End() but for BeginPass() and EndPass() as well.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

Thanks, I think I get it.

The ->End() is Always called when begin was called, because the destructor will be called at the end of function.

- can I do exactly the same with the passes that begin/end?

Meanwhile I've been playing around a bit, and the function is now as below (without the EFFECT_RAII).

(by the way, what does RAII stand for?)


/***************** TO DO : ERROR HANDLING WHEN DOING BINDINGS !!!!! ******************/

bool CD3d::RenderScene(const char *pTechnique, const CD3dcam &pCam, std::vector<Q_RENDERABLE>& pRenderBucket)
{
	// retrieve the 1st element from bucket and do all bindings
	Q_RENDERABLE *last = NULL; //&pRenderBucket[0];
	
	size_t bucketSize = pRenderBucket.size();

	for(size_t renderable = 0;renderable<bucketSize;++renderable)
	{
		auto next = &pRenderBucket[renderable];
		if(next->Effect != last->Effect) 
		{
			if(!last) mD3dscene->mShaders[last->Effect].End();

			mD3dscene->mShaders[next->Effect].SetTechnique(pTechnique);
			mD3dscene->mShaders[next->Effect].Begin();
		}

		for(unsigned int p=0;p<mD3dscene->mShaders[next->Effect].GetNumPasses();++p)
		{
			mD3dscene->mShaders[next->Effect].BeginPass(p);

			if(next->Material	!= last->Material)	mD3dscene->ShaderSelectMaterial(next->Material, last->Effect);
			if(next->Mesh		!= last->Mesh)		mD3dscene->mMeshes[next->Mesh].SetBuffers();

			mD3dscene->ShaderSetWorld(next.Instance, next.Id);
			mD3dscene->mShaders[next->Effect].Commit();

			mD3dscene->mMeshes[next->Mesh].RenderSubMesh(next->Id, LIST);	// does the draw call
			mD3dscene->mShaders[next->Effect].EndPass();
		}
		last = &pRenderBucket[renderable];	
	}
	mD3dscene->mShaders[bucketSize-1].End();
	return true;
}

I tried to modify this version using RAII, but I got stuck because I have no initial bindings anymore.

Meaning that when I create the erEffect in the scope of the whole function, I have to create it for last->effect, which is a null pointer at that moment.

Also then I try this:


EFFECT_RAII erEffect(&mD3dscene->mShaders[last->Effect].mEffect);

I get an error "no instance of constructor ... matches the argument" list.

mEffect is a CComPtr<ID3DXEffect>. When I remove the reference (&), the error is gone, probably because it already is a pointer.

Note; I will also add the number of passes to the constructor/ & operator, because this is needed for the 'begin' call.

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

can I do exactly the same with the passes that begin/end?

Can and should.

by the way, what does RAII stand for?

Resource Acquisition Is Initialization

I have to create it for last->effect, which is a null pointer at that moment.

My code allows NULL to be passed.

When I remove the reference (&), the error is gone, probably because it already is a pointer.

Whatever it takes to pass it as a pointer.

if(!last) mD3dscene->mShaders[last->Effect].End();

This always crashes.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

Thanks, this helps :)

I'm currently trying it out, only last thing I'm struggling with is that I also need to pass numPasses which is needed for the Begin call of the effect

For the constructor this works already, but for the & operator I can't add another parameter.
I think this means I have to call the constructor when I switch to another effect and then pass numPasses


struct EFFECT_RAII 
{
    EFFECT_RAII(ID3DXEffect * _peEffect, unsigned int *pNumPasses) 
	{
        peEffect = _peEffect;
		if(peEffect) peEffect->Begin(pNumPasses, D3DXFX_DONOTSAVESTATE); 
    }
    
	~EFFECT_RAII() 
	{
        if(peEffect) peEffect->End();
    }


    EFFECT_RAII & operator = (const ID3DXEffect * _peEffect) 
	{
        if(peEffect != _peEffect ) 
		{
            if(peEffect) peEffect->End();
            peEffect = const_cast<ID3DXEffect*>(peEffect);
            if(peEffect) peEffect->Begin(0, D3DXFX_DONOTSAVESTATE);	// 0 should be numpasses??
        }
        return (*this);
    }

protected :
    ID3DXEffect *peEffect;
};


// the draw function

	EFFECT_RAII erEffect(mD3dscene->mShaders[last->Effect].mEffect, &mD3dscene->mShaders[last->Effect].mNumPasses);

	for(size_t renderable=0;renderable<bucketSize;++renderable)
	{
		auto next = &pRenderBucket[renderable];
		if(next->Effect != last->Effect) 
		{
			erEffect = mD3dscene->mShaders[last->Effect].mEffect;

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me


struct EFFECT_RAII {
    EFFECT_RAII( ID3DXEffect * _peEffect, UINT * _puiPasses ) {
        peEffect = _peEffect;
        if ( peEffect ) { peEffect->Begin( _puiPasses, D3DXFX_DONOTSAVESTATE ); }
    }
    ~EFFECT_RAII() {
        if ( peEffect ) { peEffect->End(); }
    }


    EFFECT_RAII & SetEffect( const ID3DXEffect * _peEffect, UINT * _puiPasses ) {
        if ( peEffect != _peEffect ) {
            if ( peEffect ) { peEffect->End(); }
            peEffect = _peEffect;
            if ( peEffect ) { peEffect->Begin( _puiPasses, D3DXFX_DONOTSAVESTATE ); }
        }
        return (*this);
    }
protected :
    ID3DXEffect * peEffect;
};

Call SetEffect() instead of using the assignment operator.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

Thanks, got it.
One thing I ran into (and solved) whas that assigning const _peEffect to peEffect is a const/non const assignment, I solved this by putting a const cast before the _peEffect, to make it non-const

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

This topic is closed to new replies.

Advertisement