locked
Creating D1D2DeviceContext from scratch and on a bitmap?

    Question

  • I want to do off-screen rendering using Direct2D and ID2D1Effect and eventually get the final output on a IWICBitamp instance.

    I start with this code...

    Microsoft::WRL::ComPtr<ID2D1Factory1> m_d2dFactory;
    Microsoft::WRL::ComPtr<ID3D11Device>  m_d3dDevice;
    Microsoft::WRL::ComPtr<ID3D11DeviceContext> m_d3dContext;
    Microsoft::WRL::ComPtr<ID2D1Device>  m_d2d1Device;
    Microsoft::WRL::ComPtr<ID2D1DeviceContext> m_d2d1DeviceContext;
    
    D2D1_FACTORY_OPTIONS options;
    ZeroMemory(&options, sizeof(D2D1_FACTORY_OPTIONS));
    #if defined(_DEBUG)
    // If the project is in a debug build, enable Direct2D debugging via SDK Layers
      options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
    #endif
    
    D2D1CreateFactor(D2D1_FACTORY_TYPE_SINGLE_THREADED,__uuidof(ID2D1Factory1),&options,&m_d2dFactory ));
    
    UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
    
    #if defined(_DEBUG) // If the project is in a debug build, enable debugging via SDK Layers with this flag.
      creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
    #endif
    
    D3D_FEATURE_LEVEL featureLevels[]=
    {
    D3D_FEATURE_LEVEL_11_1,
    D3D_FEATURE_LEVEL_11_0,
    D3D_FEATURE_LEVEL_10_1,
    D3D_FEATURE_LEVEL_10_0,
    D3D_FEATURE_LEVEL_9_3,
    D3D_FEATURE_LEVEL_9_2,
    D3D_FEATURE_LEVEL_9_1
    };
    // ...
    HRESULT hr = D3D11CreateDevice(
    NULL,
    D3D_DRIVER_TYPE_HARDWARE,
    NULL,
    creationFlags,
    featureLevels,
    ARRAYSIZE(featureLevels),
    D3D11_SDK_VERSION,
    &m_d3dDevice,
    NULL,
    &m_d3dContext);
    
    Microsoft::WRL::ComPtr<IDXGIDevice> dxgiDevice;
    m_d3dDevice.As(&dxgiDevice);
    m_d2dFactory->CreateDevice(dxgiDevice.Get(), &m_d2d1Device);
    m_d2d1Device->CreateDeviceContext(
    D2D1_DEVICE_CONTEXT_OPTIONS_NONE, &m_d2d1DeviceContext);
    
    Microsoft::WRL::ComPtr<ID2D1Bitmap> bmp;
    D2D1_SIZE_U size = {3264, 2448};
    D2D1_BITMAP_PROPERTIES bmpProps = D2D1::BitmapProperties(D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE), 96.0f, 96.0f);
    
    m_d2d1DeviceContext->SetDpi(96.0f, 96.0f);
    hr = m_d2d1DeviceContext->CreateBitmap(size, bmpProps, &bmp);
    m_d2d1DeviceContext->SetTarget(bmp.Get());


    The last line raises exception and the breakpoint is set on the following function...

        HRESULT    CreateBitmap(        D2D1_SIZE_U size,        CONST D2D1_BITMAP_PROPERTIES &bitmapProperties,        _Outptr_ ID2D1Bitmap **bitmap         )
    {
       return CreateBitmap(size, NULL, 0, &bitmapProperties, bitmap);
    }

    And looks like the values in the functions are all uninitialized junk values.

    Help please?

     

    Friday, July 27, 2012 1:16 PM

