SDL2原始碼分析4:紋理(SDL_Texture)

來源:互聯網
上載者:User

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

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_CreateRenderer()。這篇文章繼續分析SDL的原始碼。本文分析SDL的紋理(SDL_Texture)。


SDL播放視頻的代碼流程如下所示。
初始化: 
SDL_Init(): 初始化SDL。 
SDL_CreateWindow(): 建立視窗(Window)。 
SDL_CreateRenderer(): 基於視窗建立渲染器(Render)。 
SDL_CreateTexture(): 建立紋理(Texture)。  迴圈渲染資料: 
SDL_UpdateTexture(): 設定紋理的資料。 
SDL_RenderCopy(): 紋理複製給渲染器。 

SDL_RenderPresent(): 顯示。 上篇文章分析了該流程中的第3個函數SDL_CreateRenderer()。本文繼續分析該流程中的第4個函數SDL_CreateTexture()。


SDL_Texture

SDL_Texture結構定義了一個SDL中的紋理。如果直接使用SDL2編譯好的SDK的話,是看不到SDL_Texture的內部結構的。有關它的定義在標頭檔中只有一行代碼,如下所示。

/** *  \brief An efficient driver-specific representation of pixel data */struct SDL_Texture;typedef struct SDL_Texture SDL_Texture;

在原始碼工程中可以看到SDL_Texture的定義,位於render\SDL_sysrender.h檔案中。它的定義如下。

/* Define the SDL texture structure */struct SDL_Texture{    const void *magic;    Uint32 format;              /**< The pixel format of the texture */    int access;                 /**< SDL_TextureAccess */    int w;                      /**< The width of the texture */    int h;                      /**< The height of the texture */    int modMode;                /**< The texture modulation mode */    SDL_BlendMode blendMode;    /**< The texture blend mode */    Uint8 r, g, b, a;           /**< Texture modulation values */    SDL_Renderer *renderer;    /* Support for formats not supported directly by the renderer */    SDL_Texture *native;    SDL_SW_YUVTexture *yuv;    void *pixels;    int pitch;    SDL_Rect locked_rect;    void *driverdata;           /**< Driver specific texture representation */    SDL_Texture *prev;    SDL_Texture *next;};

可以看出其中包含了一個“紋理”所具備的各種屬性。下面來看看如何建立這個SDL_Texture。

SDL_CreateTexture() 函數簡介使用SDL_CreateTexture()基於渲染器建立一個紋理。SDL_CreateTexture()的原型如下。

SDL_Texture * SDLCALL SDL_CreateTexture(SDL_Renderer * renderer,                                                        Uint32 format,                                                        int access, int w,                                                        int h);

參數的含義如下。

renderer:目標渲染器。format :紋理的格式。後面會詳述。

access :可以取以下值(定義位於SDL_TextureAccess中)    SDL_TEXTUREACCESS_STATIC :變化極少
    SDL_TEXTUREACCESS_STREAMING :變化頻繁

    SDL_TEXTUREACCESS_TARGET :暫時沒有理解

w :紋理的寬

h :紋理的高

建立成功則返回紋理的ID,失敗返回0。
函數呼叫歷程圖

SDL_ CreateTexture ()關鍵函數的調用關係可以用下圖表示。  

上面的圖片不太清晰,更清晰的圖片上傳到了相簿裡面:

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

把相簿裡面的圖片儲存下來就可以得到清晰的圖片了。
原始碼分析

SDL_CreateTexture()的原始碼位於render\SDL_render.c中。如下所示。

