OpenGL - Создание VBO на поток в Ubuntu? - PullRequest
0 голосов
/ 08 мая 2018

У меня есть приложение, в котором у меня есть данные удаленной сетки на сервере. Некоторые из этих сеток имеют вершины по 400 Кбайт и поэтому требуют многопоточности в процессе загрузки. У меня нет проблем, когда все выполняется в одном потоке, и весь код работает нормально, за исключением случаев, когда я загружаю загруженные буферы в землю openGL в многопоточной версии. В конечном итоге я получаю сбой при попытке создать VBO с помощью вызовов OpenGL. Приложение обычно segfaults на glGenBuffers. Некоторые примеры, которые я читал, когда пытался сделать вызовы OpenGL поточно-ориентированными, касались определенных окон apis и платформо-зависимых вещей, которые не сильно помогают в среде x11 ubuntu.

Так что я надеюсь, что кто-то, кто делал это раньше, может указать мне на несколько звонков, чтобы сделать это жизнеспособным, прежде чем перестроить рабочую часть.

Мой код загрузки очень прост и легок, а загрузка vbo - это типичные шаги вызовов glGenBuffer, glBind, glBufferData:

///
/// \brief The LoadMeshThread class
///     Thread to load a mesh (geometry data) from database
///
class LoadMeshThread : public vtrus::core::Thread
{
    CLASSEXTENDS(LoadMeshThread, vtrus::core::Thread)
    ADD_TO_CLASS_MAP
public:
    VTRUS_HOST
    LoadMeshThread( Chunk* chunk, uint32_t mapID, ChunkGrid* chunkVolume ) :
      super(),
      ChunkToLoadMesh(chunk),
      CpuVertices(NULL),
      CpuNormals(NULL),
      VertexCount(0),
      ChunkVolume(chunkVolume)
    {
        printf("Loading [%s]\n", chunk->GridLocation.ToString().str());
        MapID = mapID;

        ChunkToLoadMesh->AddRef();
        ChunkGrid::LiveLoadThreads++;
    }

    ///
    /// \brief ~LoadHashThread
    /// Destroyed after pthread has ended
    virtual ~LoadMeshThread()
    {
        vprintf(vtrus::debug::Threading, "[%d]\n", this->ThreadID);
        ChunkToLoadMesh->Release();
        ChunkGrid::LiveLoadThreads--;
        delete [] CpuVertices;
        delete [] CpuNormals;
    }

    ///
    /// \brief Run
    ///  Called by base class when the pthread is created
    virtual void Run();

    ///
    /// \brief ReadFromDataBase
    ///
    void ReadFromDataBase();

private:
    ChunkGrid* ChunkVolume; //Access to world data
    uint32_t MapID;
    vtrus::slam::Chunk* ChunkToLoadMesh;
    GLfloat* CpuVertices;
    GLfloat* CpuNormals;
    int VertexCount;
};

///
/// \brief LoadMeshThread::ReadFromDataBase
/// Calls into mysql and grabs the blobs containing the data
void LoadMeshThread::ReadFromDataBase()
{
    Eigen::Vector3i chunkR3 = ChunkToLoadMesh->GridLocation.ToEigen();
    uint32_t chunkID = R3ToChunkID( chunkR3 );
    vtrus::database::DataBase* vtrusDB = vtrus::database::DataBase::GetInstance();

    {
        vtrusDB->Driver->threadInit();
        {
            try
            {
                vtrus::core::String connectionString = vtrusDB->GetConnectionString();
                sql::Connection* connection = vtrusDB->Driver->connect(connectionString.str(), "gobble", "gobblegobble" );
                connection->setSchema( "gobble" );

                sql::ResultSet* result = vtrusDB->GetMeshData( connection, chunkID, MapID, 1 );

                if( result != NULL && result->next() )
                {
                    std::istream* verticesBlob = result->getBlob("VertexBuffer");
                    std::istream* normalsBlob = result->getBlob("NormalsBuffer");
                    VertexCount = result->getInt("VertexCount");

                    uint bufferSize = VertexCount*sizeof(vtrus::geometry::Vec3f);
                    CpuVertices = new GLfloat[bufferSize];
                    CpuNormals = new GLfloat[bufferSize];
                    //printf("Loading %d entries \n", entryCount );
                    verticesBlob->read( reinterpret_cast<char*>(&CpuVertices[0]), (std::streamsize)bufferSize );
                    normalsBlob->read( reinterpret_cast<char*>(&CpuNormals[0]), (std::streamsize)bufferSize );

                    delete verticesBlob;
                    delete normalsBlob;
                }

                delete result;
                delete connection;
            }
            catch ( sql::SQLException * exception )
            {
                //do nothing
                printf("WARNING: SqlException on Loading\n");
            }
        }
        vtrusDB->Driver->threadEnd();
    }
}

void LoadMeshThread::Run()
{
    vtrus::core::ScopedTimer timer("**** LoadHashThread::Run ****");

    vprintf(vtrus::debug::Threading, "[%d]\n", this->ThreadID);
    int numAttempts = 0;
    const int maxAttenpts = 10;
    uint countRemaining = 0;
    uint maxCount = 0;

    ReadFromDataBase();

    if( VertexCount > 0 )
    {
        printf("Creating [%d] vertices\n", VertexCount);
        //CRASH here when the mesh constructor calls glGenBuffer          
        vtrus::resources::Mesh* newMesh = new vtrus::resources::Mesh(VertexCount);
        //upload cpu vertices / normals to GPU

        glBindBuffer( GL_ARRAY_BUFFER, newMesh->GetVertexBuffer()->bo );
        glBufferData(GL_ARRAY_BUFFER, VertexCount * sizeof(vtrus::geometry::Vec3f), &CpuVertices[0], GL_STATIC_DRAW);

        glBindBuffer( GL_ARRAY_BUFFER, newMesh->GetNormalsBuffer()->bo);
        glBufferData(GL_ARRAY_BUFFER, VertexCount * sizeof(vtrus::geometry::Vec3f), &CpuNormals[0], GL_STATIC_DRAW);

        glBindBuffer( GL_ARRAY_BUFFER, 0 );

        ChunkVolume->AddMesh(newMesh, ChunkToLoadMesh);
        newMesh->Release();

        ChunkToLoadMesh->IsLoaded = true;
        ChunkToLoadMesh->IsSaved = true;
        ChunkToLoadMesh->SavedBlockCount = maxCount;
    }

    //Access mutex
    ChunkToLoadMesh->IsLoading = false;
}

1 Ответ

0 голосов
/ 08 мая 2018

Прежде чем можно будет использовать любую команду glXXX, gl-context должен быть установлен как текущий для потока, который будет использовать эти команды.

В мире X11 используется команда glXMakeContextCurrent или старше, но все еще действительная glXMakeCurrent. См. glX doc . Если вы используете какую-то библиотеку, которая обрабатывает gl-context для вас, ищите в ее документации.

Вы можете загрузить данные в gl-контексте и отобразить их в другом gl-контексте. Для этого оба контекста должны быть «общими», что вы обычно делаете в их конструкторах.
Но если ваша видеокарта не способна считывать при рендеринге , большого улучшения производительности не произойдет.

...