VirtualBox

source: vbox/trunk/src/VBox/Devices/Graphics/DevVGA-SVGA3d-win-d3d9.cpp@ 90778

Last change on this file since 90778 was 89163, checked in by vboxsync, 3 years ago

Devices/Graphics: Build new and old 3D backend. bugref:9830

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

© 2023 Oracle
ContactPrivacy policyTerms of Use