游戏引擎多线程二Word格式文档下载.docx

上传人:b****6 文档编号:17629267 上传时间:2022-12-07 格式:DOCX 页数:10 大小:19.46KB
下载 相关 举报
游戏引擎多线程二Word格式文档下载.docx_第1页
第1页 / 共10页
游戏引擎多线程二Word格式文档下载.docx_第2页
第2页 / 共10页
游戏引擎多线程二Word格式文档下载.docx_第3页
第3页 / 共10页
游戏引擎多线程二Word格式文档下载.docx_第4页
第4页 / 共10页
游戏引擎多线程二Word格式文档下载.docx_第5页
第5页 / 共10页
点击查看更多>>
下载资源
资源描述

游戏引擎多线程二Word格式文档下载.docx

《游戏引擎多线程二Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《游戏引擎多线程二Word格式文档下载.docx(10页珍藏版)》请在冰豆网上搜索。

游戏引擎多线程二Word格式文档下载.docx

4最后一个就是创建D3D设备的时候要用多线程标志,这个我刚开始知道有它,但文档上说它有效率损耗,总觉得这个方案的设计可以规避所有多线程问题,所以不使用这个标志也可以。

这个在我自己家里的机器上测试没问题,可是公司的机器就是死锁,还有奔溃,而且没有堆栈。

只怪自己不了解D3D内部怎么实现的了,只能用这个标志位了。

后来发现,问题出现在资源创建和lock的地方,因为资源创建是在主线程创建的,lock是在渲染线程lock,虽然创建和lock不是同一个资源,但发现同时跑D3D会有问题,创建资源是用的D3Ddevice

接口函数,Lock资源是用资源的接口函数,本来不应该有什么冲突,可能是D3D里面做什么处理,要访问同一个东西,而导致问题。

如果你的资源在渲染线程之前或者同步2个线程的时候都创建好,就不会有这个问题(事先创建好),但如果你做异步加载把创建资源扔到渲染线程,就可能要多考虑些问题了。

我建议,游戏中无论怎么加线程,主线程还是作为一个中转站的作用,这样可以减少问题复杂程度。

总之开了这个标志位会有性能损耗,但只要你创建资源不是始终都在和渲染线程并排的跑,应该问题不大,即使始终并排跑这种很少性能的减少,却可以规避设计复杂问题,也是值得的。

5还有一个问题就是一旦主线程资源删除,而渲染线程还在用到这个资源,如果用智能指针去管理,首先智能指针要具备线程安全性,第二,如果渲染线程这个时候ref为1,这个command执行完后,要析构才能让这个资源删除,否则不析构永远无法删除,这里有个潜在问题,如果资源析构的时候调用了主线程的函数(例如资源管理中,析构后要从资源管理中删除等),这个时候线程安全性就无法保证,这里就太多不可确定。

所以做一个资源GC功能很有必要,从这个资源ref为1(默认资源管理要保留一份,所以没人用的时候ref是1)的时候开始计时,这个时候没有其他在用,所以渲染肯定也不可见的,所以就不会进入渲染线程,到一定时间就可以把他GC掉,如果又有其他重新指向这个资源,那么把计时清0.

6.最后一个就是分辨率切换,窗口切换,涉及到的设备丢失问题。

这个问题处理就是一旦检测到窗口切换和设备丢失(这个检测都是在主线程来响应的),马上就不要跑主线程的添加rendercommand和渲染线程,而是把2个缓冲buffer全都清空,去处理设备丢失问题。

代码说明和运行效果

说了这么多,对程序员来说,看到代码和实现效果比什么都是重要的,上面提到的问题以及方法,都被我实现过了。

主多线程渲染架构

//如果设备不丢失,这里检测设备丢失,如果丢失先devicelost处理然后返回false,下一帧在进这个函数后,再做devicereset

if(VSRenderer:

:

ms_pRenderer->

CooperativeLevel())

{

VSRenderThreadSys:

ms_pRenderTreadSys->

Begin();

//通知渲染线程启动

if(VSSceneManager:

ms_pSceneManager)

{

VSSceneManager:

ms_pSceneManager->

Update(fTime);

}

//下面过程是添加rendercommand

VSRenderer:

BeginRendering();

Draw(fTime);

EndRendering();

if(VSRenderThreadSys:

ms_pRenderTreadSys&

&

VSResourceManager:

ms_bRenderThread)

VSRenderThreadSys:

ExChange();

//同步渲染线程,并交换buffer

else

//清空所有渲染rendercommand

ms_pRenderTreadSys)

Clear();

}

//GC功能

VSResourceManager:

GC();

voidVSRenderThreadSys:

Begin()

//设置一个准备填rendercommandbuffer

m_RenderThread.SetRender(m_RenderBuffer);

//启动渲染线程

m_RenderThread.Start();

//渲染线程运行,只要不触发被迫停止,它就会一直运行下去,如果rendercommandbuffer的所有数据都处理完毕,马上提醒主线程,不再等待

