久久精品国产精品国产精品污,男人扒开添女人下部免费视频,一级国产69式性姿势免费视频,夜鲁夜鲁很鲁在线视频 视频,欧美丰满少妇一区二区三区,国产偷国产偷亚洲高清人乐享,中文 在线 日韩 亚洲 欧美,熟妇人妻无乱码中文字幕真矢织江,一区二区三区人妻制服国产

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

mesa3d源代码阅读笔记

發布時間:2023/12/10 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mesa3d源代码阅读笔记 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.


http://www.cnblogs.com/zale_lzj/archive/2012/08/19/2646190.html



最近準備去閱讀Mesa3d(采用7.6.1版本)的源代碼,代碼量很大,感覺到十分困難。以后是否能夠讀下去,并且理解它的整個實現過程,不能確定。但既然閱讀了,就應該積累起來,特寫下本系列筆記。

1 編譯Mesa3d 7.6.1是很容易的事情,里邊包含有VC8的sln解決方案,打開它直接編譯即可完成;

2 如何調試編譯出來的opengl32.dll文件呢?其實Windows系統在檢索exe所需要的dll文件時,第一順序是在當前exe文件所在的目錄,所以只要保證編譯出的opengl32.dll與調試用的exe文件生成在同一目錄,就可以在調試時進入到對應opengl函數的實現代碼環節,并不需要將opengl32.dll拷貝到系統目錄(這樣做可以避免對系統目錄不必要的更改);

3 閱讀源代碼時,我首先是找opengl32.dll中導出的函數它具體對應的代碼函數在哪兒。嚴格地說這比較難找,因為在mesa里是使用函數分發表來處理的。在glapitemp.h頭文件里以宏的方式定義了許多函數,該文件被兩個.c文件包含,一個是dispatch.c,一個是glapi.c。前者結合dispatch.h包含glapitemp.h將對應宏展開成為對應opengl32.dll所導出的函數體定義;而后者則是定義成為一組對應opengl到處函數的相應NoOp*函數,并且將這些函數保存到__glapi_noop_table結構變量里。實際上在運行過程中,一直會有一個extern struct _glapi_table *_glapi_Dispatch;內部函數成員地址會被修正成為相應的mesa實現函數。調用opengl函數實際上是通過dispatch.c呼叫_glapi_Dispatch里所存儲的對應函數,這一過程即分發,所以說dispatch table唄;

4 當然這里wgl*系列函數和部分gl*函數都比較好找,而glBegin、glEnd以及用在它們之間的glColor*、glVertex*系列函數的分發過程就比較復雜。到現在為止,雖然調試過好幾遍mesa源代碼,但是仍然暈頭轉向的。

5 Mesa3d 7.6.1源代碼里有部分文件寫有一些說明,真的很寶貴,但遺憾的是實在太少;整個工程模塊又存有許多模塊,閱讀量很大;在光柵渲染環節存在許多函數分發表,搞得暈頭轉向。

不知道閱讀這樣的源代碼怎樣去做比較好?

?

2011-04-19 附加閱讀源碼時的opengl程序代碼

共計三個文件,代碼是在Nehe教程基礎上,附加面向對象封裝之后而成,不一定好,僅供參考。

從屬于demo項目,添加到mesa工程解決方案之下。

OpenGLDC.h/***************************************************************************** 封裝OpenGL的專用類 *****************************************************************************/ #ifndef __OPENGL_DC_H_INCLUDED #define __OPENGL_DC_H_INCLUDED#ifdef _DEBUG #include "gl/gl.h" #include "gl/glu.h"#pragma comment (lib, "opengl32.lib") #pragma comment (lib, "glu32.lib") #else #include <gl/gl.h> #include <gl/glu.h>#pragma comment (lib, "opengl32.lib") #pragma comment (lib, "glu32.lib") #endif // _DEBUG */class COpenGLDC { public:COpenGLDC();~COpenGLDC();public:GLboolean GLSetupRC(HWND hWnd);GLvoid GLRelease(GLvoid);GLboolean GLInit(GLvoid);GLvoid GLResize(GLsizei nWidth, GLsizei nHeight);GLboolean GLDrawScene(GLvoid);GLvoid ProcessKeys(bool keys[256]);protected:HWND m_hWnd;HGLRC m_hRC;HDC m_hDC; };#endif // __OPENGL_DC_H_INCLUDED

?

第二個文件

OpenGLDC.cpp#ifndef VC_EXTRALEAN #define VC_EXTRALEAN // 從Windows 頭中排除極少使用的資料 #endif#include <windows.h> #include <assert.h>#include "OpenGLDC.h"COpenGLDC::COpenGLDC() { }COpenGLDC::~COpenGLDC() {GLRelease(); }GLboolean COpenGLDC::GLSetupRC(HWND hWnd) {int nPixelFormat;PIXELFORMATDESCRIPTOR pfd = {sizeof(PIXELFORMATDESCRIPTOR), // 上述格式描述符的大小1, // 版本號PFD_DRAW_TO_WINDOW | // 支持在窗口中繪圖PFD_SUPPORT_OPENGL | // 支持OpenGL PFD_DOUBLEBUFFER, // 雙緩存模式PFD_TYPE_RGBA, // RGBA 顏色模式24, // 24 位顏色深度0, 0, 0, 0, 0, 0, // 忽略顏色位0, // 沒有Alpha非透明度緩存0, // 忽略移位位Shift Bit0, // 無累加緩存0, 0, 0, 0, // 忽略累加位32, // 32 位深度緩存 0, // 無模板緩存0, // 無輔助緩存PFD_MAIN_PLANE, // 主層0, // 保留0, 0, 0 // 忽略層,可見性和損毀掩模};m_hWnd = hWnd;if ((m_hDC = ::GetDC(m_hWnd)) == NULL){MessageBox(NULL, "獲取設備模式句柄失敗","錯誤",MB_OK|MB_ICONEXCLAMATION);return false;}if(!(nPixelFormat = ChoosePixelFormat(m_hDC, &pfd))){MessageBox(NULL, "沒找到合適的顯示模式","錯誤",MB_OK|MB_ICONEXCLAMATION);return false;}if(!SetPixelFormat(m_hDC, nPixelFormat, &pfd)) // 能夠設置像素格式么{MessageBox(NULL, "不能設置像素格式", "錯誤", MB_OK|MB_ICONEXCLAMATION);return false;}if(!(m_hRC = wglCreateContext(m_hDC))) // 獲取渲染描述句柄{MessageBox(NULL, "不能創建OpenGL渲染描述表", "錯誤",MB_OK|MB_ICONEXCLAMATION);return false;}if(!wglMakeCurrent(m_hDC, m_hRC)) // 嘗試激活著色描述表{MessageBox(NULL, "不能激活當前的OpenGL渲染描述表", "錯誤",MB_OK|MB_ICONEXCLAMATION);return false;}return true; }GLvoid COpenGLDC::GLRelease() {if(m_hRC){if(!wglMakeCurrent(NULL, NULL)) // 我們能否釋放DC和RC描述表{MessageBox(NULL, "釋放DC或RC失敗.", "關閉錯誤",MB_OK | MB_ICONINFORMATION);}if(!wglDeleteContext(m_hRC)) // 我們能否刪除RC?{MessageBox(NULL, "釋放RC失敗.", "關閉錯誤",MB_OK | MB_ICONINFORMATION);}m_hRC = NULL;}if(m_hDC != NULL && !::ReleaseDC(m_hWnd, m_hDC)) // 我們能否釋放DC{MessageBox(NULL, "釋放DC失敗.", "關閉錯誤",MB_OK | MB_ICONINFORMATION);}m_hDC = NULL; }GLvoid COpenGLDC::GLResize(GLsizei nWidth, GLsizei nHeight) {// 重置OpenGL窗口大小if(nHeight == 0) // 防止被零除nHeight = 1;glViewport(0, 0, nWidth, nHeight);glMatrixMode(GL_PROJECTION); // 選擇投影矩陣glLoadIdentity(); // 重置投影矩陣gluPerspective(45.0f, // 透視角設置為45 度(GLfloat)nWidth/(GLfloat)nHeight, // 窗口的寬與高比0.1f, 100.0f); // 視野透視深度:近點.1f遠點.0fglMatrixMode(GL_MODELVIEW); // 選擇模型觀察矩陣glLoadIdentity(); }// // // 主要改變增減代碼存放地 // ////GLboolean COpenGLDC::GLInit(GLvoid) {glShadeModel(GL_SMOOTH); // 啟用陰影平滑glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // 黑色背景glClearDepth(1.0f); // 設置深度緩存glEnable(GL_DEPTH_TEST); // 啟用深度測試glDepthFunc(GL_LEQUAL); // 所作深度測試的類型glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 告訴系統對透視進行修正return true; // 初始化OK }GLboolean COpenGLDC::GLDrawScene(GLvoid) {glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度緩存glLoadIdentity(); // 如果不添加這句,那么所畫的都會由大縮小,無法看見 //glTranslatef(-1.5f,0.0f,-6.0f); // 左移1.5 單位,并移入屏幕6.0glBegin(GL_LINE_LOOP); // 繪制三角形glColor3f(1.0f,0.0f,0.0f); // 設置當前色為紅色glVertex3f( 0.0f, 1.0f, 0.0f); // 上頂點glColor3f(0.0f,1.0f,0.0f); // 設置當前色為綠色glVertex3f(-1.0f,-1.0f, 0.0f); // 左下glColor3f(0.0f,0.0f,1.0f); // 設置當前色為藍色glVertex3f( 1.0f,-1.0f, 0.0f); // 右下glEnd(); // 三角形繪制結束glTranslatef(3.0f,0.0f,0.0f); // 右移單位glColor3f(0.5f,0.5f,1.0f); // 一次性將當前色設置為藍色glBegin(GL_QUADS); // 繪制正方形glVertex3f(-1.0f, 1.0f, 0.0f); // 左上glVertex3f( 1.0f, 1.0f, 0.0f); // 右上glVertex3f( 1.0f,-1.0f, 0.0f); // 左下glVertex3f(-1.0f,-1.0f, 0.0f); // 右下glEnd(); // 正方形繪制結束 //SwapBuffers(m_hDC); // 切換緩沖區,沒有切換的話,窗口不會繪制什么return true; }GLvoid COpenGLDC::ProcessKeys(bool keys[256]) { }


?

第三個文件

WinMain.cpp#define WIN32_LEAN_AND_MEAN #include <windows.h> #include <assert.h>#include "OpenGLDC.h"COpenGLDC *s_pOpenGLDC = NULL; BOOL s_bFullScreen = FALSE; // 全屏標志缺省,缺省設定為不全屏 bool s_keys[256]; // 保存鍵盤按鍵的數組 BOOL s_bActive = TRUE; // 窗口的活動標志,缺省為TRUE HINSTANCE s_hInstance; HWND s_hWnd; char* s_pszTitle = "NeHe's顏色實例";// 窗口回調函數聲明 LRESULT CALLBACK WndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {switch (uMsg) {case WM_ACTIVATE: // 監視窗口激活消息if (!HIWORD(wParam)) // 檢查最小化狀態s_bActive = TRUE; // 程序處于激活狀態else s_bActive = FALSE; // 程序不再激活return 0;case WM_SYSCOMMAND: // 系統中斷命令switch (wParam) // 檢查系統調用{case SC_SCREENSAVE: // 屏保要運行?case SC_MONITORPOWER: // 顯示器要進入節電模式?return 0; // 阻止發生}break; // 退出case WM_SIZE:if (s_pOpenGLDC != NULL)s_pOpenGLDC->GLResize(LOWORD(lParam), HIWORD(lParam));return 0;case WM_CLOSE:PostQuitMessage(0);return 0;case WM_KEYDOWN:s_keys[wParam] = true;return 0;case WM_KEYUP:s_keys[wParam] = false;return 0;}return DefWindowProc (hWnd, uMsg, wParam, lParam); }void KillGLWindow(void) {if (s_bFullScreen) // 我們處于全屏模式嗎?{ChangeDisplaySettings(NULL, 0); // 是的話,切換回桌面ShowCursor(TRUE); // 顯示鼠標指針}if (s_pOpenGLDC != NULL){s_pOpenGLDC->GLRelease();delete s_pOpenGLDC;s_pOpenGLDC = NULL;}if (s_hWnd && !DestroyWindow(s_hWnd)){MessageBox(NULL, "釋放窗口句柄失敗!", "關閉錯誤", MB_OK | MB_ICONINFORMATION);s_hWnd = NULL;}if (!UnregisterClass("OpenG", s_hInstance)) // 能否注銷類?{MessageBox(NULL,"不能注銷窗口類。","關閉錯誤",MB_OK | MB_ICONINFORMATION);s_hInstance = NULL;DWORD nReturnCode = GetLastError();} }/* 這個函數創建我們OpenGL窗口,參數為: ** title - 窗口標題 ** width - 窗口寬度 ** height - 窗口高度 ** bits - 顏色的位深(/16/32) ** fullscreenflag - 是否使用全屏模式,全屏模式(TRUE),窗口模式(FALSE) */ BOOL CreateGLWindow(const char* lpszTitle, int nWidth, int nHeight, int nBits, BOOL bFullScreenFlag) {WNDCLASS wndclass; // 窗口類結構DWORD dwExStyle; // 擴展窗口風格DWORD dwStyle; // 窗口風格RECT WindowRect; // 取得矩形的左上角和右下角的坐標值HWND hWnd; // 創建窗口的句柄HINSTANCE hInstance = GetModuleHandle(NULL);wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // 移動時重畫,并為窗口取得DCwndclass.lpfnWndProc = (WNDPROC) WndProc; // WndProc處理消息wndclass.cbClsExtra = 0; // 無額外窗口數據wndclass.cbWndExtra = 0; // 無額外窗口數據wndclass.hInstance = hInstance; // 設置實例wndclass.hIcon = LoadIcon(NULL, IDI_WINLOGO); // 裝入缺省圖標wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); // 裝入鼠標指針wndclass.hbrBackground = NULL; // GL不需要背景wndclass.lpszMenuName = NULL; // 不需要菜單wndclass.lpszClassName = "OpenG"; // 設定類名字if (!RegisterClass(&wndclass)) // 嘗試注冊窗口類{MessageBox(NULL,"注冊窗口失敗","錯誤",MB_OK|MB_ICONEXCLAMATION);return FALSE; // 退出并返回FALSE}s_bFullScreen = bFullScreenFlag; // 設置全局全屏標志if (s_bFullScreen) // 要嘗試全屏模式嗎?{DEVMODE dmScr; // 設備模式memset(&dmScr,0,sizeof(dmScr)); // 確保內存分配dmScr.dmSize = sizeof(dmScr); // Devmode 結構的大小dmScr.dmPelsWidth = nWidth; // 屏幕寬dmScr.dmPelsHeight= nHeight; // 屏幕高dmScr.dmBitsPerPel= nBits; // 色彩深度dmScr.dmDisplayFrequency = 75; // 刷屏速度dmScr.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT|DM_DISPLAYFREQUENCY;// 嘗試設置顯示模式并返回結果,注:CDC_FULLSCREEN移去了狀態條if (ChangeDisplaySettings(&dmScr, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL){// 若模式失敗,提供兩個選項:退出或在窗口內運行if (MessageBox(NULL,"全屏模式在當前顯卡上設置失敗!\n使用窗口模式?",lpszTitle, MB_YESNO|MB_ICONEXCLAMATION)==IDYES){//如果用戶選擇窗口模式,變量fullscreen 的值變為FALSE,程序繼續運行s_bFullScreen = FALSE; // 選擇窗口模式}else{//如果用戶選擇退出,彈出消息窗口告知用戶程序將結束。//并返回FALSE告訴程序窗口未能成功創建。程序退出。MessageBox(NULL,"程序將被關閉","錯誤",MB_OK|MB_ICONSTOP);return FALSE; // 退出并返回FALSE}}}if (s_bFullScreen){dwExStyle=WS_EX_APPWINDOW; // Window 擴展風格dwStyle=WS_POPUP; // Window 窗口風格ShowCursor(FALSE); // 隱藏鼠標}else {dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // 擴展窗體風格dwStyle = WS_OVERLAPPEDWINDOW; // 窗體風格}WindowRect.left=(long)0; // 將Left 設為0WindowRect.right=(long)nWidth; // 將Right 設為要求的寬度WindowRect.top=(long)0; // 將Top 設為0WindowRect.bottom=(long)nHeight; // 將Bottom 設為要求的高度AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle); // 調整窗口達到真正要求的大小// 創建窗口if (!(hWnd=CreateWindowEx( dwExStyle, // 擴展窗體風格"OpenG", // 類名字lpszTitle, // 窗口標題dwStyle | // 必須的窗體風格屬性WS_CLIPSIBLINGS | // 必須的窗體風格屬性WS_CLIPCHILDREN, // 必須的窗體風格屬性CW_USEDEFAULT, CW_USEDEFAULT, // 窗口位置WindowRect.right-WindowRect.left, // 計算調整好的窗口寬度WindowRect.bottom-WindowRect.top, // 計算調整好的窗口高度NULL, // 無父窗口NULL, // 無菜單hInstance, // 實例NULL))) // 不向WM_CREATE傳遞任何東東{// 如果創建失敗KillGLWindow();MessageBox(NULL,"窗口創建錯誤","錯誤",MB_OK|MB_ICONEXCLAMATION);return FALSE; // 返回FALSE}s_hInstance = hInstance;s_hWnd = hWnd;ShowWindow(hWnd,SW_SHOW); // 顯示窗口SetForegroundWindow(hWnd); // 略略提高優先級SetFocus(hWnd); // 設置鍵盤的焦點至此窗口UpdateWindow(hWnd);s_pOpenGLDC = new COpenGLDC;assert(s_pOpenGLDC != NULL);s_pOpenGLDC->GLSetupRC(hWnd);s_pOpenGLDC->GLResize(nWidth, nHeight);if (!s_pOpenGLDC->GLInit()) // 初始化新建的GL窗口{KillGLWindow(); // 重置顯示區MessageBox(NULL, "調用OpenGLDC初始化函數失敗!", "錯誤", MB_OK | MB_ICONEXCLAMATION);return FALSE;}return TRUE; }int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow) {MSG msg;BOOL done = FALSE; // 用來退出循環的BOOL變量// 提示用戶選擇運行模式 // if (MessageBox(NULL, "你想在全屏模式下運行么?", "設置全屏模式", MB_YESNO | MB_ICONQUESTION) == IDYES) // s_bFullScreen = TRUE; // else // s_bFullScreen = FALSE;// 創建OpenGL窗口if (!CreateGLWindow(s_pszTitle, 640, 480, 32, s_bFullScreen))return -1; // 失敗退出while (!done){if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) // 有消息在等待嗎?{if (msg.message == WM_QUIT) // 收到退出消息?done = TRUE; // 是,則done = TRUEelse // 不是,處理窗口消息{TranslateMessage(&msg); // 翻譯消息DispatchMessage(&msg); // 發送消息}}else {// 繪制場景。監視ESC鍵和來自DrawGLScene()的退出消息if (s_bActive){if (s_keys[VK_ESCAPE])done = TRUE;else if (s_pOpenGLDC != NULL){s_pOpenGLDC->GLDrawScene();s_pOpenGLDC->ProcessKeys(s_keys);}}if (s_keys[VK_F1]){s_keys[VK_F1] = false;KillGLWindow();s_bFullScreen = !s_bFullScreen;// 重建OpenGL窗口if (!CreateGLWindow(s_pszTitle, 640, 480, 32, s_bFullScreen))return -1; // 失敗退出}}}// 關閉程序KillGLWindow(); // 銷毀窗口return msg.wParam; // 退出程序 }
自己編寫一個小的OpenGL程序,附加在mesa工程里調試,開始進入: // OpenGLDC.cpp文件,從第59行起 // 本代碼塊之前會調用ChoosePixelFormat/SetPixelFormat但不會運行mesa里的對應發布函數 /*59*/ if(!(m_hRC = wglCreateContext(m_hDC))) // 獲取渲染描述句柄{MessageBox(NULL, "不能創建OpenGL渲染描述表", "錯誤",MB_OK|MB_ICONEXCLAMATION);return false;}if(!wglMakeCurrent(m_hDC, m_hRC)) // 嘗試激活著色描述表{MessageBox(NULL, "不能激活當前的OpenGL渲染描述表", "錯誤",MB_OK|MB_ICONEXCLAMATION);return false; /*70*/ }

