dawn-cmake/examples/Animometer.cpp

189 lines
5.7 KiB
C++

// Copyright 2017 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "SampleUtils.h"
#include "utils/ComboRenderPipelineDescriptor.h"
#include "utils/SystemUtils.h"
#include "utils/WGPUHelpers.h"
#include <cstdio>
#include <cstdlib>
#include <vector>
wgpu::Device device;
wgpu::Queue queue;
wgpu::SwapChain swapchain;
wgpu::RenderPipeline pipeline;
wgpu::BindGroup bindGroup;
wgpu::Buffer ubo;
float RandomFloat(float min, float max) {
float zeroOne = rand() / float(RAND_MAX);
return zeroOne * (max - min) + min;
}
constexpr size_t kNumTriangles = 10000;
struct alignas(kMinDynamicBufferOffsetAlignment) ShaderData {
float scale;
float time;
float offsetX;
float offsetY;
float scalar;
float scalarOffset;
};
static std::vector<ShaderData> shaderData;
void init() {
device = CreateCppDawnDevice();
queue = device.GetDefaultQueue();
swapchain = GetSwapChain(device);
swapchain.Configure(GetPreferredSwapChainTextureFormat(), wgpu::TextureUsage::RenderAttachment,
640, 480);
wgpu::ShaderModule vsModule =
utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(
#version 450
layout(std140, set = 0, binding = 0) uniform Constants {
float scale;
float time;
float offsetX;
float offsetY;
float scalar;
float scalarOffset;
} c;
layout(location = 0) out vec4 v_color;
const vec4 positions[3] = vec4[3](
vec4( 0.0f, 0.1f, 0.0f, 1.0f),
vec4(-0.1f, -0.1f, 0.0f, 1.0f),
vec4( 0.1f, -0.1f, 0.0f, 1.0f)
);
const vec4 colors[3] = vec4[3](
vec4(1.0f, 0.0f, 0.0f, 1.0f),
vec4(0.0f, 1.0f, 0.0f, 1.0f),
vec4(0.0f, 0.0f, 1.0f, 1.0f)
);
void main() {
vec4 position = positions[gl_VertexIndex];
vec4 color = colors[gl_VertexIndex];
float fade = mod(c.scalarOffset + c.time * c.scalar / 10.0, 1.0);
if (fade < 0.5) {
fade = fade * 2.0;
} else {
fade = (1.0 - fade) * 2.0;
}
float xpos = position.x * c.scale;
float ypos = position.y * c.scale;
float angle = 3.14159 * 2.0 * fade;
float xrot = xpos * cos(angle) - ypos * sin(angle);
float yrot = xpos * sin(angle) + ypos * cos(angle);
xpos = xrot + c.offsetX;
ypos = yrot + c.offsetY;
v_color = vec4(fade, 1.0 - fade, 0.0, 1.0) + color;
gl_Position = vec4(xpos, ypos, 0.0, 1.0);
})");
wgpu::ShaderModule fsModule =
utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"(
#version 450
layout(location = 0) out vec4 fragColor;
layout(location = 0) in vec4 v_color;
void main() {
fragColor = v_color;
})");
wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Vertex, wgpu::BindingType::UniformBuffer, true}});
utils::ComboRenderPipelineDescriptor descriptor(device);
descriptor.layout = utils::MakeBasicPipelineLayout(device, &bgl);
descriptor.vertexStage.module = vsModule;
descriptor.cFragmentStage.module = fsModule;
descriptor.cColorStates[0].format = GetPreferredSwapChainTextureFormat();
pipeline = device.CreateRenderPipeline(&descriptor);
shaderData.resize(kNumTriangles);
for (auto& data : shaderData) {
data.scale = RandomFloat(0.2f, 0.4f);
data.time = 0.0;
data.offsetX = RandomFloat(-0.9f, 0.9f);
data.offsetY = RandomFloat(-0.9f, 0.9f);
data.scalar = RandomFloat(0.5f, 2.0f);
data.scalarOffset = RandomFloat(0.0f, 10.0f);
}
wgpu::BufferDescriptor bufferDesc;
bufferDesc.size = kNumTriangles * sizeof(ShaderData);
bufferDesc.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Uniform;
ubo = device.CreateBuffer(&bufferDesc);
bindGroup = utils::MakeBindGroup(device, bgl, {{0, ubo, 0, sizeof(ShaderData)}});
}
void frame() {
wgpu::TextureView backbufferView = swapchain.GetCurrentTextureView();
static int f = 0;
f++;
for (auto& data : shaderData) {
data.time = f / 60.0f;
}
queue.WriteBuffer(ubo, 0, shaderData.data(), kNumTriangles * sizeof(ShaderData));
utils::ComboRenderPassDescriptor renderPass({backbufferView});
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
{
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
pass.SetPipeline(pipeline);
for (size_t i = 0; i < kNumTriangles; i++) {
uint32_t offset = i * sizeof(ShaderData);
pass.SetBindGroup(0, bindGroup, 1, &offset);
pass.Draw(3);
}
pass.EndPass();
}
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
swapchain.Present();
DoFlush();
fprintf(stderr, "frame %i\n", f);
}
int main(int argc, const char* argv[]) {
if (!InitSample(argc, argv)) {
return 1;
}
init();
while (!ShouldQuit()) {
frame();
utils::USleep(16000);
}
// TODO release stuff
}