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

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_RenderCopy()。这篇文章分析SDL显示视频最后的一个函数:SDL_RenderPresent()。

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

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

循环渲染数据: 

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

上篇文章分析了该流程中的第6个函数SDL_RenderCopy()。本文继续分析该流程中的最后一个函数SDL_RenderPresent()。

SDL_RenderPresent()

函数简介

SDL使用SDL_RenderPresent()显示画面。SDL_RenderPresent()的原型如下。

void SDLCALL SDL_RenderPresent(SDL_Renderer * renderer);

参数renderer用于指定渲染器。

函数调用关系图

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

 

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

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

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

源代码分析

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

void SDL_RenderPresent(SDL_Renderer * renderer)
{
    CHECK_RENDERER_MAGIC(renderer, );

    /* Don't draw while we're hidden */
    if (renderer->hidden) {
        return;
    }
    renderer->RenderPresent(renderer);
}

从源代码中可以看出,SDL_RenderPresent()调用了SDL_Render的RenderPresent()方法显示图像。

下面我们详细看一下几种不同的渲染器的RenderPresent()的方法。

1. Direct3D

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

static void D3D_RenderPresent(SDL_Renderer * renderer)
{
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
    HRESULT result;

    if (!data->beginScene) {
        IDirect3DDevice9_EndScene(data->device);
        data->beginScene = SDL_TRUE;
    }

    result = IDirect3DDevice9_TestCooperativeLevel(data->device);
    if (result == D3DERR_DEVICELOST) {
        /* We'll reset later */
        return;
    }
    if (result == D3DERR_DEVICENOTRESET) {
        D3D_Reset(renderer);
    }
    result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL);
    if (FAILED(result)) {
        D3D_SetError("Present()", result);
    }
}

从代码中可以看出,该函数调用了2个最关键Direct3D的API:
IDirect3DDevice9_EndScene():结束一个场景。
IDirect3DDevice9_Present():显示。

2. OpenGL

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

static void GL_RenderPresent(SDL_Renderer * renderer)
{
GL_ActivateRenderer(renderer);

    SDL_GL_SwapWindow(renderer->window);
}

代码比较简单,只有两行。关键的显示函数位于SDL_GL_SwapWindow()函数中。下面看一下SDL_GL_SwapWindow()的代码(位于video\SDL_video.c。感觉这里调用关系稍微有点乱…)。

void SDL_GL_SwapWindow(SDL_Window * window)
{
    CHECK_WINDOW_MAGIC(window, );

    if (!(window->flags & SDL_WINDOW_OPENGL)) {
        SDL_SetError("The specified window isn't an OpenGL window");
        return;
    }

    if (SDL_GL_GetCurrentWindow() != window) {
        SDL_SetError("The specified window has not been made current");
        return;
    }

    _this->GL_SwapWindow(_this, window);
}

从上述代码中可以看出,SDL_GL_SwapWindow()调用了SDL_VideoDevice的GL_SwapWindow()函数。我们看一下在“Windows视频驱动”的情况下,该函数的代码。在“Windows视频驱动”的情况下,调用GL_SwapWindow()实际上是调用了WIN_GL_SwapWindow()函数。看一下WIN_GL_SwapWindow()函数的代码(位于video\windows\SDL_windowsopengl.c)。

void WIN_GL_SwapWindow(_THIS, SDL_Window * window)
{
    HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc;

    SwapBuffers(hdc);
}

代码中调用了简单的一个函数SwapBuffers(),完成了显示功能。

3. Software

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

static void SW_RenderPresent(SDL_Renderer * renderer)
{
    SDL_Window *window = renderer->window;

    if (window) {
        SDL_UpdateWindowSurface(window);
    }
}

从代码中可以看出,SW_RenderPresent()调用了一个函数SDL_UpdateWindowSurface()。我们看一下SDL_UpdateWindowSurface()的代码(位于video\SDL_video.c)。

