gpt4 book ai didi

c++ - DirectX 11 - 使用 AVX 的 AoS 到 SoA 转换导致重新映射时顶点缓冲区损坏

转载 作者:行者123 更新时间:2023-11-30 05:39:46 26 4
gpt4 key购买 nike

嗨!
我正在 DirectX 11 中实现粒子系统并使用 Intel AVX instrinsics更新粒子数据并将其从 SoA(阵列结构)转换为 AoS(结构阵列),然后再将其传递到 IA 阶段。

似乎当我在重新映射阶段使用 AVX intrisincs 时,它会导致我的顶点缓冲区(包含粒子顶点)损坏并导致崩溃!

我以 SoA 方式构建我的粒子数据:

float*      mXPosition;
float* mYPosition;
float* mZPosition;

我为每个组件分配内存

mXPosition = (float*) _aligned_malloc( NUM_PARTICLES * sizeof(float), 32 );
mYPosition = (float*) _aligned_malloc( NUM_PARTICLES * sizeof(float), 32 );
mZPosition = (float*) _aligned_malloc( NUM_PARTICLES * sizeof(float), 32 );

我使用 D3D11_USAGE_DYNAMICD3D11_CPU_ACCESS_WRITE 创建顶点缓冲区,以便能够在 CPU 上修改粒子数据。

D3D11_BUFFER_DESC desc;
ZeroMemory( &desc, sizeof( desc ) );

desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.ByteWidth = sizeof(ParticleVertex12) * NUM_PARTICLES;
desc.StructureByteStride = sizeof(ParticleVertex12);
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;

//Allocating aligned memory for array used for maping vertices to buffer
mVertices = (float*) _aligned_malloc( ( NUM_PARTICLES * 3 ) * sizeof(float), 32 );


if( FAILED( device->CreateBuffer( &desc, &subData, &mVertexBuffer ) ) )
return E_FAIL;

顶点缓冲区创建成功。

重映射阶段

D3D11_MAPPED_SUBRESOURCE mappedResource;
HRESULT hr = deviceContext->Map( mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource );

