Захват рабочего стола Windows и отображение в виде нереальной текстуры - перепутанные пиксели - PullRequest
0 голосов
/ 03 декабря 2018

Как видно из заголовков, я пытаюсь захватить рабочий стол Windows с помощью DirectX и отобразить результат в виде текстуры в Unreal.Однако полученная текстура не является правильной, поскольку кажется, что пиксели вдоль оси X повторяются повсюду.

Базовый процесс захвата рабочего стола и его передачи в Unreal Texture показан в приведенном ниже коде (который успешно компилируется и запускается в UE 4.20 / VS 2017):

  • Получить текущий кадр рабочего стола (g_desks - это устройство, iDesk - это номер. В настоящее время работает с одним монитором, поэтому iDesk равен 1)
  • Получить DeviceContext с устройства (показано в коде инициализации внизу).)
  • Установите формат для ID3D11Texture2D (текстура), в которой хранится захват
  • Создание промежуточной текстуры для передачи
  • Сопоставление промежуточной текстуры
  • Копироватьданные из сопоставленной промежуточной текстуры в буфер Unreal с использованием Memcpy

Кроме того, жесткое кодирование значений пикселей в массив и последующее использование Memcpy в буфер текстур Unreal дает правильный вывод.Это наводит меня на мысль, что проблема заключается в преобразовании текстур или в том, как мы сначала захватываем рабочий стол.Приветствуется любая помощь!

Код захвата рабочего стола:

    IDXGIResource* resource = nullptr;

    const UINT timeout = 0; // ms

    // acquire current frame of desktop
    HRESULT resultAcquire = CurrentState.g_desks[iDesk].g_deskDupl->AcquireNextFrame(timeout, &CurrentState.g_desks[iDesk].g_frameInfo, &resource);
    if (resultAcquire != S_OK)
    {
        g_needReinit++;
        return;
    }

    CurrentState.g_desks[iDesk].g_isPointerVisible = (CurrentState.g_desks[iDesk].g_frameInfo.PointerPosition.Visible == TRUE);
    CurrentState.g_desks[iDesk].g_pointerX = CurrentState.g_desks[iDesk].g_frameInfo.PointerPosition.Position.x;
    CurrentState.g_desks[iDesk].g_pointerY = CurrentState.g_desks[iDesk].g_frameInfo.PointerPosition.Position.y;

    // check if resource was correctly acquired
    ID3D11Texture2D* texture;
    HRESULT resultQuery = resource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&texture));
    resource->Release();

    if (resultQuery != S_OK)
    {
        g_needReinit++;
        return;
    }

    HRESULT hr;

    // get context from device
    m_Device->GetImmediateContext(&m_DeviceContext);

    //Description for retrieved texture
    D3D11_TEXTURE2D_DESC desc;
    texture->GetDesc(&desc); 

    switch (desc.Format) {
        case DXGI_FORMAT_R8G8B8A8_UNORM:
            std::cout << "Good Format";
            break;
        case DXGI_FORMAT_B8G8R8A8_UNORM:
            std::cout << "Good Format";
            break;
        default:
            std::cout << "Bad Format";
    }

    // set description for the retrieved texture
    D3D11_TEXTURE2D_DESC desc2;
    desc2.Width = desc.Width;
    desc2.Height = desc.Height;
    desc2.MipLevels = desc.MipLevels;
    desc2.ArraySize = desc.ArraySize;
    desc2.Format = desc.Format;
    desc2.SampleDesc = desc.SampleDesc;
    desc2.Usage = D3D11_USAGE_STAGING;
    desc2.BindFlags = 0;
    desc2.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
    desc2.MiscFlags = 0;

    // create staging texture
    ID3D11Texture2D* stagingTexture;
    hr = m_Device->CreateTexture2D(&desc2, nullptr, &stagingTexture);
    if (FAILED(hr)) {
        std::cout << "Failed";
    }

    // copy the texture to a staging resource
    m_DeviceContext->CopyResource(stagingTexture, texture);

    D3D11_MAPPED_SUBRESOURCE mapInfo;
    hr = m_DeviceContext->Map(stagingTexture, 0, D3D11_MAP_READ, 0, &mapInfo);

    if (FAILED(hr)) {
        std::cout << "Failed";
    }

    //Use D3D11_MAPPED_SUBRESOURCE to get pointer + size of data
    FTexture2DMipMap& Mip = CurrentState.g_desks[iDesk].g_texture->PlatformData->Mips[0];

    // memcpy into buffer for unreal
    uint8 * Data = (uint8*)Mip.BulkData.Lock(LOCK_READ_WRITE);
    FMemory::Memcpy(Data, (uint8*)mapInfo.pData, mapInfo.RowPitch * desc2.Height);
    Mip.BulkData.Unlock();

    // release staging texture and frame
    m_DeviceContext->Unmap(stagingTexture, 0);
    CurrentState.g_desks[0].g_texture->UpdateResource();
    CurrentState.g_desks[iDesk].g_deskDupl->ReleaseFrame();
}

Код инициализации захвата рабочего стола:

void DeskInfo::DesktopCapturePlugin_Initialize() {

g_needReinit = 0;


IDXGIFactory1* factory;
HRESULT hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&factory));

IDXGIAdapter1* adapter;
for (int i = 0; (factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND); ++i)
{
    IDXGIOutput* output;
    for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); j++)
    {
        DXGI_OUTPUT_DESC outputDesc;
        output->GetDesc(&outputDesc);

        MONITORINFOEX monitorInfo;
        monitorInfo.cbSize = sizeof(MONITORINFOEX);
        GetMonitorInfo(outputDesc.Monitor, &monitorInfo);

        // Maybe in future add a function to identify the primary monitor.
        if (monitorInfo.dwFlags == MONITORINFOF_PRIMARY)
        {
            int iDesk = DeskAdd();

            CurrentState.g_desks[iDesk].g_width = monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left;
            CurrentState.g_desks[iDesk].g_height = monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top;

            //TODO: Hacky
            Width = monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left;
            Height = monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top;

            // Feature levels supported
            D3D_FEATURE_LEVEL FeatureLevels[] =
            {
                D3D_FEATURE_LEVEL_11_0,
                D3D_FEATURE_LEVEL_10_1,
                D3D_FEATURE_LEVEL_10_0,
                D3D_FEATURE_LEVEL_9_1
            };
            UINT NumFeatureLevels = ARRAYSIZE(FeatureLevels);
            D3D_FEATURE_LEVEL FeatureLevel;
            HRESULT hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, FeatureLevels, NumFeatureLevels,
                D3D11_SDK_VERSION, &m_Device, &FeatureLevel, &m_DeviceContext);
            if (SUCCEEDED(hr))
            {
                // Device creation succeeded, no need to loop anymore
                IDXGIOutput1* output1;
                output1 = reinterpret_cast<IDXGIOutput1*>(output);
                output1->DuplicateOutput(m_Device, &CurrentState.g_desks[iDesk].g_deskDupl);
                break;
            }

        }

        output->Release();
    }
    adapter->Release();
}

factory->Release();

}

...