[vlc-commits] direct3d11: sample only the visible area of the texture

Steve Lhomme git at videolan.org
Thu Aug 27 16:20:57 CEST 2020


vlc | branch: master | Steve Lhomme <robux4 at ycbcr.xyz> | Thu Aug 27 15:38:04 2020 +0200| [968e3788f56b5b6ad6cfdd12b6bbcf87e5853c7c] | committer: Steve Lhomme

direct3d11: sample only the visible area of the texture

This is similar to how the OpenGL module works and is easier to handle cropped
sources.

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=968e3788f56b5b6ad6cfdd12b6bbcf87e5853c7c
---

 modules/video_output/win32/d3d11_quad.c    | 121 ++++++-----------------------
 modules/video_output/win32/d3d11_quad.h    |   2 +-
 modules/video_output/win32/d3d11_shaders.c |   4 +-
 modules/video_output/win32/d3d11_shaders.h |   3 +-
 modules/video_output/win32/direct3d11.c    |  62 ++++++---------
 5 files changed, 52 insertions(+), 140 deletions(-)

diff --git a/modules/video_output/win32/d3d11_quad.c b/modules/video_output/win32/d3d11_quad.c
index f5d2bc285b..ecfbf99b39 100644
--- a/modules/video_output/win32/d3d11_quad.c
+++ b/modules/video_output/win32/d3d11_quad.c
@@ -265,89 +265,14 @@ static void orientationVertexOrder(video_orientation_t orientation, int vertex_o
     }
 }
 
