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_); }