mirror of
https://github.com/elwrcl/intel-hard-graphics.git
synced 2026-11-01 03:18:02 +03:00
init
This commit is contained in:
12511 files changed
+6156641
No files matched your search
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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"
|
||||
};
|
||||
@@ -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];
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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, ¶ms);
|
||||
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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
Reference in new issue
Block a user