Example #1
0
        public static bool IsManagedBlock(IntPtr block)
        {
            if (block == IntPtr.Zero)
            {
                throw new ArgumentNullException("block");
            }

            BlockLiteral *   literal    = (BlockLiteral *)block;
            BlockDescriptor *descriptor = (BlockDescriptor *)xamarin_get_block_descriptor();

            return(descriptor->copy_helper == ((BlockDescriptor *)literal->block_descriptor)->copy_helper);
        }
Example #2
0
        /// <summary>
        /// Creates a block descriptor with given minimal size
        /// </summary>
        /// <param name="size">The minimal size</param>
        /// <returns>The block descriptor</returns>
        private static unsafe BlockDescriptor *createBlockDescriptor(int size)
        {
#if HEAP_DEBUG_DESCRIPTOR
            Console.WriteLine("[HEAP] Creating a new block descriptor");
#endif

            // Add size of Block and BlockDescriptor
            size += sizeof(Block) + sizeof(BlockDescriptor);

            // Allocate descriptor
            size = getRequiredPageCount(size) * 0x1000;
            BlockDescriptor *descriptor = (BlockDescriptor *)Paging.AllocateVirtual(size);

#if HEAP_DEBUG_DESCRIPTOR
            Console.Write("[HEAP] New descriptor is at 0x");
            Console.WriteHex((int)descriptor);
            Console.Write(", physical: 0x");
            Console.WriteHex((int)Paging.GetPhysicalFromVirtual(descriptor));
            Console.Write('\n');
#endif

            if (descriptor == null)
            {
                Panic.DoPanic("descriptor == null");
            }

            // Setup block
            Block *first = (Block *)((int)descriptor + sizeof(BlockDescriptor));
            first->Prev       = null;
            first->Next       = null;
            first->Size       = size - sizeof(BlockDescriptor);
            first->Used       = false;
            first->Descriptor = descriptor;
#if HEAP_USE_MAGIC
            first->Magic = HEAP_MAGIC;
#endif

            // Setup descriptor
            descriptor->FreeSpace = size - sizeof(BlockDescriptor);
            descriptor->First     = first;
            descriptor->FirstFree = first;
            descriptor->Next      = null;
#if HEAP_USE_MAGIC
            descriptor->Magic = HEAP_MAGIC;
#endif

            return(descriptor);
        }
Example #3
0
        /// <summary>
        /// Dumps a table of the descriptors
        /// </summary>
        private static unsafe void dumpDescriptors()
        {
            BlockDescriptor *descriptor = firstDescriptor;

            Console.WriteLine("---");

            // Search for a big enough descriptor
            while (true)
            {
                if (descriptor->Next == null)
                {
                    break;
                }

                descriptor = descriptor->Next;

                Console.Write("[");
                Console.WriteHex((int)descriptor);
                Console.WriteLine("]");
            }

            Console.WriteLine("---");
        }
Example #4
0
        /// <summary>
        /// Gets a sufficient block descriptor for the required size
        /// </summary>
        /// <param name="size">The required size</param>
        /// <returns>The block descriptor</returns>
        private static unsafe BlockDescriptor *getSufficientDescriptor(BlockDescriptor *first, int size)
        {
            BlockDescriptor *descriptor = first;

            if (descriptor == null)
            {
                descriptor = firstDescriptor;
            }

            // Search for a big enough descriptor
            while (true)
            {
#if HEAP_USE_MAGIC
                if (descriptor->Magic != HEAP_MAGIC)
                {
                    Panic.DoPanic("descriptor->magic != HEAP_MAGIC");
                }
#endif

                if (descriptor != first && descriptor->FreeSpace >= size)
                {
                    return(descriptor);
                }

                if (descriptor->Next == null)
                {
                    break;
                }

                descriptor = descriptor->Next;
            }

            // Create next descriptor because there is no descriptor that is big enough
            BlockDescriptor *newDescriptor = createBlockDescriptor(size);
            descriptor->Next = newDescriptor;
            return(newDescriptor);
        }
