I am writing a universal overlay app (not a cheat) for DX11 fullscreen applications.
I am a complete newbie in DX11 and try to catch up fast as I am under time pressure with the project. Hoping for your help.
I am injecting a dll and hooking DX11 Present(), it seems to work quite good.
Using the swapchain from Present() I can obtain Window handler, Device and Context.
I lack a lot understanding, trying to crawl my way through existing code, tutorials and docs.
My current approach was a demo "overlay", I wanted to draw a triangle and overlay it on the existing scene.
Right now I seem to erase all existing stuff instead of overlaying.
My first goal is to overlay a simple rectangular box and add an existing image as texture on it. Any help regarding that goal would be very much appreciated.
Here my current demo overlay function which gets called in the Present() hook. The DX11 object is a structure containing the stuff I collected from the Present() swapchain (the game swapchain).
void draw_simple_test()
{
ID3D11InputLayout* g_pInputLayout = NULL;
ID3D11Buffer* g_pVertexBuffer = NULL;
ID3D11RenderTargetView* g_pRenderTargetView = NULL;
ID3D11VertexShader* g_pVertexShader = NULL;
ID3D11PixelShader* g_pPixelShader = NULL;
HRESULT hr = S_OK;
CHAR* g_strVS =
"void VS( in float4 posIn : POSITION,\n"
" out float4 posOut : SV_Position )\n"
"{\n"
" // Output the vertex position, unchanged\n"
" posOut = posIn;\n"
"}\n";
CHAR* g_strPS =
"void PS( out float4 colorOut : SV_Target )\n"
"{\n"
" // Make each pixel yellow, with alpha = 1\n"
" colorOut = float4( 1.0f, 1.0f, 1.0f, 1.0f );\n"
"}\n";
// Create the render target view
ID3D11Texture2D* pRenderTargetTexture;
hr = DX11.SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pRenderTargetTexture);
if (FAILED(hr))
return; //hr
hr = DX11.Device->CreateRenderTargetView(pRenderTargetTexture, NULL, &g_pRenderTargetView);
pRenderTargetTexture->Release();
float ClearColor[4] = { 1.0f, 0.125f, 0.3f, 1.0f }; // red, green, blue, alpha
//DX11.BackBufferRT
//DX11.Context->ClearRenderTargetView(g_pRenderTargetView, ClearColor); // clear whole view to color
DWORD dwShaderFlags = D3D10_SHADER_ENABLE_STRICTNESS;
ID3D10Blob* pBlobVS = NULL;
ID3D10Blob* pBlobError = NULL;
hr = D3DCompile(g_strVS, lstrlenA(g_strVS) + 1, "VS", NULL, NULL, "VS",
"vs_4_0", dwShaderFlags, 0, &pBlobVS, &pBlobError);
if (FAILED(hr))
{
if (pBlobError != NULL)
{
OutputDebugStringA((CHAR*)pBlobError->GetBufferPointer());
pBlobError->Release();
}
return ;//hr
}
hr = DX11.Device->CreateVertexShader(pBlobVS->GetBufferPointer(), pBlobVS->GetBufferSize(),
NULL, &g_pVertexShader);
if (FAILED(hr))
return ; //hr
// Compile and create the pixel shader
ID3D10Blob* pBlobPS = NULL;
hr = D3DCompile(g_strPS, lstrlenA(g_strPS) + 1, "PS", NULL, NULL, "PS",
"ps_4_0", dwShaderFlags, 0, &pBlobPS, &pBlobError);
if (FAILED(hr))
{
if (pBlobError != NULL)
{
OutputDebugStringA((CHAR*)pBlobError->GetBufferPointer());
pBlobError->Release();
}
return; //hr
}
hr = DX11.Device->CreatePixelShader(pBlobPS->GetBufferPointer(), pBlobPS->GetBufferSize(),
NULL, &g_pPixelShader);
if (FAILED(hr))
return ;//hr
pBlobPS->Release();
// Create the input layout
D3D11_INPUT_ELEMENT_DESC elements[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
UINT numElements = _countof(elements);
hr = DX11.Device->CreateInputLayout(elements, numElements, pBlobVS->GetBufferPointer(),
pBlobVS->GetBufferSize(), &g_pInputLayout);
if (FAILED(hr))
return ;
pBlobVS->Release();
SimpleVertex vertices[] =
{
0.0f, 0.2f, 0.2f, // top
0.5f, -0.5f, 0.5f, // left
-0.5f, -0.5f, 0.5f, // right
};
D3D11_BUFFER_DESC bd;
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof(vertices);
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = 0;
bd.MiscFlags = 0;
bd.StructureByteStride = 0;
D3D11_SUBRESOURCE_DATA initData;
initData.pSysMem = vertices;
hr = DX11.Device->CreateBuffer(&bd, &initData, &g_pVertexBuffer);
if (FAILED(hr))
return ;//hr
// ---
// zuweisen
DX11.Context->IASetInputLayout(g_pInputLayout);
UINT stride = sizeof(SimpleVertex);
UINT offset = 0;
DX11.Context->IASetVertexBuffers(0, 1, &g_pVertexBuffer, &stride, &offset);
DX11.Context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
DX11.Context->VSSetShader(g_pVertexShader, NULL, 0);
DX11.Context->PSSetShader(g_pPixelShader, NULL, 0);
RECT rc;
GetClientRect(DX11.Window, &rc);
D3D11_VIEWPORT vp;
vp.Width = (FLOAT)(rc.right - rc.left);
vp.Height = (FLOAT)(rc.bottom - rc.top);
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
DX11.Context->RSSetViewports(1, &vp);
DX11.Context->OMSetRenderTargets(1, &g_pRenderTargetView, NULL);
DX11.Context->Draw(3, 0); //3 vertices start at 0
//cleanup
}
What am I doing wrong ?
I guess I made more than one error considering I am injecting this function after the game already prepared everything.
Should I use the swapchain from the game? Create an own second one?
I'm a bit (much) lost.
It's solved, took me quite a while but the problem was indeed that buffers where damaged. It's quite obvious, I think I could not see that earlier because all the new DX stuff overwhelmed me.
This did it for me (and should hold for a while): To minimize impact you can only take those functions that you actually use in your own drawing code.
m_pContext->AddRef();
m_pContext->IAGetPrimitiveTopology(&m_primitiveTopology);
m_pContext->IAGetInputLayout(&m_pInputLayout);
m_pContext->OMGetBlendState(&m_pBlendState, m_blendFactor, &m_sampleMask);
m_pContext->OMGetDepthStencilState(&m_pDepthStencilState, &m_stencilRef);
m_pContext->RSGetState(&m_pRasterizerState);
m_pContext->VSGetShader(&m_pVS, 256, &m_numVSClassInstances);
m_pContext->VSGetConstantBuffers(0, 4, m_pVSConstantBuffer);
m_pContext->PSGetShader(&m_pPS, 256, &m_numPSClassInstances);
m_pContext->PSGetShaderResources(0, 9, m_pPSSRV);
pContext->PSGetSamplers(0, 10, m_pSamplerState);
m_pContext->PSGetConstantBuffers(0, 3, m_ppConstantBuffers);
m_pContext->OMGetRenderTargetsAndUnorderedAccessViews(2, m_RTView, &m_DepthView, 0, 0, NULL);
m_pContext->RSGetViewports(&m_numViewports, m_RSViewports);
m_pContext->GSGetShader(&m_pGS, 256, &m_numGSClassInstances);
m_pContext->GSGetConstantBuffers(0, 2, m_pGSConstantBuffer);
m_pContext->GSGetShaderResources(0, 1, &m_pGSSRV);
m_pContext->HSGetShader(&m_pHS, 256, &m_numHSClassInstances);
m_pContext->DSGetShader(&m_pDS, 256, &m_numDSClassInstances);
m_pContext->DSGetSamplers(0, 3, m_dSSamplers);
m_pContext->IAGetVertexBuffers(0, 3, m_pVB, m_vertexStride, m_vertexOffset);
m_pContext->IAGetIndexBuffer(&m_pIndexBuffer, &m_indexFormat, &m_indexOffset);
The 'set' functions need to be called upon "release" to restore the buffers. Just pick the functions you actually use, in a simple example it will be 5-6 lines of code.