VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use