Bug 1607940 - IPC TexImage. r=lsalzman,nika,handyman

Differential Revision: https://phabricator.services.mozilla.com/D83291
This commit is contained in:
Jeff Gilbert 2020-07-21 22:57:01 +00:00
Родитель db06b9e526
Коммит f25a4cdbe8
31 изменённых файлов: 1100 добавлений и 923 удалений

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

@ -882,9 +882,10 @@ RefPtr<gfx::SourceSurface> ClientWebGLContext::GetFrontBufferSnapshot(
if (!child->SendGetFrontBufferSnapshot(&res)) {
res = {};
}
if (!res.shmem) return nullptr;
const auto& surfSize = res.surfSize;
const auto& shmemBytes = ByteRange(*res.shmem);
const webgl::RaiiShmem shmem{child, res.shmem};
const auto& shmemBytes = shmem.ByteRange();
if (!surfSize.x) return nullptr; // Zero means failure.
const auto stride = surfSize.x * 4;
const auto byteSize = stride * surfSize.y;
@ -1158,6 +1159,11 @@ already_AddRefed<WebGLSyncJS> ClientWebGLContext::FenceSync(
auto ret = AsRefPtr(new WebGLSyncJS(*this));
Run<RPROC(CreateSync)>(ret->mId);
auto& availRunnable = EnsureAvailabilityRunnable();
availRunnable.mSyncs.push_back(ret.get());
ret->mCanBeAvailable = false;
return ret.forget();
}
@ -1620,7 +1626,7 @@ void ClientWebGLContext::GetInternalformatParameter(
if (IsContextLost()) return;
const auto& inProcessContext = notLost->inProcess;
Maybe<std::vector<int>> maybe;
Maybe<std::vector<int32_t>> maybe;
if (inProcessContext) {
maybe = inProcessContext->GetInternalformatParameter(target, internalformat,
pname);
@ -1805,6 +1811,20 @@ void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname,
case LOCAL_GL_PACK_ALIGNMENT:
retval.set(JS::NumberValue(state.mPixelPackState.alignment));
return;
case LOCAL_GL_UNPACK_ALIGNMENT:
retval.set(JS::NumberValue(state.mPixelUnpackState.mUnpackAlignment));
return;
case dom::WebGLRenderingContext_Binding::UNPACK_FLIP_Y_WEBGL:
retval.set(JS::BooleanValue(state.mPixelUnpackState.mFlipY));
return;
case dom::WebGLRenderingContext_Binding::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
retval.set(JS::BooleanValue(state.mPixelUnpackState.mPremultiplyAlpha));
return;
case dom::WebGLRenderingContext_Binding::UNPACK_COLORSPACE_CONVERSION_WEBGL:
retval.set(
JS::NumberValue(state.mPixelUnpackState.mColorspaceConversion));
return;
// -
// Array returns
@ -1948,6 +1968,22 @@ void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname,
case LOCAL_GL_PACK_SKIP_ROWS:
retval.set(JS::NumberValue(state.mPixelPackState.skipRows));
return;
case LOCAL_GL_UNPACK_IMAGE_HEIGHT:
retval.set(JS::NumberValue(state.mPixelUnpackState.mUnpackImageHeight));
return;
case LOCAL_GL_UNPACK_ROW_LENGTH:
retval.set(JS::NumberValue(state.mPixelUnpackState.mUnpackRowLength));
return;
case LOCAL_GL_UNPACK_SKIP_IMAGES:
retval.set(JS::NumberValue(state.mPixelUnpackState.mUnpackSkipImages));
return;
case LOCAL_GL_UNPACK_SKIP_PIXELS:
retval.set(JS::NumberValue(state.mPixelUnpackState.mUnpackSkipPixels));
return;
case LOCAL_GL_UNPACK_SKIP_ROWS:
retval.set(JS::NumberValue(state.mPixelUnpackState.mUnpackSkipRows));
return;
} // switch pname
} // if webgl2
@ -2075,8 +2111,6 @@ void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname,
case LOCAL_GL_SAMPLE_COVERAGE_INVERT:
case LOCAL_GL_SCISSOR_TEST:
case LOCAL_GL_STENCIL_TEST:
case LOCAL_GL_UNPACK_FLIP_Y_WEBGL:
case LOCAL_GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL:
// WebGL 2:
case LOCAL_GL_RASTERIZER_DISCARD:
case LOCAL_GL_TRANSFORM_FEEDBACK_ACTIVE:
@ -2603,7 +2637,17 @@ void ClientWebGLContext::DepthRange(GLclampf zNear, GLclampf zFar) {
Run<RPROC(DepthRange)>(zNear, zFar);
}
void ClientWebGLContext::Flush() { Run<RPROC(Flush)>(); }
void ClientWebGLContext::Flush() {
const FuncScope funcScope(*this, "flush");
const auto notLost = mNotLost;
if (IsContextLost()) return;
Run<RPROC(Flush)>();
if (notLost->inProcess) return;
const auto& child = mNotLost->outOfProcess->mWebGLChild;
child->FlushPendingCmds();
}
void ClientWebGLContext::Finish() {
if (IsContextLost()) return;
@ -2650,6 +2694,10 @@ void ClientWebGLContext::LineWidth(GLfloat width) {
Run<RPROC(LineWidth)>(width);
}
Maybe<webgl::ErrorInfo> SetPixelUnpack(const bool isWebgl2,
WebGLPixelStore* const unpacking,
const GLenum pname, const GLint param);
void ClientWebGLContext::PixelStorei(const GLenum pname, const GLint iparam) {
const FuncScope funcScope(*this, "pixelStorei");
if (IsContextLost()) return;
@ -2690,11 +2738,23 @@ void ClientWebGLContext::PixelStorei(const GLenum pname, const GLint iparam) {
packState.skipRows = param;
return;
case dom::MOZ_debug_Binding::UNPACK_REQUIRE_FASTPATH:
if (!IsSupported(WebGLExtensionID::MOZ_debug)) {
EnqueueError_ArgEnum("pname", pname);
return;
}
break;
default:
break;
}
Run<RPROC(PixelStorei)>(pname, param);
const auto err =
SetPixelUnpack(mIsWebGL2, &state.mPixelUnpackState, pname, iparam);
if (err) {
EnqueueError(*err);
return;
}
}
void ClientWebGLContext::PolygonOffset(GLfloat factor, GLfloat units) {
@ -2992,15 +3052,22 @@ void ClientWebGLContext::GetBufferSubData(GLenum target, GLintptr srcByteOffset,
const auto& child = notLost->outOfProcess->mWebGLChild;
child->FlushPendingCmds();
mozilla::ipc::Shmem shmem;
mozilla::ipc::Shmem rawShmem;
if (!child->SendGetBufferSubData(target, srcByteOffset, destView.length(),
&shmem))
&rawShmem)) {
return;
if (!shmem.IsReadable()) return;
}
const webgl::RaiiShmem shmem{child, rawShmem};
const auto srcView = ByteRange(shmem);
MOZ_RELEASE_ASSERT(srcView.length() == destView.length());
Memcpy(destView.begin(), srcView.begin(), srcView.length());
const auto shmemView = shmem.ByteRange();
MOZ_RELEASE_ASSERT(shmemView.length() == 1 + destView.length());
const auto ok = bool(*(shmemView.begin().get()));
const auto srcView =
Range<const uint8_t>{shmemView.begin() + 1, shmemView.end()};
if (ok) {
Memcpy(destView.begin(), srcView.begin(), srcView.length());
}
}
////
@ -3736,9 +3803,26 @@ void ClientWebGLContext::TexStorage(uint8_t funcDims, GLenum texTarget,
internalFormat, CastUvec3(size));
}
namespace webgl {
// TODO: Move these definitions into statics here.
Maybe<webgl::TexUnpackBlobDesc> FromImageBitmap(
GLenum target, uvec3 size, const dom::ImageBitmap& imageBitmap,
ErrorResult* const out_rv);
webgl::TexUnpackBlobDesc FromImageData(GLenum target, uvec3 size,
const dom::ImageData& imageData,
dom::Uint8ClampedArray* const scopedArr);
Maybe<webgl::TexUnpackBlobDesc> FromDomElem(const ClientWebGLContext&,
GLenum target, uvec3 size,
const dom::Element& src,
const bool allowBlitImage,
ErrorResult* const out_error);
} // namespace webgl
void ClientWebGLContext::TexImage(uint8_t funcDims, GLenum imageTarget,
GLint level, GLenum respecFormat,
const ivec3& offset, const ivec3& size,
const ivec3& offset, const ivec3& isize,
GLint border, const webgl::PackingInfo& pi,
const TexImageSource& src) const {
const FuncScope funcScope(*this, "tex(Sub)Image[23]D");
@ -3751,37 +3835,127 @@ void ClientWebGLContext::TexImage(uint8_t funcDims, GLenum imageTarget,
EnqueueError(LOCAL_GL_INVALID_VALUE, "`border` must be 0.");
return;
}
const auto explicitSize = CastUvec3(isize);
if (src.mView) {
const auto& view = *src.mView;
const auto& jsType = view.Type();
const auto err = JSTypeMatchUnpackTypeError(pi.type, jsType);
switch (err) {
case LOCAL_GL_INVALID_ENUM:
EnqueueError_ArgEnum("unpackType", pi.type);
return;
case LOCAL_GL_INVALID_OPERATION:
EnqueueError(LOCAL_GL_INVALID_OPERATION,
"ArrayBufferView type %s not compatible with `type` %s.",
ToString(jsType).c_str(), EnumString(pi.type).c_str());
return;
default:
break;
// -
dom::Uint8ClampedArray scopedArr;
// -
bool isDataUpload = false;
auto desc = [&]() -> Maybe<webgl::TexUnpackBlobDesc> {
if (src.mPboOffset) {
isDataUpload = true;
const auto offset = static_cast<uint64_t>(*src.mPboOffset);
return Some(webgl::TexUnpackBlobDesc{imageTarget,
explicitSize,
gfxAlphaType::NonPremult,
{},
Some(offset)});
}
if (src.mView) {
isDataUpload = true;
const auto& view = *src.mView;
const auto& jsType = view.Type();
const auto err = JSTypeMatchUnpackTypeError(pi.type, jsType);
switch (err) {
case LOCAL_GL_INVALID_ENUM:
EnqueueError_ArgEnum("unpackType", pi.type);
return {};
case LOCAL_GL_INVALID_OPERATION:
EnqueueError(LOCAL_GL_INVALID_OPERATION,
"ArrayBufferView type %s not compatible with `type` %s.",
ToString(jsType).c_str(), EnumString(pi.type).c_str());
return {};
default:
break;
}
const auto range = GetRangeFromView(view, src.mViewElemOffset,
src.mViewElemLengthOverride);
if (!range) {
EnqueueError(LOCAL_GL_INVALID_OPERATION, "`source` too small.");
return {};
}
return Some(webgl::TexUnpackBlobDesc{imageTarget,
explicitSize,
gfxAlphaType::NonPremult,
Some(RawBuffer<>{*range}),
{}});
}
if (src.mImageBitmap) {
return webgl::FromImageBitmap(imageTarget, explicitSize,
*(src.mImageBitmap), src.mOut_error);
}
if (src.mImageData) {
return Some(webgl::FromImageData(imageTarget, explicitSize,
*(src.mImageData), &scopedArr));
}
if (src.mDomElem) {
bool canUseLayerImage = true;
if (StaticPrefs::webgl_disable_DOM_blit_uploads()) {
canUseLayerImage = false;
}
if (mNotLost && mNotLost->outOfProcess) {
canUseLayerImage = false;
}
return webgl::FromDomElem(*this, imageTarget, explicitSize,
*(src.mDomElem), canUseLayerImage,
src.mOut_error);
}
return Some(webgl::TexUnpackBlobDesc{
imageTarget, explicitSize, gfxAlphaType::NonPremult, {}, {}});
}();
if (!desc) return;
// -
// Further, for uploads from TexImageSource, implied UNPACK_ROW_LENGTH and
// UNPACK_ALIGNMENT are not strictly defined. These restrictions ensure
// consistent and efficient behavior regardless of implied UNPACK_ params.
Maybe<gfx::IntSize> structuredSrcSize;
if (desc->surf) {
structuredSrcSize = Some(desc->surf->GetSize());
}
if (desc->image) {
structuredSrcSize = Some(desc->image->GetSize());
}
if (structuredSrcSize) {
auto& size = desc->size;
if (!size.x) {
size.x = structuredSrcSize->width;
}
if (!size.y) {
size.y = structuredSrcSize->height;
}
}
const auto notLost =
mNotLost; // Hold a strong-ref to prevent LoseContext=>UAF.
if (!notLost) return;
const auto& inProcessContext = notLost->inProcess;
Maybe<std::vector<int>> maybe;
if (inProcessContext) {
inProcessContext->TexImage(imageTarget, static_cast<uint32_t>(level),
respecFormat, CastUvec3(offset), CastUvec3(size),
pi, src, *GetCanvas());
} else {
MOZ_ASSERT_UNREACHABLE("TODO: Remote GetInternalformatParameter");
const auto& rawUnpacking = State().mPixelUnpackState;
const bool isSubrect =
(rawUnpacking.mUnpackImageHeight || rawUnpacking.mUnpackSkipImages ||
rawUnpacking.mUnpackRowLength || rawUnpacking.mUnpackSkipRows ||
rawUnpacking.mUnpackSkipPixels);
if (isDataUpload && isSubrect) {
if (rawUnpacking.mFlipY || rawUnpacking.mPremultiplyAlpha) {
EnqueueError(LOCAL_GL_INVALID_OPERATION,
"Non-DOM-Element uploads with alpha-premult"
" or y-flip do not support subrect selection.");
return;
}
}
desc->unpacking =
rawUnpacking.ForUseWith(desc->imageTarget, desc->size, structuredSrcSize);
// -
Run<RPROC(TexImage)>(static_cast<uint32_t>(level), respecFormat,
CastUvec3(offset), pi, std::move(*desc));
}
void ClientWebGLContext::CompressedTexImage(bool sub, uint8_t funcDims,
@ -4314,7 +4488,8 @@ void ClientWebGLContext::DoReadPixels(const webgl::ReadPixelsDesc& desc,
if (!res.byteStride) return;
const auto& byteStride = res.byteStride;
const auto& subrect = res.subrect;
const auto& shmemBytes = ByteRange(res.shmem);
const webgl::RaiiShmem shmem{child, res.shmem};
const auto& shmemBytes = shmem.ByteRange();
uint8_t bpp;
if (!GetBytesPerPixel(desc.pi, &bpp)) {
@ -4322,21 +4497,27 @@ void ClientWebGLContext::DoReadPixels(const webgl::ReadPixelsDesc& desc,
return;
}
const auto& packing = desc.packState;
auto packRect = *uvec2::From(subrect.x, subrect.y);
packRect.x += packing.skipPixels;
packRect.y += packing.skipRows;
const auto xByteSize = bpp * static_cast<uint32_t>(subrect.width);
const ptrdiff_t byteOffset = subrect.y * byteStride + subrect.x * bpp;
const ptrdiff_t byteOffset = packRect.y * byteStride + packRect.x * bpp;
auto srcItr = shmemBytes.begin() + byteOffset;
auto destItr = dest.begin() + byteOffset;
for (const auto i : IntegerRange(subrect.height)) {
Unused << i;
MOZ_RELEASE_ASSERT(srcItr + xByteSize <= shmemBytes.end());
MOZ_RELEASE_ASSERT(destItr + xByteSize <= dest.end());
if (i) {
// Don't trigger an assert on the last loop by pushing a RangedPtr past
// its bounds.
srcItr += byteStride;
destItr += byteStride;
MOZ_RELEASE_ASSERT(srcItr + xByteSize <= shmemBytes.end());
MOZ_RELEASE_ASSERT(destItr + xByteSize <= dest.end());
}
Memcpy(destItr, srcItr, xByteSize);
srcItr += byteStride;
destItr += byteStride;
}
}
@ -4418,7 +4599,7 @@ void ClientWebGLContext::GetQueryParameter(
if (IsContextLost()) return;
if (!query.ValidateUsable(*this, "query")) return;
const auto maybe = [&]() {
auto maybe = [&]() {
const auto& inProcess = mNotLost->inProcess;
if (inProcess) {
return inProcess->GetQueryParameter(query.mId, pname);
@ -4431,17 +4612,26 @@ void ClientWebGLContext::GetQueryParameter(
}
return ret;
}();
if (!maybe) return;
if (maybe) {
switch (pname) {
case LOCAL_GL_QUERY_RESULT_AVAILABLE:
retval.set(JS::BooleanValue(*maybe));
break;
default:
retval.set(JS::NumberValue(*maybe));
break;
// We must usually wait for an event loop before the query can be available.
const bool canBeAvailable =
(query.mCanBeAvailable || StaticPrefs::webgl_allow_immediate_queries());
if (!canBeAvailable) {
if (pname != LOCAL_GL_QUERY_RESULT_AVAILABLE) {
return;
}
maybe = Some(0.0);
}
switch (pname) {
case LOCAL_GL_QUERY_RESULT_AVAILABLE:
retval.set(JS::BooleanValue(*maybe));
break;
default:
retval.set(JS::NumberValue(*maybe));
break;
}
}
@ -4498,10 +4688,14 @@ void ClientWebGLContext::EndQuery(const GLenum specificTarget) {
EnumString(specificTarget).c_str());
return;
}
const auto query = slot;
slot = nullptr;
Run<RPROC(EndQuery)>(specificTarget);
auto& availRunnable = EnsureAvailabilityRunnable();
availRunnable.mQueries.push_back(query.get());
query->mCanBeAvailable = false;
}
void ClientWebGLContext::QueryCounter(WebGLQueryJS& query,
@ -4523,6 +4717,10 @@ void ClientWebGLContext::QueryCounter(WebGLQueryJS& query,
query.mTarget = target;
Run<RPROC(QueryCounter)>(query.mId);
auto& availRunnable = EnsureAvailabilityRunnable();
availRunnable.mQueries.push_back(&query);
query.mCanBeAvailable = false;
}
// -------------------------------- Sampler -------------------------------
@ -4661,6 +4859,19 @@ GLenum ClientWebGLContext::ClientWaitSync(WebGLSyncJS& sync,
break;
}
// -
const bool canBeAvailable =
(sync.mCanBeAvailable || StaticPrefs::webgl_allow_immediate_queries());
if (!canBeAvailable) {
if (timeout) {
EnqueueWarning(
"Sync object not yet queryable. Please wait for the event"
" loop.");
}
return LOCAL_GL_WAIT_FAILED;
}
return ret;
}

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

@ -46,6 +46,7 @@ class WebGLChild;
}
namespace webgl {
class AvailabilityRunnable;
class TexUnpackBlob;
class TexUnpackBytes;
} // namespace webgl
@ -175,6 +176,7 @@ class ContextGenerationInfo final {
std::array<float, 4> mBlendColor = {{0, 0, 0, 0}};
std::array<float, 2> mDepthRange = {{0, 1}};
webgl::PixelPackState mPixelPackState;
WebGLPixelStore mPixelUnpackState;
std::vector<GLenum> mCompressedTextureFormats;
@ -388,14 +390,19 @@ class WebGLProgramJS final : public nsWrapperCache, public webgl::ObjectJS {
// -
class WebGLQueryJS final : public nsWrapperCache, public webgl::ObjectJS {
class WebGLQueryJS final : public nsWrapperCache,
public webgl::ObjectJS,
public SupportsWeakPtr<WebGLQueryJS> {
friend class ClientWebGLContext;
friend class webgl::AvailabilityRunnable;
GLenum mTarget = 0; // !IsQuery until Bind
bool mCanBeAvailable = false;
public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLQueryJS)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLQueryJS)
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(WebGLQueryJS)
explicit WebGLQueryJS(const ClientWebGLContext& webgl)
: webgl::ObjectJS(webgl) {}
@ -483,14 +490,19 @@ class WebGLShaderJS final : public nsWrapperCache, public webgl::ObjectJS {
// -
class WebGLSyncJS final : public nsWrapperCache, public webgl::ObjectJS {
class WebGLSyncJS final : public nsWrapperCache,
public webgl::ObjectJS,
public SupportsWeakPtr<WebGLSyncJS> {
friend class ClientWebGLContext;
friend class webgl::AvailabilityRunnable;
bool mCanBeAvailable = false;
bool mSignaled = false;
public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLSyncJS)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLSyncJS)
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(WebGLSyncJS)
explicit WebGLSyncJS(const ClientWebGLContext& webgl)
: webgl::ObjectJS(webgl) {}
@ -694,6 +706,7 @@ struct TexImageSourceAdapter final : public TexImageSource {
class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
public nsWrapperCache,
public SupportsWeakPtr<ClientWebGLContext> {
friend class webgl::AvailabilityRunnable;
friend class webgl::ObjectJS;
friend class webgl::ProgramKeepAlive;
friend class webgl::ShaderKeepAlive;
@ -753,6 +766,14 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
// -
private:
mutable RefPtr<webgl::AvailabilityRunnable> mAvailabilityRunnable;
public:
webgl::AvailabilityRunnable& EnsureAvailabilityRunnable() const;
// -
public:
void EmulateLoseContext() const;
void OnContextLoss(webgl::ContextLossReason) const;
@ -2105,9 +2126,6 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
// -------------------------------------------------------------------------
public:
WebGLPixelStore GetPixelStore() { return mPixelStore; }
const WebGLPixelStore GetPixelStore() const { return mPixelStore; }
// https://immersive-web.github.io/webxr/#xr-compatible
bool IsXRCompatible() const;
already_AddRefed<dom::Promise> MakeXRCompatible(ErrorResult& aRv);
@ -2125,7 +2143,6 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
bool mResetLayer = true;
Maybe<const WebGLContextOptions> mInitialOptions;
WebGLPixelStore mPixelStore;
bool mXRCompatible = false;
};

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

@ -425,10 +425,6 @@ class HostWebGLContext final : public SupportsWeakPtr<HostWebGLContext> {
mContext->LinkProgram(*obj);
}
void PixelStorei(GLenum pname, uint32_t param) const {
mContext->PixelStorei(pname, param);
}
void PolygonOffset(GLfloat factor, GLfloat units) const {
mContext->PolygonOffset(factor, units);
}
@ -570,12 +566,10 @@ class HostWebGLContext final : public SupportsWeakPtr<HostWebGLContext> {
}
// TexSubImage if `!respecFormat`
void TexImage(GLenum imageTarget, uint32_t level, GLenum respecFormat,
const uvec3& offset, const uvec3& size,
const webgl::PackingInfo& pi, const TexImageSource& src,
const dom::HTMLCanvasElement& canvas) const {
mContext->TexImage(imageTarget, level, respecFormat, offset, size, pi, src,
canvas);
void TexImage(uint32_t level, GLenum respecFormat, const uvec3& offset,
const webgl::PackingInfo& pi,
const webgl::TexUnpackBlobDesc& src) const {
mContext->TexImage(level, respecFormat, offset, pi, src);
}
void TexStorage(GLenum texTarget, uint32_t levels, GLenum internalFormat,

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

@ -12,6 +12,7 @@ using mozilla::layers::CompositableHandle from "mozilla/layers/LayersTypes.h";
using mozilla::layers::SurfaceDescriptor from "mozilla/layers/LayersTypes.h";
using std::string from "ipc/IPCMessageUtils.h";
using mozilla::uvec2 from "mozilla/dom/WebGLIpdl.h";
using mozilla::webgl::Int32Vector from "mozilla/dom/WebGLIpdl.h";
using mozilla::webgl::CompileResult from "mozilla/dom/WebGLIpdl.h";
using mozilla::webgl::ContextLossReason from "mozilla/dom/WebGLIpdl.h";
using mozilla::webgl::FrontBufferSnapshotIpc from "mozilla/dom/WebGLIpdl.h";
@ -20,11 +21,7 @@ using mozilla::webgl::InitContextDesc from "mozilla/dom/WebGLIpdl.h";
using mozilla::webgl::InitContextResult from "mozilla/dom/WebGLIpdl.h";
using mozilla::webgl::Int32Vector from "mozilla/dom/WebGLIpdl.h";
using mozilla::webgl::LinkResult from "mozilla/dom/WebGLIpdl.h";
using mozilla::webgl::MaybeDouble from "mozilla/dom/WebGLIpdl.h";
using mozilla::webgl::MaybeFrontBufferSnapshotIpc from "mozilla/dom/WebGLIpdl.h";
using mozilla::webgl::MaybeShaderPrecisionFormat from "mozilla/dom/WebGLIpdl.h";
using mozilla::webgl::MaybeSurfaceDescriptor from "mozilla/dom/WebGLIpdl.h";
using mozilla::webgl::MaybeString from "mozilla/dom/WebGLIpdl.h";
using mozilla::webgl::ShaderPrecisionFormat from "mozilla/dom/WebGLIpdl.h";
using mozilla::webgl::OpaqueFramebufferOptions from "mozilla/dom/WebGLIpdl.h";
using mozilla::webgl::ReadPixelsDesc from "mozilla/dom/WebGLIpdl.h";
using mozilla::webgl::ReadPixelsResultIpc from "mozilla/dom/WebGLIpdl.h";
@ -58,6 +55,7 @@ parent:
// -
sync GetBufferSubData(uint32_t target, uint64_t srcByteOffset, uint64_t byteSize) returns (Shmem ret);
sync GetFrontBufferSnapshot() returns (FrontBufferSnapshotIpc ret);
sync ReadPixels(ReadPixelsDesc desc, uint64_t maxBytes) returns (ReadPixelsResultIpc ret);
@ -68,28 +66,27 @@ parent:
sync CreateOpaqueFramebuffer(uint64_t id, OpaqueFramebufferOptions options) returns (bool ret);
sync DrawingBufferSize() returns (uvec2 ret);
sync Finish();
sync GetBufferParameter(uint32_t target, uint32_t pname) returns (MaybeDouble ret);
sync GetBufferSubData(uint32_t target, uint64_t srcByteOffset, uint64_t byteSize) returns (Shmem ret);
sync GetBufferParameter(uint32_t target, uint32_t pname) returns (double? ret);
sync GetCompileResult(uint64_t id) returns (CompileResult ret);
sync GetError() returns (uint32_t ret);
sync GetFragDataLocation(uint64_t id, string name) returns (int32_t ret);
sync GetFramebufferAttachmentParameter(uint64_t id,
uint32_t attachment,
uint32_t pname) returns (MaybeDouble ret);
sync GetFrontBuffer(uint64_t fb, bool vr) returns (MaybeSurfaceDescriptor ret);
sync GetIndexedParameter(uint32_t target, uint32_t index) returns (MaybeDouble ret);
uint32_t pname) returns (double? ret);
sync GetFrontBuffer(uint64_t fb, bool vr) returns (SurfaceDescriptor? ret);
sync GetIndexedParameter(uint32_t target, uint32_t index) returns (double? ret);
sync GetInternalformatParameter(uint32_t target, uint32_t internalFormat, uint32_t pname) returns (Int32Vector? ret);
sync GetLinkResult(uint64_t id) returns (LinkResult ret);
sync GetNumber(uint32_t pname) returns (MaybeDouble ret);
sync GetQueryParameter(uint64_t id, uint32_t pname) returns (MaybeDouble ret);
sync GetRenderbufferParameter(uint64_t id, uint32_t pname) returns (MaybeDouble ret);
sync GetSamplerParameter(uint64_t id, uint32_t pname) returns (MaybeDouble ret);
sync GetNumber(uint32_t pname) returns (double? ret);
sync GetQueryParameter(uint64_t id, uint32_t pname) returns (double? ret);
sync GetRenderbufferParameter(uint64_t id, uint32_t pname) returns (double? ret);
sync GetSamplerParameter(uint64_t id, uint32_t pname) returns (double? ret);
sync GetShaderPrecisionFormat(
uint32_t shaderType, uint32_t precisionType) returns (MaybeShaderPrecisionFormat ret);
sync GetString(uint32_t pname) returns (MaybeString ret);
sync GetTexParameter(uint64_t id, uint32_t pname) returns (MaybeDouble ret);
uint32_t shaderType, uint32_t precisionType) returns (ShaderPrecisionFormat? ret);
sync GetString(uint32_t pname) returns (string? ret);
sync GetTexParameter(uint64_t id, uint32_t pname) returns (double? ret);
sync GetUniform(uint64_t id, uint32_t loc) returns (GetUniformData ret);
sync GetVertexAttrib(uint32_t index, uint32_t pname) returns (MaybeDouble ret);
sync GetVertexAttrib(uint32_t index, uint32_t pname) returns (double? ret);
sync IsEnabled(uint32_t cap) returns (bool ret);
sync OnMemoryPressure();
sync ValidateProgram(uint64_t id) returns (bool ret);

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

@ -8,15 +8,17 @@
#ifndef _QUEUEPARAMTRAITS_H_
#define _QUEUEPARAMTRAITS_H_ 1
#include "mozilla/ipc/SharedMemoryBasic.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/Assertions.h"
#include "mozilla/IntegerRange.h"
#include "mozilla/ipc/Shmem.h"
#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/ipc/SharedMemoryBasic.h"
#include "mozilla/ipc/Shmem.h"
#include "mozilla/Logging.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/TypeTraits.h"
#include "nsString.h"
#include "WebGLTypes.h"
namespace mozilla {
namespace webgl {
@ -168,6 +170,13 @@ class ProducerView {
reinterpret_cast<const uint8_t*>(end));
}
template <typename T>
inline QueueStatus WritePod(const T& in) {
static_assert(std::is_trivially_copyable_v<T>);
const auto begin = reinterpret_cast<const uint8_t*>(&in);
return Write(begin, begin + sizeof(T));
}
/**
* Serialize aArg using Arg's QueueParamTraits.
*/
@ -213,6 +222,13 @@ class ConsumerView {
reinterpret_cast<uint8_t*>(end));
}
template <typename T>
inline QueueStatus ReadPod(T* out) {
static_assert(std::is_trivially_copyable_v<T>);
const auto begin = reinterpret_cast<uint8_t*>(out);
return Read(begin, begin + sizeof(T));
}
/**
* Deserialize aArg using Arg's QueueParamTraits.
* If the return value is not Success then aArg is not changed.
@ -234,19 +250,23 @@ class ConsumerView {
};
template <typename T>
QueueStatus ProducerView<T>::Write(const uint8_t* begin, const uint8_t* end) {
MOZ_ASSERT(begin);
MOZ_ASSERT(begin < end);
if (IsSuccess(mStatus)) {
QueueStatus ProducerView<T>::Write(const uint8_t* const begin,
const uint8_t* const end) {
MOZ_ASSERT(begin <= end);
if (!mStatus) return mStatus;
if (begin < end) {
MOZ_ASSERT(begin);
mStatus = mProducer->WriteObject(mRead, mWrite, begin, end - begin);
}
return mStatus;
}
template <typename T>
QueueStatus ConsumerView<T>::Read(uint8_t* begin, uint8_t* end) {
MOZ_ASSERT(begin < end);
if (IsSuccess(mStatus)) {
QueueStatus ConsumerView<T>::Read(uint8_t* const begin, uint8_t* const end) {
MOZ_ASSERT(begin <= end);
if (!mStatus) return mStatus;
if (begin < end) {
MOZ_ASSERT(begin);
mStatus = mConsumer->ReadObject(mRead, mWrite, begin, end - begin);
}
return mStatus;
@ -336,6 +356,82 @@ struct QueueParamTraits<QueueStatus>
// ---------------------------------------------------------------
template <>
struct QueueParamTraits<webgl::TexUnpackBlobDesc> {
using ParamType = webgl::TexUnpackBlobDesc;
template <typename U>
static QueueStatus Write(ProducerView<U>& view, const ParamType& in) {
MOZ_ASSERT(!in.image);
const bool isSurf = bool(in.surf);
if (!view.WriteParam(in.imageTarget) || !view.WriteParam(in.size) ||
!view.WriteParam(in.srcAlphaType) || !view.WriteParam(in.unpacking) ||
!view.WriteParam(in.cpuData) || !view.WriteParam(in.pboOffset) ||
!view.WriteParam(isSurf)) {
return view.GetStatus();
}
if (isSurf) {
gfx::DataSourceSurface::ScopedMap map(in.surf,
gfx::DataSourceSurface::READ);
if (!map.IsMapped()) {
return QueueStatus::kOOMError;
}
const auto& surfSize = in.surf->GetSize();
const auto stride = *MaybeAs<size_t>(map.GetStride());
if (!view.WriteParam(surfSize) ||
!view.WriteParam(in.surf->GetFormat()) || !view.WriteParam(stride)) {
return view.GetStatus();
}
const size_t dataSize = stride * surfSize.height;
const auto& begin = map.GetData();
if (!view.Write(begin, begin + dataSize)) {
return view.GetStatus();
}
}
return QueueStatus::kSuccess;
}
template <typename U>
static QueueStatus Read(ConsumerView<U>& view, ParamType* const out) {
bool isSurf;
if (!view.ReadParam(&out->imageTarget) || !view.ReadParam(&out->size) ||
!view.ReadParam(&out->srcAlphaType) ||
!view.ReadParam(&out->unpacking) || !view.ReadParam(&out->cpuData) ||
!view.ReadParam(&out->pboOffset) || !view.ReadParam(&isSurf)) {
return view.GetStatus();
}
if (isSurf) {
gfx::IntSize surfSize;
gfx::SurfaceFormat format;
size_t stride;
if (!view.ReadParam(&surfSize) || !view.ReadParam(&format) ||
!view.ReadParam(&stride)) {
return view.GetStatus();
}
out->surf = gfx::Factory::CreateDataSourceSurfaceWithStride(
surfSize, format, stride, true);
if (!out->surf) {
return QueueStatus::kOOMError;
}
gfx::DataSourceSurface::ScopedMap map(out->surf,
gfx::DataSourceSurface::WRITE);
if (!map.IsMapped()) {
return QueueStatus::kOOMError;
}
const size_t dataSize = stride * surfSize.height;
const auto& begin = map.GetData();
if (!view.Read(begin, begin + dataSize)) {
return view.GetStatus();
}
}
return QueueStatus::kSuccess;
}
};
// ---------------------------------------------------------------
template <>
struct QueueParamTraits<nsACString> {
using ParamType = nsACString;

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

@ -18,6 +18,31 @@
#include "WebGLTexture.h"
namespace mozilla {
void WebGLPixelStore::Apply(gl::GLContext& gl, const bool isWebgl2,
const uvec3& uploadSize) const {
gl.fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, mUnpackAlignment);
if (!isWebgl2) return;
// Re-simplify. (ANGLE seems to have an issue with imageHeight ==
// uploadSize.y)
auto rowLength = mUnpackRowLength;
auto imageHeight = mUnpackImageHeight;
if (rowLength == uploadSize.x) {
rowLength = 0;
}
if (imageHeight == uploadSize.y) {
imageHeight = 0;
}
gl.fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength);
gl.fPixelStorei(LOCAL_GL_UNPACK_IMAGE_HEIGHT, imageHeight);
gl.fPixelStorei(LOCAL_GL_UNPACK_SKIP_PIXELS, mUnpackSkipPixels);
gl.fPixelStorei(LOCAL_GL_UNPACK_SKIP_ROWS, mUnpackSkipRows);
gl.fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES, mUnpackSkipImages);
}
namespace webgl {
static bool IsPIValidForDOM(const webgl::PackingInfo& pi) {
@ -65,7 +90,7 @@ static bool IsPIValidForDOM(const webgl::PackingInfo& pi) {
return true;
}
static bool ValidatePIForDOM(WebGLContext* webgl,
static bool ValidatePIForDOM(const WebGLContext* const webgl,
const webgl::PackingInfo& pi) {
if (!IsPIValidForDOM(pi)) {
webgl->ErrorInvalidValue("Format or type is invalid for DOM sources.");
@ -178,21 +203,33 @@ static WebGLTexelFormat FormatForPackingInfo(const PackingInfo& pi) {
////////////////////
static bool ValidateUnpackPixels(WebGLContext* webgl, uint32_t fullRows,
uint32_t tailPixels,
webgl::TexUnpackBlob* blob) {
if (!blob->mWidth || !blob->mHeight || !blob->mDepth) return true;
static uint32_t ZeroOn2D(const GLenum target, const uint32_t val) {
const bool is2d = !IsTexTarget3D(target);
if (is2d) return 0;
return val;
}
const auto usedPixelsPerRow = CheckedUint32(blob->mSkipPixels) + blob->mWidth;
static bool ValidateUnpackPixels(const WebGLContext* webgl, uint32_t fullRows,
uint32_t tailPixels,
webgl::TexUnpackBlob* const blob) {
const auto& size = blob->mDesc.size;
if (!size.x || !size.y || !size.z) return true;
const auto& unpacking = blob->mDesc.unpacking;
// -
const auto usedPixelsPerRow =
CheckedUint32(unpacking.mUnpackSkipPixels) + size.x;
if (!usedPixelsPerRow.isValid() ||
usedPixelsPerRow.value() > blob->mRowLength) {
usedPixelsPerRow.value() > unpacking.mUnpackRowLength) {
webgl->ErrorInvalidOperation(
"UNPACK_SKIP_PIXELS + width >"
" UNPACK_ROW_LENGTH.");
return false;
}
if (blob->mHeight > blob->mImageHeight) {
if (size.y > unpacking.mUnpackImageHeight) {
webgl->ErrorInvalidOperation("height > UNPACK_IMAGE_HEIGHT.");
return false;
}
@ -200,14 +237,15 @@ static bool ValidateUnpackPixels(WebGLContext* webgl, uint32_t fullRows,
//////
// The spec doesn't bound SKIP_ROWS + height <= IMAGE_HEIGHT, unfortunately.
auto skipFullRows = CheckedUint32(blob->mSkipImages) * blob->mImageHeight;
skipFullRows += blob->mSkipRows;
auto skipFullRows =
CheckedUint32(unpacking.mUnpackSkipImages) * unpacking.mUnpackImageHeight;
skipFullRows += unpacking.mUnpackSkipRows;
MOZ_ASSERT(blob->mDepth >= 1);
MOZ_ASSERT(blob->mHeight >= 1);
auto usedFullRows = CheckedUint32(blob->mDepth - 1) * blob->mImageHeight;
usedFullRows +=
blob->mHeight - 1; // Full rows in the final image, excluding the tail.
// Full rows in the final image, excluding the tail.
MOZ_ASSERT(size.y >= 1);
MOZ_ASSERT(size.z >= 1);
auto usedFullRows = CheckedUint32(size.z - 1) * unpacking.mUnpackImageHeight;
usedFullRows += size.y - 1;
const auto fullRowsNeeded = skipFullRows + usedFullRows;
if (!fullRowsNeeded.isValid()) {
@ -215,11 +253,14 @@ static bool ValidateUnpackPixels(WebGLContext* webgl, uint32_t fullRows,
return false;
}
if (fullRows > fullRowsNeeded.value()) return true;
if (fullRows > fullRowsNeeded.value()) {
blob->mNeedsExactUpload = false;
return true;
}
if (fullRows == fullRowsNeeded.value() &&
tailPixels >= usedPixelsPerRow.value()) {
blob->mNeedsExactUpload = true;
MOZ_ASSERT(blob->mNeedsExactUpload);
return true;
}
@ -231,15 +272,19 @@ static bool ValidateUnpackPixels(WebGLContext* webgl, uint32_t fullRows,
return false;
}
static bool ValidateUnpackBytes(WebGLContext* webgl,
static bool ValidateUnpackBytes(const WebGLContext* const webgl,
const webgl::PackingInfo& pi,
size_t availByteCount,
webgl::TexUnpackBlob* blob) {
if (!blob->mWidth || !blob->mHeight || !blob->mDepth) return true;
webgl::TexUnpackBlob* const blob) {
const auto& size = blob->mDesc.size;
if (!size.x || !size.y || !size.z) return true;
const auto& unpacking = blob->mDesc.unpacking;
const auto bytesPerPixel = webgl::BytesPerPixel(pi);
const auto bytesPerRow = CheckedUint32(blob->mRowLength) * bytesPerPixel;
const auto rowStride = RoundUpToMultipleOf(bytesPerRow, blob->mAlignment);
const auto bytesPerRow =
CheckedUint32(unpacking.mUnpackRowLength) * bytesPerPixel;
const auto rowStride =
RoundUpToMultipleOf(bytesPerRow, unpacking.mUnpackAlignment);
const auto fullRows = availByteCount / rowStride;
if (!fullRows.isValid()) {
@ -255,39 +300,39 @@ static bool ValidateUnpackBytes(WebGLContext* webgl,
////////////////////
static uint32_t ZeroOn2D(TexImageTarget target, uint32_t val) {
return (IsTarget3D(target) ? val : 0);
}
// static
std::unique_ptr<TexUnpackBlob> TexUnpackBlob::Create(
const TexUnpackBlobDesc& desc) {
return std::unique_ptr<TexUnpackBlob>{[&]() -> TexUnpackBlob* {
if (!IsTarget3D(desc.imageTarget) && desc.size.z != 1) {
MOZ_ASSERT(false);
return nullptr;
}
static uint32_t FallbackOnZero(uint32_t val, uint32_t fallback) {
return (val ? val : fallback);
}
switch (desc.unpacking.mUnpackAlignment) {
case 1:
case 2:
case 4:
case 8:
break;
default:
MOZ_ASSERT(false);
return nullptr;
}
TexUnpackBlob::TexUnpackBlob(const WebGLContext* webgl, TexImageTarget target,
uint32_t rowLength, uint32_t width,
uint32_t height, uint32_t depth,
gfxAlphaType srcAlphaType)
: mAlignment(webgl->mPixelStore.mUnpackAlignment),
mRowLength(rowLength),
mImageHeight(FallbackOnZero(
ZeroOn2D(target, webgl->mPixelStore.mUnpackImageHeight), height))
if (desc.image) {
return new TexUnpackImage(desc);
}
if (desc.surf) {
return new TexUnpackSurface(desc);
}
,
mSkipPixels(webgl->mPixelStore.mUnpackSkipPixels),
mSkipRows(webgl->mPixelStore.mUnpackSkipRows),
mSkipImages(ZeroOn2D(target, webgl->mPixelStore.mUnpackSkipImages))
,
mWidth(width),
mHeight(height),
mDepth(depth)
,
mSrcAlphaType(srcAlphaType)
,
mNeedsExactUpload(false) {
MOZ_ASSERT_IF(!IsTarget3D(target), mDepth == 1);
if (desc.srcAlphaType != gfxAlphaType::NonPremult) {
MOZ_ASSERT(false);
return nullptr;
}
return new TexUnpackBytes(desc);
}()};
}
static bool HasColorAndAlpha(const WebGLTexelFormat format) {
@ -308,22 +353,25 @@ static bool HasColorAndAlpha(const WebGLTexelFormat format) {
}
bool TexUnpackBlob::ConvertIfNeeded(
WebGLContext* webgl, const uint32_t rowLength, const uint32_t rowCount,
WebGLTexelFormat srcFormat, const uint8_t* const srcBegin,
const ptrdiff_t srcStride, WebGLTexelFormat dstFormat,
const ptrdiff_t dstStride, const uint8_t** const out_begin,
const WebGLContext* const webgl, const uint32_t rowLength,
const uint32_t rowCount, WebGLTexelFormat srcFormat,
const uint8_t* const srcBegin, const ptrdiff_t srcStride,
WebGLTexelFormat dstFormat, const ptrdiff_t dstStride,
const uint8_t** const out_begin,
UniqueBuffer* const out_anchoredBuffer) const {
MOZ_ASSERT(srcFormat != WebGLTexelFormat::FormatNotSupportingAnyConversion);
MOZ_ASSERT(dstFormat != WebGLTexelFormat::FormatNotSupportingAnyConversion);
*out_begin = srcBegin;
const auto& unpacking = mDesc.unpacking;
if (!rowLength || !rowCount) return true;
const auto srcIsPremult = (mSrcAlphaType == gfxAlphaType::Premult);
const auto& dstIsPremult = webgl->mPixelStore.mPremultiplyAlpha;
const auto srcIsPremult = (mDesc.srcAlphaType == gfxAlphaType::Premult);
const auto& dstIsPremult = unpacking.mPremultiplyAlpha;
const auto fnHasPremultMismatch = [&]() {
if (mSrcAlphaType == gfxAlphaType::Opaque) return false;
if (mDesc.srcAlphaType == gfxAlphaType::Opaque) return false;
if (!HasColorAndAlpha(srcFormat)) return false;
@ -331,8 +379,7 @@ bool TexUnpackBlob::ConvertIfNeeded(
};
const auto srcOrigin =
(webgl->mPixelStore.mFlipY ? gl::OriginPos::TopLeft
: gl::OriginPos::BottomLeft);
(unpacking.mFlipY ? gl::OriginPos::TopLeft : gl::OriginPos::BottomLeft);
const auto dstOrigin = gl::OriginPos::BottomLeft;
if (srcFormat != dstFormat) {
@ -399,66 +446,77 @@ static GLenum DoTexOrSubImage(bool isSubImage, gl::GLContext* gl,
//////////////////////////////////////////////////////////////////////////////////////////
// TexUnpackBytes
TexUnpackBytes::TexUnpackBytes(const WebGLContext* webgl, TexImageTarget target,
uint32_t width, uint32_t height, uint32_t depth,
bool isClientData, const uint8_t* ptr,
size_t availBytes)
: TexUnpackBlob(webgl, target,
FallbackOnZero(webgl->mPixelStore.mUnpackRowLength, width),
width, height, depth, gfxAlphaType::NonPremult),
mIsClientData(isClientData),
mPtr(ptr),
mAvailBytes(availBytes) {}
bool TexUnpackBytes::Validate(WebGLContext* webgl,
bool TexUnpackBytes::Validate(const WebGLContext* const webgl,
const webgl::PackingInfo& pi) {
if (mIsClientData && !mPtr) return true;
if (!HasData()) return true;
return ValidateUnpackBytes(webgl, pi, mAvailBytes, this);
CheckedInt<size_t> availBytes = 0;
if (mDesc.cpuData) {
const auto& range = mDesc.cpuData->Data();
availBytes = range.length();
} else if (mDesc.pboOffset) {
const auto& pboOffset = *mDesc.pboOffset;
const auto& pbo =
webgl->ValidateBufferSelection(LOCAL_GL_PIXEL_UNPACK_BUFFER);
if (!pbo) return false; // Might be invalid e.g. due to in-use by TF.
availBytes = pbo->ByteLength();
availBytes -= pboOffset;
} else {
MOZ_ASSERT(false, "Must be one of the above");
}
if (!availBytes.isValid()) {
webgl->ErrorInvalidOperation("Offset is passed end of buffer.");
return false;
}
return ValidateUnpackBytes(webgl, pi, availBytes.value(), this);
}
bool TexUnpackBytes::TexOrSubImage(bool isSubImage, bool needsRespec,
WebGLTexture* tex, TexImageTarget target,
GLint level,
WebGLTexture* tex, GLint level,
const webgl::DriverUnpackInfo* dui,
GLint xOffset, GLint yOffset, GLint zOffset,
const webgl::PackingInfo& pi,
GLenum* const out_error) const {
WebGLContext* webgl = tex->mContext;
const auto& webgl = tex->mContext;
const auto& target = mDesc.imageTarget;
const auto& size = mDesc.size;
const auto& unpacking = mDesc.unpacking;
const auto format = FormatForPackingInfo(pi);
const auto bytesPerPixel = webgl::BytesPerPixel(pi);
const uint8_t* uploadPtr = mPtr;
const uint8_t dummy = 0;
const uint8_t* uploadPtr = nullptr;
if (mDesc.cpuData) {
const auto range = mDesc.cpuData->Data();
uploadPtr = range.begin().get();
if (!uploadPtr) {
MOZ_ASSERT(!range.length());
uploadPtr = &dummy;
}
}
UniqueBuffer tempBuffer;
do {
if (!mIsClientData || !mPtr) break;
if (mDesc.pboOffset || !uploadPtr) break;
if (!webgl->mPixelStore.mFlipY && !webgl->mPixelStore.mPremultiplyAlpha) {
if (!unpacking.mFlipY && !unpacking.mPremultiplyAlpha) {
break;
}
if (webgl->mPixelStore.mUnpackImageHeight ||
webgl->mPixelStore.mUnpackSkipImages ||
webgl->mPixelStore.mUnpackRowLength ||
webgl->mPixelStore.mUnpackSkipRows ||
webgl->mPixelStore.mUnpackSkipPixels) {
webgl->ErrorInvalidOperation(
"Non-DOM-Element uploads with alpha-premult"
" or y-flip do not support subrect selection.");
return false;
}
webgl->GenerateWarning(
"Alpha-premult and y-flip are deprecated for"
" non-DOM-Element uploads.");
const uint32_t rowLength = mWidth;
const uint32_t rowCount = mHeight * mDepth;
const auto stride =
RoundUpToMultipleOf(rowLength * bytesPerPixel, mAlignment);
if (!ConvertIfNeeded(webgl, rowLength, rowCount, format, mPtr, stride,
const uint32_t rowLength = size.x;
const uint32_t rowCount = size.y * size.z;
const auto stride = RoundUpToMultipleOf(rowLength * bytesPerPixel,
unpacking.mUnpackAlignment);
const auto srcPtr = uploadPtr;
if (!ConvertIfNeeded(webgl, rowLength, rowCount, format, srcPtr, stride,
format, stride, &uploadPtr, &tempBuffer)) {
return false;
}
@ -488,7 +546,7 @@ bool TexUnpackBytes::TexOrSubImage(bool isSubImage, bool needsRespec,
*out_error =
DoTexOrSubImage(isSubImage, gl, target, level, dui, xOffset, yOffset,
zOffset, mWidth, mHeight, mDepth, uploadPtr);
zOffset, size.x, size.y, size.z, uploadPtr);
if (webgl->mBoundPixelUnpackBuffer) {
gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
@ -505,7 +563,7 @@ bool TexUnpackBytes::TexOrSubImage(bool isSubImage, bool needsRespec,
AssertUintParamCorrect(gl, LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
*out_error =
DoTexOrSubImage(false, gl, target, level, dui, xOffset, yOffset,
zOffset, mWidth, mHeight, mDepth, nullptr);
zOffset, size.x, size.y, size.z, nullptr);
if (*out_error) return true;
}
@ -516,32 +574,36 @@ bool TexUnpackBytes::TexOrSubImage(bool isSubImage, bool needsRespec,
// Make our sometimes-implicit values explicit. Also this keeps them constant
// when we ask for height=mHeight-1 and such.
gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, mRowLength);
gl->fPixelStorei(LOCAL_GL_UNPACK_IMAGE_HEIGHT, mImageHeight);
gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, unpacking.mUnpackRowLength);
gl->fPixelStorei(LOCAL_GL_UNPACK_IMAGE_HEIGHT, unpacking.mUnpackImageHeight);
if (mDepth > 1) {
if (size.z > 1) {
*out_error =
DoTexOrSubImage(true, gl, target, level, dui, xOffset, yOffset, zOffset,
mWidth, mHeight, mDepth - 1, uploadPtr);
size.x, size.y, size.z - 1, uploadPtr);
}
// Skip the images we uploaded.
gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES, mSkipImages + mDepth - 1);
const auto skipImages = ZeroOn2D(target, unpacking.mUnpackSkipImages);
gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES, skipImages + size.z - 1);
if (mHeight > 1) {
*out_error = DoTexOrSubImage(true, gl, target, level, dui, xOffset, yOffset,
zOffset + mDepth - 1, mWidth, mHeight - 1, 1,
uploadPtr);
if (size.y > 1) {
*out_error =
DoTexOrSubImage(true, gl, target, level, dui, xOffset, yOffset,
zOffset + size.z - 1, size.x, size.y - 1, 1, uploadPtr);
}
const auto totalSkipRows =
CheckedUint32(mSkipImages) * mImageHeight + mSkipRows;
CheckedUint32(skipImages) * unpacking.mUnpackImageHeight +
unpacking.mUnpackSkipRows;
const auto totalFullRows =
CheckedUint32(mDepth - 1) * mImageHeight + mHeight - 1;
CheckedUint32(size.z - 1) * unpacking.mUnpackImageHeight + size.y - 1;
const auto tailOffsetRows = totalSkipRows + totalFullRows;
const auto bytesPerRow = CheckedUint32(mRowLength) * bytesPerPixel;
const auto rowStride = RoundUpToMultipleOf(bytesPerRow, mAlignment);
const auto bytesPerRow =
CheckedUint32(unpacking.mUnpackRowLength) * bytesPerPixel;
const auto rowStride =
RoundUpToMultipleOf(bytesPerRow, unpacking.mUnpackAlignment);
if (!rowStride.isValid()) {
MOZ_CRASH("Should be checked earlier.");
}
@ -559,20 +621,10 @@ bool TexUnpackBytes::TexOrSubImage(bool isSubImage, bool needsRespec,
// Keep skipping pixels though!
*out_error = DoTexOrSubImage(true, gl, target, level, dui, xOffset,
yOffset + mHeight - 1, zOffset + mDepth - 1,
mWidth, 1, 1, uploadPtr);
yOffset + size.y - 1, zOffset + size.z - 1,
size.x, 1, 1, uploadPtr);
// Reset all our modified state.
gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
webgl->mPixelStore.mUnpackAlignment);
gl->fPixelStorei(LOCAL_GL_UNPACK_IMAGE_HEIGHT,
webgl->mPixelStore.mUnpackImageHeight);
gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH,
webgl->mPixelStore.mUnpackRowLength);
gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES,
webgl->mPixelStore.mUnpackSkipImages);
gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_ROWS,
webgl->mPixelStore.mUnpackSkipRows);
// Caller will reset all our modified PixelStorei state.
return true;
}
@ -581,46 +633,42 @@ bool TexUnpackBytes::TexOrSubImage(bool isSubImage, bool needsRespec,
////////////////////////////////////////////////////////////////////////////////
// TexUnpackImage
TexUnpackImage::TexUnpackImage(const WebGLContext* webgl, TexImageTarget target,
uint32_t width, uint32_t height, uint32_t depth,
layers::Image* image, gfxAlphaType srcAlphaType)
: TexUnpackBlob(webgl, target, image->GetSize().width, width, height, depth,
srcAlphaType),
mImage(image) {}
TexUnpackImage::~TexUnpackImage() = default;
bool TexUnpackImage::Validate(WebGLContext* webgl,
bool TexUnpackImage::Validate(const WebGLContext* const webgl,
const webgl::PackingInfo& pi) {
if (!ValidatePIForDOM(webgl, pi)) return false;
const auto fullRows = mImage->GetSize().height;
const auto fullRows = mDesc.image->GetSize().height;
return ValidateUnpackPixels(webgl, fullRows, 0, this);
}
bool TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec,
WebGLTexture* tex, TexImageTarget target,
GLint level,
WebGLTexture* tex, GLint level,
const webgl::DriverUnpackInfo* dui,
GLint xOffset, GLint yOffset, GLint zOffset,
const webgl::PackingInfo& pi,
GLenum* const out_error) const {
MOZ_ASSERT_IF(needsRespec, !isSubImage);
WebGLContext* webgl = tex->mContext;
const auto& webgl = tex->mContext;
const auto& target = mDesc.imageTarget;
const auto& size = mDesc.size;
const auto& image = mDesc.image;
const auto& unpacking = mDesc.unpacking;
gl::GLContext* gl = webgl->GL();
const auto& gl = webgl->GL();
if (needsRespec) {
*out_error =
DoTexOrSubImage(isSubImage, gl, target.get(), level, dui, xOffset,
yOffset, zOffset, mWidth, mHeight, mDepth, nullptr);
DoTexOrSubImage(isSubImage, gl, target, level, dui, xOffset, yOffset,
zOffset, size.x, size.y, size.z, nullptr);
if (*out_error) return true;
}
const char* fallbackReason;
do {
if (mDepth != 1) {
if (size.z != 1) {
fallbackReason = "depth is not 1";
break;
}
@ -629,18 +677,17 @@ bool TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec,
break;
}
if (webgl->mPixelStore.mUnpackSkipPixels ||
webgl->mPixelStore.mUnpackSkipRows ||
webgl->mPixelStore.mUnpackSkipImages) {
if (unpacking.mUnpackSkipPixels || unpacking.mUnpackSkipRows ||
unpacking.mUnpackSkipImages) {
fallbackReason = "non-zero UNPACK_SKIP_* not yet supported";
break;
}
const auto fnHasPremultMismatch = [&]() {
if (mSrcAlphaType == gfxAlphaType::Opaque) return false;
if (mDesc.srcAlphaType == gfxAlphaType::Opaque) return false;
const bool srcIsPremult = (mSrcAlphaType == gfxAlphaType::Premult);
const auto& dstIsPremult = webgl->mPixelStore.mPremultiplyAlpha;
const bool srcIsPremult = (mDesc.srcAlphaType == gfxAlphaType::Premult);
const auto& dstIsPremult = unpacking.mPremultiplyAlpha;
if (srcIsPremult == dstIsPremult) return false;
if (dstIsPremult) {
@ -670,7 +717,7 @@ bool TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec,
gl::GLContext::LocalErrorScope errorScope(*gl);
gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
LOCAL_GL_COLOR_ATTACHMENT0, target.get(),
LOCAL_GL_COLOR_ATTACHMENT0, target,
tex->mGLName, level);
if (errorScope.GetError()) {
@ -685,11 +732,10 @@ bool TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec,
break;
}
const gfx::IntSize dstSize(mWidth, mHeight);
const auto dstOrigin =
(webgl->mPixelStore.mFlipY ? gl::OriginPos::TopLeft
: gl::OriginPos::BottomLeft);
if (!gl->BlitHelper()->BlitImageToFramebuffer(mImage, dstSize, dstOrigin)) {
(unpacking.mFlipY ? gl::OriginPos::TopLeft : gl::OriginPos::BottomLeft);
if (!gl->BlitHelper()->BlitImageToFramebuffer(image, {size.x, size.y},
dstOrigin)) {
fallbackReason = "likely bug: failed to blit";
break;
}
@ -701,9 +747,9 @@ bool TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec,
const nsPrintfCString perfMsg(
"Failed to hit GPU-copy fast-path: %s (src type %u)", fallbackReason,
uint32_t(mImage->GetFormat()));
uint32_t(image->GetFormat()));
if (webgl->mPixelStore.mRequireFastPath) {
if (unpacking.mRequireFastPath) {
webgl->ErrorInvalidOperation("%s", perfMsg.BeginReading());
return false;
}
@ -711,7 +757,7 @@ bool TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec,
webgl->GeneratePerfWarning("%s Falling back to CPU upload.",
perfMsg.BeginReading());
const RefPtr<gfx::SourceSurface> surf = mImage->GetAsSourceSurface();
const RefPtr<gfx::SourceSurface> surf = image->GetAsSourceSurface();
RefPtr<gfx::DataSourceSurface> dataSurf;
if (surf) {
@ -725,29 +771,22 @@ bool TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec,
return false;
}
const TexUnpackSurface surfBlob(webgl, target, mWidth, mHeight, mDepth,
dataSurf, mSrcAlphaType);
return surfBlob.TexOrSubImage(isSubImage, needsRespec, tex, target, level,
dui, xOffset, yOffset, zOffset, pi, out_error);
const TexUnpackBlobDesc newDesc = {
target, size, mDesc.srcAlphaType, {}, {}, {}, dataSurf, unpacking};
const TexUnpackSurface surfBlob(newDesc);
return surfBlob.TexOrSubImage(isSubImage, needsRespec, tex, level, dui,
xOffset, yOffset, zOffset, pi, out_error);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// TexUnpackSurface
TexUnpackSurface::TexUnpackSurface(const WebGLContext* webgl,
TexImageTarget target, uint32_t width,
uint32_t height, uint32_t depth,
gfx::DataSourceSurface* surf,
gfxAlphaType srcAlphaType)
: TexUnpackBlob(webgl, target, surf->GetSize().width, width, height, depth,
srcAlphaType),
mSurf(surf) {}
TexUnpackSurface::~TexUnpackSurface() = default;
//////////
static bool GetFormatForSurf(gfx::SourceSurface* surf,
static bool GetFormatForSurf(const gfx::SourceSurface* surf,
WebGLTexelFormat* const out_texelFormat,
uint8_t* const out_bpp) {
const auto surfFormat = surf->GetFormat();
@ -796,25 +835,29 @@ static bool GetFormatForSurf(gfx::SourceSurface* surf,
//////////
bool TexUnpackSurface::Validate(WebGLContext* webgl,
bool TexUnpackSurface::Validate(const WebGLContext* const webgl,
const webgl::PackingInfo& pi) {
if (!ValidatePIForDOM(webgl, pi)) return false;
const auto fullRows = mSurf->GetSize().height;
const auto fullRows = mDesc.surf->GetSize().height;
return ValidateUnpackPixels(webgl, fullRows, 0, this);
}
bool TexUnpackSurface::TexOrSubImage(
bool isSubImage, bool needsRespec, WebGLTexture* tex, TexImageTarget target,
GLint level, const webgl::DriverUnpackInfo* dui, GLint xOffset,
GLint yOffset, GLint zOffset, const webgl::PackingInfo& dstPI,
GLenum* const out_error) const {
bool TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec,
WebGLTexture* tex, GLint level,
const webgl::DriverUnpackInfo* dui,
GLint xOffset, GLint yOffset,
GLint zOffset,
const webgl::PackingInfo& dstPI,
GLenum* const out_error) const {
const auto& webgl = tex->mContext;
const auto& size = mDesc.size;
auto& surf = *(mDesc.surf);
////
const auto rowLength = mSurf->GetSize().width;
const auto rowCount = mSurf->GetSize().height;
const auto rowLength = surf.GetSize().width;
const auto rowCount = surf.GetSize().height;
const auto& dstBPP = webgl::BytesPerPixel(dstPI);
const auto dstFormat = FormatForPackingInfo(dstPI);
@ -823,15 +866,15 @@ bool TexUnpackSurface::TexOrSubImage(
WebGLTexelFormat srcFormat;
uint8_t srcBPP;
if (!GetFormatForSurf(mSurf, &srcFormat, &srcBPP)) {
if (!GetFormatForSurf(&surf, &srcFormat, &srcBPP)) {
webgl->ErrorImplementationBug(
"GetFormatForSurf failed for"
" WebGLTexelFormat::%u.",
uint32_t(mSurf->GetFormat()));
uint32_t(surf.GetFormat()));
return false;
}
gfx::DataSourceSurface::ScopedMap map(mSurf,
gfx::DataSourceSurface::ScopedMap map(&surf,
gfx::DataSourceSurface::MapType::READ);
if (!map.IsMapped()) {
webgl->ErrorOutOfMemory("Failed to map source surface for upload.");
@ -882,15 +925,10 @@ bool TexUnpackSurface::TexOrSubImage(
}
*out_error =
DoTexOrSubImage(isSubImage, gl, target.get(), level, dui, xOffset,
yOffset, zOffset, mWidth, mHeight, mDepth, dstBegin);
DoTexOrSubImage(isSubImage, gl, mDesc.imageTarget, level, dui, xOffset,
yOffset, zOffset, size.x, size.y, size.z, dstBegin);
gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
webgl->mPixelStore.mUnpackAlignment);
if (webgl->IsWebGL2()) {
gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH,
webgl->mPixelStore.mUnpackRowLength);
}
// Caller will reset all our modified PixelStorei state.
return true;
}

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

@ -32,6 +32,8 @@ class Image;
class ImageContainer;
} // namespace layers
bool IsTarget3D(TexImageTarget target);
namespace webgl {
struct PackingInfo;
@ -39,30 +41,21 @@ struct DriverUnpackInfo;
class TexUnpackBlob {
public:
const uint32_t mAlignment;
const uint32_t mRowLength;
const uint32_t mImageHeight;
const uint32_t mSkipPixels;
const uint32_t mSkipRows;
const uint32_t mSkipImages;
const uint32_t mWidth;
const uint32_t mHeight;
const uint32_t mDepth;
const TexUnpackBlobDesc& mDesc;
bool mNeedsExactUpload = true;
const gfxAlphaType mSrcAlphaType;
bool mNeedsExactUpload;
static std::unique_ptr<TexUnpackBlob> Create(const TexUnpackBlobDesc&);
protected:
TexUnpackBlob(const WebGLContext* webgl, TexImageTarget target,
uint32_t rowLength, uint32_t width, uint32_t height,
uint32_t depth, gfxAlphaType srcAlphaType);
explicit TexUnpackBlob(const TexUnpackBlobDesc& desc) : mDesc(desc) {
MOZ_ASSERT_IF(!IsTarget3D(mDesc.imageTarget), mDesc.size.z == 1);
}
public:
virtual ~TexUnpackBlob() = default;
protected:
bool ConvertIfNeeded(WebGLContext* webgl, const uint32_t rowLength,
bool ConvertIfNeeded(const WebGLContext*, const uint32_t rowLength,
const uint32_t rowCount, WebGLTexelFormat srcFormat,
const uint8_t* const srcBegin, const ptrdiff_t srcStride,
WebGLTexelFormat dstFormat, const ptrdiff_t dstStride,
@ -73,75 +66,67 @@ class TexUnpackBlob {
public:
virtual bool HasData() const { return true; }
virtual bool Validate(WebGLContext* webgl, const webgl::PackingInfo& pi) = 0;
virtual bool Validate(const WebGLContext*, const webgl::PackingInfo& pi) = 0;
// Returns false when we've generated a WebGL error.
// Returns true but with a non-zero *out_error if we still need to generate a
// WebGL error.
virtual bool TexOrSubImage(bool isSubImage, bool needsRespec,
WebGLTexture* tex, TexImageTarget target,
GLint level, const webgl::DriverUnpackInfo* dui,
GLint xOffset, GLint yOffset, GLint zOffset,
WebGLTexture* tex, GLint level,
const webgl::DriverUnpackInfo* dui, GLint xOffset,
GLint yOffset, GLint zOffset,
const webgl::PackingInfo& pi,
GLenum* const out_error) const = 0;
};
class TexUnpackBytes final : public TexUnpackBlob {
public:
const bool mIsClientData;
const uint8_t* const mPtr;
const size_t mAvailBytes;
explicit TexUnpackBytes(const TexUnpackBlobDesc& desc) : TexUnpackBlob(desc) {
MOZ_ASSERT(mDesc.srcAlphaType == gfxAlphaType::NonPremult);
}
TexUnpackBytes(const WebGLContext* webgl, TexImageTarget target,
uint32_t width, uint32_t height, uint32_t depth,
bool isClientData, const uint8_t* ptr, size_t availBytes);
virtual bool HasData() const override {
return mDesc.pboOffset || mDesc.cpuData;
}
virtual bool HasData() const override { return !mIsClientData || bool(mPtr); }
virtual bool Validate(WebGLContext* webgl,
virtual bool Validate(const WebGLContext*,
const webgl::PackingInfo& pi) override;
virtual bool TexOrSubImage(bool isSubImage, bool needsRespec,
WebGLTexture* tex, TexImageTarget target,
GLint level, const webgl::DriverUnpackInfo* dui,
GLint xOffset, GLint yOffset, GLint zOffset,
WebGLTexture* tex, GLint level,
const webgl::DriverUnpackInfo* dui, GLint xOffset,
GLint yOffset, GLint zOffset,
const webgl::PackingInfo& pi,
GLenum* const out_error) const override;
};
class TexUnpackImage final : public TexUnpackBlob {
public:
const RefPtr<layers::Image> mImage;
TexUnpackImage(const WebGLContext* webgl, TexImageTarget target,
uint32_t width, uint32_t height, uint32_t depth,
layers::Image* image, gfxAlphaType srcAlphaType);
explicit TexUnpackImage(const TexUnpackBlobDesc& desc)
: TexUnpackBlob(desc) {}
~TexUnpackImage(); // Prevent needing to define layers::Image in the header.
virtual bool Validate(WebGLContext* webgl,
virtual bool Validate(const WebGLContext*,
const webgl::PackingInfo& pi) override;
virtual bool TexOrSubImage(bool isSubImage, bool needsRespec,
WebGLTexture* tex, TexImageTarget target,
GLint level, const webgl::DriverUnpackInfo* dui,
GLint xOffset, GLint yOffset, GLint zOffset,
WebGLTexture* tex, GLint level,
const webgl::DriverUnpackInfo* dui, GLint xOffset,
GLint yOffset, GLint zOffset,
const webgl::PackingInfo& dstPI,
GLenum* const out_error) const override;
};
class TexUnpackSurface final : public TexUnpackBlob {
public:
const RefPtr<gfx::DataSourceSurface> mSurf;
explicit TexUnpackSurface(const TexUnpackBlobDesc& desc)
: TexUnpackBlob(desc) {}
~TexUnpackSurface();
TexUnpackSurface(const WebGLContext* webgl, TexImageTarget target,
uint32_t width, uint32_t height, uint32_t depth,
gfx::DataSourceSurface* surf, gfxAlphaType srcAlphaType);
virtual bool Validate(WebGLContext* webgl,
virtual bool Validate(const WebGLContext*,
const webgl::PackingInfo& pi) override;
virtual bool TexOrSubImage(bool isSubImage, bool needsRespec,
WebGLTexture* tex, TexImageTarget target,
GLint level, const webgl::DriverUnpackInfo* dui,
GLint xOffset, GLint yOffset, GLint zOffset,
WebGLTexture* tex, GLint level,
const webgl::DriverUnpackInfo* dui, GLint xOffset,
GLint yOffset, GLint zOffset,
const webgl::PackingInfo& dstPI,
GLenum* const out_error) const override;
};

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

@ -67,26 +67,12 @@ Maybe<double> WebGL2Context::GetParameter(GLenum pname) {
case LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS:
case LOCAL_GL_MAX_VERTEX_UNIFORM_BLOCKS:
case LOCAL_GL_MAX_VERTEX_UNIFORM_COMPONENTS:
case LOCAL_GL_MIN_PROGRAM_TEXEL_OFFSET:
case LOCAL_GL_PACK_ROW_LENGTH:
case LOCAL_GL_PACK_SKIP_PIXELS:
case LOCAL_GL_PACK_SKIP_ROWS:
case LOCAL_GL_UNPACK_IMAGE_HEIGHT:
case LOCAL_GL_UNPACK_ROW_LENGTH: {
case LOCAL_GL_MIN_PROGRAM_TEXEL_OFFSET: {
GLint val;
gl->fGetIntegerv(pname, &val);
return Some(val);
}
case LOCAL_GL_UNPACK_SKIP_IMAGES:
return Some(mPixelStore.mUnpackSkipImages);
case LOCAL_GL_UNPACK_SKIP_PIXELS:
return Some(mPixelStore.mUnpackSkipPixels);
case LOCAL_GL_UNPACK_SKIP_ROWS:
return Some(mPixelStore.mUnpackSkipRows);
case LOCAL_GL_MAX_VARYING_COMPONENTS: {
// On OS X Core Profile this is buggy. The spec says that the
// value is 4 * GL_MAX_VARYING_VECTORS

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

@ -29,10 +29,6 @@ RefPtr<WebGLSync> WebGL2Context::FenceSync(GLenum condition, GLbitfield flags) {
}
RefPtr<WebGLSync> globj = new WebGLSync(this, condition, flags);
const auto& availRunnable = EnsureAvailabilityRunnable();
availRunnable->mSyncs.push_back(globj);
return globj;
}
@ -54,17 +50,6 @@ GLenum WebGL2Context::ClientWaitSync(const WebGLSync& sync, GLbitfield flags,
return LOCAL_GL_WAIT_FAILED;
}
const bool canBeAvailable =
(sync.mCanBeAvailable || StaticPrefs::webgl_allow_immediate_queries());
if (!canBeAvailable) {
if (timeout) {
GenerateWarning(
"Sync object not yet queryable. Please wait for the event"
" loop.");
}
return LOCAL_GL_WAIT_FAILED;
}
const auto ret = gl->fClientWaitSync(sync.mGLName, flags, timeout);
if (ret == LOCAL_GL_CONDITION_SATISFIED || ret == LOCAL_GL_ALREADY_SIGNALED) {

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

@ -11,68 +11,71 @@
namespace mozilla {
namespace dom {
WebGLChild::WebGLChild(ClientWebGLContext& context)
: PcqActor(this), mContext(context) {}
WebGLChild::WebGLChild(ClientWebGLContext& context) : mContext(&context) {}
WebGLChild::~WebGLChild() { (void)Send__delete__(this); }
// -
static constexpr size_t kDefaultCmdsShmemSize = 100 * 1000;
Maybe<Range<uint8_t>> WebGLChild::AllocPendingCmdBytes(const size_t size) {
if (!mPendingCmds) {
mPendingCmds.reset(new webgl::ShmemCmdBuffer);
size_t capacity = 1000 * 1000;
if (!mPendingCmdsShmem) {
size_t capacity = kDefaultCmdsShmemSize;
if (capacity < size) {
capacity = size;
}
if (!PWebGLChild::AllocShmem(
capacity, mozilla::ipc::SharedMemory::SharedMemoryType::TYPE_BASIC,
&(mPendingCmds->mShmem))) {
return {};
}
auto shmem = webgl::RaiiShmem::Alloc(
this, capacity,
mozilla::ipc::SharedMemory::SharedMemoryType::TYPE_BASIC);
MOZ_ASSERT(shmem);
if (!shmem) return {};
mPendingCmdsShmem = std::move(shmem);
mPendingCmdsPos = 0;
}
auto remaining = mPendingCmds->Remaining();
const auto range = mPendingCmdsShmem.ByteRange();
const auto remaining =
Range<uint8_t>{range.begin() + mPendingCmdsPos, range.end()};
if (size > remaining.length()) {
FlushPendingCmds();
return AllocPendingCmdBytes(size);
}
mPendingCmds->mPos += size;
mPendingCmdsPos += size;
return Some(Range<uint8_t>{remaining.begin(), remaining.begin() + size});
}
void WebGLChild::FlushPendingCmds() {
if (!mPendingCmds) return;
if (!mPendingCmdsShmem) return;
const auto cmdBytes = mPendingCmds->mPos;
SendDispatchCommands(std::move(mPendingCmds->mShmem), cmdBytes);
mPendingCmds = nullptr;
const auto byteSize = mPendingCmdsPos;
SendDispatchCommands(mPendingCmdsShmem.Extract(), byteSize);
mFlushedCmdInfo.flushes += 1;
mFlushedCmdInfo.flushedCmdBytes += cmdBytes;
mFlushedCmdInfo.flushedCmdBytes += byteSize;
printf_stderr("[WebGLChild] Flushed %zu bytes. (%zu over %zu flushes)\n",
byteSize, mFlushedCmdInfo.flushedCmdBytes,
mFlushedCmdInfo.flushes);
}
// -
mozilla::ipc::IPCResult WebGLChild::RecvJsWarning(
const std::string& text) const {
mContext.JsWarning(text);
if (!mContext) return IPC_OK();
mContext->JsWarning(text);
return IPC_OK();
}
mozilla::ipc::IPCResult WebGLChild::RecvOnContextLoss(
const webgl::ContextLossReason reason) const {
mContext.OnContextLoss(reason);
if (!mContext) return IPC_OK();
mContext->OnContextLoss(reason);
return IPC_OK();
}
/* static */
IpdlQueueProtocol WebGLChild::GetIpdlQueueProtocol(size_t aCmd, ...) {
bool isSync =
WebGLMethodDispatcher<>::SyncType(aCmd) == CommandSyncType::SYNC;
return isSync ? IpdlQueueProtocol::kSync : IpdlQueueProtocol::kBufferedAsync;
}
} // namespace dom
} // namespace mozilla

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

@ -33,9 +33,10 @@ struct FlushedCmdInfo final {
};
class WebGLChild final : public PWebGLChild,
public SupportsWeakPtr<WebGLChild>,
public mozilla::webgl::PcqActor {
std::unique_ptr<webgl::ShmemCmdBuffer> mPendingCmds;
public SupportsWeakPtr<WebGLChild> {
const WeakPtr<ClientWebGLContext> mContext;
webgl::RaiiShmem mPendingCmdsShmem;
size_t mPendingCmdsPos = 0;
FlushedCmdInfo mFlushedCmdInfo;
public:
@ -43,13 +44,8 @@ class WebGLChild final : public PWebGLChild,
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebGLChild, override);
using OtherSideActor = WebGLParent;
ClientWebGLContext& mContext;
explicit WebGLChild(ClientWebGLContext&);
// For SyncProducerActor:
static IpdlQueueProtocol GetIpdlQueueProtocol(size_t aCmd, ...);
Maybe<Range<uint8_t>> AllocPendingCmdBytes(size_t);
void FlushPendingCmds();

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

@ -26,18 +26,6 @@ using webgl::QueueStatus;
namespace webgl {
struct ShmemCmdBuffer final {
mozilla::ipc::Shmem mShmem = {};
size_t mPos = 0;
Range<uint8_t> Remaining() const {
const auto range = ByteRange(mShmem);
return {range.begin() + mPos, range.end()};
}
};
// -
class RangeConsumerView final : public webgl::ConsumerView<RangeConsumerView> {
RangedPtr<const uint8_t> mSrcItr;
const RangedPtr<const uint8_t> mSrcEnd;

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

@ -209,10 +209,6 @@ void WebGLContext::DestroyResourcesAndContext() {
mIndexedUniformBufferBindings.clear();
if (mAvailabilityRunnable) {
mAvailabilityRunnable->Run();
}
//////
if (mEmptyTFO) {
@ -1393,48 +1389,6 @@ uint64_t IndexedBufferBinding::ByteCount() const {
////////////////////////////////////////
ScopedUnpackReset::ScopedUnpackReset(const WebGLContext* const webgl)
: mWebGL(webgl) {
const auto& gl = mWebGL->gl;
// clang-format off
if (mWebGL->mPixelStore.mUnpackAlignment != 4) gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
if (mWebGL->IsWebGL2()) {
if (mWebGL->mPixelStore.mUnpackRowLength != 0) gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH , 0);
if (mWebGL->mPixelStore.mUnpackImageHeight != 0) gl->fPixelStorei(LOCAL_GL_UNPACK_IMAGE_HEIGHT, 0);
if (mWebGL->mPixelStore.mUnpackSkipPixels != 0) gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_PIXELS , 0);
if (mWebGL->mPixelStore.mUnpackSkipRows != 0) gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_ROWS , 0);
if (mWebGL->mPixelStore.mUnpackSkipImages != 0) gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES , 0);
if (mWebGL->mBoundPixelUnpackBuffer) gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
}
// clang-format on
}
ScopedUnpackReset::~ScopedUnpackReset() {
const auto& gl = mWebGL->gl;
// clang-format off
gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, mWebGL->mPixelStore.mUnpackAlignment);
if (mWebGL->IsWebGL2()) {
gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH , mWebGL->mPixelStore.mUnpackRowLength );
gl->fPixelStorei(LOCAL_GL_UNPACK_IMAGE_HEIGHT, mWebGL->mPixelStore.mUnpackImageHeight);
gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_PIXELS , mWebGL->mPixelStore.mUnpackSkipPixels );
gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_ROWS , mWebGL->mPixelStore.mUnpackSkipRows );
gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES , mWebGL->mPixelStore.mUnpackSkipImages );
GLuint pbo = 0;
if (mWebGL->mBoundPixelUnpackBuffer) {
pbo = mWebGL->mBoundPixelUnpackBuffer->mGLName;
}
gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, pbo);
}
// clang-format on
}
////////////////////
ScopedFBRebinder::~ScopedFBRebinder() {
const auto fnName = [&](WebGLFramebuffer* fb) {
return fb ? fb->mGLName : 0;
@ -1523,54 +1477,6 @@ uint64_t AvailGroups(const uint64_t totalAvailItems,
////////////////////////////////////////////////////////////////////////////////
CheckedUint32 WebGLContext::GetUnpackSize(bool isFunc3D, uint32_t width,
uint32_t height, uint32_t depth,
uint8_t bytesPerPixel) {
if (!width || !height || !depth) return 0;
////////////////
const auto& maybeRowLength = mPixelStore.mUnpackRowLength;
const auto& maybeImageHeight = mPixelStore.mUnpackImageHeight;
const auto usedPixelsPerRow =
CheckedUint32(mPixelStore.mUnpackSkipPixels) + width;
const auto stridePixelsPerRow =
(maybeRowLength ? CheckedUint32(maybeRowLength) : usedPixelsPerRow);
const auto usedRowsPerImage =
CheckedUint32(mPixelStore.mUnpackSkipRows) + height;
const auto strideRowsPerImage =
(maybeImageHeight ? CheckedUint32(maybeImageHeight) : usedRowsPerImage);
const uint32_t skipImages = (isFunc3D ? mPixelStore.mUnpackSkipImages : 0);
const CheckedUint32 usedImages = CheckedUint32(skipImages) + depth;
////////////////
CheckedUint32 strideBytesPerRow = bytesPerPixel * stridePixelsPerRow;
strideBytesPerRow =
RoundUpToMultipleOf(strideBytesPerRow, mPixelStore.mUnpackAlignment);
const CheckedUint32 strideBytesPerImage =
strideBytesPerRow * strideRowsPerImage;
////////////////
CheckedUint32 usedBytesPerRow = bytesPerPixel * usedPixelsPerRow;
// Don't round this to the alignment, since alignment here is really just used
// for establishing stride, particularly in WebGL 1, where you can't set
// ROW_LENGTH.
CheckedUint32 totalBytes = strideBytesPerImage * (usedImages - 1);
totalBytes += strideBytesPerRow * (usedRowsPerImage - 1);
totalBytes += usedBytesPerRow;
return totalBytes;
}
////////////////////////////////////////////////////////////////////////////////
const char* WebGLContext::FuncName() const {
const char* ret;
if (MOZ_LIKELY(mFuncScope)) {
@ -1642,20 +1548,19 @@ already_AddRefed<dom::Promise> ClientWebGLContext::MakeXRCompatible(
// --
webgl::AvailabilityRunnable* WebGLContext::EnsureAvailabilityRunnable() {
webgl::AvailabilityRunnable& ClientWebGLContext::EnsureAvailabilityRunnable()
const {
if (!mAvailabilityRunnable) {
RefPtr<webgl::AvailabilityRunnable> runnable =
new webgl::AvailabilityRunnable(this);
NS_DispatchToCurrentThread(runnable.forget());
mAvailabilityRunnable = new webgl::AvailabilityRunnable(this);
auto forgettable = mAvailabilityRunnable;
NS_DispatchToCurrentThread(forgettable.forget());
}
return mAvailabilityRunnable;
return *mAvailabilityRunnable;
}
webgl::AvailabilityRunnable::AvailabilityRunnable(WebGLContext* const webgl)
: Runnable("webgl::AvailabilityRunnable"), mWebGL(webgl) {
mWebGL->mAvailabilityRunnable = this;
}
webgl::AvailabilityRunnable::AvailabilityRunnable(
const ClientWebGLContext* const webgl)
: Runnable("webgl::AvailabilityRunnable"), mWebGL(webgl) {}
webgl::AvailabilityRunnable::~AvailabilityRunnable() {
MOZ_ASSERT(mQueries.empty());
@ -1664,16 +1569,20 @@ webgl::AvailabilityRunnable::~AvailabilityRunnable() {
nsresult webgl::AvailabilityRunnable::Run() {
for (const auto& cur : mQueries) {
if (!cur) continue;
cur->mCanBeAvailable = true;
}
mQueries.clear();
for (const auto& cur : mSyncs) {
if (!cur) continue;
cur->mCanBeAvailable = true;
}
mSyncs.clear();
mWebGL->mAvailabilityRunnable = nullptr;
if (mWebGL) {
mWebGL->mAvailabilityRunnable = nullptr;
}
return NS_OK;
}

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

@ -66,7 +66,6 @@ class HostWebGLContext;
class ScopedCopyTexImageSource;
class ScopedDrawCallWrapper;
class ScopedResolveTexturesForDraw;
class ScopedUnpackReset;
class WebGLBuffer;
class WebGLExtensionBase;
class WebGLFramebuffer;
@ -185,11 +184,11 @@ namespace webgl {
class AvailabilityRunnable final : public Runnable {
public:
const RefPtr<WebGLContext> mWebGL; // Prevent CC
std::vector<RefPtr<WebGLQuery>> mQueries;
std::vector<RefPtr<WebGLSync>> mSyncs;
const WeakPtr<const ClientWebGLContext> mWebGL;
std::vector<WeakPtr<WebGLQueryJS>> mQueries;
std::vector<WeakPtr<WebGLSyncJS>> mSyncs;
explicit AvailabilityRunnable(WebGLContext* webgl);
explicit AvailabilityRunnable(const ClientWebGLContext* webgl);
~AvailabilityRunnable();
NS_IMETHOD Run() override;
@ -393,6 +392,10 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr<WebGLContext> {
}
void GenerateErrorImpl(const GLenum err, const std::string& text) const;
void GenerateError(const webgl::ErrorInfo& err) {
GenerateError(err.type, "%s", err.info.c_str());
}
template <typename... Args>
void GenerateError(const GLenum err, const char* const fmt,
const Args&... args) const {
@ -593,7 +596,6 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr<WebGLContext> {
void LineWidth(GLfloat width);
void LinkProgram(WebGLProgram& prog);
void PixelStorei(GLenum pname, uint32_t param);
void PolygonOffset(GLfloat factor, GLfloat units);
////
@ -779,10 +781,9 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr<WebGLContext> {
const uvec2& size) const;
// TexSubImage if `!respectFormat`
void TexImage(GLenum imageTarget, uint32_t level, GLenum respecFormat,
uvec3 offset, uvec3 size, const webgl::PackingInfo& pi,
const TexImageSource& src,
const dom::HTMLCanvasElement& canvas) const;
void TexImage(uint32_t level, GLenum respecFormat, uvec3 offset,
const webgl::PackingInfo& pi,
const webgl::TexUnpackBlobDesc&) const;
void TexStorage(GLenum texTarget, uint32_t levels, GLenum sizedFormat,
uvec3 size) const;
@ -1096,7 +1097,6 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr<WebGLContext> {
public:
void LoseContext(
webgl::ContextLossReason reason = webgl::ContextLossReason::None);
const WebGLPixelStore GetPixelStore() const { return mPixelStore; }
protected:
nsTArray<RefPtr<WebGLTexture>> mBound2DTextures;
@ -1129,20 +1129,6 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr<WebGLContext> {
RefPtr<WebGLTransformFeedback> mDefaultTransformFeedback;
RefPtr<WebGLVertexArray> mDefaultVertexArray;
WebGLPixelStore mPixelStore;
CheckedUint32 GetUnpackSize(bool isFunc3D, uint32_t width, uint32_t height,
uint32_t depth, uint8_t bytesPerPixel);
UniquePtr<webgl::TexUnpackBlob> FromDomElem(
const dom::HTMLCanvasElement& canvas, TexImageTarget target, uvec3 size,
const dom::Element& elem, ErrorResult* const out_error) const;
UniquePtr<webgl::TexUnpackBlob> From(
const dom::HTMLCanvasElement& canvas, TexImageTarget target,
const uvec3& size, const TexImageSource& src,
dom::Uint8ClampedArray* const scopedArr) const;
////////////////////////////////////
protected:
@ -1294,19 +1280,9 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr<WebGLContext> {
const decltype(mBound2DTextures)* TexListForElemType(GLenum elemType) const;
// --
private:
webgl::AvailabilityRunnable* mAvailabilityRunnable = nullptr;
public:
webgl::AvailabilityRunnable* EnsureAvailabilityRunnable();
// -
// Friend list
friend class ScopedCopyTexImageSource;
friend class ScopedResolveTexturesForDraw;
friend class ScopedUnpackReset;
friend class webgl::TexUnpackBlob;
friend class webgl::TexUnpackBytes;
friend class webgl::TexUnpackImage;
@ -1338,15 +1314,6 @@ V RoundUpToMultipleOf(const V& value, const M& multiple) {
const char* GetEnumName(GLenum val, const char* defaultRet = "<unknown>");
std::string EnumString(GLenum val);
class ScopedUnpackReset final {
private:
const WebGLContext* const mWebGL;
public:
explicit ScopedUnpackReset(const WebGLContext* webgl);
~ScopedUnpackReset();
};
class ScopedFBRebinder final {
private:
const WebGLContext* const mWebGL;

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

@ -48,6 +48,7 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/ImageData.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "mozilla/EndianUtils.h"
#include "mozilla/RefPtr.h"
#include "mozilla/UniquePtrExtensions.h"
@ -738,68 +739,66 @@ void WebGLContext::LinkProgram(WebGLProgram& prog) {
}
}
void WebGLContext::PixelStorei(GLenum pname, uint32_t param) {
const FuncScope funcScope(*this, "pixelStorei");
if (IsContextLost()) return;
if (IsWebGL2()) {
Maybe<webgl::ErrorInfo> SetPixelUnpack(const bool isWebgl2,
WebGLPixelStore* const unpacking,
const GLenum pname, const GLint param) {
if (isWebgl2) {
uint32_t* pValueSlot = nullptr;
switch (pname) {
case LOCAL_GL_UNPACK_IMAGE_HEIGHT:
pValueSlot = &mPixelStore.mUnpackImageHeight;
pValueSlot = &unpacking->mUnpackImageHeight;
break;
case LOCAL_GL_UNPACK_SKIP_IMAGES:
pValueSlot = &mPixelStore.mUnpackSkipImages;
pValueSlot = &unpacking->mUnpackSkipImages;
break;
case LOCAL_GL_UNPACK_ROW_LENGTH:
pValueSlot = &mPixelStore.mUnpackRowLength;
pValueSlot = &unpacking->mUnpackRowLength;
break;
case LOCAL_GL_UNPACK_SKIP_ROWS:
pValueSlot = &mPixelStore.mUnpackSkipRows;
pValueSlot = &unpacking->mUnpackSkipRows;
break;
case LOCAL_GL_UNPACK_SKIP_PIXELS:
pValueSlot = &mPixelStore.mUnpackSkipPixels;
pValueSlot = &unpacking->mUnpackSkipPixels;
break;
}
if (pValueSlot) {
gl->fPixelStorei(pname, static_cast<int32_t>(param));
*pValueSlot = param;
return;
*pValueSlot = static_cast<uint32_t>(param);
return {};
}
}
switch (pname) {
case UNPACK_FLIP_Y_WEBGL:
mPixelStore.mFlipY = bool(param);
return;
case dom::WebGLRenderingContext_Binding::UNPACK_FLIP_Y_WEBGL:
unpacking->mFlipY = bool(param);
return {};
case UNPACK_PREMULTIPLY_ALPHA_WEBGL:
mPixelStore.mPremultiplyAlpha = bool(param);
return;
case dom::WebGLRenderingContext_Binding::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
unpacking->mPremultiplyAlpha = bool(param);
return {};
case UNPACK_COLORSPACE_CONVERSION_WEBGL:
case dom::WebGLRenderingContext_Binding::UNPACK_COLORSPACE_CONVERSION_WEBGL:
switch (param) {
case LOCAL_GL_NONE:
case BROWSER_DEFAULT_WEBGL:
mPixelStore.mColorspaceConversion = param;
return;
case dom::WebGLRenderingContext_Binding::BROWSER_DEFAULT_WEBGL:
break;
default:
ErrorInvalidEnumInfo("colorspace conversion parameter", param);
return;
default: {
const nsPrintfCString text("Bad UNPACK_COLORSPACE_CONVERSION: %s",
EnumString(param).c_str());
return Some(webgl::ErrorInfo{LOCAL_GL_INVALID_VALUE, ToString(text)});
}
}
unpacking->mColorspaceConversion = param;
return {};
case UNPACK_REQUIRE_FASTPATH:
if (IsExtensionEnabled(WebGLExtensionID::MOZ_debug)) {
mPixelStore.mRequireFastPath = bool(param);
return;
}
break;
case dom::MOZ_debug_Binding::UNPACK_REQUIRE_FASTPATH:
unpacking->mRequireFastPath = bool(param);
return {};
case LOCAL_GL_UNPACK_ALIGNMENT:
switch (param) {
@ -807,20 +806,22 @@ void WebGLContext::PixelStorei(GLenum pname, uint32_t param) {
case 2:
case 4:
case 8:
mPixelStore.mUnpackAlignment = param;
gl->fPixelStorei(pname, static_cast<int32_t>(param));
return;
break;
default:
ErrorInvalidValue("Invalid pack/unpack alignment value.");
return;
default: {
const nsPrintfCString text(
"UNPACK_ALIGNMENT must be [1,2,4,8], was %i", param);
return Some(webgl::ErrorInfo{LOCAL_GL_INVALID_VALUE, ToString(text)});
}
}
unpacking->mUnpackAlignment = param;
return {};
default:
break;
}
ErrorInvalidEnumInfo("pname", pname);
const nsPrintfCString text("Bad `pname`: %s", EnumString(pname).c_str());
return Some(webgl::ErrorInfo{LOCAL_GL_INVALID_ENUM, ToString(text)});
}
bool WebGLContext::DoReadPixelsAndConvert(

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

@ -233,8 +233,6 @@ Maybe<double> WebGLContext::GetParameter(const GLenum pname) {
}
case LOCAL_GL_STENCIL_CLEAR_VALUE:
case LOCAL_GL_UNPACK_ALIGNMENT:
case LOCAL_GL_PACK_ALIGNMENT:
case LOCAL_GL_SUBPIXEL_BITS: {
GLint i = 0;
gl->fGetIntegerv(pname, &i);
@ -390,16 +388,6 @@ Maybe<double> WebGLContext::GetParameter(const GLenum pname) {
return Some(bool(b));
}
// bool, WebGL-specific
case UNPACK_FLIP_Y_WEBGL:
return Some((bool)mPixelStore.mFlipY);
case UNPACK_PREMULTIPLY_ALPHA_WEBGL:
return Some((bool)mPixelStore.mPremultiplyAlpha);
// uint, WebGL-specific
case UNPACK_COLORSPACE_CONVERSION_WEBGL:
return Some(mPixelStore.mColorspaceConversion);
default:
break;
}

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

@ -145,17 +145,6 @@ void WebGLContext::TexParameter_base(GLenum texTarget, GLenum pname,
//////////////////////////////////////////////////////////////////////////////////////////
// Uploads
static bool IsTexTarget3D(const GLenum texTarget) {
switch (texTarget) {
case LOCAL_GL_TEXTURE_2D_ARRAY:
case LOCAL_GL_TEXTURE_3D:
return true;
default:
return false;
}
}
WebGLTexture* WebGLContext::GetActiveTex(const GLenum texTarget) const {
const auto* list = &mBound2DTextures;
switch (texTarget) {
@ -197,25 +186,19 @@ void WebGLContext::TexStorage(GLenum texTarget, uint32_t levels,
tex->TexStorage(texTarget, levels, internalFormat, size);
}
void WebGLContext::TexImage(GLenum imageTarget, uint32_t level,
GLenum respecFormat, uvec3 offset, uvec3 size,
void WebGLContext::TexImage(uint32_t level, GLenum respecFormat, uvec3 offset,
const webgl::PackingInfo& pi,
const TexImageSource& src,
const dom::HTMLCanvasElement& canvas) const {
const webgl::TexUnpackBlobDesc& src) const {
const WebGLContext::FuncScope funcScope(
*this, bool(respecFormat) ? "texImage" : "texSubImage");
if (respecFormat) {
offset = {0, 0, 0};
}
const auto texTarget = ImageToTexTarget(imageTarget);
if (!IsTexTarget3D(texTarget)) {
size.z = 1;
}
const auto texTarget = ImageToTexTarget(src.imageTarget);
const auto tex = GetActiveTex(texTarget);
if (!tex) return;
tex->TexImage(imageTarget, level, respecFormat, offset, size, pi, src,
canvas);
tex->TexImage(level, respecFormat, offset, pi, src);
}
void WebGLContext::CompressedTexImage(bool sub, GLenum imageTarget,

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

@ -546,22 +546,6 @@ void WebGLContext::AssertCachedGlobalState() const {
MOZ_ASSERT(int4[0] == mViewportX && int4[1] == mViewportY &&
int4[2] == mViewportWidth && int4[3] == mViewportHeight);
AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_ALIGNMENT,
mPixelStore.mUnpackAlignment);
if (IsWebGL2()) {
AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_IMAGE_HEIGHT,
mPixelStore.mUnpackImageHeight);
AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_SKIP_IMAGES,
mPixelStore.mUnpackSkipImages);
AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_ROW_LENGTH,
mPixelStore.mUnpackRowLength);
AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_SKIP_ROWS,
mPixelStore.mUnpackSkipRows);
AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_SKIP_PIXELS,
mPixelStore.mUnpackSkipPixels);
}
MOZ_ASSERT(!gl::GLContext::IsBadCallError(errorScope.GetError()));
#endif
}

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

@ -575,19 +575,6 @@ bool WebGLContext::InitAndValidateGL(FailureReason* const out_failReason) {
mDefaultVertexArray = WebGLVertexArray::Create(this);
mDefaultVertexArray->BindVertexArray();
mPixelStore.mFlipY = false;
mPixelStore.mPremultiplyAlpha = false;
mPixelStore.mColorspaceConversion = BROWSER_DEFAULT_WEBGL;
mPixelStore.mRequireFastPath = false;
// GLES 3.0.4, p259:
mPixelStore.mUnpackImageHeight = 0;
mPixelStore.mUnpackSkipImages = 0;
mPixelStore.mUnpackRowLength = 0;
mPixelStore.mUnpackSkipRows = 0;
mPixelStore.mUnpackSkipPixels = 0;
mPixelStore.mUnpackAlignment = 4;
mPrimRestartTypeBytes = 0;
mGenericVertexAttribTypes.assign(limits.maxVertexAttribs,

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

@ -10,6 +10,89 @@
#include "WebGLTypes.h"
namespace mozilla {
namespace webgl {
// TODO: This should probably replace Shmem, or at least this should move to ipc/glue.
class RaiiShmem final {
RefPtr<mozilla::ipc::ActorLifecycleProxy> mWeakRef;
mozilla::ipc::Shmem mShmem = {};
public:
/// Returns zeroed data.
static RaiiShmem Alloc(mozilla::ipc::IProtocol* const allocator,
const size_t size,
const Shmem::SharedMemory::SharedMemoryType type) {
mozilla::ipc::Shmem shmem;
if (!allocator->AllocShmem(size, type, &shmem)) return {};
return {allocator, shmem};
}
// -
RaiiShmem() = default;
RaiiShmem(mozilla::ipc::IProtocol* const allocator,
const mozilla::ipc::Shmem& shmem)
: mWeakRef(allocator->ToplevelProtocol()->GetLifecycleProxy()),
mShmem(shmem) {
// Shmems are handled by the top-level, so use that or we might leak after
// the actor dies.
MOZ_ASSERT(mWeakRef);
}
void reset() {
if (IsShmem()) {
const auto& allocator = mWeakRef->Get();
if (allocator) {
allocator->DeallocShmem(mShmem);
}
}
mWeakRef = nullptr;
mShmem = {};
}
~RaiiShmem() { reset(); }
// -
RaiiShmem(RaiiShmem&& rhs) { *this = std::move(rhs); }
RaiiShmem& operator=(RaiiShmem&& rhs) {
reset();
mWeakRef = rhs.mWeakRef;
mShmem = rhs.Extract();
return *this;
}
// -
bool IsShmem() const { return mShmem.IsReadable(); }
explicit operator bool() const { return IsShmem(); }
// -
const auto& Shmem() const {
MOZ_ASSERT(IsShmem());
return mShmem;
}
Range<uint8_t> ByteRange() const {
MOZ_ASSERT(IsShmem());
return {mShmem.get<uint8_t>(), mShmem.Size<uint8_t>()};
}
mozilla::ipc::Shmem Extract() {
auto ret = mShmem;
mShmem = {};
reset();
return ret;
}
};
using Int32Vector = std::vector<int32_t>;
} // namespace webgl
namespace ipc {
template <>
@ -476,15 +559,4 @@ struct ParamTraits<mozilla::avec3<U>> final {
} // namespace IPC
namespace mozilla {
namespace webgl {
using MaybeDouble = Maybe<double>;
using MaybeFrontBufferSnapshotIpc = Maybe<FrontBufferSnapshotIpc>;
using MaybeSurfaceDescriptor = Maybe<layers::SurfaceDescriptor>;
using MaybeReadPixelsResultIpc = Maybe<ReadPixelsResultIpc>;
using MaybeShaderPrecisionFormat = Maybe<ShaderPrecisionFormat>;
using MaybeString = Maybe<std::string>;
} // namespace webgl
} // namespace mozilla
#endif

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

@ -113,7 +113,6 @@ DEFINE_ASYNC(HostWebGLContext::FrontFace)
DEFINE_ASYNC(HostWebGLContext::Hint)
DEFINE_ASYNC(HostWebGLContext::LineWidth)
DEFINE_ASYNC(HostWebGLContext::LinkProgram)
DEFINE_ASYNC(HostWebGLContext::PixelStorei)
DEFINE_ASYNC(HostWebGLContext::PolygonOffset)
DEFINE_ASYNC(HostWebGLContext::Present)
DEFINE_ASYNC(HostWebGLContext::SampleCoverage)
@ -140,7 +139,7 @@ DEFINE_ASYNC(HostWebGLContext::BindTexture)
DEFINE_ASYNC(HostWebGLContext::GenerateMipmap)
DEFINE_ASYNC(HostWebGLContext::CopyTexImage)
DEFINE_ASYNC(HostWebGLContext::TexStorage)
// DEFINE_ASYNC(HostWebGLContext::TexImage)
DEFINE_ASYNC(HostWebGLContext::TexImage)
DEFINE_ASYNC(HostWebGLContext::CompressedTexImage)
// DEFINE_SYNC(HostWebGLContext::GetTexParameter)
DEFINE_ASYNC(HostWebGLContext::TexParameter_base)

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

@ -39,17 +39,19 @@ mozilla::ipc::IPCResult WebGLParent::RecvInitialize(
return IPC_OK();
}
WebGLParent::WebGLParent() : PcqActor(this) {}
WebGLParent::WebGLParent() = default;
WebGLParent::~WebGLParent() = default;
// -
using IPCResult = mozilla::ipc::IPCResult;
IPCResult WebGLParent::RecvDispatchCommands(Shmem&& shmem,
IPCResult WebGLParent::RecvDispatchCommands(Shmem&& rawShmem,
const uint64_t cmdsByteSize) {
auto shmem = webgl::RaiiShmem(this, std::move(rawShmem));
MOZ_ASSERT(cmdsByteSize);
const auto shmemBytes = ByteRange(shmem);
const auto shmemBytes = shmem.ByteRange();
const auto byteSize = std::min<uint64_t>(shmemBytes.length(), cmdsByteSize);
const auto cmdsBytes =
Range<const uint8_t>{shmemBytes.begin(), shmemBytes.begin() + byteSize};
@ -84,16 +86,19 @@ IPCResult WebGLParent::RecvGetFrontBufferSnapshot(
const auto surfSize = mHost->GetFrontBufferSize();
const auto byteSize = 4 * surfSize.x * surfSize.y;
Shmem shmem;
if (!PWebGLParent::AllocShmem(
byteSize, mozilla::ipc::SharedMemory::SharedMemoryType::TYPE_BASIC,
&shmem)) {
auto shmem = webgl::RaiiShmem::Alloc(
this, byteSize, mozilla::ipc::SharedMemory::SharedMemoryType::TYPE_BASIC);
MOZ_ASSERT(shmem);
if (!shmem) {
return IPC_FAIL(this, "Failed to allocate shmem for result");
}
auto shmemBytes = ByteRange(shmem);
if (!mHost->FrontBufferSnapshotInto(shmemBytes)) return IPC_OK();
*ret = {surfSize, Some(std::move(shmem))};
const auto range = shmem.ByteRange();
auto retSize = surfSize;
if (!mHost->FrontBufferSnapshotInto(range)) {
retSize = {0, 0}; // Zero means failure.
}
*ret = {retSize, shmem.Extract()};
return IPC_OK();
}
@ -101,43 +106,45 @@ IPCResult WebGLParent::RecvGetBufferSubData(const GLenum target,
const uint64_t srcByteOffset,
const uint64_t byteSize,
Shmem* const ret) {
Shmem shmem;
if (!PWebGLParent::AllocShmem(
byteSize, mozilla::ipc::SharedMemory::SharedMemoryType::TYPE_BASIC,
&shmem)) {
MOZ_ASSERT(false);
const auto allocSize = 1 + byteSize;
auto shmem = webgl::RaiiShmem::Alloc(
this, allocSize,
mozilla::ipc::SharedMemory::SharedMemoryType::TYPE_BASIC);
MOZ_ASSERT(shmem);
if (!shmem) {
return IPC_FAIL(this, "Failed to allocate shmem for result");
}
const auto range = ByteRange(shmem);
memset(range.begin().get(), 0,
range.length()); // TODO: This is usually overkill.
const auto shmemRange = shmem.ByteRange();
const auto dataRange =
Range<uint8_t>{shmemRange.begin() + 1, shmemRange.end()};
if (mHost->GetBufferSubData(target, srcByteOffset, range)) {
*ret = std::move(shmem);
}
// We need to always send the shmem:
// https://bugzilla.mozilla.org/show_bug.cgi?id=1463831#c2
const auto ok = mHost->GetBufferSubData(target, srcByteOffset, dataRange);
*(shmemRange.begin().get()) = ok;
*ret = shmem.Extract();
return IPC_OK();
}
IPCResult WebGLParent::RecvReadPixels(const webgl::ReadPixelsDesc& desc,
const uint64_t byteCount,
const uint64_t byteSize,
webgl::ReadPixelsResultIpc* const ret) {
*ret = {};
Shmem shmem;
if (!PWebGLParent::AllocShmem(
byteCount, mozilla::ipc::SharedMemory::SharedMemoryType::TYPE_BASIC,
&shmem)) {
MOZ_ASSERT(false);
const auto allocSize = std::max<uint64_t>(1, byteSize);
auto shmem = webgl::RaiiShmem::Alloc(
this, allocSize,
mozilla::ipc::SharedMemory::SharedMemoryType::TYPE_BASIC);
MOZ_ASSERT(shmem);
if (!shmem) {
return IPC_FAIL(this, "Failed to allocate shmem for result");
}
auto range = ByteRange(shmem);
memset(range.begin().get(), 0,
range.length()); // TODO: This is usually overkill.
const auto range = shmem.ByteRange();
const auto res = mHost->ReadPixelsInto(desc, range);
*ret = {res, std::move(shmem)};
*ret = {res, shmem.Extract()};
return IPC_OK();
}

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

@ -22,9 +22,7 @@ class SurfaceDescriptor;
namespace dom {
class WebGLParent : public PWebGLParent,
public SupportsWeakPtr<WebGLParent>,
public mozilla::webgl::PcqActor {
class WebGLParent : public PWebGLParent, public SupportsWeakPtr<WebGLParent> {
friend PWebGLParent;
public:
@ -42,6 +40,8 @@ class WebGLParent : public PWebGLParent,
IPCResult RecvDispatchCommands(mozilla::ipc::Shmem&&, uint64_t);
IPCResult RecvGetBufferSubData(GLenum target, uint64_t srcByteOffset,
uint64_t byteSize, mozilla::ipc::Shmem* ret);
IPCResult RecvGetFrontBufferSnapshot(webgl::FrontBufferSnapshotIpc* ret);
IPCResult RecvReadPixels(const webgl::ReadPixelsDesc&, uint64_t byteSize,
webgl::ReadPixelsResultIpc* ret);
@ -60,8 +60,6 @@ class WebGLParent : public PWebGLParent,
IPCResult RecvFinish();
IPCResult RecvGetBufferParameter(GLenum target, GLenum pname,
Maybe<double>* ret);
IPCResult RecvGetBufferSubData(GLenum target, uint64_t srcByteOffset,
uint64_t byteSize, mozilla::ipc::Shmem* ret);
IPCResult RecvGetCompileResult(ObjectId id, webgl::CompileResult* ret);
IPCResult RecvGetError(GLenum* ret);
IPCResult RecvGetFragDataLocation(ObjectId id, const std::string& name,

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

@ -76,11 +76,6 @@ void WebGLQuery::EndQuery() {
const auto driverTarget = TargetForDriver(gl, mTarget);
gl->fEndQuery(driverTarget);
////
const auto& availRunnable = mContext->EnsureAvailabilityRunnable();
availRunnable->mQueries.push_back(this);
}
Maybe<double> WebGLQuery::GetQueryParameter(GLenum pname) const {
@ -107,16 +102,6 @@ Maybe<double> WebGLQuery::GetQueryParameter(GLenum pname) const {
// End of validation
////
// We must usually wait for an event loop before the query can be available.
const bool canBeAvailable =
(mCanBeAvailable || StaticPrefs::webgl_allow_immediate_queries());
if (!canBeAvailable) {
if (pname == LOCAL_GL_QUERY_RESULT_AVAILABLE) {
return Some(false);
}
return Nothing();
}
const auto& gl = mContext->gl;
uint64_t val = 0;
@ -167,9 +152,6 @@ void WebGLQuery::QueryCounter() {
const auto& gl = mContext->gl;
gl->fQueryCounter(mGLName, mTarget);
const auto& availRunnable = mContext->EnsureAvailabilityRunnable();
availRunnable->mQueries.push_back(this);
}
} // namespace mozilla

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

@ -43,6 +43,9 @@ 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<ICRData> : std::true_type {};
@ -202,7 +205,6 @@ struct QueueParamTraits<std::vector<U>> {
template <typename V>
static QueueStatus Read(ConsumerView<V>& aConsumerView, T* aArg) {
MOZ_CRASH("no way to fallibly resize vectors without exceptions");
size_t size;
auto status = aConsumerView.ReadParam(&size);
if (!status) return status;

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

@ -586,9 +586,11 @@ static bool ZeroTextureData(const WebGLContext* webgl, GLuint tex,
UniqueBuffer zeros = calloc(1u, sliceByteCount);
if (!zeros) return false;
ScopedUnpackReset scopedReset(webgl);
gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1); // Don't bother with
// striding it well.
// Don't bother with striding it well.
// TODO: We shouldn't need to do this for CompressedTexSubImage.
gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1);
const auto revert = MakeScopeExit(
[&]() { gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4); });
GLenum error = 0;
for (const auto z : IntegerRange(depth)) {
@ -628,9 +630,10 @@ static bool ZeroTextureData(const WebGLContext* webgl, GLuint tex,
UniqueBuffer zeros = calloc(1u, sliceByteCount);
if (!zeros) return false;
ScopedUnpackReset scopedReset(webgl);
gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
1); // Don't bother with striding it well.
// Don't bother with striding it well.
gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1);
const auto revert =
MakeScopeExit([&]() { gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4); });
GLenum error = 0;
for (const auto z : IntegerRange(depth)) {

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

@ -201,10 +201,8 @@ class WebGLTexture final : public WebGLContextBoundObject,
const uvec3& size);
// TexSubImage iff `!respecFormat`
void TexImage(GLenum imageTarget, uint32_t level, GLenum respecFormat,
const uvec3& offset, const uvec3& size,
const webgl::PackingInfo& pi, const TexImageSource& src,
const dom::HTMLCanvasElement& canvas);
void TexImage(uint32_t level, GLenum respecFormat, const uvec3& offset,
const webgl::PackingInfo& pi, const webgl::TexUnpackBlobDesc&);
// CompressedTexSubImage iff `sub`
void CompressedTexImage(bool sub, GLenum imageTarget, uint32_t level,

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

@ -9,6 +9,7 @@
#include <limits>
#include "CanvasUtils.h"
#include "ClientWebGLContext.h"
#include "GLBlitHelper.h"
#include "GLContext.h"
#include "mozilla/Casting.h"
@ -30,63 +31,19 @@
#include "WebGLTexelConversions.h"
namespace mozilla {
namespace webgl {
static UniquePtr<webgl::TexUnpackBytes> FromView(
const WebGLContext* webgl, TexImageTarget target, const uvec3& size,
const dom::ArrayBufferView* view, GLuint viewElemOffset,
GLuint viewElemLengthOverride) {
const bool isClientData = true;
const uint8_t* bytes = nullptr;
size_t availByteCount = 0;
if (view) {
const auto range =
GetRangeFromView(*view, viewElemOffset, viewElemLengthOverride);
if (!range) {
webgl->GenerateError(LOCAL_GL_INVALID_OPERATION, "`source` too small.");
return nullptr;
}
bytes = range->begin().get();
availByteCount = range->length();
}
return MakeUnique<webgl::TexUnpackBytes>(webgl, target, size.x, size.y,
size.z, isClientData, bytes,
availByteCount);
}
static UniquePtr<webgl::TexUnpackBytes> FromPboOffset(const WebGLContext* webgl,
TexImageTarget target,
const uvec3& size,
WebGLintptr pboOffset) {
if (!webgl->ValidateNonNegative("offset", pboOffset)) return nullptr;
const auto& buffer =
webgl->ValidateBufferSelection(LOCAL_GL_PIXEL_UNPACK_BUFFER);
if (!buffer) return nullptr;
size_t availBufferBytes = buffer->ByteLength();
if (size_t(pboOffset) > availBufferBytes) {
webgl->ErrorInvalidOperation("Offset is passed end of buffer.");
return nullptr;
}
availBufferBytes -= pboOffset;
const bool isClientData = false;
const auto ptr = (const uint8_t*)pboOffset;
return MakeUnique<webgl::TexUnpackBytes>(webgl, target, size.x, size.y,
size.z, isClientData, ptr,
availBufferBytes);
}
static UniquePtr<webgl::TexUnpackBlob> FromImageBitmap(
const WebGLContext* webgl, TexImageTarget target, uvec3 size,
const dom::ImageBitmap& imageBitmap, ErrorResult* aRv) {
Maybe<TexUnpackBlobDesc> FromImageBitmap(const GLenum target, uvec3 size,
const dom::ImageBitmap& imageBitmap,
ErrorResult* const out_rv) {
if (imageBitmap.IsWriteOnly()) {
aRv->Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;
out_rv->Throw(NS_ERROR_DOM_SECURITY_ERR);
return {};
}
UniquePtr<dom::ImageBitmapCloneData> cloneData = imageBitmap.ToCloneData();
const auto cloneData = imageBitmap.ToCloneData();
if (!cloneData) {
return nullptr;
return {};
}
const RefPtr<gfx::DataSourceSurface> surf = cloneData->mSurface;
@ -102,40 +59,27 @@ static UniquePtr<webgl::TexUnpackBlob> FromImageBitmap(
// WhatWG "HTML Living Standard" (30 October 2015):
// "The getImageData(sx, sy, sw, sh) method [...] Pixels must be returned as
// non-premultiplied alpha values."
return MakeUnique<webgl::TexUnpackSurface>(
webgl, target, size.x, size.y, size.z, surf, cloneData->mAlphaType);
return Some(
TexUnpackBlobDesc{target, size, cloneData->mAlphaType, {}, {}, {}, surf});
}
static UniquePtr<webgl::TexUnpackBlob> FromImageData(
const WebGLContext* webgl, TexImageTarget target, uvec3 size,
const dom::ImageData& imageData, dom::Uint8ClampedArray* scopedArr) {
DebugOnly<bool> inited = scopedArr->Init(imageData.GetDataObject());
MOZ_ASSERT(inited);
TexUnpackBlobDesc FromImageData(const GLenum target, uvec3 size,
const dom::ImageData& imageData,
dom::Uint8ClampedArray* const scopedArr) {
MOZ_RELEASE_ASSERT(scopedArr->Init(imageData.GetDataObject()));
scopedArr->ComputeState();
const DebugOnly<size_t> dataSize = scopedArr->Length();
const void* const data = scopedArr->Data();
const size_t dataSize = scopedArr->Length();
const auto data = reinterpret_cast<uint8_t*>(scopedArr->Data());
const gfx::IntSize imageSize(imageData.Width(), imageData.Height());
const size_t stride = imageSize.width * 4;
const gfx::SurfaceFormat surfFormat = gfx::SurfaceFormat::R8G8B8A8;
// WhatWG "HTML Living Standard" (30 October 2015):
// "The getImageData(sx, sy, sw, sh) method [...] Pixels must be returned as
// non-premultiplied alpha values."
const auto alphaType = gfxAlphaType::NonPremult;
MOZ_ASSERT(dataSize == stride * imageSize.height);
uint8_t* wrappableData = (uint8_t*)data;
MOZ_ALWAYS_TRUE(dataSize == stride * imageSize.height);
const RefPtr<gfx::DataSourceSurface> surf =
gfx::Factory::CreateWrappingDataSourceSurface(wrappableData, stride,
imageSize, surfFormat);
if (!surf) {
webgl->ErrorOutOfMemory("OOM in FromImageData.");
return nullptr;
}
gfx::Factory::CreateWrappingDataSourceSurface(data, stride, imageSize,
surfFormat);
MOZ_ASSERT(surf);
////
@ -149,19 +93,25 @@ static UniquePtr<webgl::TexUnpackBlob> FromImageData(
////
return MakeUnique<webgl::TexUnpackSurface>(webgl, target, size.x, size.y,
size.z, surf, alphaType);
// WhatWG "HTML Living Standard" (30 October 2015):
// "The getImageData(sx, sy, sw, sh) method [...] Pixels must be returned as
// non-premultiplied alpha values."
return {target, size, gfxAlphaType::NonPremult, {}, {}, {}, surf};
}
UniquePtr<webgl::TexUnpackBlob> WebGLContext::FromDomElem(
const dom::HTMLCanvasElement& canvas, TexImageTarget target, uvec3 size,
const dom::Element& elem, ErrorResult* const out_error) const {
Maybe<webgl::TexUnpackBlobDesc> FromDomElem(const ClientWebGLContext& webgl,
const GLenum target, uvec3 size,
const dom::Element& elem,
const bool allowBlitImage,
ErrorResult* const out_error) {
const auto& canvas = *webgl.GetCanvas();
if (elem.IsHTMLElement(nsGkAtoms::canvas)) {
const dom::HTMLCanvasElement* canvas =
const dom::HTMLCanvasElement* srcCanvas =
static_cast<const dom::HTMLCanvasElement*>(&elem);
if (canvas->IsWriteOnly()) {
if (srcCanvas->IsWriteOnly()) {
out_error->Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;
return {};
}
}
@ -172,9 +122,10 @@ UniquePtr<webgl::TexUnpackBlob> WebGLContext::FromDomElem(
nsLayoutUtils::SFE_WANT_IMAGE_SURFACE |
nsLayoutUtils::SFE_USE_ELEMENT_SIZE_IF_VECTOR |
nsLayoutUtils::SFE_ALLOW_NON_PREMULT;
if (mPixelStore.mColorspaceConversion == LOCAL_GL_NONE)
const auto& unpacking = webgl.State().mPixelUnpackState;
if (unpacking.mColorspaceConversion == LOCAL_GL_NONE) {
flags |= nsLayoutUtils::SFE_NO_COLORSPACE_CONVERSION;
}
RefPtr<gfx::DrawTarget> idealDrawTarget = nullptr; // Don't care for now.
auto sfer = nsLayoutUtils::SurfaceFromElement(
@ -185,7 +136,8 @@ UniquePtr<webgl::TexUnpackBlob> WebGLContext::FromDomElem(
uint32_t elemWidth = 0;
uint32_t elemHeight = 0;
layers::Image* layersImage = nullptr;
if (!StaticPrefs::webgl_disable_DOM_blit_uploads() && sfer.mLayersImage) {
if (sfer.mLayersImage && allowBlitImage) {
layersImage = sfer.mLayersImage;
elemWidth = layersImage->GetSize().width;
elemHeight = layersImage->GetSize().height;
@ -214,9 +166,7 @@ UniquePtr<webgl::TexUnpackBlob> WebGLContext::FromDomElem(
////
if (!layersImage && !dataSurf) {
const bool isClientData = true;
return MakeUnique<webgl::TexUnpackBytes>(this, target, size.x, size.y,
size.z, isClientData, nullptr, 0);
return Some(TexUnpackBlobDesc{target, size, gfxAlphaType::NonPremult});
}
//////
@ -230,9 +180,9 @@ UniquePtr<webgl::TexUnpackBlob> WebGLContext::FromDomElem(
nsIPrincipal* dstPrincipal = canvas.NodePrincipal();
if (!dstPrincipal->Subsumes(srcPrincipal)) {
GenerateWarning("Cross-origin elements require CORS.");
webgl.EnqueueWarning("Cross-origin elements require CORS.");
out_error->Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;
return {};
}
}
@ -240,55 +190,25 @@ UniquePtr<webgl::TexUnpackBlob> WebGLContext::FromDomElem(
// mIsWriteOnly defaults to true, and so will be true even if SFE merely
// failed. Thus we must test mIsWriteOnly after successfully retrieving an
// Image or SourceSurface.
GenerateWarning("Element is write-only, thus cannot be uploaded.");
webgl.EnqueueWarning("Element is write-only, thus cannot be uploaded.");
out_error->Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;
return {};
}
//////
// Ok, we're good!
if (layersImage) {
return MakeUnique<webgl::TexUnpackImage>(
this, target, size.x, size.y, size.z, layersImage, sfer.mAlphaType);
return Some(
TexUnpackBlobDesc{target, size, sfer.mAlphaType, {}, {}, layersImage});
}
MOZ_ASSERT(dataSurf);
return MakeUnique<webgl::TexUnpackSurface>(this, target, size.x, size.y,
size.z, dataSurf, sfer.mAlphaType);
return Some(
TexUnpackBlobDesc{target, size, sfer.mAlphaType, {}, {}, {}, dataSurf});
}
////////////////////////////////////////
UniquePtr<webgl::TexUnpackBlob> WebGLContext::From(
const dom::HTMLCanvasElement& canvas, TexImageTarget target,
const uvec3& size, const TexImageSource& src,
dom::Uint8ClampedArray* const scopedArr) const {
if (src.mPboOffset) {
return FromPboOffset(this, target, size, *(src.mPboOffset));
}
if (mBoundPixelUnpackBuffer) {
ErrorInvalidOperation("PIXEL_UNPACK_BUFFER must be null.");
return nullptr;
}
if (src.mImageBitmap) {
return FromImageBitmap(this, target, size, *(src.mImageBitmap),
src.mOut_error);
}
if (src.mImageData) {
return FromImageData(this, target, size, *(src.mImageData), scopedArr);
}
if (src.mDomElem) {
return FromDomElem(canvas, target, size, *(src.mDomElem), src.mOut_error);
}
return FromView(this, target, size, src.mView, src.mViewElemOffset,
src.mViewElemLengthOverride);
}
} // namespace webgl
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
@ -936,21 +856,28 @@ void WebGLTexture::TexStorage(TexTarget target, uint32_t levels,
// Tex(Sub)Image
// TexSubImage iff `!respectFormat`
void WebGLTexture::TexImage(GLenum imageTarget, uint32_t level,
GLenum respecFormat, const uvec3& offset,
const uvec3& claimedSize,
const webgl::PackingInfo& pi,
const TexImageSource& src,
const dom::HTMLCanvasElement& canvas) {
dom::Uint8ClampedArray scopedArr;
const auto blob =
mContext->From(canvas, imageTarget, claimedSize, src, &scopedArr);
if (!blob) return;
void WebGLTexture::TexImage(uint32_t level, GLenum respecFormat,
const uvec3& offset, const webgl::PackingInfo& pi,
const webgl::TexUnpackBlobDesc& src) {
Maybe<RawBuffer<>> cpuDataView;
if (src.cpuData) {
cpuDataView = Some(RawBuffer<>{src.cpuData->Data()});
}
const auto srcViewDesc = webgl::TexUnpackBlobDesc{
src.imageTarget, src.size, src.srcAlphaType, std::move(cpuDataView),
src.pboOffset, src.image, src.surf, src.unpacking};
const auto blob = webgl::TexUnpackBlob::Create(srcViewDesc);
if (!blob) {
MOZ_ASSERT(false);
return;
}
// For DOM element upload entrypoints that have no size arguments, claimedSize
// is 0. Use blob size, not claimedSize. (blob size can also be zero, and
// that's valid!)
const auto size = uvec3{blob->mWidth, blob->mHeight, blob->mDepth};
const auto imageTarget = blob->mDesc.imageTarget;
auto size = blob->mDesc.size;
if (!IsTarget3D(imageTarget)) {
size.z = 1;
}
////////////////////////////////////
// Get dest info
@ -1055,6 +982,12 @@ void WebGLTexture::TexImage(GLenum imageTarget, uint32_t level,
////////////////////////////////////
// Do the thing!
blob->mDesc.unpacking.Apply(*mContext->gl, mContext->IsWebGL2(), size);
const auto revertUnpacking = MakeScopeExit([&]() {
const WebGLPixelStore defaultUnpacking;
defaultUnpacking.Apply(*mContext->gl, mContext->IsWebGL2(), size);
});
Maybe<webgl::ImageInfo> newImageInfo;
bool isRespec = false;
if (respecFormat) {
@ -1063,7 +996,7 @@ void WebGLTexture::TexImage(GLenum imageTarget, uint32_t level,
newImageInfo = Some(webgl::ImageInfo{dstUsage, size.x, size.y, size.z});
if (!blob->HasData()) {
newImageInfo->mUninitializedSlices =
Some(std::vector<bool>(blob->mDepth, true));
Some(std::vector<bool>(size.z, true));
}
isRespec = (imageInfo->mWidth != newImageInfo->mWidth ||
@ -1083,9 +1016,8 @@ void WebGLTexture::TexImage(GLenum imageTarget, uint32_t level,
const bool isSubImage = !respecFormat;
GLenum glError;
if (!blob->TexOrSubImage(isSubImage, isRespec, this, imageTarget, level,
driverUnpackInfo, offset.x, offset.y, offset.z, pi,
&glError)) {
if (!blob->TexOrSubImage(isSubImage, isRespec, this, level, driverUnpackInfo,
offset.x, offset.y, offset.z, pi, &glError)) {
return;
}
@ -1702,8 +1634,9 @@ static bool DoCopyTexOrSubImage(WebGLContext* webgl, bool isSubImage,
}
if (!isSubImage || zeros) {
const ScopedUnpackReset unpackReset(webgl);
gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1);
const auto revert = MakeScopeExit(
[&]() { gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4); });
if (!isSubImage) {
error = DoTexImage(gl, target, level, idealUnpack, dstWidth, dstHeight,
1, nullptr);

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

@ -25,7 +25,6 @@
#include "nsString.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "mozilla/ipc/SharedMemoryBasic.h"
//#include "WebGLStrongTypes.h"
// Manual reflection of WebIDL typedefs that are different from their
// OpenGL counterparts.
@ -289,9 +288,9 @@ class UniqueBuffer {
void* get() const { return mBuffer; }
UniqueBuffer(const UniqueBuffer& other) =
explicit UniqueBuffer(const UniqueBuffer& other) =
delete; // construct using std::move()!
void operator=(const UniqueBuffer& other) =
UniqueBuffer& operator=(const UniqueBuffer& other) =
delete; // assign using std::move()!
};
@ -351,19 +350,6 @@ struct FloatOrInt final // For TexParameter[fi] and friends.
}
};
struct WebGLPixelStore final {
uint32_t mUnpackImageHeight = 0;
uint32_t mUnpackSkipImages = 0;
uint32_t mUnpackRowLength = 0;
uint32_t mUnpackSkipRows = 0;
uint32_t mUnpackSkipPixels = 0;
uint32_t mUnpackAlignment = 0;
GLenum mColorspaceConversion = 0;
bool mFlipY = false;
bool mPremultiplyAlpha = false;
bool mRequireFastPath = false;
};
using WebGLTexUnpackVariant =
Variant<UniquePtr<webgl::TexUnpackBytes>,
UniquePtr<webgl::TexUnpackSurface>,
@ -692,7 +678,7 @@ struct GetUniformData final {
struct FrontBufferSnapshotIpc final {
uvec2 surfSize = {};
Maybe<mozilla::ipc::Shmem> shmem;
mozilla::ipc::Shmem shmem = {};
};
struct ReadPixelsResult {
@ -733,7 +719,7 @@ struct ICRData {
* inner data type must be trivially copyable by memcpy.
*/
template <typename T = uint8_t>
class RawBuffer {
class RawBuffer final {
const T* mBegin = nullptr;
size_t mLen = 0;
UniqueBuffer mOwned;
@ -752,6 +738,7 @@ class RawBuffer {
~RawBuffer() = default;
Range<const T> Data() const { return {mBegin, mLen}; }
const auto& begin() const { return mBegin; };
RawBuffer() = default;
@ -870,6 +857,17 @@ inline GLenum ImageToTexTarget(const GLenum imageTarget) {
}
}
inline bool IsTexTarget3D(const GLenum texTarget) {
switch (texTarget) {
case LOCAL_GL_TEXTURE_2D_ARRAY:
case LOCAL_GL_TEXTURE_3D:
return true;
default:
return false;
}
}
// -
namespace dom {
@ -892,15 +890,77 @@ struct TexImageSource {
ErrorResult* mOut_error = nullptr;
};
struct WebGLPixelStore final {
uint32_t mUnpackImageHeight = 0;
uint32_t mUnpackSkipImages = 0;
uint32_t mUnpackRowLength = 0;
uint32_t mUnpackSkipRows = 0;
uint32_t mUnpackSkipPixels = 0;
uint32_t mUnpackAlignment = 4;
GLenum mColorspaceConversion =
dom::WebGLRenderingContext_Binding::BROWSER_DEFAULT_WEBGL;
bool mFlipY = false;
bool mPremultiplyAlpha = false;
bool mRequireFastPath = false;
void Apply(gl::GLContext&, bool isWebgl2, const uvec3& uploadSize) const;
WebGLPixelStore ForUseWith(
const GLenum target, const uvec3& uploadSize,
const Maybe<gfx::IntSize>& structuredSrcSize) const {
auto ret = *this;
if (!IsTexTarget3D(target)) {
ret.mUnpackSkipImages = 0;
ret.mUnpackImageHeight = 0;
}
if (structuredSrcSize) {
ret.mUnpackRowLength = structuredSrcSize->width;
}
if (!ret.mUnpackRowLength) {
ret.mUnpackRowLength = uploadSize.x;
}
if (!ret.mUnpackImageHeight) {
ret.mUnpackImageHeight = uploadSize.y;
}
return ret;
}
};
struct TexImageData final {
WebGLPixelStore unpackState;
Maybe<uint64_t> pboOffset;
RawBuffer<> data;
const dom::Element* domElem = nullptr;
ErrorResult* out_domElemError = nullptr;
};
namespace webgl {
struct TexUnpackBlobDesc final {
GLenum imageTarget = LOCAL_GL_TEXTURE_2D;
uvec3 size;
gfxAlphaType srcAlphaType = gfxAlphaType::NonPremult;
Maybe<RawBuffer<>> cpuData;
Maybe<uint64_t> pboOffset;
RefPtr<layers::Image> image;
RefPtr<gfx::DataSourceSurface> surf;
WebGLPixelStore unpacking;
};
} // namespace webgl
// ---------------------------------------
// MakeRange
inline Range<uint8_t> ByteRange(const mozilla::ipc::Shmem& shmem) {
return {shmem.get<uint8_t>(), shmem.Size<uint8_t>()};
}
// -
template <typename T, size_t N>
inline Range<const T> MakeRange(T (&arr)[N]) {
return {arr, N};

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

@ -5432,6 +5432,7 @@ fail-if = (os == 'linux')
subsuite = webgl2-core
[generated/test_2_conformance2__state__gl-object-get-calls.html]
subsuite = webgl2-core
skip-if = 1
fail-if = (os == 'linux')
[generated/test_2_conformance2__sync__sync-webgl-specific.html]
subsuite = webgl2-core
@ -12280,6 +12281,7 @@ subsuite = webgl1-core
subsuite = webgl1-core
[generated/test_conformance__state__gl-object-get-calls.html]
subsuite = webgl1-core
skip-if = 1
[generated/test_conformance__state__state-uneffected-after-compositing.html]
subsuite = webgl1-core
[generated/test_conformance__textures__canvas__tex-2d-alpha-alpha-unsigned_byte.html]

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

@ -73,6 +73,14 @@ skip-if = (os == 'android') || (os == 'linux') || (os == 'win')
[generated/test_conformance__ogles__GL__mat3__mat3_001_to_006.html]
# Timeout on D3D11
skip-if = (os == 'win')
[generated/test_conformance__state__gl-object-get-calls.html]
# Really really slow on IPC mode. Update test suite to get faster/quick-mode test.
skip-if = 1
[generated/test_2_conformance2__state__gl-object-get-calls.html]
# Really really slow on IPC mode. Update test suite to get faster/quick-mode test.
skip-if = 1
# Also fails on Linux still?
fail-if = (os == 'linux')
########################################################################
# Global
@ -799,8 +807,6 @@ fail-if = (os == 'linux')
fail-if = (os == 'linux')
[generated/test_2_conformance2__state__gl-get-calls.html]
fail-if = (os == 'linux')
[generated/test_2_conformance2__state__gl-object-get-calls.html]
fail-if = (os == 'linux')
[generated/test_2_conformance__state__gl-get-calls.html]
fail-if = (os == 'linux')
[generated/test_2_conformance__glsl__bugs__sampler-array-using-loop-index.html]