-static void SetupQuadFlat(d3d_vertex_t *dst_data, const RECT *output,
-                          const d3d_quad_t *quad,
+static void SetupQuadFlat(d3d_vertex_t *dst_data, const POINT *output,
                           WORD *triangle_pos, video_orientation_t orientation)
 {
-    unsigned int src_width = quad->i_width;
-    unsigned int src_height = quad->i_height;
+    unsigned int src_width = output->x;
+    unsigned int src_height = output->y;
     float MidX,MidY;
 
-    float top, bottom, left, right;
-    /* find the middle of the visible part of the texture, it will be a 0,0
-     * the rest of the visible area must correspond to -1,1 */
-    switch (orientation)
-    {
-    case ORIENT_ROTATED_90: /* 90° anti clockwise */
-        /* right/top aligned */
-        MidY = (output->left + output->right) / 2.f;
-        MidX = (output->top + output->bottom) / 2.f;
-        top    =  MidY / (MidY - output->top);
-        bottom = -(src_height - MidX) / (MidX - output->top);
-        left   =  (MidX - src_height) / (MidX - output->left);
-        right  =                 MidX / (MidX - (src_width - output->right));
-        break;
-    case ORIENT_ROTATED_180: /* 180° */
-        /* right/top aligned */
-        MidY = (output->top + output->bottom) / 2.f;
-        MidX = (output->left + output->right) / 2.f;
-        top    =  (src_height - MidY) / (output->bottom - MidY);
-        bottom = -MidY / (MidY - output->top);
-        left   = -MidX / (MidX - output->left);
-        right  =  (src_width  - MidX) / (output->right - MidX);
-        break;
-    case ORIENT_ROTATED_270: /* 90° clockwise */
-        /* right/top aligned */
-        MidY = (output->left + output->right) / 2.f;
-        MidX = (output->top + output->bottom) / 2.f;
-        top    =  (src_width  - MidX) / (output->right - MidX);
-        bottom = -MidY / (MidY - output->top);
-        left   = -MidX / (MidX - output->left);
-        right  =  (src_height - MidY) / (output->bottom - MidY);
-        break;
-    case ORIENT_ANTI_TRANSPOSED:
-        MidY = (output->left + output->right) / 2.f;
-        MidX = (output->top + output->bottom) / 2.f;
-        top    =  (src_width  - MidX) / (output->right - MidX);
-        bottom = -MidY / (MidY - output->top);
-        left   = -(src_height - MidY) / (output->bottom - MidY);
-        right  =  MidX / (MidX - output->left);
-        break;
-    case ORIENT_TRANSPOSED:
-        MidY = (output->left + output->right) / 2.f;
-        MidX = (output->top + output->bottom) / 2.f;
-        top    =  (src_width  - MidX) / (output->right - MidX);
-        bottom = -MidY / (MidY - output->top);
-        left   = -MidX / (MidX - output->left);
-        right  =  (src_height - MidY) / (output->bottom - MidY);
-        break;
-    case ORIENT_VFLIPPED:
-        MidY = (output->top + output->bottom) / 2.f;
-        MidX = (output->left + output->right) / 2.f;
-        top    =  (src_height - MidY) / (output->bottom - MidY);
-        bottom = -MidY / (MidY - output->top);
-        left   = -MidX / (MidX - output->left);
-        right  =  (src_width  - MidX) / (output->right - MidX);
-        break;
-    case ORIENT_HFLIPPED:
-        MidY = (output->top + output->bottom) / 2.f;
-        MidX = (output->left + output->right) / 2.f;
-        top    =  MidY / (MidY - output->top);
-        bottom = -(src_height - MidY) / (output->bottom - MidY);
-        left   = -(src_width  - MidX) / (output->right - MidX);
-        right  =  MidX / (MidX - output->left);
-        break;
-    case ORIENT_NORMAL:
-    default:
-        /* left/top aligned */
-        MidY = (output->top + output->bottom) / 2.f;
-        MidX = (output->left + output->right) / 2.f;
-        top    =  MidY / (MidY - output->top);
-        bottom = -(src_height - MidY) / (output->bottom - MidY);
-        left   = -MidX / (MidX - output->left);
-        right  =  (src_width  - MidX) / (output->right - MidX);
-        break;
-    }
+    float top = 1, bottom = -1, left = -1, right = 1;
 
     const float vertices_coords[4][2] = {
         { left,  bottom },
@@ -409,11 +334,8 @@ static void SetupQuadFlat(d3d_vertex_t *dst_data, const RECT *output,
     }
 }
 
-static void SetupQuadSphere(d3d_vertex_t *dst_data, const RECT *output,
-                            const d3d_quad_t *quad, WORD *triangle_pos)
+static void SetupQuadSphere(d3d_vertex_t *dst_data, WORD *triangle_pos)
 {
-    const float scaleX = (float)(RECTWidth(*output))  / quad->i_width;
-    const float scaleY = (float)(RECTHeight(*output)) / quad->i_height;
     for (unsigned lat = 0; lat <= nbLatBands; lat++) {
         float theta = lat * (float) M_PI / nbLatBands;
         float sinTheta, cosTheta;
@@ -435,8 +357,8 @@ static void SetupQuadSphere(d3d_vertex_t *dst_data, const RECT *output,
             dst_data[off1].position.y = SPHERE_RADIUS * y;
             dst_data[off1].position.z = SPHERE_RADIUS * z;
 
-            dst_data[off1].texture.x = scaleX * lon / (float) nbLonBands; // 0(left) to 1(right)
-            dst_data[off1].texture.y = scaleY * lat / (float) nbLatBands; // 0(top) to 1 (bottom)
+            dst_data[off1].texture.x = lon / (float) nbLonBands;
+            dst_data[off1].texture.y = lat / (float) nbLatBands;
         }
     }
 
@@ -459,8 +381,7 @@ static void SetupQuadSphere(d3d_vertex_t *dst_data, const RECT *output,
 }
 
 
-static void SetupQuadCube(d3d_vertex_t *dst_data, const RECT *output,
-                          const d3d_quad_t *quad, WORD *triangle_pos)
+static void SetupQuadCube(d3d_vertex_t *dst_data, WORD *triangle_pos)
 {
 #define CUBEFACE(swap, value) \
     swap(value, -1.f,  1.f), \
@@ -486,11 +407,8 @@ static void SetupQuadCube(d3d_vertex_t *dst_data, const RECT *output,
 #undef Z_FACE
 #undef CUBEFACE
 
-    const float scaleX = (float)(output->right - output->left) / quad->i_width;
-    const float scaleY = (float)(output->bottom - output->top) / quad->i_height;
-
-    const float col[] = {0.f, scaleX / 3, scaleX * 2 / 3, scaleX};
-    const float row[] = {0.f, scaleY / 2, scaleY};
+    const float col[] = {0.f, 1.f / 3, 2.f / 3, 1.f};
+    const float row[] = {0.f, 1.f / 2, 1.f};
 
     const float tex[] = {
         col[1], row[1], // front
@@ -550,7 +468,7 @@ static void SetupQuadCube(d3d_vertex_t *dst_data, const RECT *output,
 
 #undef D3D11_UpdateQuadPosition
 bool D3D11_UpdateQuadPosition( vlc_object_t *o, d3d11_device_t *d3d_dev, d3d_quad_t *quad,
-                                const RECT *output, video_orientation_t orientation )
+                                const POINT *output, video_orientation_t orientation )
 {
     bool result = true;
     HRESULT hr;
@@ -579,13 +497,13 @@ bool D3D11_UpdateQuadPosition( vlc_object_t *o, d3d11_device_t *d3d_dev, d3d_qua
     switch (quad->projection)
     {
     case PROJECTION_MODE_RECTANGULAR:
-        SetupQuadFlat(dst_data, output, quad, mappedResource.pData, orientation);
+        SetupQuadFlat(dst_data, output, mappedResource.pData, orientation);
         break;
     case PROJECTION_MODE_EQUIRECTANGULAR:
-        SetupQuadSphere(dst_data, output, quad, mappedResource.pData);
+        SetupQuadSphere(dst_data, mappedResource.pData);
         break;
     case PROJECTION_MODE_CUBEMAP_LAYOUT_STANDARD:
-        SetupQuadCube(dst_data, output, quad, mappedResource.pData);
+        SetupQuadCube(dst_data, mappedResource.pData);
         break;
     default:
         msg_Warn(o, "Projection mode %d not handled", quad->projection);
@@ -982,6 +900,17 @@ int D3D11_SetupQuad(vlc_object_t *o, d3d11_device_t *d3d_dev, const video_format
     };
 
     PS_COLOR_TRANSFORM colorspace;
+    memcpy(colorspace.SourceCrop, IDENTITY_4X4, sizeof(colorspace.SourceCrop));
+    float scale_w = (float)fmt->i_visible_width  / fmt->i_width;
+    float scale_h = (float)fmt->i_visible_height / fmt->i_height;
+    float left   = scale_w * fmt->i_x_offset;
+    float top    = scale_h * fmt->i_y_offset;
+
+    colorspace.SourceCrop[0*4 + 0] = scale_h;
+    colorspace.SourceCrop[1*4 + 1] = scale_w;
+
+    colorspace.SourceCrop[0*4 + 3] = left / fmt->i_visible_width;
+    colorspace.SourceCrop[1*4 + 3] = top  / fmt->i_visible_height;
 
     memcpy(colorspace.WhitePoint, IDENTITY_4X4, sizeof(colorspace.WhitePoint));
 
diff --git a/modules/video_output/win32/d3d11_quad.h b/modules/video_output/win32/d3d11_quad.h
index db3926befe..662af7fead 100644
--- a/modules/video_output/win32/d3d11_quad.h
+++ b/modules/video_output/win32/d3d11_quad.h
@@ -61,7 +61,7 @@ int D3D11_SetupQuad(vlc_object_t *, d3d11_device_t *, const video_format_t *, d3
 #define D3D11_SetupQuad(a,b,c,d,e)  D3D11_SetupQuad(VLC_OBJECT(a),b,c,d,e)
 
 bool D3D11_UpdateQuadPosition( vlc_object_t *, d3d11_device_t *, d3d_quad_t *,
-                               const RECT *output, video_orientation_t );
+                               const POINT *output, video_orientation_t );
 #define D3D11_UpdateQuadPosition(a,b,c,d,e)  D3D11_UpdateQuadPosition(VLC_OBJECT(a),b,c,d,e)
 
 void D3D11_UpdateViewport(d3d_quad_t *, const RECT *, const d3d_format_t *display);
diff --git a/modules/video_output/win32/d3d11_shaders.c b/modules/video_output/win32/d3d11_shaders.c
index 8f718b933c..e1df979692 100644
--- a/modules/video_output/win32/d3d11_shaders.c
+++ b/modules/video_output/win32/d3d11_shaders.c
@@ -61,6 +61,7 @@ static const char* globPixelShaderDefault = "\
   };\n\
   cbuffer PS_COLOR_TRANSFORM : register(b1)\n\
   {\n\
+    float4x4 SourceCrop;\n\
     float4x4 WhitePoint;\n\
     float4x4 Colorspace;\n\
     float4x4 Primaries;\n\
@@ -117,7 +118,8 @@ static const char* globPixelShaderDefault = "\
       %s;\n\
   }\n\
   \n\
-  inline float4 sampleTexture(SamplerState samplerState, float3 coords) {\n\
+  inline float4 sampleTexture(SamplerState samplerState, float3 raw_coords) {\n\
+      float3 coords = mul(float4(raw_coords.xyz, 1), SourceCrop).xyz;\n\
       float4 sample;\n\
       %s /* sampling routine in sample */\n\
       return sample;\n\
diff --git a/modules/video_output/win32/d3d11_shaders.h b/modules/video_output/win32/d3d11_shaders.h
index 7712c3eff3..f3e47d48cc 100644
--- a/modules/video_output/win32/d3d11_shaders.h
+++ b/modules/video_output/win32/d3d11_shaders.h
@@ -57,6 +57,7 @@ typedef struct {
 } PS_CONSTANT_BUFFER;
 
 typedef struct {
+    FLOAT SourceCrop[4*4];
     FLOAT WhitePoint[4*4];
     FLOAT Colorspace[4*4];
     FLOAT Primaries[4*4];
@@ -94,8 +95,6 @@ typedef struct
     ID3D11PixelShader         *d3dpixelShader[D3D11_MAX_SHADER_VIEW];
     ID3D11SamplerState        *d3dsampState[2];
     D3D11_VIEWPORT            cropViewport[D3D11_MAX_SHADER_VIEW];
-    unsigned int              i_width;
-    unsigned int              i_height;
     video_projection_mode_t   projection;
 
     PS_CONSTANT_BUFFER        shaderConstants;
diff --git a/modules/video_output/win32/direct3d11.c b/modules/video_output/win32/direct3d11.c
index b6881ecc8b..b0f2e5ad0d 100644
--- a/modules/video_output/win32/direct3d11.c
+++ b/modules/video_output/win32/direct3d11.c
@@ -277,11 +277,9 @@ static void UpdateSize(vout_display_t *vd)
 
     D3D11_UpdateViewport( &sys->picQuad, &rect_dst, sys->display.pixelFormat );
 
-    RECT source_rect = {
-        .left   = vd->fmt.i_x_offset,
-        .right  = vd->fmt.i_x_offset + vd->fmt.i_visible_width,
-        .top    = vd->fmt.i_y_offset,
-        .bottom = vd->fmt.i_y_offset + vd->fmt.i_visible_height,
+    POINT source_rect = {
+        .x = vd->source.i_visible_width,
+        .y = vd->source.i_visible_height,
     };
     d3d11_device_lock( sys->d3d_dev );
 
@@ -623,17 +621,9 @@ static void PreparePicture(vout_display_t *vd, picture_t *picture, subpicture_t
                  * display, do it preferrably when creating the texture */
                 assert(p_sys->renderSrc[0]!=NULL);
             }
-            if ( sys->picQuad.i_height != texDesc.Height ||
-                 sys->picQuad.i_width != texDesc.Width )
-            {
-                /* the decoder produced different sizes than the vout, we need to
-                 * adjust the vertex */
-                sys->picQuad.i_height = texDesc.Height;
-                sys->picQuad.i_width = texDesc.Width;
-
-                CommonPlacePicture(vd, &sys->area, &sys->sys);
-                UpdateSize(vd);
-            }
+            // we should receive a source update if they don't match
+            assert( vd->source.i_height == texDesc.Height );
+            assert( vd->source.i_width == texDesc.Width );
         }
     }
 
@@ -818,16 +808,6 @@ static int Direct3D11Open(vout_display_t *vd, video_format_t *fmtp, vlc_video_co
         }
     }
 
-    /* adjust the decoder sizes to have proper padding */
-    sys->picQuad.i_width  = fmt.i_width;
-    sys->picQuad.i_height = fmt.i_height;
-    if ( sys->picQuad.textureFormat->formatTexture != DXGI_FORMAT_R8G8B8A8_UNORM &&
-         sys->picQuad.textureFormat->formatTexture != DXGI_FORMAT_B5G6R5_UNORM )
-    {
-        sys->picQuad.i_width  = (sys->picQuad.i_width  + 0x01) & ~0x01;
-        sys->picQuad.i_height = (sys->picQuad.i_height + 0x01) & ~0x01;
-    }
-
     CommonPlacePicture(vd, &sys->area, &sys->sys);
 
     err = QueryDisplayFormat(vd, &fmt);
@@ -1075,11 +1055,9 @@ static int Direct3D11CreateFormatResources(vout_display_t *vd, const video_forma
         return VLC_EGENERIC;
     }
 
-    RECT source_rect = {
-        .left   = vd->fmt.i_x_offset,
-        .right  = vd->fmt.i_x_offset + vd->fmt.i_visible_width,
-        .top    = vd->fmt.i_y_offset,
-        .bottom = vd->fmt.i_y_offset + vd->fmt.i_visible_height,
+    POINT source_rect = {
+        .x = vd->source.i_visible_width,
+        .y = vd->source.i_visible_height,
     };
     if (!D3D11_UpdateQuadPosition(vd, sys->d3d_dev, &sys->picQuad, &source_rect, vd->source.orientation))
     {
@@ -1106,8 +1084,15 @@ static int Direct3D11CreateFormatResources(vout_display_t *vd, const video_forma
         /* we need a staging texture */
         ID3D11Texture2D *textures[D3D11_MAX_SHADER_VIEW] = {0};
         video_format_t texture_fmt = vd->source;
-        texture_fmt.i_width  = sys->picQuad.i_width;
-        texture_fmt.i_height = sys->picQuad.i_height;
+
+        /* adjust the decoder sizes to have proper padding */
+        if ( sys->picQuad.textureFormat->formatTexture != DXGI_FORMAT_R8G8B8A8_UNORM &&
+             sys->picQuad.textureFormat->formatTexture != DXGI_FORMAT_B5G6R5_UNORM )
+        {
+            texture_fmt.i_width  = (texture_fmt.i_width  + 0x01) & ~0x01;
+            texture_fmt.i_height = (texture_fmt.i_height + 0x01) & ~0x01;
+        }
+
         if (!is_d3d11_opaque(fmt->i_chroma))
             texture_fmt.i_chroma = sys->picQuad.textureFormat->fourcc;
 
@@ -1329,8 +1314,6 @@ static int Direct3D11MapSubpicture(vout_display_t *vd, int *subpicture_region_co
                 free(d3dquad);
                 continue;
             }
-            d3dquad->i_width    = r->fmt.i_width;
-            d3dquad->i_height   = r->fmt.i_height;
 
             d3dquad->textureFormat = sys->regionQuad.textureFormat;
             err = D3D11_AllocateQuad(vd, sys->d3d_dev, PROJECTION_MODE_RECTANGULAR, d3dquad);
@@ -1395,11 +1378,10 @@ static int Direct3D11MapSubpicture(vout_display_t *vd, int *subpicture_region_co
             continue;
         }
 
-        RECT output;
-        output.left   = r->fmt.i_x_offset;
-        output.right  = r->fmt.i_x_offset + r->fmt.i_visible_width;
-        output.top    = r->fmt.i_y_offset;
-        output.bottom = r->fmt.i_y_offset + r->fmt.i_visible_height;
+        POINT output = {
+            .x = r->fmt.i_visible_width,
+            .y = r->fmt.i_visible_height,
+        };
 
         D3D11_UpdateQuadPosition(vd, sys->d3d_dev, quad, &output, ORIENT_NORMAL);
 



More information about the vlc-commits mailing list