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

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

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_UpdateTexture()。這篇文章繼續分析SDL的源代碼。本文分析SDL紋理複製到渲染目標的函數SDL_RenderCopy()。



 


SDL播放視頻的代碼流程如下所示。
初始化: 
SDL_Init(): 初始化SDL。 
SDL_CreateWindow(): 創建窗口(Window)。 
SDL_CreateRenderer(): 基於窗口創建渲染器(Render)。 
SDL_CreateTexture(): 創建紋理(Texture)。 
循環渲染數據: 
SDL_UpdateTexture(): 設置紋理的數據。 
SDL_RenderCopy(): 紋理複製給渲染器。 
SDL_RenderPresent(): 顯示。
上篇文章分析了該流程中的第5個函數SDL_UpdateTexture()。本文繼續分析該流程中的第6個函數SDL_RenderCopy()。


SDL_RenderCopy()

函數簡介

SDL使用SDL_RenderCopy()將紋理數據複製給渲染目標。SDL_RenderCopy()的原型如下。

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. int SDLCALL SDL_RenderCopy(SDL_Renderer * renderer,  
  2.                                            SDL_Texture * texture,  
  3.                                            const SDL_Rect * srcrect,  
  4.                                            const SDL_Rect * dstrect);  

參數的含義如下。
renderer:渲染目標。
texture:輸入紋理。
srcrect:選擇輸入紋理的一塊矩形區域作爲輸入。設置爲NULL的時候整個紋理作爲輸入。
dstrect:選擇渲染目標的一塊矩形區域作爲輸出。設置爲NULL的時候整個渲染目標作爲輸出。


成功的話返回0,失敗的話返回-1。


函數調用關係圖

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


上面的圖片不太清晰,更清晰的圖片上傳到了相冊裏面:

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

把相冊裏面的圖片保存下來就可以得到清晰的圖片了。


源代碼分析

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

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. int SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,  
  2.                const SDL_Rect * srcrect, const SDL_Rect * dstrect)  
  3. {  
  4.     SDL_Rect real_srcrect = { 0, 0, 0, 0 };  
  5.     SDL_Rect real_dstrect = { 0, 0, 0, 0 };  
  6.     SDL_FRect frect;  
  7.   
  8.   
  9.     CHECK_RENDERER_MAGIC(renderer, -1);  
  10.     CHECK_TEXTURE_MAGIC(texture, -1);  
  11.   
  12.   
  13.     if (renderer != texture->renderer) {  
  14.         return SDL_SetError("Texture was not created with this renderer");  
  15.     }  
  16.   
  17.   
  18.     real_srcrect.x = 0;  
  19.     real_srcrect.y = 0;  
  20.     real_srcrect.w = texture->w;  
  21.     real_srcrect.h = texture->h;  
  22.     if (srcrect) {  
  23.         if (!SDL_IntersectRect(srcrect, &real_srcrect, &real_srcrect)) {  
  24.             return 0;  
  25.         }  
  26.     }  
  27.   
  28.   
  29.     SDL_RenderGetViewport(renderer, &real_dstrect);  
  30.     real_dstrect.x = 0;  
  31.     real_dstrect.y = 0;  
  32.     if (dstrect) {  
  33.         if (!SDL_HasIntersection(dstrect, &real_dstrect)) {  
  34.             return 0;  
  35.         }  
  36.         real_dstrect = *dstrect;  
  37.     }  
  38.   
  39.   
  40.     if (texture->native) {  
  41.         texture = texture->native;  
  42.     }  
  43.   
  44.   
  45.     /* Don't draw while we're hidden */  
  46.     if (renderer->hidden) {  
  47.         return 0;  
  48.     }  
  49.   
  50.   
  51.     frect.x = real_dstrect.x * renderer->scale.x;  
  52.     frect.y = real_dstrect.y * renderer->scale.y;  
  53.     frect.w = real_dstrect.w * renderer->scale.x;  
  54.     frect.h = real_dstrect.h * renderer->scale.y;  
  55.   
  56.   
  57.     return renderer->RenderCopy(renderer, texture, &real_srcrect, &frect);  
  58. }  

