How can I render images on a monitor (or TV) connected to my computer's HDMI port

I am new to DirectX 10 programming and I was trying to do the following with my limited skills.

I am trying to display an image from one computer to another output device (different monitor / TV) connected via HDMI . I researched it and found out that DXGI can be very useful for rendering purposes. Moreover, upon further exploring this information, I found a link here . It shows how to display different images on multiple monitors connected to the main machine, but it requires an extended screen to do this .

My requirement is that when I run the code, it should render the image to another output device without making it expanded.

Approaching I am trying to get me to list the Video Adapters (which in my case is 1) and then list the available outputs, which should be in two numbers since I have an HDMI output connected to my PC. But if I do not set the extended display it only shows one output available in my enumerated pin array and if I expand the screen it shows two of them. When I'm done listing the outputs, I want to display this image on the desired output.

As far as I know, every video adapter has an HDMI port connected to it.

I wonder if there is a way I can programmatically access this port and be able to display an image using that port ??

Apart from MSDN, the documentation or explanation of these concepts is quite limited, so any help would be greatly appreciated. Here's the code I have:

// include the basic windows header files and the Direct3D header files
#include <windows.h>
#include <windowsx.h>
#include <d3d11.h>
#include <d3dx11.h>
#include <d3dx10.h>
#include<vector>
#include<iostream>
#include <sstream>
#include<dxgi.h>
using namespace std;
// include the Direct3D Library file
#pragma comment (lib, "d3d11.lib")
#pragma comment (lib, "d3dx11.lib")
#pragma comment (lib, "d3dx10.lib")
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "dxgi.lib")
std::vector<IDXGIAdapter*> EnumerateAdapters();

void PrintAdapterInfo(IDXGIAdapter* pAdapter);

std::vector<IDXGIOutput*> EnumerateOutputs(IDXGIAdapter* pAdapter);
void PrintOutputInfo(IDXGIOutput* output);

std::vector<DXGI_MODE_DESC*> GetDisplayModeList(IDXGIOutput* output);

void PrintDisplayModeInfo(DXGI_MODE_DESC* pModeDesc);
// global declarations
IDXGISwapChain *swapchain;             // the pointer to the swap chain interface
ID3D11Device *dev;                     // the pointer to our Direct3D device interface
ID3D11DeviceContext *devcon;           // the pointer to our Direct3D device context
ID3D11RenderTargetView *backbuffer;    // the pointer to our back buffer
IDXGIAdapter *pAdapter;
IDXGIAdapter* adapter = NULL;
IDXGIFactory1* factory = NULL;
HINSTANCE hInstance;
HINSTANCE hPrevInstance;
LPSTR lpCmdLine;
HWND hWnd;

 std::vector<IDXGIOutput*> outputArray;

int nCmdShow;
// function prototypes
void InitD3D(HWND hWnd);    // sets up and initializes Direct3D
void RenderFrame(void);     // renders a single frame
void CleanD3D(void);        // closes Direct3D and releases memory
void CreateWindowsForOutputs();
void GetAdapter();
void MultiRender();
void CreateSwapChainsAndViews();
std::vector<IDXGIAdapter*> EnumerateAdapters();

// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

struct WindowDataContainer
{
    //Direct3D 10 stuff per window data
    IDXGISwapChain* swapChain;
    ID3D11RenderTargetView* renderTargetView;
    ID3D11DepthStencilView* depthStencilView;

    // window goodies
    HWND hWnd;
    int width;
    int height;
};
std::vector<WindowDataContainer*> WindowsArray;
// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine,
                   int nCmdShow)


{
     std::cout << "Hello \nworld!"; // Will show a popup
    std::vector<IDXGIAdapter*> adapters = EnumerateAdapters();
    for(std::vector<IDXGIAdapter*>::iterator itor = adapters.begin(); itor != adapters.end(); ++itor)
    {
        //PrintAdapterInfo(*itor);

        // Get Output info
        std::vector<IDXGIOutput*> outputArray = EnumerateOutputs(*itor);
        for(std::vector<IDXGIOutput*>::iterator outputItor = outputArray.begin(); outputItor != outputArray.end(); ++outputItor)
        {
        //  PrintOutputInfo(*outputItor);

            // Get display mode list
            std::vector<DXGI_MODE_DESC*> modeList = GetDisplayModeList(*outputItor);
            for(std::vector<DXGI_MODE_DESC*>::iterator modeItor = modeList.begin(); modeItor != modeList.end(); ++modeItor)
            {
            //  PrintDisplayModeInfo(*modeItor);
            }
        }
CreateWindowsForOutputs();
MSG msg;

    while(TRUE)
    {
        if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);

            if(msg.message == WM_QUIT)
                break;
        }

     MultiRender();
    }

//std::getchar();
     //   return 0;
    }