Example #5
0
        public MTLGraphicsDevice(
            GraphicsDeviceOptions options,
            SwapchainDescription?swapchainDesc)
        {
            _device       = MTLDevice.MTLCreateSystemDefaultDevice();
            MetalFeatures = new MTLFeatureSupport(_device);
            Features      = new GraphicsDeviceFeatures(
                computeShader: true,
                geometryShader: false,
                tessellationShaders: false,
                multipleViewports: MetalFeatures.IsSupported(MTLFeatureSet.macOS_GPUFamily1_v3),
                samplerLodBias: false,
                drawBaseVertex: true,
                drawBaseInstance: true,
                drawIndirect: true,
                drawIndirectBaseInstance: true,
                fillModeWireframe: true,
                samplerAnisotropy: true,
                depthClipDisable: true,
                texture1D: true, // TODO: Should be macOS 10.11+ and iOS 11.0+.
                independentBlend: true,
                structuredBuffer: true,
                subsetTextureView: true,
                commandListDebugMarkers: true,
                bufferRangeBinding: true);
            ResourceBindingModel = options.ResourceBindingModel;

            _libSystem           = new NativeLibrary("libSystem.dylib");
            _concreteGlobalBlock = _libSystem.LoadFunction <IntPtr>("_NSConcreteGlobalBlock");
            if (MetalFeatures.IsMacOS)
            {
                _completionHandler = OnCommandBufferCompleted;
            }
            else
            {
                _completionHandler = OnCommandBufferCompleted_Static;
            }
            _completionHandlerFuncPtr  = Marshal.GetFunctionPointerForDelegate <MTLCommandBufferHandler>(_completionHandler);
            _completionBlockDescriptor = Marshal.AllocHGlobal(Unsafe.SizeOf <BlockDescriptor>());
            BlockDescriptor *descriptorPtr = (BlockDescriptor *)_completionBlockDescriptor;

            descriptorPtr->reserved   = 0;
            descriptorPtr->Block_size = (ulong)Unsafe.SizeOf <BlockDescriptor>();

            _completionBlockLiteral = Marshal.AllocHGlobal(Unsafe.SizeOf <BlockLiteral>());
            BlockLiteral *blockPtr = (BlockLiteral *)_completionBlockLiteral;

            blockPtr->isa        = _concreteGlobalBlock;
            blockPtr->flags      = 1 << 28 | 1 << 29;
            blockPtr->invoke     = _completionHandlerFuncPtr;
            blockPtr->descriptor = descriptorPtr;

            if (!MetalFeatures.IsMacOS)
            {
                lock (s_aotRegisteredBlocks)
                {
                    s_aotRegisteredBlocks.Add(_completionBlockLiteral, this);
                }
            }

            ResourceFactory = new MTLResourceFactory(this);
            _commandQueue   = _device.newCommandQueue();

            TextureSampleCount[] allSampleCounts = (TextureSampleCount[])Enum.GetValues(typeof(TextureSampleCount));
            _supportedSampleCounts = new bool[allSampleCounts.Length];
            for (int i = 0; i < allSampleCounts.Length; i++)
            {
                TextureSampleCount count = allSampleCounts[i];
                uint uintValue           = FormatHelpers.GetSampleCountUInt32(count);
                if (_device.supportsTextureSampleCount((UIntPtr)uintValue))
                {
                    _supportedSampleCounts[i] = true;
                }
            }

            if (swapchainDesc != null)
            {
                SwapchainDescription desc = swapchainDesc.Value;
                _mainSwapchain = new MTLSwapchain(this, ref desc);
            }

            PostDeviceCreated();
        }
Example #6
0
 /// <summary>
 /// Sets up the real heap
 /// </summary>
 public static void InitRealHeap()
 {
     firstDescriptor = createBlockDescriptor(MINIMALPAGES * 0x1000);
     useRealHeap     = true;
     Console.WriteLine("[HEAP] Initialized");
 }
