sdl2 opengl d3d9的mipmap和各项异性过滤渲染

Posted qianbo_insist

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sdl2 opengl d3d9的mipmap和各项异性过滤渲染相关的知识,希望对你有一定的参考价值。

sdl支持的驱动


列出后可以根据自己的需求去做,如果没有驱动就使用software去做就好了,以下列出对比,视频源为1280 720 的摄像头,使用RGB24来测试

opengl

CPU占用率在1.3% 到 1.5% 之间
GPU在5%到6.2%之间

D3D9

cpu 占用率在0.9 到1.6 之间
GPU在5%到6.2%之间

D3D11

CPU 占用率在0.7%到2.0% 之间
GPU在4.6%到5.7%之间
DEBUG 和RELEASE 并没有多大差异。
三者清晰度基本一致。

software

CPU 占用率在0.6%- 1.6%之间
GPU为零

测试代码

以下代码有冗余


int ret = cap.OpenCameraRGB(name.c_str(), w, h);
	if (ret != 0)
		return -1;

	int					screen_w, screen_h;
	SDL_Window			*screen = NULL;
	SDL_Window          *screenD3D = NULL;
	SDL_Window          *screenD3D11 = NULL;
	SDL_Renderer		*sdlRenderer = NULL;
	SDL_Renderer		*sdlRendererD3D = NULL;
	SDL_Renderer		*sdlRendererD3D11 = NULL;
	SDL_Texture			*sdlTexture = NULL;
	SDL_Texture			*sdlTextureD3D = NULL;
	SDL_Texture			*sdlTextureD3D11 = NULL;
	SDL_Rect			sdlRect;
	SDL_Thread			*video_tid;
	SDL_Event			event;
	
	SDL_Init(SDL_INIT_VIDEO |  SDL_INIT_TIMER);
	SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");
	//SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
	//SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);

	int MODE =-1;
	screen_w = w; 
	screen_h = w *9 /16;
	//screen_h = screen_w * 9 / 16;

   if (MODE == -1)
	screen = SDL_CreateWindow("FF", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
		640, 360, SDL_WINDOW_SHOWN/* SDL_WINDOW_OPENGL*/); //,
   else if(MODE == 0)
	screenD3D = SDL_CreateWindow("FFD3D", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
		640, 360, SDL_WINDOW_SHOWN/* SDL_WINDOW_OPENGL*/);
   else if(MODE == 1)
	screenD3D11 = SDL_CreateWindow("FFD3D11", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
		640, 360, SDL_WINDOW_SHOWN/* SDL_WINDOW_OPENGL*/);

	for (int i = 0; i < SDL_GetNumRenderDrivers(); ++i)
	
		SDL_RendererInfo rendererInfo = ;
		SDL_GetRenderDriverInfo(i, &rendererInfo);
		cout <<i<<" "<< rendererInfo.name << endl;
		//if (rendererInfo.name != std::string("direct3d11"))
		//
		//	continue;
		//
	
	if (MODE == -1)
	
		sdlRenderer = SDL_CreateRenderer(screen, 4, SDL_RENDERER_SOFTWARE);
		sdlTexture = SDL_CreateTexture(sdlRenderer,
			SDL_PIXELFORMAT_BGR24, //SDL_PIXELFORMAT_IYUV, //SDL_PIXELFORMAT_BGR24
			SDL_TEXTUREACCESS_STREAMING,/*SDL_TEXTUREACCESS_STREAMING,*/
			w, h);
	
	else if (MODE == 0)
	
		sdlRendererD3D = SDL_CreateRenderer(screenD3D, 0, SDL_RENDERER_ACCELERATED);
		sdlTextureD3D = SDL_CreateTexture(sdlRendererD3D,
			SDL_PIXELFORMAT_BGR24, //SDL_PIXELFORMAT_IYUV, //SDL_PIXELFORMAT_BGR24
			SDL_TEXTUREACCESS_STREAMING,/*SDL_TEXTUREACCESS_STREAMING,*/

			w, h);
	
	else if (MODE == 1)
	
		sdlRendererD3D11 = SDL_CreateRenderer(screenD3D11, 1, SDL_RENDERER_ACCELERATED);
		sdlTextureD3D11 = SDL_CreateTexture(sdlRendererD3D11,
			SDL_PIXELFORMAT_BGR24, //SDL_PIXELFORMAT_IYUV, //SDL_PIXELFORMAT_BGR24
			SDL_TEXTUREACCESS_STREAMING,/*SDL_TEXTUREACCESS_STREAMING,*/

			w, h);

	
	
	sdlRect.x = 0;
	sdlRect.y = 0;
	sdlRect.w = w;
	sdlRect.h = w*9/16;
	video_tid = SDL_CreateThread(sfp_refresh_thread, NULL, NULL);
	int got_picture;
	for (;;)
	
		SDL_WaitEvent(&event);
		if (event.type == SFM_REFRESH_EVENT)
		
			uint8_t *frame = cap.QueryFrame();

			if (frame != NULL)
			
				//int y = screen_h * 2 / 3;

				if (MODE == -1)
				
					SDL_UpdateTexture(sdlTexture, NULL/*&sdlRect*/, frame, w * 3);
					//SDL_UpdateTexture(sdlTexture, &sdlRect, out_buffer + W * H * 3, -W * 3);

					SDL_RenderClear(sdlRenderer);
					SDL_RenderCopy(sdlRenderer, sdlTexture, &sdlRect,NULL);
					SDL_RenderPresent(sdlRenderer);
				
				else if (MODE == 0)
				
					SDL_UpdateTexture(sdlTextureD3D, NULL/*&sdlRect*/, frame, w * 3);
					//SDL_UpdateTexture(sdlTexture, &sdlRect, out_buffer + W * H * 3, -W * 3);
					SDL_RenderClear(sdlRendererD3D);
					SDL_RenderCopy(sdlRendererD3D, sdlTextureD3D, &sdlRect, NULL);
					SDL_RenderPresent(sdlRendererD3D);
				
				else if (MODE == 1)
				
					SDL_UpdateTexture(sdlTextureD3D11, NULL/*&sdlRect*/, frame, w * 3);
					//SDL_UpdateTexture(sdlTexture, &sdlRect, out_buffer + W * H * 3, -W * 3);
					SDL_RenderClear(sdlRendererD3D11);
					SDL_RenderCopy(sdlRendererD3D11, sdlTextureD3D11, &sdlRect, NULL);
					SDL_RenderPresent(sdlRendererD3D11);
				
			
		
		else if (event.type == SDL_KEYDOWN)
		
			if (event.key.keysym.sym == SDLK_SPACE)
				thread_pause = !thread_pause;
		
		else if (event.type == SDL_QUIT)
		
			thread_exit = 1;
		
		else if (event.type == SFM_BREAK_EVENT)
		
			break;
		
	

