2015-01-31 6 views
0

layers: [CGImageRef]의 일부를 내 맞춤 NSViewdrawLayer(thisLayer: CALayer!, inContext ctx: CGContext!) 루틴에 알파 혼합하려고합니다. 지금까지 나는 그 레이어를 drawLayer 컨텍스트에 그리는 데 CGContextDrawImage()을 사용했습니다. 프로파일 링 중에 CGContextDrawImage()은 CPU 시간의 70 %를 필요로하므로 Accelerate 프레임 워크를 사용해보기로 결정했습니다. 코드를 변경했지만 충돌이 발생하고 이유가 무엇인지 알 수 없습니다.vImageAlphaBlend가 충돌 함

나는 이런 식으로 그 레이어를 만드는거야 :이 같은

func addLayer() { 
    let colorSpace: CGColorSpaceRef = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB) 
    let bitmapInfo = CGBitmapInfo(CGImageAlphaInfo.PremultipliedFirst.rawValue) 

    var layerContext = CGBitmapContextCreate(nil, UInt(canvasSize.width), UInt(canvasSize.height), 8, UInt(canvasSize.width * 4), colorSpace, bitmapInfo) 
    var newLayer = CGBitmapContextCreateImage(layerContext) 

    layers.append(newLayer) 
} 

내 drawLayers 일상적인 외모 :

override func drawLayer(thisLayer: CALayer!, inContext ctx: CGContext!) 
{ 
    var ctxImageBuffer = vImage_Buffer(data:CGBitmapContextGetData(ctx), 
     height:CGBitmapContextGetHeight(ctx), 
     width:CGBitmapContextGetWidth(ctx), 
     rowBytes:CGBitmapContextGetBytesPerRow(ctx)) 

    for imageLayer in layers 
    { 
     //CGContextDrawImage(ctx, CGRect(origin: frameOffset, size: canvasSize), imageLayer) 

     var inProvider:CGDataProviderRef = CGImageGetDataProvider(imageLayer) 
     var inBitmapData:CFDataRef = CGDataProviderCopyData(inProvider) 
     var buffer:vImage_Buffer = vImage_Buffer(data: &inBitmapData, height: 
      CGImageGetHeight(imageLayer), width: CGImageGetWidth(imageLayer), rowBytes: 
      CGImageGetBytesPerRow(imageLayer)) 

     vImageAlphaBlend_ARGB8888(&buffer, &ctxImageBuffer, &ctxImageBuffer, 0) 
    } 
} 

canvasSize가에 allways 동일하며 모든 레이어가 같은 크기를 가지고, 그래서 나는 왜 마지막 줄이 망가 졌는지 이해하지 못한다.

또한 CGLayerRefs에서 직접 vImageBuffers를 만드는 새로운 편리한 함수를 사용하는 방법을 알지 못합니다. 그것이 내가 복잡한 방식으로하는 이유입니다.

도움을 주시면 감사하겠습니다.

편집

inBitmapData 실제로 내가 설정 한 배경 색상을 반영 픽셀 데이터를 보유하고 있습니다. 그러나 디버거 po &inBitmapData을 할 수 없습니다이 메시지와 함께 실패합니다

error: reference to 'CFData' not used to initialize a inout parameter &inBitmapData

그래서 내가 inBitmapData에 대한 포인터를 얻을 수있는 방법을 찾았다. 그것이 내가 생각해 낸 것입니다.

알파 블렌드 입력에 필요한 두 버퍼의 데이터를 가리키는 방식을 변경해야했습니다. 이제는 더 이상 충돌하지 않고 운좋게도 속도 향상은 프로파일 러 (vImageAlphaBlend 만 약 CGContextDrawImage의 3 분의 1이 소요됩니다)에서 검사 할 수 있지만 불행히도 이미지는 흰색 이미지 배경 대신 픽셀 오류가있는 투명한 이미지를 만듭니다.

지금까지 런타임 오류가 더 이상 발생하지 않았지만 결과가 예상 한 것과 같지 않기 때문에 알파 블렌딩 기능을 올바르게 사용하지 않을까 우려됩니다.

답변

3

vImage_Buffer.data는 CFDataRef가 아니라 CFData 데이터 (픽셀 데이터)를 가리켜 야합니다.

