Skip to content

Commit 6488e4b

Browse files
authored
Merge pull request #12 from kaizhangNV/main
Add support to print result for the printable shader
2 parents 15bc3d3 + ae9db1b commit 6488e4b

File tree

7 files changed

+121
-44
lines changed

7 files changed

+121
-44
lines changed

build.mk

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ $(TRY_SLANG_TARGET_DIRECTORY_PATH)/water_demo.js: $(TRY_SLANG_SOURCE_DIRECTORY_P
8484
$(TRY_SLANG_TARGET_DIRECTORY_PATH)/ui.js: $(TRY_SLANG_SOURCE_DIRECTORY_PATH)/ui.js
8585
$(COPY) $^ $@
8686

87-
$(TRY_SLANG_TARGET_DIRECTORY_PATH)/styles: $(TRY_SLANG_SOURCE_DIRECTORY_PATH)/styles
87+
$(TRY_SLANG_TARGET_DIRECTORY_PATH)/styles: $(TRY_SLANG_SOURCE_DIRECTORY_PATH)/styles/styles.css
88+
mkdir -p $(TRY_SLANG_TARGET_DIRECTORY_PATH)/styles
8889
$(COPY) $^ $@
8990

9091
$(TRY_SLANG_TARGET_DIRECTORY_PATH)/compiler.js: $(TRY_SLANG_SOURCE_DIRECTORY_PATH)/compiler.js

compiler.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,22 @@ class SlangCompiler
55
static SLANG_STAGE_FRAGMENT = 5;
66
static SLANG_STAGE_COMPUTE = 6;
77

8+
static RENDER_SHADER = 0;
9+
static PRINT_SHADER = 1;
10+
static NON_RUNNABLE_SHADER = 2;
11+
812
globalSlangSession = null;
913
slangSession = null;
1014

1115
slangWasmModule;
12-
1316
diagnosticsMsg;
17+
shaderType;
18+
1419
constructor(module)
1520
{
1621
this.slangWasmModule = module;
1722
this.diagnosticsMsg = "";
23+
this.shaderType = SlangCompiler.NON_RUNNABLE_SHADER;
1824
}
1925

2026
init()
@@ -46,6 +52,11 @@ class SlangCompiler
4652
var entryPoint = module.findAndCheckEntryPoint(entryPointName, SlangCompiler.SLANG_STAGE_COMPUTE);
4753
if(entryPoint)
4854
{
55+
if (i == 0)
56+
this.shaderType = SlangCompiler.RENDER_SHADER;
57+
else
58+
this.shaderType = SlangCompiler.PRINT_SHADER;
59+
4960
return entryPoint;
5061
}
5162
else

compute.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ class ComputePipeline
1111
uniformBufferHost = new Float32Array(4);
1212

1313
outputBuffer;
14+
outputBufferRead;
1415
outputTexture;
1516
device;
1617
bindGroup;
@@ -87,21 +88,21 @@ class ComputePipeline
8788
// All out compute pipeline will have 2 outputs:
8889
// 1. A buffer that will be used to read the result back to the CPU
8990
// 2. A texture that will be used to display the result on the screen
90-
createOutput(invalid)
91+
createOutput(invalid, windowSize)
9192
{
9293
if (invalid)
9394
{
9495
this.destroyResources();
9596
let usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC;
96-
const numberElements = canvas.clientWidth * canvas.clientHeight;
97+
const numberElements = windowSize[0] * windowSize[1];
9798
const size = numberElements * 4; // int type
9899
this.outputBuffer = this.device.createBuffer({lable: 'outputBuffer', size, usage});
99100

100101
usage = GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST;
101102
const outputBufferRead = this.device.createBuffer({lable: 'outputBufferRead', size, usage});
102103
this.outputBufferRead = outputBufferRead;
103104

104-
const storageTexture = createOutputTexture(device, canvas.clientWidth, canvas.clientHeight, 'r32float');
105+
const storageTexture = createOutputTexture(device, windowSize[0], windowSize[1], 'r32float');
105106
this.outputTexture = storageTexture;
106107

107108
}
@@ -118,9 +119,9 @@ class ComputePipeline
118119
this.device.queue.writeBuffer(this.uniformBuffer, 0, this.uniformBufferHost);
119120
}
120121

121-
setupComputePipeline()
122+
setupComputePipeline(windowSize)
122123
{
123-
this.createOutput(true);
124+
this.createOutput(true, windowSize);
124125
this.createComputePipelineLayout();
125126
}
126127
}

