Files
DisplayFlow/demo/windows_sender/IddBridge.cpp

244 lines
7.2 KiB
C++
Raw Normal View History

2025-12-22 13:48:06 +08:00
#include "IddBridge.h"
#include <string>
#include <chrono>
IddBridge::IddBridge() = default;
IddBridge::~IddBridge() {
if (frame_acquired_) {
ReleaseFrame();
}
if (shared_) {
UnmapViewOfFile(shared_);
shared_ = nullptr;
}
if (hMap_) {
CloseHandle(hMap_);
hMap_ = nullptr;
}
if (hReadyEvent_) {
CloseHandle(hReadyEvent_);
hReadyEvent_ = nullptr;
}
if (hConsumedEvent_) {
CloseHandle(hConsumedEvent_);
hConsumedEvent_ = nullptr;
}
}
bool IddBridge::Initialize() {
D3D_FEATURE_LEVEL featureLevels[] = {
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
};
D3D_FEATURE_LEVEL featureLevel;
HRESULT hr = D3D11CreateDevice(
nullptr,
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
featureLevels,
ARRAYSIZE(featureLevels),
D3D11_SDK_VERSION,
&device_,
&featureLevel,
&context_
);
if (FAILED(hr)) {
hr = D3D11CreateDevice(
nullptr,
D3D_DRIVER_TYPE_WARP,
nullptr,
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
featureLevels,
ARRAYSIZE(featureLevels),
D3D11_SDK_VERSION,
&device_,
&featureLevel,
&context_
);
if (FAILED(hr)) {
return false;
}
}
std::wstring mapName = L"Global\\DisplayFlowIddFrame";
std::wstring readyName = L"Global\\DisplayFlowIddReady";
std::wstring consumedName = L"Global\\DisplayFlowIddConsumed";
hMap_ = OpenFileMappingW(FILE_MAP_READ, FALSE, mapName.c_str());
if (!hMap_) {
// Fallback to Local (Simulation mode)
mapName = L"Local\\DisplayFlowIddFrame";
readyName = L"Local\\DisplayFlowIddReady";
consumedName = L"Local\\DisplayFlowIddConsumed";
hMap_ = OpenFileMappingW(FILE_MAP_READ, FALSE, mapName.c_str());
}
if (!hMap_) {
// Create for testing; in production UMDF service should create
shared_size_ = 64 * 1024 * 1024; // 64MB
hMap_ = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, (DWORD)shared_size_, mapName.c_str());
if (!hMap_) {
return false;
}
} else {
// Unknown size; assume max
shared_size_ = 64 * 1024 * 1024;
}
shared_ = (uint8_t*)MapViewOfFile(hMap_, FILE_MAP_READ, 0, 0, shared_size_);
if (!shared_) {
return false;
}
hReadyEvent_ = OpenEventW(SYNCHRONIZE, FALSE, readyName.c_str());
if (!hReadyEvent_) {
hReadyEvent_ = CreateEventW(nullptr, FALSE, FALSE, readyName.c_str());
}
hConsumedEvent_ = OpenEventW(EVENT_MODIFY_STATE, FALSE, consumedName.c_str());
if (!hConsumedEvent_) {
hConsumedEvent_ = CreateEventW(nullptr, FALSE, FALSE, consumedName.c_str());
}
return true;
}
bool IddBridge::EnsureTexture(int width, int height) {
if (gpuTexture_ && tex_width_ == width && tex_height_ == height) return true;
gpuTexture_.Reset();
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.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = 0;
HRESULT hr = device_->CreateTexture2D(&desc, nullptr, &gpuTexture_);
if (FAILED(hr)) return false;
tex_width_ = width;
tex_height_ = height;
return true;
}
bool IddBridge::CaptureFrame(ComPtr<ID3D11Texture2D>& texture) {
if (!shared_ || !hReadyEvent_) return false;
DWORD wait = WaitForSingleObject(hReadyEvent_, 100);
if (wait != WAIT_OBJECT_0) {
return false;
}
auto* hdr = reinterpret_cast<const IddSharedHeader*>(shared_);
if (hdr->format != 0) {
return false;
}
int w = (int)hdr->width;
int h = (int)hdr->height;
int stride = (int)hdr->stride;
const uint8_t* pixels = shared_ + sizeof(IddSharedHeader);
if (!EnsureTexture(w, h)) return false;
D3D11_BOX box = {};
box.left = 0; box.right = w;
box.top = 0; box.bottom = h;
box.front = 0; box.back = 1;
context_->UpdateSubresource(gpuTexture_.Get(), 0, nullptr, pixels, stride, 0);
frame_acquired_ = true;
texture = gpuTexture_;
if (hConsumedEvent_) {
SetEvent(hConsumedEvent_);
}
return true;
}
void IddBridge::ReleaseFrame() {
frame_acquired_ = false;
}
// ============================================================================
// IddProducer Implementation
// ============================================================================
IddProducer::IddProducer() = default;
IddProducer::~IddProducer() {
if (shared_) UnmapViewOfFile(shared_);
if (hMap_) CloseHandle(hMap_);
if (hReadyEvent_) CloseHandle(hReadyEvent_);
if (hConsumedEvent_) CloseHandle(hConsumedEvent_);
}
bool IddProducer::Initialize() {
std::wstring mapName = L"Local\\DisplayFlowIddFrame";
std::wstring readyName = L"Local\\DisplayFlowIddReady";
std::wstring consumedName = L"Local\\DisplayFlowIddConsumed";
shared_size_ = 64 * 1024 * 1024; // 64MB
// Producer prefers Creating
hMap_ = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, (DWORD)shared_size_, mapName.c_str());
if (!hMap_) {
// Maybe already exists
hMap_ = OpenFileMappingW(FILE_MAP_WRITE, FALSE, mapName.c_str());
if (!hMap_) return false;
}
shared_ = (uint8_t*)MapViewOfFile(hMap_, FILE_MAP_WRITE, 0, 0, shared_size_);
if (!shared_) return false;
hReadyEvent_ = CreateEventW(nullptr, FALSE, FALSE, readyName.c_str());
if (!hReadyEvent_) {
hReadyEvent_ = OpenEventW(EVENT_MODIFY_STATE, FALSE, readyName.c_str());
if (!hReadyEvent_) return false;
}
hConsumedEvent_ = CreateEventW(nullptr, FALSE, FALSE, consumedName.c_str());
if (!hConsumedEvent_) {
hConsumedEvent_ = OpenEventW(SYNCHRONIZE, FALSE, consumedName.c_str());
// If failed, consumer might create it later.
}
return true;
}
bool IddProducer::SubmitFrame(const void* data, uint32_t width, uint32_t height, uint32_t stride) {
if (!shared_ || !hReadyEvent_) return false;
// Ensure consumer created the event if we missed it
if (!hConsumedEvent_) {
hConsumedEvent_ = OpenEventW(SYNCHRONIZE, FALSE, L"Local\\DisplayFlowIddConsumed");
}
// Optional: Wait for previous frame consumption to avoid tearing/overflow
// if (hConsumedEvent_) WaitForSingleObject(hConsumedEvent_, 0);
// For now, overwrite mode is faster for streaming.
IddSharedHeader* hdr = reinterpret_cast<IddSharedHeader*>(shared_);
uint32_t needed = sizeof(IddSharedHeader) + stride * height;
if (needed > shared_size_) return false;
hdr->width = width;
hdr->height = height;
hdr->format = 0;
hdr->stride = stride;
hdr->timestamp = (uint64_t)std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now().time_since_epoch()).count();
hdr->frameId = ++frameId_;
hdr->dataSize = stride * height;
std::memcpy(shared_ + sizeof(IddSharedHeader), data, hdr->dataSize);
SetEvent(hReadyEvent_);
return true;
}