2012-01-03 17 views
13

ड्राइंग करते समय प्रदर्शन मैं एक आईओएस ऐप पर काम कर रहा हूं जो डेटा को लाइन-ग्राफ के रूप में देखता है। ग्राफ को CGPath के रूप में पूर्णस्क्रीन कस्टम UIView में खींचा गया है और इसमें अधिकतम 320 डेटा-पॉइंट शामिल हैं। डेटा को अक्सर अद्यतन किया जाता है और ग्राफ को तदनुसार फिर से खींचा जाना चाहिए - 10/सेकंड की रीफ्रेश दर अच्छी होगी।अक्सर CGPaths

अभी तक इतना आसान है। ऐसा लगता है कि, मेरे दृष्टिकोण में बहुत सी CPU समय लगता है। आईफोन 4 एस पर प्रक्रिया के लिए 45% सीपीयू लोड में 320 सेगमेंट के साथ ग्राफ़ को दो बार प्रति सेकंड पर रीफ्रेश करना।

शायद मैं हुड के नीचे ग्राफिक्स-काम को कम से कम समझता हूं, लेकिन मेरे लिए सीपीयू लोड उस कार्य के लिए बहुत कुछ लगता है।

नीचे मेरा drawRect() फ़ंक्शन है जो प्रत्येक बार डेटा का एक नया सेट तैयार होने पर बुलाया जाता है। N अंक की संख्या रखता है और points एक CGPoint* वेक्टर है जो आकर्षित करने के लिए निर्देशांक के साथ है।

- (void)drawRect:(CGRect)rect { 

    CGContextRef context = UIGraphicsGetCurrentContext(); 

    // set attributes 
    CGContextSetStrokeColorWithColor(context, [UIColor lightGrayColor].CGColor); 
    CGContextSetLineWidth(context, 1.f); 

    // create path 
    CGMutablePathRef path = CGPathCreateMutable(); 
    CGPathAddLines(path, NULL, points, N+1); 

    // stroke path 
    CGContextAddPath(context, path); 
    CGContextStrokePath(context); 

    // clean up 
    CGPathRelease(path); 
} 

मैं पहली बार वर्तमान परत के लिए यह here सुझाव के रूप में जोड़ने से पहले एक ऑफ़लाइन CGContext के लिए पथ प्रतिपादन की कोशिश की, लेकिन किसी भी सकारात्मक परिणाम के बिना। मैं सीधे कैलियर को एक दृष्टिकोण ड्राइंग के साथ झुका हुआ था लेकिन इससे भी कोई फर्क नहीं पड़ता।

कोई सुझाव है कि इस कार्य के लिए प्रदर्शन में सुधार कैसे करें? या सीपीयू के लिए प्रतिपादन बस इतना अधिक काम है जिसे मैं महसूस करता हूं? ओपनजीएल कोई समझ/अंतर करेगा?

धन्यवाद/Andi

अद्यतन: मैं भी UIBezierPath बजाय CGPath उपयोग करने की कोशिश। यह पोस्ट here एक अच्छा स्पष्टीकरण देता है कि इससे मदद क्यों नहीं मिली। ट्वीविंग CGContextSetMiterLimit एट अल। भी बड़ी राहत नहीं मिली।

अद्यतन # 2: मैं अंततः ओपनजीएल में स्विच किया। यह एक खड़ी और निराशाजनक सीखने की वक्र थी, लेकिन प्रदर्शन बढ़ावा केवल अविश्वसनीय है। हालांकि, कोरग्राफिक्स एंटी-एलाइजिंग एल्गोरिदम ओपनजीएल में 4x-multisampling के साथ हासिल किए जा सकने वाले चीज़ों की तुलना में एक अच्छा काम करते हैं।

+0

आपका रंग एक निरंतर है:

यहां कुछ नमूना कोड मैंने लिखा है, यह किसी के लिए एक अच्छा प्रारंभिक बिंदु प्रदान करते हैं सकता है। यदि ड्रॉक्ट करें और हर बार एक नया पूछने के बजाए इसका पुन: उपयोग करते रहें तो इसे बाहर ले जाएं। पथ के लिए डितो। चूंकि स्ट्रोकपाथ() "पथ खाली करता है", आप उसी पथ वस्तु का पुन: उपयोग कर सकते हैं। वह क्या बदलता है? – verec

