Initial creation of Secure HLSL spec and conformance tests (#996)

* Initial creation of Secure HLSL spec and conformance tests

* Initial creation of Secure HLSL spec and conformance tests

* Move files to better place in source tree, add CMake build

* Move files to better place in source tree, add CMake build

* Remove VS solution files
diff --git a/tools/clang/tools/CMakeLists.txt b/tools/clang/tools/CMakeLists.txt
index d332430..954f5e3 100644
--- a/tools/clang/tools/CMakeLists.txt
+++ b/tools/clang/tools/CMakeLists.txt
@@ -34,3 +34,5 @@
 add_subdirectory(dotnetc)
 add_subdirectory(dxlib-sample)
 # HLSL Change Ends
+
+add_subdirectory(SecureHLSL)
\ No newline at end of file
diff --git a/tools/clang/tools/SecureHLSL/CMakeLists.txt b/tools/clang/tools/SecureHLSL/CMakeLists.txt
new file mode 100644
index 0000000..57328c1
--- /dev/null
+++ b/tools/clang/tools/SecureHLSL/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(HLSLTestEngine)
diff --git a/tools/clang/tools/SecureHLSL/Conformance/FirstTest.hlsl b/tools/clang/tools/SecureHLSL/Conformance/FirstTest.hlsl
new file mode 100644
index 0000000..4975801
--- /dev/null
+++ b/tools/clang/tools/SecureHLSL/Conformance/FirstTest.hlsl
@@ -0,0 +1,10 @@
+RWByteAddressBuffer g_bab : register(u0);

+

+[numthreads(8,8,1)]

+void main(uint GI : SV_GroupIndex) 

+{

+    uint addr = GI * 4;

+    uint val = g_bab.Load(addr);

+    g_bab.Store(addr, val + 1);

+}

+

diff --git a/tools/clang/tools/SecureHLSL/Conformance/FirstTests.json b/tools/clang/tools/SecureHLSL/Conformance/FirstTests.json
new file mode 100644
index 0000000..1b72319
--- /dev/null
+++ b/tools/clang/tools/SecureHLSL/Conformance/FirstTests.json
@@ -0,0 +1,11 @@
+{ 

+    "TestList":

+    [

+        {

+            "name" : "FirstTest",

+            "source" : "FirstTest.hlsl",

+            "input" : [0, 1, 2, 3, 4, 5, 6, 7],

+            "output" : [1, 2, 3, 4, 5, 6, 7, 8]

+        }

+    ]

+}

diff --git a/tools/clang/tools/SecureHLSL/HLSLTestEngine/CMakeLists.txt b/tools/clang/tools/SecureHLSL/HLSLTestEngine/CMakeLists.txt
new file mode 100644
index 0000000..cca525b
--- /dev/null
+++ b/tools/clang/tools/SecureHLSL/HLSLTestEngine/CMakeLists.txt
@@ -0,0 +1,24 @@
+# Copyright (C) Microsoft Corporation. All rights reserved.

+# This file is distributed under the University of Illinois Open Source License. See LICENSE.TXT for details.

+# Build HLSLTestEngine.exe as a test harness

+

+set(SOURCES

+  FenceWrapper.cpp

+  Main.cpp

+  MappedData.cpp

+  SimpleTextFile.cpp

+  )

+

+include_directories(../../../UnitTests/HLSL)

+

+add_clang_executable(HLSLTestEngine ${SOURCES})

+

+target_compile_definitions(HLSLTestEngine PRIVATE UNICODE)

+

+target_link_libraries(HLSLTestEngine d3d12)

+target_link_libraries(HLSLTestEngine dxgi)

+target_link_libraries(HLSLTestEngine runtimeobject)

+

+set_target_properties(HLSLTestEngine

+  PROPERTIES

+  LINKER_LANGUAGE CXX)

diff --git a/tools/clang/tools/SecureHLSL/HLSLTestEngine/Common.h b/tools/clang/tools/SecureHLSL/HLSLTestEngine/Common.h
new file mode 100644
index 0000000..1b78668
--- /dev/null
+++ b/tools/clang/tools/SecureHLSL/HLSLTestEngine/Common.h
@@ -0,0 +1,25 @@
+#pragma once

+

+#include <stdio.h>

+#include <windows.h>

+#include <d3d12.h>

+#include <d3dx12.h>

+#include <dxgi1_4.h>

+#include <wrl.h>

+#include <vector>

+#include <memory>

+#include <stdint.h>

+#include <DXC\Support\dxcapi.use.h>

+#include <atlbase.h>

+#include <atlconv.h>

+#include <DXProgrammableCapture.h>

+#include <Windows.Data.Json.h>

+#include <Windows.Foundation.Collections.h>

+

+using namespace Microsoft::WRL;

+using namespace Microsoft::WRL::Wrappers;

+using namespace ABI::Windows::Foundation;

+using namespace ABI::Windows::Foundation::Collections;

+using namespace ABI::Windows::Data::Json;

+

+#define IFT(x)  do { hr = (x); if (FAILED(hr)) { throw hr; } } while (false)

diff --git a/tools/clang/tools/SecureHLSL/HLSLTestEngine/FenceWrapper.cpp b/tools/clang/tools/SecureHLSL/HLSLTestEngine/FenceWrapper.cpp
new file mode 100644
index 0000000..20e831b
--- /dev/null
+++ b/tools/clang/tools/SecureHLSL/HLSLTestEngine/FenceWrapper.cpp
@@ -0,0 +1,30 @@
+#include "FenceWrapper.h"

+

+FenceWrapper::FenceWrapper(ID3D12Device *pDevice)

+{

+    HRESULT hr;

+

+    m_fenceValue = 1;

+    IFT(pDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_spFence)));

