[PATCH] d3dx9: Implement D3DXSHProjectCubeMap().

Matteo Bruni matteo.mystral at gmail.com
Tue Feb 1 05:41:27 CST 2022


On Sun, Jan 30, 2022 at 2:46 AM Zebediah Figura <zfigura at codeweavers.com> wrote:
>
> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46284
> Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
> ---
>  dlls/d3dx9_24/d3dx9_24.spec   |   2 +-
>  dlls/d3dx9_25/d3dx9_25.spec   |   2 +-
>  dlls/d3dx9_26/d3dx9_26.spec   |   2 +-
>  dlls/d3dx9_27/d3dx9_27.spec   |   2 +-
>  dlls/d3dx9_28/d3dx9_28.spec   |   2 +-
>  dlls/d3dx9_29/d3dx9_29.spec   |   2 +-
>  dlls/d3dx9_30/d3dx9_30.spec   |   2 +-
>  dlls/d3dx9_31/d3dx9_31.spec   |   2 +-
>  dlls/d3dx9_32/d3dx9_32.spec   |   2 +-
>  dlls/d3dx9_33/d3dx9_33.spec   |   2 +-
>  dlls/d3dx9_34/d3dx9_34.spec   |   2 +-
>  dlls/d3dx9_35/d3dx9_35.spec   |   2 +-
>  dlls/d3dx9_36/d3dx9_36.spec   |   2 +-
>  dlls/d3dx9_36/d3dx9_private.h |   2 +
>  dlls/d3dx9_36/math.c          | 143 ++++++++++++++++++++++++
>  dlls/d3dx9_36/surface.c       |   2 +-
>  dlls/d3dx9_36/tests/math.c    | 199 ++++++++++++++++++++++++++++++++++
>  dlls/d3dx9_37/d3dx9_37.spec   |   2 +-
>  dlls/d3dx9_38/d3dx9_38.spec   |   2 +-
>  dlls/d3dx9_39/d3dx9_39.spec   |   2 +-
>  dlls/d3dx9_40/d3dx9_40.spec   |   2 +-
>  dlls/d3dx9_41/d3dx9_41.spec   |   2 +-
>  dlls/d3dx9_42/d3dx9_42.spec   |   2 +-
>  dlls/d3dx9_43/d3dx9_43.spec   |   2 +-
>  include/d3dx9math.h           |   1 +
>  25 files changed, 366 insertions(+), 21 deletions(-)

