SDL2源代碼分析3:渲染器(SDL_Renderer)

=====================================================

SDL源代碼分析系列文章列表:

SDL2源代碼分析1:初始化(SDL_Init())

SDL2源代碼分析2:窗口(SDL_Window)

SDL2源代碼分析3:渲染器(SDL_Renderer)

SDL2源代碼分析4:紋理(SDL_Texture)

SDL2源代碼分析5:更新紋理(SDL_UpdateTexture())

SDL2源代碼分析6:複製到渲染器(SDL_RenderCopy())

SDL2源代碼分析7:顯示(SDL_RenderPresent())

SDL2源代碼分析8:視頻顯示總結

=====================================================


上一篇文章分析了SDL中創建窗口的函數SDL_CreateWindow()。這篇文章繼續分析SDL的源代碼。本文分析SDL的渲染器(SDL_Renderer)。



SDL播放視頻的代碼流程如下所示。

初始化: 
SDL_Init(): 初始化SDL。 
SDL_CreateWindow(): 創建窗口(Window)。 
SDL_CreateRenderer(): 基於窗口創建渲染器(Render)。 
SDL_CreateTexture(): 創建紋理(Texture)。 
循環渲染數據: 
SDL_UpdateTexture(): 設置紋理的數據。 
SDL_RenderCopy(): 紋理複製給渲染器。 

SDL_RenderPresent(): 顯示。

上篇文章分析了該流程中的第2個函數SDL_CreateWindow()。本文繼續分析該流程中的第3個函數SDL_CreateRenderer()。

SDL_Renderer

SDL_Renderer結構體定義了一個SDL2中的渲染器。如果直接使用SDL2編譯好的SDK的話,是看不到它的內部結構的。有關它的定義在頭文件中只有一行代碼,如下所示。

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. /** 
  2.  *  \brief A structure representing rendering state 
  3.  */  
  4. struct SDL_Renderer;  
  5. typedef struct SDL_Renderer SDL_Renderer;  

在源代碼工程中可以看到SDL_Renderer的定義,位於render\SDL_sysrender.h文件中。它的定義如下。

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. /* Define the SDL renderer structure */  
  2. struct SDL_Renderer  
  3. {  
  4.     const void *magic;  
  5.   
  6.   
  7.     void (*WindowEvent) (SDL_Renderer * renderer, const SDL_WindowEvent *event);  
  8.     int (*GetOutputSize) (SDL_Renderer * renderer, int *w, int *h);  
  9.     int (*CreateTexture) (SDL_Renderer * renderer, SDL_Texture * texture);  
  10.     int (*SetTextureColorMod) (SDL_Renderer * renderer,  
  11.                                SDL_Texture * texture);  
  12.     int (*SetTextureAlphaMod) (SDL_Renderer * renderer,  
  13.                                SDL_Texture * texture);  
  14.     int (*SetTextureBlendMode) (SDL_Renderer * renderer,  
  15.                                 SDL_Texture * texture);  
  16.     int (*UpdateTexture) (SDL_Renderer * renderer, SDL_Texture * texture,  
  17.                           const SDL_Rect * rect, const void *pixels,  
  18.                           int pitch);  
  19.     int (*UpdateTextureYUV) (SDL_Renderer * renderer, SDL_Texture * texture,  
  20.                             const SDL_Rect * rect,  
  21.                             const Uint8 *Yplane, int Ypitch,  
  22.                             const Uint8 *Uplane, int Upitch,  
  23.                             const Uint8 *Vplane, int Vpitch);  
  24.     int (*LockTexture) (SDL_Renderer * renderer, SDL_Texture * texture,  
  25.                         const SDL_Rect * rect, void **pixels, int *pitch);  
  26.     void (*UnlockTexture) (SDL_Renderer * renderer, SDL_Texture * texture);  
  27.     int (*SetRenderTarget) (SDL_Renderer * renderer, SDL_Texture * texture);  
  28.     int (*UpdateViewport) (SDL_Renderer * renderer);  
  29.     int (*UpdateClipRect) (SDL_Renderer * renderer);  
  30.     int (*RenderClear) (SDL_Renderer * renderer);  
  31.     int (*RenderDrawPoints) (SDL_Renderer * renderer, const SDL_FPoint * points,  
  32.                              int count);  
  33.     int (*RenderDrawLines) (SDL_Renderer * renderer, const SDL_FPoint * points,  
  34.                             int count);  
  35.     int (*RenderFillRects) (SDL_Renderer * renderer, const SDL_FRect * rects,  
  36.                             int count);  
  37.     int (*RenderCopy) (SDL_Renderer * renderer, SDL_Texture * texture,  
  38.                        const SDL_Rect * srcrect, const SDL_FRect * dstrect);  
  39.     int (*RenderCopyEx) (SDL_Renderer * renderer, SDL_Texture * texture,  
  40.                        const SDL_Rect * srcquad, const SDL_FRect * dstrect,  
  41.                        const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip);  
  42.     int (*RenderReadPixels) (SDL_Renderer * renderer, const SDL_Rect * rect,  
  43.                              Uint32 format, void * pixels, int pitch);  
  44.     void (*RenderPresent) (SDL_Renderer * renderer);  
  45.     void (*DestroyTexture) (SDL_Renderer * renderer, SDL_Texture * texture);  
  46.   
  47.   
  48.     void (*DestroyRenderer) (SDL_Renderer * renderer);  
  49.   
  50.   
  51.     int (*GL_BindTexture) (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh);  
  52.     int (*GL_UnbindTexture) (SDL_Renderer * renderer, SDL_Texture *texture);  
  53.   
  54.   
  55.     /* The current renderer info */  
  56.     SDL_RendererInfo info;  
  57.   
  58.   
  59.     /* The window associated with the renderer */  
  60.     SDL_Window *window;  
  61.     SDL_bool hidden;  
  62.   
  63.   
  64.     /* The logical resolution for rendering */  
  65.     int logical_w;  
  66.     int logical_h;  
  67.     int logical_w_backup;  
  68.     int logical_h_backup;  
  69.   
  70.   
  71.     /* The drawable area within the window */  
  72.     SDL_Rect viewport;  
  73.     SDL_Rect viewport_backup;  
  74.   
  75.   
  76.     /* The clip rectangle within the window */  
  77.     SDL_Rect clip_rect;  
  78.     SDL_Rect clip_rect_backup;  
  79.   
  80.   
  81.     /* The render output coordinate scale */  
  82.     SDL_FPoint scale;  
  83.     SDL_FPoint scale_backup;  
  84.   
  85.   
  86.     /* The list of textures */  
  87.     SDL_Texture *textures;  
  88.     SDL_Texture *target;  
  89.   
  90.   
  91.     Uint8 r, g, b, a;                   /**< Color for drawing operations values */  
  92.     SDL_BlendMode blendMode;            /**< The drawing blend mode */  
  93.   
  94.   
  95.     void *driverdata;  
  96. };  

通過代碼可以看出其中包含了一個“渲染器”應該包含的各種屬性。這個結構體中的各個變量還沒有深入研究,暫不詳細分析。下面來看看如何創建這個SDL_Renderer。


SDL_CreateRenderer()

函數簡介

SDL中使用SDL_CreateRenderer()基於窗口創建渲染器。SDL_CreateRenderer()原型如下。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. SDL_Renderer * SDLCALL SDL_CreateRenderer(SDL_Window * window,  
  2.                                                int index, Uint32 flags);  

參數含義如下。

window : 渲染的目標窗口。

index :打算初始化的渲染設備的索引。設置“-1”則初始化默認的渲染設備。

flags :支持以下值(位於SDL_RendererFlags定義中)

    SDL_RENDERER_SOFTWARE :使用軟件渲染

    SDL_RENDERER_ACCELERATED :使用硬件加速

    SDL_RENDERER_PRESENTVSYNC:和顯示器的刷新率同步

    SDL_RENDERER_TARGETTEXTURE :不太懂

返回創建完成的渲染器的ID。如果創建失敗則返回NULL。


函數調用關係圖

SDL_CreateRenderer()關鍵函數的調用關係可以用下圖表示。


上述圖片不太清晰,相冊裏面上傳了一份原始的大圖片:

http://my.csdn.net/leixiaohua1020/album/detail/1793385

打開上述相冊裏面的圖片,右鍵選擇“另存爲”即可保存原始圖片。


源碼分析