從源代碼中可以看出,SDL_RenderCopy()的大致流程如下。

1. 檢查輸入參數的合理性。
2. 調用SDL_Render的RenderCopy ()方法複製紋理到渲染目標。
這一步是整個函數的核心。
下面我們詳細看一下幾種不同的渲染器的RenderCopy()的方法。

1. Direct3D

Direct3D 渲染器中對應RenderCopy()的函數是D3D_RenderCopy(),它的源代碼如下所示(位於render\direct3d\SDL_render_d3d.c)。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. static int D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,  
  2.                const SDL_Rect * srcrect, const SDL_FRect * dstrect)  
  3. {  
  4.     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;  
  5.     D3D_TextureData *texturedata;  
  6.     LPDIRECT3DPIXELSHADER9 shader = NULL;  
  7.     float minx, miny, maxx, maxy;  
  8.     float minu, maxu, minv, maxv;  
  9.     DWORD color;  
  10.     Vertex vertices[4];  
  11.     HRESULT result;  
  12.   
  13.   
  14.     if (D3D_ActivateRenderer(renderer) < 0) {  
  15.         return -1;  
  16.     }  
  17.   
  18.   
  19.     texturedata = (D3D_TextureData *)texture->driverdata;  
  20.     if (!texturedata) {  
  21.         SDL_SetError("Texture is not currently available");  
  22.         return -1;  
  23.     }  
  24.   
  25.   
  26.     minx = dstrect->x - 0.5f;  
  27.     miny = dstrect->y - 0.5f;  
  28.     maxx = dstrect->x + dstrect->w - 0.5f;  
  29.     maxy = dstrect->y + dstrect->h - 0.5f;  
  30.   
  31.   
  32.     minu = (float) srcrect->x / texture->w;  
  33.     maxu = (float) (srcrect->x + srcrect->w) / texture->w;  
  34.     minv = (float) srcrect->y / texture->h;  
  35.     maxv = (float) (srcrect->y + srcrect->h) / texture->h;  
  36.   
  37.   
  38.     color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);  
  39.   
  40.   
  41.     vertices[0].x = minx;  
  42.     vertices[0].y = miny;  
  43.     vertices[0].z = 0.0f;  
  44.     vertices[0].color = color;  
  45.     vertices[0].u = minu;  
  46.     vertices[0].v = minv;  
  47.   
  48.   
  49.     vertices[1].x = maxx;  
  50.     vertices[1].y = miny;  
  51.     vertices[1].z = 0.0f;  
  52.     vertices[1].color = color;  
  53.     vertices[1].u = maxu;  
  54.     vertices[1].v = minv;  
  55.   
  56.   
  57.     vertices[2].x = maxx;  
  58.     vertices[2].y = maxy;  
  59.     vertices[2].z = 0.0f;  
  60.     vertices[2].color = color;  
  61.     vertices[2].u = maxu;  
  62.     vertices[2].v = maxv;  
  63.   
  64.   
  65.     vertices[3].x = minx;  
  66.     vertices[3].y = maxy;  
  67.     vertices[3].z = 0.0f;  
  68.     vertices[3].color = color;  
  69.     vertices[3].u = minu;  
  70.     vertices[3].v = maxv;  
  71.   
  72.   
  73.     D3D_SetBlendMode(data, texture->blendMode);  
  74.   
  75.   
  76.     D3D_UpdateTextureScaleMode(data, texturedata, 0);  
  77.   
  78.   
  79.     result =  
  80.         IDirect3DDevice9_SetTexture(data->device, 0, (IDirect3DBaseTexture9 *)  
  81.                                     texturedata->texture);  
  82.     if (FAILED(result)) {  
  83.         return D3D_SetError("SetTexture()", result);  
  84.     }  
  85.   
  86.   
  87.     if (texturedata->yuv) {  
  88.         shader = data->ps_yuv;  
  89.   
  90.   
  91.         D3D_UpdateTextureScaleMode(data, texturedata, 1);  
  92.         D3D_UpdateTextureScaleMode(data, texturedata, 2);  
  93.   
  94.   
  95.         result =  
  96.             IDirect3DDevice9_SetTexture(data->device, 1, (IDirect3DBaseTexture9 *)  
  97.                                         texturedata->utexture);  
  98.         if (FAILED(result)) {  
  99.             return D3D_SetError("SetTexture()", result);  
  100.         }  
  101.   
  102.   
  103.         result =  
  104.             IDirect3DDevice9_SetTexture(data->device, 2, (IDirect3DBaseTexture9 *)  
  105.                                         texturedata->vtexture);  
  106.         if (FAILED(result)) {  
  107.             return D3D_SetError("SetTexture()", result);  
  108.         }  
  109.     }  
  110.   
  111.   
  112.     if (shader) {  
  113.         result = IDirect3DDevice9_SetPixelShader(data->device, shader);  
  114.         if (FAILED(result)) {  
  115.             return D3D_SetError("SetShader()", result);  
  116.         }  
  117.     }  
  118.     result =  
  119.         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,  
  120.                                          vertices, sizeof(*vertices));  
  121.     if (FAILED(result)) {  
  122.         return D3D_SetError("DrawPrimitiveUP()", result);  
  123.     }  
  124.     if (shader) {  
  125.         result = IDirect3DDevice9_SetPixelShader(data->device, NULL);  
  126.         if (FAILED(result)) {  
  127.             return D3D_SetError("SetShader()", result);  
  128.         }  
  129.     }  
  130.     return 0;  
  131. }  