經第59行處的wglCreateContext函數,進入wgl.c里第179行位置的wglCreateContext,此即mesa工程的wglCreateContext發布函數,該處代碼如下所示:

wglCreateContext// wgl.c 從第179行到203行 WINGDIAPI HGLRC GLAPIENTRY wglCreateContext(HDC hdc) {int i = 0;if (!ctx_count) {for(i=0;i<MESAWGL_CTX_MAX_COUNT;i++) {wgl_ctx[i].ctx = NULL;}}for( i = 0; i < MESAWGL_CTX_MAX_COUNT; i++ ) {if ( wgl_ctx[i].ctx == NULL ) {wgl_ctx[i].ctx = WMesaCreateContext(hdc, NULL, (GLboolean)GL_TRUE,(GLboolean) (pfd[curPFD-1].doubleBuffered ?GL_TRUE : GL_FALSE), (GLboolean)(pfd[curPFD-1].pfd.cAlphaBits ? GL_TRUE : GL_FALSE) );if (wgl_ctx[i].ctx == NULL)break;ctx_count++;return ((HGLRC)wgl_ctx[i].ctx);}}SetLastError(0);return(NULL); }

在wgl.c文件聲明有wgl_ctx數組(限定大小MESAWGL_CTX_MAX_COUNT,當前取值20),ctx_count存儲該數組被初始化的數量。
第182行處判定若ctx_count大于0,則第一次初始化wgl_ctx數組所有元素全部為NULL;
第187處的for循環,目的在于尋找到一個空的wgl_ctx數組元素存儲即將創建的WMesaContext結構地址,只要創建一個,即增加ctx_count計數1,并返回所創建的結構地址(即HGLRC句柄);
第201處是不應該被執行的,當已創建的WMesaContext數量大于wgl_ctx數組寬度時,就會到達此處。所以不能創建超過20個HGLRC句柄,就本工程而言。

WMesaCreateContext函數在wmesa.c第1418行起始,該函數代碼如下所示;

WMesaCreateContext// wmesa.c 從第1418行至1531行 WMesaContext WMesaCreateContext(HDC hDC, HPALETTE* Pal,GLboolean rgb_flag,GLboolean db_flag,GLboolean alpha_flag) {WMesaContext c;struct dd_function_table functions;GLint red_bits, green_bits, blue_bits, alpha_bits;GLcontext *ctx;GLvisual *visual;(void) Pal;/* Indexed mode not supported */if (!rgb_flag)return NULL;/* Allocate wmesa context */c = CALLOC_STRUCT(wmesa_context);if (!c)return NULL;#if 0/* I do not understand this contributed code *//* Support memory and device contexts */if(WindowFromDC(hDC) != NULL) {c->hDC = GetDC(WindowFromDC(hDC)); /* huh ???? */}else {c->hDC = hDC;} #elsec->hDC = hDC; #endif/* Get data for visual *//* Dealing with this is actually a bit of overkill because Mesa will end* up treating all color component size requests less than 8 by using * a single byte per channel. In addition, the interface to the span* routines passes colors as an entire byte per channel anyway, so there* is nothing to be saved by telling the visual to be 16 bits if the device* is 16 bits. That is, Mesa is going to compute colors down to 8 bits per* channel anyway.* But we go through the motions here anyway.*/switch (GetDeviceCaps(c->hDC, BITSPIXEL)) {case 16:red_bits = green_bits = blue_bits = 5;alpha_bits = 0;break;default:red_bits = green_bits = blue_bits = 8;alpha_bits = 8;break;}/* Create visual based on flags */visual = _mesa_create_visual(rgb_flag,db_flag, /* db_flag */GL_FALSE, /* stereo */red_bits, green_bits, blue_bits, /* color RGB */alpha_flag ? alpha_bits : 0, /* color A */0, /* index bits */DEFAULT_SOFTWARE_DEPTH_BITS, /* depth_bits */8, /* stencil_bits */16,16,16, /* accum RGB */alpha_flag ? 16 : 0, /* accum A */1); /* num samples */if (!visual) {_mesa_free(c);return NULL;}/* Set up driver functions */_mesa_init_driver_functions(&functions);functions.GetString = wmesa_get_string;functions.UpdateState = wmesa_update_state;functions.GetBufferSize = wmesa_get_buffer_size;functions.Flush = wmesa_flush;functions.Clear = clear;functions.ClearIndex = clear_index;functions.ClearColor = clear_color;functions.ResizeBuffers = wmesa_resize_buffers;functions.Viewport = wmesa_viewport;/* initialize the Mesa context data */ctx = &c->gl_ctx;_mesa_initialize_context(ctx, visual, NULL, &functions, (void *)c);/* visual no longer needed - it was copied by _mesa_initialize_context() */_mesa_destroy_visual(visual);_mesa_enable_sw_extensions(ctx);_mesa_enable_1_3_extensions(ctx);_mesa_enable_1_4_extensions(ctx);_mesa_enable_1_5_extensions(ctx);_mesa_enable_2_0_extensions(ctx);_mesa_enable_2_1_extensions(ctx);/* Initialize the software rasterizer and helper modules. */if (!_swrast_CreateContext(ctx) ||!_vbo_CreateContext(ctx) ||!_tnl_CreateContext(ctx) ||!_swsetup_CreateContext(ctx)) {_mesa_free_context_data(ctx);_mesa_free(c);return NULL;}_swsetup_Wakeup(ctx);TNL_CONTEXT(ctx)->Driver.RunPipeline = _tnl_run_pipeline;return c; }

第1493行的_mesa_init_driver_functions(&functions)初始化dd_function_table結構,即設置結構的函數指針地址,該結構定義在dd.h頭文件第68行起,Device driver functions table. (設備驅動函數表),這些里的絕大多數函數直接與OpenGL狀態指令對應。
第1506行的_mesa_initialize_context函數初始化一個GLcontext結構,該結構為mesa的三大核心結構之一,成員很多。參見后文的解釋。
第1519行有4個內部模塊在做創建初始化:_swrast、_vbo、_tnl、_swsetup。
第1528行處設置_tnl管道函數,它引導了后來的對頂點變換、窗口裁剪、光照紋理計算、直至最終的渲染。

暫時停止對這些中途被呼叫內部函數的分析,來看wglMakeCurrent函數會做什么,wgl.c第234行起是工程對應的wglMakeCurrent發布函數。

wglMakeCurrent// wgl.c文件 第234行至254行 WINGDIAPI BOOL GLAPIENTRY wglMakeCurrent(HDC hdc, HGLRC hglrc) {int i;CurrentHDC = hdc;if (!hdc || !hglrc) {WMesaMakeCurrent(NULL, NULL);ctx_current = -1;return TRUE;}for ( i = 0; i < MESAWGL_CTX_MAX_COUNT; i++ ) {if ( wgl_ctx[i].ctx == (WMesaContext) hglrc ) {WMesaMakeCurrent( (WMesaContext) hglrc, hdc );ctx_current = i;return TRUE;}}return FALSE; }

第238行保存了當前設備DC句柄;
第240行檢查是否是要取消hDC與hglrc之間的關聯,如果是,則以NULL為參數調用WMesaMakeCurrent;
第246行起,for循環檢查輸入參數hglrc是否有效,即必須是先前創建時存儲過的變量地址,如果能夠找到,則調用WMesaMakeCurrent關聯hglrc與hdc設備DC;
ctx_current顯然是指向當前有效的hglrc對應的wgl_ctx數組處的序號。

之后,程序轉入到wmesa.c里的WMesaMakeCurrent函數,源代碼為:

WMesaMakeCurrent// wmesa.c 第1592行起至1648行 void WMesaMakeCurrent(WMesaContext c, HDC hdc) {WMesaFramebuffer pwfb;{/* return if already current */GET_CURRENT_CONTEXT(ctx);WMesaContext pwc = wmesa_context(ctx);if (pwc && c == pwc && pwc->hDC == hdc)return;}pwfb = wmesa_lookup_framebuffer(hdc);/* Lazy creation of framebuffers */if (c && !pwfb && hdc) {struct gl_renderbuffer *rb;GLvisual *visual = &c->gl_ctx.Visual;GLuint width, height;get_window_size(hdc, &width, &height);c->clearPen = CreatePen(PS_SOLID, 1, 0); c->clearBrush = CreateSolidBrush(0); pwfb = wmesa_new_framebuffer(hdc, visual);/* Create back buffer if double buffered */if (visual->doubleBufferMode == 1) {wmCreateBackingStore(pwfb, width, height);}/* make render buffers */if (visual->doubleBufferMode == 1) {rb = wmesa_new_renderbuffer();_mesa_add_renderbuffer(&pwfb->Base, BUFFER_BACK_LEFT, rb);wmesa_set_renderbuffer_funcs(rb, pwfb->pixelformat, pwfb->cColorBits, 1);}rb = wmesa_new_renderbuffer();_mesa_add_renderbuffer(&pwfb->Base, BUFFER_FRONT_LEFT, rb);wmesa_set_renderbuffer_funcs(rb, pwfb->pixelformat, pwfb->cColorBits, 0);/* Let Mesa own the Depth, Stencil, and Accum buffers */_mesa_add_soft_renderbuffers(&pwfb->Base,GL_FALSE, /* color */visual->depthBits > 0,visual->stencilBits > 0,visual->accumRedBits > 0,visual->alphaBits >0, GL_FALSE);}if (c && pwfb)_mesa_make_current(&c->gl_ctx, &pwfb->Base, &pwfb->Base);else_mesa_make_current(NULL, NULL, NULL); }?

第1596行至第1602行,顯然在確認hglrc與hdc是否已經是關聯的,如果是,不用做什么事直接返回即可;
第1604行查找已創建的且使用hdc的WMesaFramebuffer,若找不到則,返回NULL;
第1607處的if判斷:c(hglrc)與hdc有效,即不是要刪除,而pwfb為NULL的話,則執行第1608至1642的代碼體;
第1644行的if判斷,c(hglrc)與pwfb是否有效,若有效則調用_mesa_make_current關聯,否則用NULL參數取消關聯。

接前一文,來看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_GLif (!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); #endifif (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); #endifctx->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); #endifctx->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模塊之間還沒有交換過成員值。

執行完前面的函數之后就進入GLResize()函數,這里的它自身的源代碼如下:

// OpenGLDC.cpp 第99行至第115行 GLvoid COpenGLDC::GLResize(GLsizei nWidth, GLsizei nHeight) {// 重置OpenGL窗口大小if(nHeight == 0) // 防止被零除nHeight = 1;glViewport(0, 0, nWidth, nHeight);glMatrixMode(GL_PROJECTION); // 選擇投影矩陣glLoadIdentity(); // 重置投影矩陣gluPerspective(45.0f, // 透視角設置為45 度(GLfloat)nWidth/(GLfloat)nHeight, // 窗口的寬與高比0.6f, 100.0f); // 視野透視深度:近點.1f遠點.0fglMatrixMode(GL_MODELVIEW); // 選擇模型觀察矩陣glLoadIdentity(); }

GLResize()函數第104行呼叫glViewport,這時將轉移到viewport.c處第45行_mesa_Viewport函數:

_mesa_Viewport// viewport.c 從第44行至50行 void GLAPIENTRY _mesa_Viewport(GLint x, GLint y, GLsizei width, GLsizei height) {GET_CURRENT_CONTEXT(ctx);ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);_mesa_set_viewport(ctx, x, y, width, height); }

第47行宏替換,即取_glapi_Context的值賦給聲明的GLcontext類型的ctx變量。
第48行處,則是斷言檢查,要求保證本函數在glBegin()/glEnd()之外使用,并且立即輸出還存在緩沖區的頂點FLUSH_VERTICES;
第49行調用_mesa_set_viewport正式處理需求glViewport需求;

