Qt MinGW QThread performance bad

Qt MinGW QThread performance bad

本文关键字:bad performance QThread MinGW Qt      更新时间:2023-10-16

我们目前正在用OpenGL制作一个简单的3D引擎,几乎所有的事情都为我们的最终大学演讲做好了准备。我通常使用MSVC2015 x64编译器工作,一切都很好,构建速度很快,可执行性能也很好。然而,自从我们做了最新的改变,物理线程在MinGW 4.9.2 x86上非常慢,一些变量像delta奇怪的是0,即使线程是工作的。

当我切换回MSVC,它就像一个魅力它很难描述,所以我道歉。

为了更好地理解,这里有一个GIF: https://i.stack.imgur.com/ten1E.jpg

正如你所看到的,球体的运动非常不稳定。在MSVC上,它们非常平滑地移动,delta通常为0.007831毫秒。在MinGW上是0毫秒,有时,只是有时它非常高,大约5毫秒。我们完全不知道它会导致什么。我怀疑编译器优化了什么?我不知道……

void PhysicsThread::run(){
    qDebug() << "SUCCESSFULLY STARTED UP PHYSICS-SIMULATION";
    forever{
        mutex.lock();
        qDebug() << "RUNNING PHYSICS-SIMULATION";
        runSimulation();
        if(stop){
            mutex.unlock();
            break;
        }
        if(bPause){
            pauseManager.wait(&mutex);
        }
        mutex.unlock();
    }
}
void PhysicsThread::runSimulation(){
    auto startTime = std::chrono::high_resolution_clock::now();
    // Collision Border
    for(int i = 0 ; i < pobjectsSphere.size() ; i++) {
        PhysicsSphere* op = pobjectsSphere.at(i);
        if(op->getIsMovable()){
            if(op->getX()-(op->getSize()) < minx ){
                if(op->getVelocityX() < 0){
                    op->setVelocityX(-op->getVelocityX());
                }else{
                    op->setVelocityX(op->getVelocityX());
                }
            }else if(op->getX()+(op->getSize()) > maxx) {
                if(op->getVelocityX() > 0){
                    op->setVelocityX(-op->getVelocityX());
                }else{
                    op->setVelocityX(op->getVelocityX());
                }
            }
            if(op->getY()-(op->getSize()) < miny){
                if(op->getVelocityY() < 0){
                    op->setVelocityY(-op->getVelocityY() * op->getRemainingEnergy());
                }else{
                    op->setVelocityY(op->getVelocityY());
                }
            }else{
                if(op->getY()+(op->getSize()) > maxy){
                    if(op->getVelocityY() > 0){
                        op->setVelocityY(-op->getVelocityY());
                    }else{
                        op->setVelocityY(op->getVelocityY());
                    }
                }
                // Gravity
                op->setVelocityY(op->getVelocityY() + g*deltaTimeMS*op->getMass());
            }
            if(op->getZ()-(op->getSize()) < minz){
                if(op->getVelocityZ() < 0){
                    op->setVelocityZ(-op->getVelocityZ());
                }else{
                    op->setVelocityZ(op->getVelocityZ());
                }
            }else if(op->getZ()+(op->getSize()) > maxz){
                if(op->getVelocityZ() > 0){
                    op->setVelocityZ(-op->getVelocityZ());
                }else{
                    op->setVelocityZ(op->getVelocityZ());
                }
            }
        }
    }
    // Collision Sphere on Sphere
    for(int i = 0 ; i < pobjectsSphere.size() ; i++) {
        PhysicsSphere* op1 = pobjectsSphere.at(i);
        for(int j = i ; j < pobjectsSphere.size() ; j++) {
            PhysicsSphere* op2 = pobjectsSphere.at(j);
            // Sphere on Sphere
            if(i != j && Collision::SphereVersusSphere(op1->getX() ,op1->getY() ,op1->getZ() ,op1->getSize() ,op2->getX() ,op2->getY() ,op2->getZ() ,op2->getSize())){
                double tempX (op1->getX() - op2->getX());
                double tempY (op1->getY() - op2->getY());
                double tempZ (op1->getZ() - op2->getZ());
                double norm = sqrt(tempX*tempX + tempY*tempY + tempZ*tempZ);
                tempX = tempX / norm;
                tempY = tempY / norm;
                tempZ = tempZ / norm;
                double a1 = (op1->getVelocityX() * tempX) + (op1->getVelocityY() * tempY) + (op1->getVelocityZ() * tempZ);
                double a2 = (op2->getVelocityX() * tempX) + (op2->getVelocityY() * tempY) + (op2->getVelocityZ() * tempZ);
                double optimizedP = (2.0 * (a1 - a2)) / (op1->getMass() + op2->getMass());
                // fix
                optimizedP = std::abs(optimizedP);
                // 0.9 Verlusst
                if(op1->getIsMovable()){
                    op1->setVelocityX( op1->getVelocityX() + (optimizedP * op2->getMass() * tempX) * (op1->getRemainingEnergy()*op2->getRemainingEnergy()));
                    op1->setVelocityY( op1->getVelocityY() + (optimizedP * op2->getMass() * tempY) * (op1->getRemainingEnergy()*op2->getRemainingEnergy()));
                    op1->setVelocityZ( op1->getVelocityZ() + (optimizedP * op2->getMass() * tempZ) * (op1->getRemainingEnergy()*op2->getRemainingEnergy()));
                }
                if(op2->getIsMovable()){
                    op2->setVelocityX( op2->getVelocityX() - (optimizedP * op1->getMass() * tempX) * (op1->getRemainingEnergy()*op2->getRemainingEnergy()));
                    op2->setVelocityY( op2->getVelocityY() - (optimizedP * op1->getMass() * tempY) * (op1->getRemainingEnergy()*op2->getRemainingEnergy()));
                    op2->setVelocityZ( op2->getVelocityZ() - (optimizedP * op1->getMass() * tempZ) * (op1->getRemainingEnergy()*op2->getRemainingEnergy()));
                }
                if(!op1->getIsMovable() && op2->getIsMovable()){
                    op2->setX(op2->getX() - op1->getVelocityX() * deltaTimeMS);
                    op2->setY(op2->getY() - op1->getVelocityY() * deltaTimeMS);
                    op2->setZ(op2->getZ() - op1->getVelocityZ() * deltaTimeMS);
                    op1->setVelocityX(0.0);
                    op1->setVelocityY(0.0);
                    op1->setVelocityZ(0.0);
                }else if(op1->getIsMovable() && !op2->getIsMovable()){
                    op1->setX(op1->getX() - op2->getVelocityX() * deltaTimeMS);
                    op1->setY(op1->getY() - op2->getVelocityY() * deltaTimeMS);
                    op1->setZ(op1->getZ() - op2->getVelocityZ() * deltaTimeMS);
                    op2->setVelocityX(0.0);
                    op2->setVelocityY(0.0);
                    op2->setVelocityZ(0.0);
                }

                op1->setX(op1->getX() + op1->getVelocityX() * deltaTimeMS);
                op1->setY(op1->getY() + op1->getVelocityY() * deltaTimeMS);
                op1->setZ(op1->getZ() + op1->getVelocityZ() * deltaTimeMS);
                op2->setX(op2->getX() + op2->getVelocityX() * deltaTimeMS);
                op2->setY(op2->getY() + op2->getVelocityY() * deltaTimeMS);
                op2->setZ(op2->getZ() + op2->getVelocityZ() * deltaTimeMS);
            }
        }
    }
    for(int i = 0 ; i < pobjectsSphere.size() ; i++) {
        PhysicsSphere* op1 = pobjectsSphere.at(i);
        for(int j = 0 ; j < pobjectsBox.size() ; j++) {
            PhysicsBox* op2 = pobjectsBox.at(j);

            if(Collision::SphereVersusBox( op1->getX() ,op1->getY() ,op1->getZ() ,op1->getSize() ,op2->getMinX()+op2->getX() ,op2->getMinY()+op2->getY() ,op2->getMinZ()+op2->getZ() ,op2->getMaxX()+op2->getX() ,op2->getMaxY()+op2->getY() ,op2->getMaxZ()+op2->getZ())){
                if((op1->getX()+op1->getSize()) > op2->getMinX() && op1->getX() < op2->getMinX()+op2->getX()){
                    if(op1->getVelocityX() > 0){
                        op1->setVelocityX(-op1->getVelocityX());
                    }
                }
                if((op1->getX()-op1->getSize()) < op2->getMaxX() && op1->getX() > op2->getMaxX()+op2->getX()){
                    if(op1->getVelocityX() < 0){
                        op1->setVelocityX(-op1->getVelocityX());
                    }
                }
                if((op1->getY()+op1->getSize()) > op2->getMinY() && op1->getY() < op2->getMinY()+op2->getY()){
                    if(op1->getVelocityY() > 0){
                        op1->setVelocityY(-op1->getVelocityY());
                    }
                }
                if((op1->getY()-op1->getSize()) < op2->getMaxY() && op1->getY() > op2->getMaxY()+op2->getY()){
                    if(op1->getVelocityY() < 0){
                        op1->setVelocityY(-op1->getVelocityY());
                    }
                }
                if((op1->getZ()+op1->getSize()) > op2->getMinZ() && op1->getZ() < op2->getMinZ()+op2->getZ()){
                    if(op1->getVelocityZ() > 0){
                        op1->setVelocityZ(-op1->getVelocityZ());
                    }
                }
                if((op1->getZ()-op1->getSize()) < op2->getMaxZ() && op1->getZ() > op2->getMaxZ()+op2->getZ()){
                    if(op1->getVelocityZ() < 0){
                        op1->setVelocityZ(-op1->getVelocityZ());
                    }
                }
            }
        }
    }
    // Move
    for(int i = 0 ; i < pobjectsSphere.size() ; i++) {
        PhysicsSphere* op = pobjectsSphere.at(i);
        if(op->getIsMovable()){
            op->setX(op->getX() + op->getVelocityX()*deltaTimeMS);
            op->setY(op->getY() + op->getVelocityY()*deltaTimeMS);
            op->setZ(op->getZ() + op->getVelocityZ()*deltaTimeMS);
        }else{
            op->setVelocityX(0.0);
            op->setVelocityY(0.0);
            op->setVelocityZ(0.0);
        }
    }
    if(pauseTickTime > 0.0){
        this->msleep(pauseTickTime);
    }
    auto endTime = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double> time = endTime - startTime;
    deltaTimeNS = std::chrono::duration_cast<std::chrono::nanoseconds>(time).count();
    deltaTimeMS = deltaTimeNS / 1000000.0;
    //qDebug() << "DeltaT NS: " << deltaTimeNS << " DeltaT MS: " << deltaTimeMS;
}

QThread和mingw都没有问题,你误诊了。记住,QThread是本机线程的一个非常简单的句柄。这和你所看到的没有任何关系。

你的时间步进逻辑根本就有缺陷。你假设startTimeendTime是不同的。它们不必这样做——您只需为自己创建一个测试用例来演示这一点。你所使用的时钟的API中没有任何东西可以保证当你调用它两次时你会得到不同的结果。

你的物理引擎应该以恒定的时间步长运行,并在每个时间步长上添加一个内部时间。启动模拟时,将引擎时间设置为系统时间。然后继续计算引擎中的步骤,直到它落后于实际时间。一旦赶上,执行显示更新。和重复。