+

+    m_fenceEvent.reset(::CreateEvent(nullptr, FALSE, FALSE, nullptr));

+    if (m_fenceEvent == nullptr)

+    {

+        IFT(HRESULT_FROM_WIN32(GetLastError()));

+    }

+}

+

+void FenceWrapper::WaitForSignal(ID3D12CommandQueue *pCQ)

+{

+    HRESULT hr;

+

+    IFT(pCQ->Signal(m_spFence.Get(), m_fenceValue));

+

+    if (m_spFence->GetCompletedValue() < m_fenceValue)

+    {

+        IFT(m_spFence->SetEventOnCompletion(m_fenceValue, m_fenceEvent.get()));

+        ::WaitForSingleObject(m_fenceEvent.get(), INFINITE);

+    }

+

+    m_fenceValue++;

+}

diff --git a/tools/clang/tools/SecureHLSL/HLSLTestEngine/FenceWrapper.h b/tools/clang/tools/SecureHLSL/HLSLTestEngine/FenceWrapper.h
new file mode 100644
index 0000000..d81269e
--- /dev/null
+++ b/tools/clang/tools/SecureHLSL/HLSLTestEngine/FenceWrapper.h
@@ -0,0 +1,25 @@
+#pragma once

+

+#include "Common.h"

+

+struct HANDLECloser

+{

+    void operator()(HANDLE hToClose)

+    {

+        ::CloseHandle(hToClose);

+    }

+};

+

+class FenceWrapper

+{

+public:

+    FenceWrapper() = delete;

+    FenceWrapper(ID3D12Device *pDevice);

+

+    void WaitForSignal(ID3D12CommandQueue *pCQ);

+

+private:

+    std::unique_ptr<void, HANDLECloser> m_fenceEvent;

+    ComPtr<ID3D12Fence> m_spFence;

+    UINT64 m_fenceValue;

+};

diff --git a/tools/clang/tools/SecureHLSL/HLSLTestEngine/Main.cpp b/tools/clang/tools/SecureHLSL/HLSLTestEngine/Main.cpp
new file mode 100644
index 0000000..96300ec
--- /dev/null
+++ b/tools/clang/tools/SecureHLSL/HLSLTestEngine/Main.cpp
@@ -0,0 +1,402 @@
+#include "Common.h"

+#include "SimpleTextFile.h"

+#include "FenceWrapper.h"

+#include "MappedData.h"

+

+void SetDescriptorHeap(ID3D12GraphicsCommandList *pCommandList, ID3D12DescriptorHeap *pHeap)

+{

+    ID3D12DescriptorHeap *const pHeaps[1] = { pHeap };

+    pCommandList->SetDescriptorHeaps(ARRAYSIZE(pHeaps), pHeaps);

+}

+

+void ExecuteCommandList(ID3D12CommandQueue *pQueue, ID3D12CommandList *pList)

+{

+    ID3D12CommandList *ppCommandLists[] = { pList };

+    pQueue->ExecuteCommandLists(ARRAYSIZE(ppCommandLists), ppCommandLists);

+}

+

+void CreateComputeCommandQueue(ID3D12Device *pDevice, LPCWSTR pName, ID3D12CommandQueue **ppCommandQueue)

+{

+    HRESULT hr;

+

+    D3D12_COMMAND_QUEUE_DESC queueDesc = {};

+    queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;

+    queueDesc.Type = D3D12_COMMAND_LIST_TYPE_COMPUTE;

+    IFT(pDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(ppCommandQueue)));

