1 /*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include "config.h"
20
21 #if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0A00
22 #undef _WIN32_WINNT
23 #define _WIN32_WINNT 0x0A00
24 #endif
25
26 #include <windows.h>
27
29
30 #include <initguid.h>
31 #include <d3d11.h>
32 #include <dxgi1_2.h>
33 #if HAVE_IDXGIOUTPUT5
34 #include <dxgi1_5.h>
35 #endif
36
48
50
51 // avutil/time.h takes and returns time in microseconds
52 #define TIMER_RES 1000000
53 #define TIMER_RES64 INT64_C(1000000)
54
57
61
65
69
75
80
84
87
95
108
109 #define OFFSET(x) offsetof(DdagrabContext, x)
110 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
119 {
"auto",
"let dda pick its preferred format", 0,
AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, INT_MAX,
FLAGS, .unit =
"output_fmt" },
122 {
"10bit",
"only output default 10 Bit format", 0,
AV_OPT_TYPE_CONST, { .i64 = DXGI_FORMAT_R10G10B10A2_UNORM }, 0, INT_MAX,
FLAGS, .unit =
"output_fmt" },
123 {
"x2bgr10",
"only output 10 Bit X2BGR10", 0,
AV_OPT_TYPE_CONST, { .i64 = DXGI_FORMAT_R10G10B10A2_UNORM }, 0, INT_MAX,
FLAGS, .unit =
"output_fmt" },
126 { "allow_fallback", "don't error on fallback to default 8 Bit format",
128 { "force_fmt", "exclude BGRA from format list (experimental, discouraged by Microsoft)",
130 { "dup_frames", "duplicate frames to maintain framerate",
133 };
134
136
138 {
139 IUnknown **resp = (IUnknown**)resource;
140 if (*resp) {
141 IUnknown_Release(*resp);
143 }
144 }
145
147 {
149
157
160
166
170 }
171
173 {
175 IDXGIDevice *dxgi_device =
NULL;
176 IDXGIAdapter *dxgi_adapter =
NULL;
177 IDXGIOutput *dxgi_output =
NULL;
178 IDXGIOutput1 *dxgi_output1 =
NULL;
179 #if HAVE_IDXGIOUTPUT5 && HAVE_DPI_AWARENESS_CONTEXT
180 IDXGIOutput5 *dxgi_output5 =
NULL;
181
182 typedef DPI_AWARENESS_CONTEXT (*set_thread_dpi_t)(DPI_AWARENESS_CONTEXT);
183 set_thread_dpi_t set_thread_dpi;
184 HMODULE user32_module;
185 #endif
187 HRESULT hr;
188
189 hr = ID3D11Device_QueryInterface(dda->
device_hwctx->
device, &IID_IDXGIDevice, (
void**)&dxgi_device);
190 if (FAILED(hr)) {
193 }
194
195 hr = IDXGIDevice_GetParent(dxgi_device, &IID_IDXGIAdapter, (void**)&dxgi_adapter);
196 IDXGIDevice_Release(dxgi_device);
198 if (FAILED(hr)) {
201 }
202
203 hr = IDXGIAdapter_EnumOutputs(dxgi_adapter, dda->
output_idx, &dxgi_output);
204 IDXGIAdapter_Release(dxgi_adapter);
206 if (FAILED(hr)) {
209 }
210
211 hr = IDXGIOutput_GetDesc(dxgi_output, &dda->
output_desc);
212 if (FAILED(hr)) {
213 IDXGIOutput_Release(dxgi_output);
216 }
217
218 #if HAVE_IDXGIOUTPUT5 && HAVE_DPI_AWARENESS_CONTEXT
219 user32_module = dlopen("user32.dll", 0);
220 if (!user32_module) {
223 }
224
225 set_thread_dpi = (set_thread_dpi_t)dlsym(user32_module, "SetThreadDpiAwarenessContext");
226
227 if (set_thread_dpi)
228 hr = IDXGIOutput_QueryInterface(dxgi_output, &IID_IDXGIOutput5, (void**)&dxgi_output5);
229
230 if (set_thread_dpi && SUCCEEDED(hr)) {
231 DPI_AWARENESS_CONTEXT prev_dpi_ctx;
234 DXGI_FORMAT_R10G10B10A2_UNORM,
236 };
238
241 nb_formats = 1;
246 }
247
248 IDXGIOutput_Release(dxgi_output);
250
251 prev_dpi_ctx = set_thread_dpi(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
252 if (!prev_dpi_ctx)
254
255 hr = IDXGIOutput5_DuplicateOutput1(dxgi_output5,
257 0,
258 nb_formats,
261 IDXGIOutput5_Release(dxgi_output5);
263
264 if (prev_dpi_ctx)
265 set_thread_dpi(prev_dpi_ctx);
266
267 dlclose(user32_module);
268 user32_module =
NULL;
269 set_thread_dpi =
NULL;
270
272 } else {
273 dlclose(user32_module);
274 user32_module =
NULL;
275 set_thread_dpi =
NULL;
276
278 #else
279 {
280 #endif
284 }
285
286 hr = IDXGIOutput_QueryInterface(dxgi_output, &IID_IDXGIOutput1, (void**)&dxgi_output1);
287 IDXGIOutput_Release(dxgi_output);
289 if (FAILED(hr)) {
292 }
293
294 hr = IDXGIOutput1_DuplicateOutput(dxgi_output1,
297 IDXGIOutput1_Release(dxgi_output1);
299 }
300
301 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) {
304 } else if (hr == DXGI_ERROR_UNSUPPORTED) {
307 } else if (hr == E_INVALIDARG) {
310 } else if (hr == E_ACCESSDENIED) {
313 } else if (FAILED(hr)) {
316 }
317
321
322 return 0;
323 }
324
326 {
329
332
334 {
335 { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
336 { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }
337 };
338
340 {
343 D3D11_SAMPLER_DESC sampler_desc = { 0 };
344 D3D11_BLEND_DESC blend_desc = { 0 };
345 D3D11_BUFFER_DESC buffer_desc = { 0 };
348 HRESULT hr;
349
350 hr = ID3D11Device_CreateVertexShader(dev,
355 if (FAILED(hr)) {
358 }
359
360 hr = ID3D11Device_CreateInputLayout(dev,
366 if (FAILED(hr)) {
369 }
370
371 hr = ID3D11Device_CreatePixelShader(dev,
376 if (FAILED(hr)) {
379 }
380
382
384 buffer_desc.ByteWidth = sizeof(const_data);
385 buffer_desc.Usage = D3D11_USAGE_IMMUTABLE;
386 buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
387 hr = ID3D11Device_CreateBuffer(dev,
388 &buffer_desc,
391 if (FAILED(hr)) {
394 }
395
396 sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
397 sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
398 sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
399 sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
400 sampler_desc.ComparisonFunc = D3D11_COMPARISON_NEVER;
401 hr = ID3D11Device_CreateSamplerState(dev,
402 &sampler_desc,
404 if (FAILED(hr)) {
407 }
408
409 blend_desc.AlphaToCoverageEnable = FALSE;
410 blend_desc.IndependentBlendEnable = FALSE;
411 blend_desc.RenderTarget[0].BlendEnable = TRUE;
412 blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
413 blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
414 blend_desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
415 blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
416 blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
417 blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
418 blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
419 hr = ID3D11Device_CreateBlendState(dev,
420 &blend_desc,
422 if (FAILED(hr)) {
425 }
426
427 blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_INV_DEST_COLOR;
428 blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_COLOR;
429 hr = ID3D11Device_CreateBlendState(dev,
430 &blend_desc,
432 if (FAILED(hr)) {
435 }
436
437 return 0;
438 }
439
441 {
443
447
450
451 return 0;
452 }
453
455 uint8_t *buf,
456 DXGI_OUTDUPL_POINTER_SHAPE_INFO *shape_info,
457 ID3D11Texture2D **out_tex,
458 ID3D11ShaderResourceView **res_view)
459 {
461 D3D11_TEXTURE2D_DESC
desc = { 0 };
462 D3D11_SUBRESOURCE_DATA init_data = { 0 };
463 D3D11_SHADER_RESOURCE_VIEW_DESC resource_desc = { 0 };
464 HRESULT hr;
465
469 desc.SampleDesc.Count = 1;
470 desc.SampleDesc.Quality = 0;
471 desc.Usage = D3D11_USAGE_IMMUTABLE;
472 desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
473
474 desc.Width = shape_info->Width;
475 desc.Height = shape_info->Height;
476
477 init_data.pSysMem = buf;
478 init_data.SysMemPitch = shape_info->Pitch;
479
480 resource_desc.Format =
desc.Format;
481 resource_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
482 resource_desc.Texture2D.MostDetailedMip = 0;
483 resource_desc.Texture2D.MipLevels = 1;
484
487 &init_data,
488 out_tex);
489 if (FAILED(hr)) {
492 }
493
495 (ID3D11Resource*)*out_tex,
496 &resource_desc,
497 res_view);
498 if (FAILED(hr)) {
502 }
503
504 return 0;
505 }
506
508 {
509 int width = *_width,
height = *_height, pitch = *_pitch;
510 int real_height =
height / 2;
511 int size = real_height * pitch;
512
515
516 int y, x;
517
518 if (!
output || !output_xor) {
522 }
523
524 for (y = 0; y < real_height; y++) {
525 for (x = 0; x <
width; x++) {
526 int in_pos = (y * pitch) + (x / 8);
527 int out_pos = 4 * ((y *
width) + x);
528 int and_val = (
input[in_pos] >> (7 - (x % 8))) & 1;
529 int xor_val = (
input[in_pos +
size] >> (7 - (x % 8))) & 1;
530
531 if (!and_val && !xor_val) {
532 // solid black
533 memset(&
output[out_pos], 0, 4);
534 output[out_pos + 3] = 0xFF;
535
536 // transparent
537 memset(&output_xor[out_pos], 0, 4);
538 } else if (and_val && !xor_val) {
539 // transparent
540 memset(&
output[out_pos], 0, 4);
541
542 // transparent
543 memset(&output_xor[out_pos], 0, 4);
544 } else if (!and_val && xor_val) {
545 // solid white
546 memset(&
output[out_pos], 0xFF, 4);
547
548 // transparent
549 memset(&output_xor[out_pos], 0, 4);
550 } else if (and_val && xor_val) {
551 // transparent
552 memset(&
output[out_pos], 0, 4);
553
554 // solid white -> invert color
555 memset(&output_xor[out_pos], 0xFF, 4);
556 }
557 }
558 }
559
561 *_height = real_height;
563 *xor_out = output_xor;
564
565 return 0;
566 }
567
569 {
573 int x, y;
574
575 if (!
output || !output_xor) {
579 }
580
583
584 for (y = 0; y <
height; y++) {
585 for (x = 0; x <
width; x++) {
586 int pos = (y*pitch) + (4*x) + 3;
589 }
590 }
591
593 *xor_out = output_xor;
594
595 return 0;
596 }
597
599 {
601 HRESULT hr;
603
604 if (
frame_info->LastMouseUpdateTime.QuadPart == 0)
605 return 0;
606
609 case DXGI_MODE_ROTATION_ROTATE90:
612 break;
613 case DXGI_MODE_ROTATION_ROTATE180:
616 break;
617 case DXGI_MODE_ROTATION_ROTATE270:
620 break;
621 default:
624 }
625 } else {
627 }
628
631 DXGI_OUTDUPL_POINTER_SHAPE_INFO shape_info;
632 uint8_t *rgba_buf =
NULL, *rgb_xor_buf =
NULL;
634 if (!buf)
636
637 hr = IDXGIOutputDuplication_GetFramePointerShape(dda->
dxgi_outdupl,
639 buf,
641 &shape_info);
642 if (FAILED(hr)) {
646 }
647
648 if (shape_info.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME) {
649 ret =
convert_mono_buffer(buf, &rgba_buf, &rgb_xor_buf, &shape_info.Width, &shape_info.Height, &shape_info.Pitch);
653 } else if (shape_info.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR) {
654 ret =
fixup_color_mask(buf, &rgba_buf, &rgb_xor_buf, shape_info.Width, shape_info.Height, shape_info.Pitch);
658 } else if (shape_info.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR) {
659 rgba_buf = buf;
661 } else {
664 return 0;
665 }
666
671
678 if (ret2 < 0)
679 return ret2;
680
682 }
683
684 return 0;
685 }
686
688 {
691 IDXGIResource *desktop_resource =
NULL;
692 HRESULT hr;
694
695 hr = IDXGIOutputDuplication_AcquireNextFrame(
699 &desktop_resource);
700 if (hr == DXGI_ERROR_WAIT_TIMEOUT) {
702 } else if (FAILED(hr)) {
705 }
706
711 }
712
714 if (need_frame) {
717 }
718
719 // Unfortunately, we can't rely on the desktop_resource's format in this case.
720 // The API might even return it in with a format that was not in the initial
721 // list of supported formats, and it can change/flicker randomly.
722 // To work around this, return an internal copy of the last valid texture we got.
724
725 // The initial probing should make this impossible.
730 }
731
735 return 0;
736 }
737
738 hr = IDXGIResource_QueryInterface(desktop_resource, &IID_ID3D11Texture2D, (void**)desktop_texture);
740 if (FAILED(hr)) {
744 }
745
747 D3D11_TEXTURE2D_DESC
desc;
748 ID3D11Texture2D_GetDesc(*desktop_texture, &
desc);
749 desc.Usage = D3D11_USAGE_DEFAULT;
751 desc.CPUAccessFlags = 0;
753
755 if (FAILED(hr)) {
760 }
761 }
762
765 (ID3D11Resource*)*desktop_texture);
766
767 return 0;
768
771
772 hr = IDXGIOutputDuplication_ReleaseFrame(dda->
dxgi_outdupl);
773 if (FAILED(hr))
775
777 }
778
780 {
782 D3D11_TEXTURE2D_DESC
desc;
784
786
787 do {
792
794
798
803
804 return 0;
805 }
806
808 {
811
817
823
828 break;
829 case DXGI_FORMAT_R10G10B10A2_UNORM:
832 break;
836 break;
837 default:
840 }
841
844
849 }
850
851 return 0;
855 }
856
858 {
863
866
870 }
871
875
877 } else {
882 }
883
885
887 }
888
890
894
898
902 }
903
906
910
915 }
916
920
924
929
930 return 0;
931 }
932
934 {
937 ID3D11Texture2D *frame_tex = (ID3D11Texture2D*)
frame->data[0];
938 D3D11_RENDER_TARGET_VIEW_DESC target_desc = { 0 };
939 ID3D11RenderTargetView* target_view =
NULL;
940 ID3D11Buffer *mouse_vertex_buffer =
NULL;
941 D3D11_TEXTURE2D_DESC tex_desc, frame_desc;
942 int num_vertices = 0;
943 int x, y;
944 HRESULT hr;
946
948 return 0;
949
951 ID3D11Texture2D_GetDesc(frame_tex, &frame_desc);
952
955
957 -x >= (int)tex_desc.Width || -y >= (int)tex_desc.Height)
958 return 0;
959
960 target_desc.Format = frame_desc.Format;
961
962 if (frame_desc.ArraySize > 1) {
963 target_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
964 target_desc.Texture2DArray.ArraySize = 1;
965 target_desc.Texture2DArray.FirstArraySlice = (uintptr_t)
frame->data[1];
966 target_desc.Texture2DArray.MipSlice = 0;
967 } else {
968 target_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
969 target_desc.Texture2D.MipSlice = 0;
970 }
971
973 (ID3D11Resource*)frame_tex,
974 &target_desc,
975 &target_view);
976 if (FAILED(hr)) {
979 goto end;
980 }
981
982 ID3D11DeviceContext_ClearState(devctx);
983
984 {
985 D3D11_VIEWPORT viewport = { 0 };
986 viewport.Width = dda->
width;
987 viewport.Height = dda->
height;
988 viewport.MinDepth = 0.0f;
989 viewport.MaxDepth = 1.0f;
990
991 ID3D11DeviceContext_RSSetViewports(devctx, 1, &viewport);
992 }
993
994 {
996 // x, y, z, u, v
997 x , y + tex_desc.Height, 0.0f, 0.0f, 1.0f,
998 x , y , 0.0f, 0.0f, 0.0f,
999 x + tex_desc.Width, y + tex_desc.Height, 0.0f, 1.0f, 1.0f,
1000 x + tex_desc.Width, y , 0.0f, 1.0f, 0.0f,
1001 };
1004
1005 D3D11_SUBRESOURCE_DATA init_data = { 0 };
1006 D3D11_BUFFER_DESC buf_desc = { 0 };
1007
1009 case DXGI_MODE_ROTATION_ROTATE90:
1010 vertices[ 0] = x; vertices[ 1] = y;
1011 vertices[ 5] = x; vertices[ 6] = y - tex_desc.Width;
1012 vertices[10] = x + tex_desc.Height; vertices[11] = y;
1013 vertices[15] = x + tex_desc.Height; vertices[16] = y - tex_desc.Width;
1014 vertices[ 3] = 0.0f; vertices[ 4] = 0.0f;
1015 vertices[ 8] = 1.0f; vertices[ 9] = 0.0f;
1016 vertices[13] = 0.0f; vertices[14] = 1.0f;
1017 vertices[18] = 1.0f; vertices[19] = 1.0f;
1018 break;
1019 case DXGI_MODE_ROTATION_ROTATE180:
1020 vertices[ 0] = x - tex_desc.Width; vertices[ 1] = y;
1021 vertices[ 5] = x - tex_desc.Width; vertices[ 6] = y - tex_desc.Height;
1022 vertices[10] = x; vertices[11] = y;
1023 vertices[15] = x; vertices[16] = y - tex_desc.Height;
1024 vertices[ 3] = 1.0f; vertices[ 4] = 0.0f;
1025 vertices[ 8] = 1.0f; vertices[ 9] = 1.0f;
1026 vertices[13] = 0.0f; vertices[14] = 0.0f;
1027 vertices[18] = 0.0f; vertices[19] = 1.0f;
1028 break;
1029 case DXGI_MODE_ROTATION_ROTATE270:
1030 vertices[ 0] = x - tex_desc.Height; vertices[ 1] = y + tex_desc.Width;
1031 vertices[ 5] = x - tex_desc.Height; vertices[ 6] = y;
1032 vertices[10] = x; vertices[11] = y + tex_desc.Width;
1033 vertices[15] = x; vertices[16] = y;
1034 vertices[ 3] = 1.0f; vertices[ 4] = 1.0f;
1035 vertices[ 8] = 0.0f; vertices[ 9] = 1.0f;
1036 vertices[13] = 1.0f; vertices[14] = 0.0f;
1037 vertices[18] = 0.0f; vertices[19] = 0.0f;
1038 break;
1039 default:
1040 break;
1041 }
1042
1043 num_vertices =
sizeof(vertices) / (
sizeof(
FLOAT) * 5);
1044
1045 buf_desc.Usage = D3D11_USAGE_DEFAULT;
1046 buf_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
1047 buf_desc.ByteWidth = sizeof(vertices);
1048 init_data.pSysMem = vertices;
1049
1051 &buf_desc,
1052 &init_data,
1053 &mouse_vertex_buffer);
1054 if (FAILED(hr)) {
1057 goto end;
1058 }
1059
1060 ID3D11DeviceContext_IASetVertexBuffers(devctx, 0, 1, &mouse_vertex_buffer, &
stride, &
offset);
1061 ID3D11DeviceContext_IASetInputLayout(devctx, dda->
input_layout);
1062 ID3D11DeviceContext_IASetPrimitiveTopology(devctx, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
1063 }
1064
1066 ID3D11DeviceContext_VSSetConstantBuffers(devctx, 0, 1, &dda->
const_buffer);
1067 ID3D11DeviceContext_PSSetSamplers(devctx, 0, 1, &dda->
sampler_state);
1070
1071 ID3D11DeviceContext_OMSetBlendState(devctx, dda->
blend_state,
NULL, 0xFFFFFFFF);
1072 ID3D11DeviceContext_OMSetRenderTargets(devctx, 1, &target_view,
NULL);
1073
1074 ID3D11DeviceContext_Draw(devctx, num_vertices, 0);
1075
1079
1080 ID3D11DeviceContext_Draw(devctx, num_vertices, 0);
1081 }
1082
1083 end:
1086
1088 }
1089
1091 {
1094
1095 ID3D11Texture2D *cur_texture =
NULL;
1096 D3D11_TEXTURE2D_DESC
desc = { 0 };
1097 D3D11_BOX box = { 0 };
1098
1102 HRESULT hr;
1104
1105 /* time_frame is in units of microseconds divided by the time_base.
1106 * This means that adding a clean 1M to it is the equivalent of adding
1107 * 1M*time_base microseconds to it, except it avoids all rounding error.
1108 * The only time rounding error occurs is when multiplying to calculate
1109 * the delay. So any rounding error there corrects itself over time.
1110 */
1112 for (;;) {
1115 if (delay <= 0) {
1118 }
1119 break;
1120 }
1122 }
1123
1127
1129 do {
1132 } else {
1136 }
1137
1142
1147 }
1148
1150
1151 goto frame_done;
1155 }
else if (
ret < 0) {
1157 }
1158
1159 // AcquireNextFrame sometimes has bursts of delay.
1160 // This increases accuracy of the timestamp, but might upset consumers due to more jittery framerate?
1162
1163 ID3D11Texture2D_GetDesc(cur_texture, &
desc);
1170 }
1171
1176 }
1177
1180 box.right = box.left + dda->
width;
1181 box.bottom = box.top + dda->
height;
1182 box.front = 0;
1183 box.back = 1;
1184
1185 ID3D11DeviceContext_CopySubresourceRegion(
1187 (ID3D11Resource*)
frame->data[0], (UINT)(intptr_t)
frame->data[1],
1188 0, 0, 0,
1189 (ID3D11Resource*)cur_texture, 0,
1190 &box);
1191
1193
1194 hr = IDXGIOutputDuplication_ReleaseFrame(dda->
dxgi_outdupl);
1195 if (FAILED(hr)) {
1199 }
1200
1205 }
1206
1208
1210 desc.Format == DXGI_FORMAT_R10G10B10A2_UNORM) {
1211 // According to MSDN, all integer formats contain sRGB image data
1217 // According to MSDN, all floating point formats contain sRGB image data with linear 1.0 gamma.
1222 } else {
1225 }
1226
1230
1231 frame_done:
1234
1236
1240
1241 if (cur_texture)
1242 IDXGIOutputDuplication_ReleaseFrame(dda->
dxgi_outdupl);
1243
1246 }
1247
1249 {
1254 },
1255 };
1256
1258 .
p.
name =
"ddagrab",
1259 .p.description =
NULL_IF_CONFIG_SMALL(
"Grab Windows Desktop images using Desktop Duplication API"),
1260 .p.priv_class = &ddagrab_class,
1269 };