Linux off screen rendering doesn't work with gpu enabled

Having problems with building or using CEF's C/C++ APIs? This forum is here to help. Please do not post bug reports or feature requests here.

Linux off screen rendering doesn't work with gpu enabled

Postby hhyyrylainen » Tue Apr 10, 2018 3:19 am

Hi,

I had a weird issue where the buffer that CEF passed to OnPaint contained garbage / was glitched when I didn't use single-process mode.
I'm using version "cef_binary_3.3325.1756.g6d8faa4_linux64_minimal" with Ogre (if that makes a difference as it maybe fails in connecting to the opengl driver or something).
My opengl driver is "OpenGL version string: 4.6.0 NVIDIA 390.48"

It looked like this:
Image

Also when I used the approach also used in the sample program for setting the cursor I got an X11 error:
Code: Select all
X Error of failed request:  BadCursor (invalid Cursor parameter)
  Major opcode of failed request:  2 (X_ChangeWindowAttributes)
  Resource id in failed request:  0x780000a
  Serial number of failed request:  2083
  Current serial number in output stream:  2084


Edit: I have fixed this error (BadCursor) by using "cef_get_xdisplay();" instead of the one I created my window with.

All of this gets fixed if I use "--single-process" flag OR which I think it a better fix "--disable-gpu". I'm going to force disable gpu on linux for now but I'd like to know if this is a bug in CEF (or chromium) or I did something wrong.

This is how it looks with "--disable-gpu" (and the cursor changing also works):
Image

Here's my OnPaint method:
Code: Select all
void View::OnPaint(CefRefPtr<CefBrowser> browser, PaintElementType type,
    const RectList& dirtyRects, const void* buffer, int width, int height)
{
    CEF_REQUIRE_UI_THREAD();
    Engine::Get()->AssertIfNotMainThread();

    if(dirtyRects.empty()) {

        LOG_ERROR("View: OnPaint given empty dirtyRects list");
        return;
    }

    // Lock us, just for fun //
    // As we are always on the main thread
    GUARD_LOCK();

    // Calculate the size of the buffer //
    size_t buffSize = width * height * CEF_BYTES_PER_PIXEL;

    Ogre::TexturePtr targettexture;

    switch(type) {
    case PET_POPUP: {
        LOG_ERROR("CEF PET_POPUP not handled");
        return;
    }
    case PET_VIEW: {
        targettexture = Texture;
        break;
    }
    default: LOG_FATAL("Unknown paint type in View: OnPaint"); return;
    }

    // Make sure our texture is large enough //
    if(targettexture->getWidth() != static_cast<size_t>(width) ||
        targettexture->getHeight() != static_cast<size_t>(height)) {

        // Free resources and then change the size //
        targettexture->freeInternalResources();
        targettexture->setWidth(width);
        targettexture->setHeight(height);
        targettexture->createInternalResources();

        LOG_INFO("GuiView: recreated texture for CEF browser");
    }

    // Copy it to our texture //
    Ogre::v1::HardwarePixelBufferSharedPtr pixelBuffer = targettexture->getBuffer();

    LEVIATHAN_ASSERT(
        pixelBuffer->getSizeInBytes() == buffSize, "CEF and Ogre buffer size mismatch");

    // Copy the data over //
    const auto firstRect = dirtyRects.front();
    if(dirtyRects.size() == 1 && firstRect.x == 0 && firstRect.y == 0 &&
        firstRect.width == width && firstRect.height == height) {

        // Can directly copy the whole thing
        pixelBuffer->lock(Ogre::v1::HardwareBuffer::HBL_DISCARD);
        const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock();

        uint8_t* destptr = static_cast<uint8_t*>(pixelBox.data);
        std::memcpy(destptr, buffer, buffSize);

        pixelBuffer->unlock();

    } else {

        // Lock buffer and get a target box for writing //
        pixelBuffer->lock(Ogre::v1::HardwareBuffer::HBL_NORMAL);
        const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock();

        uint32_t* destptr = static_cast<uint32_t*>(pixelBox.data);
        const uint32_t* source = static_cast<const uint32_t*>(buffer);

        const size_t rowElements = pixelBox.rowPitch;

        for(const auto rect : dirtyRects) {

            const auto lastX = rect.x + rect.width;
            const auto lastY = rect.y + rect.height;

            for(int y = rect.y; y < lastY; ++y) {
                for(int x = rect.x; x < lastX; ++x) {

                    // Safety check. Comment out when not debugging
                    // LEVIATHAN_ASSERT(y >= 0 && y < height, "View OnPaint y out of range");
                    // LEVIATHAN_ASSERT(x >= 0 && x < width, "View OnPaint x out of range");

                    destptr[(rowElements * y) + x] = source[(y * width) + x];
                }
            }
        }

        // std::memset(destptr, 255, pixelBuffer->getSizeInBytes());
        // Unlock the buffer //
        pixelBuffer->unlock();
    }

    // // Save render result
    // Ogre::Image img;
    // Texture->convertToImage(img);
    // static std::atomic<int> spamnumber = 0;
    // img.save("Test" + std::to_string(++spamnumber) + ".png");
}
hhyyrylainen
Techie
 
Posts: 14
Joined: Tue Apr 10, 2018 3:08 am

Return to Support Forum

Who is online

Users browsing this forum: Google [Bot] and 28 guests