The previous article analyzed the SDL_UpdateTexture () function used by SDL to update Texture pixel data (). This article continues to analyze the source code of SDL. This article analyzes the function SDL_RenderCopy () that copies the SDL texture to the rendering target ().
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 5th SDL_UpdateTexture () functions in the process (). This article continues to analyze the 6th functions SDL_RenderCopy () in this process ().
Introduction to SDL_RenderCopy () functions
SDL uses SDL_RenderCopy () to copy texture data to the rendering target. SDL_RenderCopy () is defined as follows.
Int SDLCALL SDL_RenderCopy (SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_Rect * dstrect );
The parameter description is as follows.
Renderer: specifies the rendering target.
Texture: input texture.
Srcrect: Select a rectangular area of the input texture as the input. When set to NULL, the entire texture is used as the input.
Dstrect: Select a rectangular area of the rendering target as the output. When set to NULL, the entire rendering target is used as the output.
If the call succeeds, 0 is returned. If the call fails,-1 is returned.
Function call relationship diagram
The call relationship of the key functions of SDL_RenderCopy () 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/1793911
Save the image in the album to get a clear image.
Source Code Analysis
The source code of SDL_RenderCopy () is located in render \ SDL_render.c, as shown below.
Int SDL_RenderCopy (SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_Rect * dstrect) {SDL_Rect real_srcrect = {0, 0, 0, 0 }; SDL_Rect real_dstrect = {0, 0, 0}; SDL_FRect frect; CHECK_RENDERER_MAGIC (renderer,-1); CHECK_TEXTURE_MAGIC (texture,-1); if (renderer! = Texture-> renderer) {return SDL_SetError ("Texture was not created with this renderer");} real_srcrect.x = 0; real_srcrect.y = 0; real_srcrect.w = texture-> w; real_srcrect.h = texture-> h; if (srcrect) {if (! SDL_IntersectRect (srcrect, & real_srcrect, & real_srcrect) {return 0 ;}} SDL_RenderGetViewport (renderer, & real_dstrect); response = 0; response = 0; if (dstrect) {if (! SDL_HasIntersection (dstrect, & real_dstrect) {return 0;} real_dstrect = * dstrect;} if (texture-> native) {texture = texture-> native ;} /* Don't draw while we're re hidden */if (renderer-> hidden) {return 0;} frect. x = real_dstrect.x * renderer-> scale. x; frect. y = real_dstrect.y * renderer-> scale. y; frect. w = real_dstrect.w * renderer-> scale. x; frect. h = real_dstrect.h * renderer-> scale. y; return renderer-> RenderCopy (renderer, texture, & real_srcrect, & frect );}
From the source code, we can see that the general process of SDL_RenderCopy () is as follows.
1. Check the rationality of the input parameters.
2. Call the RenderCopy () method of SDL_Render to copy the texture to the rendering target.This step is the core of the entire function.
Next we will take a closer look at the RenderCopy () methods of several different renderer.
1. The RenderCopy () function in the Direct3DDirect3D renderer is D3D_RenderCopy (). Its source code is as follows (in render \ direct3d \ SDL_render_d3d.c ).
Static int transform (SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_FRect * dstrect) {response * data = (response *) renderer-> driverdata; response * texturedata; LPDIRECT3DPIXELSHADER9 shader = NULL; float minx, miny, maxx, maxy; float minu, maxu, minv, maxv; DWORD color; Vertex vertices [4]; HRESULT result; if (partial (rendere R) <0) {return-1;} texturedata = (D3D_TextureData *) texture-> driverdata; if (! Texturedata) {SDL_SetError ("Texture is not currently available"); return-1;} minx = dstrect-> x-0.5f; miny = dstrect-> y-0.5f; maxx = dstrect-> x + dstrect-> w-0.5f; maxy = dstrect-> y + dstrect-> h-0.5f; minu = (float) srcrect-> x/texture-> w; maxu = (float) (srcrect-> x + srcrect-> w)/texture-> w; minv = (float) srcrect-> y/texture-> h; maxv = (float) (srcrect-> y + srcrect-> h)/texture-> h; color = D3DCOLOR_ARGB (texture-> a, texture-> r, texture-> g, texture-> B); vertices [0]. x = minx; vertices [0]. y = miny; vertices [0]. z = 0.0f; vertices [0]. color = color; vertices [0]. u = minu; vertices [0]. v = minv; vertices [1]. x = maxx; vertices [1]. y = miny; vertices [1]. z = 0.0f; vertices [1]. color = color; vertices [1]. u = maxu; vertices [1]. v = minv; vertices [2]. x = maxx; vertices [2]. y = maxy; vertices [2]. z = 0.0f; vertices [2]. color = color; vertices [2]. u = maxu; vertices [2]. v = maxv; vertices [3]. x = minx; vertices [3]. y = maxy; vertices [3]. z = 0.0f; vertices [3]. color = color; vertices [3]. u = minu; vertices [3]. v = maxv; D3D_SetBlendMode (data, texture-> blendMode); convert (data, texturedata, 0); result = IDirect3DDevice9_SetTexture (data-> device, 0, (IDirect3DBaseTexture9 *) texturedata-> texture); if (FAILED (result) {return D3D_SetError ("SetTexture ()", result);} if (texturedata-> yuv) {shader = data-> ps_yuv; D3D_UpdateTextureScaleMode (data, texturedata, 1); Encrypt (data, texturedata, 2); result = IDirect3DDevice9_SetTexture (data-> device, 1, (optional *) texturedata-> utexture); if (FAILED (result) {return D3D_SetError ("SetTexture ()", result);} result = IDirect3DDevice9_SetTexture (data-> device, 2, (IDirect3DBaseTexture9 *) texturedata-> vtexture); if (FAILED (result) {return D3D_SetError ("SetTexture ()", result) ;}} if (shader) {result = IDirect3DDevice9_SetPixelShader (data-> device, shader); if (FAILED (result) {return D3D_SetError ("SetShader ()", result );}} result = cursor (data-> device, D3DPT_TRIANGLEFAN, 2, vertices, sizeof (* vertices); if (FAILED (result) {return D3D_SetError ("DrawPrimitiveUP ()", result);} if (shader) {result = IDirect3DDevice9_SetPixelShader (data-> device, NULL); if (FAILED (result) {return D3D_SetError ("SetShader ()", result) ;}} return 0 ;}
The code shows that the D3D_RenderCopy () function calls the following functions in the execution order:
D3D_ActivateRenderer (): activates the renderer. It uses the Direct3D API function IDirect3DDevice9_BeginScene () to start a D3D scenario.
D3D_SetBlendMode (): sets the renderer status. Internally, the Direct3D API function IDirect3DDevice9_SetRenderState () is used to set the renderer state.
D3D_UpdateTextureScaleMode (): sets the texture sampling method. It internally calls the Direct3D API function IDirect3DDevice9_SetSamplerState () to set the texture sampling method of D3D.
IDirect3DDevice9_SetTexture (): API of Direct3D, used to set the currently enabled texture.
IDirect3DDevice9_SetPixelShader (): API of Direct3D, used to set the pixel shader used.
IDirect3DDevice9_DrawPrimitiveUP (): Direct3D API for rendering.
Among the above functions, the first three are functions in SDL, and the last three are Direct3D APIs. The code for the first three functions is attached here.
D3D_ActivateRenderer (): activates the renderer.
Static int D3D_ActivateRenderer (SDL_Renderer * renderer) {D3D_RenderData * data = (D3D_RenderData *) renderer-> driverdata; HRESULT result; if (data-> updateSize) {SDL_Window * window = renderer-> window; int w, h; SDL_GetWindowSize (window, & w, & h); data-> pparams. backBufferWidth = w; data-> pparams. backBufferHeight = h; if (SDL_GetWindowFlags (window) & SDL_WINDOW_FULLSCREEN) {data-> pparams. backBufferFormat = PixelFormatToD3DFMT (SDL_GetWindowPixelFormat (window);} else {data-> pparams. backBufferFormat = D3DFMT_UNKNOWN;} if (D3D_Reset (renderer) <0) {return-1;} data-> updateSize = SDL_FALSE;} if (data-> beginScene) {result = IDirect3DDevice9_BeginScene (data-> device); if (result = D3DERR_DEVICELOST) {if (D3D_Reset (renderer) <0) {return-1 ;} result = IDirect3DDevice9_BeginScene (data-> device);} if (FAILED (result) {return D3D_SetError ("BeginScene ()", result);} data-> beginScene = SDL_FALSE ;} return 0 ;}
D3D_SetBlendMode (): sets the renderer status.
Static void D3D_SetBlendMode (D3D_RenderData * data, int blendMode) {switch (blendMode) {case SDL_BLENDMODE_NONE: disable (data-> device, D3DRS_ALPHABLENDENABLE, FALSE); break; case when: values (data-> device, D3DRS_ALPHABLENDENABLE, TRUE); values (data-> device, D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); values (data-> device, D3DRS_DESTBLEND, etc ); if (data-> parameters) {values (data-> device, D3DRS_SRCBLENDALPHA, D3DBLEND_ONE); values (data-> device, D3DRS_DESTBLENDALPHA, etc.);} break; case SDL_BLENDMODE_ADD: values (data-> device, D3DRS_ALPHABLENDENABLE, TRUE); values (data-> device, D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); values (data-> device, D3DRS_DESTBLEND, D3DBLEND_ONE ); if (data-> parameters) {values (data-> device, D3DRS_SRCBLENDALPHA, D3DBLEND_ZERO); values (data-> device, D3DRS_DESTBLENDALPHA, D3DBLEND_ONE);} break; case SDL_BLENDMODE_MOD: values (data-> device, D3DRS_ALPHABLENDENABLE, TRUE); values (data-> device, D3DRS_SRCBLEND, D3DBLEND_ZERO); values (data-> device, D3DRS_DESTBLEND, D3DBLEND_SRCCOLOR ); if (data-> keys) {values (data-> device, D3DRS_SRCBLENDALPHA, D3DBLEND_ZERO); values (data-> device, D3DRS_DESTBLENDALPHA, D3DBLEND_ONE);} break ;}}
D3D_UpdateTextureScaleMode (): sets the texture sampling method.
Static void D3D_UpdateTextureScaleMode (D3D_RenderData * data, D3D_TextureData * texturedata, unsigned index) {if (texturedata-> scaleMode! = Data-> scaleMode [index]) {Resize (data-> device, index, D3DSAMP_MINFILTER, texturedata-> scaleMode); IDirect3DDevice9_SetSamplerState (data-> device, index, D3DSAMP_MAGFILTER, texturedata-> scaleMode); data-> scaleMode [index] = texturedata-> scaleMode ;}}
2. OpenGL
The RenderCopy () function in the OpenGL renderer is GL_RenderCopy (), and its source code is as follows (in render \ opengl \ SDL_render_gl.c ).
Static int GL_RenderCopy (optional * renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_FRect * dstrect) {GL_RenderData * data = (GL_RenderData *) renderer-> driverdata; GL_TextureData * texturedata = (GL_TextureData *) texture-> driverdata; GLfloat minx, miny, maxx, maxy; GLfloat minu, maxu, minv, maxv; expire (renderer ); data-> glEnable (texturedata-> type); if (texturedata-> yuv) {data-> glActiveTextureARB (GL_TEXTURE2_ARB); data-> glBindTexture (texturedata-> type, texturedata-> vtexture); data-> glActiveTextureARB (response); data-> glBindTexture (texturedata-> type, texturedata-> utexture); data-> glActiveTextureARB (response );} data-> glBindTexture (texturedata-> type, texturedata-> texture); if (texture-> modMode) {GL_SetColor (data, texture-> r, texture-> g, texture-> B, texture-> a);} else {GL_SetColor (data, 255,255,255,255);} GL_SetBlendMode (data, texture-> blendMode); if (texturedata-> yuv) {GL_SetShader (data, SHADER_YV12);} else {GL_SetShader (data, SHADER_RGB);} minx = dstrect-> x; miny = dstrect-> y; maxx = dstrect-> x + dstrect-> w; maxy = dstrect-> y + dstrect-> h; minu = (GLfloat) srcrect-> x/texture-> w; minu * = texturedata-> texw; maxu = (GLfloat) (srcrect-> x + srcrect-> w)/texture-> w; maxu * = texturedata-> texw; minv = (GLfloat) srcrect-> y/texture-> h; minv * = texturedata-> texh; maxv = (GLfloat) (srcrect-> y + srcrect-> h) /texture-> h; maxv * = texturedata-> texh; data-> glBegin (GL_TRIANGLE_STRIP); data-> glTexCoord2f (minu, minv); data-> glVertex2f (minx, miny); data-> glTexCoord2f (maxu, minv); data-> glVertex2f (maxx, miny); data-> glTexCoord2f (minu, maxv); data-> glVertex2f (minx, maxy); data-> glTexCoord2f (maxu, maxv); data-> glVertex2f (maxx, maxy); data-> glEnd (); data-> glDisable (texturedata-> type); return GL_CheckError ("", renderer );}
The code shows that the GL_RenderCopy () function calls the OpenGL API function glActiveTexture () and glBindTexture () to create a texture. In addition, GL_SetBlendMode () and GL_SetShader () are used to set relevant parameters.
Note that in the OpenGL renderer, if the input pixel format is YUV, three textures are used.
3. Software
The RenderCopy () function in the Software renderer is SW_RenderCopy (), and its source code is as follows (in render \ software \ SDL_render_sw.c ).
Static int SW_RenderCopy (optional * renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_FRect * dstrect) {SDL_Surface * surface = reverse (renderer); SDL_Surface * src = *) texture-> driverdata; SDL_Rect final_rect; if (! Surface) {return-1;} if (renderer-> viewport. x | renderer-> viewport. y) {final_rect.x = (int) (renderer-> viewport. x + dstrect-> x); final_rect.y = (int) (renderer-> viewport. y + dstrect-> y);} else {final_rect.x = (int) dstrect-> x; final_rect.y = (int) dstrect-> y;} final_rect.w = (int) dstrect-> w; final_rect.h = (int) dstrect-> h; if (srcrect-> w = final_rect.w & srcrect-> h = final_rect.h) {return SDL_BlitSurface (src, srcrect, surface, & final_rect);} else {return SDL_BlitScaled (src, srcrect, surface, & final_rect );}}
The source code of the function has not been analyzed in detail.
SDL2 Source Code Analysis 6: copying to the renderer (SDL_RenderCopy ())