1

我有一个场景,其中包含大量由 physx 移动的类似对象,我想使用 opengl 实例化来绘制所有这些。所以,我需要用每个对象的变换数据形成一个数组,并将其传递给 opengl 着色器。而且,目前,填充数组是我的应用程序的瓶颈,因为 physx 模拟使用 16 个线程,但创建数组只使用一个线程。

因此,我创建了 data_transfer_task 类,其中包含两个索引,启动和停止,并将此索引之间的 physx 对象的转换数据移动到数组。

class data_transfer_task : public physx::PxTask {
public:
    int start;
    int stop;
    start_transfer_task* base_task;
    data_transfer_task(int start, int stop, start_transfer_task* task, physx::PxTaskManager *mtm) :physx::PxTask() {
        this->start = start;
        this->stop = stop;
        this->mTm = mtm;
        base_task = task;
    }

    void update_transforms();

    virtual const char* getName() const { return "data_transfer_task"; }
    virtual void run();
};

void data_transfer_task::update_transforms() {
    for (int i = start; i < stop; i++) {
        auto obj = base_task->objects->at(i);
        auto transform = obj->getGlobalPose();
        DrawableObject* dr = (DrawableObject*)obj->userData;
        auto pos = transform.p;
        auto rot = transform.q;

        dr->set_position(glm::vec3(pos.x, pos.y, pos.z));
        dr->set_rotation(glm::quat(rot.w, rot.x, rot.y, rot.z));
    }
}

void data_transfer_task::run() { update_transforms(); }

我创建了另一个类 start_transfer_task,它根据线程数创建和调度任务。

class start_transfer_task : public physx::PxLightCpuTask{
public:
    start_transfer_task(physx::PxCpuDispatcher* disp, std::vector<physx::PxRigidDynamic*>* obj, physx::PxTaskManager* mtm) :physx::PxLightCpuTask() {
        this->mTm = mtm;
        this->dispatcher = disp;
        this->objects = obj;
    }
    physx::PxCpuDispatcher* dispatcher;
    std::vector<physx::PxRigidDynamic*>* objects;
    void start();
    virtual const char* getName() const { return "start_transfer_task"; }
    virtual void run();
};
void start_transfer_task::start() {
    int thread_count = dispatcher->getWorkerCount();
    int obj_count = objects->size();
    int batch_size = obj_count / thread_count;
    int first_size = batch_size + obj_count % thread_count;

    auto task = new data_transfer_task(0, first_size, this, this->mTm);
    this->mTm->submitUnnamedTask(*task, physx::PxTaskType::TT_CPU);
    task->removeReference();
    if (batch_size > 0) {
        for (int i = 1; i < thread_count; i++) {
            task = new data_transfer_task(first_size + batch_size * (i - 1), first_size + batch_size * i, this, this->mTm);
            this->mTm->submitUnnamedTask(*task, physx::PxTaskType::TT_CPU);
            task->removeReference();
        }
    }
}
void data_transfer_task::run() { update_transforms(); }

我在调用模拟之前创建 start_transfer_task 实例,将 start_transfer_task 传递给模拟,并且我希望 start_transfer_task 应该在所有 physx 任务完成自己的工作之后运行,所以写入和读取 api 调用不要重叠,并且调用 fetchResults(block=true) 仅在哪里继续执行我的所有任务都完成了复制转换数据。

while (is_simulate) {
    auto transfer_task = new start_transfer_task(gScene->getCpuDispatcher(), &objects, gScene->getTaskManager());
    gScene->simulate(1.0f / 60.0f, transfer_task);
    gScene->fetchResults(true);
    //some other logic to call graphics api and sleep to sustain 30 updates per second

但是我收到了很多关于读写 api 调用重叠的警告。

\physx\source\physx\src\NpWriteCheck.cpp (53) : invalid operation : Concurrent API write call or overlapping API read and write call detected during physx::NpScene::simulateOrCollide from thread 8492! Note that write operations to the SDK must be sequential, i.e., no overlap with other write or read calls, else the resulting behavior is undefined. Also note that API writes during a callback function are not permitted.

而且,有时在启动我的应用程序后,我会收到一条奇怪的断言消息。

physx\source\task\src\TaskManager.cpp(195) : Assertion failed: !mPendingTasks"

那么,我做错了什么?

4

0 回答 0