또한 모든 이미지가 4 채널, 채널당 8 비트 데이터로 데이터를 저장하지는 않습니다. 3 채널 또는 RGBA 또는 단색으로 밝혀지면 더 많은 충돌 또는 재미있는 색상이 나타날 수 있습니다. 또한 원시 이미지 데이터가 미리 곱셈되지 않았다고 가정 했으므로 안전한 가정이 아닐 수도 있습니다.

원시 이미지 데이터의 형식과 색 공간을 보장 할 수 있도록 vImageBuffer_initWithCGImage를 사용하는 것이 좋습니다. 이 기능에 대한보다 구체적인 질문은 귀하의 혼란을 해결하는 데 도움이 될 수 있습니다.

일부 CG 호출은 vImage에서 작업을 수행합니다. 이런 식으로 코드를 재 작성하면 이러한 경우 이익이 없을 수 있습니다. 일반적으로 가장 먼저해야 할 일은 CG 콜의 백 트레이스를주의 깊게보고 왜 그렇게 많은 일을하는지 이해하려고 시도하는 것입니다. 대답은 종종 색상 공간 변환입니다. 나는 CGBitmapInfo와 드로잉 표면의 색상 공간과 이미지를주의 깊게보고, 좀 더 잘 어울리도록 할 수있는 방법이 없는지 확인합니다.

IIRC, CALayerRef는 일반적으로 더 나은 GPU 액세스를 위해 비 캐시 가능 스토리지에 데이터를 보유합니다. 이로 인해 CPU에 문제가 발생할 수 있습니다. 데이터가 CALayerRef에있는 경우 CA에서 합성 작업을 수행합니다. 또한 CALayers는 거의 항상 BGRA 8 비트 미리 곱셈을했다고 생각했습니다. 합성 작업을 수행하기 위해 CA를 사용하지 않을 경우 올바른 vImage 기능은 아마도 vImagePremultipliedAlphaBlend_RGBA/BGRA8888 일 것입니다.

+0

먼저 불편을 끼쳐 드려 죄송합니다. 문제를 해결할 수 없습니다. CFDataRef는 CFData의 타입 앨리어스이므로 충돌을 야기하지 않아 어쨌든 CFData로 변경되었습니다. 모든 레이어는 addLayer 함수로 만들어 지므로 미리 곱셈 된 알파가있는 네 개의 동일한 채널을 사용합니다. 내 문제를 게시하기 전에 RGBA (.PremultipliedLast)를 사용했지만 신속한 컴파일러는 vImagePremultipliedAlphaBlend_RGBA8888 매크로를 인식하지 못해 .PremultipliedFirst로 레이어를 만들었고 vImagePremultipliedAlphaBlend_ARGB8888도 시도했습니다. – Enie

+0

또한 vImageBuffer_initWithCGImage 함수에 관해서는 사용 방법을 지적 할 수 있습니까? 나는 이미 여기에 관한 질문을 발견했다 : http://stackoverflow.com/questions/26755978/fatal-error-unexpectedly-found-nil-while-unwrapping-an-optional-value-while-u 마지막 해결책은 해당 데이터로 nil을 사용하여 vImageBuffer 구조체를 만듭니다. vImageBuffer_initWithCGImage가 CGImage 데이터를 nil이 가리키는 곳으로 쓸 수 있는지 확실하지 않습니다. vImageCreateCGImageFromBuffer를 사용하여 vImageBuffer에서 CGImage를 만들려고 할 때 잘못된 액세스 오류가 발생하는 동안 프로그램이 중단됩니다. – Enie

+0

Swift에서 불안정하지만 & inBitmapData를 수행하면 CFDataRef에 대한 포인터를 반환하거나 CFDataGetBytePtr을 반환합니다. (inBitmapData). 이전 버전 인 경우 vImage가 CFDataRef 객체에 대한 포인터가 아니라 픽셀에 대한 포인터를 기대하기 때문에 충돌이 발생할 수 있습니다. 어쨌든 vImageBuffer_initWithCGImage와 vImageBuffer_Init은 모두 할당되었지만 초기화되지 않은 vImage_Buffer를 가져 와서 내용을 채 웁니다. 또한 vImage_Buffer.data에 대한 스토리지를 할당합니다. 작업이 끝나면 (buffer.data)를 비워야합니다. (왜 아직도 CG로 CA 레이어를 합성하고 있는지 궁금합니다.) –