int SDL_UpdateWindowSurface(SDL_Window * window)
{
    SDL_Rect full_rect;

    CHECK_WINDOW_MAGIC(window, -1);

    full_rect.x = 0;
    full_rect.y = 0;
    full_rect.w = window->w;
    full_rect.h = window->h;
    return SDL_UpdateWindowSurfaceRects(window, &full_rect, 1);
}

SDL_UpdateWindowSurface()又调用了另一个函数SDL_UpdateWindowSurfaceRects()。继续看SDL_UpdateWindowSurfaceRects()的代码。

int SDL_UpdateWindowSurfaceRects(SDL_Window * window, const SDL_Rect * rects,
                             int numrects)
{
    CHECK_WINDOW_MAGIC(window, -1);

    if (!window->surface_valid) {
        return SDL_SetError("Window surface is invalid, please call SDL_GetWindowSurface() to get a new surface");
    }

    return _this->UpdateWindowFramebuffer(_this, window, rects, numrects);
}

SDL_UpdateWindowSurfaceRects()调用了SDL_VideoDevice的UpdateWindowFramebuffer()函数。在“Windows视频驱动”的情况下,相当于调用了WIN_UpdateWindowFramebuffer()。我们看一下该函数的代码(位于video\windows\SDL_windowsframebuffer.c)

int WIN_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rect * rects, int numrects)
{
    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;

    BitBlt(data->hdc, 0, 0, window->w, window->h, data->mdc, 0, 0, SRCCOPY);
    return 0;
}

经过一系列的寻找之后,终于找到了Software渲染器显示视频的“源头”:BitBlt()函数。

SDL2源代码分析7:显示(SDL_RenderPresent())的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  8. 转:SDL2源代码分析

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

  9. SDL2源代码分析

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

随机推荐

  1. jquery 中toggle的2种用法

    一.在元素的click事件中绑定两个或两个以上的函数  toggle不像bind需要在后面添加"click"来绑定click触发事件,toggle本身就是click触发的(而且只能 ...

  2. 一个小小的抽奖活动测试脚本(python2.7)

    # coding=utf-8import requestsimport cx_Oracletns=cx_Oracle.makedsn('172.30.0.155',1521,'szdev')db1=c ...

  3. css坑了我一下下之line-height

    文字上下有间隙该怎么解决 一次很搞笑的真实经历. 我:文字上下有间隙该怎么解决? 大佬A:什么意思? 大佬B:字体的原因吧. 大佬B:MD 谁看那么细. 我:跟别的图片对不齐. 真·大佬:这个我知道. ...

  4. vsftpd详解(ubuntu)

    安装 apt-get instll vsftpd 配置vsftp vim vsftpd.conf listen=YES listen_port= anonymous_enable=NO local_e ...

  5. js去掉最后一个字符

    console.log(("0,1,2,3,4,5,".slice(0,-1)))

  6. STM32 基DMA的DAC波形发生器

    DAC是STM32系列的一个基本外设,可以将数字信号转化成模拟信号,这次我将使用DAC来输出一个特定波形. 首先确定工作方法,由于我目前在做的简易示波器在输出波形的同时还需要显示输入信号,所以不能占用 ...

  7. Java并发之BlockingQueue的使用

    Java并发之BlockingQueue的使用 一.简介 前段时间看到有些朋友在网上发了一道面试题,题目的大意就是:有两个线程A,B,  A线程每200ms就生成一个[0,100]之间的随机数, B线 ...

  8. 3.1 One-dim Vector Initialtization

    vector<int> v(10, -1); //10个-1 v.size(); v.empty(); //is empty?

  9. java.lang.NoSuchMethodException: org.apache.catalina.deploy.WebXml addServlet

    解决此异常的方法是: 删除您添加在Referenced Libraries 下的catalina.jar包, 然后删除Webapp下的部署程序,重新部署后一切正常. ? --------------- ...

  10. 05_CRUD操作

      1.Params拦截器: 作用:Parameters拦截器将把表单字段映射到ValueStack栈的栈顶对象的各个属性中, 注意:如果某个字段在栈顶对象中没有对应的属性,则Params拦截器将尝试 ...