Sign in to follow this  
Juliean

Void pointer/array handling (render queue)

Recommended Posts

Hello,

 

so I've started to implement my render queue based on this great article from the forums. However I'm having a few problems concerning void pointers. As suggested by Hodgeman instead of using vectors I've decided to go with a blob-sort of thingy for my render commands (see page free, middlemost answer for the implementation I'm basing mine off). Now this includes storing the render states/commands in an void array:

 

 

class StateGroup
{
public:    

    StateGroup(void) : pStates(NULL), cCommands(0), size(0) {};
    ~StateGroup(void) { delete[] pStates; }
    
    template<typename S>
    void AddCommand(const S& s)
    {
        void* pNewStates = malloc(size + sizeof(S));
        memcpy(pNewStates, pStates, size);

        free(pStates);
        pStates = pNewStates;

        char* ptr = reinterpret_cast<char*>(pStates);
        memcpy(ptr+size, (void*)(&s), size); //here is the issue
        size += sizeof(S);
        cCommands++;
    }    

    UINT GetCommandCount(void) const
    {
        return cCommands;
    }

    const void* GetCommands(void) const
    {
        return pStates;
    }

private:    
    
    void* pStates;
    size_t size;
    UINT cCommands;
};
 

 

 

Look at the "AddCommand-function", which adds is supposed to add a command to the blob. If I simply memcpy without converting to char and adding the proper offset first, then it works just fine in my temporal render queue implementation:


 

void RenderQueue::Sort(void)
{
    std::stable_sort(m_vInstances.begin(), m_vInstances.end(), QueueSorter);

    for(instanceVector::const_iterator ii = m_vInstances.cbegin(); ii != m_vInstances.cend(); ++ii)
    {
        const StateGroup** pStateGroups = (*ii)->GetStateGroups();

        for(UINT i = 0; i < (*ii)->GetStateCount(); i++)
        {
            const StateGroup* pGroup = pStateGroups[i];
            const void* pvCmds = pGroup->GetCommands();

            for(UINT j = 0; j < pGroup->GetCommandCount(); j++)
            {
                const RenderState::StateType type = static_cast<const RenderState*>(pvCmds)->GetType();

                switch(type)
                {
                case RenderState::StateType::VertexBuffer:
                    {
                        const BindVertexBuffer& bindVB = *reinterpret_cast<const BindVertexBuffer*>(pvCmds);
                        pBindVB->Execute(device);
                        pvCmds = static_cast<const void*>(static_cast<const char*>(pvCmds) + sizeof(BindVertexBuffer));
                    }
                case RenderState::StateType::IndexBuffer:
                    {
                        const BindIndexBuffer& bindVB = *reinterpret_cast<const BindIndexBuffer*>(pvCmds);
                        pBindVB->Execute(device);
                        pvCmds = static_cast<const void*>(static_cast<const char*>(pvCmds) + sizeof(BindIndexBuffer));
                    }
                }
            }
        }
    }
}
 

 

However of course, only the last added state is used, since memcpy will start from location 0. Now if I use the code like I did in my first code tag, I only get some garbage output when using RenderState::GetType() on my static_casted void pointer to the state blob. Why?

 

I must admit, I haven't used void pointers that often before, but here it seams like a real neat thing to have, especially given Hodgemans explanation why this can fair very well. But for now, why does this one memcpy with (from what I can say) correct values produce this garbage output?

Edited by Juliean

Share this post


Link to post
Share on other sites

Managed to fix it myself, tired programming is not a good thing to do, obviously *sigh*. Didn't need to store anything with a void ptr, a normal "RenderState**" did do the job.

 

class StateGroup
{
public:	

	StateGroup(void) : pStates(nullptr), cCommands(0) {};
	~StateGroup(void) { delete[] pStates; }
	
	void Add(const RenderState& s) 
	{
		const RenderState** pNewStates = new const RenderState*[cCommands+1];
		memcpy(pNewStates, pStates, cCommands*sizeof(RenderState*));

		delete[] pStates;
		pStates = pNewStates;

		pStates[cCommands++] = &s;
	}	

	unsigned int GetCommandCount(void) const
	{
		return cCommands;
	}

	const RenderState** GetCommands(void) const
	{
		return pStates; 
	}

private:	
	
	const RenderState** pStates;
	unsigned int cCommands;
};
void RenderQueue::Sort(void)
{
	std::stable_sort(m_vInstances.begin(), m_vInstances.end(), QueueSorter);

	for(instanceVector::const_iterator ii = m_vInstances.cbegin(); ii != m_vInstances.cend(); ++ii)
	{
		const RenderInstance* pInstance = *ii;
		const StateGroup** pStateGroups = pInstance->GetStateGroups();

		for(UINT i = 0; i < pInstance->GetStateCount(); i++)
		{
			const StateGroup* pGroup = pStateGroups[i];
			const RenderState** pvCmds = pGroup->GetCommands();

			for(UINT j = 0; j < pGroup->GetCommandCount(); j++)
			{
				const RenderState* pState = pvCmds[j];
				const RenderState::StateType type = pState->GetType();

				switch(type)
				{
				case RenderState::StateType::VertexBuffer:
					{
						const BindVertexBuffer& bindVB = *static_cast<const BindVertexBuffer*>(pState);
						bindVB.Execute(*m_pDevice);
						break;
					}
				case RenderState::StateType::VertexDeclaration:
					{
						const SetVertexDeclaration& setVD = *static_cast<const SetVertexDeclaration*>(pState);
						setVD.Execute(*m_pDevice);
						break;
					}
				case RenderState::StateType::IndexBuffer:
					{
						const BindIndexBuffer& bindIB = *static_cast<const BindIndexBuffer*>(pState);
						bindIB.Execute(*m_pDevice);
						break;
					}
				}
			}
		}

		const DrawCall* pDrawCall = pInstance->GetDrawCall();
		const DrawCall::CallType type = pDrawCall->GetType();

		switch(type)
		{
		case DrawCall::CallType::DrawIndexed:
			{
				const DrawIndexedPrimitives& pDrawIndexed = *static_cast<const DrawIndexedPrimitives*>(pDrawCall);
				pDrawIndexed.Execute(*m_pDevice);
				break;
			}
		}
	}
}

In case someone stumbles over this problem, and is confused just like me.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this