почему webgl часто теряет контекст и почему он не восстанавливается снова

#typescript #webgl

Вопрос:

Я часто получаю предупреждения о потере контекста и webglcontextlost о событиях. Я хочу знать, почему это происходит так часто, хотя я не злоупотребляю графическим процессором. Я думаю, что в моем цикле рисования есть какая-то проблема с памятью.

Во-вторых webglcontextrestored , никогда не стреляет, и я не могу восстановить контекст на данный момент.

Я настраиваю webgl2:

   constructor(readonly $wrap: HTMLElement) {

    this.$canvas = document.createElement('canvas')

    this.$canvas.width = 320
    this.$canvas.height = 180

    $wrap.appendChild(this.$canvas)

    let gl = this.$canvas.getContext('webgl2', { alpha: true, antialias: false });
    if (gl !== null) {
      this.gl = gl
    }

    this.$canvas.addEventListener('webglcontextlost', (event) => {
      console.log('context lost')
      event.preventDefault()
      this.gl = undefined
    })


    this.$canvas.addEventListener('webglcontextrestored', () => {
      console.log('restored')
      if (gl !== null) {
        this.gl = gl
      }
    })

  } 
 

Это мой код для рисования, называемый каждый requestAnimationFrame :

   flush = () => {
    let { gl, attributeBuffer, indexBuffer } = this 

 

    if (!gl) {
      return
    }



    let aIndex = 0

    this.elements.forEach((element, i) => {
      let {
        vertexData,
        indices } = element

      let { texture, fsUv } = this.quads[i]

      for (let k = 0; k < vertexData.length; k =2) {
        attributeBuffer[aIndex  ] = vertexData[k]
        attributeBuffer[aIndex  ] = vertexData[k 1]
        attributeBuffer[aIndex  ] = fsUv[k]
        attributeBuffer[aIndex  ] = fsUv[k 1]
      }

      for (let k = 0; k < indices.length; k  ) {
        indexBuffer[i * indices.length   k] = i * 4   indices[k]
      }
    })

    gl.viewport(0, 0, 320, 180)

    gl.clearColor(0, 0, 0, 1)
    gl.clear(gl.COLOR_BUFFER_BIT)

    gl.enable(gl.BLEND)
    gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA)
    
    let vao = gl.createVertexArray()
 
    gl.bindVertexArray(vao)
 
 
    let gl_abuffer = gl.createBuffer()
 
    gl.bindBuffer(gl.ARRAY_BUFFER, gl_abuffer)
 
 
    let gl_ibuffer = gl.createBuffer()
 
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl_ibuffer)
 
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indexBuffer, gl.STATIC_DRAW)
 
    let program = generateProgram(gl, vSource, fSource)
 
    gl.useProgram(program.program)


    gl.uniformMatrix3fv(program.uniformData['projectionMatrix'].location, false, this.projectionMatrix.array_t) 
   
    gl.uniform1i(program.uniformData['uSampler'].location, 0)
 
 
    gl.bindBuffer(gl.ARRAY_BUFFER, gl_abuffer)
    gl.bufferData(gl.ARRAY_BUFFER, attributeBuffer, gl.STATIC_DRAW)
 
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl_ibuffer)
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indexBuffer, gl.STATIC_DRAW)


    let stride = 2 * 4   2 * 4

    let a1loc = program.attributeData['aVertexPosition'].location
    gl.enableVertexAttribArray(a1loc)
    gl.vertexAttribPointer(a1loc, 2, gl.FLOAT, false, stride, 0) 
 
    let a2loc = program.attributeData['aTextureCoord'].location
    gl.enableVertexAttribArray(a2loc)
    gl.vertexAttribPointer(a2loc, 2, gl.FLOAT, false, stride, 2*4) 

    let glTexture = gl.createTexture() 


    gl.bindTexture(gl.TEXTURE_2D, glTexture)

    gl.texImage2D(gl.TEXTURE_2D, 0,
      gl.RGBA,
      1,
      1,
      0,
      gl.RGBA,
      gl.UNSIGNED_BYTE,
    new Uint8Array([0, 0, 255, 255]))


    let texture = this.quads[0].texture

    gl.bindTexture(gl.TEXTURE_2D, glTexture)
    gl.texImage2D(gl.TEXTURE_2D, 0,
      gl.RGBA, texture.width, texture.height, 0, gl.RGBA, gl.UNSIGNED_BYTE,
      texture)

    //gl.generateMipmap(gl.TEXTURE_2D)

    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)

    gl.drawElements(gl.TRIANGLES, indexBuffer.length, gl.UNSIGNED_SHORT, 0) 


    this.elements = []
  }
 