SDL_CreateRenderer()的源代碼位於render\SDL_render.c中,如下所示。

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. SDL_Renderer * SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags)  
  2. {  
  3. #if !SDL_RENDER_DISABLED  
  4.     SDL_Renderer *renderer = NULL;  
  5.     int n = SDL_GetNumRenderDrivers();  
  6.     const char *hint;  
  7.   
  8.   
  9.     if (!window) {  
  10.         SDL_SetError("Invalid window");  
  11.         return NULL;  
  12.     }  
  13.   
  14.   
  15.     if (SDL_GetRenderer(window)) {  
  16.         SDL_SetError("Renderer already associated with window");  
  17.         return NULL;  
  18.     }  
  19.   
  20.   
  21.     hint = SDL_GetHint(SDL_HINT_RENDER_VSYNC);  
  22.     if (hint) {  
  23.         if (*hint == '0') {  
  24.             flags &= ~SDL_RENDERER_PRESENTVSYNC;  
  25.         } else {  
  26.             flags |= SDL_RENDERER_PRESENTVSYNC;  
  27.         }  
  28.     }  
  29.   
  30.   
  31.     if (index < 0) {  
  32.         hint = SDL_GetHint(SDL_HINT_RENDER_DRIVER);  
  33.         if (hint) {  
  34.             for (index = 0; index < n; ++index) {  
  35.                 const SDL_RenderDriver *driver = render_drivers[index];  
  36.   
  37.   
  38.                 if (SDL_strcasecmp(hint, driver->info.name) == 0) {  
  39.                     /* Create a new renderer instance */  
  40.                     renderer = driver->CreateRenderer(window, flags);  
  41.                     break;  
  42.                 }  
  43.             }  
  44.         }  
  45.   
  46.   
  47.         if (!renderer) {  
  48.             for (index = 0; index < n; ++index) {  
  49.                 const SDL_RenderDriver *driver = render_drivers[index];  
  50.   
  51.   
  52.                 if ((driver->info.flags & flags) == flags) {  
  53.                     /* Create a new renderer instance */  
  54.                     renderer = driver->CreateRenderer(window, flags);  
  55.                     if (renderer) {  
  56.                         /* Yay, we got one! */  
  57.                         break;  
  58.                     }  
  59.                 }  
  60.             }  
  61.         }  
  62.         if (index == n) {  
  63.             SDL_SetError("Couldn't find matching render driver");  
  64.             return NULL;  
  65.         }  
  66.     } else {  
  67.         if (index >= SDL_GetNumRenderDrivers()) {  
  68.             SDL_SetError("index must be -1 or in the range of 0 - %d",  
  69.                          SDL_GetNumRenderDrivers() - 1);  
  70.             return NULL;  
  71.         }  
  72.         /* Create a new renderer instance */  
  73.         renderer = render_drivers[index]->CreateRenderer(window, flags);  
  74.     }  
  75.   
  76.   
  77.     if (renderer) {  
  78.         renderer->magic = &renderer_magic;  
  79.         renderer->window = window;  
  80.         renderer->scale.x = 1.0f;  
  81.         renderer->scale.y = 1.0f;  
  82.   
  83.   
  84.         if (SDL_GetWindowFlags(window) & (SDL_WINDOW_HIDDEN|SDL_WINDOW_MINIMIZED)) {  
  85.             renderer->hidden = SDL_TRUE;  
  86.         } else {  
  87.             renderer->hidden = SDL_FALSE;  
  88.         }  
  89.   
  90.   
  91.         SDL_SetWindowData(window, SDL_WINDOWRENDERDATA, renderer);  
  92.   
  93.   
  94.         SDL_RenderSetViewport(renderer, NULL);  
  95.   
  96.   
  97.         SDL_AddEventWatch(SDL_RendererEventWatch, renderer);  
  98.   
  99.   
  100.         SDL_LogInfo(SDL_LOG_CATEGORY_RENDER,  
  101.                     "Created renderer: %s", renderer->info.name);  
  102.     }  
  103.     return renderer;  
  104. #else  
  105.     SDL_SetError("SDL not built with rendering support");  
  106.     return NULL;  
  107. #endif  
  108. }  

SDL_CreateRenderer()中最重要的一個函數就是它調用了SDL_RenderDriver的CreateRenderer()方法。通過該方法可以創建一個渲染器。圍繞着這個方法,包含了一些初始化工作以及一些收尾工作。下面針對這個最核心的函數進行分析。
我們首先來看一下SDL_RenderDriver這個結構體。從字面的意思可以看出它代表了“渲染器的驅動程序”。這個結構體的定義如下。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. /* Define the SDL render driver structure */  
  2. struct SDL_RenderDriver  
  3. {  
  4.     SDL_Renderer *(*CreateRenderer) (SDL_Window * window, Uint32 flags);  
  5.   
  6.   
  7.     /* Info about the renderer capabilities */  
  8.     SDL_RendererInfo info;  
  9. };  

從代碼中可以看出,這個結構體的成員比較簡單,包含了一個函數指針CreateRenderer()和一個存儲信息的SDL_RendererInfo類型的結構體info。CreateRenderer()是用於創建渲染器的函數,而SDL_RendererInfo則包含了該結構體的一些信息,可以看一下SDL_RendererInfo的定義。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. /** 
  2.  *  \brief Information on the capabilities of a render driver or context. 
  3.  */  
  4. typedef struct SDL_RendererInfo  
  5. {  
  6.     const char *name;           /**< The name of the renderer */  
  7.     Uint32 flags;               /**< Supported ::SDL_RendererFlags */  
  8.     Uint32 num_texture_formats; /**< The number of available texture formats */  
  9.     Uint32 texture_formats[16]; /**< The available texture formats */  
  10.     int max_texture_width;      /**< The maximimum texture width */  
  11.     int max_texture_height;     /**< The maximimum texture height */  
  12. } SDL_RendererInfo;  

在SDL中有一個全局的SDL_RenderDriver類型的靜態數組render_drivers,其中存儲了SDL支持的所有渲染器。該數組定義如下。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. static const SDL_RenderDriver *render_drivers[] = {  
  2. #if SDL_VIDEO_RENDER_D3D  
  3.     &D3D_RenderDriver,  
  4. #endif  
  5. #if SDL_VIDEO_RENDER_D3D11  
  6.     &D3D11_RenderDriver,  
  7. #endif  
  8. #if SDL_VIDEO_RENDER_OGL  
  9.     &GL_RenderDriver,  
  10. #endif  
  11. #if SDL_VIDEO_RENDER_OGL_ES2  
  12.     &GLES2_RenderDriver,  
  13. #endif  
  14. #if SDL_VIDEO_RENDER_OGL_ES  
  15.     &GLES_RenderDriver,  
  16. #endif  
  17. #if SDL_VIDEO_RENDER_DIRECTFB  
  18.     &DirectFB_RenderDriver,  
  19. #endif  
  20. #if SDL_VIDEO_RENDER_PSP  
  21.     &PSP_RenderDriver,  
  22. #endif  
  23.     &SW_RenderDriver  
  24. };  

從render_drivers數組的定義可以看出,其中包含了Direct3D,OpenGL,OpenGL ES等各種渲染器的驅動程序。我們可以選擇幾個看一下。
例如Direct3D的渲染器驅動程序D3D_RenderDriver的定義如下(位於render\direct3d\SDL_render_d3d.c)。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. SDL_RenderDriver D3D_RenderDriver = {  
  2.     D3D_CreateRenderer,  
  3.     {  
  4.      "direct3d",  
  5.      (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),  
  6.      1,  
  7.      {SDL_PIXELFORMAT_ARGB8888},  
  8.      0,  
  9.      0}  
  10. };  

可以看出創建Direct3D渲染器的函數是D3D_CreateRenderer()。

OpenGL的渲染器驅動程序GL_RenderDriver的定義如下(位於render\opengl\SDL_render_gl.c)。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. SDL_RenderDriver GL_RenderDriver = {  
  2.     GL_CreateRenderer,  
  3.     {  
  4.      "opengl",  
  5.      (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),  
  6.      1,  
  7.      {SDL_PIXELFORMAT_ARGB8888},  
  8.      0,  
  9.      0}  
  10. };  

可以看出創建OpenGL渲染器的函數是GL_CreateRenderer()。


軟件渲染器驅動程序SW_RenderDriver的定義如下(位於render\software\SDL_render_sw.c)。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. SDL_RenderDriver SW_RenderDriver = {  
  2.     SW_CreateRenderer,  
  3.     {  
  4.      "software",  
  5.      SDL_RENDERER_SOFTWARE | SDL_RENDERER_TARGETTEXTURE,  
  6.      8,  
  7.      {  
  8.       SDL_PIXELFORMAT_RGB555,  
  9.       SDL_PIXELFORMAT_RGB565,  
  10.       SDL_PIXELFORMAT_RGB888,  
  11.       SDL_PIXELFORMAT_BGR888,  
  12.       SDL_PIXELFORMAT_ARGB8888,  
  13.       SDL_PIXELFORMAT_RGBA8888,  
  14.       SDL_PIXELFORMAT_ABGR8888,  
  15.       SDL_PIXELFORMAT_BGRA8888  
  16.      },  
  17.      0,  
  18.      0}  
  19. };  

可以看出創建軟件渲染器的函數是SW_CreateRenderer ()。


有關SDL_RenderDriver這個結構體就不再多說了。下面分別看一下Direct3D,OpenGL,Software這三種最常見的渲染器的創建方法。

1. Direct3D