SDL_Texture * SDL_CreateTexture(SDL_Renderer * renderer, Uint32 format, int access, int w, int h){    SDL_Texture *texture;    CHECK_RENDERER_MAGIC(renderer, NULL);    if (!format) {        format = renderer->info.texture_formats[0];    }    if (SDL_ISPIXELFORMAT_INDEXED(format)) {        SDL_SetError("Palettized textures are not supported");        return NULL;    }    if (w <= 0 || h <= 0) {        SDL_SetError("Texture dimensions can't be 0");        return NULL;    }    if ((renderer->info.max_texture_width && w > renderer->info.max_texture_width) ||        (renderer->info.max_texture_height && h > renderer->info.max_texture_height)) {        SDL_SetError("Texture dimensions are limited to %dx%d", renderer->info.max_texture_width, renderer->info.max_texture_height);        return NULL;    }    texture = (SDL_Texture *) SDL_calloc(1, sizeof(*texture));    if (!texture) {        SDL_OutOfMemory();        return NULL;    }    texture->magic = &texture_magic;    texture->format = format;    texture->access = access;    texture->w = w;    texture->h = h;    texture->r = 255;    texture->g = 255;    texture->b = 255;    texture->a = 255;    texture->renderer = renderer;    texture->next = renderer->textures;    if (renderer->textures) {        renderer->textures->prev = texture;    }    renderer->textures = texture;    if (IsSupportedFormat(renderer, format)) {        if (renderer->CreateTexture(renderer, texture) < 0) {            SDL_DestroyTexture(texture);            return 0;        }    } else {        texture->native = SDL_CreateTexture(renderer,                                GetClosestSupportedFormat(renderer, format),                                access, w, h);        if (!texture->native) {            SDL_DestroyTexture(texture);            return NULL;        }        /* Swap textures to have texture before texture->native in the list */        texture->native->next = texture->next;        if (texture->native->next) {            texture->native->next->prev = texture->native;        }        texture->prev = texture->native->prev;        if (texture->prev) {            texture->prev->next = texture;        }        texture->native->prev = texture;        texture->next = texture->native;        renderer->textures = texture;        if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {            texture->yuv = SDL_SW_CreateYUVTexture(format, w, h);            if (!texture->yuv) {                SDL_DestroyTexture(texture);                return NULL;            }        } else if (access == SDL_TEXTUREACCESS_STREAMING) {            /* The pitch is 4 byte aligned */            texture->pitch = (((w * SDL_BYTESPERPIXEL(format)) + 3) & ~3);            texture->pixels = SDL_calloc(1, texture->pitch * h);            if (!texture->pixels) {                SDL_DestroyTexture(texture);                return NULL;            }        }    }    return texture;}

從原始碼中可以看出,SDL_CreateTexture()的大致流程如下。

1. 檢查輸入參數的合理性。例如像素格式是否支援,寬和高是否小於等於0等等。

2. 建立一個SDL_Texture。調用SDL_calloc()(實際上就是calloc())為建立的SDL_Texture分配記憶體。

3. 調用SDL_Render的CreateTexture()方法建立紋理。這一步是整個函數的核心。

下面我們詳細看一下幾種不同的渲染器的CreateTexture()的方法。 1. Direct3DDirect3D 渲染器中對應CreateTexture()的函數是D3D_CreateTexture(),它的原始碼如下所示(位於render\direct3d\SDL_render_d3d.c)。

