diff --git a/src/mol-gl/shader-code.ts b/src/mol-gl/shader-code.ts index 3a23f56b35d8962b64b342dacf42895baba3472d..8059b2d429a9fec697fcc0048a56f4059b195523 100644 --- a/src/mol-gl/shader-code.ts +++ b/src/mol-gl/shader-code.ts @@ -16,8 +16,9 @@ export type DefineValues = { [k: string]: ValueCell<DefineType> } const shaderCodeId = idFactory() export interface ShaderExtensions { - readonly standardDerivatives: boolean - readonly fragDepth: boolean + readonly standardDerivatives?: boolean + readonly fragDepth?: boolean + readonly drawBuffers?: boolean } export interface ShaderCode { @@ -27,44 +28,42 @@ export interface ShaderCode { readonly extensions: ShaderExtensions } -export function ShaderCode(vert: string, frag: string, extensions: ShaderExtensions): ShaderCode { +export function ShaderCode(vert: string, frag: string, extensions: ShaderExtensions = {}): ShaderCode { return { id: shaderCodeId(), vert, frag, extensions } } export const PointsShaderCode = ShaderCode( require('mol-gl/shader/points.vert').default, - require('mol-gl/shader/points.frag').default, - { standardDerivatives: false, fragDepth: false } + require('mol-gl/shader/points.frag').default ) export const SpheresShaderCode = ShaderCode( require('mol-gl/shader/spheres.vert').default, require('mol-gl/shader/spheres.frag').default, - { standardDerivatives: false, fragDepth: true } + { fragDepth: true } ) export const TextShaderCode = ShaderCode( require('mol-gl/shader/text.vert').default, require('mol-gl/shader/text.frag').default, - { standardDerivatives: true, fragDepth: false } + { standardDerivatives: true } ) export const LinesShaderCode = ShaderCode( require('mol-gl/shader/lines.vert').default, - require('mol-gl/shader/lines.frag').default, - { standardDerivatives: false, fragDepth: false } + require('mol-gl/shader/lines.frag').default ) export const MeshShaderCode = ShaderCode( require('mol-gl/shader/mesh.vert').default, require('mol-gl/shader/mesh.frag').default, - { standardDerivatives: true, fragDepth: false } + { standardDerivatives: true } ) export const DirectVolumeShaderCode = ShaderCode( require('mol-gl/shader/direct-volume.vert').default, require('mol-gl/shader/direct-volume.frag').default, - { standardDerivatives: false, fragDepth: true } + { fragDepth: true } ) @@ -108,6 +107,14 @@ function getGlsl100FragPrefix(extensions: WebGLExtensions, shaderExtensions: Sha throw new Error(`requested 'GL_EXT_frag_depth' extension is unavailable`) } } + if (shaderExtensions.drawBuffers) { + if (extensions.drawBuffers) { + prefix.push('#extension GL_EXT_draw_buffers : require') + prefix.push('#define requiredDrawBuffers') + } else { + throw new Error(`requested 'GL_EXT_draw_buffers' extension is unavailable`) + } + } return prefix.join('\n') + '\n' } @@ -124,19 +131,33 @@ layout(location = 0) out highp vec4 out_FragColor; #define gl_FragDepthEXT gl_FragDepth #define texture2D texture +layout(location = 1) out highp vec4 out_FragData1; +layout(location = 2) out highp vec4 out_FragData2; +layout(location = 3) out highp vec4 out_FragData3; +layout(location = 4) out highp vec4 out_FragData4; +layout(location = 5) out highp vec4 out_FragData5; +layout(location = 6) out highp vec4 out_FragData6; +layout(location = 7) out highp vec4 out_FragData7; + #define enabledStandardDerivatives #define enabledFragDepth +#define requiredDrawBuffers ` +function transformGlsl300Frag(frag: string) { + return frag.replace(/gl_FragData\[([0-7])\]/g, 'out_FragData$1') +} + export function addShaderDefines(gl: GLRenderingContext, extensions: WebGLExtensions, defines: ShaderDefines, shaders: ShaderCode): ShaderCode { const webgl2 = isWebGL2(gl) const header = getDefinesCode(defines) const vertPrefix = webgl2 ? glsl300VertPrefix : '' const fragPrefix = webgl2 ? glsl300FragPrefix : getGlsl100FragPrefix(extensions, shaders.extensions) + const frag = webgl2 ? transformGlsl300Frag(shaders.frag) : shaders.frag return { id: shaderCodeId(), vert: `${vertPrefix}${header}${shaders.vert}`, - frag: `${fragPrefix}${header}${shaders.frag}`, + frag: `${fragPrefix}${header}${frag}`, extensions: shaders.extensions } } \ No newline at end of file diff --git a/src/mol-gl/webgl/compat.ts b/src/mol-gl/webgl/compat.ts index 70c2b8dfbdffea438eaf0d8a4ce7f513a1018900..8b1dff34ad9ea03d119363436293cace9649b89d 100644 --- a/src/mol-gl/webgl/compat.ts +++ b/src/mol-gl/webgl/compat.ts @@ -141,4 +141,76 @@ export function getColorBufferFloat(gl: GLRenderingContext): COMPAT_color_buffer if (ext === null) return null return { RGBA32F: ext.RGBA32F_EXT } } +} + +export interface COMPAT_draw_buffers { + drawBuffers(buffers: number[]): void; + readonly COLOR_ATTACHMENT0: number; + readonly COLOR_ATTACHMENT1: number; + readonly COLOR_ATTACHMENT2: number; + readonly COLOR_ATTACHMENT3: number; + readonly COLOR_ATTACHMENT4: number; + readonly COLOR_ATTACHMENT5: number; + readonly COLOR_ATTACHMENT6: number; + readonly COLOR_ATTACHMENT7: number; + readonly DRAW_BUFFER0: number; + readonly DRAW_BUFFER1: number; + readonly DRAW_BUFFER2: number; + readonly DRAW_BUFFER3: number; + readonly DRAW_BUFFER4: number; + readonly DRAW_BUFFER5: number; + readonly DRAW_BUFFER6: number; + readonly DRAW_BUFFER7: number; + readonly MAX_COLOR_ATTACHMENTS: number; + readonly MAX_DRAW_BUFFERS: number; +} + +export function getDrawBuffers(gl: GLRenderingContext): COMPAT_draw_buffers | null { + if (isWebGL2(gl)) { + return { + drawBuffers: gl.drawBuffers.bind(gl), + COLOR_ATTACHMENT0: gl.COLOR_ATTACHMENT0, + COLOR_ATTACHMENT1: gl.COLOR_ATTACHMENT1, + COLOR_ATTACHMENT2: gl.COLOR_ATTACHMENT2, + COLOR_ATTACHMENT3: gl.COLOR_ATTACHMENT3, + COLOR_ATTACHMENT4: gl.COLOR_ATTACHMENT4, + COLOR_ATTACHMENT5: gl.COLOR_ATTACHMENT5, + COLOR_ATTACHMENT6: gl.COLOR_ATTACHMENT6, + COLOR_ATTACHMENT7: gl.COLOR_ATTACHMENT7, + DRAW_BUFFER0: gl.DRAW_BUFFER0, + DRAW_BUFFER1: gl.DRAW_BUFFER1, + DRAW_BUFFER2: gl.DRAW_BUFFER2, + DRAW_BUFFER3: gl.DRAW_BUFFER3, + DRAW_BUFFER4: gl.DRAW_BUFFER4, + DRAW_BUFFER5: gl.DRAW_BUFFER5, + DRAW_BUFFER6: gl.DRAW_BUFFER6, + DRAW_BUFFER7: gl.DRAW_BUFFER7, + MAX_COLOR_ATTACHMENTS: gl.MAX_COLOR_ATTACHMENTS, + MAX_DRAW_BUFFERS: gl.MAX_DRAW_BUFFERS, + } + } else { + const ext = gl.getExtension('WEBGL_draw_buffers') + if (ext === null) return null + return { + drawBuffers: ext.drawBuffersWEBGL.bind(ext), + COLOR_ATTACHMENT0: ext.COLOR_ATTACHMENT0_WEBGL, + COLOR_ATTACHMENT1: ext.COLOR_ATTACHMENT1_WEBGL, + COLOR_ATTACHMENT2: ext.COLOR_ATTACHMENT2_WEBGL, + COLOR_ATTACHMENT3: ext.COLOR_ATTACHMENT3_WEBGL, + COLOR_ATTACHMENT4: ext.COLOR_ATTACHMENT4_WEBGL, + COLOR_ATTACHMENT5: ext.COLOR_ATTACHMENT5_WEBGL, + COLOR_ATTACHMENT6: ext.COLOR_ATTACHMENT6_WEBGL, + COLOR_ATTACHMENT7: ext.COLOR_ATTACHMENT7_WEBGL, + DRAW_BUFFER0: ext.DRAW_BUFFER0_WEBGL, + DRAW_BUFFER1: ext.DRAW_BUFFER1_WEBGL, + DRAW_BUFFER2: ext.DRAW_BUFFER2_WEBGL, + DRAW_BUFFER3: ext.DRAW_BUFFER3_WEBGL, + DRAW_BUFFER4: ext.DRAW_BUFFER4_WEBGL, + DRAW_BUFFER5: ext.DRAW_BUFFER5_WEBGL, + DRAW_BUFFER6: ext.DRAW_BUFFER6_WEBGL, + DRAW_BUFFER7: ext.DRAW_BUFFER7_WEBGL, + MAX_COLOR_ATTACHMENTS: ext.MAX_COLOR_ATTACHMENTS_WEBGL, + MAX_DRAW_BUFFERS: ext.MAX_DRAW_BUFFERS_WEBGL, + } + } } \ No newline at end of file diff --git a/src/mol-gl/webgl/context.ts b/src/mol-gl/webgl/context.ts index 3f8c5af5aaf37e3393d778e071f1f5e7e7406792..2ec22c9923b0c82eb51cd33b77c74970557ee3fd 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 } 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 } from './compat'; import { createFramebufferCache, FramebufferCache } from './framebuffer'; import { Scheduler } from 'mol-task'; import { isProductionMode } from 'mol-util/debug'; @@ -153,6 +153,7 @@ export type WebGLExtensions = { vertexArrayObject: COMPAT_vertex_array_object | null fragDepth: COMPAT_frag_depth | null colorBufferFloat: COMPAT_color_buffer_float | null + drawBuffers: COMPAT_draw_buffers | null } export type WebGLStats = { @@ -234,6 +235,10 @@ export function createContext(gl: GLRenderingContext): WebGLContext { if (colorBufferFloat === null) { console.log('Could not find support for "color_buffer_float"') } + const drawBuffers = getDrawBuffers(gl) + if (drawBuffers === null) { + console.log('Could not find support for "draw_buffers"') + } const state: WebGLState = { currentProgramId: -1, @@ -261,7 +266,8 @@ export function createContext(gl: GLRenderingContext): WebGLContext { elementIndexUint, vertexArrayObject, fragDepth, - colorBufferFloat + colorBufferFloat, + drawBuffers } const shaderCache: ShaderCache = createShaderCache(gl) diff --git a/src/mol-gl/webgl/texture.ts b/src/mol-gl/webgl/texture.ts index 886204c7aba358c3824bd7e8badcdc3cd8cee817..731c8f9e5be33bd55d23968dcc386668e1a71cd8 100644 --- a/src/mol-gl/webgl/texture.ts +++ b/src/mol-gl/webgl/texture.ts @@ -95,21 +95,21 @@ export function getFilter(ctx: WebGLContext, type: TextureFilter): number { } export function getAttachment(ctx: WebGLContext, attachment: TextureAttachment): number { - const { gl } = ctx + const { gl, extensions } = ctx switch (attachment) { case 'depth': return gl.DEPTH_ATTACHMENT case 'stencil': return gl.STENCIL_ATTACHMENT case 'color0': case 0: return gl.COLOR_ATTACHMENT0 } - if (isWebGL2(gl)) { + if (extensions.drawBuffers) { switch (attachment) { - case 'color1': case 1: return gl.COLOR_ATTACHMENT1 - case 'color2': case 2: return gl.COLOR_ATTACHMENT2 - case 'color3': case 3: return gl.COLOR_ATTACHMENT3 - case 'color4': case 4: return gl.COLOR_ATTACHMENT4 - case 'color5': case 5: return gl.COLOR_ATTACHMENT5 - case 'color6': case 6: return gl.COLOR_ATTACHMENT6 - case 'color7': case 7: return gl.COLOR_ATTACHMENT7 + case 'color1': case 1: return extensions.drawBuffers.COLOR_ATTACHMENT1 + case 'color2': case 2: return extensions.drawBuffers.COLOR_ATTACHMENT2 + case 'color3': case 3: return extensions.drawBuffers.COLOR_ATTACHMENT3 + case 'color4': case 4: return extensions.drawBuffers.COLOR_ATTACHMENT4 + case 'color5': case 5: return extensions.drawBuffers.COLOR_ATTACHMENT5 + case 'color6': case 6: return extensions.drawBuffers.COLOR_ATTACHMENT6 + case 'color7': case 7: return extensions.drawBuffers.COLOR_ATTACHMENT7 } } throw new Error('unknown texture attachment')