mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-03-13 19:29:14 +01:00
[d3d11] Implement GDI surface
This commit is contained in:
parent
014870b1ff
commit
028633138a
208
src/d3d11/d3d11_gdi.cpp
Normal file
208
src/d3d11/d3d11_gdi.cpp
Normal file
@ -0,0 +1,208 @@
|
||||
#include "d3d11_context.h"
|
||||
#include "d3d11_device.h"
|
||||
#include "d3d11_gdi.h"
|
||||
|
||||
#include "../util/util_gdi.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D11GDISurface::D3D11GDISurface(
|
||||
ID3D11Resource* pResource,
|
||||
UINT Subresource)
|
||||
: m_resource (pResource),
|
||||
m_subresource (Subresource),
|
||||
m_readback (nullptr),
|
||||
m_hdc (nullptr),
|
||||
m_hbitmap (nullptr),
|
||||
m_acquired (false) {
|
||||
// Allocate memory for the bitmap
|
||||
auto tex = GetCommonTexture(m_resource)->Desc();
|
||||
m_data.resize(tex->Width * tex->Height);
|
||||
|
||||
// Create GDI DC
|
||||
D3DKMT_CREATEDCFROMMEMORY desc;
|
||||
desc.pMemory = m_data.data();
|
||||
desc.Format = D3DFMT_A8R8G8B8;
|
||||
desc.Width = tex->Width;
|
||||
desc.Height = tex->Height;
|
||||
desc.Pitch = tex->Width * sizeof(uint32_t);
|
||||
desc.hDeviceDc = CreateCompatibleDC(nullptr);
|
||||
desc.pColorTable = nullptr;
|
||||
desc.hDc = nullptr;
|
||||
desc.hBitmap = nullptr;
|
||||
|
||||
uint32_t a = D3DKMTCreateDCFromMemory(&desc);
|
||||
|
||||
if (a)
|
||||
Logger::err(str::format("D3D11: Failed to create GDI DC:", std::hex, a));
|
||||
|
||||
m_hdc = desc.hDc;
|
||||
m_hbitmap = desc.hBitmap;
|
||||
}
|
||||
|
||||
|
||||
D3D11GDISurface::~D3D11GDISurface() {
|
||||
if (m_readback)
|
||||
m_readback->Release();
|
||||
|
||||
D3DKMT_DESTROYDCFROMMEMORY desc;
|
||||
desc.hDC = m_hdc;
|
||||
desc.hBitmap = m_hbitmap;
|
||||
D3DKMTDestroyDCFromMemory(&desc);
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D11GDISurface::Acquire(BOOL Discard, HDC* phdc) {
|
||||
if (!phdc)
|
||||
return E_INVALIDARG;
|
||||
|
||||
*phdc = nullptr;
|
||||
|
||||
if (m_acquired)
|
||||
return DXGI_ERROR_INVALID_CALL;
|
||||
|
||||
if (!Discard) {
|
||||
// Create a staging resource that we can map
|
||||
if (!m_readback && FAILED(CreateReadbackResource())) {
|
||||
Logger::err("D3D11: Failed to create GDI readback resource");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// Copy subresource to staging image
|
||||
Com<ID3D11Device> device;
|
||||
Com<ID3D11DeviceContext> context;
|
||||
|
||||
m_resource->GetDevice(&device);
|
||||
device->GetImmediateContext(&context);
|
||||
|
||||
context->CopySubresourceRegion(m_readback, 0,
|
||||
0, 0, 0, m_resource, m_subresource, nullptr);
|
||||
|
||||
// Copy staging image to DC memory
|
||||
auto tex = GetCommonTexture(m_resource)->Desc();
|
||||
auto rowData = reinterpret_cast<char*>(m_data.data());
|
||||
auto rowLength = sizeof(uint32_t) * tex->Width;
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE sr;
|
||||
context->Map(m_readback, 0, D3D11_MAP_READ, 0, &sr);
|
||||
|
||||
for (uint32_t i = 0; i < tex->Height; i++) {
|
||||
std::memcpy(rowData + rowLength * i,
|
||||
reinterpret_cast<const char*>(sr.pData) + sr.RowPitch * i,
|
||||
rowLength);
|
||||
}
|
||||
|
||||
context->Unmap(m_readback, 0);
|
||||
}
|
||||
|
||||
m_acquired = true;
|
||||
*phdc = m_hdc;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D11GDISurface::Release(const RECT* pDirtyRect) {
|
||||
if (!m_acquired)
|
||||
return DXGI_ERROR_INVALID_CALL;
|
||||
|
||||
Com<ID3D11Device> device;
|
||||
Com<ID3D11DeviceContext> context;
|
||||
|
||||
m_resource->GetDevice(&device);
|
||||
device->GetImmediateContext(&context);
|
||||
|
||||
// Commit changes made to the DC
|
||||
auto tex = GetCommonTexture(m_resource)->Desc();
|
||||
|
||||
RECT rect;
|
||||
|
||||
if (pDirtyRect) {
|
||||
rect.left = std::max<LONG>(pDirtyRect->left, 0);
|
||||
rect.top = std::max<LONG>(pDirtyRect->top, 0);
|
||||
rect.right = std::min<LONG>(pDirtyRect->right, tex->Width);
|
||||
rect.bottom = std::min<LONG>(pDirtyRect->bottom, tex->Height);
|
||||
} else {
|
||||
rect.left = 0;
|
||||
rect.top = 0;
|
||||
rect.right = tex->Width;
|
||||
rect.bottom = tex->Height;
|
||||
}
|
||||
|
||||
if (rect.left < rect.right && rect.top < rect.bottom) {
|
||||
D3D11_BOX box;
|
||||
box.left = rect.left;
|
||||
box.top = rect.top;
|
||||
box.front = 0;
|
||||
box.right = rect.right;
|
||||
box.bottom = rect.bottom;
|
||||
box.back = 1;
|
||||
|
||||
context->UpdateSubresource(m_resource, m_subresource,
|
||||
&box, m_data.data() + rect.left,
|
||||
sizeof(uint32_t) * tex->Width,
|
||||
sizeof(uint32_t) * tex->Width * tex->Height);
|
||||
}
|
||||
|
||||
m_acquired = false;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D11GDISurface::CreateReadbackResource() {
|
||||
auto tex = GetCommonTexture(m_resource);
|
||||
|
||||
Com<ID3D11Device> device;
|
||||
Com<ID3D11DeviceContext> context;
|
||||
|
||||
m_resource->GetDevice(&device);
|
||||
device->GetImmediateContext(&context);
|
||||
|
||||
D3D11_RESOURCE_DIMENSION dim = { };
|
||||
m_resource->GetType(&dim);
|
||||
|
||||
VkImageSubresource sr = tex->GetSubresourceFromIndex(
|
||||
VK_IMAGE_ASPECT_COLOR_BIT, m_subresource);
|
||||
|
||||
switch (dim) {
|
||||
case D3D11_RESOURCE_DIMENSION_TEXTURE1D: {
|
||||
D3D11_TEXTURE1D_DESC desc;
|
||||
desc.Width = std::max<UINT>(tex->Desc()->Width >> sr.mipLevel, 1);
|
||||
desc.MipLevels = 1;
|
||||
desc.ArraySize = 1;
|
||||
desc.Format = tex->Desc()->Format;
|
||||
desc.Usage = D3D11_USAGE_STAGING;
|
||||
desc.BindFlags = 0;
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
desc.MiscFlags = 0;
|
||||
|
||||
ID3D11Texture1D* tex1D = nullptr;
|
||||
HRESULT hr = device->CreateTexture1D(&desc, nullptr, &tex1D);
|
||||
m_readback = tex1D;
|
||||
return hr;
|
||||
} break;
|
||||
|
||||
case D3D11_RESOURCE_DIMENSION_TEXTURE2D: {
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
desc.Width = std::max<UINT>(tex->Desc()->Width >> sr.mipLevel, 1);
|
||||
desc.Height = std::max<UINT>(tex->Desc()->Height >> sr.mipLevel, 1);
|
||||
desc.MipLevels = 1;
|
||||
desc.ArraySize = 1;
|
||||
desc.Format = tex->Desc()->Format;
|
||||
desc.SampleDesc= { 1, 0 };
|
||||
desc.Usage = D3D11_USAGE_STAGING;
|
||||
desc.BindFlags = 0;
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
desc.MiscFlags = 0;
|
||||
|
||||
ID3D11Texture2D* tex2D = nullptr;
|
||||
HRESULT hr = device->CreateTexture2D(&desc, nullptr, &tex2D);
|
||||
m_readback = tex2D;
|
||||
return hr;
|
||||
} break;
|
||||
|
||||
default:
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
41
src/d3d11/d3d11_gdi.h
Normal file
41
src/d3d11/d3d11_gdi.h
Normal file
@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "d3d11_include.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class D3D11GDISurface {
|
||||
|
||||
public:
|
||||
|
||||
D3D11GDISurface(
|
||||
ID3D11Resource* pResource,
|
||||
UINT Subresource);
|
||||
|
||||
~D3D11GDISurface();
|
||||
|
||||
HRESULT Acquire(
|
||||
BOOL Discard,
|
||||
HDC* phdc);
|
||||
|
||||
HRESULT Release(
|
||||
const RECT* pDirtyRect);
|
||||
|
||||
private:
|
||||
|
||||
ID3D11Resource* m_resource;
|
||||
uint32_t m_subresource;
|
||||
ID3D11Resource* m_readback;
|
||||
HDC m_hdc;
|
||||
HANDLE m_hbitmap;
|
||||
bool m_acquired;
|
||||
|
||||
std::vector<uint32_t> m_data;
|
||||
|
||||
HRESULT CreateReadbackResource();
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -42,6 +42,7 @@ d3d11_src = [
|
||||
'd3d11_depth_stencil.cpp',
|
||||
'd3d11_device.cpp',
|
||||
'd3d11_enums.cpp',
|
||||
'd3d11_gdi.cpp',
|
||||
'd3d11_initializer.cpp',
|
||||
'd3d11_input_layout.cpp',
|
||||
'd3d11_interop.cpp',
|
||||
|
Loading…
x
Reference in New Issue
Block a user