static int D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture){    D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;    D3D_TextureData *data;    D3DPOOL pool;    DWORD usage;    HRESULT result;    data = (D3D_TextureData *) SDL_calloc(1, sizeof(*data));    if (!data) {        return SDL_OutOfMemory();    }    data->scaleMode = GetScaleQuality();    texture->driverdata = data;#ifdef USE_DYNAMIC_TEXTURE    if (texture->access == SDL_TEXTUREACCESS_STREAMING) {        pool = D3DPOOL_DEFAULT;        usage = D3DUSAGE_DYNAMIC;    } else#endif    if (texture->access == SDL_TEXTUREACCESS_TARGET) {        /* D3DPOOL_MANAGED does not work with D3DUSAGE_RENDERTARGET */        pool = D3DPOOL_DEFAULT;        usage = D3DUSAGE_RENDERTARGET;    } else {        pool = D3DPOOL_MANAGED;        usage = 0;    }    result =        IDirect3DDevice9_CreateTexture(renderdata->device, texture->w,                                       texture->h, 1, usage,                                       PixelFormatToD3DFMT(texture->format),                                       pool, &data->texture, NULL);    if (FAILED(result)) {        return D3D_SetError("CreateTexture()", result);    }    if (texture->format == SDL_PIXELFORMAT_YV12 ||        texture->format == SDL_PIXELFORMAT_IYUV) {        data->yuv = SDL_TRUE;        result =            IDirect3DDevice9_CreateTexture(renderdata->device, texture->w / 2,                                           texture->h / 2, 1, usage,                                           PixelFormatToD3DFMT(texture->format),                                           pool, &data->utexture, NULL);        if (FAILED(result)) {            return D3D_SetError("CreateTexture()", result);        }        result =            IDirect3DDevice9_CreateTexture(renderdata->device, texture->w / 2,                                           texture->h / 2, 1, usage,                                           PixelFormatToD3DFMT(texture->format),                                           pool, &data->vtexture, NULL);        if (FAILED(result)) {            return D3D_SetError("CreateTexture()", result);        }    }    return 0;}

從代碼中可以看出,該函數調用了Direct3D的API函數IDirect3DDevice9_CreateTexture()建立了一個紋理。

2. OpenGL

OpenGL渲染器中對應CreateTexture()的函數是GL_CreateTexture (),它的原始碼如下所示(位於render\opengl\SDL_render_gl.c)。

static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture){    GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;    GL_TextureData *data;    GLint internalFormat;    GLenum format, type;    int texture_w, texture_h;    GLenum scaleMode;    GL_ActivateRenderer(renderer);    if (!convert_format(renderdata, texture->format, &internalFormat,                        &format, &type)) {        return SDL_SetError("Texture format %s not supported by OpenGL",                            SDL_GetPixelFormatName(texture->format));    }    data = (GL_TextureData *) SDL_calloc(1, sizeof(*data));    if (!data) {        return SDL_OutOfMemory();    }    if (texture->access == SDL_TEXTUREACCESS_STREAMING) {        size_t size;        data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);        size = texture->h * data->pitch;        if (texture->format == SDL_PIXELFORMAT_YV12 ||            texture->format == SDL_PIXELFORMAT_IYUV) {            /* Need to add size for the U and V planes */            size += (2 * (texture->h * data->pitch) / 4);        }        data->pixels = SDL_calloc(1, size);        if (!data->pixels) {            SDL_free(data);            return SDL_OutOfMemory();        }    }    if (texture->access == SDL_TEXTUREACCESS_TARGET) {        data->fbo = GL_GetFBO(renderdata, texture->w, texture->h);    } else {        data->fbo = NULL;    }    GL_CheckError("", renderer);    renderdata->glGenTextures(1, &data->texture);    if (GL_CheckError("glGenTexures()", renderer) < 0) {        SDL_free(data);        return -1;    }    texture->driverdata = data;    if ((renderdata->GL_ARB_texture_rectangle_supported)        /* && texture->access != SDL_TEXTUREACCESS_TARGET */){        data->type = GL_TEXTURE_RECTANGLE_ARB;        texture_w = texture->w;        texture_h = texture->h;        data->texw = (GLfloat) texture_w;        data->texh = (GLfloat) texture_h;    } else {        data->type = GL_TEXTURE_2D;        texture_w = power_of_2(texture->w);        texture_h = power_of_2(texture->h);        data->texw = (GLfloat) (texture->w) / texture_w;        data->texh = (GLfloat) texture->h / texture_h;    }    data->format = format;    data->formattype = type;    scaleMode = GetScaleQuality();    renderdata->glEnable(data->type);    renderdata->glBindTexture(data->type, data->texture);    renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, scaleMode);    renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, scaleMode);    /* According to the spec, CLAMP_TO_EDGE is the default for TEXTURE_RECTANGLE       and setting it causes an INVALID_ENUM error in the latest NVidia drivers.    */    if (data->type != GL_TEXTURE_RECTANGLE_ARB) {        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,                                    GL_CLAMP_TO_EDGE);        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,                                    GL_CLAMP_TO_EDGE);    }#ifdef __MACOSX__#ifndef GL_TEXTURE_STORAGE_HINT_APPLE#define GL_TEXTURE_STORAGE_HINT_APPLE       0x85BC#endif#ifndef STORAGE_CACHED_APPLE#define STORAGE_CACHED_APPLE                0x85BE#endif#ifndef STORAGE_SHARED_APPLE#define STORAGE_SHARED_APPLE                0x85BF#endif    if (texture->access == SDL_TEXTUREACCESS_STREAMING) {        renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,                                    GL_STORAGE_SHARED_APPLE);    } else {        renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,                                    GL_STORAGE_CACHED_APPLE);    }    if (texture->access == SDL_TEXTUREACCESS_STREAMING        && texture->format == SDL_PIXELFORMAT_ARGB8888        && (texture->w % 8) == 0) {        renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);        renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);        renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,                          (data->pitch / SDL_BYTESPERPIXEL(texture->format)));        renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,                                 texture_h, 0, format, type, data->pixels);        renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);    }    else#endif    {        renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,                                 texture_h, 0, format, type, NULL);    }    renderdata->glDisable(data->type);    if (GL_CheckError("glTexImage2D()", renderer) < 0) {        return -1;    }    if (texture->format == SDL_PIXELFORMAT_YV12 ||        texture->format == SDL_PIXELFORMAT_IYUV) {        data->yuv = SDL_TRUE;        renderdata->glGenTextures(1, &data->utexture);        renderdata->glGenTextures(1, &data->vtexture);        renderdata->glEnable(data->type);        renderdata->glBindTexture(data->type, data->utexture);        renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,                                    scaleMode);        renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,                                    scaleMode);        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,                                    GL_CLAMP_TO_EDGE);        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,                                    GL_CLAMP_TO_EDGE);        renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w/2,                                 texture_h/2, 0, format, type, NULL);        renderdata->glBindTexture(data->type, data->vtexture);        renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,                                    scaleMode);        renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,                                    scaleMode);        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,                                    GL_CLAMP_TO_EDGE);        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,                                    GL_CLAMP_TO_EDGE);        renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w/2,                                 texture_h/2, 0, format, type, NULL);        renderdata->glDisable(data->type);    }    return GL_CheckError("", renderer);}

