Skip to content

Commit 5e57567

Browse files
Metal improvements (#319)
* fix render pipeline creation * fix capture support * add support for clearing depth/stencil textures * add depth/stencil clear test (disabled) --------- Co-authored-by: Simon Kallweit <[email protected]>
1 parent f4d5e75 commit 5e57567

File tree

9 files changed

+126
-14
lines changed

9 files changed

+126
-14
lines changed

src/debug-layer/debug-command-encoder.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,7 @@ void DebugCommandEncoder::clearTextureDepthStencil(
557557
}
558558
break;
559559
case DeviceType::Metal:
560+
break;
560561
case DeviceType::WGPU:
561562
RHI_VALIDATION_ERROR("Not implemented");
562563
return;

src/format-conversion.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ static const FormatConversionFuncs sFuncs[] = {
7777
{Format::R11G11B10Float, nullptr, nullptr, nullptr, nullptr},
7878

7979
{Format::D32Float, packInt32<1>, unpackInt32<1>, packFloat32<1>, unpackFloat32<1>},
80-
{Format::D16Unorm, nullptr, nullptr, nullptr, nullptr},
80+
{Format::D16Unorm, packInt16<1>, unpackInt16<1>, packUnorm16<1>, unpackUnorm16<1>},
8181
{Format::D32FloatS8Uint, nullptr, nullptr, nullptr, nullptr},
8282
};
8383

src/metal/metal-command.cpp

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,63 @@ void CommandRecorder::cmdClearTextureUint(const commands::ClearTextureUint& cmd)
261261

262262
void CommandRecorder::cmdClearTextureDepthStencil(const commands::ClearTextureDepthStencil& cmd)
263263
{
264-
NOT_SUPPORTED(S_CommandEncoder_clearTextureDepthStencil);
264+
TextureImpl* texture = checked_cast<TextureImpl*>(cmd.texture);
265+
const TextureDesc& desc = texture->m_desc;
266+
if (!is_set(desc.usage, TextureUsage::DepthStencil))
267+
return;
268+
269+
// Create a dummy render pass descriptor
270+
NS::SharedPtr<MTL::RenderPassDescriptor> renderPassDesc =
271+
NS::TransferPtr(MTL::RenderPassDescriptor::alloc()->init());
272+
273+
// Setup depth stencil attachment
274+
if (MetalUtil::isDepthFormat(texture->m_pixelFormat) && cmd.clearDepth)
275+
{
276+
MTL::RenderPassDepthAttachmentDescriptor* depthAttachment = renderPassDesc->depthAttachment();
277+
depthAttachment->setLoadAction(MTL::LoadActionClear);
278+
depthAttachment->setStoreAction(MTL::StoreActionStore);
279+
depthAttachment->setClearDepth(cmd.depthValue);
280+
depthAttachment->setTexture(texture->m_texture.get());
281+
}
282+
if (MetalUtil::isStencilFormat(texture->m_pixelFormat) && cmd.clearStencil)
283+
{
284+
MTL::RenderPassStencilAttachmentDescriptor* stencilAttachment = renderPassDesc->stencilAttachment();
285+
stencilAttachment->setLoadAction(MTL::LoadActionClear);
286+
stencilAttachment->setStoreAction(MTL::StoreActionStore);
287+
stencilAttachment->setClearStencil(cmd.stencilValue);
288+
stencilAttachment->setTexture(texture->m_texture.get());
289+
}
290+
291+
// Loop through all requested mip levels and array layers
292+
for (uint32_t layerOffset = 0; layerOffset < cmd.subresourceRange.layerCount; layerOffset++)
293+
{
294+
uint32_t layerIndex = cmd.subresourceRange.layer + layerOffset;
295+
for (uint32_t mipOffset = 0; mipOffset < cmd.subresourceRange.mipLevelCount; mipOffset++)
296+
{
297+
uint32_t mipLevel = cmd.subresourceRange.mipLevel + mipOffset;
298+
299+
// Set the level and slice for this iteration
300+
if (MetalUtil::isDepthFormat(texture->m_pixelFormat) && cmd.clearDepth)
301+
{
302+
renderPassDesc->depthAttachment()->setLevel(mipLevel);
303+
renderPassDesc->depthAttachment()->setSlice(layerIndex);
304+
}
305+
if (MetalUtil::isStencilFormat(texture->m_pixelFormat) && cmd.clearStencil)
306+
{
307+
renderPassDesc->stencilAttachment()->setLevel(mipLevel);
308+
renderPassDesc->stencilAttachment()->setSlice(layerIndex);
309+
}
310+
311+
// Set render target size for this mip level
312+
Extent3D mipSize = calcMipSize(desc.size, mipLevel);
313+
renderPassDesc->setRenderTargetWidth(mipSize.width);
314+
renderPassDesc->setRenderTargetHeight(mipSize.height);
315+
316+
// Create and execute the render pass for this subresource
317+
getRenderCommandEncoder(renderPassDesc.get());
318+
endCommandEncoder();
319+
}
320+
}
265321
}
266322

267323
void CommandRecorder::cmdUploadTextureData(const commands::UploadTextureData& cmd)

src/metal/metal-device.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ DeviceImpl::DeviceImpl() {}
2424

2525
DeviceImpl::~DeviceImpl()
2626
{
27+
if (captureEnabled())
28+
{
29+
MTL::CaptureManager* captureManager = MTL::CaptureManager::sharedCaptureManager();
30+
captureManager->stopCapture();
31+
}
32+
2733
m_queue.setNull();
2834
m_clearEngine.release();
2935
}
@@ -82,6 +88,8 @@ Result DeviceImpl::initialize(const DeviceDesc& desc)
8288
.initialize(desc.slang, SLANG_METAL_LIB, "", std::array{slang::PreprocessorMacroDesc{"__METAL__", "1"}})
8389
);
8490

