Pixi.js: Terlalu banyak konteks WebGL aktif

Dibuat pada 11 Des 2015  ·  29Komentar  ·  Sumber: pixijs/pixi.js

Saya sedang membangun aplikasi yang terintegrasi dengan React yang memuat beberapa eksperimen individual, dalam pixi.js, three.js, dll. Karena saya tidak dapat menggunakan iframe untuk memuat eksperimen, saya perlu membersihkannya sendiri.

Setiap kali ada navigasi ke eksperimen baru, saya memeriksa apakah perender itu ada, atau tidak, dan jika ya, saya akan menghancurkannya).

kode dummy

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

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

Tampaknya saya membersihkan renderer webgl saya dengan benar, namun setelah 16 halaman dimuat, saya mendapatkan peringatan yang mengatakan WARNING: Too many active WebGL contexts. Oldest context will be lost. Ini seharusnya tidak menjadi masalah di desktop karena kami hanya memiliki peringatan, tetapi di ipad macet browser dan sebuah pesan muncul: X A problem occurred with this web page, so it was reloaded. .

Saya sedang melihat threejs dan bagaimana mereka menerapkan solusi untuk ini, dan mereka memiliki kode berikut:

Apakah saya melakukan sesuatu yang konyol?

Komentar yang paling membantu

Saya pikir saya menemukan solusi yang baik. Ini memungkinkan saya untuk memiliki komponen React overlay peta yang tidak harus saling mengetahui satu sama lain dan memungkinkan React untuk memiliki DOM.

Ini menggunakan teknik ini untuk memaksa hilangnya konteks:

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

Berikut ini contoh lengkapnya:

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);
}

Mungkin PIXI harus menambahkan ini ke metode "hancurkan" sendiri?

Semua 29 komentar

@andrevenancio
Saya bukan ahli dalam Pixi mengingat saya hanya menggunakannya sejak Senin atau Selasa. Jika Anda memiliki banyak perender dan kanvas karena banyak eksperimen ( seperti ini ) dalam gagasan bahwa hanya satu yang perlu diakses pada satu waktu, saya akan memiliki perender global atau lainnya, dan menyimpan eksperimen dalam array. Kemudian ketika Anda perlu menampilkannya, lewati saja tahapan dari setiap eksperimen ke dalam penyaji.

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

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

Dengan cara ini Anda hanya membuat perender sekali dan hanya melewati tahap dari setiap percobaan. Meskipun ini hanya berfungsi jika Anda mencoba untuk hanya merender satu halaman dan memiliki semua eksperimen di dalamnya daripada memiliki banyak halaman eksperimen yang berbeda.

PENOLAKAN: Saya baru mengenal pixi, dan tidak mencoba ini, jarak tempuh Anda mungkin berbeda. Juga masih terdengar seolah-olah Anda menemukan semacam bug yang mungkin ingin dilihat atau diberikan oleh para pengembang.

Memiliki penyaji tunggal dan banyak adegan seharusnya baik-baik saja. 1 penyaji === 1 elemen kanvas.

Hai teman-teman, terima kasih atas tanggapan Anda. @samuraiseoul Apa yang Anda sarankan sama sekali tidak konyol, dan itulah cara saya biasanya melanjutkan untuk memiliki beberapa eksperimen dalam satu kerangka kerja ... namun, saya perlu membuat solusi lain karena eksperimen dapat dilakukan menggunakan pixi.js threejs atau webgl biasa. Selain itu, karena jenis transisi yang sudah ditentukan dalam struktur reaksi, pada suatu saat Anda akan melihat eksperimen lama, dan eksperimen baru pada saat yang sama, merender secara bersamaan, sehingga gagasan tentang satu penyaji menang. tidak bekerja....

Plus.... ini adalah solusi untuk masalah, bukan solusi itu sendiri... Jika metode .destroy() sebenarnya tidak menghancurkan referensi ke konteks webgl... apa gunanya? :(

Hai sobat! Sepenuhnya setuju bahwa fungsi penghancuran tidak persis melakukan apa yang seharusnya jika konteksnya tidak dihancurkan :)

Saya mengembara, apakah Anda menggunakan autodetectRenderer ? Bisa jadi konteks pengujian yang kami buat untuk mendeteksi apakah browser berkemampuan webGL tidak dihancurkan.

Beberapa info tambahan: Anda tidak dapat menghancurkan konteks webgl, mereka adalah sampah yang dikumpulkan (kecuali ada yang berubah?)