+    IFT((*ppCommandQueue)->SetName(pName));

+}

+

+void CreateRootSignatureFromDesc(ID3D12Device *pDevice, const D3D12_ROOT_SIGNATURE_DESC *pDesc, ID3D12RootSignature **pRootSig)

+{

+    HRESULT hr;

+

+    ComPtr<ID3DBlob> spSignature;

+    ComPtr<ID3DBlob> spError;

+    IFT(D3D12SerializeRootSignature(pDesc, D3D_ROOT_SIGNATURE_VERSION_1, &spSignature, &spError));

+    IFT(pDevice->CreateRootSignature(0, spSignature->GetBufferPointer(), spSignature->GetBufferSize(), IID_PPV_ARGS(pRootSig)));

+}

+

+void CompileFromText(LPCSTR pText, LPCWSTR pEntryPoint, LPCWSTR pTargetProfile, ID3DBlob **ppBlob)

+{

+    HRESULT hr;

+

+    dxc::DxcDllSupport support;

+    IFT(support.Initialize());

+

+    ComPtr<IDxcCompiler2> spCompiler;

+    IFT(support.CreateInstance(CLSID_DxcCompiler, spCompiler.ReleaseAndGetAddressOf()));

+

+    ComPtr<IDxcLibrary> spLibrary;

+    IFT(support.CreateInstance(CLSID_DxcLibrary, spLibrary.ReleaseAndGetAddressOf()));

+

+    ComPtr<IDxcBlobEncoding> spTextBlob;

+    IFT(spLibrary->CreateBlobWithEncodingFromPinned((LPBYTE)pText, (UINT32)strlen(pText), CP_UTF8, &spTextBlob));

+

+    const wchar_t* pszArgs = L"/Zi";

+

+    ComPtr<IDxcOperationResult> spResult;

+    IFT(spCompiler->Compile(

+        spTextBlob.Get(),

+        L"hlsl.hlsl",

+        pEntryPoint,

+        pTargetProfile,

+        &pszArgs,

+        1,

+        nullptr,

+        0,

+        nullptr,

+        &spResult

+    ));

+

+    HRESULT resultCode = S_OK;

+    IFT(spResult->GetStatus(&resultCode));

+

+    if (FAILED(resultCode))

+    {

+        ComPtr<IDxcBlobEncoding> spErrors;

+        IFT(spResult->GetErrorBuffer(&spErrors));

+    }

+

+    IFT(resultCode);

+    IFT(spResult->GetResult(reinterpret_cast<IDxcBlob **>(ppBlob)));

+}

+

+void CreateComputePSO(ID3D12Device *pDevice, ID3D12RootSignature *pRootSignature, LPCSTR pszShader, ID3D12PipelineState **pspComputeState)

+{

+    HRESULT hr;

+

+    // Load and compile shaders.

+    ComPtr<ID3DBlob> spComputeShader;

+    CompileFromText(pszShader, L"main", L"cs_6_0", spComputeShader.ReleaseAndGetAddressOf());

+

+    // Describe and create the compute pipeline state object (PSO).

+    D3D12_COMPUTE_PIPELINE_STATE_DESC computePsoDesc = {};

+    computePsoDesc.pRootSignature = pRootSignature;

+    computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(spComputeShader.Get());

+    computePsoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_TOOL_DEBUG;

+

+    IFT(pDevice->CreateComputePipelineState(&computePsoDesc, IID_PPV_ARGS(pspComputeState)));

+}

+

+void RecordTransitionBarrier(ID3D12GraphicsCommandList *pCommandList,

+    ID3D12Resource *pResource,

+    D3D12_RESOURCE_STATES before,

+    D3D12_RESOURCE_STATES after)

+{

+    CD3DX12_RESOURCE_BARRIER barrier(CD3DX12_RESOURCE_BARRIER::Transition(pResource, before, after));

+

+    pCommandList->ResourceBarrier(1, &barrier);

+}

+

+void CreateTestUavs(ID3D12Device *pDevice,

+    ID3D12GraphicsCommandList *pCommandList, 

+    LPCVOID values,

+    UINT valueSizeInBytes, 

+    ID3D12Resource **ppUavResource,

+    ID3D12Resource **ppReadBuffer,

+    ID3D12Resource **ppUploadResource)

+{

+    HRESULT hr;

+

+    ComPtr<ID3D12Resource> spUavResource;

+    D3D12_HEAP_PROPERTIES defaultHeapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);

+    D3D12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(valueSizeInBytes, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);

