언어 설정

Menu
Sites
Language
Multi-thread OpenGL

Hi  all, I followed the Tizen sdk 2.3 help contents https://developer.tizen.org/dev-guide/2.3.0/org.tizen.mobile.native.appprogramming/html/tutorials/ui_tutorial/multithread_opengl_tutorial.htm to write a application which use multi thread for rendering.

It can compile ,but when run it to "the glBindTexture(GL_TEXTURE_2D, tex)" the emulator disappear. And I run it in real phone , it also just show backgroud.

Anyone who can help me ? Thank you.

The codes are:

#include <app.h>
#include <Elementary.h>
#include <Elementary_GL_Helpers.h>
#include <efl_extension.h>
#include <tizen.h>

#include <math.h>
#include <sys/time.h>
#include <tizen_type.h>
#include <dlog.h>

#ifdef  LOG_TAG
#undef  LOG_TAG
#endif
#define LOG_TAG "glview"

ELEMENTARY_GLVIEW_GLOBAL_DEFINE();

//EVAS_GL_GLOBAL_GLES2_DEFINE();


#define BUFFER_COUNT 5
//#define GL() gl->


typedef enum message_Type
{
 MSG_NEWFRAME = 0,
 MSG_READY ,
 MSG_HELLO,
 MSG_GOODBYE,
 
 
}Message_Type;

typedef struct
{
   EINA_INLIST;
   GLuint fbo, tex;
   EvasGLSync sync;
   int id;
}
Target_Buffer;


typedef struct
{
 Message_Type type;
 Target_Buffer *target;
 
}Message_Data;

typedef struct appdata {
 const char *name;

 Evas_Object *win;
 Evas_Object *conform;

 /* GL related data here... */
 unsigned int program;
 unsigned int vtx_shader;
 unsigned int fgmt_shader;

 float xangle;
 float yangle;

 unsigned int idx_position;
 unsigned int idx_color;
 int idx_mvp;

 float mvp[16];

 Eina_Bool mouse_down : 1;
 Eina_Bool initialized :1;

 Evas_Object *glview;
 Ecore_Pipe * pipe;
 Eina_Lock    lck;
 Evas_GL_Context *main_ctx;
 GLuint vbo[4];
 Ecore_Thread * thread;
 
 Evas_GL_Context* ctx;
 
 Evas_GL_Surface* sfc;
 Eina_Inlist* buffers_empty;
 Eina_Inlist* buffers_ready;
} appdata_s;


static void win_back_cb(void *data, Evas_Object *obj, void *event_info) {
 appdata_s *ad = data;
 /* Let window go to hidden state. */
 elm_win_lower(ad->win);
}

 

static void del_gl(Evas_Object *obj) {
 appdata_s *ad = evas_object_data_get(obj, "ad");

 glDeleteShader(ad->vtx_shader);
 glDeleteShader(ad->fgmt_shader);
 glDeleteProgram(ad->program);

 evas_object_data_del((Evas_Object*) obj, "ad");
}

static void del_anim(void *data, Evas *evas, Evas_Object *obj, void *event_info)
{
 Ecore_Animator *ani = evas_object_data_get(obj, "ani");
 ecore_animator_del(ani);
}

static Eina_Bool anim(void *data) {
 elm_glview_changed_set(data);
 return EINA_TRUE;
}

static void resize_gl(Evas_Object *obj) {
 int w, h;

 elm_glview_size_get(obj, &w, &h);

 glViewport(0, 0, w, h);
}

 

static void create_indicator(appdata_s *ad) {
 elm_win_conformant_set(ad->win, EINA_TRUE);

 elm_win_indicator_mode_set(ad->win, ELM_WIN_INDICATOR_SHOW);
 elm_win_indicator_opacity_set(ad->win, ELM_WIN_INDICATOR_TRANSPARENT);

 ad->conform = elm_conformant_add(ad->win);
 evas_object_size_hint_weight_set(ad->conform, EVAS_HINT_EXPAND,
   EVAS_HINT_EXPAND);
 elm_win_resize_object_add(ad->win, ad->conform);
 evas_object_show(ad->conform);
}


void
draw_rectangle(appdata_s *ad, int w, int h, int tex)
{
   //ELEMENTARY_GLVIEW_GLOBAL_USE(ad->glview);
   GLuint u;
   glViewport(0, 0, w, h);
   glClearColor(1.0, 1.0, 1.0, 1.0);
  
   glClear(GL_COLOR_BUFFER_BIT);
   glEnable(GL_BLEND);
   glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
 
   glUseProgram(ad->program);
   glBindBuffer(GL_ARRAY_BUFFER, ad->vbo[0]);
   glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
   glEnableVertexAttribArray(0);
   glBindBuffer(GL_ARRAY_BUFFER, ad->vbo[1]);
  
   glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
   glEnableVertexAttribArray(1);
   u = glGetUniformLocation(ad->program, "tex");
   glUniform1i(u, 0);
  
   glActiveTexture(GL_TEXTURE0);
  
   printf("tex %d\n",tex);

 //return ;
   glBindTexture(GL_TEXTURE_2D, tex);  //crash!!!!!!!!!
 
   glDrawArrays(GL_TRIANGLES, 0, 6);
}