從代碼中可以看出,該函數調用了OpenGL的API函數glGenTextures(),glBindTexture()建立了一個紋理。並且使用glTexParameteri()設定了有關的一些參數。

在這裡有一點需要注意,在OpenGL渲染器中,如果輸入像素格式是YV12或者IYUV,就會使用3個紋理。 3. Software

Software渲染器中對應CreateTexture()的函數是SW_CreateTexture (),它的原始碼如下所示(位於render\software\SDL_render_sw.c)。

static int SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture){    int bpp;    Uint32 Rmask, Gmask, Bmask, Amask;    if (!SDL_PixelFormatEnumToMasks        (texture->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {        return SDL_SetError("Unknown texture format");    }    texture->driverdata =        SDL_CreateRGBSurface(0, texture->w, texture->h, bpp, Rmask, Gmask,                             Bmask, Amask);    SDL_SetSurfaceColorMod(texture->driverdata, texture->r, texture->g,                           texture->b);    SDL_SetSurfaceAlphaMod(texture->driverdata, texture->a);    SDL_SetSurfaceBlendMode(texture->driverdata, texture->blendMode);    if (texture->access == SDL_TEXTUREACCESS_STATIC) {        SDL_SetSurfaceRLE(texture->driverdata, 1);    }    if (!texture->driverdata) {        return -1;    }    return 0;}

該函數的原始碼還沒有詳細分析。可以看出其中調用了SDL_CreateRGBSurface()建立了“Surface”。



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.