Refresh/src/d3d11/Refresh_d3d11_d3dcompiler.c

208 lines
5.1 KiB
C

/* Refresh - a cross-platform hardware-accelerated graphics library with modern capabilities
*
* Copyright (c) 2020-2024 Evan Hemsley
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*
* Evan "cosmonaut" Hemsley <evan@moonside.games>
*
*/
#if REFRESH_D3D11
#include "Refresh_driver.h"
#define CINTERFACE
#define COBJMACROS
#include <d3dcompiler.h>
/* __stdcall declaration, largely taken from vkd3d_windows.h */
#ifdef _WIN32
#define D3DCOMPILER_API __stdcall
#else
# ifdef __stdcall
# undef __stdcall
# endif
# ifdef __x86_64__
# define __stdcall __attribute__((ms_abi))
# else
# if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2)) || defined(__APPLE__)
# define __stdcall __attribute__((__stdcall__)) __attribute__((__force_align_arg_pointer__))
# else
# define __stdcall __attribute__((__stdcall__))
# endif
# endif
# define D3DCOMPILER_API __stdcall
#endif
/* vkd3d uses stdcall for its ID3D10Blob implementation */
#ifndef _WIN32
typedef struct VKD3DBlob VKD3DBlob;
typedef struct VKD3DBlobVtbl
{
HRESULT(__stdcall* QueryInterface)(
VKD3DBlob* This,
REFIID riid,
void** ppvObject);
ULONG(__stdcall* AddRef)(VKD3DBlob* This);
ULONG(__stdcall* Release)(VKD3DBlob* This);
LPVOID(__stdcall* GetBufferPointer)(VKD3DBlob* This);
SIZE_T(__stdcall* GetBufferSize)(VKD3DBlob* This);
} VKD3DBlobVtbl;
struct VKD3DBlob
{
const VKD3DBlobVtbl* lpVtbl;
};
#define ID3D10Blob VKD3DBlob
#define ID3DBlob VKD3DBlob
#endif
/* rename the DLL for different platforms */
#if defined(WIN32)
#undef D3DCOMPILER_DLL
#define D3DCOMPILER_DLL D3DCOMPILER_DLL_A
#elif defined(__APPLE__)
#undef D3DCOMPILER_DLL
#define D3DCOMPILER_DLL "libvkd3d-utils.1.dylib"
#else
#undef D3DCOMPILER_DLL
#define D3DCOMPILER_DLL "libvkd3d-utils.so.1"
#endif
/* D3DCompile signature */
typedef HRESULT(D3DCOMPILER_API* PFN_D3DCOMPILE)(
LPCVOID pSrcData,
SIZE_T SrcDataSize,
LPCSTR pSourceName,
const D3D_SHADER_MACRO* pDefines,
ID3DInclude* pInclude,
LPCSTR pEntrypoint,
LPCSTR pTarget,
UINT Flags1,
UINT Flags2,
ID3DBlob** ppCode,
ID3DBlob** ppErrorMsgs
);
static void* d3dcompiler_dll;
static PFN_D3DCOMPILE D3DCompile_func;
#if 0 /* TODO */
static void D3D11_Quit(void)
{
if (d3dcompiler_dll) {
SDL_UnloadObject(d3dcompiler_dll);
}
d3dcompiler_dll = NULL;
D3DCompile_func = NULL;
}
#endif
extern Refresh_Shader* D3D11_CreateShader(
Refresh_Renderer *driverData,
Refresh_ShaderCreateInfo *shaderCreateInfo
);
Refresh_Shader* D3D11_CompileFromSPIRVCross(
Refresh_Renderer *driverData,
Refresh_ShaderStage shader_stage,
const char *entryPointName,
const char *source
) {
HRESULT result;
ID3DBlob *blob;
ID3DBlob *error_blob;
Refresh_ShaderCreateInfo createInfo;
Refresh_Shader *shader;
const char *profile;
/* FIXME: d3dcompiler could probably be loaded in a better spot */
/* Load the DLL if we haven't already */
if (!d3dcompiler_dll) {
d3dcompiler_dll = SDL_LoadObject(D3DCOMPILER_DLL);
if (!d3dcompiler_dll) {
SDL_SetError("Failed to load " D3DCOMPILER_DLL);
return NULL;
}
}
/* Load the D3DCompile function if we haven't already */
if (!D3DCompile_func) {
D3DCompile_func = (PFN_D3DCOMPILE) SDL_LoadFunction(d3dcompiler_dll, "D3DCompile");
if (!D3DCompile_func) {
SDL_SetError("Failed to load D3DCompile function");
return NULL;
}
}
if (shader_stage == REFRESH_SHADERSTAGE_VERTEX)
{
profile = "vs_5_0";
}
else if (shader_stage == REFRESH_SHADERSTAGE_FRAGMENT)
{
profile = "ps_5_0";
}
else if (shader_stage == REFRESH_SHADERSTAGE_COMPUTE)
{
profile = "cs_5_0";
}
else
{
SDL_SetError("%s", "Unrecognized shader stage!");
return NULL;
}
/* Compile! */
result = D3DCompile_func(
source,
SDL_strlen(source),
NULL,
NULL,
NULL,
"main", /* entry point name ignored */
profile,
0,
0,
&blob,
&error_blob
);
if (result < 0) {
SDL_SetError("%s", (const char*) ID3D10Blob_GetBufferPointer(error_blob));
ID3D10Blob_Release(error_blob);
return NULL;
}
/* Create the shader */
createInfo.code = ID3D10Blob_GetBufferPointer(blob);
createInfo.codeSize = ID3D10Blob_GetBufferSize(blob);
createInfo.format = REFRESH_SHADERFORMAT_DXBC;
createInfo.stage = shader_stage;
createInfo.entryPointName = entryPointName;
shader = D3D11_CreateShader(driverData, &createInfo);
/* Clean up */
ID3D10Blob_Release(blob);
return shader;
}
#endif /* REFRESH_D3D11 */