mesa3d原始碼閱讀筆記(3)_wglMakeCurrent解析

來源:互聯網
上載者:User

接前一文,來看WMesaMakeCurrent函數在調用_mesa_make_current之後所發生的事情:

_mesa_make_current// context.c  從第1310行到第1436行GLboolean_mesa_make_current( GLcontext *newCtx, GLframebuffer *drawBuffer,                    GLframebuffer *readBuffer ){   if (MESA_VERBOSE & VERBOSE_API)      _mesa_debug(newCtx, "_mesa_make_current()\n");   /* Check that the context's and framebuffer's visuals are compatible.    */   if (newCtx && drawBuffer && newCtx->WinSysDrawBuffer != drawBuffer) {      if (!check_compatible(newCtx, drawBuffer)) {         _mesa_warning(newCtx,              "MakeCurrent: incompatible visuals for context and drawbuffer");         return GL_FALSE;      }   }   if (newCtx && readBuffer && newCtx->WinSysReadBuffer != readBuffer) {      if (!check_compatible(newCtx, readBuffer)) {         _mesa_warning(newCtx,              "MakeCurrent: incompatible visuals for context and readbuffer");         return GL_FALSE;      }   }   /* We used to call _glapi_check_multithread() here.  Now do it in drivers */   _glapi_set_context((void *) newCtx);   ASSERT(_mesa_get_current_context() == newCtx);   if (!newCtx) {      _glapi_set_dispatch(NULL);  /* none current */   }   else {      _glapi_set_dispatch(newCtx->CurrentDispatch);      if (drawBuffer && readBuffer) { /* TODO: check if newCtx and buffer's visual match??? */         ASSERT(drawBuffer->Name == 0);         ASSERT(readBuffer->Name == 0);         _mesa_reference_framebuffer(&newCtx->WinSysDrawBuffer, drawBuffer);         _mesa_reference_framebuffer(&newCtx->WinSysReadBuffer, readBuffer);         /*          * Only set the context's Draw/ReadBuffer fields if they're NULL          * or not bound to a user-created FBO.          */         if (!newCtx->DrawBuffer || newCtx->DrawBuffer->Name == 0) {            /* KW: merge conflict here, revisit.              */            /* fix up the fb fields - these will end up wrong otherwise             * if the DRIdrawable changes, and everything relies on them.             * This is a bit messy (same as needed in _mesa_BindFramebufferEXT)             */            unsigned int i;            GLenum buffers[MAX_DRAW_BUFFERS];            _mesa_reference_framebuffer(&newCtx->DrawBuffer, drawBuffer);            for(i = 0; i < newCtx->Const.MaxDrawBuffers; i++) {               buffers[i] = newCtx->Color.DrawBuffer[i];            }            _mesa_drawbuffers(newCtx, newCtx->Const.MaxDrawBuffers, buffers, NULL);         }         if (!newCtx->ReadBuffer || newCtx->ReadBuffer->Name == 0) {            _mesa_reference_framebuffer(&newCtx->ReadBuffer, readBuffer);         }         /* XXX only set this flag if we're really changing the draw/read          * framebuffer bindings.          */ newCtx->NewState |= _NEW_BUFFERS;#if 1         /* We want to get rid of these lines: */#if _HAVE_FULL_GL         if (!drawBuffer->Initialized) {            initialize_framebuffer_size(newCtx, drawBuffer);         }         if (readBuffer != drawBuffer && !readBuffer->Initialized) {            initialize_framebuffer_size(newCtx, readBuffer);         } _mesa_resizebuffers(newCtx);#endif#else         /* We want the drawBuffer and readBuffer to be initialized by          * the driver.          * This generally means the Width and Height match the actual          * window size and the renderbuffers (both hardware and software          * based) are allocated to match.  The later can generally be          * done with a call to _mesa_resize_framebuffer().          *          * It's theoretically possible for a buffer to have zero width          * or height, but for now, assert check that the driver did what's          * expected of it.          */         ASSERT(drawBuffer->Width > 0);         ASSERT(drawBuffer->Height > 0);#endif         if (drawBuffer) {            _mesa_check_init_viewport(newCtx,                                      drawBuffer->Width, drawBuffer->Height);         }      }      if (newCtx->FirstTimeCurrent) {         check_context_limits(newCtx);         /* We can use this to help debug user's problems.  Tell them to set          * the MESA_INFO env variable before running their app.  Then the          * first time each context is made current we'll print some useful          * information.          */ if (_mesa_getenv("MESA_INFO")) {    _mesa_print_info(); } newCtx->FirstTimeCurrent = GL_FALSE;      }   }      return GL_TRUE;}

第1335行調用glapi.c裡_glapi_set_context函數設定當前的ctx,即設定工程全域變數_glapi_Context的值指向context,在wmesa_context結構成員中首成員即GLcontext,所以二者的指標地址是相同的;
第1342行調用glapi.c裡_glapi_set_dispatch設定當前的函數控制代碼,即設定工程全域變數_glapi_Dispatch指標指向。
在glapitable.h裡定義了_glapi_table結構,它包括所有的OpenGL發布函數gl*函數指標成員變數,在gl*系列發布函數代碼體基本上都是擷取當前_glapi_Dispatch成員地址,調用該成員所指向的函數指標地址。而這些成員的賦值是在_mesa_initialize_context函數執行時所做的。而這裡調用_glapi_set_dispatch將_glapi_Dispatch與具體的對應函數地址對應起來。
若沒有調用_mesa_make_current來關聯二者之前,_glapi_Dispatch初始指向__glapi_noop_table,而且如果使用NULL來調用_mesa_make_current也會使得_glapi_Dispatch指向__glapi_noop_table。
檔案域全域變數__glapi_noop_table是在glapi.c裡通過包含glapitemp.h定義宏替換來聲明定義的,該宏替換一方面定義了一組空的只警告又不做什麼的gl*函數的翻版,起頭是Noop*,一如它們的功能一樣,然後將這些函數指標收集起來即__glapi_noop_table變數的值,顯然如果使用者沒有在事前調用wglMakeCurrent關聯到可用的hglrc的話,那麼就是不應該使用gl*系列的函數的。
這裡暫不關注對幀緩衝區的相關操作,一時半會還關注不過來。

