SDL2源码分析5:更新纹理(SDL_UpdateTexture())
=====================================================
SDL源码分析系列文章列表:
SDL2源码分析5:更新纹理(SDL_UpdateTexture())
SDL2源码分析6:拷贝到渲染器(SDL_RenderCopy())
SDL2源码分析7:显示(SDL_RenderPresent())
=====================================================
上一篇文章分析了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。
函数调用关系图
上面的图片不太清晰。更清晰的图片上传到了相冊里面:
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_TEXTURE
if (texture->access == SDL_TEXTUREACCESS_STREAMING &&
rect->x == 0 && rect->y == 0 &&
rect->w == texture->w && rect->h == texture->h) {
full_texture = SDL_TRUE;
}
#endif if (!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())的更多相关文章
- SDL2源码分析6:拷贝到渲染器(SDL_RenderCopy())
===================================================== SDL源码分析系列文章列表: SDL2源码分析1:初始化(SDL_Init()) SDL2源 ...
- SDL2源码分析8:视频显示总结
===================================================== SDL源码分析系列文章列表: SDL2源码分析1:初始化(SDL_Init()) SDL2源 ...
- SDL2源码分析2:窗体(SDL_Window)
===================================================== SDL源码分析系列文章列表: SDL2源码分析1:初始化(SDL_Init()) SDL2源 ...
- SDL2源码分析1:初始化(SDL_Init())
===================================================== SDL源码分析系列文章列表: SDL2源码分析1:初始化(SDL_Init()) SDL2源 ...
- 一步步实现windows版ijkplayer系列文章之六——SDL2源码分析之OpenGL ES在windows上的渲染过程
一步步实现windows版ijkplayer系列文章之一--Windows10平台编译ffmpeg 4.0.2,生成ffplay 一步步实现windows版ijkplayer系列文章之二--Ijkpl ...
- 一步步实现windows版ijkplayer系列文章之二——Ijkplayer播放器源码分析之音视频输出——视频篇
一步步实现windows版ijkplayer系列文章之一--Windows10平台编译ffmpeg 4.0.2,生成ffplay 一步步实现windows版ijkplayer系列文章之二--Ijkpl ...
- jQuery1.6源码分析系列
原文地址:http://www.cnblogs.com/nuysoft/archive/2011/11/14/2248023.html jQuery源码分析(版本1.6.1) 目录 00 前言开光 0 ...
- 一步步实现windows版ijkplayer系列文章之三——Ijkplayer播放器源码分析之音视频输出——音频篇
一步步实现windows版ijkplayer系列文章之一--Windows10平台编译ffmpeg 4.0.2,生成ffplay 一步步实现windows版ijkplayer系列文章之二--Ijkpl ...
- jQuery1.6.1源码分析系列(作者:nuysoft/高云)
作者:nuysoft/高云 QQ:47214707 Email:nuysoft@gmail.com jQuery源码分析(版本1.6.1) 00 前言开光 01 总体架构 02 正则表达式-RegEx ...
随机推荐
- OPPO通过AWS节约大量成本提供海外服务
关于OPPO OPPO最早被人熟知是在以MP3和MP4为代表的影音市场.转型进入手机市场后,OPPO获得了更大发展机遇,近几年更是成为发展速度最快的国产品牌之中的一个.早在2010年前就開始了海外市场 ...
- Ubuntu 安装和配置minicom
Ubuntu 安装和配置minicom 1 . 安装 Minicom 用新立得软件管理器下载minicom 2.配置Minicom shell下输入 minicom -s 打开配置界面 进入Seria ...
- vscode编写插件
vscode编写插件详细过程 前言 之前编写了一个vscode插件用vscode写博客和发布,然后有园友要求写一篇来介绍如何开发一个vscode扩展插件,或者说介绍开发这个插件的过程.然而文章还没有写 ...
- ThinkPHP 3 的CURD管理用户信息 修改和删除
本节课大纲: 一.ThinkPHP 3 的CURD管理用户信息 http://localhost:8080/thinkphp/index.php/User/index 访问User类的index方法 ...
- Hadoop 的常用组件一览
Hadoop 集群安装及原理:hdfs命令行操作:Java操作hdfs的常用API接口:动态添加删除数据节点. HBase 集群安装及原理:Hbase命令行操作:Java操作Hbase的常用API接口 ...
- Swift - 基本数据类型,及常/变量声明
2015-01-08 14:59 发布:yuhang 浏览:434 下面是Swift中基本的数据类型介绍说明: 1,变量:使用var声明 1 var str:String = "hangge ...
- centos7里默认python升级到2.7.11
CentOS镜像使用帮助 http://mirrors.163.com/.help/centos.html 安装gcc yum install gcc* openssl openssl-devel ...
- 请慎用java的File#renameTo(File)方法(转)
以前我一直以为File#renameTo(File)方法与OS下面的 move/mv 命令是相同的,可以达到改名.移动文件的目的.不过后来经常发现问题:File#renameTo(File)方法会返回 ...
- cocos2dx--两个场景切换各函数调用顺序
场景A切换到场景B,有切换特效 调用顺序例如以下:(AAABABABA) A:构造函数 A:onEnter A:onEnterTransitionDidFinish B:构造函数 A:onExitTr ...
- linux expect, spawn用法小记
linux expect, spawn用法小记_IT民工_百度空间 linux expect, spawn用法小记 版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明http://sys ...