mirror of https://github.com/AxioDL/metaforce.git
aurora: Working movie player (again)
This commit is contained in:
parent
c64f9eb2d1
commit
b6b68135ef
|
@ -1,7 +1,9 @@
|
|||
#include "Runtime/CGameAllocator.hpp"
|
||||
|
||||
#include <logvisor/logvisor.hpp>
|
||||
|
||||
namespace metaforce {
|
||||
logvisor::Module AllocLog("metaforce::CGameAllocator");
|
||||
static logvisor::Module Log("metaforce::CGameAllocator");
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wclass-memaccess"
|
||||
|
||||
|
@ -44,7 +46,7 @@ u8* CGameAllocator::Alloc(size_t len) {
|
|||
void CGameAllocator::Free(u8* ptr) {
|
||||
SChunkDescription* info = reinterpret_cast<SChunkDescription*>(ptr - sizeof(SChunkDescription));
|
||||
if (info->magic != 0xE8E8E8E8 || info->sentinal != 0xEFEFEFEF) {
|
||||
AllocLog.report(logvisor::Fatal, FMT_STRING("Invalid chunk description, memory corruption!"));
|
||||
Log.report(logvisor::Fatal, FMT_STRING("Invalid chunk description, memory corruption!"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
|
|
@ -1166,18 +1166,18 @@ void ImGuiConsole::PreUpdate() {
|
|||
g_StateManager->SetActiveRandomToDefault();
|
||||
}
|
||||
|
||||
if (ImGui::IsKeyReleased(int(KeyCode::Grave))) {
|
||||
if (ImGui::IsKeyReleased(ImGuiKey_GraveAccent)) {
|
||||
m_isVisible ^= 1;
|
||||
}
|
||||
if (m_stepFrame) {
|
||||
g_Main->SetPaused(true);
|
||||
m_stepFrame = false;
|
||||
}
|
||||
if (m_paused && !m_stepFrame && ImGui::IsKeyPressed(int(KeyCode::F6))) {
|
||||
if (m_paused && !m_stepFrame && ImGui::IsKeyPressed(ImGuiKey_F6)) {
|
||||
g_Main->SetPaused(false);
|
||||
m_stepFrame = true;
|
||||
}
|
||||
if (ImGui::IsKeyReleased(int(KeyCode::F5))) {
|
||||
if (ImGui::IsKeyReleased(ImGuiKey_F5)) {
|
||||
m_paused ^= 1;
|
||||
g_Main->SetPaused(m_paused);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "Runtime/World/CPathFindArea.hpp"
|
||||
|
||||
#include <logvisor/logvisor.hpp>
|
||||
|
||||
#include "Runtime/CToken.hpp"
|
||||
#include "Runtime/IVParamObj.hpp"
|
||||
|
||||
|
|
|
@ -4,6 +4,9 @@ if (NOT MSVC)
|
|||
endif ()
|
||||
|
||||
add_subdirectory(../extern/dawn dawn EXCLUDE_FROM_ALL)
|
||||
target_compile_definitions(dawn_native PRIVATE
|
||||
DAWN_ENABLE_VULKAN_VALIDATION_LAYERS
|
||||
DAWN_VK_DATA_DIR="vulkandata")
|
||||
if (NOT MSVC)
|
||||
target_compile_options(SPIRV-Tools-static PRIVATE -Wno-implicit-fallthrough)
|
||||
target_compile_options(SPIRV-Tools-opt PRIVATE -Wno-implicit-fallthrough)
|
||||
|
@ -11,6 +14,7 @@ endif ()
|
|||
|
||||
add_library(aurora STATIC
|
||||
lib/aurora.cpp
|
||||
lib/gpu.cpp
|
||||
lib/imgui.cpp
|
||||
lib/dawn/BackendBinding.cpp
|
||||
lib/gfx/common.cpp
|
||||
|
|
|
@ -1,65 +1,31 @@
|
|||
#include <aurora/aurora.hpp>
|
||||
|
||||
#include "gfx/common.hpp"
|
||||
#include "gpu.hpp"
|
||||
#include "imgui.hpp"
|
||||
|
||||
#include <SDL.h>
|
||||
#include <dawn/native/DawnNative.h>
|
||||
// TODO HACK: dawn doesn't expose device toggles
|
||||
#include "../extern/dawn/src/dawn/native/Toggles.h"
|
||||
#include <dawn/webgpu_cpp.h>
|
||||
#include <imgui.h>
|
||||
#include <logvisor/logvisor.hpp>
|
||||
#include <magic_enum.hpp>
|
||||
|
||||
#ifdef DAWN_ENABLE_BACKEND_VULKAN
|
||||
#include <SDL_vulkan.h>
|
||||
#include <dawn/native/VulkanBackend.h>
|
||||
#endif
|
||||
#ifdef DAWN_ENABLE_BACKEND_OPENGL
|
||||
#include <SDL_opengl.h>
|
||||
#include <dawn/native/OpenGLBackend.h>
|
||||
#endif
|
||||
#ifdef DAWN_ENABLE_BACKEND_METAL
|
||||
#include <SDL_metal.h>
|
||||
#include <dawn/native/MetalBackend.h>
|
||||
#endif
|
||||
|
||||
#include "dawn/BackendBinding.hpp"
|
||||
|
||||
// imgui
|
||||
#include <backends/imgui_impl_sdl.h>
|
||||
#include <backends/imgui_impl_wgpu.h>
|
||||
|
||||
// TODO HACK: dawn doesn't expose device toggles
|
||||
namespace dawn::native {
|
||||
class DeviceBase {
|
||||
public:
|
||||
void SetToggle(Toggle toggle, bool isEnabled);
|
||||
};
|
||||
} // namespace dawn::native
|
||||
|
||||
namespace aurora {
|
||||
// TODO: Move global state to a class/struct?
|
||||
static logvisor::Module Log("aurora");
|
||||
|
||||
// TODO: Move global state to a class/struct?
|
||||
static std::unique_ptr<AppDelegate> g_AppDelegate;
|
||||
static std::vector<std::string> g_Args;
|
||||
|
||||
// SDL
|
||||
static SDL_Window* g_Window;
|
||||
|
||||
// Dawn / WebGPU
|
||||
#ifdef DAWN_ENABLE_BACKEND_VULKAN
|
||||
static wgpu::BackendType preferredBackendType = wgpu::BackendType::Vulkan;
|
||||
#elif DAWN_ENABLE_BACKEND_METAL
|
||||
static wgpu::BackendType preferredBackendType = wgpu::BackendType::Metal;
|
||||
#else
|
||||
static wgpu::BackendType preferredBackendType = wgpu::BackendType::OpenGL;
|
||||
#endif
|
||||
static std::unique_ptr<dawn::native::Instance> g_Instance;
|
||||
static dawn::native::Adapter g_Adapter;
|
||||
static wgpu::AdapterProperties g_AdapterProperties;
|
||||
wgpu::Device g_Device;
|
||||
wgpu::Queue g_Queue;
|
||||
static wgpu::SwapChain g_SwapChain;
|
||||
static std::unique_ptr<utils::BackendBinding> g_BackendBinding;
|
||||
// GPU
|
||||
using gpu::g_depthBuffer;
|
||||
using gpu::g_device;
|
||||
using gpu::g_frameBuffer;
|
||||
using gpu::g_frameBufferResolved;
|
||||
using gpu::g_queue;
|
||||
using gpu::g_swapChain;
|
||||
|
||||
static void set_window_icon(Icon icon) noexcept {
|
||||
SDL_Surface* iconSurface = SDL_CreateRGBSurfaceFrom(icon.data.get(), icon.width, icon.height, 32, 4 * icon.width,
|
||||
|
@ -79,7 +45,7 @@ static void set_window_icon(Icon icon) noexcept {
|
|||
static bool poll_events() noexcept {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event) != 0) {
|
||||
ImGui_ImplSDL2_ProcessEvent(&event);
|
||||
imgui::process_event(event);
|
||||
|
||||
switch (event.type) {
|
||||
case SDL_WINDOWEVENT: {
|
||||
|
@ -98,8 +64,7 @@ static bool poll_events() noexcept {
|
|||
break;
|
||||
}
|
||||
case SDL_WINDOWEVENT_RESIZED: {
|
||||
auto format = static_cast<wgpu::TextureFormat>(g_BackendBinding->GetPreferredSwapChainTextureFormat());
|
||||
g_SwapChain.Configure(format, wgpu::TextureUsage::RenderAttachment, event.window.data1, event.window.data2);
|
||||
gpu::resize_swapchain(event.window.data1, event.window.data2);
|
||||
g_AppDelegate->onAppWindowResized(
|
||||
{static_cast<uint32_t>(event.window.data1), static_cast<uint32_t>(event.window.data2)});
|
||||
break;
|
||||
|
@ -211,7 +176,7 @@ void app_run(std::unique_ptr<AppDelegate> app, Icon icon, int argc, char** argv)
|
|||
}
|
||||
|
||||
Uint32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE;
|
||||
switch (preferredBackendType) {
|
||||
switch (gpu::preferredBackendType) {
|
||||
#ifdef DAWN_ENABLE_BACKEND_VULKAN
|
||||
case wgpu::BackendType::Vulkan:
|
||||
flags |= SDL_WINDOW_VULKAN;
|
||||
|
@ -236,126 +201,104 @@ void app_run(std::unique_ptr<AppDelegate> app, Icon icon, int argc, char** argv)
|
|||
}
|
||||
set_window_icon(std::move(icon));
|
||||
|
||||
Log.report(logvisor::Info, FMT_STRING("Creating Dawn instance"));
|
||||
g_Instance = std::make_unique<dawn::native::Instance>();
|
||||
utils::DiscoverAdapter(g_Instance.get(), g_Window, preferredBackendType);
|
||||
gpu::initialize(g_Window);
|
||||
gfx::construct_state();
|
||||
|
||||
{
|
||||
std::vector<dawn::native::Adapter> adapters = g_Instance->GetAdapters();
|
||||
auto adapterIt = std::find_if(adapters.begin(), adapters.end(), [](const dawn::native::Adapter adapter) -> bool {
|
||||
wgpu::AdapterProperties properties;
|
||||
adapter.GetProperties(&properties);
|
||||
return properties.backendType == preferredBackendType;
|
||||
});
|
||||
if (adapterIt == adapters.end()) {
|
||||
Log.report(logvisor::Fatal, FMT_STRING("Failed to find usable graphics backend"));
|
||||
}
|
||||
g_Adapter = *adapterIt;
|
||||
}
|
||||
g_Adapter.GetProperties(&g_AdapterProperties);
|
||||
const auto backendName = magic_enum::enum_name(g_AdapterProperties.backendType);
|
||||
Log.report(logvisor::Info, FMT_STRING("Using {} graphics backend"), backendName);
|
||||
|
||||
{
|
||||
const std::array<wgpu::FeatureName, 1> requiredFeatures{
|
||||
wgpu::FeatureName::TextureCompressionBC,
|
||||
};
|
||||
const auto deviceDescriptor = wgpu::DeviceDescriptor{
|
||||
.requiredFeaturesCount = requiredFeatures.size(),
|
||||
.requiredFeatures = requiredFeatures.data(),
|
||||
};
|
||||
g_Device = wgpu::Device::Acquire(g_Adapter.CreateDevice(&deviceDescriptor));
|
||||
// TODO HACK: dawn doesn't expose device toggles
|
||||
static_cast<dawn::native::DeviceBase*>(static_cast<void*>(g_Device.Get()))
|
||||
->SetToggle(dawn::native::Toggle::UseUserDefinedLabelsInBackend, true);
|
||||
}
|
||||
|
||||
g_BackendBinding = std::unique_ptr<utils::BackendBinding>(
|
||||
utils::CreateBinding(g_AdapterProperties.backendType, g_Window, g_Device.Get()));
|
||||
if (!g_BackendBinding) {
|
||||
Log.report(logvisor::Fatal, FMT_STRING("Unsupported backend {}"), backendName);
|
||||
}
|
||||
|
||||
g_Queue = g_Device.GetQueue();
|
||||
{
|
||||
wgpu::SwapChainDescriptor descriptor{};
|
||||
descriptor.implementation = g_BackendBinding->GetSwapChainImplementation();
|
||||
g_SwapChain = g_Device.CreateSwapChain(nullptr, &descriptor);
|
||||
}
|
||||
{
|
||||
auto size = get_window_size();
|
||||
auto format = static_cast<wgpu::TextureFormat>(g_BackendBinding->GetPreferredSwapChainTextureFormat());
|
||||
Log.report(logvisor::Info, FMT_STRING("Using swapchain format {}"), magic_enum::enum_name(format));
|
||||
g_SwapChain.Configure(format, wgpu::TextureUsage::RenderAttachment, size.width, size.height);
|
||||
}
|
||||
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.IniFilename = nullptr;
|
||||
imgui::create_context();
|
||||
g_AppDelegate->onImGuiInit(1.f); // TODO scale
|
||||
ImGui_ImplSDL2_InitForMetal(g_Window);
|
||||
ImGui_ImplWGPU_Init(g_Device.Get(), 1, g_BackendBinding->GetPreferredSwapChainTextureFormat());
|
||||
imgui::initialize(g_Window);
|
||||
g_AppDelegate->onImGuiAddTextures();
|
||||
|
||||
g_AppDelegate->onAppLaunched();
|
||||
g_AppDelegate->onAppWindowResized(get_window_size());
|
||||
|
||||
while (poll_events()) {
|
||||
ImGui_ImplWGPU_NewFrame();
|
||||
ImGui_ImplSDL2_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
imgui::new_frame();
|
||||
if (!g_AppDelegate->onAppIdle(ImGui::GetIO().DeltaTime)) {
|
||||
break;
|
||||
}
|
||||
|
||||
g_AppDelegate->onAppIdle(ImGui::GetIO().DeltaTime);
|
||||
|
||||
const wgpu::TextureView view = g_SwapChain.GetCurrentTextureView();
|
||||
const wgpu::TextureView view = g_swapChain.GetCurrentTextureView();
|
||||
g_AppDelegate->onAppDraw();
|
||||
ImGui::Render();
|
||||
|
||||
auto encoder = g_Device.CreateCommandEncoder();
|
||||
const auto encoderDescriptor = wgpu::CommandEncoderDescriptor{
|
||||
.label = "Redraw encoder",
|
||||
};
|
||||
auto encoder = g_device.CreateCommandEncoder(&encoderDescriptor);
|
||||
{
|
||||
std::array<wgpu::RenderPassColorAttachment, 1> attachments{wgpu::RenderPassColorAttachment{
|
||||
const std::array attachments{
|
||||
wgpu::RenderPassColorAttachment{
|
||||
.view = view,
|
||||
// .resolveTarget = g_frameBufferResolved.view,
|
||||
.loadOp = wgpu::LoadOp::Clear,
|
||||
.storeOp = wgpu::StoreOp::Store,
|
||||
.clearColor = {0.f, 0.f, 0.f, 0.f},
|
||||
}};
|
||||
},
|
||||
};
|
||||
const auto depthStencilAttachment = wgpu::RenderPassDepthStencilAttachment{
|
||||
.view = g_depthBuffer.view,
|
||||
.depthLoadOp = wgpu::LoadOp::Clear,
|
||||
.depthStoreOp = wgpu::StoreOp::Discard,
|
||||
.clearDepth = 1.f,
|
||||
.stencilLoadOp = wgpu::LoadOp::Clear,
|
||||
.stencilStoreOp = wgpu::StoreOp::Discard,
|
||||
};
|
||||
auto renderPassDescriptor = wgpu::RenderPassDescriptor{
|
||||
.label = "Render Pass",
|
||||
.label = "Main render pass",
|
||||
.colorAttachmentCount = attachments.size(),
|
||||
.colorAttachments = attachments.data(),
|
||||
.depthStencilAttachment = &depthStencilAttachment,
|
||||
};
|
||||
auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
|
||||
gfx::render(pass);
|
||||
pass.End();
|
||||
}
|
||||
{
|
||||
const std::array attachments{
|
||||
wgpu::RenderPassColorAttachment{
|
||||
.view = view,
|
||||
.loadOp = wgpu::LoadOp::Load,
|
||||
.storeOp = wgpu::StoreOp::Store,
|
||||
},
|
||||
};
|
||||
auto renderPassDescriptor = wgpu::RenderPassDescriptor{
|
||||
.label = "ImGui render pass",
|
||||
.colorAttachmentCount = attachments.size(),
|
||||
.colorAttachments = attachments.data(),
|
||||
};
|
||||
auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
|
||||
ImGui_ImplWGPU_RenderDrawData(ImGui::GetDrawData(), pass.Get());
|
||||
imgui::render(pass);
|
||||
pass.End();
|
||||
}
|
||||
const auto buffer = encoder.Finish();
|
||||
g_Queue.Submit(1, &buffer);
|
||||
g_SwapChain.Present();
|
||||
g_queue.Submit(1, &buffer);
|
||||
g_swapChain.Present();
|
||||
|
||||
g_AppDelegate->onAppPostDraw();
|
||||
|
||||
ImGui::EndFrame();
|
||||
}
|
||||
|
||||
g_AppDelegate->onAppExiting();
|
||||
|
||||
wgpuSwapChainRelease(g_SwapChain.Release());
|
||||
wgpuQueueRelease(g_Queue.Release());
|
||||
g_BackendBinding.reset();
|
||||
wgpuDeviceRelease(g_Device.Release());
|
||||
g_Instance.reset();
|
||||
imgui::shutdown();
|
||||
gpu::shutdown();
|
||||
SDL_DestroyWindow(g_Window);
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
std::vector<std::string> get_args() noexcept { return g_Args; }
|
||||
|
||||
WindowSize get_window_size() noexcept {
|
||||
int width, height;
|
||||
SDL_GetWindowSize(g_Window, &width, &height);
|
||||
return {static_cast<uint32_t>(width), static_cast<uint32_t>(height)};
|
||||
}
|
||||
|
||||
void set_window_title(zstring_view title) noexcept { SDL_SetWindowTitle(g_Window, title.c_str()); }
|
||||
|
||||
Backend get_backend() noexcept {
|
||||
switch (g_AdapterProperties.backendType) {
|
||||
switch (gpu::g_backendType) {
|
||||
case wgpu::BackendType::WebGPU:
|
||||
return Backend::WebGPU;
|
||||
case wgpu::BackendType::D3D11:
|
||||
|
@ -374,7 +317,9 @@ Backend get_backend() noexcept {
|
|||
return Backend::Invalid;
|
||||
}
|
||||
}
|
||||
std::string_view get_backend_string() noexcept { return magic_enum::enum_name(g_AdapterProperties.backendType); }
|
||||
|
||||
std::string_view get_backend_string() noexcept { return magic_enum::enum_name(gpu::g_backendType); }
|
||||
|
||||
void set_fullscreen(bool fullscreen) noexcept {
|
||||
auto flags = SDL_GetWindowFlags(g_Window);
|
||||
if (fullscreen) {
|
||||
|
@ -388,12 +333,15 @@ void set_fullscreen(bool fullscreen) noexcept {
|
|||
int32_t get_controller_player_index(uint32_t which) noexcept {
|
||||
return -1; // TODO
|
||||
}
|
||||
|
||||
void set_controller_player_index(uint32_t which, int32_t index) noexcept {
|
||||
// TODO
|
||||
}
|
||||
|
||||
bool is_controller_gamecube(uint32_t which) noexcept {
|
||||
return true; // TODO
|
||||
}
|
||||
|
||||
std::string get_controller_name(uint32_t which) noexcept {
|
||||
return ""; // TODO
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <dawn/native/OpenGLBackend.h>
|
||||
#endif
|
||||
|
||||
namespace aurora::utils {
|
||||
namespace aurora::gpu::utils {
|
||||
|
||||
#if defined(DAWN_ENABLE_BACKEND_D3D12)
|
||||
BackendBinding* CreateD3D12Binding(SDL_Window* window, WGPUDevice device);
|
||||
|
@ -76,4 +76,4 @@ BackendBinding* CreateBinding(wgpu::BackendType type, SDL_Window* window, WGPUDe
|
|||
}
|
||||
}
|
||||
|
||||
} // namespace aurora::utils
|
||||
} // namespace aurora::gpu::utils
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
struct SDL_Window;
|
||||
|
||||
namespace aurora::utils {
|
||||
namespace aurora::gpu::utils {
|
||||
|
||||
class BackendBinding {
|
||||
public:
|
||||
|
@ -24,4 +24,4 @@ protected:
|
|||
void DiscoverAdapter(dawn::native::Instance* instance, SDL_Window* window, wgpu::BackendType type);
|
||||
BackendBinding* CreateBinding(wgpu::BackendType type, SDL_Window* window, WGPUDevice device);
|
||||
|
||||
} // namespace aurora::utils
|
||||
} // namespace aurora::gpu::utils
|
||||
|
|
|
@ -24,7 +24,7 @@ template <typename T> DawnSwapChainImplementation CreateSwapChainImplementation(
|
|||
return impl;
|
||||
}
|
||||
|
||||
namespace aurora::utils {
|
||||
namespace aurora::gpu::utils {
|
||||
class SwapChainImplMTL {
|
||||
public:
|
||||
using WSIContext = DawnWSIContextMetal;
|
||||
|
@ -105,4 +105,4 @@ private:
|
|||
};
|
||||
|
||||
BackendBinding *CreateMetalBinding(SDL_Window *window, WGPUDevice device) { return new MetalBinding(window, device); }
|
||||
} // namespace aurora::utils
|
||||
} // namespace aurora::gpu::utils
|
||||
|
|
|
@ -3,26 +3,33 @@
|
|||
#include <SDL_video.h>
|
||||
#include <dawn/native/OpenGLBackend.h>
|
||||
|
||||
namespace aurora::utils {
|
||||
namespace aurora::gpu::utils {
|
||||
class OpenGLBinding : public BackendBinding {
|
||||
public:
|
||||
OpenGLBinding(SDL_Window* window, WGPUDevice device) : BackendBinding(window, device) {}
|
||||
|
||||
uint64_t GetSwapChainImplementation() override {
|
||||
if (m_swapChainImpl.userData == nullptr) {
|
||||
m_swapChainImpl = dawn::native::opengl::CreateNativeSwapChainImpl(
|
||||
m_device, [](void* userdata) { SDL_GL_SwapWindow(static_cast<SDL_Window*>(userdata)); }, m_window);
|
||||
CreateSwapChainImpl();
|
||||
}
|
||||
return reinterpret_cast<uint64_t>(&m_swapChainImpl);
|
||||
}
|
||||
|
||||
WGPUTextureFormat GetPreferredSwapChainTextureFormat() override {
|
||||
if (m_swapChainImpl.userData == nullptr) {
|
||||
CreateSwapChainImpl();
|
||||
}
|
||||
return dawn::native::opengl::GetNativeSwapChainPreferredFormat(&m_swapChainImpl);
|
||||
}
|
||||
|
||||
private:
|
||||
DawnSwapChainImplementation m_swapChainImpl{};
|
||||
|
||||
void CreateSwapChainImpl() {
|
||||
m_swapChainImpl = dawn::native::opengl::CreateNativeSwapChainImpl(
|
||||
m_device, [](void* userdata) { SDL_GL_SwapWindow(static_cast<SDL_Window*>(userdata)); }, m_window);
|
||||
}
|
||||
};
|
||||
|
||||
BackendBinding* CreateOpenGLBinding(SDL_Window* window, WGPUDevice device) { return new OpenGLBinding(window, device); }
|
||||
} // namespace aurora::utils
|
||||
} // namespace aurora::gpu::utils
|
||||
|
|
|
@ -4,30 +4,36 @@
|
|||
#include <cassert>
|
||||
#include <dawn/native/VulkanBackend.h>
|
||||
|
||||
namespace aurora::utils {
|
||||
namespace aurora::gpu::utils {
|
||||
class VulkanBinding : public BackendBinding {
|
||||
public:
|
||||
VulkanBinding(SDL_Window* window, WGPUDevice device) : BackendBinding(window, device) {}
|
||||
|
||||
uint64_t GetSwapChainImplementation() override {
|
||||
if (m_swapChainImpl.userData == nullptr) {
|
||||
CreateSwapChainImpl();
|
||||
}
|
||||
return reinterpret_cast<uint64_t>(&m_swapChainImpl);
|
||||
}
|
||||
|
||||
WGPUTextureFormat GetPreferredSwapChainTextureFormat() override {
|
||||
if (m_swapChainImpl.userData == nullptr) {
|
||||
CreateSwapChainImpl();
|
||||
}
|
||||
return dawn::native::vulkan::GetNativeSwapChainPreferredFormat(&m_swapChainImpl);
|
||||
}
|
||||
|
||||
private:
|
||||
DawnSwapChainImplementation m_swapChainImpl{};
|
||||
|
||||
void CreateSwapChainImpl() {
|
||||
VkSurfaceKHR surface = VK_NULL_HANDLE;
|
||||
if (SDL_Vulkan_CreateSurface(m_window, dawn::native::vulkan::GetInstance(m_device), &surface) != SDL_TRUE) {
|
||||
assert(false);
|
||||
}
|
||||
m_swapChainImpl = dawn::native::vulkan::CreateNativeSwapChainImpl(m_device, surface);
|
||||
}
|
||||
return reinterpret_cast<uint64_t>(&m_swapChainImpl);
|
||||
}
|
||||
|
||||
WGPUTextureFormat GetPreferredSwapChainTextureFormat() override {
|
||||
assert(m_swapChainImpl.userData != nullptr);
|
||||
return dawn::native::vulkan::GetNativeSwapChainPreferredFormat(&m_swapChainImpl);
|
||||
}
|
||||
|
||||
private:
|
||||
DawnSwapChainImplementation m_swapChainImpl{};
|
||||
};
|
||||
|
||||
BackendBinding* CreateVulkanBinding(SDL_Window* window, WGPUDevice device) { return new VulkanBinding(window, device); }
|
||||
} // namespace aurora::utils
|
||||
} // namespace aurora::gpu::utils
|
||||
|
|
|
@ -1,10 +1,20 @@
|
|||
#include "common.hpp"
|
||||
|
||||
#include <magic_enum.hpp>
|
||||
|
||||
#include "../gpu.hpp"
|
||||
#include "movie_player/shader.hpp"
|
||||
|
||||
#include <logvisor/logvisor.hpp>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace aurora::gfx {
|
||||
static logvisor::Module Log("aurora::gfx");
|
||||
|
||||
using gpu::g_device;
|
||||
using gpu::g_queue;
|
||||
|
||||
struct ShaderState {
|
||||
movie_player::State moviePlayer;
|
||||
};
|
||||
struct ShaderDrawCommand {
|
||||
ShaderType type;
|
||||
union {
|
||||
|
@ -45,9 +55,46 @@ zeus::CMatrix4f g_mvInv;
|
|||
zeus::CMatrix4f g_proj;
|
||||
metaforce::CFogState g_fogState;
|
||||
|
||||
std::vector<Command> g_commands;
|
||||
static std::mutex g_pipelineMutex;
|
||||
static std::unordered_map<uint64_t, wgpu::RenderPipeline> g_pipelines;
|
||||
static std::vector<PipelineCreateCommand> g_queuedPipelines;
|
||||
static std::unordered_map<BindGroupRef, wgpu::BindGroup> g_cachedBindGroups;
|
||||
|
||||
bool get_dxt_compression_supported() noexcept { return g_Device.HasFeature(wgpu::FeatureName::TextureCompressionBC); }
|
||||
static ByteBuffer g_verts;
|
||||
static ByteBuffer g_uniforms;
|
||||
static ByteBuffer g_indices;
|
||||
wgpu::Buffer g_vertexBuffer;
|
||||
wgpu::Buffer g_uniformBuffer;
|
||||
wgpu::Buffer g_indexBuffer;
|
||||
|
||||
static ShaderState g_state;
|
||||
static PipelineRef g_currentPipeline;
|
||||
|
||||
static std::vector<Command> g_commands;
|
||||
|
||||
using NewPipelineCallback = std::function<wgpu::RenderPipeline()>;
|
||||
static PipelineRef find_pipeline(PipelineCreateCommand command, NewPipelineCallback cb) {
|
||||
const auto hash = xxh3_hash(command);
|
||||
bool found;
|
||||
{
|
||||
std::lock_guard guard{g_pipelineMutex};
|
||||
const auto ref = g_pipelines.find(hash);
|
||||
found = ref != g_pipelines.end();
|
||||
}
|
||||
if (!found) {
|
||||
// TODO another thread
|
||||
wgpu::RenderPipeline pipeline = cb();
|
||||
{
|
||||
std::lock_guard guard{g_pipelineMutex};
|
||||
g_pipelines[hash] = std::move(pipeline);
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
static void push_draw_command(ShaderDrawCommand data) { g_commands.push_back({CommandType::Draw, {.draw = data}}); }
|
||||
|
||||
bool get_dxt_compression_supported() noexcept { return g_device.HasFeature(wgpu::FeatureName::TextureCompressionBC); }
|
||||
|
||||
void update_model_view(const zeus::CMatrix4f& mv, const zeus::CMatrix4f& mv_inv) noexcept {
|
||||
g_mv = mv;
|
||||
|
@ -98,8 +145,134 @@ void queue_colored_quad(CameraFilterType filter_type, ZTest z_comparison, bool z
|
|||
const zeus::CRectangle& rect, float z) noexcept {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void queue_movie_player(const TextureHandle& tex_y, const TextureHandle& tex_u, const TextureHandle& tex_v,
|
||||
const zeus::CColor& color, float h_pad, float v_pad) noexcept {
|
||||
auto data = movie_player::make_draw_data(g_state.moviePlayer, tex_y, tex_u, tex_v, color, h_pad, v_pad);
|
||||
push_draw_command({.type = ShaderType::MoviePlayer, .moviePlayer = data});
|
||||
}
|
||||
template <>
|
||||
PipelineRef pipeline_ref(movie_player::PipelineConfig config) {
|
||||
return find_pipeline({.type = ShaderType::MoviePlayer, .moviePlayer = config},
|
||||
[=]() { return create_pipeline(g_state.moviePlayer, config); });
|
||||
}
|
||||
|
||||
void construct_state() {
|
||||
{
|
||||
const auto uniformDescriptor = wgpu::BufferDescriptor{
|
||||
.label = "Shared Uniform Buffer",
|
||||
.usage = wgpu::BufferUsage::Uniform | wgpu::BufferUsage::CopyDst,
|
||||
.size = 134217728, // 128mb
|
||||
};
|
||||
g_uniformBuffer = g_device.CreateBuffer(&uniformDescriptor);
|
||||
}
|
||||
{
|
||||
const auto vertexDescriptor = wgpu::BufferDescriptor{
|
||||
.label = "Shared Vertex Buffer",
|
||||
.usage = wgpu::BufferUsage::Vertex | wgpu::BufferUsage::CopyDst,
|
||||
.size = 16777216, // 16mb
|
||||
};
|
||||
g_vertexBuffer = g_device.CreateBuffer(&vertexDescriptor);
|
||||
}
|
||||
{
|
||||
const auto vertexDescriptor = wgpu::BufferDescriptor{
|
||||
.label = "Shared Index Buffer",
|
||||
.usage = wgpu::BufferUsage::Vertex | wgpu::BufferUsage::CopyDst,
|
||||
.size = 4194304, // 4mb
|
||||
};
|
||||
g_indexBuffer = g_device.CreateBuffer(&vertexDescriptor);
|
||||
}
|
||||
|
||||
g_state.moviePlayer = movie_player::construct_state();
|
||||
}
|
||||
|
||||
void render(const wgpu::RenderPassEncoder& pass) {
|
||||
{
|
||||
g_queue.WriteBuffer(g_vertexBuffer, 0, g_verts.data(), g_verts.size());
|
||||
g_queue.WriteBuffer(g_uniformBuffer, 0, g_uniforms.data(), g_uniforms.size());
|
||||
g_queue.WriteBuffer(g_indexBuffer, 0, g_indices.data(), g_indices.size());
|
||||
g_verts.clear();
|
||||
g_uniforms.clear();
|
||||
g_indices.clear();
|
||||
}
|
||||
|
||||
g_currentPipeline = UINT64_MAX;
|
||||
|
||||
for (const auto& cmd : g_commands) {
|
||||
switch (cmd.type) {
|
||||
case CommandType::SetViewport: {
|
||||
const auto& vp = cmd.data.setViewport;
|
||||
pass.SetViewport(vp.rect.position.x(), vp.rect.position.y(), vp.rect.size.x(), vp.rect.size.y(), vp.znear,
|
||||
vp.zfar);
|
||||
} break;
|
||||
case CommandType::SetScissor: {
|
||||
const auto& sc = cmd.data.setScissor;
|
||||
pass.SetScissorRect(sc.x, sc.y, sc.w, sc.h);
|
||||
} break;
|
||||
case CommandType::Draw: {
|
||||
const auto& draw = cmd.data.draw;
|
||||
switch (draw.type) {
|
||||
case ShaderType::Aabb:
|
||||
// TODO
|
||||
break;
|
||||
case ShaderType::TexturedQuad:
|
||||
// TODO
|
||||
break;
|
||||
case ShaderType::MoviePlayer:
|
||||
movie_player::render(g_state.moviePlayer, draw.moviePlayer, pass);
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
g_commands.clear();
|
||||
}
|
||||
|
||||
bool bind_pipeline(PipelineRef ref, const wgpu::RenderPassEncoder& pass) {
|
||||
if (ref == g_currentPipeline) {
|
||||
return true;
|
||||
}
|
||||
std::lock_guard guard{g_pipelineMutex};
|
||||
if (!g_pipelines.contains(ref)) {
|
||||
return false;
|
||||
}
|
||||
pass.SetPipeline(g_pipelines[ref]);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline Range push(ByteBuffer& target, const uint8_t* data, size_t length, size_t alignment) {
|
||||
size_t padding = 0;
|
||||
if (alignment != 0) {
|
||||
padding = alignment - length % alignment;
|
||||
}
|
||||
auto begin = target.size();
|
||||
target.append(data, length);
|
||||
if (padding > 0) {
|
||||
target.append_zeroes(padding);
|
||||
}
|
||||
return {begin, begin + length};
|
||||
}
|
||||
Range push_verts(const uint8_t* data, size_t length) { return push(g_verts, data, length, 0 /* TODO? */); }
|
||||
Range push_indices(const uint8_t* data, size_t length) { return push(g_indices, data, length, 0 /* TODO? */); }
|
||||
Range push_uniform(const uint8_t* data, size_t length) {
|
||||
wgpu::SupportedLimits limits;
|
||||
g_device.GetLimits(&limits);
|
||||
return push(g_uniforms, data, length, limits.limits.minUniformBufferOffsetAlignment);
|
||||
}
|
||||
|
||||
BindGroupRef bind_group_ref(const wgpu::BindGroupDescriptor& descriptor) {
|
||||
const auto id =
|
||||
xxh3_hash(descriptor.entries, descriptor.entryCount * sizeof(wgpu::BindGroupEntry), xxh3_hash(descriptor));
|
||||
if (!g_cachedBindGroups.contains(id)) {
|
||||
g_cachedBindGroups[id] = g_device.CreateBindGroup(&descriptor);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
const wgpu::BindGroup& find_bind_group(BindGroupRef id) {
|
||||
if (!g_cachedBindGroups.contains(id)) {
|
||||
Log.report(logvisor::Fatal, FMT_STRING("get_bind_group: failed to locate {}"), id);
|
||||
}
|
||||
return g_cachedBindGroups[id];
|
||||
}
|
||||
} // namespace aurora::gfx
|
||||
|
|
|
@ -9,24 +9,103 @@
|
|||
#include <xxh_x86dispatch.h>
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
XXH64_hash_t xxh3_hash(const T& input, XXH64_hash_t seed = 0) {
|
||||
return XXH3_64bits_withSeed(&input, sizeof(T), seed);
|
||||
}
|
||||
#ifndef ALIGN
|
||||
#define ALIGN(x, a) (((x) + ((a)-1)) & ~((a)-1))
|
||||
#endif
|
||||
|
||||
namespace aurora {
|
||||
extern wgpu::Device g_Device;
|
||||
extern wgpu::Queue g_Queue;
|
||||
static inline XXH64_hash_t xxh3_hash(const void* input, size_t len, XXH64_hash_t seed = 0) {
|
||||
return XXH3_64bits_withSeed(input, len, seed);
|
||||
}
|
||||
template <typename T>
|
||||
static inline XXH64_hash_t xxh3_hash(const T& input, XXH64_hash_t seed = 0) {
|
||||
return xxh3_hash(&input, sizeof(T), seed);
|
||||
}
|
||||
|
||||
class ByteBuffer {
|
||||
public:
|
||||
ByteBuffer() = default;
|
||||
explicit ByteBuffer(size_t capacity) : m_data(static_cast<uint8_t*>(calloc(1, capacity))), m_capacity(capacity) {}
|
||||
|
||||
~ByteBuffer() {
|
||||
if (m_data != nullptr) {
|
||||
free(m_data);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t* data() { return m_data; }
|
||||
const uint8_t* data() const { return m_data; }
|
||||
size_t size() const { return m_length; }
|
||||
|
||||
void append(const void* data, size_t size) {
|
||||
resize(m_length + size);
|
||||
memcpy(m_data + m_length, data, size);
|
||||
m_length += size;
|
||||
}
|
||||
void append_zeroes(size_t size) {
|
||||
resize(m_length + size);
|
||||
memset(m_data + m_length, 0, size);
|
||||
m_length += size;
|
||||
}
|
||||
|
||||
void resize(size_t size) {
|
||||
if (size == 0) {
|
||||
clear();
|
||||
} else if (m_data == nullptr) {
|
||||
m_data = static_cast<uint8_t*>(malloc(size));
|
||||
} else if (size > m_capacity) {
|
||||
m_data = static_cast<uint8_t*>(realloc(m_data, size));
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
m_capacity = size;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
if (m_data != nullptr) {
|
||||
free(m_data);
|
||||
}
|
||||
m_data = nullptr;
|
||||
m_length = 0;
|
||||
m_capacity = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t* m_data = nullptr;
|
||||
size_t m_length = 0;
|
||||
size_t m_capacity = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Vec2 {
|
||||
T x{};
|
||||
T y{};
|
||||
};
|
||||
template <typename T>
|
||||
struct Vec3 {
|
||||
T x{};
|
||||
T y{};
|
||||
T z{};
|
||||
};
|
||||
template <typename T>
|
||||
struct Vec4 {
|
||||
T x{};
|
||||
T y{};
|
||||
T z{};
|
||||
T w{};
|
||||
};
|
||||
} // namespace aurora
|
||||
|
||||
namespace aurora::gfx {
|
||||
static logvisor::Module Log("aurora::gfx");
|
||||
|
||||
extern zeus::CMatrix4f g_mv;
|
||||
extern zeus::CMatrix4f g_mvInv;
|
||||
extern zeus::CMatrix4f g_proj;
|
||||
extern metaforce::CFogState g_fogState;
|
||||
|
||||
extern wgpu::Buffer g_vertexBuffer;
|
||||
extern wgpu::Buffer g_uniformBuffer;
|
||||
extern wgpu::Buffer g_indexBuffer;
|
||||
|
||||
struct TextureRef {
|
||||
wgpu::Texture texture;
|
||||
wgpu::TextureView view;
|
||||
|
@ -38,11 +117,41 @@ struct TextureRef {
|
|||
};
|
||||
|
||||
using PipelineRef = uint64_t;
|
||||
using Range = std::pair<uint64_t, uint64_t>;
|
||||
using BindGroupRef = uint64_t;
|
||||
using Range = std::pair<uint32_t, uint32_t>;
|
||||
|
||||
enum class ShaderType {
|
||||
Aabb,
|
||||
TexturedQuad,
|
||||
MoviePlayer,
|
||||
};
|
||||
|
||||
void construct_state();
|
||||
|
||||
void render(const wgpu::RenderPassEncoder& pass);
|
||||
|
||||
Range push_verts(const uint8_t* data, size_t length);
|
||||
template <typename T>
|
||||
static inline Range push_verts(ArrayRef<T> data) {
|
||||
return push_verts(reinterpret_cast<const uint8_t*>(data.data()), data.size() * sizeof(T));
|
||||
}
|
||||
Range push_indices(const uint8_t* data, size_t length);
|
||||
template <typename T>
|
||||
static inline Range push_indices(ArrayRef<T> data) {
|
||||
return push_indices(reinterpret_cast<const uint8_t*>(data.data()), data.size() * sizeof(T));
|
||||
}
|
||||
Range push_uniform(const uint8_t* data, size_t length);
|
||||
template <typename T>
|
||||
static inline Range push_uniform(const T& data) {
|
||||
return push_uniform(reinterpret_cast<const uint8_t*>(&data), sizeof(T));
|
||||
}
|
||||
|
||||
template <typename PipelineConfig>
|
||||
PipelineRef pipeline_ref(PipelineConfig config);
|
||||
bool bind_pipeline(PipelineRef ref, const wgpu::RenderPassEncoder& pass);
|
||||
|
||||
BindGroupRef bind_group_ref(const wgpu::BindGroupDescriptor& descriptor);
|
||||
const wgpu::BindGroup& find_bind_group(BindGroupRef id);
|
||||
|
||||
static inline zeus::CMatrix4f get_combined_matrix() { return g_proj * g_mv; }
|
||||
} // namespace aurora::gfx
|
||||
|
|
|
@ -0,0 +1,280 @@
|
|||
#include "shader.hpp"
|
||||
|
||||
#include "../../gpu.hpp"
|
||||
|
||||
namespace aurora::gfx::movie_player {
|
||||
using gpu::g_device;
|
||||
using gpu::g_graphicsConfig;
|
||||
using gpu::utils::make_vertex_attributes;
|
||||
using gpu::utils::make_vertex_buffer_layout;
|
||||
using gpu::utils::make_vertex_state;
|
||||
|
||||
State construct_state() {
|
||||
wgpu::ShaderModuleWGSLDescriptor wgslDescriptor{};
|
||||
wgslDescriptor.source = R"""(
|
||||
struct Uniform {
|
||||
xf: mat4x4<f32>;
|
||||
color: vec4<f32>;
|
||||
};
|
||||
@group(0) @binding(0)
|
||||
var<uniform> ubuf: Uniform;
|
||||
@group(0) @binding(1)
|
||||
var tex_sampler: sampler;
|
||||
@group(1) @binding(0)
|
||||
var tex_y: texture_2d<f32>;
|
||||
@group(1) @binding(1)
|
||||
var tex_u: texture_2d<f32>;
|
||||
@group(1) @binding(2)
|
||||
var tex_v: texture_2d<f32>;
|
||||
|
||||
struct VertexOutput {
|
||||
@builtin(position) pos: vec4<f32>;
|
||||
@location(0) uv: vec2<f32>;
|
||||
};
|
||||
|
||||
@stage(vertex)
|
||||
fn vs_main(@location(0) in_pos: vec3<f32>, @location(1) in_uv: vec2<f32>) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
out.pos = ubuf.xf * vec4<f32>(in_pos, 1.0);
|
||||
out.uv = in_uv;
|
||||
return out;
|
||||
}
|
||||
|
||||
@stage(fragment)
|
||||
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||
var yuv = vec3<f32>(
|
||||
1.1643 * (textureSample(tex_y, tex_sampler, in.uv).x - 0.0625),
|
||||
textureSample(tex_u, tex_sampler, in.uv).x - 0.5,
|
||||
textureSample(tex_v, tex_sampler, in.uv).x - 0.5
|
||||
);
|
||||
return ubuf.color * vec4<f32>(
|
||||
yuv.x + 1.5958 * yuv.z,
|
||||
yuv.x - 0.39173 * yuv.y - 0.8129 * yuv.z,
|
||||
yuv.x + 2.017 * yuv.y,
|
||||
1.0
|
||||
);
|
||||
}
|
||||
)""";
|
||||
const auto shaderDescriptor = wgpu::ShaderModuleDescriptor{
|
||||
.nextInChain = &wgslDescriptor,
|
||||
.label = "Movie Player Shader",
|
||||
};
|
||||
auto shader = g_device.CreateShaderModule(&shaderDescriptor);
|
||||
|
||||
wgpu::SupportedLimits limits;
|
||||
g_device.GetLimits(&limits);
|
||||
const auto uniform_alignment = limits.limits.minUniformBufferOffsetAlignment;
|
||||
const auto uniform_size = ALIGN(sizeof(Uniform), uniform_alignment);
|
||||
|
||||
const std::array uniformLayoutEntries{
|
||||
wgpu::BindGroupLayoutEntry{
|
||||
.binding = 0,
|
||||
.visibility = wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment,
|
||||
.buffer =
|
||||
wgpu::BufferBindingLayout{
|
||||
.type = wgpu::BufferBindingType::Uniform,
|
||||
.hasDynamicOffset = true,
|
||||
.minBindingSize = uniform_size,
|
||||
},
|
||||
},
|
||||
wgpu::BindGroupLayoutEntry{
|
||||
.binding = 1,
|
||||
.visibility = wgpu::ShaderStage::Fragment,
|
||||
.sampler =
|
||||
wgpu::SamplerBindingLayout{
|
||||
.type = wgpu::SamplerBindingType::Filtering,
|
||||
},
|
||||
},
|
||||
};
|
||||
const auto uniformLayoutDescriptor = wgpu::BindGroupLayoutDescriptor{
|
||||
.label = "Movie Player Uniform Bind Group Layout",
|
||||
.entryCount = uniformLayoutEntries.size(),
|
||||
.entries = uniformLayoutEntries.data(),
|
||||
};
|
||||
auto uniformLayout = g_device.CreateBindGroupLayout(&uniformLayoutDescriptor);
|
||||
|
||||
const auto samplerDescriptor = wgpu::SamplerDescriptor{
|
||||
.addressModeU = wgpu::AddressMode::Repeat,
|
||||
.addressModeV = wgpu::AddressMode::Repeat,
|
||||
.addressModeW = wgpu::AddressMode::Repeat,
|
||||
.magFilter = wgpu::FilterMode::Linear,
|
||||
.minFilter = wgpu::FilterMode::Linear,
|
||||
.mipmapFilter = wgpu::FilterMode::Linear,
|
||||
.maxAnisotropy = g_graphicsConfig.textureAnistropy,
|
||||
};
|
||||
auto sampler = g_device.CreateSampler(&samplerDescriptor);
|
||||
|
||||
const std::array uniformBindGroupEntries{
|
||||
wgpu::BindGroupEntry{
|
||||
.binding = 0,
|
||||
.buffer = g_uniformBuffer,
|
||||
.offset = 0,
|
||||
.size = uniform_size,
|
||||
},
|
||||
wgpu::BindGroupEntry{
|
||||
.binding = 1,
|
||||
.sampler = sampler,
|
||||
},
|
||||
};
|
||||
const auto uniformBindGroupDescriptor = wgpu::BindGroupDescriptor{
|
||||
.label = "Movie Player Uniform Bind Group",
|
||||
.layout = uniformLayout,
|
||||
.entryCount = uniformBindGroupEntries.size(),
|
||||
.entries = uniformBindGroupEntries.data(),
|
||||
};
|
||||
auto uniformBindGroup = g_device.CreateBindGroup(&uniformBindGroupDescriptor);
|
||||
|
||||
const auto textureBinding = wgpu::TextureBindingLayout{
|
||||
.sampleType = wgpu::TextureSampleType::Float,
|
||||
.viewDimension = wgpu::TextureViewDimension::e2D,
|
||||
};
|
||||
const std::array textureLayoutEntries{
|
||||
wgpu::BindGroupLayoutEntry{
|
||||
.binding = 0,
|
||||
.visibility = wgpu::ShaderStage::Fragment,
|
||||
.texture = textureBinding,
|
||||
},
|
||||
wgpu::BindGroupLayoutEntry{
|
||||
.binding = 1,
|
||||
.visibility = wgpu::ShaderStage::Fragment,
|
||||
.texture = textureBinding,
|
||||
},
|
||||
wgpu::BindGroupLayoutEntry{
|
||||
.binding = 2,
|
||||
.visibility = wgpu::ShaderStage::Fragment,
|
||||
.texture = textureBinding,
|
||||
},
|
||||
};
|
||||
const auto textureLayoutDescriptor = wgpu::BindGroupLayoutDescriptor{
|
||||
.label = "Movie Player Texture Bind Group Layout",
|
||||
.entryCount = textureLayoutEntries.size(),
|
||||
.entries = textureLayoutEntries.data(),
|
||||
};
|
||||
auto textureLayout = g_device.CreateBindGroupLayout(&textureLayoutDescriptor);
|
||||
|
||||
const std::array bindGroupLayouts{
|
||||
uniformLayout,
|
||||
textureLayout,
|
||||
};
|
||||
const auto pipelineLayoutDescriptor = wgpu::PipelineLayoutDescriptor{
|
||||
.label = "Movie Player Pipeline Layout",
|
||||
.bindGroupLayoutCount = bindGroupLayouts.size(),
|
||||
.bindGroupLayouts = bindGroupLayouts.data(),
|
||||
};
|
||||
auto pipelineLayout = g_device.CreatePipelineLayout(&pipelineLayoutDescriptor);
|
||||
|
||||
return {
|
||||
.shader = shader,
|
||||
.uniformLayout = uniformLayout,
|
||||
.uniformBindGroup = uniformBindGroup,
|
||||
.textureLayout = textureLayout,
|
||||
.sampler = sampler,
|
||||
.pipelineLayout = pipelineLayout,
|
||||
};
|
||||
}
|
||||
|
||||
wgpu::RenderPipeline create_pipeline(const State& state, [[maybe_unused]] PipelineConfig config) {
|
||||
const auto attributes =
|
||||
make_vertex_attributes(std::array{wgpu::VertexFormat::Float32x3, wgpu::VertexFormat::Float32x2});
|
||||
const std::array vertexBuffers{make_vertex_buffer_layout(sizeof(Vert), attributes)};
|
||||
const auto depthStencil = wgpu::DepthStencilState{
|
||||
.format = g_graphicsConfig.depthFormat,
|
||||
};
|
||||
const auto blendComponent = wgpu::BlendComponent{
|
||||
.srcFactor = wgpu::BlendFactor::SrcAlpha,
|
||||
.dstFactor = wgpu::BlendFactor::OneMinusSrcAlpha,
|
||||
};
|
||||
const auto blendState = wgpu::BlendState{
|
||||
.color = blendComponent,
|
||||
.alpha = blendComponent,
|
||||
};
|
||||
const std::array colorTargets{
|
||||
wgpu::ColorTargetState{
|
||||
.format = g_graphicsConfig.colorFormat,
|
||||
.blend = &blendState,
|
||||
.writeMask = wgpu::ColorWriteMask::Red | wgpu::ColorWriteMask::Green | wgpu::ColorWriteMask::Blue,
|
||||
},
|
||||
};
|
||||
const auto fragmentState = wgpu::FragmentState{
|
||||
.module = state.shader,
|
||||
.entryPoint = "fs_main",
|
||||
.targetCount = colorTargets.size(),
|
||||
.targets = colorTargets.data(),
|
||||
};
|
||||
const auto pipelineDescriptor = wgpu::RenderPipelineDescriptor{
|
||||
.label = "Movie Player Pipeline",
|
||||
.layout = state.pipelineLayout,
|
||||
.vertex = make_vertex_state(state.shader, vertexBuffers),
|
||||
.primitive =
|
||||
wgpu::PrimitiveState{
|
||||
.topology = wgpu::PrimitiveTopology::TriangleStrip,
|
||||
},
|
||||
.depthStencil = &depthStencil,
|
||||
.multisample =
|
||||
wgpu::MultisampleState{
|
||||
.count = g_graphicsConfig.msaaSamples,
|
||||
},
|
||||
.fragment = &fragmentState,
|
||||
};
|
||||
return g_device.CreateRenderPipeline(&pipelineDescriptor);
|
||||
}
|
||||
|
||||
DrawData make_draw_data(const State& state, const TextureHandle& tex_y, const TextureHandle& tex_u,
|
||||
const TextureHandle& tex_v, const zeus::CColor& color, float h_pad, float v_pad) {
|
||||
auto pipeline = pipeline_ref(PipelineConfig{});
|
||||
|
||||
const std::array<Vert, 4> verts{
|
||||
Vert{{-h_pad, v_pad, 0.f}, {0.0, 0.0}},
|
||||
Vert{{-h_pad, -v_pad, 0.f}, {0.0, 1.0}},
|
||||
Vert{{h_pad, v_pad, 0.f}, {1.0, 0.0}},
|
||||
Vert{{h_pad, -v_pad, 0.f}, {1.0, 1.0}},
|
||||
};
|
||||
const auto vertRange = push_verts(ArrayRef{verts});
|
||||
|
||||
const auto uniform = Uniform{
|
||||
.xf = zeus::CMatrix4f{},
|
||||
.color = color,
|
||||
};
|
||||
const auto uniformRange = push_uniform(uniform);
|
||||
|
||||
std::array<wgpu::BindGroupEntry, 3> entries{
|
||||
wgpu::BindGroupEntry{
|
||||
.binding = 0,
|
||||
.textureView = tex_y.ref->view,
|
||||
},
|
||||
wgpu::BindGroupEntry{
|
||||
.binding = 1,
|
||||
.textureView = tex_u.ref->view,
|
||||
},
|
||||
wgpu::BindGroupEntry{
|
||||
.binding = 2,
|
||||
.textureView = tex_v.ref->view,
|
||||
},
|
||||
};
|
||||
const auto textureBindGroup = bind_group_ref(wgpu::BindGroupDescriptor{
|
||||
.label = "Movie Player Texture Bind Group",
|
||||
.layout = state.textureLayout,
|
||||
.entryCount = entries.size(),
|
||||
.entries = entries.data(),
|
||||
});
|
||||
|
||||
return {
|
||||
.pipeline = pipeline,
|
||||
.vertRange = vertRange,
|
||||
.uniformRange = uniformRange,
|
||||
.textureBindGroup = textureBindGroup,
|
||||
};
|
||||
}
|
||||
|
||||
void render(const State& state, const DrawData& data, const wgpu::RenderPassEncoder& pass) {
|
||||
if (!bind_pipeline(data.pipeline, pass)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::array offsets{data.uniformRange.first};
|
||||
pass.SetBindGroup(0, state.uniformBindGroup, offsets.size(), offsets.data());
|
||||
pass.SetBindGroup(1, find_bind_group(data.textureBindGroup));
|
||||
pass.SetVertexBuffer(0, g_vertexBuffer, data.vertRange.first, data.vertRange.second);
|
||||
pass.Draw(4);
|
||||
}
|
||||
} // namespace aurora::gfx::movie_player
|
|
@ -5,13 +5,13 @@ struct DrawData {
|
|||
PipelineRef pipeline;
|
||||
Range vertRange;
|
||||
Range uniformRange;
|
||||
uint64_t bindGroupId;
|
||||
BindGroupRef textureBindGroup;
|
||||
};
|
||||
|
||||
struct PipelineConfig {
|
||||
// nothing
|
||||
};
|
||||
const std::array INITIAL_PIPELINES{
|
||||
static const std::array INITIAL_PIPELINES{
|
||||
PipelineConfig{},
|
||||
};
|
||||
|
||||
|
@ -22,8 +22,20 @@ struct State {
|
|||
wgpu::BindGroupLayout textureLayout;
|
||||
wgpu::Sampler sampler;
|
||||
wgpu::PipelineLayout pipelineLayout;
|
||||
// Transient state
|
||||
std::unordered_map<uint64_t, wgpu::BindGroup> textureBindGroups;
|
||||
std::vector<uint64_t> frameUsedTextures;
|
||||
};
|
||||
|
||||
struct Vert {
|
||||
Vec3<float> pos;
|
||||
Vec2<float> uv;
|
||||
};
|
||||
struct Uniform {
|
||||
zeus::CMatrix4f xf;
|
||||
zeus::CColor color;
|
||||
};
|
||||
|
||||
State construct_state();
|
||||
wgpu::RenderPipeline create_pipeline(const State& state, [[maybe_unused]] PipelineConfig config);
|
||||
DrawData make_draw_data(const State& state, const TextureHandle& tex_y, const TextureHandle& tex_u,
|
||||
const TextureHandle& tex_v, const zeus::CColor& color, float h_pad, float v_pad);
|
||||
void render(const State& state, const DrawData& data, const wgpu::RenderPassEncoder& pass);
|
||||
} // namespace aurora::gfx::movie_player
|
||||
|
|
|
@ -1,8 +1,15 @@
|
|||
#include "common.hpp"
|
||||
|
||||
#include "../gpu.hpp"
|
||||
|
||||
#include <magic_enum.hpp>
|
||||
|
||||
namespace aurora::gfx {
|
||||
static logvisor::Module Log("aurora::gfx");
|
||||
|
||||
using gpu::g_device;
|
||||
using gpu::g_queue;
|
||||
|
||||
static wgpu::TextureFormat to_wgpu(TextureFormat format) {
|
||||
switch (format) {
|
||||
case TextureFormat::RGBA8:
|
||||
|
@ -77,7 +84,7 @@ TextureHandle new_static_texture_2d(uint32_t width, uint32_t height, uint32_t mi
|
|||
.bytesPerRow = bytesPerRow,
|
||||
.rowsPerImage = heightBlocks,
|
||||
};
|
||||
g_Queue.WriteTexture(&dstView, data.data() + offset, dataSize, &dataLayout, &physicalSize);
|
||||
g_queue.WriteTexture(&dstView, data.data() + offset, dataSize, &dataLayout, &physicalSize);
|
||||
offset += dataSize;
|
||||
}
|
||||
if (offset < data.size()) {
|
||||
|
@ -108,7 +115,7 @@ TextureHandle new_dynamic_texture_2d(uint32_t width, uint32_t height, uint32_t m
|
|||
.dimension = wgpu::TextureViewDimension::e2D,
|
||||
.mipLevelCount = mips,
|
||||
};
|
||||
auto texture = g_Device.CreateTexture(&textureDescriptor);
|
||||
auto texture = g_device.CreateTexture(&textureDescriptor);
|
||||
auto textureView = texture.CreateView(&textureViewDescriptor);
|
||||
return {std::make_shared<TextureRef>(std::move(texture), std::move(textureView), size, wgpuFormat)};
|
||||
}
|
||||
|
@ -142,6 +149,6 @@ void write_texture(const TextureHandle& handle, ArrayRef<uint8_t> data) noexcept
|
|||
.bytesPerRow = bytesPerRow,
|
||||
.rowsPerImage = heightBlocks,
|
||||
};
|
||||
g_Queue.WriteTexture(&dstView, data.data(), dataSize, &dataLayout, &ref.size);
|
||||
g_queue.WriteTexture(&dstView, data.data(), dataSize, &dataLayout, &ref.size);
|
||||
}
|
||||
} // namespace aurora::gfx
|
||||
|
|
|
@ -0,0 +1,208 @@
|
|||
#include "gpu.hpp"
|
||||
|
||||
#include <dawn/native/DawnNative.h>
|
||||
#include <dawn/webgpu_cpp.h>
|
||||
#include <logvisor/logvisor.hpp>
|
||||
#include <magic_enum.hpp>
|
||||
#include <SDL.h>
|
||||
#include <memory>
|
||||
|
||||
#include "dawn/BackendBinding.hpp"
|
||||
|
||||
// TODO HACK: dawn doesn't expose device toggles
|
||||
#include "../extern/dawn/src/dawn/native/Toggles.h"
|
||||
namespace dawn::native {
|
||||
class DeviceBase {
|
||||
public:
|
||||
void SetToggle(Toggle toggle, bool isEnabled);
|
||||
};
|
||||
} // namespace dawn::native
|
||||
|
||||
namespace aurora::gpu {
|
||||
static logvisor::Module Log("aurora::gpu");
|
||||
|
||||
wgpu::Device g_device;
|
||||
wgpu::Queue g_queue;
|
||||
wgpu::SwapChain g_swapChain;
|
||||
wgpu::BackendType g_backendType;
|
||||
GraphicsConfig g_graphicsConfig;
|
||||
TextureWithSampler g_frameBuffer;
|
||||
TextureWithSampler g_frameBufferResolved;
|
||||
TextureWithSampler g_depthBuffer;
|
||||
|
||||
static std::unique_ptr<dawn::native::Instance> g_Instance;
|
||||
static dawn::native::Adapter g_Adapter;
|
||||
static wgpu::AdapterProperties g_AdapterProperties;
|
||||
static std::unique_ptr<utils::BackendBinding> g_BackendBinding;
|
||||
|
||||
static TextureWithSampler create_render_texture(bool multisampled) {
|
||||
const auto size = wgpu::Extent3D{
|
||||
.width = g_graphicsConfig.width,
|
||||
.height = g_graphicsConfig.height,
|
||||
};
|
||||
const auto format = g_graphicsConfig.colorFormat;
|
||||
uint32_t sampleCount = 1;
|
||||
if (multisampled) {
|
||||
sampleCount = g_graphicsConfig.msaaSamples;
|
||||
}
|
||||
const auto textureDescriptor = wgpu::TextureDescriptor{
|
||||
.label = "Render texture",
|
||||
.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding,
|
||||
.size = size,
|
||||
.format = format,
|
||||
.sampleCount = sampleCount,
|
||||
};
|
||||
auto texture = g_device.CreateTexture(&textureDescriptor);
|
||||
|
||||
const auto viewDescriptor = wgpu::TextureViewDescriptor{};
|
||||
auto view = texture.CreateView(&viewDescriptor);
|
||||
|
||||
const auto samplerDescriptor = wgpu::SamplerDescriptor{
|
||||
.label = "Render sampler",
|
||||
.magFilter = wgpu::FilterMode::Linear,
|
||||
.minFilter = wgpu::FilterMode::Linear,
|
||||
.mipmapFilter = wgpu::FilterMode::Linear,
|
||||
};
|
||||
auto sampler = g_device.CreateSampler(&samplerDescriptor);
|
||||
|
||||
return {
|
||||
.texture = std::move(texture),
|
||||
.view = std::move(view),
|
||||
.size = size,
|
||||
.format = format,
|
||||
.sampler = std::move(sampler),
|
||||
};
|
||||
}
|
||||
|
||||
static TextureWithSampler create_depth_texture() {
|
||||
const auto size = wgpu::Extent3D{
|
||||
.width = g_graphicsConfig.width,
|
||||
.height = g_graphicsConfig.height,
|
||||
};
|
||||
const auto format = g_graphicsConfig.depthFormat;
|
||||
const auto textureDescriptor = wgpu::TextureDescriptor{
|
||||
.label = "Depth texture",
|
||||
.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding,
|
||||
.size = size,
|
||||
.format = format,
|
||||
.sampleCount = g_graphicsConfig.msaaSamples,
|
||||
};
|
||||
auto texture = g_device.CreateTexture(&textureDescriptor);
|
||||
|
||||
const auto viewDescriptor = wgpu::TextureViewDescriptor{};
|
||||
auto view = texture.CreateView(&viewDescriptor);
|
||||
|
||||
const auto samplerDescriptor = wgpu::SamplerDescriptor{
|
||||
.label = "Depth sampler",
|
||||
.magFilter = wgpu::FilterMode::Linear,
|
||||
.minFilter = wgpu::FilterMode::Linear,
|
||||
.mipmapFilter = wgpu::FilterMode::Linear,
|
||||
};
|
||||
auto sampler = g_device.CreateSampler(&samplerDescriptor);
|
||||
|
||||
return {
|
||||
.texture = std::move(texture),
|
||||
.view = std::move(view),
|
||||
.size = size,
|
||||
.format = format,
|
||||
.sampler = std::move(sampler),
|
||||
};
|
||||
}
|
||||
|
||||
static void error_callback(WGPUErrorType type, char const* message, void* userdata) {
|
||||
Log.report(logvisor::Error, FMT_STRING("Dawn error {}: {}"),
|
||||
magic_enum::enum_name(static_cast<wgpu::ErrorType>(type)), message);
|
||||
}
|
||||
|
||||
void initialize(SDL_Window* window) {
|
||||
Log.report(logvisor::Info, FMT_STRING("Creating Dawn instance"));
|
||||
g_Instance = std::make_unique<dawn::native::Instance>();
|
||||
g_Instance->EnableBackendValidation(true);
|
||||
utils::DiscoverAdapter(g_Instance.get(), window, preferredBackendType);
|
||||
|
||||
{
|
||||
std::vector<dawn::native::Adapter> adapters = g_Instance->GetAdapters();
|
||||
auto adapterIt = std::find_if(adapters.begin(), adapters.end(), [](const dawn::native::Adapter adapter) -> bool {
|
||||
wgpu::AdapterProperties properties;
|
||||
adapter.GetProperties(&properties);
|
||||
return properties.backendType == preferredBackendType;
|
||||
});
|
||||
if (adapterIt == adapters.end()) {
|
||||
Log.report(logvisor::Fatal, FMT_STRING("Failed to find usable graphics backend"));
|
||||
}
|
||||
g_Adapter = *adapterIt;
|
||||
}
|
||||
g_Adapter.GetProperties(&g_AdapterProperties);
|
||||
g_backendType = g_AdapterProperties.backendType;
|
||||
const auto backendName = magic_enum::enum_name(g_backendType);
|
||||
Log.report(logvisor::Info, FMT_STRING("Using {} graphics backend"), backendName);
|
||||
|
||||
{
|
||||
const std::array<wgpu::FeatureName, 1> requiredFeatures{
|
||||
wgpu::FeatureName::TextureCompressionBC,
|
||||
};
|
||||
const auto deviceDescriptor = wgpu::DeviceDescriptor{
|
||||
.requiredFeaturesCount = requiredFeatures.size(),
|
||||
.requiredFeatures = requiredFeatures.data(),
|
||||
};
|
||||
g_device = wgpu::Device::Acquire(g_Adapter.CreateDevice(&deviceDescriptor));
|
||||
g_device.SetUncapturedErrorCallback(&error_callback, nullptr);
|
||||
// TODO HACK: dawn doesn't expose device toggles
|
||||
static_cast<dawn::native::DeviceBase*>(static_cast<void*>(g_device.Get()))
|
||||
->SetToggle(dawn::native::Toggle::UseUserDefinedLabelsInBackend, true);
|
||||
}
|
||||
g_queue = g_device.GetQueue();
|
||||
|
||||
g_BackendBinding =
|
||||
std::unique_ptr<utils::BackendBinding>(utils::CreateBinding(g_backendType, window, g_device.Get()));
|
||||
if (!g_BackendBinding) {
|
||||
Log.report(logvisor::Fatal, FMT_STRING("Unsupported backend {}"), backendName);
|
||||
}
|
||||
|
||||
auto swapChainFormat = static_cast<wgpu::TextureFormat>(g_BackendBinding->GetPreferredSwapChainTextureFormat());
|
||||
if (swapChainFormat == wgpu::TextureFormat::RGBA8UnormSrgb) {
|
||||
swapChainFormat = wgpu::TextureFormat::RGBA8Unorm;
|
||||
} else if (swapChainFormat == wgpu::TextureFormat::BGRA8UnormSrgb) {
|
||||
swapChainFormat = wgpu::TextureFormat::BGRA8Unorm;
|
||||
}
|
||||
Log.report(logvisor::Info, FMT_STRING("Using swapchain swapChainFormat {}"), magic_enum::enum_name(swapChainFormat));
|
||||
{
|
||||
const auto descriptor = wgpu::SwapChainDescriptor{
|
||||
.format = swapChainFormat,
|
||||
.implementation = g_BackendBinding->GetSwapChainImplementation(),
|
||||
};
|
||||
g_swapChain = g_device.CreateSwapChain(nullptr, &descriptor);
|
||||
}
|
||||
{
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
SDL_GetWindowSize(window, &width, &height);
|
||||
g_graphicsConfig = GraphicsConfig{
|
||||
.width = static_cast<uint32_t>(width),
|
||||
.height = static_cast<uint32_t>(height),
|
||||
.colorFormat = swapChainFormat,
|
||||
.depthFormat = wgpu::TextureFormat::Depth32Float,
|
||||
.msaaSamples = 1, // TODO 4
|
||||
.textureAnistropy = 16,
|
||||
};
|
||||
resize_swapchain(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
wgpuSwapChainRelease(g_swapChain.Release());
|
||||
wgpuQueueRelease(g_queue.Release());
|
||||
g_BackendBinding.reset();
|
||||
wgpuDeviceRelease(g_device.Release());
|
||||
g_Instance.reset();
|
||||
}
|
||||
|
||||
void resize_swapchain(uint32_t width, uint32_t height) {
|
||||
g_graphicsConfig.width = width;
|
||||
g_graphicsConfig.height = height;
|
||||
g_swapChain.Configure(g_graphicsConfig.colorFormat, wgpu::TextureUsage::RenderAttachment, width, height);
|
||||
g_frameBuffer = create_render_texture(true);
|
||||
g_frameBufferResolved = create_render_texture(false);
|
||||
g_depthBuffer = create_depth_texture();
|
||||
}
|
||||
} // namespace aurora::gpu
|
|
@ -0,0 +1,131 @@
|
|||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <dawn/webgpu_cpp.h>
|
||||
|
||||
struct SDL_Window;
|
||||
|
||||
namespace aurora::gpu {
|
||||
struct GraphicsConfig {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
wgpu::TextureFormat colorFormat;
|
||||
wgpu::TextureFormat depthFormat;
|
||||
uint32_t msaaSamples;
|
||||
uint8_t textureAnistropy;
|
||||
};
|
||||
struct TextureWithSampler {
|
||||
wgpu::Texture texture;
|
||||
wgpu::TextureView view;
|
||||
wgpu::Extent3D size;
|
||||
wgpu::TextureFormat format;
|
||||
wgpu::Sampler sampler;
|
||||
};
|
||||
|
||||
#ifdef DAWN_ENABLE_BACKEND_VULKAN
|
||||
static const wgpu::BackendType preferredBackendType = wgpu::BackendType::Vulkan;
|
||||
#elif DAWN_ENABLE_BACKEND_METAL
|
||||
static const wgpu::BackendType preferredBackendType = wgpu::BackendType::Metal;
|
||||
#else
|
||||
static const wgpu::BackendType preferredBackendType = wgpu::BackendType::OpenGL;
|
||||
#endif
|
||||
extern wgpu::Device g_device;
|
||||
extern wgpu::Queue g_queue;
|
||||
extern wgpu::SwapChain g_swapChain;
|
||||
extern wgpu::BackendType g_backendType;
|
||||
extern GraphicsConfig g_graphicsConfig;
|
||||
extern TextureWithSampler g_frameBuffer;
|
||||
extern TextureWithSampler g_frameBufferResolved;
|
||||
extern TextureWithSampler g_depthBuffer;
|
||||
|
||||
void initialize(SDL_Window* window);
|
||||
void shutdown();
|
||||
void resize_swapchain(uint32_t width, uint32_t height);
|
||||
} // namespace aurora::gpu
|
||||
|
||||
namespace aurora::gpu::utils {
|
||||
template <auto N>
|
||||
static consteval std::array<wgpu::VertexAttribute, N>
|
||||
make_vertex_attributes(std::array<wgpu::VertexFormat, N> formats) {
|
||||
std::array<wgpu::VertexAttribute, N> attributes{};
|
||||
uint64_t offset = 0;
|
||||
for (uint32_t i = 0; i < N; ++i) {
|
||||
auto format = formats[i];
|
||||
attributes[i] = wgpu::VertexAttribute{
|
||||
.format = format,
|
||||
.offset = offset,
|
||||
.shaderLocation = i,
|
||||
};
|
||||
switch (format) {
|
||||
case wgpu::VertexFormat::Uint8x2:
|
||||
case wgpu::VertexFormat::Sint8x2:
|
||||
case wgpu::VertexFormat::Unorm8x2:
|
||||
case wgpu::VertexFormat::Snorm8x2:
|
||||
offset += 2;
|
||||
break;
|
||||
case wgpu::VertexFormat::Uint8x4:
|
||||
case wgpu::VertexFormat::Sint8x4:
|
||||
case wgpu::VertexFormat::Unorm8x4:
|
||||
case wgpu::VertexFormat::Snorm8x4:
|
||||
case wgpu::VertexFormat::Uint16x2:
|
||||
case wgpu::VertexFormat::Sint16x2:
|
||||
case wgpu::VertexFormat::Unorm16x2:
|
||||
case wgpu::VertexFormat::Snorm16x2:
|
||||
case wgpu::VertexFormat::Float16x2:
|
||||
case wgpu::VertexFormat::Float32:
|
||||
case wgpu::VertexFormat::Uint32:
|
||||
case wgpu::VertexFormat::Sint32:
|
||||
offset += 4;
|
||||
break;
|
||||
case wgpu::VertexFormat::Uint16x4:
|
||||
case wgpu::VertexFormat::Sint16x4:
|
||||
case wgpu::VertexFormat::Unorm16x4:
|
||||
case wgpu::VertexFormat::Snorm16x4:
|
||||
case wgpu::VertexFormat::Float16x4:
|
||||
case wgpu::VertexFormat::Float32x2:
|
||||
case wgpu::VertexFormat::Uint32x2:
|
||||
case wgpu::VertexFormat::Sint32x2:
|
||||
offset += 8;
|
||||
break;
|
||||
case wgpu::VertexFormat::Float32x3:
|
||||
case wgpu::VertexFormat::Uint32x3:
|
||||
case wgpu::VertexFormat::Sint32x3:
|
||||
offset += 12;
|
||||
break;
|
||||
case wgpu::VertexFormat::Float32x4:
|
||||
case wgpu::VertexFormat::Uint32x4:
|
||||
case wgpu::VertexFormat::Sint32x4:
|
||||
offset += 16;
|
||||
break;
|
||||
case wgpu::VertexFormat::Undefined:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return attributes;
|
||||
}
|
||||
|
||||
template <auto N>
|
||||
static inline wgpu::VertexBufferLayout
|
||||
make_vertex_buffer_layout(uint64_t arrayStride, const std::array<wgpu::VertexAttribute, N>& attributes,
|
||||
wgpu::VertexStepMode stepMode = wgpu::VertexStepMode::Vertex) {
|
||||
return {
|
||||
.arrayStride = arrayStride,
|
||||
.stepMode = stepMode,
|
||||
.attributeCount = static_cast<uint32_t>(attributes.size()),
|
||||
.attributes = attributes.data(),
|
||||
};
|
||||
}
|
||||
|
||||
template <auto N>
|
||||
static inline wgpu::VertexState make_vertex_state(const wgpu::ShaderModule& module,
|
||||
const std::array<wgpu::VertexBufferLayout, N>& buffers,
|
||||
const char* entryPoint = "vs_main") {
|
||||
return {
|
||||
.module = module,
|
||||
.entryPoint = entryPoint,
|
||||
.bufferCount = static_cast<uint32_t>(buffers.size()),
|
||||
.buffers = buffers.data(),
|
||||
};
|
||||
}
|
||||
} // namespace aurora::gpu::utils
|
|
@ -1,13 +1,49 @@
|
|||
#include <aurora/imgui.hpp>
|
||||
#include "imgui.hpp"
|
||||
|
||||
#include "gpu.hpp"
|
||||
|
||||
#include <aurora/imgui.hpp>
|
||||
#include <backends/imgui_impl_sdl.h>
|
||||
#include <backends/imgui_impl_wgpu.h>
|
||||
#include <dawn/webgpu_cpp.h>
|
||||
|
||||
namespace aurora {
|
||||
extern wgpu::Device g_Device;
|
||||
extern wgpu::Queue g_Queue;
|
||||
} // namespace aurora
|
||||
|
||||
namespace aurora::imgui {
|
||||
using gpu::g_device;
|
||||
using gpu::g_queue;
|
||||
|
||||
void create_context() noexcept {
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.IniFilename = nullptr;
|
||||
}
|
||||
|
||||
void initialize(SDL_Window* window) noexcept {
|
||||
// this just passes through to ImGui_ImplSDL2_Init (private)
|
||||
// may need to change in the future
|
||||
ImGui_ImplSDL2_InitForMetal(window);
|
||||
ImGui_ImplWGPU_Init(g_device.Get(), 1, static_cast<WGPUTextureFormat>(gpu::g_graphicsConfig.colorFormat));
|
||||
}
|
||||
|
||||
void shutdown() noexcept {
|
||||
ImGui_ImplWGPU_Shutdown();
|
||||
ImGui_ImplSDL2_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
}
|
||||
|
||||
void process_event(const SDL_Event& event) noexcept { ImGui_ImplSDL2_ProcessEvent(&event); }
|
||||
|
||||
void new_frame() noexcept {
|
||||
ImGui_ImplWGPU_NewFrame();
|
||||
ImGui_ImplSDL2_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
}
|
||||
|
||||
void render(const wgpu::RenderPassEncoder& pass) noexcept {
|
||||
ImGui::Render();
|
||||
ImGui_ImplWGPU_RenderDrawData(ImGui::GetDrawData(), pass.Get());
|
||||
}
|
||||
|
||||
ImTextureID add_texture(uint32_t width, uint32_t height, ArrayRef<uint8_t> data) noexcept {
|
||||
const auto size = wgpu::Extent3D{
|
||||
.width = width,
|
||||
|
@ -26,7 +62,7 @@ ImTextureID add_texture(uint32_t width, uint32_t height, ArrayRef<uint8_t> data)
|
|||
.mipLevelCount = 1,
|
||||
.arrayLayerCount = 1,
|
||||
};
|
||||
auto texture = g_Device.CreateTexture(&textureDescriptor);
|
||||
auto texture = g_device.CreateTexture(&textureDescriptor);
|
||||
auto textureView = texture.CreateView(&textureViewDescriptor);
|
||||
{
|
||||
const auto dstView = wgpu::ImageCopyTexture{
|
||||
|
@ -36,7 +72,7 @@ ImTextureID add_texture(uint32_t width, uint32_t height, ArrayRef<uint8_t> data)
|
|||
.bytesPerRow = 4 * width,
|
||||
.rowsPerImage = height,
|
||||
};
|
||||
g_Queue.WriteTexture(&dstView, data.data(), data.size(), &dataLayout, &size);
|
||||
g_queue.WriteTexture(&dstView, data.data(), data.size(), &dataLayout, &size);
|
||||
}
|
||||
texture.Release(); // leak some memory!
|
||||
return textureView.Release();
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
struct SDL_Window;
|
||||
union SDL_Event;
|
||||
|
||||
namespace wgpu {
|
||||
class RenderPassEncoder;
|
||||
} // namespace wgpu
|
||||
|
||||
namespace aurora::imgui {
|
||||
void create_context() noexcept;
|
||||
void initialize(SDL_Window* window) noexcept;
|
||||
void shutdown() noexcept;
|
||||
|
||||
void process_event(const SDL_Event& event) noexcept;
|
||||
void new_frame() noexcept;
|
||||
void render(const wgpu::RenderPassEncoder& pass) noexcept;
|
||||
} // namespace aurora::imgui
|
|
@ -1 +1 @@
|
|||
Subproject commit 5c8f8d031166765d2f1e2ac2de27df6d3691c05a
|
||||
Subproject commit dca527be1b77e38047054196fd6a96e8abdae131
|
|
@ -23,203 +23,4 @@ struct Icon {
|
|||
uint32_t height;
|
||||
};
|
||||
Icon GetIcon();
|
||||
|
||||
enum class KeyCode {
|
||||
/// The '1' key over the letters.
|
||||
Key1,
|
||||
/// The '2' key over the letters.
|
||||
Key2,
|
||||
/// The '3' key over the letters.
|
||||
Key3,
|
||||
/// The '4' key over the letters.
|
||||
Key4,
|
||||
/// The '5' key over the letters.
|
||||
Key5,
|
||||
/// The '6' key over the letters.
|
||||
Key6,
|
||||
/// The '7' key over the letters.
|
||||
Key7,
|
||||
/// The '8' key over the letters.
|
||||
Key8,
|
||||
/// The '9' key over the letters.
|
||||
Key9,
|
||||
/// The '0' key over the 'O' and 'P' keys.
|
||||
Key0,
|
||||
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
D,
|
||||
E,
|
||||
F,
|
||||
G,
|
||||
H,
|
||||
I,
|
||||
J,
|
||||
K,
|
||||
L,
|
||||
M,
|
||||
N,
|
||||
O,
|
||||
P,
|
||||
Q,
|
||||
R,
|
||||
S,
|
||||
T,
|
||||
U,
|
||||
V,
|
||||
W,
|
||||
X,
|
||||
Y,
|
||||
Z,
|
||||
|
||||
/// The Escape key, next to F1.
|
||||
Escape,
|
||||
|
||||
F1,
|
||||
F2,
|
||||
F3,
|
||||
F4,
|
||||
F5,
|
||||
F6,
|
||||
F7,
|
||||
F8,
|
||||
F9,
|
||||
F10,
|
||||
F11,
|
||||
F12,
|
||||
F13,
|
||||
F14,
|
||||
F15,
|
||||
F16,
|
||||
F17,
|
||||
F18,
|
||||
F19,
|
||||
F20,
|
||||
F21,
|
||||
F22,
|
||||
F23,
|
||||
F24,
|
||||
|
||||
/// Print Screen/SysRq.
|
||||
Snapshot,
|
||||
/// Scroll Lock.
|
||||
Scroll,
|
||||
/// Pause/Break key, next to Scroll lock.
|
||||
Pause,
|
||||
|
||||
/// `Insert`, next to Backspace.
|
||||
Insert,
|
||||
Home,
|
||||
Delete,
|
||||
End,
|
||||
PageDown,
|
||||
PageUp,
|
||||
|
||||
Left,
|
||||
Up,
|
||||
Right,
|
||||
Down,
|
||||
|
||||
/// The Backspace key, right over Enter.
|
||||
// TODO: rename
|
||||
Back,
|
||||
/// The Enter key.
|
||||
Return,
|
||||
/// The space bar.
|
||||
Space,
|
||||
|
||||
/// The "Compose" key on Linux.
|
||||
Compose,
|
||||
|
||||
Caret,
|
||||
|
||||
Numlock,
|
||||
Numpad0,
|
||||
Numpad1,
|
||||
Numpad2,
|
||||
Numpad3,
|
||||
Numpad4,
|
||||
Numpad5,
|
||||
Numpad6,
|
||||
Numpad7,
|
||||
Numpad8,
|
||||
Numpad9,
|
||||
NumpadAdd,
|
||||
NumpadDivide,
|
||||
NumpadDecimal,
|
||||
NumpadComma,
|
||||
NumpadEnter,
|
||||
NumpadEquals,
|
||||
NumpadMultiply,
|
||||
NumpadSubtract,
|
||||
|
||||
AbntC1,
|
||||
AbntC2,
|
||||
Apostrophe,
|
||||
Apps,
|
||||
Asterisk,
|
||||
At,
|
||||
Ax,
|
||||
Backslash,
|
||||
Calculator,
|
||||
Capital,
|
||||
Colon,
|
||||
Comma,
|
||||
Convert,
|
||||
Equals,
|
||||
Grave,
|
||||
Kana,
|
||||
Kanji,
|
||||
LAlt,
|
||||
LBracket,
|
||||
LControl,
|
||||
LShift,
|
||||
LWin,
|
||||
Mail,
|
||||
MediaSelect,
|
||||
MediaStop,
|
||||
Minus,
|
||||
Mute,
|
||||
MyComputer,
|
||||
// also called "Next"
|
||||
NavigateForward,
|
||||
// also called "Prior"
|
||||
NavigateBackward,
|
||||
NextTrack,
|
||||
NoConvert,
|
||||
OEM102,
|
||||
Period,
|
||||
PlayPause,
|
||||
Plus,
|
||||
Power,
|
||||
PrevTrack,
|
||||
RAlt,
|
||||
RBracket,
|
||||
RControl,
|
||||
RShift,
|
||||
RWin,
|
||||
Semicolon,
|
||||
Slash,
|
||||
Sleep,
|
||||
Stop,
|
||||
Sysrq,
|
||||
Tab,
|
||||
Underline,
|
||||
Unlabeled,
|
||||
VolumeDown,
|
||||
VolumeUp,
|
||||
Wake,
|
||||
WebBack,
|
||||
WebFavorites,
|
||||
WebForward,
|
||||
WebHome,
|
||||
WebRefresh,
|
||||
WebSearch,
|
||||
WebStop,
|
||||
Yen,
|
||||
Copy,
|
||||
Paste,
|
||||
Cut,
|
||||
};
|
||||
} // namespace metaforce
|
||||
|
|
Loading…
Reference in New Issue