leadedge / Spout2

A video frame sharing system for Microsoft Windows
BSD 2-Clause "Simplified" License
760 stars 138 forks source link

flickering because receiver sometimes can't access the shared texture. #89

Closed nashiro66 closed 1 year ago

nashiro66 commented 1 year ago

I implemented texture sharing between opengl process.

However, every other draw, the program can't access shared image. Here is a demo capture. I found that CheckTextureAccess returns false in ReadGLDXtexture func and can't GetSharedTextureData every other draw. Source code is here.

Thank you.

leadedge commented 1 year ago

I have built both your receiver and sender projects and they work without flicker for me. But we need to find out what the problem is. First of all, could you try -


bool Receiver::Connect()
{
    if (spout.ReceiveTexture(texture.GetTexId(), GL_TEXTURE_2D, false)) {
        if (spout.IsUpdated())
        {
            texture.Resize(spout.GetSenderWidth(), spout.GetSenderHeight());
        }
        if (spout.BindSharedTexture())
        {
            ShowLog();
            return true;
        }
    }
    return false;
}

Next, remove the mutex test and leave the texture sync to the GL/DX interop. Remove these lines -

    // if (frame.CheckTextureAccess(m_pSharedTexture)) {
        --- 
        --- 
        --- 
        // frame.AllowTextureAccess(m_pSharedTexture);
    // }

If that solves it, put the lines back in and test for a timeout in "CheckAccess" by adding the log that is commented out.

            case WAIT_TIMEOUT: // The time-out interval elapsed,
            SpoutLogError("CheckAccess - WAIT_TIMEOUT");
            break;

Is the graphics driver vertical sync setting on or off? What is the graphics hardware?

nashiro66 commented 1 year ago

I changed my code as you suggest , but it does not work. THe graphics hardware is GeForce RTX 2070 super and vertical sync setting is on. I had my friend(similaly GeForce hardware) try it, but it still is flickering.

Thank you.

leadedge commented 1 year ago

I think the problem is that the OpenGL shared texture is bound and this prevents access to the Directx shared texture that it is linked to.

There is a texture used to receive to but that is never used. Try the following -

bool Receiver::Connect()
{
    // Unbind if connected
    if (spout.IsConnected())
        spout.UnBindSharedTexture();

    if (spout.ReceiveTexture())
    {
        if (spout.BindSharedTexture()) {
            ShowLog();
            return true;
        }
    }
    return false;
}

The only problem is that the texture will be inverted because it is connected to a DirectX texture. You will need to flip the vbo texture vertices in Y.

nashiro66 commented 1 year ago

This worked! Thank you.

leadedge commented 1 year ago

That's good. Normally you would follow BindSharedTextre() with UnBindSharedTexture(), but this will work OK.