Blob Blame History Raw
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef WEBGL2CONTEXT_H_
#define WEBGL2CONTEXT_H_

#include "WebGLContext.h"

namespace mozilla {

class ErrorResult;
class WebGLSampler;
class WebGLSync;
class WebGLTransformFeedback;
class WebGLVertexArrayObject;
namespace dom {
class OwningUnsignedLongOrUint32ArrayOrBoolean;
class OwningWebGLBufferOrLongLong;
}  // namespace dom

class WebGL2Context : public WebGLContext {
 public:
  virtual ~WebGL2Context();

  static bool IsSupported();
  static WebGL2Context* Create();

  virtual bool IsWebGL2() const override { return true; }

  // -------------------------------------------------------------------------
  // IMPLEMENT nsWrapperCache

  virtual JSObject* WrapObject(JSContext* cx,
                               JS::Handle<JSObject*> givenProto) override;

  // -------------------------------------------------------------------------
  // Buffer objects - WebGL2ContextBuffers.cpp

  void CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
                         GLintptr readOffset, GLintptr writeOffset,
                         GLsizeiptr size);

 private:
  template <typename BufferT>
  void GetBufferSubDataT(GLenum target, GLintptr offset, const BufferT& data);

 public:
  void GetBufferSubData(GLenum target, GLintptr srcByteOffset,
                        const dom::ArrayBufferView& dstData,
                        GLuint dstElemOffset, GLuint dstElemCountOverride);

  // -------------------------------------------------------------------------
  // Framebuffer objects - WebGL2ContextFramebuffers.cpp