_mesa_set_viewportvoid _mesa_set_viewport(GLcontext *ctx, GLint x, GLint y,GLsizei width, GLsizei height) {if (MESA_VERBOSE & VERBOSE_API)_mesa_debug(ctx, "glViewport %d %d %d %d\n", x, y, width, height);if (width < 0 || height < 0) {_mesa_error(ctx, GL_INVALID_VALUE,"glViewport(%d, %d, %d, %d)", x, y, width, height);return;}/* clamp width and height to the implementation dependent range */width = MIN2(width, (GLsizei) ctx->Const.MaxViewportWidth);height = MIN2(height, (GLsizei) ctx->Const.MaxViewportHeight);ctx->Viewport.X = x;ctx->Viewport.Width = width;ctx->Viewport.Y = y;ctx->Viewport.Height = height;ctx->NewState |= _NEW_VIEWPORT;#if 1/* XXX remove this someday. Currently the DRI drivers rely on* the WindowMap matrix being up to date in the driver's Viewport* and DepthRange functions.*/_math_matrix_viewport(&ctx->Viewport._WindowMap,ctx->Viewport.X, ctx->Viewport.Y,ctx->Viewport.Width, ctx->Viewport.Height,ctx->Viewport.Near, ctx->Viewport.Far,ctx->DrawBuffer->_DepthMaxF); #endifif (ctx->Driver.Viewport) {/* Many drivers will use this call to check for window size changes* and reallocate the z/stencil/accum/etc buffers if needed.*/ctx->Driver.Viewport(ctx, x, y, width, height);} }

第79行起開始設置新的VIEWPORT參數到ctx->Viewport,并寫入狀態_NEW_VIEWPORT;
第90行起調用_math_matrix_viewport來計算視口矩陣,計算公式為暫記在本子上;
第101行調用ctx所指向的Driver驅動Viewport函數地址指針,即wmesa.c里的wmesa_viewport函數,具體做一些重設幀緩存區大小之類的工作吧;

_math_matrix_viewport計算視口矩陣公式:以列為矩陣即第一行元素地址 0??? 4???? 8???? 12
[?? width / 2?????? 0???????????? 0?????????????????????????????????????????????? width /2 + x? ]
[?????? 0????????? height / 2???? 0?????????????????????????????????????????????? height /2 + y? ]
[?????? 0????????????? 0??????????? depthMax * (zFar – zNear) / 2 0?? depthMax * (zFar – zNear) / 2 0 + zNear]
[?????? 0????????????? 0???????? 0?????????????????????????????????????????????????? 0 ]

glViewport執行之后,就開始glMatrixMode(GL_PROJECTION);語句的執行了,在matrix.c第146行處的_mesa_MatrixMode:

_mesa_MatrixMode// matrix.c 從第145行至228行 void GLAPIENTRY _mesa_MatrixMode( GLenum mode ) {GET_CURRENT_CONTEXT(ctx);ASSERT_OUTSIDE_BEGIN_END(ctx);if (ctx->Transform.MatrixMode == mode && mode != GL_TEXTURE)return;FLUSH_VERTICES(ctx, _NEW_TRANSFORM);switch (mode) {case GL_MODELVIEW:ctx->CurrentStack = &ctx->ModelviewMatrixStack;break;case GL_PROJECTION:ctx->CurrentStack = &ctx->ProjectionMatrixStack;break;case GL_TEXTURE:/* This error check is disabled because if we're called from* glPopAttrib() when the active texture unit is >= MaxTextureCoordUnits* we'll generate an unexpected error.* From the GL_ARB_vertex_shader spec it sounds like we should instead* do error checking in other places when we actually try to access* texture matrices beyond MaxTextureCoordUnits.*/ #if 0if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureCoordUnits) {_mesa_error(ctx, GL_INVALID_OPERATION, "glMatrixMode(invalid tex unit %d)",ctx->Texture.CurrentUnit);return;} #endifASSERT(ctx->Texture.CurrentUnit < Elements(ctx->TextureMatrixStack));ctx->CurrentStack = &ctx->TextureMatrixStack[ctx->Texture.CurrentUnit];break;case GL_COLOR:ctx->CurrentStack = &ctx->ColorMatrixStack;break;case GL_MATRIX0_NV:case GL_MATRIX1_NV:case GL_MATRIX2_NV:case GL_MATRIX3_NV:case GL_MATRIX4_NV:case GL_MATRIX5_NV:case GL_MATRIX6_NV:case GL_MATRIX7_NV:if (ctx->Extensions.NV_vertex_program) {ctx->CurrentStack = &ctx->ProgramMatrixStack[mode - GL_MATRIX0_NV];}else {_mesa_error( ctx, GL_INVALID_ENUM, "glMatrixMode(mode)" );return;}break;case GL_MATRIX0_ARB:case GL_MATRIX1_ARB:case GL_MATRIX2_ARB:case GL_MATRIX3_ARB:case GL_MATRIX4_ARB:case GL_MATRIX5_ARB:case GL_MATRIX6_ARB:case GL_MATRIX7_ARB:if (ctx->Extensions.ARB_vertex_program ||ctx->Extensions.ARB_fragment_program) {const GLuint m = mode - GL_MATRIX0_ARB;if (m > ctx->Const.MaxProgramMatrices) {_mesa_error(ctx, GL_INVALID_ENUM,"glMatrixMode(GL_MATRIX%d_ARB)", m);return;}ctx->CurrentStack = &ctx->ProgramMatrixStack[m];}else {_mesa_error( ctx, GL_INVALID_ENUM, "glMatrixMode(mode)" );return;}break;default:_mesa_error( ctx, GL_INVALID_ENUM, "glMatrixMode(mode)" );return;}ctx->Transform.MatrixMode = mode; }

第151行處檢查如果當前的模式正好匹配,而且不是紋理模式的話,即可返回,不需要重復做事;
第155行根據當前mode的設定值,設定當前所要操作的矩陣棧,當前只需要對投影矩陣棧和模型視圖矩陣棧有所了解即可;
第227行設定ctx->Transform.MatrixMode表征當前的矩陣模式;

然后開始OpenGLDC.cpp里第107行的glLoadIdentity();語句執行,對應在matrix.c第319行處的_mesa_LoadIdentity()函數:

_mesa_LoadIdentity// matrix 從第318行至329行 void GLAPIENTRY _mesa_LoadIdentity( void ) {GET_CURRENT_CONTEXT(ctx);ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);if (MESA_VERBOSE & VERBOSE_API)_mesa_debug(ctx, "glLoadIdentity()");_math_matrix_set_identity( ctx->CurrentStack->Top );ctx->NewState |= ctx->CurrentStack->DirtyFlag; }

第327行調用_math_matrix_set_identity函數將當前矩陣棧頂矩陣設為Identity矩陣,它在m_matrix.c的第1142行處,采取MEMCPY內存拷貝的形式將一個Identity矩陣的數據拷貝至GLmatrix矩陣;

然后就是OpenGLDC.cpp的第109行處的gluPerspective語句了,這是屬于glu工程的發布函數,在project.c第65行處的gluPerspective位置,其矩陣計算暫時記在本子里,然后使用gluMultMatrixd將矩陣乘至當前的矩陣棧頂ctx->CurrentStack->Top;

gluPerspective視圖投影矩陣計算公式:
[ cos(fovy / 2) / (sin(fovy / 2) * aspect)?????? 0????????????? 0?????????? 0]

[ 0????? cos(fovy/2)/sin(fovy/2)???????????? 0????????????????????????????????? 0]

[ 0??????????????? 0????? -(zFar + zNear) / (zFar – zNear)??? -(2*zFar*zNear)/(zFar - zNear)]

[ 0??????????????? 0???????????????????????????????? -1????????????????????????????????? 0]

然后再執行OpenGLDC.cpp的第113行處glMatrixMode(GL_MODELVIEW);它將當前矩陣棧ctx->CurrentStack指向ModelviewMatrixStack,然后接下來的glLoadIdentity會使棧頂矩陣重置為單位矩陣;

在GLResize()函數執行完之后,會進入GLInit執行用戶的初始化語句,但這里暫時略過這一部分的內容。
重點來看GLDrawScene()函數的調試執行:

// OpenGLDC.cpp 從第136行到161行 GLboolean COpenGLDC::GLDrawScene(GLvoid) {glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度緩存glLoadIdentity(); // 如果不添加這句,那么所畫的都會由大縮小,無法看見 //glTranslatef(-1.5f,0.0f,-6.0f); // 左移1.5 單位,并移入屏幕6.0glBegin(GL_LINE_LOOP); // 繪制三角形glColor3f(1.0f,0.0f,0.0f); // 設置當前色為紅色glVertex3f( 0.0f, 1.0f, 0.0f); // 上頂點glColor3f(0.0f,1.0f,0.0f); // 設置當前色為綠色glVertex3f(-1.0f,-1.0f, 0.0f); // 左下glColor3f(0.0f,0.0f,1.0f); // 設置當前色為藍色glVertex3f( 1.0f,-1.0f, 0.0f); // 右下glEnd(); // 三角形繪制結束glTranslatef(3.0f,0.0f,0.0f); // 右移單位glColor3f(0.5f,0.5f,1.0f); // 一次性將當前色設置為藍色glBegin(GL_QUADS); // 繪制正方形glVertex3f(-1.0f, 1.0f, 0.0f); // 左上glVertex3f( 1.0f, 1.0f, 0.0f); // 右上glVertex3f( 1.0f,-1.0f, 0.0f); // 左下glVertex3f(-1.0f,-1.0f, 0.0f); // 右下glEnd(); // 正方形繪制結束 //SwapBuffers(m_hDC); // 切換緩沖區,沒有切換的話,窗口不會繪制什么return true; }

首先是glClear語句,此語句關聯clear.c里第112行處的_mesa_Clear函數,它做了不少事情,但當下并非我注意的重點對象,因為我還不大明白自己要去關注什么。收集一下當下可能需要的關注方向:
(1) 在_mesa_update_state_locked里調用的_mesa_update_modelview_project計算模型視圖投影矩陣;需要了解一下ctx->Transform與cull position有關的成員;后面會計算ctx->_ModelProjectMatrix,因為此時的ModelViewMatrixStack.Top為單位矩陣,所以結果就是投影矩陣;
(2) 該處也會調用update_viewport_matrix函數;
(3) 最后會調用ctx所帶驅動函數地址處記錄的Clear,即wmesa.c處第289行的clear函數;

再就是glLoadIdentity();語句的執行,前面已經看到過兩次了,因為此時矩陣模式還時GL_MODELVIEW,所以它執行的結果就是將ctx->ModelviewMatrixStack重置為單位矩陣;

接下來就是glTranslatef(-1.5f, 0.0f, -6.0f);語句,它對應執行matrix.c里第454行處的_mesa_Translatef函數,它的重點是檢查是否需要做一點別的事情,然后調用_math_matrix_translate來完成平移矩陣,因為前面為單位矩陣,而這里僅僅修改矩陣的平移項:

最后是重頭戲,glBegin()/glEnd()以及在它們之間調用的函數。

glBegin()函數首先由ctx->Exec所指向的函數指針轉移至neutral_Begin,neutral_Begin由宏包裹著,展開之后將是這樣的語句:

static void __stdcall neutral_Begin( GLenum mode ) {{ GLcontext *ctx = (GLcontext *) _glapi_Context; struct gl_tnl_module * const tnl = &(ctx->TnlModule); const int tmp_offset = 7 ;; ; ; if (tnl->SwapCount == 0) ctx->Driver.BeginVertices( ctx ); tnl->Swapped[tnl->SwapCount].location = & (((_glapi_proc *)ctx->Exec)[tmp_offset]); tnl->Swapped[tnl->SwapCount].function = (_glapi_proc)neutral_Begin; tnl->SwapCount++; if ( 0 ) _mesa_debug(ctx, " swapping gl" "Begin""...\n" ); ((ctx->Exec)->Begin = tnl->Current->Begin); };(*((_glapi_Dispatch)->Begin)) ( mode ); }

執行過程是這樣的,如果是首次被調用,則會通過ctx->Driver來調用BeginVertices(即vbo_exec_api.c里第750行處的vbo_exec_BeginVertices),然后在tnl模塊的Swapped處記錄交交換的函數地址,從而將vbo_exec_Begin換至當前ctx->Exec處的對應glBegin函數指針位置處,然后調用vbo_exec_Begin;這就是neutral_Begin的執行過程。

vbo_exec_BeginVertices函數的執行過程,暫略。

vbo_exec_Begin函數的執行過程,在vbo_exec_api.c第492行處:

vbo_exec_Begin// vbo_exec_api.c 從第492行至532行 static void GLAPIENTRY vbo_exec_Begin( GLenum mode ) {GET_CURRENT_CONTEXT( ctx ); if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {struct vbo_exec_context *exec = &vbo_context(ctx)->exec;int i;if (ctx->NewState) {_mesa_update_state( ctx );CALL_Begin(ctx->Exec, (mode));return;}if (!_mesa_valid_to_render(ctx, "glBegin")) {return;}/* Heuristic: attempt to isolate attributes occuring outside* begin/end pairs.*/if (exec->vtx.vertex_size && !exec->vtx.attrsz[0]) vbo_exec_FlushVertices_internal( ctx, GL_FALSE );i = exec->vtx.prim_count++;exec->vtx.prim[i].mode = mode;exec->vtx.prim[i].begin = 1;exec->vtx.prim[i].end = 0;exec->vtx.prim[i].indexed = 0;exec->vtx.prim[i].weak = 0;exec->vtx.prim[i].pad = 0;exec->vtx.prim[i].start = exec->vtx.vert_count;exec->vtx.prim[i].count = 0;ctx->Driver.CurrentExecPrimitive = mode;}else _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );}

第496行處檢查是否在glBegin()/glEnd()之外調用,如果不是,則調用_mesa_error函數非法操作;
第500行處檢查是否有新的狀態變化,發現有ctx->NewState,則調用_mesa_update_state來更新狀態,這個函數就是先前glClear也會調用來更新狀態的那個函數,然后再調用一次vbo_exec_Begin之后退出程序;
實際上更新狀態之后的調用與沒有狀態時的調用除了前者會調用狀態更新函數之外,其余部分沒有區別,從第514行起到第527行處的代碼語句都要執行。
這就是glBegin()的執行過程。

glColor3f(1.0f, 0.0f, 0.0f);語句的對應執行流程,與glBegin()一樣經過ctx->Exec指向對應的neutral_Color3f函數,該函數被包裹在宏的聲明里,展開之后的語句是這樣的:

neutral_Color3f// vtxfmt.c 包含vtxfmt_tmp.h展開宏而產生 static void __stdcall neutral_Color3f( GLfloat r, GLfloat g, GLfloat b ) {{ GLcontext *ctx = (GLcontext *) _glapi_Context; struct gl_tnl_module * const tnl = &(ctx->TnlModule); const int tmp_offset = 13 ; ; ; ; if (tnl->SwapCount == 0) ctx->Driver.BeginVertices( ctx ); tnl->Swapped[tnl->SwapCount].location = & (((_glapi_proc *)ctx->Exec)[tmp_offset]); tnl->Swapped[tnl->SwapCount].function = (_glapi_proc)neutral_Color3f; tnl->SwapCount++; if ( 0 ) _mesa_debug(ctx, " swapping gl" "Color3f""...\n" ); ((ctx->Exec)->Color3f = tnl->Current->Color3f); };(*((_glapi_Dispatch)->Color3f)) ( r, g, b ); }

樣式與neutral_Begin差不多,畢竟是同一批宏展開。這里不會再執行ctx->Driver.BeginVertices,記錄使用過的函數地址之后,轉而執行vbo_Color3f。

vbo_Color3f// vbo_exec_api.c 通過包含vbo_attrib_tmp.h頭文件產生 static void __stdcall vbo_Color3f( GLfloat x, GLfloat y, GLfloat z ) {GLcontext *ctx = (GLcontext *) _glapi_Context;do { struct vbo_exec_context *exec = &vbo_context(ctx)->exec; if (exec->vtx.active_sz[VBO_ATTRIB_COLOR0] != 3) vbo_exec_fixup_vertex(ctx, VBO_ATTRIB_COLOR0, 3); { GLfloat *dest = exec->vtx.attrptr[VBO_ATTRIB_COLOR0]; if (3>0) dest[0] = x; if (3>1) dest[1] = y; if (3>2) dest[2] = z; if (3>3) dest[3] = 1; } if ((VBO_ATTRIB_COLOR0) == 0) { GLuint i; for (i = 0; i < exec->vtx.vertex_size; i++) exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; exec->vtx.buffer_ptr += exec->vtx.vertex_size; exec->ctx->Driver.NeedFlush |= 0x1; if (++exec->vtx.vert_count >= exec->vtx.max_vert) vbo_exec_vtx_wrap( exec ); } } while (0); }

第4行獲取vbo_exec_context指針;
第5行比對exec->vtx.active_sz[VBO_ATTRIB_COLOR0]是否等于3,若不等于3,則要修正頂點數據,在第一次調用這個函數時,該值為0,故會執行該函數;

?

而glVertex3f(0.0f, 1.0f, 0.0f);語句呢,也基本與glColor3f相似,其中neutral_Vertex3f對應的源代碼如下:

neutral_Vertex3fstatic void __stdcall neutral_Vertex3f( GLfloat x, GLfloat y, GLfloat z ) {{ GLcontext *ctx = (GLcontext *) _glapi_Context; struct gl_tnl_module * const tnl = &(ctx->TnlModule); const int tmp_offset = 136 ; ; ; ; if (tnl->SwapCount == 0) ctx->Driver.BeginVertices( ctx ); tnl->Swapped[tnl->SwapCount].location = & (((_glapi_proc *)ctx->Exec)[tmp_offset]); tnl->Swapped[tnl->SwapCount].function = (_glapi_proc)neutral_Vertex3f; tnl->SwapCount++; if ( 0 ) _mesa_debug(ctx, " swapping gl" "Vertex3f""...\n" ); ((ctx->Exec)->Vertex3f = tnl->Current->Vertex3f); };(*((_glapi_Dispatch)->Vertex3f)) ( x, y, z ); }

?

該函數執行后,會轉至vbo_Vertex3f函數執行:

vbo_Vertex3fstatic void __stdcall vbo_Vertex3f( GLfloat x, GLfloat y, GLfloat z ) {GLcontext *ctx = (GLcontext *) _glapi_Context;do { struct vbo_exec_context *exec = &vbo_context(ctx)->exec; if (exec->vtx.active_sz[VBO_ATTRIB_POS] != 3) vbo_exec_fixup_vertex(ctx, VBO_ATTRIB_POS, 3); { GLfloat *dest = exec->vtx.attrptr[VBO_ATTRIB_POS]; if (3>0) dest[0] = x; if (3>1) dest[1] = y; if (3>2) dest[2] = z; if (3>3) dest[3] = 1; } if ((VBO_ATTRIB_POS) == 0) { GLuint i; for (i = 0; i < exec->vtx.vertex_size; i++) exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i];exec->vtx.buffer_ptr += exec->vtx.vertex_size; exec->ctx->Driver.NeedFlush |= 0x1; if (++exec->vtx.vert_count >= exec->vtx.max_vert) vbo_exec_vtx_wrap( exec ); } } while (0); }

其執行與前面vbo_Color3f相似,但這里我一直弄不大清楚到底數據存儲到哪里去了呢?而程序在后面又是怎樣找到這些存儲的數據呢?

再一次重復執行glColor3f和glVertex3f時,因為前面已經登記交換函數地址,所以會直接轉到vbo_Color3f和vbo_Vertex3f執行,與前類似。

最后是glEnd();語句的執行,與前類似,首先是neutral_End:

neutral_Endstatic void __stdcall neutral_End( void ) {{ GLcontext *ctx = (GLcontext *) _glapi_Context; struct gl_tnl_module * const tnl = &(ctx->TnlModule); const int tmp_offset = 43 ; ; ; ; if (tnl->SwapCount == 0) ctx->Driver.BeginVertices( ctx ); tnl->Swapped[tnl->SwapCount].location = & (((_glapi_proc *)ctx->Exec)[tmp_offset]); tnl->Swapped[tnl->SwapCount].function = (_glapi_proc)neutral_End; tnl->SwapCount++; if ( 0 ) _mesa_debug(ctx, " swapping gl" "End""...\n" ); ((ctx->Exec)->End = tnl->Current->End); };(*((_glapi_Dispatch)->End)) (); }

不像neutral_Begin()在之前還要執行ctx->Driver.BeginVertices,neutral_End()首先會登記交換函數地址,然后轉移至vbo_exec_End執行。

vbo_exec_Endstatic void GLAPIENTRY vbo_exec_End( void ) {GET_CURRENT_CONTEXT( ctx ); if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {struct vbo_exec_context *exec = &vbo_context(ctx)->exec;int idx = exec->vtx.vert_count;int i = exec->vtx.prim_count - 1;exec->vtx.prim[i].end = 1; exec->vtx.prim[i].count = idx - exec->vtx.prim[i].start;ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;if (exec->vtx.prim_count == VBO_MAX_PRIM)vbo_exec_vtx_flush( exec, GL_FALSE );}else _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" ); }

vbo_exec_End只會記錄消息,除非數據滿了,否則不會刷新數據。

從當前的GLDrawScene()執行過程來看,第一個glBegin()/glEnd()之后不會立即刷新,但由于接下來的glTranslatef(3.0f, 0.0f, 0.0f);因為模型視圖矩陣的變更會觸導數據刷新。而來具體的過程來看,都是通過vbo_exec_vtx_flush函數來完成的。而這將是后續分析的起點。

?

vbo_exec_vtx_flush定義在vbo_exec_draw.c第353行處,具體代碼如下:

vbo_exec_vtx_flush// vbo_exec_draw.c 從第349行至417行 /*** Execute the buffer and save copied verts.*/ void vbo_exec_vtx_flush( struct vbo_exec_context *exec, GLboolean unmap ) {if (0)vbo_exec_debug_verts( exec );if (exec->vtx.prim_count && exec->vtx.vert_count) {exec->vtx.copied.nr = vbo_copy_vertices( exec ); if (exec->vtx.copied.nr != exec->vtx.vert_count) {GLcontext *ctx = exec->ctx;/* Before the update_state() as this may raise _NEW_ARRAY* from _mesa_set_varying_vp_inputs().*/vbo_exec_bind_arrays( ctx );if (ctx->NewState)_mesa_update_state( ctx );if (_mesa_is_bufferobj(exec->vtx.bufferobj)) {vbo_exec_vtx_unmap( exec );}if (0)_mesa_printf("%s %d %d\n", __FUNCTION__, exec->vtx.prim_count,exec->vtx.vert_count);vbo_context(ctx)->draw_prims( ctx, exec->vtx.inputs, exec->vtx.prim, exec->vtx.prim_count,NULL,GL_TRUE,0,exec->vtx.vert_count - 1);/* If using a real VBO, get new storage -- unless asked not to.*/if (_mesa_is_bufferobj(exec->vtx.bufferobj) && !unmap) {vbo_exec_vtx_map( exec );}}}/* May have to unmap explicitly if we didn't draw:*/if (unmap && _mesa_is_bufferobj(exec->vtx.bufferobj) &&exec->vtx.buffer_map) {vbo_exec_vtx_unmap( exec );}if (unmap || exec->vtx.vertex_size == 0)exec->vtx.max_vert = 0;elseexec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) / (exec->vtx.vertex_size * sizeof(GLfloat)));exec->vtx.buffer_ptr = exec->vtx.buffer_map;exec->vtx.prim_count = 0;exec->vtx.vert_count = 0; }

第382行是開始準備進入管道繪制處的語句,具體對應t_draw.c第363行處的_tnl_vbo_draw_prims,然后到達_tnl_draw_prims函數;

_tnl_draw_prims// t_draw.c 從第378行到450行 /* This is the main entrypoint into the slimmed-down software tnl* module. In a regular swtnl driver, this can be plugged straight* into the vbo->Driver.DrawPrims() callback.*/ void _tnl_draw_prims( GLcontext *ctx,const struct gl_client_array *arrays[],const struct _mesa_prim *prim,GLuint nr_prims,const struct _mesa_index_buffer *ib,GLuint min_index,GLuint max_index) {TNLcontext *tnl = TNL_CONTEXT(ctx);const GLuint TEST_SPLIT = 0;const GLint max = TEST_SPLIT ? 8 : tnl->vb.Size - MAX_CLIPPED_VERTICES;if (0){GLuint i;_mesa_printf("%s %d..%d\n", __FUNCTION__, min_index, max_index);for (i = 0; i < nr_prims; i++)_mesa_printf("prim %d: %s start %d count %d\n", i, _mesa_lookup_enum_by_nr(prim[i].mode),prim[i].start,prim[i].count);}if (min_index) {/* We always translate away calls with min_index != 0. */vbo_rebase_prims( ctx, arrays, prim, nr_prims, ib, min_index, max_index,_tnl_vbo_draw_prims );return;}else if (max_index > max) {/* The software TNL pipeline has a fixed amount of storage for* vertices and it is necessary to split incoming drawing commands* if they exceed that limit.*/struct split_limits limits;limits.max_verts = max;limits.max_vb_size = ~0;limits.max_indices = ~0;/* This will split the buffers one way or another and* recursively call back into this function.*/vbo_split_prims( ctx, arrays, prim, nr_prims, ib, 0, max_index,_tnl_vbo_draw_prims,&limits );}else {/* May need to map a vertex buffer object for every attribute plus* one for the index buffer.*/struct gl_buffer_object *bo[VERT_ATTRIB_MAX + 1];GLuint nr_bo = 0;/* Binding inputs may imply mapping some vertex buffer objects.* They will need to be unmapped below.*/bind_inputs(ctx, arrays, max_index+1, bo, &nr_bo);bind_indices(ctx, ib, bo, &nr_bo);bind_prims(ctx, prim, nr_prims );TNL_CONTEXT(ctx)->Driver.RunPipeline(ctx);unmap_vbos(ctx, bo, nr_bo);free_space(ctx);} }

實際執行時只會執行第431行起的else {}代碼塊,而第445行處的TNL_CONTEXT(ctx)->Driver.RunPipeline(ctx);是正式的進入管道的入口語句,它對應在t_pipeline.c第121行處的_tnl_run_pipeline。

_tnl_run_pipeline// t_pipeline.c 從第121行至162行 void _tnl_run_pipeline( GLcontext *ctx ) {TNLcontext *tnl = TNL_CONTEXT(ctx);unsigned short __tmp;GLuint i;if (!tnl->vb.Count)return;/* Check for changed input sizes or change in stride to/from zero* (ie const or non-const).*/if (check_input_changes( ctx ) || tnl->pipeline.new_state) {if (ctx->VertexProgram._MaintainTnlProgram)_tnl_UpdateFixedFunctionProgram( ctx );for (i = 0; i < tnl->pipeline.nr_stages ; i++) {struct tnl_pipeline_stage *s = &tnl->pipeline.stages[i];if (s->validate)s->validate( ctx, s );}tnl->pipeline.new_state = 0;tnl->pipeline.input_changes = 0;/* Pipeline can only change its output in response to either a* statechange or an input size/stride change. No other changes* are allowed.*/if (check_output_changes( ctx ))_tnl_notify_pipeline_output_change( ctx );}START_FAST_MATH(__tmp);for (i = 0; i < tnl->pipeline.nr_stages ; i++) {struct tnl_pipeline_stage *s = &tnl->pipeline.stages[i];if (!s->run( ctx, s ))break;}END_FAST_MATH(__tmp); }

?

其中對應的管道結構變量是:

const struct tnl_pipeline_stage *_tnl_default_pipeline[] = {&_tnl_vertex_transform_stage,&_tnl_normal_transform_stage,&_tnl_lighting_stage,&_tnl_texgen_stage,&_tnl_texture_transform_stage,&_tnl_point_attenuation_stage,&_tnl_vertex_program_stage, &_tnl_fog_coordinate_stage,&_tnl_render_stage,NULL };

由上可見首先計算頂點,然后變換,再光照等等,最后運行渲染。

?

好久沒有寫博客,同時也放下對mesa源碼的閱讀很久了。這一篇會是我最后的一篇,有不盡到之處也會放下了,畢竟OpenGL不是我的強項,后面可能沒有這么多時間來關注了。

這篇文章有點長,而我也不知道自己究竟說清楚了沒有,放在這里,一方面是作為自己閱讀的一個總結,另一方面也期望它能夠對人有所助益。

?

0? 數據結構的預備

1) __GLcontextRect

