Bug 1505871. C++ code to get component transfer filter data into webrender. r=jrmuizel

Have to use a pointer/size pair to transfer the value list to rust.

We use a "filter holder" that contains an nsTArray that owns the values.
This commit is contained in:
Timothy Nikkel 2019-02-25 19:20:26 -06:00
Родитель f7fc71637d
Коммит 17f5b2d751
15 изменённых файлов: 142 добавлений и 42 удалений

Просмотреть файл

@ -12,6 +12,7 @@
#include "mozilla/webrender/WebRenderAPI.h"
#include "mozilla/webrender/WebRenderTypes.h"
#include "Units.h"
#include "nsSVGIntegrationUtils.h" // for WrFiltersHolder
class nsDisplayTransform;

Просмотреть файл

@ -1425,7 +1425,7 @@ void WebRenderCommandBuilder::BuildWebRenderCommands(
wr::DisplayListBuilder& aBuilder,
wr::IpcResourceUpdateQueue& aResourceUpdates, nsDisplayList* aDisplayList,
nsDisplayListBuilder* aDisplayListBuilder, WebRenderScrollData& aScrollData,
wr::LayoutSize& aContentSize, nsTArray<wr::FilterOp>&& aFilters) {
wr::LayoutSize& aContentSize, WrFiltersHolder&& aFilters) {
AUTO_PROFILER_LABEL_CATEGORY_PAIR(GRAPHICS_WRDisplayList);
StackingContextHelper sc;
@ -1451,7 +1451,8 @@ void WebRenderCommandBuilder::BuildWebRenderCommands(
presContext->Document()->IsTopLevelContentDocument();
wr::StackingContextParams params;
params.mFilters = std::move(aFilters);
params.mFilters = std::move(aFilters.filters);
params.mFilterDatas = std::move(aFilters.filter_datas);
params.animation = mZoomProp.ptrOr(nullptr);
params.cache_tiles = isTopLevelContent;
params.clip =

Просмотреть файл

@ -57,7 +57,7 @@ class WebRenderCommandBuilder {
nsDisplayListBuilder* aDisplayListBuilder,
WebRenderScrollData& aScrollData,
wr::LayoutSize& aContentSize,
nsTArray<wr::FilterOp>&& aFilters);
WrFiltersHolder&& aFilters);
void PushOverrideForASR(const ActiveScrolledRoot* aASR,
const wr::WrSpatialId& aSpatialId);

Просмотреть файл

@ -246,7 +246,7 @@ void WebRenderLayerManager::EndTransaction(DrawPaintedLayerCallback aCallback,
void WebRenderLayerManager::EndTransactionWithoutLayer(
nsDisplayList* aDisplayList, nsDisplayListBuilder* aDisplayListBuilder,
nsTArray<wr::FilterOp>&& aFilters, WebRenderBackgroundData* aBackground) {
WrFiltersHolder&& aFilters, WebRenderBackgroundData* aBackground) {
AUTO_PROFILER_TRACING("Paint", "RenderLayers", GRAPHICS);
// Since we don't do repeat transactions right now, just set the time

Просмотреть файл

@ -79,7 +79,7 @@ class WebRenderLayerManager final : public LayerManager {
EndTransactionFlags aFlags = END_DEFAULT) override;
void EndTransactionWithoutLayer(
nsDisplayList* aDisplayList, nsDisplayListBuilder* aDisplayListBuilder,
nsTArray<wr::FilterOp>&& aFilters = nsTArray<wr::FilterOp>(),
WrFiltersHolder&& aFilters = WrFiltersHolder(),
WebRenderBackgroundData* aBackground = nullptr);
virtual void EndTransaction(
DrawPaintedLayerCallback aCallback, void* aCallbackData,

Просмотреть файл

@ -690,7 +690,7 @@ Maybe<wr::WrSpatialId> DisplayListBuilder::PushStackingContext(
auto spatialId = wr_dp_push_stacking_context(
mWrState, aBounds, mCurrentSpaceAndClipChain.space, &aParams,
maybeTransform, aParams.mFilters.Elements(), aParams.mFilters.Length(),
aRasterSpace);
aParams.mFilterDatas.Elements(), aParams.mFilterDatas.Length(), aRasterSpace);
return spatialId.id != 0 ? Some(spatialId) : Nothing();
}

Просмотреть файл

@ -329,6 +329,7 @@ struct MOZ_STACK_CLASS StackingContextParams : public WrStackingContextParams {
}
nsTArray<wr::FilterOp> mFilters;
nsTArray<wr::WrFilterData> mFilterDatas;
wr::LayoutRect mBounds = wr::ToLayoutRect(LayoutDeviceRect());
const gfx::Matrix4x4* mBoundTransform = nullptr;
const gfx::Matrix4x4* mTransformPtr = nullptr;

Просмотреть файл

@ -13,7 +13,7 @@ use std::cell::RefCell;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::ops::Range;
use std::os::raw::{c_void, c_char};
use std::os::raw::{c_void, c_char, c_float};
#[cfg(target_os = "android")]
use std::os::raw::{c_int};
use gleam::gl;
@ -489,6 +489,24 @@ impl ExternalImageHandler for WrExternalImageHandler {
}
}
#[repr(C)]
#[derive(Clone, Copy)]
// Used for ComponentTransfer only
pub struct WrFilterData {
funcR_type: ComponentTransferFuncType,
R_values: *mut c_float,
R_values_count: usize,
funcG_type: ComponentTransferFuncType,
G_values: *mut c_float,
G_values_count: usize,
funcB_type: ComponentTransferFuncType,
B_values: *mut c_float,
B_values_count: usize,
funcA_type: ComponentTransferFuncType,
A_values: *mut c_float,
A_values_count: usize,
}
#[repr(u32)]
pub enum WrAnimationType {
Transform = 0,
@ -1952,6 +1970,8 @@ pub extern "C" fn wr_dp_push_stacking_context(
transform: *const LayoutTransform,
filters: *const FilterOp,
filter_count: usize,
filter_datas: *const WrFilterData,
filter_datas_count: usize,
glyph_raster_space: RasterSpace,
) -> WrSpatialId {
debug_assert!(unsafe { !is_in_render_thread() });

Просмотреть файл

@ -6074,7 +6074,7 @@ void PresShell::Paint(nsView* aViewToPaint, const nsRegion& aDirtyRegion,
bgcolor = NS_ComposeColors(bgcolor, mCanvasBackgroundColor);
WebRenderBackgroundData data(wr::ToLayoutRect(bounds),
wr::ToColorF(ToDeviceColor(bgcolor)));
nsTArray<wr::FilterOp> wrFilters;
WrFiltersHolder wrFilters;
MaybeSetupTransactionIdAllocator(layerManager, presContext);
layerManager->AsWebRenderLayerManager()->EndTransactionWithoutLayer(

Просмотреть файл

@ -2604,11 +2604,11 @@ already_AddRefed<LayerManager> nsDisplayList::PaintRoot(
auto* wrManager = static_cast<WebRenderLayerManager*>(layerManager.get());
nsIDocShell* docShell = presContext->GetDocShell();
nsTArray<wr::FilterOp> wrFilters;
WrFiltersHolder wrFilters;
gfx::Matrix5x4* colorMatrix =
nsDocShell::Cast(docShell)->GetColorMatrix();
if (colorMatrix) {
wrFilters.AppendElement(
wrFilters.filters.AppendElement(
wr::FilterOp::ColorMatrix(colorMatrix->components));
}
@ -9321,7 +9321,7 @@ static float ClampStdDeviation(float aStdDeviation) {
}
bool nsDisplayFilters::CreateWebRenderCSSFilters(
nsTArray<mozilla::wr::FilterOp>& wrFilters) {
WrFiltersHolder& wrFilters) {
// All CSS filters are supported by WebRender. SVG filters are not fully
// supported, those use NS_STYLE_FILTER_URL and are handled separately.
const nsTArray<nsStyleFilter>& filters = mFrame->StyleEffects()->mFilters;
@ -9331,50 +9331,50 @@ bool nsDisplayFilters::CreateWebRenderCSSFilters(
if (filters.Length() > gfxPrefs::WebRenderMaxFilterOpsPerChain()) {
return true;
}
wrFilters.SetCapacity(filters.Length());
wrFilters.filters.SetCapacity(filters.Length());
for (const nsStyleFilter& filter : filters) {
switch (filter.GetType()) {
case NS_STYLE_FILTER_BRIGHTNESS:
wrFilters.AppendElement(wr::FilterOp::Brightness(
wrFilters.filters.AppendElement(wr::FilterOp::Brightness(
filter.GetFilterParameter().GetFactorOrPercentValue()));
break;
case NS_STYLE_FILTER_CONTRAST:
wrFilters.AppendElement(wr::FilterOp::Contrast(
wrFilters.filters.AppendElement(wr::FilterOp::Contrast(
filter.GetFilterParameter().GetFactorOrPercentValue()));
break;
case NS_STYLE_FILTER_GRAYSCALE:
wrFilters.AppendElement(wr::FilterOp::Grayscale(
wrFilters.filters.AppendElement(wr::FilterOp::Grayscale(
filter.GetFilterParameter().GetFactorOrPercentValue()));
break;
case NS_STYLE_FILTER_INVERT:
wrFilters.AppendElement(wr::FilterOp::Invert(
wrFilters.filters.AppendElement(wr::FilterOp::Invert(
filter.GetFilterParameter().GetFactorOrPercentValue()));
break;
case NS_STYLE_FILTER_OPACITY: {
float opacity = filter.GetFilterParameter().GetFactorOrPercentValue();
wrFilters.AppendElement(wr::FilterOp::Opacity(
wrFilters.filters.AppendElement(wr::FilterOp::Opacity(
wr::PropertyBinding<float>::Value(opacity), opacity));
break;
}
case NS_STYLE_FILTER_SATURATE:
wrFilters.AppendElement(wr::FilterOp::Saturate(
wrFilters.filters.AppendElement(wr::FilterOp::Saturate(
filter.GetFilterParameter().GetFactorOrPercentValue()));
break;
case NS_STYLE_FILTER_SEPIA: {
wrFilters.AppendElement(wr::FilterOp::Sepia(
wrFilters.filters.AppendElement(wr::FilterOp::Sepia(
filter.GetFilterParameter().GetFactorOrPercentValue()));
break;
}
case NS_STYLE_FILTER_HUE_ROTATE: {
wrFilters.AppendElement(wr::FilterOp::HueRotate(
wrFilters.filters.AppendElement(wr::FilterOp::HueRotate(
(float)filter.GetFilterParameter().GetAngleValueInDegrees()));
break;
}
case NS_STYLE_FILTER_BLUR: {
float appUnitsPerDevPixel =
mFrame->PresContext()->AppUnitsPerDevPixel();
wrFilters.AppendElement(mozilla::wr::FilterOp::Blur(ClampStdDeviation(
wrFilters.filters.AppendElement(mozilla::wr::FilterOp::Blur(ClampStdDeviation(
NSAppUnitsToFloatPixels(filter.GetFilterParameter().GetCoordValue(),
appUnitsPerDevPixel))));
break;
@ -9406,7 +9406,7 @@ bool nsDisplayFilters::CreateWebRenderCSSFilters(
NS_GET_A(color) / 255.0f,
});
wrFilters.AppendElement(filterOp);
wrFilters.filters.AppendElement(filterOp);
break;
}
default:
@ -9419,7 +9419,7 @@ bool nsDisplayFilters::CreateWebRenderCSSFilters(
bool nsDisplayFilters::CanCreateWebRenderCommands(
nsDisplayListBuilder* aBuilder) {
nsTArray<mozilla::wr::FilterOp> wrFilters;
WrFiltersHolder wrFilters;
Maybe<nsRect> filterClip;
if (!CreateWebRenderCSSFilters(wrFilters) &&
!nsSVGIntegrationUtils::BuildWebRenderFilters(mFrame, wrFilters,
@ -9437,7 +9437,7 @@ bool nsDisplayFilters::CreateWebRenderCommands(
nsDisplayListBuilder* aDisplayListBuilder) {
float auPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
nsTArray<mozilla::wr::FilterOp> wrFilters;
WrFiltersHolder wrFilters;
Maybe<nsRect> filterClip;
if (!CreateWebRenderCSSFilters(wrFilters) &&
!nsSVGIntegrationUtils::BuildWebRenderFilters(mFrame, wrFilters,
@ -9458,7 +9458,8 @@ bool nsDisplayFilters::CreateWebRenderCommands(
float opacity = mFrame->StyleEffects()->mOpacity;
wr::StackingContextParams params;
params.mFilters = std::move(wrFilters);
params.mFilters = std::move(wrFilters.filters);
params.mFilterDatas = std::move(wrFilters.filter_datas);
params.opacity = opacity != 1.0f && mHandleOpacity ? &opacity : nullptr;
params.clip = clip;
StackingContextHelper sc(aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder,

Просмотреть файл

@ -64,6 +64,7 @@ class nsDisplayCompositorHitTestInfo;
class nsDisplayScrollInfoLayer;
class nsCaret;
enum class nsDisplayOwnLayerFlags;
struct WrFiltersHolder;
namespace mozilla {
class FrameLayerBuilder;
@ -6389,7 +6390,7 @@ class nsDisplayFilters : public nsDisplayEffectsBase {
nsDisplayListBuilder* aDisplayListBuilder) override;
bool CanCreateWebRenderCommands(nsDisplayListBuilder* aBuilder);
bool CreateWebRenderCSSFilters(nsTArray<mozilla::wr::FilterOp>& wrFilters);
bool CreateWebRenderCSSFilters(WrFiltersHolder& wrFilters);
private:
// relative to mFrame

Просмотреть файл

@ -95,10 +95,32 @@ void nsFilterInstance::PaintFilteredFrame(
}
}
static mozilla::wr::ComponentTransferFuncType
FuncTypeToWr(uint8_t aFuncType) {
switch (aFuncType) {
case SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY:
return mozilla::wr::ComponentTransferFuncType::Identity;
case SVG_FECOMPONENTTRANSFER_TYPE_TABLE:
return mozilla::wr::ComponentTransferFuncType::Table;
case SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE:
return mozilla::wr::ComponentTransferFuncType::Discrete;
case SVG_FECOMPONENTTRANSFER_TYPE_LINEAR:
return mozilla::wr::ComponentTransferFuncType::Linear;
case SVG_FECOMPONENTTRANSFER_TYPE_GAMMA:
return mozilla::wr::ComponentTransferFuncType::Gamma;
default:
MOZ_ASSERT(false, "unknown func type?");
}
MOZ_ASSERT(false, "unknown func type?");
return mozilla::wr::ComponentTransferFuncType::Identity;
}
bool nsFilterInstance::BuildWebRenderFilters(nsIFrame* aFilteredFrame,
nsTArray<wr::FilterOp>& aWrFilters,
WrFiltersHolder& aWrFilters,
Maybe<nsRect>& aPostFilterClip) {
aWrFilters.Clear();
aWrFilters.filters.Clear();
aWrFilters.filter_datas.Clear();
aWrFilters.values.Clear();
auto& filterChain = aFilteredFrame->StyleEffects()->mFilters;
UniquePtr<UserSpaceMetrics> metrics =
@ -162,9 +184,9 @@ bool nsFilterInstance::BuildWebRenderFilters(nsIFrame* aFilteredFrame,
bool previousSrgb = srgb;
bool primNeedsSrgb = primitive.InputColorSpace(0) == gfx::ColorSpace::SRGB;
if (srgb && !primNeedsSrgb) {
aWrFilters.AppendElement(wr::FilterOp::SrgbToLinear());
aWrFilters.filters.AppendElement(wr::FilterOp::SrgbToLinear());
} else if (!srgb && primNeedsSrgb) {
aWrFilters.AppendElement(wr::FilterOp::LinearToSrgb());
aWrFilters.filters.AppendElement(wr::FilterOp::LinearToSrgb());
}
srgb = primitive.OutputColorSpace() == gfx::ColorSpace::SRGB;
@ -174,7 +196,7 @@ bool nsFilterInstance::BuildWebRenderFilters(nsIFrame* aFilteredFrame,
if (attr.is<OpacityAttributes>()) {
float opacity = attr.as<OpacityAttributes>().mOpacity;
aWrFilters.AppendElement(wr::FilterOp::Opacity(
aWrFilters.filters.AppendElement(wr::FilterOp::Opacity(
wr::PropertyBinding<float>::Value(opacity), opacity));
} else if (attr.is<ColorMatrixAttributes>()) {
const ColorMatrixAttributes& attributes =
@ -207,7 +229,7 @@ bool nsFilterInstance::BuildWebRenderFilters(nsIFrame* aFilteredFrame,
transposed[3], transposed[8], transposed[13], transposed[18],
transposed[4], transposed[9], transposed[14], transposed[19]};
aWrFilters.AppendElement(wr::FilterOp::ColorMatrix(matrix));
aWrFilters.filters.AppendElement(wr::FilterOp::ColorMatrix(matrix));
} else if (attr.is<GaussianBlurAttributes>()) {
if (finalClip) {
// There's a clip that needs to apply before the blur filter, but
@ -226,7 +248,7 @@ bool nsFilterInstance::BuildWebRenderFilters(nsIFrame* aFilteredFrame,
float radius = stdDev.width;
if (radius != 0.0) {
aWrFilters.AppendElement(wr::FilterOp::Blur(radius));
aWrFilters.filters.AppendElement(wr::FilterOp::Blur(radius));
} else {
filterIsNoop = true;
}
@ -255,14 +277,60 @@ bool nsFilterInstance::BuildWebRenderFilters(nsIFrame* aFilteredFrame,
wr::FilterOp filterOp = wr::FilterOp::DropShadow(
offset, radius, wr::ToColorF(ToDeviceColor(color)));
aWrFilters.AppendElement(filterOp);
aWrFilters.filters.AppendElement(filterOp);
} else if (attr.is<ComponentTransferAttributes>()) {
const ComponentTransferAttributes& attributes =
attr.as<ComponentTransferAttributes>();
size_t numValues = attributes.mValues[0].Length() +
attributes.mValues[1].Length() + attributes.mValues[2].Length() +
attributes.mValues[3].Length();
if (numValues > 1024) {
// Depending on how the wr shaders are implemented we may need to
// limit the total number of values.
return false;
}
wr::FilterOp filterOp = {wr::FilterOp::Tag::ComponentTransfer};
wr::WrFilterData filterData;
aWrFilters.values.AppendElement(nsTArray<float>());
nsTArray<float>* values = &aWrFilters.values[aWrFilters.values.Length()-1];
values->SetCapacity(numValues);
filterData.funcR_type = FuncTypeToWr(attributes.mTypes[0]);
size_t R_startindex = values->Length();
values->AppendElements(attributes.mValues[0]);
filterData.R_values_count = attributes.mValues[0].Length();
filterData.funcG_type = FuncTypeToWr(attributes.mTypes[1]);
size_t G_startindex = values->Length();
values->AppendElements(attributes.mValues[1]);
filterData.G_values_count = attributes.mValues[1].Length();
filterData.funcB_type = FuncTypeToWr(attributes.mTypes[2]);
size_t B_startindex = values->Length();
values->AppendElements(attributes.mValues[2]);
filterData.B_values_count = attributes.mValues[2].Length();
filterData.funcA_type = FuncTypeToWr(attributes.mTypes[3]);
size_t A_startindex = values->Length();
values->AppendElements(attributes.mValues[3]);
filterData.A_values_count = attributes.mValues[3].Length();
filterData.R_values = filterData.R_values_count > 0 ? &((*values)[R_startindex]) : nullptr;
filterData.G_values = filterData.G_values_count > 0 ? &((*values)[G_startindex]) : nullptr;
filterData.B_values = filterData.B_values_count > 0 ? &((*values)[B_startindex]) : nullptr;
filterData.A_values = filterData.A_values_count > 0 ? &((*values)[A_startindex]) : nullptr;
aWrFilters.filters.AppendElement(filterOp);
aWrFilters.filter_datas.AppendElement(filterData);
} else {
return false;
}
if (filterIsNoop && aWrFilters.Length() > 0 &&
(aWrFilters.LastElement().tag == wr::FilterOp::Tag::SrgbToLinear ||
aWrFilters.LastElement().tag == wr::FilterOp::Tag::LinearToSrgb)) {
if (filterIsNoop && aWrFilters.filters.Length() > 0 &&
(aWrFilters.filters.LastElement().tag == wr::FilterOp::Tag::SrgbToLinear ||
aWrFilters.filters.LastElement().tag == wr::FilterOp::Tag::LinearToSrgb)) {
// We pushed a color space conversion filter in prevision of applying
// another filter which turned out to be a no-op, so the conversion is
// unnecessary. Remove it from the filter list.
@ -270,7 +338,7 @@ bool nsFilterInstance::BuildWebRenderFilters(nsIFrame* aFilteredFrame,
// css/filter-effects/filter-scale-001.html for which the needless
// sRGB->linear->no-op->sRGB roundtrip introduces a slight error and we
// cannot add fuzziness to the test.
Unused << aWrFilters.PopLastElement();
Unused << aWrFilters.filters.PopLastElement();
srgb = previousSrgb;
}
@ -285,7 +353,7 @@ bool nsFilterInstance::BuildWebRenderFilters(nsIFrame* aFilteredFrame,
}
if (!srgb) {
aWrFilters.AppendElement(wr::FilterOp::LinearToSrgb());
aWrFilters.filters.AppendElement(wr::FilterOp::LinearToSrgb());
}
if (finalClip) {

Просмотреть файл

@ -123,7 +123,7 @@ class nsFilterInstance {
* supported.
*/
static bool BuildWebRenderFilters(nsIFrame* aFilteredFrame,
nsTArray<mozilla::wr::FilterOp>& aWrFilters,
WrFiltersHolder& aWrFilters,
mozilla::Maybe<nsRect>& aPostFilterClip);
private:

Просмотреть файл

@ -1086,7 +1086,7 @@ void nsSVGIntegrationUtils::PaintFilter(const PaintFramesParams& aParams) {
}
bool nsSVGIntegrationUtils::BuildWebRenderFilters(
nsIFrame* aFilteredFrame, nsTArray<mozilla::wr::FilterOp>& aWrFilters,
nsIFrame* aFilteredFrame, WrFiltersHolder& aWrFilters,
Maybe<nsRect>& aPostFilterClip) {
return nsFilterInstance::BuildWebRenderFilters(aFilteredFrame, aWrFilters,
aPostFilterClip);

Просмотреть файл

@ -34,6 +34,13 @@ class LayerManager;
struct nsPoint;
struct nsSize;
struct WrFiltersHolder {
nsTArray<mozilla::wr::FilterOp> filters;
nsTArray<mozilla::wr::WrFilterData> filter_datas;
// This exists just to own the values long enough for them to be copied into rust.
nsTArray<nsTArray<float>> values;
};
/**
* Integration of SVG effects (clipPath clipping, masking and filters) into
* regular display list based painting and hit-testing.
@ -196,7 +203,7 @@ class nsSVGIntegrationUtils final {
* supported.
*/
static bool BuildWebRenderFilters(nsIFrame* aFilteredFrame,
nsTArray<mozilla::wr::FilterOp>& aWrFilters,
WrFiltersHolder& aWrFilters,
mozilla::Maybe<nsRect>& aPostFilterClip);
/**