從代碼中可以看出,D3D_RenderCopy()函數按照執行的順序調用瞭如下函數:

D3D_ActivateRenderer():激活渲染器。其內部使用Direct3D的API函數IDirect3DDevice9_BeginScene()開始一個D3D的場景。
D3D_SetBlendMode():設置渲染器狀態。其內部使用Direct3D的API函數IDirect3DDevice9_SetRenderState()設置渲染器的狀態。
D3D_UpdateTextureScaleMode():設置紋理採樣方式。其內部調用使用Direct3D的API函數IDirect3DDevice9_SetSamplerState()設置D3D的紋理採樣方式。
IDirect3DDevice9_SetTexture():Direct3D的API,用於設置當前啓用的紋理。
IDirect3DDevice9_SetPixelShader():Direct3D的API,用於設置使用的像素着色器。

IDirect3DDevice9_DrawPrimitiveUP():Direct3D的API,用於渲染。

上述幾個函數中,前3個函數是SDL中的函數,後3個函數是Direct3D的API。在此附上前三個函數的代碼。

D3D_ActivateRenderer():激活渲染器。

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. static int D3D_ActivateRenderer(SDL_Renderer * renderer)  
  2. {  
  3.     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;  
  4.     HRESULT result;  
  5.   
  6.   
  7.     if (data->updateSize) {  
  8.         SDL_Window *window = renderer->window;  
  9.         int w, h;  
  10.   
  11.   
  12.         SDL_GetWindowSize(window, &w, &h);  
  13.         data->pparams.BackBufferWidth = w;  
  14.         data->pparams.BackBufferHeight = h;  
  15.         if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) {  
  16.             data->pparams.BackBufferFormat =  
  17.                 PixelFormatToD3DFMT(SDL_GetWindowPixelFormat(window));  
  18.         } else {  
  19.             data->pparams.BackBufferFormat = D3DFMT_UNKNOWN;  
  20.         }  
  21.         if (D3D_Reset(renderer) < 0) {  
  22.             return -1;  
  23.         }  
  24.   
  25.   
  26.         data->updateSize = SDL_FALSE;  
  27.     }  
  28.     if (data->beginScene) {  
  29.         result = IDirect3DDevice9_BeginScene(data->device);  
  30.         if (result == D3DERR_DEVICELOST) {  
  31.             if (D3D_Reset(renderer) < 0) {  
  32.                 return -1;  
  33.             }  
  34.             result = IDirect3DDevice9_BeginScene(data->device);  
  35.         }  
  36.         if (FAILED(result)) {  
  37.             return D3D_SetError("BeginScene()", result);  
  38.         }  
  39.         data->beginScene = SDL_FALSE;  
  40.     }  
  41.     return 0;  
  42. }  