Saya pikir kami menghapus referensi yang kami pegang, dan secara opsional menghapus elemen kanvas (yang diperlukan untuk pembersihan konteks) tetapi kemudian terserah browser untuk melakukan pembersihan. Ada kemungkinan konteks bocor, atau dibuat lebih cepat dari yang diinginkan browser. Jujur saya tidak yakin.

Apakah alat dev menunjukkan kebocoran di sekitar konteks seperti ini? Mungkin itu bisa membantu? Kedengarannya seperti ada sesuatu yang menjaga konteksnya.. Mungkin referensi js ke konteks atau referensi js ke kanvas yang mendasarinya?

Inilah mengapa saya masih menyukai iframe, apa pun yang terjadi.

@GoodBoyDigital Saya menggunakan autodetectRenderer seperti ini

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

Saya memarkir ini untuk saat ini, akan memberi tahu kalian apa solusinya ketika saya menemukannya .. Saya hanya berpikir bahwa memaksa konteks itu hilang, mungkin akan memaksa pengumpulan sampah untuk membersihkannya .. tetapi tidak yakin juga :)

Saya mengalami masalah yang sama. Apa yang saya bangun mengharuskan Pixi dihancurkan dan dibangun kembali cukup sering dan saya khawatir tentang implikasi memori. Setiap instance WebGL saat ini cukup kecil, tetapi akan menjadi jauh lebih besar saat kami terus mengembangkannya.

Adakah peningkatan?

Untuk lebih jelasnya, saya menggunakan Phaser, tetapi tampaknya memanggil metode renderer.destroy Pixi.

belum beruntung. Jika Anda dapat menggunakan satu perender global dan Anda hanya merender adegan yang berbeda ke dalamnya, atau, cukup memuat konten melalui iframe dan membuang apa pun yang menggantung dengan benar.

Hei peeps, ya ini benar-benar sedikit rumit. Sejauh yang saya bisa lihat, kami melakukan segala yang kami bisa untuk menghancurkan sebuah konteks. Jadi semua tekstur / program arraybuffer dll dihancurkan. Apa yang bisa kita lakukan adalah mungkin menyatukan konteks setelah dihancurkan sehingga kita menggunakannya kembali daripada membuat yang baru setiap kali?

hei @GoodBoyDigital dalam kasus saya, saya memiliki animasi masuk/keluar jadi saya akan selalu membutuhkan 2 konteks ... itulah masalah dengan mengintegrasikan dengan React dan tidak membuatnya penuh pixi ... bagaimanapun, tidak yakin ini adalah bug yang dapat Anda perbaiki per say .. Saya pikir ini lebih seperti browser yang mengelola konteks ... bahkan tidak tahu apakah peretasan dari three.js ini berfungsi ... mungkin cobalah di V4 Anda dan coba buka 16+ tab dengan pixi https://github.com/mrdoob/three.js/blob/master/src/renderers/WebGLRenderer.js#L289

Kalau tidak, jangan khawatir sobat, saya sudah mengubah arsitektur aplikasi saya ... iframe FTW :)

Barang bagus pak! Saya pasti akan menambahkan trik three.js juga.

Saya ingin menggunakan satu render global. Sebenarnya, itulah tujuan akhir saya. Namun, saya memerlukan cara untuk mengalirkan kode ke dalam konteks yang ada.

Dengan kata lain, pengguna sedang menulis kode. Itu tidak ditulis sebelumnya.

Saya pikir saya menemukan solusi yang baik. Ini memungkinkan saya untuk memiliki komponen React overlay peta yang tidak harus saling mengetahui satu sama lain dan memungkinkan React untuk memiliki DOM.

Ini menggunakan teknik ini untuk memaksa hilangnya konteks:

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

Berikut ini contoh lengkapnya:

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);
}

Mungkin PIXI harus menambahkan ini ke metode "hancurkan" sendiri?

Masuk akal jika kita memiliki konteksnya, yang menurut saya saat ini kita anggap kita miliki (v3).

Dalam fungsi isWebGLSupported() (source/core/utils/index.js) menggantikan
return !!(gl && gl.getContextAttributes().stencil);

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

memperbaiki masalah untuk saya. Itu paling menonjol di Google Chrome - Firefox bekerja dengan baik. Karena saya sedikit pemula WebGL, saya akan sangat berterima kasih atas komentar tentang pendekatan ini.

Panggilan yang baik kehilangan konteks secara paksa saat memeriksa, itu adalah ide bagus karena kita tahu (100%) bahwa kita memiliki konteks itu.

Apakah ini digabung? Kami memiliki masalah yang sama.

ping @englercj saya pikir ini bisa ditutup sekarang