Direct3D 的渲染器在創建函數是D3D_CreateRenderer()。該函數位於render\direct3d\SDL_render_d3d.c文件中。首先看一下它的代碼。

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. SDL_Renderer * D3D_CreateRenderer(SDL_Window * window, Uint32 flags)  
  2. {  
  3.     SDL_Renderer *renderer;  
  4.     D3D_RenderData *data;  
  5.     SDL_SysWMinfo windowinfo;  
  6.     HRESULT result;  
  7.     const char *hint;  
  8.     D3DPRESENT_PARAMETERS pparams;  
  9.     IDirect3DSwapChain9 *chain;  
  10.     D3DCAPS9 caps;  
  11.     DWORD device_flags;  
  12.     Uint32 window_flags;  
  13.     int w, h;  
  14.     SDL_DisplayMode fullscreen_mode;  
  15.     int displayIndex;  
  16.   
  17.   
  18.     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));  
  19.     if (!renderer) {  
  20.         SDL_OutOfMemory();  
  21.         return NULL;  
  22.     }  
  23.   
  24.   
  25.     data = (D3D_RenderData *) SDL_calloc(1, sizeof(*data));  
  26.     if (!data) {  
  27.         SDL_free(renderer);  
  28.         SDL_OutOfMemory();  
  29.         return NULL;  
  30.     }  
  31.   
  32.   
  33.     if (!D3D_LoadDLL(&data->d3dDLL, &data->d3d)) {  
  34.         SDL_free(renderer);  
  35.         SDL_free(data);  
  36.         SDL_SetError("Unable to create Direct3D interface");  
  37.         return NULL;  
  38.     }  
  39.   
  40.   
  41.     renderer->WindowEvent = D3D_WindowEvent;  
  42.     renderer->CreateTexture = D3D_CreateTexture;  
  43.     renderer->UpdateTexture = D3D_UpdateTexture;  
  44.     renderer->UpdateTextureYUV = D3D_UpdateTextureYUV;  
  45.     renderer->LockTexture = D3D_LockTexture;  
  46.     renderer->UnlockTexture = D3D_UnlockTexture;  
  47.     renderer->SetRenderTarget = D3D_SetRenderTarget;  
  48.     renderer->UpdateViewport = D3D_UpdateViewport;  
  49.     renderer->UpdateClipRect = D3D_UpdateClipRect;  
  50.     renderer->RenderClear = D3D_RenderClear;  
  51.     renderer->RenderDrawPoints = D3D_RenderDrawPoints;  
  52.     renderer->RenderDrawLines = D3D_RenderDrawLines;  
  53.     renderer->RenderFillRects = D3D_RenderFillRects;  
  54.     renderer->RenderCopy = D3D_RenderCopy;  
  55.     renderer->RenderCopyEx = D3D_RenderCopyEx;  
  56.     renderer->RenderReadPixels = D3D_RenderReadPixels;  
  57.     renderer->RenderPresent = D3D_RenderPresent;  
  58.     renderer->DestroyTexture = D3D_DestroyTexture;  
  59.     renderer->DestroyRenderer = D3D_DestroyRenderer;  
  60.     renderer->info = D3D_RenderDriver.info;  
  61.     renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);  
  62.     renderer->driverdata = data;  
  63.   
  64.   
  65.     SDL_VERSION(&windowinfo.version);  
  66.     SDL_GetWindowWMInfo(window, &windowinfo);  
  67.   
  68.   
  69.     window_flags = SDL_GetWindowFlags(window);  
  70.     SDL_GetWindowSize(window, &w, &h);  
  71.     SDL_GetWindowDisplayMode(window, &fullscreen_mode);  
  72.   
  73.   
  74.     SDL_zero(pparams);  
  75.     pparams.hDeviceWindow = windowinfo.info.win.window;  
  76.     pparams.BackBufferWidth = w;  
  77.     pparams.BackBufferHeight = h;  
  78.     if (window_flags & SDL_WINDOW_FULLSCREEN) {  
  79.         pparams.BackBufferFormat =  
  80.             PixelFormatToD3DFMT(fullscreen_mode.format);  
  81.     } else {  
  82.         pparams.BackBufferFormat = D3DFMT_UNKNOWN;  
  83.     }  
  84.     pparams.BackBufferCount = 1;  
  85.     pparams.SwapEffect = D3DSWAPEFFECT_DISCARD;  
  86.   
  87.   
  88.     if (window_flags & SDL_WINDOW_FULLSCREEN) {  
  89.         if ((window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP)  {  
  90.             pparams.Windowed = TRUE;  
  91.             pparams.FullScreen_RefreshRateInHz = 0;  
  92.         } else {  
  93.             pparams.Windowed = FALSE;  
  94.             pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate;  
  95.         }  
  96.     } else {  
  97.         pparams.Windowed = TRUE;  
  98.         pparams.FullScreen_RefreshRateInHz = 0;  
  99.     }  
  100.     if (flags & SDL_RENDERER_PRESENTVSYNC) {  
  101.         pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;  
  102.     } else {  
  103.         pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;  
  104.     }  
  105.   
  106.   
  107.     /* Get the adapter for the display that the window is on */  
  108.     displayIndex = SDL_GetWindowDisplayIndex(window);  
  109.     data->adapter = SDL_Direct3D9GetAdapterIndex(displayIndex);  
  110.   
  111.   
  112.     IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps);  
  113.   
  114.   
  115.     device_flags = D3DCREATE_FPU_PRESERVE;  
  116.     if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) {  
  117.         device_flags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;  
  118.     } else {  
  119.         device_flags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;  
  120.     }  
  121.   
  122.   
  123.     hint = SDL_GetHint(SDL_HINT_RENDER_DIRECT3D_THREADSAFE);  
  124.     if (hint && SDL_atoi(hint)) {  
  125.         device_flags |= D3DCREATE_MULTITHREADED;  
  126.     }  
  127.   
  128.   
  129.     result = IDirect3D9_CreateDevice(data->d3d, data->adapter,  
  130.                                      D3DDEVTYPE_HAL,  
  131.                                      pparams.hDeviceWindow,  
  132.                                      device_flags,  
  133.                                      &pparams, &data->device);  
  134.     if (FAILED(result)) {  
  135.         D3D_DestroyRenderer(renderer);  
  136.         D3D_SetError("CreateDevice()", result);  
  137.         return NULL;  
  138.     }  
  139.   
  140.   
  141.     /* Get presentation parameters to fill info */  
  142.     result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain);  
  143.     if (FAILED(result)) {  
  144.         D3D_DestroyRenderer(renderer);  
  145.         D3D_SetError("GetSwapChain()", result);  
  146.         return NULL;  
  147.     }  
  148.     result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams);  
  149.     if (FAILED(result)) {  
  150.         IDirect3DSwapChain9_Release(chain);  
  151.         D3D_DestroyRenderer(renderer);  
  152.         D3D_SetError("GetPresentParameters()", result);  
  153.         return NULL;  
  154.     }  
  155.     IDirect3DSwapChain9_Release(chain);  
  156.     if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) {  
  157.         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;  
  158.     }  
  159.     data->pparams = pparams;  
  160.   
  161.   
  162.     IDirect3DDevice9_GetDeviceCaps(data->device, &caps);  
  163.     renderer->info.max_texture_width = caps.MaxTextureWidth;  
  164.     renderer->info.max_texture_height = caps.MaxTextureHeight;  
  165.     if (caps.NumSimultaneousRTs >= 2) {  
  166.         renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;  
  167.     }  
  168.   
  169.   
  170.     if (caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) {  
  171.         data->enableSeparateAlphaBlend = SDL_TRUE;  
  172.     }  
  173.   
  174.   
  175.     /* Store the default render target */  
  176.     IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget );  
  177.     data->currentRenderTarget = NULL;  
  178.   
  179.   
  180.     /* Set up parameters for rendering */  
  181.     D3D_InitRenderState(data);  
  182.   
  183.   
  184.     if (caps.MaxSimultaneousTextures >= 3)  
  185.     {  
  186. #ifdef ASSEMBLE_SHADER  
  187.         /* This shader was created by running the following HLSL through the fxc compiler 
  188.            and then tuning the generated assembly. 
  189.  
  190.  
  191.            fxc /T fx_4_0 /O3 /Gfa /Fc yuv.fxc yuv.fx 
  192.  
  193.  
  194.            --- yuv.fx --- 
  195.            Texture2D g_txY; 
  196.            Texture2D g_txU; 
  197.            Texture2D g_txV; 
  198.  
  199.  
  200.            SamplerState samLinear 
  201.            { 
  202.                Filter = ANISOTROPIC; 
  203.                AddressU = Clamp; 
  204.                AddressV = Clamp; 
  205.                MaxAnisotropy = 1; 
  206.            }; 
  207.  
  208.  
  209.            struct VS_OUTPUT 
  210.            { 
  211.                 float2 TextureUV  : TEXCOORD0; 
  212.            }; 
  213.  
  214.  
  215.            struct PS_OUTPUT 
  216.            { 
  217.                 float4 RGBAColor : SV_Target; 
  218.            }; 
  219.  
  220.  
  221.            PS_OUTPUT YUV420( VS_OUTPUT In )  
  222.            { 
  223.                const float3 offset = {-0.0625, -0.5, -0.5}; 
  224.                const float3 Rcoeff = {1.164,  0.000,  1.596}; 
  225.                const float3 Gcoeff = {1.164, -0.391, -0.813}; 
  226.                const float3 Bcoeff = {1.164,  2.018,  0.000}; 
  227.  
  228.  
  229.                PS_OUTPUT Output; 
  230.                float2 TextureUV = In.TextureUV; 
  231.  
  232.  
  233.                float3 yuv; 
  234.                yuv.x = g_txY.Sample( samLinear, TextureUV ).r; 
  235.                yuv.y = g_txU.Sample( samLinear, TextureUV ).r; 
  236.                yuv.z = g_txV.Sample( samLinear, TextureUV ).r; 
  237.  
  238.  
  239.                yuv += offset; 
  240.                Output.RGBAColor.r = dot(yuv, Rcoeff); 
  241.                Output.RGBAColor.g = dot(yuv, Gcoeff); 
  242.                Output.RGBAColor.b = dot(yuv, Bcoeff); 
  243.                Output.RGBAColor.a = 1.0f; 
  244.  
  245.  
  246.                return Output; 
  247.            } 
  248.  
  249.  
  250.            technique10 RenderYUV420 
  251.            { 
  252.                pass P0 
  253.                { 
  254.                     SetPixelShader( CompileShader( ps_4_0_level_9_0, YUV420() ) ); 
  255.                } 
  256.            } 
  257.         */  
  258.         const char *shader_text =  
  259.             "ps_2_0\n"  
  260.             "def c0, -0.0625, -0.5, -0.5, 1\n"  
  261.             "def c1, 1.16400003, 0, 1.59599996, 0\n"  
  262.             "def c2, 1.16400003, -0.391000003, -0.813000023, 0\n"  
  263.             "def c3, 1.16400003, 2.01799989, 0, 0\n"  
  264.             "dcl t0.xy\n"  
  265.             "dcl v0.xyzw\n"  
  266.             "dcl_2d s0\n"  
  267.             "dcl_2d s1\n"  
  268.             "dcl_2d s2\n"  
  269.             "texld r0, t0, s0\n"  
  270.             "texld r1, t0, s1\n"  
  271.             "texld r2, t0, s2\n"  
  272.             "mov r0.y, r1.x\n"  
  273.             "mov r0.z, r2.x\n"  
  274.             "add r0.xyz, r0, c0\n"  
  275.             "dp3 r1.x, r0, c1\n"  
  276.             "dp3 r1.y, r0, c2\n"  
  277.             "dp2add r1.z, r0, c3, c3.z\n"   /* Logically this is "dp3 r1.z, r0, c3" but the optimizer did its magic */  
  278.             "mov r1.w, c0.w\n"  
  279.             "mul r0, r1, v0\n"              /* Not in the HLSL, multiply by vertex color */  
  280.             "mov oC0, r0\n"  
  281.         ;  
  282.         LPD3DXBUFFER pCode;  
  283.         LPD3DXBUFFER pErrorMsgs;  
  284.         LPDWORD shader_data = NULL;  
  285.         DWORD   shader_size = 0;  
  286.         result = D3DXAssembleShader(shader_text, SDL_strlen(shader_text), NULL, NULL, 0, &pCode, &pErrorMsgs);  
  287.         if (!FAILED(result)) {  
  288.             shader_data = (DWORD*)pCode->lpVtbl->GetBufferPointer(pCode);  
  289.             shader_size = pCode->lpVtbl->GetBufferSize(pCode);  
  290.             PrintShaderData(shader_data, shader_size);  
  291.         } else {  
  292.             const char *error = (const char *)pErrorMsgs->lpVtbl->GetBufferPointer(pErrorMsgs);  
  293.             SDL_SetError("Couldn't assemble shader: %s", error);  
  294.         }  
  295. #else  
  296.         const DWORD shader_data[] = {  
  297.             0xffff0200, 0x05000051, 0xa00f0000, 0xbd800000, 0xbf000000, 0xbf000000,  
  298.             0x3f800000, 0x05000051, 0xa00f0001, 0x3f94fdf4, 0x00000000, 0x3fcc49ba,  
  299.             0x00000000, 0x05000051, 0xa00f0002, 0x3f94fdf4, 0xbec83127, 0xbf5020c5,  
  300.             0x00000000, 0x05000051, 0xa00f0003, 0x3f94fdf4, 0x400126e9, 0x00000000,  
  301.             0x00000000, 0x0200001f, 0x80000000, 0xb0030000, 0x0200001f, 0x80000000,  
  302.             0x900f0000, 0x0200001f, 0x90000000, 0xa00f0800, 0x0200001f, 0x90000000,  
  303.             0xa00f0801, 0x0200001f, 0x90000000, 0xa00f0802, 0x03000042, 0x800f0000,  
  304.             0xb0e40000, 0xa0e40800, 0x03000042, 0x800f0001, 0xb0e40000, 0xa0e40801,  
  305.             0x03000042, 0x800f0002, 0xb0e40000, 0xa0e40802, 0x02000001, 0x80020000,  
  306.             0x80000001, 0x02000001, 0x80040000, 0x80000002, 0x03000002, 0x80070000,  
  307.             0x80e40000, 0xa0e40000, 0x03000008, 0x80010001, 0x80e40000, 0xa0e40001,  
  308.             0x03000008, 0x80020001, 0x80e40000, 0xa0e40002, 0x0400005a, 0x80040001,  
  309.             0x80e40000, 0xa0e40003, 0xa0aa0003, 0x02000001, 0x80080001, 0xa0ff0000,  
  310.             0x03000005, 0x800f0000, 0x80e40001, 0x90e40000, 0x02000001, 0x800f0800,  
  311.             0x80e40000, 0x0000ffff  
  312.         };  
  313. #endif  
  314.         if (shader_data != NULL) {  
  315.             result = IDirect3DDevice9_CreatePixelShader(data->device, shader_data, &data->ps_yuv);  
  316.             if (!FAILED(result)) {  
  317.                 renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;  
  318.                 renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;  
  319.             } else {  
  320.                 D3D_SetError("CreatePixelShader()", result);  
  321.             }  
  322.         }  
  323.     }  
  324.   
  325.   
  326.     return renderer;  
  327. }  