+    IFT(pDevice->CreateCommittedResource(

+        &defaultHeapProperties,

+        D3D12_HEAP_FLAG_NONE,

+        &bufferDesc,

+        D3D12_RESOURCE_STATE_COPY_DEST,

+        nullptr,

+        IID_PPV_ARGS(&spUavResource)));

+

+    ComPtr<ID3D12Resource> spUploadResource;

+    D3D12_HEAP_PROPERTIES uploadHeapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD);

+    D3D12_RESOURCE_DESC uploadBufferDesc = CD3DX12_RESOURCE_DESC::Buffer(valueSizeInBytes);

+    IFT(pDevice->CreateCommittedResource(

+        &uploadHeapProperties,

+        D3D12_HEAP_FLAG_NONE,

+        &uploadBufferDesc,

+        D3D12_RESOURCE_STATE_GENERIC_READ,

+        nullptr,

+        IID_PPV_ARGS(&spUploadResource)));

+

+    ComPtr<ID3D12Resource> spReadBuffer;

+    CD3DX12_HEAP_PROPERTIES readHeap(D3D12_HEAP_TYPE_READBACK);

+    CD3DX12_RESOURCE_DESC readDesc(CD3DX12_RESOURCE_DESC::Buffer(valueSizeInBytes));

+    IFT(pDevice->CreateCommittedResource(

+        &readHeap, 

+        D3D12_HEAP_FLAG_NONE, 

+        &readDesc,

+        D3D12_RESOURCE_STATE_COPY_DEST, 

+        nullptr, 

+        IID_PPV_ARGS(&spReadBuffer)));

+

+    D3D12_SUBRESOURCE_DATA transferData;

+    transferData.pData = values;

+    transferData.RowPitch = valueSizeInBytes;

+    transferData.SlicePitch = transferData.RowPitch;

+

+    UpdateSubresources<1>(pCommandList, spUavResource.Get(), spUploadResource.Get(), 0, 0, 1, &transferData);

+    RecordTransitionBarrier(pCommandList, spUavResource.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);

+

+    *ppUavResource = spUavResource.Detach();

+    *ppReadBuffer = spReadBuffer.Detach();

+    *ppUploadResource = spUploadResource.Detach();

+}

+

+void JsonArrayToVector(IJsonArray* pArray, std::vector<uint32_t> &vec)

+{

+    HRESULT hr;

+

+    ComPtr<IVector<IJsonValue *>> spInputListVector;

+    IFT(pArray->QueryInterface(IID_PPV_ARGS(&spInputListVector)));

+

+    unsigned int inputSize = 0;

+    IFT(spInputListVector->get_Size(&inputSize));

+

+    vec.resize(inputSize);

+

+    for (unsigned int inputIndex = 0; inputIndex < inputSize; inputIndex++)

+    {

+        double value = 0.0;

+        IFT(pArray->GetNumberAt(inputIndex, &value));

+        vec[inputIndex] = static_cast<uint32_t>(value);

+    }

+}

+

+int __cdecl main(void)

+{

+    HRESULT hr;

+

+    try

+    {

+        // Initialize the Windows Runtime.

+        RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);

+

+        ComPtr<IJsonObjectStatics> spJsonStaticsFactory;

+        IFT(GetActivationFactory(HStringReference(RuntimeClass_Windows_Data_Json_JsonObject).Get(), &spJsonStaticsFactory));

+

+        // Read the test metadata file

+        SimpleTextFile jsonFile(L"..\\Conformance\\FirstTests.json");

+        std::vector<wchar_t> jsonContents;

+

+        // Convert to wide when reading

+        jsonFile.ReadFile(jsonContents);

+

+        // Json object wants a Platform::String

+        ComPtr<IJsonObject> spTestListJson;

+        IFT(spJsonStaticsFactory->Parse(HStringReference(jsonContents.data()).Get(), &spTestListJson));

+

+        ComPtr<IJsonArray> spTestList;

+        IFT(spTestListJson->GetNamedArray(HStringReference(L"TestList").Get(), &spTestList));

+

+        dxc::DxcDllSupport support;

+        IFT(support.Initialize());

+

+        // Take the debug layer if we can get it

+        ComPtr<ID3D12Debug> spDebugController;

+        if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&spDebugController))))

+        {

+            spDebugController->EnableDebugLayer();

+        }

+

+        ComPtr<IDXGIFactory4> spFactory;

+        IFT(CreateDXGIFactory1(IID_PPV_ARGS(&spFactory)));

+

+        ComPtr<IDXGIAdapter> spAdapter;

+        IFT(spFactory->EnumWarpAdapter(IID_PPV_ARGS(&spAdapter)));

