VirtualBox

source: vbox/trunk/src/VBox/Devices/Graphics/DevVGA-SVGA3d-win-d3d9.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: 50.8 KB
Line 
1/* $Id: DevVGA-SVGA3d-win-d3d9.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * DevVMWare - VMWare SVGA device Direct3D 9 backend.
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#define LOG_GROUP LOG_GROUP_DEV_VMSVGA
29#include <VBox/vmm/pdmdev.h>
30
31#include <iprt/assert.h>
32
33#include "DevVGA-SVGA.h"
34#include "DevVGA-SVGA3d-internal.h"
35
36
37typedef enum D3D9TextureType
38{
39 D3D9TextureType_Texture,
40 D3D9TextureType_Bounce,
41 D3D9TextureType_Emulated
42} D3D9TextureType;
43
44DECLINLINE(D3DCUBEMAP_FACES) vmsvga3dCubemapFaceFromIndex(uint32_t iFace)
45{
46 D3DCUBEMAP_FACES Face;
47 switch (iFace)
48 {
49 case 0: Face = D3DCUBEMAP_FACE_POSITIVE_X; break;
50 case 1: Face = D3DCUBEMAP_FACE_NEGATIVE_X; break;
51 case 2: Face = D3DCUBEMAP_FACE_POSITIVE_Y; break;
52 case 3: Face = D3DCUBEMAP_FACE_NEGATIVE_Y; break;
53 case 4: Face = D3DCUBEMAP_FACE_POSITIVE_Z; break;
54 default:
55 case 5: Face = D3DCUBEMAP_FACE_NEGATIVE_Z; break;
56 }
57 return Face;
58}
59
60IDirect3DTexture9 *D3D9GetTexture(PVMSVGA3DSURFACE pSurface,
61 D3D9TextureType enmType)
62{
63 IDirect3DTexture9 *p;
64 switch (enmType)
65 {
66 default: AssertFailed();
67 RT_FALL_THRU();
68 case D3D9TextureType_Texture: p = pSurface->u.pTexture; break;
69 case D3D9TextureType_Bounce: p = pSurface->bounce.pTexture; break;
70 case D3D9TextureType_Emulated: p = pSurface->emulated.pTexture; break;
71 }
72 return p;
73}
74
75IDirect3DCubeTexture9 *D3D9GetCubeTexture(PVMSVGA3DSURFACE pSurface,
76 D3D9TextureType enmType)
77{
78 IDirect3DCubeTexture9 *p;
79 switch (enmType)
80 {
81 default: AssertFailed();
82 RT_FALL_THRU();
83 case D3D9TextureType_Texture: p = pSurface->u.pCubeTexture; break;
84 case D3D9TextureType_Bounce: p = pSurface->bounce.pCubeTexture; break;
85 case D3D9TextureType_Emulated: p = pSurface->emulated.pCubeTexture; break;
86 }
87 return p;
88}
89
90IDirect3DVolumeTexture9 *D3D9GetVolumeTexture(PVMSVGA3DSURFACE pSurface,
91 D3D9TextureType enmType)
92{
93 IDirect3DVolumeTexture9 *p;
94 switch (enmType)
95 {
96 default: AssertFailed();
97 RT_FALL_THRU();
98 case D3D9TextureType_Texture: p = pSurface->u.pVolumeTexture; break;
99 case D3D9TextureType_Bounce: p = pSurface->bounce.pVolumeTexture; break;
100 case D3D9TextureType_Emulated: p = pSurface->emulated.pVolumeTexture; break;
101 }
102 return p;
103}
104
105HRESULT D3D9GetTextureLevel(PVMSVGA3DSURFACE pSurface,
106 D3D9TextureType enmType,
107 uint32_t uFace,
108 uint32_t uMipmap,
109 IDirect3DSurface9 **ppD3DSurface)
110{
111 HRESULT hr;
112
113 if (pSurface->enmD3DResType == VMSVGA3D_D3DRESTYPE_CUBE_TEXTURE)
114 {
115 Assert(pSurface->cFaces == 6);
116
117 IDirect3DCubeTexture9 *p = D3D9GetCubeTexture(pSurface, enmType);
118 if (p)
119 {
120 D3DCUBEMAP_FACES const FaceType = vmsvga3dCubemapFaceFromIndex(uFace);
121 hr = p->GetCubeMapSurface(FaceType, uMipmap, ppD3DSurface);
122 AssertMsg(hr == D3D_OK, ("GetCubeMapSurface failed with %x\n", hr));
123 }
124 else
125 {
126 AssertFailed();
127 hr = E_INVALIDARG;
128 }
129 }
130 else if (pSurface->enmD3DResType == VMSVGA3D_D3DRESTYPE_TEXTURE)
131 {
132 Assert(pSurface->cFaces == 1);
133 Assert(uFace == 0);
134
135 IDirect3DTexture9 *p = D3D9GetTexture(pSurface, enmType);
136 if (p)
137 {
138 hr = p->GetSurfaceLevel(uMipmap, ppD3DSurface);
139 AssertMsg(hr == D3D_OK, ("GetSurfaceLevel failed with %x\n", hr));
140 }
141 else
142 {
143 AssertFailed();
144 hr = E_INVALIDARG;
145 }
146 }
147 else
148 {
149 AssertMsgFailed(("No surface level for type %d\n", pSurface->enmD3DResType));
150 hr = E_INVALIDARG;
151 }
152
153 return hr;
154}
155
156
157static HRESULT d3dCopyToVertexBuffer(IDirect3DVertexBuffer9 *pVB, const void *pvSrc, int cbSrc)
158{
159 HRESULT hr = D3D_OK;
160 void *pvDst = 0;
161 hr = pVB->Lock(0, 0, &pvDst, 0);
162 if (SUCCEEDED(hr))
163 {
164 memcpy(pvDst, pvSrc, cbSrc);
165 hr = pVB->Unlock();
166 }
167 return hr;
168}
169
170struct Vertex
171{
172 float x, y; /* The vertex position. */
173 float u, v; /* Texture coordinates. */
174};
175
176typedef struct D3D9ConversionParameters
177{
178 DWORD const *paVS; /* Vertex shader code. */
179 DWORD const *paPS; /* Pixel shader code. */
180} D3D9ConversionParameters;
181
182/** Select conversion shaders.
183 * @param d3dfmtFrom Source texture format.
184 * @param d3dfmtTo Target texture format.
185 * @param pResult Where the tore pointers to the shader code.
186 */
187static HRESULT d3d9SelectConversion(D3DFORMAT d3dfmtFrom, D3DFORMAT d3dfmtTo,
188 D3D9ConversionParameters *pResult)
189{
190 /*
191 * The shader code has been obtained from the hex listing file (hexdump.txt) produced by fxc HLSL compiler:
192 * fxc.exe /Op /Tfx_2_0 /Fxhexdump.txt shader.fx
193 *
194 * The vertex shader code is the same for all convestion variants.
195 *
196 * For example here is the complete code for aPSCodeSwapRB:
197
198 uniform extern float4 gTextureInfo; // .xy = (width, height) in pixels, .zw = (1/width, 1/height)
199 uniform extern texture gTexSource;
200 sampler sSource = sampler_state
201 {
202 Texture = <gTexSource>;
203 };
204
205 struct VS_INPUT
206 {
207 float2 Position : POSITION; // In pixels.
208 float2 TexCoord : TEXCOORD0;
209 };
210
211 struct VS_OUTPUT
212 {
213 float4 Position : POSITION; // Normalized.
214 float2 TexCoord : TEXCOORD0;
215 };
216
217 VS_OUTPUT VS(VS_INPUT In)
218 {
219 VS_OUTPUT Output;
220
221 // Position is in pixels, i.e [0; width - 1]. Top, left is 0,0.
222 // Convert to the normalized coords in the -1;1 range
223 float4 Position;
224 Position.x = 2.0f * In.Position.x / (gTextureInfo.x - 1.0f) - 1.0f;
225 Position.y = -2.0f * In.Position.y / (gTextureInfo.y - 1.0f) + 1.0f;
226 Position.z = 0.0f; // Not used.
227 Position.w = 1.0f; // It is a point.
228
229 Output.Position = Position;
230 Output.TexCoord = In.TexCoord;
231
232 return Output;
233 }
234
235 struct PS_OUTPUT
236 {
237 float4 Color : COLOR0;
238 };
239
240 PS_OUTPUT PS(VS_OUTPUT In)
241 {
242 PS_OUTPUT Output;
243
244 float2 texCoord = In.TexCoord;
245
246 float4 texColor = tex2D(sSource, texCoord);
247
248 Output.Color = texColor.bgra; // Swizzle rgba -> bgra
249
250 return Output;
251 }
252
253 technique RenderScene
254 {
255 pass P0
256 {
257 VertexShader = compile vs_2_0 VS();
258 PixelShader = compile ps_2_0 PS();
259 }
260 }
261 */
262
263 static DWORD const aVSCode[] =
264 {
265 0xfffe0200, // vs_2_0
266 0x05000051, 0xa00f0001, 0xbf800000, 0xc0000000, 0x3f800000, 0x00000000, // def c1, -1, -2, 1, 0
267 0x0200001f, 0x80000000, 0x900f0000, // dcl_position v0
268 0x0200001f, 0x80000005, 0x900f0001, // dcl_texcoord v1
269 0x03000002, 0x80010000, 0x90000000, 0x90000000, // add r0.x, v0.x, v0.x
270 0x02000001, 0x80010001, 0xa0000001, // mov r1.x, c1.x
271 0x03000002, 0x80060000, 0x80000001, 0xa0d00000, // add r0.yz, r1.x, c0.xxyw
272 0x02000006, 0x80020000, 0x80550000, // rcp r0.y, r0.y
273 0x02000006, 0x80040000, 0x80aa0000, // rcp r0.z, r0.z
274 0x04000004, 0xc0010000, 0x80000000, 0x80550000, 0xa0000001, // mad oPos.x, r0.x, r0.y, c1.x
275 0x03000005, 0x80010000, 0x90550000, 0xa0550001, // mul r0.x, v0.y, c1.y
276 0x04000004, 0xc0020000, 0x80000000, 0x80aa0000, 0xa0aa0001, // mad oPos.y, r0.x, r0.z, c1.z
277 0x02000001, 0xc00c0000, 0xa0b40001, // mov oPos.zw, c1.xywz
278 0x02000001, 0xe0030000, 0x90e40001, // mov oT0.xy, v1
279 0x0000ffff
280 };
281
282 /*
283 * Swap R and B components. Converts D3DFMT_A8R8G8B8 <-> D3DFMT_A8B8G8R8.
284 */
285 static DWORD const aPSCodeSwapRB[] =
286 {
287 0xffff0200, // ps_2_0
288 0x0200001f, 0x80000000, 0xb0030000, // dcl t0.xy
289 0x0200001f, 0x90000000, 0xa00f0800, // dcl_2d s0
290 0x03000042, 0x800f0000, 0xb0e40000, 0xa0e40800, // texld r0, t0, s0
291 0x02000001, 0x80090001, 0x80d20000, // mov r1.xw, r0.zxyw
292 0x02000001, 0x80040001, 0x80000000, // mov r1.z, r0.x
293 0x02000001, 0x80020001, 0x80550000, // mov r1.y, r0.y
294 0x02000001, 0x800f0800, 0x80e40001, // mov oC0, r1
295 0x0000ffff
296 };
297
298 /* YUY2 to RGB:
299
300 // YUY2 if not defined
301 // #define UYVY
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 target.
318 float2 texCoord = In.TexCoord;
319
320 // Convert to the target coords in pixels: xPixel = TexCoord.x * Width.
321 float xTargetPixel = texCoord.x * gTextureInfo.x;
322
323 // Source texture is half width, i.e. it contains data in pixels [0; width / 2 - 1].
324 float xSourcePixel = xTargetPixel / 2.0f;
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 // Back to the normalized coords: texCoord.x = xPixel / Width.
330 texCoord.x = xSourcePixel * gTextureInfo.z;
331
332 // Fetch YUV
333 float4 texColor = tex2D(sSource, texCoord);
334
335 // Get YUV components.
336 #ifdef UYVY
337 float u = texColor.b;
338 float y0 = texColor.g;
339 float v = texColor.r;
340 float y1 = texColor.a;
341 #else // YUY2
342 float y0 = texColor.b;
343 float u = texColor.g;
344 float y1 = texColor.r;
345 float v = texColor.a;
346 #endif
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:
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 static DWORD const aPSCodeYUY2toRGB[] =
390 {
391 0xffff0200, // ps_2_0
392 0x05000051, 0xa00f0001, 0x3f000000, 0x00000000, 0x3f800000, 0xbf000000, // def c1, 0.5, 0, 1, -0.5
393 0x05000051, 0xa00f0002, 0xbd8068dc, 0xbf008312, 0xbf008312, 0x00000000, // def c2, -0.0627000034, -0.501999974, -0.501999974, 0
394 0x05000051, 0xa00f0003, 0x3f950a81, 0x00000000, 0x3fcc4a9d, 0x00000000, // def c3, 1.16438305, 0, 1.59602702, 0
395 0x05000051, 0xa00f0004, 0x3f950a81, 0xbec89507, 0xbf501eac, 0x00000000, // def c4, 1.16438305, -0.391761988, -0.812968016, 0
396 0x05000051, 0xa00f0005, 0x3f950a81, 0x40011a54, 0x00000000, 0x00000000, // def c5, 1.16438305, 2.01723194, 0, 0
397 0x0200001f, 0x80000000, 0xb0030000, // dcl t0.xy
398 0x0200001f, 0x90000000, 0xa00f0800, // dcl_2d s0
399 0x03000005, 0x80080000, 0xb0000000, 0xa0000000, // mul r0.w, t0.x, c0.x
400 0x03000005, 0x80010000, 0x80ff0000, 0xa0000001, // mul r0.x, r0.w, c1.x
401 0x02000013, 0x80020000, 0x80000000, // frc r0.y, r0.x
402 0x04000058, 0x80040000, 0x81550000, 0xa0550001, 0xa0aa0001, // cmp r0.z, -r0.y, c1.y, c1.z
403 0x03000002, 0x80020000, 0x80000000, 0x81550000, // add r0.y, r0.x, -r0.y
404 0x03000005, 0x80010001, 0x80000000, 0xa0aa0000, // mul r1.x, r0.x, c0.z
405 0x04000058, 0x80010000, 0x80ff0000, 0xa0550001, 0x80aa0000, // cmp r0.x, r0.w, c1.y, r0.z
406 0x03000002, 0x80010000, 0x80000000, 0x80550000, // add r0.x, r0.x, r0.y
407 0x04000004, 0x80010000, 0x80ff0000, 0xa0000001, 0x81000000, // mad r0.x, r0.w, c1.x, -r0.x
408 0x03000002, 0x80010000, 0x80000000, 0xa0ff0001, // add r0.x, r0.x, c1.w
409 0x02000001, 0x80020001, 0xb0550000, // mov r1.y, t0.y
410 0x03000042, 0x800f0001, 0x80e40001, 0xa0e40800, // texld r1, r1, s0
411 0x04000058, 0x80010001, 0x80000000, 0x80000001, 0x80aa0001, // cmp r1.x, r0.x, r1.x, r1.z
412 0x02000001, 0x80040001, 0x80ff0001, // mov r1.z, r1.w
413 0x03000002, 0x80070000, 0x80e40001, 0xa0e40002, // add r0.xyz, r1, c2
414 0x03000008, 0x80110001, 0x80e40000, 0xa0e40003, // dp3_sat r1.x, r0, c3
415 0x03000008, 0x80120001, 0x80e40000, 0xa0e40004, // dp3_sat r1.y, r0, c4
416 0x0400005a, 0x80140001, 0x80e40000, 0xa0e40005, 0xa0aa0005, // dp2add_sat r1.z, r0, c5, c5.z
417 0x02000001, 0x80080001, 0xa0aa0001, // mov r1.w, c1.z
418 0x02000001, 0x800f0800, 0x80e40001, // mov oC0, r1
419 0x0000ffff
420 };
421
422 /* UYVY to RGB is same as YUY2 above except for the order of yuv components:
423
424 // YUY2 if not defined
425 #define UYVY
426 ...
427 */
428 static DWORD const aPSCodeUYVYtoRGB[] =
429 {
430 0xffff0200, // ps_2_0
431 0x05000051, 0xa00f0001, 0x3f000000, 0x00000000, 0x3f800000, 0xbf000000, // def c1, 0.5, 0, 1, -0.5
432 0x05000051, 0xa00f0002, 0xbd8068dc, 0xbf008312, 0xbf008312, 0x00000000, // def c2, -0.0627000034, -0.501999974, -0.501999974, 0
433 0x05000051, 0xa00f0003, 0x3f950a81, 0x00000000, 0x3fcc4a9d, 0x00000000, // def c3, 1.16438305, 0, 1.59602702, 0
434 0x05000051, 0xa00f0004, 0x3f950a81, 0xbec89507, 0xbf501eac, 0x00000000, // def c4, 1.16438305, -0.391761988, -0.812968016, 0
435 0x05000051, 0xa00f0005, 0x3f950a81, 0x40011a54, 0x00000000, 0x00000000, // def c5, 1.16438305, 2.01723194, 0, 0
436 0x0200001f, 0x80000000, 0xb0030000, // dcl t0.xy
437 0x0200001f, 0x90000000, 0xa00f0800, // dcl_2d s0
438 0x03000005, 0x80080000, 0xb0000000, 0xa0000000, // mul r0.w, t0.x, c0.x
439 0x03000005, 0x80010000, 0x80ff0000, 0xa0000001, // mul r0.x, r0.w, c1.x
440 0x02000013, 0x80020000, 0x80000000, // frc r0.y, r0.x
441 0x04000058, 0x80040000, 0x81550000, 0xa0550001, 0xa0aa0001, // cmp r0.z, -r0.y, c1.y, c1.z
442 0x03000002, 0x80020000, 0x80000000, 0x81550000, // add r0.y, r0.x, -r0.y
443 0x03000005, 0x80010001, 0x80000000, 0xa0aa0000, // mul r1.x, r0.x, c0.z
444 0x04000058, 0x80010000, 0x80ff0000, 0xa0550001, 0x80aa0000, // cmp r0.x, r0.w, c1.y, r0.z
445 0x03000002, 0x80010000, 0x80000000, 0x80550000, // add r0.x, r0.x, r0.y
446 0x04000004, 0x80010000, 0x80ff0000, 0xa0000001, 0x81000000, // mad r0.x, r0.w, c1.x, -r0.x
447 0x03000002, 0x80010000, 0x80000000, 0xa0ff0001, // add r0.x, r0.x, c1.w
448 0x02000001, 0x80020001, 0xb0550000, // mov r1.y, t0.y
449 0x03000042, 0x800f0001, 0x80e40001, 0xa0e40800, // texld r1, r1, s0
450 0x04000058, 0x80010000, 0x80000000, 0x80ff0001, 0x80550001, // cmp r0.x, r0.x, r1.w, r1.y
451 0x02000001, 0x80060000, 0x80c90001, // mov r0.yz, r1.yzxw
452 0x03000002, 0x80070000, 0x80e40000, 0xa0e40002, // add r0.xyz, r0, c2
453 0x03000008, 0x80110001, 0x80e40000, 0xa0e40003, // dp3_sat r1.x, r0, c3
454 0x03000008, 0x80120001, 0x80e40000, 0xa0e40004, // dp3_sat r1.y, r0, c4
455 0x0400005a, 0x80140001, 0x80e40000, 0xa0e40005, 0xa0aa0005, // dp2add_sat r1.z, r0, c5, c5.z
456 0x02000001, 0x80080001, 0xa0aa0001, // mov r1.w, c1.z
457 0x02000001, 0x800f0800, 0x80e40001, // mov oC0, r1
458 0x0000ffff
459 };
460
461 /* RGB to YUY2.
462 * UYVY is not defined.
463
464 static const float3x3 bgrCoeffs =
465 {
466 0.0977f, 0.4375f, -0.0703f,
467 0.5039f, -0.2891f, -0.3672f,
468 0.2578f, -0.1484f, 0.4375f
469 };
470
471 static const float3 yuvShift = { 0.0647f, 0.5039f, 0.5039f };
472
473 PS_OUTPUT PS(VS_OUTPUT In)
474 {
475 PS_OUTPUT Output;
476
477 // 4 bytes of an YUV macropixel contain 2 source pixels in X.
478 // I.e. each YUV texture target pixel is computed from 2 source pixels.
479 // The target texture pixels are located in the [0; width / 2 - 1] range.
480
481 // In.TexCoord are in [0;1] range, applicable both to the source and the target textures.
482 float2 texCoordDst = In.TexCoord;
483
484 // Convert to the target coords in pixels: xPixel = TexCoord.x * Width.
485 float xTargetPixel = texCoordDst.x * gTextureInfo.x;
486
487 float4 bgraOutputPixel;
488 if (xTargetPixel < gTextureInfo.x / 2.0f)
489 {
490 // Target texture is half width, i.e. it contains data in pixels [0; width / 2 - 1].
491 // Compute the source texture coords for the pixels which will be used to compute the target pixel.
492 float2 texCoordSrc = texCoordDst;
493 texCoordSrc.x *= 2.0f;
494
495 // Even pixel. Fetch two BGRA source pixels.
496 float4 texColor0 = tex2D(sSource, texCoordSrc);
497
498 // Advance one pixel (+ 1/Width)
499 texCoordSrc.x += gTextureInfo.z;
500 float4 texColor1 = tex2D(sSource, texCoordSrc);
501
502 // Compute y0, u, y1, v components
503 // https://docs.microsoft.com/en-us/windows/win32/medfound/recommended-8-bit-yuv-formats-for-video-rendering#converting-rgb888-to-yuv-444
504 //
505 // For R,G,B and Y,U,V in [0;255]
506 // Y = ( ( 66 * R + 129 * G + 25 * B + 128) >> 8) + 16
507 // U = ( ( -38 * R - 74 * G + 112 * B + 128) >> 8) + 128
508 // V = ( ( 112 * R - 94 * G - 18 * B + 128) >> 8) + 128
509 //
510 // For r,g,b and y,u,v in [0;1.0]
511 // y = 0.2578 * r + 0.5039 * g + 0.0977 * b + 0.0647
512 // u = -0.1484 * r - 0.2891 * g + 0.4375 * b + 0.5039
513 // v = 0.4375 * r - 0.3672 * g - 0.0703 * b + 0.5039
514
515 float3 yuv0 = mul(texColor0.bgr, bgrCoeffs);
516 yuv0 -= yuvShift;
517
518 float3 yuv1 = mul(texColor1.bgr, bgrCoeffs);
519 yuv1 -= yuvShift;
520
521 float y0 = yuv0.b;
522 float u = (yuv0.g + yuv1.g) / 2.0f;
523 float y1 = yuv1.b;
524 float v = (yuv0.r + yuv1.r) / 2.0f;
525
526 #ifdef UYVY
527 bgraOutputPixel = float4(u, y0, v, y1);
528 #else // YUY2
529 bgraOutputPixel = float4(y0, u, y1, v);
530 #endif
531 }
532 else
533 {
534 // [width / 2; width - 1] pixels are not used. Set to something.
535 bgraOutputPixel = float4(0.0f, 0.0f, 0.0f, 0.0f);
536 }
537
538 // Clamp to [0;1]
539 bgraOutputPixel = saturate(bgraOutputPixel);
540
541 // Return RGBA
542 Output.Color = bgraOutputPixel;
543
544 return Output;
545 }
546 */
547 static DWORD const aPSCodeRGBtoYUY2[] =
548 {
549 0xffff0200, // ps_2_0
550 0x05000051, 0xa00f0001, 0xbd84816f, 0xbf00ff97, 0xbf00ff97, 0x00000000, // def c1, -0.0647, -0.503899992, -0.503899992, 0
551 0x05000051, 0xa00f0002, 0xbe80ff97, 0x00000000, 0xbd04816f, 0x00000000, // def c2, -0.251949996, 0, -0.03235, 0
552 0x05000051, 0xa00f0003, 0x3dc816f0, 0x3f00ff97, 0x3e83fe5d, 0x00000000, // def c3, 0.0976999998, 0.503899992, 0.257800013, 0
553 0x05000051, 0xa00f0004, 0x3ee00000, 0xbe9404ea, 0xbe17f62b, 0x00000000, // def c4, 0.4375, -0.289099991, -0.148399994, 0
554 0x05000051, 0xa00f0005, 0xbd8ff972, 0xbebc01a3, 0x3ee00000, 0x00000000, // def c5, -0.0702999979, -0.367199987, 0.4375, 0
555 0x05000051, 0xa00f0006, 0x3f000000, 0x40000000, 0x3f800000, 0xbf00ff97, // def c6, 0.5, 2, 1, -0.503899992
556 0x05000051, 0xa00f0007, 0x3f000000, 0x3f800000, 0x3f000000, 0x00000000, // def c7, 0.5, 1, 0.5, 0
557 0x0200001f, 0x80000000, 0xb0030000, // dcl t0.xy
558 0x0200001f, 0x90000000, 0xa00f0800, // dcl_2d s0
559 0x03000005, 0x80030000, 0xb0e40000, 0xa0c90006, // mul r0.xy, t0, c6.yzxw
560 0x02000001, 0x80030001, 0xa0e40006, // mov r1.xy, c6
561 0x04000004, 0x80010002, 0xb0000000, 0x80550001, 0xa0aa0000, // mad r2.x, t0.x, r1.y, c0.z
562 0x02000001, 0x80020002, 0xb0550000, // mov r2.y, t0.y
563 0x03000042, 0x800f0000, 0x80e40000, 0xa0e40800, // texld r0, r0, s0
564 0x03000042, 0x800f0002, 0x80e40002, 0xa0e40800, // texld r2, r2, s0
565 0x03000005, 0x80080000, 0x80aa0000, 0xa0000003, // mul r0.w, r0.z, c3.x
566 0x04000004, 0x80080000, 0x80550000, 0xa0550003, 0x80ff0000, // mad r0.w, r0.y, c3.y, r0.w
567 0x04000004, 0x80010003, 0x80000000, 0xa0aa0003, 0x80ff0000, // mad r3.x, r0.x, c3.z, r0.w
568 0x03000005, 0x80080000, 0x80aa0000, 0xa0000004, // mul r0.w, r0.z, c4.x
569 0x04000004, 0x80080000, 0x80550000, 0xa0550004, 0x80ff0000, // mad r0.w, r0.y, c4.y, r0.w
570 0x04000004, 0x80020003, 0x80000000, 0xa0aa0004, 0x80ff0000, // mad r3.y, r0.x, c4.z, r0.w
571 0x03000005, 0x80080002, 0x80aa0000, 0xa0000005, // mul r2.w, r0.z, c5.x
572 0x04000004, 0x80080002, 0x80550000, 0xa0550005, 0x80ff0002, // mad r2.w, r0.y, c5.y, r2.w
573 0x04000004, 0x80040003, 0x80000000, 0xa0aa0005, 0x80ff0002, // mad r3.z, r0.x, c5.z, r2.w
574 0x03000002, 0x80070000, 0x80e40003, 0xa0e40001, // add r0.xyz, r3, c1
575 0x02000001, 0x80080000, 0xa0ff0006, // mov r0.w, c6.w
576 0x03000005, 0x80080002, 0x80aa0002, 0xa0000003, // mul r2.w, r2.z, c3.x
577 0x04000004, 0x80080002, 0x80550002, 0xa0550003, 0x80ff0002, // mad r2.w, r2.y, c3.y, r2.w
578 0x04000004, 0x80040003, 0x80000002, 0xa0aa0003, 0x80ff0002, // mad r3.z, r2.x, c3.z, r2.w
579 0x03000005, 0x80080002, 0x80aa0002, 0xa0000004, // mul r2.w, r2.z, c4.x
580 0x04000004, 0x80080002, 0x80550002, 0xa0550004, 0x80ff0002, // mad r2.w, r2.y, c4.y, r2.w
581 0x04000004, 0x80010003, 0x80000002, 0xa0aa0004, 0x80ff0002, // mad r3.x, r2.x, c4.z, r2.w
582 0x03000005, 0x80080003, 0x80aa0002, 0xa0000005, // mul r3.w, r2.z, c5.x
583 0x04000004, 0x80080003, 0x80550002, 0xa0550005, 0x80ff0003, // mad r3.w, r2.y, c5.y, r3.w
584 0x04000004, 0x80020003, 0x80000002, 0xa0aa0005, 0x80ff0003, // mad r3.y, r2.x, c5.z, r3.w
585 0x03000002, 0x80050002, 0x80c90000, 0x80e40003, // add r2.xz, r0.yzxw, r3
586 0x03000002, 0x80020002, 0x80ff0000, 0x80550003, // add r2.y, r0.w, r3.y
587 0x02000001, 0x80110000, 0x80aa0000, // mov_sat r0.x, r0.z
588 0x02000001, 0x80070003, 0xa0e40007, // mov r3.xyz, c7
589 0x04000004, 0x80160000, 0x80d20002, 0x80d20003, 0xa0d20002, // mad_sat r0.yz, r2.zxyw, r3.zxyw, c2.zxyw
590 0x04000004, 0x80180000, 0x80aa0002, 0x80aa0003, 0xa0aa0002, // mad_sat r0.w, r2.z, r3.z, c2.z
591 0x03000005, 0x80010001, 0x80000001, 0xa0000000, // mul r1.x, r1.x, c0.x
592 0x04000004, 0x80010001, 0xb0000000, 0xa0000000, 0x81000001, // mad r1.x, t0.x, c0.x, -r1.x
593 0x04000058, 0x800f0000, 0x80000001, 0xa0ff0003, 0x80e40000, // cmp r0, r1.x, c3.w, r0
594 0x02000001, 0x800f0800, 0x80e40000, // mov oC0, r0
595 0x0000ffff
596 };
597
598 /* RGB to UYVY is same as YUY2 above except for the order of yuv components.
599 * UYVY is defined.
600 */
601 static DWORD const aPSCodeRGBtoUYVY[] =
602 {
603 0xffff0200, // ps_2_0
604 0x05000051, 0xa00f0001, 0xbd84816f, 0xbf00ff97, 0xbf00ff97, 0x00000000, // def c1, -0.0647, -0.503899992, -0.503899992, 0
605 0x05000051, 0xa00f0002, 0xbe80ff97, 0xbd04816f, 0x00000000, 0x00000000, // def c2, -0.251949996, -0.03235, 0, 0
606 0x05000051, 0xa00f0003, 0x3dc816f0, 0x3f00ff97, 0x3e83fe5d, 0x00000000, // def c3, 0.0976999998, 0.503899992, 0.257800013, 0
607 0x05000051, 0xa00f0004, 0x3ee00000, 0xbe9404ea, 0xbe17f62b, 0x00000000, // def c4, 0.4375, -0.289099991, -0.148399994, 0
608 0x05000051, 0xa00f0005, 0xbd8ff972, 0xbebc01a3, 0x3ee00000, 0x00000000, // def c5, -0.0702999979, -0.367199987, 0.4375, 0
609 0x05000051, 0xa00f0006, 0x3f000000, 0x40000000, 0x3f800000, 0xbf00ff97, // def c6, 0.5, 2, 1, -0.503899992
610 0x05000051, 0xa00f0007, 0x3f000000, 0x3f000000, 0x3f800000, 0x00000000, // def c7, 0.5, 0.5, 1, 0
611 0x0200001f, 0x80000000, 0xb0030000, // dcl t0.xy
612 0x0200001f, 0x90000000, 0xa00f0800, // dcl_2d s0
613 0x03000005, 0x80030000, 0xb0e40000, 0xa0c90006, // mul r0.xy, t0, c6.yzxw
614 0x02000001, 0x80030001, 0xa0e40006, // mov r1.xy, c6
615 0x04000004, 0x80010002, 0xb0000000, 0x80550001, 0xa0aa0000, // mad r2.x, t0.x, r1.y, c0.z
616 0x02000001, 0x80020002, 0xb0550000, // mov r2.y, t0.y
617 0x03000042, 0x800f0000, 0x80e40000, 0xa0e40800, // texld r0, r0, s0
618 0x03000042, 0x800f0002, 0x80e40002, 0xa0e40800, // texld r2, r2, s0
619 0x03000005, 0x80080000, 0x80aa0000, 0xa0000003, // mul r0.w, r0.z, c3.x
620 0x04000004, 0x80080000, 0x80550000, 0xa0550003, 0x80ff0000, // mad r0.w, r0.y, c3.y, r0.w
621 0x04000004, 0x80010003, 0x80000000, 0xa0aa0003, 0x80ff0000, // mad r3.x, r0.x, c3.z, r0.w
622 0x03000005, 0x80080000, 0x80aa0000, 0xa0000004, // mul r0.w, r0.z, c4.x
623 0x04000004, 0x80080000, 0x80550000, 0xa0550004, 0x80ff0000, // mad r0.w, r0.y, c4.y, r0.w
624 0x04000004, 0x80020003, 0x80000000, 0xa0aa0004, 0x80ff0000, // mad r3.y, r0.x, c4.z, r0.w
625 0x03000005, 0x80080002, 0x80aa0000, 0xa0000005, // mul r2.w, r0.z, c5.x
626 0x04000004, 0x80080002, 0x80550000, 0xa0550005, 0x80ff0002, // mad r2.w, r0.y, c5.y, r2.w
627 0x04000004, 0x80040003, 0x80000000, 0xa0aa0005, 0x80ff0002, // mad r3.z, r0.x, c5.z, r2.w
628 0x03000002, 0x80070000, 0x80e40003, 0xa0e40001, // add r0.xyz, r3, c1
629 0x02000001, 0x80080000, 0xa0ff0006, // mov r0.w, c6.w
630 0x03000005, 0x80080002, 0x80aa0002, 0xa0000003, // mul r2.w, r2.z, c3.x
631 0x04000004, 0x80080002, 0x80550002, 0xa0550003, 0x80ff0002, // mad r2.w, r2.y, c3.y, r2.w
632 0x04000004, 0x80020003, 0x80000002, 0xa0aa0003, 0x80ff0002, // mad r3.y, r2.x, c3.z, r2.w
633 0x03000005, 0x80080002, 0x80aa0002, 0xa0000004, // mul r2.w, r2.z, c4.x
634 0x04000004, 0x80080002, 0x80550002, 0xa0550004, 0x80ff0002, // mad r2.w, r2.y, c4.y, r2.w
635 0x04000004, 0x80010003, 0x80000002, 0xa0aa0004, 0x80ff0002, // mad r3.x, r2.x, c4.z, r2.w
636 0x03000005, 0x80080003, 0x80aa0002, 0xa0000005, // mul r3.w, r2.z, c5.x
637 0x04000004, 0x80080003, 0x80550002, 0xa0550005, 0x80ff0003, // mad r3.w, r2.y, c5.y, r3.w
638 0x04000004, 0x80040003, 0x80000002, 0xa0aa0005, 0x80ff0003, // mad r3.z, r2.x, c5.z, r3.w
639 0x03000002, 0x80010002, 0x80550000, 0x80000003, // add r2.x, r0.y, r3.x
640 0x03000002, 0x80020002, 0x80000000, 0x80550003, // add r2.y, r0.x, r3.y
641 0x03000002, 0x80040002, 0x80ff0000, 0x80aa0003, // add r2.z, r0.w, r3.z
642 0x02000001, 0x80120000, 0x80aa0000, // mov_sat r0.y, r0.z
643 0x02000001, 0x80070003, 0xa0e40007, // mov r3.xyz, c7
644 0x04000004, 0x80110000, 0x80000002, 0x80000003, 0xa0000002, // mad_sat r0.x, r2.x, r3.x, c2.x
645 0x04000004, 0x80140000, 0x80550002, 0x80550003, 0xa0550002, // mad_sat r0.z, r2.y, r3.y, c2.y
646 0x04000004, 0x80180000, 0x80aa0002, 0x80aa0003, 0xa0aa0002, // mad_sat r0.w, r2.z, r3.z, c2.z
647 0x03000005, 0x80010001, 0x80000001, 0xa0000000, // mul r1.x, r1.x, c0.x
648 0x04000004, 0x80010001, 0xb0000000, 0xa0000000, 0x81000001, // mad r1.x, t0.x, c0.x, -r1.x
649 0x04000058, 0x800f0000, 0x80000001, 0xa0ff0003, 0x80e40000, // cmp r0, r1.x, c3.w, r0
650 0x02000001, 0x800f0800, 0x80e40000, // mov oC0, r0
651 0x0000ffff
652 };
653
654 switch (d3dfmtFrom)
655 {
656 /*
657 * Emulated to ARGB
658 */
659 case D3DFMT_A8B8G8R8:
660 {
661 if (d3dfmtTo == D3DFMT_A8R8G8B8)
662 {
663 pResult->paVS = aVSCode;
664 pResult->paPS = aPSCodeSwapRB;
665
666 return D3D_OK;
667 }
668 } break;
669 case D3DFMT_UYVY:
670 {
671 if (d3dfmtTo == D3DFMT_A8R8G8B8)
672 {
673 pResult->paVS = aVSCode;
674 pResult->paPS = aPSCodeUYVYtoRGB;
675
676 return D3D_OK;
677 }
678 } break;
679 case D3DFMT_YUY2:
680 {
681 if (d3dfmtTo == D3DFMT_A8R8G8B8)
682 {
683 pResult->paVS = aVSCode;
684 pResult->paPS = aPSCodeYUY2toRGB;
685
686 return D3D_OK;
687 }
688 } break;
689
690 /*
691 * ARGB to emulated.
692 */
693 case D3DFMT_A8R8G8B8:
694 {
695 if (d3dfmtTo == D3DFMT_A8B8G8R8)
696 {
697 pResult->paVS = aVSCode;
698 pResult->paPS = aPSCodeSwapRB;
699
700 return D3D_OK;
701 }
702 else if (d3dfmtTo == D3DFMT_UYVY)
703 {
704 pResult->paVS = aVSCode;
705 pResult->paPS = aPSCodeRGBtoUYVY;
706
707 return D3D_OK;
708 }
709 else if (d3dfmtTo == D3DFMT_YUY2)
710 {
711 pResult->paVS = aVSCode;
712 pResult->paPS = aPSCodeRGBtoYUY2;
713
714 return D3D_OK;
715 }
716 } break;
717
718 default:
719 break;
720 }
721
722 return E_NOTIMPL;
723}
724
725class D3D9Conversion
726{
727 private:
728 IDirect3DDevice9Ex *mpDevice;
729
730 /* State objects. */
731 IDirect3DVertexBuffer9 *mpVB;
732 IDirect3DVertexDeclaration9 *mpVertexDecl;
733 IDirect3DVertexShader9 *mpVS;
734 IDirect3DPixelShader9 *mpPS;
735
736 D3D9ConversionParameters mParameters;
737
738 typedef struct D3DSamplerState
739 {
740 D3DSAMPLERSTATETYPE Type;
741 DWORD Value;
742 } D3DSamplerState;
743
744 /* Saved context. */
745 struct
746 {
747 DWORD dwCull;
748 DWORD dwZEnable;
749 IDirect3DSurface9 *pRT;
750 IDirect3DVertexShader9 *pVS;
751 IDirect3DPixelShader9 *pPS;
752 IDirect3DBaseTexture9 *pTexture;
753 float aVSConstantData[4];
754 float aPSConstantData[4];
755 D3DSamplerState aSamplerState[3];
756 } mSaved;
757
758 void destroyConversion();
759 HRESULT saveContextState();
760 HRESULT restoreContextState(PVMSVGA3DCONTEXT pContext);
761 HRESULT initConversion();
762 HRESULT setConversionState(IDirect3DTexture9 *pSourceTexture,
763 uint32_t cWidth,
764 uint32_t cHeight);
765
766 public:
767 enum Direction
768 {
769 FromEmulated,
770 ToEmulated,
771 };
772
773 D3D9Conversion(IDirect3DDevice9Ex *pDevice);
774 ~D3D9Conversion();
775
776 HRESULT SelectConversion(D3DFORMAT d3dfmtFrom, D3DFORMAT d3dfmtTo);
777 HRESULT ConvertTexture(PVMSVGA3DCONTEXT pContext,
778 PVMSVGA3DSURFACE pSurface,
779 Direction enmDirection);
780};
781
782D3D9Conversion::D3D9Conversion(IDirect3DDevice9Ex *pDevice)
783 :
784 mpDevice(pDevice),
785 mpVB(0),
786 mpVertexDecl(0),
787 mpVS(0),
788 mpPS(0)
789{
790 mParameters.paVS = 0;
791 mParameters.paPS = 0;
792 mSaved.dwCull = D3DCULL_NONE;
793 mSaved.dwZEnable = D3DZB_FALSE;
794 mSaved.pRT = 0;
795 mSaved.pVS = 0;
796 mSaved.pPS = 0;
797 mSaved.pTexture = 0;
798 RT_ZERO(mSaved.aVSConstantData);
799 RT_ZERO(mSaved.aPSConstantData);
800 mSaved.aSamplerState[0].Type = D3DSAMP_MAGFILTER;
801 mSaved.aSamplerState[0].Value = D3DTEXF_POINT;
802 mSaved.aSamplerState[1].Type = D3DSAMP_MINFILTER;
803 mSaved.aSamplerState[1].Value = D3DTEXF_POINT;
804 mSaved.aSamplerState[2].Type = D3DSAMP_MIPFILTER;
805 mSaved.aSamplerState[2].Value = D3DTEXF_NONE;
806}
807
808D3D9Conversion::~D3D9Conversion()
809{
810 destroyConversion();
811}
812
813void D3D9Conversion::destroyConversion()
814{
815 D3D_RELEASE(mpVertexDecl);
816 D3D_RELEASE(mpVB);
817 D3D_RELEASE(mpVS);
818 D3D_RELEASE(mpPS);
819}
820
821HRESULT D3D9Conversion::saveContextState()
822{
823 /*
824 * This is probably faster than
825 * IDirect3DStateBlock9 *mpStateBlock;
826 * mpDevice->CreateStateBlock(D3DSBT_ALL, &mpStateBlock);
827 */
828 HRESULT hr = mpDevice->GetRenderState(D3DRS_CULLMODE, &mSaved.dwCull);
829 AssertReturn(hr == D3D_OK, hr);
830
831 hr = mpDevice->GetRenderState(D3DRS_ZENABLE, &mSaved.dwZEnable);
832 AssertReturn(hr == D3D_OK, hr);
833
834 hr = mpDevice->GetRenderTarget(0, &mSaved.pRT);
835 AssertReturn(hr == D3D_OK, hr);
836
837 hr = mpDevice->GetVertexShader(&mSaved.pVS);
838 AssertReturn(hr == D3D_OK, hr);
839
840 hr = mpDevice->GetPixelShader(&mSaved.pPS);
841 AssertReturn(hr == D3D_OK, hr);
842
843 hr = mpDevice->GetTexture(0, &mSaved.pTexture);
844 AssertReturn(hr == D3D_OK, hr);
845
846 hr = mpDevice->GetVertexShaderConstantF(0, mSaved.aVSConstantData, 1);
847 AssertReturn(hr == D3D_OK, hr);
848
849 hr = mpDevice->GetPixelShaderConstantF(0, mSaved.aPSConstantData, 1);
850 AssertReturn(hr == D3D_OK, hr);
851
852 for (uint32_t i = 0; i < RT_ELEMENTS(mSaved.aSamplerState); ++i)
853 {
854 hr = mpDevice->GetSamplerState(0, mSaved.aSamplerState[i].Type, &mSaved.aSamplerState[i].Value);
855 AssertReturn(hr == D3D_OK, hr);
856 }
857
858 return hr;
859}
860
861HRESULT D3D9Conversion::restoreContextState(PVMSVGA3DCONTEXT pContext)
862{
863 HRESULT hr = mpDevice->SetRenderState(D3DRS_CULLMODE, mSaved.dwCull);
864 Assert(hr == D3D_OK);
865
866 hr = mpDevice->SetRenderState(D3DRS_ZENABLE, mSaved.dwZEnable);
867 Assert(hr == D3D_OK);
868
869 hr = mpDevice->SetRenderTarget(0, mSaved.pRT);
870 D3D_RELEASE(mSaved.pRT); /* GetRenderTarget increases the internal reference count. */
871 Assert(hr == D3D_OK);
872
873 hr = mpDevice->SetVertexDeclaration(pContext->d3dState.pVertexDecl);
874 Assert(hr == D3D_OK);
875
876 hr = mpDevice->SetVertexShader(mSaved.pVS);
877 Assert(hr == D3D_OK);
878
879 hr = mpDevice->SetPixelShader(mSaved.pPS);
880 Assert(hr == D3D_OK);
881
882 hr = mpDevice->SetTexture(0, mSaved.pTexture);
883 D3D_RELEASE(mSaved.pTexture); /* GetTexture increases the internal reference count. */
884 Assert(hr == D3D_OK);
885
886 hr = mpDevice->SetVertexShaderConstantF(0, mSaved.aVSConstantData, 1);
887 Assert(hr == D3D_OK);
888
889 hr = mpDevice->SetPixelShaderConstantF(0, mSaved.aPSConstantData, 1);
890 Assert(hr == D3D_OK);
891
892 for (uint32_t i = 0; i < RT_ELEMENTS(mSaved.aSamplerState); ++i)
893 {
894 hr = mpDevice->SetSamplerState(0, mSaved.aSamplerState[i].Type, mSaved.aSamplerState[i].Value);
895 Assert(hr == D3D_OK);
896 }
897
898 return hr;
899}
900
901HRESULT D3D9Conversion::initConversion()
902{
903 static D3DVERTEXELEMENT9 const aVertexElements[] =
904 {
905 {0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
906 {0, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
907 D3DDECL_END()
908 };
909
910 HRESULT hr = mpDevice->CreateVertexDeclaration(aVertexElements, &mpVertexDecl);
911 AssertReturn(hr == D3D_OK, hr);
912
913 hr = mpDevice->CreateVertexBuffer(6 * sizeof(Vertex),
914 0, /* D3DUSAGE_* */
915 0, /* FVF */
916 D3DPOOL_DEFAULT,
917 &mpVB,
918 0);
919 AssertReturn(hr == D3D_OK, hr);
920
921 hr = mpDevice->CreateVertexShader(mParameters.paVS, &mpVS);
922 AssertReturn(hr == D3D_OK, hr);
923
924 hr = mpDevice->CreatePixelShader(mParameters.paPS, &mpPS);
925 AssertReturn(hr == D3D_OK, hr);
926
927 return hr;
928}
929
930HRESULT D3D9Conversion::setConversionState(IDirect3DTexture9 *pSourceTexture,
931 uint32_t cWidth,
932 uint32_t cHeight)
933{
934 /* Subtract 0.5 to line up the pixel centers with texels
935 * https://docs.microsoft.com/en-us/windows/win32/direct3d9/directly-mapping-texels-to-pixels
936 */
937 float const xLeft = -0.5f;
938 float const xRight = (float)(cWidth - 1) - 0.5f;
939 float const yTop = -0.5f;
940 float const yBottom = (float)(cHeight - 1) - 0.5f;
941
942 Vertex const aVertices[] =
943 {
944 { xLeft, yTop, 0.0f, 0.0f},
945 { xRight, yTop, 1.0f, 0.0f},
946 { xRight, yBottom, 1.0f, 1.0f},
947
948 { xLeft, yTop, 0.0f, 0.0f},
949 { xRight, yBottom, 1.0f, 1.0f},
950 { xLeft, yBottom, 0.0f, 1.0f},
951 };
952
953 HRESULT hr = d3dCopyToVertexBuffer(mpVB, aVertices, sizeof(aVertices));
954 AssertReturn(hr == D3D_OK, hr);
955
956 /* No need to save the stream source, because vmsvga3dDrawPrimitives always sets it. */
957 hr = mpDevice->SetStreamSource(0, mpVB, 0, sizeof(Vertex));
958 AssertReturn(hr == D3D_OK, hr);
959
960 /* Stored in pContext->d3dState.pVertexDecl. */
961 hr = mpDevice->SetVertexDeclaration(mpVertexDecl);
962 AssertReturn(hr == D3D_OK, hr);
963
964 /* Saved by saveContextState. */
965 hr = mpDevice->SetVertexShader(mpVS);
966 AssertReturn(hr == D3D_OK, hr);
967
968 /* Saved by saveContextState. */
969 hr = mpDevice->SetPixelShader(mpPS);
970 AssertReturn(hr == D3D_OK, hr);
971
972 /* Saved by saveContextState. */
973 hr = mpDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
974 AssertReturn(hr == D3D_OK, hr);
975
976 /* Saved by saveContextState. */
977 hr = mpDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
978 AssertReturn(hr == D3D_OK, hr);
979
980 /* Saved by saveContextState. */
981 hr = mpDevice->SetTexture(0, pSourceTexture);
982 AssertReturn(hr == D3D_OK, hr);
983
984 float aTextureInfo[4];
985 aTextureInfo[0] = (float)cWidth;
986 aTextureInfo[1] = (float)cHeight;
987 aTextureInfo[2] = 1.0f / (float)cWidth; /* Pixel width in texture coords. */
988 aTextureInfo[3] = 1.0f / (float)cHeight; /* Pixel height in texture coords. */
989
990 /* Saved by saveContextState. */
991 hr = mpDevice->SetVertexShaderConstantF(0, aTextureInfo, 1);
992 AssertReturn(hr == D3D_OK, hr);
993
994 /* Saved by saveContextState. */
995 hr = mpDevice->SetPixelShaderConstantF(0, aTextureInfo, 1);
996 AssertReturn(hr == D3D_OK, hr);
997
998 /* Saved by saveContextState. */
999 hr = mpDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
1000 AssertReturn(hr == D3D_OK, hr);
1001 hr = mpDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
1002 AssertReturn(hr == D3D_OK, hr);
1003 hr = mpDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE);
1004 AssertReturn(hr == D3D_OK, hr);
1005
1006 return hr;
1007}
1008
1009
1010HRESULT D3D9Conversion::SelectConversion(D3DFORMAT d3dfmtFrom, D3DFORMAT d3dfmtTo)
1011{
1012 /** @todo d3d9SelectConversion should be a member. Move the code here? */
1013 HRESULT hr = d3d9SelectConversion(d3dfmtFrom, d3dfmtTo, &mParameters);
1014 return hr;
1015}
1016
1017HRESULT D3D9Conversion::ConvertTexture(PVMSVGA3DCONTEXT pContext,
1018 PVMSVGA3DSURFACE pSurface,
1019 Direction enmDirection)
1020{
1021 IDirect3DTexture9 *pSourceTexture;
1022 IDirect3DTexture9 *pTargetTexture;
1023 D3D9TextureType enmTargetType;
1024
1025 if (enmDirection == FromEmulated)
1026 {
1027 pSourceTexture = pSurface->emulated.pTexture;
1028 pTargetTexture = pSurface->u.pTexture;
1029 enmTargetType = D3D9TextureType_Texture;
1030 }
1031 else if (enmDirection == ToEmulated)
1032 {
1033 pSourceTexture = pSurface->u.pTexture;
1034 pTargetTexture = pSurface->emulated.pTexture;
1035 enmTargetType = D3D9TextureType_Emulated;
1036 }
1037 else
1038 AssertFailedReturn(E_INVALIDARG);
1039
1040 AssertPtrReturn(pSourceTexture, E_INVALIDARG);
1041 AssertPtrReturn(pTargetTexture, E_INVALIDARG);
1042
1043 HRESULT hr = saveContextState();
1044 if (hr == D3D_OK)
1045 {
1046 hr = initConversion();
1047 if (hr == D3D_OK)
1048 {
1049 uint32_t const cWidth = pSurface->paMipmapLevels[0].mipmapSize.width;
1050 uint32_t const cHeight = pSurface->paMipmapLevels[0].mipmapSize.height;
1051
1052 hr = setConversionState(pSourceTexture, cWidth, cHeight);
1053 if (hr == D3D_OK)
1054 {
1055 hr = mpDevice->BeginScene();
1056 Assert(hr == D3D_OK);
1057 if (hr == D3D_OK)
1058 {
1059 for (DWORD iFace = 0; iFace < pSurface->cFaces; ++iFace)
1060 {
1061 DWORD const cMipLevels = pTargetTexture->GetLevelCount();
1062 for (DWORD iMipmap = 0; iMipmap < cMipLevels && hr == D3D_OK; ++iMipmap)
1063 {
1064 IDirect3DSurface9 *pRT = NULL;
1065 hr = D3D9GetTextureLevel(pSurface, enmTargetType, iFace, iMipmap, &pRT);
1066 Assert(hr == D3D_OK);
1067 if (hr == D3D_OK)
1068 {
1069 hr = mpDevice->SetRenderTarget(0, pRT);
1070 Assert(hr == D3D_OK);
1071 if (hr == D3D_OK)
1072 {
1073 hr = mpDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);
1074 Assert(hr == D3D_OK);
1075 }
1076
1077 D3D_RELEASE(pRT);
1078 }
1079 }
1080 }
1081
1082 hr = mpDevice->EndScene();
1083 Assert(hr == D3D_OK);
1084 }
1085 }
1086 }
1087
1088 hr = restoreContextState(pContext);
1089 }
1090
1091 destroyConversion();
1092
1093 return hr;
1094}
1095
1096
1097HRESULT D3D9UpdateTexture(PVMSVGA3DCONTEXT pContext,
1098 PVMSVGA3DSURFACE pSurface)
1099{
1100 HRESULT hr = S_OK;
1101
1102 if (pSurface->formatD3D == pSurface->d3dfmtRequested)
1103 {
1104 hr = pContext->pDevice->UpdateTexture(pSurface->bounce.pTexture, pSurface->u.pTexture);
1105 }
1106 else
1107 {
1108 if (pSurface->enmD3DResType == VMSVGA3D_D3DRESTYPE_TEXTURE)
1109 {
1110 hr = pContext->pDevice->UpdateTexture(pSurface->bounce.pTexture, pSurface->emulated.pTexture);
1111 if (hr == D3D_OK)
1112 {
1113 D3D9Conversion conv(pContext->pDevice);
1114 hr = conv.SelectConversion(pSurface->d3dfmtRequested, pSurface->formatD3D);
1115 if (hr == D3D_OK)
1116 {
1117 hr = conv.ConvertTexture(pContext, pSurface, D3D9Conversion::FromEmulated);
1118 }
1119 }
1120 }
1121 else
1122 {
1123 /** @todo Cubemaps and maybe volume textures. */
1124 hr = pContext->pDevice->UpdateTexture(pSurface->bounce.pTexture, pSurface->u.pTexture);
1125 }
1126 }
1127
1128 return hr;
1129}
1130
1131HRESULT D3D9GetSurfaceLevel(PVMSVGA3DSURFACE pSurface,
1132 uint32_t uFace,
1133 uint32_t uMipmap,
1134 bool fBounce,
1135 IDirect3DSurface9 **ppD3DSurface)
1136{
1137 HRESULT hr;
1138
1139 if ( pSurface->enmD3DResType == VMSVGA3D_D3DRESTYPE_CUBE_TEXTURE
1140 || pSurface->enmD3DResType == VMSVGA3D_D3DRESTYPE_TEXTURE)
1141 {
1142 D3D9TextureType enmType;
1143 if (fBounce)
1144 enmType = D3D9TextureType_Bounce;
1145 else if (pSurface->formatD3D != pSurface->d3dfmtRequested)
1146 enmType = D3D9TextureType_Emulated;
1147 else
1148 enmType = D3D9TextureType_Texture;
1149
1150 hr = D3D9GetTextureLevel(pSurface, enmType, uFace, uMipmap, ppD3DSurface);
1151 }
1152 else if (pSurface->enmD3DResType == VMSVGA3D_D3DRESTYPE_SURFACE)
1153 {
1154 pSurface->u.pSurface->AddRef();
1155 *ppD3DSurface = pSurface->u.pSurface;
1156 hr = S_OK;
1157 }
1158 else
1159 {
1160 AssertMsgFailed(("No surface for type %d\n", pSurface->enmD3DResType));
1161 hr = E_INVALIDARG;
1162 }
1163
1164 return hr;
1165}
1166
1167/** Copy the texture content to the bounce texture.
1168 */
1169HRESULT D3D9GetRenderTargetData(PVMSVGA3DCONTEXT pContext,
1170 PVMSVGA3DSURFACE pSurface,
1171 uint32_t uFace,
1172 uint32_t uMipmap)
1173{
1174 HRESULT hr;
1175
1176 /* Get the corresponding bounce texture surface. */
1177 IDirect3DSurface9 *pDst = NULL;
1178 hr = D3D9GetSurfaceLevel(pSurface, uFace, uMipmap, true, &pDst);
1179 AssertReturn(hr == D3D_OK, hr);
1180
1181 /* Get the actual texture surface, emulated or actual. */
1182 IDirect3DSurface9 *pSrc = NULL;
1183 hr = D3D9GetSurfaceLevel(pSurface, uFace, uMipmap, false, &pSrc);
1184 AssertReturnStmt(hr == D3D_OK,
1185 D3D_RELEASE(pDst), hr);
1186
1187 Assert(pDst != pSrc);
1188
1189 if (pSurface->formatD3D == pSurface->d3dfmtRequested)
1190 {
1191 hr = pContext->pDevice->GetRenderTargetData(pSrc, pDst);
1192 AssertMsg(hr == D3D_OK, ("GetRenderTargetData failed with %x\n", hr));
1193 }
1194 else
1195 {
1196 D3D9Conversion conv(pContext->pDevice);
1197 hr = conv.SelectConversion(pSurface->formatD3D, pSurface->d3dfmtRequested);
1198 if (hr == D3D_OK)
1199 {
1200 hr = conv.ConvertTexture(pContext, pSurface, D3D9Conversion::ToEmulated);
1201 }
1202
1203 if (hr == D3D_OK)
1204 {
1205 hr = pContext->pDevice->GetRenderTargetData(pSrc, pDst);
1206 AssertMsg(hr == D3D_OK, ("GetRenderTargetData failed with %x\n", hr));
1207 }
1208 }
1209
1210 D3D_RELEASE(pSrc);
1211 D3D_RELEASE(pDst);
1212 return hr;
1213}
1214
1215D3DFORMAT D3D9GetActualFormat(PVMSVGA3DSTATE pState, D3DFORMAT d3dfmtRequested)
1216{
1217 RT_NOREF(pState);
1218
1219 switch (d3dfmtRequested)
1220 {
1221 case D3DFMT_UYVY:
1222 if (!pState->fSupportedFormatUYVY) return D3DFMT_A8R8G8B8;
1223 break;
1224 case D3DFMT_YUY2:
1225 if (!pState->fSupportedFormatYUY2) return D3DFMT_A8R8G8B8;
1226 break;
1227 case D3DFMT_A8B8G8R8:
1228 if (!pState->fSupportedFormatA8B8G8R8) return D3DFMT_A8R8G8B8;
1229 break;
1230 default:
1231 break;
1232 }
1233
1234 /* Use the requested format. No emulation required. */
1235 return d3dfmtRequested;
1236}
1237
1238bool D3D9CheckDeviceFormat(IDirect3D9 *pD3D9, DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat)
1239{
1240 HRESULT hr = pD3D9->CheckDeviceFormat(D3DADAPTER_DEFAULT,
1241 D3DDEVTYPE_HAL,
1242 D3DFMT_X8R8G8B8, /* assume standard 32-bit display mode */
1243 Usage,
1244 RType,
1245 CheckFormat);
1246 return (hr == D3D_OK);
1247}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use