+0

प्रलेखन का दावा है कि पथ खाली हो गया है, लेकिन कम से कम मेरे कोड में यह नहीं है। यह सिर्फ बढ़ता रहता है। रंग के लिए, आपके पास एक बिंदु है। वह बुरा था, लेकिन समाधान नहीं। धन्यवाद। –

+0

आपका मतलब UIBezierPath है, है ना? NSBezierPath केवल मैक पर मौजूद है। –

उत्तर

7

यह पोस्ट here एक अच्छा स्पष्टीकरण देता है कि इससे मदद नहीं मिली।

यह भी बताता है कि आपकी drawRect: विधि धीमी क्यों है।

हर बार जब आप आकर्षित करते हैं तो आप एक CGPath ऑब्जेक्ट बना रहे हैं। आपको ऐसा करने की ज़रूरत नहीं है; जब भी आप अंक के सेट को संशोधित करते हैं तो आपको केवल एक नई CGPath ऑब्जेक्ट बनाने की आवश्यकता होती है। CGPath के निर्माण को एक नई विधि में ले जाएं जिसे आप केवल तभी कॉल करते हैं जब बिंदुओं का सेट बदलता है, और उस विधि को कॉल के बीच CGPath ऑब्जेक्ट को चारों ओर रखें। drawRect: बस इसे पुनर्प्राप्त करें।

आप पहले ही पाए गए हैं कि प्रतिपादन सबसे महंगी चीज है जो आप कर रहे हैं, जो अच्छा है: आप तेजी से प्रतिपादन नहीं कर सकते, क्या आप कर सकते हैं? दरअसल, drawRect: आदर्श रूप से को प्रतिपादन के अलावा कुछ भी नहीं करना चाहिए, इसलिए आपका लक्ष्य 100% तक जितना संभव हो सके उतना करीब रेंडर करने का समय होना चाहिए - जिसका मतलब ड्राइंग कोड से जितना संभव हो उतना सब कुछ ले जाना है।

+0

पीटर, इस उत्तर के लिए धन्यवाद! मैं समझता हूं कि प्रतिपादन वह है जो मैं सीपीयू से पूछता हूं और यह क्या कर रहा है। मैं इसे _this_ पर कब्जा करने के लिए केवल आश्चर्यचकित था। मुझे लगता है, मैं ओपनजीएल को एक शॉट दूंगा और देख सकता हूं कि क्या यह मुझे GPU पर कुछ काम ऑफ़लोड करने में मदद कर सकता है। –

+0

मेरे पास एक ही समस्या है .. और मुझे हर बार एक नया सीजीपैथ बनाना होगा जब भी कोई नया बिंदु आता है .. और यह प्रति सेकेंड 128 बार है –

0

क्या आपने इसके बजाय UIBezierPath का उपयोग करने का प्रयास किया है? UIBezierPath CGPath अंडर-द-हूड का उपयोग करता है, लेकिन यह देखना दिलचस्प होगा कि कुछ सूक्ष्म कारणों के लिए प्रदर्शन अलग है या नहीं। Apple's Documentation से:

आईओएस में पथ बनाने के लिए, यह अनुशंसित है कि आप UIBezierPath बजाय CGPath कार्यों का उपयोग जब तक आप क्षमताओं कि केवल कोर ग्राफिक्स प्रदान करता है, इस तरह के रास्तों को दीर्घवृत्त के रूप में जोड़ने के कुछ की जरूरत है। बनाने और UIKit में रास्तों प्रतिपादन के बारे में अधिक के लिए, "आहरण आकृतियाँ बेज़ियर पथ का उपयोग करना।" देख

मैं था भी CGContext पर विभिन्न गुणों की स्थापना की कोशिश करेगा, विशेष रूप से अलग लाइन में CGContextSetLineJoin() का उपयोग कर शैलियों में शामिल होने के लिए देखें कि क्या इससे कोई फर्क पड़ता है।