static void render(Evas_Object *obj)
{
 appdata_s *ad = evas_object_data_get(obj,"ad");
 
 int w,h;
 Target_Buffer *target;

 eina_lock_take(&ad->lck);
 if (!ad->buffers_ready)
 {
  // Wait
  eina_lock_release(&ad->lck);
  usleep(1000);
  return;
 }
  
 target = EINA_INLIST_CONTAINER_GET(ad->buffers_ready, Target_Buffer);
 ad->buffers_ready = eina_inlist_remove(ad->buffers_ready, ad->buffers_ready);
 eina_lock_release(&ad->lck);
 evas_object_geometry_get(ad->glview, 0, 0, &w, &h);
 //printf("tex %d\n",target->tex);

 draw_rectangle(ad, w, h, target->tex);
}

// Render thread to main loop 
static void
message_send(appdata_s *ad, Message_Type type, ...)
{
   Message_Data msg = {0};
   msg.type = type;
   if (type == MSG_NEWFRAME)
   {
      va_list args;
      va_start(args, type);
      msg.target = va_arg(args, Target_Buffer *);
      va_end(args);
   }
 
   // The pipe copies the passed data
   if(ad->pipe == NULL)
   {
  printf("pipe is null \n");
  return;
   }
   ecore_pipe_write(ad->pipe, &msg, sizeof(msg));
   return ;
}


static void
pipe_handler(void *data, void *buf, unsigned int len EINA_UNUSED)
{
   Message_Data *msg = buf;
   appdata_s *ad = data;
   switch (msg->type)
   {
      case MSG_HELLO:
         // Render thread has started 
         printf("The render thread is saying hello.\n");
         break;
      case MSG_GOODBYE:
         // It is now safe to request exit from the main loop 
         printf("Thread has cleanly terminated.\n");
         elm_exit();
         break;
   case MSG_READY:
    printf("The RenderThread has ready.\n");
      break;
   case MSG_NEWFRAME:
    // Queue a new frame description 
    printf("Got a new frame with buffer %d\n", msg->target->id);

    eina_lock_take(&ad->lck);
    ad->buffers_ready = eina_inlist_append(ad->buffers_ready, EINA_INLIST_GET(msg->target));
    eina_lock_release(&ad->lck);
    elm_glview_changed_set(ad->glview);
    //render(ad->glview);
    break;
   }
}


static Target_Buffer *
target_create(appdata_s *ad EINA_UNUSED, Evas_GL_API *gl)
{
   Target_Buffer *target = calloc(1, sizeof(Target_Buffer));
   GLenum err;
   if (!target)
      return NULL;
  // glGenFramebuffers(1, &target->fbo);
  // glBindFramebuffer(GL_FRAMEBUFFER, target->fbo);
   glGenTextures(1, &target->tex);
   glBindTexture(GL_TEXTURE_2D, target->tex);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 720, 1280, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
   //glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, target->tex, 0);
   //err = glCheckFramebufferStatus(GL_FRAMEBUFFER);
   //printf("tex create :%d \n",target->tex);
   //if (err != GL_FRAMEBUFFER_COMPLETE)
   //
   //{
  //    printf("FBO could not be set: 0x%x\n", (int) err);
   //   glDeleteTextures(1, &target->tex);
      //glDeleteFramebuffers(1, &target->fbo);
   //   free(target);
  //    return NULL;
  // }
   return target;
}

static void
thread_draw(appdata_s *ad, Evas_GL_API *gl)
{
   // Draw function 
   glClearColor(0, 0,0, 0);
   glClear(GL_COLOR_BUFFER_BIT);
}

 

