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

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

SDL_Renderer

SDL_Renderer结构体定义了一个SDL2中的渲染器,在SDL_render.h如下所示。

/**
 * A structure representing rendering state
 */
struct SDL_Renderer;
typedef struct SDL_Renderer SDL_Renderer;

在源代码工程中可以看到SDL_Renderer的定义,位于render\SDL_sysrender.h文件中。它的定义如下。

/* Define the SDL renderer structure */
struct SDL_Renderer
{
    const void *magic;

    void (*WindowEvent) (SDL_Renderer * renderer, const SDL_WindowEvent *event);
    int (*GetOutputSize) (SDL_Renderer * renderer, int *w, int *h);
    SDL_bool (*SupportsBlendMode)(SDL_Renderer * renderer, SDL_BlendMode blendMode);
    int (*CreateTexture) (SDL_Renderer * renderer, SDL_Texture * texture);
    int (*QueueSetViewport) (SDL_Renderer * renderer, SDL_RenderCommand *cmd);
    int (*QueueSetDrawColor) (SDL_Renderer * renderer, SDL_RenderCommand *cmd);
    int (*QueueDrawPoints) (SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points,
                             int count);
    int (*QueueDrawLines) (SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points,
                            int count);
    int (*QueueFillRects) (SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects,
                            int count);
    int (*QueueCopy) (SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
                       const SDL_Rect * srcrect, const SDL_FRect * dstrect);
    int (*QueueCopyEx) (SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
                        const SDL_Rect * srcquad, const SDL_FRect * dstrect,
                        const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip);
    int (*RunCommandQueue) (SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize);
    int (*UpdateTexture) (SDL_Renderer * renderer, SDL_Texture * texture,
                          const SDL_Rect * rect, const void *pixels,
                          int pitch);
#if SDL_HAVE_YUV
    int (*UpdateTextureYUV) (SDL_Renderer * renderer, SDL_Texture * texture,
                            const SDL_Rect * rect,
                            const Uint8 *Yplane, int Ypitch,
                            const Uint8 *Uplane, int Upitch,
                            const Uint8 *Vplane, int Vpitch);
    int (*UpdateTextureNV) (SDL_Renderer * renderer, SDL_Texture * texture,
                            const SDL_Rect * rect,
                            const Uint8 *Yplane, int Ypitch,
                            const Uint8 *UVplane, int UVpitch);
#endif
    int (*LockTexture) (SDL_Renderer * renderer, SDL_Texture * texture,
                        const SDL_Rect * rect, void **pixels, int *pitch);
    void (*UnlockTexture) (SDL_Renderer * renderer, SDL_Texture * texture);
    void (*SetTextureScaleMode) (SDL_Renderer * renderer, SDL_Texture * texture, SDL_ScaleMode scaleMode);
    int (*SetRenderTarget) (SDL_Renderer * renderer, SDL_Texture * texture);
    int (*RenderReadPixels) (SDL_Renderer * renderer, const SDL_Rect * rect,
                             Uint32 format, void * pixels, int pitch);
    void (*RenderPresent) (SDL_Renderer * renderer);
    void (*DestroyTexture) (SDL_Renderer * renderer, SDL_Texture * texture);

    void (*DestroyRenderer) (SDL_Renderer * renderer);

    int (*GL_BindTexture) (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh);
    int (*GL_UnbindTexture) (SDL_Renderer * renderer, SDL_Texture *texture);

    void *(*GetMetalLayer) (SDL_Renderer * renderer);
    void *(*GetMetalCommandEncoder) (SDL_Renderer * renderer);

    /* The current renderer info */
    SDL_RendererInfo info;

    /* The window associated with the renderer */
    SDL_Window *window;
    SDL_bool hidden;

    /* The logical resolution for rendering */
    int logical_w;
    int logical_h;
    int logical_w_backup;
    int logical_h_backup;

    /* Whether or not to force the viewport to even integer intervals */
    SDL_bool integer_scale;

    /* The drawable area within the window */
    SDL_Rect viewport;
    SDL_Rect viewport_backup;

    /* The clip rectangle within the window */
    SDL_Rect clip_rect;
    SDL_Rect clip_rect_backup;

    /* Wether or not the clipping rectangle is used. */
    SDL_bool clipping_enabled;
    SDL_bool clipping_enabled_backup;

    /* The render output coordinate scale */
    SDL_FPoint scale;
    SDL_FPoint scale_backup;

    /* The pixel to point coordinate scale */
    SDL_FPoint dpi_scale;

    /* Whether or not to scale relative mouse motion */
    SDL_bool relative_scaling;

    /* Remainder from scaled relative motion */
    float xrel;
    float yrel;

    /* The list of textures */
    SDL_Texture *textures;
    SDL_Texture *target;
    SDL_mutex *target_mutex;

    Uint8 r, g, b, a;                   /**< Color for drawing operations values */
    SDL_BlendMode blendMode;            /**< The drawing blend mode */

