draw( renderObject/*, info*/ ) {

		const { object, pipeline, material, context, hardwareClippingPlanes } = renderObject;
		const { programGPU } = this.get( pipeline );

		const { gl, state } = this;

		const contextData = this.get( context );

		const drawParams = renderObject.getDrawParameters();

		if ( drawParams === null ) return;

		//

		this._bindUniforms( renderObject.getBindings() );

		const frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 );

		state.setMaterial( material, frontFaceCW, hardwareClippingPlanes );

		state.useProgram( programGPU );

		// vertex state

		const attributes = renderObject.getAttributes();
		const attributesData = this.get( attributes );

		let vaoGPU = attributesData.vaoGPU;

		if ( vaoGPU === undefined ) {

			const vaoKey = this._getVaoKey( attributes );

			vaoGPU = this.vaoCache[ vaoKey ];

			if ( vaoGPU === undefined ) {

				vaoGPU = this._createVao( attributes );

				this.vaoCache[ vaoKey ] = vaoGPU;
				attributesData.vaoGPU = vaoGPU;

			}

		}

		const index = renderObject.getIndex();
		const indexGPU = ( index !== null ) ? this.get( index ).bufferGPU : null;

		state.setVertexState( vaoGPU, indexGPU );

		//

		const lastObject = contextData.lastOcclusionObject;

		if ( lastObject !== object && lastObject !== undefined ) {

			if ( lastObject !== null && lastObject.occlusionTest === true ) {

				gl.endQuery( gl.ANY_SAMPLES_PASSED );

				contextData.occlusionQueryIndex ++;

			}

			if ( object.occlusionTest === true ) {

				const query = gl.createQuery();

				gl.beginQuery( gl.ANY_SAMPLES_PASSED, query );

				contextData.occlusionQueries[ contextData.occlusionQueryIndex ] = query;
				contextData.occlusionQueryObjects[ contextData.occlusionQueryIndex ] = object;

			}

			contextData.lastOcclusionObject = object;

		}

		//
		const renderer = this.bufferRenderer;

		if ( object.isPoints ) renderer.mode = gl.POINTS;
		else if ( object.isLineSegments ) renderer.mode = gl.LINES;
		else if ( object.isLine ) renderer.mode = gl.LINE_STRIP;
		else if ( object.isLineLoop ) renderer.mode = gl.LINE_LOOP;
		else {

			if ( material.wireframe === true ) {

				state.setLineWidth( material.wireframeLinewidth * this.renderer.getPixelRatio() );
				renderer.mode = gl.LINES;

			} else {

				renderer.mode = gl.TRIANGLES;

			}

		}

		//

		const { vertexCount, instanceCount } = drawParams;
		let { firstVertex } = drawParams;

		renderer.object = object;

		if ( index !== null ) {

			firstVertex *= index.array.BYTES_PER_ELEMENT;

			const indexData = this.get( index );

			renderer.index = index.count;
			renderer.type = indexData.type;

		} else {

			renderer.index = 0;

		}

		const draw = () => {

			if ( object.isBatchedMesh ) {

				if ( object._multiDrawInstances !== null ) {

					// @deprecated, r174
					warnOnce( 'THREE.WebGLBackend: renderMultiDrawInstances has been deprecated and will be removed in r184. Append to renderMultiDraw arguments and use indirection.' );
					renderer.renderMultiDrawInstances( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount, object._multiDrawInstances );

				} else if ( ! this.hasFeature( 'WEBGL_multi_draw' ) ) {

					warnOnce( 'THREE.WebGLRenderer: WEBGL_multi_draw not supported.' );

				} else {

					renderer.renderMultiDraw( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount );

				}

			} else if ( instanceCount > 1 ) {

				renderer.renderInstances( firstVertex, vertexCount, instanceCount );

			} else {

				renderer.render( firstVertex, vertexCount );

			}

		};

		if ( renderObject.camera.isArrayCamera === true && renderObject.camera.cameras.length > 0 && renderObject.camera.isMultiViewCamera === false ) {

			const cameraData = this.get( renderObject.camera );
			const cameras = renderObject.camera.cameras;
			const cameraIndex = renderObject.getBindingGroup( 'cameraIndex' ).bindings[ 0 ];

			if ( cameraData.indexesGPU === undefined || cameraData.indexesGPU.length !== cameras.length ) {

				const data = new Uint32Array( [ 0, 0, 0, 0 ] );
				const indexesGPU = [];

				for ( let i = 0, len = cameras.length; i < len; i ++ ) {

					const bufferGPU = gl.createBuffer();

					data[ 0 ] = i;

					gl.bindBuffer( gl.UNIFORM_BUFFER, bufferGPU );
					gl.bufferData( gl.UNIFORM_BUFFER, data, gl.STATIC_DRAW );

					indexesGPU.push( bufferGPU );

				}

				cameraData.indexesGPU = indexesGPU; // TODO: Create a global library for this

			}

			const cameraIndexData = this.get( cameraIndex );
			const pixelRatio = this.renderer.getPixelRatio();

			const renderTarget = this._currentContext.renderTarget;
			const isRenderCameraDepthArray = this._isRenderCameraDepthArray( this._currentContext );
			const prevActiveCubeFace = this._currentContext.activeCubeFace;

			if ( isRenderCameraDepthArray ) {

				// Clear the depth texture
				const textureData = this.get( renderTarget.depthTexture );

				if ( textureData.clearedRenderId !== this.renderer._nodes.nodeFrame.renderId ) {

					textureData.clearedRenderId = this.renderer._nodes.nodeFrame.renderId;

					const { stencilBuffer } = renderTarget;

					for ( let i = 0, len = cameras.length; i < len; i ++ ) {

						this.renderer._activeCubeFace = i;
						this._currentContext.activeCubeFace = i;

						this._setFramebuffer( this._currentContext );
						this.clear( false, true, stencilBuffer, this._currentContext, false );

					}

					this.renderer._activeCubeFace = prevActiveCubeFace;
					this._currentContext.activeCubeFace = prevActiveCubeFace;

				}

			}

			for ( let i = 0, len = cameras.length; i < len; i ++ ) {

				const subCamera = cameras[ i ];

				if ( object.layers.test( subCamera.layers ) ) {

					if ( isRenderCameraDepthArray ) {

						// Update the active layer
						this.renderer._activeCubeFace = i;
						this._currentContext.activeCubeFace = i;

						this._setFramebuffer( this._currentContext );

					}

					const vp = subCamera.viewport;

					if ( vp !== undefined ) {

						const x = vp.x * pixelRatio;
						const y = vp.y * pixelRatio;
						const width = vp.width * pixelRatio;
						const height = vp.height * pixelRatio;

						state.viewport(
							Math.floor( x ),
							Math.floor( renderObject.context.height - height - y ),
							Math.floor( width ),
							Math.floor( height )
						);

					}

					state.bindBufferBase( gl.UNIFORM_BUFFER, cameraIndexData.index, cameraData.indexesGPU[ i ] );

					draw();

				}

				this._currentContext.activeCubeFace = prevActiveCubeFace;
				this.renderer._activeCubeFace = prevActiveCubeFace;

			}

		} else {

			draw();

		}

	}
Executes a draw command for the given render object.

@param {RenderObject} renderObject - The render object to draw.
@param {Info} info - Holds a series of statistical information about the GPU memory and the rendering process.