Skip to content

Commit

Permalink
Update to zig 2024.10 and Add new build options and shader inclusion …
Browse files Browse the repository at this point in the history
…overrides (#7)

* Added shared library build option
* build now supports SPIR-V codegen
* Fixed occasional segfault when including files with spir-v targets.
* Added file inclusion handlers.
* Compile arguments have been condensed into struct
* Moved spirv-tools to external dependency
* update to Zig 2024.10
---------

Co-authored-by: Sinnwrig <[email protected]>
Co-authored-by: sinnwrig <[email protected]>
Co-authored-by: Kai Angulo <[email protected]>
Co-authored-by: Ronald M Zielaznicki <[email protected]>
  • Loading branch information
5 people authored Oct 16, 2024
1 parent f08356c commit 92e9846
Show file tree
Hide file tree
Showing 7 changed files with 607 additions and 183 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
# -andrewrk

.zig-cache/
zig-cache/
zig-out/
/release/
/debug/
Expand Down
627 changes: 460 additions & 167 deletions build.zig

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,11 @@
"README.md",
"update.sh",
},
.dependencies = .{},
.dependencies = .{
.@"spirv-tools" = .{
.url = "https://pkg.machengine.org/spirv-tools/5d14d57d0cf8709f5ea155b32eccccd3cbcb7dca.tar.gz",
.hash = "1220cb3152f957ad886b0eff7468e4c6580b1461c4c3d0c5d4e6848dd76b1ed7123e",
.lazy = true,
},
},
}
102 changes: 92 additions & 10 deletions src/mach_dxc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,88 @@
#include <dxcapi.h>
#include <cassert>
#include <stddef.h>
#include <string>

#include "mach_dxc.h"

