Przeglądaj źródła

add support for draw buffers

Alexander Rose 6 lat temu
rodzic
commit
b21785211c

+ 33 - 12
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
     }
 }

+ 72 - 0
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,
+        }
+    }
 }

+ 8 - 2
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)

+ 9 - 9
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')