diff --git a/src/mol-gl/compute/util.ts b/src/mol-gl/compute/util.ts index fb7f9947e7f493b1d268c72fd9af38605c333135..0508154cf2a6e5900bcdcd5202d372d5b92ca5ef 100644 --- a/src/mol-gl/compute/util.ts +++ b/src/mol-gl/compute/util.ts @@ -10,6 +10,7 @@ import { printTextureImage } from 'mol-gl/renderable/util'; import { defaults, ValueCell } from 'mol-util'; import { ValueSpec, AttributeSpec, UniformSpec, Values } from 'mol-gl/renderable/schema'; import { Vec2 } from 'mol-math/linear-algebra'; +import { GLRenderingContext } from 'mol-gl/webgl/compat'; export const QuadPositions = new Float32Array([ 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, // First triangle @@ -32,12 +33,21 @@ export const QuadValues: Values<typeof QuadSchema> = { // +function getArrayForTexture(gl:GLRenderingContext, texture: Texture, size: number) { + switch (texture.type) { + case gl.UNSIGNED_BYTE: return new Uint8Array(size) + case gl.FLOAT: return new Float32Array(size) + } + throw new Error('unknown/unsupported texture type') +} + export function readTexture(ctx: WebGLContext, texture: Texture, width?: number, height?: number) { const { gl, framebufferCache } = ctx width = defaults(width, texture.width) height = defaults(height, texture.height) + const size = width * height * 4 const framebuffer = framebufferCache.get('read-texture').value - const array = texture.type === gl.UNSIGNED_BYTE ? new Uint8Array(width * height * 4) : new Float32Array(width * height * 4) + const array = getArrayForTexture(gl, texture, size) framebuffer.bind() texture.attachFramebuffer(framebuffer, 0) ctx.readPixels(0, 0, width, height, array) diff --git a/src/mol-gl/renderable/schema.ts b/src/mol-gl/renderable/schema.ts index 4c9a9e453dcd536a60efccbc3c7ac8a06be8411c..cdc083cdb4b2c78687f49e096411ed3b19935519 100644 --- a/src/mol-gl/renderable/schema.ts +++ b/src/mol-gl/renderable/schema.ts @@ -47,6 +47,7 @@ export type KindValue = { 'image-uint8': TextureImage<Uint8Array> 'image-float32': TextureImage<Float32Array> + 'image-depth': TextureImage<Uint8Array> // TODO should be Uint32Array 'volume-uint8': TextureVolume<Uint8Array> 'volume-float32': TextureVolume<Float32Array> 'texture': Texture diff --git a/src/mol-gl/webgl/compat.ts b/src/mol-gl/webgl/compat.ts index 9021af77e7f829228e8755fbc84d73463651c949..ed2da5c59020e868963163349595c8ef5e22098c 100644 --- a/src/mol-gl/webgl/compat.ts +++ b/src/mol-gl/webgl/compat.ts @@ -220,4 +220,22 @@ export interface COMPAT_shader_texture_lod { export function getShaderTextureLod(gl: GLRenderingContext): COMPAT_shader_texture_lod | null { return isWebGL2(gl) ? {} : gl.getExtension('EXT_shader_texture_lod') +} + +export interface COMPAT_depth_texture { + readonly UNSIGNED_INT_24_8: number; +} + +export function getDepthTexture(gl: GLRenderingContext): COMPAT_depth_texture | null { + if(isWebGL2(gl)) { + return { + UNSIGNED_INT_24_8: gl.UNSIGNED_INT_24_8 + } + } else { + const ext = gl.getExtension('WEBGL_depth_texture') + if (ext === null) return null + return { + UNSIGNED_INT_24_8: ext.UNSIGNED_INT_24_8_WEBGL + } + } } \ No newline at end of file diff --git a/src/mol-gl/webgl/context.ts b/src/mol-gl/webgl/context.ts index aca8e579dcc80a93d21a5edc09af0362c5c6b3c6..d03a511bf62bc797f854d401c77d417143737552 100644 --- a/src/mol-gl/webgl/context.ts +++ b/src/mol-gl/webgl/context.ts @@ -6,7 +6,7 @@ import { createProgramCache, ProgramCache } from './program' import { createShaderCache, ShaderCache } from './shader' -import { GLRenderingContext, COMPAT_instanced_arrays, COMPAT_standard_derivatives, COMPAT_vertex_array_object, getInstancedArrays, getStandardDerivatives, getVertexArrayObject, isWebGL2, COMPAT_element_index_uint, getElementIndexUint, COMPAT_texture_float, getTextureFloat, COMPAT_texture_float_linear, getTextureFloatLinear, COMPAT_blend_minmax, getBlendMinMax, getFragDepth, COMPAT_frag_depth, COMPAT_color_buffer_float, getColorBufferFloat, COMPAT_draw_buffers, getDrawBuffers, getShaderTextureLod, COMPAT_shader_texture_lod } from './compat'; +import { GLRenderingContext, COMPAT_instanced_arrays, COMPAT_standard_derivatives, COMPAT_vertex_array_object, getInstancedArrays, getStandardDerivatives, getVertexArrayObject, isWebGL2, COMPAT_element_index_uint, getElementIndexUint, COMPAT_texture_float, getTextureFloat, COMPAT_texture_float_linear, getTextureFloatLinear, COMPAT_blend_minmax, getBlendMinMax, getFragDepth, COMPAT_frag_depth, COMPAT_color_buffer_float, getColorBufferFloat, COMPAT_draw_buffers, getDrawBuffers, getShaderTextureLod, COMPAT_shader_texture_lod, getDepthTexture, COMPAT_depth_texture } from './compat'; import { createFramebufferCache, FramebufferCache, checkFramebufferStatus } from './framebuffer'; import { Scheduler } from 'mol-task'; import { isDebugMode } from 'mol-util/debug'; @@ -124,8 +124,10 @@ function readPixels(gl: GLRenderingContext, x: number, y: number, width: number, if (isDebugMode) checkFramebufferStatus(gl) if (buffer instanceof Uint8Array) { gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buffer) - } else { + } else if (buffer instanceof Float32Array) { gl.readPixels(x, y, width, height, gl.RGBA, gl.FLOAT, buffer) + } else { + throw new Error('unsupported readPixels buffer type') } if (isDebugMode) checkError(gl) } @@ -153,7 +155,9 @@ export type WebGLExtensions = { blendMinMax: COMPAT_blend_minmax textureFloat: COMPAT_texture_float textureFloatLinear: COMPAT_texture_float_linear - elementIndexUint: COMPAT_element_index_uint | null + elementIndexUint: COMPAT_element_index_uint + depthTexture: COMPAT_depth_texture + vertexArrayObject: COMPAT_vertex_array_object | null fragDepth: COMPAT_frag_depth | null colorBufferFloat: COMPAT_color_buffer_float | null @@ -184,8 +188,13 @@ function createExtensions(gl: GLRenderingContext): WebGLExtensions { } const elementIndexUint = getElementIndexUint(gl) if (elementIndexUint === null) { - console.warn('Could not find support for "element_index_uint"') + throw new Error('Could not find support for "element_index_uint"') + } + const depthTexture = getDepthTexture(gl) + if (depthTexture === null) { + throw new Error('Could not find support for "depth_texture"') } + const vertexArrayObject = getVertexArrayObject(gl) if (vertexArrayObject === null) { console.log('Could not find support for "vertex_array_object"') @@ -207,7 +216,6 @@ function createExtensions(gl: GLRenderingContext): WebGLExtensions { console.log('Could not find support for "shader_texture_lod"') } - return { instancedArrays, standardDerivatives, @@ -215,11 +223,13 @@ function createExtensions(gl: GLRenderingContext): WebGLExtensions { textureFloat, textureFloatLinear, elementIndexUint, + depthTexture, + vertexArrayObject, fragDepth, colorBufferFloat, drawBuffers, - shaderTextureLod + shaderTextureLod, } } diff --git a/src/mol-gl/webgl/render-target.ts b/src/mol-gl/webgl/render-target.ts index 01f623ecc8658f02fbf14b913a23a8332197929a..6dea8717017d85454f22cc4512bc9e4d289a3bd2 100644 --- a/src/mol-gl/webgl/render-target.ts +++ b/src/mol-gl/webgl/render-target.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ @@ -7,7 +7,7 @@ import { WebGLContext, createImageData } from './context' import { idFactory } from 'mol-util/id-factory'; import { createTexture, Texture } from './texture'; -import { createFramebuffer } from './framebuffer'; +import { createFramebuffer, Framebuffer } from './framebuffer'; import { createRenderbuffer } from './renderbuffer'; import { TextureImage } from '../renderable/util'; import { Mutable } from 'mol-util/type-helpers'; @@ -20,6 +20,7 @@ export interface RenderTarget { readonly height: number readonly image: TextureImage<any> readonly texture: Texture + readonly framebuffer: Framebuffer /** binds framebuffer and sets viewport to rendertarget's width and height */ bind: () => void @@ -30,7 +31,7 @@ export interface RenderTarget { destroy: () => void } -export function createRenderTarget (ctx: WebGLContext, _width: number, _height: number): RenderTarget { +export function createRenderTarget (ctx: WebGLContext, _width: number, _height: number, enableDepthTexture: boolean = false): RenderTarget { const { gl, stats } = ctx const image: Mutable<TextureImage<Uint8Array>> = { @@ -68,6 +69,7 @@ export function createRenderTarget (ctx: WebGLContext, _width: number, _height: get height () { return _height }, image, texture: targetTexture, + framebuffer, bind: () => { framebuffer.bind() @@ -80,7 +82,6 @@ export function createRenderTarget (ctx: WebGLContext, _width: number, _height: image.width = _width image.height = _height targetTexture.load(image) - depthRenderbuffer.setSize(_width, _height) }, readBuffer, diff --git a/src/mol-gl/webgl/texture.ts b/src/mol-gl/webgl/texture.ts index 20cc12853ad6a7475e1359899da9d6757d7ad9a3..f5b7dec523ae81dfcef1ca12861228a964407d21 100644 --- a/src/mol-gl/webgl/texture.ts +++ b/src/mol-gl/webgl/texture.ts @@ -18,14 +18,15 @@ const getNextTextureId = idFactory() export type TextureKindValue = { 'image-uint8': TextureImage<Uint8Array> 'image-float32': TextureImage<Float32Array> + 'image-depth': TextureImage<Uint8Array> // TODO should be Uint32Array 'volume-uint8': TextureVolume<Uint8Array> 'volume-float32': TextureVolume<Float32Array> 'texture': Texture } export type TextureValueType = ValueOf<TextureKindValue> export type TextureKind = keyof TextureKindValue -export type TextureType = 'ubyte' | 'float' -export type TextureFormat = 'alpha' | 'rgb' | 'rgba' +export type TextureType = 'ubyte' | 'ushort' | 'float' +export type TextureFormat = 'alpha' | 'rgb' | 'rgba' | 'depth' /** Numbers are shortcuts for color attachment */ export type TextureAttachment = 'depth' | 'stencil' | 'color0' | 'color1' | 'color2' | 'color3' | 'color4' | 'color5' | 'color6' | 'color7' | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 export type TextureFilter = 'nearest' | 'linear' @@ -35,6 +36,7 @@ export function getTarget(ctx: WebGLContext, kind: TextureKind): number { switch (kind) { case 'image-uint8': return gl.TEXTURE_2D case 'image-float32': return gl.TEXTURE_2D + case 'image-depth': return gl.TEXTURE_2D } if (isWebGL2(gl)) { switch (kind) { @@ -49,10 +51,11 @@ export function getFormat(ctx: WebGLContext, format: TextureFormat, type: Textur const { gl } = ctx switch (format) { case 'alpha': - if (isWebGL2 && type === 'float') return (gl as WebGL2RenderingContext).RED + if (isWebGL2(gl) && type === 'float') return gl.RED else return gl.ALPHA case 'rgb': return gl.RGB case 'rgba': return gl.RGBA + case 'depth': return gl.DEPTH_COMPONENT } } @@ -75,6 +78,8 @@ export function getInternalFormat(ctx: WebGLContext, format: TextureFormat, type case 'ubyte': return gl.RGBA case 'float': return gl.RGBA32F } + case 'depth': + return gl.DEPTH_COMPONENT16 } } return getFormat(ctx, format, type) @@ -84,6 +89,7 @@ export function getType(ctx: WebGLContext, type: TextureType): number { const { gl } = ctx switch (type) { case 'ubyte': return gl.UNSIGNED_BYTE + case 'ushort': return gl.UNSIGNED_SHORT case 'float': return gl.FLOAT } } @@ -152,7 +158,11 @@ export function createTexture(ctx: WebGLContext, kind: TextureKind, _format: Tex } // check texture kind and type compatability - if ((kind.endsWith('float32') && _type !== 'float') || kind.endsWith('uint8') && _type !== 'ubyte') { + if ( + (kind.endsWith('float32') && _type !== 'float') || + (kind.endsWith('uint8') && _type !== 'ubyte') || + (kind.endsWith('depth') && _type !== 'ushort') + ) { throw new Error(`texture kind '${kind}' and type '${_type}' are incompatible`) } @@ -226,19 +236,23 @@ export function createTexture(ctx: WebGLContext, kind: TextureKind, _format: Tex }, attachFramebuffer: (framebuffer: Framebuffer, attachment: TextureAttachment, layer?: number) => { framebuffer.bind() - if (target === (gl as WebGL2RenderingContext).TEXTURE_3D) { - if (layer === undefined) throw new Error('need `layer` to attach 3D texture'); - (gl as WebGL2RenderingContext).framebufferTextureLayer(gl.FRAMEBUFFER, getAttachment(ctx, attachment), texture, 0, layer) - } else { + if (target === gl.TEXTURE_2D) { gl.framebufferTexture2D(gl.FRAMEBUFFER, getAttachment(ctx, attachment), gl.TEXTURE_2D, texture, 0) + } else if (isWebGL2(gl) && target === gl.TEXTURE_3D) { + if (layer === undefined) throw new Error('need `layer` to attach 3D texture') + gl.framebufferTextureLayer(gl.FRAMEBUFFER, getAttachment(ctx, attachment), texture, 0, layer) + } else { + throw new Error('unknown texture target') } }, detachFramebuffer: (framebuffer: Framebuffer, attachment: TextureAttachment) => { framebuffer.bind() - if (target === (gl as WebGL2RenderingContext).TEXTURE_3D) { - (gl as WebGL2RenderingContext).framebufferTextureLayer(gl.FRAMEBUFFER, getAttachment(ctx, attachment), null, 0, 0) - } else { + if (target === gl.TEXTURE_2D) { gl.framebufferTexture2D(gl.FRAMEBUFFER, getAttachment(ctx, attachment), gl.TEXTURE_2D, null, 0) + } else if (isWebGL2(gl) && target === gl.TEXTURE_3D) { + gl.framebufferTextureLayer(gl.FRAMEBUFFER, getAttachment(ctx, attachment), null, 0, 0) + } else { + throw new Error('unknown texture target') } }, destroy: () => {