4

I am pretty new to DirectX 10 programming, and I have been trying to do the following with my limited skills..

I am trying to display an Image from one machine on to another output device(Another Monitor/TV) connected via HDMI. I researched on it and came to know that DXGI can be pretty useful for rendering purposes. Moreover while researching further I came across this link here. It does show how to display different images on multiple monitors connected to the main machine but it requires extended display for that.

My requirement is that when I run the code It should render the image on another output device without making it an extended display.

Approcah I am trying is that I am enumerating Video Adapters(which in my case is 1 ) and and then enumerating outputs available which should be two in numbers as I have an HDMI out connected to my PC. But if I do not set extended display it shows only one output available in my enumerated outputs array and if I extend the display it shows two of them.Once I am done with enumerating outputs I want to Render that image on desired output.

As far as i know every video adapter has a port for HDMI connected to it.

I wonder, if there is way I can access that port programatically and could render the image using that port??

Other than MSDN, documentation or explanation of those concepts are rather limited, so any help would be very welcome. Here is some 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's 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's 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();

    }
}
Community
  • 1
  • 1
G droid
  • 956
  • 5
  • 13
  • 36
  • 2
    When *everything* is **bold**, *nothing* is **bold** – Thomas Ayoub Apr 30 '15 at 11:37
  • @Thomas: Looks ok now?? :) – G droid Apr 30 '15 at 11:40
  • When you plug an external screen, the choices are "Clone" || "Extended" (I remove the cases with just one screen). So you want your ext display to be in which mode? (nice edit btw ;) ) – Thomas Ayoub Apr 30 '15 at 11:44
  • 1
    @Thomas: I don't want to use any mode ..Actually I want to display an image in the monitor (or TV) connected to HDMI port without extending the display..Is there any way I can access HDMI port of the video adapter progrmatically?? – G droid Apr 30 '15 at 12:00
  • I (think) I understood this. But to display something on the TV, the computer need to "know" it and assign it a mode, isn't it? – Thomas Ayoub Apr 30 '15 at 12:07
  • @Thomas: you are right..Is it at all possible that I only show image on the TV i want to render without cloning or extending the full desktop..can i just render an image on TV with TV's own background?? – G droid Apr 30 '15 at 12:12
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/76639/discussion-between-g-droid-and-thomas). – G droid Apr 30 '15 at 12:18
  • @Steve:Actually we are in a team..i will get it removed asap.. – G droid May 01 '15 at 05:36
  • @Gdroid have you managed to find a solution? I am facing a similar issue. – Elad Maimoni Jul 11 '18 at 17:24

0 Answers0