Может быть, я вызываю generateProgram, который компилирует и связывает программы gl каждый раз, когда в этом проблема?

Комментарии:

1. В значительной степени весь ваш цикл рендеринга должен выполняться только один раз: создание и заполнение буферов, создание программы шейдеров, загрузка данных текстур, настройка состояний сэмплера текстур, скорее всего, из-за этого.

Ответ №1:

Как отмечалось в комментарии, большую часть настройки можно выполнить только один раз. Я реорганизовал код так, что проблема решена.

  glOnce = (texture: HTMLImageElement) => {

    let { gl, attributeBuffer, indexBuffer } = this 

    if (!gl) { return }

    gl.viewport(0, 0, 320, 180)
    gl.clearColor(0, 0, 0, 1)

    gl.enable(gl.BLEND)
    gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA)

    let vao = gl.createVertexArray()
 
    gl.bindVertexArray(vao)
 
 
    this.glAttributeBuffer = gl.createBuffer()
 
    gl.bindBuffer(gl.ARRAY_BUFFER, this.glAttributeBuffer)
 
 
    this.glIndexBuffer = gl.createBuffer()
 
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.glIndexBuffer)
 
    let program = generateProgram(gl, vSource, fSource)
 
    gl.useProgram(program.program)


    gl.uniformMatrix3fv(program.uniformData['projectionMatrix'].location, false, this.projectionMatrix.array_t) 
   
    gl.uniform1i(program.uniformData['uSampler'].location, 0)
 
    let stride = 2 * 4   2 * 4

    let a1loc = program.attributeData['aVertexPosition'].location
    gl.enableVertexAttribArray(a1loc)
    gl.vertexAttribPointer(a1loc, 2, gl.FLOAT, false, stride, 0) 
 
    let a2loc = program.attributeData['aTextureCoord'].location
    gl.enableVertexAttribArray(a2loc)
    gl.vertexAttribPointer(a2loc, 2, gl.FLOAT, false, stride, 2*4) 

    let glTexture = gl.createTexture() 


    gl.bindTexture(gl.TEXTURE_2D, glTexture)

    gl.texImage2D(gl.TEXTURE_2D, 0,
      gl.RGBA,
      1,
      1,
      0,
      gl.RGBA,
      gl.UNSIGNED_BYTE,
    new Uint8Array([0, 0, 255, 255]))

   gl.bindTexture(gl.TEXTURE_2D, glTexture)
   gl.texImage2D(gl.TEXTURE_2D, 0,
     gl.RGBA, texture.width, texture.height, 0, gl.RGBA, gl.UNSIGNED_BYTE,
     texture)

    //gl.generateMipmap(gl.TEXTURE_2D)

    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)

  }

  flush = () => {
    let { gl, attributeBuffer, indexBuffer } = this

    if (!gl) {
      return
    }

    let aIndex = 0

    this.elements.forEach((element, i) => {
      let {
        vertexData,
        indices } = element

      let { texture, fsUv } = this.quads[i]

      for (let k = 0; k < vertexData.length; k =2) {
        attributeBuffer[aIndex  ] = vertexData[k]
        attributeBuffer[aIndex  ] = vertexData[k 1]
        attributeBuffer[aIndex  ] = fsUv[k]
        attributeBuffer[aIndex  ] = fsUv[k 1]
      }

      for (let k = 0; k < indices.length; k  ) {
        indexBuffer[i * indices.length   k] = i * 4   indices[k]
      }
    })

    gl.clear(gl.COLOR_BUFFER_BIT)

    gl.bindBuffer(gl.ARRAY_BUFFER, this.glAttributeBuffer)
    gl.bufferData(gl.ARRAY_BUFFER, attributeBuffer, gl.STATIC_DRAW)
 
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.glIndexBuffer)
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indexBuffer, gl.STATIC_DRAW)


    gl.drawElements(gl.TRIANGLES, indexBuffer.length, gl.UNSIGNED_SHORT, 0) 

    this.elements = []
  }