+

+        ComPtr<ID3D12Device> spDevice;

+        IFT(D3D12CreateDevice(spAdapter.Get(), D3D_FEATURE_LEVEL_12_0, IID_PPV_ARGS(&spDevice)));

+

+        ComPtr<IDXGraphicsAnalysis> spGA;

+        DXGIGetDebugInterface1(0, IID_PPV_ARGS(&spGA));

+

+        if (spGA != nullptr)

+        {

+            spGA->BeginCapture();

+        }

+

+        static const int DispatchGroupX = 1;

+        static const int DispatchGroupY = 1;

+        static const int DispatchGroupZ = 1;

+

+        ComPtr<ID3D12CommandQueue> spCommandQueue;

+        CreateComputeCommandQueue(spDevice.Get(), L"RunRWByteBufferComputeTest Command Queue", &spCommandQueue);

+

+        // Describe and create a UAV descriptor heap.

+        D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};

+        heapDesc.NumDescriptors = 1;

+        heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;

+        heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;

+

+        ComPtr<ID3D12DescriptorHeap> spUavHeap;

+        IFT(spDevice->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&spUavHeap)));

+

+        // Create root signature.

+        ComPtr<ID3D12RootSignature> spRootSignature;

+        {

+            CD3DX12_DESCRIPTOR_RANGE ranges[1];

+            ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 0, 0, 0);

+

+            CD3DX12_ROOT_PARAMETER rootParameters[1];

+            rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_ALL);

+

+            CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc;

+            rootSignatureDesc.Init(_countof(rootParameters), rootParameters, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_NONE);

+

+            CreateRootSignatureFromDesc(spDevice.Get(), &rootSignatureDesc, &spRootSignature);

+        }

+

+        ComPtr<IJsonObject> spFirstEntry;

+        IFT(spTestList->GetObjectAt(0, &spFirstEntry));

+

+        HString testName;

+        IFT(spFirstEntry->GetNamedString(HStringReference(L"name").Get(), testName.GetAddressOf()));

+

+        // Load up the input data to the shader

+        ComPtr<IJsonArray> spInputList;        

+        IFT(spFirstEntry->GetNamedArray(HStringReference(L"input").Get(), &spInputList));

+

+        std::vector<uint32_t> InputData;

+        JsonArrayToVector(spInputList.Get(), InputData);

+

+        const UINT valueSizeInBytes = static_cast<UINT>(InputData.size() * sizeof(uint32_t));

+

+        // Load up the expected output

+        ComPtr<IJsonArray> spExpectedList;

+        IFT(spFirstEntry->GetNamedArray(HStringReference(L"output").Get(), &spExpectedList));

+

+        std::vector<uint32_t> ExpectedData;

+        JsonArrayToVector(spExpectedList.Get(), ExpectedData);

+

+        HString hlslSource;

+        IFT(spFirstEntry->GetNamedString(HStringReference(L"source").Get(), hlslSource.GetAddressOf()));

+

+        HString hlslSourceWithPath;

+        IFT(::WindowsConcatString(HStringReference(L"..\\Conformance\\").Get(), hlslSource.Get(), hlslSourceWithPath.GetAddressOf()));

+

+        SimpleTextFile hlslFile(::WindowsGetStringRawBuffer(hlslSourceWithPath.Get(), nullptr));

+

+        std::vector<char> shaderSource;

+        hlslFile.ReadFile(shaderSource);

+

+        // Create pipeline state object.

+        ComPtr<ID3D12PipelineState> spComputeState;

+        CreateComputePSO(spDevice.Get(), spRootSignature.Get(), shaderSource.data(), &spComputeState);

+

+        // Create a command allocator and list for compute.

+        ComPtr<ID3D12CommandAllocator> spCommandAllocator;

+        IFT(spDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_COMPUTE, IID_PPV_ARGS(&spCommandAllocator)));

+

+        ComPtr<ID3D12GraphicsCommandList> spCommandList;

+        IFT(spDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_COMPUTE, spCommandAllocator.Get(), spComputeState.Get(), IID_PPV_ARGS(&spCommandList)));

+        spCommandList->SetName(L"ExecutionTest::RunRWByteButterComputeTest Command List");

+

+        // Set up UAV resource.

+        ComPtr<ID3D12Resource> spUavResource;

+        ComPtr<ID3D12Resource> spReadBuffer;

+        ComPtr<ID3D12Resource> spUploadResource;

+        CreateTestUavs(spDevice.Get(), spCommandList.Get(), InputData.data(), valueSizeInBytes, &spUavResource, &spReadBuffer, &spUploadResource);

