diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 60efb64033..e5687df19a 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -1908,7 +1908,8 @@ else() list(APPEND onnxruntime_EXTERNAL_LIBRARIES ${CMAKE_DL_LIBS} Threads::Threads) endif() -if (WIN32) +# When GDK_PLATFORM is set then WINAPI_FAMILY is defined in gdk_toolchain.cmake (along with other relevant flags/definitions). +if (WIN32 AND NOT GDK_PLATFORM) add_compile_definitions(WINAPI_FAMILY=100) # Desktop app if (onnxruntime_USE_WINML) add_compile_definitions(WINVER=0x0602 _WIN32_WINNT=0x0602 NTDDI_VERSION=0x06020000) # Support Windows 8 and newer diff --git a/cmake/external/abseil-cpp.cmake b/cmake/external/abseil-cpp.cmake index 98276ef4af..80a48284c9 100644 --- a/cmake/external/abseil-cpp.cmake +++ b/cmake/external/abseil-cpp.cmake @@ -24,6 +24,12 @@ FetchContent_Declare( FetchContent_MakeAvailable(abseil_cpp) FetchContent_GetProperties(abseil_cpp SOURCE_DIR) - +if (GDK_PLATFORM) + # Abseil considers any partition that is NOT in the WINAPI_PARTITION_APP a viable platform + # for Win32 symbolize code (which depends on dbghelp.lib); this logic should really be flipped + # to only include partitions that are known to support it (e.g. DESKTOP). As a workaround we + # tell Abseil to pretend we're building an APP. + target_compile_definitions(absl_symbolize PRIVATE WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP) +endif() diff --git a/cmake/gdk_toolchain.cmake b/cmake/gdk_toolchain.cmake new file mode 100644 index 0000000000..9780f6680d --- /dev/null +++ b/cmake/gdk_toolchain.cmake @@ -0,0 +1,91 @@ +# Options to configure the toolchain. +set(GDK_EDITION 210602 CACHE STRING "GDK edition.") +set(GDK_PLATFORM Scarlett CACHE STRING "GDK target platform.") + +# Required to propagate variables when CMake calls try_compile() to test the toolchain. +# https://cmake.org/cmake/help/latest/variable/CMAKE_TRY_COMPILE_PLATFORM_VARIABLES.html +set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES GDK_EDITION GDK_PLATFORM) + +cmake_path(SET gdk_gxdk_path $ENV{GameDK}/${GDK_EDITION}/GXDK NORMALIZE) + +# Set C/C++ compile flags and additional include directories. +foreach(lang C CXX) + set(CMAKE_${lang}_FLAGS_INIT "") + string(APPEND CMAKE_${lang}_FLAGS_INIT + " /D_GAMING_XBOX" + " /DWINAPI_FAMILY=WINAPI_FAMILY_GAMES" + " /D_ATL_NO_DEFAULT_LIBS" + " /D__WRL_NO_DEFAULT_LIB__" + " /D__WRL_CLASSIC_COM_STRICT__" + " /D_CRT_USE_WINAPI_PARTITION_APP" + " /DWIN32_LEAN_AND_MEAN" + " /favor:AMD64" + ) + + if(GDK_PLATFORM STREQUAL Scarlett) + string(APPEND CMAKE_${lang}_FLAGS_INIT " /D_GAMING_XBOX_SCARLETT /arch:AVX2") + elseif(GDK_PLATFORM STREQUAL XboxOne) + string(APPEND CMAKE_${lang}_FLAGS_INIT " /D_GAMING_XBOX_XBOXONE /arch:AVX") + endif() + + set(CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES ${gdk_gxdk_path}/gameKit/Include/${GDK_PLATFORM}) + + set(CMAKE_${lang}_STANDARD_LIBRARIES "onecoreuap_apiset.lib" CACHE STRING "" FORCE) +endforeach() + +# It's best to avoid inadvertently linking with any libraries not present in the OS. +list(APPEND nodefault_libs + advapi32.lib + comctl32.lib + comsupp.lib + dbghelp.lib + gdi32.lib + gdiplus.lib + guardcfw.lib + kernel32.lib + mmc.lib + msimg32.lib + msvcole.lib + msvcoled.lib + mswsock.lib + ntstrsafe.lib + ole2.lib + ole2autd.lib + ole2auto.lib + ole2d.lib + ole2ui.lib + ole2uid.lib + ole32.lib + oleacc.lib + oleaut32.lib + oledlg.lib + oledlgd.lib + oldnames.lib + runtimeobject.lib + shell32.lib + shlwapi.lib + strsafe.lib + urlmon.lib + user32.lib + userenv.lib + wlmole.lib + wlmoled.lib + onecore.lib +) + +foreach(link_type EXE SHARED MODULE) + set(CMAKE_${link_type}_LINKER_FLAGS_INIT "") + foreach(lib ${nodefault_libs}) + string(APPEND CMAKE_${link_type}_LINKER_FLAGS_INIT " /NODEFAULTLIB:${lib}") + endforeach() + string(APPEND CMAKE_${link_type}_LINKER_FLAGS_INIT " /DYNAMICBASE /NXCOMPAT /MANIFEST:NO") +endforeach() + +set(gdk_dx_libs ${gdk_gxdk_path}/gameKit/lib/amd64/PIXEvt.lib) +if(GDK_PLATFORM STREQUAL Scarlett) + list(APPEND gdk_dx_libs ${gdk_gxdk_path}/gameKit/lib/amd64/Scarlett/d3d12_xs.lib) + list(APPEND gdk_dx_libs ${gdk_gxdk_path}/gameKit/lib/amd64/Scarlett/xg_xs.lib) +elseif(GDK_PLATFORM STREQUAL XboxOne) + list(APPEND gdk_dx_libs ${gdk_gxdk_path}/gameKit/lib/amd64/XboxOne/d3d12_x.lib) + list(APPEND gdk_dx_libs ${gdk_gxdk_path}/gameKit/lib/amd64/XboxOne/xg_x.lib) +endif() \ No newline at end of file diff --git a/cmake/onnxruntime_flatbuffers.cmake b/cmake/onnxruntime_flatbuffers.cmake index fa024d0c5c..b9d97c962d 100644 --- a/cmake/onnxruntime_flatbuffers.cmake +++ b/cmake/onnxruntime_flatbuffers.cmake @@ -28,3 +28,17 @@ if (NOT onnxruntime_BUILD_SHARED_LIB) RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} FRAMEWORK DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() + +if (GDK_PLATFORM) + # cstdlib only defines std::getenv when _CRT_USE_WINAPI_FAMILY_DESKTOP_APP is defined, which + # is probably an oversight for GDK/Xbox builds (::getenv exists and works). + file(WRITE ${CMAKE_BINARY_DIR}/gdk_cstdlib_wrapper.h [[ +#pragma once +#ifdef __cplusplus +#include +namespace std { using ::getenv; } +#endif +]]) + target_compile_options(flatbuffers PRIVATE /FI${CMAKE_BINARY_DIR}/gdk_cstdlib_wrapper.h) + target_compile_options(flatc PRIVATE /FI${CMAKE_BINARY_DIR}/gdk_cstdlib_wrapper.h) +endif() \ No newline at end of file diff --git a/cmake/onnxruntime_providers.cmake b/cmake/onnxruntime_providers.cmake index da799207e4..af18cd605a 100644 --- a/cmake/onnxruntime_providers.cmake +++ b/cmake/onnxruntime_providers.cmake @@ -1070,7 +1070,11 @@ if (onnxruntime_USE_DML) function(target_add_dml target) if (onnxruntime_USE_CUSTOM_DIRECTML) - target_link_libraries(${target} PRIVATE DirectML) + if (dml_LIB_DIR) + target_link_libraries(${target} PRIVATE ${dml_LIB_DIR}/DirectML.lib) + else() + target_link_libraries(${target} PRIVATE DirectML) + endif() else() add_dependencies(${target} RESTORE_PACKAGES) target_link_libraries(${target} PRIVATE "${DML_PACKAGE_DIR}/bin/${onnxruntime_target_platform}-win/DirectML.lib") @@ -1079,11 +1083,17 @@ if (onnxruntime_USE_DML) endfunction() target_add_dml(onnxruntime_providers_dml) - target_link_libraries(onnxruntime_providers_dml PRIVATE d3d12.lib dxgi.lib) + if (GDK_PLATFORM STREQUAL Scarlett) + target_link_libraries(onnxruntime_providers_dml PRIVATE ${gdk_dx_libs}) + else() + target_link_libraries(onnxruntime_providers_dml PRIVATE d3d12.lib dxgi.lib) + endif() target_link_libraries(onnxruntime_providers_dml PRIVATE delayimp.lib) - set(onnxruntime_DELAYLOAD_FLAGS "${onnxruntime_DELAYLOAD_FLAGS} /DELAYLOAD:DirectML.dll /DELAYLOAD:d3d12.dll /DELAYLOAD:dxgi.dll /DELAYLOAD:api-ms-win-core-com-l1-1-0.dll /DELAYLOAD:shlwapi.dll /DELAYLOAD:oleaut32.dll /ignore:4199") + if (NOT GDK_PLATFORM) + set(onnxruntime_DELAYLOAD_FLAGS "${onnxruntime_DELAYLOAD_FLAGS} /DELAYLOAD:DirectML.dll /DELAYLOAD:d3d12.dll /DELAYLOAD:dxgi.dll /DELAYLOAD:api-ms-win-core-com-l1-1-0.dll /DELAYLOAD:shlwapi.dll /DELAYLOAD:oleaut32.dll /ignore:4199") + endif() target_compile_definitions(onnxruntime_providers_dml PRIVATE diff --git a/include/onnxruntime/core/providers/dml/dml_provider_factory.h b/include/onnxruntime/core/providers/dml/dml_provider_factory.h index 72816be80e..6af7dac956 100644 --- a/include/onnxruntime/core/providers/dml/dml_provider_factory.h +++ b/include/onnxruntime/core/providers/dml/dml_provider_factory.h @@ -5,7 +5,13 @@ #pragma warning(push) #pragma warning(disable : 4201) // nonstandard extension used: nameless struct/union +#ifdef _GAMING_XBOX_SCARLETT +#include +#elif defined(_GAMING_XBOX_XBOXONE) +#include +#else #include +#endif #pragma warning(pop) #ifdef __cplusplus diff --git a/onnxruntime/core/platform/path_lib.cc b/onnxruntime/core/platform/path_lib.cc index 43de1138b9..ecb66a55f4 100644 --- a/onnxruntime/core/platform/path_lib.cc +++ b/onnxruntime/core/platform/path_lib.cc @@ -13,7 +13,16 @@ #include "core/common/common.h" #ifdef _WIN32 -#if defined(USE_PATHCCH_LIB) +#if _GAMING_XBOX +// Hacky, but the PathCch* APIs work on Xbox. Presumably PathCch.h needs to be updated to include the +// GAMES partition. It would be worthwhile to investigate this a bit more (or just use std::filesystem). +#pragma push_macro("WINAPI_FAMILY") +#undef WINAPI_FAMILY +#define WINAPI_FAMILY WINAPI_FAMILY_DESKTOP_APP +#include +#pragma pop_macro("WINAPI_FAMILY") +#pragma comment(lib, "PathCch.lib") +#elif defined(USE_PATHCCH_LIB) #include #pragma comment(lib, "PathCch.lib") // Desktop apps need to support back to Windows 7, so we can't use PathCch.lib as it was added in Windows 8 @@ -38,7 +47,7 @@ namespace { Status RemoveFileSpec(PWSTR pszPath, size_t cchPath) { assert(pszPath != nullptr && pszPath[0] != L'\0'); -#if WINVER < _WIN32_WINNT_WIN8 && !defined(USE_PATHCCH_LIB) +#if WINVER < _WIN32_WINNT_WIN8 && !defined(USE_PATHCCH_LIB) && !defined(_GAMING_XBOX) (void)cchPath; for (PCWSTR t = L"\0"; *t == L'\0'; t = PathRemoveBackslashW(pszPath)) ; diff --git a/onnxruntime/core/platform/windows/stacktrace.cc b/onnxruntime/core/platform/windows/stacktrace.cc index d52d78a885..ca3aa72b85 100644 --- a/onnxruntime/core/platform/windows/stacktrace.cc +++ b/onnxruntime/core/platform/windows/stacktrace.cc @@ -33,7 +33,7 @@ class CaptureStackTrace { std::vector GetStackTrace() { #ifndef NDEBUG // TVM need to run with shared CRT, so won't work with debug helper now -#if !(defined USE_NUPHAR_TVM) && !(defined _OPSCHEMA_LIB_) +#if !(defined USE_NUPHAR_TVM) && !(defined _OPSCHEMA_LIB_) && !(defined _GAMING_XBOX) return detail::CaptureStackTrace().Trace(); #else return {}; @@ -45,7 +45,7 @@ std::vector GetStackTrace() { namespace detail { #ifndef NDEBUG -#if !(defined USE_NUPHAR_TVM) && !(defined _OPSCHEMA_LIB_) +#if !(defined USE_NUPHAR_TVM) && !(defined _OPSCHEMA_LIB_) && !(defined _GAMING_XBOX) class SymbolHelper { public: SymbolHelper() noexcept { diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/inc/MLOperatorAuthor.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/inc/MLOperatorAuthor.h index dd85b03b36..5b85576a50 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/inc/MLOperatorAuthor.h +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/inc/MLOperatorAuthor.h @@ -14,7 +14,7 @@ #include #include -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_GAMES) static_assert(sizeof(bool) == 1, "Unsupported size for bool type"); diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/BucketizedBufferAllocator.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/BucketizedBufferAllocator.cpp index 8acec1b3bb..8a02a358f6 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/BucketizedBufferAllocator.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/BucketizedBufferAllocator.cpp @@ -118,7 +118,7 @@ namespace Dml &buffer, m_initialState, nullptr, - IID_PPV_ARGS(&resource) + IID_GRAPHICS_PPV_ARGS(resource.ReleaseAndGetAddressOf()) )); resourceId = ++m_currentResourceId; @@ -143,7 +143,7 @@ namespace Dml &buffer, m_initialState, nullptr, - IID_PPV_ARGS(&resource) + IID_GRAPHICS_PPV_ARGS(resource.ReleaseAndGetAddressOf()) )); resourceId = ++m_currentResourceId; @@ -203,7 +203,11 @@ namespace Dml else { // Free the underlying allocation once queued work has completed. +#ifdef _GAMING_XBOX + m_context->QueueReference(WRAP_GRAPHICS_UNKNOWN(allocInfo->GetResource()).Get()); +#else m_context->QueueReference(allocInfo->GetResource()); +#endif allocInfo->DetachResource(); } diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/CommandAllocatorRing.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/CommandAllocatorRing.h index d394927461..26c8a021a0 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/CommandAllocatorRing.h +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/CommandAllocatorRing.h @@ -22,7 +22,7 @@ namespace Dml { ORT_THROW_IF_FAILED(device->CreateCommandAllocator( commandListType, - IID_PPV_ARGS(&info.allocator))); + IID_GRAPHICS_PPV_ARGS(info.allocator.ReleaseAndGetAddressOf()))); info.completionEvent = initialEvent; } diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/CommandQueue.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/CommandQueue.cpp index 8c6b44ef35..5516fc62cd 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/CommandQueue.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/CommandQueue.cpp @@ -11,9 +11,8 @@ namespace Dml , m_type(existingQueue->GetDesc().Type) { ComPtr device; - ORT_THROW_IF_FAILED(m_queue->GetDevice(IID_PPV_ARGS(&device))); - - ORT_THROW_IF_FAILED(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence))); + GRAPHICS_THROW_IF_FAILED(m_queue->GetDevice(IID_GRAPHICS_PPV_ARGS(device.GetAddressOf()))); + ORT_THROW_IF_FAILED(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_GRAPHICS_PPV_ARGS(m_fence.ReleaseAndGetAddressOf()))); } void CommandQueue::ExecuteCommandList(ID3D12CommandList* commandList) diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/CommandQueue.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/CommandQueue.h index 6d3a5f2636..bee5a33537 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/CommandQueue.h +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/CommandQueue.h @@ -33,6 +33,17 @@ namespace Dml GpuEvent GetNextCompletionEvent(); void QueueReference(IUnknown* object, bool waitForUnsubmittedWork); + +#ifdef _GAMING_XBOX + void QueueReference(IGraphicsUnknown* object, bool waitForUnsubmittedWork) + { + // TODO(justoeck): consider changing QueuedReference to hold a variant of + // ComPtr, ComPtr. + auto wrapper = Microsoft::WRL::Make(object); + QueueReference(wrapper.Get(), waitForUnsubmittedWork); + } +#endif + void Close(); void ReleaseCompletedReferences(); diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DescriptorPool.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DescriptorPool.cpp index c03d38c408..0c51cac6db 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DescriptorPool.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DescriptorPool.cpp @@ -13,8 +13,7 @@ namespace Dml m_heapFlags(heap->GetDesc().Flags) { ComPtr device; - ORT_THROW_IF_FAILED(heap->GetDevice(IID_PPV_ARGS(&device))); - + GRAPHICS_THROW_IF_FAILED(heap->GetDevice(IID_GRAPHICS_PPV_ARGS(device.GetAddressOf()))); m_handleIncrementSize = device->GetDescriptorHandleIncrementSize(heap->GetDesc().Type); } @@ -109,7 +108,7 @@ namespace Dml desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; ComPtr heap; - ORT_THROW_IF_FAILED(m_device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&heap))); + ORT_THROW_IF_FAILED(m_device->CreateDescriptorHeap(&desc, IID_GRAPHICS_PPV_ARGS(heap.GetAddressOf()))); m_heaps.push_back(DescriptorHeap{heap.Get()}); } diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlCommandRecorder.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlCommandRecorder.cpp index ea13610f32..bd1a8bdc66 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlCommandRecorder.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlCommandRecorder.cpp @@ -323,7 +323,7 @@ void DmlCommandRecorder::Open() m_queue->GetType(), m_commandAllocatorRing.GetCurrentAllocator(), nullptr, - IID_PPV_ARGS(&m_currentCommandList))); + IID_GRAPHICS_PPV_ARGS(m_currentCommandList.ReleaseAndGetAddressOf()))); } else { diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionContext.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionContext.cpp index 62e37c09d8..b5f070dd3f 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionContext.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionContext.cpp @@ -15,7 +15,7 @@ namespace Dml : m_queue(std::make_shared(queue)) , m_dmlRecorder(d3d12Device, dmlDevice, m_queue) { - ORT_THROW_IF_FAILED(dmlDevice->GetParentDevice(IID_PPV_ARGS(m_d3dDevice.GetAddressOf()))); + ORT_THROW_IF_FAILED(dmlDevice->GetParentDevice(IID_GRAPHICS_PPV_ARGS(m_d3dDevice.GetAddressOf()))); } void ExecutionContext::SetAllocator(std::weak_ptr allocator) @@ -178,7 +178,7 @@ namespace Dml bool waitForUnsubmittedWork = (m_currentRecorder != nullptr); m_queue->QueueReference(object, waitForUnsubmittedWork); } - + void ExecutionContext::Close() { assert(!m_closed); diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionProvider.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionProvider.cpp index 7363bba4a3..1e4f10b2cd 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionProvider.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionProvider.cpp @@ -25,7 +25,9 @@ #include "core/session/onnxruntime_c_api.h" #include +#ifndef _GAMING_XBOX #include +#endif #define ENABLE_GRAPH_COMPILATION @@ -71,7 +73,7 @@ namespace Dml } ComPtr device; - ORT_THROW_IF_FAILED(commandQueue->GetDevice(IID_PPV_ARGS(&device))); + GRAPHICS_THROW_IF_FAILED(commandQueue->GetDevice(IID_GRAPHICS_PPV_ARGS(device.GetAddressOf()))); m_impl = wil::MakeOrThrow(dmlDevice, device.Get(), commandQueue, enableMetacommands); @@ -668,8 +670,13 @@ namespace Dml } else { +#ifdef _GAMING_XBOX + ComPtr wrappedResource = Microsoft::WRL::Make(m_allocator->DecodeDataHandle(data)->GetResource()); + *abiData = wrappedResource.Detach(); +#else ComPtr resource = m_allocator->DecodeDataHandle(data)->GetResource(); *abiData = resource.Detach(); +#endif } } @@ -696,7 +703,12 @@ namespace Dml { ComPtr commandList; m_context->GetCommandListForRecording(commandList.GetAddressOf()); +#ifdef _GAMING_XBOX + ComPtr wrappedCommandList = Microsoft::WRL::Make(commandList.Get()); + *abiExecutionObject = wrappedCommandList.Detach(); +#else *abiExecutionObject = commandList.Detach(); +#endif } } diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/FusedGraphKernel.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/FusedGraphKernel.cpp index 57cfbb1229..808a0b259a 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/FusedGraphKernel.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/FusedGraphKernel.cpp @@ -164,7 +164,7 @@ namespace Dml std::for_each( initializeResourceRefs.begin(), initializeResourceRefs.end(), - [&](ComPtr& resource){ m_winmlProvider->QueueReference(resource.Get()); } + [&](ComPtr& resource){ m_winmlProvider->QueueReference(WRAP_GRAPHICS_UNKNOWN(resource).Get()); } ); if (graphDesc.reuseCommandList) @@ -312,7 +312,7 @@ namespace Dml ComPtr d3dDevice; ORT_THROW_IF_FAILED(m_provider->GetD3DDevice(d3dDevice.GetAddressOf())); - ORT_THROW_IF_FAILED(d3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&m_heap))); + ORT_THROW_IF_FAILED(d3dDevice->CreateDescriptorHeap(&desc, IID_GRAPHICS_PPV_ARGS(m_heap.ReleaseAndGetAddressOf()))); // Create a binding table for execution. DML_BINDING_TABLE_DESC bindingTableDesc = {}; @@ -326,7 +326,7 @@ namespace Dml ComPtr allocator; ORT_THROW_IF_FAILED(d3dDevice->CreateCommandAllocator( m_provider->GetCommandListTypeForQueue(), - IID_PPV_ARGS(&allocator))); + IID_GRAPHICS_PPV_ARGS(allocator.ReleaseAndGetAddressOf()))); ComPtr commandList; ORT_THROW_IF_FAILED(d3dDevice->CreateCommandList( @@ -334,7 +334,7 @@ namespace Dml m_provider->GetCommandListTypeForQueue(), allocator.Get(), nullptr, - IID_PPV_ARGS(&commandList))); + IID_GRAPHICS_PPV_ARGS(commandList.ReleaseAndGetAddressOf()))); ORT_THROW_IF_FAILED(commandList.As(&m_graphicsCommandList)); @@ -473,8 +473,8 @@ namespace Dml m_completionValue = completionValue; // Queue references to objects which must be kept alive until resulting GPU work completes - m_winmlProvider->QueueReference(m_graphicsCommandList.Get()); - m_winmlProvider->QueueReference(m_heap.Get()); + m_winmlProvider->QueueReference(WRAP_GRAPHICS_UNKNOWN(m_graphicsCommandList).Get()); + m_winmlProvider->QueueReference(WRAP_GRAPHICS_UNKNOWN(m_heap).Get()); m_winmlProvider->QueueReference(m_bindingTable.Get()); m_winmlProvider->QueueReference(m_persistentResourceAllocatorUnk.Get()); } diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/GraphKernelHelper.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/GraphKernelHelper.cpp index 893ad1e1ff..1ad3080505 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/GraphKernelHelper.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/GraphKernelHelper.cpp @@ -37,7 +37,7 @@ namespace GraphKernelHelper &resourceDesc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, nullptr, - IID_PPV_ARGS(buffer.GetAddressOf()))); + IID_GRAPHICS_PPV_ARGS(buffer.GetAddressOf()))); ORT_THROW_IF_FAILED(provider->UploadToResource(buffer.Get(), tensorPtr, tensorByteSize)); @@ -75,7 +75,7 @@ namespace GraphKernelHelper &resourceDesc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, nullptr, - IID_PPV_ARGS(buffer.GetAddressOf()))); + IID_GRAPHICS_PPV_ARGS(buffer.GetAddressOf()))); // Map the buffer and copy the data void* bufferData = nullptr; diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/GraphPartitioner.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/GraphPartitioner.cpp index 0862b07d6b..9a9c4b81bb 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/GraphPartitioner.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/GraphPartitioner.cpp @@ -11,7 +11,9 @@ #include "core/graph/indexed_sub_graph.h" #include "core/framework/compute_capability.h" #include +#ifndef _GAMING_XBOX #include +#endif #include "GraphPartitioner.h" //#define PRINT_PARTITON_INFO diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/GraphicsUnknownHelper.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/GraphicsUnknownHelper.h new file mode 100644 index 0000000000..391911ad0e --- /dev/null +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/GraphicsUnknownHelper.h @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +namespace Dml +{ +// D3D12.x interfaces inherit from IGraphicsUnknown, which does not inherit from IUnknown. This +// wrapper exists to pass IGraphicsUnknown-inheriting objects to functions with IUnknown parameters. +#ifdef _GAMING_XBOX +class GraphicsUnknownWrapper : public Microsoft::WRL::RuntimeClass, IUnknown> +{ +public: + explicit GraphicsUnknownWrapper(Microsoft::WRL::ComPtr graphicsUnknown) : m_graphicsUnknown(std::move(graphicsUnknown)) {} + explicit GraphicsUnknownWrapper(IGraphicsUnknown* graphicsUnknown) : m_graphicsUnknown(graphicsUnknown) {} + + HRESULT __stdcall QueryInterface(const IID& iid, void** object) noexcept final + { + if (iid == __uuidof(IUnknown)) + { + return RuntimeClass::QueryInterface(iid, object); + } + + return m_graphicsUnknown->QueryInterface(iid, object); + } + +private: + Microsoft::WRL::ComPtr m_graphicsUnknown; +}; +#endif + +// Convenience macro for functions that take an IUnknown* parameter and are typically +// called with a D3D-typed ComPtr argument. Example: +// m_winmlProvider->QueueReference(WRAP_GRAPHICS_UNKNOWN(resource).Get()); +// The macro is a no-op for PC (arg is convertible to IUnknown), and it will wrap +// any IGraphicsUnknown for _GAMING_XBOX platforms. +#ifdef _GAMING_XBOX +#define WRAP_GRAPHICS_UNKNOWN(expr) Microsoft::WRL::Make(expr) +#else +#define WRAP_GRAPHICS_UNKNOWN(expr) (expr) +#endif + +// IID_GRAPHICS_PPV_ARGS is to IGraphicsUnknown as IID_PPV_ARGS is to IUnknown. +// There is no IGraphicsUnknown in stock D3D, so this is the same as IID_PPV_ARGS. +// This macro should be used anywhere an interface is represented in both D3D12.x and +// D3D12. +#ifndef _GAMING_XBOX +#define IID_GRAPHICS_PPV_ARGS IID_PPV_ARGS +#endif + +// APIs like ID3D12DeviceChild::GetDevice return void in D3D12.x, but return HRESULT in D3D12. +#ifdef _GAMING_XBOX +#define GRAPHICS_THROW_IF_FAILED(hr) (hr) +#else +#define GRAPHICS_THROW_IF_FAILED(hr) ORT_THROW_IF_FAILED(hr) +#endif +} // namespace Dml \ No newline at end of file diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/PooledUploadHeap.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/PooledUploadHeap.cpp index d21893d408..db5fd301cf 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/PooledUploadHeap.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/PooledUploadHeap.cpp @@ -105,7 +105,7 @@ namespace Dml &buffer, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, - IID_PPV_ARGS(&uploadBuffer))); + IID_GRAPHICS_PPV_ARGS(uploadBuffer.ReleaseAndGetAddressOf()))); return Chunk{ sizeInBytes, std::move(uploadBuffer) }; } diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ReadbackHeap.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ReadbackHeap.cpp index af8e3797b2..31aacc3787 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ReadbackHeap.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ReadbackHeap.cpp @@ -19,7 +19,7 @@ namespace Dml &buffer, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, - IID_PPV_ARGS(&readbackHeap))); + IID_GRAPHICS_PPV_ARGS(readbackHeap.ReleaseAndGetAddressOf()))); return readbackHeap; } diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/precomp.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/precomp.h index d057c94435..5de0c39def 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/precomp.h +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/precomp.h @@ -26,9 +26,19 @@ #include +#ifdef _GAMING_XBOX_SCARLETT +#include +#include +#elif defined(_GAMING_XBOX_XBOXONE) +#include +#include +#else // Desktop #include #include #include "External/D3DX12/d3dx12.h" +#endif + +#include "GraphicsUnknownHelper.h" #include #include "core/common/common.h" diff --git a/onnxruntime/core/providers/dml/dml_provider_factory.cc b/onnxruntime/core/providers/dml/dml_provider_factory.cc index 704fb99c1b..7c3d4def27 100644 --- a/onnxruntime/core/providers/dml/dml_provider_factory.cc +++ b/onnxruntime/core/providers/dml/dml_provider_factory.cc @@ -2,7 +2,9 @@ // Licensed under the MIT License. #include +#ifndef _GAMING_XBOX #include +#endif #include using Microsoft::WRL::ComPtr; @@ -16,6 +18,7 @@ using Microsoft::WRL::ComPtr; #include "core/session/ort_apis.h" #include "core/framework/error_code_helper.h" #include "DmlExecutionProvider/src/ErrorHandling.h" +#include "DmlExecutionProvider/src/GraphicsUnknownHelper.h" #include "DmlExecutionProvider/inc/DmlExecutionProvider.h" #include "core/platform/env.h" @@ -55,6 +58,7 @@ void DMLProviderFactory::SetMetacommandsEnabled(bool metacommands_enabled) { std::shared_ptr CreateExecutionProviderFactory_DML(IDMLDevice* dml_device, ID3D12CommandQueue* cmd_queue) { +#ifndef _GAMING_XBOX // Validate that the D3D12 devices match between DML and the command queue. This specifically asks for IUnknown in // order to be able to compare the pointers for COM object identity. ComPtr d3d12_device_0; @@ -65,9 +69,10 @@ std::shared_ptr CreateExecutionProviderFactory_DML(ID if (d3d12_device_0 != d3d12_device_1) { ORT_THROW_HR(E_INVALIDARG); } +#endif ComPtr d3d12_device; - ORT_THROW_IF_FAILED(dml_device->GetParentDevice(IID_PPV_ARGS(&d3d12_device))); + ORT_THROW_IF_FAILED(dml_device->GetParentDevice(IID_GRAPHICS_PPV_ARGS(d3d12_device.ReleaseAndGetAddressOf()))); const Env& env = Env::Default(); auto luid = d3d12_device->GetAdapterLuid(); env.GetTelemetryProvider().LogExecutionProviderEvent(&luid); @@ -99,8 +104,17 @@ bool IsSoftwareAdapter(IDXGIAdapter1* adapter) { } std::shared_ptr CreateExecutionProviderFactory_DML(int device_id) { +#ifdef _GAMING_XBOX + ComPtr d3d12_device; + D3D12XBOX_CREATE_DEVICE_PARAMETERS params = {}; + params.Version = D3D12_SDK_VERSION; + params.GraphicsCommandQueueRingSizeBytes = static_cast(D3D12XBOX_DEFAULT_SIZE_BYTES); + params.GraphicsScratchMemorySizeBytes = static_cast(D3D12XBOX_DEFAULT_SIZE_BYTES); + params.ComputeScratchMemorySizeBytes = static_cast(D3D12XBOX_DEFAULT_SIZE_BYTES); + ORT_THROW_IF_FAILED(D3D12XboxCreateDevice(nullptr, ¶ms, IID_GRAPHICS_PPV_ARGS(d3d12_device.ReleaseAndGetAddressOf()))); +#else ComPtr dxgi_factory; - ORT_THROW_IF_FAILED(CreateDXGIFactory2(0, IID_PPV_ARGS(&dxgi_factory))); + ORT_THROW_IF_FAILED(CreateDXGIFactory2(0, IID_GRAPHICS_PPV_ARGS(dxgi_factory.ReleaseAndGetAddressOf()))); ComPtr adapter; ORT_THROW_IF_FAILED(dxgi_factory->EnumAdapters1(device_id, &adapter)); @@ -109,19 +123,20 @@ std::shared_ptr CreateExecutionProviderFactory_DML(in ORT_THROW_HR_IF(E_INVALIDARG, IsSoftwareAdapter(adapter.Get())); ComPtr d3d12_device; - ORT_THROW_IF_FAILED(D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&d3d12_device))); + ORT_THROW_IF_FAILED(D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_GRAPHICS_PPV_ARGS(d3d12_device.ReleaseAndGetAddressOf()))); +#endif D3D12_COMMAND_QUEUE_DESC cmd_queue_desc = {}; cmd_queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; cmd_queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_DISABLE_GPU_TIMEOUT; ComPtr cmd_queue; - ORT_THROW_IF_FAILED(d3d12_device->CreateCommandQueue(&cmd_queue_desc, IID_PPV_ARGS(&cmd_queue))); + ORT_THROW_IF_FAILED(d3d12_device->CreateCommandQueue(&cmd_queue_desc, IID_GRAPHICS_PPV_ARGS(cmd_queue.ReleaseAndGetAddressOf()))); DML_CREATE_DEVICE_FLAGS flags = DML_CREATE_DEVICE_FLAG_NONE; // In debug builds, enable the DML debug layer if the D3D12 debug layer is also enabled -#if _DEBUG +#if _DEBUG && !_GAMING_XBOX ComPtr debug_device; (void)d3d12_device->QueryInterface(IID_PPV_ARGS(&debug_device)); // ignore failure const bool is_d3d12_debug_layer_enabled = (debug_device != nullptr); diff --git a/tools/ci_build/build.py b/tools/ci_build/build.py index a46421ece2..432f2d0917 100644 --- a/tools/ci_build/build.py +++ b/tools/ci_build/build.py @@ -322,6 +322,11 @@ def parse_arguments(): parser.add_argument("--android_run_emulator", action="store_true", help="Start up an Android emulator if needed.") + parser.add_argument("--use_gdk", action='store_true', help="Build with the GDK toolchain.") + parser.add_argument("--gdk_edition", default=os.path.normpath(os.environ.get("GameDKLatest", "")).split(os.sep)[-1], + help="Build with a specific GDK edition. Defaults to the latest installed.") + parser.add_argument("--gdk_platform", default="Scarlett", help="Sets the GDK target platform.") + parser.add_argument("--ios", action='store_true', help="build for ios") parser.add_argument( "--ios_sysroot", default="", @@ -483,6 +488,9 @@ def parse_arguments(): help="Test with multi-device. Mostly used for multi-device GPU") parser.add_argument( "--use_dml", action='store_true', help="Build with DirectML.") + parser.add_argument( + "--dml_path", type=str, default="", + help="Path to a custom DirectML installation (must have bin/, lib/, and include/ subdirectories).") parser.add_argument( "--use_winml", action='store_true', help="Build with WinML.") parser.add_argument( @@ -977,6 +985,23 @@ def generate_build_tree(cmake_path, source_dir, build_dir, cuda_home, cudnn_home if args.android_cpp_shared: cmake_args += ["-DANDROID_STL=c++_shared"] + if args.dml_path: + cmake_args += [ + "-Donnxruntime_USE_CUSTOM_DIRECTML=ON", + "-Ddml_INCLUDE_DIR=" + os.path.join(args.dml_path, "include"), + "-Ddml_LIB_DIR=" + os.path.join(args.dml_path, "lib"), + ] + + if args.use_gdk: + cmake_args += [ + "-DCMAKE_TOOLCHAIN_FILE=" + os.path.join(source_dir, 'cmake', 'gdk_toolchain.cmake'), + "-DGDK_EDITION=" + args.gdk_edition, + "-DGDK_PLATFORM=" + args.gdk_platform, + "-Donnxruntime_BUILD_UNIT_TESTS=OFF" # gtest doesn't build for GDK + ] + if args.use_dml and not args.dml_path: + raise BuildError("You must set dml_path when building with the GDK.") + if is_macOS() and not args.android: cmake_args += ["-DCMAKE_OSX_ARCHITECTURES=" + args.osx_arch] if args.use_xcode: @@ -1165,6 +1190,7 @@ def generate_build_tree(cmake_path, source_dir, build_dir, cuda_home, cudnn_home "-Donnxruntime_ENABLE_MEMLEAK_CHECKER=" + ("ON" if config.lower() == 'debug' and not (args.use_nuphar or args.use_tvm) and not args.use_openvino and not + args.use_gdk and not args.enable_msvc_static_runtime and not args.disable_memleak_checker else "OFF"), "-DCMAKE_BUILD_TYPE={}".format(config)], @@ -1297,7 +1323,17 @@ def setup_migraphx_vars(args): def setup_dml_build(args, cmake_path, build_dir, configs): - if args.use_dml: + if not args.use_dml: + return + + if args.dml_path: + for expected_file in ["bin/DirectML.dll", "lib/DirectML.lib", "include/DirectML.h"]: + file_path = os.path.join(args.dml_path, expected_file) + if not os.path.exists(file_path): + raise BuildError("dml_path is invalid.", + "dml_path='{}' expected_file='{}'." + .format(args.dml_path, file_path)) + else: for config in configs: # Run the RESTORE_PACKAGES target to perform the initial # NuGet setup. @@ -2145,6 +2181,10 @@ def main(): if args.use_openvino != "CPU_FP32" and args.build_nuget: args.test = False + # GDK builds don't support testing + if args.use_gdk: + args.test = False + configs = set(args.config) # setup paths and directories