index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
<div class="resultSpace">
9393
<div class="outputSpace" id="output">
9494
<canvas class="renderCanvas" id="canvas"></canvas>
95+
<textarea readonly class="printSpace" id="printResult" style="display:none"></textarea>
9596
</div>
9697
<div class="gutter gutter-vertical"></div>
9798
<div class="codeGenSpace" id="codeGen"></div>

styles/styles.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,12 @@ h2 {
126126
height: 100%;
127127
}
128128

129+
.printSpace {
130+
background-color: var(--very-light-grey);
131+
width: 100%;
132+
height: 100%;
133+
}
134+
129135
.gutter {
130136
background-color: var(--black);
131137
background-repeat: no-repeat;
@@ -186,6 +192,7 @@ h2 {
186192
.dropdown {
187193
position: relative;
188194
display: inline-block;
195+
z-index: 99999;
189196
}
190197

191198
.dropdown-btn {

try-slang.js

Lines changed: 92 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ var codeGenArea;
1313

1414
var sourceCodeChange = true;
1515

16+
var currentWindowSize = [300, 150];
17+
18+
const RENDER_MODE = SlangCompiler.RENDER_SHADER;
19+
const PRINT_MODE = SlangCompiler.PRINT_SHADER;
20+
var currentMode = RENDER_MODE;
21+
1622
// TODO: Question?
1723
// When we generate the shader code to wgsl, the uniform variable (float time) will have 16 bytes alignment, which is not shown in the slang
1824
// code. So how the user can know the correct alignment of the uniform variable without using the slang reflection API or
@@ -86,6 +92,13 @@ function resizeCanvas(entries)
8692
{
8793
const canvas = entries[0].target;
8894

95+
if (canvas.style.display == "none")
96+
{
97+
var parentDiv = document.getElementById("output");
98+
currentWindowSize = [parentDiv.clientWidth, parentDiv.clientHeight];
99+
return true;
100+
}
101+
89102
const width = canvas.clientWidth;
90103
const height = canvas.clientHeight;
91104

@@ -95,6 +108,7 @@ function resizeCanvas(entries)
95108
canvas.width = Math.max(1, Math.min(width, device.limits.maxTextureDimension2D));
96109
canvas.height = Math.max(1, Math.min(height, device.limits.maxTextureDimension2D));
97110

111+
currentWindowSize = [canvas.width, canvas.height];
98112
return true;
99113
}
100114

@@ -111,16 +125,51 @@ function resizeCanvasHandler(entries)
111125
{
112126
if (computePipeline && passThroughPipeline)
113127
{
114-
computePipeline.createOutput(true);
128+
computePipeline.createOutput(true, currentWindowSize);
115129
computePipeline.createBindGroup();
116130
passThroughPipeline.inputTexture = computePipeline.outputTexture;
117131
passThroughPipeline.createBindGroup();
118-
requestAnimationFrame(render);
132+
if (canvas.style.display != "none")
133+
{
134+
requestAnimationFrame(render);
135+
}
119136
}
120137
}
121138
}, 100);
122139
}
123140

141+
function toggleDisplayMode(displayMode)
142+
{
143+
if (currentMode == displayMode)
144+
return;
145+
146+
if (displayMode == RENDER_MODE)
147+
{
148+
var printResult = document.getElementById("printResult")
149+
printResult.style.display = "none";
150+
151+
canvas.style.display="grid";
152+
canvas.style.width = "100%";
153+
canvas.style.height = "100%";
154+
155+
currentMode = RENDER_MODE;
156+
}
157+
else if (displayMode == PRINT_MODE)
158+
{
159+
canvas.style.display="none";
160+
var printResult = document.getElementById("printResult")
161+
printResult.style.display = "grid";
162+
printResult.style.width = "100%";
163+
printResult.style.height = "100%";
164+
printResult.style.backgroundColor = "white";
165+
166+
currentMode = PRINT_MODE;
167+
}
168+
else
169+
{
170+
console.log("Invalid display mode " + displayMode);
171+
}
172+
}
124173