    SDL_bool always_batch;
    SDL_bool batching;
    SDL_RenderCommand *render_commands;
    SDL_RenderCommand *render_commands_tail;
    SDL_RenderCommand *render_commands_pool;
    Uint32 render_command_generation;
    Uint32 last_queued_color;
    SDL_Rect last_queued_viewport;
    SDL_Rect last_queued_cliprect;
    SDL_bool last_queued_cliprect_enabled;
    SDL_bool color_queued;
    SDL_bool viewport_queued;
    SDL_bool cliprect_queued;

    void *vertex_data;
    size_t vertex_data_used;
    size_t vertex_data_allocation;

    void *driverdata;
};

通过代码可以看出其中包含了一个“渲染器”应该包含的各种属性。

SDL_CreateRenderer()

函数简介

SDL_Renderer * SDLCALL SDL_CreateRenderer(SDL_Window * window,
                                               int index, Uint32 flags);

参数含义如下。

window : 渲染的目标窗口。

index :打算初始化的渲染设备的索引。设置“-1”则初始化默认的渲染设备。

flags :支持以下值(位于SDL_RendererFlags定义中)

SDL_RENDERER_SOFTWARE :使用软件渲染
SDL_RENDERER_ACCELERATED :使用硬件加速

SDL_RENDERER_PRESENTVSYNC:和显示器的刷新率同步
SDL_RENDERER_TARGETTEXTURE :不太懂

返回创建完成的渲染器的ID。如果创建失败则返回NULL。

源码分析

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

SDL_Renderer *
SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags)
{
#if !SDL_RENDER_DISABLED
    SDL_Renderer *renderer = NULL;
    int n = SDL_GetNumRenderDrivers();
    SDL_bool batching = SDL_TRUE;
    const char *hint;

#if defined(__ANDROID__)
    Android_ActivityMutex_Lock_Running();
#endif

    if (!window) {
        SDL_SetError("Invalid window");
        goto error;
    }

    if (SDL_GetRenderer(window)) {
        SDL_SetError("Renderer already associated with window");
        goto error;
    }

    if (SDL_GetHint(SDL_HINT_RENDER_VSYNC)) {
        if (SDL_GetHintBoolean(SDL_HINT_RENDER_VSYNC, SDL_TRUE)) {
            flags |= SDL_RENDERER_PRESENTVSYNC;
        } else {
            flags &= ~SDL_RENDERER_PRESENTVSYNC;
        }
    }

    if (index < 0) {
        hint = SDL_GetHint(SDL_HINT_RENDER_DRIVER);
        if (hint) {
            for (index = 0; index < n; ++index) {
                const SDL_RenderDriver *driver = render_drivers[index];

                if (SDL_strcasecmp(hint, driver->info.name) == 0) {
                    /* Create a new renderer instance */
                    renderer = driver->CreateRenderer(window, flags);
                    if (renderer) {
                        batching = SDL_FALSE;
                    }
                    break;
                }
            }
        }

        if (!renderer) {
            for (index = 0; index < n; ++index) {
                const SDL_RenderDriver *driver = render_drivers[index];

                if ((driver->info.flags & flags) == flags) {
                    /* Create a new renderer instance */
                    renderer = driver->CreateRenderer(window, flags);
                    if (renderer) {
                        /* Yay, we got one! */
                        break;
                    }
                }
            }
        }
        if (index == n) {
            SDL_SetError("Couldn't find matching render driver");
            goto error;
        }
    } else {
        if (index >= SDL_GetNumRenderDrivers()) {
            SDL_SetError("index must be -1 or in the range of 0 - %d",
                         SDL_GetNumRenderDrivers() - 1);
            goto error;
        }
        /* Create a new renderer instance */
        renderer = render_drivers[index]->CreateRenderer(window, flags);
        batching = SDL_FALSE;
    }

    if (!renderer) {
        goto error;
    }

    VerifyDrawQueueFunctions(renderer);

    /* let app/user override batching decisions. */
    if (renderer->always_batch) {
        batching = SDL_TRUE;
    } else if (SDL_GetHint(SDL_HINT_RENDER_BATCHING)) {
        batching = SDL_GetHintBoolean(SDL_HINT_RENDER_BATCHING, SDL_TRUE);
    }

    renderer->batching = batching;
    renderer->magic = &renderer_magic;
    renderer->window = window;
    renderer->target_mutex = SDL_CreateMutex();
    renderer->scale.x = 1.0f;
    renderer->scale.y = 1.0f;
    renderer->dpi_scale.x = 1.0f;
    renderer->dpi_scale.y = 1.0f;

    /* new textures start at zero, so we start at 1 so first render doesn't flush by accident. */
    renderer->render_command_generation = 1;

    if (window && renderer->GetOutputSize) {
        int window_w, window_h;
        int output_w, output_h;
        if (renderer->GetOutputSize(renderer, &output_w, &output_h) == 0) {
            SDL_GetWindowSize(renderer->window, &window_w, &window_h);
            renderer->dpi_scale.x = (float)window_w / output_w;
            renderer->dpi_scale.y = (float)window_h / output_h;
        }
    }

    renderer->relative_scaling = SDL_GetHintBoolean(SDL_HINT_MOUSE_RELATIVE_SCALING, SDL_TRUE);

    if (SDL_GetWindowFlags(window) & (SDL_WINDOW_HIDDEN|SDL_WINDOW_MINIMIZED)) {
        renderer->hidden = SDL_TRUE;
    } else {
        renderer->hidden = SDL_FALSE;
    }

    SDL_SetWindowData(window, SDL_WINDOWRENDERDATA, renderer);

    SDL_RenderSetViewport(renderer, NULL);

    SDL_AddEventWatch(SDL_RendererEventWatch, renderer);

    SDL_LogInfo(SDL_LOG_CATEGORY_RENDER,
                "Created renderer: %s", renderer->info.name);

#if defined(__ANDROID__)
    Android_ActivityMutex_Unlock();
#endif
    return renderer;

error:

#if defined(__ANDROID__)
    Android_ActivityMutex_Unlock();
#endif
    return NULL;

#else
    SDL_SetError("SDL not built with rendering support");
    return NULL;
#endif
}