__GLcontextRect 也被定義為 GLcontext

Mesa rendering context,在這個數據結構里幾乎包括所有的OpenGL狀態

?

struct gl_transform_attrib Transform; 對應Transformation屬性

?

struct gl_viewport_attrib Viewport; 對應Viewprt屬性,glViewport()負責初始化它

?

struct gl_matrix_stack ModelviewMatrixStack;

struct gl_matrix_stack ProjectionMatrixStack;

struct gl_matrix_stack ColorMatrixStack;

struct gl_matrix_stack TextureMatrixStack[MAX_TEXTURE_UNITS];

struct gl_matrix_stack ProgramMatrixStack[MAX_PROGRAM_MATRICES];

struct gl_matrix_stack *CurrentStack; // 指向上面矩陣堆棧中的一個

?

GLmatrix _ModelProjectMatrix; // 聯合模型視圖矩陣與投影矩陣

?

2) wmesa_context? 與? wmesa_framebuffer

wmesa_context // The Windows Mesa rendering context, derived from GLcontext;

它存儲與Windows窗口有關的數據成員,除GLcontext之外,比如HDC, 清除顏色,清除畫筆,清除畫刷等等

?

wmeas_framebuffer // Windows framebuffer, derived from gl_framebuffer

除gl_framebuffer之外,窗口句柄,像素格式,顏色位數,位圖,以及像素指針,下一wmesa_framebuffer*next指針等等

?

真正地像素顏色等數據會存儲在這里,因而也就比較與平臺相關,而GLcontext則是能夠比較獨立于平臺的,如何做到的呢,依靠這里的數據結構了吧。

?

GLvisual 亦即 __GLcontextModesRes 看起來它是支持很多渲染模式的,比如RGB,累積緩存,深度緩存,各種GLX, ARB擴展等等,這個暫時不管它

?

dd_function_table Mesa內核使用這些函數指針以呼叫設備驅動,許多函數直接對應OpenGL狀態命令,Mesa內核會在完成錯誤檢查之后再調用它們,所以驅動不用再檢查

?

頂點transformation/clipping/lighting存放入 T&L模塊

Rasterization光柵化函數存放入 swrast模塊

?

3)? glapi_table

gdi項目下的 mesa.def 對應 OpenGL.dll 輸出的API函數列表,該列表與 glapi_table 很能對應上

_glapi_set_dispatch()? 是對應的設置捆綁接應函數,比如 對上? __glapi_noop_table 可表征空操作

_mesa_init_exec_table() 是對應的初始化 glBegin()/glEnd() 之間的函數

?

mesa里實現gl*的API函數是比較獨特的,通過宏替換的形式來進行。未初始化的時候,對應的都是空的函數體,在wglMakeCurrent()里才會被初始化。

?

1 前面的測試工程,調試后可發現其基本的執行流程如下:

(1) 窗口WM_CREATE之后調用 GLSetupRC(),此時也可以進行那些屬于一次性的初始化GLInit()

ChoosePixelFormat()

SetPixelFormat()

wglCreateContext

wglMakeCurrent()

(2) 窗口WM_SIZE消息處調用? GLResize()

glViewport()

glMatrixMode()

glLoadIdentity()

gluPerspective()

glMatrixMode()

glLoadIdentity()

(3) 在消息循環之外調用? GLDrawScene() 繪制

glClear()

glLoadIdentity()

glTranslatef()

glBegin()

??? glColor3f()

??? glVertex3f()

glEnd()

SwapBuffers()

(4) 退出窗口之前銷毀該銷毀的

略過

?

2 GLSetupRC() 處的執行流程

函數 wglCreateContext()

1) 若當前無有效Ctx數量,則初始化所有 wgl_ctx[i].ctx 為NULL

2) 循環遍歷所有 wgl_ctx[i],發現一個空的,則調用 WMesaCreateContext() 創建,若創建成功,則 ctx_count += 1,然后返回該句柄 HGLRC 形式

WMesaCreateContext()

1) 申請wmesa_context內存空間,然后初始化窗口句柄,像素位數,GLvisual(暫不理會)等

2) 調用 _mesa_init_driver_functions() 初始化驅動函數指針 dd_function_table 類型

3) 調用 _mesa_initialize_context() 初始化 GLcontext(這是一個重要類型)

4) 啟用一些擴展,暫時忽略

5) 初始化 software rasterizer and helper module, 四個模塊的初始化,重要!

6) 管道初始化,重要,_tnl_run_pipeline

7) 返回

?

_mesa_initialize_context()

1) 賦值初始化一些成員 GLcontext

2) share_list 的申請,(不大明白,暫時忽略處理)

3) 調用 init_attrib_groupd() 重要函數,會初始化很多東西,比如 buffer_objects, color, eval, depth, line, matrix, pixel, point, polygon, program, scissor, transform, viewport 等等

4) 申請內存空間,并初始化 ctx->Exec, ctx->Save,這個與glBegin(), glEnd() 有關

5) 再調用 _mesa_init_exec_vtxfmt() 初始化 Neutral tnl module stuff,與頂點有關的API了

6) 返回

?

wglMakeCurrent()

1) 檢查若二者當中有一個為NULL,則調用 WMesaMakeCurrent(NULL, NULL))

2) 否則找到對應的句柄,必須能找到,否則失敗,再調用 WMesaMakeCurrent()

?

WMesaMakeCurrent()

1) 如果hDC與hRC二者已經有關聯,不用做什么退出即可

2) 尋找對應 hDC 的 WMesaFramebuffer

3) 如果hDC, hRC有效,卻沒有framebuffer,則進入以下步驟創建

==> 1) 獲取窗口大小

==> 2) 調用 wmesa_new_framebuffer() 創建 WMesaFramebuffer

==> 3) 如果為雙緩存,還要創建 back buffer

==> 4) 然后make render buffers,在wmesa_set_renderbuffer_funcs()處應該注意,它初始化了讀寫像素的函數指針,比如rb->PutRow(), rb->PutRowRGB(), rb->PutMonoRow(), rb->PutValues(), rb->PubMonoValues(), rb->GetRow(), rb->GetValues() 可以從后面看出,這些函數指針完成對渲染場景像素的讀寫

雙緩存的時候,會建二個render buffers, 目前還沒有精力去關注這一方面的內容

==> 5) _mesa_add_soft_renderbuffers() 添加深度緩存,累積緩存,模板

4) 上一步之后,若hRC與framebuffer有效,則傳遞相關參數,調用 _mesa_make_current()

5) 若以上均不符合,則判定為取消置為當前,傳遞NULL,調用 _mesa_make_current()

?

_mesa_make_current()

1) 若傳入的為有效值(非空),則檢查newCtx與drawBuffer, readBuffer之間的兼容性

2) 若可行,則置全局變量 _glapi_Context 值(該值會到處被用到),否則的話會置空

3) 還有對 _glapi_set_dispatch() (它直接對應OpenGL各API函數的) 的初始化,若有效,置各函數指針 newCtx->CurrentDispatch 指針,最后初始化各種 framebuffer size,主要是drawBuffer, readBuffer這兩個

4) 后面還有一些初始化,默認也包括了 _mesa_set_viewport() _mesa_set_scissor 函數等

?

3 GLResize() 處的執行流程

注意:m_matrix.c 文件里的注釋

-- # 4x4 變換矩陣以列為優先存儲

-- # 點/頂點被認為是列矢量

-- # 點經矩陣的變換是 p' = M * p

glViewport()

1) 經過函數指針分派轉至 _mesa_Viewport()

2) 獲取當前 context

3) 確認是否在 glBegin(), glEnd() 外部使用

4) 調用 _mesa_set_viewport()

?

_mesa_set_viewport()

1) 在最大可能 MaxViewportWidth, MaxViewportHeigth 與給定值之間取最小值

2) 賦值改變 ctx->Viewport 參數,并置新狀態 _NEW_VIEWPORT

3) 調用 _math_matrix_viewport() 初始化 ctx->Viewport._WindowMap

glViewport(0, 0, nWidth, nHeight)轉換ctx->Viewport._WindowMap矩陣為

width/2?? 0???????????? 0???? width/2 + x

0?????? height/2??????? 0???? height/2 + y

0?????????? 0??? depthMax*((zFar - zNear)/2)?? depthMax*((zFar - zNear)/2 + zNear)

0?????????? 0????????????? 0?????????? 1

其中(x, y, width, height)對應上面函數的參數

zNear/zFar對應ctx->Viewport.Near/Far,初始值為0.0/1.0

depthMax值等于ctx->DrawBuffer->_DepthMaxF,該值初始值為65535.0

320? 0??? 0?? 320

0?? 240?? 0?? 240

0???? 0 32767.5 32767.5

0???? 0???? 0??? 1

以列為優先存儲的方式,故矩陣 0, 1, 2, 3 4, 5, 6, 7, 8,9,10,11, 12, 13, 14, 15內部值為

{ 320, 0, 0, 0, 0, 240, 0, 0, 0, 0, 32767.5, 0 320, 240, 32767.5, 1 }

4) 若存在驅動.Viewport,則調用它,對應 wmesa_viewport() 它負責resize_buffers()

?

glMatrixMode()

1) 經過函數指針分派轉至 _mesa_MatrixMode()

2) 獲取當前的 context

3) 確保在Begin與End() 之外使用,這個范圍跟 glViewport() 有差別,但具體怎樣暫時忽略

4) 如果ctx->Transform.MatrixMode已為給定模式,并且給定模式不等于 GL_TEXTURE,退出,不需要后面的處理

5) 因為 _NEW_TRANSFORM特性,需要完成以前的繪制,如果存在的話,FLUSH_VERTICES

6) 置 ctx->CurrentStack 為對應模式的矩陣堆棧,比如投影矩陣堆棧,模型視圖堆棧

7) 改變 ctx->Transform.MatrixMode 為給定模式

8) 返回

?

glLoadIdentity()

1) 經過函數指針分派轉至 _mesa_LoadIdentity()

2) 獲取當前的 context

3) 確保在Begin, End, Flush之外使用本函數

4) 調用 _math_matrix_set_identity() 置 ctx->CurrentStack->Top 指針為單位矩陣

5) 給 ctx->NewState 添加新狀態,后面會根據這個來調用相關的初始化函數

?

gluPerspective()

這個是glu里面的函數,設置透視投影矩陣

double radians = fovy / 2 * __glPi / 180 = 0.392699081698...;

double deltaZ = zFar - zNear = 99.4;

矩陣各數據為:

cos(radians)/sin(radians)/aspect????? 0?????????????????? 0?????????????????? 0

0??????????????????????????????? cos(radians)/sin(radians)?? 0??????????????????? 0

0???????????????????????????????????????????????? 0??? -(zFar+zNear)/deltaZ??? -2*zNear*zFar/deltaZ

0???????????????????????????????????????????????? 0????????????????? -1??????????????????? 0

其中fovy = 45.0; aspect = 1.3333; zNear = 0.6; zFar = 100.0f;

1.810660171???? 0???????????? 0???????????????????? 0

0?????????? 2.41421356???????? 0???????????????????? 0

0????????????????????? 0??? -1.0120724350???? -1.2072435090

0????????????????????? 0??????????? -1???????????????????? 0

1) 調用 __gluMakeIdentityd() 初始化 m[4][4] 為單位矩陣

2) 改變 m[0][0], m[1][1], m[2][2], m[2][3], m[3][2], m[3][3] 的值

注意從這里可以看出 m[4][4] 與 OpenGL內部矩陣的存放次序是相反的, m[2][3] 對應mtx[11]位置,而m[3][2] 對應 mtx[14]位置,這一點很需要注意

{ 1.810660171 0 0 0, 0, 2.41421356 0 0, 0 0 -1.0120724350 -1, 0 0 -1.2072435090, 0 }

3) 調用 glMultMatrixd()

?

glMultMatrixd()

1) 經過函數指針分派轉至 _mesa_MultMatrixd

2) 轉換數據精度為 float型,調用 _mesa_MultMatrixf()

3) _mesa_MultMatrixf() 獲取當前ctx,確保參數有效以及被調用位置

4) 然后調用 _math_matrix_mul_floats() 將矩陣乘至 ctx->CurrentStack->Top()

矩陣相乘,以列為優先,故 A(row, col) = A[col*4 + row] 這一點同 UGOPEN 一致

5) 給 ctx->NewState 添加新狀態

?

以上已經可以完成對 GLResize() 的分析

?

4 GLDrawScene() 處場景繪制流程

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

此函數有點復雜,會完成很多事情

1) 經函數指針分派轉至 _mesa_Clear()

2) 獲取當前 context

3) 確保在Begin, End, Flush() 之外被調用

4) 完成當前場景 FLUSH_CURRENT()

5) 確保 mask 參數正確

6) 如果有新狀態ctx->NewState,則調用 _mesa_update_state() 更新

更新過程很多,這個函數復雜也就復雜在這里了,更新完后,ctx->NewState會置為0

7) 如果有DrawBuffer, ctx->DrawBuffer有效,繼續,否則退出

8) 如果渲染模式為 GL_RENDER,ctx->RenderMode的值,繼續

9) 各種緩存模式,最后調用驅動的Clear函數,對應 wmesa.c 里的clear()函數

這里也有一些復雜,不是十分清楚,它內部具體在做什么,仔細分析,里邊應該有一個環節將記錄像素顏色的地址指針全部初始化為背景顏色的過程

?

glLoadIdentity() 置當前矩陣堆棧Top為單位矩陣

?

glTranslatef()

1) 經過函數指針分派轉至 _mesa_Translatef()

2) 獲取當前 context

3) 確保在Begin, End, Flush之外調用

4) 調用 _math_matrix_translate(),它相當于一個矩陣相乘,只是平移變換矩陣只需要更新有關的那三個值而已,可以具體化為矩陣相乘效果的

m[12] = m[0] * x + m[4] * y + m[8] * z + m[12];

m[13] = m[1] * x + m[5] * y + m[9] * z + m[13];

m[14] = m[2] * x + m[6] * y + m[10] * z + m[14];

m[15] = m[3] * x + m[7] * y + m[11] * z + m[15];

從而當前模型視圖矩陣變為:

1 0 0 -1.5

0 1 0 0

0 0 1 -6

0 0 0 1

在內部的存儲很明顯是 { 1 0 0 0, 0 1 0 0, 0 0 1 0, -1.5 0 -6 1 }

5) 變換矩陣狀態,給 ctx->NewState添加新狀態

?

glBegin()

??? glColor3f()

??? glVertex3f()

glEnd()

這里的函數會走另一個指派過程,有點復雜,難以理清頭緒

小專題1) 這里相關的函數所經過的指派過程,擴而廣之,應對里邊幾乎所有地方都有一個記錄吧,還包括所有 OpenGL API 函數的指派位置

1) neutral_**前綴指派

在 vtxfmt.c 內,然后包括 vtxfmt_tmp.h頭文件 定義PRE_LOOPBACK()宏,再轉而調用當前 GET_DISPATCH() 對應的位置,而在上面的 PRE_LOOPBACK()里有對這個位置的設置與改變的,會進入到 tnl模塊

2) vbo_***前綴指派,在 vbo_exec_api.c 內,然后包括 vbo_attrib_tmp.h 暫時忽略 vbo_save_api.c 里的

在第一次執行 neutral_**之后,以后會直接轉至 vbo_**來執行

?

glBegin()

1) 經過指派,轉至 neutral_Begin() vtxfmt_tmp.h 文件內

2) 再又指派至 vbo_exec_**處執行

在這個函數里主要是記錄和模式

?

glEnd()

1) 大體類似 先 neutral_End(),再 vbo_exec_End()

2) 并不會立即進入繪制管道

?

2012/06/05 星期二

初步的認定是 neutral_**() 會去fix頂點數據格式,vbo_**() 會記錄數據

glTranslatef()

再次執行一個矩陣變換之后,會因為檢測到需要Flush了,從而調用 驅動指針 ctx->Driver.FlushVertices, 對應 vbo_exec_FlushVertices() 函數

?

vbo_exec_FlushVertices()

內部確認參數之后,轉而調用 vbo_exec_FlushVertices_internal()

可以這么說,不帶 _internal的負責對上下文環境的處理,帶_internal的職司 FlushVertices

本函數在后面還負責恢復函數指針,讓它們重新首先指向 neutral_**()

?

5 結束場景繪制,準備進入管道

glEnd()之后未必會立即轉向實際的繪制,mesa會緩存下前面已發生的指令,當下一步發現必須繪制時(比如在glEnd()之后調用glTranlate()變換視圖矩陣了)或者緩沖區已滿,才會轉入管道準備繪制。

vbo_exec_FlushVertices_internal()

1) 若存在頂點 exec->vtx.vert_count > 0 或強制要求 flush

2) 調用 vbo_exec_vtx_flush() 轉到這里去了

3) 再回復 exec內的某些成員,方便接受下一次輸入

?

vbo_exec_vtx_flush() // Execute the buffer and save copied verts

1) 若存在 prim_count 以及 vert_count,亦即調用過 glBegin(), glVertex*() 則執行以下語句

==> 調用 vbo_copy_vertices() 獲取某個指針

