在我的Unity游戏中,我必须通过本机代码修改很多图形资源,例如纹理和顶点缓冲区,以保持良好的性能。
当代码在很短的时间内多次调用ID3D11ImmediateContext::Map时,问题就开始了(我的意思是很短-从并行运行的不同线程中调用)。映射是否成功没有规则。方法调用看起来像
ID3D11DeviceContext* sU_m_D_context;
void* BeginModifyingVBO(void* bufferHandle)
{
ID3D11Buffer* d3dbuf = static_cast<ID3D11Buffer*>(bufferHandle);
D3D11_MAPPED_SUBRESOURCE mapped;
HRESULT res = sU_m_D_context->Map(d3dbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
assert(mapped.pData);
return mapped.pData;
}
void FinishModifyingVBO(void* bufferHandle)
{
ID3D11Buffer* d3dbuf = static_cast<ID3D11Buffer*>(bufferHandle);
sU_m_D_context->Unmap(d3dbuf, 0);
}
std::mutex sU_m_D_locker;
void Mesh::ApplyBuffer()
{
sU_m_D_locker.lock();
// map buffer
VBVertex* mappedBuffer = (VBVertex*)BeginModifyingVBO(this->currentBufferPtr);
memcpy(mappedBuffer, this->mainBuffer, this->mainBufferLength * sizeof(VBVertex));
// unmap buffer
FinishModifyingVBO(this->currentBufferPtr);
sU_m_D_locker.unlock();
this->markedAsChanged = false;
}
其中d3dbuf是动态顶点缓冲区。我不知道为什么,但是尽管有很多可用内存,有时结果还是E_OUTOFMEMORY。我试图用互斥锁包围代码-无效。
这真的是内存问题,还是不太明显?
最佳答案
设备上下文方法都不是线程安全的。如果要从多个线程使用它们,则需要手动同步所有调用,或者使用多个(延迟)上下文,每个线程一个。参见Introduction to Multithreading in Direct3D 11。
错误检查也应该更好:您需要始终检查返回的HRESULT
值,因为在失败的情况下,诸如assert(mapped.pData);
之类的东西仍然可能成功。