Home Reference Source

lib/make/webgl.js

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const make = require('../make')
const random = require('../random')

class webgl extends make {
  static get internalFormat () {
    return {
      'RGB': { format: 'RGB', type: ['UNSIGNED_BYTE', 'UNSIGNED_SHORT_5_6_5'] },
      'RGBA': { format: 'RGBA', type: ['UNSIGNED_BYTE', 'UNSIGNED_SHORT_4_4_4_4', 'UNSIGNED_SHORT_5_5_5_1'] },
      'LUMINANCE_ALPHA': { format: 'LUMINANCE_ALPHA', type: ['UNSIGNED_BYTE'] },
      'LUMINANCE': { format: 'LUMINANCE', type: ['UNSIGNED_BYTE'] },
      'ALPHA': { format: 'ALPHA', type: ['UNSIGNED_BYTE'] },
      'R8': { format: 'RED', type: ['UNSIGNED_BYTE'] },
      'R16F': { format: 'RED', type: ['HALF_FLOAT', 'FLOAT'] },
      'R32F': { format: 'RED', type: ['FLOAT'] },
      'R8UI': { format: 'RED_INTEGER', type: ['UNSIGNED_BYTE'] },
      'RG8': { format: 'RG', type: ['UNSIGNED_BYTE'] },
      'RG16F': { format: 'RG', type: ['HALF_FLOAT', 'FLOAT'] },
      'RG32F': { format: 'RG', type: ['FLOAT'] },
      'RG8UI': { format: 'RG_INTEGER', type: ['UNSIGNED_BYTE'] },
      'RGB8': { format: 'RGB', type: ['UNSIGNED_BYTE'] },
      'SRGB8': { format: 'RGB', type: ['UNSIGNED_BYTE'] },
      'RGB565': { format: 'RGB', type: ['RGB', 'UNSIGNED_BYTE', 'UNSIGNED_SHORT_5_6_5'] },
      'R11F_G11F_B10F': { format: 'RGB', type: ['UNSIGNED_INT_10F_11F_11F_REV', 'HALF_FLOAT', 'FLOAT'] },
      'RGB9_E5': { format: 'RGB', type: ['HALF_FLOAT', 'FLOAT'] },
      'RGB16F': { format: 'RGB', type: ['HALF_FLOAT', 'FLOAT'] },
      'RGB32F': { format: 'RGB', type: ['FLOAT'] },
      'RGB8UI': { format: 'RGB_INTEGER', type: ['UNSIGNED_BYTE'] },
      'RGBA8': { format: 'RGBA', type: ['UNSIGNED_BYTE'] },
      'SRGB8_ALPHA8': { format: 'RGBA', type: ['UNSIGNED_BYTE'] },
      'RGB5_A1': { format: 'RGBA', type: ['UNSIGNED_BYTE', 'UNSIGNED_SHORT_5_5_5_1'] },
      'RGB10_A2': { format: 'RGBA', type: ['UNSIGNED_INT_2_10_10_10_REV'] },
      'RGBA4': { format: 'RGBA', type: ['UNSIGNED_BYTE', 'UNSIGNED_SHORT_4_4_4_4'] },
      'RGBA16F': { format: 'RGBA', type: ['HALF_FLOAT', 'FLOAT'] },
      'RGBA32F': { format: 'RGBA', type: ['FLOAT'] },
      'RGBA8UI': { format: 'RGBA_INTEGER', type: ['UNSIGNED_BYTE'] }
    }
  }

  static WebGLFormat () {
    let internalformat = random.item(Object.keys(webgl.internalFormat))
    let format = webgl.internalFormat[internalformat].format
    let type = random.item(webgl.internalFormat[internalformat].type)
    return [internalformat, format, type]
  }

  static textureSources () {
    let sources = [
      'HTMLCanvasElement',
      'HTMLImageElement',
      'HTMLVideoElement',
      'ImageData'
    ]
    return random.item(sources)
  }

  static match (shader, regex, group = 1) {
    let matches = []
    while (true) {
      let match = regex.exec(shader)
      if (match) {
        matches.push(match[group])
      } else {
        break
      }
    }
    return matches
  }