D3D_SetBlendMode():設置渲染器狀態。

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. static void D3D_SetBlendMode(D3D_RenderData * data, int blendMode)  
  2. {  
  3.     switch (blendMode) {  
  4.     case SDL_BLENDMODE_NONE:  
  5.         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,  
  6.                                         FALSE);  
  7.         break;  
  8.     case SDL_BLENDMODE_BLEND:  
  9.         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,  
  10.                                         TRUE);  
  11.         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,  
  12.                                         D3DBLEND_SRCALPHA);  
  13.         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,  
  14.                                         D3DBLEND_INVSRCALPHA);  
  15.         if (data->enableSeparateAlphaBlend) {  
  16.             IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,  
  17.                                             D3DBLEND_ONE);  
  18.             IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,  
  19.                                             D3DBLEND_INVSRCALPHA);  
  20.         }  
  21.         break;  
  22.     case SDL_BLENDMODE_ADD:  
  23.         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,  
  24.                                         TRUE);  
  25.         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,  
  26.                                         D3DBLEND_SRCALPHA);  
  27.         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,  
  28.                                         D3DBLEND_ONE);  
  29.         if (data->enableSeparateAlphaBlend) {  
  30.             IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,  
  31.                                             D3DBLEND_ZERO);  
  32.             IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,  
  33.                                             D3DBLEND_ONE);  
  34.         }  
  35.         break;  
  36.     case SDL_BLENDMODE_MOD:  
  37.         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,  
  38.                                         TRUE);  
  39.         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,  
  40.                                         D3DBLEND_ZERO);  
  41.         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,  
  42.                                         D3DBLEND_SRCCOLOR);  
  43.         if (data->enableSeparateAlphaBlend) {  
  44.             IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,  
  45.                                             D3DBLEND_ZERO);  
  46.             IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,  
  47.                                             D3DBLEND_ONE);  
  48.         }  
  49.         break;  
  50.     }  
  51. }  


D3D_UpdateTextureScaleMode():設置紋理採樣方式。

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. static void D3D_UpdateTextureScaleMode(D3D_RenderData *data, D3D_TextureData *texturedata, unsigned index)  
  2. {  
  3.     if (texturedata->scaleMode != data->scaleMode[index]) {  
  4.         IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MINFILTER,  
  5.                                          texturedata->scaleMode);  
  6.         IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MAGFILTER,  
  7.                                          texturedata->scaleMode);  
  8.         data->scaleMode[index] = texturedata->scaleMode;  
  9.     }  
  10. }  

2. OpenGL

