Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: [FIXED] RenderTexture on Intel GPU's. Let's fix this problem!  (Read 34881 times)

0 Members and 1 Guest are viewing this topic.

Haikarainen

  • Guest
[FIXED] RenderTexture on Intel GPU's. Let's fix this problem!
« on: September 14, 2012, 05:21:52 pm »
This issue was solved faster than anyone could think! Thanks to everyone involved, great effort!
At the time of writing you still need the git-version of sfml2 for the fix to be applied


This has been a known problem for a while now and it is really annoying, since RenderTexture is a huge asset to the SFML library.

I would like to gather all information possible on this problem and fix this once in for all (on linux at least, dont know if it happens on windows). I know a lot of people have been working hard debugging this problem, as have I, and I would really love it if we could gather all the people who are willing to work on this and actually fix it.

If you think you can help in any way, reply in this thread. If you need some sort of inspiration, please let it be known that Intel engineers are working fullspeed on fixing their drivers for other issues, mostly because of the Valve-Intel-cooperation on porting Steam to Linux.

The information I've gathered so far, by debugging:


I get error
intel_do_flush_locked    No such file or directory
When calling RenderTexture::display(). On my unoptimized testbed it is always the third call of one instance.

gdb does not return any sigtrap/segfault or any other error.

I have tried forcing SFML to use the fallback mechanism (context from hidden window) instead of FBO by forcing priv::RenderTextureImplFBO::isAvailable() to return false, did not do any difference.

Tried both SNA and UXA acceleration.

I have tried to track down the error down to the XFree86's Intel drivers sourcecode(2.20.7) http://cgit.freedesktop.org/xorg/driver/xf86-video-intel/, and I think it's related to the function intel_batch_do_flush on line 119 of file intel_batchbuffer.c:

static void intel_batch_do_flush(ScrnInfoPtr scrn)
{
        intel_screen_private *intel = intel_get_screen_private(scrn);
        struct intel_pixmap *priv;

        list_for_each_entry(priv, &intel->batch_pixmaps, batch)
                priv->dirty = 0;
}

I am not sure though, I cant find any file that contains parts of the error I get, so it's a tough nut to crack. Given that it is a "No such file"-error it should be an easy fix though.


I will set up a virtualbox instance a partition on my laptop with a custom linuxsetup as a proper testbed, create a minimal reproduction of the error with the latest SFML so I can truly debug both SFML code as well as driver-code without messing up my box.

Any information hugely appreciated, current set up for these results:

ArchLinux Kernel 3.5.3-1-ARCH x86_64
Intel Core i7 3610-QM
Intel Graphics HD 4000 running xf86-video-intel-sna driverpackage from official arch repos.
4 GB Memory DDR3 (Shared with GPU)
SFML 2.0
« Last Edit: October 16, 2012, 08:58:35 pm by Haikarainen »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: RenderTexture on Intel GPU's. Let's fix this problem!
« Reply #1 on: September 14, 2012, 06:28:18 pm »
Quote
I have tried forcing SFML to use the fallback mechanism (context from hidden window) instead of FBO by forcing priv::RenderTextureImplFBO::isAvailable() to return false, did not do any difference.
This is strange, because this fallback involves nothing more than what sf::RenderWindow uses.
Laurent Gomila - SFML developer

Haikarainen

  • Guest
Re: RenderTexture on Intel GPU's. Let's fix this problem!
« Reply #2 on: September 14, 2012, 07:32:55 pm »
Allright I have been able to locate the "faulty" line of code in SFML. I don't know if it is SFMLs fault, but commenting it out makes my test-unit run perfectly. Will check how well SFML works without it and look for substitutes.

This code:
#include <iostream>
#include <SFML/Graphics.hpp>

int main(int argc, char **argv) {
        std::cout <<    "sfml-intel-debug utility v 0.1" << std::endl;
       
        std::cout << "Instancing RenderTexture dbg_tex" << std::endl;
        sf::RenderTexture dbg_tex;
       
        std::cout << "Creating empty 128x128" << std::endl;
        dbg_tex.create(128,128);
       
        std::cout << "Initiating clear-display loop" << std::endl;
        for(int i = 0; i < 10;i++){
                std::cout << i << ": Clearing.. ";
                dbg_tex.clear();
                std::cout << "Displaying.. ";
                dbg_tex.display();
                std::cout << "OK." << std::endl;
        }
       

        std::cout << "All tests done. Seems to work." << std::endl;
        return 0;
}

