<commit_before>//
//  HeatMapGPU.swift
//  CAVOK
//
//  Created by <NAME> on 06/10/2016.
//  Copyright © 2016 <NAME>. All rights reserved.
//

import Foundation

import Metal

class HeatMapGPU {
    
    private var outTexture: MTLTexture? = nil
    
    init(input: [HeatData], config: WeatherConfig, steps: GridSteps) {
        guard let device = MTLCreateSystemDefaultDevice(),
            let defaultLibrary = device.newDefaultLibrary()
            else { return }
        
        
        let commandQueue = device.makeCommandQueue()
        
        let kernelFunction = defaultLibrary.makeFunction(name: "heatMapShader")
        let pipelineState = try! device.makeComputePipelineState(function: kernelFunction!)
        
        let width = config.width
        let height = config.height
        
        var arr = input.flatMap { i in [i.x, i.y, i.value] }
        
        var steps = [steps.purple.int4(), steps.red.int4(), steps.orange.int4(), steps.yellow.int4(), steps.green.int4(), steps.blue.int4()].flatMap { $0 }
        
        print("start \(config.width)x\(config.height) \(arr)")
        let outTextureDescriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .rgba8Unorm, width: width, height: height, mipmapped: false)
        self.outTexture = device.makeTexture(descriptor: outTextureDescriptor)
        
        let commandBuffer = commandQueue.makeCommandBuffer()
        let commandEncoder = commandBuffer.makeComputeCommandEncoder()
        
        commandEncoder.setComputePipelineState(pipelineState)
        commandEncoder.setTexture(self.outTexture, at: 0)
        
        var radius = config.radius
        commandEncoder.setBytes(&radius, length: MemoryLayout<Int32>.stride, at: 0)
        
        var count = input.count
        commandEncoder.setBytes(&count, length: MemoryLayout<Int32>.stride, at: 1)
        
        let dataBuffer = device.makeBuffer(bytes: &arr, length: MemoryLayout<Int32>.stride * arr.count, options: .storageModeShared)
        commandEncoder.setBuffer(dataBuffer, offset: 0, at: 2)
        
        let stepsBuffer = device.makeBuffer(bytes: &steps, length: MemoryLayout<Int32>.stride * steps.count, options: .storageModeShared)
        commandEncoder.setBuffer(stepsBuffer, offset: 0, at: 3)
        
        let threadGroupCount = MTLSizeMake(1, 1, 1)
        let threadGroups = MTLSizeMake(width / threadGroupCount.width, height / threadGroupCount.height, 1)
        
        commandEncoder.dispatchThreadgroups(threadGroups, threadsPerThreadgroup: threadGroupCount)
        
        commandEncoder.endEncoding()
        commandBuffer.commit()
        
        commandBuffer.waitUntilCompleted()
        
        print("done \(commandBuffer.error) \(commandBuffer.status.rawValue)")
    }
    
    func render() -> CGImage? {
        guard let outTexture = outTexture else {
            return nil<commit_msg>Fix crash of Metal shader when there is no data.<commit_after>//
//  HeatMapGPU.swift
//  CAVOK
//
//  Created by <NAME> on 06/10/2016.
//  Copyright © 2016 <NAME>. All rights reserved.
//

import Foundation

import Metal

class HeatMapGPU {
    
    private var outTexture: MTLTexture? = nil
    
    init(input: [HeatData], config: WeatherConfig, steps: GridSteps) {
        guard let device = MTLCreateSystemDefaultDevice(),
            let defaultLibrary = device.newDefaultLibrary()
            else { return }
        
        
        let commandQueue = device.makeCommandQueue()
        
        let kernelFunction = defaultLibrary.makeFunction(name: "heatMapShader")
        let pipelineState = try! device.makeComputePipelineState(function: kernelFunction!)
        
        let width = config.width
        let height = config.height

        let outTextureDescriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .rgba8Unorm, width: width, height: height, mipmapped: false)
        self.outTexture = device.makeTexture(descriptor: outTextureDescriptor)
        
        var arr = input.flatMap { i in [i.x, i.y, i.value] }
        if (arr.isEmpty) {
            return;
        }
        
        print("start \(config.width)x\(config.height) \(arr)")
        
        let commandBuffer = commandQueue.makeCommandBuffer()
        let commandEncoder = commandBuffer.makeComputeCommandEncoder()
        
        commandEncoder.setComputePipelineState(pipelineState)
        commandEncoder.setTexture(self.outTexture, at: 0)
        
        var radius = config.radius
        commandEncoder.setBytes(&radius, length: MemoryLayout<Int32>.stride, at: 0)
        
        var count = input.count
        commandEncoder.setBytes(&count, length: MemoryLayout<Int32>.stride, at: 1)
        
        let dataBuffer = device.makeBuffer(bytes: &arr, length: MemoryLayout<Int32>.stride * arr.count, options: .storageModeShared)
        commandEncoder.setBuffer(dataBuffer, offset: 0, at: 2)

        var steps = [steps.purple.int4(), steps.red.int4(), steps.orange.int4(), steps.yellow.int4(), steps.green.int4(), steps.blue.int4()].flatMap { $0 }
        let stepsBuffer = device.makeBuffer(bytes: &steps, length: MemoryLayout<Int32>.stride * steps.count, options: .storageModeShared)
        commandEncoder.setBuffer(stepsBuffer, offset: 0, at: 3)
        
        let threadGroupCount = MTLSizeMake(1, 1, 1)
        let threadGroups = MTLSizeMake(width / threadGroupCount.width, height / threadGroupCount.height, 1)
        
        commandEncoder.dispatchThreadgroups(threadGroups, threadsPerThreadgroup: threadGroupCount)
        
        commandEncoder.endEncoding()
        commandBuffer.commit()
        
        commandBuffer.waitUntilCompleted()
        
        print("done \(commandBuffer.error) \(commandBuffer.status.rawValue)")
    }
    
    func render() -> CGImage? {
        guard let outTexture = outTexture else {
            return nil
{'fraction_non_alphanumeric': 0.10122908842608398, 'fraction_numerical': 0.013656538067599864, 'mean_word_length': 2.641392169049099, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '232717', 'n_tokens_mistral': 1651, 'n_tokens_neox': 1591, 'n_words': 365}