OpenGL渲染器中對應RenderCopy()的函數是GL_RenderCopy(),它的源代碼如下所示(位於render\opengl\SDL_render_gl.c)。

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. static int GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,  
  2.               const SDL_Rect * srcrect, const SDL_FRect * dstrect)  
  3. {  
  4.     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;  
  5.     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;  
  6.     GLfloat minx, miny, maxx, maxy;  
  7.     GLfloat minu, maxu, minv, maxv;  
  8.   
  9.   
  10.     GL_ActivateRenderer(renderer);  
  11.   
  12.   
  13.     data->glEnable(texturedata->type);  
  14.     if (texturedata->yuv) {  
  15.         data->glActiveTextureARB(GL_TEXTURE2_ARB);  
  16.         data->glBindTexture(texturedata->type, texturedata->vtexture);  
  17.   
  18.   
  19.         data->glActiveTextureARB(GL_TEXTURE1_ARB);  
  20.         data->glBindTexture(texturedata->type, texturedata->utexture);  
  21.   
  22.   
  23.         data->glActiveTextureARB(GL_TEXTURE0_ARB);  
  24.     }  
  25.     data->glBindTexture(texturedata->type, texturedata->texture);  
  26.   
  27.   
  28.     if (texture->modMode) {  
  29.         GL_SetColor(data, texture->r, texture->g, texture->b, texture->a);  
  30.     } else {  
  31.         GL_SetColor(data, 255, 255, 255, 255);  
  32.     }  
  33.   
  34.   
  35.     GL_SetBlendMode(data, texture->blendMode);  
  36.   
  37.   
  38.     if (texturedata->yuv) {  
  39.         GL_SetShader(data, SHADER_YV12);  
  40.     } else {  
  41.         GL_SetShader(data, SHADER_RGB);  
  42.     }  
  43.   
  44.   
  45.     minx = dstrect->x;  
  46.     miny = dstrect->y;  
  47.     maxx = dstrect->x + dstrect->w;  
  48.     maxy = dstrect->y + dstrect->h;  
  49.   
  50.   
  51.     minu = (GLfloat) srcrect->x / texture->w;  
  52.     minu *= texturedata->texw;  
  53.     maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;  
  54.     maxu *= texturedata->texw;  
  55.     minv = (GLfloat) srcrect->y / texture->h;  
  56.     minv *= texturedata->texh;  
  57.     maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;  
  58.     maxv *= texturedata->texh;  
  59.   
  60.   
  61.     data->glBegin(GL_TRIANGLE_STRIP);  
  62.     data->glTexCoord2f(minu, minv);  
  63.     data->glVertex2f(minx, miny);  
  64.     data->glTexCoord2f(maxu, minv);  
  65.     data->glVertex2f(maxx, miny);  
  66.     data->glTexCoord2f(minu, maxv);  
  67.     data->glVertex2f(minx, maxy);  
  68.     data->glTexCoord2f(maxu, maxv);  
  69.     data->glVertex2f(maxx, maxy);  
  70.     data->glEnd();  
  71.   
  72.   
  73.     data->glDisable(texturedata->type);  
  74.   
  75.   
  76.     return GL_CheckError("", renderer);  
  77. }  

從代碼中可以看出,GL_RenderCopy()函數調用了OpenGL的API函數glActiveTexture(),glBindTexture()創建了一個紋理。並且使用GL_SetBlendMode(),GL_SetShader()設置了有關的一些參數。

有一點需要注意,在OpenGL渲染器中,如果輸入像素格式是YUV,就會使用3個紋理。

3. Software

Software渲染器中對應RenderCopy()的函數是SW_RenderCopy(),它的源代碼如下所示(位於render\software\SDL_render_sw.c)。

[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. static int SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,  
  2.               const SDL_Rect * srcrect, const SDL_FRect * dstrect)  
  3. {  
  4.     SDL_Surface *surface = SW_ActivateRenderer(renderer);  
  5.     SDL_Surface *src = (SDL_Surface *) texture->driverdata;  
  6.     SDL_Rect final_rect;  
  7.   
  8.   
  9.     if (!surface) {  
  10.         return -1;  
  11.     }  
  12.   
  13.   
  14.     if (renderer->viewport.x || renderer->viewport.y) {  
  15.         final_rect.x = (int)(renderer->viewport.x + dstrect->x);  
  16.         final_rect.y = (int)(renderer->viewport.y + dstrect->y);  
  17.     } else {  
  18.         final_rect.x = (int)dstrect->x;  
  19.         final_rect.y = (int)dstrect->y;  
  20.     }  
  21.     final_rect.w = (int)dstrect->w;  
  22.     final_rect.h = (int)dstrect->h;  
  23.   
  24.   
  25.     if ( srcrect->w == final_rect.w && srcrect->h == final_rect.h ) {  
  26.         return SDL_BlitSurface(src, srcrect, surface, &final_rect);  
  27.     } else {  
  28.         return SDL_BlitScaled(src, srcrect, surface, &final_rect);  
  29.     }  
  30. }  

該函數的源代碼還沒有詳細分析。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章