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

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()的原型如下。

  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中,如下所示。

  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. CHECK_RENDERER_MAGIC(renderer, -1);
  9. CHECK_TEXTURE_MAGIC(texture, -1);
  10.  
  11. if (renderer != texture->renderer) {
  12. return SDL_SetError("Texture was not created with this renderer");
  13. }
  14.  
  15. real_srcrect.x = 0;
  16. real_srcrect.y = 0;
  17. real_srcrect.w = texture->w;
  18. real_srcrect.h = texture->h;
  19. if (srcrect) {
  20. if (!SDL_IntersectRect(srcrect, &real_srcrect, &real_srcrect)) {
  21. return 0;
  22. }
  23. }
  24.  
  25. SDL_RenderGetViewport(renderer, &real_dstrect);
  26. real_dstrect.x = 0;
  27. real_dstrect.y = 0;
  28. if (dstrect) {
  29. if (!SDL_HasIntersection(dstrect, &real_dstrect)) {
  30. return 0;
  31. }
  32. real_dstrect = *dstrect;
  33. }
  34.  
  35. if (texture->native) {
  36. texture = texture->native;
  37. }
  38.  
  39. /* Don't draw while we're hidden */
  40. if (renderer->hidden) {
  41. return 0;
  42. }
  43.  
  44. frect.x = real_dstrect.x * renderer->scale.x;
  45. frect.y = real_dstrect.y * renderer->scale.y;
  46. frect.w = real_dstrect.w * renderer->scale.x;
  47. frect.h = real_dstrect.h * renderer->scale.y;
  48.  
  49. return renderer->RenderCopy(renderer, texture, &real_srcrect, &frect);
  50. }

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

1. 检查输入参数的合理性。
2. 调用SDL_Render的RenderCopy ()方法复制纹理到渲染目标。
这一步是整个函数的核心。
下面我们详细看一下几种不同的渲染器的RenderCopy()的方法。

1. Direct3D

Direct3D 渲染器中对应RenderCopy()的函数是D3D_RenderCopy(),它的源代码如下所示(位于render\direct3d\SDL_render_d3d.c)。

  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. if (D3D_ActivateRenderer(renderer) < 0) {
  14. return -1;
  15. }
  16.  
  17. texturedata = (D3D_TextureData *)texture->driverdata;
  18. if (!texturedata) {
  19. SDL_SetError("Texture is not currently available");
  20. return -1;
  21. }
  22.  
  23. minx = dstrect->x - 0.5f;
  24. miny = dstrect->y - 0.5f;
  25. maxx = dstrect->x + dstrect->w - 0.5f;
  26. maxy = dstrect->y + dstrect->h - 0.5f;
  27.  
  28. minu = (float) srcrect->x / texture->w;
  29. maxu = (float) (srcrect->x + srcrect->w) / texture->w;
  30. minv = (float) srcrect->y / texture->h;
  31. maxv = (float) (srcrect->y + srcrect->h) / texture->h;
  32.  
  33. color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
  34.  
  35. vertices[0].x = minx;
  36. vertices[0].y = miny;
  37. vertices[0].z = 0.0f;
  38. vertices[0].color = color;
  39. vertices[0].u = minu;
  40. vertices[0].v = minv;
  41.  
  42. vertices[1].x = maxx;
  43. vertices[1].y = miny;
  44. vertices[1].z = 0.0f;
  45. vertices[1].color = color;
  46. vertices[1].u = maxu;
  47. vertices[1].v = minv;
  48.  
  49. vertices[2].x = maxx;
  50. vertices[2].y = maxy;
  51. vertices[2].z = 0.0f;
  52. vertices[2].color = color;
  53. vertices[2].u = maxu;
  54. vertices[2].v = maxv;
  55.  
  56. vertices[3].x = minx;
  57. vertices[3].y = maxy;
  58. vertices[3].z = 0.0f;
  59. vertices[3].color = color;
  60. vertices[3].u = minu;
  61. vertices[3].v = maxv;
  62.  
  63. D3D_SetBlendMode(data, texture->blendMode);
  64.  
  65. D3D_UpdateTextureScaleMode(data, texturedata, 0);
  66.  
  67. result =
  68. IDirect3DDevice9_SetTexture(data->device, 0, (IDirect3DBaseTexture9 *)
  69. texturedata->texture);
  70. if (FAILED(result)) {
  71. return D3D_SetError("SetTexture()", result);
  72. }
  73.  
  74. if (texturedata->yuv) {
  75. shader = data->ps_yuv;
  76.  
  77. D3D_UpdateTextureScaleMode(data, texturedata, 1);
  78. D3D_UpdateTextureScaleMode(data, texturedata, 2);
  79.  
  80. result =
  81. IDirect3DDevice9_SetTexture(data->device, 1, (IDirect3DBaseTexture9 *)
  82. texturedata->utexture);
  83. if (FAILED(result)) {
  84. return D3D_SetError("SetTexture()", result);
  85. }
  86.  
  87. result =
  88. IDirect3DDevice9_SetTexture(data->device, 2, (IDirect3DBaseTexture9 *)
  89. texturedata->vtexture);
  90. if (FAILED(result)) {
  91. return D3D_SetError("SetTexture()", result);
  92. }
  93. }
  94.  
  95. if (shader) {
  96. result = IDirect3DDevice9_SetPixelShader(data->device, shader);
  97. if (FAILED(result)) {
  98. return D3D_SetError("SetShader()", result);
  99. }
  100. }
  101. result =
  102. IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
  103. vertices, sizeof(*vertices));
  104. if (FAILED(result)) {
  105. return D3D_SetError("DrawPrimitiveUP()", result);
  106. }
  107. if (shader) {
  108. result = IDirect3DDevice9_SetPixelShader(data->device, NULL);
  109. if (FAILED(result)) {
  110. return D3D_SetError("SetShader()", result);
  111. }
  112. }
  113. return 0;
  114. }