==> 如果與 exec->vtx.vert_count 不等則

==> ==> vbo_exec_bind_arrays()

==> ==> 若 ctx->NewState 有新狀態,則調用 _mesa_update_state() 更新之

==> ==> 若 _mesa_is_bufferobj() 則調用 vbo_exec_vtx_unmap() 調試發現這里不執行

==> ==> 調用 vbo_context(ctx)-> draw_prims() 函數,轉至 _tnl_vbo_draw_prims() 執行,然后轉至 tnl_draw_prims() 完成,開始進入管道了,在 t_draw.c 文件之內

==> 上面完成之后,從調試來看,沒再執行什么了

2) 后面恢復數據,比如 exec->vtx.buffer_ptr 指向 exec->vtx.buffer_map,以前驗證過 glVertex*()命令所操作對應的位置就是在這里的

通過以上步驟之后,就可以結束 頂點的flush() 了

?

tnl_draw_prims()

進入 軟件 tnl 模塊的最主要入口

1) 如果min_index不為0,做一些設定,因為總是假定從0序號開始的

2) 如果max_index > max,頂點太多了,需要分割一下再處理

3) 普通情形下,現在只針對這一情形閱讀:

==> bind_inputs()

==> bind_indices()

==> bind_prims()

==> TNL_CONTEXT(ctx)->Driver.RunPipeline() 對應 t_pipeline.c 下的 _tnl_run_pipeline()

==> unmap_vbos()

==> free_space()

前面的過程都很明顯的在為管道初始化數據地址

中間的函數進入 管道運行 _tnl_run_pipeline()

最后面再清理一些東西

?

6 管道繪制

這一個環節會把glBegin()/glEnd()之間的指令轉換成為最終輸出上的像素,牽涉到好幾個???#xff0c;弄懂它們也才能最終明白繪制指令是如何被具體實現的,以前的過程中對這里雖然也花了不少精力,但并沒有完全弄明白。

在矩陣變換方面,直線繪制(好像用的是中點繪制算法,但不是非??隙ㄟ@一點),超出邊界裁剪算法等地方用了不少的宏替換生成方法,如果覺得難以讀懂,建議打開VC設定里的存儲宏替換之后的.i文件。

?

矩陣變換方面的指針在 m_xform.c 內初始化,會包括好幾個文件來構建數組

?

數據結構 SWvertex 在軟件光柵化時存儲頂點的數據結構,這個很重要,最終繪制時輸入就是這個。

wpos = attr[FRAG_ATTRIB_WPOS] 在頂點里必須是第一個值,因為 tnl clipping code的緣故

wpos[0] 和 wpoa[1] 是 SWvertex 的屏幕點

wpos[2] 是 z-buffer 坐標 (如果16-位的Zbuffer,在范圍 [0, 65535] 之內)

wpos[3] 是 1/w,其中 w是W坐標的倒數,這是 ndc[XYZ]必須乘以而得到的 clip[XYZ]值

?

管道是什么樣的??

在 t_context.h 頭文件內,數據結構 tnl_pipeline_stage 描述單一的管道操作,包括create, destroy, validate, run幾個函數指針以及少量的數據成員

數據結構 tnl_pipeline 包括所有管道的數組容器,默認值在 t_pipeline.c 的最后,亦即 _tnl_default_pipeline[] 數組,從中可以看出先做頂點變換,再光照,紋理等,最后是運行渲染,渲染部分與管道部分之間可以再進一步分開

各個管道的初始化,可以在源代碼中找到

?

安裝管道

由 _tnl_install_pipeline() 來完成,可能在最開始的wglCreateContext()里就調用此函數了,此段代碼的執行應該是比較靠前的。

?

管道運行 _tnl_run_pipeline()

1) 如果 tnl->vb.Count 為0,則可退出,對應頂點數量

2) 檢查輸入變換,校驗tnl->pipeline.new_state狀態

3) 遍歷每一個管道,執行里邊的 run函數

?

頂點變換管道 t_vb_vertec.c 內

run_vertex_stage() 函數執行流程

1) 如果使用了 頂點編程,則退出

2) 如果 ctx->_NeedEyeCoords 不為0,則執行xxx (這里不大明白,具體不做什么事情)

3) VB->ClipPtr = TransformRaw() 用 ctx->_ModelProjectMatrix 矩陣變換輸入頂點,在 glBegin()與glEnd()之間所用到的值

矩陣里也對應有不少宏指派,這里會轉至 m_xform_tmp.h 內的 transform_points3_general

這里所對應的就是用模型投影矩陣變換輸入頂點

1.8106601???? 0??????????? 0????????? -2.7159901

0??????????? 2.4142137???? 0??????????????? 0

0????????????????? 0???? -1.0120724??? 4.8651910

0????????????????? 0?????????? -1???????????????? 6

(1) 頂點變換結果情況列表如下上一矩陣右乘列向量獲得 p' = M * p

(0.0 1.0 0.0) 變換為 (-2.7159901 2.4142137 4.8651910 6)

(-1.0 -1.0 0.0)??????? (-4.5266504 -2.4142137 4.8651910 6)

(1.0 -1.0 0.0)???????? (-0.90532994 -2.4142137 4.8651910 6)

上述變換結果點為VB->ClipPtr取值

4) 不管 tnl->NeedNdcCoords 是否需要,都會再進行如下一個轉換,具體是 點從

(x, y, z, w) 變換成為 (x/w y/w z/w 1/w) ,賦值給 VB->NdcPtr

從上一步再變換為

(-0.45266503 0.40236896 0.81086516 0.16666667)

(-0.75444174 -0.40236896 0.81086516 0.1666667)

(-0.15088832 -0.40236896 0.81086516 0.1666667)

以上頂點變換過程就完成了。

?

中間的這些管道因為沒有被啟用,比如光照,紋理,霧等等,故而不需要執行什么,內部會返回GL_TRUE

?

光柵渲染管道 t_vb_render.c 內

run_render()

對于這一過程,我想重要的二個地方在:內部如何建構屏幕點SWvertex;從屏幕點繪制算法;目前對后一問題有所追索,而前一問題總結得還不夠,好像層次比較復雜。

1) 調用 tnl->Driver.Render.Start() 函數 對應_swsetup_RenderStart()

==> 這里會在 _swsetup_choose_trifuncs() 初始化 tnl->Driver.Render. 三角形,四邊形,直線繪制 swsetup_line(),點繪制函數指針

==> 還有調用 setup_vertex_format() 以明確如何構建 SWvertex

內部通過 tnl_attr_map 的map數組,記錄每一個需要拷貝的值,比如總是拷貝第一個位置的 EMIT_ATTR(_TNL_ATTRIB_POS, EMIT_4F_VIEWPORT, attrib[FRAG_ATTRIB_WPOS]),然后如果有顏色設定,則拷貝顏色 EMIT_ATTR(_TNL_ATTRIB_COLOR0, EMIT_4CHAN_4F_RGBA, color);等等,范例只有這2個有設定, 最后調用 _tnl_install_attrs() 設置頂點格式

這個過程有調用 invalidate_funcs() 設置函數指針,比如 emit 指向 choose_emit_func,

2) assert() 確認 Render內的指針有值

3) 調用 tnl->Driver.Render.BuildVertices() 亦即 _tnl_build_vertices(),這里會對頂點有一個變換,但是這個變換卻又藏得很深 insert_4f_viewport_4() 函數

關鍵是在這里基于先前的輸入開始構建起后面所需要的頂點,所以它執行了一個系列的轉換流程,變換到最終的屏幕點,再最后從屏幕點開始繪制,所以這里的變換過程也很關鍵的,值得深入探討一番

==> 獲取 tnl_clipspace 指針

==> 調用 update_input_ptrs() 根據被設定的屬性數量,更新對應的數據指針地址,然后窗口viewport矩陣設置 vtx->vp_scale vtx->vp_xlate 的幾個值

==> 調用 vtx->emit()指針函數,亦即 choose_emit_func(),它會根據 vtx->attr (數據類型 tnl_clipspace_aatr ),設置對應的 a[j].emit 函數指針,a[j].insert[] 而這里的編排可能需要一點時間,對于viewport,設置的是 insert_4f_viewport_4 函數

然后再盡可能重置 vtx->emit, 若最后沒有值,則使用 _tnl_generic_emit() 函數,再調用此函數,該函數所完成的工作亦即遍歷所有頂點,調用先前在a[j].emit()里設置的函數,因而也就會調用 insert_4f_viewport_4(), 完畢之后,至此,本函數的運行結束了

頂點再一步變換為

(175.14719 336.56854 59337.523 0.1666667)

(78.578644 143.43146 59337.523 0.1666667)

(271.71573 143.43146 59337.523 0.1666667)

4) 獲取合適的渲染函數指針地址

5) 遍歷所有的prim以及頂點,繪制它們,這里又使用了宏指令來得到不同的函數指針,如果是繪制直線并且帶顏色的,會到達 rgba_line() (此函數定義經過宏替換產生),里邊的算法很像 中點繪制算法,不過不再嚴格去比對確認是否真為中點繪制算法了

6) 調用 tnl->Driver.Render.Finish(ctx)

?

以上再次對 OpenGL變換與繪制 又重新有所了解了,我在學習OpenGL的時候,有時候頭昏腦漲,搞不清楚最終這些指令會是怎樣被執行的,所以過來閱讀mesa源代碼,應該說有所收獲吧,看到管道的一種設計,看到函數的規劃與宏替換,真正體會到,C語言的簡潔與強大,當然更強的是mesa開發者對內部模型的設計,如果搞清楚了設計模型,里邊很多代碼就順理成章了。所以閱讀之后,我的感受是開發語言并不重要,項目的規劃與設計才是最重要的。



總結

以上是生活随笔為你收集整理的mesa3d源代码阅读笔记的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

