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 ...
随机推荐
- 绑定运行计划sql_plan_baseline
--因为生产环境运行的sql变化较快,版本号公布比較频繁,造成sql的运行计划不是非常稳定.常常会有一些性能非常查的sql出现 --对于这些sql,我们能够使用sql_plan_baseline对运行 ...
- Webserver管理系列:11、注意默认的隐含共享
安装完Windows Server 2008之后默认的c/d/e...磁盘是共享的. 我们能够通过取消"Microsoft网络的文件和打印机共享"服务来阻止别人訪问我们的共享文件:
- IOS之【地图MapKit】
iOS地图位置开发 iPhone SDK提供了三个类来管理位置信息:CLLocation CLLocationManager 和 CLLHeading(不常用).除了使用GPS来获取当前的位置信息 ...
- meminfo,df,
yx100:root@yxRouter:/# cat /proc/meminfoMemTotal: 126584 kBMemFree: 103156 kBBuffer ...
- 【Demo 0008】标签控制器
本章学习要点: 1. 了解标签控制器基础知识; 2. 掌握标签控制器层次结构; 3. 掌握标签控制器基本用法; 4. 掌握自定义标签控制器: ...
- MySQL中同一时候存在创建和上次更新时间戳字段解决方法浅析
在写这篇文章之前.明白我的MySQL版本号. mysql> SELECT VERSION(); +------------+ | VERSION() | +------------+ | 5.5 ...
- 与众不同 windows phone (19) - Device(设备)之陀螺仪传感器, Motion API
原文:与众不同 windows phone (19) - Device(设备)之陀螺仪传感器, Motion API [索引页][源码下载] 与众不同 windows phone (19) - Dev ...
- 在bmp上添加字符
//打开位图文件,得到位图句柄 HBITMAP OpenBmpFile(HDC hDC, LPSTR lpszFileName) { HBITMAP hBmp = NULL; ...
- [Android学习笔记]View的measure过程学习
View从创建到显示到屏幕需要经历几个过程: measure -> layout -> draw measure过程:计算view所占屏幕大小layout过程:设置view在屏幕的位置dr ...
- java垃圾回收那点事(二)不同gc策略的heap分配
在前面的文章中曾提到了在java虚拟机启动的时候会对G1,CMS, SerialGC定义不同的heap的类,并且定义不同的policy. CollectorPolicy CollectorPolicy ...