Edit

IABSD.fr/xenocara/lib/mesa/src/microsoft/compiler/dxil_validator.cpp

Branch :

  • Show log

    Commit

  • Author : jsg
    Date : 2025-06-05 11:23:11
    Hash : 67d6f117
    Message : Import Mesa 25.0.7

  • lib/mesa/src/microsoft/compiler/dxil_validator.cpp
  • #include "dxil_validator.h"
    
    #include <windows.h>
    #include <unknwn.h>
    
    #include "util/ralloc.h"
    #include "util/u_debug.h"
    #include "util/compiler.h"
    
    #include "dxcapi.h"
    
    #include <wrl/client.h>
    using Microsoft::WRL::ComPtr;
    
    struct dxil_validator {
       HMODULE dxil_mod;
       HMODULE dxcompiler_mod;
    
       IDxcValidator *dxc_validator;
       IDxcLibrary *dxc_library;
       IDxcCompiler *dxc_compiler;
    
       enum dxil_validator_version version;
    };
    
    extern "C" {
    extern IMAGE_DOS_HEADER __ImageBase;
    }
    
    static HMODULE
    load_dxil_mod()
    {
       /* First, try to load DXIL.dll from the default search-path */
    #if defined(_GAMING_XBOX_SCARLETT)
       HMODULE mod = LoadLibraryA("dxcompiler_xs.dll");
    #elif defined (_GAMING_XBOX)
       HMODULE mod = LoadLibraryA("dxcompiler_x.dll");
    #else
       HMODULE mod = LoadLibraryA("DXIL.dll");
    #endif
       if (mod)
          return mod;
    
       /* If that fails, try to load it next to the current module, so we can
        * ship DXIL.dll next to the GLon12 DLL.
        */
    
       char self_path[MAX_PATH];
       uint32_t path_size = GetModuleFileNameA((HINSTANCE)&__ImageBase,
                                               self_path, sizeof(self_path));
       if (!path_size || path_size == sizeof(self_path)) {
          debug_printf("DXIL: Unable to get path to self");
          return NULL;
       }
    
       auto last_slash = strrchr(self_path, '\\');
       if (!last_slash) {
          debug_printf("DXIL: Unable to get path to self");
          return NULL;
       }
    
       *(last_slash + 1) = '\0';
       if (strcat_s(self_path, "DXIL.dll") != 0) {
          debug_printf("DXIL: Unable to get path to DXIL.dll next to self");
          return NULL;
       }
    
       return LoadLibraryA(self_path);
    }
    
    static IDxcValidator *
    create_dxc_validator(HMODULE dxil_mod)
    {
       DxcCreateInstanceProc dxil_create_func =
          (DxcCreateInstanceProc)GetProcAddress(dxil_mod, "DxcCreateInstance");
       if (!dxil_create_func) {
          debug_printf("DXIL: Failed to load DxcCreateInstance from DXIL.dll\n");
          return NULL;
       }
    
       IDxcValidator *dxc_validator;
       HRESULT hr = dxil_create_func(CLSID_DxcValidator,
                                     IID_PPV_ARGS(&dxc_validator));
       if (FAILED(hr)) {
          debug_printf("DXIL: Failed to create validator\n");
          return NULL;
       }
    
       return dxc_validator;
    }
    
    static enum dxil_validator_version
    get_validator_version(IDxcValidator *val)
    {
       ComPtr<IDxcVersionInfo> version_info;
       if (FAILED(val->QueryInterface(version_info.ReleaseAndGetAddressOf())))
          return NO_DXIL_VALIDATION;
    
       UINT32 major, minor;
       if (FAILED(version_info->GetVersion(&major, &minor)))
          return NO_DXIL_VALIDATION;
    
       if (major == 1)
          return (enum dxil_validator_version)(DXIL_VALIDATOR_1_0 + MIN2(minor, 8));
       if (major > 1)
          return DXIL_VALIDATOR_1_8;
       return NO_DXIL_VALIDATION;
    }
    
    #ifndef _GAMING_XBOX
    static uint64_t
    get_dll_version(HMODULE mod)
    {
       WCHAR filename[MAX_PATH];
       DWORD filename_length = GetModuleFileNameW(mod, filename, ARRAY_SIZE(filename));
    
       if (filename_length == 0 || filename_length == ARRAY_SIZE(filename))
          return 0;
    
       DWORD version_handle = 0;
       DWORD version_size = GetFileVersionInfoSizeW(filename, &version_handle);
       if (version_size == 0)
          return 0;
    
       void *version_data = malloc(version_size);
       if (!version_data)
          return 0;
    
       if (!GetFileVersionInfoW(filename, version_handle, version_size, version_data)) {
          free(version_data);
          return 0;
       }
    
       UINT value_size = 0;
       VS_FIXEDFILEINFO *version_info = nullptr;
       if (!VerQueryValueW(version_data, L"\\", reinterpret_cast<void **>(&version_info), &value_size) ||
           !value_size ||
           version_info->dwSignature != VS_FFI_SIGNATURE) {
          free(version_data);
          return 0;
       }
    
       uint64_t ret =
          ((uint64_t)version_info->dwFileVersionMS << 32ull) |
          (uint64_t)version_info->dwFileVersionLS;
       free(version_data);
       return ret;
    }
    #endif
    
    static enum dxil_validator_version
    get_filtered_validator_version(HMODULE mod, enum dxil_validator_version raw)
    {
       switch (raw) {
    #ifndef _GAMING_XBOX
       case DXIL_VALIDATOR_1_6: {
          uint64_t dxil_version = get_dll_version(mod);
          static constexpr uint64_t known_bad_version =
             // 101.5.2005.60
             (101ull << 48ull) | (5ull << 32ull) | (2005ull << 16ull) | 60ull;
          if (dxil_version == known_bad_version)
             return DXIL_VALIDATOR_1_5;
          FALLTHROUGH;
       }
    #endif
       default:
          return raw;
       }
    }
    
    struct dxil_validator *
    dxil_create_validator(const void *ctx)
    {
       struct dxil_validator *val = rzalloc(ctx, struct dxil_validator);
       if (!val)
          return NULL;
    
       /* Load DXIL.dll. This is a hard requirement on Windows, so we error
        * out if this fails.
        */
       val->dxil_mod = load_dxil_mod();
       if (!val->dxil_mod) {
          debug_printf("DXIL: Failed to load DXIL.dll\n");
          goto fail;
       }
    
       /* Create IDxcValidator. This is a hard requirement on Windows, so we
        * error out if this fails.
        */
       val->dxc_validator = create_dxc_validator(val->dxil_mod);
       if (!val->dxc_validator)
          goto fail;
    
       val->version = get_filtered_validator_version(
          val->dxil_mod,
          get_validator_version(val->dxc_validator));
    
       /* Try to load dxcompiler.dll. This is just used for diagnostics, and
        * will fail on most end-users install. So we do not error out if this
        * fails.
        */
       val->dxcompiler_mod = LoadLibraryA("dxcompiler.dll");
       if (val->dxcompiler_mod) {
          /* If we managed to load dxcompiler.dll, but either don't find
           * DxcCreateInstance, or fail to create IDxcLibrary or
           * IDxcCompiler, this is a good indication that the user wants
           * diagnostics, but something went wrong. Print warnings to help
           * figuring out what's wrong, but do not treat it as an error.
           */
          DxcCreateInstanceProc compiler_create_func =
             (DxcCreateInstanceProc)GetProcAddress(val->dxcompiler_mod,
                                                   "DxcCreateInstance");
          if (!compiler_create_func) {
             debug_printf("DXIL: Failed to load DxcCreateInstance from "
                          "dxcompiler.dll\n");
          } else {
             if (FAILED(compiler_create_func(CLSID_DxcLibrary,
                                             IID_PPV_ARGS(&val->dxc_library))))
                debug_printf("DXIL: Unable to create IDxcLibrary instance\n");
    
             if (FAILED(compiler_create_func(CLSID_DxcCompiler,
                                             IID_PPV_ARGS(&val->dxc_compiler))))
                debug_printf("DXIL: Unable to create IDxcCompiler instance\n");
          }
       }
    
       return val;
    
    fail:
       if (val->dxil_mod)
          FreeLibrary(val->dxil_mod);
    
       ralloc_free(val);
       return NULL;
    }
    
    void
    dxil_destroy_validator(struct dxil_validator *val)
    {
       if (!val)
          return;
    
       /* if we have a validator, we have these */
       val->dxc_validator->Release();
       FreeLibrary(val->dxil_mod);
    
       if (val->dxcompiler_mod) {
          if (val->dxc_library)
             val->dxc_library->Release();
    
          if (val->dxc_compiler)
             val->dxc_compiler->Release();
    
          FreeLibrary(val->dxcompiler_mod);
       }
    
       ralloc_free(val);
    }
    
    class ShaderBlob : public IDxcBlob {
    public:
       ShaderBlob(void *data, size_t size) :
          m_data(data),
          m_size(size)
       {
       }
    
       LPVOID STDMETHODCALLTYPE
       GetBufferPointer(void) override
       {
          return m_data;
       }
    
       SIZE_T STDMETHODCALLTYPE
       GetBufferSize() override
       {
          return m_size;
       }
    
       HRESULT STDMETHODCALLTYPE
       QueryInterface(REFIID, void **) override
       {
          return E_NOINTERFACE;
       }
    
       ULONG STDMETHODCALLTYPE
       AddRef() override
       {
          return 1;
       }
    
       ULONG STDMETHODCALLTYPE
       Release() override
       {
          return 0;
       }
    
       void *m_data;
       size_t m_size;
    };
    
    bool
    dxil_validate_module(struct dxil_validator *val, void *data, size_t size, char **error)
    {
       if (!val)
          return false;
    
       ShaderBlob source(data, size);
    
       ComPtr<IDxcOperationResult> result;
       val->dxc_validator->Validate(&source, DxcValidatorFlags_InPlaceEdit,
                                    &result);
    
       HRESULT hr;
       result->GetStatus(&hr);
    
       if (FAILED(hr) && error) {
          /* try to resolve error message */
          *error = NULL;
          if (!val->dxc_library) {
             debug_printf("DXIL: validation failed, but lacking IDxcLibrary"
                          "from dxcompiler.dll for proper diagnostics.\n");
             return false;
          }
    
          ComPtr<IDxcBlobEncoding> blob, blob_utf8;
    
          if (FAILED(result->GetErrorBuffer(&blob)))
             fprintf(stderr, "DXIL: IDxcOperationResult::GetErrorBuffer() failed\n");
          else if (FAILED(val->dxc_library->GetBlobAsUtf8(blob.Get(),
                                                          blob_utf8.GetAddressOf())))
             fprintf(stderr, "DXIL: IDxcLibrary::GetBlobAsUtf8() failed\n");
          else {
             char *str = reinterpret_cast<char *>(blob_utf8->GetBufferPointer());
             str[blob_utf8->GetBufferSize() - 1] = 0;
             *error = ralloc_strdup(val, str);
          }
       }
    
       return SUCCEEDED(hr);
    }
    
    char *
    dxil_disasm_module(struct dxil_validator *val, void *data, size_t size)
    {
       if (!val)
          return NULL;
    
       if (!val->dxc_compiler || !val->dxc_library) {
          fprintf(stderr, "DXIL: disassembly requires IDxcLibrary and "
                  "IDxcCompiler from dxcompiler.dll\n");
          return NULL;
       }
    
       ShaderBlob source(data, size);
       ComPtr<IDxcBlobEncoding> blob, blob_utf8;
    
       if (FAILED(val->dxc_compiler->Disassemble(&source, &blob))) {
          fprintf(stderr, "DXIL: IDxcCompiler::Disassemble() failed\n");
          return NULL;
       }
    
       if (FAILED(val->dxc_library->GetBlobAsUtf8(blob.Get(), blob_utf8.GetAddressOf()))) {
          fprintf(stderr, "DXIL: IDxcLibrary::GetBlobAsUtf8() failed\n");
          return NULL;
       }
    
       char *str = reinterpret_cast<char*>(blob_utf8->GetBufferPointer());
       str[blob_utf8->GetBufferSize() - 1] = 0;
       return ralloc_strdup(val, str);
    }
    
    enum dxil_validator_version
    dxil_get_validator_version(struct dxil_validator *val)
    {
       return val ? val->version : NO_DXIL_VALIDATION;
    }