mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-06-17 12:58:55 +02:00
Support texture and screenshot dumping using WIC, no XP support.
This commit is contained in:
@ -5,12 +5,138 @@
|
|||||||
#include "D3DBase.h"
|
#include "D3DBase.h"
|
||||||
#include "D3DTexture.h"
|
#include "D3DTexture.h"
|
||||||
|
|
||||||
|
#include <atlbase.h>
|
||||||
|
#include <wincodec.h>
|
||||||
|
#include <wincodecsdk.h>
|
||||||
|
#pragma comment(lib, "WindowsCodecs.lib")
|
||||||
|
|
||||||
namespace DX11
|
namespace DX11
|
||||||
{
|
{
|
||||||
|
|
||||||
namespace D3D
|
namespace D3D
|
||||||
{
|
{
|
||||||
|
|
||||||
|
HRESULT TextureToPng(D3D11_MAPPED_SUBRESOURCE &map, LPCWSTR wzFilename, int width, int height, bool saveAlpha)
|
||||||
|
{
|
||||||
|
IWICImagingFactory *piFactory = NULL;
|
||||||
|
IWICBitmapEncoder *piEncoder = NULL;
|
||||||
|
IWICBitmapFrameEncode *piBitmapFrame = NULL;
|
||||||
|
IPropertyBag2 *pPropertybag = NULL;
|
||||||
|
|
||||||
|
IWICStream *piStream = NULL;
|
||||||
|
|
||||||
|
HRESULT hr = CoCreateInstance(
|
||||||
|
CLSID_WICImagingFactory,
|
||||||
|
NULL,
|
||||||
|
CLSCTX_INPROC_SERVER,
|
||||||
|
IID_IWICImagingFactory,
|
||||||
|
(LPVOID*)&piFactory);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = piFactory->CreateStream(&piStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = piStream->InitializeFromFilename(wzFilename, GENERIC_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = piFactory->CreateEncoder(GUID_ContainerFormatPng, NULL, &piEncoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = piEncoder->Initialize(piStream, WICBitmapEncoderNoCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = piEncoder->CreateNewFrame(&piBitmapFrame, &pPropertybag);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = piBitmapFrame->Initialize(pPropertybag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = piBitmapFrame->SetSize(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
WICPixelFormatGUID formatGUID = GUID_WICPixelFormat32bppBGRA;
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = piBitmapFrame->SetPixelFormat(&formatGUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
// We're expecting to write out 32bppBGRA. Fail if the encoder cannot do it.
|
||||||
|
hr = IsEqualGUID(formatGUID, GUID_WICPixelFormat32bppBGRA) ? S_OK : E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
if (map.pData != NULL)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < height; ++y)
|
||||||
|
{
|
||||||
|
u8* ptr = (u8*)map.pData + y * map.RowPitch;
|
||||||
|
for (unsigned int x = 0; x < map.RowPitch/4; ++x)
|
||||||
|
{
|
||||||
|
u8 r = ptr[0];
|
||||||
|
u8 g = ptr[1];
|
||||||
|
u8 b = ptr[2];
|
||||||
|
ptr[0] = b;
|
||||||
|
ptr[1] = g;
|
||||||
|
ptr[2] = r;
|
||||||
|
if (!saveAlpha)
|
||||||
|
ptr[3] = 0xff;
|
||||||
|
|
||||||
|
|
||||||
|
ptr += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hr = piBitmapFrame->WritePixels(height, map.RowPitch, height * map.RowPitch, (BYTE*)map.pData);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hr = E_OUTOFMEMORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = piBitmapFrame->Commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = piEncoder->Commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (piFactory)
|
||||||
|
piFactory->Release();
|
||||||
|
|
||||||
|
if (piBitmapFrame)
|
||||||
|
piBitmapFrame->Release();
|
||||||
|
|
||||||
|
if (piEncoder)
|
||||||
|
piEncoder->Release();
|
||||||
|
|
||||||
|
if (piStream)
|
||||||
|
piStream->Release();
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width, unsigned int height, unsigned int pitch, unsigned int level, D3D11_USAGE usage)
|
void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width, unsigned int height, unsigned int pitch, unsigned int level, D3D11_USAGE usage)
|
||||||
{
|
{
|
||||||
if (usage == D3D11_USAGE_DYNAMIC || usage == D3D11_USAGE_STAGING)
|
if (usage == D3D11_USAGE_DYNAMIC || usage == D3D11_USAGE_STAGING)
|
||||||
|
@ -11,6 +11,7 @@ namespace DX11
|
|||||||
|
|
||||||
namespace D3D
|
namespace D3D
|
||||||
{
|
{
|
||||||
|
HRESULT TextureToPng(D3D11_MAPPED_SUBRESOURCE& map, LPCWSTR wzFilename, int width, int height, bool saveAlpha = true);
|
||||||
void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width, unsigned int height, unsigned int pitch, unsigned int level, D3D11_USAGE usage);
|
void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width, unsigned int height, unsigned int pitch, unsigned int level, D3D11_USAGE usage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -690,22 +690,13 @@ bool Renderer::SaveScreenshot(const std::string &filename, const TargetRectangle
|
|||||||
D3D11_BOX box = CD3D11_BOX(rc.left, rc.top, 0, rc.right, rc.bottom, 1);
|
D3D11_BOX box = CD3D11_BOX(rc.left, rc.top, 0, rc.right, rc.bottom, 1);
|
||||||
D3D::context->CopySubresourceRegion(s_screenshot_texture, 0, 0, 0, 0, (ID3D11Resource*)D3D::GetBackBuffer()->GetTex(), 0, &box);
|
D3D::context->CopySubresourceRegion(s_screenshot_texture, 0, 0, 0, 0, (ID3D11Resource*)D3D::GetBackBuffer()->GetTex(), 0, &box);
|
||||||
|
|
||||||
// D3DX11SaveTextureToFileA doesn't allow us to ignore the alpha channel, so we need to strip it out ourselves
|
|
||||||
D3D11_MAPPED_SUBRESOURCE map;
|
D3D11_MAPPED_SUBRESOURCE map;
|
||||||
D3D::context->Map(s_screenshot_texture, 0, D3D11_MAP_READ_WRITE, 0, &map);
|
D3D::context->Map(s_screenshot_texture, 0, D3D11_MAP_READ_WRITE, 0, &map);
|
||||||
for (auto y = 0; y < rc.GetHeight(); ++y)
|
|
||||||
{
|
|
||||||
u8* ptr = (u8*)map.pData + y * map.RowPitch + 3;
|
|
||||||
for (auto x = 0; x < rc.GetWidth(); ++x)
|
|
||||||
{
|
|
||||||
*ptr = 0xFF;
|
|
||||||
ptr += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
D3D::context->Unmap(s_screenshot_texture, 0);
|
|
||||||
|
|
||||||
// ready to be saved
|
// ready to be saved
|
||||||
HRESULT hr = PD3DX11SaveTextureToFileA(D3D::context, s_screenshot_texture, D3DX11_IFF_PNG, filename.c_str());
|
HRESULT hr = D3D::TextureToPng(map, UTF8ToUTF16(filename.c_str()).c_str(), rc.GetWidth(), rc.GetHeight(), false);
|
||||||
|
D3D::context->Unmap(s_screenshot_texture, 0);
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
OSD::AddMessage(StringFromFormat("Saved %i x %i %s", rc.GetWidth(),
|
OSD::AddMessage(StringFromFormat("Saved %i x %i %s", rc.GetWidth(),
|
||||||
|
@ -42,7 +42,33 @@ bool TextureCache::TCacheEntry::Save(const char filename[], unsigned int level)
|
|||||||
warn_once = false;
|
warn_once = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return SUCCEEDED(PD3DX11SaveTextureToFileA(D3D::context, texture->GetTex(), D3DX11_IFF_PNG, filename));
|
|
||||||
|
ID3D11Texture2D* pNewTexture = NULL;
|
||||||
|
ID3D11Texture2D* pSurface = texture->GetTex();
|
||||||
|
D3D11_TEXTURE2D_DESC desc;
|
||||||
|
pSurface->GetDesc(&desc);
|
||||||
|
|
||||||
|
desc.BindFlags = 0;
|
||||||
|
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
|
||||||
|
desc.Usage = D3D11_USAGE_STAGING;
|
||||||
|
|
||||||
|
HRESULT hr = D3D::device->CreateTexture2D(&desc, NULL, &pNewTexture);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr) && pNewTexture)
|
||||||
|
{
|
||||||
|
D3D::context->CopyResource(pNewTexture, pSurface);
|
||||||
|
|
||||||
|
D3D11_MAPPED_SUBRESOURCE map;
|
||||||
|
HRESULT hr = D3D::context->Map(pNewTexture, 0, D3D11_MAP_READ_WRITE, 0, &map);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = D3D::TextureToPng(map, UTF8ToUTF16(filename).c_str(), desc.Width, desc.Height);
|
||||||
|
D3D::context->Unmap(pNewTexture, 0);
|
||||||
|
}
|
||||||
|
SAFE_RELEASE(pNewTexture);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SUCCEEDED(hr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
|
void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
|
||||||
|
Reference in New Issue
Block a user