WebGLRenderingContextBase.h [plain text]
#pragma once
#if ENABLE(WEBGL)
#include "ActivityStateChangeObserver.h"
#include "ExceptionOr.h"
#include "GPUBasedCanvasRenderingContext.h"
#include "GraphicsContextGL.h"
#include "ImageBuffer.h"
#include "SuspendableTimer.h"
#include "Timer.h"
#include "WebGLAny.h"
#include "WebGLBuffer.h"
#include "WebGLContextAttributes.h"
#include "WebGLFramebuffer.h"
#include "WebGLProgram.h"
#include "WebGLRenderbuffer.h"
#include "WebGLStateTracker.h"
#include "WebGLTexture.h"
#include "WebGLVertexArrayObjectOES.h"
#include <JavaScriptCore/ConsoleTypes.h>
#include <limits>
#include <memory>
#include <wtf/CheckedArithmetic.h>
#include <wtf/Lock.h>
#if ENABLE(WEBGL2)
#include "WebGLVertexArrayObject.h"
#endif
#if ENABLE(WEBXR)
#include "JSDOMPromiseDeferred.h"
#endif
namespace JSC {
class SlotVisitor;
}
namespace WTF {
class AbstractLocker;
}
namespace WebCore {
class ANGLEInstancedArrays;
class EXTBlendMinMax;
class EXTColorBufferFloat;
class EXTColorBufferHalfFloat;
class EXTFloatBlend;
class EXTTextureCompressionRGTC;
class EXTTextureFilterAnisotropic;
class EXTShaderTextureLOD;
class EXTsRGB;
class EXTFragDepth;
class HTMLImageElement;
class ImageData;
class IntSize;
class KHRParallelShaderCompile;
class OESStandardDerivatives;
class OESTextureFloat;
class OESTextureFloatLinear;
class OESTextureHalfFloat;
class OESTextureHalfFloatLinear;
class OESVertexArrayObject;
class OESElementIndexUint;
class OESFBORenderMipmap;
#if ENABLE(OFFSCREEN_CANVAS)
class OffscreenCanvas;
#endif
class WebGLActiveInfo;
class WebGLColorBufferFloat;
class WebGLCompressedTextureASTC;
class WebGLCompressedTextureATC;
class WebGLCompressedTextureETC;
class WebGLCompressedTextureETC1;
class WebGLCompressedTexturePVRTC;
class WebGLCompressedTextureS3TC;
class WebGLCompressedTextureS3TCsRGB;
class WebGLContextGroup;
class WebGLContextObject;
class WebGLDebugRendererInfo;
class WebGLDebugShaders;
class WebGLDepthTexture;
class WebGLDrawBuffers;
class WebGLExtension;
class WebGLLoseContext;
class WebGLObject;
class WebGLShader;
class WebGLSharedObject;
class WebGLShaderPrecisionFormat;
class WebGLUniformLocation;
#if ENABLE(VIDEO)
class HTMLVideoElement;
#endif
#if ENABLE(OFFSCREEN_CANVAS)
using WebGLCanvas = WTF::Variant<RefPtr<HTMLCanvasElement>, RefPtr<OffscreenCanvas>>;
#else
using WebGLCanvas = WTF::Variant<RefPtr<HTMLCanvasElement>>;
#endif
class WebGLRenderingContextBase : public GraphicsContextGL::Client, public GPUBasedCanvasRenderingContext, private ActivityStateChangeObserver {
WTF_MAKE_ISO_ALLOCATED(WebGLRenderingContextBase);
public:
using WebGLVersion = GraphicsContextGLWebGLVersion;
static std::unique_ptr<WebGLRenderingContextBase> create(CanvasBase&, WebGLContextAttributes&, WebGLVersion);
virtual ~WebGLRenderingContextBase();
WebGLCanvas canvas();
int drawingBufferWidth() const;
int drawingBufferHeight() const;
void activeTexture(GCGLenum texture);
void attachShader(WebGLProgram&, WebGLShader&);
void bindAttribLocation(WebGLProgram&, GCGLuint index, const String& name);
void bindBuffer(GCGLenum target, WebGLBuffer*);
virtual void bindFramebuffer(GCGLenum target, WebGLFramebuffer*);
void bindRenderbuffer(GCGLenum target, WebGLRenderbuffer*);
void bindTexture(GCGLenum target, WebGLTexture*);
void blendColor(GCGLfloat red, GCGLfloat green, GCGLfloat blue, GCGLfloat alpha);
void blendEquation(GCGLenum mode);
void blendEquationSeparate(GCGLenum modeRGB, GCGLenum modeAlpha);
void blendFunc(GCGLenum sfactor, GCGLenum dfactor);
void blendFuncSeparate(GCGLenum srcRGB, GCGLenum dstRGB, GCGLenum srcAlpha, GCGLenum dstAlpha);
using BufferDataSource = WTF::Variant<RefPtr<ArrayBuffer>, RefPtr<ArrayBufferView>>;
void bufferData(GCGLenum target, long long size, GCGLenum usage);
void bufferData(GCGLenum target, Optional<BufferDataSource>&&, GCGLenum usage);
void bufferSubData(GCGLenum target, long long offset, BufferDataSource&&);
GCGLenum checkFramebufferStatus(GCGLenum target);
void clear(GCGLbitfield mask);
void clearColor(GCGLfloat red, GCGLfloat green, GCGLfloat blue, GCGLfloat alpha);
void clearDepth(GCGLfloat);
void clearStencil(GCGLint);
void colorMask(GCGLboolean red, GCGLboolean green, GCGLboolean blue, GCGLboolean alpha);
void compileShader(WebGLShader&);
void compressedTexImage2D(GCGLenum target, GCGLint level, GCGLenum internalformat, GCGLsizei width, GCGLsizei height, GCGLint border, ArrayBufferView& data);
void compressedTexSubImage2D(GCGLenum target, GCGLint level, GCGLint xoffset, GCGLint yoffset, GCGLsizei width, GCGLsizei height, GCGLenum format, ArrayBufferView& data);
void copyTexImage2D(GCGLenum target, GCGLint level, GCGLenum internalformat, GCGLint x, GCGLint y, GCGLsizei width, GCGLsizei height, GCGLint border);
void copyTexSubImage2D(GCGLenum target, GCGLint level, GCGLint xoffset, GCGLint yoffset, GCGLint x, GCGLint y, GCGLsizei width, GCGLsizei height);
RefPtr<WebGLBuffer> createBuffer();
RefPtr<WebGLFramebuffer> createFramebuffer();
RefPtr<WebGLProgram> createProgram();
RefPtr<WebGLRenderbuffer> createRenderbuffer();
RefPtr<WebGLShader> createShader(GCGLenum type);
RefPtr<WebGLTexture> createTexture();
void cullFace(GCGLenum mode);
void deleteBuffer(WebGLBuffer*);
virtual void deleteFramebuffer(WebGLFramebuffer*);
void deleteProgram(WebGLProgram*);
void deleteRenderbuffer(WebGLRenderbuffer*);
void deleteShader(WebGLShader*);
void deleteTexture(WebGLTexture*);
void depthFunc(GCGLenum);
void depthMask(GCGLboolean);
void depthRange(GCGLfloat zNear, GCGLfloat zFar);
void detachShader(WebGLProgram&, WebGLShader&);
void disable(GCGLenum cap);
void disableVertexAttribArray(GCGLuint index);
void drawArrays(GCGLenum mode, GCGLint first, GCGLsizei count);
void drawElements(GCGLenum mode, GCGLsizei count, GCGLenum type, long long offset);
void enable(GCGLenum cap);
void enableVertexAttribArray(GCGLuint index);
void finish();
void flush();
void framebufferRenderbuffer(GCGLenum target, GCGLenum attachment, GCGLenum renderbuffertarget, WebGLRenderbuffer*);
void framebufferTexture2D(GCGLenum target, GCGLenum attachment, GCGLenum textarget, WebGLTexture*, GCGLint level);
void frontFace(GCGLenum mode);
void generateMipmap(GCGLenum target);
RefPtr<WebGLActiveInfo> getActiveAttrib(WebGLProgram&, GCGLuint index);
RefPtr<WebGLActiveInfo> getActiveUniform(WebGLProgram&, GCGLuint index);
Optional<Vector<RefPtr<WebGLShader>>> getAttachedShaders(WebGLProgram&);
GCGLint getAttribLocation(WebGLProgram&, const String& name);
WebGLAny getBufferParameter(GCGLenum target, GCGLenum pname);
Optional<WebGLContextAttributes> getContextAttributes();
GCGLenum getError();
virtual WebGLExtension* getExtension(const String& name) = 0;
virtual WebGLAny getFramebufferAttachmentParameter(GCGLenum target, GCGLenum attachment, GCGLenum pname) = 0;
virtual WebGLAny getParameter(GCGLenum pname);
WebGLAny getProgramParameter(WebGLProgram&, GCGLenum pname);
String getProgramInfoLog(WebGLProgram&);
WebGLAny getRenderbufferParameter(GCGLenum target, GCGLenum pname);
WebGLAny getShaderParameter(WebGLShader&, GCGLenum pname);
String getShaderInfoLog(WebGLShader&);
RefPtr<WebGLShaderPrecisionFormat> getShaderPrecisionFormat(GCGLenum shaderType, GCGLenum precisionType);
String getShaderSource(WebGLShader&);
virtual Optional<Vector<String>> getSupportedExtensions() = 0;
virtual WebGLAny getTexParameter(GCGLenum target, GCGLenum pname);
WebGLAny getUniform(WebGLProgram&, const WebGLUniformLocation&);
RefPtr<WebGLUniformLocation> getUniformLocation(WebGLProgram&, const String&);
WebGLAny getVertexAttrib(GCGLuint index, GCGLenum pname);
long long getVertexAttribOffset(GCGLuint index, GCGLenum pname);
bool extensionIsEnabled(const String&);
bool isPreservingDrawingBuffer() const { return m_attributes.preserveDrawingBuffer; }
void enablePreserveDrawingBuffer();
bool preventBufferClearForInspector() const { return m_preventBufferClearForInspector; }
void setPreventBufferClearForInspector(bool value) { m_preventBufferClearForInspector = value; }
void hint(GCGLenum target, GCGLenum mode);
GCGLboolean isBuffer(WebGLBuffer*);
bool isContextLost() const;
GCGLboolean isEnabled(GCGLenum cap);
GCGLboolean isFramebuffer(WebGLFramebuffer*);
GCGLboolean isProgram(WebGLProgram*);
GCGLboolean isRenderbuffer(WebGLRenderbuffer*);
GCGLboolean isShader(WebGLShader*);
GCGLboolean isTexture(WebGLTexture*);
void lineWidth(GCGLfloat);
void linkProgram(WebGLProgram&);
bool linkProgramWithoutInvalidatingAttribLocations(WebGLProgram*);
virtual void pixelStorei(GCGLenum pname, GCGLint param);
#if ENABLE(WEBXR)
using MakeXRCompatiblePromise = DOMPromiseDeferred<void>;
void makeXRCompatible(MakeXRCompatiblePromise&&);
bool isXRCompatible() const { return m_isXRCompatible; }
#endif
void polygonOffset(GCGLfloat factor, GCGLfloat units);
virtual void readPixels(GCGLint x, GCGLint y, GCGLsizei width, GCGLsizei height, GCGLenum format, GCGLenum type, ArrayBufferView& pixels);
void renderbufferStorage(GCGLenum target, GCGLenum internalformat, GCGLsizei width, GCGLsizei height);
virtual void renderbufferStorageImpl(GCGLenum target, GCGLsizei samples, GCGLenum internalformat, GCGLsizei width, GCGLsizei height, const char* functionName);
void sampleCoverage(GCGLfloat value, GCGLboolean invert);
void scissor(GCGLint x, GCGLint y, GCGLsizei width, GCGLsizei height);
void shaderSource(WebGLShader&, const String&);
void stencilFunc(GCGLenum func, GCGLint ref, GCGLuint mask);
void stencilFuncSeparate(GCGLenum face, GCGLenum func, GCGLint ref, GCGLuint mask);
void stencilMask(GCGLuint);
void stencilMaskSeparate(GCGLenum face, GCGLuint mask);
void stencilOp(GCGLenum fail, GCGLenum zfail, GCGLenum zpass);
void stencilOpSeparate(GCGLenum face, GCGLenum fail, GCGLenum zfail, GCGLenum zpass);
virtual void texImage2D(GCGLenum target, GCGLint level, GCGLenum internalformat, GCGLsizei width, GCGLsizei height, GCGLint border, GCGLenum format, GCGLenum type, RefPtr<ArrayBufferView>&&);
#if ENABLE(VIDEO)
using TexImageSource = WTF::Variant<RefPtr<ImageBitmap>, RefPtr<ImageData>, RefPtr<HTMLImageElement>, RefPtr<HTMLCanvasElement>, RefPtr<HTMLVideoElement>>;
#else
using TexImageSource = WTF::Variant<RefPtr<ImageBitmap>, RefPtr<ImageData>, RefPtr<HTMLImageElement>, RefPtr<HTMLCanvasElement>>;
#endif
virtual ExceptionOr<void> texImage2D(GCGLenum target, GCGLint level, GCGLenum internalformat, GCGLenum format, GCGLenum type, Optional<TexImageSource>);
void texParameterf(GCGLenum target, GCGLenum pname, GCGLfloat param);
void texParameteri(GCGLenum target, GCGLenum pname, GCGLint param);
virtual void texSubImage2D(GCGLenum target, GCGLint level, GCGLint xoffset, GCGLint yoffset, GCGLsizei width, GCGLsizei height, GCGLenum format, GCGLenum type, RefPtr<ArrayBufferView>&&);
virtual ExceptionOr<void> texSubImage2D(GCGLenum target, GCGLint level, GCGLint xoffset, GCGLint yoffset, GCGLenum format, GCGLenum type, Optional<TexImageSource>&&);
template <class TypedArray, class DataType>
class TypedList {
public:
using VariantType = Variant<RefPtr<TypedArray>, Vector<DataType>>;
TypedList(VariantType&& variant)
: m_variant(WTFMove(variant))
{
}
const DataType* data() const
{
return WTF::switchOn(m_variant,
[] (const RefPtr<TypedArray>& typedArray) -> const DataType* { return typedArray->data(); },
[] (const Vector<DataType>& vector) -> const DataType* { return vector.data(); }
);
}
GCGLsizei length() const
{
return WTF::switchOn(m_variant,
[] (const RefPtr<TypedArray>& typedArray) -> GCGLsizei { return typedArray->length(); },
[] (const Vector<DataType>& vector) -> GCGLsizei { return vector.size(); }
);
}
private:
VariantType m_variant;
};
using Float32List = TypedList<Float32Array, float>;
using Int32List = TypedList<Int32Array, int>;
using Uint32List = TypedList<Uint32Array, uint32_t>;
void uniform1f(const WebGLUniformLocation*, GCGLfloat x);
void uniform2f(const WebGLUniformLocation*, GCGLfloat x, GCGLfloat y);
void uniform3f(const WebGLUniformLocation*, GCGLfloat x, GCGLfloat y, GCGLfloat z);
void uniform4f(const WebGLUniformLocation*, GCGLfloat x, GCGLfloat y, GCGLfloat z, GCGLfloat w);
void uniform1i(const WebGLUniformLocation*, GCGLint x);
void uniform2i(const WebGLUniformLocation*, GCGLint x, GCGLint y);
void uniform3i(const WebGLUniformLocation*, GCGLint x, GCGLint y, GCGLint z);
void uniform4i(const WebGLUniformLocation*, GCGLint x, GCGLint y, GCGLint z, GCGLint w);
void uniform1fv(const WebGLUniformLocation*, Float32List&&);
void uniform2fv(const WebGLUniformLocation*, Float32List&&);
void uniform3fv(const WebGLUniformLocation*, Float32List&&);
void uniform4fv(const WebGLUniformLocation*, Float32List&&);
void uniform1iv(const WebGLUniformLocation*, Int32List&&);
void uniform2iv(const WebGLUniformLocation*, Int32List&&);
void uniform3iv(const WebGLUniformLocation*, Int32List&&);
void uniform4iv(const WebGLUniformLocation*, Int32List&&);
void uniformMatrix2fv(const WebGLUniformLocation*, GCGLboolean transpose, Float32List&&);
void uniformMatrix3fv(const WebGLUniformLocation*, GCGLboolean transpose, Float32List&&);
void uniformMatrix4fv(const WebGLUniformLocation*, GCGLboolean transpose, Float32List&&);
void useProgram(WebGLProgram*);
void validateProgram(WebGLProgram&);
void vertexAttrib1f(GCGLuint index, GCGLfloat x);
void vertexAttrib2f(GCGLuint index, GCGLfloat x, GCGLfloat y);
void vertexAttrib3f(GCGLuint index, GCGLfloat x, GCGLfloat y, GCGLfloat z);
void vertexAttrib4f(GCGLuint index, GCGLfloat x, GCGLfloat y, GCGLfloat z, GCGLfloat w);
void vertexAttrib1fv(GCGLuint index, Float32List&&);
void vertexAttrib2fv(GCGLuint index, Float32List&&);
void vertexAttrib3fv(GCGLuint index, Float32List&&);
void vertexAttrib4fv(GCGLuint index, Float32List&&);
void vertexAttribPointer(GCGLuint index, GCGLint size, GCGLenum type, GCGLboolean normalized,
GCGLsizei stride, long long offset);
void viewport(GCGLint x, GCGLint y, GCGLsizei width, GCGLsizei height);
enum LostContextMode {
RealLostContext,
SyntheticLostContext
};
void forceLostContext(LostContextMode);
void forceRestoreContext();
void loseContextImpl(LostContextMode);
WEBCORE_EXPORT void simulateContextChanged();
GraphicsContextGL* graphicsContextGL() const { return m_context.get(); }
WebGLContextGroup* contextGroup() const { return m_contextGroup.get(); }
PlatformLayer* platformLayer() const override;
void reshape(int width, int height) override;
void prepareForDisplayWithPaint() final;
void paintRenderingResultsToCanvas() final;
RefPtr<ImageData> paintRenderingResultsToImageData();
void removeSharedObject(WebGLSharedObject&);
void removeContextObject(WebGLContextObject&);
unsigned getMaxVertexAttribs() const { return m_maxVertexAttribs; }
bool isContextUnrecoverablyLost() const;
void drawArraysInstanced(GCGLenum mode, GCGLint first, GCGLsizei count, GCGLsizei primcount);
void drawElementsInstanced(GCGLenum mode, GCGLsizei count, GCGLenum type, long long offset, GCGLsizei primcount);
void vertexAttribDivisor(GCGLuint index, GCGLuint divisor);
WEBCORE_EXPORT void setFailNextGPUStatusCheck();
void didComposite() override;
void forceContextLost() override;
void recycleContext() override;
void dispatchContextChangedNotification() override;
virtual void addMembersToOpaqueRoots(JSC::SlotVisitor&);
Lock& objectGraphLock();
protected:
WebGLRenderingContextBase(CanvasBase&, WebGLContextAttributes);
WebGLRenderingContextBase(CanvasBase&, Ref<GraphicsContextGL>&&, WebGLContextAttributes);
friend class EXTTextureCompressionRGTC;
friend class WebGLDrawBuffers;
friend class WebGLFramebuffer;
friend class WebGLObject;
friend class OESVertexArrayObject;
friend class WebGLDebugShaders;
friend class WebGLCompressedTextureASTC;
friend class WebGLCompressedTextureATC;
friend class WebGLCompressedTextureETC;
friend class WebGLCompressedTextureETC1;
friend class WebGLCompressedTexturePVRTC;
friend class WebGLCompressedTextureS3TC;
friend class WebGLCompressedTextureS3TCsRGB;
friend class WebGLRenderingContextErrorMessageCallback;
friend class WebGLVertexArrayObjectOES;
friend class WebGLVertexArrayObject;
friend class WebGLVertexArrayObjectBase;
friend class WebGLSync;
friend class ScopedUnpackParametersResetRestore;
virtual void initializeNewContext();
virtual void initializeVertexArrayObjects() = 0;
void setupFlags();
void stop() override;
const char* activeDOMObjectName() const override;
void suspend(ReasonForSuspension) override;
void resume() override;
void addSharedObject(WebGLSharedObject&);
void addContextObject(WebGLContextObject&);
void detachAndRemoveAllObjects();
void destroyGraphicsContextGL();
void markContextChanged();
void markContextChangedAndNotifyCanvasObserver();
void addActivityStateChangeObserverIfNecessary();
void removeActivityStateChangeObserver();
bool isGLES2Compliant() { return m_isGLES2Compliant; }
bool isGLES2NPOTStrict() { return m_isGLES2NPOTStrict; }
bool isDepthStencilSupported() { return m_isDepthStencilSupported; }
unsigned sizeInBytes(GCGLenum type);
bool validateElementArraySize(GCGLsizei count, GCGLenum type, GCGLintptr offset);
virtual bool validateIndexArrayConservative(GCGLenum type, unsigned& numElementsRequired) = 0;
bool validateIndexArrayPrecise(GCGLsizei count, GCGLenum type, GCGLintptr offset, unsigned& numElementsRequired);
bool validateVertexAttributes(unsigned elementCount, unsigned primitiveCount = 0);
bool validateWebGLObject(const char*, WebGLObject*);
bool validateWebGLProgramOrShader(const char*, WebGLObject*);
#if !USE(ANGLE)
bool validateDrawArrays(const char* functionName, GCGLenum mode, GCGLint first, GCGLsizei count, GCGLsizei primcount);
bool validateDrawElements(const char* functionName, GCGLenum mode, GCGLsizei count, GCGLenum type, long long offset, unsigned& numElements, GCGLsizei primcount);
bool validateNPOTTextureLevel(GCGLsizei width, GCGLsizei height, GCGLint level, const char* functionName);
#endif
void addCompressedTextureFormat(GCGLenum);
virtual void resetUnpackParameters();
virtual void restoreUnpackParameters();
RefPtr<Image> drawImageIntoBuffer(Image&, int width, int height, int deviceScaleFactor, const char* functionName);
#if ENABLE(VIDEO)
RefPtr<Image> videoFrameToImage(HTMLVideoElement*, BackingStoreCopy);
#endif
WebGLTexture::TextureExtensionFlag textureExtensionFlags() const;
bool enableSupportedExtension(ASCIILiteral extensionNameLiteral);
void loseExtensions(LostContextMode);
virtual void uncacheDeletedBuffer(const WTF::AbstractLocker&, WebGLBuffer*);
bool compositingResultsNeedUpdating() const final { return m_compositingResultsNeedUpdating; }
bool needsPreparationForDisplay() const final { return true; }
void prepareForDisplay() final;
RefPtr<GraphicsContextGL> m_context;
RefPtr<WebGLContextGroup> m_contextGroup;
Lock m_objectGraphLock;
bool m_restoreAllowed { false };
SuspendableTimer m_restoreTimer;
bool m_needsUpdate;
bool m_markedCanvasDirty;
HashSet<WebGLContextObject*> m_contextObjects;
RefPtr<WebGLBuffer> m_boundArrayBuffer;
RefPtr<WebGLVertexArrayObjectBase> m_defaultVertexArrayObject;
RefPtr<WebGLVertexArrayObjectBase> m_boundVertexArrayObject;
void setBoundVertexArrayObject(const WTF::AbstractLocker&, WebGLVertexArrayObjectBase*);
class VertexAttribValue {
public:
VertexAttribValue()
{
initValue();
}
void initValue()
{
type = GraphicsContextGL::FLOAT;
fValue[0] = 0.0f;
fValue[1] = 0.0f;
fValue[2] = 0.0f;
fValue[3] = 1.0f;
}
GCGLenum type;
union {
GCGLfloat fValue[4];
GCGLint iValue[4];
GCGLuint uiValue[4];
};
};
Vector<VertexAttribValue> m_vertexAttribValue;
unsigned m_maxVertexAttribs;
#if !USE(ANGLE)
RefPtr<WebGLBuffer> m_vertexAttrib0Buffer;
long m_vertexAttrib0BufferSize { 0 };
GCGLfloat m_vertexAttrib0BufferValue[4];
bool m_forceAttrib0BufferRefill { true };
bool m_vertexAttrib0UsedBefore { false };
#endif
RefPtr<WebGLProgram> m_currentProgram;
RefPtr<WebGLFramebuffer> m_framebufferBinding;
RefPtr<WebGLRenderbuffer> m_renderbufferBinding;
struct TextureUnitState {
RefPtr<WebGLTexture> texture2DBinding;
RefPtr<WebGLTexture> textureCubeMapBinding;
RefPtr<WebGLTexture> texture3DBinding;
RefPtr<WebGLTexture> texture2DArrayBinding;
};
Vector<TextureUnitState> m_textureUnits;
#if !USE(ANGLE)
HashSet<unsigned, DefaultHash<unsigned>, WTF::UnsignedWithZeroKeyHashTraits<unsigned>> m_unrenderableTextureUnits;
#endif
unsigned long m_activeTextureUnit;
RefPtr<WebGLTexture> m_blackTexture2D;
RefPtr<WebGLTexture> m_blackTextureCubeMap;
Vector<GCGLenum> m_compressedTextureFormats;
class LRUImageBufferCache {
public:
LRUImageBufferCache(int capacity);
ImageBuffer* imageBuffer(const IntSize& size);
private:
void bubbleToFront(size_t idx);
Vector<RefPtr<ImageBuffer>> m_buffers;
};
LRUImageBufferCache m_generatedImageCache { 0 };
GCGLint m_maxTextureSize;
GCGLint m_maxCubeMapTextureSize;
GCGLint m_maxRenderbufferSize;
GCGLint m_maxViewportDims[2] { 0, 0 };
GCGLint m_maxTextureLevel;
GCGLint m_maxCubeMapTextureLevel;
GCGLint m_maxDrawBuffers;
GCGLint m_maxColorAttachments;
GCGLenum m_backDrawBuffer;
bool m_drawBuffersWebGLRequirementsChecked;
bool m_drawBuffersSupported;
GCGLint m_packAlignment;
GCGLint m_unpackAlignment;
bool m_unpackFlipY;
bool m_unpackPremultiplyAlpha;
GCGLenum m_unpackColorspaceConversion;
bool m_contextLost { false };
LostContextMode m_contextLostMode { SyntheticLostContext };
WebGLContextAttributes m_attributes;
bool m_layerCleared;
GCGLfloat m_clearColor[4];
bool m_scissorEnabled;
GCGLfloat m_clearDepth;
GCGLint m_clearStencil;
GCGLboolean m_colorMask[4];
GCGLboolean m_depthMask;
bool m_stencilEnabled;
GCGLuint m_stencilMask, m_stencilMaskBack;
GCGLint m_stencilFuncRef, m_stencilFuncRefBack; GCGLuint m_stencilFuncMask, m_stencilFuncMaskBack;
bool m_rasterizerDiscardEnabled { false };
bool m_isGLES2Compliant;
bool m_isGLES2NPOTStrict;
bool m_isDepthStencilSupported;
bool m_isRobustnessEXTSupported;
bool m_synthesizedErrorsToConsole { true };
int m_numGLErrorsToConsoleAllowed;
bool m_preventBufferClearForInspector { false };
bool m_isPendingPolicyResolution { false };
bool m_hasRequestedPolicyResolution { false };
bool isContextLostOrPending();
bool m_compositingResultsNeedUpdating { false };
bool m_isDisplayingWithPaint { false };
RefPtr<EXTFragDepth> m_extFragDepth;
RefPtr<EXTBlendMinMax> m_extBlendMinMax;
RefPtr<EXTsRGB> m_extsRGB;
RefPtr<EXTTextureCompressionRGTC> m_extTextureCompressionRGTC;
RefPtr<EXTTextureFilterAnisotropic> m_extTextureFilterAnisotropic;
RefPtr<EXTShaderTextureLOD> m_extShaderTextureLOD;
RefPtr<KHRParallelShaderCompile> m_khrParallelShaderCompile;
RefPtr<OESTextureFloat> m_oesTextureFloat;
RefPtr<OESTextureFloatLinear> m_oesTextureFloatLinear;
RefPtr<OESTextureHalfFloat> m_oesTextureHalfFloat;
RefPtr<OESTextureHalfFloatLinear> m_oesTextureHalfFloatLinear;
RefPtr<OESStandardDerivatives> m_oesStandardDerivatives;
RefPtr<OESVertexArrayObject> m_oesVertexArrayObject;
RefPtr<OESElementIndexUint> m_oesElementIndexUint;
RefPtr<OESFBORenderMipmap> m_oesFBORenderMipmap;
RefPtr<WebGLLoseContext> m_webglLoseContext;
RefPtr<WebGLDebugRendererInfo> m_webglDebugRendererInfo;
RefPtr<WebGLDebugShaders> m_webglDebugShaders;
RefPtr<WebGLCompressedTextureASTC> m_webglCompressedTextureASTC;
RefPtr<WebGLCompressedTextureATC> m_webglCompressedTextureATC;
RefPtr<WebGLCompressedTextureETC> m_webglCompressedTextureETC;
RefPtr<WebGLCompressedTextureETC1> m_webglCompressedTextureETC1;
RefPtr<WebGLCompressedTexturePVRTC> m_webglCompressedTexturePVRTC;
RefPtr<WebGLCompressedTextureS3TC> m_webglCompressedTextureS3TC;
RefPtr<WebGLCompressedTextureS3TCsRGB> m_webglCompressedTextureS3TCsRGB;
RefPtr<WebGLDepthTexture> m_webglDepthTexture;
RefPtr<WebGLDrawBuffers> m_webglDrawBuffers;
RefPtr<ANGLEInstancedArrays> m_angleInstancedArrays;
RefPtr<EXTColorBufferHalfFloat> m_extColorBufferHalfFloat;
RefPtr<EXTFloatBlend> m_extFloatBlend;
RefPtr<WebGLColorBufferFloat> m_webglColorBufferFloat;
RefPtr<EXTColorBufferFloat> m_extColorBufferFloat;
bool m_areWebGL2TexImageSourceFormatsAndTypesAdded { false };
bool m_areOESTextureFloatFormatsAndTypesAdded { false };
bool m_areOESTextureHalfFloatFormatsAndTypesAdded { false };
bool m_areEXTsRGBFormatsAndTypesAdded { false };
HashSet<GCGLenum> m_supportedTexImageSourceInternalFormats;
HashSet<GCGLenum> m_supportedTexImageSourceFormats;
HashSet<GCGLenum> m_supportedTexImageSourceTypes;
bool getBooleanParameter(GCGLenum);
Vector<bool> getBooleanArrayParameter(GCGLenum);
float getFloatParameter(GCGLenum);
int getIntParameter(GCGLenum);
unsigned getUnsignedIntParameter(GCGLenum);
RefPtr<Float32Array> getWebGLFloatArrayParameter(GCGLenum);
RefPtr<Int32Array> getWebGLIntArrayParameter(GCGLenum);
enum ClearCaller {
ClearCallerDrawOrClear,
ClearCallerOther,
};
bool clearIfComposited(ClearCaller, GCGLbitfield clearMask = 0);
void restoreStateAfterClear();
enum class TexImageFunctionType {
TexImage,
TexSubImage,
CopyTexImage,
CompressedTexImage
};
enum class TexImageFunctionID {
TexImage2D,
TexSubImage2D,
TexImage3D,
TexSubImage3D
};
enum class TexImageDimension {
Tex2D,
Tex3D
};
enum TexFuncValidationSourceType {
SourceArrayBufferView,
SourceImageBitmap,
SourceImageData,
SourceHTMLImageElement,
SourceHTMLCanvasElement,
#if ENABLE(VIDEO)
SourceHTMLVideoElement,
#endif
SourceUnpackBuffer,
};
enum NullDisposition {
NullAllowed,
NullNotAllowed,
NullNotReachable
};
template <typename T> IntRect getTextureSourceSize(T* textureSource)
{
return IntRect(0, 0, textureSource->width(), textureSource->height());
}
template <typename T> bool validateTexImageSubRectangle(const char* functionName,
TexImageFunctionID functionID,
T* image,
const IntRect& subRect,
GCGLsizei depth,
GCGLint unpackImageHeight,
bool* selectingSubRectangle)
{
ASSERT(functionName);
ASSERT(selectingSubRectangle);
if (!image) {
synthesizeGLError(GraphicsContextGL::OUT_OF_MEMORY, functionName, "out of memory");
return false;
}
int imageWidth = static_cast<int>(image->width());
int imageHeight = static_cast<int>(image->height());
*selectingSubRectangle = !(!subRect.x() && !subRect.y() && subRect.width() == imageWidth && subRect.height() == imageHeight);
ASSERT(!*selectingSubRectangle || isWebGL2());
if (!subRect.isValid() || subRect.x() < 0 || subRect.y() < 0
|| subRect.maxX() > imageWidth || subRect.maxY() > imageHeight
|| subRect.width() < 0 || subRect.height() < 0) {
synthesizeGLError(GraphicsContextGL::INVALID_OPERATION, functionName,
"source sub-rectangle specified via pixel unpack parameters is invalid");
return false;
}
if (functionID == TexImageFunctionID::TexImage3D || functionID == TexImageFunctionID::TexSubImage3D) {
ASSERT(unpackImageHeight >= 0);
if (depth < 1) {
synthesizeGLError(GraphicsContextGL::INVALID_OPERATION, functionName,
"Can't define a 3D texture with depth < 1");
return false;
}
Checked<GCGLint, RecordOverflow> maxYAccessed;
if (unpackImageHeight)
maxYAccessed = unpackImageHeight;
else
maxYAccessed = subRect.height();
maxYAccessed *= depth - 1;
maxYAccessed += subRect.height();
maxYAccessed += subRect.y();
if (maxYAccessed.hasOverflowed()) {
synthesizeGLError(GraphicsContextGL::INVALID_OPERATION, functionName,
"Out-of-range parameters passed for 3D texture upload");
return false;
}
if (maxYAccessed.unsafeGet() > imageHeight) {
synthesizeGLError(GraphicsContextGL::INVALID_OPERATION, functionName,
"Not enough data supplied to upload to a 3D texture with depth > 1");
return false;
}
} else {
ASSERT(depth >= 1);
ASSERT(!unpackImageHeight);
}
return true;
}
IntRect sentinelEmptyRect();
IntRect safeGetImageSize(Image*);
IntRect getImageDataSize(ImageData*);
IntRect getTexImageSourceSize(TexImageSource&);
ExceptionOr<void> texImageSourceHelper(TexImageFunctionID, GCGLenum target, GCGLint level, GCGLint internalformat, GCGLint border, GCGLenum format, GCGLenum type, GCGLint xoffset, GCGLint yoffset, GCGLint zoffset, const IntRect& sourceImageRect, GCGLsizei depth, GCGLint unpackImageHeight, TexImageSource&&);
void texImageArrayBufferViewHelper(TexImageFunctionID, GCGLenum target, GCGLint level, GCGLint internalformat, GCGLsizei width, GCGLsizei height, GCGLsizei depth, GCGLint border, GCGLenum format, GCGLenum type, GCGLint xoffset, GCGLint yoffset, GCGLint zoffset, RefPtr<ArrayBufferView>&& pixels, NullDisposition, GCGLuint srcOffset);
void texImageImpl(TexImageFunctionID, GCGLenum target, GCGLint level, GCGLenum internalformat, GCGLint xoffset, GCGLint yoffset, GCGLint zoffset, GCGLenum format, GCGLenum type, Image*, GraphicsContextGL::DOMSource, bool flipY, bool premultiplyAlpha, bool ignoreNativeImageAlphaPremultiplication, const IntRect&, GCGLsizei depth, GCGLint unpackImageHeight);
void texImage2DBase(GCGLenum target, GCGLint level, GCGLenum internalformat, GCGLsizei width, GCGLsizei height, GCGLint border, GCGLenum format, GCGLenum type, GCGLsizei byteLength, const void* pixels);
void texSubImage2DBase(GCGLenum target, GCGLint level, GCGLint xoffset, GCGLint yoffset, GCGLsizei width, GCGLsizei height, GCGLenum internalformat, GCGLenum format, GCGLenum type, GCGLsizei byteLength, const void* pixels);
static const char* getTexImageFunctionName(TexImageFunctionID);
using PixelStoreParams = GraphicsContextGL::PixelStoreParams;
virtual PixelStoreParams getPackPixelStoreParams() const;
virtual PixelStoreParams getUnpackPixelStoreParams(TexImageDimension) const;
#if !USE(ANGLE)
bool checkTextureCompleteness(const char*, bool);
void createFallbackBlackTextures1x1();
bool isTexInternalFormatColorBufferCombinationValid(GCGLenum texInternalFormat, GCGLenum colorBufferFormat);
GCGLenum getBoundReadFramebufferColorFormat();
int getBoundReadFramebufferWidth();
int getBoundReadFramebufferHeight();
#endif
bool validateLocationLength(const char* functionName, const String&);
bool validateSize(const char* functionName, GCGLint x, GCGLint y, GCGLint z = 0);
bool validateString(const char* functionName, const String&);
RefPtr<WebGLTexture> validateTextureBinding(const char* functionName, GCGLenum target);
virtual RefPtr<WebGLTexture> validateTexImageBinding(const char*, TexImageFunctionID, GCGLenum);
RefPtr<WebGLTexture> validateTexture2DBinding(const char*, GCGLenum);
void addExtensionSupportedFormatsAndTypes();
void addExtensionSupportedFormatsAndTypesWebGL2();
bool validateTexImageSourceFormatAndType(const char* functionName, TexImageFunctionType, GCGLenum internalformat, GCGLenum format, GCGLenum type);
bool validateTexFuncFormatAndType(const char* functionName, GCGLenum internalformat, GCGLenum format, GCGLenum type, GCGLint level);
bool validateTexFuncLevel(const char* functionName, GCGLenum target, GCGLint level);
virtual GCGLint maxTextureLevelForTarget(GCGLenum target);
bool validateTexFunc(const char* functionName, TexImageFunctionType, TexFuncValidationSourceType, GCGLenum target, GCGLint level, GCGLenum internalformat, GCGLsizei width,
GCGLsizei height, GCGLsizei depth, GCGLint border, GCGLenum format, GCGLenum type, GCGLint xoffset, GCGLint yoffset, GCGLint zoffset);
bool validateTexFuncParameters(const char* functionName,
TexImageFunctionType,
TexFuncValidationSourceType,
GCGLenum target, GCGLint level,
GCGLenum internalformat,
GCGLsizei width, GCGLsizei height, GCGLsizei depth,
GCGLint border,
GCGLenum format, GCGLenum type);
bool validateTexFuncData(const char* functionName, TexImageDimension,
GCGLsizei width, GCGLsizei height, GCGLsizei depth,
GCGLenum format, GCGLenum type,
ArrayBufferView* pixels,
NullDisposition,
GCGLuint srcOffset);
bool validateSettableTexInternalFormat(const char* functionName, GCGLenum format);
#if !USE(ANGLE)
bool validateCompressedTexFuncData(const char* functionName, GCGLsizei width, GCGLsizei height, GCGLenum format, ArrayBufferView& pixels);
bool validateCompressedTexFormat(GCGLenum format);
bool validateCompressedTexDimensions(const char* functionName, GCGLenum target, GCGLint level, GCGLsizei width, GCGLsizei height, GCGLenum format);
bool validateCompressedTexSubDimensions(const char* functionName, GCGLenum target, GCGLint level, GCGLint xoffset, GCGLint yoffset,
GCGLsizei width, GCGLsizei height, GCGLenum format, WebGLTexture*);
#endif
bool validateDrawMode(const char* functionName, GCGLenum);
bool validateStencilSettings(const char* functionName);
bool validateStencilFunc(const char* functionName, GCGLenum);
void texParameter(GCGLenum target, GCGLenum pname, GCGLfloat parami, GCGLint paramf, bool isFloat);
void printToConsole(MessageLevel, const String&);
virtual bool validateFramebufferTarget(GCGLenum target);
virtual WebGLFramebuffer* getFramebufferBinding(GCGLenum target);
virtual WebGLFramebuffer* getReadFramebufferBinding();
bool validateFramebufferFuncParameters(const char* functionName, GCGLenum target, GCGLenum attachment);
virtual bool validateBlendEquation(const char* functionName, GCGLenum) = 0;
bool validateBlendFuncFactors(const char* functionName, GCGLenum src, GCGLenum dst);
virtual bool validateCapability(const char* functionName, GCGLenum);
bool validateUniformLocation(const char* functionName, const WebGLUniformLocation*);
template<typename T, typename TypedListType>
Optional<GCGLSpan<const T>> validateUniformParameters(const char* functionName, const WebGLUniformLocation* location, const TypedList<TypedListType, T>& values, GCGLsizei requiredMinSize, GCGLuint srcOffset = 0, GCGLuint srcLength = 0)
{
return validateUniformMatrixParameters(functionName, location, false, values, requiredMinSize, srcOffset, srcLength);
}
template<typename T, typename TypedListType>
Optional<GCGLSpan<const T>> validateUniformMatrixParameters(const char* functionName, const WebGLUniformLocation*, GCGLboolean transpose, const TypedList<TypedListType, T>&, GCGLsizei requiredMinSize, GCGLuint srcOffset = 0, GCGLuint srcLength = 0);
virtual WebGLBuffer* validateBufferDataParameters(const char* functionName, GCGLenum target, GCGLenum usage);
ExceptionOr<bool> validateHTMLImageElement(const char* functionName, HTMLImageElement*);
ExceptionOr<bool> validateHTMLCanvasElement(const char* functionName, HTMLCanvasElement*);
#if ENABLE(VIDEO)
ExceptionOr<bool> validateHTMLVideoElement(const char* functionName, HTMLVideoElement*);
#endif
ExceptionOr<bool> validateImageBitmap(const char* functionName, ImageBitmap*);
void vertexAttribfImpl(const char* functionName, GCGLuint index, GCGLsizei expectedSize, GCGLfloat, GCGLfloat, GCGLfloat, GCGLfloat);
void vertexAttribfvImpl(const char* functionName, GCGLuint index, Float32List&&, GCGLsizei expectedSize);
bool deleteObject(const WTF::AbstractLocker&, WebGLObject*);
bool checkObjectToBeBound(const char* functionName, WebGLObject*);
virtual bool validateBufferTarget(const char* functionName, GCGLenum target);
virtual WebGLBuffer* validateBufferDataTarget(const char* functionName, GCGLenum target);
virtual bool validateAndCacheBufferBinding(const WTF::AbstractLocker&, const char* functionName, GCGLenum target, WebGLBuffer*);
#if !USE(ANGLE)
void initVertexAttrib0();
Optional<bool> simulateVertexAttrib0(GCGLuint numVertex);
bool validateSimulatedVertexAttrib0(GCGLuint numVertex);
void restoreStatesAfterVertexAttrib0Simulation();
#endif
enum ConsoleDisplayPreference { DisplayInConsole, DontDisplayInConsole };
void synthesizeGLError(GCGLenum, const char* functionName, const char* description, ConsoleDisplayPreference = DisplayInConsole);
String ensureNotNull(const String&) const;
void applyStencilTest();
void enableOrDisable(GCGLenum capability, bool enable);
IntSize clampedCanvasSize();
virtual GCGLint getMaxDrawBuffers() = 0;
virtual GCGLint getMaxColorAttachments() = 0;
void setBackDrawBuffer(GCGLenum);
void setFramebuffer(const WTF::AbstractLocker&, GCGLenum, WebGLFramebuffer*);
virtual void restoreCurrentFramebuffer();
void restoreCurrentTexture2D();
bool supportsDrawBuffers();
#if ENABLE(OFFSCREEN_CANVAS)
OffscreenCanvas* offscreenCanvas();
#endif
template <typename T> inline Optional<T> checkedAddAndMultiply(T value, T add, T multiply);
template <typename T> unsigned getMaxIndex(const RefPtr<JSC::ArrayBuffer> elementArrayBuffer, GCGLintptr uoffset, GCGLsizei n);
bool validateArrayBufferType(const char* functionName, GCGLenum type, Optional<JSC::TypedArrayType>);
private:
void scheduleTaskToDispatchContextLostEvent();
void maybeRestoreContext();
void registerWithWebGLStateTracker();
void checkForContextLossHandling();
void activityStateDidChange(OptionSet<ActivityState::Flag> oldActivityState, OptionSet<ActivityState::Flag> newActivityState) override;
WebGLStateTracker::Token m_trackerToken;
Timer m_checkForContextLossHandlingTimer;
bool m_isSuspended { false };
#if ENABLE(WEBXR)
bool m_isXRCompatible { false };
#endif
};
template <typename T>
inline Optional<T> WebGLRenderingContextBase::checkedAddAndMultiply(T value, T add, T multiply)
{
Checked<T, RecordOverflow> checkedResult = Checked<T>(value);
checkedResult += Checked<T>(add);
checkedResult *= Checked<T>(multiply);
if (checkedResult.hasOverflowed())
return WTF::nullopt;
return checkedResult.unsafeGet();
}
template<typename T>
inline unsigned WebGLRenderingContextBase::getMaxIndex(const RefPtr<JSC::ArrayBuffer> elementArrayBuffer, GCGLintptr uoffset, GCGLsizei n)
{
unsigned maxIndex = 0;
T restartIndex = 0;
#if ENABLE(WEBGL2)
if (isWebGL2())
restartIndex = std::numeric_limits<T>::max();
#endif
uoffset /= sizeof(T);
const T* p = static_cast<const T*>(elementArrayBuffer->data()) + uoffset;
while (n-- > 0) {
if (*p != restartIndex && *p > maxIndex)
maxIndex = *p;
++p;
}
return maxIndex;
}
}
SPECIALIZE_TYPE_TRAITS_CANVASRENDERINGCONTEXT(WebCore::WebGLRenderingContextBase, isWebGL())
#endif