Pixi.js: عدد كبير جدًا من سياقات WebGL النشطة

تم إنشاؤها على ١١ ديسمبر ٢٠١٥  ·  29تعليقات  ·  مصدر: pixijs/pixi.js

أقوم بإنشاء تطبيق متكامل مع React يحمل العديد من التجارب الفردية ، في pixi.js و three.js وما إلى ذلك لأنني لا أستطيع استخدام إطار iframe لتحميل التجارب ، فأنا بحاجة للتنظيف بعد نفسي.

في كل مرة يتم فيها التنقل إلى تجربة جديدة ، أتحقق مما إذا كان العارض موجودًا أم لا ، وإذا كان موجودًا ، فأنا أتلفه).

رمز وهمي

if renderer
    renderer.destroy(true);
    renderer = null

renderer = new PIXI.autoDetectRenderer ......

يبدو أنني أقوم بتنظيف عارض webgl الخاص بي بشكل صحيح ، ولكن بعد تحميل 16 صفحة ، أتلقى تحذيرًا يقول WARNING: Too many active WebGL contexts. Oldest context will be lost. لا ينبغي أن يكون هذا مشكلة على سطح المكتب لأن لدينا تحذيرًا فقط ، ولكن على جهاز iPad فإنه يتعطل المتصفح وتظهر رسالة: X A problem occurred with this web page, so it was reloaded. .

كنت أبحث في threejs وكيف يقومون بتنفيذ حل لهذا ، ولديهم الكود التالي

هل أفعل أي شيء سخيف؟

التعليق الأكثر فائدة

أعتقد أنني وجدت حلاً جيدًا. هذا يسمح لي بتراكب الخريطة لمكونات React التي لا يجب أن تعرف بعضها البعض وتسمح لـ React بامتلاك DOM.

تستخدم هذه التقنية لفرض فقدان السياق:

gl.getExtension('WEBGL_lose_context').loseContext();

إليك مثال كامل:

var document = require('global/document');
var PIXI = require('pixi.js');

// I want to keep this canvas / renderer around. For example, this might be a bottom layer PIXI / React map overlay.
var canvas1 = document.createElement('canvas');
document.body.appendChild(canvas1);
createRenderer(0xff0000, canvas1);

function createRenderer(color, canvas) {
  canvas = canvas || document.createElement('canvas');
  var renderer = new PIXI.WebGLRenderer(800, 600, {view: canvas});
  var stage = new PIXI.Container();
  var graphics = new PIXI.Graphics();
  graphics.beginFill(color, 0.5);
  graphics.drawCircle(0, 0, 200);
  graphics.endFill();
  stage.addChild(graphics);
  renderer.render(stage);
  return {renderer: renderer, stage: stage, graphics: graphics};
}

// Simulate frequent adding / removing of lots of PIXI / React map overlays on top.
for (var i = 0; i < 16; i++) {
  var canvas = document.createElement('canvas');
  document.body.appendChild(canvas);
  var scene = createRenderer(0x00ff00, canvas);
  // Uncomment to see that the original canvas isn't removed.
  /* scene.renderer.currentRenderTarget.gl
      .getExtension('WEBGL_lose_context').loseContext(); */
  scene.renderer.destroy();
  scene.stage.removeChild(scene.graphics);
  document.body.removeChild(canvas);
}

ربما يجب أن تضيف PIXI هذا إلى طريقة "التدمير" الخاصة بها؟

ال 29 كومينتر

تضمين التغريدة
أنا لست خبيرًا في رؤية Pixi لأنني كنت أستخدمها فقط منذ الاثنين أو الثلاثاء. إذا كان لديك العديد من العارضين واللوحات القماشية بسبب العديد من التجارب ( مثل هذه ) في فكرة أن هناك حاجة واحدة فقط للوصول إليها في وقت واحد ، سيكون لدي عارض شامل أو آخر ، وأحتفظ بالتجارب في مصفوفة. ثم عندما تحتاج إلى عرضها ، ما عليك سوى تمرير المرحلة من كل تجربة إلى العارض.

var renderer = PIXI.autoDetectRenderer({blah});
var experiments = [];
experiments.push(experiment1);
experiments.push(experiment2);
experiments.push(experiment3);

var currentExperiment = $('#experminetSelector').val();
renderer.render(experiments[currentExperiment]);

بهذه الطريقة ، تقوم بعمل العارض مرة واحدة فقط وتمريره للمرحلة من كل تجربة. على الرغم من أن هذا لا يعمل إلا إذا كنت تحاول عرض صفحة واحدة فقط ولديك جميع التجارب عليها بدلاً من وجود الكثير من صفحات التجارب المختلفة.

