summaryrefslogtreecommitdiffstats
path: root/xbmc/rendering/dx/ScreenshotSurfaceWindows.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/rendering/dx/ScreenshotSurfaceWindows.cpp')
-rw-r--r--xbmc/rendering/dx/ScreenshotSurfaceWindows.cpp110
1 files changed, 110 insertions, 0 deletions
diff --git a/xbmc/rendering/dx/ScreenshotSurfaceWindows.cpp b/xbmc/rendering/dx/ScreenshotSurfaceWindows.cpp
new file mode 100644
index 0000000..7a62ad6
--- /dev/null
+++ b/xbmc/rendering/dx/ScreenshotSurfaceWindows.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "ScreenshotSurfaceWindows.h"
+
+#include "ServiceBroker.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIWindowManager.h"
+#include "rendering/dx/DeviceResources.h"
+#include "utils/Screenshot.h"
+#include "utils/log.h"
+#include "windowing/GraphicContext.h"
+
+#include <mutex>
+
+#include <wrl/client.h>
+
+using namespace Microsoft::WRL;
+
+void CScreenshotSurfaceWindows::Register()
+{
+ CScreenShot::Register(CScreenshotSurfaceWindows::CreateSurface);
+}
+
+std::unique_ptr<IScreenshotSurface> CScreenshotSurfaceWindows::CreateSurface()
+{
+ return std::unique_ptr<CScreenshotSurfaceWindows>(new CScreenshotSurfaceWindows());
+}
+
+bool CScreenshotSurfaceWindows::Capture()
+{
+ CWinSystemBase* winsystem = CServiceBroker::GetWinSystem();
+ if (!winsystem)
+ return false;
+
+ CGUIComponent* gui = CServiceBroker::GetGUI();
+ if (!gui)
+ return false;
+
+ std::unique_lock<CCriticalSection> lock(winsystem->GetGfxContext());
+ gui->GetWindowManager().Render();
+
+ auto deviceResources = DX::DeviceResources::Get();
+ deviceResources->FinishCommandList();
+
+ ComPtr<ID3D11DeviceContext> pImdContext = deviceResources->GetImmediateContext();
+ ComPtr<ID3D11Device> pDevice = deviceResources->GetD3DDevice();
+ CD3DTexture& backbuffer = deviceResources->GetBackBuffer();
+ if (!backbuffer.Get())
+ return false;
+
+ D3D11_TEXTURE2D_DESC desc = {};
+ backbuffer.GetDesc(&desc);
+ desc.Usage = D3D11_USAGE_STAGING;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
+ desc.BindFlags = 0;
+
+ ComPtr<ID3D11Texture2D> pCopyTexture = nullptr;
+ if (SUCCEEDED(pDevice->CreateTexture2D(&desc, nullptr, &pCopyTexture)))
+ {
+ // take copy
+ pImdContext->CopyResource(pCopyTexture.Get(), backbuffer.Get());
+
+ D3D11_MAPPED_SUBRESOURCE res;
+ if (SUCCEEDED(pImdContext->Map(pCopyTexture.Get(), 0, D3D11_MAP_READ, 0, &res)))
+ {
+ m_width = desc.Width;
+ m_height = desc.Height;
+ m_stride = res.RowPitch;
+ m_buffer = new unsigned char[m_height * m_stride];
+ if (desc.Format == DXGI_FORMAT_R10G10B10A2_UNORM)
+ {
+ // convert R10G10B10A2 -> B8G8R8A8
+ for (int y = 0; y < m_height; y++)
+ {
+ uint32_t* pixels10 = reinterpret_cast<uint32_t*>(static_cast<uint8_t*>(res.pData) + y * res.RowPitch);
+ uint8_t* pixels8 = m_buffer + y * m_stride;
+
+ for (int x = 0; x < m_width; x++, pixels10++, pixels8 += 4)
+ {
+ // actual bit per channel is A2B10G10R10
+ uint32_t pixel = *pixels10;
+ // R
+ pixels8[2] = static_cast<uint8_t>((pixel & 0x3FF) * 255 / 1023);
+ // G
+ pixel >>= 10;
+ pixels8[1] = static_cast<uint8_t>((pixel & 0x3FF) * 255 / 1023);
+ // B
+ pixel >>= 10;
+ pixels8[0] = static_cast<uint8_t>((pixel & 0x3FF) * 255 / 1023);
+ // A
+ pixels8[3] = 0xFF;
+ }
+ }
+ }
+ else
+ memcpy(m_buffer, res.pData, m_height * m_stride);
+ pImdContext->Unmap(pCopyTexture.Get(), 0);
+ }
+ else
+ CLog::LogF(LOGERROR, "MAP_READ failed.");
+ }
+
+ return m_buffer != nullptr;
+}