125174
async function render(timeMS)
126175
{
@@ -140,55 +189,61 @@ async function render(timeMS)
140189

141190
pass.setBindGroup(0, computePipeline.bindGroup);
142191
pass.setPipeline(computePipeline.pipeline);
143-
pass.dispatchWorkgroups(canvas.clientWidth, canvas.clientHeight);
192+
pass.dispatchWorkgroups(currentWindowSize[0], currentWindowSize[1]);
144193
pass.end();
145194

146-
// Get a WebGPU context from the canvas and configure it
147-
148-
var renderPassDescriptor = passThroughPipeline.createRenderPassDesc();
149-
renderPassDescriptor.colorAttachments[0].view = context.getCurrentTexture().createView();
150-
const renderPass = encoder.beginRenderPass(renderPassDescriptor);
151-
152-
renderPass.setBindGroup(0, passThroughPipeline.bindGroup);
153-
renderPass.setPipeline(passThroughPipeline.pipeline);
154-
renderPass.draw(6); // call our vertex shader 6 times.
155-
renderPass.end();
195+
if (compiler.shaderType == SlangCompiler.RENDER_SHADER)
196+
{
197+
var renderPassDescriptor = passThroughPipeline.createRenderPassDesc();
198+
renderPassDescriptor.colorAttachments[0].view = context.getCurrentTexture().createView();
199+
const renderPass = encoder.beginRenderPass(renderPassDescriptor);
200+
201+
renderPass.setBindGroup(0, passThroughPipeline.bindGroup);
202+
renderPass.setPipeline(passThroughPipeline.pipeline);
203+
renderPass.draw(6); // call our vertex shader 6 times.
204+
renderPass.end();
205+
}
156206

157-
// copy output buffer back
158-
// encoder.copyBufferToBuffer(computePipeline.outputBuffer, 0, computePipeline.outputBufferRead, 0, computePipeline.outputBuffer.size);
207+
// copy output buffer back in print mode
208+
if (compiler.shaderType == SlangCompiler.PRINT_SHADER)
209+
encoder.copyBufferToBuffer(computePipeline.outputBuffer, 0, computePipeline.outputBufferRead, 0, computePipeline.outputBuffer.size);
159210

160211
// Finish encoding and submit the commands
161212
const commandBuffer = encoder.finish();
162213
device.queue.submit([commandBuffer]);
163214

164-
requestAnimationFrame(render);
215+
// Only request the next frame if we are in the render mode
216+
if (compiler.shaderType == SlangCompiler.RENDER_SHADER)
217+
requestAnimationFrame(render);
165218
}
166219

167-
async function waitForComplete(outputBufferRead)
220+
async function printResult(outputBufferRead)
168221
{
169-
// Read the results
222+
await device.queue.onSubmittedWorkDone();
223+
// Read the results once the job is done
170224
await Promise.all([
171225
outputBufferRead.mapAsync(GPUMapMode.READ),
172226
]);
173227

174228
const output = new Int32Array(outputBufferRead.getMappedRange());
175229

176-
outputResult(output).then(() => {
177-
outputBufferRead.unmap()
178-
});
230+
const textResult = formatResult(output);
231+
outputBufferRead.unmap();
232+
233+
console.log(canvas.style.display);
234+
235+
document.getElementById("printResult").value = textResult;
179236
}
180237

181-
async function outputResult(output)
238+
function formatResult(output)
182239
{
183-
// TODO: Optional - output the printable result to the output area
184-
// we don't have such area in the current UI
185-
// var result = "";
186-
// for (let i = 0; i < output.length; i++)
187-
// {
188-
// result += output[i] + '\n';
189-
// }
190-
//
191-
// document.getElementById("result").value = result;
240+
var result = "";
241+
for (let i = 0; i < output.length; i++)
242+
{
243+
result += output[i] + '\n';
244+
}
245+
246+
return result;
192247
}
193248

194249

@@ -199,7 +254,7 @@ var onRun = () => {
199254
if (!computePipeline)
200255
{
201256
computePipeline = new ComputePipeline(device);
202-
computePipeline.setupComputePipeline();
257+
computePipeline.setupComputePipeline(currentWindowSize);
203258
computePipeline.createUniformBuffer(4); // 4 bytes for float number
204259
}
205260

@@ -221,11 +276,12 @@ var onRun = () => {
221276
return;
222277
}
223278

279+
toggleDisplayMode(compiler.shaderType);
280+
224281
render(0);
225-
// TODO: This function is used to read the output buffer from GPU, and print out.
226-
// We will add an option to select render Mode and print mode. Once print mode is selected,
227-
// we will not enable the animation, and will call this function to print results on screen.
228-
// waitForComplete(computePipeline.outputBufferRead);
282+
283+
if (compiler.shaderType == SlangCompiler.PRINT_SHADER)
284+
printResult(computePipeline.outputBufferRead);
229285
}
230286

231287
function compileShader(entryPoint)

water_demo.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ float encodeColor(float4 color)
187187
188188
// Main
189189
[shader("compute")]
190-
void computeMain(int3 dispatchThreadID : SV_DispatchThreadID)
190+
void imageMain(int3 dispatchThreadID : SV_DispatchThreadID)
191191
{
192192
uint width = 0;
193193
uint height = 0;

0 commit comments

Comments
 (0)