إخلاء المسؤولية: أنا جديد على pixi ، ولم أجرب ذلك ، قد يختلف عدد الأميال التي قطعتها. كما أنه لا يزال يبدو كما لو أنك وجدت نوعًا من الأخطاء التي ربما يرغب المطورون في النظر فيها أو تقديم بعض الإرشادات إليها.

يجب أن يكون وجود عارض واحد ومشاهد متعددة أمرًا جيدًا. عارض واحد === عنصر لوحة واحدة.

مرحبا شباب ، شكرا لملاحظاتك. samuraiseoul ما وهذه هي pixi.js threejs أو webgl العادي. علاوة على ذلك ، نظرًا لنوع الانتقالات المحددة بالفعل في بنية التفاعل ، سترى في نقطة ما التجربة القديمة ، والتجربة الجديدة في نفس الوقت ، يتم عرضها في وقت واحد ، وبالتالي فازت فكرة عارض واحد لا يعمل ....

بالإضافة إلى .... هذا حل للمشكلة ، وليس حلًا بحد ذاته ... إذا كانت طريقة .destroy () لا تدمر بالفعل الإشارة إلى سياق webgl ... ما هي النقطة؟ :(

يا صديقي! توافق تمامًا على أن وظيفة التدمير لا تفعل بالضبط ما يفترض أن تفعله إذا لم يتم تدمير السياقات :)

أتجول ، هل تستخدم autodetectRenderer ؟ يمكن أن يكون سياق الاختبار الذي أنشأناه لاكتشاف ما إذا كان المتصفح قادرًا على webGL لم يتم إتلافه.

بعض المعلومات الإضافية: لا يمكنك تدمير سياق webgl ، فهي تُجمع القمامة (ما لم يتغير شيء ما؟)

أعتقد أننا نزيل المراجع التي نحتفظ بها ، ونزيل اختياريًا عنصر لوحة الرسم (المطلوب لتنظيف السياق) ولكن بعد ذلك يعود الأمر إلى المتصفح لإجراء التنظيف. من الممكن أن تتسرب السياقات ، أو يتم إنشاؤها بشكل أسرع مما يريده المتصفح. بصراحة لست متأكدا.

هل تشير أدوات التطوير إلى تسريبات حول سياقات مثل هذه؟ ربما يمكن أن يساعد؟ يبدو أن شيئًا ما يحافظ على السياق .. ربما js ref للسياق أو js ref للوحة القماشية الأساسية؟

هذا هو السبب في أنني ما زلت أحب إطارات iframe بغض النظر عن السبب.

GoodBoyDigital @ أستخدم autodetectRenderer مثل هذا

<strong i="9">@renderer</strong> = new PIXI.autoDetectRenderer canvas.width, canvas.height, { view: canvas, antialias: false, backgroundColor: 0xffffff }

أنا أوقف هذا الآن ، وسأعلمكم يا رفاق ما هو الحل عندما وجدت واحدًا .. كنت أفكر فقط في أن فرض هذا السياق قد يفقد ، ربما يجبر مجموعة القمامة على تنظيفه .. ولكن لست متأكدًا من ذلك أيضًا :)

لدي نفس المشكلة. ما أقوم ببنائه يتطلب تدمير Pixi وإعادة بنائها كثيرًا وأنا قلق بشأن الآثار المترتبة على الذاكرة. كل مثيل WebGL صغير جدًا في الوقت الحالي ، ولكنه سيصبح أكبر كثيرًا مع استمرارنا في بناء هذا.

أي تقدم؟

لأكون واضحًا ، أنا أستخدم Phaser ، لكن يبدو أنه يستدعي طريقة Renderer.destroy لـ Pixi.

لا حظ بعد. إذا كان بإمكانك إما استخدام عارض عالمي واحد وقمت فقط بعرض مشاهد مختلفة فيه ، أو فقط قم بتحميل المحتوى من خلال إطار iframe والذي يتخلص بشكل صحيح من كل ما هو معلق.

مرحبًا يا مختلسوا النظر ، نعم هذا أمر صعب بعض الشيء حقًا. بقدر ما أستطيع أن أرى أننا نفعل كل ما في وسعنا لتدمير السياق. لذلك يتم تدمير جميع القوام / برامج arraybuffers إلخ. ما يمكننا فعله ربما هو تجميع السياقات بمجرد تدميرها حتى نعيد استخدامها بدلاً من إنشاء سياق جديد في كل مرة؟