+        IFT(spUavResource->SetName(L"RunRWByteBufferComputeText UAV"));

+        IFT(spReadBuffer->SetName(L"RunRWByteBufferComputeText UAV Read Buffer"));

+        IFT(spUploadResource->SetName(L"RunRWByteBufferComputeText UAV Upload Buffer"));

+

+        // Close the command list and execute it to perform the GPU setup.

+        spCommandList->Close();

+        ExecuteCommandList(spCommandQueue.Get(), spCommandList.Get());

+

+        // Wait for the command list to be done

+        FenceWrapper FO(spDevice.Get());

+        FO.WaitForSignal(spCommandQueue.Get());

+

+        IFT(spCommandAllocator->Reset());

+        IFT(spCommandList->Reset(spCommandAllocator.Get(), spComputeState.Get()));

+

+        // Run the compute shader and copy the results back to readable memory.

+        D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};

+        uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;

+        uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;

+        uavDesc.Buffer.FirstElement = 0;

+        uavDesc.Buffer.NumElements = (UINT)InputData.size();

+        uavDesc.Buffer.StructureByteStride = 0;

+        uavDesc.Buffer.CounterOffsetInBytes = 0;

+        uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;

+        CD3DX12_CPU_DESCRIPTOR_HANDLE uavHandle(spUavHeap->GetCPUDescriptorHandleForHeapStart());

+        spDevice->CreateUnorderedAccessView(spUavResource.Get(), nullptr, &uavDesc, uavHandle);

+

+        SetDescriptorHeap(spCommandList.Get(), spUavHeap.Get());

+        spCommandList->SetComputeRootSignature(spRootSignature.Get());

+

+        CD3DX12_GPU_DESCRIPTOR_HANDLE uavHandleGpu(spUavHeap->GetGPUDescriptorHandleForHeapStart());

+        spCommandList->SetComputeRootDescriptorTable(0, uavHandleGpu);

+

+        spCommandList->Dispatch(DispatchGroupX, DispatchGroupY, DispatchGroupZ);

+        RecordTransitionBarrier(spCommandList.Get(), spUavResource.Get(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE);

+        spCommandList->CopyResource(spReadBuffer.Get(), spUavResource.Get());

+        spCommandList->Close();

+        ExecuteCommandList(spCommandQueue.Get(), spCommandList.Get());

+        FO.WaitForSignal(spCommandQueue.Get());

+

+        // Readback shader result

+        std::vector<uint32_t> OutputData;

+        OutputData.resize(InputData.size());

+

+        {

+            MappedData mappedData(spReadBuffer.Get(), valueSizeInBytes);

+            uint32_t *pData = static_cast<uint32_t *>(mappedData.GetData());

+            memcpy(OutputData.data(), pData, valueSizeInBytes);

+        }

+

+        FO.WaitForSignal(spCommandQueue.Get());

+

+        if (spGA != nullptr) 

+        {

+            spGA->EndCapture();

+        }

+

+        PCWSTR pszTestName = ::WindowsGetStringRawBuffer(testName.Get(), nullptr);

+

+        // Check that output matches expected

+        size_t check;

+        for (check = 0; check < ExpectedData.size(); check++)

+        {

+            if (ExpectedData[check] != OutputData[check])

+            {

+                ::wprintf(L"Test %s Failed\n", pszTestName);

+                break;

+            }

+        }

+

+        if (check == OutputData.size())

+        {

+            ::wprintf(L"Test %s Passed\n", pszTestName);

+        }

+    }

+    catch (HRESULT hrFail)

+    {

+        ::wprintf(L"Error %x\n", hrFail);

+    }

+

+    return 0;

+}

diff --git a/tools/clang/tools/SecureHLSL/HLSLTestEngine/MappedData.cpp b/tools/clang/tools/SecureHLSL/HLSLTestEngine/MappedData.cpp
new file mode 100644
index 0000000..4a03b78
--- /dev/null
+++ b/tools/clang/tools/SecureHLSL/HLSLTestEngine/MappedData.cpp
@@ -0,0 +1,51 @@
+#include "MappedData.h"

+

+MappedData::MappedData() : m_pData(nullptr), m_size(0) 

+{

+}

+

+MappedData::MappedData(ID3D12Resource *pResource, UINT32 sizeInBytes) : m_pData(nullptr), m_size(0) 

+{

+    ExecuteMap(pResource, sizeInBytes);

+}

+

+MappedData::~MappedData() 

+{

+    Reset();

+}

+

+void *MappedData::GetData() 

+{ 

+    return m_pData; 

+}

+