D3D_CreateRenderer()這個函數的代碼很長。在這裏提取它最重點的幾個進行簡單的分析。

PS:由於這個函數中包含了大量的Direct3D的API,這方面如果不熟悉的話,可以參考以下兩篇文章:

最簡單的視音頻播放示例3:Direct3D播放YUV,RGB(通過Surface)

最簡單的視音頻播放示例4:Direct3D播放RGB(通過Texture)

(1) 爲SDL_Renderer分配內存
這一步比較簡單。直接使用SDL_calloc()分配內存就可以了。SDL_calloc()實際上就是calloc(),這一點在前面的文章中已經敘述,在這裏不再重複。
(2) 加載Direct3D
加載Direct3D通過函數D3D_LoadDLL()完成。調用該函數可以得到一個IDirect3D9類型的接口。IDirect3D9接口可以用於完成D3D後續的初始化工作。D3D_LoadDLL()函數的代碼如下。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. SDL_bool D3D_LoadDLL( void **pD3DDLL, IDirect3D9 **pDirect3D9Interface )  
  2. {  
  3.     *pD3DDLL = SDL_LoadObject("D3D9.DLL");  
  4.     if (*pD3DDLL) {  
  5.         IDirect3D9 *(WINAPI * D3DCreate) (UINT SDKVersion);  
  6.   
  7.   
  8.         D3DCreate =  
  9.             (IDirect3D9 * (WINAPI *) (UINT)) SDL_LoadFunction(*pD3DDLL,  
  10.             "Direct3DCreate9");  
  11.         if (D3DCreate) {  
  12.             *pDirect3D9Interface = D3DCreate(D3D_SDK_VERSION);  
  13.         }  
  14.         if (!*pDirect3D9Interface) {  
  15.             SDL_UnloadObject(*pD3DDLL);  
  16.             *pD3DDLL = NULL;  
  17.             return SDL_FALSE;  
  18.         }  
  19.   
  20.   
  21.         return SDL_TRUE;  
  22.     } else {  
  23.         *pDirect3D9Interface = NULL;  
  24.         return SDL_FALSE;  
  25.     }  
  26. }  

從代碼中可以看出,該函數加載了一個“D3D9.DLL”的Dll,並且調用了其中的Direct3DCreate9()方法。


(3) 渲染器接口函數賦值

SDL_Render結構體中有一系列的函數指針,包含了有關渲染器的各種功能。SDL通過調用這些函數指針就可以調用渲染器相應的功能。這是SDL支持多種渲染器的一個重要特點。代碼如下所示。

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. renderer->WindowEvent = D3D_WindowEvent;  
  2. renderer->CreateTexture = D3D_CreateTexture;  
  3. renderer->UpdateTexture = D3D_UpdateTexture;  
  4. renderer->UpdateTextureYUV = D3D_UpdateTextureYUV;  
  5. renderer->LockTexture = D3D_LockTexture;  
  6. renderer->UnlockTexture = D3D_UnlockTexture;  
  7. renderer->SetRenderTarget = D3D_SetRenderTarget;  
  8. renderer->UpdateViewport = D3D_UpdateViewport;  
  9. renderer->UpdateClipRect = D3D_UpdateClipRect;  
  10. renderer->RenderClear = D3D_RenderClear;  
  11. renderer->RenderDrawPoints = D3D_RenderDrawPoints;  
  12. renderer->RenderDrawLines = D3D_RenderDrawLines;  
  13. renderer->RenderFillRects = D3D_RenderFillRects;  
  14. renderer->RenderCopy = D3D_RenderCopy;  
  15. renderer->RenderCopyEx = D3D_RenderCopyEx;  
  16. renderer->RenderReadPixels = D3D_RenderReadPixels;  
  17. renderer->RenderPresent = D3D_RenderPresent;  
  18. renderer->DestroyTexture = D3D_DestroyTexture;  
  19. renderer->DestroyRenderer = D3D_DestroyRenderer;  

(4) 創建Device

創建Direct3D的Device通過IDirect3D9_CreateDevice()函數來實現。這一方面的知識不再敘述,可以參考Direct3D創建Device的相關的文章。

(5) 設置渲染狀態

