yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Jay KwakSupport SM6.9 with GFX (#7387)debdc7251

master
84.4 KiB2318 linesraw
1// d3d12-device.cpp
2#include "d3d12-device.h"
3
4#include "../nvapi/nvapi-util.h"
5#include "d3d12-buffer.h"
6#include "d3d12-fence.h"
7#include "d3d12-framebuffer.h"
8#include "d3d12-helper-functions.h"
9#include "d3d12-pipeline-state.h"
10#include "d3d12-query.h"
11#include "d3d12-render-pass.h"
12#include "d3d12-resource-views.h"
13#include "d3d12-sampler.h"
14#include "d3d12-shader-object.h"
15#include "d3d12-shader-program.h"
16#include "d3d12-shader-table.h"
17#include "d3d12-swap-chain.h"
18#include "d3d12-vertex-layout.h"
19
20#ifdef GFX_NVAPI
21#include "../nvapi/nvapi-include.h"
22#endif
23
24#ifdef GFX_NV_AFTERMATH
25#include "GFSDK_Aftermath.h"
26#include "GFSDK_Aftermath_Defines.h"
27#include "GFSDK_Aftermath_GpuCrashDump.h"
28#endif
29
30namespace gfx
31{
32namespace d3d12
33{
34
35using namespace Slang;
36
37static const uint32_t D3D_FEATURE_LEVEL_12_2 = 0xc200;
38
39
40#if GFX_NV_AFTERMATH
41/* static */ const bool DeviceImpl::g_isAftermathEnabled = true;
42#else
43/* static */ const bool DeviceImpl::g_isAftermathEnabled = false;
44#endif
45
46struct ShaderModelInfo
47{
48    D3D_SHADER_MODEL shaderModel;
49    SlangCompileTarget compileTarget;
50    const char* profileName;
51};
52// List of shader models. Do not change oldest to newest order.
53static ShaderModelInfo kKnownShaderModels[] = {
54#define SHADER_MODEL_INFO_DXBC(major, minor)                                    \
55    {                                                                           \
56        D3D_SHADER_MODEL_##major##_##minor, SLANG_DXBC, "sm_" #major "_" #minor \
57    }
58    SHADER_MODEL_INFO_DXBC(5, 1),
59#undef SHADER_MODEL_INFO_DXBC
60#define SHADER_MODEL_INFO_DXIL(major, minor)                                    \
61    {                                                                           \
62        (D3D_SHADER_MODEL)0x##major##minor, SLANG_DXIL, "sm_" #major "_" #minor \
63    }
64    SHADER_MODEL_INFO_DXIL(6, 0),
65    SHADER_MODEL_INFO_DXIL(6, 1),
66    SHADER_MODEL_INFO_DXIL(6, 2),
67    SHADER_MODEL_INFO_DXIL(6, 3),
68    SHADER_MODEL_INFO_DXIL(6, 4),
69    SHADER_MODEL_INFO_DXIL(6, 5),
70    SHADER_MODEL_INFO_DXIL(6, 6),
71    SHADER_MODEL_INFO_DXIL(6, 7),
72    SHADER_MODEL_INFO_DXIL(6, 8),
73    SHADER_MODEL_INFO_DXIL(6, 9)
74#undef SHADER_MODEL_INFO_DXIL
75};
76
77Result DeviceImpl::createBuffer(
78    const D3D12_RESOURCE_DESC& resourceDesc,
79    const void* srcData,
80    Size srcDataSize,
81    D3D12_RESOURCE_STATES finalState,
82    D3D12Resource& resourceOut,
83    bool isShared,
84    MemoryType memoryType)
85{
86    const Size bufferSize = Size(resourceDesc.Width);
87
88    D3D12_HEAP_PROPERTIES heapProps;
89    heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
90    heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
91    heapProps.CreationNodeMask = 1;
92    heapProps.VisibleNodeMask = 1;
93
94    D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE;
95    if (isShared)
96        flags |= D3D12_HEAP_FLAG_SHARED;
97
98    D3D12_RESOURCE_DESC desc = resourceDesc;
99
100    D3D12_RESOURCE_STATES initialState = finalState;
101
102
103    switch (memoryType)
104    {
105    case MemoryType::ReadBack:
106        assert(!srcData);
107
108        heapProps.Type = D3D12_HEAP_TYPE_READBACK;
109        desc.Flags = D3D12_RESOURCE_FLAG_NONE;
110        initialState |= D3D12_RESOURCE_STATE_COPY_DEST;
111        break;
112    case MemoryType::Upload:
113
114        heapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
115        desc.Flags = D3D12_RESOURCE_FLAG_NONE;
116        initialState |= D3D12_RESOURCE_STATE_GENERIC_READ;
117        break;
118    case MemoryType::DeviceLocal:
119        heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
120        if (initialState != D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE)
121            initialState = D3D12_RESOURCE_STATE_COMMON;
122        break;
123    default:
124        return SLANG_FAIL;
125    }
126
127    // Create the resource.
128    SLANG_RETURN_ON_FAIL(
129        resourceOut.initCommitted(m_device, heapProps, flags, desc, initialState, nullptr));
130
131    if (srcData)
132    {
133        D3D12Resource uploadResource;
134
135        if (memoryType == MemoryType::DeviceLocal)
136        {
137            // If the buffer is on the default heap, create upload buffer.
138            D3D12_RESOURCE_DESC uploadDesc(resourceDesc);
139            uploadDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
140            heapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
141
142            SLANG_RETURN_ON_FAIL(uploadResource.initCommitted(
143                m_device,
144                heapProps,
145                D3D12_HEAP_FLAG_NONE,
146                uploadDesc,
147                D3D12_RESOURCE_STATE_GENERIC_READ,
148                nullptr));
149        }
150
151        // Be careful not to actually copy a resource here.
152        D3D12Resource& uploadResourceRef =
153            (memoryType == MemoryType::DeviceLocal) ? uploadResource : resourceOut;
154
155        // Copy data to the intermediate upload heap and then schedule a copy
156        // from the upload heap to the vertex buffer.
157        UINT8* dstData;
158        D3D12_RANGE readRange = {}; // We do not intend to read from this resource on the CPU.
159
160        ID3D12Resource* dxUploadResource = uploadResourceRef.getResource();
161
162        SLANG_RETURN_ON_FAIL(
163            dxUploadResource->Map(0, &readRange, reinterpret_cast<void**>(&dstData)));
164        ::memcpy(dstData, srcData, srcDataSize);
165        dxUploadResource->Unmap(0, nullptr);
166
167        if (memoryType == MemoryType::DeviceLocal)
168        {
169            auto encodeInfo = encodeResourceCommands();
170            encodeInfo.d3dCommandList
171                ->CopyBufferRegion(resourceOut, 0, uploadResourceRef, 0, bufferSize);
172            submitResourceCommandsAndWait(encodeInfo);
173        }
174    }
175
176    return SLANG_OK;
177}
178
179Result DeviceImpl::captureTextureToSurface(
180    TextureResourceImpl* resourceImpl,
181    ResourceState state,
182    ISlangBlob** outBlob,
183    Size* outRowPitch,
184    Size* outPixelSize)
185{
186    auto& resource = resourceImpl->m_resource;
187
188    const D3D12_RESOURCE_STATES initialState = D3DUtil::getResourceState(state);
189
190    const ITextureResource::Desc& gfxDesc = *resourceImpl->getDesc();
191    const D3D12_RESOURCE_DESC desc = resource.getResource()->GetDesc();
192
193    // Don't bother supporting MSAA for right now
194    if (desc.SampleDesc.Count > 1)
195    {
196        fprintf(stderr, "ERROR: cannot capture multi-sample texture\n");
197        return SLANG_FAIL;
198    }
199
200    FormatInfo formatInfo;
201    gfxGetFormatInfo(gfxDesc.format, &formatInfo);
202    Size bytesPerPixel = formatInfo.blockSizeInBytes / formatInfo.pixelsPerBlock;
203    Size rowPitch = int(desc.Width) * bytesPerPixel;
204    static const Size align = 256; // D3D requires minimum 256 byte alignment for texture data.
205    rowPitch = (rowPitch + align - 1) & ~(align - 1); // Bit trick for rounding up
206    Size bufferSize = rowPitch * int(desc.Height) * int(desc.DepthOrArraySize);
207    if (outRowPitch)
208        *outRowPitch = rowPitch;
209    if (outPixelSize)
210        *outPixelSize = bytesPerPixel;
211
212    D3D12Resource stagingResource;
213    {
214        D3D12_RESOURCE_DESC stagingDesc;
215        initBufferResourceDesc(bufferSize, stagingDesc);
216
217        D3D12_HEAP_PROPERTIES heapProps;
218        heapProps.Type = D3D12_HEAP_TYPE_READBACK;
219        heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
220        heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
221        heapProps.CreationNodeMask = 1;
222        heapProps.VisibleNodeMask = 1;
223
224        SLANG_RETURN_ON_FAIL(stagingResource.initCommitted(
225            m_device,
226            heapProps,
227            D3D12_HEAP_FLAG_NONE,
228            stagingDesc,
229            D3D12_RESOURCE_STATE_COPY_DEST,
230            nullptr));
231    }
232
233    auto encodeInfo = encodeResourceCommands();
234    auto currentState = D3DUtil::getResourceState(state);
235
236    {
237        D3D12BarrierSubmitter submitter(encodeInfo.d3dCommandList);
238        resource.transition(currentState, D3D12_RESOURCE_STATE_COPY_SOURCE, submitter);
239    }
240
241    // Do the copy
242    {
243        D3D12_TEXTURE_COPY_LOCATION srcLoc;
244        srcLoc.pResource = resource;
245        srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
246        srcLoc.SubresourceIndex = 0;
247
248        D3D12_TEXTURE_COPY_LOCATION dstLoc;
249        dstLoc.pResource = stagingResource;
250        dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
251        dstLoc.PlacedFootprint.Offset = 0;
252        dstLoc.PlacedFootprint.Footprint.Format = desc.Format;
253        dstLoc.PlacedFootprint.Footprint.Width = UINT(desc.Width);
254        dstLoc.PlacedFootprint.Footprint.Height = UINT(desc.Height);
255        dstLoc.PlacedFootprint.Footprint.Depth = UINT(desc.DepthOrArraySize);
256        dstLoc.PlacedFootprint.Footprint.RowPitch = UINT(rowPitch);
257
258        encodeInfo.d3dCommandList->CopyTextureRegion(&dstLoc, 0, 0, 0, &srcLoc, nullptr);
259    }
260
261    {
262        D3D12BarrierSubmitter submitter(encodeInfo.d3dCommandList);
263        resource.transition(D3D12_RESOURCE_STATE_COPY_SOURCE, currentState, submitter);
264    }
265
266    // Submit the copy, and wait for copy to complete
267    submitResourceCommandsAndWait(encodeInfo);
268
269    {
270        ID3D12Resource* dxResource = stagingResource;
271
272        UINT8* data;
273        D3D12_RANGE readRange = {0, bufferSize};
274
275        SLANG_RETURN_ON_FAIL(dxResource->Map(0, &readRange, reinterpret_cast<void**>(&data)));
276
277        List<uint8_t> blobData;
278
279        blobData.setCount(bufferSize);
280        memcpy(blobData.getBuffer(), data, bufferSize);
281        dxResource->Unmap(0, nullptr);
282
283        auto resultBlob = Slang::ListBlob::moveCreate(blobData);
284
285        returnComPtr(outBlob, resultBlob);
286        return SLANG_OK;
287    }
288}
289
290Result DeviceImpl::getNativeDeviceHandles(InteropHandles* outHandles)
291{
292    outHandles->handles[0].handleValue = (uint64_t)m_device;
293    outHandles->handles[0].api = InteropHandleAPI::D3D12;
294    return SLANG_OK;
295}
296
297Result DeviceImpl::_createDevice(
298    DeviceCheckFlags deviceCheckFlags,
299    const AdapterLUID* adapterLUID,
300    D3D_FEATURE_LEVEL featureLevel,
301    D3D12DeviceInfo& outDeviceInfo)
302{
303    if (m_dxDebug && (deviceCheckFlags & DeviceCheckFlag::UseDebug) && !g_isAftermathEnabled)
304    {
305        m_dxDebug->EnableDebugLayer();
306    }
307
308    outDeviceInfo.clear();
309
310    ComPtr<IDXGIFactory> dxgiFactory;
311    SLANG_RETURN_ON_FAIL(D3DUtil::createFactory(deviceCheckFlags, dxgiFactory));
312
313    List<ComPtr<IDXGIAdapter>> dxgiAdapters;
314    SLANG_RETURN_ON_FAIL(
315        D3DUtil::findAdapters(deviceCheckFlags, adapterLUID, dxgiFactory, dxgiAdapters));
316
317    ComPtr<ID3D12Device> device;
318    ComPtr<IDXGIAdapter> adapter;
319
320    for (Index i = 0; i < dxgiAdapters.getCount(); ++i)
321    {
322        IDXGIAdapter* dxgiAdapter = dxgiAdapters[i];
323        if (SLANG_SUCCEEDED(
324                m_D3D12CreateDevice(dxgiAdapter, featureLevel, IID_PPV_ARGS(device.writeRef()))))
325        {
326            adapter = dxgiAdapter;
327            break;
328        }
329    }
330
331    if (!device)
332    {
333        return SLANG_FAIL;
334    }
335
336    if (m_dxDebug && (deviceCheckFlags & DeviceCheckFlag::UseDebug) && !g_isAftermathEnabled)
337    {
338        ComPtr<ID3D12InfoQueue> infoQueue;
339        if (SLANG_SUCCEEDED(device->QueryInterface(infoQueue.writeRef())))
340        {
341            // Make break
342            infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true);
343            if (m_extendedDesc.debugBreakOnD3D12Error)
344            {
345                infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true);
346            }
347            D3D12_MESSAGE_ID hideMessages[] = {
348                D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE,
349                D3D12_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_MISMATCHINGCLEARVALUE,
350            };
351            D3D12_INFO_QUEUE_FILTER f = {};
352            f.DenyList.NumIDs = (UINT)SLANG_COUNT_OF(hideMessages);
353            f.DenyList.pIDList = hideMessages;
354            infoQueue->AddStorageFilterEntries(&f);
355
356            // Apparently there is a problem with sm 6.3 with spurious errors, with debug layer
357            // enabled
358            D3D12_FEATURE_DATA_SHADER_MODEL featureShaderModel;
359            featureShaderModel.HighestShaderModel = D3D_SHADER_MODEL_6_3;
360            SLANG_SUCCEEDED(device->CheckFeatureSupport(
361                D3D12_FEATURE_SHADER_MODEL,
362                &featureShaderModel,
363                sizeof(featureShaderModel)));
364
365            if (featureShaderModel.HighestShaderModel >= D3D_SHADER_MODEL_6_3)
366            {
367                // Filter out any messages that cause issues
368                // TODO: Remove this when the debug layers work properly
369                D3D12_MESSAGE_ID messageIds[] = {
370                    // When the debug layer is enabled this error is triggered sometimes after a
371                    // CopyDescriptorsSimple call The failed check validates that the source and
372                    // destination ranges of the copy do not overlap. The check assumes descriptor
373                    // handles are pointers to memory, but this is not always the case and the check
374                    // fails (even though everything is okay).
375                    D3D12_MESSAGE_ID_COPY_DESCRIPTORS_INVALID_RANGES,
376                };
377
378                // We filter INFO messages because they are way too many
379                D3D12_MESSAGE_SEVERITY severities[] = {D3D12_MESSAGE_SEVERITY_INFO};
380
381                D3D12_INFO_QUEUE_FILTER infoQueueFilter = {};
382                infoQueueFilter.DenyList.NumSeverities = SLANG_COUNT_OF(severities);
383                infoQueueFilter.DenyList.pSeverityList = severities;
384                infoQueueFilter.DenyList.NumIDs = SLANG_COUNT_OF(messageIds);
385                infoQueueFilter.DenyList.pIDList = messageIds;
386
387                infoQueue->PushStorageFilter(&infoQueueFilter);
388            }
389        }
390    }
391
392
393#ifdef GFX_NV_AFTERMATH
394    {
395        if ((deviceCheckFlags & DeviceCheckFlag::UseDebug) && g_isAftermathEnabled)
396        {
397            // Initialize Nsight Aftermath for this device.
398            // This combination of flags is not necessarily appropraite for real world usage
399            const uint32_t aftermathFlags =
400                GFSDK_Aftermath_FeatureFlags_EnableMarkers |      // Enable event marker tracking.
401                GFSDK_Aftermath_FeatureFlags_CallStackCapturing | // Enable automatic call stack
402                                                                  // event markers.
403                GFSDK_Aftermath_FeatureFlags_EnableResourceTracking |  // Enable tracking of
404                                                                       // resources.
405                GFSDK_Aftermath_FeatureFlags_GenerateShaderDebugInfo | // Generate debug information
406                                                                       // for shaders.
407                GFSDK_Aftermath_FeatureFlags_EnableShaderErrorReporting; // Enable additional
408                                                                         // runtime shader error
409                                                                         // reporting.
410
411            auto initResult = GFSDK_Aftermath_DX12_Initialize(
412                GFSDK_Aftermath_Version_API,
413                aftermathFlags,
414                device);
415
416            if (initResult != GFSDK_Aftermath_Result_Success)
417            {
418                SLANG_ASSERT_FAILURE("Unable to initialize aftermath");
419                // Unable to initialize
420                return SLANG_FAIL;
421            }
422        }
423    }
424#endif
425
426    // Get the descs
427    {
428        adapter->GetDesc(&outDeviceInfo.m_desc);
429
430        // Look up GetDesc1 info
431        ComPtr<IDXGIAdapter1> adapter1;
432        if (SLANG_SUCCEEDED(adapter->QueryInterface(adapter1.writeRef())))
433        {
434            adapter1->GetDesc1(&outDeviceInfo.m_desc1);
435        }
436    }
437
438    // Save other info
439    outDeviceInfo.m_device = device;
440    outDeviceInfo.m_dxgiFactory = dxgiFactory;
441    outDeviceInfo.m_adapter = adapter;
442    outDeviceInfo.m_isWarp = D3DUtil::isWarp(dxgiFactory, adapter);
443    const UINT kMicrosoftVendorId = 5140;
444    outDeviceInfo.m_isSoftware =
445        outDeviceInfo.m_isWarp ||
446        ((outDeviceInfo.m_desc1.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) != 0) ||
447        outDeviceInfo.m_desc.VendorId == kMicrosoftVendorId;
448
449    return SLANG_OK;
450}
451
452Result DeviceImpl::initialize(const Desc& desc)
453{
454    SLANG_RETURN_ON_FAIL(RendererBase::initialize(desc));
455
456    // Rather than statically link against D3D, we load it dynamically.
457
458    SharedLibrary::Handle d3dModule;
459#if SLANG_WINDOWS_FAMILY
460    const char* libName = "d3d12";
461#else
462    const char* libName = "vkd3d-proton-d3d12";
463#endif
464    if (SLANG_FAILED(SharedLibrary::load(libName, d3dModule)))
465    {
466        getDebugCallback()->handleMessage(
467            DebugMessageType::Error,
468            DebugMessageSource::Layer,
469            "error: failed load 'd3d12.dll'\n");
470        return SLANG_FAIL;
471    }
472
473    // Find extended desc.
474    for (GfxIndex i = 0; i < desc.extendedDescCount; i++)
475    {
476        StructType stype;
477        memcpy(&stype, desc.extendedDescs[i], sizeof(stype));
478        switch (stype)
479        {
480        case StructType::D3D12DeviceExtendedDesc:
481            memcpy(&m_extendedDesc, desc.extendedDescs[i], sizeof(m_extendedDesc));
482            break;
483        case StructType::D3D12ExperimentalFeaturesDesc:
484            processExperimentalFeaturesDesc(d3dModule, desc.extendedDescs[i]);
485            break;
486        }
487    }
488
489    // Initialize queue index allocator.
490    // Support max 32 queues.
491    m_queueIndexAllocator.initPool(32);
492
493    // Initialize DeviceInfo
494    {
495        m_info.deviceType = DeviceType::DirectX12;
496        m_info.bindingStyle = BindingStyle::DirectX;
497        m_info.projectionStyle = ProjectionStyle::DirectX;
498        m_info.apiName = "Direct3D 12";
499        static const float kIdentity[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
500        ::memcpy(m_info.identityProjectionMatrix, kIdentity, sizeof(kIdentity));
501    }
502
503    // Get all the dll entry points
504    m_D3D12SerializeRootSignature =
505        (PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)loadProc(d3dModule, "D3D12SerializeRootSignature");
506    if (!m_D3D12SerializeRootSignature)
507    {
508        return SLANG_FAIL;
509    }
510
511    m_D3D12SerializeVersionedRootSignature = (PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE)loadProc(
512        d3dModule,
513        "D3D12SerializeVersionedRootSignature");
514    if (!m_D3D12SerializeVersionedRootSignature)
515    {
516        return SLANG_FAIL;
517    }
518
519#if SLANG_ENABLE_PIX
520    HMODULE pixModule = LoadLibraryW(L"WinPixEventRuntime.dll");
521    if (pixModule)
522    {
523        m_BeginEventOnCommandList =
524            (PFN_BeginEventOnCommandList)GetProcAddress(pixModule, "PIXBeginEventOnCommandList");
525        m_EndEventOnCommandList =
526            (PFN_EndEventOnCommandList)GetProcAddress(pixModule, "PIXEndEventOnCommandList");
527    }
528#endif
529
530
531    // If Aftermath is enabled, we can't enable the D3D12 debug layer as well
532    if (isGfxDebugLayerEnabled() && !g_isAftermathEnabled)
533    {
534        m_D3D12GetDebugInterface =
535            (PFN_D3D12_GET_DEBUG_INTERFACE)loadProc(d3dModule, "D3D12GetDebugInterface");
536        if (m_D3D12GetDebugInterface)
537        {
538            if (SLANG_SUCCEEDED(m_D3D12GetDebugInterface(IID_PPV_ARGS(m_dxDebug.writeRef()))))
539            {
540#if 0
541                // Can enable for extra validation. NOTE! That d3d12 warns if you do....
542                // D3D12 MESSAGE : Device Debug Layer Startup Options : GPU - Based Validation is enabled(disabled by default).
543                // This results in new validation not possible during API calls on the CPU, by creating patched shaders that have validation
544                // added directly to the shader. However, it can slow things down a lot, especially for applications with numerous
545                // PSOs.Time to see the first render frame may take several minutes.
546                // [INITIALIZATION MESSAGE #1016: CREATEDEVICE_DEBUG_LAYER_STARTUP_OPTIONS]
547
548                ComPtr<ID3D12Debug1> debug1;
549                if (SLANG_SUCCEEDED(m_dxDebug->QueryInterface(debug1.writeRef())))
550                {
551                    debug1->SetEnableGPUBasedValidation(true);
552                }
553#endif
554            }
555        }
556    }
557
558    m_D3D12CreateDevice = (PFN_D3D12_CREATE_DEVICE)loadProc(d3dModule, "D3D12CreateDevice");
559    if (!m_D3D12CreateDevice)
560    {
561        return SLANG_FAIL;
562    }
563
564    if (desc.existingDeviceHandles.handles[0].handleValue == 0)
565    {
566        FlagCombiner combiner;
567        if (isGfxDebugLayerEnabled())
568        {
569            combiner.add(
570                DeviceCheckFlag::UseDebug,
571                ChangeType::OnOff); ///< First try debug then non debug
572        }
573        else
574        {
575            combiner.add(DeviceCheckFlag::UseDebug, ChangeType::Off); ///< Don't bother with debug
576        }
577        combiner.add(
578            DeviceCheckFlag::UseHardwareDevice,
579            ChangeType::OnOff); ///< First try hardware, then reference
580
581
582        const D3D_FEATURE_LEVEL featureLevels[] = {
583            (D3D_FEATURE_LEVEL)D3D_FEATURE_LEVEL_12_2,
584            D3D_FEATURE_LEVEL_12_1,
585            D3D_FEATURE_LEVEL_12_0,
586            D3D_FEATURE_LEVEL_11_1,
587            D3D_FEATURE_LEVEL_11_0,
588            D3D_FEATURE_LEVEL_10_1,
589            D3D_FEATURE_LEVEL_10_0,
590            D3D_FEATURE_LEVEL_9_3,
591            D3D_FEATURE_LEVEL_9_2,
592            D3D_FEATURE_LEVEL_9_1};
593        for (auto featureLevel : featureLevels)
594        {
595            const int numCombinations = combiner.getNumCombinations();
596            for (int i = 0; i < numCombinations; ++i)
597            {
598                if (SLANG_SUCCEEDED(_createDevice(
599                        combiner.getCombination(i),
600                        desc.adapterLUID,
601                        featureLevel,
602                        m_deviceInfo)))
603                {
604                    goto succ;
605                }
606            }
607        }
608    succ:
609        if (!m_deviceInfo.m_adapter)
610        {
611            // Couldn't find an adapter
612            return SLANG_FAIL;
613        }
614    }
615    else
616    {
617        // Store the existing device handle in desc in m_deviceInfo
618        m_deviceInfo.m_device = (ID3D12Device*)desc.existingDeviceHandles.handles[0].handleValue;
619    }
620
621    // Set the device
622    m_device = m_deviceInfo.m_device;
623
624    if (m_deviceInfo.m_isSoftware)
625    {
626        m_features.add("software-device");
627    }
628    else
629    {
630        m_features.add("hardware-device");
631    }
632
633    // NVAPI
634    if (desc.nvapiExtnSlot >= 0)
635    {
636        if (SLANG_FAILED(NVAPIUtil::initialize()))
637        {
638            return SLANG_E_NOT_AVAILABLE;
639        }
640
641#ifdef GFX_NVAPI
642        // From DOCS: Applications are expected to bind null UAV to this slot.
643        // NOTE! We don't currently do this, but doesn't seem to be a problem.
644
645        const NvAPI_Status status =
646            NvAPI_D3D12_SetNvShaderExtnSlotSpace(m_device, NvU32(desc.nvapiExtnSlot), NvU32(0));
647
648        if (status != NVAPI_OK)
649        {
650            return SLANG_E_NOT_AVAILABLE;
651        }
652
653        if (isSupportedNVAPIOp(m_device, NV_EXTN_OP_UINT64_ATOMIC))
654        {
655            m_features.add("atomic-int64");
656        }
657        if (isSupportedNVAPIOp(m_device, NV_EXTN_OP_FP32_ATOMIC))
658        {
659            m_features.add("atomic-float");
660        }
661
662        // If we have NVAPI well assume we have realtime clock
663        {
664            m_features.add("realtime-clock");
665        }
666
667        m_nvapi = true;
668#endif
669    }
670
671    D3D12_FEATURE_DATA_SHADER_MODEL shaderModelData = {};
672
673    // Find what features are supported
674    {
675        // Check this is how this is laid out...
676        SLANG_COMPILE_TIME_ASSERT(D3D_SHADER_MODEL_6_0 == 0x60);
677
678        {
679            // CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL) can fail if the runtime/driver does
680            // not yet know the specified highest shader model. Therefore we assemble a list of
681            // shader models to check and walk it from highest to lowest to find the supported
682            // shader model.
683            Slang::ShortList<D3D_SHADER_MODEL> shaderModels;
684            if (m_extendedDesc.highestShaderModel != 0)
685                shaderModels.add((D3D_SHADER_MODEL)m_extendedDesc.highestShaderModel);
686            for (int i = SLANG_COUNT_OF(kKnownShaderModels) - 1; i >= 0; --i)
687                shaderModels.add(kKnownShaderModels[i].shaderModel);
688            for (D3D_SHADER_MODEL shaderModel : shaderModels)
689            {
690                shaderModelData.HighestShaderModel = shaderModel;
691                if (SLANG_SUCCEEDED(m_device->CheckFeatureSupport(
692                        D3D12_FEATURE_SHADER_MODEL,
693                        &shaderModelData,
694                        sizeof(shaderModelData))))
695                    break;
696            }
697
698            // TODO: Currently warp causes a crash when using half, so disable for now
699            if (m_deviceInfo.m_isWarp == false &&
700                shaderModelData.HighestShaderModel >= D3D_SHADER_MODEL_6_2)
701            {
702                // With sm_6_2 we have half
703                m_features.add("half");
704            }
705        }
706        {
707            D3D12_FEATURE_DATA_D3D12_OPTIONS options;
708            if (SLANG_SUCCEEDED(m_device->CheckFeatureSupport(
709                    D3D12_FEATURE_D3D12_OPTIONS,
710                    &options,
711                    sizeof(options))))
712            {
713                // Check double precision support
714                if (options.DoublePrecisionFloatShaderOps)
715                    m_features.add("double");
716
717                // Check conservative-rasterization support
718                auto conservativeRasterTier = options.ConservativeRasterizationTier;
719                if (conservativeRasterTier == D3D12_CONSERVATIVE_RASTERIZATION_TIER_3)
720                {
721                    m_features.add("conservative-rasterization-3");
722                    m_features.add("conservative-rasterization-2");
723                    m_features.add("conservative-rasterization-1");
724                }
725                else if (conservativeRasterTier == D3D12_CONSERVATIVE_RASTERIZATION_TIER_2)
726                {
727                    m_features.add("conservative-rasterization-2");
728                    m_features.add("conservative-rasterization-1");
729                }
730                else if (conservativeRasterTier == D3D12_CONSERVATIVE_RASTERIZATION_TIER_1)
731                {
732                    m_features.add("conservative-rasterization-1");
733                }
734
735                // Check rasterizer ordered views support
736                if (options.ROVsSupported)
737                {
738                    m_features.add("rasterizer-ordered-views");
739                }
740            }
741        }
742        {
743            D3D12_FEATURE_DATA_D3D12_OPTIONS1 options;
744            if (SLANG_SUCCEEDED(m_device->CheckFeatureSupport(
745                    D3D12_FEATURE_D3D12_OPTIONS1,
746                    &options,
747                    sizeof(options))))
748            {
749                // Check wave operations support
750                if (options.WaveOps)
751                    m_features.add("wave-ops");
752            }
753        }
754        {
755            D3D12_FEATURE_DATA_D3D12_OPTIONS2 options;
756            if (SLANG_SUCCEEDED(m_device->CheckFeatureSupport(
757                    D3D12_FEATURE_D3D12_OPTIONS2,
758                    &options,
759                    sizeof(options))))
760            {
761                // Check programmable sample positions support
762                switch (options.ProgrammableSamplePositionsTier)
763                {
764                case D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_2:
765                    m_features.add("programmable-sample-positions-2");
766                    m_features.add("programmable-sample-positions-1");
767                    break;
768                case D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_1:
769                    m_features.add("programmable-sample-positions-1");
770                    break;
771                default:
772                    break;
773                }
774            }
775        }
776        {
777            D3D12_FEATURE_DATA_D3D12_OPTIONS3 options;
778            if (SLANG_SUCCEEDED(m_device->CheckFeatureSupport(
779                    D3D12_FEATURE_D3D12_OPTIONS3,
780                    &options,
781                    sizeof(options))))
782            {
783                // Check barycentrics support
784                if (options.BarycentricsSupported)
785                {
786                    m_features.add("barycentrics");
787                }
788            }
789        }
790        // Check ray tracing support
791        {
792            D3D12_FEATURE_DATA_D3D12_OPTIONS5 options;
793            if (SLANG_SUCCEEDED(m_device->CheckFeatureSupport(
794                    D3D12_FEATURE_D3D12_OPTIONS5,
795                    &options,
796                    sizeof(options))))
797            {
798                if (options.RaytracingTier != D3D12_RAYTRACING_TIER_NOT_SUPPORTED)
799                {
800                    m_features.add("ray-tracing");
801                }
802                if (options.RaytracingTier >= D3D12_RAYTRACING_TIER_1_1)
803                {
804                    m_features.add("ray-query");
805                }
806            }
807        }
808        // Check mesh shader support
809        {
810            D3D12_FEATURE_DATA_D3D12_OPTIONS7 options;
811            if (SLANG_SUCCEEDED(m_device->CheckFeatureSupport(
812                    D3D12_FEATURE_D3D12_OPTIONS7,
813                    &options,
814                    sizeof(options))))
815            {
816                if (options.MeshShaderTier >= D3D12_MESH_SHADER_TIER_1)
817                {
818                    m_features.add("mesh-shader");
819                }
820            }
821        }
822    }
823
824    m_desc = desc;
825
826    // Create a command queue for internal resource transfer operations.
827    SLANG_RETURN_ON_FAIL(createCommandQueueImpl(m_resourceCommandQueue.writeRef()));
828    // `CommandQueueImpl` holds a back reference to `D3D12Device`, make it a weak reference here
829    // since this object is already owned by `D3D12Device`.
830    m_resourceCommandQueue->breakStrongReferenceToDevice();
831    // Retrieve timestamp frequency.
832    m_resourceCommandQueue->m_d3dQueue->GetTimestampFrequency(&m_info.timestampFrequency);
833
834    // Get device limits.
835    {
836        DeviceLimits limits = {};
837        limits.maxTextureDimension1D = D3D12_REQ_TEXTURE1D_U_DIMENSION;
838        limits.maxTextureDimension2D = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION;
839        limits.maxTextureDimension3D = D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION;
840        limits.maxTextureDimensionCube = D3D12_REQ_TEXTURECUBE_DIMENSION;
841        limits.maxTextureArrayLayers = D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION;
842
843        limits.maxVertexInputElements = D3D12_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT;
844        limits.maxVertexInputElementOffset = 256; // TODO
845        limits.maxVertexStreams = D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT;
846        limits.maxVertexStreamStride = D3D12_REQ_MULTI_ELEMENT_STRUCTURE_SIZE_IN_BYTES;
847
848        limits.maxComputeThreadsPerGroup = D3D12_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP;
849        limits.maxComputeThreadGroupSize[0] = D3D12_CS_THREAD_GROUP_MAX_X;
850        limits.maxComputeThreadGroupSize[1] = D3D12_CS_THREAD_GROUP_MAX_Y;
851        limits.maxComputeThreadGroupSize[2] = D3D12_CS_THREAD_GROUP_MAX_Z;
852        limits.maxComputeDispatchThreadGroups[0] =
853            D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION;
854        limits.maxComputeDispatchThreadGroups[1] =
855            D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION;
856        limits.maxComputeDispatchThreadGroups[2] =
857            D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION;
858
859        limits.maxViewports = D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
860        limits.maxViewportDimensions[0] = D3D12_VIEWPORT_BOUNDS_MAX;
861        limits.maxViewportDimensions[1] = D3D12_VIEWPORT_BOUNDS_MAX;
862        limits.maxFramebufferDimensions[0] = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION;
863        limits.maxFramebufferDimensions[1] = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION;
864        limits.maxFramebufferDimensions[2] = 1;
865
866        limits.maxShaderVisibleSamplers = D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE;
867
868        m_info.limits = limits;
869    }
870
871    SLANG_RETURN_ON_FAIL(createTransientResourceHeapImpl(
872        ITransientResourceHeap::Flags::AllowResizing,
873        0,
874        8,
875        4,
876        m_resourceCommandTransientHeap.writeRef()));
877    // `TransientResourceHeap` holds a back reference to `D3D12Device`, make it a weak reference
878    // here since this object is already owned by `D3D12Device`.
879    m_resourceCommandTransientHeap->breakStrongReferenceToDevice();
880
881    m_cpuViewHeap = new D3D12GeneralExpandingDescriptorHeap();
882    SLANG_RETURN_ON_FAIL(m_cpuViewHeap->init(
883        m_device,
884        1024 * 1024,
885        D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
886        D3D12_DESCRIPTOR_HEAP_FLAG_NONE));
887    m_cpuSamplerHeap = new D3D12GeneralExpandingDescriptorHeap();
888    SLANG_RETURN_ON_FAIL(m_cpuSamplerHeap->init(
889        m_device,
890        2048,
891        D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
892        D3D12_DESCRIPTOR_HEAP_FLAG_NONE));
893
894    m_rtvAllocator = new D3D12GeneralExpandingDescriptorHeap();
895    SLANG_RETURN_ON_FAIL(m_rtvAllocator->init(
896        m_device,
897        16 * 1024,
898        D3D12_DESCRIPTOR_HEAP_TYPE_RTV,
899        D3D12_DESCRIPTOR_HEAP_FLAG_NONE));
900    m_dsvAllocator = new D3D12GeneralExpandingDescriptorHeap();
901    SLANG_RETURN_ON_FAIL(m_dsvAllocator->init(
902        m_device,
903        1024,
904        D3D12_DESCRIPTOR_HEAP_TYPE_DSV,
905        D3D12_DESCRIPTOR_HEAP_FLAG_NONE));
906
907    ComPtr<IDXGIDevice> dxgiDevice;
908    if (m_deviceInfo.m_adapter)
909    {
910        DXGI_ADAPTER_DESC adapterDesc;
911        m_deviceInfo.m_adapter->GetDesc(&adapterDesc);
912        m_adapterName = String::fromWString(adapterDesc.Description);
913        m_info.adapterName = m_adapterName.begin();
914    }
915
916    // Initialize DXR interface.
917#if SLANG_GFX_HAS_DXR_SUPPORT
918    m_device->QueryInterface<ID3D12Device5>(m_deviceInfo.m_device5.writeRef());
919    m_device5 = m_deviceInfo.m_device5.get();
920#endif
921    // Check shader model version.
922    SlangCompileTarget compileTarget = SLANG_DXBC;
923    const char* profileName = "sm_5_1";
924    for (auto& sm : kKnownShaderModels)
925    {
926        if (sm.shaderModel <= shaderModelData.HighestShaderModel)
927        {
928            m_features.add(sm.profileName);
929            profileName = sm.profileName;
930            compileTarget = sm.compileTarget;
931        }
932        else
933        {
934            break;
935        }
936    }
937    // If user specified a higher shader model than what the system supports, return failure.
938    int userSpecifiedShaderModel = D3DUtil::getShaderModelFromProfileName(desc.slang.targetProfile);
939    if (userSpecifiedShaderModel > shaderModelData.HighestShaderModel)
940    {
941        getDebugCallback()->handleMessage(
942            gfx::DebugMessageType::Error,
943            gfx::DebugMessageSource::Layer,
944            "The requested shader model is not supported by the system.");
945        return SLANG_E_NOT_AVAILABLE;
946    }
947    SLANG_RETURN_ON_FAIL(slangContext.initialize(
948        desc.slang,
949        desc.extendedDescCount,
950        desc.extendedDescs,
951        compileTarget,
952        profileName,
953        makeArray(slang::PreprocessorMacroDesc{"__D3D12__", "1"}).getView()));
954
955    // Allocate a D3D12 "command signature" object that matches the behavior
956    // of a D3D11-style `DrawInstancedIndirect` operation.
957    {
958        D3D12_INDIRECT_ARGUMENT_DESC args;
959        args.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW;
960
961        D3D12_COMMAND_SIGNATURE_DESC desc;
962        desc.ByteStride = sizeof(D3D12_DRAW_ARGUMENTS);
963        desc.NumArgumentDescs = 1;
964        desc.pArgumentDescs = &args;
965        desc.NodeMask = 0;
966
967        SLANG_RETURN_ON_FAIL(m_device->CreateCommandSignature(
968            &desc,
969            nullptr,
970            IID_PPV_ARGS(drawIndirectCmdSignature.writeRef())));
971    }
972
973    // Allocate a D3D12 "command signature" object that matches the behavior
974    // of a D3D11-style `DrawIndexedInstancedIndirect` operation.
975    {
976        D3D12_INDIRECT_ARGUMENT_DESC args;
977        args.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED;
978
979        D3D12_COMMAND_SIGNATURE_DESC desc;
980        desc.ByteStride = sizeof(D3D12_DRAW_INDEXED_ARGUMENTS);
981        desc.NumArgumentDescs = 1;
982        desc.pArgumentDescs = &args;
983        desc.NodeMask = 0;
984
985        SLANG_RETURN_ON_FAIL(m_device->CreateCommandSignature(
986            &desc,
987            nullptr,
988            IID_PPV_ARGS(drawIndexedIndirectCmdSignature.writeRef())));
989    }
990
991    // Allocate a D3D12 "command signature" object that matches the behavior
992    // of a D3D11-style `Dispatch` operation.
993    {
994        D3D12_INDIRECT_ARGUMENT_DESC args;
995        args.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH;
996
997        D3D12_COMMAND_SIGNATURE_DESC desc;
998        desc.ByteStride = sizeof(D3D12_DISPATCH_ARGUMENTS);
999        desc.NumArgumentDescs = 1;
1000        desc.pArgumentDescs = &args;
1001        desc.NodeMask = 0;
1002
1003        SLANG_RETURN_ON_FAIL(m_device->CreateCommandSignature(
1004            &desc,
1005            nullptr,
1006            IID_PPV_ARGS(dispatchIndirectCmdSignature.writeRef())));
1007    }
1008    m_isInitialized = true;
1009    return SLANG_OK;
1010}
1011
1012Result DeviceImpl::createTransientResourceHeap(
1013    const ITransientResourceHeap::Desc& desc,
1014    ITransientResourceHeap** outHeap)
1015{
1016    RefPtr<TransientResourceHeapImpl> heap;
1017    SLANG_RETURN_ON_FAIL(createTransientResourceHeapImpl(
1018        desc.flags,
1019        desc.constantBufferSize,
1020        getViewDescriptorCount(desc),
1021        Math::Max(1024, desc.samplerDescriptorCount),
1022        heap.writeRef()));
1023    returnComPtr(outHeap, heap);
1024    return SLANG_OK;
1025}
1026
1027Result DeviceImpl::createCommandQueue(const ICommandQueue::Desc& desc, ICommandQueue** outQueue)
1028{
1029    RefPtr<CommandQueueImpl> queue;
1030    SLANG_RETURN_ON_FAIL(createCommandQueueImpl(queue.writeRef()));
1031    returnComPtr(outQueue, queue);
1032    return SLANG_OK;
1033}
1034
1035Result DeviceImpl::createSwapchain(
1036    const ISwapchain::Desc& desc,
1037    WindowHandle window,
1038    ISwapchain** outSwapchain)
1039{
1040    RefPtr<SwapchainImpl> swapchain = new SwapchainImpl();
1041    SLANG_RETURN_ON_FAIL(swapchain->init(this, desc, window));
1042    returnComPtr(outSwapchain, swapchain);
1043    return SLANG_OK;
1044}
1045
1046SlangResult DeviceImpl::readTextureResource(
1047    ITextureResource* resource,
1048    ResourceState state,
1049    ISlangBlob** outBlob,
1050    Size* outRowPitch,
1051    Size* outPixelSize)
1052{
1053    return captureTextureToSurface(
1054        static_cast<TextureResourceImpl*>(resource),
1055        state,
1056        outBlob,
1057        outRowPitch,
1058        outPixelSize);
1059}
1060
1061Result DeviceImpl::getTextureAllocationInfo(
1062    const ITextureResource::Desc& desc,
1063    Size* outSize,
1064    Size* outAlignment)
1065{
1066    TextureResource::Desc srcDesc = fixupTextureDesc(desc);
1067    D3D12_RESOURCE_DESC resourceDesc = {};
1068    initTextureResourceDesc(resourceDesc, srcDesc);
1069    auto allocInfo = m_device->GetResourceAllocationInfo(0, 1, &resourceDesc);
1070    *outSize = (Size)allocInfo.SizeInBytes;
1071    *outAlignment = (Size)allocInfo.Alignment;
1072    return SLANG_OK;
1073}
1074
1075Result DeviceImpl::getTextureRowAlignment(Size* outAlignment)
1076{
1077    *outAlignment = D3D12_TEXTURE_DATA_PITCH_ALIGNMENT;
1078    return SLANG_OK;
1079}
1080
1081Result DeviceImpl::createTextureResource(
1082    const ITextureResource::Desc& descIn,
1083    const ITextureResource::SubresourceData* initData,
1084    ITextureResource** outResource)
1085{
1086    // Description of uploading on Dx12
1087    // https://msdn.microsoft.com/en-us/library/windows/desktop/dn899215%28v=vs.85%29.aspx
1088
1089    TextureResource::Desc srcDesc = fixupTextureDesc(descIn);
1090
1091    D3D12_RESOURCE_DESC resourceDesc = {};
1092    initTextureResourceDesc(resourceDesc, srcDesc);
1093    const int arraySize = calcEffectiveArraySize(srcDesc);
1094    const int numMipMaps = srcDesc.numMipLevels;
1095
1096    RefPtr<TextureResourceImpl> texture(new TextureResourceImpl(srcDesc));
1097
1098    // Create the target resource
1099    {
1100        D3D12_HEAP_PROPERTIES heapProps;
1101
1102        heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
1103        heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
1104        heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
1105        heapProps.CreationNodeMask = 1;
1106        heapProps.VisibleNodeMask = 1;
1107
1108        D3D12_HEAP_FLAGS flags = D3D12_HEAP_FLAG_NONE;
1109        if (descIn.isShared)
1110            flags |= D3D12_HEAP_FLAG_SHARED;
1111
1112        D3D12_CLEAR_VALUE clearValue;
1113        D3D12_CLEAR_VALUE* clearValuePtr = nullptr;
1114        clearValue.Format = resourceDesc.Format;
1115        if (descIn.optimalClearValue)
1116        {
1117            memcpy(clearValue.Color, &descIn.optimalClearValue->color, sizeof(clearValue.Color));
1118            clearValue.DepthStencil.Depth = descIn.optimalClearValue->depthStencil.depth;
1119            clearValue.DepthStencil.Stencil = descIn.optimalClearValue->depthStencil.stencil;
1120            clearValuePtr = &clearValue;
1121        }
1122        if ((resourceDesc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET |
1123                                   D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) == 0)
1124        {
1125            clearValuePtr = nullptr;
1126        }
1127        if (isTypelessDepthFormat(resourceDesc.Format))
1128        {
1129            clearValuePtr = nullptr;
1130        }
1131        SLANG_RETURN_ON_FAIL(texture->m_resource.initCommitted(
1132            m_device,
1133            heapProps,
1134            flags,
1135            resourceDesc,
1136            D3D12_RESOURCE_STATE_COPY_DEST,
1137            clearValuePtr));
1138
1139        texture->m_resource.setDebugName(L"Texture");
1140    }
1141
1142    // Calculate the layout
1143    List<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> layouts;
1144    layouts.setCount(numMipMaps);
1145    List<UInt64> mipRowSizeInBytes;
1146    mipRowSizeInBytes.setCount(srcDesc.numMipLevels);
1147    List<UInt32> mipNumRows;
1148    mipNumRows.setCount(numMipMaps);
1149
1150    // NOTE! This is just the size for one array upload -> not for the whole texture
1151    UInt64 requiredSize = 0;
1152    m_device->GetCopyableFootprints(
1153        &resourceDesc,
1154        0,
1155        srcDesc.numMipLevels,
1156        0,
1157        layouts.begin(),
1158        mipNumRows.begin(),
1159        mipRowSizeInBytes.begin(),
1160        &requiredSize);
1161
1162    // Sub resource indexing
1163    // https://msdn.microsoft.com/en-us/library/windows/desktop/dn705766(v=vs.85).aspx#subresource_indexing
1164    if (initData)
1165    {
1166        // Create the upload texture
1167        D3D12Resource uploadTexture;
1168
1169        {
1170            D3D12_HEAP_PROPERTIES heapProps;
1171
1172            heapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
1173            heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
1174            heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
1175            heapProps.CreationNodeMask = 1;
1176            heapProps.VisibleNodeMask = 1;
1177
1178            D3D12_RESOURCE_DESC uploadResourceDesc;
1179
1180            uploadResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
1181            uploadResourceDesc.Format = DXGI_FORMAT_UNKNOWN;
1182            uploadResourceDesc.Width = requiredSize;
1183            uploadResourceDesc.Height = 1;
1184            uploadResourceDesc.DepthOrArraySize = 1;
1185            uploadResourceDesc.MipLevels = 1;
1186            uploadResourceDesc.SampleDesc.Count = 1;
1187            uploadResourceDesc.SampleDesc.Quality = 0;
1188            uploadResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
1189            uploadResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
1190            uploadResourceDesc.Alignment = 0;
1191
1192            SLANG_RETURN_ON_FAIL(uploadTexture.initCommitted(
1193                m_device,
1194                heapProps,
1195                D3D12_HEAP_FLAG_NONE,
1196                uploadResourceDesc,
1197                D3D12_RESOURCE_STATE_GENERIC_READ,
1198                nullptr));
1199
1200            uploadTexture.setDebugName(L"TextureUpload");
1201        }
1202        // Get the pointer to the upload resource
1203        ID3D12Resource* uploadResource = uploadTexture;
1204
1205        int subResourceIndex = 0;
1206        for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++)
1207        {
1208            uint8_t* p;
1209            uploadResource->Map(0, nullptr, reinterpret_cast<void**>(&p));
1210
1211            for (int j = 0; j < numMipMaps; ++j)
1212            {
1213                auto srcSubresource = initData[subResourceIndex + j];
1214
1215                const D3D12_PLACED_SUBRESOURCE_FOOTPRINT& layout = layouts[j];
1216                const D3D12_SUBRESOURCE_FOOTPRINT& footprint = layout.Footprint;
1217
1218                TextureResource::Extents mipSize = calcMipSize(srcDesc.size, j);
1219                if (gfxIsCompressedFormat(descIn.format))
1220                {
1221                    mipSize.width = int(D3DUtil::calcAligned(mipSize.width, 4));
1222                    mipSize.height = int(D3DUtil::calcAligned(mipSize.height, 4));
1223                }
1224
1225                assert(
1226                    footprint.Width == mipSize.width && footprint.Height == mipSize.height &&
1227                    footprint.Depth == mipSize.depth);
1228
1229                auto mipRowSize = mipRowSizeInBytes[j];
1230
1231                const ptrdiff_t dstMipRowPitch = ptrdiff_t(footprint.RowPitch);
1232                const ptrdiff_t srcMipRowPitch = ptrdiff_t(srcSubresource.strideY);
1233
1234                const ptrdiff_t dstMipLayerPitch = ptrdiff_t(footprint.RowPitch * footprint.Height);
1235                const ptrdiff_t srcMipLayerPitch = ptrdiff_t(srcSubresource.strideZ);
1236
1237                // Our outer loop will copy the depth layers one at a time.
1238                //
1239                const uint8_t* srcLayer = (const uint8_t*)srcSubresource.data;
1240                uint8_t* dstLayer = p + layouts[j].Offset;
1241                for (int l = 0; l < mipSize.depth; l++)
1242                {
1243                    // Our inner loop will copy the rows one at a time.
1244                    //
1245                    const uint8_t* srcRow = srcLayer;
1246                    uint8_t* dstRow = dstLayer;
1247                    int j = gfxIsCompressedFormat(descIn.format)
1248                                ? 4
1249                                : 1; // BC compressed formats are organized into 4x4 blocks
1250                    for (int k = 0; k < mipSize.height; k += j)
1251                    {
1252                        ::memcpy(dstRow, srcRow, (Size)mipRowSize);
1253
1254                        srcRow += srcMipRowPitch;
1255                        dstRow += dstMipRowPitch;
1256                    }
1257
1258                    srcLayer += srcMipLayerPitch;
1259                    dstLayer += dstMipLayerPitch;
1260                }
1261
1262                // assert(srcRow == (const uint8_t*)(srcMip.getBuffer() + srcMip.getCount()));
1263            }
1264            uploadResource->Unmap(0, nullptr);
1265
1266            auto encodeInfo = encodeResourceCommands();
1267            for (int mipIndex = 0; mipIndex < numMipMaps; ++mipIndex)
1268            {
1269                // https://msdn.microsoft.com/en-us/library/windows/desktop/dn903862(v=vs.85).aspx
1270
1271                D3D12_TEXTURE_COPY_LOCATION src;
1272                src.pResource = uploadTexture;
1273                src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
1274                src.PlacedFootprint = layouts[mipIndex];
1275
1276                D3D12_TEXTURE_COPY_LOCATION dst;
1277                dst.pResource = texture->m_resource;
1278                dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
1279                dst.SubresourceIndex = subResourceIndex;
1280                encodeInfo.d3dCommandList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr);
1281
1282                subResourceIndex++;
1283            }
1284
1285            // Block - waiting for copy to complete (so can drop upload texture)
1286            submitResourceCommandsAndWait(encodeInfo);
1287        }
1288    }
1289    {
1290        auto encodeInfo = encodeResourceCommands();
1291        {
1292            D3D12BarrierSubmitter submitter(encodeInfo.d3dCommandList);
1293            texture->m_resource.transition(
1294                D3D12_RESOURCE_STATE_COPY_DEST,
1295                texture->m_defaultState,
1296                submitter);
1297        }
1298        submitResourceCommandsAndWait(encodeInfo);
1299    }
1300
1301    returnComPtr(outResource, texture);
1302    return SLANG_OK;
1303}
1304
1305Result DeviceImpl::createTextureFromNativeHandle(
1306    InteropHandle handle,
1307    const ITextureResource::Desc& srcDesc,
1308    ITextureResource** outResource)
1309{
1310    RefPtr<TextureResourceImpl> texture(new TextureResourceImpl(srcDesc));
1311
1312    if (handle.api == InteropHandleAPI::D3D12)
1313    {
1314        texture->m_resource.setResource((ID3D12Resource*)handle.handleValue);
1315    }
1316    else
1317    {
1318        return SLANG_FAIL;
1319    }
1320
1321    returnComPtr(outResource, texture);
1322    return SLANG_OK;
1323}
1324
1325Result DeviceImpl::createBufferResource(
1326    const IBufferResource::Desc& descIn,
1327    const void* initData,
1328    IBufferResource** outResource)
1329{
1330    BufferResource::Desc srcDesc = fixupBufferDesc(descIn);
1331
1332    RefPtr<BufferResourceImpl> buffer(new BufferResourceImpl(srcDesc));
1333
1334    D3D12_RESOURCE_DESC bufferDesc;
1335    initBufferResourceDesc(descIn.sizeInBytes, bufferDesc);
1336
1337    bufferDesc.Flags |= calcResourceFlags(srcDesc.allowedStates);
1338
1339    const D3D12_RESOURCE_STATES initialState = buffer->m_defaultState;
1340    SLANG_RETURN_ON_FAIL(createBuffer(
1341        bufferDesc,
1342        initData,
1343        srcDesc.sizeInBytes,
1344        initialState,
1345        buffer->m_resource,
1346        descIn.isShared,
1347        descIn.memoryType));
1348
1349    returnComPtr(outResource, buffer);
1350    return SLANG_OK;
1351}
1352
1353Result DeviceImpl::createBufferFromNativeHandle(
1354    InteropHandle handle,
1355    const IBufferResource::Desc& srcDesc,
1356    IBufferResource** outResource)
1357{
1358    RefPtr<BufferResourceImpl> buffer(new BufferResourceImpl(srcDesc));
1359
1360    if (handle.api == InteropHandleAPI::D3D12)
1361    {
1362        buffer->m_resource.setResource((ID3D12Resource*)handle.handleValue);
1363    }
1364    else
1365    {
1366        return SLANG_FAIL;
1367    }
1368
1369    returnComPtr(outResource, buffer);
1370    return SLANG_OK;
1371}
1372
1373Result DeviceImpl::createSamplerState(ISamplerState::Desc const& desc, ISamplerState** outSampler)
1374{
1375    D3D12_FILTER_REDUCTION_TYPE dxReduction = translateFilterReduction(desc.reductionOp);
1376    D3D12_FILTER dxFilter;
1377    if (desc.maxAnisotropy > 1)
1378    {
1379        dxFilter = D3D12_ENCODE_ANISOTROPIC_FILTER(dxReduction);
1380    }
1381    else
1382    {
1383        D3D12_FILTER_TYPE dxMin = translateFilterMode(desc.minFilter);
1384        D3D12_FILTER_TYPE dxMag = translateFilterMode(desc.magFilter);
1385        D3D12_FILTER_TYPE dxMip = translateFilterMode(desc.mipFilter);
1386
1387        dxFilter = D3D12_ENCODE_BASIC_FILTER(dxMin, dxMag, dxMip, dxReduction);
1388    }
1389
1390    D3D12_SAMPLER_DESC dxDesc = {};
1391    dxDesc.Filter = dxFilter;
1392    dxDesc.AddressU = translateAddressingMode(desc.addressU);
1393    dxDesc.AddressV = translateAddressingMode(desc.addressV);
1394    dxDesc.AddressW = translateAddressingMode(desc.addressW);
1395    dxDesc.MipLODBias = desc.mipLODBias;
1396    dxDesc.MaxAnisotropy = desc.maxAnisotropy;
1397    dxDesc.ComparisonFunc = translateComparisonFunc(desc.comparisonFunc);
1398    for (int ii = 0; ii < 4; ++ii)
1399        dxDesc.BorderColor[ii] = desc.borderColor[ii];
1400    dxDesc.MinLOD = desc.minLOD;
1401    dxDesc.MaxLOD = desc.maxLOD;
1402
1403    auto& samplerHeap = m_cpuSamplerHeap;
1404
1405    D3D12Descriptor cpuDescriptor;
1406    samplerHeap->allocate(&cpuDescriptor);
1407    m_device->CreateSampler(&dxDesc, cpuDescriptor.cpuHandle);
1408
1409    // TODO: We really ought to have a free-list of sampler-heap
1410    // entries that we check before we go to the heap, and then
1411    // when we are done with a sampler we simply add it to the free list.
1412    //
1413    RefPtr<SamplerStateImpl> samplerImpl = new SamplerStateImpl();
1414    samplerImpl->m_allocator = samplerHeap;
1415    samplerImpl->m_descriptor = cpuDescriptor;
1416    returnComPtr(outSampler, samplerImpl);
1417    return SLANG_OK;
1418}
1419
1420Result DeviceImpl::createTextureView(
1421    ITextureResource* texture,
1422    IResourceView::Desc const& desc,
1423    IResourceView** outView)
1424{
1425    auto resourceImpl = (TextureResourceImpl*)texture;
1426
1427    RefPtr<ResourceViewImpl> viewImpl = new ResourceViewImpl();
1428    viewImpl->m_resource = resourceImpl;
1429    viewImpl->m_desc = desc;
1430    bool isArray = resourceImpl ? resourceImpl->getDesc()->arraySize > 1 : false;
1431    bool isMultiSample = resourceImpl ? resourceImpl->getDesc()->sampleDesc.numSamples > 1 : false;
1432    switch (desc.type)
1433    {
1434    default:
1435        return SLANG_FAIL;
1436
1437    case IResourceView::Type::RenderTarget:
1438        {
1439            SLANG_RETURN_ON_FAIL(m_rtvAllocator->allocate(&viewImpl->m_descriptor));
1440            viewImpl->m_allocator = m_rtvAllocator;
1441            D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
1442            rtvDesc.Format = D3DUtil::getMapFormat(desc.format);
1443            switch (desc.renderTarget.shape)
1444            {
1445            case IResource::Type::Texture1D:
1446                rtvDesc.ViewDimension =
1447                    isArray ? D3D12_RTV_DIMENSION_TEXTURE1DARRAY : D3D12_RTV_DIMENSION_TEXTURE1D;
1448                if (isArray)
1449                {
1450                    rtvDesc.Texture1DArray.MipSlice = desc.subresourceRange.mipLevel;
1451                    rtvDesc.Texture1DArray.FirstArraySlice = desc.subresourceRange.baseArrayLayer;
1452                    rtvDesc.Texture1DArray.ArraySize = desc.subresourceRange.layerCount;
1453                }
1454                else
1455                {
1456                    rtvDesc.Texture1D.MipSlice = desc.subresourceRange.mipLevel;
1457                }
1458
1459                break;
1460            case IResource::Type::Texture2D:
1461                if (isMultiSample)
1462                {
1463                    rtvDesc.ViewDimension = isArray ? D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY
1464                                                    : D3D12_RTV_DIMENSION_TEXTURE2DMS;
1465                    rtvDesc.Texture2DMSArray.ArraySize = desc.subresourceRange.layerCount;
1466                    rtvDesc.Texture2DMSArray.FirstArraySlice = desc.subresourceRange.baseArrayLayer;
1467                }
1468                else
1469                {
1470                    rtvDesc.ViewDimension = isArray ? D3D12_RTV_DIMENSION_TEXTURE2DARRAY
1471                                                    : D3D12_RTV_DIMENSION_TEXTURE2D;
1472                    if (isArray)
1473                    {
1474                        rtvDesc.Texture2DArray.MipSlice = desc.subresourceRange.mipLevel;
1475                        rtvDesc.Texture2DArray.ArraySize = desc.subresourceRange.layerCount;
1476                        rtvDesc.Texture2DArray.FirstArraySlice =
1477                            desc.subresourceRange.baseArrayLayer;
1478                        rtvDesc.Texture2DArray.PlaneSlice =
1479                            resourceImpl
1480                                ? D3DUtil::getPlaneSlice(
1481                                      D3DUtil::getMapFormat(resourceImpl->getDesc()->format),
1482                                      desc.subresourceRange.aspectMask)
1483                                : 0;
1484                    }
1485                    else
1486                    {
1487                        rtvDesc.Texture2D.MipSlice = desc.subresourceRange.mipLevel;
1488                        rtvDesc.Texture2D.PlaneSlice =
1489                            resourceImpl
1490                                ? D3DUtil::getPlaneSlice(
1491                                      D3DUtil::getMapFormat(resourceImpl->getDesc()->format),
1492                                      desc.subresourceRange.aspectMask)
1493                                : 0;
1494                    }
1495                }
1496                break;
1497            case IResource::Type::TextureCube:
1498                rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
1499                rtvDesc.Texture2DArray.MipSlice = desc.subresourceRange.mipLevel;
1500                rtvDesc.Texture2DArray.ArraySize = desc.subresourceRange.layerCount;
1501                rtvDesc.Texture2DArray.FirstArraySlice = desc.subresourceRange.baseArrayLayer;
1502                rtvDesc.Texture2DArray.PlaneSlice =
1503                    resourceImpl ? D3DUtil::getPlaneSlice(
1504                                       D3DUtil::getMapFormat(resourceImpl->getDesc()->format),
1505                                       desc.subresourceRange.aspectMask)
1506                                 : 0;
1507                break;
1508            case IResource::Type::Texture3D:
1509                rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;
1510                rtvDesc.Texture3D.MipSlice = desc.subresourceRange.mipLevel;
1511                rtvDesc.Texture3D.FirstWSlice = desc.subresourceRange.baseArrayLayer;
1512                rtvDesc.Texture3D.WSize =
1513                    (desc.subresourceRange.layerCount == 0) ? -1 : desc.subresourceRange.layerCount;
1514                break;
1515            case IResource::Type::Buffer:
1516                rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_BUFFER;
1517                break;
1518            default:
1519                return SLANG_FAIL;
1520            }
1521            m_device->CreateRenderTargetView(
1522                resourceImpl ? resourceImpl->m_resource.getResource() : nullptr,
1523                &rtvDesc,
1524                viewImpl->m_descriptor.cpuHandle);
1525        }
1526        break;
1527
1528    case IResourceView::Type::DepthStencil:
1529        {
1530            SLANG_RETURN_ON_FAIL(m_dsvAllocator->allocate(&viewImpl->m_descriptor));
1531            viewImpl->m_allocator = m_dsvAllocator;
1532            D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
1533            dsvDesc.Format = D3DUtil::getMapFormat(desc.format);
1534            switch (desc.renderTarget.shape)
1535            {
1536            case IResource::Type::Texture1D:
1537                dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE1D;
1538                dsvDesc.Texture1D.MipSlice = desc.subresourceRange.mipLevel;
1539                break;
1540            case IResource::Type::Texture2D:
1541                if (isMultiSample)
1542                {
1543                    dsvDesc.ViewDimension = isArray ? D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY
1544                                                    : D3D12_DSV_DIMENSION_TEXTURE2DMS;
1545                    dsvDesc.Texture2DMSArray.ArraySize = desc.subresourceRange.layerCount;
1546                    dsvDesc.Texture2DMSArray.FirstArraySlice = desc.subresourceRange.baseArrayLayer;
1547                }
1548                else
1549                {
1550                    dsvDesc.ViewDimension = isArray ? D3D12_DSV_DIMENSION_TEXTURE2DARRAY
1551                                                    : D3D12_DSV_DIMENSION_TEXTURE2D;
1552                    dsvDesc.Texture2DArray.MipSlice = desc.subresourceRange.mipLevel;
1553                    dsvDesc.Texture2DArray.ArraySize = desc.subresourceRange.layerCount;
1554                    dsvDesc.Texture2DArray.FirstArraySlice = desc.subresourceRange.baseArrayLayer;
1555                }
1556                break;
1557            case IResource::Type::TextureCube:
1558                dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
1559                dsvDesc.Texture2DArray.MipSlice = desc.subresourceRange.mipLevel;
1560                dsvDesc.Texture2DArray.ArraySize = desc.subresourceRange.layerCount;
1561                dsvDesc.Texture2DArray.FirstArraySlice = desc.subresourceRange.baseArrayLayer;
1562                break;
1563            default:
1564                return SLANG_FAIL;
1565            }
1566            m_device->CreateDepthStencilView(
1567                resourceImpl ? resourceImpl->m_resource.getResource() : nullptr,
1568                &dsvDesc,
1569                viewImpl->m_descriptor.cpuHandle);
1570        }
1571        break;
1572
1573    case IResourceView::Type::UnorderedAccess:
1574        {
1575            // TODO: need to support the separate "counter resource" for the case
1576            // of append/consume buffers with attached counters.
1577
1578            SLANG_RETURN_ON_FAIL(m_cpuViewHeap->allocate(&viewImpl->m_descriptor));
1579            viewImpl->m_allocator = m_cpuViewHeap;
1580            D3D12_UNORDERED_ACCESS_VIEW_DESC d3d12desc = {};
1581            auto& resourceDesc = *resourceImpl->getDesc();
1582            d3d12desc.Format = gfxIsTypelessFormat(texture->getDesc()->format)
1583                                   ? D3DUtil::getMapFormat(desc.format)
1584                                   : D3DUtil::getMapFormat(texture->getDesc()->format);
1585            switch (resourceImpl->getDesc()->type)
1586            {
1587            case IResource::Type::Texture1D:
1588                d3d12desc.ViewDimension =
1589                    isArray ? D3D12_UAV_DIMENSION_TEXTURE1DARRAY : D3D12_UAV_DIMENSION_TEXTURE1D;
1590                if (isArray)
1591                {
1592                    d3d12desc.Texture1DArray.MipSlice = desc.subresourceRange.mipLevel;
1593                    d3d12desc.Texture1DArray.ArraySize = desc.subresourceRange.layerCount == 0
1594                                                             ? resourceDesc.arraySize
1595                                                             : desc.subresourceRange.layerCount;
1596                    d3d12desc.Texture1DArray.FirstArraySlice = desc.subresourceRange.baseArrayLayer;
1597                }
1598                else
1599                {
1600                    d3d12desc.Texture1D.MipSlice = desc.subresourceRange.mipLevel;
1601                }
1602                break;
1603            case IResource::Type::Texture2D:
1604                d3d12desc.ViewDimension =
1605                    isArray ? D3D12_UAV_DIMENSION_TEXTURE2DARRAY : D3D12_UAV_DIMENSION_TEXTURE2D;
1606                if (isArray)
1607                {
1608                    d3d12desc.Texture2DArray.MipSlice = desc.subresourceRange.mipLevel;
1609                    d3d12desc.Texture2DArray.ArraySize = desc.subresourceRange.layerCount == 0
1610                                                             ? resourceDesc.arraySize
1611                                                             : desc.subresourceRange.layerCount;
1612                    d3d12desc.Texture2DArray.FirstArraySlice = desc.subresourceRange.baseArrayLayer;
1613                    d3d12desc.Texture2DArray.PlaneSlice =
1614                        D3DUtil::getPlaneSlice(d3d12desc.Format, desc.subresourceRange.aspectMask);
1615                }
1616                else
1617                {
1618                    d3d12desc.Texture2D.MipSlice = desc.subresourceRange.mipLevel;
1619                    d3d12desc.Texture2D.PlaneSlice =
1620                        D3DUtil::getPlaneSlice(d3d12desc.Format, desc.subresourceRange.aspectMask);
1621                }
1622                break;
1623            case IResource::Type::TextureCube:
1624                d3d12desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
1625                d3d12desc.Texture2DArray.MipSlice = desc.subresourceRange.mipLevel;
1626                d3d12desc.Texture2DArray.ArraySize = desc.subresourceRange.layerCount == 0
1627                                                         ? resourceDesc.arraySize
1628                                                         : desc.subresourceRange.layerCount;
1629                d3d12desc.Texture2DArray.FirstArraySlice = desc.subresourceRange.baseArrayLayer;
1630                d3d12desc.Texture2DArray.PlaneSlice =
1631                    D3DUtil::getPlaneSlice(d3d12desc.Format, desc.subresourceRange.aspectMask);
1632                break;
1633            case IResource::Type::Texture3D:
1634                d3d12desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
1635                d3d12desc.Texture3D.MipSlice = desc.subresourceRange.mipLevel;
1636                d3d12desc.Texture3D.FirstWSlice = desc.subresourceRange.baseArrayLayer;
1637                d3d12desc.Texture3D.WSize =
1638                    resourceDesc.size.depth >> desc.subresourceRange.mipLevel;
1639                break;
1640            default:
1641                return SLANG_FAIL;
1642            }
1643            m_device->CreateUnorderedAccessView(
1644                resourceImpl->m_resource,
1645                nullptr,
1646                &d3d12desc,
1647                viewImpl->m_descriptor.cpuHandle);
1648        }
1649        break;
1650
1651    case IResourceView::Type::ShaderResource:
1652        {
1653            SLANG_RETURN_ON_FAIL(m_cpuViewHeap->allocate(&viewImpl->m_descriptor));
1654            viewImpl->m_allocator = m_cpuViewHeap;
1655
1656            // Need to construct the D3D12_SHADER_RESOURCE_VIEW_DESC because otherwise TextureCube
1657            // is not accessed appropriately (rather than just passing nullptr to
1658            // CreateShaderResourceView)
1659            const D3D12_RESOURCE_DESC resourceDesc =
1660                resourceImpl->m_resource.getResource()->GetDesc();
1661            const DXGI_FORMAT pixelFormat = desc.format == Format::Unknown
1662                                                ? resourceDesc.Format
1663                                                : D3DUtil::getMapFormat(desc.format);
1664
1665            D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
1666            initSrvDesc(
1667                resourceImpl->getType(),
1668                *resourceImpl->getDesc(),
1669                resourceDesc,
1670                pixelFormat,
1671                desc.subresourceRange,
1672                srvDesc);
1673
1674            m_device->CreateShaderResourceView(
1675                resourceImpl->m_resource,
1676                &srvDesc,
1677                viewImpl->m_descriptor.cpuHandle);
1678        }
1679        break;
1680    }
1681
1682    returnComPtr(outView, viewImpl);
1683    return SLANG_OK;
1684}
1685
1686Result DeviceImpl::getFormatSupportedResourceStates(Format format, ResourceStateSet* outStates)
1687{
1688    D3D12_FEATURE_DATA_FORMAT_SUPPORT support;
1689    support.Format = D3DUtil::getMapFormat(format);
1690    SLANG_RETURN_ON_FAIL(
1691        m_device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &support, sizeof(support)));
1692
1693    ResourceStateSet allowedStates;
1694
1695    auto dxgi1 = support.Support1;
1696    if (dxgi1 & D3D12_FORMAT_SUPPORT1_BUFFER)
1697        allowedStates.add(ResourceState::ConstantBuffer);
1698    if (dxgi1 & D3D12_FORMAT_SUPPORT1_IA_VERTEX_BUFFER)
1699        allowedStates.add(ResourceState::VertexBuffer);
1700    if (dxgi1 & D3D12_FORMAT_SUPPORT1_IA_INDEX_BUFFER)
1701        allowedStates.add(ResourceState::IndexBuffer);
1702    if (dxgi1 & D3D12_FORMAT_SUPPORT1_SO_BUFFER)
1703        allowedStates.add(ResourceState::StreamOutput);
1704    if (dxgi1 & D3D12_FORMAT_SUPPORT1_TEXTURE1D)
1705        allowedStates.add(ResourceState::ShaderResource);
1706    if (dxgi1 & D3D12_FORMAT_SUPPORT1_TEXTURE2D)
1707        allowedStates.add(ResourceState::ShaderResource);
1708    if (dxgi1 & D3D12_FORMAT_SUPPORT1_TEXTURE3D)
1709        allowedStates.add(ResourceState::ShaderResource);
1710    if (dxgi1 & D3D12_FORMAT_SUPPORT1_TEXTURECUBE)
1711        allowedStates.add(ResourceState::ShaderResource);
1712    if (dxgi1 & D3D12_FORMAT_SUPPORT1_SHADER_LOAD)
1713        allowedStates.add(ResourceState::ShaderResource);
1714    if (dxgi1 & D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE)
1715        allowedStates.add(ResourceState::ShaderResource);
1716    if (dxgi1 & D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE_COMPARISON)
1717        allowedStates.add(ResourceState::ShaderResource);
1718    if (dxgi1 & D3D12_FORMAT_SUPPORT1_SHADER_GATHER)
1719        allowedStates.add(ResourceState::ShaderResource);
1720    if (dxgi1 & D3D12_FORMAT_SUPPORT1_SHADER_GATHER_COMPARISON)
1721        allowedStates.add(ResourceState::ShaderResource);
1722    if (dxgi1 & D3D12_FORMAT_SUPPORT1_RENDER_TARGET)
1723        allowedStates.add(ResourceState::RenderTarget);
1724    if (dxgi1 & D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL)
1725        allowedStates.add(ResourceState::DepthWrite);
1726    if (dxgi1 & D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW)
1727        allowedStates.add(ResourceState::UnorderedAccess);
1728
1729    *outStates = allowedStates;
1730    return SLANG_OK;
1731}
1732
1733Result DeviceImpl::createBufferView(
1734    IBufferResource* buffer,
1735    IBufferResource* counterBuffer,
1736    IResourceView::Desc const& desc,
1737    IResourceView** outView)
1738{
1739    auto resourceImpl = (BufferResourceImpl*)buffer;
1740    auto resourceDesc = *resourceImpl->getDesc();
1741    const auto counterResourceImpl = static_cast<BufferResourceImpl*>(counterBuffer);
1742
1743    RefPtr<ResourceViewImpl> viewImpl = new ResourceViewImpl();
1744    viewImpl->m_resource = resourceImpl;
1745    viewImpl->m_counterResource = counterResourceImpl;
1746    viewImpl->m_desc = desc;
1747
1748    // Buffer view descriptors are created on demand.
1749    viewImpl->m_descriptor = {0};
1750    viewImpl->m_allocator = m_cpuViewHeap.get();
1751
1752    returnComPtr(outView, viewImpl);
1753    return SLANG_OK;
1754}
1755
1756Result DeviceImpl::createFramebuffer(IFramebuffer::Desc const& desc, IFramebuffer** outFb)
1757{
1758    RefPtr<FramebufferImpl> framebuffer = new FramebufferImpl();
1759    framebuffer->renderTargetViews.setCount(desc.renderTargetCount);
1760    framebuffer->renderTargetDescriptors.setCount(desc.renderTargetCount);
1761    framebuffer->renderTargetClearValues.setCount(desc.renderTargetCount);
1762    for (GfxIndex i = 0; i < desc.renderTargetCount; i++)
1763    {
1764        framebuffer->renderTargetViews[i] =
1765            static_cast<ResourceViewImpl*>(desc.renderTargetViews[i]);
1766        framebuffer->renderTargetDescriptors[i] =
1767            framebuffer->renderTargetViews[i]->m_descriptor.cpuHandle;
1768        if (static_cast<ResourceViewImpl*>(desc.renderTargetViews[i])->m_resource.Ptr())
1769        {
1770            auto clearValue =
1771                static_cast<TextureResourceImpl*>(
1772                    static_cast<ResourceViewImpl*>(desc.renderTargetViews[i])->m_resource.Ptr())
1773                    ->getDesc()
1774                    ->optimalClearValue;
1775            if (clearValue)
1776            {
1777                memcpy(
1778                    &framebuffer->renderTargetClearValues[i],
1779                    &clearValue->color,
1780                    sizeof(ColorClearValue));
1781            }
1782        }
1783        else
1784        {
1785            memset(&framebuffer->renderTargetClearValues[i], 0, sizeof(ColorClearValue));
1786        }
1787    }
1788    framebuffer->depthStencilView = static_cast<ResourceViewImpl*>(desc.depthStencilView);
1789    if (desc.depthStencilView)
1790    {
1791        auto clearValue =
1792            static_cast<TextureResourceImpl*>(
1793                static_cast<ResourceViewImpl*>(desc.depthStencilView)->m_resource.Ptr())
1794                ->getDesc()
1795                ->optimalClearValue;
1796
1797        if (clearValue)
1798        {
1799            framebuffer->depthStencilClearValue = clearValue->depthStencil;
1800        }
1801        framebuffer->depthStencilDescriptor =
1802            static_cast<ResourceViewImpl*>(desc.depthStencilView)->m_descriptor.cpuHandle;
1803    }
1804    else
1805    {
1806        framebuffer->depthStencilDescriptor.ptr = 0;
1807    }
1808    returnComPtr(outFb, framebuffer);
1809    return SLANG_OK;
1810}
1811
1812Result DeviceImpl::createFramebufferLayout(
1813    IFramebufferLayout::Desc const& desc,
1814    IFramebufferLayout** outLayout)
1815{
1816    RefPtr<FramebufferLayoutImpl> layout = new FramebufferLayoutImpl();
1817    layout->m_renderTargets.setCount(desc.renderTargetCount);
1818    for (GfxIndex i = 0; i < desc.renderTargetCount; i++)
1819    {
1820        layout->m_renderTargets[i] = desc.renderTargets[i];
1821    }
1822
1823    if (desc.depthStencil)
1824    {
1825        layout->m_hasDepthStencil = true;
1826        layout->m_depthStencil = *desc.depthStencil;
1827    }
1828    else
1829    {
1830        layout->m_hasDepthStencil = false;
1831    }
1832    returnComPtr(outLayout, layout);
1833    return SLANG_OK;
1834}
1835
1836Result DeviceImpl::createRenderPassLayout(
1837    const IRenderPassLayout::Desc& desc,
1838    IRenderPassLayout** outRenderPassLayout)
1839{
1840    RefPtr<RenderPassLayoutImpl> result = new RenderPassLayoutImpl();
1841    result->init(desc);
1842    returnComPtr(outRenderPassLayout, result);
1843    return SLANG_OK;
1844}
1845
1846Result DeviceImpl::createInputLayout(IInputLayout::Desc const& desc, IInputLayout** outLayout)
1847{
1848    RefPtr<InputLayoutImpl> layout(new InputLayoutImpl);
1849
1850    // Work out a buffer size to hold all text
1851    Size textSize = 0;
1852    auto inputElementCount = desc.inputElementCount;
1853    auto inputElements = desc.inputElements;
1854    auto vertexStreamCount = desc.vertexStreamCount;
1855    auto vertexStreams = desc.vertexStreams;
1856    for (int i = 0; i < Int(inputElementCount); ++i)
1857    {
1858        const char* text = inputElements[i].semanticName;
1859        textSize += text ? (::strlen(text) + 1) : 0;
1860    }
1861    layout->m_text.setCount(textSize);
1862    char* textPos = layout->m_text.getBuffer();
1863
1864    List<D3D12_INPUT_ELEMENT_DESC>& elements = layout->m_elements;
1865    SLANG_ASSERT(inputElementCount > 0);
1866    elements.setCount(inputElementCount);
1867
1868    for (Int i = 0; i < inputElementCount; ++i)
1869    {
1870        const InputElementDesc& srcEle = inputElements[i];
1871        const auto& srcStream = vertexStreams[srcEle.bufferSlotIndex];
1872        D3D12_INPUT_ELEMENT_DESC& dstEle = elements[i];
1873
1874        // Add text to the buffer
1875        const char* semanticName = srcEle.semanticName;
1876        if (semanticName)
1877        {
1878            const int len = int(::strlen(semanticName));
1879            ::memcpy(textPos, semanticName, len + 1);
1880            semanticName = textPos;
1881            textPos += len + 1;
1882        }
1883
1884        dstEle.SemanticName = semanticName;
1885        dstEle.SemanticIndex = (UINT)srcEle.semanticIndex;
1886        dstEle.Format = D3DUtil::getMapFormat(srcEle.format);
1887        dstEle.InputSlot = (UINT)srcEle.bufferSlotIndex;
1888        dstEle.AlignedByteOffset = (UINT)srcEle.offset;
1889        dstEle.InputSlotClass = D3DUtil::getInputSlotClass(srcStream.slotClass);
1890        dstEle.InstanceDataStepRate = (UINT)srcStream.instanceDataStepRate;
1891    }
1892
1893    auto& vertexStreamStrides = layout->m_vertexStreamStrides;
1894    vertexStreamStrides.setCount(vertexStreamCount);
1895    for (GfxIndex i = 0; i < vertexStreamCount; ++i)
1896    {
1897        vertexStreamStrides[i] = (UINT)vertexStreams[i].stride;
1898    }
1899
1900    returnComPtr(outLayout, layout);
1901    return SLANG_OK;
1902}
1903
1904const gfx::DeviceInfo& DeviceImpl::getDeviceInfo() const
1905{
1906    return m_info;
1907}
1908
1909Result DeviceImpl::readBufferResource(
1910    IBufferResource* bufferIn,
1911    Offset offset,
1912    Size size,
1913    ISlangBlob** outBlob)
1914{
1915
1916    BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(bufferIn);
1917
1918    const Size bufferSize = buffer->getDesc()->sizeInBytes;
1919
1920    // This will be slow!!! - it blocks CPU on GPU completion
1921    D3D12Resource& resource = buffer->m_resource;
1922
1923    D3D12Resource stageBuf;
1924    if (buffer->getDesc()->memoryType != MemoryType::ReadBack)
1925    {
1926        auto encodeInfo = encodeResourceCommands();
1927
1928        // Readback heap
1929        D3D12_HEAP_PROPERTIES heapProps;
1930        heapProps.Type = D3D12_HEAP_TYPE_READBACK;
1931        heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
1932        heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
1933        heapProps.CreationNodeMask = 1;
1934        heapProps.VisibleNodeMask = 1;
1935
1936        // Resource to readback to
1937        D3D12_RESOURCE_DESC stagingDesc;
1938        initBufferResourceDesc(size, stagingDesc);
1939
1940        SLANG_RETURN_ON_FAIL(stageBuf.initCommitted(
1941            m_device,
1942            heapProps,
1943            D3D12_HEAP_FLAG_NONE,
1944            stagingDesc,
1945            D3D12_RESOURCE_STATE_COPY_DEST,
1946            nullptr));
1947
1948        // Do the copy
1949        encodeInfo.d3dCommandList->CopyBufferRegion(stageBuf, 0, resource, offset, size);
1950
1951        // Wait until complete
1952        submitResourceCommandsAndWait(encodeInfo);
1953    }
1954
1955    D3D12Resource& stageBufRef =
1956        buffer->getDesc()->memoryType != MemoryType::ReadBack ? stageBuf : resource;
1957
1958    // Map and copy
1959    List<uint8_t> blobData;
1960    {
1961        UINT8* data;
1962        D3D12_RANGE readRange = {0, size};
1963
1964        SLANG_RETURN_ON_FAIL(
1965            stageBufRef.getResource()->Map(0, &readRange, reinterpret_cast<void**>(&data)));
1966
1967        // Copy to memory buffer
1968        blobData.setCount(size);
1969        ::memcpy(blobData.getBuffer(), data, size);
1970
1971        stageBufRef.getResource()->Unmap(0, nullptr);
1972    }
1973    auto blob = ListBlob::moveCreate(blobData);
1974    returnComPtr(outBlob, blob);
1975    return SLANG_OK;
1976}
1977
1978Result DeviceImpl::createProgram(
1979    const IShaderProgram::Desc& desc,
1980    IShaderProgram** outProgram,
1981    ISlangBlob** outDiagnosticBlob)
1982{
1983    RefPtr<ShaderProgramImpl> shaderProgram = new ShaderProgramImpl();
1984    shaderProgram->init(desc);
1985    ComPtr<ID3DBlob> d3dDiagnosticBlob;
1986    auto rootShaderLayoutResult = RootShaderObjectLayoutImpl::create(
1987        this,
1988        shaderProgram->linkedProgram,
1989        shaderProgram->linkedProgram->getLayout(),
1990        shaderProgram->m_rootObjectLayout.writeRef(),
1991        d3dDiagnosticBlob.writeRef());
1992    if (!SLANG_SUCCEEDED(rootShaderLayoutResult))
1993    {
1994        if (outDiagnosticBlob && d3dDiagnosticBlob)
1995        {
1996            String diagnostic((const char*)d3dDiagnosticBlob->GetBufferPointer());
1997            auto diagnosticBlob = StringBlob::create(diagnostic);
1998
1999            returnComPtr(outDiagnosticBlob, diagnosticBlob);
2000        }
2001        return rootShaderLayoutResult;
2002    }
2003
2004    if (!shaderProgram->isSpecializable())
2005    {
2006        SLANG_RETURN_ON_FAIL(shaderProgram->compileShaders(this));
2007    }
2008
2009    returnComPtr(outProgram, shaderProgram);
2010    return SLANG_OK;
2011}
2012
2013Result DeviceImpl::createShaderObjectLayout(
2014    slang::ISession* session,
2015    slang::TypeLayoutReflection* typeLayout,
2016    ShaderObjectLayoutBase** outLayout)
2017{
2018    RefPtr<ShaderObjectLayoutImpl> layout;
2019    SLANG_RETURN_ON_FAIL(
2020        ShaderObjectLayoutImpl::createForElementType(this, session, typeLayout, layout.writeRef()));
2021    returnRefPtrMove(outLayout, layout);
2022    return SLANG_OK;
2023}
2024
2025Result DeviceImpl::createShaderObject(ShaderObjectLayoutBase* layout, IShaderObject** outObject)
2026{
2027    RefPtr<ShaderObjectImpl> shaderObject;
2028    SLANG_RETURN_ON_FAIL(ShaderObjectImpl::create(
2029        this,
2030        reinterpret_cast<ShaderObjectLayoutImpl*>(layout),
2031        shaderObject.writeRef()));
2032    returnComPtr(outObject, shaderObject);
2033    return SLANG_OK;
2034}
2035
2036Result DeviceImpl::createMutableShaderObject(
2037    ShaderObjectLayoutBase* layout,
2038    IShaderObject** outObject)
2039{
2040    auto result = createShaderObject(layout, outObject);
2041    SLANG_RETURN_ON_FAIL(result);
2042    static_cast<ShaderObjectImpl*>(*outObject)->m_isMutable = true;
2043    return result;
2044}
2045
2046Result DeviceImpl::createMutableRootShaderObject(IShaderProgram* program, IShaderObject** outObject)
2047{
2048    RefPtr<MutableRootShaderObjectImpl> result = new MutableRootShaderObjectImpl();
2049    result->init(this);
2050    auto programImpl = static_cast<ShaderProgramImpl*>(program);
2051    result->resetImpl(
2052        this,
2053        programImpl->m_rootObjectLayout,
2054        m_cpuViewHeap.Ptr(),
2055        m_cpuSamplerHeap.Ptr(),
2056        true);
2057    returnComPtr(outObject, result);
2058    return SLANG_OK;
2059}
2060
2061Result DeviceImpl::createShaderTable(const IShaderTable::Desc& desc, IShaderTable** outShaderTable)
2062{
2063    RefPtr<ShaderTableImpl> result = new ShaderTableImpl();
2064    result->m_device = this;
2065    result->init(desc);
2066    returnComPtr(outShaderTable, result);
2067    return SLANG_OK;
2068}
2069
2070Result DeviceImpl::createGraphicsPipelineState(
2071    const GraphicsPipelineStateDesc& desc,
2072    IPipelineState** outState)
2073{
2074    RefPtr<PipelineStateImpl> pipelineStateImpl = new PipelineStateImpl(this);
2075    pipelineStateImpl->init(desc);
2076    returnComPtr(outState, pipelineStateImpl);
2077    return SLANG_OK;
2078}
2079
2080Result DeviceImpl::createComputePipelineState(
2081    const ComputePipelineStateDesc& desc,
2082    IPipelineState** outState)
2083{
2084    RefPtr<PipelineStateImpl> pipelineStateImpl = new PipelineStateImpl(this);
2085    pipelineStateImpl->init(desc);
2086    returnComPtr(outState, pipelineStateImpl);
2087    return SLANG_OK;
2088}
2089
2090DeviceImpl::ResourceCommandRecordInfo DeviceImpl::encodeResourceCommands()
2091{
2092    ResourceCommandRecordInfo info;
2093    m_resourceCommandTransientHeap->createCommandBuffer(info.commandBuffer.writeRef());
2094    info.d3dCommandList = static_cast<CommandBufferImpl*>(info.commandBuffer.get())->m_cmdList;
2095    return info;
2096}
2097
2098void DeviceImpl::submitResourceCommandsAndWait(const DeviceImpl::ResourceCommandRecordInfo& info)
2099{
2100    info.commandBuffer->close();
2101    m_resourceCommandQueue->executeCommandBuffer(info.commandBuffer);
2102    m_resourceCommandTransientHeap->finish();
2103    m_resourceCommandTransientHeap->synchronizeAndReset();
2104}
2105
2106void DeviceImpl::processExperimentalFeaturesDesc(SharedLibrary::Handle d3dModule, void* inDesc)
2107{
2108    typedef HRESULT(WINAPI * PFN_D3D12_ENABLE_EXPERIMENTAL_FEATURES)(
2109        UINT NumFeatures,
2110        const IID* pIIDs,
2111        void* pConfigurationStructs,
2112        UINT* pConfigurationStructSizes);
2113
2114    D3D12ExperimentalFeaturesDesc desc = {};
2115    memcpy(&desc, inDesc, sizeof(desc));
2116    auto enableExperimentalFeaturesFunc = (PFN_D3D12_ENABLE_EXPERIMENTAL_FEATURES)loadProc(
2117        d3dModule,
2118        "D3D12EnableExperimentalFeatures");
2119    if (!enableExperimentalFeaturesFunc)
2120    {
2121        getDebugCallback()->handleMessage(
2122            gfx::DebugMessageType::Warning,
2123            gfx::DebugMessageSource::Layer,
2124            "cannot enable D3D12 experimental features, 'D3D12EnableExperimentalFeatures' function "
2125            "not found.");
2126        return;
2127    }
2128    if (!SLANG_SUCCEEDED(enableExperimentalFeaturesFunc(
2129            desc.numFeatures,
2130            (IID*)desc.featureIIDs,
2131            desc.configurationStructs,
2132            desc.configurationStructSizes)))
2133    {
2134        getDebugCallback()->handleMessage(
2135            gfx::DebugMessageType::Warning,
2136            gfx::DebugMessageSource::Layer,
2137            "cannot enable D3D12 experimental features, 'D3D12EnableExperimentalFeatures' call "
2138            "failed.");
2139        return;
2140    }
2141}
2142
2143Result DeviceImpl::createQueryPool(const IQueryPool::Desc& desc, IQueryPool** outState)
2144{
2145    switch (desc.type)
2146    {
2147    case QueryType::AccelerationStructureCompactedSize:
2148    case QueryType::AccelerationStructureSerializedSize:
2149    case QueryType::AccelerationStructureCurrentSize:
2150        {
2151            RefPtr<PlainBufferProxyQueryPoolImpl> queryPoolImpl =
2152                new PlainBufferProxyQueryPoolImpl();
2153            uint32_t stride = 8;
2154            if (desc.type == QueryType::AccelerationStructureSerializedSize)
2155                stride = 16;
2156            SLANG_RETURN_ON_FAIL(queryPoolImpl->init(desc, this, stride));
2157            returnComPtr(outState, queryPoolImpl);
2158            return SLANG_OK;
2159        }
2160    default:
2161        {
2162            RefPtr<QueryPoolImpl> queryPoolImpl = new QueryPoolImpl();
2163            SLANG_RETURN_ON_FAIL(queryPoolImpl->init(desc, this));
2164            returnComPtr(outState, queryPoolImpl);
2165            return SLANG_OK;
2166        }
2167    }
2168}
2169
2170Result DeviceImpl::createFence(const IFence::Desc& desc, IFence** outFence)
2171{
2172    RefPtr<FenceImpl> fence = new FenceImpl();
2173    SLANG_RETURN_ON_FAIL(fence->init(this, desc));
2174    returnComPtr(outFence, fence);
2175    return SLANG_OK;
2176}
2177
2178Result DeviceImpl::waitForFences(
2179    GfxCount fenceCount,
2180    IFence** fences,
2181    uint64_t* fenceValues,
2182    bool waitForAll,
2183    uint64_t timeout)
2184{
2185    ShortList<HANDLE> waitHandles;
2186    for (GfxCount i = 0; i < fenceCount; ++i)
2187    {
2188        auto fenceImpl = static_cast<FenceImpl*>(fences[i]);
2189        waitHandles.add(fenceImpl->getWaitEvent());
2190        SLANG_RETURN_ON_FAIL(
2191            fenceImpl->m_fence->SetEventOnCompletion(fenceValues[i], fenceImpl->getWaitEvent()));
2192    }
2193    auto result = WaitForMultipleObjects(
2194        fenceCount,
2195        waitHandles.getArrayView().getBuffer(),
2196        waitForAll ? TRUE : FALSE,
2197        timeout == kTimeoutInfinite ? INFINITE : (DWORD)(timeout / 1000000));
2198    if (result == WAIT_TIMEOUT)
2199        return SLANG_E_TIME_OUT;
2200    return result == WAIT_FAILED ? SLANG_FAIL : SLANG_OK;
2201}
2202
2203Result DeviceImpl::getAccelerationStructurePrebuildInfo(
2204    const IAccelerationStructure::BuildInputs& buildInputs,
2205    IAccelerationStructure::PrebuildInfo* outPrebuildInfo)
2206{
2207    if (!m_device5)
2208        return SLANG_E_NOT_AVAILABLE;
2209
2210    D3DAccelerationStructureInputsBuilder inputsBuilder;
2211    SLANG_RETURN_ON_FAIL(inputsBuilder.build(buildInputs, getDebugCallback()));
2212
2213    D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO prebuildInfo;
2214    m_device5->GetRaytracingAccelerationStructurePrebuildInfo(&inputsBuilder.desc, &prebuildInfo);
2215
2216    outPrebuildInfo->resultDataMaxSize = (Size)prebuildInfo.ResultDataMaxSizeInBytes;
2217    outPrebuildInfo->scratchDataSize = (Size)prebuildInfo.ScratchDataSizeInBytes;
2218    outPrebuildInfo->updateScratchDataSize = (Size)prebuildInfo.UpdateScratchDataSizeInBytes;
2219    return SLANG_OK;
2220}
2221
2222Result DeviceImpl::createAccelerationStructure(
2223    const IAccelerationStructure::CreateDesc& desc,
2224    IAccelerationStructure** outAS)
2225{
2226#if SLANG_GFX_HAS_DXR_SUPPORT
2227    assert(desc.buffer != nullptr);
2228    RefPtr<AccelerationStructureImpl> result = new AccelerationStructureImpl();
2229    result->m_device5 = m_device5;
2230    result->m_buffer = static_cast<BufferResourceImpl*>(desc.buffer);
2231    result->m_size = desc.size;
2232    result->m_offset = desc.offset;
2233    result->m_allocator = m_cpuViewHeap;
2234    result->m_desc.type = IResourceView::Type::AccelerationStructure;
2235    SLANG_RETURN_ON_FAIL(m_cpuViewHeap->allocate(&result->m_descriptor));
2236    D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
2237    srvDesc.Format = DXGI_FORMAT_UNKNOWN;
2238    srvDesc.ViewDimension = D3D12_SRV_DIMENSION_RAYTRACING_ACCELERATION_STRUCTURE;
2239    srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
2240    srvDesc.RaytracingAccelerationStructure.Location =
2241        result->m_buffer->getDeviceAddress() + desc.offset;
2242    m_device->CreateShaderResourceView(nullptr, &srvDesc, result->m_descriptor.cpuHandle);
2243    returnComPtr(outAS, result);
2244    return SLANG_OK;
2245#else
2246    *outAS = nullptr;
2247    return SLANG_FAIL;
2248#endif
2249}
2250
2251Result DeviceImpl::createRayTracingPipelineState(
2252    const RayTracingPipelineStateDesc& inDesc,
2253    IPipelineState** outState)
2254{
2255    if (!m_device5)
2256    {
2257        return SLANG_E_NOT_AVAILABLE;
2258    }
2259
2260    RefPtr<RayTracingPipelineStateImpl> pipelineStateImpl = new RayTracingPipelineStateImpl(this);
2261    pipelineStateImpl->init(inDesc);
2262    returnComPtr(outState, pipelineStateImpl);
2263    return SLANG_OK;
2264}
2265
2266Result DeviceImpl::createTransientResourceHeapImpl(
2267    ITransientResourceHeap::Flags::Enum flags,
2268    Size constantBufferSize,
2269    uint32_t viewDescriptors,
2270    uint32_t samplerDescriptors,
2271    TransientResourceHeapImpl** outHeap)
2272{
2273    RefPtr<TransientResourceHeapImpl> result = new TransientResourceHeapImpl();
2274    ITransientResourceHeap::Desc desc = {};
2275    desc.flags = flags;
2276    desc.samplerDescriptorCount = samplerDescriptors;
2277    desc.constantBufferSize = constantBufferSize;
2278    desc.constantBufferDescriptorCount = viewDescriptors;
2279    desc.accelerationStructureDescriptorCount = viewDescriptors;
2280    desc.srvDescriptorCount = viewDescriptors;
2281    desc.uavDescriptorCount = viewDescriptors;
2282    SLANG_RETURN_ON_FAIL(result->init(desc, this, viewDescriptors, samplerDescriptors));
2283    returnRefPtrMove(outHeap, result);
2284    return SLANG_OK;
2285}
2286
2287Result DeviceImpl::createCommandQueueImpl(CommandQueueImpl** outQueue)
2288{
2289    int queueIndex = m_queueIndexAllocator.alloc(1);
2290    // If we run out of queue index space, then the user is requesting too many queues.
2291    if (queueIndex == -1)
2292        return SLANG_FAIL;
2293
2294    RefPtr<CommandQueueImpl> queue = new CommandQueueImpl();
2295    SLANG_RETURN_ON_FAIL(queue->init(this, (uint32_t)queueIndex));
2296    returnRefPtrMove(outQueue, queue);
2297    return SLANG_OK;
2298}
2299
2300void* DeviceImpl::loadProc(SharedLibrary::Handle module, char const* name)
2301{
2302    void* proc = SharedLibrary::findSymbolAddressByName(module, name);
2303    if (!proc)
2304    {
2305        fprintf(stderr, "error: failed load symbol '%s'\n", name);
2306        return nullptr;
2307    }
2308    return proc;
2309}
2310
2311DeviceImpl::~DeviceImpl()
2312{
2313    m_shaderObjectLayoutCache = decltype(m_shaderObjectLayoutCache)();
2314}
2315
2316
2317} // namespace d3d12
2318} // namespace gfx