//std:getchar();
}
std::vector<IDXGIAdapter*> EnumerateAdapters()
{
    // Create DXGI factory
    IDXGIFactory1* pFactory = NULL;
    HRESULT hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)(&pFactory));
    if (FAILED(hr))
    {
        MessageBox(NULL, L"Create DXGI factory failed", L"Error", 0);
    }

    // Enumerate devices
    IDXGIAdapter* pAdapter = NULL;
    std::vector<IDXGIAdapter*> vAdapters;

    for (UINT i = 0; pFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND; ++i)
    {
        vAdapters.push_back(pAdapter);
    }

    if (pFactory)
    {
        pFactory->Release();
        pFactory = NULL;
    }

    return vAdapters;
}

// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch(message)
    {
    case WM_DESTROY:
        {
            PostQuitMessage(0);
            return 0;
        } break;
    }

    return DefWindowProc (hWnd, message, wParam, lParam);
}



// this function initializes and prepares Direct3D for use
void InitD3D(HWND hWnd)
{

    // create a struct to hold information about the swap chain
    DXGI_SWAP_CHAIN_DESC scd;

    // clear out the struct for use
    ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));

    // fill the swap chain description struct
    scd.BufferCount = 1;                                    // one back buffer
    scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;     // use 32-bit color
    scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;      // how swap chain is to be used
    scd.OutputWindow = hWnd;                                // the window to be used
    scd.SampleDesc.Count = 1;                               // how many multisamples
    scd.SampleDesc.Quality = 0;                             // multisample quality level
    scd.Windowed = TRUE;                                    // windowed/full-screen mode

    // create a device, device context and swap chain using the information in the scd struct
    D3D11CreateDeviceAndSwapChain(   NULL,
        D3D_DRIVER_TYPE_HARDWARE,
        NULL,
        NULL,
        NULL,
        NULL,
        D3D11_SDK_VERSION,
        &scd,
        &swapchain,
        &dev,
        NULL,
        &devcon);


    // get the address of the back buffer
    ID3D11Texture2D *pBackBuffer;
    swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);

    // use the back buffer address to create the render target
    dev->CreateRenderTargetView(pBackBuffer, NULL, &backbuffer);
    pBackBuffer->Release();

    // set the render target as the back buffer
    devcon->OMSetRenderTargets(1, &backbuffer, NULL);


    // Set the viewport
    D3D11_VIEWPORT viewport;
    ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));

    viewport.TopLeftX = 0;
    viewport.TopLeftY = 0;
    viewport.Width = 800;
    viewport.Height = 600;

    devcon->RSSetViewports(1, &viewport);
}


// this is the function used to render a single frame
void RenderFrame(void)
{
    // clear the back buffer to a deep blue
    devcon->ClearRenderTargetView(backbuffer, D3DXCOLOR(0.0f, 0.2f, 0.4f, 1.0f));

    // do 3D rendering on the back buffer here

    // switch the back buffer and the front buffer
    swapchain->Present(0, 0);
}


// this is the function that cleans up Direct3D and COM
void CleanD3D(void)
{
    // close and release all existing COM objects
    swapchain->Release();
    backbuffer->Release();
    dev->Release();
    devcon->Release();
}

//Acquiring the outputs on our adapter
std::vector<IDXGIOutput*> EnumerateOutputs(IDXGIAdapter* pAdapter)
{
    //std::vector<IDXGIOutput*> outputs;
    IDXGIOutput* pOutput = NULL;
    for (UINT i = 0; pAdapter->EnumOutputs(i, &pOutput) != DXGI_ERROR_NOT_FOUND; ++i)
    {
        outputArray.push_back(pOutput);
    }

    return outputArray;
}





void CreateWindowsForOutputs()
{ //  std::vector<IDXGIOutput*> outputArray;
for( int i = 0; i < outputArray.size(); ++i )
{

    IDXGIOutput* output = outputArray.at(i);
    DXGI_OUTPUT_DESC outputDesc;
    output->GetDesc( &outputDesc );
    int x = outputDesc.DesktopCoordinates.left;
    int y = outputDesc.DesktopCoordinates.top;
    int width = outputDesc.DesktopCoordinates.right - x;
    int height = outputDesc.DesktopCoordinates.bottom - y;
     WNDCLASSEX wc;
       ZeroMemory(&wc, sizeof(WNDCLASSEX));

    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
    wc.lpszClassName = L"WindowClass";

    RegisterClassEx(&wc);

    RECT wr = {0, 0, 800, 600};
    AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);

    // Don't forget to clean this up. And all D3D COM objects.
    WindowDataContainer* window = new WindowDataContainer;

    window->hWnd = CreateWindowEx(NULL,
                          L"WindowClass",
                          L"Our First Direct3D Program",
                          WS_OVERLAPPEDWINDOW,
                          300,
                          300,
                          wr.right - wr.left,
                          wr.bottom - wr.top,
                          NULL,
                          NULL,
                          hInstance,
                          NULL);

    // show the window
    ShowWindow( window->hWnd, SW_SHOWDEFAULT );
    // InitD3D(hWnd);
        CreateSwapChainsAndViews();

    // set width and height
    window->width = width;
    window->height = height;
    std::vector<WindowDataContainer*> windowsArray;
    // shove it in the std::vector
    windowsArray.push_back(window);

    //if first window, associate it with DXGI so it can jump in
    // when there is something of interest in the message queue
    // think fullscreen mode switches etc. MSDN for more info.
//  if(i == 0)

    //  factory->MakeWindowAssociation( window->hWnd, 0 );

}
}

