الخامات الملمسية: مستنزف ذاكرة الرسوميات الخفي الذي لم تتوقعه
لماذا تتضخم صورة JPG بحجم 1.5 ميغابايت إلى 87 ميغابايت في ذاكرة الرسوميات؟ وما هي مشكلة صيغ PNG و JPG مع بطاقة الرسوميات؟ وكيف تتكامل تنسيقات GPU الأصلية مع Basis Universal و KTX2؟
في المقال السابق، قمنا بضغط الرؤوس الهندسية وخفض حجم النموذج، لكن الكتلة الكبرى ما تزال قائمة: الخامات الملمسية. في نماذج المواد الفيزيائية (PBR) القياسية، تشكل الخامات أكثر من 80% من حجم الملف، والأهم من ذلك أنها المكون الأساسي الذي يتضخم بشكل هائل بمجرد تحميله في ذاكرة الرسوميات (VRAM).
يركز هذا المقال على حل مشكلة استنزاف الذاكرة عبر ثلاثة محاور رئيسية: لماذا تعد صيغ PNG و JPG قاصرة هندسياً في أعين معالج الرسوميات، وكيف تعمل التنسيقات العتادية الأصلية لبطاقات GPU، وكيف يحل الثنائي Basis Universal و KTX2 هذه المعضلة على الويب.
تذكير سريع: لماذا تنفجر ذاكرة الرسوميات مع ملفات JPG؟
استعرضنا سابقاً المعادلة الأساسية لحساب حجم الذاكرة:
استهلاك ذاكرة VRAM = العرض × الارتفاع × 4 بايت (RGBA) × 1.333 (مع مستويات Mipmaps)
خامة بدقة 4096×4096 بكسل، سواء كانت ملف JPG بحجم 1.5 ميغابايت أو ملف PNG بحجم 8 ميغابايت على القرص، تستهلك حوالي 87 ميغابايت بمجرد دخولها ذاكرة الرسوميات VRAM. والسبب الجوهري هو: معالج الرسوميات GPU لا يفهم صيغ JPG أو PNG مباشرة.
تعتمد وحدة أخذ العينات (Sampler) في GPU على قراءة الألوان من كتل بكسلات ثابتة ومصفوفة في الذاكرة. وتتطلب بقاء الخامات في الذاكرة على هيئة "بكسلات خام مفرودة". لذلك، قبل أن يتمكن المتصفح من إرسال صورة JPG إلى GPU، يجب على المعالج المركزي CPU فك ضغط الصورة بالكامل إلى بكسلات RGBA أولية ثم رفعها إلى الذاكرة.
ينتج عن هذا المسار ثلاثة اختناقات رئيسية:
- انفجار استهلاك الذاكرة: تشغل البكسلات الخام غير المضغوطة مساحة هائلة في الذاكرة (87 ميغابايت لكل خامة بدقة 4K).
- بطء الرفع والتجميد: نقل كميات ضخمة من البكسلات الخام من ذاكرة النظام إلى ذاكرة GPU يستغرق وقتاً طويلاً ويؤخر ظهور أول إطار.
- استنزاف طاقة المعالج CPU: عملية فك التشفير الحسابية تستهلك موارد المعالج، خاصة على الهواتف المحمولة.
إذا طبقنا تشبيه الإسفنجة: فإن PNG و JPG إسفنجتان مضغوطتان ومجففتان يسهل نقلهما عبر الشبكة، لكنهما تمتصان الماء فوراً داخل GPU وتنتفخان إلى الحجم الأقصى، مما يعني عدم توفير أي قدر من ذاكرة الرسوميات.
تنسيقات الخامات الأصلية لبطاقات الرسوميات (GPU-Native Formats)
بما أن معالجات GPU ترفض صيغ PNG المضغوطة، فماذا لو بقيت الخامات مضغوطة داخل ذاكرة الرسوميات نفسها، بحيث يقوم العتاد بفك تشفير الكتل الصغيرة لحظياً عند الحاجة؟
هذا تماماً ما تفعله تنسيقات الخامات العتادية الأصلية:
| عائلة التنسيق | الاسم الكامل | المنصات الأساسية | الخصائص المعمارية |
|---|---|---|---|
| BC1-7 | Block Compression | الحواسيب المكتبية (Windows و Mac) | المعيار العتادي القياسي، يعتمد ضغط كتل 4×4 بكسل |
| ETC1/2 | Ericsson Texture Compression | الهواتف المحمولة (Android و iOS القديم) | المعيار الكلاسيكي لأجهزة الهواتف |
| ASTC | Adaptive Scalable Texture Compression | الهواتف ونظارات الواقع الافتراضي الحديثة | المرونة القصوى وأعلى جودة مع أحجام كتل متغيرة |
| PVRTC | PowerVR | أجهزة iOS القديمة | يتم استبداله تدريجياً بـ ASTC |
القاسم المشترك بين هذه التنسيقات: يتم ضغط الخامات في كتل صغيرة بدقة 4×4 بكسل، ويفك معالج GPU ضغط الكتلة المحددة فقط لحظة أخذ العينة. ونتيجة لذلك، يتقلص استهلاك ذاكرة الرسوميات بنسبة ثابتة بغض النظر عن محتوى الصورة.
مقارنة بين التنسيقات التقليدية وتنسيقات GPU الأصلية:
| وجه المقارنة | تنسيقات PNG و JPG التقليدية | تنسيقات GPU العتادية الأصلية |
|---|---|---|
| الحجم على القرص | صغير جداً (خاصة JPG) | متوسط (ضغط كتلي بمعدل بت ثابت) |
| استهلاك ذاكرة VRAM | ضخم جداً (بكسلات خام مفرودة) | منخفض جداً (تبقى مضغوطة داخل الذاكرة) |
| سرعة الرفع إلى GPU | بطيئة (فك تشفير CPU ثم نقل كتلة ضخمة) | سريعة جداً (نقل مباشر دون فك تشفير) |
| سرعة أخذ العينات | سريعة | سريعة (فك تشفير عتادي فوري) |
المشكلة: تشتت التوافق عبر الأجهزة المختلفة
إذا كانت تنسيقات GPU ممتازة، فلماذا لا نستخدمها مباشرة في كل مكان؟ تكمن المشكلة في تشتت التوافق العتادي:
- حواسيب سطح المكتب تدعم تنسيقات BC1-7 ولا تدعم ASTC غالباً.
- هواتف Android تدعم ETC2 و ASTC ولا تدعم BC.
- أجهزة iOS الحديثة تدعم ASTC.
إذا أردت دعم جميع الأجهزة، ستحتاج إلى إنشاء عدة نسخ من كل خامة لكل منصة، مما يضاعف حجم حزم المشاريع والجهد الهندسي. وعلى الويب تحديداً، لا يمكن معرفة نوع جهاز المستخدم مسبقاً قبل تحميل الصفحة.
تقنية Basis Universal: الترميز لمرة واحدة والتحويل للجميع
ابتكرت تقنية Basis Universal لحل مشكلة التشتت العتادي عبر مبدأ محوري بسيط:
يتم ترميز الخامة في مرحلة الإنتاج إلى "تنسيق وسيط موحد"، ثم يتم تحويل الترميز في المتصفح وقت التشغيل إلى التنسيق العتادي المدعوم على جهاز المستخدم مباشرة.
مخطط تدفق تحويل الترميز:
الخامة المصدر الأصلية (PNG/JPG)
│ ترميز غير متزامن لمرة واحدة خارج بيئة التشغيل
▼
تنسيق Basis الوسيط الموحد (ETC1S أو UASTC)
│ مدمج داخل حاوية KTX2
▼
النشر على الويب ──┬── حواسيب سطح المكتب ──→ تحويل فوري أثناء التحميل ← BC1/3/7
├── هواتف Android ─────→ تحويل فوري أثناء التحميل ← ETC2
└── أجهزة iOS و VR ────→ تحويل فوري أثناء التحميل ← ASTC
أهم الخصائص:
- الترميز يتم لمرة واحدة فقط أثناء الإنتاج.
- تحويل الترميز عند التحميل سريع للغاية (عملية حسابية بسيطة تستغرق بضع أجزاء من الألف من الثانية لكل خامة).
- ينتقل الناتج إلى ذاكرة VRAM بتنسيق عتادي مضغوط بالكامل، مما يخفض استهلاك الذاكرة بنفس كفاءة التنسيقات الأصلية.
تنسيق KTX2: الحاوية القياسية لخامات الرسوميات
لتنظيم وحفظ بيانات Basis وربطها بنماذج glTF، يُستخدم تنسيق KTX2.
لا يعد KTX2 مجرد صورة عادية، بل هو تنسيق حاوية معيارية طورته مجموعة Khronos، لتغليف بيانات خامات GPU مع البيانات الوصفية (مثل الفضاء اللوني ومستويات Mipmaps ونوع الترميز).
في نماذج glTF، يتم دمج خامات KTX2 عبر الامتداد القياسي KHR_texture_basisu.
المقارنة للتفريق بين المفاهيم الثلاثة:
| المفهوم | الدور الفني | التشبيه التبسيطي |
|---|---|---|
| Basis Universal | خوارزمية الترميز (كيفية ضغط الصورة إلى تنسيق وسيط) | طريقة الضغط |
| KTX2 | تنسيق الحاوية (كيفية تعبئة البيانات المضغوطة والترويسات) | الصندوق الحافظ |
| KHR_texture_basisu | امتداد glTF (إعلام المحرك بوجود خامات Basis مضغوطة) | بطاقة التعريف |
اختبار عملي لذاكرة VRAM: مقارنة خامة بدقة 4096
مقارنة استهلاك خامة RGBA بدقة 4096×4096 عبر مختلف الحلول:
| طريقة المعالجة | الحجم على القرص | استهلاك ذاكرة VRAM (مع Mipmaps) | سرعة الرفع | التوافق الشامل |
|---|---|---|---|---|
| PNG | حوالي 8 ميغابايت | حوالي 87 ميغابايت | بطيئة | مدعوم |
| JPG | حوالي 1.5 ميغابايت | حوالي 87 ميغابايت | بطيئة | مدعوم |
| WebP | حوالي 2 ميغابايت | حوالي 87 ميغابايت | بطيئة | مدعوم |
| KTX2 (ETC1S) | حوالي 2 إلى 3 ميغابايت | حوالي 11 إلى 14 ميغابايت | سريعة جداً | مدعوم عبر التحويل |
| KTX2 (UASTC) | حوالي 6 إلى 8 ميغابايت | حوالي 22 ميغابايت | سريعة جداً | مدعوم عبر التحويل |
الخلاصتان الأساسيتان:
- تستهلك التنسيقات التقليدية (PNG/JPG/WebP) نفس القدر تماماً من ذاكرة VRAM (87 ميغابايت)، فصغر حجم الملف على القرص لا يوفر أي مساحة في ذاكرة الرسوميات.
- يخفض تنسيق KTX2 استهلاك ذاكرة VRAM إلى الربع أو الثمن، مما يمنع انهيار المتصفحات على الهواتف وأجهزة الواقع الافتراضي.
مصفوفة دعم المنصات للتنسيقات العتادية
| المنصة أو الجهاز | BC1-7 | ETC2 | ASTC | PVRTC |
|---|---|---|---|---|
| حواسيب سطح المكتب (DirectX / Vulkan / WebGPU) | مدعوم | غير مدعوم | جزئي (في الأجهزة الحديثة) | غير مدعوم |
| نظام macOS (Metal) | مدعوم (في الأجهزة الحديثة) | غير مدعوم | مدعوم | غير مدعوم |
| أجهزة Android | غير مدعوم | مدعوم | مدعوم | غير مدعوم |
| أجهزة iOS (معالجات A8 فما فوق) | غير مدعوم | مدعوم | مدعوم | مدعوم في القديم |
| بيئة WebGL 2 | يعتمد على الامتدادات | مدعوم | جزئي | غير مدعوم |
| بيئة WebGPU | مدعوم (سطح المكتب) | مدعوم | مدعوم حسب الجهاز | غير مدعوم |
مقارنة مسار التحميل: التنسيقات التقليدية مقابل KTX2
المسار التقليدي لملفات PNG و JPG:
تنزيل ملف PNG ← ذاكرة النظام CPU ← فك تشفير بطيء عبر CPU ← بكسلات RGBA خام ← رفع كتلة ضخمة إلى GPU ← استهلاك 87 ميغابايت في VRAM
المسار الحديث لـ KTX2 و Basis:
تنزيل ملف KTX2 ← ذاكرة النظام CPU ← تحويل ترميز فوري سريع ← كتل مضغوطة لـ GPU ← رفع سريع لحجم صغير ← استهلاك 11 ميغابايت في VRAM
يلغي المسار الحديث عملية فك التشفير الثقيلة على المعالج المركزي، ويقلل حجم البيانات المرفوعة بمقدار عشرة أضعاف، محققاً ظهوراً فورياً للإطار الأول واستقراراً تاماً للذاكرة.
الخطوة التالية في السلسلة
بعد اكتمال الأسس النظرية، يتناول المقال القادم التطبيق العملي: كيفية استخدام أدوات toktx و gltf-transform لضغط الخامات، وتحميلها في Three.js و Babylon.js، وضبط معايير الجودة بين ETC1S و UASTC.