从代码中可以看出,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():激活渲染器。

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

D3D_SetBlendMode():设置渲染器状态。

  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():设置纹理采样方式。

  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)。

  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. GL_ActivateRenderer(renderer);
  10.  
  11. data->glEnable(texturedata->type);
  12. if (texturedata->yuv) {
  13. data->glActiveTextureARB(GL_TEXTURE2_ARB);
  14. data->glBindTexture(texturedata->type, texturedata->vtexture);
  15.  
  16. data->glActiveTextureARB(GL_TEXTURE1_ARB);
  17. data->glBindTexture(texturedata->type, texturedata->utexture);
  18.  
  19. data->glActiveTextureARB(GL_TEXTURE0_ARB);
  20. }
  21. data->glBindTexture(texturedata->type, texturedata->texture);
  22.  
  23. if (texture->modMode) {
  24. GL_SetColor(data, texture->r, texture->g, texture->b, texture->a);
  25. } else {
  26. GL_SetColor(data, 255, 255, 255, 255);
  27. }
  28.  
  29. GL_SetBlendMode(data, texture->blendMode);
  30.  
  31. if (texturedata->yuv) {
  32. GL_SetShader(data, SHADER_YV12);
  33. } else {
  34. GL_SetShader(data, SHADER_RGB);
  35. }
  36.  
  37. minx = dstrect->x;
  38. miny = dstrect->y;
  39. maxx = dstrect->x + dstrect->w;
  40. maxy = dstrect->y + dstrect->h;
  41.  
  42. minu = (GLfloat) srcrect->x / texture->w;
  43. minu *= texturedata->texw;
  44. maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
  45. maxu *= texturedata->texw;
  46. minv = (GLfloat) srcrect->y / texture->h;
  47. minv *= texturedata->texh;
  48. maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
  49. maxv *= texturedata->texh;
  50.  
  51. data->glBegin(GL_TRIANGLE_STRIP);
  52. data->glTexCoord2f(minu, minv);
  53. data->glVertex2f(minx, miny);
  54. data->glTexCoord2f(maxu, minv);
  55. data->glVertex2f(maxx, miny);
  56. data->glTexCoord2f(minu, maxv);
  57. data->glVertex2f(minx, maxy);
  58. data->glTexCoord2f(maxu, maxv);
  59. data->glVertex2f(maxx, maxy);
  60. data->glEnd();
  61.  
  62. data->glDisable(texturedata->type);
  63.  
  64. return GL_CheckError("", renderer);
  65. }

从代码中可以看出,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)。

  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. if (!surface) {
  9. return -1;
  10. }
  11.  
  12. if (renderer->viewport.x || renderer->viewport.y) {
  13. final_rect.x = (int)(renderer->viewport.x + dstrect->x);
  14. final_rect.y = (int)(renderer->viewport.y + dstrect->y);
  15. } else {
  16. final_rect.x = (int)dstrect->x;
  17. final_rect.y = (int)dstrect->y;
  18. }
  19. final_rect.w = (int)dstrect->w;
  20. final_rect.h = (int)dstrect->h;
  21.  
  22. if ( srcrect->w == final_rect.w && srcrect->h == final_rect.h ) {
  23. return SDL_BlitSurface(src, srcrect, surface, &final_rect);
  24. } else {
  25. return SDL_BlitScaled(src, srcrect, surface, &final_rect);
  26. }
  27. }

