mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
Merge #203
203: Add compute example r=kvark a=Napokue Co-authored-by: Timo de Kort <dekort.timo@gmail.com>
This commit is contained in:
15
Makefile
15
Makefile
@@ -70,11 +70,14 @@ lib-remote: Cargo.lock wgpu-remote/Cargo.toml $(wildcard wgpu-native/**/*.rs wgp
|
||||
ffi/wgpu.h: wgpu-native/cbindgen.toml $(wildcard wgpu-native/**/*.rs)
|
||||
rustup run nightly cbindgen wgpu-native > $(FFI_DIR)/wgpu.h
|
||||
|
||||
ffi/wgpu-remote.h: wgpu-remote/cbindgen.toml $(wildcard wgpu-native/**/*.rs wgpu-remote/**/*.rs)
|
||||
rustup run nightly cbindgen wgpu-remote >$(FFI_DIR)/wgpu-remote.h
|
||||
ffi/wgpu-remote.h: wgpu-remote/cbindgen.toml $(wildcard wgpu-native/**/*.rs wgpu-remote/**/*.rs)
|
||||
rustup run nightly cbindgen wgpu-remote > $(FFI_DIR)/wgpu-remote.h
|
||||
|
||||
examples-native: lib-native $(FFI_DIR)/wgpu.h examples/hello_triangle_c/main.c
|
||||
cd examples/hello_triangle_c && $(CREATE_BUILD_DIR) && cd build && cmake .. -DBACKEND=$(FEATURE_RUST) $(GENERATOR_PLATFORM) && cmake --build .
|
||||
example-compute: lib-native $(FFI_DIR)/wgpu.h examples/compute/main.c
|
||||
cd examples/compute && $(CREATE_BUILD_DIR) && cd build && cmake .. -DBACKEND=$(FEATURE_RUST) $(GENERATOR_PLATFORM) && cmake --build .
|
||||
|
||||
examples-remote: lib-remote $(FFI_DIR)/wgpu-remote.h examples/hello_remote_c/main.c
|
||||
cd examples/hello_remote_c && $(CREATE_BUILD_DIR) && cd build && cmake .. && cmake --build .
|
||||
example-triangle: lib-native $(FFI_DIR)/wgpu.h examples/triangle/main.c
|
||||
cd examples/triangle && $(CREATE_BUILD_DIR) && cd build && cmake .. -DBACKEND=$(FEATURE_RUST) $(GENERATOR_PLATFORM) && cmake --build .
|
||||
|
||||
example-remote: lib-remote $(FFI_DIR)/wgpu-remote.h examples/remote/main.c
|
||||
cd examples/remote && $(CREATE_BUILD_DIR) && cd build && cmake .. && cmake --build .
|
||||
41
README.md
41
README.md
@@ -20,14 +20,37 @@ Supported platforms:
|
||||
|
||||
## Usage
|
||||
|
||||
This repository contains C-language examples that link to the native library targets and perform basic rendering and computation.
|
||||
To run the C triangle example, install a C compiler + glfw 3, then run these commands at the root of the repo:
|
||||
```
|
||||
rustup toolchain install nightly
|
||||
cargo install cbindgen
|
||||
make examples-native
|
||||
cd examples/hello_triangle_c/build
|
||||
./hello_triangle
|
||||
This repository contains C-language examples that link to the native library targets and perform basic rendering and computation.
|
||||
|
||||
### Prerequisites
|
||||
- C compiler
|
||||
- GLFW 3
|
||||
- Rust nightly toolchain
|
||||
```bash
|
||||
rustup toolchain install nightly
|
||||
```
|
||||
- [Cbindgen](https://github.com/eqrion/cbindgen)
|
||||
```bash
|
||||
cargo install cbindgen
|
||||
```
|
||||
|
||||
|
||||
### Running an example
|
||||
The examples are located under the [examples](examples) directory. We are using a [Makefile](Makefile) for running the examples.
|
||||
|
||||
#### Triangle
|
||||
```bash
|
||||
make example-triangle
|
||||
```
|
||||
|
||||
The idiomatic Rust wrapper lives in https://github.com/gfx-rs/wgpu-rs and provides a number of more complex examples to get a feel of the API.
|
||||
#### Compute
|
||||
```bash
|
||||
make example-compute
|
||||
```
|
||||
|
||||
#### Remote
|
||||
```bash
|
||||
make example-remote
|
||||
```
|
||||
|
||||
The idiomatic Rust wrapper lives in https://github.com/gfx-rs/wgpu-rs and provides a number of more [complex examples](https://github.com/gfx-rs/wgpu-rs/tree/master/examples) to get a feel of the API.
|
||||
@@ -14,11 +14,11 @@ if(NOT DEFINED BACKEND OR NOT "${BACKEND}" IN_LIST AVAILABLE_BACKENDS)
|
||||
message(FATAL_ERROR "BACKEND invalid or undefined, available backends: ${AVAILABLE_BACKENDS}")
|
||||
endif()
|
||||
|
||||
project(hello_triangle)
|
||||
project(compute)
|
||||
|
||||
set(TARGET_NAME hello_triangle)
|
||||
set(TARGET_NAME compute)
|
||||
|
||||
add_executable(hello_triangle main.c)
|
||||
add_executable(compute main.c ../framework.c)
|
||||
|
||||
if(MSVC)
|
||||
add_definitions(-DWGPU_TARGET=WGPU_TARGET_WINDOWS)
|
||||
@@ -47,5 +47,7 @@ find_library(WGPU_LIBRARY wgpu_native
|
||||
)
|
||||
|
||||
target_include_directories(${TARGET_NAME} PUBLIC $ENV{GLFW3_INCLUDE_DIR})
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../ffi)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../)
|
||||
|
||||
target_link_libraries(${TARGET_NAME} glfw ${WGPU_LIBRARY} ${OS_LIBRARIES})
|
||||
138
examples/compute/main.c
Normal file
138
examples/compute/main.c
Normal file
@@ -0,0 +1,138 @@
|
||||
#ifndef WGPU_H
|
||||
#define WGPU_H
|
||||
#include "wgpu.h"
|
||||
#endif
|
||||
|
||||
#include "framework.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define BINDINGS_LENGTH (1)
|
||||
#define BIND_GROUP_LAYOUTS_LENGTH (1)
|
||||
|
||||
int main(
|
||||
int argc,
|
||||
char *argv[]) {
|
||||
|
||||
if (argc != 5) {
|
||||
printf("You must pass 4 positive integers!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t numbers[] = {
|
||||
strtoul(argv[1], NULL, 0),
|
||||
strtoul(argv[2], NULL, 0),
|
||||
strtoul(argv[3], NULL, 0),
|
||||
strtoul(argv[4], NULL, 0),
|
||||
};
|
||||
|
||||
uint32_t size = sizeof(numbers);
|
||||
|
||||
uint32_t numbers_length = size / sizeof(uint32_t);
|
||||
|
||||
WGPUInstanceId instance = wgpu_create_instance();
|
||||
|
||||
WGPUAdapterId adapter = wgpu_instance_get_adapter(instance,
|
||||
&(WGPUAdapterDescriptor){
|
||||
.power_preference = WGPUPowerPreference_LowPower,
|
||||
});
|
||||
|
||||
WGPUDeviceId device = wgpu_adapter_request_device(adapter,
|
||||
&(WGPUDeviceDescriptor){
|
||||
.extensions = NULL
|
||||
});
|
||||
|
||||
uint8_t *staging_memory;
|
||||
|
||||
WGPUBufferId staging_buffer = wgpu_device_create_buffer_mapped(device,
|
||||
&(WGPUBufferDescriptor){
|
||||
.size = size,
|
||||
.usage = WGPUBufferUsage_MAP_READ},
|
||||
&staging_memory);
|
||||
|
||||
memcpy((uint32_t *) staging_memory, numbers, size);
|
||||
|
||||
wgpu_buffer_unmap(staging_buffer);
|
||||
|
||||
WGPUBufferId storage_buffer = wgpu_device_create_buffer(device,
|
||||
&(WGPUBufferDescriptor){
|
||||
.size = size,
|
||||
.usage = WGPUBufferUsage_STORAGE});
|
||||
|
||||
WGPUBindGroupLayoutId bind_group_layout =
|
||||
wgpu_device_create_bind_group_layout(device,
|
||||
&(WGPUBindGroupLayoutDescriptor){
|
||||
.bindings = &(WGPUBindGroupLayoutBinding){
|
||||
.binding = 0,
|
||||
.visibility = WGPUShaderStage_COMPUTE,
|
||||
.ty = WGPUBindingType_StorageBuffer},
|
||||
.bindings_length = BINDINGS_LENGTH});
|
||||
|
||||
WGPUBindingResource resource = {
|
||||
.tag = WGPUBindingResource_Buffer,
|
||||
.buffer = (WGPUBufferBinding){
|
||||
.buffer = storage_buffer,
|
||||
.size = size,
|
||||
.offset = 0}};
|
||||
|
||||
WGPUBindGroupId bind_group = wgpu_device_create_bind_group(device,
|
||||
&(WGPUBindGroupDescriptor){.layout = bind_group_layout,
|
||||
.bindings = &(WGPUBindGroupBinding){
|
||||
.binding = 0,
|
||||
.resource = resource},
|
||||
.bindings_length = BINDINGS_LENGTH});
|
||||
|
||||
WGPUBindGroupLayoutId bind_group_layouts[BIND_GROUP_LAYOUTS_LENGTH] = {
|
||||
bind_group_layout};
|
||||
|
||||
WGPUPipelineLayoutId pipeline_layout =
|
||||
wgpu_device_create_pipeline_layout(device,
|
||||
&(WGPUPipelineLayoutDescriptor){
|
||||
.bind_group_layouts = bind_group_layouts,
|
||||
.bind_group_layouts_length = BIND_GROUP_LAYOUTS_LENGTH});
|
||||
|
||||
WGPUShaderModuleId shader_module = wgpu_device_create_shader_module(device,
|
||||
&(WGPUShaderModuleDescriptor){
|
||||
.code = read_file("./../../data/collatz.comp.spv")});
|
||||
|
||||
WGPUComputePipelineId compute_pipeline =
|
||||
wgpu_device_create_compute_pipeline(device,
|
||||
&(WGPUComputePipelineDescriptor){
|
||||
.layout = pipeline_layout,
|
||||
.compute_stage = (WGPUPipelineStageDescriptor){
|
||||
.module = shader_module,
|
||||
.entry_point = "main"
|
||||
}});
|
||||
|
||||
WGPUCommandEncoderId encoder = wgpu_device_create_command_encoder(
|
||||
device, &(WGPUCommandEncoderDescriptor){
|
||||
.todo = 0
|
||||
});
|
||||
|
||||
wgpu_command_buffer_copy_buffer_to_buffer(
|
||||
encoder, staging_buffer, 0, storage_buffer, 0, size);
|
||||
|
||||
WGPUComputePassId command_pass =
|
||||
wgpu_command_encoder_begin_compute_pass(encoder);
|
||||
wgpu_compute_pass_set_pipeline(command_pass, compute_pipeline);
|
||||
|
||||
wgpu_compute_pass_set_bind_group(command_pass, 0, bind_group, NULL, 0);
|
||||
wgpu_compute_pass_dispatch(command_pass, numbers_length, 1, 1);
|
||||
wgpu_compute_pass_end_pass(command_pass);
|
||||
|
||||
wgpu_command_buffer_copy_buffer_to_buffer(
|
||||
encoder, storage_buffer, 0, staging_buffer, 0, size);
|
||||
|
||||
WGPUQueueId queue = wgpu_device_get_queue(device);
|
||||
|
||||
WGPUCommandBufferId command_buffer = wgpu_command_encoder_finish(encoder);
|
||||
|
||||
wgpu_queue_submit(queue, &command_buffer, 1);
|
||||
|
||||
wgpu_buffer_map_read_async(staging_buffer, 0, size, read_buffer_map, NULL);
|
||||
|
||||
wgpu_device_poll(device, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
35
examples/framework.c
Normal file
35
examples/framework.c
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef WGPU_H
|
||||
#define WGPU_H
|
||||
#include "wgpu.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
WGPUByteArray read_file(const char *name) {
|
||||
FILE *file = fopen(name, "rb");
|
||||
fseek(file, 0, SEEK_END);
|
||||
long length = ftell(file);
|
||||
unsigned char *bytes = malloc(length);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
fread(bytes, 1, length, file);
|
||||
fclose(file);
|
||||
return (WGPUByteArray){
|
||||
.bytes = bytes,
|
||||
.length = length,
|
||||
};
|
||||
}
|
||||
|
||||
void read_buffer_map(
|
||||
WGPUBufferMapAsyncStatus status,
|
||||
const uint8_t *data,
|
||||
uint8_t *userdata) {
|
||||
if (status == WGPUBufferMapAsyncStatus_Success) {
|
||||
uint32_t *times = (uint32_t *) data;
|
||||
printf("Times: [%d, %d, %d, %d]",
|
||||
times[0],
|
||||
times[1],
|
||||
times[2],
|
||||
times[3]);
|
||||
}
|
||||
}
|
||||
11
examples/framework.h
Normal file
11
examples/framework.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef WGPU_H
|
||||
#define WGPU_H
|
||||
#include "wgpu.h"
|
||||
#endif
|
||||
|
||||
WGPUByteArray read_file(const char *name);
|
||||
|
||||
void read_buffer_map(
|
||||
WGPUBufferMapAsyncStatus status,
|
||||
const uint8_t *data,
|
||||
uint8_t *userdata);
|
||||
@@ -1,10 +1,10 @@
|
||||
cmake_minimum_required(VERSION 3.11b)
|
||||
|
||||
project(hello_remote)
|
||||
project(remote)
|
||||
|
||||
set(TARGET_NAME hello_remote)
|
||||
set(TARGET_NAME remote)
|
||||
|
||||
add_executable(hello_remote main.c)
|
||||
add_executable(remote main.c)
|
||||
|
||||
find_package(glfw3)
|
||||
|
||||
53
examples/triangle/CMakeLists.txt
Normal file
53
examples/triangle/CMakeLists.txt
Normal file
@@ -0,0 +1,53 @@
|
||||
cmake_minimum_required(VERSION 3.11b)
|
||||
|
||||
set(BACKEND_VULKAN "vulkan")
|
||||
set(BACKEND_METAL "metal")
|
||||
set(BACKEND_DX11 "dx11")
|
||||
set(BACKEND_DX12 "dx12")
|
||||
set(AVAILABLE_BACKENDS
|
||||
${BACKEND_VULKAN}
|
||||
${BACKEND_METAL}
|
||||
${BACKEND_DX11}
|
||||
${BACKEND_DX12})
|
||||
|
||||
if(NOT DEFINED BACKEND OR NOT "${BACKEND}" IN_LIST AVAILABLE_BACKENDS)
|
||||
message(FATAL_ERROR "BACKEND invalid or undefined, available backends: ${AVAILABLE_BACKENDS}")
|
||||
endif()
|
||||
|
||||
project(triangle)
|
||||
|
||||
set(TARGET_NAME triangle)
|
||||
|
||||
add_executable(triangle main.c ../framework.c)
|
||||
|
||||
if(MSVC)
|
||||
add_definitions(-DWGPU_TARGET=WGPU_TARGET_WINDOWS)
|
||||
target_compile_options(${TARGET_NAME} PRIVATE /W4)
|
||||
set(OS_LIBRARIES "userenv" "ws2_32" "Dwmapi" "dbghelp")
|
||||
if("${BACKEND}" STREQUAL "${BACKEND_DX11}")
|
||||
list(APPEND OS_LIBRARIES "d3dcompiler" "D3D11" "DXGI")
|
||||
elseif("${BACKEND}" STREQUAL "${BACKEND_DX12}")
|
||||
list(APPEND OS_LIBRARIES "d3dcompiler" "D3D12" "DXGI")
|
||||
endif()
|
||||
elseif(APPLE)
|
||||
add_definitions(-DWGPU_TARGET=WGPU_TARGET_MACOS)
|
||||
set(OS_LIBRARIES "-framework Cocoa" "-framework CoreVideo" "-framework IOKit" "-framework QuartzCore")
|
||||
target_compile_options(${TARGET_NAME} PRIVATE -x objective-c)
|
||||
else(MSVC)
|
||||
add_definitions(-DWGPU_TARGET=WGPU_TARGET_LINUX)
|
||||
target_compile_options(${TARGET_NAME} PRIVATE -Wall -Wextra -pedantic)
|
||||
endif(MSVC)
|
||||
|
||||
find_package(glfw3 3.3 REQUIRED
|
||||
HINTS "$ENV{GLFW3_INSTALL_DIR}"
|
||||
)
|
||||
|
||||
find_library(WGPU_LIBRARY wgpu_native
|
||||
HINTS "${CMAKE_CURRENT_SOURCE_DIR}/../../target/debug"
|
||||
)
|
||||
|
||||
target_include_directories(${TARGET_NAME} PUBLIC $ENV{GLFW3_INCLUDE_DIR})
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../ffi)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../)
|
||||
|
||||
target_link_libraries(${TARGET_NAME} glfw ${WGPU_LIBRARY} ${OS_LIBRARIES})
|
||||
@@ -1,4 +1,9 @@
|
||||
#include "./../../ffi/wgpu.h"
|
||||
#ifndef WGPU_H
|
||||
#define WGPU_H
|
||||
#include "wgpu.h"
|
||||
#endif
|
||||
|
||||
#include "framework.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -27,20 +32,6 @@
|
||||
#define RENDER_PASS_ATTACHMENTS_LENGTH (1)
|
||||
#define BIND_GROUP_LAYOUTS_LENGTH (1)
|
||||
|
||||
WGPUByteArray read_file(const char *name) {
|
||||
FILE *file = fopen(name, "rb");
|
||||
fseek(file, 0, SEEK_END);
|
||||
long length = ftell(file);
|
||||
unsigned char *bytes = malloc(length);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
fread(bytes, 1, length, file);
|
||||
fclose(file);
|
||||
return (WGPUByteArray){
|
||||
.bytes = bytes,
|
||||
.length = length,
|
||||
};
|
||||
}
|
||||
|
||||
int main() {
|
||||
WGPUInstanceId instance = wgpu_create_instance();
|
||||
|
||||
@@ -59,13 +50,13 @@ int main() {
|
||||
|
||||
WGPUShaderModuleId vertex_shader = wgpu_device_create_shader_module(device,
|
||||
&(WGPUShaderModuleDescriptor){
|
||||
.code = read_file("./../../data/hello_triangle.vert.spv"),
|
||||
.code = read_file("./../../data/triangle.vert.spv"),
|
||||
});
|
||||
|
||||
WGPUShaderModuleId fragment_shader =
|
||||
wgpu_device_create_shader_module(device,
|
||||
&(WGPUShaderModuleDescriptor){
|
||||
.code = read_file("./../../data/hello_triangle.frag.spv"),
|
||||
.code = read_file("./../../data/triangle.frag.spv"),
|
||||
});
|
||||
|
||||
WGPUBindGroupLayoutId bind_group_layout =
|
||||
Reference in New Issue
Block a user