設置渲染狀態在函數D3D_InitRenderState()中完成。該部分的知識也不再詳述,可以參考Direct3D相關的渲染教程。貼出D3D_InitRenderState()的代碼。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. static void D3D_InitRenderState(D3D_RenderData *data)  
  2. {  
  3.     D3DMATRIX matrix;  
  4.   
  5.   
  6.     IDirect3DDevice9 *device = data->device;  
  7.   
  8.   
  9.     IDirect3DDevice9_SetVertexShader(device, NULL);  
  10.     IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);  
  11.     IDirect3DDevice9_SetRenderState(device, D3DRS_ZENABLE, D3DZB_FALSE);  
  12.     IDirect3DDevice9_SetRenderState(device, D3DRS_CULLMODE, D3DCULL_NONE);  
  13.     IDirect3DDevice9_SetRenderState(device, D3DRS_LIGHTING, FALSE);  
  14.   
  15.   
  16.     /* Enable color modulation by diffuse color */  
  17.     IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLOROP,  
  18.                                           D3DTOP_MODULATE);  
  19.     IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG1,  
  20.                                           D3DTA_TEXTURE);  
  21.     IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG2,  
  22.                                           D3DTA_DIFFUSE);  
  23.   
  24.   
  25.     /* Enable alpha modulation by diffuse alpha */  
  26.     IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAOP,  
  27.                                           D3DTOP_MODULATE);  
  28.     IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG1,  
  29.                                           D3DTA_TEXTURE);  
  30.     IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG2,  
  31.                                           D3DTA_DIFFUSE);  
  32.   
  33.   
  34.     /* Enable separate alpha blend function, if possible */  
  35.     if (data->enableSeparateAlphaBlend) {  
  36.         IDirect3DDevice9_SetRenderState(device, D3DRS_SEPARATEALPHABLENDENABLE, TRUE);  
  37.     }  
  38.   
  39.   
  40.     /* Disable second texture stage, since we're done */  
  41.     IDirect3DDevice9_SetTextureStageState(device, 1, D3DTSS_COLOROP,  
  42.                                           D3DTOP_DISABLE);  
  43.     IDirect3DDevice9_SetTextureStageState(device, 1, D3DTSS_ALPHAOP,  
  44.                                           D3DTOP_DISABLE);  
  45.   
  46.   
  47.     /* Set an identity world and view matrix */  
  48.     matrix.m[0][0] = 1.0f;  
  49.     matrix.m[0][1] = 0.0f;  
  50.     matrix.m[0][2] = 0.0f;  
  51.     matrix.m[0][3] = 0.0f;  
  52.     matrix.m[1][0] = 0.0f;  
  53.     matrix.m[1][1] = 1.0f;  
  54.     matrix.m[1][2] = 0.0f;  
  55.     matrix.m[1][3] = 0.0f;  
  56.     matrix.m[2][0] = 0.0f;  
  57.     matrix.m[2][1] = 0.0f;  
  58.     matrix.m[2][2] = 1.0f;  
  59.     matrix.m[2][3] = 0.0f;  
  60.     matrix.m[3][0] = 0.0f;  
  61.     matrix.m[3][1] = 0.0f;  
  62.     matrix.m[3][2] = 0.0f;  
  63.     matrix.m[3][3] = 1.0f;  
  64.     IDirect3DDevice9_SetTransform(device, D3DTS_WORLD, &matrix);  
  65.     IDirect3DDevice9_SetTransform(device, D3DTS_VIEW, &matrix);  
  66.   
  67.   
  68.     /* Reset our current scale mode */  
  69.     SDL_memset(data->scaleMode, 0xFF, sizeof(data->scaleMode));  
  70.   
  71.   
  72.     /* Start the render with beginScene */  
  73.     data->beginScene = SDL_TRUE;  
  74. }  

(6) 創建Shader

創建Shader通過函數IDirect3DDevice9_CreatePixelShader()完成。

完成以上步驟之後,Direct3D的渲染器就創建完畢了。


2. OpenGL

OpenGL 的渲染器在創建函數是GL_CreateRenderer()。該函數位於render\opengl\SDL_render_gl.c文件中。首先看一下它的代碼。

PS:其中用到了OpenGL的很多API。如果對OpenGL的API還不熟悉的話,可以參考文章:

最簡單的視音頻播放示例6:OpenGL播放YUV420P(通過Texture,使用Shader)

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. SDL_Renderer * GL_CreateRenderer(SDL_Window * window, Uint32 flags)  
  2. {  
  3.     SDL_Renderer *renderer;  
  4.     GL_RenderData *data;  
  5.     const char *hint;  
  6.     GLint value;  
  7.     Uint32 window_flags;  
  8.     int profile_mask, major, minor;  
  9.   
  10.   
  11.     SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask);  
  12.     SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);  
  13.     SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);  
  14.       
  15.     window_flags = SDL_GetWindowFlags(window);  
  16.     if (!(window_flags & SDL_WINDOW_OPENGL) ||  
  17.         profile_mask == SDL_GL_CONTEXT_PROFILE_ES || major != RENDERER_CONTEXT_MAJOR || minor != RENDERER_CONTEXT_MINOR) {  
  18.           
  19.         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);  
  20.         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, RENDERER_CONTEXT_MAJOR);  
  21.         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, RENDERER_CONTEXT_MINOR);  
  22.   
  23.   
  24.         if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {  
  25.             /* Uh oh, better try to put it back... */  
  26.             SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile_mask);  
  27.             SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);  
  28.             SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);  
  29.             SDL_RecreateWindow(window, window_flags);  
  30.             return NULL;  
  31.         }  
  32.     }  
  33.   
  34.   
  35.     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));  
  36.     if (!renderer) {  
  37.         SDL_OutOfMemory();  
  38.         return NULL;  
  39.     }  
  40.   
  41.   
  42.     data = (GL_RenderData *) SDL_calloc(1, sizeof(*data));  
  43.     if (!data) {  
  44.         GL_DestroyRenderer(renderer);  
  45.         SDL_OutOfMemory();  
  46.         return NULL;  
  47.     }  
  48.   
  49.   
  50.     renderer->WindowEvent = GL_WindowEvent;  
  51.     renderer->GetOutputSize = GL_GetOutputSize;  
  52.     renderer->CreateTexture = GL_CreateTexture;  
  53.     renderer->UpdateTexture = GL_UpdateTexture;  
  54.     renderer->UpdateTextureYUV = GL_UpdateTextureYUV;  
  55.     renderer->LockTexture = GL_LockTexture;  
  56.     renderer->UnlockTexture = GL_UnlockTexture;  
  57.     renderer->SetRenderTarget = GL_SetRenderTarget;  
  58.     renderer->UpdateViewport = GL_UpdateViewport;  
  59.     renderer->UpdateClipRect = GL_UpdateClipRect;  
  60.     renderer->RenderClear = GL_RenderClear;  
  61.     renderer->RenderDrawPoints = GL_RenderDrawPoints;  
  62.     renderer->RenderDrawLines = GL_RenderDrawLines;  
  63.     renderer->RenderFillRects = GL_RenderFillRects;  
  64.     renderer->RenderCopy = GL_RenderCopy;  
  65.     renderer->RenderCopyEx = GL_RenderCopyEx;  
  66.     renderer->RenderReadPixels = GL_RenderReadPixels;  
  67.     renderer->RenderPresent = GL_RenderPresent;  
  68.     renderer->DestroyTexture = GL_DestroyTexture;  
  69.     renderer->DestroyRenderer = GL_DestroyRenderer;  
  70.     renderer->GL_BindTexture = GL_BindTexture;  
  71.     renderer->GL_UnbindTexture = GL_UnbindTexture;  
  72.     renderer->info = GL_RenderDriver.info;  
  73.     renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);  
  74.     renderer->driverdata = data;  
  75.     renderer->window = window;  
  76.   
  77.   
  78.     data->context = SDL_GL_CreateContext(window);  
  79.     if (!data->context) {  
  80.         GL_DestroyRenderer(renderer);  
  81.         return NULL;  
  82.     }  
  83.     if (SDL_GL_MakeCurrent(window, data->context) < 0) {  
  84.         GL_DestroyRenderer(renderer);  
  85.         return NULL;  
  86.     }  
  87.   
  88.   
  89.     if (GL_LoadFunctions(data) < 0) {  
  90.         GL_DestroyRenderer(renderer);  
  91.         return NULL;  
  92.     }  
  93.   
  94.   
  95. #ifdef __MACOSX__  
  96.     /* Enable multi-threaded rendering */  
  97.     /* Disabled until Ryan finishes his VBO/PBO code... 
  98.        CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine); 
  99.      */  
  100. #endif  
  101.   
  102.   
  103.     if (flags & SDL_RENDERER_PRESENTVSYNC) {  
  104.         SDL_GL_SetSwapInterval(1);  
  105.     } else {  
  106.         SDL_GL_SetSwapInterval(0);  
  107.     }  
  108.     if (SDL_GL_GetSwapInterval() > 0) {  
  109.         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;  
  110.     }  
  111.   
  112.   
  113.     /* Check for debug output support */  
  114.     if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_FLAGS, &value) == 0 &&  
  115.         (value & SDL_GL_CONTEXT_DEBUG_FLAG)) {  
  116.         data->debug_enabled = SDL_TRUE;  
  117.     }  
  118.     if (data->debug_enabled && SDL_GL_ExtensionSupported("GL_ARB_debug_output")) {  
  119.         PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARBFunc = (PFNGLDEBUGMESSAGECALLBACKARBPROC) SDL_GL_GetProcAddress("glDebugMessageCallbackARB");  
  120.   
  121.   
  122.         data->GL_ARB_debug_output_supported = SDL_TRUE;  
  123.         data->glGetPointerv(GL_DEBUG_CALLBACK_FUNCTION_ARB, (GLvoid **)&data->next_error_callback);  
  124.         data->glGetPointerv(GL_DEBUG_CALLBACK_USER_PARAM_ARB, &data->next_error_userparam);  
  125.         glDebugMessageCallbackARBFunc(GL_HandleDebugMessage, renderer);  
  126.   
  127.   
  128.         /* Make sure our callback is called when errors actually happen */  
  129.         data->glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);  
  130.     }  
  131.   
  132.   
  133.     if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle")  
  134.         || SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) {  
  135.         data->GL_ARB_texture_rectangle_supported = SDL_TRUE;  
  136.         data->glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &value);  
  137.         renderer->info.max_texture_width = value;  
  138.         renderer->info.max_texture_height = value;  
  139.     } else {  
  140.         data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);  
  141.         renderer->info.max_texture_width = value;  
  142.         renderer->info.max_texture_height = value;  
  143.     }  
  144.   
  145.   
  146.     /* Check for multitexture support */  
  147.     if (SDL_GL_ExtensionSupported("GL_ARB_multitexture")) {  
  148.         data->glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) SDL_GL_GetProcAddress("glActiveTextureARB");  
  149.         if (data->glActiveTextureARB) {  
  150.             data->GL_ARB_multitexture_supported = SDL_TRUE;  
  151.             data->glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &data->num_texture_units);  
  152.         }  
  153.     }  
  154.   
  155.   
  156.     /* Check for shader support */  
  157.     hint = SDL_GetHint(SDL_HINT_RENDER_OPENGL_SHADERS);  
  158.     if (!hint || *hint != '0') {  
  159.         data->shaders = GL_CreateShaderContext();  
  160.     }  
  161.     SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "OpenGL shaders: %s",  
  162.                 data->shaders ? "ENABLED" : "DISABLED");  
  163.   
  164.   
  165.     /* We support YV12 textures using 3 textures and a shader */  
  166.     if (data->shaders && data->num_texture_units >= 3) {  
  167.         renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;  
  168.         renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;  
  169.     }  
  170.   
  171.   
  172. #ifdef __MACOSX__  
  173.     renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_UYVY;  
  174. #endif  
  175.   
  176.   
  177.     if (SDL_GL_ExtensionSupported("GL_EXT_framebuffer_object")) {  
  178.         data->GL_EXT_framebuffer_object_supported = SDL_TRUE;  
  179.         data->glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)  
  180.             SDL_GL_GetProcAddress("glGenFramebuffersEXT");  
  181.         data->glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)  
  182.             SDL_GL_GetProcAddress("glDeleteFramebuffersEXT");  
  183.         data->glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)  
  184.             SDL_GL_GetProcAddress("glFramebufferTexture2DEXT");  
  185.         data->glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)  
  186.             SDL_GL_GetProcAddress("glBindFramebufferEXT");  
  187.         data->glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)  
  188.             SDL_GL_GetProcAddress("glCheckFramebufferStatusEXT");  
  189.         renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;  
  190.     }  
  191.     data->framebuffers = NULL;  
  192.   
  193.   
  194.     /* Set up parameters for rendering */  
  195.     GL_ResetState(renderer);  
  196.   
  197.   
  198.     return renderer;  
  199. }  

