mirror of
https://github.com/patchzyy/wiicompiled
synced 2026-09-11 09:25:05 -04:00
97 lines
3.3 KiB
C++
97 lines
3.3 KiB
C++
#include "pipeline.hpp"
|
|
|
|
#include "../webgpu/gpu.hpp"
|
|
#include "gx_fmt.hpp"
|
|
#include "shader_info.hpp"
|
|
#include "tracy/Tracy.hpp"
|
|
|
|
#include <condition_variable>
|
|
#include <memory>
|
|
#include <mutex>
|
|
|
|
#include <absl/container/flat_hash_map.h>
|
|
|
|
namespace aurora::gx {
|
|
static Module Log("aurora::gx");
|
|
|
|
namespace {
|
|
struct ShaderConfigHash {
|
|
size_t operator()(const ShaderConfig& config) const noexcept { return static_cast<size_t>(xxh3_hash(config)); }
|
|
};
|
|
|
|
struct CachedShaderModule {
|
|
std::condition_variable ready;
|
|
wgpu::ShaderModule module;
|
|
bool compiling = true;
|
|
};
|
|
|
|
std::mutex sShaderModuleCacheMutex;
|
|
absl::flat_hash_map<ShaderConfig, std::shared_ptr<CachedShaderModule>, ShaderConfigHash> sShaderModuleCache;
|
|
|
|
wgpu::ShaderModule cached_shader_module(const ShaderConfig& config) {
|
|
std::shared_ptr<CachedShaderModule> entry;
|
|
{
|
|
std::unique_lock lock{sShaderModuleCacheMutex};
|
|
const auto it = sShaderModuleCache.find(config);
|
|
if (it == sShaderModuleCache.end()) {
|
|
entry = std::make_shared<CachedShaderModule>();
|
|
sShaderModuleCache.emplace(config, entry);
|
|
} else {
|
|
entry = it->second;
|
|
entry->ready.wait(lock, [&] { return !entry->compiling; });
|
|
return entry->module;
|
|
}
|
|
}
|
|
|
|
auto module = build_shader(config);
|
|
{
|
|
std::lock_guard lock{sShaderModuleCacheMutex};
|
|
entry->module = module;
|
|
entry->compiling = false;
|
|
}
|
|
entry->ready.notify_all();
|
|
return module;
|
|
}
|
|
} // namespace
|
|
|
|
wgpu::RenderPipeline create_pipeline(const PipelineConfig& config) {
|
|
ZoneScoped;
|
|
const auto shader = cached_shader_module(config.shaderConfig);
|
|
return build_pipeline(config, {}, shader, "GX Pipeline");
|
|
}
|
|
|
|
void clear_shader_module_cache() {
|
|
std::lock_guard lock{sShaderModuleCacheMutex};
|
|
sShaderModuleCache.clear();
|
|
}
|
|
|
|
void render(const DrawData& data, const wgpu::RenderPassEncoder& pass, DrawEncodeState& state,
|
|
bool requireReadyPipeline, const gfx::Range* uniformRangeOverride) {
|
|
if (!gfx::bind_pipeline(data.pipeline, pass, state.currentPipeline, requireReadyPipeline)) {
|
|
return;
|
|
}
|
|
|
|
// An interpolated presentation slot re-encodes the identical draw with only this range replaced; overriding here avoids copying the whole DrawData per draw per slot.
|
|
const gfx::Range& uniformRange = uniformRangeOverride != nullptr ? *uniformRangeOverride : data.uniformRange;
|
|
const std::array offsets{uniformRange.offset};
|
|
pass.SetBindGroup(1, gfx::g_uniformBindGroup, offsets.size(), offsets.data());
|
|
// Resolved when the draw was recorded; see GXBindGroups.
|
|
if (data.bindGroups.resolvedTextureBindGroup != nullptr &&
|
|
data.bindGroups.resolvedTextureBindGroup != state.boundTextureBindGroup) {
|
|
wgpuRenderPassEncoderSetBindGroup(pass.Get(), 2, data.bindGroups.resolvedTextureBindGroup, 0, nullptr);
|
|
state.boundTextureBindGroup = data.bindGroups.resolvedTextureBindGroup;
|
|
}
|
|
if (data.dstAlpha != UINT32_MAX) {
|
|
const wgpu::Color color{0.f, 0.f, 0.f, data.dstAlpha / 255.f};
|
|
pass.SetBlendConstant(&color);
|
|
}
|
|
if (!state.indexBufferBound) {
|
|
// Bound once for the pass; draws select their range with firstIndex below.
|
|
pass.SetIndexBuffer(gfx::g_indexBuffer, wgpu::IndexFormat::Uint16, 0, wgpu::kWholeSize);
|
|
state.indexBufferBound = true;
|
|
}
|
|
pass.DrawIndexed(data.indexCount, data.instanceCount,
|
|
static_cast<uint32_t>(data.idxRange.offset / sizeof(uint16_t)));
|
|
}
|
|
} // namespace aurora::gx
|