Ok but what if: WGPU renderer?
This commit is contained in:
parent
a5380c4417
commit
1cca66b66f
0
.gitmodules
vendored
Normal file
0
.gitmodules
vendored
Normal file
|
@ -5,7 +5,7 @@ namespace hibis {
|
||||||
// - Image
|
// - Image
|
||||||
/// RGBA value struct. Value is between 0 and 255
|
/// RGBA value struct. Value is between 0 and 255
|
||||||
struct Color {
|
struct Color {
|
||||||
unsigned char r, g, b, a;
|
double r, g, b, a;
|
||||||
};
|
};
|
||||||
|
|
||||||
// - 2D
|
// - 2D
|
||||||
|
|
159
external/glfw3webgpu/glfw3webgpu.c
vendored
Normal file
159
external/glfw3webgpu/glfw3webgpu.c
vendored
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
/**
|
||||||
|
* This is an extension of GLFW for WebGPU, abstracting away the details of
|
||||||
|
* OS-specific operations.
|
||||||
|
*
|
||||||
|
* This file is part of the "Learn WebGPU for C++" book.
|
||||||
|
* https://eliemichel.github.io/LearnWebGPU
|
||||||
|
*
|
||||||
|
* Most of this code comes from the wgpu-native triangle example:
|
||||||
|
* https://github.com/gfx-rs/wgpu-native/blob/master/examples/triangle/main.c
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
* Copyright (c) 2022-2023 Elie Michel and the wgpu-native authors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "glfw3webgpu.h"
|
||||||
|
|
||||||
|
#include <webgpu/webgpu.h>
|
||||||
|
|
||||||
|
#define WGPU_TARGET_MACOS 1
|
||||||
|
#define WGPU_TARGET_LINUX_X11 2
|
||||||
|
#define WGPU_TARGET_WINDOWS 3
|
||||||
|
#define WGPU_TARGET_LINUX_WAYLAND 4
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#define WGPU_TARGET WGPU_TARGET_WINDOWS
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
#define WGPU_TARGET WGPU_TARGET_MACOS
|
||||||
|
#else
|
||||||
|
#define WGPU_TARGET WGPU_TARGET_LINUX_X11
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if WGPU_TARGET == WGPU_TARGET_MACOS
|
||||||
|
#include <Foundation/Foundation.h>
|
||||||
|
#include <QuartzCore/CAMetalLayer.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
#if WGPU_TARGET == WGPU_TARGET_MACOS
|
||||||
|
#define GLFW_EXPOSE_NATIVE_COCOA
|
||||||
|
#elif WGPU_TARGET == WGPU_TARGET_LINUX_X11
|
||||||
|
#define GLFW_EXPOSE_NATIVE_X11
|
||||||
|
#elif WGPU_TARGET == WGPU_TARGET_LINUX_WAYLAND
|
||||||
|
#define GLFW_EXPOSE_NATIVE_WAYLAND
|
||||||
|
#elif WGPU_TARGET == WGPU_TARGET_WINDOWS
|
||||||
|
#define GLFW_EXPOSE_NATIVE_WIN32
|
||||||
|
#endif
|
||||||
|
#include <GLFW/glfw3native.h>
|
||||||
|
|
||||||
|
WGPUSurface glfwGetWGPUSurface(WGPUInstance instance, GLFWwindow* window) {
|
||||||
|
#if WGPU_TARGET == WGPU_TARGET_MACOS
|
||||||
|
{
|
||||||
|
id metal_layer = NULL;
|
||||||
|
NSWindow* ns_window = glfwGetCocoaWindow(window);
|
||||||
|
[ns_window.contentView setWantsLayer : YES] ;
|
||||||
|
metal_layer = [CAMetalLayer layer];
|
||||||
|
[ns_window.contentView setLayer : metal_layer] ;
|
||||||
|
return wgpuInstanceCreateSurface(
|
||||||
|
instance,
|
||||||
|
&(WGPUSurfaceDescriptor){
|
||||||
|
.label = NULL,
|
||||||
|
.nextInChain =
|
||||||
|
(const WGPUChainedStruct*)&(
|
||||||
|
WGPUSurfaceDescriptorFromMetalLayer) {
|
||||||
|
.chain =
|
||||||
|
(WGPUChainedStruct){
|
||||||
|
.next = NULL,
|
||||||
|
.sType = WGPUSType_SurfaceDescriptorFromMetalLayer,
|
||||||
|
},
|
||||||
|
.layer = metal_layer,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#elif WGPU_TARGET == WGPU_TARGET_LINUX_X11
|
||||||
|
{
|
||||||
|
Display* x11_display = glfwGetX11Display();
|
||||||
|
Window x11_window = glfwGetX11Window(window);
|
||||||
|
return wgpuInstanceCreateSurface(
|
||||||
|
instance,
|
||||||
|
&(WGPUSurfaceDescriptor){
|
||||||
|
.label = NULL,
|
||||||
|
.nextInChain =
|
||||||
|
(const WGPUChainedStruct*)&(
|
||||||
|
WGPUSurfaceDescriptorFromXlibWindow) {
|
||||||
|
.chain =
|
||||||
|
(WGPUChainedStruct){
|
||||||
|
.next = NULL,
|
||||||
|
.sType = WGPUSType_SurfaceDescriptorFromXlibWindow,
|
||||||
|
},
|
||||||
|
.display = x11_display,
|
||||||
|
.window = x11_window,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#elif WGPU_TARGET == WGPU_TARGET_LINUX_WAYLAND
|
||||||
|
{
|
||||||
|
struct wl_display* wayland_display = glfwGetWaylandDisplay();
|
||||||
|
struct wl_surface* wayland_surface = glfwGetWaylandWindow(window);
|
||||||
|
return wgpuInstanceCreateSurface(
|
||||||
|
instance,
|
||||||
|
&(WGPUSurfaceDescriptor){
|
||||||
|
.label = NULL,
|
||||||
|
.nextInChain =
|
||||||
|
(const WGPUChainedStruct*)&(
|
||||||
|
WGPUSurfaceDescriptorFromWaylandSurface) {
|
||||||
|
.chain =
|
||||||
|
(WGPUChainedStruct){
|
||||||
|
.next = NULL,
|
||||||
|
.sType =
|
||||||
|
WGPUSType_SurfaceDescriptorFromWaylandSurface,
|
||||||
|
},
|
||||||
|
.display = wayland_display,
|
||||||
|
.surface = wayland_surface,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#elif WGPU_TARGET == WGPU_TARGET_WINDOWS
|
||||||
|
{
|
||||||
|
HWND hwnd = glfwGetWin32Window(window);
|
||||||
|
HINSTANCE hinstance = GetModuleHandle(NULL);
|
||||||
|
return wgpuInstanceCreateSurface(
|
||||||
|
instance,
|
||||||
|
&(WGPUSurfaceDescriptor){
|
||||||
|
.label = NULL,
|
||||||
|
.nextInChain =
|
||||||
|
(const WGPUChainedStruct*)&(
|
||||||
|
WGPUSurfaceDescriptorFromWindowsHWND) {
|
||||||
|
.chain =
|
||||||
|
(WGPUChainedStruct){
|
||||||
|
.next = NULL,
|
||||||
|
.sType = WGPUSType_SurfaceDescriptorFromWindowsHWND,
|
||||||
|
},
|
||||||
|
.hinstance = hinstance,
|
||||||
|
.hwnd = hwnd,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#error "Unsupported WGPU_TARGET"
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
49
external/glfw3webgpu/glfw3webgpu.h
vendored
Normal file
49
external/glfw3webgpu/glfw3webgpu.h
vendored
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/**
|
||||||
|
* This is an extension of GLFW for WebGPU, abstracting away the details of
|
||||||
|
* OS-specific operations.
|
||||||
|
*
|
||||||
|
* This file is part of the "Learn WebGPU for C++" book.
|
||||||
|
* https://eliemichel.github.io/LearnWebGPU
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
* Copyright (c) 2022-2023 Elie Michel and the wgpu-native authors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _glfw3_webgpu_h_
|
||||||
|
#define _glfw3_webgpu_h_
|
||||||
|
|
||||||
|
#include <webgpu/webgpu.h>
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a WGPUSurface from a GLFW window.
|
||||||
|
*/
|
||||||
|
WGPUSurface glfwGetWGPUSurface(WGPUInstance instance, GLFWwindow* window);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // _glfw3_webgpu_h_
|
14
meson.build
14
meson.build
|
@ -1,6 +1,10 @@
|
||||||
project('hibis', 'cpp', version: '0.0.0' + (not get_option('buildtype').startswith('release') ? '-' + run_command('git', 'rev-parse', '--short', 'HEAD', check: true).stdout().strip() : ''),
|
project('hibis', 'cpp', 'c', version: '0.0.0' + (not get_option('buildtype').startswith('release') ? '-' + run_command('git', 'rev-parse', '--short', 'HEAD', check: true).stdout().strip() : ''),
|
||||||
license: 'LGPL-3.0-only', meson_version: '>=0.60.3', default_options: ['cpp_std=c++17'])
|
license: 'LGPL-3.0-only', meson_version: '>=0.60.3', default_options: ['cpp_std=c++17'])
|
||||||
|
|
||||||
|
# Imports
|
||||||
|
|
||||||
|
cmake = import('cmake')
|
||||||
|
|
||||||
# Configure data
|
# Configure data
|
||||||
confdata = configuration_data()
|
confdata = configuration_data()
|
||||||
confdata.set('version', meson.project_version())
|
confdata.set('version', meson.project_version())
|
||||||
|
@ -16,6 +20,7 @@ libhibis_src_renderer = files('core/renderer/renderer.cpp')
|
||||||
libhibis_src_resources = files('core/resources/texture.cpp', 'core/resources/font.cpp', 'core/resources/shader.cpp')
|
libhibis_src_resources = files('core/resources/texture.cpp', 'core/resources/font.cpp', 'core/resources/shader.cpp')
|
||||||
libhibis_src = [libhibis_src_core, libhibis_src_renderer, libhibis_src_resources]
|
libhibis_src = [libhibis_src_core, libhibis_src_renderer, libhibis_src_resources]
|
||||||
|
|
||||||
|
libhibis_rwgpu_src = files('renderer/rwgpu/rwgpu.cpp')
|
||||||
libhibis_rglcore_src = files('renderer/rglcore/rglcore.cpp')
|
libhibis_rglcore_src = files('renderer/rglcore/rglcore.cpp')
|
||||||
libhibis_test_src = files('test/app.cpp')
|
libhibis_test_src = files('test/app.cpp')
|
||||||
|
|
||||||
|
@ -24,9 +29,14 @@ libgl = dependency('gl')
|
||||||
libglfw = dependency('glfw3')
|
libglfw = dependency('glfw3')
|
||||||
libglew = dependency('GLEW')
|
libglew = dependency('GLEW')
|
||||||
libfmt = dependency('fmt')
|
libfmt = dependency('fmt')
|
||||||
|
libwgpu = meson.get_compiler('cpp').find_library('wgpu_native')
|
||||||
|
|
||||||
|
libwgpu_glfw = static_library('glfw3webgpu', 'external/glfw3webgpu/glfw3webgpu.c', dependencies: [libglfw])
|
||||||
|
|
||||||
libfreetype2 = dependency('freetype2')
|
libfreetype2 = dependency('freetype2')
|
||||||
|
|
||||||
# Compile
|
# Compile
|
||||||
libhibis = library('hibis', libhibis_src, include_directories: include_dirs, dependencies: [libfreetype2])
|
libhibis = library('hibis', libhibis_src, include_directories: include_dirs, dependencies: [libfreetype2])
|
||||||
libhibis_rglcore = library('hibis_rglcore', libhibis_rglcore_src, include_directories: [include_dirs, './core'], link_with: libhibis, dependencies: [libfreetype2, libgl, libglfw, libglew, libfmt])
|
libhibis_rglcore = library('hibis_rglcore', libhibis_rglcore_src, include_directories: [include_dirs, './core'], link_with: libhibis, dependencies: [libfreetype2, libgl, libglfw, libglew, libfmt])
|
||||||
hibistest = executable('hibistest.exec', libhibis_test_src, include_directories: [include_dirs, './core', './renderer/rglcore'], link_with: [libhibis, libhibis_rglcore], dependencies: [libfreetype2, libgl, libglfw, libglew, libfmt])
|
libhibis_rwgpu = library('hibis_rwgpu', libhibis_rwgpu_src, include_directories: [include_dirs, './core'], link_with: [libhibis, libwgpu_glfw], dependencies: [libfreetype2, libglfw, libfmt, libwgpu])
|
||||||
|
hibistest = executable('hibistest.exec', libhibis_test_src, include_directories: [include_dirs, './core', './renderer/rwgpu'], link_with: [libhibis, libhibis_rwgpu], dependencies: [libfreetype2, libglfw, libfmt, libwgpu])
|
||||||
|
|
|
@ -78,8 +78,6 @@ namespace hibis::rglcore {
|
||||||
glUseProgram(shader->mShaderProgram);
|
glUseProgram(shader->mShaderProgram);
|
||||||
glBindVertexArray(shader->mShaderVAO);
|
glBindVertexArray(shader->mShaderVAO);
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||||
|
|
||||||
glBindVertexArray(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RGLCore::stopUsingShaders() {
|
void RGLCore::stopUsingShaders() {
|
||||||
|
|
232
renderer/rwgpu/rwgpu.cpp
Normal file
232
renderer/rwgpu/rwgpu.cpp
Normal file
|
@ -0,0 +1,232 @@
|
||||||
|
#define WEBGPU_CPP_IMPLEMENTATION
|
||||||
|
#include <fmt/format.h>
|
||||||
|
#include <sstream>
|
||||||
|
#include <webgpu/webgpu.hpp>
|
||||||
|
|
||||||
|
#include <glfw3webgpu/glfw3webgpu.h>
|
||||||
|
|
||||||
|
#include "rwgpu.hpp"
|
||||||
|
|
||||||
|
namespace hibis::rwgpu {
|
||||||
|
RWGPU::RWGPU(std::string title, IntVec2 size, LoggerCallback callback) : Renderer(callback) {
|
||||||
|
wgpu::InstanceDescriptor instanceDescriptor = {};
|
||||||
|
wgpu::RequestAdapterOptions reqAdaptOpts = {};
|
||||||
|
wgpu::DeviceDescriptor deviceDescriptor = {};
|
||||||
|
|
||||||
|
deviceDescriptor.nextInChain = nullptr;
|
||||||
|
deviceDescriptor.label = "My Device"; // anything works here, that's your call
|
||||||
|
deviceDescriptor.requiredFeaturesCount = 0; // we do not require any specific feature
|
||||||
|
deviceDescriptor.requiredLimits = nullptr; // we do not require any specific limit
|
||||||
|
deviceDescriptor.defaultQueue.nextInChain = nullptr;
|
||||||
|
deviceDescriptor.defaultQueue.label = "The default queue";
|
||||||
|
|
||||||
|
mWebGPUInstance = wgpu::createInstance(instanceDescriptor);
|
||||||
|
mWebGPUAdapter = requestAdapter(&reqAdaptOpts);
|
||||||
|
mWebGPUDevice = requestDevice(&deviceDescriptor);
|
||||||
|
mWebGPUQueue = mWebGPUDevice.getQueue();
|
||||||
|
|
||||||
|
if (!mWebGPUInstance) {
|
||||||
|
mLogger(Fatal, "Could not initialize WebGPU!");
|
||||||
|
exit(1);
|
||||||
|
} else {
|
||||||
|
const void * address = static_cast<const void*>(mWebGPUInstance);
|
||||||
|
std::stringstream pointerAsStream;
|
||||||
|
pointerAsStream << address;
|
||||||
|
mLogger(Information, fmt::format("WGPU Instance Addr: {}", pointerAsStream.str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
glfwInit();
|
||||||
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
|
|
||||||
|
mWindow = glfwCreateWindow(size.x, size.y, title.c_str(), NULL, NULL);
|
||||||
|
|
||||||
|
mWebGPUSurface = glfwGetWGPUSurface(mWebGPUInstance, mWindow);
|
||||||
|
|
||||||
|
size_t featureCount = wgpuAdapterEnumerateFeatures(mWebGPUAdapter, nullptr);
|
||||||
|
|
||||||
|
// Allocate memory (could be a new, or a malloc() if this were a C program)
|
||||||
|
mWebGPUFeatures.resize(featureCount);
|
||||||
|
|
||||||
|
// Call the function a second time, with a non-null return address
|
||||||
|
wgpuAdapterEnumerateFeatures(mWebGPUAdapter, mWebGPUFeatures.data());
|
||||||
|
|
||||||
|
mLogger(Information, "Adapter features: ");
|
||||||
|
for (wgpu::FeatureName f : mWebGPUFeatures) {
|
||||||
|
mLogger(Information, fmt::format("WebGPU Feature: {}", f));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto onDeviceError = [](WGPUErrorType type, char const* message, void* /* pUserData */) {
|
||||||
|
std::cout << "Uncaptured device error: type " << type;
|
||||||
|
if (message) std::cout << " (" << message << ")";
|
||||||
|
std::cout << std::endl;
|
||||||
|
};
|
||||||
|
|
||||||
|
wgpuDeviceSetUncapturedErrorCallback(mWebGPUDevice, onDeviceError, nullptr /* pUserData */);
|
||||||
|
|
||||||
|
// Not implemented, causes a panic
|
||||||
|
// auto onQueueWorkDone = [](WGPUQueueWorkDoneStatus status, void* /* pUserData */) {
|
||||||
|
// std::cout << "Queued work finished with status: " << status << std::endl;
|
||||||
|
// };
|
||||||
|
// wgpuQueueOnSubmittedWorkDone(mWebGPUQueue, onQueueWorkDone, nullptr /* pUserData */);
|
||||||
|
|
||||||
|
WGPUSwapChainDescriptor swapChainDesc = {};
|
||||||
|
swapChainDesc.nextInChain = nullptr;
|
||||||
|
swapChainDesc.width = size.x;
|
||||||
|
swapChainDesc.height = size.y;
|
||||||
|
|
||||||
|
WGPUTextureFormat swapChainFormat = wgpuSurfaceGetPreferredFormat(mWebGPUSurface, mWebGPUAdapter);
|
||||||
|
swapChainDesc.format = swapChainFormat;
|
||||||
|
|
||||||
|
swapChainDesc.usage = WGPUTextureUsage_RenderAttachment;
|
||||||
|
swapChainDesc.presentMode = WGPUPresentMode_Fifo;
|
||||||
|
|
||||||
|
mWebGPUSwapChain = wgpuDeviceCreateSwapChain(mWebGPUDevice, mWebGPUSurface, &swapChainDesc);
|
||||||
|
}
|
||||||
|
|
||||||
|
RWGPU::~RWGPU() {
|
||||||
|
glfwDestroyWindow(mWindow);
|
||||||
|
|
||||||
|
mWebGPUSwapChain.drop();
|
||||||
|
mWebGPUSurface.drop();
|
||||||
|
mWebGPUDevice.drop();
|
||||||
|
mWebGPUAdapter.drop();
|
||||||
|
mWebGPUInstance.drop();
|
||||||
|
}
|
||||||
|
|
||||||
|
WGPUAdapter RWGPU::requestAdapter(WGPURequestAdapterOptions const * options) {
|
||||||
|
// A simple structure holding the local information shared with the
|
||||||
|
// onAdapterRequestEnded callback.
|
||||||
|
struct UserData {
|
||||||
|
WGPUAdapter adapter = nullptr;
|
||||||
|
bool requestEnded = false;
|
||||||
|
};
|
||||||
|
UserData userData;
|
||||||
|
|
||||||
|
// Callback called by wgpuInstanceRequestAdapter when the request returns
|
||||||
|
// This is a C++ lambda function, but could be any function defined in the
|
||||||
|
// global scope. It must be non-capturing (the brackets [] are empty) so
|
||||||
|
// that it behaves like a regular C function pointer, which is what
|
||||||
|
// wgpuInstanceRequestAdapter expects (WebGPU being a C API). The workaround
|
||||||
|
// is to convey what we want to capture through the pUserData pointer,
|
||||||
|
// provided as the last argument of wgpuInstanceRequestAdapter and received
|
||||||
|
// by the callback as its last argument.
|
||||||
|
auto onAdapterRequestEnded = [](WGPURequestAdapterStatus status, WGPUAdapter adapter, char const * message, void * pUserData) {
|
||||||
|
UserData& userData = *reinterpret_cast<UserData*>(pUserData);
|
||||||
|
if (status == WGPURequestAdapterStatus_Success) {
|
||||||
|
userData.adapter = adapter;
|
||||||
|
} else {
|
||||||
|
std::cout << "Could not get WebGPU adapter: " << message << std::endl;
|
||||||
|
}
|
||||||
|
userData.requestEnded = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Call to the WebGPU request adapter procedure
|
||||||
|
wgpuInstanceRequestAdapter(
|
||||||
|
mWebGPUInstance /* equivalent of navigator.gpu */,
|
||||||
|
options,
|
||||||
|
onAdapterRequestEnded,
|
||||||
|
(void*)&userData
|
||||||
|
);
|
||||||
|
|
||||||
|
// In theory we should wait until onAdapterReady has been called, which
|
||||||
|
// could take some time (what the 'await' keyword does in the JavaScript
|
||||||
|
// code). In practice, we know that when the wgpuInstanceRequestAdapter()
|
||||||
|
// function returns its callback has been called.
|
||||||
|
assert(userData.requestEnded);
|
||||||
|
|
||||||
|
return userData.adapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
WGPUDevice RWGPU::requestDevice(WGPUDeviceDescriptor const * descriptor) {
|
||||||
|
struct UserData {
|
||||||
|
WGPUDevice device = nullptr;
|
||||||
|
bool requestEnded = false;
|
||||||
|
};
|
||||||
|
UserData userData;
|
||||||
|
|
||||||
|
auto onDeviceRequestEnded = [](WGPURequestDeviceStatus status, WGPUDevice device, char const * message, void * pUserData) {
|
||||||
|
UserData& userData = *reinterpret_cast<UserData*>(pUserData);
|
||||||
|
if (status == WGPURequestDeviceStatus_Success) {
|
||||||
|
userData.device = device;
|
||||||
|
} else {
|
||||||
|
std::cout << "Could not get WebGPU device: " << message << std::endl;
|
||||||
|
}
|
||||||
|
userData.requestEnded = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
wgpuAdapterRequestDevice(
|
||||||
|
mWebGPUAdapter,
|
||||||
|
descriptor,
|
||||||
|
onDeviceRequestEnded,
|
||||||
|
(void*)&userData
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(userData.requestEnded);
|
||||||
|
|
||||||
|
return userData.device;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RWGPU::clearScreen(Color col) {
|
||||||
|
mCurrentClearColor = {col.r, col.g, col.b, col.a};
|
||||||
|
}
|
||||||
|
|
||||||
|
void RWGPU::renderCurrent() {
|
||||||
|
wgpu::TextureView nextTexture = mWebGPUSwapChain.getCurrentTextureView();
|
||||||
|
if (!nextTexture) {
|
||||||
|
mLogger(Error, "Couldn't create next texture");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WGPUCommandEncoderDescriptor encoderDesc = {};
|
||||||
|
encoderDesc.nextInChain = nullptr;
|
||||||
|
encoderDesc.label = "HibisDrawCommandEncoder";
|
||||||
|
WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(mWebGPUDevice, &encoderDesc);
|
||||||
|
|
||||||
|
WGPURenderPassDescriptor renderPassDesc = {};
|
||||||
|
|
||||||
|
WGPURenderPassColorAttachment renderPassColorAttachment = {};
|
||||||
|
|
||||||
|
renderPassDesc.colorAttachmentCount = 1;
|
||||||
|
renderPassDesc.colorAttachments = &renderPassColorAttachment;
|
||||||
|
|
||||||
|
renderPassColorAttachment.view = nextTexture;
|
||||||
|
renderPassColorAttachment.resolveTarget = nullptr;
|
||||||
|
renderPassColorAttachment.loadOp = WGPULoadOp_Clear;
|
||||||
|
renderPassColorAttachment.storeOp = WGPUStoreOp_Store;
|
||||||
|
renderPassColorAttachment.clearValue = mCurrentClearColor;
|
||||||
|
renderPassDesc.depthStencilAttachment = nullptr;
|
||||||
|
|
||||||
|
renderPassDesc.timestampWriteCount = 0;
|
||||||
|
renderPassDesc.timestampWrites = nullptr;
|
||||||
|
renderPassDesc.nextInChain = nullptr;
|
||||||
|
|
||||||
|
WGPURenderPassEncoder renderPass = wgpuCommandEncoderBeginRenderPass(encoder, &renderPassDesc);
|
||||||
|
wgpuRenderPassEncoderEnd(renderPass);
|
||||||
|
|
||||||
|
WGPUCommandBufferDescriptor cmdBufferDescriptor = {};
|
||||||
|
cmdBufferDescriptor.nextInChain = nullptr;
|
||||||
|
cmdBufferDescriptor.label = "Command buffer";
|
||||||
|
WGPUCommandBuffer command = wgpuCommandEncoderFinish(encoder, &cmdBufferDescriptor);
|
||||||
|
wgpuQueueSubmit(mWebGPUQueue, 1, &command);
|
||||||
|
|
||||||
|
mWebGPUSwapChain.present();
|
||||||
|
nextTexture.drop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RWGPU::drawText(Resource* resource, std::string text, IntVec2 pos, Color color) {}
|
||||||
|
void RWGPU::drawTexture(Texture* resource, IntRect size) {}
|
||||||
|
|
||||||
|
void RWGPU::useShader(Shader* shader, Point2D points[3]) {}
|
||||||
|
void RWGPU::stopUsingShaders() {}
|
||||||
|
|
||||||
|
void RWGPU::preDraw() {}
|
||||||
|
void RWGPU::postDraw() {}
|
||||||
|
|
||||||
|
void RWGPU::update() {
|
||||||
|
mKeepOpen = !glfwWindowShouldClose(mWindow);
|
||||||
|
glfwPollEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RWGPU::compileShader(Shader* shader) {}
|
||||||
|
void RWGPU::toggleWireframe() {}
|
||||||
|
void RWGPU::setWindowTitle(std::string title) {}
|
||||||
|
}
|
55
renderer/rwgpu/rwgpu.hpp
Normal file
55
renderer/rwgpu/rwgpu.hpp
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <webgpu/webgpu.hpp>
|
||||||
|
|
||||||
|
#define GLFW_INCLUDE_NONE
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
#include <renderer/renderer.hpp>
|
||||||
|
|
||||||
|
namespace hibis::rwgpu {
|
||||||
|
class RWGPU : public Renderer {
|
||||||
|
public:
|
||||||
|
RWGPU(std::string title, IntVec2 size, LoggerCallback callback);
|
||||||
|
~RWGPU();
|
||||||
|
|
||||||
|
// Draw
|
||||||
|
void clearScreen(Color col = Color {0, 0, 0, 255}) override;
|
||||||
|
void renderCurrent() override;
|
||||||
|
|
||||||
|
void drawText(Resource* resource, std::string text, IntVec2 pos, Color color) override;
|
||||||
|
void drawTexture(Texture* resource, IntRect size) override;
|
||||||
|
|
||||||
|
void useShader(Shader* shader, Point2D points[3]) override;
|
||||||
|
void stopUsingShaders() override;
|
||||||
|
|
||||||
|
// Pre and Post draw
|
||||||
|
void preDraw() override;
|
||||||
|
void postDraw() override;
|
||||||
|
|
||||||
|
// Update
|
||||||
|
void update() override;
|
||||||
|
|
||||||
|
// Util
|
||||||
|
void compileShader(Shader* shader) override;
|
||||||
|
void toggleWireframe() override;
|
||||||
|
void setWindowTitle(std::string title) override;
|
||||||
|
|
||||||
|
std::vector<WGPUFeatureName> mWebGPUFeatures;
|
||||||
|
private:
|
||||||
|
WGPUAdapter requestAdapter(WGPURequestAdapterOptions const * options);
|
||||||
|
WGPUDevice requestDevice(WGPUDeviceDescriptor const * descriptor);
|
||||||
|
|
||||||
|
GLFWwindow* mWindow;
|
||||||
|
wgpu::Instance mWebGPUInstance = nullptr;
|
||||||
|
wgpu::Adapter mWebGPUAdapter = nullptr;
|
||||||
|
wgpu::Device mWebGPUDevice = nullptr;
|
||||||
|
wgpu::Queue mWebGPUQueue = nullptr;
|
||||||
|
wgpu::SwapChain mWebGPUSwapChain = nullptr;
|
||||||
|
|
||||||
|
wgpu::Surface mWebGPUSurface = nullptr;
|
||||||
|
|
||||||
|
wgpu::Color mCurrentClearColor = {0.9, 0.1, 0.2, 1.0};
|
||||||
|
};
|
||||||
|
}
|
14
test/app.cpp
14
test/app.cpp
|
@ -1,8 +1,7 @@
|
||||||
#include <logging/types.hpp>
|
#include <logging/types.hpp>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <renderer/renderer.hpp>
|
#include <renderer/renderer.hpp>
|
||||||
#include <rglcore.hpp>
|
#include <rwgpu.hpp>
|
||||||
#include <resources/font.hpp>
|
|
||||||
#include <resources/font.hpp>
|
#include <resources/font.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -18,7 +17,7 @@ WARNING("Please avoid using MSVC in C++ projects utilising std::chrono and std::
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace hibis;
|
using namespace hibis;
|
||||||
using namespace hibis::rglcore;
|
using namespace hibis::rwgpu;
|
||||||
|
|
||||||
void logger(LoggingSeverity severity, std::string message) {
|
void logger(LoggingSeverity severity, std::string message) {
|
||||||
std::string sevString;
|
std::string sevString;
|
||||||
|
@ -45,8 +44,9 @@ void logger(LoggingSeverity severity, std::string message) {
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
logger(Information, fmt::format("PWD: {}", std::getenv("PWD")));
|
logger(Information, fmt::format("PWD: {}", std::getenv("PWD")));
|
||||||
RGLCore renderer = RGLCore("test", IntVec2 {800, 600}, &logger);
|
RWGPU renderer = RWGPU("test", IntVec2 {800, 600}, &logger);
|
||||||
Engine engine = Engine(&renderer, &logger);
|
Engine engine = Engine(&renderer, &logger);
|
||||||
|
/*
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
Font font = Font(engine.mFreeTypeLibrary, "C:\\Windows\\Fonts\\Arial.ttf", 16);
|
Font font = Font(engine.mFreeTypeLibrary, "C:\\Windows\\Fonts\\Arial.ttf", 16);
|
||||||
|
@ -67,9 +67,10 @@ int main() {
|
||||||
uint f = 0;
|
uint f = 0;
|
||||||
|
|
||||||
Point2D points[3] = {{-0.5f, -0.5f}, {0.5f, -0.5f}, {0.0f, 0.5f}};
|
Point2D points[3] = {{-0.5f, -0.5f}, {0.5f, -0.5f}, {0.0f, 0.5f}};
|
||||||
|
*/
|
||||||
logger(Information, "Started Hibis test app! BEHOLD: Colours.");
|
logger(Information, "Started Hibis test app! BEHOLD: Colours.");
|
||||||
while (renderer.mKeepOpen) {
|
while (renderer.mKeepOpen) {
|
||||||
|
/*
|
||||||
// Colour changing background!
|
// Colour changing background!
|
||||||
if ((red == 255 && increaseRed) || (red == 0 && !increaseRed)) {
|
if ((red == 255 && increaseRed) || (red == 0 && !increaseRed)) {
|
||||||
increaseRed = !increaseRed;
|
increaseRed = !increaseRed;
|
||||||
|
@ -87,9 +88,10 @@ int main() {
|
||||||
else size -= 2;
|
else size -= 2;
|
||||||
font.setFontSize(size);
|
font.setFontSize(size);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// Clear screen then sleep for ~16ms
|
// Clear screen then sleep for ~16ms
|
||||||
renderer.clearScreen(Color {red, 0, 0, 255});
|
//renderer.clearScreen(Color {red, 0, 0, 255});
|
||||||
//renderer.useShader(&shader, points);
|
//renderer.useShader(&shader, points);
|
||||||
//renderer.drawText(&font, "Testing Text", IntVec2 {0, 0}, Color {255, 255, 255, 255});
|
//renderer.drawText(&font, "Testing Text", IntVec2 {0, 0}, Color {255, 255, 255, 255});
|
||||||
//renderer.drawTexture(&image, 1.0f, IntVec2 {10, 10});
|
//renderer.drawTexture(&image, 1.0f, IntVec2 {10, 10});
|
||||||
|
|
|
@ -2,5 +2,5 @@
|
||||||
layout (location = 0) in vec3 aPos;
|
layout (location = 0) in vec3 aPos;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
|
gl_Position = vec4(aPos, 1.0);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue