[3d] fix stretched gui in sbs/ou mode when using hq scalers
[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
397   m_iRequestedMethod = CSettings::Get().GetInt("videoplayer.rendermethod");
398
399   if (g_advancedSettings.m_DXVAForceProcessorRenderer || m_iRequestedMethod == RENDER_METHOD_DXVA
400       || m_iRequestedMethod == RENDER_METHOD_DXVAHD)
401   {
402     if (m_iRequestedMethod != RENDER_METHOD_DXVA && CSysInfo::IsWindowsVersionAtLeast(CSysInfo::WindowsVersionWin7))
403     {
404       m_processor = new DXVA::CProcessorHD();
405       if (!m_processor->PreInit())
406       {
407         CLog::Log(LOGNOTICE, "CWinRenderer::Preinit - could not init DXVA-HD processor - skipping");
408         SAFE_DELETE(m_processor);
409         m_processor = new DXVA::CProcessor();
410       }
411       else
412         return 0;
413     }
414     else
415       m_processor = new DXVA::CProcessor();
416
417     if (!m_processor->PreInit())
418       CLog::Log(LOGNOTICE, "CWinRenderer::Preinit - could not init DXVA2 processor - skipping");
419     else
420       return 0;
421   }
422   
423   if (g_Windowing.IsTextureFormatOk(D3DFMT_L16, 0))
424   {
425     m_formats.push_back(RENDER_FMT_YUV420P10);
426     m_formats.push_back(RENDER_FMT_YUV420P16);
427   }
428   m_formats.push_back(RENDER_FMT_NV12);
429   m_formats.push_back(RENDER_FMT_YUYV422);
430   m_formats.push_back(RENDER_FMT_UYVY422);
431
432   return 0;
433 }
434
435 void CWinRenderer::UnInit()
436 {
437   CSingleLock lock(g_graphicsContext);
438
439   if (m_SWTarget.Get())
440     m_SWTarget.Release();
441
442   if (m_IntermediateTarget.Get())
443     m_IntermediateTarget.Release();
444
445   SAFE_DELETE(m_colorShader);
446   SAFE_DELETE(m_scalerShader);
447   
448   m_bConfigured = false;
449   m_bFilterInitialized = false;
450
451   for(int i = 0; i < NUM_BUFFERS; i++)
452     DeleteYV12Texture(i);
453
454   m_NumYV12Buffers = 0;
455
456   if (m_sw_scale_ctx)
457   {
458     m_dllSwScale->sws_freeContext(m_sw_scale_ctx);
459     m_sw_scale_ctx = NULL;
460   }
461   SAFE_DELETE(m_dllSwScale);
462
463   if (m_processor)
464   {
465     m_processor->UnInit();
466     SAFE_DELETE(m_processor);
467   }
468 }
469
470 bool CWinRenderer::CreateIntermediateRenderTarget(unsigned int width, unsigned int height)
471 {
472   // Initialize a render target for intermediate rendering
473   LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
474   D3DFORMAT format = D3DFMT_X8R8G8B8;
475   DWORD usage = D3DUSAGE_RENDERTARGET;
476
477   if      (m_renderMethod == RENDER_DXVA)                            format = D3DFMT_X8R8G8B8;
478   else if (g_Windowing.IsTextureFormatOk(D3DFMT_A2R10G10B10, usage)) format = D3DFMT_A2R10G10B10;
479   else if (g_Windowing.IsTextureFormatOk(D3DFMT_A2B10G10R10, usage)) format = D3DFMT_A2B10G10R10;
480   else if (g_Windowing.IsTextureFormatOk(D3DFMT_A8R8G8B8, usage))    format = D3DFMT_A8R8G8B8;
481   else if (g_Windowing.IsTextureFormatOk(D3DFMT_A8B8G8R8, usage))    format = D3DFMT_A8B8G8R8;
482   else if (g_Windowing.IsTextureFormatOk(D3DFMT_X8R8G8B8, usage))    format = D3DFMT_X8R8G8B8;
483   else if (g_Windowing.IsTextureFormatOk(D3DFMT_X8B8G8R8, usage))    format = D3DFMT_X8B8G8R8;
484   else if (g_Windowing.IsTextureFormatOk(D3DFMT_R8G8B8, usage))      format = D3DFMT_R8G8B8;
485
486   // don't create new one if it exists with requested size and format
487   if ( m_IntermediateTarget.Get() && m_IntermediateTarget.GetFormat() == format
488     && m_IntermediateTarget.GetWidth() == width && m_IntermediateTarget.GetHeight() == height)
489     return true;
490
491   if (m_IntermediateTarget.Get())
492     m_IntermediateTarget.Release();
493
494   CLog::Log(LOGDEBUG, __FUNCTION__": format %i", format);
495
496   if(!m_IntermediateTarget.Create(width, height, 1, usage, format, D3DPOOL_DEFAULT))
497   {
498     CLog::Log(LOGERROR, __FUNCTION__": intermediate render target creation failed.", format);
499     return false;
500   }
501   return true;
502 }
503
504 void CWinRenderer::SelectSWVideoFilter()
505 {
506   switch (m_scalingMethod)
507   {
508   case VS_SCALINGMETHOD_AUTO:
509   case VS_SCALINGMETHOD_LINEAR:
510     if (Supports(VS_SCALINGMETHOD_LINEAR))
511     {
512       m_TextureFilter = D3DTEXF_LINEAR;
513       break;
514     }
515     // fall through for fallback
516   case VS_SCALINGMETHOD_NEAREST:
517   default:
518     m_TextureFilter = D3DTEXF_POINT;
519     break;
520   }
521 }
522
523 void CWinRenderer::SelectPSVideoFilter()
524 {
525   m_bUseHQScaler = false;
526
527   switch (m_scalingMethod)
528   {
529   case VS_SCALINGMETHOD_NEAREST:
530   case VS_SCALINGMETHOD_LINEAR:
531     break;
532
533   case VS_SCALINGMETHOD_CUBIC:
534   case VS_SCALINGMETHOD_LANCZOS2:
535   case VS_SCALINGMETHOD_SPLINE36_FAST:
536   case VS_SCALINGMETHOD_LANCZOS3_FAST:
537     m_bUseHQScaler = true;
538     break;
539
540   case VS_SCALINGMETHOD_SPLINE36:
541   case VS_SCALINGMETHOD_LANCZOS3:
542     m_bUseHQScaler = true;
543     break;
544
545   case VS_SCALINGMETHOD_SINC8:
546   case VS_SCALINGMETHOD_NEDI:
547     CLog::Log(LOGERROR, "D3D: TODO: This scaler has not yet been implemented");
548     break;
549
550   case VS_SCALINGMETHOD_BICUBIC_SOFTWARE:
551   case VS_SCALINGMETHOD_LANCZOS_SOFTWARE:
552   case VS_SCALINGMETHOD_SINC_SOFTWARE:
553     CLog::Log(LOGERROR, "D3D: TODO: Software scaling has not yet been implemented");
554     break;
555
556   default:
557     break;
558   }
559
560   if (m_scalingMethod == VS_SCALINGMETHOD_AUTO)
561   {
562     bool scaleSD = m_sourceHeight < 720 && m_sourceWidth < 1280;
563     bool scaleUp = (int)m_sourceHeight < g_graphicsContext.GetHeight() && (int)m_sourceWidth < g_graphicsContext.GetWidth();
564     bool scaleFps = m_fps < (g_advancedSettings.m_videoAutoScaleMaxFps + 0.01f);
565
566     if (m_renderMethod == RENDER_DXVA)
567     {
568       m_scalingMethod = VS_SCALINGMETHOD_DXVA_HARDWARE;
569       m_bUseHQScaler = false;
570     }
571     else if (scaleSD && scaleUp && scaleFps && Supports(VS_SCALINGMETHOD_LANCZOS3_FAST))
572     {
573       m_scalingMethod = VS_SCALINGMETHOD_LANCZOS3_FAST;
574       m_bUseHQScaler = true;
575     }
576   }
577 }
578
579 void CWinRenderer::UpdatePSVideoFilter()
580 {
581   SAFE_DELETE(m_scalerShader);
582
583   if (m_bUseHQScaler)
584   {
585     // First try the more efficient two pass convolution scaler
586     m_scalerShader = new CConvolutionShaderSeparable();
587
588     if (!m_scalerShader->Create(m_scalingMethod))
589     {
590       SAFE_DELETE(m_scalerShader);
591       CLog::Log(LOGNOTICE, __FUNCTION__": two pass convolution shader init problem, falling back to one pass.");
592     }
593
594     // Fallback on the one pass version
595     if (m_scalerShader == NULL)
596     {
597       m_scalerShader = new CConvolutionShader1Pass();
598
599       if (!m_scalerShader->Create(m_scalingMethod))
600       {
601         SAFE_DELETE(m_scalerShader);
602         CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error, g_localizeStrings.Get(34400), g_localizeStrings.Get(34401));
603         m_bUseHQScaler = false;
604       }
605     }
606   }
607
608   if (m_bUseHQScaler && !CreateIntermediateRenderTarget(m_sourceWidth, m_sourceHeight))
609   {
610     SAFE_DELETE(m_scalerShader);
611     m_bUseHQScaler = false;
612   }
613
614   SAFE_DELETE(m_colorShader);
615
616   if (m_renderMethod == RENDER_DXVA)
617   {
618     // we'd use m_IntermediateTarget as rendering target for possible anaglyph stereo with dxva processor.
619     if (!m_bUseHQScaler) 
620       CreateIntermediateRenderTarget(m_destWidth, m_destHeight);
621
622     // When using DXVA, we are already setup at this point, color shader is not needed
623     return;
624   }
625
626   if (m_bUseHQScaler)
627   {
628     m_colorShader = new CYUV2RGBShader();
629     if (!m_colorShader->Create(m_sourceWidth, m_sourceHeight, m_format))
630     {
631       // Try again after disabling the HQ scaler and freeing its resources
632       m_IntermediateTarget.Release();
633       SAFE_DELETE(m_scalerShader);
634       SAFE_DELETE(m_colorShader);
635       m_bUseHQScaler = false;
636     }
637   }
638
639   if (!m_bUseHQScaler) //fallback from HQ scalers and multipass creation above
640   {
641     m_colorShader = new CYUV2RGBShader();
642     if (!m_colorShader->Create(m_sourceWidth, m_sourceHeight, m_format))
643       SAFE_DELETE(m_colorShader);
644     // we're in big trouble - should fallback on D3D accelerated or sw method
645   }
646 }
647
648 void CWinRenderer::UpdateVideoFilter()
649 {
650   if (m_scalingMethodGui == CMediaSettings::Get().GetCurrentVideoSettings().m_ScalingMethod && m_bFilterInitialized)
651     return;
652
653   m_bFilterInitialized = true;
654
655   m_scalingMethodGui = CMediaSettings::Get().GetCurrentVideoSettings().m_ScalingMethod;
656   m_scalingMethod    = m_scalingMethodGui;
657
658   if (!Supports(m_scalingMethod))
659   {
660     CLog::Log(LOGWARNING, __FUNCTION__" - chosen scaling method %d is not supported by renderer", (int)m_scalingMethod);
661     m_scalingMethod = VS_SCALINGMETHOD_AUTO;
662   }
663
664   switch(m_renderMethod)
665   {
666   case RENDER_SW:
667     SelectSWVideoFilter();
668     break;
669
670   case RENDER_PS:
671   case RENDER_DXVA:
672     SelectPSVideoFilter();
673     UpdatePSVideoFilter();
674     break;
675
676   default:
677     return;
678   }
679 }
680
681 void CWinRenderer::Render(DWORD flags)
682 {
683   if (m_renderMethod == RENDER_DXVA)
684   {
685     UpdateVideoFilter();
686     if (m_bUseHQScaler)
687       g_Windowing.FlushGPU();
688     CWinRenderer::RenderProcessor(flags);
689     return;
690   }
691
692   UpdateVideoFilter();
693
694   // Optimize later? we could get by with bilinear under some circumstances
695   /*if(!m_bUseHQScaler
696     || !g_graphicsContext.IsFullScreenVideo()
697     || g_graphicsContext.IsCalibrating()
698     || (m_destRect.Width() == m_sourceWidth && m_destRect.Height() == m_sourceHeight))
699     */
700   CSingleLock lock(g_graphicsContext);
701
702   // Don't need a stencil/depth buffer and a buffer smaller than the render target causes D3D complaints and nVidia issues
703   // Save & restore when we're done.
704   LPDIRECT3DSURFACE9 pZBuffer;
705   LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
706   pD3DDevice->GetDepthStencilSurface(&pZBuffer);
707   pD3DDevice->SetDepthStencilSurface(NULL);
708
709   if (m_renderMethod == RENDER_SW)
710     RenderSW();
711   else if (m_renderMethod == RENDER_PS)
712     RenderPS();
713
714   pD3DDevice->SetDepthStencilSurface(pZBuffer);
715   pZBuffer->Release();
716 }
717
718 void CWinRenderer::RenderSW()
719 {
720   enum PixelFormat format = PixelFormatFromFormat(m_format);
721
722   // 1. convert yuv to rgb
723   m_sw_scale_ctx = m_dllSwScale->sws_getCachedContext(m_sw_scale_ctx,
724                                                       m_sourceWidth, m_sourceHeight, format,
725                                                       m_sourceWidth, m_sourceHeight, PIX_FMT_BGRA,
726                                                       SWS_FAST_BILINEAR | SwScaleCPUFlags(), NULL, NULL, NULL);
727
728   YUVBuffer* buf = (YUVBuffer*)m_VideoBuffers[m_iYV12RenderBuffer];
729
730   D3DLOCKED_RECT   srclr[MAX_PLANES];
731   uint8_t         *src[MAX_PLANES];
732   int              srcStride[MAX_PLANES];
733
734   for (unsigned int idx = 0; idx < buf->GetActivePlanes(); idx++)
735   {
736     if(!(buf->planes[idx].texture.LockRect(0, &srclr[idx], NULL, D3DLOCK_READONLY)))
737       CLog::Log(LOGERROR, __FUNCTION__" - failed to lock yuv textures into memory");
738     else
739     {
740       src[idx] = (uint8_t*)srclr[idx].pBits;
741       srcStride[idx] = srclr[idx].Pitch;
742     }
743   }
744   
745   D3DLOCKED_RECT destlr = {0,0};
746   if (!m_SWTarget.LockRect(0, &destlr, NULL, D3DLOCK_DISCARD))
747     CLog::Log(LOGERROR, __FUNCTION__" - failed to lock swtarget texture into memory");
748
749   uint8_t *dst[]  = { (uint8_t*) destlr.pBits, 0, 0, 0 };
750   int dstStride[] = { destlr.Pitch, 0, 0, 0 };
751
752   m_dllSwScale->sws_scale(m_sw_scale_ctx, src, srcStride, 0, m_sourceHeight, dst, dstStride);
753
754   for (unsigned int idx = 0; idx < buf->GetActivePlanes(); idx++)
755     if(!(buf->planes[idx].texture.UnlockRect(0)))
756       CLog::Log(LOGERROR, __FUNCTION__" - failed to unlock yuv textures");
757
758   if (!m_SWTarget.UnlockRect(0))
759     CLog::Log(LOGERROR, __FUNCTION__" - failed to unlock swtarget texture");
760
761   // 2. scale to display
762
763   // Don't know where this martian comes from but it can happen in the initial frames of a video
764   if ((m_destRect.x1 < 0 && m_destRect.x2 < 0) || (m_destRect.y1 < 0 && m_destRect.y2 < 0))
765     return;
766
767   ScaleFixedPipeline();
768 }
769
770 /*
771 Code kept for reference, as a basis to re-enable StretchRect and 
772 do the color conversion with it.
773 See IDirect3D9::CheckDeviceFormat() for support of non-standard fourcc textures
774 and IDirect3D9::CheckDeviceFormatConversion for color conversion support
775
776 void CWinRenderer::ScaleStretchRect()
777 {
778   // Test HW scaler support. StretchRect is slightly faster than drawing a quad.
779   // If linear filtering is not supported, drop back to quads, as most HW has linear filtering for quads.
780   //if(m_deviceCaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES
781   //&& m_deviceCaps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFLINEAR
782   //&& m_deviceCaps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR)
783   //{
784   //  m_StretchRectSupported = true;
785   //}
786
787   CRect sourceRect = m_sourceRect;
788   CRect destRect = m_destRect;
789
790   D3DSURFACE_DESC desc;
791   if (FAILED(target->GetDesc(&desc)))
792     CLog::Log(LOGERROR, "CWinRenderer::Render - failed to get back buffer description");
793   CRect tgtRect(0, 0, desc.Width, desc.Height);
794
795   // Need to manipulate the coordinates since StretchRect doesn't accept off-screen coordinates.
796   CWIN32Util::CropSource(sourceRect, destRect, tgtRect);
797
798   RECT srcRect = { sourceRect.x1, sourceRect.y1, sourceRect.x2, sourceRect.y2 };
799   IDirect3DSurface9* source;
800   if(!m_SWTarget.GetSurfaceLevel(0, &source))
801     CLog::Log(LOGERROR, "CWinRenderer::Render - failed to get source");
802
803   RECT dstRect = { destRect.x1, destRect.y1, destRect.x2, destRect.y2 };
804   IDirect3DSurface9* target;
805   if(FAILED(g_Windowing.Get3DDevice()->GetRenderTarget(0, &target)))
806     CLog::Log(LOGERROR, "CWinRenderer::Render - failed to get back buffer");
807
808   HRESULT hr;
809   LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
810
811   if(FAILED(hr = pD3DDevice->StretchRect(source, &srcRect, target, &dstRect, m_TextureFilter)))
812     CLog::Log(LOGERROR, __FUNCTION__" - StretchRect failed (0x%08X)", hr);
813
814   target->Release();
815   source->Release();
816 }
817 */
818
819 void CWinRenderer::ScaleFixedPipeline()
820 {
821   HRESULT hr;
822   IDirect3DDevice9 *pD3DDev = g_Windowing.Get3DDevice();
823   D3DSURFACE_DESC srcDesc;
824   if (FAILED(hr = m_SWTarget.Get()->GetLevelDesc(0, &srcDesc)))
825     CLog::Log(LOGERROR, __FUNCTION__": GetLevelDesc failed. %s", CRenderSystemDX::GetErrorDescription(hr).c_str());
826
827   float srcWidth  = (float)srcDesc.Width;
828   float srcHeight = (float)srcDesc.Height;
829
830   bool cbcontrol          = (CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast != 50.0f || CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness != 50.0f);
831   unsigned int contrast   = (unsigned int)(CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast *.01f * 255.0f); // we have to divide by two here/multiply by two later
832   unsigned int brightness = (unsigned int)(CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness * .01f * 255.0f);
833
834   D3DCOLOR diffuse  = D3DCOLOR_ARGB(255, contrast, contrast, contrast);
835   D3DCOLOR specular = D3DCOLOR_ARGB(255, brightness, brightness, brightness);
836
837   struct VERTEX
838   {
839     FLOAT x,y,z,rhw;
840     D3DCOLOR diffuse;
841     D3DCOLOR specular;
842     FLOAT tu, tv;
843   };
844
845   // Vertex format ignores viewport offsets, so correct for that here
846   CRect dest = g_graphicsContext.StereoCorrection(m_destRect);
847
848   VERTEX vertex[] =
849   {
850     {dest.x1, dest.y1, 0.0f, 1.0f, diffuse, specular, m_sourceRect.x1 / srcWidth, m_sourceRect.y1 / srcHeight},
851     {dest.x2, dest.y1, 0.0f, 1.0f, diffuse, specular, m_sourceRect.x2 / srcWidth, m_sourceRect.y1 / srcHeight},
852     {dest.x2, dest.y2, 0.0f, 1.0f, diffuse, specular, m_sourceRect.x2 / srcWidth, m_sourceRect.y2 / srcHeight},
853     {dest.x1, dest.y2, 0.0f, 1.0f, diffuse, specular, m_sourceRect.x1 / srcWidth, m_sourceRect.y2 / srcHeight},
854   };
855
856   // Compensate for D3D coordinates system
857   for(int i = 0; i < sizeof(vertex)/sizeof(vertex[0]); i++)
858   {
859     vertex[i].x -= 0.5f;
860     vertex[i].y -= 0.5f;
861   };
862
863   pD3DDev->SetTexture(0, m_SWTarget.Get());
864
865   if (!cbcontrol)
866   {
867     pD3DDev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
868     pD3DDev->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
869     pD3DDev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
870     pD3DDev->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
871     pD3DDev->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE );
872     pD3DDev->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
873   }
874   else
875   {
876     pD3DDev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE2X );
877     pD3DDev->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
878     pD3DDev->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
879     pD3DDev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
880     pD3DDev->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE );
881
882     pD3DDev->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_ADDSIGNED );
883     pD3DDev->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_CURRENT );
884     pD3DDev->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_SPECULAR );
885     pD3DDev->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
886     pD3DDev->SetTextureStageState( 1, D3DTSS_ALPHAARG1, D3DTA_CURRENT );
887
888     pD3DDev->SetTextureStageState( 2, D3DTSS_COLOROP, D3DTOP_DISABLE );
889     pD3DDev->SetTextureStageState( 2, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
890   }
891
892   pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
893   pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE);
894   pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE);
895   pD3DDev->SetRenderState(D3DRS_STENCILENABLE, FALSE);
896   pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
897   pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
898   pD3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
899
900   pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, m_TextureFilter);
901   pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, m_TextureFilter);
902   pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
903   pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
904
905   pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX1);
906
907   if (FAILED(hr = pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, vertex, sizeof(VERTEX))))
908     CLog::Log(LOGERROR, __FUNCTION__": DrawPrimitiveUP failed. %s", CRenderSystemDX::GetErrorDescription(hr).c_str());
909
910   pD3DDev->SetTexture(0, NULL);
911 }
912
913 void CWinRenderer::RenderPS()
914 {
915   if (!m_bUseHQScaler)
916   {
917     Stage1();
918   }
919   else
920   {
921     Stage1();
922     Stage2();
923   }
924 }
925
926 void CWinRenderer::Stage1()
927 {
928   if (!m_bUseHQScaler)
929   {
930     m_colorShader->Render(m_sourceRect, g_graphicsContext.StereoCorrection(m_destRect),
931                             CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast,
932                             CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness,
933                             m_iFlags,
934                             (YUVBuffer*)m_VideoBuffers[m_iYV12RenderBuffer]);
935   }
936   else
937   {
938     // Switch the render target to the temporary destination
939     LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
940     LPDIRECT3DSURFACE9 newRT, oldRT;
941     m_IntermediateTarget.GetSurfaceLevel(0, &newRT);
942     pD3DDevice->GetRenderTarget(0, &oldRT);
943     pD3DDevice->SetRenderTarget(0, newRT);
944
945     CRect srcRect(0.0f, 0.0f, m_sourceWidth, m_sourceHeight);
946     CRect rtRect(0.0f, 0.0f, m_sourceWidth, m_sourceHeight);
947
948     m_colorShader->Render(srcRect, rtRect,
949                           CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast,
950                           CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness,
951                           m_iFlags,
952                           (YUVBuffer*)m_VideoBuffers[m_iYV12RenderBuffer]);
953
954     // Restore the render target
955     pD3DDevice->SetRenderTarget(0, oldRT);
956
957     // MSDN says: Setting a new render target will cause the viewport 
958     // to be set to the full size of the new render target.
959     // So we need restore our viewport
960     g_Windowing.RestoreViewPort();
961
962     oldRT->Release();
963     newRT->Release();
964   }
965 }
966
967 void CWinRenderer::Stage2()
968 {
969   CRect sourceRect;
970
971   // fixup stereo+dxva+hq scaling issue
972   if (m_renderMethod == RENDER_DXVA)
973   {
974     sourceRect.y1 = 0.0f;
975     sourceRect.y2 = m_sourceHeight;
976     sourceRect.x1 = 0.0f;
977     sourceRect.x2 = m_sourceWidth;
978   }
979   else
980     sourceRect = m_sourceRect;
981
982   m_scalerShader->Render(m_IntermediateTarget, m_sourceWidth, m_sourceHeight, m_destWidth, m_destHeight, sourceRect, g_graphicsContext.StereoCorrection(m_destRect));
983 }
984
985 void CWinRenderer::RenderProcessor(DWORD flags)
986 {
987   CSingleLock lock(g_graphicsContext);
988   HRESULT hr;
989   CRect destRect;
990
991   if (m_bUseHQScaler)
992   {
993     destRect.y1 = 0.0f;
994     destRect.y2 = m_sourceHeight;
995     destRect.x1 = 0.0f;
996     destRect.x2 = m_sourceWidth;
997   }
998   else
999     destRect = g_graphicsContext.StereoCorrection(m_destRect);
1000
1001   DXVABuffer *image = (DXVABuffer*)m_VideoBuffers[m_iYV12RenderBuffer];
1002
1003   IDirect3DSurface9* target;
1004   if ( m_bUseHQScaler 
1005     || g_graphicsContext.GetStereoMode() == RENDER_STEREO_MODE_ANAGLYPH_RED_CYAN
1006     || g_graphicsContext.GetStereoMode() == RENDER_STEREO_MODE_ANAGLYPH_GREEN_MAGENTA)
1007   {
1008     m_IntermediateTarget.GetSurfaceLevel(0, &target);
1009   }
1010   else
1011   {
1012     if(FAILED(hr = g_Windowing.Get3DDevice()->GetRenderTarget(0, &target)))
1013     {
1014       CLog::Log(LOGERROR, "CWinRenderer::RenderSurface - failed to get render target. %s", CRenderSystemDX::GetErrorDescription(hr).c_str());
1015       return;
1016     }
1017   }
1018
1019   m_processor->Render(m_sourceRect, destRect, target, image->id, flags);
1020
1021   target->Release();
1022
1023   if (m_bUseHQScaler)
1024   {
1025     Stage2();
1026   }
1027   else if ( g_graphicsContext.GetStereoMode() == RENDER_STEREO_MODE_ANAGLYPH_RED_CYAN
1028          || g_graphicsContext.GetStereoMode() == RENDER_STEREO_MODE_ANAGLYPH_GREEN_MAGENTA)
1029   {
1030     IDirect3DDevice9 *pD3DDev = g_Windowing.Get3DDevice();
1031
1032     struct VERTEX
1033     {
1034       FLOAT x,y,z;
1035       FLOAT tu,tv;
1036     };
1037
1038     VERTEX vertex[] =
1039     {
1040       {destRect.x1 - 0.5f, destRect.y1 - 0.5f, 0.0f, m_destRect.x1 / m_destWidth, m_destRect.y1 / m_destHeight},
1041       {destRect.x2 - 0.5f, destRect.y1 - 0.5f, 0.0f, m_destRect.x2 / m_destWidth, m_destRect.y1 / m_destHeight},
1042       {destRect.x2 - 0.5f, destRect.y2 - 0.5f, 0.0f, m_destRect.x2 / m_destWidth, m_destRect.y2 / m_destHeight},
1043       {destRect.x1 - 0.5f, destRect.y2 - 0.5f, 0.0f, m_destRect.x1 / m_destWidth, m_destRect.y2 / m_destHeight},
1044     };
1045
1046     pD3DDev->SetTexture(0, m_IntermediateTarget.Get());
1047
1048     pD3DDev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
1049     pD3DDev->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
1050     pD3DDev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
1051     pD3DDev->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
1052     pD3DDev->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE );
1053     pD3DDev->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
1054
1055     pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
1056     pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
1057
1058     pD3DDev->SetFVF(D3DFVF_XYZ | D3DFVF_TEX1);
1059
1060     if (FAILED(hr = pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, vertex, sizeof(VERTEX))))
1061       CLog::Log(LOGERROR, __FUNCTION__": DrawPrimitiveUP failed. %s", CRenderSystemDX::GetErrorDescription(hr).c_str());
1062
1063     pD3DDev->SetTexture(0, NULL);
1064   }
1065 }
1066
1067 bool CWinRenderer::RenderCapture(CRenderCapture* capture)
1068 {
1069   if (!m_bConfigured || m_NumYV12Buffers == 0)
1070     return false;
1071
1072   bool succeeded = false;
1073
1074   LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
1075
1076   CRect saveSize = m_destRect;
1077   saveRotatedCoords();//backup current m_rotatedDestCoords
1078
1079   m_destRect.SetRect(0, 0, (float)capture->GetWidth(), (float)capture->GetHeight());
1080   syncDestRectToRotatedPoints();//syncs the changed destRect to m_rotatedDestCoords
1081
1082   LPDIRECT3DSURFACE9 oldSurface;
1083   pD3DDevice->GetRenderTarget(0, &oldSurface);
1084
1085   capture->BeginRender();
1086   if (capture->GetState() != CAPTURESTATE_FAILED)
1087   {
1088     pD3DDevice->BeginScene();
1089     Render(0);
1090     pD3DDevice->EndScene();
1091     capture->EndRender();
1092     succeeded = true;
1093   }
1094
1095   pD3DDevice->SetRenderTarget(0, oldSurface);
1096   oldSurface->Release();
1097
1098   m_destRect = saveSize;
1099   restoreRotatedCoords();//restores the previous state of the rotated dest coords
1100
1101   return succeeded;
1102 }
1103
1104 //********************************************************************************************************
1105 // YV12 Texture creation, deletion, copying + clearing
1106 //********************************************************************************************************
1107 void CWinRenderer::DeleteYV12Texture(int index)
1108 {
1109   CSingleLock lock(g_graphicsContext);
1110   if (m_VideoBuffers[index] != NULL)
1111     SAFE_DELETE(m_VideoBuffers[index]);
1112   m_NumYV12Buffers = 0;
1113 }
1114
1115 bool CWinRenderer::CreateYV12Texture(int index)
1116 {
1117   CSingleLock lock(g_graphicsContext);
1118   DeleteYV12Texture(index);
1119
1120   if (m_renderMethod == RENDER_DXVA)
1121   {
1122     m_VideoBuffers[index] = new DXVABuffer();
1123   }
1124   else
1125   {
1126     YUVBuffer *buf = new YUVBuffer();
1127
1128     if (!buf->Create(m_format, m_sourceWidth, m_sourceHeight))
1129     {
1130       CLog::Log(LOGERROR, __FUNCTION__" - Unable to create YV12 video texture %i", index);
1131       return false;
1132     }
1133     m_VideoBuffers[index] = buf;
1134   }
1135
1136   SVideoBuffer *buf = m_VideoBuffers[index];
1137
1138   buf->StartDecode();
1139   buf->Clear();
1140
1141   if(index == m_iYV12RenderBuffer)
1142     buf->StartRender();
1143
1144   CLog::Log(LOGDEBUG, "created video buffer %i", index);
1145   return true;
1146 }
1147
1148 bool CWinRenderer::Supports(EDEINTERLACEMODE mode)
1149 {
1150   if(mode == VS_DEINTERLACEMODE_OFF
1151   || mode == VS_DEINTERLACEMODE_AUTO
1152   || mode == VS_DEINTERLACEMODE_FORCE)
1153     return true;
1154
1155   return false;
1156 }
1157
1158 bool CWinRenderer::Supports(EINTERLACEMETHOD method)
1159 {
1160   if(method == VS_INTERLACEMETHOD_AUTO)
1161     return true;
1162
1163   if (m_renderMethod == RENDER_DXVA)
1164   {
1165     if(method == VS_INTERLACEMETHOD_DXVA_BOB
1166     || method == VS_INTERLACEMETHOD_DXVA_BEST)
1167       return true;
1168   }
1169
1170   if(m_format != RENDER_FMT_DXVA
1171   && (   method == VS_INTERLACEMETHOD_DEINTERLACE
1172       || method == VS_INTERLACEMETHOD_DEINTERLACE_HALF
1173       || method == VS_INTERLACEMETHOD_SW_BLEND))
1174     return true;
1175
1176   return false;
1177 }
1178
1179 bool CWinRenderer::Supports(ERENDERFEATURE feature)
1180 {
1181   if(feature == RENDERFEATURE_BRIGHTNESS)
1182     return true;
1183
1184   if(feature == RENDERFEATURE_CONTRAST)
1185     return true;
1186
1187   if (feature == RENDERFEATURE_STRETCH         ||
1188       feature == RENDERFEATURE_NONLINSTRETCH   ||
1189       feature == RENDERFEATURE_CROP            ||
1190       feature == RENDERFEATURE_ZOOM            ||
1191       feature == RENDERFEATURE_VERTICAL_SHIFT  ||
1192       feature == RENDERFEATURE_PIXEL_RATIO     ||
1193       feature == RENDERFEATURE_POSTPROCESS)
1194     return true;
1195
1196
1197   return false;
1198 }
1199
1200 bool CWinRenderer::Supports(ESCALINGMETHOD method)
1201 {
1202   if (m_renderMethod == RENDER_PS || m_renderMethod == RENDER_DXVA)
1203   {
1204     if(m_renderMethod == RENDER_DXVA && method == VS_SCALINGMETHOD_DXVA_HARDWARE)
1205       return true;
1206
1207     if(m_deviceCaps.PixelShaderVersion >= D3DPS_VERSION(2, 0)
1208     && (   method == VS_SCALINGMETHOD_AUTO
1209        || (method == VS_SCALINGMETHOD_LINEAR && m_renderMethod == RENDER_PS) ))
1210         return true;
1211
1212     if(m_deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0))
1213     {
1214       if(method == VS_SCALINGMETHOD_CUBIC
1215       || method == VS_SCALINGMETHOD_LANCZOS2
1216       || method == VS_SCALINGMETHOD_SPLINE36_FAST
1217       || method == VS_SCALINGMETHOD_LANCZOS3_FAST
1218       || method == VS_SCALINGMETHOD_SPLINE36
1219       || method == VS_SCALINGMETHOD_LANCZOS3)
1220       {
1221         // if scaling is below level, avoid hq scaling
1222         float scaleX = fabs(((float)m_sourceWidth - m_destRect.Width())/m_sourceWidth)*100;
1223         float scaleY = fabs(((float)m_sourceHeight - m_destRect.Height())/m_sourceHeight)*100;
1224         int minScale = CSettings::Get().GetInt("videoplayer.hqscalers");
1225         if (scaleX < minScale && scaleY < minScale)
1226           return false;
1227         return true;
1228       }
1229     }
1230   }
1231   else if(m_renderMethod == RENDER_SW)
1232   {
1233     if(method == VS_SCALINGMETHOD_AUTO
1234     || method == VS_SCALINGMETHOD_NEAREST)
1235       return true;
1236     if(method == VS_SCALINGMETHOD_LINEAR
1237     && m_deviceCaps.TextureFilterCaps & D3DPTFILTERCAPS_MINFLINEAR
1238     && m_deviceCaps.TextureFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR)
1239       return true;
1240   }
1241   return false;
1242 }
1243
1244 EINTERLACEMETHOD CWinRenderer::AutoInterlaceMethod()
1245 {
1246   if (m_renderMethod == RENDER_DXVA)
1247     return VS_INTERLACEMETHOD_DXVA_BOB;
1248   else
1249     return VS_INTERLACEMETHOD_DEINTERLACE_HALF;
1250 }
1251
1252 unsigned int CWinRenderer::GetProcessorSize()
1253 {
1254   if (m_format == RENDER_FMT_DXVA && m_processor)
1255     return m_processor->Size();
1256   else
1257     return 0;
1258 }
1259
1260 //============================================
1261
1262 YUVBuffer::~YUVBuffer()
1263 {
1264   Release();
1265 }
1266
1267 bool YUVBuffer::Create(ERenderFormat format, unsigned int width, unsigned int height)
1268 {
1269   m_format = format;
1270   m_width = width;
1271   m_height = height;
1272
1273   // Create the buffers in system memory and copy to D3DPOOL_DEFAULT:
1274   // - helps with lost devices. A buffer can be locked for dvdplayer without interfering.
1275   // - Dynamic + D3DPOOL_DEFAULT caused trouble for Intel i3 and some IGP. Bad sync/locking in the driver  I suppose
1276   // and Present failed every second time for the second video played.
1277   // - this is what D3D9 does behind the scenes anyway
1278   switch(m_format)
1279   {
1280   case RENDER_FMT_YUV420P10:
1281   case RENDER_FMT_YUV420P16:
1282     {
1283       if ( !planes[PLANE_Y].texture.Create(m_width    , m_height    , 1, 0, D3DFMT_L16, D3DPOOL_SYSTEMMEM)
1284         || !planes[PLANE_U].texture.Create(m_width / 2, m_height / 2, 1, 0, D3DFMT_L16, D3DPOOL_SYSTEMMEM)
1285         || !planes[PLANE_V].texture.Create(m_width / 2, m_height / 2, 1, 0, D3DFMT_L16, D3DPOOL_SYSTEMMEM))
1286         return false;
1287       m_activeplanes = 3;
1288       break;
1289     }
1290   case RENDER_FMT_YUV420P:
1291     {
1292       if ( !planes[PLANE_Y].texture.Create(m_width    , m_height    , 1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM)
1293         || !planes[PLANE_U].texture.Create(m_width / 2, m_height / 2, 1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM)
1294         || !planes[PLANE_V].texture.Create(m_width / 2, m_height / 2, 1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM))
1295         return false;
1296       m_activeplanes = 3;
1297       break;
1298     }
1299   case RENDER_FMT_NV12:
1300     {
1301       if ( !planes[PLANE_Y].texture.Create(m_width    , m_height    , 1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM)
1302         || !planes[PLANE_UV].texture.Create(m_width / 2, m_height / 2, 1, 0, D3DFMT_A8L8, D3DPOOL_SYSTEMMEM))
1303         return false;
1304       m_activeplanes = 2;
1305       break;
1306     }
1307   case RENDER_FMT_YUYV422:
1308     {
1309       if ( !planes[PLANE_Y].texture.Create(m_width >> 1    , m_height    , 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM))
1310         return false;
1311       m_activeplanes = 1;
1312       break;
1313     }
1314   case RENDER_FMT_UYVY422:
1315     {
1316       if ( !planes[PLANE_Y].texture.Create(m_width >> 1    , m_height    , 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM))
1317         return false;
1318       m_activeplanes = 1;
1319       break;
1320     }
1321   default:
1322     m_activeplanes = 0;
1323     return false;
1324   }
1325
1326   return true;
1327 }
1328
1329 void YUVBuffer::Release()
1330 {
1331   for(unsigned i = 0; i < m_activeplanes; i++)
1332   {
1333     planes[i].texture.Release();
1334     memset(&planes[i].rect, 0, sizeof(planes[i].rect));
1335   }
1336 }
1337
1338 void YUVBuffer::StartRender()
1339 {
1340   for(unsigned i = 0; i < m_activeplanes; i++)
1341   {
1342     if(planes[i].texture.Get() && planes[i].rect.pBits)
1343       if (!planes[i].texture.UnlockRect(0))
1344         CLog::Log(LOGERROR, __FUNCTION__" - failed to unlock texture %d", i);
1345     memset(&planes[i].rect, 0, sizeof(planes[i].rect));
1346   }
1347 }
1348
1349 void YUVBuffer::StartDecode()
1350 {
1351   for(unsigned i = 0; i < m_activeplanes; i++)
1352   {
1353     if(planes[i].texture.Get()
1354     && planes[i].texture.LockRect(0, &planes[i].rect, NULL, D3DLOCK_DISCARD) == false)
1355     {
1356       memset(&planes[i].rect, 0, sizeof(planes[i].rect));
1357       CLog::Log(LOGERROR, __FUNCTION__" - failed to lock texture %d into memory", i);
1358     }
1359   }
1360 }
1361
1362 void YUVBuffer::Clear()
1363 {
1364   // Set Y to 0 and U,V to 128 (RGB 0,0,0) to avoid visual artifacts at the start of playback
1365
1366   switch(m_format)
1367   {
1368   case RENDER_FMT_YUV420P16:
1369     {
1370       wmemset((wchar_t*)planes[PLANE_Y].rect.pBits, 0,     planes[PLANE_Y].rect.Pitch *  m_height    / 2);
1371       wmemset((wchar_t*)planes[PLANE_U].rect.pBits, 32768, planes[PLANE_U].rect.Pitch * (m_height/2) / 2);
1372       wmemset((wchar_t*)planes[PLANE_V].rect.pBits, 32768, planes[PLANE_V].rect.Pitch * (m_height/2) / 2);
1373       break;
1374     }
1375   case RENDER_FMT_YUV420P10:
1376     {
1377       wmemset((wchar_t*)planes[PLANE_Y].rect.pBits, 0,   planes[PLANE_Y].rect.Pitch *  m_height    / 2);
1378       wmemset((wchar_t*)planes[PLANE_U].rect.pBits, 512, planes[PLANE_U].rect.Pitch * (m_height/2) / 2);
1379       wmemset((wchar_t*)planes[PLANE_V].rect.pBits, 512, planes[PLANE_V].rect.Pitch * (m_height/2) / 2);
1380       break;
1381     }
1382   case RENDER_FMT_YUV420P:
1383     {
1384       memset(planes[PLANE_Y].rect.pBits, 0,   planes[PLANE_Y].rect.Pitch *  m_height);
1385       memset(planes[PLANE_U].rect.pBits, 128, planes[PLANE_U].rect.Pitch * (m_height/2));
1386       memset(planes[PLANE_V].rect.pBits, 128, planes[PLANE_V].rect.Pitch * (m_height/2));
1387       break;
1388     }
1389   case RENDER_FMT_NV12:
1390     {
1391       memset(planes[PLANE_Y].rect.pBits, 0,   planes[PLANE_Y].rect.Pitch *  m_height);
1392       memset(planes[PLANE_UV].rect.pBits, 128, planes[PLANE_U].rect.Pitch * (m_height/2));
1393       break;
1394     }
1395   // YUY2, UYVY: wmemset to set a 16bit pattern, byte-swapped because x86 is LE
1396   case RENDER_FMT_YUYV422:
1397     {
1398       wmemset((wchar_t*)planes[PLANE_Y].rect.pBits, 0x8000, planes[PLANE_Y].rect.Pitch / 2 * m_height);
1399       break;
1400     }
1401   case RENDER_FMT_UYVY422:
1402     {
1403       wmemset((wchar_t*)planes[PLANE_Y].rect.pBits, 0x0080, planes[PLANE_Y].rect.Pitch / 2 * m_height);
1404       break;
1405     }
1406
1407   }
1408 }
1409
1410
1411 //==================================
1412
1413 DXVABuffer::~DXVABuffer()
1414 {
1415   Release();
1416 }
1417
1418 void DXVABuffer::Release()
1419 {
1420   id = 0;
1421 }
1422
1423 void DXVABuffer::StartDecode()
1424 {
1425   Release();
1426 }
1427 #endif