[release] version bump to 13.0 beta1
[vuplus_xbmc] / xbmc / cores / VideoRenderers / WinRenderer.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
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/>.
18  *
19  */
20
21 #ifdef HAS_DX
22
23 #include "DllSwScale.h"
24 #include "Util.h"
25 #include "WinRenderer.h"
26 #include "cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h"
27 #include "dialogs/GUIDialogKaiToast.h"
28 #include "filesystem/File.h"
29 #include "guilib/LocalizeStrings.h"
30 #include "guilib/Texture.h"
31 #include "settings/AdvancedSettings.h"
32 #include "settings/DisplaySettings.h"
33 #include "settings/MediaSettings.h"
34 #include "settings/Settings.h"
35 #include "threads/SingleLock.h"
36 #include "utils/log.h"
37 #include "utils/MathUtils.h"
38 #include "utils/SystemInfo.h"
39 #include "VideoShaders/WinVideoFilter.h"
40 #include "win32/WIN32Util.h"
41 #include "windowing/WindowingFactory.h"
42
43 typedef struct {
44   RenderMethod  method;
45   const char   *name;
46 } RenderMethodDetail;
47
48 static RenderMethodDetail RenderMethodDetails[] = {
49     { RENDER_SW     , "Software" },
50     { RENDER_PS     , "Pixel Shaders" },
51     { RENDER_DXVA   , "DXVA" },
52     { RENDER_INVALID, NULL }
53 };
54
55 static RenderMethodDetail *FindRenderMethod(RenderMethod m)
56 {
57   for (unsigned i = 0; RenderMethodDetails[i].method != RENDER_INVALID; i++) {
58     if (RenderMethodDetails[i].method == m)
59       return &RenderMethodDetails[i];
60   }
61   return NULL;
62 }
63
64 CWinRenderer::CWinRenderer()
65 {
66   m_iYV12RenderBuffer = 0;
67   m_NumYV12Buffers = 0;
68
69   m_colorShader = NULL;
70   m_scalerShader = NULL;
71   m_extended_format = 0;
72
73   m_iRequestedMethod = RENDER_METHOD_AUTO;
74
75   m_renderMethod = RENDER_PS;
76   m_scalingMethod = VS_SCALINGMETHOD_LINEAR;
77   m_scalingMethodGui = (ESCALINGMETHOD)-1;
78   m_TextureFilter = D3DTEXF_POINT;
79
80   m_bUseHQScaler = false;
81   m_bFilterInitialized = false;
82
83   for (int i = 0; i<NUM_BUFFERS; i++)
84     m_VideoBuffers[i] = NULL;
85
86   m_sw_scale_ctx = NULL;
87   m_dllSwScale = NULL;
88   m_destWidth = 0;
89   m_destHeight = 0;
90   m_dllAvUtil = NULL;
91   m_dllAvCodec = NULL;
92   m_bConfigured = false;
93   m_clearColour = 0;
94   m_format = RENDER_FMT_NONE;
95   m_processor = NULL;
96   m_neededBuffers = 0;
97 }
98
99 CWinRenderer::~CWinRenderer()
100 {
101   UnInit();
102 }
103
104 static enum PixelFormat PixelFormatFromFormat(ERenderFormat format)
105 {
106   if      (format == RENDER_FMT_YUV420P)   return PIX_FMT_YUV420P;
107   else if (format == RENDER_FMT_YUV420P10) return PIX_FMT_YUV420P10;
108   else if (format == RENDER_FMT_YUV420P16) return PIX_FMT_YUV420P16;
109   else if (format == RENDER_FMT_NV12)      return PIX_FMT_NV12;
110   else if (format == RENDER_FMT_UYVY422)   return PIX_FMT_UYVY422;
111   else if (format == RENDER_FMT_YUYV422)   return PIX_FMT_YUYV422;
112   else return PIX_FMT_NONE;
113 }
114
115 void CWinRenderer::ManageTextures()
116 {
117   if( m_NumYV12Buffers < m_neededBuffers )
118   {
119     for(int i = m_NumYV12Buffers; i<m_neededBuffers;i++)
120       CreateYV12Texture(i);
121
122     m_NumYV12Buffers = m_neededBuffers;
123   }
124   else if( m_NumYV12Buffers > m_neededBuffers )
125   {
126     m_NumYV12Buffers = m_neededBuffers;
127     m_iYV12RenderBuffer = m_iYV12RenderBuffer % m_NumYV12Buffers;
128
129     for(int i = m_NumYV12Buffers-1; i>=m_neededBuffers;i--)
130       DeleteYV12Texture(i);
131   }
132 }
133
134 void CWinRenderer::SelectRenderMethod()
135 {
136   // Set rendering to dxva before trying it, in order to open the correct processor immediately, when deinterlacing method is auto.
137
138   // Force dxva renderer after dxva decoding: PS and SW renderers have performance issues after dxva decode.
139   if (g_advancedSettings.m_DXVAForceProcessorRenderer && m_format == RENDER_FMT_DXVA)
140   {
141     CLog::Log(LOGNOTICE, "D3D: rendering method forced to DXVA processor");
142     m_renderMethod = RENDER_DXVA;
143     if (!m_processor->Open(m_sourceWidth, m_sourceHeight, m_iFlags, m_format, m_extended_format))
144     {
145       CLog::Log(LOGNOTICE, "D3D: unable to open DXVA processor");
146       m_processor->Close();
147       m_renderMethod = RENDER_INVALID;
148     }
149   }
150   else
151   {
152     CLog::Log(LOGDEBUG, __FUNCTION__": Requested render method: %d", m_iRequestedMethod);
153
154     switch(m_iRequestedMethod)
155     {
156       case RENDER_METHOD_DXVAHD:
157       case RENDER_METHOD_DXVA:
158         m_renderMethod = RENDER_DXVA;
159         if (m_processor->Open(m_sourceWidth, m_sourceHeight, m_iFlags, m_format, m_extended_format))
160             break;
161         else
162         {
163           CLog::Log(LOGNOTICE, "D3D: unable to open DXVA processor");
164           m_processor->Close();
165         }
166       // Drop through to pixel shader
167       case RENDER_METHOD_AUTO:
168       case RENDER_METHOD_D3D_PS:
169         // Try the pixel shaders support
170         if (m_deviceCaps.PixelShaderVersion >= D3DPS_VERSION(2, 0))
171         {
172           CTestShader shader;
173           if (shader.Create())
174           {
175             m_renderMethod = RENDER_PS;
176             break;
177           }
178           else
179           {
180             CLog::Log(LOGNOTICE, "D3D: unable to load test shader - D3D installation is most likely incomplete");
181             CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Warning, "DirectX", g_localizeStrings.Get(2101));
182           }
183         }
184         else
185         {
186           CLog::Log(LOGNOTICE, "D3D: graphics adapter does not support Pixel Shaders 2.0");
187         }
188         CLog::Log(LOGNOTICE, "D3D: falling back to SW mode");
189       // drop through to software
190       case RENDER_METHOD_SOFTWARE:
191       default:
192         // So we'll do the color conversion in software.
193         m_renderMethod = RENDER_SW;
194         break;
195     }
196   }
197
198   RenderMethodDetail *rmdet = FindRenderMethod(m_renderMethod);
199   CLog::Log(LOGDEBUG, __FUNCTION__": Selected render method %d: %s", m_renderMethod, rmdet != NULL ? rmdet->name : "unknown");
200 }
201
202 bool CWinRenderer::UpdateRenderMethod()
203 {
204   if (m_SWTarget.Get())
205     m_SWTarget.Release();
206
207   if (m_renderMethod == RENDER_SW)
208   {
209     m_dllSwScale = new DllSwScale();
210
211     if (!m_dllSwScale->Load())
212       CLog::Log(LOGERROR,"CDVDDemuxFFmpeg::Open - failed to load ffmpeg libraries");
213
214     if(!m_SWTarget.Create(m_sourceWidth, m_sourceHeight, 1, D3DUSAGE_DYNAMIC, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT))
215     {
216       CLog::Log(LOGNOTICE, __FUNCTION__": Failed to create sw render target.");
217       return false;
218     }
219   }
220   return true;
221 }
222
223 bool CWinRenderer::Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation)
224 {
225   if(m_sourceWidth  != width
226   || m_sourceHeight != height)
227   {
228     m_sourceWidth       = width;
229     m_sourceHeight      = height;
230     // need to recreate textures
231     m_NumYV12Buffers    = 0;
232     m_iYV12RenderBuffer = 0;
233     // reinitialize the filters/shaders
234     m_bFilterInitialized = false;
235   }
236   else
237   {
238     if (m_VideoBuffers[m_iYV12RenderBuffer] != NULL)
239       m_VideoBuffers[m_iYV12RenderBuffer]->StartDecode();
240
241     m_iYV12RenderBuffer = 0;
242     if (m_VideoBuffers[0] != NULL)
243       m_VideoBuffers[0]->StartRender();
244   }
245
246   m_fps = fps;
247   m_iFlags = flags;
248   m_format = format;
249   m_extended_format = extended_format;
250
251   // calculate the input frame aspect ratio
252   CalculateFrameAspectRatio(d_width, d_height);
253   ChooseBestResolution(fps);
254   m_destWidth = g_graphicsContext.GetResInfo(m_resolution).iWidth;
255   m_destHeight = g_graphicsContext.GetResInfo(m_resolution).iHeight;
256   SetViewMode(CMediaSettings::Get().GetCurrentVideoSettings().m_ViewMode);
257   ManageDisplay();
258
259   m_bConfigured = true;
260
261   SelectRenderMethod();
262   UpdateRenderMethod();
263
264   return true;
265 }
266
267 int CWinRenderer::NextYV12Texture()
268 {
269   if(m_NumYV12Buffers)
270     return (m_iYV12RenderBuffer + 1) % m_NumYV12Buffers;
271   else
272     return -1;
273 }
274
275 bool CWinRenderer::AddVideoPicture(DVDVideoPicture* picture, int index)
276 {
277   if (m_renderMethod == RENDER_DXVA)
278   {
279     int source = index;
280     if(source < 0 || NextYV12Texture() < 0)
281       return false;
282
283     DXVABuffer *buf = (DXVABuffer*)m_VideoBuffers[source];
284     buf->id = m_processor->Add(picture);
285     return true;
286   }
287   return false;
288 }
289
290 int CWinRenderer::GetImage(YV12Image *image, int source, bool readonly)
291 {
292   /* take next available buffer */
293   if( source == AUTOSOURCE )
294     source = NextYV12Texture();
295
296   if( source < 0 || NextYV12Texture() < 0)
297     return -1;
298
299   YUVBuffer *buf = (YUVBuffer*)m_VideoBuffers[source];
300
301   image->cshift_x = 1;
302   image->cshift_y = 1;
303   image->height = m_sourceHeight;
304   image->width = m_sourceWidth;
305   image->flags = 0;
306   if(m_format == RENDER_FMT_YUV420P10
307   || m_format == RENDER_FMT_YUV420P16)
308     image->bpp = 2;
309   else
310     image->bpp = 1;
311
312   for(int i=0;i<3;i++)
313   {
314     image->stride[i] = buf->planes[i].rect.Pitch;
315     image->plane[i]  = (BYTE*)buf->planes[i].rect.pBits;
316   }
317
318   return source;
319 }
320
321 void CWinRenderer::ReleaseImage(int source, bool preserve)
322 {
323   // no need to release anything here since we're using system memory
324 }
325
326 void CWinRenderer::Reset()
327 {
328 }
329
330 void CWinRenderer::Update()
331 {
332   if (!m_bConfigured) return;
333   ManageDisplay();
334 }
335
336 void CWinRenderer::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
337 {
338   LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
339
340   if (clear)
341     g_graphicsContext.Clear(m_clearColour);
342
343   if(alpha < 255)
344     pD3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
345   else
346     pD3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
347
348   if (!m_bConfigured) return;
349   ManageTextures();
350
351   CSingleLock lock(g_graphicsContext);
352
353   ManageDisplay();
354
355   Render(flags);
356 }
357
358 void CWinRenderer::FlipPage(int source)
359 {
360   if(source == AUTOSOURCE)
361     source = NextYV12Texture();
362
363   if (m_VideoBuffers[m_iYV12RenderBuffer] != NULL)
364     m_VideoBuffers[m_iYV12RenderBuffer]->StartDecode();
365
366   if( source >= 0 && source < m_NumYV12Buffers )
367     m_iYV12RenderBuffer = source;
368   else
369     m_iYV12RenderBuffer = 0;
370
371   if (m_VideoBuffers[m_iYV12RenderBuffer] != NULL)
372     m_VideoBuffers[m_iYV12RenderBuffer]->StartRender();
373
374 #ifdef MP_DIRECTRENDERING
375   __asm wbinvd
376 #endif
377
378   return;
379 }
380
381 unsigned int CWinRenderer::PreInit()
382 {
383   CSingleLock lock(g_graphicsContext);
384   m_bConfigured = false;
385   UnInit();
386   m_resolution = CDisplaySettings::Get().GetCurrentResolution();
387   if ( m_resolution == RES_WINDOW )
388     m_resolution = RES_DESKTOP;
389
390   // setup the background colour
391   m_clearColour = (g_advancedSettings.m_videoBlackBarColour & 0xff) * 0x010101;
392
393   g_Windowing.Get3DDevice()->GetDeviceCaps(&m_deviceCaps);
394
395   m_formats.push_back(RENDER_FMT_YUV420P);
396   if(g_Windowing.IsTextureFormatOk(D3DFMT_L16, 0))
397   {
398     m_formats.push_back(RENDER_FMT_YUV420P10);
399     m_formats.push_back(RENDER_FMT_YUV420P16);
400   }
401   m_formats.push_back(RENDER_FMT_NV12);
402   m_formats.push_back(RENDER_FMT_YUYV422);
403   m_formats.push_back(RENDER_FMT_UYVY422);
404
405   m_iRequestedMethod = CSettings::Get().GetInt("videoplayer.rendermethod");
406
407   if (g_advancedSettings.m_DXVAForceProcessorRenderer || m_iRequestedMethod == RENDER_METHOD_DXVA
408       || m_iRequestedMethod == RENDER_METHOD_DXVAHD)
409   {
410     if (m_iRequestedMethod != RENDER_METHOD_DXVA && CSysInfo::IsWindowsVersionAtLeast(CSysInfo::WindowsVersionWin7))
411     {
412       m_processor = new DXVA::CProcessorHD();
413       if (!m_processor->PreInit())
414       {
415         CLog::Log(LOGNOTICE, "CWinRenderer::Preinit - could not init DXVA-HD processor - skipping");
416         SAFE_DELETE(m_processor);
417         m_processor = new DXVA::CProcessor();
418       }
419       else
420         return 0;
421     }
422     else
423       m_processor = new DXVA::CProcessor();
424
425     if (!m_processor->PreInit())
426       CLog::Log(LOGNOTICE, "CWinRenderer::Preinit - could not init DXVA2 processor - skipping");
427   }
428
429   return 0;
430 }
431
432 void CWinRenderer::UnInit()
433 {
434   CSingleLock lock(g_graphicsContext);
435
436   if (m_SWTarget.Get())
437     m_SWTarget.Release();
438
439   if (m_IntermediateTarget.Get())
440     m_IntermediateTarget.Release();
441
442   SAFE_DELETE(m_colorShader);
443   SAFE_DELETE(m_scalerShader);
444   
445   m_bConfigured = false;
446   m_bFilterInitialized = false;
447
448   for(int i = 0; i < NUM_BUFFERS; i++)
449     DeleteYV12Texture(i);
450
451   m_NumYV12Buffers = 0;
452
453   if (m_sw_scale_ctx)
454   {
455     m_dllSwScale->sws_freeContext(m_sw_scale_ctx);
456     m_sw_scale_ctx = NULL;
457   }
458   SAFE_DELETE(m_dllSwScale);
459
460   if (m_processor)
461   {
462     m_processor->UnInit();
463     SAFE_DELETE(m_processor);
464   }
465 }
466
467 bool CWinRenderer::CreateIntermediateRenderTarget(unsigned int width, unsigned int height)
468 {
469   // Initialize a render target for intermediate rendering
470   LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
471   D3DFORMAT format = D3DFMT_X8R8G8B8;
472   DWORD usage = D3DUSAGE_RENDERTARGET;
473
474   if      (m_renderMethod == RENDER_DXVA)                            format = D3DFMT_X8R8G8B8;
475   else if (g_Windowing.IsTextureFormatOk(D3DFMT_A2R10G10B10, usage)) format = D3DFMT_A2R10G10B10;
476   else if (g_Windowing.IsTextureFormatOk(D3DFMT_A2B10G10R10, usage)) format = D3DFMT_A2B10G10R10;
477   else if (g_Windowing.IsTextureFormatOk(D3DFMT_A8R8G8B8, usage))    format = D3DFMT_A8R8G8B8;
478   else if (g_Windowing.IsTextureFormatOk(D3DFMT_A8B8G8R8, usage))    format = D3DFMT_A8B8G8R8;
479   else if (g_Windowing.IsTextureFormatOk(D3DFMT_X8R8G8B8, usage))    format = D3DFMT_X8R8G8B8;
480   else if (g_Windowing.IsTextureFormatOk(D3DFMT_X8B8G8R8, usage))    format = D3DFMT_X8B8G8R8;
481   else if (g_Windowing.IsTextureFormatOk(D3DFMT_R8G8B8, usage))      format = D3DFMT_R8G8B8;
482
483   // don't create new one if it exists with requested size and format
484   if ( m_IntermediateTarget.Get() && m_IntermediateTarget.GetFormat() == format
485     && m_IntermediateTarget.GetWidth() == width && m_IntermediateTarget.GetHeight() == height)
486     return true;
487
488   if (m_IntermediateTarget.Get())
489     m_IntermediateTarget.Release();
490
491   CLog::Log(LOGDEBUG, __FUNCTION__": format %i", format);
492
493   if(!m_IntermediateTarget.Create(width, height, 1, usage, format, D3DPOOL_DEFAULT))
494   {
495     CLog::Log(LOGERROR, __FUNCTION__": intermediate render target creation failed.", format);
496     return false;
497   }
498   return true;
499 }
500
501 void CWinRenderer::SelectSWVideoFilter()
502 {
503   switch (m_scalingMethod)
504   {
505   case VS_SCALINGMETHOD_AUTO:
506   case VS_SCALINGMETHOD_LINEAR:
507     if (Supports(VS_SCALINGMETHOD_LINEAR))
508     {
509       m_TextureFilter = D3DTEXF_LINEAR;
510       break;
511     }
512     // fall through for fallback
513   case VS_SCALINGMETHOD_NEAREST:
514   default:
515     m_TextureFilter = D3DTEXF_POINT;
516     break;
517   }
518 }
519
520 void CWinRenderer::SelectPSVideoFilter()
521 {
522   m_bUseHQScaler = false;
523
524   switch (m_scalingMethod)
525   {
526   case VS_SCALINGMETHOD_NEAREST:
527   case VS_SCALINGMETHOD_LINEAR:
528     break;
529
530   case VS_SCALINGMETHOD_CUBIC:
531   case VS_SCALINGMETHOD_LANCZOS2:
532   case VS_SCALINGMETHOD_SPLINE36_FAST:
533   case VS_SCALINGMETHOD_LANCZOS3_FAST:
534     m_bUseHQScaler = true;
535     break;
536
537   case VS_SCALINGMETHOD_SPLINE36:
538   case VS_SCALINGMETHOD_LANCZOS3:
539     m_bUseHQScaler = true;
540     break;
541
542   case VS_SCALINGMETHOD_SINC8:
543   case VS_SCALINGMETHOD_NEDI:
544     CLog::Log(LOGERROR, "D3D: TODO: This scaler has not yet been implemented");
545     break;
546
547   case VS_SCALINGMETHOD_BICUBIC_SOFTWARE:
548   case VS_SCALINGMETHOD_LANCZOS_SOFTWARE:
549   case VS_SCALINGMETHOD_SINC_SOFTWARE:
550     CLog::Log(LOGERROR, "D3D: TODO: Software scaling has not yet been implemented");
551     break;
552
553   default:
554     break;
555   }
556
557   if (m_scalingMethod == VS_SCALINGMETHOD_AUTO)
558   {
559     bool scaleSD = m_sourceHeight < 720 && m_sourceWidth < 1280;
560     bool scaleUp = (int)m_sourceHeight < g_graphicsContext.GetHeight() && (int)m_sourceWidth < g_graphicsContext.GetWidth();
561     bool scaleFps = m_fps < (g_advancedSettings.m_videoAutoScaleMaxFps + 0.01f);
562
563     if (m_renderMethod == RENDER_DXVA)
564     {
565       m_scalingMethod = VS_SCALINGMETHOD_DXVA_HARDWARE;
566       m_bUseHQScaler = false;
567     }
568     else if (scaleSD && scaleUp && scaleFps && Supports(VS_SCALINGMETHOD_LANCZOS3_FAST))
569     {
570       m_scalingMethod = VS_SCALINGMETHOD_LANCZOS3_FAST;
571       m_bUseHQScaler = true;
572     }
573   }
574 }
575
576 void CWinRenderer::UpdatePSVideoFilter()
577 {
578   SAFE_DELETE(m_scalerShader);
579
580   if (m_bUseHQScaler)
581   {
582     // First try the more efficient two pass convolution scaler
583     m_scalerShader = new CConvolutionShaderSeparable();
584
585     if (!m_scalerShader->Create(m_scalingMethod))
586     {
587       SAFE_DELETE(m_scalerShader);
588       CLog::Log(LOGNOTICE, __FUNCTION__": two pass convolution shader init problem, falling back to one pass.");
589     }
590
591     // Fallback on the one pass version
592     if (m_scalerShader == NULL)
593     {
594       m_scalerShader = new CConvolutionShader1Pass();
595
596       if (!m_scalerShader->Create(m_scalingMethod))
597       {
598         SAFE_DELETE(m_scalerShader);
599         CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error, g_localizeStrings.Get(34400), g_localizeStrings.Get(34401));
600         m_bUseHQScaler = false;
601       }
602     }
603   }
604
605   if (m_bUseHQScaler && !CreateIntermediateRenderTarget(m_sourceWidth, m_sourceHeight))
606   {
607     SAFE_DELETE(m_scalerShader);
608     m_bUseHQScaler = false;
609   }
610
611   SAFE_DELETE(m_colorShader);
612
613   if (m_renderMethod == RENDER_DXVA)
614   {
615     // we'd use m_IntermediateTarget as rendering target for possible anaglyph stereo with dxva processor.
616     if (!m_bUseHQScaler) 
617       CreateIntermediateRenderTarget(m_destWidth, m_destHeight);
618
619     // When using DXVA, we are already setup at this point, color shader is not needed
620     return;
621   }
622
623   if (m_bUseHQScaler)
624   {
625     m_colorShader = new CYUV2RGBShader();
626     if (!m_colorShader->Create(m_sourceWidth, m_sourceHeight, m_format))
627     {
628       // Try again after disabling the HQ scaler and freeing its resources
629       m_IntermediateTarget.Release();
630       SAFE_DELETE(m_scalerShader);
631       SAFE_DELETE(m_colorShader);
632       m_bUseHQScaler = false;
633     }
634   }
635
636   if (!m_bUseHQScaler) //fallback from HQ scalers and multipass creation above
637   {
638     m_colorShader = new CYUV2RGBShader();
639     if (!m_colorShader->Create(m_sourceWidth, m_sourceHeight, m_format))
640       SAFE_DELETE(m_colorShader);
641     // we're in big trouble - should fallback on D3D accelerated or sw method
642   }
643 }
644
645 void CWinRenderer::UpdateVideoFilter()
646 {
647   if (m_scalingMethodGui == CMediaSettings::Get().GetCurrentVideoSettings().m_ScalingMethod && m_bFilterInitialized)
648     return;
649
650   m_bFilterInitialized = true;
651
652   m_scalingMethodGui = CMediaSettings::Get().GetCurrentVideoSettings().m_ScalingMethod;
653   m_scalingMethod    = m_scalingMethodGui;
654
655   if (!Supports(m_scalingMethod))
656   {
657     CLog::Log(LOGWARNING, __FUNCTION__" - chosen scaling method %d is not supported by renderer", (int)m_scalingMethod);
658     m_scalingMethod = VS_SCALINGMETHOD_AUTO;
659   }
660
661   switch(m_renderMethod)
662   {
663   case RENDER_SW:
664     SelectSWVideoFilter();
665     break;
666
667   case RENDER_PS:
668   case RENDER_DXVA:
669     SelectPSVideoFilter();
670     UpdatePSVideoFilter();
671     break;
672
673   default:
674     return;
675   }
676 }
677
678 void CWinRenderer::Render(DWORD flags)
679 {
680   if (m_renderMethod == RENDER_DXVA)
681   {
682     UpdateVideoFilter();
683     if (m_bUseHQScaler)
684       g_Windowing.FlushGPU();
685     CWinRenderer::RenderProcessor(flags);
686     return;
687   }
688
689   UpdateVideoFilter();
690
691   // Optimize later? we could get by with bilinear under some circumstances
692   /*if(!m_bUseHQScaler
693     || !g_graphicsContext.IsFullScreenVideo()
694     || g_graphicsContext.IsCalibrating()
695     || (m_destRect.Width() == m_sourceWidth && m_destRect.Height() == m_sourceHeight))
696     */
697   CSingleLock lock(g_graphicsContext);
698
699   // Don't need a stencil/depth buffer and a buffer smaller than the render target causes D3D complaints and nVidia issues
700   // Save & restore when we're done.
701   LPDIRECT3DSURFACE9 pZBuffer;
702   LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
703   pD3DDevice->GetDepthStencilSurface(&pZBuffer);
704   pD3DDevice->SetDepthStencilSurface(NULL);
705
706   if (m_renderMethod == RENDER_SW)
707     RenderSW();
708   else if (m_renderMethod == RENDER_PS)
709     RenderPS();
710
711   pD3DDevice->SetDepthStencilSurface(pZBuffer);
712   pZBuffer->Release();
713 }
714
715 void CWinRenderer::RenderSW()
716 {
717   enum PixelFormat format = PixelFormatFromFormat(m_format);
718
719   // 1. convert yuv to rgb
720   m_sw_scale_ctx = m_dllSwScale->sws_getCachedContext(m_sw_scale_ctx,
721                                                       m_sourceWidth, m_sourceHeight, format,
722                                                       m_sourceWidth, m_sourceHeight, PIX_FMT_BGRA,
723                                                       SWS_FAST_BILINEAR | SwScaleCPUFlags(), NULL, NULL, NULL);
724
725   YUVBuffer* buf = (YUVBuffer*)m_VideoBuffers[m_iYV12RenderBuffer];
726
727   D3DLOCKED_RECT   srclr[MAX_PLANES];
728   uint8_t         *src[MAX_PLANES];
729   int              srcStride[MAX_PLANES];
730
731   for (unsigned int idx = 0; idx < buf->GetActivePlanes(); idx++)
732   {
733     if(!(buf->planes[idx].texture.LockRect(0, &srclr[idx], NULL, D3DLOCK_READONLY)))
734       CLog::Log(LOGERROR, __FUNCTION__" - failed to lock yuv textures into memory");
735     else
736     {
737       src[idx] = (uint8_t*)srclr[idx].pBits;
738       srcStride[idx] = srclr[idx].Pitch;
739     }
740   }
741   
742   D3DLOCKED_RECT destlr = {0,0};
743   if (!m_SWTarget.LockRect(0, &destlr, NULL, D3DLOCK_DISCARD))
744     CLog::Log(LOGERROR, __FUNCTION__" - failed to lock swtarget texture into memory");
745
746   uint8_t *dst[]  = { (uint8_t*) destlr.pBits, 0, 0, 0 };
747   int dstStride[] = { destlr.Pitch, 0, 0, 0 };
748
749   m_dllSwScale->sws_scale(m_sw_scale_ctx, src, srcStride, 0, m_sourceHeight, dst, dstStride);
750
751   for (unsigned int idx = 0; idx < buf->GetActivePlanes(); idx++)
752     if(!(buf->planes[idx].texture.UnlockRect(0)))
753       CLog::Log(LOGERROR, __FUNCTION__" - failed to unlock yuv textures");
754
755   if (!m_SWTarget.UnlockRect(0))
756     CLog::Log(LOGERROR, __FUNCTION__" - failed to unlock swtarget texture");
757
758   // 2. scale to display
759
760   // Don't know where this martian comes from but it can happen in the initial frames of a video
761   if ((m_destRect.x1 < 0 && m_destRect.x2 < 0) || (m_destRect.y1 < 0 && m_destRect.y2 < 0))
762     return;
763
764   ScaleFixedPipeline();
765 }
766
767 /*
768 Code kept for reference, as a basis to re-enable StretchRect and 
769 do the color conversion with it.
770 See IDirect3D9::CheckDeviceFormat() for support of non-standard fourcc textures
771 and IDirect3D9::CheckDeviceFormatConversion for color conversion support
772
773 void CWinRenderer::ScaleStretchRect()
774 {
775   // Test HW scaler support. StretchRect is slightly faster than drawing a quad.
776   // If linear filtering is not supported, drop back to quads, as most HW has linear filtering for quads.
777   //if(m_deviceCaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES
778   //&& m_deviceCaps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFLINEAR
779   //&& m_deviceCaps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR)
780   //{
781   //  m_StretchRectSupported = true;
782   //}
783
784   CRect sourceRect = m_sourceRect;
785   CRect destRect = m_destRect;
786
787   D3DSURFACE_DESC desc;
788   if (FAILED(target->GetDesc(&desc)))
789     CLog::Log(LOGERROR, "CWinRenderer::Render - failed to get back buffer description");
790   CRect tgtRect(0, 0, desc.Width, desc.Height);
791
792   // Need to manipulate the coordinates since StretchRect doesn't accept off-screen coordinates.
793   CWIN32Util::CropSource(sourceRect, destRect, tgtRect);
794
795   RECT srcRect = { sourceRect.x1, sourceRect.y1, sourceRect.x2, sourceRect.y2 };
796   IDirect3DSurface9* source;
797   if(!m_SWTarget.GetSurfaceLevel(0, &source))
798     CLog::Log(LOGERROR, "CWinRenderer::Render - failed to get source");
799
800   RECT dstRect = { destRect.x1, destRect.y1, destRect.x2, destRect.y2 };
801   IDirect3DSurface9* target;
802   if(FAILED(g_Windowing.Get3DDevice()->GetRenderTarget(0, &target)))
803     CLog::Log(LOGERROR, "CWinRenderer::Render - failed to get back buffer");
804
805   HRESULT hr;
806   LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
807
808   if(FAILED(hr = pD3DDevice->StretchRect(source, &srcRect, target, &dstRect, m_TextureFilter)))
809     CLog::Log(LOGERROR, __FUNCTION__" - StretchRect failed (0x%08X)", hr);
810
811   target->Release();
812   source->Release();
813 }
814 */
815
816 void CWinRenderer::ScaleFixedPipeline()
817 {
818   HRESULT hr;
819   IDirect3DDevice9 *pD3DDev = g_Windowing.Get3DDevice();
820   D3DSURFACE_DESC srcDesc;
821   if (FAILED(hr = m_SWTarget.Get()->GetLevelDesc(0, &srcDesc)))
822     CLog::Log(LOGERROR, __FUNCTION__": GetLevelDesc failed. %s", CRenderSystemDX::GetErrorDescription(hr).c_str());
823
824   float srcWidth  = (float)srcDesc.Width;
825   float srcHeight = (float)srcDesc.Height;
826
827   bool cbcontrol          = (CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast != 50.0f || CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness != 50.0f);
828   unsigned int contrast   = (unsigned int)(CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast *.01f * 255.0f); // we have to divide by two here/multiply by two later
829   unsigned int brightness = (unsigned int)(CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness * .01f * 255.0f);
830
831   D3DCOLOR diffuse  = D3DCOLOR_ARGB(255, contrast, contrast, contrast);
832   D3DCOLOR specular = D3DCOLOR_ARGB(255, brightness, brightness, brightness);
833
834   struct VERTEX
835   {
836     FLOAT x,y,z,rhw;
837     D3DCOLOR diffuse;
838     D3DCOLOR specular;
839     FLOAT tu, tv;
840   };
841
842   // Vertex format ignores viewport offsets, so correct for that here
843   CRect dest = g_graphicsContext.StereoCorrection(m_destRect);
844
845   VERTEX vertex[] =
846   {
847     {dest.x1, dest.y1, 0.0f, 1.0f, diffuse, specular, m_sourceRect.x1 / srcWidth, m_sourceRect.y1 / srcHeight},
848     {dest.x2, dest.y1, 0.0f, 1.0f, diffuse, specular, m_sourceRect.x2 / srcWidth, m_sourceRect.y1 / srcHeight},
849     {dest.x2, dest.y2, 0.0f, 1.0f, diffuse, specular, m_sourceRect.x2 / srcWidth, m_sourceRect.y2 / srcHeight},
850     {dest.x1, dest.y2, 0.0f, 1.0f, diffuse, specular, m_sourceRect.x1 / srcWidth, m_sourceRect.y2 / srcHeight},
851   };
852
853   // Compensate for D3D coordinates system
854   for(int i = 0; i < sizeof(vertex)/sizeof(vertex[0]); i++)
855   {
856     vertex[i].x -= 0.5f;
857     vertex[i].y -= 0.5f;
858   };
859
860   pD3DDev->SetTexture(0, m_SWTarget.Get());
861
862   if (!cbcontrol)
863   {
864     pD3DDev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
865     pD3DDev->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
866     pD3DDev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
867     pD3DDev->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
868     pD3DDev->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE );
869     pD3DDev->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
870   }
871   else
872   {
873     pD3DDev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE2X );
874     pD3DDev->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
875     pD3DDev->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
876     pD3DDev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
877     pD3DDev->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE );
878
879     pD3DDev->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_ADDSIGNED );
880     pD3DDev->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_CURRENT );
881     pD3DDev->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_SPECULAR );
882     pD3DDev->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
883     pD3DDev->SetTextureStageState( 1, D3DTSS_ALPHAARG1, D3DTA_CURRENT );
884
885     pD3DDev->SetTextureStageState( 2, D3DTSS_COLOROP, D3DTOP_DISABLE );
886     pD3DDev->SetTextureStageState( 2, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
887   }
888
889   pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
890   pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE);
891   pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE);
892   pD3DDev->SetRenderState(D3DRS_STENCILENABLE, FALSE);
893   pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
894   pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
895   pD3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
896
897   pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, m_TextureFilter);
898   pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, m_TextureFilter);
899   pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
900   pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
901
902   pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX1);
903
904   if (FAILED(hr = pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, vertex, sizeof(VERTEX))))
905     CLog::Log(LOGERROR, __FUNCTION__": DrawPrimitiveUP failed. %s", CRenderSystemDX::GetErrorDescription(hr).c_str());
906
907   pD3DDev->SetTexture(0, NULL);
908 }
909
910 void CWinRenderer::RenderPS()
911 {
912   if (!m_bUseHQScaler)
913   {
914     Stage1();
915   }
916   else
917   {
918     Stage1();
919     Stage2();
920   }
921 }
922
923 void CWinRenderer::Stage1()
924 {
925   if (!m_bUseHQScaler)
926   {
927     m_colorShader->Render(m_sourceRect, g_graphicsContext.StereoCorrection(m_destRect),
928                             CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast,
929                             CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness,
930                             m_iFlags,
931                             (YUVBuffer*)m_VideoBuffers[m_iYV12RenderBuffer]);
932   }
933   else
934   {
935     // Switch the render target to the temporary destination
936     LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
937     LPDIRECT3DSURFACE9 newRT, oldRT;
938     m_IntermediateTarget.GetSurfaceLevel(0, &newRT);
939     pD3DDevice->GetRenderTarget(0, &oldRT);
940     pD3DDevice->SetRenderTarget(0, newRT);
941
942     CRect srcRect(0.0f, 0.0f, m_sourceWidth, m_sourceHeight);
943     CRect rtRect(0.0f, 0.0f, m_sourceWidth, m_sourceHeight);
944
945     m_colorShader->Render(srcRect, rtRect,
946                           CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast,
947                           CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness,
948                           m_iFlags,
949                           (YUVBuffer*)m_VideoBuffers[m_iYV12RenderBuffer]);
950
951     // Restore the render target
952     pD3DDevice->SetRenderTarget(0, oldRT);
953
954     oldRT->Release();
955     newRT->Release();
956   }
957 }
958
959 void CWinRenderer::Stage2()
960 {
961   CRect sourceRect;
962
963   // fixup stereo+dxva+hq scaling issue
964   if (m_renderMethod == RENDER_DXVA)
965   {
966     sourceRect.y1 = 0.0f;
967     sourceRect.y2 = m_sourceHeight;
968     sourceRect.x1 = 0.0f;
969     sourceRect.x2 = m_sourceWidth;
970   }
971   else
972     sourceRect = m_sourceRect;
973
974   m_scalerShader->Render(m_IntermediateTarget, m_sourceWidth, m_sourceHeight, m_destWidth, m_destHeight, sourceRect, g_graphicsContext.StereoCorrection(m_destRect));
975 }
976
977 void CWinRenderer::RenderProcessor(DWORD flags)
978 {
979   CSingleLock lock(g_graphicsContext);
980   HRESULT hr;
981   CRect destRect;
982
983   if (m_bUseHQScaler)
984   {
985     destRect.y1 = 0.0f;
986     destRect.y2 = m_sourceHeight;
987     destRect.x1 = 0.0f;
988     destRect.x2 = m_sourceWidth;
989   }
990   else
991     destRect = g_graphicsContext.StereoCorrection(m_destRect);
992
993   DXVABuffer *image = (DXVABuffer*)m_VideoBuffers[m_iYV12RenderBuffer];
994
995   IDirect3DSurface9* target;
996   if ( m_bUseHQScaler 
997     || g_graphicsContext.GetStereoMode() == RENDER_STEREO_MODE_ANAGLYPH_RED_CYAN
998     || g_graphicsContext.GetStereoMode() == RENDER_STEREO_MODE_ANAGLYPH_GREEN_MAGENTA)
999   {
1000     m_IntermediateTarget.GetSurfaceLevel(0, &target);
1001   }
1002   else
1003   {
1004     if(FAILED(hr = g_Windowing.Get3DDevice()->GetRenderTarget(0, &target)))
1005     {
1006       CLog::Log(LOGERROR, "CWinRenderer::RenderSurface - failed to get render target. %s", CRenderSystemDX::GetErrorDescription(hr).c_str());
1007       return;
1008     }
1009   }
1010
1011   m_processor->Render(m_sourceRect, destRect, target, image->id, flags);
1012
1013   target->Release();
1014
1015   if (m_bUseHQScaler)
1016   {
1017     Stage2();
1018   }
1019   else if ( g_graphicsContext.GetStereoMode() == RENDER_STEREO_MODE_ANAGLYPH_RED_CYAN
1020          || g_graphicsContext.GetStereoMode() == RENDER_STEREO_MODE_ANAGLYPH_GREEN_MAGENTA)
1021   {
1022     IDirect3DDevice9 *pD3DDev = g_Windowing.Get3DDevice();
1023
1024     struct VERTEX
1025     {
1026       FLOAT x,y,z;
1027       FLOAT tu,tv;
1028     };
1029
1030     VERTEX vertex[] =
1031     {
1032       {destRect.x1 - 0.5f, destRect.y1 - 0.5f, 0.0f, m_destRect.x1 / m_destWidth, m_destRect.y1 / m_destHeight},
1033       {destRect.x2 - 0.5f, destRect.y1 - 0.5f, 0.0f, m_destRect.x2 / m_destWidth, m_destRect.y1 / m_destHeight},
1034       {destRect.x2 - 0.5f, destRect.y2 - 0.5f, 0.0f, m_destRect.x2 / m_destWidth, m_destRect.y2 / m_destHeight},
1035       {destRect.x1 - 0.5f, destRect.y2 - 0.5f, 0.0f, m_destRect.x1 / m_destWidth, m_destRect.y2 / m_destHeight},
1036     };
1037
1038     pD3DDev->SetTexture(0, m_IntermediateTarget.Get());
1039
1040     pD3DDev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
1041     pD3DDev->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
1042     pD3DDev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
1043     pD3DDev->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
1044     pD3DDev->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE );
1045     pD3DDev->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
1046
1047     pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
1048     pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
1049
1050     pD3DDev->SetFVF(D3DFVF_XYZ | D3DFVF_TEX1);
1051
1052     if (FAILED(hr = pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, vertex, sizeof(VERTEX))))
1053       CLog::Log(LOGERROR, __FUNCTION__": DrawPrimitiveUP failed. %s", CRenderSystemDX::GetErrorDescription(hr).c_str());
1054
1055     pD3DDev->SetTexture(0, NULL);
1056   }
1057 }
1058
1059 bool CWinRenderer::RenderCapture(CRenderCapture* capture)
1060 {
1061   if (!m_bConfigured || m_NumYV12Buffers == 0)
1062     return false;
1063
1064   bool succeeded = false;
1065
1066   LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
1067
1068   CRect saveSize = m_destRect;
1069   saveRotatedCoords();//backup current m_rotatedDestCoords
1070
1071   m_destRect.SetRect(0, 0, (float)capture->GetWidth(), (float)capture->GetHeight());
1072   syncDestRectToRotatedPoints();//syncs the changed destRect to m_rotatedDestCoords
1073
1074   LPDIRECT3DSURFACE9 oldSurface;
1075   pD3DDevice->GetRenderTarget(0, &oldSurface);
1076
1077   capture->BeginRender();
1078   if (capture->GetState() != CAPTURESTATE_FAILED)
1079   {
1080     pD3DDevice->BeginScene();
1081     Render(0);
1082     pD3DDevice->EndScene();
1083     capture->EndRender();
1084     succeeded = true;
1085   }
1086
1087   pD3DDevice->SetRenderTarget(0, oldSurface);
1088   oldSurface->Release();
1089
1090   m_destRect = saveSize;
1091   restoreRotatedCoords();//restores the previous state of the rotated dest coords
1092
1093   return succeeded;
1094 }
1095
1096 //********************************************************************************************************
1097 // YV12 Texture creation, deletion, copying + clearing
1098 //********************************************************************************************************
1099 void CWinRenderer::DeleteYV12Texture(int index)
1100 {
1101   CSingleLock lock(g_graphicsContext);
1102   if (m_VideoBuffers[index] != NULL)
1103     SAFE_DELETE(m_VideoBuffers[index]);
1104   m_NumYV12Buffers = 0;
1105 }
1106
1107 bool CWinRenderer::CreateYV12Texture(int index)
1108 {
1109   CSingleLock lock(g_graphicsContext);
1110   DeleteYV12Texture(index);
1111
1112   if (m_renderMethod == RENDER_DXVA)
1113   {
1114     m_VideoBuffers[index] = new DXVABuffer();
1115   }
1116   else
1117   {
1118     YUVBuffer *buf = new YUVBuffer();
1119
1120     if (!buf->Create(m_format, m_sourceWidth, m_sourceHeight))
1121     {
1122       CLog::Log(LOGERROR, __FUNCTION__" - Unable to create YV12 video texture %i", index);
1123       return false;
1124     }
1125     m_VideoBuffers[index] = buf;
1126   }
1127
1128   SVideoBuffer *buf = m_VideoBuffers[index];
1129
1130   buf->StartDecode();
1131   buf->Clear();
1132
1133   if(index == m_iYV12RenderBuffer)
1134     buf->StartRender();
1135
1136   CLog::Log(LOGDEBUG, "created video buffer %i", index);
1137   return true;
1138 }
1139
1140 bool CWinRenderer::Supports(EDEINTERLACEMODE mode)
1141 {
1142   if(mode == VS_DEINTERLACEMODE_OFF
1143   || mode == VS_DEINTERLACEMODE_AUTO
1144   || mode == VS_DEINTERLACEMODE_FORCE)
1145     return true;
1146
1147   return false;
1148 }
1149
1150 bool CWinRenderer::Supports(EINTERLACEMETHOD method)
1151 {
1152   if(method == VS_INTERLACEMETHOD_AUTO)
1153     return true;
1154
1155   if (m_renderMethod == RENDER_DXVA)
1156   {
1157     if(method == VS_INTERLACEMETHOD_DXVA_BOB
1158     || method == VS_INTERLACEMETHOD_DXVA_BEST)
1159       return true;
1160   }
1161
1162   if(m_format != RENDER_FMT_DXVA
1163   && (   method == VS_INTERLACEMETHOD_DEINTERLACE
1164       || method == VS_INTERLACEMETHOD_DEINTERLACE_HALF
1165       || method == VS_INTERLACEMETHOD_SW_BLEND))
1166     return true;
1167
1168   return false;
1169 }
1170
1171 bool CWinRenderer::Supports(ERENDERFEATURE feature)
1172 {
1173   if(feature == RENDERFEATURE_BRIGHTNESS)
1174     return true;
1175
1176   if(feature == RENDERFEATURE_CONTRAST)
1177     return true;
1178
1179   if (feature == RENDERFEATURE_STRETCH         ||
1180       feature == RENDERFEATURE_NONLINSTRETCH   ||
1181       feature == RENDERFEATURE_CROP            ||
1182       feature == RENDERFEATURE_ZOOM            ||
1183       feature == RENDERFEATURE_VERTICAL_SHIFT  ||
1184       feature == RENDERFEATURE_PIXEL_RATIO     ||
1185       feature == RENDERFEATURE_POSTPROCESS)
1186     return true;
1187
1188
1189   return false;
1190 }
1191
1192 bool CWinRenderer::Supports(ESCALINGMETHOD method)
1193 {
1194   if (m_renderMethod == RENDER_PS || m_renderMethod == RENDER_DXVA)
1195   {
1196     if(m_renderMethod == RENDER_DXVA && method == VS_SCALINGMETHOD_DXVA_HARDWARE)
1197       return true;
1198
1199     if(m_deviceCaps.PixelShaderVersion >= D3DPS_VERSION(2, 0)
1200     && (   method == VS_SCALINGMETHOD_AUTO
1201        || (method == VS_SCALINGMETHOD_LINEAR && m_renderMethod == RENDER_PS) ))
1202         return true;
1203
1204     if(m_deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0))
1205     {
1206       if(method == VS_SCALINGMETHOD_CUBIC
1207       || method == VS_SCALINGMETHOD_LANCZOS2
1208       || method == VS_SCALINGMETHOD_SPLINE36_FAST
1209       || method == VS_SCALINGMETHOD_LANCZOS3_FAST
1210       || method == VS_SCALINGMETHOD_SPLINE36
1211       || method == VS_SCALINGMETHOD_LANCZOS3)
1212       {
1213         // if scaling is below level, avoid hq scaling
1214         float scaleX = fabs(((float)m_sourceWidth - m_destRect.Width())/m_sourceWidth)*100;
1215         float scaleY = fabs(((float)m_sourceHeight - m_destRect.Height())/m_sourceHeight)*100;
1216         int minScale = CSettings::Get().GetInt("videoplayer.hqscalers");
1217         if (scaleX < minScale && scaleY < minScale)
1218           return false;
1219         return true;
1220       }
1221     }
1222   }
1223   else if(m_renderMethod == RENDER_SW)
1224   {
1225     if(method == VS_SCALINGMETHOD_AUTO
1226     || method == VS_SCALINGMETHOD_NEAREST)
1227       return true;
1228     if(method == VS_SCALINGMETHOD_LINEAR
1229     && m_deviceCaps.TextureFilterCaps & D3DPTFILTERCAPS_MINFLINEAR
1230     && m_deviceCaps.TextureFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR)
1231       return true;
1232   }
1233   return false;
1234 }
1235
1236 EINTERLACEMETHOD CWinRenderer::AutoInterlaceMethod()
1237 {
1238   if (m_renderMethod == RENDER_DXVA)
1239     return VS_INTERLACEMETHOD_DXVA_BOB;
1240   else
1241     return VS_INTERLACEMETHOD_DEINTERLACE_HALF;
1242 }
1243
1244 unsigned int CWinRenderer::GetProcessorSize()
1245 {
1246   if (m_format == RENDER_FMT_DXVA && m_processor)
1247     return m_processor->Size();
1248   else
1249     return 0;
1250 }
1251
1252 //============================================
1253
1254 YUVBuffer::~YUVBuffer()
1255 {
1256   Release();
1257 }
1258
1259 bool YUVBuffer::Create(ERenderFormat format, unsigned int width, unsigned int height)
1260 {
1261   m_format = format;
1262   m_width = width;
1263   m_height = height;
1264
1265   // Create the buffers in system memory and copy to D3DPOOL_DEFAULT:
1266   // - helps with lost devices. A buffer can be locked for dvdplayer without interfering.
1267   // - Dynamic + D3DPOOL_DEFAULT caused trouble for Intel i3 and some IGP. Bad sync/locking in the driver  I suppose
1268   // and Present failed every second time for the second video played.
1269   // - this is what D3D9 does behind the scenes anyway
1270   switch(m_format)
1271   {
1272   case RENDER_FMT_YUV420P10:
1273   case RENDER_FMT_YUV420P16:
1274     {
1275       if ( !planes[PLANE_Y].texture.Create(m_width    , m_height    , 1, 0, D3DFMT_L16, D3DPOOL_SYSTEMMEM)
1276         || !planes[PLANE_U].texture.Create(m_width / 2, m_height / 2, 1, 0, D3DFMT_L16, D3DPOOL_SYSTEMMEM)
1277         || !planes[PLANE_V].texture.Create(m_width / 2, m_height / 2, 1, 0, D3DFMT_L16, D3DPOOL_SYSTEMMEM))
1278         return false;
1279       m_activeplanes = 3;
1280       break;
1281     }
1282   case RENDER_FMT_YUV420P:
1283     {
1284       if ( !planes[PLANE_Y].texture.Create(m_width    , m_height    , 1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM)
1285         || !planes[PLANE_U].texture.Create(m_width / 2, m_height / 2, 1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM)
1286         || !planes[PLANE_V].texture.Create(m_width / 2, m_height / 2, 1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM))
1287         return false;
1288       m_activeplanes = 3;
1289       break;
1290     }
1291   case RENDER_FMT_NV12:
1292     {
1293       if ( !planes[PLANE_Y].texture.Create(m_width    , m_height    , 1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM)
1294         || !planes[PLANE_UV].texture.Create(m_width / 2, m_height / 2, 1, 0, D3DFMT_A8L8, D3DPOOL_SYSTEMMEM))
1295         return false;
1296       m_activeplanes = 2;
1297       break;
1298     }
1299   case RENDER_FMT_YUYV422:
1300     {
1301       if ( !planes[PLANE_Y].texture.Create(m_width >> 1    , m_height    , 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM))
1302         return false;
1303       m_activeplanes = 1;
1304       break;
1305     }
1306   case RENDER_FMT_UYVY422:
1307     {
1308       if ( !planes[PLANE_Y].texture.Create(m_width >> 1    , m_height    , 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM))
1309         return false;
1310       m_activeplanes = 1;
1311       break;
1312     }
1313   default:
1314     m_activeplanes = 0;
1315     return false;
1316   }
1317
1318   return true;
1319 }
1320
1321 void YUVBuffer::Release()
1322 {
1323   for(unsigned i = 0; i < m_activeplanes; i++)
1324   {
1325     planes[i].texture.Release();
1326     memset(&planes[i].rect, 0, sizeof(planes[i].rect));
1327   }
1328 }
1329
1330 void YUVBuffer::StartRender()
1331 {
1332   for(unsigned i = 0; i < m_activeplanes; i++)
1333   {
1334     if(planes[i].texture.Get() && planes[i].rect.pBits)
1335       if (!planes[i].texture.UnlockRect(0))
1336         CLog::Log(LOGERROR, __FUNCTION__" - failed to unlock texture %d", i);
1337     memset(&planes[i].rect, 0, sizeof(planes[i].rect));
1338   }
1339 }
1340
1341 void YUVBuffer::StartDecode()
1342 {
1343   for(unsigned i = 0; i < m_activeplanes; i++)
1344   {
1345     if(planes[i].texture.Get()
1346     && planes[i].texture.LockRect(0, &planes[i].rect, NULL, D3DLOCK_DISCARD) == false)
1347     {
1348       memset(&planes[i].rect, 0, sizeof(planes[i].rect));
1349       CLog::Log(LOGERROR, __FUNCTION__" - failed to lock texture %d into memory", i);
1350     }
1351   }
1352 }
1353
1354 void YUVBuffer::Clear()
1355 {
1356   // Set Y to 0 and U,V to 128 (RGB 0,0,0) to avoid visual artifacts at the start of playback
1357
1358   switch(m_format)
1359   {
1360   case RENDER_FMT_YUV420P16:
1361     {
1362       wmemset((wchar_t*)planes[PLANE_Y].rect.pBits, 0,     planes[PLANE_Y].rect.Pitch *  m_height    / 2);
1363       wmemset((wchar_t*)planes[PLANE_U].rect.pBits, 32768, planes[PLANE_U].rect.Pitch * (m_height/2) / 2);
1364       wmemset((wchar_t*)planes[PLANE_V].rect.pBits, 32768, planes[PLANE_V].rect.Pitch * (m_height/2) / 2);
1365       break;
1366     }
1367   case RENDER_FMT_YUV420P10:
1368     {
1369       wmemset((wchar_t*)planes[PLANE_Y].rect.pBits, 0,   planes[PLANE_Y].rect.Pitch *  m_height    / 2);
1370       wmemset((wchar_t*)planes[PLANE_U].rect.pBits, 512, planes[PLANE_U].rect.Pitch * (m_height/2) / 2);
1371       wmemset((wchar_t*)planes[PLANE_V].rect.pBits, 512, planes[PLANE_V].rect.Pitch * (m_height/2) / 2);
1372       break;
1373     }
1374   case RENDER_FMT_YUV420P:
1375     {
1376       memset(planes[PLANE_Y].rect.pBits, 0,   planes[PLANE_Y].rect.Pitch *  m_height);
1377       memset(planes[PLANE_U].rect.pBits, 128, planes[PLANE_U].rect.Pitch * (m_height/2));
1378       memset(planes[PLANE_V].rect.pBits, 128, planes[PLANE_V].rect.Pitch * (m_height/2));
1379       break;
1380     }
1381   case RENDER_FMT_NV12:
1382     {
1383       memset(planes[PLANE_Y].rect.pBits, 0,   planes[PLANE_Y].rect.Pitch *  m_height);
1384       memset(planes[PLANE_UV].rect.pBits, 128, planes[PLANE_U].rect.Pitch * (m_height/2));
1385       break;
1386     }
1387   // YUY2, UYVY: wmemset to set a 16bit pattern, byte-swapped because x86 is LE
1388   case RENDER_FMT_YUYV422:
1389     {
1390       wmemset((wchar_t*)planes[PLANE_Y].rect.pBits, 0x8000, planes[PLANE_Y].rect.Pitch / 2 * m_height);
1391       break;
1392     }
1393   case RENDER_FMT_UYVY422:
1394     {
1395       wmemset((wchar_t*)planes[PLANE_Y].rect.pBits, 0x0080, planes[PLANE_Y].rect.Pitch / 2 * m_height);
1396       break;
1397     }
1398
1399   }
1400 }
1401
1402
1403 //==================================
1404
1405 DXVABuffer::~DXVABuffer()
1406 {
1407   Release();
1408 }
1409
1410 void DXVABuffer::Release()
1411 {
1412   id = 0;
1413 }
1414
1415 void DXVABuffer::StartDecode()
1416 {
1417   Release();
1418 }
1419 #endif