summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorEllie Hermaszewska <ellieh@nvidia.com>2023-04-29 11:32:53 +0800
committerGitHub <noreply@github.com>2023-04-29 11:32:53 +0800
commit5adecbe837d27cf4e0a554ae13a0338743a8cb4b (patch)
treec1e791427a2b57165f950f5df264bbaca551ccaf /tools
parent5df7ada451a993efff2b80bb1af2d8c7579ba00b (diff)
vkd3d and dxvk integration (#2823)
* Add d3d sources for linux builds * Return NOT_IMPLEMENTED for shared handle support on Linux * Enable DirectX api on Linux * Do not report DX11 support without FXC * Initial version of SynchAPI emulation * Neaten dx library name handling * Neaten and use posix-synchapi * Add premake option for DirectX on Vulkan * s/SLANG_ENABLE_VKD3D_PROTON/SLANG_ENABLE_VKD3D * Skip failing tests on vkd3d * Regenerate vs projects * Silence unused var warning
Diffstat (limited to 'tools')
-rw-r--r--tools/gfx-unit-test/copy-texture-tests.cpp11
-rw-r--r--tools/gfx/d3d/d3d-util.cpp24
-rw-r--r--tools/gfx/d3d11/d3d11-device.cpp6
-rw-r--r--tools/gfx/d3d12/d3d12-base.h1
-rw-r--r--tools/gfx/d3d12/d3d12-buffer.cpp4
-rw-r--r--tools/gfx/d3d12/d3d12-fence.cpp4
-rw-r--r--tools/gfx/d3d12/d3d12-posix-synchapi.cpp452
-rw-r--r--tools/gfx/d3d12/d3d12-posix-synchapi.h66
-rw-r--r--tools/gfx/d3d12/d3d12-texture.cpp4
9 files changed, 556 insertions, 16 deletions
diff --git a/tools/gfx-unit-test/copy-texture-tests.cpp b/tools/gfx-unit-test/copy-texture-tests.cpp
index 6a9d39d22..0129dd818 100644
--- a/tools/gfx-unit-test/copy-texture-tests.cpp
+++ b/tools/gfx-unit-test/copy-texture-tests.cpp
@@ -744,12 +744,23 @@ namespace gfx_test
template<typename T>
void copyTextureTestImpl(IDevice* device, UnitTestContext* context)
{
+ const bool isVkd3d = SLANG_ENABLE_VKD3D &&
+ strcmp(device->getDeviceInfo().apiName, "Direct3D 12") == 0;
+
// Skip Type::Unknown and Type::Buffer as well as Format::Unknown
// TODO: Add support for TextureCube
for (uint32_t i = 2; i < (uint32_t)ITextureResource::Type::_Count - 1; ++i)
{
for (uint32_t j = 1; j < (uint32_t)Format::_Count; ++j)
{
+ // Fails validation VUID-VkImageCreateInfo-imageCreateMaxMipLevels-02251
+ if(isVkd3d && ((Format)j == Format::R32G32B32_TYPELESS ||
+ (Format)j == Format::R32G32B32_FLOAT ||
+ (Format)j == Format::R32G32B32_UINT ||
+ (Format)j == Format::R32G32B32_SINT))
+ {
+ continue;
+ }
auto type = (ITextureResource::Type)i;
auto format = (Format)j;
auto validationFormat = getValidationTextureFormat(format);
diff --git a/tools/gfx/d3d/d3d-util.cpp b/tools/gfx/d3d/d3d-util.cpp
index aff610796..0257ede1b 100644
--- a/tools/gfx/d3d/d3d-util.cpp
+++ b/tools/gfx/d3d/d3d-util.cpp
@@ -431,15 +431,20 @@ bool D3DUtil::isTypeless(DXGI_FORMAT format)
static pD3DCompile compileFunc = nullptr;
if (!compileFunc)
{
+ // On Linux, vkd3d-utils isn't suitable as a unix replacement for fxc
+ // due to at least the following missing feature:
+ // https://bugs.winehq.org/show_bug.cgi?id=54872
+
// TODO(tfoley): maybe want to search for one of a few versions of the DLL
- HMODULE compilerModule = LoadLibraryA("d3dcompiler_47.dll");
- if (!compilerModule)
+ const char* const libName = "d3dcompiler_47";
+ SharedLibrary::Handle compilerModule;
+ if (SLANG_FAILED(SharedLibrary::load(libName, compilerModule)))
{
- fprintf(stderr, "error: failed load 'd3dcompiler_47.dll'\n");
+ fprintf(stderr, "error: failed to load '%s'\n", libName);
return SLANG_FAIL;
}
- compileFunc = (pD3DCompile)GetProcAddress(compilerModule, "D3DCompile");
+ compileFunc = (pD3DCompile)SharedLibrary::findSymbolAddressByName(compilerModule, "D3DCompile");
if (!compileFunc)
{
fprintf(stderr, "error: failed load symbol 'D3DCompile'\n");
@@ -488,17 +493,14 @@ bool D3DUtil::isTypeless(DXGI_FORMAT format)
/* static */SharedLibrary::Handle D3DUtil::getDxgiModule()
{
-#if SLANG_ENABLE_DXVK
- const char* const libPath = "dxvk_dxgi";
-#else
- const char* const libPath = "dxgi";
-#endif
+ const char* const libName = SLANG_ENABLE_DXVK ? "dxvk_dxgi" : "dxgi";
+
static SharedLibrary::Handle s_dxgiModule = [&](){
SharedLibrary::Handle h = nullptr;
- SharedLibrary::load(libPath, h);
+ SharedLibrary::load(libName, h);
if (!h)
{
- fprintf(stderr, "error: failed to load dll '%s'\n", libPath);
+ fprintf(stderr, "error: failed to load dll '%s'\n", libName);
}
return h;
}();
diff --git a/tools/gfx/d3d11/d3d11-device.cpp b/tools/gfx/d3d11/d3d11-device.cpp
index 4ab26725e..c10a608dc 100644
--- a/tools/gfx/d3d11/d3d11-device.cpp
+++ b/tools/gfx/d3d11/d3d11-device.cpp
@@ -47,11 +47,7 @@ SlangResult DeviceImpl::initialize(const Desc& desc)
// Rather than statically link against D3D, we load it dynamically.
SharedLibrary::Handle d3dModule;
-#if SLANG_ENABLE_DXVK
- const char* libName = "dxvk_d3d11";
-#else
- const char* libName = "d3d11";
-#endif
+ const char* libName = SLANG_ENABLE_DXVK ? "dxvk_d3d11" : "d3d11";
if (SLANG_FAILED(SharedLibrary::load(libName, d3dModule)))
{
fprintf(stderr, "error: failed to load '%s'\n", libName);
diff --git a/tools/gfx/d3d12/d3d12-base.h b/tools/gfx/d3d12/d3d12-base.h
index 52e8d4623..0e648f9c4 100644
--- a/tools/gfx/d3d12/d3d12-base.h
+++ b/tools/gfx/d3d12/d3d12-base.h
@@ -13,6 +13,7 @@
#include "core/slang-chunked-list.h"
#include "d3d12-descriptor-heap.h"
#include "d3d12-resource.h"
+#include "d3d12-posix-synchapi.h"
#pragma push_macro("WIN32_LEAN_AND_MEAN")
#pragma push_macro("NOMINMAX")
diff --git a/tools/gfx/d3d12/d3d12-buffer.cpp b/tools/gfx/d3d12/d3d12-buffer.cpp
index 42babfae6..7d3376607 100644
--- a/tools/gfx/d3d12/d3d12-buffer.cpp
+++ b/tools/gfx/d3d12/d3d12-buffer.cpp
@@ -35,6 +35,9 @@ Result BufferResourceImpl::getNativeResourceHandle(InteropHandle* outHandle)
Result BufferResourceImpl::getSharedHandle(InteropHandle* outHandle)
{
+#if !SLANG_WINDOWS_FAMILY
+ return SLANG_E_NOT_IMPLEMENTED;
+#else
// Check if a shared handle already exists for this resource.
if (sharedHandle.handleValue != 0)
{
@@ -51,6 +54,7 @@ Result BufferResourceImpl::getSharedHandle(InteropHandle* outHandle)
outHandle->api = InteropHandleAPI::D3D12;
sharedHandle = *outHandle;
return SLANG_OK;
+#endif
}
Result BufferResourceImpl::map(MemoryRange* rangeToRead, void** outPointer)
diff --git a/tools/gfx/d3d12/d3d12-fence.cpp b/tools/gfx/d3d12/d3d12-fence.cpp
index be3d94fcd..124d9354c 100644
--- a/tools/gfx/d3d12/d3d12-fence.cpp
+++ b/tools/gfx/d3d12/d3d12-fence.cpp
@@ -47,6 +47,9 @@ Result FenceImpl::setCurrentValue(uint64_t value)
Result FenceImpl::getSharedHandle(InteropHandle* outHandle)
{
+#if !SLANG_WINDOWS_FAMILY
+ return SLANG_E_NOT_IMPLEMENTED;
+#else
// Check if a shared handle already exists.
if (sharedHandle.handleValue != 0)
{
@@ -61,6 +64,7 @@ Result FenceImpl::getSharedHandle(InteropHandle* outHandle)
outHandle->api = InteropHandleAPI::D3D12;
sharedHandle = *outHandle;
return SLANG_OK;
+#endif
}
Result FenceImpl::getNativeHandle(InteropHandle* outNativeHandle)
diff --git a/tools/gfx/d3d12/d3d12-posix-synchapi.cpp b/tools/gfx/d3d12/d3d12-posix-synchapi.cpp
new file mode 100644
index 000000000..a46e96141
--- /dev/null
+++ b/tools/gfx/d3d12/d3d12-posix-synchapi.cpp
@@ -0,0 +1,452 @@
+#include "d3d12-posix-synchapi.h"
+
+#include "slang.h"
+
+#if SLANG_LINUX_FAMILY
+
+#include "core/slang-common.h"
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+#include <sys/poll.h>
+#include <sys/timerfd.h>
+#include <unistd.h>
+
+#include <cerrno>
+
+// To keep aligned with the d3d12 API, we store file descriptors in the low 32
+// bits of HANDLEs.
+static int _handleToFD(HANDLE h)
+{
+ auto i = reinterpret_cast<std::intptr_t>(h);
+ int fd = static_cast<int>(i);
+ return fd;
+}
+
+static int _handleToFlags(HANDLE h)
+{
+ auto i = reinterpret_cast<std::intptr_t>(h) >> 32;
+ int flags = static_cast<int>(i);
+ return flags;
+}
+
+static HANDLE _fdToHandle(int fd, int flags)
+{
+ static_assert(sizeof(int) <= 4);
+ static_assert(sizeof(std::intptr_t) >= 8);
+ return reinterpret_cast<HANDLE>(static_cast<std::intptr_t>(flags) << 32 | fd);
+}
+
+
+HANDLE CreateEventEx(
+ LPSECURITY_ATTRIBUTES lpEventAttributes,
+ LPCSTR lpName,
+ DWORD dwFlags,
+ DWORD dwDesiredAccess)
+{
+ int fd = ::eventfd(dwFlags & CREATE_EVENT_INITIAL_SET ? 1 : 0, EFD_CLOEXEC | EFD_NONBLOCK);
+ // Make sure not to return a zero handle, duplicate the fd if necessary
+ if(fd == 0)
+ {
+ int nextFd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
+ if(fcntl(nextFd, F_SETFL, O_NONBLOCK) == -1)
+ {
+ close(nextFd);
+ nextFd = -1;
+ }
+ close(fd);
+ fd = nextFd;
+ }
+ return fd == -1 ? nullptr : _fdToHandle(fd, dwFlags);
+}
+
+BOOL CloseHandle(HANDLE h)
+{
+ if(h == 0)
+ {
+ return 1;
+ }
+ // TODO: Windows does reference counting, how to, dupfd?
+ return ::close(_handleToFD(h)) == 0;
+ return 1;
+}
+
+BOOL ResetEvent(HANDLE h)
+{
+ int fd = _handleToFD(h);
+ pollfd pfd{fd, POLLIN, 0};
+ uint64_t x;
+ int r = 0;
+ int nEvents = poll(&pfd, 1, 0);
+ if(pfd.revents != POLLIN)
+ {
+ // Nothing to read, already reset
+ return 1;
+ }
+ if(nEvents != 1)
+ {
+ return 0;
+ }
+ r = read(fd, &x, sizeof(x));
+ if(r == sizeof(x))
+ {
+ // We reset it
+ return 1;
+ }
+ if(r == -1 && errno == EAGAIN)
+ {
+ // Something else reset it
+ return 1;
+ }
+ return 0;
+}
+
+BOOL SetEvent(HANDLE h)
+{
+ int fd = _handleToFD(h);
+ pollfd pfd{fd, POLLOUT, 0};
+ for(;;)
+ {
+ int nEvents = poll(&pfd, 1, -1);
+ SLANG_ASSERT(nEvents != -1);
+ SLANG_ASSERT(nEvents != 0); // shouldn't have timed out
+ const uint64_t one = 1;
+ int w = ::write(fd, &one, sizeof(one));
+ if(w == sizeof(one))
+ {
+ return 1;
+ }
+ if(errno != EAGAIN)
+ {
+ return 0;
+ }
+ }
+}
+
+DWORD WaitForSingleObject(HANDLE h, DWORD ms)
+{
+ int fd = _handleToFD(h);
+ bool manualReset = _handleToFlags(h) & CREATE_EVENT_MANUAL_RESET;
+ pollfd pfd{fd, POLLIN, 0};
+ uint64_t x;
+ int r = 0;
+ int nEvents = poll(&pfd, 1, ms);
+ if(pfd.revents != POLLIN)
+ {
+ return WAIT_FAILED;
+ }
+ if(nEvents == -1)
+ {
+ return WAIT_FAILED;
+ }
+ if (nEvents == 0)
+ {
+ return WAIT_TIMEOUT;
+ }
+ if(manualReset)
+ {
+ return WAIT_OBJECT_0;
+ }
+ r = read(fd, &x, sizeof(x));
+ if(r == sizeof(x))
+ {
+ return WAIT_OBJECT_0;
+ }
+ if(r == -1 && errno == EAGAIN)
+ {
+ return WAIT_TIMEOUT;
+ }
+ return WAIT_FAILED;
+}
+
+DWORD WaitForMultipleObjects(
+ DWORD n,
+ const HANDLE *hs,
+ BOOL bWaitAll,
+ DWORD dwMilliseconds)
+{
+ if(n == 0)
+ {
+ return bWaitAll ? WAIT_OBJECT_0 : WAIT_FAILED;
+ }
+ DWORD res;
+ int fds[n];
+ int flagss[n];
+ epoll_event evs[n+1]; // +1 for our timer
+ int ufd = -1;
+ int epfd = epoll_create1(EPOLL_CLOEXEC);
+ if(epfd == -1)
+ {
+ goto fail;
+ }
+
+ for(int i = 0; i < n; ++i)
+ {
+ fds[i] = _handleToFD(hs[i]);
+ flagss[i] = _handleToFlags(hs[i]);
+ epoll_event ev;
+ ev.data.fd = fds[i];
+ ev.events = EPOLLIN | EPOLLONESHOT;
+ if(epoll_ctl(epfd, EPOLL_CTL_ADD, fds[i], &ev) == -1)
+ {
+ goto fail;
+ }
+ }
+
+ // The wait all case can't be made correct on linux, as we can't atomically
+ // read from several fds and eventfd is the interface available from
+ // vkd3d-proton.
+ //
+ // As a best-effort we wait until they're all free, then grab them on one
+ // after the other, and put the values back if we can't claim them all, it
+ // sucks.
+ //
+ if(bWaitAll)
+ {
+ // Use a timer to easily know for sure when we've timed out
+ if(dwMilliseconds != INFINITE)
+ {
+ ufd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
+ if(ufd == -1)
+ {
+ goto fail;
+ }
+ itimerspec spec;
+ spec.it_interval.tv_sec = 0;
+ spec.it_interval.tv_nsec = 0;
+ spec.it_value.tv_sec = 0;
+ spec.it_value.tv_nsec = 1000000 * dwMilliseconds;
+ if(timerfd_settime(ufd, 0, &spec, nullptr) == -1)
+ {
+ goto fail;
+ }
+ evs[n].data.fd = ufd;
+ evs[n].events = EPOLLIN | EPOLLONESHOT;
+ if(epoll_ctl(epfd, EPOLL_CTL_ADD, ufd, &evs[n]) == -1)
+ {
+ goto fail;
+ }
+ }
+
+ bool timesUp = false;
+ int nSeenEvents = 0;
+ // Repeatedly call epoll_wait to eliminate read fds until the timer
+ // expires or we have elimininated all our fds
+ do
+ {
+ do
+ {
+ // Wait until epoll tells us they're all available, or the timer is
+ const int nEvents = epoll_wait(epfd, evs, n+1, -1);
+ // We didn't specify a timeout, so 0 results is abnormal
+ if(nEvents < 1)
+ {
+ goto fail;
+ }
+
+ // Process all the returned fds
+ for(int i = 0; i < nEvents; ++i)
+ {
+ if(!(evs[i].events & EPOLLIN))
+ {
+ // Something exceptional happened on the fd
+ // Possibly we could just continue and hope it doesn't
+ // happen again?
+ goto fail;
+ }
+ if(evs[i].data.fd == ufd)
+ {
+ // We're out of time, make this the last loop
+ uint64_t x;
+ int r = read(ufd, &x, sizeof(x));
+ if(r == sizeof(x))
+ {
+ timesUp = true;
+ }
+ else
+ {
+ goto fail;
+ }
+ }
+ else
+ {
+ // EPOLLONESHOT has removed this fd
+ ++nSeenEvents;
+ }
+ }
+ }
+ while(!(timesUp || nSeenEvents == n));
+
+ // If we got here without seeing enough events, we must have timed out
+ if(nSeenEvents < n)
+ {
+ res = WAIT_TIMEOUT;
+ goto end;
+ }
+
+ // See if all the events are readable.
+ // This isn't strictly necessary from a correctness point of view,
+ // but since we're not correct anything we can do helps, and it
+ // makes the code a bit cleaner.
+ // Put all the events back in our epoll instance and see if they're
+ // all readable.
+ for(int i = 0; i < n; ++i)
+ {
+ epoll_event modEv;
+ modEv.data.fd = fds[i];
+ modEv.events = EPOLLIN | EPOLLONESHOT;
+ if(epoll_ctl(epfd, EPOLL_CTL_MOD, fds[i], &modEv) == -1)
+ {
+ goto fail;
+ }
+ }
+ // Remove the timer if we're using it
+ if(dwMilliseconds != INFINITE && epoll_ctl(epfd, EPOLL_CTL_DEL, ufd, nullptr) == -1)
+ {
+ goto fail;
+ }
+ int nEvents = epoll_wait(epfd, evs, n, 0);
+ if(nEvents < 0)
+ {
+ goto fail;
+ }
+ else if(nEvents < n)
+ {
+ // They're not all still available :(
+ // Put our timer back in and try again from the top
+ if(dwMilliseconds != INFINITE && epoll_ctl(epfd, EPOLL_CTL_ADD, ufd, &evs[n]) == -1)
+ {
+ goto fail;
+ }
+ // Put back the any fds which did trigger
+ for(int i = 0; i < nEvents; ++i)
+ {
+ epoll_event modEv = evs[i];
+ modEv.events = EPOLLIN | EPOLLONESHOT;
+ if(epoll_ctl(epfd, EPOLL_CTL_MOD, modEv.data.fd, &modEv) == -1)
+ {
+ goto fail;
+ }
+ }
+ continue;
+ }
+ else if(nEvents == n)
+ {
+ for(int i = 0; i < nEvents; ++i)
+ {
+ if(!(evs->events & EPOLLIN))
+ {
+ goto fail;
+ }
+ }
+ }
+
+ // Try to grab all the events
+ uint64_t vs[n];
+ int i;
+ bool failure = false;
+ for(i = 0; i < n; ++i)
+ {
+ if(flagss[i] & CREATE_EVENT_MANUAL_RESET)
+ {
+ // We don't need to read this to unset it
+ continue;
+ }
+ int r = read(fds[i], &vs[i], sizeof(vs[i]));
+ if(r == sizeof(vs[i]))
+ {
+ continue;
+ }
+ else if(r == -1 && errno == EAGAIN)
+ {
+ // contention, put things back and try again
+ break;
+ }
+ else
+ {
+ // failure, put things back and fail
+ failure = true;
+ break;
+ }
+ }
+ if (i < n)
+ {
+ // contention or failure
+ for(int j = 0; j < i; ++j)
+ {
+ if(flagss[i] & CREATE_EVENT_MANUAL_RESET)
+ {
+ // We didn't read, so we shouldn't write
+ continue;
+ }
+ // TODO: If this doesn't succeed then another thread has jumped
+ // in between our non-atomic reads earlier, oops!
+ //
+ // This is just one case of failure we can detect,
+ // arbitrarily many things may have happened between reads
+ // and we just wouldn't know...
+ int w = write(fds[j], &vs[j], sizeof(vs[j]));
+ SLANG_ASSERT(w == sizeof(vs[j]));
+ }
+ if(failure)
+ {
+ goto fail;
+ }
+ }
+ else
+ {
+ // success
+ res = WAIT_OBJECT_0;
+ goto end;
+ }
+
+ // If we get here then we've got some contention, go back to the top and try again (or timeout)
+ }
+ while(!timesUp);
+ }
+ else
+ {
+ // Wait any
+ const int nEvents = epoll_wait(epfd, evs, n, dwMilliseconds == INFINITE ? -1 : dwMilliseconds);
+ if(nEvents == -1)
+ {
+ goto fail;
+ }
+ if(nEvents == 0)
+ {
+ res = WAIT_TIMEOUT;
+ goto end;
+ }
+ // Try reads until we get one
+ for(int i = 0; i < nEvents; ++i)
+ {
+ uint64_t x;
+ if(!evs[i].events & EPOLLIN)
+ {
+ continue;
+ }
+ const int r = ::read(evs[i].data.fd, &x, sizeof(x));
+ if (r == sizeof(x))
+ {
+ res = WAIT_OBJECT_0;
+ goto end;
+ }
+ if (errno != EAGAIN)
+ {
+ goto fail;
+ }
+ // Some other waiter got this one first
+ }
+ }
+
+ goto end;
+fail:
+ res = WAIT_FAILED;
+end:
+ close(ufd);
+ close(epfd);
+ return res;
+}
+
+#endif // SLANG_LINUX_FAMILY
diff --git a/tools/gfx/d3d12/d3d12-posix-synchapi.h b/tools/gfx/d3d12/d3d12-posix-synchapi.h
new file mode 100644
index 000000000..fb556fb51
--- /dev/null
+++ b/tools/gfx/d3d12/d3d12-posix-synchapi.h
@@ -0,0 +1,66 @@
+#pragma once
+
+#include "slang.h"
+
+#if SLANG_LINUX_FAMILY
+
+#pragma push_macro("WIN32_LEAN_AND_MEAN")
+#pragma push_macro("NOMINMAX")
+#undef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#undef NOMINMAX
+#define NOMINMAX
+#include <windows.h>
+#pragma pop_macro("NOMINMAX")
+#pragma pop_macro("WIN32_LEAN_AND_MEAN")
+
+////////////////////////////////////////////////////////////////
+//
+// It's important to note that due to platform constraints this can't be a
+// totally faithful implementation of the Windows API.
+//
+// Notably, the "wait all" case in WaitForMultipleObjects can't be made correct
+// on linux, as we can't atomically read from several fds and eventfd is the
+// interface available from vkd3d-proton.
+//
+////////////////////////////////////////////////////////////////
+
+//
+// The synchapi types and macros used in gfx
+//
+#define INFINITE 0xffffffff
+
+#define WAIT_FAILED 0xffffffff
+#define WAIT_OBJECT_0 0
+#define WAIT_TIMEOUT 258
+
+typedef struct _SECURITY_ATTRIBUTES *LPSECURITY_ATTRIBUTES;
+
+#define CREATE_EVENT_MANUAL_RESET 1
+#define CREATE_EVENT_INITIAL_SET 2
+
+#define SYNCHRONIZE 0x00100000
+#define STANDARD_RIGHTS_REQUIRED 0x000f0000
+#define EVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3)
+
+HANDLE CreateEventEx(
+ LPSECURITY_ATTRIBUTES lpEventAttributes,
+ LPCSTR lpName,
+ DWORD dwFlags,
+ DWORD dwDesiredAccess);
+
+BOOL CloseHandle(HANDLE h);
+
+BOOL ResetEvent(HANDLE h);
+
+BOOL SetEvent(HANDLE h);
+
+DWORD WaitForSingleObject(HANDLE h, DWORD ms);
+
+DWORD WaitForMultipleObjects(
+ DWORD nHandles,
+ const HANDLE *handles,
+ BOOL bWaitAll,
+ DWORD dwMilliseconds);
+
+#endif // SLANG_LINUX_FAMILY
diff --git a/tools/gfx/d3d12/d3d12-texture.cpp b/tools/gfx/d3d12/d3d12-texture.cpp
index 4f1898ef7..9f47760e5 100644
--- a/tools/gfx/d3d12/d3d12-texture.cpp
+++ b/tools/gfx/d3d12/d3d12-texture.cpp
@@ -30,6 +30,9 @@ Result TextureResourceImpl::getNativeResourceHandle(InteropHandle* outHandle)
Result TextureResourceImpl::getSharedHandle(InteropHandle* outHandle)
{
+#if !SLANG_WINDOWS_FAMILY
+ return SLANG_E_NOT_IMPLEMENTED;
+#else
// Check if a shared handle already exists for this resource.
if (sharedHandle.handleValue != 0)
{
@@ -45,6 +48,7 @@ Result TextureResourceImpl::getSharedHandle(InteropHandle* outHandle)
pResource, NULL, GENERIC_ALL, nullptr, (HANDLE*)&outHandle->handleValue));
outHandle->api = InteropHandleAPI::D3D12;
return SLANG_OK;
+#endif
}
Result TextureResourceImpl::setDebugName(const char* name)