diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..8e7e8d8 --- /dev/null +++ b/.clang-format @@ -0,0 +1,12 @@ +BasedOnStyle: Google + +BinPackArguments: false +BinPackParameters: false +ColumnLimit: 100 +DerivePointerAlignment: false +IncludeBlocks: Preserve +PointerAlignment: Left +AllowShortFunctionsOnASingleLine: Empty +BreakBeforeBraces: Allman +UseTab: Always +NamespaceIndentation: All diff --git a/bitblt-hdr.vcxproj b/bitblt-hdr.vcxproj index 9d8a1f4..1da7447 100644 --- a/bitblt-hdr.vcxproj +++ b/bitblt-hdr.vcxproj @@ -172,9 +172,11 @@ Document + + @@ -185,6 +187,7 @@ + diff --git a/bitblt-hdr.vcxproj.filters b/bitblt-hdr.vcxproj.filters index e8ab79e..2e3d5f4 100644 --- a/bitblt-hdr.vcxproj.filters +++ b/bitblt-hdr.vcxproj.filters @@ -21,6 +21,7 @@ dllproxy + @@ -43,6 +44,7 @@ deps\minhook + @@ -82,6 +84,7 @@ utils + diff --git a/bitblt_hdr.cpp b/bitblt_hdr.cpp new file mode 100644 index 0000000..397823b --- /dev/null +++ b/bitblt_hdr.cpp @@ -0,0 +1,467 @@ +#include "bitblt_hdr.hpp" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "monitor.hpp" +#include "utils/com_ptr.hpp" + +bitblt_hdr::bitblt_hdr(trampoline bitblt) : bitblt_(bitblt) +{ + init(); +} + +bitblt_hdr::~bitblt_hdr() +{ + reset(); +} + +void bitblt_hdr::reset() { + monitors_.clear(); + + render_const_buffer_ = nullptr; + virtual_desktop_tex_ = nullptr; + render_cs_ = nullptr; + ctx_ = nullptr; + device_ = nullptr; +} + +bool bitblt_hdr::init() +{ + if (device_ && ctx_) + { + return true; + } + + D3D_FEATURE_LEVEL feature_level; + + HRESULT hr = D3D11CreateDevice(nullptr, + D3D_DRIVER_TYPE_HARDWARE, + nullptr, +#ifdef _DEBUG + D3D11_CREATE_DEVICE_DEBUG, +#else + 0, +#endif + nullptr, + 0, + D3D11_SDK_VERSION, + device_, + &feature_level, + ctx_); + + if (FAILED(hr)) + { + printf("init_desktop_dup failed at line %d, hr = 0x%x\n", __LINE__, hr); + return false; + } + + if (device_->GetFeatureLevel() < D3D_FEATURE_LEVEL_11_0) + { + printf("init_desktop_dup failed at line %d, feature level < 11.0\n", __LINE__); + + device_ = nullptr; + ctx_ = nullptr; + + return false; + } + + return true; +} + +void bitblt_hdr::enum_monitors() +{ + if (monitors_.size()) + { + monitors_.clear(); + } + + com_ptr dxgi_device = device_.as(); + + if (!dxgi_device) + { + throw std::runtime_error{"enum_monitors failed to get as IDXGIDevice"}; + } + + com_ptr adapter; + HRESULT hr = dxgi_device->GetAdapter(adapter); + + if (FAILED(hr)) + { + auto msg = std::format("enum_monitors failed to GetAdapter: {:x}", hr); + throw std::runtime_error{msg}; + } + + auto outputIndex = 0u; + while (true) + { + com_ptr output; + hr = adapter->EnumOutputs(outputIndex++, output); + + if (hr == DXGI_ERROR_NOT_FOUND) + { + break; + } + + if (FAILED(hr)) + { + auto msg = std::format("enum_monitors failed to EnumOutputs: {:x}", hr); + throw std::runtime_error{msg}; + } + + com_ptr output6 = output.as(); + if (!output6) + { + throw std::runtime_error{"enum_monitors failed to get as IDXGIOutput6"}; + } + + DXGI_OUTPUT_DESC1 desc; + hr = output6->GetDesc1(&desc); + + if (FAILED(hr)) + { + printf("enum_monitors failed to GetDesc1: %x", hr); + continue; + } + + if (desc.AttachedToDesktop) + { + monitors_.push_back(std::make_unique(output6, device_)); + continue; + } + } +} + +bool bitblt_hdr::create_shader_from_source_file(LPCWSTR file_name) +{ + if (!device_) + { + return false; + } + + if (render_cs_) + { + render_cs_ = nullptr; + } + + com_ptr shader; + com_ptr error; + + HRESULT hr = D3DCompileFromFile(file_name, + nullptr, + D3D_COMPILE_STANDARD_FILE_INCLUDE, + "main", + "cs_5_0", + D3DCOMPILE_ENABLE_STRICTNESS, + 0, + shader, + error); + + if (error) + { + printf("create_shader_from_source_file: %s\n", + reinterpret_cast(error->GetBufferPointer())); + } + + if (FAILED(hr)) + { + printf("create_shader_from_source_file failed at line %d, hr = 0x%x\n", __LINE__, hr); + return false; + } + + hr = device_->CreateComputeShader( + shader->GetBufferPointer(), shader->GetBufferSize(), nullptr, render_cs_); + + if (FAILED(hr)) + { + printf("create_shader_from_source_file failed at line %d, hr = 0x%x\n", __LINE__, hr); + return false; + } + return true; +} + +bool bitblt_hdr::create_shader_from_resource(HINSTANCE instance, WORD res_id) +{ + if (!device_) + { + return false; + } + + if (render_cs_) + { + render_cs_ = nullptr; + } + + auto* const res = FindResource(instance, MAKEINTRESOURCE(res_id), RT_RCDATA); + if (!res) + { + printf("shader resource not found\n"); + return {}; + } + + auto* const handle = LoadResource(instance, res); + if (!handle) + { + printf("shader failed to load resource\n"); + return {}; + } + + const auto* bytecode = LockResource(handle); + const auto size = SizeofResource(instance, res); + + FreeResource(handle); + + HRESULT hr = device_->CreateComputeShader(bytecode, size, nullptr, render_cs_); + + if (FAILED(hr)) + { + printf("create_shader_from_resource failed at line %d, hr = 0x%x\n", __LINE__, hr); + return false; + } + return true; +} + +bool bitblt_hdr::render(com_ptr input, com_ptr target) +{ + D3D11_TEXTURE2D_DESC desc; + input->GetDesc(&desc); + + render_cb_data_.is_hdr = desc.Format == DXGI_FORMAT_R16G16B16A16_FLOAT; + + com_ptr src_srv; + D3D11_SHADER_RESOURCE_VIEW_DESC src_desc = {}; + src_desc.Format = desc.Format; + src_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + src_desc.Texture2D.MipLevels = 1; + HRESULT hr = device_->CreateShaderResourceView(input, &src_desc, src_srv); + + if (FAILED(hr)) + { + return false; + } + + com_ptr dest_uav; + D3D11_UNORDERED_ACCESS_VIEW_DESC dest_desc = {}; + dest_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + dest_desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D; + dest_desc.Texture2D.MipSlice = 0; + hr = device_->CreateUnorderedAccessView(target, &dest_desc, dest_uav); + + if (FAILED(hr)) + { + return false; + } + + if (!render_const_buffer_) + { + D3D11_BUFFER_DESC cb_desc; + cb_desc.ByteWidth = sizeof(render_constant_buffer_t); + cb_desc.Usage = D3D11_USAGE_DYNAMIC; + cb_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + cb_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + cb_desc.MiscFlags = 0; + cb_desc.StructureByteStride = 0; + + hr = device_->CreateBuffer(&cb_desc, nullptr, render_const_buffer_); + + if (FAILED(hr)) + { + return false; + } + + ctx_->CSSetConstantBuffers(0, 1, render_const_buffer_); + } + + D3D11_MAPPED_SUBRESOURCE mapped_cb; + ctx_->Map(render_const_buffer_, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_cb); + memcpy(mapped_cb.pData, &render_cb_data_, sizeof(render_constant_buffer_t)); + ctx_->Unmap(render_const_buffer_, 0); + + ctx_->CSSetShader(render_cs_, nullptr, 0); + ctx_->CSSetShaderResources(0, 1, src_srv); + ctx_->CSSetUnorderedAccessViews(0, 1, dest_uav, nullptr); + ctx_->Dispatch((desc.Width + 15) / 16, (desc.Height + 15) / 16, 1); + + ctx_->CSSetShader(nullptr, nullptr, 0); + + src_srv = nullptr; + ctx_->CSSetShaderResources(0, 1, src_srv); + + dest_uav = nullptr; + ctx_->CSSetUnorderedAccessViews(0, 1, dest_uav, nullptr); + + return true; +} + +void bitblt_hdr::capture_frame( + std::vector& buffer, int width, int height, int origin_x, int origin_y) +{ + HRESULT hr = S_OK; + + if (width != width_ || height != height_ || monitors_.empty()) + { + if (virtual_desktop_tex_) + { + virtual_desktop_tex_ = nullptr; + } + + enum_monitors(); + + width_ = width; + height_ = height; + } + + if (!virtual_desktop_tex_) + { + D3D11_TEXTURE2D_DESC desc; + desc.Width = width_; + desc.Height = height_; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS; + desc.MiscFlags = 0; + desc.CPUAccessFlags = 0; + + hr = device_->CreateTexture2D(&desc, nullptr, virtual_desktop_tex_); + if (FAILED(hr)) + { + auto msg = std::format("failed to create virtual desktop texture: {:x}", hr); + throw std::runtime_error{msg}; + } + } + + for (const auto& monitor : monitors_) + { + monitor->update_output_desc(); + const auto [x, y] = monitor->virtual_position(); + const auto rotation = monitor->rotation(); + const auto rad = rotation * (std::numbers::pi_v / 180.f); + + const auto sin_r = std::sinf(rad); + const auto cos_r = std::cosf(rad); + + /* + * cos(θ) -sin(θ) Tx + * Mt = sin(θ) cos(θ) Ty + * 0 0 1 + */ + render_cb_data_.transform_matrix[0][0] = cos_r; + render_cb_data_.transform_matrix[0][1] = -sin_r; + render_cb_data_.transform_matrix[0][2] = static_cast(x - origin_x); + + render_cb_data_.transform_matrix[1][0] = sin_r; + render_cb_data_.transform_matrix[1][1] = cos_r; + render_cb_data_.transform_matrix[1][2] = static_cast(y - origin_y); + + render_cb_data_.transform_matrix[2][0] = 0; + render_cb_data_.transform_matrix[2][1] = 0; + render_cb_data_.transform_matrix[2][2] = 1; + + printf("transform matrix: \n%.6f %.6f %.6f\n%.6f %.6f %.6f\n%.6f %.6f %.6f\n", + render_cb_data_.transform_matrix[0][0], + render_cb_data_.transform_matrix[0][1], + render_cb_data_.transform_matrix[0][2], + render_cb_data_.transform_matrix[1][0], + render_cb_data_.transform_matrix[1][1], + render_cb_data_.transform_matrix[1][2], + render_cb_data_.transform_matrix[2][0], + render_cb_data_.transform_matrix[2][1], + render_cb_data_.transform_matrix[2][2]); + + render_cb_data_.white_level = monitor->sdr_white_level(); + + auto screenshot = monitor->take_screenshot(); + if (!render(screenshot, virtual_desktop_tex_)) [[unlikely]] + { + auto name = monitor->name(); + printf("failed to render monitor %s to virtual desktop texture\n", name.data()); + } + } + + D3D11_TEXTURE2D_DESC staging_desc; + virtual_desktop_tex_->GetDesc(&staging_desc); + staging_desc.Usage = D3D11_USAGE_STAGING; + staging_desc.BindFlags = 0; + staging_desc.MiscFlags = 0; + staging_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + + com_ptr staging_tex; + hr = device_->CreateTexture2D(&staging_desc, nullptr, staging_tex); + if (FAILED(hr)) + { + auto msg = std::format("failed to create staging texture: {:x}", hr); + throw std::runtime_error{msg}; + } + + ctx_->CopyResource(staging_tex, virtual_desktop_tex_); + + D3D11_MAPPED_SUBRESOURCE mapped; + ctx_->Map(staging_tex, 0, D3D11_MAP_READ, 0, &mapped); + + buffer.resize(staging_desc.Width * staging_desc.Height * 4); + + for (size_t i = 0; i < staging_desc.Height; i++) + { + const auto* src = reinterpret_cast(mapped.pData) + mapped.RowPitch * i; + auto* dest = buffer.data() + (staging_desc.Width * 4 * i); + + std::memcpy(dest, src, staging_desc.Width * 4); + } + + ctx_->Unmap(staging_tex, 0); +} + +bool bitblt_hdr::is_ready() const { + return device_ && ctx_ && render_cs_; +} + +bool bitblt_hdr::bitblt( + HDC hdc, int x, int y, int cx, int cy, HDC hdcSrc, int x1, int y1, DWORD rop) +{ + if (!is_ready()) + { + return bitblt_(hdc, x, y, cx, cy, hdcSrc, x1, y1, rop); + } + + auto src_window = WindowFromDC(hdcSrc); + auto desktop_window = GetDesktopWindow(); + + if (src_window != desktop_window) + { + return bitblt_(hdc, x, y, cx, cy, hdcSrc, x1, y1, rop); + } + + std::vector buffer; + + try + { + capture_frame(buffer, cx, cy, x1, y1); + } + catch (std::runtime_error e) + { + printf("failed to capture_frame, error: \n%s\n", e.what()); + return bitblt_(hdc, x, y, cx, cy, hdcSrc, x1, y1, rop); + } + + HBITMAP map = CreateBitmap(cx, cy, 1, 32, buffer.data()); + HDC src = CreateCompatibleDC(hdc); + SelectObject(src, map); + + auto result = bitblt_(hdc, x, y, cx, cy, src, 0, 0, rop & ~CAPTUREBLT); + + DeleteDC(src); + DeleteObject(map); + + return result; +} diff --git a/bitblt_hdr.hpp b/bitblt_hdr.hpp new file mode 100644 index 0000000..8df5c8d --- /dev/null +++ b/bitblt_hdr.hpp @@ -0,0 +1,58 @@ +#pragma once + +#include +#include + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include + +#include "monitor.hpp" +#include "utils/com_ptr.hpp" +#include "utils/trampoline.hpp" + +using vec2_t = std::tuple; + +class bitblt_hdr +{ + public: + explicit bitblt_hdr(trampoline bitblt); + ~bitblt_hdr(); + + void reset(); + bool init(); + bool create_shader_from_source_file(LPCWSTR file_name); + bool create_shader_from_resource(HINSTANCE instance, WORD res_id); + bool is_ready() const; + bool bitblt(HDC hdc, int x, int y, int cx, int cy, HDC hdcSrc, int x1, int y1, DWORD rop); + + private: + void enum_monitors(); + bool render(com_ptr input, com_ptr target); + void capture_frame( + std::vector& buffer, int width, int height, int origin_x, int origin_y); + + com_ptr device_; + com_ptr ctx_; + com_ptr render_cs_; + com_ptr virtual_desktop_tex_; + com_ptr render_const_buffer_; + + int width_ = 0; + int height_ = 0; + + struct render_constant_buffer_t + { + float white_level = 200.0f; + uint32_t is_hdr = 0; + + float __gap[2]; + + float transform_matrix[3][4]; + } render_cb_data_; + + std::vector> monitors_; + trampoline bitblt_; +}; diff --git a/main.cpp b/main.cpp index a794c80..229f33e 100644 --- a/main.cpp +++ b/main.cpp @@ -1,504 +1,89 @@ -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#include -#include - -#include -#include -#include +#include #include #include "resource.h" -#include "monitor.hpp" - -#include "utils/com_ptr.hpp" +#include "bitblt_hdr.hpp" #include "utils/trampoline.hpp" namespace { - com_ptr device; - com_ptr ctx; - com_ptr render_cs; - com_ptr virtual_desktop_tex; - com_ptr render_const_buffer; - - int w = 0, h = 0; - - struct render_constant_buffer_t - { - float white_level = 200.0f; - uint32_t is_hdr = 0; - - float __gap[2]; - - float transform_matrix[3][4]; - } render_cb_data; + trampoline bitblt_original; + std::unique_ptr bitblt; - HINSTANCE self_instance; + HINSTANCE self_instance; - std::vector> monitors; + BOOL WINAPI + bitblt_hook(HDC hdc, int x, int y, int cx, int cy, HDC hdcSrc, int x1, int y1, DWORD rop) + { + printf("bitblt called\n"); - bool init_desktop_dup() - { - if (device && ctx) - return true; - - D3D_FEATURE_LEVEL feature_level; - - HRESULT hr = D3D11CreateDevice( - nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, -#ifdef _DEBUG - D3D11_CREATE_DEVICE_DEBUG, -#else - 0, + if (!bitblt) + { + bitblt = std::make_unique(bitblt_original); +#ifndef _DEBUG + bitblt->create_shader_from_resource(self_instance, TONEMAPPER_SHADER); #endif - nullptr, 0, D3D11_SDK_VERSION, - device, &feature_level, ctx - ); - - if (FAILED(hr)) - { - printf("init_desktop_dup failed at line %d, hr = 0x%x\n", __LINE__, hr); - return false; - } - - if (device->GetFeatureLevel() < D3D_FEATURE_LEVEL_11_0) - { - printf("init_desktop_dup failed at line %d, feature level < 11.0\n", __LINE__); - - device = nullptr; - ctx = nullptr; - - return false; - } - - return true; - } - - void enum_monitors() - { - if (monitors.size()) - monitors.clear(); - - com_ptr dxgi_device = device.as(); - - if (!dxgi_device) - throw std::runtime_error{ "enum_monitors failed to get as IDXGIDevice" }; - - com_ptr adapter; - HRESULT hr = dxgi_device->GetAdapter(adapter); - - if (FAILED(hr)) - { - auto msg = std::format("enum_monitors failed to GetAdapter: {:x}", hr); - throw std::runtime_error{ msg }; - } - - auto outputIndex = 0u; - while (true) - { - com_ptr output; - hr = adapter->EnumOutputs(outputIndex++, output); - - if (hr == DXGI_ERROR_NOT_FOUND) - { - break; - } - - if (FAILED(hr)) - { - auto msg = std::format("enum_monitors failed to EnumOutputs: {:x}", hr); - throw std::runtime_error{ msg }; - } - - com_ptr output6 = output.as(); - if (!output6) - throw std::runtime_error{ "enum_monitors failed to get as IDXGIOutput6" }; - - DXGI_OUTPUT_DESC1 desc; - hr = output6->GetDesc1(&desc); - - if (FAILED(hr)) - { - printf("enum_monitors failed to GetDesc1: %x", hr); - continue; - } + } - if (desc.AttachedToDesktop) - { - monitors.push_back(std::make_unique(output6, device)); - continue; - } - } - } - - bool compile_shader() - { - if (render_cs) - { -#if _DEBUG - render_cs = nullptr; -#else - return true; -#endif - } - -#if _DEBUG - // compile tonemapping compute shader - com_ptr shader; - com_ptr error; - - HRESULT hr = D3DCompileFromFile( - L"tonemapper.hlsl", - nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE, - "main", "cs_5_0", - D3DCOMPILE_ENABLE_STRICTNESS, 0, - shader, error - ); - - if (error) - { - printf("compile_shader: %s\n", reinterpret_cast(error->GetBufferPointer())); - } - - if (FAILED(hr)) - { - printf("compile_shader failed at line %d, hr = 0x%x\n", __LINE__, hr); - return false; - } - - hr = device->CreateComputeShader( - shader->GetBufferPointer(), shader->GetBufferSize(), - nullptr, render_cs - ); - - if (FAILED(hr)) - { - printf("compile_shader failed at line %d, hr = 0x%x\n", __LINE__, hr); - return false; - } -#else - auto* const res = FindResourceA(self_instance, MAKEINTRESOURCE(TONEMAPPER_SHADER), RT_RCDATA); - if (!res) - { - printf("compile_shader resource not found\n"); - return false; - } - - auto* const handle = LoadResource(self_instance, res); - if (!handle) - { - printf("compile_shader failed to load resource\n"); - return false; - } - - const auto* bytecode = LockResource(handle); - const auto size = SizeofResource(self_instance, res); - - HRESULT hr = device->CreateComputeShader( - bytecode, size, - nullptr, render_cs - ); - - FreeResource(handle); - - if (FAILED(hr)) - { - printf("compile_shader failed at line %d, hr = 0x%x\n", __LINE__, hr); - return false; - } +#ifdef _DEBUG + bitblt->create_shader_from_source_file(L"tonemapper.hlsl"); #endif - return true; - } - - bool render(com_ptr input, com_ptr target) - { - if (!compile_shader()) - return false; - - D3D11_TEXTURE2D_DESC desc; - input->GetDesc(&desc); - - render_cb_data.is_hdr = desc.Format == DXGI_FORMAT_R16G16B16A16_FLOAT; - - com_ptr src_srv; - D3D11_SHADER_RESOURCE_VIEW_DESC src_desc = {}; - src_desc.Format = desc.Format; - src_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - src_desc.Texture2D.MipLevels = 1; - HRESULT hr = device->CreateShaderResourceView(input, &src_desc, src_srv); - - if (FAILED(hr)) - { - return false; - } - - com_ptr dest_uav; - D3D11_UNORDERED_ACCESS_VIEW_DESC dest_desc = {}; - dest_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - dest_desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D; - dest_desc.Texture2D.MipSlice = 0; - hr = device->CreateUnorderedAccessView(target, &dest_desc, dest_uav); - - if (FAILED(hr)) - { - return false; - } - - if (!render_const_buffer) - { - D3D11_BUFFER_DESC cb_desc; - cb_desc.ByteWidth = sizeof(render_constant_buffer_t); - cb_desc.Usage = D3D11_USAGE_DYNAMIC; - cb_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - cb_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - cb_desc.MiscFlags = 0; - cb_desc.StructureByteStride = 0; - - hr = device->CreateBuffer(&cb_desc, nullptr, render_const_buffer); + return bitblt->bitblt(hdc, x, y, cx, cy, hdcSrc, x1, y1, rop); + } - if (FAILED(hr)) - return false; + void free_desktop_dup() + { + if (bitblt) + { + bitblt.reset(); + } + } - ctx->CSSetConstantBuffers(0, 1, render_const_buffer); - } + trampoline exit_process; + void exit_process_hook(UINT code) + { + free_desktop_dup(); + exit_process(code); + } - D3D11_MAPPED_SUBRESOURCE mapped_cb; - ctx->Map(render_const_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_cb); - memcpy(mapped_cb.pData, &render_cb_data, sizeof(render_constant_buffer_t)); - ctx->Unmap(render_const_buffer, 0); - - ctx->CSSetShader(render_cs, nullptr, 0); - ctx->CSSetShaderResources(0, 1, src_srv); - ctx->CSSetUnorderedAccessViews(0, 1, dest_uav, nullptr); - ctx->Dispatch((desc.Width + 15) / 16, (desc.Height + 15) / 16, 1); - - ctx->CSSetShader(nullptr, nullptr, 0); - - src_srv = nullptr; - ctx->CSSetShaderResources(0, 1, src_srv); - - dest_uav = nullptr; - ctx->CSSetUnorderedAccessViews(0, 1, dest_uav, nullptr); - - return true; - } - - void capture_frame(std::vector& buffer, int width, int height, int origin_x, int origin_y) - { - HRESULT hr = S_OK; - - if (width != w || height != h) - { - if (virtual_desktop_tex) - { - virtual_desktop_tex = nullptr; - } - - enum_monitors(); - - w = width; - h = height; - } - - if (!virtual_desktop_tex) - { - D3D11_TEXTURE2D_DESC desc; - desc.Width = w; - desc.Height = h; - desc.MipLevels = 1; - desc.ArraySize = 1; - desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS; - desc.MiscFlags = 0; - desc.CPUAccessFlags = 0; - - hr = device->CreateTexture2D(&desc, nullptr, virtual_desktop_tex); - if (FAILED(hr)) - { - auto msg = std::format("failed to create virtual desktop texture: {:x}", hr); - throw std::runtime_error{ msg }; - } - } - - for (const auto& monitor : monitors) - { - monitor->update_output_desc(); - const auto [x, y] = monitor->virtual_position(); - const auto rotation = monitor->rotation(); - const auto rad = rotation * (std::numbers::pi_v / 180.f); - - const auto sin_r = std::sinf(rad); - const auto cos_r = std::cosf(rad); - - /* - * cos(��) -sin(��) Tx - * Mt = sin(��) cos(��) Ty - * 0 0 1 - */ - render_cb_data.transform_matrix[0][0] = cos_r; - render_cb_data.transform_matrix[0][1] = -sin_r; - render_cb_data.transform_matrix[0][2] = static_cast(x - origin_x); - - render_cb_data.transform_matrix[1][0] = sin_r; - render_cb_data.transform_matrix[1][1] = cos_r; - render_cb_data.transform_matrix[1][2] = static_cast(y - origin_y); - - render_cb_data.transform_matrix[2][0] = 0; - render_cb_data.transform_matrix[2][1] = 0; - render_cb_data.transform_matrix[2][2] = 1; - - printf("transform matrix: \n%.6f %.6f %.6f\n%.6f %.6f %.6f\n%.6f %.6f %.6f\n", - render_cb_data.transform_matrix[0][0], render_cb_data.transform_matrix[0][1], render_cb_data.transform_matrix[0][2], - render_cb_data.transform_matrix[1][0], render_cb_data.transform_matrix[1][1], render_cb_data.transform_matrix[1][2], - render_cb_data.transform_matrix[2][0], render_cb_data.transform_matrix[2][1], render_cb_data.transform_matrix[2][2] - ); - - render_cb_data.white_level = monitor->sdr_white_level(); - - auto screenshot = monitor->take_screenshot(); - if (!render(screenshot, virtual_desktop_tex)) [[unlikely]] - { - auto name = monitor->name(); - printf("failed to render monitor %s to virtual desktop texture\n", name.data()); - } - } - - D3D11_TEXTURE2D_DESC staging_desc; - virtual_desktop_tex->GetDesc(&staging_desc); - staging_desc.Usage = D3D11_USAGE_STAGING; - staging_desc.BindFlags = 0; - staging_desc.MiscFlags = 0; - staging_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - - com_ptr staging_tex; - hr = device->CreateTexture2D(&staging_desc, nullptr, staging_tex); - if (FAILED(hr)) - { - auto msg = std::format("failed to create staging texture: {:x}", hr); - throw std::runtime_error{ msg }; - } - - ctx->CopyResource(staging_tex, virtual_desktop_tex); - - D3D11_MAPPED_SUBRESOURCE mapped; - ctx->Map(staging_tex, 0, D3D11_MAP_READ, 0, &mapped); - - buffer.resize(staging_desc.Width * staging_desc.Height * 4); - - for (size_t i = 0; i < staging_desc.Height; i++) - { - const auto* src = reinterpret_cast(mapped.pData) + mapped.RowPitch * i; - auto* dest = buffer.data() + (staging_desc.Width * 4 * i); - - std::memcpy(dest, src, staging_desc.Width * 4); - } - - ctx->Unmap(staging_tex, 0); - } - - trampoline bitblt; - BOOL WINAPI bitblt_hook(HDC hdc, int x, int y, int cx, int cy, HDC hdcSrc, int x1, int y1, DWORD rop) - { - printf("bitblt called\n"); - - static bool inited = init_desktop_dup(); - - if (!inited) - return bitblt(hdc, x, y, cx, cy, hdcSrc, x1, y1, rop); - - auto src_window = WindowFromDC(hdcSrc); - auto desktop_window = GetDesktopWindow(); - - if (src_window != desktop_window) - return bitblt(hdc, x, y, cx, cy, hdcSrc, x1, y1, rop); - - std::vector buffer; - - try - { - capture_frame(buffer, cx, cy, x1, y1); - } - catch (std::runtime_error e) - { - printf("failed to capture_frame, error: \n%s\n", e.what()); - return bitblt(hdc, x, y, cx, cy, hdcSrc, x1, y1, rop); - } - - HBITMAP map = CreateBitmap(cx, cy, 1, 32, buffer.data()); - HDC src = CreateCompatibleDC(hdc); - SelectObject(src, map); - - auto result = bitblt(hdc, x, y, cx, cy, src, 0, 0, rop & ~CAPTUREBLT); - - DeleteDC(src); - DeleteObject(map); - - return result; - } - - void free_desktop_dup() - { - monitors.clear(); - - render_const_buffer = nullptr; - virtual_desktop_tex = nullptr; - render_cs = nullptr; - ctx = nullptr; - device = nullptr; - } - - trampoline exit_process; - void exit_process_hook(UINT code) - { - free_desktop_dup(); - exit_process(code); - } - -#if _DEBUG - void create_console() - { - AllocConsole(); - - FILE* f; - auto _ = freopen_s(&f, "CONOUT$", "w+t", stdout); - _ = freopen_s(&f, "CONOUT$", "w", stderr); - _ = freopen_s(&f, "CONIN$", "r", stdin); - } +#ifdef _DEBUG + void create_console() + { + AllocConsole(); + + FILE* f; + auto _ = freopen_s(&f, "CONOUT$", "w+t", stdout); + _ = freopen_s(&f, "CONOUT$", "w", stderr); + _ = freopen_s(&f, "CONIN$", "r", stdin); + } #endif - class hook_autoinit - { - public: - hook_autoinit() - { -#if _DEBUG - create_console(); + class hook_autoinit + { + public: + hook_autoinit() + { +#ifdef _DEBUG + create_console(); #endif - LoadLibraryA("gdi32.dll"); - MH_Initialize(); - MH_CreateHookApi(L"gdi32.dll", "BitBlt", bitblt_hook, &bitblt); - MH_CreateHookApi(L"kernel32.dll", "ExitProcess", exit_process_hook, &exit_process); - MH_EnableHook(MH_ALL_HOOKS); - } - } hook; -} + LoadLibraryA("gdi32.dll"); + MH_Initialize(); + MH_CreateHookApi(L"gdi32.dll", "BitBlt", bitblt_hook, &bitblt_original); + MH_CreateHookApi(L"kernel32.dll", "ExitProcess", exit_process_hook, &exit_process); + MH_EnableHook(MH_ALL_HOOKS); + } + } hook; +} // namespace BOOL WINAPI DllMain(HINSTANCE instance, DWORD fdwReason, LPVOID) { - if (fdwReason == DLL_PROCESS_ATTACH) - { - self_instance = instance; - } + if (fdwReason == DLL_PROCESS_ATTACH) + { + self_instance = instance; + } - return TRUE; + return TRUE; } diff --git a/utils/trampoline.hpp b/utils/trampoline.hpp index 738e05a..619dee5 100644 --- a/utils/trampoline.hpp +++ b/utils/trampoline.hpp @@ -4,6 +4,7 @@ class trampoline { public: trampoline() { object_ = nullptr; } + trampoline(T* obj) { object_ = obj; } T* get() const { return object_; } operator T* () const { return this->get(); } void** operator&() { return reinterpret_cast(&object_); }