mirror of
https://github.com/encounter/aurora.git
synced 2026-07-09 18:19:33 -07:00
Public aurora::gfx API (custom draws & compute)
This commit is contained in:
@@ -101,8 +101,11 @@ void aurora_dvd_overlay_callbacks(const AuroraOverlayCallbacks* callbacks);
|
|||||||
/**
|
/**
|
||||||
* \brief Specify a set of overlay files to be used by the DVD layer.
|
* \brief Specify a set of overlay files to be used by the DVD layer.
|
||||||
*
|
*
|
||||||
* Calling this function immediately applies the new files and rebuilds the FST. This is not thread safe.
|
* Calling this function immediately applies the new files and rebuilds the FST, replacing any
|
||||||
* It is best you only call this once on startup, before the game's code has started.
|
* previously specified set. It may be called again at runtime; FST reads and overlay opens are
|
||||||
|
* serialized against the rebuild, and previously assigned EntryNums are stable per path. Files
|
||||||
|
* removed by a re-registration fail to open from then on (or revert to the underlying DVD file);
|
||||||
|
* already-open handles are unaffected. Only call from one thread at a time.
|
||||||
*
|
*
|
||||||
* This function must be called *after* aurora_dvd_overlay_callbacks.
|
* This function must be called *after* aurora_dvd_overlay_callbacks.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,148 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include <webgpu/webgpu_cpp.h>
|
||||||
|
|
||||||
|
namespace aurora::gfx {
|
||||||
|
|
||||||
|
inline constexpr size_t InlineDrawPayloadSize = 128;
|
||||||
|
|
||||||
|
/// Generational handle: 0 is never valid, and IDs are not reused after unregister_draw_type.
|
||||||
|
using DrawTypeId = uint64_t;
|
||||||
|
inline constexpr DrawTypeId InvalidDrawType = 0;
|
||||||
|
|
||||||
|
struct Range {
|
||||||
|
uint32_t offset = 0;
|
||||||
|
uint32_t size = 0;
|
||||||
|
|
||||||
|
bool operator==(const Range& rhs) const { return offset == rhs.offset && size == rhs.size; }
|
||||||
|
bool operator!=(const Range& rhs) const { return !(*this == rhs); }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DrawContext {
|
||||||
|
wgpu::Device device;
|
||||||
|
wgpu::Queue queue;
|
||||||
|
wgpu::Buffer vertexBuffer;
|
||||||
|
wgpu::Buffer indexBuffer;
|
||||||
|
wgpu::Buffer uniformBuffer;
|
||||||
|
wgpu::Buffer storageBuffer;
|
||||||
|
wgpu::TextureFormat colorFormat;
|
||||||
|
wgpu::TextureFormat depthFormat;
|
||||||
|
uint32_t sampleCount = 1;
|
||||||
|
uint32_t targetWidth = 0;
|
||||||
|
uint32_t targetHeight = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Invoked on the render worker thread while replaying the pass the draw was
|
||||||
|
/// recorded into. The encoder's pipeline/bind-group/viewport/scissor state is
|
||||||
|
/// restored after the callback returns. Handles in the context are borrowed and
|
||||||
|
/// valid only for the duration of the call. sampleCount/target dimensions are
|
||||||
|
/// those of the containing pass (offscreen passes are always single-sample).
|
||||||
|
using DrawCallback = void (*)(const DrawContext& ctx, const wgpu::RenderPassEncoder& pass,
|
||||||
|
const void* payload, size_t payloadSize, void* userdata);
|
||||||
|
|
||||||
|
struct DrawTypeDescriptor {
|
||||||
|
const char* label = nullptr;
|
||||||
|
DrawCallback draw = nullptr;
|
||||||
|
void* userdata = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
wgpu::Device device() noexcept;
|
||||||
|
wgpu::Queue queue() noexcept;
|
||||||
|
wgpu::TextureFormat color_format() noexcept;
|
||||||
|
wgpu::TextureFormat depth_format() noexcept;
|
||||||
|
uint32_t sample_count() noexcept;
|
||||||
|
bool uses_reversed_z() noexcept;
|
||||||
|
|
||||||
|
DrawTypeId register_draw_type(const DrawTypeDescriptor& desc);
|
||||||
|
void unregister_draw_type(DrawTypeId type) noexcept;
|
||||||
|
/// Records an inline custom draw into the currently open render pass at the
|
||||||
|
/// current position in the command stream. Payload (<= InlineDrawPayloadSize)
|
||||||
|
/// is copied. Returns false (with a warning) outside an active render pass.
|
||||||
|
bool push_custom_draw(DrawTypeId type, const void* payload, size_t payloadSize);
|
||||||
|
|
||||||
|
/// Generational handle: 0 is never valid, and IDs are not reused after unregister_encoder_task_type.
|
||||||
|
using EncoderTaskId = uint64_t;
|
||||||
|
inline constexpr EncoderTaskId InvalidEncoderTask = 0;
|
||||||
|
|
||||||
|
struct EncoderTaskContext {
|
||||||
|
wgpu::Device device;
|
||||||
|
wgpu::Queue queue;
|
||||||
|
wgpu::Buffer vertexBuffer;
|
||||||
|
wgpu::Buffer indexBuffer;
|
||||||
|
wgpu::Buffer uniformBuffer;
|
||||||
|
wgpu::Buffer storageBuffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Invoked on the render worker thread with the frame's command encoder,
|
||||||
|
/// positioned between two render passes. The callback may begin/end compute
|
||||||
|
/// passes and record copies on the encoder; it must leave no pass open when it
|
||||||
|
/// returns and must not Finish the encoder. Handles in the context are borrowed
|
||||||
|
/// and valid only for the duration of the call. Data appended to the streaming
|
||||||
|
/// buffers before the task was pushed is GPU-visible inside it.
|
||||||
|
using EncoderTaskCallback = void (*)(const EncoderTaskContext& ctx, const wgpu::CommandEncoder& cmd,
|
||||||
|
const void* payload, size_t payloadSize, void* userdata);
|
||||||
|
|
||||||
|
struct EncoderTaskDescriptor {
|
||||||
|
const char* label = nullptr;
|
||||||
|
EncoderTaskCallback callback = nullptr;
|
||||||
|
void* userdata = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
EncoderTaskId register_encoder_task_type(const EncoderTaskDescriptor& desc);
|
||||||
|
void unregister_encoder_task_type(EncoderTaskId type) noexcept;
|
||||||
|
/// Seals the current EFB pass, records an encoder task to execute on the frame
|
||||||
|
/// encoder at this point, and resumes rendering on a pass that loads the
|
||||||
|
/// existing contents. Payload semantics match push_custom_draw. Returns false
|
||||||
|
/// (with a warning) outside an active render pass or while an offscreen pass
|
||||||
|
/// is open.
|
||||||
|
bool push_encoder_task(EncoderTaskId type, const void* payload, size_t payloadSize);
|
||||||
|
|
||||||
|
/// Append transient data to the shared per-frame streaming buffers. Returned
|
||||||
|
/// ranges are valid for the current frame only. Returns an empty Range (with a
|
||||||
|
/// warning) outside an active recording frame.
|
||||||
|
Range push_verts(const uint8_t* data, size_t length, size_t alignment);
|
||||||
|
Range push_indices(const uint8_t* data, size_t length, size_t alignment);
|
||||||
|
Range push_uniform(const uint8_t* data, size_t length);
|
||||||
|
Range push_storage(const uint8_t* data, size_t length);
|
||||||
|
|
||||||
|
struct ResolveDesc {
|
||||||
|
bool color = true;
|
||||||
|
bool depth = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ResolvedTargets {
|
||||||
|
wgpu::TextureView color; // single-sample snapshot; null if not requested
|
||||||
|
wgpu::TextureView depth; // single-sample R32Float depth snapshot; null if not requested
|
||||||
|
wgpu::TextureFormat colorFormat = wgpu::TextureFormat::Undefined;
|
||||||
|
uint32_t width = 0;
|
||||||
|
uint32_t height = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Snapshots the current pass targets into pooled textures (valid for the
|
||||||
|
/// current frame), then: on the EFB, continues rendering on a fresh EFB pass
|
||||||
|
/// (GXCopyTex semantics); in an offscreen pass created by create_pass, ends it
|
||||||
|
/// and restores the suspended EFB pass (GXRestoreFrameBuffer semantics).
|
||||||
|
/// Requesting neither color nor depth is a plain pass break (or offscreen
|
||||||
|
/// close, discarding its output). Depth is left null when unsupported by the
|
||||||
|
/// device. Returns false (with a warning) outside an active render pass.
|
||||||
|
bool resolve_pass(const ResolveDesc& desc, ResolvedTargets& out);
|
||||||
|
|
||||||
|
/// Opens an offscreen render pass (GXCreateFrameBuffer semantics): cleared
|
||||||
|
/// single-sample color+depth at (width, height) with full-target
|
||||||
|
/// viewport/scissor. Subsequent draws target it until resolve_pass restores the
|
||||||
|
/// EFB. Nesting is unsupported: returns false (with a warning) outside an
|
||||||
|
/// active render pass or while any offscreen pass is already open.
|
||||||
|
bool create_pass(uint32_t width, uint32_t height);
|
||||||
|
|
||||||
|
/// True while an offscreen pass (create_pass or GXCreateFrameBuffer) is open.
|
||||||
|
bool is_offscreen() noexcept;
|
||||||
|
|
||||||
|
/// Blocks until the render worker has drained its queue. After this returns,
|
||||||
|
/// no draw callback is executing or queued to execute; used before unloading
|
||||||
|
/// code that registered draw types. Callable from the game thread only.
|
||||||
|
void synchronize();
|
||||||
|
|
||||||
|
} // namespace aurora::gfx
|
||||||
@@ -78,8 +78,8 @@ void copy_tex(const void* dest, GXBool clear) noexcept {
|
|||||||
const auto clearColor = clear && g_gxState.colorUpdate;
|
const auto clearColor = clear && g_gxState.colorUpdate;
|
||||||
const auto clearAlpha = clear && g_gxState.alphaUpdate;
|
const auto clearAlpha = clear && g_gxState.alphaUpdate;
|
||||||
const auto clearDepth = clear && g_gxState.depthUpdate;
|
const auto clearDepth = clear && g_gxState.depthUpdate;
|
||||||
gfx::resolve_pass(handle.handle, rect, clearColor, clearAlpha, clearDepth, g_gxState.clearColor, clear_depth_value(),
|
gfx::resolve_pass_into(handle.handle, rect, clearColor, clearAlpha, clearDepth, g_gxState.clearColor,
|
||||||
texCopyFmt);
|
clear_depth_value(), texCopyFmt);
|
||||||
++handle.revision;
|
++handle.revision;
|
||||||
g_gxState.copyTextures[dest] = handle;
|
g_gxState.copyTextures[dest] = handle;
|
||||||
}
|
}
|
||||||
|
|||||||
+587
-25
File diff suppressed because it is too large
Load Diff
+4
-11
@@ -11,6 +11,7 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include <aurora/gfx.h>
|
#include <aurora/gfx.h>
|
||||||
|
#include <aurora/gfx.hpp>
|
||||||
#include <aurora/math.hpp>
|
#include <aurora/math.hpp>
|
||||||
#include <dolphin/gx/GXEnum.h>
|
#include <dolphin/gx/GXEnum.h>
|
||||||
#include <webgpu/webgpu_cpp.h>
|
#include <webgpu/webgpu_cpp.h>
|
||||||
@@ -173,7 +174,7 @@ private:
|
|||||||
namespace aurora::gfx {
|
namespace aurora::gfx {
|
||||||
inline constexpr bool UseTextureBuffer = true;
|
inline constexpr bool UseTextureBuffer = true;
|
||||||
inline constexpr uint64_t UniformBufferSize = 25165824; // 24mb
|
inline constexpr uint64_t UniformBufferSize = 25165824; // 24mb
|
||||||
inline constexpr uint64_t VertexBufferSize = 3145728; // 3mb
|
inline constexpr uint64_t VertexBufferSize = 5242880; // 5mb
|
||||||
inline constexpr uint64_t IndexBufferSize = 1048576; // 1mb
|
inline constexpr uint64_t IndexBufferSize = 1048576; // 1mb
|
||||||
inline constexpr uint64_t StorageBufferSize = 8388608; // 8mb
|
inline constexpr uint64_t StorageBufferSize = 8388608; // 8mb
|
||||||
inline constexpr uint64_t TextureUploadSize = 25165824; // 24mb
|
inline constexpr uint64_t TextureUploadSize = 25165824; // 24mb
|
||||||
@@ -194,13 +195,6 @@ using BindGroupRef = HashType;
|
|||||||
using PipelineRef = HashType;
|
using PipelineRef = HashType;
|
||||||
using SamplerRef = HashType;
|
using SamplerRef = HashType;
|
||||||
using ShaderRef = HashType;
|
using ShaderRef = HashType;
|
||||||
struct Range {
|
|
||||||
uint32_t offset = 0;
|
|
||||||
uint32_t size = 0;
|
|
||||||
|
|
||||||
bool operator==(const Range& rhs) const { return memcmp(this, &rhs, sizeof(*this)) == 0; }
|
|
||||||
bool operator!=(const Range& rhs) const { return !(*this == rhs); }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ClipRect {
|
struct ClipRect {
|
||||||
int32_t x;
|
int32_t x;
|
||||||
@@ -236,8 +230,8 @@ void after_submit() noexcept;
|
|||||||
void gpu_synchronize();
|
void gpu_synchronize();
|
||||||
void after_present() noexcept;
|
void after_present() noexcept;
|
||||||
float calculate_fps() noexcept;
|
float calculate_fps() noexcept;
|
||||||
void resolve_pass(TextureHandle texture, ClipRect rect, bool clearColor, bool clearAlpha, bool clearDepth,
|
void resolve_pass_into(TextureHandle texture, ClipRect rect, bool clearColor, bool clearAlpha, bool clearDepth,
|
||||||
Vec4<float> clearColorValue, float clearDepthValue, GXTexFmt resolveFormat = GX_TF_RGBA8);
|
Vec4<float> clearColorValue, float clearDepthValue, GXTexFmt resolveFormat = GX_TF_RGBA8);
|
||||||
|
|
||||||
struct ColorPassDescriptor {
|
struct ColorPassDescriptor {
|
||||||
const char* label = nullptr;
|
const char* label = nullptr;
|
||||||
@@ -257,7 +251,6 @@ struct ColorPassDescriptor {
|
|||||||
wgpu::LoadOp stencilLoadOp = wgpu::LoadOp::Undefined;
|
wgpu::LoadOp stencilLoadOp = wgpu::LoadOp::Undefined;
|
||||||
wgpu::StoreOp stencilStoreOp = wgpu::StoreOp::Undefined;
|
wgpu::StoreOp stencilStoreOp = wgpu::StoreOp::Undefined;
|
||||||
uint32_t stencilClearValue = 0;
|
uint32_t stencilClearValue = 0;
|
||||||
bool observable = true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void begin_color_pass(const ColorPassDescriptor& desc);
|
void begin_color_pass(const ColorPassDescriptor& desc);
|
||||||
|
|||||||
@@ -244,6 +244,45 @@ static constexpr std::string_view FragZ16 = R"(
|
|||||||
}
|
}
|
||||||
)"sv;
|
)"sv;
|
||||||
|
|
||||||
|
// Depth -> R32Float (no scaling)
|
||||||
|
static constexpr std::string_view DepthSnapshotShader = R"(
|
||||||
|
@group(0) @binding(0) var src: texture_depth_2d;
|
||||||
|
|
||||||
|
var<private> positions: array<vec2f, 3> = array(
|
||||||
|
vec2f(-1.0, 1.0),
|
||||||
|
vec2f(-1.0, -3.0),
|
||||||
|
vec2f(3.0, 1.0),
|
||||||
|
);
|
||||||
|
|
||||||
|
@vertex fn vs_main(@builtin(vertex_index) vi: u32) -> @builtin(position) vec4f {
|
||||||
|
return vec4f(positions[vi], 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@fragment fn fs_main(@builtin(position) pos: vec4f) -> @location(0) vec4f {
|
||||||
|
let depth = textureLoad(src, vec2i(pos.xy), 0);
|
||||||
|
return vec4f(depth, 0.0, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
)"sv;
|
||||||
|
|
||||||
|
static constexpr std::string_view DepthSnapshotShaderMS = R"(
|
||||||
|
@group(0) @binding(0) var src: texture_depth_multisampled_2d;
|
||||||
|
|
||||||
|
var<private> positions: array<vec2f, 3> = array(
|
||||||
|
vec2f(-1.0, 1.0),
|
||||||
|
vec2f(-1.0, -3.0),
|
||||||
|
vec2f(3.0, 1.0),
|
||||||
|
);
|
||||||
|
|
||||||
|
@vertex fn vs_main(@builtin(vertex_index) vi: u32) -> @builtin(position) vec4f {
|
||||||
|
return vec4f(positions[vi], 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@fragment fn fs_main(@builtin(position) pos: vec4f) -> @location(0) vec4f {
|
||||||
|
let depth = textureLoad(src, vec2i(pos.xy), 0);
|
||||||
|
return vec4f(depth, 0.0, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
)"sv;
|
||||||
|
|
||||||
struct ConvPipeline {
|
struct ConvPipeline {
|
||||||
GXTexFmt fmt;
|
GXTexFmt fmt;
|
||||||
std::string_view fragShader;
|
std::string_view fragShader;
|
||||||
@@ -278,6 +317,75 @@ static wgpu::Sampler g_nearestSampler;
|
|||||||
static wgpu::Sampler g_linearSampler;
|
static wgpu::Sampler g_linearSampler;
|
||||||
static absl::flat_hash_map<GXTexFmt, wgpu::RenderPipeline> g_pipelines;
|
static absl::flat_hash_map<GXTexFmt, wgpu::RenderPipeline> g_pipelines;
|
||||||
static wgpu::RenderPipeline g_blitPipeline;
|
static wgpu::RenderPipeline g_blitPipeline;
|
||||||
|
static wgpu::BindGroupLayout g_depthSnapshotBindGroupLayout;
|
||||||
|
static wgpu::BindGroupLayout g_depthSnapshotBindGroupLayoutMS;
|
||||||
|
static wgpu::RenderPipeline g_depthSnapshotPipeline;
|
||||||
|
static wgpu::RenderPipeline g_depthSnapshotPipelineMS;
|
||||||
|
|
||||||
|
static wgpu::BindGroupLayout create_depth_snapshot_layout(bool multisampled, const char* label) {
|
||||||
|
const std::array entries{
|
||||||
|
wgpu::BindGroupLayoutEntry{
|
||||||
|
.binding = 0,
|
||||||
|
.visibility = wgpu::ShaderStage::Fragment,
|
||||||
|
.texture =
|
||||||
|
wgpu::TextureBindingLayout{
|
||||||
|
.sampleType = wgpu::TextureSampleType::Depth,
|
||||||
|
.viewDimension = wgpu::TextureViewDimension::e2D,
|
||||||
|
.multisampled = multisampled,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const wgpu::BindGroupLayoutDescriptor descriptor{
|
||||||
|
.label = label,
|
||||||
|
.entryCount = entries.size(),
|
||||||
|
.entries = entries.data(),
|
||||||
|
};
|
||||||
|
return g_device.CreateBindGroupLayout(&descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
static wgpu::RenderPipeline create_depth_snapshot_pipeline(const std::string_view shaderSource,
|
||||||
|
const wgpu::BindGroupLayout& bindGroupLayout,
|
||||||
|
const char* label) {
|
||||||
|
const std::string source{shaderSource};
|
||||||
|
const wgpu::ShaderSourceWGSL wgslSource{wgpu::ShaderSourceWGSL::Init{
|
||||||
|
.code = source.c_str(),
|
||||||
|
}};
|
||||||
|
const wgpu::ShaderModuleDescriptor moduleDescriptor{
|
||||||
|
.nextInChain = &wgslSource,
|
||||||
|
.label = label,
|
||||||
|
};
|
||||||
|
const auto module = g_device.CreateShaderModule(&moduleDescriptor);
|
||||||
|
|
||||||
|
const std::array colorTargets{wgpu::ColorTargetState{
|
||||||
|
.format = wgpu::TextureFormat::R32Float,
|
||||||
|
}};
|
||||||
|
const wgpu::FragmentState fragmentState{
|
||||||
|
.module = module,
|
||||||
|
.entryPoint = "fs_main",
|
||||||
|
.targetCount = colorTargets.size(),
|
||||||
|
.targets = colorTargets.data(),
|
||||||
|
};
|
||||||
|
const wgpu::PipelineLayoutDescriptor layoutDescriptor{
|
||||||
|
.bindGroupLayoutCount = 1,
|
||||||
|
.bindGroupLayouts = &bindGroupLayout,
|
||||||
|
};
|
||||||
|
const auto pipelineLayout = g_device.CreatePipelineLayout(&layoutDescriptor);
|
||||||
|
const wgpu::RenderPipelineDescriptor pipelineDescriptor{
|
||||||
|
.label = label,
|
||||||
|
.layout = pipelineLayout,
|
||||||
|
.vertex =
|
||||||
|
wgpu::VertexState{
|
||||||
|
.module = module,
|
||||||
|
.entryPoint = "vs_main",
|
||||||
|
},
|
||||||
|
.primitive =
|
||||||
|
wgpu::PrimitiveState{
|
||||||
|
.topology = wgpu::PrimitiveTopology::TriangleList,
|
||||||
|
},
|
||||||
|
.fragment = &fragmentState,
|
||||||
|
};
|
||||||
|
return g_device.CreateRenderPipeline(&pipelineDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
static wgpu::RenderPipeline create_pipeline(const ConvPipeline& conv, const std::string_view shaderPreamble,
|
static wgpu::RenderPipeline create_pipeline(const ConvPipeline& conv, const std::string_view shaderPreamble,
|
||||||
const wgpu::BindGroupLayout& bindGroupLayout) {
|
const wgpu::BindGroupLayout& bindGroupLayout) {
|
||||||
@@ -408,6 +516,12 @@ void initialize() {
|
|||||||
Log.fatal("Output format mismatch for {}", conv.fmt);
|
Log.fatal("Output format mismatch for {}", conv.fmt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
g_depthSnapshotBindGroupLayout = create_depth_snapshot_layout(false, "Depth Snapshot Bind Group Layout");
|
||||||
|
g_depthSnapshotBindGroupLayoutMS = create_depth_snapshot_layout(true, "Depth Snapshot MS Bind Group Layout");
|
||||||
|
g_depthSnapshotPipeline =
|
||||||
|
create_depth_snapshot_pipeline(DepthSnapshotShader, g_depthSnapshotBindGroupLayout, "Depth Snapshot");
|
||||||
|
g_depthSnapshotPipelineMS =
|
||||||
|
create_depth_snapshot_pipeline(DepthSnapshotShaderMS, g_depthSnapshotBindGroupLayoutMS, "Depth Snapshot MS");
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr wgpu::SamplerDescriptor nearestSamplerDescriptor{
|
static constexpr wgpu::SamplerDescriptor nearestSamplerDescriptor{
|
||||||
@@ -432,6 +546,10 @@ void shutdown() {
|
|||||||
g_depthBindGroupLayout = {};
|
g_depthBindGroupLayout = {};
|
||||||
g_nearestSampler = {};
|
g_nearestSampler = {};
|
||||||
g_linearSampler = {};
|
g_linearSampler = {};
|
||||||
|
g_depthSnapshotBindGroupLayout = {};
|
||||||
|
g_depthSnapshotBindGroupLayoutMS = {};
|
||||||
|
g_depthSnapshotPipeline = {};
|
||||||
|
g_depthSnapshotPipelineMS = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void execute(const wgpu::CommandEncoder& cmd, const ConvRequest& req, const wgpu::RenderPipeline& pipeline) {
|
static void execute(const wgpu::CommandEncoder& cmd, const ConvRequest& req, const wgpu::RenderPipeline& pipeline) {
|
||||||
@@ -519,4 +637,47 @@ void run(const wgpu::CommandEncoder& cmd, const ConvRequest& req) {
|
|||||||
|
|
||||||
void blit(const wgpu::CommandEncoder& cmd, const ConvRequest& req) { execute(cmd, req, g_blitPipeline); }
|
void blit(const wgpu::CommandEncoder& cmd, const ConvRequest& req) { execute(cmd, req, g_blitPipeline); }
|
||||||
|
|
||||||
|
bool snapshot_depth_supported() noexcept { return static_cast<bool>(g_depthSnapshotPipeline); }
|
||||||
|
|
||||||
|
void snapshot_depth(const wgpu::CommandEncoder& cmd, const wgpu::TextureView& srcDepth, uint32_t msaaSamples,
|
||||||
|
const wgpu::TextureView& dst) {
|
||||||
|
const bool multisampled = msaaSamples > 1;
|
||||||
|
const auto& pipeline = multisampled ? g_depthSnapshotPipelineMS : g_depthSnapshotPipeline;
|
||||||
|
if (!pipeline) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const std::array bindGroupEntries{
|
||||||
|
wgpu::BindGroupEntry{
|
||||||
|
.binding = 0,
|
||||||
|
.textureView = srcDepth,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const wgpu::BindGroupDescriptor bindGroupDescriptor{
|
||||||
|
.layout = multisampled ? g_depthSnapshotBindGroupLayoutMS : g_depthSnapshotBindGroupLayout,
|
||||||
|
.entryCount = bindGroupEntries.size(),
|
||||||
|
.entries = bindGroupEntries.data(),
|
||||||
|
};
|
||||||
|
const auto bindGroup = g_device.CreateBindGroup(&bindGroupDescriptor);
|
||||||
|
|
||||||
|
const std::array colorAttachments{
|
||||||
|
wgpu::RenderPassColorAttachment{
|
||||||
|
.view = dst,
|
||||||
|
.loadOp = wgpu::LoadOp::Clear,
|
||||||
|
.storeOp = wgpu::StoreOp::Store,
|
||||||
|
.clearValue = {0.0, 0.0, 0.0, 0.0},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const wgpu::RenderPassDescriptor renderPassDescriptor{
|
||||||
|
.label = "Depth Snapshot Pass",
|
||||||
|
.colorAttachmentCount = colorAttachments.size(),
|
||||||
|
.colorAttachments = colorAttachments.data(),
|
||||||
|
.timestampWrites = webgpu::gpu_prof::pass_writes("Depth snapshot"),
|
||||||
|
};
|
||||||
|
const auto pass = cmd.BeginRenderPass(&renderPassDescriptor);
|
||||||
|
pass.SetPipeline(pipeline);
|
||||||
|
pass.SetBindGroup(0, bindGroup);
|
||||||
|
pass.Draw(3);
|
||||||
|
pass.End();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace aurora::gfx::tex_copy_conv
|
} // namespace aurora::gfx::tex_copy_conv
|
||||||
|
|||||||
@@ -26,4 +26,8 @@ void shutdown();
|
|||||||
void run(const wgpu::CommandEncoder& cmd, const ConvRequest& req);
|
void run(const wgpu::CommandEncoder& cmd, const ConvRequest& req);
|
||||||
void blit(const wgpu::CommandEncoder& cmd, const ConvRequest& req);
|
void blit(const wgpu::CommandEncoder& cmd, const ConvRequest& req);
|
||||||
|
|
||||||
|
bool snapshot_depth_supported() noexcept;
|
||||||
|
void snapshot_depth(const wgpu::CommandEncoder& cmd, const wgpu::TextureView& srcDepth, uint32_t msaaSamples,
|
||||||
|
const wgpu::TextureView& dst);
|
||||||
|
|
||||||
} // namespace aurora::gfx::tex_copy_conv
|
} // namespace aurora::gfx::tex_copy_conv
|
||||||
|
|||||||
@@ -697,7 +697,6 @@ void WebGPURenderInterface::BeginRenderTargetPass(const wgpu::TextureView& view,
|
|||||||
.stencilLoadOp = clearStencil ? wgpu::LoadOp::Clear : wgpu::LoadOp::Undefined,
|
.stencilLoadOp = clearStencil ? wgpu::LoadOp::Clear : wgpu::LoadOp::Undefined,
|
||||||
.stencilStoreOp = clearStencil ? wgpu::StoreOp::Store : wgpu::StoreOp::Undefined,
|
.stencilStoreOp = clearStencil ? wgpu::StoreOp::Store : wgpu::StoreOp::Undefined,
|
||||||
.stencilClearValue = 0,
|
.stencilClearValue = 0,
|
||||||
.observable = true,
|
|
||||||
});
|
});
|
||||||
m_passActive = true;
|
m_passActive = true;
|
||||||
ApplyViewport();
|
ApplyViewport();
|
||||||
@@ -725,7 +724,6 @@ void WebGPURenderInterface::BeginLayerPass(Rml::LayerHandle layer, wgpu::LoadOp
|
|||||||
.stencilLoadOp = clearStencil ? wgpu::LoadOp::Clear : wgpu::LoadOp::Load,
|
.stencilLoadOp = clearStencil ? wgpu::LoadOp::Clear : wgpu::LoadOp::Load,
|
||||||
.stencilStoreOp = wgpu::StoreOp::Store,
|
.stencilStoreOp = wgpu::StoreOp::Store,
|
||||||
.stencilClearValue = 0,
|
.stencilClearValue = 0,
|
||||||
.observable = true,
|
|
||||||
});
|
});
|
||||||
m_passActive = true;
|
m_passActive = true;
|
||||||
ApplyViewport();
|
ApplyViewport();
|
||||||
|
|||||||
Reference in New Issue
Block a user