diff --git a/frontend/src/ts/dynamicObject/heightField/HeightFieldPipeline.ts b/frontend/src/ts/dynamicObject/heightField/HeightFieldPipeline.ts index def402d..73fa9d2 100644 --- a/frontend/src/ts/dynamicObject/heightField/HeightFieldPipeline.ts +++ b/frontend/src/ts/dynamicObject/heightField/HeightFieldPipeline.ts @@ -32,7 +32,7 @@ export class HeightFieldPipeline extends AbstractPipeline { this.preProzessedShaderCoder = resolveShader(this.shaderCode); this.vertexConstants = {}; this.vertexBufferLayout = []; - this.fragmentConstants = project.getDisplayFragmentOutputConstantsCopy(); + this.fragmentConstants = project.getDisplayFragmentOutputConstants(); this.topology = "triangle-strip"; this.cullMode = "none"; this.depthCompare = "less"; diff --git a/frontend/src/ts/project/Project.ts b/frontend/src/ts/project/Project.ts index 80b480a..b307f6b 100644 --- a/frontend/src/ts/project/Project.ts +++ b/frontend/src/ts/project/Project.ts @@ -44,7 +44,13 @@ export class Project { this.renderer.requestAnimationFrameWith(vp); } - getDisplayFragmentOutputConstantsCopy(): Record { + getTargetColorspaceConstants(): Record { + return { + targetColorSpace: this.config.output.display.swapChainColorSpace == "srgb" ? 0 : 1, + }; + } + + getDisplayFragmentOutputConstants(): Record { return { targetColorSpace: this.config.output.display.swapChainColorSpace == "srgb" ? 0 : 1, componentTranfere: this.config.output.render.mode === "deferred" ? 0 : 1, diff --git a/frontend/src/ts/rendering/CompositingPipeline.ts b/frontend/src/ts/rendering/CompositingPipeline.ts index 68b1750..aa4ea4c 100644 --- a/frontend/src/ts/rendering/CompositingPipeline.ts +++ b/frontend/src/ts/rendering/CompositingPipeline.ts @@ -31,7 +31,7 @@ export class CompositingPipeline extends AbstractPipeline { this.preProzessedShaderCoder = resolveShader(this.shaderCode); this.vertexConstants = {}; this.vertexBufferLayout = []; - this.fragmentConstants = project.getDisplayFragmentOutputConstantsCopy(); + this.fragmentConstants = project.getTargetColorspaceConstants(); this.topology = "triangle-strip"; this.cullMode = "none"; this.depthCompare = "always"; diff --git a/frontend/src/ts/rendering/Renderer.ts b/frontend/src/ts/rendering/Renderer.ts index a25fed7..4c7d29e 100644 --- a/frontend/src/ts/rendering/Renderer.ts +++ b/frontend/src/ts/rendering/Renderer.ts @@ -56,7 +56,6 @@ export default class Renderer { }, ] }); - this.bindGroupR3Layout = gpuDevice.createBindGroupLayout({ label: "Default R3 bind group layout", entries: [ @@ -76,7 +75,6 @@ export default class Renderer { }, ] }); - this.compositingBindGroupLayout = gpuDevice.createBindGroupLayout({ label: "Compositing bind group layout", entries: [ @@ -123,7 +121,6 @@ export default class Renderer { }, ] }); - this.bindGroup0 = gpuDevice.createBindGroup({ label: "Global default bind group 0", entries: [ @@ -159,71 +156,80 @@ export default class Renderer { endOfPassWriteIndex: 1 }, }; - this.overlayRenderPassDescriptor = { - label: "Overlay Render Pass", + this.r16ResolveRenderPassDescriptor = { + label: "r16 Resolve Render Pass", colorAttachments: [ { loadOp: "clear", - storeOp: "store", clearValue: [0, 0, 0, 0], + storeOp: "store", view: null as unknown as GPUTextureView, } ], - depthStencilAttachment: { - depthLoadOp: "load", - depthStoreOp: "discard", - view: null as unknown as GPUTextureView, - }, timestampWrites: { querySet: null as unknown as GPUQuerySet, beginningOfPassWriteIndex: 2, endOfPassWriteIndex: 3 }, - } - this.compositingRenderPassDescriptor = { - label: "Overlay Render Pass", + }; + this.selectionRenderPassDescriptor = { + label: "Selection Render Pass", colorAttachments: [ { - loadOp: "load", + loadOp: "clear", storeOp: "store", + clearValue: [0, 0, 0, 0], view: null as unknown as GPUTextureView, } ], + depthStencilAttachment: { + depthLoadOp: "clear", + depthClearValue: 1.0, + depthStoreOp: "store", + view: null as unknown as GPUTextureView, + }, timestampWrites: { querySet: null as unknown as GPUQuerySet, beginningOfPassWriteIndex: 4, endOfPassWriteIndex: 5 }, - } - this.r16ResolveRenderPassDescriptor = { - label: "r16 Resolve Render Pass", + }; + this.overlayRenderPassDescriptor = { + label: "Overlay Render Pass", colorAttachments: [ { loadOp: "clear", - clearValue: [0, 0, 0, 0], storeOp: "store", + clearValue: [0, 0, 0, 0], view: null as unknown as GPUTextureView, } ], + depthStencilAttachment: { + depthLoadOp: "load", + depthStoreOp: "discard", + view: null as unknown as GPUTextureView, + }, + timestampWrites: { + querySet: null as unknown as GPUQuerySet, + beginningOfPassWriteIndex: 6, + endOfPassWriteIndex: 7 + }, } - this.selectionRenderPassDescriptor = { - label: "Selection Render Pass", + this.compositingRenderPassDescriptor = { + label: "Overlay Render Pass", colorAttachments: [ { - loadOp: "clear", + loadOp: "load", storeOp: "store", - clearValue: [0, 0, 0, 0], view: null as unknown as GPUTextureView, } ], - depthStencilAttachment: { - depthLoadOp: "clear", - depthClearValue: 1.0, - depthStoreOp: "store", - view: null as unknown as GPUTextureView, - } - } - + timestampWrites: { + querySet: null as unknown as GPUQuerySet, + beginningOfPassWriteIndex: 8, + endOfPassWriteIndex: 9 + }, + }; } reconfigureContext() { @@ -234,7 +240,7 @@ export default class Renderer { } rebuildDisplayOutputPipelines() { - const outConsts = this.project.getDisplayFragmentOutputConstantsCopy(); + const outConsts = this.project.getDisplayFragmentOutputConstants(); const format = this.project.getSwapChainFormat(); const msaa = (this.project.config.output.render as OutputForwardRenderConfig).msaa; for (const hf of this.project.scene.heightFieldObjects) { @@ -289,9 +295,9 @@ export default class Renderer { const config = this.project.config.output.render as OutputForwardRenderConfig; viewportCache.setupRenderPasses( this.r3renderPassDescriptor, - this.overlayRenderPassDescriptor, this.r16ResolveRenderPassDescriptor, this.selectionRenderPassDescriptor, + this.overlayRenderPassDescriptor, this.compositingRenderPassDescriptor, config); diff --git a/frontend/src/ts/rendering/Shader.ts b/frontend/src/ts/rendering/Shader.ts index 4f0e8df..6286c92 100644 --- a/frontend/src/ts/rendering/Shader.ts +++ b/frontend/src/ts/rendering/Shader.ts @@ -4,6 +4,7 @@ import sRGB_OETF from "../../wgsl/utility/sRGB_OETF.wgsl?raw"; import fragmentOutput from "../../wgsl/utility/fragmentOutput.wgsl?raw"; import frame from "../../wgsl/utility/frame.wgsl?raw"; import fullScreenQuad from "../../wgsl/utility/fullScreenQuadVertex.wgsl?raw"; +import targetColorSpace from "../../wgsl/utility/targetColorSpace.wgsl?raw"; import r3 from "../../wgsl/utility/r3.wgsl?raw"; const snippets: { [key: string]: string } = { @@ -14,6 +15,7 @@ const snippets: { [key: string]: string } = { "utility/frame": frame, "utility/fullScreenQuadVertex": fullScreenQuad, "utility/r3": r3, + "utility/targetColorSpace": targetColorSpace, }; export function resolveIncludes(code: string): string { @@ -27,13 +29,13 @@ export function resolveIncludes(code: string): string { }); } -export function resolveVariables(code: string, map: {[key: string]: string}): string { - for(const key in map) +export function resolveVariables(code: string, map: { [key: string]: string }): string { + for (const key in map) code = code.replaceAll(`#${key}`, map[key]); return code; } -export function resolveShader(code: string, map: {[key: string]: string} = {}): string { +export function resolveShader(code: string, map: { [key: string]: string } = {}): string { return resolveVariables(resolveIncludes(code), map); } diff --git a/frontend/src/ts/rendering/Viewport.ts b/frontend/src/ts/rendering/Viewport.ts index fe39d7f..afe1319 100644 --- a/frontend/src/ts/rendering/Viewport.ts +++ b/frontend/src/ts/rendering/Viewport.ts @@ -16,7 +16,7 @@ export interface Viewport { * This method recieves the GPU time spend the render passes on this viewport in nanoseconds. * @param time The time spend in nanoseconds. */ - setGPUTime(r3Time: number, overlayTime: number, compositingTime: number): void; + setGPUTime(r3Time: number, r16ResolveTime: number, selectionTime: number, overlayTime: number, compositingTime: number): void; /** * @param viewUBO The buffer to write to. * @param frame The current frame time to upload. diff --git a/frontend/src/ts/rendering/ViewportCache.ts b/frontend/src/ts/rendering/ViewportCache.ts index 9f4599f..99be535 100644 --- a/frontend/src/ts/rendering/ViewportCache.ts +++ b/frontend/src/ts/rendering/ViewportCache.ts @@ -33,12 +33,12 @@ export class ViewportCache { this.querySet = gpuDevice.createQuerySet({ label: `time stamp query set for ${viewport.lable}`, type: 'timestamp', - count: 6, + count: 10, }); this.timeStempBufferResolve = gpuDevice.createBuffer({ label: `time stemp querey resolve buffer for ${viewport.lable}`, size: this.querySet.count * 8, - usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.QUERY_RESOLVE, + usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST | GPUBufferUsage.QUERY_RESOLVE, }); this.timeStempMapBuffer = gpuDevice.createBuffer({ @@ -237,9 +237,9 @@ export class ViewportCache { public setupRenderPasses( r3renderPassDescriptor: GPURenderPassDescriptor, - overlayRenderPassDescriptor: GPURenderPassDescriptor, r16ResolveRenderPassDescriptor: GPURenderPassDescriptor, selectionRenderPassDescriptor: GPURenderPassDescriptor, + overlayRenderPassDescriptor: GPURenderPassDescriptor, compositingRenderPassDescriptor: GPURenderPassDescriptor, config: OutputForwardRenderConfig) { const colorAttachment = getElement(r3renderPassDescriptor.colorAttachments, 0); @@ -334,12 +334,16 @@ export class ViewportCache { } const r3TimestampWrites = r3renderPassDescriptor.timestampWrites; + const r16ResolveTimestampWrites = r16ResolveRenderPassDescriptor.timestampWrites; + const selectionTimestampWrites = selectionRenderPassDescriptor.timestampWrites; const overlayTimestampWrites = overlayRenderPassDescriptor.timestampWrites; const compositingTimestampWrites = compositingRenderPassDescriptor.timestampWrites; - if (r3TimestampWrites && overlayTimestampWrites && compositingTimestampWrites) { + if (r3TimestampWrites && overlayTimestampWrites && compositingTimestampWrites && r16ResolveTimestampWrites && selectionTimestampWrites) { r3TimestampWrites.querySet = this.querySet; + r16ResolveTimestampWrites.querySet = this.querySet; overlayTimestampWrites.querySet = this.querySet; compositingTimestampWrites.querySet = this.querySet; + selectionTimestampWrites.querySet = this.querySet; } } @@ -352,17 +356,27 @@ export class ViewportCache { this.timeStempBufferResolve.size); } } - + private resetBuffer = new BigInt64Array(10); public asyncGPUPerformanceUpdate() { if (this.timeStempMapBuffer.mapState === "unmapped") { this.timeStempMapBuffer.mapAsync(GPUMapMode.READ).then(() => { const times = new BigInt64Array(this.timeStempMapBuffer.getMappedRange()); const r3Time = Number(times[1] - times[0]); - const overlayTime = Number(times[3] - times[2]); - const compositingTime = Number(times[5] - times[4]); - // console.log(r3Time / 1000000, overlayTime / 1000000, compositingTime / 1000000); + const r16Time = Number(times[3] - times[2]); + const selectionTime = Number(times[5] - times[4]); + const overlayTime = Number(times[7] - times[6]); + const compositingTime = Number(times[9] - times[8]); + // console.log( + // "R3:", r3Time / 1000000, + // "R16 Resolve:", r16Time / 1000000, + // "Selection", selectionTime / 1000000, + // "Overlay", overlayTime / 1000000, + // "Compositing", compositingTime / 1000000, + // "total:", (r3Time + r16Time + selectionTime + overlayTime + compositingTime) / 1000000); + this.timeStempMapBuffer.unmap(); - this.viewport.setGPUTime(r3Time, overlayTime, compositingTime); + gpuDevice.queue.writeBuffer(this.timeStempBufferResolve, 0, this.resetBuffer, 0, this.resetBuffer.length) + this.viewport.setGPUTime(r3Time, r16Time, selectionTime, overlayTime, compositingTime); }); } } diff --git a/frontend/src/ts/ui/panes/ViewportPane.ts b/frontend/src/ts/ui/panes/ViewportPane.ts index 266a33a..40a095d 100644 --- a/frontend/src/ts/ui/panes/ViewportPane.ts +++ b/frontend/src/ts/ui/panes/ViewportPane.ts @@ -154,9 +154,12 @@ export class ViewportPane extends HTMLElement implements Viewport { return this.canvasContext.getCurrentTexture(); } - setGPUTime(r3Time: number, overlayTime: number): void { + setGPUTime(r3Time: number, r16ResolveTime: number, selectionTime: number, overlayTime: number, compositingTime: number): void { r3Time; + r16ResolveTime; + selectionTime; overlayTime; + compositingTime; } connectedCallback() { diff --git a/frontend/src/wgsl/compositing.wgsl b/frontend/src/wgsl/compositing.wgsl index 9aacc8b..9813f7b 100644 --- a/frontend/src/wgsl/compositing.wgsl +++ b/frontend/src/wgsl/compositing.wgsl @@ -4,9 +4,9 @@ @group(0) @binding(1) var idRT: texture_2d; @group(0) @binding(2) var selectionRT: texture_2d; -#include +#include -const searchSize = 1; +const searchSize = 2; const edgeColorArray: array = array( vec4f(0.0, 0.0, 0.0, 0.2), vec4f(0.93, 0.34, 0.0, 1.0), @@ -18,13 +18,15 @@ fn selectionOverlay(tc: vec2i) -> vec4f { var maxSelection = thisSelection; var idChange = false; var selectionChange = false; + let texSize = vec2i(textureDimensions(idRT, 0)); for(var y = -searchSize; y <= searchSize; y += searchSize) { for(var x = -searchSize; x <= searchSize; x += searchSize) { - if(x == 0 && y == 0) { + let tcS = tc + vec2i(x, y); + if((x == 0 && y == 0) || tcS.x < 0 || tcS.y < 0 || tcS.x >= texSize.x || tcS.y >= texSize.y) { continue; } - let val = textureLoad(idRT, tc + vec2i(x, y), 0).x; - let selection = textureLoad(selectionRT, tc + vec2i(x, y), 0).x; + let val = textureLoad(idRT, tcS, 0).x; + let selection = textureLoad(selectionRT, tcS, 0).x; maxSelection = max(maxSelection, selection); idChange |= val != thisID; selectionChange |= selection != thisSelection; @@ -55,6 +57,6 @@ fn fragment_main(@builtin(position) position: vec4f) -> @location(0) vec4f { let tc = vec2i(position.xy); let overlay = textureLoad(overlayRT, tc, 0); let selection = selectionOverlay(tc); - let color = createOutputFragment(mix(overlay.rgb, selection.rgb, selection.a)); + let color = convertToTargetColorSpace(select(overlay.rgb, selection.rgb, selection.a > 0.0)); return vec4f(color, max(overlay.a, selection.a)); } \ No newline at end of file diff --git a/frontend/src/wgsl/debug/grid.wgsl b/frontend/src/wgsl/debug/grid.wgsl index a29ba99..e6a90fe 100644 --- a/frontend/src/wgsl/debug/grid.wgsl +++ b/frontend/src/wgsl/debug/grid.wgsl @@ -72,7 +72,7 @@ fn fragment_main(vertexData: VertexOut) -> @location(0) vec4f { if(a <= 0) { discard; } - var color = vec3f(0.2); + var color = vec3f(0.3); if(a1000 > 0) { let abs_ws_pos = abs(ws_pos); @@ -80,7 +80,7 @@ fn fragment_main(vertexData: VertexOut) -> @location(0) vec4f { let isYAxis = abs_ws_pos.y < 500 && g1000_2D.y >= g1000_2D.x; if(isXAxis && isYAxis) { - color = vec3f(0.1); + color = vec3f(0.5); } else if(isXAxis) { color = vec3f(1.0, 0.2, 0.2); } else if(isYAxis) { diff --git a/frontend/src/wgsl/utility/fragmentOutput.wgsl b/frontend/src/wgsl/utility/fragmentOutput.wgsl index 39324f2..4a8ef2b 100644 --- a/frontend/src/wgsl/utility/fragmentOutput.wgsl +++ b/frontend/src/wgsl/utility/fragmentOutput.wgsl @@ -1,17 +1,8 @@ -#include +#include #include #include -override targetColorSpace: i32; // 0: sRGB; 1: Display-P3 override componentTranfere: i32; // 0: none; 1: sRGB - -fn convertToTargetColorSpace(linearRGB: vec3f) -> vec3f { - if(targetColorSpace == 1) { - return linearRGBToLinearDisplayP3(linearRGB); - } - return linearRGB; -} - fn createOutputFragment(linearRGB: vec3f) -> vec3f { var color = convertToTargetColorSpace(linearRGB); if(componentTranfere == 1) { diff --git a/frontend/src/wgsl/utility/targetColorSpace.wgsl b/frontend/src/wgsl/utility/targetColorSpace.wgsl new file mode 100644 index 0000000..d29ea64 --- /dev/null +++ b/frontend/src/wgsl/utility/targetColorSpace.wgsl @@ -0,0 +1,8 @@ +#include +override targetColorSpace: i32; // 0: sRGB; 1: Display-P3 +fn convertToTargetColorSpace(linearRGB: vec3f) -> vec3f { + if(targetColorSpace == 1) { + return linearRGBToLinearDisplayP3(linearRGB); + } + return linearRGB; +} \ No newline at end of file