GL_CreateRenderer()這個函數的代碼很長。在這裏提取它最重點的幾個進行簡單的分析。

(1) 爲SDL_Renderer分配內存

這一步比較簡單。直接使用SDL_calloc()分配內存就可以了。

(2) 渲染器接口函數賦值

SDL_Render結構體中有一系列的函數指針,包含了有關渲染器的各種功能。這一點在Direct3D的時候已經提過,不再重複。代碼如下。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. renderer->WindowEvent = GL_WindowEvent;  
  2. renderer->GetOutputSize = GL_GetOutputSize;  
  3. renderer->CreateTexture = GL_CreateTexture;  
  4. renderer->UpdateTexture = GL_UpdateTexture;  
  5. renderer->UpdateTextureYUV = GL_UpdateTextureYUV;  
  6. renderer->LockTexture = GL_LockTexture;  
  7. renderer->UnlockTexture = GL_UnlockTexture;  
  8. renderer->SetRenderTarget = GL_SetRenderTarget;  
  9. renderer->UpdateViewport = GL_UpdateViewport;  
  10. renderer->UpdateClipRect = GL_UpdateClipRect;  
  11. renderer->RenderClear = GL_RenderClear;  
  12. renderer->RenderDrawPoints = GL_RenderDrawPoints;  
  13. renderer->RenderDrawLines = GL_RenderDrawLines;  
  14. renderer->RenderFillRects = GL_RenderFillRects;  
  15. renderer->RenderCopy = GL_RenderCopy;  
  16. renderer->RenderCopyEx = GL_RenderCopyEx;  
  17. renderer->RenderReadPixels = GL_RenderReadPixels;  
  18. renderer->RenderPresent = GL_RenderPresent;  
  19. renderer->DestroyTexture = GL_DestroyTexture;  
  20. renderer->DestroyRenderer = GL_DestroyRenderer;  
  21. renderer->GL_BindTexture = GL_BindTexture;  
  22. renderer->GL_UnbindTexture = GL_UnbindTexture;  

(3) 初始化OpenGL
初始化OpenGL各種變量,包括SDL_GL_CreateContext(),SDL_GL_MakeCurrent(),GL_LoadFunctions()等函數。這一部分還沒有詳細分析。

(4) 初始化Shader

對Shader的初始化在函數GL_CreateShaderContext()中完成。GL_CreateShaderContext()的代碼如下(位於render\opengl\SDL_shaders_gl.c)。

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. GL_ShaderContext * GL_CreateShaderContext()  
  2. {  
  3.     GL_ShaderContext *ctx;  
  4.     SDL_bool shaders_supported;  
  5.     int i;  
  6.   
  7.   
  8.     ctx = (GL_ShaderContext *)SDL_calloc(1, sizeof(*ctx));  
  9.     if (!ctx) {  
  10.         return NULL;  
  11.     }  
  12.   
  13.   
  14.     if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle")  
  15.         || SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) {  
  16.         ctx->GL_ARB_texture_rectangle_supported = SDL_TRUE;  
  17.     }  
  18.   
  19.   
  20.     /* Check for shader support */  
  21.     shaders_supported = SDL_FALSE;  
  22.     if (SDL_GL_ExtensionSupported("GL_ARB_shader_objects") &&  
  23.         SDL_GL_ExtensionSupported("GL_ARB_shading_language_100") &&  
  24.         SDL_GL_ExtensionSupported("GL_ARB_vertex_shader") &&  
  25.         SDL_GL_ExtensionSupported("GL_ARB_fragment_shader")) {  
  26.         ctx->glGetError = (GLenum (*)(void)) SDL_GL_GetProcAddress("glGetError");  
  27.         ctx->glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) SDL_GL_GetProcAddress("glAttachObjectARB");  
  28.         ctx->glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) SDL_GL_GetProcAddress("glCompileShaderARB");  
  29.         ctx->glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glCreateProgramObjectARB");  
  30.         ctx->glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) SDL_GL_GetProcAddress("glCreateShaderObjectARB");  
  31.         ctx->glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) SDL_GL_GetProcAddress("glDeleteObjectARB");  
  32.         ctx->glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) SDL_GL_GetProcAddress("glGetInfoLogARB");  
  33.         ctx->glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) SDL_GL_GetProcAddress("glGetObjectParameterivARB");  
  34.         ctx->glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) SDL_GL_GetProcAddress("glGetUniformLocationARB");  
  35.         ctx->glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) SDL_GL_GetProcAddress("glLinkProgramARB");  
  36.         ctx->glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) SDL_GL_GetProcAddress("glShaderSourceARB");  
  37.         ctx->glUniform1iARB = (PFNGLUNIFORM1IARBPROC) SDL_GL_GetProcAddress("glUniform1iARB");  
  38.         ctx->glUniform1fARB = (PFNGLUNIFORM1FARBPROC) SDL_GL_GetProcAddress("glUniform1fARB");  
  39.         ctx->glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glUseProgramObjectARB");  
  40.         if (ctx->glGetError &&  
  41.             ctx->glAttachObjectARB &&  
  42.             ctx->glCompileShaderARB &&  
  43.             ctx->glCreateProgramObjectARB &&  
  44.             ctx->glCreateShaderObjectARB &&  
  45.             ctx->glDeleteObjectARB &&  
  46.             ctx->glGetInfoLogARB &&  
  47.             ctx->glGetObjectParameterivARB &&  
  48.             ctx->glGetUniformLocationARB &&  
  49.             ctx->glLinkProgramARB &&  
  50.             ctx->glShaderSourceARB &&  
  51.             ctx->glUniform1iARB &&  
  52.             ctx->glUniform1fARB &&  
  53.             ctx->glUseProgramObjectARB) {  
  54.             shaders_supported = SDL_TRUE;  
  55.         }  
  56.     }  
  57.   
  58.   
  59.     if (!shaders_supported) {  
  60.         SDL_free(ctx);  
  61.         return NULL;  
  62.     }  
  63.   
  64.   
  65.     /* Compile all the shaders */  
  66.     for (i = 0; i < NUM_SHADERS; ++i) {  
  67.         if (!CompileShaderProgram(ctx, i, &ctx->shaders[i])) {  
  68.             GL_DestroyShaderContext(ctx);  
  69.             return NULL;  
  70.         }  
  71.     }  
  72.   
  73.   
  74.     /* We're done! */  
  75.     return ctx;  
  76. }  

上述代碼主要完成了以下兩步:
第一步,初始化GL_ShaderContext。GL_ShaderContext中包含了OpenGL的Shader方面用到的各種接口函數。GL_ShaderContext定義如下。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. struct GL_ShaderContext  
  2. {  
  3.     GLenum (*glGetError)(void);  
  4.   
  5.   
  6.     PFNGLATTACHOBJECTARBPROC glAttachObjectARB;  
  7.     PFNGLCOMPILESHADERARBPROC glCompileShaderARB;  
  8.     PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB;  
  9.     PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB;  
  10.     PFNGLDELETEOBJECTARBPROC glDeleteObjectARB;  
  11.     PFNGLGETINFOLOGARBPROC glGetInfoLogARB;  
  12.     PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB;  
  13.     PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB;  
  14.     PFNGLLINKPROGRAMARBPROC glLinkProgramARB;  
  15.     PFNGLSHADERSOURCEARBPROC glShaderSourceARB;  
  16.     PFNGLUNIFORM1IARBPROC glUniform1iARB;  
  17.     PFNGLUNIFORM1FARBPROC glUniform1fARB;  
  18.     PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB;  
  19.   
  20.   
  21.     SDL_bool GL_ARB_texture_rectangle_supported;  
  22.   
  23.   
  24.     GL_ShaderData shaders[NUM_SHADERS];  
  25. };  

