208 lines
5.1 KiB
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 */
|