SDL_CreateRenderer()中最重要的一个函数就是它调用了SDL_RenderDriver的CreateRenderer()方法。通过该方法可以创建一个渲染器。围绕着这个方法,包含了一些初始化工作以及一些收尾工作。下面针对这个最核心的函数进行分析。
我们首先来看一下SDL_RenderDriver这个结构体。从字面的意思可以看出它代表了“渲染器的驱动程序”。这个结构体的定义如下。

/* Define the SDL render driver structure */
struct SDL_RenderDriver
{
    SDL_Renderer *(*CreateRenderer) (SDL_Window * window, Uint32 flags);

    /* Info about the renderer capabilities */
    SDL_RendererInfo info;
};

从代码中可以看出,这个结构体的成员比较简单,包含了一个函数指针CreateRenderer()和一个存储信息的SDL_RendererInfo类型的结构体info。CreateRenderer()是用于创建渲染器的函数,而SDL_RendererInfo则包含了该结构体的一些信息,可以看一下SDL_RendererInfo的定义。

/**
 * Information on the capabilities of a render driver or context.
 */
typedef struct SDL_RendererInfo
{
    const char *name;           /**< The name of the renderer */
    Uint32 flags;               /**< Supported ::SDL_RendererFlags */
    Uint32 num_texture_formats; /**< The number of available texture formats */
    Uint32 texture_formats[16]; /**< The available texture formats */
    int max_texture_width;      /**< The maximum texture width */
    int max_texture_height;     /**< The maximum texture height */
} SDL_RendererInfo;

在SDL中有一个全局的SDL_RenderDriver类型的静态数组render_drivers,其中存储了SDL支持的所有渲染器。该数组定义如下。

static const SDL_RenderDriver *render_drivers[] = {
#if SDL_VIDEO_RENDER_D3D
    &D3D_RenderDriver,
#endif
#if SDL_VIDEO_RENDER_D3D11
    &D3D11_RenderDriver,
#endif
#if SDL_VIDEO_RENDER_METAL
    &METAL_RenderDriver,
#endif
#if SDL_VIDEO_RENDER_OGL
    &GL_RenderDriver,
#endif
#if SDL_VIDEO_RENDER_OGL_ES2
    &GLES2_RenderDriver,
#endif
#if SDL_VIDEO_RENDER_OGL_ES
    &GLES_RenderDriver,
#endif
#if SDL_VIDEO_RENDER_DIRECTFB
    &DirectFB_RenderDriver,
#endif
#if SDL_VIDEO_RENDER_PSP
    &PSP_RenderDriver,
#endif
#if SDL_VIDEO_RENDER_VITA_GXM
    &VITA_GXM_RenderDriver,
#endif
#if SDL_VIDEO_RENDER_SW
    &SW_RenderDriver
#endif
};

从render_drivers数组的定义可以看出,其中包含了Direct3D,OpenGL,OpenGL ES等各种渲染器的驱动程序。我们可以选择几个看一下。

例如Direct3D的渲染器驱动程序D3D_RenderDriver的定义如下(位于render\direct3d\SDL_render_d3d.c)。

SDL_RenderDriver D3D_RenderDriver = {
    D3D_CreateRenderer,
    {
     "direct3d",
     (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
     1,
     {SDL_PIXELFORMAT_ARGB8888},
     0,
     0}
};

可以看出创建OpenGL渲染器的函数是GL_CreateRenderer()。

参考文献

1、https://blog.csdn.net/leixiaohua1020/article/details/40723085

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值