  static parseUniforms (shader, group = 1) {
    /* Todo: Parse their individual data types into categories. */
    return webgl.match(shader, /uniform .+? (\w+)(?=[\[;])/gm, group) // eslint-disable-line no-useless-escape
  }

  static parseAttributes (shader, group = 1) {
    return webgl.match(shader, /attribute .+? (\w+)(?=;)/gm, group)
  }

  static parseVaryings (shader, group = 1) {
    return webgl.match(shader, /varying .+? (\w+)(?=;)/gm, group)
  }

  static parseFragDatav2 (shader, group = 1) {
    // #version 200
    return webgl.match(shader, /(gl_Frag[^[ =]+)/gm, group)
  }

  static parseFragDatav3 (shader, group = 1) {
    // #version 300
    return webgl.match(shader, /out .+? (\w+)(?=[\[;])/gm, group) // eslint-disable-line no-useless-escape
  }

  static parseFrag (shader, group = 1) {
    let matches = webgl.parseFragDatav2(shader)
    if (matches.length) {
      return matches
    }
    return webgl.parseFragDatav3(shader)
  }

  static randomBitmask () {
    const values = []
    for (let i = 0; i < 8; i++) {
      values.push(random.item([1, 0]))
    }

    return parseInt(values.join(''))
  }

  static randomBufferTarget (isWebGL2) {
    let target = [
      'ARRAY_BUFFER',
      'ELEMENT_ARRAY_BUFFER'
    ]
    if (isWebGL2) {
      target.extend([
        'COPY_READ_BUFFER',
        'COPY_WRITE_BUFFER',
        'TRANSFORM_FEEDBACK_BUFFER',
        'UNIFORM_BUFFER',
        'PIXEL_PACK_BUFFER',
        'PIXEL_UNPACK_BUFFER'
      ])
    }
    return random.item(target)
  }

  static randomTexParameter (isWebGL2) {
    let pname = [
      'TEXTURE_MAG_FILTER',
      'TEXTURE_MIN_FILTER',
      'TEXTURE_WRAP_S',
      'TEXTURE_WRAP_T'
    ]
    if (isWebGL2) {
      pname.extend([
        'TEXTURE_BASE_LEVEL',
        'TEXTURE_COMPARE_FUNC',
        'TEXTURE_COMPARE_MODE',
        'TEXTURE_MAX_LEVEL',
        'TEXTURE_MAX_LOD',
        'TEXTURE_MIN_LOD',
        'TEXTURE_WRAP_R'
      ])
    }
    return random.item(pname)
  }

  static randomTexParameterValue (isWebGL2) {
    let pnameparam = {
      'TEXTURE_MAG_FILTER': [
        'LINEAR',
        'NEAREST'
      ],
      'TEXTURE_MIN_FILTER': [
        'LINEAR',
        'NEAREST',
        'NEAREST_MIPMAP_NEAREST',
        'LINEAR_MIPMAP_NEAREST',
        'NEAREST_MIPMAP_LINEA',
        'LINEAR_MIPMAP_LINEAR'
      ],
      'TEXTURE_WRAP_S': [
        'REPEAT',
        'CLAMP_TO_EDGE',
        'MIRRORED_REPEAT'
      ],
      'TEXTURE_WRAP_T': [
        'REPEAT',
        'CLAMP_TO_EDGE',
        'MIRRORED_REPEAT'
      ]
    }
    if (isWebGL2) {
      pnameparam = Object.assign(
        pnameparam,
        {
          'TEXTURE_BASE_LEVEL': [
            make.number.any()
          ],
          'TEXTURE_COMPARE_FUNC': [
            'LEQUAL',
            'GEQUAL',
            'LESS',
            'GREATER',
            'EQUAL',
            'NOTEQUAL',
            'ALWAYS',
            'NEVER'
          ],
          'TEXTURE_COMPARE_MODE': [
            'NONE',
            'COMPARE_REF_TO_TEXTURE'
          ],
          'TEXTURE_MAX_LEVEL': [
            make.number.any()
          ],
          'TEXTURE_MAX_LOD': [
            make.number.float()
          ],
          'TEXTURE_MIN_LOD': [
            make.number.float()
          ],
          'TEXTURE_WRAP_R': [
            'REPEAT',
            'CLAMP_TO_EDGE',
            'MIRRORED_REPEAT'
          ]
        }
      )
    }
    let pname = random.item(Object.keys(pnameparam))
    let param = random.item(pnameparam[pname])
    return [pname, param]
  }

  static randomBlendMode (isWebGL2) {
    let mode = [
      'FUNC_ADD',
      'FUNC_SUBTRACT',
      'FUNC_REVERSE_SUBTRACT'
    ]
    if (isWebGL2) {
      mode.extend([
        'MIN',
        'MAX'
      ])
    }
    return random.item(mode)
  }

  static randomBlendFactor (isWebGL2) {
    let factor = [
      'ZERO',
      'ONE',
      'SRC_COLOR',
      'ONE_MINUS_SRC_COLOR',
      'DST_COLOR',
      'ONE_MINUS_DST_COLOR',
      'SRC_ALPHA',
      'ONE_MINUS_SRC_ALPHA',
      'DST_ALPHA',
      'ONE_MINUS_DST_ALPHA',
      'CONSTANT_COLOR',
      'ONE_MINUS_CONSTANT_COLOR',
      'CONSTANT_ALPHA',
      'ONE_MINUS_CONSTANT_ALPHA',
      'SRC_ALPHA_SATURATE'
    ]
    return random.item(factor)
  }

  static randomFace (isWebGL2) {
    let mode = [
      'FRONT',
      'BACK',
      'FRONT_AND_BACK'
    ]
    return random.item(mode)
  }

  static randomTexImage2DTarget (isWebGL2) {
    let target = [
      'TEXTURE_2D',
      'TEXTURE_CUBE_MAP_POSITIVE_X',
      'TEXTURE_CUBE_MAP_NEGATIVE_X',
      'TEXTURE_CUBE_MAP_POSITIVE_Y',
      'TEXTURE_CUBE_MAP_NEGATIVE_Y',
      'TEXTURE_CUBE_MAP_POSITIVE_Z',
      'TEXTURE_CUBE_MAP_NEGATIVE_Z'
    ]
    return random.item(target)
  }

  static randomTextureTarget (isWebGL2) {
    let target = [
      'TEXTURE_2D',
      'TEXTURE_CUBE_MAP'
    ]
    if (isWebGL2) {
      target.extend([
        'TEXTURE_3D',
        'TEXTURE_2D_ARRAY'
      ])
    }
    return random.item(target)
  }

  static randomFunc (isWebGL2) {
    let func = [
      'NEVER',
      'LESS',
      'EQUAL',
      'LEQUAL',
      'GREATER',
      'NOTEQUAL',
      'GEQUAL',
      'ALWAYS'
    ]
    return random.item(func)
  }

  static randomCap (isWebGL2) {
    let cap = [
      'BLEND',
      'CULL_FACE',
      'DEPTH_TEST',
      'DITHER',
      'POLYGON_OFFSET_FILL',
      'SAMPLE_ALPHA_TO_COVERAGE',
      'SAMPLE_COVERAGE',
      'SCISSOR_TEST',
      'STENCIL_TEST'
    ]
    if (isWebGL2) {
      cap.extend([
        'RASTERIZER_DISCARD'
      ])
    }
    return random.item(cap)
  }

  static randomPrimitive (isWebGL2) {
    let mode = [
      'POINTS',
      'LINE_STRIP',
      'LINE_LOOP',
      'LINES',
      'TRIANGLE_STRIP',
      'TRIANGLE_FAN',
      'TRIANGLES'
    ]
    return random.item(mode)
  }

  static randomTextureAttachment (isWebGL2) {
    let attachment = [
      'COLOR_ATTACHMENT0',
      'DEPTH_ATTACHMENT',
      'STENCIL_ATTACHMENT',
      'DEPTH_STENCIL_ATTACHMENT'
    ]
    if (isWebGL2) {
      attachment.extend([
        `COLOR_ATTACHMENT${random.range(0, 15)}`
      ])
    }
    return random.item(attachment)
  }

  static randomAttachmentQuery (isWebGL2) {
    let pname = [
      'FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE',
      'FRAMEBUFFER_ATTACHMENT_OBJECT_NAME',
      'FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL',
      'FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE'
    ]
    if (isWebGL2) {
      pname.extend([
        'FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE',
        'FRAMEBUFFER_ATTACHMENT_BLUE_SIZE',
        'FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING',
        'FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE',
        'FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE',
        'FRAMEBUFFER_ATTACHMENT_GREEN_SIZE',
        'FRAMEBUFFER_ATTACHMENT_RED_SIZE',
        'FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE',
        'FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER'
      ])
    }
    return random.item(pname)
  }

  static randomShaderPrecision (isWebGL2) {
    let precisiontype = [
      'LOW_FLOAT',
      'MEDIUM_FLOAT',
      'HIGH_FLOAT',
      'LOW_INT',
      'MEDIUM_INT',
      'HIGH_INT'
    ]
    return random.item(precisiontype)
  }

  static randomStencilRefParameter (isWebGL2) {
    let param = [
      'STENCIL_FUNC',
      'STENCIL_VALUE_MASK',
      'STENCIL_REF',
      'STENCIL_BACK_FUNC',
      'STENCIL_BACK_VALUE_MASK',
      'STENCIL_BACK_REF',
      'STENCIL_BITS'
    ]
    return random.item(param)
  }

  static randomStencilMaskParameter (isWebGL2) {
    let param = [
      'STENCIL_WRITEMASK',
      'STENCIL_BACK_WRITEMASK',
      'STENCIL_BITS'
    ]
    return random.item(param)
  }

  static randomVertexAttribParameter (isWebGL2) {
    let pname = [
      'VERTEX_ATTRIB_ARRAY_BUFFER_BINDING',
      'VERTEX_ATTRIB_ARRAY_ENABLED',
      'VERTEX_ATTRIB_ARRAY_SIZE',
      'VERTEX_ATTRIB_ARRAY_STRIDE',
      'VERTEX_ATTRIB_ARRAY_TYPE',
      'VERTEX_ATTRIB_ARRAY_NORMALIZED',
      'CURRENT_VERTEX_ATTRIB'
    ]
    if (isWebGL2) {
      pname.extend([
        'VERTEX_ATTRIB_ARRAY_INTEGER',
        'VERTEX_ATTRIB_ARRAY_DIVISOR',
        'VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE'
      ])
    }
    return random.item(pname)
  }

  static randomHint (isWebGL2) {
    let target = [
      'GENERATE_MIPMAP_HINT'
    ]
    if (isWebGL2) {
      target.extend([
        'FRAGMENT_SHADER_DERIVATIVE_HINT'
      ])
    }
    return random.item(target)
  }

  static randomHintMode (isWebGL2) {
    let mode = [
      'FASTEST',
      'NICEST',
      'DONT_CARE'
    ]
    return random.item(mode)
  }

  static randomPixelStorage (isWebGL2) {
    let pname = {
      'PACK_ALIGNMENT': random.item([1, 2, 4, 8]),
      'UNPACK_ALIGNMENT': random.item([1, 2, 4, 8]),
      'UNPACK_FLIP_Y_WEBGL': random.bool(),
      'UNPACK_PREMULTIPLY_ALPHA_WEBGL': random.bool(),
      'UNPACK_COLORSPACE_CONVERSION_WEBGL': random.item([0, 0x9244])
    }
    if (isWebGL2) {
      Object.assign(
        pname,
        {
          'PACK_ROW_LENGTH': make.number.any(),
          'PACK_SKIP_PIXELS': make.number.any(),
          'PACK_SKIP_ROWS': make.number.any(),
          'UNPACK_ROW_LENGTH': make.number.any(),
          'UNPACK_IMAGE_HEIGHT': make.number.any(),
          'UNPACK_SKIP_PIXELS': make.number.any(),
          'UNPACK_SKIP_ROWS': make.number.any(),
          'UNPACK_SKIP_IMAGES': make.number.any()
        }
      )
    }
    let name = random.item(Object.keys(pname))
    return [name, pname[name]]
  }

  static randomStencilAction (isWebGL2) {
    let action = [
      'KEEP',
      'ZERO',
      'REPLACE',
      'INCR',
      'INCR_WRAP',
      'DECR',
      'DECR_WRAP',
      'INVERT'
    ]
    return random.item(action)
  }

  static randomQueryTarget (isWebGL2) {
    let target = [
      'ANY_SAMPLES_PASSED',
      'ANY_SAMPLES_PASSED_CONSERVATIVE',
      'TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN'
    ]
    return random.item(target)
  }

  static randomQueryPname (isWebGL2) {
    let pname = [
      'CURRENT_QUERY',
      'QUERY_RESULT',
      'QUERY_RESULT_AVAILABLE'
    ]
    return random.item(pname)
  }

  static randomSamplerParameter (isWebGL2) {
    let pname = [
      'TEXTURE_MAG_FILTER',
      'TEXTURE_MIN_FILTER',
      'TEXTURE_WRAP_S',
      'TEXTURE_WRAP_T',
      'TEXTURE_BASE_LEVEL',
      'TEXTURE_COMPARE_FUNC',
      'TEXTURE_COMPARE_MODE',
      'TEXTURE_MAX_LEVEL',
      'TEXTURE_WRAP_R',
      'TEXTURE_MAX_LOD',
      'TEXTURE_MIN_LOD',
      'TEXTURE_MAX_ANISOTROPY_EXT'
    ]
    return random.item(pname)
  }

  static randomSyncParameter (isWebGL2) {
    let pname = [
      'OBJECT_TYPE',
      'SYNC_STATUS',
      'SYNC_CONDITION',
      'SYNC_FLAGS'
    ]
    return random.item(pname)
  }

  static randomClearBuffer (isWebGL2) {
    let buffer = [
      'COLOR',
      'DEPTH',
      'STENCIL',
      'DEPTH_STENCIL'
    ]
    return random.item(buffer)
  }

  static randomBindBufferTarget (isWebGL2) {
    let target = [
      'TRANSFORM_FEEDBACK_BUFFER',
      'UNIFORM_BUFFER'
    ]
    return random.item(target)
  }

  static randomIndexedParameterTarget (isWebGL2) {
    let target = [
      'TRANSFORM_FEEDBACK_BUFFER_BINDING',
      'TRANSFORM_FEEDBACK_BUFFER_SIZE',
      'TRANSFORM_FEEDBACK_BUFFER_START',
      'UNIFORM_BUFFER_BINDING',
      'UNIFORM_BUFFER_SIZE',
      'UNIFORM_BUFFER_START'
    ]
    return random.item(target)
  }

  static randomUniformParameter (isWebGL2) {
    let pname = [
      'UNIFORM_TYPE',
      'UNIFORM_SIZE',
      'UNIFORM_BLOCK_INDEX',
      'UNIFORM_OFFSET',
      'UNIFORM_ARRAY_STRIDE',
      'UNIFORM_MATRIX_STRIDE',
      'UNIFORM_IS_ROW_MAJOR'
    ]
    return random.item(pname)
  }

  static randomUniformBlockParameter (isWebGL2) {
    let pname = [
      'UNIFORM_BLOCK_BINDING',
      'UNIFORM_BLOCK_DATA_SIZE',
      'UNIFORM_BLOCK_ACTIVE_UNIFORMS',
      'UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES',
      'UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER',
      'UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER'
    ]
    return random.item(pname)
  }

  static randomPixelDatatype (isWebGL2) {
    let type = [
      'UNSIGNED_BYTE',
      'UNSIGNED_SHORT',
      'UNSIGNED_SHORT_5_6_5',
      'UNSIGNED_SHORT_4_4_4_4',
      'UNSIGNED_SHORT_5_5_5_1',
      'UNSIGNED_INT',
      'FLOAT'
    ]
    return random.item(type)
  }

  static randomBufferUsage (isWebGL2) {
    let usage = [
      'STATIC_DRAW',
      'DYNAMIC_DRAW',
      'STREAM_DRAW'
    ]
    if (isWebGL2) {
      usage.extend([
        'STATIC_READ',
        'DYNAMIC_READ',
        'STREAM_READ',
        'STATIC_COPY',
        'DYNAMIC_COPY',
        'STREAM_COPY'
      ])
    }
    return random.item(usage)
  }

  static randomParameter (isWebGL2) {
    let pname = [
      'ACTIVE_TEXTURE',
      'ALIASED_LINE_WIDTH_RANGE',
      'ALIASED_POINT_SIZE_RANGE',
      'ALPHA_BITS',
      'ARRAY_BUFFER_BINDING',
      'BLEND',
      'BLEND_COLOR',
      'BLEND_DST_ALPHA',
      'BLEND_DST_RGB',
      'BLEND_EQUATION_ALPHA',
      'BLEND_EQUATION_RGB',
      'BLEND_SRC_ALPHA',
      'BLEND_SRC_RGB',
      'BLUE_BITS',
      'COLOR_CLEAR_VALUE',
      'COLOR_WRITEMASK',
      'COMPRESSED_TEXTURE_FORMATS',
      'CULL_FACE',
      'CULL_FACE_MODE',
      'CURRENT_PROGRAM',
      'DEPTH_BITS',
      'DEPTH_CLEAR_VALUE',
      'DEPTH_FUNC',
      'DEPTH_RANGE',
      'DEPTH_TEST',
      'DEPTH_WRITEMASK',
      'DITHER',
      'ELEMENT_ARRAY_BUFFER_BINDING',
      'FRAMEBUFFER_BINDING',
      'FRONT_FACE',
      'GENERATE_MIPMAP_HINT',
      'GREEN_BITS',
      'IMPLEMENTATION_COLOR_READ_FORMAT',
      'IMPLEMENTATION_COLOR_READ_TYPE',
      'LINE_WIDTH',
      'MAX_COMBINED_TEXTURE_IMAGE_UNITS',
      'MAX_CUBE_MAP_TEXTURE_SIZE',
      'MAX_FRAGMENT_UNIFORM_VECTORS',
      'MAX_RENDERBUFFER_SIZE',
      'MAX_TEXTURE_IMAGE_UNITS',
      'MAX_TEXTURE_SIZE',
      'MAX_VARYING_VECTORS',
      'MAX_VERTEX_ATTRIBS',
      'MAX_VERTEX_TEXTURE_IMAGE_UNITS',
      'MAX_VERTEX_UNIFORM_VECTORS',
      'MAX_VIEWPORT_DIMS',
      'PACK_ALIGNMENT',
      'POLYGON_OFFSET_FACTOR',
      'POLYGON_OFFSET_FILL',
      'POLYGON_OFFSET_UNITS',
      'RED_BITS',
      'RENDERBUFFER_BINDING',
      'RENDERER',
      'SAMPLE_ALPHA_TO_COVERAGE',
      'SAMPLE_BUFFERS',
      'SAMPLE_COVERAGE',
      'SAMPLE_COVERAGE_INVERT',
      'SAMPLE_COVERAGE_VALUE',
      'SAMPLES',
      'SCISSOR_BOX',
      'SCISSOR_TEST',
      'SHADING_LANGUAGE_VERSION',
      'STENCIL_BACK_FAIL',
      'STENCIL_BACK_FUNC',
      'STENCIL_BACK_PASS_DEPTH_FAIL',
      'STENCIL_BACK_PASS_DEPTH_PASS',
      'STENCIL_BACK_REF',
      'STENCIL_BACK_VALUE_MASK',
      'STENCIL_BACK_WRITEMASK',
      'STENCIL_BITS',
      'STENCIL_CLEAR_VALUE',
      'STENCIL_FAIL',
      'STENCIL_FUNC',
      'STENCIL_PASS_DEPTH_FAIL',
      'STENCIL_PASS_DEPTH_PASS',
      'STENCIL_REF',
      'STENCIL_TEST',
      'STENCIL_VALUE_MASK',
      'STENCIL_WRITEMASK',
      'SUBPIXEL_BITS',
      'TEXTURE_BINDING_2D',
      'TEXTURE_BINDING_CUBE_MAP',
      'UNPACK_ALIGNMENT',
      'UNPACK_COLORSPACE_CONVERSION_WEBGL',
      'UNPACK_FLIP_Y_WEBGL',
      'UNPACK_PREMULTIPLY_ALPHA_WEBGL',
      'VENDOR',
      'VERSION',
      'VIEWPORT',
      'VERSION',
      'SHADING_LANGUAGE_VERSION',
      'VENDOR',
      'RENDERER'
    ]

    if (isWebGL2) {
      pname.extend([
        'COPY_READ_BUFFER_BINDING',
        'COPY_WRITE_BUFFER_BINDING',
        'DRAW_BUFFERi',
        'DRAW_FRAMEBUFFER_BINDING',
        'FRAGMENT_SHADER_DERIVATIVE_HINT',
        'MAX_3D_TEXTURE_SIZE',
        'MAX_ARRAY_TEXTURE_LAYERS',
        'MAX_CLIENT_WAIT_TIMEOUT_WEBGL',
        'MAX_COLOR_ATTACHMENTS',
        'MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS',
        'MAX_COMBINED_UNIFORM_BLOCKS',
        'MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS',
        'MAX_DRAW_BUFFERS',
        'MAX_ELEMENT_INDEX',
        'MAX_ELEMENTS_INDICE',
        'MAX_ELEMENTS_VERTICES',
        'MAX_FRAGMENT_INPUT_COMPONENTS',
        'MAX_FRAGMENT_UNIFORM_BLOCKS',
        'MAX_FRAGMENT_UNIFORM_COMPONENTS',
        'MAX_PROGRAM_TEXEL_OFFSET',
        'MAX_SAMPLES',
        'MAX_SERVER_WAIT_TIMEOUT',
        'MAX_TEXTURE_LOD_BIAS',
        'MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS',
        'MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS',
        'MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS',
        'MAX_UNIFORM_BLOCK_SIZE',
        'MAX_UNIFORM_BUFFER_BINDINGS',
        'MAX_VARYING_COMPONENTS',
        'MAX_VERTEX_OUTPUT_COMPONENTS',
        'MAX_VERTEX_UNIFORM_BLOCKS',
        'MAX_VERTEX_UNIFORM_COMPONENTS',
        'MIN_PROGRAM_TEXEL_OFFSET',
        'PACK_ROW_LENGTH',
        'PACK_SKIP_PIXELS',
        'PACK_SKIP_ROWS',
        'PIXEL_PACK_BUFFER_BINDING',
        'PIXEL_UNPACK_BUFFER_BINDING',
        'RASTERIZER_DISCARD',
        'READ_BUFFER',
        'READ_FRAMEBUFFER_BINDING',
        'SAMPLER_BINDING',
        'TEXTURE_BINDING_2D_ARRAY',
        'TEXTURE_BINDING_3D',
        'TRANSFORM_FEEDBACK_ACTIVE',
        'TRANSFORM_FEEDBACK_BINDING',
        'TRANSFORM_FEEDBACK_BUFFER_BINDING',
        'TRANSFORM_FEEDBACK_PAUSED',
        'UNIFORM_BUFFER_BINDING',
        'UNIFORM_BUFFER_OFFSET_ALIGNMENT',
        'UNPACK_IMAGE_HEIGHT',
        'UNPACK_ROW_LENGTH',
        'UNPACK_SKIP_IMAGES',
        'UNPACK_SKIP_PIXELS',
        'UNPACK_SKIP_ROWS',
        'VERTEX_ARRAY_BINDING'
      ])
    }
    return random.item(pname)
  }

  static randomProgramParameter () {
    let pname = [
      'DELETE_STATUS',
      'LINK_STATUS',
      'VALIDATE_STATUS',
      'ATTACHED_SHADERS',
      'ACTIVE_ATTRIBUTES',
      'ACTIVE_UNIFORMS',
      'TRANSFORM_FEEDBACK_BUFFER_MODE',
      'TRANSFORM_FEEDBACK_VARYINGS',
      'ACTIVE_UNIFORM_BLOCKS'
    ]
    return random.item(pname)
  }

  static randomRenderBufferParameter () {
    let pname = [
      'RENDERBUFFER_WIDTH',
      'RENDERBUFFER_HEIGHT',
      'RENDERBUFFER_INTERNAL_FORMAT',
      'RENDERBUFFER_RED_SIZE',
      'RENDERBUFFER_GREEN_SIZE',
      'RENDERBUFFER_BLUE_SIZE',
      'RENDERBUFFER_ALPHA_SIZE',
      'RENDERBUFFER_DEPTH_SIZE',
      'RENDERBUFFER_STENCIL_SIZE'
    ]
    return random.item(pname)
  }

  static randomExtension (pattern) {
    let extensions = [
      'ANGLE_instanced_arrays',
      'EXT_blend_minmax',
      'EXT_color_buffer_half_float',
      'EXT_frag_depth',
      'EXT_sRGB',
      'EXT_shader_texture_lod',
      'EXT_texture_filter_anisotropic',
      'EXT_disjoint_timer_query',
      'OES_element_index_uint',
      'OES_standard_derivatives',
      'OES_texture_float',
      'OES_texture_float_linear',
      'OES_texture_half_float',
      'OES_texture_half_float_linear',
      'OES_vertex_array_object',
      'WEBGL_color_buffer_float',
      'WEBGL_compressed_texture_s3tc',
      'WEBGL_compressed_texture_s3tc_srgb',
      'WEBGL_debug_renderer_info',
      'WEBGL_debug_shaders',
      'WEBGL_depth_texture',
      'WEBGL_draw_buffers',
      'WEBGL_lose_context'
    ]

    if (pattern) {
      let candidates = []
      extensions.forEach((ext) => ext.includes(pattern) ? candidates.push(ext) : '')
      if (candidates.length >= 0) {
        return random.item(candidates)
      }
    }

    return random.item(extensions)
  }
}

module.exports = webgl