久久久久久av无码免费看大片 | 久久99久久99精品中文字幕 | 日本一本二本三区免费 | 亚洲日本在线电影 | 国产精品va在线观看无码 | √天堂资源地址中文在线 | 大色综合色综合网站 | 少妇性l交大片 | 免费看少妇作爱视频 | 小泽玛莉亚一区二区视频在线 | 一个人免费观看的www视频 | 牛和人交xxxx欧美 | 无遮无挡爽爽免费视频 | 国产乱人伦偷精品视频 | 色综合久久久久综合一本到桃花网 | 性欧美videos高清精品 | 熟妇女人妻丰满少妇中文字幕 | 中文字幕人妻无码一区二区三区 | 国产人妻人伦精品1国产丝袜 | 成人精品天堂一区二区三区 | 97人妻精品一区二区三区 | 性欧美疯狂xxxxbbbb | 欧美喷潮久久久xxxxx | 精品久久久久久人妻无码中文字幕 | 久久久久成人精品免费播放动漫 | 亚洲一区二区三区无码久久 | 色妞www精品免费视频 | 丁香啪啪综合成人亚洲 | 无码人妻av免费一区二区三区 | 女人被男人爽到呻吟的视频 | 国产乱子伦视频在线播放 | 亚洲а∨天堂久久精品2021 | 国产av人人夜夜澡人人爽麻豆 | 爽爽影院免费观看 | 日韩视频 中文字幕 视频一区 | 亚洲无人区午夜福利码高清完整版 | 亚洲热妇无码av在线播放 | 久久久久免费看成人影片 | 欧美第一黄网免费网站 | 日日橹狠狠爱欧美视频 | 18禁止看的免费污网站 | 动漫av一区二区在线观看 | 国产精品无码成人午夜电影 | 日日天日日夜日日摸 | 亚欧洲精品在线视频免费观看 | 东京无码熟妇人妻av在线网址 | 国产卡一卡二卡三 | 亚洲日韩一区二区三区 | 成人免费视频视频在线观看 免费 | 蜜桃av抽搐高潮一区二区 | yw尤物av无码国产在线观看 | 国产精品人妻一区二区三区四 | 亚洲国产高清在线观看视频 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 精品国产一区二区三区四区在线看 | 成熟妇人a片免费看网站 | 扒开双腿吃奶呻吟做受视频 | 久久久www成人免费毛片 | 伊人久久婷婷五月综合97色 | 日韩精品无码免费一区二区三区 | 无码任你躁久久久久久久 | 精品国产青草久久久久福利 | 日本精品少妇一区二区三区 | 97色伦图片97综合影院 | 精品欧美一区二区三区久久久 | 国产电影无码午夜在线播放 | 无遮挡国产高潮视频免费观看 | a国产一区二区免费入口 | 蜜桃无码一区二区三区 | 男女性色大片免费网站 | 99久久精品日本一区二区免费 | 熟女少妇在线视频播放 | 无码国内精品人妻少妇 | 无码人妻丰满熟妇区毛片18 | 亚洲爆乳精品无码一区二区三区 | 无码午夜成人1000部免费视频 | 久久久久成人精品免费播放动漫 | 无码午夜成人1000部免费视频 | 日本熟妇浓毛 | 老头边吃奶边弄进去呻吟 | 久久久精品国产sm最大网站 | 露脸叫床粗话东北少妇 | 人人爽人人爽人人片av亚洲 | 18无码粉嫩小泬无套在线观看 | 未满小14洗澡无码视频网站 | 97精品人妻一区二区三区香蕉 | 日韩精品a片一区二区三区妖精 | 精品少妇爆乳无码av无码专区 | 大屁股大乳丰满人妻 | 午夜嘿嘿嘿影院 | 一个人看的视频www在线 | 伦伦影院午夜理论片 | 精品 日韩 国产 欧美 视频 | 午夜精品久久久久久久久 | 久久久久人妻一区精品色欧美 | 野外少妇愉情中文字幕 | 人妻插b视频一区二区三区 | 99久久久无码国产aaa精品 | 人妻体内射精一区二区三四 | 国产美女精品一区二区三区 | 宝宝好涨水快流出来免费视频 | 在线观看欧美一区二区三区 | 人人爽人人爽人人片av亚洲 | 色婷婷久久一区二区三区麻豆 | 一本色道婷婷久久欧美 | 国产美女极度色诱视频www | 欧美日本精品一区二区三区 | 成人免费视频一区二区 | 在线精品国产一区二区三区 | 久久亚洲精品中文字幕无男同 | 水蜜桃色314在线观看 | 色一情一乱一伦一区二区三欧美 | 2020最新国产自产精品 | 老头边吃奶边弄进去呻吟 | 99国产欧美久久久精品 | 在线精品国产一区二区三区 | 在线观看免费人成视频 | 久久婷婷五月综合色国产香蕉 | 亚洲国产欧美日韩精品一区二区三区 | 国产高清不卡无码视频 | 曰本女人与公拘交酡免费视频 | 少妇无码吹潮 | 无套内谢的新婚少妇国语播放 | 少妇性l交大片 | 精品无人国产偷自产在线 | 欧美激情内射喷水高潮 | 成人精品视频一区二区三区尤物 | 久久精品国产亚洲精品 | 国产激情精品一区二区三区 | 在线精品亚洲一区二区 | 午夜成人1000部免费视频 | 国产片av国语在线观看 | 亚洲乱码日产精品bd | 中文字幕日韩精品一区二区三区 | 国模大胆一区二区三区 | 成熟妇人a片免费看网站 | 国产精品美女久久久网av | 中文无码成人免费视频在线观看 | 日日躁夜夜躁狠狠躁 | 国产无遮挡又黄又爽又色 | 亚洲成a人片在线观看无码 | 男女性色大片免费网站 | 久久久久久久久蜜桃 | 国产成人综合色在线观看网站 | 国产欧美精品一区二区三区 | 成人无码精品一区二区三区 | 精品水蜜桃久久久久久久 | 中文字幕人成乱码熟女app | 国内少妇偷人精品视频免费 | 狠狠色丁香久久婷婷综合五月 | 亚洲日韩av片在线观看 | 日本一卡2卡3卡四卡精品网站 | 99国产精品白浆在线观看免费 | 美女毛片一区二区三区四区 | 日日天干夜夜狠狠爱 | 一本久久a久久精品亚洲 | 夜夜躁日日躁狠狠久久av | 欧美色就是色 | 国产精品无码一区二区三区不卡 | 国产成人综合在线女婷五月99播放 | 免费无码一区二区三区蜜桃大 | 免费男性肉肉影院 | 亚洲中文无码av永久不收费 | 亚洲自偷自偷在线制服 | 久久成人a毛片免费观看网站 | 国产精品手机免费 | 香蕉久久久久久av成人 | 日韩精品一区二区av在线 | 欧美老妇交乱视频在线观看 | a在线观看免费网站大全 | 偷窥村妇洗澡毛毛多 | 亚洲中文无码av永久不收费 | 久久午夜无码鲁丝片午夜精品 | 天天摸天天碰天天添 | 亚洲中文字幕久久无码 | 亚洲精品一区二区三区大桥未久 | 精品国产精品久久一区免费式 | 波多野结衣一区二区三区av免费 | 精品国偷自产在线 | 青青久在线视频免费观看 | 国产乱人伦偷精品视频 | 丝袜足控一区二区三区 | 乱码午夜-极国产极内射 | 好男人社区资源 | 丰满护士巨好爽好大乳 | 亚洲精品www久久久 | 午夜成人1000部免费视频 | 一区二区三区乱码在线 | 欧洲 | 99er热精品视频 | 骚片av蜜桃精品一区 | 男人扒开女人内裤强吻桶进去 | 无码任你躁久久久久久久 | 国产综合色产在线精品 | 亚洲精品中文字幕久久久久 | 熟女俱乐部五十路六十路av | 乱码av麻豆丝袜熟女系列 | 欧美刺激性大交 | 久久精品视频在线看15 | 亚洲欧美精品伊人久久 | 又大又硬又黄的免费视频 | 免费视频欧美无人区码 | 99精品国产综合久久久久五月天 | 国产精品爱久久久久久久 | 俄罗斯老熟妇色xxxx | 青春草在线视频免费观看 | 亚洲精品国产品国语在线观看 | 国产精品沙发午睡系列 | 亚洲人交乣女bbw | 蜜桃av抽搐高潮一区二区 | 午夜精品一区二区三区在线观看 | 中文字幕久久久久人妻 | 国产精品人妻一区二区三区四 | 欧美丰满老熟妇xxxxx性 | 日本免费一区二区三区最新 | 亚洲国产日韩a在线播放 | 亚洲s码欧洲m码国产av | 伊人久久大香线焦av综合影院 | 免费中文字幕日韩欧美 | 久久精品人人做人人综合 | 久久久av男人的天堂 | 精品国精品国产自在久国产87 | 午夜熟女插插xx免费视频 | 少妇性荡欲午夜性开放视频剧场 | 日本一区二区三区免费播放 | 极品尤物被啪到呻吟喷水 | 在线a亚洲视频播放在线观看 | 蜜桃无码一区二区三区 | 天堂一区人妻无码 | 国产一区二区三区精品视频 | 欧美精品无码一区二区三区 | 中文字幕无码日韩专区 | 伊人久久婷婷五月综合97色 | 少妇邻居内射在线 | 精品无码av一区二区三区 | 国产精品香蕉在线观看 | 亚洲无人区一区二区三区 | 亚洲国产午夜精品理论片 | 少女韩国电视剧在线观看完整 | 欧美xxxxx精品 | 国产精品.xx视频.xxtv | 国产内射爽爽大片视频社区在线 | 精品国产一区av天美传媒 | 国产熟妇另类久久久久 | 图片区 小说区 区 亚洲五月 | 日本高清一区免费中文视频 | 在线播放免费人成毛片乱码 | 日本精品人妻无码免费大全 | 亚洲欧洲日本综合aⅴ在线 | 日韩人妻少妇一区二区三区 | 国产精品人人妻人人爽 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 狠狠色欧美亚洲狠狠色www | 久久精品中文闷骚内射 | 欧美国产亚洲日韩在线二区 | 奇米影视888欧美在线观看 | 国产超级va在线观看视频 | 成人精品天堂一区二区三区 | 一区二区三区乱码在线 | 欧洲 | 性开放的女人aaa片 | 久久综合色之久久综合 | 一本久久a久久精品vr综合 | 欧美 日韩 亚洲 在线 | 美女极度色诱视频国产 | 色偷偷人人澡人人爽人人模 | 亚洲精品一区二区三区大桥未久 | 又紧又大又爽精品一区二区 | 日韩成人一区二区三区在线观看 | 国产 精品 自在自线 | 亚洲成av人综合在线观看 | 女人被男人躁得好爽免费视频 | 国产无遮挡吃胸膜奶免费看 | 激情内射日本一区二区三区 | 在线观看国产午夜福利片 | 国产亚洲日韩欧美另类第八页 | 99精品久久毛片a片 | 亚洲一区av无码专区在线观看 | 狠狠色欧美亚洲狠狠色www | 国产高潮视频在线观看 | 麻豆国产丝袜白领秘书在线观看 | 精品国产福利一区二区 | 国产精品久久国产三级国 | 麻豆国产97在线 | 欧洲 | 99在线 | 亚洲 | 国产免费久久精品国产传媒 | 国内精品九九久久久精品 | 又大又黄又粗又爽的免费视频 | 鲁鲁鲁爽爽爽在线视频观看 | 欧美日韩人成综合在线播放 | 久久这里只有精品视频9 | 中文无码伦av中文字幕 | 一本久道高清无码视频 | 免费观看激色视频网站 | 中文字幕av无码一区二区三区电影 | 国产精品va在线观看无码 | 性欧美大战久久久久久久 | 亚洲一区二区三区 | 成人欧美一区二区三区黑人 | 久久午夜无码鲁丝片午夜精品 | 人妻与老人中文字幕 | 国产熟妇另类久久久久 | 亚洲成a人片在线观看无码3d | 精品欧洲av无码一区二区三区 | 黑人粗大猛烈进出高潮视频 | 久久国产精品萌白酱免费 | 性啪啪chinese东北女人 | 欧美乱妇无乱码大黄a片 | 久久亚洲精品中文字幕无男同 | 荫蒂添的好舒服视频囗交 | 无码av中文字幕免费放 | 精品欧洲av无码一区二区三区 | 国产精品va在线播放 | 18精品久久久无码午夜福利 | 国产人妻精品午夜福利免费 | 麻豆国产人妻欲求不满谁演的 | 真人与拘做受免费视频 | 精品偷拍一区二区三区在线看 | 亚洲精品国产第一综合99久久 | 色综合天天综合狠狠爱 | 午夜精品久久久久久久久 | 国产精品办公室沙发 | 熟女俱乐部五十路六十路av | 国产口爆吞精在线视频 | 亚洲精品一区三区三区在线观看 | 精品乱码久久久久久久 | 欧美日韩在线亚洲综合国产人 | 久久久久亚洲精品男人的天堂 | 日欧一片内射va在线影院 | 国产国产精品人在线视 | 久久国产精品精品国产色婷婷 | 日韩人妻系列无码专区 | 无码午夜成人1000部免费视频 | 性欧美牲交xxxxx视频 | 成人无码视频免费播放 | 国产一区二区三区精品视频 | 丁香啪啪综合成人亚洲 | 亚洲欧美日韩国产精品一区二区 | 欧美日韩一区二区免费视频 | 少女韩国电视剧在线观看完整 | 久久国产精品_国产精品 | 人人妻人人澡人人爽人人精品 | 亚洲成av人片在线观看无码不卡 | 国产一区二区不卡老阿姨 | 欧美性猛交xxxx富婆 | 四虎国产精品免费久久 | 国产精品久久久久影院嫩草 | 丰满少妇人妻久久久久久 | 国产深夜福利视频在线 | 激情国产av做激情国产爱 | 国产性猛交╳xxx乱大交 国产精品久久久久久无码 欧洲欧美人成视频在线 | 欧美国产日韩久久mv | 熟妇人妻激情偷爽文 | 4hu四虎永久在线观看 | 国产日产欧产精品精品app | 亚洲综合色区中文字幕 | 亚洲日韩乱码中文无码蜜桃臀网站 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 性欧美videos高清精品 | 在线观看国产一区二区三区 | 波多野结衣av一区二区全免费观看 | 小sao货水好多真紧h无码视频 | 正在播放东北夫妻内射 | 97夜夜澡人人爽人人喊中国片 | 99精品视频在线观看免费 | 激情国产av做激情国产爱 | 亚洲无人区午夜福利码高清完整版 | 香港三级日本三级妇三级 | 荫蒂添的好舒服视频囗交 | 亚洲一区二区三区无码久久 | 亚洲男人av香蕉爽爽爽爽 | 久久精品一区二区三区四区 | 水蜜桃亚洲一二三四在线 | 国产9 9在线 | 中文 | 色婷婷综合激情综在线播放 | 久久人人爽人人爽人人片ⅴ | 色综合久久久无码中文字幕 | 日本精品人妻无码77777 天堂一区人妻无码 | 日日橹狠狠爱欧美视频 | 国语精品一区二区三区 | 欧美变态另类xxxx | 久久 国产 尿 小便 嘘嘘 | 国产猛烈高潮尖叫视频免费 | 国产偷抇久久精品a片69 | 久久国产劲爆∧v内射 | 最新国产麻豆aⅴ精品无码 | 国产精品永久免费视频 | 亚洲国产精品久久人人爱 | 国产成人无码专区 | 四十如虎的丰满熟妇啪啪 | 男女下面进入的视频免费午夜 | 久久亚洲精品成人无码 | 久久zyz资源站无码中文动漫 | 久久综合狠狠综合久久综合88 | аⅴ资源天堂资源库在线 | 无码av岛国片在线播放 | 性欧美牲交xxxxx视频 | 中文字幕av伊人av无码av | 国产精品毛片一区二区 | 国产亚洲精品久久久久久 | 亚洲中文字幕在线观看 | 国产午夜福利100集发布 | 亚洲男人av香蕉爽爽爽爽 | 夜夜躁日日躁狠狠久久av | 欧美丰满熟妇xxxx性ppx人交 | 激情国产av做激情国产爱 | 婷婷综合久久中文字幕蜜桃三电影 | 久久久久免费精品国产 | 欧美第一黄网免费网站 | 伊人久久大香线蕉亚洲 | 国产美女极度色诱视频www | 2020久久香蕉国产线看观看 | yw尤物av无码国产在线观看 | 亚洲欧美日韩成人高清在线一区 | 中文字幕av日韩精品一区二区 | 国产亚洲精品久久久久久国模美 | 国内综合精品午夜久久资源 | 国产成人精品三级麻豆 | 国产香蕉尹人视频在线 | 天天燥日日燥 | 丰满人妻翻云覆雨呻吟视频 | 大肉大捧一进一出视频出来呀 | 日韩人妻无码中文字幕视频 | 亚洲七七久久桃花影院 | 婷婷五月综合缴情在线视频 | 国产免费无码一区二区视频 | 精品成在人线av无码免费看 | 日日噜噜噜噜夜夜爽亚洲精品 | 少妇高潮喷潮久久久影院 | 日产国产精品亚洲系列 | 沈阳熟女露脸对白视频 | 又大又紧又粉嫩18p少妇 | 日本在线高清不卡免费播放 | 久久精品无码一区二区三区 | 亚洲人成网站在线播放942 | 免费观看黄网站 | 免费看少妇作爱视频 | 亚洲成在人网站无码天堂 | 国产一区二区三区四区五区加勒比 | 99久久99久久免费精品蜜桃 | 亚洲精品美女久久久久久久 | 欧美真人作爱免费视频 | 性史性农村dvd毛片 | 日本护士毛茸茸高潮 | aⅴ亚洲 日韩 色 图网站 播放 | 无套内射视频囯产 | 对白脏话肉麻粗话av | 国产精品内射视频免费 | 日日噜噜噜噜夜夜爽亚洲精品 | 无码av中文字幕免费放 | 麻豆国产人妻欲求不满谁演的 | 露脸叫床粗话东北少妇 | 国产精品久久久久久久影院 | 中文字幕人妻无码一夲道 | 国产农村妇女高潮大叫 | 久久天天躁狠狠躁夜夜免费观看 | 国精品人妻无码一区二区三区蜜柚 | 成人影院yy111111在线观看 | 久久精品国产一区二区三区 | 亚洲精品久久久久久一区二区 | 中文精品无码中文字幕无码专区 | 精品aⅴ一区二区三区 | 性生交大片免费看l | 亚洲精品一区二区三区在线观看 | 久久zyz资源站无码中文动漫 | 一本加勒比波多野结衣 | 日韩少妇白浆无码系列 | 日日噜噜噜噜夜夜爽亚洲精品 | 午夜时刻免费入口 | 国产精品手机免费 | 波多野结衣乳巨码无在线观看 | 樱花草在线播放免费中文 | 荡女精品导航 | 大肉大捧一进一出视频出来呀 | 国产在线精品一区二区高清不卡 | 精品无人区无码乱码毛片国产 | 国产区女主播在线观看 | 性啪啪chinese东北女人 | 纯爱无遮挡h肉动漫在线播放 | 中文字幕av伊人av无码av | 亚洲国产精品美女久久久久 | 蜜桃av蜜臀av色欲av麻 999久久久国产精品消防器材 | 熟妇激情内射com | 久久国产精品精品国产色婷婷 | 国产熟妇另类久久久久 | 久久精品女人天堂av免费观看 | а天堂中文在线官网 | 国产午夜亚洲精品不卡下载 | 人人妻人人澡人人爽欧美精品 | 蜜臀av在线观看 在线欧美精品一区二区三区 | 日产精品高潮呻吟av久久 | 永久免费观看美女裸体的网站 | 99精品无人区乱码1区2区3区 | 欧美国产亚洲日韩在线二区 | 国产免费久久精品国产传媒 | 天天爽夜夜爽夜夜爽 | 亚洲国产精品无码一区二区三区 | 内射后入在线观看一区 | 成人欧美一区二区三区 | 日欧一片内射va在线影院 | 狠狠色噜噜狠狠狠7777奇米 | 亚洲一区av无码专区在线观看 | 成人女人看片免费视频放人 | 日本熟妇浓毛 | 5858s亚洲色大成网站www | 亚洲日韩av片在线观看 | 久久国产劲爆∧v内射 | 扒开双腿疯狂进出爽爽爽视频 | 久久99国产综合精品 | 牲欲强的熟妇农村老妇女视频 | 夜夜躁日日躁狠狠久久av | 日产精品99久久久久久 | 性欧美疯狂xxxxbbbb | 亚洲色成人中文字幕网站 | 国产精品沙发午睡系列 | 久久 国产 尿 小便 嘘嘘 | 久久熟妇人妻午夜寂寞影院 | 荫蒂被男人添的好舒服爽免费视频 | 国产成人无码区免费内射一片色欲 | 国产午夜无码精品免费看 | 国产精品久免费的黄网站 | 午夜时刻免费入口 | 国内揄拍国内精品人妻 | 久精品国产欧美亚洲色aⅴ大片 | 任你躁国产自任一区二区三区 | 免费观看的无遮挡av | 国产在线aaa片一区二区99 | 玩弄中年熟妇正在播放 | 少妇人妻偷人精品无码视频 | 欧美日韩色另类综合 | 国产成人无码av一区二区 | 国产人妻精品午夜福利免费 | 无码国模国产在线观看 | www国产精品内射老师 | 熟妇人妻无乱码中文字幕 | 欧美丰满少妇xxxx性 | 一本无码人妻在中文字幕免费 | 日欧一片内射va在线影院 | 日本一本二本三区免费 | 日本熟妇人妻xxxxx人hd | 精品无人国产偷自产在线 | 亚洲乱亚洲乱妇50p | 亚洲国产一区二区三区在线观看 | 7777奇米四色成人眼影 | 国产又爽又黄又刺激的视频 | 亚洲综合另类小说色区 | 欧美日韩综合一区二区三区 | 国产精品亚洲а∨无码播放麻豆 | 熟女少妇人妻中文字幕 | 欧美国产日韩久久mv | 久久aⅴ免费观看 | aⅴ亚洲 日韩 色 图网站 播放 | 国产一区二区三区精品视频 | 亚洲一区二区三区偷拍女厕 | 日本欧美一区二区三区乱码 | 国产成人一区二区三区在线观看 | 中文字幕无码热在线视频 | 成年美女黄网站色大免费全看 | 18无码粉嫩小泬无套在线观看 | 在线 国产 欧美 亚洲 天堂 | 水蜜桃av无码 | 国产亚洲精品精品国产亚洲综合 | 久久综合给合久久狠狠狠97色 | 天干天干啦夜天干天2017 | 色综合视频一区二区三区 | 狠狠综合久久久久综合网 | 午夜精品久久久内射近拍高清 | 欧美熟妇另类久久久久久不卡 | 欧美日韩色另类综合 | 亚洲男人av香蕉爽爽爽爽 | 女人被男人躁得好爽免费视频 | 亚洲精品国产精品乱码视色 | 亚洲国产精品一区二区美利坚 | 丝袜足控一区二区三区 | 中文字幕av无码一区二区三区电影 | 国产艳妇av在线观看果冻传媒 | 无码一区二区三区在线 | 精品国产一区二区三区四区在线看 | 一二三四社区在线中文视频 | 蜜臀av在线播放 久久综合激激的五月天 | 久久人人爽人人人人片 | 久久人人爽人人人人片 | 国产精品99久久精品爆乳 | 无码成人精品区在线观看 | 成人精品视频一区二区三区尤物 | 日本爽爽爽爽爽爽在线观看免 | 亚洲欧美日韩综合久久久 | 丰满人妻翻云覆雨呻吟视频 | 欧美猛少妇色xxxxx | 色狠狠av一区二区三区 | 欧美色就是色 | 欧美色就是色 | 性史性农村dvd毛片 | 国产熟妇高潮叫床视频播放 | 国产高清av在线播放 | 无码人妻少妇伦在线电影 | 澳门永久av免费网站 | 十八禁视频网站在线观看 | 88国产精品欧美一区二区三区 | 国产无遮挡吃胸膜奶免费看 | 亚洲s色大片在线观看 | 日韩视频 中文字幕 视频一区 | 成人欧美一区二区三区 | 亚洲精品综合一区二区三区在线 | 中文字幕+乱码+中文字幕一区 | 久久久久久久女国产乱让韩 | 双乳奶水饱满少妇呻吟 | 国产成人无码av在线影院 | 精品夜夜澡人妻无码av蜜桃 | 亚洲中文字幕乱码av波多ji | 亚洲熟妇色xxxxx欧美老妇 | 人妻互换免费中文字幕 | 学生妹亚洲一区二区 | 成人精品一区二区三区中文字幕 | 亚洲a无码综合a国产av中文 | 大胆欧美熟妇xx | 国产情侣作爱视频免费观看 | 久久99精品久久久久久动态图 | 国内精品人妻无码久久久影院蜜桃 | 乌克兰少妇xxxx做受 | 欧美35页视频在线观看 | 无码av最新清无码专区吞精 | 国产在热线精品视频 | 永久黄网站色视频免费直播 | 成人aaa片一区国产精品 | 激情国产av做激情国产爱 | 一本色道久久综合亚洲精品不卡 | 国产精品办公室沙发 | 啦啦啦www在线观看免费视频 | 狠狠噜狠狠狠狠丁香五月 | 亚洲国产一区二区三区在线观看 | 中文字幕 亚洲精品 第1页 | 一本久道久久综合狠狠爱 | 久久久久久a亚洲欧洲av冫 | 女高中生第一次破苞av | 水蜜桃色314在线观看 | 激情内射日本一区二区三区 | 丰满护士巨好爽好大乳 | 天海翼激烈高潮到腰振不止 | 自拍偷自拍亚洲精品10p | 国内精品九九久久久精品 | 中国大陆精品视频xxxx | 国产人妻大战黑人第1集 | 久久人人爽人人爽人人片ⅴ | 国产综合色产在线精品 | 男人和女人高潮免费网站 | 99国产精品白浆在线观看免费 | 亚洲成a人片在线观看无码 | 成在人线av无码免观看麻豆 | 国产极品美女高潮无套在线观看 | 天天做天天爱天天爽综合网 | 中文字幕乱码中文乱码51精品 | 中文字幕日韩精品一区二区三区 | 亚洲热妇无码av在线播放 | 亚洲综合伊人久久大杳蕉 | 九九久久精品国产免费看小说 | 天干天干啦夜天干天2017 | 在线精品亚洲一区二区 | 奇米影视7777久久精品人人爽 | 国精产品一品二品国精品69xx | 天天做天天爱天天爽综合网 | 欧美国产亚洲日韩在线二区 | 中文毛片无遮挡高清免费 | 国产精品毛片一区二区 | 在线a亚洲视频播放在线观看 | 国产精品-区区久久久狼 | 无码午夜成人1000部免费视频 | 亚洲国产精品久久人人爱 | 波多野42部无码喷潮在线 | 高潮毛片无遮挡高清免费 | 午夜时刻免费入口 | 亚洲爆乳大丰满无码专区 | 狠狠综合久久久久综合网 | 在线成人www免费观看视频 | 九一九色国产 | 国产日产欧产精品精品app | 无码成人精品区在线观看 | 久久久久免费看成人影片 | 色五月丁香五月综合五月 | 欧美日韩视频无码一区二区三 | 久久97精品久久久久久久不卡 | 欧美自拍另类欧美综合图片区 | 丰满人妻翻云覆雨呻吟视频 | 国产人妻人伦精品 | 久久人人爽人人爽人人片ⅴ | 国产成人午夜福利在线播放 | 欧美黑人性暴力猛交喷水 | 国产激情无码一区二区 | 国产麻豆精品一区二区三区v视界 | 欧美 丝袜 自拍 制服 另类 | 少妇人妻大乳在线视频 | 日本一本二本三区免费 | 久久精品视频在线看15 | 亚洲自偷自偷在线制服 | 大乳丰满人妻中文字幕日本 | 一本久久a久久精品vr综合 | 国产av一区二区精品久久凹凸 | 装睡被陌生人摸出水好爽 | 免费无码肉片在线观看 | 131美女爱做视频 | 一本大道伊人av久久综合 | 日本乱人伦片中文三区 | 九九久久精品国产免费看小说 | 性生交大片免费看l | 亚洲熟妇色xxxxx欧美老妇 | 国产精品丝袜黑色高跟鞋 | 国产猛烈高潮尖叫视频免费 | 一区二区三区乱码在线 | 欧洲 | 蜜臀aⅴ国产精品久久久国产老师 | 欧美人与牲动交xxxx | 欧美人与动性行为视频 | 亚洲一区二区观看播放 | 在线播放无码字幕亚洲 | 亚洲综合伊人久久大杳蕉 | 999久久久国产精品消防器材 | 欧美日韩在线亚洲综合国产人 | 7777奇米四色成人眼影 | 强开小婷嫩苞又嫩又紧视频 | 国产成人一区二区三区在线观看 | 色一情一乱一伦一区二区三欧美 | 成人亚洲精品久久久久 | 中文字幕无码免费久久99 | 欧洲欧美人成视频在线 | 波多野结衣乳巨码无在线观看 | 曰本女人与公拘交酡免费视频 | 国产性生交xxxxx无码 | 国产片av国语在线观看 | 人妻尝试又大又粗久久 | 久久天天躁夜夜躁狠狠 | 一本久久a久久精品亚洲 | 六十路熟妇乱子伦 | 性色欲情网站iwww九文堂 | 中文精品久久久久人妻不卡 | 精品国产一区二区三区四区在线看 | 少妇无码av无码专区在线观看 | 亚洲精品中文字幕久久久久 | 在线欧美精品一区二区三区 | 四虎国产精品一区二区 | 野狼第一精品社区 | 扒开双腿疯狂进出爽爽爽视频 | 天下第一社区视频www日本 | 国产精品无码mv在线观看 | 国产精品爱久久久久久久 | 久久午夜无码鲁丝片午夜精品 | 人人澡人摸人人添 | 婷婷综合久久中文字幕蜜桃三电影 | 国产成人精品视频ⅴa片软件竹菊 | 亚洲国产精品一区二区美利坚 | 国产性生大片免费观看性 | 久久精品人人做人人综合试看 | 久久精品成人欧美大片 | 中文无码成人免费视频在线观看 | 牲欲强的熟妇农村老妇女 | 国产精品久久久久久亚洲毛片 | 丰满人妻被黑人猛烈进入 | 丁香花在线影院观看在线播放 | 国产片av国语在线观看 | 4hu四虎永久在线观看 | 亚洲 高清 成人 动漫 | 中国大陆精品视频xxxx | av人摸人人人澡人人超碰下载 | 亚洲小说春色综合另类 | 亚洲 欧美 激情 小说 另类 | 真人与拘做受免费视频 | 亚洲日本va中文字幕 | 日本xxxx色视频在线观看免费 | 国产超碰人人爽人人做人人添 | 97色伦图片97综合影院 | 97夜夜澡人人爽人人喊中国片 | 国产成人精品一区二区在线小狼 | 无码人妻精品一区二区三区不卡 | 亚洲成a人片在线观看无码3d | 精品成在人线av无码免费看 | 亚洲精品一区二区三区在线 | 亚洲小说图区综合在线 | 精品一区二区不卡无码av | 久久国产精品偷任你爽任你 | 国产麻豆精品一区二区三区v视界 | 伦伦影院午夜理论片 | 亚洲国产精品一区二区第一页 | 人人妻人人澡人人爽人人精品浪潮 | 亚洲熟妇自偷自拍另类 | 在线视频网站www色 | 丁香啪啪综合成人亚洲 | 久久精品成人欧美大片 | 国产亚洲精品精品国产亚洲综合 | 午夜丰满少妇性开放视频 | 岛国片人妻三上悠亚 | 国产精品久久久久久亚洲影视内衣 | 精品无码一区二区三区的天堂 | 久久久婷婷五月亚洲97号色 | 人妻熟女一区 | 国产后入清纯学生妹 | 99在线 | 亚洲 | 亚洲综合另类小说色区 | 熟妇人妻激情偷爽文 | 97色伦图片97综合影院 | 免费中文字幕日韩欧美 | 免费看少妇作爱视频 | 久久精品一区二区三区四区 | 国产亚洲精品久久久久久久久动漫 | 女人被男人躁得好爽免费视频 | 国产色视频一区二区三区 | 成人无码精品一区二区三区 | 黑人巨大精品欧美一区二区 | 中文字幕人妻无码一区二区三区 | 日本爽爽爽爽爽爽在线观看免 | 内射白嫩少妇超碰 | 动漫av一区二区在线观看 | 欧美日韩视频无码一区二区三 | 乱中年女人伦av三区 | 狠狠cao日日穞夜夜穞av | 日本精品高清一区二区 | 国产精品久久久久久无码 | 日韩成人一区二区三区在线观看 | 中文字幕精品av一区二区五区 | 国产xxx69麻豆国语对白 | 欧美性生交xxxxx久久久 | 国产网红无码精品视频 | 欧美性生交xxxxx久久久 | 国产特级毛片aaaaaaa高清 | 熟妇激情内射com | 300部国产真实乱 | 天堂无码人妻精品一区二区三区 | 国产成人无码区免费内射一片色欲 | 日韩亚洲欧美中文高清在线 | 日产国产精品亚洲系列 | av在线亚洲欧洲日产一区二区 | 欧美日韩一区二区免费视频 | 亚洲精品一区二区三区大桥未久 | 国产热a欧美热a在线视频 | 无码精品国产va在线观看dvd | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 久久99精品国产麻豆蜜芽 | 欧美阿v高清资源不卡在线播放 | 成人精品一区二区三区中文字幕 | 久久综合给久久狠狠97色 | 一个人免费观看的www视频 | 欧美怡红院免费全部视频 | 99久久久无码国产aaa精品 | 九月婷婷人人澡人人添人人爽 | 日本一卡2卡3卡四卡精品网站 | 好屌草这里只有精品 | 精品国偷自产在线视频 | 国产精品怡红院永久免费 | 九九综合va免费看 | 人妻体内射精一区二区三四 | 一二三四在线观看免费视频 | 国内综合精品午夜久久资源 | 国产情侣作爱视频免费观看 | 欧美丰满熟妇xxxx性ppx人交 | 久久精品中文字幕一区 | 国内精品久久久久久中文字幕 | √天堂资源地址中文在线 | 久久婷婷五月综合色国产香蕉 | 亚洲中文字幕乱码av波多ji | 欧美 亚洲 国产 另类 | 野狼第一精品社区 | 亚洲人亚洲人成电影网站色 | 国产成人综合色在线观看网站 | 又黄又爽又色的视频 | 精品欧美一区二区三区久久久 | 日日噜噜噜噜夜夜爽亚洲精品 | 亚洲另类伦春色综合小说 | 精品 日韩 国产 欧美 视频 | 在线播放免费人成毛片乱码 | 国产成人无码av在线影院 | 国产精品国产三级国产专播 | 九九在线中文字幕无码 | 亚拍精品一区二区三区探花 | 亚洲乱码日产精品bd | 中文字幕人妻无码一夲道 | 青青青爽视频在线观看 | 狠狠色噜噜狠狠狠狠7777米奇 | av无码久久久久不卡免费网站 | 亚洲一区二区三区国产精华液 | 无码人妻丰满熟妇区毛片18 | 极品嫩模高潮叫床 | 久久国产精品萌白酱免费 | 麻豆蜜桃av蜜臀av色欲av | 久久久婷婷五月亚洲97号色 | 欧美 日韩 人妻 高清 中文 | 亚洲熟熟妇xxxx | 免费看男女做好爽好硬视频 | 中国女人内谢69xxxxxa片 | 性史性农村dvd毛片 | 麻豆成人精品国产免费 | 在线观看国产午夜福利片 | 亚洲精品美女久久久久久久 | 全黄性性激高免费视频 | 亚洲国产精品久久人人爱 | 高潮喷水的毛片 | 草草网站影院白丝内射 | 麻豆成人精品国产免费 | 亚洲精品综合五月久久小说 | 国产一区二区不卡老阿姨 | 午夜丰满少妇性开放视频 | 国产后入清纯学生妹 | 久久精品丝袜高跟鞋 | 蜜臀av在线观看 在线欧美精品一区二区三区 | 无套内谢老熟女 | 日韩视频 中文字幕 视频一区 | 精品国产一区二区三区四区在线看 | 久久久久久国产精品无码下载 | 久久人妻内射无码一区三区 | 国产 浪潮av性色四虎 | 老子影院午夜伦不卡 | 丰满少妇女裸体bbw | 精品熟女少妇av免费观看 | 综合人妻久久一区二区精品 | 国产一区二区三区日韩精品 | 扒开双腿吃奶呻吟做受视频 | 久久久精品456亚洲影院 | 久久综合网欧美色妞网 | 成人试看120秒体验区 | 亚洲欧美国产精品久久 | 欧美肥老太牲交大战 | 国产两女互慰高潮视频在线观看 | 国产精品自产拍在线观看 | 成人亚洲精品久久久久软件 | 免费看男女做好爽好硬视频 | 乱码午夜-极国产极内射 | 亚洲理论电影在线观看 | 国产特级毛片aaaaaa高潮流水 | 亚洲 欧美 激情 小说 另类 | 一区二区三区高清视频一 | 国产精品久免费的黄网站 | 中文字幕av无码一区二区三区电影 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 99久久人妻精品免费二区 | 性欧美熟妇videofreesex | 99久久精品日本一区二区免费 | 双乳奶水饱满少妇呻吟 | 成熟女人特级毛片www免费 | 亚洲熟妇色xxxxx欧美老妇y | 国内精品一区二区三区不卡 | 日本精品人妻无码77777 天堂一区人妻无码 | 精品人人妻人人澡人人爽人人 | 99视频精品全部免费免费观看 | 免费人成网站视频在线观看 | 99精品国产综合久久久久五月天 | 日日天干夜夜狠狠爱 | 欧美三级不卡在线观看 | 午夜男女很黄的视频 | 国产精品亚洲а∨无码播放麻豆 | 国产精品99爱免费视频 | 免费乱码人妻系列无码专区 | 少妇无码一区二区二三区 | 国产熟女一区二区三区四区五区 | 国产亚洲精品久久久久久国模美 | 国产成人无码av一区二区 | 东京无码熟妇人妻av在线网址 | 丝袜人妻一区二区三区 | 午夜性刺激在线视频免费 | 亚洲大尺度无码无码专区 | 成人无码影片精品久久久 | 人妻少妇精品久久 | 国产无套内射久久久国产 | 色窝窝无码一区二区三区色欲 | 国产精品第一区揄拍无码 | 九一九色国产 | 曰韩少妇内射免费播放 | 老熟妇乱子伦牲交视频 | aⅴ亚洲 日韩 色 图网站 播放 | 4hu四虎永久在线观看 | 无码福利日韩神码福利片 | 无码帝国www无码专区色综合 | 欧美国产日韩亚洲中文 | 国产熟妇另类久久久久 | 97精品人妻一区二区三区香蕉 | 乱人伦中文视频在线观看 | 自拍偷自拍亚洲精品被多人伦好爽 | 精品一区二区三区波多野结衣 | 一本久久伊人热热精品中文字幕 | 欧美性黑人极品hd | 久久五月精品中文字幕 | 熟妇女人妻丰满少妇中文字幕 | 国产精品久久久av久久久 | 久久久久久久女国产乱让韩 | www国产精品内射老师 | 国产网红无码精品视频 | 300部国产真实乱 | 国产精品多人p群无码 | 国产熟妇另类久久久久 | 特黄特色大片免费播放器图片 | 人妻互换免费中文字幕 | 欧美喷潮久久久xxxxx | 伦伦影院午夜理论片 | 丰满人妻精品国产99aⅴ | 99久久亚洲精品无码毛片 | 成人亚洲精品久久久久软件 | 国产精品久久国产三级国 | 久久久久久久人妻无码中文字幕爆 | 伊人久久大香线蕉av一区二区 | 偷窥村妇洗澡毛毛多 | 色综合久久网 | 狠狠亚洲超碰狼人久久 | 熟女体下毛毛黑森林 | 欧美性猛交xxxx富婆 | 奇米影视888欧美在线观看 | 日韩无码专区 | 亚洲 日韩 欧美 成人 在线观看 | 无码一区二区三区在线观看 | 人妻中文无码久热丝袜 | 欧美三级不卡在线观看 | 欧美自拍另类欧美综合图片区 | 亚洲熟女一区二区三区 | 狠狠色欧美亚洲狠狠色www | 国产精品-区区久久久狼 | 欧美日韩综合一区二区三区 | 久久久精品欧美一区二区免费 | 中文字幕亚洲情99在线 | 国産精品久久久久久久 | √天堂资源地址中文在线 | 日日噜噜噜噜夜夜爽亚洲精品 | 麻豆av传媒蜜桃天美传媒 | 51国偷自产一区二区三区 | 老司机亚洲精品影院 | 亚洲欧洲无卡二区视頻 | 成人免费无码大片a毛片 | 丝袜人妻一区二区三区 | 激情国产av做激情国产爱 | 国产av一区二区精品久久凹凸 | 无码人妻丰满熟妇区毛片18 | 1000部夫妻午夜免费 | 丰满人妻被黑人猛烈进入 | 亚洲乱码日产精品bd | 亚洲中文字幕在线观看 | 97夜夜澡人人双人人人喊 | 久激情内射婷内射蜜桃人妖 | 欧美真人作爱免费视频 | 国产精品久免费的黄网站 | 日本精品少妇一区二区三区 | 国产精品亚洲а∨无码播放麻豆 | a片在线免费观看 | 一本精品99久久精品77 | 国产人妻大战黑人第1集 | 成人动漫在线观看 | 77777熟女视频在线观看 а天堂中文在线官网 | 亚洲熟女一区二区三区 | 性做久久久久久久免费看 | 亚洲 欧美 激情 小说 另类 | 在线观看免费人成视频 | 久久久久久久人妻无码中文字幕爆 | 欧美三级a做爰在线观看 | 国产一精品一av一免费 | 天堂久久天堂av色综合 | 两性色午夜免费视频 | 帮老师解开蕾丝奶罩吸乳网站 | 蜜桃视频插满18在线观看 | 久久99热只有频精品8 | 午夜福利试看120秒体验区 | 久久五月精品中文字幕 | 暴力强奷在线播放无码 | 免费国产成人高清在线观看网站 | 女人色极品影院 | 精品国偷自产在线视频 | 日本熟妇乱子伦xxxx | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 国产精品久久国产精品99 | 呦交小u女精品视频 | 玩弄少妇高潮ⅹxxxyw | 国产国产精品人在线视 | 动漫av网站免费观看 | 真人与拘做受免费视频 | 欧美日韩视频无码一区二区三 | 久久久久久久久888 | 国内揄拍国内精品人妻 | 图片区 小说区 区 亚洲五月 | 中文字幕无码av激情不卡 | 日韩欧美中文字幕在线三区 | 亚洲一区二区观看播放 | 1000部夫妻午夜免费 | 久久综合给合久久狠狠狠97色 | a片在线免费观看 | 男女猛烈xx00免费视频试看 | 少妇无码一区二区二三区 | 动漫av网站免费观看 | 国产精品久久久久9999小说 | 日韩人妻无码一区二区三区久久99 | 天堂一区人妻无码 | 荫蒂被男人添的好舒服爽免费视频 | 国产xxx69麻豆国语对白 | 亚洲精品国产精品乱码视色 | 中文字幕av无码一区二区三区电影 | 东京热无码av男人的天堂 | 国产麻豆精品一区二区三区v视界 | 国产在线精品一区二区高清不卡 | 亚洲色成人中文字幕网站 | 亚洲成a人片在线观看无码3d | 色欲人妻aaaaaaa无码 | 国产99久久精品一区二区 | 在线观看欧美一区二区三区 | 国产美女极度色诱视频www | 99久久精品午夜一区二区 | 亚洲 高清 成人 动漫 | 人人妻人人澡人人爽人人精品浪潮 | 日本一区二区更新不卡 | 国产熟妇高潮叫床视频播放 | 狠狠cao日日穞夜夜穞av | 中文字幕无码日韩专区 | 中文字幕av日韩精品一区二区 | 好爽又高潮了毛片免费下载 | 大肉大捧一进一出视频出来呀 | 99久久精品午夜一区二区 | 影音先锋中文字幕无码 | 亚洲乱码日产精品bd | 亚洲综合精品香蕉久久网 | 色老头在线一区二区三区 | 一本精品99久久精品77 | 在线欧美精品一区二区三区 | 欧美 亚洲 国产 另类 | 国产午夜亚洲精品不卡下载 | 亚洲日韩乱码中文无码蜜桃臀网站 | 亚洲国产av精品一区二区蜜芽 | 国产精品对白交换视频 | 国产97在线 | 亚洲 | 国产成人无码一二三区视频 | 午夜精品一区二区三区的区别 | 日韩av无码一区二区三区 | 国产无av码在线观看 | 人人澡人人妻人人爽人人蜜桃 | 偷窥日本少妇撒尿chinese | 中文字幕乱码中文乱码51精品 | 国产亚洲人成a在线v网站 | 精品无码成人片一区二区98 | 麻豆md0077饥渴少妇 | 野外少妇愉情中文字幕 | а√资源新版在线天堂 | 亚洲天堂2017无码中文 | 国精产品一品二品国精品69xx | 国产精品二区一区二区aⅴ污介绍 | 乱人伦人妻中文字幕无码久久网 | 国产成人无码午夜视频在线观看 | 小泽玛莉亚一区二区视频在线 | 国产精品亚洲а∨无码播放麻豆 | 狂野欧美性猛交免费视频 | 麻豆成人精品国产免费 | 少妇高潮一区二区三区99 | 老太婆性杂交欧美肥老太 | 亚洲欧美精品aaaaaa片 | 国产艳妇av在线观看果冻传媒 | 国产成人午夜福利在线播放 | 精品无人国产偷自产在线 | 国产后入清纯学生妹 | 免费乱码人妻系列无码专区 | 人人妻人人澡人人爽欧美一区九九 | 色狠狠av一区二区三区 | 红桃av一区二区三区在线无码av | 伊人久久婷婷五月综合97色 | 久久久久se色偷偷亚洲精品av | 欧美日韩久久久精品a片 | 扒开双腿疯狂进出爽爽爽视频 | 影音先锋中文字幕无码 | 欧美人与禽zoz0性伦交 | 日韩精品无码免费一区二区三区 | 亚洲精品中文字幕乱码 | 性史性农村dvd毛片 | 一本久久a久久精品vr综合 | 双乳奶水饱满少妇呻吟 | 青青青手机频在线观看 | 婷婷丁香六月激情综合啪 | 日韩人妻无码中文字幕视频 | 在线精品亚洲一区二区 | 亚洲日韩精品欧美一区二区 | 成人性做爰aaa片免费看不忠 | 99久久99久久免费精品蜜桃 | 奇米影视888欧美在线观看 | 国产日产欧产精品精品app | 婷婷五月综合激情中文字幕 | 久久综合色之久久综合 | 暴力强奷在线播放无码 | 亚洲春色在线视频 | 中文亚洲成a人片在线观看 | 亚洲成在人网站无码天堂 | 丰满人妻精品国产99aⅴ | 久久久久久亚洲精品a片成人 | 狠狠综合久久久久综合网 | 西西人体www44rt大胆高清 | 天堂在线观看www | 久久久久成人片免费观看蜜芽 | 伊人久久大香线焦av综合影院 | 欧美丰满老熟妇xxxxx性 | 国产成人一区二区三区别 | 久久久久久久久蜜桃 | 人人妻人人澡人人爽欧美精品 | 玩弄少妇高潮ⅹxxxyw | 亚洲一区二区三区无码久久 | 中文字幕乱码中文乱码51精品 | 国产性生交xxxxx无码 | 蜜臀av在线播放 久久综合激激的五月天 | 国产色xx群视频射精 | 欧美大屁股xxxxhd黑色 | 欧美黑人巨大xxxxx | 国产激情艳情在线看视频 | 午夜无码人妻av大片色欲 | 波多野结衣av在线观看 | 性欧美牲交xxxxx视频 | 中文字幕无码日韩欧毛 | 亚洲s色大片在线观看 | 亚洲色欲久久久综合网东京热 | 亚洲天堂2017无码中文 | 亚洲 另类 在线 欧美 制服 | 在教室伦流澡到高潮hnp视频 | 欧美人与物videos另类 | 无码人妻av免费一区二区三区 | 国产亚洲人成a在线v网站 | 欧美三级不卡在线观看 | 国产一区二区三区精品视频 | 国产成人无码a区在线观看视频app | 无码吃奶揉捏奶头高潮视频 | 55夜色66夜色国产精品视频 | 日日橹狠狠爱欧美视频 | 亚洲精品中文字幕久久久久 | 强奷人妻日本中文字幕 | 日韩精品a片一区二区三区妖精 | 欧美老人巨大xxxx做受 | 亚洲日韩av一区二区三区四区 | 十八禁视频网站在线观看 | 狠狠色噜噜狠狠狠7777奇米 | 国产内射爽爽大片视频社区在线 | 蜜臀av在线播放 久久综合激激的五月天 | 日本免费一区二区三区最新 | 久久久久成人精品免费播放动漫 | 日本免费一区二区三区最新 | 国产精品永久免费视频 | 300部国产真实乱 | 日韩视频 中文字幕 视频一区 | 东京无码熟妇人妻av在线网址 | 久久久久久亚洲精品a片成人 | 亚洲区欧美区综合区自拍区 | 大屁股大乳丰满人妻 | 亚洲国产精品一区二区美利坚 | 久久午夜无码鲁丝片午夜精品 | 久久久久久久人妻无码中文字幕爆 | 精品无码一区二区三区的天堂 | 久久久av男人的天堂 | 天天爽夜夜爽夜夜爽 | 亚洲精品成a人在线观看 | 国产精品久久久久无码av色戒 | 97夜夜澡人人爽人人喊中国片 | 久久成人a毛片免费观看网站 | 日本熟妇大屁股人妻 | 色综合视频一区二区三区 | 久久这里只有精品视频9 | 国产乱码精品一品二品 | 97资源共享在线视频 | 中文精品久久久久人妻不卡 | 男女超爽视频免费播放 | 日本成熟视频免费视频 | 色诱久久久久综合网ywww | 四虎国产精品一区二区 | 天天爽夜夜爽夜夜爽 | 国产人成高清在线视频99最全资源 | 精品亚洲成av人在线观看 | 国产乱子伦视频在线播放 | 风流少妇按摩来高潮 | 国産精品久久久久久久 | 青草视频在线播放 | 亚洲国精产品一二二线 | 亚洲精品国偷拍自产在线麻豆 | 国模大胆一区二区三区 | 久久久精品成人免费观看 | 久久久无码中文字幕久... | 久久aⅴ免费观看 | 国产亚av手机在线观看 | 国产女主播喷水视频在线观看 | 精品无码av一区二区三区 | 中国大陆精品视频xxxx | 国产激情无码一区二区 | 无码人妻av免费一区二区三区 | 久久zyz资源站无码中文动漫 | 国产亚洲精品久久久ai换 | 性色欲网站人妻丰满中文久久不卡 | 国产成人无码午夜视频在线观看 | 欧美精品在线观看 | 午夜熟女插插xx免费视频 | 又大又硬又爽免费视频 | 好男人www社区 | 精品人妻人人做人人爽 | 又紧又大又爽精品一区二区 | 国产乡下妇女做爰 | 国产亚洲精品久久久久久国模美 | 精品久久久中文字幕人妻 | 国产精品无码一区二区桃花视频 | 亚洲欧洲中文日韩av乱码 | 老子影院午夜伦不卡 | 日韩欧美中文字幕公布 | 波多野结衣乳巨码无在线观看 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 日本丰满护士爆乳xxxx | 国产国产精品人在线视 | 国产精品亚洲五月天高清 | 奇米影视888欧美在线观看 | 亚洲精品成a人在线观看 | 亚洲精品中文字幕乱码 | 亚洲gv猛男gv无码男同 | av无码久久久久不卡免费网站 | 欧美老熟妇乱xxxxx | 国产色精品久久人妻 | 亚洲日韩一区二区 | 十八禁视频网站在线观看 | 中文字幕人妻丝袜二区 | 日韩精品a片一区二区三区妖精 | 国产无套内射久久久国产 | 丰满人妻一区二区三区免费视频 | 国产一区二区三区精品视频 | 黑人玩弄人妻中文在线 | 黑人玩弄人妻中文在线 | 国精品人妻无码一区二区三区蜜柚 | 国产美女极度色诱视频www | 成人精品一区二区三区中文字幕 | 色婷婷av一区二区三区之红樱桃 | 午夜精品一区二区三区的区别 | 一本大道伊人av久久综合 | 国产农村乱对白刺激视频 | 亚洲欧美日韩综合久久久 | 色综合久久久无码网中文 | 亚洲精品久久久久久一区二区 | 久久久www成人免费毛片 | 久久99精品国产麻豆蜜芽 | 中国女人内谢69xxxxxa片 | 少妇被黑人到高潮喷出白浆 | 国产九九九九九九九a片 | 国产农村妇女高潮大叫 | 国产特级毛片aaaaaa高潮流水 | 国产欧美精品一区二区三区 | 国产乱子伦视频在线播放 | 黑人玩弄人妻中文在线 | 亚洲精品午夜国产va久久成人 | 亚洲精品成人福利网站 | 国内揄拍国内精品少妇国语 | 国产无遮挡又黄又爽又色 | 丝袜 中出 制服 人妻 美腿 | 日本爽爽爽爽爽爽在线观看免 | 精品成在人线av无码免费看 | 女人高潮内射99精品 | 欧美日韩一区二区免费视频 | 乱人伦人妻中文字幕无码久久网 | 久久久中文久久久无码 | 亚洲日韩av片在线观看 | 亚洲自偷精品视频自拍 | 丝袜 中出 制服 人妻 美腿 | 男人的天堂av网站 | 国产激情无码一区二区app | 亚洲国产欧美在线成人 | 精品国产aⅴ无码一区二区 | 免费播放一区二区三区 | 亚洲精品鲁一鲁一区二区三区 | 曰本女人与公拘交酡免费视频 | 国内丰满熟女出轨videos | 亚洲国产欧美国产综合一区 | 国产麻豆精品精东影业av网站 | 三级4级全黄60分钟 | 中文字幕人妻丝袜二区 | 人人澡人人透人人爽 | 粗大的内捧猛烈进出视频 | 久久久精品欧美一区二区免费 | 欧美丰满老熟妇xxxxx性 | 黑人玩弄人妻中文在线 | 在线播放亚洲第一字幕 | 欧美真人作爱免费视频 | 55夜色66夜色国产精品视频 | 亚洲呦女专区 | 大肉大捧一进一出好爽视频 | 亚洲爆乳无码专区 | 激情综合激情五月俺也去 | 国产熟女一区二区三区四区五区 | 图片区 小说区 区 亚洲五月 | 麻豆精品国产精华精华液好用吗 | 亚洲精品国偷拍自产在线观看蜜桃 | 老熟女重囗味hdxx69 | 成人欧美一区二区三区黑人免费 | 国产精品国产自线拍免费软件 | 老熟女乱子伦 | 欧美人妻一区二区三区 | 好男人www社区 | 美女极度色诱视频国产 | 亚洲国产av精品一区二区蜜芽 | 人人超人人超碰超国产 | 亚洲国产精品无码久久久久高潮 | 在线 国产 欧美 亚洲 天堂 | 亚洲 另类 在线 欧美 制服 | 牲欲强的熟妇农村老妇女视频 | 久久精品视频在线看15 | 天堂无码人妻精品一区二区三区 | 国产麻豆精品一区二区三区v视界 | 在线精品国产一区二区三区 | 国产精品无码久久av | 日本va欧美va欧美va精品 | 日日碰狠狠躁久久躁蜜桃 | 98国产精品综合一区二区三区 | 国产精品自产拍在线观看 | 色综合久久久久综合一本到桃花网 | 国产又爽又黄又刺激的视频 | 久久久婷婷五月亚洲97号色 | 成人女人看片免费视频放人 | 狠狠亚洲超碰狼人久久 | 久久久久久国产精品无码下载 | 久青草影院在线观看国产 | 国产亲子乱弄免费视频 | 国产乱码精品一品二品 | 精品人妻av区 | 高中生自慰www网站 | 久久久婷婷五月亚洲97号色 | 九一九色国产 | 欧美日韩综合一区二区三区 | 国产高清不卡无码视频 | 精品亚洲成av人在线观看 | 88国产精品欧美一区二区三区 | 亚拍精品一区二区三区探花 | 国产精品久久久av久久久 | 日韩精品乱码av一区二区 | 免费人成网站视频在线观看 | 人人妻人人藻人人爽欧美一区 | 亚洲欧洲中文日韩av乱码 | 无码人妻精品一区二区三区下载 | 久久久久久久女国产乱让韩 | 日本免费一区二区三区最新 | 国产另类ts人妖一区二区 | 国产精品久久久久久亚洲毛片 | 中文字幕无码日韩欧毛 | v一区无码内射国产 | 人人妻人人澡人人爽欧美一区九九 | 在线观看国产午夜福利片 | 国产真人无遮挡作爱免费视频 | 中文字幕人妻无码一区二区三区 | 国产午夜亚洲精品不卡 | 东京热一精品无码av | 激情五月综合色婷婷一区二区 | 欧美自拍另类欧美综合图片区 | 人妻无码αv中文字幕久久琪琪布 | 伊人色综合久久天天小片 | 欧美国产日韩亚洲中文 | 国产精品沙发午睡系列 | 红桃av一区二区三区在线无码av | 红桃av一区二区三区在线无码av | 全球成人中文在线 | 奇米影视888欧美在线观看 | 欧美熟妇另类久久久久久不卡 | 亚洲一区av无码专区在线观看 | 欧美兽交xxxx×视频 | 亚洲狠狠婷婷综合久久 | 亚洲国产精品久久人人爱 | 国产综合色产在线精品 | 国产av久久久久精东av | 噜噜噜亚洲色成人网站 | 亚洲国产成人av在线观看 | 老熟妇乱子伦牲交视频 | 亚洲国产成人av在线观看 | 亚洲中文无码av永久不收费 | 久久久久亚洲精品男人的天堂 | 又大又黄又粗又爽的免费视频 | 精品国产精品久久一区免费式 | 人人爽人人爽人人片av亚洲 | 色偷偷人人澡人人爽人人模 | 久久精品国产一区二区三区 | 色综合久久久久综合一本到桃花网 | 大乳丰满人妻中文字幕日本 | 久久综合给久久狠狠97色 | 无套内谢的新婚少妇国语播放 | 亚洲综合在线一区二区三区 | 国内精品久久毛片一区二区 | 久久久精品欧美一区二区免费 | 少妇愉情理伦片bd | 四虎影视成人永久免费观看视频 | 成 人 免费观看网站 | 无码乱肉视频免费大全合集 | 欧美阿v高清资源不卡在线播放 | 色综合久久久久综合一本到桃花网 | 一个人看的www免费视频在线观看 | 欧美日韩人成综合在线播放 | 澳门永久av免费网站 | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 午夜精品一区二区三区的区别 | 日韩无码专区 | 中文字幕无码av激情不卡 | 午夜福利不卡在线视频 | aⅴ亚洲 日韩 色 图网站 播放 | 成人影院yy111111在线观看 | 久久国产精品二国产精品 | 亚洲码国产精品高潮在线 | 台湾无码一区二区 | 亚洲高清偷拍一区二区三区 | 亚洲理论电影在线观看 | 真人与拘做受免费视频一 | 少妇久久久久久人妻无码 | 精品无码一区二区三区爱欲 | 在线精品亚洲一区二区 | 成人亚洲精品久久久久 | 欧美日韩视频无码一区二区三 | 在线观看国产一区二区三区 | 亚洲国产精品无码一区二区三区 | 人妻与老人中文字幕 | 丝袜美腿亚洲一区二区 | 亚洲成熟女人毛毛耸耸多 | 亚洲精品一区二区三区婷婷月 | 国产午夜视频在线观看 | 亚洲中文字幕在线观看 | 国产精品久久久午夜夜伦鲁鲁 | 国产精品亚洲а∨无码播放麻豆 | 欧美性黑人极品hd | 97精品人妻一区二区三区香蕉 | 久久精品国产99久久6动漫 | 亚洲成av人片天堂网无码】 | 欧美丰满熟妇xxxx性ppx人交 | 国内精品一区二区三区不卡 | 白嫩日本少妇做爰 | 丰满肥臀大屁股熟妇激情视频 | 精品水蜜桃久久久久久久 | 亚洲国产精品无码一区二区三区 | 超碰97人人射妻 | 俄罗斯老熟妇色xxxx | 国产性猛交╳xxx乱大交 国产精品久久久久久无码 欧洲欧美人成视频在线 | 丝袜足控一区二区三区 | 亚洲精品国产第一综合99久久 | 国产成人无码区免费内射一片色欲 | 亚洲狠狠色丁香婷婷综合 | 久久久久久av无码免费看大片 | 精品久久久久久亚洲精品 | 欧美肥老太牲交大战 | 好爽又高潮了毛片免费下载 | 亚洲成av人影院在线观看 | 无码人妻精品一区二区三区下载 | 欧美一区二区三区 | 国产九九九九九九九a片 | 亚洲精品久久久久久久久久久 | 激情内射日本一区二区三区 | 青青草原综合久久大伊人精品 | 亚洲精品成人福利网站 | 中文字幕无码人妻少妇免费 | 久久国产精品_国产精品 | 国产又爽又黄又刺激的视频 | 国产精品无码一区二区三区不卡 | 国产熟妇高潮叫床视频播放 | 日本护士毛茸茸高潮 | 少妇久久久久久人妻无码 | 麻豆国产97在线 | 欧洲 | 网友自拍区视频精品 | 久9re热视频这里只有精品 | 激情内射日本一区二区三区 | 无码帝国www无码专区色综合 | 国产精品美女久久久网av | 无码人妻丰满熟妇区毛片18 | 成熟人妻av无码专区 | 亚洲国产精品无码一区二区三区 | 国产av剧情md精品麻豆 | 婷婷综合久久中文字幕蜜桃三电影 | 麻豆md0077饥渴少妇 | 综合网日日天干夜夜久久 | 欧美人与禽猛交狂配 | 国产成人久久精品流白浆 | 欧美35页视频在线观看 | а天堂中文在线官网 | 久久久国产一区二区三区 | 免费观看激色视频网站 | 国产精品久久久 | 中文字幕乱码人妻无码久久 | 一个人免费观看的www视频 | 国产精品丝袜黑色高跟鞋 | 日本欧美一区二区三区乱码 | 女人被男人爽到呻吟的视频 | 红桃av一区二区三区在线无码av | 一本一道久久综合久久 | 日本精品高清一区二区 | 亚洲国产精品久久人人爱 | 国精产品一品二品国精品69xx | 中文字幕无线码 | 高中生自慰www网站 | 国产色精品久久人妻 | 熟妇人妻无码xxx视频 | 无码一区二区三区在线观看 | 久久亚洲中文字幕精品一区 | 少妇激情av一区二区 | 亚洲综合无码一区二区三区 | 色综合久久88色综合天天 | 在教室伦流澡到高潮hnp视频 | 亚洲国产日韩a在线播放 | 十八禁真人啪啪免费网站 | 无码国产色欲xxxxx视频 | 国产精品亚洲一区二区三区喷水 | 一本大道伊人av久久综合 | 久久久精品欧美一区二区免费 | 中文精品久久久久人妻不卡 | 亚洲成a人片在线观看无码 | 婷婷丁香五月天综合东京热 | 亚洲色欲久久久综合网东京热 | 国产精品丝袜黑色高跟鞋 | 76少妇精品导航 | 日本熟妇乱子伦xxxx | 少妇人妻av毛片在线看 | 婷婷综合久久中文字幕蜜桃三电影 | 亚洲色www成人永久网址 | 秋霞成人午夜鲁丝一区二区三区 | 麻豆av传媒蜜桃天美传媒 | 久激情内射婷内射蜜桃人妖 | 美女毛片一区二区三区四区 | 精品一区二区不卡无码av | 免费观看又污又黄的网站 | 久久无码人妻影院 | 四虎影视成人永久免费观看视频 | 伊人久久婷婷五月综合97色 | 欧美 亚洲 国产 另类 | 欧美乱妇无乱码大黄a片 | 精品一区二区三区波多野结衣 | 亚洲精品一区二区三区婷婷月 | 无码人妻黑人中文字幕 | 乱码午夜-极国产极内射 | 无码国产色欲xxxxx视频 | аⅴ资源天堂资源库在线 | 久久久久成人精品免费播放动漫 | 一个人免费观看的www视频 | 亚洲成色在线综合网站 | 亚洲乱亚洲乱妇50p | 国产真人无遮挡作爱免费视频 | 国产精品无码成人午夜电影 | 国产另类ts人妖一区二区 | 久久国产自偷自偷免费一区调 | 中文字幕av无码一区二区三区电影 | 久久精品99久久香蕉国产色戒 | 嫩b人妻精品一区二区三区 | 老子影院午夜精品无码 | 色综合久久久无码网中文 | 日日摸天天摸爽爽狠狠97 | 亚洲色偷偷男人的天堂 | 熟妇人妻中文av无码 | 久久综合网欧美色妞网 | 亚洲 a v无 码免 费 成 人 a v | 国产亚洲人成在线播放 | 国产黄在线观看免费观看不卡 | 亚洲国产av精品一区二区蜜芽 | 性色欲网站人妻丰满中文久久不卡 | 狠狠色欧美亚洲狠狠色www | 亚洲 激情 小说 另类 欧美 | 欧美成人免费全部网站 | 亚洲精品一区二区三区在线观看 | 国产精品va在线观看无码 | 精品久久久无码人妻字幂 | 熟妇人妻无乱码中文字幕 | 国内揄拍国内精品人妻 | 97精品国产97久久久久久免费 | 亚洲欧美日韩综合久久久 | 精品国产乱码久久久久乱码 | 国产 精品 自在自线 | 帮老师解开蕾丝奶罩吸乳网站 | av香港经典三级级 在线 | 最近中文2019字幕第二页 | 熟女少妇在线视频播放 | 日韩av无码一区二区三区 | 精品国产国产综合精品 | 欧美xxxx黑人又粗又长 | 国产精品二区一区二区aⅴ污介绍 | 国产9 9在线 | 中文 | 亚洲一区二区三区偷拍女厕 | 久久亚洲中文字幕精品一区 | 久久综合久久自在自线精品自 | 日日躁夜夜躁狠狠躁 | 日本精品高清一区二区 | 国产成人精品三级麻豆 | 国内精品久久久久久中文字幕 | av人摸人人人澡人人超碰下载 | 四十如虎的丰满熟妇啪啪 | 日本熟妇人妻xxxxx人hd | 亚洲一区二区三区无码久久 | 无码人妻精品一区二区三区下载 | 国产 浪潮av性色四虎 | 久久精品中文字幕一区 | 久久精品国产一区二区三区肥胖 | 午夜精品久久久久久久 | 国产九九九九九九九a片 | 国产凸凹视频一区二区 | 麻豆av传媒蜜桃天美传媒 | 又粗又大又硬又长又爽 | 欧美精品一区二区精品久久 | 中文字幕人妻丝袜二区 | 亚洲欧洲日本无在线码 | 国产婷婷色一区二区三区在线 | 亚洲人成网站在线播放942 |