0

I have a scene with tons of similar objects moved by physx, and i want to draw all of this using opengl instansing. So, i need to form a array with transform data of each object and pass it in to opengl shader. And, currently, filling an array is bottleneck of my app, because physx simulation using 16 thread, but creating array use just one thread.

So, i created data_transfer_task class, which contain two indexes, start and stop and move transform data of physx objects between this indexes to array.

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(); }

I created another class start_transfer_task, which creates and sheduled tasks according to thread count.

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(); }

I create start_transfer_task instance before call simulate, pass start_transfer_task to simulate, and i expect that start_transfer_task should run after all physx task done its own job, so write and read api calls dont owerlap, and calling fetchResults(block=true) continue execution only where all of my tasks finish copy transform data.

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

But i got many warnings about read and write api call owerlapping like this.

\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.

And, sometimes after start my app, i got a strange assert message.

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

So, what i doing wrong ?

1 Answers1

0

The concurrent API call warning is essentially telling you that you are calling for multiple thread PhysX API functions that are supposed to be single threaded.

Using the PhysX API you have to be very careful because it is not thread safe, and the thread safeness is left to the user.

Read this for more information.

Marc Cayuela
  • 1,504
  • 13
  • 26
  • I readed all of this stuff before writing the code. to be more precise, chapter "Data Access from Multiple Threads" and "Locking Semantics" says that READ API calls may be made simultaneously from multiple threads. And my code used only READ API calls. Also physx api reference says that you can pass completion task to simulate function and this task will be run after all simulation tasks finished, so overlapping write and read calls sould not exist. – Yasha Akimov Dec 03 '22 at 05:33