The previous article analyzed the sdl_createrenderer () function used to create a Renderer in SDL (). This article continues to analyze the source code of SDL. This document analyzes the SDL texture (sdl_texture ).
The code process for playing a video by using SDL is as follows.
Initialization:
Sdl_init (): Initialize SDL.
Sdl_createwindow (): create a window ).
Sdl_createrenderer (): Creates a Renderer (render) based on the window ).
Sdl_createtexture (): Creates a texture (texture ).
Loop rendering data:
Sdl_updatetexture (): Specifies the texture data.
Sdl_rendercopy (): Copies the texture to the Renderer.
Sdl_renderpresent (): display.
The previous article analyzed the 3rd sdl_createrenderer () functions in the process (). This article continues to analyze the 4th function sdl_createtexture () in this process ().
Sdl_texture
The sdl_texture structure defines the texture in an SDL. If sdl2 compiled SDK is used directly, the internal structure of sdl_texture is invisible. Only one line of code is defined in the header file, as shown below.
/** * \brief An efficient driver-specific representation of pixel data */struct SDL_Texture;typedef struct SDL_Texture SDL_Texture;
In the source code project, you can see the definition of sdl_texture, which is located in the render \ sdl_sysrender.h file. It is defined as follows.
/* 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;};
It can be seen that it contains various attributes of a "texture. Next let's take a look at how to create this sdl_texture.
Sdl_createtexture ()
Function IntroductionUse sdl_createtexture () to create a texture based on the Renderer. Sdl_createtexture () is defined as follows.
SDL_Texture * SDLCALL SDL_CreateTexture(SDL_Renderer * renderer, Uint32 format, int access, int w, int h);
The parameter description is as follows.
Renderer: Target Renderer.
Format: Specifies the texture format. It will be detailed later.
Access: You can obtain the following values (defined in sdl_textureaccess)
Sdl_textureaccess_static: Few changes
Sdl_textureaccess_streaming: frequent changes
Sdl_textureaccess_target: not understood yet
W: texture width
H: texture height
If the creation is successful, the texture ID is returned. If the creation fails, 0 is returned.
Function call Relationship Diagram
The call relationship between the SDL _ createtexture () key functions can be expressed.
The above picture is not clear, and the clearer picture is uploaded to the album:
Http://my.csdn.net/leixiaohua1020/album/detail/1793543
Save the image in the album to get a clear image.
Source code analysis
The source code of sdl_createtexture () is located in render \ sdl_render.c. As shown below.
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;}
From the source code, we can see that the general process of sdl_createtexture () is as follows.
1. Check the rationality of the input parameters.For example, whether the pixel format is supported, and whether the width and height are less than or equal to 0.
2. Create an sdl_texture.Call sdl_calloc () (actually calloc () to allocate memory for the newly created sdl_texture.
3. Call the createtexture () method of sdl_render to create a texture.This step is the core of the entire function.
Next we will take a detailed look at the createtexture () methods of several different Renderer.
1. The createtexture () function in the direct3ddirect3d Renderer is d3d_createtexture (). Its source code is as follows (in 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;}
The Code shows that this function calls the direct3d API function idirect3ddevice9_createtexture () to create a texture.
2. OpenGL
The createtexture () function in the OpenGL Renderer is gl_createtexture (), and its source code is as follows (in 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);}
The Code shows that this function calls the OpenGL API function glgentextures () and glbindtexture () to create a texture. You can use gltexparameteri () to set relevant parameters.
Note that in the OpenGL Renderer, if the input pixel format is yv12 or iyuv, three textures are used.
3. Software
The createtexture () function in the software Renderer is sw_createtexture (), and its source code is as follows (in 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;}
The source code of the function has not been analyzed in detail. We can see that "surface" is created by calling sdl_creatergbsurface ".
Sdl2 source code analysis 4: texture (sdl_texture)