Workaround for ID3D11Texture2D to ResourcePtr

Mar 24, 2013 at 12:12 AM
Edited Mar 24, 2013 at 12:12 AM
Ive implemented inside the RendererDX11 one method to make a ResourcePtr of a ID3D11Texture2D:

Is there a workaround to do this without modificate the engine?
ResourcePtr RendererDX11::LoadTexture( ID3D11Texture2D* texture2D ) //@MODIFICATION HIEROGLYPH3 0001
{
    int ResourceID = StoreNewResource( new Texture2dDX11( reinterpret_cast< ID3D11Texture2D* >( texture2D ) ) );

    Texture2dConfigDX11 TextureConfig;
    reinterpret_cast< ID3D11Texture2D* >( texture2D )->GetDesc( &TextureConfig.m_State );

    return( ResourcePtr( new ResourceProxyDX11( ResourceID, &TextureConfig, this ) ) );
}
Coordinator
Mar 24, 2013 at 12:35 AM
Where did the texture pointer come from that you passed in? The Renderer is supposed to be the only class with access to the device, so any texture creation should be done within the renderer itself. If it is created inside the renderer, then that method should store it within the renderer with the StoreNewResource method.

Would that work for you?
Mar 24, 2013 at 12:41 AM
Edited Mar 24, 2013 at 12:42 AM
I have a extern renderer. It renders the Direct2D content in an ID3D11Texture2D. I have to create this mehod to inject this Tetxture in your engine.
Coordinator
Mar 24, 2013 at 12:46 AM
Ahhh - I see. It should be possible for me to implement this method then - probably I will need to add a reference to the interface to ensure that it isn't destroyed before the renderer is finished using it. I can put that into the next release, and I'll use a method similar to what you have posted here.

Thanks for the suggestion!
Mar 24, 2013 at 2:12 AM
Edited Mar 24, 2013 at 2:54 AM
Ive postet you the GUIOverlay.cpp in one other thread.

It shows the use of the LoadTexture(...)-Method call to convert an ID3D11Texture2D to a ResourcePtr smartpointer.

Edit:
I see i had to implement one more method inside the engine to use the extern D2D1Renderer.

you can see it in my InitializeD2D1Renderer() Method inside the App class. (postet in one thread)
if(!_rendererD2D1->Initialize(m_pWindow->GetHandle(), &m_pRenderer11->GetDevice(), width, height)) {
    return false;
}
There is the m_pRenderer11->GetDevice() method. So I have to get the ID3D11Device device from your RendererDX11 object.

I make this method for that to get it.
ID3D11Device& RendererDX11::GetDevice() {
    return *m_pDevice;
}
Coordinator
Mar 26, 2013 at 3:10 AM
Is it necessary to get a reference to the device? Wouldn't it be possible to add a method to the renderer that you could use to generate the texture surface from within RendererDX11?

I have no problem to add the methods if this is the only way to gain access to the D2D functionality, but if possible I would like to keep the device itself encapsulated within the renderer. Does the ID3D11Device interface need to be the same one that is being used in the Hieroglyph renderer, or can it be any device that gets created by the D2D renderer?

Unfortunately I'm not that familiar with D2D... I'll add these methods in, and then if we can make it work without them then I will remove them at a later time.
Mar 26, 2013 at 7:16 AM
You have right. We dont really need the device do integrate the renderer properly. The only thing we need is a Texture on that we can render the direct2D content.

I will reconsider it. Gimme some time.
Mar 26, 2013 at 7:48 AM
Edited Mar 26, 2013 at 9:18 AM
Ok i removed the ID3D11Device& GetDevice(); method out of you RenderDX11 and create a method like this:
ID3D11Texture2D* CreateSharedSurface(int width, int height);
ID3D11Texture2D* RendererDX11::CreateSharedSurface(int width, int height) {
    HRESULT hr;

    // Create the shared texture to draw D2D content to
    D3D11_TEXTURE2D_DESC desc;
    ZeroMemory(&desc, sizeof(desc));

    desc.Width = width;
    desc.Height = height;
    desc.MipLevels = 1;
    desc.ArraySize = 1;
    desc.Format = DXGI_FORMAT::DXGI_FORMAT_B8G8R8A8_UNORM;
    desc.SampleDesc.Count = 1;
    desc.Usage = D3D11_USAGE::D3D11_USAGE_DEFAULT;
    desc.BindFlags = D3D11_BIND_FLAG::D3D11_BIND_RENDER_TARGET | D3D11_BIND_FLAG::D3D11_BIND_SHADER_RESOURCE;
    desc.MiscFlags = D3D11_RESOURCE_MISC_FLAG::D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;

    ID3D11Texture2D* sharedTexture_DX11 = 0;
    hr = m_pDevice->CreateTexture2D(&desc, NULL, &sharedTexture_DX11);

    return sharedTexture_DX11;
}
if(!_rendererD2D1->Initialize(m_pRenderer11->CreateSharedSurface(width, height))) {
       return false;
 }
