yum-mirror/slang

Making it easier to work with shaders

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

aidanfnvAdd slang-test check for D3D11 double support (#6761)28006e36d

master
66.2 KiB1886 linesraw
1// d3d11-device.cpp
2#define _CRT_SECURE_NO_WARNINGS
3#include "d3d11-device.h"
4
5#include "d3d11-buffer.h"
6#include "d3d11-helper-functions.h"
7#include "d3d11-query.h"
8#include "d3d11-resource-views.h"
9#include "d3d11-sampler.h"
10#include "d3d11-scopeNVAPI.h"
11#include "d3d11-shader-object-layout.h"
12#include "d3d11-shader-object.h"
13#include "d3d11-shader-program.h"
14#include "d3d11-swap-chain.h"
15#include "d3d11-texture.h"
16#include "d3d11-vertex-layout.h"
17
18#ifdef GFX_NV_AFTERMATH
19#include "GFSDK_Aftermath.h"
20#include "GFSDK_Aftermath_Defines.h"
21#include "GFSDK_Aftermath_GpuCrashDump.h"
22#endif
23
24namespace gfx
25{
26
27using namespace Slang;
28
29namespace d3d11
30{
31
32SlangResult DeviceImpl::initialize(const Desc& desc)
33{
34    SLANG_RETURN_ON_FAIL(slangContext.initialize(
35        desc.slang,
36        desc.extendedDescCount,
37        desc.extendedDescs,
38        SLANG_DXBC,
39        "sm_5_0",
40        makeArray(slang::PreprocessorMacroDesc{"__D3D11__", "1"}).getView()));
41
42    SLANG_RETURN_ON_FAIL(RendererBase::initialize(desc));
43
44    // Initialize DeviceInfo
45    {
46        m_info.deviceType = DeviceType::DirectX11;
47        m_info.bindingStyle = BindingStyle::DirectX;
48        m_info.projectionStyle = ProjectionStyle::DirectX;
49        m_info.apiName = "Direct3D 11";
50        static const float kIdentity[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
51        ::memcpy(m_info.identityProjectionMatrix, kIdentity, sizeof(kIdentity));
52    }
53
54    m_desc = desc;
55
56    // Rather than statically link against D3D, we load it dynamically.
57    SharedLibrary::Handle d3dModule;
58    const char* libName = SLANG_ENABLE_DXVK ? "dxvk_d3d11" : "d3d11";
59    if (SLANG_FAILED(SharedLibrary::load(libName, d3dModule)))
60    {
61        fprintf(stderr, "error: failed to load '%s'\n", libName);
62        return SLANG_FAIL;
63    }
64
65    PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN D3D11CreateDeviceAndSwapChain_ =
66        (PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN)SharedLibrary::findSymbolAddressByName(
67            d3dModule,
68            "D3D11CreateDeviceAndSwapChain");
69    if (!D3D11CreateDeviceAndSwapChain_)
70    {
71        fprintf(stderr, "error: failed load symbol 'D3D11CreateDeviceAndSwapChain'\n");
72        return SLANG_FAIL;
73    }
74
75    PFN_D3D11_CREATE_DEVICE D3D11CreateDevice_ = (PFN_D3D11_CREATE_DEVICE)
76        SharedLibrary::findSymbolAddressByName(d3dModule, "D3D11CreateDevice");
77    if (!D3D11CreateDevice_)
78    {
79        fprintf(stderr, "error: failed load symbol 'D3D11CreateDevice'\n");
80        return SLANG_FAIL;
81    }
82
83    // We will ask for the highest feature level that can be supported.
84    const D3D_FEATURE_LEVEL featureLevels[] = {
85        D3D_FEATURE_LEVEL_11_1,
86        D3D_FEATURE_LEVEL_11_0,
87        D3D_FEATURE_LEVEL_10_1,
88        D3D_FEATURE_LEVEL_10_0,
89        D3D_FEATURE_LEVEL_9_3,
90        D3D_FEATURE_LEVEL_9_2,
91        D3D_FEATURE_LEVEL_9_1,
92    };
93    D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_9_1;
94    const int totalNumFeatureLevels = SLANG_COUNT_OF(featureLevels);
95
96    {
97        // On a machine that does not have an up-to-date version of D3D installed,
98        // the `D3D11CreateDeviceAndSwapChain` call will fail with `E_INVALIDARG`
99        // if you ask for feature level 11_1 (DeviceCheckFlag::UseFullFeatureLevel).
100        // The workaround is to call `D3D11CreateDeviceAndSwapChain` the first time
101        // with 11_1 and then back off to 11_0 if that fails.
102
103        FlagCombiner combiner;
104        // TODO: we should probably provide a command-line option
105        // to override UseDebug of default rather than leave it
106        // up to each back-end to specify.
107
108#if _DEBUG
109        combiner.add(
110            DeviceCheckFlag::UseDebug,
111            ChangeType::OnOff); ///< First try debug then non debug
112#else
113        combiner.add(DeviceCheckFlag::UseDebug, ChangeType::Off); ///< Don't bother with debug
114#endif
115        combiner.add(
116            DeviceCheckFlag::UseHardwareDevice,
117            ChangeType::OnOff); ///< First try hardware, then reference
118        combiner.add(
119            DeviceCheckFlag::UseFullFeatureLevel,
120            ChangeType::OnOff); ///< First try fully featured, then degrade features
121
122
123        const int numCombinations = combiner.getNumCombinations();
124        Result res = SLANG_FAIL;
125        for (int i = 0; i < numCombinations; ++i)
126        {
127            const auto deviceCheckFlags = combiner.getCombination(i);
128            D3DUtil::createFactory(deviceCheckFlags, m_dxgiFactory);
129
130            // If we have an adapter set on the desc, look it up.
131            ComPtr<IDXGIAdapter> adapter;
132            if (desc.adapterLUID)
133            {
134                List<ComPtr<IDXGIAdapter>> dxgiAdapters;
135                D3DUtil::findAdapters(
136                    deviceCheckFlags,
137                    desc.adapterLUID,
138                    m_dxgiFactory,
139                    dxgiAdapters);
140                if (dxgiAdapters.getCount() == 0)
141                {
142                    continue;
143                }
144                adapter = dxgiAdapters[0];
145            }
146
147            // The adapter can be nullptr - that just means 'default', but when so we need to select
148            // the driver type
149            D3D_DRIVER_TYPE driverType = D3D_DRIVER_TYPE_UNKNOWN;
150            if (adapter == nullptr)
151            {
152                // If we don't have an adapter, select directly
153                driverType = (deviceCheckFlags & DeviceCheckFlag::UseHardwareDevice)
154                                 ? D3D_DRIVER_TYPE_HARDWARE
155                                 : D3D_DRIVER_TYPE_REFERENCE;
156            }
157
158            const int startFeatureIndex =
159                (deviceCheckFlags & DeviceCheckFlag::UseFullFeatureLevel) ? 0 : 1;
160            const UINT deviceFlags =
161                (deviceCheckFlags & DeviceCheckFlag::UseDebug) ? D3D11_CREATE_DEVICE_DEBUG : 0;
162
163            res = D3D11CreateDevice_(
164                adapter,
165                driverType,
166                nullptr,
167                deviceFlags,
168                &featureLevels[startFeatureIndex],
169                totalNumFeatureLevels - startFeatureIndex,
170                D3D11_SDK_VERSION,
171                m_device.writeRef(),
172                &featureLevel,
173                m_immediateContext.writeRef());
174
175#ifdef GFX_NV_AFTERMATH
176            if (SLANG_SUCCEEDED(res))
177            {
178                if (deviceCheckFlags & DeviceCheckFlag::UseDebug)
179                {
180                    // Initialize Nsight Aftermath for this device.
181                    // This combination of flags is not necessarily appropriate for real world usage
182                    const uint32_t aftermathFlags =
183                        GFSDK_Aftermath_FeatureFlags_EnableMarkers |      // Enable event marker
184                                                                          // tracking.
185                        GFSDK_Aftermath_FeatureFlags_CallStackCapturing | // Enable automatic call
186                                                                          // stack event markers.
187                        GFSDK_Aftermath_FeatureFlags_EnableResourceTracking |  // Enable tracking of
188                                                                               // resources.
189                        GFSDK_Aftermath_FeatureFlags_GenerateShaderDebugInfo | // Generate debug
190                                                                               // information for
191                                                                               // shaders.
192                        GFSDK_Aftermath_FeatureFlags_EnableShaderErrorReporting; // Enable
193                                                                                 // additional
194                                                                                 // runtime shader
195                                                                                 // error reporting.
196
197                    auto initResult = GFSDK_Aftermath_DX11_Initialize(
198                        GFSDK_Aftermath_Version_API,
199                        aftermathFlags,
200                        m_device);
201
202                    if (initResult != GFSDK_Aftermath_Result_Success)
203                    {
204                        SLANG_ASSERT_FAILURE("Unable to initialize aftermath");
205                        // Unable to initialize aftermath
206                        return SLANG_FAIL;
207                    }
208                }
209            }
210#endif
211
212            // Check if successfully constructed - if so we are done.
213            if (SLANG_SUCCEEDED(res))
214            {
215                break;
216            }
217        }
218        // If res is failure, means all styles have have failed, and so initialization fails.
219        if (SLANG_FAILED(res))
220        {
221            return res;
222        }
223        // Check we have a swap chain, context and device
224        SLANG_ASSERT(m_immediateContext && m_device);
225
226        ComPtr<IDXGIDevice> dxgiDevice;
227        if (m_device->QueryInterface(dxgiDevice.writeRef()) == 0)
228        {
229            ComPtr<IDXGIAdapter> dxgiAdapter;
230            dxgiDevice->GetAdapter(dxgiAdapter.writeRef());
231            DXGI_ADAPTER_DESC adapterDesc;
232            dxgiAdapter->GetDesc(&adapterDesc);
233            m_adapterName = String::fromWString(adapterDesc.Description);
234            m_info.adapterName = m_adapterName.begin();
235        }
236    }
237
238    // NVAPI
239    if (desc.nvapiExtnSlot >= 0)
240    {
241        if (SLANG_FAILED(NVAPIUtil::initialize()))
242        {
243            return SLANG_E_NOT_AVAILABLE;
244        }
245
246#ifdef GFX_NVAPI
247        if (NvAPI_D3D11_SetNvShaderExtnSlot(m_device, NvU32(desc.nvapiExtnSlot)) != NVAPI_OK)
248        {
249            return SLANG_E_NOT_AVAILABLE;
250        }
251
252        if (isSupportedNVAPIOp(m_device, NV_EXTN_OP_UINT64_ATOMIC))
253        {
254            m_features.add("atomic-int64");
255        }
256        if (isSupportedNVAPIOp(m_device, NV_EXTN_OP_FP32_ATOMIC))
257        {
258            m_features.add("atomic-float");
259        }
260
261        // If we have NVAPI well assume we have realtime clock
262        {
263            m_features.add("realtime-clock");
264        }
265
266        m_nvapi = true;
267#endif
268    }
269
270    // Check double precision support
271    {
272        D3D11_FEATURE_DATA_DOUBLES doublePrecisionFeature = {};
273        if (SUCCEEDED(m_device->CheckFeatureSupport(
274                D3D11_FEATURE_DOUBLES,
275                &doublePrecisionFeature,
276                sizeof(doublePrecisionFeature))) &&
277            doublePrecisionFeature.DoublePrecisionFloatShaderOps)
278        {
279            m_features.add("double");
280        }
281    }
282
283    {
284        // Create a TIMESTAMP_DISJOINT query object to query/update frequency info.
285        D3D11_QUERY_DESC disjointQueryDesc = {};
286        disjointQueryDesc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT;
287        SLANG_RETURN_ON_FAIL(m_device->CreateQuery(&disjointQueryDesc, m_disjointQuery.writeRef()));
288        m_immediateContext->Begin(m_disjointQuery);
289        m_immediateContext->End(m_disjointQuery);
290        D3D11_QUERY_DATA_TIMESTAMP_DISJOINT disjointData = {};
291        m_immediateContext->GetData(m_disjointQuery, &disjointData, sizeof(disjointData), 0);
292        m_info.timestampFrequency = disjointData.Frequency;
293    }
294
295    // Get device limits.
296    {
297        uint32_t maxTextureDimensionUV = 2048;
298        if (featureLevel >= D3D_FEATURE_LEVEL_9_3)
299            maxTextureDimensionUV = 4096;
300        if (featureLevel >= D3D_FEATURE_LEVEL_10_0)
301            maxTextureDimensionUV = 8192;
302        if (featureLevel >= D3D_FEATURE_LEVEL_11_0)
303            maxTextureDimensionUV = 16384;
304
305        uint32_t maxTextureDimensionW = 256;
306        if (featureLevel >= D3D_FEATURE_LEVEL_10_0)
307            maxTextureDimensionW = 2048;
308
309        uint32_t maxTextureDimensionCube = 512;
310        if (featureLevel >= D3D_FEATURE_LEVEL_9_3)
311            maxTextureDimensionCube = maxTextureDimensionUV;
312
313        uint32_t maxInputElements = 16;
314        if (featureLevel >= D3D_FEATURE_LEVEL_10_1)
315            maxInputElements = 32;
316
317        uint32_t maxColorAttachments = 4;
318        if (featureLevel >= D3D_FEATURE_LEVEL_10_1)
319            maxColorAttachments = 8;
320
321        uint32_t maxComputeThreadGroupSizeXY = 0;
322        uint32_t maxComputeThreadGroupSizeZ = 0;
323        uint32_t maxComputeDispatchThreadGroupsZ = 0;
324        if (featureLevel >= D3D_FEATURE_LEVEL_10_0)
325        {
326            maxComputeThreadGroupSizeXY = D3D11_CS_4_X_THREAD_GROUP_MAX_X;
327            maxComputeThreadGroupSizeZ = 1;
328            maxComputeDispatchThreadGroupsZ = 1;
329        }
330        if (featureLevel >= D3D_FEATURE_LEVEL_11_0)
331        {
332            maxComputeThreadGroupSizeXY = D3D11_CS_THREAD_GROUP_MAX_X;
333            maxComputeThreadGroupSizeZ = D3D11_CS_THREAD_GROUP_MAX_Z;
334            maxComputeDispatchThreadGroupsZ = D3D11_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION;
335        }
336
337        DeviceLimits limits = {};
338        limits.maxTextureDimension1D = maxTextureDimensionUV;
339        limits.maxTextureDimension2D = maxTextureDimensionUV;
340        limits.maxTextureDimension3D = maxTextureDimensionW;
341        limits.maxTextureDimensionCube = maxTextureDimensionCube;
342        limits.maxTextureArrayLayers = maxTextureDimensionCube;
343
344        limits.maxVertexInputElements = maxInputElements;
345        limits.maxVertexInputElementOffset = 256; // TODO
346        limits.maxVertexStreams = D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT;
347        limits.maxVertexStreamStride = D3D11_REQ_MULTI_ELEMENT_STRUCTURE_SIZE_IN_BYTES;
348
349        limits.maxComputeThreadsPerGroup = D3D11_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP;
350        limits.maxComputeThreadGroupSize[0] = maxComputeThreadGroupSizeXY;
351        limits.maxComputeThreadGroupSize[1] = maxComputeThreadGroupSizeXY;
352        limits.maxComputeThreadGroupSize[2] = maxComputeThreadGroupSizeZ;
353        limits.maxComputeDispatchThreadGroups[0] =
354            D3D11_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION;
355        limits.maxComputeDispatchThreadGroups[1] =
356            D3D11_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION;
357        limits.maxComputeDispatchThreadGroups[2] = maxComputeDispatchThreadGroupsZ;
358
359        limits.maxViewports = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
360        limits.maxViewportDimensions[0] = D3D11_VIEWPORT_BOUNDS_MAX;
361        limits.maxViewportDimensions[1] = D3D11_VIEWPORT_BOUNDS_MAX;
362        limits.maxFramebufferDimensions[0] = 4096; // TODO
363        limits.maxFramebufferDimensions[1] = 4096; // TODO
364        limits.maxFramebufferDimensions[2] = 1;
365
366        limits.maxShaderVisibleSamplers = D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT;
367
368        m_info.limits = limits;
369    }
370
371    return SLANG_OK;
372}
373
374void DeviceImpl::clearFrame(uint32_t colorBufferMask, bool clearDepth, bool clearStencil)
375{
376    uint32_t mask = 1;
377    for (auto rtv : m_currentFramebuffer->renderTargetViews)
378    {
379        if (colorBufferMask & mask)
380            m_immediateContext->ClearRenderTargetView(rtv->m_rtv, rtv->m_clearValue);
381        mask <<= 1;
382    }
383
384    if (m_currentFramebuffer->depthStencilView)
385    {
386        UINT clearFlags = 0;
387        if (clearDepth)
388            clearFlags = D3D11_CLEAR_DEPTH;
389        if (clearStencil)
390            clearFlags |= D3D11_CLEAR_STENCIL;
391        if (clearFlags)
392        {
393            m_immediateContext->ClearDepthStencilView(
394                m_currentFramebuffer->depthStencilView->m_dsv,
395                clearFlags,
396                m_currentFramebuffer->depthStencilView->m_clearValue.depth,
397                m_currentFramebuffer->depthStencilView->m_clearValue.stencil);
398        }
399    }
400}
401
402Result DeviceImpl::createSwapchain(
403    const ISwapchain::Desc& desc,
404    WindowHandle window,
405    ISwapchain** outSwapchain)
406{
407    RefPtr<SwapchainImpl> swapchain = new SwapchainImpl();
408    SLANG_RETURN_ON_FAIL(swapchain->init(this, desc, window));
409    returnComPtr(outSwapchain, swapchain);
410    return SLANG_OK;
411}
412
413Result DeviceImpl::createFramebufferLayout(
414    const IFramebufferLayout::Desc& desc,
415    IFramebufferLayout** outLayout)
416{
417    RefPtr<FramebufferLayoutImpl> layout = new FramebufferLayoutImpl();
418    layout->m_renderTargets.setCount(desc.renderTargetCount);
419    for (GfxIndex i = 0; i < desc.renderTargetCount; i++)
420    {
421        layout->m_renderTargets[i] = desc.renderTargets[i];
422    }
423
424    if (desc.depthStencil)
425    {
426        layout->m_hasDepthStencil = true;
427        layout->m_depthStencil = *desc.depthStencil;
428    }
429    else
430    {
431        layout->m_hasDepthStencil = false;
432    }
433    returnComPtr(outLayout, layout);
434    return SLANG_OK;
435}
436
437Result DeviceImpl::createFramebuffer(const IFramebuffer::Desc& desc, IFramebuffer** outFramebuffer)
438{
439    RefPtr<FramebufferImpl> framebuffer = new FramebufferImpl();
440    framebuffer->renderTargetViews.setCount(desc.renderTargetCount);
441    framebuffer->d3dRenderTargetViews.setCount(desc.renderTargetCount);
442    for (GfxIndex i = 0; i < desc.renderTargetCount; i++)
443    {
444        framebuffer->renderTargetViews[i] =
445            static_cast<RenderTargetViewImpl*>(desc.renderTargetViews[i]);
446        framebuffer->d3dRenderTargetViews[i] = framebuffer->renderTargetViews[i]->m_rtv;
447    }
448    framebuffer->depthStencilView = static_cast<DepthStencilViewImpl*>(desc.depthStencilView);
449    framebuffer->d3dDepthStencilView =
450        framebuffer->depthStencilView ? framebuffer->depthStencilView->m_dsv : nullptr;
451    returnComPtr(outFramebuffer, framebuffer);
452    return SLANG_OK;
453}
454
455void DeviceImpl::setFramebuffer(IFramebuffer* frameBuffer)
456{
457    // Note: the framebuffer state will be flushed to the pipeline as part
458    // of binding the root shader object.
459    //
460    // TODO: alternatively we could call `OMSetRenderTargets` here and then
461    // call `OMSetRenderTargetsAndUnorderedAccessViews` later with the option
462    // that preserves the existing RTV/DSV bindings.
463    //
464    m_currentFramebuffer = static_cast<FramebufferImpl*>(frameBuffer);
465}
466
467void DeviceImpl::setStencilReference(uint32_t referenceValue)
468{
469    m_stencilRef = referenceValue;
470    m_depthStencilStateDirty = true;
471}
472
473SlangResult DeviceImpl::readTextureResource(
474    ITextureResource* resource,
475    ResourceState state,
476    ISlangBlob** outBlob,
477    size_t* outRowPitch,
478    size_t* outPixelSize)
479{
480    SLANG_UNUSED(state);
481
482    auto texture = static_cast<TextureResourceImpl*>(resource);
483    // Don't bother supporting MSAA for right now
484    if (texture->getDesc()->sampleDesc.numSamples > 1)
485    {
486        fprintf(stderr, "ERROR: cannot capture multi-sample texture\n");
487        return E_INVALIDARG;
488    }
489
490    FormatInfo sizeInfo;
491    gfxGetFormatInfo(texture->getDesc()->format, &sizeInfo);
492    size_t bytesPerPixel = sizeInfo.blockSizeInBytes / sizeInfo.pixelsPerBlock;
493    size_t rowPitch = int(texture->getDesc()->size.width) * bytesPerPixel;
494    size_t bufferSize = rowPitch * int(texture->getDesc()->size.height);
495    if (outRowPitch)
496        *outRowPitch = rowPitch;
497    if (outPixelSize)
498        *outPixelSize = bytesPerPixel;
499
500    D3D11_TEXTURE2D_DESC textureDesc;
501    auto d3d11Texture = ((ID3D11Texture2D*)texture->m_resource.get());
502    d3d11Texture->GetDesc(&textureDesc);
503
504    HRESULT hr = S_OK;
505    ComPtr<ID3D11Texture2D> stagingTexture;
506
507    if (textureDesc.Usage == D3D11_USAGE_STAGING &&
508        (textureDesc.CPUAccessFlags & D3D11_CPU_ACCESS_READ))
509    {
510        stagingTexture = d3d11Texture;
511    }
512    else
513    {
514        // Modify the descriptor to give us a staging texture
515        textureDesc.BindFlags = 0;
516        textureDesc.MiscFlags &= ~D3D11_RESOURCE_MISC_TEXTURECUBE;
517        textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
518        textureDesc.Usage = D3D11_USAGE_STAGING;
519
520        hr = m_device->CreateTexture2D(&textureDesc, 0, stagingTexture.writeRef());
521        if (FAILED(hr))
522        {
523            fprintf(stderr, "ERROR: failed to create staging texture\n");
524            return hr;
525        }
526
527        m_immediateContext->CopyResource(stagingTexture, d3d11Texture);
528    }
529
530    // Now just read back texels from the staging textures
531    {
532        D3D11_MAPPED_SUBRESOURCE mappedResource;
533        SLANG_RETURN_ON_FAIL(
534            m_immediateContext->Map(stagingTexture, 0, D3D11_MAP_READ, 0, &mappedResource));
535
536        List<uint8_t> data;
537
538        data.setCount(bufferSize);
539        char* buffer = (char*)data.begin();
540        for (size_t y = 0; y < textureDesc.Height; y++)
541        {
542            memcpy(
543                (char*)buffer + y * (*outRowPitch),
544                (char*)mappedResource.pData + y * mappedResource.RowPitch,
545                *outRowPitch);
546        }
547        // Make sure to unmap
548        m_immediateContext->Unmap(stagingTexture, 0);
549
550        ComPtr<ISlangBlob> blob = ListBlob::moveCreate(data);
551
552        returnComPtr(outBlob, blob);
553        return SLANG_OK;
554    }
555}
556
557Result DeviceImpl::createTextureResource(
558    const ITextureResource::Desc& descIn,
559    const ITextureResource::SubresourceData* initData,
560    ITextureResource** outResource)
561{
562    TextureResource::Desc srcDesc = fixupTextureDesc(descIn);
563
564    const int effectiveArraySize = calcEffectiveArraySize(srcDesc);
565
566    const DXGI_FORMAT format = D3DUtil::getMapFormat(srcDesc.format);
567    if (format == DXGI_FORMAT_UNKNOWN)
568    {
569        return SLANG_FAIL;
570    }
571
572    const int bindFlags = _calcResourceBindFlags(srcDesc.allowedStates);
573
574    // Set up the initialize data
575    List<D3D11_SUBRESOURCE_DATA> subRes;
576    D3D11_SUBRESOURCE_DATA* subResourcesPtr = nullptr;
577    if (initData)
578    {
579        subRes.setCount(srcDesc.numMipLevels * effectiveArraySize);
580        {
581            int subResourceIndex = 0;
582            for (int i = 0; i < effectiveArraySize; i++)
583            {
584                for (int j = 0; j < srcDesc.numMipLevels; j++)
585                {
586                    const int mipHeight = calcMipSize(srcDesc.size.height, j);
587
588                    D3D11_SUBRESOURCE_DATA& data = subRes[subResourceIndex];
589                    auto& srcData = initData[subResourceIndex];
590
591                    data.pSysMem = srcData.data;
592                    data.SysMemPitch = UINT(srcData.strideY);
593                    data.SysMemSlicePitch = UINT(srcData.strideZ);
594
595                    subResourceIndex++;
596                }
597            }
598        }
599        subResourcesPtr = subRes.getBuffer();
600    }
601
602    const int accessFlags = _calcResourceAccessFlags(srcDesc.memoryType);
603
604    RefPtr<TextureResourceImpl> texture(new TextureResourceImpl(srcDesc));
605
606    switch (srcDesc.type)
607    {
608    case IResource::Type::Texture1D:
609        {
610            D3D11_TEXTURE1D_DESC desc = {0};
611            desc.BindFlags = bindFlags;
612            desc.CPUAccessFlags = accessFlags;
613            desc.Format = format;
614            desc.MiscFlags = 0;
615            desc.MipLevels = srcDesc.numMipLevels;
616            desc.ArraySize = effectiveArraySize;
617            desc.Width = srcDesc.size.width;
618            desc.Usage = D3D11_USAGE_DEFAULT;
619
620            ComPtr<ID3D11Texture1D> texture1D;
621            SLANG_RETURN_ON_FAIL(
622                m_device->CreateTexture1D(&desc, subResourcesPtr, texture1D.writeRef()));
623
624            texture->m_resource = texture1D;
625            break;
626        }
627    case IResource::Type::TextureCube:
628    case IResource::Type::Texture2D:
629        {
630            D3D11_TEXTURE2D_DESC desc = {0};
631            desc.BindFlags = bindFlags;
632            desc.CPUAccessFlags = accessFlags;
633            desc.Format = format;
634            desc.MiscFlags = 0;
635            desc.MipLevels = srcDesc.numMipLevels;
636            desc.ArraySize = effectiveArraySize;
637
638            desc.Width = srcDesc.size.width;
639            desc.Height = srcDesc.size.height;
640            desc.Usage = D3D11_USAGE_DEFAULT;
641            desc.SampleDesc.Count = srcDesc.sampleDesc.numSamples;
642            desc.SampleDesc.Quality = srcDesc.sampleDesc.quality;
643
644            if (srcDesc.type == IResource::Type::TextureCube)
645            {
646                desc.MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE;
647            }
648
649            ComPtr<ID3D11Texture2D> texture2D;
650            SLANG_RETURN_ON_FAIL(
651                m_device->CreateTexture2D(&desc, subResourcesPtr, texture2D.writeRef()));
652
653            texture->m_resource = texture2D;
654            break;
655        }
656    case IResource::Type::Texture3D:
657        {
658            D3D11_TEXTURE3D_DESC desc = {0};
659            desc.BindFlags = bindFlags;
660            desc.CPUAccessFlags = accessFlags;
661            desc.Format = format;
662            desc.MiscFlags = 0;
663            desc.MipLevels = srcDesc.numMipLevels;
664            desc.Width = srcDesc.size.width;
665            desc.Height = srcDesc.size.height;
666            desc.Depth = srcDesc.size.depth;
667            desc.Usage = D3D11_USAGE_DEFAULT;
668
669            ComPtr<ID3D11Texture3D> texture3D;
670            SLANG_RETURN_ON_FAIL(
671                m_device->CreateTexture3D(&desc, subResourcesPtr, texture3D.writeRef()));
672
673            texture->m_resource = texture3D;
674            break;
675        }
676    default:
677        return SLANG_FAIL;
678    }
679
680    returnComPtr(outResource, texture);
681    return SLANG_OK;
682}
683
684Result DeviceImpl::createBufferResource(
685    const IBufferResource::Desc& descIn,
686    const void* initData,
687    IBufferResource** outResource)
688{
689    IBufferResource::Desc srcDesc = fixupBufferDesc(descIn);
690
691    auto d3dBindFlags = _calcResourceBindFlags(srcDesc.allowedStates);
692
693    size_t alignedSizeInBytes = srcDesc.sizeInBytes;
694
695    if (d3dBindFlags & D3D11_BIND_CONSTANT_BUFFER)
696    {
697        // Make aligned to 256 bytes... not sure why, but if you remove this the tests do fail.
698        alignedSizeInBytes = D3DUtil::calcAligned(alignedSizeInBytes, 256);
699    }
700
701    // Hack to make the initialization never read from out of bounds memory, by copying into a
702    // buffer
703    List<uint8_t> initDataBuffer;
704    if (initData && alignedSizeInBytes > srcDesc.sizeInBytes)
705    {
706        initDataBuffer.setCount(alignedSizeInBytes);
707        ::memcpy(initDataBuffer.getBuffer(), initData, srcDesc.sizeInBytes);
708        initData = initDataBuffer.getBuffer();
709    }
710
711    D3D11_BUFFER_DESC bufferDesc = {0};
712    bufferDesc.ByteWidth = UINT(alignedSizeInBytes);
713    bufferDesc.BindFlags = d3dBindFlags;
714    // For read we'll need to do some staging
715    bufferDesc.CPUAccessFlags = _calcResourceAccessFlags(descIn.memoryType);
716    bufferDesc.Usage = D3D11_USAGE_DEFAULT;
717
718    // If written by CPU, make it dynamic
719    if (descIn.memoryType == MemoryType::Upload &&
720        !descIn.allowedStates.contains(ResourceState::UnorderedAccess))
721    {
722        bufferDesc.Usage = D3D11_USAGE_DYNAMIC;
723    }
724
725    if (srcDesc.memoryType == MemoryType::ReadBack)
726    {
727        bufferDesc.CPUAccessFlags |= D3D11_CPU_ACCESS_READ;
728        bufferDesc.Usage = D3D11_USAGE_STAGING;
729    }
730
731    switch (descIn.defaultState)
732    {
733    case ResourceState::ConstantBuffer:
734        {
735            // We'll just assume ConstantBuffers are dynamic for now
736            bufferDesc.Usage = D3D11_USAGE_DYNAMIC;
737            break;
738        }
739    default:
740        break;
741    }
742
743    if (bufferDesc.BindFlags & (D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE))
744    {
745        // desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
746        if (srcDesc.elementSize != 0)
747        {
748            bufferDesc.StructureByteStride = (UINT)srcDesc.elementSize;
749            bufferDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
750        }
751        else
752        {
753            bufferDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
754        }
755    }
756
757    if (srcDesc.memoryType == MemoryType::Upload)
758    {
759        bufferDesc.CPUAccessFlags |= D3D11_CPU_ACCESS_WRITE;
760    }
761
762    D3D11_SUBRESOURCE_DATA subResourceData = {0};
763    subResourceData.pSysMem = initData;
764
765    RefPtr<BufferResourceImpl> buffer(new BufferResourceImpl(srcDesc));
766
767    SLANG_RETURN_ON_FAIL(m_device->CreateBuffer(
768        &bufferDesc,
769        initData ? &subResourceData : nullptr,
770        buffer->m_buffer.writeRef()));
771    buffer->m_d3dUsage = bufferDesc.Usage;
772
773    if (srcDesc.memoryType == MemoryType::ReadBack || bufferDesc.Usage != D3D11_USAGE_DYNAMIC)
774    {
775        D3D11_BUFFER_DESC bufDesc = {};
776        bufDesc.BindFlags = 0;
777        bufDesc.ByteWidth = (UINT)alignedSizeInBytes;
778        bufDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
779        bufDesc.Usage = D3D11_USAGE_STAGING;
780
781        SLANG_RETURN_ON_FAIL(
782            m_device->CreateBuffer(&bufDesc, nullptr, buffer->m_staging.writeRef()));
783    }
784    returnComPtr(outResource, buffer);
785    return SLANG_OK;
786}
787
788Result DeviceImpl::createSamplerState(ISamplerState::Desc const& desc, ISamplerState** outSampler)
789{
790    D3D11_FILTER_REDUCTION_TYPE dxReduction = translateFilterReduction(desc.reductionOp);
791    D3D11_FILTER dxFilter;
792    if (desc.maxAnisotropy > 1)
793    {
794        dxFilter = D3D11_ENCODE_ANISOTROPIC_FILTER(dxReduction);
795    }
796    else
797    {
798        D3D11_FILTER_TYPE dxMin = translateFilterMode(desc.minFilter);
799        D3D11_FILTER_TYPE dxMag = translateFilterMode(desc.magFilter);
800        D3D11_FILTER_TYPE dxMip = translateFilterMode(desc.mipFilter);
801
802        dxFilter = D3D11_ENCODE_BASIC_FILTER(dxMin, dxMag, dxMip, dxReduction);
803    }
804
805    D3D11_SAMPLER_DESC dxDesc = {};
806    dxDesc.Filter = dxFilter;
807    dxDesc.AddressU = translateAddressingMode(desc.addressU);
808    dxDesc.AddressV = translateAddressingMode(desc.addressV);
809    dxDesc.AddressW = translateAddressingMode(desc.addressW);
810    dxDesc.MipLODBias = desc.mipLODBias;
811    dxDesc.MaxAnisotropy = desc.maxAnisotropy;
812    dxDesc.ComparisonFunc = translateComparisonFunc(desc.comparisonFunc);
813    for (int ii = 0; ii < 4; ++ii)
814        dxDesc.BorderColor[ii] = desc.borderColor[ii];
815    dxDesc.MinLOD = desc.minLOD;
816    dxDesc.MaxLOD = desc.maxLOD;
817
818    ComPtr<ID3D11SamplerState> sampler;
819    SLANG_RETURN_ON_FAIL(m_device->CreateSamplerState(&dxDesc, sampler.writeRef()));
820
821    RefPtr<SamplerStateImpl> samplerImpl = new SamplerStateImpl();
822    samplerImpl->m_sampler = sampler;
823    returnComPtr(outSampler, samplerImpl);
824    return SLANG_OK;
825}
826
827Result DeviceImpl::createTextureView(
828    ITextureResource* texture,
829    IResourceView::Desc const& desc,
830    IResourceView** outView)
831{
832    auto resourceImpl = (TextureResourceImpl*)texture;
833
834    switch (desc.type)
835    {
836    default:
837        return SLANG_FAIL;
838
839    case IResourceView::Type::RenderTarget:
840        {
841            ComPtr<ID3D11RenderTargetView> rtv;
842            SLANG_RETURN_ON_FAIL(m_device->CreateRenderTargetView(
843                resourceImpl->m_resource,
844                nullptr,
845                rtv.writeRef()));
846
847            RefPtr<RenderTargetViewImpl> viewImpl = new RenderTargetViewImpl();
848            viewImpl->m_type = ResourceViewImpl::Type::RTV;
849            viewImpl->m_rtv = rtv;
850            viewImpl->m_desc = desc;
851            if (resourceImpl->getDesc()->optimalClearValue)
852            {
853                memcpy(
854                    viewImpl->m_clearValue,
855                    &resourceImpl->getDesc()->optimalClearValue->color,
856                    sizeof(float) * 4);
857            }
858            returnComPtr(outView, viewImpl);
859            return SLANG_OK;
860        }
861        break;
862
863    case IResourceView::Type::DepthStencil:
864        {
865            ComPtr<ID3D11DepthStencilView> dsv;
866            SLANG_RETURN_ON_FAIL(m_device->CreateDepthStencilView(
867                resourceImpl->m_resource,
868                nullptr,
869                dsv.writeRef()));
870
871            RefPtr<DepthStencilViewImpl> viewImpl = new DepthStencilViewImpl();
872            viewImpl->m_type = ResourceViewImpl::Type::DSV;
873            viewImpl->m_dsv = dsv;
874            if (resourceImpl->getDesc()->optimalClearValue)
875                viewImpl->m_clearValue = resourceImpl->getDesc()->optimalClearValue->depthStencil;
876            viewImpl->m_desc = desc;
877
878            returnComPtr(outView, viewImpl);
879            return SLANG_OK;
880        }
881        break;
882
883    case IResourceView::Type::UnorderedAccess:
884        {
885            ComPtr<ID3D11UnorderedAccessView> uav;
886            SLANG_RETURN_ON_FAIL(m_device->CreateUnorderedAccessView(
887                resourceImpl->m_resource,
888                nullptr,
889                uav.writeRef()));
890
891            RefPtr<UnorderedAccessViewImpl> viewImpl = new UnorderedAccessViewImpl();
892            viewImpl->m_type = ResourceViewImpl::Type::UAV;
893            viewImpl->m_uav = uav;
894            viewImpl->m_desc = desc;
895
896            returnComPtr(outView, viewImpl);
897            return SLANG_OK;
898        }
899        break;
900
901    case IResourceView::Type::ShaderResource:
902        {
903            D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
904            initSrvDesc(
905                resourceImpl->getType(),
906                *resourceImpl->getDesc(),
907                D3DUtil::getMapFormat(desc.format),
908                srvDesc);
909
910            ComPtr<ID3D11ShaderResourceView> srv;
911            SLANG_RETURN_ON_FAIL(m_device->CreateShaderResourceView(
912                resourceImpl->m_resource,
913                &srvDesc,
914                srv.writeRef()));
915
916            RefPtr<ShaderResourceViewImpl> viewImpl = new ShaderResourceViewImpl();
917            viewImpl->m_type = ResourceViewImpl::Type::SRV;
918            viewImpl->m_srv = srv;
919            viewImpl->m_desc = desc;
920
921            returnComPtr(outView, viewImpl);
922            return SLANG_OK;
923        }
924        break;
925    }
926}
927
928Result DeviceImpl::createBufferView(
929    IBufferResource* buffer,
930    IBufferResource* counterBuffer,
931    IResourceView::Desc const& desc,
932    IResourceView** outView)
933{
934    auto resourceImpl = (BufferResourceImpl*)buffer;
935    auto resourceDesc = *resourceImpl->getDesc();
936
937    switch (desc.type)
938    {
939    default:
940        return SLANG_FAIL;
941
942    case IResourceView::Type::UnorderedAccess:
943        {
944            D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
945            uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
946            uavDesc.Format = D3DUtil::getMapFormat(desc.format);
947            uavDesc.Buffer.FirstElement = 0;
948
949            if (resourceDesc.elementSize)
950            {
951                uavDesc.Buffer.NumElements =
952                    UINT(resourceDesc.sizeInBytes / resourceDesc.elementSize);
953            }
954            else if (desc.format == Format::Unknown)
955            {
956                uavDesc.Buffer.Flags |= D3D11_BUFFER_UAV_FLAG_RAW;
957                uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
958                uavDesc.Buffer.NumElements = UINT(resourceDesc.sizeInBytes / 4);
959            }
960            else
961            {
962                FormatInfo sizeInfo;
963                gfxGetFormatInfo(desc.format, &sizeInfo);
964                uavDesc.Buffer.NumElements = UINT(
965                    resourceDesc.sizeInBytes /
966                    (sizeInfo.blockSizeInBytes / sizeInfo.pixelsPerBlock));
967            }
968
969            ComPtr<ID3D11UnorderedAccessView> uav;
970            SLANG_RETURN_ON_FAIL(m_device->CreateUnorderedAccessView(
971                resourceImpl->m_buffer,
972                &uavDesc,
973                uav.writeRef()));
974
975            RefPtr<UnorderedAccessViewImpl> viewImpl = new UnorderedAccessViewImpl();
976            viewImpl->m_type = ResourceViewImpl::Type::UAV;
977            viewImpl->m_uav = uav;
978            viewImpl->m_desc = desc;
979
980            returnComPtr(outView, viewImpl);
981            return SLANG_OK;
982        }
983        break;
984
985    case IResourceView::Type::ShaderResource:
986        {
987            D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
988            srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
989            srvDesc.Format = D3DUtil::getMapFormat(desc.format);
990            srvDesc.Buffer.FirstElement = 0;
991
992            if (resourceDesc.elementSize)
993            {
994                srvDesc.Buffer.NumElements =
995                    UINT(resourceDesc.sizeInBytes / resourceDesc.elementSize);
996            }
997            else if (desc.format == Format::Unknown)
998            {
999                // We need to switch to a different member of the `union`,
1000                // so that we can set the `BufferEx.Flags` member.
1001                //
1002                srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX;
1003
1004                // Because we've switched, we need to re-set the `FirstElement`
1005                // field to be valid, since we can't count on all compilers
1006                // to respect that `Buffer.FirstElement` and `BufferEx.FirstElement`
1007                // alias in memory.
1008                //
1009                srvDesc.BufferEx.FirstElement = 0;
1010
1011                srvDesc.BufferEx.Flags = D3D11_BUFFEREX_SRV_FLAG_RAW;
1012                srvDesc.Format = DXGI_FORMAT_R32_TYPELESS;
1013                srvDesc.BufferEx.NumElements = UINT(resourceDesc.sizeInBytes / 4);
1014            }
1015            else
1016            {
1017                FormatInfo sizeInfo;
1018                gfxGetFormatInfo(desc.format, &sizeInfo);
1019                srvDesc.Buffer.NumElements = UINT(
1020                    resourceDesc.sizeInBytes /
1021                    (sizeInfo.blockSizeInBytes / sizeInfo.pixelsPerBlock));
1022            }
1023
1024            ComPtr<ID3D11ShaderResourceView> srv;
1025            SLANG_RETURN_ON_FAIL(m_device->CreateShaderResourceView(
1026                resourceImpl->m_buffer,
1027                &srvDesc,
1028                srv.writeRef()));
1029
1030            RefPtr<ShaderResourceViewImpl> viewImpl = new ShaderResourceViewImpl();
1031            viewImpl->m_type = ResourceViewImpl::Type::SRV;
1032            viewImpl->m_srv = srv;
1033            viewImpl->m_desc = desc;
1034            returnComPtr(outView, viewImpl);
1035            return SLANG_OK;
1036        }
1037        break;
1038    }
1039}
1040
1041Result DeviceImpl::createInputLayout(IInputLayout::Desc const& desc, IInputLayout** outLayout)
1042{
1043    D3D11_INPUT_ELEMENT_DESC inputElements[16] = {};
1044
1045    char hlslBuffer[1024];
1046    char* hlslCursor = &hlslBuffer[0];
1047
1048    hlslCursor += sprintf(hlslCursor, "float4 main(\n");
1049
1050    auto inputElementCount = desc.inputElementCount;
1051    auto inputElementsIn = desc.inputElements;
1052    for (Int ii = 0; ii < inputElementCount; ++ii)
1053    {
1054        auto vertexStreamIndex = inputElementsIn[ii].bufferSlotIndex;
1055        auto& vertexStream = desc.vertexStreams[vertexStreamIndex];
1056
1057        inputElements[ii].SemanticName = inputElementsIn[ii].semanticName;
1058        inputElements[ii].SemanticIndex = (UINT)inputElementsIn[ii].semanticIndex;
1059        inputElements[ii].Format = D3DUtil::getMapFormat(inputElementsIn[ii].format);
1060        inputElements[ii].InputSlot = (UINT)vertexStreamIndex;
1061        inputElements[ii].AlignedByteOffset = (UINT)inputElementsIn[ii].offset;
1062        inputElements[ii].InputSlotClass = (vertexStream.slotClass == InputSlotClass::PerInstance)
1063                                               ? D3D11_INPUT_PER_INSTANCE_DATA
1064                                               : D3D11_INPUT_PER_VERTEX_DATA;
1065        inputElements[ii].InstanceDataStepRate = (UINT)vertexStream.instanceDataStepRate;
1066
1067        if (ii != 0)
1068        {
1069            hlslCursor += sprintf(hlslCursor, ",\n");
1070        }
1071
1072        char const* typeName = "Unknown";
1073        switch (inputElementsIn[ii].format)
1074        {
1075        case Format::R32G32B32A32_FLOAT:
1076        case Format::R8G8B8A8_UNORM:
1077            typeName = "float4";
1078            break;
1079        case Format::R32G32B32_FLOAT:
1080            typeName = "float3";
1081            break;
1082        case Format::R32G32_FLOAT:
1083            typeName = "float2";
1084            break;
1085        case Format::R32_FLOAT:
1086            typeName = "float";
1087            break;
1088        default:
1089            return SLANG_FAIL;
1090        }
1091
1092        hlslCursor += sprintf(
1093            hlslCursor,
1094            "%s a%d : %s%d",
1095            typeName,
1096            (int)ii,
1097            inputElementsIn[ii].semanticName,
1098            (int)inputElementsIn[ii].semanticIndex);
1099    }
1100
1101    hlslCursor += sprintf(hlslCursor, "\n) : SV_Position { return 0; }");
1102
1103    ComPtr<ID3DBlob> vertexShaderBlob;
1104    SLANG_RETURN_ON_FAIL(
1105        D3DUtil::compileHLSLShader("inputLayout", hlslBuffer, "main", "vs_5_0", vertexShaderBlob));
1106
1107    ComPtr<ID3D11InputLayout> inputLayout;
1108    SLANG_RETURN_ON_FAIL(m_device->CreateInputLayout(
1109        &inputElements[0],
1110        (UINT)inputElementCount,
1111        vertexShaderBlob->GetBufferPointer(),
1112        vertexShaderBlob->GetBufferSize(),
1113        inputLayout.writeRef()));
1114
1115    RefPtr<InputLayoutImpl> impl = new InputLayoutImpl;
1116    impl->m_layout.swap(inputLayout);
1117
1118    auto vertexStreamCount = desc.vertexStreamCount;
1119    impl->m_vertexStreamStrides.setCount(vertexStreamCount);
1120    for (Int i = 0; i < vertexStreamCount; ++i)
1121    {
1122        impl->m_vertexStreamStrides[i] = (UINT)desc.vertexStreams[i].stride;
1123    }
1124
1125    returnComPtr(outLayout, impl);
1126    return SLANG_OK;
1127}
1128
1129Result DeviceImpl::createQueryPool(const IQueryPool::Desc& desc, IQueryPool** outPool)
1130{
1131    RefPtr<QueryPoolImpl> result = new QueryPoolImpl();
1132    SLANG_RETURN_ON_FAIL(result->init(desc, this));
1133    returnComPtr(outPool, result);
1134    return SLANG_OK;
1135}
1136
1137void* DeviceImpl::map(IBufferResource* bufferIn, MapFlavor flavor)
1138{
1139    BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(bufferIn);
1140
1141    D3D11_MAP mapType;
1142    ID3D11Buffer* buffer = bufferResource->m_buffer;
1143
1144    switch (flavor)
1145    {
1146    case MapFlavor::WriteDiscard:
1147        mapType = D3D11_MAP_WRITE_DISCARD;
1148        break;
1149    case MapFlavor::HostWrite:
1150        mapType = D3D11_MAP_WRITE_NO_OVERWRITE;
1151        break;
1152    case MapFlavor::HostRead:
1153        mapType = D3D11_MAP_READ;
1154        break;
1155    default:
1156        return nullptr;
1157    }
1158
1159    bufferResource->m_mapFlavor = flavor;
1160
1161    switch (flavor)
1162    {
1163    case MapFlavor::WriteDiscard:
1164    case MapFlavor::HostWrite:
1165        // If buffer is not dynamic, we need to use staging buffer.
1166        if (bufferResource->m_d3dUsage != D3D11_USAGE_DYNAMIC)
1167        {
1168            bufferResource->m_uploadStagingBuffer.setCount(bufferResource->getDesc()->sizeInBytes);
1169            return bufferResource->m_uploadStagingBuffer.getBuffer();
1170        }
1171        break;
1172    case MapFlavor::HostRead:
1173        buffer = bufferResource->m_staging;
1174        if (!buffer)
1175        {
1176            return nullptr;
1177        }
1178
1179        // Okay copy the data over
1180        m_immediateContext->CopyResource(buffer, bufferResource->m_buffer);
1181    }
1182
1183    // We update our constant buffer per-frame, just for the purposes
1184    // of the example, but we don't actually load different data
1185    // per-frame (we always use an identity projection).
1186    D3D11_MAPPED_SUBRESOURCE mappedSub;
1187    SLANG_RETURN_NULL_ON_FAIL(m_immediateContext->Map(buffer, 0, mapType, 0, &mappedSub));
1188
1189    return mappedSub.pData;
1190}
1191
1192void DeviceImpl::unmap(IBufferResource* bufferIn, size_t offsetWritten, size_t sizeWritten)
1193{
1194    BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(bufferIn);
1195    switch (bufferResource->m_mapFlavor)
1196    {
1197    case MapFlavor::WriteDiscard:
1198    case MapFlavor::HostWrite:
1199        // If buffer is not dynamic, the CPU has already written to the staging buffer,
1200        // and we need to copy the content over to the GPU buffer.
1201        if (bufferResource->m_d3dUsage != D3D11_USAGE_DYNAMIC && sizeWritten != 0)
1202        {
1203            D3D11_BOX dstBox = {};
1204            dstBox.left = (UINT)offsetWritten;
1205            dstBox.right = (UINT)(offsetWritten + sizeWritten);
1206            dstBox.back = 1;
1207            dstBox.bottom = 1;
1208            m_immediateContext->UpdateSubresource(
1209                bufferResource->m_buffer,
1210                0,
1211                &dstBox,
1212                bufferResource->m_uploadStagingBuffer.getBuffer() + offsetWritten,
1213                0,
1214                0);
1215            return;
1216        }
1217    }
1218    m_immediateContext->Unmap(
1219        bufferResource->m_mapFlavor == MapFlavor::HostRead ? bufferResource->m_staging
1220                                                           : bufferResource->m_buffer,
1221        0);
1222}
1223
1224#if 0
1225void D3D11Device::setInputLayout(InputLayout* inputLayoutIn)
1226{
1227    auto inputLayout = static_cast<InputLayoutImpl*>(inputLayoutIn);
1228    m_immediateContext->IASetInputLayout(inputLayout->m_layout);
1229}
1230#endif
1231
1232void DeviceImpl::setPrimitiveTopology(PrimitiveTopology topology)
1233{
1234    m_immediateContext->IASetPrimitiveTopology(D3DUtil::getPrimitiveTopology(topology));
1235}
1236
1237void DeviceImpl::setVertexBuffers(
1238    GfxIndex startSlot,
1239    GfxCount slotCount,
1240    IBufferResource* const* buffersIn,
1241    const Offset* offsetsIn)
1242{
1243    static const int kMaxVertexBuffers = 16;
1244    assert(slotCount <= kMaxVertexBuffers);
1245    assert(m_currentPipelineState); // The pipeline state should be created before setting vertex
1246                                    // buffers.
1247
1248    UINT vertexStrides[kMaxVertexBuffers];
1249    UINT vertexOffsets[kMaxVertexBuffers];
1250    ID3D11Buffer* dxBuffers[kMaxVertexBuffers];
1251
1252    auto buffers = (BufferResourceImpl* const*)buffersIn;
1253
1254    for (GfxIndex ii = 0; ii < slotCount; ++ii)
1255    {
1256        auto inputLayout = (InputLayoutImpl*)m_currentPipelineState->inputLayout.Ptr();
1257        vertexStrides[ii] = inputLayout->m_vertexStreamStrides[startSlot + ii];
1258        vertexOffsets[ii] = (UINT)offsetsIn[ii];
1259        dxBuffers[ii] = buffers[ii]->m_buffer;
1260    }
1261
1262    m_immediateContext->IASetVertexBuffers(
1263        (UINT)startSlot,
1264        (UINT)slotCount,
1265        dxBuffers,
1266        &vertexStrides[0],
1267        &vertexOffsets[0]);
1268}
1269
1270void DeviceImpl::setIndexBuffer(IBufferResource* buffer, Format indexFormat, Offset offset)
1271{
1272    DXGI_FORMAT dxFormat = D3DUtil::getMapFormat(indexFormat);
1273    m_immediateContext->IASetIndexBuffer(
1274        ((BufferResourceImpl*)buffer)->m_buffer,
1275        dxFormat,
1276        UINT(offset));
1277}
1278
1279void DeviceImpl::setViewports(GfxCount count, Viewport const* viewports)
1280{
1281    static const int kMaxViewports = D3D11_VIEWPORT_AND_SCISSORRECT_MAX_INDEX + 1;
1282    assert(count <= kMaxViewports);
1283
1284    D3D11_VIEWPORT dxViewports[kMaxViewports];
1285    for (GfxIndex ii = 0; ii < count; ++ii)
1286    {
1287        auto& inViewport = viewports[ii];
1288        auto& dxViewport = dxViewports[ii];
1289
1290        dxViewport.TopLeftX = inViewport.originX;
1291        dxViewport.TopLeftY = inViewport.originY;
1292        dxViewport.Width = inViewport.extentX;
1293        dxViewport.Height = inViewport.extentY;
1294        dxViewport.MinDepth = inViewport.minZ;
1295        dxViewport.MaxDepth = inViewport.maxZ;
1296    }
1297
1298    m_immediateContext->RSSetViewports(UINT(count), dxViewports);
1299}
1300
1301void DeviceImpl::setScissorRects(GfxCount count, ScissorRect const* rects)
1302{
1303    static const int kMaxScissorRects = D3D11_VIEWPORT_AND_SCISSORRECT_MAX_INDEX + 1;
1304    assert(count <= kMaxScissorRects);
1305
1306    D3D11_RECT dxRects[kMaxScissorRects];
1307    for (GfxIndex ii = 0; ii < count; ++ii)
1308    {
1309        auto& inRect = rects[ii];
1310        auto& dxRect = dxRects[ii];
1311
1312        dxRect.left = LONG(inRect.minX);
1313        dxRect.top = LONG(inRect.minY);
1314        dxRect.right = LONG(inRect.maxX);
1315        dxRect.bottom = LONG(inRect.maxY);
1316    }
1317
1318    m_immediateContext->RSSetScissorRects(UINT(count), dxRects);
1319}
1320
1321
1322void DeviceImpl::setPipelineState(IPipelineState* state)
1323{
1324    auto pipelineType = static_cast<PipelineStateBase*>(state)->desc.type;
1325
1326    switch (pipelineType)
1327    {
1328    default:
1329        break;
1330
1331    case PipelineType::Graphics:
1332        {
1333            auto stateImpl = (GraphicsPipelineStateImpl*)state;
1334            auto programImpl = static_cast<ShaderProgramImpl*>(stateImpl->m_program.Ptr());
1335
1336            // TODO: We could conceivably do some lightweight state
1337            // differencing here (e.g., check if `programImpl` is the
1338            // same as the program that is currently bound).
1339            //
1340            // It isn't clear how much that would pay off given that
1341            // the D3D11 runtime seems to do its own state diffing.
1342
1343            // IA
1344
1345            m_immediateContext->IASetInputLayout(stateImpl->m_inputLayout->m_layout);
1346
1347            // VS
1348
1349            // TODO(tfoley): Why the conditional here? If somebody is trying to disable the VS or
1350            // PS, shouldn't we respect that?
1351            if (programImpl->m_vertexShader)
1352                m_immediateContext->VSSetShader(programImpl->m_vertexShader, nullptr, 0);
1353
1354            // HS
1355
1356            // DS
1357
1358            // GS
1359
1360            // RS
1361
1362            m_immediateContext->RSSetState(stateImpl->m_rasterizerState);
1363
1364            // PS
1365            if (programImpl->m_pixelShader)
1366                m_immediateContext->PSSetShader(programImpl->m_pixelShader, nullptr, 0);
1367
1368            // OM
1369
1370            m_immediateContext->OMSetBlendState(
1371                stateImpl->m_blendState,
1372                stateImpl->m_blendColor,
1373                stateImpl->m_sampleMask);
1374
1375            m_currentPipelineState = stateImpl;
1376
1377            m_depthStencilStateDirty = true;
1378        }
1379        break;
1380
1381    case PipelineType::Compute:
1382        {
1383            auto stateImpl = (ComputePipelineStateImpl*)state;
1384            auto programImpl = static_cast<ShaderProgramImpl*>(stateImpl->m_program.Ptr());
1385
1386            // CS
1387
1388            m_immediateContext->CSSetShader(programImpl->m_computeShader, nullptr, 0);
1389            m_currentPipelineState = stateImpl;
1390        }
1391        break;
1392    }
1393
1394    /// ...
1395}
1396
1397void DeviceImpl::draw(GfxCount vertexCount, GfxIndex startVertex)
1398{
1399    _flushGraphicsState();
1400    m_immediateContext->Draw(vertexCount, startVertex);
1401}
1402
1403void DeviceImpl::drawIndexed(GfxCount indexCount, GfxIndex startIndex, GfxIndex baseVertex)
1404{
1405    _flushGraphicsState();
1406    m_immediateContext->DrawIndexed(indexCount, startIndex, baseVertex);
1407}
1408
1409void DeviceImpl::drawInstanced(
1410    GfxCount vertexCount,
1411    GfxCount instanceCount,
1412    GfxIndex startVertex,
1413    GfxIndex startInstanceLocation)
1414{
1415    _flushGraphicsState();
1416    m_immediateContext
1417        ->DrawInstanced(vertexCount, instanceCount, startVertex, startInstanceLocation);
1418}
1419
1420void DeviceImpl::drawIndexedInstanced(
1421    GfxCount indexCount,
1422    GfxCount instanceCount,
1423    GfxIndex startIndexLocation,
1424    GfxIndex baseVertexLocation,
1425    GfxIndex startInstanceLocation)
1426{
1427    _flushGraphicsState();
1428    m_immediateContext->DrawIndexedInstanced(
1429        indexCount,
1430        instanceCount,
1431        startIndexLocation,
1432        baseVertexLocation,
1433        startInstanceLocation);
1434}
1435
1436Result DeviceImpl::createProgram(
1437    const IShaderProgram::Desc& desc,
1438    IShaderProgram** outProgram,
1439    ISlangBlob** outDiagnosticBlob)
1440{
1441    SLANG_ASSERT(desc.slangGlobalScope);
1442
1443    if (desc.slangGlobalScope->getSpecializationParamCount() != 0)
1444    {
1445        // For a specializable program, we don't invoke any actual slang compilation yet.
1446        RefPtr<ShaderProgramImpl> shaderProgram = new ShaderProgramImpl();
1447        shaderProgram->init(desc);
1448        returnComPtr(outProgram, shaderProgram);
1449        return SLANG_OK;
1450    }
1451
1452    // If the program is already specialized, compile and create shader kernels now.
1453    SlangInt targetIndex = 0;
1454    auto slangGlobalScope = desc.slangGlobalScope;
1455    auto programLayout = slangGlobalScope->getLayout(targetIndex);
1456    if (!programLayout)
1457        return SLANG_FAIL;
1458    SlangUInt entryPointCount = programLayout->getEntryPointCount();
1459    if (entryPointCount == 0)
1460        return SLANG_FAIL;
1461
1462    RefPtr<ShaderProgramImpl> shaderProgram = new ShaderProgramImpl();
1463    shaderProgram->slangGlobalScope = desc.slangGlobalScope;
1464
1465    ScopeNVAPI scopeNVAPI;
1466    SLANG_RETURN_ON_FAIL(scopeNVAPI.init(this, 0));
1467    for (SlangUInt i = 0; i < entryPointCount; i++)
1468    {
1469        ComPtr<ISlangBlob> kernelCode;
1470        ComPtr<ISlangBlob> diagnostics;
1471
1472        auto compileResult = getEntryPointCodeFromShaderCache(
1473            slangGlobalScope,
1474            (SlangInt)i,
1475            0,
1476            kernelCode.writeRef(),
1477            diagnostics.writeRef());
1478
1479        if (diagnostics)
1480        {
1481            DebugMessageType msgType = DebugMessageType::Warning;
1482            if (compileResult != SLANG_OK)
1483                msgType = DebugMessageType::Error;
1484            getDebugCallback()->handleMessage(
1485                msgType,
1486                DebugMessageSource::Slang,
1487                (char*)diagnostics->getBufferPointer());
1488            if (outDiagnosticBlob)
1489                returnComPtr(outDiagnosticBlob, diagnostics);
1490        }
1491
1492        SLANG_RETURN_ON_FAIL(compileResult);
1493
1494        auto entryPoint = programLayout->getEntryPointByIndex(i);
1495        switch (entryPoint->getStage())
1496        {
1497        case SLANG_STAGE_COMPUTE:
1498            SLANG_ASSERT(entryPointCount == 1);
1499            SLANG_RETURN_ON_FAIL(m_device->CreateComputeShader(
1500                kernelCode->getBufferPointer(),
1501                kernelCode->getBufferSize(),
1502                nullptr,
1503                shaderProgram->m_computeShader.writeRef()));
1504            break;
1505        case SLANG_STAGE_VERTEX:
1506            SLANG_RETURN_ON_FAIL(m_device->CreateVertexShader(
1507                kernelCode->getBufferPointer(),
1508                kernelCode->getBufferSize(),
1509                nullptr,
1510                shaderProgram->m_vertexShader.writeRef()));
1511            break;
1512        case SLANG_STAGE_FRAGMENT:
1513            SLANG_RETURN_ON_FAIL(m_device->CreatePixelShader(
1514                kernelCode->getBufferPointer(),
1515                kernelCode->getBufferSize(),
1516                nullptr,
1517                shaderProgram->m_pixelShader.writeRef()));
1518            break;
1519        default:
1520            SLANG_ASSERT(!"pipeline stage not implemented");
1521        }
1522    }
1523    returnComPtr(outProgram, shaderProgram);
1524    return SLANG_OK;
1525}
1526
1527Result DeviceImpl::createShaderObjectLayout(
1528    slang::ISession* session,
1529    slang::TypeLayoutReflection* typeLayout,
1530    ShaderObjectLayoutBase** outLayout)
1531{
1532    RefPtr<ShaderObjectLayoutImpl> layout;
1533    SLANG_RETURN_ON_FAIL(
1534        ShaderObjectLayoutImpl::createForElementType(this, session, typeLayout, layout.writeRef()));
1535    returnRefPtrMove(outLayout, layout);
1536    return SLANG_OK;
1537}
1538
1539Result DeviceImpl::createShaderObject(ShaderObjectLayoutBase* layout, IShaderObject** outObject)
1540{
1541    RefPtr<ShaderObjectImpl> shaderObject;
1542    SLANG_RETURN_ON_FAIL(ShaderObjectImpl::create(
1543        this,
1544        static_cast<ShaderObjectLayoutImpl*>(layout),
1545        shaderObject.writeRef()));
1546    returnComPtr(outObject, shaderObject);
1547    return SLANG_OK;
1548}
1549
1550Result DeviceImpl::createMutableShaderObject(
1551    ShaderObjectLayoutBase* layout,
1552    IShaderObject** outObject)
1553{
1554    auto layoutImpl = static_cast<ShaderObjectLayoutImpl*>(layout);
1555
1556    RefPtr<MutableShaderObjectImpl> result = new MutableShaderObjectImpl();
1557    SLANG_RETURN_ON_FAIL(result->init(this, layoutImpl));
1558    returnComPtr(outObject, result);
1559
1560    return SLANG_OK;
1561}
1562
1563Result DeviceImpl::createRootShaderObject(IShaderProgram* program, ShaderObjectBase** outObject)
1564{
1565    auto programImpl = static_cast<ShaderProgramImpl*>(program);
1566    RefPtr<RootShaderObjectImpl> shaderObject;
1567    RefPtr<RootShaderObjectLayoutImpl> rootLayout;
1568    SLANG_RETURN_ON_FAIL(RootShaderObjectLayoutImpl::create(
1569        this,
1570        programImpl->slangGlobalScope,
1571        programImpl->slangGlobalScope->getLayout(),
1572        rootLayout.writeRef()));
1573    SLANG_RETURN_ON_FAIL(
1574        RootShaderObjectImpl::create(this, rootLayout.Ptr(), shaderObject.writeRef()));
1575    returnRefPtrMove(outObject, shaderObject);
1576    return SLANG_OK;
1577}
1578
1579void DeviceImpl::bindRootShaderObject(IShaderObject* shaderObject)
1580{
1581    RootShaderObjectImpl* rootShaderObjectImpl = static_cast<RootShaderObjectImpl*>(shaderObject);
1582    RefPtr<PipelineStateBase> specializedPipeline;
1583    // TODO: Do something less crappy than just asserting on failure here
1584    SLANG_ASSERT_VOID_ON_FAIL(
1585        maybeSpecializePipeline(m_currentPipelineState, rootShaderObjectImpl, specializedPipeline));
1586    maybeSpecializePipeline(m_currentPipelineState, rootShaderObjectImpl, specializedPipeline);
1587    PipelineStateImpl* specializedPipelineImpl =
1588        static_cast<PipelineStateImpl*>(specializedPipeline.Ptr());
1589    setPipelineState(specializedPipelineImpl);
1590
1591    // In order to bind the root object we must compute its specialized layout.
1592    //
1593    // TODO: This is in most ways redundant with `maybeSpecializePipeline` above,
1594    // and the two operations should really be one.
1595    //
1596    RefPtr<ShaderObjectLayoutImpl> specializedRootLayout;
1597    rootShaderObjectImpl->_getSpecializedLayout(specializedRootLayout.writeRef());
1598    RootShaderObjectLayoutImpl* specializedRootLayoutImpl =
1599        static_cast<RootShaderObjectLayoutImpl*>(specializedRootLayout.Ptr());
1600
1601    // Depending on whether we are binding a compute or a graphics/rasterization
1602    // pipeline, we will need to bind any SRVs/UAVs/CBs/samplers using different
1603    // D3D11 calls. We deal with that distinction here by instantiating an
1604    // appropriate subtype of `BindingContext` based on the pipeline type.
1605    //
1606    switch (m_currentPipelineState->desc.type)
1607    {
1608    case PipelineType::Compute:
1609        {
1610            ComputeBindingContext context(this, m_immediateContext);
1611            rootShaderObjectImpl->bindAsRoot(&context, specializedRootLayoutImpl);
1612
1613            // Because D3D11 requires all UAVs to be set at once, we did *not* issue
1614            // actual binding calls during the `bindAsRoot` step, and instead we
1615            // batch them up and set them here.
1616            //
1617            m_immediateContext
1618                ->CSSetUnorderedAccessViews(0, context.uavCount, context.uavs, nullptr);
1619        }
1620        break;
1621    default:
1622        {
1623            GraphicsBindingContext context(this, m_immediateContext);
1624            rootShaderObjectImpl->bindAsRoot(&context, specializedRootLayoutImpl);
1625
1626            // Similar to the compute case above, the rasteirzation case needs to
1627            // set the UAVs after the call to `bindAsRoot()` completes, but we
1628            // also have a few extra wrinkles here that are specific to the D3D 11.0
1629            // rasterization pipeline.
1630            //
1631            // In D3D 11.0, the RTV and UAV binding slots alias, so that a shader
1632            // that binds an RTV for `SV_Target0` cannot also bind a UAV for `u0`.
1633            // The Slang layout algorithm already accounts for this rule, and assigns
1634            // all UAVs to slots taht won't alias the RTVs it knows about.
1635            //
1636            // In order to account for the aliasing, we need to consider how many
1637            // RTVs are bound as part of the active framebuffer, and then adjust
1638            // the UAVs that we bind accordingly.
1639            //
1640            auto rtvCount = (UINT)m_currentFramebuffer->renderTargetViews.getCount();
1641            //
1642            // The `context` we are using will have computed the number of UAV registers
1643            // that might need to be bound, as a range from 0 to `context.uavCount`.
1644            // However we need to skip over the first `rtvCount` of those, so the
1645            // actual number of UAVs we wnat to bind is smaller:
1646            //
1647            // Note: As a result we expect that either there were no UAVs bound,
1648            // *or* the number of UAV slots bound is higher than the number of
1649            // RTVs so that there is something left to actually bind.
1650            //
1651            SLANG_ASSERT((context.uavCount == 0) || (context.uavCount >= rtvCount));
1652            auto bindableUAVCount = context.uavCount - rtvCount;
1653            //
1654            // Similarly, the actual UAVs we intend to bind will come after the first
1655            // `rtvCount` in the array.
1656            //
1657            auto bindableUAVs = context.uavs + rtvCount;
1658
1659            // Once the offsetting is accounted for, we set all of the RTVs, DSV,
1660            // and UAVs with one call.
1661            //
1662            // TODO: We may want to use the capability for `OMSetRenderTargetsAnd...`
1663            // to only set the UAVs and leave the RTVs/UAVs alone, so that we don't
1664            // needlessly re-bind RTVs during a pass.
1665            //
1666            m_immediateContext->OMSetRenderTargetsAndUnorderedAccessViews(
1667                rtvCount,
1668                m_currentFramebuffer->d3dRenderTargetViews.getArrayView().getBuffer(),
1669                m_currentFramebuffer->d3dDepthStencilView,
1670                rtvCount,
1671                bindableUAVCount,
1672                bindableUAVs,
1673                nullptr);
1674        }
1675        break;
1676    }
1677}
1678
1679Result DeviceImpl::createGraphicsPipelineState(
1680    const GraphicsPipelineStateDesc& inDesc,
1681    IPipelineState** outState)
1682{
1683    GraphicsPipelineStateDesc desc = inDesc;
1684
1685    auto programImpl = (ShaderProgramImpl*)desc.program;
1686
1687    ComPtr<ID3D11DepthStencilState> depthStencilState;
1688    {
1689        D3D11_DEPTH_STENCIL_DESC dsDesc;
1690        dsDesc.DepthEnable = desc.depthStencil.depthTestEnable;
1691        dsDesc.DepthWriteMask = desc.depthStencil.depthWriteEnable ? D3D11_DEPTH_WRITE_MASK_ALL
1692                                                                   : D3D11_DEPTH_WRITE_MASK_ZERO;
1693        dsDesc.DepthFunc = translateComparisonFunc(desc.depthStencil.depthFunc);
1694        dsDesc.StencilEnable = desc.depthStencil.stencilEnable;
1695        dsDesc.StencilReadMask = desc.depthStencil.stencilReadMask;
1696        dsDesc.StencilWriteMask = desc.depthStencil.stencilWriteMask;
1697
1698#define FACE(DST, SRC)                                                                            \
1699    dsDesc.DST.StencilFailOp = translateStencilOp(desc.depthStencil.SRC.stencilFailOp);           \
1700    dsDesc.DST.StencilDepthFailOp = translateStencilOp(desc.depthStencil.SRC.stencilDepthFailOp); \
1701    dsDesc.DST.StencilPassOp = translateStencilOp(desc.depthStencil.SRC.stencilPassOp);           \
1702    dsDesc.DST.StencilFunc = translateComparisonFunc(desc.depthStencil.SRC.stencilFunc);          \
1703    /* end */
1704
1705        FACE(FrontFace, frontFace);
1706        FACE(BackFace, backFace);
1707
1708        SLANG_RETURN_ON_FAIL(
1709            m_device->CreateDepthStencilState(&dsDesc, depthStencilState.writeRef()));
1710    }
1711
1712    ComPtr<ID3D11RasterizerState> rasterizerState;
1713    {
1714        D3D11_RASTERIZER_DESC rsDesc;
1715        rsDesc.FillMode = translateFillMode(desc.rasterizer.fillMode);
1716        rsDesc.CullMode = translateCullMode(desc.rasterizer.cullMode);
1717        rsDesc.FrontCounterClockwise = desc.rasterizer.frontFace == FrontFaceMode::Clockwise;
1718        rsDesc.DepthBias = desc.rasterizer.depthBias;
1719        rsDesc.DepthBiasClamp = desc.rasterizer.depthBiasClamp;
1720        rsDesc.SlopeScaledDepthBias = desc.rasterizer.slopeScaledDepthBias;
1721        rsDesc.DepthClipEnable = desc.rasterizer.depthClipEnable;
1722        rsDesc.ScissorEnable = desc.rasterizer.scissorEnable;
1723        rsDesc.MultisampleEnable = desc.rasterizer.multisampleEnable;
1724        rsDesc.AntialiasedLineEnable = desc.rasterizer.antialiasedLineEnable;
1725
1726        SLANG_RETURN_ON_FAIL(m_device->CreateRasterizerState(&rsDesc, rasterizerState.writeRef()));
1727    }
1728
1729    ComPtr<ID3D11BlendState> blendState;
1730    {
1731        auto& srcDesc = desc.blend;
1732        D3D11_BLEND_DESC dstDesc = {};
1733
1734        TargetBlendDesc defaultTargetBlendDesc;
1735
1736        static const UInt kMaxTargets = D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT;
1737        if (srcDesc.targetCount > kMaxTargets)
1738            return SLANG_FAIL;
1739
1740        for (GfxIndex ii = 0; ii < kMaxTargets; ++ii)
1741        {
1742            TargetBlendDesc const* srcTargetBlendDescPtr = nullptr;
1743            if (ii < srcDesc.targetCount)
1744            {
1745                srcTargetBlendDescPtr = &srcDesc.targets[ii];
1746            }
1747            else if (srcDesc.targetCount == 0)
1748            {
1749                srcTargetBlendDescPtr = &defaultTargetBlendDesc;
1750            }
1751            else
1752            {
1753                srcTargetBlendDescPtr = &srcDesc.targets[srcDesc.targetCount - 1];
1754            }
1755
1756            auto& srcTargetBlendDesc = *srcTargetBlendDescPtr;
1757            auto& dstTargetBlendDesc = dstDesc.RenderTarget[ii];
1758
1759            if (isBlendDisabled(srcTargetBlendDesc))
1760            {
1761                dstTargetBlendDesc.BlendEnable = false;
1762                dstTargetBlendDesc.BlendOp = D3D11_BLEND_OP_ADD;
1763                dstTargetBlendDesc.BlendOpAlpha = D3D11_BLEND_OP_ADD;
1764                dstTargetBlendDesc.SrcBlend = D3D11_BLEND_ONE;
1765                dstTargetBlendDesc.SrcBlendAlpha = D3D11_BLEND_ONE;
1766                dstTargetBlendDesc.DestBlend = D3D11_BLEND_ZERO;
1767                dstTargetBlendDesc.DestBlendAlpha = D3D11_BLEND_ZERO;
1768            }
1769            else
1770            {
1771                dstTargetBlendDesc.BlendEnable = true;
1772                dstTargetBlendDesc.BlendOp = translateBlendOp(srcTargetBlendDesc.color.op);
1773                dstTargetBlendDesc.BlendOpAlpha = translateBlendOp(srcTargetBlendDesc.alpha.op);
1774                dstTargetBlendDesc.SrcBlend =
1775                    translateBlendFactor(srcTargetBlendDesc.color.srcFactor);
1776                dstTargetBlendDesc.SrcBlendAlpha =
1777                    translateBlendFactor(srcTargetBlendDesc.alpha.srcFactor);
1778                dstTargetBlendDesc.DestBlend =
1779                    translateBlendFactor(srcTargetBlendDesc.color.dstFactor);
1780                dstTargetBlendDesc.DestBlendAlpha =
1781                    translateBlendFactor(srcTargetBlendDesc.alpha.dstFactor);
1782            }
1783
1784            dstTargetBlendDesc.RenderTargetWriteMask =
1785                translateRenderTargetWriteMask(srcTargetBlendDesc.writeMask);
1786        }
1787
1788        dstDesc.IndependentBlendEnable = srcDesc.targetCount > 1;
1789        dstDesc.AlphaToCoverageEnable = srcDesc.alphaToCoverageEnable;
1790
1791        SLANG_RETURN_ON_FAIL(m_device->CreateBlendState(&dstDesc, blendState.writeRef()));
1792    }
1793
1794    RefPtr<GraphicsPipelineStateImpl> state = new GraphicsPipelineStateImpl();
1795    state->m_depthStencilState = depthStencilState;
1796    state->m_rasterizerState = rasterizerState;
1797    state->m_blendState = blendState;
1798    state->m_inputLayout = static_cast<InputLayoutImpl*>(desc.inputLayout);
1799    state->m_rtvCount = (UINT) static_cast<FramebufferLayoutImpl*>(desc.framebufferLayout)
1800                            ->m_renderTargets.getCount();
1801    state->m_blendColor[0] = 0;
1802    state->m_blendColor[1] = 0;
1803    state->m_blendColor[2] = 0;
1804    state->m_blendColor[3] = 0;
1805    state->m_sampleMask = 0xFFFFFFFF;
1806    state->init(desc);
1807    returnComPtr(outState, state);
1808    return SLANG_OK;
1809}
1810
1811Result DeviceImpl::createComputePipelineState(
1812    const ComputePipelineStateDesc& inDesc,
1813    IPipelineState** outState)
1814{
1815    ComputePipelineStateDesc desc = inDesc;
1816
1817    RefPtr<ComputePipelineStateImpl> state = new ComputePipelineStateImpl();
1818    state->init(desc);
1819    returnComPtr(outState, state);
1820    return SLANG_OK;
1821}
1822
1823void DeviceImpl::copyBuffer(
1824    IBufferResource* dst,
1825    Offset dstOffset,
1826    IBufferResource* src,
1827    Offset srcOffset,
1828    Size size)
1829{
1830    auto dstImpl = static_cast<BufferResourceImpl*>(dst);
1831    auto srcImpl = static_cast<BufferResourceImpl*>(src);
1832    D3D11_BOX srcBox = {};
1833    srcBox.left = (UINT)srcOffset;
1834    srcBox.right = (UINT)(srcOffset + size);
1835    srcBox.bottom = srcBox.back = 1;
1836    m_immediateContext->CopySubresourceRegion(
1837        dstImpl->m_buffer,
1838        0,
1839        (UINT)dstOffset,
1840        0,
1841        0,
1842        srcImpl->m_buffer,
1843        0,
1844        &srcBox);
1845}
1846
1847void DeviceImpl::dispatchCompute(int x, int y, int z)
1848{
1849    m_immediateContext->Dispatch(x, y, z);
1850}
1851
1852void DeviceImpl::_flushGraphicsState()
1853{
1854    if (m_depthStencilStateDirty)
1855    {
1856        m_depthStencilStateDirty = false;
1857        auto pipelineState = static_cast<GraphicsPipelineStateImpl*>(m_currentPipelineState.Ptr());
1858        m_immediateContext->OMSetDepthStencilState(
1859            pipelineState->m_depthStencilState,
1860            m_stencilRef);
1861    }
1862}
1863
1864void DeviceImpl::beginCommandBuffer(const CommandBufferInfo& info)
1865{
1866    if (info.hasWriteTimestamps)
1867    {
1868        m_immediateContext->Begin(m_disjointQuery);
1869    }
1870}
1871
1872void DeviceImpl::endCommandBuffer(const CommandBufferInfo& info)
1873{
1874    if (info.hasWriteTimestamps)
1875    {
1876        m_immediateContext->End(m_disjointQuery);
1877    }
1878}
1879
1880void DeviceImpl::writeTimestamp(IQueryPool* pool, GfxIndex index)
1881{
1882    auto poolImpl = static_cast<QueryPoolImpl*>(pool);
1883    m_immediateContext->End(poolImpl->getQuery(index));
1884}
1885} // namespace d3d11
1886} // namespace gfx