現在回過頭來看GLcontext結構中與_glapi_table有關的成員,以及它們的初始化賦值:

// mtypes.h  /*2893*/ struct __GLcontextRec/*2894*/ {            // ....../*2898*/    /** \name API function pointer tables *//*2899*/    /*@{*//*2900*/    struct _glapi_table *Save;/**< Display list save functions *//*2901*/    struct _glapi_table *Exec;/**< Execute functions *//*2902*/    struct _glapi_table *CurrentDispatch;  /**< == Save or Exec !! *//*2903*/    /*@}*/            // ....../*3094*/ };

__GLcontextRec即GLcontext結構,成員Save和Exec均在_mesa_initialize_context時初始化,有許多gl*發布函數均在這裡設定對應的函數指標地址,以下代碼嘗試弄清楚該函數所做的具體工作:

_mesa_initialize_context// context.c  從第843行起至933行GLboolean_mesa_initialize_context(GLcontext *ctx,                         const GLvisual *visual,                         GLcontext *share_list,                         const struct dd_function_table *driverFunctions,                         void *driverContext){   struct gl_shared_state *shared;   /*ASSERT(driverContext);*/   assert(driverFunctions->NewTextureObject);   assert(driverFunctions->FreeTexImageData);   /* misc one-time initializations */   one_time_init(ctx);   ctx->Visual = *visual;   ctx->DrawBuffer = NULL;   ctx->ReadBuffer = NULL;   ctx->WinSysDrawBuffer = NULL;   ctx->WinSysReadBuffer = NULL;   /* Plug in driver functions and context pointer here.    * This is important because when we call alloc_shared_state() below    * we'll call ctx->Driver.NewTextureObject() to create the default    * textures.    */   ctx->Driver = *driverFunctions;   ctx->DriverCtx = driverContext;   if (share_list) {      /* share state with another context */      shared = share_list->Shared;   }   else {      /* allocate new, unshared state */      shared = _mesa_alloc_shared_state(ctx);      if (!shared)         return GL_FALSE;   }   _glthread_LOCK_MUTEX(shared->Mutex);   ctx->Shared = shared;   shared->RefCount++;   _glthread_UNLOCK_MUTEX(shared->Mutex);   if (!init_attrib_groups( ctx )) {      _mesa_free_shared_state(ctx, ctx->Shared);      return GL_FALSE;   }   /* setup the API dispatch tables */   ctx->Exec = alloc_dispatch_table();   ctx->Save = alloc_dispatch_table();   if (!ctx->Exec || !ctx->Save) {      _mesa_free_shared_state(ctx, ctx->Shared);      if (ctx->Exec)         _mesa_free(ctx->Exec);      return GL_FALSE;   }#if FEATURE_dispatch   _mesa_init_exec_table(ctx->Exec);#endif   ctx->CurrentDispatch = ctx->Exec;#if FEATURE_dlist   _mesa_init_dlist_table(ctx->Save);   _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );#endif   /* Neutral tnl module stuff */   _mesa_init_exec_vtxfmt( ctx );    ctx->TnlModule.Current = NULL;   ctx->TnlModule.SwapCount = 0;   ctx->FragmentProgram._MaintainTexEnvProgram      = (_mesa_getenv("MESA_TEX_PROG") != NULL);   ctx->VertexProgram._MaintainTnlProgram      = (_mesa_getenv("MESA_TNL_PROG") != NULL);   if (ctx->VertexProgram._MaintainTnlProgram) {      /* this is required... */      ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE;   }#ifdef FEATURE_extra_context_init   _mesa_initialize_context_extra(ctx);#endif   ctx->FirstTimeCurrent = GL_TRUE;   return GL_TRUE;}

第895行,申請_glapi_table結構,並以警告函數指標初始化,賦給ctx->Exec。而第896行與此一樣;
第904行,調用在api_exec.c裡第151行的_mesa_init_exec_table函數設定ctx->Exec各成員指標指向對應的工程函數;
第905行,設定當前的函數分發表指向ctx->Exec;
第908行、第909行都是對ctx->Save的初始化,暫時不去解析;
第912行則是調用在vtxfmt.c裡的_mesa_init_exec_vtxfmt函數設定ctx->Exec中對應GLvertexformat結構的成員函數指標初始化;
GLvertexformat結構在dd.h標頭檔裡定義,它所包含的函數都是有可能在glBegin()/glEnd()之間使用的函數。
neutral_vtxfmt是vtxfmt.c定義宏定義包含vtxfmt_tmp.h而得到的檔案域全域變數,這些函數的代碼體都差不多,估計是與tnl模組的互動;
第913行與914行初始化表明vtxfmt與tnl模組之間還沒有交換過成員值。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.