> diff --git a/dlls/d3dx9_36/math.c b/dlls/d3dx9_36/math.c
> index a7b0a018680..0dde552d45f 100644
> --- a/dlls/d3dx9_36/math.c
> +++ b/dlls/d3dx9_36/math.c
> @@ -2969,6 +2969,149 @@ static void rotate_X(FLOAT *out, UINT order, FLOAT a, FLOAT *in)
>      out[35] = 0.9057110548f * in[31] - 0.4192627370f * in[33] + 0.0624999329f * in[35];
>  }
>
> +static void set_vec3(D3DXVECTOR3 *v, float x, float y, float z)
> +{
> +    v->x = x;
> +    v->y = y;
> +    v->z = z;
> +}
> +
> +/*
> + * The following implementation of D3DXSHProjectCubeMap is based on the
> + * SHProjectCubeMap() implementation from Microsoft's DirectXMath library,
> + * covered under the following copyright:
> + *
> + * Copyright (c) Microsoft Corporation.
> + * Licensed under the MIT License.
> + */
> +HRESULT WINAPI D3DXSHProjectCubeMap(unsigned int order, IDirect3DCubeTexture9 *texture, float *red, float *green, float *blue)
> +{
> +    const unsigned int order_square = order * order;
> +    const struct pixel_format_desc *format;
> +    unsigned int x, y, i, face;
> +    float B, S, proj_normal;
> +    D3DSURFACE_DESC desc;
> +    float Wt = 0.0f;
> +    float *temp;
> +    HRESULT hr;
> +
> +    TRACE("order %u, texture %p, red %p, green %p, blue %p.\n", order, texture, red, green, blue);
> +
> +    if (!texture || !red || order < D3DXSH_MINORDER || order > D3DXSH_MAXORDER)
> +        return D3DERR_INVALIDCALL;
> +
> +    memset(red, 0, order_square * sizeof(float));
> +    if (green)
> +        memset(green, 0, order_square * sizeof(float));
> +    if (blue)
> +        memset(blue, 0, order_square * sizeof(float));
> +
> +    if (FAILED(hr = IDirect3DCubeTexture9_GetLevelDesc(texture, 0, &desc)))
> +    {
> +        ERR("Failed to get level desc, hr %#x.\n", hr);
> +        return hr;
> +    }
> +
> +    format = get_format_info(desc.Format);
> +    if (format->type != FORMAT_ARGB && format->type != FORMAT_ARGBF16 && format->type != FORMAT_ARGBF)
> +    {
> +        FIXME("Unsupported texture format %#x.\n", desc.Format);
> +        return D3DERR_INVALIDCALL;
> +    }
> +
> +    if (!(temp = malloc(order_square * sizeof(*temp))))
> +        return E_OUTOFMEMORY;
> +
> +    B = -1.0f + 1.0f / desc.Width;
> +    if (desc.Width > 1)
> +        S = 2.0f * (1.0f - 1.0f / desc.Width) / (desc.Width - 1.0f);
> +    else
> +        S = 0.0f;
> +
> +    for (face = 0; face < 6; ++face)
> +    {
> +        D3DLOCKED_RECT map_desc;
> +
> +        if (FAILED(hr = IDirect3DCubeTexture9_LockRect(texture, face, 0, &map_desc, NULL, D3DLOCK_READONLY)))

Are levels > 0 entirely ignored?
I think we should test that and update the implementation as necessary.

> +        {
> +            ERR("Failed to map texture, hr %#x.\n", hr);
> +            return hr;
> +        }

Missing free(temp);

> +
> +        for (y = 0; y < desc.Height; ++y)
> +        {
> +            const BYTE *row = (const BYTE *)map_desc.pBits + y * map_desc.Pitch;
> +
> +            for (x = 0; x < desc.Width; ++x)
> +            {
> +                float diff_solid, x_3d, y_3d;
> +                const float u = x * S + B;
> +                const float v = y * S + B;
> +                struct vec4 colour;
> +                D3DXVECTOR3 dir;
> +
> +                x_3d = (x * 2.0f + 1.0f) / desc.Width - 1.0f;
> +                y_3d = (y * 2.0f + 1.0f) / desc.Width - 1.0f;
> +
> +                switch (face)
> +                {
> +                    case D3DCUBEMAP_FACE_POSITIVE_X:
> +                        set_vec3(&dir, 1.0f, -y_3d, -x_3d);
> +                        break;
> +
> +                    case D3DCUBEMAP_FACE_NEGATIVE_X:
> +                        set_vec3(&dir, -1.0f, -y_3d, x_3d);
> +                        break;
> +
> +                    case D3DCUBEMAP_FACE_POSITIVE_Y:
> +                        set_vec3(&dir, x_3d, 1.0f, y_3d);
> +                        break;
> +
> +                    case D3DCUBEMAP_FACE_NEGATIVE_Y:
> +                        set_vec3(&dir, x_3d, -1.0f, -y_3d);
> +                        break;
> +
> +                    case D3DCUBEMAP_FACE_POSITIVE_Z:
> +                        set_vec3(&dir, x_3d, -y_3d, 1.0f);
> +                        break;
> +
> +                    case D3DCUBEMAP_FACE_NEGATIVE_Z:
> +                        set_vec3(&dir, -x_3d, -y_3d, -1.0f);
> +                        break;
> +                }
> +
> +                diff_solid = 4.0f / ((1.0f + u * u + v * v) * sqrtf(1.0f + u * u + v * v));

This could also be written more concisely as
diff_solid = 4.0f * powf(1.0f + u * u + v * v, -1.5f);
Does the original code mention anything about it? Is one version
faster, or more accurate, than the alternative? I'd give it another
look (no need to do crazy benchmarking, I'm just curious if one
version is much better than the other i.e. one order of magnitude or
more) and put a comment here to explain the choice made, either way.

> +                Wt += diff_solid;
> +
> +                D3DXVec3Normalize(&dir, &dir);
> +                D3DXSHEvalDirection(temp, order, &dir);
> +
> +                format_to_vec4(format, &row[x * format->block_byte_count], &colour);
> +
> +                for (i = 0; i < order_square; ++i)
> +                {
> +                    red[i] += temp[i] * colour.x * diff_solid;
> +                    if (green)
> +                        green[i] += temp[i] * colour.y * diff_solid;
> +                    if (blue)
> +                        blue[i] += temp[i] * colour.z * diff_solid;
> +                }
> +            }
> +        }
> +
> +        IDirect3DCubeTexture9_UnlockRect(texture, face, 0);
> +    }
> +
> +    proj_normal = (4.0f * M_PI) / Wt;
> +    D3DXSHScale(red, order, red, proj_normal);
> +    if (green)
> +        D3DXSHScale(green, order, green, proj_normal);
> +    if (blue)
> +        D3DXSHScale(blue, order, blue, proj_normal);
> +
> +    return D3D_OK;
> +}

Missing free(temp);

> diff --git a/dlls/d3dx9_36/tests/math.c b/dlls/d3dx9_36/tests/math.c
> index 6f64e25d200..40193f50fcc 100644
> --- a/dlls/d3dx9_36/tests/math.c
> +++ b/dlls/d3dx9_36/tests/math.c
> @@ -22,6 +22,7 @@
>  #include "wine/test.h"
>  #include "d3dx9.h"
>  #include <math.h>
> +#include <stdint.h>
>
>  static BOOL compare_float(float f, float g, unsigned int ulps)
>  {
> @@ -205,6 +206,53 @@ static void set_matrix(D3DXMATRIX* mat,
>      U(mat)->m[3][0] = m30; U(mat)->m[3][1] = m31; U(mat)->m[3][2] = m32; U(mat)->m[3][3] = m33;
>  }
>
> +static HWND create_window(void)
> +{
> +    RECT r = {0, 0, 640, 480};
> +
> +    AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW | WS_VISIBLE, FALSE);
> +
> +    return CreateWindowA("static", "d3d9_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
> +            0, 0, r.right - r.left, r.bottom - r.top, NULL, NULL, NULL, NULL);

Not that it matters but maybe we could name the window "d3dx9_test" or
something.



More information about the wine-devel mailing list