{Multi-Threaded Mesh Skinning Showing Promise}

From: http://www.garagegames.com/community/blogs/view/14899

多线程网格皮肤化显示约定

网格皮肤化, 是对象渲染过程中的一部分, 这一过程由 TSSkinMesh::render() 完成。TSSkinMesh::render() 会调用 UpdateSkin() , 然后再调用 Parent::render() 。Parent::render() 会创建一个渲染实例。然而, 顶点缓存(vertex buffer) 被创建后, 并不会被立即使用。据与此, 使用一个"Promise" 来表示一个尚未准备好但最终会准备好的东西的想法诞生了。与许多网络案例相似, 网格的肤化也是如此。

 

#ifndef _PROMISE_H_
#define _PROMISE_H_

// This is a rough draft
template <typename T>
class Promise {
protected:
    // Return the promised data. Undefined results if isReady() is false.
    virtual T* get() = 0;

public:
    virtual ~Promise() { }

    // Returns true if the promised data is ready.
    vritual bool isReady() const = 0;

    // Blocks until the promised data is ready, and returns it.
    virtual T* resolve() {
        while(!isReady()) {
            return get();
        }
    }
};

#endif

 

然后, 在渲染实例对象中存储一个 Promise* 指针 而不在是一个顶点缓存(vertex buffer) 指针。在向设备发送绘制数据之前, 调用某个 promise 实例的 resolve() 方法, 可达到在未准备好之前的等待操作。

#ifndef _SIMPLE_PROMISE_H
#define _SIMPLE_PROMISE_H

template <typename T>
class SimplePromise : public Promise<T> {
    protected:
        T *mPtr;
        virtual T *get() { return mPtr; }
    
    public:
        SimplePromise(T *ptr) : mPtr = ptr {  }
        virtual bool isReady() const { return true; }
        virtual boid set(T *ptr) { mPtr = ptr; }
};

#endif

 

于是, 可以创建 ThreadedPromise 类来表示使用一个线程来完成某个约定(promise)。然后, 在创建一个 PromisedFulfilerThread 类, 该类可以操作一个ThreadedPromise 类实例的集合。由于加锁、释放锁也是需要时间的,不适合对一个集合进行简单操作, 也就是说, 将锁置于 PromisedFulfilerThread 类中是不合适。通过重新对问题进行考虑, 将互斥锁(mutex)置于 PromisedPromise 类中更为合适。通过测试发现, 主线程(Thread main) 会对渲染实例进行批处理操作, 开始绘制, 当进入到一个尚未准备就绪的 Promise 中时,停下来空转。如果主线程可以在需要时选取若干 promise 实例, 然后完成它,还是可以提升渲染性能的。

TSSkinBatcher -- Threaded Skin Promise Metrics  
   - Promises batched to threads: 134050  
   - Fulfilled before resolve: 91382  
   - Promises blocked on resolve: 42668 [31.83%]  
      + Worker thread processed 15065 [35.31%]  
      + Main thread processed 27603 [64.69%] 

可以发现,134k 次皮肤请求中,91k 次在主线程请求之前在Worker线程种得到处理;42k次的 promise 阻塞了主线程。在这42k次请求中, 在主线程准备访问它们之前, 15k个 promise在Worker线程种得到处理...

#ifndef _THREADEDPROMISE_H
#define _THREADEDPROMISE_H

template<typename T>
class ThreadedPromise : public Promise<T> {

    public:

    virtual T* resolve() {
        PROFILE_SCOPE(ThreadedPromise_Resolve);
        #ifdef ENABLE_THREADED_PROMISE_METRICS
        if(_isReady()) {
            Atomic::Value32::Increment(&smNoBlockResolves);
            return get();
        }
        #else
        if(_isReady()) {
            returng get();
        }
        #endif

        // Interlock op, take control of promise
        if(mInterlockState == ilsPromiseNoState &&
           (Atomic::Value32::Increment(&mInterlockState) == ilsPromiseAcquired)) {
               #ifdef ENABLE_THREADED_PROMISE_METRICS
               Atomic::Value32::Increment(&smMainThreadResolveBlocks);
               #endif
               return set(reinterpret_cast<T*>(mFulfilerFunction(mFunctionData)));
        }
        while(!_isReady()) {
            Platform::sleep(0);
        }

        #ifdef ENABLE_THREADED_PROMISE_METRICS
        Atomic::Value32::Increment(&smWorkerThreadResolveBlocks);
        #endif
        return get();
    }
// ...

 

posted @ 2015-04-15 18:15  long#long  阅读(145)  评论(0编辑  收藏  举报