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 "Runtime/CGameAllocator.hpp"
|
||||||
|
|
||||||
|
#include <logvisor/logvisor.hpp>
|
||||||
|
|
||||||
namespace metaforce {
|
namespace metaforce {
|
||||||
logvisor::Module AllocLog("metaforce::CGameAllocator");
|
static logvisor::Module Log("metaforce::CGameAllocator");
|
||||||
|
|
||||||
#pragma GCC diagnostic ignored "-Wclass-memaccess"
|
#pragma GCC diagnostic ignored "-Wclass-memaccess"
|
||||||
|
|
||||||
|
@ -44,7 +46,7 @@ u8* CGameAllocator::Alloc(size_t len) {
|
||||||
void CGameAllocator::Free(u8* ptr) {
|
void CGameAllocator::Free(u8* ptr) {
|
||||||
SChunkDescription* info = reinterpret_cast<SChunkDescription*>(ptr - sizeof(SChunkDescription));
|
SChunkDescription* info = reinterpret_cast<SChunkDescription*>(ptr - sizeof(SChunkDescription));
|
||||||
if (info->magic != 0xE8E8E8E8 || info->sentinal != 0xEFEFEFEF) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
|
@ -1166,18 +1166,18 @@ void ImGuiConsole::PreUpdate() {
|
||||||
g_StateManager->SetActiveRandomToDefault();
|
g_StateManager->SetActiveRandomToDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::IsKeyReleased(int(KeyCode::Grave))) {
|
if (ImGui::IsKeyReleased(ImGuiKey_GraveAccent)) {
|
||||||
m_isVisible ^= 1;
|
m_isVisible ^= 1;
|
||||||
}
|
}
|
||||||
if (m_stepFrame) {
|
if (m_stepFrame) {
|
||||||
g_Main->SetPaused(true);
|
g_Main->SetPaused(true);
|
||||||
m_stepFrame = false;
|
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);
|
g_Main->SetPaused(false);
|
||||||
m_stepFrame = true;
|
m_stepFrame = true;
|
||||||
}
|
}
|
||||||
if (ImGui::IsKeyReleased(int(KeyCode::F5))) {
|
if (ImGui::IsKeyReleased(ImGuiKey_F5)) {
|
||||||
m_paused ^= 1;
|
m_paused ^= 1;
|
||||||
g_Main->SetPaused(m_paused);
|
g_Main->SetPaused(m_paused);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "Runtime/World/CPathFindArea.hpp"
|
#include "Runtime/World/CPathFindArea.hpp"
|
||||||
|
|
||||||
|
#include <logvisor/logvisor.hpp>
|
||||||
|
|
||||||
#include "Runtime/CToken.hpp"
|
#include "Runtime/CToken.hpp"
|
||||||
#include "Runtime/IVParamObj.hpp"
|
#include "Runtime/IVParamObj.hpp"
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,9 @@ if (NOT MSVC)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
add_subdirectory(../extern/dawn dawn EXCLUDE_FROM_ALL)
|
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)
|
if (NOT MSVC)
|
||||||
target_compile_options(SPIRV-Tools-static PRIVATE -Wno-implicit-fallthrough)
|
target_compile_options(SPIRV-Tools-static PRIVATE -Wno-implicit-fallthrough)
|
||||||
target_compile_options(SPIRV-Tools-opt PRIVATE -Wno-implicit-fallthrough)
|
target_compile_options(SPIRV-Tools-opt PRIVATE -Wno-implicit-fallthrough)
|
||||||
|
@ -11,6 +14,7 @@ endif ()
|
||||||
|
|
||||||
add_library(aurora STATIC
|
add_library(aurora STATIC
|
||||||
lib/aurora.cpp
|
lib/aurora.cpp
|
||||||
|
lib/gpu.cpp
|
||||||
lib/imgui.cpp
|
lib/imgui.cpp
|
||||||
lib/dawn/BackendBinding.cpp
|
lib/dawn/BackendBinding.cpp
|
||||||
lib/gfx/common.cpp
|
lib/gfx/common.cpp
|
||||||
|
|
|
@ -1,65 +1,31 @@
|
||||||
#include <aurora/aurora.hpp>
|
#include <aurora/aurora.hpp>
|
||||||
|
|
||||||
|
#include "gfx/common.hpp"
|
||||||
|
#include "gpu.hpp"
|
||||||
|
#include "imgui.hpp"
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <dawn/native/DawnNative.h>
|
#include <imgui.h>
|
||||||
// TODO HACK: dawn doesn't expose device toggles
|
|
||||||
#include "../extern/dawn/src/dawn/native/Toggles.h"
|
|
||||||
#include <dawn/webgpu_cpp.h>
|
|
||||||
#include <logvisor/logvisor.hpp>
|
#include <logvisor/logvisor.hpp>
|
||||||
#include <magic_enum.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 {
|
namespace aurora {
|
||||||
// TODO: Move global state to a class/struct?
|
|
||||||
static logvisor::Module Log("aurora");
|
static logvisor::Module Log("aurora");
|
||||||
|
|
||||||
|
// TODO: Move global state to a class/struct?
|
||||||
static std::unique_ptr<AppDelegate> g_AppDelegate;
|
static std::unique_ptr<AppDelegate> g_AppDelegate;
|
||||||
static std::vector<std::string> g_Args;
|
static std::vector<std::string> g_Args;
|
||||||
|
|
||||||
// SDL
|
// SDL
|
||||||
static SDL_Window* g_Window;
|
static SDL_Window* g_Window;
|
||||||
|
|
||||||
// Dawn / WebGPU
|
// GPU
|
||||||
#ifdef DAWN_ENABLE_BACKEND_VULKAN
|
using gpu::g_depthBuffer;
|
||||||
static wgpu::BackendType preferredBackendType = wgpu::BackendType::Vulkan;
|
using gpu::g_device;
|
||||||
#elif DAWN_ENABLE_BACKEND_METAL
|
using gpu::g_frameBuffer;
|
||||||
static wgpu::BackendType preferredBackendType = wgpu::BackendType::Metal;
|
using gpu::g_frameBufferResolved;
|
||||||
#else
|
using gpu::g_queue;
|
||||||
static wgpu::BackendType preferredBackendType = wgpu::BackendType::OpenGL;
|
using gpu::g_swapChain;
|
||||||
#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;
|
|
||||||
|
|
||||||
static void set_window_icon(Icon icon) noexcept {
|
static void set_window_icon(Icon icon) noexcept {
|
||||||
SDL_Surface* iconSurface = SDL_CreateRGBSurfaceFrom(icon.data.get(), icon.width, icon.height, 32, 4 * icon.width,
|
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 {
|
static bool poll_events() noexcept {
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
while (SDL_PollEvent(&event) != 0) {
|
while (SDL_PollEvent(&event) != 0) {
|
||||||
ImGui_ImplSDL2_ProcessEvent(&event);
|
imgui::process_event(event);
|
||||||
|
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case SDL_WINDOWEVENT: {
|
case SDL_WINDOWEVENT: {
|
||||||
|
@ -98,8 +64,7 @@ static bool poll_events() noexcept {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SDL_WINDOWEVENT_RESIZED: {
|
case SDL_WINDOWEVENT_RESIZED: {
|
||||||
auto format = static_cast<wgpu::TextureFormat>(g_BackendBinding->GetPreferredSwapChainTextureFormat());
|
gpu::resize_swapchain(event.window.data1, event.window.data2);
|
||||||
g_SwapChain.Configure(format, wgpu::TextureUsage::RenderAttachment, event.window.data1, event.window.data2);
|
|
||||||
g_AppDelegate->onAppWindowResized(
|
g_AppDelegate->onAppWindowResized(
|
||||||
{static_cast<uint32_t>(event.window.data1), static_cast<uint32_t>(event.window.data2)});
|
{static_cast<uint32_t>(event.window.data1), static_cast<uint32_t>(event.window.data2)});
|
||||||
break;
|
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;
|
Uint32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE;
|
||||||
switch (preferredBackendType) {
|
switch (gpu::preferredBackendType) {
|
||||||
#ifdef DAWN_ENABLE_BACKEND_VULKAN
|
#ifdef DAWN_ENABLE_BACKEND_VULKAN
|
||||||
case wgpu::BackendType::Vulkan:
|
case wgpu::BackendType::Vulkan:
|
||||||
flags |= SDL_WINDOW_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));
|
set_window_icon(std::move(icon));
|
||||||
|
|
||||||
Log.report(logvisor::Info, FMT_STRING("Creating Dawn instance"));
|
gpu::initialize(g_Window);
|
||||||
g_Instance = std::make_unique<dawn::native::Instance>();
|
gfx::construct_state();
|
||||||
utils::DiscoverAdapter(g_Instance.get(), g_Window, preferredBackendType);
|
|
||||||
|
|
||||||
{
|
imgui::create_context();
|
||||||
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;
|
|
||||||
g_AppDelegate->onImGuiInit(1.f); // TODO scale
|
g_AppDelegate->onImGuiInit(1.f); // TODO scale
|
||||||
ImGui_ImplSDL2_InitForMetal(g_Window);
|
imgui::initialize(g_Window);
|
||||||
ImGui_ImplWGPU_Init(g_Device.Get(), 1, g_BackendBinding->GetPreferredSwapChainTextureFormat());
|
|
||||||
g_AppDelegate->onImGuiAddTextures();
|
g_AppDelegate->onImGuiAddTextures();
|
||||||
|
|
||||||
g_AppDelegate->onAppLaunched();
|
g_AppDelegate->onAppLaunched();
|
||||||
g_AppDelegate->onAppWindowResized(get_window_size());
|
g_AppDelegate->onAppWindowResized(get_window_size());
|
||||||
|
|
||||||
while (poll_events()) {
|
while (poll_events()) {
|
||||||
ImGui_ImplWGPU_NewFrame();
|
imgui::new_frame();
|
||||||
ImGui_ImplSDL2_NewFrame();
|
if (!g_AppDelegate->onAppIdle(ImGui::GetIO().DeltaTime)) {
|
||||||
ImGui::NewFrame();
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
g_AppDelegate->onAppIdle(ImGui::GetIO().DeltaTime);
|
const wgpu::TextureView view = g_swapChain.GetCurrentTextureView();
|
||||||
|
|
||||||
const wgpu::TextureView view = g_SwapChain.GetCurrentTextureView();
|
|
||||||
g_AppDelegate->onAppDraw();
|
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,
|
.view = view,
|
||||||
|
// .resolveTarget = g_frameBufferResolved.view,
|
||||||
.loadOp = wgpu::LoadOp::Clear,
|
.loadOp = wgpu::LoadOp::Clear,
|
||||||
.storeOp = wgpu::StoreOp::Store,
|
.storeOp = wgpu::StoreOp::Store,
|
||||||
.clearColor = {0.f, 0.f, 0.f, 0.f},
|
.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{
|
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(),
|
.colorAttachmentCount = attachments.size(),
|
||||||
.colorAttachments = attachments.data(),
|
.colorAttachments = attachments.data(),
|
||||||
};
|
};
|
||||||
auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
|
auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
|
||||||
ImGui_ImplWGPU_RenderDrawData(ImGui::GetDrawData(), pass.Get());
|
imgui::render(pass);
|
||||||
pass.End();
|
pass.End();
|
||||||
}
|
}
|
||||||
const auto buffer = encoder.Finish();
|
const auto buffer = encoder.Finish();
|
||||||
g_Queue.Submit(1, &buffer);
|
g_queue.Submit(1, &buffer);
|
||||||
g_SwapChain.Present();
|
g_swapChain.Present();
|
||||||
|
|
||||||
g_AppDelegate->onAppPostDraw();
|
g_AppDelegate->onAppPostDraw();
|
||||||
|
|
||||||
|
ImGui::EndFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
g_AppDelegate->onAppExiting();
|
g_AppDelegate->onAppExiting();
|
||||||
|
|
||||||
wgpuSwapChainRelease(g_SwapChain.Release());
|
imgui::shutdown();
|
||||||
wgpuQueueRelease(g_Queue.Release());
|
gpu::shutdown();
|
||||||
g_BackendBinding.reset();
|
|
||||||
wgpuDeviceRelease(g_Device.Release());
|
|
||||||
g_Instance.reset();
|
|
||||||
SDL_DestroyWindow(g_Window);
|
SDL_DestroyWindow(g_Window);
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> get_args() noexcept { return g_Args; }
|
std::vector<std::string> get_args() noexcept { return g_Args; }
|
||||||
|
|
||||||
WindowSize get_window_size() noexcept {
|
WindowSize get_window_size() noexcept {
|
||||||
int width, height;
|
int width, height;
|
||||||
SDL_GetWindowSize(g_Window, &width, &height);
|
SDL_GetWindowSize(g_Window, &width, &height);
|
||||||
return {static_cast<uint32_t>(width), static_cast<uint32_t>(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()); }
|
void set_window_title(zstring_view title) noexcept { SDL_SetWindowTitle(g_Window, title.c_str()); }
|
||||||
|
|
||||||
Backend get_backend() noexcept {
|
Backend get_backend() noexcept {
|
||||||
switch (g_AdapterProperties.backendType) {
|
switch (gpu::g_backendType) {
|
||||||
case wgpu::BackendType::WebGPU:
|
case wgpu::BackendType::WebGPU:
|
||||||
return Backend::WebGPU;
|
return Backend::WebGPU;
|
||||||
case wgpu::BackendType::D3D11:
|
case wgpu::BackendType::D3D11:
|
||||||
|
@ -374,7 +317,9 @@ Backend get_backend() noexcept {
|
||||||
return Backend::Invalid;
|
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 {
|
void set_fullscreen(bool fullscreen) noexcept {
|
||||||
auto flags = SDL_GetWindowFlags(g_Window);
|
auto flags = SDL_GetWindowFlags(g_Window);
|
||||||
if (fullscreen) {
|
if (fullscreen) {
|
||||||
|
@ -388,12 +333,15 @@ void set_fullscreen(bool fullscreen) noexcept {
|
||||||
int32_t get_controller_player_index(uint32_t which) noexcept {
|
int32_t get_controller_player_index(uint32_t which) noexcept {
|
||||||
return -1; // TODO
|
return -1; // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_controller_player_index(uint32_t which, int32_t index) noexcept {
|
void set_controller_player_index(uint32_t which, int32_t index) noexcept {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_controller_gamecube(uint32_t which) noexcept {
|
bool is_controller_gamecube(uint32_t which) noexcept {
|
||||||
return true; // TODO
|
return true; // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_controller_name(uint32_t which) noexcept {
|
std::string get_controller_name(uint32_t which) noexcept {
|
||||||
return ""; // TODO
|
return ""; // TODO
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include <dawn/native/OpenGLBackend.h>
|
#include <dawn/native/OpenGLBackend.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace aurora::utils {
|
namespace aurora::gpu::utils {
|
||||||
|
|
||||||
#if defined(DAWN_ENABLE_BACKEND_D3D12)
|
#if defined(DAWN_ENABLE_BACKEND_D3D12)
|
||||||
BackendBinding* CreateD3D12Binding(SDL_Window* window, WGPUDevice device);
|
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;
|
struct SDL_Window;
|
||||||
|
|
||||||
namespace aurora::utils {
|
namespace aurora::gpu::utils {
|
||||||
|
|
||||||
class BackendBinding {
|
class BackendBinding {
|
||||||
public:
|
public:
|
||||||
|
@ -24,4 +24,4 @@ protected:
|
||||||
void DiscoverAdapter(dawn::native::Instance* instance, SDL_Window* window, wgpu::BackendType type);
|
void DiscoverAdapter(dawn::native::Instance* instance, SDL_Window* window, wgpu::BackendType type);
|
||||||
BackendBinding* CreateBinding(wgpu::BackendType type, SDL_Window* window, WGPUDevice device);
|
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;
|
return impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace aurora::utils {
|
namespace aurora::gpu::utils {
|
||||||
class SwapChainImplMTL {
|
class SwapChainImplMTL {
|
||||||
public:
|
public:
|
||||||
using WSIContext = DawnWSIContextMetal;
|
using WSIContext = DawnWSIContextMetal;
|
||||||
|
@ -105,4 +105,4 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
BackendBinding *CreateMetalBinding(SDL_Window *window, WGPUDevice device) { return new MetalBinding(window, device); }
|
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 <SDL_video.h>
|
||||||
#include <dawn/native/OpenGLBackend.h>
|
#include <dawn/native/OpenGLBackend.h>
|
||||||
|
|
||||||
namespace aurora::utils {
|
namespace aurora::gpu::utils {
|
||||||
class OpenGLBinding : public BackendBinding {
|
class OpenGLBinding : public BackendBinding {
|
||||||
public:
|
public:
|
||||||
OpenGLBinding(SDL_Window* window, WGPUDevice device) : BackendBinding(window, device) {}
|
OpenGLBinding(SDL_Window* window, WGPUDevice device) : BackendBinding(window, device) {}
|
||||||
|
|
||||||
uint64_t GetSwapChainImplementation() override {
|
uint64_t GetSwapChainImplementation() override {
|
||||||
if (m_swapChainImpl.userData == nullptr) {
|
if (m_swapChainImpl.userData == nullptr) {
|
||||||
m_swapChainImpl = dawn::native::opengl::CreateNativeSwapChainImpl(
|
CreateSwapChainImpl();
|
||||||
m_device, [](void* userdata) { SDL_GL_SwapWindow(static_cast<SDL_Window*>(userdata)); }, m_window);
|
|
||||||
}
|
}
|
||||||
return reinterpret_cast<uint64_t>(&m_swapChainImpl);
|
return reinterpret_cast<uint64_t>(&m_swapChainImpl);
|
||||||
}
|
}
|
||||||
|
|
||||||
WGPUTextureFormat GetPreferredSwapChainTextureFormat() override {
|
WGPUTextureFormat GetPreferredSwapChainTextureFormat() override {
|
||||||
|
if (m_swapChainImpl.userData == nullptr) {
|
||||||
|
CreateSwapChainImpl();
|
||||||
|
}
|
||||||
return dawn::native::opengl::GetNativeSwapChainPreferredFormat(&m_swapChainImpl);
|
return dawn::native::opengl::GetNativeSwapChainPreferredFormat(&m_swapChainImpl);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DawnSwapChainImplementation m_swapChainImpl{};
|
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); }
|
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 <cassert>
|
||||||
#include <dawn/native/VulkanBackend.h>
|
#include <dawn/native/VulkanBackend.h>
|
||||||
|
|
||||||
namespace aurora::utils {
|
namespace aurora::gpu::utils {
|
||||||
class VulkanBinding : public BackendBinding {
|
class VulkanBinding : public BackendBinding {
|
||||||
public:
|
public:
|
||||||
VulkanBinding(SDL_Window* window, WGPUDevice device) : BackendBinding(window, device) {}
|
VulkanBinding(SDL_Window* window, WGPUDevice device) : BackendBinding(window, device) {}
|
||||||
|
|
||||||
uint64_t GetSwapChainImplementation() override {
|
uint64_t GetSwapChainImplementation() override {
|
||||||
if (m_swapChainImpl.userData == nullptr) {
|
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;
|
VkSurfaceKHR surface = VK_NULL_HANDLE;
|
||||||
if (SDL_Vulkan_CreateSurface(m_window, dawn::native::vulkan::GetInstance(m_device), &surface) != SDL_TRUE) {
|
if (SDL_Vulkan_CreateSurface(m_window, dawn::native::vulkan::GetInstance(m_device), &surface) != SDL_TRUE) {
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
m_swapChainImpl = dawn::native::vulkan::CreateNativeSwapChainImpl(m_device, surface);
|
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); }
|
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 "common.hpp"
|
||||||
|
|
||||||
#include <magic_enum.hpp>
|
#include "../gpu.hpp"
|
||||||
|
|
||||||
#include "movie_player/shader.hpp"
|
#include "movie_player/shader.hpp"
|
||||||
|
|
||||||
|
#include <logvisor/logvisor.hpp>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace aurora::gfx {
|
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 {
|
struct ShaderDrawCommand {
|
||||||
ShaderType type;
|
ShaderType type;
|
||||||
union {
|
union {
|
||||||
|
@ -45,9 +55,46 @@ zeus::CMatrix4f g_mvInv;
|
||||||
zeus::CMatrix4f g_proj;
|
zeus::CMatrix4f g_proj;
|
||||||
metaforce::CFogState g_fogState;
|
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 {
|
void update_model_view(const zeus::CMatrix4f& mv, const zeus::CMatrix4f& mv_inv) noexcept {
|
||||||
g_mv = mv;
|
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 {
|
const zeus::CRectangle& rect, float z) noexcept {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
void queue_movie_player(const TextureHandle& tex_y, const TextureHandle& tex_u, const TextureHandle& tex_v,
|
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 {
|
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
|
// 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
|
} // namespace aurora::gfx
|
||||||
|
|
|
@ -9,24 +9,103 @@
|
||||||
#include <xxh_x86dispatch.h>
|
#include <xxh_x86dispatch.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <typename T>
|
#ifndef ALIGN
|
||||||
XXH64_hash_t xxh3_hash(const T& input, XXH64_hash_t seed = 0) {
|
#define ALIGN(x, a) (((x) + ((a)-1)) & ~((a)-1))
|
||||||
return XXH3_64bits_withSeed(&input, sizeof(T), seed);
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
namespace aurora {
|
namespace aurora {
|
||||||
extern wgpu::Device g_Device;
|
static inline XXH64_hash_t xxh3_hash(const void* input, size_t len, XXH64_hash_t seed = 0) {
|
||||||
extern wgpu::Queue g_Queue;
|
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
|
||||||
|
|
||||||
namespace aurora::gfx {
|
namespace aurora::gfx {
|
||||||
static logvisor::Module Log("aurora::gfx");
|
|
||||||
|
|
||||||
extern zeus::CMatrix4f g_mv;
|
extern zeus::CMatrix4f g_mv;
|
||||||
extern zeus::CMatrix4f g_mvInv;
|
extern zeus::CMatrix4f g_mvInv;
|
||||||
extern zeus::CMatrix4f g_proj;
|
extern zeus::CMatrix4f g_proj;
|
||||||
extern metaforce::CFogState g_fogState;
|
extern metaforce::CFogState g_fogState;
|
||||||
|
|
||||||
|
extern wgpu::Buffer g_vertexBuffer;
|
||||||
|
extern wgpu::Buffer g_uniformBuffer;
|
||||||
|
extern wgpu::Buffer g_indexBuffer;
|
||||||
|
|
||||||
struct TextureRef {
|
struct TextureRef {
|
||||||
wgpu::Texture texture;
|
wgpu::Texture texture;
|
||||||
wgpu::TextureView view;
|
wgpu::TextureView view;
|
||||||
|
@ -38,11 +117,41 @@ struct TextureRef {
|
||||||
};
|
};
|
||||||
|
|
||||||
using PipelineRef = uint64_t;
|
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 {
|
enum class ShaderType {
|
||||||
Aabb,
|
Aabb,
|
||||||
TexturedQuad,
|
TexturedQuad,
|
||||||
MoviePlayer,
|
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
|
} // 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;
|
PipelineRef pipeline;
|
||||||
Range vertRange;
|
Range vertRange;
|
||||||
Range uniformRange;
|
Range uniformRange;
|
||||||
uint64_t bindGroupId;
|
BindGroupRef textureBindGroup;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PipelineConfig {
|
struct PipelineConfig {
|
||||||
// nothing
|
// nothing
|
||||||
};
|
};
|
||||||
const std::array INITIAL_PIPELINES{
|
static const std::array INITIAL_PIPELINES{
|
||||||
PipelineConfig{},
|
PipelineConfig{},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,8 +22,20 @@ struct State {
|
||||||
wgpu::BindGroupLayout textureLayout;
|
wgpu::BindGroupLayout textureLayout;
|
||||||
wgpu::Sampler sampler;
|
wgpu::Sampler sampler;
|
||||||
wgpu::PipelineLayout pipelineLayout;
|
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
|
} // namespace aurora::gfx::movie_player
|
||||||
|
|
|
@ -1,8 +1,15 @@
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
|
|
||||||
|
#include "../gpu.hpp"
|
||||||
|
|
||||||
#include <magic_enum.hpp>
|
#include <magic_enum.hpp>
|
||||||
|
|
||||||
namespace aurora::gfx {
|
namespace aurora::gfx {
|
||||||
|
static logvisor::Module Log("aurora::gfx");
|
||||||
|
|
||||||
|
using gpu::g_device;
|
||||||
|
using gpu::g_queue;
|
||||||
|
|
||||||
static wgpu::TextureFormat to_wgpu(TextureFormat format) {
|
static wgpu::TextureFormat to_wgpu(TextureFormat format) {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case TextureFormat::RGBA8:
|
case TextureFormat::RGBA8:
|
||||||
|
@ -77,7 +84,7 @@ TextureHandle new_static_texture_2d(uint32_t width, uint32_t height, uint32_t mi
|
||||||
.bytesPerRow = bytesPerRow,
|
.bytesPerRow = bytesPerRow,
|
||||||
.rowsPerImage = heightBlocks,
|
.rowsPerImage = heightBlocks,
|
||||||
};
|
};
|
||||||
g_Queue.WriteTexture(&dstView, data.data() + offset, dataSize, &dataLayout, &physicalSize);
|
g_queue.WriteTexture(&dstView, data.data() + offset, dataSize, &dataLayout, &physicalSize);
|
||||||
offset += dataSize;
|
offset += dataSize;
|
||||||
}
|
}
|
||||||
if (offset < data.size()) {
|
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,
|
.dimension = wgpu::TextureViewDimension::e2D,
|
||||||
.mipLevelCount = mips,
|
.mipLevelCount = mips,
|
||||||
};
|
};
|
||||||
auto texture = g_Device.CreateTexture(&textureDescriptor);
|
auto texture = g_device.CreateTexture(&textureDescriptor);
|
||||||
auto textureView = texture.CreateView(&textureViewDescriptor);
|
auto textureView = texture.CreateView(&textureViewDescriptor);
|
||||||
return {std::make_shared<TextureRef>(std::move(texture), std::move(textureView), size, wgpuFormat)};
|
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,
|
.bytesPerRow = bytesPerRow,
|
||||||
.rowsPerImage = heightBlocks,
|
.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
|
} // 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>
|
#include <dawn/webgpu_cpp.h>
|
||||||
|
|
||||||
namespace aurora {
|
|
||||||
extern wgpu::Device g_Device;
|
|
||||||
extern wgpu::Queue g_Queue;
|
|
||||||
} // namespace aurora
|
|
||||||
|
|
||||||
namespace aurora::imgui {
|
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 {
|
ImTextureID add_texture(uint32_t width, uint32_t height, ArrayRef<uint8_t> data) noexcept {
|
||||||
const auto size = wgpu::Extent3D{
|
const auto size = wgpu::Extent3D{
|
||||||
.width = width,
|
.width = width,
|
||||||
|
@ -26,7 +62,7 @@ ImTextureID add_texture(uint32_t width, uint32_t height, ArrayRef<uint8_t> data)
|
||||||
.mipLevelCount = 1,
|
.mipLevelCount = 1,
|
||||||
.arrayLayerCount = 1,
|
.arrayLayerCount = 1,
|
||||||
};
|
};
|
||||||
auto texture = g_Device.CreateTexture(&textureDescriptor);
|
auto texture = g_device.CreateTexture(&textureDescriptor);
|
||||||
auto textureView = texture.CreateView(&textureViewDescriptor);
|
auto textureView = texture.CreateView(&textureViewDescriptor);
|
||||||
{
|
{
|
||||||
const auto dstView = wgpu::ImageCopyTexture{
|
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,
|
.bytesPerRow = 4 * width,
|
||||||
.rowsPerImage = height,
|
.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!
|
texture.Release(); // leak some memory!
|
||||||
return textureView.Release();
|
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;
|
uint32_t height;
|
||||||
};
|
};
|
||||||
Icon GetIcon();
|
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
|
} // namespace metaforce
|
||||||
|
|
Loading…
Reference in New Issue