はかせのラボ

私の頭の中を書いていく雑記ブログです

プログラミング インスタンシング導入したらメモリリークした・・・

あいさつ

どうも、はかせです。
今回は前回複数テクスチャ使ったインスタンシングができるようになったので
以前作った弾幕に入れてみた話です。

実装

今回実装は極めて単純に
描画データをまとめた構造体を定義し、
その構造体を管理クラスに投げて描画します。

//テクスチャ情報を保持
struct TEXTURE_DATA
{
	std::wstring fileName;
	ComPtr<ID3D11Resource> texture;
	ComPtr<ID3D11ShaderResourceView> shaderView;
};

struct RENDER_TEXTURE_DATA
{
	TEXTURE_DATA* textureData = nullptr;
	int drawNumber = 0;
	DirectX::XMMATRIX renderMatrix;
	DirectX::XMVECTOR renderColor;
	ComPtr<ID3D11VertexShader> vertexShader = nullptr;
	ComPtr<ID3D11PixelShader> pixelShader = nullptr;
	ComPtr<ID3D11Buffer> vertexBuffer = nullptr;
	ComPtr<ID3D11Buffer> indexBuffer = nullptr;
	ComPtr<ID3D11InputLayout> inputLayout = nullptr;
	ID3D11DepthStencilState* depthStencilState = nullptr;
	ComPtr<ID3D11SamplerState> samplerState = nullptr;
	ComPtr<ID3D11RasterizerState> rasterizeState = nullptr;
	D3D11_PRIMITIVE_TOPOLOGY topology;
	bool isAlphaBlend = false;
	UINT stride = 0;
	UINT offset = 0;
	~RENDER_TEXTURE_DATA() 
	{
		vertexBuffer.Reset();
		vertexShader.Reset();
		pixelShader.Reset();
		indexBuffer.Reset();
		inputLayout.Reset();
		depthStencilState = nullptr;
		samplerState.Reset();
		rasterizeState.Reset();
	};
};
void MyDirectX::DXRenderManager::Render()
{
	//インスタンスデータ用バッファの設定
	D3D11_BUFFER_DESC bd_instance;
	bd_instance.Usage = D3D11_USAGE_DYNAMIC;
	bd_instance.ByteWidth = sizeof(PerInstanceData) * mRenderDatas.capacity();
	bd_instance.BindFlags = D3D11_BIND_SHADER_RESOURCE;
	bd_instance.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
	bd_instance.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
	bd_instance.StructureByteStride = sizeof(PerInstanceData);
	mDevice->CreateBuffer(&bd_instance, NULL, &mPerInstanceBuffer);
	//インスタンス用のリソースビューを作成
	D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
	ZeroMemory(&srvDesc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
	srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX;
	srvDesc.BufferEx.FirstElement = 0;
	srvDesc.Format = DXGI_FORMAT_UNKNOWN;
	srvDesc.BufferEx.NumElements = mRenderDatas.capacity();
	mDevice->CreateShaderResourceView(mPerInstanceBuffer.Get(), &srvDesc, &mShaderResourceView);

	// パラメータの受け渡し
	D3D11_MAPPED_SUBRESOURCE pdata;
	PerInstanceData* instanceData = nullptr;
	std::set<std::wstring> fileNames;
	std::map <std::wstring, std::vector<RENDER_TEXTURE_DATA*>> splitData;
	//各テクスチャ毎に描画データをまとめる
	for (auto render : mRenderDatas)
	{
		splitData[render->textureData->fileName].push_back(render);
		fileNames.insert(render->textureData->fileName);
	}
	for(auto fileName:fileNames)
	{
		//各テクスチャ毎に描画する
		for(auto render:splitData[fileName])
		{
			mDeviceContext->IASetVertexBuffers(0, 1, render->vertexBuffer.GetAddressOf(), &render->stride, &render->offset);
			//インデックスバッファーの設定
			mDeviceContext->IASetIndexBuffer(render->indexBuffer.Get(), DXGI_FORMAT_R32_UINT, render->offset);
			//入力レイアウト設定
			mDeviceContext->IASetInputLayout(render->inputLayout.Get());
			//頂点情報の解釈の仕方を設定
			mDeviceContext->IASetPrimitiveTopology(render->topology);

			int instanceCount = splitData[fileName].capacity();
			mDeviceContext->VSSetShader(render->vertexShader.Get(), NULL, 0);
			mDeviceContext->PSSetShader(render->pixelShader.Get(), NULL, 0);
			mDeviceContext->PSSetSamplers(0, 1, render->samplerState.GetAddressOf());
			mDeviceContext->Map(mPerInstanceBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &pdata);
			instanceData = (PerInstanceData*)(pdata.pData);
			for (int i = 0; i < instanceCount; i++)
			{
				//行列情報をセット
				instanceData[i].renderMatrix = render->renderMatrix;
				//色情報をセット
				instanceData[i].renderColor = render->renderColor;
			}
			mDeviceContext->Unmap(mPerInstanceBuffer.Get(), 0);
			mDeviceContext->VSSetShaderResources(0, 1, mShaderResourceView.GetAddressOf());
			ID3D11ShaderResourceView* srv[] = { mShaderResourceView.Get() ,render->textureData->shaderView.Get() };
			mDeviceContext->PSSetShaderResources(0, 2, srv);
			mDeviceContext->OMSetDepthStencilState(render->depthStencilState, 0);
			mManager->OMSetBlendState(render->isAlphaBlend);
			// 描画実行
			mDeviceContext->DrawIndexedInstanced(render->drawNumber, instanceCount, 0, 0, 0);
		}
	}
	std::vector<RENDER_TEXTURE_DATA*> swapVector;
	mRenderDatas.swap(swapVector);
	splitData.clear();
	fileNames.clear();
	mRenderDatas.clear();
}

void MyDirectX::DXRenderManager::PushRenderData(RENDER_TEXTURE_DATA* renderData)
{
	mRenderDatas.push_back(renderData);
}

これでデータをまとめて一括で描画することに成功しました。

全部うまくいくことなんてありえない

f:id:hakase0274:20190626233509p:plain
ぎゃー!!!

_(:3 」∠)_瀕死

な、なんでだ・・・?
今回各種ポインタはComPtrにして管理を自動化しているのに・・・
しかも軒並みRefcount0だし・・・・

あとがき

今回はインスタンシング導入してやったー
からの
メモリリークして_(:3 」∠)_瀕死 でした。

ComPtrってようはスマートポインタみたく参照カウント持って
それが0になったらReleseしてくれると思ってたんですけど違うんですかね?
それとも参照カウントの認識自体間違ってる?

うーんわからん・・・orz
またググる&テストの時間ですね。
(最悪ほぼ全改修なんてこともあるかも・・・)

それでは今回はこの辺でノシ