0

我正在尝试使用 Google Native Client 实现渲染循环,我知道您不能在除主线程之外的任何线程上进行 Pepper API 调用,因此我正在尝试实现以下内容。Module() -> 使用 DoGL_() 创建新线程 -> DoGL() 在主线程上调用带有 Pepper API 调用的函数 -> DoGL_() 仍然在单独的线程上调用 DoGL()。

我正在尝试仅使用 Pepper 19 来执行此操作,而且我对线程的了解还不够多,无法解决此问题。现在模块只是崩溃了。

这是我的代码(不漂亮,我只是想摆脱杂务代码):

DoGL.h

#include "Include.h"



class Context : public pp::Graphics3DClient
{
    pp::Size size;
    bool init_;
    const struct PPB_OpenGLES2 *gles2Interface;
    public: 
        Context( pp::Instance *instance );
        ~Context();
        virtual void Graphics3DContextLost() {
        }
        bool MakeCurrentContext( pp::Instance *instance );
        void FlushContext();
        pp::Graphics3D context;
        void ( *callback ) ( void*, int32_t );
        pp::Instance *ppinstance;
        PPB_Graphics3D* ppb_g3d_interface;
        GLuint programObject;
        GLuint LoadShader( const char *shaderSrc, GLenum type );
        GLuint Init();
        void Draw();
        void DoGL();
        void GLDebug( std::string msg = "" );
        static void FillIn( void* v, int32_t i ) {
        }
        pp::Core *ppb_core_interface;
};

static Context *cjcontext;
void* DoGL_( void* p ) {
    cjcontext->DoGL();
}
void Init_( void *p, int32_t i ) {
    cjcontext->Init();
}
void Draw_( void *p, int32_t i ) {
    cjcontext->Draw();
}
void MakeContext_( void *p, int32_t i ) {
    cjcontext->ppinstance->PostMessage( "Called on the main thread!!!!\n" );
    cjcontext->MakeCurrentContext( cjcontext->ppinstance );
}
void FlushContext_( void *p, int32_t i ) {
    cjcontext->FlushContext();
}

DoGL.cpp

#include "DoGL.h"
Context::Context( pp::Instance *instance ) : pp::Graphics3DClient( instance )
{
    pp::Module *module = pp::Module::Get();
    gles2Interface = static_cast< const struct PPB_OpenGLES2 * > ( module->GetBrowserInterface( PPB_OPENGLES2_INTERFACE ) );
    init_ = false;
}
Context::~Context() {
    glSetCurrentContextPPAPI( 0 );
}
bool Context::MakeCurrentContext( pp::Instance *instance )
{
    //Is somthing broken?//
    if( instance == NULL ) {
        glSetCurrentContextPPAPI( 0 );
        return ( false );
    }
    if( context.is_null() == true )
    {
        //OpenGL attributes.//
        int32_t attribs[] = 
        { 
            PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8,
            PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 24,
            PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 8,
            PP_GRAPHICS3DATTRIB_SAMPLES, 0,
            PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0,
            PP_GRAPHICS3DATTRIB_WIDTH, 500,
            PP_GRAPHICS3DATTRIB_HEIGHT, 500,
            PP_GRAPHICS3DATTRIB_NONE /*Terminate list.*/
         };
        context = pp::Graphics3D( instance, pp::Graphics3D(), attribs );
        if ( context.is_null() == true ) {
            glSetCurrentContextPPAPI( 0 );
            return ( false );
        }
        instance->BindGraphics( context );
    }
    //Get the context.//
    glSetCurrentContextPPAPI( context.pp_resource() );
    glViewport( 0, 0, 500, 500 );
    glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
    return true;
}
void Context::FlushContext()
{
    //Make sure that the flush is not pending.//
    for( unsigned int wait = 0; wait < 1001; ++wait );
    context.SwapBuffers( pp::CompletionCallback( FillIn, ( ( void* ) this ) ) );
}

GLuint Context::LoadShader( const char *shaderSrc, GLenum type )
{
    GLuint shader;
    GLint compiled;
    //Create the shader object.//
    shader = glCreateShader( type );
    if( shader == 0 ) {
        return 0;
    }
    //Load the shader source.//
    glShaderSource( shader, 1, &shaderSrc, NULL );
    //Compile the shader.//
    glCompileShader( shader );
    //Check the compile status.//
    glGetShaderiv( shader, GL_COMPILE_STATUS, &compiled );
    return shader;
}