  void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
                       GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
                       GLbitfield mask, GLenum filter);
  void FramebufferTextureLayer(GLenum target, GLenum attachment,
                               WebGLTexture* texture, GLint level, GLint layer);

  virtual JS::Value GetFramebufferAttachmentParameter(JSContext* cx,
                                                      GLenum target,
                                                      GLenum attachment,
                                                      GLenum pname,
                                                      ErrorResult& rv) override;
  // Make the inline version from the superclass visible here.
  using WebGLContext::GetFramebufferAttachmentParameter;

  void InvalidateFramebuffer(GLenum target,
                             const dom::Sequence<GLenum>& attachments,
                             ErrorResult& rv);
  void InvalidateSubFramebuffer(GLenum target,
                                const dom::Sequence<GLenum>& attachments,
                                GLint x, GLint y, GLsizei width, GLsizei height,
                                ErrorResult& rv);
  void ReadBuffer(GLenum mode);

  // -------------------------------------------------------------------------
  // Renderbuffer objects - WebGL2ContextRenderbuffers.cpp

  void GetInternalformatParameter(JSContext*, GLenum target,
                                  GLenum internalformat, GLenum pname,
                                  JS::MutableHandleValue retval,
                                  ErrorResult& rv);
  void RenderbufferStorageMultisample(GLenum target, GLsizei samples,
                                      GLenum internalformat, GLsizei width,
                                      GLsizei height);

  // -------------------------------------------------------------------------
  // Texture objects - WebGL2ContextTextures.cpp

  void TexStorage2D(GLenum target, GLsizei levels, GLenum internalFormat,
                    GLsizei width, GLsizei height) {
    const char funcName[] = "TexStorage2D";
    const uint8_t funcDims = 2;
    const GLsizei depth = 1;
    TexStorage(funcName, funcDims, target, levels, internalFormat, width,
               height, depth);
  }

  void TexStorage3D(GLenum target, GLsizei levels, GLenum internalFormat,
                    GLsizei width, GLsizei height, GLsizei depth) {
    const char funcName[] = "TexStorage3D";
    const uint8_t funcDims = 3;
    TexStorage(funcName, funcDims, target, levels, internalFormat, width,
               height, depth);
  }

 protected:
  void TexStorage(const char* funcName, uint8_t funcDims, GLenum target,
                  GLsizei levels, GLenum internalFormat, GLsizei width,
                  GLsizei height, GLsizei depth);

  ////////////////////////////////////

 public:
  void CompressedTexImage3D(GLenum target, GLint level, GLenum internalFormat,
                            GLsizei width, GLsizei height, GLsizei depth,
                            GLint border, GLsizei imageSize,
                            WebGLintptr offset) {
    const char funcName[] = "compressedTexImage3D";
    const uint8_t funcDims = 3;
    const TexImageSourceAdapter src(&offset, 0, 0);
    CompressedTexImage(funcName, funcDims, target, level, internalFormat, width,
                       height, depth, border, src, Some(imageSize));
  }

  template <typename T>
  void CompressedTexImage3D(GLenum target, GLint level, GLenum internalFormat,
                            GLsizei width, GLsizei height, GLsizei depth,
                            GLint border, const T& anySrc,
                            GLuint viewElemOffset = 0,
                            GLuint viewElemLengthOverride = 0) {
    const char funcName[] = "compressedTexImage3D";
    const uint8_t funcDims = 3;
    const TexImageSourceAdapter src(&anySrc, viewElemOffset,
                                    viewElemLengthOverride);
    CompressedTexImage(funcName, funcDims, target, level, internalFormat, width,
                       height, depth, border, src, Nothing());
  }

  void CompressedTexSubImage3D(GLenum target, GLint level, GLint xOffset,
                               GLint yOffset, GLint zOffset, GLsizei width,
                               GLsizei height, GLsizei depth,
                               GLenum unpackFormat, GLsizei imageSize,
                               WebGLintptr offset) {
    const char funcName[] = "compressedTexSubImage3D";
    const uint8_t funcDims = 3;
    const TexImageSourceAdapter src(&offset, 0, 0);
    CompressedTexSubImage(funcName, funcDims, target, level, xOffset, yOffset,
                          zOffset, width, height, depth, unpackFormat, src,
                          Some(imageSize));
  }

  template <typename T>
  void CompressedTexSubImage3D(GLenum target, GLint level, GLint xOffset,
                               GLint yOffset, GLint zOffset, GLsizei width,
                               GLsizei height, GLsizei depth,
                               GLenum unpackFormat, const T& anySrc,
                               GLuint viewElemOffset = 0,
                               GLuint viewElemLengthOverride = 0) {
    const char funcName[] = "compressedTexSubImage3D";
    const uint8_t funcDims = 3;
    const TexImageSourceAdapter src(&anySrc, viewElemOffset,
                                    viewElemLengthOverride);
    CompressedTexSubImage(funcName, funcDims, target, level, xOffset, yOffset,
                          zOffset, width, height, depth, unpackFormat, src,
                          Nothing());
  }

  ////////////////////////////////////

  void CopyTexSubImage3D(GLenum target, GLint level, GLint xOffset,
                         GLint yOffset, GLint zOffset, GLint x, GLint y,
                         GLsizei width, GLsizei height) {
    const char funcName[] = "copyTexSubImage3D";
    const uint8_t funcDims = 3;
    CopyTexSubImage(funcName, funcDims, target, level, xOffset, yOffset,
                    zOffset, x, y, width, height);
  }

  ////////////////////////////////////

  template <typename T>
  void TexImage3D(GLenum target, GLint level, GLenum internalFormat,
                  GLsizei width, GLsizei height, GLsizei depth, GLint border,
                  GLenum unpackFormat, GLenum unpackType, const T& anySrc,
                  ErrorResult& out_error) {
    const TexImageSourceAdapter src(&anySrc, &out_error);
    TexImage3D(target, level, internalFormat, width, height, depth, border,
               unpackFormat, unpackType, src);
  }

  void TexImage3D(GLenum target, GLint level, GLenum internalFormat,
                  GLsizei width, GLsizei height, GLsizei depth, GLint border,
                  GLenum unpackFormat, GLenum unpackType,
                  const dom::ArrayBufferView& view, GLuint viewElemOffset,
                  ErrorResult&) {
    const TexImageSourceAdapter src(&view, viewElemOffset);
    TexImage3D(target, level, internalFormat, width, height, depth, border,
               unpackFormat, unpackType, src);
  }

 protected:
  void TexImage3D(GLenum target, GLint level, GLenum internalFormat,
                  GLsizei width, GLsizei height, GLsizei depth, GLint border,
                  GLenum unpackFormat, GLenum unpackType,
                  const TexImageSource& src) {
    const char funcName[] = "texImage3D";
    const uint8_t funcDims = 3;
    TexImage(funcName, funcDims, target, level, internalFormat, width, height,
             depth, border, unpackFormat, unpackType, src);
  }

  ////////////////////////////////////

 public:
  template <typename T>
  void TexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
                     GLint zOffset, GLsizei width, GLsizei height,
                     GLsizei depth, GLenum unpackFormat, GLenum unpackType,
                     const T& anySrc, ErrorResult& out_error) {
    const TexImageSourceAdapter src(&anySrc, &out_error);
    TexSubImage3D(target, level, xOffset, yOffset, zOffset, width, height,
                  depth, unpackFormat, unpackType, src);
  }

  void TexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
                     GLint zOffset, GLsizei width, GLsizei height,
                     GLsizei depth, GLenum unpackFormat, GLenum unpackType,
                     const dom::Nullable<dom::ArrayBufferView>& maybeSrcView,
                     GLuint srcElemOffset, ErrorResult&) {
    if (IsContextLost()) return;

    if (!ValidateNonNull("texSubImage3D", maybeSrcView)) return;
    const auto& srcView = maybeSrcView.Value();

    const TexImageSourceAdapter src(&srcView, srcElemOffset);
    TexSubImage3D(target, level, xOffset, yOffset, zOffset, width, height,
                  depth, unpackFormat, unpackType, src);
  }

 protected:
  void TexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
                     GLint zOffset, GLsizei width, GLsizei height,
                     GLsizei depth, GLenum unpackFormat, GLenum unpackType,
                     const TexImageSource& src) {
    const char funcName[] = "texSubImage3D";
    const uint8_t funcDims = 3;
    TexSubImage(funcName, funcDims, target, level, xOffset, yOffset, zOffset,
                width, height, depth, unpackFormat, unpackType, src);
  }

 public:
  // -------------------------------------------------------------------------
  // Programs and shaders - WebGL2ContextPrograms.cpp
  GLint GetFragDataLocation(const WebGLProgram& program, const nsAString& name);

  // -------------------------------------------------------------------------
  // Uniforms and attributes - WebGL2ContextUniforms.cpp

  void VertexAttribIPointer(GLuint index, GLint size, GLenum type,
                            GLsizei stride, WebGLintptr byteOffset) {
    const char funcName[] = "vertexAttribIPointer";
    const bool isFuncInt = true;
    const bool normalized = false;
    VertexAttribAnyPointer(funcName, isFuncInt, index, size, type, normalized,
                           stride, byteOffset);
  }

  ////////////////

  // GL 3.0 & ES 3.0
  void VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w,
                       const char* funcName = nullptr);
  void VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w,
                        const char* funcName = nullptr);

  void VertexAttribI4iv(GLuint index, const Int32ListU& list) {
    const auto& arr = Int32Arr::From(list);
    if (!ValidateAttribArraySetter("vertexAttribI4iv", 4, arr.elemCount))
      return;

    const auto& itr = arr.elemBytes;
    VertexAttribI4i(index, itr[0], itr[1], itr[2], itr[3]);
  }

  void VertexAttribI4uiv(GLuint index, const Uint32ListU& list) {
    const auto& arr = Uint32Arr::From(list);
    if (!ValidateAttribArraySetter("vertexAttribI4uiv", 4, arr.elemCount))
      return;

    const auto& itr = arr.elemBytes;
    VertexAttribI4ui(index, itr[0], itr[1], itr[2], itr[3]);
  }

  // -------------------------------------------------------------------------
  // Writing to the drawing buffer

  /* Implemented in WebGLContext
  void VertexAttribDivisor(GLuint index, GLuint divisor);
  void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count,
                           GLsizei instanceCount);
  void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
                             GLintptr offset, GLsizei instanceCount);
  */

  void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count,
                         GLenum type, WebGLintptr byteOffset) {
    const char funcName[] = "drawRangeElements";
    if (IsContextLost()) return;

    if (end < start) {
      ErrorInvalidValue("%s: end must be >= start.", funcName);
      return;
    }

    DrawElements(mode, count, type, byteOffset, funcName);
  }

  // ------------------------------------------------------------------------
  // Multiple Render Targets - WebGL2ContextMRTs.cpp
  /* Implemented in WebGLContext
  void DrawBuffers(const dom::Sequence<GLenum>& buffers);
  */

 private:
  bool ValidateClearBuffer(const char* funcName, GLenum buffer,
                           GLint drawBuffer, size_t availElemCount,
                           GLuint elemOffset, GLenum funcType);

  void ClearBufferfv(GLenum buffer, GLint drawBuffer, const Float32Arr& src,
                     GLuint srcElemOffset);
  void ClearBufferiv(GLenum buffer, GLint drawBuffer, const Int32Arr& src,
                     GLuint srcElemOffset);
  void ClearBufferuiv(GLenum buffer, GLint drawBuffer, const Uint32Arr& src,
                      GLuint srcElemOffset);

 public:
  void ClearBufferfv(GLenum buffer, GLint drawBuffer, const Float32ListU& list,
                     GLuint srcElemOffset) {
    ClearBufferfv(buffer, drawBuffer, Float32Arr::From(list), srcElemOffset);
  }
  void ClearBufferiv(GLenum buffer, GLint drawBuffer, const Int32ListU& list,
                     GLuint srcElemOffset) {
    ClearBufferiv(buffer, drawBuffer, Int32Arr::From(list), srcElemOffset);
  }
  void ClearBufferuiv(GLenum buffer, GLint drawBuffer, const Uint32ListU& list,
                      GLuint srcElemOffset) {
    ClearBufferuiv(buffer, drawBuffer, Uint32Arr::From(list), srcElemOffset);
  }

  void ClearBufferfi(GLenum buffer, GLint drawBuffer, GLfloat depth,
                     GLint stencil);

  // -------------------------------------------------------------------------
  // Sampler Objects - WebGL2ContextSamplers.cpp

  already_AddRefed<WebGLSampler> CreateSampler();
  void DeleteSampler(WebGLSampler* sampler);
  bool IsSampler(const WebGLSampler* sampler);
  void BindSampler(GLuint unit, WebGLSampler* sampler);
  void SamplerParameteri(WebGLSampler& sampler, GLenum pname, GLint param);
  void SamplerParameterf(WebGLSampler& sampler, GLenum pname, GLfloat param);
  void GetSamplerParameter(JSContext*, const WebGLSampler& sampler,
                           GLenum pname, JS::MutableHandleValue retval);

  // -------------------------------------------------------------------------
  // Sync objects - WebGL2ContextSync.cpp

  const GLuint64 kMaxClientWaitSyncTimeoutNS =
      1000 * 1000 * 1000;  // 1000ms in ns.

  already_AddRefed<WebGLSync> FenceSync(GLenum condition, GLbitfield flags);
  bool IsSync(const WebGLSync* sync);
  void DeleteSync(WebGLSync* sync);
  GLenum ClientWaitSync(const WebGLSync& sync, GLbitfield flags,
                        GLuint64 timeout);
  void WaitSync(const WebGLSync& sync, GLbitfield flags, GLint64 timeout);
  void GetSyncParameter(JSContext*, const WebGLSync& sync, GLenum pname,
                        JS::MutableHandleValue retval);

  // -------------------------------------------------------------------------
  // Transform Feedback - WebGL2ContextTransformFeedback.cpp

  already_AddRefed<WebGLTransformFeedback> CreateTransformFeedback();
  void DeleteTransformFeedback(WebGLTransformFeedback* tf);
  bool IsTransformFeedback(const WebGLTransformFeedback* tf);
  void BindTransformFeedback(GLenum target, WebGLTransformFeedback* tf);
  void BeginTransformFeedback(GLenum primitiveMode);
  void EndTransformFeedback();
  void PauseTransformFeedback();
  void ResumeTransformFeedback();
  void TransformFeedbackVaryings(WebGLProgram& program,
                                 const dom::Sequence<nsString>& varyings,
                                 GLenum bufferMode);
  already_AddRefed<WebGLActiveInfo> GetTransformFeedbackVarying(
      const WebGLProgram& program, GLuint index);

  // -------------------------------------------------------------------------
  // Uniform Buffer Objects and Transform Feedback Buffers -
  // WebGL2ContextUniforms.cpp
  // TODO(djg): Implemented in WebGLContext
  /*
      void BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer);
      void BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer,
                           GLintptr offset, GLsizeiptr size);
  */
  virtual JS::Value GetParameter(JSContext* cx, GLenum pname,
                                 ErrorResult& rv) override;
  // Make the inline version from the superclass visible here.
  using WebGLContext::GetParameter;
  void GetIndexedParameter(JSContext* cx, GLenum target, GLuint index,
                           JS::MutableHandleValue retval, ErrorResult& rv);
  void GetUniformIndices(const WebGLProgram& program,
                         const dom::Sequence<nsString>& uniformNames,
                         dom::Nullable<nsTArray<GLuint> >& retval);
  void GetActiveUniforms(JSContext* cx, const WebGLProgram& program,
                         const dom::Sequence<GLuint>& uniformIndices,
                         GLenum pname, JS::MutableHandleValue retval);

  GLuint GetUniformBlockIndex(const WebGLProgram& program,
                              const nsAString& uniformBlockName);
  void GetActiveUniformBlockParameter(JSContext*, const WebGLProgram& program,
                                      GLuint uniformBlockIndex, GLenum pname,
                                      JS::MutableHandleValue retval,
                                      ErrorResult& rv);
  void GetActiveUniformBlockName(const WebGLProgram& program,
                                 GLuint uniformBlockIndex, nsAString& retval);
  void UniformBlockBinding(WebGLProgram& program, GLuint uniformBlockIndex,
                           GLuint uniformBlockBinding);

  // -------------------------------------------------------------------------
  // Vertex Array Object - WebGL2ContextVAOs.cpp
  // TODO(djg): Implemented in WebGLContext
  /*
      already_AddRefed<WebGLVertexArrayObject> CreateVertexArray();
      void DeleteVertexArray(WebGLVertexArrayObject* vertexArray);
      bool IsVertexArray(WebGLVertexArrayObject* vertexArray);
      void BindVertexArray(WebGLVertexArrayObject* vertexArray);
  */

 private:
  WebGL2Context();
  virtual UniquePtr<webgl::FormatUsageAuthority> CreateFormatUsage(
      gl::GLContext* gl) const override;

  virtual bool IsTexParamValid(GLenum pname) const override;

  void UpdateBoundQuery(GLenum target, WebGLQuery* query);

  // CreateVertexArrayImpl is assumed to be infallible.
  virtual WebGLVertexArray* CreateVertexArrayImpl() override;
};

}  // namespace mozilla

#endif