void thread_run(void *data, Ecore_Thread *th EINA_UNUSED)
{
 printf("The Render Thread run .\n");
 
 appdata_s *ad = (appdata_s *)data;
 Evas_GL *evgl = elm_glview_evas_gl_get(ad->glview);

 Evas_GL_Config  *cfg;
 cfg = evas_gl_config_new();
 cfg->color_format = EVAS_GL_NO_FBO;
 cfg->depth_bits = EVAS_GL_DEPTH_NONE;
 cfg->stencil_bits = EVAS_GL_STENCIL_NONE;
 cfg->options_bits = EVAS_GL_OPTIONS_NONE;
 ad->sfc = evas_gl_pbuffer_surface_create(evgl, cfg, 720, 1280, NULL);
 evas_gl_config_free(cfg);
 ad->ctx = evas_gl_context_create(evgl, ad->main_ctx);
 evas_gl_make_current(evgl, ad->sfc, ad->ctx);

 
 Evas_GL_API* gl= evas_gl_api_get(evgl);

 // Create targets (needs at least 2) 
 eina_lock_take(&ad->lck);
 int i;
 Target_Buffer *target;
 for (i = 0; i < BUFFER_COUNT; i++)
 {
    target = target_create(ad, gl);
    if (!target) break;
    target->id = i;
    ad->buffers_empty = eina_inlist_append(ad->buffers_empty,
                                           EINA_INLIST_GET(target));
 }
 eina_lock_release(&ad->lck);
 message_send(ad, MSG_READY);

 

   evas_gl_make_current(evgl, ad->sfc, ad->ctx);
  
   while (!ecore_thread_check(ad->thread))
   {
      // Get an empty buffer 
      eina_lock_take(&ad->lck);
      if (!ad->buffers_empty)
      {
         // Wait
         eina_lock_release(&ad->lck);
         usleep(1000);
         continue;
      }
  
      target = EINA_INLIST_CONTAINER_GET(ad->buffers_empty, Target_Buffer);
      ad->buffers_empty = eina_inlist_remove(ad->buffers_empty, ad->buffers_empty);
      eina_lock_release(&ad->lck);
      // Prepare new frame 
      glViewport(0, 0, 720, 1280);
     // glBindFramebuffer(GL_FRAMEBUFFER, target->fbo);
  
      // Draw a new frame 
      thread_draw(ad, gl);
  
      // Release FBO; some drivers complain if it is bound by a different thread
     // glBindFramebuffer(GL_FRAMEBUFFER, 0);   //remove by ds
 
   message_send(ad, MSG_NEWFRAME, target);   //add by ds
  
   }
}


static void
init(Evas_Object *o)
{
   //APPDATA(o);
   //GLUSE(o);
   printf("The main thread init.\n");
   appdata_s *ad;
   ad = evas_object_data_get(o,"ad");
   const char *p;
   static const char vertex_texture[] =
       "attribute vec4 vPosition;\n"
       "attribute vec2 vTexCoord;\n"
       "varying vec2 texcoord;\n"
       "void main()\n"
       "{\n"
       "   gl_Position = vPosition;\n"
       "   texcoord = vTexCoord;\n"
       "}\n";
   static const char fragment_texture[] =
       "#ifdef GL_ES\n"
       "precision mediump float;\n"
       "#endif\n"
       "uniform sampler2D tex;\n"
       "varying vec2 texcoord;\n"
       "void main()\n"
       "{\n"
       "   gl_FragColor = texture2D(tex, texcoord);\n"
       "}\n";
   const float rectangle_fullscreen_vertices[] =
   {
      1.0,  1.0,  0.0,
      -1.0, -1.0,  0.0,
      1.0, -1.0,  0.0,
      1.0,  1.0,  0.0,
      -1.0,  1.0,  0.0,
      -1.0, -1.0,  0.0
   };
   const float texture_vertices[] =
   {
      1.0,  1.0,
      0.0,  0.0,
      1.0,  0.0,
      1.0,  1.0,
      0.0,  1.0,
      0.0,  0.0,
   };
   // Init main data
   ad->main_ctx = evas_gl_current_context_get(elm_glview_evas_gl_get(o));
   // Create vertex data
   glGenBuffers(2, ad->vbo);
   glBindBuffer(GL_ARRAY_BUFFER, ad->vbo[0]);
   glBufferData(GL_ARRAY_BUFFER, 3 * 6 * 4, rectangle_fullscreen_vertices, GL_STATIC_DRAW);
   glBindBuffer(GL_ARRAY_BUFFER, ad->vbo[1]);
   glBufferData(GL_ARRAY_BUFFER, 2 * 6 * 4, texture_vertices, GL_STATIC_DRAW);
   // Texture draw
   p = vertex_texture;
   ad->vtx_shader = glCreateShader(GL_VERTEX_SHADER);
   glShaderSource(ad->vtx_shader, 1, &p, NULL);
   glCompileShader(ad->vtx_shader);
   p = fragment_texture;
   ad->fgmt_shader = glCreateShader(GL_FRAGMENT_SHADER);
   glShaderSource(ad->fgmt_shader, 1, &p, NULL);
   glCompileShader(ad->fgmt_shader);
   ad->program = glCreateProgram();
   glAttachShader(ad->program, ad->vtx_shader);
   glAttachShader(ad->program, ad->fgmt_shader);
   glBindAttribLocation(ad->program, 0, "vPosition");
   glBindAttribLocation(ad->program, 1, "vTexCoord");
   glLinkProgram(ad->program);

   printf("The main thread end.\n");

   ad->thread = ecore_thread_run(thread_run, NULL, NULL, ad);
}