91+
SLANG_RETURN_ON_FAIL(m_clearEngine.initialize(m_device.get()));
92+
8593
// TODO: expose via some other means
8694
if (captureEnabled())
8795
{
@@ -110,8 +118,6 @@ Result DeviceImpl::initialize(const DeviceDesc& desc)
110118
}
111119
}
112120

113-
SLANG_RETURN_ON_FAIL(m_clearEngine.initialize(m_device.get()));
114-
115121
return SLANG_OK;
116122
}
117123

src/metal/metal-device.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ class DeviceImpl : public Device
108108
DeviceInfo m_info;
109109
std::string m_adapterName;
110110

111-
bool captureEnabled() const { return std::getenv("MTL_CAPTURE") != nullptr; }
111+
bool captureEnabled() const { return std::getenv("MTL_CAPTURE_ENABLED") != nullptr; }
112112

113113
DeviceDesc m_desc;
114114
NS::SharedPtr<MTL::Device> m_device;

src/metal/metal-pipeline.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,12 +131,6 @@ Result DeviceImpl::createRenderPipeline2(const RenderPipelineDesc& desc, IRender
131131
const auto& depthStencil = desc.depthStencil;
132132
NS::SharedPtr<MTL::DepthStencilDescriptor> depthStencilDesc =
133133
NS::TransferPtr(MTL::DepthStencilDescriptor::alloc()->init());
134-
NS::SharedPtr<MTL::DepthStencilState> depthStencilState =
135-
NS::TransferPtr(m_device->newDepthStencilState(depthStencilDesc.get()));
136-
if (!depthStencilState)
137-
{
138-
return SLANG_FAIL;
139-
}
140134
if (depthStencil.depthTestEnable)
141135
{
142136
depthStencilDesc->setDepthCompareFunction(MetalUtil::translateCompareFunction(depthStencil.depthFunc));
@@ -151,6 +145,12 @@ Result DeviceImpl::createRenderPipeline2(const RenderPipelineDesc& desc, IRender
151145
createStencilDesc(depthStencil.backFace, depthStencil.stencilReadMask, depthStencil.stencilWriteMask).get()
152146
);
153147
}
148+
NS::SharedPtr<MTL::DepthStencilState> depthStencilState =
149+
NS::TransferPtr(m_device->newDepthStencilState(depthStencilDesc.get()));
150+
if (!depthStencilState)
151+
{
152+
return SLANG_FAIL;
153+
}
154154

155155
RefPtr<RenderPipelineImpl> pipeline = new RenderPipelineImpl(this);
156156
pipeline->m_program = program;

src/metal/metal-texture.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ Result DeviceImpl::createTexture(const TextureDesc& desc_, const SubresourceData
8787
textureDesc->setSampleCount(desc.sampleCount);
8888

8989
MTL::TextureUsage textureUsage = MTL::TextureUsageUnknown;
90-
if (is_set(desc.usage, TextureUsage::RenderTarget))
90+
if (is_set(desc.usage, TextureUsage::RenderTarget) || is_set(desc.usage, TextureUsage::DepthStencil))
9191
{
9292
textureUsage |= MTL::TextureUsageRenderTarget;
9393
}

tests/test-cmd-clear-texture.cpp

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,12 @@ static const std::vector<Format> kSintFormats = {
100100
// Format::R64Sint, // TODO not supported yet
101101
};
102102

103+
static const std::vector<Format> kDepthStencilFormats = {
104+
Format::D16Unorm,
105+
Format::D32Float,
106+
Format::D32FloatS8Uint,
107+
};
108+
103109
GPU_TEST_CASE("cmd-clear-texture-float-zero", D3D11 | D3D12 | Vulkan | Metal | CUDA)
104110
{
105111
TextureTestOptions options(device, 1);
@@ -274,4 +280,47 @@ GPU_TEST_CASE("cmd-clear-texture-sint-pattern", D3D11 | D3D12 | Vulkan | Metal |
274280
);
275281
}
276282

277-
GPU_TEST_CASE("cmd-clear-texture-depth-stencil", D3D11 | D3D12 | Vulkan | Metal) {}
283+
GPU_TEST_CASE("cmd-clear-texture-depth-stencil", D3D11 | D3D12 | Vulkan | Metal)
284+
{
285+
#if 0
286+
TextureTestOptions options(device, 1);
287+
options.addVariants(
288+
TTShape::D2,
289+
TTArray::Both,
290+
TTMip::Both,
291+
TTMS::Off,
292+
kDepthStencilFormats,
293+
TextureUsage::DepthStencil
294+
);
295+
296+
runTextureTest(
297+
options,
298+
[device](TextureTestContext* c)
299+
{
300+
printf("cmd-clear-texture-depth-stencil\n");
301+
ComPtr<ITexture> texture = c->getTexture();
302+
ComPtr<ICommandQueue> queue = device->getQueue(QueueType::Graphics);
303+
{
304+
ComPtr<ICommandEncoder> encoder = queue->createCommandEncoder();
305+
306+
// Clear depth to 0.5 and stencil to 42
307+
float depthValue = 0.5f;
308+
uint8_t stencilValue = 42;
309+
310+
// Create a subresource range that covers all mips and array layers
311+
SubresourceRange range = kEntireTexture;
312+
313+
// Clear both depth and stencil
314+
encoder->clearTextureDepthStencil(texture, range, true, depthValue, true, stencilValue);
315+
queue->submit(encoder->finish());
316+
317+
// Verify the clear values
318+
// For depth formats, we use clearFloat with the depth value
319+
float clearValues[4] = {depthValue, 0.0f, 0.0f, 0.0f};
320+
c->getTextureData().clearFloat(clearValues);
321+
c->getTextureData().checkEqual(texture);
322+
}
323+
}
324+
);
325+
#endif
326+
}

tests/texture-test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1224,7 +1224,7 @@ void TextureTestOptions::filterFormat(int state, TextureTestVariant variant)
12241224

12251225
const FormatInfo& info = getFormatInfo(format);
12261226

1227-
// WebGPU doesn't support writing into depth textures.
1227+
// Metal doesn't support writing into depth textures.
12281228
if (m_device->getDeviceType() == DeviceType::Metal && (info.hasDepth || info.hasStencil))
12291229
return;
12301230

0 commit comments

Comments
 (0)