This commit is contained in:
elwrcl committed 2026-06-06 13:25:15 +03:00
1 parent 04d4dc8b09
commit 818cab85dc
12511 files changed
+6156641

No files matched your search

+772
View File
@@ -0,0 +1,772 @@
///////////////////////////////////////////////////////////////////////////////
// //
// dxcapi.h //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// Provides declarations for the DirectX Compiler API entry point. //
// //
///////////////////////////////////////////////////////////////////////////////
#ifndef __DXC_API__
#define __DXC_API__
#ifdef _WIN32
#ifndef DXC_API_IMPORT
#define DXC_API_IMPORT __declspec(dllimport)
#endif
#else
#ifndef DXC_API_IMPORT
#define DXC_API_IMPORT __attribute__ ((visibility ("default")))
#endif
#endif
#include <stdint.h>
#ifndef CROSS_PLATFORM_UUIDOF
// Warning: This macro exists in WinAdapter.h as well
#if defined(_MSC_VER)
#define CROSS_PLATFORM_UUIDOF(iface, spec) \
struct __declspec(uuid(spec)) iface;
#else /* defined(_MSC_VER) */
#if defined(__MINGW32__)
#include <guiddef.h>
#include <sal.h>
#ifndef _Maybenull_
#define _Maybenull_
#endif
#ifndef _In_count_
#define _In_count_(x)
#endif
#ifndef _In_opt_count_
#define _In_opt_count_(x)
#endif
#ifndef _In_bytecount_
#define _In_bytecount_(x)
#endif
#endif /* defined(__MINGW32__) */
#ifndef __CRT_UUID_DECL
#define __CRT_UUID_DECL(type, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
extern "C++" \
{ \
template <> \
struct __mesa_emulated_uuidof_s<type> \
{ \
static constexpr IID __uuid_inst = { \
l, w1, w2, {b1, b2, b3, b4, b5, b6, b7, b8}}; \
}; \
template <> \
constexpr const GUID &__mesa_emulated_uuidof<type>() \
{ \
return __mesa_emulated_uuidof_s<type>::__uuid_inst; \
} \
template <> \
constexpr const GUID &__mesa_emulated_uuidof<type *>() \
{ \
return __mesa_emulated_uuidof_s<type>::__uuid_inst; \
} \
}
#define __uuidof(T) __mesa_emulated_uuidof<typename std::decay<T>::type>()
#endif /*__CRT_UUID_DECL */
constexpr uint8_t __nybble_from_hex(char c) {
return ((c >= '0' && c <= '9')
? (c - '0')
: ((c >= 'a' && c <= 'f')
? (c - 'a' + 10)
: ((c >= 'A' && c <= 'F') ? (c - 'A' + 10)
: /* Should be an error */ -1)));
}
constexpr uint8_t __byte_from_hexstr(const char str[2], unsigned offset) {
return __nybble_from_hex(str[offset + 0]) << 4 | __nybble_from_hex(str[offset + 1]);
}
constexpr unsigned short __short_from_hexstr_be(const char str[4], unsigned offset)
{
unsigned short hi = __byte_from_hexstr(str, offset + 0);
unsigned short lo = __byte_from_hexstr(str, offset + 2);
return (hi << 8) | lo;
}
constexpr unsigned int __word_from_hexstr_be(const char str[8], unsigned offset)
{
unsigned int hi = __short_from_hexstr_be(str, offset + 0);
unsigned int lo = __short_from_hexstr_be(str, offset + 4);
return (hi << 16) | lo;
}
#define CROSS_PLATFORM_UUIDOF(iface, spec) \
struct iface; \
__CRT_UUID_DECL( \
iface, \
__word_from_hexstr_be(spec, 0), \
__short_from_hexstr_be(spec, 9), \
__short_from_hexstr_be(spec, 14), \
__byte_from_hexstr(spec, 19), __byte_from_hexstr(spec, 21), \
__byte_from_hexstr(spec, 24), __byte_from_hexstr(spec, 26), \
__byte_from_hexstr(spec, 28), __byte_from_hexstr(spec, 30), \
__byte_from_hexstr(spec, 32), __byte_from_hexstr(spec, 34))
#endif /* defined(_MSC_VER) */
#endif /* CROSS_PLATFORM_UUIDOF */
#ifndef _WIN32
CROSS_PLATFORM_UUIDOF(INoMarshal, "ECC8691B-C1DB-4DC0-855E-65F6C551AF49")
struct INoMarshal : public IUnknown {};
CROSS_PLATFORM_UUIDOF(IMalloc, "00000002-0000-0000-C000-000000000046")
struct IMalloc : public IUnknown {
virtual void *Alloc(size_t size);
virtual void *Realloc(void *ptr, size_t size);
virtual void Free(void *ptr);
virtual HRESULT QueryInterface(REFIID riid, void **ppvObject);
};
CROSS_PLATFORM_UUIDOF(ISequentialStream, "0C733A30-2A1C-11CE-ADE5-00AA0044773D")
struct ISequentialStream : public IUnknown {
virtual HRESULT Read(void *pv, ULONG cb, ULONG *pcbRead) = 0;
virtual HRESULT Write(const void *pv, ULONG cb, ULONG *pcbWritten) = 0;
};
CROSS_PLATFORM_UUIDOF(IStream, "0000000c-0000-0000-C000-000000000046")
struct IStream : public ISequentialStream {
virtual HRESULT Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin,
ULARGE_INTEGER *plibNewPosition) = 0;
virtual HRESULT SetSize(ULARGE_INTEGER libNewSize) = 0;
virtual HRESULT CopyTo(IStream *pstm, ULARGE_INTEGER cb,
ULARGE_INTEGER *pcbRead,
ULARGE_INTEGER *pcbWritten) = 0;
virtual HRESULT Commit(DWORD grfCommitFlags) = 0;
virtual HRESULT Revert(void) = 0;
virtual HRESULT LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb,
DWORD dwLockType) = 0;
virtual HRESULT UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb,
DWORD dwLockType) = 0;
virtual HRESULT Stat(STATSTG *pstatstg, DWORD grfStatFlag) = 0;
virtual HRESULT Clone(IStream **ppstm) = 0;
};
#endif
struct IMalloc;
struct IDxcIncludeHandler;
typedef HRESULT (__stdcall *DxcCreateInstanceProc)(
_In_ REFCLSID rclsid,
_In_ REFIID riid,
_Out_ LPVOID* ppv
);
typedef HRESULT(__stdcall *DxcCreateInstance2Proc)(
_In_ IMalloc *pMalloc,
_In_ REFCLSID rclsid,
_In_ REFIID riid,
_Out_ LPVOID* ppv
);
/// <summary>
/// Creates a single uninitialized object of the class associated with a specified CLSID.
/// </summary>
/// <param name="rclsid">
/// The CLSID associated with the data and code that will be used to create the object.
/// </param>
/// <param name="riid">
/// A reference to the identifier of the interface to be used to communicate
/// with the object.
/// </param>
/// <param name="ppv">
/// Address of pointer variable that receives the interface pointer requested
/// in riid. Upon successful return, *ppv contains the requested interface
/// pointer. Upon failure, *ppv contains NULL.</param>
/// <remarks>
/// While this function is similar to CoCreateInstance, there is no COM involvement.
/// </remarks>
extern "C"
DXC_API_IMPORT HRESULT __stdcall DxcCreateInstance(
_In_ REFCLSID rclsid,
_In_ REFIID riid,
_Out_ LPVOID* ppv
);
extern "C"
DXC_API_IMPORT HRESULT __stdcall DxcCreateInstance2(
_In_ IMalloc *pMalloc,
_In_ REFCLSID rclsid,
_In_ REFIID riid,
_Out_ LPVOID* ppv
);
// For convenience, equivalent definitions to CP_UTF8 and CP_UTF16.
#define DXC_CP_UTF8 65001
#define DXC_CP_UTF16 1200
// Use DXC_CP_ACP for: Binary; ANSI Text; Autodetect UTF with BOM
#define DXC_CP_ACP 0
// This flag indicates that the shader hash was computed taking into account source information (-Zss)
#define DXC_HASHFLAG_INCLUDES_SOURCE 1
// Hash digest type for ShaderHash
typedef struct DxcShaderHash {
UINT32 Flags; // DXC_HASHFLAG_*
BYTE HashDigest[16];
} DxcShaderHash;
#define DXC_FOURCC(ch0, ch1, ch2, ch3) ( \
(UINT32)(UINT8)(ch0) | (UINT32)(UINT8)(ch1) << 8 | \
(UINT32)(UINT8)(ch2) << 16 | (UINT32)(UINT8)(ch3) << 24 \
)
#define DXC_PART_PDB DXC_FOURCC('I', 'L', 'D', 'B')
#define DXC_PART_PDB_NAME DXC_FOURCC('I', 'L', 'D', 'N')
#define DXC_PART_PRIVATE_DATA DXC_FOURCC('P', 'R', 'I', 'V')
#define DXC_PART_ROOT_SIGNATURE DXC_FOURCC('R', 'T', 'S', '0')
#define DXC_PART_DXIL DXC_FOURCC('D', 'X', 'I', 'L')
#define DXC_PART_REFLECTION_DATA DXC_FOURCC('S', 'T', 'A', 'T')
#define DXC_PART_SHADER_HASH DXC_FOURCC('H', 'A', 'S', 'H')
#define DXC_PART_INPUT_SIGNATURE DXC_FOURCC('I', 'S', 'G', '1')
#define DXC_PART_OUTPUT_SIGNATURE DXC_FOURCC('O', 'S', 'G', '1')
#define DXC_PART_PATCH_CONSTANT_SIGNATURE DXC_FOURCC('P', 'S', 'G', '1')
// Some option arguments are defined here for continuity with D3DCompile interface
#define DXC_ARG_DEBUG L"-Zi"
#define DXC_ARG_SKIP_VALIDATION L"-Vd"
#define DXC_ARG_SKIP_OPTIMIZATIONS L"-Od"
#define DXC_ARG_PACK_MATRIX_ROW_MAJOR L"-Zpr"
#define DXC_ARG_PACK_MATRIX_COLUMN_MAJOR L"-Zpc"
#define DXC_ARG_AVOID_FLOW_CONTROL L"-Gfa"
#define DXC_ARG_PREFER_FLOW_CONTROL L"-Gfp"
#define DXC_ARG_ENABLE_STRICTNESS L"-Ges"
#define DXC_ARG_ENABLE_BACKWARDS_COMPATIBILITY L"-Gec"
#define DXC_ARG_IEEE_STRICTNESS L"-Gis"
#define DXC_ARG_OPTIMIZATION_LEVEL0 L"-O0"
#define DXC_ARG_OPTIMIZATION_LEVEL1 L"-O1"
#define DXC_ARG_OPTIMIZATION_LEVEL2 L"-O2"
#define DXC_ARG_OPTIMIZATION_LEVEL3 L"-O3"
#define DXC_ARG_WARNINGS_ARE_ERRORS L"-WX"
#define DXC_ARG_RESOURCES_MAY_ALIAS L"-res_may_alias"
#define DXC_ARG_ALL_RESOURCES_BOUND L"-all_resources_bound"
#define DXC_ARG_DEBUG_NAME_FOR_SOURCE L"-Zss"
#define DXC_ARG_DEBUG_NAME_FOR_BINARY L"-Zsb"
// IDxcBlob is an alias of ID3D10Blob and ID3DBlob
CROSS_PLATFORM_UUIDOF(IDxcBlob, "8BA5FB08-5195-40e2-AC58-0D989C3A0102")
struct IDxcBlob : public IUnknown {
public:
virtual LPVOID STDMETHODCALLTYPE GetBufferPointer(void) = 0;
virtual SIZE_T STDMETHODCALLTYPE GetBufferSize(void) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcBlobEncoding, "7241d424-2646-4191-97c0-98e96e42fc68")
struct IDxcBlobEncoding : public IDxcBlob {
public:
virtual HRESULT STDMETHODCALLTYPE GetEncoding(_Out_ BOOL *pKnown,
_Out_ UINT32 *pCodePage) = 0;
};
// Notes on IDxcBlobUtf16 and IDxcBlobUtf8
// These guarantee null-terminated text and the stated encoding.
// GetBufferSize() will return the size in bytes, including null-terminator
// GetStringLength() will return the length in characters, excluding the null-terminator
// Name strings will use IDxcBlobUtf16, while other string output blobs,
// such as errors/warnings, preprocessed HLSL, or other text will be based
// on the -encoding option.
// The API will use this interface for output name strings
CROSS_PLATFORM_UUIDOF(IDxcBlobUtf16, "A3F84EAB-0FAA-497E-A39C-EE6ED60B2D84")
struct IDxcBlobUtf16 : public IDxcBlobEncoding {
public:
virtual LPCWSTR STDMETHODCALLTYPE GetStringPointer(void) = 0;
virtual SIZE_T STDMETHODCALLTYPE GetStringLength(void) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcBlobUtf8, "3DA636C9-BA71-4024-A301-30CBF125305B")
struct IDxcBlobUtf8 : public IDxcBlobEncoding {
public:
virtual LPCSTR STDMETHODCALLTYPE GetStringPointer(void) = 0;
virtual SIZE_T STDMETHODCALLTYPE GetStringLength(void) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcIncludeHandler, "7f61fc7d-950d-467f-b3e3-3c02fb49187c")
struct IDxcIncludeHandler : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE LoadSource(
_In_z_ LPCWSTR pFilename, // Candidate filename.
_COM_Outptr_result_maybenull_ IDxcBlob **ppIncludeSource // Resultant source object for included file, nullptr if not found.
) = 0;
};
// Structure for supplying bytes or text input to Dxc APIs.
// Use Encoding = 0 for non-text bytes, ANSI text, or unknown with BOM.
typedef struct DxcBuffer {
LPCVOID Ptr;
SIZE_T Size;
UINT Encoding;
} DxcText;
struct DxcDefine {
LPCWSTR Name;
_Maybenull_ LPCWSTR Value;
};
CROSS_PLATFORM_UUIDOF(IDxcCompilerArgs, "73EFFE2A-70DC-45F8-9690-EFF64C02429D")
struct IDxcCompilerArgs : public IUnknown {
// Pass GetArguments() and GetCount() to Compile
virtual LPCWSTR* STDMETHODCALLTYPE GetArguments() = 0;
virtual UINT32 STDMETHODCALLTYPE GetCount() = 0;
// Add additional arguments or defines here, if desired.
virtual HRESULT STDMETHODCALLTYPE AddArguments(
_In_opt_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments to add
_In_ UINT32 argCount // Number of arguments to add
) = 0;
virtual HRESULT STDMETHODCALLTYPE AddArgumentsUTF8(
_In_opt_count_(argCount)LPCSTR *pArguments, // Array of pointers to UTF-8 arguments to add
_In_ UINT32 argCount // Number of arguments to add
) = 0;
virtual HRESULT STDMETHODCALLTYPE AddDefines(
_In_count_(defineCount) const DxcDefine *pDefines, // Array of defines
_In_ UINT32 defineCount // Number of defines
) = 0;
};
//////////////////////////
// Legacy Interfaces
/////////////////////////
// NOTE: IDxcUtils replaces IDxcLibrary
CROSS_PLATFORM_UUIDOF(IDxcLibrary, "e5204dc7-d18c-4c3c-bdfb-851673980fe7")
struct IDxcLibrary : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE SetMalloc(_In_opt_ IMalloc *pMalloc) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateBlobFromBlob(
_In_ IDxcBlob *pBlob, UINT32 offset, UINT32 length, _COM_Outptr_ IDxcBlob **ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateBlobFromFile(
_In_z_ LPCWSTR pFileName, _In_opt_ UINT32* codePage,
_COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateBlobWithEncodingFromPinned(
_In_bytecount_(size) LPCVOID pText, UINT32 size, UINT32 codePage,
_COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateBlobWithEncodingOnHeapCopy(
_In_bytecount_(size) LPCVOID pText, UINT32 size, UINT32 codePage,
_COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateBlobWithEncodingOnMalloc(
_In_bytecount_(size) LPCVOID pText, IMalloc *pIMalloc, UINT32 size, UINT32 codePage,
_COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateIncludeHandler(
_COM_Outptr_ IDxcIncludeHandler **ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateStreamFromBlobReadOnly(
_In_ IDxcBlob *pBlob, _COM_Outptr_ IStream **ppStream) = 0;
virtual HRESULT STDMETHODCALLTYPE GetBlobAsUtf8(
_In_ IDxcBlob *pBlob, _COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
virtual HRESULT STDMETHODCALLTYPE GetBlobAsUtf16(
_In_ IDxcBlob *pBlob, _COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
};
// NOTE: IDxcResult replaces IDxcOperationResult
CROSS_PLATFORM_UUIDOF(IDxcOperationResult, "CEDB484A-D4E9-445A-B991-CA21CA157DC2")
struct IDxcOperationResult : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE GetStatus(_Out_ HRESULT *pStatus) = 0;
// GetResult returns the main result of the operation.
// This corresponds to:
// DXC_OUT_OBJECT - Compile() with shader or library target
// DXC_OUT_DISASSEMBLY - Disassemble()
// DXC_OUT_HLSL - Compile() with -P
// DXC_OUT_ROOT_SIGNATURE - Compile() with rootsig_* target
virtual HRESULT STDMETHODCALLTYPE GetResult(_COM_Outptr_result_maybenull_ IDxcBlob **ppResult) = 0;
// GetErrorBuffer Corresponds to DXC_OUT_ERRORS.
virtual HRESULT STDMETHODCALLTYPE GetErrorBuffer(_COM_Outptr_result_maybenull_ IDxcBlobEncoding **ppErrors) = 0;
};
// NOTE: IDxcCompiler3 replaces IDxcCompiler and IDxcCompiler2
CROSS_PLATFORM_UUIDOF(IDxcCompiler, "8c210bf3-011f-4422-8d70-6f9acb8db617")
struct IDxcCompiler : public IUnknown {
// Compile a single entry point to the target shader model
virtual HRESULT STDMETHODCALLTYPE Compile(
_In_ IDxcBlob *pSource, // Source text to compile
_In_opt_z_ LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and include handlers.
_In_opt_z_ LPCWSTR pEntryPoint, // entry point name
_In_z_ LPCWSTR pTargetProfile, // shader profile to compile
_In_opt_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
_In_ UINT32 argCount, // Number of arguments
_In_count_(defineCount)
const DxcDefine *pDefines, // Array of defines
_In_ UINT32 defineCount, // Number of defines
_In_opt_ IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle #include directives (optional)
_COM_Outptr_ IDxcOperationResult **ppResult // Compiler output status, buffer, and errors
) = 0;
// Preprocess source text
virtual HRESULT STDMETHODCALLTYPE Preprocess(
_In_ IDxcBlob *pSource, // Source text to preprocess
_In_opt_z_ LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and include handlers.
_In_opt_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
_In_ UINT32 argCount, // Number of arguments
_In_count_(defineCount)
const DxcDefine *pDefines, // Array of defines
_In_ UINT32 defineCount, // Number of defines
_In_opt_ IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle #include directives (optional)
_COM_Outptr_ IDxcOperationResult **ppResult // Preprocessor output status, buffer, and errors
) = 0;
// Disassemble a program.
virtual HRESULT STDMETHODCALLTYPE Disassemble(
_In_ IDxcBlob *pSource, // Program to disassemble.
_COM_Outptr_ IDxcBlobEncoding **ppDisassembly // Disassembly text.
) = 0;
};
// NOTE: IDxcCompiler3 replaces IDxcCompiler and IDxcCompiler2
CROSS_PLATFORM_UUIDOF(IDxcCompiler2, "A005A9D9-B8BB-4594-B5C9-0E633BEC4D37")
struct IDxcCompiler2 : public IDxcCompiler {
// Compile a single entry point to the target shader model with debug information.
virtual HRESULT STDMETHODCALLTYPE CompileWithDebug(
_In_ IDxcBlob *pSource, // Source text to compile
_In_opt_z_ LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and include handlers.
_In_opt_z_ LPCWSTR pEntryPoint, // Entry point name
_In_z_ LPCWSTR pTargetProfile, // Shader profile to compile
_In_opt_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
_In_ UINT32 argCount, // Number of arguments
_In_count_(defineCount)
const DxcDefine *pDefines, // Array of defines
_In_ UINT32 defineCount, // Number of defines
_In_opt_ IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle #include directives (optional)
_COM_Outptr_ IDxcOperationResult **ppResult, // Compiler output status, buffer, and errors
_Outptr_opt_result_z_ LPWSTR *ppDebugBlobName,// Suggested file name for debug blob. (Must be HeapFree()'d!)
_COM_Outptr_opt_ IDxcBlob **ppDebugBlob // Debug blob
) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcLinker, "F1B5BE2A-62DD-4327-A1C2-42AC1E1E78E6")
struct IDxcLinker : public IUnknown {
public:
// Register a library with name to ref it later.
virtual HRESULT RegisterLibrary(
_In_opt_ LPCWSTR pLibName, // Name of the library.
_In_ IDxcBlob *pLib // Library blob.
) = 0;
// Links the shader and produces a shader blob that the Direct3D runtime can
// use.
virtual HRESULT STDMETHODCALLTYPE Link(
_In_opt_ LPCWSTR pEntryName, // Entry point name
_In_ LPCWSTR pTargetProfile, // shader profile to link
_In_count_(libCount)
const LPCWSTR *pLibNames, // Array of library names to link
_In_ UINT32 libCount, // Number of libraries to link
_In_opt_count_(argCount) const LPCWSTR *pArguments, // Array of pointers to arguments
_In_ UINT32 argCount, // Number of arguments
_COM_Outptr_
IDxcOperationResult **ppResult // Linker output status, buffer, and errors
) = 0;
};
/////////////////////////
// Latest interfaces. Please use these
////////////////////////
// NOTE: IDxcUtils replaces IDxcLibrary
CROSS_PLATFORM_UUIDOF(IDxcUtils, "4605C4CB-2019-492A-ADA4-65F20BB7D67F")
struct IDxcUtils : public IUnknown {
// Create a sub-blob that holds a reference to the outer blob and points to its memory.
virtual HRESULT STDMETHODCALLTYPE CreateBlobFromBlob(
_In_ IDxcBlob *pBlob, UINT32 offset, UINT32 length, _COM_Outptr_ IDxcBlob **ppResult) = 0;
// For codePage, use 0 (or DXC_CP_ACP) for raw binary or ANSI code page
// Creates a blob referencing existing memory, with no copy.
// User must manage the memory lifetime separately.
// (was: CreateBlobWithEncodingFromPinned)
virtual HRESULT STDMETHODCALLTYPE CreateBlobFromPinned(
_In_bytecount_(size) LPCVOID pData, UINT32 size, UINT32 codePage,
_COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
// Create blob, taking ownership of memory allocated with supplied allocator.
// (was: CreateBlobWithEncodingOnMalloc)
virtual HRESULT STDMETHODCALLTYPE MoveToBlob(
_In_bytecount_(size) LPCVOID pData, IMalloc *pIMalloc, UINT32 size, UINT32 codePage,
_COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
////
// New blobs and copied contents are allocated with the current allocator
// Copy blob contents to memory owned by the new blob.
// (was: CreateBlobWithEncodingOnHeapCopy)
virtual HRESULT STDMETHODCALLTYPE CreateBlob(
_In_bytecount_(size) LPCVOID pData, UINT32 size, UINT32 codePage,
_COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
// (was: CreateBlobFromFile)
virtual HRESULT STDMETHODCALLTYPE LoadFile(
_In_z_ LPCWSTR pFileName, _In_opt_ UINT32* pCodePage,
_COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateReadOnlyStreamFromBlob(
_In_ IDxcBlob *pBlob, _COM_Outptr_ IStream **ppStream) = 0;
// Create default file-based include handler
virtual HRESULT STDMETHODCALLTYPE CreateDefaultIncludeHandler(
_COM_Outptr_ IDxcIncludeHandler **ppResult) = 0;
// Convert or return matching encoded text blobs
virtual HRESULT STDMETHODCALLTYPE GetBlobAsUtf8(
_In_ IDxcBlob *pBlob, _COM_Outptr_ IDxcBlobUtf8 **pBlobEncoding) = 0;
virtual HRESULT STDMETHODCALLTYPE GetBlobAsUtf16(
_In_ IDxcBlob *pBlob, _COM_Outptr_ IDxcBlobUtf16 **pBlobEncoding) = 0;
virtual HRESULT STDMETHODCALLTYPE GetDxilContainerPart(
_In_ const DxcBuffer *pShader,
_In_ UINT32 DxcPart,
_Outptr_result_nullonfailure_ void **ppPartData,
_Out_ UINT32 *pPartSizeInBytes) = 0;
// Create reflection interface from serialized Dxil container, or DXC_PART_REFLECTION_DATA.
// TBD: Require part header for RDAT? (leaning towards yes)
virtual HRESULT STDMETHODCALLTYPE CreateReflection(
_In_ const DxcBuffer *pData, REFIID iid, void **ppvReflection) = 0;
virtual HRESULT STDMETHODCALLTYPE BuildArguments(
_In_opt_z_ LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and include handlers.
_In_opt_z_ LPCWSTR pEntryPoint, // Entry point name. (-E)
_In_z_ LPCWSTR pTargetProfile, // Shader profile to compile. (-T)
_In_opt_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
_In_ UINT32 argCount, // Number of arguments
_In_count_(defineCount)
const DxcDefine *pDefines, // Array of defines
_In_ UINT32 defineCount, // Number of defines
_COM_Outptr_ IDxcCompilerArgs **ppArgs // Arguments you can use with Compile() method
) = 0;
// Takes the shader PDB and returns the hash and the container inside it
virtual HRESULT STDMETHODCALLTYPE GetPDBContents(
_In_ IDxcBlob *pPDBBlob, _COM_Outptr_ IDxcBlob **ppHash, _COM_Outptr_ IDxcBlob **ppContainer) = 0;
};
// For use with IDxcResult::[Has|Get]Output dxcOutKind argument
// Note: text outputs returned from version 2 APIs are UTF-8 or UTF-16 based on -encoding option
typedef enum DXC_OUT_KIND {
DXC_OUT_NONE = 0,
DXC_OUT_OBJECT = 1, // IDxcBlob - Shader or library object
DXC_OUT_ERRORS = 2, // IDxcBlobUtf8 or IDxcBlobUtf16
DXC_OUT_PDB = 3, // IDxcBlob
DXC_OUT_SHADER_HASH = 4, // IDxcBlob - DxcShaderHash of shader or shader with source info (-Zsb/-Zss)
DXC_OUT_DISASSEMBLY = 5, // IDxcBlobUtf8 or IDxcBlobUtf16 - from Disassemble
DXC_OUT_HLSL = 6, // IDxcBlobUtf8 or IDxcBlobUtf16 - from Preprocessor or Rewriter
DXC_OUT_TEXT = 7, // IDxcBlobUtf8 or IDxcBlobUtf16 - other text, such as -ast-dump or -Odump
DXC_OUT_REFLECTION = 8, // IDxcBlob - RDAT part with reflection data
DXC_OUT_ROOT_SIGNATURE = 9, // IDxcBlob - Serialized root signature output
DXC_OUT_EXTRA_OUTPUTS = 10,// IDxcExtraResults - Extra outputs
DXC_OUT_FORCE_DWORD = 0xFFFFFFFF
} DXC_OUT_KIND;
CROSS_PLATFORM_UUIDOF(IDxcResult, "58346CDA-DDE7-4497-9461-6F87AF5E0659")
struct IDxcResult : public IDxcOperationResult {
virtual BOOL STDMETHODCALLTYPE HasOutput(_In_ DXC_OUT_KIND dxcOutKind) = 0;
virtual HRESULT STDMETHODCALLTYPE GetOutput(_In_ DXC_OUT_KIND dxcOutKind,
_In_ REFIID iid, _COM_Outptr_opt_result_maybenull_ void **ppvObject,
_COM_Outptr_ IDxcBlobUtf16 **ppOutputName) = 0;
virtual UINT32 GetNumOutputs() = 0;
virtual DXC_OUT_KIND GetOutputByIndex(UINT32 Index) = 0;
virtual DXC_OUT_KIND PrimaryOutput() = 0;
};
// Special names for extra output that should get written to specific streams
#define DXC_EXTRA_OUTPUT_NAME_STDOUT L"*stdout*"
#define DXC_EXTRA_OUTPUT_NAME_STDERR L"*stderr*"
CROSS_PLATFORM_UUIDOF(IDxcExtraOutputs, "319b37a2-a5c2-494a-a5de-4801b2faf989")
struct IDxcExtraOutputs : public IUnknown {
virtual UINT32 STDMETHODCALLTYPE GetOutputCount() = 0;
virtual HRESULT STDMETHODCALLTYPE GetOutput(_In_ UINT32 uIndex,
_In_ REFIID iid, _COM_Outptr_opt_result_maybenull_ void **ppvObject,
_COM_Outptr_opt_result_maybenull_ IDxcBlobUtf16 **ppOutputType,
_COM_Outptr_opt_result_maybenull_ IDxcBlobUtf16 **ppOutputName) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcCompiler3, "228B4687-5A6A-4730-900C-9702B2203F54")
struct IDxcCompiler3 : public IUnknown {
// Compile a single entry point to the target shader model,
// Compile a library to a library target (-T lib_*),
// Compile a root signature (-T rootsig_*), or
// Preprocess HLSL source (-P)
virtual HRESULT STDMETHODCALLTYPE Compile(
_In_ const DxcBuffer *pSource, // Source text to compile
_In_opt_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
_In_ UINT32 argCount, // Number of arguments
_In_opt_ IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle #include directives (optional)
_In_ REFIID riid, _Out_ LPVOID *ppResult // IDxcResult: status, buffer, and errors
) = 0;
// Disassemble a program.
virtual HRESULT STDMETHODCALLTYPE Disassemble(
_In_ const DxcBuffer *pObject, // Program to disassemble: dxil container or bitcode.
_In_ REFIID riid, _Out_ LPVOID *ppResult // IDxcResult: status, disassembly text, and errors
) = 0;
};
static const UINT32 DxcValidatorFlags_Default = 0;
static const UINT32 DxcValidatorFlags_InPlaceEdit = 1; // Validator is allowed to update shader blob in-place.
static const UINT32 DxcValidatorFlags_RootSignatureOnly = 2;
static const UINT32 DxcValidatorFlags_ModuleOnly = 4;
static const UINT32 DxcValidatorFlags_ValidMask = 0x7;
CROSS_PLATFORM_UUIDOF(IDxcValidator, "A6E82BD2-1FD7-4826-9811-2857E797F49A")
struct IDxcValidator : public IUnknown {
// Validate a shader.
virtual HRESULT STDMETHODCALLTYPE Validate(
_In_ IDxcBlob *pShader, // Shader to validate.
_In_ UINT32 Flags, // Validation flags.
_COM_Outptr_ IDxcOperationResult **ppResult // Validation output status, buffer, and errors
) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcContainerBuilder, "334b1f50-2292-4b35-99a1-25588d8c17fe")
struct IDxcContainerBuilder : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE Load(_In_ IDxcBlob *pDxilContainerHeader) = 0; // Loads DxilContainer to the builder
virtual HRESULT STDMETHODCALLTYPE AddPart(_In_ UINT32 fourCC, _In_ IDxcBlob *pSource) = 0; // Part to add to the container
virtual HRESULT STDMETHODCALLTYPE RemovePart(_In_ UINT32 fourCC) = 0; // Remove the part with fourCC
virtual HRESULT STDMETHODCALLTYPE SerializeContainer(_Out_ IDxcOperationResult **ppResult) = 0; // Builds a container of the given container builder state
};
CROSS_PLATFORM_UUIDOF(IDxcAssembler, "091f7a26-1c1f-4948-904b-e6e3a8a771d5")
struct IDxcAssembler : public IUnknown {
// Assemble dxil in ll or llvm bitcode to DXIL container.
virtual HRESULT STDMETHODCALLTYPE AssembleToContainer(
_In_ IDxcBlob *pShader, // Shader to assemble.
_COM_Outptr_ IDxcOperationResult **ppResult // Assembly output status, buffer, and errors
) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcContainerReflection, "d2c21b26-8350-4bdc-976a-331ce6f4c54c")
struct IDxcContainerReflection : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE Load(_In_ IDxcBlob *pContainer) = 0; // Container to load.
virtual HRESULT STDMETHODCALLTYPE GetPartCount(_Out_ UINT32 *pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetPartKind(UINT32 idx, _Out_ UINT32 *pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetPartContent(UINT32 idx, _COM_Outptr_ IDxcBlob **ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE FindFirstPartKind(UINT32 kind, _Out_ UINT32 *pResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetPartReflection(UINT32 idx, REFIID iid, void **ppvObject) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcOptimizerPass, "AE2CD79F-CC22-453F-9B6B-B124E7A5204C")
struct IDxcOptimizerPass : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE GetOptionName(_COM_Outptr_ LPWSTR *ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetDescription(_COM_Outptr_ LPWSTR *ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetOptionArgCount(_Out_ UINT32 *pCount) = 0;
virtual HRESULT STDMETHODCALLTYPE GetOptionArgName(UINT32 argIndex, _COM_Outptr_ LPWSTR *ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE GetOptionArgDescription(UINT32 argIndex, _COM_Outptr_ LPWSTR *ppResult) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcOptimizer, "25740E2E-9CBA-401B-9119-4FB42F39F270")
struct IDxcOptimizer : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE GetAvailablePassCount(_Out_ UINT32 *pCount) = 0;
virtual HRESULT STDMETHODCALLTYPE GetAvailablePass(UINT32 index, _COM_Outptr_ IDxcOptimizerPass** ppResult) = 0;
virtual HRESULT STDMETHODCALLTYPE RunOptimizer(IDxcBlob *pBlob,
_In_count_(optionCount) LPCWSTR *ppOptions, UINT32 optionCount,
_COM_Outptr_ IDxcBlob **pOutputModule,
_COM_Outptr_opt_ IDxcBlobEncoding **ppOutputText) = 0;
};
static const UINT32 DxcVersionInfoFlags_None = 0;
static const UINT32 DxcVersionInfoFlags_Debug = 1; // Matches VS_FF_DEBUG
static const UINT32 DxcVersionInfoFlags_Internal = 2; // Internal Validator (non-signing)
CROSS_PLATFORM_UUIDOF(IDxcVersionInfo, "b04f5b50-2059-4f12-a8ff-a1e0cde1cc7e")
struct IDxcVersionInfo : public IUnknown {
virtual HRESULT STDMETHODCALLTYPE GetVersion(_Out_ UINT32 *pMajor, _Out_ UINT32 *pMinor) = 0;
virtual HRESULT STDMETHODCALLTYPE GetFlags(_Out_ UINT32 *pFlags) = 0;
};
CROSS_PLATFORM_UUIDOF(IDxcVersionInfo2, "fb6904c4-42f0-4b62-9c46-983af7da7c83")
struct IDxcVersionInfo2 : public IDxcVersionInfo {
virtual HRESULT STDMETHODCALLTYPE GetCommitInfo(_Out_ UINT32 *pCommitCount, _Out_ char **pCommitHash) = 0;
};
// Note: __declspec(selectany) requires 'extern'
// On Linux __declspec(selectany) is removed and using 'extern' results in link error.
#ifdef _MSC_VER
#define CLSID_SCOPE __declspec(selectany) extern
#else
#define CLSID_SCOPE
#endif
CLSID_SCOPE const CLSID CLSID_DxcCompiler = {
0x73e22d93,
0xe6ce,
0x47f3,
{0xb5, 0xbf, 0xf0, 0x66, 0x4f, 0x39, 0xc1, 0xb0}};
// {EF6A8087-B0EA-4D56-9E45-D07E1A8B7806}
CLSID_SCOPE const GUID CLSID_DxcLinker = {
0xef6a8087,
0xb0ea,
0x4d56,
{0x9e, 0x45, 0xd0, 0x7e, 0x1a, 0x8b, 0x78, 0x6}};
// {CD1F6B73-2AB0-484D-8EDC-EBE7A43CA09F}
CLSID_SCOPE const CLSID CLSID_DxcDiaDataSource = {
0xcd1f6b73,
0x2ab0,
0x484d,
{0x8e, 0xdc, 0xeb, 0xe7, 0xa4, 0x3c, 0xa0, 0x9f}};
// {3E56AE82-224D-470F-A1A1-FE3016EE9F9D}
CLSID_SCOPE const CLSID CLSID_DxcCompilerArgs = {
0x3e56ae82,
0x224d,
0x470f,
{0xa1, 0xa1, 0xfe, 0x30, 0x16, 0xee, 0x9f, 0x9d}};
// {6245D6AF-66E0-48FD-80B4-4D271796748C}
CLSID_SCOPE const GUID CLSID_DxcLibrary = {
0x6245d6af,
0x66e0,
0x48fd,
{0x80, 0xb4, 0x4d, 0x27, 0x17, 0x96, 0x74, 0x8c}};
CLSID_SCOPE const GUID CLSID_DxcUtils = CLSID_DxcLibrary;
// {8CA3E215-F728-4CF3-8CDD-88AF917587A1}
CLSID_SCOPE const GUID CLSID_DxcValidator = {
0x8ca3e215,
0xf728,
0x4cf3,
{0x8c, 0xdd, 0x88, 0xaf, 0x91, 0x75, 0x87, 0xa1}};
// {D728DB68-F903-4F80-94CD-DCCF76EC7151}
CLSID_SCOPE const GUID CLSID_DxcAssembler = {
0xd728db68,
0xf903,
0x4f80,
{0x94, 0xcd, 0xdc, 0xcf, 0x76, 0xec, 0x71, 0x51}};
// {b9f54489-55b8-400c-ba3a-1675e4728b91}
CLSID_SCOPE const GUID CLSID_DxcContainerReflection = {
0xb9f54489,
0x55b8,
0x400c,
{0xba, 0x3a, 0x16, 0x75, 0xe4, 0x72, 0x8b, 0x91}};
// {AE2CD79F-CC22-453F-9B6B-B124E7A5204C}
CLSID_SCOPE const GUID CLSID_DxcOptimizer = {
0xae2cd79f,
0xcc22,
0x453f,
{0x9b, 0x6b, 0xb1, 0x24, 0xe7, 0xa5, 0x20, 0x4c}};
// {94134294-411f-4574-b4d0-8741e25240d2}
CLSID_SCOPE const GUID CLSID_DxcContainerBuilder = {
0x94134294,
0x411f,
0x4574,
{0xb4, 0xd0, 0x87, 0x41, 0xe2, 0x52, 0x40, 0xd2}};
#endif
+104
View File
@@ -0,0 +1,104 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "dxil_buffer.h"
#include <assert.h>
void
dxil_buffer_init(struct dxil_buffer *b, unsigned abbrev_width)
{
blob_init(&b->blob);
b->buf = 0;
b->buf_bits = 0;
b->abbrev_width = abbrev_width;
}
void
dxil_buffer_finish(struct dxil_buffer *b)
{
blob_finish(&b->blob);
}
static bool
flush_dword(struct dxil_buffer *b)
{
assert(b->buf_bits >= 32 && b->buf_bits < 64);
uint32_t lower_bits = b->buf & UINT32_MAX;
if (!blob_write_bytes(&b->blob, &lower_bits, sizeof(lower_bits)))
return false;
b->buf >>= 32;
b->buf_bits -= 32;
return true;
}
bool
dxil_buffer_emit_bits(struct dxil_buffer *b, uint32_t data, unsigned width)
{
assert(b->buf_bits < 32);
assert(width > 0 && width <= 32);
assert((data & ~((UINT64_C(1) << width) - 1)) == 0);
b->buf |= ((uint64_t)data) << b->buf_bits;
b->buf_bits += width;
if (b->buf_bits >= 32)
return flush_dword(b);
return true;
}
bool
dxil_buffer_emit_vbr_bits(struct dxil_buffer *b, uint64_t data,
unsigned width)
{
assert(width > 1 && width <= 32);
uint32_t tag = UINT32_C(1) << (width - 1);
uint32_t max = tag - 1;
while (data > max) {
uint32_t value = (data & max) | tag;
data >>= width - 1;
if (!dxil_buffer_emit_bits(b, value, width))
return false;
}
return dxil_buffer_emit_bits(b, data, width);
}
bool
dxil_buffer_align(struct dxil_buffer *b)
{
assert(b->buf_bits < 32);
if (b->buf_bits) {
b->buf_bits = 32;
return flush_dword(b);
}
return true;
}
+60
View File
@@ -0,0 +1,60 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DXIL_BUFFER_H
#define DXIL_BUFFER_H
#include "util/blob.h"
struct dxil_buffer {
struct blob blob;
uint64_t buf;
unsigned buf_bits;
unsigned abbrev_width;
};
void
dxil_buffer_init(struct dxil_buffer *b, unsigned abbrev_width);
void
dxil_buffer_finish(struct dxil_buffer *b);
bool
dxil_buffer_emit_bits(struct dxil_buffer *b, uint32_t data, unsigned width);
bool
dxil_buffer_emit_vbr_bits(struct dxil_buffer *b, uint64_t data,
unsigned width);
bool
dxil_buffer_align(struct dxil_buffer *b);
static inline bool
dxil_buffer_emit_abbrev_id(struct dxil_buffer *b, uint32_t id)
{
return dxil_buffer_emit_bits(b, id, b->abbrev_width);
}
#endif
+129
View File
@@ -0,0 +1,129 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "dxil_buffer.h"
#include <assert.h>
#include <stdio.h>
static void
init()
{
struct dxil_buffer buf;
dxil_buffer_init(&buf, 2);
assert(!buf.buf);
assert(!buf.buf_bits);
}
static void
assert_blob_data(const struct dxil_buffer *m, const uint8_t *data,
size_t len)
{
if (m->blob.size != len) {
fprintf(stderr, "blob-size mismatch, expected %zd, got %zd",
len, m->blob.size);
abort();
}
for (size_t i = 0; i < len; ++i) {
if (m->blob.data[i] != data[i]) {
fprintf(stderr, "blob-data mismatch at index %zd, "
"expected 0x%02x, got 0x%02x", i,
data[i], m->blob.data[i]);
abort();
}
}
}
#define ASSERT_BLOB_DATA(m, data) \
assert_blob_data(m, data, sizeof(data))
static void
align()
{
struct dxil_buffer buf;
dxil_buffer_init(&buf, 2);
assert_blob_data(&buf, NULL, 0);
dxil_buffer_init(&buf, 2);
dxil_buffer_emit_bits(&buf, 0xbeef, 16);
dxil_buffer_align(&buf);
assert(!buf.buf);
assert(!buf.buf_bits);
uint8_t expected0[] = { 0xef, 0xbe, 0x00, 0x00 };
ASSERT_BLOB_DATA(&buf, expected0);
dxil_buffer_align(&buf);
ASSERT_BLOB_DATA(&buf, expected0);
}
static void
emit_bits()
{
struct dxil_buffer buf;
dxil_buffer_init(&buf, 2);
dxil_buffer_emit_bits(&buf, 0xbeef, 16);
dxil_buffer_align(&buf);
assert(!buf.buf);
assert(!buf.buf_bits);
uint8_t expected0[] = { 0xef, 0xbe, 0x00, 0x00 };
ASSERT_BLOB_DATA(&buf, expected0);
dxil_buffer_init(&buf, 2);
dxil_buffer_emit_bits(&buf, 0xdead, 16);
dxil_buffer_emit_bits(&buf, 0xbeef, 16);
assert(!buf.buf);
assert(!buf.buf_bits);
uint8_t expected1[] = { 0xad, 0xde, 0xef, 0xbe };
ASSERT_BLOB_DATA(&buf, expected1);
dxil_buffer_init(&buf, 2);
dxil_buffer_emit_bits(&buf, 0x1111111, 28);
dxil_buffer_emit_bits(&buf, 0x22222222, 32);
dxil_buffer_align(&buf);
uint8_t expected2[] = { 0x11, 0x11, 0x11, 0x21, 0x22, 0x22, 0x22, 0x02 };
ASSERT_BLOB_DATA(&buf, expected2);
}
static void
emit_vbr_bits()
{
struct dxil_buffer buf;
dxil_buffer_init(&buf, 2);
dxil_buffer_emit_vbr_bits(&buf, 0x1a, 8);
dxil_buffer_emit_vbr_bits(&buf, 0x1a, 6);
dxil_buffer_emit_vbr_bits(&buf, 0x00, 2);
dxil_buffer_emit_vbr_bits(&buf, 0x0a, 4);
dxil_buffer_emit_vbr_bits(&buf, 0x04, 2);
dxil_buffer_emit_vbr_bits(&buf, 0x00, 2);
uint8_t expected[] = { 0x1a, 0x1a, 0x1a, 0x1a };
ASSERT_BLOB_DATA(&buf, expected);
}
int
main()
{
init();
align();
emit_bits();
emit_vbr_bits();
return 0;
}
+395
View File
@@ -0,0 +1,395 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "dxil_container.h"
#include "dxil_module.h"
#include "util/u_debug.h"
#include <assert.h>
const uint32_t DXIL_DXBC = DXIL_FOURCC('D', 'X', 'B', 'C');
void
dxil_container_init(struct dxil_container *c)
{
blob_init(&c->parts);
c->num_parts = 0;
}
void
dxil_container_finish(struct dxil_container *c)
{
blob_finish(&c->parts);
}
static bool
add_part_header(struct dxil_container *c,
enum dxil_part_fourcc fourcc,
uint32_t part_size)
{
assert(c->parts.size < UINT_MAX);
unsigned offset = (unsigned)c->parts.size;
if (!blob_write_bytes(&c->parts, &fourcc, sizeof(fourcc)) ||
!blob_write_bytes(&c->parts, &part_size, sizeof(part_size)))
return false;
assert(c->num_parts < DXIL_MAX_PARTS);
c->part_offsets[c->num_parts++] = offset;
return true;
}
static bool
add_part(struct dxil_container *c,
enum dxil_part_fourcc fourcc,
const void *part_data, uint32_t part_size)
{
return add_part_header(c, fourcc, part_size) &&
blob_write_bytes(&c->parts, part_data, part_size);
}
bool
dxil_container_add_features(struct dxil_container *c,
const struct dxil_features *features)
{
/* DXIL feature info is a bitfield packed into a uint64_t. */
static_assert(sizeof(struct dxil_features) <= sizeof(uint64_t),
"Expected dxil_features to fit into a uint64_t");
uint64_t bits = 0;
memcpy(&bits, features, sizeof(struct dxil_features));
return add_part(c, DXIL_SFI0, &bits, sizeof(uint64_t));
}
typedef struct {
struct {
const char *name;
uint32_t offset;
} entries[DXIL_SHADER_MAX_IO_ROWS];
uint32_t num_entries;
} name_offset_cache_t;
static uint32_t
get_semantic_name_offset(name_offset_cache_t *cache, const char *name,
struct _mesa_string_buffer *buf, uint32_t buf_offset,
bool validator_7)
{
uint32_t offset = buf->length + buf_offset;
/* DXC doesn't de-duplicate arbitrary semantic names until validator 1.7, only SVs. */
if (validator_7 || strncmp(name, "SV_", 3) == 0) {
/* consider replacing this with a binary search using rb_tree */
for (unsigned i = 0; i < cache->num_entries; ++i) {
if (!strcmp(name, cache->entries[i].name))
return cache->entries[i].offset;
}
cache->entries[cache->num_entries].name = name;
cache->entries[cache->num_entries].offset = offset;
++cache->num_entries;
}
_mesa_string_buffer_append_len(buf, name, strlen(name) + 1);
return offset;
}
static uint32_t
collect_semantic_names(unsigned num_records,
struct dxil_signature_record *io_data,
struct _mesa_string_buffer *buf,
uint32_t buf_offset,
bool validator_7)
{
name_offset_cache_t cache;
cache.num_entries = 0;
for (unsigned i = 0; i < num_records; ++i) {
struct dxil_signature_record *io = &io_data[i];
uint32_t offset = get_semantic_name_offset(&cache, io->name, buf, buf_offset, validator_7);
for (unsigned j = 0; j < io->num_elements; ++j)
io->elements[j].semantic_name_offset = offset;
}
if (validator_7 && buf->length % sizeof(uint32_t) != 0) {
unsigned padding_to_add = sizeof(uint32_t) - (buf->length % sizeof(uint32_t));
char padding[sizeof(uint32_t)] = { 0 };
_mesa_string_buffer_append_len(buf, padding, padding_to_add);
}
return buf_offset + buf->length;
}
bool
dxil_container_add_io_signature(struct dxil_container *c,
enum dxil_part_fourcc part,
unsigned num_records,
struct dxil_signature_record *io_data,
bool validator_7)
{
struct {
uint32_t param_count;
uint32_t param_offset;
} header;
header.param_count = 0;
uint32_t fixed_size = sizeof(header);
header.param_offset = fixed_size;
bool retval = true;
for (unsigned i = 0; i < num_records; ++i) {
/* TODO:
* - Here we need to check whether the value is actually part of the
* signature */
fixed_size += sizeof(struct dxil_signature_element) * io_data[i].num_elements;
header.param_count += io_data[i].num_elements;
}
struct _mesa_string_buffer *names =
_mesa_string_buffer_create(NULL, 1024);
uint32_t last_offset = collect_semantic_names(num_records, io_data,
names, fixed_size,
validator_7);
if (!add_part_header(c, part, last_offset) ||
!blob_write_bytes(&c->parts, &header, sizeof(header))) {
retval = false;
goto cleanup;
}
/* write all parts */
for (unsigned i = 0; i < num_records; ++i)
for (unsigned j = 0; j < io_data[i].num_elements; ++j) {
if (!blob_write_bytes(&c->parts, &io_data[i].elements[j],
sizeof(io_data[i].elements[j]))) {
retval = false;
goto cleanup;
}
}
/* write all names */
if (!blob_write_bytes(&c->parts, names->buf, names->length))
retval = false;
cleanup:
_mesa_string_buffer_destroy(names);
return retval;
}
bool
dxil_container_add_state_validation(struct dxil_container *c,
const struct dxil_module *m,
struct dxil_validation_state *state)
{
uint32_t psv_size = m->minor_validator >= 8 ?
sizeof(struct dxil_psv_runtime_info_3) : m->minor_validator >= 6 ?
sizeof(struct dxil_psv_runtime_info_2) : sizeof(struct dxil_psv_runtime_info_1);
uint32_t resource_bind_info_size = m->minor_validator >= 6 ?
sizeof(struct dxil_resource_v1) : sizeof(struct dxil_resource_v0);
uint32_t dxil_pvs_sig_size = sizeof(struct dxil_psv_signature_element);
uint32_t resource_count = state->num_resources;
struct dxil_psv_runtime_info_3 *psv3 = &state->state;
struct dxil_psv_runtime_info_2 *psv2 = &psv3->psv2;
struct dxil_psv_runtime_info_1 *psv1 = &psv2->psv1;
uint32_t size = psv_size + 2 * sizeof(uint32_t);
if (resource_count > 0) {
size += sizeof (uint32_t) +
resource_bind_info_size * resource_count;
}
uint32_t string_table_size = (m->sem_string_table->length + 3) & ~3u;
size += sizeof(uint32_t) + string_table_size;
size += sizeof(uint32_t) + m->sem_index_table.size * sizeof(uint32_t);
if (m->num_sig_inputs || m->num_sig_outputs || m->num_sig_patch_consts) {
size += sizeof(uint32_t);
}
size += dxil_pvs_sig_size * m->num_sig_inputs;
size += dxil_pvs_sig_size * m->num_sig_outputs;
size += dxil_pvs_sig_size * m->num_sig_patch_consts;
psv1->sig_input_vectors = (uint8_t)m->num_psv_inputs;
for (unsigned i = 0; i < 4; ++i)
psv1->sig_output_vectors[i] = (uint8_t)m->num_psv_outputs[i];
if (psv1->uses_view_id) {
for (unsigned i = 0; i < 4; ++i)
size += m->dependency_table_dwords_per_input[i] * sizeof(uint32_t);
}
for (unsigned i = 0; i < 4; ++i)
size += m->io_dependency_table_size[i] * sizeof(uint32_t);
if (!add_part_header(c, DXIL_PSV0, size))
return false;
if (!blob_write_bytes(&c->parts, &psv_size, sizeof(psv_size)))
return false;
if (!blob_write_bytes(&c->parts, &state->state, psv_size))
return false;
if (!blob_write_bytes(&c->parts, &resource_count, sizeof(resource_count)))
return false;
if (resource_count > 0) {
if (!blob_write_bytes(&c->parts, &resource_bind_info_size, sizeof(resource_bind_info_size)) ||
!blob_write_bytes(&c->parts, state->resources.v0, resource_bind_info_size * state->num_resources))
return false;
}
uint32_t fill = 0;
if (!blob_write_bytes(&c->parts, &string_table_size, sizeof(string_table_size)) ||
!blob_write_bytes(&c->parts, m->sem_string_table->buf, m->sem_string_table->length) ||
!blob_write_bytes(&c->parts, &fill, string_table_size - m->sem_string_table->length))
return false;
if (!blob_write_bytes(&c->parts, &m->sem_index_table.size, sizeof(uint32_t)))
return false;
if (m->sem_index_table.size > 0) {
if (!blob_write_bytes(&c->parts, m->sem_index_table.data,
m->sem_index_table.size * sizeof(uint32_t)))
return false;
}
if (m->num_sig_inputs || m->num_sig_outputs || m->num_sig_patch_consts) {
if (!blob_write_bytes(&c->parts, &dxil_pvs_sig_size, sizeof(dxil_pvs_sig_size)))
return false;
if (!blob_write_bytes(&c->parts, &m->psv_inputs, dxil_pvs_sig_size * m->num_sig_inputs))
return false;
if (!blob_write_bytes(&c->parts, &m->psv_outputs, dxil_pvs_sig_size * m->num_sig_outputs))
return false;
if (!blob_write_bytes(&c->parts, &m->psv_patch_consts, dxil_pvs_sig_size * m->num_sig_patch_consts))
return false;
}
/* This was a bug in the DXIL validation logic prior to 1.8. When replicating these I/O dependency
* tables from the metadata to the container, the pointer is advanced for each stream,
* and then copied for all streams... meaning that the first streams have zero data, since the
* pointer is advanced and then never written to. The last stream (that has data) then has the
* data from all streams written to it. However, if any stream before the last one has a larger
* size, this will cause corruption, since it's writing to the smaller space that was allocated
* for the last stream. We assume that never happens, and just zero all earlier streams. */
if (m->shader_kind == DXIL_GEOMETRY_SHADER && m->minor_validator < 8) {
bool zero_view_id_deps = false, zero_io_deps = false;
for (int i = 3; i >= 0; --i) {
if (psv1->uses_view_id && m->dependency_table_dwords_per_input[i]) {
if (zero_view_id_deps)
memset(m->viewid_dependency_table[i], 0, sizeof(uint32_t) * m->dependency_table_dwords_per_input[i]);
zero_view_id_deps = true;
}
if (m->io_dependency_table_size[i]) {
if (zero_io_deps)
memset(m->io_dependency_table[i], 0, sizeof(uint32_t) * m->io_dependency_table_size[i]);
zero_io_deps = true;
}
}
}
if (psv1->uses_view_id) {
for (unsigned i = 0; i < 4; ++i)
if (!blob_write_bytes(&c->parts, m->viewid_dependency_table[i],
sizeof(uint32_t) * m->dependency_table_dwords_per_input[i]))
return false;
}
for (unsigned i = 0; i < 4; ++i)
if (!blob_write_bytes(&c->parts, m->io_dependency_table[i],
sizeof(uint32_t) * m->io_dependency_table_size[i]))
return false;
return true;
}
bool
dxil_container_add_module(struct dxil_container *c,
const struct dxil_module *m)
{
assert(m->buf.buf_bits == 0); // make sure the module is fully flushed
uint32_t version = (m->shader_kind << 16) |
(m->major_version << 4) |
m->minor_version;
uint32_t size = 6 * sizeof(uint32_t) + m->buf.blob.size;
assert(size % sizeof(uint32_t) == 0);
uint32_t uint32_size = size / sizeof(uint32_t);
uint32_t magic = 0x4C495844;
uint32_t dxil_version = 1 << 8; // I have no idea...
uint32_t bitcode_offset = 16;
uint32_t bitcode_size = m->buf.blob.size;
return add_part_header(c, DXIL_DXIL, size) &&
blob_write_bytes(&c->parts, &version, sizeof(version)) &&
blob_write_bytes(&c->parts, &uint32_size, sizeof(uint32_size)) &&
blob_write_bytes(&c->parts, &magic, sizeof(magic)) &&
blob_write_bytes(&c->parts, &dxil_version, sizeof(dxil_version)) &&
blob_write_bytes(&c->parts, &bitcode_offset, sizeof(bitcode_offset)) &&
blob_write_bytes(&c->parts, &bitcode_size, sizeof(bitcode_size)) &&
blob_write_bytes(&c->parts, m->buf.blob.data, m->buf.blob.size);
}
bool
dxil_container_write(struct dxil_container *c, struct blob *blob)
{
assert(blob->size == 0);
if (!blob_write_bytes(blob, &DXIL_DXBC, sizeof(DXIL_DXBC)))
return false;
const uint8_t unsigned_digest[16] = { 0 }; // null-digest means unsigned
if (!blob_write_bytes(blob, unsigned_digest, sizeof(unsigned_digest)))
return false;
uint16_t major_version = 1;
uint16_t minor_version = 0;
if (!blob_write_bytes(blob, &major_version, sizeof(major_version)) ||
!blob_write_bytes(blob, &minor_version, sizeof(minor_version)))
return false;
size_t header_size = 32 + 4 * c->num_parts;
size_t size = header_size + c->parts.size;
assert(size <= UINT32_MAX);
uint32_t container_size = (uint32_t)size;
if (!blob_write_bytes(blob, &container_size, sizeof(container_size)))
return false;
uint32_t part_offsets[DXIL_MAX_PARTS];
for (int i = 0; i < c->num_parts; ++i) {
size_t offset = header_size + c->part_offsets[i];
assert(offset <= UINT32_MAX);
part_offsets[i] = (uint32_t)offset;
}
if (!blob_write_bytes(blob, &c->num_parts, sizeof(c->num_parts)) ||
!blob_write_bytes(blob, part_offsets, sizeof(uint32_t) * c->num_parts) ||
!blob_write_bytes(blob, c->parts.data, c->parts.size))
return false;
return true;
}
+135
View File
@@ -0,0 +1,135 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DXIL_CONTAINER_H
#define DXIL_CONTAINER_H
#ifdef __cplusplus
extern "C" {
#endif
#include "util/blob.h"
#include "dxil_signature.h"
#define DXIL_MAX_PARTS 8
struct dxil_container {
struct blob parts;
unsigned part_offsets[DXIL_MAX_PARTS];
unsigned num_parts;
};
enum dxil_resource_type {
DXIL_RES_INVALID = 0,
DXIL_RES_SAMPLER = 1,
DXIL_RES_CBV = 2,
DXIL_RES_SRV_TYPED = 3,
DXIL_RES_SRV_RAW = 4,
DXIL_RES_SRV_STRUCTURED = 5,
DXIL_RES_UAV_TYPED = 6,
DXIL_RES_UAV_RAW = 7,
DXIL_RES_UAV_STRUCTURED,
DXIL_RES_UAV_STRUCTURED_WITH_COUNTER,
DXIL_RES_NUM_ENTRIES /* should always be last */
};
#define DXIL_FOURCC(ch0, ch1, ch2, ch3) ( \
(uint32_t)(ch0) | (uint32_t)(ch1) << 8 | \
(uint32_t)(ch2) << 16 | (uint32_t)(ch3) << 24)
enum dxil_part_fourcc {
DXIL_RDEF = DXIL_FOURCC('R', 'D', 'E', 'F'),
DXIL_ISG1 = DXIL_FOURCC('I', 'S', 'G', '1'),
DXIL_OSG1 = DXIL_FOURCC('O', 'S', 'G', '1'),
DXIL_PSG1 = DXIL_FOURCC('P', 'S', 'G', '1'),
DXIL_STAT = DXIL_FOURCC('S', 'T', 'A', 'T'),
DXIL_ILDB = DXIL_FOURCC('I', 'L', 'D', 'B'),
DXIL_ILDN = DXIL_FOURCC('I', 'L', 'D', 'N'),
DXIL_SFI0 = DXIL_FOURCC('S', 'F', 'I', '0'),
DXIL_PRIV = DXIL_FOURCC('P', 'R', 'I', 'V'),
DXIL_RTS0 = DXIL_FOURCC('R', 'T', 'S', '0'),
DXIL_DXIL = DXIL_FOURCC('D', 'X', 'I', 'L'),
DXIL_PSV0 = DXIL_FOURCC('P', 'S', 'V', '0'),
DXIL_RDAT = DXIL_FOURCC('R', 'D', 'A', 'T'),
DXIL_HASH = DXIL_FOURCC('H', 'A', 'S', 'H'),
};
struct dxil_resource_v0 {
uint32_t resource_type;
uint32_t space;
uint32_t lower_bound;
uint32_t upper_bound;
};
struct dxil_resource_v1 {
struct dxil_resource_v0 v0;
uint32_t resource_kind;
uint32_t resource_flags;
};
struct dxil_validation_state {
struct dxil_psv_runtime_info_3 state;
union {
const struct dxil_resource_v0 *v0;
const struct dxil_resource_v1 *v1;
} resources;
uint32_t num_resources;
};
void
dxil_container_init(struct dxil_container *c);
void
dxil_container_finish(struct dxil_container *c);
struct dxil_features;
bool
dxil_container_add_features(struct dxil_container *c,
const struct dxil_features *features);
bool
dxil_container_add_io_signature(struct dxil_container *c,
enum dxil_part_fourcc part,
unsigned num_records,
struct dxil_signature_record *io,
bool validator_7);
bool
dxil_container_add_state_validation(struct dxil_container *c,
const struct dxil_module *m,
struct dxil_validation_state *state);
bool
dxil_container_add_module(struct dxil_container *c,
const struct dxil_module *m);
bool
dxil_container_write(struct dxil_container *c, struct blob *blob);
#ifdef __cplusplus
}
#endif
#endif
+808
View File
@@ -0,0 +1,808 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "dxil_dump.h"
#include "dxil_internal.h"
#define DIXL_DUMP_DECL
#include "dxil_dump_decls.h"
#include "dxil_module.h"
#include "util/string_buffer.h"
#include "util/list.h"
#include <stdio.h>
struct dxil_dumper {
struct _mesa_string_buffer *buf;
int current_indent;
};
struct dxil_dumper *dxil_dump_create(void)
{
struct dxil_dumper *d = calloc(1, sizeof(struct dxil_dumper));
d->buf = _mesa_string_buffer_create(NULL, 1024);
d->current_indent = 0;
return d;
}
void dxil_dump_free(struct dxil_dumper *d)
{
_mesa_string_buffer_destroy(d->buf);
d->buf = 0;
free(d);
}
void dxil_dump_buf_to_file(struct dxil_dumper *d, FILE *f)
{
assert(f);
assert(d);
assert(d->buf);
fprintf(f, "%s", d->buf->buf);
}
static
void dxil_dump_indention_inc(struct dxil_dumper *d)
{
++d->current_indent;
}
static
void dxil_dump_indention_dec(struct dxil_dumper *d)
{
--d->current_indent;
assert(d->current_indent >= 0);
}
static
void dxil_dump_indent(struct dxil_dumper *d)
{
for (int i = 0; i < 2 * d->current_indent; ++i)
_mesa_string_buffer_append_char(d->buf, ' ');
}
void
dxil_dump_module(struct dxil_dumper *d, struct dxil_module *m)
{
assert(m);
assert(d);
_mesa_string_buffer_printf(d->buf, "DXIL MODULE:\n");
dump_metadata(d, m);
dump_shader_info(d, &m->info);
dump_types(d, &m->type_list);
dump_gvars(d, &m->gvar_list);
dump_funcs(d, &m->func_list);
dump_attr_set_list(d, &m->attr_set_list);
dump_constants(d, &m->const_list);
struct dxil_func_def *func_def;
LIST_FOR_EACH_ENTRY(func_def, &m->func_def_list, head) {
dump_instrs(d, &func_def->instr_list);
}
dump_mdnodes(d, &m->mdnode_list);
dump_named_nodes(d, &m->md_named_node_list);
dump_io_signatures(d->buf, m);
dump_psv(d->buf, m);
_mesa_string_buffer_printf(d->buf, "END DXIL MODULE\n");
}
static void
dump_metadata(struct dxil_dumper *d, struct dxil_module *m)
{
_mesa_string_buffer_printf(d->buf, "Shader: %s\n",
dump_shader_string(m->shader_kind));
_mesa_string_buffer_printf(d->buf, "Version: %d.%d\n",
m->major_version, m->minor_version);
dump_features(d->buf, &m->feats);
}
static void
dump_shader_info(struct dxil_dumper *d, struct dxil_shader_info *info)
{
_mesa_string_buffer_append(d->buf, "Shader Info:\n");
if (info->has_out_position)
_mesa_string_buffer_append(d->buf, " has_out_position\n");
}
static const char *
dump_shader_string(enum dxil_shader_kind kind)
{
#define SHADER_STR(X) case DXIL_ ## X ## _SHADER: return #X
switch (kind) {
SHADER_STR(VERTEX);
SHADER_STR(PIXEL);
SHADER_STR(GEOMETRY);
SHADER_STR(COMPUTE);
default:
return "UNSUPPORTED";
}
#undef SHADER_STR
}
static void
dump_features(struct _mesa_string_buffer *buf, struct dxil_features *feat)
{
_mesa_string_buffer_printf(buf, "Features:\n");
#define PRINT_FEAT(F) if (feat->F) _mesa_string_buffer_printf(buf, " %s\n", #F)
PRINT_FEAT(doubles);
PRINT_FEAT(cs_4x_raw_sb);
PRINT_FEAT(uavs_at_every_stage);
PRINT_FEAT(use_64uavs);
PRINT_FEAT(min_precision);
PRINT_FEAT(dx11_1_double_extensions);
PRINT_FEAT(dx11_1_shader_extensions);
PRINT_FEAT(dx9_comparison_filtering);
PRINT_FEAT(tiled_resources);
PRINT_FEAT(stencil_ref);
PRINT_FEAT(inner_coverage);
PRINT_FEAT(typed_uav_load_additional_formats);
PRINT_FEAT(rovs);
PRINT_FEAT(array_layer_from_vs_or_ds);
PRINT_FEAT(wave_ops);
PRINT_FEAT(int64_ops);
PRINT_FEAT(view_id);
PRINT_FEAT(barycentrics);
PRINT_FEAT(native_low_precision);
PRINT_FEAT(shading_rate);
PRINT_FEAT(raytracing_tier_1_1);
PRINT_FEAT(sampler_feedback);
#undef PRINT_FEAT
}
static void
dump_types(struct dxil_dumper *d, struct list_head *list)
{
if (!list_length(list))
return;
_mesa_string_buffer_append(d->buf, "Types:\n");
dxil_dump_indention_inc(d);
list_for_each_entry(struct dxil_type, type, list, head) {
dxil_dump_indent(d);
dump_type(d, type);
_mesa_string_buffer_append(d->buf, "\n");
}
dxil_dump_indention_dec(d);
}
static void dump_type_name(struct dxil_dumper *d, const struct dxil_type *type)
{
if (!type) {
_mesa_string_buffer_append(d->buf, "(type error)");
return;
}
switch (type->type) {
case TYPE_VOID:
_mesa_string_buffer_append(d->buf, "void");
break;
case TYPE_INTEGER:
_mesa_string_buffer_printf(d->buf, "int%d", type->int_bits);
break;
case TYPE_FLOAT:
_mesa_string_buffer_printf(d->buf, "float%d", type->float_bits);
break;
case TYPE_POINTER:
dump_type_name(d, type->ptr_target_type);
_mesa_string_buffer_append(d->buf, "*");
break;
case TYPE_STRUCT:
_mesa_string_buffer_printf(d->buf, "struct %s", type->struct_def.name);
break;
case TYPE_ARRAY:
dump_type_name(d, type->array_or_vector_def.elem_type);
_mesa_string_buffer_printf(d->buf, "[%zu]", type->array_or_vector_def.num_elems);
break;
case TYPE_FUNCTION:
_mesa_string_buffer_append(d->buf, "(");
dump_type_name(d, type->function_def.ret_type);
_mesa_string_buffer_append(d->buf, ")(");
for (size_t i = 0; i < type->function_def.args.num_types; ++i) {
if (i > 0)
_mesa_string_buffer_append(d->buf, ", ");
dump_type_name(d, type->function_def.args.types[i]);
}
_mesa_string_buffer_append(d->buf, ")");
break;
case TYPE_VECTOR:
_mesa_string_buffer_append(d->buf, "vector<");
dump_type_name(d, type->array_or_vector_def.elem_type);
_mesa_string_buffer_printf(d->buf, ", %zu>", type->array_or_vector_def.num_elems);
break;
default:
_mesa_string_buffer_printf(d->buf, "unknown type %d", type->type);
}
}
static void
dump_type(struct dxil_dumper *d, const struct dxil_type *type)
{
switch (type->type) {
case TYPE_STRUCT:
_mesa_string_buffer_printf(d->buf, "struct %s {\n", type->struct_def.name);
dxil_dump_indention_inc(d);
for (size_t i = 0; i < type->struct_def.elem.num_types; ++i) {
dxil_dump_indent(d);
dump_type(d, type->struct_def.elem.types[i]);
_mesa_string_buffer_append(d->buf, "\n");
}
dxil_dump_indention_dec(d);
dxil_dump_indent(d);
_mesa_string_buffer_append(d->buf, "}\n");
break;
default:
dump_type_name(d, type);
break;
}
}
static void
dump_gvars(struct dxil_dumper *d, struct list_head *list)
{
if (!list_length(list))
return;
_mesa_string_buffer_append(d->buf, "Global variables:\n");
dxil_dump_indention_inc(d);
list_for_each_entry(struct dxil_gvar, gvar, list, head) {
dxil_dump_indent(d);
_mesa_string_buffer_printf(d->buf, "address_space(%d) ", gvar->as);
if (gvar->constant)
_mesa_string_buffer_append(d->buf, "const ");
if (gvar->align)
_mesa_string_buffer_append(d->buf, "align ");
if (gvar->initializer)
_mesa_string_buffer_printf(d->buf, "init_id:%d\n", gvar->initializer->id);
dump_type_name(d, gvar->type);
_mesa_string_buffer_printf(d->buf, " val_id:%d\n", gvar->value.id);
}
dxil_dump_indention_dec(d);
}
static void
dump_funcs(struct dxil_dumper *d, struct list_head *list)
{
if (!list_length(list))
return;
_mesa_string_buffer_append(d->buf, "Functions:\n");
dxil_dump_indention_inc(d);
list_for_each_entry(struct dxil_func, func, list, head) {
dxil_dump_indent(d);
if (func->decl)
_mesa_string_buffer_append(d->buf, "declare ");
_mesa_string_buffer_append(d->buf, func->name);
_mesa_string_buffer_append_char(d->buf, ' ');
dump_type_name(d, func->type);
if (func->attr_set)
_mesa_string_buffer_printf(d->buf, " #%d", func->attr_set);
_mesa_string_buffer_append_char(d->buf, '\n');
}
dxil_dump_indention_dec(d);
}
static void
dump_attr_set_list(struct dxil_dumper *d, struct list_head *list)
{
if (!list_length(list))
return;
_mesa_string_buffer_append(d->buf, "Attribute set:\n");
dxil_dump_indention_inc(d);
int attr_id = 1;
list_for_each_entry(struct attrib_set, attr, list, head) {
_mesa_string_buffer_printf(d->buf, " #%d: {", attr_id++);
for (unsigned i = 0; i < attr->num_attrs; ++i) {
if (i > 0)
_mesa_string_buffer_append_char(d->buf, ' ');
if (attr->attrs[i].type == DXIL_ATTR_ENUM) {
const char *value = "";
switch (attr->attrs[i].key.kind) {
case DXIL_ATTR_KIND_NONE: value = "none"; break;
case DXIL_ATTR_KIND_NO_UNWIND: value = "nounwind"; break;
case DXIL_ATTR_KIND_READ_NONE: value = "readnone"; break;
case DXIL_ATTR_KIND_READ_ONLY: value = "readonly"; break;
case DXIL_ATTR_KIND_NO_DUPLICATE: value = "noduplicate"; break;
}
_mesa_string_buffer_append(d->buf, value);
} else if (attr->attrs[i].type == DXIL_ATTR_STRING) {
_mesa_string_buffer_append_char(d->buf, '"');
_mesa_string_buffer_append(d->buf, attr->attrs[i].key.str);
_mesa_string_buffer_append_char(d->buf, '"');
} else if (attr->attrs[i].type == DXIL_ATTR_STRING_VALUE) {
_mesa_string_buffer_append_char(d->buf, '"');
_mesa_string_buffer_append(d->buf, attr->attrs[i].key.str);
_mesa_string_buffer_append(d->buf, "\"=\"");
_mesa_string_buffer_append(d->buf, attr->attrs[i].value.str);
_mesa_string_buffer_append_char(d->buf, '"');
}
}
_mesa_string_buffer_append(d->buf, "}\n");
}
dxil_dump_indention_dec(d);
}
static void
dump_constants(struct dxil_dumper *d, struct list_head *list)
{
if (!list_length(list))
return;
_mesa_string_buffer_append(d->buf, "Constants:\n");
dxil_dump_indention_inc(d);
list_for_each_entry(struct dxil_const, cnst, list, head) {
_mesa_string_buffer_append_char(d->buf, ' ');
dump_value(d, &cnst->value);
_mesa_string_buffer_append(d->buf, " = ");
dump_type_name(d, cnst->value.type);
if (!cnst->undef) {
switch (cnst->value.type->type) {
case TYPE_FLOAT:
_mesa_string_buffer_printf(d->buf, " %10.5f\n", cnst->float_value);
break;
case TYPE_INTEGER:
_mesa_string_buffer_printf(d->buf, " %" PRIdMAX "\n", cnst->int_value);
break;
case TYPE_ARRAY:
_mesa_string_buffer_append(d->buf, "{");
for (unsigned i = 0;
i < cnst->value.type->array_or_vector_def.num_elems; i++) {
_mesa_string_buffer_printf(d->buf, " %%%d",
cnst->array_values[i]->id);
dump_type_name(d, cnst->value.type);
if (i != cnst->value.type->array_or_vector_def.num_elems - 1)
_mesa_string_buffer_append(d->buf, ",");
_mesa_string_buffer_append(d->buf, " ");
}
_mesa_string_buffer_append(d->buf, "}\n");
break;
case TYPE_STRUCT:
_mesa_string_buffer_append(d->buf, "{");
for (unsigned i = 0;
i < cnst->value.type->struct_def.elem.num_types; i++) {
_mesa_string_buffer_printf(d->buf, " %%%d",
cnst->struct_values[i]->id);
dump_type_name(d, cnst->struct_values[i]->type);
if (i != cnst->value.type->struct_def.elem.num_types - 1)
_mesa_string_buffer_append(d->buf, ",");
_mesa_string_buffer_append(d->buf, " ");
}
_mesa_string_buffer_append(d->buf, "}\n");
break;
default:
UNREACHABLE("Unsupported const type");
}
} else
_mesa_string_buffer_append(d->buf, " undef\n");
}
dxil_dump_indention_dec(d);
}
static void
dump_instrs(struct dxil_dumper *d, struct list_head *list)
{
_mesa_string_buffer_append(d->buf, "Shader body:\n");
dxil_dump_indention_inc(d);
list_for_each_entry(struct dxil_instr, instr, list, head) {
dxil_dump_indent(d);
if (instr->has_value) {
dump_value(d, &instr->value);
_mesa_string_buffer_append(d->buf, " = ");
} else {
_mesa_string_buffer_append_char(d->buf, ' ');
}
switch (instr->type) {
case INSTR_BINOP: dump_instr_binop(d, &instr->binop); break;
case INSTR_CMP: dump_instr_cmp(d, &instr->cmp);break;
case INSTR_SELECT:dump_instr_select(d, &instr->select); break;
case INSTR_CAST: dump_instr_cast(d, &instr->cast); break;
case INSTR_CALL: dump_instr_call(d, &instr->call); break;
case INSTR_RET: dump_instr_ret(d, &instr->ret); break;
case INSTR_EXTRACTVAL: dump_instr_extractval(d, &instr->extractval); break;
case INSTR_BR: dump_instr_branch(d, &instr->br); break;
case INSTR_PHI: dump_instr_phi(d, &instr->phi); break;
case INSTR_ALLOCA: dump_instr_alloca(d, &instr->alloca); break;
case INSTR_GEP: dump_instr_gep(d, &instr->gep); break;
case INSTR_LOAD: dump_instr_load(d, &instr->load); break;
case INSTR_STORE: dump_instr_store(d, &instr->store); break;
case INSTR_ATOMICRMW: dump_instr_atomicrmw(d, &instr->atomicrmw); break;
default:
_mesa_string_buffer_printf(d->buf, "unknown instruction type %d", instr->type);
}
_mesa_string_buffer_append(d->buf, "\n");
}
dxil_dump_indention_dec(d);
}
static void
dump_instr_binop(struct dxil_dumper *d, struct dxil_instr_binop *binop)
{
const char *str = binop->opcode < DXIL_BINOP_INSTR_COUNT ?
binop_strings[binop->opcode] : "INVALID";
_mesa_string_buffer_printf(d->buf, "%s ", str);
dump_instr_print_operands(d, 2, binop->operands);
}
static void
dump_instr_cmp(struct dxil_dumper *d, struct dxil_instr_cmp *cmp)
{
const char *str = cmp->pred < DXIL_CMP_INSTR_COUNT ?
pred_strings[cmp->pred] : "INVALID";
_mesa_string_buffer_printf(d->buf, "%s ", str);
dump_instr_print_operands(d, 2, cmp->operands);
}
static void
dump_instr_select(struct dxil_dumper *d, struct dxil_instr_select *select)
{
_mesa_string_buffer_append(d->buf, "sel ");
dump_instr_print_operands(d, 3, select->operands);
}
static void
dump_instr_cast(struct dxil_dumper *d, struct dxil_instr_cast *cast)
{
const char *str = cast->opcode < DXIL_CAST_INSTR_COUNT ?
cast_opcode_strings[cast->opcode] : "INVALID";
_mesa_string_buffer_printf(d->buf, "%s.", str);
dump_type_name(d, cast->type);
_mesa_string_buffer_append_char(d->buf, ' ');
dump_value(d, cast->value);
}
static void
dump_instr_call(struct dxil_dumper *d, struct dxil_instr_call *call)
{
assert(call->num_args == call->func->type->function_def.args.num_types);
struct dxil_type **func_arg_types = call->func->type->function_def.args.types;
_mesa_string_buffer_printf(d->buf, "%s(", call->func->name);
for (unsigned i = 0; i < call->num_args; ++i) {
if (i > 0)
_mesa_string_buffer_append(d->buf, ", ");
dump_type_name(d, func_arg_types[i]);
_mesa_string_buffer_append_char(d->buf, ' ');
dump_value(d, call->args[i]);
}
_mesa_string_buffer_append_char(d->buf, ')');
}
static void
dump_instr_ret(struct dxil_dumper *d, struct dxil_instr_ret *ret)
{
_mesa_string_buffer_append(d->buf, "ret ");
if (ret->value)
dump_value(d, ret->value);
}
static void
dump_instr_extractval(struct dxil_dumper *d, struct dxil_instr_extractval *extr)
{
_mesa_string_buffer_append(d->buf, "extractvalue ");
dump_type_name(d, extr->type);
dump_value(d, extr->src);
_mesa_string_buffer_printf(d->buf, ", %d", extr->idx);
}
static void
dump_instr_branch(struct dxil_dumper *d, struct dxil_instr_br *br)
{
_mesa_string_buffer_append(d->buf, "branch ");
if (br->cond)
dump_value(d, br->cond);
else
_mesa_string_buffer_append(d->buf, " (uncond)");
_mesa_string_buffer_printf(d->buf, " %d %d", br->succ[0], br->succ[1]);
}
static void
dump_instr_phi(struct dxil_dumper *d, struct dxil_instr_phi *phi)
{
_mesa_string_buffer_append(d->buf, "phi ");
dump_type_name(d, phi->type);
struct dxil_phi_src *src = phi->incoming;
for (unsigned i = 0; i < phi->num_incoming; ++i, ++src) {
if (i > 0)
_mesa_string_buffer_append(d->buf, ", ");
dump_value(d, src->value);
_mesa_string_buffer_printf(d->buf, "(%d)", src->block);
}
}
static void
dump_instr_alloca(struct dxil_dumper *d, struct dxil_instr_alloca *alloca)
{
_mesa_string_buffer_append(d->buf, "alloca ");
dump_type_name(d, alloca->alloc_type);
_mesa_string_buffer_append(d->buf, ", ");
dump_type_name(d, alloca->size_type);
_mesa_string_buffer_append(d->buf, ", ");
dump_value(d, alloca->size);
unsigned align_mask = (1 << 6 ) - 1;
unsigned align = alloca->align & align_mask;
_mesa_string_buffer_printf(d->buf, ", %d", 1 << (align - 1));
}
static void
dump_instr_gep(struct dxil_dumper *d, struct dxil_instr_gep *gep)
{
_mesa_string_buffer_append(d->buf, "getelementptr ");
if (gep->inbounds)
_mesa_string_buffer_append(d->buf, "inbounds ");
dump_type_name(d, gep->source_elem_type);
_mesa_string_buffer_append(d->buf, ", ");
for (unsigned i = 0; i < gep->num_operands; ++i) {
if (i > 0)
_mesa_string_buffer_append(d->buf, ", ");
dump_value(d, gep->operands[i]);
}
}
static void
dump_instr_load(struct dxil_dumper *d, struct dxil_instr_load *load)
{
_mesa_string_buffer_append(d->buf, "load ");
if (load->is_volatile)
_mesa_string_buffer_append(d->buf, " volatile");
dump_type_name(d, load->type);
_mesa_string_buffer_append(d->buf, ", ");
dump_value(d, load->ptr);
_mesa_string_buffer_printf(d->buf, ", %d", load->align);
}
static void
dump_instr_store(struct dxil_dumper *d, struct dxil_instr_store *store)
{
_mesa_string_buffer_append(d->buf, "store ");
if (store->is_volatile)
_mesa_string_buffer_append(d->buf, " volatile");
dump_value(d, store->value);
_mesa_string_buffer_append(d->buf, ", ");
dump_value(d, store->ptr);
_mesa_string_buffer_printf(d->buf, ", %d", store->align);
}
static const char *rmworder_str[] = {
[DXIL_ATOMIC_ORDERING_NOTATOMIC] = "not-atomic",
[DXIL_ATOMIC_ORDERING_UNORDERED] = "unordered",
[DXIL_ATOMIC_ORDERING_MONOTONIC] = "monotonic",
[DXIL_ATOMIC_ORDERING_ACQUIRE] = "acquire",
[DXIL_ATOMIC_ORDERING_RELEASE] = "release",
[DXIL_ATOMIC_ORDERING_ACQREL] = "acqrel",
[DXIL_ATOMIC_ORDERING_SEQCST] = "seqcst",
};
static const char *rmwsync_str[] = {
[DXIL_SYNC_SCOPE_SINGLETHREAD] = "single-thread",
[DXIL_SYNC_SCOPE_CROSSTHREAD] = "cross-thread",
};
static const char *rmwop_str[] = {
[DXIL_RMWOP_XCHG] = "xchg",
[DXIL_RMWOP_ADD] = "add",
[DXIL_RMWOP_SUB] = "sub",
[DXIL_RMWOP_AND] = "and",
[DXIL_RMWOP_NAND] = "nand",
[DXIL_RMWOP_OR] = "or",
[DXIL_RMWOP_XOR] = "xor",
[DXIL_RMWOP_MAX] = "max",
[DXIL_RMWOP_MIN] = "min",
[DXIL_RMWOP_UMAX] = "umax",
[DXIL_RMWOP_UMIN] = "umin",
};
static void
dump_instr_atomicrmw(struct dxil_dumper *d, struct dxil_instr_atomicrmw *rmw)
{
_mesa_string_buffer_printf(d->buf, "atomicrmw.%s ", rmwop_str[rmw->op]);
if (rmw->is_volatile)
_mesa_string_buffer_append(d->buf, " volatile");
dump_value(d, rmw->value);
_mesa_string_buffer_append(d->buf, ", ");
dump_value(d, rmw->ptr);
_mesa_string_buffer_printf(d->buf, ", ordering(%s)", rmworder_str[rmw->ordering]);
_mesa_string_buffer_printf(d->buf, ", sync_scope(%s)", rmwsync_str[rmw->syncscope]);
}
static void
dump_instr_print_operands(struct dxil_dumper *d, int num,
const struct dxil_value *val[])
{
for (int i = 0; i < num; ++i) {
if (i > 0)
_mesa_string_buffer_append(d->buf, ", ");
dump_value(d, val[i]);
}
}
static void
dump_value(struct dxil_dumper *d, const struct dxil_value *val)
{
if (val->id < 10)
_mesa_string_buffer_append(d->buf, " ");
if (val->id < 100)
_mesa_string_buffer_append(d->buf, " ");
_mesa_string_buffer_printf(d->buf, "%%%d", val->id);
dump_type_name(d, val->type);
}
static void
dump_mdnodes(struct dxil_dumper *d, struct list_head *list)
{
if (!list_length(list))
return;
_mesa_string_buffer_append(d->buf, "MD-Nodes:\n");
dxil_dump_indention_inc(d);
list_for_each_entry(struct dxil_mdnode, node, list, head) {
dump_mdnode(d, node);
}
dxil_dump_indention_dec(d);
}
static void
dump_mdnode(struct dxil_dumper *d, const struct dxil_mdnode *node)
{
dxil_dump_indent(d);
switch (node->type) {
case MD_STRING:
_mesa_string_buffer_printf(d->buf, "S:%s\n", node->string);
break;
case MD_VALUE:
_mesa_string_buffer_append(d->buf, "V:");
dump_type_name(d, node->value.type);
_mesa_string_buffer_append_char(d->buf, ' ');
dump_value(d, node->value.value);
_mesa_string_buffer_append_char(d->buf, '\n');
break;
case MD_NODE:
_mesa_string_buffer_append(d->buf, " \\\n");
dxil_dump_indention_inc(d);
for (size_t i = 0; i < node->node.num_subnodes; ++i) {
if (node->node.subnodes[i])
dump_mdnode(d, node->node.subnodes[i]);
else {
dxil_dump_indent(d);
_mesa_string_buffer_append(d->buf, "(nullptr)\n");
}
}
dxil_dump_indention_dec(d);
break;
}
}
static void
dump_named_nodes(struct dxil_dumper *d, struct list_head *list)
{
if (!list_length(list))
return;
_mesa_string_buffer_append(d->buf, "Named Nodes:\n");
dxil_dump_indention_inc(d);
list_for_each_entry(struct dxil_named_node, node, list, head) {
dxil_dump_indent(d);
_mesa_string_buffer_printf(d->buf, "%s:\n", node->name);
dxil_dump_indention_inc(d);
for (size_t i = 0; i < node->num_subnodes; ++i) {
if (node->subnodes[i])
dump_mdnode(d, node->subnodes[i]);
else {
dxil_dump_indent(d);
_mesa_string_buffer_append(d->buf, "(nullptr)\n");
}
}
dxil_dump_indention_dec(d);
}
dxil_dump_indention_dec(d);
}
static void
mask_to_string(uint32_t mask, char str[5])
{
const char *mc = "xyzw";
for (int i = 0; i < 4 && mask; ++i) {
str[i] = (mask & (1 << i)) ? mc[i] : '_';
}
str[4] = 0;
}
static void dump_io_signatures(struct _mesa_string_buffer *buf, struct dxil_module *m)
{
_mesa_string_buffer_append(buf, "\nInput signature:\n");
dump_io_signature(buf, m->num_sig_inputs, m->inputs);
_mesa_string_buffer_append(buf, "\nOutput signature:\n");
dump_io_signature(buf, m->num_sig_outputs, m->outputs);
}
static void dump_io_signature(struct _mesa_string_buffer *buf, unsigned num,
struct dxil_signature_record *io)
{
_mesa_string_buffer_append(buf, " SEMANTIC-NAME Index Mask Reg SysValue Format\n");
_mesa_string_buffer_append(buf, "----------------------------------------------\n");
for (unsigned i = 0; i < num; ++i, ++io) {
for (unsigned j = 0; j < io->num_elements; ++j) {
char mask[5] = "";
mask_to_string(io->elements[j].mask, mask);
_mesa_string_buffer_printf(buf, "%-15s %3d %4s %3d %-8s %-7s\n",
io->name, io->elements[j].semantic_index,
mask, io->elements[j].reg, io->sysvalue,
component_type_as_string(io->elements[j].comp_type));
}
}
}
static const char *component_type_as_string(uint32_t type)
{
return (type < DXIL_PROG_SIG_COMP_TYPE_COUNT) ?
dxil_type_strings[type] : "invalid";
}
static void dump_psv(struct _mesa_string_buffer *buf,
struct dxil_module *m)
{
_mesa_string_buffer_append(buf, "\nPipeline State Validation\nInputs:\n");
dump_psv_io(buf, m, m->num_sig_inputs, m->psv_inputs);
_mesa_string_buffer_append(buf, "\nOutputs:\n");
dump_psv_io(buf, m, m->num_sig_outputs, m->psv_outputs);
}
static void dump_psv_io(struct _mesa_string_buffer *buf, struct dxil_module *m,
unsigned num, struct dxil_psv_signature_element *io)
{
_mesa_string_buffer_append(buf, " SEMANTIC-NAME Rows Cols Kind Comp-Type Interp dynmask+stream Indices\n");
_mesa_string_buffer_append(buf, "----------------------------------------------\n");
for (unsigned i = 0; i < num; ++i, ++io) {
_mesa_string_buffer_printf(buf, "%-14s %d+%d %d+%d %4d %-7s %-4d %-9d [",
m->sem_string_table->buf + io->semantic_name_offset,
(int)io->start_row, (int)io->rows,
(int)((io->cols_and_start & 0xf) >> 4),
(int)(io->cols_and_start & 0xf),
(int)io->semantic_kind,
component_type_as_string(io->component_type),
(int)io->interpolation_mode,
(int)io->dynamic_mask_and_stream);
for (int k = 0; k < io->rows; ++k) {
if (k > 0)
_mesa_string_buffer_append(buf, ", ");
_mesa_string_buffer_printf(buf,"%d ", m->sem_index_table.data[io->start_row + k]);
}
_mesa_string_buffer_append(buf, "]\n");
}
}
+53
View File
@@ -0,0 +1,53 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DXIL_DUMP_H
#define DXIL_DUMP_H
#include <stdio.h>
struct dxil_module;
struct _mesa_string_buffer;
#ifdef __cplusplus
extern "C" {
#endif
struct dxil_dumper;
struct dxil_dumper *dxil_dump_create(void);
void dxil_dump_free(struct dxil_dumper *d);
void dxil_dump_buf_to_file(struct dxil_dumper *d, FILE *f);
void
dxil_dump_module(struct dxil_dumper *d, struct dxil_module *m);
#ifdef __cplusplus
}
#endif
#endif // DXIL_DUMP_H
+179
View File
@@ -0,0 +1,179 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DIXL_DUMP_DECL
#error This header can only be included from dxil_dump.c
#endif
#include "dxil_module.h"
static void
dump_metadata(struct dxil_dumper *buf, struct dxil_module *m);
static void
dump_shader_info(struct dxil_dumper *buf, struct dxil_shader_info *info);
static const char *
dump_shader_string(enum dxil_shader_kind kind);
static void
dump_features(struct _mesa_string_buffer *buf, struct dxil_features *feat);
static void
dump_types(struct dxil_dumper *buf, struct list_head *list);
static void
dump_gvars(struct dxil_dumper *buf, struct list_head *list);
static void
dump_constants(struct dxil_dumper *buf, struct list_head *list);
static void
dump_funcs(struct dxil_dumper *buf, struct list_head *list);
static void
dump_attr_set_list(struct dxil_dumper *buf, struct list_head *list);
static void
dump_instrs(struct dxil_dumper *buf, struct list_head *list);
static void
dump_mdnodes(struct dxil_dumper *buf, struct list_head *list);
static void
dump_mdnode(struct dxil_dumper *d, const struct dxil_mdnode *node);
static void
dump_named_nodes(struct dxil_dumper *d, struct list_head *list);
static void
dump_type(struct dxil_dumper *buf, const struct dxil_type *type);
static void
dump_instr_binop(struct dxil_dumper *d, struct dxil_instr_binop *binop);
static void
dump_instr_cmp(struct dxil_dumper *d, struct dxil_instr_cmp *cmp);
static void
dump_instr_select(struct dxil_dumper *d, struct dxil_instr_select *select);
static void
dump_instr_cast(struct dxil_dumper *d, struct dxil_instr_cast *cast);
static void
dump_instr_call(struct dxil_dumper *d, struct dxil_instr_call *call);
static void
dump_instr_ret(struct dxil_dumper *d, struct dxil_instr_ret *ret);
static void
dump_instr_extractval(struct dxil_dumper *d, struct dxil_instr_extractval *ret);
static void
dump_instr_branch(struct dxil_dumper *d, struct dxil_instr_br *br);
static void
dump_instr_phi(struct dxil_dumper *d, struct dxil_instr_phi *phi);
static void
dump_instr_alloca(struct dxil_dumper *d, struct dxil_instr_alloca *alloca);
static void
dump_instr_gep(struct dxil_dumper *d, struct dxil_instr_gep *gep);
static void
dump_instr_load(struct dxil_dumper *d, struct dxil_instr_load *store);
static void
dump_instr_store(struct dxil_dumper *d, struct dxil_instr_store *store);
static void
dump_instr_atomicrmw(struct dxil_dumper *d, struct dxil_instr_atomicrmw *rmw);
static void
dump_instr_print_operands(struct dxil_dumper *d, int num,
const struct dxil_value *val[]);
static void dump_io_signatures(struct _mesa_string_buffer *buf,
struct dxil_module *m);
static void
dump_io_signature(struct _mesa_string_buffer *buf, unsigned num,
struct dxil_signature_record *io);
static const char *component_type_as_string(uint32_t type);
static void dump_psv(struct _mesa_string_buffer *buf,
struct dxil_module *m);
static void dump_psv_io(struct _mesa_string_buffer *buf, struct dxil_module *m,
unsigned num, struct dxil_psv_signature_element *io);
static void
dump_value(struct dxil_dumper *d, const struct dxil_value *val);
static const char *binop_strings[DXIL_BINOP_INSTR_COUNT] = {
[DXIL_BINOP_ADD] = "add",
[DXIL_BINOP_SUB] = "sub",
[DXIL_BINOP_MUL] = "mul",
[DXIL_BINOP_UDIV] = "udiv",
[DXIL_BINOP_SDIV] = "sdiv",
[DXIL_BINOP_UREM] = "urem",
[DXIL_BINOP_SREM] = "srem",
[DXIL_BINOP_SHL] = "shl",
[DXIL_BINOP_LSHR] = "lshr",
[DXIL_BINOP_ASHR] = "ashr",
[DXIL_BINOP_AND] = "and",
[DXIL_BINOP_OR] = "or",
[DXIL_BINOP_XOR]= "xor"
};
static const char *pred_strings[DXIL_CMP_INSTR_COUNT] = {
[DXIL_FCMP_FALSE] = "FALSE",
[DXIL_FCMP_OEQ] = "ord-fEQ",
[DXIL_FCMP_OGT] = "ord-fGT",
[DXIL_FCMP_OGE] = "ord-fGE",
[DXIL_FCMP_OLT] = "ord-fLT",
[DXIL_FCMP_OLE] = "ord-fLE",
[DXIL_FCMP_ONE] = "ord-fNE",
[DXIL_FCMP_ORD] = "ord-fRD",
[DXIL_FCMP_UNO] = "unord-fNO",
[DXIL_FCMP_UEQ] = "unord-fEQ",
[DXIL_FCMP_UGT] = "unord-fGT",
[DXIL_FCMP_UGE] = "unord-fGE",
[DXIL_FCMP_ULT] = "unord-fLT",
[DXIL_FCMP_ULE] = "unord-fLE",
[DXIL_FCMP_UNE] = "unord-fNE",
[DXIL_FCMP_TRUE] = "TRUE",
[DXIL_ICMP_EQ] = "iEQ",
[DXIL_ICMP_NE] = "iNE",
[DXIL_ICMP_UGT] = "uiGT",
[DXIL_ICMP_UGE] = "uiGE",
[DXIL_ICMP_ULT] = "uiLT",
[DXIL_ICMP_ULE] = "uiLE",
[DXIL_ICMP_SGT] = "iGT",
[DXIL_ICMP_SGE] = "iGE",
[DXIL_ICMP_SLT] = "iLT",
[DXIL_ICMP_SLE] = "iLE"
};
static const char *cast_opcode_strings[DXIL_CAST_INSTR_COUNT] = {
[DXIL_CAST_TRUNC] = "trunc",
[DXIL_CAST_ZEXT] = "zext",
[DXIL_CAST_SEXT] = "sext",
[DXIL_CAST_FPTOUI] = "ftoui",
[DXIL_CAST_FPTOSI] = "ftoi",
[DXIL_CAST_UITOFP] = "uitof",
[DXIL_CAST_SITOFP] = "itof",
[DXIL_CAST_FPTRUNC] = "ftrunc",
[DXIL_CAST_FPEXT] = "fext",
[DXIL_CAST_PTRTOINT] = "ptrtoint",
[DXIL_CAST_INTTOPTR] = "inttoptr",
[DXIL_CAST_BITCAST] = "bitcast",
[DXIL_CAST_ADDRSPACECAST] = "addrspacecast",
};
static const char *dxil_type_strings[DXIL_PROG_SIG_COMP_TYPE_COUNT] = {
[DXIL_PROG_SIG_COMP_TYPE_UNKNOWN] = "unknown",
[DXIL_PROG_SIG_COMP_TYPE_UINT32] = "uint32",
[DXIL_PROG_SIG_COMP_TYPE_SINT32] = "int32",
[DXIL_PROG_SIG_COMP_TYPE_FLOAT32] = "float32",
[DXIL_PROG_SIG_COMP_TYPE_UINT16] = "uint16",
[DXIL_PROG_SIG_COMP_TYPE_SINT16] = "int16",
[DXIL_PROG_SIG_COMP_TYPE_FLOAT16] = "float16",
[DXIL_PROG_SIG_COMP_TYPE_UINT64] = "uint64",
[DXIL_PROG_SIG_COMP_TYPE_SINT64] = "int64",
[DXIL_PROG_SIG_COMP_TYPE_FLOAT64] = "float64"
};
+193
View File
@@ -0,0 +1,193 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "dxil_enums.h"
#include "glsl_types.h"
#include "nir.h"
#include "util/u_debug.h"
enum dxil_prog_sig_comp_type dxil_get_prog_sig_comp_type(const struct glsl_type *type)
{
type = glsl_without_array(type);
switch (glsl_get_base_type(type)) {
case GLSL_TYPE_UINT: return DXIL_PROG_SIG_COMP_TYPE_UINT32;
case GLSL_TYPE_INT: return DXIL_PROG_SIG_COMP_TYPE_SINT32;
case GLSL_TYPE_FLOAT: return DXIL_PROG_SIG_COMP_TYPE_FLOAT32;
case GLSL_TYPE_FLOAT16: return DXIL_PROG_SIG_COMP_TYPE_FLOAT16;
case GLSL_TYPE_DOUBLE: return DXIL_PROG_SIG_COMP_TYPE_UINT32;
case GLSL_TYPE_UINT16: return DXIL_PROG_SIG_COMP_TYPE_UINT16;
case GLSL_TYPE_INT16: return DXIL_PROG_SIG_COMP_TYPE_SINT16;
case GLSL_TYPE_UINT64: return DXIL_PROG_SIG_COMP_TYPE_UINT32;
case GLSL_TYPE_INT64: return DXIL_PROG_SIG_COMP_TYPE_SINT32;
case GLSL_TYPE_BOOL: return DXIL_PROG_SIG_COMP_TYPE_UINT32;
/* For structs, just emit them as float registers. This way, they can be
* interpolated or not, and it doesn't matter, and it avoids linking issues
* that we'd see if the type here tried to depend on (e.g.) interp mode. */
case GLSL_TYPE_STRUCT: return DXIL_PROG_SIG_COMP_TYPE_FLOAT32;
default:
debug_printf("unexpected type: %s\n", glsl_get_type_name(type));
return DXIL_PROG_SIG_COMP_TYPE_UNKNOWN;
}
}
enum dxil_component_type dxil_get_comp_type_from_prog_sig_type(enum dxil_prog_sig_comp_type type)
{
switch (type) {
case DXIL_PROG_SIG_COMP_TYPE_UINT32: return DXIL_COMP_TYPE_U32;
case DXIL_PROG_SIG_COMP_TYPE_SINT32: return DXIL_COMP_TYPE_I32;
case DXIL_PROG_SIG_COMP_TYPE_FLOAT32: return DXIL_COMP_TYPE_F32;
case DXIL_PROG_SIG_COMP_TYPE_UINT16: return DXIL_COMP_TYPE_U16;
case DXIL_PROG_SIG_COMP_TYPE_SINT16: return DXIL_COMP_TYPE_I16;
case DXIL_PROG_SIG_COMP_TYPE_FLOAT16: return DXIL_COMP_TYPE_F16;
default:
debug_printf("unexpected signature type\n");
UNREACHABLE("unexpected signature type");
}
}
enum dxil_component_type dxil_get_comp_type(const struct glsl_type *type)
{
type = glsl_without_array(type);
enum glsl_base_type base_type = glsl_get_base_type(type);
if (glsl_type_is_texture(type) || glsl_type_is_image(type))
base_type = glsl_get_sampler_result_type(type);
switch (base_type) {
case GLSL_TYPE_UINT: return DXIL_COMP_TYPE_U32;
case GLSL_TYPE_INT: return DXIL_COMP_TYPE_I32;
case GLSL_TYPE_FLOAT: return DXIL_COMP_TYPE_F32;
case GLSL_TYPE_FLOAT16: return DXIL_COMP_TYPE_F16;
case GLSL_TYPE_DOUBLE: return DXIL_COMP_TYPE_F64;
case GLSL_TYPE_UINT16: return DXIL_COMP_TYPE_U16;
case GLSL_TYPE_INT16: return DXIL_COMP_TYPE_I16;
case GLSL_TYPE_UINT64: return DXIL_COMP_TYPE_U64;
case GLSL_TYPE_INT64: return DXIL_COMP_TYPE_I64;
case GLSL_TYPE_BOOL: return DXIL_COMP_TYPE_I1;
default:
debug_printf("type: %s\n", glsl_get_type_name(type));
UNREACHABLE("unexpected glsl type");
}
}
enum dxil_resource_kind dxil_sampler_dim_to_resource_kind(enum glsl_sampler_dim dim, bool is_array)
{
switch (dim) {
case GLSL_SAMPLER_DIM_1D:
return is_array ? DXIL_RESOURCE_KIND_TEXTURE1D_ARRAY
: DXIL_RESOURCE_KIND_TEXTURE1D;
case GLSL_SAMPLER_DIM_2D:
case GLSL_SAMPLER_DIM_EXTERNAL:
return is_array ? DXIL_RESOURCE_KIND_TEXTURE2D_ARRAY
: DXIL_RESOURCE_KIND_TEXTURE2D;
case GLSL_SAMPLER_DIM_SUBPASS:
return DXIL_RESOURCE_KIND_TEXTURE2D_ARRAY;
case GLSL_SAMPLER_DIM_3D:
return DXIL_RESOURCE_KIND_TEXTURE3D;
case GLSL_SAMPLER_DIM_CUBE:
return is_array ? DXIL_RESOURCE_KIND_TEXTURECUBE_ARRAY
: DXIL_RESOURCE_KIND_TEXTURECUBE;
case GLSL_SAMPLER_DIM_RECT:
return DXIL_RESOURCE_KIND_TEXTURE2D;
case GLSL_SAMPLER_DIM_BUF:
return DXIL_RESOURCE_KIND_TYPED_BUFFER;
case GLSL_SAMPLER_DIM_MS:
return is_array ? DXIL_RESOURCE_KIND_TEXTURE2DMS_ARRAY
: DXIL_RESOURCE_KIND_TEXTURE2DMS;
case GLSL_SAMPLER_DIM_SUBPASS_MS:
return DXIL_RESOURCE_KIND_TEXTURE2DMS_ARRAY;
default:
UNREACHABLE("unexpected sampler type");
}
}
enum dxil_resource_kind dxil_get_resource_kind(const struct glsl_type *type)
{
type = glsl_without_array(type);
/* This looks weird, we strip the arrays but then we still test whether it's
* an array, key is the first refers to sampler[] and the second to samplerArray */
bool is_array = glsl_sampler_type_is_array(type);
if (glsl_type_is_texture(type) || glsl_type_is_image(type))
return dxil_sampler_dim_to_resource_kind(glsl_get_sampler_dim(type), is_array);
debug_printf("type: %s\n", glsl_get_type_name(type));
UNREACHABLE("unexpected glsl type");
}
enum dxil_input_primitive dxil_get_input_primitive(enum mesa_prim primitive)
{
switch (primitive) {
case MESA_PRIM_POINTS:
return DXIL_INPUT_PRIMITIVE_POINT;
case MESA_PRIM_LINES:
return DXIL_INPUT_PRIMITIVE_LINE;
case MESA_PRIM_LINES_ADJACENCY:
return DXIL_INPUT_PRIMITIVE_LINES_ADJENCY;
case MESA_PRIM_TRIANGLES:
return DXIL_INPUT_PRIMITIVE_TRIANGLE;
case MESA_PRIM_TRIANGLES_ADJACENCY:
return DXIL_INPUT_PRIMITIVE_TRIANGLES_ADJENCY;
default:
UNREACHABLE("unhandled primitive topology");
}
}
enum dxil_primitive_topology dxil_get_primitive_topology(enum mesa_prim topology)
{
switch (topology) {
case MESA_PRIM_POINTS:
return DXIL_PRIMITIVE_TOPOLOGY_POINT_LIST;
case MESA_PRIM_LINES:
return DXIL_PRIMITIVE_TOPOLOGY_LINE_LIST;
case MESA_PRIM_LINE_STRIP:
return DXIL_PRIMITIVE_TOPOLOGY_LINE_STRIP;
case MESA_PRIM_TRIANGLE_STRIP:
return DXIL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
default:
UNREACHABLE("unhandled primitive topology");
}
}
static const char *overload_str[DXIL_NUM_OVERLOADS] = {
[DXIL_NONE] = "",
[DXIL_I1] = "i1",
[DXIL_I16] = "i16",
[DXIL_I32] = "i32",
[DXIL_I64] = "i64",
[DXIL_F16] = "f16",
[DXIL_F32] = "f32",
[DXIL_F64] = "f64",
};
const char *dxil_overload_suffix( enum overload_type overload)
{
assert(overload < DXIL_NUM_OVERLOADS);
return overload_str[overload];
}
+401
View File
@@ -0,0 +1,401 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DIXL_ENUMS_H
#define DIXL_ENUMS_H
#include <stdbool.h>
#include "shader_enums.h"
enum dxil_signature_kind {
DXIL_SIG_INVALID = 0,
DXIL_SIG_INPUT,
DXIL_SIG_OUTPUT,
DXIL_SIG_PATCH_CONST_OR_PRIM
};
/* These enums are taken from
* DirectXShaderCompiler/lib/dxc/DXIL/DxilConstants.h
*/
enum dxil_semantic_kind {
DXIL_SEM_ARBITRARY,
DXIL_SEM_VERTEX_ID,
DXIL_SEM_INSTANCE_ID,
DXIL_SEM_POSITION,
DXIL_SEM_RENDERTARGET_ARRAY_INDEX,
DXIL_SEM_VIEWPORT_ARRAY_INDEX,
DXIL_SEM_CLIP_DISTANCE,
DXIL_SEM_CULL_DISTANCE,
DXIL_SEM_OUTPUT_CONTROL_POINT_ID,
DXIL_SEM_DOMAIN_LOCATION,
DXIL_SEM_PRIMITIVE_ID,
DXIL_SEM_GS_INSTANCE_ID,
DXIL_SEM_SAMPLE_INDEX,
DXIL_SEM_IS_FRONT_FACE,
DXIL_SEM_COVERAGE,
DXIL_SEM_INNER_COVERAGE,
DXIL_SEM_TARGET,
DXIL_SEM_DEPTH,
DXIL_SEM_DEPTH_LE,
DXIL_SEM_DEPTH_GE,
DXIL_SEM_STENCIL_REF,
DXIL_SEM_DISPATCH_THREAD_ID,
DXIL_SEM_GROUP_ID,
DXIL_SEM_GROUP_INDEX,
DXIL_SEM_GROUP_THREAD_ID,
DXIL_SEM_TESS_FACTOR,
DXIL_SEM_INSIDE_TESS_FACTOR,
DXIL_SEM_VIEW_ID,
DXIL_SEM_BARYCENTRICS,
DXIL_SEM_SHADING_RATE,
DXIL_SEM_CULL_PRIMITIVE,
DXIL_SEM_INVALID
};
enum dxil_prog_sig_semantic {
DXIL_PROG_SEM_UNDEFINED = 0,
DXIL_PROG_SEM_POSITION = 1,
DXIL_PROG_SEM_CLIP_DISTANCE = 2,
DXIL_PROG_SEM_CULL_DISTANCE = 3,
DXIL_PROG_SEM_RENDERTARGET_ARRAY_INDEX = 4,
DXIL_PROG_SEM_VIEWPORT_ARRAY_INDEX = 5,
DXIL_PROG_SEM_VERTEX_ID = 6,
DXIL_PROG_SEM_PRIMITIVE_ID = 7,
DXIL_PROG_SEM_INSTANCE_ID = 8,
DXIL_PROG_SEM_IS_FRONTFACE = 9,
DXIL_PROG_SEM_SAMPLE_INDEX = 10,
DXIL_PROG_SEM_FINAL_QUAD_EDGE_TESSFACTOR = 11,
DXIL_PROG_SEM_FINAL_QUAD_INSIDE_EDGE_TESSFACTOR = 12,
DXIL_PROG_SEM_FINAL_TRI_EDGE_TESSFACTOR = 13,
DXIL_PROG_SEM_FINAL_TRI_INSIDE_EDGE_TESSFACTOR = 14,
DXIL_PROG_SEM_FINAL_LINE_DETAIL_TESSFACTOR = 15,
DXIL_PROG_SEM_FINAL_LINE_DENSITY_TESSFACTOR = 16,
DXIL_PROG_SEM_BARYCENTRICS = 23,
DXIL_PROG_SEM_SHADING_RATE = 24,
DXIL_PROG_SEM_CULL_PRIMITIVE = 25,
DXIL_PROG_SEM_TARGET = 64,
DXIL_PROG_SEM_DEPTH = 65,
DXIL_PROG_SEM_COVERAGE = 66,
DXIL_PROG_SEM_DEPTH_GE = 67,
DXIL_PROG_SEM_DEPTH_LE = 68,
DXIL_PROG_SEM_STENCIL_REF = 69,
DXIL_PROG_SEM_INNER_COVERAGE = 70
};
enum dxil_prog_sig_comp_type {
DXIL_PROG_SIG_COMP_TYPE_UNKNOWN = 0,
DXIL_PROG_SIG_COMP_TYPE_UINT32 = 1,
DXIL_PROG_SIG_COMP_TYPE_SINT32 = 2,
DXIL_PROG_SIG_COMP_TYPE_FLOAT32 = 3,
DXIL_PROG_SIG_COMP_TYPE_UINT16 = 4,
DXIL_PROG_SIG_COMP_TYPE_SINT16 = 5,
DXIL_PROG_SIG_COMP_TYPE_FLOAT16 = 6,
DXIL_PROG_SIG_COMP_TYPE_UINT64 = 7,
DXIL_PROG_SIG_COMP_TYPE_SINT64 = 8,
DXIL_PROG_SIG_COMP_TYPE_FLOAT64 = 9,
DXIL_PROG_SIG_COMP_TYPE_COUNT
};
enum dxil_sig_point_kind {
DXIL_SIG_POINT_VSIN, // Ordinary Vertex Shader input from Input Assembler
DXIL_SIG_POINT_VSOUT, // Ordinary Vertex Shader output that may feed Rasterizer
DXIL_SIG_POINT_PCIN, // Patch Constant function non-patch inputs
DXIL_SIG_POINT_HSIN, // Hull Shader function non-patch inputs
DXIL_SIG_POINT_HSCPIN, // Hull Shader patch inputs - Control Points
DXIL_SIG_POINT_HSCPOut, // Hull Shader function output - Control Point
DXIL_SIG_POINT_PCOUT, // Patch Constant function output - Patch Constant data passed to Domain Shader
DXIL_SIG_POINT_DSIN, // Domain Shader regular input - Patch Constant data plus system values
DXIL_SIG_POINT_DSCPIN, // Domain Shader patch input - Control Points
DXIL_SIG_POINT_DSOUT, // Domain Shader output - vertex data that may feed Rasterizer
DXIL_SIG_POINT_GSVIN, // Geometry Shader vertex input - qualified with primitive type
DXIL_SIG_POINT_GSIN, // Geometry Shader non-vertex inputs (system values)
DXIL_SIG_POINT_GSOUT, // Geometry Shader output - vertex data that may feed Rasterizer
DXIL_SIG_POINT_PSIN, // Pixel Shader input
DXIL_SIG_POINT_PSOUT, // Pixel Shader output
DXIL_SIG_POINT_CSIN, // Compute Shader input
DXIL_SIG_POINT_MSIN, // Mesh Shader input
DXIL_SIG_POINT_MSOUT, // Mesh Shader vertices output
DXIL_SIG_POINT_MSPOUT, // Mesh Shader primitives output
DXIL_SIG_POINT_ASIN, // Amplification Shader input
DXIL_SIG_POINT_INVALID
};
enum dxil_min_precision {
DXIL_MIN_PREC_DEFAULT = 0,
DXIL_MIN_PREC_FLOAT16 = 1,
DXIL_MIN_PREC_FLOAT2_8 = 2,
DXIL_MIN_PREC_RESERVED = 3,
DXIL_MIN_PREC_SINT16 = 4,
DXIL_MIN_PREC_UINT16 = 5,
DXIL_MIN_PREC_ANY16 = 0xf0,
DXIL_MIN_PREC_ANY10 = 0xf1
};
enum dxil_semantic_interpret_kind {
DXIL_SEM_INTERP_NA, // Not Available
DXIL_SEM_INTERP_SV, // Normal System Value
DXIL_SEM_INTERP_SGV, // System Generated Value (sorted last)
DXIL_SEM_INTERP_ARB, // Treated as Arbitrary
DXIL_SEM_INTERP_NOT_IN_SIG, // Not included in signature (intrinsic access)
DXIL_SEM_INTERP_NOT_PACKED, // Included in signature, but does not contribute to packing
DXIL_SEM_INTERP_TARGET, // Special handling for SV_Target
DXIL_SEM_INTERP_TESSFACTOR, // Special handling for tessellation factors
DXIL_SEM_INTERP_SHADOW, // Shadow element must be added to a signature for compatibility
DXIL_SEM_INTERP_CLIPCULL, // Special packing rules for SV_ClipDistance or SV_CullDistance
DXIL_SEM_INTERP_INVALID
};
enum dxil_component_type {
DXIL_COMP_TYPE_INVALID = 0,
DXIL_COMP_TYPE_I1 = 1,
DXIL_COMP_TYPE_I16 = 2,
DXIL_COMP_TYPE_U16 = 3,
DXIL_COMP_TYPE_I32 = 4,
DXIL_COMP_TYPE_U32 = 5,
DXIL_COMP_TYPE_I64 = 6,
DXIL_COMP_TYPE_U64 = 7,
DXIL_COMP_TYPE_F16 = 8,
DXIL_COMP_TYPE_F32 = 9,
DXIL_COMP_TYPE_F64 = 10,
DXIL_COMP_TYPE_SNORMF16 = 11,
DXIL_COMP_TYPE_UNORMF16 = 12,
DXIL_COMP_TYPE_SNORMF32 = 13,
DXIL_COMP_TYPE_UNORMF32 = 14,
DXIL_COMP_TYPE_SNORMF64 = 15,
DXIL_COMP_TYPE_UNORMF64 = 16
};
enum dxil_interpolation_mode {
DXIL_INTERP_UNDEFINED = 0,
DXIL_INTERP_CONSTANT = 1,
DXIL_INTERP_LINEAR = 2,
DXIL_INTERP_LINEAR_CENTROID = 3,
DXIL_INTERP_LINEAR_NOPERSPECTIVE = 4,
DXIL_INTERP_LINEAR_NOPERSPECTIVE_CENTROID = 5,
DXIL_INTERP_LINEAR_SAMPLE = 6,
DXIL_INTERP_LINEAR_NOPERSPECTIVE_SAMPLE = 7,
DXIL_INTERP_INVALID = 8
};
enum overload_type {
DXIL_NONE,
DXIL_I1,
DXIL_I16,
DXIL_I32,
DXIL_I64,
DXIL_F16,
DXIL_F32,
DXIL_F64,
DXIL_NUM_OVERLOADS
};
enum dxil_resource_class {
DXIL_RESOURCE_CLASS_SRV = 0,
DXIL_RESOURCE_CLASS_UAV = 1,
DXIL_RESOURCE_CLASS_CBV = 2,
DXIL_RESOURCE_CLASS_SAMPLER = 3
};
enum dxil_resource_kind {
DXIL_RESOURCE_KIND_INVALID = 0,
DXIL_RESOURCE_KIND_TEXTURE1D = 1,
DXIL_RESOURCE_KIND_TEXTURE2D = 2,
DXIL_RESOURCE_KIND_TEXTURE2DMS = 3,
DXIL_RESOURCE_KIND_TEXTURE3D = 4,
DXIL_RESOURCE_KIND_TEXTURECUBE = 5,
DXIL_RESOURCE_KIND_TEXTURE1D_ARRAY = 6,
DXIL_RESOURCE_KIND_TEXTURE2D_ARRAY = 7,
DXIL_RESOURCE_KIND_TEXTURE2DMS_ARRAY = 8,
DXIL_RESOURCE_KIND_TEXTURECUBE_ARRAY = 9,
DXIL_RESOURCE_KIND_TYPED_BUFFER = 10,
DXIL_RESOURCE_KIND_RAW_BUFFER = 11,
DXIL_RESOURCE_KIND_STRUCTURED_BUFFER = 12,
DXIL_RESOURCE_KIND_CBUFFER = 13,
DXIL_RESOURCE_KIND_SAMPLER = 14,
DXIL_RESOURCE_KIND_TBUFFER = 15,
};
enum dxil_sampler_kind {
DXIL_SAMPLER_KIND_DEFAULT = 0,
DXIL_SAMPLER_KIND_COMPARISON = 1,
DXIL_SAMPLER_KIND_MONO = 2,
DXIL_SAMPLER_KIND_INVALID = 3,
};
enum dxil_attr_kind {
DXIL_ATTR_KIND_NONE = 0,
DXIL_ATTR_KIND_NO_DUPLICATE = 12,
DXIL_ATTR_KIND_NO_UNWIND = 18,
DXIL_ATTR_KIND_READ_NONE = 20,
DXIL_ATTR_KIND_READ_ONLY = 21,
};
enum dxil_input_primitive {
DXIL_INPUT_PRIMITIVE_UNDEFINED = 0,
DXIL_INPUT_PRIMITIVE_POINT = 1,
DXIL_INPUT_PRIMITIVE_LINE = 2,
DXIL_INPUT_PRIMITIVE_TRIANGLE = 3,
DXIL_INPUT_PRIMITIVE_LINES_ADJENCY = 6,
DXIL_INPUT_PRIMITIVE_TRIANGLES_ADJENCY = 7,
};
enum dxil_primitive_topology {
DXIL_PRIMITIVE_TOPOLOGY_UNDEFINED = 0,
DXIL_PRIMITIVE_TOPOLOGY_POINT_LIST = 1,
DXIL_PRIMITIVE_TOPOLOGY_LINE_LIST = 2,
DXIL_PRIMITIVE_TOPOLOGY_LINE_STRIP = 3,
DXIL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST = 4,
DXIL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP = 5,
};
enum dxil_shader_tag {
DXIL_SHADER_TAG_FLAGS = 0,
DXIL_SHADER_TAG_GS_STATE = 1,
DXIL_SHADER_TAG_DS_STATE = 2,
DXIL_SHADER_TAG_HS_STATE = 3,
DXIL_SHADER_TAG_NUM_THREADS = 4,
DXIL_SHADER_TAG_WAVE_SIZE = 11,
DXIL_SHADER_TAG_WAVE_SIZE_RANGE = 23,
};
enum dxil_barrier_mode {
DXIL_BARRIER_MODE_SYNC_THREAD_GROUP = 1,
DXIL_BARRIER_MODE_UAV_FENCE_GLOBAL = 2,
DXIL_BARRIER_MODE_UAV_FENCE_THREAD_GROUP = 4,
DXIL_BARRIER_MODE_GROUPSHARED_MEM_FENCE = 8,
};
enum dxil_address_space {
DXIL_AS_DEFAULT = 0,
DXIL_AS_DEVMEM = 1,
DXIL_AS_CBUF = 2,
DXIL_AS_GROUPSHARED = 3,
};
enum dxil_rmw_op {
DXIL_RMWOP_XCHG = 0,
DXIL_RMWOP_ADD = 1,
DXIL_RMWOP_SUB = 2,
DXIL_RMWOP_AND = 3,
DXIL_RMWOP_NAND = 4,
DXIL_RMWOP_OR = 5,
DXIL_RMWOP_XOR = 6,
DXIL_RMWOP_MAX = 7,
DXIL_RMWOP_MIN = 8,
DXIL_RMWOP_UMAX = 9,
DXIL_RMWOP_UMIN = 10,
};
enum dxil_atomic_ordering {
DXIL_ATOMIC_ORDERING_NOTATOMIC = 0,
DXIL_ATOMIC_ORDERING_UNORDERED = 1,
DXIL_ATOMIC_ORDERING_MONOTONIC = 2,
DXIL_ATOMIC_ORDERING_ACQUIRE = 3,
DXIL_ATOMIC_ORDERING_RELEASE = 4,
DXIL_ATOMIC_ORDERING_ACQREL = 5,
DXIL_ATOMIC_ORDERING_SEQCST = 6,
};
enum dxil_sync_scope {
DXIL_SYNC_SCOPE_SINGLETHREAD = 0,
DXIL_SYNC_SCOPE_CROSSTHREAD = 1,
};
enum dxil_tessellator_domain {
DXIL_TESSELLATOR_DOMAIN_UNDEFINED = 0,
DXIL_TESSELLATOR_DOMAIN_ISOLINE = 1,
DXIL_TESSELLATOR_DOMAIN_TRI = 2,
DXIL_TESSELLATOR_DOMAIN_QUAD = 3,
};
enum dxil_tessellator_output_primitive {
DXIL_TESSELLATOR_OUTPUT_PRIMITIVE_UNDEFINED = 0,
DXIL_TESSELLATOR_OUTPUT_PRIMITIVE_POINT = 1,
DXIL_TESSELLATOR_OUTPUT_PRIMITIVE_LINE = 2,
DXIL_TESSELLATOR_OUTPUT_PRIMITIVE_TRIANGLE_CW = 3,
DXIL_TESSELLATOR_OUTPUT_PRIMITIVE_TRIANGLE_CCW = 4,
};
enum dxil_tessellator_partitioning {
DXIL_TESSELLATOR_PARTITIONING_UNDEFINED = 0,
DXIL_TESSELLATOR_PARTITIONING_INTEGER = 1,
DXIL_TESSELLATOR_PARTITIONING_POW2 = 2,
DXIL_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD = 3,
DXIL_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN = 4,
};
enum dxil_signature_element_extended_properties {
DXIL_SIGNATURE_ELEMENT_OUTPUT_STREAM = 0,
DXIL_SIGNATURE_ELEMENT_GLOBAL_SYMBOL = 1,
DXIL_SIGNATURE_ELEMENT_DYNAMIC_INDEX_COMPONENT_MASK = 2,
DXIL_SIGNATURE_ELEMENT_USAGE_COMPONENT_MASK = 3,
};
enum dxil_quad_op_kind {
QUAD_READ_ACROSS_X = 0,
QUAD_READ_ACROSS_Y = 1,
QUAD_READ_ACROSS_DIAGONAL = 2,
};
enum dxil_wave_op_kind {
DXIL_WAVE_OP_SUM = 0,
DXIL_WAVE_OP_PRODUCT = 1,
DXIL_WAVE_OP_MIN = 2,
DXIL_WAVE_OP_MAX = 3,
};
enum dxil_wave_bit_op_kind {
DXIL_WAVE_BIT_OP_AND = 0,
DXIL_WAVE_BIT_OP_OR = 1,
DXIL_WAVE_BIT_OP_XOR = 2,
};
#ifdef __cplusplus
extern "C" {
#endif
struct glsl_type;
enum glsl_sampler_dim;
enum dxil_component_type dxil_get_comp_type(const struct glsl_type *type);
enum dxil_prog_sig_comp_type dxil_get_prog_sig_comp_type(const struct glsl_type *type);
enum dxil_component_type dxil_get_comp_type_from_prog_sig_type(enum dxil_prog_sig_comp_type type);
enum dxil_resource_kind dxil_sampler_dim_to_resource_kind(enum glsl_sampler_dim dim, bool is_array);
enum dxil_resource_kind dxil_get_resource_kind(const struct glsl_type *type);
enum dxil_primitive_topology dxil_get_primitive_topology(enum mesa_prim topology);
enum dxil_input_primitive dxil_get_input_primitive(enum mesa_prim primitive);
const char *dxil_overload_suffix( enum overload_type overload);
#ifdef __cplusplus
}
#endif
#endif // DXIL_ENUMS_H
+287
View File
@@ -0,0 +1,287 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "dxil_function.h"
#include "dxil_module.h"
#define MAX_FUNC_PARAMS 18
struct predefined_func_descr {
const char *base_name;
const char *retval_descr;
const char *param_descr;
enum dxil_attr_kind attr;
};
static struct predefined_func_descr predefined_funcs[] = {
{"dx.op.atomicBinOp", "O", "i@iiiii", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.cbufferLoad", "O", "i@ii", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.cbufferLoadLegacy", "B", "i@i", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.createHandle", "@", "iciib", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.storeOutput", "v", "iiicO", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.loadInput", "O", "iiici", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.tertiary", "O", "iOOO", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.quaternary", "O", "iOOOO", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.threadId", "i", "ii", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.threadIdInGroup", "i", "ii", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.flattenedThreadIdInGroup", "i", "i", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.groupId", "i", "ii", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.unary", "O", "iO", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.unaryBits", "i", "iO", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.isSpecialFloat", "b", "iO", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.binary", "O", "iOO", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.bufferStore", "v", "i@iiOOOOc", DXIL_ATTR_KIND_NONE},
{"dx.op.rawBufferStore", "v", "i@iiOOOOci", DXIL_ATTR_KIND_NONE},
{"dx.op.bufferLoad", "R", "i@ii", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.rawBufferLoad", "R", "i@iici", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.attributeAtVertex", "O", "iiicc", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.sample", "R", "i@@ffffiiif", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.sampleBias", "R", "i@@ffffiiiff", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.sampleLevel", "R", "i@@ffffiiif", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.sampleGrad", "R", "i@@ffffiiifffffff", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.sampleCmp", "R", "i@@ffffiiiff", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.sampleCmpLevel", "R", "i@@ffffiiiff", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.sampleCmpLevelZero", "R", "i@@ffffiiif", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.sampleCmpBias", "R", "i@@ffffiiifff", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.sampleCmpGrad", "R", "i@@ffffiiiffffffff", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.textureLoad", "R", "i@iiiiiii", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.textureGather", "R", "i@@ffffiii", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.textureGatherCmp", "R", "i@@ffffiiif", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.discard", "v", "ib", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.sampleIndex", "i", "i", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.emitStream", "v", "ic", DXIL_ATTR_KIND_NONE},
{"dx.op.cutStream", "v", "ic", DXIL_ATTR_KIND_NONE},
{"dx.op.getDimensions", "D", "i@i", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.calculateLOD", "f", "i@@fffb", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.barrier", "v", "ii", DXIL_ATTR_KIND_NO_DUPLICATE},
{"dx.op.atomicCompareExchange", "O", "i@iiiii", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.textureStore", "v", "i@iiiOOOOc", DXIL_ATTR_KIND_NONE},
{"dx.op.primitiveID", "i", "i", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.outputControlPointID", "i", "i", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.gsInstanceID", "i", "i", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.viewID", "i", "i", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.domainLocation", "f", "ic", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.legacyF16ToF32", "f", "ii", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.legacyF32ToF16", "i", "if", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.makeDouble", "g", "iii", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.splitDouble", "G", "ig", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.texture2DMSGetSamplePosition", "S", "i@i", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.renderTargetGetSamplePosition", "S", "ii", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.evalSnapped", "O", "iiicii", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.evalCentroid", "O", "iiic", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.evalSampleIndex", "O", "iiici", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.coverage", "i", "i", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.storePatchConstant", "v", "iiicO", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.loadPatchConstant", "O", "iiic", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.loadOutputControlPoint", "O", "iiici", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.createHandleFromBinding", "@", "i#ib", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.createHandleFromHeap", "@", "iibb", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.annotateHandle", "@", "i@P", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.isHelperLane", "b", "i", DXIL_ATTR_KIND_READ_ONLY},
{"dx.op.waveIsFirstLane", "b", "i", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.waveGetLaneIndex", "i", "i", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.waveGetLaneCount", "i", "i", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.waveReadLaneFirst", "O", "iO", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.waveReadLaneAt", "O", "iOi", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.waveAnyTrue", "b", "ib", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.waveAllTrue", "b", "ib", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.waveActiveAllEqual", "b", "iO", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.waveActiveBallot", "F", "ib", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.waveActiveOp", "O", "iOcc", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.waveActiveBit", "O", "iOc", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.wavePrefixOp", "O", "iOcc", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.quadReadLaneAt", "O", "iOi", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.quadOp", "O", "iOc", DXIL_ATTR_KIND_NO_UNWIND},
{"dx.op.dot4AddPacked", "i", "iiii", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.startVertexLocation", "i", "i", DXIL_ATTR_KIND_READ_NONE},
{"dx.op.startInstanceLocation", "i", "i", DXIL_ATTR_KIND_READ_NONE},
};
struct func_descr {
const char *name;
enum overload_type overload;
};
struct func_rb_node {
struct rb_node node;
const struct dxil_func *func;
struct func_descr descr;
};
static inline
const struct func_rb_node *
func_rb_node(const struct rb_node *n)
{
return (const struct func_rb_node *)n;
}
static int
func_compare_to_name_and_overload(const struct rb_node *node, const void *data)
{
const struct func_descr *descr = (const struct func_descr *)data;
const struct func_rb_node *f = func_rb_node(node);
if (f->descr.overload < descr->overload)
return -1;
if (f->descr.overload > descr->overload)
return 1;
return strcmp(f->descr.name, descr->name);
}
static const struct dxil_func *
allocate_function_from_predefined(struct dxil_module *mod,
const char *name,
enum overload_type overload)
{
for (unsigned i = 0; i < ARRAY_SIZE(predefined_funcs); ++i) {
if (!strcmp(predefined_funcs[i].base_name, name)) {
return dxil_alloc_func(mod, name, overload,
predefined_funcs[i].retval_descr,
predefined_funcs[i].param_descr,
predefined_funcs[i].attr);
}
}
UNREACHABLE("Invalid function name");
}
const struct dxil_func *
dxil_get_function(struct dxil_module *mod,
const char *name, enum overload_type overload)
{
struct func_descr descr = { name, overload };
const struct rb_node *node = rb_tree_search(mod->functions, &descr,
func_compare_to_name_and_overload);
if (node)
return func_rb_node(node)->func;
return allocate_function_from_predefined(mod, name, overload);
}
static int func_compare_name(const struct rb_node *lhs, const struct rb_node *rhs)
{
const struct func_rb_node *node = func_rb_node(rhs);
return func_compare_to_name_and_overload(lhs, &node->descr);
}
static void
dxil_add_function(struct rb_tree *functions, const struct dxil_func *func,
const char *name, enum overload_type overload)
{
struct func_rb_node *f = rzalloc(functions, struct func_rb_node);
f->func = func;
f->descr.name = name;
f->descr.overload = overload;
rb_tree_insert(functions, &f->node, func_compare_name);
}
static const struct dxil_type *
get_type_from_string(struct dxil_module *mod, const char *param_descr,
enum overload_type overload, int *idx)
{
assert(param_descr);
char type_id = param_descr[(*idx)++];
assert(*idx <= (int)strlen(param_descr));
switch (type_id) {
case DXIL_FUNC_PARAM_INT64: return dxil_module_get_int_type(mod, 64);
case DXIL_FUNC_PARAM_INT32: return dxil_module_get_int_type(mod, 32);
case DXIL_FUNC_PARAM_INT16: return dxil_module_get_int_type(mod, 16);
case DXIL_FUNC_PARAM_INT8: return dxil_module_get_int_type(mod, 8);
case DXIL_FUNC_PARAM_BOOL: return dxil_module_get_int_type(mod, 1);
case DXIL_FUNC_PARAM_FLOAT64: return dxil_module_get_float_type(mod, 64);
case DXIL_FUNC_PARAM_FLOAT32: return dxil_module_get_float_type(mod, 32);
case DXIL_FUNC_PARAM_FLOAT16: return dxil_module_get_float_type(mod, 16);
case DXIL_FUNC_PARAM_HANDLE: return dxil_module_get_handle_type(mod);
case DXIL_FUNC_PARAM_VOID: return dxil_module_get_void_type(mod);
case DXIL_FUNC_PARAM_FROM_OVERLOAD: return dxil_get_overload_type(mod, overload);
case DXIL_FUNC_PARAM_RESRET: return dxil_module_get_resret_type(mod, overload);
case DXIL_FUNC_PARAM_DIM: return dxil_module_get_dimret_type(mod);
case DXIL_FUNC_PARAM_SAMPLE_POS: return dxil_module_get_samplepos_type(mod);
case DXIL_FUNC_PARAM_CBUF_RET: return dxil_module_get_cbuf_ret_type(mod, overload);
case DXIL_FUNC_PARAM_SPLIT_DOUBLE: return dxil_module_get_split_double_ret_type(mod);
case DXIL_FUNC_PARAM_RES_BIND: return dxil_module_get_res_bind_type(mod);
case DXIL_FUNC_PARAM_RES_PROPS: return dxil_module_get_res_props_type(mod);
case DXIL_FUNC_PARAM_POINTER: {
const struct dxil_type *target = get_type_from_string(mod, param_descr, overload, idx);
return dxil_module_get_pointer_type(mod, target);
}
case DXIL_FUNC_PARAM_FOURI32: return dxil_module_get_fouri32_type(mod);
default:
assert(0 && "unknown type identifier");
}
return NULL;
}
const struct dxil_func *
dxil_alloc_func_with_rettype(struct dxil_module *mod, const char *name,
enum overload_type overload,
const struct dxil_type *retval_type,
const char *param_descr,
enum dxil_attr_kind attr)
{
assert(param_descr);
const struct dxil_type *arg_types[MAX_FUNC_PARAMS];
int index = 0;
unsigned num_params = 0;
while (param_descr[num_params]) {
const struct dxil_type *t = get_type_from_string(mod, param_descr, overload, &index);
if (!t)
return NULL;
assert(num_params < MAX_FUNC_PARAMS);
arg_types[num_params++] = t;
}
const struct dxil_type *func_type =
dxil_module_add_function_type(mod, retval_type,
arg_types, num_params);
if (!func_type) {
fprintf(stderr, "%s: Func type allocation failed\n", __func__);
return NULL;
}
char full_name[100];
snprintf(full_name, sizeof (full_name), "%s%s%s", name,
overload == DXIL_NONE ? "" : ".", dxil_overload_suffix(overload));
const struct dxil_func *func = dxil_add_function_decl(mod, full_name, func_type, attr);
if (func)
dxil_add_function(mod->functions, func, name, overload);
return func;
}
const struct dxil_func *
dxil_alloc_func(struct dxil_module *mod, const char *name, enum overload_type overload,
const char *retval_type_descr,
const char *param_descr, enum dxil_attr_kind attr)
{
int index = 0;
const struct dxil_type *retval_type = get_type_from_string(mod, retval_type_descr, overload, &index);
assert(retval_type_descr[index] == 0);
return dxil_alloc_func_with_rettype(mod, name, overload, retval_type,
param_descr, attr);
}
+97
View File
@@ -0,0 +1,97 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DXIL_FUNCTION_H
#define DXIL_FUNCTION_H
#define DXIL_FUNC_PARAM_INT64 'l'
#define DXIL_FUNC_PARAM_INT32 'i'
#define DXIL_FUNC_PARAM_INT16 'h'
#define DXIL_FUNC_PARAM_INT8 'c'
#define DXIL_FUNC_PARAM_BOOL 'b'
#define DXIL_FUNC_PARAM_FLOAT64 'g'
#define DXIL_FUNC_PARAM_FLOAT32 'f'
#define DXIL_FUNC_PARAM_FLOAT16 'e'
#define DXIL_FUNC_PARAM_HANDLE '@'
#define DXIL_FUNC_PARAM_POINTER '*'
#define DXIL_FUNC_PARAM_VOID 'v'
#define DXIL_FUNC_PARAM_FROM_OVERLOAD 'O'
#define DXIL_FUNC_PARAM_RESRET 'R'
#define DXIL_FUNC_PARAM_CBUF_RET 'B'
#define DXIL_FUNC_PARAM_DIM 'D'
#define DXIL_FUNC_PARAM_SPLIT_DOUBLE 'G'
#define DXIL_FUNC_PARAM_SAMPLE_POS 'S'
#define DXIL_FUNC_PARAM_RES_BIND '#'
#define DXIL_FUNC_PARAM_RES_PROPS 'P'
#define DXIL_FUNC_PARAM_FOURI32 'F'
#include "dxil_module.h"
#include "util/rb_tree.h"
const char *dxil_overload_suffix( enum overload_type overload);
const struct dxil_type *
dxil_get_overload_type(struct dxil_module *mod, enum overload_type overload);
/* These functions implement a generic method for declaring functions
* The input parameters types are given as a string using the characters
* given above as identifyer for the types. Only scalars and pointers to
* scalars are implemented at this point.
*
* Examples:
*
* Call: dxil_alloc_func(mod, "storeData.f32", "v", "icf");
* Result function: void storeData.f32(int32, int8, float32)
*
* Call: dxil_alloc_func(mod, "storeData.f32", "e", "*icf");
* Result function: float16 storeData.f32(int32 *, int8, float32)
*
* Call: dxil_alloc_func(mod, "storeData.f32", "*h", "b*f");
* Result function: float16 storeData.f32(bool *, float32 *)
*
*/
const struct dxil_func *
dxil_alloc_func(struct dxil_module *mod, const char *name, enum overload_type overload,
const char *retval_type_descr, const char *param_descr, enum dxil_attr_kind attr);
/* For specifically constructed return types one can also create the return type
* seperately and pass it as paramaer
*/
const struct dxil_func *
dxil_alloc_func_with_rettype(struct dxil_module *mod, const char *name, enum overload_type overload,
const struct dxil_type *retval_type, const char *param_descr,
enum dxil_attr_kind attr);
/* This call should be the usual entry point to allocate a new function type.
* 'name' must either be in the list of predefined functions, or a function
* with 'name' and 'overload' must already be allocated by using one of the above
* function calls. The allocated functions are searched for by using an rb_tree, so
* the search complexity should be O(log(n)).
*/
const struct dxil_func *
dxil_get_function(struct dxil_module *mod, const char *name,
enum overload_type overload);
#endif // DXIL_FUNCTION_H
+310
View File
@@ -0,0 +1,310 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DXIL_INTERNAL_H
#define DXIL_INTERNAL_H
#include "dxil_module.h"
#include "util/list.h"
#include <stdint.h>
// Malloc.h defines a macro for alloca. Let's at least make sure that all includers
// of this header have the same definition of alloca.
#include <malloc.h>
struct dxil_type_list {
struct dxil_type **types;
size_t num_types;
};
struct dxil_type {
enum type_type {
TYPE_VOID,
TYPE_INTEGER,
TYPE_FLOAT,
TYPE_POINTER,
TYPE_STRUCT,
TYPE_ARRAY,
TYPE_VECTOR,
TYPE_FUNCTION
} type;
union {
unsigned int_bits;
unsigned float_bits;
const struct dxil_type *ptr_target_type;
struct {
const char *name;
struct dxil_type_list elem;
} struct_def;
struct {
const struct dxil_type *ret_type;
struct dxil_type_list args;
} function_def;
struct {
const struct dxil_type *elem_type;
size_t num_elems;
} array_or_vector_def;
};
struct list_head head;
unsigned id;
};
struct dxil_value {
int id;
const struct dxil_type *type;
};
struct dxil_gvar {
const char *name;
const struct dxil_type *type;
bool constant;
enum dxil_address_space as;
int align;
const struct dxil_value *initializer;
struct dxil_value value;
struct list_head head;
};
struct dxil_func {
char *name;
const struct dxil_type *type;
bool decl;
unsigned attr_set;
struct dxil_value value;
struct list_head head;
};
struct dxil_attrib {
enum {
DXIL_ATTR_ENUM,
DXIL_ATTR_ENUM_VALUE,
DXIL_ATTR_STRING = 3,
DXIL_ATTR_STRING_VALUE,
} type;
union {
enum dxil_attr_kind kind;
const char *str;
} key;
union {
uint64_t integer;
const char *str;
} value;
};
struct attrib_set {
struct dxil_attrib attrs[2];
unsigned num_attrs;
struct list_head head;
};
struct dxil_instr_binop {
enum dxil_bin_opcode opcode;
const struct dxil_value *operands[2];
enum dxil_opt_flags flags;
};
struct dxil_instr_cmp {
enum dxil_cmp_pred pred;
const struct dxil_value *operands[2];
};
struct dxil_instr_select {
const struct dxil_value *operands[3];
};
struct dxil_instr_cast {
enum dxil_cast_opcode opcode;
const struct dxil_type *type;
const struct dxil_value *value;
};
struct dxil_instr_call {
const struct dxil_func *func;
struct dxil_value **args;
size_t num_args;
};
struct dxil_instr_ret {
struct dxil_value *value;
};
struct dxil_instr_extractval {
const struct dxil_value *src;
const struct dxil_type *type;
unsigned int idx;
};
struct dxil_instr_br {
const struct dxil_value *cond;
unsigned succ[2];
};
struct dxil_instr_phi {
const struct dxil_type *type;
struct dxil_phi_src {
const struct dxil_value *value;
unsigned block;
} *incoming;
size_t num_incoming;
};
struct dxil_instr_alloca {
const struct dxil_type *alloc_type;
const struct dxil_type *size_type;
const struct dxil_value *size;
unsigned align;
};
struct dxil_instr_gep {
bool inbounds;
const struct dxil_type *source_elem_type;
struct dxil_value **operands;
size_t num_operands;
};
struct dxil_instr_load {
const struct dxil_value *ptr;
const struct dxil_type *type;
unsigned align;
bool is_volatile;
};
struct dxil_instr_store {
const struct dxil_value *value, *ptr;
unsigned align;
bool is_volatile;
};
struct dxil_instr_atomicrmw {
const struct dxil_value *value, *ptr;
enum dxil_rmw_op op;
bool is_volatile;
enum dxil_atomic_ordering ordering;
enum dxil_sync_scope syncscope;
};
struct dxil_instr_cmpxchg {
const struct dxil_value *cmpval, *newval, *ptr;
bool is_volatile;
enum dxil_atomic_ordering ordering;
enum dxil_sync_scope syncscope;
};
struct dxil_instr {
enum instr_type {
INSTR_BINOP,
INSTR_CMP,
INSTR_SELECT,
INSTR_CAST,
INSTR_BR,
INSTR_PHI,
INSTR_CALL,
INSTR_RET,
INSTR_EXTRACTVAL,
INSTR_ALLOCA,
INSTR_GEP,
INSTR_LOAD,
INSTR_STORE,
INSTR_ATOMICRMW,
INSTR_CMPXCHG,
} type;
union {
struct dxil_instr_binop binop;
struct dxil_instr_cmp cmp;
struct dxil_instr_select select;
struct dxil_instr_cast cast;
struct dxil_instr_call call;
struct dxil_instr_ret ret;
struct dxil_instr_extractval extractval;
struct dxil_instr_phi phi;
struct dxil_instr_br br;
struct dxil_instr_alloca alloca;
struct dxil_instr_gep gep;
struct dxil_instr_load load;
struct dxil_instr_store store;
struct dxil_instr_atomicrmw atomicrmw;
struct dxil_instr_cmpxchg cmpxchg;
};
bool has_value;
struct dxil_value value;
struct list_head head;
};
struct dxil_const {
struct dxil_value value;
bool undef;
union {
intmax_t int_value;
double float_value;
const struct dxil_value **array_values;
const struct dxil_value **struct_values;
const struct dxil_value **vector_values;
};
struct list_head head;
};
struct dxil_mdnode {
enum mdnode_type {
MD_STRING,
MD_VALUE,
MD_NODE
} type;
union {
char *string;
struct {
const struct dxil_type *type;
const struct dxil_value *value;
} value;
struct {
const struct dxil_mdnode **subnodes;
size_t num_subnodes;
} node;
};
struct list_head head;
unsigned id;
};
struct dxil_named_node {
char *name;
const struct dxil_mdnode **subnodes;
size_t num_subnodes;
struct list_head head;
};
#endif // DXIL_INTERNAL_H
File diff suppressed because it is too large. Load diff
+587
View File
@@ -0,0 +1,587 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
/*
* See the DirectX Shader Compiler for documentation for DXIL details:
* https://github.com/Microsoft/DirectXShaderCompiler/blob/master/docs/DXIL.rst
*/
#ifndef DXIL_MODULE_H
#define DXIL_MODULE_H
#ifdef __cplusplus
extern "C" {
#endif
#include "dxil_buffer.h"
#include "dxil_signature.h"
#include "util/list.h"
#define DXIL_SHADER_MAX_IO_ROWS 128
enum dxil_shader_kind {
DXIL_PIXEL_SHADER = 0,
DXIL_VERTEX_SHADER = 1,
DXIL_GEOMETRY_SHADER = 2,
DXIL_HULL_SHADER = 3,
DXIL_DOMAIN_SHADER = 4,
DXIL_COMPUTE_SHADER = 5,
};
extern int debug_dxil;
enum dxil_debug_flags {
DXIL_DEBUG_VERBOSE = 1 << 0,
DXIL_DEBUG_DUMP_BLOB = 1 << 1,
DXIL_DEBUG_TRACE = 1 << 2,
DXIL_DEBUG_DUMP_MODULE = 1 << 3,
};
enum dxil_bin_opcode {
DXIL_BINOP_ADD = 0,
DXIL_BINOP_SUB = 1,
DXIL_BINOP_MUL = 2,
DXIL_BINOP_UDIV = 3,
DXIL_BINOP_SDIV = 4,
DXIL_BINOP_UREM = 5,
DXIL_BINOP_SREM = 6,
DXIL_BINOP_SHL = 7,
DXIL_BINOP_LSHR = 8,
DXIL_BINOP_ASHR = 9,
DXIL_BINOP_AND = 10,
DXIL_BINOP_OR = 11,
DXIL_BINOP_XOR = 12,
DXIL_BINOP_INSTR_COUNT
};
enum dxil_cast_opcode {
DXIL_CAST_TRUNC = 0,
DXIL_CAST_ZEXT = 1,
DXIL_CAST_SEXT = 2,
DXIL_CAST_FPTOUI = 3,
DXIL_CAST_FPTOSI = 4,
DXIL_CAST_UITOFP = 5,
DXIL_CAST_SITOFP = 6,
DXIL_CAST_FPTRUNC = 7,
DXIL_CAST_FPEXT = 8,
DXIL_CAST_PTRTOINT = 9,
DXIL_CAST_INTTOPTR = 10,
DXIL_CAST_BITCAST = 11,
DXIL_CAST_ADDRSPACECAST = 12,
DXIL_CAST_INSTR_COUNT
};
enum dxil_cmp_pred {
DXIL_FCMP_FALSE = 0,
DXIL_FCMP_OEQ = 1,
DXIL_FCMP_OGT = 2,
DXIL_FCMP_OGE = 3,
DXIL_FCMP_OLT = 4,
DXIL_FCMP_OLE = 5,
DXIL_FCMP_ONE = 6,
DXIL_FCMP_ORD = 7,
DXIL_FCMP_UNO = 8,
DXIL_FCMP_UEQ = 9,
DXIL_FCMP_UGT = 10,
DXIL_FCMP_UGE = 11,
DXIL_FCMP_ULT = 12,
DXIL_FCMP_ULE = 13,
DXIL_FCMP_UNE = 14,
DXIL_FCMP_TRUE = 15,
DXIL_ICMP_EQ = 32,
DXIL_ICMP_NE = 33,
DXIL_ICMP_UGT = 34,
DXIL_ICMP_UGE = 35,
DXIL_ICMP_ULT = 36,
DXIL_ICMP_ULE = 37,
DXIL_ICMP_SGT = 38,
DXIL_ICMP_SGE = 39,
DXIL_ICMP_SLT = 40,
DXIL_ICMP_SLE = 41,
DXIL_CMP_INSTR_COUNT
};
enum dxil_opt_flags {
DXIL_UNSAFE_ALGEBRA = (1 << 0),
DXIL_NO_NANS = (1 << 1),
DXIL_NO_INFS = (1 << 2),
DXIL_NO_SIGNED_ZEROS = (1 << 3),
DXIL_ALLOW_RECIPROCAL = (1 << 4)
};
struct dxil_features {
uint64_t doubles : 1,
cs_4x_raw_sb : 1,
uavs_at_every_stage : 1,
use_64uavs : 1,
min_precision : 1,
dx11_1_double_extensions : 1,
dx11_1_shader_extensions : 1,
dx9_comparison_filtering : 1,
tiled_resources : 1,
stencil_ref : 1,
inner_coverage : 1,
typed_uav_load_additional_formats : 1,
rovs : 1,
array_layer_from_vs_or_ds : 1,
wave_ops : 1,
int64_ops : 1,
view_id : 1,
barycentrics : 1,
native_low_precision : 1,
shading_rate : 1,
raytracing_tier_1_1 : 1,
sampler_feedback : 1,
atomic_int64_typed : 1,
atomic_int64_tgsm : 1,
derivatives_in_mesh_or_amp : 1,
resource_descriptor_heap_indexing : 1,
sampler_descriptor_heap_indexing : 1,
unnamed : 1,
atomic_int64_heap_resource : 1,
advanced_texture_ops : 1,
writable_msaa : 1,
sample_cmp_bias_gradient : 1,
extended_command_info : 1;
};
struct dxil_shader_info {
unsigned has_out_position:1;
unsigned has_out_depth:1;
unsigned has_per_sample_input:1;
};
struct dxil_func_def {
struct list_head head;
const struct dxil_func *func;
struct list_head instr_list;
int *basic_block_ids; /* maps from "user" ids to LLVM ids */
size_t num_basic_block_ids;
unsigned curr_block;
};
struct dxil_module {
void *ralloc_ctx;
enum dxil_shader_kind shader_kind;
unsigned major_version, minor_version;
unsigned major_validator, minor_validator;
struct dxil_features feats;
unsigned raw_and_structured_buffers : 1;
struct dxil_shader_info info;
struct dxil_buffer buf;
/* The number of entries in the arrays below */
unsigned num_sig_inputs;
unsigned num_sig_outputs;
unsigned num_sig_patch_consts;
/* The number of "vectors" of elements. This is used to determine the sizes
* of the dependency tables.
*/
unsigned num_psv_inputs;
unsigned num_psv_outputs[4];
unsigned num_psv_patch_consts;
struct dxil_signature_record inputs[DXIL_SHADER_MAX_IO_ROWS];
struct dxil_signature_record outputs[DXIL_SHADER_MAX_IO_ROWS];
struct dxil_signature_record patch_consts[DXIL_SHADER_MAX_IO_ROWS];
/* This array is indexed using var->data.driver_location, which
* is not a direct match to IO rows, since a row is a vec4, and
* variables can occupy less than that, and several vars can
* be packed in a row. Hence the x4, but I doubt we can end up
* with more than 80x4 variables in practice. Maybe this array
* should be allocated dynamically based on on the maximum
* driver_location across all input vars.
*/
uint8_t input_mappings[DXIL_SHADER_MAX_IO_ROWS * 4];
uint8_t output_mappings[DXIL_SHADER_MAX_IO_ROWS * 4];
uint8_t patch_mappings[DXIL_SHADER_MAX_IO_ROWS * 4];
struct dxil_psv_signature_element psv_inputs[DXIL_SHADER_MAX_IO_ROWS];
struct dxil_psv_signature_element psv_outputs[DXIL_SHADER_MAX_IO_ROWS];
struct dxil_psv_signature_element psv_patch_consts[DXIL_SHADER_MAX_IO_ROWS];
struct _mesa_string_buffer *sem_string_table;
struct dxil_psv_sem_index_table sem_index_table;
/* These tables are a bitmask per input, with one bit per output
* to indicate whether or not that input contributes to the output.
* Each input's bitmask size is rounded up to a uint32 (DWORD),
* so a bitbask for one output component is the same as for 8 output vec4s.
* Sizes are in number of uint32s.
* Meaning of each array entry depends on shader stage.
* GS: [i] = output stream index
* HS: [0] = control point outputs, [1] = patch constant outputs
* DS: [0] = control point inputs, [1] = patch constant inputs (only for io table)
* PS/VS: only 0 is used. */
uint32_t *serialized_dependency_table;
uint32_t *viewid_dependency_table[4];
uint32_t *io_dependency_table[4];
uint32_t dependency_table_dwords_per_input[4];
uint32_t io_dependency_table_size[4];
uint32_t serialized_dependency_table_size;
struct {
unsigned abbrev_width;
intptr_t offset;
} blocks[16];
size_t num_blocks;
struct list_head type_list;
struct list_head gvar_list;
struct list_head func_list;
struct list_head func_def_list;
struct list_head attr_set_list;
struct list_head const_list;
struct list_head mdnode_list;
struct list_head md_named_node_list;
const struct dxil_type *void_type;
const struct dxil_type *int1_type, *int8_type, *int16_type,
*int32_type, *int64_type;
const struct dxil_type *float16_type, *float32_type, *float64_type;
struct rb_tree *functions;
struct dxil_func_def *cur_emitting_func;
};
struct dxil_instr;
struct dxil_value;
void
dxil_module_init(struct dxil_module *m, void *ralloc_ctx);
void
dxil_module_release(struct dxil_module *m);
const struct dxil_value *
dxil_add_global_var(struct dxil_module *m, const char *name,
const struct dxil_type *type,
enum dxil_address_space as, int align,
const struct dxil_value *value);
const struct dxil_value *
dxil_add_global_ptr_var(struct dxil_module *m, const char *name,
const struct dxil_type *type,
enum dxil_address_space as, int align,
const struct dxil_value *value);
struct dxil_func_def *
dxil_add_function_def(struct dxil_module *m, const char *name,
const struct dxil_type *type, unsigned num_blocks,
const char *const *attr_keys, const char *const *attr_values);
const struct dxil_func *
dxil_add_function_decl(struct dxil_module *m, const char *name,
const struct dxil_type *type,
enum dxil_attr_kind attr);
const struct dxil_type *
dxil_module_get_void_type(struct dxil_module *m);
const struct dxil_type *
dxil_module_get_int_type(struct dxil_module *m, unsigned bit_size);
const struct dxil_type *
dxil_module_get_float_type(struct dxil_module *m, unsigned bit_size);
const struct dxil_type *
dxil_module_get_pointer_type(struct dxil_module *m,
const struct dxil_type *target);
const struct dxil_type *
dxil_get_overload_type(struct dxil_module *mod, enum overload_type overload);
const struct dxil_type *
dxil_module_get_handle_type(struct dxil_module *m);
const struct dxil_type *
dxil_module_get_cbuf_ret_type(struct dxil_module *mod, enum overload_type overload);
const struct dxil_type *
dxil_module_get_split_double_ret_type(struct dxil_module *mod);
const struct dxil_type *
dxil_module_get_res_type(struct dxil_module *m, enum dxil_resource_kind kind,
enum dxil_component_type comp_type, unsigned num_comps,
bool readwrite);
const struct dxil_type *
dxil_module_get_resret_type(struct dxil_module *m, enum overload_type overload);
const struct dxil_type *
dxil_module_get_dimret_type(struct dxil_module *m);
const struct dxil_type *
dxil_module_get_samplepos_type(struct dxil_module *m);
const struct dxil_type *
dxil_module_get_res_bind_type(struct dxil_module *m);
const struct dxil_type *
dxil_module_get_res_props_type(struct dxil_module *m);
const struct dxil_type *
dxil_module_get_fouri32_type(struct dxil_module *m);
const struct dxil_type *
dxil_module_get_struct_type(struct dxil_module *m,
const char *name,
const struct dxil_type **elem_types,
size_t num_elem_types);
const struct dxil_type *
dxil_module_get_array_type(struct dxil_module *m,
const struct dxil_type *elem_type,
size_t num_elems);
const struct dxil_type *
dxil_module_get_vector_type(struct dxil_module *m,
const struct dxil_type *elem_type,
size_t num_elems);
const struct dxil_type *
dxil_module_add_function_type(struct dxil_module *m,
const struct dxil_type *ret_type,
const struct dxil_type **arg_types,
size_t num_arg_types);
nir_alu_type
dxil_type_to_nir_type(const struct dxil_type *type);
bool
dxil_value_type_equal_to(const struct dxil_value *value,
const struct dxil_type *lhs);
bool
dxil_value_type_bitsize_equal_to(const struct dxil_value *value, unsigned bitsize);
const struct dxil_type *
dxil_value_get_type(const struct dxil_value *value);
const struct dxil_value *
dxil_module_get_int1_const(struct dxil_module *m, bool value);
const struct dxil_value *
dxil_module_get_int8_const(struct dxil_module *m, int8_t value);
const struct dxil_value *
dxil_module_get_int16_const(struct dxil_module *m, int16_t value);
const struct dxil_value *
dxil_module_get_int32_const(struct dxil_module *m, int32_t value);
const struct dxil_value *
dxil_module_get_int64_const(struct dxil_module *m, int64_t value);
const struct dxil_value *
dxil_module_get_int_const(struct dxil_module *m, intmax_t value,
unsigned bit_size);
const struct dxil_value *
dxil_module_get_float16_const(struct dxil_module *m, uint16_t);
const struct dxil_value *
dxil_module_get_float_const(struct dxil_module *m, float value);
const struct dxil_value *
dxil_module_get_double_const(struct dxil_module *m, double value);
const struct dxil_value *
dxil_module_get_array_const(struct dxil_module *m, const struct dxil_type *type,
const struct dxil_value **values);
const struct dxil_value *
dxil_module_get_vector_const(struct dxil_module *m, const struct dxil_type *type,
const struct dxil_value **values);
const struct dxil_value *
dxil_module_get_struct_const(struct dxil_module *m, const struct dxil_type *type,
const struct dxil_value **values);
const struct dxil_value *
dxil_module_get_undef(struct dxil_module *m, const struct dxil_type *type);
const struct dxil_value *
dxil_module_get_res_bind_const(struct dxil_module *m,
uint32_t lower_bound,
uint32_t upper_bound,
uint32_t space,
uint8_t class);
const struct dxil_value *
dxil_module_get_res_props_const(struct dxil_module *m,
enum dxil_resource_class class,
const struct dxil_mdnode *mdnode);
const struct dxil_value *
dxil_module_get_srv_res_props_const(struct dxil_module *m,
const nir_tex_instr *tex);
const struct dxil_value *
dxil_module_get_sampler_res_props_const(struct dxil_module *m,
bool is_shadow);
const struct dxil_value *
dxil_module_get_uav_res_props_const(struct dxil_module *m,
nir_intrinsic_instr *intr);
const struct dxil_value *
dxil_module_get_buffer_res_props_const(struct dxil_module *m,
enum dxil_resource_class class,
enum dxil_resource_kind kind);
const struct dxil_mdnode *
dxil_get_metadata_string(struct dxil_module *m, const char *str);
const struct dxil_mdnode *
dxil_get_metadata_value(struct dxil_module *m, const struct dxil_type *type,
const struct dxil_value *value);
const struct dxil_mdnode *
dxil_get_metadata_func(struct dxil_module *m, const struct dxil_func *func);
const struct dxil_mdnode *
dxil_get_metadata_int1(struct dxil_module *m, bool value);
const struct dxil_mdnode *
dxil_get_metadata_int8(struct dxil_module *m, int8_t value);
const struct dxil_mdnode *
dxil_get_metadata_int32(struct dxil_module *m, int32_t value);
const struct dxil_mdnode *
dxil_get_metadata_int64(struct dxil_module *m, int64_t value);
const struct dxil_mdnode *
dxil_get_metadata_float32(struct dxil_module *m, float value);
const struct dxil_mdnode *
dxil_get_metadata_node(struct dxil_module *m,
const struct dxil_mdnode *subnodes[],
size_t num_subnodes);
bool
dxil_add_metadata_named_node(struct dxil_module *m, const char *name,
const struct dxil_mdnode *subnodes[],
size_t num_subnodes);
const struct dxil_value *
dxil_emit_binop(struct dxil_module *m, enum dxil_bin_opcode opcode,
const struct dxil_value *op0, const struct dxil_value *op1,
enum dxil_opt_flags flags);
const struct dxil_value *
dxil_emit_cmp(struct dxil_module *m, enum dxil_cmp_pred pred,
const struct dxil_value *op0, const struct dxil_value *op1);
const struct dxil_value *
dxil_emit_select(struct dxil_module *m,
const struct dxil_value *op0,
const struct dxil_value *op1,
const struct dxil_value *op2);
const struct dxil_value *
dxil_emit_extractval(struct dxil_module *m, const struct dxil_value *src,
const unsigned int index);
const struct dxil_value *
dxil_emit_cast(struct dxil_module *m, enum dxil_cast_opcode opcode,
const struct dxil_type *type,
const struct dxil_value *value);
bool
dxil_emit_branch(struct dxil_module *m, const struct dxil_value *cond,
unsigned true_block, unsigned false_block);
const struct dxil_value *
dxil_instr_get_return_value(struct dxil_instr *instr);
struct dxil_instr *
dxil_emit_phi(struct dxil_module *m, const struct dxil_type *type);
bool
dxil_phi_add_incoming(struct dxil_instr *instr,
const struct dxil_value *incoming_values[],
const unsigned incoming_blocks[],
size_t num_incoming);
const struct dxil_value *
dxil_emit_call(struct dxil_module *m,
const struct dxil_func *func,
const struct dxil_value **args, size_t num_args);
bool
dxil_emit_call_void(struct dxil_module *m,
const struct dxil_func *func,
const struct dxil_value **args, size_t num_args);
bool
dxil_emit_ret_void(struct dxil_module *m);
const struct dxil_value *
dxil_emit_alloca(struct dxil_module *m, const struct dxil_type *alloc_type,
const struct dxil_value *size,
unsigned int align);
const struct dxil_value *
dxil_emit_gep_inbounds(struct dxil_module *m,
const struct dxil_value **operands,
size_t num_operands);
const struct dxil_value *
dxil_emit_load(struct dxil_module *m, const struct dxil_value *ptr,
unsigned align,
bool is_volatile);
bool
dxil_emit_store(struct dxil_module *m, const struct dxil_value *value,
const struct dxil_value *ptr, unsigned align,
bool is_volatile);
const struct dxil_value *
dxil_emit_cmpxchg(struct dxil_module *m, const struct dxil_value *cmpval,
const struct dxil_value *newval,
const struct dxil_value *ptr, bool is_volatile,
enum dxil_atomic_ordering ordering,
enum dxil_sync_scope syncscope);
const struct dxil_value *
dxil_emit_atomicrmw(struct dxil_module *m, const struct dxil_value *value,
const struct dxil_value *ptr, enum dxil_rmw_op op,
bool is_volatile, enum dxil_atomic_ordering ordering,
enum dxil_sync_scope syncscope);
bool
dxil_emit_module(struct dxil_module *m);
#ifdef __cplusplus
}
#endif
#endif
File diff suppressed because it is too large. Load diff
+103
View File
@@ -0,0 +1,103 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DXIL_NIR_H
#define DXIL_NIR_H
#include <stdbool.h>
#include "nir.h"
#include "nir_builder.h"
#ifdef __cplusplus
extern "C" {
#endif
bool dxil_nir_lower_8bit_conv(nir_shader *shader);
bool dxil_nir_lower_16bit_conv(nir_shader *shader);
bool dxil_nir_algebraic(nir_shader *shader);
bool dxil_nir_lower_fquantize2f16(nir_shader *shader);
bool dxil_nir_lower_constant_to_temp(nir_shader *shader);
bool dxil_nir_flatten_var_arrays(nir_shader *shader, nir_variable_mode modes);
bool dxil_nir_lower_var_bit_size(nir_shader *shader, nir_variable_mode modes,
unsigned min_bit_size, unsigned max_bit_size);
bool dxil_nir_remove_oob_array_accesses(nir_shader *shader);
bool dxil_nir_scratch_and_shared_to_dxil(nir_shader *shader);
bool dxil_nir_lower_deref_ssbo(nir_shader *shader);
bool dxil_nir_opt_alu_deref_srcs(nir_shader *shader);
bool dxil_nir_lower_upcast_phis(nir_shader *shader, unsigned min_bit_size);
bool dxil_nir_split_clip_cull_distance(nir_shader *shader);
bool dxil_nir_lower_double_math(nir_shader *shader);
bool dxil_nir_lower_system_values_to_zero(nir_shader *shader,
gl_system_value* system_value,
uint32_t count);
bool dxil_nir_lower_system_values(nir_shader *shader);
bool dxil_nir_split_typed_samplers(nir_shader *shader);
bool dxil_nir_lower_sysval_to_load_input(nir_shader *s, nir_variable **sysval_vars);
bool dxil_nir_lower_vs_vertex_conversion(nir_shader *s, enum pipe_format target_formats[]);
void
dxil_sort_by_driver_location(nir_shader* s, nir_variable_mode modes);
void
dxil_sort_ps_outputs(nir_shader* s);
void
dxil_reassign_driver_locations(nir_shader* s, nir_variable_mode modes,
uint64_t other_stage_mask, const BITSET_WORD *other_stage_frac_mask);
bool dxil_nir_split_tess_ctrl(nir_shader *nir, nir_function **patch_const_func);
bool dxil_nir_fixup_tess_level_for_domain(nir_shader *nir);
bool dxil_nir_set_tcs_patches_in(nir_shader *nir, unsigned num_control_points);
bool dxil_nir_lower_ubo_array_one_to_static(nir_shader *s);
bool dxil_nir_fix_io_uint_type(nir_shader *s, uint64_t in_mask, uint64_t out_mask);
bool dxil_nir_lower_discard_and_terminate(nir_shader* s);
bool dxil_nir_ensure_position_writes(nir_shader *s);
bool dxil_nir_lower_sample_pos(nir_shader *s);
bool dxil_nir_lower_subgroup_id(nir_shader *s);
bool dxil_nir_lower_num_subgroups(nir_shader *s);
bool dxil_nir_split_unaligned_loads_stores(nir_shader *shader, nir_variable_mode modes);
bool dxil_nir_lower_unsupported_subgroup_scan(nir_shader *s);
bool dxil_nir_forward_front_face(nir_shader *s);
bool dxil_nir_move_consts(nir_shader *s);
struct dxil_module;
bool dxil_nir_analyze_io_dependencies(struct dxil_module *mod, nir_shader *s);
bool dxil_nir_guess_image_formats(nir_shader *s);
bool dxil_nir_lower_coherent_loads_and_stores(nir_shader *s);
bool dxil_nir_kill_undefined_varyings(nir_shader *shader, uint64_t prev_stage_written_mask,
uint32_t prev_stage_patch_written_mask, const BITSET_WORD *prev_stage_frac_output_mask);
bool dxil_nir_kill_unused_outputs(nir_shader *shader, uint64_t next_stage_read_mask,
uint32_t next_stage_patch_read_mask, const BITSET_WORD *next_stage_frac_input_mask);
void dxil_nir_propagate_interp_to_outputs(nir_shader *prev_stage_nir,
const nir_shader *fs_nir);
/* Synthesize placeholder TES inputs mirroring TCS outputs the consumer
* doesn't already declare, so DXIL signature shapes match. */
bool dxil_nir_pad_tes_input_signature(nir_shader *tes, const nir_shader *tcs);
#ifdef __cplusplus
}
#endif
#endif /* DXIL_NIR_H */
@@ -0,0 +1,127 @@
#
# Copyright (C) 2020 Microsoft Corporation
#
# Copyright (C) 2018 Alyssa Rosenzweig
#
# Copyright (C) 2016 Intel Corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
import argparse
import sys
import math
a = 'a'
b = 'b'
c = 'c'
# The nir_lower_bit_size() pass gets rid of all 8bit ALUs but insert new u2u8
# and i2i8 operations to convert the result back to the original type after the
# arithmetic operation is done. Those u2u8 and i2i8 operations, as any other
# 8bit operations, are not supported by DXIL and needs to be discarded. The
# dxil_nir_lower_8bit_conv() pass is here for that.
# Similarly, some hardware doesn't support 16bit values
no_8bit_conv = []
no_16bit_conv = []
def remove_unsupported_casts(arr, bit_size, mask, max_unsigned_float, min_signed_float, max_signed_float):
for outer_op_type in ('u2u', 'i2i', 'u2f', 'i2f'):
for outer_op_sz in (16, 32, 64):
if outer_op_sz == bit_size:
continue
outer_op = outer_op_type + str(int(outer_op_sz))
for inner_op_type in ('u2u', 'i2i'):
inner_op = inner_op_type + str(int(bit_size))
for src_sz in (16, 32, 64):
if (src_sz == bit_size):
continue
# Coming from integral, truncate appropriately
orig_seq = (outer_op, (inner_op, 'a@' + str(int(src_sz))))
if (outer_op[0] == 'u'):
new_seq = ('iand', a, mask)
else:
shift = src_sz - bit_size
new_seq = ('ishr', ('ishl', a, shift), shift)
# Make sure the destination is the right type/size
if outer_op_sz != src_sz or outer_op[2] != inner_op[0]:
new_seq = (outer_op, new_seq)
arr += [(orig_seq, new_seq)]
for inner_op_type in ('f2u', 'f2i'):
inner_op = inner_op_type + str(int(bit_size))
if (outer_op[2] == 'f'):
# From float and to float, just truncate via min/max, and ensure the right float size
for src_sz in (16, 32, 64):
if (src_sz == bit_size):
continue
orig_seq = (outer_op, (inner_op, 'a@' + str(int(src_sz))))
if (outer_op[0] == 'u'):
new_seq = ('fmin', ('fmax', a, 0.0), max_unsigned_float)
else:
new_seq = ('fmin', ('fmax', a, min_signed_float), max_signed_float)
if outer_op_sz != src_sz:
new_seq = ('f2f' + str(int(outer_op_sz)), new_seq)
arr += [(orig_seq, new_seq)]
else:
# From float to integral, convert to integral type first, then truncate
orig_seq = (outer_op, (inner_op, a))
float_conv = ('f2' + inner_op[2] + str(int(outer_op_sz)), a)
if (outer_op[0] == 'u'):
new_seq = ('iand', float_conv, mask)
else:
shift = outer_op_sz - bit_size
new_seq = ('ishr', ('ishl', float_conv, shift), shift)
arr += [(orig_seq, new_seq)]
remove_unsupported_casts(no_8bit_conv, 8, 0xff, 255.0, -128.0, 127.0)
remove_unsupported_casts(no_16bit_conv, 16, 0xffff, 65535.0, -32768.0, 32767.0)
algebraic_ops = [
(('b2b32', 'a'), ('b2i32', 'a')),
(('b2b1', 'a'), ('ine', ('b2i32', a), 0)),
]
no_16bit_conv += [
(('f2f32', ('u2u16', 'a@32')), ('unpack_half_x_dxil', a)),
(('u2u32', ('f2f16_rtz', 'a@32')), ('pack_half_2x16_split', 'a', 0)),
]
def main():
parser = argparse.ArgumentParser()
parser.add_argument('-p', '--import-path', required=True)
args = parser.parse_args()
sys.path.insert(0, args.import_path)
run()
def run():
import nir_algebraic # pylint: disable=import-error
print('#include "dxil_nir.h"')
print(nir_algebraic.AlgebraicPass("dxil_nir_lower_8bit_conv",
no_8bit_conv).render())
print(nir_algebraic.AlgebraicPass("dxil_nir_lower_16bit_conv",
no_16bit_conv).render())
print(nir_algebraic.AlgebraicPass("dxil_nir_algebraic",
algebraic_ops).render())
if __name__ == '__main__':
main()
@@ -0,0 +1,556 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "dxil_nir_lower_int_cubemaps.h"
#include "nir_builder.h"
#include "nir_builtin_builder.h"
static bool
type_needs_lowering(const struct glsl_type *type, bool lower_samplers)
{
type = glsl_without_array(type);
if (!glsl_type_is_image(type) && !glsl_type_is_sampler(type))
return false;
if (glsl_get_sampler_dim(type) != GLSL_SAMPLER_DIM_CUBE)
return false;
if (glsl_type_is_image(type))
return true;
return lower_samplers && glsl_base_type_is_integer(glsl_get_sampler_result_type(type));
}
static bool
lower_int_cubmap_to_array_filter(const nir_instr *instr,
const void *options)
{
bool lower_samplers = *(bool *)options;
if (instr->type == nir_instr_type_intrinsic) {
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
switch (intr->intrinsic) {
case nir_intrinsic_image_atomic:
case nir_intrinsic_image_atomic_swap:
case nir_intrinsic_image_load:
case nir_intrinsic_image_size:
case nir_intrinsic_image_store:
case nir_intrinsic_image_deref_atomic:
case nir_intrinsic_image_deref_atomic_swap:
case nir_intrinsic_image_deref_load:
case nir_intrinsic_image_deref_size:
case nir_intrinsic_image_deref_store:
return nir_intrinsic_image_dim(intr) == GLSL_SAMPLER_DIM_CUBE;
default:
return false;
}
} else if (instr->type == nir_instr_type_deref) {
nir_deref_instr *deref = nir_instr_as_deref(instr);
return type_needs_lowering(deref->type, lower_samplers);
} else if (instr->type == nir_instr_type_tex && lower_samplers) {
nir_tex_instr *tex = nir_instr_as_tex(instr);
if (tex->sampler_dim != GLSL_SAMPLER_DIM_CUBE)
return false;
switch (tex->op) {
case nir_texop_tex:
case nir_texop_txb:
case nir_texop_txd:
case nir_texop_txl:
case nir_texop_txs:
case nir_texop_lod:
case nir_texop_tg4:
break;
default:
return false;
}
int sampler_deref = nir_tex_instr_src_index(tex, nir_tex_src_sampler_deref);
assert(sampler_deref >= 0);
nir_deref_instr *deref = nir_def_as_deref(tex->src[sampler_deref].src.ssa);
nir_variable *cube = nir_deref_instr_get_variable(deref);
return glsl_base_type_is_integer(glsl_get_sampler_result_type(cube->type));
}
return false;
}
typedef struct {
bool image;
nir_def *rx;
nir_def *ry;
nir_def *rz;
nir_def *arx;
nir_def *ary;
nir_def *arz;
nir_def *array;
} coord_t;
/* This is taken from from sp_tex_sample:convert_cube */
static nir_def *
evaluate_face_x(nir_builder *b, coord_t *coord)
{
nir_def *sign = nir_fsign(b, coord->rx);
nir_def *positive = nir_fge_imm(b, coord->rx, 0.0);
nir_def *ima = nir_fdiv(b, nir_imm_float(b, -0.5), coord->arx);
nir_def *x = nir_fadd_imm(b, nir_fmul(b, nir_fmul(b, sign, ima), coord->rz), 0.5);
nir_def *y = nir_fadd_imm(b, nir_fmul(b, ima, coord->ry), 0.5);
nir_def *face = nir_bcsel(b, positive, nir_imm_float(b, 0.0), nir_imm_float(b, 1.0));
if (coord->array)
face = nir_fadd(b, face, coord->array);
return coord->image ?
nir_vec4(b, x,y, face, nir_undef(b, 1, 32)) :
nir_vec3(b, x,y, face);
}
static nir_def *
evaluate_face_y(nir_builder *b, coord_t *coord)
{
nir_def *sign = nir_fsign(b, coord->ry);
nir_def *positive = nir_fge_imm(b, coord->ry, 0.0);
nir_def *ima = nir_fdiv(b, nir_imm_float(b, 0.5), coord->ary);
nir_def *x = nir_fadd_imm(b, nir_fmul(b, ima, coord->rx), 0.5);
nir_def *y = nir_fadd_imm(b, nir_fmul(b, nir_fmul(b, sign, ima), coord->rz), 0.5);
nir_def *face = nir_bcsel(b, positive, nir_imm_float(b, 2.0), nir_imm_float(b, 3.0));
if (coord->array)
face = nir_fadd(b, face, coord->array);
return coord->image ?
nir_vec4(b, x,y, face, nir_undef(b, 1, 32)) :
nir_vec3(b, x,y, face);
}
static nir_def *
evaluate_face_z(nir_builder *b, coord_t *coord)
{
nir_def *sign = nir_fsign(b, coord->rz);
nir_def *positive = nir_fge_imm(b, coord->rz, 0.0);
nir_def *ima = nir_fdiv(b, nir_imm_float(b, -0.5), coord->arz);
nir_def *x = nir_fadd_imm(b, nir_fmul(b, nir_fmul(b, sign, ima), nir_fneg(b, coord->rx)), 0.5);
nir_def *y = nir_fadd_imm(b, nir_fmul(b, ima, coord->ry), 0.5);
nir_def *face = nir_bcsel(b, positive, nir_imm_float(b, 4.0), nir_imm_float(b, 5.0));
if (coord->array)
face = nir_fadd(b, face, coord->array);
return coord->image ?
nir_vec4(b, x,y, face, nir_undef(b, 1, 32)) :
nir_vec3(b, x,y, face);
}
static nir_def *
create_array_tex_from_cube_tex(nir_builder *b, nir_tex_instr *tex, nir_def *coord, nir_texop op)
{
nir_tex_instr *array_tex;
array_tex = nir_tex_instr_create(b->shader, tex->num_srcs);
array_tex->op = op;
array_tex->sampler_dim = GLSL_SAMPLER_DIM_2D;
array_tex->is_array = true;
array_tex->is_shadow = tex->is_shadow;
array_tex->is_new_style_shadow = tex->is_new_style_shadow;
array_tex->texture_index = tex->texture_index;
array_tex->sampler_index = tex->sampler_index;
array_tex->dest_type = tex->dest_type;
array_tex->coord_components = 3;
array_tex->can_speculate = tex->can_speculate;
nir_src coord_src = nir_src_for_ssa(coord);
for (unsigned i = 0; i < tex->num_srcs; i++) {
nir_src *psrc = (tex->src[i].src_type == nir_tex_src_coord) ?
&coord_src : &tex->src[i].src;
array_tex->src[i].src = nir_src_for_ssa(psrc->ssa);
array_tex->src[i].src_type = tex->src[i].src_type;
}
nir_def_init(&array_tex->instr, &array_tex->def,
nir_tex_instr_dest_size(array_tex), 32);
nir_builder_instr_insert(b, &array_tex->instr);
return &array_tex->def;
}
static nir_def *
handle_cube_edge(nir_builder *b, nir_def *x, nir_def *y, nir_def *face, nir_def *array_slice_cube_base, nir_def *tex_size)
{
enum cube_remap
{
cube_remap_zero = 0,
cube_remap_x,
cube_remap_y,
cube_remap_tex_size,
cube_remap_tex_size_minus_x,
cube_remap_tex_size_minus_y,
cube_remap_size,
};
struct cube_remap_table
{
enum cube_remap remap_x;
enum cube_remap remap_y;
uint32_t remap_face;
};
static const struct cube_remap_table cube_remap_neg_x[6] =
{
{cube_remap_tex_size, cube_remap_y, 4},
{cube_remap_tex_size, cube_remap_y, 5},
{cube_remap_y, cube_remap_zero, 1},
{cube_remap_tex_size_minus_y, cube_remap_tex_size, 1},
{cube_remap_tex_size, cube_remap_y, 1},
{cube_remap_tex_size, cube_remap_y, 0},
};
static const struct cube_remap_table cube_remap_pos_x[6] =
{
{cube_remap_zero, cube_remap_y, 5},
{cube_remap_zero, cube_remap_y, 4},
{cube_remap_tex_size_minus_y, cube_remap_zero, 0},
{cube_remap_y, cube_remap_tex_size, 0},
{cube_remap_zero, cube_remap_y, 0},
{cube_remap_zero, cube_remap_y, 1},
};
static const struct cube_remap_table cube_remap_neg_y[6] =
{
{cube_remap_tex_size, cube_remap_tex_size_minus_x, 2},
{cube_remap_zero, cube_remap_x, 2},
{cube_remap_tex_size_minus_x, cube_remap_zero, 5},
{cube_remap_x, cube_remap_tex_size, 4},
{cube_remap_x, cube_remap_tex_size, 2},
{cube_remap_tex_size_minus_x, cube_remap_zero, 2},
};
static const struct cube_remap_table cube_remap_pos_y[6] =
{
{cube_remap_tex_size, cube_remap_x, 3},
{cube_remap_zero, cube_remap_tex_size_minus_x, 3},
{cube_remap_x, cube_remap_zero, 4},
{cube_remap_tex_size_minus_x, cube_remap_tex_size, 5},
{cube_remap_x, cube_remap_zero, 3},
{cube_remap_tex_size_minus_x, cube_remap_tex_size, 3},
};
static const struct cube_remap_table* remap_tables[4] = {
cube_remap_neg_x,
cube_remap_pos_x,
cube_remap_neg_y,
cube_remap_pos_y
};
nir_def *zero = nir_imm_int(b, 0);
/* Doesn't matter since the texture is square */
tex_size = nir_channel(b, tex_size, 0);
nir_def *x_on = nir_iand(b, nir_ige(b, x, zero), nir_ige(b, tex_size, x));
nir_def *y_on = nir_iand(b, nir_ige(b, y, zero), nir_ige(b, tex_size, y));
nir_def *one_on = nir_ixor(b, x_on, y_on);
/* If the sample did not fall off the face in either dimension, then set output = input */
nir_def *x_result = x;
nir_def *y_result = y;
nir_def *face_result = face;
/* otherwise, if the sample fell off the face in either the X or the Y direction, remap to the new face */
nir_def *remap_predicates[4] =
{
nir_iand(b, one_on, nir_ilt(b, x, zero)),
nir_iand(b, one_on, nir_ilt(b, tex_size, x)),
nir_iand(b, one_on, nir_ilt(b, y, zero)),
nir_iand(b, one_on, nir_ilt(b, tex_size, y)),
};
nir_def *remap_array[cube_remap_size];
remap_array[cube_remap_zero] = zero;
remap_array[cube_remap_x] = x;
remap_array[cube_remap_y] = y;
remap_array[cube_remap_tex_size] = tex_size;
remap_array[cube_remap_tex_size_minus_x] = nir_isub(b, tex_size, x);
remap_array[cube_remap_tex_size_minus_y] = nir_isub(b, tex_size, y);
/* For each possible way the sample could have fallen off */
for (unsigned i = 0; i < 4; i++) {
const struct cube_remap_table* remap_table = remap_tables[i];
/* For each possible original face */
for (unsigned j = 0; j < 6; j++) {
nir_def *predicate = nir_iand(b, remap_predicates[i], nir_ieq_imm(b, face, j));
x_result = nir_bcsel(b, predicate, remap_array[remap_table[j].remap_x], x_result);
y_result = nir_bcsel(b, predicate, remap_array[remap_table[j].remap_y], y_result);
face_result = nir_bcsel(b, predicate, remap_array[remap_table[j].remap_face], face_result);
}
}
return nir_vec3(b, x_result, y_result, nir_iadd(b, face_result, array_slice_cube_base));
}
static nir_def *
handle_cube_gather(nir_builder *b, nir_tex_instr *tex, nir_def *coord)
{
nir_def *tex_size = nir_get_texture_size(b, tex);
/* nir_get_texture_size puts the cursor before the tex op */
b->cursor = nir_after_def(coord);
nir_def *const_05 = nir_imm_float(b, 0.5f);
nir_def *texel_coords = nir_fmul(b, nir_trim_vector(b, coord, 2),
nir_i2f32(b, nir_trim_vector(b, tex_size, 2)));
nir_def *x_orig = nir_channel(b, texel_coords, 0);
nir_def *y_orig = nir_channel(b, texel_coords, 1);
nir_def *x_pos = nir_f2i32(b, nir_fadd(b, x_orig, const_05));
nir_def *x_neg = nir_f2i32(b, nir_fsub(b, x_orig, const_05));
nir_def *y_pos = nir_f2i32(b, nir_fadd(b, y_orig, const_05));
nir_def *y_neg = nir_f2i32(b, nir_fsub(b, y_orig, const_05));
nir_def *coords[4][2] = {
{ x_neg, y_pos },
{ x_pos, y_pos },
{ x_pos, y_neg },
{ x_neg, y_neg },
};
nir_def *array_slice_2d = nir_f2i32(b, nir_channel(b, coord, 2));
nir_def *face = nir_imod_imm(b, array_slice_2d, 6);
nir_def *array_slice_cube_base = nir_isub(b, array_slice_2d, face);
nir_def *channels[4];
for (unsigned i = 0; i < 4; ++i) {
nir_def *final_coord = handle_cube_edge(b, coords[i][0], coords[i][1], face, array_slice_cube_base, tex_size);
nir_def *sampled_val = create_array_tex_from_cube_tex(b, tex, final_coord, nir_texop_txf);
channels[i] = nir_channel(b, sampled_val, tex->component);
}
return nir_vec(b, channels, 4);
}
static nir_def *
lower_cube_coords(nir_builder *b, nir_def *coord, bool is_array, bool is_image)
{
coord_t coords;
coords.image = is_image;
coords.rx = nir_channel(b, coord, 0);
coords.ry = nir_channel(b, coord, 1);
coords.rz = nir_channel(b, coord, 2);
coords.arx = nir_fabs(b, coords.rx);
coords.ary = nir_fabs(b, coords.ry);
coords.arz = nir_fabs(b, coords.rz);
coords.array = NULL;
if (is_array)
coords.array = nir_fmul_imm(b, nir_channel(b, coord, 3), 6.0f);
nir_def *use_face_x = nir_iand(b,
nir_fge(b, coords.arx, coords.ary),
nir_fge(b, coords.arx, coords.arz));
nir_if *use_face_x_if = nir_push_if(b, use_face_x);
nir_def *face_x_coord = evaluate_face_x(b, &coords);
nir_if *use_face_x_else = nir_push_else(b, use_face_x_if);
nir_def *use_face_y = nir_iand(b,
nir_fge(b, coords.ary, coords.arx),
nir_fge(b, coords.ary, coords.arz));
nir_if *use_face_y_if = nir_push_if(b, use_face_y);
nir_def *face_y_coord = evaluate_face_y(b, &coords);
nir_if *use_face_y_else = nir_push_else(b, use_face_y_if);
nir_def *face_z_coord = evaluate_face_z(b, &coords);
nir_pop_if(b, use_face_y_else);
nir_def *face_y_or_z_coord = nir_if_phi(b, face_y_coord, face_z_coord);
nir_pop_if(b, use_face_x_else);
// This contains in xy the normalized sample coordinates, and in z the face index
nir_def *coord_and_face = nir_if_phi(b, face_x_coord, face_y_or_z_coord);
return coord_and_face;
}
static nir_def *
lower_cube_sample(nir_builder *b, nir_tex_instr *tex)
{
int coord_index = nir_tex_instr_src_index(tex, nir_tex_src_coord);
assert(coord_index >= 0);
/* Evaluate the face and the xy coordinates for a 2D tex op */
nir_def *coord = tex->src[coord_index].src.ssa;
nir_def *coord_and_face = lower_cube_coords(b, coord, tex->is_array, false);
if (tex->op == nir_texop_tg4)
return handle_cube_gather(b, tex, coord_and_face);
else
return create_array_tex_from_cube_tex(b, tex, coord_and_face, tex->op);
}
static nir_def *
lower_cube_image_load_store_atomic(nir_builder *b, nir_intrinsic_instr *intr)
{
b->cursor = nir_before_instr(&intr->instr);
nir_intrinsic_set_image_array(intr, true);
nir_intrinsic_set_image_dim(intr, GLSL_SAMPLER_DIM_2D);
return NIR_LOWER_INSTR_PROGRESS;
}
static nir_def *
lower_cube_txs(nir_builder *b, nir_tex_instr *tex)
{
b->cursor = nir_after_instr(&tex->instr);
if (!tex->is_array)
return nir_trim_vector(b, &tex->def, 2);
nir_def *array_dim = nir_channel(b, &tex->def, 2);
nir_def *cube_array_dim = nir_idiv(b, array_dim, nir_imm_int(b, 6));
return nir_vec3(b, nir_channel(b, &tex->def, 0),
nir_channel(b, &tex->def, 1),
cube_array_dim);
}
static nir_def *
lower_cube_image_size(nir_builder *b, nir_intrinsic_instr *intr)
{
b->cursor = nir_after_instr(&intr->instr);
if (!nir_intrinsic_image_array(intr))
return nir_trim_vector(b, &intr->def, 2);
nir_def *array_dim = nir_channel(b, &intr->def, 2);
nir_def *cube_array_dim = nir_idiv(b, array_dim, nir_imm_int(b, 6));
return nir_vec3(b, nir_channel(b, &intr->def, 0),
nir_channel(b, &intr->def, 1),
cube_array_dim);
}
static const struct glsl_type *
make_2darray_sampler_from_cubemap(const struct glsl_type *type)
{
return glsl_get_sampler_dim(type) == GLSL_SAMPLER_DIM_CUBE ?
glsl_sampler_type(
GLSL_SAMPLER_DIM_2D,
false, true,
glsl_get_sampler_result_type(type)) : type;
}
static const struct glsl_type *
make_2darray_image_from_cubemap(const struct glsl_type *type)
{
return glsl_get_sampler_dim(type) == GLSL_SAMPLER_DIM_CUBE ?
glsl_image_type(
GLSL_SAMPLER_DIM_2D,
true,
glsl_get_sampler_result_type(type)) : type;
}
static const struct glsl_type *
make_2darray_from_cubemap_with_array(const struct glsl_type *type, bool is_image)
{
if (glsl_type_is_array(type)) {
const struct glsl_type *new_type = glsl_without_array(type);
return new_type != type ? glsl_array_type(make_2darray_from_cubemap_with_array(glsl_without_array(type), is_image),
glsl_get_length(type), 0) : type;
} else if (is_image)
return make_2darray_image_from_cubemap(type);
else
return make_2darray_sampler_from_cubemap(type);
}
static nir_def *
lower_int_cubemap_to_array_tex(nir_builder *b, nir_tex_instr *tex)
{
switch (tex->op) {
case nir_texop_tex:
case nir_texop_txb:
case nir_texop_txd:
case nir_texop_txl:
case nir_texop_lod:
case nir_texop_tg4:
return lower_cube_sample(b, tex);
case nir_texop_txs:
return lower_cube_txs(b, tex);
default:
UNREACHABLE("Unsupported cupe map texture operation");
}
}
static nir_def *
lower_cube_image_intrinsic(nir_builder *b, nir_intrinsic_instr *intr)
{
if (intr->intrinsic == nir_intrinsic_image_size ||
intr->intrinsic == nir_intrinsic_image_deref_size)
return lower_cube_image_size(b, intr);
else
return lower_cube_image_load_store_atomic(b, intr);
}
static nir_def *
lower_cube_image_deref(nir_builder *b, nir_deref_instr *deref)
{
deref->type = make_2darray_from_cubemap_with_array(
deref->type,
glsl_type_is_image(glsl_without_array(deref->type)));
return NIR_LOWER_INSTR_PROGRESS;
}
static nir_def *
lower_int_cubmap_to_array_impl(nir_builder *b, nir_instr *instr,
void *options)
{
bool lower_samplers = *(bool *)options;
if (instr->type == nir_instr_type_tex && lower_samplers)
return lower_int_cubemap_to_array_tex(b, nir_instr_as_tex(instr));
else if (instr->type == nir_instr_type_intrinsic)
return lower_cube_image_intrinsic(b, nir_instr_as_intrinsic(instr));
else if (instr->type == nir_instr_type_deref)
return lower_cube_image_deref(b, nir_instr_as_deref(instr));
return NULL;
}
bool
dxil_nir_lower_int_cubemaps(nir_shader *s, bool lower_samplers)
{
bool result =
nir_shader_lower_instructions(s,
lower_int_cubmap_to_array_filter,
lower_int_cubmap_to_array_impl,
&lower_samplers);
if (result) {
nir_foreach_variable_with_modes_safe(var, s, nir_var_uniform | nir_var_image) {
if (!type_needs_lowering(var->type, lower_samplers))
continue;
bool is_image = glsl_type_is_image(glsl_without_array(var->type));
var->type = make_2darray_from_cubemap_with_array(var->type, is_image);
}
}
return result;
}
@@ -0,0 +1,40 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef DXIL_NIR_LOWER_INT_CUBEMAPS_H
#define DXIL_NIR_LOWER_INT_CUBEMAPS_H
#include "nir.h"
#ifdef __cplusplus
extern "C" {
#endif
bool
dxil_nir_lower_int_cubemaps(nir_shader *s, bool lower_samplers);
#ifdef __cplusplus
}
#endif
#endif // DXIL_NIR_LOWER_INT_CUBEMAPS_H
@@ -0,0 +1,575 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "dxil_nir_lower_int_samplers.h"
#include "nir_builder.h"
#include "nir_builtin_builder.h"
typedef struct {
unsigned n_texture_states;
dxil_wrap_sampler_state* wrap_states;
dxil_texture_swizzle_state* tex_swizzles;
float max_bias;
} sampler_states;
static bool
lower_sample_to_txf_for_integer_tex_filter(const nir_instr *instr,
const void *_options)
{
if (instr->type != nir_instr_type_tex)
return false;
nir_tex_instr *tex = nir_instr_as_tex(instr);
if (tex->op != nir_texop_tex &&
tex->op != nir_texop_txb &&
tex->op != nir_texop_txl &&
tex->op != nir_texop_txd)
return false;
return (tex->dest_type & (nir_type_int | nir_type_uint));
}
static nir_def *
dx_get_texture_lod(nir_builder *b, nir_tex_instr *tex)
{
nir_tex_instr *tql;
unsigned num_srcs = 0;
for (unsigned i = 0; i < tex->num_srcs; i++) {
if (tex->src[i].src_type == nir_tex_src_coord ||
tex->src[i].src_type == nir_tex_src_texture_deref ||
tex->src[i].src_type == nir_tex_src_sampler_deref ||
tex->src[i].src_type == nir_tex_src_texture_offset ||
tex->src[i].src_type == nir_tex_src_sampler_offset ||
tex->src[i].src_type == nir_tex_src_texture_handle ||
tex->src[i].src_type == nir_tex_src_sampler_handle)
num_srcs++;
}
tql = nir_tex_instr_create(b->shader, num_srcs);
tql->op = nir_texop_lod;
unsigned coord_components = tex->coord_components;
if (tex->is_array)
--coord_components;
tql->coord_components = coord_components;
tql->sampler_dim = tex->sampler_dim;
tql->is_shadow = tex->is_shadow;
tql->is_new_style_shadow = tex->is_new_style_shadow;
tql->texture_index = tex->texture_index;
tql->sampler_index = tex->sampler_index;
tql->can_speculate = tex->can_speculate;
tql->dest_type = nir_type_float32;
/* The coordinate needs special handling because we might have
* to strip the array index. Don't clutter the code with an additional
* check for is_array though, in the worst case we create an additional
* move the the optimization will remove later again. */
int coord_index = nir_tex_instr_src_index(tex, nir_tex_src_coord);
nir_def *ssa_src = nir_trim_vector(b, tex->src[coord_index].src.ssa,
coord_components);
tql->src[0].src = nir_src_for_ssa(ssa_src);
tql->src[0].src_type = nir_tex_src_coord;
unsigned idx = 1;
for (unsigned i = 0; i < tex->num_srcs; i++) {
if (tex->src[i].src_type == nir_tex_src_texture_deref ||
tex->src[i].src_type == nir_tex_src_sampler_deref ||
tex->src[i].src_type == nir_tex_src_texture_offset ||
tex->src[i].src_type == nir_tex_src_sampler_offset ||
tex->src[i].src_type == nir_tex_src_texture_handle ||
tex->src[i].src_type == nir_tex_src_sampler_handle) {
tql->src[idx].src = nir_src_for_ssa(tex->src[i].src.ssa);
tql->src[idx].src_type = tex->src[i].src_type;
idx++;
}
}
nir_def_init(&tql->instr, &tql->def, 2, 32);
nir_builder_instr_insert(b, &tql->instr);
/* DirectX LOD only has a value in x channel */
return nir_channel(b, &tql->def, 0);
}
typedef struct {
nir_def *coords;
nir_def *use_border_color;
} wrap_result_t;
typedef struct {
nir_def *lod;
nir_def *size;
int ncoord_comp;
wrap_result_t wrap[3];
} wrap_lower_param_t;
static void
wrap_clamp_to_edge(nir_builder *b, wrap_result_t *wrap_params, nir_def *size)
{
/* clamp(coord, 0, size - 1) */
wrap_params->coords = nir_fmin(b, nir_fadd_imm(b, size, -1.0f),
nir_fmax(b, wrap_params->coords, nir_imm_float(b, 0.0f)));
}
static void
wrap_repeat(nir_builder *b, wrap_result_t *wrap_params, nir_def *size)
{
/* mod(coord, size)
* This instruction must be exact, otherwise certain sizes result in
* incorrect sampling */
wrap_params->coords = nir_fmod(b, wrap_params->coords, size);
nir_def_as_alu(wrap_params->coords)->fp_math_ctrl |= nir_fp_exact;
}
static nir_def *
mirror(nir_builder *b, nir_def *coord)
{
/* coord if >= 0, otherwise -(1 + coord) */
return nir_bcsel(b, nir_fge_imm(b, coord, 0.0f), coord,
nir_fneg(b, nir_fadd_imm(b, coord, 1.0f)));
}
static void
wrap_mirror_repeat(nir_builder *b, wrap_result_t *wrap_params, nir_def *size)
{
/* (size − 1) − mirror(mod(coord, 2 * size) − size) */
nir_def *coord_mod2size = nir_fmod(b, wrap_params->coords, nir_fmul_imm(b, size, 2.0f));
nir_def_as_alu(coord_mod2size)->fp_math_ctrl |= nir_fp_exact;
nir_def *a = nir_fsub(b, coord_mod2size, size);
wrap_params->coords = nir_fsub(b, nir_fadd_imm(b, size, -1.0f), mirror(b, a));
}
static void
wrap_mirror_clamp_to_edge(nir_builder *b, wrap_result_t *wrap_params, nir_def *size)
{
/* clamp(mirror(coord), 0, size - 1) */
wrap_params->coords = nir_fmin(b, nir_fadd_imm(b, size, -1.0f),
nir_fmax(b, mirror(b, wrap_params->coords), nir_imm_float(b, 0.0f)));
}
static void
wrap_clamp(nir_builder *b, wrap_result_t *wrap_params, nir_def *size)
{
nir_def *is_low = nir_flt_imm(b, wrap_params->coords, 0.0);
nir_def *is_high = nir_fge(b, wrap_params->coords, size);
wrap_params->use_border_color = nir_ior(b, is_low, is_high);
}
static void
wrap_mirror_clamp(nir_builder *b, wrap_result_t *wrap_params, nir_def *size)
{
/* We have to take care of the boundaries */
nir_def *is_low = nir_flt(b, wrap_params->coords, nir_fmul_imm(b, size, -1.0));
nir_def *is_high = nir_flt(b, nir_fmul_imm(b, size, 2.0), wrap_params->coords);
wrap_params->use_border_color = nir_ior(b, is_low, is_high);
/* Within the boundaries this acts like mirror_repeat */
wrap_mirror_repeat(b, wrap_params, size);
}
static wrap_result_t
wrap_coords(nir_builder *b, nir_def *coords, enum dxil_tex_wrap wrap,
nir_def *size)
{
wrap_result_t result = {coords, nir_imm_false(b)};
switch (wrap) {
case DXIL_TEX_WRAP_CLAMP_TO_EDGE:
wrap_clamp_to_edge(b, &result, size);
break;
case DXIL_TEX_WRAP_REPEAT:
wrap_repeat(b, &result, size);
break;
case DXIL_TEX_WRAP_MIRROR_REPEAT:
wrap_mirror_repeat(b, &result, size);
break;
case DXIL_TEX_WRAP_MIRROR_CLAMP:
case DXIL_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
wrap_mirror_clamp_to_edge(b, &result, size);
break;
case DXIL_TEX_WRAP_CLAMP:
case DXIL_TEX_WRAP_CLAMP_TO_BORDER:
wrap_clamp(b, &result, size);
break;
case DXIL_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
wrap_mirror_clamp(b, &result, size);
break;
}
return result;
}
static nir_def *
load_bordercolor(nir_builder *b, nir_tex_instr *tex, const dxil_wrap_sampler_state *active_state,
const dxil_texture_swizzle_state *tex_swizzle)
{
int ndest_comp = tex->def.num_components;
unsigned swizzle[4] = {
tex_swizzle->swizzle_r,
tex_swizzle->swizzle_g,
tex_swizzle->swizzle_b,
tex_swizzle->swizzle_a
};
/* Avoid any possible float conversion issues */
uint32_t border_color[4];
memcpy(border_color, active_state->border_color, sizeof(border_color));
STATIC_ASSERT(sizeof(border_color) == sizeof(active_state->border_color));
nir_const_value const_value[4];
for (int i = 0; i < ndest_comp; ++i) {
switch (swizzle[i]) {
case PIPE_SWIZZLE_0:
const_value[i] = nir_const_value_for_uint(0, 32);
break;
case PIPE_SWIZZLE_1:
const_value[i] = nir_const_value_for_uint(1, 32);
break;
case PIPE_SWIZZLE_X:
case PIPE_SWIZZLE_Y:
case PIPE_SWIZZLE_Z:
case PIPE_SWIZZLE_W:
const_value[i] = nir_const_value_for_uint(border_color[swizzle[i]], 32);
break;
default:
UNREACHABLE("Unexpected swizzle value");
}
}
return nir_build_imm(b, ndest_comp, 32, const_value);
}
static nir_tex_instr *
create_txf_from_tex(nir_builder *b, nir_tex_instr *tex)
{
nir_tex_instr *txf;
unsigned num_srcs = 0;
for (unsigned i = 0; i < tex->num_srcs; i++) {
if (tex->src[i].src_type == nir_tex_src_texture_deref ||
tex->src[i].src_type == nir_tex_src_texture_offset ||
tex->src[i].src_type == nir_tex_src_texture_handle)
num_srcs++;
}
txf = nir_tex_instr_create(b->shader, num_srcs);
txf->op = nir_texop_txf;
txf->coord_components = tex->coord_components;
txf->sampler_dim = tex->sampler_dim;
txf->is_array = tex->is_array;
txf->is_shadow = tex->is_shadow;
txf->is_new_style_shadow = tex->is_new_style_shadow;
txf->texture_index = tex->texture_index;
txf->sampler_index = tex->sampler_index;
txf->can_speculate = tex->can_speculate;
txf->dest_type = tex->dest_type;
unsigned idx = 0;
for (unsigned i = 0; i < tex->num_srcs; i++) {
if (tex->src[i].src_type == nir_tex_src_texture_deref ||
tex->src[i].src_type == nir_tex_src_texture_offset ||
tex->src[i].src_type == nir_tex_src_texture_handle) {
txf->src[idx].src = nir_src_for_ssa(tex->src[i].src.ssa);
txf->src[idx].src_type = tex->src[i].src_type;
idx++;
}
}
nir_def_init(&txf->instr, &txf->def, nir_tex_instr_dest_size(txf), 32);
nir_builder_instr_insert(b, &txf->instr);
return txf;
}
static nir_def *
load_texel(nir_builder *b, nir_tex_instr *tex, wrap_lower_param_t *params)
{
nir_def *texcoord = NULL;
/* Put coordinates back together */
switch (tex->coord_components) {
case 1:
texcoord = params->wrap[0].coords;
break;
case 2:
texcoord = nir_vec2(b, params->wrap[0].coords, params->wrap[1].coords);
break;
case 3:
texcoord = nir_vec3(b, params->wrap[0].coords, params->wrap[1].coords, params->wrap[2].coords);
break;
default:
;
}
texcoord = nir_f2i32(b, texcoord);
nir_tex_instr *load = create_txf_from_tex(b, tex);
nir_tex_instr_add_src(load, nir_tex_src_lod, params->lod);
nir_tex_instr_add_src(load, nir_tex_src_coord, texcoord);
b->cursor = nir_after_instr(&load->instr);
return &load->def;
}
typedef struct {
const dxil_wrap_sampler_state *aws;
float max_bias;
nir_def *size;
int ncoord_comp;
} lod_params;
static nir_def *
evalute_active_lod(nir_builder *b, nir_tex_instr *tex, lod_params *params)
{
static nir_def *lod = NULL;
/* Later we use min_lod for clamping the LOD to a legal value */
float min_lod = MAX2(params->aws->min_lod, 0.0f);
/* Evaluate the LOD to be used for the texel fetch */
if (unlikely(tex->op == nir_texop_txl)) {
int lod_index = nir_tex_instr_src_index(tex, nir_tex_src_lod);
/* if we have an explicite LOD, take it */
lod = tex->src[lod_index].src.ssa;
} else if (unlikely(tex->op == nir_texop_txd)) {
int ddx_index = nir_tex_instr_src_index(tex, nir_tex_src_ddx);
int ddy_index = nir_tex_instr_src_index(tex, nir_tex_src_ddy);
assert(ddx_index >= 0 && ddy_index >= 0);
nir_def *grad = nir_fmax(b,
tex->src[ddx_index].src.ssa,
tex->src[ddy_index].src.ssa);
nir_def *r = nir_fmul(b, grad, nir_i2f32(b, params->size));
nir_def *rho = nir_channel(b, r, 0);
for (int i = 1; i < params->ncoord_comp; ++i)
rho = nir_fmax(b, rho, nir_channel(b, r, i));
lod = nir_flog2(b, rho);
} else if (b->shader->info.stage == MESA_SHADER_FRAGMENT){
lod = dx_get_texture_lod(b, tex);
} else {
/* Only fragment shaders provide the gradient information to evaluate a LOD,
* so force 0 otherwise */
lod = nir_imm_float(b, 0.0);
}
/* Evaluate bias according to OpenGL (4.6 (Compatibility Profile) October 22, 2019),
* sec. 8.14.1, eq. (8.9)
*
* lod' = lambda + CLAMP(bias_texobj + bias_texunit + bias_shader)
*
* bias_texobj is the value of TEXTURE_LOD_BIAS for the bound texture object. ...
* bias_textunt is the value of TEXTURE_LOD_BIAS for the current texture unit, ...
* bias shader is the value of the optional bias parameter in the texture
* lookup functions available to fragment shaders. ... The sum of these values
* is clamped to the range [−bias_max, bias_max] where bias_max is the value
* of the implementation defined constant MAX_TEXTURE_LOD_BIAS.
* In core contexts the value bias_texunit is dropped from above equation.
*
* Gallium provides the value lod_bias as the sum of bias_texobj and bias_texunit
* in compatibility contexts and as bias_texobj in core contexts, hence the
* implementation here is the same in both cases.
*/
nir_def *lod_bias = nir_imm_float(b, params->aws->lod_bias);
if (unlikely(tex->op == nir_texop_txb)) {
int bias_index = nir_tex_instr_src_index(tex, nir_tex_src_bias);
lod_bias = nir_fadd(b, lod_bias, tex->src[bias_index].src.ssa);
}
lod = nir_fadd(b, lod, nir_fclamp(b, lod_bias,
nir_imm_float(b, -params->max_bias),
nir_imm_float(b, params->max_bias)));
/* Clamp lod according to ibid. eq. (8.10) */
lod = nir_fmax(b, lod, nir_imm_float(b, min_lod));
/* If the max lod is > max_bias = log2(max_texture_size), the lod will be clamped
* by the number of levels, no need to clamp it againt the max_lod first. */
if (params->aws->max_lod <= params->max_bias)
lod = nir_fmin(b, lod, nir_imm_float(b, params->aws->max_lod));
/* Pick nearest LOD */
lod = nir_f2i32(b, nir_fround_even(b, lod));
/* cap actual lod by number of available levels */
return nir_imin(b, lod, nir_imm_int(b, params->aws->last_level));
}
static nir_def *
lower_sample_to_txf_for_integer_tex_impl(nir_builder *b, nir_instr *instr,
void *options)
{
sampler_states *states = (sampler_states *)options;
wrap_lower_param_t params = {0};
nir_tex_instr *tex = nir_instr_as_tex(instr);
const static dxil_wrap_sampler_state default_wrap_state = {
{ 0, 0, 0, 1 },
0,
FLT_MIN, FLT_MAX,
0,
{ 0, 0, 0 },
1,
0,
0,
0
};
const dxil_wrap_sampler_state *active_wrap_state = tex->sampler_index < states->n_texture_states ? &states->wrap_states[tex->sampler_index] : &default_wrap_state;
b->cursor = nir_before_instr(instr);
int coord_index = nir_tex_instr_src_index(tex, nir_tex_src_coord);
nir_def *old_coord = tex->src[coord_index].src.ssa;
params.ncoord_comp = tex->coord_components;
if (tex->is_array)
params.ncoord_comp -= 1;
/* This helper to get the texture size always uses LOD 0, and DirectX doesn't support
* giving another LOD when querying the texture size */
nir_def *size0 = nir_get_texture_size(b, tex);
params.lod = nir_imm_int(b, 0);
if (active_wrap_state->last_level > 0) {
lod_params p = {
.aws = active_wrap_state,
.max_bias = states->max_bias,
.size = size0,
.ncoord_comp = params.ncoord_comp
};
params.lod = evalute_active_lod(b, tex, &p);
/* Evaluate actual level size*/
params.size = nir_i2f32(b, nir_imax(b, nir_ishr(b, size0, params.lod),
nir_imm_int(b, 1)));
} else {
params.size = nir_i2f32(b, size0);
}
nir_def *new_coord = old_coord;
if (!active_wrap_state->is_nonnormalized_coords) {
/* Evaluate the integer lookup coordinates for the requested LOD, don't touch the
* array index */
if (!tex->is_array) {
new_coord = nir_fmul(b, params.size, old_coord);
} else {
nir_def *array_index = nir_channel(b, old_coord, params.ncoord_comp);
int mask = (1 << params.ncoord_comp) - 1;
nir_def *coord = nir_fmul(b, nir_channels(b, params.size, mask),
nir_channels(b, old_coord, mask));
switch (params.ncoord_comp) {
case 1:
new_coord = nir_vec2(b, coord, array_index);
break;
case 2:
new_coord = nir_vec3(b, nir_channel(b, coord, 0),
nir_channel(b, coord, 1),
array_index);
break;
default:
UNREACHABLE("unsupported number of non-array coordinates");
}
}
}
nir_def *coord_help[3];
for (int i = 0; i < params.ncoord_comp; ++i)
coord_help[i] = nir_ffloor(b, nir_channel(b, new_coord, i));
// Note: array index needs to be rounded to nearest before clamp rather than floored
if (tex->is_array)
coord_help[params.ncoord_comp] = nir_fround_even(b, nir_channel(b, new_coord, params.ncoord_comp));
/* Correct the texture coordinates for the offsets. */
int offset_index = nir_tex_instr_src_index(tex, nir_tex_src_offset);
if (offset_index >= 0) {
nir_def *offset = tex->src[offset_index].src.ssa;
for (int i = 0; i < params.ncoord_comp; ++i)
coord_help[i] = nir_fadd(b, coord_help[i], nir_i2f32(b, nir_channel(b, offset, i)));
}
nir_def *use_border_color = nir_imm_false(b);
if (!active_wrap_state->skip_boundary_conditions) {
for (int i = 0; i < params.ncoord_comp; ++i) {
params.wrap[i] = wrap_coords(b, coord_help[i], active_wrap_state->wrap[i], nir_channel(b, params.size, i));
use_border_color = nir_ior(b, use_border_color, params.wrap[i].use_border_color);
}
if (tex->is_array)
params.wrap[params.ncoord_comp] =
wrap_coords(b, coord_help[params.ncoord_comp],
DXIL_TEX_WRAP_CLAMP_TO_EDGE,
nir_i2f32(b, nir_channel(b, size0, params.ncoord_comp)));
} else {
/* When we emulate a cube map by using a texture array, the coordinates are always
* in range, and we don't have to take care of boundary conditions */
for (unsigned i = 0; i < 3; ++i) {
params.wrap[i].coords = coord_help[i];
params.wrap[i].use_border_color = nir_imm_false(b);
}
}
const dxil_texture_swizzle_state one2one = {
PIPE_SWIZZLE_X, PIPE_SWIZZLE_Y, PIPE_SWIZZLE_Z, PIPE_SWIZZLE_W
};
nir_if *border_if = nir_push_if(b, use_border_color);
const dxil_texture_swizzle_state *swizzle = (states->tex_swizzles && tex->sampler_index < states->n_texture_states) ?
&states->tex_swizzles[tex->sampler_index]:
&one2one;
nir_def *border_color = load_bordercolor(b, tex, active_wrap_state, swizzle);
nir_if *border_else = nir_push_else(b, border_if);
nir_def *sampler_color = load_texel(b, tex, &params);
nir_pop_if(b, border_else);
return nir_if_phi(b, border_color, sampler_color);
}
/* Sampling from integer textures is not allowed in DirectX, so we have
* to use texel fetches. For this we have to scale the coordiantes
* to be integer based, and evaluate the LOD the texel fetch has to be
* applied on, and take care of the boundary conditions .
*/
bool
dxil_lower_sample_to_txf_for_integer_tex(nir_shader *s,
unsigned n_texture_states,
dxil_wrap_sampler_state *wrap_states,
dxil_texture_swizzle_state *tex_swizzles,
float max_bias)
{
sampler_states states = { n_texture_states, wrap_states, tex_swizzles, max_bias};
bool result =
nir_shader_lower_instructions(s,
lower_sample_to_txf_for_integer_tex_filter,
lower_sample_to_txf_for_integer_tex_impl,
&states);
return result;
}
@@ -0,0 +1,75 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef DXIL_NIR_LOWER_INT_SAMPLERS_H
#define DXIL_NIR_LOWER_INT_SAMPLERS_H
#include "nir.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
unsigned swizzle_r:3;
unsigned swizzle_g:3;
unsigned swizzle_b:3;
unsigned swizzle_a:3;
} dxil_texture_swizzle_state;
enum dxil_tex_wrap {
DXIL_TEX_WRAP_REPEAT,
DXIL_TEX_WRAP_CLAMP,
DXIL_TEX_WRAP_CLAMP_TO_EDGE,
DXIL_TEX_WRAP_CLAMP_TO_BORDER,
DXIL_TEX_WRAP_MIRROR_REPEAT,
DXIL_TEX_WRAP_MIRROR_CLAMP,
DXIL_TEX_WRAP_MIRROR_CLAMP_TO_EDGE,
DXIL_TEX_WRAP_MIRROR_CLAMP_TO_BORDER,
};
typedef struct {
float border_color[4];
float lod_bias;
float min_lod, max_lod;
int last_level;
uint8_t wrap[3]; /* enum dxil_tex_wrap */
uint8_t is_int_sampler:1;
uint8_t is_nonnormalized_coords:1;
uint8_t is_linear_filtering:1;
uint8_t skip_boundary_conditions:1;
uint8_t unused:4;
} dxil_wrap_sampler_state;
bool
dxil_lower_sample_to_txf_for_integer_tex(nir_shader *s,
unsigned n_texture_states,
dxil_wrap_sampler_state *wrap_states,
dxil_texture_swizzle_state *tex_swizzles,
float max_bias);
#ifdef __cplusplus
}
#endif
#endif // DXIL_NIR_LOWER_INT_SAMPLERS_H
@@ -0,0 +1,167 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "dxil_nir.h"
#include "nir_builder.h"
#include "nir_builtin_builder.h"
static enum pipe_format
get_input_target_format(nir_variable *var, const void *options)
{
enum pipe_format *target_formats = (enum pipe_format *)options;
return target_formats[var->data.driver_location];
}
static bool
lower_vs_vertex_conversion_filter(const nir_instr *instr, const void *options)
{
if (instr->type != nir_instr_type_intrinsic)
return false;
nir_intrinsic_instr *inst = nir_instr_as_intrinsic(instr);
if (inst->intrinsic != nir_intrinsic_load_deref)
return false;
nir_variable *var = nir_intrinsic_get_var(inst, 0);
return (var->data.mode == nir_var_shader_in) &&
(get_input_target_format(var, options) != PIPE_FORMAT_NONE);
}
typedef nir_def *
(*shift_right_func)(nir_builder *build, nir_def *src0, nir_def *src1);
/* decoding the signed vs unsigned scaled format is handled
* by applying the signed or unsigned shift right function
* accordingly */
static nir_def *
from_10_10_10_2_scaled(nir_builder *b, nir_def *src,
nir_def *lshift, shift_right_func shr)
{
nir_def *rshift = nir_imm_ivec4(b, 22, 22, 22, 30);
return nir_i2f32(b, shr(b, nir_ishl(b, src, lshift), rshift));
}
static nir_def *
from_10_10_10_2_snorm(nir_builder *b, nir_def *src, nir_def *lshift)
{
nir_def *split = from_10_10_10_2_scaled(b, src, lshift, nir_ishr);
nir_def *scale_rgb = nir_imm_vec4(b,
1.0f / 0x1ff,
1.0f / 0x1ff,
1.0f / 0x1ff,
1.0f);
return nir_fmul(b, split, scale_rgb);
}
static nir_def *
from_10_10_10_2_unorm(nir_builder *b, nir_def *src, nir_def *lshift)
{
nir_def *split = from_10_10_10_2_scaled(b, src, lshift, nir_ushr);
nir_def *scale_rgb = nir_imm_vec4(b,
1.0f / 0x3ff,
1.0f / 0x3ff,
1.0f / 0x3ff,
1.0f / 3.0f);
return nir_fmul(b, split, scale_rgb);
}
inline static nir_def *
lshift_rgba(nir_builder *b)
{
return nir_imm_ivec4(b, 22, 12, 2, 0);
}
inline static nir_def *
lshift_bgra(nir_builder *b)
{
return nir_imm_ivec4(b, 2, 12, 22, 0);
}
static nir_def *
lower_vs_vertex_conversion_impl(nir_builder *b, nir_instr *instr, void *options)
{
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
nir_variable *var = nir_intrinsic_get_var(intr, 0);
enum pipe_format fmt = get_input_target_format(var, options);
if (!util_format_has_alpha(fmt)) {
/* these formats need the alpha channel replaced with 1: */
assert(fmt == PIPE_FORMAT_R8G8B8_SINT ||
fmt == PIPE_FORMAT_R8G8B8_UINT ||
fmt == PIPE_FORMAT_R16G16B16_SINT ||
fmt == PIPE_FORMAT_R16G16B16_UINT);
if (intr->def.num_components == 3)
return NULL;
return nir_vector_insert_imm(b, &intr->def, nir_imm_int(b, 1), 3);
} else {
nir_def *src = nir_channel(b, &intr->def, 0);
switch (fmt) {
case PIPE_FORMAT_R10G10B10A2_SNORM:
return from_10_10_10_2_snorm(b, src, lshift_rgba(b));
case PIPE_FORMAT_B10G10R10A2_SNORM:
return from_10_10_10_2_snorm(b, src, lshift_bgra(b));
case PIPE_FORMAT_B10G10R10A2_UNORM:
return from_10_10_10_2_unorm(b, src, lshift_bgra(b));
case PIPE_FORMAT_R10G10B10A2_SSCALED:
return from_10_10_10_2_scaled(b, src, lshift_rgba(b), nir_ishr);
case PIPE_FORMAT_B10G10R10A2_SSCALED:
return from_10_10_10_2_scaled(b, src, lshift_bgra(b), nir_ishr);
case PIPE_FORMAT_R10G10B10A2_USCALED:
return from_10_10_10_2_scaled(b, src, lshift_rgba(b), nir_ushr);
case PIPE_FORMAT_B10G10R10A2_USCALED:
return from_10_10_10_2_scaled(b, src, lshift_bgra(b), nir_ushr);
case PIPE_FORMAT_R8G8B8A8_USCALED:
case PIPE_FORMAT_R16G16B16A16_USCALED:
return nir_u2f32(b, &intr->def);
case PIPE_FORMAT_R8G8B8A8_SSCALED:
case PIPE_FORMAT_R16G16B16A16_SSCALED:
return nir_i2f32(b, &intr->def);
default:
UNREACHABLE("Unsupported emulated vertex format");
}
}
}
/* Lower emulated vertex attribute input
* The vertex attributes are passed as R32_UINT that needs to be converted
* to one of the RGB10A2 formats that need to be emulated.
*
* @param target_formats contains the per attribute format to convert to
* or PIPE_FORMAT_NONE if no conversion is needed
*/
bool
dxil_nir_lower_vs_vertex_conversion(nir_shader *s,
enum pipe_format target_formats[])
{
assert(s->info.stage == MESA_SHADER_VERTEX);
bool result =
nir_shader_lower_instructions(s,
lower_vs_vertex_conversion_filter,
lower_vs_vertex_conversion_impl,
target_formats);
return result;
}
+409
View File
@@ -0,0 +1,409 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "nir.h"
#include "nir_builder.h"
#include "nir_control_flow.h"
#include "dxil_nir.h"
static bool
is_memory_barrier_tcs_patch(const nir_intrinsic_instr *intr)
{
if (intr->intrinsic == nir_intrinsic_barrier &&
nir_intrinsic_memory_modes(intr) & nir_var_shader_out) {
assert(nir_intrinsic_memory_modes(intr) == nir_var_shader_out);
assert(nir_intrinsic_memory_scope(intr) == SCOPE_WORKGROUP || nir_intrinsic_memory_scope(intr) == SCOPE_INVOCATION);
return true;
} else {
return false;
}
}
static void
remove_hs_intrinsics(nir_function_impl *impl)
{
nir_foreach_block(block, impl) {
nir_foreach_instr_safe(instr, block) {
if (instr->type != nir_instr_type_intrinsic)
continue;
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
if (intr->intrinsic == nir_intrinsic_load_output ||
intr->intrinsic == nir_intrinsic_load_per_vertex_output) {
nir_builder b = nir_builder_at(nir_before_instr(&intr->instr));
nir_def_rewrite_uses(&intr->def, nir_undef(&b, intr->def.num_components, intr->def.bit_size));
} else if (intr->intrinsic != nir_intrinsic_store_output &&
!is_memory_barrier_tcs_patch(intr)) {
continue;
}
nir_instr_remove(instr);
}
}
nir_progress(true, impl, nir_metadata_control_flow);
}
static void
add_instr_and_srcs_to_set(struct set *instr_set, nir_instr *instr);
static bool
add_srcs_to_set(nir_src *src, void *state)
{
add_instr_and_srcs_to_set(state, nir_def_instr(src->ssa));
return true;
}
static void
add_instr_and_srcs_to_set(struct set *instr_set, nir_instr *instr)
{
bool was_already_found = false;
_mesa_set_search_or_add(instr_set, instr, &was_already_found);
if (!was_already_found)
nir_foreach_src(instr, add_srcs_to_set, instr_set);
}
static void
prune_patch_function_to_intrinsic_and_srcs(nir_function_impl *impl)
{
struct set *instr_set = _mesa_pointer_set_create(NULL);
/* Do this in two phases:
* 1. Find all instructions that contribute to a store_output and add them to
* the set. Also, add instructions that contribute to control flow.
* 2. Erase every instruction that isn't in the set
*/
nir_foreach_block(block, impl) {
nir_if *following_if = nir_block_get_following_if(block);
if (following_if) {
add_instr_and_srcs_to_set(instr_set, nir_def_instr(following_if->condition.ssa));
}
nir_foreach_instr_safe(instr, block) {
if (instr->type == nir_instr_type_intrinsic) {
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
if (intr->intrinsic != nir_intrinsic_store_output &&
!is_memory_barrier_tcs_patch(intr))
continue;
} else if (instr->type != nir_instr_type_jump)
continue;
add_instr_and_srcs_to_set(instr_set, instr);
}
}
nir_foreach_block_reverse(block, impl) {
nir_foreach_instr_reverse_safe(instr, block) {
struct set_entry *entry = _mesa_set_search(instr_set, instr);
if (!entry)
nir_instr_remove(instr);
}
}
_mesa_set_destroy(instr_set, NULL);
}
static nir_cursor
get_cursor_for_instr_without_cf(nir_instr *instr)
{
nir_block *block = instr->block;
if (block->cf_node.parent->type == nir_cf_node_function)
return nir_before_instr(instr);
do {
block = nir_cf_node_as_block(nir_cf_node_prev(block->cf_node.parent));
} while (block->cf_node.parent->type != nir_cf_node_function);
return nir_after_block_before_jump(block);
}
struct tcs_patch_loop_state {
nir_def *deref, *count;
nir_cursor begin_cursor, end_cursor, insert_cursor;
nir_loop *loop;
};
static void
start_tcs_loop(nir_builder *b, struct tcs_patch_loop_state *state, nir_deref_instr *loop_var_deref)
{
if (!loop_var_deref)
return;
nir_store_deref(b, loop_var_deref, nir_imm_int(b, 0), 1);
state->loop = nir_push_loop(b);
state->count = nir_load_deref(b, loop_var_deref);
nir_break_if(b, nir_ige_imm(b, state->count, b->impl->function->shader->info.tess.tcs_vertices_out));
state->insert_cursor = b->cursor;
nir_store_deref(b, loop_var_deref, nir_iadd_imm(b, state->count, 1), 1);
nir_pop_loop(b, state->loop);
}
static void
end_tcs_loop(nir_builder *b, struct tcs_patch_loop_state *state)
{
if (!state->loop)
return;
nir_cf_list extracted;
nir_cf_extract(&extracted, state->begin_cursor, state->end_cursor);
nir_cf_reinsert(&extracted, state->insert_cursor);
*state = (struct tcs_patch_loop_state ){ 0 };
}
/* In HLSL/DXIL, the hull (tesselation control) shader is split into two:
* 1. The main hull shader, which runs once per output control point.
* 2. A patch constant function, which runs once overall.
* In GLSL/NIR, these are combined. Each invocation must write to the output
* array with a constant gl_InvocationID, which is (apparently) lowered to an
* if/else ladder in nir. Each invocation must write the same value to patch
* constants - or else undefined behavior strikes. NIR uses store_output to
* write the patch constants, and store_per_vertex_output to write the control
* point values.
*
* We clone the NIR function to produce 2: one with the store_output intrinsics
* removed, which becomes the main shader (only writes control points), and one
* with everything that doesn't contribute to store_output removed, which becomes
* the patch constant function.
*
* For the patch constant function, if the expressions rely on gl_InvocationID,
* then we need to run the resulting logic in a loop, using the loop counter to
* replace gl_InvocationID. This loop can be terminated when a barrier is hit. If
* gl_InvocationID is used again after the barrier, then another loop needs to begin.
*/
bool
dxil_nir_split_tess_ctrl(nir_shader *nir, nir_function **patch_const_func)
{
assert(nir->info.stage == MESA_SHADER_TESS_CTRL);
assert(exec_list_length(&nir->functions) == 1);
nir_function_impl *entrypoint = nir_shader_get_entrypoint(nir);
*patch_const_func = nir_function_create(nir, "PatchConstantFunc");
nir_function_impl *patch_const_func_impl = nir_function_impl_clone(nir, entrypoint);
nir_function_set_impl(*patch_const_func, patch_const_func_impl);
remove_hs_intrinsics(entrypoint);
prune_patch_function_to_intrinsic_and_srcs(patch_const_func_impl);
/* Kill dead references to the invocation ID from the patch const func so we don't
* insert unnecessarily loops
*/
bool progress;
do {
progress = false;
progress |= nir_opt_dead_cf(nir);
progress |= nir_opt_dce(nir);
} while (progress);
/* Now, the patch constant function needs to be split into blocks and loops.
* The series of instructions up to the first block containing a load_invocation_id
* will run sequentially. Then a loop is inserted so load_invocation_id will load the
* loop counter. This loop continues until a barrier is reached, when the loop
* is closed and the process begins again.
*
* First, sink load_invocation_id so that each use has its own local load.
* This ensures the load sits in the same pre/post-barrier region as its
* use, which the loop-wrapping pass below relies on — even for single-use
* loads whose use sits across a barrier.
*/
nir_builder b = nir_builder_create(patch_const_func_impl);
nir_foreach_block(block, patch_const_func_impl) {
nir_foreach_instr_safe(instr, block) {
if (instr->type != nir_instr_type_intrinsic)
continue;
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
if (intr->intrinsic != nir_intrinsic_load_invocation_id ||
list_is_empty(&intr->def.uses))
continue;
nir_foreach_use_including_if_safe(src, &intr->def) {
b.cursor = nir_before_src(src);
nir_src_rewrite(src, nir_load_invocation_id(&b));
}
nir_instr_remove(instr);
}
}
/* Now replace those invocation ID loads with loads of a local variable that's used as a loop counter */
nir_variable *loop_var = NULL;
nir_deref_instr *loop_var_deref = NULL;
struct tcs_patch_loop_state state = { 0 };
nir_foreach_block_safe(block, patch_const_func_impl) {
nir_foreach_instr_safe(instr, block) {
if (instr->type != nir_instr_type_intrinsic)
continue;
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
switch (intr->intrinsic) {
case nir_intrinsic_load_invocation_id: {
if (!loop_var) {
loop_var = nir_local_variable_create(patch_const_func_impl, glsl_int_type(), "PatchConstInvocId");
b.cursor = nir_before_impl(patch_const_func_impl);
loop_var_deref = nir_build_deref_var(&b, loop_var);
}
if (!state.loop) {
b.cursor = state.begin_cursor = get_cursor_for_instr_without_cf(instr);
start_tcs_loop(&b, &state, loop_var_deref);
}
nir_def_rewrite_uses(&intr->def, state.count);
break;
}
case nir_intrinsic_barrier:
if (!is_memory_barrier_tcs_patch(intr))
break;
/* The GL tessellation spec says:
* The barrier() function may only be called inside the main entry point of the tessellation control shader
* and may not be called in potentially divergent flow control. In particular, barrier() may not be called
* inside a switch statement, in either sub-statement of an if statement, inside a do, for, or while loop,
* or at any point after a return statement in the function main().
*
* Therefore, we should be at function-level control flow.
*/
assert(nir_cursors_equal(nir_before_instr(instr), get_cursor_for_instr_without_cf(instr)));
state.end_cursor = nir_before_instr(instr);
end_tcs_loop(&b, &state);
nir_instr_remove(instr);
break;
default:
break;
}
}
}
state.end_cursor = nir_after_block_before_jump(nir_impl_last_block(patch_const_func_impl));
end_tcs_loop(&b, &state);
//TODO: this isn't correct if the def isn't loop invariant
/* If we have more than one loop, SSA needs to be repaired for one loop to use defs from another. */
if (loop_var)
nir_repair_ssa_impl(patch_const_func_impl);
nir_progress(true, patch_const_func_impl, nir_metadata_none);
nir_progress(true, entrypoint, nir_metadata_none);
return true;
}
struct remove_tess_level_accesses_data {
unsigned location;
unsigned size;
};
static bool
remove_tess_level_accesses(nir_builder *b, nir_instr *instr, void *_data)
{
struct remove_tess_level_accesses_data *data = _data;
if (instr->type != nir_instr_type_intrinsic)
return false;
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
if (intr->intrinsic != nir_intrinsic_store_output &&
intr->intrinsic != nir_intrinsic_load_input)
return false;
nir_io_semantics io = nir_intrinsic_io_semantics(intr);
if (io.location != data->location)
return false;
if (nir_intrinsic_component(intr) < data->size)
return false;
if (intr->intrinsic == nir_intrinsic_store_output) {
assert(nir_src_num_components(intr->src[0]) == 1);
nir_instr_remove(instr);
} else {
b->cursor = nir_after_instr(instr);
assert(intr->def.num_components == 1);
nir_def_rewrite_uses(&intr->def, nir_undef(b, 1, intr->def.bit_size));
}
return true;
}
/* Update the types of the tess level variables and remove writes to removed components.
* GL always has a 4-component outer tess level and 2-component inner, while D3D requires
* the number of components to vary based on the primitive mode.
* The 4 and 2 is for quads, while triangles are 3 and 1, and lines are 2 and 0.
*/
bool
dxil_nir_fixup_tess_level_for_domain(nir_shader *nir)
{
bool progress = false;
if (nir->info.tess._primitive_mode != TESS_PRIMITIVE_QUADS) {
nir_foreach_variable_with_modes_safe(var, nir, nir_var_shader_out | nir_var_shader_in) {
unsigned new_array_size = 4;
unsigned old_array_size = glsl_array_size(var->type);
if (var->data.location == VARYING_SLOT_TESS_LEVEL_OUTER) {
new_array_size = nir->info.tess._primitive_mode == TESS_PRIMITIVE_TRIANGLES ? 3 : 2;
assert(var->data.compact && (old_array_size == 4 || old_array_size == new_array_size));
} else if (var->data.location == VARYING_SLOT_TESS_LEVEL_INNER) {
new_array_size = nir->info.tess._primitive_mode == TESS_PRIMITIVE_TRIANGLES ? 1 : 0;
assert(var->data.compact && (old_array_size == 2 || old_array_size == new_array_size));
} else
continue;
if (new_array_size == old_array_size)
continue;
progress = true;
if (new_array_size)
var->type = glsl_array_type(glsl_float_type(), new_array_size, 0);
else {
exec_node_remove(&var->node);
ralloc_free(var);
}
struct remove_tess_level_accesses_data pass_data = {
.location = var->data.location,
.size = new_array_size
};
nir_shader_instructions_pass(nir, remove_tess_level_accesses,
nir_metadata_control_flow, &pass_data);
}
}
return progress;
}
static bool
tcs_update_deref_input_types(nir_builder *b, nir_instr *instr, void *data)
{
if (instr->type != nir_instr_type_deref)
return false;
nir_deref_instr *deref = nir_instr_as_deref(instr);
if (deref->deref_type != nir_deref_type_var)
return false;
nir_variable *var = deref->var;
deref->type = var->type;
return true;
}
bool
dxil_nir_set_tcs_patches_in(nir_shader *nir, unsigned num_control_points)
{
bool progress = false;
nir_foreach_variable_with_modes(var, nir, nir_var_shader_in) {
if (nir_is_arrayed_io(var, MESA_SHADER_TESS_CTRL)) {
var->type = glsl_array_type(glsl_get_array_element(var->type), num_control_points, 0);
progress = true;
}
}
if (progress)
nir_shader_instructions_pass(nir, tcs_update_deref_input_types, nir_metadata_all, NULL);
return progress;
}
+897
View File
@@ -0,0 +1,897 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "dxil_signature.h"
#include "dxil_enums.h"
#include "dxil_module.h"
#include "glsl_types.h"
#include "nir_to_dxil.h"
#include "util/u_debug.h"
#include <string.h>
struct semantic_info {
enum dxil_semantic_kind kind;
char name[64];
int index;
enum dxil_prog_sig_comp_type comp_type;
uint8_t sig_comp_type;
int32_t start_row;
int32_t rows;
uint8_t start_col;
uint8_t cols;
uint8_t interpolation;
uint8_t stream;
const char *sysvalue_name;
};
static bool
is_depth_output(enum dxil_semantic_kind kind)
{
return kind == DXIL_SEM_DEPTH || kind == DXIL_SEM_DEPTH_GE ||
kind == DXIL_SEM_DEPTH_LE || kind == DXIL_SEM_STENCIL_REF;
}
static uint8_t
get_interpolation(nir_variable *var)
{
if (var->data.patch)
return DXIL_INTERP_UNDEFINED;
if (glsl_type_is_integer(glsl_without_array_or_matrix(var->type)) ||
glsl_type_is_64bit(glsl_without_array_or_matrix(var->type)))
return DXIL_INTERP_CONSTANT;
if (var->data.sample) {
if (var->data.location == VARYING_SLOT_POS)
return DXIL_INTERP_LINEAR_NOPERSPECTIVE_SAMPLE;
switch (var->data.interpolation) {
case INTERP_MODE_NONE: return DXIL_INTERP_LINEAR_SAMPLE;
case INTERP_MODE_FLAT: return DXIL_INTERP_CONSTANT;
case INTERP_MODE_NOPERSPECTIVE: return DXIL_INTERP_LINEAR_NOPERSPECTIVE_SAMPLE;
case INTERP_MODE_SMOOTH: return DXIL_INTERP_LINEAR_SAMPLE;
}
} else if (unlikely(var->data.centroid)) {
if (var->data.location == VARYING_SLOT_POS)
return DXIL_INTERP_LINEAR_NOPERSPECTIVE_CENTROID;
switch (var->data.interpolation) {
case INTERP_MODE_NONE: return DXIL_INTERP_LINEAR_CENTROID;
case INTERP_MODE_FLAT: return DXIL_INTERP_CONSTANT;
case INTERP_MODE_NOPERSPECTIVE: return DXIL_INTERP_LINEAR_NOPERSPECTIVE_CENTROID;
case INTERP_MODE_SMOOTH: return DXIL_INTERP_LINEAR_CENTROID;
}
} else {
if (var->data.location == VARYING_SLOT_POS)
return DXIL_INTERP_LINEAR_NOPERSPECTIVE;
switch (var->data.interpolation) {
case INTERP_MODE_NONE: return DXIL_INTERP_LINEAR;
case INTERP_MODE_FLAT: return DXIL_INTERP_CONSTANT;
case INTERP_MODE_NOPERSPECTIVE: return DXIL_INTERP_LINEAR_NOPERSPECTIVE;
case INTERP_MODE_SMOOTH: return DXIL_INTERP_LINEAR;
}
}
return DXIL_INTERP_LINEAR;
}
static const char *
in_sysvalue_name(nir_variable *var)
{
switch (var->data.location) {
case VARYING_SLOT_POS:
return "POS";
case VARYING_SLOT_FACE:
return "FACE";
case VARYING_SLOT_LAYER:
return "RTINDEX";
default:
return "NONE";
}
}
/*
* The signatures are written into the stream in two pieces:
* DxilProgramSignatureElement is a fixes size structure that gets dumped
* to the stream in order of the registers and each contains an offset
* to the semantic name string. Then these strings are dumped into the stream.
*/
static unsigned
get_additional_semantic_info(nir_shader *s, nir_variable *var, struct semantic_info *info,
unsigned next_row, unsigned clip_size)
{
const struct glsl_type *type = var->type;
if (nir_is_arrayed_io(var, s->info.stage))
type = glsl_get_array_element(type);
info->comp_type = dxil_get_prog_sig_comp_type(type);
info->sig_comp_type = dxil_get_comp_type_from_prog_sig_type(info->comp_type);
bool is_depth = is_depth_output(info->kind);
bool is_gs_input = s->info.stage == MESA_SHADER_GEOMETRY &&
(var->data.mode & (nir_var_shader_in | nir_var_system_value));
info->stream = var->data.stream;
info->rows = 1;
if (info->kind == DXIL_SEM_TARGET) {
info->start_row = info->index;
info->cols = 4;
} else if (is_depth ||
(info->kind == DXIL_SEM_PRIMITIVE_ID && is_gs_input) ||
info->kind == DXIL_SEM_COVERAGE ||
info->kind == DXIL_SEM_SAMPLE_INDEX) {
// This turns into a 'N/A' mask in the disassembly
info->start_row = -1;
info->cols = 1;
} else if (info->kind == DXIL_SEM_TESS_FACTOR ||
info->kind == DXIL_SEM_INSIDE_TESS_FACTOR) {
assert(var->data.compact);
info->start_row = next_row;
info->rows = glsl_get_aoa_size(type);
info->cols = 1;
next_row += info->rows;
} else if (var->data.compact) {
info->start_row = next_row;
next_row++;
assert(glsl_type_is_array(type) && info->kind == DXIL_SEM_CLIP_DISTANCE);
unsigned num_floats = glsl_get_aoa_size(type);
unsigned start_offset = (var->data.location - VARYING_SLOT_CLIP_DIST0) * 4 +
var->data.location_frac;
if (start_offset >= clip_size) {
info->kind = DXIL_SEM_CULL_DISTANCE;
snprintf(info->name, 64, "SV_CullDistance");
}
info->cols = num_floats;
info->start_col = (uint8_t)var->data.location_frac;
} else {
info->start_row = next_row;
info->rows = glsl_count_vec4_slots(type, false, false);
if (glsl_type_is_array(type))
type = glsl_get_array_element(type);
next_row += info->rows;
info->start_col = (uint8_t)var->data.location_frac;
info->cols = MIN2(glsl_get_component_slots(type), 4);
}
return next_row;
}
typedef void (*semantic_info_proc)(nir_variable *var, struct semantic_info *info, mesa_shader_stage stage);
static void
get_semantic_vs_in_name(nir_variable *var, struct semantic_info *info, mesa_shader_stage stage)
{
strcpy(info->name, "TEXCOORD");
info->index = var->data.driver_location;
info->kind = DXIL_SEM_ARBITRARY;
}
static void
get_semantic_sv_name(nir_variable *var, struct semantic_info *info, mesa_shader_stage stage)
{
if (stage != MESA_SHADER_VERTEX)
info->interpolation = get_interpolation(var);
switch (var->data.location) {
case SYSTEM_VALUE_VERTEX_ID_ZERO_BASE:
info->kind = DXIL_SEM_VERTEX_ID;
break;
case SYSTEM_VALUE_INSTANCE_ID:
info->kind = DXIL_SEM_INSTANCE_ID;
break;
case SYSTEM_VALUE_PRIMITIVE_ID:
info->kind = DXIL_SEM_PRIMITIVE_ID;
break;
case SYSTEM_VALUE_SAMPLE_ID:
info->kind = DXIL_SEM_SAMPLE_INDEX;
break;
default:
UNREACHABLE("unsupported system value");
}
strncpy(info->name, var->name, ARRAY_SIZE(info->name) - 1);
}
static void
get_semantic_ps_outname(nir_variable *var, struct semantic_info *info)
{
info->kind = DXIL_SEM_INVALID;
switch (var->data.location) {
case FRAG_RESULT_COLOR:
snprintf(info->name, 64, "%s", "SV_Target");
info->index = var->data.index;
info->kind = DXIL_SEM_TARGET;
break;
case FRAG_RESULT_DATA0:
case FRAG_RESULT_DATA1:
case FRAG_RESULT_DATA2:
case FRAG_RESULT_DATA3:
case FRAG_RESULT_DATA4:
case FRAG_RESULT_DATA5:
case FRAG_RESULT_DATA6:
case FRAG_RESULT_DATA7:
snprintf(info->name, 64, "%s", "SV_Target");
info->index = var->data.location - FRAG_RESULT_DATA0;
if (var->data.location == FRAG_RESULT_DATA0 &&
var->data.index > 0)
info->index = var->data.index;
info->kind = DXIL_SEM_TARGET;
break;
case FRAG_RESULT_DEPTH:
snprintf(info->name, 64, "%s", "SV_Depth");
info->kind = DXIL_SEM_DEPTH;
break;
case FRAG_RESULT_STENCIL:
snprintf(info->name, 64, "%s", "SV_StencilRef");
info->kind = DXIL_SEM_STENCIL_REF; //??
break;
case FRAG_RESULT_SAMPLE_MASK:
snprintf(info->name, 64, "%s", "SV_Coverage");
info->kind = DXIL_SEM_COVERAGE; //??
break;
default:
snprintf(info->name, 64, "%s", "UNDEFINED");
break;
}
}
static void
get_semantic_name(nir_variable *var, struct semantic_info *info,
const struct glsl_type *type)
{
info->kind = DXIL_SEM_INVALID;
info->interpolation = get_interpolation(var);
switch (var->data.location) {
case VARYING_SLOT_POS:
assert(glsl_get_components(type) == 4);
snprintf(info->name, 64, "%s", "SV_Position");
info->kind = DXIL_SEM_POSITION;
break;
case VARYING_SLOT_FACE:
assert(glsl_get_components(type) == 1);
snprintf(info->name, 64, "%s", "SV_IsFrontFace");
info->kind = DXIL_SEM_IS_FRONT_FACE;
break;
case VARYING_SLOT_PRIMITIVE_ID:
assert(glsl_get_components(type) == 1);
snprintf(info->name, 64, "%s", "SV_PrimitiveID");
info->kind = DXIL_SEM_PRIMITIVE_ID;
break;
case VARYING_SLOT_CLIP_DIST1:
info->index = 1;
FALLTHROUGH;
case VARYING_SLOT_CLIP_DIST0:
assert(var->data.location == VARYING_SLOT_CLIP_DIST1 || info->index == 0);
snprintf(info->name, 64, "%s", "SV_ClipDistance");
info->kind = DXIL_SEM_CLIP_DISTANCE;
break;
case VARYING_SLOT_TESS_LEVEL_INNER:
assert(glsl_get_components(type) <= 2);
snprintf(info->name, 64, "%s", "SV_InsideTessFactor");
info->kind = DXIL_SEM_INSIDE_TESS_FACTOR;
break;
case VARYING_SLOT_TESS_LEVEL_OUTER:
assert(glsl_get_components(type) <= 4);
snprintf(info->name, 64, "%s", "SV_TessFactor");
info->kind = DXIL_SEM_TESS_FACTOR;
break;
case VARYING_SLOT_VIEWPORT:
assert(glsl_get_components(type) == 1);
snprintf(info->name, 64, "%s", "SV_ViewportArrayIndex");
info->kind = DXIL_SEM_VIEWPORT_ARRAY_INDEX;
break;
case VARYING_SLOT_LAYER:
assert(glsl_get_components(type) == 1);
snprintf(info->name, 64, "%s", "SV_RenderTargetArrayIndex");
info->kind = DXIL_SEM_RENDERTARGET_ARRAY_INDEX;
break;
default: {
info->index = var->data.driver_location;
strcpy(info->name, "TEXCOORD");
info->kind = DXIL_SEM_ARBITRARY;
}
}
}
static void
get_semantic_in_name(nir_variable *var, struct semantic_info *info, mesa_shader_stage stage)
{
const struct glsl_type *type = var->type;
if (nir_is_arrayed_io(var, stage) &&
glsl_type_is_array(type))
type = glsl_get_array_element(type);
get_semantic_name(var, info, type);
info->sysvalue_name = in_sysvalue_name(var);
}
static enum dxil_prog_sig_semantic
prog_semantic_from_kind(enum dxil_semantic_kind kind, unsigned num_vals, unsigned start_val)
{
switch (kind) {
case DXIL_SEM_ARBITRARY: return DXIL_PROG_SEM_UNDEFINED;
case DXIL_SEM_VERTEX_ID: return DXIL_PROG_SEM_VERTEX_ID;
case DXIL_SEM_INSTANCE_ID: return DXIL_PROG_SEM_INSTANCE_ID;
case DXIL_SEM_POSITION: return DXIL_PROG_SEM_POSITION;
case DXIL_SEM_COVERAGE: return DXIL_PROG_SEM_COVERAGE;
case DXIL_SEM_INNER_COVERAGE: return DXIL_PROG_SEM_INNER_COVERAGE;
case DXIL_SEM_PRIMITIVE_ID: return DXIL_PROG_SEM_PRIMITIVE_ID;
case DXIL_SEM_SAMPLE_INDEX: return DXIL_PROG_SEM_SAMPLE_INDEX;
case DXIL_SEM_IS_FRONT_FACE: return DXIL_PROG_SEM_IS_FRONTFACE;
case DXIL_SEM_RENDERTARGET_ARRAY_INDEX: return DXIL_PROG_SEM_RENDERTARGET_ARRAY_INDEX;
case DXIL_SEM_VIEWPORT_ARRAY_INDEX: return DXIL_PROG_SEM_VIEWPORT_ARRAY_INDEX;
case DXIL_SEM_CLIP_DISTANCE: return DXIL_PROG_SEM_CLIP_DISTANCE;
case DXIL_SEM_CULL_DISTANCE: return DXIL_PROG_SEM_CULL_DISTANCE;
case DXIL_SEM_BARYCENTRICS: return DXIL_PROG_SEM_BARYCENTRICS;
case DXIL_SEM_SHADING_RATE: return DXIL_PROG_SEM_SHADING_RATE;
case DXIL_SEM_CULL_PRIMITIVE: return DXIL_PROG_SEM_CULL_PRIMITIVE;
case DXIL_SEM_TARGET: return DXIL_PROG_SEM_TARGET;
case DXIL_SEM_DEPTH: return DXIL_PROG_SEM_DEPTH;
case DXIL_SEM_DEPTH_LE: return DXIL_PROG_SEM_DEPTH_LE;
case DXIL_SEM_DEPTH_GE: return DXIL_PROG_SEM_DEPTH_GE;
case DXIL_SEM_STENCIL_REF: return DXIL_PROG_SEM_STENCIL_REF;
case DXIL_SEM_TESS_FACTOR:
switch (num_vals) {
case 4: return DXIL_PROG_SEM_FINAL_QUAD_EDGE_TESSFACTOR;
case 3: return DXIL_PROG_SEM_FINAL_TRI_EDGE_TESSFACTOR;
case 2: return start_val == 0 ?
DXIL_PROG_SEM_FINAL_LINE_DENSITY_TESSFACTOR :
DXIL_PROG_SEM_FINAL_LINE_DETAIL_TESSFACTOR;
default:
UNREACHABLE("Invalid row count for tess factor");
}
case DXIL_SEM_INSIDE_TESS_FACTOR:
switch (num_vals) {
case 2: return DXIL_PROG_SEM_FINAL_QUAD_INSIDE_EDGE_TESSFACTOR;
case 1: return DXIL_PROG_SEM_FINAL_TRI_INSIDE_EDGE_TESSFACTOR;
default:
UNREACHABLE("Invalid row count for inner tess factor");
}
default:
return DXIL_PROG_SEM_UNDEFINED;
}
}
static
uint32_t
copy_semantic_name_to_string(struct _mesa_string_buffer *string_out, const char *name)
{
/* copy the semantic name */
uint32_t retval = string_out->length;
size_t name_len = strlen(name) + 1;
_mesa_string_buffer_append_len(string_out, name, name_len);
return retval;
}
static
uint32_t
append_semantic_index_to_table(struct dxil_psv_sem_index_table *table, uint32_t index,
uint32_t num_rows)
{
for (unsigned i = 0; i < table->size; ++i) {
unsigned j = 0;
for (; j < num_rows && i + j < table->size; ++j)
if (table->data[i + j] != index + j)
break;
if (j == num_rows)
return i;
else if (j > 0)
i += j - 1;
}
uint32_t retval = table->size;
assert(table->size + num_rows <= ARRAY_SIZE(table->data));
for (unsigned i = 0; i < num_rows; ++i)
table->data[table->size++] = index + i;
return retval;
}
static const struct dxil_mdnode *
fill_SV_param_nodes(struct dxil_module *mod, unsigned record_id,
const struct dxil_signature_record *rec,
const struct dxil_psv_signature_element *psv,
bool is_input) {
const struct dxil_mdnode *SV_params_nodes[11];
/* For this to always work we should use vectorize_io, but for FS out and VS in
* this is not implemented globally */
const struct dxil_mdnode *flattened_semantics[256];
for (unsigned i = 0; i < rec->num_elements; ++i)
flattened_semantics[i] = dxil_get_metadata_int32(mod, rec->elements[i].semantic_index);
SV_params_nodes[0] = dxil_get_metadata_int32(mod, (int)record_id); // Unique element ID
SV_params_nodes[1] = dxil_get_metadata_string(mod, rec->name); // Element name
SV_params_nodes[2] = dxil_get_metadata_int8(mod, rec->sig_comp_type); // Element type
SV_params_nodes[3] = dxil_get_metadata_int8(mod, (int8_t)psv->semantic_kind); // Effective system value
SV_params_nodes[4] = dxil_get_metadata_node(mod, flattened_semantics,
rec->num_elements); // Semantic index vector
SV_params_nodes[5] = dxil_get_metadata_int8(mod, psv->interpolation_mode); // Interpolation mode
SV_params_nodes[6] = dxil_get_metadata_int32(mod, psv->rows); // Number of rows
SV_params_nodes[7] = dxil_get_metadata_int8(mod, psv->cols_and_start & 0xf); // Number of columns
SV_params_nodes[8] = dxil_get_metadata_int32(mod, rec->elements[0].reg); // Element packing start row
SV_params_nodes[9] = dxil_get_metadata_int8(mod, (psv->cols_and_start >> 4) & 0x3); // Element packing start column
const struct dxil_mdnode *SV_metadata[6];
unsigned num_metadata_nodes = 0;
if (rec->elements[0].stream != 0) {
SV_metadata[num_metadata_nodes++] = dxil_get_metadata_int32(mod, DXIL_SIGNATURE_ELEMENT_OUTPUT_STREAM);
SV_metadata[num_metadata_nodes++] = dxil_get_metadata_int32(mod, rec->elements[0].stream);
}
uint8_t usage_mask = rec->elements[0].always_reads_mask;
if (!is_input)
usage_mask = 0xf & ~rec->elements[0].never_writes_mask;
if (usage_mask && mod->minor_validator >= 5) {
usage_mask >>= (psv->cols_and_start >> 4) & 0x3;
SV_metadata[num_metadata_nodes++] = dxil_get_metadata_int32(mod, DXIL_SIGNATURE_ELEMENT_USAGE_COMPONENT_MASK);
SV_metadata[num_metadata_nodes++] = dxil_get_metadata_int8(mod, usage_mask);
}
uint8_t dynamic_index_mask = psv->dynamic_mask_and_stream & 0xf;
if (dynamic_index_mask) {
SV_metadata[num_metadata_nodes++] = dxil_get_metadata_int32(mod, DXIL_SIGNATURE_ELEMENT_DYNAMIC_INDEX_COMPONENT_MASK);
SV_metadata[num_metadata_nodes++] = dxil_get_metadata_int8(mod, dynamic_index_mask);
}
SV_params_nodes[10] = num_metadata_nodes ? dxil_get_metadata_node(mod, SV_metadata, num_metadata_nodes) : NULL;
return dxil_get_metadata_node(mod, SV_params_nodes, ARRAY_SIZE(SV_params_nodes));
}
static void
fill_signature_element(struct dxil_signature_element *elm,
struct semantic_info *semantic,
unsigned row)
{
memset(elm, 0, sizeof(struct dxil_signature_element));
elm->stream = semantic->stream;
// elm->semantic_name_offset = 0; // Offset needs to be filled out when writing
elm->semantic_index = semantic->index + row;
elm->system_value = (uint32_t) prog_semantic_from_kind(semantic->kind, semantic->rows, row);
elm->comp_type = (uint32_t) semantic->comp_type;
elm->reg = semantic->start_row + row;
assert(semantic->cols + semantic->start_col <= 4);
elm->mask = (uint8_t) (((1 << semantic->cols) - 1) << semantic->start_col);
elm->min_precision = DXIL_MIN_PREC_DEFAULT;
}
static bool
fill_psv_signature_element(struct dxil_psv_signature_element *psv_elm,
struct semantic_info *semantic, struct dxil_module *mod)
{
memset(psv_elm, 0, sizeof(struct dxil_psv_signature_element));
psv_elm->rows = semantic->rows;
if (semantic->start_row >= 0) {
assert(semantic->start_row < 256);
psv_elm->start_row = semantic->start_row;
psv_elm->cols_and_start = (1u << 6) | (semantic->start_col << 4) | semantic->cols;
} else {
/* The validation expects that the the start row is not egative
* and apparently the extra bit in the cols_and_start indicates that the
* row is meant literally, so don't set it in this case.
* (Source of information: Comparing with the validation structures
* created by dxcompiler)
*/
psv_elm->start_row = 0;
psv_elm->cols_and_start = (semantic->start_col << 4) | semantic->cols;
}
psv_elm->semantic_kind = (uint8_t)semantic->kind;
psv_elm->component_type = semantic->comp_type;
psv_elm->interpolation_mode = semantic->interpolation;
psv_elm->dynamic_mask_and_stream = (semantic->stream) << 4;
if (semantic->kind == DXIL_SEM_ARBITRARY && strlen(semantic->name)) {
psv_elm->semantic_name_offset =
copy_semantic_name_to_string(mod->sem_string_table, semantic->name);
/* TODO: clean up memory */
if (psv_elm->semantic_name_offset == (uint32_t)-1)
return false;
}
psv_elm->semantic_indexes_offset =
append_semantic_index_to_table(&mod->sem_index_table, semantic->index, semantic->rows);
return true;
}
static bool
fill_io_signature(struct dxil_module *mod, int id,
struct semantic_info *semantic,
struct dxil_signature_record *rec,
struct dxil_psv_signature_element *psv_elm)
{
rec->name = ralloc_strdup(mod->ralloc_ctx, semantic->name);
rec->num_elements = semantic->rows;
rec->sig_comp_type = semantic->sig_comp_type;
for (unsigned i = 0; i < semantic->rows; ++i)
fill_signature_element(&rec->elements[i], semantic, i);
return fill_psv_signature_element(psv_elm, semantic, mod);
}
static unsigned
get_input_signature_group(struct dxil_module *mod,
unsigned num_inputs,
nir_shader *s, nir_variable_mode modes,
semantic_info_proc get_semantics, unsigned *row_iter,
unsigned input_clip_size)
{
nir_foreach_variable_with_modes(var, s, modes) {
if (var->data.patch)
continue;
struct semantic_info semantic = {0};
get_semantics(var, &semantic, s->info.stage);
mod->inputs[num_inputs].sysvalue = semantic.sysvalue_name;
nir_variable *base_var = var;
if (var->data.location_frac) {
/* Note: Specifically search for a variable that has space for these additional components */
nir_foreach_variable_with_modes(test_var, s, modes) {
if (var->data.location == test_var->data.location) {
/* Variables should be sorted such that we're only looking for an already-emitted variable */
if (test_var == var)
break;
base_var = test_var;
if (test_var->data.location_frac == 0 &&
glsl_get_component_slots(
nir_is_arrayed_io(test_var, s->info.stage) ?
glsl_get_array_element(test_var->type) : test_var->type) <= var->data.location_frac)
break;
}
}
}
if (base_var != var)
/* Combine fractional vars into any already existing row */
get_additional_semantic_info(s, var, &semantic,
mod->psv_inputs[mod->input_mappings[base_var->data.driver_location]].start_row,
input_clip_size);
else
*row_iter = get_additional_semantic_info(s, var, &semantic, *row_iter, input_clip_size);
mod->input_mappings[var->data.driver_location] = num_inputs;
struct dxil_psv_signature_element *psv_elm = &mod->psv_inputs[num_inputs];
if (!fill_io_signature(mod, num_inputs, &semantic,
&mod->inputs[num_inputs], psv_elm))
return 0;
mod->num_psv_inputs = MAX2(mod->num_psv_inputs,
semantic.start_row + semantic.rows);
++num_inputs;
assert(num_inputs < VARYING_SLOT_MAX * 4);
}
return num_inputs;
}
static void
process_input_signature(struct dxil_module *mod, nir_shader *s, unsigned input_clip_size)
{
if (s->info.stage == MESA_SHADER_KERNEL)
return;
unsigned next_row = 0;
mod->num_sig_inputs = get_input_signature_group(mod, 0,
s, nir_var_shader_in,
s->info.stage == MESA_SHADER_VERTEX ?
get_semantic_vs_in_name : get_semantic_in_name,
&next_row, input_clip_size);
mod->num_sig_inputs = get_input_signature_group(mod, mod->num_sig_inputs,
s, nir_var_system_value,
get_semantic_sv_name,
&next_row, input_clip_size);
}
static const char *out_sysvalue_name(nir_variable *var)
{
switch (var->data.location) {
case VARYING_SLOT_FACE:
return "FACE";
case VARYING_SLOT_POS:
return "POS";
case VARYING_SLOT_CLIP_DIST0:
case VARYING_SLOT_CLIP_DIST1:
return "CLIPDST";
case VARYING_SLOT_PRIMITIVE_ID:
return "PRIMID";
default:
return "NO";
}
}
static void
process_output_signature(struct dxil_module *mod, nir_shader *s)
{
unsigned num_outputs = 0;
unsigned next_row = 0;
nir_foreach_variable_with_modes(var, s, nir_var_shader_out) {
struct semantic_info semantic = {0};
if (var->data.patch)
continue;
if (s->info.stage == MESA_SHADER_FRAGMENT) {
get_semantic_ps_outname(var, &semantic);
mod->outputs[num_outputs].sysvalue = "TARGET";
} else {
const struct glsl_type *type = var->type;
if (nir_is_arrayed_io(var, s->info.stage))
type = glsl_get_array_element(type);
get_semantic_name(var, &semantic, type);
mod->outputs[num_outputs].sysvalue = out_sysvalue_name(var);
}
nir_variable *base_var = var;
if (var->data.location_frac) {
if (s->info.stage == MESA_SHADER_FRAGMENT) {
/* Fragment shader outputs are all either scalars, or must be declared as a single 4-component vector.
* Any attempt to declare partial vectors split across multiple variables is ignored.
*/
continue;
}
base_var = nir_find_variable_with_location(s, nir_var_shader_out, var->data.location);
}
if (base_var != var &&
base_var->data.stream == var->data.stream)
/* Combine fractional vars into any already existing row */
get_additional_semantic_info(s, var, &semantic,
mod->psv_outputs[mod->output_mappings[base_var->data.driver_location]].start_row,
s->info.clip_distance_array_size);
else
next_row = get_additional_semantic_info(s, var, &semantic, next_row, s->info.clip_distance_array_size);
mod->info.has_out_position |= semantic.kind== DXIL_SEM_POSITION;
mod->info.has_out_depth |= semantic.kind == DXIL_SEM_DEPTH;
mod->output_mappings[var->data.driver_location] = num_outputs;
struct dxil_psv_signature_element *psv_elm = &mod->psv_outputs[num_outputs];
if (!fill_io_signature(mod, num_outputs, &semantic,
&mod->outputs[num_outputs], psv_elm))
return;
for (unsigned i = 0; i < mod->outputs[num_outputs].num_elements; ++i) {
struct dxil_signature_element *elm = &mod->outputs[num_outputs].elements[i];
if (mod->minor_validator <= 4)
elm->never_writes_mask = 0xff & ~elm->mask;
else
/* This will be updated by the module processing */
elm->never_writes_mask = 0xf & ~elm->mask;
}
++num_outputs;
mod->num_psv_outputs[semantic.stream] = MAX2(mod->num_psv_outputs[semantic.stream],
semantic.start_row + semantic.rows);
}
mod->num_sig_outputs = num_outputs;
}
static const char *
patch_sysvalue_name(nir_variable *var)
{
switch (var->data.location) {
case VARYING_SLOT_TESS_LEVEL_OUTER:
switch (glsl_get_aoa_size(var->type)) {
case 4:
return "QUADEDGE";
case 3:
return "TRIEDGE";
case 2:
return var->data.location_frac == 0 ?
"LINEDET" : "LINEDEN";
default:
UNREACHABLE("Unexpected outer tess factor array size");
}
break;
case VARYING_SLOT_TESS_LEVEL_INNER:
switch (glsl_get_aoa_size(var->type)) {
case 2:
return "QUADINT";
case 1:
return "TRIINT";
default:
UNREACHABLE("Unexpected inner tess factory array size");
}
break;
default:
return "NO";
}
}
static void
process_patch_const_signature(struct dxil_module *mod, nir_shader *s)
{
if (s->info.stage != MESA_SHADER_TESS_CTRL &&
s->info.stage != MESA_SHADER_TESS_EVAL)
return;
nir_variable_mode mode = s->info.stage == MESA_SHADER_TESS_CTRL ?
nir_var_shader_out : nir_var_shader_in;
unsigned num_consts = 0;
unsigned next_row = 0;
nir_foreach_variable_with_modes(var, s, mode) {
struct semantic_info semantic = {0};
if (!var->data.patch)
continue;
const struct glsl_type *type = var->type;
get_semantic_name(var, &semantic, type);
mod->patch_consts[num_consts].sysvalue = patch_sysvalue_name(var);
nir_variable *base_var = var;
if (var->data.location_frac)
base_var = nir_find_variable_with_location(s, mode, var->data.location);
if (base_var != var)
/* Combine fractional vars into any already existing row */
get_additional_semantic_info(s, var, &semantic,
mod->psv_patch_consts[mod->patch_mappings[base_var->data.driver_location]].start_row,
0);
else
next_row = get_additional_semantic_info(s, var, &semantic, next_row, 0);
mod->patch_mappings[var->data.driver_location] = num_consts;
struct dxil_psv_signature_element *psv_elm = &mod->psv_patch_consts[num_consts];
if (!fill_io_signature(mod, num_consts, &semantic,
&mod->patch_consts[num_consts], psv_elm))
return;
if (mode == nir_var_shader_out) {
for (unsigned i = 0; i < mod->patch_consts[num_consts].num_elements; ++i) {
struct dxil_signature_element *elm = &mod->patch_consts[num_consts].elements[i];
if (mod->minor_validator <= 4)
elm->never_writes_mask = 0xff & ~elm->mask;
else
/* This will be updated by the module processing */
elm->never_writes_mask = 0xf & ~elm->mask;
}
}
++num_consts;
mod->num_psv_patch_consts = MAX2(mod->num_psv_patch_consts,
semantic.start_row + semantic.rows);
}
mod->num_sig_patch_consts = num_consts;
}
static void
prepare_dependency_tables(struct dxil_module *mod, nir_shader *s)
{
bool uses_view_id = BITSET_TEST(s->info.system_values_read, SYSTEM_VALUE_VIEW_INDEX);
uint32_t num_output_streams = s->info.stage == MESA_SHADER_GEOMETRY ? 4 : 1;
uint32_t num_tables = s->info.stage == MESA_SHADER_TESS_CTRL || s->info.stage == MESA_SHADER_TESS_EVAL ? 2 : num_output_streams;
const uint32_t output_vecs_per_dword = 32 /* bits per dword */ / 4 /* components per vec */;
const uint32_t masks_per_input_vec = 4 /* components per vec */;
for (uint32_t i = 0; i < num_output_streams; ++i)
mod->dependency_table_dwords_per_input[i] = DIV_ROUND_UP(mod->num_psv_outputs[i], output_vecs_per_dword);
if (s->info.stage == MESA_SHADER_TESS_CTRL)
mod->dependency_table_dwords_per_input[1] = DIV_ROUND_UP(mod->num_psv_patch_consts, output_vecs_per_dword);
uint32_t view_id_table_sizes[4] = { 0 };
if (uses_view_id) {
for (uint32_t i = 0; i < 4; ++i)
view_id_table_sizes[i] = mod->dependency_table_dwords_per_input[i];
}
for (uint32_t i = 0; i < num_output_streams; ++i)
mod->io_dependency_table_size[i] = mod->dependency_table_dwords_per_input[i] * mod->num_psv_inputs * masks_per_input_vec;
if (s->info.stage == MESA_SHADER_TESS_CTRL)
mod->io_dependency_table_size[1] = mod->dependency_table_dwords_per_input[1] * mod->num_psv_inputs * masks_per_input_vec;
else if (s->info.stage == MESA_SHADER_TESS_EVAL)
mod->io_dependency_table_size[1] = mod->dependency_table_dwords_per_input[0] * mod->num_psv_patch_consts * masks_per_input_vec;
mod->serialized_dependency_table_size = num_tables + 1;
for (uint32_t i = 0; i < num_tables; ++i) {
mod->serialized_dependency_table_size += view_id_table_sizes[i] + mod->io_dependency_table_size[i];
}
uint32_t *table = calloc(mod->serialized_dependency_table_size, sizeof(uint32_t));
mod->serialized_dependency_table = table;
*(table++) = mod->num_psv_inputs * 4;
for (uint32_t i = 0; i < num_output_streams; ++i) {
*(table++) = mod->num_psv_outputs[i] * 4;
mod->viewid_dependency_table[i] = table;
table += view_id_table_sizes[i];
mod->io_dependency_table[i] = table;
table += mod->io_dependency_table_size[i];
}
if (s->info.stage == MESA_SHADER_TESS_CTRL || s->info.stage == MESA_SHADER_TESS_EVAL) {
*(table++) = mod->num_psv_patch_consts * 4;
if (s->info.stage == MESA_SHADER_TESS_CTRL) {
mod->viewid_dependency_table[1] = table;
table += view_id_table_sizes[1];
}
mod->io_dependency_table[1] = table;
table += mod->io_dependency_table_size[1];
}
}
void
preprocess_signatures(struct dxil_module *mod, nir_shader *s, unsigned input_clip_size)
{
/* DXC does the same: Add an empty string before everything else */
mod->sem_string_table = _mesa_string_buffer_create(mod->ralloc_ctx, 1024);
copy_semantic_name_to_string(mod->sem_string_table, "");
process_input_signature(mod, s, input_clip_size);
process_output_signature(mod, s);
process_patch_const_signature(mod, s);
prepare_dependency_tables(mod, s);
}
static const struct dxil_mdnode *
get_signature_metadata(struct dxil_module *mod,
const struct dxil_signature_record *recs,
const struct dxil_psv_signature_element *psvs,
unsigned num_elements,
bool is_input)
{
if (num_elements == 0)
return NULL;
const struct dxil_mdnode *nodes[VARYING_SLOT_MAX * 4];
for (unsigned i = 0; i < num_elements; ++i) {
nodes[i] = fill_SV_param_nodes(mod, i, &recs[i], &psvs[i], is_input);
}
return dxil_get_metadata_node(mod, nodes, num_elements);
}
const struct dxil_mdnode *
get_signatures(struct dxil_module *mod)
{
const struct dxil_mdnode *input_signature = get_signature_metadata(mod, mod->inputs, mod->psv_inputs, mod->num_sig_inputs, true);
const struct dxil_mdnode *output_signature = get_signature_metadata(mod, mod->outputs, mod->psv_outputs, mod->num_sig_outputs, false);
const struct dxil_mdnode *patch_const_signature = get_signature_metadata(mod, mod->patch_consts, mod->psv_patch_consts, mod->num_sig_patch_consts,
mod->shader_kind == DXIL_DOMAIN_SHADER);
const struct dxil_mdnode *SV_nodes[3] = {
input_signature,
output_signature,
patch_const_signature
};
if (output_signature || input_signature || patch_const_signature)
return dxil_get_metadata_node(mod, SV_nodes, ARRAY_SIZE(SV_nodes));
else
return NULL;
}
+169
View File
@@ -0,0 +1,169 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DXIL_SIGNATURE_H
#define DXIL_SIGNATURE_H
#include "dxil_enums.h"
#include "nir.h"
#include "util/string_buffer.h"
#ifdef __cplusplus
extern "C" {
#endif
/* struct taken from DXILContainer
* Enums values were replaced by uint32_t since they must occupy 32 bit
*/
struct dxil_signature_element {
uint32_t stream; // Stream index (parameters must appear in non-decreasing stream order)
uint32_t semantic_name_offset; // Offset to char * stream from start of DxilProgramSignature.
uint32_t semantic_index; // Semantic Index
uint32_t system_value; // Semantic type. Similar to DxilSemantic::Kind, but a serialized rather than processing rep.
uint32_t comp_type; // Type of bits.
uint32_t reg; // Register Index (row index)
uint8_t mask; // Mask (column allocation)
union { // Unconditional cases useful for validation of shader linkage.
uint8_t never_writes_mask; // For an output signature, the shader the signature belongs to never
// writes the masked components of the output register.
uint8_t always_reads_mask; // For an input signature, the shader the signature belongs to always
// reads the masked components of the input register.
};
uint16_t pad;
uint32_t min_precision; // Minimum precision of input/output data
};
struct dxil_signature_record {
struct dxil_signature_element elements[32];
unsigned num_elements;
const char *sysvalue;
char *name;
uint8_t sig_comp_type;
};
struct dxil_psv_sem_index_table {
uint32_t data[128];
uint32_t size;
};
struct dxil_psv_signature_element {
uint32_t semantic_name_offset; // Offset into StringTable
uint32_t semantic_indexes_offset; // Offset into PSVSemanticIndexTable, count == Rows
uint8_t rows; // Number of rows this element occupies
uint8_t start_row; // Starting row of packing location if allocated
uint8_t cols_and_start; // 0:4 = Cols, 4:6 = StartCol, 6:7 == Allocated
uint8_t semantic_kind; // PSVSemanticKind
uint8_t component_type; // DxilProgramSigCompType
uint8_t interpolation_mode; // DXIL::InterpolationMode or D3D10_SB_INTERPOLATION_MODE
uint8_t dynamic_mask_and_stream; // 0:4 = DynamicIndexMask, 4:6 = OutputStream (0-3)
uint8_t reserved;
};
struct dxil_psv_runtime_info_0 {
union {
struct {
char output_position_present;
} vs;
struct {
uint32_t input_control_point_count;
uint32_t output_control_point_count;
uint32_t tessellator_domain;
uint32_t tessellator_output_primitive;
} hs;
struct {
uint32_t input_control_point_count;
char output_position_present;
uint32_t tessellator_domain;
} ds;
struct {
uint32_t input_primitive;
uint32_t output_toplology;
uint32_t output_stream_mask;
char output_position_present;
} gs;
struct {
char depth_output;
char sample_frequency;
} ps;
/* Maximum sized defining the union size (MSInfo)*/
struct {
uint32_t dummy1[3];
uint16_t dummy2[2];
} dummy;
};
uint32_t min_expected_wave_lane_count; // minimum lane count required, 0 if unused
uint32_t max_expected_wave_lane_count; // maximum lane count required, 0xffffffff if unused
};
struct dxil_psv_runtime_info_1 {
struct dxil_psv_runtime_info_0 psv0;
uint8_t shader_stage; // PSVShaderKind
uint8_t uses_view_id;
union {
uint16_t max_vertex_count; // MaxVertexCount for GS only (max 1024)
uint8_t sig_patch_const_or_prim_vectors; // Output for HS; Input for DS; Primitive output for MS (overlaps MS1::SigPrimVectors)
// struct { uint8_t dummy[2]; } fill;
};
// PSVSignatureElement counts
uint8_t sig_input_elements;
uint8_t sig_output_elements;
uint8_t sig_patch_const_or_prim_elements;
// Number of packed vectors per signature
uint8_t sig_input_vectors;
uint8_t sig_output_vectors[4];
};
struct dxil_psv_runtime_info_2 {
struct dxil_psv_runtime_info_1 psv1;
uint32_t num_threads_x;
uint32_t num_threads_y;
uint32_t num_threads_z;
};
struct dxil_psv_runtime_info_3 {
struct dxil_psv_runtime_info_2 psv2;
uint32_t entry_function_name;
};
struct dxil_mdnode;
struct dxil_module;
void
preprocess_signatures(struct dxil_module *mod, nir_shader *s, unsigned input_clip_size);
const struct dxil_mdnode *
get_signatures(struct dxil_module *mod);
#ifdef __cplusplus
}
#endif
#endif
+377
View File
@@ -0,0 +1,377 @@
#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;
}
+57
View File
@@ -0,0 +1,57 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DXIL_VALIDATOR_H
#define DXIL_VALIDATOR_H
#include "dxil_versions.h"
#include <stddef.h>
struct dxil_validator;
#ifdef __cplusplus
extern "C" {
#endif
struct dxil_validator *
dxil_create_validator(const void *ctx);
void
dxil_destroy_validator(struct dxil_validator *val);
bool
dxil_validate_module(struct dxil_validator *val, void *data,
size_t size, char **error);
char *
dxil_disasm_module(struct dxil_validator *val, void *data, size_t size);
enum dxil_validator_version
dxil_get_validator_version(struct dxil_validator *val);
#ifdef __cplusplus
}
#endif
#endif
+60
View File
@@ -0,0 +1,60 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DXIL_VERSIONS_H
#define DXIL_VERSIONS_H
#ifdef __cplusplus
extern "C" {
#endif
enum dxil_shader_model {
SHADER_MODEL_6_0 = 0x60000,
SHADER_MODEL_6_1,
SHADER_MODEL_6_2,
SHADER_MODEL_6_3,
SHADER_MODEL_6_4,
SHADER_MODEL_6_5,
SHADER_MODEL_6_6,
SHADER_MODEL_6_7,
SHADER_MODEL_6_8,
};
enum dxil_validator_version {
NO_DXIL_VALIDATION,
DXIL_VALIDATOR_1_0 = 0x10000,
DXIL_VALIDATOR_1_1,
DXIL_VALIDATOR_1_2,
DXIL_VALIDATOR_1_3,
DXIL_VALIDATOR_1_4,
DXIL_VALIDATOR_1_5,
DXIL_VALIDATOR_1_6,
DXIL_VALIDATOR_1_7,
DXIL_VALIDATOR_1_8,
};
#ifdef __cplusplus
}
#endif
#endif
+60
View File
@@ -0,0 +1,60 @@
# Copyright © Microsoft Corporation
# SPDX-License-Identifier: MIT
files_libdxil_compiler = files(
'dxil_buffer.c',
'dxil_container.c',
'dxil_dump.c',
'dxil_enums.c',
'dxil_function.c',
'dxil_module.c',
'dxil_nir.c',
'dxil_nir_lower_int_cubemaps.c',
'dxil_nir_lower_int_samplers.c',
'dxil_nir_lower_vs_vertex_conversion.c',
'dxil_signature.c',
'dxil_nir_tess.c',
'nir_to_dxil.c',
)
if host_machine.system() == 'windows'
files_libdxil_compiler += files('dxil_validator.cpp')
endif
dxil_nir_algebraic_c = custom_target(
'dxil_nir_algebraic.c',
input : 'dxil_nir_algebraic.py',
output : 'dxil_nir_algebraic.c',
command : [
prog_python, '@INPUT@', '-p', dir_compiler_nir,
],
capture : true,
depend_files : nir_algebraic_depends,
)
libdxil_compiler = static_library(
'dxil_compiler',
[files_libdxil_compiler, dxil_nir_algebraic_c, sha1_h],
include_directories : [inc_include, inc_src],
dependencies: [idep_nir_headers, dep_valgrind],
gnu_symbol_visibility : 'hidden',
)
idep_libdxil_compiler = declare_dependency(
link_with : libdxil_compiler,
dependencies : [idep_mesautil, dep_version],
include_directories : include_directories('.')
)
if with_tests
test(
'dxil_buffer',
executable(
'dxil_buffer_test',
files('dxil_buffer_test.c'),
include_directories : [inc_src],
dependencies : [idep_libdxil_compiler]
),
suite: 'd3d12'
)
endif
File diff suppressed because it is too large. Load diff
+116
View File
@@ -0,0 +1,116 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef NIR_TO_DXIL_H
#define NIR_TO_DXIL_H
#include <stdbool.h>
#include "nir.h"
#include "dxil_versions.h"
#ifdef __cplusplus
extern "C" {
#endif
struct blob;
/* Controls how resource decls/accesses are handled. Common to all:
* Images, textures, and samplers map to D3D UAV, SRV, and sampler types
* Shared is lowered to explicit I/O and then to a DXIL-specific intrinsic for 4-byte indices instead of byte addressing
* Input/output are lowered to dedicated intrinsics
*/
enum dxil_environment {
/* In the GL environment:
* Samplers/textures are lowered, vars/intrinsics use binding to refer to them; dynamic array indexing supported with offset srcs
* The lowering done by mesa/st assigns bindings from 0 -> N
* All other resource variables have driver_location set instead, assigned from 0 -> N
* UBOs may or may not have interface variables, and are declared from ubo_binding_offset -> num_ubos
* SSBOs may or may not have interface variables, and are declared from from 0 -> num_ssbos
* Images are *not* lowered, so that dynamic indexing can deterministically get a base binding via the deref chain
* TODO: Maybe support lowering and use nir_intrinsic_range_base to get the base
* No immediate constant buffer, or scratch
*/
DXIL_ENVIRONMENT_GL,
/* In the CL environment:
* Shader kind is always KERNEL
* All resources use binding for identification
* Samplers/textures/images are lowered; dynamic indexing not supported by spec
* UBOs are arrays of uints in the NIR
* SSBOs are implicitly declared via num_kernel_globals
* Variables of shader_temp are used to declare an immediate constant buffer, with load_ptr_dxil intrinsics to access it
* Scratch is supported and lowered to DXIL-specific intrinsics for scalar 32-bit access
*/
DXIL_ENVIRONMENT_CL,
/* In the Vulkan environment:
* All resources use binding / descriptor_set for identification
* Samplers/textures/images support two modes:
* 1. Derefs: deref chains are walked to emit the DXIL handle to the resource; dynamic indexing supported
* 2. Bindless: the resource source is assumed as an index into a descriptor heap
* UBOs/SSBOs are struct variables in the NIR, accessed via vulkan_resource_index/load_vulkan_descriptor; dynamic indexing supported
* If load_vulkan_descriptor gets an index that didn't come from vulkan_resource_index, it is assumed to be an index into a descriptor heap
* Read-only SSBOs, as declared in the SPIR-V, are bound as raw buffer SRVs instead of UAVs, unless they're lowered to bindless
* No immediate constant buffer or scratch
*/
DXIL_ENVIRONMENT_VULKAN,
};
struct nir_to_dxil_options {
bool interpolate_at_vertex;
bool lower_int16;
bool disable_math_refactoring;
bool last_ubo_is_not_arrayed;
bool advanced_texture_ops;
unsigned provoking_vertex;
unsigned num_kernel_globals;
unsigned input_clip_size;
enum dxil_environment environment;
enum dxil_shader_model shader_model_max;
enum dxil_validator_version validator_version_max;
};
typedef void (*dxil_msg_callback)(void *priv, const char *msg);
struct dxil_logger {
void *priv;
dxil_msg_callback log;
};
bool
nir_to_dxil(struct nir_shader *s, const struct nir_to_dxil_options *opts,
const struct dxil_logger *logger, struct blob *blob);
const nir_shader_compiler_options*
dxil_get_base_nir_compiler_options(void);
void
dxil_get_nir_compiler_options(nir_shader_compiler_options *options,
enum dxil_shader_model shader_model_max,
unsigned supported_int_sizes,
unsigned supported_float_sizes);
#ifdef __cplusplus
}
#endif
#endif