看這個結構體的定義會給人一種很混亂的感覺。不用去理會那些大串的大寫字母,只要知道這個結構體是函數的接口的“合集”就可以了。從函數的名稱中我們可以看出有編譯Shader的glCreateShaderObject(),glShaderSource(),glCompileShader()等;以及編譯Program的glCreateProgramObject(),glAttachObject (),glLinkProgram(),glUseProgramObject ()等等。
GL_CreateShaderContext()函數中創建了一個GL_ShaderContext並對其中的接口函數進行了賦值。

第二步,編譯Shader程序。該功能在CompileShaderProgram()函數中完成。CompileShaderProgram()的函數代碼如下所示。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. static SDL_bool CompileShaderProgram(GL_ShaderContext *ctx, int index, GL_ShaderData *data)  
  2. {  
  3.     const int num_tmus_bound = 4;  
  4.     const char *vert_defines = "";  
  5.     const char *frag_defines = "";  
  6.     int i;  
  7.     GLint location;  
  8.   
  9.   
  10.     if (index == SHADER_NONE) {  
  11.         return SDL_TRUE;  
  12.     }  
  13.   
  14.   
  15.     ctx->glGetError();  
  16.   
  17.   
  18.     /* Make sure we use the correct sampler type for our texture type */  
  19.     if (ctx->GL_ARB_texture_rectangle_supported) {  
  20.         frag_defines =  
  21. "#define sampler2D sampler2DRect\n"  
  22. "#define texture2D texture2DRect\n";  
  23.     }  
  24.   
  25.   
  26.     /* Create one program object to rule them all */  
  27.     data->program = ctx->glCreateProgramObjectARB();  
  28.   
  29.   
  30.     /* Create the vertex shader */  
  31.     data->vert_shader = ctx->glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);  
  32.     if (!CompileShader(ctx, data->vert_shader, vert_defines, shader_source[index][0])) {  
  33.         return SDL_FALSE;  
  34.     }  
  35.   
  36.   
  37.     /* Create the fragment shader */  
  38.     data->frag_shader = ctx->glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);  
  39.     if (!CompileShader(ctx, data->frag_shader, frag_defines, shader_source[index][1])) {  
  40.         return SDL_FALSE;  
  41.     }  
  42.   
  43.   
  44.     /* ... and in the darkness bind them */  
  45.     ctx->glAttachObjectARB(data->program, data->vert_shader);  
  46.     ctx->glAttachObjectARB(data->program, data->frag_shader);  
  47.     ctx->glLinkProgramARB(data->program);  
  48.   
  49.   
  50.     /* Set up some uniform variables */  
  51.     ctx->glUseProgramObjectARB(data->program);  
  52.     for (i = 0; i < num_tmus_bound; ++i) {  
  53.         char tex_name[10];  
  54.         SDL_snprintf(tex_name, SDL_arraysize(tex_name), "tex%d", i);  
  55.         location = ctx->glGetUniformLocationARB(data->program, tex_name);  
  56.         if (location >= 0) {  
  57.             ctx->glUniform1iARB(location, i);  
  58.         }  
  59.     }  
  60.     ctx->glUseProgramObjectARB(0);  
  61.   
  62.   
  63.     return (ctx->glGetError() == GL_NO_ERROR);  
  64. }  

從代碼中可以看出,這個函數調用了GL_ShaderContext中用於初始化Shader以及Program的各個函數。有關初始化的流程不再細說,可以參考相關的文章。

在該函數中,調用了CompileShader()專門用於初始化Shader。該函數被調用了兩次,分別用於初始化vertex shader和fragment shader。

CompileShader()的代碼如下。

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. static SDL_bool CompileShader(GL_ShaderContext *ctx, GLhandleARB shader, const char *defines, const char *source)  
  2. {  
  3.     GLint status;  
  4.     const char *sources[2];  
  5.   
  6.   
  7.     sources[0] = defines;  
  8.     sources[1] = source;  
  9.   
  10.   
  11.     ctx->glShaderSourceARB(shader, SDL_arraysize(sources), sources, NULL);  
  12.     ctx->glCompileShaderARB(shader);  
  13.     ctx->glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &status);  
  14.     if (status == 0) {  
  15.         GLint length;  
  16.         char *info;  
  17.   
  18.   
  19.         ctx->glGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);  
  20.         info = SDL_stack_alloc(char, length+1);  
  21.         ctx->glGetInfoLogARB(shader, length, NULL, info);  
  22.         SDL_LogError(SDL_LOG_CATEGORY_RENDER,  
  23.             "Failed to compile shader:\n%s%s\n%s", defines, source, info);  
  24. #ifdef DEBUG_SHADERS  
  25.         fprintf(stderr,  
  26.             "Failed to compile shader:\n%s%s\n%s", defines, source, info);  
  27. #endif  
  28.         SDL_stack_free(info);  
  29.   
  30.   
  31.         return SDL_FALSE;  
  32.     } else {  
  33.         return SDL_TRUE;  
  34.     }  
  35. }  

從代碼中可以看出,該函數調用glShaderSource(),glCompileShader(),glGetObjectParameteriv()這幾個函數初始化一個Shader。
Shader的代碼位於一個名稱爲shader_source的char型二維數組裏,源代碼如下所示。數組中每個元素代表一個Shader的代碼,每個Shader的代碼包含兩個部分:vertex shader代碼(對應元素[0])以及fragment shader代碼(對應元素[1])。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. /* 
  2.  * NOTE: Always use sampler2D, etc here. We'll #define them to the 
  3.  *  texture_rectangle versions if we choose to use that extension. 
  4.  */  
  5. static const char *shader_source[NUM_SHADERS][2] =  
  6. {  
  7.     /* SHADER_NONE */  
  8.     { NULL, NULL },  
  9.   
  10.   
  11.     /* SHADER_SOLID */  
  12.     {  
  13.         /* vertex shader */  
  14. "varying vec4 v_color;\n"  
  15. "\n"  
  16. "void main()\n"  
  17. "{\n"  
  18. "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"  
  19. "    v_color = gl_Color;\n"  
  20. "}",  
  21.         /* fragment shader */  
  22. "varying vec4 v_color;\n"  
  23. "\n"  
  24. "void main()\n"  
  25. "{\n"  
  26. "    gl_FragColor = v_color;\n"  
  27. "}"  
  28.     },  
  29.   
  30.   
  31.     /* SHADER_RGB */  
  32.     {  
  33.         /* vertex shader */  
  34. "varying vec4 v_color;\n"  
  35. "varying vec2 v_texCoord;\n"  
  36. "\n"  
  37. "void main()\n"  
  38. "{\n"  
  39. "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"  
  40. "    v_color = gl_Color;\n"  
  41. "    v_texCoord = vec2(gl_MultiTexCoord0);\n"  
  42. "}",  
  43.         /* fragment shader */  
  44. "varying vec4 v_color;\n"  
  45. "varying vec2 v_texCoord;\n"  
  46. "uniform sampler2D tex0;\n"  
  47. "\n"  
  48. "void main()\n"  
  49. "{\n"  
  50. "    gl_FragColor = texture2D(tex0, v_texCoord) * v_color;\n"  
  51. "}"  
  52.     },  
  53.   
  54.   
  55.     /* SHADER_YV12 */  
  56.     {  
  57.         /* vertex shader */  
  58. "varying vec4 v_color;\n"  
  59. "varying vec2 v_texCoord;\n"  
  60. "\n"  
  61. "void main()\n"  
  62. "{\n"  
  63. "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"  
  64. "    v_color = gl_Color;\n"  
  65. "    v_texCoord = vec2(gl_MultiTexCoord0);\n"  
  66. "}",  
  67.         /* fragment shader */  
  68. "varying vec4 v_color;\n"  
  69. "varying vec2 v_texCoord;\n"  
  70. "uniform sampler2D tex0; // Y \n"  
  71. "uniform sampler2D tex1; // U \n"  
  72. "uniform sampler2D tex2; // V \n"  
  73. "\n"  
  74. "// YUV offset \n"  
  75. "const vec3 offset = vec3(-0.0625, -0.5, -0.5);\n"  
  76. "\n"  
  77. "// RGB coefficients \n"  
  78. "const vec3 Rcoeff = vec3(1.164,  0.000,  1.596);\n"  
  79. "const vec3 Gcoeff = vec3(1.164, -0.391, -0.813);\n"  
  80. "const vec3 Bcoeff = vec3(1.164,  2.018,  0.000);\n"  
  81. "\n"  
  82. "void main()\n"  
  83. "{\n"  
  84. "    vec2 tcoord;\n"  
  85. "    vec3 yuv, rgb;\n"  
  86. "\n"  
  87. "    // Get the Y value \n"  
  88. "    tcoord = v_texCoord;\n"  
  89. "    yuv.x = texture2D(tex0, tcoord).r;\n"  
  90. "\n"  
  91. "    // Get the U and V values \n"  
  92. "    tcoord *= 0.5;\n"  
  93. "    yuv.y = texture2D(tex1, tcoord).r;\n"  
  94. "    yuv.z = texture2D(tex2, tcoord).r;\n"  
  95. "\n"  
  96. "    // Do the color transform \n"  
  97. "    yuv += offset;\n"  
  98. "    rgb.r = dot(yuv, Rcoeff);\n"  
  99. "    rgb.g = dot(yuv, Gcoeff);\n"  
  100. "    rgb.b = dot(yuv, Bcoeff);\n"  
  101. "\n"  
  102. "    // That was easy. :) \n"  
  103. "    gl_FragColor = vec4(rgb, 1.0) * v_color;\n"  
  104. "}"  
  105.     },  
  106. };  

有關OpenGL的渲染器的初始化代碼暫時分析到這裏。

