[vlc-devel] [PATCH] Direct3D shader support (HLSL)

Sasha Koruga skoruga at gmail.com
Mon Aug 16 06:07:58 CEST 2010


Hello,

Here is the shader code with GUI support stripped out (as requested,
I'll submit that in a separate patch). Also as requested, I modified
the code so that instead of taking a hard-coded string as the shader
code, it will load the pixelShader.fx file. This allows users to
freely adjust the shader code without needing to recompile VLC
(however, that does require that the pixelShader.fx file is
distributed in release). Also, I made significant adjustments in order
to enable users to have multiple shaders running at the same time.

Please note: The make file needs to be adjusted so that the
pixelShader.fx gets copied to config_GetUserDir( VLC_DATA_DIR )
(please feel free to adjust this) for window builds.
config_GetUserDir( VLC_DATA_DIR ) currently returns "C:\Users\<user
name>\AppData\Roaming\vlc" for me, but that's with make
package-win32-base-exe. As I said, feel free to adjust that and put
the file where ever you please.
The code does have a fallback where it will check the current
directory if it cannot find the file in VLC_DATA_DIR.

Best Regards,
Sasha


Patch:
>From cbd13740f6f382d85a03116afa396d548c0e9fd0 Mon Sep 17 00:00:00 2001
From: Sasha Koruga <skoruga at gmail.com>
Date: Sun, 15 Aug 2010 20:48:05 -0700
Subject: [PATCH] Direct3D Pixel Shading (HLSL) support added (no GUI)

---
 modules/video_output/msw/common.h       |    5 +-
 modules/video_output/msw/direct3d.c     |  208 +++++++++++++++++++++++++------
 modules/video_output/msw/pixelShader.fx |  162 ++++++++++++++++++++++++
 3 files changed, 336 insertions(+), 39 deletions(-)
 create mode 100644 modules/video_output/msw/pixelShader.fx

diff --git a/modules/video_output/msw/common.h
b/modules/video_output/msw/common.h
index 3a67c7d..e3d2fa0 100644
--- a/modules/video_output/msw/common.h
+++ b/modules/video_output/msw/common.h
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * common.h: Windows video output header file
  *****************************************************************************
- * Copyright (C) 2001-2009 the VideoLAN team
+ * Copyright (C) 2001-2010 the VideoLAN team
  * $Id$
  *
  * Authors: Gildas Bazin <gbazin at videolan.org>
@@ -168,6 +168,7 @@ struct vout_display_sys_t
     bool allow_hw_yuv;    /* Should we use hardware YUV->RGB conversions */
     /* show video on desktop window ? */
     bool use_desktop;
+    bool *shaderFXOption;
     struct {
         bool is_fullscreen;
         bool is_on_top;
@@ -177,6 +178,8 @@ struct vout_display_sys_t

     // core objects
     HINSTANCE               hd3d9_dll;       /* handle of the opened
d3d9 dll */
+    HINSTANCE               hd3d9x_dll;      /* handle of the opened
d3d9x dll */
+    void*                   d3dxShader;
     LPDIRECT3D9             d3dobj;
     LPDIRECT3DDEVICE9       d3ddev;
     D3DPRESENT_PARAMETERS   d3dpp;
diff --git a/modules/video_output/msw/direct3d.c
b/modules/video_output/msw/direct3d.c
index 9237c30..4ce7327 100644
--- a/modules/video_output/msw/direct3d.c
+++ b/modules/video_output/msw/direct3d.c
@@ -1,10 +1,11 @@
 /*****************************************************************************
  * direct3d.c: Windows Direct3D video output module
  *****************************************************************************
- * Copyright (C) 2006-2009 the VideoLAN team
+ * Copyright (C) 2006-2010 the VideoLAN team
  *$Id$
  *
- * Authors: Damien Fouilleul <damienf at videolan.org>
+ * Authors: Damien Fouilleul <damienf at videolan.org>,
+ *          Sasha Koruga <skoruga at gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -44,8 +45,16 @@

 #include <windows.h>
 #include <d3d9.h>
+#include <d3dx9.h>

 #include "common.h"
+#include "hlsl.h"
+
+#ifndef D3DXFX_NOT_CLONEABLE
+#define D3DXFX_NOT_CLONEABLE    (1 << 11)
+#endif
+
+#define SHADEROPTIONSCOUNT 8

 /*****************************************************************************
  * Module descriptor
@@ -456,6 +465,31 @@ static int Direct3DCreate(vout_display_t *vd)
     }
     sys->d3dobj = d3dobj;

+    //load shader support
+    for(int i = 43; i > 23; --i) {
+        char buffer[3], filename[14];
+        const char pre[] = "D3dx9_", post[] = ".dll";
+        strncpy(filename, pre, sizeof(pre));
+        strncat(filename, itoa(i,buffer,10), 2);
+        strncat(filename, post, sizeof(post));
+        sys->hd3d9x_dll = LoadLibrary(filename);
+        msg_Dbg(vd, "Attempting to load: %s", filename);
+        if(sys->hd3d9x_dll) {
+            msg_Dbg(vd, "loaded: %s", filename);
+            break;
+        }
+    }
+    if(!sys->hd3d9x_dll) {
+        msg_Warn(vd, "cannot load D3dx9d_[24-43].dll; HLSL pixel
shading will be disabled. (Please install DirectX end-user runtime)");
+        sys->d3dxShader = NULL;
+        sys->shaderFXOption = NULL;
+    }
+    else {
+        sys->shaderFXOption = malloc(sizeof(bool) * SHADEROPTIONSCOUNT);
+        for(unsigned int i = 0; i < SHADEROPTIONSCOUNT; ++i)
+            sys->shaderFXOption[i] = false;
+    }
+
     /*
     ** Get device capabilities
     */
@@ -478,13 +512,23 @@ static void Direct3DDestroy(vout_display_t *vd)
 {
     vout_display_sys_t *sys = vd->sys;

-    if (sys->d3dobj)
-       IDirect3D9_Release(sys->d3dobj);
-    if (sys->hd3d9_dll)
+    if (sys->d3dobj) {
+        IDirect3D9_Release(sys->d3dobj);
+        sys->d3dobj = NULL;
+    }
+    if (sys->hd3d9_dll) {
         FreeLibrary(sys->hd3d9_dll);
+        sys->hd3d9_dll = NULL;
+    }
+    if (sys->hd3d9x_dll) {
+        FreeLibrary(sys->hd3d9x_dll);
+        sys->hd3d9x_dll = NULL;
+    }
+    if (sys->shaderFXOption) {
+        free(sys->shaderFXOption);
+        sys->shaderFXOption = NULL;
+    }

-    sys->d3dobj = NULL;
-    sys->hd3d9_dll = NULL;
 }


@@ -589,6 +633,40 @@ static int Direct3DOpen(vout_display_t *vd,
video_format_t *fmt)
         return VLC_EGENERIC;
     }

+    if(sys->hd3d9x_dll) {
+        HRESULT (WINAPI * OurD3DXCreateEffectFromFileA)(
+            LPDIRECT3DDEVICE9               pDevice,
+            LPCSTR                          pSrcFile,
+            CONST D3DXMACRO*                pDefines,
+            LPD3DXINCLUDE                   pInclude,
+            DWORD                           Flags,
+            LPD3DXEFFECTPOOL                pPool,
+            LPD3DXEFFECT*                   ppEffect,
+            LPD3DXBUFFER*                   ppCompilationErrors);
+
+        OurD3DXCreateEffectFromFileA =
(void*)GetProcAddress(sys->hd3d9x_dll,
TEXT("D3DXCreateEffectFromFileA"));
+        if (!OurD3DXCreateEffectFromFileA) {
+            msg_Warn(vd, "Cannot locate reference to
D3DXCreateEffectFromFileA ABI in DLL; pixel shading will be
disabled");
+            sys->d3dxShader = NULL;
+        }
+        else {
+            LPD3DXBUFFER buffer = NULL;
+            DWORD dwShaderFlags = D3DXFX_NOT_CLONEABLE;
+            char fileLocation[512];
+            strncpy(fileLocation, config_GetUserDir( VLC_DATA_DIR ), 512);
+            strncat(fileLocation, "\\pixelShader.fx", 512 -
strlen(fileLocation));
+            HRESULT hr = OurD3DXCreateEffectFromFileA(sys->d3ddev,
fileLocation, NULL, NULL, dwShaderFlags, NULL,
((ID3DXEffect**)(&sys->d3dxShader)), &buffer);
+            if(FAILED(hr)) //try loading it from current directory as
oppose to VLC_DATA_DIR
+                hr = OurD3DXCreateEffectFromFileA(sys->d3ddev,
"pixelShader.fx", NULL, NULL, dwShaderFlags, NULL,
((ID3DXEffect**)(&sys->d3dxShader)), &buffer);
+            if(FAILED(hr)) {
+               msg_Warn(vd, "D3DXCreateEffectFromFileA Error
(hr=0x%lX) -- pixel shading will be disabled (pixelShader.fx possibly
missing).", hr);
+               if(buffer)
+                   msg_Warn(vd, "HLSL Compilation Error: %s",
(char*)buffer->lpVtbl->GetBufferPointer(buffer));
+               sys->d3dxShader = NULL;
+            }
+        }
+    }
+
     /* Change the window title bar text */
     EventThreadUpdateTitle(sys->event, VOUT_TITLE " (Direct3D output)");

@@ -605,10 +683,14 @@ static void Direct3DClose(vout_display_t *vd)

     Direct3DDestroyResources(vd);

-    if (sys->d3ddev)
+    if(sys->d3dxShader) {
+        ((ID3DXEffect*)(sys->d3dxShader))->lpVtbl->Release(sys->d3dxShader);
+        sys->d3dxShader = NULL;
+    }
+    if (sys->d3ddev) {
        IDirect3DDevice9_Release(sys->d3ddev);
-
-    sys->d3ddev = NULL;
+       sys->d3ddev = NULL;
+    }
 }

 /**
@@ -1035,6 +1117,7 @@ static void Direct3DDestroyScene(vout_display_t *vd)
  */
 static void Direct3DRenderScene(vout_display_t *vd, LPDIRECT3DSURFACE9 surface)
 {
+    unsigned int shaderPasses;
     vout_display_sys_t *sys = vd->sys;
     LPDIRECT3DDEVICE9 d3ddev = sys->d3ddev;
     HRESULT hr;
@@ -1145,39 +1228,88 @@ static void Direct3DRenderScene(vout_display_t
*vd, LPDIRECT3DSURFACE9 surface)
         return;
     }

-    // Setup our texture. Using textures introduces the texture stage states,
-    // which govern how textures get blended together (in the case of multiple
-    // textures) and lighting information. In this case, we are modulating
-    // (blending) our texture with the diffuse color of the vertices.
-    hr = IDirect3DDevice9_SetTexture(d3ddev, 0,
(LPDIRECT3DBASETEXTURE9)d3dtex);
-    if (FAILED(hr)) {
-        msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
-        IDirect3DDevice9_EndScene(d3ddev);
-        return;
-    }
+    if(((ID3DXEffect*)(sys->d3dxShader)))
+    {
+        hr = ((ID3DXEffect*)(sys->d3dxShader))->lpVtbl->SetTechnique(((ID3DXEffect*)(sys->d3dxShader)),
"Shade");
+        if (FAILED(hr))
+        {
+           msg_Err(vd, "SetTechnique failed (hr=0x%lX)", hr);
+        }

-    // Render the vertex buffer contents
-    hr = IDirect3DDevice9_SetStreamSource(d3ddev, 0, d3dvtc, 0,
sizeof(CUSTOMVERTEX));
-    if (FAILED(hr)) {
-        msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
-        IDirect3DDevice9_EndScene(d3ddev);
-        return;
+        const char * shaderStrings[SHADEROPTIONSCOUNT] =
{"convertbt", "widen", "detect", "gamma18", "gamma22", "gammabt",
"invert", "grayscale"};
+        for(unsigned int i = 0; i < SHADEROPTIONSCOUNT; ++i)
+        {
+            hr =
((ID3DXEffect*)(sys->d3dxShader))->lpVtbl->SetBool(((ID3DXEffect*)(sys->d3dxShader)),
shaderStrings[i], sys->shaderFXOption[i]);
+            if (FAILED(hr))
+            {
+                msg_Err(vd, "SetBool #%d failed (hr=0x%lX)", i, hr);
+            }
+        }
+
+        hr = ((ID3DXEffect*)(sys->d3dxShader))->lpVtbl->Begin(((ID3DXEffect*)(sys->d3dxShader)),
&shaderPasses, 0);
+        if (FAILED(hr))
+        {
+           msg_Err(vd, "Begin failed (hr=0x%lX)", hr);
+        }
     }
+    else
+        shaderPasses = 1;
+
+    for( UINT uPass = 0; uPass < shaderPasses; ++uPass ) {
+        if(((ID3DXEffect*)(sys->d3dxShader))) {
+            hr =
((ID3DXEffect*)(sys->d3dxShader))->lpVtbl->BeginPass(((ID3DXEffect*)(sys->d3dxShader)),
uPass);
+            if (FAILED(hr))
+                msg_Err(vd, "BeginPass failed (hr=0x%lX)", hr);
+        }
+
+        // Setup our texture. Using textures introduces the texture
stage states,
+        // which govern how textures get blended together (in the
case of multiple
+        // textures) and lighting information. In this case, we are modulating
+        // (blending) our texture with the diffuse color of the vertices.
+        hr = IDirect3DDevice9_SetTexture(d3ddev, 0,
(LPDIRECT3DBASETEXTURE9)d3dtex);
+        if (FAILED(hr)) {
+            msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
+            IDirect3DDevice9_EndScene(d3ddev);
+            return;
+        }
+
+        // Render the vertex buffer contents
+        hr = IDirect3DDevice9_SetStreamSource(d3ddev, 0, d3dvtc, 0,
sizeof(CUSTOMVERTEX));
+        if (FAILED(hr)) {
+            msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
+            IDirect3DDevice9_EndScene(d3ddev);
+            return;
+        }
+
+        // we use FVF instead of vertex shader
+        hr = IDirect3DDevice9_SetFVF(d3ddev, D3DFVF_CUSTOMVERTEX);
+        if (FAILED(hr)) {
+            msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
+            IDirect3DDevice9_EndScene(d3ddev);
+            return;
+        }
+
+        // draw rectangle
+        hr = IDirect3DDevice9_DrawPrimitive(d3ddev, D3DPT_TRIANGLEFAN, 0, 2);
+        if (FAILED(hr)) {
+            msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
+            IDirect3DDevice9_EndScene(d3ddev);
+            return;
+        }
+
+
+        if(((ID3DXEffect*)(sys->d3dxShader))) {
+            hr =
((ID3DXEffect*)(sys->d3dxShader))->lpVtbl->EndPass(((ID3DXEffect*)(sys->d3dxShader)));
+            if (FAILED(hr))
+                msg_Err(vd, "EndPass failed (hr=0x%lX)", hr);
+        }

-    // we use FVF instead of vertex shader
-    hr = IDirect3DDevice9_SetFVF(d3ddev, D3DFVF_CUSTOMVERTEX);
-    if (FAILED(hr)) {
-        msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
-        IDirect3DDevice9_EndScene(d3ddev);
-        return;
     }

-    // draw rectangle
-    hr = IDirect3DDevice9_DrawPrimitive(d3ddev, D3DPT_TRIANGLEFAN, 0, 2);
-    if (FAILED(hr)) {
-        msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
-        IDirect3DDevice9_EndScene(d3ddev);
-        return;
+    if(((ID3DXEffect*)(sys->d3dxShader))) {
+        hr = ((ID3DXEffect*)(sys->d3dxShader))->lpVtbl->End(((ID3DXEffect*)(sys->d3dxShader)));
+        if (FAILED(hr))
+           msg_Err(vd, "End failed (hr=0x%lX)", hr);
     }

     // End the scene
diff --git a/modules/video_output/msw/pixelShader.fx
b/modules/video_output/msw/pixelShader.fx
new file mode 100644
index 0000000..ed71b3e
--- /dev/null
+++ b/modules/video_output/msw/pixelShader.fx
@@ -0,0 +1,162 @@
+/*****************************************************************************
+ * pixelShader.fx: Direct3D Shader Code
+ *****************************************************************************
+ * Copyright (C) 2010 the VideoLAN team
+ *
+ * Authors: Sasha Koruga <skoruga at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA
02110-1301, USA.
+ *****************************************************************************/
+sampler2D screen;
+bool convertbt, widen, detect, gamma18, gamma22, gammabt, invert, grayscale;
+
+float4 rgb_to_yuv601(float4 RGB)
+{
+    float Kr = 0.299;
+    float Kg = 0.587;
+    float Kb = 0.114;
+    float Y = Kr*RGB.r + Kg*RGB.g + Kb*RGB.b;
+    float V = (RGB.r-Y)/(1-Kr);
+    float U = (RGB.b-Y)/(1-Kb);
+    return float4(Y,U,V,1);
+}
+
+float4 yuv709_to_rgb(float4 YUV)
+{
+    float Kr = 0.2125;
+    float Kg = 0.7154;
+    float Kb = 0.0721;
+    float Y = YUV.x;
+    float U = YUV.y;
+    float V = YUV.z;
+    float R = Y + V*(1-Kr);
+    float G = Y - U*(1-Kb)*Kb/Kg - V*(1-Kr)*Kr/Kg;
+    float B = Y + U*(1-Kb);
+    return float4(R,G,B,1);
+}
+
+float4 Invert(float4 color)
+{
+    color.r = 1.0 - color.r;
+    color.g = 1.0 - color.g;
+    color.b = 1.0 - color.b;
+    return color;
+}
+
+float4 Convert601to709(float4 color)
+{
+    return yuv709_to_rgb(rgb_to_yuv601(color));
+}
+
+float4 GammaCorrection18(float4 color)
+{
+    color = pow(abs(color),1.0/1.8);
+    return color;
+}
+
+float4 GammaCorrection22(float4 color)
+{
+    color = pow(abs(color),1.0/2.2);
+    return color;
+}
+
+float4 GammaCorrectionBT709(float4 color)
+{
+    if(color.r > 0.018)
+        color.r = 1.099 * pow(abs(color.r),0.45) - 0.099;
+    else
+        color.r = 4.5138 * color.r;
+    if(color.g > 0.018)
+        color.g = 1.099 * pow(abs(color.g),0.45) - 0.099;
+    else
+        color.g = 4.5138 * color.g;
+    if(color.b > 0.018)
+        color.b = 1.099 * pow(abs(color.b),0.45) - 0.099;
+    else
+        color.b = 4.5138 * color.b;
+    return color;
+}
+
+float4 WidenColorSpace(float4 color)
+{
+    color.r = max(color.r - 0.0627450980392157,0) * 1.164383561643836;
+    color.g = max(color.g - 0.0627450980392157,0) * 1.164383561643836;
+    color.b = max(color.b - 0.0627450980392157,0) * 1.164383561643836;
+    return saturate(color);
+}
+
+float4 Grayscale(float4 color)
+{
+    float gray = 0.2989 * color.r + 0.5870 * color.g + 0.1140 * color.b;
+    color.r = color.g = color.b = gray;
+    return saturate(color);
+}
+
+float4 Detect15(float4 color)
+{
+    for(int i = 0; i < 3; ++i)
+    {
+            if(color[i] < .03 || color[i] >.97)
+            {
+                color[0] = 1; color[1] = color[2] = 0;
+            }
+    }
+    return saturate(color);
+}
+
+float4 disabled(float2 screenCoords : TEXCOORD0) : COLOR0
+{
+    return saturate(tex2D( screen, screenCoords.xy));
+}
+
+float4 shade(float2 screenCoords : TEXCOORD0) : COLOR0
+{
+    float4 color = tex2D( screen, screenCoords.xy);
+
+    if(convertbt)
+        color = Convert601to709(color);
+    if(widen)
+        color = WidenColorSpace(color);
+    if(detect)
+        color = Detect15(color);
+    if(gamma18)
+        color = GammaCorrection18(color);
+    if(gamma22)
+        color = GammaCorrection22(color);
+    if(gammabt)
+        color = GammaCorrectionBT709(color);
+    if(invert)
+        color = Invert(color);
+    if(grayscale)
+        color = Grayscale(color);
+
+    return color;
+}
+
+technique Shade
+{
+    pass p1
+    {
+        PixelShader = compile ps_3_0 shade();
+    }
+}
+
+technique Disabled
+{
+    pass p1
+    {
+        PixelShader = compile ps_2_0 disabled();
+    }
+}
-- 
1.7.0.2.msysgit.0
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-Direct3D-Pixel-Shading-HLSL-support-added-no-GUI.patch
Type: application/octet-stream
Size: 17185 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/vlc-devel/attachments/20100815/f23181fd/attachment.obj>


More information about the vlc-devel mailing list