Example #7
0
        /// <summary>
        /// Frees a piece of memory
        /// </summary>
        /// <param name="ptr">The pointer</param>
        public static unsafe void Free(void *ptr)
        {
#if HEAP_DEBUG
            if (ptr == null)
            {
                Panic.DoPanic("[HEAP] Free(null)");
            }
#endif

            Block *          block      = getBlockFromPtr(ptr);
            BlockDescriptor *descriptor = block->Descriptor;

#if HEAP_DEBUG
            if (!block->Used)
            {
                Panic.DoPanic("[HEAP] Tried to free a block that was already freed");
            }
#endif

            Mutex.InternalLock(&descriptor->Lock);

            // Not used anymore
            block->Used = false;
            block->Descriptor->FreeSpace += block->Size;
            if ((int)block->Descriptor->FirstFree > (int)block)
            {
                block->Descriptor->FirstFree = block;
            }

            // Merge forward
            if (block->Next != null && !block->Next->Used)
            {
                Block *next = block->Next;
                block->Size += next->Size;
                block->Next  = next->Next;

                if ((int)block->Descriptor->FirstFree > (int)next)
                {
                    block->Descriptor->FirstFree = next;
                }

                if (next->Next != null)
                {
                    next->Next->Prev = block;
                }
            }

            // Merge backwards
            if (block->Prev != null && !block->Prev->Used)
            {
                Block *prev = block->Prev;
                prev->Size += block->Size;
                prev->Next  = block->Next;

                if ((int)block->Descriptor->FirstFree > (int)prev)
                {
                    block->Descriptor->FirstFree = prev;
                }

                if (block->Next != null)
                {
                    block->Next->Prev = prev;
                }
            }

            Mutex.InternalUnlock(&descriptor->Lock);
        }