The handling of the lifetime of the sharedTexture is going to the enduser. Perhaps you handle this inside your renderer then.

I will adapt the implementation details in the documentation.

Is such a method what you thought about?
Coordinator
Mar 26, 2013 at 12:08 PM
That is perfect. So this is sufficient to allow the D3D and the D2D device to collaborate on the same surface? If so, we don't have to worry about the lifetime management, since both sides are able to add a reference to the COM object. Hieroglyph 3 will inherently have added a reference by creating the object, and your D2D renderer can manually add one in the initialize function.

That way there is no guessing about when it should be destroyed. I can update the code and commit it later tonight.

Thanks for the fast turnaround on the idea!
Mar 26, 2013 at 3:03 PM
Edited Mar 26, 2013 at 6:25 PM
There are four hard task to figure out in the future.

1) Mixing heavy and lightweight components with the interaction-model (mouse events should be aborted on the 3D view if the 2D content is over it) [I think there we have to interop someday]
2) Resizing of the application scales the texture. Causes that the mouse hittest is not correct anymore. [I think a update method on size changing on my side will do this]
3) Making it possible to render in multiply textures, so it is possible to use the D2D1Renderer on meshes, as overlay or do what ever at the same time. [On my side]
4) Implementing mechanisms for absolute and relative coordinates [On my side]
Coordinator
Mar 27, 2013 at 2:19 AM
I think those four items should be possible. Here are my comments on them:
  1. This is handled in my event system by the handler returning true. If it returns true, then the event manager stops passing that event to other listeners. I think something similar to this should be able to get the interaction model to work out ok. Most likely the 2D layer would get the first chance to handle the events, and then it would get passed to the 3D layer.
  2. The resize event in Hieroglyph could be set up to resize the texture from within the renderer. Actually, if the application is set up to manage that texture then this will happen automatically. The only other thing we would need is a resize method in the D2D1Renderer so that it can update its data structures accordingly.
  3. This could be similar to the resize method, where you just accept a shared texture pointer as an input (i.e. something like SetTarget(ID3D11Texture2D* pTexture) ). Most of the code for this is probably already available in your renderer, it just has to be refactored a little bit.
  4. This one is on your side :)
I won't have access to my development machine tonight, so I can't make any updates until tomorrow. However, I should be able to get your command line args added in, as well as the create shared texture method. After that I plan to take a closer look at the mouse event model changes. You are moving pretty fast - I'm having trouble keeping up!

In any case, I am really enjoying the exchange, and I look forward to further collaboration.
Mar 27, 2013 at 4:19 AM
1) Yes this was my solution too when i modificates your engine.
2) Yes
3) I will look
4) Yes

There is no hurry. Im a little workaholic that has no reallife at the moment.
Coordinator
Mar 28, 2013 at 2:53 AM
I just took a closer look at the code snippet you posted above, and this is actually already supported in the Hieroglyph engine. You can create a texture in the normal way by passing a description structure to it. Then you can use the renderer method shown here:
Texture2dDX11* RendererDX11::GetTexture2DByIndex( int rid );
The returned interface has a method for acquiring the raw ID3D11Resource*, which can then be cast to a ID3D11Texture2D* and used in the 2D renderer. This is a bit of a long way around, but it would allow us to keep the existing mechanisms in place without creating a special case for 2D textures. If you would like, I can write a small patch and send it over to you for the D2D1Renderer that implements this method...

In any case, I will be adding the method for acquiring the command line parameters, and then we'll see what I can add from there.
Mar 28, 2013 at 8:44 AM
Ok yes i give it a try.