voidVSRenderThread:

Run()

while(!

IsStopTrigger())

if(m_pRenderBuffer)

m_pRenderBuffer->

Excuce();

m_pRenderBuffer=NULL;

m_Event.Trigger();

ExChange()

//主线程等待渲染线程完毕

m_RenderThread.m_Event.Wait();

//挂起渲染线程

m_RenderThread.Suspend();

m_RenderBuffer->

//交换2个buffer

Swap(m_UpdateBuffer,m_RenderBuffer);

//有些资源有双D3D资源的进行多线程的,要交换buffer

for(unsignedinti=0;

i<

VSBind:

ms_DynamicTwoBindArray.GetNum();

i++)

ms_DynamicTwoBindArray->

RenderCommand说明

//这里封装了D3DSetRenderState

boolVSDX9Renderer:

SetRenderState(D3DRENDERSTATETYPEState,DWORDValue)

structVSDx9RenderStatePara

D3DRENDERSTATETYPEState;

DWORDValue;

};

HRESULThResult=NULL;

VSDx9RenderStateParaRenderStatePara;

RenderStatePara.State=State;

RenderStatePara.Value=Value;

ENQUEUE_UNIQUE_RENDER_COMMAND_TWOPARAMETER(VSDx9SetRenderStateCommand,

VSDx9RenderStatePara,RenderStatePara,RenderStatePara,LPDIRECT3DDEVICE9,m_pDevice,m_pDevice,

hResult=m_pDevice->

SetRenderState(RenderStatePara.State,RenderStatePara.Value);

VSMAC_ASSERT(!

FAILED(hResult));

})

ENQUEUE_UNIQUE_RENDER_COMMAND_END

return!

FAILED(hResult);

这里的宏和unreal内部实现不太一样,我做修改,基本意思就是如果开启了多线程渲染,则把命令提交到buffer中,如果不是则直接运行。

所以你会看到2个hResult=m_pDevice->

其实第一个构建rendercommand的类的里面运行代码,第二是如果没开启多线程的话直接就运行。

再来看这个宏,你要是仔细读前面unreal的,你就知道里面嵌套了一个宏,只有嵌套的不一样

#defineENQUEUE_RENDER_COMMAND(TypeName,Params)\

if(VSResourceManager:

ms_bRenderThread)\

{\

TypeName*pCommand=(TypeName*)VSRenderThreadSys:

AssignCommand<

TypeName>

();

\

VS_NEW(pCommand)TypeNameParams;

}\

else\

如果是多线程的话,就构建实例,加入队列,如果不是,则直接运行代码

#defineENQUEUE_UNIQUE_RENDER_COMMAND_END}

再看一个

SetVertexShaderConstant(unsignedintuiStartRegister,void*pDate,

unsignedintRegisterNum,unsignedintuiType)

structVSDx9VertexShaderConstantPara

unsignedintuiStartRegister;

void*pDate;

unsignedintRegisterNum;

unsignedintuiType;

VSDx9VertexShaderConstantParaVertexShaderConstantPara;

VertexShaderConstantPara.uiStartRegister=uiStartRegister;

VertexShaderConstantPara.RegisterNum=RegisterNum;

VertexShaderConstantPara.uiType=uiType;

if(VSResourceManager:

VertexShaderConstantPara.pDate=VSRenderThreadSys:

Assign(uiType,RegisterNum);

VSMemcpy(VertexShaderConstantPara.pDate,pDate,RegisterNum*sizeof(VSREAL)*4);

else

VertexShaderConstantPara.pDate=pDate;

ENQUEUE_UNIQUE_RENDER_COMMAND_TWOPARAMETER(VSDx9SetVertexShaderConstantCommand,

VSDx9VertexShaderConstantPara,VertexShaderConstantPara,VertexShaderConstantPara,LPDIRECT3DDEVICE9,m_pDevice,m_pDevice,

if(VertexShaderConstantPara.uiType==VSUserConstant:

VT_BOOL)

hResult=m_pDevice->

SetVertexShaderConstantB(VertexShaderConstantPara.uiStartRegister,(constBOOL*)VertexShaderConstantPara.pDate,VertexShaderConstantPara.RegisterNum);

VSMAC_ASSERT(!

elseif(VertexShaderConstantPara.uiType==VSUserConstant:

VT_FLOAT)

SetVertexShaderConstantF(VertexShaderConstantPara.uiStartRegister,(constfloat*)VertexShaderConstantPara.pDate,VertexShaderConstantPara.RegisterNum);

VT_INT)

SetVertexShaderConstantI(VertexShaderConstantPara.uiStartRegister,(constint*)VertexShaderConstantPara.pDate,VertexShaderConstantPara.RegisterNum);

VSMAC_ASSERT(0);

return1;

这个封装了D3D设置vshader的函数,参数也是在buffer里面分配的,这里记录了,分配的地址和长度。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销 > 销售营销

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1