From 8ea3854d94eb1ff213be716a38493d601784810b Mon Sep 17 00:00:00 2001 From: skallweitNV <64953474+skallweitNV@users.noreply.github.com> Date: Thu, 6 Jun 2024 18:08:38 +0200 Subject: work on gfx metal backend (#4287) * implement sampler state * implement input layout * implement fence object * buffer implementation * texture implementation * cleanup * add adapter enumeration * supported formats and allocation info * work on device and implement readBufferResource * skeleton for transient resource heap * initial work on command queue / buffers / encoders * fix uploading initial buffer data * implement buffer resource view * string utility functions * wip query pool implementation * cleanup * swapchain * wip * remove plain buffer view * extend gfxGetDeviceTypeName with metal * basic support for resource binding with compute shaders * needed for metal bindings * replace assert(0) with SLANG_UNIMPLEMENTED_X --- tools/gfx/metal/metal-command-encoder.cpp | 190 +++++++++++++++++++++--------- 1 file changed, 133 insertions(+), 57 deletions(-) (limited to 'tools/gfx/metal/metal-command-encoder.cpp') diff --git a/tools/gfx/metal/metal-command-encoder.cpp b/tools/gfx/metal/metal-command-encoder.cpp index 1e74733d1..f1e834400 100644 --- a/tools/gfx/metal/metal-command-encoder.cpp +++ b/tools/gfx/metal/metal-command-encoder.cpp @@ -10,6 +10,7 @@ #include "metal-shader-program.h" #include "metal-shader-table.h" #include "metal-texture.h" +#include "metal-util.h" #include "metal-helper-functions.h" @@ -24,37 +25,46 @@ namespace metal void PipelineCommandEncoder::init(CommandBufferImpl* commandBuffer) { m_commandBuffer = commandBuffer; - m_device = commandBuffer->m_renderer; - m_metalCommandBuffer = m_commandBuffer->m_commandBuffer; + m_metalCommandBuffer = m_commandBuffer->m_commandBuffer.get(); } -void ResourceCommandEncoder::copyBuffer( - IBufferResource* dst, Offset dstOffset, IBufferResource* src, Offset srcOffset, Size size) +void PipelineCommandEncoder::endEncodingImpl() { + m_commandBuffer->endMetalCommandEncoder(); } -void ResourceCommandEncoder::uploadBufferData( - IBufferResource* buffer, Offset offset, Size size, void* data) -{ -} - -void ResourceCommandEncoder::textureBarrier( - GfxCount count, ITextureResource* const* textures, ResourceState src, ResourceState dst) +Result PipelineCommandEncoder::setPipelineStateImpl(IPipelineState* state, IShaderObject** outRootObject) { + m_currentPipeline = static_cast(state); + // m_commandBuffer->m_mutableRootShaderObject = nullptr; + SLANG_RETURN_ON_FAIL(m_commandBuffer->m_rootObject.init( + m_commandBuffer->m_device, + m_currentPipeline->getProgram()->m_rootObjectLayout)); + *outRootObject = &m_commandBuffer->m_rootObject; + return SLANG_OK; } -// TODO: Change size_t to Count? -void ResourceCommandEncoder::bufferBarrier( - GfxCount count, IBufferResource* const* buffers, ResourceState src, ResourceState dst) +void ResourceCommandEncoder::endEncoding() { + PipelineCommandEncoder::endEncodingImpl(); } -void ResourceCommandEncoder::endEncoding() +void ResourceCommandEncoder::writeTimestamp(IQueryPool* queryPool, GfxIndex index) { + auto encoder = m_commandBuffer->getMetalBlitCommandEncoder(); + encoder->sampleCountersInBuffer(static_cast(queryPool)->m_counterSampleBuffer.get(), index, true); } -void ResourceCommandEncoder::writeTimestamp(IQueryPool* queryPool, GfxIndex index) +void ResourceCommandEncoder::copyBuffer( + IBufferResource* dst, Offset dstOffset, IBufferResource* src, Offset srcOffset, Size size) { + auto encoder = m_commandBuffer->getMetalBlitCommandEncoder(); + encoder->copyFromBuffer( + static_cast(src)->m_buffer.get(), + srcOffset, + static_cast(dst)->m_buffer.get(), + dstOffset, + size); } void ResourceCommandEncoder::copyTexture( @@ -68,6 +78,62 @@ void ResourceCommandEncoder::copyTexture( ITextureResource::Offset3D srcOffset, ITextureResource::Extents extent) { + auto encoder = m_commandBuffer->getMetalBlitCommandEncoder(); + + if (dstSubresource.layerCount == 0 && dstSubresource.mipLevelCount == 0 && srcSubresource.layerCount == 0 && srcSubresource.mipLevelCount == 0) + { + encoder->copyFromTexture( + static_cast(src)->m_texture.get(), + static_cast(dst)->m_texture.get()); + } + else + { + for (GfxIndex layer = 0; layer < dstSubresource.layerCount; layer++) + { + encoder->copyFromTexture( + static_cast(src)->m_texture.get(), + srcSubresource.baseArrayLayer + layer, + srcSubresource.mipLevel, + MTL::Origin(srcOffset.x, srcOffset.y, srcOffset.z), + MTL::Size(extent.width, extent.height, extent.depth), + static_cast(dst)->m_texture.get(), + dstSubresource.baseArrayLayer + layer, + dstSubresource.mipLevel, + MTL::Origin(dstOffset.x, dstOffset.y, dstOffset.z)); + } + } +} + +void ResourceCommandEncoder::copyTextureToBuffer( + IBufferResource* dst, + Offset dstOffset, + Size dstSize, + Size dstRowStride, + ITextureResource* src, + ResourceState srcState, + SubresourceRange srcSubresource, + ITextureResource::Offset3D srcOffset, + ITextureResource::Extents extent) +{ + assert(srcSubresource.mipLevelCount <= 1); + + auto encoder = m_commandBuffer->getMetalBlitCommandEncoder(); + encoder->copyFromTexture( + static_cast(src)->m_texture.get(), + srcSubresource.baseArrayLayer, + srcSubresource.mipLevel, + MTL::Origin(srcOffset.x, srcOffset.y, srcOffset.z), + MTL::Size(extent.width, extent.height, extent.depth), + static_cast(dst)->m_buffer.get(), + dstOffset, + dstRowStride, + dstSize); +} + +void ResourceCommandEncoder::uploadBufferData( + IBufferResource* buffer, Offset offset, Size size, void* data) +{ + SLANG_UNIMPLEMENTED_X("uploadBufferData"); } void ResourceCommandEncoder::uploadTextureData( @@ -78,12 +144,34 @@ void ResourceCommandEncoder::uploadTextureData( ITextureResource::SubresourceData* subResourceData, GfxCount subResourceDataCount) { + SLANG_UNIMPLEMENTED_X("uploadTextureData"); } +void ResourceCommandEncoder::bufferBarrier( + GfxCount count, IBufferResource* const* buffers, ResourceState src, ResourceState dst) +{ + // We use automatic hazard tracking for now, no need for barriers. +} + +void ResourceCommandEncoder::textureBarrier( + GfxCount count, ITextureResource* const* textures, ResourceState src, ResourceState dst) +{ + // We use automatic hazard tracking for now, no need for barriers. +} + +void ResourceCommandEncoder::textureSubresourceBarrier( + ITextureResource* texture, + SubresourceRange subresourceRange, + ResourceState src, + ResourceState dst) +{ + // We use automatic hazard tracking for now, no need for barriers. +} void ResourceCommandEncoder::clearResourceView( IResourceView* view, ClearValue* clearValue, ClearResourceViewFlags::Enum flags) { + SLANG_UNIMPLEMENTED_X("clearResourceView"); } void ResourceCommandEncoder::resolveResource( @@ -94,41 +182,29 @@ void ResourceCommandEncoder::resolveResource( ResourceState destState, SubresourceRange destRange) { + SLANG_UNIMPLEMENTED_X("resolveResource"); } void ResourceCommandEncoder::resolveQuery( IQueryPool* queryPool, GfxIndex index, GfxCount count, IBufferResource* buffer, Offset offset) { -} - -void ResourceCommandEncoder::copyTextureToBuffer( - IBufferResource* dst, - Offset dstOffset, - Size dstSize, - Size dstRowStride, - ITextureResource* src, - ResourceState srcState, - SubresourceRange srcSubresource, - ITextureResource::Offset3D srcOffset, - ITextureResource::Extents extent) -{ - assert(srcSubresource.mipLevelCount <= 1); -} - -void ResourceCommandEncoder::textureSubresourceBarrier( - ITextureResource* texture, - SubresourceRange subresourceRange, - ResourceState src, - ResourceState dst) -{ + auto encoder = m_commandBuffer->getMetalBlitCommandEncoder(); + encoder->resolveCounters( + static_cast(queryPool)->m_counterSampleBuffer.get(), + NS::Range(index, count), + static_cast(buffer)->m_buffer.get(), + offset); } void ResourceCommandEncoder::beginDebugEvent(const char* name, float rgbColor[3]) { + NS::SharedPtr string = MetalUtil::createString(name); + m_commandBuffer->m_commandBuffer->pushDebugGroup(string.get()); } void ResourceCommandEncoder::endDebugEvent() { + m_commandBuffer->m_commandBuffer->popDebugGroup(); } void RenderCommandEncoder::beginPass(IRenderPassLayout* renderPass, IFramebuffer* framebuffer) @@ -145,7 +221,7 @@ void RenderCommandEncoder::beginPass(IRenderPassLayout* renderPass, IFramebuffer if (rpd->depthAttachment() && false) { TextureResourceViewImpl* depthView = static_cast(fb->depthStencilView.get()); - rpd->depthAttachment()->setTexture(depthView->m_texture->m_texture); + rpd->depthAttachment()->setTexture(depthView->m_texture->m_texture.get()); } const int colorTargetCount = fb->renderTargetViews.getCount(); for (int i = 0; i < colorTargetCount; ++i) @@ -153,15 +229,7 @@ void RenderCommandEncoder::beginPass(IRenderPassLayout* renderPass, IFramebuffer TextureResourceViewImpl* texView = static_cast(fb->renderTargetViews[i].get()); MTL::Texture* tex = nullptr; assert(texView->m_texture); - if (texView->m_texture->m_isCurrentDrawable) - { - CA::MetalDrawable* drawable = static_cast(fb->m_renderer->m_drawable); - tex = drawable->texture(); - } - else - { - tex = texView->m_texture->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)); } @@ -181,7 +249,7 @@ Result RenderCommandEncoder::bindPipeline( { m_currentPipeline = static_cast(pipelineState); // Initialize the root object - SLANG_RETURN_ON_FAIL(m_commandBuffer->m_rootObject.init(m_commandBuffer->m_renderer, + SLANG_RETURN_ON_FAIL(m_commandBuffer->m_rootObject.init(m_commandBuffer->m_device, m_currentPipeline->getProgram()->m_rootObjectLayout)); *outRootObject = &m_commandBuffer->m_rootObject; //if (pPipelineState->m_renderState == nullptr) return SLANG_ERROR_INVALID_PARAMETER; @@ -249,8 +317,8 @@ void RenderCommandEncoder::setVertexBuffers( BufferResourceImpl* buffer = static_cast(buffers[i]); if (buffer) { - MTL::Buffer* vertexBuffers = {buffer->m_buffer}; - m_encoder->setVertexBuffer(buffer->m_buffer, offsets[i], slotIndex); + MTL::Buffer* vertexBuffers = {buffer->m_buffer.get()}; + m_encoder->setVertexBuffer(buffer->m_buffer.get(), offsets[i], slotIndex); // ... } } @@ -369,12 +437,15 @@ Result RenderCommandEncoder::drawMeshTasks(int x, int y, int z) return SLANG_E_NOT_IMPLEMENTED; } -void ComputeCommandEncoder::endEncoding() { } +void ComputeCommandEncoder::endEncoding() +{ + ResourceCommandEncoder::endEncoding(); +} Result ComputeCommandEncoder::bindPipeline( IPipelineState* pipelineState, IShaderObject** outRootObject) { - return SLANG_E_NOT_IMPLEMENTED; + return setPipelineStateImpl(pipelineState, outRootObject); } Result ComputeCommandEncoder::bindPipelineWithRootObject( @@ -386,10 +457,15 @@ Result ComputeCommandEncoder::bindPipelineWithRootObject( Result ComputeCommandEncoder::dispatchCompute(int x, int y, int z) { auto pipeline = static_cast(m_currentPipeline.Ptr()); - if (!pipeline) - { - return SLANG_FAIL; - } + pipeline->ensureAPIPipelineStateCreated(); + + auto metalComputeCommandEncoder = m_commandBuffer->getMetalComputeCommandEncoder(); + metalComputeCommandEncoder->setComputePipelineState(pipeline->m_computePipelineState.get()); + ComputeBindingContext bindingContext; + bindingContext.init(m_commandBuffer->m_device, metalComputeCommandEncoder); + auto program = static_cast(m_currentPipeline->m_program.get()); + m_commandBuffer->m_rootObject.bindAsRoot(&bindingContext, program->m_rootObjectLayout); + metalComputeCommandEncoder->dispatchThreadgroups(MTL::Size(x, y, z), pipeline->m_threadGroupSize); // Also create descriptor sets based on the given pipeline layout return SLANG_E_NOT_IMPLEMENTED; -- cgit v1.2.3