सबसे पहले, अगर आप को समझने के लिए क्या हुड के नीचे हो रहा है चाहते हैं, आप Android Graphics Architecture document पढ़ने की जरूरत है। यह लंबा है, लेकिन यदि आप ईमानदारी से "क्यों" समझना चाहते हैं, तो यह शुरू करने का स्थान है।
TextureView
TextureView बारे में इस तरह से काम करता है: यह एक सतह है, जो एक निर्माता-उपभोक्त रिश्ते के साथ बफ़र्स की एक कतार है। यदि आप सॉफ़्टवेयर (कैनवास) प्रतिपादन का उपयोग कर रहे हैं, तो आप सतह को लॉक करते हैं, जो आपको बफर देता है; आप इसे आकर्षित करते हैं; फिर आप सतह को अनलॉक करते हैं, जो उपभोक्ता को बफर भेजता है। इस मामले में उपभोक्ता एक ही प्रक्रिया में है, और इसे सतह के मिश्रण या (आंतरिक रूप से, अधिक उपयुक्त) जीएलकंस्यूमर कहा जाता है। यह बफर को ओपनजीएल ईएस बनावट में परिवर्तित करता है, जिसे फिर दृश्य में प्रस्तुत किया जाता है।
यदि आप हार्डवेयर त्वरण को बंद करते हैं, तो GLES अक्षम है, और TextureView कुछ भी नहीं कर सकता है। यही कारण है कि जब आप हार्डवेयर त्वरण बंद कर दिया तो आपको कुछ भी नहीं मिला। The documentation बहुत विशिष्ट है: "TextureView का उपयोग केवल हार्डवेयर त्वरित विंडो में किया जा सकता है। सॉफ़्टवेयर में प्रस्तुत किए जाने पर, TextureView कुछ भी नहीं खींचा जाएगा।"
यदि आप एक गंदे आय निर्दिष्ट करते हैं, तो सॉफ्टवेयर रेंडरर में पिछली सामग्री को प्रतिपादन के बाद पूरा कर देगा। मुझे विश्वास नहीं है कि यह एक क्लिप रेक्ट सेट करता है, इसलिए यदि आप DrawColor() को कॉल करते हैं, तो आप पूरी स्क्रीन भर देंगे, और उसके बाद उन पिक्सल को ओवरराइट किया जाएगा। यदि आप वर्तमान में क्लिप रेक्ट सेट नहीं कर रहे हैं, तो आप ऐसा करने से कुछ प्रदर्शन लाभ देख सकते हैं। (हालांकि मैंने कोड को चेक नहीं किया था।)
गंदे रेक्ट एक इन-आउट पैरामीटर है। जब आप lockCanvas()
पर कॉल करते हैं, तो आप जिस रेक्ट को चाहते हैं उसे पास करते हैं, और सिस्टम को कॉल रिटर्न से पहले इसे संशोधित करने की अनुमति है। (व्यावहारिक रूप से, ऐसा करने का एकमात्र कारण यह होगा कि अगर कोई पिछला फ्रेम नहीं था या सतह का आकार बदल दिया गया था, तो इस मामले में यह पूरी स्क्रीन को कवर करने के लिए इसका विस्तार करेगा। मुझे लगता है कि यह अधिक प्रत्यक्ष रूप से संभाला जाएगा "मैंने आपके रेक्ट को अस्वीकार कर दिया" सिग्नल।) आपको वापस आने वाले रेक्ट के अंदर प्रत्येक पिक्सेल को अपडेट करना होगा। आप को रेक्ट को बदलने की अनुमति नहीं देते हैं, जो आप अपने नमूने में करने की कोशिश कर रहे हैं - जो भी lockCanvas()
सफल होने के बाद गंदे आय में है, वह है जिसे आपको आकर्षित करने की आवश्यकता है।
मुझे संदेह है कि गंदा रेक्ट गलत प्रबंधन आपके झटके का स्रोत है। अफसोस की बात है, यह बनाने के लिए एक आसान गलती है, क्योंकि lockCanvas()
dirtyRect
तर्क का व्यवहार केवल the Surface class में ही दस्तावेज किया गया है।
सतह और बफरिंग
सभी सतहों डबल या ट्रिपल बफ़र कर रहे हैं। इसके चारों ओर कोई रास्ता नहीं है - आप एक साथ पढ़ और लिख नहीं सकते और फाड़ नहीं सकते। यदि आप एक बफर चाहते हैं जिसे आप वांछित करते समय संशोधित और धक्का दे सकते हैं, तो उस बफर को लॉक, कॉपी और अनलॉक करने की आवश्यकता होगी, जो संरचना पाइपलाइन में स्टालों बनाता है। सर्वश्रेष्ठ थ्रूपुट और विलंबता के लिए, बफर फ़्लिप बेहतर है।
यदि आप लॉक-कॉपी-अनलॉक व्यवहार चाहते हैं, तो आप इसे स्वयं लिख सकते हैं (या एक पुस्तकालय जो इसे करता है), और यह उतना ही कुशल होगा जितना कि सिस्टम ने आपके लिए किया था (आपको लगता है ब्लिट लूप के साथ अच्छा है)। ऑफ-स्क्रीन कैनवास पर जाएं और बिटमैप को ब्लूट करें, या ओपनजीएल ईएस एफबीओ पर जाएं और बफर को ब्लिट करें। आप ग्राफिका के "record GL app" गतिविधि में उत्तरार्द्ध का एक उदाहरण पा सकते हैं, जिसमें एक मोड है जो एक बार ऑफ-स्क्रीन प्रस्तुत करता है, और फिर दो बार ब्लिट्ज करता है (एक बार डिस्प्ले के लिए, वीडियो रिकॉर्ड करने के लिए एक बार)।
अधिक गति और इस तरह के
वहाँ Android पर पिक्सल आकर्षित करने के लिए दो बुनियादी तरीके हैं: कैनवास के साथ, या ओपन के साथ। एक सतह या बिटमैप को कैनवास प्रतिपादन हमेशा सॉफ्टवेयर में किया जाता है, जबकि ओपीजीएल प्रतिपादन जीपीयू के साथ किया जाता है। एकमात्र अपवाद यह है कि, custom View पर प्रतिपादन करते समय, आप हार्डवेयर त्वरण का उपयोग करने का विकल्प चुन सकते हैं, लेकिन यह SurfaceView या TextureView की सतह पर प्रतिपादन करते समय लागू नहीं होता है।
एक ड्राइंग या पेंटिंग ऐप या तो ड्राइंग कमांड को याद कर सकता है, या बस बफर पर पिक्सेल फेंक सकता है और इसकी स्मृति के रूप में उपयोग कर सकता है। पूर्व गहरा "पूर्ववत" करने की अनुमति देता है, उत्तरार्द्ध बहुत आसान है, और बढ़ने के लिए सामान की मात्रा के रूप में तेजी से बेहतर प्रदर्शन है। ऐसा लगता है जैसे आप बाद वाले करना चाहते हैं, इसलिए ऑफ-स्क्रीन से ब्लिटिंग समझ में आता है।
अधिकांश मोबाइल उपकरणों में 4096x4096 की हार्डवेयर सीमा होती है या जीएलएस बनावट के लिए छोटी होती है, इसलिए आप किसी भी चीज़ के लिए एक बनावट का उपयोग करने में सक्षम नहीं होंगे। आप आकार सीमा मान (GL_MAX_TEXTURE_SIZE) से पूछ सकते हैं, लेकिन आप एक आंतरिक बफर के साथ बेहतर हो सकते हैं जो आप जितना चाहें उतना बड़ा हो, और केवल उस भाग को प्रस्तुत करें जो स्क्रीन पर फिट बैठता है। मुझे नहीं पता कि स्कीया (कैनवास) सीमा क्या है, लेकिन मेरा मानना है कि आप बहुत अधिक बिटमैप्स बना सकते हैं।
आपकी ज़रूरतों के आधार पर, एक SurfaceView एक TextureView के लिए बेहतर हो सकता है, क्योंकि यह मध्यवर्ती जीएलएस बनावट चरण से बचाता है। सतह पर जो कुछ भी आप आकर्षित करते हैं वह सीधे सिस्टम कंपोजिटर (सतहफ्लिंगर) पर जाता है। इस दृष्टिकोण के लिए नीचे की तरफ यह है कि, क्योंकि सतह का उपभोक्ता प्रक्रिया में नहीं है, इसलिए दृश्य प्रणाली को आउटपुट को संभालने का कोई मौका नहीं है, इसलिए सतह एक स्वतंत्र परत है। (एक ड्राइंग प्रोग्राम के लिए यह फायदेमंद हो सकता है - खींची जा रही छवि एक परत पर है, आपका यूआई शीर्ष पर एक अलग परत पर है।)
एफडब्ल्यूआईडब्ल्यू, मैंने कोड को नहीं देखा है, लेकिन डैन सैंडलर के Markers ऐप एक चोटी के लायक हो सकता है (स्रोत कोड here)।
अद्यतन: भ्रष्टाचार identified as a bug और fixed in 'L' था।
4096x4096 बहुत बड़ा है। मुझे आश्चर्य नहीं है कि आपके पास प्रदर्शन समस्याएं हैं। क्या आपको बिल्कुल एक ऐसी छवि चाहिए जो बड़ी है? आप ग्राफिक्स आर्किटेक्चर देख सकते हैं: https://source.android.com/devices/graphics/architecture.html। –
@ डेविड एम हाँ यह एक आवश्यकता है। मैंने कोर ग्राफिक्स, यूआईएसक्रोल व्यू और आईपैड एयर पर आईओएस पर एक समान ऐप बनाया है, प्रदर्शन 4096x4096 पर ठीक है। 2013 नेक्सस 7 को आईपैड एयर से बेहतर प्रदर्शन करना चाहिए या कम से कम तुलनीय मुझे लगता है। – jjxtra
@ डेविड एम मुझे वास्तव में क्या मिलता है यह है कि यदि मैं लॉक कैनवास कॉल को शून्य करता हूं तो प्रदर्शन बहुत अच्छा होता है, लेकिन फिर बनावट की सामग्री दूषित हो जाती है ... यह बहुत अजीब बात है कि लॉक कैनवास (रेक्ट) लॉक से धीमा होगा (नल) ... – jjxtra