3. Software

Software的渲染器在創建函數是SW_CreateRenderer()。該函數位於render\software\SDL_render_sw.c文件中。首先看一下它的代碼。

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. SDL_Renderer * SW_CreateRenderer(SDL_Window * window, Uint32 flags)  
  2. {  
  3.     SDL_Surface *surface;  
  4.   
  5.   
  6.     surface = SDL_GetWindowSurface(window);  
  7.     if (!surface) {  
  8.         return NULL;  
  9.     }  
  10.     return SW_CreateRendererForSurface(surface);  
  11. }  

從代碼中可以看出,SW_CreateRenderer()調用了2個函數:SDL_GetWindowSurface()和SW_CreateRendererForSurface()。SDL_GetWindowSurface()用於創建一個Surface;SW_CreateRendererForSurface()基於Surface創建一個Renderer。
下面分別看一下這2個函數的代碼。
SDL_GetWindowSurface()的代碼如下所示(位於video\SDL_video.c)。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. SDL_Surface * SDL_GetWindowSurface(SDL_Window * window)  
  2. {  
  3.     CHECK_WINDOW_MAGIC(window, NULL);  
  4.   
  5.   
  6.     if (!window->surface_valid) {  
  7.         if (window->surface) {  
  8.             window->surface->flags &= ~SDL_DONTFREE;  
  9.             SDL_FreeSurface(window->surface);  
  10.         }  
  11.         window->surface = SDL_CreateWindowFramebuffer(window);  
  12.         if (window->surface) {  
  13.             window->surface_valid = SDL_TRUE;  
  14.             window->surface->flags |= SDL_DONTFREE;  
  15.         }  
  16.     }  
  17.     return window->surface;  
  18. }  

其中調用了一個函數SDL_CreateWindowFramebuffer(),看一下該函數的代碼。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. static SDL_Surface * SDL_CreateWindowFramebuffer(SDL_Window * window)  
  2. {  
  3.     Uint32 format;  
  4.     void *pixels;  
  5.     int pitch;  
  6.     int bpp;  
  7.     Uint32 Rmask, Gmask, Bmask, Amask;  
  8.   
  9.   
  10.     if (!_this->CreateWindowFramebuffer || !_this->UpdateWindowFramebuffer) {  
  11.         return NULL;  
  12.     }  
  13.   
  14.   
  15.     if (_this->CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch) < 0) {  
  16.         return NULL;  
  17.     }  
  18.   
  19.   
  20.     if (!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {  
  21.         return NULL;  
  22.     }  
  23.   
  24.   
  25.     return SDL_CreateRGBSurfaceFrom(pixels, window->w, window->h, bpp, pitch, Rmask, Gmask, Bmask, Amask);  
  26. }  

該函數中調用了SDL_VideoDevice中的一個函數CreateWindowFramebuffer()。我們以“Windows視頻驅動”爲例,看看CreateWindowFramebuffer()中的代碼。在“Windows視頻驅動”下,CreateWindowFramebuffer()對應的函數是WIN_CreateWindowFramebuffer()。下面看一下該函數的代碼。

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. int WIN_CreateWindowFramebuffer(_THIS, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch)  
  2. {  
  3.     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;  
  4.     size_t size;  
  5.     LPBITMAPINFO info;  
  6.     HBITMAP hbm;  
  7.   
  8.   
  9.     /* Free the old framebuffer surface */  
  10.     if (data->mdc) {  
  11.         DeleteDC(data->mdc);  
  12.     }  
  13.     if (data->hbm) {  
  14.         DeleteObject(data->hbm);  
  15.     }  
  16.   
  17.   
  18.     /* Find out the format of the screen */  
  19.     size = sizeof(BITMAPINFOHEADER) + 256 * sizeof (RGBQUAD);  
  20.     info = (LPBITMAPINFO)SDL_stack_alloc(Uint8, size);  
  21.   
  22.   
  23.     SDL_memset(info, 0, size);  
  24.     info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);  
  25.   
  26.   
  27.     /* The second call to GetDIBits() fills in the bitfields */  
  28.     hbm = CreateCompatibleBitmap(data->hdc, 1, 1);  
  29.     GetDIBits(data->hdc, hbm, 0, 0, NULL, info, DIB_RGB_COLORS);  
  30.     GetDIBits(data->hdc, hbm, 0, 0, NULL, info, DIB_RGB_COLORS);  
  31.     DeleteObject(hbm);  
  32.   
  33.   
  34.     *format = SDL_PIXELFORMAT_UNKNOWN;  
  35.     if (info->bmiHeader.biCompression == BI_BITFIELDS) {  
  36.         int bpp;  
  37.         Uint32 *masks;  
  38.   
  39.   
  40.         bpp = info->bmiHeader.biPlanes * info->bmiHeader.biBitCount;  
  41.         masks = (Uint32*)((Uint8*)info + info->bmiHeader.biSize);  
  42.         *format = SDL_MasksToPixelFormatEnum(bpp, masks[0], masks[1], masks[2], 0);  
  43.     }  
  44.     if (*format == SDL_PIXELFORMAT_UNKNOWN)  
  45.     {  
  46.         /* We'll use RGB format for now */  
  47.         *format = SDL_PIXELFORMAT_RGB888;  
  48.   
  49.   
  50.         /* Create a new one */  
  51.         SDL_memset(info, 0, size);  
  52.         info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);  
  53.         info->bmiHeader.biPlanes = 1;  
  54.         info->bmiHeader.biBitCount = 32;  
  55.         info->bmiHeader.biCompression = BI_RGB;  
  56.     }  
  57.   
  58.   
  59.     /* Fill in the size information */  
  60.     *pitch = (((window->w * SDL_BYTESPERPIXEL(*format)) + 3) & ~3);  
  61.     info->bmiHeader.biWidth = window->w;  
  62.     info->bmiHeader.biHeight = -window->h;  /* negative for topdown bitmap */  
  63.     info->bmiHeader.biSizeImage = window->h * (*pitch);  
  64.   
  65.   
  66.     data->mdc = CreateCompatibleDC(data->hdc);  
  67.     data->hbm = CreateDIBSection(data->hdc, info, DIB_RGB_COLORS, pixels, NULL, 0);  
  68.     SDL_stack_free(info);  
  69.   
  70.   
  71.     if (!data->hbm) {  
  72.         return WIN_SetError("Unable to create DIB");  
  73.     }  
  74.     SelectObject(data->mdc, data->hbm);  
  75.   
  76.   
  77.     return 0;  
  78. }  

從代碼中可以看出,該函數調用了Win32的API函數CreateCompatibleBitmap(),CreateCompatibleDC()等一系列方法創建了“Surface”。

SDL_GetWindowSurface()函數到此分析完畢,現在回過頭來再看SW_CreateRenderer ()的另一個函數SW_CreateRendererForSurface()。該函數的代碼如下。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. SDL_Renderer * SW_CreateRendererForSurface(SDL_Surface * surface)  
  2. {  
  3.     SDL_Renderer *renderer;  
  4.     SW_RenderData *data;  
  5.   
  6.   
  7.     if (!surface) {  
  8.         SDL_SetError("Can't create renderer for NULL surface");  
  9.         return NULL;  
  10.     }  
  11.   
  12.   
  13.     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));  
  14.     if (!renderer) {  
  15.         SDL_OutOfMemory();  
  16.         return NULL;  
  17.     }  
  18.   
  19.   
  20.     data = (SW_RenderData *) SDL_calloc(1, sizeof(*data));  
  21.     if (!data) {  
  22.         SW_DestroyRenderer(renderer);  
  23.         SDL_OutOfMemory();  
  24.         return NULL;  
  25.     }  
  26.     data->surface = surface;  
  27.   
  28.   
  29.     renderer->WindowEvent = SW_WindowEvent;  
  30.     renderer->GetOutputSize = SW_GetOutputSize;  
  31.     renderer->CreateTexture = SW_CreateTexture;  
  32.     renderer->SetTextureColorMod = SW_SetTextureColorMod;  
  33.     renderer->SetTextureAlphaMod = SW_SetTextureAlphaMod;  
  34.     renderer->SetTextureBlendMode = SW_SetTextureBlendMode;  
  35.     renderer->UpdateTexture = SW_UpdateTexture;  
  36.     renderer->LockTexture = SW_LockTexture;  
  37.     renderer->UnlockTexture = SW_UnlockTexture;  
  38.     renderer->SetRenderTarget = SW_SetRenderTarget;  
  39.     renderer->UpdateViewport = SW_UpdateViewport;  
  40.     renderer->UpdateClipRect = SW_UpdateClipRect;  
  41.     renderer->RenderClear = SW_RenderClear;  
  42.     renderer->RenderDrawPoints = SW_RenderDrawPoints;  
  43.     renderer->RenderDrawLines = SW_RenderDrawLines;  
  44.     renderer->RenderFillRects = SW_RenderFillRects;  
  45.     renderer->RenderCopy = SW_RenderCopy;  
  46.     renderer->RenderCopyEx = SW_RenderCopyEx;  
  47.     renderer->RenderReadPixels = SW_RenderReadPixels;  
  48.     renderer->RenderPresent = SW_RenderPresent;  
  49.     renderer->DestroyTexture = SW_DestroyTexture;  
  50.     renderer->DestroyRenderer = SW_DestroyRenderer;  
  51.     renderer->info = SW_RenderDriver.info;  
  52.     renderer->driverdata = data;  
  53.   
  54.   
  55.     SW_ActivateRenderer(renderer);  
  56.   
  57.   
  58.     return renderer;  
  59. }  

與前面的函數一樣,該函數完成了SDL_Renderer結構體中函數指針的賦值。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章