if( SUCCEEDED( hr ) )
{
size_t counter = 0;
for (int baseIndex = 0; baseIndex < NUM_PARTICLES / 8; baseIndex++)
{
// Mapping from SOA-pattern to AOS-pattern

//Load
__m256 xReg = _mm256_load_ps( &mXPosition[baseIndex * 8] );
__m256 yReg = _mm256_load_ps( &mYPosition[baseIndex * 8] );
__m256 zReg = _mm256_load_ps( &mZPosition[baseIndex * 8] );

//Set test values
xReg = _mm256_set_ps( 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f );
yReg = _mm256_set_ps( 21.0f, 22.0f, 23.0f, 24.0f, 25.0f, 26.0f, 27.0f, 28.0f );
zReg = _mm256_set_ps( 31.0f, 32.0f, 33.0f, 34.0f, 35.0f, 36.0f, 37.0f, 38.0f );

//Shuffle
__m256 xyReg = _mm256_shuffle_ps( xReg, yReg, _MM_SHUFFLE( 2,0,2,0 ) );
__m256 yzReg = _mm256_shuffle_ps( yReg, zReg, _MM_SHUFFLE( 3,1,3,1 ) );
__m256 zxReg = _mm256_shuffle_ps( zReg, xReg, _MM_SHUFFLE( 3,1,2,0 ) );

__m256 reg03 = _mm256_shuffle_ps( xyReg, zxReg, _MM_SHUFFLE( 2, 0, 2, 0 ) );
__m256 reg14 = _mm256_shuffle_ps( yzReg, xyReg, _MM_SHUFFLE( 3, 1, 2, 0 ) );
__m256 reg25 = _mm256_shuffle_ps( zxReg, yzReg, _MM_SHUFFLE( 3, 1, 3, 1 ) );


//Map, xyz
__m128* vertexRegAOS = (__m128*)mTempPtr;

vertexRegAOS[0] = _mm256_castps256_ps128( reg03 ); // x8,y8,z8,x7
vertexRegAOS[1] = _mm256_castps256_ps128( reg14 ); // y7,z7,x6,y6
vertexRegAOS[2] = _mm256_castps256_ps128( reg25 ); // z6,x5,y5,z5

vertexRegAOS[3] = _mm256_extractf128_ps( reg03, 1 ); // x4,y4,z4,x3
vertexRegAOS[4] = _mm256_extractf128_ps( reg14, 1 ); // y3,z3,x2,y2
vertexRegAOS[5] = _mm256_extractf128_ps( reg25, 1 ); // z2,x1,y1,z1

for ( int index = 0, subIndex = 0 ; index < 6; index++ )
{
mVertices[counter++] = vertexRegAOS[index].m128_f32[(subIndex++) % 4];
mVertices[counter++] = vertexRegAOS[index].m128_f32[(subIndex++) % 4];
mVertices[counter++] = vertexRegAOS[index].m128_f32[(subIndex++) % 4];
mVertices[counter++] = vertexRegAOS[index].m128_f32[(subIndex++) % 4];
}



memcpy( mappedResource.pData, mVertices, sizeof( ParticleVertex12 ) * NUM_PARTICLES );
deviceContext->Unmap( mVertexBuffer, 0 );
}

应用程序在遇到这一行时崩溃

deviceContext->Unmap( mVertexBuffer, 0 );

并显示消息

D3D11 CORRUPTION: ID3D11DeviceContext::Unmap: First parameter is corrupt or NULL. [ MISCELLANEOUS CORRUPTION #13: CORRUPTED_PARAMETER1]

我可能已经找到了问题所在,但由于我对使用 AVX 还很陌生,所以我还没有设法解决它。

如果我注释掉这部分:

        //Map, xyz
__m128* vertexRegAOS = (__m128*)mTempPtr;

vertexRegAOS[0] = _mm256_castps256_ps128( reg03 ); // x8,y8,z8,x7
vertexRegAOS[1] = _mm256_castps256_ps128( reg14 ); // y7,z7,x6,y6
vertexRegAOS[2] = _mm256_castps256_ps128( reg25 ); // z6,x5,y5,z5

vertexRegAOS[3] = _mm256_extractf128_ps( reg03, 1 ); // x4,y4,z4,x3
vertexRegAOS[4] = _mm256_extractf128_ps( reg14, 1 ); // y3,z3,x2,y2
vertexRegAOS[5] = _mm256_extractf128_ps( reg25, 1 ); // z2,x1,y1,z1

for ( int index = 0, subIndex = 0 ; index < 6; index++ )
{
mVertices[counter++] = vertexRegAOS[index].m128_f32[(subIndex++) % 4];
mVertices[counter++] = vertexRegAOS[index].m128_f32[(subIndex++) % 4];
mVertices[counter++] = vertexRegAOS[index].m128_f32[(subIndex++) % 4];
mVertices[counter++] = vertexRegAOS[index].m128_f32[(subIndex++) % 4];
}

然后它不会崩溃。类型转换中使用的 mTempPtr 定义如下

mTempPtr = new float[6];

有没有 AVX 专家知道我哪里做错了?感谢您提出任何建议!

谢谢!

最佳答案

我认为您的错误是为六个 32 位 float 分配空间,然后存储六个 128 位 float vector 。你很可能。踩到下一次分配的簿记数据,导致在尝试 free() 时出错。

mTempPtr = new float[6];
__m128* vertexRegAOS = (__m128*)mTempPtr;
vertexRegAOS[0] = _mm_setzero_ps();
vertexRegAOS[1] = _mm_setzero_ps(); // buffer overrun here: you only had room for 2 more floats, but you store 4.
vertexRegAOS[2] = ...; // step on more stuff
... // corrupt even more memory :P

您可以通过使用 VPERM2F128 然后使用一个 256b 存储而不是 2x VEXTRACTF128(显然不能对其存储进行微融合)来保存一两个 uop和存储数据微指令)。

    vertexRegAOS[0] = _mm256_castps256_ps128( reg03 );  // x8,y8,z8,x7
vertexRegAOS[1] = _mm256_castps256_ps128( reg14 ); // y7,z7,x6,y6
vertexRegAOS[2] = _mm256_castps256_ps128( reg25 ); // z6,x5,y5,z5

vertexRegAOS[3] = _mm256_extractf128_ps( reg03, 1 ); // x4,y4,z4,x3
// vertexRegAOS[4] = _mm256_extractf128_ps( reg14, 1 ); // y3,z3,x2,y2
// vertexRegAOS[5] = _mm256_extractf128_ps( reg25, 1 ); // z2,x1,y1,z1
__m256 reg45 = _mm256_permute2f128_ps (reg14, reg25, 1|(3<<4) );
_mm256_storeu_ps( (float*)(vertexRegAOS + 4), reg45);

不过,如果您的代码必须在 AMD Piledriver 上正常运行,请不要使用 256b 存储。它有一个糟糕的性能错误,使 256b 存储比两个 128b 慢得多。

此外,从 vertexRegAOS 复制到 mVertices[counter++] 的循环不只是一个 memcpy 吗?我不明白你为什么不直接存储到它,如果需要的话,使用未对齐的存储。它没有注释,也许我没有花足够的时间盯着它看,如果它实际上没有按顺序复制每个 float 的话。

关于c++ - DirectX 11 - 使用 AVX 的 AoS 到 SoA 转换导致重新映射时顶点缓冲区损坏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32138321/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com