该函数的源代码还没有详细分析。

SDL2源代码分析6:复制到渲染器(SDL_RenderCopy())的更多相关文章

  1. SDL2源代码分析3:渲染器(SDL_Renderer)

    ===================================================== SDL源代码分析系列文章列表: SDL2源代码分析1:初始化(SDL_Init()) SDL ...

  2. 转:SDL2源代码分析

    1:初始化(SDL_Init()) SDL简介 有关SDL的简介在<最简单的视音频播放示例7:SDL2播放RGB/YUV>以及<最简单的视音频播放示例9:SDL2播放PCM>中 ...

  3. SDL2源代码分析8:视频显示总结

    ===================================================== SDL源代码分析系列文章列表: SDL2源代码分析1:初始化(SDL_Init()) SDL ...

  4. SDL2源代码分析7:显示(SDL_RenderPresent())

    ===================================================== SDL源代码分析系列文章列表: SDL2源代码分析1:初始化(SDL_Init()) SDL ...

  5. SDL2源代码分析5:更新纹理(SDL_UpdateTexture())

    ===================================================== SDL源代码分析系列文章列表: SDL2源代码分析1:初始化(SDL_Init()) SDL ...

  6. SDL2源代码分析4:纹理(SDL_Texture)

    ===================================================== SDL源代码分析系列文章列表: SDL2源代码分析1:初始化(SDL_Init()) SDL ...

  7. SDL2源代码分析2:窗口(SDL_Window)

    ===================================================== SDL源代码分析系列文章列表: SDL2源代码分析1:初始化(SDL_Init()) SDL ...

  8. SDL2源代码分析1:初始化(SDL_Init())

    ===================================================== SDL源代码分析系列文章列表: SDL2源代码分析1:初始化(SDL_Init()) SDL ...

  9. SDL2源代码分析

    1:初始化(SDL_Init()) SDL简介 有关SDL的简介在<最简单的视音频播放示例7:SDL2播放RGB/YUV>以及<最简单的视音频播放示例9:SDL2播放PCM>中 ...

随机推荐

  1. 关于java线程中stop interrupt daemon wait notify

    一.关于终止线程stop与interrupt 一般来说,线程执行结束后就变成消亡状态,乍看之下我们并不需要人为进行干预(人为停止线程),不过凡事都有例外吧,在服务器或者其他应用场景下,线程为了提供服务 ...

  2. solr6.6初探之分词篇

    关于solr6.6搭建与配置可以参考 solr6.6初探之配置篇 在这里我们探讨一下分词的配置 一.关于分词 1.分词是指将一个中文词语拆成若干个词,提供搜索引擎进行查找,比如说:北京大学 是一个词那 ...

  3. 上传本地项目到Github

    进入要上传的本地文件夹,右键打开Git Bash Here,然后进行以下步骤: 1.在命令行中,输入"git init",使Test文件夹加入git管理: 2.输入"gi ...

  4. Union和Union All 的区别

    Union和Union All 的区别: Union 是对结果集进行并集操作,不包括重复行,同时进行默认规则的排序: Union All,对两个结果集进行并集操作,包括重复行,不进行排序: Inter ...

  5. Android.mk 详解

    Android中增加本地程序或者库,这些程序与其所在路径没有关系,只和它们的Android.mk有关系. Android.mk与普通的makefile略有不同,Android.mk具有统一的写法,主要 ...

  6. JavaBean toString方式

    package object; import java.util.Date; public class ReportDataQo implements java.io.Serializable { p ...

  7. 关于Matchvs一些使用心得与建议

    我的项目是类似<贪吃蛇>玩法的一款IO游戏,就是几个玩家在游戏界面中可以吃食物,也可以相互吃,吃了食物或对方都会变大这样子.我是在用cocos creator做完前端开发的部分后,开始接入 ...

  8. jquery easyui datagrid 排序列

    点击排序列,将获取参数有:page=1&rows=10&sort=UserName&order=desc c#后台获取sort跟order参数 string sortColum ...

  9. 数据结构之Trie树

    1. 概述 Trie树,又称字典树,单词查找树或者前缀树,是一种用于快速检索的多叉树结构,如英文字母的字典树是一个26叉树,数字的字典树是一个10叉树. Trie一词来自retrieve,发音为/tr ...

  10. Hive中yyyymmdd和yyyy-mm-dd日期之间的切换

    以2017-12-05和20171205相互转换为例说明 方法1: from_unixtime+ unix_timestamp --20171205转成2017-12-05 ','yyyymmdd') ...