+UINT32 MappedData::GetSize() const 

+{ 

+    return m_size; 

+}

+

+void MappedData::Reset()

+{

+    if (_spResource != nullptr)

+    {

+        _spResource->Unmap(0, nullptr);

+        _spResource.Reset();

+    }

+

+    m_pData = nullptr;

+}

+

+void MappedData::ExecuteMap(ID3D12Resource *pResource, UINT32 sizeInBytes)

+{

+    HRESULT hr;

+

+    Reset();

+    

+    D3D12_RANGE ResourceRange;

+    ResourceRange.Begin = 0;

+    ResourceRange.End = sizeInBytes;

+    IFT(pResource->Map(0, &ResourceRange, &m_pData));

+

+    _spResource = pResource;

+    m_size = sizeInBytes;

+}

diff --git a/tools/clang/tools/SecureHLSL/HLSLTestEngine/MappedData.h b/tools/clang/tools/SecureHLSL/HLSLTestEngine/MappedData.h
new file mode 100644
index 0000000..8f3dcd3
--- /dev/null
+++ b/tools/clang/tools/SecureHLSL/HLSLTestEngine/MappedData.h
@@ -0,0 +1,23 @@
+#pragma once

+

+#include "Common.h"

+

+class MappedData

+{

+public:

+    MappedData();

+    MappedData(ID3D12Resource *pResource, UINT32 sizeInBytes);

+    ~MappedData();

+    

+    void *GetData();

+    UINT32 GetSize() const;

+    void Reset();

+    

+private:

+    void ExecuteMap(ID3D12Resource *pResource, UINT32 sizeInBytes);

+

+private:

+    ComPtr<ID3D12Resource> _spResource;

+    void *m_pData;

+    UINT32 m_size;

+};

diff --git a/tools/clang/tools/SecureHLSL/HLSLTestEngine/Readme.md b/tools/clang/tools/SecureHLSL/HLSLTestEngine/Readme.md
new file mode 100644
index 0000000..d2224eb
--- /dev/null
+++ b/tools/clang/tools/SecureHLSL/HLSLTestEngine/Readme.md
@@ -0,0 +1,9 @@
+# HLSL Test Engine

+

+## How to build

+

+This project is meant to be used with Visual Studio 2017 15.4 and the Windows SDK version 10.0.16299.15.

+

+After building you can run the program from the HLSLTestEngine directory and it will find the Conformance test path and run the tests.

+

+This uses WARP for D3D12 rendering so that it will have consistent results on each machine.

diff --git a/tools/clang/tools/SecureHLSL/HLSLTestEngine/SimpleTextFile.cpp b/tools/clang/tools/SecureHLSL/HLSLTestEngine/SimpleTextFile.cpp
new file mode 100644
index 0000000..4904473
--- /dev/null
+++ b/tools/clang/tools/SecureHLSL/HLSLTestEngine/SimpleTextFile.cpp
@@ -0,0 +1,86 @@
+#include "SimpleTextFile.h"

+

+SimpleTextFile::SimpleTextFile(const wchar_t* pszFilename)