gl.getExtension('WEBGL_lose_context').loseContext() dapat menekan peringatan tetapi spesifikasi mengatakan itu hanya mensimulasikan kehilangan konteks, sampai WEBGL_lose_context.restoreContext() dipanggil - yang dapat memulihkan konteks hanya jika tidak benar-benar hilang di tempat pertama.

Ini mungkin berguna: lose_context() hanya simulasi (sesuai dengan spesifikasi) tetapi di utas ini ( WebGL Publik: WEBGL_lose_context kita belajar (dari pengembang mozilla Jeff Gilbert) bahwa di Firefox loseContext() adalah buah bibir untuk " lepaskan konteks ini dan itusumber daya" .

Masalahnya adalah browser lain menangani ini secara berbeda. Ada komentar dari pengembang Google (Ken Russell) yang merekomendasikan : Harap gunakan penghapusan eksplisit* API di WebGLRenderingContext untuk melepaskan sumber daya GPU yang tidak lagi digunakan aplikasi Anda.

Saya harus mengakui bahwa saya belum bereksperimen dengan semua ini, tetapi sepertinya solusi apa pun akan spesifik untuk browser.

Catatan implementasi FF yang menarik. Memang, saran Ken tentang menghapus sumber daya individu terlihat seperti cara standar, FF hanyalah salah satu di antara banyak browser populer dan bahkan perilaku FF mungkin berubah tanpa pemberitahuan. Saya juga belum menguji per browser karena tidak ingin bergantung pada detail implementasi dan string agen pengguna yang dapat dipalsukan atau sniffing browser dan jalur kode tambahan ketika ada alternatif.

Saya sedang melakukan beberapa pengujian untuk aplikasi saya hari ini di iOS dan mengalami kesalahan ini. Apakah ada solusi yang diketahui? Tampilan pixi saya adalah subkomponen layar di aplikasi saya, jadi layar itu akan rusak saat pengguna keluar dari halaman itu. Saya berpikir, apakah akan berhasil entah bagaimana melepaskan/menyambungkan kembali penyaji yang sama ke kanvas tampilan untuk mengatasi masalah ini?

Solusinya adalah tidak membuat banyak konteks. Cukup gunakan kembali yang Anda miliki. Jika Anda menavigasi halaman, maka tidak masalah apa yang dibuat di halaman sebelumnya.

Hmm, jadi bagaimana cara saya menggunakan kembali konteks? Saya menggunakan angularJS, jadi saya bekerja dalam kerangka templating. Seperti, bisakah saya melepaskan elemen kanvas dari DOM dan menyimpannya, lalu ketika pengguna kembali ke halaman, pasang kembali ke tempatnya di halaman? Akan sangat bagus jika ada cara di dalam PIXI untuk mengatakan "gunakan perender + konteks yang ada ini dan lampirkan ke kanvas baru ini", tetapi saya tidak mengerti bagaimana hal itu terjadi di bawah tenda.

Alasan saya peduli adalah saya menggunakan satu tampilan pixi besar sebagai latar belakang aplikasi saya, dan saya memiliki yang lebih kecil yang saya gunakan di halaman pengaturan saya. Jika pengguna pergi ke halaman pengaturan beberapa kali, itu membunuh latar belakang utama karena dibuat terlebih dahulu.

Sepertinya ini akan menjadi masalah dengan menggunakan PIXI dalam aplikasi satu halaman mana pun.

Menyimpan instance PIXI.Application/PIXI.WebGLRenderer/PIXI.CanvasRenderer Anda juga akan menyimpan instance elemen kanvas Anda. Misalnya, di PIXI.Application, Anda bisa mendapatkan properti view yang merupakan HTMLCanvasElement. Anda dapat memasukkan elemen kanvas ini dan menghapusnya dari aplikasi AngularJS/React Anda. Di PIXI Anda dapat memberi tahu Renderer elemen kanvas mana yang akan digunakan dengan meneruskannya sebagai opsi, namun, Anda tidak boleh menggunakan ini. Sebagai gantinya, izinkan PIXI untuk membuat elemen kanvasnya sendiri secara internal dan cukup tambahkanChild ke beberapa wadah 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);

Ok, terima kasih, saya akan mencobanya. Tidak terlihat buruk sama sekali sebenarnya.

Baiklah, melepaskan dan menambahkan kembali tampilan alih-alih menghancurkannya memecahkan masalah saya, terima kasih atas bantuannya.

Utas ini telah dikunci secara otomatis karena tidak ada aktivitas terbaru setelah ditutup. Silakan buka edisi baru untuk bug terkait.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat