diff --git a/.gitignore b/.gitignore index dca0dae..29b2852 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .idea/ cmake-build-*/ build/ +xcode/ .DS_Store diff --git a/src/metal/draw_metal.m b/src/metal/draw_metal.m index 2eb7772..b0cb05e 100644 --- a/src/metal/draw_metal.m +++ b/src/metal/draw_metal.m @@ -43,9 +43,11 @@ id _pso; MTLViewport _viewport; vector_float4 _drawColourF; + dispatch_semaphore_t _inFlightSemaphore; - unsigned _vtxListCount, _vtxListReserve, _idxListCount, _idxListReserve; - id _vtxMtlBuffer, _idxMtlBuffer; + unsigned _vtxListCount[3], _vtxListReserve[3], _idxListCount[3], _idxListReserve[3]; + id _vtxMtlBuffer[3], _idxMtlBuffer[3], *_vtxFront, *_idxFront; + int _frame; } - (id) init:(SDL_Window*)window @@ -54,10 +56,14 @@ return nil; self.drawColour = BLACK; - _vtxListReserve = 0; - _idxListReserve = 0; - _vtxMtlBuffer = nil; - _idxMtlBuffer = nil; + _vtxListReserve[0] = _vtxListReserve[1] = _vtxListReserve[2] = 0; + _idxListReserve[0] = _idxListReserve[1] = _idxListReserve[2] = 0; + _vtxMtlBuffer[0] = _vtxMtlBuffer[1] = _vtxMtlBuffer[2] = nil; + _idxMtlBuffer[0] = _idxMtlBuffer[1] = _idxMtlBuffer[2] = nil; + _vtxFront = &_vtxMtlBuffer[0]; + _idxFront = &_idxMtlBuffer[0]; + _frame = 0; + // Create Metal view _window = window; @@ -119,6 +125,9 @@ // Set viewport [self setView:[self getDrawSize]]; + // Allow up to 3 frames in-flight + _inFlightSemaphore = dispatch_semaphore_create(3); + return self; } @@ -131,10 +140,10 @@ - (unsigned) resizeBuffer:(id *)buf itemSize:(unsigned)nsz requiredNum:(unsigned)count { - unsigned reserve; + unsigned long reserve; if (*buf) if (count * nsz <= (reserve = [*buf length])) - return reserve; + return (unsigned)reserve; // Calculate new capacity unsigned newCapacity = (count + DRAWLIST_CHUNK_SIZE - 1) / DRAWLIST_CHUNK_SIZE * DRAWLIST_CHUNK_SIZE; @@ -185,55 +194,57 @@ { _passDesc.colorAttachments[0].clearColor = MTLClearColorMake( _drawColourF[0], _drawColourF[1], _drawColourF[2], _drawColourF[3]); - _vtxListCount = 0; - _idxListCount = 0; + _vtxListCount[_frame] = 0; + _idxListCount[_frame] = 0; } - (void) reserveVertices:(unsigned)count { - count += _vtxListCount; - if (count * sizeof(ShaderVertex) > _vtxListReserve) - _vtxListReserve = [self resizeBuffer:&_vtxMtlBuffer itemSize:sizeof(ShaderVertex) requiredNum:count]; + count += _vtxListCount[_frame]; + if (count * sizeof(ShaderVertex) > _vtxListReserve[_frame]) + _vtxListReserve[_frame] = [self resizeBuffer:_vtxFront itemSize:sizeof(ShaderVertex) requiredNum:count]; } - (void) reserveIndices:(unsigned)count { - count += _idxListCount; - if (count * sizeof(uint16_t) > _idxListReserve) - _idxListReserve = [self resizeBuffer:&_idxMtlBuffer itemSize:sizeof(uint16_t) requiredNum:count]; + count += _idxListCount[_frame]; + if (count * sizeof(uint16_t) > _idxListReserve[_frame]) + _idxListReserve[_frame] = [self resizeBuffer:_idxFront itemSize:sizeof(uint16_t) requiredNum:count]; } - (uint16_t) queueVertex:(float)x :(float)y { - if (_vtxListCount * sizeof(ShaderVertex) >= _vtxListReserve) + if (_vtxListCount[_frame] * sizeof(ShaderVertex) >= _vtxListReserve[_frame]) [self reserveVertices:1]; - ((ShaderVertex*)_vtxMtlBuffer.contents)[_vtxListCount] = (ShaderVertex){ + ((ShaderVertex*)(*_vtxFront).contents)[_vtxListCount[_frame]] = (ShaderVertex){ .position = { x, y }, .colour = _drawColourF }; - return _vtxListCount++; + return _vtxListCount[_frame]++; } - (uint16_t) queueIndex:(uint16_t)idx { - if (_idxListCount * sizeof(uint16_t) >= _idxListReserve) + if (_idxListCount[_frame] * sizeof(uint16_t) >= _idxListReserve[_frame]) [self reserveIndices:1]; - ((uint16_t*)_idxMtlBuffer.contents)[_idxListCount++] = idx; + ((uint16_t*)(*_idxFront).contents)[_idxListCount[_frame]++] = idx; return idx; } - (void) queueIndices:(uint16_t*)idcs count:(unsigned)count { - if ((_idxListCount + count) * sizeof(uint16_t) >= _idxListReserve) + if ((_idxListCount[_frame] + count) * sizeof(uint16_t) >= _idxListReserve[_frame]) [self reserveIndices:count]; - memcpy(&((uint16_t*)_idxMtlBuffer.contents)[_idxListCount], idcs, count * sizeof(uint16_t)); - _idxListCount += count; + memcpy(&((uint16_t*)(*_idxFront).contents)[_idxListCount[_frame]], idcs, count * sizeof(uint16_t)); + _idxListCount[_frame] += count; } - (void) present { + dispatch_semaphore_wait(_inFlightSemaphore, DISPATCH_TIME_FOREVER); + // Synchronise buffers - [_vtxMtlBuffer didModifyRange:(NSRange){ .location = 0, .length = _vtxListCount * sizeof(ShaderVertex) }]; - [_idxMtlBuffer didModifyRange:(NSRange){ .location = 0, .length = _idxListCount * sizeof(uint16_t) }]; + [*_vtxFront didModifyRange:(NSRange){ .location = 0, .length = _vtxListCount[_frame] * sizeof(ShaderVertex) }]; + [*_idxFront didModifyRange:(NSRange){ .location = 0, .length = _idxListCount[_frame] * sizeof(uint16_t) }]; @autoreleasepool { @@ -241,29 +252,37 @@ _passDesc.colorAttachments[0].texture = rt.texture; id cmdBuf = [_queue commandBuffer]; - id enc = [cmdBuf renderCommandEncoderWithDescriptor:_passDesc]; + [cmdBuf addCompletedHandler:^(id _Nonnull _) + { + dispatch_semaphore_signal(_inFlightSemaphore); + }]; + id enc = [cmdBuf renderCommandEncoderWithDescriptor:_passDesc]; [enc setViewport:_viewport]; [enc setCullMode:MTLCullModeNone]; [enc setRenderPipelineState:_pso]; - if (_vtxMtlBuffer && _idxMtlBuffer) + if (*_vtxFront && *_idxFront) { - [enc setVertexBuffer:_vtxMtlBuffer offset:0 atIndex:ShaderInputIdxVerticies]; + [enc setVertexBuffer:*_vtxFront offset:0 atIndex:ShaderInputIdxVerticies]; const vector_float2 viewportScale = { (float)(1.0 / _viewport.width), (float)(1.0 / _viewport.height) }; [enc setVertexBytes:&viewportScale length:sizeof(vector_float2) atIndex:ShaderInputViewportScale]; [enc drawIndexedPrimitives:MTLPrimitiveTypeLine - indexCount:_idxListCount indexType:MTLIndexTypeUInt16 - indexBuffer:_idxMtlBuffer indexBufferOffset:0]; + indexCount:_idxListCount[_frame] indexType:MTLIndexTypeUInt16 + indexBuffer:*_idxFront indexBufferOffset:0]; - _vtxListCount = 0; - _idxListCount = 0; + _vtxListCount[_frame] = _idxListCount[_frame] = 0; } [enc endEncoding]; [cmdBuf presentDrawable:rt]; [cmdBuf commit]; } + + if (++_frame == 3) + _frame = 0; + _vtxFront = &_vtxMtlBuffer[_frame]; + _idxFront = &_idxMtlBuffer[_frame]; } @end @@ -324,7 +343,7 @@ void DrawRect(int x, int y, int w, int h) [renderer reserveVertices:4]; vector_float2 f00 = { x, y }, f10 = { x + w, y }, - f01 = { x, y + h}, f11 = { x + w, y + h }; + f01 = { x, y + h }, f11 = { x + w, y + h }; uint16_t i00 = [renderer queueVertex:f00[0] :f00[1]]; uint16_t i10 = [renderer queueVertex:f10[0] :f10[1]]; uint16_t i11 = [renderer queueVertex:f11[0] :f11[1]];