std::vector<DXGI_MODE_DESC*> GetDisplayModeList(IDXGIOutput* output)
{
    UINT num = 0;
    DXGI_FORMAT format = DXGI_FORMAT_R32G32B32A32_TYPELESS;
    UINT flags = DXGI_ENUM_MODES_INTERLACED | DXGI_ENUM_MODES_SCALING;

    // Get number of display modes
    output->GetDisplayModeList(format, flags, &num, 0);

    // Get display mode list
    DXGI_MODE_DESC * pDescs = new DXGI_MODE_DESC[num];
    output->GetDisplayModeList(format, flags, &num, pDescs);

    std::vector<DXGI_MODE_DESC*> displayList;
    for(int i = 0; i < num; ++i)
    {
        displayList.push_back(&pDescs[i]);
    }

    return displayList;
}
void CreateSwapChainsAndViews()
{
    std::vector<WindowDataContainer*> windowsArray;

    for( int i = 0; i < windowsArray.size(); i++ )
    {

        WindowDataContainer* window = windowsArray.at(i);

        // get the dxgi device
        IDXGIDevice* DXGIDevice = NULL;
        dev->QueryInterface( IID_IDXGIDevice, ( void** )&DXGIDevice ); // COM stuff, hopefully you are familiar

        // create a swap chain
        DXGI_SWAP_CHAIN_DESC swapChainDesc;

        // fill it in
           WindowDataContainer *p_Window = new WindowDataContainer;
        HRESULT hr = factory->CreateSwapChain( DXGIDevice, &swapChainDesc, &p_Window->swapChain );
        DXGIDevice->Release();
        DXGIDevice = NULL;

        // get the backbuffer
        ID3D11Texture2D* backBuffer = NULL;
        hr = window->swapChain->GetBuffer( 0, IID_ID3D11Texture2D, ( void** )&backBuffer );

        // get the backbuffer desc
        D3D11_TEXTURE2D_DESC backBufferDesc;
        backBuffer->GetDesc( &backBufferDesc );

        // create the render target view
        D3D11_RENDER_TARGET_VIEW_DESC RTVDesc;

        // fill it in

        dev->CreateRenderTargetView( backBuffer, &RTVDesc, &window->renderTargetView );
        backBuffer->Release();
        backBuffer = NULL;

        // Create depth stencil texture
        ID3D11Texture2D* depthStencil = NULL;
        D3D11_TEXTURE2D_DESC descDepth;

        // fill it in


        dev->CreateTexture2D( &descDepth, NULL, &depthStencil );

        // Create the depth stencil view
        D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;

        // fill it in

        dev->CreateDepthStencilView( depthStencil, &descDSV, &window->depthStencilView );

    }

}
void MultiRender( )
{
    std::vector<WindowDataContainer*> windowsArray;
    // Clear them all
    for( int i = 0; i < windowsArray.size(); i++ )
    {
        WindowDataContainer* window = windowsArray.at(i);

        // There is the answer to your second question:
        devcon->OMSetRenderTargets( 1, &window->renderTargetView, NULL );

        // Don't forget to adjust the viewport, in fullscreen it not important...
        D3D11_VIEWPORT Viewport;
        Viewport.TopLeftX = 0;
        Viewport.TopLeftY = 0;
        Viewport.Width = window->width;
        Viewport.Height = window->height;
        Viewport.MinDepth = 0.0f;
        Viewport.MaxDepth = 1.0f;
        devcon->RSSetViewports( 1, &Viewport );

        // TO DO: AMAZING STUFF PER WINDOW
    }
}
//std::vector<IDXGIOutput*> outputArray; // contains outputs per adapter
void EnumOutputsOnAdapter()
{
    IDXGIOutput* output = NULL;
    for(int i = 0; DXGI_ERROR_NOT_FOUND != adapter->EnumOutputs(i, &output); ++i)
    {

        // get the description
        DXGI_OUTPUT_DESC outputDesc;
        HRESULT hr = output->GetDesc( &outputDesc );

        outputArray.push_back( output );
    }

}
// applicable for multiple ones with little effort
void GetAdapter() 
{
    // remember, we assume there only one adapter (example purposes)
    for( int i = 0; DXGI_ERROR_NOT_FOUND != factory->EnumAdapters( i, &adapter ); ++i );
    {

        // get the description of the adapter, assuming no failure
        DXGI_ADAPTER_DESC adapterDesc;
        HRESULT hr = adapter->GetDesc( &adapterDesc );

        // Getting the outputs active on our adapter
        EnumOutputsOnAdapter();

    }
}

      

+3


source to share





All Articles