#ifdef __cplusplus
extern "C" {
#endif

// Dynamic allocation for multibyte string conversion.
char* wcstombsAlloc(const wchar_t* inval)
{
size_t size = std::wcslen(inval);
size_t outsz = (size + 1) * MB_CUR_MAX;

auto buf = (char*)std::malloc(outsz);
std::memset(buf, 0, outsz);
std::setlocale(LC_CTYPE,"");
size = std::wcstombs(buf, inval, size * sizeof(wchar_t));

if (size == (size_t)(-1)) {
std::free(buf);
buf = nullptr;
} else {
buf = (char*)std::realloc(buf, size + 1);
}

return buf;
}

// Provides a way for C applications to override file inclusion by offloading it to a function pointer
class MachDxcIncludeHandler : public IDxcIncludeHandler
{
public:
ULONG STDMETHODCALLTYPE AddRef() override { return 0; }
ULONG STDMETHODCALLTYPE Release() override { return 0; }

HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override {
if (riid == __uuidof(IDxcIncludeHandler) || riid == __uuidof(IUnknown)) {
*ppvObject = this;
return S_OK;
}
*ppvObject = nullptr;
return E_NOINTERFACE;
}

MachDxcIncludeCallbacks* callbacks;
IDxcUtils* utils;

MachDxcIncludeHandler(MachDxcIncludeCallbacks* callbacks_ptr, IDxcUtils* util_ptr) {
callbacks = callbacks_ptr;
utils = util_ptr;
}

HRESULT STDMETHODCALLTYPE LoadSource(LPCWSTR filename, IDxcBlob **ppIncludeSource) override {
if (callbacks->include_func == nullptr || callbacks->free_func == nullptr)
return E_POINTER;

char* filename_utf8 = wcstombsAlloc(filename);

if (filename_utf8 == nullptr)
filename_utf8 = strdup(u8"");

MachDxcIncludeResult* include_result = callbacks->include_func(callbacks->include_ctx, filename_utf8);

std::free(filename_utf8);

const char* include_text = include_result != nullptr && include_result->header_data != nullptr ? include_result->header_data : u8"";
size_t include_len = include_result != nullptr ? include_result->header_length : 0;

CComPtr<IDxcBlobEncoding> text_blob;
HRESULT result = utils->CreateBlob(include_text, include_len, CP_UTF8, &text_blob);

if (SUCCEEDED(result))
*ppIncludeSource = text_blob.Detach();

callbacks->free_func(callbacks->include_ctx, include_result);

return S_OK;
}
};


// Mach change start: static dxcompiler/dxil
BOOL MachDxcompilerInvokeDllMain();
void MachDxcompilerInvokeDllShutdown();
Expand All @@ -46,53 +121,60 @@ MACH_EXPORT void machDxcDeinit(MachDxcCompiler compiler) {
MachDxcompilerInvokeDllShutdown();
}


//---------------------
// MachDxcCompileResult
//---------------------
MACH_EXPORT MachDxcCompileResult machDxcCompile(
MachDxcCompiler compiler,
char const* code,
size_t code_len,
char const* const* args,
size_t args_len
MachDxcCompileOptions* options
) {
CComPtr<IDxcCompiler3> dxcInstance = CComPtr(reinterpret_cast<IDxcCompiler3*>(compiler));

CComPtr<IDxcUtils> pUtils;
DxcCreateInstance(CLSID_DxcUtils, IID_PPV_ARGS(&pUtils));
CComPtr<IDxcBlobEncoding> pSource;
pUtils->CreateBlob(code, code_len, CP_UTF8, &pSource);
pUtils->CreateBlob(options->code, options->code_len, CP_UTF8, &pSource);

DxcBuffer sourceBuffer;
sourceBuffer.Ptr = pSource->GetBufferPointer();
sourceBuffer.Size = pSource->GetBufferSize();
sourceBuffer.Encoding = 0;

// We have args in char form, but dxcInstance->Compile expects wchar_t form.
LPCWSTR* arguments = (LPCWSTR*)malloc(sizeof(LPCWSTR) * args_len);
LPCWSTR* arguments = (LPCWSTR*)malloc(sizeof(LPCWSTR) * options->args_len);
wchar_t* wtext_buf = (wchar_t*)malloc(4096);
wchar_t* wtext_cursor = wtext_buf;
assert(arguments);
assert(wtext_buf);

for (int i=0; i < args_len; i++) {
for (int i=0; i < options->args_len; i++) {
size_t available = 4096 / sizeof(wchar_t) - (wtext_cursor - wtext_buf);
size_t written = std::mbstowcs(wtext_cursor, args[i], available);
size_t written = std::mbstowcs(wtext_cursor, options->args[i], available);
arguments[i] = wtext_cursor;
wtext_cursor += written + 1;
}

MachDxcIncludeHandler* handler = nullptr;
if (options->include_callbacks != nullptr) // Leave include handler as default (nullptr) unless there's available callbacks
handler = new MachDxcIncludeHandler(options->include_callbacks, pUtils);

CComPtr<IDxcResult> pCompileResult;
HRESULT hr = dxcInstance->Compile(
&sourceBuffer,
arguments,
(uint32_t)args_len,
nullptr,
(uint32_t)options->args_len,
handler,
IID_PPV_ARGS(&pCompileResult)
);

if (handler != nullptr)
delete handler;

assert(SUCCEEDED(hr));
free(arguments);
free(wtext_buf);

return reinterpret_cast<MachDxcCompileResult>(pCompileResult.Detach());
}

Expand Down
34 changes: 30 additions & 4 deletions src/mach_dxc.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,35 @@ typedef struct MachDxcCompileResultImpl* MachDxcCompileResult MACH_OBJECT_ATTRIB
typedef struct MachDxcCompileErrorImpl* MachDxcCompileError MACH_OBJECT_ATTRIBUTE;
typedef struct MachDxcCompileObjectImpl* MachDxcCompileObject MACH_OBJECT_ATTRIBUTE;


typedef struct MachDxcIncludeResult {
const char* header_data; // UTF-8 or null
size_t header_length;
} MachDxcIncludeResult;

typedef MachDxcIncludeResult* (*MachDxcIncludeFunc)(void* ctx, const char* header_name);

typedef int (*MachDxcFreeIncludeFunc)(void* ctx, MachDxcIncludeResult* result);

typedef struct MachDxcIncludeCallbacks {
void* include_ctx;
MachDxcIncludeFunc include_func;
MachDxcFreeIncludeFunc free_func;
} MachDxcIncludeCallbacks;


typedef struct MachDxcCompileOptions {
// Required
char const* code;
size_t code_len;
char const* const* args;
size_t args_len;

// Optional
MachDxcIncludeCallbacks* include_callbacks; // nullable
} MachDxcCompileOptions;


//----------------
// MachDxcCompiler
//----------------
Expand All @@ -55,10 +84,7 @@ MACH_EXPORT void machDxcDeinit(MachDxcCompiler compiler);
/// Invoke machDxcCompileResultDeinit when done with the result.
MACH_EXPORT MachDxcCompileResult machDxcCompile(
MachDxcCompiler compiler,
char const* code,
size_t code_len,
char const* const* args,
size_t args_len
MachDxcCompileOptions* options
);

/// Returns an error object, or null in the case of success.
Expand Down
10 changes: 9 additions & 1 deletion src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,15 @@ pub const Compiler = struct {
}

pub fn compile(compiler: Compiler, code: []const u8, args: []const [*:0]const u8) Result {
const result = c.machDxcCompile(compiler.handle, code.ptr, code.len, args.ptr, args.len);
var options: c.MachDxcCompileOptions = .{
.code = code.ptr,
.code_len = code.len,
.args = args.ptr,
.args_len = args.len,
.include_callbacks = null,
};

const result = c.machDxcCompile(compiler.handle, @ptrCast(&options));
return .{ .handle = result };
}

Expand Down
8 changes: 8 additions & 0 deletions src/shared_main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include "mach_dxc.h"

int main(void)
{
MachDxcCompiler comp = machDxcInit();
machDxcDeinit(comp);
}

0 comments on commit 92e9846

Please sign in to comment.