Example #8
0
        /// <summary>
        /// Allocates an aligned piece of memory
        /// </summary>
        /// <param name="alignment">The alignment</param>
        /// <param name="size">The size</param>
        public static unsafe void *AlignedAlloc(int alignment, int size)
        {
#if HEAP_DEBUG
            if (size <= 0)
            {
                Panic.DoPanic("[HEAP] size <= 0");
            }

            if (alignment <= 0)
            {
                Panic.DoPanic("[HEAP] alignment <= 0");
            }
#endif

            if (useRealHeap)
            {
                // Find a descriptor that is big enough to hold the block header and its data
                // We need to look for something that can hold an aligned size if alignment is requested
                size += sizeof(Block);

                // Safe size
                if (size % alignment != 0)
                {
                    size  = size - (size % alignment);
                    size += alignment;
                }

                Block *          currentBlock  = null;
                Block *          previousBlock = null;
                BlockDescriptor *descriptor    = getSufficientDescriptor(null, size);

                if (descriptor == null)
                {
                    Panic.DoPanic("[HEAP] descriptor == null");
                }

retry:

                currentBlock  = descriptor->FirstFree;
                previousBlock = null;

                // Lock descriptor
                Mutex.InternalLock(&descriptor->Lock);

                // Search in the descriptor
                while (true)
                {
                    // Can fit in here
                    if (currentBlock->Used || currentBlock->Size < size)
                    {
                        goto nextBlock;
                    }

#if HEAP_USE_MAGIC
                    if (currentBlock->Magic != HEAP_MAGIC)
                    {
                        Panic.DoPanic("currentBlock->Magic != HEAP_MAGIC");
                    }
#endif

                    // Check if this block data would be aligned
                    int currentData = (int)currentBlock + sizeof(Block);
                    int remainder   = currentData % alignment;

                    // Not aligned
                    if (remainder != 0)
                    {
                        // Split the current block into two
                        // The first part is a padding
                        // The second part is the block we want for allocation
                        // This only happens if there is enough space left

                        // Size of gap
                        int gapSize = alignment - remainder;
                        int newSize = currentBlock->Size - gapSize;

                        // Would the new block be too small to fit our data into?
                        if (newSize < size)
                        {
                            goto nextBlock;
                        }

                        // Store old data
                        Block *newNext = currentBlock->Next;
                        bool   newUsed = currentBlock->Used;

                        // Move block forward
                        currentBlock             = (Block *)((int)currentBlock + gapSize);
                        currentBlock->Used       = newUsed;
                        currentBlock->Prev       = previousBlock;
                        currentBlock->Next       = newNext;
                        currentBlock->Size       = newSize;
                        currentBlock->Descriptor = descriptor;

                        // Increase size of previous block if needed
                        if (previousBlock != null)
                        {
                            previousBlock->Next  = currentBlock;
                            previousBlock->Size += gapSize;

                            // If the block is used and the gap is merged
                            // that means that the total free space in this descriptor decreases
                            if (currentBlock->Used)
                            {
                                descriptor->FreeSpace -= gapSize;
                            }
                        }
                        // There's space left to move this block and let the first block point to the new one
                        else if (gapSize >= sizeof(Block))
                        {
                            // Update first block
                            Block *first = descriptor->First;
                            descriptor->FreeSpace -= gapSize;

                            first->Used       = false;
                            first->Prev       = null;
                            first->Next       = currentBlock;
                            first->Size       = gapSize;
                            first->Descriptor = descriptor;
#if HEAP_USE_MAGIC
                            first->Magic = HEAP_MAGIC;
#endif
                            currentBlock->Prev = first;
                        }
                        // This is the first block that was moved
                        else
                        {
                            // Update header
                            descriptor->First     = currentBlock;
                            descriptor->FirstFree = currentBlock;
                        }
                    }

                    // Calculate leftover part for the next block
                    int leftover = currentBlock->Size - size;

                    // Update header
                    currentBlock->Used       = true;
                    currentBlock->Descriptor = descriptor;
                    currentBlock->Prev       = previousBlock;
#if HEAP_USE_MAGIC
                    currentBlock->Magic = HEAP_MAGIC;
#endif

                    // Update descriptor
                    descriptor->FreeSpace -= size;

                    // If we have something left over, create a new block
                    if (leftover > sizeof(Block) + 4)
                    {
                        // Update header
                        Block *afterBlock = (Block *)((int)currentBlock + size);
                        afterBlock->Size       = leftover;
                        afterBlock->Used       = false;
                        afterBlock->Next       = currentBlock->Next;
                        afterBlock->Prev       = currentBlock;
                        afterBlock->Descriptor = descriptor;

#if HEAP_USE_MAGIC
                        afterBlock->Magic = HEAP_MAGIC;
#endif

                        if (currentBlock->Next != null)
                        {
                            currentBlock->Next->Prev = afterBlock;
                        }

                        currentBlock->Next = afterBlock;
                        currentBlock->Size = size;

                        // Update descriptor
                        if ((int)currentBlock < (int)descriptor->FirstFree)
                        {
                            descriptor->FirstFree = currentBlock;
                        }
                    }

                    // Return block (skip header)
                    Mutex.InternalUnlock(&descriptor->Lock);
                    return((void *)((int)currentBlock + sizeof(Block)));

                    // Next block
nextBlock:
                    {
                        previousBlock = currentBlock;
                        currentBlock  = currentBlock->Next;
                        Mutex.InternalUnlock(&descriptor->Lock);
                        if (currentBlock == null)
                        {
                            // This was the last block in the descriptor
                            // Due to alignment issues we haven't found a good place
                            // Get another descriptor that has enough free space
                            descriptor = getSufficientDescriptor(descriptor, size);
                            goto retry;
                        }
                    }
                }
            }
            else
            {
                if (alignment == 0x1000)
                {
                    return(KAlloc(size, true));
                }
                else if (alignment == 4)
                {
                    return(KAlloc(size, false));
                }
                else
                {
                    Panic.DoPanic("[HEAP] Unsupported alignment in early allocation");
                    return(null);
                }
            }
        }