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