summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorskallweitNV <64953474+skallweitNV@users.noreply.github.com>2024-06-10 18:12:01 +0200
committerGitHub <noreply@github.com>2024-06-10 18:12:01 +0200
commit6857dd57549f01daa025f45221a693259e474958 (patch)
treec6db90150ff093eea525e57c7e52c0cc1c970095 /tools
parent0974463daf0982626cb2b8c8bb6f494f3e6c9e52 (diff)
[gfx] Metal graphics support (#4324)
* fix double semicolons * fix another double semicolon * wait for init data upload * remove obsolete setData * refactor swapchain to work on virtual back buffers * buffer/texture use breakable device reference * refactor input layout * create render command encoder * add todo * refactor framebuffer layout * refactor framebuffer * refactor shader program * translatePrimitiveType * add more translate functions * refactor framebuffer * refactor render pass * implement graphics pipeline state * add depth stencil state * initial render command encoder support * comment
Diffstat (limited to 'tools')
-rw-r--r--tools/gfx/metal/metal-buffer.h2
-rw-r--r--tools/gfx/metal/metal-command-buffer.cpp4
-rw-r--r--tools/gfx/metal/metal-command-buffer.h2
-rw-r--r--tools/gfx/metal/metal-command-encoder.cpp241
-rw-r--r--tools/gfx/metal/metal-command-encoder.h36
-rw-r--r--tools/gfx/metal/metal-device.cpp65
-rw-r--r--tools/gfx/metal/metal-framebuffer.cpp78
-rw-r--r--tools/gfx/metal/metal-framebuffer.h30
-rw-r--r--tools/gfx/metal/metal-helper-functions.h60
-rw-r--r--tools/gfx/metal/metal-pipeline-state.cpp137
-rw-r--r--tools/gfx/metal/metal-pipeline-state.h2
-rw-r--r--tools/gfx/metal/metal-render-pass.cpp38
-rw-r--r--tools/gfx/metal/metal-render-pass.h2
-rw-r--r--tools/gfx/metal/metal-shader-program.cpp15
-rw-r--r--tools/gfx/metal/metal-shader-program.h14
-rw-r--r--tools/gfx/metal/metal-swap-chain.cpp82
-rw-r--r--tools/gfx/metal/metal-swap-chain.h3
-rw-r--r--tools/gfx/metal/metal-texture.h2
-rw-r--r--tools/gfx/metal/metal-util.cpp206
-rw-r--r--tools/gfx/metal/metal-util.h31
-rw-r--r--tools/gfx/metal/metal-vertex-layout.cpp57
-rw-r--r--tools/gfx/metal/metal-vertex-layout.h6
-rw-r--r--tools/gfx/vulkan/vk-fence.cpp2
23 files changed, 748 insertions, 367 deletions
diff --git a/tools/gfx/metal/metal-buffer.h b/tools/gfx/metal/metal-buffer.h
index 08fa6481d..3f8f60d0e 100644
--- a/tools/gfx/metal/metal-buffer.h
+++ b/tools/gfx/metal/metal-buffer.h
@@ -17,7 +17,7 @@ class BufferResourceImpl : public BufferResource
public:
typedef BufferResource Parent;
- RefPtr<DeviceImpl> m_device;
+ BreakableReference<DeviceImpl> m_device;
NS::SharedPtr<MTL::Buffer> m_buffer;
BufferResourceImpl(const IBufferResource::Desc& desc, DeviceImpl* device);
diff --git a/tools/gfx/metal/metal-command-buffer.cpp b/tools/gfx/metal/metal-command-buffer.cpp
index 8aac6ea4b..c54552ae4 100644
--- a/tools/gfx/metal/metal-command-buffer.cpp
+++ b/tools/gfx/metal/metal-command-buffer.cpp
@@ -80,12 +80,12 @@ Result CommandBufferImpl::getNativeHandle(InteropHandle* outHandle)
return SLANG_E_NOT_IMPLEMENTED;
}
-MTL::RenderCommandEncoder* CommandBufferImpl::getMetalRenderCommandEncoder()
+MTL::RenderCommandEncoder* CommandBufferImpl::getMetalRenderCommandEncoder(MTL::RenderPassDescriptor* renderPassDesc)
{
if (!m_metalRenderCommandEncoder)
{
endMetalCommandEncoder();
- // m_metalRenderCommandEncoder = NS::RetainPtr(m_commandBuffer->renderCommandEncoder());
+ m_metalRenderCommandEncoder = NS::RetainPtr(m_commandBuffer->renderCommandEncoder(renderPassDesc));
}
return m_metalRenderCommandEncoder.get();
}
diff --git a/tools/gfx/metal/metal-command-buffer.h b/tools/gfx/metal/metal-command-buffer.h
index 3041ba310..6c000b5df 100644
--- a/tools/gfx/metal/metal-command-buffer.h
+++ b/tools/gfx/metal/metal-command-buffer.h
@@ -45,7 +45,7 @@ public:
void beginCommandBuffer();
- MTL::RenderCommandEncoder* getMetalRenderCommandEncoder();
+ MTL::RenderCommandEncoder* getMetalRenderCommandEncoder(MTL::RenderPassDescriptor* renderPassDesc);
MTL::ComputeCommandEncoder* getMetalComputeCommandEncoder();
MTL::BlitCommandEncoder* getMetalBlitCommandEncoder();
void endMetalCommandEncoder();
diff --git a/tools/gfx/metal/metal-command-encoder.cpp b/tools/gfx/metal/metal-command-encoder.cpp
index f1e834400..3e0fbd1f6 100644
--- a/tools/gfx/metal/metal-command-encoder.cpp
+++ b/tools/gfx/metal/metal-command-encoder.cpp
@@ -209,52 +209,59 @@ void ResourceCommandEncoder::endDebugEvent()
void RenderCommandEncoder::beginPass(IRenderPassLayout* renderPass, IFramebuffer* framebuffer)
{
- FramebufferImpl* fb = static_cast<FramebufferImpl*>(framebuffer);
- if (fb == nullptr)
+ m_renderPassLayout = static_cast<RenderPassLayoutImpl*>(renderPass);
+ m_framebuffer = static_cast<FramebufferImpl*>(framebuffer);
+ if (!m_framebuffer)
{
+ // TODO use empty framebuffer
return;
}
- RenderPassLayoutImpl* renderPassLayoutImpl = static_cast<RenderPassLayoutImpl*>(renderPass);
- MTL::RenderPassDescriptor* rpd = renderPassLayoutImpl->m_renderPassDesc->copy();
+ // Create a copy of the render pass descriptor and fill in remaining information.
+ m_renderPassDesc = NS::TransferPtr(m_renderPassLayout->m_renderPassDesc->copy());
- if (rpd->depthAttachment() && false)
+ m_renderPassDesc->setRenderTargetWidth(m_framebuffer->m_width);
+ m_renderPassDesc->setRenderTargetHeight(m_framebuffer->m_height);
+
+ for (Index i = 0; i < m_framebuffer->m_renderTargetViews.getCount(); ++i)
{
- TextureResourceViewImpl* depthView = static_cast<TextureResourceViewImpl*>(fb->depthStencilView.get());
- rpd->depthAttachment()->setTexture(depthView->m_texture->m_texture.get());
+ TextureResourceViewImpl* renderTargetView = m_framebuffer->m_renderTargetViews[i];
+ MTL::RenderPassColorAttachmentDescriptor* colorAttachment = m_renderPassDesc->colorAttachments()->object(i);
+ colorAttachment->setTexture(renderTargetView->m_texture->m_texture.get());
+ colorAttachment->setLevel(renderTargetView->m_desc.subresourceRange.mipLevel);
+ colorAttachment->setSlice(renderTargetView->m_desc.subresourceRange.baseArrayLayer);
}
- const int colorTargetCount = fb->renderTargetViews.getCount();
- for (int i = 0; i < colorTargetCount; ++i)
+
+ if (m_framebuffer->m_depthStencilView)
{
- TextureResourceViewImpl* texView = static_cast<TextureResourceViewImpl*>(fb->renderTargetViews[i].get());
- MTL::Texture* tex = nullptr;
- assert(texView->m_texture);
- tex = texView->m_texture->m_texture.get();
- rpd->colorAttachments()->object(i)->setTexture(tex);
- rpd->colorAttachments()->object(i)->setClearColor(MTL::ClearColor(0.2, 0.4, 0.9, 1.0));
+ TextureResourceViewImpl* depthStencilView = m_framebuffer->m_depthStencilView.get();
+ MTL::PixelFormat pixelFormat = MetalUtil::translatePixelFormat(depthStencilView->m_desc.format);
+ if (MetalUtil::isDepthFormat(pixelFormat))
+ {
+ MTL::RenderPassDepthAttachmentDescriptor* depthAttachment = m_renderPassDesc->depthAttachment();
+ depthAttachment->setTexture(depthStencilView->m_texture->m_texture.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->setLevel(depthStencilView->m_desc.subresourceRange.mipLevel);
+ stencilAttachment->setSlice(depthStencilView->m_desc.subresourceRange.baseArrayLayer);
+ }
}
- rpd->setRenderTargetWidth(fb->m_width);
- rpd->setRenderTargetHeight(fb->m_height);
-
- m_encoder = m_metalCommandBuffer->renderCommandEncoder(rpd);
}
void RenderCommandEncoder::endEncoding()
{
- m_encoder->endEncoding();
+ PipelineCommandEncoder::endEncodingImpl();
}
Result RenderCommandEncoder::bindPipeline(
IPipelineState* pipelineState, IShaderObject** outRootObject)
{
- m_currentPipeline = static_cast<PipelineStateImpl*>(pipelineState);
- // Initialize the root object
- SLANG_RETURN_ON_FAIL(m_commandBuffer->m_rootObject.init(m_commandBuffer->m_device,
- m_currentPipeline->getProgram<ShaderProgramImpl>()->m_rootObjectLayout));
- *outRootObject = &m_commandBuffer->m_rootObject;
- //if (pPipelineState->m_renderState == nullptr) return SLANG_ERROR_INVALID_PARAMETER;
- //m_encoder->setRenderPipelineState(pPipelineState->m_renderState);
- return SLANG_OK;
+ return setPipelineStateImpl(pipelineState, outRootObject);
}
Result RenderCommandEncoder::bindPipelineWithRootObject(
@@ -265,44 +272,37 @@ Result RenderCommandEncoder::bindPipelineWithRootObject(
void RenderCommandEncoder::setViewports(GfxCount count, const Viewport* viewports)
{
- static const int kMaxViewports = 8; // TODO: base on device caps
- assert(count <= kMaxViewports);
-
m_viewports.setCount(count);
for (GfxIndex i = 0; i < count; ++i)
{
- const auto& inViewport = viewports[i];
- auto& metalViewport = m_viewports[i];
- metalViewport.height = inViewport.extentY;
- metalViewport.width = inViewport.extentX;
- metalViewport.originX = inViewport.originX;
- metalViewport.originY = inViewport.originY;
- metalViewport.znear = inViewport.minZ;
- metalViewport.zfar = inViewport.maxZ;
+ const auto& viewport = viewports[i];
+ auto& mtlViewport = m_viewports[i];
+ mtlViewport.originX = viewport.originX;
+ mtlViewport.originY = viewport.originY;
+ mtlViewport.width = viewport.extentX;
+ mtlViewport.height = viewport.extentY;
+ mtlViewport.znear = viewport.minZ;
+ mtlViewport.zfar = viewport.maxZ;
}
- m_encoder->setViewports(m_viewports.begin(), count);
}
void RenderCommandEncoder::setScissorRects(GfxCount count, const ScissorRect* rects)
{
- static const int kMaxScissorRects = 9; // TODO:
- assert(count < kMaxScissorRects);
-
m_scissorRects.setCount(count);
for (GfxIndex i = 0; i < count; ++i)
{
- const auto& inRect = rects[i];
- auto& metalRect = m_scissorRects[i];
- metalRect.height = inRect.maxX - inRect.minX;
- metalRect.width = inRect.maxY - inRect.minY;
- metalRect.x = inRect.minX;
- metalRect.y = inRect.minY;
+ const auto& rect = rects[i];
+ auto& mtlRect = m_scissorRects[i];
+ mtlRect.x = rect.minX;
+ mtlRect.y = rect.minY;
+ mtlRect.width = rect.maxX - rect.minX;
+ mtlRect.height = rect.maxY - rect.minY;
}
- m_encoder->setScissorRects(m_scissorRects.begin(), count);
}
void RenderCommandEncoder::setPrimitiveTopology(PrimitiveTopology topology)
{
+ m_primitiveType = MetalUtil::translatePrimitiveType(topology);
}
void RenderCommandEncoder::setVertexBuffers(
@@ -311,79 +311,104 @@ void RenderCommandEncoder::setVertexBuffers(
IBufferResource* const* buffers,
const Offset* offsets)
{
- for (GfxIndex i = 0; i < GfxIndex(slotCount); i++)
+ Index count = Math::Max(m_vertexBuffers.getCount(), Index(startSlot + slotCount));
+ m_vertexBuffers.setCount(count);
+ m_vertexBufferOffsets.setCount(count);
+
+ for (Index i = 0; i < Index(slotCount); i++)
{
- GfxIndex slotIndex = startSlot + i;
- BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(buffers[i]);
- if (buffer)
- {
- MTL::Buffer* vertexBuffers = {buffer->m_buffer.get()};
- m_encoder->setVertexBuffer(buffer->m_buffer.get(), offsets[i], slotIndex);
- // ...
- }
+ Index slotIndex = startSlot + i;
+ m_vertexBuffers[slotIndex] = static_cast<BufferResourceImpl*>(buffers[i])->m_buffer.get();
+ m_vertexBufferOffsets[slotIndex] = offsets[i];
}
}
void RenderCommandEncoder::setIndexBuffer(
IBufferResource* buffer, Format indexFormat, Offset offset)
{
+ m_indexBuffer = static_cast<BufferResourceImpl*>(buffer)->m_buffer.get();
+ m_indexBufferOffset = offset;
+
+ switch (indexFormat)
+ {
+ case Format::R16_UINT:
+ m_indexBufferType = MTL::IndexTypeUInt16;
+ break;
+ case Format::R32_UINT:
+ m_indexBufferType = MTL::IndexTypeUInt32;
+ break;
+ default:
+ assert(!"unsupported index format");
+ }
+}
+
+void RenderCommandEncoder::setStencilReference(uint32_t referenceValue)
+{
+ m_stencilReferenceValue = referenceValue;
}
-Result RenderCommandEncoder::prepareDraw()
+Result RenderCommandEncoder::setSamplePositions(
+ GfxCount samplesPerPixel, GfxCount pixelCount, const SamplePosition* samplePositions)
+{
+ return SLANG_E_NOT_AVAILABLE;
+}
+
+Result RenderCommandEncoder::prepareDraw(MTL::RenderCommandEncoder*& encoder)
{
- // Bind render state, including JIT pipeline state object creation
auto pipeline = static_cast<PipelineStateImpl*>(m_currentPipeline.Ptr());
- if (!pipeline)
+ pipeline->ensureAPIPipelineStateCreated();
+
+ encoder = m_commandBuffer->getMetalRenderCommandEncoder(m_renderPassDesc.get());
+ encoder->setRenderPipelineState(pipeline->m_renderPipelineState.get());
+ // TODO only vertex stage bindings are set for now
+ VertexBindingContext bindingContext;
+ bindingContext.init(m_commandBuffer->m_device, encoder);
+ auto program = static_cast<ShaderProgramImpl*>(m_currentPipeline->m_program.get());
+ m_commandBuffer->m_rootObject.bindAsRoot(&bindingContext, program->m_rootObjectLayout);
+
+ for (Index i = 0; i < m_vertexBuffers.getCount(); ++i)
{
- return SLANG_FAIL;
+ encoder->setVertexBuffer(m_vertexBuffers[i], m_vertexBufferOffsets[i], m_currentPipeline->m_vertexBufferOffset + i);
}
- // TODO: specialization, binding, ...
- SLANG_RETURN_ON_FAIL(pipeline->ensureAPIPipelineStateCreated());
- return SLANG_OK;
-}
-static Result translatePrimitiveType(gfx::PrimitiveType primType, MTL::PrimitiveType& mtlType)
-{
- switch (primType)
+ encoder->setViewports(m_viewports.getArrayView().getBuffer(), m_viewports.getCount());
+ encoder->setScissorRects(m_scissorRects.getArrayView().getBuffer(), m_scissorRects.getCount());
+
+ const RasterizerDesc& rasterDesc = pipeline->desc.graphics.rasterizer;
+ const DepthStencilDesc& depthStencilDesc = pipeline->desc.graphics.depthStencil;
+ encoder->setFrontFacingWinding(MetalUtil::translateWinding(rasterDesc.frontFace));
+ encoder->setCullMode(MetalUtil::translateCullMode(rasterDesc.cullMode));
+ encoder->setDepthClipMode(rasterDesc.depthClipEnable ? MTL::DepthClipModeClip : MTL::DepthClipModeClamp); // TODO correct?
+ encoder->setDepthBias(rasterDesc.depthBias, rasterDesc.slopeScaledDepthBias, rasterDesc.depthBiasClamp);
+ encoder->setTriangleFillMode(MetalUtil::translateTriangleFillMode(rasterDesc.fillMode));
+ // encoder->setBlendColor(); // not supported by gfx
+ if (m_framebuffer->m_depthStencilView)
{
- case PrimitiveType::Triangle:
- mtlType = MTL::PrimitiveTypeTriangle;
- break;
- case PrimitiveType::Line:
- mtlType = MTL::PrimitiveTypeLine;
- break;
- case PrimitiveType::Point:
- mtlType = MTL::PrimitiveTypePoint;
- break;
- case PrimitiveType::Patch:
- default:
- return SLANG_E_INVALID_ARG;
+ encoder->setDepthStencilState(pipeline->m_depthStencilState.get());
}
+ encoder->setStencilReferenceValue(m_stencilReferenceValue);
+
return SLANG_OK;
}
Result RenderCommandEncoder::draw(GfxCount vertexCount, GfxIndex startVertex)
{
- SLANG_RETURN_ON_FAIL(prepareDraw());
-
- MTL::PrimitiveType primType;
- Result res = translatePrimitiveType(m_currentPipeline->desc.graphics.primitiveType, primType);
- if (res != SLANG_OK)
- return res;
- m_encoder->drawPrimitives(primType, startVertex, vertexCount);
+ MTL::RenderCommandEncoder* encoder;
+ SLANG_RETURN_ON_FAIL(prepareDraw(encoder));
+ encoder->drawPrimitives(m_primitiveType, startVertex, vertexCount);
return SLANG_OK;
}
Result RenderCommandEncoder::drawIndexed(
GfxCount indexCount, GfxIndex startIndex, GfxIndex baseVertex)
{
+ MTL::RenderCommandEncoder* encoder;
+ SLANG_RETURN_ON_FAIL(prepareDraw(encoder));
+ // TODO baseVertex is not supported by Metal
+ encoder->drawIndexedPrimitives(m_primitiveType, indexCount, m_indexBufferType, m_indexBuffer, m_indexBufferOffset);
return SLANG_E_NOT_IMPLEMENTED;
}
-void RenderCommandEncoder::setStencilReference(uint32_t referenceValue)
-{
-}
-
Result RenderCommandEncoder::drawIndirect(
GfxCount maxDrawCount,
IBufferResource* argBuffer,
@@ -404,20 +429,16 @@ Result RenderCommandEncoder::drawIndexedIndirect(
return SLANG_E_NOT_IMPLEMENTED;
}
-Result RenderCommandEncoder::setSamplePositions(
- GfxCount samplesPerPixel, GfxCount pixelCount, const SamplePosition* samplePositions)
-{
- return SLANG_E_NOT_AVAILABLE;
-}
-
Result RenderCommandEncoder::drawInstanced(
GfxCount vertexCount,
GfxCount instanceCount,
GfxIndex startVertex,
GfxIndex startInstanceLocation)
{
- SLANG_RETURN_ON_FAIL(prepareDraw());
- return SLANG_E_NOT_IMPLEMENTED;
+ MTL::RenderCommandEncoder* encoder;
+ SLANG_RETURN_ON_FAIL(prepareDraw(encoder));
+ encoder->drawPrimitives(m_primitiveType, startVertex, vertexCount, instanceCount, startInstanceLocation);
+ return SLANG_OK;
}
Result RenderCommandEncoder::drawIndexedInstanced(
@@ -427,13 +448,14 @@ Result RenderCommandEncoder::drawIndexedInstanced(
GfxIndex baseVertexLocation,
GfxIndex startInstanceLocation)
{
- SLANG_RETURN_ON_FAIL(prepareDraw());
- return SLANG_E_NOT_IMPLEMENTED;
+ MTL::RenderCommandEncoder* encoder;
+ SLANG_RETURN_ON_FAIL(prepareDraw(encoder));
+ encoder->drawIndexedPrimitives(m_primitiveType, indexCount, m_indexBufferType, m_indexBuffer, startIndexLocation, instanceCount, baseVertexLocation, startIndexLocation);
+ return SLANG_OK;
}
Result RenderCommandEncoder::drawMeshTasks(int x, int y, int z)
{
- SLANG_RETURN_ON_FAIL(prepareDraw());
return SLANG_E_NOT_IMPLEMENTED;
}
@@ -459,16 +481,15 @@ Result ComputeCommandEncoder::dispatchCompute(int x, int y, int z)
auto pipeline = static_cast<PipelineStateImpl*>(m_currentPipeline.Ptr());
pipeline->ensureAPIPipelineStateCreated();
- auto metalComputeCommandEncoder = m_commandBuffer->getMetalComputeCommandEncoder();
- metalComputeCommandEncoder->setComputePipelineState(pipeline->m_computePipelineState.get());
+ MTL::ComputeCommandEncoder* encoder = m_commandBuffer->getMetalComputeCommandEncoder();
+ encoder->setComputePipelineState(pipeline->m_computePipelineState.get());
ComputeBindingContext bindingContext;
- bindingContext.init(m_commandBuffer->m_device, metalComputeCommandEncoder);
+ bindingContext.init(m_commandBuffer->m_device, encoder);
auto program = static_cast<ShaderProgramImpl*>(m_currentPipeline->m_program.get());
m_commandBuffer->m_rootObject.bindAsRoot(&bindingContext, program->m_rootObjectLayout);
- metalComputeCommandEncoder->dispatchThreadgroups(MTL::Size(x, y, z), pipeline->m_threadGroupSize);
+ encoder->dispatchThreadgroups(MTL::Size(x, y, z), pipeline->m_threadGroupSize);
- // Also create descriptor sets based on the given pipeline layout
- return SLANG_E_NOT_IMPLEMENTED;
+ return SLANG_OK;
}
Result ComputeCommandEncoder::dispatchComputeIndirect(IBufferResource* argBuffer, Offset offset)
diff --git a/tools/gfx/metal/metal-command-encoder.h b/tools/gfx/metal/metal-command-encoder.h
index 851ee60af..8ef9e5fb5 100644
--- a/tools/gfx/metal/metal-command-encoder.h
+++ b/tools/gfx/metal/metal-command-encoder.h
@@ -3,6 +3,7 @@
#include "metal-base.h"
#include "metal-pipeline-state.h"
+#include "metal-render-pass.h"
namespace gfx
{
@@ -159,9 +160,22 @@ class RenderCommandEncoder
return nullptr;
}
public:
- MTL::RenderCommandEncoder* m_encoder;
- List<MTL::ScissorRect> m_scissorRects;
- List<MTL::Viewport> m_viewports;
+ RefPtr<RenderPassLayoutImpl> m_renderPassLayout;
+ RefPtr<FramebufferImpl> m_framebuffer;
+ NS::SharedPtr<MTL::RenderPassDescriptor> m_renderPassDesc;
+
+ ShortList<MTL::Viewport, 16> m_viewports;
+ ShortList<MTL::ScissorRect, 16> m_scissorRects;
+ MTL::PrimitiveType m_primitiveType = MTL::PrimitiveTypeTriangle;
+
+ ShortList<MTL::Buffer*, 16> m_vertexBuffers;
+ ShortList<NS::UInteger, 16> m_vertexBufferOffsets;
+
+ MTL::Buffer* m_indexBuffer = nullptr;
+ NS::UInteger m_indexBufferOffset = 0;
+ MTL::IndexType m_indexBufferType = MTL::IndexTypeUInt16;
+
+ uint32_t m_stencilReferenceValue = 0;
public:
void beginPass(IRenderPassLayout* renderPass, IFramebuffer* framebuffer);
@@ -192,15 +206,20 @@ public:
virtual SLANG_NO_THROW void SLANG_MCALL
setIndexBuffer(IBufferResource* buffer, Format indexFormat, Offset offset = 0) override;
- Result prepareDraw();
+ virtual SLANG_NO_THROW void SLANG_MCALL setStencilReference(uint32_t referenceValue) override;
+
+ virtual SLANG_NO_THROW Result SLANG_MCALL setSamplePositions(
+ GfxCount samplesPerPixel,
+ GfxCount pixelCount,
+ const SamplePosition* samplePositions) override;
+
+ Result prepareDraw(MTL::RenderCommandEncoder*& encoder);
virtual SLANG_NO_THROW Result SLANG_MCALL
draw(GfxCount vertexCount, GfxIndex startVertex = 0) override;
virtual SLANG_NO_THROW Result SLANG_MCALL
drawIndexed(GfxCount indexCount, GfxIndex startIndex = 0, GfxIndex baseVertex = 0) override;
- virtual SLANG_NO_THROW void SLANG_MCALL setStencilReference(uint32_t referenceValue) override;
-
virtual SLANG_NO_THROW Result SLANG_MCALL drawIndirect(
GfxCount maxDrawCount,
IBufferResource* argBuffer,
@@ -215,11 +234,6 @@ public:
IBufferResource* countBuffer,
Offset countOffset) override;
- virtual SLANG_NO_THROW Result SLANG_MCALL setSamplePositions(
- GfxCount samplesPerPixel,
- GfxCount pixelCount,
- const SamplePosition* samplePositions) override;
-
virtual SLANG_NO_THROW Result SLANG_MCALL drawInstanced(
GfxCount vertexCount,
GfxCount instanceCount,
diff --git a/tools/gfx/metal/metal-device.cpp b/tools/gfx/metal/metal-device.cpp
index d844e6e89..a4cf23da3 100644
--- a/tools/gfx/metal/metal-device.cpp
+++ b/tools/gfx/metal/metal-device.cpp
@@ -144,9 +144,9 @@ Result DeviceImpl::createSwapchain(
{
AUTORELEASEPOOL
- RefPtr<SwapchainImpl> sc = new SwapchainImpl();
- SLANG_RETURN_ON_FAIL(sc->init(this, desc, window));
- returnComPtr(outSwapchain, sc);
+ RefPtr<SwapchainImpl> swapchainImpl = new SwapchainImpl();
+ SLANG_RETURN_ON_FAIL(swapchainImpl->init(this, desc, window));
+ returnComPtr(outSwapchain, swapchainImpl);
return SLANG_OK;
}
@@ -154,9 +154,9 @@ Result DeviceImpl::createFramebufferLayout(const IFramebufferLayout::Desc& desc,
{
AUTORELEASEPOOL
- RefPtr<FramebufferLayoutImpl> layout = new FramebufferLayoutImpl;
- SLANG_RETURN_ON_FAIL(layout->init(this, desc));
- returnComPtr(outLayout, layout);
+ RefPtr<FramebufferLayoutImpl> layoutImpl = new FramebufferLayoutImpl;
+ SLANG_RETURN_ON_FAIL(layoutImpl->init(desc));
+ returnComPtr(outLayout, layoutImpl);
return SLANG_OK;
}
@@ -164,9 +164,9 @@ Result DeviceImpl::createRenderPassLayout(const IRenderPassLayout::Desc& desc, I
{
AUTORELEASEPOOL
- RefPtr<RenderPassLayoutImpl> result = new RenderPassLayoutImpl;
- SLANG_RETURN_ON_FAIL(result->init(this, desc));
- returnComPtr(outRenderPassLayout, result);
+ RefPtr<RenderPassLayoutImpl> renderPassLayoutImpl = new RenderPassLayoutImpl;
+ SLANG_RETURN_ON_FAIL(renderPassLayoutImpl->init(this, desc));
+ returnComPtr(outRenderPassLayout, renderPassLayoutImpl);
return SLANG_OK;
}
@@ -174,9 +174,9 @@ Result DeviceImpl::createFramebuffer(const IFramebuffer::Desc& desc, IFramebuffe
{
AUTORELEASEPOOL
- RefPtr<FramebufferImpl> fb = new FramebufferImpl;
- SLANG_RETURN_ON_FAIL(fb->init(this, desc));
- returnComPtr(outFramebuffer, fb);
+ RefPtr<FramebufferImpl> framebufferImpl = new FramebufferImpl;
+ SLANG_RETURN_ON_FAIL(framebufferImpl->init(this, desc));
+ returnComPtr(outFramebuffer, framebufferImpl);
return SLANG_OK;
}
@@ -381,6 +381,8 @@ Result DeviceImpl::createTextureResource(
return SLANG_FAIL;
}
+ // TODO: handle initData
+
returnComPtr(outResource, textureImpl);
return SLANG_OK;
}
@@ -429,6 +431,7 @@ Result DeviceImpl::createBufferResource(
encoder->copyFromBuffer(stagingBuffer.get(), 0, bufferImpl->m_buffer.get(), 0, bufferSize);
encoder->endEncoding();
commandBuffer->commit();
+ commandBuffer->waitUntilCompleted();
}
returnComPtr(outResource, bufferImpl);
@@ -558,8 +561,8 @@ Result DeviceImpl::createBufferView(
RefPtr<BufferResourceViewImpl> viewImpl = new BufferResourceViewImpl(this);
viewImpl->m_desc = desc;
viewImpl->m_buffer = bufferImpl;
- viewImpl->m_offset = desc.bufferRange.offset;;
- viewImpl->m_size = desc.bufferRange.size == 0 ? bufferImpl->getDesc()->sizeInBytes : desc.bufferRange.size;;
+ viewImpl->m_offset = desc.bufferRange.offset;
+ viewImpl->m_size = desc.bufferRange.size == 0 ? bufferImpl->getDesc()->sizeInBytes : desc.bufferRange.size;
returnComPtr(outView, viewImpl);
return SLANG_OK;
}
@@ -568,37 +571,9 @@ Result DeviceImpl::createInputLayout(IInputLayout::Desc const& desc, IInputLayou
{
AUTORELEASEPOOL
- RefPtr<InputLayoutImpl> layout(new InputLayoutImpl);
- layout->m_vertexDescriptor = NS::TransferPtr(MTL::VertexDescriptor::alloc()->init());
- if (!layout->m_vertexDescriptor)
- {
- return SLANG_FAIL;
- }
-
- for (Int i = 0; i < desc.inputElementCount; ++i)
- {
- const auto& inputElement = desc.inputElements[i];
- MTL::VertexAttributeDescriptor* desc = layout->m_vertexDescriptor->attributes()->object(i);
- desc->setOffset(inputElement.offset);
- desc->setBufferIndex(inputElement.bufferSlotIndex);
- MTL::VertexFormat metalFormat = MetalUtil::translateVertexFormat(inputElement.format);
- if (metalFormat == MTL::VertexFormatInvalid)
- {
- return SLANG_FAIL;
- }
- desc->setFormat(metalFormat);
- }
-
- for (Int i = 0; i < desc.vertexStreamCount; ++i)
- {
- const auto& vertexStream = desc.vertexStreams[i];
- MTL::VertexBufferLayoutDescriptor* desc = layout->m_vertexDescriptor->layouts()->object(i);
- desc->setStepFunction(MetalUtil::translateVertexStepFunction(vertexStream.slotClass));
- desc->setStepRate(vertexStream.instanceDataStepRate);
- desc->setStride(vertexStream.stride);
- }
-
- returnComPtr(outLayout, layout);
+ RefPtr<InputLayoutImpl> layoutImpl(new InputLayoutImpl);
+ SLANG_RETURN_ON_FAIL(layoutImpl->init(desc));
+ returnComPtr(outLayout, layoutImpl);
return SLANG_OK;
}
diff --git a/tools/gfx/metal/metal-framebuffer.cpp b/tools/gfx/metal/metal-framebuffer.cpp
index 46e60b2eb..76e944b4a 100644
--- a/tools/gfx/metal/metal-framebuffer.cpp
+++ b/tools/gfx/metal/metal-framebuffer.cpp
@@ -12,60 +12,56 @@ using namespace Slang;
namespace metal
{
-FramebufferLayoutImpl::~FramebufferLayoutImpl()
+Result FramebufferLayoutImpl::init(const IFramebufferLayout::Desc& desc)
{
- //m_renderPass->release();
-}
-
-Result FramebufferLayoutImpl::init(DeviceImpl* device, const IFramebufferLayout::Desc& desc)
-{
- // Metal doesn't have a notion of Framebuffers or FramebufferLayouts per se.
- // We simply stash the desc and use it when creating the (convenience) Framebuffer
- m_device = device;
- m_desc = desc;
+ for (Index i = 0; i < desc.renderTargetCount; ++i)
+ {
+ m_renderTargets.add(desc.renderTargets[i]);
+ }
+ if (desc.depthStencil)
+ {
+ m_depthStencil = *desc.depthStencil;
+ }
+ else
+ {
+ m_depthStencil = {};
+ }
return SLANG_OK;
}
-FramebufferImpl::~FramebufferImpl()
-{
-}
-
Result FramebufferImpl::init(DeviceImpl* device, const IFramebuffer::Desc& desc)
{
m_device = device;
m_layout = static_cast<FramebufferLayoutImpl*>(desc.layout);
- m_width = m_height = 1;
-
- TextureResourceViewImpl* dsv = static_cast<TextureResourceViewImpl*>(desc.depthStencilView);
-
- // Get frame dimensions from attachments.
- if (dsv)
+ m_renderTargetViews.setCount(desc.renderTargetCount);
+ for (Index i = 0; i < desc.renderTargetCount; ++i)
{
- // If we have a depth attachment, get frame size from there.
- auto size = dsv->m_texture->getDesc()->size;
- auto viewDesc = dsv->getViewDesc();
- m_width = Math::Max(1u, uint32_t(size.width >> viewDesc->subresourceRange.mipLevel));
- m_height = Math::Max(1u, uint32_t(size.height >> viewDesc->subresourceRange.mipLevel));
- }
- else if (desc.renderTargetCount > 0)
- {
- // If we don't have a depth attachment, then we must have at least
- // one color attachment. Get frame dimension from there.
- auto viewImpl = static_cast<TextureResourceViewImpl*>(desc.renderTargetViews[0]);
- auto resourceDesc = viewImpl->m_texture->getDesc();
- auto viewDesc = viewImpl->getViewDesc();
- auto size = resourceDesc->size;
- m_width = Math::Max(1u, uint32_t(size.width >> viewDesc->subresourceRange.mipLevel));
- m_height = Math::Max(1u, uint32_t(size.height >> viewDesc->subresourceRange.mipLevel));
+ m_renderTargetViews[i] = static_cast<TextureResourceViewImpl*>(desc.renderTargetViews[i]);
}
+ m_depthStencilView = static_cast<TextureResourceViewImpl*>(desc.depthStencilView);
+
+ // Determine framebuffer dimensions & sample count;
+ m_width = 1;
+ m_height = 1;
+ m_sampleCount = 1;
- // Initialize depthstencil and render target views
- depthStencilView = desc.depthStencilView;
+ auto visitView = [this](TextureResourceViewImpl* view)
+ {
+ const ITextureResource::Desc* textureDesc = view->m_texture->getDesc();
+ const IResourceView::Desc* viewDesc = view->getViewDesc();
+ m_width = Math::Max(1u, uint32_t(textureDesc->size.width >> viewDesc->subresourceRange.mipLevel));
+ m_height = Math::Max(1u, uint32_t(textureDesc->size.height >> viewDesc->subresourceRange.mipLevel));
+ m_sampleCount = Math::Max(m_sampleCount, uint32_t(textureDesc->sampleDesc.numSamples));
+ return SLANG_OK;
+ };
- renderTargetViews.setCount(desc.renderTargetCount);
- for (int i = 0; i < desc.renderTargetCount; ++i)
+ for (auto view : m_renderTargetViews)
+ {
+ visitView(view);
+ }
+ if (m_depthStencilView)
{
- renderTargetViews[i] = desc.renderTargetViews[i];
+ visitView(m_depthStencilView);
}
return SLANG_OK;
diff --git a/tools/gfx/metal/metal-framebuffer.h b/tools/gfx/metal/metal-framebuffer.h
index 7bd3b0bef..90abf1b85 100644
--- a/tools/gfx/metal/metal-framebuffer.h
+++ b/tools/gfx/metal/metal-framebuffer.h
@@ -20,41 +20,25 @@ enum
class FramebufferLayoutImpl : public FramebufferLayoutBase
{
public:
- RefPtr<DeviceImpl> m_device;
- Desc m_desc;
-#if 0
- MTL::RenderPassDescriptor* m_renderPass = nullptr;
- Array<MTL::RenderPassColorAttachmentDescriptor*, kMaxTargets> m_targetDescs;
- MTL::RenderPassDepthAttachmentDescriptor* m_depthAttachmentDesc = nullptr;
- MTL::RenderPassStencilAttachmentDescriptor* m_stencilAttachmentDesc = nullptr;
- bool m_hasDepthStencilTarget = false;
- uint32_t m_renderTargetCount = 0;
-#endif
+ List<IFramebufferLayout::TargetLayout> m_renderTargets;
+ IFramebufferLayout::TargetLayout m_depthStencil;
public:
- ~FramebufferLayoutImpl();
- Result init(DeviceImpl* device, const IFramebufferLayout::Desc& desc);
+ Result init(const IFramebufferLayout::Desc& desc);
};
class FramebufferImpl : public FramebufferBase
{
public:
BreakableReference<DeviceImpl> m_device;
- ShortList<ComPtr<IResourceView>> renderTargetViews;
- ComPtr<IResourceView> depthStencilView;
+ RefPtr<FramebufferLayoutImpl> m_layout;
+ ShortList<RefPtr<TextureResourceViewImpl>> m_renderTargetViews;
+ RefPtr<TextureResourceViewImpl> m_depthStencilView;
uint32_t m_width;
uint32_t m_height;
- MTL::ClearColor m_clearValues[kMaxTargets];
- RefPtr<FramebufferLayoutImpl> m_layout;
-#if 0
- Array<MTL::RenderPassColorAttachmentDescriptor*, kMaxTargets> m_colorTargetDescs;
- MTL::RenderPassDepthAttachmentDescriptor* m_depthAttachmentDesc = nullptr;
- MTL::RenderPassStencilAttachmentDescriptor* m_stencilAttachmentDesc = nullptr;
-#endif
+ uint32_t m_sampleCount;
public:
- ~FramebufferImpl();
-
Result init(DeviceImpl* device, const IFramebuffer::Desc& desc);
};
diff --git a/tools/gfx/metal/metal-helper-functions.h b/tools/gfx/metal/metal-helper-functions.h
index 0936cfa46..9fe4c9ff9 100644
--- a/tools/gfx/metal/metal-helper-functions.h
+++ b/tools/gfx/metal/metal-helper-functions.h
@@ -53,7 +53,6 @@ struct BindingOffset
struct BindingContext
{
DeviceImpl* device = nullptr;
- virtual void setData(const void* data, NS::UInteger length, NS::UInteger index) = 0;
virtual void setBuffer(MTL::Buffer* buffer, NS::UInteger index) = 0;
virtual void setTexture(MTL::Texture* texture, NS::UInteger index) = 0;
virtual void setSampler(MTL::SamplerState* sampler, NS::UInteger index) = 0;
@@ -70,11 +69,6 @@ struct ComputeBindingContext : public BindingContext
return SLANG_OK;
}
- void setData(const void* data, NS::UInteger length, NS::UInteger index) override
- {
- encoder->setBytes(data, length, index);
- }
-
void setBuffer(MTL::Buffer* buffer, NS::UInteger index) override
{
encoder->setBuffer(buffer, 0, index);
@@ -91,6 +85,60 @@ struct ComputeBindingContext : public BindingContext
}
};
+struct VertexBindingContext : public BindingContext
+{
+ MTL::RenderCommandEncoder* encoder;
+
+ Result init(DeviceImpl* device, MTL::RenderCommandEncoder* encoder)
+ {
+ this->device = device;
+ this->encoder = encoder;
+ return SLANG_OK;
+ }
+
+ void setBuffer(MTL::Buffer* buffer, NS::UInteger index) override
+ {
+ encoder->setVertexBuffer(buffer, 0, index);
+ }
+
+ void setTexture(MTL::Texture* texture, NS::UInteger index) override
+ {
+ encoder->setVertexTexture(texture, index);
+ }
+
+ void setSampler(MTL::SamplerState* sampler, NS::UInteger index) override
+ {
+ encoder->setVertexSamplerState(sampler, index);
+ }
+};
+
+struct FragmentBindingContext : public BindingContext
+{
+ MTL::RenderCommandEncoder* encoder;
+
+ Result init(DeviceImpl* device, MTL::RenderCommandEncoder* encoder)
+ {
+ this->device = device;
+ this->encoder = encoder;
+ return SLANG_OK;
+ }
+
+ void setBuffer(MTL::Buffer* buffer, NS::UInteger index) override
+ {
+ encoder->setFragmentBuffer(buffer, 0, index);
+ }
+
+ void setTexture(MTL::Texture* texture, NS::UInteger index) override
+ {
+ encoder->setFragmentTexture(texture, index);
+ }
+
+ void setSampler(MTL::SamplerState* sampler, NS::UInteger index) override
+ {
+ encoder->setFragmentSamplerState(sampler, index);
+ }
+};
+
} // namespace metal
Result SLANG_MCALL getMetalAdapters(List<AdapterInfo>& outAdapters);
diff --git a/tools/gfx/metal/metal-pipeline-state.cpp b/tools/gfx/metal/metal-pipeline-state.cpp
index b0fce682e..8daaeccda 100644
--- a/tools/gfx/metal/metal-pipeline-state.cpp
+++ b/tools/gfx/metal/metal-pipeline-state.cpp
@@ -50,40 +50,84 @@ void PipelineStateImpl::init(const RayTracingPipelineStateDesc& desc)
Result PipelineStateImpl::createMetalRenderPipelineState()
{
- NS::SharedPtr<MTL::RenderPipelineDescriptor> pd = NS::TransferPtr(MTL::RenderPipelineDescriptor::alloc()->init());
auto programImpl = static_cast<ShaderProgramImpl*>(m_program.Ptr());
- if (programImpl)
+ if (!programImpl)
+ return SLANG_FAIL;
+
+ NS::SharedPtr<MTL::RenderPipelineDescriptor> pd = NS::TransferPtr(MTL::RenderPipelineDescriptor::alloc()->init());
+
+ for (const ShaderProgramImpl::Module& module : programImpl->m_modules)
{
- SLANG_RETURN_ON_FAIL(programImpl->compileShaders(m_device));
+ auto functionName = MetalUtil::createString(module.entryPointName.getBuffer());
+ NS::SharedPtr<MTL::Function> function = NS::TransferPtr(module.library->newFunction(functionName.get()));
+ if (!function)
+ return SLANG_FAIL;
+
+ switch (module.stage)
+ {
+ case SLANG_STAGE_VERTEX:
+ pd->setVertexFunction(function.get());
+ break;
+ case SLANG_STAGE_FRAGMENT:
+ pd->setFragmentFunction(function.get());
+ break;
+ default:
+ return SLANG_FAIL;
+ }
}
- const auto& programReflection = m_program->linkedProgram->getLayout();
- const auto& composedProgram = m_program->linkedProgram;
- for (SlangUInt i = 0; i < programReflection->getEntryPointCount(); ++i)
+ // Offset vertex buffer indices in vertex layout.
+ // They need to be in a range not used by other buffer bindings.
+ m_vertexBufferOffset = 10; // TODO get from layout
+ auto inputLayoutImpl = static_cast<InputLayoutImpl*>(desc.graphics.inputLayout);
+ NS::SharedPtr<MTL::VertexDescriptor> vertexDescriptor = inputLayoutImpl->createVertexDescriptor(m_vertexBufferOffset);
+ pd->setVertexDescriptor(vertexDescriptor.get());
+ pd->setInputPrimitiveTopology(MetalUtil::translatePrimitiveTopologyClass(desc.graphics.primitiveType));
+
+ // Set rasterization state
+ auto framebufferLayoutImpl = static_cast<FramebufferLayoutImpl*>(desc.graphics.framebufferLayout);
+ const auto& blend = desc.graphics.blend;
+ GfxCount sampleCount = 1;
+
+ pd->setAlphaToCoverageEnabled(blend.alphaToCoverageEnable);
+ // pd->setAlphaToOneEnabled(); // Currently not supported by gfx
+ // pd->setRasterizationEnabled(true); // Enabled by default
+
+ for (Index i = 0; i < framebufferLayoutImpl->m_renderTargets.getCount(); ++i)
+ {
+ const IFramebufferLayout::TargetLayout& targetLayout = framebufferLayoutImpl->m_renderTargets[i];
+ MTL::RenderPipelineColorAttachmentDescriptor* colorAttachment = pd->colorAttachments()->object(i);
+ colorAttachment->setPixelFormat(MetalUtil::translatePixelFormat(targetLayout.format));
+ if (i < blend.targetCount)
+ {
+ const TargetBlendDesc& targetBlendDesc = blend.targets[i];
+ colorAttachment->setBlendingEnabled(targetBlendDesc.enableBlend);
+ colorAttachment->setSourceRGBBlendFactor(MetalUtil::translateBlendFactor(targetBlendDesc.color.srcFactor));
+ colorAttachment->setDestinationRGBBlendFactor(MetalUtil::translateBlendFactor(targetBlendDesc.color.dstFactor));
+ colorAttachment->setRgbBlendOperation(MetalUtil::translateBlendOperation(targetBlendDesc.color.op));
+ colorAttachment->setSourceAlphaBlendFactor(MetalUtil::translateBlendFactor(targetBlendDesc.alpha.srcFactor));
+ colorAttachment->setDestinationAlphaBlendFactor(MetalUtil::translateBlendFactor(targetBlendDesc.alpha.dstFactor));
+ colorAttachment->setAlphaBlendOperation(MetalUtil::translateBlendOperation(targetBlendDesc.alpha.op));
+ colorAttachment->setWriteMask(MetalUtil::translateColorWriteMask(targetBlendDesc.writeMask));
+ }
+ sampleCount = Math::Max(sampleCount, targetLayout.sampleCount);
+ }
+ if (framebufferLayoutImpl->m_depthStencil.format != Format::Unknown)
{
- SlangStage stage = programReflection->getEntryPointByIndex(i)->getStage();
- if (stage == SLANG_STAGE_VERTEX)
+ const IFramebufferLayout::TargetLayout& depthStencil = framebufferLayoutImpl->m_depthStencil;
+ MTL::PixelFormat pixelFormat = MetalUtil::translatePixelFormat(depthStencil.format);
+ if (MetalUtil::isDepthFormat(pixelFormat))
+ {
+ pd->setDepthAttachmentPixelFormat(MetalUtil::translatePixelFormat(depthStencil.format));
+ }
+ if (MetalUtil::isStencilFormat(pixelFormat))
{
- ComPtr<slang::IBlob> metalCode;
- {
- ComPtr<slang::IBlob> diagnosticsBlob;
- SlangResult result = composedProgram->getEntryPointCode(i, 0, metalCode.writeRef(), diagnosticsBlob.writeRef());
- if (diagnosticsBlob)
- {
- std::cout << diagnosticsBlob->getBufferPointer() << std::endl;
- }
- //MTL::Function* f = ...
- //RETURN_ON_FAIL(result);
- //pd->setVertexFunction();
- }
+ pd->setStencilAttachmentPixelFormat(MetalUtil::translatePixelFormat(depthStencil.format));
}
- //pd->setFragmentFunction();
}
- // pd->colorAttachments()->object(0)->setPixelFormat(...);
- // pd->setDepthAttachmentPixelFormat(...);
- // Set deftault viewport and scissor
- // Set default rasterization state
- // Set default framebuffer layout
+
+ pd->setRasterSampleCount(sampleCount);
+
NS::Error* error;
m_renderPipelineState = NS::TransferPtr(m_device->m_device->newRenderPipelineState(pd.get(), &error));
if (!m_renderPipelineState)
@@ -91,6 +135,38 @@ Result PipelineStateImpl::createMetalRenderPipelineState()
std::cout << error->localizedDescription()->utf8String() << std::endl;
return SLANG_E_INVALID_ARG;
}
+
+ // Create depth stencil state
+ auto createStencilDesc = [](const DepthStencilOpDesc& desc, uint32_t readMask, uint32_t writeMask) -> NS::SharedPtr<MTL::StencilDescriptor>
+ {
+ NS::SharedPtr<MTL::StencilDescriptor> stencilDesc = NS::TransferPtr(MTL::StencilDescriptor::alloc()->init());
+ stencilDesc->setStencilCompareFunction(MetalUtil::translateCompareFunction(desc.stencilFunc));
+ stencilDesc->setStencilFailureOperation(MetalUtil::translateStencilOperation(desc.stencilFailOp));
+ stencilDesc->setDepthFailureOperation(MetalUtil::translateStencilOperation(desc.stencilDepthFailOp));
+ stencilDesc->setDepthStencilPassOperation(MetalUtil::translateStencilOperation(desc.stencilPassOp));
+ stencilDesc->setReadMask(readMask);
+ stencilDesc->setWriteMask(writeMask);
+ return stencilDesc;
+ };
+
+ const auto& depthStencil = desc.graphics.depthStencil;
+ NS::SharedPtr<MTL::DepthStencilDescriptor> depthStencilDesc = NS::TransferPtr(MTL::DepthStencilDescriptor::alloc()->init());
+ m_depthStencilState = NS::TransferPtr(m_device->m_device->newDepthStencilState(depthStencilDesc.get()));
+ if (!m_depthStencilState)
+ {
+ return SLANG_FAIL;
+ }
+ if (depthStencil.depthTestEnable)
+ {
+ depthStencilDesc->setDepthCompareFunction(MetalUtil::translateCompareFunction(depthStencil.depthFunc));
+ }
+ depthStencilDesc->setDepthWriteEnabled(depthStencil.depthWriteEnable);
+ if (depthStencil.stencilEnable)
+ {
+ depthStencilDesc->setFrontFaceStencil(createStencilDesc(depthStencil.frontFace, depthStencil.stencilReadMask, depthStencil.stencilWriteMask).get());
+ depthStencilDesc->setBackFaceStencil(createStencilDesc(depthStencil.backFace, depthStencil.stencilReadMask, depthStencil.stencilWriteMask).get());
+ }
+
return SLANG_OK;
}
@@ -100,10 +176,9 @@ Result PipelineStateImpl::createMetalComputePipelineState()
if (!programImpl)
return SLANG_FAIL;
- NS::SharedPtr<MTL::ComputePipelineDescriptor> pd = NS::TransferPtr(MTL::ComputePipelineDescriptor::alloc()->init());
-
- auto functionName = MetalUtil::createString(programImpl->m_entryPointNames[0].getBuffer());
- NS::SharedPtr<MTL::Function> function = NS::TransferPtr(programImpl->m_modules[0]->newFunction(functionName.get()));
+ const ShaderProgramImpl::Module& module = programImpl->m_modules[0];
+ auto functionName = MetalUtil::createString(module.entryPointName.getBuffer());
+ NS::SharedPtr<MTL::Function> function = NS::TransferPtr(module.library->newFunction(functionName.get()));
if (!function)
return SLANG_FAIL;
@@ -120,6 +195,8 @@ Result PipelineStateImpl::createMetalComputePipelineState()
Result PipelineStateImpl::ensureAPIPipelineStateCreated()
{
+ AUTORELEASEPOOL
+
switch (desc.type)
{
case PipelineType::Compute:
diff --git a/tools/gfx/metal/metal-pipeline-state.h b/tools/gfx/metal/metal-pipeline-state.h
index e816af5b1..2a4f431b4 100644
--- a/tools/gfx/metal/metal-pipeline-state.h
+++ b/tools/gfx/metal/metal-pipeline-state.h
@@ -16,8 +16,10 @@ class PipelineStateImpl : public PipelineStateBase
public:
RefPtr<DeviceImpl> m_device;
NS::SharedPtr<MTL::RenderPipelineState> m_renderPipelineState;
+ NS::SharedPtr<MTL::DepthStencilState> m_depthStencilState;
NS::SharedPtr<MTL::ComputePipelineState> m_computePipelineState;
MTL::Size m_threadGroupSize;
+ NS::UInteger m_vertexBufferOffset;
PipelineStateImpl(DeviceImpl* device);
~PipelineStateImpl();
diff --git a/tools/gfx/metal/metal-render-pass.cpp b/tools/gfx/metal/metal-render-pass.cpp
index f0849eb4b..bc60cf746 100644
--- a/tools/gfx/metal/metal-render-pass.cpp
+++ b/tools/gfx/metal/metal-render-pass.cpp
@@ -18,21 +18,18 @@ IRenderPassLayout* RenderPassLayoutImpl::getInterface(const Guid& guid)
return nullptr;
}
-RenderPassLayoutImpl::~RenderPassLayoutImpl()
-{
-}
-
static inline MTL::LoadAction translateLoadOp(IRenderPassLayout::TargetLoadOp loadOp)
{
switch (loadOp)
{
- case IRenderPassLayout::TargetLoadOp::Clear:
- return MTL::LoadAction::LoadActionClear;
case IRenderPassLayout::TargetLoadOp::Load:
- return MTL::LoadAction::LoadActionLoad;
+ return MTL::LoadActionLoad;
+ case IRenderPassLayout::TargetLoadOp::Clear:
+ return MTL::LoadActionClear;
case IRenderPassLayout::TargetLoadOp::DontCare:
+ return MTL::LoadActionDontCare;
default:
- return MTL::LoadAction::LoadActionDontCare;
+ return MTL::LoadAction(0);
}
}
@@ -41,10 +38,11 @@ static inline MTL::StoreAction translateStoreOp(IRenderPassLayout::TargetStoreOp
switch (storeOp)
{
case IRenderPassLayout::TargetStoreOp::Store:
- return MTL::StoreAction::StoreActionStore;
+ return MTL::StoreActionStore;
case IRenderPassLayout::TargetStoreOp::DontCare:
+ return MTL::StoreActionDontCare;
default:
- return MTL::StoreAction::StoreActionDontCare;
+ return MTL::StoreAction(0);
}
}
@@ -57,27 +55,21 @@ Result RenderPassLayoutImpl::init(DeviceImpl* device, const IRenderPassLayout::D
// Initialize render pass descriptor, filling in attachment metadata, but leaving texture data unbound.
m_renderPassDesc = NS::TransferPtr(MTL::RenderPassDescriptor::alloc()->init());
- m_renderPassDesc->setRenderTargetArrayLength(desc.renderTargetCount);
- MTL::RenderPassColorAttachmentDescriptorArray* colorAttachments = m_renderPassDesc->colorAttachments();
+ m_renderPassDesc->setRenderTargetArrayLength(desc.renderTargetCount);
for (GfxIndex i = 0; i < desc.renderTargetCount; ++i)
{
- MTL::RenderPassColorAttachmentDescriptor* colorAttach = MTL::RenderPassColorAttachmentDescriptor::alloc()->init();
- colorAttach->setLoadAction(translateLoadOp(desc.renderTargetAccess[i].loadOp));
- colorAttach->setStoreAction(translateStoreOp(desc.renderTargetAccess[i].storeOp));
- // We set the texture when the render pass is executed, using the associated framebuffer.
- colorAttach->setTexture(nullptr);
- colorAttachments->setObject(colorAttach, i);
+ MTL::RenderPassColorAttachmentDescriptor* colorAttachment = m_renderPassDesc->colorAttachments()->object(i);
+ colorAttachment->setLoadAction(translateLoadOp(desc.renderTargetAccess[i].loadOp));
+ colorAttachment->setStoreAction(translateStoreOp(desc.renderTargetAccess[i].storeOp));
}
+
m_renderPassDesc->depthAttachment()->setLoadAction(translateLoadOp(desc.depthStencilAccess->loadOp));
m_renderPassDesc->depthAttachment()->setStoreAction(translateStoreOp(desc.depthStencilAccess->storeOp));
- // We set the depth texture when the render pass is executed, using the associated framebuffer.
- m_renderPassDesc->depthAttachment()->setTexture(nullptr);
- //m_renderPassDesc->depthAttachment()->setClearDepth(1000000.);
+
m_renderPassDesc->stencilAttachment()->setLoadAction(translateLoadOp(desc.depthStencilAccess->loadOp));
m_renderPassDesc->stencilAttachment()->setStoreAction(translateStoreOp(desc.depthStencilAccess->storeOp));
- // We set the stencil texture when the render pass is executed, using the associated framebuffer.
- m_renderPassDesc->stencilAttachment()->setTexture(nullptr);
+
return SLANG_OK;
}
diff --git a/tools/gfx/metal/metal-render-pass.h b/tools/gfx/metal/metal-render-pass.h
index ef69d8909..ee66b0c4d 100644
--- a/tools/gfx/metal/metal-render-pass.h
+++ b/tools/gfx/metal/metal-render-pass.h
@@ -24,8 +24,6 @@ public:
RefPtr<DeviceImpl> m_device;
NS::SharedPtr<MTL::RenderPassDescriptor> m_renderPassDesc;
- ~RenderPassLayoutImpl();
-
Result init(DeviceImpl* device, const IRenderPassLayout::Desc& desc);
};
diff --git a/tools/gfx/metal/metal-shader-program.cpp b/tools/gfx/metal/metal-shader-program.cpp
index 1b998bc57..e0f973eb6 100644
--- a/tools/gfx/metal/metal-shader-program.cpp
+++ b/tools/gfx/metal/metal-shader-program.cpp
@@ -22,19 +22,22 @@ ShaderProgramImpl::~ShaderProgramImpl()
Result ShaderProgramImpl::createShaderModule(slang::EntryPointReflection* entryPointInfo, ComPtr<ISlangBlob> kernelCode)
{
- m_codeBlobs.add(kernelCode);
- const char* realEntryPointName = entryPointInfo->getNameOverride();
+ Module module;
+ module.stage = entryPointInfo->getStage();
+ module.entryPointName = entryPointInfo->getNameOverride();
+ module.code = kernelCode;
+
dispatch_data_t data = dispatch_data_create(kernelCode->getBufferPointer(), kernelCode->getBufferSize(), dispatch_get_main_queue(), NULL);
NS::Error* error;
- NS::SharedPtr<MTL::Library> library = NS::TransferPtr(m_device->m_device->newLibrary(data, &error));
- if (!library)
+ module.library = NS::TransferPtr(m_device->m_device->newLibrary(data, &error));
+ if (!module.library)
{
// TODO use better mechanism for reporting errors
std::cout << error->localizedDescription()->utf8String() << std::endl;
return SLANG_E_INVALID_ARG;
}
- m_entryPointNames.add(realEntryPointName);
- m_modules.add(library);
+
+ m_modules.add(module);
return SLANG_OK;
}
diff --git a/tools/gfx/metal/metal-shader-program.h b/tools/gfx/metal/metal-shader-program.h
index 50f568321..ed2f231ec 100644
--- a/tools/gfx/metal/metal-shader-program.h
+++ b/tools/gfx/metal/metal-shader-program.h
@@ -16,12 +16,18 @@ class ShaderProgramImpl : public ShaderProgramBase
{
public:
BreakableReference<DeviceImpl> m_device;
-
- List<String> m_entryPointNames;
- List<ComPtr<ISlangBlob>> m_codeBlobs; //< To keep storage of code in scope
- List<NS::SharedPtr<MTL::Library>> m_modules;
RefPtr<RootShaderObjectLayoutImpl> m_rootObjectLayout;
+ struct Module
+ {
+ SlangStage stage;
+ String entryPointName;
+ ComPtr<ISlangBlob> code;
+ NS::SharedPtr<MTL::Library> library;
+ };
+
+ List<Module> m_modules;
+
ShaderProgramImpl(DeviceImpl* device);
~ShaderProgramImpl();
diff --git a/tools/gfx/metal/metal-swap-chain.cpp b/tools/gfx/metal/metal-swap-chain.cpp
index 0a28b214c..1478c8bf4 100644
--- a/tools/gfx/metal/metal-swap-chain.cpp
+++ b/tools/gfx/metal/metal-swap-chain.cpp
@@ -24,6 +24,26 @@ void SwapchainImpl::getWindowSize(int& widthOut, int& heightOut) const
CocoaUtil::getNSWindowContentSize((void*)m_windowHandle.handleValues[0], &widthOut, &heightOut);
}
+void SwapchainImpl::createImages()
+{
+ m_images.setCount(m_desc.imageCount);
+ for (GfxCount i = 0; i < m_desc.imageCount; ++i)
+ {
+ ITextureResource::Desc imageDesc = {};
+ imageDesc.allowedStates = ResourceStateSet(
+ ResourceState::Present, ResourceState::RenderTarget, ResourceState::CopyDestination, ResourceState::CopySource);
+ imageDesc.type = IResource::Type::Texture2D;
+ imageDesc.arraySize = 0;
+ imageDesc.format = m_desc.format;
+ imageDesc.size.width = m_desc.width;
+ imageDesc.size.height = m_desc.height;
+ imageDesc.size.depth = 1;
+ imageDesc.numMipLevels = 1;
+ imageDesc.defaultState = ResourceState::Present;
+ m_device->createTextureResource(imageDesc, nullptr, (gfx::ITextureResource**)m_images[i].writeRef());
+ }
+}
+
SwapchainImpl::~SwapchainImpl()
{
m_images.clear();
@@ -36,7 +56,7 @@ Result SwapchainImpl::init(DeviceImpl* device, const ISwapchain::Desc& desc, Win
m_desc = desc;
m_windowHandle = window;
m_metalFormat = MetalUtil::translatePixelFormat(desc.format);
- m_currentImageIndex = 0;
+ m_currentImageIndex = -1;
getWindowSize(m_desc.width, m_desc.height);
@@ -48,14 +68,17 @@ Result SwapchainImpl::init(DeviceImpl* device, const ISwapchain::Desc& desc, Win
m_metalLayer->setPixelFormat(m_metalFormat);
m_metalLayer->setDevice(m_device->m_device.get());
m_metalLayer->setDrawableSize(CGSize{(float)m_desc.width, (float)m_desc.height});
- m_metalLayer->setFramebufferOnly(true);
+ // We need to be able to copy from a texture.
+ m_metalLayer->setFramebufferOnly(false);
+
+ createImages();
return SLANG_OK;
}
Result SwapchainImpl::getImage(GfxIndex index, ITextureResource** outResource)
{
- if (index < 0 || index != m_currentImageIndex)
+ if (index < 0 || index >= m_desc.imageCount)
return SLANG_FAIL;
returnComPtr(outResource, m_images[index]);
return SLANG_OK;
@@ -63,24 +86,27 @@ Result SwapchainImpl::getImage(GfxIndex index, ITextureResource** outResource)
Result SwapchainImpl::resize(GfxCount width, GfxCount height)
{
- SLANG_UNUSED(width);
- SLANG_UNUSED(height);
- m_images.clear();
m_currentImageIndex = -1;
m_currentDrawable.reset();
getWindowSize(m_desc.width, m_desc.height);
m_metalLayer->setDrawableSize(CGSize{(float)m_desc.width, (float)m_desc.height});
+ createImages();
return SLANG_OK;
}
Result SwapchainImpl::present()
{
+ AUTORELEASEPOOL
+
if (!m_currentDrawable)
{
return SLANG_FAIL;
}
MTL::CommandBuffer* commandBuffer = m_device->m_commandQueue->commandBuffer();
+ MTL::BlitCommandEncoder* encoder = commandBuffer->blitCommandEncoder();
+ encoder->copyFromTexture(m_images[m_currentImageIndex]->m_texture.get(), m_currentDrawable->texture());
+ encoder->endEncoding();
commandBuffer->presentDrawable(m_currentDrawable.get());
commandBuffer->commit();
m_currentDrawable.reset();
@@ -103,48 +129,22 @@ int SwapchainImpl::acquireNextImage()
{
AUTORELEASEPOOL
- CA::MetalDrawable* drawable = m_metalLayer->nextDrawable();
- if (drawable == nullptr)
+ m_currentDrawable = NS::RetainPtr(m_metalLayer->nextDrawable());
+ if (m_currentDrawable)
{
- return -1;
+ m_currentImageIndex = (m_currentImageIndex + 1) % m_desc.imageCount;
}
-
- m_currentDrawable = NS::RetainPtr(drawable);
- MTL::Texture* texture = drawable->texture();
-
- // Check if we got a texture we've seen before.
- for (Index i = 0; i < m_images.getCount(); i++)
+ else
{
- if (m_images[i]->m_texture.get() == texture)
- {
- m_currentImageIndex = i;
- return m_currentImageIndex;
- }
+ m_currentImageIndex = -1;
}
-
- // Create a new texture object to wrap the drawable's texture.
-
- ITextureResource::Desc desc = {};
- desc.allowedStates = ResourceStateSet(
- ResourceState::Present, ResourceState::RenderTarget, ResourceState::CopyDestination);
- desc.type = IResource::Type::Texture2D;
- desc.arraySize = 0;
- desc.format = m_desc.format; // TODO use actual pixelformat
- desc.size.width = texture->width();
- desc.size.height = texture->height();
- desc.size.depth = 1;
- desc.numMipLevels = 1;
- desc.defaultState = ResourceState::Present;
- RefPtr<TextureResourceImpl> image = new TextureResourceImpl(desc, m_device);
- image->m_texture = NS::RetainPtr(texture);
-
- m_currentImageIndex = m_images.getCount();
- m_images.add(image);
-
return m_currentImageIndex;
}
-Result SwapchainImpl::setFullScreenMode(bool mode) { return SLANG_FAIL; }
+Result SwapchainImpl::setFullScreenMode(bool mode)
+{
+ return SLANG_E_NOT_AVAILABLE;
+}
} // namespace metal
} // namespace gfx
diff --git a/tools/gfx/metal/metal-swap-chain.h b/tools/gfx/metal/metal-swap-chain.h
index bed1c0f5b..b7d57e271 100644
--- a/tools/gfx/metal/metal-swap-chain.h
+++ b/tools/gfx/metal/metal-swap-chain.h
@@ -28,11 +28,12 @@ public:
WindowHandle m_windowHandle;
CA::MetalLayer* m_metalLayer = nullptr;
ShortList<RefPtr<TextureResourceImpl>> m_images;
- NS::SharedPtr<MTL::Drawable> m_currentDrawable;
+ NS::SharedPtr<CA::MetalDrawable> m_currentDrawable;
Index m_currentImageIndex = -1;
MTL::PixelFormat m_metalFormat = MTL::PixelFormat::PixelFormatInvalid;
void getWindowSize(int& widthOut, int& heightOut) const;
+ void createImages();
public:
~SwapchainImpl();
diff --git a/tools/gfx/metal/metal-texture.h b/tools/gfx/metal/metal-texture.h
index 853af7ab0..8f8ab3576 100644
--- a/tools/gfx/metal/metal-texture.h
+++ b/tools/gfx/metal/metal-texture.h
@@ -20,7 +20,7 @@ public:
TextureResourceImpl(const Desc& desc, DeviceImpl* device);
~TextureResourceImpl();
- RefPtr<DeviceImpl> m_device;
+ BreakableReference<DeviceImpl> m_device;
NS::SharedPtr<MTL::Texture> m_texture;
// TODO still needed?
// MTL::PixelFormat m_metalFormat = MTL::PixelFormat::PixelFormatInvalid;
diff --git a/tools/gfx/metal/metal-util.cpp b/tools/gfx/metal/metal-util.cpp
index d7d2a793d..ed96eb487 100644
--- a/tools/gfx/metal/metal-util.cpp
+++ b/tools/gfx/metal/metal-util.cpp
@@ -176,6 +176,35 @@ MTL::VertexFormat MetalUtil::translateVertexFormat(Format format)
}
}
+bool MetalUtil::isDepthFormat(MTL::PixelFormat format)
+{
+ switch (format)
+ {
+ case MTL::PixelFormatDepth16Unorm:
+ case MTL::PixelFormatDepth32Float:
+ case MTL::PixelFormatDepth24Unorm_Stencil8:
+ case MTL::PixelFormatDepth32Float_Stencil8:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool MetalUtil::isStencilFormat(MTL::PixelFormat format)
+{
+ switch (format)
+ {
+ case MTL::PixelFormatStencil8:
+ case MTL::PixelFormatDepth24Unorm_Stencil8:
+ case MTL::PixelFormatDepth32Float_Stencil8:
+ case MTL::PixelFormatX32_Stencil8:
+ case MTL::PixelFormatX24_Stencil8:
+ return true;
+ default:
+ return false;
+ }
+}
+
MTL::SamplerMinMagFilter MetalUtil::translateSamplerMinMagFilter(TextureFilteringMode mode)
{
switch (mode)
@@ -246,6 +275,31 @@ MTL::CompareFunction MetalUtil::translateCompareFunction(ComparisonFunc func)
}
}
+MTL::StencilOperation MetalUtil::translateStencilOperation(StencilOp op)
+{
+ switch (op)
+ {
+ case StencilOp::Keep:
+ return MTL::StencilOperationKeep;
+ case StencilOp::Zero:
+ return MTL::StencilOperationZero;
+ case StencilOp::Replace:
+ return MTL::StencilOperationReplace;
+ case StencilOp::IncrementSaturate:
+ return MTL::StencilOperationIncrementClamp;
+ case StencilOp::DecrementSaturate:
+ return MTL::StencilOperationDecrementClamp;
+ case StencilOp::Invert:
+ return MTL::StencilOperationInvert;
+ case StencilOp::IncrementWrap:
+ return MTL::StencilOperationIncrementWrap;
+ case StencilOp::DecrementWrap:
+ return MTL::StencilOperationDecrementWrap;
+ default:
+ return MTL::StencilOperation(0);
+ }
+}
+
MTL::VertexStepFunction MetalUtil::translateVertexStepFunction(InputSlotClass slotClass)
{
switch (slotClass)
@@ -259,4 +313,156 @@ MTL::VertexStepFunction MetalUtil::translateVertexStepFunction(InputSlotClass sl
}
}
+MTL::PrimitiveType MetalUtil::translatePrimitiveType(PrimitiveTopology topology)
+{
+ switch (topology)
+ {
+ case PrimitiveTopology::TriangleList:
+ return MTL::PrimitiveTypeTriangle;
+ case PrimitiveTopology::TriangleStrip:
+ return MTL::PrimitiveTypeTriangleStrip;
+ case PrimitiveTopology::PointList:
+ return MTL::PrimitiveTypePoint;
+ case PrimitiveTopology::LineList:
+ return MTL::PrimitiveTypeLine;
+ case PrimitiveTopology::LineStrip:
+ return MTL::PrimitiveTypeLineStrip;
+ default:
+ return MTL::PrimitiveType(0);
+ }
+}
+
+MTL::PrimitiveTopologyClass MetalUtil::translatePrimitiveTopologyClass(PrimitiveType type)
+{
+ switch (type)
+ {
+ case PrimitiveType::Point:
+ return MTL::PrimitiveTopologyClassPoint;
+ case PrimitiveType::Line:
+ return MTL::PrimitiveTopologyClassLine;
+ case PrimitiveType::Triangle:
+ return MTL::PrimitiveTopologyClassTriangle;
+ case PrimitiveType::Patch:
+ default:
+ return MTL::PrimitiveTopologyClassUnspecified;
+ }
+}
+
+MTL::BlendFactor MetalUtil::translateBlendFactor(BlendFactor factor)
+{
+ switch (factor)
+ {
+ case BlendFactor::Zero:
+ return MTL::BlendFactorZero;
+ case BlendFactor::One:
+ return MTL::BlendFactorOne;
+ case BlendFactor::SrcColor:
+ return MTL::BlendFactorSourceColor;
+ case BlendFactor::InvSrcColor:
+ return MTL::BlendFactorOneMinusSourceColor;
+ case BlendFactor::SrcAlpha:
+ return MTL::BlendFactorSourceAlpha;
+ case BlendFactor::InvSrcAlpha:
+ return MTL::BlendFactorOneMinusSourceAlpha;
+ case BlendFactor::DestAlpha:
+ return MTL::BlendFactorDestinationAlpha;
+ case BlendFactor::InvDestAlpha:
+ return MTL::BlendFactorOneMinusDestinationAlpha;
+ case BlendFactor::DestColor:
+ return MTL::BlendFactorDestinationColor;
+ case BlendFactor::InvDestColor:
+ return MTL::BlendFactorOneMinusDestinationColor;
+ case BlendFactor::SrcAlphaSaturate:
+ return MTL::BlendFactorSourceAlphaSaturated;
+ case BlendFactor::BlendColor:
+ return MTL::BlendFactorBlendColor;
+ case BlendFactor::InvBlendColor:
+ return MTL::BlendFactorOneMinusBlendColor;
+ case BlendFactor::SecondarySrcColor:
+ return MTL::BlendFactorSource1Color;
+ case BlendFactor::InvSecondarySrcColor:
+ return MTL::BlendFactorOneMinusSource1Color;
+ case BlendFactor::SecondarySrcAlpha:
+ return MTL::BlendFactorSource1Alpha;
+ case BlendFactor::InvSecondarySrcAlpha:
+ return MTL::BlendFactorOneMinusSource1Alpha;
+ default:
+ return MTL::BlendFactor(0);
+ }
+}
+
+MTL::BlendOperation MetalUtil::translateBlendOperation(BlendOp op)
+{
+ switch (op)
+ {
+ case BlendOp::Add:
+ return MTL::BlendOperationAdd;
+ case BlendOp::Subtract:
+ return MTL::BlendOperationSubtract;
+ case BlendOp::ReverseSubtract:
+ return MTL::BlendOperationReverseSubtract;
+ case BlendOp::Min:
+ return MTL::BlendOperationMin;
+ case BlendOp::Max:
+ return MTL::BlendOperationMax;
+ default:
+ return MTL::BlendOperation(0);
+ }
+}
+
+MTL::ColorWriteMask MetalUtil::translateColorWriteMask(RenderTargetWriteMask::Type mask)
+{
+ MTL::ColorWriteMask result = MTL::ColorWriteMaskNone;
+ if (mask & RenderTargetWriteMask::EnableRed)
+ result |= MTL::ColorWriteMaskRed;
+ if (mask & RenderTargetWriteMask::EnableGreen)
+ result |= MTL::ColorWriteMaskGreen;
+ if (mask & RenderTargetWriteMask::EnableBlue)
+ result |= MTL::ColorWriteMaskBlue;
+ if (mask & RenderTargetWriteMask::EnableAlpha)
+ result |= MTL::ColorWriteMaskAlpha;
+ return result;
+}
+
+MTL::Winding MetalUtil::translateWinding(FrontFaceMode mode)
+{
+ switch (mode)
+ {
+ case FrontFaceMode::CounterClockwise:
+ return MTL::WindingCounterClockwise;
+ case FrontFaceMode::Clockwise:
+ return MTL::WindingClockwise;
+ default:
+ return MTL::Winding(0);
+ }
+}
+
+MTL::CullMode MetalUtil::translateCullMode(CullMode mode)
+{
+ switch (mode)
+ {
+ case CullMode::None:
+ return MTL::CullModeNone;
+ case CullMode::Front:
+ return MTL::CullModeFront;
+ case CullMode::Back:
+ return MTL::CullModeBack;
+ default:
+ return MTL::CullMode(0);
+ }
+}
+
+MTL::TriangleFillMode MetalUtil::translateTriangleFillMode(FillMode mode)
+{
+ switch (mode)
+ {
+ case FillMode::Solid:
+ return MTL::TriangleFillModeFill;
+ case FillMode::Wireframe:
+ return MTL::TriangleFillModeLines;
+ default:
+ return MTL::TriangleFillMode(0);
+ }
+}
+
} // namespace gfx
diff --git a/tools/gfx/metal/metal-util.h b/tools/gfx/metal/metal-util.h
index 617d82e29..279f0c67e 100644
--- a/tools/gfx/metal/metal-util.h
+++ b/tools/gfx/metal/metal-util.h
@@ -25,31 +25,28 @@ struct MetalUtil
static MTL::PixelFormat translatePixelFormat(Format format);
static MTL::VertexFormat translateVertexFormat(Format format);
- static inline bool isDepthFormat(MTL::PixelFormat format)
- {
- switch (format)
- {
- return true;
- }
- return false;
- }
-
- static inline bool isStencilFormat(MTL::PixelFormat format)
- {
- switch (format)
- {
- return true;
- }
- return false;
- }
+ static bool isDepthFormat(MTL::PixelFormat format);
+ static bool isStencilFormat(MTL::PixelFormat format);
static MTL::SamplerMinMagFilter translateSamplerMinMagFilter(TextureFilteringMode mode);
static MTL::SamplerMipFilter translateSamplerMipFilter(TextureFilteringMode mode);
static MTL::SamplerAddressMode translateSamplerAddressMode(TextureAddressingMode mode);
static MTL::CompareFunction translateCompareFunction(ComparisonFunc func);
+ static MTL::StencilOperation translateStencilOperation(StencilOp op);
static MTL::VertexStepFunction translateVertexStepFunction(InputSlotClass slotClass);
+ static MTL::PrimitiveType translatePrimitiveType(PrimitiveTopology topology);
+ static MTL::PrimitiveTopologyClass translatePrimitiveTopologyClass(PrimitiveType type);
+
+ static MTL::BlendFactor translateBlendFactor(BlendFactor factor);
+ static MTL::BlendOperation translateBlendOperation(BlendOp op);
+ static MTL::ColorWriteMask translateColorWriteMask(RenderTargetWriteMask::Type mask);
+
+ static MTL::Winding translateWinding(FrontFaceMode mode);
+ static MTL::CullMode translateCullMode(CullMode mode);
+ static MTL::TriangleFillMode translateTriangleFillMode(FillMode mode);
+
};
struct ScopedAutoreleasePool
diff --git a/tools/gfx/metal/metal-vertex-layout.cpp b/tools/gfx/metal/metal-vertex-layout.cpp
new file mode 100644
index 000000000..686f3ad0c
--- /dev/null
+++ b/tools/gfx/metal/metal-vertex-layout.cpp
@@ -0,0 +1,57 @@
+// metal-vertex-layout.cpp
+#include "metal-vertex-layout.h"
+#include "metal-util.h"
+
+namespace gfx
+{
+
+using namespace Slang;
+
+namespace metal
+{
+
+Result InputLayoutImpl::init(const IInputLayout::Desc& desc)
+{
+ for (Index i = 0; i < desc.inputElementCount; i++)
+ {
+ if (MetalUtil::translateVertexFormat(desc.inputElements[i].format) == MTL::VertexFormatInvalid)
+ {
+ return SLANG_E_INVALID_ARG;
+ }
+ m_inputElements.add(desc.inputElements[i]);
+ }
+ for (Index i = 0; i < desc.vertexStreamCount; i++)
+ {
+ m_vertexStreams.add(desc.vertexStreams[i]);
+ }
+ return SLANG_OK;
+}
+
+NS::SharedPtr<MTL::VertexDescriptor> InputLayoutImpl::createVertexDescriptor(NS::UInteger vertexBufferIndexOffset)
+{
+ NS::SharedPtr<MTL::VertexDescriptor> vertexDescriptor = NS::TransferPtr(MTL::VertexDescriptor::alloc()->init());
+
+ for (Index i = 0; i < m_inputElements.getCount(); i++)
+ {
+ const auto& inputElement = m_inputElements[i];
+ MTL::VertexAttributeDescriptor* desc = vertexDescriptor->attributes()->object(i);
+ desc->setOffset(inputElement.offset);
+ desc->setBufferIndex(inputElement.bufferSlotIndex + vertexBufferIndexOffset);
+ MTL::VertexFormat metalFormat = MetalUtil::translateVertexFormat(inputElement.format);
+ desc->setFormat(metalFormat);
+ }
+
+ for (Index i = 0; i < m_vertexStreams.getCount(); i++)
+ {
+ const auto& vertexStream = m_vertexStreams[i];
+ MTL::VertexBufferLayoutDescriptor* desc = vertexDescriptor->layouts()->object(i + vertexBufferIndexOffset);
+ desc->setStepFunction(MetalUtil::translateVertexStepFunction(vertexStream.slotClass));
+ desc->setStepRate(vertexStream.slotClass == InputSlotClass::PerVertex ? 1 : vertexStream.instanceDataStepRate);
+ desc->setStride(vertexStream.stride);
+ }
+
+ return vertexDescriptor;
+}
+
+} // namespace metal
+} // namespace gfx
diff --git a/tools/gfx/metal/metal-vertex-layout.h b/tools/gfx/metal/metal-vertex-layout.h
index b0f989efd..5cfdf3dc6 100644
--- a/tools/gfx/metal/metal-vertex-layout.h
+++ b/tools/gfx/metal/metal-vertex-layout.h
@@ -14,7 +14,11 @@ namespace metal
class InputLayoutImpl : public InputLayoutBase
{
public:
- NS::SharedPtr<MTL::VertexDescriptor> m_vertexDescriptor;
+ List<InputElementDesc> m_inputElements;
+ List<VertexStreamDesc> m_vertexStreams;
+
+ Result init(const IInputLayout::Desc& desc);
+ NS::SharedPtr<MTL::VertexDescriptor> createVertexDescriptor(NS::UInteger vertexBufferIndexOffset);
};
} // namespace metal
diff --git a/tools/gfx/vulkan/vk-fence.cpp b/tools/gfx/vulkan/vk-fence.cpp
index f81f56ca7..d71847dcb 100644
--- a/tools/gfx/vulkan/vk-fence.cpp
+++ b/tools/gfx/vulkan/vk-fence.cpp
@@ -52,7 +52,7 @@ Result FenceImpl::init(const IFence::Desc& desc)
{
#if SLANG_WINDOWS_FAMILY
exportSemaphoreWin32HandleInfoKHR.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR;
- exportSemaphoreWin32HandleInfoKHR.pNext = timelineCreateInfo.pNext;;
+ exportSemaphoreWin32HandleInfoKHR.pNext = timelineCreateInfo.pNext;
exportSemaphoreWin32HandleInfoKHR.pAttributes = nullptr;
exportSemaphoreWin32HandleInfoKHR.dwAccess = GENERIC_ALL;
exportSemaphoreWin32HandleInfoKHR.name = (LPCWSTR)nullptr;