Skip to content

Commit

Permalink
[gfx] Metal texture fixes (shader-slang#4331)
Browse files Browse the repository at this point in the history
  • Loading branch information
skallweitNV authored Jun 11, 2024
1 parent df0a201 commit 5a28968
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 54 deletions.
1 change: 0 additions & 1 deletion tests/compute/texture-get-dimensions.slang
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
//DISABLE_TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute -shaderobj
// TODO(JS): Doesn't work on CUDA as there aren't any CUDA functions to get dimensions.
//DISABLE_TEST(compute):COMPARE_COMPUTE_EX:-cuda -compute -shaderobj
//DISABLE_TEST(compute):COMPARE_COMPUTE:-slang -shaderobj -mtl

//TEST_INPUT: Texture1D(size=4, content = one):name t1D
Texture1D<float> t1D;
Expand Down
4 changes: 3 additions & 1 deletion tools/gfx/metal/metal-command-buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,9 @@ void CommandBufferImpl::close()

Result CommandBufferImpl::getNativeHandle(InteropHandle* outHandle)
{
return SLANG_E_NOT_IMPLEMENTED;
outHandle->api = InteropHandleAPI::Metal;
outHandle->handleValue = reinterpret_cast<intptr_t>(m_commandBuffer.get());
return SLANG_OK;
}

MTL::RenderCommandEncoder* CommandBufferImpl::getMetalRenderCommandEncoder(MTL::RenderPassDescriptor* renderPassDesc)
Expand Down
6 changes: 3 additions & 3 deletions tools/gfx/metal/metal-command-encoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ void RenderCommandEncoder::beginPass(IRenderPassLayout* renderPass, IFramebuffer
{
TextureResourceViewImpl* renderTargetView = m_framebuffer->m_renderTargetViews[i];
MTL::RenderPassColorAttachmentDescriptor* colorAttachment = m_renderPassDesc->colorAttachments()->object(i);
colorAttachment->setTexture(renderTargetView->m_texture->m_texture.get());
colorAttachment->setTexture(renderTargetView->m_textureView.get());
colorAttachment->setLevel(renderTargetView->m_desc.subresourceRange.mipLevel);
colorAttachment->setSlice(renderTargetView->m_desc.subresourceRange.baseArrayLayer);
}
Expand All @@ -239,14 +239,14 @@ void RenderCommandEncoder::beginPass(IRenderPassLayout* renderPass, IFramebuffer
if (MetalUtil::isDepthFormat(pixelFormat))
{
MTL::RenderPassDepthAttachmentDescriptor* depthAttachment = m_renderPassDesc->depthAttachment();
depthAttachment->setTexture(depthStencilView->m_texture->m_texture.get());
depthAttachment->setTexture(depthStencilView->m_textureView.get());
depthAttachment->setLevel(depthStencilView->m_desc.subresourceRange.mipLevel);
depthAttachment->setSlice(depthStencilView->m_desc.subresourceRange.baseArrayLayer);
}
if (MetalUtil::isStencilFormat(pixelFormat))
{
MTL::RenderPassStencilAttachmentDescriptor* stencilAttachment = m_renderPassDesc->stencilAttachment();
stencilAttachment->setTexture(depthStencilView->m_texture->m_texture.get());
stencilAttachment->setTexture(depthStencilView->m_textureView.get());
stencilAttachment->setLevel(depthStencilView->m_desc.subresourceRange.mipLevel);
stencilAttachment->setSlice(depthStencilView->m_desc.subresourceRange.baseArrayLayer);
}
Expand Down
125 changes: 81 additions & 44 deletions tools/gfx/metal/metal-device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,11 @@ Result DeviceImpl::createTextureResource(

TextureResource::Desc desc = fixupTextureDesc(descIn);

// Metal doesn't support mip-mapping for 1D textures
// However, we still need to use the provided mip level count when initializing the texture
Count initMipLevels = desc.numMipLevels;
desc.numMipLevels = desc.type == IResource::Type::Texture1D ? 1 : desc.numMipLevels;

const MTL::PixelFormat pixelFormat = MetalUtil::translatePixelFormat(desc.format);
if (pixelFormat == MTL::PixelFormat::PixelFormatInvalid)
{
Expand All @@ -316,29 +321,29 @@ Result DeviceImpl::createTextureResource(
break;
}

NS::UInteger arrayLength = calcEffectiveArraySize(desc);
bool isArray = desc.arraySize > 0;

switch (desc.type)
{
case IResource::Type::Texture1D:
textureDesc->setTextureType(arrayLength > 1 ? MTL::TextureType1DArray : MTL::TextureType1D);
textureDesc->setTextureType(isArray ? MTL::TextureType1DArray : MTL::TextureType1D);
textureDesc->setWidth(desc.size.width);
break;
case IResource::Type::Texture2D:
if (desc.sampleDesc.numSamples > 1)
{
textureDesc->setTextureType(arrayLength > 1 ? MTL::TextureType2DMultisampleArray : MTL::TextureType2DMultisample);
textureDesc->setTextureType(isArray ? MTL::TextureType2DMultisampleArray : MTL::TextureType2DMultisample);
textureDesc->setSampleCount(desc.sampleDesc.numSamples);
}
else
{
textureDesc->setTextureType(arrayLength > 1 ? MTL::TextureType2DArray : MTL::TextureType2D);
textureDesc->setTextureType(isArray ? MTL::TextureType2DArray : MTL::TextureType2D);
}
textureDesc->setWidth(descIn.size.width);
textureDesc->setHeight(descIn.size.height);
break;
case IResource::Type::TextureCube:
textureDesc->setTextureType(arrayLength > 6 ? MTL::TextureTypeCubeArray : MTL::TextureTypeCube);
textureDesc->setTextureType(isArray ? MTL::TextureTypeCubeArray : MTL::TextureTypeCube);
textureDesc->setWidth(descIn.size.width);
textureDesc->setHeight(descIn.size.height);
break;
Expand Down Expand Up @@ -369,7 +374,7 @@ Result DeviceImpl::createTextureResource(
}

textureDesc->setMipmapLevelCount(desc.numMipLevels);
textureDesc->setArrayLength(arrayLength);
textureDesc->setArrayLength(isArray ? desc.arraySize : 1);
textureDesc->setPixelFormat(pixelFormat);
textureDesc->setUsage(textureUsage);
textureDesc->setSampleCount(desc.sampleDesc.numSamples);
Expand All @@ -380,8 +385,52 @@ Result DeviceImpl::createTextureResource(
{
return SLANG_FAIL;
}
textureImpl->m_textureType = textureDesc->textureType();
textureImpl->m_pixelFormat = textureDesc->pixelFormat();

// TODO: handle initData
if (initData)
{
textureDesc->setStorageMode(MTL::StorageModeManaged);
textureDesc->setCpuCacheMode(MTL::CPUCacheModeDefaultCache);
NS::SharedPtr<MTL::Texture> stagingTexture = NS::TransferPtr(m_device->newTexture(textureDesc.get()));

MTL::CommandBuffer* commandBuffer = m_commandQueue->commandBuffer();
MTL::BlitCommandEncoder* encoder = commandBuffer->blitCommandEncoder();
if (!stagingTexture || !commandBuffer || !encoder)
{
return SLANG_FAIL;
}

Count sliceCount = isArray ? desc.arraySize : 1;
if (desc.type == IResource::Type::TextureCube)
{
sliceCount *= 6;
}

for (Index slice = 0; slice < sliceCount; ++slice)
{
MTL::Region region;
region.origin = MTL::Origin(0, 0, 0);
region.size = MTL::Size(desc.size.width, desc.size.height, desc.size.depth);
for (Index level = 0; level < initMipLevels; ++level)
{
if (level >= desc.numMipLevels)
continue;
const ITextureResource::SubresourceData& subresourceData = initData[slice * initMipLevels + level];
stagingTexture->replaceRegion(region, level, slice, subresourceData.data, subresourceData.strideY, subresourceData.strideZ);
encoder->synchronizeTexture(stagingTexture.get(), slice, level);
region.size.width = region.size.width > 0 ? Math::Max(1ul, region.size.width >> 1) : 0;
region.size.height = region.size.height > 0 ? Math::Max(1ul, region.size.height >> 1) : 0;
region.size.depth = region.size.depth > 0 ? Math::Max(1ul, region.size.depth >> 1) : 0;
}
}

encoder->copyFromTexture(stagingTexture.get(), textureImpl->m_texture.get());
encoder->endEncoding();
commandBuffer->commit();
commandBuffer->waitUntilCompleted();
}

returnComPtr(outResource, textureImpl);
return SLANG_OK;
Expand Down Expand Up @@ -461,52 +510,40 @@ Result DeviceImpl::createTextureView(
{
AUTORELEASEPOOL

auto resourceImpl = static_cast<TextureResourceImpl*>(texture);
RefPtr<TextureResourceViewImpl> view = new TextureResourceViewImpl(this);
view->m_desc = desc;
view->m_device = this;
if (texture == nullptr)
auto textureImpl = static_cast<TextureResourceImpl*>(texture);
RefPtr<TextureResourceViewImpl> viewImpl = new TextureResourceViewImpl(this);
viewImpl->m_desc = desc;
viewImpl->m_device = this;
viewImpl->m_texture = textureImpl;
if (textureImpl == nullptr)
{
view->m_texture = nullptr;
returnComPtr(outView, view);
returnComPtr(outView, viewImpl);
return SLANG_OK;
}

bool isArray = resourceImpl->getDesc()->arraySize > 1;
MTL::PixelFormat pixelFormat = MetalUtil::translatePixelFormat(desc.format);
NS::Range levelRange(desc.subresourceRange.baseArrayLayer, std::max(desc.subresourceRange.layerCount, 1));
NS::Range sliceRange(desc.subresourceRange.mipLevel, std::max(desc.subresourceRange.mipLevelCount, 1));
MTL::TextureType textureType;
switch (resourceImpl->getType())
{
case IResource::Type::Texture1D:
textureType = isArray ? MTL::TextureType1DArray : MTL::TextureType1D;
break;
case IResource::Type::Texture2D:
textureType = isArray ? MTL::TextureType2DArray : MTL::TextureType2D;
break;
case IResource::Type::Texture3D:
const ITextureResource::Desc& textureDesc = *textureImpl->getDesc();
SubresourceRange sr = desc.subresourceRange;
sr.mipLevelCount = sr.mipLevelCount == 0 ? textureDesc.numMipLevels - sr.mipLevel : sr.mipLevelCount;
sr.layerCount = sr.layerCount == 0 ? textureDesc.arraySize - sr.baseArrayLayer : sr.layerCount;
if (sr.mipLevel == 0 && sr.mipLevelCount == textureDesc.numMipLevels &&
sr.baseArrayLayer == 0 && sr.layerCount == textureDesc.arraySize)
{
if (isArray) SLANG_UNIMPLEMENTED_X("Metal does not support arrays of 3D textures.");
textureType = MTL::TextureType3D;
break;
}
case IResource::Type::TextureCube:
textureType = isArray ? MTL::TextureTypeCube : MTL::TextureTypeCubeArray;
break;
default:
SLANG_UNIMPLEMENTED_X("Unsupported texture type.");
break;
viewImpl->m_textureView = textureImpl->m_texture;
returnComPtr(outView, viewImpl);
return SLANG_OK;
}
ITextureResource::Desc newDesc = *texture->getDesc();
newDesc.numMipLevels = levelRange.length;
newDesc.arraySize = sliceRange.length;

view->m_type = ResourceViewImpl::ViewType::Texture;
view->m_texture = resourceImpl; //new TextureResourceImpl(newDesc, this);
view->m_texture->m_texture = NS::TransferPtr(resourceImpl->m_texture->newTextureView(pixelFormat, textureType, levelRange, sliceRange));
returnComPtr(outView, view);
MTL::PixelFormat pixelFormat = desc.format == Format::Unknown ? textureImpl->m_pixelFormat : MetalUtil::translatePixelFormat(desc.format);
NS::Range levelRange(sr.baseArrayLayer, sr.layerCount);
NS::Range sliceRange(sr.mipLevel, sr.mipLevelCount);

viewImpl->m_textureView = NS::TransferPtr(textureImpl->m_texture->newTextureView(pixelFormat, textureImpl->m_textureType, levelRange, sliceRange));
if (!viewImpl->m_textureView)
{
return SLANG_FAIL;
}

returnComPtr(outView, viewImpl);
return SLANG_OK;
}

Expand Down
13 changes: 12 additions & 1 deletion tools/gfx/metal/metal-pipeline-state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,18 @@ Result PipelineStateImpl::ensureAPIPipelineStateCreated()

SLANG_NO_THROW Result SLANG_MCALL PipelineStateImpl::getNativeHandle(InteropHandle* outHandle)
{
return SLANG_E_NOT_IMPLEMENTED;
switch (desc.type)
{
case PipelineType::Compute:
outHandle->api = InteropHandleAPI::Metal;
outHandle->handleValue = reinterpret_cast<intptr_t>(m_computePipelineState.get());
return SLANG_OK;
case PipelineType::Graphics:
outHandle->api = InteropHandleAPI::Metal;
outHandle->handleValue = reinterpret_cast<intptr_t>(m_renderPipelineState.get());
return SLANG_OK;
}
return SLANG_FAIL;
}

RayTracingPipelineStateImpl::RayTracingPipelineStateImpl(DeviceImpl* device)
Expand Down
1 change: 1 addition & 0 deletions tools/gfx/metal/metal-resource-views.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class TextureResourceViewImpl : public ResourceViewImpl
{}
~TextureResourceViewImpl();
RefPtr<TextureResourceImpl> m_texture;
NS::SharedPtr<MTL::Texture> m_textureView;

virtual SLANG_NO_THROW Result SLANG_MCALL getNativeHandle(InteropHandle* outHandle) override;
};
Expand Down
2 changes: 1 addition & 1 deletion tools/gfx/metal/metal-shader-object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ Result ShaderObjectImpl::bindAsValue(
for (uint32_t i = 0; i < count; ++i)
{
auto texture = m_textures[baseIndex + i];
context->setTexture(texture ? texture->m_texture->m_texture.get() : nullptr, registerOffset + i);
context->setTexture(texture ? texture->m_textureView.get() : nullptr, registerOffset + i);
}
}

Expand Down
5 changes: 2 additions & 3 deletions tools/gfx/metal/metal-texture.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@ class TextureResourceImpl : public TextureResource

BreakableReference<DeviceImpl> m_device;
NS::SharedPtr<MTL::Texture> m_texture;
// TODO still needed?
// MTL::PixelFormat m_metalFormat = MTL::PixelFormat::PixelFormatInvalid;
// bool m_isWeakImageReference = false;
MTL::TextureType m_textureType;
MTL::PixelFormat m_pixelFormat;

virtual SLANG_NO_THROW Result SLANG_MCALL getNativeResourceHandle(InteropHandle* outHandle) override;

Expand Down

0 comments on commit 5a28968

Please sign in to comment.