Crashes if SFML flushes here:
void RenderTextureImplFBO::updateTexture(unsigned int)
{
        std::cout << "AlterDBG: Ignoring flush!" << std::endl;
    //glFlush();
}

My understanding of glFlush is, that it forces the underlying OpenGL mechanisms to complete its operations (probably in another thread?) before continuing, this would probably create tearing or other distortions to rendertextures, but I do not know yet, I will test another project of mine with the altered libraries.

EDIT: allright I tested looping the clear-display 100 times instead, without the flush, and it seems to crash once the internal operations finish anyway. As I suspected.
« Last Edit: September 14, 2012, 07:36:55 pm by Haikarainen »

Haikarainen

  • Guest
Re: RenderTexture on Intel GPU's. Let's fix this problem!
« Reply #3 on: September 14, 2012, 09:37:00 pm »
I tried to debug it further by creating a minimal example of what SFML internally do when creating, clearing and displaying a rendertexture, but I failed miserably to do so because of SFML's complexity and my lack of knowledge of the sfml codebase.

Laurent if you're still uptodate on how rendertextures work internally and have time I'd really appreciate if you could help me out on this.

I basically want:

sf::RenderTexture tex;
tex.create(32,32);
tex.clear();
tex.display();

except the internal code. My efforts so far are really pityful, and involves sf::(priv::Gl?)Context:

        sf::Context context;
        for(int x = 0; x < 100; x++){
                glClear(GL_DEPTH_BUFFER_BIT);
                context.display(); // <- this lines fail, I bet you know why
        }

It would really be much easier to debug this if you take the higherlevel sfml api and go deeper, instead of starting out and guessing at drivers/gl code and going upwards

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: RenderTexture on Intel GPU's. Let's fix this problem!
« Reply #4 on: September 15, 2012, 12:18:27 am »
Here it is:

#include <GL/glew.h>
#include <SFML/OpenGL.hpp>
#include <SFML/Window.hpp>
#include <iostream>

int main()
{
    // ----- RenderTexture::create -----

        // ----- RenderTextureImplFBO::isAvailable -----

        sf::Context dummy;
        if (glewInit() != GLEW_OK)
        {
            std::cout << "glewInit failed" << std::endl;
            return -1;
        }

        if (!GLEW_EXT_framebuffer_object)
        {
            std::cout << "GLEW_EXT_framebuffer_object not supported" << std::endl;
            return -1;
        }

        // ----- Texture::create -----
        GLuint texture;
        glGenTextures(1, &texture);
        if (glGetError() != GL_NO_ERROR)
        {
            std::cout << "glGenTextures failed" << std::endl;
            return -1;
        }

        glBindTexture(GL_TEXTURE_2D, texture);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
        if (glGetError() != GL_NO_ERROR)
        {
            std::cout << "glTexImage2D failed" << std::endl;
            return -1;
        }

        // ----- RenderTextureImplFBO::create -----

        sf::Context* context = new sf::Context;

        GLuint frameBuffer = 0;
        glGenFramebuffersEXT(1, &frameBuffer);
        if (!frameBuffer || (glGetError() != GL_NO_ERROR))
        {
            std::cout << "glGenFramebuffersEXT failed" << std::endl;
            return -1;
        }
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameBuffer);
        if (glGetError() != GL_NO_ERROR)
        {
            std::cout << "glBindFramebufferEXT failed" << std::endl;
            return -1;
        }

        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture, 0);
        if (glGetError() != GL_NO_ERROR)
        {
            std::cout << "glFramebufferTexture2DEXT failed" << std::endl;
            return -1;
        }

        if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
        {
            std::cout << "glCheckFramebufferStatusEXT failed" << std::endl;
            return -1;
        }

    for (int i = 0; i < 100; ++i)
    {
        // ----- RenderTarget::clear -----

        if (!context->setActive(true))
        {
            std::cout << "context.setActive failed" << std::endl;
            return -1;
        }
        glClearColor(1.f, 1.f, 1.f, 1.f);
        glClear(GL_COLOR_BUFFER_BIT);

        // ----- RenderTarget::display -----

        glFlush();
        if (glGetError() != GL_NO_ERROR)
        {
            std::cout << "glFlush failed" << std::endl;
            return -1;
        }
    }

    // ----- RenderTexture::~RenderTexture -----

        // ----- RenderTextureImplFBO::~RenderTextureImplFBO -----

        glDeleteFramebuffersEXT(1, &frameBuffer);
        if (glGetError() != GL_NO_ERROR)
        {
            std::cout << "glDeleteFramebuffersEXT failed" << std::endl;
            return -1;
        }
        delete context;

        // ----- Texture::~Texture -----

        glDeleteTextures(1, &texture);
        if (glGetError() != GL_NO_ERROR)
        {
            std::cout << "glDeleteTextures failed" << std::endl;
            return -1;
        }

    return 0;
}

