зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1778808 - Use stricter TiedFields instead of IsTriviallySerializable in WebGL's QueueParamTraits. r=lsalzman,nika
``` // We guarantee our robustness via these requirements: // * Object.MutTiedFields() gives us a tuple, // * where the combined sizeofs all field types sums to sizeof(Object), // * (thus we know we are exhaustively listing all fields) // * where feeding each field back into ParamTraits succeeds, // * and ParamTraits is only automated for BytesAlwaysValidT<T> types. // (BytesAlwaysValidT rejects bool and enum types, and only accepts int/float // types, or array or std::arrays of such types) // (Yes, bit-field fields are rejected by MutTiedFields too) ``` BytesAlwaysValidT<T> is the same as the IsTriviallySerializable<T> that it replaces, however the emphasis is different, and should discourage tagging structs as IsTriviallySerializable, since they more clearly aren't BytesAlwaysValid. Differential Revision: https://phabricator.services.mozilla.com/D151676
This commit is contained in:
Родитель
5f9d36e992
Коммит
f608e1f1e0
|
@ -800,7 +800,7 @@ bool ClientWebGLContext::CreateHostContext(const uvec2& requestedSize) {
|
|||
{
|
||||
webgl::TypedQuad initVal;
|
||||
const float fData[4] = {0, 0, 0, 1};
|
||||
memcpy(initVal.data, fData, sizeof(initVal.data));
|
||||
memcpy(initVal.data.data(), fData, initVal.data.size());
|
||||
state.mGenericVertexAttribs.resize(limits.maxVertexAttribs, initVal);
|
||||
}
|
||||
|
||||
|
@ -2780,7 +2780,7 @@ void ClientWebGLContext::ClearBufferTv(const GLenum buffer,
|
|||
webgl::TypedQuad data;
|
||||
data.type = type;
|
||||
|
||||
auto dataSize = sizeof(data.data);
|
||||
auto dataSize = data.data.size();
|
||||
switch (buffer) {
|
||||
case LOCAL_GL_COLOR:
|
||||
break;
|
||||
|
@ -2804,7 +2804,7 @@ void ClientWebGLContext::ClearBufferTv(const GLenum buffer,
|
|||
return;
|
||||
}
|
||||
|
||||
memcpy(data.data, view.begin().get() + byteOffset.value(), dataSize);
|
||||
memcpy(data.data.data(), view.begin().get() + byteOffset.value(), dataSize);
|
||||
Run<RPROC(ClearBufferTv)>(buffer, drawBuffer, data);
|
||||
|
||||
AfterDrawCall();
|
||||
|
@ -4550,15 +4550,17 @@ void ClientWebGLContext::GetVertexAttrib(JSContext* cx, GLuint index,
|
|||
switch (attrib.type) {
|
||||
case webgl::AttribBaseType::Float:
|
||||
obj = dom::Float32Array::Create(
|
||||
cx, this, 4, reinterpret_cast<const float*>(attrib.data));
|
||||
cx, this, 4, reinterpret_cast<const float*>(attrib.data.data()));
|
||||
break;
|
||||
case webgl::AttribBaseType::Int:
|
||||
obj = dom::Int32Array::Create(
|
||||
cx, this, 4, reinterpret_cast<const int32_t*>(attrib.data));
|
||||
cx, this, 4,
|
||||
reinterpret_cast<const int32_t*>(attrib.data.data()));
|
||||
break;
|
||||
case webgl::AttribBaseType::Uint:
|
||||
obj = dom::Uint32Array::Create(
|
||||
cx, this, 4, reinterpret_cast<const uint32_t*>(attrib.data));
|
||||
cx, this, 4,
|
||||
reinterpret_cast<const uint32_t*>(attrib.data.data()));
|
||||
break;
|
||||
case webgl::AttribBaseType::Boolean:
|
||||
MOZ_CRASH("impossible");
|
||||
|
@ -4752,7 +4754,7 @@ void ClientWebGLContext::VertexAttrib4Tv(GLuint index, webgl::AttribBaseType t,
|
|||
|
||||
auto& attrib = list[index];
|
||||
attrib.type = t;
|
||||
memcpy(attrib.data, src.begin().get(), sizeof(attrib.data));
|
||||
memcpy(attrib.data.data(), src.begin().get(), attrib.data.size());
|
||||
|
||||
Run<RPROC(VertexAttrib4T)>(index, attrib);
|
||||
}
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include "nsString.h"
|
||||
#include "WebGLTypes.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace mozilla::webgl {
|
||||
|
||||
template <typename T>
|
||||
|
@ -29,11 +31,6 @@ struct RemoveCVR {
|
|||
typename std::remove_reference<typename std::remove_cv<T>::type>::type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct IsTriviallySerializable
|
||||
: public std::integral_constant<bool, std::is_arithmetic<T>::value &&
|
||||
!std::is_same<T, bool>::value> {};
|
||||
|
||||
/**
|
||||
* QueueParamTraits provide the user with a way to implement PCQ argument
|
||||
* (de)serialization. It uses a PcqView, which permits the system to
|
||||
|
@ -67,6 +64,37 @@ inline Range<T> AsRange(T* const begin, T* const end) {
|
|||
return {begin, *size};
|
||||
}
|
||||
|
||||
// -
|
||||
// BytesAlwaysValidT
|
||||
|
||||
template <class T>
|
||||
struct BytesAlwaysValidT {
|
||||
using non_cv = typename std::remove_cv<T>::type;
|
||||
static constexpr bool value =
|
||||
std::is_arithmetic<T>::value && !std::is_same<non_cv, bool>::value;
|
||||
};
|
||||
static_assert(BytesAlwaysValidT<float>::value);
|
||||
static_assert(!BytesAlwaysValidT<bool>::value);
|
||||
static_assert(!BytesAlwaysValidT<const bool>::value);
|
||||
static_assert(!BytesAlwaysValidT<int*>::value);
|
||||
static_assert(BytesAlwaysValidT<intptr_t>::value);
|
||||
|
||||
template <class T, size_t N>
|
||||
struct BytesAlwaysValidT<std::array<T, N>> {
|
||||
static constexpr bool value = BytesAlwaysValidT<T>::value;
|
||||
};
|
||||
static_assert(BytesAlwaysValidT<std::array<int, 4>>::value);
|
||||
static_assert(!BytesAlwaysValidT<std::array<bool, 4>>::value);
|
||||
|
||||
template <class T, size_t N>
|
||||
struct BytesAlwaysValidT<T[N]> {
|
||||
static constexpr bool value = BytesAlwaysValidT<T>::value;
|
||||
};
|
||||
static_assert(BytesAlwaysValidT<int[4]>::value);
|
||||
static_assert(!BytesAlwaysValidT<bool[4]>::value);
|
||||
|
||||
// -
|
||||
|
||||
/**
|
||||
* Used to give QueueParamTraits a way to write to the Producer without
|
||||
* actually altering it, in case the transaction fails.
|
||||
|
@ -82,6 +110,7 @@ class ProducerView {
|
|||
|
||||
template <typename T>
|
||||
bool WriteFromRange(const Range<const T>& src) {
|
||||
static_assert(BytesAlwaysValidT<T>::value);
|
||||
if (MOZ_LIKELY(mOk)) {
|
||||
mOk &= mProducer->WriteFromRange(src);
|
||||
}
|
||||
|
@ -98,13 +127,6 @@ class ProducerView {
|
|||
return WriteFromRange(AsRange(begin, end));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool WritePod(const T& in) {
|
||||
static_assert(std::is_trivially_copyable_v<T>);
|
||||
const auto begin = ∈
|
||||
return Write(begin, begin + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize aArg using Arg's QueueParamTraits.
|
||||
*/
|
||||
|
@ -155,18 +177,13 @@ class ConsumerView {
|
|||
/// Return a view wrapping the shmem.
|
||||
template <typename T>
|
||||
inline Maybe<Range<const T>> ReadRange(const size_t elemCount) {
|
||||
static_assert(BytesAlwaysValidT<T>::value);
|
||||
if (MOZ_UNLIKELY(!mOk)) return {};
|
||||
const auto view = mConsumer->template ReadRange<T>(elemCount);
|
||||
mOk &= bool(view);
|
||||
return view;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool ReadPod(T* out) {
|
||||
static_assert(std::is_trivially_copyable_v<T>);
|
||||
return Read(out, out + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize aArg using Arg's QueueParamTraits.
|
||||
* If the return value is not Success then aArg is not changed.
|
||||
|
@ -185,28 +202,25 @@ class ConsumerView {
|
|||
bool mOk = true;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// -
|
||||
|
||||
/**
|
||||
* True for types that can be (de)serialized by memcpy.
|
||||
*/
|
||||
template <typename Arg>
|
||||
struct QueueParamTraits {
|
||||
template <typename U>
|
||||
static bool Write(ProducerView<U>& aProducerView, const Arg& aArg) {
|
||||
static_assert(std::is_trivially_copyable<Arg>::value,
|
||||
template <typename ProducerView>
|
||||
static bool Write(ProducerView& aProducerView, const Arg& aArg) {
|
||||
static_assert(BytesAlwaysValidT<Arg>::value,
|
||||
"No QueueParamTraits specialization was found for this type "
|
||||
"and it does not satisfy is_trivially_copyable.");
|
||||
"and it does not satisfy BytesAlwaysValid.");
|
||||
// Write self as binary
|
||||
const auto begin = &aArg;
|
||||
return aProducerView.Write(begin, begin + 1);
|
||||
const auto pArg = &aArg;
|
||||
return aProducerView.Write(pArg, pArg + 1);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
static bool Read(ConsumerView<U>& aConsumerView, Arg* aArg) {
|
||||
static_assert(std::is_trivially_copyable<Arg>::value,
|
||||
template <typename ConsumerView>
|
||||
static bool Read(ConsumerView& aConsumerView, Arg* aArg) {
|
||||
static_assert(BytesAlwaysValidT<Arg>::value,
|
||||
"No QueueParamTraits specialization was found for this type "
|
||||
"and it does not satisfy is_trivially_copyable.");
|
||||
"and it does not satisfy BytesAlwaysValid.");
|
||||
// Read self as binary
|
||||
return aConsumerView.Read(aArg, aArg + 1);
|
||||
}
|
||||
|
@ -237,6 +251,84 @@ struct QueueParamTraits<bool> {
|
|||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
template <class T, class UT = std::underlying_type_t<T>>
|
||||
Maybe<T> AsValidEnum(const UT raw_val) {
|
||||
const auto raw_enum = T{raw_val}; // This is the risk we prevent!
|
||||
if (!IsEnumCase(raw_enum)) return {};
|
||||
return Some(raw_enum);
|
||||
}
|
||||
|
||||
// -
|
||||
|
||||
template <class TT>
|
||||
struct QueueParamTraits_IsEnumCase {
|
||||
using T = TT;
|
||||
using UT = std::underlying_type_t<T>;
|
||||
|
||||
template <typename ProducerView>
|
||||
static bool Write(ProducerView& aProducerView, const T& aArg) {
|
||||
MOZ_ASSERT(IsEnumCase(aArg));
|
||||
const auto shadow = static_cast<UT>(aArg);
|
||||
aProducerView.WriteParam(shadow);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ConsumerView>
|
||||
static bool Read(ConsumerView& aConsumerView, T* aArg) {
|
||||
auto shadow = UT{};
|
||||
aConsumerView.ReadParam(&shadow);
|
||||
const auto e = AsValidEnum<T>(shadow);
|
||||
if (!e) return false;
|
||||
*aArg = *e;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
// We guarantee our robustness via these requirements:
|
||||
// * Object.MutTiedFields() gives us a tuple,
|
||||
// * where the combined sizeofs all field types sums to sizeof(Object),
|
||||
// * (thus we know we are exhaustively listing all fields)
|
||||
// * where feeding each field back into ParamTraits succeeds,
|
||||
// * and ParamTraits is only automated for BytesAlwaysValidT<T> types.
|
||||
// (BytesAlwaysValidT rejects bool and enum types, and only accepts int/float
|
||||
// types, or array or std::arrays of such types)
|
||||
// (Yes, bit-field fields are rejected by MutTiedFields too)
|
||||
|
||||
template <class TT>
|
||||
struct QueueParamTraits_TiedFields {
|
||||
using T = TT;
|
||||
|
||||
template <typename ProducerView>
|
||||
static bool Write(ProducerView& aProducerView, const T& aArg) {
|
||||
const auto fields = TiedFields(aArg);
|
||||
static_assert(SizeofTupleArgs(fields) == sizeof(T), "Are there missing fields or padding between fields?");
|
||||
|
||||
bool ok = true;
|
||||
MapTuple(fields, [&](const auto& field) {
|
||||
ok &= aProducerView.WriteParam(field);
|
||||
return true;
|
||||
});
|
||||
return ok;
|
||||
}
|
||||
|
||||
template <typename ConsumerView>
|
||||
static bool Read(ConsumerView& aConsumerView, T* aArg) {
|
||||
const auto fields = TiedFields(*aArg);
|
||||
static_assert(SizeofTupleArgs(fields) == sizeof(T));
|
||||
|
||||
bool ok = true;
|
||||
MapTuple(fields, [&](auto& field) {
|
||||
ok &= aConsumerView.ReadParam(&field);
|
||||
return true;
|
||||
});
|
||||
return ok;
|
||||
}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
// Adapted from IPC::EnumSerializer, this class safely handles enum values,
|
||||
// validating that they are in range using the same EnumValidators as IPDL
|
||||
// (namely ContiguousEnumValidator and ContiguousEnumValidatorInclusive).
|
||||
|
@ -485,11 +577,10 @@ struct QueueParamTraits<nsString> : public QueueParamTraits<nsAString> {
|
|||
// ---------------------------------------------------------------
|
||||
|
||||
template <typename NSTArrayType,
|
||||
bool =
|
||||
IsTriviallySerializable<typename NSTArrayType::value_type>::value>
|
||||
bool = BytesAlwaysValidT<typename NSTArrayType::value_type>::value>
|
||||
struct NSArrayQueueParamTraits;
|
||||
|
||||
// For ElementTypes that are !IsTriviallySerializable
|
||||
// For ElementTypes that are !BytesAlwaysValidT
|
||||
template <typename _ElementType>
|
||||
struct NSArrayQueueParamTraits<nsTArray<_ElementType>, false> {
|
||||
using ElementType = _ElementType;
|
||||
|
@ -523,7 +614,7 @@ struct NSArrayQueueParamTraits<nsTArray<_ElementType>, false> {
|
|||
}
|
||||
};
|
||||
|
||||
// For ElementTypes that are IsTriviallySerializable
|
||||
// For ElementTypes that are BytesAlwaysValidT
|
||||
template <typename _ElementType>
|
||||
struct NSArrayQueueParamTraits<nsTArray<_ElementType>, true> {
|
||||
using ElementType = _ElementType;
|
||||
|
@ -561,11 +652,10 @@ struct QueueParamTraits<nsTArray<ElementType>>
|
|||
// ---------------------------------------------------------------
|
||||
|
||||
template <typename ArrayType,
|
||||
bool =
|
||||
IsTriviallySerializable<typename ArrayType::ElementType>::value>
|
||||
bool = BytesAlwaysValidT<typename ArrayType::ElementType>::value>
|
||||
struct ArrayQueueParamTraits;
|
||||
|
||||
// For ElementTypes that are !IsTriviallySerializable
|
||||
// For ElementTypes that are !BytesAlwaysValidT
|
||||
template <typename _ElementType, size_t Length>
|
||||
struct ArrayQueueParamTraits<Array<_ElementType, Length>, false> {
|
||||
using ElementType = _ElementType;
|
||||
|
@ -588,7 +678,7 @@ struct ArrayQueueParamTraits<Array<_ElementType, Length>, false> {
|
|||
}
|
||||
};
|
||||
|
||||
// For ElementTypes that are IsTriviallySerializable
|
||||
// For ElementTypes that are BytesAlwaysValidT
|
||||
template <typename _ElementType, size_t Length>
|
||||
struct ArrayQueueParamTraits<Array<_ElementType, Length>, true> {
|
||||
using ElementType = _ElementType;
|
||||
|
|
|
@ -0,0 +1,253 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef DOM_CANVAS_TIED_FIELDS_H
|
||||
#define DOM_CANVAS_TIED_FIELDS_H
|
||||
|
||||
#include "TupleUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// -
|
||||
|
||||
/**
|
||||
* TiedFields(T&) -> std::tuple<Fields&...>
|
||||
* TiedFields(const T&) -> std::tuple<const Fields&...>
|
||||
*
|
||||
* You can also overload TiedFields without adding T::MutTiedFields:
|
||||
* template<>
|
||||
* inline auto TiedFields<gfx::IntSize>(gfx::IntSize& a) {
|
||||
* return std::tie(a.width, a.height);
|
||||
* }
|
||||
*/
|
||||
template <class T>
|
||||
constexpr auto TiedFields(T& t) {
|
||||
const auto fields = t.MutTiedFields();
|
||||
return fields;
|
||||
}
|
||||
template <class T, class... Args, class Tup = std::tuple<Args&...>>
|
||||
constexpr auto TiedFields(const T& t) {
|
||||
// Uncast const to get mutable-fields tuple, but reapply const to tuple args.
|
||||
const auto mutFields = TiedFields(const_cast<T&>(t));
|
||||
return ToTupleOfConstRefs(mutFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if all bytes in T are accounted for via size of all tied fields.
|
||||
* Returns false if there's bytes unaccounted for, which might indicate either
|
||||
* unaccounted-for padding or missing fields.
|
||||
* The goal is to check that TiedFields returns every field in T, and this
|
||||
* returns false if it suspects there are bytes that are not accounted for by
|
||||
* TiedFields.
|
||||
*
|
||||
* `constexpr` effectively cannot do math on pointers, so it's not possible to
|
||||
* figure out via `constexpr` whether fields are consecutive or dense.
|
||||
* However, we can at least compare `sizeof(T)` to the sum of `sizeof(Args...)`
|
||||
* for `TiedFields(T) -> std::tuple<Args...>`.
|
||||
*
|
||||
* See TiedFieldsExamples.
|
||||
*/
|
||||
template <class T>
|
||||
constexpr bool AreAllBytesTiedFields(const T& t) {
|
||||
const auto fields = TiedFields(t);
|
||||
const auto fields_size_sum = SizeofTupleArgs(fields);
|
||||
const auto t_size = sizeof(T);
|
||||
return fields_size_sum == t_size;
|
||||
}
|
||||
|
||||
// -
|
||||
|
||||
/**
|
||||
* Padding<T> can be used to pad out a struct so that it's not implicitly
|
||||
* padded by struct rules.
|
||||
* You can also just add your padding to TiedFields, but by explicitly typing
|
||||
* padding like this, serialization can make a choice whether to copy Padding,
|
||||
* or instead to omit the copy.
|
||||
*
|
||||
* Omitting the copy isn't always faster.
|
||||
* struct Entry {
|
||||
* uint16_t key;
|
||||
* Padding<uint16_t> padding;
|
||||
* uint32_t val;
|
||||
* auto MutTiedFields() { return std::tie(key, padding, val); }
|
||||
* };
|
||||
* If you serialize Padding, the serialized size is 8, and the compiler will
|
||||
* optimize serialization to a single 8-byte memcpy.
|
||||
* If your serialization omits Padding, the serialized size of Entry shrinks
|
||||
* by 25%. If you have a big list of Entrys, maybe this is a big savings!
|
||||
* However, by optimizing for size here you sacrifice speed, because this splits
|
||||
* the single memcpy into two: a 2-byte memcpy and a 4-byte memcpy.
|
||||
*
|
||||
* Explicitly marking padding gives callers the option of choosing.
|
||||
*/
|
||||
template <class T>
|
||||
struct Padding {
|
||||
T ignored;
|
||||
|
||||
friend constexpr bool operator==(const Padding&, const Padding&) {
|
||||
return true;
|
||||
}
|
||||
friend constexpr bool operator<(const Padding&, const Padding&) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(Padding<bool>) == 1);
|
||||
static_assert(sizeof(Padding<bool[2]>) == 2);
|
||||
static_assert(sizeof(Padding<int>) == 4);
|
||||
|
||||
// -
|
||||
|
||||
template <size_t I>
|
||||
struct DecayDownT : public DecayDownT<I - 1> {};
|
||||
|
||||
template <>
|
||||
struct DecayDownT<0> {};
|
||||
|
||||
// -
|
||||
|
||||
/// Warning, IsDenseNestedScalars should not be used to indicate the safety of
|
||||
/// a memcpy.
|
||||
/// If you trust both the source and destination, you should use
|
||||
/// std::is_trivially_copyable.
|
||||
template <class T>
|
||||
constexpr bool IsDenseNestedScalars(const T& t);
|
||||
|
||||
// -
|
||||
|
||||
namespace IsDenseNestedScalarsDetails {
|
||||
|
||||
template <class T, std::enable_if_t<std::is_scalar<T>::value, bool> = true>
|
||||
constexpr bool Impl(const T&, DecayDownT<3>) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T, size_t N>
|
||||
constexpr bool Impl(const T (&t)[N], DecayDownT<3>) {
|
||||
return IsDenseNestedScalars(t[0]);
|
||||
}
|
||||
|
||||
template <class T, size_t N>
|
||||
constexpr bool Impl(const std::array<T, N>& t, DecayDownT<3>) {
|
||||
return IsDenseNestedScalars(t[0]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr bool Impl(const Padding<T>& t, DecayDownT<3>) {
|
||||
return IsDenseNestedScalars(t.ignored);
|
||||
}
|
||||
|
||||
// -
|
||||
|
||||
template <class T>
|
||||
constexpr bool Impl(const T& t, DecayDownT<1>) {
|
||||
const auto tup = TiedFields(t);
|
||||
bool ok = AreAllBytesTiedFields(t);
|
||||
MapTuple(tup, [&](const auto& field) {
|
||||
ok &= IsDenseNestedScalars(field);
|
||||
return true;
|
||||
});
|
||||
return ok;
|
||||
}
|
||||
|
||||
} // namespace IsDenseNestedScalarsDetails
|
||||
|
||||
// -
|
||||
|
||||
template <class T>
|
||||
constexpr bool IsDenseNestedScalars(const T& t) {
|
||||
return IsDenseNestedScalarsDetails::Impl(t, DecayDownT<5>{});
|
||||
}
|
||||
static_assert(IsDenseNestedScalars(1));
|
||||
// Compile error: Missing TiedFields:
|
||||
// static_assert(IsDenseNestedScalars(std::pair<int,int>{}));
|
||||
|
||||
namespace TiedFieldsExamples {
|
||||
|
||||
struct Cat {
|
||||
int i;
|
||||
bool b;
|
||||
|
||||
constexpr auto MutTiedFields() { return std::tie(i, b); }
|
||||
};
|
||||
static_assert(sizeof(Cat) == 8);
|
||||
static_assert(!AreAllBytesTiedFields(Cat{}));
|
||||
static_assert(!IsDenseNestedScalars(Cat{}));
|
||||
|
||||
struct Dog {
|
||||
bool b;
|
||||
int i;
|
||||
|
||||
constexpr auto MutTiedFields() { return std::tie(i, b); }
|
||||
};
|
||||
static_assert(sizeof(Dog) == 8);
|
||||
static_assert(!AreAllBytesTiedFields(Dog{}));
|
||||
static_assert(!IsDenseNestedScalars(Dog{}));
|
||||
|
||||
struct Fish {
|
||||
bool b;
|
||||
bool padding[3];
|
||||
int i;
|
||||
|
||||
constexpr auto MutTiedFields() { return std::tie(i, b, padding); }
|
||||
};
|
||||
static_assert(sizeof(Fish) == 8);
|
||||
static_assert(AreAllBytesTiedFields(Fish{}));
|
||||
static_assert(IsDenseNestedScalars(Fish{}));
|
||||
|
||||
struct Eel { // Like a Fish, but you can skip serializing the padding.
|
||||
bool b;
|
||||
Padding<bool> padding[3];
|
||||
int i;
|
||||
|
||||
constexpr auto MutTiedFields() { return std::tie(i, b, padding); }
|
||||
};
|
||||
static_assert(sizeof(Eel) == 8);
|
||||
static_assert(AreAllBytesTiedFields(Eel{}));
|
||||
static_assert(IsDenseNestedScalars(Eel{}));
|
||||
|
||||
// -
|
||||
|
||||
//#define LETS_USE_BIT_FIELDS
|
||||
#ifdef LETS_USE_BIT_FIELDS
|
||||
# undef LETS_USE_BIT_FIELDS
|
||||
|
||||
struct Platypus {
|
||||
short s : 1;
|
||||
short s2 : 1;
|
||||
int i;
|
||||
|
||||
constexpr auto MutTiedFields() {
|
||||
return std::tie(s, s2, i); // Error: Can't take reference to bit-field.
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
// -
|
||||
|
||||
struct FishTank {
|
||||
Fish f;
|
||||
int i2;
|
||||
|
||||
constexpr auto MutTiedFields() { return std::tie(f, i2); }
|
||||
};
|
||||
static_assert(sizeof(FishTank) == 12);
|
||||
static_assert(AreAllBytesTiedFields(FishTank{}));
|
||||
static_assert(IsDenseNestedScalars(FishTank{}));
|
||||
|
||||
struct CatCarrier {
|
||||
Cat c;
|
||||
int i2;
|
||||
|
||||
constexpr auto MutTiedFields() { return std::tie(c, i2); }
|
||||
};
|
||||
static_assert(sizeof(CatCarrier) == 12);
|
||||
static_assert(AreAllBytesTiedFields(CatCarrier{}));
|
||||
static_assert(!IsDenseNestedScalars(CatCarrier{})); // Because:
|
||||
static_assert(!AreAllBytesTiedFields(CatCarrier{}.c));
|
||||
|
||||
} // namespace TiedFieldsExamples
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // DOM_CANVAS_TIED_FIELDS_H
|
|
@ -0,0 +1,61 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef DOM_CANVAS_TUPLE_UTILS_H
|
||||
#define DOM_CANVAS_TUPLE_UTILS_H
|
||||
|
||||
#include <tuple>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// -
|
||||
// ToTupleOfConstRefs
|
||||
|
||||
template <class T>
|
||||
constexpr const auto& ToConstRef1(T& ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class Tup, size_t... Ids>
|
||||
constexpr auto ToTupleOfConstRefsN(const Tup& tup,
|
||||
const std::index_sequence<Ids...>&) {
|
||||
return std::tie(ToConstRef1(std::get<Ids>(tup))...);
|
||||
}
|
||||
|
||||
template <class... Args, size_t... Ids, class Tup = std::tuple<Args...>>
|
||||
constexpr auto ToTupleOfConstRefs(const Tup& tup) {
|
||||
return ToTupleOfConstRefsN(
|
||||
tup, std::make_index_sequence<std::tuple_size_v<Tup>>());
|
||||
}
|
||||
|
||||
// -
|
||||
// MapTuple
|
||||
|
||||
template <class Tup, class Callable, size_t... Ids>
|
||||
constexpr auto MapTupleN(Tup&& tup, Callable&& fn,
|
||||
const std::index_sequence<Ids...>&) {
|
||||
return std::make_tuple(fn(std::get<Ids>(tup))...);
|
||||
}
|
||||
|
||||
/// Callable::operator()(T) cannot return void or you will get weird errors.
|
||||
template <class... Args, class Callable, class Tup = std::tuple<Args...>>
|
||||
constexpr auto MapTuple(Tup&& t, Callable&& fn) {
|
||||
using Tup2 = typename std::remove_reference<Tup>::type;
|
||||
return MapTupleN(t, fn, std::make_index_sequence<std::tuple_size_v<Tup2>>());
|
||||
}
|
||||
|
||||
// -
|
||||
|
||||
template <class... Args>
|
||||
constexpr auto SizeofTupleArgs(const std::tuple<Args...>&) {
|
||||
size_t total = 0;
|
||||
for (const auto s : {sizeof(Args)...}) {
|
||||
total += s;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // DOM_CANVAS_TUPLE_UTILS_H
|
|
@ -119,17 +119,17 @@ void WebGL2Context::ClearBufferTv(GLenum buffer, GLint drawBuffer,
|
|||
|
||||
case webgl::AttribBaseType::Float:
|
||||
gl->fClearBufferfv(buffer, drawBuffer,
|
||||
reinterpret_cast<const float*>(data.data));
|
||||
reinterpret_cast<const float*>(data.data.data()));
|
||||
break;
|
||||
|
||||
case webgl::AttribBaseType::Int:
|
||||
gl->fClearBufferiv(buffer, drawBuffer,
|
||||
reinterpret_cast<const int32_t*>(data.data));
|
||||
reinterpret_cast<const int32_t*>(data.data.data()));
|
||||
break;
|
||||
|
||||
case webgl::AttribBaseType::Uint:
|
||||
gl->fClearBufferuiv(buffer, drawBuffer,
|
||||
reinterpret_cast<const uint32_t*>(data.data));
|
||||
reinterpret_cast<const uint32_t*>(data.data.data()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -106,22 +106,6 @@ WebGLContextOptions::WebGLContextOptions() {
|
|||
antialias = StaticPrefs::webgl_default_antialias();
|
||||
}
|
||||
|
||||
bool WebGLContextOptions::operator==(const WebGLContextOptions& r) const {
|
||||
bool eq = true;
|
||||
eq &= (alpha == r.alpha);
|
||||
eq &= (depth == r.depth);
|
||||
eq &= (stencil == r.stencil);
|
||||
eq &= (premultipliedAlpha == r.premultipliedAlpha);
|
||||
eq &= (antialias == r.antialias);
|
||||
eq &= (preserveDrawingBuffer == r.preserveDrawingBuffer);
|
||||
eq &= (failIfMajorPerformanceCaveat == r.failIfMajorPerformanceCaveat);
|
||||
eq &= (xrCompatible == r.xrCompatible);
|
||||
eq &= (powerPreference == r.powerPreference);
|
||||
eq &= (colorSpace == r.colorSpace);
|
||||
eq &= (ignoreColorSpace == r.ignoreColorSpace);
|
||||
return eq;
|
||||
}
|
||||
|
||||
StaticMutex WebGLContext::sLruMutex;
|
||||
std::list<WebGLContext*> WebGLContext::sLru;
|
||||
|
||||
|
|
|
@ -57,15 +57,16 @@ void WebGLContext::VertexAttrib4T(GLuint index, const webgl::TypedQuad& src) {
|
|||
switch (src.type) {
|
||||
case webgl::AttribBaseType::Boolean:
|
||||
case webgl::AttribBaseType::Float:
|
||||
gl->fVertexAttrib4fv(index, reinterpret_cast<const float*>(src.data));
|
||||
gl->fVertexAttrib4fv(index,
|
||||
reinterpret_cast<const float*>(src.data.data()));
|
||||
break;
|
||||
case webgl::AttribBaseType::Int:
|
||||
gl->fVertexAttribI4iv(index,
|
||||
reinterpret_cast<const int32_t*>(src.data));
|
||||
gl->fVertexAttribI4iv(
|
||||
index, reinterpret_cast<const int32_t*>(src.data.data()));
|
||||
break;
|
||||
case webgl::AttribBaseType::Uint:
|
||||
gl->fVertexAttribI4uiv(index,
|
||||
reinterpret_cast<const uint32_t*>(src.data));
|
||||
gl->fVertexAttribI4uiv(
|
||||
index, reinterpret_cast<const uint32_t*>(src.data.data()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -76,7 +77,7 @@ void WebGLContext::VertexAttrib4T(GLuint index, const webgl::TypedQuad& src) {
|
|||
mGenericVertexAttribTypeInvalidator.InvalidateCaches();
|
||||
|
||||
if (!index) {
|
||||
memcpy(mGenericVertexAttrib0Data, src.data,
|
||||
memcpy(mGenericVertexAttrib0Data, src.data.data(),
|
||||
sizeof(mGenericVertexAttrib0Data));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,69 +14,104 @@
|
|||
#include "WebGLContext.h"
|
||||
#include "WebGLTypes.h"
|
||||
|
||||
namespace mozilla::webgl {
|
||||
namespace mozilla {
|
||||
namespace webgl {
|
||||
template <typename T>
|
||||
struct QueueParamTraits;
|
||||
|
||||
template <>
|
||||
struct IsTriviallySerializable<FloatOrInt> : std::true_type {};
|
||||
// -
|
||||
|
||||
template <>
|
||||
struct IsTriviallySerializable<webgl::ShaderPrecisionFormat> : std::true_type {
|
||||
};
|
||||
#define USE_TIED_FIELDS(T) \
|
||||
template <> \
|
||||
struct QueueParamTraits<T> : QueueParamTraits_TiedFields<T> {};
|
||||
|
||||
template <>
|
||||
struct IsTriviallySerializable<WebGLContextOptions> : std::true_type {};
|
||||
// -
|
||||
|
||||
template <>
|
||||
struct IsTriviallySerializable<WebGLTexImageData> : std::true_type {};
|
||||
USE_TIED_FIELDS(layers::RemoteTextureId)
|
||||
USE_TIED_FIELDS(layers::RemoteTextureOwnerId)
|
||||
USE_TIED_FIELDS(WebGLContextOptions)
|
||||
USE_TIED_FIELDS(webgl::PixelUnpackStateWebgl)
|
||||
USE_TIED_FIELDS(webgl::SwapChainOptions)
|
||||
USE_TIED_FIELDS(webgl::ReadPixelsDesc)
|
||||
USE_TIED_FIELDS(webgl::VertAttribPointerDesc)
|
||||
USE_TIED_FIELDS(webgl::PackingInfo)
|
||||
USE_TIED_FIELDS(webgl::TypedQuad)
|
||||
USE_TIED_FIELDS(webgl::PixelPackingState)
|
||||
USE_TIED_FIELDS(FloatOrInt)
|
||||
|
||||
} // namespace webgl
|
||||
template <>
|
||||
struct IsTriviallySerializable<WebGLTexPboOffset> : std::true_type {};
|
||||
inline auto TiedFields<gfx::IntSize>(gfx::IntSize& a) {
|
||||
return std::tie(a.width, a.height);
|
||||
}
|
||||
namespace webgl {
|
||||
USE_TIED_FIELDS(gfx::IntSize)
|
||||
|
||||
template <>
|
||||
struct IsTriviallySerializable<webgl::ExtensionBits> : std::true_type {};
|
||||
template <>
|
||||
struct IsTriviallySerializable<webgl::GetUniformData> : std::true_type {};
|
||||
// -
|
||||
|
||||
template <>
|
||||
struct IsTriviallySerializable<mozilla::webgl::PackingInfo> : std::true_type {};
|
||||
template <>
|
||||
struct IsTriviallySerializable<mozilla::webgl::PixelPackingState>
|
||||
: std::true_type {};
|
||||
template <>
|
||||
struct IsTriviallySerializable<mozilla::webgl::PixelUnpackStateWebgl>
|
||||
: std::true_type {};
|
||||
#undef USE_TIED_FIELDS
|
||||
|
||||
template <>
|
||||
struct IsTriviallySerializable<gfx::IntSize> : std::true_type {};
|
||||
// -
|
||||
|
||||
template <typename T>
|
||||
struct IsTriviallySerializable<avec2<T>> : std::true_type {};
|
||||
template <typename T>
|
||||
struct IsTriviallySerializable<avec3<T>> : std::true_type {};
|
||||
template <class T>
|
||||
struct QueueParamTraits<avec2<T>> : QueueParamTraits_TiedFields<avec2<T>> {};
|
||||
|
||||
template <>
|
||||
struct IsTriviallySerializable<webgl::TexUnpackBlob> : std::true_type {};
|
||||
template <class T>
|
||||
struct QueueParamTraits<avec3<T>> : QueueParamTraits_TiedFields<avec3<T>> {};
|
||||
|
||||
template <>
|
||||
struct IsTriviallySerializable<webgl::TypedQuad> : std::true_type {};
|
||||
template <>
|
||||
struct IsTriviallySerializable<webgl::VertAttribPointerDesc> : std::true_type {
|
||||
};
|
||||
template <>
|
||||
struct IsTriviallySerializable<webgl::ReadPixelsDesc> : std::true_type {};
|
||||
// template <>
|
||||
// struct IsTriviallySerializable<layers::SurfaceDescriptor> : std::true_type
|
||||
// {};
|
||||
// SurfaceDescriptorBuffer is *not* trivial.
|
||||
template <>
|
||||
struct IsTriviallySerializable<layers::RemoteTextureId> : std::true_type {};
|
||||
template <>
|
||||
struct IsTriviallySerializable<layers::RemoteTextureOwnerId> : std::true_type {
|
||||
};
|
||||
template <>
|
||||
struct IsTriviallySerializable<webgl::SwapChainOptions> : std::true_type {};
|
||||
// ---------------------------------------------------------------------
|
||||
// Enums!
|
||||
|
||||
inline constexpr bool IsEnumCase(const dom::WebGLPowerPreference raw) {
|
||||
switch (raw) {
|
||||
case dom::WebGLPowerPreference::Default:
|
||||
case dom::WebGLPowerPreference::Low_power:
|
||||
case dom::WebGLPowerPreference::High_performance:
|
||||
return true;
|
||||
case dom::WebGLPowerPreference::EndGuard_:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline constexpr bool IsEnumCase(const dom::PredefinedColorSpace raw) {
|
||||
switch (raw) {
|
||||
case dom::PredefinedColorSpace::Srgb:
|
||||
case dom::PredefinedColorSpace::Display_p3:
|
||||
return true;
|
||||
case dom::PredefinedColorSpace::EndGuard_:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline constexpr bool IsEnumCase(const webgl::AttribBaseType raw) {
|
||||
switch (raw) {
|
||||
case webgl::AttribBaseType::Boolean:
|
||||
case webgl::AttribBaseType::Float:
|
||||
case webgl::AttribBaseType::Int:
|
||||
case webgl::AttribBaseType::Uint:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static_assert(IsEnumCase(dom::WebGLPowerPreference(2)));
|
||||
static_assert(!IsEnumCase(dom::WebGLPowerPreference(3)));
|
||||
static_assert(!IsEnumCase(dom::WebGLPowerPreference(5)));
|
||||
|
||||
#define USE_IS_ENUM_CASE(T) \
|
||||
template <> \
|
||||
struct QueueParamTraits<T> : QueueParamTraits_IsEnumCase<T> {};
|
||||
|
||||
USE_IS_ENUM_CASE(dom::WebGLPowerPreference)
|
||||
USE_IS_ENUM_CASE(dom::PredefinedColorSpace)
|
||||
USE_IS_ENUM_CASE(webgl::AttribBaseType)
|
||||
|
||||
#undef USE_IS_ENUM_CASE
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Custom QueueParamTraits
|
||||
|
||||
template <typename T>
|
||||
struct QueueParamTraits<RawBuffer<T>> {
|
||||
|
@ -267,6 +302,7 @@ struct QueueParamTraits<gfxAlphaType>
|
|||
: public ContiguousEnumSerializerInclusive<
|
||||
gfxAlphaType, gfxAlphaType::Opaque, gfxAlphaType::NonPremult> {};
|
||||
|
||||
} // namespace mozilla::webgl
|
||||
} // namespace webgl
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // WEBGLQUEUEPARAMTRAITS_H_
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
@ -34,6 +35,7 @@
|
|||
#include "nsString.h"
|
||||
#include "mozilla/dom/WebGLRenderingContextBinding.h"
|
||||
#include "mozilla/ipc/SharedMemoryBasic.h"
|
||||
#include "TiedFields.h"
|
||||
|
||||
// Manual reflection of WebIDL typedefs that are different from their
|
||||
// OpenGL counterparts.
|
||||
|
@ -344,37 +346,68 @@ enum class BufferKind : uint8_t {
|
|||
struct FloatOrInt final // For TexParameter[fi] and friends.
|
||||
{
|
||||
bool isFloat = false;
|
||||
uint8_t padding[3] = {};
|
||||
GLfloat f = 0;
|
||||
GLint i = 0;
|
||||
|
||||
explicit FloatOrInt(GLint x = 0) : isFloat(false), f(x), i(x) {}
|
||||
|
||||
explicit FloatOrInt(GLfloat x) : isFloat(true), f(x), i(roundf(x)) {}
|
||||
|
||||
auto MutTiedFields() { return std::tie(isFloat, padding, f, i); }
|
||||
};
|
||||
|
||||
// -
|
||||
|
||||
struct WebGLContextOptions {
|
||||
bool alpha = true;
|
||||
bool depth = true;
|
||||
bool stencil = false;
|
||||
bool premultipliedAlpha = true;
|
||||
|
||||
bool antialias = true;
|
||||
bool preserveDrawingBuffer = false;
|
||||
bool failIfMajorPerformanceCaveat = false;
|
||||
bool xrCompatible = false;
|
||||
|
||||
dom::WebGLPowerPreference powerPreference =
|
||||
dom::WebGLPowerPreference::Default;
|
||||
dom::PredefinedColorSpace colorSpace = dom::PredefinedColorSpace::Srgb;
|
||||
bool ignoreColorSpace = true; // Our legacy behavior.
|
||||
bool shouldResistFingerprinting = true;
|
||||
|
||||
bool enableDebugRendererInfo = false;
|
||||
|
||||
auto MutTiedFields() {
|
||||
// clang-format off
|
||||
return std::tie(
|
||||
alpha,
|
||||
depth,
|
||||
stencil,
|
||||
premultipliedAlpha,
|
||||
|
||||
antialias,
|
||||
preserveDrawingBuffer,
|
||||
failIfMajorPerformanceCaveat,
|
||||
xrCompatible,
|
||||
|
||||
powerPreference,
|
||||
colorSpace,
|
||||
ignoreColorSpace,
|
||||
shouldResistFingerprinting,
|
||||
|
||||
enableDebugRendererInfo);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
WebGLContextOptions();
|
||||
WebGLContextOptions(const WebGLContextOptions&) = default;
|
||||
|
||||
bool operator==(const WebGLContextOptions&) const;
|
||||
bool operator!=(const WebGLContextOptions& rhs) const {
|
||||
return !(*this == rhs);
|
||||
using Self = WebGLContextOptions;
|
||||
friend bool operator==(const Self& a, const Self& b) {
|
||||
return TiedFields(a) == TiedFields(b);
|
||||
}
|
||||
friend bool operator!=(const Self& a, const Self& b) { return !(a == b); }
|
||||
};
|
||||
|
||||
namespace gfx {
|
||||
|
@ -402,6 +435,8 @@ struct avec2 {
|
|||
T x = T();
|
||||
T y = T();
|
||||
|
||||
auto MutTiedFields() { return std::tie(x, y); }
|
||||
|
||||
template <typename U, typename V>
|
||||
static Maybe<avec2> From(const U _x, const V _y) {
|
||||
const auto x = CheckedInt<T>(_x);
|
||||
|
@ -477,6 +512,8 @@ struct avec3 {
|
|||
T y = T();
|
||||
T z = T();
|
||||
|
||||
auto MutTiedFields() { return std::tie(x, y, z); }
|
||||
|
||||
template <typename U, typename V>
|
||||
static Maybe<avec3> From(const U _x, const V _y, const V _z) {
|
||||
const auto x = CheckedInt<T>(_x);
|
||||
|
@ -515,14 +552,14 @@ struct PackingInfo final {
|
|||
GLenum format = 0;
|
||||
GLenum type = 0;
|
||||
|
||||
bool operator<(const PackingInfo& x) const {
|
||||
if (format != x.format) return format < x.format;
|
||||
auto MutTiedFields() { return std::tie(format, type); }
|
||||
|
||||
return type < x.type;
|
||||
using Self = PackingInfo;
|
||||
friend bool operator<(const Self& a, const Self& b) {
|
||||
return TiedFields(a) < TiedFields(b);
|
||||
}
|
||||
|
||||
bool operator==(const PackingInfo& x) const {
|
||||
return (format == x.format && type == x.type);
|
||||
friend bool operator==(const Self& a, const Self& b) {
|
||||
return TiedFields(a) == TiedFields(b);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
|
@ -682,10 +719,15 @@ struct OpaqueFramebufferOptions final {
|
|||
// -
|
||||
|
||||
struct SwapChainOptions final {
|
||||
bool bgra = false;
|
||||
bool forceAsyncPresent = false;
|
||||
layers::RemoteTextureId remoteTextureId;
|
||||
layers::RemoteTextureOwnerId remoteTextureOwnerId;
|
||||
bool bgra = false;
|
||||
bool forceAsyncPresent = false;
|
||||
uint16_t padding1;
|
||||
uint32_t padding2; // Pad to sizeof(u64)
|
||||
|
||||
auto MutTiedFields() { return std::tie(
|
||||
remoteTextureId, remoteTextureOwnerId, bgra, forceAsyncPresent, padding1, padding2); }
|
||||
};
|
||||
|
||||
// -
|
||||
|
@ -739,8 +781,11 @@ struct LinkResult final {
|
|||
|
||||
/// 4x32-bit primitives, with a type tag.
|
||||
struct TypedQuad final {
|
||||
alignas(alignof(float)) uint8_t data[4 * sizeof(float)] = {};
|
||||
alignas(alignof(float)) std::array<uint8_t, 4 * sizeof(float)> data = {};
|
||||
webgl::AttribBaseType type = webgl::AttribBaseType::Float;
|
||||
uint8_t padding[3] = {};
|
||||
|
||||
constexpr auto MutTiedFields() { return std::tie(data, type, padding); }
|
||||
};
|
||||
|
||||
/// [1-16]x32-bit primitives, with a type tag.
|
||||
|
@ -770,6 +815,11 @@ struct VertAttribPointerDesc final {
|
|||
uint8_t byteStrideOrZero = 0;
|
||||
GLenum type = LOCAL_GL_FLOAT;
|
||||
uint64_t byteOffset = 0;
|
||||
|
||||
auto MutTiedFields() {
|
||||
return std::tie(intFunc, channels, normalized, byteStrideOrZero, type,
|
||||
byteOffset);
|
||||
}
|
||||
};
|
||||
|
||||
struct VertAttribPointerCalculated final {
|
||||
|
@ -985,12 +1035,14 @@ struct PixelPackingState : public DeriveNotEq<PixelPackingState> {
|
|||
uint32_t skipRows = 0;
|
||||
uint32_t skipImages = 0;
|
||||
|
||||
// C++20's default comparison operators can't come soon enough!
|
||||
bool operator==(const PixelPackingState& rhs) const {
|
||||
return alignmentInTypeElems == rhs.alignmentInTypeElems &&
|
||||
rowLength == rhs.rowLength && imageHeight == rhs.imageHeight &&
|
||||
skipPixels == rhs.skipPixels && skipRows == rhs.skipRows &&
|
||||
skipImages == rhs.skipImages;
|
||||
auto MutTiedFields() {
|
||||
return std::tie(alignmentInTypeElems, rowLength, imageHeight, skipPixels,
|
||||
skipRows, skipImages);
|
||||
}
|
||||
|
||||
using Self = PixelPackingState;
|
||||
friend bool operator==(const Self& a, const Self& b) {
|
||||
return TiedFields(a) == TiedFields(b);
|
||||
}
|
||||
|
||||
static void AssertDefaultUnpack(gl::GLContext& gl, const bool isWebgl2) {
|
||||
|
@ -1008,6 +1060,13 @@ struct PixelUnpackStateWebgl final : public PixelPackingState {
|
|||
bool flipY = false;
|
||||
bool premultiplyAlpha = false;
|
||||
bool requireFastPath = false;
|
||||
uint8_t padding = {};
|
||||
|
||||
auto MutTiedFields() {
|
||||
return std::tuple_cat(PixelPackingState::MutTiedFields(),
|
||||
std::tie(colorspaceConversion, flipY,
|
||||
premultiplyAlpha, requireFastPath, padding));
|
||||
}
|
||||
};
|
||||
|
||||
struct ExplicitPixelPackingState final {
|
||||
|
@ -1041,6 +1100,8 @@ struct ReadPixelsDesc final {
|
|||
uvec2 size;
|
||||
PackingInfo pi = {LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE};
|
||||
PixelPackingState packState;
|
||||
|
||||
auto MutTiedFields() { return std::tie(srcOffset, size, pi, packState); }
|
||||
};
|
||||
|
||||
} // namespace webgl
|
||||
|
|
|
@ -64,6 +64,8 @@ EXPORTS.mozilla.dom += [
|
|||
"OffscreenCanvasRenderingContext2D.h",
|
||||
"QueueParamTraits.h",
|
||||
"TextMetrics.h",
|
||||
"TiedFields.h",
|
||||
"TupleUtils.h",
|
||||
"WebGLChild.h",
|
||||
"WebGLCommandQueue.h",
|
||||
"WebGLIpdl.h",
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <iosfwd> // for ostream
|
||||
#include <stdint.h> // for uint32_t
|
||||
#include <stdio.h> // FILE
|
||||
#include <tuple>
|
||||
|
||||
#include "Units.h"
|
||||
#include "mozilla/DefineEnum.h" // for MOZ_DEFINE_ENUM_CLASS_WITH_BASE
|
||||
|
@ -331,6 +332,10 @@ enum class CompositableHandleOwner : uint8_t {
|
|||
struct RemoteTextureId {
|
||||
uint64_t mId = 0;
|
||||
|
||||
auto MutTiedFields() {
|
||||
return std::tie(mId);
|
||||
}
|
||||
|
||||
static RemoteTextureId GetNext();
|
||||
|
||||
bool IsValid() const { return mId != 0; }
|
||||
|
@ -370,6 +375,10 @@ struct RemoteTextureId {
|
|||
struct RemoteTextureOwnerId {
|
||||
uint64_t mId = 0;
|
||||
|
||||
auto MutTiedFields() {
|
||||
return std::tie(mId);
|
||||
}
|
||||
|
||||
static RemoteTextureOwnerId GetNext();
|
||||
|
||||
bool IsValid() const { return mId != 0; }
|
||||
|
|
Загрузка…
Ссылка в новой задаче