1 /*****************************************************************************
2 * d3d11_quad.c: Direct3D11 Qaud handling
3 *****************************************************************************
4 * Copyright (C) 2017-2018 VLC authors and VideoLAN
6 * Authors: Steve Lhomme <robux4@gmail.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
28 #include <vlc_common.h>
30 #if !defined(_WIN32_WINNT) || _WIN32_WINNT < _WIN32_WINNT_WIN7
32 # define _WIN32_WINNT _WIN32_WINNT_WIN7
38 #include "d3d11_quad.h"
40 #define SPHERE_SLICES 128
41 #define nbLatBands SPHERE_SLICES
42 #define nbLonBands SPHERE_SLICES
44 void D3D11_RenderQuad(d3d11_device_t
*d3d_dev
, d3d_quad_t
*quad
,
45 ID3D11ShaderResourceView
*resourceView
[D3D11_MAX_SHADER_VIEW
],
46 ID3D11RenderTargetView
*d3drenderTargetView
[D3D11_MAX_SHADER_VIEW
])
51 ID3D11DeviceContext_IASetPrimitiveTopology(d3d_dev
->d3dcontext
, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST
);
54 ID3D11DeviceContext_IASetInputLayout(d3d_dev
->d3dcontext
, quad
->pVertexLayout
);
55 ID3D11DeviceContext_IASetVertexBuffers(d3d_dev
->d3dcontext
, 0, 1, &quad
->pVertexBuffer
, &quad
->vertexStride
, &offset
);
56 ID3D11DeviceContext_IASetIndexBuffer(d3d_dev
->d3dcontext
, quad
->pIndexBuffer
, DXGI_FORMAT_R16_UINT
, 0);
57 if ( quad
->pVertexShaderConstants
)
58 ID3D11DeviceContext_VSSetConstantBuffers(d3d_dev
->d3dcontext
, 0, 1, &quad
->pVertexShaderConstants
);
60 ID3D11DeviceContext_VSSetShader(d3d_dev
->d3dcontext
, quad
->d3dvertexShader
, NULL
, 0);
63 ID3D11DeviceContext_PSSetConstantBuffers(d3d_dev
->d3dcontext
, 0, quad
->PSConstantsCount
, quad
->pPixelShaderConstants
);
64 assert(quad
->resourceCount
<= D3D11_MAX_SHADER_VIEW
);
65 ID3D11DeviceContext_PSSetShaderResources(d3d_dev
->d3dcontext
, 0, quad
->resourceCount
, resourceView
);
67 for (size_t i
=0; i
<D3D11_MAX_SHADER_VIEW
; i
++)
69 if (!d3drenderTargetView
[i
])
72 ID3D11DeviceContext_PSSetShader(d3d_dev
->d3dcontext
, quad
->d3dpixelShader
[i
], NULL
, 0);
74 ID3D11DeviceContext_RSSetViewports(d3d_dev
->d3dcontext
, 1, &quad
->cropViewport
[i
]);
76 ID3D11DeviceContext_OMSetRenderTargets(d3d_dev
->d3dcontext
, 1, &d3drenderTargetView
[i
], NULL
);
78 ID3D11DeviceContext_DrawIndexed(d3d_dev
->d3dcontext
, quad
->indexCount
, 0, 0);
82 static bool AllocQuadVertices(vlc_object_t
*o
, d3d11_device_t
*d3d_dev
, d3d_quad_t
*quad
)
86 switch (quad
->projection
)
88 case PROJECTION_MODE_RECTANGULAR
:
89 quad
->vertexCount
= 4;
90 quad
->indexCount
= 2 * 3;
92 case PROJECTION_MODE_EQUIRECTANGULAR
:
93 quad
->vertexCount
= (SPHERE_SLICES
+ 1) * (SPHERE_SLICES
+ 1);
94 quad
->indexCount
= nbLatBands
* nbLonBands
* 2 * 3;
96 case PROJECTION_MODE_CUBEMAP_LAYOUT_STANDARD
:
97 quad
->vertexCount
= 4 * 6;
98 quad
->indexCount
= 6 * 2 * 3;
101 msg_Warn(o
, "Projection mode %d not handled", quad
->projection
);
105 quad
->vertexStride
= sizeof(d3d_vertex_t
);
107 D3D11_BUFFER_DESC bd
;
108 memset(&bd
, 0, sizeof(bd
));
109 bd
.Usage
= D3D11_USAGE_DYNAMIC
;
110 bd
.ByteWidth
= quad
->vertexStride
* quad
->vertexCount
;
111 bd
.BindFlags
= D3D11_BIND_VERTEX_BUFFER
;
112 bd
.CPUAccessFlags
= D3D11_CPU_ACCESS_WRITE
;
114 hr
= ID3D11Device_CreateBuffer(d3d_dev
->d3ddevice
, &bd
, NULL
, &quad
->pVertexBuffer
);
116 msg_Err(o
, "Failed to create vertex buffer. (hr=%lX)", hr
);
120 /* create the index of the vertices */
121 D3D11_BUFFER_DESC quadDesc
= {
122 .Usage
= D3D11_USAGE_DYNAMIC
,
123 .ByteWidth
= sizeof(WORD
) * quad
->indexCount
,
124 .BindFlags
= D3D11_BIND_INDEX_BUFFER
,
125 .CPUAccessFlags
= D3D11_CPU_ACCESS_WRITE
,
128 hr
= ID3D11Device_CreateBuffer(d3d_dev
->d3ddevice
, &quadDesc
, NULL
, &quad
->pIndexBuffer
);
130 msg_Err(o
, "Could not create the quad indices. (hr=0x%lX)", hr
);
131 ID3D11Buffer_Release(quad
->pVertexBuffer
);
132 quad
->pVertexBuffer
= NULL
;
139 void D3D11_ReleaseQuad(d3d_quad_t
*quad
)
141 if (quad
->pPixelShaderConstants
[0])
143 ID3D11Buffer_Release(quad
->pPixelShaderConstants
[0]);
144 quad
->pPixelShaderConstants
[0] = NULL
;
146 if (quad
->pPixelShaderConstants
[1])
148 ID3D11Buffer_Release(quad
->pPixelShaderConstants
[1]);
149 quad
->pPixelShaderConstants
[1] = NULL
;
151 if (quad
->pVertexBuffer
)
153 ID3D11Buffer_Release(quad
->pVertexBuffer
);
154 quad
->pVertexBuffer
= NULL
;
156 quad
->d3dvertexShader
= NULL
;
157 if (quad
->pIndexBuffer
)
159 ID3D11Buffer_Release(quad
->pIndexBuffer
);
160 quad
->pIndexBuffer
= NULL
;
162 if (quad
->pVertexShaderConstants
)
164 ID3D11Buffer_Release(quad
->pVertexShaderConstants
);
165 quad
->pVertexShaderConstants
= NULL
;
167 for (size_t i
=0; i
<D3D11_MAX_SHADER_VIEW
; i
++)
169 if (quad
->d3dpixelShader
[i
])
171 ID3D11PixelShader_Release(quad
->d3dpixelShader
[i
]);
172 quad
->d3dpixelShader
[i
] = NULL
;
175 ReleasePictureSys(&quad
->picSys
);
179 * Compute the vertex ordering needed to rotate the video. Without
180 * rotation, the vertices of the rectangle are defined in a counterclockwise
181 * order. This function computes a remapping of the coordinates to
182 * implement the rotation, given fixed texture coordinates.
183 * The unrotated order is the following:
187 * For a 180 degrees rotation it should like this:
191 * Vertex 0 should be assigned coordinates at index 2 from the
192 * unrotated order and so on, thus yielding order: 2 3 0 1.
194 static void orientationVertexOrder(video_orientation_t orientation
, int vertex_order
[static 4])
196 switch (orientation
) {
197 case ORIENT_ROTATED_90
:
203 case ORIENT_ROTATED_270
:
209 case ORIENT_ROTATED_180
:
215 case ORIENT_TRANSPOSED
:
221 case ORIENT_HFLIPPED
:
227 case ORIENT_VFLIPPED
:
233 case ORIENT_ANTI_TRANSPOSED
: /* transpose + vflip */
248 static void SetupQuadFlat(d3d_vertex_t
*dst_data
, const RECT
*output
,
249 const d3d_quad_t
*quad
,
250 WORD
*triangle_pos
, video_orientation_t orientation
)
252 unsigned int src_width
= quad
->i_width
;
253 unsigned int src_height
= quad
->i_height
;
256 float top
, bottom
, left
, right
;
257 /* find the middle of the visible part of the texture, it will be a 0,0
258 * the rest of the visible area must correspond to -1,1 */
261 case ORIENT_ROTATED_90
: /* 90° anti clockwise */
262 /* right/top aligned */
263 MidY
= (output
->left
+ output
->right
) / 2.f
;
264 MidX
= (output
->top
+ output
->bottom
) / 2.f
;
265 top
= MidY
/ (MidY
- output
->top
);
266 bottom
= -(src_height
- MidX
) / (MidX
- output
->top
);
267 left
= (MidX
- src_height
) / (MidX
- output
->left
);
268 right
= MidX
/ (MidX
- (src_width
- output
->right
));
270 case ORIENT_ROTATED_180
: /* 180° */
271 /* right/top aligned */
272 MidY
= (output
->top
+ output
->bottom
) / 2.f
;
273 MidX
= (output
->left
+ output
->right
) / 2.f
;
274 top
= (src_height
- MidY
) / (output
->bottom
- MidY
);
275 bottom
= -MidY
/ (MidY
- output
->top
);
276 left
= -MidX
/ (MidX
- output
->left
);
277 right
= (src_width
- MidX
) / (output
->right
- MidX
);
279 case ORIENT_ROTATED_270
: /* 90° clockwise */
280 /* right/top aligned */
281 MidY
= (output
->left
+ output
->right
) / 2.f
;
282 MidX
= (output
->top
+ output
->bottom
) / 2.f
;
283 top
= (src_width
- MidX
) / (output
->right
- MidX
);
284 bottom
= -MidY
/ (MidY
- output
->top
);
285 left
= -MidX
/ (MidX
- output
->left
);
286 right
= (src_height
- MidY
) / (output
->bottom
- MidY
);
288 case ORIENT_ANTI_TRANSPOSED
:
289 MidY
= (output
->left
+ output
->right
) / 2.f
;
290 MidX
= (output
->top
+ output
->bottom
) / 2.f
;
291 top
= (src_width
- MidX
) / (output
->right
- MidX
);
292 bottom
= -MidY
/ (MidY
- output
->top
);
293 left
= -(src_height
- MidY
) / (output
->bottom
- MidY
);
294 right
= MidX
/ (MidX
- output
->left
);
296 case ORIENT_TRANSPOSED
:
297 MidY
= (output
->left
+ output
->right
) / 2.f
;
298 MidX
= (output
->top
+ output
->bottom
) / 2.f
;
299 top
= (src_width
- MidX
) / (output
->right
- MidX
);
300 bottom
= -MidY
/ (MidY
- output
->top
);
301 left
= -MidX
/ (MidX
- output
->left
);
302 right
= (src_height
- MidY
) / (output
->bottom
- MidY
);
304 case ORIENT_VFLIPPED
:
305 MidY
= (output
->top
+ output
->bottom
) / 2.f
;
306 MidX
= (output
->left
+ output
->right
) / 2.f
;
307 top
= (src_height
- MidY
) / (output
->bottom
- MidY
);
308 bottom
= -MidY
/ (MidY
- output
->top
);
309 left
= -MidX
/ (MidX
- output
->left
);
310 right
= (src_width
- MidX
) / (output
->right
- MidX
);
312 case ORIENT_HFLIPPED
:
313 MidY
= (output
->top
+ output
->bottom
) / 2.f
;
314 MidX
= (output
->left
+ output
->right
) / 2.f
;
315 top
= MidY
/ (MidY
- output
->top
);
316 bottom
= -(src_height
- MidY
) / (output
->bottom
- MidY
);
317 left
= -(src_width
- MidX
) / (output
->right
- MidX
);
318 right
= MidX
/ (MidX
- output
->left
);
322 /* left/top aligned */
323 MidY
= (output
->top
+ output
->bottom
) / 2.f
;
324 MidX
= (output
->left
+ output
->right
) / 2.f
;
325 top
= MidY
/ (MidY
- output
->top
);
326 bottom
= -(src_height
- MidY
) / (output
->bottom
- MidY
);
327 left
= -MidX
/ (MidX
- output
->left
);
328 right
= (src_width
- MidX
) / (output
->right
- MidX
);
332 const float vertices_coords
[4][2] = {
339 /* Compute index remapping necessary to implement the rotation. */
341 orientationVertexOrder(orientation
, vertex_order
);
343 for (int i
= 0; i
< 4; ++i
) {
344 dst_data
[i
].position
.x
= vertices_coords
[vertex_order
[i
]][0];
345 dst_data
[i
].position
.y
= vertices_coords
[vertex_order
[i
]][1];
349 dst_data
[0].position
.z
= 0.0f
;
350 dst_data
[0].texture
.x
= 0.0f
;
351 dst_data
[0].texture
.y
= 1.0f
;
354 dst_data
[1].position
.z
= 0.0f
;
355 dst_data
[1].texture
.x
= 1.0f
;
356 dst_data
[1].texture
.y
= 1.0f
;
359 dst_data
[2].position
.z
= 0.0f
;
360 dst_data
[2].texture
.x
= 1.0f
;
361 dst_data
[2].texture
.y
= 0.0f
;
364 dst_data
[3].position
.z
= 0.0f
;
365 dst_data
[3].texture
.x
= 0.0f
;
366 dst_data
[3].texture
.y
= 0.0f
;
368 /* Make sure surfaces are facing the right way */
369 if( orientation
== ORIENT_TOP_RIGHT
|| orientation
== ORIENT_BOTTOM_LEFT
370 || orientation
== ORIENT_LEFT_TOP
|| orientation
== ORIENT_RIGHT_BOTTOM
)
392 static void SetupQuadSphere(d3d_vertex_t
*dst_data
, const RECT
*output
,
393 const d3d_quad_t
*quad
, WORD
*triangle_pos
)
395 const float scaleX
= (float)(output
->right
- output
->left
) / quad
->i_width
;
396 const float scaleY
= (float)(output
->bottom
- output
->top
) / quad
->i_height
;
397 for (unsigned lat
= 0; lat
<= nbLatBands
; lat
++) {
398 float theta
= lat
* (float) M_PI
/ nbLatBands
;
399 float sinTheta
, cosTheta
;
401 sincosf(theta
, &sinTheta
, &cosTheta
);
403 for (unsigned lon
= 0; lon
<= nbLonBands
; lon
++) {
404 float phi
= lon
* 2 * (float) M_PI
/ nbLonBands
;
405 float sinPhi
, cosPhi
;
407 sincosf(phi
, &sinPhi
, &cosPhi
);
409 float x
= cosPhi
* sinTheta
;
411 float z
= sinPhi
* sinTheta
;
413 unsigned off1
= lat
* (nbLonBands
+ 1) + lon
;
414 dst_data
[off1
].position
.x
= SPHERE_RADIUS
* x
;
415 dst_data
[off1
].position
.y
= SPHERE_RADIUS
* y
;
416 dst_data
[off1
].position
.z
= SPHERE_RADIUS
* z
;
418 dst_data
[off1
].texture
.x
= scaleX
* lon
/ (float) nbLonBands
; // 0(left) to 1(right)
419 dst_data
[off1
].texture
.y
= scaleY
* lat
/ (float) nbLatBands
; // 0(top) to 1 (bottom)
423 for (unsigned lat
= 0; lat
< nbLatBands
; lat
++) {
424 for (unsigned lon
= 0; lon
< nbLonBands
; lon
++) {
425 unsigned first
= (lat
* (nbLonBands
+ 1)) + lon
;
426 unsigned second
= first
+ nbLonBands
+ 1;
428 unsigned off
= (lat
* nbLatBands
+ lon
) * 3 * 2;
430 triangle_pos
[off
] = first
;
431 triangle_pos
[off
+ 1] = first
+ 1;
432 triangle_pos
[off
+ 2] = second
;
434 triangle_pos
[off
+ 3] = second
;
435 triangle_pos
[off
+ 4] = first
+ 1;
436 triangle_pos
[off
+ 5] = second
+ 1;
442 static void SetupQuadCube(d3d_vertex_t
*dst_data
, const RECT
*output
,
443 const d3d_quad_t
*quad
, WORD
*triangle_pos
)
445 static const float coord
[] = {
446 -1.0, 1.0, -1.0f
, // front
451 -1.0, 1.0, 1.0f
, // back
456 -1.0, 1.0, -1.0f
, // left
461 1.0f
, 1.0, -1.0f
, // right
466 -1.0, -1.0, 1.0f
, // bottom
471 -1.0, 1.0, 1.0f
, // top
477 const float scaleX
= (float)(output
->right
- output
->left
) / quad
->i_width
;
478 const float scaleY
= (float)(output
->bottom
- output
->top
) / quad
->i_height
;
480 const float col
[] = {0.f
, scaleX
/ 3, scaleX
* 2 / 3, scaleX
};
481 const float row
[] = {0.f
, scaleY
/ 2, scaleY
};
483 const float tex
[] = {
484 col
[1], row
[1], // front
489 col
[3], row
[1], // back
494 col
[2], row
[0], // left
499 col
[0], row
[0], // right
504 col
[0], row
[2], // bottom
509 col
[2], row
[0], // top
515 const unsigned i_nbVertices
= ARRAY_SIZE(coord
) / 3;
517 for (unsigned v
= 0; v
< i_nbVertices
; ++v
)
519 dst_data
[v
].position
.x
= coord
[3 * v
];
520 dst_data
[v
].position
.y
= coord
[3 * v
+ 1];
521 dst_data
[v
].position
.z
= coord
[3 * v
+ 2];
523 dst_data
[v
].texture
.x
= tex
[2 * v
];
524 dst_data
[v
].texture
.y
= tex
[2 * v
+ 1];
528 2, 1, 0, 3, 1, 2, // front
529 4, 7, 6, 5, 7, 4, // back
530 8, 11, 10, 9, 11, 8, // left
531 14, 13, 12, 15, 13, 14, // right
532 16, 19, 18, 17, 19, 16, // bottom
533 22, 21, 20, 23, 21, 22, // top
536 memcpy(triangle_pos
, ind
, sizeof(ind
));
539 #undef D3D11_UpdateQuadPosition
540 bool D3D11_UpdateQuadPosition( vlc_object_t
*o
, d3d11_device_t
*d3d_dev
, d3d_quad_t
*quad
,
541 const RECT
*output
, video_orientation_t orientation
)
544 D3D11_MAPPED_SUBRESOURCE mappedResource
;
546 if (unlikely(quad
->pVertexBuffer
== NULL
))
549 /* create the vertices */
550 hr
= ID3D11DeviceContext_Map(d3d_dev
->d3dcontext
, (ID3D11Resource
*)quad
->pVertexBuffer
, 0, D3D11_MAP_WRITE_DISCARD
, 0, &mappedResource
);
552 msg_Err(o
, "Failed to lock the vertex buffer (hr=0x%lX)", hr
);
555 d3d_vertex_t
*dst_data
= mappedResource
.pData
;
557 /* create the vertex indices */
558 hr
= ID3D11DeviceContext_Map(d3d_dev
->d3dcontext
, (ID3D11Resource
*)quad
->pIndexBuffer
, 0, D3D11_MAP_WRITE_DISCARD
, 0, &mappedResource
);
560 msg_Err(o
, "Failed to lock the index buffer (hr=0x%lX)", hr
);
561 ID3D11DeviceContext_Unmap(d3d_dev
->d3dcontext
, (ID3D11Resource
*)quad
->pVertexBuffer
, 0);
564 WORD
*triangle_pos
= mappedResource
.pData
;
566 switch (quad
->projection
)
568 case PROJECTION_MODE_RECTANGULAR
:
569 SetupQuadFlat(dst_data
, output
, quad
, triangle_pos
, orientation
);
571 case PROJECTION_MODE_EQUIRECTANGULAR
:
572 SetupQuadSphere(dst_data
, output
, quad
, triangle_pos
);
574 case PROJECTION_MODE_CUBEMAP_LAYOUT_STANDARD
:
575 SetupQuadCube(dst_data
, output
, quad
, triangle_pos
);
578 msg_Warn(o
, "Projection mode %d not handled", quad
->projection
);
582 ID3D11DeviceContext_Unmap(d3d_dev
->d3dcontext
, (ID3D11Resource
*)quad
->pIndexBuffer
, 0);
583 ID3D11DeviceContext_Unmap(d3d_dev
->d3dcontext
, (ID3D11Resource
*)quad
->pVertexBuffer
, 0);
588 static bool ShaderUpdateConstants(vlc_object_t
*o
, d3d11_device_t
*d3d_dev
, d3d_quad_t
*quad
)
590 D3D11_MAPPED_SUBRESOURCE mappedResource
;
591 HRESULT hr
= ID3D11DeviceContext_Map(d3d_dev
->d3dcontext
, (ID3D11Resource
*)quad
->pPixelShaderConstants
[0], 0, D3D11_MAP_WRITE_DISCARD
, 0, &mappedResource
);
594 msg_Err(o
, "Failed to lock the picture shader constants (hr=0x%lX)", hr
);
598 PS_CONSTANT_BUFFER
*dst_data
= mappedResource
.pData
;
599 *dst_data
= quad
->shaderConstants
;
600 ID3D11DeviceContext_Unmap(d3d_dev
->d3dcontext
, (ID3D11Resource
*)quad
->pPixelShaderConstants
[0], 0);
604 #undef D3D11_UpdateQuadOpacity
605 void D3D11_UpdateQuadOpacity(vlc_object_t
*o
, d3d11_device_t
*d3d_dev
, d3d_quad_t
*quad
, float opacity
)
607 if (quad
->shaderConstants
.Opacity
== opacity
)
610 float old
= quad
->shaderConstants
.Opacity
;
611 quad
->shaderConstants
.Opacity
= opacity
;
612 if (!ShaderUpdateConstants(o
, d3d_dev
, quad
))
613 quad
->shaderConstants
.Opacity
= old
;
616 #undef D3D11_UpdateQuadLuminanceScale
617 void D3D11_UpdateQuadLuminanceScale(vlc_object_t
*o
, d3d11_device_t
*d3d_dev
, d3d_quad_t
*quad
, float luminanceScale
)
619 if (quad
->shaderConstants
.LuminanceScale
== luminanceScale
)
622 float old
= quad
->shaderConstants
.LuminanceScale
;
623 quad
->shaderConstants
.LuminanceScale
= luminanceScale
;
624 if (!ShaderUpdateConstants(o
, d3d_dev
, quad
))
625 quad
->shaderConstants
.LuminanceScale
= old
;
628 #undef D3D11_SetupQuad
629 int D3D11_SetupQuad(vlc_object_t
*o
, d3d11_device_t
*d3d_dev
, const video_format_t
*fmt
, d3d_quad_t
*quad
,
630 const display_info_t
*displayFormat
, const RECT
*output
,
631 ID3D11VertexShader
*d3dvertexShader
, ID3D11InputLayout
*pVertexLayout
,
632 video_projection_mode_t projection
, video_orientation_t orientation
)
635 const bool RGB_shader
= IsRGBShader(quad
->formatInfo
);
637 quad
->shaderConstants
.LuminanceScale
= GetFormatLuminance(o
, fmt
) / (float)displayFormat
->luminance_peak
;
639 /* pixel shader constant buffer */
640 quad
->shaderConstants
.Opacity
= 1.0;
641 if (fmt
->i_visible_width
== fmt
->i_width
)
642 quad
->shaderConstants
.BoundaryX
= 1.0; /* let texture clamping happen */
644 quad
->shaderConstants
.BoundaryX
= (FLOAT
) (fmt
->i_visible_width
- 1) / fmt
->i_width
;
645 if (fmt
->i_visible_height
== fmt
->i_height
)
646 quad
->shaderConstants
.BoundaryY
= 1.0; /* let texture clamping happen */
648 quad
->shaderConstants
.BoundaryY
= (FLOAT
) (fmt
->i_visible_height
- 1) / fmt
->i_height
;
650 static_assert((sizeof(PS_CONSTANT_BUFFER
)%16)==0,"Constant buffers require 16-byte alignment");
651 D3D11_BUFFER_DESC constantDesc
= {
652 .Usage
= D3D11_USAGE_DYNAMIC
,
653 .ByteWidth
= sizeof(PS_CONSTANT_BUFFER
),
654 .BindFlags
= D3D11_BIND_CONSTANT_BUFFER
,
655 .CPUAccessFlags
= D3D11_CPU_ACCESS_WRITE
,
657 D3D11_SUBRESOURCE_DATA constantInit
= { .pSysMem
= &quad
->shaderConstants
};
658 hr
= ID3D11Device_CreateBuffer(d3d_dev
->d3ddevice
, &constantDesc
, &constantInit
, &quad
->pPixelShaderConstants
[0]);
660 msg_Err(o
, "Could not create the pixel shader constant buffer. (hr=0x%lX)", hr
);
664 FLOAT itu_black_level
= 0.f
;
665 FLOAT itu_achromacy
= 0.f
;
668 switch (quad
->formatInfo
->bitsPerChannel
)
671 /* Rec. ITU-R BT.709-6 §4.6 */
672 itu_black_level
= 16.f
/ 255.f
;
673 itu_achromacy
= 128.f
/ 255.f
;
676 /* Rec. ITU-R BT.709-6 §4.6 */
677 itu_black_level
= 64.f
/ 1023.f
;
678 itu_achromacy
= 512.f
/ 1023.f
;
681 /* Rec. ITU-R BT.2020-2 Table 5 */
682 itu_black_level
= 256.f
/ 4095.f
;
683 itu_achromacy
= 2048.f
/ 4095.f
;
686 /* unknown bitdepth, use approximation for infinite bit depth */
687 itu_black_level
= 16.f
/ 256.f
;
688 itu_achromacy
= 128.f
/ 256.f
;
693 static const FLOAT IDENTITY_4X4
[4 * 4] = {
700 /* matrices for studio range */
701 /* see https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion, in studio range */
702 static const FLOAT COLORSPACE_BT601_YUV_TO_FULL_RGBA
[4*4] = {
703 1.164383561643836f
, 0.f
, 1.596026785714286f
, 0.f
,
704 1.164383561643836f
, -0.391762290094914f
, -0.812967647237771f
, 0.f
,
705 1.164383561643836f
, 2.017232142857142f
, 0.f
, 0.f
,
708 /* see https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.709_conversion, in studio range */
709 static const FLOAT COLORSPACE_BT709_YUV_TO_FULL_RGBA
[4*4] = {
710 1.164383561643836f
, 0.f
, 1.792741071428571f
, 0.f
,
711 1.164383561643836f
, -0.213248614273730f
, -0.532909328559444f
, 0.f
,
712 1.164383561643836f
, 2.112401785714286f
, 0.f
, 0.f
,
715 /* see https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.2020_conversion, in studio range */
716 static const FLOAT COLORSPACE_BT2020_YUV_TO_FULL_RGBA
[4*4] = {
717 1.164383561643836f
, 0.000000000000f
, 1.678674107143f
, 0.f
,
718 1.164383561643836f
, -0.127007098661f
, -0.440987687946f
, 0.f
,
719 1.164383561643836f
, 2.141772321429f
, 0.000000000000f
, 0.f
,
723 PS_COLOR_TRANSFORM colorspace
;
725 memcpy(colorspace
.WhitePoint
, IDENTITY_4X4
, sizeof(colorspace
.WhitePoint
));
727 const FLOAT
*ppColorspace
;
729 ppColorspace
= IDENTITY_4X4
;
732 case COLOR_SPACE_BT709
:
733 ppColorspace
= COLORSPACE_BT709_YUV_TO_FULL_RGBA
;
735 case COLOR_SPACE_BT2020
:
736 ppColorspace
= COLORSPACE_BT2020_YUV_TO_FULL_RGBA
;
738 case COLOR_SPACE_BT601
:
739 ppColorspace
= COLORSPACE_BT601_YUV_TO_FULL_RGBA
;
742 case COLOR_SPACE_UNDEF
:
743 if( fmt
->i_height
> 576 )
744 ppColorspace
= COLORSPACE_BT709_YUV_TO_FULL_RGBA
;
746 ppColorspace
= COLORSPACE_BT601_YUV_TO_FULL_RGBA
;
749 /* all matrices work in studio range and output in full range */
750 colorspace
.WhitePoint
[0*4 + 3] = -itu_black_level
;
751 colorspace
.WhitePoint
[1*4 + 3] = -itu_achromacy
;
752 colorspace
.WhitePoint
[2*4 + 3] = -itu_achromacy
;
755 memcpy(colorspace
.Colorspace
, ppColorspace
, sizeof(colorspace
.Colorspace
));
757 constantInit
.pSysMem
= &colorspace
;
759 static_assert((sizeof(PS_COLOR_TRANSFORM
)%16)==0,"Constant buffers require 16-byte alignment");
760 constantDesc
.ByteWidth
= sizeof(PS_COLOR_TRANSFORM
);
761 hr
= ID3D11Device_CreateBuffer(d3d_dev
->d3ddevice
, &constantDesc
, &constantInit
, &quad
->pPixelShaderConstants
[1]);
763 msg_Err(o
, "Could not create the pixel shader constant buffer. (hr=0x%lX)", hr
);
766 quad
->PSConstantsCount
= 2;
767 quad
->projection
= projection
;
769 /* vertex shader constant buffer */
770 if (projection
== PROJECTION_MODE_EQUIRECTANGULAR
771 || projection
== PROJECTION_MODE_CUBEMAP_LAYOUT_STANDARD
)
773 constantDesc
.ByteWidth
= sizeof(VS_PROJECTION_CONST
);
774 static_assert((sizeof(VS_PROJECTION_CONST
)%16)==0,"Constant buffers require 16-byte alignment");
775 hr
= ID3D11Device_CreateBuffer(d3d_dev
->d3ddevice
, &constantDesc
, NULL
, &quad
->pVertexShaderConstants
);
777 msg_Err(o
, "Could not create the vertex shader constant buffer. (hr=0x%lX)", hr
);
782 quad
->picSys
.formatTexture
= quad
->formatInfo
->formatTexture
;
783 quad
->picSys
.context
= d3d_dev
->d3dcontext
;
784 ID3D11DeviceContext_AddRef(quad
->picSys
.context
);
786 if (!AllocQuadVertices(o
, d3d_dev
, quad
))
788 if (!D3D11_UpdateQuadPosition(o
, d3d_dev
, quad
, output
, orientation
))
791 for (size_t i
=0; i
<D3D11_MAX_SHADER_VIEW
; i
++)
793 quad
->cropViewport
[i
].MinDepth
= 0.0f
;
794 quad
->cropViewport
[i
].MaxDepth
= 1.0f
;
796 quad
->d3dvertexShader
= d3dvertexShader
;
797 quad
->pVertexLayout
= pVertexLayout
;
798 quad
->resourceCount
= DxgiResourceCount(quad
->formatInfo
);
803 D3D11_ReleaseQuad(quad
);
807 void D3D11_UpdateViewport(d3d_quad_t
*quad
, const RECT
*rect
)
809 quad
->cropViewport
[0].TopLeftX
= rect
->left
;
810 quad
->cropViewport
[0].TopLeftY
= rect
->top
;
811 quad
->cropViewport
[0].Width
= rect
->right
- rect
->left
;
812 quad
->cropViewport
[0].Height
= rect
->bottom
- rect
->top
;
814 if ( quad
->formatInfo
->formatTexture
== DXGI_FORMAT_NV12
||
815 quad
->formatInfo
->formatTexture
== DXGI_FORMAT_P010
)
817 quad
->cropViewport
[1].TopLeftX
= rect
->left
/ 2;
818 quad
->cropViewport
[1].TopLeftY
= rect
->top
/ 2;
819 quad
->cropViewport
[1].Width
= (rect
->right
- rect
->left
) / 2;
820 quad
->cropViewport
[1].Height
= (rect
->bottom
- rect
->top
) / 2;