sdl2 渲染问题

sdl2 的渲染里面并没有再高级的放大缩小算法,在大的图像缩小时会产生不舒服的纹理,需要滤波算法,这需要修改源码。

sdl opengl 渲染

	screen = SDL_CreateWindow("FFGL", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
			640, 360, SDL_WINDOW_OPENGL); //,

		glContext = SDL_GL_CreateContext(screen);
		if (glContext == NULL)
		
			// Display error message
			printf("OpenGL context could not be created! SDL Error: %s\\n", SDL_GetError());
			return false;
		
		else
		
			glewInit();
		

使用opengl 要创建opengl得窗口,并且产生mipmap图像,就能够比较清晰,这个要自己写的,sdl2 里面并没有加入这个方法,但是这个方式是可以的,需要自己写opengl的代码,下面使用d3d9,在sdl2 中d3d9也并没有使用mipmap 图像,也没有使用各项异性过滤。

修改sdl d3d9代码

	/* setup default renderstate */
	IDirect3DDevice9_SetRenderState(m_d3d_device, D3DRS_SRCBLEND, D3DBLEND_ONE);
	IDirect3DDevice9_SetRenderState(m_d3d_device, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
	IDirect3DDevice9_SetRenderState(m_d3d_device, D3DRS_ALPHAFUNC, D3DCMP_GREATER);
	IDirect3DDevice9_SetRenderState(m_d3d_device, D3DRS_ALPHAREF, (DWORD)0x0);
	IDirect3DDevice9_SetRenderState(m_d3d_device, D3DRS_LIGHTING, FALSE);
	IDirect3DDevice9_SetSamplerState(m_d3d_device, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
	IDirect3DDevice9_SetSamplerState(m_d3d_device, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);

找到所有Create_Texture 的代码

result = IDirect3DDevice9_CreateTexture(device, texturerep->w, texturerep->h,1, texturerep->usage,
                PixelFormatToD3DFMT(texturerep->format), D3DPOOL_DEFAULT, &texturerep->texture, NULL);

修改成

result = IDirect3DDevice9_CreateTexture(device, texturerep->w, texturerep->h,0, texturerep->usage,
                PixelFormatToD3DFMT(texturerep->format), D3DPOOL_DEFAULT, &texturerep->texture, NULL);

//1 改成0 ,
各项异性过滤加上,mipmap 生成等级map加上,结果出问题
IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC);
		IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
		IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);

在d3d9 的render里面修改使用后,sdl 窗口大小必须和纹理大小一样,否则黑屏。所以这个方式就没有用了。

显示正确方法

前面得修改都去除,sdl 源代码不修改,如果直接使用ffmpeg的缩小方法,缩放到和窗口一样大小,那直接显示就非常好了。下面对比以下

总结

前面使用了一堆好的方法,sdl最后放到窗口上时没有算法保证过滤。这个要修正。

不使用sdl

不使用sdl,直接使用opengl 或者 direct3d是比较合适的。快速地做出一个显示效果可以使用sdl,不建议在产品中使用。

以上是关于sdl2 opengl d3d9的mipmap和各项异性过滤渲染的主要内容,如果未能解决你的问题,请参考以下文章

SDL2 主滴答系统(openGL)

SDL2:如何同时拥有 SDL2 菜单和 OpenGL 上下文?

opengl 渲染纹理并在是不是使用 mipmap 之间切换

SDL2 OpenGL 抗锯齿没有效果

SDL2 / Opengl3 无法显示任何内容

SDL2+OpenGL 绘制立体图形