static Evas_Object* add_win(const char *name) {
 Evas_Object *win;

 //elm_config_accel_preference_set("opengl");
 
 elm_config_accel_preference_set("gl");
 elm_config_accel_preference_override_set(EINA_TRUE);
 
 win = elm_win_util_standard_add(name, "OpenGL example: Cube");

 if (!win)
  return NULL;

// if (elm_win_wm_rotation_supported_get(win)) {
//  int rots[4] = { 0, 90, 180, 270 };
//  elm_win_wm_rotation_available_rotations_set(win, rots, 4);
// }

 evas_object_show(win);

 return win;
}

static bool app_create(void *data) {
 /* Hook to take necessary actions before main event loop starts
  * Initialize UI resources and application's data
  * If this function returns true, the main loop of application starts
  * If this function returns false, the application is terminated. */
    printf("The app create.\n");

 Evas_Object *win, *bx, *o;
 Ecore_Animator *ani;
 appdata_s *ad = data;

 if (!data)
  return false;

 /* Create the window */
 win = add_win("glview");

 if (!win)
  return false;

 eext_object_event_callback_add(win, EEXT_CALLBACK_BACK, win_back_cb, ad);

 ad->win = win;

 /* Add a box to contain our GLView */
 bx = elm_box_add(win);
 evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
 elm_win_resize_object_add(win, bx);
 evas_object_show(bx);

 /* Create and initialize GLView */
 o = elm_glview_add(win);
 //ELEMENTARY_GLVIEW_GLOBAL_USE(o);
 evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
 evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);

 
 //o = elm_glview_version_add(win, EVAS_GL_GLES_2_X);
 //evas_object_size_hint_min_set(o, 240, 240);
 //elm_win_resize_object_add(win, o);

 /* Request a surface with alpha and a depth buffer */
 elm_glview_mode_set(o, ELM_GLVIEW_ALPHA | ELM_GLVIEW_DEPTH);

 elm_glview_render_policy_set(o, ELM_GLVIEW_RENDER_POLICY_ON_DEMAND);
 elm_glview_resize_policy_set(o, ELM_GLVIEW_RESIZE_POLICY_RECREATE);

 ELEMENTARY_GLVIEW_GLOBAL_USE(o);  //add by ds
 /* The initialize callback function gets registered here */
 printf("ready to into init function.\n");

 ad->pipe = ecore_pipe_add(pipe_handler, ad);
 eina_lock_new(&ad->lck);
 elm_glview_init_func_set(o, init);

 /* The delete callback function gets registered here */
 elm_glview_del_func_set(o, del_gl);

 /* The resize callback function gets registered here */
 elm_glview_resize_func_set(o, resize_gl);

 /* The render callback function gets registered here */
 elm_glview_render_func_set(o, render);

 /* Add the GLView to the box and show it */
 elm_box_pack_end(bx, o);
 evas_object_show(o);

 elm_object_focus_set(o, EINA_TRUE);

 ani = ecore_animator_add(anim, o);
 evas_object_data_set(o, "ani", ani);
 evas_object_show(win);

 evas_object_data_set(o, "ad", ad);
 ad->glview = o ;

 

 create_indicator(ad);

 /* Return true: the main loop will now start running */
 return true;
}

static void app_control(app_control_h app_control, void *data) {
 /* Handle the launch request. */
}

static void app_pause(void *data) {
 /* Take necessary actions when application becomes invisible. */
}

static void app_resume(void *data) {
 /* Take necessary actions when application becomes visible. */
}

static void app_terminate(void *data) {
 /* Release all resources. */
}

int main(int argc, char *argv[]) {
 appdata_s ad = { NULL, };
 int ret = 0;

 ui_app_lifecycle_callback_s event_callback = {NULL,};

 ad.name = "glview";

 event_callback.create = app_create;
 event_callback.terminate = app_terminate;
 event_callback.pause = app_pause;
 event_callback.resume = app_resume;
 event_callback.app_control = app_control;

 ret = ui_app_main(argc, argv, &event_callback, &ad);
 if (ret != APP_ERROR_NONE) {
  printf( "The application failed to start, and returned %d", ret);
 }

 return ret;
}

Responses

1 댓글
Xaemin Cho

Hi,

I had tested your source code with my Z1.

All white screen was shown as you described at first time, but when I comment-out glBindTexture, then all black screen was shown.

So I think glBind texture is not main reason of error, because I didn't see any un-textured solid objects in the screen even when I didn't call glBindTexture.

 

What was your reference code if there is?

How about other OpenGL samples in your Z1?