लेयर मॉडल
परिचय
ज़्यादातर वेब डेवलपर के लिए, वेब पेज का बुनियादी मॉडल डीओएम होता है. किसी पेज को रेंडर करने की प्रोसेस में अक्सर किसी पेज को रेंडर करना बहुत आसान नहीं होता है. इसकी मदद से, स्क्रीन पर दिखाई जाने वाली इमेज को इमेज में बदला जा सकता है. आधुनिक ब्राउज़र ने ग्राफ़िक्स कार्ड का लाभ उठाने के लिए हाल ही के सालों में रेंडरिंग के काम करने का तरीका बदल दिया है: इसे अक्सर “हार्डवेयर से तेज़ी लाएं” कहा जाता है. किसी सामान्य वेब पेज (जैसे, Canvas2D या WebGL नहीं) के बारे में बात करते समय, उस शब्द का क्या मतलब है? यह लेख उस बेसिक मॉडल के बारे में बताता है जो Chrome में वेब कॉन्टेंट की हार्डवेयर ऐक्सेलरेटेड रेंडरिंग को तैयार करता है.
बड़े, फ़ैटी सीमाएं
यहां हम WebKit के बारे में बात कर रहे हैं. साथ ही, खास तौर पर हम WebKit के Chromium पोर्ट की बात कर रहे हैं. इस लेख में Chrome को लागू करने से जुड़ी जानकारी दी गई है, न कि वेब प्लैटफ़ॉर्म की सुविधाओं के बारे में. वेब प्लैटफ़ॉर्म और स्टैंडर्ड, इस लेवल की जानकारी लागू नहीं करते. इसलिए, इस बात की कोई गारंटी नहीं है कि इस लेख में दी गई जानकारी दूसरे ब्राउज़र पर लागू होगी. हालांकि, अंदरूनी जानकारी की मदद से, डीबग करने और परफ़ॉर्मेंस को बेहतर बनाने में मदद मिल सकती है.
साथ ही, ध्यान दें कि इस पूरे लेख में Chrome के रेंडरिंग आर्किटेक्चर के मुख्य हिस्से के बारे में बताया गया है. यह आर्किटेक्चर बहुत तेज़ी से बदल रहा है. इस लेख में सिर्फ़ ऐसी जानकारी दी गई है जिसमें बदलाव होने की संभावना नहीं है. हालांकि, इस बात की कोई गारंटी नहीं है कि ये सब छह महीनों में लागू हो जाएंगे.
यह समझना ज़रूरी है कि पिछले कुछ समय से, Chrome के पास दो अलग-अलग रेंडरिंग पाथ हैं: हार्डवेयर-एक्सेलरेटेड पाथ और पुराना सॉफ़्टवेयर पाथ. इस तरह सभी पेज, Windows, ChromeOS, और Android के लिए Chrome पर, हार्डवेयर ऐक्सेलरेटेड पाथ पर चले जाते हैं. Mac और Linux में केवल ऐसे पेज, जिनमें अपनी कुछ सामग्री के लिए कंपोज़िटिंग की आवश्यकता होती है, त्वरित पथ में नीचे जाते हैं (इसके लिए कंपोज़िटिंग की आवश्यकता के बारे में नीचे देखें), लेकिन जल्द ही सभी पेज वहां भी त्वरित पथ में चले जाएंगे.
आखिर में, हम रेंडरिंग इंजन के बारे में ज़्यादा जानकारी हासिल करने की कोशिश कर रहे हैं. साथ ही, हम इसकी ऐसी सुविधाओं के बारे में पता कर रहे हैं जिनसे परफ़ॉर्मेंस पर काफ़ी असर पड़ता है. अपनी साइट की परफ़ॉर्मेंस को बेहतर बनाने की कोशिश करते समय, लेयर मॉडल को समझना मददगार हो सकता है. हालांकि, खुद को पैर से शूट करना भी आसान होता है: लेयर इस्तेमाल करना उपयोगी होता है, लेकिन बहुत सारी लेयर बनाने से पूरे ग्राफ़िक स्टैक में ओवरहेड हो सकता है. खुद को पहले से तैयार रखें!
डीओएम से स्क्रीन तक
पेश है लेयर
पेज के लोड और पार्स हो जाने के बाद, उसे ब्राउज़र में एक स्ट्रक्चर के तौर पर दिखाया जाता है. इसके बारे में कई वेब डेवलपर को पता है: DOM. हालांकि, किसी पेज को रेंडर करते समय, ब्राउज़र में कई इंटरमीडिएट प्रज़ेंटेशन मौजूद होते हैं. ये डेवलपर को सीधे तौर पर नहीं दिखते. इन स्ट्रक्चर में सबसे ज़रूरी है लेयर.
Chrome में असल में कई तरह की लेयर होती हैं: Renderlayers, जो डीओएम के सब-ट्री के लिए ज़िम्मेदार हैं और Graphicslayers, जो Renderlayers के सब-ट्री के लिए ज़िम्मेदार हैं. यहां बाद वाला विकल्प हमारे लिए सबसे दिलचस्प है, क्योंकि Graphicslayers को ही जीपीयू में, टेक्सचर के तौर पर अपलोड किया जाता है. मैं यहां से बस 'लेयर' बोलूंगा, जिसका मतलब है Graphicslayer.
जीपीयू से जुड़ी शब्दावली को जानें: बनावट क्या है? इसे किसी बिटमैप इमेज की तरह समझें, जिसे मुख्य मेमोरी (जैसे, रैम) से वीडियो मेमोरी (जैसे कि आपके जीपीयू पर वीआरएएम) में ले जाया जाता है. जीपीयू पर आने के बाद, इसे मेश ज्यामिति पर मैप किया जा सकता है -- वीडियो गेम या सीएडी प्रोग्राम में, इस तकनीक का इस्तेमाल स्केलेटल 3D मॉडल को “स्किन” देने के लिए किया जाता है. Chrome, वेब पेज का कुछ कॉन्टेंट जीपीयू पर लाने के लिए, टेक्सचर का इस्तेमाल करता है. टेक्स्चर को सही रेक्टैंगल मेश पर लागू करके, उन्हें अलग-अलग पोज़िशन और ट्रांसफ़ॉर्मेशन के लिए किफ़ायती तरीके से मैप किया जा सकता है. 3D सीएसएस इसी तरह काम करती है और यह तेज़ स्क्रोलिंग के लिए भी बेहतरीन है. हालांकि, बाद में इन दोनों के बारे में और भी बेहतर तरीके से बताया जा सकता है.
लेयर के कॉन्सेप्ट को समझाने के लिए, कुछ उदाहरण देखें.
Chrome में लेयर का अध्ययन करते समय, "रेंडरिंग" हेडिंग के तहत, Dev टूल की सेटिंग में "कंपोज़िट किए गए लेयर बॉर्डर दिखाएं" फ़्लैग (उदाहरण के लिए, छोटा कॉग आइकॉन) एक बहुत ही मददगार टूल है. यह स्क्रीन पर लेयर की जगह आसानी से हाइलाइट करता है. आइए इसे चालू करें. यह लेख लिखते समय, ये स्क्रीनशॉट और उदाहरण Chrome कैनरी के सबसे नए वर्शन Chrome 27 से लिए गए हैं.
इमेज 1: एक लेयर वाला पेज
<!doctype html>
<html>
<body>
<div>I am a strange root.</div>
</body>
</html>
इस पेज में सिर्फ़ एक लेयर है. नीला ग्रिड, टाइल को दिखाता है. इन्हें किसी लेयर की सब-यूनिट माना जा सकता है. Chrome इसका इस्तेमाल, किसी बड़ी लेयर के कुछ हिस्सों को एक बार में जीपीयू पर अपलोड करने के लिए करता है. यहां उनकी कोई अहमियत नहीं है.
इमेज 2: अपनी लेयर में कोई एलिमेंट
<!doctype html>
<html>
<body>
<div style="transform: rotateY(30deg) rotateX(-30deg); width: 200px;">
I am a strange root.
</div>
</body>
</html>
<div>
को घुमाने के लिए, उस पर 3D सीएसएस प्रॉपर्टी डालकर, हम यह देख सकते हैं कि एलिमेंट को अपनी लेयर मिलने पर वह कैसा दिखता है: नारंगी बॉर्डर पर ध्यान दें, जो इस व्यू में एक लेयर को आउटलाइन करता है.
लेयर बनाने की शर्तें
अन्य लेयर को किस तरह की लेयर मिलती है? Chrome के अनुभव में समय के साथ हुए बदलाव हुए हैं और यह आगे भी बढ़ रही है. हालांकि, फ़िलहाल इनमें से कोई भी ट्रिगर लेयर बनाया जा रहा है:
- 3D या पर्सपेक्टिव ट्रांसफ़ॉर्म सीएसएस प्रॉपर्टी
<video>
एलिमेंट, जो फटाफट वीडियो डिकोड करने की सुविधा का इस्तेमाल कर रहे हैं- 3D (WebGL) कॉन्टेक्स्ट या एक्सेलरेटेड 2D कॉन्टेक्स्ट वाले
<canvas>
एलिमेंट - कंपोज़िट प्लगिन (जैसे कि Flash)
- अपारदर्शिता के लिए सीएसएस ऐनिमेशन वाले एलिमेंट या एनिमेटेड ट्रांसफ़ॉर्म का इस्तेमाल कर रहे हैं
- Accelerated CSS फ़िल्टर वाले एलिमेंट
- एलिमेंट में ऐसा डिसेंडेंट है जिसमें कंपोज़िटिंग लेयर है (दूसरे शब्दों में, अगर एलिमेंट में ऐसा चाइल्ड एलिमेंट मौजूद है जो अपनी लेयर में है)
- एलिमेंट में कम z-इंडेक्स वाला सिबलिंग है, जिसमें एक कंपोज़िटिंग लेयर है (दूसरे शब्दों में, इसे कंपोज़िट लेयर के ऊपर रेंडर किया जाता है)
व्यवहारिक संकेत: ऐनिमेशन
हम लेयर को इधर-उधर भी ले जा सकते हैं. इससे वे ऐनिमेशन के लिए काफ़ी मददगार साबित होती हैं.
इमेज 3: ऐनिमेशन वाली लेयर
<!doctype html>
<html>
<head>
<style>
div {
animation-duration: 5s;
animation-name: slide;
animation-iteration-count: infinite;
animation-direction: alternate;
width: 200px;
height: 200px;
margin: 100px;
background-color: gray;
}
@keyframes slide {
from {
transform: rotate(0deg);
}
to {
transform: rotate(120deg);
}
}
</style>
</head>
<body>
<div>I am a strange root.</div>
</body>
</html>
जैसा कि पहले बताया गया है, स्थिर वेब सामग्री के आस-पास जाने के लिए लेयर बहुत काम की होती हैं. मूल मामले में, Chrome किसी लेयर के कॉन्टेंट को सॉफ़्टवेयर बिटमैप में पेंट करता है. इसके बाद ही, उसे जीपीयू पर टेक्सचर के तौर पर अपलोड करता है. अगर आने वाले समय में वह कॉन्टेंट नहीं बदलता है, तो उसे फिर से पेंट करने की ज़रूरत नहीं है. यह एक अच्छी बात है: रीपेंट करने में समय लगता है, जो दूसरे कामों में खर्च हो सकता है, जैसे JavaScript चलाना. अगर पेंट लंबा है, तो ऐनिमेशन में हिचकिचाएं या देरी होती है.
उदाहरण के लिए, डेवलपर टूल टाइमलाइन का यह व्यू देखें: इस लेयर के आगे-पीछे घूमने के दौरान पेंट की कोई कार्रवाई नहीं होती.
अमान्य! फिर से पेंट करना
लेकिन अगर लेयर का कॉन्टेंट बदल जाता है, तो उसे फिर से पेंट करना होगा.
इमेज 4: लेयर को फिर से पेंट करना
<!doctype html>
<html>
<head>
<style>
div {
animation-duration: 5s;
animation-name: slide;
animation-iteration-count: infinite;
animation-direction: alternate;
width: 200px;
height: 200px;
margin: 100px;
background-color: gray;
}
@keyframes slide {
from {
transform: rotate(0deg);
}
to {
transform: rotate(120deg);
}
}
</style>
</head>
<body>
<div id="foo">I am a strange root.</div>
<input id="paint" type="button" value="repaint">
<script>
var w = 200;
document.getElementById('paint').onclick = function() {
document.getElementById('foo').style.width = (w++) + 'px';
}
</script>
</body>
</html>
इनपुट एलिमेंट पर हर बार क्लिक करने पर, रोटेटिंग एलिमेंट की चौड़ाई 1 पिक्सल हो जाती है. इससे पूरे एलिमेंट को रिलेआउट और रीपेंट किया जाता है, जो इस मामले में एक पूरी लेयर है.
जो पेंट किया गया है उसे देखने का एक अच्छा तरीका है Dev Tools में मौजूद “पेंट रेक्टस दिखाएं” टूल. साथ ही, Dev Tools की सेटिंग में मौजूद “रेंडरिंग” हेडिंग के नीचे. इसे चालू करने के बाद, ध्यान दें कि बटन पर क्लिक करने पर एनिमेटेड एलिमेंट और बटन, दोनों लाल फ़्लैश करते हैं.
पेंट इवेंट, Dev टूल की टाइमलाइन में भी दिखते हैं. तेज़ आंखों वाले पाठकों को पता चल सकता है कि वहां पेंट करने के दो इवेंट हैं: एक लेयर के लिए और दूसरा बटन के लिए. जब यह अपनी उदास स्थिति में आता है या इससे बाहर आता है, तब यह फिर से पेंट हो जाता है.
ध्यान दें कि Chrome को हमेशा पूरी लेयर को फिर से पेंट करने की ज़रूरत नहीं होती. Chrome सिर्फ़ डीओएम के अमान्य हिस्से को ही फिर से पेंट करने की कोशिश करता है. इस मामले में, हमने जिस DOM एलिमेंट में बदलाव किया है वह पूरी लेयर का साइज़ है. लेकिन कई अन्य मामलों में, किसी लेयर में बहुत सारे DOM एलिमेंट होंगे.
अगला सवाल यह है कि अमान्य होने की वजह क्या है और उसे दोबारा पेंट करने के लिए मजबूर किया जाता है. इसका पूरा जवाब देना मुश्किल है, क्योंकि ऐसे कई मामले होते हैं जो अमान्य हो सकते हैं. इसकी सबसे आम वजह, सीएसएस स्टाइल में बदलाव करके या रिलेआउट की वजह से, DOM को गंदा करना है. टोनी गेनिलकोर ने रिलायआउट की वजहों पर एक बेहतरीन ब्लॉग पोस्ट लिखी है. वहीं, स्टोयन स्टेफ़ानोव का एक लेख जिसमें पेंटिंग के बारे में ज़्यादा विस्तार से बताया गया है (हालांकि, आखिर में सिर्फ़ पेंटिंग के बारे में बताया गया है, न कि कॉन्टेंट बनाने के बारे में).
इसकी वजह से आपको पता चल सकता है कि जिस चीज़ पर काम किया जा रहा है उस पर असर पड़ता है या नहीं, Dev Tools की टाइमलाइन और शो पेंट रेक्टैंगल टूल इस्तेमाल करें. इससे, आपको पता चलेगा कि आपके न होने पर भी पेंट किया जा रहा है या नहीं. इसके बाद, रिलेआउट/रीपेंट करने से ठीक पहले यह पता करने की कोशिश करें कि आपने डीओएम को कहां गंदा किया था. अगर पेंटिंग बनाना ज़रूरी है, लेकिन ऐसा लगता है कि इसमें ज़्यादा समय लग रहा है, तो Dev Tools में 'लगातार पेंटिंग' मोड के बारे में Eberhard Gräther का लेख पढ़ें.
इसे एक साथ रखा जा रहा है: DOM को स्क्रीन पर
Chrome, डीओएम को स्क्रीन इमेज में कैसे बदलता है? सैद्धांतिक तौर पर, यह:
- डीओएम को लेता है और उसे लेयर में बांटता है
- इनमें से हर लेयर को सॉफ़्टवेयर बिटमैप में अलग से पेंट करता है
- उन्हें टेक्सचर के तौर पर, जीपीयू पर अपलोड करता है
- यह अलग-अलग लेयर को एक साथ मिलाकर स्क्रीन की फ़ाइनल इमेज बनाता है.
ऐसा तब होता है, जब Chrome पहली बार किसी वेब पेज का फ़्रेम बनाता है. लेकिन फिर यह भावी फ़्रेम के लिए कुछ शॉर्टकट ले सकता है:
- अगर सीएसएस की कुछ प्रॉपर्टी बदल जाती हैं, तो किसी चीज़ को दोबारा पेंट करने की ज़रूरत नहीं है. Chrome बस उन मौजूदा लेयर को टेक्सचर के तौर पर फिर से बना सकता है जो जीपीयू पर पहले से मौजूद हैं. हालांकि, इन्हें अलग-अलग कंपोज़िटिंग प्रॉपर्टी (जैसे कि अलग-अलग पोज़िशन में, अलग-अलग ओपैसिटी वगैरह के साथ) के साथ फिर से कंपोज़िट किया जा सकता है.
- अगर लेयर का कोई हिस्सा अमान्य हो जाता है, तो उसे फिर से पेंट करके फिर से अपलोड किया जाता है. अगर इसका कॉन्टेंट वैसा ही रहता है, लेकिन इसके कंपोज़िट एट्रिब्यूट बदल जाते हैं (जैसे कि इसका अनुवाद हो जाता है या इसकी ओपैसिटी बदलती है), तो Chrome इसे जीपीयू पर छोड़ सकता है और नया फ़्रेम बनाने के लिए फिर से कंपोज़िट कर सकता है.
अब आपको साफ़ तौर पर पता चल गया होगा कि लेयर पर आधारित कंपोज़िटिंग मॉडल, रेंडरिंग की परफ़ॉर्मेंस को बेहतर बनाने के लिए बहुत काम करता है. जब किसी चीज़ को पेंट करने की ज़रूरत नहीं होती, तो कंपोज़िटिंग किफ़ायती होती है. इसलिए, रेंडरिंग परफ़ को डीबग करते समय लेयर को दोबारा पेंट करने से बचना एक अच्छा लक्ष्य है. समझदार डेवलपर ऊपर दिए गए कंपोज़िटिंग ट्रिगर की सूची देखेंगे और उन्हें पता चलेगा कि लेयर बनाना आसानी से लागू किया जा सकता है. लेकिन बिना सोचे-समझे उन्हें बनाएं, क्योंकि ये मुफ़्त नहीं होते हैं: ये सिस्टम की रैम और जीपीयू (खास तौर पर मोबाइल डिवाइसों पर सीमित) में मेमोरी लेते हैं. इनमें से बहुत सारे होने की वजह से तर्क के साथ दूसरे ओवरहेड हो सकते हैं, जिनसे नज़र रखी जा सकती है. कई लेयर, रास्टराइज़ करने में लगने वाले समय को भी बढ़ा सकती हैं. ऐसा तब होता है, जब वे लेयर बड़ी हों और उन लेयर को ओवरलैप कर रही हों जहां वे पहले नहीं थीं. इस वजह से, इस प्रोसेस को कभी-कभी "ओवरड्रॉ" भी कहा जाता है. इसलिए, अपनी जानकारी का इस्तेमाल सोच-समझकर करें!
अभी के लिए बस इतना ही. लेयर मॉडल के व्यावहारिक नतीजों के बारे में कुछ और लेखों के लिए हमारे साथ बने रहें.