مرحبًا GoodBoyDigital في حالتي ، كان لدي رسم متحرك داخل / خارج ، لذا كنت بحاجة دائمًا إلى سياقين ... هذه هي مشكلة التكامل مع React وعدم جعلها كاملة pixi ... على أي حال ، لست متأكدًا من أن هذا خطأ يمكنك إصلاحه لكل قول .. أعتقد أنه أشبه بالمتصفح الذي يدير السياقات ... لا أعرف حتى ما إذا كان هذا الاختراق من موقع three.js يعمل ... ربما يمكنك تجربته في الإصدار 4 الخاص بك ومحاولة فتح أكثر من 16 علامة تبويب باستخدام pixi https://github.com/mrdoob/three.js/blob/master/src/renderers/WebGLRenderer.js#L289

وإلا فلا داعي للقلق ، لقد غيرت بالفعل بنية تطبيقي ... iframe FTW :)

رجل الاشياء الجيدة! سأبحث بالتأكيد في إضافة خدعة three.js أيضًا.

أود استخدام عرض عالمي واحد. في الحقيقة ، هذا هو هدفي النهائي. ومع ذلك ، سأحتاج إلى طريقة لدفق الكود إلى السياق الحالي.

بمعنى آخر ، يقوم المستخدم بكتابة الكود. انها ليست مكتوبة مسبقا.

أعتقد أنني وجدت حلاً جيدًا. هذا يسمح لي بتراكب الخريطة لمكونات React التي لا يجب أن تعرف بعضها البعض وتسمح لـ React بامتلاك DOM.

تستخدم هذه التقنية لفرض فقدان السياق:

gl.getExtension('WEBGL_lose_context').loseContext();

إليك مثال كامل:

var document = require('global/document');
var PIXI = require('pixi.js');

// I want to keep this canvas / renderer around. For example, this might be a bottom layer PIXI / React map overlay.
var canvas1 = document.createElement('canvas');
document.body.appendChild(canvas1);
createRenderer(0xff0000, canvas1);

function createRenderer(color, canvas) {
  canvas = canvas || document.createElement('canvas');
  var renderer = new PIXI.WebGLRenderer(800, 600, {view: canvas});
  var stage = new PIXI.Container();
  var graphics = new PIXI.Graphics();
  graphics.beginFill(color, 0.5);
  graphics.drawCircle(0, 0, 200);
  graphics.endFill();
  stage.addChild(graphics);
  renderer.render(stage);
  return {renderer: renderer, stage: stage, graphics: graphics};
}

// Simulate frequent adding / removing of lots of PIXI / React map overlays on top.
for (var i = 0; i < 16; i++) {
  var canvas = document.createElement('canvas');
  document.body.appendChild(canvas);
  var scene = createRenderer(0x00ff00, canvas);
  // Uncomment to see that the original canvas isn't removed.
  /* scene.renderer.currentRenderTarget.gl
      .getExtension('WEBGL_lose_context').loseContext(); */
  scene.renderer.destroy();
  scene.stage.removeChild(scene.graphics);
  document.body.removeChild(canvas);
}

ربما يجب أن تضيف PIXI هذا إلى طريقة "التدمير" الخاصة بها؟

هذا منطقي إذا كنا نملك السياق ، والذي أعتقد أننا نفترض أننا نملكه الآن (آية ٣).

في الوظيفة isWebGLSupported () (source / core / utils / index.js) يستبدل
return !!(gl && gl.getContextAttributes().stencil);

مع
var success = !!(gl && gl.getContextAttributes().stencil); gl.getExtension('WEBGL_lose_context').loseContext(); gl = undefined; return success;

أصلح المشكلة بالنسبة لي. كان الأكثر بروزًا في Google Chrome - عمل Firefox في كلتا الحالتين. نظرًا لأنني لست من WebGL ، سأكون ممتنًا حقًا للتعليق على هذا النهج.

المكالمة الجيدة تفقد السياق بالقوة عند التحقق ، هذه فكرة رائعة لأننا نعلم (100٪) أننا نمتلك هذا السياق.

هل تم دمج هذا؟ نحن نواجه نفس المشكلة.

pingenglercj أعتقد أنه يمكن إغلاق هذا الآن

قد يمنع gl.getExtension('WEBGL_lose_context').loseContext() التحذير لكن المواصفات تقول إنه يحاكي فقط فقدان السياق ، حتى يتم استدعاء WEBGL_lose_context.restoreContext() - والذي يمكنه استعادة السياق فقط إذا لم يكن مفقودًا بالفعل في المقام الأول.