Answers

  • Hi Pragos,

    I have implemented the same requirement for my image viewer.

    In which I am  applying a Blur effect and drawing it over a Bitmap by setting the bitmap as render target.

    I have used the following code.

    // Create temporary bitmap to render to in the background.
    	ComPtr<ID2D1Bitmap1> renderTarget;
    	D2D1_BITMAP_PROPERTIES1 renderTargetProperties = D2D1::BitmapProperties1(
    		D2D1_BITMAP_OPTIONS_TARGET,
    		D2D1::PixelFormat(
    		DXGI_FORMAT_B8G8R8A8_UNORM,
    		D2D1_ALPHA_MODE_PREMULTIPLIED
    		)
    		);
    
    	DX::ThrowIfFailed(
    		m_d2dContext->CreateBitmap(
    		m_imagePixelSize, 
    		nullptr,
    		0,
    		&renderTargetProperties,
    		&renderTarget
    		)
    		);
    	// Draw to temporary target in background. This ensures GPU processes image / populates mip levels.
    	// This drawing code is blocking, which is why we have to perform it on a background thread to allow
    	// the thumbnail to be continously rendered in the foreground.
    	m_d2dContext->SetTarget(renderTarget.Get());
    
    	m_d2dContext->BeginDraw();
    	m_d2dContext->DrawImage(
    		m_gaussianBlurEffect.Get(),
    		D2D1_INTERPOLATION_MODE_LINEAR,
    		D2D1_COMPOSITE_MODE_SOURCE_COPY
    		);
    
    	DX::ThrowIfFailed(m_d2dContext->EndDraw());

    In my case I have taken the rendered image as stream.

    thanks,

    Bhash

     

    • Marked as answer by pragos Friday, July 27, 2012 2:53 PM
    Friday, July 27, 2012 2:15 PM

All replies

  • Hi Pragos,

    I have implemented the same requirement for my image viewer.

    In which I am  applying a Blur effect and drawing it over a Bitmap by setting the bitmap as render target.

    I have used the following code.

    // Create temporary bitmap to render to in the background.
    	ComPtr<ID2D1Bitmap1> renderTarget;
    	D2D1_BITMAP_PROPERTIES1 renderTargetProperties = D2D1::BitmapProperties1(
    		D2D1_BITMAP_OPTIONS_TARGET,
    		D2D1::PixelFormat(
    		DXGI_FORMAT_B8G8R8A8_UNORM,
    		D2D1_ALPHA_MODE_PREMULTIPLIED
    		)
    		);
    
    	DX::ThrowIfFailed(
    		m_d2dContext->CreateBitmap(
    		m_imagePixelSize, 
    		nullptr,
    		0,
    		&renderTargetProperties,
    		&renderTarget
    		)
    		);
    	// Draw to temporary target in background. This ensures GPU processes image / populates mip levels.
    	// This drawing code is blocking, which is why we have to perform it on a background thread to allow
    	// the thumbnail to be continously rendered in the foreground.
    	m_d2dContext->SetTarget(renderTarget.Get());
    
    	m_d2dContext->BeginDraw();
    	m_d2dContext->DrawImage(
    		m_gaussianBlurEffect.Get(),
    		D2D1_INTERPOLATION_MODE_LINEAR,
    		D2D1_COMPOSITE_MODE_SOURCE_COPY
    		);
    
    	DX::ThrowIfFailed(m_d2dContext->EndDraw());

    In my case I have taken the rendered image as stream.

    thanks,

    Bhash

     

    • Marked as answer by pragos Friday, July 27, 2012 2:53 PM
    Friday, July 27, 2012 2:15 PM
  • Thanks Bhash, that worked for me!

    Can I get the pixels from ID2D1Bitmap1 into an array or into a IWICBitmap? Or how Can I save the result after EndDraw()?

    I tried this...

        ComPtr<ID2D1Bitmap1> m_d2d1TargetBitmap;
        ...
        ...
        ComPtr<IDXGISurface> surface;
        m_d2d1TargetBitmap->GetSurface(&surface);
        DXGI_MAPPED_RECT mappedRect;
        DXGI_SURFACE_DESC desc;
        surface->GetDesc(&desc);
        HRESULT hr = surface->Map(&mappedRect, DXGI_MAP_READ);

    tried The mappedRect.pBits is supposed to get the pointer to the image pixels, but the problem is, the Map call failed with invalid argument error returned.

    • Edited by pragos Friday, July 27, 2012 4:03 PM
    Friday, July 27, 2012 2:55 PM