GLuint Context::Init()
{
    const char* vShaderStr =  
        "#version 100                \n"
        "attribute vec4 vPosition;   \n"
        "void main()                 \n"
        "{                           \n"
        "   gl_Position = vPosition; \n"
        "}                           \n";
    const char* fShaderStr =  
        "#version 100                               \n"
        "precision mediump float;                   \n"
        "void main()                                \n"
        "{                                          \n"
        "  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); \n"
        "}                                          \n";
    GLuint vertexShader;
    GLuint fragmentShader;
    GLint linked;
    //Load the vertex/fragment shaders.//
    vertexShader = LoadShader( vShaderStr, GL_VERTEX_SHADER );
    fragmentShader = LoadShader( fShaderStr, GL_FRAGMENT_SHADER );
    //Create the program object.//
    programObject = glCreateProgram();
    if( programObject == 0 ) {
        return 0;
    }
    glAttachShader( programObject, vertexShader );
    glAttachShader( programObject, fragmentShader );
    //Bind vPosition to attribute 0.//
    glBindAttribLocation( programObject, 0, "vPosition" );
    //Link the program.//
    glLinkProgram( programObject );
    //Check the link status.//
    glGetProgramiv( programObject, GL_LINK_STATUS, &linked );
    glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
    return programObject;
}


void Context::Draw()
{
    ppinstance->PostMessage( "Drawing!" );
    GLfloat scaler = 1.f;
    GLfloat vVertices[] = 
    { 
        0.0f,  ( scaler * 0.5f ), 0.0f, 
        ( scaler * -0.5f ), ( scaler * -0.5f ), 0.0f,
        ( scaler * 0.5f ), ( scaler * -0.5f ),  0.0f
     };
    ++scaler;
    ppinstance->PostMessage( "Scaler" );
    ppinstance->PostMessage( scaler );
    //Set the viewport.
    glViewport( 0, 0, 500, 500 );
    //Clear the color buffer.//
    glClear( GL_COLOR_BUFFER_BIT );
    //Use the program object.//
    glUseProgram( programObject );
    //Load the vertex data.//
    glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, vVertices );
    glEnableVertexAttribArray( 0 );
    glDrawArrays( GL_TRIANGLES, 0, 3 );
}

void Context::DoGL()
{
    if( init_ == false )
    {
        pp::CompletionCallback cc;
        //ppinstance->PostMessage( "Init is false." );
        cjcontext->MakeCurrentContext( ppinstance );
        for( int i = 0; i < 10001; ++i );
        cc = pp::CompletionCallback( &Init_, 0, 0 );
        ppb_core_interface->CallOnMainThread( 0, cc, 0 );
        init_ = true;
        cjcontext->FlushContext();
    }
    pp::CompletionCallback cc;
    for( int i = 0; i < 101; ++i );
    cc = pp::CompletionCallback( &MakeContext_, 0, 0 );
    ppb_core_interface->CallOnMainThread( 0, cc, 0 );
    for( int i = 0; i < 101; ++i );
    cc = pp::CompletionCallback( &Draw_, 0, 0 );
    ppb_core_interface->CallOnMainThread( 0, cc, 0 );
    for( int i = 0; i < 101; ++i );
    cc = pp::CompletionCallback( &FlushContext_, 0, 0 );
    ppb_core_interface->CallOnMainThread( 0, cc, 0 );
    void *p;
    DoGL_( p );
}

pthread_t reanderHandle;
int threadStatus;

//Standard NaCl chore code.//
class CubeJumpInstance : public pp::Instance
{
    public: 
        explicit CubeJumpInstance( PP_Instance instance ) : pp::Instance( instance ) {
            PostMessage( "Instance create.\n" );
        }
        virtual ~CubeJumpInstance() {
            PostMessage( "Instance destroyed.\n" );
        }
};

class CubeJumpModule : public pp::Module
{
    public: 
        CubeJumpModule() : pp::Module() {
        }
        virtual ~CubeJumpModule() {
            glTerminatePPAPI();
        }
        virtual pp::Instance* CreateInstance( PP_Instance instance )
        {
            glInitializePPAPI( get_browser_interface() );
            pp::Instance *instance_ = new CubeJumpInstance( instance );
            cjcontext = new Context( instance_ );
            cjcontext->ppinstance = instance_;
            cjcontext->ppb_core_interface = this->core();
            threadStatus = pthread_create( &reanderHandle, 0, DoGL_, 0 );
            cjcontext->ppinstance->PostMessage( "Instace done.\n" );
            //pthread_join( reanderHandle, 0 );
            return cjcontext->ppinstance;
        }
};

namespace pp
{
    pp::Module* CreateModule() {
        return new CubeJumpModule();
    }
}
4

1 回答 1

0

这里有很多问题,我将专注于主要概念:您不需要渲染线程,您可以只使用交换缓冲区来驱动渲染循环。

基本概念是:

// do this to kick things off
CallOnMainThread(Render)

Render()
    if (!init)
        Init();

    MakeContext();
    Draw();
    SwapBuffers(Render);

而已。SwapBuffers将安排下一次调用在“正确”时间进行渲染。

至于你的程序为什么会崩溃,可能是很多事情,我猜你的主要问题是递归调用DoGL,直到你的堆栈爆炸。

于 2013-02-13T21:07:43.350 回答