قد يكون هذا مفيدا: lose_context () ليست سوى محاكاة (وفقا لمواصفات)، ولكن في هذا الموضوع ( تقنية WebGL العامة: WEBGL_lose_context نتعلم (من موزيلا المطور جيف جيلبرت) أنه في فايرفوكس loseContext() هي مضرب المثل في " الافراج عن هذا السياق والموارد " .

المشكلة هي أن المتصفحات الأخرى تتعامل مع هذا بشكل مختلف. هناك تعليقات من مطور Google (كين راسل) توصي بما يلي: الرجاء استخدام الحذف الصريح * واجهات برمجة التطبيقات على WebGLRenderingContext لإصدار موارد GPU التي لم يعد تطبيقك يستخدمها.

يجب أن أعترف أنني لم أجرب أيًا من هذا ولكن يبدو أن أي حل سيكون خاصًا بالمتصفح.

مثيرة للاهتمام مذكرة تنفيذ FF. في الواقع ، يبدو أن نصيحة كين بشأن حذف الموارد الفردية هي الطريقة القياسية للذهاب ، فإن FF ليست سوى واحدة من بين العديد من المتصفحات الشائعة وحتى سلوك FF قد يتغير دون إشعار. لم أختبر أيضًا لكل متصفح بسبب عدم رغبتي في الاعتماد على تفاصيل التنفيذ وسلسلة وكيل المستخدم المزيفة أو استنشاق المتصفح ومسارات التعليمات البرمجية الإضافية عندما يكون هناك بديل.

كنت أقوم ببعض الاختبارات لتطبيقي اليوم على نظام التشغيل iOS وواجهت هذا الخطأ. هل هناك حل معروف؟ تعد طريقة عرض pixi الخاصة بي مكونًا فرعيًا لشاشة على تطبيقي ، لذا يتم إتلافها عندما ينتقل المستخدم بعيدًا عن تلك الصفحة. كنت أفكر ، هل من الممكن فصل / إعادة إرفاق نفس العارض بطريقة ما بلوحة العرض لحل المشكلة؟

الحل هو عدم إنشاء سياقات متعددة. فقط أعد استخدام ما لديك. إذا كنت تتنقل بين الصفحات ، فلا يهم ما تم إنشاؤه في الصفحة السابقة.

حسنًا ، كيف يمكنني إعادة استخدام السياق؟ أنا أستخدم angularJS ، لذلك أنا أعمل ضمن إطار عمل قوالب. مثل ، هل يمكنني فصل عنصر Canvas من DOM وتخزينه ، ثم عندما يعود المستخدم إلى الصفحة ، يعيد إرفاقه في مكانه في الصفحة؟ سيكون رائعًا لو كانت هناك طريقة داخل PIXI لقول "استخدم هذا العارض + السياق الحالي وأرفقهما بهذه اللوحة الجديدة" ، لكنني لا أفهم كيف يحدث ذلك تحت الغطاء.

السبب الذي يجعلني مهتمًا هو أنني أستخدم عرض بيكسي كبير كخلفية لتطبيقي ، ولدي صورة أصغر أستخدمها في صفحة الإعدادات الخاصة بي. إذا انتقل المستخدم إلى صفحة الإعدادات عدة مرات ، فإنه يقتل الخلفية الرئيسية لأنه تم إنشاؤه أولاً.

يبدو أن هذا سيكون مشكلة في استخدام PIXI داخل أي تطبيق صفحة واحدة.

سيؤدي حفظ مثيل PIXI.Application / PIXI.WebGLRenderer / PIXI.CanvasRenderer أيضًا إلى حفظ مثيل عنصر canvas. على سبيل المثال ، في PIXI.Application ، يمكنك الحصول على الخاصية view وهي HTMLCanvasElement. يمكنك إدراج عنصر لوحة الرسم هذا وإزالته من تطبيق AngularJS / React. في PIXI ، يمكنك إخبار العارض عن عنصر لوحة الرسم الذي يجب استخدامه عن طريق تمريره كخيار ، ومع ذلك ، لا يجب عليك استخدام هذا. بدلاً من ذلك ، اسمح لـ PIXI بإنشاء عنصر لوحة الرسم الخاص بها داخليًا وقم فقط بإلحاق الطفل ببعض حاوية DOM.

<div id="pixi-container"></div>
// maintain the reference to this Application even as your SPA view gets destroyed
const app = new PIXI.Application();

// Insert in the DOM or whatever the equivalent is in Angular
document.querySelector("#pixi-container").appendChild(app.view);

حسنًا ، شكرًا ، سأجرب ذلك. لا تبدو سيئة على الإطلاق في الواقع.

حسنًا ، أدى فصل العرض وإعادة عرضه بدلاً من تدميره إلى حل مشكلتي ، شكرًا على المساعدة يا رفاق.

تم قفل سلسلة الرسائل هذه تلقائيًا نظرًا لعدم وجود أي نشاط حديث بعد إغلاقه. الرجاء فتح قضية جديدة للأخطاء ذات الصلة.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات