diff --git a/include/Support/Pipeline.h b/include/Support/Pipeline.h index dffc5405..775a372f 100644 --- a/include/Support/Pipeline.h +++ b/include/Support/Pipeline.h @@ -144,6 +144,7 @@ struct Resource { Buffer *BufferPtr = nullptr; bool HasCounter; std::optional TilesMapped; + std::optional IsReserved; bool isRaw() const { switch (Kind) { diff --git a/lib/API/DX/Device.cpp b/lib/API/DX/Device.cpp index d44f2f15..64e33c38 100644 --- a/lib/API/DX/Device.cpp +++ b/lib/API/DX/Device.cpp @@ -158,10 +158,12 @@ static D3D12_RESOURCE_DESC getResourceDescription(const Resource &R) { R.isTexture() ? B.OutputProps.Width : getUAVBufferSize(R); const uint32_t Height = R.isTexture() ? B.OutputProps.Height : 1; D3D12_TEXTURE_LAYOUT Layout; + const bool IsReserved = R.IsReserved.has_value() && *R.IsReserved; if (R.isTexture()) - Layout = getDXKind(R.Kind) == SRV - ? D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE - : D3D12_TEXTURE_LAYOUT_UNKNOWN; + Layout = + IsReserved && (getDXKind(R.Kind) == SRV || getDXKind(R.Kind) == UAV) + ? D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE + : D3D12_TEXTURE_LAYOUT_UNKNOWN; else Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; @@ -552,8 +554,53 @@ class DXDevice : public offloadtest::Device { return Ret; } + llvm::Error setupTiledResource(Resource &R, InvocationState &IS, + const D3D12_RESOURCE_DESC ResDesc, + ComPtr &Heap, + ComPtr &Buffer) { + // Tile mapping setup (only skipped when TilesMapped is set to 0) + const UINT NumTiles = getNumTiles(R.TilesMapped, ResDesc.Width); + + if (NumTiles > 0) { + // Create a Heap large enough for the mapped tiles + D3D12_HEAP_DESC HeapDesc = {}; + HeapDesc.Properties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT); + HeapDesc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT; + HeapDesc.SizeInBytes = static_cast(NumTiles) * + D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT; + HeapDesc.Flags = D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES; + + if (auto Err = + HR::toError(Device->CreateHeap(&HeapDesc, IID_PPV_ARGS(&Heap)), + "Failed to create heap for tiled SRV resource.")) + return Err; + + // Define one contiguous mapping region + const D3D12_TILED_RESOURCE_COORDINATE StartCoord = {0, 0, 0, 0}; + D3D12_TILE_REGION_SIZE RegionSize = {}; + RegionSize.NumTiles = NumTiles; + RegionSize.UseBox = FALSE; + + const D3D12_TILE_RANGE_FLAGS RangeFlag = D3D12_TILE_RANGE_FLAG_NONE; + const UINT HeapRangeStartOffset = 0; + const UINT RangeTileCount = NumTiles; + + ID3D12CommandQueue *CommandQueue = IS.Queue.Get(); + CommandQueue->UpdateTileMappings( + Buffer.Get(), 1, &StartCoord, &RegionSize, // One region + Heap.Get(), 1, &RangeFlag, &HeapRangeStartOffset, &RangeTileCount, + D3D12_TILE_MAPPING_FLAG_NONE); + } + return llvm::Error::success(); + } + llvm::Expected createSRV(Resource &R, InvocationState &IS) { ResourceBundle Bundle; + + // for committed resources + const D3D12_HEAP_PROPERTIES HeapProp = + CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT); + const D3D12_RESOURCE_DESC ResDesc = getResourceDescription(R); const D3D12_RESOURCE_DESC UploadResDesc = CD3DX12_RESOURCE_DESC::Buffer(R.size()); @@ -572,12 +619,23 @@ class DXDevice : public offloadtest::Device { llvm::outs() << " }\n"; ComPtr Buffer; - if (auto Err = - HR::toError(Device->CreateReservedResource( - &ResDesc, D3D12_RESOURCE_STATE_COMMON, nullptr, - IID_PPV_ARGS(&Buffer)), - "Failed to create reserved resource (buffer).")) - return Err; + const bool IsReserved = R.IsReserved.has_value() && *R.IsReserved; + if (IsReserved) { + if (auto Err = + HR::toError(Device->CreateReservedResource( + &ResDesc, D3D12_RESOURCE_STATE_COMMON, nullptr, + IID_PPV_ARGS(&Buffer)), + "Failed to create reserved resource (buffer).")) + return Err; + } else { + if (auto Err = + HR::toError(Device->CreateCommittedResource( + &HeapProp, D3D12_HEAP_FLAG_NONE, &ResDesc, + D3D12_RESOURCE_STATE_COMMON, nullptr, + IID_PPV_ARGS(&Buffer)), + "Failed to create committed resource (buffer).")) + return Err; + } // Committed upload buffer ComPtr UploadBuffer; @@ -589,41 +647,11 @@ class DXDevice : public offloadtest::Device { "Failed to create committed resource (upload buffer).")) return Err; - // Tile mapping setup (only skipped when TilesMapped is set to 0) - const UINT NumTiles = getNumTiles(R.TilesMapped, ResDesc.Width); ComPtr Heap; // optional, only created if NumTiles > 0 - - if (NumTiles > 0) { - // Create a Heap large enough for the mapped tiles - D3D12_HEAP_DESC HeapDesc = {}; - HeapDesc.Properties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT); - HeapDesc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT; - HeapDesc.SizeInBytes = static_cast(NumTiles) * - D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT; - HeapDesc.Flags = D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES; - - if (auto Err = - HR::toError(Device->CreateHeap(&HeapDesc, IID_PPV_ARGS(&Heap)), - "Failed to create heap for tiled SRV resource.")) + if (IsReserved) + if (auto Err = setupTiledResource(R, IS, ResDesc, Heap, Buffer)) return Err; - // Define one contiguous mapping region - const D3D12_TILED_RESOURCE_COORDINATE StartCoord = {0, 0, 0, 0}; - D3D12_TILE_REGION_SIZE RegionSize = {}; - RegionSize.NumTiles = NumTiles; - RegionSize.UseBox = FALSE; - - const D3D12_TILE_RANGE_FLAGS RangeFlag = D3D12_TILE_RANGE_FLAG_NONE; - const UINT HeapRangeStartOffset = 0; - const UINT RangeTileCount = NumTiles; - - ID3D12CommandQueue *CommandQueue = IS.Queue.Get(); - CommandQueue->UpdateTileMappings( - Buffer.Get(), 1, &StartCoord, &RegionSize, // One region - Heap.Get(), 1, &RangeFlag, &HeapRangeStartOffset, &RangeTileCount, - D3D12_TILE_MAPPING_FLAG_NONE); - } - // Upload data initialization void *ResDataPtr = nullptr; if (SUCCEEDED(UploadBuffer->Map(0, NULL, &ResDataPtr))) { @@ -668,8 +696,10 @@ class DXDevice : public offloadtest::Device { ResourceBundle Bundle; const uint32_t BufferSize = getUAVBufferSize(R); + // for committed resources const D3D12_HEAP_PROPERTIES HeapProp = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT); + const D3D12_RESOURCE_DESC ResDesc = getResourceDescription(R); const D3D12_HEAP_PROPERTIES ReadBackHeapProp = @@ -686,35 +716,53 @@ class DXDevice : public offloadtest::Device { D3D12_TEXTURE_LAYOUT_ROW_MAJOR, D3D12_RESOURCE_FLAG_NONE}; - const D3D12_HEAP_PROPERTIES UploadHeapProp = - CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD); const D3D12_RESOURCE_DESC UploadResDesc = CD3DX12_RESOURCE_DESC::Buffer(BufferSize); + const D3D12_HEAP_PROPERTIES UploadHeapProps = + CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD); uint32_t RegOffset = 0; + for (const auto &ResData : R.BufferPtr->Data) { llvm::outs() << "Creating UAV: { Size = " << BufferSize << ", Register = u" << R.DXBinding.Register + RegOffset << ", Space = " << R.DXBinding.Space - << ", HasCounter = " << R.HasCounter << " }\n"; + << ", HasCounter = " << R.HasCounter; + + if (R.TilesMapped) + llvm::outs() << ", TilesMapped = " << *R.TilesMapped; + llvm::outs() << " }\n"; ComPtr Buffer; - if (auto Err = HR::toError( - Device->CreateCommittedResource( - &HeapProp, D3D12_HEAP_FLAG_NONE, &ResDesc, - D3D12_RESOURCE_STATE_COMMON, nullptr, IID_PPV_ARGS(&Buffer)), - "Failed to create committed resource (buffer).")) - return Err; + const bool IsReserved = R.IsReserved.has_value() && *R.IsReserved; + if (IsReserved) { + if (auto Err = + HR::toError(Device->CreateReservedResource( + &ResDesc, D3D12_RESOURCE_STATE_COMMON, nullptr, + IID_PPV_ARGS(&Buffer)), + "Failed to create reserved resource (buffer).")) + return Err; + } else { + if (auto Err = + HR::toError(Device->CreateCommittedResource( + &HeapProp, D3D12_HEAP_FLAG_NONE, &ResDesc, + D3D12_RESOURCE_STATE_COMMON, nullptr, + IID_PPV_ARGS(&Buffer)), + "Failed to create committed resource (buffer).")) + return Err; + } + // Committed upload buffer ComPtr UploadBuffer; if (auto Err = HR::toError( Device->CreateCommittedResource( - &UploadHeapProp, D3D12_HEAP_FLAG_NONE, &UploadResDesc, + &UploadHeapProps, D3D12_HEAP_FLAG_NONE, &UploadResDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&UploadBuffer)), "Failed to create committed resource (upload buffer).")) return Err; + // Committed readback buffer ComPtr ReadBackBuffer; if (auto Err = HR::toError( Device->CreateCommittedResource( @@ -724,17 +772,24 @@ class DXDevice : public offloadtest::Device { "Failed to create committed resource (readback buffer).")) return Err; - // Initialize the UAV data + ComPtr Heap; // optional, only created if NumTiles > 0 + if (IsReserved) + if (auto Err = setupTiledResource(R, IS, ResDesc, Heap, Buffer)) + return Err; + + // Upload data initialization void *ResDataPtr = nullptr; - if (auto Err = HR::toError(UploadBuffer->Map(0, nullptr, &ResDataPtr), - "Failed to acquire UAV data pointer.")) - return Err; - memcpy(ResDataPtr, ResData.get(), R.size()); - UploadBuffer->Unmap(0, nullptr); + if (SUCCEEDED(UploadBuffer->Map(0, NULL, &ResDataPtr))) { + memcpy(ResDataPtr, ResData.get(), R.size()); + UploadBuffer->Unmap(0, nullptr); + } else { + return llvm::createStringError(std::errc::io_error, + "Failed to map UAV upload buffer."); + } addResourceUploadCommands(R, IS, Buffer, UploadBuffer); - Bundle.emplace_back(UploadBuffer, Buffer, ReadBackBuffer); + Bundle.emplace_back(UploadBuffer, Buffer, ReadBackBuffer, Heap); RegOffset++; } return Bundle; @@ -921,6 +976,12 @@ class DXDevice : public offloadtest::Device { if (R.Kind != dx::RootParamKind::RootDescriptor) continue; auto &Resource = std::get(R.Data); + if (!Resource.IsReserved && Resource.TilesMapped.has_value()) { + return llvm::createStringError( + std::errc::invalid_argument, + "Error: Cannot define tiles mapped without declaring resource as " + "reserved."); + } if (auto Err = CreateBuffer(Resource, IS.RootResources)) return Err; } @@ -1001,14 +1062,28 @@ class DXDevice : public offloadtest::Device { "Failed to register end event.")) return Err; + // 60000 ms timeout (1 minute) + static constexpr int TimeoutMS = 60000; + #ifdef _WIN32 - WaitForSingleObject(IS.Event, INFINITE); -#else // WSL + const DWORD WaitRes = WaitForSingleObject(IS.Event, TimeoutMS); + if (WaitRes == WAIT_TIMEOUT) + return llvm::createStringError(std::errc::timed_out, + "Fence wait timed out"); + if (WaitRes != WAIT_OBJECT_0) + return llvm::createStringError(std::errc::io_error, + "Unexpected WaitForSingleObject result"); +#else pollfd PollEvent; PollEvent.fd = IS.Event; PollEvent.events = POLLIN; PollEvent.revents = 0; - if (poll(&PollEvent, 1, -1) == -1) + + int Ret = poll(&PollEvent, 1, TimeoutMS); + if (Ret == 0) + return llvm::createStringError(std::errc::timed_out, + "Fence wait timed out"); + if (Ret < 0) return llvm::createStringError( std::error_code(errno, std::system_category()), strerror(errno)); #endif @@ -1433,6 +1508,13 @@ class DXDevice : public offloadtest::Device { return llvm::Error::success(); } + llvm::Error waitThenReturnErr(llvm::Error Err, InvocationState &IS) { + llvm::Error WaitErr = waitForSignal(IS); + if (WaitErr) + return llvm::joinErrors(std::move(WaitErr), std::move(Err)); + return Err; + } + llvm::Error executeProgram(Pipeline &P) override { llvm::sys::AddSignalHandler( [](void *Cookie) { @@ -1476,7 +1558,7 @@ class DXDevice : public offloadtest::Device { return Err; llvm::outs() << "Buffers created.\n"; if (auto Err = createEvent(State)) - return Err; + return waitThenReturnErr(std::move(Err), State); llvm::outs() << "Event prepared.\n"; if (P.isCompute()) { @@ -1486,33 +1568,33 @@ class DXDevice : public offloadtest::Device { std::errc::invalid_argument, "Compute pipeline must have exactly one compute shader."); if (auto Err = createComputePSO(P.Shaders[0].Shader->getBuffer(), State)) - return Err; + return waitThenReturnErr(std::move(Err), State); llvm::outs() << "PSO created.\n"; if (auto Err = createComputeCommands(P, State)) - return Err; + return waitThenReturnErr(std::move(Err), State); llvm::outs() << "Compute command list created.\n"; } else { // Create render target, readback and vertex buffer and PSO. if (auto Err = createRenderTarget(P, State)) - return Err; + return waitThenReturnErr(std::move(Err), State); llvm::outs() << "Render target created.\n"; if (auto Err = createVertexBuffer(P, State)) - return Err; + return waitThenReturnErr(std::move(Err), State); llvm::outs() << "Vertex buffer created.\n"; if (auto Err = createGraphicsPSO(P, State)) - return Err; + return waitThenReturnErr(std::move(Err), State); llvm::outs() << "Graphics PSO created.\n"; if (auto Err = createGraphicsCommands(P, State)) - return Err; + return waitThenReturnErr(std::move(Err), State); llvm::outs() << "Graphics command list created complete.\n"; } if (auto Err = executeCommandList(State)) - return Err; + return waitThenReturnErr(std::move(Err), State); llvm::outs() << "Compute commands executed.\n"; if (auto Err = readBack(P, State)) - return Err; + return waitThenReturnErr(std::move(Err), State); llvm::outs() << "Read data back.\n"; return llvm::Error::success(); diff --git a/lib/API/VK/Device.cpp b/lib/API/VK/Device.cpp index a5557e38..6141454e 100644 --- a/lib/API/VK/Device.cpp +++ b/lib/API/VK/Device.cpp @@ -789,8 +789,8 @@ class VKDevice : public offloadtest::Device { std::errc::invalid_argument, "No RenderTarget buffer specified for graphics pipeline."); Resource FrameBuffer = { - ResourceKind::Texture2D, "RenderTarget", {}, {}, - P.Bindings.RTargetBufferPtr, false, std::nullopt}; + ResourceKind::Texture2D, "RenderTarget", {}, {}, + P.Bindings.RTargetBufferPtr, false, std::nullopt, false}; IS.FrameBufferResource.Size = P.Bindings.RTargetBufferPtr->size(); IS.FrameBufferResource.BufferPtr = P.Bindings.RTargetBufferPtr; IS.FrameBufferResource.ImageLayout = @@ -817,8 +817,8 @@ class VKDevice : public offloadtest::Device { std::errc::invalid_argument, "No Vertex buffer specified for graphics pipeline."); const Resource VertexBuffer = { - ResourceKind::StructuredBuffer, "VertexBuffer", {}, {}, - P.Bindings.VertexBufferPtr, false, std::nullopt}; + ResourceKind::StructuredBuffer, "VertexBuffer", {}, {}, + P.Bindings.VertexBufferPtr, false, std::nullopt, false}; auto ExVHostBuf = createBuffer(IS, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VertexBuffer.size(), diff --git a/lib/Support/Pipeline.cpp b/lib/Support/Pipeline.cpp index c66f8683..702ae5ee 100644 --- a/lib/Support/Pipeline.cpp +++ b/lib/Support/Pipeline.cpp @@ -292,6 +292,7 @@ void MappingTraits::mapping(IO &I, I.mapRequired("Kind", R.Kind); I.mapOptional("HasCounter", R.HasCounter, 0); I.mapOptional("TilesMapped", R.TilesMapped); + I.mapOptional("IsReserved", R.IsReserved); I.mapRequired("DirectXBinding", R.DXBinding); I.mapOptional("VulkanBinding", R.VKBinding); } diff --git a/test/Feature/HLSLLib/PartiallyMappedResources.test b/test/Feature/HLSLLib/PartiallyMappedResources.test index 4f5f915d..dff09d5f 100644 --- a/test/Feature/HLSLLib/PartiallyMappedResources.test +++ b/test/Feature/HLSLLib/PartiallyMappedResources.test @@ -113,6 +113,7 @@ DescriptorSets: VulkanBinding: Binding: 0 TilesMapped: 1 + IsReserved: True - Name: Y Kind: StructuredBuffer DirectXBinding: @@ -121,6 +122,7 @@ DescriptorSets: VulkanBinding: Binding: 1 TilesMapped: 0 + IsReserved: True - Name: Out Kind: RWStructuredBuffer DirectXBinding: