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

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_CreateTexture()。这篇文章继续分析SDL的源代码。本文分析SDL更新纹理数据函数SDL_UpdateTexture()。

SDL播放视频的代码流程如下所示。
初始化: 

SDL_Init(): 初始化SDL。 
SDL_CreateWindow(): 创建窗口(Window)。 
SDL_CreateRenderer(): 基于窗口创建渲染器(Render)。 
SDL_CreateTexture(): 创建纹理(Texture)。

循环渲染数据: 

SDL_UpdateTexture(): 设置纹理的数据。 
SDL_RenderCopy(): 纹理复制给渲染器。 
SDL_RenderPresent(): 显示。

上篇文章分析了该流程中的第4个函数SDL_CreateTexture()。本文继续分析该流程中的第5个函数SDL_UpdateTexture()。

SDL_UpdateTexture()

函数简介

SDL使用SDL_UpdateTexture()设置纹理的像素数据。SDL_UpdateTexture()的原型如下。

int SDLCALL SDL_UpdateTexture(SDL_Texture * texture,const SDL_Rect * rect,const void *pixels, int pitch);

参数的含义如下。

texture:目标纹理。

rect:更新像素的矩形区域。设置为NULL的时候更新整个区域。

pixels:像素数据。

pitch:一行像素数据的字节数。

成功的话返回0,失败的话返回-1。

函数调用关系图

SDL_UpdateTexture()关键函数的调用关系可以用下图表示。

上面的图片不太清晰,更清晰的图片上传到了相册里面:

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

把相册里面的图片保存下来就可以得到清晰的图片。

源代码分析

SDL_UpdateTexture()的源代码位于render\SDL_render.c中。如下所示。

int SDL_UpdateTexture(SDL_Texture * texture, const SDL_Rect * rect,const void *pixels, int pitch)
{SDL_Renderer *renderer;SDL_Rect full_rect;CHECK_TEXTURE_MAGIC(texture, -1);if (!pixels) {return SDL_InvalidParamError("pixels");}if (!pitch) {return SDL_InvalidParamError("pitch");}if (!rect) {full_rect.x = 0;full_rect.y = 0;full_rect.w = texture->w;full_rect.h = texture->h;rect = &full_rect;}if (texture->yuv) {return SDL_UpdateTextureYUV(texture, rect, pixels, pitch);} else if (texture->native) {return SDL_UpdateTextureNative(texture, rect, pixels, pitch);} else {renderer = texture->renderer;return renderer->UpdateTexture(renderer, texture, rect, pixels, pitch);}
}

从源代码中可以看出,SDL_UpdateTexture()的大致流程如下。
1. 检查输入参数的合理性。例如像素格式是否支持,宽和高是否小于等于0等等。
2. 如果是一些特殊的格式,进行一定的处理:

a) 如果输入的像素数据是YUV格式的,则会调用SDL_UpdateTextureYUV()进行处理。
b) 如果输入的像素数据的像素格式不是渲染器支持的格式,则会调用SDL_UpdateTextureNative()进行处理。

3. 调用SDL_Render的UpdateTexture()方法更新纹理。这一步是整个函数的核心。
下面我们详细看一下几种不同的渲染器的UpdateTexture ()的方法。

1. Direct3D

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

static int
D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,const SDL_Rect * rect, const void *pixels, int pitch)
{D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;SDL_bool full_texture = SDL_FALSE;#ifdef USE_DYNAMIC_TEXTUREif (texture->access == SDL_TEXTUREACCESS_STREAMING &&rect->x == 0 && rect->y == 0 &&rect->w == texture->w && rect->h == texture->h) {full_texture = SDL_TRUE;}
#endifif (!data) {SDL_SetError("Texture is not currently available");return -1;}if (D3D_UpdateTextureInternal(data->texture, texture->format, full_texture, rect->x, rect->y, rect->w, rect->h, pixels, pitch) < 0) {return -1;}if (data->yuv) {/* Skip to the correct offset into the next texture */pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);if (D3D_UpdateTextureInternal(texture->format == SDL_PIXELFORMAT_YV12 ? data->vtexture : data->utexture, texture->format, full_texture, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, pixels, pitch / 2) < 0) {return -1;}/* Skip to the correct offset into the next texture */pixels = (const void*)((const Uint8*)pixels + (rect->h * pitch)/4);if (D3D_UpdateTextureInternal(texture->format == SDL_PIXELFORMAT_YV12 ? data->utexture : data->vtexture, texture->format, full_texture, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, pixels, pitch / 2) < 0) {return -1;}}return 0;
}

