2 * Copyright (C) 2007-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
23 #include "WinVideoFilter.h"
24 #include "windowing/WindowingFactory.h"
25 #include "../../../utils/log.h"
26 #include "../../../FileSystem/File.h"
28 #include "ConvolutionKernels.h"
29 #include "YUV2RGBShader.h"
30 #include "win32/WIN32Util.h"
31 #include "cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h"
33 CYUV2RGBMatrix::CYUV2RGBMatrix()
39 m_format = RENDER_FMT_NONE;
42 void CYUV2RGBMatrix::SetParameters(float contrast, float blacklevel, unsigned int flags, ERenderFormat format)
44 if (m_contrast != contrast)
47 m_contrast = contrast;
49 if (m_blacklevel != blacklevel)
52 m_blacklevel = blacklevel;
59 if (m_format != format)
66 D3DXMATRIX* CYUV2RGBMatrix::Matrix()
70 TransformMatrix matrix;
71 CalculateYUVMatrix(matrix, m_flags, m_format, m_blacklevel, m_contrast);
73 m_mat._11 = matrix.m[0][0];
74 m_mat._12 = matrix.m[1][0];
75 m_mat._13 = matrix.m[2][0];
77 m_mat._21 = matrix.m[0][1];
78 m_mat._22 = matrix.m[1][1];
79 m_mat._23 = matrix.m[2][1];
81 m_mat._31 = matrix.m[0][2];
82 m_mat._32 = matrix.m[1][2];
83 m_mat._33 = matrix.m[2][2];
85 m_mat._41 = matrix.m[0][3];
86 m_mat._42 = matrix.m[1][3];
87 m_mat._43 = matrix.m[2][3];
95 //===================================================================
97 CWinShader::~CWinShader()
106 bool CWinShader::CreateVertexBuffer(DWORD FVF, unsigned int vertCount, unsigned int vertSize, unsigned int primitivesCount)
108 if (!m_vb.Create(vertCount * vertSize, D3DUSAGE_WRITEONLY, FVF, g_Windowing.DefaultD3DPool()))
110 m_vbsize = vertCount * vertSize;
112 m_vertsize = vertSize;
113 m_primitivesCount = primitivesCount;
117 bool CWinShader::LockVertexBuffer(void **data)
119 if (!m_vb.Lock(0, m_vbsize, data, 0))
121 CLog::Log(LOGERROR, __FUNCTION__" - failed to lock vertex buffer");
127 bool CWinShader::UnlockVertexBuffer()
131 CLog::Log(LOGERROR, __FUNCTION__" - failed to unlock vertex buffer");
137 bool CWinShader::LoadEffect(CStdString filename, DefinesMap* defines)
139 CLog::Log(LOGDEBUG, __FUNCTION__" - loading shader %s", filename.c_str());
141 XFILE::CFileStream file;
142 if(!file.Open(filename))
144 CLog::Log(LOGERROR, __FUNCTION__" - failed to open file %s", filename.c_str());
148 CStdString pStrEffect;
149 getline(file, pStrEffect, '\0');
151 if (!m_effect.Create(pStrEffect, defines))
153 CLog::Log(LOGERROR, __FUNCTION__" %s failed", pStrEffect.c_str());
160 bool CWinShader::Execute(std::vector<LPDIRECT3DSURFACE9> *vecRT, unsigned int vertexIndexStep)
162 LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
164 LPDIRECT3DSURFACE9 oldRT = 0;
165 // The render target will be overriden: save the caller's original RT
166 if (vecRT != NULL && !vecRT->empty())
167 pD3DDevice->GetRenderTarget(0, &oldRT);
169 pD3DDevice->SetFVF(m_FVF);
170 pD3DDevice->SetStreamSource(0, m_vb.Get(), 0, m_vertsize);
173 if (!m_effect.Begin( &cPasses, 0 ))
175 CLog::Log(LOGERROR, __FUNCTION__" - failed to begin d3d effect");
179 for( iPass = 0; iPass < cPasses; iPass++ )
181 if (!m_effect.BeginPass( iPass ))
183 CLog::Log(LOGERROR, __FUNCTION__" - failed to begin d3d effect pass");
187 if (vecRT != NULL && vecRT->size() > iPass)
188 pD3DDevice->SetRenderTarget(0, (*vecRT)[iPass]);
190 HRESULT hr = pD3DDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, iPass * vertexIndexStep, m_primitivesCount);
192 CLog::Log(LOGERROR, __FUNCTION__" - failed DrawPrimitive %08X", hr);
194 if (!m_effect.EndPass())
195 CLog::Log(LOGERROR, __FUNCTION__" - failed to end d3d effect pass");
198 CLog::Log(LOGERROR, __FUNCTION__" - failed to end d3d effect");
202 pD3DDevice->SetRenderTarget(0, oldRT);
209 //==================================================================================
211 bool CYUV2RGBShader::Create(unsigned int sourceWidth, unsigned int sourceHeight, ERenderFormat fmt)
213 CWinShader::CreateVertexBuffer(D3DFVF_XYZRHW | D3DFVF_TEX3, 4, sizeof(CUSTOMVERTEX), 2);
215 m_sourceWidth = sourceWidth;
216 m_sourceHeight = sourceHeight;
219 unsigned int texWidth;
223 if (fmt == RENDER_FMT_YUV420P16)
225 defines["XBMC_YV12"] = "";
226 texWidth = sourceWidth;
228 if(!m_YUVPlanes[0].Create(texWidth , m_sourceHeight , 1, 0, D3DFMT_L16, D3DPOOL_DEFAULT)
229 || !m_YUVPlanes[1].Create(texWidth / 2, m_sourceHeight / 2, 1, 0, D3DFMT_L16, D3DPOOL_DEFAULT)
230 || !m_YUVPlanes[2].Create(texWidth / 2, m_sourceHeight / 2, 1, 0, D3DFMT_L16, D3DPOOL_DEFAULT))
232 CLog::Log(LOGERROR, __FUNCTION__": Failed to create 16 bit YV12 planes.");
236 else if (fmt == RENDER_FMT_YUV420P10)
238 defines["XBMC_YV12"] = "";
239 texWidth = sourceWidth;
241 if(!m_YUVPlanes[0].Create(texWidth , m_sourceHeight , 1, 0, D3DFMT_L16, D3DPOOL_DEFAULT)
242 || !m_YUVPlanes[1].Create(texWidth / 2, m_sourceHeight / 2, 1, 0, D3DFMT_L16, D3DPOOL_DEFAULT)
243 || !m_YUVPlanes[2].Create(texWidth / 2, m_sourceHeight / 2, 1, 0, D3DFMT_L16, D3DPOOL_DEFAULT))
245 CLog::Log(LOGERROR, __FUNCTION__": Failed to create 10 bit YV12 planes.");
249 else if (fmt == RENDER_FMT_YUV420P)
251 defines["XBMC_YV12"] = "";
252 texWidth = sourceWidth;
254 if(!m_YUVPlanes[0].Create(texWidth , m_sourceHeight , 1, 0, D3DFMT_L8, D3DPOOL_DEFAULT)
255 || !m_YUVPlanes[1].Create(texWidth / 2, m_sourceHeight / 2, 1, 0, D3DFMT_L8, D3DPOOL_DEFAULT)
256 || !m_YUVPlanes[2].Create(texWidth / 2, m_sourceHeight / 2, 1, 0, D3DFMT_L8, D3DPOOL_DEFAULT))
258 CLog::Log(LOGERROR, __FUNCTION__": Failed to create YV12 planes.");
262 else if (fmt == RENDER_FMT_NV12)
264 defines["XBMC_NV12"] = "";
265 texWidth = sourceWidth;
267 if(!m_YUVPlanes[0].Create(texWidth , m_sourceHeight , 1, 0, D3DFMT_L8, D3DPOOL_DEFAULT)
268 || !m_YUVPlanes[1].Create(texWidth / 2, m_sourceHeight / 2, 1, 0, D3DFMT_A8L8, D3DPOOL_DEFAULT))
270 CLog::Log(LOGERROR, __FUNCTION__": Failed to create NV12 planes.");
274 else if (fmt == RENDER_FMT_YUYV422)
276 defines["XBMC_YUY2"] = "";
277 texWidth = sourceWidth >> 1;
279 if(!m_YUVPlanes[0].Create(texWidth , m_sourceHeight , 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT))
281 CLog::Log(LOGERROR, __FUNCTION__": Failed to create YUY2 planes.");
285 else if (fmt == RENDER_FMT_UYVY422)
287 defines["XBMC_UYVY"] = "";
288 texWidth = sourceWidth >> 1;
290 if(!m_YUVPlanes[0].Create(texWidth , m_sourceHeight , 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT))
292 CLog::Log(LOGERROR, __FUNCTION__": Failed to create UYVY planes.");
299 m_texSteps[0] = 1.0f/(float)texWidth;
300 m_texSteps[1] = 1.0f/(float)sourceHeight;
302 CStdString effectString = "special://xbmc/system/shaders/yuv2rgb_d3d.fx";
304 if(!LoadEffect(effectString, &defines))
306 CLog::Log(LOGERROR, __FUNCTION__": Failed to load shader %s.", effectString.c_str());
313 void CYUV2RGBShader::Render(CRect sourceRect, CRect destRect,
319 PrepareParameters(sourceRect, destRect,
320 contrast, brightness, flags);
322 SetShaderParameters(YUVbuf);
326 CYUV2RGBShader::~CYUV2RGBShader()
328 for(unsigned i = 0; i < MAX_PLANES; i++)
330 if (m_YUVPlanes[i].Get())
331 m_YUVPlanes[i].Release();
335 void CYUV2RGBShader::PrepareParameters(CRect sourceRect,
341 //See RGB renderer for comment on this
342 #define CHROMAOFFSET_HORIZ 0.25f
344 if (m_sourceRect != sourceRect || m_destRect != destRect)
346 m_sourceRect = sourceRect;
347 m_destRect = destRect;
350 CWinShader::LockVertexBuffer((void**)&v);
352 v[0].x = destRect.x1;
353 v[0].y = destRect.y1;
354 v[0].tu = sourceRect.x1 / m_sourceWidth;
355 v[0].tv = sourceRect.y1 / m_sourceHeight;
356 v[0].tu2 = v[0].tu3 = (sourceRect.x1 / 2.0f + CHROMAOFFSET_HORIZ) / (m_sourceWidth>>1);
357 v[0].tv2 = v[0].tv3 = (sourceRect.y1 / 2.0f + CHROMAOFFSET_HORIZ) / (m_sourceHeight>>1);
359 v[1].x = destRect.x2;
360 v[1].y = destRect.y1;
361 v[1].tu = sourceRect.x2 / m_sourceWidth;
362 v[1].tv = sourceRect.y1 / m_sourceHeight;
363 v[1].tu2 = v[1].tu3 = (sourceRect.x2 / 2.0f + CHROMAOFFSET_HORIZ) / (m_sourceWidth>>1);
364 v[1].tv2 = v[1].tv3 = (sourceRect.y1 / 2.0f + CHROMAOFFSET_HORIZ) / (m_sourceHeight>>1);
366 v[2].x = destRect.x2;
367 v[2].y = destRect.y2;
368 v[2].tu = sourceRect.x2 / m_sourceWidth;
369 v[2].tv = sourceRect.y2 / m_sourceHeight;
370 v[2].tu2 = v[2].tu3 = (sourceRect.x2 / 2.0f + CHROMAOFFSET_HORIZ) / (m_sourceWidth>>1);
371 v[2].tv2 = v[2].tv3 = (sourceRect.y2 / 2.0f + CHROMAOFFSET_HORIZ) / (m_sourceHeight>>1);
373 v[3].x = destRect.x1;
374 v[3].y = destRect.y2;
375 v[3].tu = sourceRect.x1 / m_sourceWidth;
376 v[3].tv = sourceRect.y2 / m_sourceHeight;
377 v[3].tu2 = v[3].tu3 = (sourceRect.x1 / 2.0f + CHROMAOFFSET_HORIZ) / (m_sourceWidth>>1);
378 v[3].tv2 = v[3].tv3 = (sourceRect.y2 / 2.0f + CHROMAOFFSET_HORIZ) / (m_sourceHeight>>1);
380 // -0.5 offset to compensate for D3D rasterization
382 for(int i = 0; i < 4; i++)
389 CWinShader::UnlockVertexBuffer();
392 m_matrix.SetParameters(contrast * 0.02f,
393 brightness * 0.01f - 0.5f,
398 void CYUV2RGBShader::SetShaderParameters(YUVBuffer* YUVbuf)
400 m_effect.SetMatrix("g_ColorMatrix", m_matrix.Matrix());
401 m_effect.SetTechnique("YUV2RGB_T");
402 m_effect.SetTexture("g_YTexture", m_YUVPlanes[0]);
403 if (YUVbuf->GetActivePlanes() > 1)
404 m_effect.SetTexture("g_UTexture", m_YUVPlanes[1]);
405 if (YUVbuf->GetActivePlanes() > 2)
406 m_effect.SetTexture("g_VTexture", m_YUVPlanes[2]);
407 m_effect.SetFloatArray("g_StepXY", m_texSteps, sizeof(m_texSteps)/sizeof(m_texSteps[0]));
410 bool CYUV2RGBShader::UploadToGPU(YUVBuffer* YUVbuf)
412 const POINT point = { 0, 0 };
414 for (unsigned int i = 0; i<YUVbuf->GetActivePlanes(); i++)
416 const RECT rect = { 0, 0, YUVbuf->planes[i].texture.GetWidth(), YUVbuf->planes[i].texture.GetHeight() };
417 IDirect3DSurface9 *src, *dest;
418 if(FAILED(YUVbuf->planes[i].texture.Get()->GetSurfaceLevel(0, &src)))
419 CLog::Log(LOGERROR, __FUNCTION__": Failed to retrieve level 0 surface for source YUV plane %d", i);
420 if (FAILED(m_YUVPlanes[i].Get()->GetSurfaceLevel(0, &dest)))
421 CLog::Log(LOGERROR, __FUNCTION__": Failed to retrieve level 0 surface for destination YUV plane %d", i);
423 if (FAILED(g_Windowing.Get3DDevice()->UpdateSurface(src, &rect, dest, &point)))
425 CLog::Log(LOGERROR, __FUNCTION__": Failed to copy plane %d from sysmem to vidmem.", i);
436 //==================================================================================
438 CConvolutionShader::~CConvolutionShader()
440 if(m_HQKernelTexture.Get())
441 m_HQKernelTexture.Release();
444 bool CConvolutionShader::ChooseKernelD3DFormat()
446 if (g_Windowing.IsTextureFormatOk(D3DFMT_A16B16G16R16F, 0))
448 m_KernelFormat = D3DFMT_A16B16G16R16F;
452 else if (g_Windowing.IsTextureFormatOk(D3DFMT_A8B8G8R8, 0))
454 m_KernelFormat = D3DFMT_A8B8G8R8;
458 else if (g_Windowing.IsTextureFormatOk(D3DFMT_A8R8G8B8, 0))
460 m_KernelFormat = D3DFMT_A8R8G8B8;
470 bool CConvolutionShader::CreateHQKernel(ESCALINGMETHOD method)
472 CConvolutionKernel kern(method, 256);
474 if (!m_HQKernelTexture.Create(kern.GetSize(), 1, 1, g_Windowing.DefaultD3DUsage(), m_KernelFormat, g_Windowing.DefaultD3DPool()))
476 CLog::Log(LOGERROR, __FUNCTION__": Failed to create kernel texture.");
485 float *rawVals = kern.GetFloatPixels();
486 D3DXFLOAT16* float16Vals = new D3DXFLOAT16[kern.GetSize()*4];
488 for(int i = 0; i < kern.GetSize()*4; i++)
489 float16Vals[i] = rawVals[i];
490 kernelVals = float16Vals;
491 kernelValsSize = sizeof(D3DXFLOAT16)*kern.GetSize()*4;
495 kernelVals = kern.GetUint8Pixels();
496 kernelValsSize = sizeof(uint8_t)*kern.GetSize()*4;
500 if (!m_HQKernelTexture.LockRect(0, &lr, NULL, D3DLOCK_DISCARD))
501 CLog::Log(LOGERROR, __FUNCTION__": Failed to lock kernel texture.");
502 memcpy(lr.pBits, kernelVals, kernelValsSize);
503 if (!m_HQKernelTexture.UnlockRect(0))
504 CLog::Log(LOGERROR, __FUNCTION__": Failed to unlock kernel texture.");
511 //==================================================================================
512 bool CConvolutionShader1Pass::Create(ESCALINGMETHOD method)
514 CStdString effectString;
517 case VS_SCALINGMETHOD_CUBIC:
518 case VS_SCALINGMETHOD_LANCZOS2:
519 case VS_SCALINGMETHOD_SPLINE36_FAST:
520 case VS_SCALINGMETHOD_LANCZOS3_FAST:
521 effectString = "special://xbmc/system/shaders/convolution-4x4_d3d.fx";
523 case VS_SCALINGMETHOD_SPLINE36:
524 case VS_SCALINGMETHOD_LANCZOS3:
525 effectString = "special://xbmc/system/shaders/convolution-6x6_d3d.fx";
528 CLog::Log(LOGERROR, __FUNCTION__": scaling method %d not supported.", method);
532 if (!ChooseKernelD3DFormat())
534 CLog::Log(LOGERROR, __FUNCTION__": failed to find a compatible texture format for the kernel.");
538 CWinShader::CreateVertexBuffer(D3DFVF_XYZRHW | D3DFVF_TEX1, 4, sizeof(CUSTOMVERTEX), 2);
542 defines["HAS_FLOAT_TEXTURE"] = "";
544 defines["HAS_RGBA"] = "";
546 if(!LoadEffect(effectString, &defines))
548 CLog::Log(LOGERROR, __FUNCTION__": Failed to load shader %s.", effectString.c_str());
552 if (!CreateHQKernel(method))
558 void CConvolutionShader1Pass::Render(CD3DTexture &sourceTexture,
559 unsigned int sourceWidth, unsigned int sourceHeight,
560 unsigned int destWidth, unsigned int destHeight,
564 PrepareParameters(sourceWidth, sourceHeight, sourceRect, destRect);
565 float texSteps[] = { 1.0f/(float)sourceWidth, 1.0f/(float)sourceHeight};
566 SetShaderParameters(sourceTexture, &texSteps[0], sizeof(texSteps)/sizeof(texSteps[0]));
570 void CConvolutionShader1Pass::PrepareParameters(unsigned int sourceWidth, unsigned int sourceHeight,
574 if(m_sourceWidth != sourceWidth || m_sourceHeight != sourceHeight
575 || m_sourceRect != sourceRect || m_destRect != destRect)
577 m_sourceWidth = sourceWidth;
578 m_sourceHeight = sourceHeight;
579 m_sourceRect = sourceRect;
580 m_destRect = destRect;
583 CWinShader::LockVertexBuffer((void**)&v);
585 v[0].x = destRect.x1;
586 v[0].y = destRect.y1;
587 v[0].tu = sourceRect.x1 / sourceWidth;
588 v[0].tv = sourceRect.y1 / sourceHeight;
590 v[1].x = destRect.x2;
591 v[1].y = destRect.y1;
592 v[1].tu = sourceRect.x2 / sourceWidth;
593 v[1].tv = sourceRect.y1 / sourceHeight;
595 v[2].x = destRect.x2;
596 v[2].y = destRect.y2;
597 v[2].tu = sourceRect.x2 / sourceWidth;
598 v[2].tv = sourceRect.y2 / sourceHeight;
600 v[3].x = destRect.x1;
601 v[3].y = destRect.y2;
602 v[3].tu = sourceRect.x1 / sourceWidth;
603 v[3].tv = sourceRect.y2 / sourceHeight;
605 // -0.5 offset to compensate for D3D rasterization
607 for(int i = 0; i < 4; i++)
615 CWinShader::UnlockVertexBuffer();
619 void CConvolutionShader1Pass::SetShaderParameters(CD3DTexture &sourceTexture, float* texSteps, int texStepsCount)
621 m_effect.SetTechnique( "SCALER_T" );
622 m_effect.SetTexture( "g_Texture", sourceTexture ) ;
623 m_effect.SetTexture( "g_KernelTexture", m_HQKernelTexture );
624 m_effect.SetFloatArray("g_StepXY", texSteps, texStepsCount);
627 //==================================================================================
629 CConvolutionShaderSeparable::CConvolutionShaderSeparable()
637 bool CConvolutionShaderSeparable::Create(ESCALINGMETHOD method)
639 CStdString effectString;
642 case VS_SCALINGMETHOD_CUBIC:
643 case VS_SCALINGMETHOD_LANCZOS2:
644 case VS_SCALINGMETHOD_SPLINE36_FAST:
645 case VS_SCALINGMETHOD_LANCZOS3_FAST:
646 effectString = "special://xbmc/system/shaders/convolutionsep-4x4_d3d.fx";
648 case VS_SCALINGMETHOD_SPLINE36:
649 case VS_SCALINGMETHOD_LANCZOS3:
650 effectString = "special://xbmc/system/shaders/convolutionsep-6x6_d3d.fx";
653 CLog::Log(LOGERROR, __FUNCTION__": scaling method %d not supported.", method);
657 if (!ChooseIntermediateD3DFormat())
659 CLog::Log(LOGERROR, __FUNCTION__": failed to find a compatible texture format for the intermediate render target.");
663 if (!ChooseKernelD3DFormat())
665 CLog::Log(LOGERROR, __FUNCTION__": failed to find a compatible texture format for the kernel.");
669 CWinShader::CreateVertexBuffer(D3DFVF_XYZRHW | D3DFVF_TEX1, 8, sizeof(CUSTOMVERTEX), 2);
673 defines["HAS_FLOAT_TEXTURE"] = "";
675 defines["HAS_RGBA"] = "";
677 if(!LoadEffect(effectString, &defines))
679 CLog::Log(LOGERROR, __FUNCTION__": Failed to load shader %s.", effectString.c_str());
683 if (!CreateHQKernel(method))
689 void CConvolutionShaderSeparable::Render(CD3DTexture &sourceTexture,
690 unsigned int sourceWidth, unsigned int sourceHeight,
691 unsigned int destWidth, unsigned int destHeight,
695 LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
697 if(m_destWidth != destWidth || m_sourceHeight != sourceHeight)
698 CreateIntermediateRenderTarget(destWidth, sourceHeight);
700 PrepareParameters(sourceWidth, sourceHeight, destWidth, destHeight, sourceRect, destRect);
701 float texSteps1[] = { 1.0f/(float)sourceWidth, 1.0f/(float)sourceHeight};
702 float texSteps2[] = { 1.0f/(float)destWidth, 1.0f/(float)(sourceHeight)};
703 SetShaderParameters(sourceTexture, &texSteps1[0], sizeof(texSteps1)/sizeof(texSteps1[0]), &texSteps2[0], sizeof(texSteps2)/sizeof(texSteps2[0]));
705 // This part should be cleaned up, but how?
706 std::vector<LPDIRECT3DSURFACE9> rts;
707 LPDIRECT3DSURFACE9 intRT, currentRT;
708 m_IntermediateTarget.GetSurfaceLevel(0, &intRT);
709 pD3DDevice->GetRenderTarget(0, ¤tRT);
710 rts.push_back(intRT);
711 rts.push_back(currentRT);
714 currentRT->Release();
717 CConvolutionShaderSeparable::~CConvolutionShaderSeparable()
719 if (m_IntermediateTarget.Get())
720 m_IntermediateTarget.Release();
723 bool CConvolutionShaderSeparable::ChooseIntermediateD3DFormat()
725 DWORD usage = D3DUSAGE_RENDERTARGET;
727 // Need a float texture, as the output of the first pass can contain negative values.
728 if (g_Windowing.IsTextureFormatOk(D3DFMT_A16B16G16R16F, usage)) m_IntermediateFormat = D3DFMT_A16B16G16R16F;
729 else if (g_Windowing.IsTextureFormatOk(D3DFMT_A32B32G32R32F, usage)) m_IntermediateFormat = D3DFMT_A32B32G32R32F;
732 CLog::Log(LOGNOTICE, __FUNCTION__": no float format available for the intermediate render target");
736 CLog::Log(LOGDEBUG, __FUNCTION__": format %i", m_IntermediateFormat);
741 bool CConvolutionShaderSeparable::CreateIntermediateRenderTarget(unsigned int width, unsigned int height)
743 if (m_IntermediateTarget.Get())
744 m_IntermediateTarget.Release();
746 if(!m_IntermediateTarget.Create(width, height, 1, D3DUSAGE_RENDERTARGET, m_IntermediateFormat, D3DPOOL_DEFAULT))
748 CLog::Log(LOGERROR, __FUNCTION__": render target creation failed.");
754 bool CConvolutionShaderSeparable::ClearIntermediateRenderTarget()
756 LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
758 LPDIRECT3DSURFACE9 currentRT;
759 pD3DDevice->GetRenderTarget(0, ¤tRT);
761 LPDIRECT3DSURFACE9 intermediateRT;
762 m_IntermediateTarget.GetSurfaceLevel(0, &intermediateRT);
764 pD3DDevice->SetRenderTarget(0, intermediateRT);
766 pD3DDevice->Clear(0L, NULL, D3DCLEAR_TARGET, 0L, 1.0f, 0L);
768 pD3DDevice->SetRenderTarget(0, currentRT);
769 currentRT->Release();
770 intermediateRT->Release();
775 void CConvolutionShaderSeparable::PrepareParameters(unsigned int sourceWidth, unsigned int sourceHeight,
776 unsigned int destWidth, unsigned int destHeight,
780 if(m_sourceWidth != sourceWidth || m_sourceHeight != sourceHeight
781 || m_destWidth != destWidth || m_destHeight != destHeight
782 || m_sourceRect != sourceRect || m_destRect != destRect)
784 // fixme better: clearing the whole render target when changing the source/dest rect is not optimal.
785 // Problem is that the edges of the final picture may retain content when the rects change.
786 // For example when changing zoom value, the edges can retain content from the previous zoom value.
787 // Playing with coordinates was unsuccessful so far, this is a quick fix for release.
788 ClearIntermediateRenderTarget();
790 m_sourceWidth = sourceWidth;
791 m_sourceHeight = sourceHeight;
792 m_destWidth = destWidth;
793 m_destHeight = destHeight;
794 m_sourceRect = sourceRect;
795 m_destRect = destRect;
798 CWinShader::LockVertexBuffer((void**)&v);
800 // Alter rectangles the destination rectangle exceeds the intermediate target width when zooming and causes artifacts.
801 // Work on the parameters rather than the members to avoid disturbing the parameter change detection the next time the function is called
802 CRect tgtRect(0, 0, destWidth, destHeight);
803 CWIN32Util::CropSource(sourceRect, destRect, tgtRect);
805 // Manipulate the coordinates to work only on the active parts of the textures,
806 // and therefore avoid the need to clear surfaces/render targets
809 // Horizontal dimension: crop/zoom, so that it is completely done with the convolution shader. Scaling to display width in pass1 and
810 // cropping/zooming in pass 2 would use bilinear in pass2, which we don't want.
811 // Vertical dimension: crop using sourceRect to save memory bandwidth for high zoom values, but don't stretch/shrink in any way in this pass.
815 v[0].tu = sourceRect.x1 / sourceWidth;
816 v[0].tv = sourceRect.y1 / sourceHeight;
818 v[1].x = destRect.x2 - destRect.x1;
820 v[1].tu = sourceRect.x2 / sourceWidth;
821 v[1].tv = sourceRect.y1 / sourceHeight;
823 v[2].x = destRect.x2 - destRect.x1;
824 v[2].y = sourceRect.y2 - sourceRect.y1;
825 v[2].tu = sourceRect.x2 / sourceWidth;
826 v[2].tv = sourceRect.y2 / sourceHeight;
829 v[3].y = sourceRect.y2 - sourceRect.y1;
830 v[3].tu = sourceRect.x1 / sourceWidth;
831 v[3].tv = sourceRect.y2 / sourceHeight;
833 // Pass 2: pass the horizontal data untouched, resize vertical dimension for final result.
835 v[4].x = destRect.x1;
836 v[4].y = destRect.y1;
840 v[5].x = destRect.x2;
841 v[5].y = destRect.y1;
842 v[5].tu = (destRect.x2 - destRect.x1) / destWidth;
845 v[6].x = destRect.x2;
846 v[6].y = destRect.y2;
847 v[6].tu = (destRect.x2 - destRect.x1) / destWidth;
848 v[6].tv = (sourceRect.y2 - sourceRect.y1) / sourceHeight;
850 v[7].x = destRect.x1;
851 v[7].y = destRect.y2;
853 v[7].tv = (sourceRect.y2 - sourceRect.y1) / sourceHeight;
855 // -0.5 offset to compensate for D3D rasterization
857 for(int i = 0; i < 8; i++)
865 CWinShader::UnlockVertexBuffer();
869 void CConvolutionShaderSeparable::SetShaderParameters(CD3DTexture &sourceTexture, float* texSteps1, int texStepsCount1, float* texSteps2, int texStepsCount2)
871 m_effect.SetTechnique( "SCALER_T" );
872 m_effect.SetTexture( "g_Texture", sourceTexture ) ;
873 m_effect.SetTexture( "g_KernelTexture", m_HQKernelTexture );
874 m_effect.SetTexture( "g_IntermediateTexture", m_IntermediateTarget ) ;
875 m_effect.SetFloatArray("g_StepXY_P0", texSteps1, texStepsCount1);
876 m_effect.SetFloatArray("g_StepXY_P1", texSteps2, texStepsCount2);
880 //==========================================================
882 bool CTestShader::Create()
884 CStdString effectString = "special://xbmc/system/shaders/testshader.fx";
886 if(!LoadEffect(effectString, NULL))
888 CLog::Log(LOGERROR, __FUNCTION__": Failed to load shader %s.", effectString.c_str());