I want to capture game in Native code using DirectX capture. I use staging buffer to capture the screen. But I only get black screen after capture. Any input on what I am doing wrong in code attached?
// Check out http://docs.unity3d.com/Documentation/Manual/NativePluginInterface.html
// for additional documentation about this process.
#include "UnityPlugin.h"
#include "GraphicsInclude.h"
#if _WIN32
#include "Capture/DXCapture.h"
#include <d3d11.h>
#include <DXGI.h>
#endif
#include <string>
#include <iostream>
#if _WIN32
// DirectX states
ID3D11Device* g_d3d_Device;
ID3D11DeviceContext* g_d3d_DeviceContext;
ID3D11RenderTargetView* g_renderTargetView[1];
ID3D11Texture2D* g_backBuffer;
#endif
// For now width and height are hardcoded
int width = 1280;
int height = 720;
int bpp = 4;
#pragma once
#pragma warning (push)
#if _MSC_VER && !__INTEL_COMPILER
// Disable warnings about macro re-definitions if we're using the DX SDK
// http://stackoverflow.com/questions/19336841/i-get-a-lot-of-macro-redefinition-when-using-directx-10
#pragma warning (disable: 4005)
#endif
#if _WIN32
#include <d3d11.h>
#endif
#pragma warning (pop)
typedef void(*FuncPtr)(const char *);
FuncPtr Debug;
static void DebugLog (const char* str)
{
#if UNITY_WIN
OutputDebugStringA (str);
//Debug(str);
#else
printf ("%s", str);
#endif
}
extern "C"
{
EXPORT_API void SetDebugFunction(FuncPtr fp)
{
Debug = fp;
}
}
// If exported by a plugin, this function will be called when graphics device is created, destroyed,
// and before and after it is reset (ie, resolution changed).
extern "C" void EXPORT_API UnitySetGraphicsDevice( void* device, int deviceType, int eventType )
{
char log[256];
#if _WIN32
ID3D11DepthStencilView* depthViews[1];
ID3D11Resource* targetResource;
D3D11_RENDER_TARGET_VIEW_DESC targetView;
// Assign default values.
g_d3d_Device = (ID3D11Device*)device;
g_d3d_Device->GetImmediateContext(&g_d3d_DeviceContext);
g_d3d_DeviceContext->OMGetRenderTargets(1, g_renderTargetView, depthViews);
if (g_renderTargetView[0] == nullptr){
DebugLog("No debug target view found\n");
}
g_renderTargetView[0]->GetResource(&targetResource);
g_renderTargetView[0]->GetDesc(&targetView);
sprintf(log, "Format is %d\n", targetView.Format);
DebugLog(log);
// Try to initialize screen capture methods.
// We try them explicitly one by one until we find one that works
DebugLog("Trying DirectX capture method\n");
g_screenCapture = new DXCapture(g_d3d_Device, g_d3d_DeviceContext, targetResource, width, height, targetView.Format);
if (!g_screenCapture->supported())
{
DebugLog("Cannot initialize DirectX capture method\n");
delete g_screenCapture;
g_screenCapture = NULL;
}
else
{
DebugLog("Using DirectX Capture method\n");
goto foundCaptureMethod;
}
// at this point, couldn't find any capture methods
DebugLog("Could not initialize any capture methods");
foundCaptureMethod:
DebugLog("Initialize capture methods");
#endif
}
// If exported by a plugin, this function will be called for GL.IssuePluginEvent script calls.
// The function will be called on a rendering thread; note that when multithreaded rendering is used,
// the rendering thread WILL BE DIFFERENT from the thread that all scripts & other game logic happens!
// You have to ensure any synchronization with other plugin script calls is properly done by you.
extern "C" void EXPORT_API UnityRenderEvent ( int eventID )
{
// Capture the frame using our current capture method
const unsigned char* theFrame = g_screenCapture->capture();
g_screenCapture->endCapture(); // Done with capture data
}
DXCapture.cpp
#include "DXCapture.h"
DXCapture::smile:XCapture(ID3D11Device* d3DDevice, ID3D11DeviceContext* d3DDeviceContext,
ID3D11Resource* backbuffer,
int backbufferWidth, int backbufferHeight,
DXGI_FORMAT format)
: _d3D11Device(d3DDevice),
_d3D11DeviceContext(d3DDeviceContext),
_backbuffer(backbuffer),
_backbufferWidth(backbufferWidth),
_backbufferHeight(backbufferHeight),
_format(format)
{
}
bool DXCapture::supported()
{
try
{
// Create a staging resource
D3D11_TEXTURE2D_DESC stagingTextureDesc;
stagingTextureDesc.Width = _backbufferWidth;
stagingTextureDesc.Height = _backbufferHeight;
stagingTextureDesc.MipLevels = stagingTextureDesc.ArraySize = 1;
//stagingTextureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
stagingTextureDesc.Format = _format;
stagingTextureDesc.SampleDesc.Count = 1;
stagingTextureDesc.SampleDesc.Quality = 0;
stagingTextureDesc.Usage = D3D11_USAGE_STAGING;
stagingTextureDesc.BindFlags = 0;
stagingTextureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
stagingTextureDesc.MiscFlags = 0;
if (!SUCCEEDED(_d3D11Device->CreateTexture2D(&stagingTextureDesc, NULL, &_stagingBuffer)))
return false;
return true;
}
catch (...)
{
return false; // Something went wrong, we can't set up DX capture
}
}
CapturePixelFormat DXCapture::getCapturePixelFormat()
{
return CAPTURE_PIXELFORMAT_R8G8B8A8; // Always
}
const unsigned char* DXCapture::capture()
{
// Copy the frame to the staging buffer
_d3D11DeviceContext->CopyResource(_stagingBuffer, _backbuffer);
// Lock the staging buffer and post it to the host app for encoding
D3D11_MAPPED_SUBRESOURCE mappedBuffer;
HRESULT bufferMapResult = _d3D11DeviceContext->Map(_stagingBuffer, 0, D3D11_MAP_READ, 0, &mappedBuffer);
if (SUCCEEDED(bufferMapResult))
{
unsigned char* pixel_bytes = (unsigned char*)mappedBuffer.pData;
return pixel_bytes;
}
return NULL;
}
void DXCapture::endCapture()
{
// Unmap this buffer, the application is done with the capture
_d3D11DeviceContext->Unmap(_stagingBuffer, 0);
}
DXCapture::~DXCapture()
{
if (_stagingBuffer != NULL)
{
_stagingBuffer->Release();
_stagingBuffer = NULL;
}
}