diff options
Diffstat (limited to 'tools/render-test')
36 files changed, 16 insertions, 10851 deletions
diff --git a/tools/render-test/circular-resource-heap-d3d12.cpp b/tools/render-test/circular-resource-heap-d3d12.cpp deleted file mode 100644 index ae8e13822..000000000 --- a/tools/render-test/circular-resource-heap-d3d12.cpp +++ /dev/null @@ -1,222 +0,0 @@ -#include "circular-resource-heap-d3d12.h" - -namespace renderer_test { -using namespace Slang; - -D3D12CircularResourceHeap::D3D12CircularResourceHeap(): - m_fence(nullptr), - m_device(nullptr), - m_blockFreeList(sizeof(Block), SLANG_ALIGN_OF(Block), 16), - m_blocks(nullptr) -{ - m_back.m_block = nullptr; - m_back.m_position = nullptr; - m_front.m_block = nullptr; - m_front.m_position = nullptr; -} - -D3D12CircularResourceHeap::~D3D12CircularResourceHeap() -{ - _freeBlockListResources(m_blocks); -} - -void D3D12CircularResourceHeap::_freeBlockListResources(const Block* start) -{ - if (start) - { - const Block* block = start; - do - { - ID3D12Resource* resource = block->m_resource; - - resource->Unmap(0, nullptr); - resource->Release(); - - // Next in list - block = block->m_next; - - } while (block != start); - } -} - -Result D3D12CircularResourceHeap::init(ID3D12Device* device, const Desc& desc, D3D12CounterFence* fence) -{ - assert(m_blocks == nullptr); - assert(desc.m_blockSize > 0); - - m_fence = fence; - m_desc = desc; - m_device = device; - - return SLANG_OK; -} - -void D3D12CircularResourceHeap::addSync(uint64_t signalValue) -{ - assert(signalValue == m_fence->getCurrentValue()); - PendingEntry entry; - entry.m_completedValue = signalValue; - entry.m_cursor = m_front; - m_pendingQueue.Add(entry); -} - -void D3D12CircularResourceHeap::updateCompleted() -{ - const uint64_t completedValue = m_fence->getCompletedValue(); - -#if 0 - while (m_pendingQueue.Count() != 0) - { - const PendingEntry& entry = m_pendingQueue[0]; - if (entry.m_completedValue <= completedValue) - { - m_back = entry.m_cursor; - m_pendingQueue.RemoveAt(0); - } - else - { - break; - } - } -#else - // A more efficient implementation is m_pendingQueue is implemented as a vector like type - const int size = int(m_pendingQueue.Count()); - int end = 0; - while (end < size && m_pendingQueue[end].m_completedValue <= completedValue) - { - end++; - } - - if (end > 0) - { - // Set the back position - m_back = m_pendingQueue[end - 1].m_cursor; - if (end == size) - { - m_pendingQueue.Clear(); - } - else - { - m_pendingQueue.RemoveRange(0, size); - } - } -#endif -} - -D3D12CircularResourceHeap::Block* D3D12CircularResourceHeap::_newBlock() -{ - D3D12_RESOURCE_DESC desc; - - desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - desc.Alignment = 0; - desc.Width = m_desc.m_blockSize; - desc.Height = 1; - desc.DepthOrArraySize = 1; - desc.MipLevels = 1; - desc.Format = DXGI_FORMAT_UNKNOWN; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; - desc.Flags = D3D12_RESOURCE_FLAG_NONE; - - ComPtr<ID3D12Resource> resource; - Result res = m_device->CreateCommittedResource(&m_desc.m_heapProperties, m_desc.m_heapFlags, &desc, m_desc.m_initialState, nullptr, IID_PPV_ARGS(resource.writeRef())); - if (SLANG_FAILED(res)) - { - assert(!"Resource allocation failed"); - return nullptr; - } - - uint8_t* data = nullptr; - if (m_desc.m_heapProperties.Type == D3D12_HEAP_TYPE_READBACK) - { - } - else - { - // Map it, and keep it mapped - resource->Map(0, nullptr, (void**)&data); - } - - // We have no blocks -> so lets allocate the first - Block* block = (Block*)m_blockFreeList.allocate(); - block->m_next = nullptr; - - block->m_resource = resource.detach(); - block->m_start = data; - return block; -} - -D3D12CircularResourceHeap::Cursor D3D12CircularResourceHeap::allocate(size_t size, size_t alignment) -{ - const size_t blockSize = getBlockSize(); - - assert(size <= blockSize); - - // If nothing is allocated add the first block - if (m_blocks == nullptr) - { - Block* block = _newBlock(); - if (!block) - { - Cursor cursor = {}; - return cursor; - } - m_blocks = block; - // Make circular - block->m_next = block; - - // Point front and back to same position, as currently it is all free - m_back = { block, block->m_start }; - m_front = m_back; - } - - // If front and back are in the same block then front MUST be ahead of back (as that defined as - // an invariant and is required for block insertion to be possible - Block* block = m_front.m_block; - - // Check the invariant - assert(block != m_back.m_block || m_front.m_position >= m_back.m_position); - - { - uint8_t* cur = (uint8_t*)((size_t(m_front.m_position) + alignment - 1) & ~(alignment - 1)); - // Does the the allocation fit? - if (cur + size <= block->m_start + blockSize) - { - // It fits - // Move the front forward - m_front.m_position = cur + size; - Cursor cursor = { block, cur }; - return cursor; - } - } - - // Okay I can't fit into current block... - - // If the next block contains front, we need to add a block, else we can use that block - if (block->m_next == m_back.m_block) - { - Block* newBlock = _newBlock(); - // Insert into the list - newBlock->m_next = block->m_next; - block->m_next = newBlock; - } - - // Use the block we are going to add to - block = block->m_next; - uint8_t* cur = (uint8_t*)((size_t(block->m_start) + alignment - 1) & ~(alignment - 1)); - // Does the the allocation fit? - if (cur + size > block->m_start + blockSize) - { - assert(!"Couldn't fit into a free block(!) Alignment breaks it?"); - Cursor cursor = {}; - return cursor; - } - // It fits - // Move the front forward - m_front.m_block = block; - m_front.m_position = cur + size; - Cursor cursor = { block, cur }; - return cursor; -} - -} // namespace renderer_test diff --git a/tools/render-test/circular-resource-heap-d3d12.h b/tools/render-test/circular-resource-heap-d3d12.h deleted file mode 100644 index baa9a9b0c..000000000 --- a/tools/render-test/circular-resource-heap-d3d12.h +++ /dev/null @@ -1,206 +0,0 @@ -#pragma once - -#include "../../slang-com-ptr.h" -#include "../../source/core/list.h" -#include "../../source/core/slang-free-list.h" - -#include "resource-d3d12.h" - -namespace renderer_test { - -/*! \brief The D3D12CircularResourceHeap is a heap that is suited for size constrained real-time resources allocation that -is transitory in nature. It is designed to allocate resources which are used and discarded, often used where in -previous versions of DirectX the 'DISCARD' flag was used. - -The idea is to have a heap which chunks of resource can be allocated, and used for GPU execution, -and that the heap is able through the addSync/updateCompleted idiom is able to track when the usage of the resources is -completed allowing them to be reused. The heap is arranged as circularly, with new allocations made from the front, and the back -being updated as the GPU updating the back when it is informed anything using prior parts of the heap have completed. In this -arrangement all the heap between the back and the front can be thought of as in use or potentially in use by the GPU. All the heap -from the front back around to the back, is free and can be allocated from. It is the responsibility of the user of the Heap to make -sure the invariant holds, but in most normal usage it does so simply. - -Another feature of the heap is that it does not require upfront knowledge of how big a heap is needed. The backing resources will be expanded -dynamically with requests as needed. The only requirement is that know single request can be larger than m_blockSize specified in the Desc -used to initialize the heap. This is because all the backing resources are allocated to a single size. This limitation means the D3D12CircularResourceHeap -may not be the best use for example for uploading a texture - because it's design is really around transitory uploads or write backs, and so more suited -to constant buffers, vertex buffer, index buffers and the like. - -To upload a texture at program startup it is most likely better to use a D3D12ResourceScopeManager. - -\code{.cpp} - -typedef D3D12CircularResourceHeap Heap; - -Heap::Cursor cursor = heap.allocateVertexBuffer(sizeof(Vertex) * numVerts); -Memory:copy(cursor.m_position, verts, sizeof(Vertex) * numVerts); - -// Do a command using the GPU handle -m_commandList->... -// Do another command using the GPU handle - -m_commandList->... - -// Execute the command list on the command queue -{ - ID3D12CommandList* lists[] = { m_commandList }; - m_commandQueue->ExecuteCommandLists(SLANG_COUNT_OF(lists), lists); -} - -// Add a sync point -const uint64_t signalValue = m_fence.nextSignal(m_commandQueue); -heap.addSync(signalValue) - -// The cursors cannot be used anymore - -// At some later point call updateCompleted. This will see where the GPU is at, and make resources available that the GPU no longer accesses. -heap.updateCompleted(); - -\endcode - -### Implementation - -Front and back can be in the same block, but ONLY if back is behind front, because we have to always be able to insert -new blocks in front of front. So it must be possible to do an block insertion between the two of them. - -|--B---F-----| |----------| - -When B and F are on top of one another it means there is nothing in the list. NOTE this also means that a move of front can never place it -top of the back. - -https://msdn.microsoft.com/en-us/library/windows/desktop/dn899125%28v=vs.85%29.aspx -https://msdn.microsoft.com/en-us/library/windows/desktop/mt426646%28v=vs.85%29.aspx -*/ - -class D3D12CircularResourceHeap -{ - protected: - struct Block; - public: - typedef D3D12CircularResourceHeap ThisType; - - /// The alignment used for VERTEX_BUFFER allocations - /// Strictly speaking it seems the hardware can handle 4 byte alignment, but since often in use - /// data will be copied from CPU memory to the allocation, using 16 byte alignment is superior as allows - /// significantly faster memcpy. - /// The sample that shows sizeof(float) - 4 bytes is appropriate is at the link below. - /// https://msdn.microsoft.com/en-us/library/windows/desktop/mt426646%28v=vs.85%29.aspx - enum - { - VERTEX_BUFFER_ALIGNMENT = 16, - }; - - struct Desc - { - void init() - { - { - D3D12_HEAP_PROPERTIES& props = m_heapProperties; - - props.Type = D3D12_HEAP_TYPE_UPLOAD; - props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - props.CreationNodeMask = 1; - props.VisibleNodeMask = 1; - } - m_heapFlags = D3D12_HEAP_FLAG_NONE; - m_initialState = D3D12_RESOURCE_STATE_GENERIC_READ; - m_blockSize = 0; - } - - D3D12_HEAP_PROPERTIES m_heapProperties; - D3D12_HEAP_FLAGS m_heapFlags; - D3D12_RESOURCE_STATES m_initialState; - size_t m_blockSize; - }; - - /// Cursor position - struct Cursor - { - /// Get GpuHandle - SLANG_FORCE_INLINE D3D12_GPU_VIRTUAL_ADDRESS getGpuHandle() const { return m_block->m_resource->GetGPUVirtualAddress() + size_t(m_position - m_block->m_start); } - /// Must have a block and position - SLANG_FORCE_INLINE bool isValid() const { return m_block != nullptr; } - /// Calculate the offset into the underlying resource - SLANG_FORCE_INLINE size_t getOffset() const { return size_t(m_position - m_block->m_start); } - /// Get the underlying resource - SLANG_FORCE_INLINE ID3D12Resource* getResource() const { return m_block->m_resource; } - - Block* m_block; ///< The block index - uint8_t* m_position; ///< The current position - }; - - /// Get the desc used to initialize the heap - SLANG_FORCE_INLINE const Desc& getDesc() const { return m_desc; } - - /// Must be called before used - /// Block size must be at least as large as the _largest_ thing allocated - /// Also note depending on alignment of a resource allocation, the block size might also need to take into account the - /// maximum alignment use. It is a REQUIREMENT that a newly allocated resource block is large enough to hold any - /// allocation taking into account the alignment used. - Slang::Result init(ID3D12Device* device, const Desc& desc, D3D12CounterFence* fence); - - /// Get the block size - SLANG_FORCE_INLINE size_t getBlockSize() const { return m_desc.m_blockSize; } - - /// Allocate constant buffer of specified size - Cursor allocate(size_t size, size_t alignment); - - /// Allocate a constant buffer - SLANG_FORCE_INLINE Cursor allocateConstantBuffer(size_t size) { return allocate(size, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT); } - /// Allocate a vertex buffer - SLANG_FORCE_INLINE Cursor allocateVertexBuffer(size_t size) { return allocate(size, VERTEX_BUFFER_ALIGNMENT); } - - /// Create filled in constant buffer - SLANG_FORCE_INLINE Cursor newConstantBuffer(const void* data, size_t size) { Cursor cursor = allocateConstantBuffer(size); ::memcpy(cursor.m_position, data, size); return cursor; } - /// Create in filled in constant buffer - template <typename T> - SLANG_FORCE_INLINE Cursor newConstantBuffer(const T& in) { return newConstantBuffer(&in, sizeof(T)); } - - /// Look where the GPU has got to and release anything not currently used - void updateCompleted(); - /// Add a sync point - meaning that when this point is hit in the queue - /// all of the resources up to this point will no longer be used. - void addSync(uint64_t signalValue); - - /// Get the gpu address of this cursor - D3D12_GPU_VIRTUAL_ADDRESS getGpuHandle(const Cursor& cursor) const { return cursor.m_block->m_resource->GetGPUVirtualAddress() + size_t(cursor.m_position - cursor.m_block->m_start); } - - /// Ctor - D3D12CircularResourceHeap(); - /// Dtor - ~D3D12CircularResourceHeap(); - - protected: - - struct Block - { - ID3D12Resource* m_resource; ///< The mapped resource - uint8_t* m_start; ///< Once created the resource is mapped to here - Block* m_next; ///< Points to next block in the list - }; - struct PendingEntry - { - uint64_t m_completedValue; ///< The value when this is completed - Cursor m_cursor; ///< the cursor at that point - }; - void _freeBlockListResources(const Block* block); - /// Create a new block (with associated resource), do not add the block list - Block* _newBlock(); - - Block* m_blocks; ///< Circular singly linked list of block. nullptr initially - Slang::FreeList m_blockFreeList; ///< Free list of actual allocations of blocks - Slang::List<PendingEntry> m_pendingQueue; ///< Holds the list of pending positions. When the fence value is greater than the value on the queue entry, the entry is done. - - // Allocation is made from the front, and freed from the back. - Cursor m_back; ///< Current back position. - Cursor m_front; ///< Current front position. - - Desc m_desc; ///< Describes the heap - - D3D12CounterFence* m_fence; ///< The fence to use - ID3D12Device* m_device; ///< The device that resources will be constructed on -}; - -} // namespace renderer_test - diff --git a/tools/render-test/d3d-util.cpp b/tools/render-test/d3d-util.cpp deleted file mode 100644 index 08aa563ca..000000000 --- a/tools/render-test/d3d-util.cpp +++ /dev/null @@ -1,306 +0,0 @@ -// d3d-util.cpp -#include "d3d-util.h" - -#include <d3dcompiler.h> - -// We will use the C standard library just for printing error messages. -#include <stdio.h> - -namespace renderer_test { -using namespace Slang; - -/* static */D3D_PRIMITIVE_TOPOLOGY D3DUtil::getPrimitiveTopology(PrimitiveTopology topology) -{ - switch (topology) - { - case PrimitiveTopology::TriangleList: - { - return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; - } - default: break; - } - return D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED; -} - -/* static */DXGI_FORMAT D3DUtil::getMapFormat(Format format) -{ - switch (format) - { - case Format::RGBA_Float32: return DXGI_FORMAT_R32G32B32A32_FLOAT; - case Format::RGB_Float32: return DXGI_FORMAT_R32G32B32_FLOAT; - case Format::RG_Float32: return DXGI_FORMAT_R32G32_FLOAT; - case Format::R_Float32: return DXGI_FORMAT_R32_FLOAT; - case Format::RGBA_Unorm_UInt8: return DXGI_FORMAT_R8G8B8A8_UNORM; - case Format::R_UInt32: return DXGI_FORMAT_R32_UINT; - - case Format::D_Float32: return DXGI_FORMAT_D32_FLOAT; - case Format::D_Unorm24_S8: return DXGI_FORMAT_D24_UNORM_S8_UINT; - - default: return DXGI_FORMAT_UNKNOWN; - } -} - -/* static */DXGI_FORMAT D3DUtil::calcResourceFormat(UsageType usage, Int usageFlags, DXGI_FORMAT format) -{ - SLANG_UNUSED(usage); - if (usageFlags) - { - switch (format) - { - case DXGI_FORMAT_R32_FLOAT: /* fallthru */ - case DXGI_FORMAT_R32_UINT: - case DXGI_FORMAT_D32_FLOAT: - { - return DXGI_FORMAT_R32_TYPELESS; - } - case DXGI_FORMAT_D24_UNORM_S8_UINT: return DXGI_FORMAT_R24G8_TYPELESS; - default: break; - } - return format; - } - return format; -} - -/* static */DXGI_FORMAT D3DUtil::calcFormat(UsageType usage, DXGI_FORMAT format) -{ - switch (usage) - { - case USAGE_COUNT_OF: - case USAGE_UNKNOWN: - { - return DXGI_FORMAT_UNKNOWN; - } - case USAGE_DEPTH_STENCIL: - { - switch (format) - { - case DXGI_FORMAT_D32_FLOAT: /* fallthru */ - case DXGI_FORMAT_R32_TYPELESS: - { - return DXGI_FORMAT_D32_FLOAT; - } - case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: return DXGI_FORMAT_D24_UNORM_S8_UINT; - case DXGI_FORMAT_R24G8_TYPELESS: return DXGI_FORMAT_D24_UNORM_S8_UINT; - default: break; - } - return format; - } - case USAGE_TARGET: - { - switch (format) - { - case DXGI_FORMAT_D32_FLOAT: /* fallthru */ - case DXGI_FORMAT_D24_UNORM_S8_UINT: - { - return DXGI_FORMAT_UNKNOWN; - } - case DXGI_FORMAT_R32_TYPELESS: return DXGI_FORMAT_R32_FLOAT; - default: break; - } - return format; - } - case USAGE_SRV: - { - switch (format) - { - case DXGI_FORMAT_D32_FLOAT: /* fallthru */ - case DXGI_FORMAT_R32_TYPELESS: - { - return DXGI_FORMAT_R32_FLOAT; - } - case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: return DXGI_FORMAT_R24_UNORM_X8_TYPELESS; - default: break; - } - - return format; - } - } - - assert(!"Not reachable"); - return DXGI_FORMAT_UNKNOWN; -} - -bool D3DUtil::isTypeless(DXGI_FORMAT format) -{ - switch (format) - { - case DXGI_FORMAT_R32G32B32A32_TYPELESS: - case DXGI_FORMAT_R32G32B32_TYPELESS: - case DXGI_FORMAT_R16G16B16A16_TYPELESS: - case DXGI_FORMAT_R32G32_TYPELESS: - case DXGI_FORMAT_R32G8X24_TYPELESS: - case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: - case DXGI_FORMAT_R10G10B10A2_TYPELESS: - case DXGI_FORMAT_R8G8B8A8_TYPELESS: - case DXGI_FORMAT_R16G16_TYPELESS: - case DXGI_FORMAT_R32_TYPELESS: - case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: - case DXGI_FORMAT_R24G8_TYPELESS: - case DXGI_FORMAT_R8G8_TYPELESS: - case DXGI_FORMAT_R16_TYPELESS: - case DXGI_FORMAT_R8_TYPELESS: - case DXGI_FORMAT_BC1_TYPELESS: - case DXGI_FORMAT_BC2_TYPELESS: - case DXGI_FORMAT_BC3_TYPELESS: - case DXGI_FORMAT_BC4_TYPELESS: - case DXGI_FORMAT_BC5_TYPELESS: - case DXGI_FORMAT_B8G8R8A8_TYPELESS: - case DXGI_FORMAT_BC6H_TYPELESS: - case DXGI_FORMAT_BC7_TYPELESS: - { - return true; - } - default: break; - } - return false; -} - -/* static */Int D3DUtil::getNumColorChannelBits(DXGI_FORMAT fmt) -{ - switch (fmt) - { - case DXGI_FORMAT_R32G32B32A32_TYPELESS: - case DXGI_FORMAT_R32G32B32A32_FLOAT: - case DXGI_FORMAT_R32G32B32A32_UINT: - case DXGI_FORMAT_R32G32B32A32_SINT: - case DXGI_FORMAT_R32G32B32_TYPELESS: - case DXGI_FORMAT_R32G32B32_FLOAT: - case DXGI_FORMAT_R32G32B32_UINT: - case DXGI_FORMAT_R32G32B32_SINT: - { - return 32; - } - case DXGI_FORMAT_R16G16B16A16_TYPELESS: - case DXGI_FORMAT_R16G16B16A16_FLOAT: - case DXGI_FORMAT_R16G16B16A16_UNORM: - case DXGI_FORMAT_R16G16B16A16_UINT: - case DXGI_FORMAT_R16G16B16A16_SNORM: - case DXGI_FORMAT_R16G16B16A16_SINT: - { - return 16; - } - case DXGI_FORMAT_R10G10B10A2_TYPELESS: - case DXGI_FORMAT_R10G10B10A2_UNORM: - case DXGI_FORMAT_R10G10B10A2_UINT: - case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: - { - return 10; - } - case DXGI_FORMAT_R8G8B8A8_TYPELESS: - case DXGI_FORMAT_R8G8B8A8_UNORM: - case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: - case DXGI_FORMAT_R8G8B8A8_UINT: - case DXGI_FORMAT_R8G8B8A8_SNORM: - case DXGI_FORMAT_R8G8B8A8_SINT: - case DXGI_FORMAT_B8G8R8A8_UNORM: - case DXGI_FORMAT_B8G8R8X8_UNORM: - case DXGI_FORMAT_B8G8R8A8_TYPELESS: - case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: - case DXGI_FORMAT_B8G8R8X8_TYPELESS: - case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: - { - return 8; - } - case DXGI_FORMAT_B5G6R5_UNORM: - case DXGI_FORMAT_B5G5R5A1_UNORM: - { - return 5; - } - case DXGI_FORMAT_B4G4R4A4_UNORM: - return 4; - - default: - return 0; - } -} - -// Note: this subroutine is now only used by D3D11 for generating bytecode to go into input layouts. -// -// TODO: we can probably remove that code completely by switching to a PSO-like model across all APIs. -// -/* static */Result D3DUtil::compileHLSLShader(char const* sourcePath, char const* source, char const* entryPointName, char const* dxProfileName, ComPtr<ID3DBlob>& shaderBlobOut) -{ - // Rather than statically link against the `d3dcompile` library, we - // dynamically load it. - // - // Note: A more realistic application would compile from HLSL text to D3D - // shader bytecode as part of an offline process, rather than doing it - // on-the-fly like this - // - static pD3DCompile compileFunc = nullptr; - if (!compileFunc) - { - // TODO(tfoley): maybe want to search for one of a few versions of the DLL - HMODULE compilerModule = LoadLibraryA("d3dcompiler_47.dll"); - if (!compilerModule) - { - fprintf(stderr, "error: failed load 'd3dcompiler_47.dll'\n"); - return SLANG_FAIL; - } - - compileFunc = (pD3DCompile)GetProcAddress(compilerModule, "D3DCompile"); - if (!compileFunc) - { - fprintf(stderr, "error: failed load symbol 'D3DCompile'\n"); - return SLANG_FAIL; - } - } - - // For this example, we turn on debug output, and turn off all - // optimization. A real application would only use these flags - // when shader debugging is needed. - UINT flags = 0; - flags |= D3DCOMPILE_DEBUG; - flags |= D3DCOMPILE_OPTIMIZATION_LEVEL0 | D3DCOMPILE_SKIP_OPTIMIZATION; - - // We will always define `__HLSL__` when compiling here, so that - // input code can react differently to being compiled as pure HLSL. - D3D_SHADER_MACRO defines[] = { - { "__HLSL__", "1" }, - { nullptr, nullptr }, - }; - - // The `D3DCompile` entry point takes a bunch of parameters, but we - // don't really need most of them for Slang-generated code. - ComPtr<ID3DBlob> shaderBlob; - ComPtr<ID3DBlob> errorBlob; - - HRESULT hr = compileFunc(source, strlen(source), sourcePath, &defines[0], nullptr, entryPointName, dxProfileName, flags, 0, - shaderBlob.writeRef(), errorBlob.writeRef()); - - // If the HLSL-to-bytecode compilation produced any diagnostic messages - // then we will print them out (whether or not the compilation failed). - if (errorBlob) - { - ::fputs((const char*)errorBlob->GetBufferPointer(), stderr); - ::fflush(stderr); - ::OutputDebugStringA((const char*)errorBlob->GetBufferPointer()); - } - - SLANG_RETURN_ON_FAIL(hr); - shaderBlobOut.swap(shaderBlob); - return SLANG_OK; -} - -/* static */void D3DUtil::appendWideChars(const char* in, List<wchar_t>& out) -{ - size_t len = ::strlen(in); - - const DWORD dwFlags = 0; - int outSize = ::MultiByteToWideChar(CP_UTF8, dwFlags, in, int(len), nullptr, 0); - - if (outSize > 0) - { - const UInt prevSize = out.Count(); - out.SetSize(prevSize + len + 1); - - WCHAR* dst = out.Buffer() + prevSize; - ::MultiByteToWideChar(CP_UTF8, dwFlags, in, int(len), dst, outSize); - // Make null terminated - dst[outSize] = 0; - // Remove terminating 0 from array - out.UnsafeShrinkToSize(prevSize + outSize); - } -} - -} // renderer_test diff --git a/tools/render-test/d3d-util.h b/tools/render-test/d3d-util.h deleted file mode 100644 index b7a268fd8..000000000 --- a/tools/render-test/d3d-util.h +++ /dev/null @@ -1,61 +0,0 @@ -// d3d-util.h -#pragma once - -#include <stdint.h> - -#include "../../slang-com-helper.h" - -#include "../../slang-com-ptr.h" -#include "../../source/core/list.h" - -#include "render.h" - -#include <D3Dcommon.h> -#include <DXGIFormat.h> - -namespace renderer_test { - -class D3DUtil -{ - public: - enum UsageType - { - USAGE_UNKNOWN, ///< Generally used to mark an error - USAGE_TARGET, ///< Format should be used when written as target - USAGE_DEPTH_STENCIL, ///< Format should be used when written as depth stencil - USAGE_SRV, ///< Format if being read as srv - USAGE_COUNT_OF, - }; - enum UsageFlag - { - USAGE_FLAG_MULTI_SAMPLE = 0x1, ///< If set will be used form multi sampling (such as MSAA) - USAGE_FLAG_SRV = 0x2, ///< If set means will be used as a shader resource view (SRV) - }; - - /// Get primitive topology as D3D primitive topology - static D3D_PRIMITIVE_TOPOLOGY getPrimitiveTopology(PrimitiveTopology prim); - - /// Calculate size taking into account alignment. Alignment must be a power of 2 - static UInt calcAligned(UInt size, UInt alignment) { return (size + alignment - 1) & ~(alignment - 1); } - - /// Compile HLSL code to DXBC - static Slang::Result compileHLSLShader(char const* sourcePath, char const* source, char const* entryPointName, char const* dxProfileName, Slang::ComPtr<ID3DBlob>& shaderBlobOut); - - /// Given a slang pixel format returns the equivalent DXGI_ pixel format. If the format is not known, will return DXGI_FORMAT_UNKNOWN - static DXGI_FORMAT getMapFormat(Format format); - - /// Given the usage, flags, and format will return the most suitable format. Will return DXGI_UNKNOWN if combination is not possible - static DXGI_FORMAT calcFormat(UsageType usage, DXGI_FORMAT format); - /// Calculate appropriate format for creating a buffer for usage and flags - static DXGI_FORMAT calcResourceFormat(UsageType usage, Int usageFlags, DXGI_FORMAT format); - /// True if the type is 'typeless' - static bool isTypeless(DXGI_FORMAT format); - - /// Returns number of bits used for color channel for format (for channels with multiple sizes, returns smallest ie RGB565 -> 5) - static Int getNumColorChannelBits(DXGI_FORMAT fmt); - - /// Append text in in, into wide char array - static void appendWideChars(const char* in, Slang::List<wchar_t>& out); -}; - -} // renderer_test diff --git a/tools/render-test/descriptor-heap-d3d12.cpp b/tools/render-test/descriptor-heap-d3d12.cpp deleted file mode 100644 index 5bd238528..000000000 --- a/tools/render-test/descriptor-heap-d3d12.cpp +++ /dev/null @@ -1,47 +0,0 @@ - -#include "descriptor-heap-d3d12.h" - -namespace renderer_test { -using namespace Slang; - -D3D12DescriptorHeap::D3D12DescriptorHeap(): - m_totalSize(0), - m_currentIndex(0), - m_descriptorSize(0) -{ -} - -Result D3D12DescriptorHeap::init(ID3D12Device* device, int size, D3D12_DESCRIPTOR_HEAP_TYPE type, D3D12_DESCRIPTOR_HEAP_FLAGS flags) -{ - D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {}; - srvHeapDesc.NumDescriptors = size; - srvHeapDesc.Flags = flags; - srvHeapDesc.Type = type; - SLANG_RETURN_ON_FAIL(device->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(m_heap.writeRef()))); - - m_descriptorSize = device->GetDescriptorHandleIncrementSize(type); - m_totalSize = size; - - return SLANG_OK; -} - -Result D3D12DescriptorHeap::init(ID3D12Device* device, const D3D12_CPU_DESCRIPTOR_HANDLE* handles, int numHandles, D3D12_DESCRIPTOR_HEAP_TYPE type, D3D12_DESCRIPTOR_HEAP_FLAGS flags) -{ - SLANG_RETURN_ON_FAIL(init(device, numHandles, type, flags)); - D3D12_CPU_DESCRIPTOR_HANDLE dst = m_heap->GetCPUDescriptorHandleForHeapStart(); - - // Copy them all - for (int i = 0; i < numHandles; i++, dst.ptr += m_descriptorSize) - { - D3D12_CPU_DESCRIPTOR_HANDLE src = handles[i]; - if (src.ptr != 0) - { - device->CopyDescriptorsSimple(1, dst, src, type); - } - } - - return SLANG_OK; -} - -} // namespace renderer_test - diff --git a/tools/render-test/descriptor-heap-d3d12.h b/tools/render-test/descriptor-heap-d3d12.h deleted file mode 100644 index 1d0302d2c..000000000 --- a/tools/render-test/descriptor-heap-d3d12.h +++ /dev/null @@ -1,115 +0,0 @@ -#pragma once - - -#include <dxgi.h> -#include <d3d12.h> - -#include "../../slang-com-ptr.h" - -namespace renderer_test { - -/*! \brief A simple class to manage an underlying Dx12 Descriptor Heap. Allocations are made linearly in order. It is not possible to free -individual allocations, but all allocations can be deallocated with 'deallocateAll'. */ -class D3D12DescriptorHeap -{ - public: - typedef D3D12DescriptorHeap ThisType; - - /// Initialize - Slang::Result init(ID3D12Device* device, int size, D3D12_DESCRIPTOR_HEAP_TYPE type, D3D12_DESCRIPTOR_HEAP_FLAGS flags); - /// Initialize with an array of handles copying over the representation - Slang::Result init(ID3D12Device* device, const D3D12_CPU_DESCRIPTOR_HANDLE* handles, int numHandles, D3D12_DESCRIPTOR_HEAP_TYPE type, D3D12_DESCRIPTOR_HEAP_FLAGS flags); - - /// Returns the number of slots that have been used - SLANG_FORCE_INLINE int getUsedSize() const { return m_currentIndex; } - - /// Get the total amount of descriptors possible on the heap - SLANG_FORCE_INLINE int getTotalSize() const { return m_totalSize; } - /// Allocate a descriptor. Returns the index, or -1 if none left. - SLANG_FORCE_INLINE int allocate(); - /// Allocate a number of descriptors. Returns the start index (or -1 if not possible) - SLANG_FORCE_INLINE int allocate(int numDescriptors); - - /// - SLANG_FORCE_INLINE int placeAt(int index); - - /// Deallocates all allocations, and starts allocation from the start of the underlying heap again - SLANG_FORCE_INLINE void deallocateAll() { m_currentIndex = 0; } - - /// Get the size of each - SLANG_FORCE_INLINE int getDescriptorSize() const { return m_descriptorSize; } - - /// Get the GPU heap start - SLANG_FORCE_INLINE D3D12_GPU_DESCRIPTOR_HANDLE getGpuStart() const { return m_heap->GetGPUDescriptorHandleForHeapStart(); } - /// Get the CPU heap start - SLANG_FORCE_INLINE D3D12_CPU_DESCRIPTOR_HANDLE getCpuStart() const { return m_heap->GetCPUDescriptorHandleForHeapStart(); } - - /// Get the GPU handle at the specified index - SLANG_FORCE_INLINE D3D12_GPU_DESCRIPTOR_HANDLE getGpuHandle(int index) const; - /// Get the CPU handle at the specified index - SLANG_FORCE_INLINE D3D12_CPU_DESCRIPTOR_HANDLE getCpuHandle(int index) const; - - /// Get the underlying heap - SLANG_FORCE_INLINE ID3D12DescriptorHeap* getHeap() const { return m_heap; } - - /// Ctor - D3D12DescriptorHeap(); - -protected: - Slang::ComPtr<ID3D12DescriptorHeap> m_heap; ///< The underlying heap being allocated from - int m_totalSize; ///< Total amount of allocations available on the heap - int m_currentIndex; ///< The current descriptor - int m_descriptorSize; ///< The size of each descriptor -}; - -// --------------------------------------------------------------------------- -int D3D12DescriptorHeap::allocate() -{ - assert(m_currentIndex < m_totalSize); - if (m_currentIndex < m_totalSize) - { - return m_currentIndex++; - } - return -1; -} -// --------------------------------------------------------------------------- -int D3D12DescriptorHeap::allocate(int numDescriptors) -{ - assert(m_currentIndex + numDescriptors <= m_totalSize); - if (m_currentIndex + numDescriptors <= m_totalSize) - { - const int index = m_currentIndex; - m_currentIndex += numDescriptors; - return index; - } - return -1; -} -// --------------------------------------------------------------------------- -SLANG_FORCE_INLINE int D3D12DescriptorHeap::placeAt(int index) -{ - assert(index >= 0 && index < m_totalSize); - m_currentIndex = index + 1; - return index; -} - -// --------------------------------------------------------------------------- -SLANG_FORCE_INLINE D3D12_CPU_DESCRIPTOR_HANDLE D3D12DescriptorHeap::getCpuHandle(int index) const -{ - assert(index >= 0 && index < m_totalSize); - D3D12_CPU_DESCRIPTOR_HANDLE start = m_heap->GetCPUDescriptorHandleForHeapStart(); - D3D12_CPU_DESCRIPTOR_HANDLE dst; - dst.ptr = start.ptr + m_descriptorSize * index; - return dst; -} -// --------------------------------------------------------------------------- -SLANG_FORCE_INLINE D3D12_GPU_DESCRIPTOR_HANDLE D3D12DescriptorHeap::getGpuHandle(int index) const -{ - assert(index >= 0 && index < m_totalSize); - D3D12_GPU_DESCRIPTOR_HANDLE start = m_heap->GetGPUDescriptorHandleForHeapStart(); - D3D12_GPU_DESCRIPTOR_HANDLE dst; - dst.ptr = start.ptr + m_descriptorSize * index; - return dst; -} - -} // namespace renderer_test - diff --git a/tools/render-test/options.h b/tools/render-test/options.h index a14acec15..82c018f66 100644 --- a/tools/render-test/options.h +++ b/tools/render-test/options.h @@ -9,6 +9,8 @@ namespace renderer_test { +using namespace slang_graphics; + struct Options { enum @@ -25,7 +27,7 @@ struct Options // Raw HLSL or GLSL input, bypassing Slang Native, }; - + enum class ShaderProgramType { diff --git a/tools/render-test/png-serialize-util.h b/tools/render-test/png-serialize-util.h index fe3b4f873..dad17ae74 100644 --- a/tools/render-test/png-serialize-util.h +++ b/tools/render-test/png-serialize-util.h @@ -2,10 +2,12 @@ #pragma once #include "surface.h" - + namespace renderer_test { -struct PngSerializeUtil +using namespace slang_graphics; + +struct PngSerializeUtil { static Slang::Result write(const char* filename, const Surface& surface); diff --git a/tools/render-test/render-d3d11.cpp b/tools/render-test/render-d3d11.cpp deleted file mode 100644 index 109c5aca1..000000000 --- a/tools/render-test/render-d3d11.cpp +++ /dev/null @@ -1,1101 +0,0 @@ -// render-d3d11.cpp - -#define _CRT_SECURE_NO_WARNINGS - -#include "render-d3d11.h" - -#include "options.h" -#include "render.h" -#include "d3d-util.h" - -#include "surface.h" - -// In order to use the Slang API, we need to include its header - -#include <slang.h> - -#include "../../slang-com-ptr.h" - -// We will be rendering with Direct3D 11, so we need to include -// the Windows and D3D11 headers - -#define WIN32_LEAN_AND_MEAN -#define NOMINMAX -#include <Windows.h> -#undef WIN32_LEAN_AND_MEAN -#undef NOMINMAX - -#include <d3d11_2.h> -#include <d3dcompiler.h> - -// We will use the C standard library just for printing error messages. -#include <stdio.h> - -#ifdef _MSC_VER -#include <stddef.h> -#if (_MSC_VER < 1900) -#define snprintf sprintf_s -#endif -#endif -// -using namespace Slang; - -namespace renderer_test { - -class D3D11Renderer : public Renderer -{ -public: - // Renderer implementation - virtual SlangResult initialize(const Desc& desc, void* inWindowHandle) override; - virtual void setClearColor(const float color[4]) override; - virtual void clearFrame() override; - virtual void presentFrame() override; - virtual TextureResource* createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData) override; - virtual BufferResource* createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& bufferDesc, const void* initData) override; - virtual SlangResult captureScreenSurface(Surface& surfaceOut) override; - virtual InputLayout* createInputLayout( const InputElementDesc* inputElements, UInt inputElementCount) override; - virtual BindingState* createBindingState(const BindingState::Desc& desc) override; - virtual ShaderProgram* createProgram(const ShaderProgram::Desc& desc) override; - virtual void* map(BufferResource* buffer, MapFlavor flavor) override; - virtual void unmap(BufferResource* buffer) override; - virtual void setInputLayout(InputLayout* inputLayout) override; - virtual void setPrimitiveTopology(PrimitiveTopology topology) override; - virtual void setBindingState(BindingState * state); - virtual void setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) override; - virtual void setShaderProgram(ShaderProgram* inProgram) override; - virtual void draw(UInt vertexCount, UInt startVertex) override; - virtual void dispatchCompute(int x, int y, int z) override; - virtual void submitGpuWork() override {} - virtual void waitForGpu() override {} - virtual RendererType getRendererType() const override { return RendererType::DirectX11; } - - protected: - - struct BindingDetail - { - ComPtr<ID3D11ShaderResourceView> m_srv; - ComPtr<ID3D11UnorderedAccessView> m_uav; - ComPtr<ID3D11SamplerState> m_samplerState; - }; - - class BindingStateImpl: public BindingState - { - public: - typedef BindingState Parent; - - /// Ctor - BindingStateImpl(const Desc& desc): - Parent(desc) - {} - - List<BindingDetail> m_bindingDetails; - }; - - class ShaderProgramImpl: public ShaderProgram - { - public: - ComPtr<ID3D11VertexShader> m_vertexShader; - ComPtr<ID3D11PixelShader> m_pixelShader; - ComPtr<ID3D11ComputeShader> m_computeShader; - }; - - class BufferResourceImpl: public BufferResource - { - public: - typedef BufferResource Parent; - - BufferResourceImpl(const Desc& desc, Usage initialUsage): - Parent(desc), - m_initialUsage(initialUsage) - { - } - - MapFlavor m_mapFlavor; - Usage m_initialUsage; - ComPtr<ID3D11Buffer> m_buffer; - ComPtr<ID3D11Buffer> m_staging; - }; - class TextureResourceImpl : public TextureResource - { - public: - typedef TextureResource Parent; - - TextureResourceImpl(const Desc& desc, Usage initialUsage) : - Parent(desc), - m_initialUsage(initialUsage) - { - } - Usage m_initialUsage; - ComPtr<ID3D11Resource> m_resource; - }; - - class InputLayoutImpl: public InputLayout - { - public: - ComPtr<ID3D11InputLayout> m_layout; - }; - - /// Capture a texture to a file - static HRESULT captureTextureToSurface(ID3D11Device* device, ID3D11DeviceContext* context, ID3D11Texture2D* texture, Surface& surfaceOut); - - void _applyBindingState(bool isCompute); - - ComPtr<IDXGISwapChain> m_swapChain; - ComPtr<ID3D11Device> m_device; - ComPtr<ID3D11DeviceContext> m_immediateContext; - ComPtr<ID3D11Texture2D> m_backBufferTexture; - - List<ComPtr<ID3D11RenderTargetView> > m_renderTargetViews; - List<ComPtr<ID3D11Texture2D> > m_renderTargetTextures; - - RefPtr<BindingStateImpl> m_currentBindings; - - Desc m_desc; - - float m_clearColor[4] = { 0, 0, 0, 0 }; -}; - -Renderer* createD3D11Renderer() -{ - return new D3D11Renderer(); -} - -/* static */HRESULT D3D11Renderer::captureTextureToSurface(ID3D11Device* device, ID3D11DeviceContext* context, ID3D11Texture2D* texture, Surface& surfaceOut) -{ - if (!context) return E_INVALIDARG; - if (!texture) return E_INVALIDARG; - - D3D11_TEXTURE2D_DESC textureDesc; - texture->GetDesc(&textureDesc); - - // Don't bother supporting MSAA for right now - if (textureDesc.SampleDesc.Count > 1) - { - fprintf(stderr, "ERROR: cannot capture multi-sample texture\n"); - return E_INVALIDARG; - } - - HRESULT hr = S_OK; - ComPtr<ID3D11Texture2D> stagingTexture; - - if (textureDesc.Usage == D3D11_USAGE_STAGING && (textureDesc.CPUAccessFlags & D3D11_CPU_ACCESS_READ)) - { - stagingTexture = texture; - } - else - { - // Modify the descriptor to give us a staging texture - textureDesc.BindFlags = 0; - textureDesc.MiscFlags &= ~D3D11_RESOURCE_MISC_TEXTURECUBE; - textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - textureDesc.Usage = D3D11_USAGE_STAGING; - - hr = device->CreateTexture2D(&textureDesc, 0, stagingTexture.writeRef()); - if (FAILED(hr)) - { - fprintf(stderr, "ERROR: failed to create staging texture\n"); - return hr; - } - - context->CopyResource(stagingTexture, texture); - } - - // Now just read back texels from the staging textures - { - D3D11_MAPPED_SUBRESOURCE mappedResource; - SLANG_RETURN_ON_FAIL(context->Map(stagingTexture, 0, D3D11_MAP_READ, 0, &mappedResource)); - - Result res = surfaceOut.set(textureDesc.Width, textureDesc.Height, Format::RGBA_Unorm_UInt8, mappedResource.RowPitch, mappedResource.pData, SurfaceAllocator::getMallocAllocator()); - - // Make sure to unmap - context->Unmap(stagingTexture, 0); - return res; - } -} - -// !!!!!!!!!!!!!!!!!!!!!!!!!!!! Renderer interface !!!!!!!!!!!!!!!!!!!!!!!!!! - -SlangResult D3D11Renderer::initialize(const Desc& desc, void* inWindowHandle) -{ - auto windowHandle = (HWND)inWindowHandle; - m_desc = desc; - - // Rather than statically link against D3D, we load it dynamically. - HMODULE d3dModule = LoadLibraryA("d3d11.dll"); - if (!d3dModule) - { - fprintf(stderr, "error: failed load 'd3d11.dll'\n"); - return SLANG_FAIL; - } - - PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN D3D11CreateDeviceAndSwapChain_ = - (PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN)GetProcAddress(d3dModule, "D3D11CreateDeviceAndSwapChain"); - if (!D3D11CreateDeviceAndSwapChain_) - { - fprintf(stderr, - "error: failed load symbol 'D3D11CreateDeviceAndSwapChain'\n"); - return SLANG_FAIL; - } - - // We create our device in debug mode, just so that we can check that the - // example doesn't trigger warnings. - UINT deviceFlags = 0; - deviceFlags |= D3D11_CREATE_DEVICE_DEBUG; - - // Our swap chain uses RGBA8 with sRGB, with double buffering. - DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 }; - swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - - // Note(tfoley): Disabling sRGB for DX back buffer for now, so that we - // can get consistent output with OpenGL, where setting up sRGB will - // probably be more involved. - // swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; - swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - - swapChainDesc.SampleDesc.Count = 1; - swapChainDesc.SampleDesc.Quality = 0; - swapChainDesc.BufferCount = 2; - swapChainDesc.OutputWindow = windowHandle; - swapChainDesc.Windowed = TRUE; - swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; - swapChainDesc.Flags = 0; - - // We will ask for the highest feature level that can be supported. - const D3D_FEATURE_LEVEL featureLevels[] = { - D3D_FEATURE_LEVEL_11_1, - D3D_FEATURE_LEVEL_11_0, - D3D_FEATURE_LEVEL_10_1, - D3D_FEATURE_LEVEL_10_0, - D3D_FEATURE_LEVEL_9_3, - D3D_FEATURE_LEVEL_9_2, - D3D_FEATURE_LEVEL_9_1, - }; - D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_9_1; - const int totalNumFeatureLevels = SLANG_COUNT_OF(featureLevels); - - // On a machine that does not have an up-to-date version of D3D installed, - // the `D3D11CreateDeviceAndSwapChain` call will fail with `E_INVALIDARG` - // if you ask for featuer level 11_1. The workaround is to call - // `D3D11CreateDeviceAndSwapChain` up to twice: the first time with 11_1 - // at the start of the list of requested feature levels, and the second - // time without it. - - for (int ii = 0; ii < 2; ++ii) - { - const HRESULT hr = D3D11CreateDeviceAndSwapChain_( - nullptr, // adapter (use default) - D3D_DRIVER_TYPE_REFERENCE, - //D3D_DRIVER_TYPE_HARDWARE, - nullptr, // software - deviceFlags, - &featureLevels[ii], - totalNumFeatureLevels - ii, - D3D11_SDK_VERSION, - &swapChainDesc, - m_swapChain.writeRef(), - m_device.writeRef(), - &featureLevel, - m_immediateContext.writeRef()); - - // Failures with `E_INVALIDARG` might be due to feature level 11_1 - // not being supported. - if (hr == E_INVALIDARG) - { - continue; - } - - // Other failures are real, though. - SLANG_RETURN_ON_FAIL(hr); - // We must have a swap chain - break; - } - - // After we've created the swap chain, we can request a pointer to the - // back buffer as a D3D11 texture, and create a render-target view from it. - - static const IID kIID_ID3D11Texture2D = { - 0x6f15aaf2, 0xd208, 0x4e89, 0x9a, 0xb4, 0x48, - 0x95, 0x35, 0xd3, 0x4f, 0x9c }; - - SLANG_RETURN_ON_FAIL(m_swapChain->GetBuffer(0, kIID_ID3D11Texture2D, (void**)m_backBufferTexture.writeRef())); - - for (int i = 0; i < 8; i++) - { - ComPtr<ID3D11Texture2D> texture; - D3D11_TEXTURE2D_DESC textureDesc; - m_backBufferTexture->GetDesc(&textureDesc); - SLANG_RETURN_ON_FAIL(m_device->CreateTexture2D(&textureDesc, nullptr, texture.writeRef())); - - ComPtr<ID3D11RenderTargetView> rtv; - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - rtvDesc.Texture2D.MipSlice = 0; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - SLANG_RETURN_ON_FAIL(m_device->CreateRenderTargetView(texture, &rtvDesc, rtv.writeRef())); - - m_renderTargetViews.Add(rtv); - m_renderTargetTextures.Add(texture); - } - - m_immediateContext->OMSetRenderTargets((UINT)m_renderTargetViews.Count(), m_renderTargetViews.Buffer()->readRef(), nullptr); - - // Similarly, we are going to set up a viewport once, and then never - // switch, since this is a simple test app. - D3D11_VIEWPORT viewport; - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - viewport.Width = (float)desc.width; - viewport.Height = (float)desc.height; - viewport.MaxDepth = 1; // TODO(tfoley): use reversed depth - viewport.MinDepth = 0; - m_immediateContext->RSSetViewports(1, &viewport); - - return SLANG_OK; -} - -void D3D11Renderer::setClearColor(const float color[4]) -{ - memcpy(m_clearColor, color, sizeof(m_clearColor)); -} - -void D3D11Renderer::clearFrame() -{ - for (auto i = 0u; i < m_renderTargetViews.Count(); i++) - { - m_immediateContext->ClearRenderTargetView(m_renderTargetViews[i], m_clearColor); - } -} - -void D3D11Renderer::presentFrame() -{ - m_immediateContext->CopyResource(m_backBufferTexture, m_renderTargetTextures[0]); - m_swapChain->Present(0, 0); -} - -SlangResult D3D11Renderer::captureScreenSurface(Surface& surfaceOut) -{ - return captureTextureToSurface(m_device, m_immediateContext, m_renderTargetTextures[0], surfaceOut); -} - -static D3D11_BIND_FLAG _calcResourceFlag(Resource::BindFlag::Enum bindFlag) -{ - typedef Resource::BindFlag BindFlag; - switch (bindFlag) - { - case BindFlag::VertexBuffer: return D3D11_BIND_VERTEX_BUFFER; - case BindFlag::IndexBuffer: return D3D11_BIND_INDEX_BUFFER; - case BindFlag::ConstantBuffer: return D3D11_BIND_CONSTANT_BUFFER; - case BindFlag::StreamOutput: return D3D11_BIND_STREAM_OUTPUT; - case BindFlag::RenderTarget: return D3D11_BIND_RENDER_TARGET; - case BindFlag::DepthStencil: return D3D11_BIND_DEPTH_STENCIL; - case BindFlag::UnorderedAccess: return D3D11_BIND_UNORDERED_ACCESS; - case BindFlag::PixelShaderResource: return D3D11_BIND_SHADER_RESOURCE; - case BindFlag::NonPixelShaderResource: return D3D11_BIND_SHADER_RESOURCE; - default: return D3D11_BIND_FLAG(0); - } -} - -static int _calcResourceBindFlags(int bindFlags) -{ - int dstFlags = 0; - while (bindFlags) - { - int lsb = bindFlags & -bindFlags; - - dstFlags |= _calcResourceFlag(Resource::BindFlag::Enum(lsb)); - bindFlags &= ~lsb; - } - return dstFlags; -} - -static int _calcResourceAccessFlags(int accessFlags) -{ - switch (accessFlags) - { - case 0: return 0; - case Resource::AccessFlag::Read: return D3D11_CPU_ACCESS_READ; - case Resource::AccessFlag::Write: return D3D11_CPU_ACCESS_WRITE; - case Resource::AccessFlag::Read | - Resource::AccessFlag::Write: return D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; - default: assert(!"Invalid flags"); return 0; - } -} - -TextureResource* D3D11Renderer::createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& descIn, const TextureResource::Data* initData) -{ - TextureResource::Desc srcDesc(descIn); - srcDesc.setDefaults(initialUsage); - - const int effectiveArraySize = srcDesc.calcEffectiveArraySize(); - - assert(initData); - assert(initData->numSubResources == srcDesc.numMipLevels * effectiveArraySize * srcDesc.size.depth); - - const DXGI_FORMAT format = D3DUtil::getMapFormat(srcDesc.format); - if (format == DXGI_FORMAT_UNKNOWN) - { - return nullptr; - } - - const int bindFlags = _calcResourceBindFlags(srcDesc.bindFlags); - - // Set up the initialize data - List<D3D11_SUBRESOURCE_DATA> subRes; - subRes.SetSize(srcDesc.numMipLevels * effectiveArraySize); - { - int subResourceIndex = 0; - for (int i = 0; i < effectiveArraySize; i++) - { - for (int j = 0; j < srcDesc.numMipLevels; j++) - { - const int mipHeight = TextureResource::calcMipSize(srcDesc.size.height, j); - - D3D11_SUBRESOURCE_DATA& data = subRes[subResourceIndex]; - - data.pSysMem = initData->subResources[subResourceIndex]; - - data.SysMemPitch = UINT(initData->mipRowStrides[j]); - data.SysMemSlicePitch = UINT(initData->mipRowStrides[j] * mipHeight); - - subResourceIndex++; - } - } - } - - const int accessFlags = _calcResourceAccessFlags(srcDesc.cpuAccessFlags); - - RefPtr<TextureResourceImpl> texture(new TextureResourceImpl(srcDesc, initialUsage)); - - switch (srcDesc.type) - { - case Resource::Type::Texture1D: - { - D3D11_TEXTURE1D_DESC desc = { 0 }; - desc.BindFlags = bindFlags; - desc.CPUAccessFlags = accessFlags; - desc.Format = format; - desc.MiscFlags = 0; - desc.MipLevels = srcDesc.numMipLevels; - desc.ArraySize = effectiveArraySize; - desc.Width = srcDesc.size.width; - desc.Usage = D3D11_USAGE_DEFAULT; - - ComPtr<ID3D11Texture1D> texture1D; - SLANG_RETURN_NULL_ON_FAIL(m_device->CreateTexture1D(&desc, subRes.Buffer(), texture1D.writeRef())); - - texture->m_resource = texture1D; - break; - } - case Resource::Type::TextureCube: - case Resource::Type::Texture2D: - { - D3D11_TEXTURE2D_DESC desc = { 0 }; - desc.BindFlags = bindFlags; - desc.CPUAccessFlags = accessFlags; - desc.Format = format; - desc.MiscFlags = 0; - desc.MipLevels = srcDesc.numMipLevels; - desc.ArraySize = effectiveArraySize; - - desc.Width = srcDesc.size.width; - desc.Height = srcDesc.size.height; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.SampleDesc.Count = srcDesc.sampleDesc.numSamples; - desc.SampleDesc.Quality = srcDesc.sampleDesc.quality; - - if (srcDesc.type == Resource::Type::TextureCube) - { - desc.MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE; - } - - ComPtr<ID3D11Texture2D> texture2D; - SLANG_RETURN_NULL_ON_FAIL(m_device->CreateTexture2D(&desc, subRes.Buffer(), texture2D.writeRef())); - - texture->m_resource = texture2D; - break; - } - case Resource::Type::Texture3D: - { - D3D11_TEXTURE3D_DESC desc = { 0 }; - desc.BindFlags = bindFlags; - desc.CPUAccessFlags = accessFlags; - desc.Format = format; - desc.MiscFlags = 0; - desc.MipLevels = srcDesc.numMipLevels; - desc.Width = srcDesc.size.width; - desc.Height = srcDesc.size.height; - desc.Depth = srcDesc.size.depth; - desc.Usage = D3D11_USAGE_DEFAULT; - - ComPtr<ID3D11Texture3D> texture3D; - SLANG_RETURN_NULL_ON_FAIL(m_device->CreateTexture3D(&desc, subRes.Buffer(), texture3D.writeRef())); - - texture->m_resource = texture3D; - break; - } - default: return nullptr; - } - - return texture.detach(); -} - -BufferResource* D3D11Renderer::createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& descIn, const void* initData) -{ - BufferResource::Desc srcDesc(descIn); - srcDesc.setDefaults(initialUsage); - - // Make aligned to 256 bytes... not sure why, but if you remove this the tests do fail. - const size_t alignedSizeInBytes = D3DUtil::calcAligned(srcDesc.sizeInBytes, 256); - - // Hack to make the initialization never read from out of bounds memory, by copying into a buffer - List<uint8_t> initDataBuffer; - if (initData && alignedSizeInBytes > srcDesc.sizeInBytes) - { - initDataBuffer.SetSize(alignedSizeInBytes); - ::memcpy(initDataBuffer.Buffer(), initData, srcDesc.sizeInBytes); - initData = initDataBuffer.Buffer(); - } - - D3D11_BUFFER_DESC bufferDesc = { 0 }; - bufferDesc.ByteWidth = UINT(alignedSizeInBytes); - bufferDesc.BindFlags = _calcResourceBindFlags(srcDesc.bindFlags); - // For read we'll need to do some staging - bufferDesc.CPUAccessFlags = _calcResourceAccessFlags(descIn.cpuAccessFlags & Resource::AccessFlag::Write); - bufferDesc.Usage = D3D11_USAGE_DEFAULT; - - // If written by CPU, make it dynamic - if (descIn.cpuAccessFlags & Resource::AccessFlag::Write) - { - bufferDesc.Usage = D3D11_USAGE_DYNAMIC; - } - - switch (initialUsage) - { - case Resource::Usage::ConstantBuffer: - { - // We'll just assume ConstantBuffers are dynamic for now - bufferDesc.Usage = D3D11_USAGE_DYNAMIC; - break; - } - default: break; - } - - if (bufferDesc.BindFlags & (D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE)) - { - //desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE; - if (srcDesc.elementSize != 0) - { - bufferDesc.StructureByteStride = srcDesc.elementSize; - bufferDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; - } - else - { - bufferDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS; - } - } - - D3D11_SUBRESOURCE_DATA subResourceData = { 0 }; - subResourceData.pSysMem = initData; - - RefPtr<BufferResourceImpl> buffer(new BufferResourceImpl(srcDesc, initialUsage)); - - SLANG_RETURN_NULL_ON_FAIL(m_device->CreateBuffer(&bufferDesc, initData ? &subResourceData : nullptr, buffer->m_buffer.writeRef())); - - if (srcDesc.cpuAccessFlags & Resource::AccessFlag::Read) - { - D3D11_BUFFER_DESC bufDesc = {}; - bufDesc.BindFlags = 0; - bufDesc.ByteWidth = (UINT)alignedSizeInBytes; - bufDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - bufDesc.Usage = D3D11_USAGE_STAGING; - - SLANG_RETURN_NULL_ON_FAIL(m_device->CreateBuffer(&bufDesc, nullptr, buffer->m_staging.writeRef())); - } - - return buffer.detach(); -} - -InputLayout* D3D11Renderer::createInputLayout(const InputElementDesc* inputElementsIn, UInt inputElementCount) -{ - D3D11_INPUT_ELEMENT_DESC inputElements[16] = {}; - - char hlslBuffer[1024]; - char* hlslCursor = &hlslBuffer[0]; - - hlslCursor += sprintf(hlslCursor, "float4 main(\n"); - - for (UInt ii = 0; ii < inputElementCount; ++ii) - { - inputElements[ii].SemanticName = inputElementsIn[ii].semanticName; - inputElements[ii].SemanticIndex = (UINT)inputElementsIn[ii].semanticIndex; - inputElements[ii].Format = D3DUtil::getMapFormat(inputElementsIn[ii].format); - inputElements[ii].InputSlot = 0; - inputElements[ii].AlignedByteOffset = (UINT)inputElementsIn[ii].offset; - inputElements[ii].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; - inputElements[ii].InstanceDataStepRate = 0; - - if (ii != 0) - { - hlslCursor += sprintf(hlslCursor, ",\n"); - } - - char const* typeName = "Unknown"; - switch (inputElementsIn[ii].format) - { - case Format::RGBA_Float32: - typeName = "float4"; - break; - case Format::RGB_Float32: - typeName = "float3"; - break; - case Format::RG_Float32: - typeName = "float2"; - break; - case Format::R_Float32: - typeName = "float"; - break; - default: - return nullptr; - } - - hlslCursor += sprintf(hlslCursor, "%s a%d : %s%d", - typeName, - (int)ii, - inputElementsIn[ii].semanticName, - (int)inputElementsIn[ii].semanticIndex); - } - - hlslCursor += sprintf(hlslCursor, "\n) : SV_Position { return 0; }"); - - ComPtr<ID3DBlob> vertexShaderBlob; - SLANG_RETURN_NULL_ON_FAIL(D3DUtil::compileHLSLShader("inputLayout", hlslBuffer, "main", "vs_5_0", vertexShaderBlob)); - - ComPtr<ID3D11InputLayout> inputLayout; - SLANG_RETURN_NULL_ON_FAIL(m_device->CreateInputLayout(&inputElements[0], (UINT)inputElementCount, vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), - inputLayout.writeRef())); - - InputLayoutImpl* impl = new InputLayoutImpl; - impl->m_layout.swap(inputLayout); - - return impl; -} - -void* D3D11Renderer::map(BufferResource* bufferIn, MapFlavor flavor) -{ - BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(bufferIn); - - D3D11_MAP mapType; - ID3D11Buffer* buffer = bufferResource->m_buffer; - - switch (flavor) - { - case MapFlavor::WriteDiscard: - mapType = D3D11_MAP_WRITE_DISCARD; - break; - case MapFlavor::HostWrite: - mapType = D3D11_MAP_WRITE; - break; - case MapFlavor::HostRead: - mapType = D3D11_MAP_READ; - - buffer = bufferResource->m_staging; - if (!buffer) - { - return nullptr; - } - - // Okay copy the data over - m_immediateContext->CopyResource(buffer, bufferResource->m_buffer); - - break; - default: - return nullptr; - } - - // We update our constant buffer per-frame, just for the purposes - // of the example, but we don't actually load different data - // per-frame (we always use an identity projection). - D3D11_MAPPED_SUBRESOURCE mappedSub; - SLANG_RETURN_NULL_ON_FAIL(m_immediateContext->Map(buffer, 0, mapType, 0, &mappedSub)); - - bufferResource->m_mapFlavor = flavor; - - return mappedSub.pData; -} - -void D3D11Renderer::unmap(BufferResource* bufferIn) -{ - BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(bufferIn); - ID3D11Buffer* buffer = (bufferResource->m_mapFlavor == MapFlavor::HostRead) ? bufferResource->m_staging : bufferResource->m_buffer; - m_immediateContext->Unmap(buffer, 0); -} - -void D3D11Renderer::setInputLayout(InputLayout* inputLayoutIn) -{ - auto inputLayout = static_cast<InputLayoutImpl*>(inputLayoutIn); - m_immediateContext->IASetInputLayout(inputLayout->m_layout); -} - -void D3D11Renderer::setPrimitiveTopology(PrimitiveTopology topology) -{ - m_immediateContext->IASetPrimitiveTopology(D3DUtil::getPrimitiveTopology(topology)); -} - -void D3D11Renderer::setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffersIn, const UInt* stridesIn, const UInt* offsetsIn) -{ - static const int kMaxVertexBuffers = 16; - assert(slotCount <= kMaxVertexBuffers); - - UINT vertexStrides[kMaxVertexBuffers]; - UINT vertexOffsets[kMaxVertexBuffers]; - ID3D11Buffer* dxBuffers[kMaxVertexBuffers]; - - auto buffers = (BufferResourceImpl*const*)buffersIn; - - for (UInt ii = 0; ii < slotCount; ++ii) - { - vertexStrides[ii] = (UINT)stridesIn[ii]; - vertexOffsets[ii] = (UINT)offsetsIn[ii]; - dxBuffers[ii] = buffers[ii]->m_buffer; - } - - m_immediateContext->IASetVertexBuffers((UINT)startSlot, (UINT)slotCount, dxBuffers, &vertexStrides[0], &vertexOffsets[0]); -} - -void D3D11Renderer::setShaderProgram(ShaderProgram* programIn) -{ - auto program = (ShaderProgramImpl*)programIn; - m_immediateContext->CSSetShader(program->m_computeShader, nullptr, 0); - m_immediateContext->VSSetShader(program->m_vertexShader, nullptr, 0); - m_immediateContext->PSSetShader(program->m_pixelShader, nullptr, 0); -} - -void D3D11Renderer::draw(UInt vertexCount, UInt startVertex) -{ - _applyBindingState(false); - m_immediateContext->Draw((UINT)vertexCount, (UINT)startVertex); -} - -ShaderProgram* D3D11Renderer::createProgram(const ShaderProgram::Desc& desc) -{ - if (desc.pipelineType == PipelineType::Compute) - { - auto computeKernel = desc.findKernel(StageType::Compute); - - ComPtr<ID3D11ComputeShader> computeShader; - SLANG_RETURN_NULL_ON_FAIL(m_device->CreateComputeShader(computeKernel->codeBegin, computeKernel->getCodeSize(), nullptr, computeShader.writeRef())); - - ShaderProgramImpl* shaderProgram = new ShaderProgramImpl(); - shaderProgram->m_computeShader.swap(computeShader); - return shaderProgram; - } - else - { - auto vertexKernel = desc.findKernel(StageType::Vertex); - auto fragmentKernel = desc.findKernel(StageType::Fragment); - - ComPtr<ID3D11VertexShader> vertexShader; - ComPtr<ID3D11PixelShader> pixelShader; - - SLANG_RETURN_NULL_ON_FAIL(m_device->CreateVertexShader(vertexKernel->codeBegin, vertexKernel->getCodeSize(), nullptr, vertexShader.writeRef())); - SLANG_RETURN_NULL_ON_FAIL(m_device->CreatePixelShader(fragmentKernel->codeBegin, fragmentKernel->getCodeSize(), nullptr, pixelShader.writeRef())); - - ShaderProgramImpl* shaderProgram = new ShaderProgramImpl(); - shaderProgram->m_vertexShader.swap(vertexShader); - shaderProgram->m_pixelShader.swap(pixelShader); - return shaderProgram; - } -} - -void D3D11Renderer::dispatchCompute(int x, int y, int z) -{ - _applyBindingState(true); - m_immediateContext->Dispatch(x, y, z); -} - -BindingState* D3D11Renderer::createBindingState(const BindingState::Desc& bindingStateDesc) -{ - RefPtr<BindingStateImpl> bindingState(new BindingStateImpl(bindingStateDesc)); - - const auto& srcBindings = bindingStateDesc.m_bindings; - const int numBindings = int(srcBindings.Count()); - - auto& dstDetails = bindingState->m_bindingDetails; - dstDetails.SetSize(numBindings); - - for (int i = 0; i < numBindings; ++i) - { - auto& dstDetail = dstDetails[i]; - const auto& srcBinding = srcBindings[i]; - - assert(srcBinding.registerRange.isSingle()); - - switch (srcBinding.bindingType) - { - case BindingType::Buffer: - { - assert(srcBinding.resource && srcBinding.resource->isBuffer()); - - BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(srcBinding.resource.Ptr()); - const BufferResource::Desc& bufferDesc = buffer->getDesc(); - - const int elemSize = bufferDesc.elementSize <= 0 ? 1 : bufferDesc.elementSize; - - if (bufferDesc.bindFlags & Resource::BindFlag::UnorderedAccess) - { - D3D11_UNORDERED_ACCESS_VIEW_DESC viewDesc; - memset(&viewDesc, 0, sizeof(viewDesc)); - viewDesc.Buffer.FirstElement = 0; - viewDesc.Buffer.NumElements = (UINT)(bufferDesc.sizeInBytes / elemSize); - viewDesc.Buffer.Flags = 0; - viewDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; - viewDesc.Format = D3DUtil::getMapFormat(bufferDesc.format); - - if (bufferDesc.elementSize == 0 && bufferDesc.format == Format::Unknown) - { - viewDesc.Buffer.Flags |= D3D11_BUFFER_UAV_FLAG_RAW; - viewDesc.Format = DXGI_FORMAT_R32_TYPELESS; - } - - SLANG_RETURN_NULL_ON_FAIL(m_device->CreateUnorderedAccessView(buffer->m_buffer, &viewDesc, dstDetail.m_uav.writeRef())); - } - if (bufferDesc.bindFlags & (Resource::BindFlag::NonPixelShaderResource | Resource::BindFlag::PixelShaderResource)) - { - D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc; - memset(&viewDesc, 0, sizeof(viewDesc)); - viewDesc.Buffer.FirstElement = 0; - viewDesc.Buffer.ElementWidth = elemSize; - viewDesc.Buffer.NumElements = (UINT)(bufferDesc.sizeInBytes / elemSize); - viewDesc.Buffer.ElementOffset = 0; - viewDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; - viewDesc.Format = DXGI_FORMAT_UNKNOWN; - - if (bufferDesc.elementSize == 0) - { - viewDesc.Format = DXGI_FORMAT_R32_FLOAT; - } - - SLANG_RETURN_NULL_ON_FAIL(m_device->CreateShaderResourceView(buffer->m_buffer, &viewDesc, dstDetail.m_srv.writeRef())); - } - break; - } - case BindingType::Texture: - case BindingType::CombinedTextureSampler: - { - assert(srcBinding.resource && srcBinding.resource->isTexture()); - - TextureResourceImpl* texture = static_cast<TextureResourceImpl*>(srcBinding.resource.Ptr()); - - const TextureResource::Desc& textureDesc = texture->getDesc(); - - D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc; - viewDesc.Format = D3DUtil::getMapFormat(textureDesc.format); - - switch (texture->getType()) - { - case Resource::Type::Texture1D: - { - if (textureDesc.arraySize <= 0) - { - viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D; - viewDesc.Texture1D.MipLevels = textureDesc.numMipLevels; - viewDesc.Texture1D.MostDetailedMip = 0; - } - else - { - viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1DARRAY; - viewDesc.Texture1DArray.ArraySize = textureDesc.arraySize; - viewDesc.Texture1DArray.FirstArraySlice = 0; - viewDesc.Texture1DArray.MipLevels = textureDesc.numMipLevels; - viewDesc.Texture1DArray.MostDetailedMip = 0; - } - break; - } - case Resource::Type::Texture2D: - { - if (textureDesc.arraySize <= 0) - { - viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - viewDesc.Texture2D.MipLevels = textureDesc.numMipLevels; - viewDesc.Texture2D.MostDetailedMip = 0; - } - else - { - viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; - viewDesc.Texture2DArray.ArraySize = textureDesc.arraySize; - viewDesc.Texture2DArray.FirstArraySlice = 0; - viewDesc.Texture2DArray.MipLevels = textureDesc.numMipLevels; - viewDesc.Texture2DArray.MostDetailedMip = 0; - } - break; - } - case Resource::Type::TextureCube: - { - if (textureDesc.arraySize <= 0) - { - viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; - viewDesc.TextureCube.MipLevels = textureDesc.numMipLevels; - viewDesc.TextureCube.MostDetailedMip = 0; - } - else - { - viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBEARRAY; - viewDesc.TextureCubeArray.MipLevels = textureDesc.numMipLevels; - viewDesc.TextureCubeArray.MostDetailedMip = 0; - viewDesc.TextureCubeArray.First2DArrayFace = 0; - viewDesc.TextureCubeArray.NumCubes = textureDesc.arraySize; - } - break; - } - case Resource::Type::Texture3D: - { - viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D; - viewDesc.Texture3D.MipLevels = textureDesc.numMipLevels; // Old code fixed as one - viewDesc.Texture3D.MostDetailedMip = 0; - break; - } - default: - { - assert(!"Unhandled type"); - return nullptr; - } - } - - SLANG_RETURN_NULL_ON_FAIL(m_device->CreateShaderResourceView(texture->m_resource, &viewDesc, dstDetail.m_srv.writeRef())); - break; - } - case BindingType::Sampler: - { - const BindingState::SamplerDesc& samplerDesc = bindingStateDesc.m_samplerDescs[srcBinding.descIndex]; - - D3D11_SAMPLER_DESC desc = {}; - desc.AddressU = desc.AddressV = desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; - - if (samplerDesc.isCompareSampler) - { - desc.ComparisonFunc = D3D11_COMPARISON_LESS_EQUAL; - desc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT; - desc.MinLOD = desc.MaxLOD = 0.0f; - } - else - { - desc.Filter = D3D11_FILTER_ANISOTROPIC; - desc.MaxAnisotropy = 8; - desc.MinLOD = 0.0f; - desc.MaxLOD = 100.0f; - } - SLANG_RETURN_NULL_ON_FAIL(m_device->CreateSamplerState(&desc, dstDetail.m_samplerState.writeRef())); - break; - } - default: - { - assert(!"Unhandled type"); - return nullptr; - } - } - } - - // Done - return bindingState.detach(); -} - -void D3D11Renderer::_applyBindingState(bool isCompute) -{ - auto context = m_immediateContext.get(); - - const auto& details = m_currentBindings->m_bindingDetails; - const auto& bindings = m_currentBindings->getDesc().m_bindings; - - const int numBindings = int(bindings.Count()); - - for (int i = 0; i < numBindings; ++i) - { - const auto& binding = bindings[i]; - const auto& detail = details[i]; - - const int bindingIndex = binding.registerRange.getSingleIndex(); - - switch (binding.bindingType) - { - case BindingType::Buffer: - { - assert(binding.resource && binding.resource->isBuffer()); - if (binding.resource->canBind(Resource::BindFlag::ConstantBuffer)) - { - ID3D11Buffer* buffer = static_cast<BufferResourceImpl*>(binding.resource.Ptr())->m_buffer; - if (isCompute) - context->CSSetConstantBuffers(bindingIndex, 1, &buffer); - else - { - context->VSSetConstantBuffers(bindingIndex, 1, &buffer); - context->PSSetConstantBuffers(bindingIndex, 1, &buffer); - } - } - else if (detail.m_uav) - { - if (isCompute) - context->CSSetUnorderedAccessViews(bindingIndex, 1, detail.m_uav.readRef(), nullptr); - else - context->OMSetRenderTargetsAndUnorderedAccessViews(m_currentBindings->getDesc().m_numRenderTargets, - m_renderTargetViews.Buffer()->readRef(), nullptr, bindingIndex, 1, detail.m_uav.readRef(), nullptr); - } - else - { - if (isCompute) - context->CSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef()); - else - { - context->PSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef()); - context->VSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef()); - } - } - break; - } - case BindingType::Texture: - { - if (detail.m_uav) - { - if (isCompute) - context->CSSetUnorderedAccessViews(bindingIndex, 1, detail.m_uav.readRef(), nullptr); - else - context->OMSetRenderTargetsAndUnorderedAccessViews(D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, - nullptr, nullptr, bindingIndex, 1, detail.m_uav.readRef(), nullptr); - } - else - { - if (isCompute) - context->CSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef()); - else - { - context->PSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef()); - context->VSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef()); - } - } - break; - } - case BindingType::Sampler: - { - if (isCompute) - context->CSSetSamplers(bindingIndex, 1, detail.m_samplerState.readRef()); - else - { - context->PSSetSamplers(bindingIndex, 1, detail.m_samplerState.readRef()); - context->VSSetSamplers(bindingIndex, 1, detail.m_samplerState.readRef()); - } - break; - } - default: - { - assert(!"Not implemented"); - return; - } - } - } -} - -void D3D11Renderer::setBindingState(BindingState* state) -{ - m_currentBindings = static_cast<BindingStateImpl*>(state); -} - -} // renderer_test diff --git a/tools/render-test/render-d3d11.h b/tools/render-test/render-d3d11.h deleted file mode 100644 index 59142731d..000000000 --- a/tools/render-test/render-d3d11.h +++ /dev/null @@ -1,10 +0,0 @@ -// render-d3d11.h -#pragma once - -namespace renderer_test { - -class Renderer; - -Renderer* createD3D11Renderer(); - -} // renderer_test diff --git a/tools/render-test/render-d3d12.cpp b/tools/render-test/render-d3d12.cpp deleted file mode 100644 index 7603332b4..000000000 --- a/tools/render-test/render-d3d12.cpp +++ /dev/null @@ -1,2467 +0,0 @@ -// render-d3d12.cpp -#define _CRT_SECURE_NO_WARNINGS - -#include "render-d3d12.h" - -#include "options.h" -#include "render.h" - -#include "surface.h" - -// In order to use the Slang API, we need to include its header - -#include <slang.h> - -// We will be rendering with Direct3D 12, so we need to include -// the Windows and D3D12 headers - -#define WIN32_LEAN_AND_MEAN -#define NOMINMAX -#include <Windows.h> -#undef WIN32_LEAN_AND_MEAN -#undef NOMINMAX - -#include <dxgi1_4.h> -#include <d3d12.h> -#include <d3dcompiler.h> - -#include "../../slang-com-ptr.h" - -#include "resource-d3d12.h" -#include "descriptor-heap-d3d12.h" -#include "circular-resource-heap-d3d12.h" - -#include "d3d-util.h" - -// We will use the C standard library just for printing error messages. -#include <stdio.h> - -#ifdef _MSC_VER -#include <stddef.h> -#if (_MSC_VER < 1900) -#define snprintf sprintf_s -#endif -#endif -// - -#define ENABLE_DEBUG_LAYER 1 - -namespace renderer_test { -using namespace Slang; - -class D3D12Renderer : public Renderer -{ -public: - // Renderer implementation - virtual SlangResult initialize(const Desc& desc, void* inWindowHandle) override; - virtual void setClearColor(const float color[4]) override; - virtual void clearFrame() override; - virtual void presentFrame() override; - virtual TextureResource* createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData) override; - virtual BufferResource* createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& bufferDesc, const void* initData) override; - virtual SlangResult captureScreenSurface(Surface& surfaceOut) override; - virtual InputLayout* createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) override; - virtual BindingState* createBindingState(const BindingState::Desc& bindingStateDesc) override; - virtual ShaderProgram* createProgram(const ShaderProgram::Desc& desc) override; - virtual void* map(BufferResource* buffer, MapFlavor flavor) override; - virtual void unmap(BufferResource* buffer) override; - virtual void setInputLayout(InputLayout* inputLayout) override; - virtual void setPrimitiveTopology(PrimitiveTopology topology) override; - virtual void setBindingState(BindingState* state); - virtual void setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) override; - virtual void setShaderProgram(ShaderProgram* inProgram) override; - virtual void draw(UInt vertexCount, UInt startVertex) override; - virtual void dispatchCompute(int x, int y, int z) override; - virtual void submitGpuWork() override; - virtual void waitForGpu() override; - virtual RendererType getRendererType() const override { return RendererType::DirectX12; } - - ~D3D12Renderer(); - -protected: - static const Int kMaxNumRenderFrames = 4; - static const Int kMaxNumRenderTargets = 3; - - struct Submitter - { - virtual void setRootConstantBufferView(int index, D3D12_GPU_VIRTUAL_ADDRESS gpuBufferLocation) = 0; - virtual void setRootDescriptorTable(int index, D3D12_GPU_DESCRIPTOR_HANDLE BaseDescriptor) = 0; - virtual void setRootSignature(ID3D12RootSignature* rootSignature) = 0; - }; - - struct FrameInfo - { - FrameInfo() :m_fenceValue(0) {} - void reset() - { - m_commandAllocator.setNull(); - } - ComPtr<ID3D12CommandAllocator> m_commandAllocator; ///< The command allocator for this frame - UINT64 m_fenceValue; ///< The fence value when rendering this Frame is complete - }; - - class ShaderProgramImpl: public ShaderProgram - { - public: - PipelineType m_pipelineType; - List<uint8_t> m_vertexShader; - List<uint8_t> m_pixelShader; - List<uint8_t> m_computeShader; - }; - - class BufferResourceImpl: public BufferResource - { - public: - typedef BufferResource Parent; - - enum class BackingStyle - { - Unknown, - ResourceBacked, ///< The contents is only held within the resource - MemoryBacked, ///< The current contents is held in m_memory and copied to GPU every time it's used (typically used for constant buffers) - }; - - void bindConstantBufferView(D3D12CircularResourceHeap& circularHeap, int index, Submitter* submitter) const - { - switch (m_backingStyle) - { - case BackingStyle::MemoryBacked: - { - const size_t bufferSize = m_memory.Count(); - D3D12CircularResourceHeap::Cursor cursor = circularHeap.allocateConstantBuffer(bufferSize); - ::memcpy(cursor.m_position, m_memory.Buffer(), bufferSize); - // Set the constant buffer - submitter->setRootConstantBufferView(index, circularHeap.getGpuHandle(cursor)); - break; - } - case BackingStyle::ResourceBacked: - { - // Set the constant buffer - submitter->setRootConstantBufferView(index, m_resource.getResource()->GetGPUVirtualAddress()); - break; - } - default: break; - } - } - - BufferResourceImpl(Resource::Usage initialUsage, const Desc& desc): - Parent(desc), - m_mapFlavor(MapFlavor::HostRead), - m_initialUsage(initialUsage) - { - } - - static BackingStyle _calcResourceBackingStyle(Usage usage) - { - switch (usage) - { - case Usage::ConstantBuffer: return BackingStyle::MemoryBacked; - default: return BackingStyle::ResourceBacked; - } - } - - BackingStyle m_backingStyle; ///< How the resource is 'backed' - either as a resource or cpu memory. Cpu memory is typically used for constant buffers. - D3D12Resource m_resource; ///< The resource typically in gpu memory - D3D12Resource m_uploadResource; ///< If the resource can be written to, and is in gpu memory (ie not Memory backed), will have upload resource - - Usage m_initialUsage; - - List<uint8_t> m_memory; ///< Cpu memory buffer, used if the m_backingStyle is MemoryBacked - MapFlavor m_mapFlavor; ///< If the resource is mapped holds the current mapping flavor - }; - - class TextureResourceImpl: public TextureResource - { - public: - typedef TextureResource Parent; - - TextureResourceImpl(const Desc& desc): - Parent(desc) - { - } - - D3D12Resource m_resource; - }; - - class InputLayoutImpl: public InputLayout - { - public: - List<D3D12_INPUT_ELEMENT_DESC> m_elements; - List<char> m_text; ///< Holds all strings to keep in scope - }; - - struct BindingDetail - { - int m_srvIndex = -1; - int m_uavIndex = -1; - int m_samplerIndex = -1; - }; - - class BindingStateImpl: public BindingState - { - public: - typedef BindingState Parent; - - Result init(ID3D12Device* device) - { - // Set up descriptor heaps - SLANG_RETURN_ON_FAIL(m_viewHeap.init(device, 256, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)); - SLANG_RETURN_ON_FAIL(m_samplerHeap.init(device, 16, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)); - return SLANG_OK; - } - - /// Ctor - BindingStateImpl(const Desc& desc) : - Parent(desc) - {} - - List<BindingDetail> m_bindingDetails; ///< These match 1-1 to the bindings in the m_desc - - D3D12DescriptorHeap m_viewHeap; ///< Cbv, Srv, Uav - D3D12DescriptorHeap m_samplerHeap; ///< Heap for samplers - }; - - class RenderState: public RefObject - { - public: - D3D12_PRIMITIVE_TOPOLOGY_TYPE m_primitiveTopologyType; - RefPtr<BindingStateImpl> m_bindingState; - RefPtr<InputLayoutImpl> m_inputLayout; - RefPtr<ShaderProgramImpl> m_shaderProgram; - - ComPtr<ID3D12RootSignature> m_rootSignature; - ComPtr<ID3D12PipelineState> m_pipelineState; - }; - - struct BoundVertexBuffer - { - RefPtr<BufferResourceImpl> m_buffer; - int m_stride; - int m_offset; - }; - - struct BindParameters - { - enum - { - kMaxRanges = 16, - kMaxParameters = 32 - }; - - D3D12_DESCRIPTOR_RANGE& nextRange() { return m_ranges[m_rangeIndex++]; } - D3D12_ROOT_PARAMETER& nextParameter() { return m_parameters[m_paramIndex++]; } - - BindParameters(): - m_rangeIndex(0), - m_paramIndex(0) - {} - - D3D12_DESCRIPTOR_RANGE m_ranges[kMaxRanges]; - int m_rangeIndex; - D3D12_ROOT_PARAMETER m_parameters[kMaxParameters]; - int m_paramIndex; - }; - - struct GraphicsSubmitter : public Submitter - { - virtual void setRootConstantBufferView(int index, D3D12_GPU_VIRTUAL_ADDRESS gpuBufferLocation) override - { - m_commandList->SetGraphicsRootConstantBufferView(index, gpuBufferLocation); - } - virtual void setRootDescriptorTable(int index, D3D12_GPU_DESCRIPTOR_HANDLE baseDescriptor) override - { - m_commandList->SetGraphicsRootDescriptorTable(index, baseDescriptor); - } - void setRootSignature(ID3D12RootSignature* rootSignature) - { - m_commandList->SetGraphicsRootSignature(rootSignature); - } - - GraphicsSubmitter(ID3D12GraphicsCommandList* commandList): - m_commandList(commandList) - { - } - - ID3D12GraphicsCommandList* m_commandList; - }; - - struct ComputeSubmitter : public Submitter - { - virtual void setRootConstantBufferView(int index, D3D12_GPU_VIRTUAL_ADDRESS gpuBufferLocation) override - { - m_commandList->SetComputeRootConstantBufferView(index, gpuBufferLocation); - } - virtual void setRootDescriptorTable(int index, D3D12_GPU_DESCRIPTOR_HANDLE baseDescriptor) override - { - m_commandList->SetComputeRootDescriptorTable(index, baseDescriptor); - } - void setRootSignature(ID3D12RootSignature* rootSignature) - { - m_commandList->SetComputeRootSignature(rootSignature); - } - - ComputeSubmitter(ID3D12GraphicsCommandList* commandList) : - m_commandList(commandList) - { - } - - ID3D12GraphicsCommandList* m_commandList; - }; - - static PROC loadProc(HMODULE module, char const* name); - Result createFrameResources(); - /// Blocks until gpu has completed all work - void releaseFrameResources(); - - Result createBuffer(const D3D12_RESOURCE_DESC& resourceDesc, const void* srcData, D3D12Resource& uploadResource, D3D12_RESOURCE_STATES finalState, D3D12Resource& resourceOut); - - void beginRender(); - - void endRender(); - - void submitGpuWorkAndWait(); - void _resetCommandList(); - - Result captureTextureToSurface(D3D12Resource& resource, Surface& surfaceOut); - - FrameInfo& getFrame() { return m_frameInfos[m_frameIndex]; } - const FrameInfo& getFrame() const { return m_frameInfos[m_frameIndex]; } - - ID3D12GraphicsCommandList* getCommandList() const { return m_commandList; } - - RenderState* calcRenderState(); - /// From current bindings calculate the root signature and pipeline state - Result calcGraphicsPipelineState(ComPtr<ID3D12RootSignature>& sigOut, ComPtr<ID3D12PipelineState>& pipelineStateOut); - Result calcComputePipelineState(ComPtr<ID3D12RootSignature>& signatureOut, ComPtr<ID3D12PipelineState>& pipelineStateOut); - - Result _bindRenderState(RenderState* renderState, ID3D12GraphicsCommandList* commandList, Submitter* submitter); - - Result _calcBindParameters(BindParameters& params); - RenderState* findRenderState(PipelineType pipelineType); - - PFN_D3D12_SERIALIZE_ROOT_SIGNATURE m_D3D12SerializeRootSignature = nullptr; - - D3D12CircularResourceHeap m_circularResourceHeap; - - int m_commandListOpenCount = 0; ///< If >0 the command list should be open - - List<BoundVertexBuffer> m_boundVertexBuffers; - - RefPtr<ShaderProgramImpl> m_boundShaderProgram; - RefPtr<InputLayoutImpl> m_boundInputLayout; - RefPtr<BindingStateImpl> m_boundBindingState; - - DXGI_FORMAT m_targetFormat = DXGI_FORMAT_R8G8B8A8_UNORM; - DXGI_FORMAT m_depthStencilFormat = DXGI_FORMAT_D24_UNORM_S8_UINT; - bool m_hasVsync = true; - bool m_isFullSpeed = false; - bool m_allowFullScreen = false; - bool m_isMultiSampled = false; - int m_numTargetSamples = 1; ///< The number of multi sample samples - int m_targetSampleQuality = 0; ///< The multi sample quality - - Desc m_desc; - - bool m_isInitialized = false; - - D3D12_PRIMITIVE_TOPOLOGY_TYPE m_primitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; - D3D12_PRIMITIVE_TOPOLOGY m_primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; - - float m_clearColor[4] = { 0, 0, 0, 0 }; - - D3D12_VIEWPORT m_viewport = {}; - - ComPtr<ID3D12Debug> m_dxDebug; - - ComPtr<ID3D12Device> m_device; - ComPtr<IDXGISwapChain3> m_swapChain; - ComPtr<ID3D12CommandQueue> m_commandQueue; - ComPtr<ID3D12DescriptorHeap> m_rtvHeap; - ComPtr<ID3D12GraphicsCommandList> m_commandList; - - D3D12_RECT m_scissorRect = {}; - - List<RefPtr<RenderState> > m_renderStates; ///< Holds list of all render state combinations - RenderState* m_currentRenderState = nullptr; ///< The current combination - - UINT m_rtvDescriptorSize = 0; - - ComPtr<ID3D12DescriptorHeap> m_dsvHeap; - UINT m_dsvDescriptorSize = 0; - - // Synchronization objects. - D3D12CounterFence m_fence; - - HANDLE m_swapChainWaitableObject; - - // Frame specific data - int m_numRenderFrames = 0; - UINT m_frameIndex = 0; - FrameInfo m_frameInfos[kMaxNumRenderFrames]; - - int m_numRenderTargets = 2; - int m_renderTargetIndex = 0; - - D3D12Resource* m_backBuffers[kMaxNumRenderTargets]; - D3D12Resource* m_renderTargets[kMaxNumRenderTargets]; - - D3D12Resource m_backBufferResources[kMaxNumRenderTargets]; - D3D12Resource m_renderTargetResources[kMaxNumRenderTargets]; - - D3D12Resource m_depthStencil; - D3D12_CPU_DESCRIPTOR_HANDLE m_depthStencilView = {}; - - int32_t m_depthStencilUsageFlags = 0; ///< D3DUtil::UsageFlag combination for depth stencil - int32_t m_targetUsageFlags = 0; ///< D3DUtil::UsageFlag combination for target - - HWND m_hwnd = nullptr; -}; - -Renderer* createD3D12Renderer() -{ - return new D3D12Renderer; -} - -/* static */PROC D3D12Renderer::loadProc(HMODULE module, char const* name) -{ - PROC proc = ::GetProcAddress(module, name); - if (!proc) - { - fprintf(stderr, "error: failed load symbol '%s'\n", name); - return nullptr; - } - return proc; -} - -void D3D12Renderer::releaseFrameResources() -{ - // https://msdn.microsoft.com/en-us/library/windows/desktop/bb174577%28v=vs.85%29.aspx - - // Release the resources holding references to the swap chain (requirement of - // IDXGISwapChain::ResizeBuffers) and reset the frame fence values to the - // current fence value. - for (int i = 0; i < m_numRenderFrames; i++) - { - FrameInfo& info = m_frameInfos[i]; - info.reset(); - info.m_fenceValue = m_fence.getCurrentValue(); - } - for (int i = 0; i < m_numRenderTargets; i++) - { - m_backBuffers[i]->setResourceNull(); - m_renderTargets[i]->setResourceNull(); - } -} - -void D3D12Renderer::waitForGpu() -{ - m_fence.nextSignalAndWait(m_commandQueue); -} - -D3D12Renderer::~D3D12Renderer() -{ - if (m_isInitialized) - { - // Ensure that the GPU is no longer referencing resources that are about to be - // cleaned up by the destructor. - waitForGpu(); - } -} - -static void _initSrvDesc(Resource::Type resourceType, const TextureResource::Desc& textureDesc, const D3D12_RESOURCE_DESC& desc, DXGI_FORMAT pixelFormat, D3D12_SHADER_RESOURCE_VIEW_DESC& descOut) -{ - // create SRV - descOut = D3D12_SHADER_RESOURCE_VIEW_DESC(); - - descOut.Format = (pixelFormat == DXGI_FORMAT_UNKNOWN) ? D3DUtil::calcFormat(D3DUtil::USAGE_SRV, desc.Format) : pixelFormat; - descOut.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - if (desc.DepthOrArraySize == 1) - { - switch (desc.Dimension) - { - case D3D12_RESOURCE_DIMENSION_TEXTURE1D: descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D; break; - case D3D12_RESOURCE_DIMENSION_TEXTURE2D: descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; break; - case D3D12_RESOURCE_DIMENSION_TEXTURE3D: descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D; break; - default: assert(!"Unknown dimension"); - } - - descOut.Texture2D.MipLevels = desc.MipLevels; - descOut.Texture2D.MostDetailedMip = 0; - descOut.Texture2D.PlaneSlice = 0; - descOut.Texture2D.ResourceMinLODClamp = 0.0f; - } - else if (resourceType == Resource::Type::TextureCube) - { - if (textureDesc.arraySize > 1) - { - descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY; - - descOut.TextureCubeArray.NumCubes = textureDesc.arraySize; - descOut.TextureCubeArray.First2DArrayFace = 0; - descOut.TextureCubeArray.MipLevels = desc.MipLevels; - descOut.TextureCubeArray.MostDetailedMip = 0; - descOut.TextureCubeArray.ResourceMinLODClamp = 0; - } - else - { - descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE; - - descOut.TextureCube.MipLevels = desc.MipLevels; - descOut.TextureCube.MostDetailedMip = 0; - descOut.TextureCube.ResourceMinLODClamp = 0; - } - } - else - { - assert(desc.DepthOrArraySize > 1); - - switch (desc.Dimension) - { - case D3D12_RESOURCE_DIMENSION_TEXTURE1D: descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY; break; - case D3D12_RESOURCE_DIMENSION_TEXTURE2D: descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; break; - case D3D12_RESOURCE_DIMENSION_TEXTURE3D: descOut.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D; break; - - default: assert(!"Unknown dimension"); - } - - descOut.Texture2DArray.ArraySize = desc.DepthOrArraySize; - descOut.Texture2DArray.MostDetailedMip = 0; - descOut.Texture2DArray.MipLevels = desc.MipLevels; - descOut.Texture2DArray.FirstArraySlice = 0; - descOut.Texture2DArray.PlaneSlice = 0; - descOut.Texture2DArray.ResourceMinLODClamp = 0; - } -} - -static void _initBufferResourceDesc(size_t bufferSize, D3D12_RESOURCE_DESC& out) -{ - out = {}; - - out.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - out.Alignment = 0; - out.Width = bufferSize; - out.Height = 1; - out.DepthOrArraySize = 1; - out.MipLevels = 1; - out.Format = DXGI_FORMAT_UNKNOWN; - out.SampleDesc.Count = 1; - out.SampleDesc.Quality = 0; - out.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; - out.Flags = D3D12_RESOURCE_FLAG_NONE; -} - -Result D3D12Renderer::createBuffer(const D3D12_RESOURCE_DESC& resourceDesc, const void* srcData, D3D12Resource& uploadResource, D3D12_RESOURCE_STATES finalState, D3D12Resource& resourceOut) -{ - const size_t bufferSize = size_t(resourceDesc.Width); - - { - D3D12_HEAP_PROPERTIES heapProps; - heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; - heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - heapProps.CreationNodeMask = 1; - heapProps.VisibleNodeMask = 1; - - const D3D12_RESOURCE_STATES initialState = srcData ? D3D12_RESOURCE_STATE_COPY_DEST : finalState; - - SLANG_RETURN_ON_FAIL(resourceOut.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, resourceDesc, initialState, nullptr)); - } - - { - D3D12_HEAP_PROPERTIES heapProps; - heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; - heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - heapProps.CreationNodeMask = 1; - heapProps.VisibleNodeMask = 1; - - D3D12_RESOURCE_DESC uploadResourceDesc(resourceDesc); - uploadResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; - - SLANG_RETURN_ON_FAIL(uploadResource.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, uploadResourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr)); - } - - if (srcData) - { - // Copy data to the intermediate upload heap and then schedule a copy - // from the upload heap to the vertex buffer. - UINT8* dstData; - D3D12_RANGE readRange = {}; // We do not intend to read from this resource on the CPU. - - ID3D12Resource* dxUploadResource = uploadResource.getResource(); - - SLANG_RETURN_ON_FAIL(dxUploadResource->Map(0, &readRange, reinterpret_cast<void**>(&dstData))); - ::memcpy(dstData, srcData, bufferSize); - dxUploadResource->Unmap(0, nullptr); - - m_commandList->CopyBufferRegion(resourceOut, 0, uploadResource, 0, bufferSize); - - // Make sure it's in the right state - { - D3D12BarrierSubmitter submitter(m_commandList); - resourceOut.transition(finalState, submitter); - } - - submitGpuWorkAndWait(); - } - - return SLANG_OK; -} - -void D3D12Renderer::_resetCommandList() -{ - const FrameInfo& frame = getFrame(); - - ID3D12GraphicsCommandList* commandList = getCommandList(); - commandList->Reset(frame.m_commandAllocator, nullptr); - - D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = { m_rtvHeap->GetCPUDescriptorHandleForHeapStart().ptr + m_renderTargetIndex * m_rtvDescriptorSize }; - if (m_depthStencil) - { - commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &m_depthStencilView); - } - else - { - commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr); - } - - // Set necessary state. - commandList->RSSetViewports(1, &m_viewport); - commandList->RSSetScissorRects(1, &m_scissorRect); -} - -void D3D12Renderer::beginRender() -{ - // Should currently not be open! - assert(m_commandListOpenCount == 0); - - m_circularResourceHeap.updateCompleted(); - - getFrame().m_commandAllocator->Reset(); - - _resetCommandList(); - - // Indicate that the render target needs to be writable - { - D3D12BarrierSubmitter submitter(m_commandList); - m_renderTargets[m_renderTargetIndex]->transition(D3D12_RESOURCE_STATE_RENDER_TARGET, submitter); - } - - m_commandListOpenCount = 1; -} - -void D3D12Renderer::endRender() -{ - assert(m_commandListOpenCount == 1); - - { - const UInt64 signalValue = m_fence.nextSignal(m_commandQueue); - m_circularResourceHeap.addSync(signalValue); - } - - D3D12Resource& backBuffer = *m_backBuffers[m_renderTargetIndex]; - if (m_isMultiSampled) - { - // MSAA resolve - D3D12Resource& renderTarget = *m_renderTargets[m_renderTargetIndex]; - assert(&renderTarget != &backBuffer); - // Barriers to wait for the render target, and the backbuffer to be in correct state - { - D3D12BarrierSubmitter submitter(m_commandList); - renderTarget.transition(D3D12_RESOURCE_STATE_RESOLVE_SOURCE, submitter); - backBuffer.transition(D3D12_RESOURCE_STATE_RESOLVE_DEST, submitter); - } - - // Do the resolve... - m_commandList->ResolveSubresource(backBuffer, 0, renderTarget, 0, m_targetFormat); - } - - // Make the back buffer presentable - { - D3D12BarrierSubmitter submitter(m_commandList); - backBuffer.transition(D3D12_RESOURCE_STATE_PRESENT, submitter); - } - - SLANG_ASSERT_VOID_ON_FAIL(m_commandList->Close()); - - { - // Execute the command list. - ID3D12CommandList* commandLists[] = { m_commandList }; - m_commandQueue->ExecuteCommandLists(SLANG_COUNT_OF(commandLists), commandLists); - } - - assert(m_commandListOpenCount == 1); - // Must be 0 - m_commandListOpenCount = 0; -} - -void D3D12Renderer::submitGpuWork() -{ - assert(m_commandListOpenCount); - ID3D12GraphicsCommandList* commandList = getCommandList(); - - SLANG_ASSERT_VOID_ON_FAIL(commandList->Close()); - { - // Execute the command list. - ID3D12CommandList* commandLists[] = { commandList }; - m_commandQueue->ExecuteCommandLists(SLANG_COUNT_OF(commandLists), commandLists); - } - - // Reset the render target - _resetCommandList(); -} - -void D3D12Renderer::submitGpuWorkAndWait() -{ - submitGpuWork(); - waitForGpu(); -} - -Result D3D12Renderer::captureTextureToSurface(D3D12Resource& resource, Surface& surfaceOut) -{ - const D3D12_RESOURCE_STATES initialState = resource.getState(); - - const D3D12_RESOURCE_DESC desc = resource.getResource()->GetDesc(); - - // Don't bother supporting MSAA for right now - if (desc.SampleDesc.Count > 1) - { - fprintf(stderr, "ERROR: cannot capture multi-sample texture\n"); - return SLANG_FAIL; - } - - size_t bytesPerPixel = sizeof(uint32_t); - size_t rowPitch = int(desc.Width) * bytesPerPixel; - size_t bufferSize = rowPitch * int(desc.Height); - - D3D12Resource stagingResource; - { - D3D12_RESOURCE_DESC stagingDesc; - _initBufferResourceDesc(bufferSize, stagingDesc); - - D3D12_HEAP_PROPERTIES heapProps; - heapProps.Type = D3D12_HEAP_TYPE_READBACK; - heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - heapProps.CreationNodeMask = 1; - heapProps.VisibleNodeMask = 1; - - SLANG_RETURN_ON_FAIL(stagingResource.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, stagingDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr)); - } - - { - D3D12BarrierSubmitter submitter(m_commandList); - resource.transition(D3D12_RESOURCE_STATE_COPY_SOURCE, submitter); - } - - // Do the copy - { - D3D12_TEXTURE_COPY_LOCATION srcLoc; - srcLoc.pResource = resource; - srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - srcLoc.SubresourceIndex = 0; - - D3D12_TEXTURE_COPY_LOCATION dstLoc; - dstLoc.pResource = stagingResource; - dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - dstLoc.PlacedFootprint.Offset = 0; - dstLoc.PlacedFootprint.Footprint.Format = desc.Format; - dstLoc.PlacedFootprint.Footprint.Width = UINT(desc.Width); - dstLoc.PlacedFootprint.Footprint.Height = UINT(desc.Height); - dstLoc.PlacedFootprint.Footprint.Depth = 1; - dstLoc.PlacedFootprint.Footprint.RowPitch = UINT(rowPitch); - - m_commandList->CopyTextureRegion(&dstLoc, 0, 0, 0, &srcLoc, nullptr); - } - - { - D3D12BarrierSubmitter submitter(m_commandList); - resource.transition(initialState, submitter); - } - - // Submit the copy, and wait for copy to complete - submitGpuWorkAndWait(); - - { - ID3D12Resource* dxResource = stagingResource; - - UINT8* data; - D3D12_RANGE readRange = {0, bufferSize}; - - SLANG_RETURN_ON_FAIL(dxResource->Map(0, &readRange, reinterpret_cast<void**>(&data))); - - Result res = surfaceOut.set(int(desc.Width), int(desc.Height), Format::RGBA_Unorm_UInt8, int(rowPitch), data, SurfaceAllocator::getMallocAllocator()); - - dxResource->Unmap(0, nullptr); - return res; - } -} - -Result D3D12Renderer::calcComputePipelineState(ComPtr<ID3D12RootSignature>& signatureOut, ComPtr<ID3D12PipelineState>& pipelineStateOut) -{ - BindParameters bindParameters; - _calcBindParameters(bindParameters); - - ComPtr<ID3D12RootSignature> rootSignature; - ComPtr<ID3D12PipelineState> pipelineState; - - { - D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc; - rootSignatureDesc.NumParameters = bindParameters.m_paramIndex; - rootSignatureDesc.pParameters = bindParameters.m_parameters; - rootSignatureDesc.NumStaticSamplers = 0; - rootSignatureDesc.pStaticSamplers = nullptr; - rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE; - - ComPtr<ID3DBlob> signature; - ComPtr<ID3DBlob> error; - SLANG_RETURN_ON_FAIL(m_D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, signature.writeRef(), error.writeRef())); - SLANG_RETURN_ON_FAIL(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(rootSignature.writeRef()))); - } - - { - // Describe and create the compute pipeline state object - D3D12_COMPUTE_PIPELINE_STATE_DESC computeDesc = {}; - computeDesc.pRootSignature = rootSignature; - computeDesc.CS = { m_boundShaderProgram->m_computeShader.Buffer(), m_boundShaderProgram->m_computeShader.Count() }; - SLANG_RETURN_ON_FAIL(m_device->CreateComputePipelineState(&computeDesc, IID_PPV_ARGS(pipelineState.writeRef()))); - } - - signatureOut.swap(rootSignature); - pipelineStateOut.swap(pipelineState); - - return SLANG_OK; -} - -Result D3D12Renderer::calcGraphicsPipelineState(ComPtr<ID3D12RootSignature>& signatureOut, ComPtr<ID3D12PipelineState>& pipelineStateOut) -{ - BindParameters bindParameters; - _calcBindParameters(bindParameters); - - ComPtr<ID3D12RootSignature> rootSignature; - ComPtr<ID3D12PipelineState> pipelineState; - - { - // Deny unnecessary access to certain pipeline stages - D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc; - rootSignatureDesc.NumParameters = bindParameters.m_paramIndex; - rootSignatureDesc.pParameters = bindParameters.m_parameters; - rootSignatureDesc.NumStaticSamplers = 0; - rootSignatureDesc.pStaticSamplers = nullptr; - rootSignatureDesc.Flags = m_boundInputLayout ? D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT : D3D12_ROOT_SIGNATURE_FLAG_NONE; - - ComPtr<ID3DBlob> signature; - ComPtr<ID3DBlob> error; - SLANG_RETURN_ON_FAIL(m_D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, signature.writeRef(), error.writeRef())); - SLANG_RETURN_ON_FAIL(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(rootSignature.writeRef()))); - } - - { - // Describe and create the graphics pipeline state object (PSO) - D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; - - psoDesc.pRootSignature = rootSignature; - - psoDesc.VS = { m_boundShaderProgram->m_vertexShader.Buffer(), m_boundShaderProgram->m_vertexShader.Count() }; - psoDesc.PS = { m_boundShaderProgram->m_pixelShader.Buffer(), m_boundShaderProgram->m_pixelShader.Count() }; - - { - psoDesc.InputLayout = { m_boundInputLayout->m_elements.Buffer(), UINT(m_boundInputLayout->m_elements.Count()) }; - psoDesc.PrimitiveTopologyType = m_primitiveTopologyType; - - { - const int numRenderTargets = m_boundBindingState ? m_boundBindingState->getDesc().m_numRenderTargets : 1; - - psoDesc.DSVFormat = m_depthStencilFormat; - psoDesc.NumRenderTargets = numRenderTargets; - for (Int i = 0; i < numRenderTargets; i++) - { - psoDesc.RTVFormats[i] = m_targetFormat; - } - - psoDesc.SampleDesc.Count = 1; - psoDesc.SampleDesc.Quality = 0; - - psoDesc.SampleMask = UINT_MAX; - } - - { - auto& rs = psoDesc.RasterizerState; - rs.FillMode = D3D12_FILL_MODE_SOLID; - rs.CullMode = D3D12_CULL_MODE_NONE; - rs.FrontCounterClockwise = FALSE; - rs.DepthBias = D3D12_DEFAULT_DEPTH_BIAS; - rs.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP; - rs.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS; - rs.DepthClipEnable = TRUE; - rs.MultisampleEnable = FALSE; - rs.AntialiasedLineEnable = FALSE; - rs.ForcedSampleCount = 0; - rs.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF; - } - - { - D3D12_BLEND_DESC& blend = psoDesc.BlendState; - - blend.AlphaToCoverageEnable = FALSE; - blend.IndependentBlendEnable = FALSE; - const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = - { - FALSE,FALSE, - D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, - D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, - D3D12_LOGIC_OP_NOOP, - D3D12_COLOR_WRITE_ENABLE_ALL, - }; - for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i) - { - blend.RenderTarget[i] = defaultRenderTargetBlendDesc; - } - } - - { - auto& ds = psoDesc.DepthStencilState; - - ds.DepthEnable = FALSE; - ds.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; - ds.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS; - //ds.DepthFunc = D3D12_COMPARISON_FUNC_LESS; - ds.StencilEnable = FALSE; - ds.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK; - ds.StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK; - const D3D12_DEPTH_STENCILOP_DESC defaultStencilOp = - { - D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_COMPARISON_FUNC_ALWAYS - }; - ds.FrontFace = defaultStencilOp; - ds.BackFace = defaultStencilOp; - } - } - - psoDesc.PrimitiveTopologyType = m_primitiveTopologyType; - - SLANG_RETURN_ON_FAIL(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(pipelineState.writeRef()))); - } - - signatureOut.swap(rootSignature); - pipelineStateOut.swap(pipelineState); - - return SLANG_OK; -} - -D3D12Renderer::RenderState* D3D12Renderer::findRenderState(PipelineType pipelineType) -{ - switch (pipelineType) - { - case PipelineType::Compute: - { - // Check if current state is a match - if (m_currentRenderState) - { - if (m_currentRenderState->m_bindingState == m_boundBindingState && - m_currentRenderState->m_shaderProgram == m_boundShaderProgram) - { - return m_currentRenderState; - } - } - - const int num = int(m_renderStates.Count()); - for (int i = 0; i < num; i++) - { - RenderState* renderState = m_renderStates[i]; - if (renderState->m_bindingState == m_boundBindingState && - renderState->m_shaderProgram == m_boundShaderProgram) - { - return renderState; - } - } - break; - } - case PipelineType::Graphics: - { - if (m_currentRenderState) - { - if (m_currentRenderState->m_bindingState == m_boundBindingState && - m_currentRenderState->m_inputLayout == m_boundInputLayout && - m_currentRenderState->m_shaderProgram == m_boundShaderProgram && - m_currentRenderState->m_primitiveTopologyType == m_primitiveTopologyType) - { - return m_currentRenderState; - } - } - // See if matches one in the list - { - const int num = int(m_renderStates.Count()); - for (int i = 0; i < num; i++) - { - RenderState* renderState = m_renderStates[i]; - if (renderState->m_bindingState == m_boundBindingState && - renderState->m_inputLayout == m_boundInputLayout && - renderState->m_shaderProgram == m_boundShaderProgram && - renderState->m_primitiveTopologyType == m_primitiveTopologyType) - { - // Okay we have a match - return renderState; - } - } - } - break; - } - default: break; - } - return nullptr; -} - -D3D12Renderer::RenderState* D3D12Renderer::calcRenderState() -{ - if (!m_boundShaderProgram) - { - return nullptr; - } - m_currentRenderState = findRenderState(m_boundShaderProgram->m_pipelineType); - if (m_currentRenderState) - { - return m_currentRenderState; - } - - ComPtr<ID3D12RootSignature> rootSignature; - ComPtr<ID3D12PipelineState> pipelineState; - - switch (m_boundShaderProgram->m_pipelineType) - { - case PipelineType::Compute: - { - if (SLANG_FAILED(calcComputePipelineState(rootSignature, pipelineState))) - { - return nullptr; - } - break; - } - case PipelineType::Graphics: - { - if (SLANG_FAILED(calcGraphicsPipelineState(rootSignature, pipelineState))) - { - return nullptr; - } - break; - } - default: return nullptr; - } - - RenderState* renderState = new RenderState; - - renderState->m_primitiveTopologyType = m_primitiveTopologyType; - renderState->m_bindingState = m_boundBindingState; - renderState->m_inputLayout = m_boundInputLayout; - renderState->m_shaderProgram = m_boundShaderProgram; - - renderState->m_rootSignature.swap(rootSignature); - renderState->m_pipelineState.swap(pipelineState); - - m_renderStates.Add(renderState); - - m_currentRenderState = renderState; - - return renderState; -} - -Result D3D12Renderer::_calcBindParameters(BindParameters& params) -{ - int numConstantBuffers = 0; - { - if (m_boundBindingState) - { - const int numBoundConstantBuffers = numConstantBuffers; - - const BindingState::Desc& bindingStateDesc = m_boundBindingState->getDesc(); - - const auto& bindings = bindingStateDesc.m_bindings; - const auto& details = m_boundBindingState->m_bindingDetails; - - const int numBindings = int(bindings.Count()); - - for (int i = 0; i < numBindings; i++) - { - const auto& binding = bindings[i]; - const auto& detail = details[i]; - - const int bindingIndex = binding.registerRange.getSingleIndex(); - - if (binding.bindingType == BindingType::Buffer) - { - assert(binding.resource && binding.resource->isBuffer()); - if (binding.resource->canBind(Resource::BindFlag::ConstantBuffer)) - { - // Make sure it's not overlapping the ones we just statically defined - //assert(binding.m_binding < numBoundConstantBuffers); - - D3D12_ROOT_PARAMETER& param = params.nextParameter(); - param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; - param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; - - D3D12_ROOT_DESCRIPTOR& descriptor = param.Descriptor; - descriptor.ShaderRegister = bindingIndex; - descriptor.RegisterSpace = 0; - - numConstantBuffers++; - } - } - - if (detail.m_srvIndex >= 0) - { - D3D12_DESCRIPTOR_RANGE& range = params.nextRange(); - - range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; - range.NumDescriptors = 1; - range.BaseShaderRegister = bindingIndex; - range.RegisterSpace = 0; - range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; - - D3D12_ROOT_PARAMETER& param = params.nextParameter(); - - param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; - param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; - - D3D12_ROOT_DESCRIPTOR_TABLE& table = param.DescriptorTable; - table.NumDescriptorRanges = 1; - table.pDescriptorRanges = ⦥ - } - - if (detail.m_uavIndex >= 0) - { - D3D12_DESCRIPTOR_RANGE& range = params.nextRange(); - - range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; - range.NumDescriptors = 1; - range.BaseShaderRegister = bindingIndex; - range.RegisterSpace = 0; - range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; - - D3D12_ROOT_PARAMETER& param = params.nextParameter(); - - param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; - param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; - - D3D12_ROOT_DESCRIPTOR_TABLE& table = param.DescriptorTable; - table.NumDescriptorRanges = 1; - table.pDescriptorRanges = ⦥ - } - } - } - } - - // All the samplers are in one continuous section of the sampler heap - if (m_boundBindingState && m_boundBindingState->m_samplerHeap.getUsedSize() > 0) - { - D3D12_DESCRIPTOR_RANGE& range = params.nextRange(); - - range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; - range.NumDescriptors = m_boundBindingState->m_samplerHeap.getUsedSize(); - range.BaseShaderRegister = 0; - range.RegisterSpace = 0; - range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; - - D3D12_ROOT_PARAMETER& param = params.nextParameter(); - - param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; - param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; - - D3D12_ROOT_DESCRIPTOR_TABLE& table = param.DescriptorTable; - table.NumDescriptorRanges = 1; - table.pDescriptorRanges = ⦥ - } - return SLANG_OK; -} - -Result D3D12Renderer::_bindRenderState(RenderState* renderState, ID3D12GraphicsCommandList* commandList, Submitter* submitter) -{ - BindingStateImpl* bindingState = m_boundBindingState; - - submitter->setRootSignature(renderState->m_rootSignature); - commandList->SetPipelineState(renderState->m_pipelineState); - - if (bindingState) - { - ID3D12DescriptorHeap* heaps[] = - { - bindingState->m_viewHeap.getHeap(), - bindingState->m_samplerHeap.getHeap(), - }; - commandList->SetDescriptorHeaps(SLANG_COUNT_OF(heaps), heaps); - } - else - { - commandList->SetDescriptorHeaps(0, nullptr); - } - - { - int index = 0; - - int numConstantBuffers = 0; - { - if (bindingState) - { - D3D12DescriptorHeap& heap = bindingState->m_viewHeap; - const auto& details = bindingState->m_bindingDetails; - const auto& bindings = bindingState->getDesc().m_bindings; - const int numBindings = int(details.Count()); - - for (int i = 0; i < numBindings; i++) - { - const auto& detail = details[i]; - const auto& binding = bindings[i]; - - if (binding.bindingType == BindingType::Buffer) - { - assert(binding.resource && binding.resource->isBuffer()); - if (binding.resource->canBind(Resource::BindFlag::ConstantBuffer)) - { - BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(binding.resource.Ptr()); - buffer->bindConstantBufferView(m_circularResourceHeap, index++, submitter); - numConstantBuffers++; - } - } - - if (detail.m_srvIndex >= 0) - { - submitter->setRootDescriptorTable(index++, heap.getGpuHandle(detail.m_srvIndex)); - } - - if (detail.m_uavIndex >= 0) - { - submitter->setRootDescriptorTable(index++, heap.getGpuHandle(detail.m_uavIndex)); - } - } - } - } - - if (bindingState && bindingState->m_samplerHeap.getUsedSize() > 0) - { - submitter->setRootDescriptorTable(index, bindingState->m_samplerHeap.getGpuStart()); - } - } - - return SLANG_OK; -} - -// !!!!!!!!!!!!!!!!!!!!!!!!!!!! Renderer interface !!!!!!!!!!!!!!!!!!!!!!!!!! - -Result D3D12Renderer::initialize(const Desc& desc, void* inWindowHandle) -{ - m_hwnd = (HWND)inWindowHandle; - // Rather than statically link against D3D, we load it dynamically. - - HMODULE d3dModule = LoadLibraryA("d3d12.dll"); - if (!d3dModule) - { - fprintf(stderr, "error: failed load 'd3d12.dll'\n"); - return SLANG_FAIL; - } - - HMODULE dxgiModule = LoadLibraryA("Dxgi.dll"); - if (!dxgiModule) - { - fprintf(stderr, "error: failed load 'dxgi.dll'\n"); - return SLANG_FAIL; - } - - -#define LOAD_D3D_PROC(TYPE, NAME) \ - TYPE NAME##_ = (TYPE) loadProc(d3dModule, #NAME); -#define LOAD_DXGI_PROC(TYPE, NAME) \ - TYPE NAME##_ = (TYPE) loadProc(dxgiModule, #NAME); - - UINT dxgiFactoryFlags = 0; - -#if ENABLE_DEBUG_LAYER - { - LOAD_D3D_PROC(PFN_D3D12_GET_DEBUG_INTERFACE, D3D12GetDebugInterface); - if (D3D12GetDebugInterface_) - { - if (SUCCEEDED(D3D12GetDebugInterface_(IID_PPV_ARGS(m_dxDebug.writeRef())))) - { - m_dxDebug->EnableDebugLayer(); - dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG; - } - } - } -#endif - - m_D3D12SerializeRootSignature = (PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)loadProc(d3dModule, "D3D12SerializeRootSignature"); - if (!m_D3D12SerializeRootSignature) - { - return SLANG_FAIL; - } - - // Try and create DXGIFactory - ComPtr<IDXGIFactory4> dxgiFactory; - { - typedef HRESULT(WINAPI *PFN_DXGI_CREATE_FACTORY_2)(UINT Flags, REFIID riid, _COM_Outptr_ void **ppFactory); - LOAD_DXGI_PROC(PFN_DXGI_CREATE_FACTORY_2, CreateDXGIFactory2); - if (!CreateDXGIFactory2_) - { - return SLANG_FAIL; - } - SLANG_RETURN_ON_FAIL(CreateDXGIFactory2_(dxgiFactoryFlags, IID_PPV_ARGS(dxgiFactory.writeRef()))); - } - - D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_0; - - // Search for an adapter that meets our requirements - ComPtr<IDXGIAdapter> adapter; - - LOAD_D3D_PROC(PFN_D3D12_CREATE_DEVICE, D3D12CreateDevice); - if (!D3D12CreateDevice_) - { - return SLANG_FAIL; - } - - const bool useWarp = false; - - if (useWarp) - { - SLANG_RETURN_ON_FAIL(dxgiFactory->EnumWarpAdapter(IID_PPV_ARGS(adapter.writeRef()))); - SLANG_RETURN_ON_FAIL(D3D12CreateDevice_(adapter, featureLevel, IID_PPV_ARGS(m_device.writeRef()))); - } - else - { - UINT adapterCounter = 0; - for (;;) - { - UINT adapterIndex = adapterCounter++; - - ComPtr<IDXGIAdapter1> candidateAdapter; - if (dxgiFactory->EnumAdapters1(adapterIndex, candidateAdapter.writeRef()) == DXGI_ERROR_NOT_FOUND) - break; - - DXGI_ADAPTER_DESC1 desc; - candidateAdapter->GetDesc1(&desc); - - if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) - { - // TODO: may want to allow software driver as fallback - } - else if (SUCCEEDED(D3D12CreateDevice_(candidateAdapter, featureLevel, IID_PPV_ARGS(m_device.writeRef())))) - { - // We found one! - adapter = candidateAdapter; - break; - } - } - } - - if (!adapter) - { - // Couldn't find an adapter - return SLANG_FAIL; - } - - m_numRenderFrames = 3; - m_numRenderTargets = 2; - - m_desc = desc; - - // set viewport - { - m_viewport.Width = float(m_desc.width); - m_viewport.Height = float(m_desc.height); - m_viewport.MinDepth = 0; - m_viewport.MaxDepth = 1; - m_viewport.TopLeftX = 0; - m_viewport.TopLeftY = 0; - } - - { - m_scissorRect.left = 0; - m_scissorRect.top = 0; - m_scissorRect.right = m_desc.width; - m_scissorRect.bottom = m_desc.height; - } - - // Describe and create the command queue. - D3D12_COMMAND_QUEUE_DESC queueDesc = {}; - queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; - queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - - SLANG_RETURN_ON_FAIL(m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(m_commandQueue.writeRef()))); - - // Describe the swap chain. - DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; - swapChainDesc.BufferCount = m_numRenderTargets; - swapChainDesc.BufferDesc.Width = m_desc.width; - swapChainDesc.BufferDesc.Height = m_desc.height; - swapChainDesc.BufferDesc.Format = m_targetFormat; - swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; - swapChainDesc.OutputWindow = m_hwnd; - swapChainDesc.SampleDesc.Count = 1; - swapChainDesc.Windowed = TRUE; - - if (m_isFullSpeed) - { - m_hasVsync = false; - m_allowFullScreen = false; - } - - if (!m_hasVsync) - { - swapChainDesc.Flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; - } - - // Swap chain needs the queue so that it can force a flush on it. - ComPtr<IDXGISwapChain> swapChain; - SLANG_RETURN_ON_FAIL(dxgiFactory->CreateSwapChain(m_commandQueue, &swapChainDesc, swapChain.writeRef())); - SLANG_RETURN_ON_FAIL(swapChain->QueryInterface(m_swapChain.writeRef())); - - if (!m_hasVsync) - { - m_swapChainWaitableObject = m_swapChain->GetFrameLatencyWaitableObject(); - - int maxLatency = m_numRenderTargets - 2; - - // Make sure the maximum latency is in the range required by dx12 runtime - maxLatency = (maxLatency < 1) ? 1 : maxLatency; - maxLatency = (maxLatency > DXGI_MAX_SWAP_CHAIN_BUFFERS) ? DXGI_MAX_SWAP_CHAIN_BUFFERS : maxLatency; - - m_swapChain->SetMaximumFrameLatency(maxLatency); - } - - // This sample does not support fullscreen transitions. - SLANG_RETURN_ON_FAIL(dxgiFactory->MakeWindowAssociation(m_hwnd, DXGI_MWA_NO_ALT_ENTER)); - - m_renderTargetIndex = m_swapChain->GetCurrentBackBufferIndex(); - - // Create descriptor heaps. - { - // Describe and create a render target view (RTV) descriptor heap. - D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {}; - - rtvHeapDesc.NumDescriptors = m_numRenderTargets; - rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; - rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; - SLANG_RETURN_ON_FAIL(m_device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(m_rtvHeap.writeRef()))); - m_rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); - } - - { - // Describe and create a depth stencil view (DSV) descriptor heap. - D3D12_DESCRIPTOR_HEAP_DESC dsvHeapDesc = {}; - dsvHeapDesc.NumDescriptors = 1; - dsvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; - dsvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; - SLANG_RETURN_ON_FAIL(m_device->CreateDescriptorHeap(&dsvHeapDesc, IID_PPV_ARGS(m_dsvHeap.writeRef()))); - - m_dsvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV); - } - - // Setup frame resources - { - SLANG_RETURN_ON_FAIL(createFrameResources()); - } - - // Setup fence, and close the command list (as default state without begin/endRender is closed) - { - SLANG_RETURN_ON_FAIL(m_fence.init(m_device)); - // Create the command list. When command lists are created they are open, so close it. - FrameInfo& frame = m_frameInfos[m_frameIndex]; - SLANG_RETURN_ON_FAIL(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, frame.m_commandAllocator, nullptr, IID_PPV_ARGS(m_commandList.writeRef()))); - m_commandList->Close(); - } - - { - D3D12CircularResourceHeap::Desc desc; - desc.init(); - // Define size - desc.m_blockSize = 65536; - // Set up the heap - m_circularResourceHeap.init(m_device, desc, &m_fence); - } - - // Setup for rendering - beginRender(); - - m_isInitialized = true; - return SLANG_OK; -} - -Result D3D12Renderer::createFrameResources() -{ - // Create back buffers - { - D3D12_CPU_DESCRIPTOR_HANDLE rtvStart(m_rtvHeap->GetCPUDescriptorHandleForHeapStart()); - - // Work out target format - D3D12_RESOURCE_DESC resourceDesc; - { - ComPtr<ID3D12Resource> backBuffer; - SLANG_RETURN_ON_FAIL(m_swapChain->GetBuffer(0, IID_PPV_ARGS(backBuffer.writeRef()))); - resourceDesc = backBuffer->GetDesc(); - } - const DXGI_FORMAT resourceFormat = D3DUtil::calcResourceFormat(D3DUtil::USAGE_TARGET, m_targetUsageFlags, resourceDesc.Format); - const DXGI_FORMAT targetFormat = D3DUtil::calcFormat(D3DUtil::USAGE_TARGET, resourceFormat); - - // Set the target format - m_targetFormat = targetFormat; - - // Create a RTV, and a command allocator for each frame. - for (int i = 0; i < m_numRenderTargets; i++) - { - // Get the back buffer - ComPtr<ID3D12Resource> backBuffer; - SLANG_RETURN_ON_FAIL(m_swapChain->GetBuffer(UINT(i), IID_PPV_ARGS(backBuffer.writeRef()))); - - // Set up resource for back buffer - m_backBufferResources[i].setResource(backBuffer, D3D12_RESOURCE_STATE_COMMON); - m_backBuffers[i] = &m_backBufferResources[i]; - // Assume they are the same thing for now... - m_renderTargets[i] = &m_backBufferResources[i]; - - // If we are multi-sampling - create a render target separate from the back buffer - if (m_isMultiSampled) - { - D3D12_HEAP_PROPERTIES heapProps; - heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; - heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - heapProps.CreationNodeMask = 1; - heapProps.VisibleNodeMask = 1; - D3D12_CLEAR_VALUE clearValue = {}; - clearValue.Format = m_targetFormat; - - // Don't know targets alignment, so just memory copy - ::memcpy(clearValue.Color, m_clearColor, sizeof(m_clearColor)); - - D3D12_RESOURCE_DESC desc(resourceDesc); - - desc.Format = resourceFormat; - desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; - desc.SampleDesc.Count = m_numTargetSamples; - desc.SampleDesc.Quality = m_targetSampleQuality; - desc.Alignment = 0; - - SLANG_RETURN_ON_FAIL(m_renderTargetResources[i].initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, desc, D3D12_RESOURCE_STATE_RENDER_TARGET, &clearValue)); - m_renderTargets[i] = &m_renderTargetResources[i]; - } - - D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = { rtvStart.ptr + i * m_rtvDescriptorSize }; - m_device->CreateRenderTargetView(*m_renderTargets[i], nullptr, rtvHandle); - } - } - - // Set up frames - for (int i = 0; i < m_numRenderFrames; i++) - { - FrameInfo& frame = m_frameInfos[i]; - SLANG_RETURN_ON_FAIL(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(frame.m_commandAllocator.writeRef()))); - } - - { - D3D12_RESOURCE_DESC desc = m_backBuffers[0]->getResource()->GetDesc(); - assert(desc.Width == UINT64(m_desc.width) && desc.Height == UINT64(m_desc.height)); - } - - // Create the depth stencil view. - { - D3D12_HEAP_PROPERTIES heapProps; - heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; - heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - heapProps.CreationNodeMask = 1; - heapProps.VisibleNodeMask = 1; - - DXGI_FORMAT resourceFormat = D3DUtil::calcResourceFormat(D3DUtil::USAGE_DEPTH_STENCIL, m_depthStencilUsageFlags, m_depthStencilFormat); - DXGI_FORMAT depthStencilFormat = D3DUtil::calcFormat(D3DUtil::USAGE_DEPTH_STENCIL, resourceFormat); - - // Set the depth stencil format - m_depthStencilFormat = depthStencilFormat; - - // Setup default clear - D3D12_CLEAR_VALUE clearValue = {}; - clearValue.Format = depthStencilFormat; - clearValue.DepthStencil.Depth = 1.0f; - clearValue.DepthStencil.Stencil = 0; - - D3D12_RESOURCE_DESC resourceDesc = {}; - resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; - resourceDesc.Format = resourceFormat; - resourceDesc.Width = m_desc.width; - resourceDesc.Height = m_desc.height; - resourceDesc.DepthOrArraySize = 1; - resourceDesc.MipLevels = 1; - resourceDesc.SampleDesc.Count = m_numTargetSamples; - resourceDesc.SampleDesc.Quality = m_targetSampleQuality; - resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; - resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; - resourceDesc.Alignment = 0; - - SLANG_RETURN_ON_FAIL(m_depthStencil.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, resourceDesc, D3D12_RESOURCE_STATE_DEPTH_WRITE, &clearValue)); - - // Set the depth stencil - D3D12_DEPTH_STENCIL_VIEW_DESC depthStencilDesc = {}; - depthStencilDesc.Format = depthStencilFormat; - depthStencilDesc.ViewDimension = m_isMultiSampled ? D3D12_DSV_DIMENSION_TEXTURE2DMS : D3D12_DSV_DIMENSION_TEXTURE2D; - depthStencilDesc.Flags = D3D12_DSV_FLAG_NONE; - - // Set up as the depth stencil view - m_device->CreateDepthStencilView(m_depthStencil, &depthStencilDesc, m_dsvHeap->GetCPUDescriptorHandleForHeapStart()); - m_depthStencilView = m_dsvHeap->GetCPUDescriptorHandleForHeapStart(); - } - - m_viewport.Width = static_cast<float>(m_desc.width); - m_viewport.Height = static_cast<float>(m_desc.height); - m_viewport.MaxDepth = 1.0f; - - m_scissorRect.right = static_cast<LONG>(m_desc.width); - m_scissorRect.bottom = static_cast<LONG>(m_desc.height); - - return SLANG_OK; -} - -void D3D12Renderer::setClearColor(const float color[4]) -{ - memcpy(m_clearColor, color, sizeof(m_clearColor)); -} - -void D3D12Renderer::clearFrame() -{ - // Record commands - D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = { m_rtvHeap->GetCPUDescriptorHandleForHeapStart().ptr + m_renderTargetIndex * m_rtvDescriptorSize }; - m_commandList->ClearRenderTargetView(rtvHandle, m_clearColor, 0, nullptr); - if (m_depthStencil) - { - m_commandList->ClearDepthStencilView(m_depthStencilView, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr); - } -} - -void D3D12Renderer::presentFrame() -{ - endRender(); - - if (m_swapChainWaitableObject) - { - // check if now is good time to present - // This doesn't wait - because the wait time is 0. If it returns WAIT_TIMEOUT it means that no frame is waiting to be be displayed - // so there is no point doing a present. - const bool shouldPresent = (WaitForSingleObjectEx(m_swapChainWaitableObject, 0, TRUE) != WAIT_TIMEOUT); - if (shouldPresent) - { - m_swapChain->Present(0, 0); - } - } - else - { - if (SLANG_FAILED(m_swapChain->Present(1, 0))) - { - assert(!"Problem presenting"); - beginRender(); - return; - } - } - - // Increment the fence value. Save on the frame - we'll know that frame is done when the fence value >= - m_frameInfos[m_frameIndex].m_fenceValue = m_fence.nextSignal(m_commandQueue); - - // increment frame index after signal - m_frameIndex = (m_frameIndex + 1) % m_numRenderFrames; - // Update the render target index. - m_renderTargetIndex = m_swapChain->GetCurrentBackBufferIndex(); - - // On the current frame wait until it is completed - { - FrameInfo& frame = m_frameInfos[m_frameIndex]; - // If the next frame is not ready to be rendered yet, wait until it is ready. - m_fence.waitUntilCompleted(frame.m_fenceValue); - } - - // Setup such that rendering can restart - beginRender(); -} - -SlangResult D3D12Renderer::captureScreenSurface(Surface& surfaceOut) -{ - return captureTextureToSurface(*m_renderTargets[m_renderTargetIndex], surfaceOut); -} - -static D3D12_RESOURCE_STATES _calcResourceState(Resource::Usage usage) -{ - typedef Resource::Usage Usage; - switch (usage) - { - case Usage::VertexBuffer: return D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER; - case Usage::IndexBuffer: return D3D12_RESOURCE_STATE_INDEX_BUFFER; - case Usage::ConstantBuffer: return D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER; - case Usage::StreamOutput: return D3D12_RESOURCE_STATE_STREAM_OUT; - case Usage::RenderTarget: return D3D12_RESOURCE_STATE_RENDER_TARGET; - case Usage::DepthWrite: return D3D12_RESOURCE_STATE_DEPTH_WRITE; - case Usage::DepthRead: return D3D12_RESOURCE_STATE_DEPTH_READ; - case Usage::UnorderedAccess: return D3D12_RESOURCE_STATE_UNORDERED_ACCESS; - case Usage::PixelShaderResource: return D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; - case Usage::NonPixelShaderResource: return D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; - case Usage::GenericRead: return D3D12_RESOURCE_STATE_GENERIC_READ; - default: return D3D12_RESOURCE_STATES(0); - } -} - -static D3D12_RESOURCE_FLAGS _calcResourceFlag(Resource::BindFlag::Enum bindFlag) -{ - typedef Resource::BindFlag BindFlag; - switch (bindFlag) - { - case BindFlag::RenderTarget: return D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; - case BindFlag::DepthStencil: return D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; - case BindFlag::UnorderedAccess: return D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; - default: return D3D12_RESOURCE_FLAG_NONE; - } -} - -static D3D12_RESOURCE_FLAGS _calcResourceBindFlags(Resource::Usage initialUsage, int bindFlags) -{ - int dstFlags = 0; - while (bindFlags) - { - int lsb = bindFlags & -bindFlags; - - dstFlags |= _calcResourceFlag(Resource::BindFlag::Enum(lsb)); - bindFlags &= ~lsb; - } - return D3D12_RESOURCE_FLAGS(dstFlags); -} - -static D3D12_RESOURCE_DIMENSION _calcResourceDimension(Resource::Type type) -{ - switch (type) - { - case Resource::Type::Buffer: return D3D12_RESOURCE_DIMENSION_BUFFER; - case Resource::Type::Texture1D: return D3D12_RESOURCE_DIMENSION_TEXTURE1D; - case Resource::Type::TextureCube: - case Resource::Type::Texture2D: - { - return D3D12_RESOURCE_DIMENSION_TEXTURE2D; - } - case Resource::Type::Texture3D: return D3D12_RESOURCE_DIMENSION_TEXTURE3D; - default: return D3D12_RESOURCE_DIMENSION_UNKNOWN; - } -} - -TextureResource* D3D12Renderer::createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& descIn, const TextureResource::Data* initData) -{ - // Description of uploading on Dx12 - // https://msdn.microsoft.com/en-us/library/windows/desktop/dn899215%28v=vs.85%29.aspx - - TextureResource::Desc srcDesc(descIn); - srcDesc.setDefaults(initialUsage); - - const DXGI_FORMAT pixelFormat = D3DUtil::getMapFormat(srcDesc.format); - if (pixelFormat == DXGI_FORMAT_UNKNOWN) - { - return nullptr; - } - - const int arraySize = srcDesc.calcEffectiveArraySize(); - - const D3D12_RESOURCE_DIMENSION dimension = _calcResourceDimension(srcDesc.type); - if (dimension == D3D12_RESOURCE_DIMENSION_UNKNOWN) - { - return nullptr; - } - - const int numMipMaps = srcDesc.numMipLevels; - - // Setup desc - D3D12_RESOURCE_DESC resourceDesc; - - resourceDesc.Dimension = dimension; - resourceDesc.Format = pixelFormat; - resourceDesc.Width = srcDesc.size.width; - resourceDesc.Height = srcDesc.size.height; - resourceDesc.DepthOrArraySize = (srcDesc.size.depth > 1) ? srcDesc.size.depth : arraySize; - - resourceDesc.MipLevels = numMipMaps; - resourceDesc.SampleDesc.Count = srcDesc.sampleDesc.numSamples; - resourceDesc.SampleDesc.Quality = srcDesc.sampleDesc.quality; - - resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; - resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; - resourceDesc.Alignment = 0; - - RefPtr<TextureResourceImpl> texture(new TextureResourceImpl(srcDesc)); - - // Create the target resource - { - D3D12_HEAP_PROPERTIES heapProps; - - heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; - heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - heapProps.CreationNodeMask = 1; - heapProps.VisibleNodeMask = 1; - - SLANG_RETURN_NULL_ON_FAIL(texture->m_resource.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, resourceDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr)); - - texture->m_resource.setDebugName(L"Texture"); - } - - // Calculate the layout - List<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> layouts; - layouts.SetSize(numMipMaps); - List<UInt64> mipRowSizeInBytes; - mipRowSizeInBytes.SetSize(numMipMaps); - List<UInt32> mipNumRows; - mipNumRows.SetSize(numMipMaps); - - // Since textures are effectively immutable currently initData must be set - assert(initData); - // We should have this many sub resources - assert(initData->numSubResources == numMipMaps * srcDesc.size.depth * arraySize); - - // This is just the size for one array upload -> not for the whole texure - UInt64 requiredSize = 0; - m_device->GetCopyableFootprints(&resourceDesc, 0, numMipMaps, 0, layouts.begin(), mipNumRows.begin(), mipRowSizeInBytes.begin(), &requiredSize); - - // Sub resource indexing - // https://msdn.microsoft.com/en-us/library/windows/desktop/dn705766(v=vs.85).aspx#subresource_indexing - - int subResourceIndex = 0; - for (int i = 0; i < arraySize; i++) - { - // Create the upload texture - D3D12Resource uploadTexture; - { - D3D12_HEAP_PROPERTIES heapProps; - - heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; - heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - heapProps.CreationNodeMask = 1; - heapProps.VisibleNodeMask = 1; - - D3D12_RESOURCE_DESC uploadResourceDesc; - - uploadResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - uploadResourceDesc.Format = DXGI_FORMAT_UNKNOWN; - uploadResourceDesc.Width = requiredSize; - uploadResourceDesc.Height = 1; - uploadResourceDesc.DepthOrArraySize = 1; - uploadResourceDesc.MipLevels = 1; - uploadResourceDesc.SampleDesc.Count = 1; - uploadResourceDesc.SampleDesc.Quality = 0; - uploadResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; - uploadResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; - uploadResourceDesc.Alignment = 0; - - SLANG_RETURN_NULL_ON_FAIL(uploadTexture.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, uploadResourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr)); - - uploadTexture.setDebugName(L"TextureUpload"); - } - - ID3D12Resource* uploadResource = uploadTexture; - - uint8_t* p; - uploadResource->Map(0, nullptr, reinterpret_cast<void**>(&p)); - - for (int j = 0; j < numMipMaps; ++j) - { - const D3D12_PLACED_SUBRESOURCE_FOOTPRINT& layout = layouts[j]; - const D3D12_SUBRESOURCE_FOOTPRINT& footprint = layout.Footprint; - - const TextureResource::Size mipSize = srcDesc.size.calcMipSize(j); - - assert(footprint.Width == mipSize.width && footprint.Height == mipSize.height && footprint.Depth == mipSize.depth); - - const ptrdiff_t dstMipRowPitch = ptrdiff_t(layouts[j].Footprint.RowPitch); - const ptrdiff_t srcMipRowPitch = ptrdiff_t(initData->mipRowStrides[j]); - - assert(dstMipRowPitch >= srcMipRowPitch); - - const uint8_t* srcRow = (const uint8_t*)initData->subResources[subResourceIndex]; - uint8_t* dstRow = p + layouts[j].Offset; - - // Copy the depth each mip - for (int l = 0; l < mipSize.depth; l++) - { - // Copy rows - for (int k = 0; k < mipSize.height; ++k) - { - ::memcpy(dstRow, srcRow, srcMipRowPitch); - - srcRow += srcMipRowPitch; - dstRow += dstMipRowPitch; - } - } - - //assert(srcRow == (const uint8_t*)(srcMip.Buffer() + srcMip.Count())); - } - uploadResource->Unmap(0, nullptr); - - for (int mipIndex = 0; mipIndex < numMipMaps; ++mipIndex) - { - // https://msdn.microsoft.com/en-us/library/windows/desktop/dn903862(v=vs.85).aspx - - D3D12_TEXTURE_COPY_LOCATION src; - src.pResource = uploadTexture; - src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - src.PlacedFootprint = layouts[mipIndex]; - - D3D12_TEXTURE_COPY_LOCATION dst; - dst.pResource = texture->m_resource; - dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - dst.SubresourceIndex = subResourceIndex; - m_commandList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr); - - subResourceIndex++; - } - - { - // const D3D12_RESOURCE_STATES finalState = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; - const D3D12_RESOURCE_STATES finalState = _calcResourceState(initialUsage); - - D3D12BarrierSubmitter submitter(m_commandList); - texture->m_resource.transition(finalState, submitter); - } - - // Block - waiting for copy to complete (so can drop upload texture) - submitGpuWorkAndWait(); - } - - return texture.detach(); -} - -BufferResource* D3D12Renderer::createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& descIn, const void* initData) -{ - typedef BufferResourceImpl::BackingStyle Style; - - BufferResource::Desc srcDesc(descIn); - srcDesc.setDefaults(initialUsage); - - RefPtr<BufferResourceImpl> buffer(new BufferResourceImpl(initialUsage, srcDesc)); - - // Save the style - buffer->m_backingStyle = BufferResourceImpl::_calcResourceBackingStyle(initialUsage); - - D3D12_RESOURCE_DESC bufferDesc; - _initBufferResourceDesc(srcDesc.sizeInBytes, bufferDesc); - - bufferDesc.Flags = _calcResourceBindFlags(initialUsage, srcDesc.bindFlags); - - switch (buffer->m_backingStyle) - { - case Style::MemoryBacked: - { - // Assume the constant buffer will change every frame. We'll just keep a copy of the contents - // in regular memory until it needed - buffer->m_memory.SetSize(UInt(srcDesc.sizeInBytes)); - // Initialize - if (initData) - { - ::memcpy(buffer->m_memory.Buffer(), initData, srcDesc.sizeInBytes); - } - break; - } - case Style::ResourceBacked: - { - const D3D12_RESOURCE_STATES initialState = _calcResourceState(initialUsage); - SLANG_RETURN_NULL_ON_FAIL(createBuffer(bufferDesc, initData, buffer->m_uploadResource, initialState, buffer->m_resource)); - break; - } - default: return nullptr; - } - - return buffer.detach(); -} - -InputLayout* D3D12Renderer::createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) -{ - RefPtr<InputLayoutImpl> layout(new InputLayoutImpl); - - // Work out a buffer size to hold all text - size_t textSize = 0; - for (int i = 0; i < Int(inputElementCount); ++i) - { - const char* text = inputElements[i].semanticName; - textSize += text ? (::strlen(text) + 1) : 0; - } - layout->m_text.SetSize(textSize); - char* textPos = layout->m_text.Buffer(); - - // - List<D3D12_INPUT_ELEMENT_DESC>& elements = layout->m_elements; - elements.SetSize(inputElementCount); - - - for (UInt i = 0; i < inputElementCount; ++i) - { - const InputElementDesc& srcEle = inputElements[i]; - D3D12_INPUT_ELEMENT_DESC& dstEle = elements[i]; - - // Add text to the buffer - const char* semanticName = srcEle.semanticName; - if (semanticName) - { - const int len = int(::strlen(semanticName)); - ::memcpy(textPos, semanticName, len + 1); - semanticName = textPos; - textPos += len + 1; - } - - dstEle.SemanticName = semanticName; - dstEle.SemanticIndex = (UINT)srcEle.semanticIndex; - dstEle.Format = D3DUtil::getMapFormat(srcEle.format); - dstEle.InputSlot = 0; - dstEle.AlignedByteOffset = (UINT)srcEle.offset; - dstEle.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA; - dstEle.InstanceDataStepRate = 0; - } - - return layout.detach(); -} - -void* D3D12Renderer::map(BufferResource* bufferIn, MapFlavor flavor) -{ - typedef BufferResourceImpl::BackingStyle Style; - - BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(bufferIn); - buffer->m_mapFlavor = flavor; - - const size_t bufferSize = buffer->getDesc().sizeInBytes; - - switch (buffer->m_backingStyle) - { - case Style::ResourceBacked: - { - // We need this in a state so we can upload - switch (flavor) - { - case MapFlavor::HostWrite: - case MapFlavor::WriteDiscard: - { - D3D12BarrierSubmitter submitter(m_commandList); - buffer->m_uploadResource.transition(D3D12_RESOURCE_STATE_GENERIC_READ, submitter); - buffer->m_resource.transition(D3D12_RESOURCE_STATE_COPY_DEST, submitter); - - const D3D12_RANGE readRange = {}; - - void* uploadData; - SLANG_RETURN_NULL_ON_FAIL(buffer->m_uploadResource.getResource()->Map(0, &readRange, reinterpret_cast<void**>(&uploadData))); - return uploadData; - - break; - } - case MapFlavor::HostRead: - { - // This will be slow!!! - it blocks CPU on GPU completion - D3D12Resource& resource = buffer->m_resource; - - // Readback heap - D3D12_HEAP_PROPERTIES heapProps; - heapProps.Type = D3D12_HEAP_TYPE_READBACK; - heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - heapProps.CreationNodeMask = 1; - heapProps.VisibleNodeMask = 1; - - // Resource to readback to - D3D12_RESOURCE_DESC stagingDesc; - _initBufferResourceDesc(bufferSize, stagingDesc); - - D3D12Resource stageBuf; - SLANG_RETURN_NULL_ON_FAIL(stageBuf.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, stagingDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr)); - - const D3D12_RESOURCE_STATES initialState = resource.getState(); - - // Make it a source - { - D3D12BarrierSubmitter submitter(m_commandList); - resource.transition(D3D12_RESOURCE_STATE_COPY_SOURCE, submitter); - } - // Do the copy - m_commandList->CopyBufferRegion(stageBuf, 0, resource, 0, bufferSize); - // Switch it back - { - D3D12BarrierSubmitter submitter(m_commandList); - resource.transition(initialState, submitter); - } - - // Wait until complete - submitGpuWorkAndWait(); - - // Map and copy - { - UINT8* data; - D3D12_RANGE readRange = { 0, bufferSize }; - - SLANG_RETURN_NULL_ON_FAIL(stageBuf.getResource()->Map(0, &readRange, reinterpret_cast<void**>(&data))); - - // Copy to memory buffer - buffer->m_memory.SetSize(bufferSize); - ::memcpy(buffer->m_memory.Buffer(), data, bufferSize); - - stageBuf.getResource()->Unmap(0, nullptr); - } - - return buffer->m_memory.Buffer(); - } - } - break; - } - case Style::MemoryBacked: - { - return buffer->m_memory.Buffer(); - } - default: return nullptr; - } - - return nullptr; -} - -void D3D12Renderer::unmap(BufferResource* bufferIn) -{ - typedef BufferResourceImpl::BackingStyle Style; - BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(bufferIn); - - switch (buffer->m_backingStyle) - { - case Style::MemoryBacked: - { - // Don't need to do anything, as will be uploaded automatically when used - break; - } - case Style::ResourceBacked: - { - // We need this in a state so we can upload - switch (buffer->m_mapFlavor) - { - case MapFlavor::HostWrite: - case MapFlavor::WriteDiscard: - { - // Unmap - ID3D12Resource* uploadResource = buffer->m_uploadResource; - ID3D12Resource* resource = buffer->m_resource; - - uploadResource->Unmap(0, nullptr); - - const D3D12_RESOURCE_STATES initialState = buffer->m_resource.getState(); - - { - D3D12BarrierSubmitter submitter(m_commandList); - buffer->m_uploadResource.transition(D3D12_RESOURCE_STATE_GENERIC_READ, submitter); - buffer->m_resource.transition(D3D12_RESOURCE_STATE_COPY_DEST, submitter); - } - - m_commandList->CopyBufferRegion(resource, 0, uploadResource, 0, buffer->getDesc().sizeInBytes); - - { - D3D12BarrierSubmitter submitter(m_commandList); - buffer->m_resource.transition(initialState, submitter); - } - break; - } - case MapFlavor::HostRead: - { - break; - } - } - } - } -} - -void D3D12Renderer::setInputLayout(InputLayout* inputLayout) -{ - m_boundInputLayout = static_cast<InputLayoutImpl*>(inputLayout); -} - -void D3D12Renderer::setPrimitiveTopology(PrimitiveTopology topology) -{ - switch (topology) - { - case PrimitiveTopology::TriangleList: - { - m_primitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; - m_primitiveTopology = D3DUtil::getPrimitiveTopology(topology); - break; - } - default: - { - assert(!"Unhandled type"); - } - } -} - -void D3D12Renderer::setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) -{ - { - const UInt num = startSlot + slotCount; - if (num > m_boundVertexBuffers.Count()) - { - m_boundVertexBuffers.SetSize(num); - } - } - - for (UInt i = 0; i < slotCount; i++) - { - BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(buffers[i]); - if (buffer) - { - assert(buffer->m_initialUsage == Resource::Usage::VertexBuffer); - } - - BoundVertexBuffer& boundBuffer = m_boundVertexBuffers[startSlot + i]; - boundBuffer.m_buffer = buffer; - boundBuffer.m_stride = int(strides[i]); - boundBuffer.m_offset = int(offsets[i]); - } -} - -void D3D12Renderer::setShaderProgram(ShaderProgram* inProgram) -{ - m_boundShaderProgram = static_cast<ShaderProgramImpl*>(inProgram); -} - -void D3D12Renderer::draw(UInt vertexCount, UInt startVertex) -{ - ID3D12GraphicsCommandList* commandList = m_commandList; - - RenderState* renderState = calcRenderState(); - if (!renderState) - { - assert(!"Couldn't create render state"); - return; - } - - BindingStateImpl* bindingState = m_boundBindingState; - - // Submit - setting for graphics - { - GraphicsSubmitter submitter(commandList); - _bindRenderState(renderState, commandList, &submitter); - } - - commandList->IASetPrimitiveTopology(m_primitiveTopology); - - // Set up vertex buffer views - { - int numVertexViews = 0; - D3D12_VERTEX_BUFFER_VIEW vertexViews[16]; - for (int i = 0; i < int(m_boundVertexBuffers.Count()); i++) - { - const BoundVertexBuffer& boundVertexBuffer = m_boundVertexBuffers[i]; - BufferResourceImpl* buffer = boundVertexBuffer.m_buffer; - if (buffer) - { - D3D12_VERTEX_BUFFER_VIEW& vertexView = vertexViews[numVertexViews++]; - vertexView.BufferLocation = buffer->m_resource.getResource()->GetGPUVirtualAddress(); - vertexView.SizeInBytes = int(buffer->getDesc().sizeInBytes); - vertexView.StrideInBytes = boundVertexBuffer.m_stride; - } - } - commandList->IASetVertexBuffers(0, numVertexViews, vertexViews); - } - - commandList->DrawInstanced(UINT(vertexCount), 1, UINT(startVertex), 0); -} - -void D3D12Renderer::dispatchCompute(int x, int y, int z) -{ - ID3D12GraphicsCommandList* commandList = m_commandList; - RenderState* renderState = calcRenderState(); - - // Submit binding for compute - { - ComputeSubmitter submitter(commandList); - _bindRenderState(renderState, commandList, &submitter); - } - - commandList->Dispatch(x, y, z); -} - -BindingState* D3D12Renderer::createBindingState(const BindingState::Desc& bindingStateDesc) -{ - RefPtr<BindingStateImpl> bindingState(new BindingStateImpl(bindingStateDesc)); - - SLANG_RETURN_NULL_ON_FAIL(bindingState->init(m_device)); - - const auto& srcBindings = bindingStateDesc.m_bindings; - const int numBindings = int(srcBindings.Count()); - - auto& dstDetails = bindingState->m_bindingDetails; - dstDetails.SetSize(numBindings); - - for (int i = 0; i < numBindings; ++i) - { - const auto& srcEntry = srcBindings[i]; - auto& dstDetail = dstDetails[i]; - - const int bindingIndex = srcEntry.registerRange.getSingleIndex(); - - switch (srcEntry.bindingType) - { - case BindingType::Buffer: - { - assert(srcEntry.resource && srcEntry.resource->isBuffer()); - BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(srcEntry.resource.Ptr()); - const BufferResource::Desc& bufferDesc = bufferResource->getDesc(); - - const size_t bufferSize = bufferDesc.sizeInBytes; - const int elemSize = bufferDesc.elementSize <= 0 ? sizeof(uint32_t) : bufferDesc.elementSize; - - const bool createSrv = false; - - // NOTE! In this arrangement the buffer can either be a ConstantBuffer or a 'StorageBuffer'. - // If it's a storage buffer then it has a 'uav'. - // In neither circumstance is there an associated srv - // This departs a little from dx11 code - in that it will create srv and uav for a storage buffer. - if (bufferDesc.bindFlags & Resource::BindFlag::UnorderedAccess) - { - dstDetail.m_uavIndex = bindingState->m_viewHeap.allocate(); - if (dstDetail.m_uavIndex < 0) - { - return nullptr; - } - - D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; - - uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; - uavDesc.Format = D3DUtil::getMapFormat(bufferDesc.format); - - uavDesc.Buffer.StructureByteStride = elemSize; - - uavDesc.Buffer.FirstElement = 0; - uavDesc.Buffer.NumElements = (UINT)(bufferSize / elemSize); - uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE; - - if (bufferDesc.elementSize == 0 && bufferDesc.format == Format::Unknown) - { - uavDesc.Buffer.Flags |= D3D12_BUFFER_UAV_FLAG_RAW; - uavDesc.Format = DXGI_FORMAT_R32_TYPELESS; - - uavDesc.Buffer.StructureByteStride = 0; - } - else if( bufferDesc.format != Format::Unknown ) - { - uavDesc.Buffer.StructureByteStride = 0; - } - - m_device->CreateUnorderedAccessView(bufferResource->m_resource, nullptr, &uavDesc, bindingState->m_viewHeap.getCpuHandle(dstDetail.m_uavIndex)); - } - if (createSrv && (bufferDesc.bindFlags & (Resource::BindFlag::NonPixelShaderResource | Resource::BindFlag::PixelShaderResource))) - { - dstDetail.m_srvIndex = bindingState->m_viewHeap.allocate(); - if (dstDetail.m_srvIndex < 0) - { - return nullptr; - } - - D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc; - - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; - srvDesc.Format = DXGI_FORMAT_UNKNOWN; - srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - - srvDesc.Buffer.FirstElement = 0; - srvDesc.Buffer.NumElements = (UINT)(bufferSize / elemSize); - srvDesc.Buffer.StructureByteStride = elemSize; - srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE; - - if (bufferDesc.elementSize == 0) - { - srvDesc.Format = DXGI_FORMAT_R32_FLOAT; - } - - m_device->CreateShaderResourceView(bufferResource->m_resource, &srvDesc, bindingState->m_viewHeap.getCpuHandle(dstDetail.m_srvIndex)); - } - - break; - } - case BindingType::Texture: - { - assert(srcEntry.resource && srcEntry.resource->isTexture()); - - TextureResourceImpl* textureResource = static_cast<TextureResourceImpl*>(srcEntry.resource.Ptr()); - - dstDetail.m_srvIndex = bindingState->m_viewHeap.allocate(); - if (dstDetail.m_srvIndex < 0) - { - return nullptr; - } - - { - const D3D12_RESOURCE_DESC resourceDesc = textureResource->m_resource.getResource()->GetDesc(); - const DXGI_FORMAT pixelFormat = resourceDesc.Format; - - D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc; - _initSrvDesc(textureResource->getType(), textureResource->getDesc(), resourceDesc, pixelFormat, srvDesc); - - // Create descriptor - m_device->CreateShaderResourceView(textureResource->m_resource, &srvDesc, bindingState->m_viewHeap.getCpuHandle(dstDetail.m_srvIndex)); - } - - break; - } - case BindingType::Sampler: - { - const BindingState::SamplerDesc& samplerDesc = bindingStateDesc.m_samplerDescs[srcEntry.descIndex]; - - const int samplerIndex = bindingIndex; - dstDetail.m_samplerIndex = samplerIndex; - bindingState->m_samplerHeap.placeAt(samplerIndex); - - D3D12_SAMPLER_DESC desc = {}; - desc.AddressU = desc.AddressV = desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP; - desc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS; - - if (samplerDesc.isCompareSampler) - { - desc.ComparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL; - desc.Filter = D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT; - } - else - { - desc.Filter = D3D12_FILTER_ANISOTROPIC; - desc.MaxAnisotropy = 8; - desc.MinLOD = 0.0f; - desc.MaxLOD = 100.0f; - } - - m_device->CreateSampler(&desc, bindingState->m_samplerHeap.getCpuHandle(samplerIndex)); - - break; - } - case BindingType::CombinedTextureSampler: - { - assert(!"Not implemented"); - return nullptr; - } - } - } - - return bindingState.detach(); -} - -void D3D12Renderer::setBindingState(BindingState* state) -{ - m_boundBindingState = static_cast<BindingStateImpl*>(state); -} - -ShaderProgram* D3D12Renderer::createProgram(const ShaderProgram::Desc& desc) -{ - RefPtr<ShaderProgramImpl> program(new ShaderProgramImpl()); - program->m_pipelineType = desc.pipelineType; - - if (desc.pipelineType == PipelineType::Compute) - { - auto computeKernel = desc.findKernel(StageType::Compute); - program->m_computeShader.InsertRange(0, (const uint8_t*) computeKernel->codeBegin, computeKernel->getCodeSize()); - } - else - { - auto vertexKernel = desc.findKernel(StageType::Vertex); - auto fragmentKernel = desc.findKernel(StageType::Fragment); - - program->m_vertexShader.InsertRange(0, (const uint8_t*) vertexKernel->codeBegin, vertexKernel->getCodeSize()); - program->m_pixelShader.InsertRange(0, (const uint8_t*) fragmentKernel->codeBegin, fragmentKernel->getCodeSize()); - } - - return program.detach(); -} - - -} // renderer_test diff --git a/tools/render-test/render-d3d12.h b/tools/render-test/render-d3d12.h deleted file mode 100644 index 259af7f7b..000000000 --- a/tools/render-test/render-d3d12.h +++ /dev/null @@ -1,10 +0,0 @@ -// render-d3d12.h -#pragma once - -namespace renderer_test { - -class Renderer; - -Renderer* createD3D12Renderer(); - -} // renderer_test diff --git a/tools/render-test/render-gl.cpp b/tools/render-test/render-gl.cpp deleted file mode 100644 index dc9f0c43a..000000000 --- a/tools/render-test/render-gl.cpp +++ /dev/null @@ -1,1049 +0,0 @@ -// render-gl.cpp -#include "render-gl.h" - -#include "options.h" -#include "render.h" - -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include "core/basic.h" -#include "core/secure-crt.h" -#include "external/stb/stb_image_write.h" - -#include "surface.h" - -// TODO(tfoley): eventually we should be able to run these -// tests on non-Windows targets to confirm that cross-compilation -// at least *works* on those platforms... -#define WIN32_LEAN_AND_MEAN -#define NOMINMAX -#include <Windows.h> -#undef WIN32_LEAN_AND_MEAN -#undef NOMINMAX - -#ifdef _MSC_VER -#include <stddef.h> -#if (_MSC_VER < 1900) -#define snprintf sprintf_s -#endif -#endif - -#pragma comment(lib, "opengl32") - -#include <GL/GL.h> -#include "external/glext.h" - -// We define an "X-macro" for mapping over loadable OpenGL -// extension entry point that we will use, so that we can -// easily write generic code to iterate over them. -#define MAP_GL_EXTENSION_FUNCS(F) \ - F(glCreateProgram, PFNGLCREATEPROGRAMPROC) \ - F(glCreateShader, PFNGLCREATESHADERPROC) \ - F(glShaderSource, PFNGLSHADERSOURCEPROC) \ - F(glCompileShader, PFNGLCOMPILESHADERPROC) \ - F(glGetShaderiv, PFNGLGETSHADERIVPROC) \ - F(glDeleteShader, PFNGLDELETESHADERPROC) \ - F(glAttachShader, PFNGLATTACHSHADERPROC) \ - F(glLinkProgram, PFNGLLINKPROGRAMPROC) \ - F(glGetProgramiv, PFNGLGETPROGRAMIVPROC) \ - F(glGetProgramInfoLog, PFNGLGETPROGRAMINFOLOGPROC) \ - F(glDeleteProgram, PFNGLDELETEPROGRAMPROC) \ - F(glGetShaderInfoLog, PFNGLGETSHADERINFOLOGPROC) \ - F(glGenBuffers, PFNGLGENBUFFERSPROC) \ - F(glBindBuffer, PFNGLBINDBUFFERPROC) \ - F(glBufferData, PFNGLBUFFERDATAPROC) \ - F(glDeleteBuffers, PFNGLDELETEBUFFERSPROC) \ - F(glMapBuffer, PFNGLMAPBUFFERPROC) \ - F(glUnmapBuffer, PFNGLUNMAPBUFFERPROC) \ - F(glUseProgram, PFNGLUSEPROGRAMPROC) \ - F(glBindBufferBase, PFNGLBINDBUFFERBASEPROC) \ - F(glVertexAttribPointer, PFNGLVERTEXATTRIBPOINTERPROC) \ - F(glEnableVertexAttribArray, PFNGLENABLEVERTEXATTRIBARRAYPROC) \ - F(glDisableVertexAttribArray, PFNGLDISABLEVERTEXATTRIBARRAYPROC) \ - F(glDebugMessageCallback, PFNGLDEBUGMESSAGECALLBACKPROC) \ - F(glDispatchCompute, PFNGLDISPATCHCOMPUTEPROC) \ - F(glActiveTexture, PFNGLACTIVETEXTUREPROC) \ - F(glCreateSamplers, PFNGLCREATESAMPLERSPROC) \ - F(glDeleteSamplers, PFNGLDELETESAMPLERSPROC) \ - F(glBindSampler, PFNGLBINDSAMPLERPROC) \ - F(glTexImage3D, PFNGLTEXIMAGE3DPROC) \ - F(glSamplerParameteri, PFNGLSAMPLERPARAMETERIPROC) \ - /* end */ - -using namespace Slang; - -namespace renderer_test { - -class GLRenderer : public Renderer -{ -public: - - // Renderer implementation - virtual SlangResult initialize(const Desc& desc, void* inWindowHandle) override; - virtual void setClearColor(const float color[4]) override; - virtual void clearFrame() override; - virtual void presentFrame() override; - virtual TextureResource* createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData) override; - virtual BufferResource* createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& descIn, const void* initData) override; - virtual SlangResult captureScreenSurface(Surface& surfaceOut) override; - virtual InputLayout* createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) override; - virtual BindingState* createBindingState(const BindingState::Desc& bindingStateDesc) override; - virtual ShaderProgram* createProgram(const ShaderProgram::Desc& desc) override; - virtual void* map(BufferResource* buffer, MapFlavor flavor) override; - virtual void unmap(BufferResource* buffer) override; - virtual void setInputLayout(InputLayout* inputLayout) override; - virtual void setPrimitiveTopology(PrimitiveTopology topology) override; - virtual void setBindingState(BindingState* state); - virtual void setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) override; - virtual void setShaderProgram(ShaderProgram* inProgram) override; - virtual void draw(UInt vertexCount, UInt startVertex) override; - virtual void dispatchCompute(int x, int y, int z) override; - virtual void submitGpuWork() override {} - virtual void waitForGpu() override {} - virtual RendererType getRendererType() const override { return RendererType::OpenGl; } - - protected: - enum - { - kMaxVertexStreams = 16, - }; - - struct VertexAttributeFormat - { - GLint componentCount; - GLenum componentType; - GLboolean normalized; - }; - - struct VertexAttributeDesc - { - VertexAttributeFormat format; - GLuint streamIndex; - GLsizei offset; - }; - - class InputLayoutImpl: public InputLayout - { - public: - VertexAttributeDesc m_attributes[kMaxVertexStreams]; - UInt m_attributeCount = 0; - }; - - class BufferResourceImpl: public BufferResource - { - public: - typedef BufferResource Parent; - - BufferResourceImpl(Usage initialUsage, const Desc& desc, GLRenderer* renderer, GLuint id, GLenum target): - Parent(desc), - m_renderer(renderer), - m_handle(id), - m_initialUsage(initialUsage), - m_target(target) - {} - ~BufferResourceImpl() - { - if (m_renderer) - { - m_renderer->glDeleteBuffers(1, &m_handle); - } - } - - Usage m_initialUsage; - GLRenderer* m_renderer; - GLuint m_handle; - GLenum m_target; - }; - - class TextureResourceImpl: public TextureResource - { - public: - typedef TextureResource Parent; - - TextureResourceImpl(Usage initialUsage, const Desc& desc, GLRenderer* renderer): - Parent(desc), - m_initialUsage(initialUsage), - m_renderer(renderer) - { - m_target = 0; - m_handle = 0; - } - - ~TextureResourceImpl() - { - if (m_handle) - { - glDeleteTextures(1, &m_handle); - } - } - - Usage m_initialUsage; - GLRenderer* m_renderer; - GLenum m_target; - GLuint m_handle; - }; - - struct BindingDetail - { - GLuint m_samplerHandle = 0; - }; - - class BindingStateImpl: public BindingState - { - public: - typedef BindingState Parent; - - /// Ctor - BindingStateImpl(const Desc& desc, GLRenderer* renderer): - Parent(desc), - m_renderer(renderer) - { - } - - ~BindingStateImpl() - { - if (m_renderer) - { - m_renderer->destroyBindingEntries(getDesc(), m_bindingDetails.Buffer()); - } - } - - GLRenderer* m_renderer; - List<BindingDetail> m_bindingDetails; - }; - - class ShaderProgramImpl : public ShaderProgram - { - public: - ShaderProgramImpl(GLRenderer* renderer, GLuint id): - m_renderer(renderer), - m_id(id) - { - } - ~ShaderProgramImpl() - { - if (m_renderer) - { - m_renderer->glDeleteProgram(m_id); - } - } - - GLuint m_id; - GLRenderer* m_renderer; - }; - - enum class GlPixelFormat - { - Unknown, - RGBA_Unorm_UInt8, - CountOf, - }; - - struct GlPixelFormatInfo - { - GLint internalFormat; // such as GL_RGBA8 - GLenum format; // such as GL_RGBA - GLenum formatType; // such as GL_UNSIGNED_BYTE - }; - - void destroyBindingEntries(const BindingState::Desc& desc, const BindingDetail* details); - - void bindBufferImpl(int target, UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* offsets); - void flushStateForDraw(); - GLuint loadShader(GLenum stage, char const* source); - void debugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message); - - /// Returns GlPixelFormat::Unknown if not an equivalent - static GlPixelFormat _getGlPixelFormat(Format format); - - static void APIENTRY staticDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam); - static VertexAttributeFormat getVertexAttributeFormat(Format format); - - static void compileTimeAsserts(); - - HDC m_hdc; - HGLRC m_glContext; - float m_clearColor[4] = { 0, 0, 0, 0 }; - - RefPtr<ShaderProgramImpl> m_boundShaderProgram; - RefPtr<InputLayoutImpl> m_boundInputLayout; - - GLenum m_boundPrimitiveTopology = GL_TRIANGLES; - GLuint m_boundVertexStreamBuffers[kMaxVertexStreams]; - UInt m_boundVertexStreamStrides[kMaxVertexStreams]; - UInt m_boundVertexStreamOffsets[kMaxVertexStreams]; - - Desc m_desc; - - // Declare a function pointer for each OpenGL - // extension function we need to load -#define DECLARE_GL_EXTENSION_FUNC(NAME, TYPE) TYPE NAME; - MAP_GL_EXTENSION_FUNCS(DECLARE_GL_EXTENSION_FUNC) -#undef DECLARE_GL_EXTENSION_FUNC - - static const GlPixelFormatInfo s_pixelFormatInfos[]; /// Maps GlPixelFormat to a format info -}; - -/* static */GLRenderer::GlPixelFormat GLRenderer::_getGlPixelFormat(Format format) -{ - switch (format) - { - case Format::RGBA_Unorm_UInt8: return GlPixelFormat::RGBA_Unorm_UInt8; - default: return GlPixelFormat::Unknown; - } -} - -/* static */ const GLRenderer::GlPixelFormatInfo GLRenderer::s_pixelFormatInfos[] = -{ - // internalType, format, formatType - { 0, 0, 0}, // GlPixelFormat::Unknown - { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE }, // GlPixelFormat::RGBA_Unorm_UInt8 -}; - -/* static */void GLRenderer::compileTimeAsserts() -{ - SLANG_COMPILE_TIME_ASSERT(SLANG_COUNT_OF(s_pixelFormatInfos) == int(GlPixelFormat::CountOf)); -} - -Renderer* createGLRenderer() -{ - return new GLRenderer(); -} - -void GLRenderer::debugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message) -{ - ::OutputDebugStringA("GL: "); - ::OutputDebugStringA(message); - ::OutputDebugStringA("\n"); - - switch (type) - { - case GL_DEBUG_TYPE_ERROR: - break; - default: - break; - } -} - -/* static */void APIENTRY GLRenderer::staticDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) -{ - ((GLRenderer*)userParam)->debugCallback(source, type, id, severity, length, message); -} - -/* static */GLRenderer::VertexAttributeFormat GLRenderer::getVertexAttributeFormat(Format format) -{ - switch (format) - { - default: assert(!"unexpected"); return VertexAttributeFormat(); - -#define CASE(NAME, COUNT, TYPE, NORMALIZED) \ - case Format::NAME: do { VertexAttributeFormat result = {COUNT, TYPE, NORMALIZED}; return result; } while (0) - - CASE(RGBA_Float32, 4, GL_FLOAT, GL_FALSE); - CASE(RGB_Float32, 3, GL_FLOAT, GL_FALSE); - CASE(RG_Float32, 2, GL_FLOAT, GL_FALSE); - CASE(R_Float32, 1, GL_FLOAT, GL_FALSE); -#undef CASE - } -} - -void GLRenderer::bindBufferImpl(int target, UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* offsets) -{ - for (UInt ii = 0; ii < slotCount; ++ii) - { - UInt slot = startSlot + ii; - - BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(buffers[ii]); - GLuint bufferID = buffer ? buffer->m_handle : 0; - - assert(!offsets || !offsets[ii]); - - glBindBufferBase(target, (GLuint)slot, bufferID); - } -} - -void GLRenderer::flushStateForDraw() -{ - auto layout = m_boundInputLayout.Ptr(); - auto attrCount = layout->m_attributeCount; - for (UInt ii = 0; ii < attrCount; ++ii) - { - auto& attr = layout->m_attributes[ii]; - - auto streamIndex = attr.streamIndex; - - glBindBuffer(GL_ARRAY_BUFFER, m_boundVertexStreamBuffers[streamIndex]); - - glVertexAttribPointer( - (GLuint)ii, - attr.format.componentCount, - attr.format.componentType, - attr.format.normalized, - (GLsizei)m_boundVertexStreamStrides[streamIndex], - (GLvoid*)(attr.offset + m_boundVertexStreamOffsets[streamIndex])); - - glEnableVertexAttribArray((GLuint)ii); - } - for (UInt ii = attrCount; ii < kMaxVertexStreams; ++ii) - { - glDisableVertexAttribArray((GLuint)ii); - } -} - -GLuint GLRenderer::loadShader(GLenum stage, const char* source) -{ - // GLSL is monumentally stupid. It officially requires the `#version` directive - // to be the first thing in the file, which wouldn't be so bad but the API - // doesn't provide a way to pass a `#define` into your shader other than by - // prepending it to the whole thing. - // - // We are going to solve this problem by doing some surgery on the source - // that was passed in. - - const char* sourceBegin = source; - const char* sourceEnd = source + strlen(source); - - // Look for a version directive in the user-provided source. - const char* versionBegin = strstr(source, "#version"); - const char* versionEnd = nullptr; - if (versionBegin) - { - // If we found a directive, then scan for the end-of-line - // after it, and use that to specify the slice. - versionEnd = strchr(versionBegin, '\n'); - if (!versionEnd) - { - versionEnd = sourceEnd; - } - else - { - versionEnd = versionEnd + 1; - } - } - else - { - // If we didn't find a directive, then treat it as being - // a zero-byte slice at the start of the string - versionBegin = sourceBegin; - versionEnd = sourceBegin; - } - - enum { kMaxSourceStringCount = 16 }; - const GLchar* sourceStrings[kMaxSourceStringCount]; - GLint sourceStringLengths[kMaxSourceStringCount]; - - int sourceStringCount = 0; - - const char* stagePrelude = "\n"; - switch (stage) - { -#define CASE(NAME) case GL_##NAME##_SHADER: stagePrelude = "#define __GLSL_" #NAME "__ 1\n"; break - - CASE(VERTEX); - CASE(TESS_CONTROL); - CASE(TESS_EVALUATION); - CASE(GEOMETRY); - CASE(FRAGMENT); - CASE(COMPUTE); - -#undef CASE - } - - const char* prelude = - "#define __GLSL__ 1\n" - ; - -#define ADD_SOURCE_STRING_SPAN(BEGIN, END) \ - sourceStrings[sourceStringCount] = BEGIN; \ - sourceStringLengths[sourceStringCount++] = GLint(END - BEGIN) \ - /* end */ - -#define ADD_SOURCE_STRING(BEGIN) \ - sourceStrings[sourceStringCount] = BEGIN; \ - sourceStringLengths[sourceStringCount++] = GLint(strlen(BEGIN)) \ - /* end */ - - ADD_SOURCE_STRING_SPAN(versionBegin, versionEnd); - ADD_SOURCE_STRING(stagePrelude); - ADD_SOURCE_STRING(prelude); - ADD_SOURCE_STRING_SPAN(sourceBegin, versionBegin); - ADD_SOURCE_STRING_SPAN(versionEnd, sourceEnd); - - auto shaderID = glCreateShader(stage); - glShaderSource( - shaderID, - sourceStringCount, - &sourceStrings[0], - &sourceStringLengths[0]); - glCompileShader(shaderID); - - GLint success = GL_FALSE; - glGetShaderiv(shaderID, GL_COMPILE_STATUS, &success); - if (!success) - { - int maxSize = 0; - glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &maxSize); - - auto infoBuffer = (char*)malloc(maxSize); - - int infoSize = 0; - glGetShaderInfoLog(shaderID, maxSize, &infoSize, infoBuffer); - if (infoSize > 0) - { - fprintf(stderr, "%s", infoBuffer); - ::OutputDebugStringA(infoBuffer); - } - - glDeleteShader(shaderID); - return 0; - } - - return shaderID; -} - -void GLRenderer::destroyBindingEntries(const BindingState::Desc& desc, const BindingDetail* details) -{ - const auto& bindings = desc.m_bindings; - const int numBindings = int(bindings.Count()); - for (int i = 0; i < numBindings; ++i) - { - const auto& binding = bindings[i]; - const auto& detail = details[i]; - - if (binding.bindingType == BindingType::Sampler && detail.m_samplerHandle != 0) - { - glDeleteSamplers(1, &detail.m_samplerHandle); - } - } -} - -// !!!!!!!!!!!!!!!!!!!!!!!!!!!! Renderer interface !!!!!!!!!!!!!!!!!!!!!!!!!! - -SlangResult GLRenderer::initialize(const Desc& desc, void* inWindowHandle) -{ - auto windowHandle = (HWND)inWindowHandle; - m_desc = desc; - - m_hdc = ::GetDC(windowHandle); - - PIXELFORMATDESCRIPTOR pixelFormatDesc = { sizeof(PIXELFORMATDESCRIPTOR) }; - pixelFormatDesc.nVersion = 1; - pixelFormatDesc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - pixelFormatDesc.iPixelType = PFD_TYPE_RGBA; - pixelFormatDesc.cColorBits = 32; - pixelFormatDesc.cDepthBits = 24; - pixelFormatDesc.cStencilBits = 8; - pixelFormatDesc.iLayerType = PFD_MAIN_PLANE; - - int pixelFormatIndex = ChoosePixelFormat(m_hdc, &pixelFormatDesc); - SetPixelFormat(m_hdc, pixelFormatIndex, &pixelFormatDesc); - - m_glContext = wglCreateContext(m_hdc); - wglMakeCurrent(m_hdc, m_glContext); - - auto renderer = glGetString(GL_RENDERER); - auto extensions = glGetString(GL_EXTENSIONS); - - // Load each of our extension functions by name - -#define LOAD_GL_EXTENSION_FUNC(NAME, TYPE) NAME = (TYPE) wglGetProcAddress(#NAME); - MAP_GL_EXTENSION_FUNCS(LOAD_GL_EXTENSION_FUNC) -#undef LOAD_GL_EXTENSION_FUNC - - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - - glViewport(0, 0, desc.width, desc.height); - - if (glDebugMessageCallback) - { - glEnable(GL_DEBUG_OUTPUT); - glDebugMessageCallback(staticDebugCallback, this); - } - - return SLANG_OK; -} - -void GLRenderer::setClearColor(const float color[4]) -{ - glClearColor(color[0], color[1], color[2], color[3]); -} - -void GLRenderer::clearFrame() -{ - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); -} - -void GLRenderer::presentFrame() -{ - glFlush(); - ::SwapBuffers(m_hdc); -} - -SlangResult GLRenderer::captureScreenSurface(Surface& surfaceOut) -{ - SLANG_RETURN_ON_FAIL(surfaceOut.allocate(m_desc.width, m_desc.height, Format::RGBA_Unorm_UInt8, 1, SurfaceAllocator::getMallocAllocator())); - glReadPixels(0, 0, m_desc.width, m_desc.height, GL_RGBA, GL_UNSIGNED_BYTE, surfaceOut.m_data); - surfaceOut.flipInplaceVertically(); - return SLANG_OK; -} - -TextureResource* GLRenderer::createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& descIn, const TextureResource::Data* initData) -{ - TextureResource::Desc srcDesc(descIn); - srcDesc.setDefaults(initialUsage); - - GlPixelFormat pixelFormat = _getGlPixelFormat(srcDesc.format); - if (pixelFormat == GlPixelFormat::Unknown) - { - return nullptr; - } - - const GlPixelFormatInfo& info = s_pixelFormatInfos[int(pixelFormat)]; - - const GLint internalFormat = info.internalFormat; - const GLenum format = info.format; - const GLenum formatType = info.formatType; - - RefPtr<TextureResourceImpl> texture(new TextureResourceImpl(initialUsage, srcDesc, this)); - - GLenum target = 0; - GLuint handle = 0; - glGenTextures(1, &handle); - - const int effectiveArraySize = srcDesc.calcEffectiveArraySize(); - - assert(initData); - assert(initData->numSubResources == srcDesc.numMipLevels * srcDesc.size.depth * effectiveArraySize); - - // Set on texture so will be freed if failure - texture->m_handle = handle; - const void*const*const data = initData->subResources; - - switch (srcDesc.type) - { - case Resource::Type::Texture1D: - { - if (srcDesc.arraySize > 0) - { - target = GL_TEXTURE_1D_ARRAY; - glBindTexture(target, handle); - - int slice = 0; - for (int i = 0; i < effectiveArraySize; i++) - { - for (int j = 0; j < srcDesc.numMipLevels; j++) - { - glTexImage2D(target, j, internalFormat, srcDesc.size.width, i, 0, format, formatType, data[slice++]); - } - } - } - else - { - target = GL_TEXTURE_1D; - glBindTexture(target, handle); - for (int i = 0; i < srcDesc.numMipLevels; i++) - { - glTexImage1D(target, i, internalFormat, srcDesc.size.width, 0, format, formatType, data[i]); - } - } - break; - } - case Resource::Type::TextureCube: - case Resource::Type::Texture2D: - { - if (srcDesc.arraySize > 0) - { - if (srcDesc.type == Resource::Type::TextureCube) - { - target = GL_TEXTURE_CUBE_MAP_ARRAY; - } - else - { - target = GL_TEXTURE_2D_ARRAY; - } - - glBindTexture(target, handle); - - int slice = 0; - for (int i = 0; i < effectiveArraySize; i++) - { - for (int j = 0; j < srcDesc.numMipLevels; j++) - { - glTexImage3D(target, j, internalFormat, srcDesc.size.width, srcDesc.size.height, slice, 0, format, formatType, data[slice++]); - } - } - } - else - { - if (srcDesc.type == Resource::Type::TextureCube) - { - target = GL_TEXTURE_CUBE_MAP; - glBindTexture(target, handle); - - int slice = 0; - for (int j = 0; j < 6; j++) - { - for (int i = 0; i < srcDesc.numMipLevels; i++) - { - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, i, internalFormat, srcDesc.size.width, srcDesc.size.height, 0, format, formatType, data[slice++]); - } - } - } - else - { - target = GL_TEXTURE_2D; - glBindTexture(target, handle); - for (int i = 0; i < srcDesc.numMipLevels; i++) - { - glTexImage2D(target, i, internalFormat, srcDesc.size.width, srcDesc.size.height, 0, format, formatType, data[i]); - } - } - } - break; - } - case Resource::Type::Texture3D: - { - target = GL_TEXTURE_3D; - glBindTexture(target, handle); - for (int i = 0; i < srcDesc.numMipLevels; i++) - { - glTexImage3D(target, i, internalFormat, srcDesc.size.width, srcDesc.size.height, srcDesc.size.depth, 0, format, formatType, data[i]); - } - break; - } - default: return nullptr; - } - - glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_REPEAT); - - // Assume regular sampling (might be superseded - if a combined sampler wanted) - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8.0f); - - texture->m_target = target; - - return texture.detach(); -} - -static GLenum _calcUsage(Resource::Usage usage) -{ - typedef Resource::Usage Usage; - switch (usage) - { - case Usage::ConstantBuffer: return GL_DYNAMIC_DRAW; - default: return GL_STATIC_READ; - } -} - -static GLenum _calcTarget(Resource::Usage usage) -{ - typedef Resource::Usage Usage; - switch (usage) - { - case Usage::ConstantBuffer: return GL_UNIFORM_BUFFER; - default: return GL_SHADER_STORAGE_BUFFER; - } -} - -BufferResource* GLRenderer::createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& descIn, const void* initData) -{ - BufferResource::Desc desc(descIn); - desc.setDefaults(initialUsage); - - const GLenum target = _calcTarget(initialUsage); - // TODO: should derive from desc... - const GLenum usage = _calcUsage(initialUsage); - - GLuint bufferID = 0; - glGenBuffers(1, &bufferID); - glBindBuffer(target, bufferID); - - glBufferData(target, descIn.sizeInBytes, initData, usage); - - return new BufferResourceImpl(initialUsage, desc, this, bufferID, target); -} - -InputLayout* GLRenderer::createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) -{ - InputLayoutImpl* inputLayout = new InputLayoutImpl; - - inputLayout->m_attributeCount = inputElementCount; - for (UInt ii = 0; ii < inputElementCount; ++ii) - { - auto& inputAttr = inputElements[ii]; - auto& glAttr = inputLayout->m_attributes[ii]; - - glAttr.streamIndex = 0; - glAttr.format = getVertexAttributeFormat(inputAttr.format); - glAttr.offset = (GLsizei)inputAttr.offset; - } - - return (InputLayout*)inputLayout; -} - -void* GLRenderer::map(BufferResource* bufferIn, MapFlavor flavor) -{ - BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(bufferIn); - - //GLenum target = GL_UNIFORM_BUFFER; - - GLuint access = 0; - switch (flavor) - { - case MapFlavor::WriteDiscard: - case MapFlavor::HostWrite: - access = GL_WRITE_ONLY; - break; - case MapFlavor::HostRead: - access = GL_READ_ONLY; - break; - } - - glBindBuffer(buffer->m_target, buffer->m_handle); - - return glMapBuffer(buffer->m_target, access); -} - -void GLRenderer::unmap(BufferResource* bufferIn) -{ - BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(bufferIn); - glUnmapBuffer(buffer->m_target); -} - -void GLRenderer::setInputLayout(InputLayout* inputLayout) -{ - m_boundInputLayout = static_cast<InputLayoutImpl*>(inputLayout); -} - -void GLRenderer::setPrimitiveTopology(PrimitiveTopology topology) -{ - GLenum glTopology = 0; - switch (topology) - { -#define CASE(NAME, VALUE) case PrimitiveTopology::NAME: glTopology = VALUE; break - - CASE(TriangleList, GL_TRIANGLES); - -#undef CASE - } - m_boundPrimitiveTopology = glTopology; -} - -void GLRenderer::setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) -{ - for (UInt ii = 0; ii < slotCount; ++ii) - { - UInt slot = startSlot + ii; - - BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(buffers[ii]); - GLuint bufferID = buffer ? buffer->m_handle : 0; - - m_boundVertexStreamBuffers[slot] = bufferID; - m_boundVertexStreamStrides[slot] = strides[ii]; - m_boundVertexStreamOffsets[slot] = offsets[ii]; - } -} - -void GLRenderer::setShaderProgram(ShaderProgram* programIn) -{ - ShaderProgramImpl* program = static_cast<ShaderProgramImpl*>(programIn); - m_boundShaderProgram = program; - GLuint programID = program ? program->m_id : 0; - glUseProgram(programID); -} - -void GLRenderer::draw(UInt vertexCount, UInt startVertex = 0) -{ - flushStateForDraw(); - - glDrawArrays(m_boundPrimitiveTopology, (GLint)startVertex, (GLsizei)vertexCount); -} - -void GLRenderer::dispatchCompute(int x, int y, int z) -{ - glDispatchCompute(x, y, z); -} - -BindingState* GLRenderer::createBindingState(const BindingState::Desc& bindingStateDesc) -{ - RefPtr<BindingStateImpl> bindingState(new BindingStateImpl(bindingStateDesc, this)); - - const auto& srcBindings = bindingStateDesc.m_bindings; - const int numBindings = int(srcBindings.Count()); - - auto& dstDetails = bindingState->m_bindingDetails; - dstDetails.SetSize(numBindings); - - for (int i = 0; i < numBindings; ++i) - { - auto& dstDetail = dstDetails[i]; - const auto& srcBinding = srcBindings[i]; - - - switch (srcBinding.bindingType) - { - case BindingType::Texture: - case BindingType::Buffer: - { - break; - } - case BindingType::CombinedTextureSampler: - { - assert(srcBinding.resource && srcBinding.resource->isTexture()); - TextureResourceImpl* texture = static_cast<TextureResourceImpl*>(srcBinding.resource.Ptr()); - const BindingState::SamplerDesc& samplerDesc = bindingStateDesc.m_samplerDescs[srcBinding.descIndex]; - - if (samplerDesc.isCompareSampler) - { - auto target = texture->m_target; - - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - glTexParameteri(target, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); - } - break; - } - case BindingType::Sampler: - { - const BindingState::SamplerDesc& samplerDesc = bindingStateDesc.m_samplerDescs[srcBinding.descIndex]; - - GLuint handle; - - glCreateSamplers(1, &handle); - glSamplerParameteri(handle, GL_TEXTURE_WRAP_S, GL_REPEAT); - glSamplerParameteri(handle, GL_TEXTURE_WRAP_T, GL_REPEAT); - glSamplerParameteri(handle, GL_TEXTURE_WRAP_R, GL_REPEAT); - - if (samplerDesc.isCompareSampler) - { - glSamplerParameteri(handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glSamplerParameteri(handle, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glSamplerParameteri(handle, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - glSamplerParameteri(handle, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); - } - else - { - glSamplerParameteri(handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glSamplerParameteri(handle, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glSamplerParameteri(handle, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8); - } - - dstDetail.m_samplerHandle = handle; - break; - } - } - } - - return bindingState.detach(); -} - -void GLRenderer::setBindingState(BindingState* stateIn) -{ - BindingStateImpl* state = static_cast<BindingStateImpl*>(stateIn); - - const auto& bindingDesc = state->getDesc(); - - const auto& details = state->m_bindingDetails; - const auto& bindings = bindingDesc.m_bindings; - const int numBindings = int(bindings.Count()); - - for (int i = 0; i < numBindings; ++i) - { - const auto& binding = bindings[i]; - const auto& detail = details[i]; - - switch (binding.bindingType) - { - case BindingType::Buffer: - { - const int bindingIndex = binding.registerRange.getSingleIndex(); - - BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(binding.resource.Ptr()); - glBindBufferBase(buffer->m_target, bindingIndex, buffer->m_handle); - break; - } - case BindingType::Sampler: - { - for (int index = binding.registerRange.index; index < binding.registerRange.index + binding.registerRange.size; ++index) - { - glBindSampler(index, detail.m_samplerHandle); - } - break; - } - case BindingType::Texture: - case BindingType::CombinedTextureSampler: - { - BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(binding.resource.Ptr()); - - const int bindingIndex = binding.registerRange.getSingleIndex(); - - glActiveTexture(GL_TEXTURE0 + bindingIndex); - glBindTexture(buffer->m_target, buffer->m_handle); - break; - } - } - } -} - -ShaderProgram* GLRenderer::createProgram(const ShaderProgram::Desc& desc) -{ - auto programID = glCreateProgram(); - if(desc.pipelineType == PipelineType::Compute ) - { - auto computeKernel = desc.findKernel(StageType::Compute); - auto computeShaderID = loadShader(GL_COMPUTE_SHADER, (char const*) computeKernel->codeBegin); - glAttachShader(programID, computeShaderID); - glLinkProgram(programID); - glDeleteShader(computeShaderID); - } - else - { - auto vertexKernel = desc.findKernel(StageType::Vertex); - auto fragmentKernel = desc.findKernel(StageType::Fragment); - - auto vertexShaderID = loadShader(GL_VERTEX_SHADER, (char const*) vertexKernel->codeBegin); - auto fragmentShaderID = loadShader(GL_FRAGMENT_SHADER, (char const*) fragmentKernel->codeBegin); - - glAttachShader(programID, vertexShaderID); - glAttachShader(programID, fragmentShaderID); - - - glLinkProgram(programID); - - glDeleteShader(vertexShaderID); - glDeleteShader(fragmentShaderID); - } - GLint success = GL_FALSE; - glGetProgramiv(programID, GL_LINK_STATUS, &success); - if (!success) - { - int maxSize = 0; - glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &maxSize); - - auto infoBuffer = (char*)::malloc(maxSize); - - int infoSize = 0; - glGetProgramInfoLog(programID, maxSize, &infoSize, infoBuffer); - if (infoSize > 0) - { - fprintf(stderr, "%s", infoBuffer); - OutputDebugStringA(infoBuffer); - } - - ::free(infoBuffer); - - glDeleteProgram(programID); - return nullptr; - } - - return new ShaderProgramImpl(this, programID); -} - - -} // renderer_test diff --git a/tools/render-test/render-gl.h b/tools/render-test/render-gl.h deleted file mode 100644 index 4e6de970c..000000000 --- a/tools/render-test/render-gl.h +++ /dev/null @@ -1,10 +0,0 @@ -// render-d3d11.h -#pragma once - -namespace renderer_test { - -class Renderer; - -Renderer* createGLRenderer(); - -} // renderer_test diff --git a/tools/render-test/render-test.vcxproj b/tools/render-test/render-test.vcxproj index 915d0d753..66ad9e7ed 100644 --- a/tools/render-test/render-test.vcxproj +++ b/tools/render-test/render-test.vcxproj @@ -99,7 +99,7 @@ <PrecompiledHeader>NotUsing</PrecompiledHeader> <WarningLevel>Level3</WarningLevel> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories>..\..;..\..\external;..\..\source;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>..\..;..\..\external;..\..\source;..\slang-graphics;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <DebugInformationFormat>EditAndContinue</DebugInformationFormat> <Optimization>Disabled</Optimization> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> @@ -117,7 +117,7 @@ <PrecompiledHeader>NotUsing</PrecompiledHeader> <WarningLevel>Level3</WarningLevel> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories>..\..;..\..\external;..\..\source;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>..\..;..\..\external;..\..\source;..\slang-graphics;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <DebugInformationFormat>EditAndContinue</DebugInformationFormat> <Optimization>Disabled</Optimization> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> @@ -135,7 +135,7 @@ <PrecompiledHeader>NotUsing</PrecompiledHeader> <WarningLevel>Level3</WarningLevel> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories>..\..;..\..\external;..\..\source;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>..\..;..\..\external;..\..\source;..\slang-graphics;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <Optimization>Full</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> @@ -157,7 +157,7 @@ <PrecompiledHeader>NotUsing</PrecompiledHeader> <WarningLevel>Level3</WarningLevel> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories>..\..;..\..\external;..\..\source;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>..\..;..\..\external;..\..\source;..\slang-graphics;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <Optimization>Full</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> @@ -175,50 +175,19 @@ </PostBuildEvent> </ItemDefinitionGroup> <ItemGroup> - <ClInclude Include="circular-resource-heap-d3d12.h" /> - <ClInclude Include="d3d-util.h" /> - <ClInclude Include="descriptor-heap-d3d12.h" /> <ClInclude Include="options.h" /> <ClInclude Include="png-serialize-util.h" /> - <ClInclude Include="render-d3d11.h" /> - <ClInclude Include="render-d3d12.h" /> - <ClInclude Include="render-gl.h" /> - <ClInclude Include="render-vk.h" /> - <ClInclude Include="render.h" /> - <ClInclude Include="resource-d3d12.h" /> <ClInclude Include="shader-input-layout.h" /> <ClInclude Include="shader-renderer-util.h" /> <ClInclude Include="slang-support.h" /> - <ClInclude Include="surface.h" /> - <ClInclude Include="vk-api.h" /> - <ClInclude Include="vk-device-queue.h" /> - <ClInclude Include="vk-module.h" /> - <ClInclude Include="vk-swap-chain.h" /> - <ClInclude Include="vk-util.h" /> - <ClInclude Include="window.h" /> </ItemGroup> <ItemGroup> - <ClCompile Include="circular-resource-heap-d3d12.cpp" /> - <ClCompile Include="d3d-util.cpp" /> - <ClCompile Include="descriptor-heap-d3d12.cpp" /> <ClCompile Include="main.cpp" /> <ClCompile Include="options.cpp" /> <ClCompile Include="png-serialize-util.cpp" /> - <ClCompile Include="render-d3d11.cpp" /> - <ClCompile Include="render-d3d12.cpp" /> - <ClCompile Include="render-gl.cpp" /> - <ClCompile Include="render-vk.cpp" /> - <ClCompile Include="render.cpp" /> - <ClCompile Include="resource-d3d12.cpp" /> <ClCompile Include="shader-input-layout.cpp" /> <ClCompile Include="shader-renderer-util.cpp" /> <ClCompile Include="slang-support.cpp" /> - <ClCompile Include="surface.cpp" /> - <ClCompile Include="vk-api.cpp" /> - <ClCompile Include="vk-device-queue.cpp" /> - <ClCompile Include="vk-module.cpp" /> - <ClCompile Include="vk-swap-chain.cpp" /> - <ClCompile Include="vk-util.cpp" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\..\source\core\core.vcxproj"> @@ -227,6 +196,9 @@ <ProjectReference Include="..\..\source\slang\slang.vcxproj"> <Project>{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}</Project> </ProjectReference> + <ProjectReference Include="..\slang-graphics\slang-graphics.vcxproj"> + <Project>{222F7498-B40C-4F3F-A704-DDEB91A4484A}</Project> + </ProjectReference> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> diff --git a/tools/render-test/render-test.vcxproj.filters b/tools/render-test/render-test.vcxproj.filters index b2f48a397..ff3d52a7e 100644 --- a/tools/render-test/render-test.vcxproj.filters +++ b/tools/render-test/render-test.vcxproj.filters @@ -9,39 +9,12 @@ </Filter> </ItemGroup> <ItemGroup> - <ClInclude Include="circular-resource-heap-d3d12.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="d3d-util.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="descriptor-heap-d3d12.h"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="options.h"> <Filter>Header Files</Filter> </ClInclude> <ClInclude Include="png-serialize-util.h"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="render-d3d11.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="render-d3d12.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="render-gl.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="render-vk.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="render.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="resource-d3d12.h"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="shader-input-layout.h"> <Filter>Header Files</Filter> </ClInclude> @@ -51,38 +24,8 @@ <ClInclude Include="slang-support.h"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="surface.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="vk-api.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="vk-device-queue.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="vk-module.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="vk-swap-chain.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="vk-util.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="window.h"> - <Filter>Header Files</Filter> - </ClInclude> </ItemGroup> <ItemGroup> - <ClCompile Include="circular-resource-heap-d3d12.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="d3d-util.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="descriptor-heap-d3d12.cpp"> - <Filter>Source Files</Filter> - </ClCompile> <ClCompile Include="main.cpp"> <Filter>Source Files</Filter> </ClCompile> @@ -92,24 +35,6 @@ <ClCompile Include="png-serialize-util.cpp"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="render-d3d11.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="render-d3d12.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="render-gl.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="render-vk.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="render.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="resource-d3d12.cpp"> - <Filter>Source Files</Filter> - </ClCompile> <ClCompile Include="shader-input-layout.cpp"> <Filter>Source Files</Filter> </ClCompile> @@ -119,23 +44,5 @@ <ClCompile Include="slang-support.cpp"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="surface.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="vk-api.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="vk-device-queue.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="vk-module.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="vk-swap-chain.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="vk-util.cpp"> - <Filter>Source Files</Filter> - </ClCompile> </ItemGroup> </Project>
\ No newline at end of file diff --git a/tools/render-test/render-vk.cpp b/tools/render-test/render-vk.cpp deleted file mode 100644 index bbdc2f08c..000000000 --- a/tools/render-test/render-vk.cpp +++ /dev/null @@ -1,2019 +0,0 @@ -// render-vk.cpp -#include "render-vk.h" - -#include "options.h" -#include "render.h" - -#include "../../source/core/smart-pointer.h" - -#include "vk-api.h" -#include "vk-util.h" -#include "vk-device-queue.h" -#include "vk-swap-chain.h" - -#include "surface.h" - -// Vulkan has a different coordinate system to ogl -// http://anki3d.org/vulkan-coordinate-system/ - -#define ENABLE_VALIDATION_LAYER 1 - -#ifdef _MSC_VER -# include <stddef.h> -# pragma warning(disable: 4996) -# if (_MSC_VER < 1900) -# define snprintf sprintf_s -# endif -#endif - -namespace renderer_test { -using namespace Slang; - -class VKRenderer : public Renderer -{ -public: - enum { kMaxRenderTargets = 8, kMaxAttachments = kMaxRenderTargets + 1 }; - - // Renderer implementation - virtual SlangResult initialize(const Desc& desc, void* inWindowHandle) override; - virtual void setClearColor(const float color[4]) override; - virtual void clearFrame() override; - virtual void presentFrame() override; - virtual TextureResource* createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData) override; - virtual BufferResource* createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& bufferDesc, const void* initData) override; - virtual SlangResult captureScreenSurface(Surface& surface) override; - virtual InputLayout* createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) override; - virtual BindingState* createBindingState(const BindingState::Desc& bindingStateDesc) override; - virtual ShaderProgram* createProgram(const ShaderProgram::Desc& desc) override; - virtual void* map(BufferResource* buffer, MapFlavor flavor) override; - virtual void unmap(BufferResource* buffer) override; - virtual void setInputLayout(InputLayout* inputLayout) override; - virtual void setPrimitiveTopology(PrimitiveTopology topology) override; - virtual void setBindingState(BindingState* state); - virtual void setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) override; - virtual void setShaderProgram(ShaderProgram* inProgram) override; - virtual void draw(UInt vertexCount, UInt startVertex) override; - virtual void dispatchCompute(int x, int y, int z) override; - virtual void submitGpuWork() override; - virtual void waitForGpu() override; - virtual RendererType getRendererType() const override { return RendererType::Vulkan; } - - /// Dtor - ~VKRenderer(); - - protected: - - class Buffer - { - public: - /// Initialize a buffer with specified size, and memory props - Result init(const VulkanApi& api, size_t bufferSize, VkBufferUsageFlags usage, VkMemoryPropertyFlags reqMemoryProperties); - - /// Returns true if has been initialized - bool isInitialized() const { return m_api != nullptr; } - - // Default Ctor - Buffer(): - m_api(nullptr) - {} - - /// Dtor - ~Buffer() - { - if (m_api) - { - m_api->vkDestroyBuffer(m_api->m_device, m_buffer, nullptr); - m_api->vkFreeMemory(m_api->m_device, m_memory, nullptr); - } - } - - VkBuffer m_buffer; - VkDeviceMemory m_memory; - const VulkanApi* m_api; - }; - - class InputLayoutImpl : public InputLayout - { - public: - List<VkVertexInputAttributeDescription> m_vertexDescs; - int m_vertexSize; - }; - - class BufferResourceImpl: public BufferResource - { - public: - typedef BufferResource Parent; - - BufferResourceImpl(Resource::Usage initialUsage, const BufferResource::Desc& desc, VKRenderer* renderer): - Parent(desc), - m_renderer(renderer), - m_initialUsage(initialUsage) - { - assert(renderer); - } - - Resource::Usage m_initialUsage; - VKRenderer* m_renderer; - Buffer m_buffer; - Buffer m_uploadBuffer; - List<uint8_t> m_readBuffer; ///< Stores the contents when a map read is performed - - MapFlavor m_mapFlavor = MapFlavor::Unknown; ///< If resource is mapped, records what kind of mapping else Unknown (if not mapped) - }; - - class TextureResourceImpl : public TextureResource - { - public: - typedef TextureResource Parent; - - TextureResourceImpl(const Desc& desc, Usage initialUsage, const VulkanApi* api) : - Parent(desc), - m_initialUsage(initialUsage), - m_api(api) - { - } - ~TextureResourceImpl() - { - if (m_api) - { - if (m_imageMemory != VK_NULL_HANDLE) - { - m_api->vkFreeMemory(m_api->m_device, m_imageMemory, nullptr); - } - if (m_image != VK_NULL_HANDLE) - { - m_api->vkDestroyImage(m_api->m_device, m_image, nullptr); - } - } - } - - Usage m_initialUsage; - - VkImage m_image = VK_NULL_HANDLE; - VkDeviceMemory m_imageMemory = VK_NULL_HANDLE; - - const VulkanApi* m_api; - }; - - class ShaderProgramImpl: public ShaderProgram - { - public: - - ShaderProgramImpl(PipelineType pipelineType): - m_pipelineType(pipelineType) - {} - - PipelineType m_pipelineType; - - VkPipelineShaderStageCreateInfo m_compute; - VkPipelineShaderStageCreateInfo m_vertex; - VkPipelineShaderStageCreateInfo m_fragment; - - List<char> m_buffers[2]; //< To keep storage of code in scope - }; - - struct BindingDetail - { - VkImageView m_srv = VK_NULL_HANDLE; - VkBufferView m_uav = VK_NULL_HANDLE; - VkSampler m_sampler = VK_NULL_HANDLE; - }; - - class BindingStateImpl: public BindingState - { - public: - typedef BindingState Parent; - - BindingStateImpl(const Desc& desc, const VulkanApi* api): - Parent(desc), - m_api(api) - { - } - ~BindingStateImpl() - { - for (int i = 0; i < int(m_bindingDetails.Count()); ++i) - { - BindingDetail& detail = m_bindingDetails[i]; - if (detail.m_sampler != VK_NULL_HANDLE) - { - m_api->vkDestroySampler(m_api->m_device, detail.m_sampler, nullptr); - } - if (detail.m_srv != VK_NULL_HANDLE) - { - m_api->vkDestroyImageView(m_api->m_device, detail.m_srv, nullptr); - } - if (detail.m_uav != VK_NULL_HANDLE) - { - m_api->vkDestroyBufferView(m_api->m_device, detail.m_uav, nullptr); - } - } - } - - const VulkanApi* m_api; - List<BindingDetail> m_bindingDetails; - }; - - struct BoundVertexBuffer - { - RefPtr<BufferResourceImpl> m_buffer; - int m_stride; - int m_offset; - }; - - class Pipeline : public RefObject - { - public: - Pipeline(const VulkanApi& api): - m_api(&api) - { - } - ~Pipeline() - { - if (m_pipeline != VK_NULL_HANDLE) - { - m_api->vkDestroyPipeline(m_api->m_device, m_pipeline, nullptr); - } - if (m_descriptorPool != VK_NULL_HANDLE) - { - m_api->vkDestroyDescriptorPool(m_api->m_device, m_descriptorPool, nullptr); - } - if (m_pipelineLayout != VK_NULL_HANDLE) - { - m_api->vkDestroyPipelineLayout(m_api->m_device, m_pipelineLayout, nullptr); - } - if(m_descriptorSetLayout != VK_NULL_HANDLE) - { - m_api->vkDestroyDescriptorSetLayout(m_api->m_device, m_descriptorSetLayout, nullptr); - } - } - - const VulkanApi* m_api; - - VkPrimitiveTopology m_primitiveTopology; - RefPtr<BindingStateImpl> m_bindingState; - RefPtr<InputLayoutImpl> m_inputLayout; - RefPtr<ShaderProgramImpl> m_shaderProgram; - - VkDescriptorSetLayout m_descriptorSetLayout = VK_NULL_HANDLE; - VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE; - VkDescriptorPool m_descriptorPool = VK_NULL_HANDLE; - VkDescriptorSet m_descriptorSet = VK_NULL_HANDLE; - VkPipeline m_pipeline = VK_NULL_HANDLE; - }; - - VkBool32 handleDebugMessage(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, - size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg); - - VkPipelineShaderStageCreateInfo compileEntryPoint( - ShaderProgram::KernelDesc const& kernelDesc, - VkShaderStageFlagBits stage, - List<char>& bufferOut); - - static VKAPI_ATTR VkBool32 VKAPI_CALL debugMessageCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, - size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg, void* pUserData); - - /// Returns true if m_currentPipeline matches the current configuration - Pipeline* _getPipeline(); - bool _isEqual(const Pipeline& pipeline) const; - Slang::Result _createPipeline(RefPtr<Pipeline>& pipelineOut); - void _beginRender(); - void _endRender(); - - Slang::Result _beginPass(); - void _endPass(); - void _transitionImageLayout(VkImage image, VkFormat format, const TextureResource::Desc& desc, VkImageLayout oldLayout, VkImageLayout newLayout); - - VkDebugReportCallbackEXT m_debugReportCallback; - - RefPtr<InputLayoutImpl> m_currentInputLayout; - RefPtr<BindingStateImpl> m_currentBindingState; - RefPtr<ShaderProgramImpl> m_currentProgram; - - List<RefPtr<Pipeline> > m_pipelineCache; - Pipeline* m_currentPipeline = nullptr; - - List<BoundVertexBuffer> m_boundVertexBuffers; - - VkPrimitiveTopology m_primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - - VkDevice m_device = VK_NULL_HANDLE; - - VulkanModule m_module; - VulkanApi m_api; - - VulkanDeviceQueue m_deviceQueue; - VulkanSwapChain m_swapChain; - - VkRenderPass m_renderPass = VK_NULL_HANDLE; - - int m_swapChainImageIndex = -1; - - float m_clearColor[4] = { 0, 0, 0, 0 }; - - Desc m_desc; -}; - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! VkRenderer::Buffer !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ - -Result VKRenderer::Buffer::init(const VulkanApi& api, size_t bufferSize, VkBufferUsageFlags usage, VkMemoryPropertyFlags reqMemoryProperties) -{ - assert(!isInitialized()); - - m_api = &api; - m_memory = VK_NULL_HANDLE; - m_buffer = VK_NULL_HANDLE; - - VkBufferCreateInfo bufferCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; - bufferCreateInfo.size = bufferSize; - bufferCreateInfo.usage = usage; - - SLANG_VK_CHECK(api.vkCreateBuffer(api.m_device, &bufferCreateInfo, nullptr, &m_buffer)); - - VkMemoryRequirements memoryReqs = {}; - api.vkGetBufferMemoryRequirements(api.m_device, m_buffer, &memoryReqs); - - int memoryTypeIndex = api.findMemoryTypeIndex(memoryReqs.memoryTypeBits, reqMemoryProperties); - assert(memoryTypeIndex >= 0); - - VkMemoryPropertyFlags actualMemoryProperites = api.m_deviceMemoryProperties.memoryTypes[memoryTypeIndex].propertyFlags; - - VkMemoryAllocateInfo allocateInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; - allocateInfo.allocationSize = memoryReqs.size; - allocateInfo.memoryTypeIndex = memoryTypeIndex; - - SLANG_VK_CHECK(api.vkAllocateMemory(api.m_device, &allocateInfo, nullptr, &m_memory)); - SLANG_VK_CHECK(api.vkBindBufferMemory(api.m_device, m_buffer, m_memory, 0)); - - return SLANG_OK; -} - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! VkRenderer !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ - -bool VKRenderer::_isEqual(const Pipeline& pipeline) const -{ - return - pipeline.m_bindingState == m_currentBindingState && - pipeline.m_primitiveTopology == m_primitiveTopology && - pipeline.m_inputLayout == m_currentInputLayout && - pipeline.m_shaderProgram == m_currentProgram; -} - -VKRenderer::Pipeline* VKRenderer::_getPipeline() -{ - if (m_currentPipeline && _isEqual(*m_currentPipeline)) - { - return m_currentPipeline; - } - - // Look for a match in the cache - for (int i = 0; i < int(m_pipelineCache.Count()); ++i) - { - Pipeline* pipeline = m_pipelineCache[i]; - if (_isEqual(*pipeline)) - { - m_currentPipeline = pipeline; - return pipeline; - } - } - - RefPtr<Pipeline> pipeline; - SLANG_RETURN_NULL_ON_FAIL(_createPipeline(pipeline)); - m_pipelineCache.Add(pipeline); - m_currentPipeline = pipeline; - return pipeline; -} - -Slang::Result VKRenderer::_createPipeline(RefPtr<Pipeline>& pipelineOut) -{ - RefPtr<Pipeline> pipeline(new Pipeline(m_api)); - - // Initialize the state - pipeline->m_primitiveTopology = m_primitiveTopology; - pipeline->m_bindingState = m_currentBindingState; - pipeline->m_shaderProgram = m_currentProgram; - pipeline->m_inputLayout = m_currentInputLayout; - - // Must be equal at this point if all the items are correctly set in pipeline - assert(_isEqual(*pipeline)); - - // First create a pipeline layout based on what is bound - - const auto& srcDetails = m_currentBindingState->m_bindingDetails; - const auto& srcBindings = m_currentBindingState->getDesc().m_bindings; - - const int numBindings = int(srcBindings.Count()); - - int numBuffers = 0; - int numImages = 0; - - int numDescriptorByType[VK_DESCRIPTOR_TYPE_RANGE_SIZE] = { 0, }; - - Slang::List<VkDescriptorSetLayoutBinding> dstBindings; - for (int i = 0; i < numBindings; ++i) - { - const auto& srcDetail = srcDetails[i]; - const auto& srcBinding = srcBindings[i]; - - VkDescriptorSetLayoutBinding dstBinding = {}; - - dstBinding.descriptorCount = 1; - - switch (srcBinding.bindingType) - { - case BindingType::Buffer: - { - BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(srcBinding.resource.Ptr()); - const BufferResource::Desc& bufferResourceDesc = bufferResource->getDesc(); - - if (bufferResourceDesc.bindFlags & Resource::BindFlag::UnorderedAccess) - { - dstBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - dstBinding.stageFlags = VK_SHADER_STAGE_ALL; - dstBindings.Add(dstBinding); - - numDescriptorByType[dstBinding.descriptorType] ++; - numBuffers++; - } - else if (bufferResourceDesc.bindFlags & Resource::BindFlag::ConstantBuffer) - { - dstBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - dstBinding.stageFlags = VK_SHADER_STAGE_ALL; - dstBindings.Add(dstBinding); - - numDescriptorByType[dstBinding.descriptorType] ++; - numBuffers++; - } - break; - } - case BindingType::Texture: - { - dstBinding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - dstBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - dstBindings.Add(dstBinding); - - numDescriptorByType[dstBinding.descriptorType] ++; - numImages++; - break; - } - case BindingType::Sampler: - { - dstBinding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; - dstBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - dstBindings.Add(dstBinding); - - numDescriptorByType[dstBinding.descriptorType] ++; - numImages++; - break; - } - - case BindingType::CombinedTextureSampler: - { - dstBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - dstBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - dstBindings.Add(dstBinding); - - numDescriptorByType[dstBinding.descriptorType] ++; - numImages++; - break; - } - default: - { - assert(!"Unhandled type"); - return SLANG_FAIL; - } - } - } - - // Create a descriptor pool for allocating sets - { -#if 0 - VkDescriptorPoolSize poolSizes[] = - { - { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 128 }, - { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 128 }, - { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 128 }, - }; -#endif - - List<VkDescriptorPoolSize> poolSizes; - for (int i = 0; i < SLANG_COUNT_OF(numDescriptorByType); ++i) - { - int numDescriptors = numDescriptorByType[i]; - if (numDescriptors > 0) - { - const VkDescriptorPoolSize poolSize = { VkDescriptorType(i), uint32_t(numDescriptors) }; - poolSizes.Add(poolSize); - } - } - VkDescriptorPoolCreateInfo descriptorPoolInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; - - descriptorPoolInfo.maxSets = 128; // TODO: actually pick a size. - descriptorPoolInfo.poolSizeCount = uint32_t(poolSizes.Count()); - descriptorPoolInfo.pPoolSizes = poolSizes.Buffer(); - - SLANG_VK_CHECK(m_api.vkCreateDescriptorPool(m_device, &descriptorPoolInfo, nullptr, &pipeline->m_descriptorPool)); - } - - // Create the layout - { - VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; - descriptorSetLayoutInfo.bindingCount = uint32_t(dstBindings.Count()); - descriptorSetLayoutInfo.pBindings = dstBindings.Buffer(); - - SLANG_VK_CHECK(m_api.vkCreateDescriptorSetLayout(m_device, &descriptorSetLayoutInfo, nullptr, &pipeline->m_descriptorSetLayout)); - } - - // Create a descriptor set based on our layout - { - VkDescriptorSetAllocateInfo descriptorSetAllocInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; - descriptorSetAllocInfo.descriptorPool = pipeline->m_descriptorPool; - descriptorSetAllocInfo.descriptorSetCount = 1; - descriptorSetAllocInfo.pSetLayouts = &pipeline->m_descriptorSetLayout; - - SLANG_VK_CHECK(m_api.vkAllocateDescriptorSets(m_device, &descriptorSetAllocInfo, &pipeline->m_descriptorSet)); - } - - // Fill in the descriptor set, using our binding information - - List<VkDescriptorImageInfo> imageInfos; - List<VkDescriptorBufferInfo> bufferInfos; - List<VkWriteDescriptorSet> writes; - - // Make sure there is enough space... - imageInfos.Reserve(numImages); - bufferInfos.Reserve(numBuffers); - - int elementIndex = 0; - - for (int i = 0; i < numBindings; ++i) - { - const auto& srcDetail = srcDetails[i]; - const auto& srcBinding = srcBindings[i]; - - const int bindingIndex = srcBinding.registerRange.getSingleIndex(); - - VkWriteDescriptorSet writeInfo = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; - writeInfo.descriptorCount = 1; - writeInfo.dstSet = pipeline->m_descriptorSet; - writeInfo.dstBinding = bindingIndex; - writeInfo.dstArrayElement = 0; - - switch (srcBinding.bindingType) - { - case BindingType::Buffer: - { - assert(srcBinding.resource && srcBinding.resource->isBuffer()); - BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(srcBinding.resource.Ptr()); - const BufferResource::Desc& bufferResourceDesc = bufferResource->getDesc(); - - { - VkDescriptorBufferInfo bufferInfo; - bufferInfo.buffer = bufferResource->m_buffer.m_buffer; - bufferInfo.offset = 0; - bufferInfo.range = bufferResourceDesc.sizeInBytes; - - bufferInfos.Add(bufferInfo); - } - - writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - if (bufferResource->m_initialUsage == Resource::Usage::UnorderedAccess) - { - writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - } - else if (bufferResource->m_initialUsage == Resource::Usage::ConstantBuffer) - { - writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - } - - writeInfo.pBufferInfo = &bufferInfos.Last(); - - writes.Add(writeInfo); - break; - } - case BindingType::Texture: - { - assert(srcBinding.resource && srcBinding.resource->isTexture()); - - TextureResourceImpl* textureResource = static_cast<TextureResourceImpl*>(srcBinding.resource.Ptr()); - const TextureResource::Desc& textureResourceDesc = textureResource->getDesc(); - - { - VkDescriptorImageInfo imageInfo = {}; - imageInfo.imageView = srcDetail.m_srv; - imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imageInfos.Add(imageInfo); - } - - writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - writeInfo.pImageInfo = &imageInfos.Last(); - - writes.Add(writeInfo); - break; - } - case BindingType::Sampler: - { - { - VkDescriptorImageInfo imageInfo = {}; - imageInfo.sampler = srcDetail.m_sampler; - //imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imageInfos.Add(imageInfo); - } - - writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; - writeInfo.pImageInfo = &imageInfos.Last(); - - writes.Add(writeInfo); - break; - } - default: - { - assert(!"Binding not currently handled"); - return SLANG_FAIL; - } - } - } - - assert(imageInfos.Count() == numImages); - assert(bufferInfos.Count() == numBuffers); - - // Write into the descriptor set - { - m_api.vkUpdateDescriptorSets(m_device, uint32_t(writes.Count()), writes.Buffer(), 0, nullptr); - } - - // Create a pipeline layout based on our descriptor set layout(s) - - VkPipelineLayoutCreateInfo pipelineLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; - pipelineLayoutInfo.setLayoutCount = 1; - pipelineLayoutInfo.pSetLayouts = &pipeline->m_descriptorSetLayout; - - SLANG_VK_CHECK(m_api.vkCreatePipelineLayout(m_device, &pipelineLayoutInfo, nullptr, &pipeline->m_pipelineLayout)); - - VkPipelineCache pipelineCache = VK_NULL_HANDLE; - - if (m_currentProgram->m_pipelineType == PipelineType::Compute) - { - // Then create a pipeline to use that layout - - VkComputePipelineCreateInfo computePipelineInfo = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO }; - computePipelineInfo.stage = m_currentProgram->m_compute; - computePipelineInfo.layout = pipeline->m_pipelineLayout; - - SLANG_VK_CHECK(m_api.vkCreateComputePipelines(m_device, pipelineCache, 1, &computePipelineInfo, nullptr, &pipeline->m_pipeline)); - } - else if (m_currentProgram->m_pipelineType == PipelineType::Graphics) - { - // Create the graphics pipeline - - const int width = m_swapChain.getWidth(); - const int height = m_swapChain.getHeight(); - - VkPipelineShaderStageCreateInfo shaderStages[] = { m_currentProgram->m_vertex, m_currentProgram->m_fragment }; - - // VertexBuffer/s - // Currently only handles one - - VkPipelineVertexInputStateCreateInfo vertexInputInfo = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO }; - vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertexInputInfo.vertexBindingDescriptionCount = 0; - vertexInputInfo.vertexAttributeDescriptionCount = 0; - - VkVertexInputBindingDescription vertexInputBindingDescription; - - if (m_currentInputLayout) - { - vertexInputBindingDescription.binding = 0; - vertexInputBindingDescription.stride = m_currentInputLayout->m_vertexSize; - vertexInputBindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - - const auto& srcAttributeDescs = m_currentInputLayout->m_vertexDescs; - - vertexInputInfo.vertexBindingDescriptionCount = 1; - vertexInputInfo.pVertexBindingDescriptions = &vertexInputBindingDescription; - - vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(srcAttributeDescs.Count()); - vertexInputInfo.pVertexAttributeDescriptions = srcAttributeDescs.Buffer(); - } - - // - - VkPipelineInputAssemblyStateCreateInfo inputAssembly = {}; - inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - inputAssembly.primitiveRestartEnable = VK_FALSE; - - VkViewport viewport = {}; - viewport.x = 0.0f; - viewport.y = 0.0f; - viewport.width = (float)width; - viewport.height = (float)height; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - - VkRect2D scissor = {}; - scissor.offset = { 0, 0 }; - scissor.extent = { uint32_t(width), uint32_t(height) }; - - VkPipelineViewportStateCreateInfo viewportState = {}; - viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewportState.viewportCount = 1; - viewportState.pViewports = &viewport; - viewportState.scissorCount = 1; - viewportState.pScissors = &scissor; - - VkPipelineRasterizationStateCreateInfo rasterizer = {}; - rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterizer.depthClampEnable = VK_FALSE; - rasterizer.rasterizerDiscardEnable = VK_FALSE; - rasterizer.polygonMode = VK_POLYGON_MODE_FILL; - rasterizer.lineWidth = 1.0f; - rasterizer.cullMode = VK_CULL_MODE_NONE; - rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; - rasterizer.depthBiasEnable = VK_FALSE; - - VkPipelineMultisampleStateCreateInfo multisampling = {}; - multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisampling.sampleShadingEnable = VK_FALSE; - multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - - VkPipelineColorBlendAttachmentState colorBlendAttachment = {}; - colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - colorBlendAttachment.blendEnable = VK_FALSE; - - VkPipelineColorBlendStateCreateInfo colorBlending = {}; - colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - colorBlending.logicOpEnable = VK_FALSE; - colorBlending.logicOp = VK_LOGIC_OP_COPY; - colorBlending.attachmentCount = 1; - colorBlending.pAttachments = &colorBlendAttachment; - colorBlending.blendConstants[0] = 0.0f; - colorBlending.blendConstants[1] = 0.0f; - colorBlending.blendConstants[2] = 0.0f; - colorBlending.blendConstants[3] = 0.0f; - - VkGraphicsPipelineCreateInfo pipelineInfo = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO }; - - pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipelineInfo.stageCount = 2; - pipelineInfo.pStages = shaderStages; - pipelineInfo.pVertexInputState = &vertexInputInfo; - pipelineInfo.pInputAssemblyState = &inputAssembly; - pipelineInfo.pViewportState = &viewportState; - pipelineInfo.pRasterizationState = &rasterizer; - pipelineInfo.pMultisampleState = &multisampling; - pipelineInfo.pColorBlendState = &colorBlending; - pipelineInfo.layout = pipeline->m_pipelineLayout; - pipelineInfo.renderPass = m_renderPass; - pipelineInfo.subpass = 0; - pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; - - SLANG_VK_CHECK(m_api.vkCreateGraphicsPipelines(m_device, pipelineCache, 1, &pipelineInfo, nullptr, &pipeline->m_pipeline)); - } - else - { - assert(!"Unhandled program type"); - return SLANG_FAIL; - } - - pipelineOut = pipeline; - return SLANG_OK; -} - -Result VKRenderer::_beginPass() -{ - if (m_swapChainImageIndex < 0) - { - return SLANG_FAIL; - } - - const int numRenderTargets = 1; - - const VulkanSwapChain::Image& image = m_swapChain.getImages()[m_swapChainImageIndex]; - - int numAttachments = 0; - - // Start render pass - VkClearValue clearValues[kMaxAttachments]; - clearValues[numAttachments++] = VkClearValue{ m_clearColor[0], m_clearColor[1], m_clearColor[2], m_clearColor[3] }; - - bool hasDepthBuffer = false; - if (hasDepthBuffer) - { - VkClearValue& clearValue = clearValues[numAttachments++]; - - clearValue.depthStencil.depth = 1.0f; - clearValue.depthStencil.stencil = 0; - } - - const int width = m_swapChain.getWidth(); - const int height = m_swapChain.getHeight(); - - VkCommandBuffer cmdBuffer = m_deviceQueue.getCommandBuffer(); - - VkRenderPassBeginInfo renderPassBegin = {}; - renderPassBegin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassBegin.renderPass = m_renderPass; - renderPassBegin.framebuffer = image.m_frameBuffer; - renderPassBegin.renderArea.offset.x = 0; - renderPassBegin.renderArea.offset.y = 0; - renderPassBegin.renderArea.extent.width = width; - renderPassBegin.renderArea.extent.height = height; - renderPassBegin.clearValueCount = numAttachments; - renderPassBegin.pClearValues = clearValues; - - m_api.vkCmdBeginRenderPass(cmdBuffer, &renderPassBegin, VK_SUBPASS_CONTENTS_INLINE); - - // Set up scissor and viewport - { - VkRect2D rects[kMaxRenderTargets] = {}; - VkViewport viewports[kMaxRenderTargets] = {}; - for (int i = 0; i < numRenderTargets; ++i) - { - rects[i] = VkRect2D{ 0, 0, uint32_t(width), uint32_t(height) }; - - VkViewport& dstViewport = viewports[i]; - - dstViewport.x = 0.0f; - dstViewport.y = 0.0f; - dstViewport.width = float(width); - dstViewport.height = float(height); - dstViewport.minDepth = 0.0f; - dstViewport.maxDepth = 1.0f; - } - - m_api.vkCmdSetScissor(cmdBuffer, 0, numRenderTargets, rects); - m_api.vkCmdSetViewport(cmdBuffer, 0, numRenderTargets, viewports); - } - - return SLANG_OK; -} - -void VKRenderer::_endPass() -{ - VkCommandBuffer cmdBuffer = m_deviceQueue.getCommandBuffer(); - m_api.vkCmdEndRenderPass(cmdBuffer); -} - -void VKRenderer::_beginRender() -{ - m_swapChainImageIndex = m_swapChain.nextFrontImageIndex(); - - if (m_swapChainImageIndex < 0) - { - return; - } -} - -void VKRenderer::_endRender() -{ - m_deviceQueue.flush(); -} - -Renderer* createVKRenderer() -{ - return new VKRenderer; -} - -VKRenderer::~VKRenderer() -{ - if (m_renderPass != VK_NULL_HANDLE) - { - m_api.vkDestroyRenderPass(m_device, m_renderPass, nullptr); - m_renderPass = VK_NULL_HANDLE; - } -} - - -VkBool32 VKRenderer::handleDebugMessage(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, - size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg) -{ - char const* severity = "message"; - if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) - severity = "warning"; - if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) - severity = "error"; - - // pMsg can be really big (it can be assembler dump for example) - // Use a dynamic buffer to store - size_t bufferSize = strlen(pMsg) + 1 + 1024; - List<char> bufferArray; - bufferArray.SetSize(bufferSize); - char* buffer = bufferArray.Buffer(); - - sprintf_s(buffer, - bufferSize, - "%s: %s %d: %s\n", - pLayerPrefix, - severity, - msgCode, - pMsg); - - fprintf(stderr, "%s", buffer); - fflush(stderr); - - OutputDebugStringA(buffer); - - return VK_FALSE; -} - -/* static */VKAPI_ATTR VkBool32 VKAPI_CALL VKRenderer::debugMessageCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, - size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg, void* pUserData) -{ - return ((VKRenderer*)pUserData)->handleDebugMessage(flags, objType, srcObject, location, msgCode, pLayerPrefix, pMsg); -} - -VkPipelineShaderStageCreateInfo VKRenderer::compileEntryPoint( - ShaderProgram::KernelDesc const& kernelDesc, - VkShaderStageFlagBits stage, - List<char>& bufferOut) -{ - char const* dataBegin = (char const*) kernelDesc.codeBegin; - char const* dataEnd = (char const*) kernelDesc.codeEnd; - - // We need to make a copy of the code, since the Slang compiler - // will free the memory after a compile request is closed. - size_t codeSize = dataEnd - dataBegin; - - bufferOut.InsertRange(0, dataBegin, codeSize); - - char* codeBegin = bufferOut.Buffer(); - - VkShaderModuleCreateInfo moduleCreateInfo = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO }; - moduleCreateInfo.pCode = (uint32_t*)codeBegin; - moduleCreateInfo.codeSize = codeSize; - - VkShaderModule module; - SLANG_VK_CHECK(m_api.vkCreateShaderModule(m_device, &moduleCreateInfo, nullptr, &module)); - - VkPipelineShaderStageCreateInfo shaderStageCreateInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO }; - shaderStageCreateInfo.stage = stage; - - shaderStageCreateInfo.module = module; - shaderStageCreateInfo.pName = "main"; - - return shaderStageCreateInfo; -} - -// !!!!!!!!!!!!!!!!!!!!!!!!!!!! Renderer interface !!!!!!!!!!!!!!!!!!!!!!!!!! - -SlangResult VKRenderer::initialize(const Desc& desc, void* inWindowHandle) -{ - SLANG_RETURN_ON_FAIL(m_module.init()); - SLANG_RETURN_ON_FAIL(m_api.initGlobalProcs(m_module)); - - m_desc = desc; - - VkApplicationInfo applicationInfo = { VK_STRUCTURE_TYPE_APPLICATION_INFO }; - applicationInfo.pApplicationName = "slang-render-test"; - applicationInfo.pEngineName = "slang-render-test"; - applicationInfo.apiVersion = VK_API_VERSION_1_0; - - char const* instanceExtensions[] = - { - VK_KHR_SURFACE_EXTENSION_NAME, - -#if SLANG_WINDOWS_FAMILY - VK_KHR_WIN32_SURFACE_EXTENSION_NAME, -#else - VK_KHR_XLIB_SURFACE_EXTENSION_NAME -#endif - -#if ENABLE_VALIDATION_LAYER - VK_EXT_DEBUG_REPORT_EXTENSION_NAME, -#endif - }; - - VkInstance instance = VK_NULL_HANDLE; - - VkInstanceCreateInfo instanceCreateInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO }; - instanceCreateInfo.pApplicationInfo = &applicationInfo; - - instanceCreateInfo.enabledExtensionCount = SLANG_COUNT_OF(instanceExtensions); - instanceCreateInfo.ppEnabledExtensionNames = &instanceExtensions[0]; - -#if ENABLE_VALIDATION_LAYER - const char* layerNames[] = { "VK_LAYER_LUNARG_standard_validation" }; - instanceCreateInfo.enabledLayerCount = SLANG_COUNT_OF(layerNames); - instanceCreateInfo.ppEnabledLayerNames = layerNames; -#endif - - SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateInstance(&instanceCreateInfo, nullptr, &instance)); - SLANG_RETURN_ON_FAIL(m_api.initInstanceProcs(instance)); - -#if ENABLE_VALIDATION_LAYER - VkDebugReportFlagsEXT debugFlags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT; - - VkDebugReportCallbackCreateInfoEXT debugCreateInfo = { VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT }; - debugCreateInfo.pfnCallback = &debugMessageCallback; - debugCreateInfo.pUserData = this; - debugCreateInfo.flags = debugFlags; - - SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateDebugReportCallbackEXT(instance, &debugCreateInfo, nullptr, &m_debugReportCallback)); -#endif - - uint32_t numPhysicalDevices = 0; - SLANG_VK_RETURN_ON_FAIL(m_api.vkEnumeratePhysicalDevices(instance, &numPhysicalDevices, nullptr)); - - List<VkPhysicalDevice> physicalDevices; - physicalDevices.SetSize(numPhysicalDevices); - SLANG_VK_RETURN_ON_FAIL(m_api.vkEnumeratePhysicalDevices(instance, &numPhysicalDevices, physicalDevices.Buffer())); - - // TODO: allow override of selected device - uint32_t selectedDeviceIndex = 0; - - SLANG_RETURN_ON_FAIL(m_api.initPhysicalDevice(physicalDevices[selectedDeviceIndex])); - - int queueFamilyIndex = m_api.findQueue(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT); - assert(queueFamilyIndex >= 0); - - float queuePriority = 0.0f; - VkDeviceQueueCreateInfo queueCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO }; - queueCreateInfo.queueFamilyIndex = queueFamilyIndex; - queueCreateInfo.queueCount = 1; - queueCreateInfo.pQueuePriorities = &queuePriority; - - char const* const deviceExtensions[] = - { - VK_KHR_SWAPCHAIN_EXTENSION_NAME, - }; - - VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; - deviceCreateInfo.queueCreateInfoCount = 1; - deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; - deviceCreateInfo.pEnabledFeatures = &m_api.m_deviceFeatures; - - deviceCreateInfo.enabledExtensionCount = SLANG_COUNT_OF(deviceExtensions); - deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions; - - SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateDevice(m_api.m_physicalDevice, &deviceCreateInfo, nullptr, &m_device)); - SLANG_RETURN_ON_FAIL(m_api.initDeviceProcs(m_device)); - - { - VkQueue queue; - m_api.vkGetDeviceQueue(m_device, queueFamilyIndex, 0, &queue); - SLANG_RETURN_ON_FAIL(m_deviceQueue.init(m_api, queue, queueFamilyIndex)); - } - - // set up swap chain - - { - VulkanSwapChain::Desc desc; - VulkanSwapChain::PlatformDesc* platformDesc = nullptr; - - desc.init(); - desc.m_format = Format::RGBA_Unorm_UInt8; - -#if SLANG_WINDOWS_FAMILY - VulkanSwapChain::WinPlatformDesc winPlatformDesc; - winPlatformDesc.m_hinstance = ::GetModuleHandle(nullptr); - winPlatformDesc.m_hwnd = (HWND)inWindowHandle; - platformDesc = &winPlatformDesc; -#endif - - SLANG_RETURN_ON_FAIL(m_swapChain.init(&m_deviceQueue, desc, platformDesc)); - } - - // depth/stencil? - - // render pass? - - { - const int numRenderTargets = 1; - bool shouldClear = true; - bool shouldClearDepth = false; - bool shouldClearStencil = false; - bool hasDepthBuffer = false; - - Format depthFormat = Format::Unknown; - VkFormat colorFormat = m_swapChain.getVkFormat(); - - int numAttachments = 0; - // We need extra space if we have depth buffer - VkAttachmentDescription attachmentDesc[kMaxRenderTargets + 1] = {}; - for (int i = 0; i < numRenderTargets; ++i) - { - VkAttachmentDescription& dst = attachmentDesc[numAttachments ++]; - - dst.flags = 0; - dst.format = colorFormat; - dst.samples = VK_SAMPLE_COUNT_1_BIT; - dst.loadOp = shouldClear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD; - dst.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - dst.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - dst.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - dst.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - dst.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - } - if (hasDepthBuffer) - { - VkAttachmentDescription& dst = attachmentDesc[numAttachments++]; - - dst.flags = 0; - dst.format = VulkanUtil::getVkFormat(depthFormat); - dst.samples = VK_SAMPLE_COUNT_1_BIT; - dst.loadOp = shouldClearDepth ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD; - dst.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - dst.stencilLoadOp = shouldClearStencil ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD; - dst.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; - dst.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - dst.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - } - - VkAttachmentReference colorAttachments[kMaxRenderTargets] = {}; - for (int i = 0; i < numRenderTargets; ++i) - { - VkAttachmentReference& dst = colorAttachments[i]; - dst.attachment = i; - dst.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - } - - VkAttachmentReference depthAttachment = {}; - depthAttachment.attachment = numRenderTargets; - depthAttachment.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - VkSubpassDescription subpassDesc = {}; - subpassDesc.flags = 0; - subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpassDesc.inputAttachmentCount = 0u; - subpassDesc.pInputAttachments = nullptr; - subpassDesc.colorAttachmentCount = numRenderTargets; - subpassDesc.pColorAttachments = colorAttachments; - subpassDesc.pResolveAttachments = nullptr; - subpassDesc.pDepthStencilAttachment = hasDepthBuffer ? &depthAttachment : nullptr; - subpassDesc.preserveAttachmentCount = 0u; - subpassDesc.pPreserveAttachments = nullptr; - - VkRenderPassCreateInfo renderPassCreateInfo = {}; - renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - renderPassCreateInfo.attachmentCount = numAttachments; - renderPassCreateInfo.pAttachments = attachmentDesc; - renderPassCreateInfo.subpassCount = 1; - renderPassCreateInfo.pSubpasses = &subpassDesc; - SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateRenderPass(m_device, &renderPassCreateInfo, nullptr, &m_renderPass)); - } - - // frame buffer - SLANG_RETURN_ON_FAIL(m_swapChain.createFrameBuffers(m_renderPass)); - - _beginRender(); - - return SLANG_OK; -} - -void VKRenderer::submitGpuWork() -{ - m_deviceQueue.flush(); -} - -void VKRenderer::waitForGpu() -{ - m_deviceQueue.flushAndWait(); -} - -void VKRenderer::setClearColor(const float color[4]) -{ - for (int ii = 0; ii < 4; ++ii) - m_clearColor[ii] = color[ii]; -} - -void VKRenderer::clearFrame() -{ -} - -void VKRenderer::presentFrame() -{ - _endRender(); - - const bool vsync = true; - m_swapChain.present(vsync); - - _beginRender(); -} - -SlangResult VKRenderer::captureScreenSurface(Surface& surfaceOut) -{ - return SLANG_FAIL; -} - -static VkBufferUsageFlagBits _calcBufferUsageFlags(Resource::BindFlag::Enum bind) -{ - typedef Resource::BindFlag BindFlag; - - switch (bind) - { - case BindFlag::VertexBuffer: return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; - case BindFlag::IndexBuffer: return VK_BUFFER_USAGE_INDEX_BUFFER_BIT; - case BindFlag::ConstantBuffer: return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - case BindFlag::StreamOutput: - case BindFlag::RenderTarget: - case BindFlag::DepthStencil: - { - assert(!"Not supported yet"); - return VkBufferUsageFlagBits(0); - } - case BindFlag::UnorderedAccess: return VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; - case BindFlag::PixelShaderResource: return VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - case BindFlag::NonPixelShaderResource: return VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - default: return VkBufferUsageFlagBits(0); - } -} - -static VkBufferUsageFlagBits _calcBufferUsageFlags(int bindFlags) -{ - int dstFlags = 0; - while (bindFlags) - { - int lsb = bindFlags & -bindFlags; - dstFlags |= _calcBufferUsageFlags(Resource::BindFlag::Enum(lsb)); - bindFlags &= ~lsb; - } - return VkBufferUsageFlagBits(dstFlags); -} - -static VkBufferUsageFlags _calcBufferUsageFlags(int bindFlags, int cpuAccessFlags, const void* initData) -{ - VkBufferUsageFlags usage = _calcBufferUsageFlags(bindFlags); - - if (cpuAccessFlags & Resource::AccessFlag::Read) - { - // If it can be read from, set this - usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - } - if ((cpuAccessFlags & Resource::AccessFlag::Write) || initData) - { - usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; - } - - return usage; -} - -static VkImageUsageFlagBits _calcImageUsageFlags(Resource::BindFlag::Enum bind) -{ - typedef Resource::BindFlag BindFlag; - - switch (bind) - { - case BindFlag::RenderTarget: return VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - case BindFlag::DepthStencil: return VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - case BindFlag::NonPixelShaderResource: - case BindFlag::PixelShaderResource: - { - // Ignore - return VkImageUsageFlagBits(0); - } - default: - { - assert(!"Unsupported"); - return VkImageUsageFlagBits(0); - } - } -} - -static VkImageUsageFlagBits _calcImageUsageFlags(int bindFlags) -{ - int dstFlags = 0; - while (bindFlags) - { - int lsb = bindFlags & -bindFlags; - dstFlags |= _calcImageUsageFlags(Resource::BindFlag::Enum(lsb)); - bindFlags &= ~lsb; - } - return VkImageUsageFlagBits(dstFlags); -} - -static VkImageUsageFlags _calcImageUsageFlags(int bindFlags, int cpuAccessFlags, const void* initData) -{ - VkImageUsageFlags usage = _calcImageUsageFlags(bindFlags); - - usage |= VK_IMAGE_USAGE_SAMPLED_BIT; - - if (cpuAccessFlags & Resource::AccessFlag::Read) - { - // If it can be read from, set this - usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - } - if ((cpuAccessFlags & Resource::AccessFlag::Write) || initData) - { - usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; - } - - return usage; -} - -void VKRenderer::_transitionImageLayout(VkImage image, VkFormat format, const TextureResource::Desc& desc, VkImageLayout oldLayout, VkImageLayout newLayout) -{ - VkImageMemoryBarrier barrier = {}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.oldLayout = oldLayout; - barrier.newLayout = newLayout; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.image = image; - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barrier.subresourceRange.baseMipLevel = 0; - barrier.subresourceRange.levelCount = desc.numMipLevels; - barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = 1; - - VkPipelineStageFlags sourceStage; - VkPipelineStageFlags destinationStage; - - if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) - { - barrier.srcAccessMask = 0; - barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - - sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - } - else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) - { - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - - sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - } - else - { - assert(!"unsupported layout transition!"); - return; - } - - VkCommandBuffer commandBuffer = m_deviceQueue.getCommandBuffer(); - - m_api.vkCmdPipelineBarrier(commandBuffer, sourceStage, destinationStage, 0, 0, nullptr, 0, nullptr, 1, &barrier); -} - -TextureResource* VKRenderer::createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& descIn, const TextureResource::Data* initData) -{ - TextureResource::Desc desc(descIn); - desc.setDefaults(initialUsage); - - const VkFormat format = VulkanUtil::getVkFormat(desc.format); - if (format == VK_FORMAT_UNDEFINED) - { - assert(!"Unhandled image format"); - return nullptr; - } - - const int arraySize = desc.calcEffectiveArraySize(); - - RefPtr<TextureResourceImpl> texture(new TextureResourceImpl(desc, initialUsage, &m_api)); - - // Create the image - { - VkImageCreateInfo imageInfo = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; - - switch (desc.type) - { - case Resource::Type::Texture1D: - { - imageInfo.imageType = VK_IMAGE_TYPE_1D; - imageInfo.extent = VkExtent3D{ uint32_t(descIn.size.width), 1, 1 }; - break; - } - case Resource::Type::Texture2D: - { - imageInfo.imageType = VK_IMAGE_TYPE_2D; - imageInfo.extent = VkExtent3D{ uint32_t(descIn.size.width), uint32_t(descIn.size.height), 1 }; - break; - } - case Resource::Type::TextureCube: - { - imageInfo.imageType = VK_IMAGE_TYPE_2D; - imageInfo.extent = VkExtent3D{ uint32_t(descIn.size.width), uint32_t(descIn.size.height), 1 }; - break; - } - case Resource::Type::Texture3D: - { - // Can't have an array and 3d texture - assert(desc.arraySize <= 1); - - imageInfo.imageType = VK_IMAGE_TYPE_3D; - imageInfo.extent = VkExtent3D{ uint32_t(descIn.size.width), uint32_t(descIn.size.height), uint32_t(descIn.size.depth) }; - break; - } - default: - { - assert(!"Unhandled type"); - return nullptr; - } - } - - imageInfo.mipLevels = desc.numMipLevels; - imageInfo.arrayLayers = arraySize; - - imageInfo.format = format; - - imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageInfo.usage = _calcImageUsageFlags(desc.bindFlags, desc.cpuAccessFlags, initData); - imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; - imageInfo.flags = 0; // Optional - - SLANG_VK_RETURN_NULL_ON_FAIL(m_api.vkCreateImage(m_device, &imageInfo, nullptr, &texture->m_image)); - } - - VkMemoryRequirements memRequirements; - m_api.vkGetImageMemoryRequirements(m_device, texture->m_image, &memRequirements); - - // Allocate the memory - { - VkMemoryPropertyFlags reqMemoryProperties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - - VkMemoryAllocateInfo allocInfo = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; - - int memoryTypeIndex = m_api.findMemoryTypeIndex(memRequirements.memoryTypeBits, reqMemoryProperties); - assert(memoryTypeIndex >= 0); - - VkMemoryPropertyFlags actualMemoryProperites = m_api.m_deviceMemoryProperties.memoryTypes[memoryTypeIndex].propertyFlags; - - allocInfo.allocationSize = memRequirements.size; - allocInfo.memoryTypeIndex = memoryTypeIndex; - - SLANG_VK_RETURN_NULL_ON_FAIL(m_api.vkAllocateMemory(m_device, &allocInfo, nullptr, &texture->m_imageMemory)); - } - - // Bind the memory to the image - m_api.vkBindImageMemory(m_device, texture->m_image, texture->m_imageMemory, 0); - - if (initData) - { - List<TextureResource::Size> mipSizes; - - VkCommandBuffer commandBuffer = m_deviceQueue.getCommandBuffer(); - - const int numMipMaps = desc.numMipLevels; - assert(initData->numMips == numMipMaps); - - // Calculate how large the buffer has to be - size_t bufferSize = 0; - // Calculate how large an array entry is - for (int j = 0; j < numMipMaps; ++j) - { - const TextureResource::Size mipSize = desc.size.calcMipSize(j); - - const int rowSizeInBytes = Surface::calcRowSize(desc.format, mipSize.width); - const int numRows = Surface::calcNumRows(desc.format, mipSize.height); - - mipSizes.Add(mipSize); - - bufferSize += (rowSizeInBytes * numRows) * mipSize.depth; - } - - - // Calculate the total size taking into account the array - bufferSize *= arraySize; - - Buffer uploadBuffer; - SLANG_RETURN_NULL_ON_FAIL(uploadBuffer.init(m_api, bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)); - - assert(mipSizes.Count() == numMipMaps); - - // Copy into upload buffer - { - int subResourceIndex = 0; - - uint8_t* dstData; - m_api.vkMapMemory(m_device, uploadBuffer.m_memory, 0, bufferSize, 0, (void**)&dstData); - - for (int i = 0; i < arraySize; ++i) - { - for (int j = 0; j < int(mipSizes.Count()); ++j) - { - const auto& mipSize = mipSizes[j]; - - const ptrdiff_t srcRowStride = initData->mipRowStrides[j]; - const int dstRowSizeInBytes = Surface::calcRowSize(desc.format, mipSize.width); - const int numRows = Surface::calcNumRows(desc.format, mipSize.height); - - for (int k = 0; k < mipSize.depth; k++) - { - const uint8_t* srcData = (const uint8_t*)(initData->subResources[subResourceIndex]); - - for (int l = 0; l < numRows; l++) - { - ::memcpy(dstData, srcData, dstRowSizeInBytes); - - dstData += dstRowSizeInBytes; - srcData += srcRowStride; - } - - subResourceIndex++; - } - } - } - - m_api.vkUnmapMemory(m_device, uploadBuffer.m_memory); - } - - _transitionImageLayout(texture->m_image, format, texture->getDesc(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - - { - size_t srcOffset = 0; - for (int i = 0; i < arraySize; ++i) - { - for (int j = 0; j < int(mipSizes.Count()); ++j) - { - const auto& mipSize = mipSizes[j]; - - const int rowSizeInBytes = Surface::calcRowSize(desc.format, mipSize.width); - const int numRows = Surface::calcNumRows(desc.format, mipSize.height); - - // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkBufferImageCopy.html - // bufferRowLength and bufferImageHeight specify the data in buffer memory as a subregion of a larger two- or three-dimensional image, - // and control the addressing calculations of data in buffer memory. If either of these values is zero, that aspect of the buffer memory - // is considered to be tightly packed according to the imageExtent. - - VkBufferImageCopy region = {}; - - region.bufferOffset = srcOffset; - region.bufferRowLength = 0; //rowSizeInBytes; - region.bufferImageHeight = 0; - - region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.imageSubresource.mipLevel = j; - region.imageSubresource.baseArrayLayer = i; - region.imageSubresource.layerCount = 1; - region.imageOffset = { 0, 0, 0 }; - region.imageExtent = { uint32_t(mipSize.width), uint32_t(mipSize.height), uint32_t(mipSize.depth) }; - - // Do the copy (do all depths in a single go) - m_api.vkCmdCopyBufferToImage(commandBuffer, uploadBuffer.m_buffer, texture->m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); - - // Next - srcOffset += rowSizeInBytes * numRows * mipSize.depth; - } - } - } - - _transitionImageLayout(texture->m_image, format, texture->getDesc(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - - m_deviceQueue.flushAndWait(); - } - - return texture.detach(); -} - -BufferResource* VKRenderer::createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& descIn, const void* initData) -{ - BufferResource::Desc desc(descIn); - desc.setDefaults(initialUsage); - - const size_t bufferSize = desc.sizeInBytes; - - VkMemoryPropertyFlags reqMemoryProperties = 0; - - VkBufferUsageFlags usage = _calcBufferUsageFlags(desc.bindFlags, desc.cpuAccessFlags, initData); - - switch (initialUsage) - { - case Resource::Usage::ConstantBuffer: - { - reqMemoryProperties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - break; - } - default: break; - } - - RefPtr<BufferResourceImpl> buffer(new BufferResourceImpl(initialUsage, desc, this)); - SLANG_RETURN_NULL_ON_FAIL(buffer->m_buffer.init(m_api, desc.sizeInBytes, usage, reqMemoryProperties)); - - if ((desc.cpuAccessFlags & Resource::AccessFlag::Write) || initData) - { - SLANG_RETURN_NULL_ON_FAIL(buffer->m_uploadBuffer.init(m_api, bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)); - } - - if (initData) - { - // TODO: only create staging buffer if the memory type - // used for the buffer doesn't let us fill things in - // directly. - // Copy into staging buffer - void* mappedData = nullptr; - SLANG_VK_CHECK(m_api.vkMapMemory(m_device, buffer->m_uploadBuffer.m_memory, 0, bufferSize, 0, &mappedData)); - ::memcpy(mappedData, initData, bufferSize); - m_api.vkUnmapMemory(m_device, buffer->m_uploadBuffer.m_memory); - - // Copy from staging buffer to real buffer - VkCommandBuffer commandBuffer = m_deviceQueue.getCommandBuffer(); - - VkBufferCopy copyInfo = {}; - copyInfo.size = bufferSize; - m_api.vkCmdCopyBuffer(commandBuffer, buffer->m_uploadBuffer.m_buffer, buffer->m_buffer.m_buffer, 1, ©Info); - - //flushCommandBuffer(commandBuffer); - } - - return buffer.detach(); -} - -InputLayout* VKRenderer::createInputLayout(const InputElementDesc* elements, UInt numElements) -{ - RefPtr<InputLayoutImpl> layout(new InputLayoutImpl); - - List<VkVertexInputAttributeDescription>& dstVertexDescs = layout->m_vertexDescs; - - size_t vertexSize = 0; - dstVertexDescs.SetSize(numElements); - - for (UInt i = 0; i < numElements; ++i) - { - const InputElementDesc& srcDesc = elements[i]; - VkVertexInputAttributeDescription& dstDesc = dstVertexDescs[i]; - - dstDesc.location = uint32_t(i); - dstDesc.binding = 0; - dstDesc.format = VulkanUtil::getVkFormat(srcDesc.format); - if (dstDesc.format == VK_FORMAT_UNDEFINED) - { - return nullptr; - } - - dstDesc.offset = uint32_t(srcDesc.offset); - - const size_t elementSize = RendererUtil::getFormatSize(srcDesc.format); - assert(elementSize > 0); - const size_t endElement = srcDesc.offset + elementSize; - - vertexSize = (vertexSize < endElement) ? endElement : vertexSize; - } - - // Work out the overall size - layout->m_vertexSize = int(vertexSize); - return layout.detach(); -} - -void* VKRenderer::map(BufferResource* bufferIn, MapFlavor flavor) -{ - BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(bufferIn); - assert(buffer->m_mapFlavor == MapFlavor::Unknown); - - // Make sure everything has completed before reading... - m_deviceQueue.flushAndWait(); - - const size_t bufferSize = buffer->getDesc().sizeInBytes; - - switch (flavor) - { - case MapFlavor::WriteDiscard: - case MapFlavor::HostWrite: - { - if (!buffer->m_uploadBuffer.isInitialized()) - { - return nullptr; - } - - void* mappedData = nullptr; - SLANG_VK_CHECK(m_api.vkMapMemory(m_device, buffer->m_uploadBuffer.m_memory, 0, bufferSize, 0, &mappedData)); - buffer->m_mapFlavor = flavor; - return mappedData; - } - case MapFlavor::HostRead: - { - // Make sure there is space in the read buffer - buffer->m_readBuffer.SetSize(bufferSize); - - // create staging buffer - Buffer staging; - - SLANG_RETURN_NULL_ON_FAIL(staging.init(m_api, bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)); - - // Copy from real buffer to staging buffer - VkCommandBuffer commandBuffer = m_deviceQueue.getCommandBuffer(); - - VkBufferCopy copyInfo = {}; - copyInfo.size = bufferSize; - m_api.vkCmdCopyBuffer(commandBuffer, buffer->m_buffer.m_buffer, staging.m_buffer, 1, ©Info); - - m_deviceQueue.flushAndWait(); - - // Write out the data from the buffer - void* mappedData = nullptr; - SLANG_VK_CHECK(m_api.vkMapMemory(m_device, staging.m_memory, 0, bufferSize, 0, &mappedData)); - - ::memcpy(buffer->m_readBuffer.Buffer(), mappedData, bufferSize); - m_api.vkUnmapMemory(m_device, staging.m_memory); - - buffer->m_mapFlavor = flavor; - - return buffer->m_readBuffer.Buffer(); - } - default: - return nullptr; - } -} - -void VKRenderer::unmap(BufferResource* bufferIn) -{ - BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(bufferIn); - assert(buffer->m_mapFlavor != MapFlavor::Unknown); - - const size_t bufferSize = buffer->getDesc().sizeInBytes; - - switch (buffer->m_mapFlavor) - { - case MapFlavor::WriteDiscard: - case MapFlavor::HostWrite: - { - m_api.vkUnmapMemory(m_device, buffer->m_uploadBuffer.m_memory); - - // Copy from staging buffer to real buffer - VkCommandBuffer commandBuffer = m_deviceQueue.getCommandBuffer(); - - VkBufferCopy copyInfo = {}; - copyInfo.size = bufferSize; - m_api.vkCmdCopyBuffer(commandBuffer, buffer->m_uploadBuffer.m_buffer, buffer->m_buffer.m_buffer, 1, ©Info); - - // TODO: is this necessary? - //m_deviceQueue.flushAndWait(); - break; - } - default: break; - } - - // Mark as no longer mapped - buffer->m_mapFlavor = MapFlavor::Unknown; -} - -void VKRenderer::setInputLayout(InputLayout* inputLayout) -{ - m_currentInputLayout = static_cast<InputLayoutImpl*>(inputLayout); -} - -void VKRenderer::setPrimitiveTopology(PrimitiveTopology topology) -{ - m_primitiveTopology = VulkanUtil::getVkPrimitiveTopology(topology); -} - -void VKRenderer::setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) -{ - { - const UInt num = startSlot + slotCount; - if (num > m_boundVertexBuffers.Count()) - { - m_boundVertexBuffers.SetSize(num); - } - } - - for (UInt i = 0; i < slotCount; i++) - { - BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(buffers[i]); - if (buffer) - { - assert(buffer->m_initialUsage == Resource::Usage::VertexBuffer); - } - - BoundVertexBuffer& boundBuffer = m_boundVertexBuffers[startSlot + i]; - boundBuffer.m_buffer = buffer; - boundBuffer.m_stride = int(strides[i]); - boundBuffer.m_offset = int(offsets[i]); - } -} - -void VKRenderer::setShaderProgram(ShaderProgram* program) -{ - m_currentProgram = (ShaderProgramImpl*)program; -} - -void VKRenderer::draw(UInt vertexCount, UInt startVertex = 0) -{ - Pipeline* pipeline = _getPipeline(); - if (!pipeline || pipeline->m_shaderProgram->m_pipelineType != PipelineType::Graphics) - { - assert(!"Invalid render pipeline"); - return; - } - - SLANG_RETURN_VOID_ON_FAIL(_beginPass()); - - // Also create descriptor sets based on the given pipeline layout - VkCommandBuffer commandBuffer = m_deviceQueue.getCommandBuffer(); - - m_api.vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->m_pipeline); - m_api.vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->m_pipelineLayout, - 0, 1, &pipeline->m_descriptorSet, 0, nullptr); - - // Bind the vertex buffer - if (m_boundVertexBuffers.Count() > 0 && m_boundVertexBuffers[0].m_buffer) - { - const BoundVertexBuffer& boundVertexBuffer = m_boundVertexBuffers[0]; - - VkBuffer vertexBuffers[] = { boundVertexBuffer.m_buffer->m_buffer.m_buffer }; - VkDeviceSize offsets[] = { VkDeviceSize(boundVertexBuffer.m_offset) }; - - m_api.vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets); - } - - m_api.vkCmdDraw(commandBuffer, static_cast<uint32_t>(vertexCount), 1, 0, 0); - - _endPass(); -} - -void VKRenderer::dispatchCompute(int x, int y, int z) -{ - Pipeline* pipeline = _getPipeline(); - if (!pipeline || pipeline->m_shaderProgram->m_pipelineType != PipelineType::Compute) - { - assert(!"Invalid render pipeline"); - return; - } - - // Also create descriptor sets based on the given pipeline layout - VkCommandBuffer commandBuffer = m_deviceQueue.getCommandBuffer(); - - m_api.vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->m_pipeline); - - m_api.vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->m_pipelineLayout, - 0, 1, &pipeline->m_descriptorSet, 0, nullptr); - - m_api.vkCmdDispatch(commandBuffer, x, y, z); -} - -static VkImageViewType _calcImageViewType(TextureResource::Type type, const TextureResource::Desc& desc) -{ - switch (type) - { - case Resource::Type::Texture1D: return desc.arraySize > 1 ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D; - case Resource::Type::Texture2D: return desc.arraySize > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D; - case Resource::Type::TextureCube: return desc.arraySize > 1 ? VK_IMAGE_VIEW_TYPE_CUBE_ARRAY : VK_IMAGE_VIEW_TYPE_CUBE; - case Resource::Type::Texture3D: - { - // Can't have an array and 3d texture - assert(desc.arraySize <= 1); - if (desc.arraySize <= 1) - { - return VK_IMAGE_VIEW_TYPE_3D; - } - break; - } - default: break; - } - - return VK_IMAGE_VIEW_TYPE_MAX_ENUM; -} - - -BindingState* VKRenderer::createBindingState(const BindingState::Desc& bindingStateDesc) -{ - RefPtr<BindingStateImpl> bindingState(new BindingStateImpl(bindingStateDesc, &m_api)); - - const auto& srcBindings = bindingStateDesc.m_bindings; - const int numBindings = int(srcBindings.Count()); - - auto& dstDetails = bindingState->m_bindingDetails; - dstDetails.SetSize(numBindings); - - for (int i = 0; i < numBindings; ++i) - { - auto& dstDetail = dstDetails[i]; - const auto& srcBinding = srcBindings[i]; - - switch (srcBinding.bindingType) - { - case BindingType::Buffer: - { - if (!srcBinding.resource || !srcBinding.resource->isBuffer()) - { - assert(!"Needs to have a buffer resource set"); - return nullptr; - } - - BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(srcBinding.resource.Ptr()); - const BufferResource::Desc& bufferResourceDesc = bufferResource->getDesc(); - - if (bufferResourceDesc.bindFlags & Resource::BindFlag::UnorderedAccess) - { - // VkBufferView uav - - VkBufferViewCreateInfo info = { VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO }; - - info.format = VK_FORMAT_R32_SFLOAT; - // TODO: - // Not sure how to handle typeless? - if (bufferResourceDesc.elementSize == 0) - { - info.format = VK_FORMAT_R32_SFLOAT; // DXGI_FORMAT_R32_TYPELESS ? - } - - info.buffer = bufferResource->m_buffer.m_buffer; - info.offset = 0; - info.range = bufferResourceDesc.sizeInBytes; - - SLANG_VK_RETURN_NULL_ON_FAIL(m_api.vkCreateBufferView(m_device, &info, nullptr, &dstDetail.m_uav)); - } - - // TODO: Setup views. - // VkImageView srv - - - break; - } - case BindingType::Sampler: - { - VkSamplerCreateInfo samplerInfo = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; - - samplerInfo.magFilter = VK_FILTER_LINEAR; - samplerInfo.minFilter = VK_FILTER_LINEAR; - - samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; - - samplerInfo.anisotropyEnable = VK_FALSE; - samplerInfo.maxAnisotropy = 1; - - samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; - samplerInfo.unnormalizedCoordinates = VK_FALSE; - samplerInfo.compareEnable = VK_FALSE; - samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; - samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - - SLANG_VK_RETURN_NULL_ON_FAIL(m_api.vkCreateSampler(m_device, &samplerInfo, nullptr, &dstDetail.m_sampler)); - - break; - } - case BindingType::Texture: - { - if (!srcBinding.resource || !srcBinding.resource->isTexture()) - { - assert(!"Needs to have a texture resource set"); - return nullptr; - } - - TextureResourceImpl* textureResource = static_cast<TextureResourceImpl*>(srcBinding.resource.Ptr()); - const TextureResource::Desc& texDesc = textureResource->getDesc(); - - VkImageViewType imageViewType = _calcImageViewType(textureResource->getType(), texDesc); - if (imageViewType == VK_IMAGE_VIEW_TYPE_MAX_ENUM) - { - assert(!"Invalid view type"); - return nullptr; - } - const VkFormat format = VulkanUtil::getVkFormat(texDesc.format); - if (format == VK_FORMAT_UNDEFINED) - { - assert(!"Unhandled image format"); - return nullptr; - } - - // Create the image view - - VkImageViewCreateInfo viewInfo = {}; - viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - viewInfo.image = textureResource->m_image; - viewInfo.viewType = imageViewType; - viewInfo.format = format; - viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - viewInfo.subresourceRange.baseMipLevel = 0; - viewInfo.subresourceRange.levelCount = 1; - viewInfo.subresourceRange.baseArrayLayer = 0; - viewInfo.subresourceRange.layerCount = 1; - - viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; - viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; - viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; - viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; - - SLANG_VK_RETURN_NULL_ON_FAIL(m_api.vkCreateImageView(m_device, &viewInfo, nullptr, &dstDetail.m_srv)); - - break; - } - case BindingType::CombinedTextureSampler: - { - assert(!"not implemented"); - return nullptr; - } - } - } - - return bindingState.detach();; -} - -void VKRenderer::setBindingState(BindingState* state) -{ - m_currentBindingState = static_cast<BindingStateImpl*>(state); -} - -ShaderProgram* VKRenderer::createProgram(const ShaderProgram::Desc& desc) -{ - ShaderProgramImpl* impl = new ShaderProgramImpl(desc.pipelineType); - if( desc.pipelineType == PipelineType::Compute) - { - auto computeKernel = desc.findKernel(StageType::Compute); - impl->m_compute = compileEntryPoint(*computeKernel, VK_SHADER_STAGE_COMPUTE_BIT, impl->m_buffers[0]); - } - else - { - auto vertexKernel = desc.findKernel(StageType::Vertex); - auto fragmentKernel = desc.findKernel(StageType::Fragment); - - impl->m_vertex = compileEntryPoint(*vertexKernel, VK_SHADER_STAGE_VERTEX_BIT, impl->m_buffers[0]); - impl->m_fragment = compileEntryPoint(*fragmentKernel, VK_SHADER_STAGE_FRAGMENT_BIT, impl->m_buffers[1]); - } - return impl; -} - -} // renderer_test diff --git a/tools/render-test/render-vk.h b/tools/render-test/render-vk.h deleted file mode 100644 index 7f6d789d0..000000000 --- a/tools/render-test/render-vk.h +++ /dev/null @@ -1,10 +0,0 @@ -// render-vk.h -#pragma once - -namespace renderer_test { - -class Renderer; - -Renderer* createVKRenderer(); - -} // renderer_test diff --git a/tools/render-test/render.cpp b/tools/render-test/render.cpp deleted file mode 100644 index bfb7aeb94..000000000 --- a/tools/render-test/render.cpp +++ /dev/null @@ -1,390 +0,0 @@ -// render.cpp -#include "render.h" - -#include "../../source/core/slang-math.h" - -namespace renderer_test { -using namespace Slang; - -/* static */const Resource::BindFlag::Enum Resource::s_requiredBinding[] = -{ - BindFlag::VertexBuffer, // VertexBuffer - BindFlag::IndexBuffer, // IndexBuffer - BindFlag::ConstantBuffer, // ConstantBuffer - BindFlag::StreamOutput, // StreamOut - BindFlag::RenderTarget, // RenderTager - BindFlag::DepthStencil, // DepthRead - BindFlag::DepthStencil, // DepthWrite - BindFlag::UnorderedAccess, // UnorderedAccess - BindFlag::PixelShaderResource, // PixelShaderResource - BindFlag::NonPixelShaderResource, // NonPixelShaderResource - BindFlag::Enum(BindFlag::PixelShaderResource | BindFlag::NonPixelShaderResource), // GenericRead -}; - - -/* static */void Resource::compileTimeAsserts() -{ - SLANG_COMPILE_TIME_ASSERT(SLANG_COUNT_OF(s_requiredBinding) == int(Usage::CountOf)); -} - -static const Resource::DescBase s_emptyDescBase = {}; - -const Resource::DescBase& Resource::getDescBase() const -{ - if (isBuffer()) - { - return static_cast<const BufferResource *>(this)->getDesc(); - } - else if (isTexture()) - { - return static_cast<const TextureResource *>(this)->getDesc(); - } - return s_emptyDescBase; -} - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! RendererUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ - -/* static */const uint8_t RendererUtil::s_formatSize[] = -{ - 0, // Unknown, - - uint8_t(sizeof(float) * 4), // RGBA_Float32, - uint8_t(sizeof(float) * 3), // RGB_Float32, - uint8_t(sizeof(float) * 2), // RG_Float32, - uint8_t(sizeof(float) * 1), // R_Float32, - - uint8_t(sizeof(uint32_t)), // RGBA_Unorm_UInt8, - - uint8_t(sizeof(uint32_t)), // R_UInt32, - - uint8_t(sizeof(float)), // D_Float32, - uint8_t(sizeof(uint32_t)), // D_Unorm24_S8, -}; - -/* static */const BindingStyle RendererUtil::s_rendererTypeToBindingStyle[] = -{ - BindingStyle::Unknown, // Unknown, - BindingStyle::DirectX, // DirectX11, - BindingStyle::DirectX, // DirectX12, - BindingStyle::OpenGl, // OpenGl, - BindingStyle::Vulkan, // Vulkan -}; - -/* static */void RendererUtil::compileTimeAsserts() -{ - SLANG_COMPILE_TIME_ASSERT(SLANG_COUNT_OF(s_formatSize) == int(Format::CountOf)); - SLANG_COMPILE_TIME_ASSERT(SLANG_COUNT_OF(s_rendererTypeToBindingStyle) == int(RendererType::CountOf)); -} - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!! BindingState::Desc !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ - -void BindingState::Desc::addSampler(const SamplerDesc& desc, const RegisterRange& registerRange) -{ - int descIndex = int(m_samplerDescs.Count()); - m_samplerDescs.Add(desc); - - Binding binding; - binding.bindingType = BindingType::Sampler; - binding.resource = nullptr; - binding.registerRange = registerRange; - binding.descIndex = descIndex; - - m_bindings.Add(binding); -} - -void BindingState::Desc::addResource(BindingType bindingType, Resource* resource, const RegisterRange& registerRange) -{ - assert(resource); - - Binding binding; - binding.bindingType = bindingType; - binding.resource = resource; - binding.descIndex = -1; - binding.registerRange = registerRange; - m_bindings.Add(binding); -} - -void BindingState::Desc::addCombinedTextureSampler(TextureResource* resource, const SamplerDesc& samplerDesc, const RegisterRange& registerRange) -{ - assert(resource); - - int samplerDescIndex = int(m_samplerDescs.Count()); - m_samplerDescs.Add(samplerDesc); - - Binding binding; - binding.bindingType = BindingType::CombinedTextureSampler; - binding.resource = resource; - binding.descIndex = samplerDescIndex; - binding.registerRange = registerRange; - m_bindings.Add(binding); -} - -void BindingState::Desc::clear() -{ - m_bindings.Clear(); - m_samplerDescs.Clear(); - m_numRenderTargets = 1; -} - -int BindingState::Desc::findBindingIndex(Resource::BindFlag::Enum bindFlag, int registerIndex) const -{ - const int numBindings = int(m_bindings.Count()); - for (int i = 0; i < numBindings; ++i) - { - const Binding& binding = m_bindings[i]; - if (binding.resource && (binding.resource->getDescBase().bindFlags & bindFlag) != 0) - { - if (binding.registerRange.hasRegister(registerIndex)) - { - return i; - } - } - } - - return -1; -} - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!! TextureResource::Size !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ - -int TextureResource::Size::calcMaxDimension(Type type) const -{ - switch (type) - { - case Resource::Type::Texture1D: return this->width; - case Resource::Type::Texture3D: return std::max(std::max(this->width, this->height), this->depth); - case Resource::Type::TextureCube: // fallthru - case Resource::Type::Texture2D: - { - return std::max(this->width, this->height); - } - default: return 0; - } -} - -TextureResource::Size TextureResource::Size::calcMipSize(int mipLevel) const -{ - Size size; - size.width = TextureResource::calcMipSize(this->width, mipLevel); - size.height = TextureResource::calcMipSize(this->height, mipLevel); - size.depth = TextureResource::calcMipSize(this->depth, mipLevel); - return size; -} - -/* !!!!!!!!!!!!!!!!!!!!!!!!! BufferResource::Desc !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ - -void BufferResource::Desc::setDefaults(Usage initialUsage) -{ - if (this->bindFlags == 0) - { - this->bindFlags = Resource::s_requiredBinding[int(initialUsage)]; - } -} - -/* !!!!!!!!!!!!!!!!!!!!!!!!! TextureResource::Desc !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ - -int TextureResource::Desc::calcNumMipLevels() const -{ - const int maxDimensionSize = this->size.calcMaxDimension(type); - return (maxDimensionSize > 0) ? (Math::Log2Floor(maxDimensionSize) + 1) : 0; -} - -int TextureResource::Desc::calcNumSubResources() const -{ - const int numMipMaps = (this->numMipLevels > 0) ? this->numMipLevels : calcNumMipLevels(); - const int arrSize = (this->arraySize > 0) ? this->arraySize : 1; - - switch (type) - { - case Resource::Type::Texture1D: - case Resource::Type::Texture2D: - { - return numMipMaps * arrSize; - } - case Resource::Type::Texture3D: - { - // can't have arrays of 3d textures - assert(this->arraySize <= 1); - return numMipMaps * this->size.depth; - } - case Resource::Type::TextureCube: - { - // There are 6 faces to a cubemap - return numMipMaps * arrSize * 6; - } - default: return 0; - } -} - -void TextureResource::Desc::fixSize() -{ - switch (type) - { - case Resource::Type::Texture1D: - { - this->size.height = 1; - this->size.depth = 1; - break; - } - case Resource::Type::TextureCube: - case Resource::Type::Texture2D: - { - this->size.depth = 1; - break; - } - case Resource::Type::Texture3D: - { - // Can't have an array - this->arraySize = 0; - break; - } - default: break; - } -} - -void TextureResource::Desc::setDefaults(Usage initialUsage) -{ - fixSize(); - if (this->bindFlags == 0) - { - this->bindFlags = Resource::s_requiredBinding[int(initialUsage)]; - } - if (this->numMipLevels <= 0) - { - this->numMipLevels = calcNumMipLevels(); - } -} - -int TextureResource::Desc::calcEffectiveArraySize() const -{ - const int arrSize = (this->arraySize > 0) ? this->arraySize : 1; - - switch (type) - { - case Resource::Type::Texture1D: // fallthru - case Resource::Type::Texture2D: - { - return arrSize; - } - case Resource::Type::TextureCube: return arrSize * 6; - case Resource::Type::Texture3D: return 1; - default: return 0; - } -} - -void TextureResource::Desc::init(Type typeIn) -{ - this->type = typeIn; - this->size.init(); - - this->format = Format::Unknown; - this->arraySize = 0; - this->numMipLevels = 0; - this->sampleDesc.init(); - - this->bindFlags = 0; - this->cpuAccessFlags = 0; -} - -void TextureResource::Desc::init1D(Format formatIn, int widthIn, int numMipMapsIn) -{ - this->type = Type::Texture1D; - this->size.init(widthIn); - - this->format = format; - this->arraySize = 0; - this->numMipLevels = numMipMapsIn; - this->sampleDesc.init(); - - this->bindFlags = 0; - this->cpuAccessFlags = 0; -} - -void TextureResource::Desc::init2D(Type typeIn, Format formatIn, int widthIn, int heightIn, int numMipMapsIn) -{ - assert(typeIn == Type::Texture2D || typeIn == Type::TextureCube); - - this->type = type; - this->size.init(widthIn, heightIn); - - this->format = format; - this->arraySize = 0; - this->numMipLevels = numMipMapsIn; - this->sampleDesc.init(); - - this->bindFlags = 0; - this->cpuAccessFlags = 0; -} - -void TextureResource::Desc::init3D(Format formatIn, int widthIn, int heightIn, int depthIn, int numMipMapsIn) -{ - this->type = Type::Texture3D; - this->size.init(widthIn, heightIn, depthIn); - - this->format = format; - this->arraySize = 0; - this->numMipLevels = numMipMapsIn; - this->sampleDesc.init(); - - this->bindFlags = 0; - this->cpuAccessFlags = 0; -} - -/* !!!!!!!!!!!!!!!!!!!!!!!!! RennderUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ - -ProjectionStyle RendererUtil::getProjectionStyle(RendererType type) -{ - switch (type) - { - case RendererType::DirectX11: - case RendererType::DirectX12: - { - return ProjectionStyle::DirectX; - } - case RendererType::OpenGl: return ProjectionStyle::OpenGl; - case RendererType::Vulkan: return ProjectionStyle::Vulkan; - case RendererType::Unknown: return ProjectionStyle::Unknown; - default: - { - assert(!"Unhandled type"); - return ProjectionStyle::Unknown; - } - } -} - -/* static */void RendererUtil::getIdentityProjection(ProjectionStyle style, float projMatrix[16]) -{ - switch (style) - { - case ProjectionStyle::DirectX: - case ProjectionStyle::OpenGl: - { - static const float kIdentity[] = - { - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - }; - ::memcpy(projMatrix, kIdentity, sizeof(kIdentity)); - break; - } - case ProjectionStyle::Vulkan: - { - static const float kIdentity[] = - { - 1, 0, 0, 0, - 0, -1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - }; - ::memcpy(projMatrix, kIdentity, sizeof(kIdentity)); - break; - } - default: - { - assert(!"Not handled"); - } - } -} - -} // renderer_test diff --git a/tools/render-test/render.h b/tools/render-test/render.h deleted file mode 100644 index 6a3c58a05..000000000 --- a/tools/render-test/render.h +++ /dev/null @@ -1,583 +0,0 @@ -// render.h -#pragma once - -#include "window.h" - -//#include "shader-input-layout.h" - -#include "../../slang-com-helper.h" - -#include "../../source/core/smart-pointer.h" -#include "../../source/core/list.h" - -namespace renderer_test { - -// Had to move here, because Options needs types defined here -typedef intptr_t Int; -typedef uintptr_t UInt; - -// pre declare types -class Surface; - -// Declare opaque type -class InputLayout: public Slang::RefObject -{ - public: -}; - -enum class PipelineType -{ - Unknown, - Graphics, - Compute, - CountOf, -}; - -enum class StageType -{ - Unknown, - Vertex, - Hull, - Domain, - Geometry, - Fragment, - Compute, - CountOf, -}; - -enum class RendererType -{ - Unknown, - DirectX11, - DirectX12, - OpenGl, - Vulkan, - CountOf, -}; - -enum class ProjectionStyle -{ - Unknown, - OpenGl, - DirectX, - Vulkan, - CountOf, -}; - -/// The style of the binding -enum class BindingStyle -{ - Unknown, - DirectX, - OpenGl, - Vulkan, - CountOf, -}; - -class ShaderProgram: public Slang::RefObject -{ -public: - - struct KernelDesc - { - StageType stage; - void const* codeBegin; - void const* codeEnd; - - UInt getCodeSize() const { return (char const*)codeEnd - (char const*)codeBegin; } - }; - - struct Desc - { - PipelineType pipelineType; - KernelDesc const* kernels; - Int kernelCount; - - /// Find and return the kernel for `stage`, if present. - KernelDesc const* findKernel(StageType stage) const - { - for(Int ii = 0; ii < kernelCount; ++ii) - if(kernels[ii].stage == stage) - return &kernels[ii]; - return nullptr; - } - }; -}; - -struct ShaderCompileRequest -{ - struct SourceInfo - { - char const* path; - - // The data may either be source text (in which - // case it can be assumed to be nul-terminated with - // `dataEnd` pointing at the terminator), or - // raw binary data (in which case `dataEnd` points - // at the end of the buffer). - char const* dataBegin; - char const* dataEnd; - }; - - struct EntryPoint - { - char const* name = nullptr; - SourceInfo source; - }; - - SourceInfo source; - EntryPoint vertexShader; - EntryPoint fragmentShader; - EntryPoint computeShader; - Slang::List<Slang::String> entryPointTypeArguments; -}; - -/// Different formats of things like pixels or elements of vertices -/// NOTE! Any change to this type (adding, removing, changing order) - must also be reflected in changes to RendererUtil -enum class Format -{ - Unknown, - - RGBA_Float32, - RGB_Float32, - RG_Float32, - R_Float32, - - RGBA_Unorm_UInt8, - - R_UInt32, - - D_Float32, - D_Unorm24_S8, - - CountOf, -}; - -struct InputElementDesc -{ - char const* semanticName; - UInt semanticIndex; - Format format; - UInt offset; -}; - -enum class MapFlavor -{ - Unknown, ///< Unknown mapping type - HostRead, - HostWrite, - WriteDiscard, -}; - -enum class PrimitiveTopology -{ - TriangleList, -}; - -class Resource: public Slang::RefObject -{ - public: - - /// The type of resource. - /// NOTE! The order needs to be such that all texture types are at or after Texture1D (otherwise isTexture won't work correctly) - enum class Type - { - Unknown, ///< Unknown - Buffer, ///< A buffer (like a constant/index/vertex buffer) - Texture1D, ///< A 1d texture - Texture2D, ///< A 2d texture - Texture3D, ///< A 3d texture - TextureCube, ///< A cubemap consists of 6 Texture2D like faces - CountOf, - }; - - /// Describes how a resource is to be used - enum class Usage - { - Unknown = -1, - VertexBuffer = 0, - IndexBuffer, - ConstantBuffer, - StreamOutput, - RenderTarget, - DepthRead, - DepthWrite, - UnorderedAccess, - PixelShaderResource, - NonPixelShaderResource, - GenericRead, - CountOf, - }; - - /// Binding flags describe all of the ways a resource can be bound - and therefore used - struct BindFlag - { - enum Enum - { - VertexBuffer = 0x001, - IndexBuffer = 0x002, - ConstantBuffer = 0x004, - StreamOutput = 0x008, - RenderTarget = 0x010, - DepthStencil = 0x020, - UnorderedAccess = 0x040, - PixelShaderResource = 0x080, - NonPixelShaderResource = 0x100, - }; - }; - - /// Combinations describe how a resource can be accessed (typically by the host/cpu) - struct AccessFlag - { - enum Enum - { - Read = 0x1, - Write = 0x2 - }; - }; - - /// Base class for Descs - struct DescBase - { - bool canBind(BindFlag::Enum bindFlag) const { return (bindFlags & bindFlag) != 0; } - bool hasCpuAccessFlag(AccessFlag::Enum accessFlag) { return (cpuAccessFlags & accessFlag) != 0; } - - Type type = Type::Unknown; - - int bindFlags = 0; ///< Combination of Resource::BindFlag or 0 (and will use initialUsage to set) - int cpuAccessFlags = 0; ///< Combination of Resource::AccessFlag - }; - - /// Get the type - SLANG_FORCE_INLINE Type getType() const { return m_type; } - /// True if it's a texture derived type - SLANG_FORCE_INLINE bool isTexture() const { return int(m_type) >= int(Type::Texture1D); } - /// True if it's a buffer derived type - SLANG_FORCE_INLINE bool isBuffer() const { return m_type == Type::Buffer; } - - /// Get the descBase - const DescBase& getDescBase() const; - /// Returns true if can bind with flag - bool canBind(BindFlag::Enum bindFlag) const { return getDescBase().canBind(bindFlag); } - - /// For a usage gives the required binding flags - static const BindFlag::Enum s_requiredBinding[]; /// Maps Usage to bind flags required - - protected: - Resource(Type type): - m_type(type) - {} - - static void compileTimeAsserts(); - - Type m_type; -}; - -class BufferResource: public Resource -{ - public: - typedef Resource Parent; - - struct Desc: public DescBase - { - void init(size_t sizeInBytesIn) - { - sizeInBytes = sizeInBytesIn; - elementSize = 0; - format = Format::Unknown; - } - /// Set up default parameters based on usage - void setDefaults(Usage initialUsage); - - size_t sizeInBytes; ///< Total size in bytes - int elementSize; ///< Get the element stride. If > 0, this is a structured buffer - Format format; - }; - - /// Get the buffer description - SLANG_FORCE_INLINE const Desc& getDesc() const { return m_desc; } - - /// Ctor - BufferResource(const Desc& desc): - Parent(Type::Buffer), - m_desc(desc) - { - } - - protected: - Desc m_desc; -}; - -class TextureResource: public Resource -{ - public: - typedef Resource Parent; - - struct SampleDesc - { - void init() - { - numSamples = 1; - quality = 0; - } - int numSamples; ///< Number of samples per pixel - int quality; ///< The quality measure for the samples - }; - - struct Size - { - void init() - { - width = height = depth = 1; - } - void init(int widthIn, int heightIn = 1, int depthIn = 1) - { - width = widthIn; - height = heightIn; - depth = depthIn; - } - /// Given the type works out the maximum dimension size - int calcMaxDimension(Type type) const; - /// Given a size, calculates the size at a mip level - Size calcMipSize(int mipLevel) const; - - int width; ///< Width in pixels - int height; ///< Height in pixels (if 2d or 3d) - int depth; ///< Depth (if 3d) - }; - - struct Desc: public DescBase - { - /// Initialize with default values - void init(Type typeIn); - /// Initialize different dimensions. For cubemap, use init2D - void init1D(Format format, int width, int numMipMaps = 0); - void init2D(Type typeIn, Format format, int width, int height, int numMipMaps = 0); - void init3D(Format format, int width, int height, int depth, int numMipMaps = 0); - - /// Given the type, calculates the number of mip maps. 0 on error - int calcNumMipLevels() const; - /// Calculate the total number of sub resources. 0 on error. - int calcNumSubResources() const; - - /// Calculate the effective array size - in essence the amount if mip map sets needed. - /// In practice takes into account if the arraySize is 0 (it's not an array, but it will still have at least one mip set) - /// and if the type is a cubemap (multiplies the amount of mip sets by 6) - int calcEffectiveArraySize() const; - - /// Use type to fix the size values (and array size). - /// For example a 1d texture, should have height and depth set to 1. - void fixSize(); - - /// Set up default parameters based on type and usage - void setDefaults(Usage initialUsage); - - Size size; - - int arraySize; ///< Array size - - int numMipLevels; ///< Number of mip levels - if 0 will create all mip levels - Format format; ///< The resources format - SampleDesc sampleDesc; ///< How the resource is sampled - }; - - /// The ordering of the subResources is - /// forall (effectiveArraySize) - /// forall (mip levels) - /// forall (depth levels) - struct Data - { - ptrdiff_t* mipRowStrides; ///< The row stride for a mip map - int numMips; ///< The number of mip maps - const void*const* subResources; ///< Pointers to each full mip subResource - int numSubResources; ///< The total amount of subResources. Typically = numMips * depth * arraySize - }; - - /// Get the description of the texture - SLANG_FORCE_INLINE const Desc& getDesc() const { return m_desc; } - - /// Ctor - TextureResource(const Desc& desc): - Parent(desc.type), - m_desc(desc) - { - } - - SLANG_FORCE_INLINE static int calcMipSize(int width, int mipLevel) - { - width = width >> mipLevel; - return width > 0 ? width : 1; - } - - protected: - Desc m_desc; -}; - -enum class BindingType -{ - Unknown, - Sampler, - Buffer, - Texture, - CombinedTextureSampler, - CountOf, -}; - -class BindingState : public Slang::RefObject -{ -public: - /// A register set consists of one or more contiguous indices. - /// To be valid index >= 0 and size >= 1 - struct RegisterRange - { - /// True if contains valid contents - bool isValid() const { return size > 0; } - /// True if valid single value - bool isSingle() const { return size == 1; } - /// Get as a single index (must be at least one index) - int getSingleIndex() const { return (size == 1) ? index : -1; } - /// Return the first index - int getFirstIndex() const { return (size > 0) ? index : -1; } - /// True if contains register index - bool hasRegister(int registerIndex) const { return registerIndex >= index && registerIndex < index + size; } - - static RegisterRange makeInvalid() { return RegisterRange{ -1, 0 }; } - static RegisterRange makeSingle(int index) { return RegisterRange{ int16_t(index), 1 }; } - static RegisterRange makeRange(int index, int size) { return RegisterRange{ int16_t(index), uint16_t(size) }; } - - int16_t index; ///< The base index - uint16_t size; ///< The amount of register indices - }; - - struct SamplerDesc - { - bool isCompareSampler; - }; - - struct Binding - { - BindingType bindingType; ///< Type of binding - int descIndex; ///< The description index associated with type. -1 if not used. For example if bindingType is Sampler, the descIndex is into m_samplerDescs. - Slang::RefPtr<Resource> resource; ///< Associated resource. nullptr if not used - RegisterRange registerRange; /// Defines the registers for binding - }; - - struct Desc - { - /// Add a resource - assumed that the binding will match the Desc of the resource - void addResource(BindingType bindingType, Resource* resource, const RegisterRange& registerRange); - /// Add a sampler - void addSampler(const SamplerDesc& desc, const RegisterRange& registerRange); - /// Add a BufferResource - void addBufferResource(BufferResource* resource, const RegisterRange& registerRange) { addResource(BindingType::Buffer, resource, registerRange); } - /// Add a texture - void addTextureResource(TextureResource* resource, const RegisterRange& registerRange) { addResource(BindingType::Texture, resource, registerRange); } - /// Add combined texture a - void addCombinedTextureSampler(TextureResource* resource, const SamplerDesc& samplerDesc, const RegisterRange& registerRange); - - /// Returns the bind index, that has the bind flag, and indexes the specified register - int findBindingIndex(Resource::BindFlag::Enum bindFlag, int registerIndex) const; - - /// Clear the contents - void clear(); - - Slang::List<Binding> m_bindings; ///< All of the bindings in order - Slang::List<SamplerDesc> m_samplerDescs; ///< Holds the SamplerDesc for the binding - indexed by the descIndex member of Binding - - int m_numRenderTargets = 1; - }; - - /// Get the Desc used to create this binding - SLANG_FORCE_INLINE const Desc& getDesc() const { return m_desc; } - - protected: - BindingState(const Desc& desc): - m_desc(desc) - { - } - - Desc m_desc; -}; - -class Renderer: public Slang::RefObject -{ -public: - - struct Desc - { - int width; ///< Width in pixels - int height; ///< height in pixels - }; - - virtual SlangResult initialize(const Desc& desc, void* inWindowHandle) = 0; - - virtual void setClearColor(const float color[4]) = 0; - virtual void clearFrame() = 0; - - virtual void presentFrame() = 0; - - /// Create a texture resource. initData holds the initialize data to set the contents of the texture when constructed. - virtual TextureResource* createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData = nullptr) { return nullptr; } - /// Create a buffer resource - virtual BufferResource* createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& desc, const void* initData = nullptr) { return nullptr; } - - /// Captures the back buffer and stores the result in surfaceOut. If the surface contains data - it will either be overwritten (if same size and format), or freed and a re-allocated. - virtual SlangResult captureScreenSurface(Surface& surfaceOut) = 0; - - virtual InputLayout* createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) = 0; - virtual BindingState* createBindingState(const BindingState::Desc& desc) { return nullptr; } - - virtual ShaderProgram* createProgram(const ShaderProgram::Desc& desc) = 0; - - virtual void* map(BufferResource* buffer, MapFlavor flavor) = 0; - virtual void unmap(BufferResource* buffer) = 0; - - virtual void setInputLayout(InputLayout* inputLayout) = 0; - virtual void setPrimitiveTopology(PrimitiveTopology topology) = 0; - virtual void setBindingState(BindingState* state) = 0; - virtual void setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) = 0; - - inline void setVertexBuffer(UInt slot, BufferResource* buffer, UInt stride, UInt offset = 0); - - virtual void setShaderProgram(ShaderProgram* program) = 0; - - virtual void draw(UInt vertexCount, UInt startVertex = 0) = 0; - virtual void dispatchCompute(int x, int y, int z) = 0; - - /// Commit any buffered state changes or draw calls. - /// presentFrame will commitAll implicitly before doing a present - virtual void submitGpuWork() = 0; - /// Blocks until Gpu work is complete - virtual void waitForGpu() = 0; - - /// Get the type of this renderer - virtual RendererType getRendererType() const = 0; -}; - -// ---------------------------------------------------------------------------------------- -inline void Renderer::setVertexBuffer(UInt slot, BufferResource* buffer, UInt stride, UInt offset) -{ - setVertexBuffers(slot, 1, &buffer, &stride, &offset); -} - -/// Functions that are around Renderer and it's types -struct RendererUtil -{ - /// Gets the size in bytes of a Format type. Returns 0 if a size is not defined/invalid - SLANG_FORCE_INLINE static size_t getFormatSize(Format format) { return s_formatSize[int(format)]; } - /// Given a renderer type, gets a projection style - static ProjectionStyle getProjectionStyle(RendererType type); - - /// Given the projection style returns an 'identity' matrix, which ensures x,y mapping to pixels is the same on all targets - static void getIdentityProjection(ProjectionStyle style, float projMatrix[16]); - - /// Get the binding style from the type - static BindingStyle getBindingStyle(RendererType type) { return s_rendererTypeToBindingStyle[int(type)]; } - - private: - static void compileTimeAsserts(); - static const uint8_t s_formatSize[]; // Maps Format::XXX to a size in bytes; - static const BindingStyle s_rendererTypeToBindingStyle[]; ///< Maps a RendererType to a BindingStyle -}; - -} // renderer_test diff --git a/tools/render-test/resource-d3d12.cpp b/tools/render-test/resource-d3d12.cpp deleted file mode 100644 index 160c7f898..000000000 --- a/tools/render-test/resource-d3d12.cpp +++ /dev/null @@ -1,214 +0,0 @@ -// resource-d3d12.cpp -#include "resource-d3d12.h" - -namespace renderer_test { -using namespace Slang; - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! D3D12BarrierSubmitter !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ - -void D3D12BarrierSubmitter::_flush() -{ - assert(m_numBarriers > 0); - - if (m_commandList) - { - m_commandList->ResourceBarrier(UINT(m_numBarriers), m_barriers); - } - m_numBarriers = 0; -} - -D3D12_RESOURCE_BARRIER& D3D12BarrierSubmitter::_expandOne() -{ - _flush(); - return m_barriers[m_numBarriers++]; -} - -void D3D12BarrierSubmitter::transition(ID3D12Resource* resource, D3D12_RESOURCE_STATES prevState, D3D12_RESOURCE_STATES nextState) -{ - if (nextState != prevState) - { - D3D12_RESOURCE_BARRIER& barrier = expandOne(); - - const UINT subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - const D3D12_RESOURCE_BARRIER_FLAGS flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; - - ::memset(&barrier, 0, sizeof(barrier)); - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Flags = flags; - barrier.Transition.pResource = resource; - barrier.Transition.StateBefore = prevState; - barrier.Transition.StateAfter = nextState; - barrier.Transition.Subresource = subresource; - } - else - { - if (nextState == D3D12_RESOURCE_STATE_UNORDERED_ACCESS) - { - D3D12_RESOURCE_BARRIER& barrier = expandOne(); - - ::memset(&barrier, 0, sizeof(barrier)); - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; - barrier.UAV.pResource = resource; - } - } -} - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! D3D12ResourceBase !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ - -/* static */DXGI_FORMAT D3D12ResourceBase::calcFormat(D3DUtil::UsageType usage, ID3D12Resource* resource) -{ - return resource ? D3DUtil::calcFormat(usage, resource->GetDesc().Format) : DXGI_FORMAT_UNKNOWN; -} - -void D3D12ResourceBase::transition(D3D12_RESOURCE_STATES nextState, D3D12BarrierSubmitter& submitter) -{ - // Transition only if there is a resource - if (m_resource) - { - submitter.transition(m_resource, m_state, nextState); - m_state = nextState; - } -} - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! D3D12CounterFence !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ - -D3D12CounterFence::~D3D12CounterFence() -{ - if (m_event) - { - CloseHandle(m_event); - } -} - -Result D3D12CounterFence::init(ID3D12Device* device, uint64_t initialValue) -{ - m_currentValue = initialValue; - - SLANG_RETURN_ON_FAIL(device->CreateFence(m_currentValue, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(m_fence.writeRef()))); - // Create an event handle to use for frame synchronization. - m_event = ::CreateEvent(nullptr, FALSE, FALSE, nullptr); - if (m_event == nullptr) - { - Result res = HRESULT_FROM_WIN32(GetLastError()); - return SLANG_FAILED(res) ? res : SLANG_FAIL; - } - return SLANG_OK; -} - -UInt64 D3D12CounterFence::nextSignal(ID3D12CommandQueue* commandQueue) -{ - // Increment the fence value. Save on the frame - we'll know that frame is done when the fence value >= - m_currentValue++; - // Schedule a Signal command in the queue. - Result res = commandQueue->Signal(m_fence, m_currentValue); - if (SLANG_FAILED(res)) - { - assert(!"Signal failed"); - } - return m_currentValue; -} - -void D3D12CounterFence::waitUntilCompleted(uint64_t completedValue) -{ - // You can only wait for a value that is less than or equal to the current value - assert(completedValue <= m_currentValue); - - // Wait until the previous frame is finished. - while (m_fence->GetCompletedValue() < completedValue) - { - // Make it signal with the current value - SLANG_ASSERT_VOID_ON_FAIL(m_fence->SetEventOnCompletion(completedValue, m_event)); - WaitForSingleObject(m_event, INFINITE); - } -} - -void D3D12CounterFence::nextSignalAndWait(ID3D12CommandQueue* commandQueue) -{ - waitUntilCompleted(nextSignal(commandQueue)); -} - -/* !!!!!!!!!!!!!!!!!!!!!!!!! D3D12Resource !!!!!!!!!!!!!!!!!!!!!!!! */ - -/* static */void D3D12Resource::setDebugName(ID3D12Resource* resource, const char* name) -{ - if (resource) - { - size_t len = ::strlen(name); - List<wchar_t> buf; - buf.SetSize(len + 1); - - D3DUtil::appendWideChars(name, buf); - resource->SetName(buf.begin()); - } -} - -void D3D12Resource::setDebugName(const char* name) -{ - setDebugName(m_resource, name); -} - -void D3D12Resource::setDebugName(const wchar_t* name) -{ - if (m_resource) - { - m_resource->SetName(name); - } -} - -void D3D12Resource::setResource(ID3D12Resource* resource, D3D12_RESOURCE_STATES initialState) -{ - if (resource != m_resource) - { - if (resource) - { - resource->AddRef(); - } - if (m_resource) - { - m_resource->Release(); - } - m_resource = resource; - } - m_prevState = initialState; - m_state = initialState; -} - -void D3D12Resource::setResourceNull() -{ - if (m_resource) - { - m_resource->Release(); - m_resource = nullptr; - } -} - -Result D3D12Resource::initCommitted(ID3D12Device* device, const D3D12_HEAP_PROPERTIES& heapProps, D3D12_HEAP_FLAGS heapFlags, const D3D12_RESOURCE_DESC& resourceDesc, D3D12_RESOURCE_STATES initState, const D3D12_CLEAR_VALUE * clearValue) -{ - setResourceNull(); - ComPtr<ID3D12Resource> resource; - SLANG_RETURN_ON_FAIL(device->CreateCommittedResource(&heapProps, heapFlags, &resourceDesc, initState, clearValue, IID_PPV_ARGS(resource.writeRef()))); - setResource(resource, initState); - return SLANG_OK; -} - -ID3D12Resource* D3D12Resource::detach() -{ - ID3D12Resource* resource = m_resource; - m_resource = nullptr; - return resource; -} - -void D3D12Resource::swap(ComPtr<ID3D12Resource>& resourceInOut) -{ - ID3D12Resource* tmp = m_resource; - m_resource = resourceInOut.detach(); - resourceInOut.attach(tmp); -} - -void D3D12Resource::setState(D3D12_RESOURCE_STATES state) -{ - m_prevState = state; - m_state = state; -} - -} // renderer_test diff --git a/tools/render-test/resource-d3d12.h b/tools/render-test/resource-d3d12.h deleted file mode 100644 index 1f0ba638b..000000000 --- a/tools/render-test/resource-d3d12.h +++ /dev/null @@ -1,178 +0,0 @@ -// resource-d3d12.h -#pragma once - -#define WIN32_LEAN_AND_MEAN -#define NOMINMAX -#include <Windows.h> -#undef WIN32_LEAN_AND_MEAN -#undef NOMINMAX - -#include <dxgi1_4.h> -#include <d3d12.h> - -#include "../../slang-com-ptr.h" -#include "d3d-util.h" - -namespace renderer_test { - -// Enables more conservative barriers - restoring the state of resources after they are used. -// Should not need to be enabled in normal builds, as the barriers should correctly sync resources -// If enabling fixes an issue it implies regular barriers are not correctly used. -#define SLANG_ENABLE_CONSERVATIVE_RESOURCE_BARRIERS 0 - -struct D3D12BarrierSubmitter -{ - enum { MAX_BARRIERS = 8 }; - - /// Expand one space to hold a barrier - SLANG_FORCE_INLINE D3D12_RESOURCE_BARRIER& expandOne() { return (m_numBarriers < MAX_BARRIERS) ? m_barriers[m_numBarriers++] : _expandOne(); } - /// Flush barriers to command list - SLANG_FORCE_INLINE void flush() { if (m_numBarriers > 0) _flush(); } - - /// Transition resource from prevState to nextState - void transition(ID3D12Resource* resource, D3D12_RESOURCE_STATES prevState, D3D12_RESOURCE_STATES nextState); - - /// Ctor - SLANG_FORCE_INLINE D3D12BarrierSubmitter(ID3D12GraphicsCommandList* commandList) : m_numBarriers(0), m_commandList(commandList) { } - /// Dtor - SLANG_FORCE_INLINE ~D3D12BarrierSubmitter() { flush(); } - -protected: - D3D12_RESOURCE_BARRIER& _expandOne(); - void _flush(); - - ID3D12GraphicsCommandList* m_commandList; - int m_numBarriers; - D3D12_RESOURCE_BARRIER m_barriers[MAX_BARRIERS]; -}; - -/*! \brief A class to simplify using Dx12 fences. - -A fence is a mechanism to track GPU work. This is achieved by having a counter that the CPU holds -called the current value. Calling nextSignal will increase the CPU counter, and add a fence -with that value to the commandQueue. When the GPU has completed all the work before the fence it will -update the completed value. This is typically used when -the CPU needs to know the GPU has finished some piece of work has completed. To do this the CPU -can check the completed value, and when it is greater or equal to the value returned by nextSignal the -CPU will know that all the work prior to when the nextSignal was added to the queue will have completed. - -NOTE! This cannot be used across threads, as for amongst other reasons SetEventOnCompletion -only works with a single value. - -Signal on the CommandQueue updates the fence on the GPU side. Signal on the fence object changes -the value on the CPU side (not used here). - -Useful article describing how Dx12 synchronization works: -https://msdn.microsoft.com/en-us/library/windows/desktop/dn899217%28v=vs.85%29.aspx -*/ -class D3D12CounterFence -{ -public: - /// Must be called before used - SlangResult init(ID3D12Device* device, uint64_t initialValue = 0); - /// Increases the counter, signals the queue and waits for the signal to be hit - void nextSignalAndWait(ID3D12CommandQueue* queue); - /// Signals with next counter value. Returns the value the signal was called on - uint64_t nextSignal(ID3D12CommandQueue* commandQueue); - /// Get the current value - SLANG_FORCE_INLINE uint64_t getCurrentValue() const { return m_currentValue; } - /// Get the completed value - SLANG_FORCE_INLINE uint64_t getCompletedValue() const { return m_fence->GetCompletedValue(); } - - /// Waits for the the specified value - void waitUntilCompleted(uint64_t completedValue); - - /// Ctor - D3D12CounterFence() :m_event(nullptr), m_currentValue(0) {} - /// Dtor - ~D3D12CounterFence(); - -protected: - HANDLE m_event; - Slang::ComPtr<ID3D12Fence> m_fence; - UINT64 m_currentValue; -}; - -/** The base class for resource types allows for tracking of state. It does not allow for setting of the resource though, such that -an interface can return a D3D12ResourceBase, and a client cant manipulate it's state, but it cannot replace/change the actual resource */ -struct D3D12ResourceBase -{ - /// Add a transition if necessary to the list - void transition(D3D12_RESOURCE_STATES nextState, D3D12BarrierSubmitter& submitter); - /// Get the current state - SLANG_FORCE_INLINE D3D12_RESOURCE_STATES getState() const { return m_state; } - - /// Get the associated resource - SLANG_FORCE_INLINE ID3D12Resource* getResource() const { return m_resource; } - - /// True if a resource is set - SLANG_FORCE_INLINE bool isSet() const { return m_resource != nullptr; } - - /// Coercible into ID3D12Resource - SLANG_FORCE_INLINE operator ID3D12Resource*() const { return m_resource; } - - /// restore previous state -#if SLANG_ENABLE_CONSERVATIVE_RESOURCE_BARRIERS - SLANG_FORCE_INLINE Void restore(D3D12BarrierSubmitter& submitter) { transition(m_prevState, submitter); } -#else - SLANG_FORCE_INLINE void restore(D3D12BarrierSubmitter& submitter) { SLANG_UNUSED(submitter) } -#endif - - /// Given the usage, flags, and format will return the most suitable format. Will return DXGI_UNKNOWN if combination is not possible - static DXGI_FORMAT calcFormat(D3DUtil::UsageType usage, ID3D12Resource* resource); - - /// Ctor - SLANG_FORCE_INLINE D3D12ResourceBase() : - m_state(D3D12_RESOURCE_STATE_COMMON), - m_prevState(D3D12_RESOURCE_STATE_COMMON), - m_resource(nullptr) - {} - -protected: - /// This is protected so as clients cannot slice the class, and so state tracking is lost - ~D3D12ResourceBase() {} - - ID3D12Resource* m_resource; ///< The resource (ref counted) - D3D12_RESOURCE_STATES m_state; ///< The current tracked expected state, if all associated transitions have completed on ID3D12CommandList - D3D12_RESOURCE_STATES m_prevState; ///< The previous state -}; - -struct D3D12Resource : public D3D12ResourceBase -{ - - /// Dtor - ~D3D12Resource() - { - if (m_resource) - { - m_resource->Release(); - } - } - - /// Initialize as committed resource - Slang::Result initCommitted(ID3D12Device* device, const D3D12_HEAP_PROPERTIES& heapProps, D3D12_HEAP_FLAGS heapFlags, const D3D12_RESOURCE_DESC& resourceDesc, D3D12_RESOURCE_STATES initState, const D3D12_CLEAR_VALUE * clearValue); - - /// Set a resource with an initial state - void setResource(ID3D12Resource* resource, D3D12_RESOURCE_STATES initialState); - /// Make the resource null - void setResourceNull(); - /// Returns the attached resource (with any ref counts) and sets to nullptr on this. - ID3D12Resource* detach(); - - /// Swaps the resource contents with the contents of the smart pointer - void swap(Slang::ComPtr<ID3D12Resource>& resourceInOut); - - /// Sets the current state of the resource (the current state is taken to be the future state once the command list has executed) - /// NOTE! This must be used with care, otherwise state tracking can be made incorrect. - void setState(D3D12_RESOURCE_STATES state); - - /// Set the debug name on a resource - static void setDebugName(ID3D12Resource* resource, const char* name); - - /// Set the the debug name on the resource - void setDebugName(const wchar_t* name); - /// Set the debug name - void setDebugName(const char* name); -}; - -} // renderer_test diff --git a/tools/render-test/shader-input-layout.h b/tools/render-test/shader-input-layout.h index 7537527ab..19a7e59d0 100644 --- a/tools/render-test/shader-input-layout.h +++ b/tools/render-test/shader-input-layout.h @@ -7,6 +7,8 @@ namespace renderer_test { +using namespace slang_graphics; + enum class ShaderInputType { Buffer, Texture, Sampler, CombinedTextureSampler diff --git a/tools/render-test/surface.cpp b/tools/render-test/surface.cpp deleted file mode 100644 index eabe555c3..000000000 --- a/tools/render-test/surface.cpp +++ /dev/null @@ -1,222 +0,0 @@ -// surface.cpp -#include "surface.h" - -#include <stdlib.h> -#include <stdio.h> - -#include "../../source/core/list.h" - -namespace renderer_test { -using namespace Slang; - -class MallocSurfaceAllocator: public SurfaceAllocator -{ - public: - - virtual Slang::Result allocate(int width, int height, Format format, int alignment, Surface& surface) override; - virtual void deallocate(Surface& surface) override; -}; - -static MallocSurfaceAllocator s_mallocSurfaceAllocator; - -/// Get the malloc allocator -/* static */SurfaceAllocator* SurfaceAllocator::getMallocAllocator() -{ - return &s_mallocSurfaceAllocator; -} - -Slang::Result MallocSurfaceAllocator::allocate(int width, int height, Format format, int alignment, Surface& surface) -{ - assert(surface.m_data == nullptr); - - // Calculate row size - - const int rowSizeInBytes = Surface::calcRowSize(format, width); - const int numRows = Surface::calcNumRows(format, height); - - alignment = (alignment <= 0) ? int(sizeof(void*)) : alignment; - // It must be a power of 2 - assert( ((alignment - 1) & alignment) == 0); - - // Align rowSize - const int alignedRowSizeInBytes = (rowSizeInBytes + alignment - 1) & -alignment; - - size_t totalSize = numRows * alignedRowSizeInBytes; - - uint8_t* data = (uint8_t*)::malloc(totalSize); - if (!data) - { - return SLANG_E_OUT_OF_MEMORY; - } - - surface.m_data = data; - surface.m_width = width; - surface.m_height = height; - surface.m_format = format; - surface.m_numRows = numRows; - surface.m_rowStrideInBytes = alignedRowSizeInBytes; - - surface.m_allocator = this; - return SLANG_OK; -} - -void MallocSurfaceAllocator::deallocate(Surface& surface) -{ - assert(surface.m_data); - // Make sure it's not an inverted, cos otherwise m_data is not the start address - assert(surface.m_rowStrideInBytes > 0); - ::free(surface.m_data); -} - -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Surface !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -/* static */int Surface::calcRowSize(Format format, int width) -{ - size_t pixelSize = RendererUtil::getFormatSize(format); - if (pixelSize == 0) - { - return 0; - } - return int(pixelSize * width); -} - -/* static */int Surface::calcNumRows(Format format, int height) -{ - // Don't have any compressed types, so number of rows is same as the height - return height; -} - -void Surface::init() -{ - m_width = 0; - m_height = 0; - m_format = Format::Unknown; - m_data = nullptr; - m_numRows = 0; - m_rowStrideInBytes = 0; - // NOTE! does not clear the allocator. - // If called with an allocation memory will leak! -} - -Surface::~Surface() -{ - if (m_data && m_allocator) - { - m_allocator->deallocate(*this); - } -} - -void Surface::deallocate() -{ - if (m_data && m_allocator) - { - m_allocator->deallocate(*this); - init(); - } -} - -Result Surface::allocate(int width, int height, Format format, int alignment, SurfaceAllocator* allocator) -{ - deallocate(); - allocator = allocator ? allocator : m_allocator; - if (!allocator) - { - // An allocator needs to be set on the surface, or one passed in. - return SLANG_FAIL; - } - return allocator->allocate(width, height, format, alignment, *this); -} - -void Surface::setUnowned(int width, int height, Format format, int strideInBytes, void* data) -{ - deallocate(); - - // This is unowned - m_allocator = nullptr; - - m_width = width; - m_height = height; - m_format = format; - m_rowStrideInBytes = strideInBytes; - m_data = (uint8_t*)data; - - m_numRows = Surface::calcNumRows(format, height); - - const int rowSizeInBytes = Surface::calcRowSize(format, width); - assert((strideInBytes > 0 && rowSizeInBytes <= strideInBytes) || (strideInBytes < 0 && rowSizeInBytes <= -strideInBytes)); -} - -void Surface::zeroContents() -{ - const int rowSizeInBytes = Surface::calcRowSize(m_format, m_width); - - const int stride = m_rowStrideInBytes; - uint8_t* dst = m_data; - - for (int i = 0; i < m_numRows; i++, dst += stride) - { - ::memset(dst, 0, rowSizeInBytes); - } -} - -void Surface::flipInplaceVertically() -{ - // Can only flip when m_height matches number of rows - assert(m_numRows == m_height); - - const int rowSizeInBytes = Surface::calcRowSize(m_format, m_width); - if (rowSizeInBytes <= 0 || m_numRows <= 1) - { - return; - } - - uint8_t* top = m_data; - uint8_t* bottom = m_data + (m_numRows - 1) * m_rowStrideInBytes; - - List<uint8_t> bufferList; - bufferList.SetSize(rowSizeInBytes); - uint8_t* buffer = bufferList.Buffer(); - - const int stride = m_rowStrideInBytes; - - const int num = m_height >> 1; - for (int i = 0; i < num; ++i, top += stride, bottom -= stride) - { - ::memcpy(buffer, top, rowSizeInBytes); - ::memcpy(top, bottom, rowSizeInBytes); - ::memcpy(bottom, buffer, rowSizeInBytes); - } -} - -SlangResult Surface::set(int width, int height, Format format, int srcRowStride, const void* data, SurfaceAllocator* allocator) -{ - if (hasContents() && m_width == width && m_height == height && m_format == format) - { - // I can just overwrite the contents that is there - } - else - { - SLANG_RETURN_ON_FAIL(allocate(width, height, format, 0, allocator)); - } - - // Okay just need to set the contents - - { - const size_t rowSize = calcRowSize(format, width); - - const uint8_t* srcRow = (const uint8_t*)data; - uint8_t* dstRow = (uint8_t*)m_data; - - for (int i = 0; i < m_numRows; i++) - { - ::memcpy(dstRow, srcRow, rowSize); - - srcRow += srcRowStride; - dstRow += m_rowStrideInBytes; - } - } - - return SLANG_OK; -} - -} // renderer_test diff --git a/tools/render-test/surface.h b/tools/render-test/surface.h deleted file mode 100644 index c7460238f..000000000 --- a/tools/render-test/surface.h +++ /dev/null @@ -1,86 +0,0 @@ -// surface.h -#pragma once - -#include "render.h" - -namespace renderer_test { - -class Surface; - -class SurfaceAllocator -{ - public: - virtual Slang::Result allocate(int width, int height, Format format, int alignment, Surface& surface) = 0; - virtual void deallocate(Surface& surface) = 0; - - /// Get the malloc allocator - static SurfaceAllocator* getMallocAllocator(); -}; - -class Surface -{ - public: - - enum - { - kDefaultAlignment = sizeof(void*) - }; - - /// Allocate - Slang::Result allocate(int width, int height, Format format, int alignment = kDefaultAlignment, SurfaceAllocator* allocator = nullptr); - - /// Deallocate contents - void deallocate(); - /// Initialize contents (zero sized, no data). Note that the allocator pointer is left as is - void init(); - - /// Set unowned - void setUnowned(int width, int height, Format format, int strideInBytes, void* data); - - /// Set the contents - the memory will be owned by this surface (ie will be freed by the allocator when goes out of scope or is deallocated) - Slang::Result set(int width, int height, Format format, int strideInBytes, const void* data, SurfaceAllocator* allocator); - - template <typename T> - T* calcNextRow(T* ptr) const { return (T*)calcNextRow((void*)ptr); } - template <typename T> - const T* calcNextRow(const T* ptr) const { return (const T*)calcNextRow((const void*)ptr); } - - void* calcNextRow(void* ptr) const { return (void*)(((uint8_t*)ptr) + m_rowStrideInBytes); } - const void* calcNextRow(const void* ptr) const { return (const void*)(((const uint8_t*)ptr) + m_rowStrideInBytes); } - - /// Writes zero to all of the contents - void zeroContents(); - - /// Flips the contents vertically in place - void flipInplaceVertically(); - - /// True if has some contents - bool hasContents() const { return m_data != nullptr; } - - /// Ctor - Surface() : - m_allocator(nullptr) - { - init(); - } - /// Dtor - ~Surface(); - - /// Get the size of the row in bytes - static int calcRowSize(Format format, int width); - /// Calculates the number of rows - static int calcNumRows(Format format, int height); - - int m_width; - int m_height; - Format m_format; - - uint8_t* m_data; /// The data that makes up the image. If nullptr, has no data. Pointer to first 'row' of the image. - - int m_numRows; ///< Total amount of rows (typically same as height, but in compressed formats may be less) - int m_rowStrideInBytes; ///< The number of bytes between rows - - SurfaceAllocator* m_allocator; ///< Can be null if so contents is 'unowned', if set -}; - -} // renderer_test diff --git a/tools/render-test/vk-api.cpp b/tools/render-test/vk-api.cpp deleted file mode 100644 index df222d8ad..000000000 --- a/tools/render-test/vk-api.cpp +++ /dev/null @@ -1,138 +0,0 @@ -// vk-api.cpp -#include "vk-api.h" - -#include "../../source/core/list.h" - -namespace renderer_test { -using namespace Slang; - -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! VulkanApi !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -#define VK_API_CHECK_FUNCTION(x) && (x != nullptr) -#define VK_API_CHECK_FUNCTIONS(FUNCTION_LIST) true FUNCTION_LIST(VK_API_CHECK_FUNCTION) - -bool VulkanApi::areDefined(ProcType type) const -{ - switch (type) - { - case ProcType::Global: return VK_API_CHECK_FUNCTIONS(VK_API_ALL_GLOBAL_PROCS); - case ProcType::Instance: return VK_API_CHECK_FUNCTIONS(VK_API_ALL_INSTANCE_PROCS); - case ProcType::Device: return VK_API_CHECK_FUNCTIONS(VK_API_ALL_DEVICE_PROCS); - default: - { - assert(!"Unhandled type"); - return false; - } - } -} - -Slang::Result VulkanApi::initGlobalProcs(const VulkanModule& module) -{ -#define VK_API_GET_GLOBAL_PROC(x) x = (PFN_##x)module.getFunction(#x); - - // Initialize all the global functions - VK_API_ALL_GLOBAL_PROCS(VK_API_GET_GLOBAL_PROC) - - if (!areDefined(ProcType::Global)) - { - return SLANG_FAIL; - } - m_module = &module; - return SLANG_OK; -} - -Slang::Result VulkanApi::initInstanceProcs(VkInstance instance) -{ - assert(instance && vkGetInstanceProcAddr != nullptr); - -#define VK_API_GET_INSTANCE_PROC(x) x = (PFN_##x)vkGetInstanceProcAddr(instance, #x); - - VK_API_ALL_INSTANCE_PROCS(VK_API_GET_INSTANCE_PROC) - - if (!areDefined(ProcType::Instance)) - { - return SLANG_FAIL; - } - - m_instance = instance; - return SLANG_OK; -} - -Slang::Result VulkanApi::initPhysicalDevice(VkPhysicalDevice physicalDevice) -{ - assert(m_physicalDevice == VK_NULL_HANDLE); - m_physicalDevice = physicalDevice; - - vkGetPhysicalDeviceProperties(m_physicalDevice, &m_deviceProperties); - vkGetPhysicalDeviceFeatures(m_physicalDevice, &m_deviceFeatures); - vkGetPhysicalDeviceMemoryProperties(m_physicalDevice, &m_deviceMemoryProperties); - - return SLANG_OK; -} - -Slang::Result VulkanApi::initDeviceProcs(VkDevice device) -{ - assert(m_instance && device && vkGetDeviceProcAddr != nullptr); - -#define VK_API_GET_DEVICE_PROC(x) x = (PFN_##x)vkGetDeviceProcAddr(device, #x); - - VK_API_ALL_DEVICE_PROCS(VK_API_GET_DEVICE_PROC) - - if (!areDefined(ProcType::Device)) - { - return SLANG_FAIL; - } - - m_device = device; - return SLANG_OK; -} - -int VulkanApi::findMemoryTypeIndex(uint32_t typeBits, VkMemoryPropertyFlags properties) const -{ - assert(typeBits); - - const int numMemoryTypes = int(m_deviceMemoryProperties.memoryTypeCount); - - // bit holds current test bit against typeBits. Ie bit == 1 << typeBits - - uint32_t bit = 1; - for (int i = 0; i < numMemoryTypes; ++i, bit += bit) - { - auto const& memoryType = m_deviceMemoryProperties.memoryTypes[i]; - if ((typeBits & bit) && (memoryType.propertyFlags & properties) == properties) - { - return i; - } - } - - //assert(!"failed to find a usable memory type"); - return -1; -} - -int VulkanApi::findQueue(VkQueueFlags reqFlags) const -{ - assert(m_physicalDevice != VK_NULL_HANDLE); - - uint32_t numQueueFamilies = 0; - vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &numQueueFamilies, nullptr); - - Slang::List<VkQueueFamilyProperties> queueFamilies; - queueFamilies.SetSize(numQueueFamilies); - vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &numQueueFamilies, queueFamilies.Buffer()); - - // Find a queue that can service our needs - //VkQueueFlags reqQueueFlags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT; - - int queueFamilyIndex = -1; - for (int i = 0; i < int(numQueueFamilies); ++i) - { - if ((queueFamilies[i].queueFlags & reqFlags) == reqFlags) - { - return i; - } - } - - return -1; -} - -} // renderer_test diff --git a/tools/render-test/vk-api.h b/tools/render-test/vk-api.h deleted file mode 100644 index 521d6301d..000000000 --- a/tools/render-test/vk-api.h +++ /dev/null @@ -1,196 +0,0 @@ -// vk-api.h -#pragma once - -#include "vk-module.h" - -namespace renderer_test { - -#define VK_API_GLOBAL_PROCS(x) \ - x(vkGetInstanceProcAddr) \ - x(vkCreateInstance) \ - /* */ - -#define VK_API_INSTANCE_PROCS(x) \ - x(vkCreateDevice) \ - x(vkCreateDebugReportCallbackEXT) \ - x(vkDestroyDebugReportCallbackEXT) \ - x(vkDebugReportMessageEXT) \ - x(vkEnumeratePhysicalDevices) \ - x(vkGetPhysicalDeviceProperties) \ - x(vkGetPhysicalDeviceFeatures) \ - x(vkGetPhysicalDeviceMemoryProperties) \ - x(vkGetPhysicalDeviceQueueFamilyProperties) \ - x(vkGetPhysicalDeviceFormatProperties) \ - x(vkGetDeviceProcAddr) \ - /* */ - -#define VK_API_DEVICE_PROCS(x) \ - x(vkCreateDescriptorPool) \ - x(vkDestroyDescriptorPool) \ - x(vkGetDeviceQueue) \ - x(vkQueueSubmit) \ - x(vkQueueWaitIdle) \ - x(vkCreateBuffer) \ - x(vkAllocateMemory) \ - x(vkMapMemory) \ - x(vkUnmapMemory) \ - x(vkCmdCopyBuffer) \ - x(vkDestroyBuffer) \ - x(vkFreeMemory) \ - x(vkCreateDescriptorSetLayout) \ - x(vkDestroyDescriptorSetLayout) \ - x(vkAllocateDescriptorSets) \ - x(vkUpdateDescriptorSets) \ - x(vkCreatePipelineLayout) \ - x(vkDestroyPipelineLayout) \ - x(vkCreateComputePipelines) \ - x(vkCreateGraphicsPipelines) \ - x(vkDestroyPipeline) \ - x(vkCreateShaderModule) \ - x(vkDestroyShaderModule) \ - x(vkCreateFramebuffer) \ - x(vkDestroyFramebuffer) \ - x(vkCreateImage) \ - x(vkDestroyImage) \ - x(vkCreateImageView) \ - x(vkDestroyImageView) \ - x(vkCreateRenderPass) \ - x(vkDestroyRenderPass) \ - x(vkCreateCommandPool) \ - x(vkDestroyCommandPool) \ - x(vkCreateSampler) \ - x(vkDestroySampler) \ - x(vkCreateBufferView) \ - x(vkDestroyBufferView) \ - \ - x(vkGetBufferMemoryRequirements) \ - x(vkGetImageMemoryRequirements) \ - \ - x(vkCmdBindPipeline) \ - x(vkCmdBindDescriptorSets) \ - x(vkCmdDispatch) \ - x(vkCmdDraw) \ - x(vkCmdSetScissor) \ - x(vkCmdSetViewport) \ - x(vkCmdBindVertexBuffers) \ - x(vkCmdBindIndexBuffer) \ - x(vkCmdBeginRenderPass) \ - x(vkCmdEndRenderPass) \ - x(vkCmdPipelineBarrier) \ - x(vkCmdCopyBufferToImage)\ - \ - x(vkCreateFence) \ - x(vkDestroyFence) \ - x(vkResetFences) \ - x(vkGetFenceStatus) \ - x(vkWaitForFences) \ - \ - x(vkCreateSemaphore) \ - x(vkDestroySemaphore) \ - \ - x(vkCreateEvent) \ - x(vkDestroyEvent) \ - x(vkGetEventStatus) \ - x(vkSetEvent) \ - x(vkResetEvent) \ - \ - x(vkFreeCommandBuffers) \ - x(vkAllocateCommandBuffers) \ - x(vkBeginCommandBuffer) \ - x(vkEndCommandBuffer) \ - x(vkResetCommandBuffer) \ - \ - x(vkBindImageMemory) \ - x(vkBindBufferMemory) \ - /* */ - -#if SLANG_WINDOWS_FAMILY -# define VK_API_INSTANCE_PLATFORM_KHR_PROCS(x) \ - x(vkCreateWin32SurfaceKHR) \ - /* */ -#else -# define VK_API_INSTANCE_PLATFORM_KHR_PROCS(x) \ - x(vkCreateXlibSurfaceKHR) \ - /* */ -#endif - -#define VK_API_INSTANCE_KHR_PROCS(x) \ - VK_API_INSTANCE_PLATFORM_KHR_PROCS(x) \ - x(vkGetPhysicalDeviceSurfaceSupportKHR) \ - x(vkGetPhysicalDeviceSurfaceFormatsKHR) \ - x(vkGetPhysicalDeviceSurfacePresentModesKHR) \ - x(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) \ - x(vkDestroySurfaceKHR) \ - /* */ - -#define VK_API_DEVICE_KHR_PROCS(x) \ - x(vkQueuePresentKHR) \ - x(vkCreateSwapchainKHR) \ - x(vkGetSwapchainImagesKHR) \ - x(vkDestroySwapchainKHR) \ - x(vkAcquireNextImageKHR) \ - /* */ - -#define VK_API_ALL_GLOBAL_PROCS(x) \ - VK_API_GLOBAL_PROCS(x) - -#define VK_API_ALL_INSTANCE_PROCS(x) \ - VK_API_INSTANCE_PROCS(x) \ - VK_API_INSTANCE_KHR_PROCS(x) - -#define VK_API_ALL_DEVICE_PROCS(x) \ - VK_API_DEVICE_PROCS(x) \ - VK_API_DEVICE_KHR_PROCS(x) - -#define VK_API_ALL_PROCS(x) \ - VK_API_ALL_GLOBAL_PROCS(x) \ - VK_API_ALL_INSTANCE_PROCS(x) \ - VK_API_ALL_DEVICE_PROCS(x) \ - /* */ - -#define VK_API_DECLARE_PROC(NAME) PFN_##NAME NAME = nullptr; - -struct VulkanApi -{ - VK_API_ALL_PROCS(VK_API_DECLARE_PROC) - - enum class ProcType - { - Global, - Instance, - Device, - }; - - /// Returns true if all the functions in the class are defined - bool areDefined(ProcType type) const; - - /// Sets up global parameters - Slang::Result initGlobalProcs(const VulkanModule& module); - /// Initialize the instance functions - Slang::Result initInstanceProcs(VkInstance instance); - - /// Called before initDevice - Slang::Result initPhysicalDevice(VkPhysicalDevice physicalDevice); - - /// Initialize the device functions - Slang::Result initDeviceProcs(VkDevice device); - - /// Type bits control which indices are tested against bit 0 for testing at index 0 - /// properties - a memory type must have all the bits set as passed in - /// Returns -1 if couldn't find an appropriate memory type index - int findMemoryTypeIndex(uint32_t typeBits, VkMemoryPropertyFlags properties) const; - - /// Given queue required flags, finds a queue - int findQueue(VkQueueFlags reqFlags) const; - - const VulkanModule* m_module = nullptr; ///< Module this was all loaded from - VkInstance m_instance = VK_NULL_HANDLE; - VkDevice m_device = VK_NULL_HANDLE; - VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE; - - VkPhysicalDeviceProperties m_deviceProperties; - VkPhysicalDeviceFeatures m_deviceFeatures; - VkPhysicalDeviceMemoryProperties m_deviceMemoryProperties; -}; - -} // renderer_test diff --git a/tools/render-test/vk-device-queue.cpp b/tools/render-test/vk-device-queue.cpp deleted file mode 100644 index d40442c22..000000000 --- a/tools/render-test/vk-device-queue.cpp +++ /dev/null @@ -1,199 +0,0 @@ -// vk-device-queue.cpp -#include "vk-device-queue.h" - -#include <stdlib.h> -#include <stdio.h> -#include <assert.h> - -namespace renderer_test { -using namespace Slang; - -VulkanDeviceQueue::~VulkanDeviceQueue() -{ - for (int i = 0; i < int(EventType::CountOf); ++i) - { - m_api->vkDestroySemaphore(m_api->m_device, m_semaphores[i], nullptr); - } - - for (int i = 0; i < m_numCommandBuffers; i++) - { - m_api->vkFreeCommandBuffers(m_api->m_device, m_commandPool, 1, &m_commandBuffers[i]); - m_api->vkDestroyFence(m_api->m_device, m_fences[i].fence, nullptr); - } - m_api->vkDestroyCommandPool(m_api->m_device, m_commandPool, nullptr); -} - -SlangResult VulkanDeviceQueue::init(const VulkanApi& api, VkQueue queue, int queueIndex) -{ - assert(m_api == nullptr); - m_api = &api; - - for (int i = 0; i < int(EventType::CountOf); ++i) - { - m_semaphores[i] = VK_NULL_HANDLE; - m_currentSemaphores[i] = VK_NULL_HANDLE; - } - - m_numCommandBuffers = kMaxCommandBuffers; - m_queueIndex = queueIndex; - - m_queue = queue; - - VkCommandPoolCreateInfo poolCreateInfo = {}; - poolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - poolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - - poolCreateInfo.queueFamilyIndex = queueIndex; - - api.vkCreateCommandPool(api.m_device, &poolCreateInfo, nullptr, &m_commandPool); - - VkCommandBufferAllocateInfo commandInfo = {}; - commandInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - commandInfo.commandPool = m_commandPool; - commandInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - commandInfo.commandBufferCount = 1; - - VkFenceCreateInfo fenceCreateInfo = {}; - fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fenceCreateInfo.flags = 0; // VK_FENCE_CREATE_SIGNALED_BIT; - - for (int i = 0; i < m_numCommandBuffers; i++) - { - Fence& fence = m_fences[i]; - - api.vkAllocateCommandBuffers(api.m_device, &commandInfo, &m_commandBuffers[i]); - - api.vkCreateFence(api.m_device, &fenceCreateInfo, nullptr, &fence.fence); - fence.active = false; - fence.value = 0; - } - - VkSemaphoreCreateInfo semaphoreCreateInfo = {}; - semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - - for (int i = 0; i < int(EventType::CountOf); ++i) - { - api.vkCreateSemaphore(api.m_device, &semaphoreCreateInfo, nullptr, &m_semaphores[i]); - } - - // Second step of flush to prime command buffer - flushStepB(); - - return SLANG_OK; -} - -void VulkanDeviceQueue::flushStepA() -{ - m_api->vkEndCommandBuffer(m_commandBuffer); - - VkPipelineStageFlags stageFlags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - - VkSubmitInfo submitInfo = {}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - - // Wait semaphores - if (isCurrent(EventType::BeginFrame)) - { - submitInfo.waitSemaphoreCount = 1; - submitInfo.pWaitSemaphores = &m_currentSemaphores[int(EventType::BeginFrame)]; - } - - submitInfo.pWaitDstStageMask = &stageFlags; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &m_commandBuffer; - - // Signal semaphores - if (isCurrent(EventType::EndFrame)) - { - submitInfo.signalSemaphoreCount = 1; - submitInfo.pSignalSemaphores = &m_currentSemaphores[int(EventType::EndFrame)]; - } - - Fence& fence = m_fences[m_commandBufferIndex]; - - m_api->vkQueueSubmit(m_queue, 1, &submitInfo, fence.fence); - - // mark signaled fence value - fence.value = m_nextFenceValue; - fence.active = true; - - // increment fence value - m_nextFenceValue++; - - // No longer waiting on this semaphore - makeCompleted(EventType::BeginFrame); -} - -void VulkanDeviceQueue::_updateFenceAtIndex( int fenceIndex, bool blocking) -{ - Fence& fence = m_fences[fenceIndex]; - - if (fence.active) - { - uint64_t timeout = blocking ? ~uint64_t(0) : 0; - - if (VK_SUCCESS == m_api->vkWaitForFences(m_api->m_device, 1, &fence.fence, VK_TRUE, timeout)) - { - m_api->vkResetFences(m_api->m_device, 1, &fence.fence); - - fence.active = false; - - if (fence.value > m_lastFenceCompleted) - { - m_lastFenceCompleted = fence.value; - } - } - } -} - -void VulkanDeviceQueue::flushStepB() -{ - m_commandBufferIndex = (m_commandBufferIndex + 1) % m_numCommandBuffers; - m_commandBuffer = m_commandBuffers[m_commandBufferIndex]; - - // non-blocking update of fence values - for (int i = 0; i < m_numCommandBuffers; ++i) - { - _updateFenceAtIndex(i, false); - } - - // blocking update of fence values - _updateFenceAtIndex(m_commandBufferIndex, true); - - m_api->vkResetCommandBuffer(m_commandBuffer, 0); - - //m_api.vkResetCommandPool(m_api->m_device, m_commandPool, 0); - - VkCommandBufferBeginInfo beginInfo = {}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - - m_api->vkBeginCommandBuffer(m_commandBuffer, &beginInfo); -} - -void VulkanDeviceQueue::flush() -{ - flushStepA(); - flushStepB(); -} - -void VulkanDeviceQueue::flushAndWait() -{ - flush(); - waitForIdle(); -} - -VkSemaphore VulkanDeviceQueue::makeCurrent(EventType eventType) -{ - assert(!isCurrent(eventType)); - VkSemaphore semaphore = m_semaphores[int(eventType)]; - m_currentSemaphores[int(eventType)] = semaphore; - return semaphore; -} - -void VulkanDeviceQueue::makeCompleted(EventType eventType) -{ - m_currentSemaphores[int(eventType)] = VK_NULL_HANDLE; -} - -} // renderer_test diff --git a/tools/render-test/vk-device-queue.h b/tools/render-test/vk-device-queue.h deleted file mode 100644 index 8381f5166..000000000 --- a/tools/render-test/vk-device-queue.h +++ /dev/null @@ -1,94 +0,0 @@ -// vk-swap-chain.h -#pragma once - -#include "vk-api.h" - -namespace renderer_test { - -struct VulkanDeviceQueue -{ - enum - { - kMaxCommandBuffers = 8, - }; - - enum class EventType - { - BeginFrame, - EndFrame, - CountOf, - }; - - /// Initialize - must be called before anything else can be done - SlangResult init(const VulkanApi& api, VkQueue queue, int queueIndex); - - /// Flushes the current command list, and steps to next (internally this is equivalent to a stepA followed by stepB) - void flush(); - /// Performs a full flush, and then waits for idle. - void flushAndWait(); - - /// Blocks until all work submitted to GPU has completed - void waitForIdle() { m_api->vkQueueWaitIdle(m_queue); } - - /// Get the graphics queue index (as set on init) - int getQueueIndex() const { return m_queueIndex; } - - /// Make the specified event 'current' - meaning it's semaphore must be waited on - VkSemaphore makeCurrent(EventType eventType); - /// Makes the event no longer required to be waited on - void makeCompleted(EventType eventType); - /// Returns true if the event is already current - SLANG_FORCE_INLINE bool isCurrent(EventType eventType) const { return m_currentSemaphores[int(eventType)] != VK_NULL_HANDLE; } - - /// Get the command buffer - VkCommandBuffer getCommandBuffer() const { return m_commandBuffer; } - - /// Get the queue - VkQueue getQueue() const { return m_queue; } - - /// Get the API - const VulkanApi* getApi() const { return m_api; } - - /// Flushes the current command list - void flushStepA(); - /// Steps to next command buffer and opens. May block if command buffer is still in use - void flushStepB(); - - /// Dtor - ~VulkanDeviceQueue(); - - protected: - - struct Fence - { - VkFence fence; - bool active; - uint64_t value; - }; - - void _updateFenceAtIndex(int fenceIndex, bool blocking); - - VkQueue m_queue = VK_NULL_HANDLE; - - VkCommandPool m_commandPool = VK_NULL_HANDLE; - int m_numCommandBuffers = 0; - int m_commandBufferIndex = 0; - // There are the same amount of command buffers as fences - VkCommandBuffer m_commandBuffers[kMaxCommandBuffers] = { VK_NULL_HANDLE }; - - Fence m_fences[kMaxCommandBuffers] = { {VK_NULL_HANDLE, 0, 0u} }; - - VkCommandBuffer m_commandBuffer = VK_NULL_HANDLE; - - VkSemaphore m_semaphores[int(EventType::CountOf)]; - VkSemaphore m_currentSemaphores[int(EventType::CountOf)]; - - uint64_t m_lastFenceCompleted = 1; - uint64_t m_nextFenceValue = 2; - - int m_queueIndex = 0; - - const VulkanApi* m_api = nullptr; -}; - -} // renderer_test diff --git a/tools/render-test/vk-module.cpp b/tools/render-test/vk-module.cpp deleted file mode 100644 index e98bd08cd..000000000 --- a/tools/render-test/vk-module.cpp +++ /dev/null @@ -1,76 +0,0 @@ -// module.cpp -#include "vk-module.h" - -#include <stdlib.h> -#include <stdio.h> -#include <assert.h> - -#if SLANG_WINDOWS_FAMILY -# include <windows.h> -#else -# include <dlfcn.h> -#endif - -namespace renderer_test { -using namespace Slang; - -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! VulkanModule !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -Slang::Result VulkanModule::init() -{ - if (isInitialized()) - { - destroy(); - return SLANG_OK; - } - - const char* dynamicLibraryName = "Unknown"; - -#if SLANG_WINDOWS_FAMILY - dynamicLibraryName = "vulkan-1.dll"; - HMODULE module = ::LoadLibraryA(dynamicLibraryName); - m_module = (void*)module; -#else - dynamicLibraryName = "libvulkan.so.1"; - m_module = dlopen(dynamicLibraryName, RTLD_NOW); -#endif - - if (!m_module) - { - fprintf(stderr, "error: failed load '%s'\n", dynamicLibraryName); - return SLANG_FAIL; - } - - return SLANG_OK; -} - -PFN_vkVoidFunction VulkanModule::getFunction(const char* name) const -{ - assert(m_module); - if (!m_module) - { - return nullptr; - } -#if SLANG_WINDOWS_FAMILY - return (PFN_vkVoidFunction)::GetProcAddress((HMODULE)m_module, name); -#else - return (PFN_vkVoidFunction)dlsym(m_module, name); -#endif -} - -void VulkanModule::destroy() -{ - if (!isInitialized()) - { - return; - } - -#if SLANG_WINDOWS_FAMILY - ::FreeLibrary((HMODULE)m_module); -#else - dlclose(m_module); -#endif - m_module = nullptr; -} - -} // renderer_test diff --git a/tools/render-test/vk-module.h b/tools/render-test/vk-module.h deleted file mode 100644 index 0aed2303f..000000000 --- a/tools/render-test/vk-module.h +++ /dev/null @@ -1,39 +0,0 @@ -// vk-module.h -#pragma once - -#include "../../slang.h" - -#include "../../slang-com-helper.h" - -#if SLANG_WINDOWS_FAMILY -# define VK_USE_PLATFORM_WIN32_KHR 1 -#else -# define VK_USE_PLATFORM_XLIB_KHR 1 -#endif - -#define VK_NO_PROTOTYPES -#include <vulkan/vulkan.h> - -namespace renderer_test { - -struct VulkanModule -{ - /// true if has been initialized - SLANG_FORCE_INLINE bool isInitialized() const { return m_module != nullptr; } - - /// Get a function by name - PFN_vkVoidFunction getFunction(const char* name) const; - - /// Initialize - Slang::Result init(); - /// Destroy - void destroy(); - - /// Dtor - ~VulkanModule() { destroy(); } - - protected: - void* m_module = nullptr; -}; - -} // renderer_test diff --git a/tools/render-test/vk-swap-chain.cpp b/tools/render-test/vk-swap-chain.cpp deleted file mode 100644 index 7b8b6221c..000000000 --- a/tools/render-test/vk-swap-chain.cpp +++ /dev/null @@ -1,421 +0,0 @@ -// vk-swap-chain.cpp -#include "vk-swap-chain.h" - -#include "vk-util.h" - -#include "../../source/core/list.h" - -#include <stdlib.h> -#include <stdio.h> - -namespace renderer_test { -using namespace Slang; - -static int _indexOf(List<VkSurfaceFormatKHR>& formatsIn, VkFormat format) -{ - const int numFormats = int(formatsIn.Count()); - const VkSurfaceFormatKHR* formats = formatsIn.Buffer(); - - for (int i = 0; i < numFormats; ++i) - { - if (formats[i].format == format) - { - return i; - } - } - return -1; -} - -SlangResult VulkanSwapChain::init(VulkanDeviceQueue* deviceQueue, const Desc& descIn, const PlatformDesc* platformDescIn) -{ - assert(platformDescIn); - - m_deviceQueue = deviceQueue; - m_api = deviceQueue->getApi(); - - // Make sure it's not set initially - m_format = VK_FORMAT_UNDEFINED; - - Desc desc(descIn); - -#if SLANG_WINDOWS_FAMILY - const WinPlatformDesc* platformDesc = static_cast<const WinPlatformDesc*>(platformDescIn); - _setPlatformDesc(*platformDesc); - - VkWin32SurfaceCreateInfoKHR surfaceCreateInfo = {}; - surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; - surfaceCreateInfo.hinstance = platformDesc->m_hinstance; - surfaceCreateInfo.hwnd = platformDesc->m_hwnd; - - SLANG_VK_RETURN_ON_FAIL(m_api->vkCreateWin32SurfaceKHR(m_api->m_instance, &surfaceCreateInfo, nullptr, &m_surface)); -#else - const XPlatformDesc* platformDesc = static_cast<const XPlatformDesc*>(platformDescIn); - _setPlatformDesc(*platformDesc); - - VkXlibSurfaceCreateInfoKHR surfaceCreateInfo = {}; - surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; - surfaceCreateInfo.dpy = platformDesc->m_display; - surfaceCreateInfo.window = platformDesc->m_window; - - SLANG_VK_RETURN_ON_FAIL(m_api->vkCreateXlibSurfaceKHR(m_api->m_instance, &surfaceCreateInfo, nullptr, &m_surface)); -#endif - - VkBool32 supported = false; - m_api->vkGetPhysicalDeviceSurfaceSupportKHR(m_api->m_physicalDevice, deviceQueue->getQueueIndex(), m_surface, &supported); - - uint32_t numSurfaceFormats = 0; - List<VkSurfaceFormatKHR> surfaceFormats; - m_api->vkGetPhysicalDeviceSurfaceFormatsKHR(m_api->m_physicalDevice, m_surface, &numSurfaceFormats, nullptr); - surfaceFormats.SetSize(int(numSurfaceFormats)); - m_api->vkGetPhysicalDeviceSurfaceFormatsKHR(m_api->m_physicalDevice, m_surface, &numSurfaceFormats, surfaceFormats.Buffer()); - - // Look for a suitable format - List<VkFormat> formats; - formats.Add(VulkanUtil::getVkFormat(desc.m_format)); - // HACK! To check for a different format if couldn't be found - if (descIn.m_format == Format::RGBA_Unorm_UInt8) - { - formats.Add(VK_FORMAT_B8G8R8A8_UNORM); - } - - for(int i = 0; i < int(formats.Count()); ++i) - { - VkFormat format = formats[i]; - if (_indexOf(surfaceFormats, format) >= 0) - { - m_format = format; - } - } - - if (m_format == VK_FORMAT_UNDEFINED) - { - return SLANG_FAIL; - } - - // Save the desc - m_desc = desc; - - SLANG_RETURN_ON_FAIL(_createSwapChain()); - - m_desc = desc; - return SLANG_OK; -} - -void VulkanSwapChain::getWindowSize(int* widthOut, int* heightOut) const -{ -#if SLANG_WINDOWS_FAMILY - auto platformDesc = _getPlatformDesc<WinPlatformDesc>(); - - RECT rc; - ::GetClientRect(platformDesc->m_hwnd, &rc); - *widthOut = rc.right - rc.left; - *heightOut = rc.bottom - rc.top; -#else - auto platformDesc = _getPlatformDesc<XPlatformDesc>(); - - XWindowAttributes winAttr = {}; - XGetWindowAttributes(platformDesc->m_display, platformDesc->m_window, &winAttr); - - *widthOut = winAttr.width; - *heightOut = winAttr.height; -#endif -} - -SlangResult VulkanSwapChain::_createFrameBuffers(VkRenderPass renderPass) -{ - assert(renderPass != VK_NULL_HANDLE); - - for (int i = 0; i < int(m_images.Count()); ++i) - { - Image& image = m_images[i]; - VkImageView attachments[] = - { - image.m_imageView - }; - - VkFramebufferCreateInfo framebufferInfo = {}; - framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - framebufferInfo.renderPass = renderPass; - framebufferInfo.attachmentCount = 1; - framebufferInfo.pAttachments = attachments; - framebufferInfo.width = m_width; - framebufferInfo.height = m_height; - framebufferInfo.layers = 1; - - SLANG_VK_RETURN_ON_FAIL(m_api->vkCreateFramebuffer(m_api->m_device, &framebufferInfo, nullptr, &image.m_frameBuffer)); - } - - return SLANG_OK; -} - -void VulkanSwapChain::_destroyFrameBuffers() -{ - for (int i = 0; i < int(m_images.Count()); ++i) - { - Image& image = m_images[i]; - if (image.m_frameBuffer != VK_NULL_HANDLE) - { - m_api->vkDestroyFramebuffer(m_api->m_device, image.m_frameBuffer, nullptr); - image.m_frameBuffer = VK_NULL_HANDLE; - } - } -} - -SlangResult VulkanSwapChain::createFrameBuffers(VkRenderPass renderPass) -{ - if (m_renderPass != VK_NULL_HANDLE) - { - _destroyFrameBuffers(); - m_renderPass = VK_NULL_HANDLE; - } - if (renderPass != VK_NULL_HANDLE) - { - SLANG_RETURN_ON_FAIL(_createFrameBuffers(renderPass)); - } - m_renderPass = renderPass; - return SLANG_OK; -} - -SlangResult VulkanSwapChain::_createSwapChain() -{ - if (hasValidSwapChain()) - { - return SLANG_OK; - } - - int width, height; - getWindowSize(&width, &height); - - VkExtent2D imageExtent = {}; - imageExtent.width = width; - imageExtent.height = height; - - m_width = width; - m_height = height; - - // catch this before throwing error - if (m_width == 0 || m_height == 0) - { - return SLANG_FAIL; - } - - // It is necessary to query the caps -> otherwise the LunarG verification layer will issue an error - { - VkSurfaceCapabilitiesKHR surfaceCaps; - - SLANG_VK_RETURN_ON_FAIL(m_api->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_api->m_physicalDevice, m_surface, &surfaceCaps)); - } - - List<VkPresentModeKHR> presentModes; - uint32_t numPresentModes = 0; - m_api->vkGetPhysicalDeviceSurfacePresentModesKHR(m_api->m_physicalDevice, m_surface, &numPresentModes, nullptr); - presentModes.SetSize(numPresentModes); - m_api->vkGetPhysicalDeviceSurfacePresentModesKHR(m_api->m_physicalDevice, m_surface, &numPresentModes, presentModes.Buffer()); - - { - int numCheckPresentOptions = 3; - VkPresentModeKHR presentOptions[] = { VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_KHR }; - if (m_vsync) - { - presentOptions[0] = VK_PRESENT_MODE_FIFO_KHR; - presentOptions[1] = VK_PRESENT_MODE_IMMEDIATE_KHR; - presentOptions[2] = VK_PRESENT_MODE_MAILBOX_KHR; - } - - m_presentMode = VK_PRESENT_MODE_MAX_ENUM_KHR; // Invalid - - // Find the first option that's available on the device - for (int j = 0; j < numCheckPresentOptions; j++) - { - if (presentModes.IndexOf(presentOptions[j]) != UInt(-1)) - { - m_presentMode = presentOptions[j]; - break; - } - } - - if (m_presentMode == VK_PRESENT_MODE_MAX_ENUM_KHR) - { - return SLANG_FAIL; - } - } - - VkSwapchainKHR oldSwapchain = VK_NULL_HANDLE; - - VkSwapchainCreateInfoKHR swapchainDesc = {}; - swapchainDesc.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - swapchainDesc.surface = m_surface; - swapchainDesc.minImageCount = 3; - swapchainDesc.imageFormat = m_format; - swapchainDesc.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; - swapchainDesc.imageExtent = imageExtent; - swapchainDesc.imageArrayLayers = 1; - swapchainDesc.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; - swapchainDesc.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - swapchainDesc.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; - swapchainDesc.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - swapchainDesc.presentMode = m_presentMode; - swapchainDesc.clipped = VK_TRUE; - swapchainDesc.oldSwapchain = oldSwapchain; - - SLANG_VK_RETURN_ON_FAIL(m_api->vkCreateSwapchainKHR(m_api->m_device, &swapchainDesc, nullptr, &m_swapChain)); - - uint32_t numSwapChainImages = 0; - m_api->vkGetSwapchainImagesKHR(m_api->m_device, m_swapChain, &numSwapChainImages, nullptr); - - { - List<VkImage> images; - images.SetSize(numSwapChainImages); - - m_api->vkGetSwapchainImagesKHR(m_api->m_device, m_swapChain, &numSwapChainImages, images.Buffer()); - - m_images.SetSize(numSwapChainImages); - for (int i = 0; i < int(numSwapChainImages); ++i) - { - Image& dstImage = m_images[i]; - dstImage.m_image = images[i]; - - } - } - - { - VkImageViewCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - - createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - createInfo.format = m_format; - - createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; - - createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - createInfo.subresourceRange.baseMipLevel = 0; - createInfo.subresourceRange.levelCount = 1; - createInfo.subresourceRange.baseArrayLayer = 0; - createInfo.subresourceRange.layerCount = 1; - - for (int i = 0; i < int(numSwapChainImages); ++i) - { - Image& image = m_images[i]; - - createInfo.image = image.m_image; - - SLANG_VK_RETURN_ON_FAIL(m_api->vkCreateImageView(m_api->m_device, &createInfo, nullptr, &image.m_imageView)); - } - } - - if (m_renderPass != VK_NULL_HANDLE) - { - _createFrameBuffers(m_renderPass); - } - - return SLANG_OK; -} - -void VulkanSwapChain::_destroySwapChain() -{ - if (!hasValidSwapChain()) - { - return; - } - - m_deviceQueue->waitForIdle(); - - if (m_renderPass != VK_NULL_HANDLE) - { - _destroyFrameBuffers(); - } - - for (int i = 0; i < int(m_images.Count()); ++i) - { - Image& image = m_images[i]; - - if (image.m_imageView != VK_NULL_HANDLE) - { - m_api->vkDestroyImageView(m_api->m_device, image.m_imageView, nullptr); - } - } - - if (m_swapChain != VK_NULL_HANDLE) - { - m_api->vkDestroySwapchainKHR(m_api->m_device, m_swapChain, nullptr); - m_swapChain = VK_NULL_HANDLE; - } - - // Mark that it is no longer used - m_images.Clear(); -} - -VulkanSwapChain::~VulkanSwapChain() -{ - _destroySwapChain(); - - if (m_surface) - { - m_api->vkDestroySurfaceKHR(m_api->m_instance, m_surface, nullptr); - m_surface = VK_NULL_HANDLE; - } -} - -int VulkanSwapChain::nextFrontImageIndex() -{ - if (!hasValidSwapChain()) - { - if (SLANG_FAILED(_createSwapChain())) - { - return -1; - } - } - - VkSemaphore beginFrameSemaphore = m_deviceQueue->makeCurrent(VulkanDeviceQueue::EventType::BeginFrame); - - uint32_t swapChainIndex = 0; - VkResult result = m_api->vkAcquireNextImageKHR(m_api->m_device, m_swapChain, UINT64_MAX, beginFrameSemaphore, VK_NULL_HANDLE, &swapChainIndex); - - if (result != VK_SUCCESS) - { - _destroySwapChain(); - return -1; - } - m_currentSwapChainIndex = int(swapChainIndex); - return swapChainIndex; -} - -void VulkanSwapChain::present(bool vsync) -{ - if (!hasValidSwapChain()) - { - m_deviceQueue->flush(); - return; - } - - VkSemaphore endFrameSemaphore = m_deviceQueue->makeCurrent(VulkanDeviceQueue::EventType::EndFrame); - - m_deviceQueue->flushStepA(); - - uint32_t swapChainIndices[] = { uint32_t(m_currentSwapChainIndex) }; - - VkPresentInfoKHR presentInfo = {}; - presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - presentInfo.swapchainCount = 1; - presentInfo.pSwapchains = &m_swapChain; - presentInfo.pImageIndices = swapChainIndices; - presentInfo.waitSemaphoreCount = 1; - presentInfo.pWaitSemaphores = &endFrameSemaphore; - - VkResult result = m_api->vkQueuePresentKHR(m_deviceQueue->getQueue(), &presentInfo); - - m_deviceQueue->makeCompleted(VulkanDeviceQueue::EventType::EndFrame); - - m_deviceQueue->flushStepB(); - - if (result != VK_SUCCESS || m_vsync != vsync) - { - m_vsync = vsync; - _destroySwapChain(); - } -} - -} // renderer_test diff --git a/tools/render-test/vk-swap-chain.h b/tools/render-test/vk-swap-chain.h deleted file mode 100644 index 2c9fb588d..000000000 --- a/tools/render-test/vk-swap-chain.h +++ /dev/null @@ -1,141 +0,0 @@ -// vk-swap-chain.h -#pragma once - -#include "vk-api.h" -#include "vk-device-queue.h" - -#include "render.h" - -#include "../../source/core/list.h" - -namespace renderer_test { - -struct VulkanSwapChain -{ - /* enum - { - kMaxImages = 8, - }; */ - - /// Base class for platform specific information - struct PlatformDesc - { - }; - -#if SLANG_WINDOWS_FAMILY - struct WinPlatformDesc: public PlatformDesc - { - HINSTANCE m_hinstance; - HWND m_hwnd; - }; -#else - struct XPlatformDesc : public PlatformDesc - { - Display* m_display; - Window m_window; - }; -#endif - - struct Desc - { - void init() - { - m_format = Format::Unknown; - m_depthFormatTypeless = Format::Unknown; - m_depthFormat = Format::Unknown; - m_textureDepthFormat = Format::Unknown; - } - - Format m_format; - //bool m_enableFormat; - Format m_depthFormatTypeless; - Format m_depthFormat; - Format m_textureDepthFormat; - }; - - struct Image - { - VkImage m_image = VK_NULL_HANDLE; - VkImageView m_imageView = VK_NULL_HANDLE; - VkFramebuffer m_frameBuffer = VK_NULL_HANDLE; - }; - - - /// Must be called before the swap chain can be used - SlangResult init(VulkanDeviceQueue* deviceQueue, const Desc& desc, const PlatformDesc* platformDesc); - - /// Create the frame buffers (they must be compatible with the supplied renderPass) - SlangResult createFrameBuffers(VkRenderPass renderPass); - - /// Returned the desc used to construct the swap chain. - /// Is invalid if init hasn't returned with successful result. - const Desc& getDesc() const { return m_desc; } - - /// True if the swap chain is available - bool hasValidSwapChain() const { return m_images.Count() > 0; } - - /// Present to the display - void present(bool vsync); - - /// Get the current size of the window (in pixels written to widthOut, heightOut) - void getWindowSize(int* widthOut, int* heightOut) const; - - /// Get the VkFormat for the back buffer - VkFormat getVkFormat() const { return m_format; } - - /// Get width of the back buffers - int getWidth() const { return m_width; } - /// Get the height of the back buffer - int getHeight() const { return m_height; } - - /// Get the detail about the images - const Slang::List<Image>& getImages() const { return m_images; } - - /// Get the next front render image index. Returns -1, if image couldn't be found - int nextFrontImageIndex(); - - /// Dtor - ~VulkanSwapChain(); - - protected: - - - template <typename T> - void _setPlatformDesc(const T& desc) - { - const PlatformDesc* check = &desc; - int size = (sizeof(T) + sizeof(void*) - 1) / sizeof(void*); - m_platformDescBuffer.SetSize(size); - *(T*)m_platformDescBuffer.Buffer() = desc; - } - template <typename T> - const T* _getPlatformDesc() const { return static_cast<const T*>((const PlatformDesc*)m_platformDescBuffer.Buffer()); } - SlangResult _createSwapChain(); - void _destroySwapChain(); - SlangResult _createFrameBuffers(VkRenderPass renderPass); - void _destroyFrameBuffers(); - - bool m_vsync = true; - int m_width = 0; - int m_height = 0; - - VkPresentModeKHR m_presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; - VkFormat m_format = VK_FORMAT_UNDEFINED; ///< The format used for backbuffer. Valid after successful init. - - VkSurfaceKHR m_surface = VK_NULL_HANDLE; - VkSwapchainKHR m_swapChain = VK_NULL_HANDLE; - - VkRenderPass m_renderPass = VK_NULL_HANDLE; //< Not owned - - int m_currentSwapChainIndex = 0; - - Slang::List<Image> m_images; - - VulkanDeviceQueue* m_deviceQueue = nullptr; - const VulkanApi* m_api = nullptr; - - Desc m_desc; ///< The desc used to init this swap chain - Slang::List<void*> m_platformDescBuffer; ///< Buffer to hold the platform specific description parameters (as passed in platformDesc) -}; - -} // renderer_test diff --git a/tools/render-test/vk-util.cpp b/tools/render-test/vk-util.cpp deleted file mode 100644 index 925001144..000000000 --- a/tools/render-test/vk-util.cpp +++ /dev/null @@ -1,59 +0,0 @@ -// vk-util.cpp -#include "vk-util.h" - -#include <stdlib.h> -#include <stdio.h> - -namespace renderer_test { - -/* static */VkFormat VulkanUtil::getVkFormat(Format format) -{ - switch (format) - { - case Format::RGBA_Float32: return VK_FORMAT_R32G32B32A32_SFLOAT; - case Format::RGB_Float32: return VK_FORMAT_R32G32B32_SFLOAT; - case Format::RG_Float32: return VK_FORMAT_R32G32_SFLOAT; - case Format::R_Float32: return VK_FORMAT_R32_SFLOAT; - case Format::RGBA_Unorm_UInt8: return VK_FORMAT_R8G8B8A8_UNORM; - case Format::R_UInt32: return VK_FORMAT_R32_UINT; - - case Format::D_Float32: return VK_FORMAT_D32_SFLOAT; - case Format::D_Unorm24_S8: return VK_FORMAT_D24_UNORM_S8_UINT; - - default: return VK_FORMAT_UNDEFINED; - } -} - -/* static */SlangResult VulkanUtil::toSlangResult(VkResult res) -{ - return (res == VK_SUCCESS) ? SLANG_OK : SLANG_FAIL; -} - -/* static */Slang::Result VulkanUtil::handleFail(VkResult res) -{ - if (res != VK_SUCCESS) - { - assert(!"Vulkan returned a failure"); - } - return toSlangResult(res); -} - -/* static */void VulkanUtil::checkFail(VkResult res) -{ - assert(res != VK_SUCCESS); - assert(!"Vulkan check failed"); - -} - -/* static */VkPrimitiveTopology VulkanUtil::getVkPrimitiveTopology(PrimitiveTopology topology) -{ - switch (topology) - { - case PrimitiveTopology::TriangleList: return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - default: break; - } - assert(!"Unknown topology"); - return VK_PRIMITIVE_TOPOLOGY_MAX_ENUM; -} - -} // renderer_test diff --git a/tools/render-test/vk-util.h b/tools/render-test/vk-util.h deleted file mode 100644 index 2d98a1c0f..000000000 --- a/tools/render-test/vk-util.h +++ /dev/null @@ -1,41 +0,0 @@ -// vk-util.h -#pragma once - -#include "vk-api.h" -#include "render.h" - -// Macros to make testing vulkan return codes simpler - -/// SLANG_VK_RETURN_ON_FAIL can be used in a similar way to SLANG_RETURN_ON_FAIL macro, except it will turn a vulkan failure into Slang::Result in the process -/// Calls handleFail which on debug builds asserts -#define SLANG_VK_RETURN_ON_FAIL(x) { VkResult _res = x; if (_res != VK_SUCCESS) { return VulkanUtil::handleFail(_res); } } - -#define SLANG_VK_RETURN_NULL_ON_FAIL(x) { VkResult _res = x; if (_res != VK_SUCCESS) { VulkanUtil::handleFail(_res); return nullptr; } } - -/// Is similar to SLANG_VK_RETURN_ON_FAIL, but does not return. Will call checkFail on failure - which asserts on debug builds. -#define SLANG_VK_CHECK(x) { VkResult _res = x; if (_res != VK_SUCCESS) { VulkanUtil::checkFail(_res); } } - -namespace renderer_test { - -// Utility functions for Vulkan -struct VulkanUtil -{ - /// Get the equivalent VkFormat from the format - /// Returns VK_FORMAT_UNDEFINED if a match is not found - static VkFormat getVkFormat(Format format); - - /// Called by SLANG_VK_RETURN_FAIL if a res is a failure. - /// On debug builds this will cause an assertion on failure. - static Slang::Result handleFail(VkResult res); - /// Called when a failure has occurred with SLANG_VK_CHECK - will typically assert. - static void checkFail(VkResult res); - - /// Get the VkPrimitiveTopology for the given topology. - /// Returns VK_PRIMITIVE_TOPOLOGY_MAX_ENUM on failure - static VkPrimitiveTopology getVkPrimitiveTopology(PrimitiveTopology topology); - - /// Returns Slang::Result equivalent of a VkResult - static Slang::Result toSlangResult(VkResult res); -}; - -} // renderer_test diff --git a/tools/render-test/window.h b/tools/render-test/window.h deleted file mode 100644 index 5d0a89ee4..000000000 --- a/tools/render-test/window.h +++ /dev/null @@ -1,10 +0,0 @@ -// window.h -#pragma once - -namespace renderer_test { - -typedef struct Window Window; - -Window* createWindow(); - -} // renderer_test |
