diff options
| -rw-r--r-- | build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj | 1 | ||||
| -rw-r--r-- | build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters | 3 | ||||
| -rw-r--r-- | tools/gfx-unit-test/clear-texture-test.cpp | 87 | ||||
| -rw-r--r-- | tools/gfx/d3d/d3d-swapchain.h | 4 | ||||
| -rw-r--r-- | tools/gfx/resource-desc-utils.cpp | 23 | ||||
| -rw-r--r-- | tools/gfx/resource-desc-utils.h | 3 | ||||
| -rw-r--r-- | tools/gfx/vulkan/render-vk.cpp | 530 | ||||
| -rw-r--r-- | tools/gfx/vulkan/vk-api.h | 3 | ||||
| -rw-r--r-- | tools/gfx/vulkan/vk-util.cpp | 15 |
9 files changed, 537 insertions, 132 deletions
diff --git a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj index b44864334..0a0428a5a 100644 --- a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj +++ b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj @@ -273,6 +273,7 @@ </ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\tools\gfx-unit-test\buffer-barrier-test.cpp" />
+ <ClCompile Include="..\..\..\tools\gfx-unit-test\clear-texture-test.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\compute-smoke.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\copy-texture-tests.cpp" />
<ClCompile Include="..\..\..\tools\gfx-unit-test\create-buffer-from-handle.cpp" />
diff --git a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters index fd1ff52cd..fec2fafc6 100644 --- a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters +++ b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters @@ -20,6 +20,9 @@ <ClCompile Include="..\..\..\tools\gfx-unit-test\buffer-barrier-test.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\..\..\tools\gfx-unit-test\clear-texture-test.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="..\..\..\tools\gfx-unit-test\compute-smoke.cpp">
<Filter>Source Files</Filter>
</ClCompile>
diff --git a/tools/gfx-unit-test/clear-texture-test.cpp b/tools/gfx-unit-test/clear-texture-test.cpp new file mode 100644 index 000000000..13db72402 --- /dev/null +++ b/tools/gfx-unit-test/clear-texture-test.cpp @@ -0,0 +1,87 @@ +#include "tools/unit-test/slang-unit-test.h" + +#include "slang-gfx.h" +#include "gfx-test-util.h" +#include "tools/gfx-util/shader-cursor.h" +#include "source/core/slang-basic.h" + +using namespace Slang; +using namespace gfx; + +namespace gfx_test +{ + void clearTextureTestImpl(IDevice* device, UnitTestContext* context) + { + Slang::ComPtr<ITransientResourceHeap> transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ITextureResource::Desc srcTexDesc = {}; + srcTexDesc.type = IResource::Type::Texture2D; + srcTexDesc.numMipLevels = 1; + srcTexDesc.arraySize = 1; + srcTexDesc.size.width = 4; + srcTexDesc.size.height = 4; + srcTexDesc.size.depth = 1; + srcTexDesc.defaultState = ResourceState::RenderTarget; + srcTexDesc.allowedStates = ResourceStateSet( + ResourceState::RenderTarget, + ResourceState::CopySource, + ResourceState::CopyDestination); + srcTexDesc.format = Format::R32G32B32A32_FLOAT; + + Slang::ComPtr<ITextureResource> srcTexture; + GFX_CHECK_CALL_ABORT(device->createTextureResource( + srcTexDesc, nullptr, srcTexture.writeRef())); + + Slang::ComPtr<IResourceView> rtv; + IResourceView::Desc rtvDesc = {}; + rtvDesc.type = IResourceView::Type::RenderTarget; + rtvDesc.format = Format::R32G32B32A32_FLOAT; + rtvDesc.renderTarget.shape = IResource::Type::Texture2D; + rtv = device->createTextureView(srcTexture, rtvDesc); + + { + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = device->createCommandQueue(queueDesc); + + auto commandBuffer = transientHeap->createCommandBuffer(); + auto resourceEncoder = commandBuffer->encodeResourceCommands(); + ClearValue clearValue = {}; + clearValue.color.floatValues[0] = 0.5f; + clearValue.color.floatValues[1] = 1.0f; + clearValue.color.floatValues[2] = 0.2f; + clearValue.color.floatValues[3] = 0.1f; + resourceEncoder->clearResourceView(rtv, &clearValue, ClearResourceViewFlags::FloatClearValues); + resourceEncoder->textureBarrier( + srcTexture, ResourceState::RenderTarget, ResourceState::CopySource); + resourceEncoder->endEncoding(); + + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + + queue->waitOnHost(); + + Slang::ComPtr<ISlangBlob> blob; + size_t rowPitch, pixelSize; + device->readTextureResource( + srcTexture, + ResourceState::CopySource, + blob.writeRef(), + &rowPitch, + &pixelSize); + float* data = (float*)blob->getBufferPointer(); + for (int i = 0; i < 4; i++) + { + SLANG_CHECK(data[i] == clearValue.color.floatValues[i]); + } + } + } + + SLANG_UNIT_TEST(clearTextureTestVulkan) + { + runTestImpl(clearTextureTestImpl, unitTestContext, Slang::RenderApiFlag::Vulkan); + } +} diff --git a/tools/gfx/d3d/d3d-swapchain.h b/tools/gfx/d3d/d3d-swapchain.h index 11914cca8..99343aaf4 100644 --- a/tools/gfx/d3d/d3d-swapchain.h +++ b/tools/gfx/d3d/d3d-swapchain.h @@ -35,12 +35,14 @@ public: m_desc = desc; + m_desc.format = srgbToLinearFormat(m_desc.format); + // Describe the swap chain. DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; swapChainDesc.BufferCount = desc.imageCount; swapChainDesc.BufferDesc.Width = desc.width; swapChainDesc.BufferDesc.Height = desc.height; - swapChainDesc.BufferDesc.Format = D3DUtil::getMapFormat(desc.format); + swapChainDesc.BufferDesc.Format = D3DUtil::getMapFormat(m_desc.format); swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.SwapEffect = swapEffect; swapChainDesc.OutputWindow = (HWND)window.handleValues[0]; diff --git a/tools/gfx/resource-desc-utils.cpp b/tools/gfx/resource-desc-utils.cpp index 93609cd0e..b36e765e5 100644 --- a/tools/gfx/resource-desc-utils.cpp +++ b/tools/gfx/resource-desc-utils.cpp @@ -17,4 +17,27 @@ ITextureResource::Desc fixupTextureDesc(const ITextureResource::Desc& desc) rs.allowedStates.add(rs.defaultState); return rs; } + +Format srgbToLinearFormat(Format format) +{ + switch (format) + { + case Format::BC1_UNORM_SRGB: + return Format::BC1_UNORM; + case Format::BC2_UNORM_SRGB: + return Format::BC2_UNORM; + case Format::BC3_UNORM_SRGB: + return Format::BC3_UNORM; + case Format::BC7_UNORM_SRGB: + return Format::BC7_UNORM; + case Format::B8G8R8A8_UNORM_SRGB: + return Format::B8G8R8A8_UNORM; + case Format::B8G8R8X8_UNORM_SRGB: + return Format::B8G8R8X8_UNORM; + case Format::R8G8B8A8_UNORM_SRGB: + return Format::R8G8B8A8_UNORM; + default: + return format; + } +} } diff --git a/tools/gfx/resource-desc-utils.h b/tools/gfx/resource-desc-utils.h index 11150ce2a..09d909bdb 100644 --- a/tools/gfx/resource-desc-utils.h +++ b/tools/gfx/resource-desc-utils.h @@ -96,4 +96,7 @@ inline int calcNumSubResources(const ITextureResource::Desc& desc) IBufferResource::Desc fixupBufferDesc(const IBufferResource::Desc& desc); ITextureResource::Desc fixupTextureDesc(const ITextureResource::Desc& desc); + +Format srgbToLinearFormat(Format format); + } diff --git a/tools/gfx/vulkan/render-vk.cpp b/tools/gfx/vulkan/render-vk.cpp index d3f0329d8..eb4044639 100644 --- a/tools/gfx/vulkan/render-vk.cpp +++ b/tools/gfx/vulkan/render-vk.cpp @@ -179,6 +179,21 @@ public: public: class TransientResourceHeapImpl; + static size_t calcRowSize(Format format, int width) + { + FormatInfo sizeInfo; + gfxGetFormatInfo(format, &sizeInfo); + return size_t( + (width + sizeInfo.blockWidth - 1) / sizeInfo.blockWidth * sizeInfo.blockSizeInBytes); + } + + static size_t calcNumRows(Format format, int height) + { + FormatInfo sizeInfo; + gfxGetFormatInfo(format, &sizeInfo); + return (size_t)(height + sizeInfo.blockHeight - 1) / sizeInfo.blockHeight; + } + class Buffer { public: @@ -627,6 +642,8 @@ public: dst.flags = 0; dst.format = VulkanUtil::getVkFormat(renderTarget.format); + if (renderTarget.format == Format::Unknown) + dst.format = VK_FORMAT_R8G8B8A8_UNORM; dst.samples = (VkSampleCountFlagBits)renderTarget.sampleCount; // The following load/store/layout settings does not matter. @@ -2418,29 +2435,33 @@ public: static void _uploadBufferData( VkCommandBuffer commandBuffer, + TransientResourceHeapImpl* transientHeap, BufferResourceImpl* buffer, size_t offset, size_t size, void* data) { auto& api = buffer->m_renderer->m_api; + IBufferResource* stagingBuffer = nullptr; + transientHeap->allocateStagingBuffer(size, stagingBuffer, ResourceState::CopySource); - assert(buffer->m_uploadBuffer.isInitialized()); + BufferResourceImpl* stagingBufferImpl = + static_cast<BufferResourceImpl*>(stagingBuffer); void* mappedData = nullptr; SLANG_VK_CHECK(api.vkMapMemory( - api.m_device, buffer->m_uploadBuffer.m_memory, offset, size, 0, &mappedData)); + api.m_device, stagingBufferImpl->m_buffer.m_memory, 0, size, 0, &mappedData)); memcpy(mappedData, data, size); - api.vkUnmapMemory(api.m_device, buffer->m_uploadBuffer.m_memory); + api.vkUnmapMemory(api.m_device, stagingBufferImpl->m_buffer.m_memory); // Copy from staging buffer to real buffer VkBufferCopy copyInfo = {}; copyInfo.size = size; copyInfo.dstOffset = offset; - copyInfo.srcOffset = offset; + copyInfo.srcOffset = 0; api.vkCmdCopyBuffer( commandBuffer, - buffer->m_uploadBuffer.m_buffer, + stagingBufferImpl->m_buffer.m_buffer, buffer->m_buffer.m_buffer, 1, ©Info); @@ -2450,7 +2471,12 @@ public: { m_vkPreCommandBuffer = m_commandBuffer->getPreCommandBuffer(); _uploadBufferData( - m_vkPreCommandBuffer, static_cast<BufferResourceImpl*>(buffer), offset, size, data); + m_vkPreCommandBuffer, + m_commandBuffer->m_transientHeap.get(), + static_cast<BufferResourceImpl*>(buffer), + offset, + size, + data); } Result bindRootShaderObjectImpl(VkPipelineBindPoint bindPoint); @@ -2582,15 +2608,22 @@ public: if (offset.bindingRangeIndex >= layout->getBindingRangeCount()) return SLANG_E_INVALID_ARG; auto& bindingRange = layout->getBindingRange(offset.bindingRangeIndex); - if (resourceView->getViewDesc()->type == IResourceView::Type::AccelerationStructure) + if (!resourceView) { - m_resourceViews[bindingRange.baseIndex + offset.bindingArrayIndex] = - static_cast<AccelerationStructureImpl*>(resourceView); + m_resourceViews[bindingRange.baseIndex + offset.bindingArrayIndex] = nullptr; } else { - m_resourceViews[bindingRange.baseIndex + offset.bindingArrayIndex] = - static_cast<ResourceViewImpl*>(resourceView); + if (resourceView->getViewDesc()->type == IResourceView::Type::AccelerationStructure) + { + m_resourceViews[bindingRange.baseIndex + offset.bindingArrayIndex] = + static_cast<AccelerationStructureImpl*>(resourceView); + } + else + { + m_resourceViews[bindingRange.baseIndex + offset.bindingArrayIndex] = + static_cast<ResourceViewImpl*>(resourceView); + } } return SLANG_OK; } @@ -2848,7 +2881,10 @@ public: auto descriptorSet = context.descriptorSets[offset.bindingSet]; VkDescriptorBufferInfo bufferInfo = {}; - bufferInfo.buffer = buffer->m_buffer.m_buffer; + if (buffer) + { + bufferInfo.buffer = buffer->m_buffer.m_buffer; + } bufferInfo.offset = bufferOffset; bufferInfo.range = bufferSize; @@ -2922,19 +2958,19 @@ public: for(Index i = 0; i < count; ++i) { auto resourceView = static_cast<TexelBufferResourceViewImpl*>(resourceViews[i].Ptr()); - if (!resourceView) - continue; - VkBufferView bufferView = resourceView->m_view; - + VkBufferView bufferView = VK_NULL_HANDLE; + if (resourceView) + { + bufferView = resourceView->m_view; + } VkWriteDescriptorSet write = {}; write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write.descriptorCount = 1; write.descriptorType = descriptorType; write.dstArrayElement = uint32_t(i); write.dstBinding = offset.binding; write.dstSet = descriptorSet; + write.descriptorCount = 1; write.pTexelBufferView = &bufferView; - writeDescriptor(context, write); } } @@ -2952,12 +2988,20 @@ public: { auto texture = slots[i].textureView; auto sampler = slots[i].sampler; - if (!texture) - continue; VkDescriptorImageInfo imageInfo = {}; - imageInfo.imageView = texture->m_view; - imageInfo.imageLayout = texture->m_layout; - imageInfo.sampler = sampler->m_sampler; + if (texture) + { + imageInfo.imageView = texture->m_view; + imageInfo.imageLayout = texture->m_layout; + } + if (sampler) + { + imageInfo.sampler = sampler->m_sampler; + } + else + { + imageInfo.sampler = context.device->m_defaultSampler; + } VkWriteDescriptorSet write = {}; write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; @@ -2985,12 +3029,13 @@ public: { auto accelerationStructure = static_cast<AccelerationStructureImpl*>(resourceViews[i].Ptr()); - if (!accelerationStructure) - continue; VkWriteDescriptorSetAccelerationStructureKHR writeAS = {}; writeAS.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR; - writeAS.accelerationStructureCount = 1; - writeAS.pAccelerationStructures = &accelerationStructure->m_vkHandle; + if (accelerationStructure) + { + writeAS.accelerationStructureCount = 1; + writeAS.pAccelerationStructures = &accelerationStructure->m_vkHandle; + } VkWriteDescriptorSet write = {}; write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; write.descriptorCount = 1; @@ -3015,11 +3060,12 @@ public: for(Index i = 0; i < count; ++i) { auto texture = static_cast<TextureResourceViewImpl*>(resourceViews[i].Ptr()); - if (!texture) - continue; VkDescriptorImageInfo imageInfo = {}; - imageInfo.imageView = texture->m_view; - imageInfo.imageLayout = texture->m_layout; + if (texture) + { + imageInfo.imageView = texture->m_view; + imageInfo.imageLayout = texture->m_layout; + } imageInfo.sampler = 0; VkWriteDescriptorSet write = {}; @@ -3047,12 +3093,17 @@ public: for(Index i = 0; i < count; ++i) { auto sampler = samplers[i]; - if (!sampler) - continue; VkDescriptorImageInfo imageInfo = {}; imageInfo.imageView = 0; imageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - imageInfo.sampler = sampler->m_sampler; + if (sampler) + { + imageInfo.sampler = sampler->m_sampler; + } + else + { + imageInfo.sampler = context.device->m_defaultSampler; + } VkWriteDescriptorSet write = {}; write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; @@ -4448,6 +4499,7 @@ public: { PipelineCommandEncoder::_uploadBufferData( m_commandBuffer->m_commandBuffer, + m_commandBuffer->m_transientHeap.get(), static_cast<BufferResourceImpl*>(buffer), offset, size, @@ -4459,8 +4511,7 @@ public: ResourceState src, ResourceState dst) override { - List<VkImageMemoryBarrier> barriers; - barriers.setCount(count); + ShortList<VkImageMemoryBarrier, 16> barriers; for (size_t i = 0; i < count; i++) { @@ -4480,8 +4531,8 @@ public: barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; barrier.subresourceRange.baseArrayLayer = 0; barrier.subresourceRange.baseMipLevel = 0; - barrier.subresourceRange.layerCount = desc->arraySize; - barrier.subresourceRange.levelCount = desc->numMipLevels; + barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; barrier.srcAccessMask = calcAccessFlags(src); barrier.dstAccessMask = calcAccessFlags(dst); barriers.add(barrier); @@ -4491,7 +4542,17 @@ public: VkPipelineStageFlagBits dstStage = calcPipelineStageFlags(dst, false); auto& vkApi = m_commandBuffer->m_renderer->m_api; - vkApi.vkCmdPipelineBarrier(m_commandBuffer->m_commandBuffer, srcStage, dstStage, 0, 0, nullptr, 0, nullptr, (uint32_t)count, barriers.getBuffer()); + vkApi.vkCmdPipelineBarrier( + m_commandBuffer->m_commandBuffer, + srcStage, + dstStage, + 0, + 0, + nullptr, + 0, + nullptr, + (uint32_t)count, + barriers.getArrayView().getBuffer()); } virtual SLANG_NO_THROW void SLANG_MCALL bufferBarrier( size_t count, @@ -4584,29 +4645,37 @@ public: auto dstImage = static_cast<TextureResourceImpl*>(dst); auto dstDesc = dstImage->getDesc(); auto dstImageLayout = VulkanUtil::getImageLayoutFromState(dstState); - - for (Int layer = 0; layer < srcSubresource.layerCount; ++layer) + if (dstSubresource.layerCount == 0 && dstSubresource.mipLevelCount == 0) { - for (Int mipId = 0; mipId < srcSubresource.mipLevelCount; ++mipId) - { - VkImageCopy region = {}; - region.srcSubresource.aspectMask = getAspectMask(srcSubresource.aspectMask); - region.srcSubresource.baseArrayLayer = (uint32_t)(layer + srcSubresource.baseArrayLayer); - region.srcSubresource.mipLevel = (uint32_t)(mipId + srcSubresource.mipLevel); - region.srcSubresource.layerCount = 1; - region.srcOffset = { (int32_t)srcOffset.x, (int32_t)srcOffset.y, (int32_t)srcOffset.z }; - region.dstSubresource.aspectMask = getAspectMask(dstSubresource.aspectMask); - region.dstSubresource.baseArrayLayer = - (uint32_t)(layer + dstSubresource.baseArrayLayer); - region.dstSubresource.mipLevel = (uint32_t)(mipId + dstSubresource.mipLevel); - region.dstSubresource.layerCount = 1; - region.dstOffset = { (int32_t)dstOffset.x, (int32_t)dstOffset.y, (int32_t)dstOffset.z }; - region.extent = { (uint32_t)extent.width, (uint32_t)extent.height, (uint32_t)extent.depth }; - - auto& vkApi = m_commandBuffer->m_renderer->m_api; - vkApi.vkCmdCopyImage(m_commandBuffer->m_commandBuffer, srcImage->m_image, srcImageLayout, dstImage->m_image, dstImageLayout, 1, ®ion); - } + extent = dstDesc->size; + dstSubresource.layerCount = dstDesc->arraySize; + if (dstSubresource.layerCount == 0) + dstSubresource.layerCount = 1; + dstSubresource.mipLevelCount = dstDesc->numMipLevels; + } + if (srcSubresource.layerCount == 0 && srcSubresource.mipLevelCount == 0) + { + extent = srcDesc->size; + srcSubresource.layerCount = srcDesc->arraySize; + if (srcSubresource.layerCount == 0) + srcSubresource.layerCount = 1; + srcSubresource.mipLevelCount = dstDesc->numMipLevels; } + VkImageCopy region = {}; + region.srcSubresource.aspectMask = getAspectMask(srcSubresource.aspectMask); + region.srcSubresource.baseArrayLayer = srcSubresource.baseArrayLayer; + region.srcSubresource.mipLevel = srcSubresource.mipLevel; + region.srcSubresource.layerCount = srcSubresource.layerCount; + region.srcOffset = { (int32_t)srcOffset.x, (int32_t)srcOffset.y, (int32_t)srcOffset.z }; + region.dstSubresource.aspectMask = getAspectMask(dstSubresource.aspectMask); + region.dstSubresource.baseArrayLayer = dstSubresource.baseArrayLayer; + region.dstSubresource.mipLevel = dstSubresource.mipLevel; + region.dstSubresource.layerCount = dstSubresource.layerCount; + region.dstOffset = { (int32_t)dstOffset.x, (int32_t)dstOffset.y, (int32_t)dstOffset.z }; + region.extent = { (uint32_t)extent.width, (uint32_t)extent.height, (uint32_t)extent.depth }; + + auto& vkApi = m_commandBuffer->m_renderer->m_api; + vkApi.vkCmdCopyImage(m_commandBuffer->m_commandBuffer, srcImage->m_image, srcImageLayout, dstImage->m_image, dstImageLayout, 1, ®ion); } virtual SLANG_NO_THROW void SLANG_MCALL uploadTextureData( @@ -4617,13 +4686,137 @@ public: ITextureResource::SubresourceData* subResourceData, size_t subResourceDataCount) override { - SLANG_UNUSED(dst); - SLANG_UNUSED(subResourceRange); - SLANG_UNUSED(offset); - SLANG_UNUSED(extend); - SLANG_UNUSED(subResourceData); - SLANG_UNUSED(subResourceDataCount); - SLANG_UNIMPLEMENTED_X("uploadTextureData"); + // VALIDATION: dst must be in TransferDst state. + + auto& vkApi = m_commandBuffer->m_renderer->m_api; + auto dstImpl = static_cast<TextureResourceImpl*>(dst); + List<TextureResource::Size> mipSizes; + + VkCommandBuffer commandBuffer = m_commandBuffer->m_commandBuffer; + auto& desc = *dstImpl->getDesc(); + // Calculate how large the buffer has to be + size_t bufferSize = 0; + // Calculate how large an array entry is + for (uint32_t j = subResourceRange.mipLevel; + j < subResourceRange.mipLevel + subResourceRange.mipLevelCount; + ++j) + { + const TextureResource::Size mipSize = calcMipSize(desc.size, j); + + auto rowSizeInBytes = calcRowSize(desc.format, mipSize.width); + auto numRows = calcNumRows(desc.format, mipSize.height); + + mipSizes.add(mipSize); + + bufferSize += (rowSizeInBytes * numRows) * mipSize.depth; + } + + // Calculate the total size taking into account the array + bufferSize *= subResourceRange.layerCount; + + IBufferResource* uploadBuffer = nullptr; + m_commandBuffer->m_transientHeap->allocateStagingBuffer( + bufferSize, uploadBuffer, gfx::ResourceState::CopySource); + + // Copy into upload buffer + { + int subResourceCounter = 0; + + uint8_t* dstData; + uploadBuffer->map(nullptr, (void**)&dstData); + uint8_t* dstDataStart; + dstDataStart = dstData; + + size_t dstSubresourceOffset = 0; + for (uint32_t i = 0; i <subResourceRange.layerCount; ++i) + { + for (Index j = 0; j < mipSizes.getCount(); ++j) + { + const auto& mipSize = mipSizes[j]; + + int subResourceIndex = subResourceCounter++; + auto initSubresource = subResourceData[subResourceIndex]; + + const ptrdiff_t srcRowStride = (ptrdiff_t)initSubresource.strideY; + const ptrdiff_t srcLayerStride = (ptrdiff_t)initSubresource.strideZ; + + auto dstRowSizeInBytes = calcRowSize(desc.format, mipSize.width); + auto numRows = calcNumRows(desc.format, mipSize.height); + auto dstLayerSizeInBytes = dstRowSizeInBytes * numRows; + + const uint8_t* srcLayer = (const uint8_t*)initSubresource.data; + uint8_t* dstLayer = dstData + dstSubresourceOffset; + + for (int k = 0; k < mipSize.depth; k++) + { + const uint8_t* srcRow = srcLayer; + uint8_t* dstRow = dstLayer; + + for (uint32_t l = 0; l < numRows; l++) + { + ::memcpy(dstRow, srcRow, dstRowSizeInBytes); + + dstRow += dstRowSizeInBytes; + srcRow += srcRowStride; + } + + dstLayer += dstLayerSizeInBytes; + srcLayer += srcLayerStride; + } + + dstSubresourceOffset += dstLayerSizeInBytes * mipSize.depth; + } + } + uploadBuffer->unmap(nullptr); + } + { + size_t srcOffset = 0; + for (uint32_t i = 0; i < subResourceRange.layerCount; ++i) + { + for (Index j = 0; j < mipSizes.getCount(); ++j) + { + const auto& mipSize = mipSizes[j]; + + auto rowSizeInBytes = calcRowSize(desc.format, mipSize.width); + auto numRows = 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 = uint32_t(j); + region.imageSubresource.baseArrayLayer = subResourceRange.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) + vkApi.vkCmdCopyBufferToImage( + commandBuffer, + static_cast<BufferResourceImpl*>(uploadBuffer)->m_buffer.m_buffer, + dstImpl->m_image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, + ®ion); + + // Next + srcOffset += rowSizeInBytes * numRows * mipSize.depth; + } + } + } } void _clearColorImage(TextureResourceViewImpl* viewImpl, ClearValue* clearValue) @@ -5448,13 +5641,17 @@ public: submitInfo.signalSemaphoreCount = (uint32_t)signalSemaphores.getCount(); submitInfo.pSignalSemaphores = signalSemaphores.getBuffer(); - auto commandBufferImpl = static_cast<CommandBufferImpl*>(commandBuffers[0]); - auto vkFence = commandBufferImpl->m_transientHeap->getCurrentFence(); - vkAPI.vkResetFences(vkAPI.m_device, 1, &vkFence); + VkFence vkFence = VK_NULL_HANDLE; + if (count) + { + auto commandBufferImpl = static_cast<CommandBufferImpl*>(commandBuffers[0]); + vkFence = commandBufferImpl->m_transientHeap->getCurrentFence(); + vkAPI.vkResetFences(vkAPI.m_device, 1, &vkFence); + commandBufferImpl->m_transientHeap->advanceFence(); + } vkAPI.vkQueueSubmit(m_queue, 1, &submitInfo, vkFence); m_pendingWaitSemaphores[0] = m_semaphore; m_pendingWaitSemaphores[1] = VK_NULL_HANDLE; - commandBufferImpl->m_transientHeap->advanceFence(); } virtual SLANG_NO_THROW void SLANG_MCALL executeCommandBuffers( @@ -5924,20 +6121,24 @@ public: waitSemaphores.add(s); } } + m_queue->m_pendingWaitSemaphores[0] = VK_NULL_HANDLE; + m_queue->m_pendingWaitSemaphores[1] = VK_NULL_HANDLE; presentInfo.waitSemaphoreCount = (uint32_t)waitSemaphores.getCount(); if (presentInfo.waitSemaphoreCount) { presentInfo.pWaitSemaphores = waitSemaphores.getBuffer(); } - m_api->vkQueuePresentKHR(m_queue->m_queue, &presentInfo); - m_queue->m_pendingWaitSemaphores[0] = VK_NULL_HANDLE; - m_queue->m_pendingWaitSemaphores[1] = VK_NULL_HANDLE; + if (m_currentImageIndex != -1) + m_api->vkQueuePresentKHR(m_queue->m_queue, &presentInfo); return SLANG_OK; } virtual SLANG_NO_THROW int SLANG_MCALL acquireNextImage() override { if (!m_images.getCount()) + { + m_queue->m_pendingWaitSemaphores[1] = VK_NULL_HANDLE; return -1; + } m_currentImageIndex = -1; VkResult result = m_api->vkAcquireNextImageKHR( @@ -6025,6 +6226,8 @@ public: // worrying the `ShaderProgramImpl` object getting destroyed after the completion of // `VKDevice::~VKDevice()'. ChunkedList<RefPtr<RefObject>, 1024> m_deviceObjectsWithPotentialBackReferences; + + VkSampler m_defaultSampler; }; void VKDevice::PipelineCommandEncoder::init(CommandBufferImpl* commandBuffer) @@ -6192,7 +6395,8 @@ VKDevice::~VKDevice() shaderCache.free(); m_deviceObjectsWithPotentialBackReferences.clearAndDeallocate(); - // Same as clear but, also dtors all elements, which clear does not + m_api.vkDestroySampler(m_device, m_defaultSampler, nullptr); + m_deviceQueue.destroy(); descriptorSetAllocator.close(); @@ -6320,7 +6524,8 @@ Result VKDevice::initVulkanInstanceAndDevice(const InteropHandle* handles, bool if (!m_api.m_module->isSoftware()) { instanceExtensions.add(VK_KHR_SURFACE_EXTENSION_NAME); - instanceExtensions.add("VK_GOOGLE_surfaceless_query"); + // Note: this extension is not yet supported by nvidia drivers, disable for now. + // instanceExtensions.add("VK_GOOGLE_surfaceless_query"); #if SLANG_WINDOWS_FAMILY instanceExtensions.add(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); #elif defined(SLANG_ENABLE_XLIB) @@ -6547,6 +6752,10 @@ Result VKDevice::initVulkanInstanceAndDevice(const InteropHandle* handles, bool extendedFeatures.atomicInt64Features.pNext = deviceFeatures2.pNext; deviceFeatures2.pNext = &extendedFeatures.atomicInt64Features; + // robustness2 features + extendedFeatures.robustness2Features.pNext = deviceFeatures2.pNext; + deviceFeatures2.pNext = &extendedFeatures.robustness2Features; + // Atomic Float // To detect atomic float we need // https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderAtomicFloatFeaturesEXT.html @@ -6645,6 +6854,7 @@ Result VKDevice::initVulkanInstanceAndDevice(const InteropHandle* handles, bool deviceExtensions.add(VK_KHR_SHADER_SUBGROUP_EXTENDED_TYPES_EXTENSION_NAME); m_features.add("shader-subgroup-extended-types"); } + #if 0 if (extendedFeatures.accelerationStructureFeatures.accelerationStructure) { extendedFeatures.accelerationStructureFeatures.pNext = (void*)deviceCreateInfo.pNext; @@ -6653,7 +6863,6 @@ Result VKDevice::initVulkanInstanceAndDevice(const InteropHandle* handles, bool deviceExtensions.add(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); m_features.add("acceleration-structure"); } - if (extendedFeatures.rayQueryFeatures.rayQuery) { extendedFeatures.rayQueryFeatures.pNext = (void*)deviceCreateInfo.pNext; @@ -6662,6 +6871,7 @@ Result VKDevice::initVulkanInstanceAndDevice(const InteropHandle* handles, bool m_features.add("ray-query"); m_features.add("ray-tracing"); } + #endif if (extendedFeatures.bufferDeviceAddressFeatures.bufferDeviceAddress) { extendedFeatures.bufferDeviceAddressFeatures.pNext = (void*)deviceCreateInfo.pNext; @@ -6679,6 +6889,14 @@ Result VKDevice::initVulkanInstanceAndDevice(const InteropHandle* handles, bool m_features.add("inline-uniform-block"); } + if (extendedFeatures.robustness2Features.nullDescriptor) + { + extendedFeatures.robustness2Features.pNext = (void*)deviceCreateInfo.pNext; + deviceCreateInfo.pNext = &extendedFeatures.robustness2Features; + deviceExtensions.add(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME); + m_features.add("robustness2"); + } + uint32_t extensionCount = 0; m_api.vkEnumerateDeviceExtensionProperties(m_api.m_physicalDevice, NULL, &extensionCount, NULL); Slang::List<VkExtensionProperties> extensions; @@ -6784,6 +7002,27 @@ SlangResult VKDevice::initialize(const Desc& desc) SLANG_SPIRV, "sm_5_1", makeArray(slang::PreprocessorMacroDesc{ "__VK__", "1" }).getView())); + + // Create default sampler. + { + VkSamplerCreateInfo samplerInfo = {VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + samplerInfo.magFilter = VK_FILTER_NEAREST; + samplerInfo.minFilter = VK_FILTER_NEAREST; + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + 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_NEVER; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + samplerInfo.minLod = 0.0f; + samplerInfo.maxLod = 0.0f; + SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateSampler(m_device, &samplerInfo, nullptr, &m_defaultSampler)); + } + return SLANG_OK; } @@ -6920,20 +7159,6 @@ Result VKDevice::createFramebuffer(const IFramebuffer::Desc& desc, IFramebuffer* return SLANG_OK; } -size_t calcRowSize(Format format, int width) -{ - FormatInfo sizeInfo; - gfxGetFormatInfo(format, &sizeInfo); - return size_t((width + sizeInfo.blockWidth - 1) / sizeInfo.blockWidth * sizeInfo.blockSizeInBytes); -} - -size_t calcNumRows(Format format, int height) -{ - FormatInfo sizeInfo; - gfxGetFormatInfo(format, &sizeInfo); - return (size_t)(height + sizeInfo.blockHeight - 1) / sizeInfo.blockHeight; -} - SlangResult VKDevice::readTextureResource( ITextureResource* texture, ResourceState state, @@ -7205,6 +7430,8 @@ static VkImageUsageFlagBits _calcImageUsageFlags(ResourceState state) return VK_IMAGE_USAGE_TRANSFER_SRC_BIT; case ResourceState::ResolveDestination: return VK_IMAGE_USAGE_TRANSFER_DST_BIT; + case ResourceState::General: + return (VkImageUsageFlagBits)0; default: { assert(!"Unsupported"); @@ -7722,7 +7949,8 @@ Result VKDevice::createBufferResource(const IBufferResource::Desc& descIn, const usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; } - if (desc.allowedStates.contains(ResourceState::ConstantBuffer)) + if (desc.allowedStates.contains(ResourceState::ConstantBuffer) || + desc.memoryType == MemoryType::Upload || desc.memoryType == MemoryType::ReadBack) { reqMemoryProperties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; } @@ -7737,29 +7965,34 @@ Result VKDevice::createBufferResource(const IBufferResource::Desc& descIn, const SLANG_RETURN_ON_FAIL(buffer->m_buffer.init(m_api, desc.sizeInBytes, usage, reqMemoryProperties)); } - if (desc.memoryType == MemoryType::Upload || initData) - { - SLANG_RETURN_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); + if (desc.memoryType == MemoryType::DeviceLocal) + { + SLANG_RETURN_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)); + // 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(); + // 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); - m_deviceQueue.flush(); + VkBufferCopy copyInfo = {}; + copyInfo.size = bufferSize; + m_api.vkCmdCopyBuffer(commandBuffer, buffer->m_uploadBuffer.m_buffer, buffer->m_buffer.m_buffer, 1, ©Info); + m_deviceQueue.flush(); + } + else + { + // Copy into mapped buffer directly + void* mappedData = nullptr; + SLANG_VK_CHECK(m_api.vkMapMemory( + m_device, buffer->m_buffer.m_memory, 0, bufferSize, 0, &mappedData)); + ::memcpy(mappedData, initData, bufferSize); + m_api.vkUnmapMemory(m_device, buffer->m_buffer.m_memory); + } } returnComPtr(outResource, buffer); @@ -7936,13 +8169,33 @@ Result VKDevice::createTextureView(ITextureResource* texture, IResourceView::Des auto resourceImpl = static_cast<TextureResourceImpl*>(texture); RefPtr<TextureResourceViewImpl> view = new TextureResourceViewImpl(this); view->m_texture = resourceImpl; + view->m_desc = desc; + if (!texture) + { + view->m_view = VK_NULL_HANDLE; + returnComPtr(outView, view); + return SLANG_OK; + } + bool isArray = false; + switch (desc.type) + { + case IResourceView::Type::DepthStencil: + case IResourceView::Type::RenderTarget: + isArray = desc.renderTarget.arraySize > 1; + break; + case IResourceView::Type::ShaderResource: + case IResourceView::Type::UnorderedAccess: + isArray = desc.subresourceRange.layerCount > 1; + break; + default: + break; + } VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.flags = 0; createInfo.format = gfxIsTypelessFormat(texture->getDesc()->format) ? VulkanUtil::getVkFormat(desc.format) : resourceImpl->m_vkformat; createInfo.image = resourceImpl->m_image; createInfo.components = VkComponentMapping{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,VK_COMPONENT_SWIZZLE_B,VK_COMPONENT_SWIZZLE_A }; - bool isArray = resourceImpl->getDesc()->arraySize != 0; switch (resourceImpl->getType()) { case IResource::Type::Texture1D: @@ -8008,7 +8261,6 @@ Result VKDevice::createTextureView(ITextureResource* texture, IResourceView::Des SLANG_UNIMPLEMENTED_X("Unknown TextureViewDesc type."); break; } - view->m_desc = desc; m_api.vkCreateImageView(m_device, &createInfo, nullptr, &view->m_view); returnComPtr(outView, view); return SLANG_OK; @@ -8017,22 +8269,36 @@ Result VKDevice::createTextureView(ITextureResource* texture, IResourceView::Des Result VKDevice::getFormatSupportedResourceStates(Format format, ResourceStateSet* outStates) { // TODO: Add variables to VkDevice to track supported surface presentable formats + VkFormat vkFormat = VulkanUtil::getVkFormat(format); - VkFormatProperties supportedProperties; - m_api.vkGetPhysicalDeviceFormatProperties(m_api.m_physicalDevice, vkFormat, &supportedProperties); - uint32_t surfaceFormatCount = 0; - m_api.vkGetPhysicalDeviceSurfaceFormatsKHR(m_api.m_physicalDevice, VK_NULL_HANDLE, &surfaceFormatCount, nullptr); + VkFormatProperties supportedProperties = {}; + m_api.vkGetPhysicalDeviceFormatProperties( + m_api.m_physicalDevice, vkFormat, &supportedProperties); + HashSet<VkFormat> presentableFormats; + // TODO: enable this once we have VK_GOOGLE_surfaceless_query. +#if 0 List<VkSurfaceFormatKHR> surfaceFormats; + + uint32_t surfaceFormatCount = 0; + m_api.vkGetPhysicalDeviceSurfaceFormatsKHR( + m_api.m_physicalDevice, VK_NULL_HANDLE, &surfaceFormatCount, nullptr); + surfaceFormats.setCount(surfaceFormatCount); m_api.vkGetPhysicalDeviceSurfaceFormatsKHR(m_api.m_physicalDevice, VK_NULL_HANDLE, &surfaceFormatCount, surfaceFormats.getBuffer()); - - HashSet<VkFormat> presentableFormats; for (auto surfaceFormat : surfaceFormats) { presentableFormats.Add(surfaceFormat.format); } +#else + // Until we have a solution to query presentable formats without needing a surface, + // hard code presentable formats that is supported by most drivers. + presentableFormats.Add(VK_FORMAT_R8G8B8A8_UNORM); + presentableFormats.Add(VK_FORMAT_B8G8R8A8_UNORM); + presentableFormats.Add(VK_FORMAT_R8G8B8A8_SRGB); + presentableFormats.Add(VK_FORMAT_B8G8R8A8_SRGB); +#endif ResourceStateSet allowedStates; // TODO: Currently only supports VK_IMAGE_TILING_OPTIMAL @@ -8108,7 +8374,7 @@ Result VKDevice::createBufferView( auto resourceImpl = (BufferResourceImpl*) buffer; // TODO: These should come from the `ResourceView::Desc` - auto stride = resourceImpl->getDesc()->elementSize; + auto stride = buffer ? resourceImpl->getDesc()->elementSize : 0; if (stride == 0) { if (desc.format == Format::Unknown) @@ -8124,8 +8390,9 @@ Result VKDevice::createBufferView( } } VkDeviceSize offset = (VkDeviceSize)desc.bufferRange.firstElement * stride; - VkDeviceSize size = desc.bufferRange.elementCount == 0 ? resourceImpl->getDesc()->sizeInBytes - : (VkDeviceSize)desc.bufferRange.elementCount * stride; + VkDeviceSize size = desc.bufferRange.elementCount == 0 + ? (buffer ? resourceImpl->getDesc()->sizeInBytes : 0) + : (VkDeviceSize)desc.bufferRange.elementCount * stride; // There are two different cases we need to think about for buffers. // @@ -8177,13 +8444,17 @@ Result VKDevice::createBufferView( { VkBufferViewCreateInfo info = { VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO }; - info.format = VulkanUtil::getVkFormat(desc.format); - info.buffer = resourceImpl->m_buffer.m_buffer; - info.offset = offset; - info.range = size; + VkBufferView view = VK_NULL_HANDLE; - VkBufferView view; - SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateBufferView(m_device, &info, nullptr, &view)); + if (buffer) + { + info.format = VulkanUtil::getVkFormat(desc.format); + info.buffer = resourceImpl->m_buffer.m_buffer; + info.offset = offset; + info.range = size; + + SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateBufferView(m_device, &info, nullptr, &view)); + } RefPtr<TexelBufferResourceViewImpl> viewImpl = new TexelBufferResourceViewImpl(this); viewImpl->m_buffer = resourceImpl; @@ -8596,7 +8867,7 @@ Result VKDevice::createGraphicsPipelineState(const GraphicsPipelineStateDesc& in multisampling.alphaToCoverageEnable = blendDesc.alphaToCoverageEnable; multisampling.alphaToOneEnable = VK_FALSE; - auto targetCount = blendDesc.targetCount; + auto targetCount = Math::Min(framebufferLayoutImpl->m_renderTargetCount, (uint32_t)blendDesc.targetCount); List<VkPipelineColorBlendAttachmentState> colorBlendAttachments; // Regardless of whether blending is enabled, Vulkan always applies the color write mask operation, @@ -8606,6 +8877,7 @@ Result VKDevice::createGraphicsPipelineState(const GraphicsPipelineStateDesc& in { colorBlendAttachments.setCount(1); auto& vkBlendDesc = colorBlendAttachments[0]; + memset(&vkBlendDesc, 0, sizeof(vkBlendDesc)); vkBlendDesc.blendEnable = VK_FALSE; vkBlendDesc.colorWriteMask = (VkColorComponentFlags)RenderTargetWriteMask::EnableAll; } diff --git a/tools/gfx/vulkan/vk-api.h b/tools/gfx/vulkan/vk-api.h index 372ecaeea..4c4d576a7 100644 --- a/tools/gfx/vulkan/vk-api.h +++ b/tools/gfx/vulkan/vk-api.h @@ -257,6 +257,9 @@ struct VulkanExtendedFeatureProperties // Inline uniform block features VkPhysicalDeviceInlineUniformBlockFeaturesEXT inlineUniformBlockFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT}; + // Robustness2 features + VkPhysicalDeviceRobustness2FeaturesEXT robustness2Features = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT}; }; struct VulkanApi diff --git a/tools/gfx/vulkan/vk-util.cpp b/tools/gfx/vulkan/vk-util.cpp index ea87e7c68..633239f24 100644 --- a/tools/gfx/vulkan/vk-util.cpp +++ b/tools/gfx/vulkan/vk-util.cpp @@ -157,6 +157,7 @@ VkImageLayout VulkanUtil::getImageLayoutFromState(ResourceState state) case ResourceState::ShaderResource: return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; case ResourceState::UnorderedAccess: + case ResourceState::General: return VK_IMAGE_LAYOUT_GENERAL; case ResourceState::Present: return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; @@ -200,8 +201,18 @@ VkImageLayout VulkanUtil::getImageLayoutFromState(ResourceState state) { switch (topology) { - case PrimitiveTopology::TriangleList: return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - default: break; + case PrimitiveTopology::LineList: + return VK_PRIMITIVE_TOPOLOGY_LINE_LIST; + case PrimitiveTopology::LineStrip: + return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP; + case PrimitiveTopology::TriangleList: + return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + case PrimitiveTopology::TriangleStrip: + return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + case PrimitiveTopology::PointList: + return VK_PRIMITIVE_TOPOLOGY_POINT_LIST; + default: + break; } assert(!"Unknown topology"); return VK_PRIMITIVE_TOPOLOGY_MAX_ENUM; |