Let me know if it correctly reproduces the error.

I really appreciate that you work hard on this major problem, a lot of users will thank you if you succeed to solve it :)
« Last Edit: September 15, 2012, 12:20:21 am by Laurent »
Laurent Gomila - SFML developer

Foaly

  • Sr. Member
  • ****
  • Posts: 453
    • View Profile
Re: RenderTexture on Intel GPU's. Let's fix this problem!
« Reply #5 on: September 15, 2012, 01:31:15 am »
Awesome! I'd really like to see this fixed :)

Haikarainen

  • Guest
Re: RenderTexture on Intel GPU's. Let's fix this problem!
« Reply #6 on: September 15, 2012, 01:52:32 pm »
Here it is:

...

Let me know if it correctly reproduces the error.

I really appreciate that you work hard on this major problem, a lot of users will thank you if you succeed to solve it :)

Thanks a lot :) It does reproduce the problem! Will continue debugging today

EDIT: Finally something more specific that seems to work!

If you clear with depth buffer instead of  GL_COLOR_BUFFER_BIT it works! WOO more info to debug with :D

EDIT2: Got a hint http://www.google.se/search?sugexp=chrome,mod=2&sourceid=chrome&ie=UTF-8&q=IntelClearWithBlit from https://bugs.kde.org/show_bug.cgi?id=kwin-intel

EDIT3: I've been able to trace the problem back to the mesa drivers http://opensource.apple.com/source/X11server/X11server-85/mesa/Mesa-7.0.4/src/mesa/drivers/dri/i965/intel_blit.c  look at IntelClearWithBlit. It does some if-statements on what kind of bufferbit to clear with, and then proceeds to LOCK_HARDWARE if it isnt depth or stencil bit.

EDIT4: Allright, Ofc those are the apple drivers and the linux ones seems to be a bit different(and way more complicated). I will try to debug these but Im not sure I will succeed. Source is here: http://cgit.freedesktop.org/mesa/mesa/ lsmod | grep intel to see wether you use 915/965 mesa drivers.

EDIT5: Some more info, the specific errors that begins with "intel_do_flush_locked" is printed from line  167 in file "intel_batchbuffer.c" .

EDIT6: Traced the actual function that fails to libdrm, function drm_intel_bo_mrb_exec. Have downloaded source of same version I have installed from http://dri.freedesktop.org/libdrm/

EDIT7: Allright I'm taking a break. The DRM code is REALLY ugly (im currently still tracing the drm_intel_bo_mrb_exec function, it returns another function, which in turn returns another function and goes on like that in a long loop. Currently in intel_bufmgr_gem.c. Oh, they also use GOTO statement).

If anyone feels like it, please go ahead and debug this.
« Last Edit: September 15, 2012, 03:50:54 pm by Haikarainen »

Szunti

  • Newbie
  • *
  • Posts: 10
    • View Profile
Re: RenderTexture on Intel GPU's. Let's fix this problem!
« Reply #7 on: September 15, 2012, 10:08:23 pm »
I started a hunt for this bug. The mesa xdemo manywin gives the same intel error. The code is much easier, And there I could find what happens.

Shortly the problem is multiple XOpenDisplay calls + opengl context sharing. When I changed manywin to use one XOpenDisplay call and reuse the Display struct pointer from that, it started to work.


In detail (I didn't know much about OpenGL and don't really know the X Server so it might say obvious things):

1) Display *XOpenDisplay(...) calls give another pointer back every time, even for same display.
2) __glXInitialize(Display* dpy), which should initialize displays for OpenGl use the address of the Display struct to store which displays has been initialized, so for every pointer from XOpenDisplay it initializes the display, even multiple times the same one, if you use XOpenDisplay for the same display, which is the situation in manywin
3) for every screen intel-drm creates  a bufmgr to store buffer-objects, in our case it means different bufmgr for windows on same display
4) bufmgr-s cannot share objects, but manywin use a shared context for the windows
5) when the bufmgr creates the exec_buffer (which is the code that the GPU will run), it cannot reference the shared context's object, and drm gives an ENOENT error, which is translated to "No such file or directory."

I filed a bug to mesa: https://bugs.freedesktop.org/show_bug.cgi?id=54971

If the problem is the same, then a workaround is to limit the XOpenDisplay and similar calls count to 1.

Szunti

  • Newbie
  • *
  • Posts: 10
    • View Profile
Re: RenderTexture on Intel GPU's. Let's fix this problem!
« Reply #8 on: September 15, 2012, 10:12:55 pm »
And I have a dirty patch to libgl which lets me run the sfml shader example, although it crash with a different error in manywin and in the sample program you gave.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: RenderTexture on Intel GPU's. Let's fix this problem!
« Reply #9 on: September 15, 2012, 10:53:41 pm »
So, in the code I posted above, if you remove these lines:

sf::Context* context = new sf::Context;
if (!context->setActive(true))
{
    std::cout << "context.setActive failed" << std::endl;
    return -1;
}
 
delete context;

... the error disappears?
Laurent Gomila - SFML developer

Szunti

  • Newbie
  • *
  • Posts: 10
    • View Profile
Re: RenderTexture on Intel GPU's. Let's fix this problem!
« Reply #10 on: September 15, 2012, 11:12:33 pm »
Not unfortuantely.

Btw a good way to get some info about buffer objects etc, is using the INTEL_DEBUG environment variable.

I use
INTEL_DEBUG="buf bat" ./sfml-test 2>&1 | less

Which shows weird things.
« Last Edit: September 18, 2012, 11:33:15 pm by Szunti »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: RenderTexture on Intel GPU's. Let's fix this problem!
« Reply #11 on: September 15, 2012, 11:17:36 pm »
Quote
Not unfortuantely.
But there's only one OpenGL context and one call to XOpenDisplay, with this modification. So is there something else which causes the error?

Quote
Which shows weird things.
Like what? :P
Laurent Gomila - SFML developer

Szunti

  • Newbie
  • *
  • Posts: 10
    • View Profile
Re: RenderTexture on Intel GPU's. Let's fix this problem!
« Reply #12 on: September 16, 2012, 12:13:55 am »
XOpenDisplay is called a lot of times. I can see that in gdb. I am almost sure that the last test program would work if they weren't.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: RenderTexture on Intel GPU's. Let's fix this problem!
« Reply #13 on: September 16, 2012, 10:22:02 am »
Hmm yeah, maybe there's something tricky with my internal context management.

Anyway, since you already wrote a patch that makes a single call to XOpenDisplay, it would be easier for people to just test your modified version of SFML.

For anyone who wants to test it, here it is:
https://github.com/Szunti/SFML/tree/1display
Laurent Gomila - SFML developer

Szunti

  • Newbie
  • *
  • Posts: 10
    • View Profile
Re: RenderTexture on Intel GPU's. Let's fix this problem!
« Reply #14 on: September 16, 2012, 01:36:11 pm »
And if you test pls test the shader exmaple. For me, when I change to the "edge post-effect" effect the pixelate shader is used again on the objects.

 

anything