1 /*****************************************************************************
2 * direct3d9.c: Windows Direct3D9 video output module
3 *****************************************************************************
4 * Copyright (C) 2006-2014 VLC authors and VideoLAN
6 * Authors: Martell Malone <martellmalone@gmail.com>,
7 * Damien Fouilleul <damienf@videolan.org>,
8 * Sasha Koruga <skoruga@gmail.com>,
9 * Felix Abecassis <felix.abecassis@gmail.com>
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 2.1 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program; if not, write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
26 /*****************************************************************************
29 * This plugin will use YUV surface if supported, using YUV will result in
30 * the best video quality (hardware filtering when rescaling the picture)
31 * and the fastest display as it requires less processing.
33 * If YUV overlay is not supported this plugin will use RGB offscreen video
34 * surfaces that will be blitted onto the primary surface (display) to
35 * effectively display the pictures.
37 *****************************************************************************/
42 #include <vlc_common.h>
43 #include <vlc_plugin.h>
44 #include <vlc_vout_display.h>
47 #include <vlc/libvlc.h>
48 #include <vlc/libvlc_picture.h>
49 #include <vlc/libvlc_media.h>
50 #include <vlc/libvlc_renderer_discoverer.h>
51 #include <vlc/libvlc_media_player.h>
55 #ifdef HAVE_D3DX9EFFECT_H
56 #include <d3dx9effect.h>
58 #include "../../video_chroma/d3d9_fmt.h"
62 #include "builtin_shaders.h"
63 #include "../../video_chroma/copy.h"
67 /*****************************************************************************
69 *****************************************************************************/
70 static int Open(vout_display_t
*, const vout_display_cfg_t
*,
71 video_format_t
*, vlc_video_context
*);
72 static void Close(vout_display_t
*);
74 #define DESKTOP_LONGTEXT N_(\
75 "The desktop mode allows you to display the video on the desktop.")
77 #define HW_BLENDING_TEXT N_("Use hardware blending support")
78 #define HW_BLENDING_LONGTEXT N_(\
79 "Try to use hardware acceleration for subtitle/OSD blending.")
80 #define HW_YUV_TEXT N_("Use hardware YUV->RGB conversions")
81 #define HW_YUV_LONGTEXT N_(\
82 "Try to use hardware acceleration for YUV->RGB conversions. " \
83 "This option doesn't have any effect when using overlays.")
85 #define PIXEL_SHADER_TEXT N_("Pixel Shader")
86 #define PIXEL_SHADER_LONGTEXT N_(\
87 "Choose a pixel shader to apply.")
88 #define PIXEL_SHADER_FILE_TEXT N_("Path to HLSL file")
89 #define PIXEL_SHADER_FILE_LONGTEXT N_("Path to an HLSL file containing a single pixel shader.")
90 /* The latest option in the selection list: used for loading a shader file. */
91 #define SELECTED_SHADER_FILE N_("HLSL File")
93 #define D3D9_HELP N_("Recommended video output for Windows Vista and later versions")
96 set_shortname("Direct3D9")
97 set_description(N_("Direct3D9 video output"))
99 set_category(CAT_VIDEO
)
100 set_subcategory(SUBCAT_VIDEO_VOUT
)
102 add_bool("direct3d9-hw-blending", true, HW_BLENDING_TEXT
, HW_BLENDING_LONGTEXT
, true)
103 add_bool("directx-hw-yuv", true, HW_YUV_TEXT
, HW_YUV_LONGTEXT
, true)
105 add_string("direct3d9-shader", "", PIXEL_SHADER_TEXT
, PIXEL_SHADER_LONGTEXT
, true)
106 add_loadfile("direct3d9-shader-file", NULL
,
107 PIXEL_SHADER_FILE_TEXT
, PIXEL_SHADER_FILE_LONGTEXT
)
109 add_bool("direct3d9-dxvahd", true, DXVAHD_TEXT
, DXVAHD_LONGTEXT
, true)
111 add_shortcut("direct3d9", "direct3d")
112 set_callback_display(Open
, 280)
115 /*****************************************************************************
117 *****************************************************************************/
118 static const vlc_fourcc_t d3d_subpicture_chromas
[] = {
126 D3DFORMAT format
; /* D3D format */
127 vlc_fourcc_t fourcc
; /* VLC fourcc */
133 struct vout_display_sys_t
135 vout_display_sys_win32_t sys
; /* only use if sys.event is not NULL */
136 display_win32_area_t area
;
138 bool allow_hw_yuv
; /* Should we use hardware YUV->RGB conversions */
141 d3d9_decoder_device_t
*d3d9_device
;
142 vlc_decoder_device
*dec_device
; // if d3d9_decoder comes from a decoder device
144 D3DFORMAT BufferFormat
;
146 HINSTANCE hxdll
; /* handle of the opened d3d9x dll */
147 IDirect3DPixelShader9
* d3dx_shader
;
150 IDirect3DTexture9
*sceneTexture
;
151 IDirect3DVertexBuffer9
*sceneVertexBuffer
;
152 D3DFORMAT d3dregion_format
; /* Backbuffer output format */
153 size_t d3dregion_count
; /* for subpictures */
154 struct d3d_region_t
*d3dregion
; /* for subpictures */
156 const d3d9_format_t
*sw_texture_fmt
; /* Rendering texture(s) format */
157 IDirect3DSurface9
*dx_render
;
164 /* outside rendering */
165 void *outside_opaque
;
166 libvlc_video_update_output_cb updateOutputCb
;
167 libvlc_video_swap_cb swapCb
;
168 libvlc_video_makeCurrent_cb startEndRenderingCb
;
170 /* range converter */
173 IDXVAHD_VideoProcessor
*proc
;
180 FLOAT x
,y
,z
; // vertex untransformed position
181 FLOAT rhw
; // eye distance
182 D3DCOLOR diffuse
; // diffuse color
183 FLOAT tu
, tv
; // texture relative coordinates
185 #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
187 typedef struct d3d_region_t
{
188 D3DFORMAT format
; // for subpictures
189 unsigned width
; // for pixel shaders
190 unsigned height
; // for pixel shaders
191 CUSTOMVERTEX vertex
[4];
192 IDirect3DTexture9
*texture
;
196 static HINSTANCE
Direct3D9LoadShaderLibrary(void)
198 HINSTANCE instance
= NULL
;
199 for (int i
= 43; i
> 23; --i
) {
201 _snwprintf(filename
, ARRAY_SIZE(filename
), TEXT("D3dx9_%d.dll"), i
);
202 instance
= LoadLibrary(filename
);
210 * Compute the vertex ordering needed to rotate the video. Without
211 * rotation, the vertices of the rectangle are defined in a clockwise
212 * order. This function computes a remapping of the coordinates to
213 * implement the rotation, given fixed texture coordinates.
214 * The unrotated order is the following:
218 * For a 180 degrees rotation it should like this:
222 * Vertex 0 should be assigned coordinates at index 2 from the
223 * unrotated order and so on, thus yielding order: 2 3 0 1.
225 static void orientationVertexOrder(video_orientation_t orientation
, int vertex_order
[static 4])
227 switch (orientation
) {
228 case ORIENT_ROTATED_90
: /* ORIENT_RIGHT_TOP */
234 case ORIENT_ROTATED_270
: /* ORIENT_LEFT_BOTTOM */
240 case ORIENT_ROTATED_180
: /* ORIENT_BOTTOM_RIGHT */
246 case ORIENT_TRANSPOSED
: /* ORIENT_LEFT_TOP */
252 case ORIENT_HFLIPPED
: /* ORIENT_TOP_RIGHT */
258 case ORIENT_VFLIPPED
: /* ORIENT_BOTTOM_LEFT */
264 case ORIENT_ANTI_TRANSPOSED
: /* ORIENT_RIGHT_BOTTOM */
279 static void Direct3D9SetupVertices(CUSTOMVERTEX
*vertices
,
280 const RECT
*full_texture
, const RECT
*visible_texture
,
281 const RECT
*rect_in_display
,
283 video_orientation_t orientation
)
285 /* Vertices of the dst rectangle in the unrotated (clockwise) order. */
286 const int vertices_coords
[4][2] = {
287 { rect_in_display
->left
, rect_in_display
->top
},
288 { rect_in_display
->right
, rect_in_display
->top
},
289 { rect_in_display
->right
, rect_in_display
->bottom
},
290 { rect_in_display
->left
, rect_in_display
->bottom
},
293 /* Compute index remapping necessary to implement the rotation. */
295 orientationVertexOrder(orientation
, vertex_order
);
297 for (int i
= 0; i
< 4; ++i
) {
298 vertices
[i
].x
= vertices_coords
[vertex_order
[i
]][0];
299 vertices
[i
].y
= vertices_coords
[vertex_order
[i
]][1];
302 float texture_right
= (float)visible_texture
->right
/ (float)full_texture
->right
;
303 float texture_left
= (float)visible_texture
->left
/ (float)full_texture
->right
;
304 float texture_top
= (float)visible_texture
->top
/ (float)full_texture
->bottom
;
305 float texture_bottom
= (float)visible_texture
->bottom
/ (float)full_texture
->bottom
;
307 vertices
[0].tu
= texture_left
;
308 vertices
[0].tv
= texture_top
;
310 vertices
[1].tu
= texture_right
;
311 vertices
[1].tv
= texture_top
;
313 vertices
[2].tu
= texture_right
;
314 vertices
[2].tv
= texture_bottom
;
316 vertices
[3].tu
= texture_left
;
317 vertices
[3].tv
= texture_bottom
;
319 for (int i
= 0; i
< 4; i
++) {
320 /* -0.5f is a "feature" of DirectX and it seems to apply to Direct3d also */
321 /* http://www.sjbrown.co.uk/2003/05/01/fix-directx-rasterisation/ */
322 vertices
[i
].x
-= 0.5;
323 vertices
[i
].y
-= 0.5;
325 vertices
[i
].z
= 0.0f
;
326 vertices
[i
].rhw
= 1.0f
;
327 vertices
[i
].diffuse
= D3DCOLOR_ARGB(alpha
, 255, 255, 255);
332 * It copies picture surface into a texture and setup the associated d3d_region_t.
334 static int Direct3D9ImportPicture(vout_display_t
*vd
,
335 d3d_region_t
*region
,
336 IDirect3DSurface9
*source
)
338 vout_display_sys_t
*sys
= vd
->sys
;
342 msg_Dbg(vd
, "no surface to render?");
346 /* retrieve texture top-level surface */
347 IDirect3DSurface9
*destination
;
348 hr
= IDirect3DTexture9_GetSurfaceLevel(sys
->sceneTexture
, 0, &destination
);
350 msg_Dbg(vd
, "Failed IDirect3DTexture9_GetSurfaceLevel: 0x%lX", hr
);
354 if (sys
->processor
.proc
)
356 DXVAHD_STREAM_DATA inputStream
= { 0 };
357 inputStream
.Enable
= TRUE
;
358 inputStream
.pInputSurface
= source
;
359 hr
= IDXVAHD_VideoProcessor_VideoProcessBltHD( sys
->processor
.proc
, destination
, 0, 1, &inputStream
);
361 D3DSURFACE_DESC srcDesc
, dstDesc
;
362 IDirect3DSurface9_GetDesc(source
, &srcDesc
);
363 IDirect3DSurface9_GetDesc(destination
, &dstDesc
);
365 msg_Dbg(vd
, "Failed VideoProcessBltHD src:%4.4s (%d) dst:%4.4s (%d) (hr=0x%lX)",
366 (const char*)&srcDesc
.Format
, srcDesc
.Format
,
367 (const char*)&dstDesc
.Format
, dstDesc
.Format
, hr
);
372 /* Copy picture surface into texture surface
373 * color space conversion happen here */
374 RECT source_visible_rect
= {
375 .left
= vd
->source
->i_x_offset
,
376 .right
= vd
->source
->i_x_offset
+ vd
->source
->i_visible_width
,
377 .top
= vd
->source
->i_y_offset
,
378 .bottom
= vd
->source
->i_y_offset
+ vd
->source
->i_visible_height
,
380 RECT texture_visible_rect
= {
382 .right
= vd
->source
->i_visible_width
,
384 .bottom
= vd
->source
->i_visible_height
,
386 // On nVidia & AMD, StretchRect will fail if the visible size isn't even.
387 // When copying the entire buffer, the margin end up being blended in the actual picture
388 // on nVidia (regardless of even/odd dimensions)
389 if (texture_visible_rect
.right
& 1)
391 texture_visible_rect
.right
++;
392 source_visible_rect
.right
++;
394 if (texture_visible_rect
.bottom
& 1)
396 texture_visible_rect
.bottom
++;
397 source_visible_rect
.bottom
++;
400 hr
= IDirect3DDevice9_StretchRect(sys
->d3d9_device
->d3ddev
.dev
, source
, &source_visible_rect
,
401 destination
, &texture_visible_rect
,
404 msg_Dbg(vd
, "Failed StretchRect: source 0x%p. (hr=0x%lX)",
408 IDirect3DSurface9_Release(destination
);
413 region
->texture
= sys
->sceneTexture
;
414 RECT texture_rect
= {
416 .right
= vd
->source
->i_width
,
418 .bottom
= vd
->source
->i_height
,
420 RECT rect_in_display
= {
421 .left
= sys
->area
.place
.x
,
422 .right
= sys
->area
.place
.x
+ sys
->area
.place
.width
,
423 .top
= sys
->area
.place
.y
,
424 .bottom
= sys
->area
.place
.y
+ sys
->area
.place
.height
,
426 RECT texture_visible_rect
= {
427 .left
= vd
->source
->i_x_offset
,
428 .right
= vd
->source
->i_x_offset
+ vd
->source
->i_visible_width
,
429 .top
= vd
->source
->i_y_offset
,
430 .bottom
= vd
->source
->i_y_offset
+ vd
->source
->i_visible_height
,
432 Direct3D9SetupVertices(region
->vertex
, &texture_rect
, &texture_visible_rect
,
433 &rect_in_display
, 255, vd
->source
->orientation
);
437 static void Direct3D9DeleteRegions(size_t count
, d3d_region_t
*region
)
439 for (size_t i
= 0; i
< count
; i
++) {
440 if (region
[i
].texture
)
441 IDirect3DTexture9_Release(region
[i
].texture
);
447 * It releases the scene resources.
449 static void Direct3D9DestroyScene(vout_display_t
*vd
)
451 vout_display_sys_t
*sys
= vd
->sys
;
453 Direct3D9DeleteRegions(sys
->d3dregion_count
, sys
->d3dregion
);
454 sys
->d3dregion_count
= 0;
455 sys
->d3dregion
= NULL
;
457 if (sys
->sceneVertexBuffer
)
459 IDirect3DVertexBuffer9_Release(sys
->sceneVertexBuffer
);
460 sys
->sceneVertexBuffer
= NULL
;
463 if (sys
->sceneTexture
)
465 IDirect3DTexture9_Release(sys
->sceneTexture
);
466 sys
->sceneTexture
= NULL
;
469 msg_Dbg(vd
, "Direct3D9 scene released successfully");
472 static void Direct3D9DestroyShaders(vout_display_t
*vd
)
474 vout_display_sys_t
*sys
= vd
->sys
;
476 if (sys
->d3dx_shader
)
478 IDirect3DPixelShader9_Release(sys
->d3dx_shader
);
479 sys
->d3dx_shader
= NULL
;
484 * It destroys the picture and scene resources.
486 static void Direct3D9DestroyResources(vout_display_t
*vd
)
488 Direct3D9DestroyScene(vd
);
489 if (vd
->sys
->dx_render
)
491 IDirect3DSurface9_Release(vd
->sys
->dx_render
);
492 vd
->sys
->dx_render
= NULL
;
494 Direct3D9DestroyShaders(vd
);
497 static int UpdateOutput(vout_display_t
*vd
, const video_format_t
*fmt
,
498 libvlc_video_output_cfg_t
*out
)
500 vout_display_sys_t
*sys
= vd
->sys
;
501 libvlc_video_render_cfg_t cfg
;
502 cfg
.width
= vd
->cfg
->display
.width
;
503 cfg
.height
= vd
->cfg
->display
.height
;
505 switch (fmt
->i_chroma
)
507 case VLC_CODEC_D3D9_OPAQUE
:
510 case VLC_CODEC_D3D9_OPAQUE_10B
:
515 const vlc_chroma_description_t
*p_format
= vlc_fourcc_GetChromaDescription(fmt
->i_chroma
);
516 if (p_format
== NULL
)
522 cfg
.bitdepth
= p_format
->pixel_bits
== 0 ? 8 : p_format
->pixel_bits
/
523 (p_format
->plane_count
==1 ? p_format
->pixel_size
: 1);
529 cfg
.full_range
= fmt
->color_range
== COLOR_RANGE_FULL
;
530 cfg
.primaries
= (libvlc_video_color_primaries_t
) fmt
->primaries
;
531 cfg
.colorspace
= (libvlc_video_color_space_t
) fmt
->space
;
532 cfg
.transfer
= (libvlc_video_transfer_func_t
) fmt
->transfer
;
534 cfg
.device
= sys
->d3d9_device
->d3ddev
.dev
;
536 libvlc_video_output_cfg_t local_out
;
539 if (!sys
->updateOutputCb( sys
->outside_opaque
, &cfg
, out
))
541 msg_Err(vd
, "Failed to set the external render size");
549 * It allocates and initializes the resources needed to render the scene.
551 static int Direct3D9CreateScene(vout_display_t
*vd
, const video_format_t
*fmt
)
553 vout_display_sys_t
*sys
= vd
->sys
;
554 IDirect3DDevice9
*d3ddev
= sys
->d3d9_device
->d3ddev
.dev
;
557 UINT width
= fmt
->i_visible_width
;
558 UINT height
= fmt
->i_visible_height
;
559 // On nVidia & AMD, StretchRect will fail if the visible size isn't even.
560 // When copying the entire buffer, the margin end up being blended in the actual picture
561 // on nVidia (regardless of even/odd dimensions)
562 if (height
& 1) height
++;
563 if (width
& 1) width
++;
566 * Create a texture for use when rendering a scene
567 * for performance reason, texture format is identical to backbuffer
568 * which would usually be a RGB format
570 hr
= IDirect3DDevice9_CreateTexture(d3ddev
,
574 D3DUSAGE_RENDERTARGET
,
580 msg_Err(vd
, "Failed to create texture. (hr=0x%lX)", hr
);
585 msg_Dbg(vd
, "Direct3D created texture: %ix%i",
586 fmt
->i_width
, fmt
->i_height
);
590 ** Create a vertex buffer for use when rendering scene
592 hr
= IDirect3DDevice9_CreateVertexBuffer(d3ddev
,
593 sizeof(CUSTOMVERTEX
)*4,
594 D3DUSAGE_DYNAMIC
|D3DUSAGE_WRITEONLY
,
597 &sys
->sceneVertexBuffer
,
600 msg_Err(vd
, "Failed to create vertex buffer. (hr=0x%lX)", hr
);
601 IDirect3DTexture9_Release(sys
->sceneTexture
);
602 sys
->sceneTexture
= NULL
;
606 // we use FVF instead of vertex shader
607 hr
= IDirect3DDevice9_SetFVF(d3ddev
, D3DFVF_CUSTOMVERTEX
);
609 msg_Dbg(vd
, "Failed SetFVF: 0x%lX", hr
);
614 sys
->d3dregion_count
= 0;
615 sys
->d3dregion
= NULL
;
617 sys
->clear_scene
= true;
619 // Texture coordinates outside the range [0.0, 1.0] are set
620 // to the texture color at 0.0 or 1.0, respectively.
621 IDirect3DDevice9_SetSamplerState(d3ddev
, 0, D3DSAMP_ADDRESSU
, D3DTADDRESS_CLAMP
);
622 IDirect3DDevice9_SetSamplerState(d3ddev
, 0, D3DSAMP_ADDRESSV
, D3DTADDRESS_CLAMP
);
624 // Set linear filtering quality
625 if (sys
->d3d9_device
->d3ddev
.caps
.TextureFilterCaps
& D3DPTFILTERCAPS_MINFLINEAR
) {
626 //msg_Dbg(vd, "Using D3DTEXF_LINEAR for minification");
627 IDirect3DDevice9_SetSamplerState(d3ddev
, 0, D3DSAMP_MINFILTER
, D3DTEXF_LINEAR
);
629 //msg_Dbg(vd, "Using D3DTEXF_POINT for minification");
630 IDirect3DDevice9_SetSamplerState(d3ddev
, 0, D3DSAMP_MINFILTER
, D3DTEXF_POINT
);
632 if (sys
->d3d9_device
->d3ddev
.caps
.TextureFilterCaps
& D3DPTFILTERCAPS_MAGFLINEAR
) {
633 //msg_Dbg(vd, "Using D3DTEXF_LINEAR for magnification");
634 IDirect3DDevice9_SetSamplerState(d3ddev
, 0, D3DSAMP_MAGFILTER
, D3DTEXF_LINEAR
);
636 //msg_Dbg(vd, "Using D3DTEXF_POINT for magnification");
637 IDirect3DDevice9_SetSamplerState(d3ddev
, 0, D3DSAMP_MAGFILTER
, D3DTEXF_POINT
);
640 // set maximum ambient light
641 IDirect3DDevice9_SetRenderState(d3ddev
, D3DRS_AMBIENT
, D3DCOLOR_XRGB(255,255,255));
644 IDirect3DDevice9_SetRenderState(d3ddev
, D3DRS_CULLMODE
, D3DCULL_NONE
);
646 // Turn off the zbuffer
647 IDirect3DDevice9_SetRenderState(d3ddev
, D3DRS_ZENABLE
, D3DZB_FALSE
);
650 IDirect3DDevice9_SetRenderState(d3ddev
, D3DRS_LIGHTING
, FALSE
);
653 IDirect3DDevice9_SetRenderState(d3ddev
, D3DRS_DITHERENABLE
, TRUE
);
656 IDirect3DDevice9_SetRenderState(d3ddev
, D3DRS_STENCILENABLE
, FALSE
);
659 IDirect3DDevice9_SetRenderState(d3ddev
, D3DRS_ALPHABLENDENABLE
, FALSE
);
660 IDirect3DDevice9_SetRenderState(d3ddev
, D3DRS_SRCBLEND
,D3DBLEND_SRCALPHA
);
661 IDirect3DDevice9_SetRenderState(d3ddev
, D3DRS_DESTBLEND
,D3DBLEND_INVSRCALPHA
);
663 if (sys
->d3d9_device
->d3ddev
.caps
.AlphaCmpCaps
& D3DPCMPCAPS_GREATER
) {
664 IDirect3DDevice9_SetRenderState(d3ddev
, D3DRS_ALPHATESTENABLE
,TRUE
);
665 IDirect3DDevice9_SetRenderState(d3ddev
, D3DRS_ALPHAREF
, 0x00);
666 IDirect3DDevice9_SetRenderState(d3ddev
, D3DRS_ALPHAFUNC
,D3DCMP_GREATER
);
669 // Set texture states
670 IDirect3DDevice9_SetTextureStageState(d3ddev
, 0, D3DTSS_COLOROP
,D3DTOP_SELECTARG1
);
671 IDirect3DDevice9_SetTextureStageState(d3ddev
, 0, D3DTSS_COLORARG1
,D3DTA_TEXTURE
);
673 IDirect3DDevice9_SetTextureStageState(d3ddev
, 0, D3DTSS_ALPHAOP
, D3DTOP_MODULATE
);
674 IDirect3DDevice9_SetTextureStageState(d3ddev
, 0, D3DTSS_ALPHAARG1
,D3DTA_TEXTURE
);
675 IDirect3DDevice9_SetTextureStageState(d3ddev
, 0, D3DTSS_ALPHAARG2
,D3DTA_DIFFUSE
);
677 msg_Dbg(vd
, "Direct3D9 scene created successfully");
682 #ifdef HAVE_D3DX9EFFECT_H
683 static int Direct3D9CompileShader(vout_display_t
*vd
, const char *shader_source
, size_t source_length
)
685 vout_display_sys_t
*sys
= vd
->sys
;
687 HRESULT (WINAPI
* OurD3DXCompileShader
)(
690 const D3DXMACRO
*pDefines
,
691 LPD3DXINCLUDE pInclude
,
692 LPCSTR pFunctionName
,
695 LPD3DXBUFFER
*ppShader
,
696 LPD3DXBUFFER
*ppErrorMsgs
,
697 LPD3DXCONSTANTTABLE
*ppConstantTable
);
699 OurD3DXCompileShader
= (void*)GetProcAddress(sys
->hxdll
, "D3DXCompileShader");
700 if (!OurD3DXCompileShader
) {
701 msg_Warn(vd
, "Cannot locate reference to D3DXCompileShader; pixel shading will be disabled");
705 LPD3DXBUFFER error_msgs
= NULL
;
706 LPD3DXBUFFER compiled_shader
= NULL
;
708 DWORD shader_flags
= 0;
709 HRESULT hr
= OurD3DXCompileShader(shader_source
, source_length
, NULL
, NULL
,
710 "main", "ps_3_0", shader_flags
, &compiled_shader
, &error_msgs
, NULL
);
713 msg_Warn(vd
, "D3DXCompileShader Error (hr=0x%lX)", hr
);
715 msg_Warn(vd
, "HLSL Compilation Error: %s", (char*)ID3DXBuffer_GetBufferPointer(error_msgs
));
716 ID3DXBuffer_Release(error_msgs
);
721 hr
= IDirect3DDevice9_CreatePixelShader(sys
->d3d9_device
->d3ddev
.dev
,
722 ID3DXBuffer_GetBufferPointer(compiled_shader
),
726 ID3DXBuffer_Release(compiled_shader
);
728 ID3DXBuffer_Release(error_msgs
);
731 msg_Warn(vd
, "IDirect3DDevice9_CreatePixelShader error (hr=0x%lX)", hr
);
737 # define Direct3D9CompileShader(a,b,c) VLC_EGENERIC
740 #define MAX_SHADER_FILE_SIZE (1024*1024)
742 static int Direct3D9CreateShaders(vout_display_t
*vd
)
744 vout_display_sys_t
*sys
= vd
->sys
;
749 /* Find which shader was selected in the list. */
750 char *selected_shader
= var_InheritString(vd
, "direct3d9-shader");
751 if (!selected_shader
)
752 return VLC_SUCCESS
; /* Nothing to do */
754 const char *shader_source_builtin
= NULL
;
755 char *shader_source_file
= NULL
;
758 for (size_t i
= 0; i
< BUILTIN_SHADERS_COUNT
; ++i
) {
759 if (!strcmp(selected_shader
, builtin_shaders
[i
].name
)) {
760 shader_source_builtin
= builtin_shaders
[i
].code
;
765 if (shader_source_builtin
) {
766 /* A builtin shader was selected. */
767 int err
= Direct3D9CompileShader(vd
, shader_source_builtin
, strlen(shader_source_builtin
));
771 if (strcmp(selected_shader
, SELECTED_SHADER_FILE
))
772 goto error
; /* Unrecognized entry in the list. */
773 /* The source code of the shader needs to be read from a file. */
774 char *filepath
= var_InheritString(vd
, "direct3d9-shader-file");
775 if (!filepath
|| !*filepath
)
780 /* Open file, find its size with fseek/ftell and read its content in a buffer. */
781 fs
= vlc_fopen(filepath
, "rb");
784 int ret
= fseek(fs
, 0, SEEK_END
);
787 long length
= ftell(fs
);
788 if (length
== -1 || length
>= MAX_SHADER_FILE_SIZE
)
791 shader_source_file
= vlc_alloc(length
, sizeof(*shader_source_file
));
792 if (!shader_source_file
)
794 ret
= fread(shader_source_file
, length
, 1, fs
);
797 ret
= Direct3D9CompileShader(vd
, shader_source_file
, length
);
802 free(selected_shader
);
803 free(shader_source_file
);
809 Direct3D9DestroyShaders(vd
);
810 free(selected_shader
);
811 free(shader_source_file
);
818 * It creates the picture and scene resources.
820 static int Direct3D9CreateResources(vout_display_t
*vd
, const video_format_t
*fmt
)
822 vout_display_sys_t
*sys
= vd
->sys
;
824 if (Direct3D9CreateScene(vd
, fmt
)) {
825 msg_Err(vd
, "Direct3D scene initialization failed !");
828 if (Direct3D9CreateShaders(vd
)) {
829 /* Failing to initialize shaders is not fatal. */
830 msg_Warn(vd
, "Direct3D shaders initialization failed !");
833 sys
->d3dregion_format
= D3DFMT_UNKNOWN
;
834 for (int i
= 0; i
< 2; i
++) {
835 D3DFORMAT dfmt
= i
== 0 ? D3DFMT_A8B8G8R8
: D3DFMT_A8R8G8B8
;
836 if (SUCCEEDED(IDirect3D9_CheckDeviceFormat(sys
->d3d9_device
->hd3d
.obj
,
837 sys
->d3d9_device
->d3ddev
.adapterId
,
843 sys
->d3dregion_format
= dfmt
;
848 if( !is_d3d9_opaque( fmt
->i_chroma
) )
850 HRESULT hr
= IDirect3DDevice9_CreateOffscreenPlainSurface(sys
->d3d9_device
->d3ddev
.dev
,
853 sys
->sw_texture_fmt
->format
,
858 msg_Err(vd
, "Failed to allocate offscreen surface (hr=0x%lX)", hr
);
867 * It reset the Direct3D9 device and its resources.
869 static int Direct3D9Reset(vout_display_t
*vd
, const video_format_t
*fmtp
)
871 vout_display_sys_t
*sys
= vd
->sys
;
873 int res
= D3D9_ResetDevice( VLC_OBJECT(vd
), sys
->d3d9_device
);
874 if (res
!= VLC_SUCCESS
)
877 /* release all D3D objects */
878 Direct3D9DestroyResources(vd
);
880 if (UpdateOutput(vd
, fmtp
, NULL
) != VLC_SUCCESS
)
884 if (Direct3D9CreateResources(vd
, fmtp
)) {
885 msg_Dbg(vd
, "Direct3D9CreateResources failed !");
891 static void Direct3D9ImportSubpicture(vout_display_t
*vd
,
892 size_t *count_ptr
, d3d_region_t
**region
,
893 subpicture_t
*subpicture
)
895 vout_display_sys_t
*sys
= vd
->sys
;
898 for (subpicture_region_t
*r
= subpicture
->p_region
; r
; r
= r
->p_next
)
902 *region
= calloc(count
, sizeof(**region
));
903 if (*region
== NULL
) {
909 for (subpicture_region_t
*r
= subpicture
->p_region
; r
; r
= r
->p_next
, i
++) {
910 d3d_region_t
*d3dr
= &(*region
)[i
];
913 d3dr
->texture
= NULL
;
914 for (size_t j
= 0; j
< sys
->d3dregion_count
; j
++) {
915 d3d_region_t
*cache
= &sys
->d3dregion
[j
];
916 if (cache
->texture
&&
917 cache
->format
== sys
->d3dregion_format
&&
918 cache
->width
== r
->fmt
.i_width
&&
919 cache
->height
== r
->fmt
.i_height
) {
921 memset(cache
, 0, sizeof(*cache
));
925 if (!d3dr
->texture
) {
926 d3dr
->format
= sys
->d3dregion_format
;
927 d3dr
->width
= r
->fmt
.i_width
;
928 d3dr
->height
= r
->fmt
.i_height
;
929 hr
= IDirect3DDevice9_CreateTexture(sys
->d3d9_device
->d3ddev
.dev
,
930 d3dr
->width
, d3dr
->height
,
938 d3dr
->texture
= NULL
;
939 msg_Err(vd
, "Failed to create %dx%d texture for OSD (hr=0x%lX)",
940 d3dr
->width
, d3dr
->height
, hr
);
944 msg_Dbg(vd
, "Created %dx%d texture for OSD",
945 r
->fmt
.i_width
, r
->fmt
.i_height
);
950 hr
= IDirect3DTexture9_LockRect(d3dr
->texture
, 0, &lock
, NULL
, 0);
952 uint8_t *dst_data
= lock
.pBits
;
953 int dst_pitch
= lock
.Pitch
;
954 uint8_t *src_data
= r
->p_picture
->p
->p_pixels
;
955 int src_pitch
= r
->p_picture
->p
->i_pitch
;
957 if (d3dr
->format
== D3DFMT_A8B8G8R8
) {
958 if (dst_pitch
== r
->p_picture
->p
->i_pitch
) {
959 memcpy(dst_data
, src_data
, r
->fmt
.i_height
* dst_pitch
);
961 int copy_pitch
= __MIN(dst_pitch
, r
->p_picture
->p
->i_pitch
);
962 for (unsigned y
= 0; y
< r
->fmt
.i_height
; y
++) {
963 memcpy(&dst_data
[y
* dst_pitch
], &src_data
[y
* src_pitch
], copy_pitch
);
967 int copy_pitch
= __MIN(dst_pitch
, r
->p_picture
->p
->i_pitch
);
968 for (unsigned y
= 0; y
< r
->fmt
.i_height
; y
++) {
969 for (int x
= 0; x
< copy_pitch
; x
+= 4) {
970 dst_data
[y
* dst_pitch
+ x
+ 0] = src_data
[y
* src_pitch
+ x
+ 2];
971 dst_data
[y
* dst_pitch
+ x
+ 1] = src_data
[y
* src_pitch
+ x
+ 1];
972 dst_data
[y
* dst_pitch
+ x
+ 2] = src_data
[y
* src_pitch
+ x
+ 0];
973 dst_data
[y
* dst_pitch
+ x
+ 3] = src_data
[y
* src_pitch
+ x
+ 3];
977 hr
= IDirect3DTexture9_UnlockRect(d3dr
->texture
, 0);
979 msg_Err(vd
, "Failed to unlock the texture");
981 msg_Err(vd
, "Failed to lock the texture");
984 /* Map the subpicture to sys->sys.sys.place */
985 const float scale_w
= (float)(sys
->area
.place
.width
) / subpicture
->i_original_picture_width
;
986 const float scale_h
= (float)(sys
->area
.place
.height
) / subpicture
->i_original_picture_height
;
988 RECT rect_in_display
;
989 rect_in_display
.left
= scale_w
* r
->i_x
,
990 rect_in_display
.right
= rect_in_display
.left
+ scale_w
* r
->fmt
.i_visible_width
,
991 rect_in_display
.top
= scale_h
* r
->i_y
,
992 rect_in_display
.bottom
= rect_in_display
.top
+ scale_h
* r
->fmt
.i_visible_height
;
994 rect_in_display
.left
+= sys
->area
.place
.x
;
995 rect_in_display
.right
+= sys
->area
.place
.x
;
996 rect_in_display
.top
+= sys
->area
.place
.y
;
997 rect_in_display
.bottom
+= sys
->area
.place
.y
;
1000 texture_rect
.left
= 0;
1001 texture_rect
.right
= r
->fmt
.i_width
;
1002 texture_rect
.top
= 0;
1003 texture_rect
.bottom
= r
->fmt
.i_height
;
1005 RECT texture_visible_rect
;
1006 texture_visible_rect
.left
= r
->fmt
.i_x_offset
;
1007 texture_visible_rect
.right
= r
->fmt
.i_x_offset
+ r
->fmt
.i_visible_width
;
1008 texture_visible_rect
.top
= r
->fmt
.i_y_offset
;
1009 texture_visible_rect
.bottom
= r
->fmt
.i_y_offset
+ r
->fmt
.i_visible_height
;
1011 Direct3D9SetupVertices(d3dr
->vertex
, &texture_rect
, &texture_visible_rect
,
1012 &rect_in_display
, subpicture
->i_alpha
* r
->i_alpha
/ 255, ORIENT_NORMAL
);
1016 static int Direct3D9RenderRegion(vout_display_t
*vd
,
1017 const d3d_region_t
*region
,
1018 bool use_pixel_shader
)
1020 vout_display_sys_t
*sys
= vd
->sys
;
1022 IDirect3DDevice9
*d3ddev
= vd
->sys
->d3d9_device
->d3ddev
.dev
;
1026 /* Import vertices */
1028 hr
= IDirect3DVertexBuffer9_Lock(sys
->sceneVertexBuffer
, 0, 0, &vertex
, D3DLOCK_DISCARD
);
1030 msg_Dbg(vd
, "Failed IDirect3DVertexBuffer9_Lock: 0x%lX", hr
);
1033 memcpy(vertex
, region
->vertex
, sizeof(region
->vertex
));
1034 hr
= IDirect3DVertexBuffer9_Unlock(sys
->sceneVertexBuffer
);
1036 msg_Dbg(vd
, "Failed IDirect3DVertexBuffer9_Unlock: 0x%lX", hr
);
1040 // Render the vertex buffer contents
1041 hr
= IDirect3DDevice9_SetStreamSource(d3ddev
, 0, sys
->sceneVertexBuffer
, 0, sizeof(CUSTOMVERTEX
));
1043 msg_Dbg(vd
, "Failed SetStreamSource: 0x%lX", hr
);
1047 // Setup our texture. Using textures introduces the texture stage states,
1048 // which govern how textures get blended together (in the case of multiple
1049 // textures) and lighting information. In this case, we are modulating
1050 // (blending) our texture with the diffuse color of the vertices.
1051 hr
= IDirect3DDevice9_SetTexture(d3ddev
, 0, (IDirect3DBaseTexture9
*)region
->texture
);
1053 msg_Dbg(vd
, "Failed SetTexture: 0x%lX", hr
);
1057 if (sys
->d3dx_shader
) {
1058 if (use_pixel_shader
)
1060 hr
= IDirect3DDevice9_SetPixelShader(d3ddev
, sys
->d3dx_shader
);
1061 float shader_data
[4] = { region
->width
, region
->height
, 0, 0 };
1062 hr
= IDirect3DDevice9_SetPixelShaderConstantF(d3ddev
, 0, shader_data
, 1);
1064 msg_Dbg(vd
, "Failed SetPixelShaderConstantF: 0x%lX", hr
);
1068 else /* Disable any existing pixel shader. */
1069 hr
= IDirect3DDevice9_SetPixelShader(d3ddev
, NULL
);
1071 msg_Dbg(vd
, "Failed SetPixelShader: 0x%lX", hr
);
1077 hr
= IDirect3DDevice9_DrawPrimitive(d3ddev
, D3DPT_TRIANGLEFAN
, 0, 2);
1079 msg_Dbg(vd
, "Failed DrawPrimitive: 0x%lX", hr
);
1086 * It renders the scene.
1088 * This function is intented for higher end 3D cards, with pixel shader support
1089 * and at least 64 MiB of video RAM.
1091 static void Direct3D9RenderScene(vout_display_t
*vd
,
1092 d3d_region_t
*picture
,
1093 size_t subpicture_count
,
1094 d3d_region_t
*subpicture
)
1096 vout_display_sys_t
*sys
= vd
->sys
;
1097 IDirect3DDevice9
*d3ddev
= sys
->d3d9_device
->d3ddev
.dev
;
1100 if (sys
->startEndRenderingCb
&& !sys
->startEndRenderingCb( sys
->outside_opaque
, true ))
1103 if (sys
->clear_scene
) {
1104 /* Clear the backbuffer and the zbuffer */
1105 hr
= IDirect3DDevice9_Clear(d3ddev
, 0, NULL
, D3DCLEAR_TARGET
,
1106 D3DCOLOR_XRGB(0, 0, 0), 1.0f
, 0);
1108 msg_Dbg(vd
, "Failed Clear: 0x%lX", hr
);
1111 sys
->clear_scene
= false;
1114 hr
= IDirect3DDevice9_BeginScene(d3ddev
);
1116 msg_Dbg(vd
, "Failed BeginScene: 0x%lX", hr
);
1120 Direct3D9RenderRegion(vd
, picture
, true);
1122 if (subpicture_count
)
1124 IDirect3DDevice9_SetRenderState(d3ddev
, D3DRS_ALPHABLENDENABLE
, TRUE
);
1125 for (size_t i
= 0; i
< subpicture_count
; i
++) {
1126 d3d_region_t
*r
= &subpicture
[i
];
1128 Direct3D9RenderRegion(vd
, r
, false);
1130 IDirect3DDevice9_SetRenderState(d3ddev
, D3DRS_ALPHABLENDENABLE
, FALSE
);
1133 hr
= IDirect3DDevice9_EndScene(d3ddev
);
1135 msg_Dbg(vd
, "Failed EndScene: 0x%lX", hr
);
1137 if (sys
->startEndRenderingCb
)
1138 sys
->startEndRenderingCb( sys
->outside_opaque
, false );
1141 static void Prepare(vout_display_t
*vd
, picture_t
*picture
,
1142 subpicture_t
*subpicture
, vlc_tick_t date
)
1145 vout_display_sys_t
*sys
= vd
->sys
;
1147 /* Position Change */
1148 if (sys
->area
.place_changed
) {
1149 #if 0 /* need that when bicubic filter is available */
1153 GetClientRect(p_sys
->sys
.hvideownd
, &rect
);
1154 width
= RECTWidth(rect
);
1155 height
= RECTHeight(rect
);
1157 if (width
!= p_sys
->pp
.BackBufferWidth
|| height
!= p_sys
->pp
.BackBufferHeight
)
1159 msg_Dbg(vd
, "resizing device back buffers to (%lux%lu)", width
, height
);
1160 // need to reset D3D device to resize back buffer
1161 if (VLC_SUCCESS
!= Direct3D9ResetDevice(vd
, width
, height
))
1162 return VLC_EGENERIC
;
1165 UpdateOutput(vd
, vd
->fmt
, NULL
);
1167 sys
->clear_scene
= true;
1168 sys
->area
.place_changed
= false;
1171 d3d9_device_t
*p_d3d9_dev
= &sys
->d3d9_device
->d3ddev
;
1173 /* check if device is still available */
1174 HRESULT hr
= IDirect3DDevice9_TestCooperativeLevel(p_d3d9_dev
->dev
);
1176 if (hr
== D3DERR_DEVICENOTRESET
&& !sys
->reset_device
) {
1177 sys
->reset_device
= true;
1178 /* FIXME what to do here in case of failure */
1179 if (Direct3D9Reset(vd
, vd
->fmt
)) {
1180 msg_Err(vd
, "Failed to reset device");
1183 sys
->reset_device
= false;
1184 sys
->lost_not_ready
= false;
1186 if (hr
== D3DERR_DEVICELOST
&& !sys
->lost_not_ready
) {
1187 /* Device is lost but not yet ready for reset. */
1188 sys
->lost_not_ready
= true;
1193 /* FIXME it is a bit ugly, we need the surface to be unlocked for
1195 * The clean way would be to release the picture (and ensure that
1196 * the vout doesn't keep a reference). But because of the vout
1197 * wrapper, we can't */
1198 IDirect3DSurface9
*surface
;
1200 if ( !is_d3d9_opaque(picture
->format
.i_chroma
) )
1202 D3DLOCKED_RECT d3drect
;
1203 surface
= sys
->dx_render
;
1204 HRESULT hr
= IDirect3DSurface9_LockRect(surface
, &d3drect
, NULL
, 0);
1205 if (unlikely(FAILED(hr
))) {
1206 msg_Err(vd
, "failed to lock surface");
1210 picture_t fake_pic
= *picture
;
1211 picture_UpdatePlanes(&fake_pic
, d3drect
.pBits
, d3drect
.Pitch
);
1212 picture_CopyPixels(&fake_pic
, picture
);
1213 IDirect3DSurface9_UnlockRect(surface
);
1217 const picture_sys_d3d9_t
*picsys
= ActiveD3D9PictureSys(picture
);
1218 surface
= picsys
->surface
;
1219 if (picsys
->surface
!= surface
)
1221 D3DSURFACE_DESC srcDesc
, dstDesc
;
1222 IDirect3DSurface9_GetDesc(picsys
->surface
, &srcDesc
);
1223 IDirect3DSurface9_GetDesc(surface
, &dstDesc
);
1224 if ( srcDesc
.Width
== dstDesc
.Width
&& srcDesc
.Height
== dstDesc
.Height
)
1225 surface
= picsys
->surface
;
1230 visibleSource
.left
= 0;
1231 visibleSource
.top
= 0;
1232 visibleSource
.right
= picture
->format
.i_visible_width
;
1233 visibleSource
.bottom
= picture
->format
.i_visible_height
;
1235 hr
= IDirect3DDevice9_StretchRect( p_d3d9_dev
->dev
, picsys
->surface
, &visibleSource
, surface
, &visibleSource
, D3DTEXF_NONE
);
1237 msg_Err(vd
, "Failed to copy the hw surface to the decoder surface (hr=0x%lX)", hr
);
1243 d3d_region_t picture_region
;
1244 if (!Direct3D9ImportPicture(vd
, &picture_region
, surface
)) {
1245 picture_region
.width
= picture
->format
.i_visible_width
;
1246 picture_region
.height
= picture
->format
.i_visible_height
;
1247 size_t subpicture_region_count
= 0;
1248 d3d_region_t
*subpicture_region
= NULL
;
1250 Direct3D9ImportSubpicture(vd
, &subpicture_region_count
, &subpicture_region
,
1253 Direct3D9RenderScene(vd
, &picture_region
,
1254 subpicture_region_count
, subpicture_region
);
1256 Direct3D9DeleteRegions(sys
->d3dregion_count
, sys
->d3dregion
);
1257 sys
->d3dregion_count
= subpicture_region_count
;
1258 sys
->d3dregion
= subpicture_region
;
1262 static void Swap(vout_display_t
*vd
)
1264 vout_display_sys_t
*sys
= vd
->sys
;
1265 const d3d9_device_t
*p_d3d9_dev
= &sys
->d3d9_device
->d3ddev
;
1267 // Present the back buffer contents to the display
1268 // No stretching should happen here !
1271 .right
= vd
->cfg
->display
.width
,
1273 .bottom
= vd
->cfg
->display
.height
1277 if (sys
->d3d9_device
->hd3d
.use_ex
) {
1278 hr
= IDirect3DDevice9Ex_PresentEx(p_d3d9_dev
->devex
, &src
, &src
, sys
->sys
.hvideownd
, NULL
, 0);
1280 hr
= IDirect3DDevice9_Present(p_d3d9_dev
->dev
, &src
, &src
, sys
->sys
.hvideownd
, NULL
);
1283 msg_Dbg(vd
, "Failed Present: 0x%lX", hr
);
1287 static void Display(vout_display_t
*vd
, picture_t
*picture
)
1289 VLC_UNUSED(picture
);
1290 vout_display_sys_t
*sys
= vd
->sys
;
1292 if (sys
->lost_not_ready
)
1295 sys
->swapCb( sys
->outside_opaque
);
1299 * It releases an instance of Direct3D9
1301 static void Direct3D9Destroy(vout_display_sys_t
*sys
)
1303 if (sys
->processor
.proc
)
1305 IDXVAHD_VideoProcessor_Release(sys
->processor
.proc
);
1306 FreeLibrary(sys
->processor
.dll
);
1308 if (sys
->dec_device
)
1309 vlc_decoder_device_Release(sys
->dec_device
);
1310 else if (sys
->d3d9_device
)
1312 D3D9_ReleaseDevice(sys
->d3d9_device
);
1316 FreeLibrary(sys
->hxdll
);
1322 * It tests if the conversion from src to dst is supported.
1324 static int Direct3D9CheckConversion(vout_display_t
*vd
, D3DFORMAT src
)
1326 vout_display_sys_t
*sys
= vd
->sys
;
1327 IDirect3D9
*d3dobj
= sys
->d3d9_device
->hd3d
.obj
;
1328 D3DFORMAT dst
= sys
->BufferFormat
;
1331 /* test whether device can create a surface of that format */
1332 hr
= IDirect3D9_CheckDeviceFormat(d3dobj
, sys
->d3d9_device
->d3ddev
.adapterId
,
1333 D3DDEVTYPE_HAL
, dst
, 0,
1334 D3DRTYPE_SURFACE
, src
);
1335 if (!SUCCEEDED(hr
)) {
1336 if (D3DERR_NOTAVAILABLE
!= hr
)
1337 msg_Err(vd
, "Could not query adapter supported formats. (hr=0x%lX)", hr
);
1338 return VLC_EGENERIC
;
1343 static const d3d9_format_t d3d_formats
[] = {
1344 /* YV12 is always used for planar 420, the planes are then swapped in Lock() */
1345 { "YV12", MAKEFOURCC('Y','V','1','2'), VLC_CODEC_YV12
, 0,0,0 },
1346 { "YV12", MAKEFOURCC('Y','V','1','2'), VLC_CODEC_I420
, 0,0,0 },
1347 { "YV12", MAKEFOURCC('Y','V','1','2'), VLC_CODEC_J420
, 0,0,0 },
1348 { "NV12", MAKEFOURCC('N','V','1','2'), VLC_CODEC_NV12
, 0,0,0 },
1349 { "DXA9", MAKEFOURCC('N','V','1','2'), VLC_CODEC_D3D9_OPAQUE
, 0,0,0 },
1350 { "DXA9_422", MAKEFOURCC('Y','U','Y','2'), VLC_CODEC_D3D9_OPAQUE
, 0,0,0 },
1351 { "DXA9_444", MAKEFOURCC('A','Y','U','V'), VLC_CODEC_D3D9_OPAQUE
, 0,0,0 },
1352 { "DXA9_10", MAKEFOURCC('P','0','1','0'), VLC_CODEC_D3D9_OPAQUE_10B
, 0,0,0 },
1353 { "DXA9_10_422", MAKEFOURCC('Y','2','1','0'), VLC_CODEC_D3D9_OPAQUE_10B
, 0,0,0 },
1354 { "DXA9_10_444", MAKEFOURCC('Y','4','1','0'), VLC_CODEC_D3D9_OPAQUE_10B
, 0,0,0 },
1355 { "UYVY", D3DFMT_UYVY
, VLC_CODEC_UYVY
, 0,0,0 },
1356 { "YUY2", D3DFMT_YUY2
, VLC_CODEC_YUYV
, 0,0,0 },
1357 { "X8R8G8B8", D3DFMT_X8R8G8B8
,VLC_CODEC_RGB32
, 0xff0000, 0x00ff00, 0x0000ff },
1358 { "A8R8G8B8", D3DFMT_A8R8G8B8
,VLC_CODEC_RGB32
, 0xff0000, 0x00ff00, 0x0000ff },
1359 { "8G8B8", D3DFMT_R8G8B8
, VLC_CODEC_RGB24
, 0xff0000, 0x00ff00, 0x0000ff },
1360 { "R5G6B5", D3DFMT_R5G6B5
, VLC_CODEC_RGB16
, 0x1f<<11, 0x3f<<5, 0x1f<<0 },
1361 { "X1R5G5B5", D3DFMT_X1R5G5B5
,VLC_CODEC_RGB15
, 0x1f<<10, 0x1f<<5, 0x1f<<0 },
1363 { NULL
, 0, 0, 0,0,0}
1366 static const d3d9_format_t
*FindBufferFormat(D3DFORMAT fmt
)
1368 for (unsigned j
= 0; d3d_formats
[j
].name
; j
++) {
1369 const d3d9_format_t
*format
= &d3d_formats
[j
];
1371 if (format
->format
!= fmt
)
1380 * It returns the format (closest to chroma) that can be converted to target */
1381 static const d3d9_format_t
*Direct3DFindFormat(vout_display_t
*vd
, const video_format_t
*fmt
, vlc_video_context
*vctx
)
1383 vout_display_sys_t
*sys
= vd
->sys
;
1384 bool hardware_scale_ok
= !(fmt
->i_visible_width
& 1) && !(fmt
->i_visible_height
& 1);
1385 if( !hardware_scale_ok
)
1386 msg_Warn( vd
, "Disabling hardware chroma conversion due to odd dimensions" );
1388 for (unsigned pass
= 0; pass
< 2; pass
++) {
1389 const vlc_fourcc_t
*list
;
1390 const vlc_fourcc_t dxva_chroma
[] = {fmt
->i_chroma
, 0};
1391 D3DFORMAT decoder_format
= D3DFMT_UNKNOWN
;
1393 if (pass
== 0 && is_d3d9_opaque(fmt
->i_chroma
))
1395 d3d9_video_context_t
*vctx_sys
= GetD3D9ContextPrivate(vctx
);
1396 assert(vctx_sys
!= NULL
);
1398 decoder_format
= vctx_sys
->format
;
1399 msg_Dbg(vd
, "favor decoder format: %4.4s (%d)", (const char*)&decoder_format
, decoder_format
);
1401 else if (pass
== 0 && hardware_scale_ok
&& sys
->allow_hw_yuv
&& vlc_fourcc_IsYUV(fmt
->i_chroma
))
1402 list
= vlc_fourcc_GetYUVFallback(fmt
->i_chroma
);
1404 list
= vlc_fourcc_GetRGBFallback(fmt
->i_chroma
);
1408 for (unsigned i
= 0; list
[i
] != 0; i
++) {
1409 for (unsigned j
= 0; d3d_formats
[j
].name
; j
++) {
1410 const d3d9_format_t
*format
= &d3d_formats
[j
];
1412 if (format
->fourcc
!= list
[i
])
1414 if (decoder_format
!= D3DFMT_UNKNOWN
&& format
->format
!= decoder_format
)
1415 continue; // not the Hardware format we prefer
1417 msg_Dbg(vd
, "trying surface pixel format: %s", format
->name
);
1418 if (!Direct3D9CheckConversion(vd
, format
->format
))
1426 static void SetupProcessorInput(vout_display_t
*vd
, const video_format_t
*fmt
, const d3d9_format_t
*d3dfmt
)
1428 vout_display_sys_t
*sys
= vd
->sys
;
1430 DXVAHD_STREAM_STATE_D3DFORMAT_DATA d3dformat
= { d3dfmt
->format
};
1431 hr
= IDXVAHD_VideoProcessor_SetVideoProcessStreamState( sys
->processor
.proc
, 0, DXVAHD_STREAM_STATE_D3DFORMAT
, sizeof(d3dformat
), &d3dformat
);
1433 DXVAHD_STREAM_STATE_FRAME_FORMAT_DATA frame_format
= { DXVAHD_FRAME_FORMAT_PROGRESSIVE
};
1434 hr
= IDXVAHD_VideoProcessor_SetVideoProcessStreamState( sys
->processor
.proc
, 0, DXVAHD_STREAM_STATE_FRAME_FORMAT
, sizeof(frame_format
), &frame_format
);
1436 DXVAHD_STREAM_STATE_INPUT_COLOR_SPACE_DATA colorspace
= { 0 };
1437 colorspace
.RGB_Range
= fmt
->color_range
== COLOR_RANGE_FULL
? 0 : 1;
1438 colorspace
.YCbCr_xvYCC
= fmt
->color_range
== COLOR_RANGE_FULL
? 1 : 0;
1439 colorspace
.YCbCr_Matrix
= fmt
->space
== COLOR_SPACE_BT601
? 0 : 1;
1440 hr
= IDXVAHD_VideoProcessor_SetVideoProcessStreamState( sys
->processor
.proc
, 0, DXVAHD_STREAM_STATE_INPUT_COLOR_SPACE
, sizeof(colorspace
), &colorspace
);
1442 DXVAHD_STREAM_STATE_SOURCE_RECT_DATA srcRect
;
1443 srcRect
.Enable
= TRUE
;
1444 srcRect
.SourceRect
= (RECT
) {
1445 .left
= vd
->source
->i_x_offset
,
1446 .right
= vd
->source
->i_x_offset
+ vd
->source
->i_visible_width
,
1447 .top
= vd
->source
->i_y_offset
,
1448 .bottom
= vd
->source
->i_y_offset
+ vd
->source
->i_visible_height
,
1450 hr
= IDXVAHD_VideoProcessor_SetVideoProcessStreamState( sys
->processor
.proc
, 0, DXVAHD_STREAM_STATE_SOURCE_RECT
, sizeof(srcRect
), &srcRect
);
1452 DXVAHD_BLT_STATE_TARGET_RECT_DATA dstRect
;
1453 dstRect
.Enable
= TRUE
;
1454 dstRect
.TargetRect
= (RECT
) {
1456 .right
= vd
->source
->i_visible_width
,
1458 .bottom
= vd
->source
->i_visible_height
,
1460 hr
= IDXVAHD_VideoProcessor_SetVideoProcessBltState( sys
->processor
.proc
, DXVAHD_BLT_STATE_TARGET_RECT
, sizeof(dstRect
), &dstRect
);
1463 static void GetFrameRate(DXVAHD_RATIONAL
*r
, const video_format_t
*fmt
)
1465 if (fmt
->i_frame_rate
&& fmt
->i_frame_rate_base
)
1467 r
->Numerator
= fmt
->i_frame_rate
;
1468 r
->Denominator
= fmt
->i_frame_rate_base
;
1477 static int InitRangeProcessor(vout_display_t
*vd
, const d3d9_format_t
*d3dfmt
,
1478 const libvlc_video_output_cfg_t
*render_out
)
1480 vout_display_sys_t
*sys
= vd
->sys
;
1484 sys
->processor
.dll
= LoadLibrary(TEXT("DXVA2.DLL"));
1485 if (unlikely(!sys
->processor
.dll
))
1487 msg_Err(vd
, "Failed to load DXVA2.DLL");
1488 return VLC_EGENERIC
;
1491 D3DFORMAT
*formatsList
= NULL
;
1492 DXVAHD_VPCAPS
*capsList
= NULL
;
1493 IDXVAHD_Device
*hd_device
= NULL
;
1495 HRESULT (WINAPI
*CreateDevice
)(IDirect3DDevice9Ex
*,const DXVAHD_CONTENT_DESC
*,DXVAHD_DEVICE_USAGE
,PDXVAHDSW_Plugin
,IDXVAHD_Device
**);
1496 CreateDevice
= (void *)GetProcAddress(sys
->processor
.dll
, "DXVAHD_CreateDevice");
1497 if (CreateDevice
== NULL
)
1499 msg_Err(vd
, "Can't create HD device (not Windows 7+)");
1503 DXVAHD_CONTENT_DESC desc
;
1504 desc
.InputFrameFormat
= DXVAHD_FRAME_FORMAT_PROGRESSIVE
;
1505 GetFrameRate( &desc
.InputFrameRate
, vd
->source
);
1506 desc
.InputWidth
= vd
->source
->i_visible_width
;
1507 desc
.InputHeight
= vd
->source
->i_visible_height
;
1508 desc
.OutputFrameRate
= desc
.InputFrameRate
;
1509 desc
.OutputWidth
= vd
->source
->i_visible_width
;
1510 desc
.OutputHeight
= vd
->source
->i_visible_height
;
1512 hr
= CreateDevice(sys
->d3d9_device
->d3ddev
.devex
, &desc
, DXVAHD_DEVICE_USAGE_PLAYBACK_NORMAL
, NULL
, &hd_device
);
1515 msg_Dbg(vd
, "Failed to create the device (error 0x%lX)", hr
);
1519 DXVAHD_VPDEVCAPS devcaps
= { 0 };
1520 hr
= IDXVAHD_Device_GetVideoProcessorDeviceCaps( hd_device
, &devcaps
);
1521 if (unlikely(FAILED(hr
)))
1523 msg_Err(vd
, "Failed to get the device capabilities (error 0x%lX)", hr
);
1526 if (devcaps
.VideoProcessorCount
== 0)
1528 msg_Warn(vd
, "No good video processor found for range conversion");
1532 formatsList
= malloc(devcaps
.InputFormatCount
* sizeof(*formatsList
));
1533 if (unlikely(formatsList
== NULL
))
1535 msg_Dbg(vd
, "Failed to allocate %u input formats", devcaps
.InputFormatCount
);
1539 hr
= IDXVAHD_Device_GetVideoProcessorInputFormats( hd_device
, devcaps
.InputFormatCount
, formatsList
);
1541 for (i
=0; i
<devcaps
.InputFormatCount
; i
++)
1543 if (formatsList
[i
] == d3dfmt
->format
)
1546 if (i
== devcaps
.InputFormatCount
)
1548 msg_Warn(vd
, "Input format %s not supported for range conversion", d3dfmt
->name
);
1553 formatsList
= malloc(devcaps
.OutputFormatCount
* sizeof(*formatsList
));
1554 if (unlikely(formatsList
== NULL
))
1556 msg_Dbg(vd
, "Failed to allocate %u output formats", devcaps
.OutputFormatCount
);
1560 hr
= IDXVAHD_Device_GetVideoProcessorOutputFormats( hd_device
, devcaps
.OutputFormatCount
, formatsList
);
1561 for (i
=0; i
<devcaps
.OutputFormatCount
; i
++)
1563 if (formatsList
[i
] == sys
->BufferFormat
)
1566 if (i
== devcaps
.OutputFormatCount
)
1568 msg_Warn(vd
, "Output format %d not supported for range conversion", sys
->BufferFormat
);
1572 capsList
= malloc(devcaps
.VideoProcessorCount
* sizeof(*capsList
));
1573 if (unlikely(capsList
== NULL
))
1575 msg_Dbg(vd
, "Failed to allocate %u video processors", devcaps
.VideoProcessorCount
);
1578 hr
= IDXVAHD_Device_GetVideoProcessorCaps( hd_device
, devcaps
.VideoProcessorCount
, capsList
);
1581 msg_Dbg(vd
, "Failed to get the processor caps (error 0x%lX)", hr
);
1585 hr
= IDXVAHD_Device_CreateVideoProcessor( hd_device
, &capsList
->VPGuid
, &sys
->processor
.proc
);
1588 msg_Dbg(vd
, "Failed to create the processor (error 0x%lX)", hr
);
1591 IDXVAHD_Device_Release( hd_device
);
1593 SetupProcessorInput(vd
, vd
->source
, d3dfmt
);
1595 DXVAHD_BLT_STATE_OUTPUT_COLOR_SPACE_DATA colorspace
;
1596 colorspace
.Usage
= 0; // playback
1597 colorspace
.RGB_Range
= render_out
->full_range
? 0 : 1;
1598 colorspace
.YCbCr_xvYCC
= render_out
->full_range
? 1 : 0;
1599 colorspace
.YCbCr_Matrix
= render_out
->colorspace
== libvlc_video_colorspace_BT601
? 0 : 1;
1600 hr
= IDXVAHD_VideoProcessor_SetVideoProcessBltState( sys
->processor
.proc
, DXVAHD_BLT_STATE_OUTPUT_COLOR_SPACE
, sizeof(colorspace
), &colorspace
);
1608 IDXVAHD_Device_Release(hd_device
);
1609 FreeLibrary(sys
->processor
.dll
);
1610 return VLC_EGENERIC
;
1614 * It creates a Direct3D9 device and the associated resources.
1616 static int Direct3D9Open(vout_display_t
*vd
, video_format_t
*fmt
, vlc_video_context
*vctx
)
1618 vout_display_sys_t
*sys
= vd
->sys
;
1620 libvlc_video_output_cfg_t render_out
;
1621 if (UpdateOutput(vd
, vd
->source
, &render_out
) != VLC_SUCCESS
)
1622 return VLC_EGENERIC
;
1624 sys
->BufferFormat
= render_out
.d3d9_format
;
1625 const d3d9_format_t
*dst_format
= FindBufferFormat(sys
->BufferFormat
);
1626 if (unlikely(!dst_format
))
1627 msg_Warn(vd
, "Unknown back buffer format 0x%X", sys
->BufferFormat
);
1629 /* Find the appropriate D3DFORMAT for the render chroma, the format will be the closest to
1630 * the requested chroma which is usable by the hardware in an offscreen surface, as they
1631 * typically support more formats than textures */
1632 const d3d9_format_t
*d3dfmt
= Direct3DFindFormat(vd
, vd
->source
, vctx
);
1634 msg_Err(vd
, "unsupported source pixel format %4.4s", (const char*)&vd
->source
->i_chroma
);
1637 msg_Dbg(vd
, "found input surface format %s for source %4.4s", d3dfmt
->name
, (const char *)&vd
->source
->i_chroma
);
1639 bool force_dxva_hd
= var_InheritBool(vd
, "direct3d9-dxvahd");
1640 if (force_dxva_hd
|| (dst_format
&& vd
->source
->color_range
!= COLOR_RANGE_FULL
&& dst_format
->rmask
&& !d3dfmt
->rmask
&&
1641 sys
->d3d9_device
->d3ddev
.identifier
.VendorId
== GPU_MANUFACTURER_NVIDIA
))
1643 // NVIDIA bug, YUV to RGB internal conversion in StretchRect always converts from limited to limited range
1644 msg_Dbg(vd
, "init DXVA-HD processor from %s to %s", d3dfmt
->name
, dst_format
?dst_format
->name
:"unknown");
1645 int err
= InitRangeProcessor( vd
, d3dfmt
, &render_out
);
1646 if (err
!= VLC_SUCCESS
)
1647 force_dxva_hd
= false;
1651 // test whether device can perform color-conversion from that format to target format
1652 HRESULT hr
= IDirect3D9_CheckDeviceFormatConversion(sys
->d3d9_device
->hd3d
.obj
,
1653 sys
->d3d9_device
->d3ddev
.adapterId
,
1655 d3dfmt
->format
, sys
->BufferFormat
);
1658 msg_Dbg(vd
, "Unsupported conversion from %s to %s", d3dfmt
->name
, dst_format
?dst_format
->name
:"unknown" );
1661 msg_Dbg(vd
, "using StrecthRect from %s to %s", d3dfmt
->name
, dst_format
?dst_format
->name
:"unknown" );
1666 fmt
->i_chroma
= d3dfmt
->fourcc
;
1667 fmt
->i_rmask
= d3dfmt
->rmask
;
1668 fmt
->i_gmask
= d3dfmt
->gmask
;
1669 fmt
->i_bmask
= d3dfmt
->bmask
;
1670 sys
->sw_texture_fmt
= d3dfmt
;
1672 if (Direct3D9CreateResources(vd
, fmt
)) {
1673 msg_Err(vd
, "Failed to allocate resources");
1677 msg_Dbg(vd
, "Direct3D9 display adapter successfully initialized");
1681 return VLC_EGENERIC
;
1685 * It releases the Direct3D9 device and its resources.
1687 static void Direct3D9Close(vout_display_t
*vd
)
1689 Direct3D9DestroyResources(vd
);
1692 static int Control(vout_display_t
*vd
, int query
)
1694 vout_display_sys_t
*sys
= vd
->sys
;
1695 return CommonControl(vd
, &sys
->area
, &sys
->sys
, query
);
1705 static void ListShaders(enum_context_t
*ctx
)
1707 size_t num_shaders
= BUILTIN_SHADERS_COUNT
;
1708 ctx
->values
= xrealloc(ctx
->values
, (ctx
->count
+ num_shaders
+ 1) * sizeof(char *));
1709 ctx
->descs
= xrealloc(ctx
->descs
, (ctx
->count
+ num_shaders
+ 1) * sizeof(char *));
1710 for (size_t i
= 0; i
< num_shaders
; ++i
) {
1711 ctx
->values
[ctx
->count
] = strdup(builtin_shaders
[i
].name
);
1712 ctx
->descs
[ctx
->count
] = strdup(builtin_shaders
[i
].name
);
1715 ctx
->values
[ctx
->count
] = strdup(SELECTED_SHADER_FILE
);
1716 ctx
->descs
[ctx
->count
] = strdup(SELECTED_SHADER_FILE
);
1720 /* Populate the list of available shader techniques in the options */
1721 static int FindShadersCallback(const char *name
, char ***values
, char ***descs
)
1725 enum_context_t ctx
= { NULL
, NULL
, 0 };
1729 *values
= ctx
.values
;
1735 VLC_CONFIG_STRING_ENUM(FindShadersCallback
)
1737 static bool LocalSwapchainUpdateOutput( void *opaque
, const libvlc_video_render_cfg_t
*cfg
, libvlc_video_output_cfg_t
*out
)
1740 vout_display_t
*vd
= opaque
;
1741 vout_display_sys_t
*sys
= vd
->sys
;
1743 D3DDISPLAYMODE d3ddm
;
1744 HRESULT hr
= IDirect3D9_GetAdapterDisplayMode(sys
->d3d9_device
->hd3d
.obj
, sys
->d3d9_device
->d3ddev
.adapterId
, &d3ddm
);
1745 if (unlikely(FAILED(hr
)))
1748 out
->d3d9_format
= d3ddm
.Format
;
1749 out
->full_range
= true;
1750 out
->colorspace
= libvlc_video_colorspace_BT709
;
1751 out
->primaries
= libvlc_video_primaries_BT709
;
1752 out
->transfer
= libvlc_video_transfer_func_SRGB
;
1757 static void LocalSwapchainSwap( void *opaque
)
1759 vout_display_t
*vd
= opaque
;
1763 static const struct vlc_display_operations ops
= {
1764 Close
, Prepare
, Display
, Control
, NULL
, NULL
,
1768 * It creates a Direct3D vout display.
1770 static int Open(vout_display_t
*vd
, const vout_display_cfg_t
*cfg
,
1771 video_format_t
*fmtp
, vlc_video_context
*context
)
1773 vout_display_sys_t
*sys
;
1775 if ( !vd
->obj
.force
&& vd
->source
->projection_mode
!= PROJECTION_MODE_RECTANGULAR
)
1776 return VLC_EGENERIC
; /* let a module who can handle it do it */
1778 if ( !vd
->obj
.force
&& vd
->source
->mastering
.max_luminance
!= 0)
1779 return VLC_EGENERIC
; /* let a module who can handle it do it */
1781 /* do not use D3D9 on XP unless forced */
1784 bool isVistaOrGreater
= false;
1785 HMODULE hKernel32
= GetModuleHandle(TEXT("kernel32.dll"));
1786 if (likely(hKernel32
!= NULL
))
1787 isVistaOrGreater
= GetProcAddress(hKernel32
, "EnumResourceLanguagesExW") != NULL
;
1788 if (!isVistaOrGreater
)
1789 return VLC_EGENERIC
;
1792 /* Allocate structure */
1793 vd
->sys
= sys
= calloc(1, sizeof(vout_display_sys_t
));
1797 CommonInit(&sys
->area
);
1799 sys
->outside_opaque
= var_InheritAddress( vd
, "vout-cb-opaque" );
1800 sys
->updateOutputCb
= var_InheritAddress( vd
, "vout-cb-update-output" );
1801 sys
->swapCb
= var_InheritAddress( vd
, "vout-cb-swap" );
1802 sys
->startEndRenderingCb
= var_InheritAddress( vd
, "vout-cb-make-current" );
1804 if ( sys
->swapCb
== NULL
|| sys
->startEndRenderingCb
== NULL
|| sys
->updateOutputCb
== NULL
)
1806 /* use our own callbacks, since there isn't any external ones */
1807 if (CommonWindowInit(vd
, &sys
->area
, &sys
->sys
, false))
1810 sys
->outside_opaque
= vd
;
1811 sys
->updateOutputCb
= LocalSwapchainUpdateOutput
;
1812 sys
->swapCb
= LocalSwapchainSwap
;
1813 sys
->startEndRenderingCb
= NULL
;
1816 sys
->dec_device
= context
? vlc_video_context_HoldDevice(context
) : NULL
;
1817 sys
->d3d9_device
= GetD3D9OpaqueDevice(sys
->dec_device
);
1818 if ( sys
->d3d9_device
== NULL
)
1820 if (sys
->dec_device
)
1822 vlc_decoder_device_Release(sys
->dec_device
);
1823 sys
->dec_device
= NULL
;
1826 sys
->d3d9_device
= D3D9_CreateDevice( vd
);
1827 if (sys
->d3d9_device
== NULL
) {
1828 msg_Err( vd
, "D3D9 Creation failed!" );
1834 if ( vd
->source
->i_visible_width
> sys
->d3d9_device
->d3ddev
.caps
.MaxTextureWidth
||
1835 vd
->source
->i_visible_height
> sys
->d3d9_device
->d3ddev
.caps
.MaxTextureHeight
)
1837 msg_Err(vd
, "Textures too large %ux%u max possible: %lx%lx",
1838 vd
->source
->i_visible_width
, vd
->source
->i_visible_height
,
1839 sys
->d3d9_device
->d3ddev
.caps
.MaxTextureWidth
,
1840 sys
->d3d9_device
->d3ddev
.caps
.MaxTextureHeight
);
1844 if (sys
->swapCb
== LocalSwapchainSwap
)
1845 CommonPlacePicture(vd
, &sys
->area
);
1847 sys
->hxdll
= Direct3D9LoadShaderLibrary();
1849 msg_Warn(vd
, "cannot load Direct3D9 Shader Library; HLSL pixel shading will be disabled.");
1851 sys
->reset_device
= false;
1852 sys
->lost_not_ready
= false;
1853 sys
->allow_hw_yuv
= var_CreateGetBool(vd
, "directx-hw-yuv");
1857 if (Direct3D9Open(vd
, &fmt
, context
)) {
1858 msg_Err(vd
, "Direct3D9 could not be opened");
1862 /* Setup vout_display now that everything is fine */
1863 if (var_InheritBool(vd
, "direct3d9-hw-blending") &&
1864 sys
->d3dregion_format
!= D3DFMT_UNKNOWN
&&
1865 (sys
->d3d9_device
->d3ddev
.caps
.SrcBlendCaps
& D3DPBLENDCAPS_SRCALPHA
) &&
1866 (sys
->d3d9_device
->d3ddev
.caps
.DestBlendCaps
& D3DPBLENDCAPS_INVSRCALPHA
) &&
1867 (sys
->d3d9_device
->d3ddev
.caps
.TextureCaps
& D3DPTEXTURECAPS_ALPHA
) &&
1868 (sys
->d3d9_device
->d3ddev
.caps
.TextureOpCaps
& D3DTEXOPCAPS_SELECTARG1
) &&
1869 (sys
->d3d9_device
->d3ddev
.caps
.TextureOpCaps
& D3DTEXOPCAPS_MODULATE
))
1870 vd
->info
.subpicture_chromas
= d3d_subpicture_chromas
;
1872 vd
->info
.subpicture_chromas
= NULL
;
1874 video_format_Clean(fmtp
);
1875 video_format_Copy(fmtp
, &fmt
);
1879 /* Change the window title bar text */
1880 vout_window_SetTitle(cfg
->window
, VOUT_TITLE
" (Direct3D9 output)");
1885 CommonWindowClean(&sys
->sys
);
1886 Direct3D9Destroy(sys
);
1888 return VLC_EGENERIC
;
1892 * It destroyes a Direct3D vout display.
1894 static void Close(vout_display_t
*vd
)
1898 CommonWindowClean(&vd
->sys
->sys
);
1900 Direct3D9Destroy(vd
->sys
);