从代码中可以看出,该函数调用了D3D_UpdateTextureInternal()函数。在这里需要注意,如果输入像素格式是YUV,就会使用3个纹理,对于多出的那2个纹理会单独进行处理。调用的函数D3D_UpdateTextureInternal()代码如下。

static int D3D_UpdateTextureInternal(IDirect3DTexture9 *texture, Uint32 format, SDL_bool full_texture, int x, int y, int w, int h, const void *pixels, int pitch)
{RECT d3drect;D3DLOCKED_RECT locked;const Uint8 *src;Uint8 *dst;int row, length;HRESULT result;if (full_texture) {result = IDirect3DTexture9_LockRect(texture, 0, &locked, NULL, D3DLOCK_DISCARD);} else {d3drect.left = x;d3drect.right = x + w;d3drect.top = y;d3drect.bottom = y + h;result = IDirect3DTexture9_LockRect(texture, 0, &locked, &d3drect, 0);}if (FAILED(result)) {return D3D_SetError("LockRect()", result);}src = (const Uint8 *)pixels;dst = locked.pBits;length = w * SDL_BYTESPERPIXEL(format);if (length == pitch && length == locked.Pitch) {SDL_memcpy(dst, src, length*h);} else {if (length > pitch) {length = pitch;}if (length > locked.Pitch) {length = locked.Pitch;}for (row = 0; row < h; ++row) {SDL_memcpy(dst, src, length);src += pitch;dst += locked.Pitch;}}IDirect3DTexture9_UnlockRect(texture, 0);return 0;
}

从代码中可以看出,该函数首先调用IDirect3DTexture9_LockRect()锁定纹理,然后使用SDL_memcpy()将新的像素数据拷贝至纹理(SDL_memcpy()实际上就是memcpy()), 最后使用IDirect3DTexture9_UnlockRect()解锁纹理。

2. OpenGL

OpenGL渲染器中对应UpdateTexture()的函数是GL_UpdateTexture(),它的源代码如下所示(位于render\opengl\SDL_render_gl.c)。

static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,const SDL_Rect * rect, const void *pixels, int pitch)
{GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;GL_TextureData *data = (GL_TextureData *) texture->driverdata;GL_ActivateRenderer(renderer);renderdata->glEnable(data->type);renderdata->glBindTexture(data->type, data->texture);renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,(pitch / SDL_BYTESPERPIXEL(texture->format)));renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,rect->h, data->format, data->formattype,pixels);if (data->yuv) {renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, (pitch / 2));/* Skip to the correct offset into the next texture */pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);if (texture->format == SDL_PIXELFORMAT_YV12) {renderdata->glBindTexture(data->type, data->vtexture);} else {renderdata->glBindTexture(data->type, data->utexture);}renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,rect->w/2, rect->h/2,data->format, data->formattype, pixels);/* Skip to the correct offset into the next texture */pixels = (const void*)((const Uint8*)pixels + (rect->h * pitch)/4);if (texture->format == SDL_PIXELFORMAT_YV12) {renderdata->glBindTexture(data->type, data->utexture);} else {renderdata->glBindTexture(data->type, data->vtexture);}renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,rect->w/2, rect->h/2,data->format, data->formattype, pixels);}renderdata->glDisable(data->type);return GL_CheckError("glTexSubImage2D()", renderer);
}

从代码中可以看出,该函数调用了OpenGL的API函数glBindTexture (),glTexSubImage2D()等更新了一个纹理。
在这里有一点需要注意,如果输入像素格式是YUV,就会使用3个纹理,对于多出的那2个纹理会单独进行处理。

