VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Video/disp/wddm/gallium/GaDxva.cpp@ 93299

Last change on this file since 93299 was 93299, checked in by vboxsync, 2 years ago

Add/win: VC++ 19.2 update 11 build adjustments. bugref:8489

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.4 KB
Line 
1/* $Id: GaDxva.cpp 93299 2022-01-18 11:23:59Z vboxsync $ */
2/** @file
3 * VirtualBox WDDM DXVA for the Gallium based driver.
4 */
5
6/*
7 * Copyright (C) 2019-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "../VBoxDispD3DCmn.h"
19
20#define D3D_RELEASE(ptr) do { \
21 if (ptr) \
22 { \
23 (ptr)->Release(); \
24 (ptr) = 0; \
25 } \
26} while (0)
27
28struct Vertex
29{
30 float x, y; /* The vertex position in pixels. */
31 float u, v; /* Normalized texture coordinates. */
32};
33
34/* Saved context. */
35typedef struct VBOXDXVAD3D9SAVEDSTATE
36{
37 D3DVIEWPORT9 Viewport;
38 DWORD rsCull;
39 DWORD rsZEnable;
40 IDirect3DSurface9 *pRT;
41 IDirect3DVertexShader9 *pVS;
42 IDirect3DPixelShader9 *pPS;
43 IDirect3DBaseTexture9 *pTexture;
44 float aVSConstantData[4];
45 float aPSConstantData[4];
46 DWORD ssMagFilter;
47 DWORD ssMinFilter;
48 DWORD ssMipFilter;
49} VBOXDXVAD3D9SAVEDSTATE;
50
51/*
52 * Draw a quad in order to convert the input resource to the output render target.
53 * The pixel shader will provide required conversion.
54 */
55typedef struct VBOXWDDMVIDEOPROCESSDEVICE
56{
57 /* Creation parameters. */
58 PVBOXWDDMDISP_DEVICE pDevice;
59 GUID VideoProcGuid;
60 DXVADDI_VIDEODESC VideoDesc;
61 D3DDDIFORMAT RenderTargetFormat;
62 UINT MaxSubStreams;
63
64 /* The current render target, i.e. the Blt destination. */
65 PVBOXWDDMDISP_RESOURCE pRenderTarget;
66 UINT RTSubResourceIndex;
67 IDirect3DTexture9 *pRTTexture;
68 IDirect3DSurface9 *pRTSurface;
69
70 /* Private objects for video processing. */
71 IDirect3DTexture9 *pStagingTexture; /* Intermediate texture. */
72 IDirect3DVertexBuffer9 *pVB; /* Vertex buffer which describes the quad we render. */
73 IDirect3DVertexDeclaration9 *pVertexDecl; /* Vertex declaration for the quad vertices. */
74 IDirect3DVertexShader9 *pVS; /* Vertex shader. */
75 IDirect3DPixelShader9 *pPS; /* Pixel shader. */
76
77 /* Saved D3D device state, which the blitter changes. */
78 VBOXDXVAD3D9SAVEDSTATE SavedState;
79} VBOXWDDMVIDEOPROCESSDEVICE;
80
81static GUID const gaDeviceGuids[] =
82{
83 DXVADDI_VideoProcProgressiveDevice,
84 DXVADDI_VideoProcBobDevice
85};
86
87static D3DDDIFORMAT const gaInputFormats[] =
88{
89 D3DDDIFMT_YUY2
90};
91
92static D3DDDIFORMAT const gaOutputFormats[] =
93{
94 D3DDDIFMT_A8R8G8B8,
95 D3DDDIFMT_X8R8G8B8
96};
97
98static int vboxDxvaFindDeviceGuid(GUID const *pGuid)
99{
100 for (int i = 0; i < RT_ELEMENTS(gaDeviceGuids); ++i)
101 {
102 if (memcmp(pGuid, &gaDeviceGuids[i], sizeof(GUID)) == 0)
103 return i;
104 }
105 return -1;
106}
107
108static int vboxDxvaFindInputFormat(D3DDDIFORMAT enmFormat)
109{
110 for (int i = 0; i < RT_ELEMENTS(gaInputFormats); ++i)
111 {
112 if (enmFormat == gaInputFormats[0])
113 return i;
114 }
115 return -1;
116}
117
118static HRESULT vboxDxvaCopyToVertexBuffer(IDirect3DVertexBuffer9 *pVB, const void *pvSrc, int cbSrc)
119{
120 void *pvDst = 0;
121 HRESULT hr = pVB->Lock(0, 0, &pvDst, 0);
122 if (SUCCEEDED(hr))
123 {
124 memcpy(pvDst, pvSrc, cbSrc);
125 hr = pVB->Unlock();
126 }
127 return hr;
128}
129
130static HRESULT vboxDxvaDeviceStateSave(IDirect3DDevice9 *pDevice9, VBOXDXVAD3D9SAVEDSTATE *pState)
131{
132 HRESULT hr;
133
134 hr = pDevice9->GetViewport(&pState->Viewport);
135 AssertReturn(hr == D3D_OK, hr);
136
137 hr = pDevice9->GetRenderState(D3DRS_CULLMODE, &pState->rsCull);
138 AssertReturn(hr == D3D_OK, hr);
139
140 hr = pDevice9->GetRenderState(D3DRS_ZENABLE, &pState->rsZEnable);
141 AssertReturn(hr == D3D_OK, hr);
142
143 hr = pDevice9->GetRenderTarget(0, &pState->pRT);
144 AssertReturn(hr == D3D_OK, hr);
145
146 hr = pDevice9->GetVertexShader(&pState->pVS);
147 AssertReturn(hr == D3D_OK, hr);
148
149 hr = pDevice9->GetPixelShader(&pState->pPS);
150 AssertReturn(hr == D3D_OK, hr);
151
152 hr = pDevice9->GetTexture(0, &pState->pTexture);
153 AssertReturn(hr == D3D_OK, hr);
154
155 hr = pDevice9->GetVertexShaderConstantF(0, pState->aVSConstantData, 1);
156 AssertReturn(hr == D3D_OK, hr);
157
158 hr = pDevice9->GetPixelShaderConstantF(0, pState->aPSConstantData, 1);
159 AssertReturn(hr == D3D_OK, hr);
160
161 hr = pDevice9->GetSamplerState(0, D3DSAMP_MAGFILTER, &pState->ssMagFilter);
162 AssertReturn(hr == D3D_OK, hr);
163
164 hr = pDevice9->GetSamplerState(0, D3DSAMP_MINFILTER, &pState->ssMinFilter);
165 AssertReturn(hr == D3D_OK, hr);
166
167 hr = pDevice9->GetSamplerState(0, D3DSAMP_MIPFILTER, &pState->ssMipFilter);
168 AssertReturn(hr == D3D_OK, hr);
169
170 return hr;
171}
172
173static void vboxDxvaDeviceStateRestore(IDirect3DDevice9 *pDevice9, VBOXDXVAD3D9SAVEDSTATE const *pState)
174{
175 HRESULT hr;
176
177 hr = pDevice9->SetViewport(&pState->Viewport);
178 Assert(hr == D3D_OK);
179
180 hr = pDevice9->SetRenderState(D3DRS_CULLMODE, pState->rsCull);
181 Assert(hr == D3D_OK);
182
183 hr = pDevice9->SetRenderState(D3DRS_ZENABLE, pState->rsZEnable);
184 Assert(hr == D3D_OK);
185
186 hr = pDevice9->SetRenderTarget(0, pState->pRT);
187 Assert(hr == D3D_OK);
188
189 hr = pDevice9->SetVertexShader(pState->pVS);
190 Assert(hr == D3D_OK);
191
192 hr = pDevice9->SetPixelShader(pState->pPS);
193 Assert(hr == D3D_OK);
194
195 hr = pDevice9->SetTexture(0, pState->pTexture);
196 Assert(hr == D3D_OK);
197
198 hr = pDevice9->SetVertexShaderConstantF(0, pState->aVSConstantData, 1);
199 Assert(hr == D3D_OK);
200
201 hr = pDevice9->SetPixelShaderConstantF(0, pState->aPSConstantData, 1);
202 Assert(hr == D3D_OK);
203
204 hr = pDevice9->SetSamplerState(0, D3DSAMP_MAGFILTER, pState->ssMagFilter);
205 Assert(hr == D3D_OK);
206
207 hr = pDevice9->SetSamplerState(0, D3DSAMP_MINFILTER, pState->ssMinFilter);
208 Assert(hr == D3D_OK);
209
210 hr = pDevice9->SetSamplerState(0, D3DSAMP_MIPFILTER, pState->ssMipFilter);
211 Assert(hr == D3D_OK);
212}
213
214static HRESULT vboxDxvaUploadSample(VBOXWDDMVIDEOPROCESSDEVICE *pVideoProcessDevice,
215 IDirect3DTexture9 *pSrcTexture,
216 UINT SrcSubResourceIndex)
217{
218 HRESULT hr;
219
220 /*
221 * Upload the source data to the staging texture.
222 */
223 D3DLOCKED_RECT StagingLockedRect;
224 hr = pVideoProcessDevice->pStagingTexture->LockRect(0, /* texture level */
225 &StagingLockedRect,
226 NULL, /* entire texture */
227 D3DLOCK_DISCARD);
228 Assert(hr == D3D_OK);
229 if (hr == D3D_OK)
230 {
231 D3DLOCKED_RECT SampleLockedRect;
232 hr = pSrcTexture->LockRect(SrcSubResourceIndex, /* texture level */
233 &SampleLockedRect,
234 NULL, /* entire texture */
235 D3DLOCK_READONLY);
236 Assert(hr == D3D_OK);
237 if (hr == D3D_OK)
238 {
239 uint8_t *pDst = (uint8_t *)StagingLockedRect.pBits;
240 const uint8_t *pSrc = (uint8_t *)SampleLockedRect.pBits;
241 for (uint32_t j = 0; j < pVideoProcessDevice->VideoDesc.SampleHeight; ++j)
242 {
243 memcpy(pDst, pSrc, RT_MIN(SampleLockedRect.Pitch, StagingLockedRect.Pitch));
244
245 pDst += StagingLockedRect.Pitch;
246 pSrc += SampleLockedRect.Pitch;
247 }
248
249 pSrcTexture->UnlockRect(SrcSubResourceIndex /* texture level */);
250 }
251 pVideoProcessDevice->pStagingTexture->UnlockRect(0 /* texture level */);
252 }
253
254 return hr;
255}
256
257/*
258 * The shader code has been obtained from the hex listing file (hexdump.txt) produced by fxc HLSL compiler:
259 * fxc.exe /Op /Tfx_2_0 /Fxhexdump.txt shader.fx
260 *
261 uniform extern float4 gTextureInfo; // .xy = (TargetWidth, TargetHeight), .zw = (SourceWidth, SourceHeight) in pixels
262 uniform extern texture gTexSource;
263 sampler sSource = sampler_state
264 {
265 Texture = <gTexSource>;
266 };
267
268 struct VS_INPUT
269 {
270 float2 Position : POSITION; // In pixels
271 float2 TexCoord : TEXCOORD0; // Normalized
272 };
273
274 struct VS_OUTPUT
275 {
276 float4 Position : POSITION; // Normalized
277 float2 TexCoord : TEXCOORD0; // Normalized
278 };
279
280 VS_OUTPUT VS(VS_INPUT In)
281 {
282 VS_OUTPUT Output;
283
284 // Target position is in pixels, i.e left,top is 0,0; right,bottom is width - 1,height - 1.
285 // Convert to the normalized coords in the -1;1 range (x right, y up).
286 float4 Position;
287 Position.x = 2.0f * In.Position.x / (gTextureInfo.x - 1.0f) - 1.0f;
288 Position.y = -2.0f * In.Position.y / (gTextureInfo.y - 1.0f) + 1.0f;
289 Position.z = 0.0f; // Not used.
290 Position.w = 1.0f; // It is a point.
291
292 Output.Position = Position;
293 Output.TexCoord = In.TexCoord;
294
295 return Output;
296 }
297
298 struct PS_OUTPUT
299 {
300 float4 Color : COLOR0;
301 };
302
303 static const float3x3 yuvCoeffs =
304 {
305 1.164383f, 1.164383f, 1.164383f,
306 0.0f, -0.391762f, 2.017232f,
307 1.596027f, -0.812968f, 0.0f
308 };
309
310 PS_OUTPUT PS(VS_OUTPUT In)
311 {
312 PS_OUTPUT Output;
313
314 // 4 bytes of an YUV macropixel contain 2 pixels in X for the target.
315 // I.e. each YUV texture pixel is sampled twice: for both even and odd target pixels.
316
317 // In.TexCoord are in [0;1] range for the source texture.
318 float2 texCoord = In.TexCoord;
319
320 // Source texture data is half width, i.e. it contains data in pixels [0; width / 2 - 1].
321 texCoord.x = texCoord.x / 2.0f;
322
323 // Which source pixel needs to be read: xPixel = TexCoord.x * SourceWidth.
324 float xSourcePixel = texCoord.x * gTextureInfo.z;
325
326 // Remainder is about 0.25 for even pixels and about 0.75 for odd pixels.
327 float remainder = xSourcePixel - trunc(xSourcePixel);
328
329 // Fetch YUV
330 float4 texColor = tex2D(sSource, texCoord);
331
332 // Get YUV components.
333 float y0 = texColor.b;
334 float u = texColor.g;
335 float y1 = texColor.r;
336 float v = texColor.a;
337
338 // Get y0 for even x coordinates and y1 for odd ones.
339 float y = remainder < 0.5f ? y0 : y1;
340
341 // Make a vector for easier calculation.
342 float3 yuv = float3(y, u, v);
343
344 // Convert YUV to RGB for BT.601:
345 // https://docs.microsoft.com/en-us/windows/win32/medfound/recommended-8-bit-yuv-formats-for-video-rendering#converting-8-bit-yuv-to-rgb888
346 //
347 // For 8bit [0;255] when Y = [16;235], U,V = [16;239]:
348 //
349 // C = Y - 16
350 // D = U - 128
351 // E = V - 128
352 //
353 // R = 1.164383 * C + 1.596027 * E
354 // G = 1.164383 * C - 0.391762 * D - 0.812968 * E
355 // B = 1.164383 * C + 2.017232 * D
356 //
357 // For shader values [0;1.0] when Y = [16/255;235/255], U,V = [16/255;239/255]:
358 //
359 // C = Y - 0.0627
360 // D = U - 0.5020
361 // E = V - 0.5020
362 //
363 // R = 1.164383 * C + 1.596027 * E
364 // G = 1.164383 * C - 0.391762 * D - 0.812968 * E
365 // B = 1.164383 * C + 2.017232 * D
366 //
367 yuv -= float3(0.0627f, 0.502f, 0.502f);
368 float3 bgr = mul(yuv, yuvCoeffs);
369
370 // Clamp to [0;1]
371 bgr = saturate(bgr);
372
373 // Return RGBA
374 Output.Color = float4(bgr, 1.0f);
375
376 return Output;
377 }
378
379 technique RenderScene
380 {
381 pass P0
382 {
383 VertexShader = compile vs_2_0 VS();
384 PixelShader = compile ps_2_0 PS();
385 }
386 }
387 */
388
389static DWORD const aVSCode[] =
390{
391 0xfffe0200, // vs_2_0
392 0x05000051, 0xa00f0001, 0xbf800000, 0xc0000000, 0x3f800000, 0x00000000, // def c1, -1, -2, 1, 0
393 0x0200001f, 0x80000000, 0x900f0000, // dcl_position v0
394 0x0200001f, 0x80000005, 0x900f0001, // dcl_texcoord v1
395 0x03000002, 0x80010000, 0x90000000, 0x90000000, // add r0.x, v0.x, v0.x
396 0x02000001, 0x80010001, 0xa0000001, // mov r1.x, c1.x
397 0x03000002, 0x80060000, 0x80000001, 0xa0d00000, // add r0.yz, r1.x, c0.xxyw
398 0x02000006, 0x80020000, 0x80550000, // rcp r0.y, r0.y
399 0x02000006, 0x80040000, 0x80aa0000, // rcp r0.z, r0.z
400 0x04000004, 0xc0010000, 0x80000000, 0x80550000, 0xa0000001, // mad oPos.x, r0.x, r0.y, c1.x
401 0x03000005, 0x80010000, 0x90550000, 0xa0550001, // mul r0.x, v0.y, c1.y
402 0x04000004, 0xc0020000, 0x80000000, 0x80aa0000, 0xa0aa0001, // mad oPos.y, r0.x, r0.z, c1.z
403 0x02000001, 0xc00c0000, 0xa0b40001, // mov oPos.zw, c1.xywz
404 0x02000001, 0xe0030000, 0x90e40001, // mov oT0.xy, v1
405 0x0000ffff
406};
407
408static DWORD const aPSCodeYUY2toRGB[] =
409{
410 0xffff0200, // ps_2_0
411 0x05000051, 0xa00f0005, 0x3f000000, 0x00000000, 0x3f800000, 0x3f000000, // def c5, 0.5, 0, 1, 0.5
412 0x0200001f, 0x80000000, 0xb0030000, // dcl t0.xy
413 0x0200001f, 0x90000000, 0xa00f0800, // dcl_2d s0
414 0x03000005, 0x80080000, 0xb0000000, 0xa0000005, // mul r0.w, t0.x, c5.x
415 0x03000005, 0x80010000, 0x80ff0000, 0xa0aa0000, // mul r0.x, r0.w, c0.z
416 0x02000013, 0x80020000, 0x80000000, // frc r0.y, r0.x
417 0x04000058, 0x80040000, 0x81550000, 0xa0550005, 0xa0aa0005, // cmp r0.z, -r0.y, c5.y, c5.z
418 0x03000002, 0x80020000, 0x80000000, 0x81550000, // add r0.y, r0.x, -r0.y
419 0x04000058, 0x80010000, 0x80000000, 0xa0550005, 0x80aa0000, // cmp r0.x, r0.x, c5.y, r0.z
420 0x03000002, 0x80010000, 0x80000000, 0x80550000, // add r0.x, r0.x, r0.y
421 0x04000004, 0x80010000, 0x80ff0000, 0xa0aa0000, 0x81000000, // mad r0.x, r0.w, c0.z, -r0.x
422 0x03000002, 0x80010000, 0x80000000, 0xa1ff0005, // add r0.x, r0.x, -c5.w
423 0x03000005, 0x80030001, 0xb0e40000, 0xa01b0005, // mul r1.xy, t0, c5.wzyx
424 0x03000042, 0x800f0001, 0x80e40001, 0xa0e40800, // texld r1, r1, s0
425 0x04000058, 0x80010001, 0x80000000, 0x80000001, 0x80aa0001, // cmp r1.x, r0.x, r1.x, r1.z
426 0x02000001, 0x80040001, 0x80ff0001, // mov r1.z, r1.w
427 0x03000002, 0x80070000, 0x80e40001, 0xa1e40001, // add r0.xyz, r1, -c1
428 0x03000008, 0x80110001, 0x80e40000, 0xa0e40002, // dp3_sat r1.x, r0, c2
429 0x03000008, 0x80120001, 0x80e40000, 0xa0e40003, // dp3_sat r1.y, r0, c3
430 0x03000008, 0x80140001, 0x80e40000, 0xa0e40004, // dp3_sat r1.z, r0, c4
431 0x02000001, 0x80080001, 0xa0aa0005, // mov r1.w, c5.z
432 0x02000001, 0x800f0800, 0x80e40001, // mov oC0, r1
433 0x0000ffff
434};
435
436
437static HRESULT vboxDxvaInit(VBOXWDDMVIDEOPROCESSDEVICE *pVideoProcessDevice)
438{
439 HRESULT hr;
440
441 IDirect3DDevice9 *pDevice9 = pVideoProcessDevice->pDevice->pDevice9If;
442
443 DWORD const *paVS = &aVSCode[0];
444 DWORD const *paPS = &aPSCodeYUY2toRGB[0];
445
446 static D3DVERTEXELEMENT9 const aVertexElements[] =
447 {
448 {0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
449 {0, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
450 D3DDECL_END()
451 };
452
453 hr = pDevice9->CreateVertexDeclaration(aVertexElements, &pVideoProcessDevice->pVertexDecl);
454 AssertReturn(hr == D3D_OK, hr);
455
456 hr = pDevice9->CreateVertexBuffer(6 * sizeof(Vertex), /* 2 triangles. */
457 D3DUSAGE_WRITEONLY,
458 0, /* FVF */
459 D3DPOOL_DEFAULT,
460 &pVideoProcessDevice->pVB,
461 0);
462 AssertReturn(hr == D3D_OK, hr);
463
464 hr = pDevice9->CreateVertexShader(paVS, &pVideoProcessDevice->pVS);
465 AssertReturn(hr == D3D_OK, hr);
466
467 hr = pDevice9->CreatePixelShader(paPS, &pVideoProcessDevice->pPS);
468 AssertReturn(hr == D3D_OK, hr);
469
470 hr = pDevice9->CreateTexture(pVideoProcessDevice->VideoDesc.SampleWidth,
471 pVideoProcessDevice->VideoDesc.SampleHeight,
472 0, /* Levels */
473 0, /* D3DUSAGE_ */
474 D3DFMT_A8R8G8B8, //D3DFMT_YUY2,
475 D3DPOOL_DEFAULT,
476 &pVideoProcessDevice->pStagingTexture,
477 NULL);
478 AssertReturn(hr == D3D_OK, hr);
479
480 return S_OK;
481}
482
483static float const aPSConstsBT601[] =
484{
485 0.062745f, 0.501961f, 0.501961f, 0.0f, // offsets
486 // Y U V
487 1.164384f, 0.000000f, 1.596027f, 0.0f, // R
488 1.164384f, -0.391762f, -0.812968f, 0.0f, // G
489 1.164384f, 2.017232f, 0.000000f, 0.0f, // B
490};
491static float const aPSConstsBT709[] =
492{
493 0.062745f, 0.501961f, 0.501961f, 0.0f, // offsets
494 // Y U V
495 1.164384f, 0.000000f, 1.792741f, 0.0f, // R
496 1.164384f, -0.213249f, -0.532909f, 0.0f, // G
497 1.164384f, 2.112402f, 0.000000f, 0.0f, // B
498};
499static float const aPSConstsSMPTE240M[] =
500{
501 0.062745f, 0.501961f, 0.501961f, 0.0f, // offsets
502 // Y U V
503 1.164384f, 0.000000f, 1.794107f, 0.0f, // R
504 1.164384f, -0.257985f, -0.542583f, 0.0f, // G
505 1.164384f, 2.078705f, 0.000000f, 0.0f, // B
506};
507
508static HRESULT vboxDxvaSetState(VBOXWDDMVIDEOPROCESSDEVICE *pVideoProcessDevice, DXVADDI_EXTENDEDFORMAT const *pSampleFormat)
509{
510 HRESULT hr;
511
512 IDirect3DDevice9 *pDevice9 = pVideoProcessDevice->pDevice->pDevice9If;
513
514 hr = pDevice9->SetStreamSource(0, pVideoProcessDevice->pVB, 0, sizeof(Vertex));
515 AssertReturn(hr == D3D_OK, hr);
516
517 hr = pDevice9->SetVertexDeclaration(pVideoProcessDevice->pVertexDecl);
518 AssertReturn(hr == D3D_OK, hr);
519
520 hr = pDevice9->SetVertexShader(pVideoProcessDevice->pVS);
521 AssertReturn(hr == D3D_OK, hr);
522
523 hr = pDevice9->SetPixelShader(pVideoProcessDevice->pPS);
524 AssertReturn(hr == D3D_OK, hr);
525
526 hr = pDevice9->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
527 AssertReturn(hr == D3D_OK, hr);
528
529 hr = pDevice9->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
530 AssertReturn(hr == D3D_OK, hr);
531
532 hr = pDevice9->SetTexture(0, pVideoProcessDevice->pStagingTexture);
533 AssertReturn(hr == D3D_OK, hr);
534
535 float const cTargetWidth = pVideoProcessDevice->pRenderTarget->aAllocations[0].SurfDesc.width;
536 float const cTargetHeight = pVideoProcessDevice->pRenderTarget->aAllocations[0].SurfDesc.height;
537
538 float const cSampleWidth = pVideoProcessDevice->VideoDesc.SampleWidth;
539 float const cSampleHeight = pVideoProcessDevice->VideoDesc.SampleHeight;
540
541 float aTextureInfo[4];
542 aTextureInfo[0] = cTargetWidth;
543 aTextureInfo[1] = cTargetHeight;
544 aTextureInfo[2] = cSampleWidth;
545 aTextureInfo[3] = cSampleHeight;
546
547 hr = pDevice9->SetVertexShaderConstantF(0, aTextureInfo, 1);
548 AssertReturn(hr == D3D_OK, hr);
549 hr = pDevice9->SetPixelShaderConstantF(0, aTextureInfo, 1);
550 AssertReturn(hr == D3D_OK, hr);
551
552 float const *pConstantData;
553 UINT Vector4fCount;
554 switch (pSampleFormat->VideoTransferMatrix)
555 {
556 case DXVADDI_VideoTransferMatrix_BT709:
557 pConstantData = aPSConstsBT709;
558 Vector4fCount = RT_ELEMENTS(aPSConstsBT709) / 4;
559 break;
560 case DXVADDI_VideoTransferMatrix_SMPTE240M:
561 pConstantData = aPSConstsSMPTE240M;
562 Vector4fCount = RT_ELEMENTS(aPSConstsSMPTE240M) / 4;
563 break;
564 case DXVADDI_VideoTransferMatrix_BT601:
565 default:
566 pConstantData = aPSConstsBT601;
567 Vector4fCount = RT_ELEMENTS(aPSConstsBT601) / 4;
568 break;
569 }
570
571 hr = pDevice9->SetPixelShaderConstantF(1, pConstantData, Vector4fCount);
572 AssertReturn(hr == D3D_OK, hr);
573
574 hr = pDevice9->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
575 AssertReturn(hr == D3D_OK, hr);
576 hr = pDevice9->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
577 AssertReturn(hr == D3D_OK, hr);
578 hr = pDevice9->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE);
579 AssertReturn(hr == D3D_OK, hr);
580
581 hr = pDevice9->SetRenderTarget(0, pVideoProcessDevice->pRTSurface);
582 AssertReturn(hr == D3D_OK, hr);
583
584 return S_OK;
585}
586
587static HRESULT vboxDxvaUpdateVertexBuffer(VBOXWDDMVIDEOPROCESSDEVICE *pVideoProcessDevice,
588 RECT const *pSrcRect,
589 RECT const *pDstRect)
590{
591 HRESULT hr;
592
593 /* Do not display anything if the source rectangle is not what is expected.
594 * But assert anyway in order to be able to investigate.
595 */
596 AssertReturn(pSrcRect->right > pSrcRect->left, S_OK);
597 AssertReturn(pSrcRect->bottom > pSrcRect->top, S_OK);
598
599 float const cSrcWidth = pVideoProcessDevice->VideoDesc.SampleWidth;
600 float const cSrcHeight = pVideoProcessDevice->VideoDesc.SampleHeight;
601
602 float const uSrcLeft = (float)pSrcRect->left / cSrcWidth;
603 float const uSrcRight = (float)pSrcRect->right / cSrcWidth;
604 float const vSrcTop = (float)pSrcRect->top / cSrcHeight;
605 float const vSrcBottom = (float)pSrcRect->bottom / cSrcHeight;
606
607 /* Subtract 0.5 to line up the pixel centers with texels
608 * https://docs.microsoft.com/en-us/windows/win32/direct3d9/directly-mapping-texels-to-pixels
609 */
610 float const xDstLeft = (float)pDstRect->left - 0.5f;
611 float const xDstRight = (float)pDstRect->right - 0.5f;
612 float const yDstTop = (float)pDstRect->top - 0.5f;
613 float const yDstBottom = (float)pDstRect->bottom - 0.5f;
614
615 Vertex const aVertices[] =
616 {
617 { xDstLeft, yDstTop, uSrcLeft, vSrcTop},
618 { xDstRight, yDstTop, uSrcRight, vSrcTop},
619 { xDstRight, yDstBottom, uSrcRight, vSrcBottom},
620
621 { xDstLeft, yDstTop, uSrcLeft, vSrcTop},
622 { xDstRight, yDstBottom, uSrcRight, vSrcBottom},
623 { xDstLeft, yDstBottom, uSrcLeft, vSrcBottom},
624 };
625
626 hr = vboxDxvaCopyToVertexBuffer(pVideoProcessDevice->pVB, aVertices, sizeof(aVertices));
627 AssertReturn(hr == D3D_OK, hr);
628
629 return S_OK;
630}
631
632static HRESULT vboxDxvaProcessBlt(VBOXWDDMVIDEOPROCESSDEVICE *pVideoProcessDevice,
633 D3DDDIARG_VIDEOPROCESSBLT const *pData,
634 IDirect3DTexture9 *paSrcTextures[])
635{
636 HRESULT hr;
637
638 IDirect3DDevice9 *pDevice9 = pVideoProcessDevice->pDevice->pDevice9If;
639
640 hr = vboxDxvaDeviceStateSave(pDevice9, &pVideoProcessDevice->SavedState);
641 if (hr == D3D_OK)
642 {
643 /* Set the required state for the blits, inclusding the render target. */
644 hr = vboxDxvaSetState(pVideoProcessDevice, &pData->pSrcSurfaces[0].SampleFormat);
645 if (hr == D3D_OK)
646 {
647 /* Clear the target rectangle. */
648 /** @todo Use pData->BackgroundColor */
649 D3DCOLOR BgColor = 0;
650 D3DRECT TargetRect;
651 TargetRect.x1 = pData->TargetRect.left;
652 TargetRect.y1 = pData->TargetRect.top;
653 TargetRect.x2 = pData->TargetRect.right;
654 TargetRect.y2 = pData->TargetRect.bottom;
655 hr = pDevice9->Clear(1, &TargetRect, D3DCLEAR_TARGET, BgColor, 0.0f, 0);
656 Assert(hr == D3D_OK); /* Ignore errors. */
657
658 DXVADDI_VIDEOSAMPLE const *pSrcSample = &pData->pSrcSurfaces[0];
659 IDirect3DTexture9 *pSrcTexture = paSrcTextures[0];
660
661 /* Upload the source data to the staging texture. */
662 hr = vboxDxvaUploadSample(pVideoProcessDevice, pSrcTexture, pSrcSample->SrcSubResourceIndex);
663 if (hr == D3D_OK)
664 {
665 /* Setup the blit dimensions. */
666 hr = vboxDxvaUpdateVertexBuffer(pVideoProcessDevice, &pSrcSample->SrcRect, &pSrcSample->DstRect);
667 Assert(hr == D3D_OK);
668 if (hr == D3D_OK)
669 {
670
671 hr = pDevice9->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);
672 Assert(hr == D3D_OK);
673 }
674 }
675 }
676
677 vboxDxvaDeviceStateRestore(pDevice9, &pVideoProcessDevice->SavedState);
678 }
679
680 return hr;
681}
682
683/*
684 *
685 * Public API.
686 *
687 */
688HRESULT VBoxDxvaGetDeviceGuidCount(UINT *pcGuids)
689{
690 *pcGuids = RT_ELEMENTS(gaDeviceGuids);
691 return S_OK;
692}
693
694HRESULT VBoxDxvaGetDeviceGuids(GUID *paGuids, UINT cbGuids)
695{
696 if (cbGuids >= sizeof(gaDeviceGuids))
697 {
698 memcpy(paGuids, &gaDeviceGuids[0], sizeof(gaDeviceGuids));
699 return S_OK;
700 }
701
702 AssertFailed();
703 return E_INVALIDARG;
704}
705
706HRESULT VBoxDxvaGetOutputFormatCount(UINT *pcFormats, DXVADDI_VIDEOPROCESSORINPUT const *pVPI, bool fSubstream)
707{
708 RT_NOREF(fSubstream);
709
710 UINT cFormats = 0;
711 if (pVPI)
712 {
713 if (vboxDxvaFindDeviceGuid(pVPI->pVideoProcGuid) >= 0)
714 {
715 if (vboxDxvaFindInputFormat(pVPI->VideoDesc.Format) >= 0)
716 {
717 cFormats = RT_ELEMENTS(gaOutputFormats);
718 }
719 }
720 }
721
722 *pcFormats = cFormats;
723 return S_OK;
724}
725
726HRESULT VBoxDxvaGetOutputFormats(D3DDDIFORMAT *paFormats, UINT cbFormats, DXVADDI_VIDEOPROCESSORINPUT const *pVPI, bool fSubstream)
727{
728 RT_NOREF(fSubstream);
729
730 if (pVPI)
731 {
732 if (vboxDxvaFindDeviceGuid(pVPI->pVideoProcGuid) >= 0)
733 {
734 if (vboxDxvaFindInputFormat(pVPI->VideoDesc.Format) >= 0)
735 {
736 if (cbFormats >= sizeof(gaOutputFormats))
737 {
738 memcpy(paFormats, gaOutputFormats, sizeof(gaOutputFormats));
739 return S_OK;
740 }
741 }
742 }
743 }
744
745 AssertFailed();
746 return E_INVALIDARG;
747}
748
749HRESULT VBoxDxvaGetCaps(DXVADDI_VIDEOPROCESSORCAPS *pVideoProcessorCaps,
750 DXVADDI_VIDEOPROCESSORINPUT const *pVPI)
751{
752 RT_ZERO(*pVideoProcessorCaps);
753
754 if (pVPI)
755 {
756 if (vboxDxvaFindDeviceGuid(pVPI->pVideoProcGuid) >= 0)
757 {
758 if (vboxDxvaFindInputFormat(pVPI->VideoDesc.Format) >= 0)
759 {
760 pVideoProcessorCaps->InputPool = D3DDDIPOOL_SYSTEMMEM;
761 pVideoProcessorCaps->NumForwardRefSamples = 0; /// @todo 1 for deinterlacing?
762 pVideoProcessorCaps->NumBackwardRefSamples = 0;
763 pVideoProcessorCaps->OutputFormat = D3DDDIFMT_X8R8G8B8;
764 pVideoProcessorCaps->DeinterlaceTechnology = DXVADDI_DEINTERLACETECH_UNKNOWN;
765 pVideoProcessorCaps->ProcAmpControlCaps = DXVADDI_PROCAMP_NONE; /// @todo Maybe some?
766 pVideoProcessorCaps->VideoProcessorOperations = DXVADDI_VIDEOPROCESS_YUV2RGB
767 | DXVADDI_VIDEOPROCESS_STRETCHX
768 | DXVADDI_VIDEOPROCESS_STRETCHY
769 | DXVADDI_VIDEOPROCESS_YUV2RGBEXTENDED
770 | DXVADDI_VIDEOPROCESS_CONSTRICTION
771 | DXVADDI_VIDEOPROCESS_LINEARSCALING
772 | DXVADDI_VIDEOPROCESS_GAMMACOMPENSATED;
773 pVideoProcessorCaps->NoiseFilterTechnology = DXVADDI_NOISEFILTERTECH_UNSUPPORTED;
774 pVideoProcessorCaps->DetailFilterTechnology = DXVADDI_DETAILFILTERTECH_UNSUPPORTED;
775 return S_OK;
776 }
777 }
778 }
779
780 AssertFailed();
781 return E_INVALIDARG;
782}
783
784HRESULT VBoxDxvaCreateVideoProcessDevice(PVBOXWDDMDISP_DEVICE pDevice, D3DDDIARG_CREATEVIDEOPROCESSDEVICE *pData)
785{
786 /*
787 * Do minimum here. Devices are created and destroyed without being used.
788 */
789 VBOXWDDMVIDEOPROCESSDEVICE *pVideoProcessDevice =
790 (VBOXWDDMVIDEOPROCESSDEVICE *)RTMemAllocZ(sizeof(VBOXWDDMVIDEOPROCESSDEVICE));
791 if (pVideoProcessDevice)
792 {
793 pVideoProcessDevice->pDevice = pDevice;
794 pVideoProcessDevice->VideoProcGuid = *pData->pVideoProcGuid;
795 pVideoProcessDevice->VideoDesc = pData->VideoDesc;
796 pVideoProcessDevice->RenderTargetFormat = pData->RenderTargetFormat;
797 pVideoProcessDevice->MaxSubStreams = pData->MaxSubStreams;
798
799 pData->hVideoProcess = pVideoProcessDevice;
800 return S_OK;
801 }
802
803 return E_OUTOFMEMORY;
804}
805
806HRESULT VBoxDxvaDestroyVideoProcessDevice(PVBOXWDDMDISP_DEVICE pDevice, HANDLE hVideoProcessor)
807{
808 VBOXWDDMVIDEOPROCESSDEVICE *pVideoProcessDevice = (VBOXWDDMVIDEOPROCESSDEVICE *)hVideoProcessor;
809 AssertReturn(pDevice == pVideoProcessDevice->pDevice, E_INVALIDARG);
810
811 D3D_RELEASE(pVideoProcessDevice->pRTSurface);
812
813 D3D_RELEASE(pVideoProcessDevice->pStagingTexture);
814 D3D_RELEASE(pVideoProcessDevice->pVertexDecl);
815 D3D_RELEASE(pVideoProcessDevice->pVB);
816 D3D_RELEASE(pVideoProcessDevice->pVS);
817 D3D_RELEASE(pVideoProcessDevice->pPS);
818
819 RTMemFree(pVideoProcessDevice);
820
821 return S_OK;
822}
823
824HRESULT VBoxDxvaVideoProcessBeginFrame(PVBOXWDDMDISP_DEVICE pDevice, HANDLE hVideoProcessor)
825{
826 VBOXWDDMVIDEOPROCESSDEVICE *pVideoProcessDevice = (VBOXWDDMVIDEOPROCESSDEVICE *)hVideoProcessor;
827 AssertReturn(pDevice == pVideoProcessDevice->pDevice, E_INVALIDARG);
828 AssertPtrReturn(pDevice->pDevice9If, E_INVALIDARG);
829
830 HRESULT hr = S_OK;
831 if (!pVideoProcessDevice->pStagingTexture)
832 {
833 hr = vboxDxvaInit(pVideoProcessDevice);
834 }
835
836 return hr;
837}
838
839HRESULT VBoxDxvaVideoProcessEndFrame(PVBOXWDDMDISP_DEVICE pDevice, D3DDDIARG_VIDEOPROCESSENDFRAME *pData)
840{
841 VBOXWDDMVIDEOPROCESSDEVICE *pVideoProcessDevice = (VBOXWDDMVIDEOPROCESSDEVICE *)pData->hVideoProcess;
842 AssertReturn(pDevice == pVideoProcessDevice->pDevice, E_INVALIDARG);
843 return S_OK;
844}
845
846HRESULT VBoxDxvaSetVideoProcessRenderTarget(PVBOXWDDMDISP_DEVICE pDevice,
847 const D3DDDIARG_SETVIDEOPROCESSRENDERTARGET *pData)
848{
849 VBOXWDDMVIDEOPROCESSDEVICE *pVideoProcessDevice = (VBOXWDDMVIDEOPROCESSDEVICE *)pData->hVideoProcess;
850 AssertReturn(pDevice == pVideoProcessDevice->pDevice, E_INVALIDARG);
851
852 D3D_RELEASE(pVideoProcessDevice->pRTSurface);
853 pVideoProcessDevice->pRenderTarget = NULL;
854 pVideoProcessDevice->RTSubResourceIndex = 0;
855 pVideoProcessDevice->pRTTexture = NULL;
856
857 PVBOXWDDMDISP_RESOURCE pRc = (PVBOXWDDMDISP_RESOURCE)pData->hRenderTarget;
858 AssertReturn(pRc->cAllocations > pData->SubResourceIndex, E_INVALIDARG);
859
860 VBOXWDDMDISP_ALLOCATION *pAllocation = &pRc->aAllocations[pData->SubResourceIndex];
861 AssertPtrReturn(pAllocation->pD3DIf, E_INVALIDARG);
862 AssertReturn(pAllocation->enmD3DIfType == VBOXDISP_D3DIFTYPE_TEXTURE, E_INVALIDARG);
863
864#ifdef LOG_ENABLED
865 LOGREL_EXACT(("VideoProcess RT %dx%d sid=%u\n",
866 pRc->aAllocations[0].SurfDesc.width, pRc->aAllocations[0].SurfDesc.height, pAllocation->hostID));
867#endif
868
869 IDirect3DTexture9 *pRTTexture = (IDirect3DTexture9 *)pAllocation->pD3DIf;
870 HRESULT hr = pRTTexture->GetSurfaceLevel(pData->SubResourceIndex, &pVideoProcessDevice->pRTSurface);
871 AssertReturn(hr == D3D_OK, E_INVALIDARG);
872
873 pVideoProcessDevice->pRenderTarget = pRc;
874 pVideoProcessDevice->RTSubResourceIndex = pData->SubResourceIndex;
875 pVideoProcessDevice->pRTTexture = pRTTexture;
876
877 return S_OK;
878}
879
880HRESULT VBoxDxvaVideoProcessBlt(PVBOXWDDMDISP_DEVICE pDevice, const D3DDDIARG_VIDEOPROCESSBLT *pData)
881{
882 VBOXWDDMVIDEOPROCESSDEVICE *pVideoProcessDevice = (VBOXWDDMVIDEOPROCESSDEVICE *)pData->hVideoProcess;
883 AssertReturn(pDevice == pVideoProcessDevice->pDevice, E_INVALIDARG);
884 AssertPtrReturn(pDevice->pDevice9If, E_INVALIDARG);
885 AssertPtrReturn(pVideoProcessDevice->pRTSurface, E_INVALIDARG);
886
887 AssertReturn(pData->NumSrcSurfaces > 0, E_INVALIDARG);
888
889 PVBOXWDDMDISP_RESOURCE pSrcRc = (PVBOXWDDMDISP_RESOURCE)pData->pSrcSurfaces[0].SrcResource;
890 AssertReturn(pSrcRc->cAllocations > pData->pSrcSurfaces[0].SrcSubResourceIndex, E_INVALIDARG);
891
892 VBOXWDDMDISP_ALLOCATION *pAllocation = &pSrcRc->aAllocations[pData->pSrcSurfaces[0].SrcSubResourceIndex];
893 AssertPtrReturn(pAllocation->pD3DIf, E_INVALIDARG);
894 AssertReturn(pAllocation->enmD3DIfType == VBOXDISP_D3DIFTYPE_TEXTURE, E_INVALIDARG);
895
896 IDirect3DTexture9 *pSrcTexture = (IDirect3DTexture9 *)pAllocation->pD3DIf;
897
898#ifdef LOG_ENABLED
899 LOGREL_EXACT(("VideoProcess Blt sid = %u fmt 0x%08x %d,%d %dx%d (%dx%d) -> %d,%d %dx%d (%d,%d %dx%d, %dx%d)\n",
900 pAllocation->hostID, pSrcRc->aAllocations[0].SurfDesc.format,
901 pData->pSrcSurfaces[0].SrcRect.left, pData->pSrcSurfaces[0].SrcRect.top,
902 pData->pSrcSurfaces[0].SrcRect.right - pData->pSrcSurfaces[0].SrcRect.left,
903 pData->pSrcSurfaces[0].SrcRect.bottom - pData->pSrcSurfaces[0].SrcRect.top,
904
905 pSrcRc->aAllocations[0].SurfDesc.width,
906 pSrcRc->aAllocations[0].SurfDesc.height,
907
908 pData->pSrcSurfaces[0].DstRect.left, pData->pSrcSurfaces[0].DstRect.top,
909 pData->pSrcSurfaces[0].DstRect.right - pData->pSrcSurfaces[0].DstRect.left,
910 pData->pSrcSurfaces[0].DstRect.bottom - pData->pSrcSurfaces[0].DstRect.top,
911
912 pData->TargetRect.left, pData->TargetRect.top,
913 pData->TargetRect.right - pData->TargetRect.left, pData->TargetRect.bottom - pData->TargetRect.top,
914
915 pVideoProcessDevice->pRenderTarget->aAllocations[0].SurfDesc.width,
916 pVideoProcessDevice->pRenderTarget->aAllocations[0].SurfDesc.height));
917
918 DXVADDI_EXTENDEDFORMAT *pSampleFormat = &pData->pSrcSurfaces[0].SampleFormat;
919 LOGREL_EXACT(("VideoProcess Blt SampleFormat %u, VideoChromaSubsampling %u, NominalRange %u, VideoTransferMatrix %u, VideoLighting %u, VideoPrimaries %u, VideoTransferFunction %u\n",
920 pSampleFormat->SampleFormat, pSampleFormat->VideoChromaSubsampling, pSampleFormat->NominalRange,
921 pSampleFormat->VideoTransferMatrix, pSampleFormat->VideoLighting, pSampleFormat->VideoPrimaries,
922 pSampleFormat->VideoTransferFunction));
923#endif
924
925 HRESULT hr = vboxDxvaProcessBlt(pVideoProcessDevice, pData, &pSrcTexture);
926 return hr;
927}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use