Home > OS >  Unity: CopyTexture to External texture2D
Unity: CopyTexture to External texture2D

Time:03-22

I need to expose a Unity texture/Rendertexture to some native plugin, which requires the "D3D11_RESOURCE_MISC_SHARED" flag on the texture.

textures created by unity doesn't have this flag, so, I created it from the plugin side, and then created a reference texture within unity using CreateExternalTexture, and copied the contents to this native texture using Graphics.CopyTexture.

the 2 textures have the same dimension, same size, same format, and same mipCount(0)

the problem is, when I show it in unity (for debugging purpose), I can see nothing and no error occurs.

btw, if I copy by ReadPixel, an error occures :

ReadPixels called on undefined image 0 (valid values are 0 - -1

if I create the texture using unity api, CopyTexture succeeds and result can be seen. but then, I lose the "D3D11_RESOURCE_MISC_SHARED" flag.

so, maybe the texture I created is not valid? my code:

    D3D11_TEXTURE2D_DESC desc = { 0 };
desc.Width = width;
desc.Height = height;
desc.MipLevels = 0;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;//这里,格式能不能调整?比如,A8是需要的吗?
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;//普通资源
//desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;//应该不需要cpu访问的,不是read也不是write
desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;//for "OpenSharedHandle" d3d11 api

HRESULT hr = E_FAIL;
if (FAILED(hr = pDevice->CreateTexture2D(&desc, nullptr, &g_unityEquirectTexture)))
{
    Log(" Create Shared Texture Failed!");
    return NULL;
}
Log("CreateSharedTexture success");
//return g_unityEquirectTexture;

Unity CopyTexture Code:

        if (output == null)
    {
        Debug.Log($"limit = {QualitySettings.masterTextureLimit}");
        //output = new Texture2D(equirect.width, equirect.height, TextureFormat.RGBA32,false);//uncomment this line and then copyTexture below succeeds
        IntPtr externalTextureData = CGDKInterOp.cgdk_c_CreateExternalTexture(equirectLeft.GetNativeTexturePtr(), equirectLeft.width * 2, equirectLeft.height);
        if (externalTextureData != IntPtr.Zero)
        {
            output = Texture2D.CreateExternalTexture(equirectLeft.width * 2, equirectLeft.height, TextureFormat.RGBA32, false, true, externalTextureData);
        }
    }
    if (output == null)
    {
        Debug.LogError("create texture from external failed!");
        return;
    }

    //RenderTexture.active = equirect;
    //output.ReadPixels(new Rect(0, 0, equirect.width, equirect.height), 0, 0);
    //RenderTexture.active = null;
    Graphics.CopyTexture(equirect, output);

CodePudding user response:

There might be a better solution for this but the last time I needed to copy over texture data from a native side to managed (Unity), I did it through marshalling of the data.

You essentially just need to expose a method in the native plugin to pass you the texture data as an array and then have a method in the C# code to fetch it data (by calling the method), releasing the pointer to native memory when you're done. You can find information about marshalling and interop in Microsoft's documentation (e.g. https://docs.microsoft.com/en-us/dotnet/framework/interop/marshalling-different-types-of-arrays). If your texture is always guaranteed to be of the same size and format, it's easier - but if you need to know some additional parameters so that you know how the Texture should be represented in managed-land, you can always pass yourself the additional data through the same method.

CodePudding user response:

OK, solved by myself.

the problem is: Miplevel == 0.this causes d3d11 creating a texture with 0B memory allocated! change Miplevel to 1 solved the problem

note: In unity inspector, we can see the memory allocated by textures. I found that my texture has 0B memory from the inspector and then, I search using this clue and found the solution

  • Related