diff options
Diffstat (limited to 'dom/canvas')
162 files changed, 8131 insertions, 854 deletions
diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 62f6e6443d..1a79a9f734 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -682,6 +682,8 @@ class AdjustedTarget { CompositionOp UsedOperation() const { return mUsedOperation; } + bool UseOptimizeShadow() const { return mOptimizeShadow; } + ShadowOptions ShadowParams() const { const ContextState& state = mCtx->CurrentState(); return ShadowOptions(ToDeviceColor(state.shadowColor), state.shadowOffset, @@ -5359,6 +5361,40 @@ static Matrix ComputeRotationMatrix(gfxFloat aRotatedWidth, .PostTranslate(shiftLeftTopToOrigin); } +static Maybe<layers::SurfaceDescriptor> +MaybeGetSurfaceDescriptorForRemoteCanvas( + const SurfaceFromElementResult& aResult) { + if (!StaticPrefs::gfx_canvas_remote_use_draw_image_fast_path()) { + return Nothing(); + } + + if (!aResult.mLayersImage) { + return Nothing(); + } + + Maybe<layers::SurfaceDescriptor> sd; + sd = aResult.mLayersImage->GetDesc(); + if (sd.isNothing() || + sd.ref().type() != + layers::SurfaceDescriptor::TSurfaceDescriptorGPUVideo) { + return Nothing(); + } + + const auto& sdv = sd.ref().get_SurfaceDescriptorGPUVideo(); + const auto& sdvType = sdv.type(); + if (sdvType == + layers::SurfaceDescriptorGPUVideo::TSurfaceDescriptorRemoteDecoder) { + const auto& sdrd = sdv.get_SurfaceDescriptorRemoteDecoder(); + const auto& subdesc = sdrd.subdesc(); + const auto& subdescType = subdesc.type(); + if (subdescType == layers::RemoteDecoderVideoSubDescriptor::Tnull_t) { + return sd; + } + } + + return Nothing(); +} + // drawImage(in HTMLImageElement image, in float dx, in float dy); // -- render image from 0,0 at dx,dy top-left coords // drawImage(in HTMLImageElement image, in float dx, in float dy, in float dw, @@ -5470,6 +5506,8 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage, } DirectDrawInfo drawInfo; + Maybe<layers::SurfaceDescriptor> surfaceDescriptor; + SurfaceFromElementResult res; if (!srcSurf) { // The canvas spec says that drawImage should draw the first frame @@ -5478,7 +5516,6 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage, nsLayoutUtils::SFE_NO_RASTERIZING_VECTORS | nsLayoutUtils::SFE_ALLOW_UNCROPPED_UNSCALED; - SurfaceFromElementResult res; if (offscreenCanvas) { res = nsLayoutUtils::SurfaceFromOffscreenCanvas(offscreenCanvas, sfeFlags, mTarget); @@ -5487,12 +5524,34 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage, } else { res = CanvasRenderingContext2D::CachedSurfaceFromElement(element); if (!res.mSourceSurface) { - res = nsLayoutUtils::SurfaceFromElement(element, sfeFlags, mTarget); + HTMLVideoElement* video = HTMLVideoElement::FromNodeOrNull(element); + if (video && mBufferProvider->IsAccelerated() && + mTarget->IsRecording() && + !(!NeedToApplyFilter() && NeedToDrawShadow())) { + res = nsLayoutUtils::SurfaceFromElement( + video, sfeFlags, mTarget, /* aOptimizeSourceSurface */ false); + surfaceDescriptor = MaybeGetSurfaceDescriptorForRemoteCanvas(res); + if (surfaceDescriptor.isNothing() && res.mLayersImage) { + if ((res.mSourceSurface = res.mLayersImage->GetAsSourceSurface())) { + RefPtr<SourceSurface> opt = + mTarget->OptimizeSourceSurface(res.mSourceSurface); + if (opt) { + res.mSourceSurface = opt; + } + } + } + } else { + res = nsLayoutUtils::SurfaceFromElement(element, sfeFlags, mTarget); + } } } - srcSurf = res.GetSourceSurface(); - if (!srcSurf && !res.mDrawInfo.mImgContainer) { + if (surfaceDescriptor.isNothing()) { + srcSurf = res.GetSourceSurface(); + } + + if (!srcSurf && surfaceDescriptor.isNothing() && + !res.mDrawInfo.mImgContainer) { // https://html.spec.whatwg.org/#check-the-usability-of-the-image-argument: // // Only throw if the request is broken and the element is an @@ -5612,10 +5671,10 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage, return; } - if (srcSurf) { + if (srcSurf || surfaceDescriptor.isSome()) { gfx::Rect sourceRect(aSx, aSy, aSw, aSh); - if ((element && element == mCanvasElement) || - (offscreenCanvas && offscreenCanvas == mOffscreenCanvas)) { + if (srcSurf && ((element && element == mCanvasElement) || + (offscreenCanvas && offscreenCanvas == mOffscreenCanvas))) { // srcSurf is a snapshot of mTarget. If we draw to mTarget now, we'll // trigger a COW copy of the whole canvas into srcSurf. That's a huge // waste if sourceRect doesn't cover the whole canvas. @@ -5656,10 +5715,24 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage, destRect.y = 0; } - tempTarget.DrawSurface( - srcSurf, destRect, sourceRect, - DrawSurfaceOptions(samplingFilter, SamplingBounds::UNBOUNDED), - DrawOptions(CurrentState().globalAlpha, op, antialiasMode)); + if (srcSurf) { + MOZ_ASSERT(surfaceDescriptor.isNothing()); + + tempTarget.DrawSurface( + srcSurf, destRect, sourceRect, + DrawSurfaceOptions(samplingFilter, SamplingBounds::UNBOUNDED), + DrawOptions(CurrentState().globalAlpha, op, antialiasMode)); + } else if (surfaceDescriptor.isSome()) { + MOZ_ASSERT(!tempTarget.UseOptimizeShadow()); + MOZ_ASSERT(res.mLayersImage); + + mTarget->DrawSurfaceDescriptor( + surfaceDescriptor.ref(), res.mLayersImage, destRect, sourceRect, + DrawSurfaceOptions(samplingFilter, SamplingBounds::UNBOUNDED), + DrawOptions(CurrentState().globalAlpha, op, antialiasMode)); + } else { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + } if (rotationDeg != VideoRotation::kDegree_0) { tempTarget->SetTransform(currentTransform); diff --git a/dom/canvas/ClientWebGLContext.cpp b/dom/canvas/ClientWebGLContext.cpp index 1614d2ead2..236ea916d0 100644 --- a/dom/canvas/ClientWebGLContext.cpp +++ b/dom/canvas/ClientWebGLContext.cpp @@ -548,36 +548,42 @@ Maybe<layers::SurfaceDescriptor> ClientWebGLContext::GetFrontBuffer( const auto& child = mNotLost->outOfProcess; child->FlushPendingCmds(); - Maybe<layers::SurfaceDescriptor> ret; + // Always synchronously get the front buffer if not using a remote texture. + bool needsSync = true; + Maybe<layers::SurfaceDescriptor> syncDesc; + Maybe<layers::SurfaceDescriptor> remoteDesc; auto& info = child->GetFlushedCmdInfo(); // If valid remote texture data was set for async present, then use it. if (!fb && !vr && mRemoteTextureOwnerId && mLastRemoteTextureId) { const auto tooManyFlushes = 10; // If there are many flushed cmds, force synchronous IPC to avoid too many - // pending ipc messages. - if (XRE_IsParentProcess() || - gfx::gfxVars::WebglOopAsyncPresentForceSync() || - info.flushesSinceLastCongestionCheck > tooManyFlushes) { - // Request the front buffer from IPDL to cause a sync, even though we - // will continue to use the remote texture descriptor after. - (void)child->SendGetFrontBuffer(fb ? fb->mId : 0, vr, &ret); - } - // Reset flushesSinceLastCongestionCheck - info.flushesSinceLastCongestionCheck = 0; - info.congestionCheckGeneration++; + // pending ipc messages. Otherwise don't sync for other cases to avoid any + // performance penalty. + needsSync = XRE_IsParentProcess() || + gfx::gfxVars::WebglOopAsyncPresentForceSync() || + info.flushesSinceLastCongestionCheck > tooManyFlushes; - return Some(layers::SurfaceDescriptorRemoteTexture(*mLastRemoteTextureId, - *mRemoteTextureOwnerId)); + // Only send over a remote texture descriptor if the WebGLChild actor is + // alive to ensure the remote texture id is valid. + if (child->CanSend()) { + remoteDesc = Some(layers::SurfaceDescriptorRemoteTexture( + *mLastRemoteTextureId, *mRemoteTextureOwnerId)); + } } - if (!child->SendGetFrontBuffer(fb ? fb->mId : 0, vr, &ret)) return {}; + if (needsSync && + !child->SendGetFrontBuffer(fb ? fb->mId : 0, vr, &syncDesc)) { + return {}; + } // Reset flushesSinceLastCongestionCheck info.flushesSinceLastCongestionCheck = 0; info.congestionCheckGeneration++; - return ret; + // If there is a remote texture descriptor, use that preferentially, as the + // sync front buffer descriptor was only created to force a sync first. + return remoteDesc ? remoteDesc : syncDesc; } Maybe<layers::SurfaceDescriptor> ClientWebGLContext::PresentFrontBuffer( @@ -957,9 +963,31 @@ bool ClientWebGLContext::CreateHostContext(const uvec2& requestedSize) { .mCurrentQueryByTarget[LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN]; } + state.mIsEnabledMap = Some(webgl::MakeIsEnabledMap(mIsWebGL2)); + return true; } +std::unordered_map<GLenum, bool> webgl::MakeIsEnabledMap(const bool webgl2) { + auto ret = std::unordered_map<GLenum, bool>{}; + + ret[LOCAL_GL_BLEND] = false; + ret[LOCAL_GL_CULL_FACE] = false; + ret[LOCAL_GL_DEPTH_TEST] = false; + ret[LOCAL_GL_DITHER] = true; + ret[LOCAL_GL_POLYGON_OFFSET_FILL] = false; + ret[LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE] = false; + ret[LOCAL_GL_SAMPLE_COVERAGE] = false; + ret[LOCAL_GL_SCISSOR_TEST] = false; + ret[LOCAL_GL_STENCIL_TEST] = false; + + if (webgl2) { + ret[LOCAL_GL_RASTERIZER_DISCARD] = false; + } + + return ret; +} + // ------- uvec2 ClientWebGLContext::DrawingBufferSize() { @@ -1461,6 +1489,8 @@ already_AddRefed<WebGLSyncJS> ClientWebGLContext::FenceSync( availRunnable.mSyncs.push_back(ret.get()); ret->mCanBeAvailable = false; + AutoEnqueueFlush(); + return ret.forget(); } @@ -1895,24 +1925,40 @@ bool ClientWebGLContext::IsVertexArray( // ------------------------- GL State ------------------------- -void ClientWebGLContext::SetEnabledI(GLenum cap, Maybe<GLuint> i, - bool val) const { +void ClientWebGLContext::SetEnabledI(const GLenum cap, const Maybe<GLuint> i, + const bool val) const { + const FuncScope funcScope(*this, "enable/disable"); + if (IsContextLost()) return; + + auto& map = *mNotLost->state.mIsEnabledMap; + auto slot = MaybeFind(map, cap); + if (i && cap != LOCAL_GL_BLEND) { + slot = nullptr; + } + if (!slot) { + EnqueueError_ArgEnum("cap", cap); + return; + } + Run<RPROC(SetEnabled)>(cap, i, val); + + if (!i || *i == 0) { + *slot = val; + } } -bool ClientWebGLContext::IsEnabled(GLenum cap) const { +bool ClientWebGLContext::IsEnabled(const GLenum cap) const { const FuncScope funcScope(*this, "isEnabled"); if (IsContextLost()) return false; - const auto& inProcess = mNotLost->inProcess; - if (inProcess) { - return inProcess->IsEnabled(cap); + const auto& map = *mNotLost->state.mIsEnabledMap; + const auto slot = MaybeFind(map, cap); + if (!slot) { + EnqueueError_ArgEnum("cap", cap); + return false; } - const auto& child = mNotLost->outOfProcess; - child->FlushPendingCmds(); - bool ret = {}; - if (!child->SendIsEnabled(cap, &ret)) return false; - return ret; + + return *slot; } template <typename T, typename S> @@ -2178,6 +2224,10 @@ void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname, (void)ToJSValueOrNull(cx, state.mBoundDrawFb, retval); return; + case LOCAL_GL_MAX_CLIENT_WAIT_TIMEOUT_WEBGL: + retval.set(JS::NumberValue(webgl::kMaxClientWaitSyncTimeoutNS)); + return; + case LOCAL_GL_PIXEL_PACK_BUFFER_BINDING: fnSetRetval_Buffer(LOCAL_GL_PIXEL_PACK_BUFFER); return; @@ -2987,7 +3037,7 @@ void ClientWebGLContext::DepthRange(GLclampf zNear, GLclampf zFar) { Run<RPROC(DepthRange)>(zNear, zFar); } -void ClientWebGLContext::Flush(const bool flushGl) { +void ClientWebGLContext::Flush(const bool flushGl) const { const FuncScope funcScope(*this, "flush"); if (IsContextLost()) return; @@ -5417,13 +5467,11 @@ void ClientWebGLContext::GetSyncParameter( case LOCAL_GL_SYNC_FLAGS: return JS::NumberValue(0); case LOCAL_GL_SYNC_STATUS: { - if (!sync.mSignaled) { - const auto res = ClientWaitSync(sync, 0, 0); - sync.mSignaled = (res == LOCAL_GL_ALREADY_SIGNALED || - res == LOCAL_GL_CONDITION_SATISFIED); - } - return JS::NumberValue(sync.mSignaled ? LOCAL_GL_SIGNALED - : LOCAL_GL_UNSIGNALED); + const auto res = ClientWaitSync(sync, 0, 0); + const auto signaled = (res == LOCAL_GL_ALREADY_SIGNALED || + res == LOCAL_GL_CONDITION_SATISFIED); + return JS::NumberValue(signaled ? LOCAL_GL_SIGNALED + : LOCAL_GL_UNSIGNALED); } default: EnqueueError_ArgEnum("pname", pname); @@ -5432,6 +5480,8 @@ void ClientWebGLContext::GetSyncParameter( }()); } +// - + GLenum ClientWebGLContext::ClientWaitSync(WebGLSyncJS& sync, const GLbitfield flags, const GLuint64 timeout) const { @@ -5439,12 +5489,63 @@ GLenum ClientWebGLContext::ClientWaitSync(WebGLSyncJS& sync, if (IsContextLost()) return LOCAL_GL_WAIT_FAILED; if (!sync.ValidateUsable(*this, "sync")) return LOCAL_GL_WAIT_FAILED; - if (flags != 0 && flags != LOCAL_GL_SYNC_FLUSH_COMMANDS_BIT) { + static constexpr auto VALID_BITS = LOCAL_GL_SYNC_FLUSH_COMMANDS_BIT; + if ((flags | VALID_BITS) != VALID_BITS) { EnqueueError(LOCAL_GL_INVALID_VALUE, "`flags` must be SYNC_FLUSH_COMMANDS_BIT or 0."); return LOCAL_GL_WAIT_FAILED; } + if (timeout > webgl::kMaxClientWaitSyncTimeoutNS) { + EnqueueError( + LOCAL_GL_INVALID_OPERATION, + "`timeout` (%sns) must be less than MAX_CLIENT_WAIT_TIMEOUT_WEBGL " + "(%sns).", + ToStringWithCommas(timeout).c_str(), + ToStringWithCommas(webgl::kMaxClientWaitSyncTimeoutNS).c_str()); + return LOCAL_GL_WAIT_FAILED; + } + + const bool canBeAvailable = + (sync.mCanBeAvailable || StaticPrefs::webgl_allow_immediate_queries()); + if (!canBeAvailable) { + constexpr uint8_t WARN_AT = 100; + if (sync.mNumQueriesBeforeFirstFrameBoundary <= WARN_AT) { + sync.mNumQueriesBeforeFirstFrameBoundary += 1; + if (sync.mNumQueriesBeforeFirstFrameBoundary == WARN_AT) { + EnqueueWarning( + "ClientWaitSync must return TIMEOUT_EXPIRED until control has" + " returned to the user agent's main loop, but was polled %hhu " + "times. Are you spin-locking? (only warns once)", + sync.mNumQueriesBeforeFirstFrameBoundary); + } + } + return LOCAL_GL_TIMEOUT_EXPIRED; + } + + if (mCompletedSyncId >= sync.mId) { + return LOCAL_GL_ALREADY_SIGNALED; + } + if (flags & LOCAL_GL_SYNC_FLUSH_COMMANDS_BIT) { + Flush(); + } else { + constexpr uint8_t WARN_AT = 100; + if (sync.mNumQueriesWithoutFlushCommandsBit <= WARN_AT) { + sync.mNumQueriesWithoutFlushCommandsBit += 1; + if (sync.mNumQueriesWithoutFlushCommandsBit == WARN_AT) { + EnqueueWarning( + "ClientWaitSync with timeout=0 (or GetSyncParameter(SYNC_STATUS)) " + "called %hhu times without SYNC_FLUSH_COMMANDS_BIT. If you do not " + "flush, this sync object is not guaranteed to ever complete.", + sync.mNumQueriesWithoutFlushCommandsBit); + } + } + } + if (!timeout) return LOCAL_GL_TIMEOUT_EXPIRED; + + // - + // Fine, time to block: + const auto ret = [&]() { const auto& inProcess = mNotLost->inProcess; if (inProcess) { @@ -5462,29 +5563,10 @@ GLenum ClientWebGLContext::ClientWaitSync(WebGLSyncJS& sync, switch (ret) { case LOCAL_GL_CONDITION_SATISFIED: case LOCAL_GL_ALREADY_SIGNALED: - sync.mSignaled = true; + OnSyncComplete(sync.mId); break; } - // - - - const bool canBeAvailable = - (sync.mCanBeAvailable || StaticPrefs::webgl_allow_immediate_queries()); - if (!canBeAvailable) { - constexpr uint8_t WARN_AT = 100; - if (sync.mNumQueriesBeforeFirstFrameBoundary <= WARN_AT) { - sync.mNumQueriesBeforeFirstFrameBoundary += 1; - if (sync.mNumQueriesBeforeFirstFrameBoundary == WARN_AT) { - EnqueueWarning( - "ClientWaitSync must return TIMEOUT_EXPIRED until control has" - " returned to the user agent's main loop, but was polled %hhu " - "times. Are you spin-locking? (only warns once)", - sync.mNumQueriesBeforeFirstFrameBoundary); - } - } - return LOCAL_GL_TIMEOUT_EXPIRED; - } - return ret; } @@ -5688,6 +5770,7 @@ void ClientWebGLContext::DrawBuffers(const dom::Sequence<GLenum>& buffers) { void ClientWebGLContext::EnqueueErrorImpl(const GLenum error, const nsACString& text) const { if (!mNotLost) return; // Ignored if context is lost. + AutoEnqueueFlush(); Run<RPROC(GenerateError)>(error, ToString(text)); } @@ -6570,7 +6653,7 @@ Maybe<Span<uint8_t>> ClientWebGLContext::ValidateArrayBufferView( // --------------------------- webgl::ObjectJS::ObjectJS(const ClientWebGLContext& webgl) - : mGeneration(webgl.mNotLost), mId(webgl.mNotLost->state.NextId()) {} + : mGeneration(webgl.mNotLost), mId(webgl.NextId()) {} // - diff --git a/dom/canvas/ClientWebGLContext.h b/dom/canvas/ClientWebGLContext.h index 3c011a3027..e736235361 100644 --- a/dom/canvas/ClientWebGLContext.h +++ b/dom/canvas/ClientWebGLContext.h @@ -134,9 +134,6 @@ class ShaderKeepAlive final { }; class ContextGenerationInfo final { - private: - ObjectId mLastId = 0; - public: webgl::ExtensionBits mEnabledExtensions; RefPtr<WebGLProgramJS> mCurrentProgram; @@ -180,7 +177,7 @@ class ContextGenerationInfo final { webgl::ProvokingVertex mProvokingVertex = webgl::ProvokingVertex::LastVertex; - ObjectId NextId() { return mLastId += 1; } + mutable Maybe<std::unordered_map<GLenum, bool>> mIsEnabledMap; }; // - @@ -493,7 +490,7 @@ class WebGLSyncJS final : public nsWrapperCache, bool mCanBeAvailable = false; uint8_t mNumQueriesBeforeFirstFrameBoundary = 0; - bool mSignaled = false; + uint8_t mNumQueriesWithoutFlushCommandsBit = 0; public: NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLSyncJS) @@ -781,8 +778,11 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal, mutable GLenum mNextError = 0; mutable webgl::LossStatus mLossStatus = webgl::LossStatus::Ready; mutable bool mAwaitingRestore = false; + mutable webgl::ObjectId mLastId = 0; public: + webgl::ObjectId NextId() const { return mLastId += 1; } + // Holds Some Id if async present is used mutable Maybe<layers::RemoteTextureId> mLastRemoteTextureId; mutable Maybe<layers::RemoteTextureOwnerId> mRemoteTextureOwnerId; @@ -1092,15 +1092,15 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal, // - - bool mAutoFlushPending = false; + mutable bool mAutoFlushPending = false; - void AutoEnqueueFlush() { + void AutoEnqueueFlush() const { if (MOZ_LIKELY(mAutoFlushPending)) return; mAutoFlushPending = true; - const auto weak = WeakPtr<ClientWebGLContext>(this); - const auto DeferredFlush = [weak]() { - const auto strong = RefPtr<ClientWebGLContext>(weak); + const auto DeferredFlush = [weak = + WeakPtr<const ClientWebGLContext>(this)]() { + const auto strong = RefPtr<const ClientWebGLContext>(weak); if (!strong) return; if (!strong->mAutoFlushPending) return; strong->mAutoFlushPending = false; @@ -1111,12 +1111,12 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal, }; already_AddRefed<mozilla::CancelableRunnable> runnable = - NS_NewCancelableRunnableFunction("enqueue Event_webglcontextrestored", + NS_NewCancelableRunnableFunction("ClientWebGLContext::DeferredFlush", DeferredFlush); NS_DispatchToCurrentThread(std::move(runnable)); } - void CancelAutoFlush() { mAutoFlushPending = false; } + void CancelAutoFlush() const { mAutoFlushPending = false; } // - @@ -1141,6 +1141,7 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal, void Disable(GLenum cap) const { SetEnabledI(cap, {}, false); } void Enable(GLenum cap) const { SetEnabledI(cap, {}, true); } void SetEnabledI(GLenum cap, Maybe<GLuint> i, bool val) const; + bool IsEnabled(GLenum cap) const; private: @@ -1397,7 +1398,7 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal, void DepthRange(GLclampf zNear, GLclampf zFar); - void Flush(bool flushGl = true); + void Flush(bool flushGl = true) const; void Finish(); @@ -2245,6 +2246,13 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal, JS::MutableHandle<JS::Value> retval) const; void WaitSync(const WebGLSyncJS&, GLbitfield flags, GLint64 timeout) const; + mutable webgl::ObjectId mCompletedSyncId = 0; + void OnSyncComplete(webgl::ObjectId id) const { + if (mCompletedSyncId < id) { + mCompletedSyncId = id; + } + } + // -------------------------- Transform Feedback --------------------------- void BindTransformFeedback(GLenum target, WebGLTransformFeedbackJS*); diff --git a/dom/canvas/DrawTargetWebgl.cpp b/dom/canvas/DrawTargetWebgl.cpp index eae6dd78f3..fdc45cc842 100644 --- a/dom/canvas/DrawTargetWebgl.cpp +++ b/dom/canvas/DrawTargetWebgl.cpp @@ -21,6 +21,7 @@ #include "mozilla/gfx/Swizzle.h" #include "mozilla/layers/ImageDataSerializer.h" #include "mozilla/layers/RemoteTextureMap.h" +#include "mozilla/widget/ScreenManager.h" #include "skia/include/core/SkPixmap.h" #include "nsContentUtils.h" @@ -325,6 +326,11 @@ void SharedContextWebgl::UnlinkGlyphCaches() { void SharedContextWebgl::OnMemoryPressure() { mShouldClearCaches = true; } +void SharedContextWebgl::ClearCaches() { + OnMemoryPressure(); + ClearCachesIfNecessary(); +} + // Clear out the entire list of texture handles from any source. void SharedContextWebgl::ClearAllTextures() { while (!mTextureHandles.isEmpty()) { @@ -852,10 +858,14 @@ bool DrawTargetWebgl::CanCreate(const IntSize& aSize, SurfaceFormat aFormat) { // In addition, allow acceleration up to this size even if the screen is // smaller. A lot content expects this size to work well. See Bug 999841 static const int32_t kScreenPixels = 980 * 480; - IntSize screenSize = gfxPlatform::GetPlatform()->GetScreenSize(); - if (aSize.width * aSize.height > - std::max(screenSize.width * screenSize.height, kScreenPixels)) { - return false; + + if (RefPtr<widget::Screen> screen = + widget::ScreenManager::GetSingleton().GetPrimaryScreen()) { + LayoutDeviceIntSize screenSize = screen->GetRect().Size(); + if (aSize.width * aSize.height > + std::max(screenSize.width * screenSize.height, kScreenPixels)) { + return false; + } } } diff --git a/dom/canvas/DrawTargetWebgl.h b/dom/canvas/DrawTargetWebgl.h index 955ccaabf0..8dc9fff048 100644 --- a/dom/canvas/DrawTargetWebgl.h +++ b/dom/canvas/DrawTargetWebgl.h @@ -92,6 +92,8 @@ class SharedContextWebgl : public mozilla::RefCounted<SharedContextWebgl>, void OnMemoryPressure(); + void ClearCaches(); + private: SharedContextWebgl(); diff --git a/dom/canvas/HostWebGLContext.cpp b/dom/canvas/HostWebGLContext.cpp index 11051c756f..4eea15773a 100644 --- a/dom/canvas/HostWebGLContext.cpp +++ b/dom/canvas/HostWebGLContext.cpp @@ -180,6 +180,17 @@ void HostWebGLContext::CreateSync(const ObjectId id) { return; } slot = GetWebGL2Context()->FenceSync(LOCAL_GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + + if (!slot) return; + + slot->OnCompleteTaskAdd([host = WeakPtr{this}, id]() { + if (!host) return; + if (host->mOwnerData.inProcess) { + host->mOwnerData.inProcess->OnSyncComplete(id); + } else if (host->mOwnerData.outOfProcess) { + (void)host->mOwnerData.outOfProcess->SendOnSyncComplete(id); + } + }); } void HostWebGLContext::CreateTexture(const ObjectId id) { diff --git a/dom/canvas/HostWebGLContext.h b/dom/canvas/HostWebGLContext.h index cc385bc26a..23b836f9db 100644 --- a/dom/canvas/HostWebGLContext.h +++ b/dom/canvas/HostWebGLContext.h @@ -260,8 +260,6 @@ class HostWebGLContext final : public SupportsWeakPtr { mContext->SetEnabled(cap, i, val); } - bool IsEnabled(GLenum cap) const { return mContext->IsEnabled(cap); } - Maybe<double> GetNumber(GLenum pname) const { return mContext->GetParameter(pname); } diff --git a/dom/canvas/PWebGL.ipdl b/dom/canvas/PWebGL.ipdl index a49d41e582..82c813bfd5 100644 --- a/dom/canvas/PWebGL.ipdl +++ b/dom/canvas/PWebGL.ipdl @@ -101,7 +101,6 @@ parent: 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 (double? ret); - sync IsEnabled(uint32_t cap) returns (bool ret); sync OnMemoryPressure(); sync ValidateProgram(uint64_t id) returns (bool ret); @@ -110,6 +109,9 @@ child: // Tell client that this queue needs to be shut down async OnContextLoss(ContextLossReason aReason); + + // Triggered when the id from FenceSync completes. + async OnSyncComplete(uint64_t id); }; } // dom diff --git a/dom/canvas/QueueParamTraits.h b/dom/canvas/QueueParamTraits.h index a67f5abf51..87fe910675 100644 --- a/dom/canvas/QueueParamTraits.h +++ b/dom/canvas/QueueParamTraits.h @@ -262,15 +262,6 @@ struct QueueParamTraits<bool> { // --------------------------------------------------------------- template <class T> -Maybe<T> AsValidEnum(const std::underlying_type_t<T> raw_val) { - const auto raw_enum = T{raw_val}; // This is the risk we prevent! - if (!IsEnumCase(raw_enum)) return {}; - return Some(raw_enum); -} - -// - - -template <class T> struct QueueParamTraits_IsEnumCase { template <typename ProducerView> static bool Write(ProducerView& aProducerView, const T& aArg) { diff --git a/dom/canvas/TexUnpackBlob.cpp b/dom/canvas/TexUnpackBlob.cpp index e13dc1c064..c59253cfd8 100644 --- a/dom/canvas/TexUnpackBlob.cpp +++ b/dom/canvas/TexUnpackBlob.cpp @@ -25,6 +25,8 @@ namespace mozilla { bool webgl::PixelPackingState::AssertCurrentUnpack(gl::GLContext& gl, const bool isWebgl2) const { + if (!kIsDebug) return true; + auto actual = PixelPackingState{}; gl.GetInt(LOCAL_GL_UNPACK_ALIGNMENT, &actual.alignmentInTypeElems); if (isWebgl2) { diff --git a/dom/canvas/TiedFields.h b/dom/canvas/TiedFields.h index 2df225aeee..a071da9dab 100644 --- a/dom/canvas/TiedFields.h +++ b/dom/canvas/TiedFields.h @@ -131,42 +131,34 @@ constexpr bool AssertTiedFieldsAreExhaustive() { // - /** - * Padding<T> can be used to pad out a struct so that it's not implicitly - * padded by struct rules. - * You can also just add your padding to TiedFields, but by explicitly typing - * padding like this, serialization can make a choice whether to copy Padding, - * or instead to omit the copy. - * - * Omitting the copy isn't always faster. - * struct Entry { - * uint16_t key; - * Padding<uint16_t> padding; - * uint32_t val; - * auto MutTiedFields() { return std::tie(key, padding, val); } - * }; - * If you serialize Padding, the serialized size is 8, and the compiler will - * optimize serialization to a single 8-byte memcpy. - * If your serialization omits Padding, the serialized size of Entry shrinks - * by 25%. If you have a big list of Entrys, maybe this is a big savings! - * However, by optimizing for size here you sacrifice speed, because this splits - * the single memcpy into two: a 2-byte memcpy and a 4-byte memcpy. - * - * Explicitly marking padding gives callers the option of choosing. + * PaddingField<T,N=1> can be used to pad out a struct so that it's not + * implicitly padded by struct rules, but also can't be accidentally initialized + * via Aggregate Initialization. (TiedFields serialization checks rely on object + * fields leaving no implicit padding bytes, but explicit padding fields are + * fine) While you can use e.g. `uint8_t _padding[3];`, consider instead + * `PaddingField<uint8_t,3> _padding;` for clarity and to move the `3` nearer + * to the `uint8_t`. */ -template <class T> -struct Padding { - T ignored; +template <class T, size_t N = 1> +struct PaddingField { + static_assert(!std::is_array_v<T>, "Use PaddingField<T,N> not <T[N]>."); - friend constexpr bool operator==(const Padding&, const Padding&) { + std::array<T, N> ignored = {}; + + PaddingField() {} + + friend constexpr bool operator==(const PaddingField&, const PaddingField&) { return true; } - friend constexpr bool operator<(const Padding&, const Padding&) { + friend constexpr bool operator<(const PaddingField&, const PaddingField&) { return false; } + + auto MutTiedFields() { return std::tie(ignored); } }; -static_assert(sizeof(Padding<bool>) == 1); -static_assert(sizeof(Padding<bool[2]>) == 2); -static_assert(sizeof(Padding<int>) == 4); +static_assert(sizeof(PaddingField<bool>) == 1); +static_assert(sizeof(PaddingField<bool, 2>) == 2); +static_assert(sizeof(PaddingField<int>) == 4); // - @@ -202,7 +194,7 @@ static_assert(AreAllBytesTiedFields<Fish>()); struct Eel { // Like a Fish, but you can skip serializing the padding. bool b; - Padding<bool> padding[3]; + PaddingField<bool, 3> padding; int i; constexpr auto MutTiedFields() { return std::tie(i, b, padding); } diff --git a/dom/canvas/WebGL2Context.h b/dom/canvas/WebGL2Context.h index 018c81f298..c8fbdef5ee 100644 --- a/dom/canvas/WebGL2Context.h +++ b/dom/canvas/WebGL2Context.h @@ -104,12 +104,8 @@ class WebGL2Context final : public WebGLContext { // ------------------------------------------------------------------------- // Sync objects - WebGL2ContextSync.cpp - const GLuint64 kMaxClientWaitSyncTimeoutNS = - 1000 * 1000 * 1000; // 1000ms in ns. - RefPtr<WebGLSync> FenceSync(GLenum condition, GLbitfield flags); - GLenum ClientWaitSync(const WebGLSync& sync, GLbitfield flags, - GLuint64 timeout); + GLenum ClientWaitSync(WebGLSync& sync, GLbitfield flags, GLuint64 timeout); // ------------------------------------------------------------------------- // Transform Feedback - WebGL2ContextTransformFeedback.cpp diff --git a/dom/canvas/WebGL2ContextState.cpp b/dom/canvas/WebGL2ContextState.cpp index b97592b570..b7d2f44000 100644 --- a/dom/canvas/WebGL2ContextState.cpp +++ b/dom/canvas/WebGL2ContextState.cpp @@ -81,10 +81,6 @@ Maybe<double> WebGL2Context::GetParameter(GLenum pname) { return Some(4 * val); } - /* GLint64 */ - case LOCAL_GL_MAX_CLIENT_WAIT_TIMEOUT_WEBGL: - return Some(kMaxClientWaitSyncTimeoutNS); - case LOCAL_GL_MAX_ELEMENT_INDEX: // GL_MAX_ELEMENT_INDEX becomes available in GL 4.3 or via ES3 // compatibility diff --git a/dom/canvas/WebGL2ContextSync.cpp b/dom/canvas/WebGL2ContextSync.cpp index b0092ca682..e5a1b1bc7b 100644 --- a/dom/canvas/WebGL2ContextSync.cpp +++ b/dom/canvas/WebGL2ContextSync.cpp @@ -29,10 +29,12 @@ RefPtr<WebGLSync> WebGL2Context::FenceSync(GLenum condition, GLbitfield flags) { } RefPtr<WebGLSync> globj = new WebGLSync(this, condition, flags); + mPendingSyncs.emplace_back(globj); + EnsurePollPendingSyncs_Pending(); return globj; } -GLenum WebGL2Context::ClientWaitSync(const WebGLSync& sync, GLbitfield flags, +GLenum WebGL2Context::ClientWaitSync(WebGLSync& sync, GLbitfield flags, GLuint64 timeout) { const FuncScope funcScope(*this, "clientWaitSync"); if (IsContextLost()) return LOCAL_GL_WAIT_FAILED; @@ -44,19 +46,52 @@ GLenum WebGL2Context::ClientWaitSync(const WebGLSync& sync, GLbitfield flags, return LOCAL_GL_WAIT_FAILED; } - if (timeout > kMaxClientWaitSyncTimeoutNS) { - ErrorInvalidOperation("`timeout` must not exceed %s nanoseconds.", - "MAX_CLIENT_WAIT_TIMEOUT_WEBGL"); - return LOCAL_GL_WAIT_FAILED; - } - - const auto ret = gl->fClientWaitSync(sync.mGLName, flags, timeout); + const auto ret = sync.ClientWaitSync(flags, timeout); + return UnderlyingValue(ret); +} - if (ret == LOCAL_GL_CONDITION_SATISFIED || ret == LOCAL_GL_ALREADY_SIGNALED) { - sync.MarkSignaled(); +void WebGLContext::EnsurePollPendingSyncs_Pending() const { + if (mPollPendingSyncs_Pending) return; + mPollPendingSyncs_Pending = NS_NewRunnableFunction( + "WebGLContext::PollPendingSyncs", [weak = WeakPtr{this}]() { + if (const auto strong = RefPtr{weak.get()}) { + strong->mPollPendingSyncs_Pending = nullptr; + strong->PollPendingSyncs(); + if (strong->mPendingSyncs.size()) { + // Not done yet... + strong->EnsurePollPendingSyncs_Pending(); + } + } + }); + if (const auto eventTarget = GetCurrentSerialEventTarget()) { + eventTarget->DelayedDispatch(do_AddRef(mPollPendingSyncs_Pending), + kPollPendingSyncs_DelayMs); + } else { + NS_WARNING( + "[EnsurePollPendingSyncs_Pending] GetCurrentSerialEventTarget() -> " + "nullptr"); } +} - return ret; +void WebGLContext::PollPendingSyncs() const { + const FuncScope funcScope(*this, "<pollPendingSyncs>"); + if (IsContextLost()) return; + + while (mPendingSyncs.size()) { + if (const auto sync = RefPtr{mPendingSyncs.front().get()}) { + const auto res = sync->ClientWaitSync(0, 0); + switch (res) { + case ClientWaitSyncResult::WAIT_FAILED: + case ClientWaitSyncResult::TIMEOUT_EXPIRED: + return; + case ClientWaitSyncResult::CONDITION_SATISFIED: + case ClientWaitSyncResult::ALREADY_SIGNALED: + // Communication back to child happens in sync->lientWaitSync. + break; + } + } + mPendingSyncs.pop_front(); + } } } // namespace mozilla diff --git a/dom/canvas/WebGLChild.cpp b/dom/canvas/WebGLChild.cpp index ebfe35db88..81ea1dcdd6 100644 --- a/dom/canvas/WebGLChild.cpp +++ b/dom/canvas/WebGLChild.cpp @@ -162,4 +162,11 @@ mozilla::ipc::IPCResult WebGLChild::RecvOnContextLoss( return IPC_OK(); } +mozilla::ipc::IPCResult WebGLChild::RecvOnSyncComplete( + const webgl::ObjectId id) const { + if (!mContext) return IPC_OK(); + mContext->OnSyncComplete(id); + return IPC_OK(); +} + } // namespace mozilla::dom diff --git a/dom/canvas/WebGLChild.h b/dom/canvas/WebGLChild.h index 6848237d8f..f4229e1b9b 100644 --- a/dom/canvas/WebGLChild.h +++ b/dom/canvas/WebGLChild.h @@ -58,6 +58,7 @@ class WebGLChild final : public PWebGLChild, public SupportsWeakPtr { public: mozilla::ipc::IPCResult RecvJsWarning(const std::string&) const; mozilla::ipc::IPCResult RecvOnContextLoss(webgl::ContextLossReason) const; + mozilla::ipc::IPCResult RecvOnSyncComplete(webgl::ObjectId) const; }; } // namespace dom diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index ec19bfef3d..4bd189c46c 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -881,6 +881,8 @@ void WebGLContext::OnEndOfFrame() { mDrawCallsSinceLastFlush = 0; + PollPendingSyncs(); + BumpLru(); } diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h index 5ab584174c..d144584f4f 100644 --- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -303,6 +303,15 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr { uint64_t mNextFenceId = 1; uint64_t mCompletedFenceId = 0; + mutable std::list<WeakPtr<WebGLSync>> mPendingSyncs; + mutable RefPtr<nsIRunnable> mPollPendingSyncs_Pending; + static constexpr uint32_t kPollPendingSyncs_DelayMs = + 4; // Four times a frame. + public: + void EnsurePollPendingSyncs_Pending() const; + void PollPendingSyncs() const; + + protected: std::unique_ptr<gl::Texture> mIncompleteTexOverride; public: @@ -756,8 +765,6 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr { virtual Maybe<double> GetParameter(GLenum pname); Maybe<std::string> GetString(GLenum pname) const; - bool IsEnabled(GLenum cap); - private: static StaticMutex sLruMutex; static std::list<WebGLContext*> sLru MOZ_GUARDED_BY(sLruMutex); @@ -780,8 +787,7 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr { }; ScissorRect mScissorRect = {}; - bool ValidateCapabilityEnum(GLenum cap); - bool* GetStateTrackingSlot(GLenum cap, GLuint i); + bool* GetStateTrackingSlot(GLenum cap); // Allocation debugging variables mutable uint64_t mDataAllocGLCallCount = 0; diff --git a/dom/canvas/WebGLContextState.cpp b/dom/canvas/WebGLContextState.cpp index f81e590436..e057a0195b 100644 --- a/dom/canvas/WebGLContextState.cpp +++ b/dom/canvas/WebGLContextState.cpp @@ -27,27 +27,25 @@ void WebGLContext::SetEnabled(const GLenum cap, const Maybe<GLuint> i, const FuncScope funcScope(*this, "enable(i)/disable(i)"); if (IsContextLost()) return; - if (!ValidateCapabilityEnum(cap)) return; - - if (i) { - if (cap != LOCAL_GL_BLEND) { - ErrorInvalidEnumArg("cap", cap); - return; - } - - const auto limit = MaxValidDrawBuffers(); - if (*i >= limit) { - ErrorInvalidValue("`index` (%u) must be < %s (%u)", *i, - "MAX_DRAW_BUFFERS", limit); - return; - } + static const auto webgl1Map = webgl::MakeIsEnabledMap(false); + static const auto webgl2Map = webgl::MakeIsEnabledMap(true); + const auto* map = &webgl2Map; + if (!IsWebGL2()) { + map = &webgl1Map; + } + if (!MaybeFind(*map, cap)) { + MOZ_ASSERT(false, "Bad cap."); + return; } - const auto slot = GetStateTrackingSlot(cap, i ? *i : 0); - if (slot) { - *slot = enabled; - } else if (cap == LOCAL_GL_BLEND) { + if (cap == LOCAL_GL_BLEND) { if (i) { + const auto limit = MaxValidDrawBuffers(); + if (*i >= limit) { + ErrorInvalidValue("`index` (%u) must be < %s (%u)", *i, + "MAX_DRAW_BUFFERS", limit); + return; + } mBlendEnabled[*i] = enabled; } else { if (enabled) { @@ -56,6 +54,15 @@ void WebGLContext::SetEnabled(const GLenum cap, const Maybe<GLuint> i, mBlendEnabled.reset(); } } + } else { + if (i) { + MOZ_ASSERT(false, "i"); + return; + } + const auto slot = GetStateTrackingSlot(cap); + if (slot) { + *slot = enabled; + } } switch (cap) { @@ -431,39 +438,7 @@ Maybe<double> WebGLContext::GetParameter(const GLenum pname) { return Nothing(); } -bool WebGLContext::IsEnabled(GLenum cap) { - const FuncScope funcScope(*this, "isEnabled"); - if (IsContextLost()) return false; - - if (!ValidateCapabilityEnum(cap)) return false; - - const auto& slot = GetStateTrackingSlot(cap, 0); - if (slot) return *slot; - - return gl->fIsEnabled(cap); -} - -bool WebGLContext::ValidateCapabilityEnum(GLenum cap) { - switch (cap) { - case LOCAL_GL_BLEND: - case LOCAL_GL_CULL_FACE: - case LOCAL_GL_DEPTH_TEST: - case LOCAL_GL_DITHER: - case LOCAL_GL_POLYGON_OFFSET_FILL: - case LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE: - case LOCAL_GL_SAMPLE_COVERAGE: - case LOCAL_GL_SCISSOR_TEST: - case LOCAL_GL_STENCIL_TEST: - return true; - case LOCAL_GL_RASTERIZER_DISCARD: - return IsWebGL2(); - default: - ErrorInvalidEnumInfo("cap", cap); - return false; - } -} - -bool* WebGLContext::GetStateTrackingSlot(GLenum cap, GLuint i) { +bool* WebGLContext::GetStateTrackingSlot(GLenum cap) { switch (cap) { case LOCAL_GL_DEPTH_TEST: return &mDepthTestEnabled; diff --git a/dom/canvas/WebGLFramebuffer.cpp b/dom/canvas/WebGLFramebuffer.cpp index 108d2178cc..949177a217 100644 --- a/dom/canvas/WebGLFramebuffer.cpp +++ b/dom/canvas/WebGLFramebuffer.cpp @@ -352,10 +352,17 @@ Maybe<double> WebGLFBAttachPoint::GetParameter(WebGLContext* webgl, case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: - case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: isPNameValid = webgl->IsWebGL2(); break; + case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: + isPNameValid = (webgl->IsWebGL2() || + webgl->IsExtensionEnabled( + WebGLExtensionID::WEBGL_color_buffer_float) || + webgl->IsExtensionEnabled( + WebGLExtensionID::EXT_color_buffer_half_float)); + break; + case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: isPNameValid = (webgl->IsWebGL2() || webgl->IsExtensionEnabled(WebGLExtensionID::EXT_sRGB)); @@ -404,7 +411,14 @@ Maybe<double> WebGLFBAttachPoint::GetParameter(WebGLContext* webgl, break; case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: - MOZ_ASSERT(attachment != LOCAL_GL_DEPTH_STENCIL_ATTACHMENT); + if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) { + webgl->ErrorInvalidOperation( + "Querying" + " FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE" + " against DEPTH_STENCIL_ATTACHMENT is an" + " error."); + return Nothing(); + } if (format->unsizedFormat == webgl::UnsizedFormat::DEPTH_STENCIL) { MOZ_ASSERT(attachment == LOCAL_GL_DEPTH_ATTACHMENT || @@ -1222,17 +1236,6 @@ Maybe<double> WebGLFramebuffer::GetAttachmentParameter(GLenum attachEnum, auto attach = maybeAttach.value(); if (mContext->IsWebGL2() && attachEnum == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) { - // There are a couple special rules for this one. - - if (pname == LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE) { - mContext->ErrorInvalidOperation( - "Querying" - " FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE" - " against DEPTH_STENCIL_ATTACHMENT is an" - " error."); - return Nothing(); - } - if (mDepthAttachment.Renderbuffer() != mStencilAttachment.Renderbuffer() || mDepthAttachment.Texture() != mStencilAttachment.Texture()) { mContext->ErrorInvalidOperation( diff --git a/dom/canvas/WebGLIpdl.h b/dom/canvas/WebGLIpdl.h index 5a35c05909..45a5c5ad64 100644 --- a/dom/canvas/WebGLIpdl.h +++ b/dom/canvas/WebGLIpdl.h @@ -245,6 +245,45 @@ struct ParamTraits<mozilla::dom::PredefinedColorSpace> final mozilla::dom::PredefinedColorSpace> {}; // - +// ParamTraits_IsEnumCase + +/* +`IsEnumCase(T) -> bool` guarantees that we never have false negatives or false +positives due to adding or removing enum cases to enums, and forgetting to +update their serializations. Also, it allows enums to be non-continguous, unlike +ContiguousEnumSerializer. +*/ + +template <class T> +struct ParamTraits_IsEnumCase { + static bool Write(MessageWriter* const writer, const T& in) { + MOZ_ASSERT(IsEnumCase(in)); + const auto shadow = static_cast<std::underlying_type_t<T>>(in); + WriteParam(writer, shadow); + return true; + } + + static bool Read(MessageReader* const reader, T* const out) { + auto shadow = std::underlying_type_t<T>{}; + if (!ReadParam(reader, &shadow)) return false; + const auto e = mozilla::AsValidEnum<T>(shadow); + if (!e) return false; + *out = *e; + return true; + } +}; + +// - + +#define USE_IS_ENUM_CASE(T) \ + template <> \ + struct ParamTraits<T> : public ParamTraits_IsEnumCase<T> {}; + +USE_IS_ENUM_CASE(mozilla::webgl::OptionalRenderableFormatBits) + +#undef USE_IS_ENUM_CASE + +// - // ParamTraits_TiedFields template <class T> @@ -272,6 +311,10 @@ struct ParamTraits_TiedFields { } }; +template <class U, size_t N> +struct ParamTraits<mozilla::PaddingField<U, N>> final + : public ParamTraits_TiedFields<mozilla::PaddingField<U, N>> {}; + // - template <> @@ -609,35 +652,6 @@ struct ParamTraits<mozilla::avec3<U>> final { } }; -// - - -template <class TT> -struct ParamTraits_IsEnumCase { - using T = TT; - - static void Write(IPC::MessageWriter* const writer, const T& in) { - MOZ_RELEASE_ASSERT(IsEnumCase(in)); - WriteParam(writer, mozilla::UnderlyingValue(in)); - } - - static bool Read(IPC::MessageReader* const reader, T* const out) { - std::underlying_type_t<T> rawVal; - if (!ReadParam(reader, &rawVal)) return false; - *out = static_cast<T>(rawVal); - return IsEnumCase(*out); - } -}; - -// - - -#define USE_IS_ENUM_CASE(T) \ - template <> \ - struct ParamTraits<T> : public ParamTraits_IsEnumCase<T> {}; - -USE_IS_ENUM_CASE(mozilla::webgl::OptionalRenderableFormatBits) - -#undef USE_IS_ENUM_CASE - } // namespace IPC #endif diff --git a/dom/canvas/WebGLParent.cpp b/dom/canvas/WebGLParent.cpp index 44a0692b3f..e107d6cb50 100644 --- a/dom/canvas/WebGLParent.cpp +++ b/dom/canvas/WebGLParent.cpp @@ -462,15 +462,6 @@ IPCResult WebGLParent::RecvGetVertexAttrib(GLuint index, GLenum pname, return IPC_OK(); } -IPCResult WebGLParent::RecvIsEnabled(GLenum cap, bool* const ret) { - if (!mHost) { - return IPC_FAIL(this, "HostWebGLContext is not initialized."); - } - - *ret = mHost->IsEnabled(cap); - return IPC_OK(); -} - IPCResult WebGLParent::RecvOnMemoryPressure() { if (!mHost) { return IPC_FAIL(this, "HostWebGLContext is not initialized."); diff --git a/dom/canvas/WebGLParent.h b/dom/canvas/WebGLParent.h index 4cdc03e0ec..b3b4511e76 100644 --- a/dom/canvas/WebGLParent.h +++ b/dom/canvas/WebGLParent.h @@ -103,7 +103,6 @@ class WebGLParent : public PWebGLParent, public SupportsWeakPtr { IPCResult RecvGetUniform(ObjectId id, uint32_t loc, webgl::GetUniformData* ret); IPCResult RecvGetVertexAttrib(GLuint index, GLenum pname, Maybe<double>* ret); - IPCResult RecvIsEnabled(GLenum cap, bool* ret); IPCResult RecvOnMemoryPressure(); IPCResult RecvValidateProgram(ObjectId id, bool* ret); diff --git a/dom/canvas/WebGLSync.cpp b/dom/canvas/WebGLSync.cpp index e4b196ab04..6a8e9403f7 100644 --- a/dom/canvas/WebGLSync.cpp +++ b/dom/canvas/WebGLSync.cpp @@ -23,10 +23,39 @@ WebGLSync::~WebGLSync() { mContext->gl->fDeleteSync(mGLName); } -void WebGLSync::MarkSignaled() const { - if (mContext->mCompletedFenceId < mFenceId) { - mContext->mCompletedFenceId = mFenceId; +ClientWaitSyncResult WebGLSync::ClientWaitSync(const GLbitfield flags, + const GLuint64 timeout) { + if (!mContext) return ClientWaitSyncResult::WAIT_FAILED; + if (IsKnownComplete()) return ClientWaitSyncResult::ALREADY_SIGNALED; + + auto ret = ClientWaitSyncResult::WAIT_FAILED; + bool newlyComplete = false; + const auto status = static_cast<ClientWaitSyncResult>( + mContext->gl->fClientWaitSync(mGLName, 0, 0)); + switch (status) { + case ClientWaitSyncResult::TIMEOUT_EXPIRED: // Poll() -> false + case ClientWaitSyncResult::WAIT_FAILED: // Error + ret = status; + break; + case ClientWaitSyncResult::CONDITION_SATISFIED: // Should never happen, but + // tolerate it. + case ClientWaitSyncResult::ALREADY_SIGNALED: // Poll() -> true + newlyComplete = true; + ret = status; + break; + } + + if (newlyComplete) { + if (mContext->mCompletedFenceId < mFenceId) { + mContext->mCompletedFenceId = mFenceId; + } + MOZ_RELEASE_ASSERT(mOnCompleteTasks); + for (const auto& task : *mOnCompleteTasks) { + (*task)(); + } + mOnCompleteTasks = {}; } + return ret; } } // namespace mozilla diff --git a/dom/canvas/WebGLSync.h b/dom/canvas/WebGLSync.h index 22c77941e2..48ed2ee58f 100644 --- a/dom/canvas/WebGLSync.h +++ b/dom/canvas/WebGLSync.h @@ -11,9 +11,30 @@ namespace mozilla { namespace webgl { class AvailabilityRunnable; + +struct Task { + virtual ~Task() = default; + virtual void operator()() const = 0; +}; + +template <class F> +struct FnTask : public Task { + const F fn; + + explicit FnTask(F&& fn) : fn(std::move(fn)) {} + + virtual void operator()() const override { fn(); } +}; } // namespace webgl -class WebGLSync final : public WebGLContextBoundObject { +enum class ClientWaitSyncResult : GLenum { + WAIT_FAILED = LOCAL_GL_WAIT_FAILED, + TIMEOUT_EXPIRED = LOCAL_GL_TIMEOUT_EXPIRED, + CONDITION_SATISFIED = LOCAL_GL_CONDITION_SATISFIED, + ALREADY_SIGNALED = LOCAL_GL_ALREADY_SIGNALED, +}; + +class WebGLSync final : public WebGLContextBoundObject, public SupportsWeakPtr { friend class WebGL2Context; friend class webgl::AvailabilityRunnable; @@ -23,10 +44,22 @@ class WebGLSync final : public WebGLContextBoundObject { const uint64_t mFenceId; bool mCanBeAvailable = false; + std::optional<std::vector<std::unique_ptr<webgl::Task>>> mOnCompleteTasks = + std::vector<std::unique_ptr<webgl::Task>>{}; + public: WebGLSync(WebGLContext* webgl, GLenum condition, GLbitfield flags); - void MarkSignaled() const; + ClientWaitSyncResult ClientWaitSync(GLbitfield flags, GLuint64 timeout); + + template <class F> + void OnCompleteTaskAdd(F&& fn) { + MOZ_RELEASE_ASSERT(mOnCompleteTasks); + auto task = std::make_unique<webgl::FnTask<F>>(std::move(fn)); + mOnCompleteTasks->push_back(std::move(task)); + } + + bool IsKnownComplete() const { return !mOnCompleteTasks; } private: ~WebGLSync() override; diff --git a/dom/canvas/WebGLTypes.h b/dom/canvas/WebGLTypes.h index c268047930..f5f78e98cb 100644 --- a/dom/canvas/WebGLTypes.h +++ b/dom/canvas/WebGLTypes.h @@ -1224,6 +1224,15 @@ inline bool StartsWith(const std::string_view str, // - +template <class T> +Maybe<T> AsValidEnum(const std::underlying_type_t<T> raw_val) { + const auto raw_enum = T{raw_val}; // This is the risk we prevent! + if (!IsEnumCase(raw_enum)) return {}; + return Some(raw_enum); +} + +// - + namespace webgl { // In theory, this number can be unbounded based on the driver. However, no @@ -1302,6 +1311,50 @@ struct ReinterpretToSpan { } }; +// - + +inline std::string Join(Span<const std::string> ss, + const std::string_view& delim) { + if (!ss.size()) return ""; + auto ret = std::string(); + { + auto chars = delim.size() * (ss.size() - 1); + for (const auto& s : ss) { + chars += s.size(); + } + ret.reserve(chars); + } + + ret = ss[0]; + ss = ss.subspan(1); + for (const auto& s : ss) { + ret += delim; + ret += s; + } + return ret; +} + +inline std::string ToStringWithCommas(uint64_t v) { + if (!v) return "0"; + std::vector<std::string> chunks; + while (v) { + const auto chunk = v % 1000; + v /= 1000; + chunks.insert(chunks.begin(), std::to_string(chunk)); + } + return Join(chunks, ","); +} + +// - + +namespace webgl { + +std::unordered_map<GLenum, bool> MakeIsEnabledMap(bool webgl2); + +static constexpr uint32_t kMaxClientWaitSyncTimeoutNS = + 1000 * 1000 * 1000; // 1000ms in ns. + +} // namespace webgl } // namespace mozilla #endif diff --git a/dom/canvas/test/crossorigin/mochitest.toml b/dom/canvas/test/crossorigin/mochitest.toml index e45b2624cd..0b62b02eab 100644 --- a/dom/canvas/test/crossorigin/mochitest.toml +++ b/dom/canvas/test/crossorigin/mochitest.toml @@ -7,6 +7,10 @@ support-files = [ "image.png", "video.sjs", ] +# The video used in those tests crash the Android emulator's VP9 decoder. +prefs = [ + "media.android-media-codec.enabled=false", +] ["test_canvas2d_crossorigin.html"] skip-if = [ diff --git a/dom/canvas/test/mochitest.toml b/dom/canvas/test/mochitest.toml index 3e96fff26b..6ab48c09c6 100644 --- a/dom/canvas/test/mochitest.toml +++ b/dom/canvas/test/mochitest.toml @@ -36,7 +36,11 @@ support-files = [ "offscreencanvas_serviceworker_inner.html", "crossorigin/image.png", "crossorigin/video.sjs", - "../../media/test/320x240.ogv", + "../../media/test/320x240.webm", +] +# The video used in those tests crash the Android emulator's VP9 decoder. +prefs = [ + "media.android-media-codec.enabled=false", ] ["test_2d.clearRect.image.offscreen.html"] diff --git a/dom/canvas/test/test_imagebitmap.html b/dom/canvas/test/test_imagebitmap.html index 7a68db08df..3c7958242b 100644 --- a/dom/canvas/test/test_imagebitmap.html +++ b/dom/canvas/test/test_imagebitmap.html @@ -6,7 +6,7 @@ <body> <img src="image_anim-gr.gif" id="image" class="resource"> -<video width="320" height="240" src="http://example.com/tests/dom/canvas/test/crossorigin/video.sjs?name=tests/dom/canvas/test/320x240.ogv&type=video/ogg&cors=anonymous" id="video" crossOrigin="anonymous" autoplay></video> +<video width="320" height="240" src="http://example.com/tests/dom/canvas/test/crossorigin/video.sjs?name=tests/dom/canvas/test/320x240.webm&type=video/webm&cors=anonymous" id="video" crossOrigin="anonymous" autoplay></video> <canvas id="c1" class="output" width="128" height="128"></canvas> <canvas id="c2" width="128" height="128"></canvas> @@ -226,7 +226,7 @@ function testSecurityErrors() { reject(); } - uncleanVideo.src = "http://example.com/tests/dom/canvas/test/crossorigin/video.sjs?name=tests/dom/canvas/test/320x240.ogv&type=video/ogg"; + uncleanVideo.src = "http://example.com/tests/dom/canvas/test/crossorigin/video.sjs?name=tests/dom/canvas/test/320x240.webm&type=video/webm"; uncleanVideo.play(); }); } diff --git a/dom/canvas/test/test_imagebitmap_cropping.html b/dom/canvas/test/test_imagebitmap_cropping.html index 56ccbf62e2..bb0f06f423 100644 --- a/dom/canvas/test/test_imagebitmap_cropping.html +++ b/dom/canvas/test/test_imagebitmap_cropping.html @@ -33,7 +33,7 @@ function isPixel(ctx, x, y, c, d) { } // -// The pattern of the 320x240.ogv video. +// The pattern of the 320x240.webm video. // .------------------------------------------------. // | 255 | 255 | 0 | 0 | 255 | 255 | 0 | // | 255 | 255 | 255 | 255 | 0 | 0 | 0 | @@ -135,7 +135,7 @@ var gJPEGBlob; function prepareSources() { gVideo = document.createElement("video"); - gVideo.src = "http://example.com/tests/dom/canvas/test/crossorigin/video.sjs?name=tests/dom/canvas/test/320x240.ogv&type=video/ogg&cors=anonymous"; + gVideo.src = "http://example.com/tests/dom/canvas/test/crossorigin/video.sjs?name=tests/dom/canvas/test/320x240.webm&type=video/webm&cors=anonymous"; gVideo.crossOrigin = "anonymous"; gVideo.autoplay = "true" diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/canvas/00_test_list.txt b/dom/canvas/test/webgl-conf/checkout/conformance/canvas/00_test_list.txt index 558163de17..c0cdadcd03 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance/canvas/00_test_list.txt +++ b/dom/canvas/test/webgl-conf/checkout/conformance/canvas/00_test_list.txt @@ -4,6 +4,8 @@ canvas-test.html canvas-zero-size.html drawingbuffer-static-canvas-test.html --min-version 1.0.2 drawingbuffer-hd-dpi-test.html +# Uncomment once fully passing on WebGL 1 +# --min-version 1.0.4 --max-version 1.9.9 drawingbuffer-storage-test.html drawingbuffer-test.html --min-version 1.0.3 draw-webgl-to-canvas-test.html --min-version 1.0.3 draw-static-webgl-to-multiple-canvas-test.html diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/canvas/drawingbuffer-storage-test.html b/dom/canvas/test/webgl-conf/checkout/conformance/canvas/drawingbuffer-storage-test.html new file mode 100644 index 0000000000..285cd047d1 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance/canvas/drawingbuffer-storage-test.html @@ -0,0 +1,27 @@ +<!-- +Copyright (c) 2023 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL drawingBufferStorage Conformance Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +<script src="../../js/tests/drawingbuffer-storage-test.js"></script> +</head> +<body> +<div id="description"></div> +<div id="console"></div> +<script> +runTest(1); + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/00_test_list.txt b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/00_test_list.txt index 9a72b67ef0..e121e90676 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/00_test_list.txt +++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/00_test_list.txt @@ -1,15 +1,19 @@ --min-version 1.0.3 --max-version 1.9.9 angle-instanced-arrays.html --min-version 1.0.3 --max-version 1.9.9 angle-instanced-arrays-out-of-bounds.html --min-version 1.0.3 --max-version 1.9.9 ext-blend-minmax.html +--min-version 1.0.4 ext-clip-control.html --min-version 1.0.4 ext-color-buffer-half-float.html +--min-version 1.0.4 ext-depth-clamp.html --min-version 1.0.4 ext-float-blend.html --min-version 1.0.4 ext-texture-compression-bptc.html --min-version 1.0.4 ext-texture-compression-rgtc.html --min-version 1.0.4 ext-disjoint-timer-query.html --min-version 1.0.3 --max-version 1.9.9 ext-frag-depth.html +--min-version 1.0.4 ext-polygon-offset-clamp.html --min-version 1.0.3 --max-version 1.9.9 ext-shader-texture-lod.html --min-version 1.0.3 --max-version 1.9.9 ext-sRGB.html --min-version 1.0.2 ext-texture-filter-anisotropic.html +--min-version 1.0.4 ext-texture-mirror-clamp-to-edge.html --min-version 1.0.2 get-extension.html --min-version 1.0.4 khr-parallel-shader-compile.html --max-version 1.9.9 oes-standard-derivatives.html @@ -29,6 +33,7 @@ --min-version 1.0.3 --max-version 1.9.9 oes-texture-half-float-with-video.html --min-version 1.0.2 --max-version 1.9.9 oes-element-index-uint.html --min-version 1.0.4 --max-version 1.9.9 oes-fbo-render-mipmap.html +--min-version 1.0.4 --max-version 1.9.9 webgl-blend-func-extended.html webgl-debug-renderer-info.html webgl-debug-shaders.html --min-version 1.0.4 webgl-compressed-texture-astc.html @@ -44,3 +49,4 @@ webgl-debug-shaders.html --min-version 1.0.4 --max-version 1.9.9 webgl-draw-buffers-framebuffer-unsupported.html --min-version 1.0.4 --max-version 1.9.9 webgl-draw-buffers-max-draw-buffers.html --min-version 1.0.4 webgl-multi-draw.html +--min-version 1.0.4 webgl-polygon-mode.html diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-clip-control.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-clip-control.html new file mode 100644 index 0000000000..f5c557c839 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-clip-control.html @@ -0,0 +1,185 @@ +<!-- +Copyright (c) 2023 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL EXT_clip_control Conformance Tests</title> +<LINK rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<canvas width="32" height="32" id="c"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description("This test verifies the functionality of the EXT_clip_control extension, if it is available."); + +debug(""); + +var wtu = WebGLTestUtils; +var gl = wtu.create3DContext("c"); +var ext; +const w = gl.drawingBufferWidth; +const h = gl.drawingBufferHeight; + +function runTestNoExtension() { + debug(""); + debug("Check the parameters without the extension"); + shouldBeNull("gl.getParameter(0x935C /* CLIP_ORIGIN_EXT */)"); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + shouldBeNull("gl.getParameter(0x935D /* CLIP_DEPTH_MODE_EXT */)"); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); +} + +function checkEnums() { + debug(""); + debug("Check enums"); + shouldBe("ext.LOWER_LEFT_EXT", "0x8CA1"); + shouldBe("ext.UPPER_LEFT_EXT", "0x8CA2"); + + shouldBe("ext.NEGATIVE_ONE_TO_ONE_EXT", "0x935E"); + shouldBe("ext.ZERO_TO_ONE_EXT", "0x935F"); + + shouldBe("ext.CLIP_ORIGIN_EXT", "0x935C"); + shouldBe("ext.CLIP_DEPTH_MODE_EXT", "0x935D"); +} + +function checkQueries() { + debug(""); + debug("Check default state"); + shouldBe('gl.getParameter(ext.CLIP_ORIGIN_EXT)', 'ext.LOWER_LEFT_EXT'); + shouldBe('gl.getParameter(ext.CLIP_DEPTH_MODE_EXT)', 'ext.NEGATIVE_ONE_TO_ONE_EXT'); + debug(""); + debug("Check state updates using the new function"); + ext.clipControlEXT(ext.UPPER_LEFT_EXT, ext.ZERO_TO_ONE_EXT); + shouldBe('gl.getParameter(ext.CLIP_ORIGIN_EXT)', 'ext.UPPER_LEFT_EXT'); + shouldBe('gl.getParameter(ext.CLIP_DEPTH_MODE_EXT)', 'ext.ZERO_TO_ONE_EXT'); + ext.clipControlEXT(ext.LOWER_LEFT_EXT, ext.ZERO_TO_ONE_EXT); + shouldBe('gl.getParameter(ext.CLIP_ORIGIN_EXT)', 'ext.LOWER_LEFT_EXT'); + shouldBe('gl.getParameter(ext.CLIP_DEPTH_MODE_EXT)', 'ext.ZERO_TO_ONE_EXT'); + ext.clipControlEXT(ext.UPPER_LEFT_EXT, ext.NEGATIVE_ONE_TO_ONE_EXT); + shouldBe('gl.getParameter(ext.CLIP_ORIGIN_EXT)', 'ext.UPPER_LEFT_EXT'); + shouldBe('gl.getParameter(ext.CLIP_DEPTH_MODE_EXT)', 'ext.NEGATIVE_ONE_TO_ONE_EXT'); + ext.clipControlEXT(ext.LOWER_LEFT_EXT, ext.NEGATIVE_ONE_TO_ONE_EXT); + shouldBe('gl.getParameter(ext.CLIP_ORIGIN_EXT)', 'ext.LOWER_LEFT_EXT'); + shouldBe('gl.getParameter(ext.CLIP_DEPTH_MODE_EXT)', 'ext.NEGATIVE_ONE_TO_ONE_EXT'); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); +} + +function checkDepthMode() { + debug(""); + debug("Check depth mode toggling"); + + gl.enable(gl.DEPTH_TEST); + gl.clear(gl.DEPTH_BUFFER_BIT); + + const program = wtu.setupProgram(gl, [wtu.simpleVertexShader, + wtu.simpleColorFragmentShader]); + gl.useProgram(program); + const colorLoc = gl.getUniformLocation(program, "u_color"); + wtu.setupUnitQuad(gl); + + // Draw red at 0 with the default depth mode + gl.uniform4f(colorLoc, 1, 0, 0, 1); + ext.clipControlEXT(ext.LOWER_LEFT_EXT, ext.NEGATIVE_ONE_TO_ONE_EXT); + wtu.drawUnitQuad(gl); + wtu.checkCanvasRect(gl, 0, 0, w, h, [255, 0, 0, 255]); + + // Draw green at 0, depth test must fail + gl.uniform4f(colorLoc, 0, 1, 0, 1); + wtu.drawUnitQuad(gl); + wtu.checkCanvasRect(gl, 0, 0, w, h, [255, 0, 0, 255]); + + // Draw green at 0 after switching the depth mode + ext.clipControlEXT(ext.LOWER_LEFT_EXT, ext.ZERO_TO_ONE_EXT); + wtu.drawUnitQuad(gl); + wtu.checkCanvasRect(gl, 0, 0, w, h, [0, 255, 0, 255]); + + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); +} + +function checkClipOrigin() { + debug(""); + debug("Check clip origin toggling"); + + gl.disable(gl.DEPTH_TEST); + + const vertexShader = ` + attribute vec4 vPosition; + varying float y; + void main() { + gl_Position = vPosition; + y = vPosition.y; + }`; + const fragmentShader = ` + precision mediump float; + varying float y; + void main() { + if (y > 0.0) { + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + } else { + gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0); + } + }`; + + const program = wtu.setupProgram(gl, [vertexShader, fragmentShader]); + gl.useProgram(program); + + wtu.setupUnitQuad(gl); + + ext.clipControlEXT(ext.LOWER_LEFT_EXT, ext.NEGATIVE_ONE_TO_ONE_EXT); + wtu.drawUnitQuad(gl); + wtu.checkCanvasRect(gl, 0, 0, w, h / 2 - 2, [0, 255, 0, 255]); + wtu.checkCanvasRect(gl, 0, h / 2 + 2, w, h / 2 - 2, [255, 0, 0, 255]); + + ext.clipControlEXT(ext.UPPER_LEFT_EXT, ext.NEGATIVE_ONE_TO_ONE_EXT); + wtu.drawUnitQuad(gl); + wtu.checkCanvasRect(gl, 0, 0, w, h / 2 - 2, [255, 0, 0, 255]); + wtu.checkCanvasRect(gl, 0, h / 2 + 2, w, h / 2 - 2, [0, 255, 0, 255]); + + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); +} + +function runTestExtension() { + checkEnums(); + checkQueries(); + checkDepthMode(); + checkClipOrigin(); +} + +function runTest() { + if (!gl) { + testFailed("WebGL context does not exist"); + return; + } + testPassed("WebGL context exists"); + + runTestNoExtension(); + + ext = gl.getExtension("EXT_clip_control"); + + wtu.runExtensionSupportedTest(gl, "EXT_clip_control", ext !== null); + + if (ext !== null) { + runTestExtension(); + } else { + testPassed("No EXT_clip_control support -- this is legal"); + } +} + +runTest(); + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-depth-clamp.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-depth-clamp.html new file mode 100644 index 0000000000..6082c9880c --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-depth-clamp.html @@ -0,0 +1,168 @@ +<!-- +Copyright (c) 2023 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL EXT_depth_clamp Conformance Tests</title> +<LINK rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<canvas width="32" height="32" id="c"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description("This test verifies the functionality of the EXT_depth_clamp extension, if it is available."); + +debug(""); + +var wtu = WebGLTestUtils; +var gl = wtu.create3DContext("c"); +var ext; +const w = gl.drawingBufferWidth; +const h = gl.drawingBufferHeight; + +function runTestNoExtension() { + debug(""); + debug("Check the parameter without the extension"); + shouldBeNull("gl.getParameter(0x864F /* DEPTH_CLAMP_EXT */)"); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + debug("Check the cap without the extension"); + gl.disable(0x864F /* DEPTH_CLAMP_EXT */); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "cap unknown without enabling the extension"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + gl.enable(0x864F /* DEPTH_CLAMP_EXT */); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "cap unknown without enabling the extension"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + shouldBeFalse("gl.isEnabled(0x864F /* DEPTH_CLAMP_EXT */)"); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "cap unknown without enabling the extension"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); +} + +function checkEnums() { + debug(""); + debug("Check enums"); + shouldBe("ext.DEPTH_CLAMP_EXT", "0x864F"); +} + +function checkQueries() { + debug(""); + debug("Check default state"); + shouldBeFalse('gl.isEnabled(ext.DEPTH_CLAMP_EXT)'); + shouldBeFalse('gl.getParameter(ext.DEPTH_CLAMP_EXT)'); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + debug(""); + debug("Check state update using the new capability"); + gl.enable(ext.DEPTH_CLAMP_EXT); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + shouldBeTrue('gl.isEnabled(ext.DEPTH_CLAMP_EXT)'); + shouldBeTrue('gl.getParameter(ext.DEPTH_CLAMP_EXT)'); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + gl.disable(ext.DEPTH_CLAMP_EXT); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + shouldBeFalse('gl.isEnabled(ext.DEPTH_CLAMP_EXT)'); + shouldBeFalse('gl.getParameter(ext.DEPTH_CLAMP_EXT)'); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); +} + +function checkClamping() { + debug(""); + debug("Check depth clamp operation"); + + // Draw a red quad located beyond the clipping volume. + // When depth clamping is enabled, it must be drawn. + const vertexShader = ` + attribute vec2 vPosition; + uniform float u_depth; + void main() { + gl_Position = vec4(vPosition, u_depth, 1.0); + }`; + const program = wtu.setupProgram(gl, [vertexShader, + wtu.simpleColorFragmentShader]); + gl.useProgram(program); + const colorLoc = gl.getUniformLocation(program, "u_color"); + const depthLoc = gl.getUniformLocation(program, "u_depth"); + + wtu.setupUnitQuad(gl); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + // Red beyond the far plane + gl.uniform4f(colorLoc, 1, 0, 0, 1); + gl.uniform1f(depthLoc, +2); + + // Clipped + wtu.clearAndDrawUnitQuad(gl); + wtu.checkCanvasRect(gl, 0, 0, w, h, [255, 255, 255, 255]); + + // Enable depth clamping, disable depth clipping + gl.enable(ext.DEPTH_CLAMP_EXT); + + // Not clipped + wtu.clearAndDrawUnitQuad(gl); + wtu.checkCanvasRect(gl, 0, 0, w, h, [255, 0, 0, 255]); + + // Green beyond the near plane + gl.uniform4f(colorLoc, 0, 1, 0, 1); + gl.uniform1f(depthLoc, -2); + + // Not clipped + wtu.clearAndDrawUnitQuad(gl); + wtu.checkCanvasRect(gl, 0, 0, w, h, [0, 255, 0, 255]); + + // Blue beyond the near plane with clamping disabled + gl.disable(ext.DEPTH_CLAMP_EXT); + gl.uniform4f(colorLoc, 0, 0, 1, 1); + + // Clipped + wtu.clearAndDrawUnitQuad(gl); + wtu.checkCanvasRect(gl, 0, 0, w, h, [255, 255, 255, 255]); + + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); +} + +function runTestExtension() { + checkEnums(); + checkQueries(); + checkClamping(); +} + +function runTest() { + if (!gl) { + testFailed("WebGL context does not exist"); + return; + } + testPassed("WebGL context exists"); + + runTestNoExtension(); + + ext = gl.getExtension("EXT_depth_clamp"); + + wtu.runExtensionSupportedTest(gl, "EXT_depth_clamp", ext !== null); + + if (ext !== null) { + runTestExtension(); + } else { + testPassed("No EXT_depth_clamp support -- this is legal"); + } +} + +runTest(); + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-disjoint-timer-query.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-disjoint-timer-query.html index 1fc29cc445..7965987c64 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-disjoint-timer-query.html +++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-disjoint-timer-query.html @@ -25,7 +25,9 @@ description("This test verifies the functionality of the EXT_disjoint_timer_quer var wtu = WebGLTestUtils; var canvas = document.getElementById("canvas"); var gl = wtu.create3DContext(canvas); +var gl2 = null; var ext = null; +var ext2 = null; var query = null; var query2 = null; var elapsed_query = null; @@ -61,6 +63,8 @@ if (!gl) { runTimeStampTest(); } verifyQueryResultsNotAvailable(); + verifyDeleteQueryBehavior(); + verifyDeleteQueryErrorBehavior(); window.requestAnimationFrame(checkQueryResults); } @@ -245,6 +249,61 @@ function verifyQueryResultsNotAvailable() { testPassed("Queries' results didn't become available in a spin loop"); } +function verifyDeleteQueryBehavior() { + debug(""); + debug("Testing deleting an active query should end it."); + + // Use a new context for this test + gl2 = wtu.create3DContext(null, null, 1); + if (!gl2) return; + ext2 = gl2.getExtension("EXT_disjoint_timer_query"); + if (!ext2) return; + + query = ext2.createQueryEXT(); + ext2.beginQueryEXT(ext2.TIME_ELAPSED_EXT, query); + wtu.glErrorShouldBe(gl2, gl2.NONE, "The query began successfully"); + ext2.deleteQueryEXT(query); + wtu.glErrorShouldBe(gl2, gl2.NONE, "Deletion of the active query succeeds"); + shouldBeNull("ext2.getQueryEXT(ext2.TIME_ELAPSED_EXT, ext2.CURRENT_QUERY_EXT)"); + shouldBeFalse("ext2.isQueryEXT(query)"); + query = ext2.createQueryEXT(); + ext2.beginQueryEXT(ext2.TIME_ELAPSED_EXT, query); + wtu.glErrorShouldBe(gl2, gl2.NONE, "Beginning a new query succeeds"); + ext2.endQueryEXT(ext2.TIME_ELAPSED_EXT); + ext2.deleteQueryEXT(query); + wtu.glErrorShouldBe(gl2, gl2.NONE); + query = null; + ext2 = null; + gl2 = null; +} + +function verifyDeleteQueryErrorBehavior() { + debug(""); + debug("Testing deleting a query created by another context."); + + // Use new contexts for this test + gl2 = wtu.create3DContext(null, null, 1); + var gl3 = wtu.create3DContext(null, null, 1); + if (!gl2 || !gl3) return; + ext2 = gl2.getExtension("EXT_disjoint_timer_query"); + var ext3 = gl3.getExtension("EXT_disjoint_timer_query"); + if (!ext2 || !ext3) return; + + query = ext2.createQueryEXT(); + ext2.beginQueryEXT(ext2.TIME_ELAPSED_EXT, query); + ext3.deleteQueryEXT(query); + wtu.glErrorShouldBe(gl3, gl3.INVALID_OPERATION); + shouldBeTrue("ext2.isQueryEXT(query)"); + shouldBe("ext2.getQueryEXT(ext2.TIME_ELAPSED_EXT, ext2.CURRENT_QUERY_EXT)", "query"); + ext2.endQueryEXT(ext2.TIME_ELAPSED_EXT); + ext2.deleteQueryEXT(query); + wtu.glErrorShouldBe(gl2, gl2.NONE); + query = null; + ext2 = null; + gl2 = null; + gl3 = null; +} + function checkQueryResults() { if (availability_retry > 0) { // Make a reasonable attempt to wait for the queries' results to become available. diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-polygon-offset-clamp.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-polygon-offset-clamp.html new file mode 100644 index 0000000000..ce14e96fc7 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-polygon-offset-clamp.html @@ -0,0 +1,172 @@ +<!-- +Copyright (c) 2023 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL EXT_polygon_offset_clamp Conformance Tests</title> +<LINK rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<canvas width="32" height="32" id="c"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description("This test verifies the functionality of the EXT_polygon_offset_clamp extension, if it is available."); + +debug(""); + +var wtu = WebGLTestUtils; +var gl = wtu.create3DContext(); +var ext; +const w = gl.drawingBufferWidth; +const h = gl.drawingBufferHeight; + +function runTestNoExtension() { + debug(""); + debug("Check the parameter without the extension"); + shouldBeNull("gl.getParameter(0x8E1B /* POLYGON_OFFSET_CLAMP_EXT */)"); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); +} + +function checkEnums() { + debug(""); + debug("Check enums"); + shouldBe("ext.POLYGON_OFFSET_CLAMP_EXT", "0x8E1B"); +} + +function checkQueries() { + debug(""); + debug("Check default state"); + shouldBe('gl.getParameter(gl.POLYGON_OFFSET_FACTOR)', '0.0'); + shouldBe('gl.getParameter(gl.POLYGON_OFFSET_UNITS)', '0.0'); + shouldBe('gl.getParameter(ext.POLYGON_OFFSET_CLAMP_EXT)', '0.0'); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + debug(""); + debug("Check state update using the new function"); + ext.polygonOffsetClampEXT(1.0, 2.0, 3.0); + shouldBe('gl.getParameter(gl.POLYGON_OFFSET_FACTOR)', '1.0'); + shouldBe('gl.getParameter(gl.POLYGON_OFFSET_UNITS)', '2.0'); + shouldBe('gl.getParameter(ext.POLYGON_OFFSET_CLAMP_EXT)', '3.0'); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + debug(""); + debug("Check that the unextended function resets the clamp value to zero"); + gl.polygonOffset(4.0, 5.0); + shouldBe('gl.getParameter(gl.POLYGON_OFFSET_FACTOR)', '4.0'); + shouldBe('gl.getParameter(gl.POLYGON_OFFSET_UNITS)', '5.0'); + shouldBe('gl.getParameter(ext.POLYGON_OFFSET_CLAMP_EXT)', '0.0'); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); +} + +function checkClamping() { + debug(""); + debug("Check polygon offset clamp operation"); + + // The shader creates a depth slope from left (0) to right (1). + // + // This test issues two draw calls: + // + // Draw 2 (green): factor width, offset 0, clamp 0.5, depth test: Greater + // ^ | __________________ + // | | __/ __/ + // | V __/ __/ <--- Draw 1 (red): factor width, offset 0, clamp 0.25 + // | __/ __/ + // | __/ __/ + // |/ __/ + // | __/ + // | __/ + // |/ + // | + // | + // +-------------------------------> + // + // Result: <---------green--------><--red--> + + + const program = wtu.setupProgram(gl, [wtu.simpleVertexShader, + wtu.simpleColorFragmentShader]); + gl.useProgram(program); + const colorLoc = gl.getUniformLocation(program, "u_color"); + + const buf = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, buf); + gl.bufferData( + gl.ARRAY_BUFFER, + new Float32Array([-1, -1, -1, 1, -1, 1, -1, 1, -1, 1, 1, 1]), + gl.STATIC_DRAW); + gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(0); + + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + gl.enable(gl.POLYGON_OFFSET_FILL); + gl.clearColor(0, 0, 0, 1); + gl.clearDepth(0); + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + gl.enable(gl.DEPTH_TEST); + + gl.depthFunc(gl.ALWAYS); + gl.uniform4f(colorLoc, 1, 0, 0, 1); + ext.polygonOffsetClampEXT(w, 0, 0.25); + gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); + + gl.depthFunc(gl.GREATER); + gl.uniform4f(colorLoc, 0, 1, 0, 1); + ext.polygonOffsetClampEXT(w, 0, 0.5); + gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); + + wtu.checkCanvasRect( + gl, + 0, 0, 3 * w / 4 - 1, h, + [0, 255, 0, 255], "should be green"); + + wtu.checkCanvasRect( + gl, + 3 * w / 4 + 1, 0, w / 4 - 1, h, + [255, 0, 0, 255], "should be red"); + + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); +} + +function runTestExtension() { + checkEnums(); + checkQueries(); + checkClamping(); +} + +function runTest() { + if (!gl) { + testFailed("WebGL context does not exist"); + return; + } + testPassed("WebGL context exists"); + + runTestNoExtension(); + + ext = gl.getExtension("EXT_polygon_offset_clamp"); + + wtu.runExtensionSupportedTest(gl, "EXT_polygon_offset_clamp", ext !== null); + + if (ext !== null) { + runTestExtension(); + } else { + testPassed("No EXT_polygon_offset_clamp support -- this is legal"); + } +} + +runTest(); + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-sRGB.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-sRGB.html index 7e8353f7f2..a997bdb4ab 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-sRGB.html +++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-sRGB.html @@ -222,6 +222,40 @@ if (!gl) { runFormatTest(textureFormatFixture, false); runFormatTest(renderbufferFormatFixture, false); + { + var fbo = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + + debug("Checking getFramebufferAttachmentParameter with a renderbuffer"); + { + var rbo = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rbo); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGB565, 1, 1); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo); + wtu.glErrorShouldBe(gl, gl.NO_ERROR); + shouldBeNull('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, 0x8210 /* FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT */)'); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM); + gl.bindRenderbuffer(gl.RENDERBUFFER, null); + gl.deleteRenderbuffer(rbo); + } + + debug("Checking getFramebufferAttachmentParameter with a texture"); + { + var tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0); + wtu.glErrorShouldBe(gl, gl.NO_ERROR); + shouldBeNull('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, 0x8210 /* FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT */)'); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM); + gl.bindTexture(gl.TEXTURE_2D, null); + gl.deleteTexture(tex); + } + + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + gl.deleteFramebuffer(fbo); + } + debug(""); debug("Checking sRGB texture support"); diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-texture-compression-rgtc.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-texture-compression-rgtc.html index 70dcf9ba7b..d9c34af25f 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-texture-compression-rgtc.html +++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-texture-compression-rgtc.html @@ -120,16 +120,16 @@ function runTestExtension() { gl.bindTexture(gl.TEXTURE_2D, tex); gl.texImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_RED_RGTC1_EXT, 4, 4, 0, gl.RED, gl.UNSIGNED_BYTE, null); - wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "COMPRESSED_RED_RGTC1_EXT fails with texImage2D"); + wtu.glErrorShouldBe(gl, [gl.INVALID_VALUE, gl.INVALID_OPERATION], "COMPRESSED_RED_RGTC1_EXT fails with texImage2D"); gl.texImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_SIGNED_RED_RGTC1_EXT, 4, 4, 0, gl.RED, gl.BYTE, null); - wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "COMPRESSED_SIGNED_RED_RGTC1_EXT fails with texImage2D"); + wtu.glErrorShouldBe(gl, [gl.INVALID_VALUE, gl.INVALID_OPERATION], "COMPRESSED_SIGNED_RED_RGTC1_EXT fails with texImage2D"); gl.texImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_RED_GREEN_RGTC2_EXT, 4, 4, 0, gl.RG, gl.UNSIGNED_BYTE, null); - wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "COMPRESSED_RED_GREEN_RGTC2_EXT fails with texImage2D"); + wtu.glErrorShouldBe(gl, [gl.INVALID_VALUE, gl.INVALID_OPERATION], "COMPRESSED_RED_GREEN_RGTC2_EXT fails with texImage2D"); gl.texImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT, 4, 4, 0, gl.RG, gl.BYTE, null); - wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT fails with texImage2D"); + wtu.glErrorShouldBe(gl, [gl.INVALID_VALUE, gl.INVALID_OPERATION], "COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT fails with texImage2D"); gl.deleteTexture(tex); } diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-texture-mirror-clamp-to-edge.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-texture-mirror-clamp-to-edge.html new file mode 100644 index 0000000000..4e2f980b4b --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/ext-texture-mirror-clamp-to-edge.html @@ -0,0 +1,217 @@ +<!-- +Copyright (c) 2023 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL EXT_texture_mirror_clamp_to_edge Conformance Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<canvas width="32" height="32" id="c"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description("This test verifies the functionality of the EXT_texture_mirror_clamp_to_edge extension, if it is available."); + +debug(""); + +var wtu = WebGLTestUtils; +var gl = wtu.create3DContext("c"); +const w = gl.drawingBufferWidth; +const h = gl.drawingBufferHeight; +var ext; +var sampler; + +const pnames = ['TEXTURE_WRAP_S', 'TEXTURE_WRAP_T']; +if (gl.TEXTURE_WRAP_R) { + pnames.push('TEXTURE_WRAP_R'); +} + +function runTestNoExtension() { + debug(""); + debug("Check the texture parameter without the extension"); + + const tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + + const MIRROR_CLAMP_TO_EDGE_EXT = 0x8743; + + for (const pname of pnames) { + gl.texParameteri(gl.TEXTURE_2D, gl[pname], MIRROR_CLAMP_TO_EDGE_EXT); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `value unknown for ${pname} via texParameteri without enabling the extension`); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no more errors"); + gl.texParameterf(gl.TEXTURE_2D, gl[pname], MIRROR_CLAMP_TO_EDGE_EXT); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `value unknown for ${pname} via texParameterf without enabling the extension`); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no more errors"); + } + + if (!gl.createSampler) return; + + const sampler = gl.createSampler(); + for (const pname of pnames) { + gl.samplerParameteri(sampler, gl[pname], MIRROR_CLAMP_TO_EDGE_EXT); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `value unknown for ${pname} via samplerParameteri without enabling the extension`); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no more errors"); + gl.samplerParameterf(sampler, gl[pname], MIRROR_CLAMP_TO_EDGE_EXT); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `value unknown for ${pname} via samplerParameterf without enabling the extension`); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no more errors"); + } +} + +function checkEnums() { + debug(""); + debug("Check enums"); + shouldBe("ext.MIRROR_CLAMP_TO_EDGE_EXT", "0x8743"); +} + +function checkQueries() { + debug(""); + debug("Check texture and sampler state updates"); + + const tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + + for (const pname of pnames) { + gl.texParameteri(gl.TEXTURE_2D, gl[pname], ext.MIRROR_CLAMP_TO_EDGE_EXT); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from texParameteri"); + shouldBe(`gl.getTexParameter(gl.TEXTURE_2D, gl.${pname})`, "ext.MIRROR_CLAMP_TO_EDGE_EXT"); + gl.texParameteri(gl.TEXTURE_2D, gl[pname], gl.REPEAT); + + gl.texParameterf(gl.TEXTURE_2D, gl[pname], ext.MIRROR_CLAMP_TO_EDGE_EXT); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from texParameterf"); + shouldBe(`gl.getTexParameter(gl.TEXTURE_2D, gl.${pname})`, "ext.MIRROR_CLAMP_TO_EDGE_EXT"); + gl.texParameterf(gl.TEXTURE_2D, gl[pname], gl.REPEAT); + } + + if (!gl.createSampler) return; + + sampler = gl.createSampler(); + for (const pname of pnames) { + gl.samplerParameteri(sampler, gl[pname], ext.MIRROR_CLAMP_TO_EDGE_EXT); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from samplerParameteri"); + shouldBe(`gl.getSamplerParameter(sampler, gl.${pname})`, "ext.MIRROR_CLAMP_TO_EDGE_EXT"); + gl.samplerParameteri(sampler, gl[pname], gl.REPEAT); + + gl.samplerParameterf(sampler, gl[pname], ext.MIRROR_CLAMP_TO_EDGE_EXT); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from samplerParameterf"); + shouldBe(`gl.getSamplerParameter(sampler, gl.${pname})`, "ext.MIRROR_CLAMP_TO_EDGE_EXT"); + gl.samplerParameterf(sampler, gl[pname], gl.REPEAT); + } +} + +function checkSampling() { + debug(""); + debug(`Check texture sampling with mirror-clamp-to-edge mode`); + + wtu.setupUnitQuad(gl); + const vs = `precision highp float; + attribute vec4 vPosition; + varying vec2 texCoord; + void main() { + gl_Position = vec4(vPosition.xy, 0.0, 1.0); + texCoord = vPosition.xy * 2.0; + }`; + const program = wtu.setupProgram(gl, [vs, wtu.simpleTextureFragmentShader]); + gl.useProgram(program); + + const black = [ 0, 0, 0, 255]; + const red = [255, 0, 0, 255]; + const green = [ 0, 255, 0, 255]; + const blue = [ 0, 0, 255, 255]; + const data = new Uint8Array([...black, ...red, ...green, ...blue]); + + function checkPixels() { + function checkPixel(x, y, color) { + const screen = (s, t) => s * (t * 0.5 + 0.5); + wtu.checkCanvasRect(gl, screen(w, x), screen(h, y), 1, 1, color, + `(${x.toFixed(3)}, ${y.toFixed(3)}): ${color} `); + } + for (const signX of [+1, -1]) { + for (const signY of [+1, -1]) { + // This function expects screen-space coordinates + // normalized to [-1, +1]. The region from [0, 0] + // to [+1, +1] behaves like regular clamp-to-edge. + // Other three quadrants should be mirrored. + checkPixel(signX * 0.125, signY * 0.125, black); + checkPixel(signX * 0.375, signY * 0.125, red); + checkPixel(signX * 0.750, signY * 0.125, red); + checkPixel(signX * 0.125, signY * 0.375, green); + checkPixel(signX * 0.125, signY * 0.750, green); + checkPixel(signX * 0.375, signY * 0.375, blue); + checkPixel(signX * 0.750, signY * 0.375, blue); + checkPixel(signX * 0.375, signY * 0.750, blue); + checkPixel(signX * 0.750, signY * 0.750, blue); + } + } + } + + const tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2, 2, 0, gl.RGBA, gl.UNSIGNED_BYTE, data); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, ext.MIRROR_CLAMP_TO_EDGE_EXT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, ext.MIRROR_CLAMP_TO_EDGE_EXT); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texture created and configured"); + + wtu.drawUnitQuad(gl); + checkPixels(); + + if (!gl.createSampler) return; + + debug(""); + debug(`Check texture sampling with mirror-clamp-to-edge mode using a sampler object`); + + const texWithSampler = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, texWithSampler); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2, 2, 0, gl.RGBA, gl.UNSIGNED_BYTE, data); + + sampler = gl.createSampler(); + gl.bindSampler(0, sampler); + gl.samplerParameteri(sampler, gl.TEXTURE_WRAP_S, ext.MIRROR_CLAMP_TO_EDGE_EXT); + gl.samplerParameteri(sampler, gl.TEXTURE_WRAP_T, ext.MIRROR_CLAMP_TO_EDGE_EXT); + gl.samplerParameteri(sampler, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.samplerParameteri(sampler, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texture created and sampler configured"); + + wtu.drawUnitQuad(gl); + checkPixels(); +} + +function runTest() { + if (!gl) { + testFailed("context does not exist"); + return; + } + testPassed("context exists"); + + runTestNoExtension(); + + ext = gl.getExtension("EXT_texture_mirror_clamp_to_edge"); + wtu.runExtensionSupportedTest(gl, "EXT_texture_mirror_clamp_to_edge", ext !== null); + + if (ext !== null) { + checkEnums(); + checkQueries(); + checkSampling(); + } else { + testPassed("No EXT_texture_mirror_clamp_to_edge support -- this is legal"); + } +} + +runTest(); + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/khr-parallel-shader-compile.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/khr-parallel-shader-compile.html index 2915a2d2de..6a8b1981e5 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/khr-parallel-shader-compile.html +++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/khr-parallel-shader-compile.html @@ -169,6 +169,32 @@ let extraCode = ''; testPassed(`COMPLETION_STATUS_KHR sucessfully transitioned from false to true`); } + debug("Checking that compiling lots of programs in parallel eventually completes."); + let programs = []; + for (let i = 0; i < 256; ++i) { + gl.shaderSource(vs, vertexSource()); + gl.shaderSource(fs, fragmentSource()); + gl.compileShader(vs); + gl.compileShader(fs); + let program = gl.createProgram(); + gl.attachShader(program, vs); + gl.attachShader(program, fs); + gl.linkProgram(program); + programs.push(program); + } + let allDone = false; + while (!allDone) { + allDone = true; + for (let i = 0; i < programs.length; ++i) { + if (!gl.getProgramParameter(programs[i], COMPLETION_STATUS_KHR)) { + allDone = false; + break; + } + } + if (!allDone) { + await new Promise(requestAnimationFrame); + } + } debug("Checking that status is true when context is lost."); if (loseContext) { diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-with-video.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-with-video.html index 3ccbd50f15..cb406706f9 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-with-video.html +++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float-with-video.html @@ -33,7 +33,6 @@ function testPrologue(gl) { <video width="640" height="228" id="vid" controls muted> <source src="../../resources/red-green.mp4" type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"' /> <source src="../../resources/red-green.webmvp8.webm" type='video/webm; codecs="vp8, vorbis"' /> - <source src="../../resources/red-green.theora.ogv" type='video/ogg; codecs="theora, vorbis"' /> </video> </body> </html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float.html index a757cb22ec..8bec35b9cf 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float.html +++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-float.html @@ -60,6 +60,7 @@ debug(""); var wtu = WebGLTestUtils; var canvas = document.getElementById("canvas"); var gl = wtu.create3DContext(canvas); +var ext = null; if (!gl) { testFailed("WebGL context does not exist"); @@ -81,6 +82,33 @@ if (!gl) { // the extension has not been enabled yet. runTextureCreationTest(testProgram, false); + { + debug(""); + debug("Testing that component type framebuffer attachment queries are rejected with the extension disabled"); + const fbo = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + + const rbo = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rbo); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,gl.RENDERBUFFER, rbo); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGB565, 8, 8); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setup renderbuffer should succeed."); + shouldBeNull('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, 0x8211 /* FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT */)'); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Query must fail."); + gl.deleteRenderbuffer(rbo); + + const tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 8, 8, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setup texture should succeed."); + shouldBeNull('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, 0x8211 /* FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT */)'); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Query must fail."); + gl.deleteTexture(tex); + + gl.deleteFramebuffer(fbo); + } + if (!gl.getExtension("OES_texture_float")) { testPassed("No OES_texture_float support -- this is legal"); } else { @@ -109,6 +137,43 @@ if (!gl) { runRenderTargetAndReadbackTest(testProgram, gl.RGBA, 4, [10000, 10000, 10000, 10000], 0.5, true); runFramebufferTest(); + { + debug(""); + debug("Testing that component type framebuffer attachment queries are accepted with the extension enabled"); + ext = gl.getExtension("WEBGL_color_buffer_float"); + shouldBeNonNull('ext'); + const fbo = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + + const rbo = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rbo); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,gl.RENDERBUFFER, rbo); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGB565, 8, 8); + shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, ext.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT)', 'ext.UNSIGNED_NORMALIZED_EXT'); + gl.renderbufferStorage(gl.RENDERBUFFER, ext.RGBA32F_EXT, 8, 8); + shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, ext.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT)', 'gl.FLOAT'); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No errors after valid renderbuffer attachment queries."); + + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT,gl.RENDERBUFFER, rbo); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, 8, 8); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No errors after depth-stencil renderbuffer setup."); + shouldBeNull('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, ext.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT)'); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Component type query is not allowed for combined depth-stencil attachments."); + gl.deleteRenderbuffer(rbo); + + const tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 8, 8, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, ext.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT)', 'ext.UNSIGNED_NORMALIZED_EXT'); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 8, 8, 0, gl.RGBA, gl.FLOAT, null); + shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, ext.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT)', 'gl.FLOAT'); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No errors after valid texture attachment queries."); + gl.deleteTexture(tex); + + gl.deleteFramebuffer(fbo); + } + debug(""); debug("Test float32 blending without EXT_float_blend."); testExtFloatBlend(gl.RGBA); diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-with-video.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-with-video.html index 719b332113..d6076b29f9 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-with-video.html +++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-texture-half-float-with-video.html @@ -38,7 +38,6 @@ function testPrologue(gl) { <video width="640" height="228" id="vid" controls muted> <source src="../../resources/red-green.mp4" type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"' /> <source src="../../resources/red-green.webmvp8.webm" type='video/webm; codecs="vp8, vorbis"' /> - <source src="../../resources/red-green.theora.ogv" type='video/ogg; codecs="theora, vorbis"' /> </video> </body> </html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-blend-func-extended.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-blend-func-extended.html new file mode 100644 index 0000000000..62e25adaa2 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-blend-func-extended.html @@ -0,0 +1,26 @@ +<!-- +Copyright (c) 2023 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL 1.0 WEBGL_blend_func_extended Conformance Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<canvas width="32" height="32" id="c"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +var contextVersion = 1; +</script> +<script src="../../js/tests/webgl-blend-func-extended.js"></script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-polygon-mode.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-polygon-mode.html new file mode 100644 index 0000000000..fd65f692a6 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-polygon-mode.html @@ -0,0 +1,185 @@ +<!-- +Copyright (c) 2023 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL WEBGL_polygon_mode Conformance Tests</title> +<LINK rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<canvas width="32" height="32" id="c"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description("This test verifies the functionality of the WEBGL_polygon_mode extension, if it is available."); + +debug(""); + +var wtu = WebGLTestUtils; +var gl = wtu.create3DContext("c"); +var ext; +const w = gl.drawingBufferWidth; +const h = gl.drawingBufferHeight; + +function runTestNoExtension() { + debug(""); + debug("Check the parameters without the extension"); + shouldBeNull("gl.getParameter(0x0B40 /* POLYGON_MODE_WEBGL */)"); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + shouldBeNull("gl.getParameter(0x2A02 /* POLYGON_OFFSET_LINE_WEBGL */)"); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + debug("Check the cap without the extension"); + gl.disable(0x2A02 /* POLYGON_OFFSET_LINE_WEBGL */); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "cap unknown without enabling the extension"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + gl.enable(0x2A02 /* POLYGON_OFFSET_LINE_WEBGL */); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "cap unknown without enabling the extension"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + shouldBeFalse("gl.isEnabled(0x2A02 /* POLYGON_OFFSET_LINE_WEBGL */)"); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "cap unknown without enabling the extension"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); +} + +function checkEnums() { + debug(""); + debug("Check enums"); + shouldBe("ext.POLYGON_MODE_WEBGL", "0x0B40"); + shouldBe("ext.POLYGON_OFFSET_LINE_WEBGL", "0x2A02"); + shouldBe("ext.LINE_WEBGL", "0x1B01"); + shouldBe("ext.FILL_WEBGL", "0x1B02"); +} + +function checkQueries() { + debug(""); + debug("Check default state"); + shouldBe('gl.getParameter(ext.POLYGON_MODE_WEBGL)', 'ext.FILL_WEBGL'); + shouldBeFalse('gl.getParameter(ext.POLYGON_OFFSET_LINE_WEBGL)'); + shouldBeFalse('gl.isEnabled(ext.POLYGON_OFFSET_LINE_WEBGL)'); + debug(""); + debug("Check state updates"); + ext.polygonModeWEBGL(gl.FRONT_AND_BACK, ext.LINE_WEBGL); + shouldBe('gl.getParameter(ext.POLYGON_MODE_WEBGL)', 'ext.LINE_WEBGL'); + ext.polygonModeWEBGL(gl.FRONT_AND_BACK, ext.FILL_WEBGL); + shouldBe('gl.getParameter(ext.POLYGON_MODE_WEBGL)', 'ext.FILL_WEBGL'); + debug(""); + debug("Check errors"); + ext.polygonModeWEBGL(gl.FRONT, ext.LINE_WEBGL); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "invalid face"); + ext.polygonModeWEBGL(gl.FRONT_AND_BACK, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "invalid mode"); + shouldBe('gl.getParameter(ext.POLYGON_MODE_WEBGL)', 'ext.FILL_WEBGL'); + debug(""); + debug("Check cap updates"); + gl.enable(ext.POLYGON_OFFSET_LINE_WEBGL); + shouldBeTrue('gl.getParameter(ext.POLYGON_OFFSET_LINE_WEBGL)'); + shouldBeTrue('gl.isEnabled(ext.POLYGON_OFFSET_LINE_WEBGL)'); + gl.disable(ext.POLYGON_OFFSET_LINE_WEBGL); + shouldBeFalse('gl.getParameter(ext.POLYGON_OFFSET_LINE_WEBGL)'); + shouldBeFalse('gl.isEnabled(ext.POLYGON_OFFSET_LINE_WEBGL)'); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); +} + +function checkDiagonal(r, g, b) { + const pixels = new Uint8Array(w * h * 4); + gl.readPixels(0, 0, w, h, gl.RGBA, gl.UNSIGNED_BYTE, pixels); + for (let i = 0; i < w; i++) + { + const baseOffset = (i * w + i) * 4; + if (pixels[baseOffset + 0] != r || + pixels[baseOffset + 1] != g || + pixels[baseOffset + 2] != b) { + testFailed(`Unexpected diagonal color at (${i}, ${i})`); + return; + } + } + testPassed("Expected diagonal color"); +} + +function checkLineMode() { + debug(""); + debug("Check line polygon mode"); + + gl.enable(gl.DEPTH_TEST); + + const program = wtu.setupProgram(gl, [wtu.simpleVertexShader, + wtu.simpleColorFragmentShader]); + gl.useProgram(program); + const colorLoc = gl.getUniformLocation(program, "u_color"); + + wtu.setupUnitQuad(gl); + + // Draw red quad with lines + gl.uniform4f(colorLoc, 1, 0, 0, 1); + ext.polygonModeWEBGL(gl.FRONT_AND_BACK, ext.LINE_WEBGL); + wtu.clearAndDrawUnitQuad(gl); + + // Nothing is drawn inside triangles + wtu.checkCanvasRect(gl, 2, 17, 13, 13, [255, 255, 255, 255]); + wtu.checkCanvasRect(gl, 17, 2, 13, 13, [255, 255, 255, 255]); + + // Main diagonal is drawn + checkDiagonal(255, 0, 0); + + // Test polygon offset + gl.polygonOffset(0, -2); + gl.enable(gl.POLYGON_OFFSET_FILL); + + // Depth test must fail because line mode uses its own polygon offset toggle + gl.uniform4f(colorLoc, 0, 1, 0, 1); + wtu.drawUnitQuad(gl); + checkDiagonal(255, 0, 0); + + // Depth test must pass + gl.enable(ext.POLYGON_OFFSET_LINE_WEBGL) + wtu.drawUnitQuad(gl); + checkDiagonal(0, 255, 0); + + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); +} + +function runTestExtension() { + checkEnums(); + checkQueries(); + checkLineMode(); +} + +function runTest() { + if (!gl) { + testFailed("WebGL context does not exist"); + return; + } + testPassed("WebGL context exists"); + + runTestNoExtension(); + + ext = gl.getExtension("WEBGL_polygon_mode"); + + wtu.runExtensionSupportedTest(gl, "WEBGL_polygon_mode", ext !== null); + + if (ext !== null) { + runTestExtension(); + } else { + testPassed("No WEBGL_polygon_mode support -- this is legal"); + } +} + +runTest(); + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/reading/read-pixels-test.html b/dom/canvas/test/webgl-conf/checkout/conformance/reading/read-pixels-test.html index 078b436427..3791be2448 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance/reading/read-pixels-test.html +++ b/dom/canvas/test/webgl-conf/checkout/conformance/reading/read-pixels-test.html @@ -39,6 +39,43 @@ function runTest(canvas, antialias) { gl = wtu.create3DContext(canvas, {antialias: antialias}); var contextVersion = wtu.getDefault3DContextVersion(); + debug(""); + debug("Test null pixels"); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, null); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "null pixels"); + + debug(""); + debug("Test pixels size"); + gl.readPixels(0, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(0)); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "empty pixels array with 0x0 read data"); + gl.readPixels(0, 0, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(0)); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "empty pixels array with 1x0 read data"); + gl.readPixels(0, 0, 0, 1, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(0)); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "empty pixels array with 0x1 read data"); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(3)); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "small pixels array for 1x1 read data"); + if (contextVersion >= 2) { + gl.readPixels(0, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(0), 1); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "offset is greater than array size"); + gl.readPixels(0, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(1), 1); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no space left in pixels array with 0x0 read data"); + gl.readPixels(0, 0, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(1), 1); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no space left in pixels array with 1x0 read data"); + gl.readPixels(0, 0, 0, 1, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(1), 1); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no space left in pixels array with 0x1 read data"); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(4), 1); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "no space left in pixels array with 1x1 read data"); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(5), 1); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "read 1x1 data fits into pixels with offset"); + } + + debug(""); + debug("Test combined depth-stencil type"); + // The combined type is undefined in WebGL 1.0 and never allowed as a read type in WebGL 2.0 + gl.readPixels(0, 0, 1, 1, gl.RGBA, 0x8DAD /* FLOAT_32_UNSIGNED_INT_24_8_REV */, new Uint8Array(32)); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "FLOAT_32_UNSIGNED_INT_24_8_REV is rejected"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no extra error generated"); + var width = 2; var height = 2; var continueTestFunc = continueTestPart1; diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/exif-orientation.html b/dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/exif-orientation.html index 3fd596d445..5a4b88e5b8 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/exif-orientation.html +++ b/dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/exif-orientation.html @@ -56,35 +56,20 @@ function checkPixels(flipY) } } -async function testImageBitmapFromBlobWithFlipY(blob, flipY) +async function testImageBitmapWithFlipY(source, flipY) { - let bitmap; - // As a concession to Firefox, which doesn't yet implement - // createImageBitmap with creation options, skip the tests - // involving flipY=true if ImageBitmap creation throws an - // exception, and use the single-argument constructor for the - // flipY=false case. - if (flipY) { - try { - bitmap = await createImageBitmap(blob, {imageOrientation: flipY}); - } catch (e) { - output(" (createImageBitmap options not supported - skipping flipY=true case)"); - return; - } - } else { - bitmap = await createImageBitmap(blob); - } + const bitmap = await createImageBitmap(source, flipY ? {imageOrientation: flipY} : undefined); output(" Testing texImage2D, flipY = " + flipY); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, bitmap); wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]); - checkPixels(flipY); + checkPixels(flipY == "flipY"); output(" Testing texSubImage2D, flipY = " + flipY); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, bitmap.width, bitmap.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, bitmap); wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]); - checkPixels(flipY); + checkPixels(flipY == "flipY"); } async function testImageBitmapFromBlob(filename) @@ -93,8 +78,16 @@ async function testImageBitmapFromBlob(filename) let blob = await response.blob(); output("----------------------------------------------------------------"); output("Testing " + filename + " via ImageBitmap from Blob"); - await testImageBitmapFromBlobWithFlipY(blob, true); - await testImageBitmapFromBlobWithFlipY(blob, false); + await testImageBitmapWithFlipY(blob, "flipY"); + await testImageBitmapWithFlipY(blob, "none"); + await testImageBitmapWithFlipY(blob, undefined); +} + +async function testImageBitmapFromImage(image) +{ + await testImageBitmapWithFlipY(image, "flipY"); + await testImageBitmapWithFlipY(image, "none"); + await testImageBitmapWithFlipY(image, undefined); } async function testImageElementWithFlipY(image, flipY) @@ -124,6 +117,11 @@ async function testImageElement(filename) await testImageElementWithFlipY(image, true); await testImageElementWithFlipY(image, false); + + output("----------------------------------------------------------------"); + output("Testing " + filename + " via ImageBitmap from HTMLImageElement"); + + await testImageBitmapFromImage(image); } async function testSingleImage(filename) @@ -149,9 +147,9 @@ async function run() "exif-orientation-test-3-rotate-180.jpg", "exif-orientation-test-4-mirror-vertical.jpg", "exif-orientation-test-5-mirror-horizontal-90-ccw.jpg", - "exif-orientation-test-6-90-ccw.jpg", + "exif-orientation-test-6-90-cw.jpg", "exif-orientation-test-7-mirror-horizontal-90-cw.jpg", - "exif-orientation-test-8-90-cw.jpg", + "exif-orientation-test-8-90-ccw.jpg", ]; for (let fn of filenames) { diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/tex-video-using-tex-unit-non-zero.html b/dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/tex-video-using-tex-unit-non-zero.html index ee9bad4341..1acc3a4380 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/tex-video-using-tex-unit-non-zero.html +++ b/dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/tex-video-using-tex-unit-non-zero.html @@ -96,8 +96,6 @@ found in the LICENSE.txt file. type: 'video/webm; codecs="vp8, vorbis"' }, { src: resourcePath + "red-green.bt601.vp9.webm", type: 'video/webm; codecs="vp9"' }, - { src: resourcePath + "red-green.theora.ogv", - type: 'video/ogg; codecs="theora, vorbis"' }, ]; var currentVideo = null; diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/texture-npot-video.html b/dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/texture-npot-video.html index ef979d4c5a..9a8e3198ba 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/texture-npot-video.html +++ b/dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/texture-npot-video.html @@ -154,7 +154,6 @@ function runTest(videoElement) <video id="vid" style="display:none;" muted> <source src="../../../resources/npot-video.mp4" type='video/mp4; codecs="avc1.42E01E"' /> <source src="../../../resources/npot-video.webmvp8.webm" type='video/webm; codecs="vp8"' /> - <source src="../../../resources/npot-video.theora.ogv" type='video/ogg; codecs="theora"' /> </video> </body> </html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/texture-srgb-upload.html b/dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/texture-srgb-upload.html index 3508670563..6f66bfdde6 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/texture-srgb-upload.html +++ b/dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/texture-srgb-upload.html @@ -62,12 +62,22 @@ function invoke(fn) { return fn(); } invoke(async () => { const video = document.createElement("video"); video.src = DATA_URL_FOR_720p_png_bt709_bt709_tv_yuv420p_vp9_webm; - //video.src = "Big_Buck_Bunny_360_10s_1MB.mp4"; - //video.src = "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"; + if (!video.canPlayType('video/webm')) { + debug('Browser can not play webm videos. Skipping test.'); + finishTest(); + return; + } + video.muted = true; video.loop = true; video.crossOrigin = "anonymous"; - await video.play(); + try { + await video.play(); + } catch (e) { + debug('Browser could not play this specific video. Skipping test.'); + finishTest(); + return; + } function renderTex(canvas, fn_tex_image) { const gl = canvas.gl = wtu.create3DContext(canvas); diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/texture-upload-size.html b/dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/texture-upload-size.html index a0f30dc89f..b5ba6afed3 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/texture-upload-size.html +++ b/dom/canvas/test/webgl-conf/checkout/conformance/textures/misc/texture-upload-size.html @@ -99,7 +99,6 @@ var tests = [ {type: "video", src: "../../../resources/red-green.mp4", videoType: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"'}, {type: "video", src: "../../../resources/red-green.bt601.vp9.webm", videoType: 'video/webm; codecs="vp9"'}, {type: "video", src: "../../../resources/red-green.webmvp8.webm", videoType: 'video/webm; codecs="vp8, vorbis"'}, - {type: "video", src: "../../../resources/red-green.theora.ogv", videoType: 'video/ogg; codecs="theora, vorbis"'}, ]; var testIndex = 0; diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/uniforms/uniform-location.html b/dom/canvas/test/webgl-conf/checkout/conformance/uniforms/uniform-location.html index 3b1c185caf..6de8114651 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance/uniforms/uniform-location.html +++ b/dom/canvas/test/webgl-conf/checkout/conformance/uniforms/uniform-location.html @@ -68,6 +68,10 @@ contextA.stencilMask(1); wtu.shouldGenerateGLError(contextA, contextA.NO_ERROR, "contextA.linkProgram(programS)"); wtu.shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.uniform1i(locationSx, 3)"); wtu.shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.getUniform(programS, locationSx)"); +// Make sure that with no current program, uniform location validation doesn't get confused. +wtu.shouldGenerateGLError(contextA, contextA.NO_ERROR, "contextA.useProgram(null)"); +wtu.shouldGenerateGLError(contextA, contextA.INVALID_OPERATION, "contextA.uniform1i(locationSx, 3)"); +wtu.shouldGenerateGLError(contextA, contextA.NO_ERROR, "contextA.useProgram(programS)"); // Retrieve the locations again, and they should be good. locationSx = contextA.getUniformLocation(programS, "u_struct.x"); diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/00_test_list.txt b/dom/canvas/test/webgl-conf/checkout/conformance2/00_test_list.txt index e251dc9758..fabc72c1da 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance2/00_test_list.txt +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/00_test_list.txt @@ -18,3 +18,4 @@ textures/00_test_list.txt transform_feedback/00_test_list.txt uniforms/00_test_list.txt vertex_arrays/00_test_list.txt +--min-version 2.0.1 wasm/00_test_list.txt diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/canvas/00_test_list.txt b/dom/canvas/test/webgl-conf/checkout/conformance2/canvas/00_test_list.txt index 35e011f3bf..878a2797c4 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance2/canvas/00_test_list.txt +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/canvas/00_test_list.txt @@ -1 +1,2 @@ +--min-version 2.0.1 drawingbuffer-storage-test.html --min-version 2.0.1 to-data-url-with-pack-params.html diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/canvas/drawingbuffer-storage-test.html b/dom/canvas/test/webgl-conf/checkout/conformance2/canvas/drawingbuffer-storage-test.html new file mode 100644 index 0000000000..6f18d441c0 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/canvas/drawingbuffer-storage-test.html @@ -0,0 +1,27 @@ +<!-- +Copyright (c) 2023 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL2 drawingBufferStorage Conformance Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +<script src="../../js/tests/drawingbuffer-storage-test.js"></script> +</head> +<body> +<div id="description"></div> +<div id="console"></div> +<script> +runTest(2); + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/00_test_list.txt b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/00_test_list.txt index 559071ff06..2cc4456ecb 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/00_test_list.txt +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/00_test_list.txt @@ -1,11 +1,16 @@ ext-color-buffer-float.html --min-version 2.0.1 ext-color-buffer-half-float.html +--min-version 2.0.1 ext-conservative-depth.html ext-disjoint-timer-query-webgl2.html +--min-version 2.0.1 ext-render-snorm.html --min-version 2.0.1 ext-texture-filter-anisotropic.html --min-version 2.0.1 ext-texture-norm16.html promoted-extensions.html promoted-extensions-in-shaders.html +--min-version 2.0.1 nv-shader-noperspective-interpolation.html --min-version 2.0.1 oes-draw-buffers-indexed.html +--min-version 2.0.1 oes-sample-variables.html +--min-version 2.0.1 oes-shader-multisample-interpolation.html --min-version 2.0.1 ovr_multiview2.html --min-version 2.0.1 ovr_multiview2_depth.html --min-version 2.0.1 ovr_multiview2_draw_buffers.html @@ -16,4 +21,10 @@ promoted-extensions-in-shaders.html --min-version 2.0.1 ovr_multiview2_timer_query.html --min-version 2.0.1 ovr_multiview2_transform_feedback.html --min-version 2.0.1 required-extensions.html +--min-version 2.0.1 webgl-blend-func-extended.html +--min-version 2.0.1 webgl-clip-cull-distance.html --min-version 2.0.1 webgl-multi-draw-instanced-base-vertex-base-instance.html +--min-version 2.0.1 webgl-provoking-vertex.html +--min-version 2.0.1 webgl-render-shared-exponent.html +--min-version 2.0.1 webgl-shader-pixel-local-storage.html +--min-version 2.0.1 webgl-stencil-texturing.html diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/ext-conservative-depth.html b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/ext-conservative-depth.html new file mode 100644 index 0000000000..c9c9f85bdb --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/ext-conservative-depth.html @@ -0,0 +1,145 @@ +<!-- +Copyright (c) 2023 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL EXT_conservative_depth Conformance Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<canvas width="32" height="32" id="c"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description("This test verifies the functionality of the EXT_conservative_depth extension, if it is available."); + +debug(""); + +var wtu = WebGLTestUtils; +var gl = wtu.create3DContext("c", null, 2); +var ext; + +function runShaderTests(extensionEnabled) { + debug(""); + debug("Testing various shader compiles with extension " + (extensionEnabled ? "enabled" : "disabled")); + + const macro = `#version 300 es + precision mediump float; + out vec4 my_FragColor; + void main() { + #ifdef GL_EXT_conservative_depth + my_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + #else + #error no GL_EXT_conservative_depth; + #endif + }`; + + const missingExtension = `#version 300 es + precision mediump float; + out vec4 my_FragColor; + layout (depth_any) out float gl_FragDepth; + void main() { + my_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + gl_FragDepth = 1.0; + }`; + + const valid = `#version 300 es + #extension GL_EXT_conservative_depth : enable + precision mediump float; + out vec4 my_FragColor; + layout (depth_any) out float gl_FragDepth; + void main() { + my_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + gl_FragDepth = 1.0; + }`; + + const invalid = `#version 300 es + #extension GL_EXT_conservative_depth : enable + precision mediump float; + out vec4 my_FragColor; + layout (depth_unchanged) out float gl_FragDepth; + void main() { + my_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + gl_FragDepth = 1.0; + }`; + + // Always expect the shader missing the #extension pragma to fail (whether enabled or not) + if (wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, missingExtension])) { + testFailed("Depth layout qualifier allowed without #extension pragma"); + } else { + testPassed("Depth layout qualifier disallowed without #extension pragma"); + } + + // Expect the macro shader to succeed ONLY if enabled + if (wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, macro])) { + if (extensionEnabled) { + testPassed("Macro defined in shaders when extension is enabled"); + } else { + testFailed("Macro defined in shaders when extension is disabled"); + } + } else { + if (extensionEnabled) { + testFailed("Macro not defined in shaders when extension is enabled"); + } else { + testPassed("Macro not defined in shaders when extension is disabled"); + } + } + + // Try to compile a shader using a layout qualifier that should only succeed if enabled + if (wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, valid])) { + if (extensionEnabled) { + testPassed("Depth layout qualifier compiled successfully when extension enabled"); + } else { + testFailed("Depth layout qualifier compiled successfully when extension disabled"); + } + } else { + if (extensionEnabled) { + testFailed("Depth layout qualifier failed to compile when extension enabled"); + } else { + testPassed("Depth layout qualifier failed to compile when extension disabled"); + } + } + + // Try to compile a shader using a disallowed layout qualifier + if (wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, invalid])) { + testFailed("Unsupported depth layout qualifier compiled successfully"); + } else { + testPassed("Unsupported depth layout qualifier failed to compile"); + } +} + +function runTest() { + if (!gl) { + testFailed("WebGL context does not exist"); + return; + } + testPassed("WebGL context exists"); + + runShaderTests(false); + + ext = gl.getExtension("EXT_conservative_depth"); + wtu.runExtensionSupportedTest(gl, "EXT_conservative_depth", ext !== null); + + if (!ext) { + testPassed("No EXT_conservative_depth support -- this is legal"); + } else { + testPassed("Successfully enabled EXT_conservative_depth extension"); + runShaderTests(true); + } +} + +runTest(); + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/ext-disjoint-timer-query-webgl2.html b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/ext-disjoint-timer-query-webgl2.html index c051fa36a3..f1e9a82d8a 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/ext-disjoint-timer-query-webgl2.html +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/ext-disjoint-timer-query-webgl2.html @@ -25,7 +25,9 @@ description("This test verifies the functionality of the EXT_disjoint_timer_quer var wtu = WebGLTestUtils; var canvas = document.getElementById("canvas"); var gl = wtu.create3DContext(canvas, null, 2); +var gl2 = null; var ext = null; +var ext2 = null; var query = null; var query2 = null; var elapsed_query = null; @@ -62,6 +64,8 @@ if (!gl) { wtu.glErrorShouldBe(gl, gl.NO_ERROR); } verifyQueryResultsNotAvailable(); + verifyDeleteQueryBehavior(); + verifyDeleteQueryErrorBehavior(); wtu.glErrorShouldBe(gl, gl.NO_ERROR); window.requestAnimationFrame(checkQueryResults); @@ -249,6 +253,60 @@ function verifyQueryResultsNotAvailable() { testPassed("Queries' results didn't become available in a spin loop"); } +function verifyDeleteQueryBehavior() { + debug(""); + debug("Testing deleting an active query should end it."); + + // Use a new context for this test + gl2 = wtu.create3DContext(null, null, 2); + if (!gl2) return; + ext2 = gl2.getExtension("EXT_disjoint_timer_query_webgl2"); + if (!ext2) return; + + query = gl2.createQuery(); + gl2.beginQuery(ext.TIME_ELAPSED_EXT, query); + wtu.glErrorShouldBe(gl2, gl2.NONE, "The query began successfully"); + gl2.deleteQuery(query); + wtu.glErrorShouldBe(gl2, gl2.NONE, "Deletion of the active query succeeds"); + shouldBeNull("gl2.getQuery(ext2.TIME_ELAPSED_EXT, gl2.CURRENT_QUERY)"); + shouldBeFalse("gl2.isQuery(query)"); + query = gl2.createQuery(); + gl2.beginQuery(ext2.TIME_ELAPSED_EXT, query); + wtu.glErrorShouldBe(gl, gl2.NONE, "Beginning a new query succeeds"); + gl2.endQuery(gl2.TIME_ELAPSED_EXT); + gl2.deleteQuery(query); + wtu.glErrorShouldBe(gl, gl.NONE); + query = null; + ext2 = null; + gl2 = null; +} + +function verifyDeleteQueryErrorBehavior() { + debug(""); + debug("Testing deleting a query created by another context."); + + // Use new contexts for this test + gl2 = wtu.create3DContext(null, null, 2); + var gl3 = wtu.create3DContext(null, null, 2); + if (!gl2 || !gl3) return; + ext2 = gl2.getExtension("EXT_disjoint_timer_query_webgl2"); + if (!ext2) return; + + query = gl2.createQuery(); + gl2.beginQuery(ext2.TIME_ELAPSED_EXT, query); + gl3.deleteQuery(query); + wtu.glErrorShouldBe(gl3, gl3.INVALID_OPERATION); + shouldBeTrue("gl2.isQuery(query)"); + shouldBe("gl2.getQuery(ext2.TIME_ELAPSED_EXT, gl2.CURRENT_QUERY)", "query"); + gl2.endQuery(ext2.TIME_ELAPSED_EXT); + gl2.deleteQuery(query); + wtu.glErrorShouldBe(gl2, gl2.NONE); + query = null; + ext2 = null; + gl2 = null; + gl3 = null; +} + function checkQueryResults() { if (availability_retry > 0) { // Make a reasonable attempt to wait for the queries' results to become available. diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/ext-render-snorm.html b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/ext-render-snorm.html new file mode 100644 index 0000000000..723e762773 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/ext-render-snorm.html @@ -0,0 +1,201 @@ +<!-- +Copyright (c) 2023 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL EXT_render_snorm Conformance Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description("This test verifies the functionality of the EXT_render_snorm extension, if it is available."); + +debug(""); + +var wtu = WebGLTestUtils; +var gl = wtu.create3DContext(null, null, 2); +var ext; + +function createTypedArray(type) { + switch (type) { + case gl.BYTE: + return new Int8Array(4); + case gl.UNSIGNED_BYTE: + return new Uint8Array(4); + case gl.SHORT: + return new Int16Array(4); + case gl.UNSIGNED_SHORT: + return new Uint16Array(4); + default: + return null; + } +} + +function drawTest(config) { + wtu.drawUnitQuad(gl); + + const implementationType = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE); + const implementationFormat = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT); + + // Support for reading signed data with unsigned read type is not required + // but implementations may allow such conversions. Do not expect the error + // when the type matches the buffer type or when it's explicitly supported. + for (const type of [gl.BYTE, gl.UNSIGNED_BYTE, gl.SHORT, gl.UNSIGNED_SHORT]) { + if (type == config.type) continue; + if (implementationFormat != gl.RGBA || implementationType != type) { + gl.readPixels(0, 0, 1, 1, gl.RGBA, type, createTypedArray(type)); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "reading with unsupported type fails"); + } + } + + const defaultPixel = createTypedArray(config.type); + wtu.checkCanvasRect(gl, 0, 0, 1, 1, config.color, + "reading with the RGBA format and matching type", 1, + defaultPixel, + config.type, gl.RGBA); + + if (implementationFormat == config.format && implementationType == config.type) { + const implementationPixel = createTypedArray(implementationType); + const color = [config.color[0]]; + if (config.format != gl.RED) color.push(config.color[1]); + if (config.format == gl.RGBA) color.push(config.color[2], config.color[3]); + wtu.checkCanvasRect(gl, 0, 0, 1, 1, color, + "reading with the exact format/type", 1, + implementationPixel, + implementationType, implementationFormat); + } +} + +function renderbufferTest(config, isSupported) { + debug(""); + debug(`${config.name} renderbuffer: ` + + `${!isSupported || !config.color ? "NOT " : ""}supported`); + + const rbo = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rbo); + gl.renderbufferStorage(gl.RENDERBUFFER, config.internalFormat, 1, 1); + if (!isSupported || !config.color) { + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "renderbuffer allocation failed"); + return; + } + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "renderbuffer allocation succeeded"); + + const fbo = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo); + + wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE); + + drawTest(config); +} + +function textureTest(config, isRenderable, isTexturable) { + debug(""); + debug(`${config.name} texture: ` + + `${!isRenderable || !config.color ? "NOT " : ""}renderable, ` + + `${!isTexturable ? "NOT " : ""}texturable`); + + const tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + gl.texImage2D(gl.TEXTURE_2D, 0, config.internalFormat, 1, 1, 0, config.format, config.type, null); + if (!isTexturable) { + wtu.glErrorShouldBe(gl, + [gl.INVALID_ENUM, gl.INVALID_VALUE, gl.INVALID_OPERATION], + "texture allocation failed"); + return; + } + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texture allocation succeeded"); + + const fbo = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0); + + if (!isRenderable || !config.color) { + wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT); + return; + } + wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE); + + drawTest(config); +} + +function formatTest(isSnormEnabled, isNorm16Enabled) { + const program = wtu.setupProgram(gl, [wtu.simpleVertexShader, + wtu.simpleColorFragmentShader]); + gl.useProgram(program); + gl.uniform4f(gl.getUniformLocation(program, "u_color"), -0.0625, -0.125, -0.25, -0.5); + + wtu.setupUnitQuad(gl); + + const configs8 = [ + {name: "R8_SNORM", format: gl.RED, type: gl.BYTE, internalFormat: gl.R8_SNORM, color: [-8, 0, 0, 127]}, + {name: "RG8_SNORM", format: gl.RG, type: gl.BYTE, internalFormat: gl.RG8_SNORM, color: [-8, -16, 0, 127]}, + {name: "RGB8_SNORM", format: gl.RGB, type: gl.BYTE, internalFormat: gl.RGB8_SNORM, color: null}, + {name: "RGBA8_SNORM", format: gl.RGBA, type: gl.BYTE, internalFormat: gl.RGBA8_SNORM, color: [-8, -16, -32, -64]} + ]; + + const configs16 = [ + {name: "R16_SNORM", format: gl.RED, type: gl.SHORT, internalFormat: 0x8F98 /* R16_SNORM_EXT */, color: [-2048, 0, 0, 32767]}, + {name: "RG16_SNORM", format: gl.RG, type: gl.SHORT, internalFormat: 0x8F99 /* RG16_SNORM_EXT */, color: [-2048, -4096, 0, 32767]}, + {name: "RGB16_SNORM", format: gl.RGB, type: gl.SHORT, internalFormat: 0x8F9A /* RGB16_SNORM_EXT */, color: null}, + {name: "RGBA16_SNORM", format: gl.RGBA, type: gl.SHORT, internalFormat: 0x8F9B /* RGBA16_SNORM_EXT */, color: [-2048, -4096, -8192, -16384]} + ]; + + for (const config of configs8) { + renderbufferTest(config, isSnormEnabled); + textureTest(config, isSnormEnabled, true); + } + + for (const config of configs16) { + renderbufferTest(config, isSnormEnabled && isNorm16Enabled); + textureTest(config, isSnormEnabled && isNorm16Enabled, isNorm16Enabled); + } +} + +function runTest() { + if (!gl) { + testFailed("context does not exist"); + return; + } + + testPassed("context exists"); + + debug(""); + debug("Testing signed normalized formats with EXT_render_snorm disabled"); + formatTest(false, false); + + ext = gl.getExtension("EXT_render_snorm"); + wtu.runExtensionSupportedTest(gl, "EXT_render_snorm", ext !== null); + + if (ext !== null) { + debug(""); + debug("Testing signed normalized formats with only EXT_render_snorm enabled"); + formatTest(true, false); + + if (gl.getExtension("EXT_texture_norm16")) { + debug(""); + debug("Testing signed normalized formats with EXT_render_snorm and EXT_texture_norm16 enabled"); + formatTest(true, true); + } + } else { + testPassed("No EXT_render_snorm support -- this is legal"); + } +} + +runTest(); + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/nv-shader-noperspective-interpolation.html b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/nv-shader-noperspective-interpolation.html new file mode 100644 index 0000000000..2198c17b1a --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/nv-shader-noperspective-interpolation.html @@ -0,0 +1,251 @@ +<!-- +Copyright (c) 2023 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL NV_shader_noperspective_interpolation Conformance Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<canvas width="128" height="128" id="c"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description("This test verifies the functionality of the NV_shader_noperspective_interpolation extension, if it is available."); + +debug(""); + +var wtu = WebGLTestUtils; +var gl = wtu.create3DContext("c", null, 2); +var ext; + +function runShaderTests(extensionEnabled) { + debug(""); + debug("Testing various shader compiles with extension " + (extensionEnabled ? "enabled" : "disabled")); + + const macroVertex = `#version 300 es + in vec4 vPosition; + void main() { + #ifdef GL_NV_shader_noperspective_interpolation + gl_Position = vPosition; + #else + #error no GL_NV_shader_noperspective_interpolation; + #endif + }`; + + const macroFragment = `#version 300 es + precision highp float; + out vec4 my_FragColor; + void main() { + #ifdef GL_NV_shader_noperspective_interpolation + my_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + #else + #error no GL_NV_shader_noperspective_interpolation; + #endif + }`; + + for (const shaders of [[wtu.simpleVertexShaderESSL300, macroFragment], + [macroVertex, wtu.simpleColorFragmentShaderESSL300]]) { + // Expect the macro shader to succeed ONLY if enabled + if (wtu.setupProgram(gl, shaders)) { + if (extensionEnabled) { + testPassed("Macro defined in shaders when extension is enabled"); + } else { + testFailed("Macro defined in shaders when extension is disabled"); + } + } else { + if (extensionEnabled) { + testFailed("Macro not defined in shaders when extension is enabled"); + } else { + testPassed("Macro not defined in shaders when extension is disabled"); + } + } + } + + const missingVertex = `#version 300 es + noperspective out float interpolant; + in vec4 vPosition; + void main() { + gl_Position = vPosition; + }`; + + const missingFragment = `#version 300 es + precision highp float; + noperspective in float interpolant; + out vec4 my_FragColor; + void main() { + my_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + }`; + + // Always expect the shader missing the #extension pragma to fail (whether enabled or not) + for (const shaders of [[missingVertex, wtu.simpleColorFragmentShaderESSL300], + [wtu.simpleVertexShaderESSL300, missingFragment], + [missingVertex, missingFragment]]) { + if (wtu.setupProgram(gl, shaders)) { + testFailed("Noperspective interpolation qualifier allowed without #extension pragma"); + } else { + testPassed("Noperspective interpolation qualifier disallowed without #extension pragma"); + } + } + + const validVertex = `#version 300 es + #extension GL_NV_shader_noperspective_interpolation : enable + noperspective out float interpolant; + in vec4 vPosition; + void main() { + gl_Position = vPosition; + }`; + + const validFragment = `#version 300 es + #extension GL_NV_shader_noperspective_interpolation : enable + precision highp float; + noperspective in float interpolant; + out vec4 my_FragColor; + void main() { + my_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + }`; + + // Try to compile a shader using a noperspective qualifier that should only succeed if enabled + if (wtu.setupProgram(gl, [validVertex, validFragment])) { + if (extensionEnabled) { + testPassed("Noperspective interpolation qualifier compiled successfully when extension enabled"); + } else { + testFailed("Noperspective interpolation qualifier compiled successfully when extension disabled"); + } + } else { + if (extensionEnabled) { + testFailed("Noperspective interpolation qualifier failed to compile when extension enabled"); + } else { + testPassed("Noperspective interpolation qualifier failed to compile when extension disabled"); + } + } + + debug(""); +} + +function runInterpolationTest() { + function draw(program, skew) { + gl.useProgram(program); + + const posLoc = gl.getAttribLocation(program, "position"); + const colLoc = gl.getAttribLocation(program, "color"); + + const buf = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, buf); + gl.bufferData( + gl.ARRAY_BUFFER, + new Float32Array([ + -1.0, -1.0, 0.0, 1.0, + +1.0, -1.0, 0.0, 1.0, + 0.0, +1.0 * skew, 0.0, skew, + + 1.0, 0.0, 0.0, 1.0, + 0.0, 1.0, 0.0, 1.0, + 0.0, 0.0, 1.0, 1.0]), + gl.STATIC_DRAW); + + gl.vertexAttribPointer(posLoc, 4, gl.FLOAT, false, 0, 0); + gl.vertexAttribPointer(colLoc, 4, gl.FLOAT, false, 0, 48); + gl.enableVertexAttribArray(posLoc); + gl.enableVertexAttribArray(colLoc); + gl.drawArrays(gl.TRIANGLES, 0, 3); + } + + const vertexSmooth = `#version 300 es + in vec4 position; + in vec4 color; + smooth out vec4 interp_color; + void main() { + gl_Position = position; + interp_color = color; + }`; + + const fragmentSmooth = `#version 300 es + precision highp float; + smooth in vec4 interp_color; + out vec4 fragColor; + void main() { + fragColor = interp_color; + }`; + const programSmooth = wtu.setupProgram(gl, [vertexSmooth, fragmentSmooth]); + + debug("Get non-skewed value with smooth interpolation"); + gl.clearColor(0.0, 0.0, 0.0, 1.0); + gl.clear(gl.COLOR_BUFFER_BIT); + draw(programSmooth, 1.0); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + const smoothColor = new Uint8Array(4); + gl.readPixels(64, 64, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, smoothColor); + + const vertexNoperspective = `#version 300 es + #extension GL_NV_shader_noperspective_interpolation : require + in vec4 position; + in vec4 color; + noperspective out vec4 interp_color; + void main() { + gl_Position = position; + interp_color = color; + }`; + + const fragmentNoperspective = `#version 300 es + #extension GL_NV_shader_noperspective_interpolation : require + precision highp float; + noperspective in vec4 interp_color; + out vec4 fragColor; + void main() { + fragColor = interp_color; + }`; + const programNoperspective = wtu.setupProgram(gl, [vertexNoperspective, fragmentNoperspective]); + + debug(""); + debug("Check non-skewed value with noperspective interpolation"); + gl.clear(gl.COLOR_BUFFER_BIT); + draw(programNoperspective, 1.0); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + wtu.checkCanvasRect(gl, 64, 64, 1, 1, smoothColor, "Non-skewed noperspective should match smooth"); + + debug(""); + debug("Check skewed value with noperspective interpolation"); + gl.clear(gl.COLOR_BUFFER_BIT); + draw(programNoperspective, 2.0); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + wtu.checkCanvasRect(gl, 64, 64, 1, 1, smoothColor, "Skewed noperspective should match smooth"); +} + +function runTest() { + if (!gl) { + testFailed("WebGL context does not exist"); + return; + } + testPassed("WebGL context exists"); + + runShaderTests(false); + + ext = gl.getExtension("NV_shader_noperspective_interpolation"); + wtu.runExtensionSupportedTest(gl, "NV_shader_noperspective_interpolation", ext !== null); + + if (!ext) { + testPassed("No NV_shader_noperspective_interpolation support -- this is legal"); + } else { + testPassed("Successfully enabled NV_shader_noperspective_interpolation extension"); + runShaderTests(true); + runInterpolationTest(); + } +} + +runTest(); + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/oes-sample-variables.html b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/oes-sample-variables.html new file mode 100644 index 0000000000..41fc8f8242 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/oes-sample-variables.html @@ -0,0 +1,474 @@ +<!-- +Copyright (c) 2023 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL OES_sample_variables Conformance Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<canvas width="32" height="32" id="c"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description("This test verifies the functionality of the OES_sample_variables extension, if it is available."); + +debug(""); + +var wtu = WebGLTestUtils; +var gl = wtu.create3DContext("c", { antialias: false }, 2); +var ext; + +function runShaderTests(extensionEnabled) { + debug(""); + debug("Testing various shader compiles with extension " + (extensionEnabled ? "enabled" : "disabled")); + + const macro = `#version 300 es + precision highp float; + out vec4 my_FragColor; + void main() { + #ifdef GL_OES_sample_variables + my_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + #else + #error no GL_OES_sample_variables; + #endif + }`; + + // Expect the macro shader to succeed ONLY if enabled + if (wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, macro])) { + if (extensionEnabled) { + testPassed("Macro defined in shaders when extension is enabled"); + } else { + testFailed("Macro defined in shaders when extension is disabled"); + } + } else { + if (extensionEnabled) { + testFailed("Macro not defined in shaders when extension is enabled"); + } else { + testPassed("Macro not defined in shaders when extension is disabled"); + } + } + + const missing = `#version 300 es + precision highp float; + out vec4 my_FragColor; + void main() { + gl_SampleMask[0] = gl_SampleMaskIn[0] & 0x55555555; + my_FragColor = vec4(gl_SamplePosition.yx, float(gl_SampleID), float(gl_MaxSamples + gl_NumSamples)); + }`; + + // Always expect the shader missing the #extension pragma to fail (whether enabled or not) + if (wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, missing])) { + testFailed("Sample variables allowed without #extension pragma"); + } else { + testPassed("Sample variables disallowed without #extension pragma"); + } + + const valid = `#version 300 es + #extension GL_OES_sample_variables : enable + precision highp float; + out vec4 my_FragColor; + void main() { + gl_SampleMask[0] = gl_SampleMaskIn[0] & 0x55555555; + my_FragColor = vec4(gl_SamplePosition.yx, float(gl_SampleID), float(gl_MaxSamples + gl_NumSamples)); + }`; + + // Try to compile a shader using sample variables that should only succeed if enabled + if (wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, valid])) { + if (extensionEnabled) { + testPassed("Sample variables compiled successfully when extension enabled"); + } else { + testFailed("Sample variables compiled successfully when extension disabled"); + } + } else { + if (extensionEnabled) { + testFailed("Sample variables failed to compile when extension enabled"); + } else { + testPassed("Sample variables failed to compile when extension disabled"); + } + } + + debug(""); +} + +function runMaxSamplesTest() { + debug(""); + debug("Testing gl_MaxSamples"); + + const frag = `#version 300 es + #extension GL_OES_sample_variables : require + precision highp float; + out vec4 color; + void main() { + color = vec4(float(gl_MaxSamples * 4) / 255.0, 0.0, 0.0, 1.0); + }`; + gl.useProgram(wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, frag])); + + wtu.setupUnitQuad(gl); + wtu.drawUnitQuad(gl); + + wtu.checkCanvas(gl, [gl.getParameter(gl.MAX_SAMPLES) * 4, 0, 0, 255], "should match MAX_SAMPLES", 1); +} + +function runNumSamplesTest() { + debug(""); + debug("Testing gl_NumSamples"); + + const rbo = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rbo); + gl.renderbufferStorageMultisample(gl.RENDERBUFFER, 4, gl.RGBA8, 32, 32); + + const fbo = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo); + + wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE); + + const frag = `#version 300 es + #extension GL_OES_sample_variables : require + precision highp float; + out vec4 color; + void main() { + if (gl_NumSamples == 4) { + color = vec4(0.0, 1.0, 0.0, 1.0); + } else { + color = vec4(1.0, 0.0, 0.0, 1.0); + } + }`; + gl.useProgram(wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, frag])); + + wtu.setupUnitQuad(gl); + wtu.drawUnitQuad(gl); + + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); + gl.blitFramebuffer(0, 0, 32, 32, 0, 0, 32, 32, gl.COLOR_BUFFER_BIT, gl.NEAREST); + + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null); + wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green"); +} + +function runSampleIDTest() { + debug(""); + debug("Testing gl_SampleID"); + + const frag = `#version 300 es + #extension GL_OES_sample_variables : require + precision highp float; + out vec4 color; + uniform int id; + void main() { + // Special value when the selected sample is processed, 0.0 otherwise + float r = float(gl_SampleID == id ? (1 << gl_SampleID) : 0) * 32.0 / 255.0; + // Must always be 0.0 + float g = float(gl_SampleID < 0 || gl_SampleID >= gl_NumSamples); + color = vec4(r, g, 0.0, 1.0); + }`; + const program = wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, frag]); + gl.useProgram(program); + + wtu.setupUnitQuad(gl); + + const rbo = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rbo); + gl.renderbufferStorageMultisample(gl.RENDERBUFFER, 4, gl.RGBA8, 32, 32); + + const fbo = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo); + + wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE); + + for (let sample = 0; sample < 4; sample++) { + debug(`Sample ${sample} is selected`); + + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo); + gl.uniform1i(gl.getUniformLocation(program, "id"), sample); + wtu.drawUnitQuad(gl); + + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); + gl.blitFramebuffer(0, 0, 32, 32, 0, 0, 32, 32, gl.COLOR_BUFFER_BIT, gl.NEAREST); + + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null); + wtu.checkCanvas(gl, [(1 << sample) * 8, 0, 0, 255], undefined, 1); + } +} + +function runSampleMaskInTest() { + debug(""); + debug("Testing gl_SampleMaskIn"); + + const frag = `#version 300 es + #extension GL_OES_sample_variables : require + precision highp float; + out vec4 color; + uint popcount(uint v) { + uint c = 0u; + for (; v != 0u; v >>= 1) c += v & 1u; + return c; + } + void main() { + float r = float(popcount(uint(gl_SampleMaskIn[0]))); + color = vec4(r * 4.0 / 255.0, 0, 0, 1); + }`; + + const program = wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, frag]); + gl.useProgram(program); + + // Use a triangle instead of the WTU's quad + // to avoid artifacts along the diagonal + const vertices = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, vertices); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ + -1.0, 1.0, + 1.0, -1.0, + -1.0, -1.0]), gl.STATIC_DRAW); + gl.enableVertexAttribArray(0); + gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0); + + function test(sampleCount, sampleCoverageEnabled, coverage) { + if (sampleCoverageEnabled) { + gl.enable(gl.SAMPLE_COVERAGE); + } else { + gl.disable(gl.SAMPLE_COVERAGE); + } + + gl.sampleCoverage(coverage, false); + + const rbo = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rbo); + gl.renderbufferStorageMultisample(gl.RENDERBUFFER, sampleCount, gl.RGBA8, 32, 32); + + const fbo = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo); + + wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE); + + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo); + gl.clear(gl.COLOR_BUFFER_BIT); + gl.drawArrays(gl.TRIANGLES, 0, 3); + + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); + gl.blitFramebuffer(0, 0, 32, 32, 0, 0, 32, 32, gl.COLOR_BUFFER_BIT, gl.NEAREST); + + // Shader scales up the number of input samples to increase precision in unorm8 space. + let expected = Math.max(sampleCount, 1) * 4; + + // Sample coverage must not affect single sampled buffers + if (sampleCoverageEnabled && sampleCount > 0) { + // The number of samples in gl_SampleMaskIn must be affected by the sample + // coverage GL state and then the resolved value must be scaled down again. + expected *= coverage * coverage; + } + + // Check only the red channel + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null); + const pixel = new Uint8Array(4); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel); + const message = `Expected: ${expected}, Actual: ${pixel[0]}, ` + + `Samples: ${sampleCount}, Sample Coverage: ${sampleCoverageEnabled}, Coverage: ${coverage}`; + if (Math.abs(pixel[0] - expected) > 2) { + testFailed(message); + } else { + testPassed(message); + } + } + + // Include all exposed sample counts and additionally test single-sampled rendering + const sampleCounts = [...gl.getInternalformatParameter(gl.RENDERBUFFER, gl.RGBA8, gl.SAMPLES), 0]; + + for (const sampleCount of sampleCounts) { + if (sampleCount > 32) { + // This test will not work with more than 32 samples. + continue; + } + + for (const sampleCoverageEnabled of [false, true]) { + for (const coverage of [0.0, 0.5, 1.0]) { + if (sampleCount == 1 && coverage != 0.0 && coverage != 1.0) { + continue; + } + test(sampleCount, sampleCoverageEnabled, coverage); + } + } + } +} + +function runSampleMaskInPerSampleTest() { + debug(""); + debug("Testing gl_SampleMaskIn with per-sample shading"); + + const frag = `#version 300 es + #extension GL_OES_sample_variables : require + precision highp float; + out vec4 color; + void main() { + float r = float(gl_SampleMaskIn[0] == (1 << gl_SampleID)); + color = vec4(r, 0, 0, 1); + }`; + const program = wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, frag]); + gl.useProgram(program); + + wtu.setupUnitQuad(gl); + + // Include all exposed sample counts and additionally test single-sampled rendering + const sampleCounts = [...gl.getInternalformatParameter(gl.RENDERBUFFER, gl.RGBA8, gl.SAMPLES), 0]; + for (const sampleCount of sampleCounts) { + if (sampleCount > 32) { + // This test will not work with more than 32 samples. + continue; + } + + const rbo = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rbo); + gl.renderbufferStorageMultisample(gl.RENDERBUFFER, sampleCount, gl.RGBA8, 32, 32); + + const fbo = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo); + + wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE); + + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo); + wtu.drawUnitQuad(gl); + + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); + gl.blitFramebuffer(0, 0, 32, 32, 0, 0, 32, 32, gl.COLOR_BUFFER_BIT, gl.NEAREST); + + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null); + wtu.checkCanvas(gl, [255, 0, 0, 255], `Samples: ${sampleCount}`, 1); + } +} + +function runSampleMaskTest() { + debug(""); + debug("Testing gl_SampleMask"); + + const frag = `#version 300 es + #extension GL_OES_sample_variables : require + precision highp float; + uniform highp int sampleMask; + out vec4 color; + void main() { + gl_SampleMask[0] = sampleMask; + color = vec4(1, 0, 0, 1); + }`; + const program = wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, frag]); + gl.useProgram(program); + + // Use a triangle instead of the WTU's quad + // to avoid artifacts along the diagonal + const vertices = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, vertices); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ + -1.0, 1.0, + 1.0, -1.0, + -1.0, -1.0]), gl.STATIC_DRAW); + gl.enableVertexAttribArray(0); + gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0); + + function test(sampleCount, sampleMask) { + const rbo = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rbo); + gl.renderbufferStorageMultisample(gl.RENDERBUFFER, sampleCount, gl.RGBA8, 32, 32); + + const fbo = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo); + + wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE); + + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo); + gl.clear(gl.COLOR_BUFFER_BIT); + gl.uniform1i(gl.getUniformLocation(program, "sampleMask"), sampleMask); + gl.drawArrays(gl.TRIANGLES, 0, 3); + + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); + gl.blitFramebuffer(0, 0, 32, 32, 0, 0, 32, 32, gl.COLOR_BUFFER_BIT, gl.NEAREST); + + let expected = 1.0; + if (sampleCount > 0) { + let mask = sampleMask & ((1 << Math.max(sampleCount, 1)) - 1); + let bits = 0; + for (; mask != 0; mask >>= 1) bits += mask & 1; + expected = bits / Math.max(sampleCount, 1); + } + expected *= 255; + + // Check only the red channel + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null); + const pixel = new Uint8Array(4); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel); + const message = `Samples: ${sampleCount}, ` + + `gl_SampleMask[0]: 0x${sampleMask.toString(16).padStart(8, "0").toUpperCase()}, ` + + `Actual: ${pixel[0]}, Expected: ${expected}`; + if (Math.abs(pixel[0] - expected) > 2) { + testFailed(message); + } else { + testPassed(message); + } + } + + // Include all exposed sample counts and additionally test single-sampled rendering + const sampleCounts = [...gl.getInternalformatParameter(gl.RENDERBUFFER, gl.RGBA8, gl.SAMPLES), 0]; + + for (const sampleCount of sampleCounts) { + if (sampleCount > 31) { + // This test will not work with more than 31 samples. + continue; + } + + for (const sampleMask of [0xFFFFFFFF, 0x55555555, 0xAAAAAAAA, 0x00000000]) { + test(sampleCount, sampleMask); + } + } +} + +function runTest() { + if (!gl) { + testFailed("WebGL context does not exist"); + return; + } + testPassed("WebGL context exists"); + + runShaderTests(false); + + ext = gl.getExtension("OES_sample_variables"); + wtu.runExtensionSupportedTest(gl, "OES_sample_variables", ext !== null); + + if (!ext) { + testPassed("No OES_sample_variables support -- this is legal"); + } else { + testPassed("Successfully enabled OES_sample_variables extension"); + runShaderTests(true); + + debug("Testing sample variables"); + runMaxSamplesTest(); + runNumSamplesTest(); + runSampleIDTest(); + runSampleMaskInTest(); + runSampleMaskInPerSampleTest(); + runSampleMaskTest(); + } +} + +runTest(); + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/oes-shader-multisample-interpolation.html b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/oes-shader-multisample-interpolation.html new file mode 100644 index 0000000000..dcb272c2f0 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/oes-shader-multisample-interpolation.html @@ -0,0 +1,313 @@ +<!-- +Copyright (c) 2023 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL OES_shader_multisample_interpolation Conformance Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<canvas width="32" height="32" id="c"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description("This test verifies the functionality of the OES_shader_multisample_interpolation extension, if it is available."); + +debug(""); + +var wtu = WebGLTestUtils; +var gl = wtu.create3DContext("c", { antialias: false }, 2); +var ext; + +function runShaderTests(extensionEnabled) { + debug(""); + debug("Testing various shader compiles with extension " + (extensionEnabled ? "enabled" : "disabled")); + + const macroVertex = `#version 300 es + in vec4 vPosition; + void main() { + #ifdef GL_OES_shader_multisample_interpolation + gl_Position = vPosition; + #else + #error no GL_OES_shader_multisample_interpolation; + #endif + }`; + + const macroFragment = `#version 300 es + precision highp float; + out vec4 my_FragColor; + void main() { + #ifdef GL_OES_shader_multisample_interpolation + my_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + #else + #error no GL_OES_shader_multisample_interpolation; + #endif + }`; + + for (const shaders of [[wtu.simpleVertexShaderESSL300, macroFragment], + [macroVertex, wtu.simpleColorFragmentShaderESSL300]]) { + // Expect the macro shader to succeed ONLY if enabled + if (wtu.setupProgram(gl, shaders)) { + if (extensionEnabled) { + testPassed("Macro defined in shaders when extension is enabled"); + } else { + testFailed("Macro defined in shaders when extension is disabled"); + } + } else { + if (extensionEnabled) { + testFailed("Macro not defined in shaders when extension is enabled"); + } else { + testPassed("Macro not defined in shaders when extension is disabled"); + } + } + } + + const missingVertex = `#version 300 es + sample out float interpolant; + in vec4 vPosition; + void main() { + gl_Position = vPosition; + }`; + + const missingFragment = `#version 300 es + precision highp float; + sample in float interpolant; + out vec4 my_FragColor; + void main() { + my_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + }`; + + // Always expect the shader missing the #extension pragma to fail (whether enabled or not) + for (const shaders of [[missingVertex, wtu.simpleColorFragmentShaderESSL300], + [wtu.simpleVertexShaderESSL300, missingFragment], + [missingVertex, missingFragment]]) { + if (wtu.setupProgram(gl, shaders)) { + testFailed("Sample interpolation qualifier allowed without #extension pragma"); + } else { + testPassed("Sample interpolation qualifier disallowed without #extension pragma"); + } + } + + const validVertex = `#version 300 es + #extension GL_OES_shader_multisample_interpolation : enable + sample out float interpolant; + in vec4 vPosition; + void main() { + gl_Position = vPosition; + }`; + + const validFragment = `#version 300 es + #extension GL_OES_shader_multisample_interpolation : enable + precision highp float; + sample in float interpolant; + out vec4 my_FragColor; + void main() { + my_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + }`; + + // Try to compile a shader using a sample qualifier that should only succeed if enabled + if (wtu.setupProgram(gl, [validVertex, validFragment])) { + if (extensionEnabled) { + testPassed("Sample interpolation qualifier compiled successfully when extension enabled"); + } else { + testFailed("Sample interpolation qualifier compiled successfully when extension disabled"); + } + } else { + if (extensionEnabled) { + testFailed("Sample interpolation qualifier failed to compile when extension enabled"); + } else { + testPassed("Sample interpolation qualifier failed to compile when extension disabled"); + } + } +} + +function runQueryTests(extensionEnabled) { + debug(""); + debug("Testing parameters with extension " + (extensionEnabled ? "enabled" : "disabled")); + if (extensionEnabled) { + shouldBeGreaterThanOrEqual("gl.getParameter(ext.FRAGMENT_INTERPOLATION_OFFSET_BITS_OES)", "4"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + const limit = 0.5 - Math.pow(2, -gl.getParameter(ext.FRAGMENT_INTERPOLATION_OFFSET_BITS_OES)); + shouldBeLessThanOrEqual("gl.getParameter(ext.MIN_FRAGMENT_INTERPOLATION_OFFSET_OES)", `-${limit}`); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + shouldBeGreaterThanOrEqual("gl.getParameter(ext.MAX_FRAGMENT_INTERPOLATION_OFFSET_OES)", `${limit}`); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + } else { + shouldBeNull("gl.getParameter(0x8E5B /* MIN_FRAGMENT_INTERPOLATION_OFFSET_OES */)"); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + shouldBeNull("gl.getParameter(0x8E5C /* MAX_FRAGMENT_INTERPOLATION_OFFSET_OES */)"); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + shouldBeNull("gl.getParameter(0x8E5D /* FRAGMENT_INTERPOLATION_OFFSET_BITS_OES */)"); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + } +} + +function checkEnums() { + debug(""); + debug("Check enums"); + shouldBe("ext.MIN_FRAGMENT_INTERPOLATION_OFFSET_OES", "0x8E5B"); + shouldBe("ext.MAX_FRAGMENT_INTERPOLATION_OFFSET_OES", "0x8E5C"); + shouldBe("ext.FRAGMENT_INTERPOLATION_OFFSET_BITS_OES", "0x8E5D"); +} + +/* + * This test renders a triangle using MSAAx4 and 1x1 viewport + * with the following vertex colors. + * + * | Position | Color | + * |==========|===========| + * | (-1, -1) | (0, 0, 0) | + * | (-1, +1) | (0, 1, 0) | + * | (+1, -1) | (1, 0, 0) | + * + * This triangle cannot cover all four samples. + * + * When default interpolation is used, the vertex color is interpolated + * once, most likely in the pixel center. + * + * When per-sample interpolation is used, the vertex color is interpolated + * several times, producing a distinct value for each covered sample. + * Due to the asymmetry of sample positions, the resolved pixel color must + * not match the color produced by default interpolation. + * + * OpenGL specs do not guarantee specific sample positions, so the test + * checks only that the resolved colors are different. + */ +function runInterpolationTest() { + debug(""); + debug("Testing multisample interpolation"); + + function draw(program) { + gl.viewport(0, 0, 1, 1); + gl.useProgram(program); + + const posLoc = gl.getAttribLocation(program, "position"); + const buf = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, buf); + gl.bufferData( + gl.ARRAY_BUFFER, + new Float32Array([ + -1.0, -1.0, + -1.0, +1.0, + +1.0, -1.0]), + gl.STATIC_DRAW); + + gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(posLoc); + + const rbo = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rbo); + gl.renderbufferStorageMultisample(gl.RENDERBUFFER, 4, gl.RGBA8, 1, 1); + + const fbo = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo); + + wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE); + + gl.clear(gl.COLOR_BUFFER_BIT); + gl.drawArrays(gl.TRIANGLES, 0, 3); + + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo); + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); + gl.blitFramebuffer(0, 0, 1, 1, 0, 0, 1, 1, gl.COLOR_BUFFER_BIT, gl.NEAREST); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null); + } + + const vertexCenter = `#version 300 es + in vec4 position; + out vec4 interp_color; + void main() { + gl_Position = position; + interp_color = vec4(position.xy * 0.5 + 0.5, 0.0, 1.0); + }`; + + const fragmentCenter = `#version 300 es + precision highp float; + in vec4 interp_color; + out vec4 fragColor; + void main() { + fragColor = interp_color; + }`; + const programCenter = wtu.setupProgram(gl, [vertexCenter, fragmentCenter]); + + draw(programCenter); + const centerColor = new Uint8Array(4); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, centerColor); + + const vertexSample = `#version 300 es + #extension GL_OES_shader_multisample_interpolation : require + in vec4 position; + sample out vec4 interp_color; + void main() { + gl_Position = position; + interp_color = vec4(position.xy * 0.5 + 0.5, 0.0, 1.0); + }`; + + const fragmentSample = `#version 300 es + #extension GL_OES_shader_multisample_interpolation : require + precision highp float; + sample in vec4 interp_color; + out vec4 fragColor; + void main() { + fragColor = interp_color; + }`; + const programSample = wtu.setupProgram(gl, [vertexSample, fragmentSample]); + + draw(programSample); + const sampleColor = new Uint8Array(4); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, sampleColor); + + const message = `Pixel-center value: ${centerColor}, sample-average value: ${sampleColor}`; + if (centerColor[0] == sampleColor[0] && centerColor[1] == sampleColor[1]) { + testFailed(message); + } else { + testPassed(message); + } +} + +function runTest() { + if (!gl) { + testFailed("WebGL context does not exist"); + return; + } + testPassed("WebGL context exists"); + + runQueryTests(false); + runShaderTests(false); + + debug(""); + ext = gl.getExtension("OES_shader_multisample_interpolation"); + wtu.runExtensionSupportedTest(gl, "OES_shader_multisample_interpolation", ext !== null); + + if (!ext) { + testPassed("No OES_shader_multisample_interpolation support -- this is legal"); + } else { + testPassed("Successfully enabled OES_shader_multisample_interpolation extension"); + runQueryTests(true); + runShaderTests(true); + runInterpolationTest(); + } +} + +runTest(); + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl-blend-func-extended.html b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl-blend-func-extended.html new file mode 100644 index 0000000000..792e9aafa7 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl-blend-func-extended.html @@ -0,0 +1,26 @@ +<!-- +Copyright (c) 2023 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL 2.0 WEBGL_blend_func_extended Conformance Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<canvas width="32" height="32" id="c"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +var contextVersion = 2; +</script> +<script src="../../js/tests/webgl-blend-func-extended.js"></script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl-clip-cull-distance.html b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl-clip-cull-distance.html new file mode 100644 index 0000000000..cb2253c326 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl-clip-cull-distance.html @@ -0,0 +1,475 @@ +<!-- +Copyright (c) 2022 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL WEBGL_clip_cull_distance Conformance Tests</title> +<LINK rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<canvas width="32" height="32" id="c"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description("This test verifies the functionality of the WEBGL_clip_cull_distance extension, if it is available."); + +debug(""); + +var wtu = WebGLTestUtils; +var gl = wtu.create3DContext("c", null, 2); +var ext; +const w = gl.drawingBufferWidth; +const h = gl.drawingBufferHeight; + +function runTestNoExtension() { + debug(""); + debug("Check parameters and capabilities without the extension"); + + shouldBeNull("gl.getParameter(0x0D32 /* MAX_CLIP_DISTANCES_WEBGL */)"); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension"); + shouldBeNull("gl.getParameter(0x82F9 /* MAX_CULL_DISTANCES_WEBGL */)"); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension"); + shouldBeNull("gl.getParameter(0x82FA /* MAX_COMBINED_CLIP_AND_CULL_DISTANCES_WEBGL */)"); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension"); + + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + const assertState = (i) => { + shouldBeFalse(`gl.isEnabled(${0x3000 + i} /* CLIP_DISTANCE${i}_WEBGL */)`); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension"); + + shouldBeNull(`gl.getParameter(${0x3000 + i} /* CLIP_DISTANCE${i}_WEBGL */)`); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension"); + }; + + for (let i = 0; i < 8; i++) { + assertState(i); + + gl.enable(0x3000 + i /* CLIP_DISTANCEi_WEBGL */); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "capability unknown without enabling the extension"); + + assertState(i); + + gl.disable(0x3000 + i /* CLIP_DISTANCEi_WEBGL */); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "capability unknown without enabling the extension"); + + assertState(i); + } + + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + debug(""); +} + +function checkEnums() { + debug(""); + debug("Check enums"); + shouldBe("ext.MAX_CLIP_DISTANCES_WEBGL", "0x0D32"); + shouldBe("ext.MAX_CULL_DISTANCES_WEBGL", "0x82F9"); + shouldBe("ext.MAX_COMBINED_CLIP_AND_CULL_DISTANCES_WEBGL", "0x82FA"); + shouldBe("ext.CLIP_DISTANCE0_WEBGL", "0x3000"); + shouldBe("ext.CLIP_DISTANCE1_WEBGL", "0x3001"); + shouldBe("ext.CLIP_DISTANCE2_WEBGL", "0x3002"); + shouldBe("ext.CLIP_DISTANCE3_WEBGL", "0x3003"); + shouldBe("ext.CLIP_DISTANCE4_WEBGL", "0x3004"); + shouldBe("ext.CLIP_DISTANCE5_WEBGL", "0x3005"); + shouldBe("ext.CLIP_DISTANCE6_WEBGL", "0x3006"); + shouldBe("ext.CLIP_DISTANCE7_WEBGL", "0x3007"); +} + +function checkQueries() { + debug(""); + debug("Check parameters"); + shouldBeGreaterThanOrEqual('gl.getParameter(ext.MAX_CLIP_DISTANCES_WEBGL)', '8'); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + const maxCullDistances = gl.getParameter(ext.MAX_CULL_DISTANCES_WEBGL); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + if (maxCullDistances == 0) { + testPassed("No cull distance support"); + shouldBe("gl.getParameter(ext.MAX_COMBINED_CLIP_AND_CULL_DISTANCES_WEBGL)", "0"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + } else if (maxCullDistances >= 8) { + testPassed("Optional cull distance support"); + shouldBeGreaterThanOrEqual("gl.getParameter(ext.MAX_COMBINED_CLIP_AND_CULL_DISTANCES_WEBGL)", "8"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + } else { + testFailed("Invalid number of supported cull distances"); + } + + debug(""); + debug("Check clip distance capabilities"); + + const assertState = (i, s) => { + shouldBe(`gl.isEnabled(${0x3000 + i} /* CLIP_DISTANCE${i}_WEBGL */)`, s ? "true" : "false"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + shouldBe(`gl.getParameter(${0x3000 + i} /* CLIP_DISTANCE${i}_WEBGL */)`, s ? "true" : "false"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + }; + + for (let i = 0; i < 8; i++) { + assertState(i, false); + + gl.enable(ext.CLIP_DISTANCE0_WEBGL + i); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + assertState(i, true); + + gl.disable(ext.CLIP_DISTANCE0_WEBGL + i); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + assertState(i, false); + } +} + +function checkClipDistance() { + debug(""); + debug("Check clip distance operation"); + + const vs = `#version 300 es +#extension GL_ANGLE_clip_cull_distance : require + +uniform vec4 u_plane; +in vec2 a_position; +void main() +{ + gl_Position = vec4(a_position, 0.0, 1.0); + gl_ClipDistance[0] = dot(gl_Position, u_plane); +}`; + + const program = wtu.setupProgram(gl, [vs, wtu.simpleColorFragmentShaderESSL300]); + gl.useProgram(program); + gl.uniform4fv(gl.getUniformLocation(program, 'u_color'), [1.0, 0.0, 0.0, 1.0]); + + gl.enable(ext.CLIP_DISTANCE0_WEBGL); + + // Clear to blue + gl.clearColor(0, 0, 1, 1); + gl.clear(gl.COLOR_BUFFER_BIT); + + wtu.setupUnitQuad(gl); + + // Draw full screen quad with color red + gl.uniform4f(gl.getUniformLocation(program, "u_plane"), 1, 0, 0, 0.5); + wtu.drawUnitQuad(gl); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + // All pixels on the left of the plane x = -0.5 must be blue + let x = 0; + let y = 0; + let width = w / 4 - 1; + let height = h; + wtu.checkCanvasRect(gl, x, y, width, height, + [0, 0, 255, 255], "should be blue"); + + // All pixels on the right of the plane x = -0.5 must be red + x = w / 4 + 2; + y = 0; + width = w - x; + height = h; + wtu.checkCanvasRect(gl, x, y, width, height, + [255, 0, 0, 255], "should be red"); + + // Clear to green + gl.clearColor(0, 1, 0, 1); + gl.clear(gl.COLOR_BUFFER_BIT); + + // Draw full screen quad with color red + gl.uniform4f(gl.getUniformLocation(program, "u_plane"), -1, 0, 0, -0.5); + wtu.drawUnitQuad(gl); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + // All pixels on the left of the plane x = -0.5 must be red + x = 0; + y = 0; + width = w / 4 - 1; + height = h; + wtu.checkCanvasRect(gl, x, y, width, height, + [255, 0, 0, 255], "should be red"); + + // All pixels on the right of the plane x = -0.5 must be green + x = w / 4 + 2; + y = 0; + width = w - x; + height = h; + wtu.checkCanvasRect(gl, x, y, width, height, + [0, 255, 0, 255], "should be green"); + + // Disable CLIP_DISTANCE0 and draw again + gl.disable(ext.CLIP_DISTANCE0_WEBGL); + wtu.drawUnitQuad(gl); + + // All pixels must be red + wtu.checkCanvas(gl, [255, 0, 0, 255], "should be red"); +} + +function checkClipDistanceInterpolation() { + debug(""); + debug("Check clip distance interpolation"); + + const vs = `#version 300 es +#extension GL_ANGLE_clip_cull_distance : require +in vec2 a_position; +void main() +{ + gl_Position = vec4(a_position, 0.0, 1.0); + gl_ClipDistance[0] = dot(gl_Position, vec4( 1, 0, 0, 0.5)); + gl_ClipDistance[1] = dot(gl_Position, vec4(-1, 0, 0, 0.5)); + gl_ClipDistance[2] = dot(gl_Position, vec4( 0, 1, 0, 0.5)); + gl_ClipDistance[3] = dot(gl_Position, vec4( 0, -1, 0, 0.5)); + gl_ClipDistance[4] = gl_ClipDistance[0]; + gl_ClipDistance[5] = gl_ClipDistance[1]; + gl_ClipDistance[6] = gl_ClipDistance[2]; + gl_ClipDistance[7] = gl_ClipDistance[3]; +}`; + + const fs = `#version 300 es +#extension GL_ANGLE_clip_cull_distance : require +precision highp float; +out vec4 my_FragColor; +void main() +{ + float r = gl_ClipDistance[0] + gl_ClipDistance[1]; + float g = gl_ClipDistance[2] + gl_ClipDistance[3]; + float b = gl_ClipDistance[4] + gl_ClipDistance[5]; + float a = gl_ClipDistance[6] + gl_ClipDistance[7]; + my_FragColor = vec4(r, g, b, a) * 0.5; +}`; + + const program = wtu.setupProgram(gl, [vs, fs]); + gl.useProgram(program); + + gl.enable(ext.CLIP_DISTANCE0_WEBGL); + gl.enable(ext.CLIP_DISTANCE1_WEBGL); + gl.enable(ext.CLIP_DISTANCE2_WEBGL); + gl.enable(ext.CLIP_DISTANCE3_WEBGL); + gl.enable(ext.CLIP_DISTANCE4_WEBGL); + gl.enable(ext.CLIP_DISTANCE5_WEBGL); + gl.enable(ext.CLIP_DISTANCE6_WEBGL); + gl.enable(ext.CLIP_DISTANCE7_WEBGL); + + wtu.setupUnitQuad(gl); + + // Clear to blue + gl.clearColor(0, 0, 1, 1); + gl.clear(gl.COLOR_BUFFER_BIT); + + // Draw full screen quad with color gray + wtu.drawUnitQuad(gl); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + const data = new Uint8Array(w * h * 4); + gl.readPixels(0, 0, w, h, gl.RGBA, gl.UNSIGNED_BYTE, data); + let passed = true; + for (let x = 0; x < w; x++) { + for (let y = 0; y < h; y++) { + const currentPosition = (y * h + x) * 4; + const inside = (x >= w / 4 && x < w * 3 / 4 && y >= h / 4 && y < h * 3 / 4); + const expected = inside ? [127, 127, 127, 127] : [0, 0, 255, 255]; + const actual = data.slice(currentPosition, currentPosition + 4); + if (Math.abs(actual[0] - expected[0]) > 1 || + Math.abs(actual[1] - expected[1]) > 1 || + Math.abs(actual[2] - expected[2]) > 1 || + Math.abs(actual[3] - expected[3]) > 1) { + passed = false; + } + } + } + if (passed) { + testPassed("Correct clip distance interpolation"); + } else { + testFailed("Incorrect clip distance interpolation"); + } +} + +function checkCullDistance() { + debug(""); + debug("Check cull distance operation"); + + if (gl.getParameter(ext.MAX_CULL_DISTANCES_WEBGL) == 0) { + testPassed("No cull distance support"); + return; + } + + const vs = `#version 300 es +#extension GL_ANGLE_clip_cull_distance : require + +uniform vec4 u_plane; +in vec2 a_position; +void main() +{ + gl_Position = vec4(a_position, 0.0, 1.0); + gl_CullDistance[0] = dot(gl_Position, u_plane); +}`; + + const program = wtu.setupProgram(gl, [vs, wtu.simpleColorFragmentShaderESSL300]); + gl.useProgram(program); + gl.uniform4fv(gl.getUniformLocation(program, 'u_color'), [1.0, 0.0, 0.0, 1.0]); + + // Clear to blue + gl.clearColor(0, 0, 1, 1); + gl.clear(gl.COLOR_BUFFER_BIT); + + wtu.setupUnitQuad(gl); + + // Draw full screen quad with color red + gl.uniform4f(gl.getUniformLocation(program, "u_plane"), 1, 0, 0, 0.5); + wtu.drawUnitQuad(gl); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + // All pixels must be red + wtu.checkCanvas(gl, [255, 0, 0, 255], "should be red"); + + // Clear to green + gl.clearColor(0, 1, 0, 1); + gl.clear(gl.COLOR_BUFFER_BIT); + + // Draw full screen quad with color red + gl.uniform4f(gl.getUniformLocation(program, "u_plane"), -1, 1, 0, -0.5); + wtu.drawUnitQuad(gl); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + // All pixels above the y > x line must be red + const data = new Uint8Array(w * h * 4); + gl.readPixels(0, 0, w, h, gl.RGBA, gl.UNSIGNED_BYTE, data); + let passed = true; + for (let x = 0; x < w; ++x) { + for (let y = 0; y < h; ++y) { + if (y <= x + 2 && y >= x - 2) continue; // skip the edge + const currentPosition = (y * h + x) * 4; + const actual = data.slice(currentPosition, currentPosition + 2); + const expected = (y > x) ? [255, 0] : [0, 255]; + if (actual[0] != expected[0] || actual[1] != expected[1]) { + passed = false; + } + } + } + if (passed) { + testPassed("Correct cull distance operation"); + } else { + testFailed("Incorrect cull distance operation"); + } +} + +function checkCullDistanceInterpolation() { + debug(""); + debug("Check cull distance interpolation"); + + if (gl.getParameter(ext.MAX_CULL_DISTANCES_WEBGL) == 0) { + testPassed("No cull distance support"); + return; + } + + const vs = `#version 300 es +#extension GL_ANGLE_clip_cull_distance : require +in vec2 a_position; +void main() +{ + gl_Position = vec4(a_position, 0.0, 1.0); + gl_CullDistance[0] = dot(gl_Position, vec4( 1, 0, 0, 1)); + gl_CullDistance[1] = dot(gl_Position, vec4(-1, 0, 0, 1)); + gl_CullDistance[2] = dot(gl_Position, vec4( 0, 1, 0, 1)); + gl_CullDistance[3] = dot(gl_Position, vec4( 0, -1, 0, 1)); + gl_CullDistance[4] = gl_CullDistance[0]; + gl_CullDistance[5] = gl_CullDistance[1]; + gl_CullDistance[6] = gl_CullDistance[2]; + gl_CullDistance[7] = gl_CullDistance[3]; +}`; + + const fs = `#version 300 es +#extension GL_ANGLE_clip_cull_distance : require +precision highp float; +out vec4 my_FragColor; +void main() +{ + float r = gl_CullDistance[0] + gl_CullDistance[1]; + float g = gl_CullDistance[2] + gl_CullDistance[3]; + float b = gl_CullDistance[4] + gl_CullDistance[5]; + float a = gl_CullDistance[6] + gl_CullDistance[7]; + my_FragColor = vec4(r, g, b, a) * 0.25; +}`; + + const program = wtu.setupProgram(gl, [vs, fs]); + gl.useProgram(program); + + // Clear to blue + gl.clearColor(0, 0, 1, 1); + gl.clear(gl.COLOR_BUFFER_BIT); + + wtu.setupQuad(gl, {scale: 0.5}); + + // Draw a small quad with color gray + wtu.drawUnitQuad(gl); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + const data = new Uint8Array(w * h * 4); + gl.readPixels(0, 0, w, h, gl.RGBA, gl.UNSIGNED_BYTE, data); + let passed = true; + for (let x = 0; x < w; x++) { + for (let y = 0; y < h; y++) { + const currentPosition = (y * h + x) * 4; + const inside = (x >= w / 4 && x < w * 3 / 4 && y >= h / 4 && y < h * 3 / 4); + const expected = inside ? [127, 127, 127, 127] : [0, 0, 255, 255]; + const actual = data.slice(currentPosition, currentPosition + 4); + if (Math.abs(actual[0] - expected[0]) > 1 || + Math.abs(actual[1] - expected[1]) > 1 || + Math.abs(actual[2] - expected[2]) > 1 || + Math.abs(actual[3] - expected[3]) > 1) { + passed = false; + } + } + } + if (passed) { + testPassed("Correct cull distance interpolation"); + } else { + testFailed("Incorrect cull distance interpolation"); + } +} + +function runTestExtension() { + checkEnums(); + checkQueries(); + + checkClipDistance(); + checkClipDistanceInterpolation(); + + checkCullDistance(); + checkCullDistanceInterpolation(); +} + +function runTest() { + if (!gl) { + testFailed("context does not exist"); + } else { + testPassed("context exists"); + + runTestNoExtension(); + + ext = gl.getExtension("WEBGL_clip_cull_distance"); + + wtu.runExtensionSupportedTest(gl, "WEBGL_clip_cull_distance", ext !== null); + + if (ext !== null) { + runTestExtension(); + } else { + testPassed("No WEBGL_clip_cull_distance support -- this is legal"); + } + } +} + +runTest(); + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl-provoking-vertex.html b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl-provoking-vertex.html new file mode 100644 index 0000000000..3737409b3a --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl-provoking-vertex.html @@ -0,0 +1,165 @@ +<!-- +Copyright (c) 2022 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL WEBGL_provoking_vertex Conformance Tests</title> +<LINK rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<canvas width="16" height="16" id="c"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description("This test verifies the functionality of the WEBGL_provoking_vertex extension, if it is available."); + +debug(""); + +var wtu = WebGLTestUtils; +var gl = wtu.create3DContext("c", null, 2); +var ext; + +function runTestNoExtension() { + debug(""); + debug("Check getParameter without the extension"); + shouldBeNull("gl.getParameter(0x8E4F /* PROVOKING_VERTEX_WEBGL */)"); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension"); + debug(""); +} + +function runTestExtension() { + debug(""); + debug("Check enums"); + shouldBe("ext.FIRST_VERTEX_CONVENTION_WEBGL", "0x8E4D"); + shouldBe("ext.LAST_VERTEX_CONVENTION_WEBGL", "0x8E4E"); + shouldBe("ext.PROVOKING_VERTEX_WEBGL", "0x8E4F"); + + debug(""); + debug("Check default state"); + shouldBe("gl.getParameter(ext.PROVOKING_VERTEX_WEBGL)", "ext.LAST_VERTEX_CONVENTION_WEBGL"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "parameter known with the extension enabled"); + + debug(""); + debug("Check state updates"); + ext.provokingVertexWEBGL(ext.FIRST_VERTEX_CONVENTION_WEBGL); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "provokingVertexWEBGL(ext.FIRST_VERTEX_CONVENTION_WEBGL) generates no errors"); + shouldBe("gl.getParameter(ext.PROVOKING_VERTEX_WEBGL)", "ext.FIRST_VERTEX_CONVENTION_WEBGL"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR); + ext.provokingVertexWEBGL(ext.LAST_VERTEX_CONVENTION_WEBGL); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "provokingVertexWEBGL(ext.LAST_VERTEX_CONVENTION_WEBGL) generates no errors"); + shouldBe("gl.getParameter(ext.PROVOKING_VERTEX_WEBGL)", "ext.LAST_VERTEX_CONVENTION_WEBGL"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR); + + debug(""); + debug("Check invalid provoking vertex mode"); + ext.provokingVertexWEBGL(ext.FIRST_VERTEX_CONVENTION_WEBGL); + ext.provokingVertexWEBGL(ext.PROVOKING_VERTEX_WEBGL); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "invalid provoking mode generates an error"); + shouldBe("gl.getParameter(ext.PROVOKING_VERTEX_WEBGL)", "ext.FIRST_VERTEX_CONVENTION_WEBGL"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR); + + debug(""); + debug("Check provoking vertex operation"); + + const vs = `#version 300 es + in int intAttrib; + in vec2 position; + flat out int attrib; + void main() { + gl_Position = vec4(position, 0, 1); + attrib = intAttrib; + }`; + + const fs = `#version 300 es + flat in int attrib; + out int fragColor; + void main() { + fragColor = attrib; + }`; + + const program = wtu.setupProgram(gl, [vs, fs]); + gl.useProgram(program); + + const tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + gl.texStorage2D(gl.TEXTURE_2D, 1, gl.R32I, 16, 16); + + const fb = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0); + + const vb = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, vb); + const buf = new ArrayBuffer(36); + new Float32Array(buf, 0, 6).set([-1.0, -1.0, 3.0, -1.0, -1.0, 3.0]); + new Int32Array(buf, 24, 3).set([1, 2, 3]); + gl.bufferData(gl.ARRAY_BUFFER, buf, gl.STATIC_DRAW); + + const positionLocation = gl.getAttribLocation(program, "position"); + gl.enableVertexAttribArray(positionLocation); + gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0); + + const intAttribLocation = gl.getAttribLocation(program, "intAttrib"); + gl.enableVertexAttribArray(intAttribLocation); + gl.vertexAttribIPointer(intAttribLocation, 1, gl.INT, 0, 24); + + const pixel = new Int32Array(4); + + ext.provokingVertexWEBGL(ext.LAST_VERTEX_CONVENTION_WEBGL); + gl.clearBufferiv(gl.COLOR, 0, new Int32Array(4)); + gl.drawArrays(gl.TRIANGLES, 0, 3); + gl.readPixels(0, 0, 1, 1, gl.RGBA_INTEGER, gl.INT, pixel); + + if (pixel[0] == 3) { + testPassed("Correct last provoking vertex"); + } else { + testFailed("Incorrect last provoking vertex"); + } + + ext.provokingVertexWEBGL(ext.FIRST_VERTEX_CONVENTION_WEBGL); + gl.clearBufferiv(gl.COLOR, 0, new Int32Array(4)); + gl.drawArrays(gl.TRIANGLES, 0, 3); + gl.readPixels(0, 0, 1, 1, gl.RGBA_INTEGER, gl.INT, pixel); + + if (pixel[0] == 1) { + testPassed("Correct first provoking vertex"); + } else { + testFailed("Incorrect first provoking vertex"); + } +} + +function runTest() { + if (!gl) { + testFailed("context does not exist"); + } else { + testPassed("context exists"); + + runTestNoExtension(); + + ext = gl.getExtension("WEBGL_provoking_vertex"); + + wtu.runExtensionSupportedTest(gl, "WEBGL_provoking_vertex", ext !== null); + + if (ext !== null) { + runTestExtension(); + } else { + testPassed("No WEBGL_provoking_vertex support -- this is legal"); + } + } +} + +runTest(); + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl-render-shared-exponent.html b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl-render-shared-exponent.html new file mode 100644 index 0000000000..11d505fcc6 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl-render-shared-exponent.html @@ -0,0 +1,251 @@ +<!-- +Copyright (c) 2023 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL WEBGL_render_shared_exponent Conformance Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description("This test verifies the functionality of the WEBGL_render_shared_exponent extension, if it is available."); + +debug(""); + +var wtu = WebGLTestUtils; +var gl = wtu.create3DContext(null, null, 2); +var ext; +const color = [64.0, 32.0, 16.0, 1.0]; + +function drawTest() { + wtu.clearAndDrawUnitQuad(gl); + + wtu.checkCanvasRect(gl, 0, 0, 1, 1, color, + "reading with the RGBA format and FLOAT type", 1, + new Float32Array(4), gl.FLOAT, gl.RGBA); + + const implementationType = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE); + const implementationFormat = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT); + if (implementationFormat == gl.RGB && implementationType == gl.UNSIGNED_INT_5_9_9_9_REV) { + // Shared exponent value may be implementation + // specific, so compare decoded values. + const value = new Uint32Array(1); + gl.readPixels(0, 0, 1, 1, gl.RGB, gl.UNSIGNED_INT_5_9_9_9_REV, value); + wtu.glErrorShouldBe(gl, gl.NO_ERROR); + + let r = (value >> 0) & 0x1FF; + let g = (value >> 9) & 0x1FF; + let b = (value >> 18) & 0x1FF; + let e = (value >> 27) & 0x01F; + debug(`Raw value: 0x${value[0].toString(16).toUpperCase()}, ` + + `Raw components: R = ${r}, G = ${g}, B = ${b}, E = ${e}`); + + e = Math.pow(2, e - 24); + r *= e; + g *= e; + b *= e; + debug(`Decoded color: (${r}, ${g}, ${b})`); + + if (r == color[0] && g == color[1] && b == color[2]) { + testPassed("reading with the exact format/type"); + } else { + testFailed("reading with the exact format/type"); + } + } +} + +function renderbufferTest(isSupported) { + debug(""); + debug(`RGB9_E5 renderbuffer: ` + + `${!isSupported ? "NOT " : ""}supported`); + + const rbo = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rbo); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGB9_E5, 1, 1); + if (!isSupported) { + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "renderbuffer allocation failed"); + return; + } + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "renderbuffer allocation succeeded"); + + const fbo = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo); + + wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE); + + drawTest(); +} + +function textureTest(isRenderable) { + debug(""); + debug(`RGB9_E5 texture: ` + + `${!isRenderable ? "NOT " : ""}renderable`); + + const tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB9_E5, 1, 1, 0, gl.RGB, gl.UNSIGNED_INT_5_9_9_9_REV, null); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texture allocation succeeded"); + + const fbo = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0); + + if (!isRenderable) { + wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT); + return; + } + wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE); + + drawTest(); +} + +function formatTest(isEnabled) { + const program = wtu.setupProgram(gl, [wtu.simpleVertexShader, + wtu.simpleColorFragmentShader]); + gl.useProgram(program); + gl.uniform4fv(gl.getUniformLocation(program, "u_color"), color); + + wtu.setupUnitQuad(gl); + + renderbufferTest(isEnabled); + textureTest(isEnabled); +} + +function colorMaskTest() { + debug(""); + debug("Test color write masks with shared exponent color buffers"); + + const fs = `#version 300 es + precision highp float; + layout(location = 0) out vec4 color0; + layout(location = 1) out vec4 color1; + void main() { + color0 = vec4(1.0, 0.0, 0.0, 1.0); + color1 = vec4(0.0, 1.0, 0.0, 1.0); + }`; + const program = wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, fs]); + gl.useProgram(program); + + const fbo = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + + const rb0 = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rb0); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGB9_E5, 4, 4); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb0); + + const rb1 = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rb1); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, 4, 4); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.RENDERBUFFER, rb1); + + wtu.glErrorShouldBe(gl, gl.NO_ERROR); + wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE); + + const clearValue = new Float32Array(4); + const dbiExt = gl.getExtension("OES_draw_buffers_indexed"); + + function expectError(enabled, effectiveMask, operation) { + if (!enabled || + effectiveMask == 0x0 /* 0000 */ || + effectiveMask == 0x8 /* 000A */ || + effectiveMask == 0x7 /* RGB0 */ || + effectiveMask == 0xF /* RGBA */ ) { + wtu.glErrorShouldBe(gl, gl.NO_ERROR, operation); + } else { + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, operation); + } + } + + function runOps(enabled, mask0) { + wtu.drawUnitQuad(gl); + expectError(enabled, mask0, "draw"); + + gl.clear(gl.COLOR_BUFFER_BIT); + expectError(enabled, mask0, "clear"); + + gl.clearBufferfv(gl.COLOR, 0, clearValue); + expectError(enabled, mask0, "clearBufferfv(RGB9_E5)"); + gl.clearBufferfv(gl.COLOR, 1, clearValue); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "clearBufferfv(RGBA8)"); + } + + for (let mask = 0; mask < 16; mask++) { + for (const enabled of [false, true]) { + debug(""); + debug(`Setting common color mask ` + + `${mask & 1 ? "R" : "0"}` + + `${mask & 2 ? "G" : "0"}` + + `${mask & 4 ? "B" : "0"}` + + `${mask & 8 ? "A" : "0"}` + + " with RGB9_E5 attachment " + + (enabled ? "enabled" : "disabled")); + gl.colorMask(mask & 1, mask & 2, mask & 4, mask & 8); + gl.drawBuffers([enabled ? gl.COLOR_ATTACHMENT0 : gl.NONE, + gl.COLOR_ATTACHMENT1]); + + runOps(enabled, mask); + + if (dbiExt) { + debug("Setting incompatible color mask on unused draw buffer") + dbiExt.colorMaskiOES(2, true, false, false, false); + runOps(enabled, mask); // common mask remains on draw buffer 0 + + debug("Setting incompatible color mask on RGBA8 draw buffer") + dbiExt.colorMaskiOES(1, true, false, false, false); + runOps(enabled, mask); // common mask remains on draw buffer 0 + + debug("Setting incompatible color mask on RGB9_E5 draw buffer") + dbiExt.colorMaskiOES(0, true, false, false, false); + runOps(enabled, 1); // overridden + + debug("Setting compatible color mask on RGB9_E5 draw buffer") + dbiExt.colorMaskiOES(0, true, true, true, false); + runOps(enabled, 7); // overridden + } + } + } +} + +function runTest() { + if (!gl) { + testFailed("context does not exist"); + return; + } + testPassed("context exists"); + + debug(""); + debug("Testing shared exponent rendering with extension disabled"); + formatTest(false); + + ext = gl.getExtension("WEBGL_render_shared_exponent"); + wtu.runExtensionSupportedTest(gl, "WEBGL_render_shared_exponent", ext !== null); + + if (ext !== null) { + debug(""); + debug("Testing shared exponent rendering with extension enabled"); + formatTest(true); + colorMaskTest(); + } else { + testPassed("No WEBGL_render_shared_exponent support -- this is legal"); + } +} + +runTest(); + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl-shader-pixel-local-storage.html b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl-shader-pixel-local-storage.html new file mode 100644 index 0000000000..e548eea46c --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl-shader-pixel-local-storage.html @@ -0,0 +1,445 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL WEBGL_shader_pixel_local_storage Conformance Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/desktop-gl-constants.js"></script> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +<script src="../../js/tests/compositing-test.js"></script> +<script src="../../js/tests/invalid-vertex-attrib-test.js"></script> +</head> +<body> +<div id="description"></div> +<canvas id="canvas" width="128" height="128" style="background-color:#080"> </canvas> +<canvas id="canvas_no_alpha" width="128" height="128"> </canvas> +<div id="console"></div> +<script> +"use strict"; +description("This test verifies the functionality of the WEBGL_shader_pixel_local_storage " + + "extension, if it is available."); + +const wtu = WebGLTestUtils; +const canvas = document.getElementById("canvas"); +const gl = wtu.create3DContext(canvas, {alpha: true}, 2); +const gl_no_alpha = wtu.create3DContext("canvas_no_alpha", {alpha: false}, 2); +let pls = null; + +// Outputs a fullscreen quad from a 4-vertex triangle strip. +const fullscreenQuadVertexShader = `#version 300 es +void main() { + gl_Position.x = (gl_VertexID & 1) == 0 ? -1. : 1.; + gl_Position.y = (gl_VertexID & 2) == 0 ? -1. : 1.; + gl_Position.zw = vec2(0, 1); +}`; + +function arraysEqual(a, b) { + if (typeof a !== typeof b) + return false; + if (a.length != b.length) + return false; + for (let i = 0; i < a.length; ++i) { + if (a[i] !== b[i]) + return false; + } + return true; +} + +async function runTest() { + if (!gl) { + testFailed("WebGL2 context does not exist"); + finishTest(); + return; + } + + debug("\nCheck the behavior surrounding WEBGL_shader_pixel_local_storage being enabled."); + checkExtensionNotSupportedWhenDisabled(); + checkDependencyExtensionsEnabled(false); + debug("Enable WEBGL_shader_pixel_local_storage."); + pls = gl.getExtension("WEBGL_shader_pixel_local_storage"); + wtu.runExtensionSupportedTest(gl, "WEBGL_shader_pixel_local_storage", pls != null); + if (!pls) { + finishTest(); + return; + } + checkDependencyExtensionsEnabled(true); + + checkImplementationDependentLimits(); + checkInitialValues(); + checkWebGLNonNormativeBehavior(); + + await checkRendering(gl); + await checkRendering(gl_no_alpha); + + finishTest(); +} + +function checkExtensionNotSupportedWhenDisabled() { + debug("\nCheck that a context does not support WEBGL_shader_pixel_local_storage before it is " + + "enabled"); + shouldBeNull("gl.getParameter(0x96E0 /*MAX_PIXEL_LOCAL_STORAGE_PLANES_WEBGL*/)"); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension"); + shouldBeNull( + "gl.getParameter(0x96E1 /*MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE_WEBGL*/)"); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension"); + shouldBeNull( + "gl.getParameter(0x96E2 /*MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES_WEBGL*/)"); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension"); + shouldBeNull( + "gl.getParameter(0x96E3 /*PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL*/)"); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension"); + wtu.glErrorShouldBe(gl, gl.NONE); +} + +function checkDependencyExtensionsEnabled(enabled) { + debug("\nCheck that dependency extensions of WEBGL_shader_pixel_local_storage are " + + (enabled ? "enabled" : "disabled")); + if (wtu.getSupportedExtensionWithKnownPrefixes(gl, "OES_draw_buffers_indexed") !== undefined) { + gl.getIndexedParameter(gl.BLEND_EQUATION_RGB, 1); + wtu.glErrorShouldBe(gl, enabled ? gl.NONE : gl.INVALID_ENUM, + "OES_draw_buffers_indexed not enabled or disabled as expected"); + } + if (wtu.getSupportedExtensionWithKnownPrefixes(gl, "EXT_color_buffer_float") !== undefined) { + gl.bindRenderbuffer(gl.RENDERBUFFER, gl.createRenderbuffer()); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.R32F, 1, 1); + wtu.glErrorShouldBe(gl, enabled ? gl.NONE : gl.INVALID_ENUM, + "EXT_color_buffer_float not enabled or disabled as expected"); + gl.bindRenderbuffer(gl.RENDERBUFFER, null); + } + if (wtu.getSupportedExtensionWithKnownPrefixes(gl, "EXT_color_buffer_half_float") !== undefined) { + gl.bindRenderbuffer(gl.RENDERBUFFER, gl.createRenderbuffer()); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.RG16F, 1, 1); + wtu.glErrorShouldBe(gl, enabled ? gl.NONE : gl.INVALID_ENUM, + "EXT_color_buffer_half_float not enabled or disabled as expected"); + gl.bindRenderbuffer(gl.RENDERBUFFER, null); + } +} + +function checkImplementationDependentLimits() { + debug("\nVerify conformant implementation-dependent PLS limits."); + window.MAX_PIXEL_LOCAL_STORAGE_PLANES = + gl.getParameter(pls.MAX_PIXEL_LOCAL_STORAGE_PLANES_WEBGL); + window.MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE = + gl.getParameter(pls.MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE_WEBGL); + window.MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES = + gl.getParameter(pls.MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES_WEBGL); + wtu.glErrorShouldBe(gl, gl.NONE, "Pixel local storage queries should be supported."); + + window.MAX_COLOR_ATTACHMENTS = gl.getParameter(gl.MAX_COLOR_ATTACHMENTS); + window.MAX_DRAW_BUFFERS = gl.getParameter(gl.MAX_DRAW_BUFFERS); + + // Table 6.X: Impementation Dependent Pixel Local Storage Limits. + shouldBeTrue("MAX_PIXEL_LOCAL_STORAGE_PLANES >= 4"); + shouldBeTrue("MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE >= 0"); + shouldBeTrue("MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES >= 4"); + + // Logical deductions based on 6.X. + shouldBeTrue(`MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES >= + MAX_PIXEL_LOCAL_STORAGE_PLANES`); + shouldBeTrue(`MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES >= + MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE`); + shouldBeTrue(`MAX_COLOR_ATTACHMENTS + MAX_PIXEL_LOCAL_STORAGE_PLANES >= + MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES`); + shouldBeTrue(`MAX_DRAW_BUFFERS + MAX_PIXEL_LOCAL_STORAGE_PLANES >= + MAX_COMBINED_DRAW_BUFFERS_AND_PIXEL_LOCAL_STORAGE_PLANES`); +} + +function checkInitialValues() { + debug("\nCheck that PLS state has the correct initial values."); + shouldBeTrue("gl.getParameter(pls.PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL) == 0"); + wtu.glErrorShouldBe( + gl, gl.NONE, + "It's valid to query GL_PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL even when fbo 0 is bound."); + + // Table 6.Y: Pixel Local Storage State + gl.bindFramebuffer(gl.FRAMEBUFFER, gl.createFramebuffer()); + shouldBeTrue("gl.getParameter(pls.PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL) == 0"); + debug("Check the initial clear values for each plane."); + const MAX_PIXEL_LOCAL_STORAGE_PLANES = + gl.getParameter(pls.MAX_PIXEL_LOCAL_STORAGE_PLANES_WEBGL); + for (let i = 0; i < MAX_PIXEL_LOCAL_STORAGE_PLANES; ++i) + { + expectTrue(pls.getFramebufferPixelLocalStorageParameterWEBGL( + i, pls.PIXEL_LOCAL_FORMAT_WEBGL) == gl.NONE); + expectTrue(pls.getFramebufferPixelLocalStorageParameterWEBGL( + i, pls.PIXEL_LOCAL_TEXTURE_NAME_WEBGL) == null); + expectTrue(pls.getFramebufferPixelLocalStorageParameterWEBGL( + i, pls.PIXEL_LOCAL_TEXTURE_LEVEL_WEBGL) == 0); + expectTrue(pls.getFramebufferPixelLocalStorageParameterWEBGL( + i, pls.PIXEL_LOCAL_TEXTURE_LAYER_WEBGL) == 0); + expectTrue(arraysEqual( + pls.getFramebufferPixelLocalStorageParameterWEBGL( + i, pls.PIXEL_LOCAL_CLEAR_VALUE_FLOAT_WEBGL), + new Float32Array([0, 0, 0, 0]))); + expectTrue(arraysEqual( + pls.getFramebufferPixelLocalStorageParameterWEBGL( + i, pls.PIXEL_LOCAL_CLEAR_VALUE_INT_WEBGL), + new Int32Array([0, 0, 0, 0]))); + expectTrue(arraysEqual( + pls.getFramebufferPixelLocalStorageParameterWEBGL( + i, pls.PIXEL_LOCAL_CLEAR_VALUE_UNSIGNED_INT_WEBGL), + new Uint32Array([0, 0, 0, 0]))); + } + wtu.glErrorShouldBe(gl, gl.NONE); + gl.bindFramebuffer(gl.FRAMEBUFFER, null); +} + +function checkWebGLNonNormativeBehavior() { + debug("\nCheck the WebGL-specific behavior not found in the " + + "ANGLE_shader_pixel_local_storage specification."); + gl.bindFramebuffer(gl.FRAMEBUFFER, gl.createFramebuffer()); + + debug("If 'texture' has been deleted, generates an INVALID_OPERATION error."); + wtu.glErrorShouldBe(gl, gl.NONE); + const tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, 1, 1); + wtu.glErrorShouldBe(gl, gl.NONE); + gl.deleteTexture(tex); + pls.framebufferTexturePixelLocalStorageWEBGL(0, tex, 0, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION); + + debug("\nIf 'texture' was generated by a different WebGL2RenderingContext than this one, " + + "generates an INVALID_OPERATION error."); + const gl2 = wtu.create3DContext(null, null, 2); + const tex2 = gl2.createTexture(); + gl2.bindTexture(gl2.TEXTURE_2D, tex2); + gl2.texStorage2D(gl2.TEXTURE_2D, 1, gl2.RGBA8, 1, 1); + pls.framebufferTexturePixelLocalStorageWEBGL(0, tex2, 0, 0); + wtu.glErrorShouldBe(gl2, gl2.NONE); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION); + + debug("\nIf value has less than srcOffset + 4 elements, generates an INVALID_VALUE error."); + wtu.glErrorShouldBe(gl, gl.NONE); + pls.framebufferPixelLocalClearValuefvWEBGL(0, new Float32Array(3)); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE); + pls.framebufferPixelLocalClearValuefvWEBGL(1, [0, 0, 0]); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE); + pls.framebufferPixelLocalClearValueivWEBGL(2, new Int32Array(3)); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE); + pls.framebufferPixelLocalClearValueivWEBGL(3, [0, 0, 0]); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE); + pls.framebufferPixelLocalClearValueuivWEBGL(4, new Uint32Array(3)); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE); + pls.framebufferPixelLocalClearValueuivWEBGL(3, [0, 0, 0]); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE); + pls.framebufferPixelLocalClearValuefvWEBGL(2, new Float32Array(5), 2); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE); + pls.framebufferPixelLocalClearValuefvWEBGL(1, [0, 0, 0, 0, 0], 2); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE); + pls.framebufferPixelLocalClearValueivWEBGL(0, new Int32Array(5), 2); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE); + pls.framebufferPixelLocalClearValueivWEBGL(1, [0, 0, 0, 0, 0], 2); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE); + pls.framebufferPixelLocalClearValueuivWEBGL(2, new Uint32Array(5), 2); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE); + pls.framebufferPixelLocalClearValueuivWEBGL(3, [0, 0, 0, 0, 0], 2); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE); + + debug("\nCheck that srcOffset works properly."); + const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + pls.framebufferPixelLocalClearValuefvWEBGL(0, new Float32Array(arr), 1); + wtu.glErrorShouldBe(gl, gl.NONE); + shouldBeTrue(`arraysEqual(pls.getFramebufferPixelLocalStorageParameterWEBGL( + 0, pls.PIXEL_LOCAL_CLEAR_VALUE_FLOAT_WEBGL), + new Float32Array([1, 2, 3, 4]))`); + pls.framebufferPixelLocalClearValuefvWEBGL(1, arr, 2); + wtu.glErrorShouldBe(gl, gl.NONE); + shouldBeTrue(`arraysEqual(pls.getFramebufferPixelLocalStorageParameterWEBGL( + 1, pls.PIXEL_LOCAL_CLEAR_VALUE_FLOAT_WEBGL), + [2, 3, 4, 5])`); + pls.framebufferPixelLocalClearValueivWEBGL(2, new Int32Array(arr), 3); + wtu.glErrorShouldBe(gl, gl.NONE); + shouldBeTrue(`arraysEqual(pls.getFramebufferPixelLocalStorageParameterWEBGL( + 2, pls.PIXEL_LOCAL_CLEAR_VALUE_INT_WEBGL), + new Float32Array([3, 4, 5, 6]))`); + pls.framebufferPixelLocalClearValueivWEBGL(3, arr, 4); + wtu.glErrorShouldBe(gl, gl.NONE); + shouldBeTrue(`arraysEqual(pls.getFramebufferPixelLocalStorageParameterWEBGL( + 3, pls.PIXEL_LOCAL_CLEAR_VALUE_INT_WEBGL), + [4, 5, 6, 7])`); + pls.framebufferPixelLocalClearValueuivWEBGL(2, new Uint32Array(arr), 5); + wtu.glErrorShouldBe(gl, gl.NONE); + shouldBeTrue(`arraysEqual(pls.getFramebufferPixelLocalStorageParameterWEBGL( + 2, pls.PIXEL_LOCAL_CLEAR_VALUE_UNSIGNED_INT_WEBGL), + new Uint32Array([5, 6, 7, 8]))`); + pls.framebufferPixelLocalClearValueuivWEBGL(1, arr, 6); + wtu.glErrorShouldBe(gl, gl.NONE); + shouldBeTrue(`arraysEqual(pls.getFramebufferPixelLocalStorageParameterWEBGL( + 1, pls.PIXEL_LOCAL_CLEAR_VALUE_UNSIGNED_INT_WEBGL), + [6, 7, 8, 9])`); + wtu.glErrorShouldBe(gl, gl.NONE); + + debug("\nCheck that PIXEL_LOCAL_TEXTURE_NAME_WEBGL returns a WebGLTexture."); + shouldBeTrue(`pls.getFramebufferPixelLocalStorageParameterWEBGL( + 0, pls.PIXEL_LOCAL_TEXTURE_NAME_WEBGL) === null`); + window.validTex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, validTex); + gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, 1, 1); + wtu.glErrorShouldBe(gl, gl.NONE); + pls.framebufferTexturePixelLocalStorageWEBGL(0, validTex, 0, 0); + shouldBeTrue(`pls.getFramebufferPixelLocalStorageParameterWEBGL( + 0, pls.PIXEL_LOCAL_TEXTURE_NAME_WEBGL) === validTex`); + pls.framebufferTexturePixelLocalStorageWEBGL(0, null, 0, 0); + shouldBeTrue(`pls.getFramebufferPixelLocalStorageParameterWEBGL( + 0, pls.PIXEL_LOCAL_TEXTURE_NAME_WEBGL) === null`); + + wtu.glErrorShouldBe(gl, gl.NONE); + gl.bindFramebuffer(gl.FRAMEBUFFER, null); +} + +async function checkRendering(localGL) { + const localCanvas = localGL.canvas; + const alpha = localGL.getContextAttributes().alpha; + debug("\nCheck very simple rendering with {alpha: " + alpha + "}"); + + const localPLS = localGL.getExtension("WEBGL_shader_pixel_local_storage"); + if (!localPLS) { + testFailed("localGL doesn't support pixel local storage."); + return; + } + + const tex = localGL.createTexture(); + localGL.bindTexture(localGL.TEXTURE_2D, tex); + localGL.texStorage2D(localGL.TEXTURE_2D, 1, localGL.RGBA8, localCanvas.width, localCanvas.height); + wtu.glErrorShouldBe(localGL, localGL.NONE); + + const plsFBO = localGL.createFramebuffer(); + localGL.bindFramebuffer(localGL.FRAMEBUFFER, plsFBO); + localPLS.framebufferTexturePixelLocalStorageWEBGL(0, tex, 0, 0); + wtu.glErrorShouldBe(localGL, localGL.NONE); + + localGL.viewport(0, 0, localCanvas.width, localCanvas.height); + + // Adds a uniform color into the existing color in pixel local storage. + const fs = `#version 300 es + #extension GL_ANGLE_shader_pixel_local_storage : require + precision lowp float; + uniform vec4 color; + layout(binding=0, rgba8) uniform lowp pixelLocalANGLE pls; + void main() { + vec4 newColor = color + pixelLocalLoadANGLE(pls); + pixelLocalStoreANGLE(pls, newColor); + }`; + + const program = wtu.setupProgram(localGL, [fullscreenQuadVertexShader, fs]); + if (!program) { + testFailed("Failed to compile program."); + return; + } + + localGL.useProgram(program); + const colorUniLocation = localGL.getUniformLocation(program, "color"); + wtu.glErrorShouldBe(localGL, localGL.NONE); + + // Disable color mask to ensure PLS and canvas manage their own color masks properly. + localGL.colorMask(false, true, false, true); + + // Set global variables for shouldBeTrue(). + window.localGL = localGL; + window.localPLS = localPLS; + + debug("\nCheck that pixel local storage works properly"); + localGL.disable(localGL.DITHER); + localPLS.beginPixelLocalStorageWEBGL([localPLS.LOAD_OP_ZERO_WEBGL]); + wtu.glErrorShouldBe(localGL, localGL.NONE); + shouldBeTrue("localGL.getParameter(localPLS.PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL) == 1"); + + localGL.uniform4f(colorUniLocation, 0, 1, 0, 0); + localGL.drawArrays(localGL.TRIANGLE_STRIP, 0, 4); + + localPLS.pixelLocalStorageBarrierWEBGL(); + + localGL.uniform4f(colorUniLocation, 1, 0, 0, 0); + localGL.drawArrays(localGL.TRIANGLE_STRIP, 0, 4); + + localPLS.endPixelLocalStorageWEBGL([localPLS.STORE_OP_STORE_WEBGL]); + wtu.glErrorShouldBe(localGL, localGL.NONE); + shouldBeTrue("localGL.getParameter(localPLS.PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL) == 0"); + + const readFBO = localGL.createFramebuffer(); + localGL.bindFramebuffer(localGL.READ_FRAMEBUFFER, readFBO); + localGL.framebufferTexture2D(localGL.READ_FRAMEBUFFER, localGL.COLOR_ATTACHMENT0, + localGL.TEXTURE_2D, tex, 0); + wtu.glErrorShouldBe(localGL, localGL.NONE); + wtu.checkCanvas(localGL, [255, 255, 0, 0]); + + debug("\nCheck that alpha is properly handled in the main canvas."); + localGL.bindFramebuffer(localGL.DRAW_FRAMEBUFFER, null); + localGL.blitFramebuffer(0, 0, localCanvas.width, localCanvas.height, 0, 0, localCanvas.width, + localCanvas.height, localGL.COLOR_BUFFER_BIT, localGL.NEAREST); + localGL.bindFramebuffer(localGL.FRAMEBUFFER, null); + wtu.glErrorShouldBe(localGL, localGL.NONE); + wtu.checkCanvas(localGL, [255, 255, 0, alpha ? 0 : 255]); + + localGL.bindFramebuffer(localGL.FRAMEBUFFER, plsFBO); + localPLS.beginPixelLocalStorageWEBGL([localPLS.LOAD_OP_LOAD_WEBGL]); + wtu.glErrorShouldBe(localGL, localGL.NONE); + shouldBeTrue("localGL.getParameter(localPLS.PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL) == 1"); + + debug("\nGoing down from composite."); + + // The canvas should get cleared after compositing, even if PLS is active and color mask is + // disabled. + await new Promise(resolve => wtu.waitForComposite(resolve)); + + // Reset global variables for shouldBeTrue() after await. + window.localGL = localGL; + window.localPLS = localPLS; + + debug("\nBack from composite!"); + debug("\nPLS should still be active on plsFBO even after being interrupted for compositing."); + wtu.glErrorShouldBe(localGL, localGL.NONE); + shouldBeTrue("localGL.getParameter(localPLS.PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL) == 1"); + + localGL.uniform4f(colorUniLocation, 0, 0, 1, 0); + localGL.drawArrays(localGL.TRIANGLE_STRIP, 0, 4); + + localPLS.endPixelLocalStorageWEBGL([localPLS.STORE_OP_STORE_WEBGL]); + wtu.glErrorShouldBe(localGL, localGL.NONE); + shouldBeTrue("localGL.getParameter(localPLS.PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_WEBGL) == 0"); + + debug("\nThe canvas should have gotten cleared while PLS was active."); + localGL.bindFramebuffer(localGL.FRAMEBUFFER, null); + wtu.checkCanvas(localGL, [0, 0, 0, alpha ? 0 : 255]); + + debug("\nThe additional PLS draw to plsFBO should have still worked after being interrupted " + + "for compositing."); + localGL.bindFramebuffer(localGL.READ_FRAMEBUFFER, readFBO); + wtu.checkCanvas(localGL, [255, 255, 255, 0]); + wtu.glErrorShouldBe(localGL, localGL.NONE); + + // Draws 'tex' to the canvas. + const fs2 = `#version 300 es + uniform lowp sampler2D tex; + out lowp vec4 fragColor; + void main() { + ivec2 pixelCoord = ivec2(floor(gl_FragCoord.xy)); + fragColor = texelFetch(tex, pixelCoord, 0); + }`; + + const program2 = wtu.setupProgram(localGL, [fullscreenQuadVertexShader, fs2]); + if (!program2) { + testFailed("Failed to compile program2."); + return; + } + + debug("\nBlue should still be disabled in the color mask. Alpha is not disabled but should be " + + "implicitly disabled since the canvas doesn't have alpha."); + localGL.useProgram(program2); + localGL.uniform1i(localGL.getUniformLocation(program2, "tex"), 0); + localGL.bindFramebuffer(localGL.FRAMEBUFFER, null); + localGL.drawArrays(localGL.TRIANGLE_STRIP, 0, 4); + wtu.checkCanvas(localGL, [0, 255, 0, alpha ? 0 : 255]); + + debug("\nThe client's color mask should have been preserved."); + shouldBeTrue(`arraysEqual(localGL.getParameter(localGL.COLOR_WRITEMASK), + [false, true, false, true])`); +} + +runTest(); +var successfullyParsed = true; +</script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl-stencil-texturing.html b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl-stencil-texturing.html new file mode 100644 index 0000000000..729a5bcf8a --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/extensions/webgl-stencil-texturing.html @@ -0,0 +1,279 @@ +<!-- +Copyright (c) 2023 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL WEBGL_stencil_texturing Conformance Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description("This test verifies the functionality of the WEBGL_stencil_texturing extension, if it is available."); + +debug(""); + +var wtu = WebGLTestUtils; +var gl = wtu.create3DContext(null, null, 2); +var ext; + +function runTestNoExtension() { + debug(""); + debug("Check the texture parameter without the extension"); + + const tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + + shouldBeNull("gl.getTexParameter(gl.TEXTURE_2D, 0x90EA /* DEPTH_STENCIL_TEXTURE_MODE_WEBGL */)"); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no more errors"); + + gl.texParameteri(gl.TEXTURE_2D, 0x90EA /* DEPTH_STENCIL_TEXTURE_MODE_WEBGL */, gl.DEPTH_COMPONENT); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown for texParameteri without enabling the extension"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no more errors"); + + gl.texParameterf(gl.TEXTURE_2D, 0x90EA /* DEPTH_STENCIL_TEXTURE_MODE_WEBGL */, gl.DEPTH_COMPONENT); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown for texParameterf without enabling the extension"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no more errors"); + + const sampler = gl.createSampler(); + gl.samplerParameteri(sampler, 0x90EA /* DEPTH_STENCIL_TEXTURE_MODE_WEBGL */, gl.DEPTH_COMPONENT); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown for samplerParameteri"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no more errors"); + gl.samplerParameterf(sampler, 0x90EA /* DEPTH_STENCIL_TEXTURE_MODE_WEBGL */, gl.DEPTH_COMPONENT); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown for samplerParameterf"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no more errors"); +} + +function checkEnums() { + debug(""); + debug("Check enums"); + shouldBe("ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL", "0x90EA"); + shouldBe("ext.STENCIL_INDEX_WEBGL", "0x1901"); +} + +function checkQueries() { + const tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + + debug(""); + debug("Check default texture state"); + shouldBe('gl.getTexParameter(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL)', 'gl.DEPTH_COMPONENT'); + debug(""); + debug("Check texture state updates using texParameteri"); + gl.texParameteri(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL, ext.STENCIL_INDEX_WEBGL); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + shouldBe('gl.getTexParameter(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL)', 'ext.STENCIL_INDEX_WEBGL'); + gl.texParameteri(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL, gl.DEPTH_COMPONENT); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + shouldBe('gl.getTexParameter(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL)', 'gl.DEPTH_COMPONENT'); + gl.texParameteri(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "invalid depth stencil mode value rejected by texParameteri"); + shouldBe('gl.getTexParameter(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL)', 'gl.DEPTH_COMPONENT'); + debug(""); + debug("Check texture state updates using texParameterf"); + gl.texParameterf(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL, ext.STENCIL_INDEX_WEBGL); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + shouldBe('gl.getTexParameter(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL)', 'ext.STENCIL_INDEX_WEBGL'); + gl.texParameterf(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL, gl.DEPTH_COMPONENT); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + shouldBe('gl.getTexParameter(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL)', 'gl.DEPTH_COMPONENT'); + gl.texParameterf(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL, 0); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "invalid depth stencil mode value rejected by texParameterf"); + shouldBe('gl.getTexParameter(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL)', 'gl.DEPTH_COMPONENT'); + + debug(""); + debug("Check that depth stencil texture mode is not accepted as a sampler state"); + const sampler = gl.createSampler(); + gl.samplerParameteri(sampler, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL, gl.DEPTH_COMPONENT); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown for samplerParameteri"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no more errors"); + gl.samplerParameterf(sampler, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL, gl.DEPTH_COMPONENT); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown for samplerParameterf"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no more errors"); +} + +function checkSampling() { + const formats = [ + {name: "DEPTH_COMPONENT16", internalFormat: gl.DEPTH_COMPONENT16, + format: gl.DEPTH_COMPONENT, type: gl.UNSIGNED_SHORT}, + {name: "DEPTH_COMPONENT24", internalFormat: gl.DEPTH_COMPONENT24, + format: gl.DEPTH_COMPONENT, type: gl.UNSIGNED_INT}, + {name: "DEPTH_COMPONENT32F", internalFormat: gl.DEPTH_COMPONENT32F, + format: gl.DEPTH_COMPONENT, type: gl.FLOAT}, + {name: "DEPTH24_STENCIL8", internalFormat: gl.DEPTH24_STENCIL8, + format: gl.DEPTH_STENCIL, type: gl.UNSIGNED_INT_24_8}, + {name: "DEPTH32F_STENCIL8", internalFormat: gl.DEPTH32F_STENCIL8, + format: gl.DEPTH_STENCIL, type: gl.FLOAT_32_UNSIGNED_INT_24_8_REV} + ]; + + gl.enable(gl.DEPTH_TEST); + gl.enable(gl.STENCIL_TEST); + gl.stencilFunc(gl.ALWAYS, 170, 0xFF); + gl.stencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE); + + wtu.setupUnitQuad(gl); + + const drawProgram = wtu.setupProgram(gl, [wtu.simpleVertexShader, + wtu.simpleColorFragmentShader]); + + const readDepthProgram = wtu.setupProgram(gl, [wtu.simpleTextureVertexShaderESSL300, + wtu.simpleTextureFragmentShaderESSL300]); + + const readStencilShader = `#version 300 es + precision highp float; + uniform highp usampler2D tex; + in vec2 texCoord; + out vec4 out_color; + void main() { + out_color = vec4(texture(tex, texCoord)) / 255.0; + }`; + const readStencilProgram = wtu.setupProgram(gl, [wtu.simpleTextureVertexShaderESSL300, + readStencilShader]); + + for (const format of formats) { + debug(""); + debug(`Testing depth stencil texture modes with ${format.name}`); + const fbo = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + + const rbo = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rbo); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, 1, 1); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo); + + const tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + gl.texImage2D(gl.TEXTURE_2D, 0, format.internalFormat, 1, 1, 0, format.format, format.type, null); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texture created"); + + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, tex, 0); + if (format.format == gl.DEPTH_STENCIL) { + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.TEXTURE_2D, tex, 0); + } + wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE); + + gl.clear(gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); + gl.useProgram(drawProgram); + wtu.drawUnitQuad(gl); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no errors after drawing to the depth or depth stencil texture"); + + // Detach the depth or depth stencil texture to avoid feedback loop + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, null); + wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE); + + const magFilters = ['NEAREST', 'LINEAR']; + + const minFilters = [ + 'NEAREST', + 'LINEAR', + 'NEAREST_MIPMAP_NEAREST', + 'LINEAR_MIPMAP_NEAREST', + 'NEAREST_MIPMAP_LINEAR', + 'LINEAR_MIPMAP_LINEAR' + ]; + + const modes = [ + [gl.DEPTH_COMPONENT, 'DEPTH_COMPONENT'], + [ext.STENCIL_INDEX_WEBGL, 'STENCIL_INDEX_WEBGL'] + ]; + + const programs = [ + [readDepthProgram, 'depth'], + [readStencilProgram, 'stencil'] + ]; + + function validFilters(magFilter, minFilter) { + return magFilter == gl.NEAREST && + (minFilter == gl.NEAREST || minFilter == gl.NEAREST_MIPMAP_NEAREST); + } + + for (const program of programs) { + gl.useProgram(program[0]); + for (const mode of modes) { + gl.texParameteri(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL, mode[0]); + for (const magFilter of magFilters) { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl[magFilter]); + for (const minFilter of minFilters) { + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl[minFilter]); + debug(`Program: ${program[1]}, mode: ${mode[1]}, mag: ${magFilter}, min: ${minFilter}`); + + gl.clear(gl.COLOR_BUFFER_BIT); + wtu.drawUnitQuad(gl); + + if (format.format == gl.DEPTH_COMPONENT || mode[0] == gl.DEPTH_COMPONENT) { + if (program[1] == 'depth') { + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + if (validFilters(gl[magFilter], gl[minFilter])) { + wtu.checkCanvasRect(gl, 0, 0, 1, 1, [128, 0, 0, 255], "sampling depth from complete texture", 1); + } else { + wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0, 0, 0, 255], "sampling depth from incomplete texture", 1); + } + } else { + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "sampling depth using incompatible program"); + } + } else { + if (program[1] == 'stencil') { + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + if (validFilters(gl[magFilter], gl[minFilter])) { + wtu.checkCanvasRect(gl, 0, 0, 1, 1, [170, 0, 0, 1], "sampling stencil from complete texture", 1); + } else { + // Incomplete textures may produce [0, 0, 0, 1] or [0, 0, 0, 255]. + const value = new Uint8Array(4); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, value); + wtu.glErrorShouldBe(gl, gl.NO_ERROR); + const msg = "sampling stencil from incomplete texture"; + if (value[0] == 0 && value[1] == 0 && value[2] == 0 && (value[3] == 1 || value[3] == 255)) { + testPassed(msg); + } else { + testFailed(`${msg}: ${value}`); + } + } + } else { + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "sampling stencil using incompatible program"); + } + } + } + } + } + } + } +} + +function runTest() { + if (!gl) { + testFailed("context does not exist"); + return; + } + testPassed("context exists"); + + runTestNoExtension(); + + ext = gl.getExtension("WEBGL_stencil_texturing"); + wtu.runExtensionSupportedTest(gl, "WEBGL_stencil_texturing", ext !== null); + + if (ext !== null) { + checkEnums(); + checkQueries(); + checkSampling(); + } else { + testPassed("No WEBGL_stencil_texturing support -- this is legal"); + } +} + +runTest(); + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/glsl3/00_test_list.txt b/dom/canvas/test/webgl-conf/checkout/conformance2/glsl3/00_test_list.txt index 5a47d470f9..9e8bc87a62 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance2/glsl3/00_test_list.txt +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/glsl3/00_test_list.txt @@ -41,6 +41,7 @@ shader-with-invalid-characters.html shader-with-mis-matching-uniform-block.html short-circuiting-in-loop-condition.html --min-version 2.0.1 switch-case.html +--min-version 2.0.1 texture-bias.html --min-version 2.0.1 texture-offset-non-constant-offset.html texture-offset-out-of-range.html --min-version 2.0.1 texture-offset-uniform-texture-coordinate.html diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/glsl3/texture-bias.html b/dom/canvas/test/webgl-conf/checkout/conformance2/glsl3/texture-bias.html new file mode 100644 index 0000000000..0c30eb7129 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/glsl3/texture-bias.html @@ -0,0 +1,146 @@ +<!-- +Copyright (c) 2022 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>GLSL texture bias test</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +<script src="../../js/glsl-conformance-test.js"></script> +</head> +<body> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description("Texture bias should both function and respect limits."); + +function runTest(gl) { + // no if idea any drivers have a giant limit like 2^32 so just in case. + const kMaxMaxTextureSize = 256 * 1024 * 1024; + const maxTextureSize = Math.min(kMaxMaxTextureSize, gl.getParameter(gl.MAX_TEXTURE_SIZE)); + const maxLODs = (Math.log2(maxTextureSize) | 0) + 1; + const maxTextureLODBias = gl.getParameter(gl.MAX_TEXTURE_LOD_BIAS); + + debug(`maxTextureSize: ${maxTextureSize}`); + debug(`maxLODs: ${maxLODs}`); + debug(`maxTextureLODBias: ${maxTextureLODBias}`); + + const vs = `#version 300 es + uniform float uvMult; + out vec2 v_uv; + void main() { + vec2 xy = vec2( + gl_VertexID % 2, + (gl_VertexID / 2 + gl_VertexID / 3) % 2); + + gl_Position = vec4(xy * 2. - 1.0, 0, 1); + v_uv = xy * uvMult; + } + `; + const fs = `#version 300 es + precision highp float; + uniform sampler2D tex; + uniform float biasMult; + in vec2 v_uv; + out vec4 fragColor; + void main() { + vec4 texColor = texture(tex, v_uv, (gl_FragCoord.x - 0.5) * biasMult); // the color we care about + vec4 texelColor = texelFetch(tex, ivec2(0), int(gl_FragCoord)); // just a sanity check + vec4 coordColor = vec4((100.0 + gl_FragCoord.x - 0.5) / 255.0); // another sanity check + fragColor = mix(texColor, coordColor, step(1.0, gl_FragCoord.y)); // line < 1 = texColor, line >= 1 = coordColor + fragColor = mix(fragColor, texelColor, step(2.0, gl_FragCoord.y)); // line < 2 = fragColor, line >= 2 = texelColor + } + `; + const program = wtu.setupProgram(gl, [vs, fs]); + const uvMultLoc = gl.getUniformLocation(program, 'uvMult'); + const biasLoc = gl.getUniformLocation(program, 'biasMult'); + + gl.canvas.width = maxLODs; + gl.canvas.height = 3; + gl.viewport(0, 0, maxLODs, 3); + + // create a texture where each mip is a different color (1, 2, 3, ...) + const tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_NEAREST); + gl.texStorage2D(gl.TEXTURE_2D, maxLODs, gl.RGBA8, maxTextureSize, 1); + { + let level = 0; + for (let width = maxTextureSize; width > 0; width = width / 2 | 0) { + const pixels = new Uint8Array(width * 1 * 4); + pixels.fill(level + 1); + debug(`fill mip level: ${level}, width: ${width}`); + gl.texSubImage2D(gl.TEXTURE_2D, level, 0, 0, width, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels); + wtu.glErrorShouldBe(gl, gl.NO_ERROR); + ++level; + } + } + + // Draw each mip. Result should be [mip0, mip1, mip2, ...] + debug(""); + debug("check positive bias"); + // set the UVs so we'd get mip level 0 for every pixel + gl.uniform1f(uvMultLoc, maxLODs / maxTextureSize); + gl.uniform1f(biasLoc, 1); + gl.drawArrays(gl.TRIANGLES, 0, 6); + + wtu.glErrorShouldBe(gl, gl.NO_ERROR); + + const clampPlusMinus = (v, limit) => Math.min(limit, Math.max(-limit, v)); + + const checkResults = (gl, biasMult) => { + const base = biasMult > 0 ? 1 : maxLODs; + for (let i = 0; i < maxLODs; ++i) { + { + const expected = new Array(4).fill(clampPlusMinus(i * biasMult, maxTextureLODBias) + base); + wtu.checkCanvasRect(gl, i, 0, 1, 1, expected, `should be: ${expected}`); + } + { + const expected = new Array(4).fill(100 + i); + wtu.checkCanvasRect(gl, i, 1, 1, 1, expected, `should be: ${expected}`); + } + { + const expected = new Array(4).fill(i + 1); + wtu.checkCanvasRect(gl, i, 2, 1, 1, expected, `should be: ${expected}`); + } + } + } + + checkResults(gl, 1); + + // Draw each mip. Result should be [mipMax, mipMax - 1, mipMax - 2, ...] + debug(""); + debug("check negative bias"); + // set the UVs so we'd get highest mip level (the 1x1 level mip) for every pixel + gl.uniform1f(uvMultLoc, maxLODs); + gl.uniform1f(biasLoc, -1); + gl.drawArrays(gl.TRIANGLES, 0, 6); + + checkResults(gl, -1); + + finishTest(); +} + +const wtu = WebGLTestUtils; + +const gl = wtu.create3DContext(undefined, undefined, 2); + +var successfullyParsed = true; + +if (!gl) { + testFailed("Unable to initialize WebGL 2.0 context."); +} else { + runTest(gl); +} + +</script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/query/00_test_list.txt b/dom/canvas/test/webgl-conf/checkout/conformance2/query/00_test_list.txt index c40921bf88..a2e21b5ad7 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance2/query/00_test_list.txt +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/query/00_test_list.txt @@ -1,2 +1,3 @@ occlusion-query.html +--min-version 2.0.1 occlusion-query-scissor.html query.html diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/query/occlusion-query-scissor.html b/dom/canvas/test/webgl-conf/checkout/conformance2/query/occlusion-query-scissor.html new file mode 100644 index 0000000000..dec88e56d3 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/query/occlusion-query-scissor.html @@ -0,0 +1,117 @@ +<!-- +Copyright (c) 2022 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebGL Occlusion Query w/Scissor Conformance Tests</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +</head> +<body> +<div id="description"></div> +<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas> +<div id="console"></div> +<script> +"use strict"; +description("This test verifies the functionality of occlusion query objects with the scissor test."); +debug('Regression test for <a href="http://anglebug.com/7157">http://anglebug.com/7157</a>'); + +debug(""); + +const wtu = WebGLTestUtils; + +const wait = () => new Promise(resolve => setTimeout(resolve)); + +async function runOcclusionQueryTest(gl) { + const kSize = 4; + const colors = [ + [0, 0, 0, 255], + [255, 0, 0, 255], + [0, 255, 0, 255], + [255, 255, 0, 255], + ]; + const framebuffers = colors.map((color, index) => { + const tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, kSize, kSize, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + + const fb = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0); + + gl.clearColor(index & 1, (index >> 1) & 1, (index >> 2) & 1, 1); + gl.clear(gl.COLOR_BUFFER_BIT); + + wtu.checkCanvasRect(gl, 0, 0, kSize, kSize, color); + + return fb; + }); + + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "setup should succeed"); + + gl.viewport(0, 0, kSize, kSize); + + const program = wtu.setupSimpleColorProgram(gl, 0); + gl.uniform4f(gl.getUniformLocation(program, "u_color"), 0, 1, 0, 1); + wtu.setupUnitQuad(gl, 0); + + const query = gl.createQuery();; + + for (let i = 0; i < 256; ++i) + { + gl.beginQuery(gl.ANY_SAMPLES_PASSED, query); + let drawn = false; + + framebuffers.forEach((fb, index) => { + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + const scissor = (i >> 4 >> index) & 1; + if (i & (1 << index)) + { + if (scissor) + { + gl.enable(gl.SCISSOR_TEST); + gl.scissor(0, 0, 0, 0); + } + wtu.drawUnitQuad(gl); + drawn ||= !scissor; + if (scissor) + { + gl.disable(gl.SCISSOR_TEST); + gl.scissor(0, 0, kSize, kSize); + } + } + }); + + gl.endQuery(gl.ANY_SAMPLES_PASSED); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should draw"); + + do { + await wait(); + } while (!gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE)); + + const result = gl.getQueryParameter(query, gl.QUERY_RESULT); + + const expected = drawn ? 1 : 0; + assertMsg(result === expected, `pass ${i}, result: ${result} === expected: ${expected}`); + } + finishTest(); +} + +const canvas = document.getElementById("canvas"); +const gl = wtu.create3DContext(canvas, null, 2); + +if (!gl) { + testFailed("WebGL context does not exist"); +} else { + testPassed("WebGL context exists"); + runOcclusionQueryTest(gl); +} +</script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/renderbuffers/framebuffer-object-attachment.html b/dom/canvas/test/webgl-conf/checkout/conformance2/renderbuffers/framebuffer-object-attachment.html index 754ff2cc73..bc4d623446 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance2/renderbuffers/framebuffer-object-attachment.html +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/renderbuffers/framebuffer-object-attachment.html @@ -111,9 +111,10 @@ function testFramebufferWebGL1RequiredCombinations() { gl.deleteFramebuffer(fbo); } -function testDepthStencilAttachmentBehaviors() { +function testDepthStencilAttachmentBehaviors(testOrphanedRenderbuffers) { + let suffix = testOrphanedRenderbuffers ? " with deleted renderbuffer" : ""; debug(""); - debug("Checking ES3 DEPTH_STENCIL_ATTACHMENT behaviors are implemented for WebGL 2"); + debug("Checking ES3 DEPTH_STENCIL_ATTACHMENT behaviors are implemented for WebGL 2" + suffix); // DEPTH_STENCIL_ATTACHMENT is treated as an independent attachment point in WebGL 1; // however, in WebGL 2, it is treated as an alias for DEPTH_ATTACHMENT + STENCIL_ATTACHMENT. var size = 16; @@ -127,24 +128,45 @@ function testDepthStencilAttachmentBehaviors() { gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, size, size); checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); - var depthBuffer = gl.createRenderbuffer(); - gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer); - gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, size, size); + function createDepthBuffer() { + let buffer = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, buffer); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, size, size); + gl.bindRenderbuffer(gl.RENDERBUFFER, null); + return buffer; + } + + function createStencilBuffer() { + let buffer = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, buffer); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.STENCIL_INDEX8, size, size); + gl.bindRenderbuffer(gl.RENDERBUFFER, null); + return buffer; + } - var stencilBuffer = gl.createRenderbuffer(); - gl.bindRenderbuffer(gl.RENDERBUFFER, stencilBuffer); - gl.renderbufferStorage(gl.RENDERBUFFER, gl.STENCIL_INDEX8, size, size); + function createDepthStencilBuffer() { + let buffer = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, buffer); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, size, size); + gl.bindRenderbuffer(gl.RENDERBUFFER, null); + return buffer; + } - var depthStencilBuffer = gl.createRenderbuffer(); - gl.bindRenderbuffer(gl.RENDERBUFFER, depthStencilBuffer); - gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, size, size); + function orphan(renderbuffer) { + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + gl.deleteRenderbuffer(renderbuffer); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + } wtu.glErrorShouldBe(gl, gl.NO_ERROR); debug(""); - debug("color + depth"); + debug("color + depth" + suffix); + var depthBuffer = createDepthBuffer(); gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer); + if (testOrphanedRenderbuffers) + orphan(depthBuffer); shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthBuffer); shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); @@ -153,9 +175,12 @@ function testDepthStencilAttachmentBehaviors() { checkBufferBits(gl.DEPTH_ATTACHMENT); debug(""); - debug("color + depth + stencil: depth != stencil"); + debug("color + depth + stencil: depth != stencil" + suffix); + var stencilBuffer = createStencilBuffer(); gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, stencilBuffer); + if (testOrphanedRenderbuffers) + orphan(stencilBuffer); shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthBuffer); shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", stencilBuffer); shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); @@ -170,9 +195,12 @@ function testDepthStencilAttachmentBehaviors() { wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION); debug(""); - debug("color + depth: DEPTH_STENCIL for DEPTH_ATTACHMENT"); + debug("color + depth: DEPTH_STENCIL for DEPTH_ATTACHMENT" + suffix); + var depthStencilBuffer = createDepthStencilBuffer(); gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer); + if (testOrphanedRenderbuffers) + orphan(depthStencilBuffer); shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); @@ -181,9 +209,16 @@ function testDepthStencilAttachmentBehaviors() { checkBufferBits(gl.DEPTH_ATTACHMENT); debug(""); - debug("color + depth + stencil: DEPTH_STENCIL for DEPTH_ATTACHMENT and STENCIL_ATTACHMENT"); + debug("color + depth + stencil: DEPTH_STENCIL for DEPTH_ATTACHMENT and STENCIL_ATTACHMENT" + suffix); + if (testOrphanedRenderbuffers) { + depthStencilBuffer = createDepthStencilBuffer(); + gl.framebufferRenderbuffer( + gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer); + } gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer); + if (testOrphanedRenderbuffers) + orphan(depthStencilBuffer); shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); @@ -192,7 +227,7 @@ function testDepthStencilAttachmentBehaviors() { checkBufferBits(gl.DEPTH_STENCIL_ATTACHMENT); debug(""); - debug("color + depth_stencil"); + debug("color + depth_stencil" + suffix); var texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, texture); gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH24_STENCIL8, size, size, 0, gl.DEPTH_STENCIL, gl.UNSIGNED_INT_24_8, null); @@ -209,8 +244,12 @@ function testDepthStencilAttachmentBehaviors() { shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); wtu.glErrorShouldBe(gl, gl.NO_ERROR); + if (testOrphanedRenderbuffers) + depthStencilBuffer = createDepthStencilBuffer(); gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer); + if (testOrphanedRenderbuffers) + orphan(depthStencilBuffer); shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); @@ -219,16 +258,24 @@ function testDepthStencilAttachmentBehaviors() { checkBufferBits(gl.DEPTH_STENCIL_ATTACHMENT); debug(""); - debug("DEPTH_STENCIL_ATTACHMENT overwrites DEPTH_ATTACHMENT/STENCIL_ATTACHMENT") + debug("DEPTH_STENCIL_ATTACHMENT overwrites DEPTH_ATTACHMENT/STENCIL_ATTACHMENT" + suffix); + if (testOrphanedRenderbuffers) + depthBuffer = createDepthBuffer(); gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer); + if (testOrphanedRenderbuffers) + orphan(depthBuffer); shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthBuffer); shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION); + if (testOrphanedRenderbuffers) + depthStencilBuffer = createDepthStencilBuffer(); gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer); + if (testOrphanedRenderbuffers) + orphan(depthStencilBuffer); shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); @@ -244,9 +291,13 @@ function testDepthStencilAttachmentBehaviors() { checkBufferBits(); debug(""); - debug("STENCIL_ATTACHMENT overwrites stencil set by DEPTH_STENCIL_ATTACHMENT") + debug("STENCIL_ATTACHMENT overwrites stencil set by DEPTH_STENCIL_ATTACHMENT" + suffix); + if (testOrphanedRenderbuffers) + depthStencilBuffer = createDepthStencilBuffer(); gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer); + if (testOrphanedRenderbuffers) + orphan(depthStencilBuffer); shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); @@ -260,6 +311,28 @@ function testDepthStencilAttachmentBehaviors() { wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION); checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); checkBufferBits(gl.DEPTH_ATTACHMENT); + + debug(""); + debug("DEPTH_ATTACHMENT overwrites depth set by DEPTH_STENCIL_ATTACHMENT" + suffix); + if (testOrphanedRenderbuffers) + depthStencilBuffer = createDepthStencilBuffer(); + gl.framebufferRenderbuffer( + gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer); + if (testOrphanedRenderbuffers) + orphan(depthStencilBuffer); + shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); + shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); + shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); + wtu.glErrorShouldBe(gl, gl.NO_ERROR); + + gl.framebufferRenderbuffer( + gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, null); + shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); + shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer); + shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION); + checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); + checkBufferBits(gl.STENCIL_ATTACHMENT); } function testFramebufferIncompleteAttachment() { @@ -469,7 +542,8 @@ description("Test framebuffer object attachment behaviors"); shouldBeNonNull("gl = wtu.create3DContext(undefined, undefined, 2)"); testFramebufferWebGL1RequiredCombinations(); -testDepthStencilAttachmentBehaviors(); +testDepthStencilAttachmentBehaviors(false); +testDepthStencilAttachmentBehaviors(true); testFramebufferIncompleteAttachment(); testFramebufferIncompleteMissingAttachment(); testFramebufferWithImagesOfDifferentSizes(); diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/renderbuffers/framebuffer-texture-layer.html b/dom/canvas/test/webgl-conf/checkout/conformance2/renderbuffers/framebuffer-texture-layer.html index 0e435d6a2e..13e5d790e8 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance2/renderbuffers/framebuffer-texture-layer.html +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/renderbuffers/framebuffer-texture-layer.html @@ -121,6 +121,37 @@ function testFramebufferTextureLayer() { "attaching a depth_stencil texture to a framebuffer should succeed."); checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); + var texDepthStencil = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D_ARRAY, texDepthStencil); + + var texDepthStencilMany = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D_ARRAY, texDepthStencilMany); + var fbDepthStencilMany = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbDepthStencilMany); + gl.texImage3D(gl.TEXTURE_2D_ARRAY, + 0, // level + gl.DEPTH24_STENCIL8, // internalFormat + 1, // width + 1, // height + 2, // depth + 0, // border + gl.DEPTH_STENCIL, // format + gl.UNSIGNED_INT_24_8, // type + new Uint32Array([0, 1])); // data + + gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, texDepthStencilMany, 0, 0); + gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, texDepthStencilMany, 0, 0); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, + "attaching a depth_stencil 2d array texture level 0 to a framebuffer should succeed."); + checkFramebuffer([gl.FRAMEBUFFER_COMPLETE]); + shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", texDepthStencilMany); + gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, texDepthStencilMany, 0, 1); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, + "attaching a 2d array texture level 0 to depth and layer 1 to stencil attachment of a framebuffer should succeed."); + // "Depth and stencil attachments, if present, are the same image." If not, then "FRAMEBUFFER_UNSUPPORTED". + checkFramebuffer([gl.FRAMEBUFFER_UNSUPPORTED]); + shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", texDepthStencilMany); + // Clean up gl.deleteTexture(tex3d); gl.deleteTexture(texDepthStencil); diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/00_test_list.txt b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/00_test_list.txt index 92ce232ee2..c4a1bbe9e8 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/00_test_list.txt +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/00_test_list.txt @@ -11,7 +11,6 @@ blitframebuffer-size-overflow.html --min-version 2.0.1 blitframebuffer-stencil-only.html blitframebuffer-test.html --min-version 2.0.1 blitframebuffer-unaffected-by-colormask.html ---min-version 2.0.1 builtin-vert-attribs.html canvas-resizing-with-pbo-bound.html --min-version 2.0.1 clearbuffer-sub-source.html --min-version 2.0.1 clearbufferfv-with-alpha-false.html diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/builtin-vert-attribs.html b/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/builtin-vert-attribs.html deleted file mode 100644 index cc64c9034b..0000000000 --- a/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/builtin-vert-attribs.html +++ /dev/null @@ -1,408 +0,0 @@ -<!-- -Copyright (c) 2022 The Khronos Group Inc. -Use of this source code is governed by an MIT-style license that can be -found in the LICENSE.txt file. ---> - -<!DOCTYPE html> -<html> -<head> -<meta charset=utf-8> -<link rel=stylesheet href="../../resources/js-test-style.css"/> -<script src="../../js/js-test-pre.js"></script> -<script src="../../js/webgl-test-utils.js"></script> -</head> -<body> -<canvas id=e_canvas width=1 height=1 style="width: 100px; height: 100px;"></canvas> -<div id=description></div> -<div id=console></div> -<script> -"use strict"; -description('gl_VertexID and gl_InstanceID should behave as per spec.'); - -// - -/* -So what are gl_VertexID and gl_InstanceID supposed to do? -In ES 3.0 and GL 4.1 (Core), this is all we get: - -# ES 3.0 - -> (p78) gl_VertexID holds the integer index i implicitly passed by DrawArrays or -> one of the other drawing commands defined in section 2.9.3. The value of -> gl_VertexID is defined if and only if all enabled vertex arrays have non-zero buffer -> object bindings. -> gl_InstanceID holds the integer instance number of the current primitive in -> an instanced draw call (see section 2.9.3). - - -# GL 4.1 (Core) - -> (p102) gl_VertexID holds the integer index i implicitly passed by DrawArrays or -> one of the other drawing commands defined in section 2.8.3. -> gl_InstanceID holds the integer index of the current primitive in an -> instanced draw call (see section 2.8.3). - - -# ES 3.1 - -ES 3.1 retains the wording from ES 3.0, but adds the following clarifications: - -gl_VertexID: -> (p252) The index of any element transferred to the GL by DrawArraysOneInstance -> is referred to as its vertex ID, and may be read by a vertex shader as gl_VertexID. -> The vertex ID of the ith element transferred is first + i. - -> (p254) The index of any element transferred to the GL by -> DrawElementsOneInstance is referred to as its vertex ID, and may be read by a vertex shader as -> gl_VertexID. If no element array buffer is bound, the vertex ID of the ith element -> transferred is indices[i] + basevertex. Otherwise, the vertex ID of the ith -> element transferred is the sum of basevertex and the value stored in the currently -> bound element array buffer at offset indices + i. - -gl_InstanceID -> (p255) If an enabled vertex attribute array is instanced (it has a non-zero divisor as -> specified by VertexAttribDivisor), the element index that is transferred to the GL, -> for all vertices, is given by -> `floor(instance / divisor) + baseinstance` - - -# Errata - -Drivers generally do implement the ES 3.1 behavior. -A notable exception is Mac's legacy GL (4.1) driver which has two bugs here. -(Both ANGLE-on-Metal and the system M1+ GL driver seem correct though) - -## gl_InstanceID random for DrawArrays calls -Use ERRATA.IGNORE_GL_INSTANCE_ID to cause these tests to pass. - -## Adds `first` to user-attrib instanced fetch ids in DrawArrays calls. -Use ERRATA.FIRST_ADDS_TO_INSTANCE to cause these tests to pass. -*/ - -const wtu = WebGLTestUtils; -const gl = wtu.create3DContext('e_canvas'); - -const ERRATA = {}; -//ERRATA.IGNORE_GL_INSTANCE_ID = true; // Chrome on ANGLE-on-Mac-GL needs this. -//ERRATA.FIRST_ADDS_TO_INSTANCE = true; // Firefox with MOZ_WEBGL_WORKAROUND_FIRST_AFFECTS_INSTANCE_ID=0 would need this. - -debug(`ERRATA: ${JSON.stringify(ERRATA)}`); - -function make_vs_point(vid, iid) { - return `\ - #version 300 es - - ${vid.name == 'gl_VertexID' ? '// ' : ''}layout(location=${vid.loc}) in highp int ${vid.name}; - ${iid.name == 'gl_InstanceID' ? '// ' :''}layout(location=${iid.loc}) in highp int ${iid.name}; - out vec4 v_color; - - void main() { - gl_PointSize = 1.0; - gl_Position = vec4(0.0, 0.0, 0.0, 1.0); - v_color = vec4(1.0, float(${vid.name}) / 255.0, float(${iid.name}) / 255.0, 1.0); -#if ${(iid.name == 'gl_InstanceID' && ERRATA.IGNORE_GL_INSTANCE_ID)|0} - v_color.b = 0.0; -#endif - }`; -} - -function make_vs_tri(vid, iid) { - return `\ - #version 300 es - - ${vid.name == 'gl_VertexID' ? '// ' : ''}layout(location=${vid.loc}) in highp int ${vid.name}; - ${iid.name == 'gl_InstanceID' ? '// ' :''}layout(location=${iid.loc}) in highp int ${iid.name}; - out vec4 v_color; - - void main() { - int prim_vert_id = ${vid.name} % 3; - int flat_vert_id = ${vid.name} - prim_vert_id + 2; - gl_Position = vec4(0.0, 0.0, 0.0, 1.0); - gl_Position.x = (prim_vert_id == 1) ? 2.0 : -1.0; - gl_Position.y = (prim_vert_id == 2) ? 2.0 : -1.0; - v_color = vec4(1.0, float(flat_vert_id) / 255.0, float(${iid.name}) / 255.0, 1.0); -#if ${(iid.name == 'gl_InstanceID' && ERRATA.IGNORE_GL_INSTANCE_ID)|0} - v_color.b = 0.0; -#endif - }`; -} - -const FS = `\ - #version 300 es - precision mediump float; - - in vec4 v_color; - out vec4 o_color; - - void main() { - o_color = v_color; - } -`; - - -function crossCombine(...args) { - function crossCombine2(listA, listB) { - const listC = []; - for (const a of listA) { - for (const b of listB) { - const c = Object.assign({}, a, b); - listC.push(c); - } - } - return listC; - } - - let res = [{}]; - while (args.length) { - const next = args.shift(); - next[0].defined; - res = crossCombine2(res, next); - } - return res; -} - -/// makeCombiner('foo', [5, 3]) -> [{foo: 5}, {foo: 3}] -function makeCombiner(key, vals) { - const ret = []; - for (const val of vals) { - const cur = {}; - cur[key] = val; - ret.push(cur); - } - return ret; -} - -debug('Draw a point with a shader that takes no attributes and verify it fills the whole canvas.'); - - -let TESTS = [ - makeCombiner('vid', [ - {name: 'a_VertexID', loc:0}, - {name: 'a_VertexID', loc:2}, // Test 2, so that we're not only testing 0. - {name: 'gl_VertexID', loc:-1}, - {name: 'gl_VertexID', loc:0}, // Enable a vertex array, despite not using it. - {name: 'gl_VertexID', loc:2}, // Enable a vertex array, despite not using it. - ]), - makeCombiner('iid', [ - {name: 'a_InstanceID', loc:1}, - {name: 'gl_InstanceID', loc:-1}, - {name: 'gl_InstanceID', loc:1}, // Enable a vertex array, despite not using it. - ]), - makeCombiner('separate_vbufs', [true, false]), -]; -//console.log('a', {TESTS}); -TESTS = crossCombine(...TESTS); -//console.log('b', {TESTS}); - - -let vdata = new Int32Array(1000); -vdata = vdata.map((v,i) => i); -const vbuf = gl.createBuffer(); -gl.bindBuffer(gl.ARRAY_BUFFER, vbuf); -gl.bufferData(gl.ARRAY_BUFFER, vdata, gl.STATIC_DRAW); - - -const vbuf2 = gl.createBuffer(); -gl.bindBuffer(gl.ARRAY_BUFFER, vbuf2); -gl.bufferData(gl.ARRAY_BUFFER, vdata, gl.STATIC_DRAW); - - -let index_data = new Uint32Array(1000); -index_data = index_data.map((x,i) => 10+i); -const index_buffer = gl.createBuffer(); -gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer); -gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, index_data, gl.STATIC_DRAW); - - -gl.disable(gl.DEPTH_TEST); - -(async () => { - for (const desc of TESTS) { - await wtu.dispatchPromise(); // Yield, for responsiveness. - debug(''); - debug('---------------------'); - debug(`desc: ${JSON.stringify(desc)}`); - - let fn = (vs) => { - //console.log({vs}); - const prog = wtu.setupProgram(gl, [vs, FS]); - - { - const WEBGL_debug_shaders = gl.getExtension('WEBGL_debug_shaders'); - let i = -1; - for (const s of gl.getAttachedShaders(prog)) { - i += 1; - debug(''); - debug(`shader[${i}] getShaderSource() -> `); - debug(gl.getShaderSource(s)); - if (WEBGL_debug_shaders) { - debug(`shader[${i}] getTranslatedShaderSource() -> `); - debug(WEBGL_debug_shaders.getTranslatedShaderSource(s)); - } - } - } - return prog; - }; - const point_prog = fn(make_vs_point(desc.vid, desc.iid)); - const tri_prog = fn(make_vs_tri(desc.vid, desc.iid)); - - // - - - gl.bindBuffer(gl.ARRAY_BUFFER, null); - for (let i = 0; i <= 2; i++) { - gl.disableVertexAttribArray(i); - gl.vertexAttribPointer(i, 4, gl.FLOAT, false, 0, 0); - gl.vertexAttribDivisor(i, 0); - } - - gl.bindBuffer(gl.ARRAY_BUFFER, vbuf); - let loc = desc.vid.loc; - if (loc != -1) { - gl.enableVertexAttribArray(loc); - gl.vertexAttribIPointer(loc, 1, gl.INT, 0, 0); - }; - - if (desc.separate_vbufs) { - gl.bindBuffer(gl.ARRAY_BUFFER, vbuf2); - } - loc = desc.iid.loc; - if (loc != -1) { - gl.enableVertexAttribArray(loc); - gl.vertexAttribIPointer(loc, 1, gl.INT, 0, 0); - gl.vertexAttribDivisor(loc, 1); - }; - - { - const err = gl.getError(); - if (err) throw err; // Broken init. - } - - // - - - fn = (eval_str, expected_arr) => { - if (ERRATA.IGNORE_GL_INSTANCE_ID) { - if (desc.iid.name == 'gl_InstanceID') { - expected_arr = expected_arr.map(x => x); - expected_arr[2] = 0; - } - } - - debug(''); - //debug(`${eval_str} -> [${expected_arr.join(', ')}]`); - eval(eval_str); - - const err = gl.getError(); - if (err) throw err; // Broken subtest. - - wtu.checkCanvas(gl, expected_arr, eval_str); - } - - gl.useProgram(point_prog); - - gl.clear(gl.COLOR_BUFFER_BIT); - fn(`gl.drawArrays(gl.POINTS, 0, 0)`, [0, 0, 0, 0]); - fn(`gl.drawArrays(gl.POINTS, 0, 1)`, [255, 0, 0, 255]); - fn(`gl.drawArrays(gl.POINTS, 0, 2)`, [255, 1, 0, 255]); - if (ERRATA.FIRST_ADDS_TO_INSTANCE) { - fn(`gl.drawArrays(gl.POINTS, 100, 2)`, [255, 100+2-1, 100, 255]); - } else { - fn(`gl.drawArrays(gl.POINTS, 100, 2)`, [255, 100+2-1, 0, 255]); - } - fn(`gl.drawArrays(gl.POINTS, 0, 255)`, [255, 254, 0, 255]); - fn(`gl.drawArrays(gl.POINTS, 0, 256)`, [255, 255, 0, 255]); - - gl.clear(gl.COLOR_BUFFER_BIT); - fn(`gl.drawArraysInstanced(gl.POINTS, 0, 0, 1)`, [0, 0, 0, 0]); - gl.clear(gl.COLOR_BUFFER_BIT); - fn(`gl.drawArraysInstanced(gl.POINTS, 0, 1, 0)`, [0, 0, 0, 0]); - - fn(`gl.drawArraysInstanced(gl.POINTS, 0, 1, 1)`, [255, 0, 0, 255]); - fn(`gl.drawArraysInstanced(gl.POINTS, 0, 2, 1)`, [255, 1, 0, 255]); - fn(`gl.drawArraysInstanced(gl.POINTS, 0, 1, 2)`, [255, 0, 1, 255]); - fn(`gl.drawArraysInstanced(gl.POINTS, 0, 2, 2)`, [255, 1, 1, 255]); - if (ERRATA.FIRST_ADDS_TO_INSTANCE) { - fn(`gl.drawArraysInstanced(gl.POINTS, 100, 2, 2)`, [255, 100+2-1, 101, 255]); - } else { - fn(`gl.drawArraysInstanced(gl.POINTS, 100, 2, 2)`, [255, 100+2-1, 1, 255]); - } - fn(`gl.drawArraysInstanced(gl.POINTS, 0, 255, 255)`, [255, 254, 254, 255]); - - // - - - gl.clear(gl.COLOR_BUFFER_BIT); - fn(`gl.drawElements(gl.POINTS, 0, gl.UNSIGNED_INT, 4*0)`, [0, 0, 0, 0]); - fn(`gl.drawElements(gl.POINTS, 1, gl.UNSIGNED_INT, 4*0)`, [255, 10+0, 0, 255]); - fn(`gl.drawElements(gl.POINTS, 2, gl.UNSIGNED_INT, 4*0)`, [255, 10+1, 0, 255]); - fn(`gl.drawElements(gl.POINTS, 2, gl.UNSIGNED_INT, 4*100)`, [255, 100+10+1, 0, 255]); - fn(`gl.drawElements(gl.POINTS, 245, gl.UNSIGNED_INT, 4*0)`, [255, 10+244, 0, 255]); - fn(`gl.drawElements(gl.POINTS, 246, gl.UNSIGNED_INT, 4*0)`, [255, 10+245, 0, 255]); - - gl.clear(gl.COLOR_BUFFER_BIT); - fn(`gl.drawElementsInstanced(gl.POINTS, 0, gl.UNSIGNED_INT, 4*0, 1)`, [0, 0, 0, 0]); - gl.clear(gl.COLOR_BUFFER_BIT); - fn(`gl.drawElementsInstanced(gl.POINTS, 1, gl.UNSIGNED_INT, 4*0, 0)`, [0, 0, 0, 0]); - - fn(`gl.drawElementsInstanced(gl.POINTS, 1, gl.UNSIGNED_INT, 4*0, 1)`, [255, 10+0, 0, 255]); - fn(`gl.drawElementsInstanced(gl.POINTS, 2, gl.UNSIGNED_INT, 4*0, 1)`, [255, 10+1, 0, 255]); - fn(`gl.drawElementsInstanced(gl.POINTS, 1, gl.UNSIGNED_INT, 4*0, 2)`, [255, 10+0, 1, 255]); - fn(`gl.drawElementsInstanced(gl.POINTS, 2, gl.UNSIGNED_INT, 4*0, 2)`, [255, 10+1, 1, 255]); - fn(`gl.drawElementsInstanced(gl.POINTS, 2, gl.UNSIGNED_INT, 4*100, 2)`, [255, 100+10+1, 1, 255]); - fn(`gl.drawElementsInstanced(gl.POINTS, 245, gl.UNSIGNED_INT, 4*0, 255)`, [255, 10+244, 254, 255]); - - // - - - gl.useProgram(tri_prog); - - gl.clear(gl.COLOR_BUFFER_BIT); - fn(`gl.drawArrays(gl.TRIANGLES, 0, 0*3)`, [0, 0, 0, 0]); - fn(`gl.drawArrays(gl.TRIANGLES, 0, 1*3)`, [255, 1*3-1, 0, 255]); - fn(`gl.drawArrays(gl.TRIANGLES, 0, 2*3)`, [255, 2*3-1, 0, 255]); - if (ERRATA.FIRST_ADDS_TO_INSTANCE) { - fn(`gl.drawArrays(gl.TRIANGLES, 90, 2*3)`, [255, 90+2*3-1, 90, 255]); - } else { - fn(`gl.drawArrays(gl.TRIANGLES, 90, 2*3)`, [255, 90+2*3-1, 0, 255]); - } - - gl.clear(gl.COLOR_BUFFER_BIT); - fn(`gl.drawArraysInstanced(gl.TRIANGLES, 0, 0, 1)`, [0, 0, 0, 0]); - gl.clear(gl.COLOR_BUFFER_BIT); - fn(`gl.drawArraysInstanced(gl.TRIANGLES, 0, 1*3, 0)`, [0, 0, 0, 0]); - - fn(`gl.drawArraysInstanced(gl.TRIANGLES, 0, 1*3, 1)`, [255, 1*3-1, 0, 255]); - fn(`gl.drawArraysInstanced(gl.TRIANGLES, 0, 2*3, 1)`, [255, 2*3-1, 0, 255]); - fn(`gl.drawArraysInstanced(gl.TRIANGLES, 0, 1*3, 2)`, [255, 1*3-1, 1, 255]); - fn(`gl.drawArraysInstanced(gl.TRIANGLES, 0, 2*3, 2)`, [255, 2*3-1, 1, 255]); - if (ERRATA.FIRST_ADDS_TO_INSTANCE) { - fn(`gl.drawArraysInstanced(gl.TRIANGLES, 90, 2*3, 2)`, [255, 90+2*3-1, 91, 255]); - } else { - fn(`gl.drawArraysInstanced(gl.TRIANGLES, 90, 2*3, 2)`, [255, 90+2*3-1, 1, 255]); - } - - // - - - gl.clear(gl.COLOR_BUFFER_BIT); - fn(`gl.drawElements(gl.TRIANGLES, 0*3, gl.UNSIGNED_INT, 4*0)`, [0, 0, 0, 0]); - fn(`gl.drawElements(gl.TRIANGLES, 1*3, gl.UNSIGNED_INT, 4*0)`, [255, 10+1*3-1, 0, 255]); - fn(`gl.drawElements(gl.TRIANGLES, 2*3, gl.UNSIGNED_INT, 4*0)`, [255, 10+2*3-1, 0, 255]); - fn(`gl.drawElements(gl.TRIANGLES, 2*3, gl.UNSIGNED_INT, 4*100)`, [255, 100+10+2*3-1, 0, 255]); - - gl.clear(gl.COLOR_BUFFER_BIT); - fn(`gl.drawElementsInstanced(gl.TRIANGLES, 0*3, gl.UNSIGNED_INT, 4*0, 1)`, [0, 0, 0, 0]); - gl.clear(gl.COLOR_BUFFER_BIT); - fn(`gl.drawElementsInstanced(gl.TRIANGLES, 1*3, gl.UNSIGNED_INT, 4*0, 0)`, [0, 0, 0, 0]); - - fn(`gl.drawElementsInstanced(gl.TRIANGLES, 1*3, gl.UNSIGNED_INT, 4*0, 1)`, [255, 10+1*3-1, 0, 255]); - fn(`gl.drawElementsInstanced(gl.TRIANGLES, 2*3, gl.UNSIGNED_INT, 4*0, 1)`, [255, 10+2*3-1, 0, 255]); - fn(`gl.drawElementsInstanced(gl.TRIANGLES, 1*3, gl.UNSIGNED_INT, 4*0, 2)`, [255, 10+1*3-1, 1, 255]); - fn(`gl.drawElementsInstanced(gl.TRIANGLES, 2*3, gl.UNSIGNED_INT, 4*0, 2)`, [255, 10+2*3-1, 1, 255]); - fn(`gl.drawElementsInstanced(gl.TRIANGLES, 2*3, gl.UNSIGNED_INT, 4*100, 2)`, [255, 100+10+2*3-1, 1, 255]); - } - - finishTest(); -})(); - -var successfullyParsed = true; -</script> -</body> -</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/textures/misc/00_test_list.txt b/dom/canvas/test/webgl-conf/checkout/conformance2/textures/misc/00_test_list.txt index 17f8312e58..3639c10547 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance2/textures/misc/00_test_list.txt +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/textures/misc/00_test_list.txt @@ -20,6 +20,7 @@ mipmap-fbo.html --min-version 2.0.1 origin-clean-conformance-offscreencanvas.html tex-3d-size-limit.html --min-version 2.0.1 tex-base-level-bug.html +--min-version 2.0.1 tex-image-10bpc.html tex-image-and-sub-image-with-array-buffer-view-sub-source.html tex-image-with-bad-args.html tex-image-with-bad-args-from-dom-elements.html diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/textures/misc/tex-image-10bpc.html b/dom/canvas/test/webgl-conf/checkout/conformance2/textures/misc/tex-image-10bpc.html new file mode 100644 index 0000000000..973a0ec0f5 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/textures/misc/tex-image-10bpc.html @@ -0,0 +1,66 @@ +<!-- +Copyright (c) 2023 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8" /> +<title>Ensure 10bpc image is not crushed to 8bpc in texImage2D</title> +<link rel="stylesheet" href="../../../resources/js-test-style.css" /> +<script src="../../../js/js-test-pre.js"></script> +<script src="../../../js/webgl-test-utils.js"></script> +</head> +<body> +<canvas id="example" width="24" height="24"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description(document.title); +var wtu = WebGLTestUtils; +var gl = wtu.create3DContext("example", undefined, 2); +var uniquePixels; + +// This is an 8x1, 10-bit-per-channel PNG (encoded as 16bpc). +// The first pixel is black, and each next pixel is one brighter; approximately: +// (0/1023,0,0), (1/1023,0,0), (2/1023,0,0), ..., (7/1023,0,0) +const imgW = 8, imgH = 1; +const imgURL = "../../../resources/red-gradient-8x1-10bit-untagged.png"; + +const img = document.createElement("img"); +img.onload = () => { + const tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + const level = 0; + const internalformat = gl.RGB10_A2; + const border = 0; + const format = gl.RGBA; + const type = gl.UNSIGNED_INT_2_10_10_10_REV; + gl.texImage2D(gl.TEXTURE_2D, level, internalformat, imgW, imgH, border, format, type, img); + + const fbo = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0); + + shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE"); + + const pixels = new Uint32Array(imgW * imgH); + gl.readPixels(0, 0, imgW, imgH, format, type, pixels); + uniquePixels = new Set(pixels); + // If the image was crushed to 8bpc, there will be 2-3 distinct values: + // (0/255,0,0), (1/255,0,0), and maybe (2/255,0,0) (depending on truncation vs rounding). + // If it wasn't, there should be 7-8. + // At time of writing, on Mac M1, Chrome gets 2 if it's crushed, and 7 if it's not. + shouldBeGreaterThanOrEqual("uniquePixels.size", "7", "there should be at least 7 distinct color values"); + + finishTest(); +}; +img.src = imgURL; + +var successfullyParsed = true; +</script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/textures/misc/tex-image-with-bad-args-from-dom-elements.html b/dom/canvas/test/webgl-conf/checkout/conformance2/textures/misc/tex-image-with-bad-args-from-dom-elements.html index f1616e81d7..34ece05699 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance2/textures/misc/tex-image-with-bad-args-from-dom-elements.html +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/textures/misc/tex-image-with-bad-args-from-dom-elements.html @@ -106,7 +106,6 @@ var tests = [ { type: "video", src: "../../../resources/red-green.mp4", videoType: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"', run: testVideo }, { type: "video", src: "../../../resources/red-green.bt601.vp9.webm", videoType: 'video/webm; codecs="vp9"', run: testVideo }, { type: "video", src: "../../../resources/red-green.webmvp8.webm", videoType: 'video/webm; codecs="vp8, vorbis"', run: testVideo }, - { type: "video", src: "../../../resources/red-green.theora.ogv", videoType: 'video/ogg; codecs="theora, vorbis"', run: testVideo }, ]; var testIndex = 0; diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/textures/misc/tex-new-formats.html b/dom/canvas/test/webgl-conf/checkout/conformance2/textures/misc/tex-new-formats.html index df10edb4d3..760bc6bd19 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance2/textures/misc/tex-new-formats.html +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/textures/misc/tex-new-formats.html @@ -37,6 +37,7 @@ if (!gl) { testPassed("WebGL context exists"); runTexFormatsTest(); + runDepthStencilFormatTest(); wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors"); } @@ -556,6 +557,35 @@ function runTexFormatsTest() }); } +function runDepthStencilFormatTest() { + debug(""); + debug("Testing FLOAT_32_UNSIGNED_INT_24_8_REV with data"); + const fb = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fb); + + const tex2D = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex2D); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH32F_STENCIL8, 1, 1, 0, gl.DEPTH_STENCIL, gl.FLOAT_32_UNSIGNED_INT_24_8_REV, new Uint8Array(8)); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_2D, tex2D, 0); + if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) { + testFailed("2D texture with invalid type was created"); + } else { + testPassed("2D texture with invalid type was not created") + } + + const tex3D = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D_ARRAY, tex3D); + gl.texImage3D(gl.TEXTURE_2D_ARRAY, 0, gl.DEPTH32F_STENCIL8, 1, 1, 1, 0, gl.DEPTH_STENCIL, gl.FLOAT_32_UNSIGNED_INT_24_8_REV, new Uint8Array(8)); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION); + gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, tex3D, 0, 0); + if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) { + testFailed("2D array texture with invalid type was created"); + } else { + testPassed("2D array texture with invalid type was not created") + } +} + debug(""); var successfullyParsed = true; </script> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/simultaneous_binding.html b/dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/simultaneous_binding.html index 228b4ab5cf..11d1eaa829 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/simultaneous_binding.html +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/simultaneous_binding.html @@ -304,6 +304,17 @@ for (let genericBindPointValue of genericBindPointValues) { gl.copyBufferSubData(gl.COPY_READ_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, 1); wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "copyBufferSubData with double bound buffer"); + debug("<hr/>Test that rejected operations do not change the bound buffer size"); + + gl.bindBuffer(gl.ARRAY_BUFFER, tfBuffer); + gl.bufferData(gl.ARRAY_BUFFER, 8, gl.STATIC_DRAW); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "bufferData with double bound buffer"); + + gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null); + gl.bufferSubData(gl.ARRAY_BUFFER, 0, new Uint8Array(16)); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "bufferSubData should succeed"); + gl.bindBuffer(gl.ARRAY_BUFFER, null); + debug("<hr/>Test bufferData family with tf object unbound"); gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null); diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/transform_feedback.html b/dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/transform_feedback.html index 20256c6ace..16855453f0 100644 --- a/dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/transform_feedback.html +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/transform_feedback.html @@ -64,6 +64,8 @@ if (!gl) { runUnboundDeleteTest(); runBoundDeleteTest(); runOneOutputFeedbackTest(); + runUnchangedBufferBindingsTest(); + runNoOutputsTest(); // Must be the last test, since it's asynchronous and calls finishTest(). runTwoOutputFeedbackTest(); } @@ -638,6 +640,70 @@ function runContextLostOneOutputFeedbackTest() { finishTest(); } +function runUnchangedBufferBindingsTest() { + debug(""); + debug("Testing that buffer bindings cannot be changed while transform feedback is active"); + + program = wtu.setupTransformFeedbackProgram( + gl, [wtu.simpleVertexShader, wtu.simpleColorFragmentShader], ['gl_Position'], gl.INTERLEAVED_ATTRIBS); + + tf = gl.createTransformFeedback(); + gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf); + + buf = gl.createBuffer(); + gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, buf); + + gl.beginTransformFeedback(gl.POINTS); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Transform feedback is active"); + + gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, gl.createBuffer()); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Cannot change the bound buffer while transform feedback is active"); + shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING, 0)", "buf"); + + gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, buf); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Cannot rebind the same buffer while transform feedback is active"); + + gl.bindBufferRange(gl.TRANSFORM_FEEDBACK_BUFFER, 0, gl.createBuffer(), 0, 64); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Cannot change the bound buffer while transform feedback is active"); + shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING, 0)", "buf"); + + gl.bindBufferRange(gl.TRANSFORM_FEEDBACK_BUFFER, 0, buf, 0, 64); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Cannot rebind the same buffer while transform feedback is active"); + + gl.endTransformFeedback(); + gl.deleteTransformFeedback(tf); + gl.deleteBuffer(buf); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No extra errors after the test"); +} + +function runNoOutputsTest() { + debug(""); + debug("Testing transform feedback with no varyings to record"); + + tf = gl.createTransformFeedback(); + gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf); + + buf = gl.createBuffer(); + gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, buf); + + for (const mode of ['SEPARATE_ATTRIBS', 'INTERLEAVED_ATTRIBS']) { + program = wtu.setupTransformFeedbackProgram( + gl, [wtu.simpleVertexShader, wtu.simpleColorFragmentShader], [], gl[mode]); + + debug(`Testing with ${mode}`); + gl.beginTransformFeedback(gl.POINTS); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "beginTransformFeedback: No varyings to record"); + gl.useProgram(null); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "useProgram: Transform feedback is not active"); + gl.endTransformFeedback(); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "endTransformFeedback: Transform feedback is not active"); + } + + gl.deleteTransformFeedback(tf); + gl.deleteBuffer(buf); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No extra errors after the test"); +} + debug(""); </script> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/00_test_list.txt b/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/00_test_list.txt new file mode 100644 index 0000000000..d188fc30a6 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/00_test_list.txt @@ -0,0 +1,12 @@ +--min-version 2.0.1 readpixels-16gb-wasm-memory.html +--min-version 2.0.1 readpixels-4gb-wasm-memory.html +--min-version 2.0.1 teximage2d-16gb-wasm-memory.html +--min-version 2.0.1 teximage2d-4gb-wasm-memory.html +--min-version 2.0.1 texsubimage2d-16gb-wasm-memory.html +--min-version 2.0.1 texsubimage2d-4gb-wasm-memory.html +--min-version 2.0.1 bufferdata-16gb-wasm-memory.html +--min-version 2.0.1 bufferdata-4gb-wasm-memory.html +--min-version 2.0.1 buffersubdata-16gb-wasm-memory.html +--min-version 2.0.1 buffersubdata-4gb-wasm-memory.html +--min-version 2.0.1 getbuffersubdata-16gb-wasm-memory.html +--min-version 2.0.1 getbuffersubdata-4gb-wasm-memory.html
\ No newline at end of file diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/bufferdata-16gb-wasm-memory.html b/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/bufferdata-16gb-wasm-memory.html new file mode 100644 index 0000000000..0dd21bf64f --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/bufferdata-16gb-wasm-memory.html @@ -0,0 +1,51 @@ +<!-- +Copyright (c) 2024 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>bufferData test to Wasm Memory 16GB in size.</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"> </script> +</head> +<body> +<canvas id="canvas" width="2" height="2" style="width: 40px; height: 40px;"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description(document.title); +debug("Tests that bufferData can be called on WebAssembly Memory of 16GB in size."); +debug(""); +let wtu = WebGLTestUtils; +let gl = wtu.create3DContext("canvas", undefined, 2); + +const PAGE = 65536; +const SIZE = 16 * 1024 * 1024 * 1024; +let view = new Uint8Array(new WebAssembly.Memory({ index: 'i64', initial: SIZE / PAGE }).buffer); +let expectedData = new Uint8Array([1, 2, 3, 4]); +const length = expectedData.length; +const offset = SIZE - length; +view.set(expectedData, offset); + +let buf = gl.createBuffer(); +gl.bindBuffer(gl.ARRAY_BUFFER, buf); +gl.bufferData(gl.ARRAY_BUFFER, view, gl.STATIC_DRAW, offset, length); +wtu.glErrorShouldBe(gl, gl.NO_ERROR); + +let actualData = new Uint8Array(length); +gl.getBufferSubData(gl.ARRAY_BUFFER, 0, actualData); +wtu.glErrorShouldBe(gl, gl.NO_ERROR); +for (let i = 0; i < length; i++) { + shouldBe(`actualData[${i}]`, `expectedData[${i}]`); +} + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/bufferdata-4gb-wasm-memory.html b/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/bufferdata-4gb-wasm-memory.html new file mode 100644 index 0000000000..2296c3a5ea --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/bufferdata-4gb-wasm-memory.html @@ -0,0 +1,51 @@ +<!-- +Copyright (c) 2024 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>bufferData test to Wasm Memory 4GB in size.</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"> </script> +</head> +<body> +<canvas id="canvas" width="2" height="2" style="width: 40px; height: 40px;"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description(document.title); +debug("Tests that bufferData can be called on WebAssembly Memory of 4GB in size."); +debug(""); +let wtu = WebGLTestUtils; +let gl = wtu.create3DContext("canvas", undefined, 2); + +const PAGE = 65536; +const SIZE = 4 * 1024 * 1024 * 1024 - PAGE; +let view = new Uint8Array(new WebAssembly.Memory({ initial: SIZE / PAGE }).buffer); +let expectedData = new Uint8Array([1, 2, 3, 4]); +const length = expectedData.length; +const offset = SIZE - length; +view.set(expectedData, offset); + +let buf = gl.createBuffer(); +gl.bindBuffer(gl.ARRAY_BUFFER, buf); +gl.bufferData(gl.ARRAY_BUFFER, view, gl.STATIC_DRAW, offset, length); +wtu.glErrorShouldBe(gl, gl.NO_ERROR); + +let actualData = new Uint8Array(length); +gl.getBufferSubData(gl.ARRAY_BUFFER, 0, actualData); +wtu.glErrorShouldBe(gl, gl.NO_ERROR); +for (let i = 0; i < length; i++) { + shouldBe(`actualData[${i}]`, `expectedData[${i}]`); +} + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/buffersubdata-16gb-wasm-memory.html b/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/buffersubdata-16gb-wasm-memory.html new file mode 100644 index 0000000000..08d6d1df50 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/buffersubdata-16gb-wasm-memory.html @@ -0,0 +1,52 @@ +<!-- +Copyright (c) 2024 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>bufferSubData test to Wasm Memory 16GB in size.</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"> </script> +</head> +<body> +<canvas id="canvas" width="2" height="2" style="width: 40px; height: 40px;"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description(document.title); +debug("Tests that bufferSubData can be called on WebAssembly Memory of 16GB in size."); +debug(""); +let wtu = WebGLTestUtils; +let gl = wtu.create3DContext("canvas", undefined, 2); + +const PAGE = 65536; +const SIZE = 16 * 1024 * 1024 * 1024; +let view = new Uint8Array(new WebAssembly.Memory({ index: 'i64', initial: SIZE / PAGE }).buffer); +let expectedData = new Uint8Array([1, 2]); +const length = expectedData.length; +let srcOffset = SIZE - length; +view.set(expectedData, srcOffset); +const dstByteOffset = 4; + +let buf = gl.createBuffer(); +gl.bindBuffer(gl.ARRAY_BUFFER, buf); +gl.bufferData(gl.ARRAY_BUFFER, 8, gl.STATIC_DRAW); +gl.bufferSubData(gl.ARRAY_BUFFER, dstByteOffset, view, srcOffset, length); +wtu.glErrorShouldBe(gl, gl.NO_ERROR); + +let actualData = new Uint8Array(length); +gl.getBufferSubData(gl.ARRAY_BUFFER, dstByteOffset, actualData); +for (let i = 0; i < length; i++) { + shouldBe(`actualData[${i}]`, `expectedData[${i}]`); +} + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/buffersubdata-4gb-wasm-memory.html b/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/buffersubdata-4gb-wasm-memory.html new file mode 100644 index 0000000000..2834a6901b --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/buffersubdata-4gb-wasm-memory.html @@ -0,0 +1,52 @@ +<!-- +Copyright (c) 2024 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>bufferSubData test to Wasm Memory 4GB in size.</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"> </script> +</head> +<body> +<canvas id="canvas" width="2" height="2" style="width: 40px; height: 40px;"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description(document.title); +debug("Tests that bufferSubData can be called on WebAssembly Memory of 4GB in size."); +debug(""); +let wtu = WebGLTestUtils; +let gl = wtu.create3DContext("canvas", undefined, 2); + +const PAGE = 65536; +const SIZE = 4 * 1024 * 1024 * 1024 - PAGE; +let view = new Uint8Array(new WebAssembly.Memory({ initial: SIZE / PAGE }).buffer); +let expectedData = new Uint8Array([1, 2]); +const length = expectedData.length; +let srcOffset = SIZE - length; +view.set(expectedData, srcOffset); +const dstByteOffset = 4; + +let buf = gl.createBuffer(); +gl.bindBuffer(gl.ARRAY_BUFFER, buf); +gl.bufferData(gl.ARRAY_BUFFER, 8, gl.STATIC_DRAW); +gl.bufferSubData(gl.ARRAY_BUFFER, dstByteOffset, view, srcOffset, length); +wtu.glErrorShouldBe(gl, gl.NO_ERROR); + +let actualData = new Uint8Array(length); +gl.getBufferSubData(gl.ARRAY_BUFFER, dstByteOffset, actualData); +for (let i = 0; i < length; i++) { + shouldBe(`actualData[${i}]`, `expectedData[${i}]`); +} + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/getbuffersubdata-16gb-wasm-memory.html b/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/getbuffersubdata-16gb-wasm-memory.html new file mode 100644 index 0000000000..8390957b02 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/getbuffersubdata-16gb-wasm-memory.html @@ -0,0 +1,48 @@ +<!-- +Copyright (c) 2024 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>getBufferSubData test to Wasm Memory 16GB in size.</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"> </script> +</head> +<body> +<canvas id="canvas" width="2" height="2" style="width: 40px; height: 40px;"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description(document.title); +debug("Tests that getBufferSubData can be called on WebAssembly Memory of 16GB in size."); +debug(""); +let wtu = WebGLTestUtils; +let gl = wtu.create3DContext("canvas", undefined, 2); + +const PAGE = 65536; +const SIZE = 16 * 1024 * 1024 * 1024; +let view = new Uint8Array(new WebAssembly.Memory({ index: 'i64', initial: SIZE / PAGE }).buffer); +let expectedData = new Uint8Array([1, 2, 3, 4]); + +let buf = gl.createBuffer(); +gl.bindBuffer(gl.ARRAY_BUFFER, buf); +gl.bufferData(gl.ARRAY_BUFFER, expectedData, gl.STATIC_DRAW); + +const length = expectedData.length; +const offset = SIZE - length; +gl.getBufferSubData(gl.ARRAY_BUFFER, 0, view, offset, length); +wtu.glErrorShouldBe(gl, gl.NO_ERROR); +for (let i = 0; i < length; i++) { + shouldBe(`view[${i + offset}]`, `expectedData[${i}]`); +} + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/getbuffersubdata-4gb-wasm-memory.html b/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/getbuffersubdata-4gb-wasm-memory.html new file mode 100644 index 0000000000..09a336b753 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/getbuffersubdata-4gb-wasm-memory.html @@ -0,0 +1,48 @@ +<!-- +Copyright (c) 2024 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>getBufferSubData test to Wasm Memory 4GB in size.</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"> </script> +</head> +<body> +<canvas id="canvas" width="2" height="2" style="width: 40px; height: 40px;"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description(document.title); +debug("Tests that getBufferSubData can be called on WebAssembly Memory of 4GB in size."); +debug(""); +let wtu = WebGLTestUtils; +let gl = wtu.create3DContext("canvas", undefined, 2); + +const PAGE = 65536; +const SIZE = 4 * 1024 * 1024 * 1024 - PAGE; +let view = new Uint8Array(new WebAssembly.Memory({ initial: SIZE / PAGE }).buffer); +let expectedData = new Uint8Array([1, 2, 3, 4]); + +let buf = gl.createBuffer(); +gl.bindBuffer(gl.ARRAY_BUFFER, buf); +gl.bufferData(gl.ARRAY_BUFFER, expectedData, gl.STATIC_DRAW); + +const length = expectedData.length; +const offset = SIZE - length; +gl.getBufferSubData(gl.ARRAY_BUFFER, 0, view, offset, length); +wtu.glErrorShouldBe(gl, gl.NO_ERROR); +for (let i = 0; i < length; i++) { + shouldBe(`view[${i + offset}]`, `expectedData[${i}]`); +} + +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/readpixels-16gb-wasm-memory.html b/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/readpixels-16gb-wasm-memory.html new file mode 100644 index 0000000000..af74678dda --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/readpixels-16gb-wasm-memory.html @@ -0,0 +1,51 @@ +<!-- +Copyright (c) 2023 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>gl.readPixels() test to Wasm Memory 16GB in size.</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"> </script> +</head> +<body> +<canvas id="canvas" width="2" height="2" style="width: 40px; height: 40px;"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description(document.title); +debug(""); +debug("Tests that gl.readPixels() can be called on WebAssembly Memory of 16GB in size."); +debug(""); +let wtu = WebGLTestUtils; +let gl = wtu.create3DContext("canvas", undefined, 2); + +const PAGE = 65536; +const SIZE = 16*1024*1024*1024; +let view = new Uint8Array(new WebAssembly.Memory({ index: 'i64', initial: SIZE/PAGE }).buffer); + +// Clear the canvas to a specific color +const expectedColor = [42, 84, 128, 255]; +gl.clearColor(expectedColor[0]/255.0, expectedColor[1]/255.0, expectedColor[2]/255.0, expectedColor[3]/255.0); +gl.clear(gl.COLOR_BUFFER_BIT); + +// Test that gl.readPixels() can be called with a high offset to Memory +const offset = SIZE - 4; +view.set([0,0,0,0], offset); // For good measure, clear data at offset before reading +gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, view, offset); +wtu.glErrorShouldBe(gl, gl.NO_ERROR); +let obtainedColor = view.subarray(offset, offset+4); +shouldBe('obtainedColor[0]', 'expectedColor[0]'); +shouldBe('obtainedColor[1]', 'expectedColor[1]'); +shouldBe('obtainedColor[2]', 'expectedColor[2]'); +shouldBe('obtainedColor[3]', 'expectedColor[3]'); +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/readpixels-4gb-wasm-memory.html b/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/readpixels-4gb-wasm-memory.html new file mode 100644 index 0000000000..f97a3ccba0 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/readpixels-4gb-wasm-memory.html @@ -0,0 +1,50 @@ +<!-- +Copyright (c) 2023 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>gl.readPixels() test to Wasm Memory 4GB in size.</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"> </script> +</head> +<body> +<canvas id="canvas" width="2" height="2" style="width: 40px; height: 40px;"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description(document.title); +debug("Tests that gl.readPixels() can be called on WebAssembly Memory of 4GB in size."); +debug(""); +let wtu = WebGLTestUtils; +let gl = wtu.create3DContext("canvas", undefined, 2); + +const PAGE = 65536; +const SIZE = 4*1024*1024*1024 - PAGE; // when uint32_t size is max, we can only reach one page short of full 4GB +let view = new Uint8Array(new WebAssembly.Memory({ initial: SIZE/PAGE }).buffer); + +// Clear the canvas to a specific color +const expectedColor = [42, 84, 128, 255]; +gl.clearColor(expectedColor[0]/255.0, expectedColor[1]/255.0, expectedColor[2]/255.0, expectedColor[3]/255.0); +gl.clear(gl.COLOR_BUFFER_BIT); + +// Test that gl.readPixels() can be called with a high offset to Memory +const offset = SIZE - 4; +view.set([0,0,0,0], offset); // For good measure, clear data at offset before reading +gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, view, offset); +wtu.glErrorShouldBe(gl, gl.NO_ERROR); +let obtainedColor = view.subarray(offset, offset+4); +shouldBe('obtainedColor[0]', 'expectedColor[0]'); +shouldBe('obtainedColor[1]', 'expectedColor[1]'); +shouldBe('obtainedColor[2]', 'expectedColor[2]'); +shouldBe('obtainedColor[3]', 'expectedColor[3]'); +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/teximage2d-16gb-wasm-memory.html b/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/teximage2d-16gb-wasm-memory.html new file mode 100644 index 0000000000..8ce5111953 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/teximage2d-16gb-wasm-memory.html @@ -0,0 +1,85 @@ +<!-- +Copyright (c) 2023 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>gl.texImage2D() test to Wasm Memory 16GB in size.</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"> </script> +</head> +<body> +<canvas id="canvas" width="2" height="2" style="width: 40px; height: 40px;"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description(document.title); +debug("Tests that gl.texImage2D() can be called on WebAssembly Memory 16GB in size."); +debug(""); +let wtu = WebGLTestUtils; +let gl = wtu.create3DContext("canvas", undefined, 2); + +const PAGE = 65536; +const SIZE = 16*1024*1024*1024; +let view = new Uint8Array(new WebAssembly.Memory({ index: 'i64', initial: SIZE/PAGE }).buffer); + +function compileShader(type, src) { + let shader = gl.createShader(type); + gl.shaderSource(shader, src); + gl.compileShader(shader); + let log = gl.getShaderInfoLog(shader); + if (log) debug(log); + return shader; +} + +function createProgram(vs, fs) { + let program = gl.createProgram(); + gl.attachShader(program, vs); + gl.attachShader(program, fs); + gl.bindAttribLocation(program, 0, 'pos'); + gl.linkProgram(program); + gl.useProgram(program); + return program; +} + +let program = createProgram( + compileShader(gl.VERTEX_SHADER, ` + varying vec2 uv; + attribute vec2 pos; + void main() { uv = pos; gl_Position = vec4(pos*2.0-vec2(1.0,1.0),0,1); }`), + compileShader(gl.FRAGMENT_SHADER, ` + precision lowp float; + uniform sampler2D tex; + varying vec2 uv; + void main() { gl_FragColor = texture2D(tex,uv); }`)); + +gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer()); +gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, 1, 0, 0, 1, 1, 1]), gl.STATIC_DRAW); +gl.vertexAttribPointer(0, 2, gl.FLOAT, gl.FALSE, 0, 0); +gl.enableVertexAttribArray(0); + +let texture = gl.createTexture(); +gl.bindTexture(gl.TEXTURE_2D, texture); + +// Test uploading an image +const expectedColor = [42, 84, 128, 255]; +const offset = SIZE - 4; +view.set(expectedColor, offset); +gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, view, offset); +wtu.glErrorShouldBe(gl, gl.NO_ERROR); + +// Test rendering with that image +gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); + +// Verify that we rendered what we expected +wtu.checkCanvasRect(gl, 0, 0, 1, 1, expectedColor, "texImage2D produced expected color"); +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/teximage2d-4gb-wasm-memory.html b/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/teximage2d-4gb-wasm-memory.html new file mode 100644 index 0000000000..5d6897347d --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/teximage2d-4gb-wasm-memory.html @@ -0,0 +1,85 @@ +<!-- +Copyright (c) 2023 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>gl.texImage2D() test to Wasm Memory 4GB in size.</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"> </script> +</head> +<body> +<canvas id="canvas" width="2" height="2" style="width: 40px; height: 40px;"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description(document.title); +debug("Tests that gl.texImage2D() can be called on WebAssembly Memory 4GB in size."); +debug(""); +let wtu = WebGLTestUtils; +let gl = wtu.create3DContext("canvas", undefined, 2); + +const PAGE = 65536; +const SIZE = 4*1024*1024*1024 - PAGE; // when uint32_t size is max, we can only reach one page short of full 4GB +let view = new Uint8Array(new WebAssembly.Memory({ initial: SIZE/PAGE }).buffer); + +function compileShader(type, src) { + let shader = gl.createShader(type); + gl.shaderSource(shader, src); + gl.compileShader(shader); + let log = gl.getShaderInfoLog(shader); + if (log) debug(log); + return shader; +} + +function createProgram(vs, fs) { + let program = gl.createProgram(); + gl.attachShader(program, vs); + gl.attachShader(program, fs); + gl.bindAttribLocation(program, 0, 'pos'); + gl.linkProgram(program); + gl.useProgram(program); + return program; +} + +let program = createProgram( + compileShader(gl.VERTEX_SHADER, ` + varying vec2 uv; + attribute vec2 pos; + void main() { uv = pos; gl_Position = vec4(pos*2.0-vec2(1.0,1.0),0,1); }`), + compileShader(gl.FRAGMENT_SHADER, ` + precision lowp float; + uniform sampler2D tex; + varying vec2 uv; + void main() { gl_FragColor = texture2D(tex,uv); }`)); + +gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer()); +gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, 1, 0, 0, 1, 1, 1]), gl.STATIC_DRAW); +gl.vertexAttribPointer(0, 2, gl.FLOAT, gl.FALSE, 0, 0); +gl.enableVertexAttribArray(0); + +let texture = gl.createTexture(); +gl.bindTexture(gl.TEXTURE_2D, texture); + +// Test uploading an image +const expectedColor = [42, 84, 128, 255]; +const offset = SIZE - 4; +view.set(expectedColor, offset); +gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, view, offset); +wtu.glErrorShouldBe(gl, gl.NO_ERROR); + +// Test rendering with that image +gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); + +// Verify that we rendered what we expected +wtu.checkCanvasRect(gl, 0, 0, 1, 1, expectedColor, "texImage2D produced expected color"); +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/texsubimage2d-16gb-wasm-memory.html b/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/texsubimage2d-16gb-wasm-memory.html new file mode 100644 index 0000000000..328d42ec49 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/texsubimage2d-16gb-wasm-memory.html @@ -0,0 +1,86 @@ +<!-- +Copyright (c) 2023 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>gl.texSubImage2D() test to Wasm Memory 16GB in size.</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"> </script> +</head> +<body> +<canvas id="canvas" width="2" height="2" style="width: 40px; height: 40px;"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description(document.title); +debug("Tests that gl.texSubImage2D() can be called on WebAssembly Memory 16GB in size."); +debug(""); +let wtu = WebGLTestUtils; +let gl = wtu.create3DContext("canvas", undefined, 2); + +const PAGE = 65536; +const SIZE = 16*1024*1024*1024; +let view = new Uint8Array(new WebAssembly.Memory({ index: 'i64', initial: SIZE/PAGE }).buffer); + +function compileShader(type, src) { + let shader = gl.createShader(type); + gl.shaderSource(shader, src); + gl.compileShader(shader); + let log = gl.getShaderInfoLog(shader); + if (log) debug(log); + return shader; +} + +function createProgram(vs, fs) { + let program = gl.createProgram(); + gl.attachShader(program, vs); + gl.attachShader(program, fs); + gl.bindAttribLocation(program, 0, 'pos'); + gl.linkProgram(program); + gl.useProgram(program); + return program; +} + +let program = createProgram( + compileShader(gl.VERTEX_SHADER, ` + varying vec2 uv; + attribute vec2 pos; + void main() { uv = pos; gl_Position = vec4(pos*2.0-vec2(1.0,1.0),0,1); }`), + compileShader(gl.FRAGMENT_SHADER, ` + precision lowp float; + uniform sampler2D tex; + varying vec2 uv; + void main() { gl_FragColor = texture2D(tex,uv); }`)); + +gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer()); +gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, 1, 0, 0, 1, 1, 1]), gl.STATIC_DRAW); +gl.vertexAttribPointer(0, 2, gl.FLOAT, gl.FALSE, 0, 0); +gl.enableVertexAttribArray(0); + +let texture = gl.createTexture(); +gl.bindTexture(gl.TEXTURE_2D, texture); + +// Test uploading an image +const expectedColor = [42, 84, 128, 255]; +const offset = SIZE - 4; +view.set(expectedColor, offset); +gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, 1, 1); +gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, view, offset); +wtu.glErrorShouldBe(gl, gl.NO_ERROR); + +// Test rendering with that image +gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); + +// Verify that we rendered what we expected +wtu.checkCanvasRect(gl, 0, 0, 1, 1, expectedColor, "texSubImage2D produced expected color"); +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/texsubimage2d-4gb-wasm-memory.html b/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/texsubimage2d-4gb-wasm-memory.html new file mode 100644 index 0000000000..d7756629a0 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance2/wasm/texsubimage2d-4gb-wasm-memory.html @@ -0,0 +1,86 @@ +<!-- +Copyright (c) 2023 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>gl.texSubImage2D() test to Wasm Memory 4GB in size.</title> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"> </script> +</head> +<body> +<canvas id="canvas" width="2" height="2" style="width: 40px; height: 40px;"></canvas> +<div id="description"></div> +<div id="console"></div> +<script> +"use strict"; +description(document.title); +debug("Tests that gl.texSubImage2D() can be called on WebAssembly Memory 4GB in size."); +debug(""); +let wtu = WebGLTestUtils; +let gl = wtu.create3DContext("canvas", undefined, 2); + +const PAGE = 65536; +const SIZE = 4*1024*1024*1024 - PAGE; // when uint32_t size is max, we can only reach one page short of full 4GB +let view = new Uint8Array(new WebAssembly.Memory({ initial: SIZE/PAGE }).buffer); + +function compileShader(type, src) { + let shader = gl.createShader(type); + gl.shaderSource(shader, src); + gl.compileShader(shader); + let log = gl.getShaderInfoLog(shader); + if (log) debug(log); + return shader; +} + +function createProgram(vs, fs) { + let program = gl.createProgram(); + gl.attachShader(program, vs); + gl.attachShader(program, fs); + gl.bindAttribLocation(program, 0, 'pos'); + gl.linkProgram(program); + gl.useProgram(program); + return program; +} + +let program = createProgram( + compileShader(gl.VERTEX_SHADER, ` + varying vec2 uv; + attribute vec2 pos; + void main() { uv = pos; gl_Position = vec4(pos*2.0-vec2(1.0,1.0),0,1); }`), + compileShader(gl.FRAGMENT_SHADER, ` + precision lowp float; + uniform sampler2D tex; + varying vec2 uv; + void main() { gl_FragColor = texture2D(tex,uv); }`)); + +gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer()); +gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, 1, 0, 0, 1, 1, 1]), gl.STATIC_DRAW); +gl.vertexAttribPointer(0, 2, gl.FLOAT, gl.FALSE, 0, 0); +gl.enableVertexAttribArray(0); + +let texture = gl.createTexture(); +gl.bindTexture(gl.TEXTURE_2D, texture); + +// Test uploading an image +const expectedColor = [42, 84, 128, 255]; +const offset = SIZE - 4; +view.set(expectedColor, offset); +gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, 1, 1); +gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, view, offset); +wtu.glErrorShouldBe(gl, gl.NO_ERROR); + +// Test rendering with that image +gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); + +// Verify that we rendered what we expected +wtu.checkCanvasRect(gl, 0, 0, 1, 1, expectedColor, "texSubImage2D produced expected color"); +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTestCase.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTestCase.js index ec08eea5ca..55913f4366 100644 --- a/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTestCase.js +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTestCase.js @@ -453,7 +453,32 @@ goog.scope(function() { if (inited) { // Run the test, save the result. + + const debug = tcuTestCase._debug = tcuTestCase._debug || (() => { + function LapStopwatch() { + this.lap = function() { + const now = performance.now(); + const ret = now - this.last; + this.last = now; + return ret; + }; + this.lap(); + } + return { + stopwatch: new LapStopwatch(), + testDoneCount: 0, + }; + })(); + const overheadDur = debug.stopwatch.lap(); + tcuTestCase.lastResult = state.currentTest.iterate(); + + const testDur = debug.stopwatch.lap(); + debug.testDoneCount += 1; + console.log( + `[test ${debug.testDoneCount}] Ran in ${testDur}ms`, + `(+ ${overheadDur}ms overhead)`, + ); } else { // Skip uninitialized test. tcuTestCase.lastResult = tcuTestCase.IterateResult.STOP; @@ -484,8 +509,8 @@ goog.scope(function() { } tcuTestCase.runner.runCallback(tcuTestCase.runTestCases); - } else + } else { tcuTestCase.runner.terminate(); + } }; - }); diff --git a/dom/canvas/test/webgl-conf/checkout/extra/tex-image-with-video-test.js b/dom/canvas/test/webgl-conf/checkout/extra/tex-image-with-video-test.js index 01f56b56c3..d2d6be0e28 100644 --- a/dom/canvas/test/webgl-conf/checkout/extra/tex-image-with-video-test.js +++ b/dom/canvas/test/webgl-conf/checkout/extra/tex-image-with-video-test.js @@ -27,7 +27,6 @@ function generateTest(pixelFormat, pixelType, prologue) { { src: "../resources/red-green.mp4" , type: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"', }, { src: "../resources/red-green.webmvp8.webm", type: 'video/webm; codecs="vp8, vorbis"', }, { src: "../resources/red-green.webmvp9.webm", type: 'video/webm; codecs="vp9"', }, - { src: "../resources/red-green.theora.ogv", type: 'video/ogg; codecs="theora, vorbis"', }, ]; var videoNdx = 0; diff --git a/dom/canvas/test/webgl-conf/checkout/js/js-test-pre.js b/dom/canvas/test/webgl-conf/checkout/js/js-test-pre.js index e1cb9f749c..adc1f8a5aa 100644 --- a/dom/canvas/test/webgl-conf/checkout/js/js-test-pre.js +++ b/dom/canvas/test/webgl-conf/checkout/js/js-test-pre.js @@ -93,20 +93,25 @@ const RESULTS = { fail: 0, }; +// We cache these values since they will potentially be accessed many (100k+) +// times and accessing window can be significantly slower than a local variable. +const locationPathname = window.location.pathname; +const webglTestHarness = window.parent.webglTestHarness; + function reportTestResultsToHarness(success, msg) { if (success) { RESULTS.pass += 1; } else { RESULTS.fail += 1; } - if (window.parent.webglTestHarness) { - window.parent.webglTestHarness.reportResults(window.location.pathname, success, msg); + if (webglTestHarness) { + webglTestHarness.reportResults(locationPathname, success, msg); } } function reportSkippedTestResultsToHarness(success, msg) { - if (window.parent.webglTestHarness) { - window.parent.webglTestHarness.reportResults(window.location.pathname, success, msg, true); + if (webglTestHarness) { + webglTestHarness.reportResults(locationPathname, success, msg, true); } } @@ -116,8 +121,8 @@ function notifyFinishedToHarness() { } window._didNotifyFinishedToHarness = true; - if (window.parent.webglTestHarness) { - window.parent.webglTestHarness.notifyFinished(window.location.pathname); + if (webglTestHarness) { + webglTestHarness.notifyFinished(locationPathname); } if (window.nonKhronosFrameworkNotifyDone) { window.nonKhronosFrameworkNotifyDone(); @@ -268,9 +273,9 @@ function getCurrentTestName() */ function testPassedOptions(msg, addSpan) { + reportTestResultsToHarness(true, _currentTestName + ": " + msg); if (addSpan && !quietMode()) { - reportTestResultsToHarness(true, _currentTestName + ": " + msg); _addSpan('<span><span class="pass">PASS</span> ' + escapeHTML(_currentTestName) + ": " + escapeHTML(msg) + '</span>'); } if (_jsTestPreVerboseLogging) { @@ -285,9 +290,9 @@ function testPassedOptions(msg, addSpan) */ function testSkippedOptions(msg, addSpan) { + reportSkippedTestResultsToHarness(true, _currentTestName + ": " + msg); if (addSpan && !quietMode()) { - reportSkippedTestResultsToHarness(true, _currentTestName + ": " + msg); _addSpan('<span><span class="warn">SKIP</span> ' + escapeHTML(_currentTestName) + ": " + escapeHTML(msg) + '</span>'); } if (_jsTestPreVerboseLogging) { diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/compressed-texture-utils.js b/dom/canvas/test/webgl-conf/checkout/js/tests/compressed-texture-utils.js index 46d155f5f1..04396c9b32 100644 --- a/dom/canvas/test/webgl-conf/checkout/js/tests/compressed-texture-utils.js +++ b/dom/canvas/test/webgl-conf/checkout/js/tests/compressed-texture-utils.js @@ -67,6 +67,10 @@ let testCompressedFormatsUnavailableWhenExtensionDisabled = function(gl, compres if (compressedFormats.hasOwnProperty(name)) { gl.compressedTexImage2D(gl.TEXTURE_2D, 0, compressedFormats[name], testSize, testSize, 0, new Uint8Array(expectedByteLength(testSize, testSize, compressedFormats[name]))); wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Trying to use format " + name + " with extension disabled."); + if (gl.texStorage2D) { + gl.texStorage2D(gl.TEXTURE_2D, 1, compressedFormats[name], testSize, testSize); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Trying to use format " + name + " with texStorage2D with extension disabled."); + } } } gl.bindTexture(gl.TEXTURE_2D, null); @@ -255,4 +259,4 @@ return { testTexStorageLevelDimensions: testTexStorageLevelDimensions, }; -})();
\ No newline at end of file +})(); diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/drawingbuffer-storage-test.js b/dom/canvas/test/webgl-conf/checkout/js/tests/drawingbuffer-storage-test.js new file mode 100644 index 0000000000..330171b320 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/js/tests/drawingbuffer-storage-test.js @@ -0,0 +1,275 @@ +/* +Copyright (c) 2023 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +*/ + +"use strict"; + +let gl; +let oldViewport; +let width; +let height; +let format; +let hasDrawingBufferStorage; +let maxRenderbufferSize; + +function runTest(contextVersion) { + description(); + debug(""); + + function initialize() { + let canvas = document.createElement("canvas"); + gl = wtu.create3DContext(canvas, {antialias: false}); + if (!gl) { + testFailed("context does not exist"); + return [0, 0]; + } + + hasDrawingBufferStorage = `drawingBufferStorage` in gl; + if (!hasDrawingBufferStorage) { + testPassed("drawingBufferStorage not present -- skipping test"); + return; + } + + maxRenderbufferSize = gl.getParameter(gl.MAX_RENDERBUFFER_SIZE); + } + + function testPixel(expected, actual, tol) { + let str = 'approx equal: expected: ' + expected + ', actual: ' + actual + ', tolerance: ' + tol; + for (let i = 0; i < 4; ++i) { + if (Math.abs(expected[i] - actual[i]) > tol) { + testFailed(str); + return; + } + } + testPassed(str); + } + + function srgbToLinear(x) { + if (x < 0.0) + return 0.0; + if (x < 0.04045) + return x / 12.92; + if (x < 1.0) { + return Math.pow((x + 0.055)/1.044, 2.4); + } + return 1.0; + } + + function testClearColor() { + // Make a fresh canvas. + let canvas = document.createElement("canvas"); + canvas.width = 16; + canvas.height = 16; + + gl = wtu.create3DContext(canvas, {antialias: false}); + if (!gl) { + testFailed("context does not exist"); + return; + } + testPassed("context exists"); + shouldBe('gl.drawingBufferFormat', 'gl.RGBA8'); + + let testCase = function(f, size, clearColor, expectedPixel, tolerance) { + format = f; + width = size[0]; + height = size[1]; + + gl.drawingBufferStorage(format, width, height); + shouldBe('gl.getError()', 'gl.NO_ERROR'); + + shouldBe('gl.drawingBufferFormat', 'format'); + shouldBe('gl.drawingBufferWidth', 'width'); + shouldBe('gl.drawingBufferHeight', 'height'); + + gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); + gl.clear(gl.COLOR_BUFFER_BIT); + + let buf; + if (format == 0x881A /*RGBA16F*/) { + buf = new Float32Array(4); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.FLOAT, buf); + } else { + buf = new Uint8Array(4); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, buf); + } + testPixel(expectedPixel, buf, tolerance); + } + + debug('Testing RGBA8'); + testCase(gl.RGBA8, [16, 32], + [16 / 255, 32 / 255, 64 / 255, 128 / 255], + [16, 32, 64, 128], + 0); + + // WebGL 1 must use EXT_sRGB for SRGB8_ALPHA8. + let srgb8_alpha8 = gl.SRGB8_ALPHA8; + if (!srgb8_alpha8) { + let ext = gl.getExtension('EXT_sRGB'); + if (ext) { + srgb8_alpha8 = ext.SRGB8_ALPHA8_EXT; + } + } + if (srgb8_alpha8) { + debug('Testing SRGB8_ALPHA8'); + testCase(srgb8_alpha8, [16, 32], + [srgbToLinear(64/255), srgbToLinear(16/255), srgbToLinear(32/255), 128 / 255], + [64, 16, 32, 128], + 1); + } + + if (gl.getExtension('EXT_color_buffer_float')) { + // WebGL 1 must use EXT_color_buffer_half_float for RGBA16F. + let rgba16f = gl.RGBA16F; + if (!rgba16f) { + let ext = gl.getExtension('EXT_color_buffer_half_float'); + if (ext) { + rgba16f = ext.RGBA16F_EXT; + } + } + + debug('Testing RGBA16F'); + testCase(rgba16f, [18, 28], + [0.25, 0.5, 0.75, 0.125], + [0.25, 0.5, 0.75, 0.125], + 0.00001); + } else { + debug('Skipping RGBA16F'); + } + + shouldBe('gl.getError()', 'gl.NO_ERROR'); + } + + function testNoAlpha() { + let canvas = document.createElement("canvas"); + canvas.width = 16; + canvas.height = 16; + gl = wtu.create3DContext(canvas, {alpha:false}); + if (!gl) { + testFailed("context does not exist"); + return; + } + debug('Testing alpha:false'); + + // Report RGB8 for the format. + shouldBe('gl.drawingBufferFormat', 'gl.RGB8'); + + // If WebGLContextAttributes.alpha is false, generate INVALID_OPERATION. + gl.drawingBufferStorage(gl.RGBA8, 16, 16); + shouldBe('gl.getError()', 'gl.INVALID_OPERATION'); + } + + function testMissingExtension() { + let canvas = document.createElement("canvas"); + canvas.width = 16; + canvas.height = 16; + gl = wtu.create3DContext(canvas); + if (!gl) { + testFailed("context does not exist"); + return; + } + + debug('Testing use of RGBA16F without enabling EXT_color_buffer_float'); + gl.drawingBufferStorage(gl.RGBA16F, 16, 16); + shouldBe('gl.getError()', 'gl.INVALID_ENUM'); + } + + function testMaxSize() { + let canvas = document.createElement("canvas"); + canvas.width = 16; + canvas.height = 16; + gl = wtu.create3DContext(canvas); + if (!gl) { + testFailed("context does not exist"); + return; + } + + debug('Testing maximum size'); + gl.drawingBufferStorage(gl.RGBA8, maxRenderbufferSize, maxRenderbufferSize); + shouldBe('gl.getError()', 'gl.NONE'); + shouldBe('gl.drawingBufferWidth', 'maxRenderbufferSize'); + shouldBe('gl.drawingBufferHeight', 'maxRenderbufferSize'); + + debug('Testing over-maximum width and ehgith'); + gl.drawingBufferStorage(gl.RGBA8, maxRenderbufferSize+1, 16); + shouldBe('gl.getError()', 'gl.INVALID_VALUE'); + gl.drawingBufferStorage(gl.RGBA8, 16, maxRenderbufferSize+1); + shouldBe('gl.getError()', 'gl.INVALID_VALUE'); + shouldBe('gl.drawingBufferWidth', 'maxRenderbufferSize'); + shouldBe('gl.drawingBufferHeight', 'maxRenderbufferSize'); + } + + function testDrawToCanvas() { + let canvasGL = document.createElement("canvas"); + canvasGL.width = 16; + canvasGL.height = 16; + gl = wtu.create3DContext(canvasGL); + if (!gl) { + testFailed("context does not exist"); + return; + } + + let canvas2D = document.createElement("canvas"); + canvas2D.width = 16; + canvas2D.height = 16; + let ctx = canvas2D.getContext('2d'); + let imageData = new ImageData(16, 16); + + let testCase = function(f, clearColor, canvasColor, tolerance) { + gl.drawingBufferStorage(f, 16, 16); + gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); + gl.clear(gl.COLOR_BUFFER_BIT); + + ctx.putImageData(imageData, 0, 0); + ctx.drawImage(canvasGL, 0, 0); + testPixel(canvasColor, ctx.getImageData(8, 8, 1, 1).data, tolerance); + } + + debug('Drawing RGBA to canvas'); + testCase(gl.RGBA8, [16/255, 32/255, 64/255, 64/255], [64, 128, 255, 64], 0); + + // WebGL 1 must use EXT_sRGB for SRGB8_ALPHA8. + let srgb8_alpha8 = gl.SRGB8_ALPHA8; + if (!srgb8_alpha8) { + let ext = gl.getExtension('EXT_sRGB'); + if (ext) { + srgb8_alpha8 = ext.SRGB8_ALPHA8_EXT; + } + } + if (srgb8_alpha8) { + debug('Drawing opaque SRGB8_ALPHA8 to canvas'); + testCase(srgb8_alpha8, + [srgbToLinear(64/255), srgbToLinear(32/255), srgbToLinear(16/255), 1.0], + [64, 32, 16, 255], + 1); + + debug('Drawing transparent SRGB8_ALPHA8 to canvas'); + // We set the tolerance to 5 because of compounding error. The backbuffer + // may be off by 1, and then un-premultiplying alpha of 64/55 will multiply + // that error by 4. Then add one to be safe. + testCase(srgb8_alpha8, + [srgbToLinear(32/255), srgbToLinear(64/255), srgbToLinear(16/255), 64/255], + [128, 255, 64, 64], + 5); + } + + if (gl.getExtension('EXT_color_buffer_float')) { + debug('Drawing transparent RGBA16F to canvas'); + testCase(gl.RGBA16F, + [32/255, 64/255, 16/255, 64/255], + [128, 255, 64, 64], + 1); + } + } + + let wtu = WebGLTestUtils; + initialize(); + if (hasDrawingBufferStorage) { + testClearColor(); + testNoAlpha(); + testMissingExtension(); + testMaxSize(); + testDrawToCanvas(); + } +} diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/ext-color-buffer-half-float.js b/dom/canvas/test/webgl-conf/checkout/js/tests/ext-color-buffer-half-float.js index 51509e8a6e..2975ec0fe4 100644 --- a/dom/canvas/test/webgl-conf/checkout/js/tests/ext-color-buffer-half-float.js +++ b/dom/canvas/test/webgl-conf/checkout/js/tests/ext-color-buffer-half-float.js @@ -422,6 +422,33 @@ if (!gl) { runRGB16FNegativeTest(); } + if (version == 1) { + debug(""); + debug("Testing that component type framebuffer attachment queries are rejected with the extension disabled"); + const fbo = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + + const rbo = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rbo); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,gl.RENDERBUFFER, rbo); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGB565, 8, 8); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setup renderbuffer should succeed."); + shouldBeNull('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, 0x8211 /* FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE */)'); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Query must fail."); + gl.deleteRenderbuffer(rbo); + + const tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 8, 8, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setup texture should succeed."); + shouldBeNull('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, 0x8211 /* FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE */)'); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Query must fail."); + gl.deleteTexture(tex); + + gl.deleteFramebuffer(fbo); + } + let oesTextureHalfFloat = null; if (version == 1) { // oesTextureHalfFloat implicitly enables EXT_color_buffer_half_float if supported @@ -466,6 +493,47 @@ if (!gl) { runCopyTexImageTest(true); runUniqueObjectTest(); + + { + debug(""); + debug("Testing that component type framebuffer attachment queries are accepted with the extension enabled"); + const fbo = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + + const rbo = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rbo); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,gl.RENDERBUFFER, rbo); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGB565, 8, 8); + shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, ext.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT)', 'ext.UNSIGNED_NORMALIZED_EXT'); + gl.renderbufferStorage(gl.RENDERBUFFER, ext.RGBA16F_EXT, 8, 8); + shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, ext.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT)', 'gl.FLOAT'); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No errors after valid renderbuffer attachment queries."); + + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT,gl.RENDERBUFFER, rbo); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, 8, 8); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No errors after depth-stencil renderbuffer setup."); + shouldBeNull('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, ext.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT)'); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Component type query is not allowed for combined depth-stencil attachments."); + gl.deleteRenderbuffer(rbo); + + const tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 8, 8, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, ext.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT)', 'ext.UNSIGNED_NORMALIZED_EXT'); + const tex_ext = gl.getExtension("OES_texture_half_float"); + if (version > 1 || tex_ext) { + if (version > 1) + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA16F, 8, 8, 0, gl.RGBA, gl.HALF_FLOAT, null); + else + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 8, 8, 0, gl.RGBA, tex_ext.HALF_FLOAT_OES, null); + shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, ext.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT)', 'gl.FLOAT'); + } + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No errors after valid texture attachment queries."); + gl.deleteTexture(tex); + + gl.deleteFramebuffer(fbo); + } } } diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-video.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-video.js index 14cf4628be..504b70564e 100644 --- a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-video.js +++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-video.js @@ -14,7 +14,6 @@ function generateTest(internalFormat, pixelFormat, pixelType, prologue, resource { src: resourcePath + "red-green.mp4" , type: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"', }, { src: resourcePath + "red-green.webmvp8.webm" , type: 'video/webm; codecs="vp8, vorbis"', }, { src: resourcePath + "red-green.bt601.vp9.webm", type: 'video/webm; codecs="vp9"', }, - { src: resourcePath + "red-green.theora.ogv" , type: 'video/ogg; codecs="theora, vorbis"', }, ]; function init() diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-video.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-video.js index 6e8bcf96e9..8dadde2d69 100644 --- a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-video.js +++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-video.js @@ -27,7 +27,6 @@ function generateTest(internalFormat, pixelFormat, pixelType, prologue, resource { src: resourcePath + "red-green.mp4" , type: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"', }, { src: resourcePath + "red-green.webmvp8.webm" , type: 'video/webm; codecs="vp8, vorbis"', }, { src: resourcePath + "red-green.bt601.vp9.webm", type: 'video/webm; codecs="vp9"', }, - { src: resourcePath + "red-green.theora.ogv" , type: 'video/ogg; codecs="theora, vorbis"', }, ]; function init() diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-video.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-video.js index a268f7d8d5..b1dbd33913 100644 --- a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-video.js +++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-video.js @@ -14,7 +14,6 @@ function generateTest(internalFormat, pixelFormat, pixelType, prologue, resource { src: resourcePath + "red-green.mp4" , type: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"', }, { src: resourcePath + "red-green.webmvp8.webm" , type: 'video/webm; codecs="vp8, vorbis"', }, { src: resourcePath + "red-green.bt601.vp9.webm", type: 'video/webm; codecs="vp9"', }, - { src: resourcePath + "red-green.theora.ogv" , type: 'video/ogg; codecs="theora, vorbis"', }, ]; function init() diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-video.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-video.js index 0c2c40e8a5..43ad660070 100644 --- a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-video.js +++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-video.js @@ -29,7 +29,6 @@ function generateTest(internalFormat, pixelFormat, pixelType, prologue, resource { src: resourcePath + "red-green.mp4" , type: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"', }, { src: resourcePath + "red-green.bt601.vp9.webm", type: 'video/webm; codecs="vp9"', }, { src: resourcePath + "red-green.webmvp8.webm", type: 'video/webm; codecs="vp8, vorbis"', }, - { src: resourcePath + "red-green.theora.ogv", type: 'video/ogg; codecs="theora, vorbis"', }, ]; function init() diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/webgl-blend-func-extended.js b/dom/canvas/test/webgl-conf/checkout/js/tests/webgl-blend-func-extended.js new file mode 100644 index 0000000000..086d9cfb16 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/js/tests/webgl-blend-func-extended.js @@ -0,0 +1,548 @@ +"use strict"; +description("This test verifies the functionality of the WEBGL_blend_func_extended extension, if it is available."); + +debug(""); + +var wtu = WebGLTestUtils; +var gl = wtu.create3DContext("c", undefined, contextVersion); +var ext; + +function runTestNoExtension() { + debug(""); + debug("Testing getParameter without the extension"); + shouldBeNull("gl.getParameter(0x88FC /* MAX_DUAL_SOURCE_DRAW_BUFFERS_WEBGL */)"); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + if (contextVersion == 1) { + debug(""); + debug("Testing SRC_ALPHA_SATURATE without the extension"); + + gl.blendFunc(gl.ONE, gl.SRC_ALPHA_SATURATE); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "SRC_ALPHA_SATURATE not accepted as blendFunc dfactor"); + gl.blendFuncSeparate(gl.ONE, gl.SRC_ALPHA_SATURATE, gl.ONE, gl.ONE); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "SRC_ALPHA_SATURATE not accepted as blendFuncSeparate dstRGB"); + gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, gl.SRC_ALPHA_SATURATE); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "SRC_ALPHA_SATURATE not accepted as blendFuncSeparate dstAlpha"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + } + + debug(""); + debug("Testing SRC1 blend funcs without the extension"); + + const extFuncs = { + SRC1_COLOR_WEBGL: 0x88F9, + SRC1_ALPHA_WEBGL: 0x8589, + ONE_MINUS_SRC1_COLOR_WEBGL: 0x88FA, + ONE_MINUS_SRC1_ALPHA_WEBGL: 0x88FB + }; + + for (const func in extFuncs) { + gl.blendFunc(extFuncs[func], gl.ONE); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFunc sfactor`); + gl.blendFunc(gl.ONE, extFuncs[func]); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFunc dfactor`); + gl.blendFuncSeparate(extFuncs[func], gl.ONE, gl.ONE, gl.ONE); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparate srcRGB`); + gl.blendFuncSeparate(gl.ONE, extFuncs[func], gl.ONE, gl.ONE); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparate dstRGB`); + gl.blendFuncSeparate(gl.ONE, gl.ONE, extFuncs[func], gl.ONE); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparate srcAlpha`); + gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, extFuncs[func]); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparate dstAlpha`); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + } + + const dbi = gl.getExtension("OES_draw_buffers_indexed"); + if (!dbi) return; + + debug(""); + debug("Testing indexed SRC1 blend funcs without the extension"); + for (const func in extFuncs) { + dbi.blendFunciOES(0, extFuncs[func], gl.ONE); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFunciOES src`); + dbi.blendFunciOES(0, gl.ONE, extFuncs[func]); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFunciOES dst`); + dbi.blendFuncSeparateiOES(0, extFuncs[func], gl.ONE, gl.ONE, gl.ONE); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparateiOES srcRGB`); + dbi.blendFuncSeparateiOES(0, gl.ONE, extFuncs[func], gl.ONE, gl.ONE); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparateiOES dstRGB`); + dbi.blendFuncSeparateiOES(0, gl.ONE, gl.ONE, extFuncs[func], gl.ONE); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparateiOES srcAlpha`); + dbi.blendFuncSeparateiOES(0, gl.ONE, gl.ONE, gl.ONE, extFuncs[func]); + wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, `${func} not accepted as blendFuncSeparateiOES dstAlpha`); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + } +} + +function runEnumTests() { + debug(""); + debug("Testing enums"); + shouldBe("ext.SRC1_COLOR_WEBGL", "0x88F9"); + shouldBe("ext.SRC1_ALPHA_WEBGL", "0x8589"); + shouldBe("ext.ONE_MINUS_SRC1_COLOR_WEBGL", "0x88FA"); + shouldBe("ext.ONE_MINUS_SRC1_ALPHA_WEBGL", "0x88FB"); + shouldBe("ext.MAX_DUAL_SOURCE_DRAW_BUFFERS_WEBGL", "0x88FC"); +} + +function runQueryTests() { + debug(""); + debug("Testing getParameter"); + shouldBeGreaterThanOrEqual("gl.getParameter(ext.MAX_DUAL_SOURCE_DRAW_BUFFERS_WEBGL)", "1"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + + if (contextVersion == 1) { + debug(""); + debug("Testing SRC_ALPHA_SATURATE with the extension"); + + gl.blendFunc(gl.ONE, gl.SRC_ALPHA_SATURATE); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "SRC_ALPHA_SATURATE accepted as blendFunc dfactor"); + shouldBe("gl.getParameter(gl.BLEND_DST_RGB)", "gl.SRC_ALPHA_SATURATE"); + shouldBe("gl.getParameter(gl.BLEND_DST_ALPHA)", "gl.SRC_ALPHA_SATURATE"); + gl.blendFuncSeparate(gl.ONE, gl.SRC_ALPHA_SATURATE, gl.ONE, gl.ONE); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "SRC_ALPHA_SATURATE accepted as blendFuncSeparate dstRGB"); + shouldBe("gl.getParameter(gl.BLEND_DST_RGB)", "gl.SRC_ALPHA_SATURATE"); + gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, gl.SRC_ALPHA_SATURATE); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "SRC_ALPHA_SATURATE accepted as blendFuncSeparate dstAlpha"); + shouldBe("gl.getParameter(gl.BLEND_DST_ALPHA)", "gl.SRC_ALPHA_SATURATE"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + } + + const extFuncs = [ + "SRC1_COLOR_WEBGL", + "SRC1_ALPHA_WEBGL", + "ONE_MINUS_SRC1_COLOR_WEBGL", + "ONE_MINUS_SRC1_ALPHA_WEBGL" + ]; + + debug(""); + debug("Testing blend state updates with SRC1 blend funcs"); + for (const func of extFuncs) { + gl.blendFunc(ext[func], gl.ONE); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFunc sfactor`); + shouldBe("gl.getParameter(gl.BLEND_SRC_RGB)", `ext.${func}`); + shouldBe("gl.getParameter(gl.BLEND_SRC_ALPHA)", `ext.${func}`); + gl.blendFunc(gl.ONE, ext[func]); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFunc dfactor`); + shouldBe("gl.getParameter(gl.BLEND_DST_RGB)", `ext.${func}`); + shouldBe("gl.getParameter(gl.BLEND_DST_ALPHA)", `ext.${func}`); + gl.blendFuncSeparate(ext[func], gl.ONE, gl.ONE, gl.ONE); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFuncSeparate srcRGB`); + shouldBe("gl.getParameter(gl.BLEND_SRC_RGB)", `ext.${func}`); + gl.blendFuncSeparate(gl.ONE, ext[func], gl.ONE, gl.ONE); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFuncSeparate dstRGB`); + shouldBe("gl.getParameter(gl.BLEND_DST_RGB)", `ext.${func}`); + gl.blendFuncSeparate(gl.ONE, gl.ONE, ext[func], gl.ONE); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFuncSeparate srcAlpha`); + shouldBe("gl.getParameter(gl.BLEND_SRC_ALPHA)", `ext.${func}`); + gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, ext[func]); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFuncSeparate dstAlpha`); + shouldBe("gl.getParameter(gl.BLEND_DST_ALPHA)", `ext.${func}`); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + } + + const dbi = gl.getExtension("OES_draw_buffers_indexed"); + if (!dbi) return; + + debug(""); + debug("Testing indexed blend state updates with SRC1 blend funcs"); + for (const func of extFuncs) { + dbi.blendFunciOES(0, ext[func], gl.ONE); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFunciOES src`); + shouldBe("gl.getIndexedParameter(gl.BLEND_SRC_RGB, 0)", `ext.${func}`); + shouldBe("gl.getIndexedParameter(gl.BLEND_SRC_ALPHA, 0)", `ext.${func}`); + dbi.blendFunciOES(0, gl.ONE, ext[func]); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} accepted as blendFunciOES dst`); + shouldBe("gl.getIndexedParameter(gl.BLEND_DST_RGB, 0)", `ext.${func}`); + shouldBe("gl.getIndexedParameter(gl.BLEND_DST_ALPHA, 0)", `ext.${func}`); + dbi.blendFuncSeparateiOES(0, ext[func], gl.ONE, gl.ONE, gl.ONE); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} not accepted as blendFuncSeparateiOES srcRGB`); + shouldBe("gl.getIndexedParameter(gl.BLEND_SRC_RGB, 0)", `ext.${func}`); + dbi.blendFuncSeparateiOES(0, gl.ONE, ext[func], gl.ONE, gl.ONE); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} not accepted as blendFuncSeparateiOES dstRGB`); + shouldBe("gl.getIndexedParameter(gl.BLEND_DST_RGB, 0)", `ext.${func}`); + dbi.blendFuncSeparateiOES(0, gl.ONE, gl.ONE, ext[func], gl.ONE); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} not accepted as blendFuncSeparateiOES srcAlpha`); + shouldBe("gl.getIndexedParameter(gl.BLEND_SRC_ALPHA, 0)", `ext.${func}`); + dbi.blendFuncSeparateiOES(0, gl.ONE, gl.ONE, gl.ONE, ext[func]); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, `${func} not accepted as blendFuncSeparateiOES dstAlpha`); + shouldBe("gl.getIndexedParameter(gl.BLEND_DST_ALPHA, 0)", `ext.${func}`); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); + } +} + +function runShaderTests(extensionEnabled) { + debug(""); + debug("Testing various shader compiles with extension " + (extensionEnabled ? "enabled" : "disabled")); + + const shaderSets = []; + + const macro100 = `precision mediump float; + void main() { + #ifdef GL_EXT_blend_func_extended + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + #else + #error no GL_EXT_blend_func_extended; + #endif + }`; + const macro300 = `#version 300 es + out mediump vec4 my_FragColor; + void main() { + #ifdef GL_EXT_blend_func_extended + my_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + #else + #error no GL_EXT_blend_func_extended; + #endif + }`; + shaderSets.push([wtu.simpleVertexShader, macro100]); + if (contextVersion == 2) { + shaderSets.push([wtu.simpleVertexShaderESSL300, macro300]); + } + + for (const shaders of shaderSets) { + // Expect the macro shader to succeed ONLY if enabled + if (wtu.setupProgram(gl, shaders)) { + if (extensionEnabled) { + testPassed("Macro defined in shaders when extension is enabled"); + } else { + testFailed("Macro defined in shaders when extension is disabled"); + } + } else { + if (extensionEnabled) { + testFailed("Macro not defined in shaders when extension is enabled"); + } else { + testPassed("Macro not defined in shaders when extension is disabled"); + } + } + } + + shaderSets.length = 0; + + const missing100 = ` + void main() { + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + gl_SecondaryFragColorEXT = vec4(0.0, 1.0, 0.0, 1.0); + }`; + shaderSets.push([wtu.simpleVertexShader, missing100]); + + const missing300 = `#version 300 es + layout(location = 0) out mediump vec4 oColor0; + layout(location = 0, index = 1) out mediump vec4 oColor1; + void main() { + oColor0 = vec4(1.0, 0.0, 0.0, 1.0); + oColor1 = vec4(0.0, 1.0, 0.0, 1.0); + }`; + if (contextVersion == 2) { + shaderSets.push([wtu.simpleVertexShaderESSL300, missing300]); + } + + // Always expect the shader missing the #extension pragma to fail (whether enabled or not) + for (const shaders of shaderSets) { + if (wtu.setupProgram(gl, shaders)) { + testFailed("Secondary fragment output allowed without #extension pragma"); + } else { + testPassed("Secondary fragment output disallowed without #extension pragma"); + } + } + + shaderSets.length = 0; + + const valid100 = `#extension GL_EXT_blend_func_extended : enable + void main() { + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + gl_SecondaryFragColorEXT = vec4(0.0, 1.0, 0.0, 1.0); + }`; + shaderSets.push([wtu.simpleVertexShader, valid100]); + + const valid300 = `#version 300 es + #extension GL_EXT_blend_func_extended : enable + layout(location = 0) out mediump vec4 oColor0; + layout(location = 0, index = 1) out mediump vec4 oColor1; + void main() { + oColor0 = vec4(1.0, 0.0, 0.0, 1.0); + oColor1 = vec4(0.0, 1.0, 0.0, 1.0); + }`; + if (contextVersion == 2) { + shaderSets.push([wtu.simpleVertexShaderESSL300, valid300]); + } + + // Try to compile a shader using a secondary fragment output that should only succeed if enabled + for (const shaders of shaderSets) { + if (wtu.setupProgram(gl, shaders)) { + if (extensionEnabled) { + testPassed("Secondary fragment output compiled successfully when extension enabled"); + } else { + testFailed("Secondary fragment output compiled successfully when extension disabled"); + } + } else { + if (extensionEnabled) { + testFailed("Secondary fragment output failed to compile when extension enabled"); + } else { + testPassed("Secondary fragment output failed to compile when extension disabled"); + } + } + } + + // ESSL 3.00: Testing that multiple outputs require explicit locations + if (contextVersion == 2) { + const locations300 = `#version 300 es + #extension GL_EXT_blend_func_extended : enable + out mediump vec4 color0; + out mediump vec4 color1; + void main() { + color0 = vec4(1.0, 0.0, 0.0, 1.0); + color1 = vec4(0.0, 1.0, 0.0, 1.0); + }`; + if (wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, locations300])) { + testFailed("Multiple fragment outputs compiled successfully without explicit locations"); + } else { + testPassed("Multiple fragment outputs failed to compile without explicit locations"); + } + } +} + +function runMissingOutputsTests() { + debug(""); + debug("Test draw calls with missing fragment outputs"); + + wtu.setupUnitQuad(gl); + gl.blendFunc(gl.ONE, ext.SRC1_COLOR_WEBGL); + + for (const enabled of [false, true]) { + if (enabled) { + gl.enable(gl.BLEND); + } else { + gl.disable(gl.BLEND); + } + + for (const maskedOut of [false, true]) { + gl.colorMask(!maskedOut, false, false, false); + + const label = `Dual-source blending ${enabled ? "ENABLED" : "DISABLED"}, ` + + `missing fragment outputs, and ` + + `${maskedOut ? "" : "NOT "}all color channels masked out`; + debug(`ESSL 1.00: ${label}`); + + { + const none = "void main() {}"; + wtu.setupProgram(gl, [wtu.simpleVertexShader, none]); + wtu.drawUnitQuad(gl); + wtu.glErrorShouldBe(gl, maskedOut ? gl.NO_ERROR : gl.INVALID_OPERATION, + "no fragment outputs"); + } + + { + const fragColor = ` + void main() { + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + }`; + wtu.setupProgram(gl, [wtu.simpleVertexShader, fragColor]); + wtu.drawUnitQuad(gl); + wtu.glErrorShouldBe(gl, (!enabled || maskedOut) ? gl.NO_ERROR : gl.INVALID_OPERATION, + "only gl_FragColor"); + } + + { + const secondaryFragColor = `#extension GL_EXT_blend_func_extended : enable + void main() { + gl_SecondaryFragColorEXT = vec4(0.0, 1.0, 0.0, 1.0); + }`; + wtu.setupProgram(gl, [wtu.simpleVertexShader, secondaryFragColor]); + wtu.drawUnitQuad(gl); + wtu.glErrorShouldBe(gl, maskedOut ? gl.NO_ERROR : gl.INVALID_OPERATION, + "only gl_SecondaryFragColorEXT"); + } + + if (contextVersion == 1) continue; + + debug(`ESSL 3.00: ${label}`); + + { + const none = `#version 300 es + void main() {}`; + wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, none]); + wtu.drawUnitQuad(gl); + wtu.glErrorShouldBe(gl, maskedOut ? gl.NO_ERROR : gl.INVALID_OPERATION, + "no fragment outputs"); + } + + { + const color0 = `#version 300 es + out mediump vec4 color0; + void main() { + color0 = vec4(1.0, 0.0, 0.0, 1.0); + }`; + wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, color0]); + wtu.drawUnitQuad(gl); + wtu.glErrorShouldBe(gl, (!enabled || maskedOut) ? gl.NO_ERROR : gl.INVALID_OPERATION, + "only index 0 output"); + } + + { + const color1 = `#version 300 es + #extension GL_EXT_blend_func_extended : enable + layout(location = 0, index = 1) out mediump vec4 color1; + void main() { + color1 = vec4(0.0, 1.0, 0.0, 1.0); + }`; + wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, color1]); + wtu.drawUnitQuad(gl); + wtu.glErrorShouldBe(gl, maskedOut ? gl.NO_ERROR : gl.INVALID_OPERATION, + "only index 1 output"); + } + } + } + gl.colorMask(true, true, true, true); +} + +function runDrawBuffersLimitTests() { + const dbi = gl.getExtension("OES_draw_buffers_indexed"); + if (!dbi) return; + + debug(""); + debug("Testing that dual-source blending limits the number of active draw buffers"); + + const rb0 = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rb0); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, 1, 1); + + const rb1 = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, rb1); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, 1, 1); + + gl.bindRenderbuffer(gl.RENDERBUFFER, null); + + const fbo = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb0); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.RENDERBUFFER, rb1); + wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE); + + const fs = `#version 300 es + #extension GL_EXT_blend_func_extended : enable + layout(location = 0, index = 0) out mediump vec4 color0; + layout(location = 0, index = 1) out mediump vec4 color1; + void main() { + color0 = vec4(1.0, 0.0, 0.0, 1.0); + color1 = vec4(0.0, 1.0, 0.0, 1.0); + }`; + wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, fs]); + + wtu.setupUnitQuad(gl); + + // Enable both draw buffers + gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1]); + + // Mask out draw buffer 1 to pass missing fragment outputs check + dbi.colorMaskiOES(1, false, false, false, false); + + const extFuncs = [ + "SRC1_COLOR_WEBGL", + "SRC1_ALPHA_WEBGL", + "ONE_MINUS_SRC1_COLOR_WEBGL", + "ONE_MINUS_SRC1_ALPHA_WEBGL" + ]; + + for (const func of extFuncs) { + for (let slot = 0; slot < 4; slot++) { + let param; + switch (slot) { + case 0: + param = "srcRGB"; + gl.blendFuncSeparate(ext[func], gl.ONE, gl.ONE, gl.ONE); + break; + case 1: + param = "dstRGB"; + gl.blendFuncSeparate(gl.ONE, ext[func], gl.ONE, gl.ONE); + break; + case 2: + param = "srcAlpha"; + gl.blendFuncSeparate(gl.ONE, gl.ONE, ext[func], gl.ONE); + break; + case 3: + param = "dstAlpha"; + gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, ext[func]); + break; + } + debug(`Testing ${func} with ${param}`); + + // Limit must be applied even with blending disabled + gl.disable(gl.BLEND); + wtu.drawUnitQuad(gl); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blending disabled"); + + gl.enable(gl.BLEND); + wtu.drawUnitQuad(gl); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "blending enabled"); + + // Limit is not applied when non-SRC1 funcs are used + gl.blendFunc(gl.ONE, gl.ONE); + wtu.drawUnitQuad(gl); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "dual-source blending disabled"); + } + } + gl.bindFramebuffer(gl.FRAMEBUFFER, null); +} + +function runBlendingTests() { + debug(""); + debug("Testing rendering with two most common dual-source blending configurations"); + + const fs = `#extension GL_EXT_blend_func_extended : enable + uniform mediump vec4 u_src0; + uniform mediump vec4 u_src1; + void main() { + gl_FragColor = u_src0; + gl_SecondaryFragColorEXT = u_src1; + }`; + const program = wtu.setupProgram(gl, [wtu.simpleVertexShader, fs]); + const uSrc0 = gl.getUniformLocation(program, "u_src0"); + const uSrc1 = gl.getUniformLocation(program, "u_src1"); + + gl.enable(gl.BLEND); + wtu.setupUnitQuad(gl); + gl.clearColor(1.0, 1.0, 1.0, 1.0); + + gl.clear(gl.COLOR_BUFFER_BIT); + gl.blendFunc(gl.ONE, ext.SRC1_COLOR_WEBGL); + gl.uniform4f(uSrc0, 0.250, 0.375, 0.500, 0.625); + gl.uniform4f(uSrc1, 0.125, 0.125, 0.125, 0.125); + wtu.drawUnitQuad(gl); + wtu.checkCanvas(gl, [96, 128, 159, 191], "Multiply destination by SRC1 and add SRC0", 2); + + gl.clear(gl.COLOR_BUFFER_BIT); + gl.blendFunc(ext.SRC1_COLOR_WEBGL, ext.ONE_MINUS_SRC1_COLOR_WEBGL); + gl.uniform4f(uSrc0, 0.125, 0.125, 0.125, 0.125); + gl.uniform4f(uSrc1, 0.500, 0.375, 0.250, 0.125); + wtu.drawUnitQuad(gl); + wtu.checkCanvas(gl, [143, 171, 199, 227], "Per-channel color interpolation using SRC1", 2); +} + +function runTest() { + if (!gl) { + testFailed("context does not exist"); + return; + } + testPassed("context exists"); + + runTestNoExtension(); + runShaderTests(false); + + ext = gl.getExtension("WEBGL_blend_func_extended"); + wtu.runExtensionSupportedTest(gl, "WEBGL_blend_func_extended", ext !== null); + + if (ext !== null) { + runEnumTests(); + runQueryTests(); + runShaderTests(true); + runMissingOutputsTests(); + runDrawBuffersLimitTests(); + runBlendingTests(); + } else { + testPassed("No WEBGL_blend_func_extended support -- this is legal"); + } +} + +runTest(); + +var successfullyParsed = true; diff --git a/dom/canvas/test/webgl-conf/checkout/js/webgl-test-harness.js b/dom/canvas/test/webgl-conf/checkout/js/webgl-test-harness.js index f48d9d2ad7..ca6cbfcd36 100644 --- a/dom/canvas/test/webgl-conf/checkout/js/webgl-test-harness.js +++ b/dom/canvas/test/webgl-conf/checkout/js/webgl-test-harness.js @@ -538,15 +538,36 @@ TestHarness.prototype.runTests = function(opt_options) { this.startNextTest(); }; -TestHarness.prototype.setTimeout = function(test) { - var that = this; - test.timeoutId = this.window.setTimeout(function() { - that.timeout(test); - }, this.timeoutDelay); +TestHarness.prototype._bumpTimeout = function(test) { + const newTimeoutAt = performance.now() + this.timeoutDelay; + if (test.timeoutAt) { + test.timeoutAt = newTimeoutAt; + return; + } + test.timeoutAt = newTimeoutAt; + + const harness = this; + + function enqueueWatchdog() { + const remaining = test.timeoutAt - performance.now(); + //console.log(`watchdog started at ${performance.now()}, ${test.timeoutAt} requested`); + this.window.setTimeout(() => { + if (!test.timeoutAt) return; // Timeout was cleared. + const remainingAtCheckTime = test.timeoutAt - performance.now(); + if (performance.now() >= test.timeoutAt) { + //console.log(`watchdog won at ${performance.now()}, ${test.timeoutAt} requested`); + harness.timeout(test); + return; + } + //console.log(`watchdog lost at ${performance.now()}, as ${test.timeoutAt} is now requested`); + enqueueWatchdog(); + }, remaining); + } + enqueueWatchdog(); }; TestHarness.prototype.clearTimeout = function(test) { - this.window.clearTimeout(test.timeoutId); + test.timeoutAt = null; }; TestHarness.prototype.startNextTest = function() { @@ -577,7 +598,7 @@ TestHarness.prototype.startTest = function(iframe, testFile, webglVersion) { "dumpShaders": this.dumpShaders, "quiet": this.quiet }); - this.setTimeout(test); + this._bumpTimeout(test); } else { this.reportResults(url, !!this.allowSkip, "skipped", true); this.notifyFinished(url); @@ -595,11 +616,15 @@ TestHarness.prototype.getTest = function(url) { TestHarness.prototype.reportResults = function(url, success, msg, skipped) { url = FilterURL(url); var test = this.getTest(url); - this.clearTimeout(test); - log((success ? "PASS" : "FAIL") + ": " + msg); + if (0) { + // This is too slow to leave on for tests like + // deqp/functional/gles3/vertexarrays/multiple_attributes.output.html + // which has 33013505 calls to reportResults. + log((success ? "PASS" : "FAIL") + ": " + msg); + } this.reportFunc(TestHarness.reportType.TEST_RESULT, url, msg, success, skipped); // For each result we get, reset the timeout - this.setTimeout(test); + this._bumpTimeout(test); }; TestHarness.prototype.dequeTest = function(test) { diff --git a/dom/canvas/test/webgl-conf/checkout/py/lint/lint.allowlist b/dom/canvas/test/webgl-conf/checkout/py/lint/lint.allowlist index eb4efce09e..b610bfa4e1 100644 --- a/dom/canvas/test/webgl-conf/checkout/py/lint/lint.allowlist +++ b/dom/canvas/test/webgl-conf/checkout/py/lint/lint.allowlist @@ -21,7 +21,7 @@ UNNECESSARY EXECUTABLE PERMISSION:specs/1.0 UNNECESSARY EXECUTABLE PERMISSION:specs/2.0 ## Ignore INDENT TABS ## - + INDENT TABS:*.frag INDENT TABS:*.vert #The original dEQP tests used tabs throughout. @@ -46,7 +46,6 @@ INVALID UNICODE:conformance/glsl/misc/non-ascii.vert.html *:*.mp3 *:*.m4a *:*.oga -*:*.ogv *:*.webm *:*.mp4 *:*.m4v diff --git a/dom/canvas/test/webgl-conf/checkout/resources/exif-orientation-originals/exif-orientation-test-8-90-cw.jpg b/dom/canvas/test/webgl-conf/checkout/resources/exif-orientation-originals/exif-orientation-test-6-90-cw.jpg Binary files differindex d4e75fac7d..d4e75fac7d 100644 --- a/dom/canvas/test/webgl-conf/checkout/resources/exif-orientation-originals/exif-orientation-test-8-90-cw.jpg +++ b/dom/canvas/test/webgl-conf/checkout/resources/exif-orientation-originals/exif-orientation-test-6-90-cw.jpg diff --git a/dom/canvas/test/webgl-conf/checkout/resources/exif-orientation-originals/exif-orientation-test-6-90-ccw.jpg b/dom/canvas/test/webgl-conf/checkout/resources/exif-orientation-originals/exif-orientation-test-8-90-ccw.jpg Binary files differindex b4679aedd9..b4679aedd9 100644 --- a/dom/canvas/test/webgl-conf/checkout/resources/exif-orientation-originals/exif-orientation-test-6-90-ccw.jpg +++ b/dom/canvas/test/webgl-conf/checkout/resources/exif-orientation-originals/exif-orientation-test-8-90-ccw.jpg diff --git a/dom/canvas/test/webgl-conf/checkout/resources/exif-orientation-test-6-90-ccw.jpg b/dom/canvas/test/webgl-conf/checkout/resources/exif-orientation-test-6-90-cw.jpg Binary files differindex f8c9a6b0cc..f8c9a6b0cc 100644 --- a/dom/canvas/test/webgl-conf/checkout/resources/exif-orientation-test-6-90-ccw.jpg +++ b/dom/canvas/test/webgl-conf/checkout/resources/exif-orientation-test-6-90-cw.jpg diff --git a/dom/canvas/test/webgl-conf/checkout/resources/exif-orientation-test-8-90-cw.jpg b/dom/canvas/test/webgl-conf/checkout/resources/exif-orientation-test-8-90-ccw.jpg Binary files differindex 594c86ff4e..594c86ff4e 100644 --- a/dom/canvas/test/webgl-conf/checkout/resources/exif-orientation-test-8-90-cw.jpg +++ b/dom/canvas/test/webgl-conf/checkout/resources/exif-orientation-test-8-90-ccw.jpg diff --git a/dom/canvas/test/webgl-conf/checkout/resources/npot-video.theora.ogv b/dom/canvas/test/webgl-conf/checkout/resources/npot-video.theora.ogv Binary files differdeleted file mode 100644 index 4458678fbf..0000000000 --- a/dom/canvas/test/webgl-conf/checkout/resources/npot-video.theora.ogv +++ /dev/null diff --git a/dom/canvas/test/webgl-conf/checkout/resources/red-gradient-8x1-10bit-untagged.png b/dom/canvas/test/webgl-conf/checkout/resources/red-gradient-8x1-10bit-untagged.png Binary files differnew file mode 100644 index 0000000000..d01209e9b5 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/resources/red-gradient-8x1-10bit-untagged.png diff --git a/dom/canvas/test/webgl-conf/checkout/resources/red-green.theora.ogv b/dom/canvas/test/webgl-conf/checkout/resources/red-green.theora.ogv Binary files differdeleted file mode 100644 index 1543915a10..0000000000 --- a/dom/canvas/test/webgl-conf/checkout/resources/red-green.theora.ogv +++ /dev/null diff --git a/dom/canvas/test/webgl-conf/checkout/test-guidelines.md b/dom/canvas/test/webgl-conf/checkout/test-guidelines.md index 679892b1f0..b02738726e 100644 --- a/dom/canvas/test/webgl-conf/checkout/test-guidelines.md +++ b/dom/canvas/test/webgl-conf/checkout/test-guidelines.md @@ -18,7 +18,7 @@ the WebGL Working Group when "official" snapshots are taken. These lines must appear in a comment at the top of every code file under sdk/tests/conformance ``` -Copyright (c) 2019 The Khronos Group Inc. +Copyright (c) 2023 The Khronos Group Inc. Use of this source code is governed by an MIT-style license that can be found in the LICENSE.txt file. ``` @@ -102,7 +102,7 @@ found in the LICENSE.txt file. * Tests that are short and run synchronously end with - <script src="../../resources/js-test-post.js"></script> + <script src="../../js/js-test-post.js"></script> * Tests that take a long time use setTimeout so as not to freeze the browser. @@ -144,7 +144,7 @@ found in the LICENSE.txt file. * Vendors may place test harness specific code in the testing infrastructure. - resources/js-test-pre.js + js/js-test-pre.js conformance/more/unit.js * Indent with spaces not tabs. (not everyone uses your tab settings). diff --git a/dom/canvas/test/webgl-conf/cherry_picks.txt b/dom/canvas/test/webgl-conf/cherry_picks.txt index cf84cd4492..f5342bb2b8 100644 --- a/dom/canvas/test/webgl-conf/cherry_picks.txt +++ b/dom/canvas/test/webgl-conf/cherry_picks.txt @@ -1,54 +1,17 @@ -commit 4f57098d0dbad68f41c87835fca5a6f0ba669350 -Author: Gregg Tavares <github@greggman.com> -Date: Thu Nov 24 10:29:32 2022 -0800 +commit cd04892d7d7ac986a83383b06bfa792c9c369f8c +Author: Kelsey Gilbert <kelsey.gilbert@mozilla.com> +Date: Tue Apr 2 14:43:02 2024 -0700 - Test calling getUniform from non-current program - - It's possible this is already tested but I didn't see anything - obvious and Firefox fails this test - -commit d308751948807f08b36d06b0e8c835a1ffe078ae -Author: Kelsey Gilbert <jdashg@gmail.com> -Date: Tue Oct 18 15:21:32 2022 -0700 - - Add conformance/textures/misc/texture-srgb-upload.html. - - Test for both webgl1+ext and webgl2. - Test uploads from ArrayBuffer and (inlined) video. - Ensure that srgb textures fetch/decode 0x7f as 0.21 not 0.5. - - Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1696693 - -commit 50024c70fc8c8f1613275cffe90dea02a20297f3 -Author: Kelsey Gilbert <jdashg@gmail.com> -Date: Wed Aug 17 15:01:24 2022 -0700 - - Add test of gl_VertexID and gl_InstanceID. - - Includes details in new test about both state-of-specification, and known errata. - - Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1779800 - -commit 92af460e46a82d60140b5a1df1379feb79730d3a -Author: Kelsey Gilbert <jdashg@gmail.com> -Date: Tue Sep 6 15:21:32 2022 -0700 - - Add test for getUniformIndices. - - Also test to ensure that it returns the correct id by checking the name from getActiveUniform. - - Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1755973 + Remove more theora/.ogv from sdk/*. -Cherries picked +Above: cherries picked ================================================================================ -Merge base from: ups/main +Below: merge base from: ups/main -commit 4996b40a69857919579a12f828188c9f428c402c -Author: Alexey Knyazev <3479527+lexaknyazev@users.noreply.github.com> -Date: Sat Aug 20 01:53:01 2022 +0400 +commit 4c5b8bfe586d983fae6a0571cc702f43e5f5b719 +Author: Ken Russell <kbrussel@alum.mit.edu> +Date: Tue Apr 2 14:17:01 2024 -0700 - Allow makeXRCompatible in OffscreenCanvas contexts (#3480) + Verify invalidated uniform locations when there is no current program. (#3633) - Fixes failures of: - conformance/offscreencanvas/methods.html - conformance/offscreencanvas/methods-worker.html + Associated with crbug.com/331119482 . diff --git a/dom/canvas/test/webgl-conf/generated-mochitest.toml b/dom/canvas/test/webgl-conf/generated-mochitest.toml index 0cee17acf4..e63ef0abfd 100644 --- a/dom/canvas/test/webgl-conf/generated-mochitest.toml +++ b/dom/canvas/test/webgl-conf/generated-mochitest.toml @@ -65,6 +65,7 @@ support-files = [ "checkout/conformance/canvas/draw-webgl-to-canvas-test.html", "checkout/conformance/canvas/drawingbuffer-hd-dpi-test.html", "checkout/conformance/canvas/drawingbuffer-static-canvas-test.html", + "checkout/conformance/canvas/drawingbuffer-storage-test.html", "checkout/conformance/canvas/drawingbuffer-test.html", "checkout/conformance/canvas/framebuffer-bindings-affected-by-to-data-url.html", "checkout/conformance/canvas/framebuffer-bindings-unaffected-on-resize.html", @@ -104,15 +105,19 @@ support-files = [ "checkout/conformance/extensions/angle-instanced-arrays-out-of-bounds.html", "checkout/conformance/extensions/angle-instanced-arrays.html", "checkout/conformance/extensions/ext-blend-minmax.html", + "checkout/conformance/extensions/ext-clip-control.html", "checkout/conformance/extensions/ext-color-buffer-half-float.html", + "checkout/conformance/extensions/ext-depth-clamp.html", "checkout/conformance/extensions/ext-disjoint-timer-query.html", "checkout/conformance/extensions/ext-float-blend.html", "checkout/conformance/extensions/ext-frag-depth.html", + "checkout/conformance/extensions/ext-polygon-offset-clamp.html", "checkout/conformance/extensions/ext-sRGB.html", "checkout/conformance/extensions/ext-shader-texture-lod.html", "checkout/conformance/extensions/ext-texture-compression-bptc.html", "checkout/conformance/extensions/ext-texture-compression-rgtc.html", "checkout/conformance/extensions/ext-texture-filter-anisotropic.html", + "checkout/conformance/extensions/ext-texture-mirror-clamp-to-edge.html", "checkout/conformance/extensions/get-extension.html", "checkout/conformance/extensions/khr-parallel-shader-compile.html", "checkout/conformance/extensions/oes-element-index-uint.html", @@ -133,6 +138,7 @@ support-files = [ "checkout/conformance/extensions/oes-vertex-array-object-bufferData.html", "checkout/conformance/extensions/oes-vertex-array-object.html", "checkout/conformance/extensions/s3tc-and-rgtc.html", + "checkout/conformance/extensions/webgl-blend-func-extended.html", "checkout/conformance/extensions/webgl-compressed-texture-astc.html", "checkout/conformance/extensions/webgl-compressed-texture-etc.html", "checkout/conformance/extensions/webgl-compressed-texture-etc1.html", @@ -147,6 +153,7 @@ support-files = [ "checkout/conformance/extensions/webgl-draw-buffers-max-draw-buffers.html", "checkout/conformance/extensions/webgl-draw-buffers.html", "checkout/conformance/extensions/webgl-multi-draw.html", + "checkout/conformance/extensions/webgl-polygon-mode.html", "checkout/conformance/extensions/webgl-webcodecs-video-frame.html", "checkout/conformance/glsl/00_test_list.txt", "checkout/conformance/glsl/bugs/00_test_list.txt", @@ -2597,6 +2604,7 @@ support-files = [ "checkout/conformance2/buffers/uniform-buffers.html", "checkout/conformance2/canvas/00_test_list.txt", "checkout/conformance2/canvas/compositing.html", + "checkout/conformance2/canvas/drawingbuffer-storage-test.html", "checkout/conformance2/canvas/to-data-url-with-pack-params.html", "checkout/conformance2/context/00_test_list.txt", "checkout/conformance2/context/constants-and-properties-2.html", @@ -2611,10 +2619,15 @@ support-files = [ "checkout/conformance2/extensions/00_test_list.txt", "checkout/conformance2/extensions/ext-color-buffer-float.html", "checkout/conformance2/extensions/ext-color-buffer-half-float.html", + "checkout/conformance2/extensions/ext-conservative-depth.html", "checkout/conformance2/extensions/ext-disjoint-timer-query-webgl2.html", + "checkout/conformance2/extensions/ext-render-snorm.html", "checkout/conformance2/extensions/ext-texture-filter-anisotropic.html", "checkout/conformance2/extensions/ext-texture-norm16.html", + "checkout/conformance2/extensions/nv-shader-noperspective-interpolation.html", "checkout/conformance2/extensions/oes-draw-buffers-indexed.html", + "checkout/conformance2/extensions/oes-sample-variables.html", + "checkout/conformance2/extensions/oes-shader-multisample-interpolation.html", "checkout/conformance2/extensions/ovr_multiview2.html", "checkout/conformance2/extensions/ovr_multiview2_depth.html", "checkout/conformance2/extensions/ovr_multiview2_draw_buffers.html", @@ -2627,7 +2640,13 @@ support-files = [ "checkout/conformance2/extensions/promoted-extensions-in-shaders.html", "checkout/conformance2/extensions/promoted-extensions.html", "checkout/conformance2/extensions/required-extensions.html", + "checkout/conformance2/extensions/webgl-blend-func-extended.html", + "checkout/conformance2/extensions/webgl-clip-cull-distance.html", "checkout/conformance2/extensions/webgl-multi-draw-instanced-base-vertex-base-instance.html", + "checkout/conformance2/extensions/webgl-provoking-vertex.html", + "checkout/conformance2/extensions/webgl-render-shared-exponent.html", + "checkout/conformance2/extensions/webgl-shader-pixel-local-storage.html", + "checkout/conformance2/extensions/webgl-stencil-texturing.html", "checkout/conformance2/glsl3/00_test_list.txt", "checkout/conformance2/glsl3/array-as-return-value.html", "checkout/conformance2/glsl3/array-assign-constructor.html", @@ -2672,6 +2691,7 @@ support-files = [ "checkout/conformance2/glsl3/shader-with-mis-matching-uniform-block.html", "checkout/conformance2/glsl3/short-circuiting-in-loop-condition.html", "checkout/conformance2/glsl3/switch-case.html", + "checkout/conformance2/glsl3/texture-bias.html", "checkout/conformance2/glsl3/texture-offset-non-constant-offset.html", "checkout/conformance2/glsl3/texture-offset-out-of-range.html", "checkout/conformance2/glsl3/texture-offset-uniform-texture-coordinate.html", @@ -2714,6 +2734,7 @@ support-files = [ "checkout/conformance2/programs/gl-get-frag-data-location.html", "checkout/conformance2/programs/sampler-uniforms.html", "checkout/conformance2/query/00_test_list.txt", + "checkout/conformance2/query/occlusion-query-scissor.html", "checkout/conformance2/query/occlusion-query.html", "checkout/conformance2/query/query.html", "checkout/conformance2/reading/00_test_list.txt", @@ -2747,7 +2768,6 @@ support-files = [ "checkout/conformance2/rendering/blitframebuffer-stencil-only.html", "checkout/conformance2/rendering/blitframebuffer-test.html", "checkout/conformance2/rendering/blitframebuffer-unaffected-by-colormask.html", - "checkout/conformance2/rendering/builtin-vert-attribs.html", "checkout/conformance2/rendering/canvas-resizing-with-pbo-bound.html", "checkout/conformance2/rendering/clear-func-buffer-type-match.html", "checkout/conformance2/rendering/clear-srgb-color-buffer.html", @@ -3511,6 +3531,7 @@ support-files = [ "checkout/conformance2/textures/misc/tex-3d-mipmap-levels-intel-bug.html", "checkout/conformance2/textures/misc/tex-3d-size-limit.html", "checkout/conformance2/textures/misc/tex-base-level-bug.html", + "checkout/conformance2/textures/misc/tex-image-10bpc.html", "checkout/conformance2/textures/misc/tex-image-and-sub-image-with-array-buffer-view-sub-source.html", "checkout/conformance2/textures/misc/tex-image-with-bad-args-from-dom-elements.html", "checkout/conformance2/textures/misc/tex-image-with-bad-args.html", @@ -3758,6 +3779,19 @@ support-files = [ "checkout/conformance2/vertex_arrays/00_test_list.txt", "checkout/conformance2/vertex_arrays/vertex-array-object-and-disabled-attributes.html", "checkout/conformance2/vertex_arrays/vertex-array-object.html", + "checkout/conformance2/wasm/00_test_list.txt", + "checkout/conformance2/wasm/bufferdata-16gb-wasm-memory.html", + "checkout/conformance2/wasm/bufferdata-4gb-wasm-memory.html", + "checkout/conformance2/wasm/buffersubdata-16gb-wasm-memory.html", + "checkout/conformance2/wasm/buffersubdata-4gb-wasm-memory.html", + "checkout/conformance2/wasm/getbuffersubdata-16gb-wasm-memory.html", + "checkout/conformance2/wasm/getbuffersubdata-4gb-wasm-memory.html", + "checkout/conformance2/wasm/readpixels-16gb-wasm-memory.html", + "checkout/conformance2/wasm/readpixels-4gb-wasm-memory.html", + "checkout/conformance2/wasm/teximage2d-16gb-wasm-memory.html", + "checkout/conformance2/wasm/teximage2d-4gb-wasm-memory.html", + "checkout/conformance2/wasm/texsubimage2d-16gb-wasm-memory.html", + "checkout/conformance2/wasm/texsubimage2d-4gb-wasm-memory.html", "checkout/deqp/00_test_list.txt", "checkout/deqp/LICENSE", "checkout/deqp/README.md", @@ -5018,6 +5052,7 @@ support-files = [ "checkout/js/tests/compressed-tex-image.js", "checkout/js/tests/compressed-texture-utils.js", "checkout/js/tests/context-methods.js", + "checkout/js/tests/drawingbuffer-storage-test.js", "checkout/js/tests/ext-color-buffer-half-float.js", "checkout/js/tests/ext-float-blend.js", "checkout/js/tests/ext-texture-filter-anisotropic.js", @@ -5068,6 +5103,7 @@ support-files = [ "checkout/js/tests/texture-corner-case-videos.js", "checkout/js/tests/typed-array-test-cases.js", "checkout/js/tests/typed-array-worker.js", + "checkout/js/tests/webgl-blend-func-extended.js", "checkout/js/tests/webgl-compressed-texture-size-limit.js", "checkout/js/tests/webgl-draw-buffers-utils.js", "checkout/js/webgl-test-harness.js", @@ -5090,18 +5126,18 @@ support-files = [ "checkout/resources/exif-orientation-originals/exif-orientation-test-3-rotate-180.jpg", "checkout/resources/exif-orientation-originals/exif-orientation-test-4-mirror-vertical.jpg", "checkout/resources/exif-orientation-originals/exif-orientation-test-5-mirror-horizontal-90-ccw.jpg", - "checkout/resources/exif-orientation-originals/exif-orientation-test-6-90-ccw.jpg", + "checkout/resources/exif-orientation-originals/exif-orientation-test-6-90-cw.jpg", "checkout/resources/exif-orientation-originals/exif-orientation-test-7-mirror-horizontal-90-cw.jpg", - "checkout/resources/exif-orientation-originals/exif-orientation-test-8-90-cw.jpg", + "checkout/resources/exif-orientation-originals/exif-orientation-test-8-90-ccw.jpg", "checkout/resources/exif-orientation-originals/exif-orientation-test.psd", "checkout/resources/exif-orientation-test-1-normal.jpg", "checkout/resources/exif-orientation-test-2-mirror-horizontal.jpg", "checkout/resources/exif-orientation-test-3-rotate-180.jpg", "checkout/resources/exif-orientation-test-4-mirror-vertical.jpg", "checkout/resources/exif-orientation-test-5-mirror-horizontal-90-ccw.jpg", - "checkout/resources/exif-orientation-test-6-90-ccw.jpg", + "checkout/resources/exif-orientation-test-6-90-cw.jpg", "checkout/resources/exif-orientation-test-7-mirror-horizontal-90-cw.jpg", - "checkout/resources/exif-orientation-test-8-90-cw.jpg", + "checkout/resources/exif-orientation-test-8-90-ccw.jpg", "checkout/resources/floatUniformShader.vert", "checkout/resources/fragmentShader.frag", "checkout/resources/glsl-feature-tests.css", @@ -5128,10 +5164,10 @@ support-files = [ "checkout/resources/noopUniformShaderES3.vert", "checkout/resources/npot-video-1920x1080.mp4", "checkout/resources/npot-video.mp4", - "checkout/resources/npot-video.theora.ogv", "checkout/resources/npot-video.webmvp8.webm", "checkout/resources/ogles-tests.css", "checkout/resources/opengl_logo.jpg", + "checkout/resources/red-gradient-8x1-10bit-untagged.png", "checkout/resources/red-green-128x128-linear-profile.jpg", "checkout/resources/red-green-128x128-linear-profile.psd", "checkout/resources/red-green-480x272-sar-136x135-dar-16x9.mp4", @@ -5145,7 +5181,6 @@ support-files = [ "checkout/resources/red-green.mp4", "checkout/resources/red-green.png", "checkout/resources/red-green.svg", - "checkout/resources/red-green.theora.ogv", "checkout/resources/red-green.webmvp8.webm", "checkout/resources/red-indexed.png", "checkout/resources/samplerForWebGL2UniformShader.frag", @@ -5254,6 +5289,9 @@ subsuite = "webgl2-core" ["generated/test_2_conformance2__buffers__uniform-buffers.html"] subsuite = "webgl2-core" +["generated/test_2_conformance2__canvas__drawingbuffer-storage-test.html"] +subsuite = "webgl2-core" + ["generated/test_2_conformance2__canvas__to-data-url-with-pack-params.html"] subsuite = "webgl2-core" @@ -5295,9 +5333,15 @@ skip-if = ["os == 'mac' && debug"] ["generated/test_2_conformance2__extensions__ext-color-buffer-half-float.html"] subsuite = "webgl2-core" +["generated/test_2_conformance2__extensions__ext-conservative-depth.html"] +subsuite = "webgl2-core" + ["generated/test_2_conformance2__extensions__ext-disjoint-timer-query-webgl2.html"] subsuite = "webgl2-core" +["generated/test_2_conformance2__extensions__ext-render-snorm.html"] +subsuite = "webgl2-core" + ["generated/test_2_conformance2__extensions__ext-texture-filter-anisotropic.html"] subsuite = "webgl2-core" @@ -5309,9 +5353,18 @@ fail-if = [ "os == 'linux'", ] +["generated/test_2_conformance2__extensions__nv-shader-noperspective-interpolation.html"] +subsuite = "webgl2-core" + ["generated/test_2_conformance2__extensions__oes-draw-buffers-indexed.html"] subsuite = "webgl2-core" +["generated/test_2_conformance2__extensions__oes-sample-variables.html"] +subsuite = "webgl2-core" + +["generated/test_2_conformance2__extensions__oes-shader-multisample-interpolation.html"] +subsuite = "webgl2-core" + ["generated/test_2_conformance2__extensions__ovr_multiview2.html"] subsuite = "webgl2-core" fail-if = ["os == 'win'"] @@ -5357,10 +5410,28 @@ subsuite = "webgl2-core" subsuite = "webgl2-core" fail-if = ["os == 'linux'"] +["generated/test_2_conformance2__extensions__webgl-blend-func-extended.html"] +subsuite = "webgl2-core" + +["generated/test_2_conformance2__extensions__webgl-clip-cull-distance.html"] +subsuite = "webgl2-core" + ["generated/test_2_conformance2__extensions__webgl-multi-draw-instanced-base-vertex-base-instance.html"] subsuite = "webgl2-core" fail-if = ["os == 'mac' && !apple_silicon"] +["generated/test_2_conformance2__extensions__webgl-provoking-vertex.html"] +subsuite = "webgl2-core" + +["generated/test_2_conformance2__extensions__webgl-render-shared-exponent.html"] +subsuite = "webgl2-core" + +["generated/test_2_conformance2__extensions__webgl-shader-pixel-local-storage.html"] +subsuite = "webgl2-core" + +["generated/test_2_conformance2__extensions__webgl-stencil-texturing.html"] +subsuite = "webgl2-core" + ["generated/test_2_conformance2__glsl3__array-as-return-value.html"] subsuite = "webgl2-ext" @@ -5493,6 +5564,10 @@ subsuite = "webgl2-ext" subsuite = "webgl2-ext" fail-if = ["os == 'win'"] +["generated/test_2_conformance2__glsl3__texture-bias.html"] +subsuite = "webgl2-ext" +fail-if = ["os == 'win'"] + ["generated/test_2_conformance2__glsl3__texture-offset-non-constant-offset.html"] subsuite = "webgl2-ext" @@ -5620,6 +5695,9 @@ fail-if = ["os == 'android'"] ["generated/test_2_conformance2__programs__sampler-uniforms.html"] subsuite = "webgl2-core" +["generated/test_2_conformance2__query__occlusion-query-scissor.html"] +subsuite = "webgl2-core" + ["generated/test_2_conformance2__query__occlusion-query.html"] subsuite = "webgl2-core" skip-if = ["true"] @@ -5721,9 +5799,6 @@ subsuite = "webgl2-core" ["generated/test_2_conformance2__rendering__blitframebuffer-unaffected-by-colormask.html"] subsuite = "webgl2-core" -["generated/test_2_conformance2__rendering__builtin-vert-attribs.html"] -subsuite = "webgl2-core" - ["generated/test_2_conformance2__rendering__canvas-resizing-with-pbo-bound.html"] subsuite = "webgl2-core" @@ -8083,6 +8158,10 @@ subsuite = "webgl2-core" subsuite = "webgl2-core" fail-if = ["os == 'mac'"] # macosx1014 due to 1563418 +["generated/test_2_conformance2__textures__misc__tex-image-10bpc.html"] +subsuite = "webgl2-core" +fail-if = ["true"] + ["generated/test_2_conformance2__textures__misc__tex-image-and-sub-image-with-array-buffer-view-sub-source.html"] subsuite = "webgl2-core" @@ -8875,6 +8954,54 @@ subsuite = "webgl2-core" ["generated/test_2_conformance2__vertex_arrays__vertex-array-object.html"] subsuite = "webgl2-core" +["generated/test_2_conformance2__wasm__bufferdata-16gb-wasm-memory.html"] +subsuite = "webgl2-core" +fail-if = ["true"] + +["generated/test_2_conformance2__wasm__bufferdata-4gb-wasm-memory.html"] +subsuite = "webgl2-core" +fail-if = ["true"] + +["generated/test_2_conformance2__wasm__buffersubdata-16gb-wasm-memory.html"] +subsuite = "webgl2-core" +fail-if = ["true"] + +["generated/test_2_conformance2__wasm__buffersubdata-4gb-wasm-memory.html"] +subsuite = "webgl2-core" +fail-if = ["true"] + +["generated/test_2_conformance2__wasm__getbuffersubdata-16gb-wasm-memory.html"] +subsuite = "webgl2-core" +fail-if = ["true"] + +["generated/test_2_conformance2__wasm__getbuffersubdata-4gb-wasm-memory.html"] +subsuite = "webgl2-core" +fail-if = ["true"] + +["generated/test_2_conformance2__wasm__readpixels-16gb-wasm-memory.html"] +subsuite = "webgl2-core" +fail-if = ["true"] + +["generated/test_2_conformance2__wasm__readpixels-4gb-wasm-memory.html"] +subsuite = "webgl2-core" +fail-if = ["true"] + +["generated/test_2_conformance2__wasm__teximage2d-16gb-wasm-memory.html"] +subsuite = "webgl2-core" +fail-if = ["true"] + +["generated/test_2_conformance2__wasm__teximage2d-4gb-wasm-memory.html"] +subsuite = "webgl2-core" +fail-if = ["true"] + +["generated/test_2_conformance2__wasm__texsubimage2d-16gb-wasm-memory.html"] +subsuite = "webgl2-core" +fail-if = ["true"] + +["generated/test_2_conformance2__wasm__texsubimage2d-4gb-wasm-memory.html"] +subsuite = "webgl2-core" +fail-if = ["true"] + ["generated/test_2_conformance__attribs__gl-bindAttribLocation-aliasing.html"] subsuite = "webgl2-core" @@ -9067,15 +9194,24 @@ subsuite = "webgl2-core" ["generated/test_2_conformance__context__zero-sized-canvas.html"] subsuite = "webgl2-core" +["generated/test_2_conformance__extensions__ext-clip-control.html"] +subsuite = "webgl2-core" + ["generated/test_2_conformance__extensions__ext-color-buffer-half-float.html"] subsuite = "webgl2-core" +["generated/test_2_conformance__extensions__ext-depth-clamp.html"] +subsuite = "webgl2-core" + ["generated/test_2_conformance__extensions__ext-disjoint-timer-query.html"] subsuite = "webgl2-core" ["generated/test_2_conformance__extensions__ext-float-blend.html"] subsuite = "webgl2-core" +["generated/test_2_conformance__extensions__ext-polygon-offset-clamp.html"] +subsuite = "webgl2-core" + ["generated/test_2_conformance__extensions__ext-texture-compression-bptc.html"] subsuite = "webgl2-core" @@ -9085,6 +9221,9 @@ subsuite = "webgl2-core" ["generated/test_2_conformance__extensions__ext-texture-filter-anisotropic.html"] subsuite = "webgl2-core" +["generated/test_2_conformance__extensions__ext-texture-mirror-clamp-to-edge.html"] +subsuite = "webgl2-core" + ["generated/test_2_conformance__extensions__get-extension.html"] subsuite = "webgl2-core" @@ -9125,6 +9264,9 @@ subsuite = "webgl2-core" ["generated/test_2_conformance__extensions__webgl-multi-draw.html"] subsuite = "webgl2-core" +["generated/test_2_conformance__extensions__webgl-polygon-mode.html"] +subsuite = "webgl2-core" + ["generated/test_2_conformance__glsl__bugs__angle-ambiguous-function-call.html"] subsuite = "webgl2-ext" @@ -14187,9 +14329,15 @@ skip-if = ["os == 'mac' && os_version == '10.15'"] ["generated/test_conformance__extensions__ext-blend-minmax.html"] subsuite = "webgl1-core" +["generated/test_conformance__extensions__ext-clip-control.html"] +subsuite = "webgl1-core" + ["generated/test_conformance__extensions__ext-color-buffer-half-float.html"] subsuite = "webgl1-core" +["generated/test_conformance__extensions__ext-depth-clamp.html"] +subsuite = "webgl1-core" + ["generated/test_conformance__extensions__ext-disjoint-timer-query.html"] subsuite = "webgl1-core" @@ -14199,6 +14347,9 @@ subsuite = "webgl1-core" ["generated/test_conformance__extensions__ext-frag-depth.html"] subsuite = "webgl1-core" +["generated/test_conformance__extensions__ext-polygon-offset-clamp.html"] +subsuite = "webgl1-core" + ["generated/test_conformance__extensions__ext-sRGB.html"] subsuite = "webgl1-core" fail-if = ["os == 'android'"] @@ -14215,6 +14366,9 @@ subsuite = "webgl1-core" ["generated/test_conformance__extensions__ext-texture-filter-anisotropic.html"] subsuite = "webgl1-core" +["generated/test_conformance__extensions__ext-texture-mirror-clamp-to-edge.html"] +subsuite = "webgl1-core" + ["generated/test_conformance__extensions__get-extension.html"] subsuite = "webgl1-core" @@ -14278,6 +14432,9 @@ subsuite = "webgl1-core" ["generated/test_conformance__extensions__s3tc-and-rgtc.html"] subsuite = "webgl1-core" +["generated/test_conformance__extensions__webgl-blend-func-extended.html"] +subsuite = "webgl1-core" + ["generated/test_conformance__extensions__webgl-compressed-texture-astc.html"] subsuite = "webgl1-core" @@ -14320,6 +14477,9 @@ subsuite = "webgl1-core" ["generated/test_conformance__extensions__webgl-multi-draw.html"] subsuite = "webgl1-core" +["generated/test_conformance__extensions__webgl-polygon-mode.html"] +subsuite = "webgl1-core" + ["generated/test_conformance__glsl__bugs__angle-ambiguous-function-call.html"] subsuite = "webgl1-ext" @@ -16705,7 +16865,7 @@ subsuite = "webgl1-core" skip-if = [ "win11_2009", # win11 - 50/50 intermittent "os == 'android' && android_version == '33'", #Bug 1873144 - ] + ] ["generated/test_conformance__textures__misc__texture-npot.html"] subsuite = "webgl1-core" diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__canvas__drawingbuffer-storage-test.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__canvas__drawingbuffer-storage-test.html new file mode 100644 index 0000000000..00fba64f26 --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__canvas__drawingbuffer-storage-test.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance2/canvas/drawingbuffer-storage-test.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__ext-conservative-depth.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__ext-conservative-depth.html new file mode 100644 index 0000000000..2ae10d93fe --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__ext-conservative-depth.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance2/extensions/ext-conservative-depth.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__rendering__builtin-vert-attribs.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__ext-render-snorm.html index 0c6200a9a9..aa47f840a0 100644 --- a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__rendering__builtin-vert-attribs.html +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__ext-render-snorm.html @@ -12,6 +12,6 @@ <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> </head> <body> - <iframe src='../mochi-single.html?checkout/conformance2/rendering/builtin-vert-attribs.html?webglVersion=2'></iframe> + <iframe src='../mochi-single.html?checkout/conformance2/extensions/ext-render-snorm.html?webglVersion=2'></iframe> </body> </html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__nv-shader-noperspective-interpolation.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__nv-shader-noperspective-interpolation.html new file mode 100644 index 0000000000..c4e820eaae --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__nv-shader-noperspective-interpolation.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance2/extensions/nv-shader-noperspective-interpolation.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__oes-sample-variables.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__oes-sample-variables.html new file mode 100644 index 0000000000..a7582e4fa4 --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__oes-sample-variables.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance2/extensions/oes-sample-variables.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__oes-shader-multisample-interpolation.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__oes-shader-multisample-interpolation.html new file mode 100644 index 0000000000..f7fae5d1c5 --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__oes-shader-multisample-interpolation.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance2/extensions/oes-shader-multisample-interpolation.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__webgl-blend-func-extended.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__webgl-blend-func-extended.html new file mode 100644 index 0000000000..d0ad1a13bf --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__webgl-blend-func-extended.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance2/extensions/webgl-blend-func-extended.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__webgl-clip-cull-distance.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__webgl-clip-cull-distance.html new file mode 100644 index 0000000000..f2b113ac78 --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__webgl-clip-cull-distance.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance2/extensions/webgl-clip-cull-distance.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__webgl-provoking-vertex.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__webgl-provoking-vertex.html new file mode 100644 index 0000000000..132519dff3 --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__webgl-provoking-vertex.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance2/extensions/webgl-provoking-vertex.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__webgl-render-shared-exponent.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__webgl-render-shared-exponent.html new file mode 100644 index 0000000000..7d4a15493b --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__webgl-render-shared-exponent.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance2/extensions/webgl-render-shared-exponent.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__webgl-shader-pixel-local-storage.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__webgl-shader-pixel-local-storage.html new file mode 100644 index 0000000000..4b30aadc2b --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__webgl-shader-pixel-local-storage.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance2/extensions/webgl-shader-pixel-local-storage.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__webgl-stencil-texturing.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__webgl-stencil-texturing.html new file mode 100644 index 0000000000..f867f36977 --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__extensions__webgl-stencil-texturing.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance2/extensions/webgl-stencil-texturing.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__glsl3__texture-bias.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__glsl3__texture-bias.html new file mode 100644 index 0000000000..6ec1ed29d4 --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__glsl3__texture-bias.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance2/glsl3/texture-bias.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__query__occlusion-query-scissor.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__query__occlusion-query-scissor.html new file mode 100644 index 0000000000..9337ee8fd4 --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__query__occlusion-query-scissor.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance2/query/occlusion-query-scissor.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__textures__misc__tex-image-10bpc.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__textures__misc__tex-image-10bpc.html new file mode 100644 index 0000000000..c6f5f90019 --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__textures__misc__tex-image-10bpc.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance2/textures/misc/tex-image-10bpc.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__bufferdata-16gb-wasm-memory.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__bufferdata-16gb-wasm-memory.html new file mode 100644 index 0000000000..d005e42f84 --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__bufferdata-16gb-wasm-memory.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance2/wasm/bufferdata-16gb-wasm-memory.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__bufferdata-4gb-wasm-memory.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__bufferdata-4gb-wasm-memory.html new file mode 100644 index 0000000000..81d331a5be --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__bufferdata-4gb-wasm-memory.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance2/wasm/bufferdata-4gb-wasm-memory.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__buffersubdata-16gb-wasm-memory.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__buffersubdata-16gb-wasm-memory.html new file mode 100644 index 0000000000..09b63204a7 --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__buffersubdata-16gb-wasm-memory.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance2/wasm/buffersubdata-16gb-wasm-memory.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__buffersubdata-4gb-wasm-memory.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__buffersubdata-4gb-wasm-memory.html new file mode 100644 index 0000000000..6d0240794b --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__buffersubdata-4gb-wasm-memory.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance2/wasm/buffersubdata-4gb-wasm-memory.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__getbuffersubdata-16gb-wasm-memory.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__getbuffersubdata-16gb-wasm-memory.html new file mode 100644 index 0000000000..3bbe93a68a --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__getbuffersubdata-16gb-wasm-memory.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance2/wasm/getbuffersubdata-16gb-wasm-memory.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__getbuffersubdata-4gb-wasm-memory.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__getbuffersubdata-4gb-wasm-memory.html new file mode 100644 index 0000000000..d310a733f6 --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__getbuffersubdata-4gb-wasm-memory.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance2/wasm/getbuffersubdata-4gb-wasm-memory.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__readpixels-16gb-wasm-memory.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__readpixels-16gb-wasm-memory.html new file mode 100644 index 0000000000..342b9e7015 --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__readpixels-16gb-wasm-memory.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance2/wasm/readpixels-16gb-wasm-memory.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__readpixels-4gb-wasm-memory.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__readpixels-4gb-wasm-memory.html new file mode 100644 index 0000000000..d772a2824a --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__readpixels-4gb-wasm-memory.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance2/wasm/readpixels-4gb-wasm-memory.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__teximage2d-16gb-wasm-memory.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__teximage2d-16gb-wasm-memory.html new file mode 100644 index 0000000000..5ce7bdb9bd --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__teximage2d-16gb-wasm-memory.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance2/wasm/teximage2d-16gb-wasm-memory.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__teximage2d-4gb-wasm-memory.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__teximage2d-4gb-wasm-memory.html new file mode 100644 index 0000000000..135f5b4a32 --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__teximage2d-4gb-wasm-memory.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance2/wasm/teximage2d-4gb-wasm-memory.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__texsubimage2d-16gb-wasm-memory.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__texsubimage2d-16gb-wasm-memory.html new file mode 100644 index 0000000000..eca227b3a5 --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__texsubimage2d-16gb-wasm-memory.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance2/wasm/texsubimage2d-16gb-wasm-memory.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__texsubimage2d-4gb-wasm-memory.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__texsubimage2d-4gb-wasm-memory.html new file mode 100644 index 0000000000..b5b2d1cc6f --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance2__wasm__texsubimage2d-4gb-wasm-memory.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance2/wasm/texsubimage2d-4gb-wasm-memory.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance__extensions__ext-clip-control.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance__extensions__ext-clip-control.html new file mode 100644 index 0000000000..0cdc6e1101 --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance__extensions__ext-clip-control.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance/extensions/ext-clip-control.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance__extensions__ext-depth-clamp.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance__extensions__ext-depth-clamp.html new file mode 100644 index 0000000000..9cb87c0570 --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance__extensions__ext-depth-clamp.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance/extensions/ext-depth-clamp.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance__extensions__ext-polygon-offset-clamp.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance__extensions__ext-polygon-offset-clamp.html new file mode 100644 index 0000000000..b0df2ff3bc --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance__extensions__ext-polygon-offset-clamp.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance/extensions/ext-polygon-offset-clamp.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance__extensions__ext-texture-mirror-clamp-to-edge.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance__extensions__ext-texture-mirror-clamp-to-edge.html new file mode 100644 index 0000000000..470477e4de --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance__extensions__ext-texture-mirror-clamp-to-edge.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance/extensions/ext-texture-mirror-clamp-to-edge.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_2_conformance__extensions__webgl-polygon-mode.html b/dom/canvas/test/webgl-conf/generated/test_2_conformance__extensions__webgl-polygon-mode.html new file mode 100644 index 0000000000..642d0dc652 --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_2_conformance__extensions__webgl-polygon-mode.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance/extensions/webgl-polygon-mode.html?webglVersion=2'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_conformance__extensions__ext-clip-control.html b/dom/canvas/test/webgl-conf/generated/test_conformance__extensions__ext-clip-control.html new file mode 100644 index 0000000000..7fb1b875ce --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_conformance__extensions__ext-clip-control.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance/extensions/ext-clip-control.html'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_conformance__extensions__ext-depth-clamp.html b/dom/canvas/test/webgl-conf/generated/test_conformance__extensions__ext-depth-clamp.html new file mode 100644 index 0000000000..f6162ae15f --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_conformance__extensions__ext-depth-clamp.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance/extensions/ext-depth-clamp.html'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_conformance__extensions__ext-polygon-offset-clamp.html b/dom/canvas/test/webgl-conf/generated/test_conformance__extensions__ext-polygon-offset-clamp.html new file mode 100644 index 0000000000..b1a736ebb3 --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_conformance__extensions__ext-polygon-offset-clamp.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance/extensions/ext-polygon-offset-clamp.html'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_conformance__extensions__ext-texture-mirror-clamp-to-edge.html b/dom/canvas/test/webgl-conf/generated/test_conformance__extensions__ext-texture-mirror-clamp-to-edge.html new file mode 100644 index 0000000000..d13072949f --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_conformance__extensions__ext-texture-mirror-clamp-to-edge.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance/extensions/ext-texture-mirror-clamp-to-edge.html'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_conformance__extensions__webgl-blend-func-extended.html b/dom/canvas/test/webgl-conf/generated/test_conformance__extensions__webgl-blend-func-extended.html new file mode 100644 index 0000000000..66d1fcefda --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_conformance__extensions__webgl-blend-func-extended.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance/extensions/webgl-blend-func-extended.html'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/generated/test_conformance__extensions__webgl-polygon-mode.html b/dom/canvas/test/webgl-conf/generated/test_conformance__extensions__webgl-polygon-mode.html new file mode 100644 index 0000000000..c7783dc938 --- /dev/null +++ b/dom/canvas/test/webgl-conf/generated/test_conformance__extensions__webgl-polygon-mode.html @@ -0,0 +1,17 @@ +<!-- GENERATED FILE, DO NOT EDIT --> +<!DOCTYPE HTML> +<html> + <head> + <meta charset='utf-8'/> + <title> + Mochitest wrapper for WebGL Conformance Test Suite tests + </title> + <link rel='stylesheet' type='text/css' href='../iframe-passthrough.css'/> + + <script src='/tests/SimpleTest/SimpleTest.js'></script> + <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/> + </head> + <body> + <iframe src='../mochi-single.html?checkout/conformance/extensions/webgl-polygon-mode.html'></iframe> + </body> +</html> diff --git a/dom/canvas/test/webgl-conf/mochitest-errata.toml b/dom/canvas/test/webgl-conf/mochitest-errata.toml index 5bf2b3f89b..e036a20ba1 100644 --- a/dom/canvas/test/webgl-conf/mochitest-errata.toml +++ b/dom/canvas/test/webgl-conf/mochitest-errata.toml @@ -30,6 +30,68 @@ prefs = "media.seamless-looping-video=false" fail-if = ["true"] #################### +# Failures from 2024-04 CTS update + +["generated/test_2_conformance2__textures__misc__tex-image-10bpc.html"] +# gl.checkFramebufferStatus(gl.FRAMEBUFFER) should be 36053. Was 36054. +# uniquePixels.size should be >= 7. Was 1 (of type number). +fail-if = ["true"] + + +["generated/test_2_conformance2__wasm__bufferdata-16gb-wasm-memory.html"] +# successfullyParsed should be true (of type boolean). Was undefined (of type undefined). +fail-if = ["true"] + +["generated/test_2_conformance2__wasm__bufferdata-4gb-wasm-memory.html"] +# successfullyParsed should be true (of type boolean). Was undefined (of type undefined). +fail-if = ["true"] + +["generated/test_2_conformance2__wasm__buffersubdata-16gb-wasm-memory.html"] +# successfullyParsed should be true (of type boolean). Was undefined (of type undefined). +fail-if = ["true"] + +["generated/test_2_conformance2__wasm__buffersubdata-4gb-wasm-memory.html"] +# successfullyParsed should be true (of type boolean). Was undefined (of type undefined). +fail-if = ["true"] + +["generated/test_2_conformance2__wasm__getbuffersubdata-16gb-wasm-memory.html"] +# successfullyParsed should be true (of type boolean). Was undefined (of type undefined). +fail-if = ["true"] + +["generated/test_2_conformance2__wasm__getbuffersubdata-4gb-wasm-memory.html"] +# successfullyParsed should be true (of type boolean). Was undefined (of type undefined). +fail-if = ["true"] + +["generated/test_2_conformance2__wasm__readpixels-16gb-wasm-memory.html"] +# successfullyParsed should be true (of type boolean). Was undefined (of type undefined). +fail-if = ["true"] + +["generated/test_2_conformance2__wasm__readpixels-4gb-wasm-memory.html"] +# successfullyParsed should be true (of type boolean). Was undefined (of type undefined). +fail-if = ["true"] + +["generated/test_2_conformance2__wasm__teximage2d-16gb-wasm-memory.html"] +# successfullyParsed should be true (of type boolean). Was undefined (of type undefined). +fail-if = ["true"] + +["generated/test_2_conformance2__wasm__teximage2d-4gb-wasm-memory.html"] +# successfullyParsed should be true (of type boolean). Was undefined (of type undefined). +fail-if = ["true"] + +["generated/test_2_conformance2__wasm__texsubimage2d-16gb-wasm-memory.html"] +# successfullyParsed should be true (of type boolean). Was undefined (of type undefined). +fail-if = ["true"] + +["generated/test_2_conformance2__wasm__texsubimage2d-4gb-wasm-memory.html"] +# successfullyParsed should be true (of type boolean). Was undefined (of type undefined). +fail-if = ["true"] + +["generated/test_2_conformance2__glsl3__texture-bias.html"] +# should be: 3,3,3,3 +# should be: 13,13,13,13 +fail-if = ["os == 'win'"] + +#################### # Bugs surfaced during fx106 CTS update ["generated/test_conformance__programs__program-handling.html"] diff --git a/dom/canvas/test/webgl-conf/moz.yaml b/dom/canvas/test/webgl-conf/moz.yaml index 7ebde7dcb2..fc40ba1b4d 100644 --- a/dom/canvas/test/webgl-conf/moz.yaml +++ b/dom/canvas/test/webgl-conf/moz.yaml @@ -13,8 +13,8 @@ origin: license: MIT - release: commit 4996b40a69857919579a12f828188c9f428c402c Fri Aug 19 14:53:01 2022 -0700 - revision: 4996b40a69857919579a12f828188c9f428c402c + release: commit 4c5b8bfe586d983fae6a0571cc702f43e5f5b719 Tue Apr 2 14:17:01 2024 -0700 + revision: 4c5b8bfe586d983fae6a0571cc702f43e5f5b719 updatebot: diff --git a/dom/canvas/test/webgl-mochitest/mochitest.toml b/dom/canvas/test/webgl-mochitest/mochitest.toml index 88e2fab88b..88b9b8ae91 100644 --- a/dom/canvas/test/webgl-mochitest/mochitest.toml +++ b/dom/canvas/test/webgl-mochitest/mochitest.toml @@ -8,7 +8,6 @@ support-files = [ "webgl-util.js", "test_video_fastpath.js", "red-green.mp4", - "red-green.theora.ogv", "red-green.webmvp8.webm", "red-green.webmvp9.webm", ] @@ -199,20 +198,12 @@ support-files = ["blank_15000x10000.png"] ["test_video_fastpath_mp4.html"] skip-if = ["win11_2009 && bits == 32"] # No fast video path for h264 decoder (done in RDD, can't be read in content) -["test_video_fastpath_theora.html"] -skip-if = [ - "os == 'linux' && os_version == '18.04'", - "apple_catalina", - "apple_silicon", - "win11_2009 && bits == 32", # No fast video path for theora decoder (done in RDD, can't be read in content) -] - ["test_video_fastpath_vp8.html"] skip-if = [ "os == 'linux' && os_version == '18.04'", "apple_catalina", "apple_silicon", - "win11_2009 && bits == 32", # No fast video path for theora decoder (done in RDD, can't be read in content) + "win11_2009 && bits == 32", # No fast video path for vp8 decoder (done in RDD, can't be read in content) ] ["test_video_fastpath_vp9.html"] @@ -220,7 +211,7 @@ skip-if = [ "os == 'linux' && os_version == '18.04'", "apple_catalina", "apple_silicon", - "win11_2009 && bits == 32", # No fast video path for theora decoder (done in RDD, can't be read in content) + "win11_2009 && bits == 32", # No fast video path for vp9 decoder (done in RDD, can't be read in content) ] ["test_webgl2_alpha_luminance.html"] diff --git a/dom/canvas/test/webgl-mochitest/red-green.theora.ogv b/dom/canvas/test/webgl-mochitest/red-green.theora.ogv Binary files differdeleted file mode 100644 index 1543915a10..0000000000 --- a/dom/canvas/test/webgl-mochitest/red-green.theora.ogv +++ /dev/null diff --git a/dom/canvas/test/webgl-mochitest/test_video_fastpath_theora.html b/dom/canvas/test/webgl-mochitest/test_video_fastpath_theora.html deleted file mode 100644 index 4f4fbab88b..0000000000 --- a/dom/canvas/test/webgl-mochitest/test_video_fastpath_theora.html +++ /dev/null @@ -1,21 +0,0 @@ -<html> - <head> - <meta name="timeout" content="long"/> - <meta http-equiv="Content-type" content="text/html;charset=UTF-8"/> - <title>Video Fastpath upload test</title> - <script src="/tests/SimpleTest/SimpleTest.js"></script> - <script src="test_video_fastpath.js"></script> - <link rel="stylesheet" href="/tests/SimpleTest/test.css"> - </head> - <body> - <script> - - function runTest() { - startTest("red-green.theora.ogv"); - } - - SimpleTest.waitForExplicitFinish(); - SpecialPowers.pushPrefEnv({"set" : [["webgl.enable-privileged-extensions", true]]}, runTest); - </script> - </body> -</html> |