Skip to content

Commit 97a02f0

Browse files
committed
image loading example
1 parent 4095125 commit 97a02f0

File tree

2 files changed

+352
-1
lines changed

2 files changed

+352
-1
lines changed

examples/image.jl

Lines changed: 350 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,350 @@
1+
using OhMyREPL
2+
using Eyeball
3+
using WGPU
4+
using GeometryBasics
5+
using LinearAlgebra
6+
using Rotations
7+
using WGPU_jll
8+
using GLFW
9+
using StaticArrays
10+
using Images
11+
using ImageView
12+
13+
WGPU.SetLogLevel(WGPULogLevel_Debug)
14+
15+
shaderSource = Vector{UInt8}(
16+
"""
17+
struct Locals {
18+
transform: mat4x4<f32>,
19+
};
20+
21+
@group(0) @binding(0)
22+
var<uniform> r_locals: Locals;
23+
24+
struct VertexInput {
25+
@location(0) pos : vec4<f32>,
26+
@location(1) texcoord: vec2<f32>,
27+
};
28+
29+
struct VertexOutput {
30+
@location(0) texcoord: vec2<f32>,
31+
@builtin(position) pos: vec4<f32>,
32+
};
33+
34+
@stage(vertex)
35+
fn vs_main(in: VertexInput) -> VertexOutput {
36+
let ndc: vec4<f32> = r_locals.transform * in.pos;
37+
var out: VertexOutput;
38+
out.pos = vec4<f32>(ndc.x, ndc.y, 0.0, 1.0);
39+
out.texcoord = in.texcoord;
40+
return out;
41+
}
42+
43+
@group(0) @binding(1)
44+
var r_tex: texture_2d<f32>;
45+
46+
@group(0) @binding(2)
47+
var r_sampler: sampler;
48+
49+
@stage(fragment)
50+
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
51+
let value = textureSample(r_tex, r_sampler, in.texcoord);
52+
return vec4<f32>(value);
53+
}
54+
"""
55+
);
56+
57+
canvas = WGPU.defaultCanvas(WGPU.WGPUCanvas)
58+
gpuDevice = WGPU.getDefaultDevice()
59+
shadercode = WGPU.loadWGSL(shaderSource) |> first;
60+
cshader = Ref(WGPU.createShaderModule(gpuDevice, "shadercode", shadercode, nothing, nothing));
61+
62+
flatten(x) = reshape(x, (:,))
63+
64+
vertexData = cat([
65+
[-1, -1, 1, 1, 0, 0],
66+
[1, -1, 1, 1, 1, 0],
67+
[1, 1, 1, 1, 1, 1],
68+
[-1, 1, 1, 1, 0, 1],
69+
[-1, 1, -1, 1, 1, 0],
70+
[1, 1, -1, 1, 0, 0],
71+
[1, -1, -1, 1, 0, 1],
72+
[-1, -1, -1, 1, 1, 1],
73+
[1, -1, -1, 1, 0, 0],
74+
[1, 1, -1, 1, 1, 0],
75+
[1, 1, 1, 1, 1, 1],
76+
[1, -1, 1, 1, 0, 1],
77+
[-1, -1, 1, 1, 1, 0],
78+
[-1, 1, 1, 1, 0, 0],
79+
[-1, 1, -1, 1, 0, 1],
80+
[-1, -1, -1, 1, 1, 1],
81+
[1, 1, -1, 1, 1, 0],
82+
[-1, 1, -1, 1, 0, 0],
83+
[-1, 1, 1, 1, 0, 1],
84+
[1, 1, 1, 1, 1, 1],
85+
[1, -1, 1, 1, 0, 0],
86+
[-1, -1, 1, 1, 1, 0],
87+
[-1, -1, -1, 1, 1, 1],
88+
[1, -1, -1, 1, 0, 1],
89+
]..., dims=2) .|> Float32
90+
91+
92+
indexData = cat([
93+
[0, 1, 2, 2, 3, 0],
94+
[4, 5, 6, 6, 7, 4],
95+
[8, 9, 10, 10, 11, 8],
96+
[12, 13, 14, 14, 15, 12],
97+
[16, 17, 18, 18, 19, 16],
98+
[20, 21, 22, 22, 23, 20],
99+
]..., dims=2) .|> UInt32
100+
101+
102+
textureData = begin
103+
img = load("/Users/arhik/Pictures/OIP.jpeg")
104+
img = imresize(img, (256, 256))
105+
img = RGBA.(img)
106+
imgview = channelview(img) |> collect
107+
# imgview = permutedims(imgview, (2, 3, 1)) |> collect
108+
# permutedims(imgview, (2, 1, 3)) |> collect
109+
end
110+
111+
112+
textureSize = (size(textureData)[2:3]..., 1)
113+
114+
115+
uniformData = ones(Float32, (4, 4)) |> Diagonal |> Matrix
116+
117+
118+
(vertexBuffer, _) = WGPU.createBufferWithData(
119+
gpuDevice,
120+
"vertexBuffer",
121+
vertexData,
122+
["Vertex", "CopySrc"]
123+
)
124+
125+
126+
(indexBuffer, _) = WGPU.createBufferWithData(
127+
gpuDevice,
128+
"indexBuffer",
129+
indexData |> flatten,
130+
"Index"
131+
)
132+
133+
(uniformBuffer, _) = WGPU.createBufferWithData(
134+
gpuDevice,
135+
"uniformBuffer",
136+
uniformData,
137+
["Uniform", "CopyDst"]
138+
)
139+
140+
renderTextureFormat = WGPU.getPreferredFormat(canvas)
141+
142+
texture = WGPU.createTexture(
143+
gpuDevice,
144+
"texture",
145+
textureSize,
146+
1,
147+
1,
148+
WGPUTextureDimension_2D,
149+
WGPUTextureFormat_RGBA8UnormSrgb,
150+
WGPU.getEnum(WGPU.WGPUTextureUsage, ["CopyDst", "TextureBinding"]),
151+
)
152+
153+
textureView = WGPU.createView(texture)
154+
155+
dstLayout = [
156+
:dst => [
157+
:texture => texture |> Ref,
158+
:mipLevel => 0,
159+
:origin => ((0, 0, 0) .|> Float32)
160+
],
161+
:textureData => textureData |> Ref,
162+
:layout => [
163+
:offset => 0,
164+
:bytesPerRow => 256*4, # TODO
165+
:rowsPerImage => 256
166+
],
167+
:textureSize => textureSize
168+
]
169+
170+
sampler = WGPU.createSampler(gpuDevice)
171+
172+
WGPU.writeTexture(gpuDevice.queue; dstLayout...)
173+
174+
bindingLayouts = [
175+
WGPU.WGPUBufferEntry => [
176+
:binding => 0,
177+
:visibility => ["Vertex", "Fragment"],
178+
:type => "Uniform"
179+
],
180+
WGPU.WGPUTextureEntry => [
181+
:binding => 1,
182+
:visibility => "Fragment",
183+
:sampleType => "Float",
184+
:viewDimension => "2D",
185+
:multisampled => false
186+
],
187+
WGPU.WGPUSamplerEntry => [
188+
:binding => 2,
189+
:visibility => "Fragment",
190+
:type => "Filtering"
191+
]
192+
]
193+
194+
bindings = [
195+
WGPU.GPUBuffer => [
196+
:binding => 0,
197+
:buffer => uniformBuffer,
198+
:offset => 0,
199+
:size => uniformBuffer.size
200+
],
201+
WGPU.GPUTextureView => [
202+
:binding => 1,
203+
:textureView => textureView
204+
],
205+
WGPU.GPUSampler => [
206+
:binding => 2,
207+
:sampler => sampler
208+
]
209+
]
210+
211+
(bindGroupLayouts, bindGroup) = WGPU.makeBindGroupAndLayout(gpuDevice, bindingLayouts, bindings)
212+
#
213+
# cBindingLayoutsList = WGPU.makeEntryList(bindingLayouts) |> Ref
214+
# cBindingsList = WGPU.makeBindGroupEntryList(bindings) |> Ref
215+
# bindGroupLayout = WGPU.createBindGroupLayout(gpuDevice, "Bind Group Layout", cBindingLayoutsList[])
216+
# bindGroup = WGPU.createBindGroup("BindGroup", gpuDevice, bindGroupLayout, cBindingsList[])
217+
#
218+
# if bindGroupLayout.internal[] == C_NULL
219+
# bindGroupLayouts = []
220+
# else
221+
# bindGroupLayouts = map((x)->x.internal[], [bindGroupLayout,])
222+
# end
223+
224+
pipelineLayout = WGPU.createPipelineLayout(gpuDevice, "PipeLineLayout", bindGroupLayouts)
225+
226+
presentContext = WGPU.getContext(canvas)
227+
228+
WGPU.determineSize(presentContext[])
229+
230+
WGPU.config(presentContext, device=gpuDevice, format = renderTextureFormat)
231+
232+
renderpipelineOptions = [
233+
WGPU.GPUVertexState => [
234+
:_module => cshader[],
235+
:entryPoint => "vs_main",
236+
:buffers => [
237+
WGPU.GPUVertexBufferLayout => [
238+
:arrayStride => 6*4,
239+
:stepMode => "Vertex",
240+
:attributes => [
241+
:attribute => [
242+
:format => "Float32x4",
243+
:offset => 0,
244+
:shaderLocation => 0
245+
],
246+
:attribute => [
247+
:format => "Float32x2",
248+
:offset => 4*4,
249+
:shaderLocation => 1
250+
]
251+
]
252+
],
253+
]
254+
],
255+
WGPU.GPUPrimitiveState => [
256+
:topology => "TriangleList",
257+
:frontFace => "CCW",
258+
:cullMode => "Back",
259+
:stripIndexFormat => "Undefined"
260+
],
261+
WGPU.GPUDepthStencilState => [],
262+
WGPU.GPUMultiSampleState => [
263+
:count => 1,
264+
:mask => typemax(UInt32),
265+
:alphaToCoverageEnabled=>false
266+
],
267+
WGPU.GPUFragmentState => [
268+
:_module => cshader[],
269+
:entryPoint => "fs_main",
270+
:targets => [
271+
WGPU.GPUColorTargetState => [
272+
:format => renderTextureFormat,
273+
:color => [
274+
:srcFactor => "One",
275+
:dstFactor => "Zero",
276+
:operation => "Add"
277+
],
278+
:alpha => [
279+
:srcFactor => "One",
280+
:dstFactor => "Zero",
281+
:operation => "Add",
282+
]
283+
],
284+
]
285+
]
286+
]
287+
288+
renderPipeline = WGPU.createRenderPipeline(
289+
gpuDevice, pipelineLayout,
290+
renderpipelineOptions;
291+
label=" "
292+
)
293+
294+
295+
prevTime = time()
296+
try
297+
while !GLFW.WindowShouldClose(canvas.windowRef[])
298+
a1 = 0.3f0
299+
a2 = time()
300+
s = 0.6f0
301+
ortho = s.*Matrix{Float32}(I, (3, 3))
302+
rotxy = RotXY(a1, a2)
303+
uniformData[1:3, 1:3] .= rotxy*ortho
304+
305+
(tmpBuffer, _) = WGPU.createBufferWithData(
306+
gpuDevice, "ROTATION BUFFER", uniformData, "CopySrc"
307+
)
308+
309+
currentTextureView = WGPU.getCurrentTexture(presentContext[]) |> Ref;
310+
cmdEncoder = WGPU.createCommandEncoder(gpuDevice, "CMD ENCODER")
311+
WGPU.copyBufferToBuffer(cmdEncoder, tmpBuffer, 0, uniformBuffer, 0, sizeof(uniformData))
312+
313+
renderPassOptions = [
314+
WGPU.GPUColorAttachments => [
315+
:attachments => [
316+
WGPU.GPUColorAttachment => [
317+
:view => currentTextureView[],
318+
:resolveTarget => C_NULL,
319+
:clearValue => (abs(0.8f0*sin(a2)), abs(0.8f0*cos(a2)), 0.3f0, 1.0f0),
320+
:loadOp => WGPULoadOp_Clear,
321+
:storeOp => WGPUStoreOp_Store,
322+
],
323+
]
324+
],
325+
WGPU.GPUDepthStencilAttachments => [
326+
]
327+
]
328+
329+
renderPass = WGPU.beginRenderPass(cmdEncoder, renderPassOptions |> Ref; label= "BEGIN RENDER PASS")
330+
331+
WGPU.setPipeline(renderPass, renderPipeline)
332+
WGPU.setIndexBuffer(renderPass, indexBuffer, "Uint32")
333+
WGPU.setVertexBuffer(renderPass, 0, vertexBuffer)
334+
WGPU.setBindGroup(renderPass, 0, bindGroup, UInt32[], 0, 99)
335+
WGPU.drawIndexed(renderPass, Int32(indexBuffer.size/sizeof(UInt32)); instanceCount = 1, firstIndex=0, baseVertex= 0, firstInstance=0)
336+
WGPU.endEncoder(renderPass)
337+
WGPU.submit(gpuDevice.queue, [WGPU.finish(cmdEncoder),])
338+
WGPU.present(presentContext[])
339+
GLFW.PollEvents()
340+
# dataDown = reinterpret(Float32, WGPU.readBuffer(gpuDevice, vertexBuffer, 0, sizeof(vertexData)))
341+
# @info sum(dataDown .== vertexData |> flatten)
342+
# @info dataDown
343+
# println("FPS : $(1/(a2 - prevTime))")
344+
# WGPU.destroy(tmpBuffer)
345+
# WGPU.destroy(currentTextureView[])
346+
prevTime = a2
347+
end
348+
finally
349+
GLFW.DestroyWindow(canvas.windowRef[])
350+
end

examples/triangle.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
## Load WGPU
22
using WGPU
33
using GLFW
4-
4+
using Debugger
55
using WGPU_jll
66
using Images
77

@@ -36,6 +36,7 @@ shaderSource = Vector{UInt8}(
3636
"""
3737
);
3838

39+
@enter canvas = WGPU.defaultInit(WGPU.WGPUCanvas);
3940
canvas = WGPU.defaultInit(WGPU.WGPUCanvas);
4041
gpuDevice = WGPU.getDefaultDevice();
4142
shadercode = WGPU.loadWGSL(shaderSource) |> first;

0 commit comments

Comments
 (0)