3. Software

Software渲染器中对应UpdateTexture()的函数是SW_UpdateTexture(),它的源代码如下所示(位于render\software\SDL_render_sw.c)。

static int SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,const SDL_Rect * rect, const void *pixels, int pitch)
{SDL_Surface *surface = (SDL_Surface *) texture->driverdata;Uint8 *src, *dst;int row;size_t length;if(SDL_MUSTLOCK(surface))SDL_LockSurface(surface);src = (Uint8 *) pixels;dst = (Uint8 *) surface->pixels +rect->y * surface->pitch +rect->x * surface->format->BytesPerPixel;length = rect->w * surface->format->BytesPerPixel;for (row = 0; row < rect->h; ++row) {SDL_memcpy(dst, src, length);src += pitch;dst += surface->pitch;}if(SDL_MUSTLOCK(surface))SDL_UnlockSurface(surface);return 0;
}

该函数的源代码还没有详细分析。其中最关键的函数要数SDL_memcpy()了,正是这个函数更新了纹理的像素数据。但是Software渲染器纹理修改的时候是否需要Lock()和Unlock()呢?这一点一直也没太搞清。

SDL2源代码分析5:更新纹理(SDL_UpdateTexture())相关推荐

  1. SDL2源代码分析5 更新纹理(SDL UpdateTexture )

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

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

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

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

    SDL源代码分析系列文章列表: SDL2源代码分析1:初始化(SDL_Init()) SDL2源代码分析2:窗口(SDL_Window) SDL2源代码分析3:渲染器(SDL_Renderer) SD ...

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

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

  5. SDL2源代码分析6:复制到渲染器(SDL_RenderCopy())

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

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

    ===================================================== 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. 兄弟连区块链教程Fabric1.0源代码分析configupdate处理通道配置更新

    区块链教程Fabric1.0源代码分析configupdate处理通道配置更新,2018年下半年,区块链行业正逐渐褪去发展之初的浮躁.回归理性,表面上看相关人才需求与身价似乎正在回落.但事实上,正是初 ...

最新文章

  1. 前端页面紫红色_谷歌正在开发一种神秘的新型移动操作系统,称为紫红色
  2. Go 语言调用 python2
  3. PTGAN:针对行人重识别的生成对抗网络 | PaperDaily #36
  4. Android之SharedPreferences 存储复杂对象
  5. OraOLEDbpus.dll找不到指定的模块的解决办法
  6. Ext.form.field.CheckBox复选框和Ext.form.field.Radio单选框
  7. h5 video 手机上无法显示_手机镜象投屏到电视上全屏显示
  8. 指令脚本redis线上环境监控脚本(python脚本)
  9. python 标准库 —— io(StringIO)
  10. 将当前登录用户去重显示。
  11. BD_source code for problem 1555
  12. CRMEB首届UI设计大赛报名啦!
  13. 分布式光纤传感技术(DTS/BOTDA/BOTDR/光栅/OTDR)近几年会有较快的发展(本人预测)
  14. 实战制作U盘工具去除XP系统管理员密码
  15. python写的 自定义连点器 的开发全过程(抢票、信息轰炸等、游戏连招等)——思路及解析【内附完整源码】
  16. token是什么?(加密)
  17. udp buffer 和reassemble buffer
  18. php表格 单元格,实例演示PhpSpreadsheet的单元格设置教程
  19. win10资源管理器无法最小化,无法移动
  20. 漳州市计算机报名时间,漳州市计算机操作员证怎么考要什么条件考试需要多久...

热门文章

  1. Bailian2698 八皇后【回溯】
  2. Bailian3751 地质考察队【最值】
  3. UVA10394 Twin Primes【孪生素数】
  4. UVA11636 Hello World!【模拟】
  5. CCF NOI1005 存款收益
  6. CCF201412-4 最优灌溉(100分)
  7. 深度学习框架 —— tflearn 的学习
  8. 机器学习竞赛(代码)
  9. 数据结构的时间复杂度与空间复杂度、及相关证明
  10. 强悍的 vim —— 处理大小写转换