mirror of
https://github.com/encounter/aurora.git
synced 2026-07-09 18:19:33 -07:00
Optimize RmlUi render passes
This commit is contained in:
+11
-3
@@ -239,13 +239,16 @@ void end_frame() noexcept {
|
|||||||
presentSource.size.width, presentSource.size.height);
|
presentSource.size.width, presentSource.size.height);
|
||||||
|
|
||||||
wgpu::BindGroup rmlBindGroup;
|
wgpu::BindGroup rmlBindGroup;
|
||||||
|
bool rmlOverlay = false;
|
||||||
#if AURORA_ENABLE_RMLUI
|
#if AURORA_ENABLE_RMLUI
|
||||||
if (rmlui::is_initialized()) {
|
if (rmlui::is_initialized()) {
|
||||||
rmlBindGroup = rmlui::record_frame(viewport);
|
auto rmlFrame = rmlui::record_frame(viewport);
|
||||||
|
rmlBindGroup = std::move(rmlFrame.bindGroup);
|
||||||
|
rmlOverlay = rmlFrame.overlay;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
gfx::end_frame([rmlBindGroup = std::move(rmlBindGroup), viewport,
|
gfx::end_frame([rmlBindGroup = std::move(rmlBindGroup), rmlOverlay, viewport,
|
||||||
imguiDrawData = std::move(imguiDrawData)](wgpu::CommandEncoder& encoder) {
|
imguiDrawData = std::move(imguiDrawData)](wgpu::CommandEncoder& encoder) {
|
||||||
wgpu::Texture currentTexture;
|
wgpu::Texture currentTexture;
|
||||||
wgpu::TextureView currentView;
|
wgpu::TextureView currentView;
|
||||||
@@ -267,7 +270,7 @@ void end_frame() noexcept {
|
|||||||
const bool canPresent = currentTexture && currentView;
|
const bool canPresent = currentTexture && currentView;
|
||||||
if (canPresent) {
|
if (canPresent) {
|
||||||
wgpu::BindGroup presentBindGroup;
|
wgpu::BindGroup presentBindGroup;
|
||||||
if (rmlBindGroup) {
|
if (rmlBindGroup && !rmlOverlay) {
|
||||||
presentBindGroup = rmlBindGroup;
|
presentBindGroup = rmlBindGroup;
|
||||||
} else {
|
} else {
|
||||||
const auto& resampledSource = webgpu::resample_present_source(encoder, viewport);
|
const auto& resampledSource = webgpu::resample_present_source(encoder, viewport);
|
||||||
@@ -294,6 +297,11 @@ void end_frame() noexcept {
|
|||||||
pass.SetViewport(viewport.left, viewport.top, viewport.width, viewport.height, viewport.znear, viewport.zfar);
|
pass.SetViewport(viewport.left, viewport.top, viewport.width, viewport.height, viewport.znear, viewport.zfar);
|
||||||
|
|
||||||
pass.Draw(3);
|
pass.Draw(3);
|
||||||
|
if (rmlBindGroup && rmlOverlay) {
|
||||||
|
pass.SetPipeline(webgpu::g_CopyPremultipliedAlphaPipeline);
|
||||||
|
pass.SetBindGroup(0, rmlBindGroup, 0, nullptr);
|
||||||
|
pass.Draw(3);
|
||||||
|
}
|
||||||
pass.End();
|
pass.End();
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|||||||
+35
-3
@@ -4,6 +4,7 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include <RmlUi/Core.h>
|
#include <RmlUi/Core.h>
|
||||||
|
#include <RmlUi/Core/Element.h>
|
||||||
#include <RmlUi_Backend.h>
|
#include <RmlUi_Backend.h>
|
||||||
#include <RmlUi_Platform_SDL.h>
|
#include <RmlUi_Platform_SDL.h>
|
||||||
#include <tracy/Tracy.hpp>
|
#include <tracy/Tracy.hpp>
|
||||||
@@ -82,6 +83,32 @@ void ensure_render_target(Rml::Vector2i dimensions) noexcept {
|
|||||||
s_renderTargetCopyBindGroup = webgpu::create_copy_bind_group(s_renderTarget);
|
s_renderTargetCopyBindGroup = webgpu::create_copy_bind_group(s_renderTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool element_has_visible_backdrop_filter(const Rml::Element* element) noexcept {
|
||||||
|
if (element == nullptr || !element->IsVisible(true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& computed = element->GetComputedValues();
|
||||||
|
if (computed.opacity() > 0.f && computed.has_backdrop_filter()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int childCount = element->GetNumChildren();
|
||||||
|
for (int childIndex = 0; childIndex < childCount; ++childIndex) {
|
||||||
|
if (element_has_visible_backdrop_filter(element->GetChild(childIndex))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool context_has_visible_backdrop_filter(Rml::Context* context) noexcept {
|
||||||
|
if (context == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return element_has_visible_backdrop_filter(context->GetRootElement());
|
||||||
|
}
|
||||||
|
|
||||||
struct MappedPoint {
|
struct MappedPoint {
|
||||||
Rml::Vector2f position;
|
Rml::Vector2f position;
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
@@ -408,7 +435,7 @@ void handle_event(SDL_Event& event) noexcept {
|
|||||||
RmlSDL::InputEventHandler(g_context, window::get_sdl_window(), event);
|
RmlSDL::InputEventHandler(g_context, window::get_sdl_window(), event);
|
||||||
}
|
}
|
||||||
|
|
||||||
wgpu::BindGroup record_frame(const webgpu::Viewport& presentViewport) noexcept {
|
RecordedFrame record_frame(const webgpu::Viewport& presentViewport) noexcept {
|
||||||
if (g_context == nullptr) {
|
if (g_context == nullptr) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -422,10 +449,12 @@ wgpu::BindGroup record_frame(const webgpu::Viewport& presentViewport) noexcept {
|
|||||||
|
|
||||||
sync_context_metrics(dim);
|
sync_context_metrics(dim);
|
||||||
g_context->Update();
|
g_context->Update();
|
||||||
|
const bool needsBackdrop = context_has_visible_backdrop_filter(g_context);
|
||||||
|
|
||||||
auto* renderInterface = get_render_interface();
|
auto* renderInterface = get_render_interface();
|
||||||
renderInterface->SetWindowSize(g_context->GetDimensions());
|
renderInterface->SetWindowSize(g_context->GetDimensions());
|
||||||
renderInterface->BeginFrame(s_renderTarget, webgpu::present_source());
|
renderInterface->BeginFrame(s_renderTarget, webgpu::present_source(),
|
||||||
|
needsBackdrop ? BaseLayerContent::Scene : BaseLayerContent::Transparent);
|
||||||
|
|
||||||
Backend::BeginFrame();
|
Backend::BeginFrame();
|
||||||
g_context->Render();
|
g_context->Render();
|
||||||
@@ -435,7 +464,10 @@ wgpu::BindGroup record_frame(const webgpu::Viewport& presentViewport) noexcept {
|
|||||||
// We didn't render anything
|
// We didn't render anything
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return s_renderTargetCopyBindGroup;
|
return {
|
||||||
|
.bindGroup = s_renderTargetCopyBindGroup,
|
||||||
|
.overlay = !needsBackdrop,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void shutdown() noexcept {
|
void shutdown() noexcept {
|
||||||
|
|||||||
+6
-1
@@ -9,9 +9,14 @@
|
|||||||
|
|
||||||
namespace aurora::rmlui {
|
namespace aurora::rmlui {
|
||||||
|
|
||||||
|
struct RecordedFrame {
|
||||||
|
wgpu::BindGroup bindGroup;
|
||||||
|
bool overlay = false;
|
||||||
|
};
|
||||||
|
|
||||||
void initialize(const AuroraWindowSize& size) noexcept;
|
void initialize(const AuroraWindowSize& size) noexcept;
|
||||||
void handle_event(SDL_Event& event) noexcept;
|
void handle_event(SDL_Event& event) noexcept;
|
||||||
wgpu::BindGroup record_frame(const webgpu::Viewport& presentViewport) noexcept;
|
RecordedFrame record_frame(const webgpu::Viewport& presentViewport) noexcept;
|
||||||
void shutdown() noexcept;
|
void shutdown() noexcept;
|
||||||
|
|
||||||
} // namespace aurora::rmlui
|
} // namespace aurora::rmlui
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ namespace {
|
|||||||
Module Log("aurora::rmlui::RenderInterface");
|
Module Log("aurora::rmlui::RenderInterface");
|
||||||
|
|
||||||
constexpr size_t rmlBufferOffsetAlignment = 4;
|
constexpr size_t rmlBufferOffsetAlignment = 4;
|
||||||
|
constexpr float FilterEpsilon = 0.0001f;
|
||||||
|
|
||||||
struct Image {
|
struct Image {
|
||||||
std::unique_ptr<uint8_t[]> data;
|
std::unique_ptr<uint8_t[]> data;
|
||||||
@@ -53,6 +54,23 @@ struct CompiledShaderData {
|
|||||||
GradientUniformBlock gradient;
|
GradientUniformBlock gradient;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class FilterType {
|
||||||
|
Opacity,
|
||||||
|
Blur,
|
||||||
|
DropShadow,
|
||||||
|
ColorMatrix,
|
||||||
|
MaskImage,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CompiledFilter {
|
||||||
|
FilterType type = FilterType::Blur;
|
||||||
|
float opacity = 1.f;
|
||||||
|
float sigma = 0.f;
|
||||||
|
Rml::Vector2f offset;
|
||||||
|
Rml::ColourbPremultiplied color;
|
||||||
|
Rml::Matrix4f colorMatrix;
|
||||||
|
};
|
||||||
|
|
||||||
Image get_image(const Rml::String& source) {
|
Image get_image(const Rml::String& source) {
|
||||||
FileInterface_SDL fileInterface;
|
FileInterface_SDL fileInterface;
|
||||||
const Rml::FileHandle file = fileInterface.Open(source);
|
const Rml::FileHandle file = fileInterface.Open(source);
|
||||||
@@ -158,6 +176,74 @@ Rml::ColumnMajorMatrix4f to_shader_matrix(const Rml::Matrix4f& matrix) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_identity_matrix(const Rml::Matrix4f& matrix) {
|
||||||
|
const Rml::Matrix4f identity = Rml::Matrix4f::Identity();
|
||||||
|
const auto* matrixData = matrix.data();
|
||||||
|
const auto* identityData = identity.data();
|
||||||
|
for (size_t i = 0; i < 16; ++i) {
|
||||||
|
if (std::abs(matrixData[i] - identityData[i]) > FilterEpsilon) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_identity_filter(const CompiledFilter& filter) {
|
||||||
|
switch (filter.type) {
|
||||||
|
case FilterType::Opacity:
|
||||||
|
return std::abs(filter.opacity - 1.f) <= FilterEpsilon;
|
||||||
|
case FilterType::Blur:
|
||||||
|
return filter.sigma < 0.5f;
|
||||||
|
case FilterType::ColorMatrix:
|
||||||
|
return is_identity_matrix(filter.colorMatrix);
|
||||||
|
case FilterType::DropShadow:
|
||||||
|
case FilterType::MaskImage:
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Rml::CompiledFilterHandle> active_filters(Rml::Span<const Rml::CompiledFilterHandle> filters) {
|
||||||
|
std::vector<Rml::CompiledFilterHandle> activeFilters;
|
||||||
|
activeFilters.reserve(filters.size());
|
||||||
|
for (Rml::CompiledFilterHandle filterHandle : filters) {
|
||||||
|
const auto* filter = reinterpret_cast<const CompiledFilter*>(filterHandle);
|
||||||
|
if (filter != nullptr && !is_identity_filter(*filter)) {
|
||||||
|
activeFilters.push_back(filterHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return activeFilters;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool try_fold_simple_filters(Rml::Span<const Rml::CompiledFilterHandle> filters, Rml::Matrix4f& colorMatrix,
|
||||||
|
float& opacity) {
|
||||||
|
colorMatrix = Rml::Matrix4f::Identity();
|
||||||
|
opacity = 1.f;
|
||||||
|
|
||||||
|
for (Rml::CompiledFilterHandle filterHandle : filters) {
|
||||||
|
const auto* filter = reinterpret_cast<const CompiledFilter*>(filterHandle);
|
||||||
|
if (filter == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (filter->type) {
|
||||||
|
case FilterType::Opacity:
|
||||||
|
opacity *= filter->opacity;
|
||||||
|
break;
|
||||||
|
case FilterType::ColorMatrix:
|
||||||
|
colorMatrix = filter->colorMatrix * colorMatrix;
|
||||||
|
break;
|
||||||
|
case FilterType::Blur:
|
||||||
|
case FilterType::DropShadow:
|
||||||
|
case FilterType::MaskImage:
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Rml::Rectanglei downsample_scissor(Rml::Rectanglei scissor) {
|
Rml::Rectanglei downsample_scissor(Rml::Rectanglei scissor) {
|
||||||
scissor.p0 = (scissor.p0 + Rml::Vector2i(1)) / 2;
|
scissor.p0 = (scissor.p0 + Rml::Vector2i(1)) / 2;
|
||||||
scissor.p1 = Rml::Math::Max(scissor.p1 / 2, scissor.p0);
|
scissor.p1 = Rml::Math::Max(scissor.p1 / 2, scissor.p0);
|
||||||
@@ -223,6 +309,18 @@ gfx::PipelineRef blit_pipeline(wgpu::TextureFormat colorFormat, uint32_t sampleC
|
|||||||
blend ? BlendMode::Premultiplied : BlendMode::None));
|
blend ? BlendMode::Premultiplied : BlendMode::None));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gfx::PipelineRef simple_filter_pipeline(wgpu::TextureFormat colorFormat, uint32_t sampleCount,
|
||||||
|
WebGPURenderInterface::BlitPipelineType type, bool useStencil) {
|
||||||
|
const bool blend = type == WebGPURenderInterface::BlitPipelineType::Blend ||
|
||||||
|
type == WebGPURenderInterface::BlitPipelineType::BlendMasked;
|
||||||
|
const bool masked = type == WebGPURenderInterface::BlitPipelineType::BlendMasked ||
|
||||||
|
type == WebGPURenderInterface::BlitPipelineType::ReplaceMasked;
|
||||||
|
return gfx::pipeline_ref(
|
||||||
|
make_pipeline_config(PipelineKind::SimpleFilter, colorFormat, sampleCount, VertexLayoutKind::Fullscreen,
|
||||||
|
masked ? StencilMode::EqualKeep : (useStencil ? StencilMode::AlwaysKeep : StencilMode::None),
|
||||||
|
blend ? BlendMode::Premultiplied : BlendMode::None));
|
||||||
|
}
|
||||||
|
|
||||||
gfx::PipelineRef seed_resample_pipeline(wgpu::TextureFormat colorFormat, uint32_t sampleCount, bool useStencil) {
|
gfx::PipelineRef seed_resample_pipeline(wgpu::TextureFormat colorFormat, uint32_t sampleCount, bool useStencil) {
|
||||||
return gfx::pipeline_ref(
|
return gfx::pipeline_ref(
|
||||||
make_pipeline_config(PipelineKind::SeedResample, colorFormat, sampleCount, VertexLayoutKind::Fullscreen,
|
make_pipeline_config(PipelineKind::SeedResample, colorFormat, sampleCount, VertexLayoutKind::Fullscreen,
|
||||||
@@ -640,6 +738,11 @@ void WebGPURenderInterface::EnsureFrameRenderingStarted() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_frameRenderingStarted = true;
|
m_frameRenderingStarted = true;
|
||||||
|
if (m_baseLayerContent == BaseLayerContent::Transparent) {
|
||||||
|
BeginLayerPass(0, wgpu::LoadOp::Clear, "RmlUi transparent base layer pass", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const auto seedBindGroup = texture_bind_group_ref(m_frameSeedView);
|
const auto seedBindGroup = texture_bind_group_ref(m_frameSeedView);
|
||||||
const auto seedUniformRange = gfx::push_uniform(SeedResampleUniformBlock{
|
const auto seedUniformRange = gfx::push_uniform(SeedResampleUniformBlock{
|
||||||
.samplerMode = sampler_mode(),
|
.samplerMode = sampler_mode(),
|
||||||
@@ -832,9 +935,8 @@ void WebGPURenderInterface::RenderBlur(float sigma, const RenderTarget& sourceDe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPURenderInterface::RenderFilters(Rml::Span<const Rml::CompiledFilterHandle> filters) {
|
size_t WebGPURenderInterface::RenderFilters(Rml::Span<const Rml::CompiledFilterHandle> filters) {
|
||||||
constexpr size_t sourceIndex = 0;
|
size_t sourceIndex = 0;
|
||||||
constexpr size_t shadowIndex = 1;
|
|
||||||
constexpr size_t tempIndex = 2;
|
constexpr size_t tempIndex = 2;
|
||||||
|
|
||||||
for (Rml::CompiledFilterHandle filterHandle : filters) {
|
for (Rml::CompiledFilterHandle filterHandle : filters) {
|
||||||
@@ -842,22 +944,24 @@ void WebGPURenderInterface::RenderFilters(Rml::Span<const Rml::CompiledFilterHan
|
|||||||
if (filter == nullptr) {
|
if (filter == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
const size_t scratchIndex = sourceIndex == 0 ? 1 : 0;
|
||||||
|
|
||||||
switch (filter->type) {
|
switch (filter->type) {
|
||||||
case FilterType::Opacity: {
|
case FilterType::Opacity: {
|
||||||
BeginRenderTargetPass(m_postprocessTargets[shadowIndex].view, wgpu::LoadOp::Clear, "RmlUi opacity pass");
|
const SimpleFilterUniformBlock simpleFilterUniform{
|
||||||
|
.matrix = to_shader_matrix(Rml::Matrix4f::Identity()),
|
||||||
|
.opacity = {filter->opacity, 0.f, 0.f, 0.f},
|
||||||
|
};
|
||||||
|
const auto simpleFilterRange = gfx::push_uniform(simpleFilterUniform);
|
||||||
|
BeginRenderTargetPass(m_postprocessTargets[scratchIndex].view, wgpu::LoadOp::Clear, "RmlUi opacity pass");
|
||||||
DrawFullscreenTexture(texture_bind_group_ref(m_postprocessTargets[sourceIndex].view),
|
DrawFullscreenTexture(texture_bind_group_ref(m_postprocessTargets[sourceIndex].view),
|
||||||
filter_pipeline(PipelineKind::Opacity, m_renderTargetFormat, VertexLayoutKind::Fullscreen,
|
filter_pipeline(PipelineKind::SimpleFilter, m_renderTargetFormat), uniform_bind_group_ref(),
|
||||||
BlendMode::Opacity),
|
simpleFilterRange);
|
||||||
0, {}, true, {filter->opacity, filter->opacity, filter->opacity, filter->opacity}, true);
|
sourceIndex = scratchIndex;
|
||||||
CompositeToTarget(texture_bind_group_ref(m_postprocessTargets[shadowIndex].view),
|
|
||||||
m_postprocessTargets[sourceIndex].view, wgpu::LoadOp::Clear,
|
|
||||||
blit_pipeline(m_renderTargetFormat, 1, BlitPipelineType::Replace, false),
|
|
||||||
"RmlUi opacity result copy pass");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FilterType::Blur:
|
case FilterType::Blur:
|
||||||
RenderBlur(filter->sigma, m_postprocessTargets[sourceIndex], m_postprocessTargets[shadowIndex]);
|
RenderBlur(filter->sigma, m_postprocessTargets[sourceIndex], m_postprocessTargets[tempIndex]);
|
||||||
break;
|
break;
|
||||||
case FilterType::DropShadow: {
|
case FilterType::DropShadow: {
|
||||||
TexCoordLimits texCoordLimits = GetPostprocessTexCoordLimits();
|
TexCoordLimits texCoordLimits = GetPostprocessTexCoordLimits();
|
||||||
@@ -883,58 +987,52 @@ void WebGPURenderInterface::RenderFilters(Rml::Span<const Rml::CompiledFilterHan
|
|||||||
};
|
};
|
||||||
const auto dropShadowRange = gfx::push_uniform(dropShadowUniform);
|
const auto dropShadowRange = gfx::push_uniform(dropShadowUniform);
|
||||||
CompositeToTarget(texture_bind_group_ref(m_postprocessTargets[sourceIndex].view),
|
CompositeToTarget(texture_bind_group_ref(m_postprocessTargets[sourceIndex].view),
|
||||||
m_postprocessTargets[shadowIndex].view, wgpu::LoadOp::Clear,
|
m_postprocessTargets[scratchIndex].view, wgpu::LoadOp::Clear,
|
||||||
filter_pipeline(PipelineKind::DropShadow, m_renderTargetFormat), "RmlUi drop shadow pass",
|
filter_pipeline(PipelineKind::DropShadow, m_renderTargetFormat), "RmlUi drop shadow pass",
|
||||||
uniform_bind_group_ref(), dropShadowRange);
|
uniform_bind_group_ref(), dropShadowRange);
|
||||||
|
|
||||||
RenderBlur(filter->sigma, m_postprocessTargets[shadowIndex], m_postprocessTargets[tempIndex]);
|
RenderBlur(filter->sigma, m_postprocessTargets[scratchIndex], m_postprocessTargets[tempIndex]);
|
||||||
|
|
||||||
CompositeToTarget(texture_bind_group_ref(m_postprocessTargets[sourceIndex].view),
|
CompositeToTarget(texture_bind_group_ref(m_postprocessTargets[sourceIndex].view),
|
||||||
m_postprocessTargets[shadowIndex].view, wgpu::LoadOp::Load,
|
m_postprocessTargets[scratchIndex].view, wgpu::LoadOp::Load,
|
||||||
blit_pipeline(m_renderTargetFormat, 1, BlitPipelineType::Blend, false),
|
blit_pipeline(m_renderTargetFormat, 1, BlitPipelineType::Blend, false),
|
||||||
"RmlUi drop shadow source composite pass");
|
"RmlUi drop shadow source composite pass");
|
||||||
CompositeToTarget(texture_bind_group_ref(m_postprocessTargets[shadowIndex].view),
|
sourceIndex = scratchIndex;
|
||||||
m_postprocessTargets[sourceIndex].view, wgpu::LoadOp::Clear,
|
|
||||||
blit_pipeline(m_renderTargetFormat, 1, BlitPipelineType::Replace, false),
|
|
||||||
"RmlUi drop shadow result copy pass");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FilterType::ColorMatrix: {
|
case FilterType::ColorMatrix: {
|
||||||
const ColorMatrixUniformBlock colorMatrixUniform{
|
const SimpleFilterUniformBlock simpleFilterUniform{
|
||||||
.matrix = to_shader_matrix(filter->colorMatrix),
|
.matrix = to_shader_matrix(filter->colorMatrix),
|
||||||
|
.opacity = {1.f, 0.f, 0.f, 0.f},
|
||||||
};
|
};
|
||||||
const auto colorMatrixRange = gfx::push_uniform(colorMatrixUniform);
|
const auto simpleFilterRange = gfx::push_uniform(simpleFilterUniform);
|
||||||
|
|
||||||
CompositeToTarget(texture_bind_group_ref(m_postprocessTargets[sourceIndex].view),
|
CompositeToTarget(texture_bind_group_ref(m_postprocessTargets[sourceIndex].view),
|
||||||
m_postprocessTargets[shadowIndex].view, wgpu::LoadOp::Clear,
|
m_postprocessTargets[scratchIndex].view, wgpu::LoadOp::Clear,
|
||||||
filter_pipeline(PipelineKind::ColorMatrix, m_renderTargetFormat), "RmlUi color matrix pass",
|
filter_pipeline(PipelineKind::SimpleFilter, m_renderTargetFormat), "RmlUi color matrix pass",
|
||||||
uniform_bind_group_ref(), colorMatrixRange);
|
uniform_bind_group_ref(), simpleFilterRange);
|
||||||
CompositeToTarget(texture_bind_group_ref(m_postprocessTargets[shadowIndex].view),
|
sourceIndex = scratchIndex;
|
||||||
m_postprocessTargets[sourceIndex].view, wgpu::LoadOp::Clear,
|
|
||||||
blit_pipeline(m_renderTargetFormat, 1, BlitPipelineType::Replace, false),
|
|
||||||
"RmlUi color matrix result copy pass");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FilterType::MaskImage: {
|
case FilterType::MaskImage: {
|
||||||
CompositeToTarget(texture_bind_group_ref(m_postprocessTargets[sourceIndex].view),
|
CompositeToTarget(texture_bind_group_ref(m_postprocessTargets[sourceIndex].view),
|
||||||
m_postprocessTargets[shadowIndex].view, wgpu::LoadOp::Clear,
|
m_postprocessTargets[scratchIndex].view, wgpu::LoadOp::Clear,
|
||||||
filter_pipeline(PipelineKind::MaskImage, m_renderTargetFormat), "RmlUi mask image pass",
|
filter_pipeline(PipelineKind::MaskImage, m_renderTargetFormat), "RmlUi mask image pass",
|
||||||
texture_bind_group_ref(m_blendMaskTarget.view), {}, false);
|
texture_bind_group_ref(m_blendMaskTarget.view), {}, false);
|
||||||
CompositeToTarget(texture_bind_group_ref(m_postprocessTargets[shadowIndex].view),
|
sourceIndex = scratchIndex;
|
||||||
m_postprocessTargets[sourceIndex].view, wgpu::LoadOp::Clear,
|
|
||||||
blit_pipeline(m_renderTargetFormat, 1, BlitPipelineType::Replace, false),
|
|
||||||
"RmlUi mask image result copy pass");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EndActivePass();
|
EndActivePass();
|
||||||
|
return sourceIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPURenderInterface::BeginFrame(const webgpu::TextureWithSampler& target,
|
void WebGPURenderInterface::BeginFrame(const webgpu::TextureWithSampler& target,
|
||||||
const webgpu::TextureWithSampler& seedTarget) {
|
const webgpu::TextureWithSampler& sceneTarget,
|
||||||
m_frameSeedView = seedTarget.view;
|
BaseLayerContent baseLayerContent) {
|
||||||
|
m_frameSeedView = sceneTarget.view;
|
||||||
m_frameSize = target.size;
|
m_frameSize = target.size;
|
||||||
m_viewport = {
|
m_viewport = {
|
||||||
.left = 0.f,
|
.left = 0.f,
|
||||||
@@ -950,6 +1048,7 @@ void WebGPURenderInterface::BeginFrame(const webgpu::TextureWithSampler& target,
|
|||||||
m_frameRenderingStarted = false;
|
m_frameRenderingStarted = false;
|
||||||
m_frameActive = true;
|
m_frameActive = true;
|
||||||
m_passActive = false;
|
m_passActive = false;
|
||||||
|
m_baseLayerContent = baseLayerContent;
|
||||||
|
|
||||||
NewFrame();
|
NewFrame();
|
||||||
EnsureFrameTargets(target.size);
|
EnsureFrameTargets(target.size);
|
||||||
@@ -998,6 +1097,7 @@ bool WebGPURenderInterface::EndFrame() {
|
|||||||
m_frameActive = false;
|
m_frameActive = false;
|
||||||
m_frameSeedView = {};
|
m_frameSeedView = {};
|
||||||
m_frameRenderingStarted = false;
|
m_frameRenderingStarted = false;
|
||||||
|
m_baseLayerContent = BaseLayerContent::Transparent;
|
||||||
return rendered;
|
return rendered;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1024,17 +1124,52 @@ void WebGPURenderInterface::CompositeLayers(Rml::LayerHandle source, Rml::LayerH
|
|||||||
}
|
}
|
||||||
|
|
||||||
EnsureFrameRenderingStarted();
|
EnsureFrameRenderingStarted();
|
||||||
CompositeToTarget(texture_bind_group_ref(m_layers[source].view), m_postprocessTargets[0].view, wgpu::LoadOp::Clear,
|
|
||||||
blit_pipeline(m_renderTargetFormat, 1, BlitPipelineType::Replace, false), "RmlUi layer copy pass");
|
|
||||||
const Rml::LayerHandle topLayer = m_layerStack.empty() ? 0 : m_layerStack.back();
|
const Rml::LayerHandle topLayer = m_layerStack.empty() ? 0 : m_layerStack.back();
|
||||||
RenderFilters(filters);
|
const std::vector<Rml::CompiledFilterHandle> activeFilterHandles = active_filters(filters);
|
||||||
|
const Rml::Span activeFilters{activeFilterHandles.data(), activeFilterHandles.size()};
|
||||||
|
|
||||||
const bool replace = blendMode == Rml::BlendMode::Replace;
|
const bool replace = blendMode == Rml::BlendMode::Replace;
|
||||||
const BlitPipelineType pipelineType =
|
const BlitPipelineType pipelineType =
|
||||||
replace ? (m_clipMaskEnabled ? BlitPipelineType::ReplaceMasked : BlitPipelineType::Replace)
|
replace ? (m_clipMaskEnabled ? BlitPipelineType::ReplaceMasked : BlitPipelineType::Replace)
|
||||||
: (m_clipMaskEnabled ? BlitPipelineType::BlendMasked : BlitPipelineType::Blend);
|
: (m_clipMaskEnabled ? BlitPipelineType::BlendMasked : BlitPipelineType::Blend);
|
||||||
|
if (activeFilters.empty() && source != destination) {
|
||||||
|
BeginLayerPass(destination, wgpu::LoadOp::Load, "RmlUi layer direct composite pass");
|
||||||
|
DrawFullscreenTexture(texture_bind_group_ref(m_layers[source].view),
|
||||||
|
blit_pipeline(m_renderTargetFormat, LayerSampleCount, pipelineType, true));
|
||||||
|
|
||||||
|
if (destination != topLayer) {
|
||||||
|
EndActivePass();
|
||||||
|
m_activeLayer = topLayer;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::Matrix4f simpleFilterMatrix;
|
||||||
|
float simpleFilterOpacity = 1.f;
|
||||||
|
if (source != destination && try_fold_simple_filters(activeFilters, simpleFilterMatrix, simpleFilterOpacity)) {
|
||||||
|
const SimpleFilterUniformBlock simpleFilterUniform{
|
||||||
|
.matrix = to_shader_matrix(simpleFilterMatrix),
|
||||||
|
.opacity = {simpleFilterOpacity, 0.f, 0.f, 0.f},
|
||||||
|
};
|
||||||
|
const auto simpleFilterRange = gfx::push_uniform(simpleFilterUniform);
|
||||||
|
BeginLayerPass(destination, wgpu::LoadOp::Load, "RmlUi simple filter composite pass");
|
||||||
|
DrawFullscreenTexture(texture_bind_group_ref(m_layers[source].view),
|
||||||
|
simple_filter_pipeline(m_renderTargetFormat, LayerSampleCount, pipelineType, true),
|
||||||
|
uniform_bind_group_ref(), simpleFilterRange);
|
||||||
|
|
||||||
|
if (destination != topLayer) {
|
||||||
|
EndActivePass();
|
||||||
|
m_activeLayer = topLayer;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CompositeToTarget(texture_bind_group_ref(m_layers[source].view), m_postprocessTargets[0].view, wgpu::LoadOp::Clear,
|
||||||
|
blit_pipeline(m_renderTargetFormat, 1, BlitPipelineType::Replace, false), "RmlUi layer copy pass");
|
||||||
|
const size_t filteredIndex = RenderFilters(activeFilters);
|
||||||
|
|
||||||
BeginLayerPass(destination, wgpu::LoadOp::Load, "RmlUi layer composite pass");
|
BeginLayerPass(destination, wgpu::LoadOp::Load, "RmlUi layer composite pass");
|
||||||
DrawFullscreenTexture(texture_bind_group_ref(m_postprocessTargets[0].view),
|
DrawFullscreenTexture(texture_bind_group_ref(m_postprocessTargets[filteredIndex].view),
|
||||||
blit_pipeline(m_renderTargetFormat, LayerSampleCount, pipelineType, true));
|
blit_pipeline(m_renderTargetFormat, LayerSampleCount, pipelineType, true));
|
||||||
|
|
||||||
if (destination != topLayer) {
|
if (destination != topLayer) {
|
||||||
|
|||||||
@@ -41,8 +41,9 @@ struct DropShadowUniformBlock {
|
|||||||
Rml::Vector2f texCoordMax;
|
Rml::Vector2f texCoordMax;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ColorMatrixUniformBlock {
|
struct SimpleFilterUniformBlock {
|
||||||
Rml::ColumnMajorMatrix4f matrix;
|
Rml::ColumnMajorMatrix4f matrix;
|
||||||
|
Rml::Vector4f opacity;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GradientUniformBlock {
|
struct GradientUniformBlock {
|
||||||
@@ -60,6 +61,11 @@ struct TexCoordLimits {
|
|||||||
Rml::Vector2f max;
|
Rml::Vector2f max;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class BaseLayerContent {
|
||||||
|
Transparent,
|
||||||
|
Scene,
|
||||||
|
};
|
||||||
|
|
||||||
class WebGPURenderInterface : public Rml::RenderInterface {
|
class WebGPURenderInterface : public Rml::RenderInterface {
|
||||||
public:
|
public:
|
||||||
static constexpr wgpu::TextureFormat ClipMaskStencilFormat = wgpu::TextureFormat::Stencil8;
|
static constexpr wgpu::TextureFormat ClipMaskStencilFormat = wgpu::TextureFormat::Stencil8;
|
||||||
@@ -81,14 +87,6 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class FilterType {
|
|
||||||
Opacity,
|
|
||||||
Blur,
|
|
||||||
DropShadow,
|
|
||||||
ColorMatrix,
|
|
||||||
MaskImage,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RenderTarget {
|
struct RenderTarget {
|
||||||
wgpu::Texture texture;
|
wgpu::Texture texture;
|
||||||
wgpu::TextureView view;
|
wgpu::TextureView view;
|
||||||
@@ -97,15 +95,6 @@ private:
|
|||||||
wgpu::Extent3D size;
|
wgpu::Extent3D size;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CompiledFilter {
|
|
||||||
FilterType type = FilterType::Blur;
|
|
||||||
float opacity = 1.f;
|
|
||||||
float sigma = 0.f;
|
|
||||||
Rml::Vector2f offset;
|
|
||||||
Rml::ColourbPremultiplied color;
|
|
||||||
Rml::Matrix4f colorMatrix;
|
|
||||||
};
|
|
||||||
|
|
||||||
wgpu::TextureView m_frameSeedView;
|
wgpu::TextureView m_frameSeedView;
|
||||||
|
|
||||||
wgpu::TextureFormat m_renderTargetFormat = wgpu::TextureFormat::Undefined;
|
wgpu::TextureFormat m_renderTargetFormat = wgpu::TextureFormat::Undefined;
|
||||||
@@ -120,10 +109,11 @@ private:
|
|||||||
Rml::Vector2i m_clipResetGeometrySize{};
|
Rml::Vector2i m_clipResetGeometrySize{};
|
||||||
std::vector<RenderTarget> m_layers;
|
std::vector<RenderTarget> m_layers;
|
||||||
std::array<RenderTarget, 3> m_postprocessTargets{};
|
std::array<RenderTarget, 3> m_postprocessTargets{};
|
||||||
RenderTarget m_blendMaskTarget;
|
RenderTarget m_blendMaskTarget{};
|
||||||
std::vector<Rml::LayerHandle> m_layerStack;
|
std::vector<Rml::LayerHandle> m_layerStack;
|
||||||
Rml::LayerHandle m_activeLayer = 0;
|
Rml::LayerHandle m_activeLayer = 0;
|
||||||
Rml::LayerHandle m_nextLayer = 1;
|
Rml::LayerHandle m_nextLayer = 1;
|
||||||
|
BaseLayerContent m_baseLayerContent = BaseLayerContent::Transparent;
|
||||||
|
|
||||||
Rml::Vector2i m_windowSize{};
|
Rml::Vector2i m_windowSize{};
|
||||||
Rml::Matrix4f m_translationMatrix = Rml::Matrix4f::Identity();
|
Rml::Matrix4f m_translationMatrix = Rml::Matrix4f::Identity();
|
||||||
@@ -169,7 +159,7 @@ private:
|
|||||||
gfx::Range extraUniformRange = {}, bool extraBindGroupHasDynamicOffset = true,
|
gfx::Range extraUniformRange = {}, bool extraBindGroupHasDynamicOffset = true,
|
||||||
std::array<float, 4> blendConstant = {}, bool hasBlendConstant = false);
|
std::array<float, 4> blendConstant = {}, bool hasBlendConstant = false);
|
||||||
void RenderBlur(float sigma, const RenderTarget& sourceDestination, const RenderTarget& temp);
|
void RenderBlur(float sigma, const RenderTarget& sourceDestination, const RenderTarget& temp);
|
||||||
void RenderFilters(Rml::Span<const Rml::CompiledFilterHandle> filters);
|
size_t RenderFilters(Rml::Span<const Rml::CompiledFilterHandle> filters);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Rml::CompiledGeometryHandle CompileGeometry(Rml::Span<const Rml::Vertex> vertices,
|
Rml::CompiledGeometryHandle CompileGeometry(Rml::Span<const Rml::Vertex> vertices,
|
||||||
@@ -199,7 +189,8 @@ public:
|
|||||||
Rml::TextureHandle texture) override;
|
Rml::TextureHandle texture) override;
|
||||||
void ReleaseShader(Rml::CompiledShaderHandle shader) override;
|
void ReleaseShader(Rml::CompiledShaderHandle shader) override;
|
||||||
|
|
||||||
void BeginFrame(const webgpu::TextureWithSampler& target, const webgpu::TextureWithSampler& seed_target);
|
void BeginFrame(const webgpu::TextureWithSampler& target, const webgpu::TextureWithSampler& scene_target,
|
||||||
|
BaseLayerContent baseLayerContent);
|
||||||
bool EndFrame();
|
bool EndFrame();
|
||||||
void SetWindowSize(const Rml::Vector2i& window_size) { m_windowSize = window_size; }
|
void SetWindowSize(const Rml::Vector2i& window_size) { m_windowSize = window_size; }
|
||||||
void SetRenderTargetFormat(wgpu::TextureFormat render_target_format) { m_renderTargetFormat = render_target_format; }
|
void SetRenderTargetFormat(wgpu::TextureFormat render_target_format) { m_renderTargetFormat = render_target_format; }
|
||||||
|
|||||||
+11
-27
@@ -24,8 +24,8 @@ constexpr uint32_t DynamicGroup2 = 1u << 2u;
|
|||||||
|
|
||||||
constexpr uint64_t CommonUniformBindingSize = AURORA_ALIGN(sizeof(UniformBlock), 16);
|
constexpr uint64_t CommonUniformBindingSize = AURORA_ALIGN(sizeof(UniformBlock), 16);
|
||||||
constexpr uint64_t ExtraUniformBindingSize =
|
constexpr uint64_t ExtraUniformBindingSize =
|
||||||
AURORA_ALIGN(std::max({sizeof(BlurUniformBlock), sizeof(DropShadowUniformBlock), sizeof(ColorMatrixUniformBlock),
|
AURORA_ALIGN(std::max({sizeof(BlurUniformBlock), sizeof(DropShadowUniformBlock), sizeof(SimpleFilterUniformBlock),
|
||||||
sizeof(GradientUniformBlock), sizeof(SeedResampleUniformBlock)}),
|
sizeof(GradientUniforzxmBlock), sizeof(SeedResampleUniformBlock)}),
|
||||||
16);
|
16);
|
||||||
|
|
||||||
constexpr std::string_view vertexSource = R"(
|
constexpr std::string_view vertexSource = R"(
|
||||||
@@ -367,20 +367,21 @@ fn main(@builtin(position) position: vec4<f32>, @location(0) uv: vec2<f32>) -> @
|
|||||||
}
|
}
|
||||||
)"sv;
|
)"sv;
|
||||||
|
|
||||||
constexpr std::string_view colorMatrixFragmentSource = R"(
|
constexpr std::string_view simpleFilterFragmentSource = R"(
|
||||||
struct ColorMatrixUniforms {
|
struct SimpleFilterUniforms {
|
||||||
matrix: mat4x4<f32>,
|
matrix: mat4x4<f32>,
|
||||||
|
opacity: vec4<f32>,
|
||||||
};
|
};
|
||||||
|
|
||||||
@group(0) @binding(1) var s: sampler;
|
@group(0) @binding(1) var s: sampler;
|
||||||
@group(1) @binding(0) var t: texture_2d<f32>;
|
@group(1) @binding(0) var t: texture_2d<f32>;
|
||||||
@group(2) @binding(0) var<uniform> color_matrix: ColorMatrixUniforms;
|
@group(2) @binding(0) var<uniform> simple_filter: SimpleFilterUniforms;
|
||||||
|
|
||||||
@fragment
|
@fragment
|
||||||
fn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {
|
fn main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {
|
||||||
let tex_color = textureSample(t, s, uv);
|
let tex_color = textureSample(t, s, uv);
|
||||||
let transformed_color = (color_matrix.matrix * tex_color).rgb;
|
let transformed_color = simple_filter.matrix * tex_color;
|
||||||
return vec4<f32>(transformed_color, tex_color.a);
|
return vec4<f32>(transformed_color.rgb, tex_color.a) * simple_filter.opacity.x;
|
||||||
}
|
}
|
||||||
)"sv;
|
)"sv;
|
||||||
|
|
||||||
@@ -511,21 +512,6 @@ wgpu::BlendState blend_state(BlendMode mode) {
|
|||||||
.dstFactor = wgpu::BlendFactor::OneMinusSrcAlpha,
|
.dstFactor = wgpu::BlendFactor::OneMinusSrcAlpha,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
case BlendMode::Opacity:
|
|
||||||
return {
|
|
||||||
.color =
|
|
||||||
{
|
|
||||||
.operation = wgpu::BlendOperation::Add,
|
|
||||||
.srcFactor = wgpu::BlendFactor::Constant,
|
|
||||||
.dstFactor = wgpu::BlendFactor::Zero,
|
|
||||||
},
|
|
||||||
.alpha =
|
|
||||||
{
|
|
||||||
.operation = wgpu::BlendOperation::Add,
|
|
||||||
.srcFactor = wgpu::BlendFactor::Constant,
|
|
||||||
.dstFactor = wgpu::BlendFactor::Zero,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
case BlendMode::None:
|
case BlendMode::None:
|
||||||
default:
|
default:
|
||||||
return {};
|
return {};
|
||||||
@@ -548,7 +534,7 @@ const wgpu::PipelineLayout create_pipeline_layout(PipelineKind kind) {
|
|||||||
case PipelineKind::Blur:
|
case PipelineKind::Blur:
|
||||||
case PipelineKind::RegionBlit:
|
case PipelineKind::RegionBlit:
|
||||||
case PipelineKind::DropShadow:
|
case PipelineKind::DropShadow:
|
||||||
case PipelineKind::ColorMatrix:
|
case PipelineKind::SimpleFilter:
|
||||||
case PipelineKind::SeedResample:
|
case PipelineKind::SeedResample:
|
||||||
layouts[layoutCount++] = g_imageBindGroupLayout;
|
layouts[layoutCount++] = g_imageBindGroupLayout;
|
||||||
layouts[layoutCount++] = g_uniformBindGroupLayout;
|
layouts[layoutCount++] = g_uniformBindGroupLayout;
|
||||||
@@ -556,7 +542,6 @@ const wgpu::PipelineLayout create_pipeline_layout(PipelineKind kind) {
|
|||||||
case PipelineKind::Geometry:
|
case PipelineKind::Geometry:
|
||||||
case PipelineKind::Blit:
|
case PipelineKind::Blit:
|
||||||
case PipelineKind::OpaqueBlit:
|
case PipelineKind::OpaqueBlit:
|
||||||
case PipelineKind::Opacity:
|
|
||||||
default:
|
default:
|
||||||
layouts[layoutCount++] = g_imageBindGroupLayout;
|
layouts[layoutCount++] = g_imageBindGroupLayout;
|
||||||
break;
|
break;
|
||||||
@@ -585,12 +570,11 @@ const std::string_view fragment_source(PipelineKind kind) {
|
|||||||
return regionBlitFragmentSource;
|
return regionBlitFragmentSource;
|
||||||
case PipelineKind::DropShadow:
|
case PipelineKind::DropShadow:
|
||||||
return dropShadowFragmentSource;
|
return dropShadowFragmentSource;
|
||||||
case PipelineKind::ColorMatrix:
|
case PipelineKind::SimpleFilter:
|
||||||
return colorMatrixFragmentSource;
|
return simpleFilterFragmentSource;
|
||||||
case PipelineKind::MaskImage:
|
case PipelineKind::MaskImage:
|
||||||
return maskImageFragmentSource;
|
return maskImageFragmentSource;
|
||||||
case PipelineKind::Blit:
|
case PipelineKind::Blit:
|
||||||
case PipelineKind::Opacity:
|
|
||||||
default:
|
default:
|
||||||
return blitFragmentSource;
|
return blitFragmentSource;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
namespace aurora::rmlui {
|
namespace aurora::rmlui {
|
||||||
|
|
||||||
constexpr uint32_t RmlPipelineConfigVersion = 1;
|
constexpr uint32_t RmlPipelineConfigVersion = 2;
|
||||||
|
|
||||||
enum class PipelineKind : uint32_t {
|
enum class PipelineKind : uint32_t {
|
||||||
Geometry,
|
Geometry,
|
||||||
@@ -18,11 +18,10 @@ enum class PipelineKind : uint32_t {
|
|||||||
Blit,
|
Blit,
|
||||||
OpaqueBlit,
|
OpaqueBlit,
|
||||||
SeedResample,
|
SeedResample,
|
||||||
Opacity,
|
SimpleFilter,
|
||||||
Blur,
|
Blur,
|
||||||
RegionBlit,
|
RegionBlit,
|
||||||
DropShadow,
|
DropShadow,
|
||||||
ColorMatrix,
|
|
||||||
MaskImage,
|
MaskImage,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -43,7 +42,6 @@ enum class StencilMode : uint32_t {
|
|||||||
enum class BlendMode : uint32_t {
|
enum class BlendMode : uint32_t {
|
||||||
None,
|
None,
|
||||||
Premultiplied,
|
Premultiplied,
|
||||||
Opacity,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class DrawKind : uint32_t {
|
enum class DrawKind : uint32_t {
|
||||||
|
|||||||
+59
-29
@@ -47,6 +47,7 @@ TextureWithSampler g_depthBuffer;
|
|||||||
// EFB -> XFB copy pipeline
|
// EFB -> XFB copy pipeline
|
||||||
static wgpu::BindGroupLayout g_CopyBindGroupLayout;
|
static wgpu::BindGroupLayout g_CopyBindGroupLayout;
|
||||||
wgpu::RenderPipeline g_CopyPipeline;
|
wgpu::RenderPipeline g_CopyPipeline;
|
||||||
|
wgpu::RenderPipeline g_CopyPremultipliedAlphaPipeline;
|
||||||
wgpu::BindGroup g_CopyBindGroup;
|
wgpu::BindGroup g_CopyBindGroup;
|
||||||
static AuroraSampler g_Resampler = SAMPLER_BILINEAR;
|
static AuroraSampler g_Resampler = SAMPLER_BILINEAR;
|
||||||
static wgpu::BindGroupLayout g_ResampleBindGroupLayout;
|
static wgpu::BindGroupLayout g_ResampleBindGroupLayout;
|
||||||
@@ -411,26 +412,21 @@ fn vs_main(@builtin(vertex_index) vtxIdx: u32) -> VertexOutput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@fragment
|
@fragment
|
||||||
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
fn fs_opaque(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||||
let color = textureSample(efb_texture, efb_sampler, in.uv);
|
let color = textureSample(efb_texture, efb_sampler, in.uv);
|
||||||
return vec4(color.rgb, 1.0);
|
return vec4(color.rgb, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@fragment
|
||||||
|
fn fs_premultiplied_alpha(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||||
|
return textureSample(efb_texture, efb_sampler, in.uv);
|
||||||
|
}
|
||||||
)""";
|
)""";
|
||||||
const wgpu::ShaderModuleDescriptor moduleDescriptor{
|
const wgpu::ShaderModuleDescriptor moduleDescriptor{
|
||||||
.nextInChain = &sourceDescriptor,
|
.nextInChain = &sourceDescriptor,
|
||||||
.label = "XFB Copy Module",
|
.label = "XFB Copy Module",
|
||||||
};
|
};
|
||||||
auto module = g_device.CreateShaderModule(&moduleDescriptor);
|
auto module = g_device.CreateShaderModule(&moduleDescriptor);
|
||||||
const std::array colorTargets{wgpu::ColorTargetState{
|
|
||||||
.format = g_graphicsConfig.surfaceConfiguration.format,
|
|
||||||
.writeMask = wgpu::ColorWriteMask::All,
|
|
||||||
}};
|
|
||||||
const wgpu::FragmentState fragmentState{
|
|
||||||
.module = module,
|
|
||||||
.entryPoint = "fs_main",
|
|
||||||
.targetCount = colorTargets.size(),
|
|
||||||
.targets = colorTargets.data(),
|
|
||||||
};
|
|
||||||
const std::array bindGroupLayoutEntries{
|
const std::array bindGroupLayoutEntries{
|
||||||
wgpu::BindGroupLayoutEntry{
|
wgpu::BindGroupLayoutEntry{
|
||||||
.binding = 0,
|
.binding = 0,
|
||||||
@@ -460,25 +456,58 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
|||||||
.bindGroupLayouts = &g_CopyBindGroupLayout,
|
.bindGroupLayouts = &g_CopyBindGroupLayout,
|
||||||
};
|
};
|
||||||
auto pipelineLayout = g_device.CreatePipelineLayout(&layoutDescriptor);
|
auto pipelineLayout = g_device.CreatePipelineLayout(&layoutDescriptor);
|
||||||
const wgpu::RenderPipelineDescriptor pipelineDescriptor{
|
|
||||||
.layout = pipelineLayout,
|
const auto make_copy_pipeline = [&](const char* label, const char* fragmentEntryPoint, const wgpu::BlendState* blend) {
|
||||||
.vertex =
|
const std::array colorTargets{wgpu::ColorTargetState{
|
||||||
wgpu::VertexState{
|
.format = g_graphicsConfig.surfaceConfiguration.format,
|
||||||
.module = module,
|
.blend = blend,
|
||||||
.entryPoint = "vs_main",
|
.writeMask = wgpu::ColorWriteMask::All,
|
||||||
},
|
}};
|
||||||
.primitive =
|
const wgpu::FragmentState fragmentState{
|
||||||
wgpu::PrimitiveState{
|
.module = module,
|
||||||
.topology = wgpu::PrimitiveTopology::TriangleList,
|
.entryPoint = fragmentEntryPoint,
|
||||||
},
|
.targetCount = colorTargets.size(),
|
||||||
.multisample =
|
.targets = colorTargets.data(),
|
||||||
wgpu::MultisampleState{
|
};
|
||||||
.count = 1,
|
const wgpu::RenderPipelineDescriptor pipelineDescriptor{
|
||||||
.mask = UINT32_MAX,
|
.label = label,
|
||||||
},
|
.layout = pipelineLayout,
|
||||||
.fragment = &fragmentState,
|
.vertex =
|
||||||
|
wgpu::VertexState{
|
||||||
|
.module = module,
|
||||||
|
.entryPoint = "vs_main",
|
||||||
|
},
|
||||||
|
.primitive =
|
||||||
|
wgpu::PrimitiveState{
|
||||||
|
.topology = wgpu::PrimitiveTopology::TriangleList,
|
||||||
|
},
|
||||||
|
.multisample =
|
||||||
|
wgpu::MultisampleState{
|
||||||
|
.count = 1,
|
||||||
|
.mask = UINT32_MAX,
|
||||||
|
},
|
||||||
|
.fragment = &fragmentState,
|
||||||
|
};
|
||||||
|
return g_device.CreateRenderPipeline(&pipelineDescriptor);
|
||||||
};
|
};
|
||||||
g_CopyPipeline = g_device.CreateRenderPipeline(&pipelineDescriptor);
|
g_CopyPipeline = make_copy_pipeline("XFB Copy Pipeline", "fs_opaque", nullptr);
|
||||||
|
|
||||||
|
const wgpu::BlendState premultipliedAlphaBlend{
|
||||||
|
.color =
|
||||||
|
{
|
||||||
|
.operation = wgpu::BlendOperation::Add,
|
||||||
|
.srcFactor = wgpu::BlendFactor::One,
|
||||||
|
.dstFactor = wgpu::BlendFactor::OneMinusSrcAlpha,
|
||||||
|
},
|
||||||
|
.alpha =
|
||||||
|
{
|
||||||
|
.operation = wgpu::BlendOperation::Add,
|
||||||
|
.srcFactor = wgpu::BlendFactor::One,
|
||||||
|
.dstFactor = wgpu::BlendFactor::OneMinusSrcAlpha,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
g_CopyPremultipliedAlphaPipeline =
|
||||||
|
make_copy_pipeline("XFB Premultiplied Alpha Copy Pipeline", "fs_premultiplied_alpha", &premultipliedAlphaBlend);
|
||||||
}
|
}
|
||||||
|
|
||||||
void create_resample_pipeline() {
|
void create_resample_pipeline() {
|
||||||
@@ -983,6 +1012,7 @@ void shutdown() {
|
|||||||
gpu_prof::shutdown();
|
gpu_prof::shutdown();
|
||||||
g_CopyBindGroupLayout = {};
|
g_CopyBindGroupLayout = {};
|
||||||
g_CopyPipeline = {};
|
g_CopyPipeline = {};
|
||||||
|
g_CopyPremultipliedAlphaPipeline = {};
|
||||||
g_CopyBindGroup = {};
|
g_CopyBindGroup = {};
|
||||||
g_ResampleBindGroupLayout = {};
|
g_ResampleBindGroupLayout = {};
|
||||||
g_ResamplePipeline = {};
|
g_ResamplePipeline = {};
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ extern TextureWithSampler g_frameBuffer;
|
|||||||
extern TextureWithSampler g_frameBufferResolved;
|
extern TextureWithSampler g_frameBufferResolved;
|
||||||
extern TextureWithSampler g_depthBuffer;
|
extern TextureWithSampler g_depthBuffer;
|
||||||
extern wgpu::RenderPipeline g_CopyPipeline;
|
extern wgpu::RenderPipeline g_CopyPipeline;
|
||||||
|
extern wgpu::RenderPipeline g_CopyPremultipliedAlphaPipeline;
|
||||||
extern wgpu::BindGroup g_CopyBindGroup;
|
extern wgpu::BindGroup g_CopyBindGroup;
|
||||||
extern wgpu::Instance g_instance;
|
extern wgpu::Instance g_instance;
|
||||||
extern wgpu::AdapterInfo g_adapterInfo;
|
extern wgpu::AdapterInfo g_adapterInfo;
|
||||||
|
|||||||
Reference in New Issue
Block a user