既存のすべてのグラフィックコード(OpenGL用に作成)を使用できるようにし、OpenGL呼び出しを同等のDirect3DにルーティングするOpenGLラッパーを作成しようとしています。これは、パフォーマンスがかなりの問題であることが判明していることを除いて、これまでのところ驚くほどうまく機能しています。
今、私はD3Dを設計されていない方法で使用している可能性が高いことを認めます。レンダリングループごとに1つの頂点バッファーを数千回更新しています。「スプライト」を描画するたびに、テクスチャ座標などを使用して4つの頂点をGPUに送信し、画面上の「スプライト」の数が一度に約1k〜1.5kに達すると、アプリのFPSは次のように低下します。 10fps未満。
VS2012パフォーマンス分析(これは素晴らしいですが)を使用すると、ID3D11DeviceContext->Drawメソッドが大部分の時間を占めていることがわかります。 スクリーンショットはこちら
頂点バッファの設定中、または描画メソッド中に正しく使用していない設定はありますか?すべてのスプライトに同じ頂点バッファーを使用するのは本当に本当に悪いことですか?もしそうなら、既存のグラフィックコードベースのアーキテクチャを大幅に変更しない他のオプションはありますか(OpenGLパラダイムを中心に構築されています...すべてをフレームごとにGPUに送信してください!)
私のゲームで最大のFPSキラーは、画面に大量のテキストを表示しているときです。各文字はテクスチャクワッドであり、各文字には頂点バッファへの個別の更新とDrawへの個別の呼び出しが必要です。D3DまたはハードウェアがDrawの多くの呼び出しを好まない場合、他にどのようにして一度に多くのテキストを画面に描画できますか?
この問題の診断に役立つコードが他にあるかどうかをお知らせください。
ありがとう!
これが私が実行しているハードウェアです:
- Core i7 @ 3.5GHz
- 16ギガのRAM
- GeForce GTX 560 Ti
そして、これが私が実行しているソフトウェアです:
- Windows8リリースプレビュー
- VS 2012
- DirectX 11
描画方法は次のとおりです。
void OpenGL::Draw(const std::vector<OpenGLVertex>& vertices)
{
auto matrix = *_matrices.top();
_constantBufferData.view = DirectX::XMMatrixTranspose(matrix);
_context->UpdateSubresource(_constantBuffer, 0, NULL, &_constantBufferData, 0, 0);
_context->IASetInputLayout(_inputLayout);
_context->VSSetShader(_vertexShader, nullptr, 0);
_context->VSSetConstantBuffers(0, 1, &_constantBuffer);
D3D11_PRIMITIVE_TOPOLOGY topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
ID3D11ShaderResourceView* texture = _textures[_currentTextureId];
// Set shader texture resource in the pixel shader.
_context->PSSetShader(_pixelShaderTexture, nullptr, 0);
_context->PSSetShaderResources(0, 1, &texture);
D3D11_MAPPED_SUBRESOURCE mappedResource;
D3D11_MAP mapType = D3D11_MAP::D3D11_MAP_WRITE_DISCARD;
auto hr = _context->Map(_vertexBuffer, 0, mapType, 0, &mappedResource);
if (SUCCEEDED(hr))
{
OpenGLVertex *pData = reinterpret_cast<OpenGLVertex *>(mappedResource.pData);
memcpy(&(pData[_currentVertex]), &vertices[0], sizeof(OpenGLVertex) * vertices.size());
_context->Unmap(_vertexBuffer, 0);
}
UINT stride = sizeof(OpenGLVertex);
UINT offset = 0;
_context->IASetVertexBuffers(0, 1, &_vertexBuffer, &stride, &offset);
_context->IASetPrimitiveTopology(topology);
_context->Draw(vertices.size(), _currentVertex);
_currentVertex += (int)vertices.size();
}
そして、頂点バッファを作成するメソッドは次のとおりです。
void OpenGL::CreateVertexBuffer()
{
D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(bd));
bd.Usage = D3D11_USAGE_DYNAMIC;
bd.ByteWidth = _maxVertices * sizeof(OpenGLVertex);
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = D3D11_CPU_ACCESS_FLAG::D3D11_CPU_ACCESS_WRITE;
bd.MiscFlags = 0;
bd.StructureByteStride = 0;
D3D11_SUBRESOURCE_DATA initData;
ZeroMemory(&initData, sizeof(initData));
_device->CreateBuffer(&bd, NULL, &_vertexBuffer);
}
これが私の頂点シェーダーコードです:
cbuffer ModelViewProjectionConstantBuffer : register(b0)
{
matrix model;
matrix view;
matrix projection;
};
struct VertexShaderInput
{
float3 pos : POSITION;
float4 color : COLOR0;
float2 tex : TEXCOORD0;
};
struct VertexShaderOutput
{
float4 pos : SV_POSITION;
float4 color : COLOR0;
float2 tex : TEXCOORD0;
};
VertexShaderOutput main(VertexShaderInput input)
{
VertexShaderOutput output;
float4 pos = float4(input.pos, 1.0f);
// Transform the vertex position into projected space.
pos = mul(pos, model);
pos = mul(pos, view);
pos = mul(pos, projection);
output.pos = pos;
// Pass through the color without modification.
output.color = input.color;
output.tex = input.tex;
return output;
}