Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Capture unity screen in native code using DirectX capture

Discussion in 'Editor & General Support' started by ranjan_rishi, Aug 13, 2015.

  1. ranjan_rishi

    ranjan_rishi

    Joined:
    Dec 1, 2014
    Posts:
    9
    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?

    Code (C++):
    1. // Check out http://docs.unity3d.com/Documentation/Manual/NativePluginInterface.html
    2. // for additional documentation about this process.
    3.  
    4. #include "UnityPlugin.h"
    5. #include "GraphicsInclude.h"
    6.  
    7. #if _WIN32
    8. #include "Capture/DXCapture.h"
    9. #include <d3d11.h>
    10. #include <DXGI.h>
    11. #endif
    12.  
    13.  
    14. #include <string>
    15. #include <iostream>
    16.  
    17.  
    18. #if _WIN32
    19. // DirectX states
    20. ID3D11Device* g_d3d_Device;
    21. ID3D11DeviceContext* g_d3d_DeviceContext;
    22. ID3D11RenderTargetView* g_renderTargetView[1];
    23. ID3D11Texture2D* g_backBuffer;
    24. #endif
    25.  
    26. // For now width and height are hardcoded
    27. int width = 1280;
    28. int height = 720;
    29. int bpp = 4;
    30.  
    31. #pragma once
    32.  
    33. #pragma warning (push)
    34.  
    35. #if _MSC_VER && !__INTEL_COMPILER
    36. // Disable warnings about macro re-definitions if we're using the DX SDK
    37. // http://stackoverflow.com/questions/19336841/i-get-a-lot-of-macro-redefinition-when-using-directx-10
    38. #pragma warning (disable: 4005)
    39. #endif
    40.  
    41. #if _WIN32
    42. #include <d3d11.h>
    43. #endif
    44.  
    45. #pragma warning (pop)
    46.  
    47. typedef void(*FuncPtr)(const char *);
    48.  
    49. FuncPtr Debug;
    50.  
    51. static void DebugLog (const char* str)
    52. {
    53. #if UNITY_WIN
    54.     OutputDebugStringA (str);  
    55.     //Debug(str);
    56. #else
    57.     printf ("%s", str);
    58. #endif
    59. }
    60.  
    61. extern "C"
    62. {
    63.     EXPORT_API void SetDebugFunction(FuncPtr fp)
    64.     {
    65.         Debug = fp;
    66.     }
    67. }
    68.  
    69. // If exported by a plugin, this function will be called when graphics device is created, destroyed,
    70. // and before and after it is reset (ie, resolution changed).
    71. extern "C" void EXPORT_API UnitySetGraphicsDevice( void* device, int deviceType, int eventType )
    72. {
    73.     char log[256];
    74.  
    75. #if _WIN32
    76.     ID3D11DepthStencilView* depthViews[1];
    77.     ID3D11Resource* targetResource;
    78.     D3D11_RENDER_TARGET_VIEW_DESC targetView;
    79.     // Assign default values.
    80.     g_d3d_Device = (ID3D11Device*)device;
    81.     g_d3d_Device->GetImmediateContext(&g_d3d_DeviceContext);
    82.  
    83.     g_d3d_DeviceContext->OMGetRenderTargets(1, g_renderTargetView, depthViews);
    84.  
    85.     if (g_renderTargetView[0] == nullptr){
    86.         DebugLog("No debug target view found\n");
    87.     }
    88.  
    89.     g_renderTargetView[0]->GetResource(&targetResource);
    90.  
    91.     g_renderTargetView[0]->GetDesc(&targetView);
    92.  
    93.     sprintf(log, "Format is %d\n", targetView.Format);
    94.     DebugLog(log);
    95.  
    96.     // Try to initialize screen capture methods.
    97.     // We try them explicitly one by one until we find one that works
    98.  
    99.     DebugLog("Trying DirectX capture method\n");
    100.     g_screenCapture = new DXCapture(g_d3d_Device, g_d3d_DeviceContext, targetResource, width, height, targetView.Format);
    101.     if (!g_screenCapture->supported())
    102.     {
    103.         DebugLog("Cannot initialize DirectX capture method\n");
    104.         delete g_screenCapture;
    105.         g_screenCapture = NULL;
    106.     }
    107.     else
    108.     {
    109.         DebugLog("Using DirectX Capture method\n");
    110.         goto foundCaptureMethod;
    111.     }
    112.  
    113.     // at this point, couldn't find any capture methods
    114.     DebugLog("Could not initialize any capture methods");
    115.  
    116. foundCaptureMethod:
    117.     DebugLog("Initialize capture methods");
    118.  
    119. #endif
    120.  
    121.  
    122. }
    123.  
    124.  
    125. // If exported by a plugin, this function will be called for GL.IssuePluginEvent script calls.
    126. // The function will be called on a rendering thread; note that when multithreaded rendering is used,
    127. // the rendering thread WILL BE DIFFERENT from the thread that all scripts & other game logic happens!
    128. // You have to ensure any synchronization with other plugin script calls is properly done by you.
    129. extern "C" void EXPORT_API UnityRenderEvent ( int eventID )
    130. {
    131.  
    132.         // Capture the frame using our current capture method
    133.         const unsigned char* theFrame = g_screenCapture->capture();
    134.         g_screenCapture->endCapture(); // Done with capture data
    135.  
    136. }
    137.  
    138.  
    DXCapture.cpp
    Code (C++):
    1.  
    2.  
    3. #include "DXCapture.h"
    4.  
    5. DXCapture::DXCapture(ID3D11Device* d3DDevice, ID3D11DeviceContext* d3DDeviceContext,
    6.                                          ID3D11Resource* backbuffer,
    7.                      int backbufferWidth, int backbufferHeight,
    8.                                          DXGI_FORMAT format)
    9.     : _d3D11Device(d3DDevice),
    10.       _d3D11DeviceContext(d3DDeviceContext),
    11.       _backbuffer(backbuffer),
    12.       _backbufferWidth(backbufferWidth),
    13.       _backbufferHeight(backbufferHeight),
    14.           _format(format)
    15. {
    16. }
    17.  
    18. bool DXCapture::supported()
    19. {
    20.     try
    21.     {
    22.         // Create a staging resource
    23.         D3D11_TEXTURE2D_DESC stagingTextureDesc;
    24.         stagingTextureDesc.Width = _backbufferWidth;
    25.         stagingTextureDesc.Height = _backbufferHeight;
    26.         stagingTextureDesc.MipLevels = stagingTextureDesc.ArraySize = 1;
    27.         //stagingTextureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    28.                 stagingTextureDesc.Format = _format;
    29.         stagingTextureDesc.SampleDesc.Count = 1;
    30.         stagingTextureDesc.SampleDesc.Quality = 0;
    31.         stagingTextureDesc.Usage = D3D11_USAGE_STAGING;
    32.         stagingTextureDesc.BindFlags = 0;
    33.         stagingTextureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
    34.         stagingTextureDesc.MiscFlags = 0;
    35.  
    36.         if (!SUCCEEDED(_d3D11Device->CreateTexture2D(&stagingTextureDesc, NULL, &_stagingBuffer)))
    37.             return false;
    38.  
    39.         return true;
    40.     }
    41.     catch (...)
    42.     {
    43.         return false; // Something went wrong, we can't set up DX capture
    44.     }
    45. }
    46.  
    47. CapturePixelFormat DXCapture::getCapturePixelFormat()
    48. {
    49.     return CAPTURE_PIXELFORMAT_R8G8B8A8; // Always
    50. }
    51.  
    52. const unsigned char* DXCapture::capture()
    53. {
    54.     // Copy the frame to the staging buffer
    55.     _d3D11DeviceContext->CopyResource(_stagingBuffer, _backbuffer);
    56.  
    57.     // Lock the staging buffer and post it to the host app for encoding
    58.     D3D11_MAPPED_SUBRESOURCE mappedBuffer;
    59.     HRESULT bufferMapResult = _d3D11DeviceContext->Map(_stagingBuffer, 0, D3D11_MAP_READ, 0, &mappedBuffer);
    60.     if (SUCCEEDED(bufferMapResult))
    61.     {
    62.         unsigned char* pixel_bytes = (unsigned char*)mappedBuffer.pData;
    63.         return pixel_bytes;
    64.     }
    65.  
    66.     return NULL;
    67. }
    68.  
    69. void DXCapture::endCapture()
    70. {
    71.     // Unmap this buffer, the application is done with the capture
    72.     _d3D11DeviceContext->Unmap(_stagingBuffer, 0);
    73. }
    74.  
    75. DXCapture::~DXCapture()
    76. {
    77.     if (_stagingBuffer != NULL)
    78.     {
    79.         _stagingBuffer->Release();
    80.         _stagingBuffer = NULL;
    81.     }
    82. }
    83.  
    84.  
     
  2. ranjan_rishi

    ranjan_rishi

    Joined:
    Dec 1, 2014
    Posts:
    9
    I know the issues. I should us D3D11_RTV_DIMENSION_TEXTURE2D for copyresource.
     
  3. ranjan_rishi

    ranjan_rishi

    Joined:
    Dec 1, 2014
    Posts:
    9
  4. weir75034

    weir75034

    Joined:
    Aug 24, 2018
    Posts:
    1
    I try your method and use ScreenGrab, here is the code:
    Code (CSharp):
    1. void App3Main::SaveScreenshot()
    2. {
    3.     auto file = ref new Platform::String(Windows::Storage::ApplicationData::Current->TemporaryFolder->Path->Data()) + "\\Screenshot.png";
    4.  
    5.  
    6.  
    7.     /*
    8.     ComPtr<ID3D11Texture2D> backBuffer;
    9.     DX::ThrowIfFailed(m_deviceResources->GetSwapChain()->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&backBuffer));
    10.     */
    11.  
    12.     ID3D11RenderTargetView* targets[] = { nullptr, nullptr };
    13.     m_sceneRenderer->GetContext()->OMGetRenderTargets(ARRAYSIZE(targets), targets, nullptr);
    14.     D3D11_RENDER_TARGET_VIEW_DESC targetView;
    15.     targets[0]->GetDesc(&targetView);
    16.     ID3D11Resource* targetResource;
    17.     targets[0]->GetResource(&targetResource);
    18.  
    19.     auto hResult = SaveWICTextureToFile(m_sceneRenderer->GetContext(), targetResource, GUID_ContainerFormatPng, file->Data());
    20. }
    Eventually, I succeeded. Good luck!!!