+{

+    HRESULT hr;

+

+    _hFile = ::CreateFile(pszFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

+    if (_hFile == nullptr)

+    {

+        IFT(E_FAIL);

+    }

+}

+

+SimpleTextFile::~SimpleTextFile()

+{

+    if (_hFile != nullptr)

+    {

+        ::CloseHandle(_hFile);

+    }

+}

+

+void SimpleTextFile::ReadFile(std::vector<char> &fileBytes)

+{

+    HRESULT hr;

+

+    LARGE_INTEGER fileSize;

+    if (!::GetFileSizeEx(_hFile, &fileSize))

+    {

+        IFT(E_FAIL);

+    }

+

+    if (fileSize.HighPart != 0)

+    {

+        // Not expecting gigantic HLSL files

+        IFT(E_UNEXPECTED);

+    }

+

+    // We know now how much we need to store the whole file

+    fileBytes.resize(fileSize.LowPart + 2);

+

+    DWORD dwRead;

+    if (!::ReadFile(_hFile, fileBytes.data(), fileSize.LowPart, &dwRead, nullptr))

+    {

+        IFT(E_FAIL);

+    }

+

+    // Terminate file data so it can be cast to a string

+    fileBytes[fileSize.LowPart] = 0;

+    fileBytes[fileSize.LowPart + 1] = 0;

+}

+

+void SimpleTextFile::ReadFile(std::vector<wchar_t> &fileBytes)

+{

+    HRESULT hr;

+

+    // First read raw data

+    std::vector<char> rawFile;

+    ReadFile(rawFile);

+

+    // Find out the needed buffer size

+    const int utf16Length = ::MultiByteToWideChar(

+        CP_UTF8,

+        MB_ERR_INVALID_CHARS,

+        rawFile.data(),

+        -1,

+        nullptr,

+        0);

+

+    if (utf16Length == 0)

+    {

+        IFT(E_FAIL);

+    }

+

+    fileBytes.resize(utf16Length);

+

+    if (!::MultiByteToWideChar(

+        CP_UTF8,

+        MB_ERR_INVALID_CHARS,

+        rawFile.data(),

+        -1,

+        fileBytes.data(),

+        static_cast<int>(fileBytes.size())))

+    {

+        IFT(E_FAIL);

+    }

+}

diff --git a/tools/clang/tools/SecureHLSL/HLSLTestEngine/SimpleTextFile.h b/tools/clang/tools/SecureHLSL/HLSLTestEngine/SimpleTextFile.h
new file mode 100644
index 0000000..7a34ede
--- /dev/null
+++ b/tools/clang/tools/SecureHLSL/HLSLTestEngine/SimpleTextFile.h
@@ -0,0 +1,16 @@
+#pragma once

+

+#include "Common.h"

+

+class SimpleTextFile

+{

+public:

+    SimpleTextFile(const wchar_t* pszFilename);

+    ~SimpleTextFile();

+

+    void ReadFile(std::vector<char> &fileBytes);

+    void ReadFile(std::vector<wchar_t> &fileBytes);

+

+private:

+    HANDLE _hFile;

+};

diff --git a/tools/clang/tools/SecureHLSL/SecureHLSLSpec.md b/tools/clang/tools/SecureHLSL/SecureHLSLSpec.md
new file mode 100644
index 0000000..57c4baf
--- /dev/null
+++ b/tools/clang/tools/SecureHLSL/SecureHLSLSpec.md
@@ -0,0 +1,76 @@
+Secure HLSL Specification

+

+Contents

+

+1. Introduction

+2. Basics

+3. Variables and Types

+4. Operators and Expressions

+5. Statements

+6. Builtin identifiers

+7. Grammar

+8. Errors

+9. Open Issues

+

+# Variables and Types

+

+All variables and functions must be declared before being referenced. Variables and functions are referenced with an Identifier. There is no concept of a default type - all variable declarations and function declarations must specify types.

+

+Identifier tokens are defined in 2.TODO. The grammar in section 7 shows the variety of declaration statement syntax. Multiple variables can be declared in a single statement, and declarations can initialize most types.

+

+Types can be split into three categories - basic types, object types and user defined types.

+

+## Basic Types

+

+Type | Description

+--- | ---

+void                | Only valid when describing the return type of a function

+bool                | Boolean value that can only be true or false

+int                 | Scalar 32 bit signed integer

+uint                | Scalar 32 bit unsigned integer

+dword               | Scalar 32 bit unsigned integer

+float               | Scalar 32 bit float

+&lt;type&gt;*N*     | Vector of *type* with dimension N (1 <= N <= 4)

+&lt;type&gt;*N*x*M* | Matrix of *type* with N rows and M columns (1 <= N &vert; M <= 4)

+

+There is no string type in Secure HLSL.

+

+## Object Types

+

+Type | Description

+--- | ---

+SamplerState            | Texture sampler

+SamplerComparisonState  | Texture sampler with comparison

+Texture*N*D             | Texture with N dimensions

+

+## User Defined Types

+

+User defined types are defined with the struct keyword and allow the aggregation of basic types and other structures. The members can be arrays.

+

+## Arrays

+

+All types can be declared with arrays with positive nonzero integer size. Only single dimensional arrays are allowed.

+

+# Operators and Expressions

+

+## Array subscripting

+

+The square bracket operator [*index*] is used to access an element of an array.

+

+Accessing an index that is out of bounds for the declared array results in a zeroed result being returned. If the variable is a struct then

+the members of the struct are all zeroed out.

+

+Accessing a texture or sampler array with an out of bounds index will result in a *null object* being returned. Any subsequent operations

+done on this object result in a zeroed output being returned.

+

+# Open Issues

+

+- Should half / double / min16 / min10 be part of secure HLSL?

+- Vector&lt;type, size&gt; vs &lt;type&gt;N?

+- How many variants of vector / matrix declaration will be allowed?

+- Interpolation modifiers?

+- Do structs hide previous type names?

+- Local struct definitions?

+- Array access with non-int types?

+- Multidimensional arrays?

+- Is null object the way we want to handle these cases?
\ No newline at end of file