texture g_UTexture;
texture g_VTexture;
float4x4 g_ColorMatrix;
+float2 g_StepXY;
sampler YSampler =
sampler_state {
float4 YUV = float4(tex2D (YSampler, In.TextureY).x
, tex2D (USampler, In.TextureU).ra
, 1.0);
+#elif defined(XBMC_YUY2) || defined(XBMC_UYVY)
+ // The HLSL compiler is smart enough to optimize away these redundant assignments.
+ // That way the code is almost identical to the OGL shader.
+ float2 stepxy = g_StepXY;
+ float2 pos = In.TextureY;
+ pos = float2(pos.x - (stepxy.x * 0.25), pos.y);
+ float2 f = frac(pos / stepxy);
+
+ //y axis will be correctly interpolated by opengl
+ //x axis will not, so we grab two pixels at the center of two columns and interpolate ourselves
+ float4 c1 = tex2D(YSampler, float2(pos.x + ((0.5 - f.x) * stepxy.x), pos.y));
+ float4 c2 = tex2D(YSampler, float2(pos.x + ((1.5 - f.x) * stepxy.x), pos.y));
+
+ /* each pixel has two Y subpixels and one UV subpixel
+ YUV Y YUV
+ check if we're left or right of the middle Y subpixel and interpolate accordingly*/
+ #if defined(XBMC_YUY2) // BGRA = YUYV
+ float leftY = lerp(c1.b, c1.r, f.x * 2.0);
+ float rightY = lerp(c1.r, c2.b, f.x * 2.0 - 1.0);
+ float2 outUV = lerp(c1.ga, c2.ga, f.x);
+ #elif defined(XBMC_UYVY) // BGRA = UYVY
+ float leftY = lerp(c1.g, c1.a, f.x * 2.0);
+ float rightY = lerp(c1.a, c2.g, f.x * 2.0 - 1.0);
+ float2 outUV = lerp(c1.br, c2.br, f.x);
+ #endif
+ float outY = lerp(leftY, rightY, step(0.5, f.x));
+ float4 YUV = float4(outY, outUV, 1.0);
#endif
+
OUT.RGBColor = mul(YUV, g_ColorMatrix);
OUT.RGBColor.a = 1.0;
return OUT;
CWinShader::CreateVertexBuffer(D3DFVF_XYZRHW | D3DFVF_TEX3, 4, sizeof(CUSTOMVERTEX), 2);
+ m_sourceWidth = sourceWidth;
+ m_sourceHeight = sourceHeight;
+
+ unsigned int texWidth;
+
DefinesMap defines;
if (fmt == YV12)
+ {
defines["XBMC_YV12"] = "";
+ texWidth = sourceWidth;
+
+ if(!m_YUVPlanes[0].Create(texWidth , m_sourceHeight , 1, 0, D3DFMT_L8, D3DPOOL_DEFAULT)
+ || !m_YUVPlanes[1].Create(texWidth / 2, m_sourceHeight / 2, 1, 0, D3DFMT_L8, D3DPOOL_DEFAULT)
+ || !m_YUVPlanes[2].Create(texWidth / 2, m_sourceHeight / 2, 1, 0, D3DFMT_L8, D3DPOOL_DEFAULT))
+ {
+ CLog::Log(LOGERROR, __FUNCTION__": Failed to create YV12 planes.");
+ return false;
+ }
+ }
else if (fmt == NV12)
+ {
defines["XBMC_NV12"] = "";
- else
- return false;
+ texWidth = sourceWidth;
- CStdString effectString = "special://xbmc/system/shaders/yuv2rgb_d3d.fx";
-
- if(!LoadEffect(effectString, &defines))
- {
- CLog::Log(LOGERROR, __FUNCTION__": Failed to load shader %s.", effectString.c_str());
- return false;
+ if(!m_YUVPlanes[0].Create(texWidth , m_sourceHeight , 1, 0, D3DFMT_L8, D3DPOOL_DEFAULT)
+ || !m_YUVPlanes[1].Create(texWidth / 2, m_sourceHeight / 2, 1, 0, D3DFMT_A8L8, D3DPOOL_DEFAULT))
+ {
+ CLog::Log(LOGERROR, __FUNCTION__": Failed to create NV12 planes.");
+ return false;
+ }
}
-
- m_sourceWidth = sourceWidth;
- m_sourceHeight = sourceHeight;
-
- if (fmt == YV12)
+ else if (fmt == YUY2)
{
- if(!m_YUVPlanes[0].Create(m_sourceWidth , m_sourceHeight , 1, 0, D3DFMT_L8, D3DPOOL_DEFAULT)
- || !m_YUVPlanes[1].Create(m_sourceWidth / 2, m_sourceHeight / 2, 1, 0, D3DFMT_L8, D3DPOOL_DEFAULT)
- || !m_YUVPlanes[2].Create(m_sourceWidth / 2, m_sourceHeight / 2, 1, 0, D3DFMT_L8, D3DPOOL_DEFAULT))
+ defines["XBMC_YUY2"] = "";
+ texWidth = sourceWidth >> 1;
+
+ if(!m_YUVPlanes[0].Create(texWidth , m_sourceHeight , 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT))
{
- CLog::Log(LOGERROR, __FUNCTION__": Failed to create YUV planes.");
+ CLog::Log(LOGERROR, __FUNCTION__": Failed to create YUY2 planes.");
return false;
}
}
- else if (fmt == NV12)
+ else if (fmt == UYVY)
{
- if(!m_YUVPlanes[0].Create(m_sourceWidth , m_sourceHeight , 1, 0, D3DFMT_L8, D3DPOOL_DEFAULT)
- || !m_YUVPlanes[1].Create(m_sourceWidth / 2, m_sourceHeight / 2, 1, 0, D3DFMT_A8L8, D3DPOOL_DEFAULT))
+ defines["XBMC_UYVY"] = "";
+ texWidth = sourceWidth >> 1;
+
+ if(!m_YUVPlanes[0].Create(texWidth , m_sourceHeight , 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT))
{
- CLog::Log(LOGERROR, __FUNCTION__": Failed to create YUV planes.");
+ CLog::Log(LOGERROR, __FUNCTION__": Failed to create UYVY planes.");
return false;
}
}
+ else
+ return false;
+
+ m_texSteps[0] = 1.0f/(float)texWidth;
+ m_texSteps[1] = 1.0f/(float)sourceHeight;
+
+ CStdString effectString = "special://xbmc/system/shaders/yuv2rgb_d3d.fx";
+
+ if(!LoadEffect(effectString, &defines))
+ {
+ CLog::Log(LOGERROR, __FUNCTION__": Failed to load shader %s.", effectString.c_str());
+ return false;
+ }
return true;
}
void CYUV2RGBShader::SetShaderParameters(YUVBuffer* YUVbuf)
{
- m_effect.SetMatrix( "g_ColorMatrix", m_matrix.Matrix());
- m_effect.SetTechnique( "YUV2RGB_T" );
- m_effect.SetTexture( "g_YTexture", m_YUVPlanes[0] ) ;
- m_effect.SetTexture( "g_UTexture", m_YUVPlanes[1] ) ;
- if (YUVbuf->GetActivePlanes() == 3)
- m_effect.SetTexture( "g_VTexture", m_YUVPlanes[2] ) ;
+ m_effect.SetMatrix("g_ColorMatrix", m_matrix.Matrix());
+ m_effect.SetTechnique("YUV2RGB_T");
+ m_effect.SetTexture("g_YTexture", m_YUVPlanes[0]);
+ if (YUVbuf->GetActivePlanes() > 1)
+ m_effect.SetTexture("g_UTexture", m_YUVPlanes[1]);
+ if (YUVbuf->GetActivePlanes() > 2)
+ m_effect.SetTexture("g_VTexture", m_YUVPlanes[2]);
+ m_effect.SetFloatArray("g_StepXY", m_texSteps, sizeof(m_texSteps)/sizeof(m_texSteps[0]));
}
void CYUV2RGBShader::ReleaseInternal()
bool CYUV2RGBShader::UploadToGPU(YUVBuffer* YUVbuf)
{
- const RECT rect = { 0, 0, m_sourceWidth, m_sourceHeight };
- const RECT recthalf = { 0, 0, m_sourceWidth / 2, m_sourceHeight / 2};
const POINT point = { 0, 0 };
for (unsigned int i = 0; i<YUVbuf->GetActivePlanes(); i++)
{
+ const RECT rect = { 0, 0, YUVbuf->planes[i].texture.GetWidth(), YUVbuf->planes[i].texture.GetHeight() };
IDirect3DSurface9 *src, *dest;
if(FAILED(YUVbuf->planes[i].texture.Get()->GetSurfaceLevel(0, &src)))
CLog::Log(LOGERROR, __FUNCTION__": Failed to retrieve level 0 surface for source YUV plane %d", i);
if (FAILED(m_YUVPlanes[i].Get()->GetSurfaceLevel(0, &dest)))
CLog::Log(LOGERROR, __FUNCTION__": Failed to retrieve level 0 surface for destination YUV plane %d", i);
- if (FAILED(g_Windowing.Get3DDevice()->UpdateSurface(src, i == 0 ? &rect : &recthalf, dest, &point)))
+ if (FAILED(g_Windowing.Get3DDevice()->UpdateSurface(src, &rect, dest, &point)))
{
CLog::Log(LOGERROR, __FUNCTION__": Failed to copy plane %d from sysmem to vidmem.", i);
src->Release();