diff options
author | 2019-10-13 13:50:38 +0200 | |
---|---|---|
committer | 2019-10-13 07:50:38 -0400 | |
commit | 0837e7451a84f95c29dbdb9bd6b8b931fee1635d (patch) | |
tree | 626bcbd250a7fbebdf5958a288d2f438d4f9fb5a /3rdparty/bgfx/src/renderer_mtl.mm | |
parent | c913ccb59d713ce0b91135520719ac5385e54358 (diff) |
WIP: sync bgfx, bx and bimg with latest upstream (#5723)
* Sync with bgfx upstream revision b91d0b6
* Sync with bx upstream revision d60912b
* Sync with bimg upstream revision bd81f60
* Add astc-codec decoder
* Rename VertexDecl to VertexLayout
* Rename UniformType enum Int1 to Sampler.
* Add NVN stub
* Fix unused-const-variable error on macOS
* Drop redundant explicit language parameters
buildoptions_cpp are only applied to c++ files and buildoptions_objcpp are only
applied to objective c++ files. As such, hardcoding -x offers no benefit while
preventing overrides (such as one needed by 3rdparty/bgfx/src/renderer_vk.cpp on
macOS) from working.
* Re-introduce -x c++ in places where C code is compiled as C++ to prevent clang from throwing a warning
* Build bgfx as Objective-C++ on macOS
It is needed due to included headers
* Enable Direct3D12 and Vulkan bgfx rendering backends
* Enable building of spirv shaders
* Properly escape /c in cmd call
* Comment out dx12 bgfx renderer
* Honor VERBOSE setting during shaders build
* Only invert hlsl shader XYZ_TO_sRGB matrix for opengl
* Add spirv shaders
* OpenGL ES needs transposed matrix too
* Metal needs transposed matrix as well
Diffstat (limited to '3rdparty/bgfx/src/renderer_mtl.mm')
-rw-r--r-- | 3rdparty/bgfx/src/renderer_mtl.mm | 2024 |
1 files changed, 1249 insertions, 775 deletions
diff --git a/3rdparty/bgfx/src/renderer_mtl.mm b/3rdparty/bgfx/src/renderer_mtl.mm index d104f7130d6..2cbb902f566 100644 --- a/3rdparty/bgfx/src/renderer_mtl.mm +++ b/3rdparty/bgfx/src/renderer_mtl.mm @@ -22,6 +22,14 @@ namespace bgfx { namespace mtl { static char s_viewName[BGFX_CONFIG_MAX_VIEWS][BGFX_CONFIG_MAX_VIEW_NAME]; + inline void setViewType(ViewId _view, const bx::StringView _str) + { + if (BX_ENABLED(BGFX_CONFIG_DEBUG_ANNOTATION || BGFX_CONFIG_PROFILER) ) + { + bx::memCopy(&s_viewName[_view][3], _str.getPtr(), _str.getLength() ); + } + } + struct PrimInfo { MTLPrimitiveType m_type; @@ -304,7 +312,7 @@ namespace bgfx { namespace mtl }; BX_STATIC_ASSERT(TextureFormat::Count == BX_COUNTOF(s_textureFormat) ); - int s_msaa[] = + int32_t s_msaa[] = { 1, 2, @@ -319,7 +327,7 @@ namespace bgfx { namespace mtl { case MTLDataTypeUInt: case MTLDataTypeInt: - return UniformType::Int1; + return UniformType::Sampler; case MTLDataTypeFloat: case MTLDataTypeFloat2: @@ -358,6 +366,7 @@ namespace bgfx { namespace mtl , m_captureSize(0) , m_saveScreenshot(false) { + bx::memSet(&m_windows, 0xff, sizeof(m_windows) ); } ~RendererContextMtl() @@ -387,7 +396,22 @@ namespace bgfx { namespace mtl } retain(m_device); - createFrameBuffer(m_fbh, g_platformData.nwh, 0, 0, TextureFormat::Unknown, TextureFormat::UnknownDepth); + + m_mainFrameBuffer.create( + 0 + , g_platformData.nwh + , _init.resolution.width + , _init.resolution.height + , TextureFormat::Unknown + , TextureFormat::UnknownDepth + ); + m_numWindows = 1; + + if (NULL == m_mainFrameBuffer.m_swapChain->m_metalLayer) + { + release(m_device); + return false; + } m_cmd.init(m_device); BGFX_FATAL(NULL != m_cmd.m_commandQueue, Fatal::UnableToInitialize, "Unable to create Metal device."); @@ -434,16 +458,17 @@ namespace bgfx { namespace mtl if (NULL != lib) { m_screenshotBlitProgramVsh.m_function = lib.newFunctionWithName(SHADER_FUNCTION_NAME); + release(lib); } lib = m_device.newLibraryWithSource(fshSource); if (NULL != lib) { m_screenshotBlitProgramFsh.m_function = lib.newFunctionWithName(SHADER_FUNCTION_NAME); + release(lib); } m_screenshotBlitProgram.create(&m_screenshotBlitProgramVsh, &m_screenshotBlitProgramFsh); - release(lib); reset(m_renderPipelineDescriptor); m_renderPipelineDescriptor.colorAttachments[0].pixelFormat = m_mainFrameBuffer.m_swapChain->m_metalLayer.pixelFormat; @@ -467,6 +492,7 @@ namespace bgfx { namespace mtl | BGFX_CAPS_TEXTURE_READ_BACK | BGFX_CAPS_VERTEX_ATTRIB_HALF | BGFX_CAPS_VERTEX_ATTRIB_UINT10 + | BGFX_CAPS_COMPUTE ); if (BX_ENABLED(BX_PLATFORM_IOS) ) @@ -481,16 +507,34 @@ namespace bgfx { namespace mtl } g_caps.limits.maxFBAttachments = uint8_t(bx::uint32_min(m_device.supportsFeatureSet( (MTLFeatureSet)1 /* MTLFeatureSet_iOS_GPUFamily2_v1 */) ? 8 : 4, BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS) ); + + if ( m_device.supportsFeatureSet( (MTLFeatureSet)4 /* MTLFeatureSet_iOS_GPUFamily3_v1 */ )) + { + g_caps.supported |= BGFX_CAPS_DRAW_INDIRECT; + } + + if ( m_device.supportsFeatureSet( (MTLFeatureSet)11 /* MTLFeatureSet_iOS_GPUFamily4_v1 */ )) + { + g_caps.supported |= BGFX_CAPS_TEXTURE_CUBE_ARRAY; + } } else if (BX_ENABLED(BX_PLATFORM_OSX) ) { g_caps.limits.maxTextureSize = 16384; g_caps.limits.maxFBAttachments = 8; g_caps.supported |= BGFX_CAPS_TEXTURE_CUBE_ARRAY; + + if ( m_device.supportsFeatureSet( (MTLFeatureSet)10001 /* MTLFeatureSet_macOS_GPUFamily1_v2 */ )) + { + g_caps.supported |= BGFX_CAPS_DRAW_INDIRECT; + } } g_caps.limits.maxTextureLayers = 2048; g_caps.limits.maxVertexStreams = BGFX_CONFIG_MAX_VERTEX_STREAMS; + // Maximum number of entries in the buffer argument table, per graphics or compute function are 31. + // It is decremented by 1 because 1 entry is used for uniforms. + g_caps.limits.maxComputeBindings = bx::uint32_min(30, BGFX_MAX_COMPUTE_BINDINGS); m_hasPixelFormatDepth32Float_Stencil8 = false || BX_ENABLED(BX_PLATFORM_OSX) @@ -594,11 +638,17 @@ namespace bgfx { namespace mtl } } - for (uint32_t ii = 1; ii < 5; ++ii) + for (uint32_t ii = 1, last = 0; ii < BX_COUNTOF(s_msaa); ++ii) { - if (!m_device.supportsTextureSampleCount(s_msaa[ii]) ) + const int32_t sampleCount = 1; //1<<ii; + if (m_device.supportsTextureSampleCount(sampleCount) ) + { + s_msaa[ii] = sampleCount; + last = ii; + } + else { - s_msaa[ii] = s_msaa[ii-1]; + s_msaa[ii] = s_msaa[last]; } } @@ -612,6 +662,7 @@ namespace bgfx { namespace mtl m_gpuTimer.init(); g_internalData.context = m_device; + return true; } @@ -621,6 +672,10 @@ namespace bgfx { namespace mtl m_gpuTimer.shutdown(); m_pipelineStateCache.invalidate(); + m_pipelineProgram.clear(); + + m_depthStencilStateCache.invalidate(); + m_samplerStateCache.invalidate(); for (uint32_t ii = 0; ii < BX_COUNTOF(m_shaders); ++ii) { @@ -647,11 +702,7 @@ namespace bgfx { namespace mtl MTL_RELEASE(m_textureDescriptor); MTL_RELEASE(m_samplerDescriptor); - MTL_RELEASE(m_mainFrameBuffer.m_swapChain->m_backBufferDepth); - if (BX_ENABLED(BX_PLATFORM_IOS) ) - { - MTL_RELEASE(m_mainFrameBuffer.m_swapChain->m_backBufferStencil); - } + m_mainFrameBuffer.destroy(); for (uint8_t i=0; i < MTL_MAX_FRAMES_IN_FLIGHT; ++i) { @@ -681,20 +732,20 @@ namespace bgfx { namespace mtl m_indexBuffers[_handle.idx].destroy(); } - void createVertexDecl(VertexDeclHandle _handle, const VertexDecl& _decl) override + void createVertexLayout(VertexLayoutHandle _handle, const VertexLayout& _layout) override { - VertexDecl& decl = m_vertexDecls[_handle.idx]; - bx::memCopy(&decl, &_decl, sizeof(VertexDecl) ); - dump(decl); + VertexLayout& layout = m_vertexLayouts[_handle.idx]; + bx::memCopy(&layout, &_layout, sizeof(VertexLayout) ); + dump(layout); } - void destroyVertexDecl(VertexDeclHandle /*_handle*/) override + void destroyVertexLayout(VertexLayoutHandle /*_handle*/) override { } - void createVertexBuffer(VertexBufferHandle _handle, const Memory* _mem, VertexDeclHandle _declHandle, uint16_t _flags) override + void createVertexBuffer(VertexBufferHandle _handle, const Memory* _mem, VertexLayoutHandle _layoutHandle, uint16_t _flags) override { - m_vertexBuffers[_handle.idx].create(_mem->size, _mem->data, _declHandle, _flags); + m_vertexBuffers[_handle.idx].create(_mem->size, _mem->data, _layoutHandle, _flags); } void destroyVertexBuffer(VertexBufferHandle _handle) override @@ -719,8 +770,8 @@ namespace bgfx { namespace mtl void createDynamicVertexBuffer(VertexBufferHandle _handle, uint32_t _size, uint16_t _flags) override { - VertexDeclHandle decl = BGFX_INVALID_HANDLE; - m_vertexBuffers[_handle.idx].create(_size, NULL, decl, _flags); + VertexLayoutHandle layoutHandle = BGFX_INVALID_HANDLE; + m_vertexBuffers[_handle.idx].create(_size, NULL, layoutHandle, _flags); } void updateDynamicVertexBuffer(VertexBufferHandle _handle, uint32_t _offset, uint32_t _size, const Memory* _mem) override @@ -745,11 +796,24 @@ namespace bgfx { namespace mtl void createProgram(ProgramHandle _handle, ShaderHandle _vsh, ShaderHandle _fsh) override { - m_program[_handle.idx].create(&m_shaders[_vsh.idx], &m_shaders[_fsh.idx]); + m_program[_handle.idx].create(&m_shaders[_vsh.idx], isValid(_fsh) ? &m_shaders[_fsh.idx] : NULL); } void destroyProgram(ProgramHandle _handle) override { + for (PipelineProgramArray::iterator it = m_pipelineProgram.begin(); it != m_pipelineProgram.end();) + { + if (it->program.idx == _handle.idx) + { + m_pipelineStateCache.invalidate(it->key); + it = m_pipelineProgram.erase(it); + } + else + { + ++it; + } + } + m_program[_handle.idx].destroy(); } @@ -774,11 +838,17 @@ namespace bgfx { namespace mtl void readTexture(TextureHandle _handle, void* _data, uint8_t _mip) override { - m_cmd.kick(false, true); - m_commandBuffer = m_cmd.alloc(); - const TextureMtl& texture = m_textures[_handle.idx]; + +#if BX_PLATFORM_OSX + BlitCommandEncoder bce = s_renderMtl->getBlitCommandEncoder(); + bce.synchronizeTexture(texture.m_ptr, 0, _mip); + endEncoding(); +#endif // BX_PLATFORM_OSX + m_cmd.kick(false, true); + m_commandBuffer = m_cmd.alloc(); + BX_CHECK(_mip<texture.m_numMips,"Invalid mip: %d num mips:",_mip,texture.m_numMips); uint32_t srcWidth = bx::uint32_max(1, texture.m_ptr.width() >> _mip); @@ -845,29 +915,37 @@ namespace bgfx { namespace mtl void createFrameBuffer(FrameBufferHandle _handle, void* _nwh, uint32_t _width, uint32_t _height, TextureFormat::Enum _format, TextureFormat::Enum _depthFormat) override { - uint16_t denseIdx = m_numWindows++; - m_windows[denseIdx] = _handle; - if (!isValid(_handle)) - { - m_mainFrameBuffer.create(denseIdx, _nwh, _width, _height, _format, _depthFormat); - } - else + for (uint32_t ii = 0, num = m_numWindows; ii < num; ++ii) { - m_frameBuffers[_handle.idx].create(denseIdx, _nwh, _width, _height, _format, _depthFormat); - m_frameBuffers[_handle.idx].m_swapChain->resize(m_frameBuffers[_handle.idx], _width, _height, 0);//_resolution.reset); + FrameBufferHandle handle = m_windows[ii]; + if (isValid(handle) + && m_frameBuffers[handle.idx].m_nwh == _nwh) + { + destroyFrameBuffer(handle); + } } + + uint16_t denseIdx = m_numWindows++; + m_windows[denseIdx] = _handle; + + FrameBufferMtl& fb = m_frameBuffers[_handle.idx]; + fb.create(denseIdx, _nwh, _width, _height, _format, _depthFormat); + fb.m_swapChain->resize(m_frameBuffers[_handle.idx], _width, _height, 0); } void destroyFrameBuffer(FrameBufferHandle _handle) override { uint16_t denseIdx = m_frameBuffers[_handle.idx].destroy(); + if (UINT16_MAX != denseIdx) { --m_numWindows; + if (m_numWindows > 1) { FrameBufferHandle handle = m_windows[m_numWindows]; m_windows[m_numWindows] = {kInvalidHandle}; + if (m_numWindows != denseIdx) { m_windows[denseIdx] = handle; @@ -942,14 +1020,11 @@ namespace bgfx { namespace mtl void updateViewName(ViewId _id, const char* _name) override { - if (BX_ENABLED(BGFX_CONFIG_DEBUG_PIX) ) - { - bx::strCopy( - &s_viewName[_id][BGFX_CONFIG_MAX_VIEW_NAME_RESERVED] - , BX_COUNTOF(s_viewName[0])-BGFX_CONFIG_MAX_VIEW_NAME_RESERVED - , _name - ); - } + bx::strCopy( + &s_viewName[_id][BGFX_CONFIG_MAX_VIEW_NAME_RESERVED] + , BX_COUNTOF(s_viewName[0])-BGFX_CONFIG_MAX_VIEW_NAME_RESERVED + , _name + ); } void updateUniform(uint16_t _loc, const void* _data, uint32_t _size) override @@ -957,23 +1032,31 @@ namespace bgfx { namespace mtl bx::memCopy(m_uniforms[_loc], _data, _size); } - void setMarker(const char* _marker, uint32_t /*_size*/) override + void invalidateOcclusionQuery(OcclusionQueryHandle _handle) override + { + m_occlusionQuery.invalidate(_handle); + } + + void setMarker(const char* _marker, uint16_t _len) override { - if (BX_ENABLED(BGFX_CONFIG_DEBUG_MTL) ) + BX_UNUSED(_len); + + if (BX_ENABLED(BGFX_CONFIG_DEBUG_ANNOTATION) ) { m_renderCommandEncoder.insertDebugSignpost(_marker); } } - void invalidateOcclusionQuery(OcclusionQueryHandle _handle) override + virtual void setName(Handle _handle, const char* _name, uint16_t _len) override { - m_occlusionQuery.invalidate(_handle); - } + BX_UNUSED(_len); - virtual void setName(Handle _handle, const char* _name) override - { switch (_handle.type) { + case Handle::IndexBuffer: + m_indexBuffers[_handle.idx].m_ptr.setLabel(_name); + break; + case Handle::Shader: m_shaders[_handle.idx].m_function.setLabel(_name); break; @@ -982,6 +1065,10 @@ namespace bgfx { namespace mtl m_textures[_handle.idx].m_ptr.setLabel(_name); break; + case Handle::VertexBuffer: + m_vertexBuffers[_handle.idx].m_ptr.setLabel(_name); + break; + default: BX_CHECK(false, "Invalid handle type?! %d", _handle.type); break; @@ -994,20 +1081,33 @@ namespace bgfx { namespace mtl void blitSetup(TextVideoMemBlitter& _blitter) override { - RenderCommandEncoder rce = m_renderCommandEncoder; + BX_UNUSED(_blitter); + } + + void blitRender(TextVideoMemBlitter& _blitter, uint32_t _numIndices) override + { + const uint32_t numVertices = _numIndices*4/6; + if (0 < numVertices) + { + m_indexBuffers [_blitter.m_ib->handle.idx].update( + 0 + , bx::strideAlign(_numIndices*2, 4) + , _blitter.m_ib->data + , true + ); + m_vertexBuffers[_blitter.m_vb->handle.idx].update( + 0 + , numVertices*_blitter.m_layout.m_stride + , _blitter.m_vb->data + , true + ); - uint32_t width = m_resolution.width; - uint32_t height = m_resolution.height; + endEncoding(); - FrameBufferHandle fbh = BGFX_INVALID_HANDLE; + uint32_t width = m_resolution.width; + uint32_t height = m_resolution.height; - if (NULL == rce - || m_renderCommandEncoderFrameBufferHandle.idx != kInvalidHandle) - { - if (m_renderCommandEncoder) - { - m_renderCommandEncoder.endEncoding(); - } + FrameBufferHandle fbh = BGFX_INVALID_HANDLE; RenderPassDescriptor renderPassDescriptor = newRenderPassDescriptor(); @@ -1015,80 +1115,77 @@ namespace bgfx { namespace mtl renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionLoad; renderPassDescriptor.colorAttachments[0].storeAction = - NULL != renderPassDescriptor.colorAttachments[0].resolveTexture - ? MTLStoreActionMultisampleResolve - : MTLStoreActionStore - ; + NULL != renderPassDescriptor.colorAttachments[0].resolveTexture + ? MTLStoreActionMultisampleResolve + : MTLStoreActionStore + ; - rce = m_commandBuffer.renderCommandEncoderWithDescriptor(renderPassDescriptor); + RenderCommandEncoder rce = m_commandBuffer.renderCommandEncoderWithDescriptor(renderPassDescriptor); m_renderCommandEncoder = rce; m_renderCommandEncoderFrameBufferHandle = fbh; MTL_RELEASE(renderPassDescriptor); - } - MTLViewport viewport = { 0.0f, 0.0f, (float)width, (float)height, 0.0f, 1.0f}; - rce.setViewport(viewport); - MTLScissorRect rc = { 0,0,width,height }; - rce.setScissorRect(rc); - rce.setCullMode(MTLCullModeNone); + MTLViewport viewport = { 0.0f, 0.0f, (float)width, (float)height, 0.0f, 1.0f}; + rce.setViewport(viewport); + MTLScissorRect rc = { 0,0,width,height }; + rce.setScissorRect(rc); + rce.setCullMode(MTLCullModeNone); - uint64_t state = 0 + uint64_t state = 0 | BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A | BGFX_STATE_DEPTH_TEST_ALWAYS ; - setDepthStencilState(state); + setDepthStencilState(state); - RenderPipelineState pso = getPipelineState( - state - , 0 - , fbh - , _blitter.m_vb->decl - , _blitter.m_program.idx - , 0 - ); - rce.setRenderPipelineState(pso); + PipelineStateMtl* pso = getPipelineState( + state + , 0 + , fbh + , _blitter.m_vb->layoutHandle + , _blitter.m_program + , 0 + ); + rce.setRenderPipelineState(pso->m_rps); - ProgramMtl& program = m_program[_blitter.m_program.idx]; - uint32_t vertexUniformBufferSize = program.m_vshConstantBufferSize; - uint32_t fragmentUniformBufferSize = program.m_fshConstantBufferSize; + const uint32_t vertexUniformBufferSize = pso->m_vshConstantBufferSize; + const uint32_t fragmentUniformBufferSize = pso->m_fshConstantBufferSize; - if (vertexUniformBufferSize ) - { - m_uniformBufferVertexOffset = BX_ALIGN_MASK(m_uniformBufferVertexOffset, program.m_vshConstantBufferAlignmentMask); - rce.setVertexBuffer(m_uniformBuffer, m_uniformBufferVertexOffset, 0); - } + if (vertexUniformBufferSize) + { + m_uniformBufferVertexOffset = BX_ALIGN_MASK(m_uniformBufferVertexOffset, pso->m_vshConstantBufferAlignmentMask); + rce.setVertexBuffer(m_uniformBuffer, m_uniformBufferVertexOffset, 0); + } - m_uniformBufferFragmentOffset = m_uniformBufferVertexOffset + vertexUniformBufferSize; - if (fragmentUniformBufferSize ) - { - m_uniformBufferFragmentOffset = BX_ALIGN_MASK(m_uniformBufferFragmentOffset, program.m_fshConstantBufferAlignmentMask); - rce.setFragmentBuffer(m_uniformBuffer, m_uniformBufferFragmentOffset, 0); - } + m_uniformBufferFragmentOffset = m_uniformBufferVertexOffset + vertexUniformBufferSize; - float proj[16]; - bx::mtxOrtho(proj, 0.0f, (float)width, (float)height, 0.0f, 0.0f, 1000.0f, 0.0f, false); + if (0 != fragmentUniformBufferSize) + { + m_uniformBufferFragmentOffset = BX_ALIGN_MASK(m_uniformBufferFragmentOffset, pso->m_fshConstantBufferAlignmentMask); + rce.setFragmentBuffer(m_uniformBuffer, m_uniformBufferFragmentOffset, 0); + } - PredefinedUniform& predefined = program.m_predefined[0]; - uint8_t flags = predefined.m_type; - setShaderUniform(flags, predefined.m_loc, proj, 4); + float proj[16]; + bx::mtxOrtho(proj, 0.0f, (float)width, (float)height, 0.0f, 0.0f, 1000.0f, 0.0f, false); - m_textures[_blitter.m_texture.idx].commit(0, false, true); - } + PredefinedUniform& predefined = pso->m_predefined[0]; + uint8_t flags = predefined.m_type; + setShaderUniform(flags, predefined.m_loc, proj, 4); - void blitRender(TextVideoMemBlitter& _blitter, uint32_t _numIndices) override - { - const uint32_t numVertices = _numIndices*4/6; - if (0 < numVertices) - { - m_indexBuffers [_blitter.m_ib->handle.idx].update(0, _numIndices*2, _blitter.m_ib->data, true); - m_vertexBuffers[_blitter.m_vb->handle.idx].update(0, numVertices*_blitter.m_decl.m_stride, _blitter.m_vb->data, true); + m_textures[_blitter.m_texture.idx].commit(0, false, true); VertexBufferMtl& vb = m_vertexBuffers[_blitter.m_vb->handle.idx]; - m_renderCommandEncoder.setVertexBuffer(vb.getBuffer(), 0, 1); + m_renderCommandEncoder.setVertexBuffer(vb.m_ptr, 0, 1); - m_renderCommandEncoder.drawIndexedPrimitives(MTLPrimitiveTypeTriangle, _numIndices, MTLIndexTypeUInt16, m_indexBuffers[_blitter.m_ib->handle.idx].getBuffer(), 0, 1); + m_renderCommandEncoder.drawIndexedPrimitives( + MTLPrimitiveTypeTriangle + , _numIndices + , MTLIndexTypeUInt16 + , m_indexBuffers[_blitter.m_ib->handle.idx].m_ptr + , 0 + , 1 + ); } } @@ -1107,11 +1204,16 @@ namespace bgfx { namespace mtl for (uint32_t ii = 0, num = m_numWindows; ii < num; ++ii) { FrameBufferMtl& frameBuffer = ii == 0 ? m_mainFrameBuffer : m_frameBuffers[m_windows[ii].idx]; - if (NULL != frameBuffer.m_swapChain && - frameBuffer.m_swapChain->m_drawable) + if (NULL != frameBuffer.m_swapChain + && frameBuffer.m_swapChain->m_drawableTexture) { - m_commandBuffer.presentDrawable(frameBuffer.m_swapChain->m_drawable); - MTL_RELEASE(frameBuffer.m_swapChain->m_drawable); + MTL_RELEASE(frameBuffer.m_swapChain->m_drawableTexture); + + if ( NULL != frameBuffer.m_swapChain->m_drawable) + { + m_commandBuffer.presentDrawable(frameBuffer.m_swapChain->m_drawable); + MTL_RELEASE(frameBuffer.m_swapChain->m_drawable); + } } } @@ -1157,6 +1259,7 @@ namespace bgfx { namespace mtl { MTL_RELEASE(m_screenshotBlitRenderPipelineState) reset(m_renderPipelineDescriptor); + m_renderPipelineDescriptor.colorAttachments[0].pixelFormat = m_mainFrameBuffer.m_swapChain->m_metalLayer.pixelFormat; m_renderPipelineDescriptor.vertexFunction = m_screenshotBlitProgram.m_vsh->m_function; m_renderPipelineDescriptor.fragmentFunction = m_screenshotBlitProgram.m_fsh->m_function; @@ -1165,6 +1268,14 @@ namespace bgfx { namespace mtl } } + void invalidateCompute() + { + if (m_computeCommandEncoder) + { + m_computeCommandEncoder.endEncoding(); + m_computeCommandEncoder = NULL; + } + } void updateCapture() { @@ -1251,7 +1362,7 @@ namespace bgfx { namespace mtl { g_callback->captureEnd(); BX_FREE(g_allocator, m_capture); - m_capture = NULL; + m_capture = NULL; m_captureSize = 0; } } @@ -1342,9 +1453,9 @@ namespace bgfx { namespace mtl } break; - CASE_IMPLEMENT_UNIFORM(Int1, I, int); - CASE_IMPLEMENT_UNIFORM(Vec4, F, float); - CASE_IMPLEMENT_UNIFORM(Mat4, F, float); + CASE_IMPLEMENT_UNIFORM(Sampler, I, int); + CASE_IMPLEMENT_UNIFORM(Vec4, F, float); + CASE_IMPLEMENT_UNIFORM(Mat4, F, float); case UniformType::End: break; @@ -1395,45 +1506,50 @@ namespace bgfx { namespace mtl uint32_t numMrt = 1; FrameBufferHandle fbh = m_fbh; - if (isValid(fbh) ) + if (isValid(fbh) && m_frameBuffers[fbh.idx].m_swapChain == NULL) { const FrameBufferMtl& fb = m_frameBuffers[fbh.idx]; numMrt = bx::uint32_max(1, fb.m_num); } - const ProgramMtl& program = m_program[_clearQuad.m_program[numMrt-1].idx]; - RenderPipelineState pso = getPipelineState( + const VertexLayout* layout = &_clearQuad.m_layout; + const PipelineStateMtl* pso = getPipelineState( state , 0 , fbh - , _clearQuad.m_vb->decl - , _clearQuad.m_program[numMrt-1].idx + , 1 + , &layout + , _clearQuad.m_program[numMrt-1] , 0 ); - m_renderCommandEncoder.setRenderPipelineState(pso); + m_renderCommandEncoder.setRenderPipelineState(pso->m_rps); - uint32_t fragmentUniformBufferSize = program.m_fshConstantBufferSize; + const uint32_t vertexUniformBufferSize = pso->m_vshConstantBufferSize; + const uint32_t fragmentUniformBufferSize = pso->m_fshConstantBufferSize; - m_uniformBufferFragmentOffset = m_uniformBufferVertexOffset; + if (0 != vertexUniformBufferSize) + { + m_uniformBufferVertexOffset = BX_ALIGN_MASK(m_uniformBufferVertexOffset, pso->m_vshConstantBufferAlignmentMask); + m_renderCommandEncoder.setVertexBuffer(m_uniformBuffer, m_uniformBufferVertexOffset, 0); + } + + m_uniformBufferFragmentOffset = m_uniformBufferVertexOffset + vertexUniformBufferSize; if (fragmentUniformBufferSize) { - m_uniformBufferFragmentOffset = BX_ALIGN_MASK(m_uniformBufferFragmentOffset, program.m_fshConstantBufferAlignmentMask); + m_uniformBufferFragmentOffset = BX_ALIGN_MASK(m_uniformBufferFragmentOffset, pso->m_fshConstantBufferAlignmentMask); m_renderCommandEncoder.setFragmentBuffer(m_uniformBuffer, m_uniformBufferFragmentOffset, 0); } + float mrtClearColor[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS][4]; + float mrtClearDepth[4] = { _clear.m_depth }; + if (BGFX_CLEAR_COLOR_USE_PALETTE & _clear.m_flags) { - float mrtClear[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS][4]; for (uint32_t ii = 0; ii < numMrt; ++ii) { uint8_t index = (uint8_t)bx::uint32_min(BGFX_CONFIG_MAX_COLOR_PALETTE-1, _clear.m_index[ii]); - bx::memCopy(mrtClear[ii], _palette[index], 16); + bx::memCopy(mrtClearColor[ii], _palette[index], 16); } - - bx::memCopy( (uint8_t*)m_uniformBuffer.contents() + m_uniformBufferFragmentOffset - , mrtClear - , bx::uint32_min(fragmentUniformBufferSize, sizeof(mrtClear) ) - ); } else { @@ -1445,87 +1561,82 @@ namespace bgfx { namespace mtl _clear.m_index[3]*1.0f/255.0f, }; - bx::memCopy( (uint8_t*)m_uniformBuffer.contents() + m_uniformBufferFragmentOffset - , rgba - , bx::uint32_min(fragmentUniformBufferSize, sizeof(rgba) ) - ); + for (uint32_t ii = 0; ii < numMrt; ++ii) + { + bx::memCopy( mrtClearColor[ii] + , rgba + , 16 + ); + } } - m_uniformBufferFragmentOffset += fragmentUniformBufferSize; - m_uniformBufferVertexOffset = m_uniformBufferFragmentOffset; + bx::memCopy( (uint8_t*)m_uniformBuffer.contents() + m_uniformBufferVertexOffset + , mrtClearDepth + , bx::uint32_min(vertexUniformBufferSize, sizeof(mrtClearDepth) ) + ); - const VertexBufferMtl& vb = m_vertexBuffers[_clearQuad.m_vb->handle.idx]; - const VertexDecl& vertexDecl = m_vertexDecls[_clearQuad.m_vb->decl.idx]; - const uint32_t stride = vertexDecl.m_stride; - const uint32_t offset = 0; + bx::memCopy( (uint8_t*)m_uniformBuffer.contents() + m_uniformBufferFragmentOffset + , mrtClearColor + , bx::uint32_min(fragmentUniformBufferSize, sizeof(mrtClearColor) ) + ); - { - struct Vertex - { - float m_x; - float m_y; - float m_z; - }; - Vertex* vertex = (Vertex*)_clearQuad.m_vb->data; - BX_CHECK(stride == sizeof(Vertex) - , "Stride/Vertex mismatch (stride %d, sizeof(Vertex) %d)" - , stride - , sizeof(Vertex) - ); - BX_UNUSED(stride); - - const float depth = _clear.m_depth; - - vertex->m_x = -1.0f; - vertex->m_y = -1.0f; - vertex->m_z = depth; - vertex++; - vertex->m_x = 1.0f; - vertex->m_y = -1.0f; - vertex->m_z = depth; - vertex++; - vertex->m_x = -1.0f; - vertex->m_y = 1.0f; - vertex->m_z = depth; - vertex++; - vertex->m_x = 1.0f; - vertex->m_y = 1.0f; - vertex->m_z = depth; - } + m_uniformBufferFragmentOffset += fragmentUniformBufferSize; + m_uniformBufferVertexOffset = m_uniformBufferFragmentOffset; + + const VertexBufferMtl& vb = m_vertexBuffers[_clearQuad.m_vb.idx]; - m_vertexBuffers[_clearQuad.m_vb->handle.idx].update(0, 4*_clearQuad.m_decl.m_stride, _clearQuad.m_vb->data); m_renderCommandEncoder.setCullMode(MTLCullModeNone); - m_renderCommandEncoder.setVertexBuffer(vb.getBuffer(), offset, 1); + m_renderCommandEncoder.setVertexBuffer(vb.m_ptr, 0, 1); m_renderCommandEncoder.drawPrimitives(MTLPrimitiveTypeTriangleStrip, 0, 4, 1); } - void setFrameBuffer(RenderPassDescriptor renderPassDescriptor, FrameBufferHandle _fbh, bool _msaa = true) + void setAttachment(MTLRenderPassAttachmentDescriptor* _attachmentDescriptor, const Attachment& _at, uint8_t _textureType, bool _resolve) { - if (!isValid(_fbh) || m_frameBuffers[_fbh.idx].m_swapChain) + _attachmentDescriptor.level = _at.mip; + if ( _textureType == TextureMtl::Texture3D ) + _attachmentDescriptor.depthPlane = _at.layer; + else + _attachmentDescriptor.slice = _at.layer; + + if ( _resolve ) { - SwapChainMtl* swapChain = - !isValid(_fbh) ? - m_mainFrameBuffer.m_swapChain : - m_frameBuffers[_fbh.idx].m_swapChain; - if (NULL != m_backBufferColorMsaa) + _attachmentDescriptor.resolveLevel = _at.mip; + if ( _textureType == TextureMtl::Texture3D ) + _attachmentDescriptor.resolveDepthPlane = _at.layer; + else + _attachmentDescriptor.resolveSlice = _at.layer; + } + } + + void setFrameBuffer(RenderPassDescriptor _renderPassDescriptor, FrameBufferHandle _fbh, bool _msaa = true) + { + if (!isValid(_fbh) + || m_frameBuffers[_fbh.idx].m_swapChain) + { + SwapChainMtl* swapChain = !isValid(_fbh) + ? m_mainFrameBuffer.m_swapChain + : m_frameBuffers[_fbh.idx].m_swapChain + ; + + if (NULL != swapChain->m_backBufferColorMsaa) { - renderPassDescriptor.colorAttachments[0].texture = swapChain->m_backBufferColorMsaa; - renderPassDescriptor.colorAttachments[0].resolveTexture = NULL != m_screenshotTarget + _renderPassDescriptor.colorAttachments[0].texture = swapChain->m_backBufferColorMsaa; + _renderPassDescriptor.colorAttachments[0].resolveTexture = NULL != m_screenshotTarget ? m_screenshotTarget.m_obj - : swapChain->currentDrawable().texture + : swapChain->currentDrawableTexture() ; } else { - renderPassDescriptor.colorAttachments[0].texture = NULL != m_screenshotTarget + _renderPassDescriptor.colorAttachments[0].texture = NULL != m_screenshotTarget ? m_screenshotTarget.m_obj - : swapChain->currentDrawable().texture + : swapChain->currentDrawableTexture() ; } - renderPassDescriptor.depthAttachment.texture = swapChain->m_backBufferDepth; - renderPassDescriptor.stencilAttachment.texture = swapChain->m_backBufferStencil; + _renderPassDescriptor.depthAttachment.texture = swapChain->m_backBufferDepth; + _renderPassDescriptor.stencilAttachment.texture = swapChain->m_backBufferStencil; } else { @@ -1534,35 +1645,40 @@ namespace bgfx { namespace mtl for (uint32_t ii = 0; ii < frameBuffer.m_num; ++ii) { const TextureMtl& texture = m_textures[frameBuffer.m_colorHandle[ii].idx]; - renderPassDescriptor.colorAttachments[ii].texture = texture.m_ptrMsaa + _renderPassDescriptor.colorAttachments[ii].texture = texture.m_ptrMsaa ? texture.m_ptrMsaa : texture.m_ptr ; - renderPassDescriptor.colorAttachments[ii].resolveTexture = texture.m_ptrMsaa + _renderPassDescriptor.colorAttachments[ii].resolveTexture = texture.m_ptrMsaa ? texture.m_ptr.m_obj : NULL ; + + setAttachment(_renderPassDescriptor.colorAttachments[ii], frameBuffer.m_colorAttachment[ii], texture.m_type, texture.m_ptrMsaa != NULL); } if (isValid(frameBuffer.m_depthHandle) ) { const TextureMtl& texture = m_textures[frameBuffer.m_depthHandle.idx]; - renderPassDescriptor.depthAttachment.texture = texture.m_ptrMsaa + _renderPassDescriptor.depthAttachment.texture = texture.m_ptrMsaa ? texture.m_ptrMsaa : texture.m_ptr ; - renderPassDescriptor.stencilAttachment.texture = texture.m_ptrStencil; + _renderPassDescriptor.stencilAttachment.texture = texture.m_ptrStencil; + + setAttachment(_renderPassDescriptor.depthAttachment, frameBuffer.m_depthAttachment, texture.m_type, NULL != texture.m_ptrMsaa); + setAttachment(_renderPassDescriptor.stencilAttachment, frameBuffer.m_depthAttachment, texture.m_type, NULL != texture.m_ptrMsaa); if (texture.m_textureFormat == TextureFormat::D24S8) { if (texture.m_ptr.pixelFormat() == 255 /* Depth24Unorm_Stencil8 */ || texture.m_ptr.pixelFormat() == 260 /* Depth32Float_Stencil8 */) { - renderPassDescriptor.stencilAttachment.texture = renderPassDescriptor.depthAttachment.texture; + _renderPassDescriptor.stencilAttachment.texture = _renderPassDescriptor.depthAttachment.texture; } else { - renderPassDescriptor.stencilAttachment.texture = texture.m_ptrMsaa + _renderPassDescriptor.stencilAttachment.texture = texture.m_ptrMsaa ? texture.m_ptrMsaa : texture.m_ptrStencil ; @@ -1617,10 +1733,10 @@ namespace bgfx { namespace mtl frontFaceDesc.readMask = readMask; frontFaceDesc.writeMask = writeMask; - backfaceDesc.stencilFailureOperation = s_stencilOp[(bstencil&BGFX_STENCIL_OP_FAIL_S_MASK)>>BGFX_STENCIL_OP_FAIL_S_SHIFT]; - backfaceDesc.depthFailureOperation = s_stencilOp[(bstencil&BGFX_STENCIL_OP_FAIL_Z_MASK)>>BGFX_STENCIL_OP_FAIL_Z_SHIFT]; - backfaceDesc.depthStencilPassOperation = s_stencilOp[(bstencil&BGFX_STENCIL_OP_PASS_Z_MASK)>>BGFX_STENCIL_OP_PASS_Z_SHIFT]; - backfaceDesc.stencilCompareFunction = s_cmpFunc[(bstencil&BGFX_STENCIL_TEST_MASK)>>BGFX_STENCIL_TEST_SHIFT]; + backfaceDesc.stencilFailureOperation = s_stencilOp[(bstencil&BGFX_STENCIL_OP_FAIL_S_MASK)>>BGFX_STENCIL_OP_FAIL_S_SHIFT]; + backfaceDesc.depthFailureOperation = s_stencilOp[(bstencil&BGFX_STENCIL_OP_FAIL_Z_MASK)>>BGFX_STENCIL_OP_FAIL_Z_SHIFT]; + backfaceDesc.depthStencilPassOperation = s_stencilOp[(bstencil&BGFX_STENCIL_OP_PASS_Z_MASK)>>BGFX_STENCIL_OP_PASS_Z_SHIFT]; + backfaceDesc.stencilCompareFunction = s_cmpFunc[(bstencil&BGFX_STENCIL_TEST_MASK)>>BGFX_STENCIL_TEST_SHIFT]; backfaceDesc.readMask = readMask; backfaceDesc.writeMask = writeMask; @@ -1642,13 +1758,155 @@ namespace bgfx { namespace mtl m_renderCommandEncoder.setStencilReferenceValue(ref); } - RenderPipelineState getPipelineState( + void processArguments( + PipelineStateMtl* ps + , NSArray <MTLArgument *>* _vertexArgs + , NSArray <MTLArgument *>* _fragmentArgs + ) + { + ps->m_numPredefined = 0; + + for (uint32_t shaderType = 0; shaderType < 2; ++shaderType) + { + UniformBuffer*& constantBuffer = shaderType == 0 + ? ps->m_vshConstantBuffer + : ps->m_fshConstantBuffer + ; + const int8_t fragmentBit = (1 == shaderType ? BGFX_UNIFORM_FRAGMENTBIT : 0); + + for (MTLArgument* arg in (shaderType == 0 ? _vertexArgs : _fragmentArgs) ) + { + BX_TRACE("arg: %s type:%d", utf8String(arg.name), arg.type); + + if (arg.active) + { + if (arg.type == MTLArgumentTypeBuffer + && 0 == bx::strCmp(utf8String(arg.name), SHADER_UNIFORM_NAME) ) + { + BX_CHECK( arg.index == 0, "Uniform buffer must be in the buffer slot 0."); + BX_CHECK( MTLDataTypeStruct == arg.bufferDataType, "%s's type must be a struct",SHADER_UNIFORM_NAME ); + + if (MTLDataTypeStruct == arg.bufferDataType) + { + if (shaderType == 0) + { + ps->m_vshConstantBufferSize = (uint32_t)arg.bufferDataSize; + ps->m_vshConstantBufferAlignmentMask = (uint32_t)arg.bufferAlignment - 1; + } + else + { + ps->m_fshConstantBufferSize = (uint32_t)arg.bufferDataSize; + ps->m_fshConstantBufferAlignmentMask = (uint32_t)arg.bufferAlignment - 1; + } + + for (MTLStructMember* uniform in arg.bufferStructType.members ) + { + const char* name = utf8String(uniform.name); + BX_TRACE("uniform: %s type:%d", name, uniform.dataType); + + MTLDataType dataType = uniform.dataType; + uint32_t num = 1; + + if (dataType == MTLDataTypeArray) + { + dataType = uniform.arrayType.elementType; + num = (uint32_t)uniform.arrayType.arrayLength; + } + + switch (dataType) + { + case MTLDataTypeFloat4: num *= 1; break; + case MTLDataTypeFloat4x4: num *= 4; break; + case MTLDataTypeFloat3x3: num *= 3; break; + + default: + BX_WARN(0, "Unsupported uniform MTLDataType: %d", uniform.dataType); + break; + } + + const PredefinedUniform::Enum predefined = nameToPredefinedUniformEnum(name); + + if (PredefinedUniform::Count != predefined) + { + ps->m_predefined[ps->m_numPredefined].m_loc = uint32_t(uniform.offset); + ps->m_predefined[ps->m_numPredefined].m_count = uint16_t(num); + ps->m_predefined[ps->m_numPredefined].m_type = uint8_t(predefined|fragmentBit); + ++ps->m_numPredefined; + } + else + { + const UniformRegInfo* info = s_renderMtl->m_uniformReg.find(name); + BX_WARN(NULL != info, "User defined uniform '%s' is not found, it won't be set.", name); + + if (NULL != info) + { + if (NULL == constantBuffer) + { + constantBuffer = UniformBuffer::create(1024); + } + + UniformType::Enum type = convertMtlType(dataType); + constantBuffer->writeUniformHandle( (UniformType::Enum)(type|fragmentBit), uint32_t(uniform.offset), info->m_handle, uint16_t(num) ); + BX_TRACE("store %s %d offset:%d", name, info->m_handle, uint32_t(uniform.offset) ); + } + } + } + } + } + else if ( arg.type == MTLArgumentTypeBuffer && arg.index > 0 && NULL != arg.bufferStructType) + { + const char* name = utf8String(arg.name); + + if (arg.index >= BGFX_CONFIG_MAX_TEXTURE_SAMPLERS) + { + BX_WARN(false, "Binding index is too large %d max is %d. User defined uniform '%s' won't be set.", int(arg.index - 1), BGFX_CONFIG_MAX_TEXTURE_SAMPLERS - 1, name); + } + else + { + ps->m_bindingTypes[arg.index-1] = fragmentBit ? PipelineStateMtl::BindToFragmentShader : PipelineStateMtl::BindToVertexShader; + BX_TRACE("buffer %s index:%d", name, uint32_t(arg.index-1) ); + } + } + else if (arg.type == MTLArgumentTypeTexture) + { + const char* name = utf8String(arg.name); + const UniformRegInfo* info = s_renderMtl->m_uniformReg.find(name); + BX_WARN(NULL != info, "User defined uniform '%s' is not found, it won't be set.", name); + + if (NULL != info) + { + if (arg.index >= BGFX_CONFIG_MAX_TEXTURE_SAMPLERS) + { + BX_WARN(false, "Binding index is too large %d max is %d. User defined uniform '%s' won't be set.", int(arg.index), BGFX_CONFIG_MAX_TEXTURE_SAMPLERS - 1, name); + } + else + { + ps->m_bindingTypes[arg.index] = fragmentBit ? PipelineStateMtl::BindToFragmentShader : PipelineStateMtl::BindToVertexShader; + BX_TRACE("texture %s %d index:%d", name, info->m_handle, uint32_t(arg.index) ); + } + } + } + else if (arg.type == MTLArgumentTypeSampler) + { + BX_TRACE("sampler: %s index:%d", utf8String(arg.name), arg.index); + } + } + } + + if (NULL != constantBuffer) + { + constantBuffer->finish(); + } + } + } + + PipelineStateMtl* getPipelineState( uint64_t _state , uint32_t _rgba , FrameBufferHandle _fbh , uint8_t _numStreams - , const VertexDecl** _vertexDecls - , uint16_t _programIdx + , const VertexLayout** _layouts + , ProgramHandle _program , uint8_t _numInstanceData ) { @@ -1663,7 +1921,7 @@ namespace bgfx { namespace mtl ); const bool independentBlendEnable = !!(BGFX_STATE_BLEND_INDEPENDENT & _state); - ProgramMtl& program = m_program[_programIdx]; + const ProgramMtl& program = m_program[_program.idx]; bx::HashMurmur2A murmur; murmur.begin(); @@ -1673,7 +1931,7 @@ namespace bgfx { namespace mtl if (!isValid(_fbh) ) { - murmur.add(m_backBufferPixelFormatHash); + murmur.add(m_mainFrameBuffer.m_pixelFormatHash); } else { @@ -1689,14 +1947,17 @@ namespace bgfx { namespace mtl for (uint8_t ii = 0; ii < _numStreams; ++ii) { - murmur.add(_vertexDecls[ii]->m_hash); + murmur.add(_layouts[ii]->m_hash); } uint32_t hash = murmur.end(); - RenderPipelineState pso = m_pipelineStateCache.find(hash); + PipelineStateMtl* pso = m_pipelineStateCache.find(hash); + if (NULL == pso) { + pso = BX_NEW(g_allocator, PipelineStateMtl); + RenderPipelineDescriptor pd = m_renderPipelineDescriptor; reset(pd); @@ -1704,14 +1965,18 @@ namespace bgfx { namespace mtl uint32_t frameBufferAttachment = 1; - if (!isValid(_fbh) || s_renderMtl->m_frameBuffers[_fbh.idx].m_swapChain) + if (!isValid(_fbh) + || s_renderMtl->m_frameBuffers[_fbh.idx].m_swapChain) { - SwapChainMtl* swapChain = - !isValid(_fbh) ? - s_renderMtl->m_mainFrameBuffer.m_swapChain : - s_renderMtl->m_frameBuffers[_fbh.idx].m_swapChain; - pd.sampleCount = NULL != swapChain->m_backBufferColorMsaa ? swapChain->m_backBufferColorMsaa.sampleCount() : 1; - pd.colorAttachments[0].pixelFormat = swapChain->currentDrawable().texture.pixelFormat; + SwapChainMtl* swapChain = !isValid(_fbh) + ? s_renderMtl->m_mainFrameBuffer.m_swapChain + : s_renderMtl->m_frameBuffers[_fbh.idx].m_swapChain + ; + pd.sampleCount = NULL != swapChain->m_backBufferColorMsaa + ? swapChain->m_backBufferColorMsaa.sampleCount() + : 1 + ; + pd.colorAttachments[0].pixelFormat = swapChain->currentDrawableTexture().pixelFormat; pd.depthAttachmentPixelFormat = swapChain->m_backBufferDepth.m_obj.pixelFormat; pd.stencilAttachmentPixelFormat = swapChain->m_backBufferStencil.m_obj.pixelFormat; } @@ -1817,33 +2082,38 @@ namespace bgfx { namespace mtl uint8_t stream = 0; for (; stream < _numStreams; ++stream) { - const VertexDecl& vertexDecl = *_vertexDecls[stream]; + const VertexLayout& layout = *_layouts[stream]; + bool streamUsed = false; for (uint32_t ii = 0; Attrib::Count != program.m_used[ii]; ++ii) { Attrib::Enum attr = Attrib::Enum(program.m_used[ii]); + if (attrSet[attr]) + continue; const uint32_t loc = program.m_attributes[attr]; uint8_t num; AttribType::Enum type; bool normalized; bool asInt; - vertexDecl.decode(attr, num, type, normalized, asInt); + layout.decode(attr, num, type, normalized, asInt); BX_CHECK(num <= 4, "num must be <= 4"); - if (UINT16_MAX != vertexDecl.m_attributes[attr]) + if (UINT16_MAX != layout.m_attributes[attr]) { vertexDesc.attributes[loc].format = s_attribType[type][num-1][normalized?1:0]; vertexDesc.attributes[loc].bufferIndex = stream+1; - vertexDesc.attributes[loc].offset = vertexDecl.m_offset[attr]; + vertexDesc.attributes[loc].offset = layout.m_offset[attr]; BX_TRACE("attrib: %s format: %d offset: %d", s_attribName[attr], (int)vertexDesc.attributes[loc].format, (int)vertexDesc.attributes[loc].offset); attrSet[attr] = true; + streamUsed = true; } } - - vertexDesc.layouts[stream+1].stride = vertexDecl.getStride(); - vertexDesc.layouts[stream+1].stepFunction = MTLVertexStepFunctionPerVertex; + if (streamUsed) { + vertexDesc.layouts[stream+1].stride = layout.getStride(); + vertexDesc.layouts[stream+1].stepFunction = MTLVertexStepFunctionPerVertex; + } } for (uint32_t ii = 0; Attrib::Count != program.m_used[ii]; ++ii) @@ -1875,169 +2145,67 @@ namespace bgfx { namespace mtl pd.vertexDescriptor = vertexDesc; - if (program.m_processedUniforms) { - pso = m_device.newRenderPipelineStateWithDescriptor(pd); - } - else - { - program.m_numPredefined = 0; RenderPipelineReflection reflection = NULL; - pso = m_device.newRenderPipelineStateWithDescriptor(pd, MTLPipelineOptionBufferTypeInfo, &reflection); + pso->m_rps = m_device.newRenderPipelineStateWithDescriptor(pd, MTLPipelineOptionBufferTypeInfo, &reflection); if (NULL != reflection) { - for (uint32_t shaderType = 0; shaderType < 2; ++shaderType) - { - UniformBuffer*& constantBuffer = shaderType == 0 - ? program.m_vshConstantBuffer - : program.m_fshConstantBuffer - ; - uint8_t fragmentBit = (1 == shaderType ? BGFX_UNIFORM_FRAGMENTBIT : 0); - - for (MTLArgument* arg in (shaderType == 0 ? reflection.vertexArguments : reflection.fragmentArguments) ) - { - BX_TRACE("arg: %s type:%d", utf8String(arg.name), arg.type); - if (arg.active) - { - if (arg.type == MTLArgumentTypeBuffer - && 0 == bx::strCmp(utf8String(arg.name), SHADER_UNIFORM_NAME) ) - { - BX_CHECK( arg.index == 0, "Uniform buffer must be in the buffer slot 0."); - BX_CHECK( MTLDataTypeStruct == arg.bufferDataType, "%s's type must be a struct",SHADER_UNIFORM_NAME ); - - if (MTLDataTypeStruct == arg.bufferDataType) - { - if (shaderType == 0) - { - program.m_vshConstantBufferSize = (uint32_t)arg.bufferDataSize; - program.m_vshConstantBufferAlignmentMask = (uint32_t)arg.bufferAlignment - 1; - } - else - { - program.m_fshConstantBufferSize = (uint32_t)arg.bufferDataSize; - program.m_fshConstantBufferAlignmentMask = (uint32_t)arg.bufferAlignment - 1; - } - - for (MTLStructMember* uniform in arg.bufferStructType.members ) - { - const char* name = utf8String(uniform.name); - BX_TRACE("uniform: %s type:%d", name, uniform.dataType); - - MTLDataType dataType = uniform.dataType; - uint32_t num = 1; - - if (dataType == MTLDataTypeArray) - { - dataType = uniform.arrayType.elementType; - num = (uint32_t)uniform.arrayType.arrayLength; - } - - switch (dataType) - { - case MTLDataTypeFloat4: num *= 1; break; - case MTLDataTypeFloat4x4: num *= 4; break; - case MTLDataTypeFloat3x3: num *= 3; break; - - default: - BX_WARN(0, "Unsupported uniform MTLDataType: %d", uniform.dataType); - break; - } - - PredefinedUniform::Enum predefined = nameToPredefinedUniformEnum(name); - if (PredefinedUniform::Count != predefined) - { - program.m_predefined[program.m_numPredefined].m_loc = uint32_t(uniform.offset); - program.m_predefined[program.m_numPredefined].m_count = uint16_t(num); - program.m_predefined[program.m_numPredefined].m_type = uint8_t(predefined|fragmentBit); - ++program.m_numPredefined; - } - else - { - const UniformRegInfo* info = m_uniformReg.find(name); - BX_WARN(NULL != info, "User defined uniform '%s' is not found, it won't be set.", name); - - if (NULL != info) - { - if (NULL == constantBuffer) - { - constantBuffer = UniformBuffer::create(1024); - } - - UniformType::Enum type = convertMtlType(dataType); - constantBuffer->writeUniformHandle( (UniformType::Enum)(type|fragmentBit), uint32_t(uniform.offset), info->m_handle, uint16_t(num) ); - BX_TRACE("store %s %d offset:%d", name, info->m_handle, uint32_t(uniform.offset) ); - } - } - } - } - } - else if (arg.type == MTLArgumentTypeTexture) - { - const char* name = utf8String(arg.name); - const UniformRegInfo* info = m_uniformReg.find(name); - BX_WARN(NULL != info, "User defined uniform '%s' is not found, it won't be set.", name); - - if (NULL != info) - { - if (program.m_samplerCount >= BGFX_CONFIG_MAX_TEXTURE_SAMPLERS) - { - BX_WARN(NULL != info, "Too many samplers in shader(only %d is supported). User defined uniform '%s' won't be set.", BGFX_CONFIG_MAX_TEXTURE_SAMPLERS, name); - } - else - { - program.m_samplers[program.m_samplerCount].m_index = uint32_t(arg.index); - program.m_samplers[program.m_samplerCount].m_uniform = info->m_handle; - program.m_samplers[program.m_samplerCount].m_fragment = fragmentBit ? 1 : 0; - ++program.m_samplerCount; - BX_TRACE("texture %s %d index:%d", name, info->m_handle, uint32_t(arg.index) ); - } - } - } - else if (arg.type == MTLArgumentTypeSampler) - { - BX_TRACE("sampler: %s index:%d", utf8String(arg.name), arg.index); - } - } - } - - if (NULL != constantBuffer) - { - constantBuffer->finish(); - } - } + processArguments(pso, reflection.vertexArguments, reflection.fragmentArguments); } - - program.m_processedUniforms = true; } m_pipelineStateCache.add(hash, pso); + m_pipelineProgram.push_back({hash, _program}); } return pso; } - RenderPipelineState getPipelineState( + PipelineStateMtl* getPipelineState( uint64_t _state , uint32_t _rgba , FrameBufferHandle _fbh - , VertexDeclHandle _declHandle - , uint16_t _programIdx + , VertexLayoutHandle _layoutHandle + , ProgramHandle _program , uint16_t _numInstanceData ) { - const VertexDecl* decl = &m_vertexDecls[_declHandle.idx]; + const VertexLayout* layout = &m_vertexLayouts[_layoutHandle.idx]; return getPipelineState( _state , _rgba , _fbh , 1 - , &decl - , _programIdx + , &layout + , _program , _numInstanceData ); } + PipelineStateMtl* getComputePipelineState(ProgramHandle _program) + { + ProgramMtl& program = m_program[_program.idx]; + + if (NULL == program.m_computePS) + { + PipelineStateMtl* pso = BX_NEW(g_allocator, PipelineStateMtl); + program.m_computePS = pso; + + ComputePipelineReflection reflection = NULL; + pso->m_cps = m_device.newComputePipelineStateWithFunction(program.m_vsh->m_function, MTLPipelineOptionBufferTypeInfo, &reflection); + processArguments(pso, reflection.arguments, NULL); + + for (uint32_t ii = 0; ii < 3; ++ii) + { + pso->m_numThreads[ii] = program.m_vsh->m_numThreads[ii]; + } + } + + return program.m_computePS; + } + + SamplerState getSamplerState(uint32_t _flags) { _flags &= BGFX_SAMPLER_BITS_MASK; @@ -2045,20 +2213,19 @@ namespace bgfx { namespace mtl if (NULL == sampler) { - m_samplerDescriptor.sAddressMode = s_textureAddress[(_flags&BGFX_SAMPLER_U_MASK)>>BGFX_SAMPLER_U_SHIFT]; m_samplerDescriptor.tAddressMode = s_textureAddress[(_flags&BGFX_SAMPLER_V_MASK)>>BGFX_SAMPLER_V_SHIFT]; m_samplerDescriptor.rAddressMode = s_textureAddress[(_flags&BGFX_SAMPLER_W_MASK)>>BGFX_SAMPLER_W_SHIFT]; - m_samplerDescriptor.minFilter = s_textureFilterMinMag[(_flags&BGFX_SAMPLER_MIN_MASK)>>BGFX_SAMPLER_MIN_SHIFT]; - m_samplerDescriptor.magFilter = s_textureFilterMinMag[(_flags&BGFX_SAMPLER_MAG_MASK)>>BGFX_SAMPLER_MAG_SHIFT]; - m_samplerDescriptor.mipFilter = s_textureFilterMip[(_flags&BGFX_SAMPLER_MIP_MASK)>>BGFX_SAMPLER_MIP_SHIFT]; - m_samplerDescriptor.lodMinClamp = 0; - m_samplerDescriptor.lodMaxClamp = FLT_MAX; + m_samplerDescriptor.minFilter = s_textureFilterMinMag[(_flags&BGFX_SAMPLER_MIN_MASK)>>BGFX_SAMPLER_MIN_SHIFT]; + m_samplerDescriptor.magFilter = s_textureFilterMinMag[(_flags&BGFX_SAMPLER_MAG_MASK)>>BGFX_SAMPLER_MAG_SHIFT]; + m_samplerDescriptor.mipFilter = s_textureFilterMip[(_flags&BGFX_SAMPLER_MIP_MASK)>>BGFX_SAMPLER_MIP_SHIFT]; + m_samplerDescriptor.lodMinClamp = 0; + m_samplerDescriptor.lodMaxClamp = FLT_MAX; m_samplerDescriptor.normalizedCoordinates = TRUE; m_samplerDescriptor.maxAnisotropy = (0 != (_flags & (BGFX_SAMPLER_MIN_ANISOTROPIC|BGFX_SAMPLER_MAG_ANISOTROPIC) ) ) ? m_mainFrameBuffer.m_swapChain->m_maxAnisotropy : 1; if (m_macOS11Runtime - || [m_device supportsFeatureSet:(MTLFeatureSet)4 /*MTLFeatureSet_iOS_GPUFamily3_v1*/]) + || [m_device supportsFeatureSet:(MTLFeatureSet)4 /*MTLFeatureSet_iOS_GPUFamily3_v1*/]) { const uint32_t cmpFunc = (_flags&BGFX_SAMPLER_COMPARE_MASK)>>BGFX_SAMPLER_COMPARE_SHIFT; m_samplerDescriptor.compareFunction = 0 == cmpFunc @@ -2082,9 +2249,11 @@ namespace bgfx { namespace mtl BlitCommandEncoder getBlitCommandEncoder() { - if (m_blitCommandEncoder == NULL) + if (NULL == m_blitCommandEncoder) { - if (m_commandBuffer == NULL) + endEncoding(); + + if (NULL == m_commandBuffer) { m_commandBuffer = m_cmd.alloc(); } @@ -2095,15 +2264,25 @@ namespace bgfx { namespace mtl return m_blitCommandEncoder; } - id<CAMetalDrawable> currentDrawable() + void endEncoding() { - if (m_drawable == nil) + if (0 != m_renderCommandEncoder) { - m_drawable = m_metalLayer.nextDrawable; - retain(m_drawable); // keep alive to be useable at 'flip' + m_renderCommandEncoder.endEncoding(); + m_renderCommandEncoder = 0; + } + + if (0 != m_computeCommandEncoder) + { + m_computeCommandEncoder.endEncoding(); + m_computeCommandEncoder = 0; } - return m_drawable; + if (0 != m_blitCommandEncoder) + { + m_blitCommandEncoder.endEncoding(); + m_blitCommandEncoder = 0; + } } Device m_device; @@ -2111,13 +2290,6 @@ namespace bgfx { namespace mtl TimerQueryMtl m_gpuTimer; CommandQueueMtl m_cmd; - CAMetalLayer* m_metalLayer; - Texture m_backBufferColorMsaa; - Texture m_backBufferDepth; - Texture m_backBufferStencil; - uint32_t m_backBufferPixelFormatHash; - uint32_t m_maxAnisotropy; - bool m_iOS9Runtime; bool m_macOS11Runtime; bool m_hasPixelFormatDepth32Float_Stencil8; @@ -2139,13 +2311,23 @@ namespace bgfx { namespace mtl TextureMtl m_textures[BGFX_CONFIG_MAX_TEXTURES]; FrameBufferMtl m_mainFrameBuffer; FrameBufferMtl m_frameBuffers[BGFX_CONFIG_MAX_FRAME_BUFFERS]; - VertexDecl m_vertexDecls[BGFX_CONFIG_MAX_VERTEX_DECLS]; + VertexLayout m_vertexLayouts[BGFX_CONFIG_MAX_VERTEX_LAYOUTS]; UniformRegistry m_uniformReg; void* m_uniforms[BGFX_CONFIG_MAX_UNIFORMS]; - StateCacheT<RenderPipelineState> m_pipelineStateCache; - StateCacheT<DepthStencilState> m_depthStencilStateCache; - StateCacheT<SamplerState> m_samplerStateCache; + struct PipelineProgram + { + uint64_t key; + ProgramHandle program; + }; + + typedef stl::vector<PipelineProgram> PipelineProgramArray; + + PipelineProgramArray m_pipelineProgram; + + StateCacheT<PipelineStateMtl*> m_pipelineStateCache; + StateCacheT<DepthStencilState> m_depthStencilStateCache; + StateCacheT<SamplerState> m_samplerStateCache; TextVideoMem m_textVideoMem; @@ -2166,7 +2348,6 @@ namespace bgfx { namespace mtl SamplerDescriptor m_samplerDescriptor; // currently active objects data - id <CAMetalDrawable> m_drawable; bool m_saveScreenshot; Texture m_screenshotTarget; ShaderMtl m_screenshotBlitProgramVsh; @@ -2174,11 +2355,11 @@ namespace bgfx { namespace mtl ProgramMtl m_screenshotBlitProgram; RenderPipelineState m_screenshotBlitRenderPipelineState; - CommandBuffer m_commandBuffer; - CommandBuffer m_prevCommandBuffer; - BlitCommandEncoder m_blitCommandEncoder; - RenderCommandEncoder m_renderCommandEncoder; - FrameBufferHandle m_renderCommandEncoderFrameBufferHandle; + CommandBuffer m_commandBuffer; + BlitCommandEncoder m_blitCommandEncoder; + RenderCommandEncoder m_renderCommandEncoder; + ComputeCommandEncoder m_computeCommandEncoder; + FrameBufferHandle m_renderCommandEncoderFrameBufferHandle; }; RendererContextI* rendererCreate(const Init& _init) @@ -2255,6 +2436,14 @@ namespace bgfx { namespace mtl bx::read(&reader, regCount); } + if (isShaderType(magic, 'C')) + { + for (uint32_t ii = 0; ii < 3; ++ii) + { + bx::read(&reader, m_numThreads[ii]); + } + } + uint32_t shaderSize; bx::read(&reader, shaderSize); @@ -2335,91 +2524,63 @@ namespace bgfx { namespace mtl { m_vsh = NULL; m_fsh = NULL; - - if (NULL != m_vshConstantBuffer) - { - UniformBuffer::destroy(m_vshConstantBuffer); - m_vshConstantBuffer = NULL; - } - - if (NULL != m_fshConstantBuffer) + if ( NULL != m_computePS ) { - UniformBuffer::destroy(m_fshConstantBuffer); - m_fshConstantBuffer = NULL; + BX_DELETE(g_allocator, m_computePS); + m_computePS = NULL; } - - m_vshConstantBufferSize = 0; - m_vshConstantBufferAlignmentMask = 0; - m_fshConstantBufferSize = 0; - m_fshConstantBufferAlignmentMask = 0; - - m_samplerCount = 0; - m_processedUniforms = false; - m_numPredefined = 0; } void BufferMtl::create(uint32_t _size, void* _data, uint16_t _flags, uint16_t _stride, bool _vertex) { - BX_UNUSED(_stride, _vertex); + BX_UNUSED(_stride); m_size = _size; m_flags = _flags; - m_dynamic = (NULL == _data); + m_vertex = _vertex; if (NULL == _data) { - for (uint32_t ii = 0; ii < MTL_MAX_FRAMES_IN_FLIGHT; ++ii) - { - m_buffers[ii] = s_renderMtl->m_device.newBufferWithLength(_size, 0); - } + m_ptr = s_renderMtl->m_device.newBufferWithLength(_size, 0); } else { - m_buffers[0] = s_renderMtl->m_device.newBufferWithBytes(_data, _size, 0); + m_ptr = s_renderMtl->m_device.newBufferWithBytes(_data, _size, 0); } } void BufferMtl::update(uint32_t _offset, uint32_t _size, void* _data, bool _discard) { - BX_UNUSED(_discard); + BlitCommandEncoder bce = s_renderMtl->getBlitCommandEncoder(); - if (m_dynamic - && _discard) + if (!m_vertex && !_discard) { - m_bufferIndex = (m_bufferIndex + 1) % MTL_MAX_FRAMES_IN_FLIGHT; - bx::memCopy( (uint8_t*)getBuffer().contents() + _offset, _data, _size); - } - else if (NULL != s_renderMtl->m_renderCommandEncoder) - { - s_renderMtl->m_cmd.release(m_buffers[m_bufferIndex]); - - if (_offset == 0 - && _size == m_size) + if ( m_dynamic == NULL ) { - m_buffers[m_bufferIndex] = s_renderMtl->m_device.newBufferWithBytes(_data, _size, 0); - } - else - { - const void* oldContent = m_buffers[m_bufferIndex].contents(); - m_buffers[m_bufferIndex] = s_renderMtl->m_device.newBufferWithBytes(oldContent, m_size, 0); - bx::memCopy( (uint8_t*)m_buffers[m_bufferIndex].contents() + _offset, _data, _size); + m_dynamic = (uint8_t*)BX_ALLOC(g_allocator, m_size); } + + bx::memCopy(m_dynamic + _offset, _data, _size); + uint32_t start = _offset & 4; + uint32_t end = bx::strideAlign(_offset + _size, 4); + + Buffer temp = s_renderMtl->m_device.newBufferWithBytes(m_dynamic, end - start, 0); + bce.copyFromBuffer(temp, 0, m_ptr, start, end - start); + s_renderMtl->m_cmd.release(temp); } else { - BlitCommandEncoder bce = s_renderMtl->getBlitCommandEncoder(); - Buffer temp = s_renderMtl->m_device.newBufferWithBytes(_data, _size, 0); - bce.copyFromBuffer(temp, 0, getBuffer(), _offset, _size); - release(temp); + bce.copyFromBuffer(temp, 0, m_ptr, _offset, _size); + s_renderMtl->m_cmd.release(temp); } } - void VertexBufferMtl::create(uint32_t _size, void* _data, VertexDeclHandle _declHandle, uint16_t _flags) + void VertexBufferMtl::create(uint32_t _size, void* _data, VertexLayoutHandle _layoutHandle, uint16_t _flags) { - m_decl = _declHandle; - uint16_t stride = isValid(_declHandle) - ? s_renderMtl->m_vertexDecls[_declHandle.idx].m_stride + m_layoutHandle = _layoutHandle; + uint16_t stride = isValid(_layoutHandle) + ? s_renderMtl->m_vertexLayouts[_layoutHandle.idx].m_stride : 0 ; @@ -2434,18 +2595,26 @@ namespace bgfx { namespace mtl if (bimg::imageParse(imageContainer, _mem->data, _mem->size) ) { - uint8_t numMips = imageContainer.m_numMips; - const uint8_t startLod = uint8_t(bx::uint32_min(_skip, numMips-1) ); - numMips -= startLod; const bimg::ImageBlockInfo& blockInfo = getBlockInfo(bimg::TextureFormat::Enum(imageContainer.m_format) ); - const uint32_t textureWidth = bx::uint32_max(blockInfo.blockWidth, imageContainer.m_width >>startLod); - const uint32_t textureHeight = bx::uint32_max(blockInfo.blockHeight, imageContainer.m_height>>startLod); - const uint16_t numLayers = imageContainer.m_numLayers; + const uint8_t startLod = bx::min<uint8_t>(_skip, imageContainer.m_numMips-1); + + bimg::TextureInfo ti; + bimg::imageGetSize( + &ti + , uint16_t(imageContainer.m_width >>startLod) + , uint16_t(imageContainer.m_height>>startLod) + , uint16_t(imageContainer.m_depth >>startLod) + , imageContainer.m_cubeMap + , 1 < imageContainer.m_numMips + , imageContainer.m_numLayers + , imageContainer.m_format + ); + ti.numMips = bx::min<uint8_t>(imageContainer.m_numMips-startLod, ti.numMips); m_flags = _flags; - m_width = textureWidth; - m_height = textureHeight; - m_depth = imageContainer.m_depth; + m_width = ti.width; + m_height = ti.height; + m_depth = ti.depth; m_requestedFormat = uint8_t(imageContainer.m_format); m_textureFormat = uint8_t(getViableTextureFormat(imageContainer) ); const bool convert = m_textureFormat != m_requestedFormat; @@ -2453,7 +2622,7 @@ namespace bgfx { namespace mtl TextureDescriptor desc = s_renderMtl->m_textureDescriptor; - if (1 < numLayers) + if (1 < ti.numLayers) { if (imageContainer.m_cubeMap) { @@ -2471,7 +2640,7 @@ namespace bgfx { namespace mtl desc.textureType = MTLTextureTypeCube; m_type = TextureCube; } - else if (imageContainer.m_depth > 1) + else if (1 < imageContainer.m_depth) { desc.textureType = MTLTextureType3D; m_type = Texture3D; @@ -2482,8 +2651,8 @@ namespace bgfx { namespace mtl m_type = Texture2D; } - m_numMips = numMips; - const uint16_t numSides = numLayers * (imageContainer.m_cubeMap ? 6 : 1); + m_numMips = ti.numMips; + const uint16_t numSides = ti.numLayers * (imageContainer.m_cubeMap ? 6 : 1); const bool compressed = bimg::isCompressed(bimg::TextureFormat::Enum(m_textureFormat) ); const bool writeOnly = 0 != (_flags&BGFX_TEXTURE_RT_WRITE_ONLY); const bool computeWrite = 0 != (_flags&BGFX_TEXTURE_COMPUTE_WRITE); @@ -2494,18 +2663,18 @@ namespace bgfx { namespace mtl , this - s_renderMtl->m_textures , getName( (TextureFormat::Enum)m_textureFormat) , getName( (TextureFormat::Enum)m_requestedFormat) - , numLayers - , textureWidth - , textureHeight + , ti.numLayers + , ti.width + , ti.height , imageContainer.m_cubeMap ? "x6" : "" - , renderTarget ? 'x' : '.' - , writeOnly ? 'x' : '.' - , computeWrite ? 'x' : '.' - , srgb ? 'x' : '.' + , renderTarget ? 'x' : ' ' + , writeOnly ? 'x' : ' ' + , computeWrite ? 'x' : ' ' + , srgb ? 'x' : ' ' ); const uint32_t msaaQuality = bx::uint32_satsub( (_flags&BGFX_TEXTURE_RT_MSAA_MASK)>>BGFX_TEXTURE_RT_MSAA_SHIFT, 1); - int sampleCount = s_msaa[msaaQuality]; + const int32_t sampleCount = s_msaa[msaaQuality]; MTLPixelFormat format = MTLPixelFormatInvalid; if (srgb) @@ -2524,14 +2693,15 @@ namespace bgfx { namespace mtl } desc.pixelFormat = format; - desc.width = textureWidth; - desc.height = textureHeight; + desc.width = ti.width; + desc.height = ti.height; desc.depth = bx::uint32_max(1,imageContainer.m_depth); - desc.mipmapLevelCount = numMips; + desc.mipmapLevelCount = ti.numMips; desc.sampleCount = 1; - desc.arrayLength = numLayers; + desc.arrayLength = ti.numLayers; - if (s_renderMtl->m_iOS9Runtime || s_renderMtl->m_macOS11Runtime) + if (s_renderMtl->m_iOS9Runtime + || s_renderMtl->m_macOS11Runtime) { desc.cpuCacheMode = MTLCPUCacheModeDefaultCache; @@ -2582,20 +2752,20 @@ namespace bgfx { namespace mtl uint8_t* temp = NULL; if (convert) { - temp = (uint8_t*)BX_ALLOC(g_allocator, textureWidth*textureHeight*4); + temp = (uint8_t*)BX_ALLOC(g_allocator, ti.width*ti.height*4); } for (uint8_t side = 0; side < numSides; ++side) { - uint32_t width = textureWidth; - uint32_t height = textureHeight; - uint32_t depth = imageContainer.m_depth; + uint32_t width = ti.width; + uint32_t height = ti.height; + uint32_t depth = ti.depth; - for (uint8_t lod = 0, num = numMips; lod < num; ++lod) + for (uint8_t lod = 0, num = ti.numMips; lod < num; ++lod) { - width = bx::uint32_max(1, width); - height = bx::uint32_max(1, height); - depth = bx::uint32_max(1, depth); + width = bx::max(1u, width); + height = bx::max(1u, height); + depth = bx::max(1u, depth); bimg::ImageMip mip; if (bimg::imageGetRawData(imageContainer, side, lod+startLod, _mem->data, _mem->size, mip) ) @@ -2668,8 +2838,8 @@ namespace bgfx { namespace mtl const uint32_t bpp = bimg::getBitsPerPixel(bimg::TextureFormat::Enum(m_textureFormat) ); const uint32_t rectpitch = _rect.m_width*bpp/8; const uint32_t srcpitch = UINT16_MAX == _pitch ? rectpitch : _pitch; - const uint32_t slice = ( (m_type == Texture3D) ? 0 : _side + _z * (m_type == TextureCube ? 6 : 1) ); - const uint16_t z = (m_type == Texture3D) ? _z : 0 ; + const uint32_t slice = ( (m_type == Texture3D) ? 0 : _side + _z * (m_type == TextureCube ? 6 : 1) ); + const uint16_t zz = (m_type == Texture3D) ? _z : 0 ; const bool convert = m_textureFormat != m_requestedFormat; @@ -2697,7 +2867,7 @@ namespace bgfx { namespace mtl MTLRegion region = { - { _rect.m_x, _rect.m_y, z }, + { _rect.m_x, _rect.m_y, zz }, { _rect.m_width, _rect.m_height, _depth }, }; @@ -2728,7 +2898,7 @@ namespace bgfx { namespace mtl , m_ptr , slice , _mip - , MTLOriginMake(_rect.m_x, _rect.m_y, z) + , MTLOriginMake(_rect.m_x, _rect.m_y, zz) ); release(tempBuffer); } @@ -2764,13 +2934,54 @@ namespace bgfx { namespace mtl } } + Texture TextureMtl::getTextureMipLevel(int _mip) + { + if (_mip >= 0 + && _mip < m_numMips + && NULL != m_ptr) + { + if (NULL == m_ptrMips[_mip]) + { + if (TextureCube == m_type) + { + m_ptrMips[_mip] = m_ptr.newTextureViewWithPixelFormat( + m_ptr.pixelFormat() + , MTLTextureType2DArray + , NSMakeRange(_mip,1) + , NSMakeRange(0,m_ptr.arrayLength() * 6) + ); + } + else + { + m_ptrMips[_mip] = m_ptr.newTextureViewWithPixelFormat( + m_ptr.pixelFormat() + , m_ptr.textureType() + , NSMakeRange(_mip,1) + , NSMakeRange(0,m_ptr.arrayLength()) + ); + } + } + + return m_ptrMips[_mip]; + } + + return 0; + } + SwapChainMtl::~SwapChainMtl() { + MTL_RELEASE(m_metalLayer); + MTL_RELEASE(m_drawable); + MTL_RELEASE(m_drawableTexture); + MTL_RELEASE(m_backBufferDepth); - if (BX_ENABLED(BX_PLATFORM_IOS) ) + MTL_RELEASE(m_backBufferStencil); + + if (NULL != m_backBufferColorMsaa) { - MTL_RELEASE(m_backBufferStencil); + MTL_RELEASE(m_backBufferColorMsaa); } + } void SwapChainMtl::init(void* _nwh) @@ -2793,7 +3004,7 @@ namespace bgfx { namespace mtl if (NULL == metalLayer || ![metalLayer isKindOfClass:NSClassFromString(@"CAMetalLayer")]) { - BX_WARN(NULL != metalLayer, "Unable to create Metal device. Please set platform data window to a CAMetalLayer"); + BX_WARN(false, "Unable to create Metal device. Please set platform data window to a CAMetalLayer"); return; } @@ -2809,10 +3020,34 @@ namespace bgfx { namespace mtl } else { - NSWindow* nsWindow = (NSWindow*)_nwh; - [nsWindow.contentView setWantsLayer:YES]; - m_metalLayer = [CAMetalLayer layer]; - [nsWindow.contentView setLayer:m_metalLayer]; + NSView *contentView; + + if ([nvh isKindOfClass:[NSView class]]) + { + contentView = (NSView*)nvh; + } + else if ([nvh isKindOfClass:[NSWindow class]]) + { + NSWindow* nsWindow = (NSWindow*)nvh; + contentView = [nsWindow contentView]; + } + else + { + BX_WARN(0, "Unable to create Metal device. Please set platform data window to an NSWindow, NSView, or CAMetalLayer"); + return; + } + + CALayer* layer = contentView.layer; + if(NULL != layer && [layer isKindOfClass:NSClassFromString(@"CAMetalLayer")]) + { + m_metalLayer = (CAMetalLayer*)layer; + } + else + { + [contentView setWantsLayer:YES]; + m_metalLayer = [CAMetalLayer layer]; + [contentView setLayer:m_metalLayer]; + } } } #endif // BX_PLATFORM_* @@ -2827,15 +3062,22 @@ namespace bgfx { namespace mtl m_metalLayer.device = s_renderMtl->m_device; m_metalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm; m_metalLayer.magnificationFilter = kCAFilterNearest; + + retain(m_metalLayer); } void SwapChainMtl::resize(FrameBufferMtl &_frameBuffer, uint32_t _width, uint32_t _height, uint32_t _flags) { - int sampleCount = s_msaa[(_flags&BGFX_RESET_MSAA_MASK)>>BGFX_RESET_MSAA_SHIFT]; - -#if BX_PLATFORM_OSX > 101300 - m_metalLayer.displaySyncEnabled = 0 != (_flags&BGFX_RESET_VSYNC); -#endif // BX_PLATFORM_OSX > 101300 + const int32_t sampleCount = s_msaa[(_flags&BGFX_RESET_MSAA_MASK)>>BGFX_RESET_MSAA_SHIFT]; + +#if BX_PLATFORM_OSX +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 + if (@available(macOS 10.13, *)) + { + m_metalLayer.displaySyncEnabled = 0 != (_flags&BGFX_RESET_VSYNC); + } +#endif // __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 +#endif // BX_PLATFORM_OSX m_metalLayer.drawableSize = CGSizeMake(_width, _height); m_metalLayer.pixelFormat = (_flags & BGFX_RESET_SRGB_BACKBUFFER) @@ -2894,7 +3136,7 @@ namespace bgfx { namespace mtl m_backBufferStencil = s_renderMtl->m_device.newTextureWithDescriptor(desc); } - if ( sampleCount > 1 ) + if (sampleCount > 1) { if (NULL != m_backBufferColorMsaa) { @@ -2908,35 +3150,67 @@ namespace bgfx { namespace mtl bx::HashMurmur2A murmur; murmur.begin(); murmur.add(1); - murmur.add((uint32_t)m_metalLayer.pixelFormat); - murmur.add((uint32_t)m_backBufferDepth.pixelFormat()); - murmur.add((uint32_t)m_backBufferStencil.pixelFormat()); - murmur.add((uint32_t)sampleCount); + murmur.add( (uint32_t)m_metalLayer.pixelFormat); + murmur.add( (uint32_t)m_backBufferDepth.pixelFormat()); + murmur.add( (uint32_t)m_backBufferStencil.pixelFormat()); + murmur.add( (uint32_t)sampleCount); _frameBuffer.m_pixelFormatHash = murmur.end(); } - id<CAMetalDrawable> SwapChainMtl::currentDrawable() + id <MTLTexture> SwapChainMtl::currentDrawableTexture() { - if (m_drawable == nil) + if (NULL == m_drawableTexture) { m_drawable = m_metalLayer.nextDrawable; - retain(m_drawable); // keep alive to be useable at 'flip' + if (m_drawable != NULL) + { + m_drawableTexture = m_drawable.texture; + retain(m_drawableTexture); + retain(m_drawable); // keep alive to be useable at 'flip' + } + else + { + TextureDescriptor desc = s_renderMtl->m_textureDescriptor; + desc.textureType = MTLTextureType2D; + desc.pixelFormat = m_metalLayer.pixelFormat; + desc.width = m_metalLayer.drawableSize.width; + desc.height = m_metalLayer.drawableSize.height; + desc.depth = 1; + desc.mipmapLevelCount = 1; + desc.sampleCount = 1; + desc.arrayLength = 1; + + if (s_renderMtl->m_iOS9Runtime + || s_renderMtl->m_macOS11Runtime) + { + desc.cpuCacheMode = MTLCPUCacheModeDefaultCache; + desc.storageMode = BX_ENABLED(BX_PLATFORM_IOS) + ? (MTLStorageMode)0 // MTLStorageModeShared + : (MTLStorageMode)1 // MTLStorageModeManaged + ; + + desc.usage = MTLTextureUsageRenderTarget; + } + + m_drawableTexture = s_renderMtl->m_device.newTextureWithDescriptor(desc); + } } - return m_drawable; + return m_drawableTexture; } void FrameBufferMtl::create(uint8_t _num, const Attachment* _attachment) { m_swapChain = NULL; - m_denseIdx = UINT16_MAX; - m_num = 0; - m_width = 0; - m_height = 0; + m_denseIdx = UINT16_MAX; + m_num = 0; + m_width = 0; + m_height = 0; for (uint32_t ii = 0; ii < _num; ++ii) { - TextureHandle handle = _attachment[ii].handle; + const Attachment& at = _attachment[ii]; + TextureHandle handle = at.handle; if (isValid(handle) ) { @@ -2951,10 +3225,12 @@ namespace bgfx { namespace mtl if (bimg::isDepth(bimg::TextureFormat::Enum(texture.m_textureFormat) ) ) { m_depthHandle = handle; + m_depthAttachment = at; } else { m_colorHandle[m_num] = handle; + m_colorAttachment[m_num] = at; m_num++; } } @@ -2994,8 +3270,10 @@ namespace bgfx { namespace mtl { BX_UNUSED(_format, _depthFormat); m_swapChain = BX_NEW(g_allocator, SwapChainMtl); + m_num = 0; m_width = _width; m_height = _height; + m_nwh = _nwh; m_denseIdx = _denseIdx; m_swapChain->init(_nwh); @@ -3014,6 +3292,7 @@ namespace bgfx { namespace mtl } m_num = 0; + m_nwh = NULL; m_depthHandle.idx = kInvalidHandle; uint16_t denseIdx = m_denseIdx; @@ -3041,7 +3320,7 @@ namespace bgfx { namespace mtl return m_activeCommandBuffer; } - static void commandBufferFinishedCallback(void* _data) + inline void commandBufferFinishedCallback(void* _data) { CommandQueueMtl* queue = (CommandQueueMtl*)_data; @@ -3123,6 +3402,17 @@ namespace bgfx { namespace mtl { } + uint32_t TimerQueryMtl::begin(uint32_t _resultIdx) + { + BX_UNUSED(_resultIdx); + return 0; + } + + void TimerQueryMtl::end(uint32_t _idx) + { + BX_UNUSED(_idx); + } + static void setTimestamp(void* _data) { *( (int64_t*)_data) = bx::getHPCounter(); @@ -3135,10 +3425,10 @@ namespace bgfx { namespace mtl m_control.consume(1); } - uint32_t offset = m_control.m_current * 2 + 0; + uint32_t offset = m_control.m_current; - _commandBuffer.addScheduledHandler(setTimestamp, &m_result[offset]); - _commandBuffer.addCompletedHandler(setTimestamp, &m_result[offset+1]); + _commandBuffer.addScheduledHandler(setTimestamp, &m_result[offset].m_begin); + _commandBuffer.addCompletedHandler(setTimestamp, &m_result[offset].m_end); m_control.commit(1); } @@ -3146,9 +3436,9 @@ namespace bgfx { namespace mtl { if (0 != m_control.available() ) { - uint32_t offset = m_control.m_read * 2; - m_begin = m_result[offset+0]; - m_end = m_result[offset+1]; + uint32_t offset = m_control.m_read; + m_begin = m_result[offset].m_begin; + m_end = m_result[offset].m_end; m_elapsed = m_end - m_begin; m_control.consume(1); @@ -3224,15 +3514,13 @@ namespace bgfx { namespace mtl void RendererContextMtl::submitBlit(BlitState& _bs, uint16_t _view) { - if (!_bs.hasItem(_view)) - return; - - if (0 != m_renderCommandEncoder) + if (!_bs.hasItem(_view) ) { - m_renderCommandEncoder.endEncoding(); - m_renderCommandEncoder = 0; + return; } + endEncoding(); + m_blitCommandEncoder = getBlitCommandEncoder(); while (_bs.hasItem(_view) ) @@ -3310,11 +3598,13 @@ namespace bgfx { namespace mtl { m_cmd.finish(false); - if (m_commandBuffer == NULL) + if (NULL == m_commandBuffer) { m_commandBuffer = m_cmd.alloc(); } + BGFX_MTL_PROFILER_BEGIN_LITERAL("rendererSubmit", kColorFrame); + int64_t timeBegin = bx::getHPCounter(); int64_t captureElapsed = 0; @@ -3383,14 +3673,16 @@ namespace bgfx { namespace mtl if (0 < _render->m_iboffset) { + BGFX_PROFILER_SCOPE("bgfx/Update transient index buffer", kColorResource); TransientIndexBuffer* ib = _render->m_transientIb; - m_indexBuffers[ib->handle.idx].update(0, _render->m_iboffset, ib->data, true); + m_indexBuffers[ib->handle.idx].update(0, bx::strideAlign(_render->m_iboffset,4), ib->data, true); } if (0 < _render->m_vboffset) { + BGFX_PROFILER_SCOPE("bgfx/Update transient vertex buffer", kColorResource); TransientVertexBuffer* vb = _render->m_transientVb; - m_vertexBuffers[vb->handle.idx].update(0, _render->m_vboffset, vb->data, true); + m_vertexBuffers[vb->handle.idx].update(0, bx::strideAlign(_render->m_vboffset,4), vb->data, true); } _render->sort(); @@ -3403,14 +3695,13 @@ namespace bgfx { namespace mtl RenderBind currentBind; currentBind.clear(); - const bool hmdEnabled = false; static ViewState viewState; - viewState.reset(_render, hmdEnabled); + viewState.reset(_render); uint32_t blendFactor = 0; bool wireframe = !!(_render->m_debug&BGFX_DEBUG_WIREFRAME); - uint16_t programIdx = kInvalidHandle; + ProgramHandle currentProgram = BGFX_INVALID_HANDLE; SortKey key; uint16_t view = UINT16_MAX; FrameBufferHandle fbh = { BGFX_CONFIG_MAX_FRAME_BUFFERS }; @@ -3420,33 +3711,38 @@ namespace bgfx { namespace mtl const uint64_t primType = 0; uint8_t primIndex = uint8_t(primType>>BGFX_STATE_PT_SHIFT); PrimInfo prim = s_primInfo[primIndex]; + const uint32_t maxComputeBindings = g_caps.limits.maxComputeBindings; + const uint32_t maxTextureSamplers = g_caps.limits.maxTextureSamplers; - ProgramMtl* currentProgram = NULL; RenderCommandEncoder rce; + PipelineStateMtl* currentPso = NULL; - bool wasCompute = false; + bool wasCompute = false; bool viewHasScissor = false; Rect viewScissorRect; viewScissorRect.clear(); uint32_t statsNumPrimsSubmitted[BX_COUNTOF(s_primInfo)] = {}; - uint32_t statsNumPrimsRendered[BX_COUNTOF(s_primInfo)] = {}; - uint32_t statsNumInstances[BX_COUNTOF(s_primInfo)] = {}; - uint32_t statsNumDrawIndirect[BX_COUNTOF(s_primInfo)] = {}; + uint32_t statsNumPrimsRendered[BX_COUNTOF(s_primInfo)] = {}; + uint32_t statsNumInstances[BX_COUNTOF(s_primInfo)] = {}; + uint32_t statsNumDrawIndirect[BX_COUNTOF(s_primInfo)] = {}; uint32_t statsNumIndices = 0; uint32_t statsKeyType[2] = {}; + Profiler<TimerQueryMtl> profiler( + _render + , m_gpuTimer + , s_viewName + ); + m_occlusionQuery.resolve(_render); if (0 == (_render->m_debug&BGFX_DEBUG_IFH) ) { - bool viewRestart = false; - uint8_t eye = 0; - uint8_t restartState = 0; viewState.m_rect = _render->m_view[0].m_rect; - int32_t numItems = _render->m_numRenderItems; - for (int32_t item = 0, restartItem = numItems; item < numItems || restartItem < numItems;) + + for (int32_t item = 0; item < numItems;) { const uint64_t encodedKey = _render->m_sortKeys[item]; const bool isCompute = key.decode(encodedKey, _render->m_viewRemap); @@ -3462,226 +3758,360 @@ namespace bgfx { namespace mtl const RenderBind& renderBind = _render->m_renderItemBind[itemIdx]; ++item; - if (viewChanged) + if (viewChanged + || (!isCompute && wasCompute) ) { - if (1 == restartState) - { - restartState = 2; - item = restartItem; - restartItem = numItems; - view = UINT16_MAX; - continue; - } - view = key.m_view; - programIdx = kInvalidHandle; + currentProgram = BGFX_INVALID_HANDLE; - viewRestart = BGFX_VIEW_STEREO == (_render->m_view[view].m_flags & BGFX_VIEW_STEREO); - viewRestart &= hmdEnabled; - - if (viewRestart) - { - if (0 == restartState) - { - restartState = 1; - restartItem = item - 1; - } - - eye = (restartState - 1) & 1; - restartState &= 1; - } - else + if (item > 1) { - eye = 0; + profiler.end(); } - viewState.m_rect = _render->m_view[view].m_rect; + BGFX_MTL_PROFILER_END(); + setViewType(view, " "); + BGFX_MTL_PROFILER_BEGIN(view, kColorView); - if (viewRestart) - { - viewState.m_rect.m_x = eye * (viewState.m_rect.m_width+1)/2; - viewState.m_rect.m_width /= 2; - } + profiler.begin(view); + + viewState.m_rect = _render->m_view[view].m_rect; submitBlit(bs, view); - const Rect& scissorRect = _render->m_view[view].m_scissor; - viewHasScissor = !scissorRect.isZero(); - viewScissorRect = viewHasScissor ? scissorRect : viewState.m_rect; - Clear& clr = _render->m_view[view].m_clear; + if (!isCompute) + { + const Rect& scissorRect = _render->m_view[view].m_scissor; + viewHasScissor = !scissorRect.isZero(); + viewScissorRect = viewHasScissor ? scissorRect : viewState.m_rect; + Clear& clr = _render->m_view[view].m_clear; - Rect viewRect = viewState.m_rect; - bool clearWithRenderPass = false; + Rect viewRect = viewState.m_rect; + bool clearWithRenderPass = false; - if (NULL == m_renderCommandEncoder - || fbh.idx != _render->m_view[view].m_fbh.idx) - { - if (0 != m_renderCommandEncoder) + if ((NULL == m_renderCommandEncoder + || fbh.idx != _render->m_view[view].m_fbh.idx)) { - m_renderCommandEncoder.endEncoding(); - } + endEncoding(); - RenderPassDescriptor renderPassDescriptor = newRenderPassDescriptor(); - renderPassDescriptor.visibilityResultBuffer = m_occlusionQuery.m_buffer; + RenderPassDescriptor renderPassDescriptor = newRenderPassDescriptor(); + renderPassDescriptor.visibilityResultBuffer = m_occlusionQuery.m_buffer; - fbh = _render->m_view[view].m_fbh; + fbh = _render->m_view[view].m_fbh; - uint32_t width = m_resolution.width; - uint32_t height = m_resolution.height; + uint32_t width = m_resolution.width; + uint32_t height = m_resolution.height; - if (isValid(fbh) ) - { - FrameBufferMtl& frameBuffer = m_frameBuffers[fbh.idx]; - width = frameBuffer.m_width; - height = frameBuffer.m_height; - } + if (isValid(fbh) ) + { + FrameBufferMtl& frameBuffer = m_frameBuffers[fbh.idx]; + width = frameBuffer.m_width; + height = frameBuffer.m_height; + } - clearWithRenderPass = true - && 0 == viewRect.m_x - && 0 == viewRect.m_y - && width == viewRect.m_width - && height == viewRect.m_height - ; + clearWithRenderPass = true + && 0 == viewRect.m_x + && 0 == viewRect.m_y + && width == viewRect.m_width + && height == viewRect.m_height + ; - setFrameBuffer(renderPassDescriptor, fbh); + setFrameBuffer(renderPassDescriptor, fbh); - if (clearWithRenderPass) - { - for (uint32_t ii = 0; ii < g_caps.limits.maxFBAttachments; ++ii) + if (clearWithRenderPass) { - MTLRenderPassColorAttachmentDescriptor* desc = renderPassDescriptor.colorAttachments[ii]; - - if (desc.texture != NULL) + for (uint32_t ii = 0; ii < g_caps.limits.maxFBAttachments; ++ii) { - if (0 != (BGFX_CLEAR_COLOR & clr.m_flags) ) + MTLRenderPassColorAttachmentDescriptor* desc = renderPassDescriptor.colorAttachments[ii]; + + if (desc.texture != NULL) { - if (0 != (BGFX_CLEAR_COLOR_USE_PALETTE & clr.m_flags) ) + if (0 != (BGFX_CLEAR_COLOR & clr.m_flags) ) { - uint8_t index = (uint8_t)bx::uint32_min(BGFX_CONFIG_MAX_COLOR_PALETTE-1, clr.m_index[ii]); - const float* rgba = _render->m_colorPalette[index]; - const float rr = rgba[0]; - const float gg = rgba[1]; - const float bb = rgba[2]; - const float aa = rgba[3]; - desc.clearColor = MTLClearColorMake(rr, gg, bb, aa); + if (0 != (BGFX_CLEAR_COLOR_USE_PALETTE & clr.m_flags) ) + { + uint8_t index = (uint8_t)bx::uint32_min(BGFX_CONFIG_MAX_COLOR_PALETTE-1, clr.m_index[ii]); + const float* rgba = _render->m_colorPalette[index]; + const float rr = rgba[0]; + const float gg = rgba[1]; + const float bb = rgba[2]; + const float aa = rgba[3]; + desc.clearColor = MTLClearColorMake(rr, gg, bb, aa); + } + else + { + float rr = clr.m_index[0]*1.0f/255.0f; + float gg = clr.m_index[1]*1.0f/255.0f; + float bb = clr.m_index[2]*1.0f/255.0f; + float aa = clr.m_index[3]*1.0f/255.0f; + desc.clearColor = MTLClearColorMake(rr, gg, bb, aa); + } + + desc.loadAction = MTLLoadActionClear; } else { - float rr = clr.m_index[0]*1.0f/255.0f; - float gg = clr.m_index[1]*1.0f/255.0f; - float bb = clr.m_index[2]*1.0f/255.0f; - float aa = clr.m_index[3]*1.0f/255.0f; - desc.clearColor = MTLClearColorMake(rr, gg, bb, aa); + desc.loadAction = MTLLoadActionLoad; } - desc.loadAction = MTLLoadActionClear; + desc.storeAction = desc.texture.sampleCount > 1 ? MTLStoreActionMultisampleResolve : MTLStoreActionStore; } - else + } + + RenderPassDepthAttachmentDescriptor depthAttachment = renderPassDescriptor.depthAttachment; + + if (NULL != depthAttachment.texture) + { + depthAttachment.clearDepth = clr.m_depth; + depthAttachment.loadAction = 0 != (BGFX_CLEAR_DEPTH & clr.m_flags) + ? MTLLoadActionClear + : MTLLoadActionLoad + ; + depthAttachment.storeAction = NULL != m_mainFrameBuffer.m_swapChain->m_backBufferColorMsaa + ? MTLStoreActionDontCare + : MTLStoreActionStore + ; + } + + RenderPassStencilAttachmentDescriptor stencilAttachment = renderPassDescriptor.stencilAttachment; + + if (NULL != stencilAttachment.texture) + { + stencilAttachment.clearStencil = clr.m_stencil; + stencilAttachment.loadAction = 0 != (BGFX_CLEAR_STENCIL & clr.m_flags) + ? MTLLoadActionClear + : MTLLoadActionLoad + ; + stencilAttachment.storeAction = NULL != m_mainFrameBuffer.m_swapChain->m_backBufferColorMsaa + ? MTLStoreActionDontCare + : MTLStoreActionStore + ; + } + } + else + { + for (uint32_t ii = 0; ii < g_caps.limits.maxFBAttachments; ++ii) + { + MTLRenderPassColorAttachmentDescriptor* desc = renderPassDescriptor.colorAttachments[ii]; + if (desc.texture != NULL) { desc.loadAction = MTLLoadActionLoad; } - desc.storeAction = desc.texture.sampleCount > 1 ? MTLStoreActionMultisampleResolve : MTLStoreActionStore; } - } - RenderPassDepthAttachmentDescriptor depthAttachment = renderPassDescriptor.depthAttachment; - if (NULL != depthAttachment.texture) - { - depthAttachment.clearDepth = clr.m_depth; - depthAttachment.loadAction = 0 != (BGFX_CLEAR_DEPTH & clr.m_flags) - ? MTLLoadActionClear - : MTLLoadActionLoad - ; - depthAttachment.storeAction = NULL != m_mainFrameBuffer.m_swapChain->m_backBufferColorMsaa - ? MTLStoreActionDontCare - : MTLStoreActionStore - ; - } + RenderPassDepthAttachmentDescriptor depthAttachment = renderPassDescriptor.depthAttachment; - RenderPassStencilAttachmentDescriptor stencilAttachment = renderPassDescriptor.stencilAttachment; - if (NULL != stencilAttachment.texture) - { - stencilAttachment.clearStencil = clr.m_stencil; - stencilAttachment.loadAction = 0 != (BGFX_CLEAR_STENCIL & clr.m_flags) - ? MTLLoadActionClear - : MTLLoadActionLoad - ; - stencilAttachment.storeAction = NULL != m_mainFrameBuffer.m_swapChain->m_backBufferColorMsaa - ? MTLStoreActionDontCare - : MTLStoreActionStore - ; + if (NULL != depthAttachment.texture) + { + depthAttachment.loadAction = MTLLoadActionLoad; + depthAttachment.storeAction = MTLStoreActionStore; + } + + RenderPassStencilAttachmentDescriptor stencilAttachment = renderPassDescriptor.stencilAttachment; + + if (NULL != stencilAttachment.texture) + { + stencilAttachment.loadAction = MTLLoadActionLoad; + stencilAttachment.storeAction = MTLStoreActionStore; + } } + + rce = m_commandBuffer.renderCommandEncoderWithDescriptor(renderPassDescriptor); + m_renderCommandEncoder = rce; + m_renderCommandEncoderFrameBufferHandle = fbh; + MTL_RELEASE(renderPassDescriptor); } - else + else if (BX_ENABLED(BGFX_CONFIG_DEBUG_ANNOTATION) ) + { + rce.popDebugGroup(); + } + + if (BX_ENABLED(BGFX_CONFIG_DEBUG_ANNOTATION) ) + { + rce.pushDebugGroup(s_viewName[view]); + } + + rce.setTriangleFillMode(wireframe ? MTLTriangleFillModeLines : MTLTriangleFillModeFill); + + MTLViewport vp; + vp.originX = viewState.m_rect.m_x; + vp.originY = viewState.m_rect.m_y; + vp.width = viewState.m_rect.m_width; + vp.height = viewState.m_rect.m_height; + vp.znear = 0.0f; + vp.zfar = 1.0f; + rce.setViewport(vp); + + if (BGFX_CLEAR_NONE != (clr.m_flags & BGFX_CLEAR_MASK) + && !clearWithRenderPass) + { + clearQuad(_clearQuad, viewState.m_rect, clr, _render->m_colorPalette); + } + } + } + + if (isCompute) + { + if (!wasCompute) + { + wasCompute = true; + + endEncoding(); + rce = NULL; + + setViewType(view, "C"); + BGFX_MTL_PROFILER_END(); + BGFX_MTL_PROFILER_BEGIN(view, kColorCompute); + + m_computeCommandEncoder = m_commandBuffer.computeCommandEncoder(); + } + else if (viewChanged && BX_ENABLED(BGFX_CONFIG_DEBUG_ANNOTATION) ) + { + m_computeCommandEncoder.popDebugGroup(); + } + + if (viewChanged + && BX_ENABLED(BGFX_CONFIG_DEBUG_ANNOTATION) ) + { + s_viewName[view][3] = L'C'; + m_computeCommandEncoder.pushDebugGroup(s_viewName[view]); + s_viewName[view][3] = L' '; + } + + const RenderCompute& compute = renderItem.compute; + + bool programChanged = false; + rendererUpdateUniforms(this, _render->m_uniformBuffer[compute.m_uniformIdx], compute.m_uniformBegin, compute.m_uniformEnd); + + if (key.m_program.idx != currentProgram.idx) + { + currentProgram = key.m_program; + + currentPso = getComputePipelineState(currentProgram); + + if (NULL == currentPso) + { + currentProgram = BGFX_INVALID_HANDLE; + continue; + } + + m_computeCommandEncoder.setComputePipelineState(currentPso->m_cps); + programChanged = true; + } + + if (isValid(currentProgram) + && NULL != currentPso) + { + uint32_t vertexUniformBufferSize = currentPso->m_vshConstantBufferSize; + + if (0 != vertexUniformBufferSize) + { + m_uniformBufferVertexOffset = BX_ALIGN_MASK(m_uniformBufferVertexOffset, currentPso->m_vshConstantBufferAlignmentMask); + m_computeCommandEncoder.setBuffer(m_uniformBuffer, m_uniformBufferVertexOffset, 0); + } + + UniformBuffer* vcb = currentPso->m_vshConstantBuffer; + if (NULL != vcb) + { + commit(*vcb); + } + + viewState.setPredefined<4>(this, view, *currentPso, _render, compute); + + m_uniformBufferVertexOffset += vertexUniformBufferSize; + } + BX_UNUSED(programChanged); + + for (uint8_t stage = 0; stage < maxComputeBindings; ++stage) + { + const Binding& bind = renderBind.m_bind[stage]; + if (kInvalidHandle != bind.m_idx) { - for (uint32_t ii = 0; ii < g_caps.limits.maxFBAttachments; ++ii) + switch (bind.m_type) { - MTLRenderPassColorAttachmentDescriptor* desc = renderPassDescriptor.colorAttachments[ii]; - if (desc.texture != NULL) + case Binding::Image: { - desc.loadAction = MTLLoadActionLoad; + TextureMtl& texture = m_textures[bind.m_idx]; + m_computeCommandEncoder.setTexture(texture.getTextureMipLevel(bind.m_mip), stage); } - } + break; - RenderPassDepthAttachmentDescriptor depthAttachment = renderPassDescriptor.depthAttachment; - if (NULL != depthAttachment.texture) - { - depthAttachment.loadAction = MTLLoadActionLoad; - depthAttachment.storeAction = MTLStoreActionStore; - } + case Binding::Texture: + { + TextureMtl& texture = m_textures[bind.m_idx]; + uint32_t flags = bind.m_samplerFlags; + + m_computeCommandEncoder.setTexture(texture.m_ptr, stage); + m_computeCommandEncoder.setSamplerState( + 0 == (BGFX_SAMPLER_INTERNAL_DEFAULT & flags) + ? getSamplerState(flags) + : texture.m_sampler + , stage + ); + } + break; - RenderPassStencilAttachmentDescriptor stencilAttachment = renderPassDescriptor.stencilAttachment; - if (NULL != stencilAttachment.texture) - { - stencilAttachment.loadAction = MTLLoadActionLoad; - stencilAttachment.storeAction = MTLStoreActionStore; + case Binding::IndexBuffer: + case Binding::VertexBuffer: + { + const BufferMtl& buffer = Binding::IndexBuffer == bind.m_type + ? m_indexBuffers[bind.m_idx] + : m_vertexBuffers[bind.m_idx] + ; + m_computeCommandEncoder.setBuffer(buffer.m_ptr, 0, stage + 1); + } + break; } } - - rce = m_commandBuffer.renderCommandEncoderWithDescriptor(renderPassDescriptor); - m_renderCommandEncoder = rce; - m_renderCommandEncoderFrameBufferHandle = fbh; - MTL_RELEASE(renderPassDescriptor); } - rce.setTriangleFillMode(wireframe ? MTLTriangleFillModeLines : MTLTriangleFillModeFill); + MTLSize threadsPerGroup = MTLSizeMake( + currentPso->m_numThreads[0] + , currentPso->m_numThreads[1] + , currentPso->m_numThreads[2] + ); - if (BX_ENABLED(BGFX_CONFIG_DEBUG_MTL) ) + if (isValid(compute.m_indirectBuffer) ) { - if (item != 1) + const VertexBufferMtl& vb = m_vertexBuffers[compute.m_indirectBuffer.idx]; + + uint32_t numDrawIndirect = UINT16_MAX == compute.m_numIndirect + ? vb.m_size/BGFX_CONFIG_DRAW_INDIRECT_STRIDE + : compute.m_numIndirect + ; + + uint32_t args = compute.m_startIndirect * BGFX_CONFIG_DRAW_INDIRECT_STRIDE; + for (uint32_t ii = 0; ii < numDrawIndirect; ++ii) { - rce.popDebugGroup(); + m_computeCommandEncoder.dispatchThreadgroupsWithIndirectBuffer( + vb.m_ptr + , args + , threadsPerGroup + ); + args += BGFX_CONFIG_DRAW_INDIRECT_STRIDE; } - - rce.pushDebugGroup(s_viewName[view]); } - - MTLViewport vp; - vp.originX = viewState.m_rect.m_x; - vp.originY = viewState.m_rect.m_y; - vp.width = viewState.m_rect.m_width; - vp.height = viewState.m_rect.m_height; - vp.znear = 0.0f; - vp.zfar = 1.0f; - rce.setViewport(vp); - - if (BGFX_CLEAR_NONE != (clr.m_flags & BGFX_CLEAR_MASK) - && !clearWithRenderPass) + else { - clearQuad(_clearQuad, viewState.m_rect, clr, _render->m_colorPalette); + m_computeCommandEncoder.dispatchThreadgroups( + MTLSizeMake(compute.m_numX, compute.m_numY, compute.m_numZ) + , threadsPerGroup + ); } + continue; } + bool resetState = viewChanged || wasCompute; if (wasCompute) { wasCompute = false; + currentProgram = BGFX_INVALID_HANDLE; - programIdx = kInvalidHandle; - currentProgram = NULL; - - //invalidateCompute(); + setViewType(view, " "); + BGFX_MTL_PROFILER_END(); + BGFX_MTL_PROFILER_BEGIN(view, kColorDraw); } const RenderDraw& draw = renderItem.draw; @@ -3727,7 +4157,7 @@ namespace bgfx { namespace mtl currentBind.clear(); - programIdx = kInvalidHandle; + currentProgram = BGFX_INVALID_HANDLE; setDepthStencilState(newFlags, packStencil(BGFX_STENCIL_DEFAULT, BGFX_STENCIL_DEFAULT) ); const uint64_t pt = newFlags&BGFX_STATE_PT_MASK; @@ -3826,12 +4256,11 @@ namespace bgfx { namespace mtl } bool programChanged = false; - bool constantsChanged = draw.m_uniformBegin < draw.m_uniformEnd; rendererUpdateUniforms(this, _render->m_uniformBuffer[draw.m_uniformIdx], draw.m_uniformBegin, draw.m_uniformEnd); bool vertexStreamChanged = hasVertexStreamChanged(currentState, draw); - if (key.m_program != programIdx + if (key.m_program.idx != currentProgram.idx || vertexStreamChanged || (0 | BGFX_STATE_BLEND_MASK @@ -3844,36 +4273,39 @@ namespace bgfx { namespace mtl ) & changedFlags || ( (blendFactor != draw.m_rgba) && !!(newFlags & BGFX_STATE_BLEND_INDEPENDENT) ) ) { - programIdx = key.m_program; + currentProgram = key.m_program; currentState.m_streamMask = draw.m_streamMask; currentState.m_instanceDataBuffer.idx = draw.m_instanceDataBuffer.idx; currentState.m_instanceDataOffset = draw.m_instanceDataOffset; currentState.m_instanceDataStride = draw.m_instanceDataStride; - const VertexDecl* decls[BGFX_CONFIG_MAX_VERTEX_STREAMS]; + const VertexLayout* layouts[BGFX_CONFIG_MAX_VERTEX_STREAMS]; uint32_t numVertices = draw.m_numVertices; uint8_t numStreams = 0; - for (uint32_t idx = 0, streamMask = draw.m_streamMask, ntz = bx::uint32_cnttz(streamMask) + for (uint32_t idx = 0, streamMask = draw.m_streamMask ; 0 != streamMask - ; streamMask >>= 1, idx += 1, ntz = bx::uint32_cnttz(streamMask), ++numStreams + ; streamMask >>= 1, idx += 1, ++numStreams ) { + const uint32_t ntz = bx::uint32_cnttz(streamMask); streamMask >>= ntz; idx += ntz; - currentState.m_stream[idx].m_decl = draw.m_stream[idx].m_decl; - currentState.m_stream[idx].m_handle = draw.m_stream[idx].m_handle; - currentState.m_stream[idx].m_startVertex = draw.m_stream[idx].m_startVertex; + currentState.m_stream[idx].m_layoutHandle = draw.m_stream[idx].m_layoutHandle; + currentState.m_stream[idx].m_handle = draw.m_stream[idx].m_handle; + currentState.m_stream[idx].m_startVertex = draw.m_stream[idx].m_startVertex; const uint16_t handle = draw.m_stream[idx].m_handle.idx; const VertexBufferMtl& vb = m_vertexBuffers[handle]; - const uint16_t decl = !isValid(vb.m_decl) ? draw.m_stream[idx].m_decl.idx : vb.m_decl.idx; - const VertexDecl& vertexDecl = m_vertexDecls[decl]; - const uint32_t stride = vertexDecl.m_stride; + const uint16_t decl = isValid(draw.m_stream[idx].m_layoutHandle) + ? draw.m_stream[idx].m_layoutHandle.idx + : vb.m_layoutHandle.idx; + const VertexLayout& layout = m_vertexLayouts[decl]; + const uint32_t stride = layout.m_stride; - decls[numStreams] = &vertexDecl; + layouts[numStreams] = &layout; numVertices = bx::uint32_min(UINT32_MAX == draw.m_numVertices ? vb.m_size/stride @@ -3882,123 +4314,128 @@ namespace bgfx { namespace mtl ); const uint32_t offset = draw.m_stream[idx].m_startVertex * stride; - rce.setVertexBuffer(vb.getBuffer(), offset, idx+1); + rce.setVertexBuffer(vb.m_ptr, offset, idx+1); } currentState.m_numVertices = numVertices; - if (kInvalidHandle == programIdx) + if (!isValid(currentProgram) ) { - currentProgram = NULL; continue; } else { - ProgramMtl& program = m_program[programIdx]; - currentProgram = &program; - - RenderPipelineState pso = NULL; + currentPso = NULL; if (0 < numStreams) { - pso = getPipelineState( + currentPso = getPipelineState( newFlags , draw.m_rgba , fbh , numStreams - , decls - , programIdx + , layouts + , currentProgram , draw.m_instanceDataStride/16 ); } - if (NULL == pso) + if (NULL == currentPso) { - currentProgram = NULL; - programIdx = kInvalidHandle; + currentProgram = BGFX_INVALID_HANDLE; continue; } - rce.setRenderPipelineState(pso); + rce.setRenderPipelineState(currentPso->m_rps); } if (isValid(draw.m_instanceDataBuffer) ) { const VertexBufferMtl& inst = m_vertexBuffers[draw.m_instanceDataBuffer.idx]; - rce.setVertexBuffer(inst.getBuffer(), draw.m_instanceDataOffset, numStreams+1); + rce.setVertexBuffer(inst.m_ptr, draw.m_instanceDataOffset, numStreams+1); } - programChanged = - constantsChanged = true; + programChanged = true; } - if (kInvalidHandle != programIdx) + if (isValid(currentProgram) ) { - ProgramMtl& program = m_program[programIdx]; - - uint32_t vertexUniformBufferSize = program.m_vshConstantBufferSize; - uint32_t fragmentUniformBufferSize = program.m_fshConstantBufferSize; + const uint32_t vertexUniformBufferSize = currentPso->m_vshConstantBufferSize; + const uint32_t fragmentUniformBufferSize = currentPso->m_fshConstantBufferSize; if (0 != vertexUniformBufferSize) { - m_uniformBufferVertexOffset = BX_ALIGN_MASK(m_uniformBufferVertexOffset, program.m_vshConstantBufferAlignmentMask); + m_uniformBufferVertexOffset = BX_ALIGN_MASK(m_uniformBufferVertexOffset, currentPso->m_vshConstantBufferAlignmentMask); rce.setVertexBuffer(m_uniformBuffer, m_uniformBufferVertexOffset, 0); } m_uniformBufferFragmentOffset = m_uniformBufferVertexOffset + vertexUniformBufferSize; if (0 != fragmentUniformBufferSize) { - m_uniformBufferFragmentOffset = BX_ALIGN_MASK(m_uniformBufferFragmentOffset, program.m_fshConstantBufferAlignmentMask); + m_uniformBufferFragmentOffset = BX_ALIGN_MASK(m_uniformBufferFragmentOffset, currentPso->m_fshConstantBufferAlignmentMask); rce.setFragmentBuffer(m_uniformBuffer, m_uniformBufferFragmentOffset, 0); } - if (constantsChanged) + UniformBuffer* vcb = currentPso->m_vshConstantBuffer; + if (NULL != vcb) { - UniformBuffer* vcb = program.m_vshConstantBuffer; - if (NULL != vcb) - { - commit(*vcb); - } - - UniformBuffer* fcb = program.m_fshConstantBuffer; - if (NULL != fcb) - { - commit(*fcb); - } + commit(*vcb); + } + + UniformBuffer* fcb = currentPso->m_fshConstantBuffer; + if (NULL != fcb) + { + commit(*fcb); } - viewState.setPredefined<4>(this, view, eye, program, _render, draw); + viewState.setPredefined<4>(this, view, *currentPso, _render, draw); m_uniformBufferFragmentOffset += fragmentUniformBufferSize; - m_uniformBufferVertexOffset = m_uniformBufferFragmentOffset; + m_uniformBufferVertexOffset = m_uniformBufferFragmentOffset; } - if (kInvalidHandle != programIdx) + if (isValid(currentProgram) ) { - ProgramMtl& program = m_program[programIdx]; - - for (uint32_t sampler = 0; sampler < program.m_samplerCount; ++sampler) + uint8_t* bindingTypes = currentPso->m_bindingTypes; + for (uint8_t stage = 0; stage < maxTextureSamplers; ++stage) { - ProgramMtl::SamplerInfo& samplerInfo = program.m_samplers[sampler]; - - UniformHandle handle = samplerInfo.m_uniform; - int stage = *((int*)m_uniforms[handle.idx]); - const Binding& bind = renderBind.m_bind[stage]; Binding& current = currentBind.m_bind[stage]; - if (current.m_idx != bind.m_idx - || current.m_samplerFlags != bind.m_samplerFlags - || programChanged) + || current.m_type != bind.m_type + || current.m_samplerFlags != bind.m_samplerFlags + || programChanged) { if (kInvalidHandle != bind.m_idx) { - TextureMtl& texture = m_textures[bind.m_idx]; - texture.commit(samplerInfo.m_index - , !samplerInfo.m_fragment - , samplerInfo.m_fragment - , bind.m_samplerFlags - ); + switch (bind.m_type) + { + case Binding::Texture: + { + TextureMtl& texture = m_textures[bind.m_idx]; + texture.commit(stage + , 0 != (bindingTypes[stage] & PipelineStateMtl::BindToVertexShader) + , 0 != (bindingTypes[stage] & PipelineStateMtl::BindToFragmentShader) + , bind.m_samplerFlags + ); + } + break; + + case Binding::IndexBuffer: + case Binding::VertexBuffer: + { + const BufferMtl& buffer = Binding::IndexBuffer == bind.m_type + ? m_indexBuffers[bind.m_idx] + : m_vertexBuffers[bind.m_idx] + ; + + if (0 != (bindingTypes[stage] & PipelineStateMtl::BindToVertexShader)) + rce.setVertexBuffer(buffer.m_ptr, 0, stage + 1); + if (0 != (bindingTypes[stage] & PipelineStateMtl::BindToFragmentShader)) + rce.setFragmentBuffer(buffer.m_ptr, 0, stage + 1); + } + break; + } } } @@ -4012,9 +4449,9 @@ namespace bgfx { namespace mtl if (UINT32_MAX == numVertices) { const VertexBufferMtl& vb = m_vertexBuffers[currentState.m_stream[0].m_handle.idx]; - uint16_t decl = !isValid(vb.m_decl) ? draw.m_stream[0].m_decl.idx : vb.m_decl.idx; - const VertexDecl& vertexDecl = m_vertexDecls[decl]; - numVertices = vb.m_size/vertexDecl.m_stride; + uint16_t decl = !isValid(vb.m_layoutHandle) ? draw.m_stream[0].m_layoutHandle.idx : vb.m_layoutHandle.idx; + const VertexLayout& layout = m_vertexLayouts[decl]; + numVertices = vb.m_size/layout.m_stride; } uint32_t numIndices = 0; @@ -4030,6 +4467,34 @@ namespace bgfx { namespace mtl if (isValid(draw.m_indirectBuffer) ) { + const VertexBufferMtl& vb = m_vertexBuffers[draw.m_indirectBuffer.idx]; + + if (isValid(draw.m_indexBuffer) ) + { + const IndexBufferMtl& ib = m_indexBuffers[draw.m_indexBuffer.idx]; + MTLIndexType indexType = 0 == (ib.m_flags & BGFX_BUFFER_INDEX32) ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32; + + numDrawIndirect = UINT16_MAX == draw.m_numIndirect + ? vb.m_size/BGFX_CONFIG_DRAW_INDIRECT_STRIDE + : draw.m_numIndirect + ; + + for (uint32_t ii = 0; ii < numDrawIndirect; ++ii) + { + rce.drawIndexedPrimitives(prim.m_type,indexType, ib.m_ptr, 0, vb.m_ptr, (draw.m_startIndirect + ii )* BGFX_CONFIG_DRAW_INDIRECT_STRIDE); + } + } + else + { + numDrawIndirect = UINT16_MAX == draw.m_numIndirect + ? vb.m_size/BGFX_CONFIG_DRAW_INDIRECT_STRIDE + : draw.m_numIndirect + ; + for (uint32_t ii = 0; ii < numDrawIndirect; ++ii) + { + rce.drawPrimitives(prim.m_type,vb.m_ptr, (draw.m_startIndirect + ii) * BGFX_CONFIG_DRAW_INDIRECT_STRIDE); + } + } } else { @@ -4046,7 +4511,7 @@ namespace bgfx { namespace mtl numInstances = draw.m_numInstances; numPrimsRendered = numPrimsSubmitted*draw.m_numInstances; - rce.drawIndexedPrimitives(prim.m_type, numIndices, indexType, ib.getBuffer(), 0, draw.m_numInstances); + rce.drawIndexedPrimitives(prim.m_type, numIndices, indexType, ib.m_ptr, 0, draw.m_numInstances); } else if (prim.m_min <= draw.m_numIndices) { @@ -4056,7 +4521,7 @@ namespace bgfx { namespace mtl numInstances = draw.m_numInstances; numPrimsRendered = numPrimsSubmitted*draw.m_numInstances; - rce.drawIndexedPrimitives(prim.m_type, numIndices, indexType, ib.getBuffer(), draw.m_startIndex * indexSize,numInstances); + rce.drawIndexedPrimitives(prim.m_type, numIndices, indexType, ib.m_ptr, draw.m_startIndex * indexSize,numInstances); } } else @@ -4065,7 +4530,7 @@ namespace bgfx { namespace mtl numInstances = draw.m_numInstances; numPrimsRendered = numPrimsSubmitted*draw.m_numInstances; - rce.drawPrimitives(prim.m_type, 0, draw.m_numVertices, draw.m_numInstances); + rce.drawPrimitives(prim.m_type, 0, numVertices, draw.m_numInstances); } } @@ -4084,7 +4549,11 @@ namespace bgfx { namespace mtl if (wasCompute) { - //invalidateCompute(); + invalidateCompute(); + + setViewType(view, "C"); + BGFX_MTL_PROFILER_END(); + BGFX_MTL_PROFILER_BEGIN(view, kColorCompute); } submitBlit(bs, BGFX_CONFIG_MAX_VIEWS); @@ -4095,10 +4564,12 @@ namespace bgfx { namespace mtl capture(); rce = m_renderCommandEncoder; captureElapsed += bx::getHPCounter(); + + profiler.end(); } } - if (BX_ENABLED(BGFX_CONFIG_DEBUG_MTL) ) + if (BX_ENABLED(BGFX_CONFIG_DEBUG_ANNOTATION) ) { if (0 < _render->m_numRenderItems) { @@ -4106,6 +4577,8 @@ namespace bgfx { namespace mtl } } + BGFX_MTL_PROFILER_END(); + int64_t timeEnd = bx::getHPCounter(); int64_t frameTime = timeEnd - timeBegin; @@ -4241,18 +4714,19 @@ namespace bgfx { namespace mtl rce.popDebugGroup(); } - rce.endEncoding(); - m_renderCommandEncoder = 0; + endEncoding(); m_renderCommandEncoderFrameBufferHandle.idx = kInvalidHandle; if (m_screenshotTarget) { RenderPassDescriptor renderPassDescriptor = newRenderPassDescriptor(); - renderPassDescriptor.colorAttachments[0].texture = m_mainFrameBuffer.m_swapChain->currentDrawable().texture; + renderPassDescriptor.colorAttachments[0].texture = m_mainFrameBuffer.m_swapChain->currentDrawableTexture(); renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore; rce = m_commandBuffer.renderCommandEncoderWithDescriptor(renderPassDescriptor); + MTL_RELEASE(renderPassDescriptor); + rce.setCullMode(MTLCullModeNone); rce.setRenderPipelineState(m_screenshotBlitRenderPipelineState); |