क्या आपने उपकरण में टाइम प्रोफाइलर उपकरण का उपयोग करके अपना कोड प्रोफाइल किया है? यह संभवतः यह पता लगाने का सबसे अच्छा तरीका है कि प्रदर्शन बाधा वास्तव में कहां हो रही है, भले ही बाधा प्रणाली ढांचे के अंदर कहीं भी हो।

+0

I NSBezierPath के बारे में एक टिप्पणी के साथ मेरी पोस्ट को अपडेट किया गया और लाइन पैरामीटर को ट्वीक कर दिया गया। टाइम प्रोफाइलर से पता चलता है कि अधिकांश कैलोरी (83%) को एए_रेन्डर के अंदर जला दिया जा रहा है जो कि सीजी का हिस्सा है। –

+0

उपकरण का उपयोग करके प्रोफाइलिंग के बारे में क्या? कोई अंतर्दृष्टि? –

+0

(क्षमा करें, मैंने पहली वाक्य के बाद वापसी पर मारा;)) –

0

मैं इस पर कोई विशेषज्ञ नहीं हूं, लेकिन मुझे पहले क्या संदेह होगा कि यह खुद को प्रस्तुत करने के बजाय 'अंक' को अपडेट करने में समय लग सकता है। इस मामले में, आप बस अंक अपडेट करना बंद कर सकते हैं और उसी पथ को प्रतिपादित करना दोहरा सकते हैं, और देख सकते हैं कि इसमें लगभग उसी CPU समय लगता है या नहीं। यदि नहीं, तो आप अद्यतन एल्गोरिदम पर ध्यान केंद्रित करने में प्रदर्शन को बेहतर बना सकते हैं।

यदि यह वास्तव में प्रतिपादन की समस्या है, तो मुझे लगता है कि ओपनजीएल निश्चित रूप से प्रदर्शन में सुधार करना चाहिए क्योंकि यह सिद्धांत में एक ही समय में सभी 320 लाइनों को प्रस्तुत करेगा।

+0

डेटा अपडेट करना समस्या नहीं है (मैंने टाइम प्रोफाइलर में चेक किया है)। मैंने एक ही रास्ते को बार-बार प्रस्तुत करने से परहेज किया, क्योंकि वास्तविक जीवन में डेटा भी बदल रहा है। और मैं केवल उसी बिटमैप को अपडेट करके सीजी का जीवन आसान बनाना नहीं चाहता था;) इस बिंदु पर, मैं ओपनजीएल से बचने के लिए लड़ रहा हूं, लेकिन अगर मुझे ... –

4

इस पर निर्भर करते हुए कि आप अपना रास्ता कैसे बनाते हैं, यह हो सकता है कि 300 अलग-अलग पथों को चित्रित करना 300 अंकों के साथ एक पथ से तेज़ है। इसका कारण यह है कि अक्सर ड्राइंग एल्गोरिदम ओवरलैपिंग लाइनों को समझने और चौराहे को 'सही' बनाने के तरीके को देखने के लिए देखेगा - जब शायद आप केवल एक दूसरे को ओवरलैप ओवरलैप करने की इच्छा रखते हैं। कई ओवरलैप और चौराहे वाले एल्गोरिदम एन ** 2 या जटिलता में हैं, इसलिए एक पथ में अंकों की संख्या के वर्ग के साथ ड्राइंग स्केल की गति।

यह आपके द्वारा उपयोग किए जाने वाले सटीक विकल्पों (उनमें से कुछ डिफ़ॉल्ट) पर निर्भर करता है। आपको इसे आजमाने की ज़रूरत है।

0

मैंने अपनी परियोजना में धातु का उपयोग करके ऐसा किया है। धातु का उपयोग करने में स्पष्ट रूप से अतिरिक्त जटिलता है, इसलिए आपकी प्रदर्शन आवश्यकताओं के आधार पर, यह उपयुक्त हो सकता है या नहीं भी हो सकता है।

धातु के साथ, सभी काम GPU में किया जाता है और इसलिए CPU उपयोग शून्य के करीब होगा। अधिकांश आईओएस उपकरणों पर आप 60 एफपीएस पर आसानी से कई सौ या कई हजार घटता प्रस्तुत कर सकते हैं। https://github.com/eldade/ios_metal_bezier_renderer