Implement swizzling for L/A/LA.
draft
Implement swizzling for L/A/LA.
--- a/dom/canvas/TexUnpackBlob.cpp
+++ b/dom/canvas/TexUnpackBlob.cpp
@@ -653,17 +653,17 @@ TexUnpackSurface::ConvertSurface(WebGLCo
checkedDstSize *= height;
if (!checkedDstSize.isValid()) {
*out_outOfMemory = true;
return false;
}
const size_t dstSize = checkedDstSize.value();
- UniqueBuffer dstBuffer(malloc(dstSize));
+ UniqueBuffer dstBuffer = malloc(dstSize);
if (!dstBuffer) {
*out_outOfMemory = true;
return false;
}
void* const dstBegin = dstBuffer.get();
gl::OriginPos srcOrigin, dstOrigin;
OriginsForDOM(webgl, &srcOrigin, &dstOrigin);
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -119,18 +119,16 @@ WebGLContext::WebGLContext()
mFakeVertexAttrib0BufferObjectVector[0] = 0;
mFakeVertexAttrib0BufferObjectVector[1] = 0;
mFakeVertexAttrib0BufferObjectVector[2] = 0;
mFakeVertexAttrib0BufferObjectVector[3] = 1;
mFakeVertexAttrib0BufferObjectSize = 0;
mFakeVertexAttrib0BufferObject = 0;
mFakeVertexAttrib0BufferStatus = WebGLVertexAttrib0Status::Default;
- mCanSkipFakeBlack = false;
-
mViewportX = 0;
mViewportY = 0;
mViewportWidth = 0;
mViewportHeight = 0;
mDitherEnabled = 1;
mRasterizerDiscardEnabled = 0; // OpenGL ES 3.0 spec p244
mScissorTestEnabled = 0;
@@ -235,20 +233,24 @@ WebGLContext::DestroyResourcesAndContext
mPrograms.getLast()->DeleteOnce();
while (!mQueries.isEmpty())
mQueries.getLast()->DeleteOnce();
while (!mSamplers.isEmpty())
mSamplers.getLast()->DeleteOnce();
while (!mTransformFeedbacks.isEmpty())
mTransformFeedbacks.getLast()->DeleteOnce();
- mFakeBlack_2D_Opaque = nullptr;
- mFakeBlack_2D_Alpha = nullptr;
- mFakeBlack_CubeMap_Opaque = nullptr;
- mFakeBlack_CubeMap_Alpha = nullptr;
+ mFakeBlack_2D_0000 = nullptr;
+ mFakeBlack_2D_0001 = nullptr;
+ mFakeBlack_CubeMap_0000 = nullptr;
+ mFakeBlack_CubeMap_0001 = nullptr;
+ mFakeBlack_3D_0000 = nullptr;
+ mFakeBlack_3D_0001 = nullptr;
+ mFakeBlack_2D_Array_0000 = nullptr;
+ mFakeBlack_2D_Array_0001 = nullptr;
if (mFakeVertexAttrib0BufferObject)
gl->fDeleteBuffers(1, &mFakeVertexAttrib0BufferObject);
// disable all extensions except "WEBGL_lose_context". see bug #927969
// spec: http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
for (size_t i = 0; i < size_t(WebGLExtensionID::Max); ++i) {
WebGLExtensionID extension = WebGLExtensionID(i);
@@ -1975,17 +1977,17 @@ ZeroTextureData(WebGLContext* webgl, con
checkedByteCount *= heightBlocks;
checkedByteCount *= depth;
if (!checkedByteCount.isValid())
return false;
const size_t byteCount = checkedByteCount.value();
- UniqueBuffer zeros(calloc(1, byteCount));
+ UniqueBuffer zeros = calloc(1, byteCount);
if (!zeros)
return false;
GLenum error = DoCompressedTexSubImage(gl, target.get(), level, xOffset, yOffset,
zOffset, width, height, depth, sizedFormat,
byteCount, zeros.get());
if (error)
return false;
@@ -2007,17 +2009,17 @@ ZeroTextureData(WebGLContext* webgl, con
checkedByteCount *= height;
checkedByteCount *= depth;
if (!checkedByteCount.isValid())
return false;
const size_t byteCount = checkedByteCount.value();
- UniqueBuffer zeros(calloc(1, byteCount));
+ UniqueBuffer zeros = calloc(1, byteCount);
if (!zeros)
return false;
GLenum error;
if (respecifyTexture) {
MOZ_RELEASE_ASSERT(!xOffset && !yOffset && !zOffset);
const auto internalFormat = driverUnpackInfo->internalFormat;
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -82,17 +82,18 @@ class nsIDocShell;
#define LOCAL_GL_BROWSER_DEFAULT_WEBGL 0x9244
#define LOCAL_GL_CONTEXT_LOST_WEBGL 0x9242
#define LOCAL_GL_MAX_CLIENT_WAIT_TIMEOUT_WEBGL 0x9247
#define LOCAL_GL_UNPACK_COLORSPACE_CONVERSION_WEBGL 0x9243
#define LOCAL_GL_UNPACK_FLIP_Y_WEBGL 0x9240
#define LOCAL_GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL 0x9241
namespace mozilla {
-
+class ScopedCopyTexImageSource;
+class ScopedResolveTexturesForDraw;
class ScopedUnpackReset;
class WebGLActiveInfo;
class WebGLContextLossHandler;
class WebGLBuffer;
class WebGLExtensionBase;
class WebGLFramebuffer;
class WebGLProgram;
class WebGLQuery;
@@ -1038,17 +1039,17 @@ private:
uint32_t mMaxFetchedInstances;
bool DrawArrays_check(GLint first, GLsizei count, GLsizei primcount,
const char* info);
bool DrawElements_check(GLsizei count, GLenum type, WebGLintptr byteOffset,
GLsizei primcount, const char* info,
GLuint* out_upperBound);
bool DrawInstanced_check(const char* info);
- void Draw_cleanup();
+ void Draw_cleanup(const char* funcName);
void VertexAttrib1fv_base(GLuint index, uint32_t arrayLength,
const GLfloat* ptr);
void VertexAttrib2fv_base(GLuint index, uint32_t arrayLength,
const GLfloat* ptr);
void VertexAttrib3fv_base(GLuint index, uint32_t arrayLength,
const GLfloat* ptr);
void VertexAttrib4fv_base(GLuint index, uint32_t arrayLength,
@@ -1418,40 +1419,38 @@ protected:
CheckedUint32 GetPackSize(uint32_t width, uint32_t height, uint8_t bytesPerPixel,
CheckedUint32* const out_startOffset,
CheckedUint32* const out_rowStride);
GLenum mPixelStore_ColorspaceConversion;
bool mPixelStore_FlipY;
bool mPixelStore_PremultiplyAlpha;
-public:
- // Fake-black
+ ////////////////////////////////////
class FakeBlackTexture {
+ public:
gl::GLContext* const mGL;
- GLuint mGLName;
+ const GLuint mGLName;
- public:
- FakeBlackTexture(gl::GLContext* gl, TexTarget target, GLenum format);
+ FakeBlackTexture(gl::GLContext* gl, TexTarget target, FakeBlackType type);
~FakeBlackTexture();
- GLuint GLName() const { return mGLName; }
};
- void InvalidateFakeBlackCache() { mCanSkipFakeBlack = false; }
-
-protected:
- bool mCanSkipFakeBlack;
+ UniquePtr<FakeBlackTexture> mFakeBlack_2D_0000;
+ UniquePtr<FakeBlackTexture> mFakeBlack_2D_0001;
+ UniquePtr<FakeBlackTexture> mFakeBlack_CubeMap_0000;
+ UniquePtr<FakeBlackTexture> mFakeBlack_CubeMap_0001;
+ UniquePtr<FakeBlackTexture> mFakeBlack_3D_0000;
+ UniquePtr<FakeBlackTexture> mFakeBlack_3D_0001;
+ UniquePtr<FakeBlackTexture> mFakeBlack_2D_Array_0000;
+ UniquePtr<FakeBlackTexture> mFakeBlack_2D_Array_0001;
- UniquePtr<FakeBlackTexture> mFakeBlack_2D_Opaque;
- UniquePtr<FakeBlackTexture> mFakeBlack_2D_Alpha;
- UniquePtr<FakeBlackTexture> mFakeBlack_CubeMap_Opaque;
- UniquePtr<FakeBlackTexture> mFakeBlack_CubeMap_Alpha;
+ void BindFakeBlack(uint32_t texUnit, TexTarget target, FakeBlackType fakeBlack);
- bool BindFakeBlackTextures(const char* funcName);
- void UnbindFakeBlackTextures();
+ ////////////////////////////////////
// Generic Vertex Attributes
UniquePtr<GLenum[]> mVertexAttribType;
GLfloat mVertexAttrib0Vector[4];
GLfloat mFakeVertexAttrib0BufferObjectVector[4];
size_t mFakeVertexAttrib0BufferObjectSize;
GLuint mFakeVertexAttrib0BufferObject;
WebGLVertexAttrib0Status mFakeVertexAttrib0BufferStatus;
@@ -1562,16 +1561,18 @@ public:
public:
UniquePtr<webgl::FormatUsageAuthority> mFormatUsage;
virtual UniquePtr<webgl::FormatUsageAuthority>
CreateFormatUsage(gl::GLContext* gl) const = 0;
// Friend list
+ friend class ScopedCopyTexImageSource;
+ friend class ScopedResolveTexturesForDraw;
friend class ScopedUnpackReset;
friend class webgl::TexUnpackBytes;
friend class webgl::TexUnpackSurface;
friend class WebGLTexture;
friend class WebGLFramebuffer;
friend class WebGLRenderbuffer;
friend class WebGLProgram;
friend class WebGLQuery;
@@ -1686,17 +1687,17 @@ class UniqueBuffer
// Like UniquePtr<>, but for void* and malloc/calloc/free.
void* mBuffer;
public:
UniqueBuffer()
: mBuffer(nullptr)
{ }
- explicit UniqueBuffer(void* buffer)
+ UniqueBuffer(void* buffer)
: mBuffer(buffer)
{ }
~UniqueBuffer() {
free(mBuffer);
}
UniqueBuffer(UniqueBuffer&& other) {
--- a/dom/canvas/WebGLContextDraw.cpp
+++ b/dom/canvas/WebGLContextDraw.cpp
@@ -18,16 +18,138 @@
#include "WebGLVertexArray.h"
#include "WebGLVertexAttribData.h"
namespace mozilla {
// For a Tegra workaround.
static const int MAX_DRAW_CALLS_SINCE_FLUSH = 100;
+////////////////////////////////////////
+
+class ScopedResolveTexturesForDraw
+{
+ struct TexRebindRequest
+ {
+ const uint32_t texUnit;
+ WebGLTexture* const tex;
+ };
+
+ WebGLContext* const mWebGL;
+ std::vector<TexRebindRequest> mRebindRequests;
+
+public:
+ ScopedResolveTexturesForDraw(WebGLContext* webgl, const char* funcName,
+ bool* const out_error);
+ ~ScopedResolveTexturesForDraw();
+};
+
+ScopedResolveTexturesForDraw::ScopedResolveTexturesForDraw(WebGLContext* webgl,
+ const char* funcName,
+ bool* const out_error)
+ : mWebGL(webgl)
+{
+ //typedef nsTArray<WebGLRefPtr<WebGLTexture>> TexturesT;
+ typedef decltype(WebGLContext::mBound2DTextures) TexturesT;
+
+ const auto fnResolveAll = [this, funcName, out_error](const TexturesT& textures)
+ {
+ const auto len = textures.Length();
+ for (uint32_t texUnit = 0; texUnit < len; ++texUnit) {
+ WebGLTexture* tex = textures[texUnit];
+ if (!tex)
+ continue;
+
+ FakeBlackType fakeBlack;
+ *out_error |= !tex->ResolveForDraw(funcName, texUnit, &fakeBlack);
+
+ if (fakeBlack == FakeBlackType::None)
+ continue;
+
+ mWebGL->BindFakeBlack(texUnit, tex->Target(), fakeBlack);
+ mRebindRequests.push_back({texUnit, tex});
+ }
+ };
+
+ *out_error = false;
+
+ fnResolveAll(mWebGL->mBound2DTextures);
+ fnResolveAll(mWebGL->mBoundCubeMapTextures);
+ fnResolveAll(mWebGL->mBound3DTextures);
+ fnResolveAll(mWebGL->mBound2DArrayTextures);
+
+ if (*out_error) {
+ mWebGL->ErrorOutOfMemory("%s: Failed to resolve textures for draw.", funcName);
+ }
+}
+
+ScopedResolveTexturesForDraw::~ScopedResolveTexturesForDraw()
+{
+ if (!mRebindRequests.size())
+ return;
+
+ gl::GLContext* gl = mWebGL->gl;
+
+ for (const auto& itr : mRebindRequests) {
+ gl->fActiveTexture(LOCAL_GL_TEXTURE0 + itr.texUnit);
+ gl->fBindTexture(itr.tex->Target().get(), itr.tex->mGLName);
+ }
+
+ gl->fActiveTexture(LOCAL_GL_TEXTURE0 + mWebGL->mActiveTexture);
+}
+
+void
+WebGLContext::BindFakeBlack(uint32_t texUnit, TexTarget target, FakeBlackType fakeBlack)
+{
+ MOZ_ASSERT(fakeBlack == FakeBlackType::RGBA0000 ||
+ fakeBlack == FakeBlackType::RGBA0001);
+
+ const auto fnGetSlot = [this, target, fakeBlack]() -> UniquePtr<FakeBlackTexture>*
+ {
+ switch (fakeBlack) {
+ case FakeBlackType::RGBA0000:
+ switch (target.get()) {
+ case LOCAL_GL_TEXTURE_2D : return &mFakeBlack_2D_0000;
+ case LOCAL_GL_TEXTURE_CUBE_MAP: return &mFakeBlack_CubeMap_0000;
+ case LOCAL_GL_TEXTURE_3D : return &mFakeBlack_3D_0000;
+ case LOCAL_GL_TEXTURE_2D_ARRAY: return &mFakeBlack_2D_Array_0000;
+ default: return nullptr;
+ }
+
+ case FakeBlackType::RGBA0001:
+ switch (target.get()) {
+ case LOCAL_GL_TEXTURE_2D : return &mFakeBlack_2D_0001;
+ case LOCAL_GL_TEXTURE_CUBE_MAP: return &mFakeBlack_CubeMap_0001;
+ case LOCAL_GL_TEXTURE_3D : return &mFakeBlack_3D_0001;
+ case LOCAL_GL_TEXTURE_2D_ARRAY: return &mFakeBlack_2D_Array_0001;
+ default: return nullptr;
+ }
+
+ default:
+ return nullptr;
+ }
+ };
+
+ UniquePtr<FakeBlackTexture>* slot = fnGetSlot();
+ if (!slot) {
+ MOZ_CRASH("fnGetSlot failed.");
+ }
+ UniquePtr<FakeBlackTexture>& fakeBlackTex = *slot;
+
+ if (!fakeBlackTex) {
+ fakeBlackTex.reset(new FakeBlackTexture(gl, target, fakeBlack));
+ }
+
+ gl->fActiveTexture(LOCAL_GL_TEXTURE0 + texUnit);
+ gl->fBindTexture(target.get(), fakeBlackTex->mGLName);
+ gl->fActiveTexture(LOCAL_GL_TEXTURE0 + mActiveTexture);
+}
+
+////////////////////////////////////////
+
bool
WebGLContext::DrawInstanced_check(const char* info)
{
if ((IsWebGL2() ||
IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays)) &&
!mBufferFetchingHasPerVertex)
{
/* http://www.khronos.org/registry/gles/extensions/ANGLE/ANGLE_instanced_arrays.txt
@@ -110,64 +232,73 @@ WebGLContext::DrawArrays_check(GLint fir
if (!DoFakeVertexAttrib0(checked_firstPlusCount.value())) {
return false;
}
if (!DrawInstanced_check(info)) {
return false;
}
- if (!BindFakeBlackTextures(info))
- return false;
-
return true;
}
void
WebGLContext::DrawArrays(GLenum mode, GLint first, GLsizei count)
{
+ const char funcName[] = "drawArrays";
if (IsContextLost())
return;
- if (!ValidateDrawModeEnum(mode, "drawArrays: mode"))
+ if (!ValidateDrawModeEnum(mode, funcName))
return;
- if (!DrawArrays_check(first, count, 1, "drawArrays"))
+ bool error;
+ ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
+ if (error)
+ return;
+
+ if (!DrawArrays_check(first, count, 1, funcName))
return;
RunContextLossTimer();
{
ScopedMaskWorkaround autoMask(*this);
gl->fDrawArrays(mode, first, count);
}
- Draw_cleanup();
+ Draw_cleanup(funcName);
}
void
WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount)
{
+ const char funcName[] = "drawArraysInstanced";
if (IsContextLost())
return;
- if (!ValidateDrawModeEnum(mode, "drawArraysInstanced: mode"))
+ if (!ValidateDrawModeEnum(mode, funcName))
return;
- if (!DrawArrays_check(first, count, primcount, "drawArraysInstanced"))
+ bool error;
+ ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
+ if (error)
+ return;
+
+ if (!DrawArrays_check(first, count, primcount, funcName))
return;
RunContextLossTimer();
{
ScopedMaskWorkaround autoMask(*this);
gl->fDrawArraysInstanced(mode, first, count, primcount);
}
- Draw_cleanup();
+ Draw_cleanup(funcName);
}
bool
WebGLContext::DrawElements_check(GLsizei count, GLenum type,
WebGLintptr byteOffset, GLsizei primcount,
const char* info, GLuint* out_upperBound)
{
if (count < 0 || byteOffset < 0) {
@@ -292,89 +423,91 @@ WebGLContext::DrawElements_check(GLsizei
if (!DoFakeVertexAttrib0(mMaxFetchedVertices)) {
return false;
}
if (!DrawInstanced_check(info)) {
return false;
}
- if (!BindFakeBlackTextures(info))
- return false;
-
return true;
}
void
WebGLContext::DrawElements(GLenum mode, GLsizei count, GLenum type,
WebGLintptr byteOffset)
{
+ const char funcName[] = "drawElements";
if (IsContextLost())
return;
- if (!ValidateDrawModeEnum(mode, "drawElements: mode"))
+ if (!ValidateDrawModeEnum(mode, funcName))
+ return;
+
+ bool error;
+ ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
+ if (error)
return;
GLuint upperBound = 0;
- if (!DrawElements_check(count, type, byteOffset, 1, "drawElements",
- &upperBound))
- {
+ if (!DrawElements_check(count, type, byteOffset, 1, funcName, &upperBound))
return;
- }
RunContextLossTimer();
{
ScopedMaskWorkaround autoMask(*this);
if (gl->IsSupported(gl::GLFeature::draw_range_elements)) {
gl->fDrawRangeElements(mode, 0, upperBound, count, type,
reinterpret_cast<GLvoid*>(byteOffset));
} else {
gl->fDrawElements(mode, count, type,
reinterpret_cast<GLvoid*>(byteOffset));
}
}
- Draw_cleanup();
+ Draw_cleanup(funcName);
}
void
WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
WebGLintptr byteOffset, GLsizei primcount)
{
+ const char funcName[] = "drawElementsInstanced";
if (IsContextLost())
return;
- if (!ValidateDrawModeEnum(mode, "drawElementsInstanced: mode"))
+ if (!ValidateDrawModeEnum(mode, funcName))
+ return;
+
+ bool error;
+ ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
+ if (error)
return;
GLuint upperBound = 0;
- if (!DrawElements_check(count, type, byteOffset, primcount,
- "drawElementsInstanced", &upperBound))
- {
+ if (!DrawElements_check(count, type, byteOffset, primcount, funcName, &upperBound))
return;
- }
RunContextLossTimer();
{
ScopedMaskWorkaround autoMask(*this);
gl->fDrawElementsInstanced(mode, count, type,
reinterpret_cast<GLvoid*>(byteOffset),
primcount);
}
- Draw_cleanup();
+ Draw_cleanup(funcName);
}
-void WebGLContext::Draw_cleanup()
+void WebGLContext::Draw_cleanup(const char* funcName)
{
UndoFakeVertexAttrib0();
- UnbindFakeBlackTextures();
if (!mBoundDrawFramebuffer) {
Invalidate();
mShouldPresent = true;
MOZ_ASSERT(!mBackbufferNeedsClear);
}
if (gl->WorkAroundDriverBugs()) {
@@ -402,18 +535,19 @@ void WebGLContext::Draw_cleanup()
destWidth = mWidth;
destHeight = mHeight;
}
if (mViewportWidth > int32_t(destWidth) ||
mViewportHeight > int32_t(destHeight))
{
if (!mAlreadyWarnedAboutViewportLargerThanDest) {
- GenerateWarning("Drawing to a destination rect smaller than the viewport rect. "
- "(This warning will only be given once)");
+ GenerateWarning("%s: Drawing to a destination rect smaller than the viewport"
+ " rect. (This warning will only be given once)",
+ funcName);
mAlreadyWarnedAboutViewportLargerThanDest = true;
}
}
}
/*
* Verify that state is consistent for drawing, and compute max number of elements (maxAllowedCount)
* that will be legal to be read from bound VBOs.
@@ -654,184 +788,64 @@ WebGLContext::UndoFakeVertexAttrib0()
}
} else {
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
}
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->mGLName : 0);
}
-static bool
-BindFakeBlackHelper(const char* funcName, gl::GLContext* gl, TexTarget target,
- const nsTArray<WebGLRefPtr<WebGLTexture>>& texArray,
- WebGLContext::FakeBlackTexture* opaqueTex,
- WebGLContext::FakeBlackTexture* alphaTex, bool* const out_wasNeeded)
+static GLuint
+CreateGLTexture(gl::GLContext* gl)
{
- MOZ_ASSERT(opaqueTex && alphaTex);
-
- *out_wasNeeded = false;
-
- int32_t len = texArray.Length();
- for (int32_t i = 0; i < len; i++) {
- WebGLTexture* tex = texArray[i];
- if (!tex)
- continue;
-
- WebGLTextureFakeBlackStatus status;
- if (!tex->ResolveFakeBlackStatus(funcName, &status))
- return false; // World is currently exploding...
-
- MOZ_ASSERT(status != WebGLTextureFakeBlackStatus::Unknown);
-
- if (MOZ_LIKELY(status == WebGLTextureFakeBlackStatus::NotNeeded))
- continue;
-
- // Ok, needs fake-black.
- *out_wasNeeded = true;
-
- // Default to (0, 0, 0, 1) for incomplete textures, as well as uninit'd alpha-less
- // formats.
- WebGLContext::FakeBlackTexture* fakeTex = opaqueTex;
-
- if (status == WebGLTextureFakeBlackStatus::UninitializedImageData) {
- const auto& imageInfo = tex->BaseImageInfo();
- if (imageInfo.mFormat->format->hasAlpha) {
- fakeTex = alphaTex;
- }
- }
-
- gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
- gl->fBindTexture(target.get(), fakeTex->GLName());
- }
-
- return true;
-}
-
-static bool
-UnbindFakeBlackHelper(gl::GLContext* gl, TexTarget target,
- const nsTArray<WebGLRefPtr<WebGLTexture>>& texArray)
-{
- bool changedActiveTex = false;
-
- const int32_t len = texArray.Length();
- for (int32_t i = 0; i < len; i++) {
- WebGLTexture* tex = texArray[i];
- if (!tex)
- continue;
-
- auto status = tex->FakeBlackStatus();
- MOZ_ASSERT(status != WebGLTextureFakeBlackStatus::Unknown);
- if (MOZ_LIKELY(status == WebGLTextureFakeBlackStatus::NotNeeded))
- continue;
-
- gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
- changedActiveTex = true;
-
- gl->fBindTexture(target.get(), tex->mGLName);
- }
-
- return changedActiveTex;
+ MOZ_ASSERT(gl->IsCurrent());
+ GLuint ret = 0;
+ gl->fGenTextures(1, &ret);
+ return ret;
}
-bool
-WebGLContext::BindFakeBlackTextures(const char* funcName)
+WebGLContext::FakeBlackTexture::FakeBlackTexture(gl::GLContext* gl, TexTarget target,
+ FakeBlackType type)
+ : mGL(gl)
+ , mGLName(CreateGLTexture(gl))
{
- if (mCanSkipFakeBlack)
- return true;
+ GLenum texFormat;
+ switch (type) {
+ case FakeBlackType::RGBA0000:
+ texFormat = LOCAL_GL_RGBA;
+ break;
- if (!mFakeBlack_2D_Opaque) {
- typedef FakeBlackTexture T;
+ case FakeBlackType::RGBA0001:
+ texFormat = LOCAL_GL_RGB;
+ break;
- mFakeBlack_2D_Opaque = MakeUnique<T>(gl, LOCAL_GL_TEXTURE_2D, LOCAL_GL_RGB);
- mFakeBlack_2D_Alpha = MakeUnique<T>(gl, LOCAL_GL_TEXTURE_2D, LOCAL_GL_RGBA);
-
- mFakeBlack_CubeMap_Opaque = MakeUnique<T>(gl, LOCAL_GL_TEXTURE_CUBE_MAP,
- LOCAL_GL_RGB);
- mFakeBlack_CubeMap_Alpha = MakeUnique<T>(gl, LOCAL_GL_TEXTURE_CUBE_MAP,
- LOCAL_GL_RGBA);
+ default:
+ MOZ_CRASH("bad type");
}
- bool wasEverNeeded = false;
- bool wasNeeded;
-
- if (!BindFakeBlackHelper(funcName, gl, LOCAL_GL_TEXTURE_2D, mBound2DTextures,
- mFakeBlack_2D_Opaque.get(), mFakeBlack_2D_Alpha.get(),
- &wasNeeded))
- {
- goto FAIL;
- }
- wasEverNeeded |= wasNeeded;
+ gl::ScopedBindTexture scopedBind(mGL, mGLName, target.get());
- if (!BindFakeBlackHelper(funcName, gl, LOCAL_GL_TEXTURE_CUBE_MAP,
- mBoundCubeMapTextures, mFakeBlack_CubeMap_Opaque.get(),
- mFakeBlack_CubeMap_Alpha.get(), &wasNeeded))
- {
- goto FAIL;
- }
- wasEverNeeded |= wasNeeded;
-
- mCanSkipFakeBlack = !wasEverNeeded;
- return true;
-
-FAIL:
- ErrorOutOfMemory("%s: Failed to bind fake-black textures.");
- return false;
-}
-
-void
-WebGLContext::UnbindFakeBlackTextures()
-{
- if (mCanSkipFakeBlack)
- return;
-
- bool changedActiveTex = false;
+ mGL->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST);
+ mGL->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST);
- changedActiveTex |= UnbindFakeBlackHelper(gl, LOCAL_GL_TEXTURE_2D, mBound2DTextures);
- changedActiveTex |= UnbindFakeBlackHelper(gl, LOCAL_GL_TEXTURE_CUBE_MAP,
- mBoundCubeMapTextures);
-
- if (changedActiveTex) {
- gl->fActiveTexture(LOCAL_GL_TEXTURE0 + mActiveTexture);
+ // We allocate our zeros on the heap, and we overallocate (16 bytes instead of 4) to
+ // minimize the risk of running into a driver bug in texImage2D, as it is a bit
+ // unusual maybe to create 1x1 textures, and the stack may not have the alignment that
+ // TexImage2D expects.
+ UniqueBuffer zeros = moz_xcalloc(1, 16);
+ if (target == LOCAL_GL_TEXTURE_CUBE_MAP) {
+ for (int i = 0; i < 6; ++i) {
+ DoTexImage(mGL, LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, texFormat, 1, 1,
+ 1, texFormat, LOCAL_GL_UNSIGNED_BYTE, zeros.get());
+ }
+ } else {
+ DoTexImage(mGL, target.get(), 0, texFormat, 1, 1, 1, texFormat,
+ LOCAL_GL_UNSIGNED_BYTE, zeros.get());
}
}
-WebGLContext::FakeBlackTexture::FakeBlackTexture(gl::GLContext* gl, TexTarget target, GLenum format)
- : mGL(gl)
- , mGLName(0)
-{
- MOZ_ASSERT(format == LOCAL_GL_RGB || format == LOCAL_GL_RGBA);
-
- mGL->MakeCurrent();
- GLuint formerBinding = 0;
- gl->GetUIntegerv(target == LOCAL_GL_TEXTURE_2D
- ? LOCAL_GL_TEXTURE_BINDING_2D
- : LOCAL_GL_TEXTURE_BINDING_CUBE_MAP,
- &formerBinding);
- gl->fGenTextures(1, &mGLName);
- gl->fBindTexture(target.get(), mGLName);
-
- // we allocate our zeros on the heap, and we overallocate (16 bytes instead of 4)
- // to minimize the risk of running into a driver bug in texImage2D, as it is
- // a bit unusual maybe to create 1x1 textures, and the stack may not have the alignment
- // that texImage2D expects.
- UniquePtr<uint8_t> zeros((uint8_t*)moz_xcalloc(1, 16));
- if (target == LOCAL_GL_TEXTURE_2D) {
- gl->fTexImage2D(target.get(), 0, format, 1, 1,
- 0, format, LOCAL_GL_UNSIGNED_BYTE, zeros.get());
- } else {
- for (GLuint i = 0; i < 6; ++i) {
- gl->fTexImage2D(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, format, 1, 1,
- 0, format, LOCAL_GL_UNSIGNED_BYTE, zeros.get());
- }
- }
-
- gl->fBindTexture(target.get(), formerBinding);
-}
-
WebGLContext::FakeBlackTexture::~FakeBlackTexture()
{
- if (mGL) {
- mGL->MakeCurrent();
- mGL->fDeleteTextures(1, &mGLName);
- }
+ mGL->MakeCurrent();
+ mGL->fDeleteTextures(1, &mGLName);
}
} // namespace mozilla
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -1335,17 +1335,17 @@ WebGLContext::DoReadPixelsAndConvert(GLi
CheckedUint32 destStride;
const CheckedUint32 destSize = GetPackSize(width, height, destBytesPerPixel,
&destOffset, &destStride);
if (!readSize.isValid() || !destSize.isValid()) {
ErrorOutOfMemory("readPixels: Overflow calculating sizes for conversion.");
return false;
}
- UniqueBuffer readBuffer(malloc(readSize.value()));
+ UniqueBuffer readBuffer = malloc(readSize.value());
if (!readBuffer) {
ErrorOutOfMemory("readPixels: Failed to alloc temp buffer for conversion.");
return false;
}
gl::GLContext::LocalErrorScope errorScope(*gl);
gl->fReadPixels(x, y, width, height, readFormat, readType, readBuffer.get());
--- a/dom/canvas/WebGLExtensionTextureFloat.cpp
+++ b/dom/canvas/WebGLExtensionTextureFloat.cpp
@@ -10,49 +10,73 @@
#include "WebGLFormats.h"
namespace mozilla {
WebGLExtensionTextureFloat::WebGLExtensionTextureFloat(WebGLContext* webgl)
: WebGLExtensionBase(webgl)
{
auto& fua = webgl->mFormatUsage;
+ gl::GLContext* gl = webgl->GL();
webgl::PackingInfo pi;
webgl::DriverUnpackInfo dui;
+ const GLint* swizzle = nullptr;
- const auto fnAdd = [&fua, &pi, &dui](webgl::EffectiveFormat effFormat) {
+ const auto fnAdd = [&fua, &pi, &dui, &swizzle](webgl::EffectiveFormat effFormat) {
+ MOZ_ASSERT(!pi.type && !dui.unpackType);
+ pi.type = LOCAL_GL_FLOAT;
+ dui.unpackType = LOCAL_GL_FLOAT;
+
auto usage = fua->EditUsage(effFormat);
fua->AddUnsizedTexFormat(pi, usage);
usage->AddUnpack(pi, dui);
+
+ usage->textureSwizzleRGBA = swizzle;
};
- const bool isCore = webgl->GL()->IsCoreProfile();
+ const bool isCore = gl->IsCoreProfile();
- pi = {LOCAL_GL_RGBA, LOCAL_GL_FLOAT};
- dui = {LOCAL_GL_RGBA, LOCAL_GL_RGBA, LOCAL_GL_FLOAT};
+ pi = {LOCAL_GL_RGBA, 0};
+ dui = {pi.format, pi.format, pi.type};
fnAdd(webgl::EffectiveFormat::RGBA32F);
- pi = {LOCAL_GL_RGB, LOCAL_GL_FLOAT};
- dui = {LOCAL_GL_RGB, LOCAL_GL_RGB, LOCAL_GL_FLOAT};
+ pi = {LOCAL_GL_RGB, 0};
+ dui = {pi.format, pi.format, pi.type};
fnAdd(webgl::EffectiveFormat::RGB32F);
- pi = {LOCAL_GL_LUMINANCE, LOCAL_GL_FLOAT};
- if (isCore) dui = {LOCAL_GL_R32F, LOCAL_GL_RED, LOCAL_GL_FLOAT};
- else dui = {LOCAL_GL_LUMINANCE, LOCAL_GL_LUMINANCE, LOCAL_GL_FLOAT};
+ pi = {LOCAL_GL_LUMINANCE, 0};
+ if (isCore) {
+ dui = {LOCAL_GL_R32F, LOCAL_GL_RED, 0};
+ swizzle = webgl::FormatUsageInfo::kLuminanceSwizzleRGBA;
+ } else {
+ dui = {pi.format, pi.format, pi.type};
+ swizzle = nullptr;
+ }
fnAdd(webgl::EffectiveFormat::Luminance32F);
- pi = {LOCAL_GL_ALPHA, LOCAL_GL_FLOAT};
- if (isCore) dui = {LOCAL_GL_R32F, LOCAL_GL_RED, LOCAL_GL_FLOAT};
- else dui = {LOCAL_GL_ALPHA, LOCAL_GL_ALPHA, LOCAL_GL_FLOAT};
+ pi = {LOCAL_GL_ALPHA, 0};
+ if (isCore) {
+ dui = {LOCAL_GL_R32F, LOCAL_GL_RED, 0};
+ swizzle = webgl::FormatUsageInfo::kAlphaSwizzleRGBA;
+ } else {
+ dui = {pi.format, pi.format, pi.type};
+ swizzle = nullptr;
+ }
fnAdd(webgl::EffectiveFormat::Alpha32F);
- pi = {LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_FLOAT};
- if (isCore) dui = {LOCAL_GL_RG32F, LOCAL_GL_RG, LOCAL_GL_FLOAT};
- else dui = {LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_FLOAT};
+ pi = {LOCAL_GL_LUMINANCE_ALPHA, 0};
+ dui = {pi.format, pi.format, pi.type};
+ if (isCore) {
+ dui = {LOCAL_GL_RG32F, LOCAL_GL_RG, 0};
+ swizzle = webgl::FormatUsageInfo::kLumAlphaSwizzleRGBA;
+ } else {
+ dui = {pi.format, pi.format, pi.type};
+ swizzle = nullptr;
+ }
fnAdd(webgl::EffectiveFormat::Luminance32FAlpha32F);
}
WebGLExtensionTextureFloat::~WebGLExtensionTextureFloat()
{
}
IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionTextureFloat, OES_texture_float)
--- a/dom/canvas/WebGLExtensionTextureHalfFloat.cpp
+++ b/dom/canvas/WebGLExtensionTextureHalfFloat.cpp
@@ -10,55 +10,81 @@
#include "WebGLFormats.h"
namespace mozilla {
WebGLExtensionTextureHalfFloat::WebGLExtensionTextureHalfFloat(WebGLContext* webgl)
: WebGLExtensionBase(webgl)
{
auto& fua = webgl->mFormatUsage;
+ gl::GLContext* gl = webgl->GL();
webgl::PackingInfo pi;
webgl::DriverUnpackInfo dui;
-
- const auto fnAdd = [&fua, &pi, &dui](webgl::EffectiveFormat effFormat) {
- auto usage = fua->EditUsage(effFormat);
- fua->AddUnsizedTexFormat(pi, usage);
- usage->AddUnpack(pi, dui);
- };
+ const GLint* swizzle = nullptr;
GLenum driverUnpackType = LOCAL_GL_HALF_FLOAT;
- if (!webgl->GL()->IsSupported(gl::GLFeature::texture_half_float)) {
- MOZ_ASSERT(webgl->GL()->IsExtensionSupported(gl::GLContext::OES_texture_half_float));
+ if (!gl->IsSupported(gl::GLFeature::texture_half_float)) {
+ MOZ_ASSERT(gl->IsExtensionSupported(gl::GLContext::OES_texture_half_float));
driverUnpackType = LOCAL_GL_HALF_FLOAT_OES;
}
- const bool isCore = webgl->GL()->IsCoreProfile();
+ const auto fnAdd = [&fua, &pi, &dui, &swizzle,
+ driverUnpackType](webgl::EffectiveFormat effFormat)
+ {
+ MOZ_ASSERT(!pi.type && !dui.unpackType);
+ pi.type = LOCAL_GL_HALF_FLOAT_OES;
+ dui.unpackType = driverUnpackType;
- pi = {LOCAL_GL_RGBA, LOCAL_GL_HALF_FLOAT_OES};
- dui = {LOCAL_GL_RGBA, LOCAL_GL_RGBA, driverUnpackType};
+ auto usage = fua->EditUsage(effFormat);
+ fua->AddUnsizedTexFormat(pi, usage);
+ usage->AddUnpack(pi, dui);
+
+ usage->textureSwizzleRGBA = swizzle;
+ };
+
+ const bool isCore = gl->IsCoreProfile();
+
+ pi = {LOCAL_GL_RGBA, 0};
+ dui = {pi.format, pi.format, pi.type};
fnAdd(webgl::EffectiveFormat::RGBA16F);
- pi = {LOCAL_GL_RGB, LOCAL_GL_HALF_FLOAT_OES};
- dui = {LOCAL_GL_RGB, LOCAL_GL_RGB, driverUnpackType};
+ pi = {LOCAL_GL_RGB, 0};
+ dui = {pi.format, pi.format, pi.type};
fnAdd(webgl::EffectiveFormat::RGB16F);
- pi = {LOCAL_GL_LUMINANCE, LOCAL_GL_HALF_FLOAT_OES};
- if (isCore) dui = {LOCAL_GL_R16F, LOCAL_GL_RED, driverUnpackType};
- else dui = {LOCAL_GL_LUMINANCE, LOCAL_GL_LUMINANCE, driverUnpackType};
+ pi = {LOCAL_GL_LUMINANCE, 0};
+ if (isCore) {
+ dui = {LOCAL_GL_R16F, LOCAL_GL_RED, 0};
+ swizzle = webgl::FormatUsageInfo::kLuminanceSwizzleRGBA;
+ } else {
+ dui = {pi.format, pi.format, pi.type};
+ swizzle = nullptr;
+ }
fnAdd(webgl::EffectiveFormat::Luminance16F);
- pi = {LOCAL_GL_ALPHA, LOCAL_GL_HALF_FLOAT_OES};
- if (isCore) dui = {LOCAL_GL_R16F, LOCAL_GL_RED, driverUnpackType};
- else dui = {LOCAL_GL_ALPHA, LOCAL_GL_ALPHA, driverUnpackType};
+ pi = {LOCAL_GL_ALPHA, 0};
+ if (isCore) {
+ dui = {LOCAL_GL_R16F, LOCAL_GL_RED, 0};
+ swizzle = webgl::FormatUsageInfo::kAlphaSwizzleRGBA;
+ } else {
+ dui = {pi.format, pi.format, pi.type};
+ swizzle = nullptr;
+ }
fnAdd(webgl::EffectiveFormat::Alpha16F);
- pi = {LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_HALF_FLOAT_OES};
- if (isCore) dui = {LOCAL_GL_RG16F, LOCAL_GL_RG, driverUnpackType};
- else dui = {LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_LUMINANCE_ALPHA, driverUnpackType};
+ pi = {LOCAL_GL_LUMINANCE_ALPHA, 0};
+ dui = {pi.format, pi.format, pi.type};
+ if (isCore) {
+ dui = {LOCAL_GL_RG16F, LOCAL_GL_RG, 0};
+ swizzle = webgl::FormatUsageInfo::kLumAlphaSwizzleRGBA;
+ } else {
+ dui = {pi.format, pi.format, pi.type};
+ swizzle = nullptr;
+ }
fnAdd(webgl::EffectiveFormat::Luminance16FAlpha16F);
}
WebGLExtensionTextureHalfFloat::~WebGLExtensionTextureHalfFloat()
{
}
IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionTextureHalfFloat, OES_texture_half_float)
--- a/dom/canvas/WebGLFormats.cpp
+++ b/dom/canvas/WebGLFormats.cpp
@@ -448,67 +448,85 @@ SetUsage(FormatUsageAuthority* fua, Effe
MOZ_ASSERT(!fua->GetUsage(effFormat));
auto usage = fua->EditUsage(effFormat);
usage->isRenderable = isRenderable;
usage->isFilterable = isFilterable;
}
static void
+AddSimpleUnsized(FormatUsageAuthority* fua, GLenum unpackFormat, GLenum unpackType,
+ EffectiveFormat effFormat)
+{
+ auto usage = fua->EditUsage(effFormat);
+
+ const PackingInfo pi = {unpackFormat, unpackType};
+ fua->AddUnsizedTexFormat(pi, usage);
+
+ const DriverUnpackInfo dui = {unpackFormat, unpackFormat, unpackType};
+ usage->AddUnpack(pi, dui);
+};
+
+
+/*static*/ const GLint FormatUsageInfo::kLuminanceSwizzleRGBA[4] = { LOCAL_GL_RED,
+ LOCAL_GL_RED,
+ LOCAL_GL_RED,
+ LOCAL_GL_ONE };
+/*static*/ const GLint FormatUsageInfo::kAlphaSwizzleRGBA[4] = { LOCAL_GL_ZERO,
+ LOCAL_GL_ZERO,
+ LOCAL_GL_ZERO,
+ LOCAL_GL_RED };
+/*static*/ const GLint FormatUsageInfo::kLumAlphaSwizzleRGBA[4] = { LOCAL_GL_RED,
+ LOCAL_GL_RED,
+ LOCAL_GL_RED,
+ LOCAL_GL_GREEN };
+
+static void
AddLegacyFormats_LA8(FormatUsageAuthority* fua, gl::GLContext* gl)
{
- PackingInfo pi;
- DriverUnpackInfo dui;
+ if (gl->IsCoreProfile()) {
+ PackingInfo pi;
+ DriverUnpackInfo dui;
- const auto fnAdd = [fua, &pi, &dui](EffectiveFormat effFormat) {
- auto usage = fua->EditUsage(effFormat);
- fua->AddUnsizedTexFormat(pi, usage);
- usage->AddUnpack(pi, dui);
- };
-
- const bool isCore = gl->IsCoreProfile();
+ const auto fnAdd = [fua, &pi, &dui](EffectiveFormat effFormat,
+ const GLint* swizzle)
+ {
+ auto usage = fua->EditUsage(effFormat);
+ fua->AddUnsizedTexFormat(pi, usage);
+ usage->AddUnpack(pi, dui);
+ usage->textureSwizzleRGBA = swizzle;
+ };
- pi = {LOCAL_GL_LUMINANCE, LOCAL_GL_UNSIGNED_BYTE};
- if (isCore) dui = {LOCAL_GL_R8, LOCAL_GL_RED, LOCAL_GL_UNSIGNED_BYTE};
- else dui = {LOCAL_GL_LUMINANCE, LOCAL_GL_LUMINANCE, LOCAL_GL_UNSIGNED_BYTE};
- fnAdd(EffectiveFormat::Luminance8);
+ pi = {LOCAL_GL_LUMINANCE, LOCAL_GL_UNSIGNED_BYTE};
+ dui = {LOCAL_GL_R8, LOCAL_GL_RED, LOCAL_GL_UNSIGNED_BYTE};
+ fnAdd(EffectiveFormat::Luminance8, FormatUsageInfo::kLuminanceSwizzleRGBA);
+
+ pi = {LOCAL_GL_ALPHA, LOCAL_GL_UNSIGNED_BYTE};
+ dui = {LOCAL_GL_R8, LOCAL_GL_RED, LOCAL_GL_UNSIGNED_BYTE};
+ fnAdd(EffectiveFormat::Luminance8, FormatUsageInfo::kAlphaSwizzleRGBA);
- pi = {LOCAL_GL_ALPHA, LOCAL_GL_UNSIGNED_BYTE};
- if (isCore) dui = {LOCAL_GL_R8, LOCAL_GL_RED, LOCAL_GL_UNSIGNED_BYTE};
- else dui = {LOCAL_GL_ALPHA, LOCAL_GL_ALPHA, LOCAL_GL_UNSIGNED_BYTE};
- fnAdd(EffectiveFormat::Alpha8);
-
- pi = {LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_UNSIGNED_BYTE};
- if (isCore) dui = {LOCAL_GL_RG8, LOCAL_GL_RG, LOCAL_GL_UNSIGNED_BYTE};
- else dui = {LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_UNSIGNED_BYTE};
- fnAdd(EffectiveFormat::Luminance8Alpha8);
+ pi = {LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_UNSIGNED_BYTE};
+ dui = {LOCAL_GL_RG8, LOCAL_GL_RG, LOCAL_GL_UNSIGNED_BYTE};
+ fnAdd(EffectiveFormat::Luminance8Alpha8, FormatUsageInfo::kLumAlphaSwizzleRGBA);
+ } else {
+ AddSimpleUnsized(fua, LOCAL_GL_LUMINANCE , LOCAL_GL_UNSIGNED_BYTE, EffectiveFormat::Luminance8 );
+ AddSimpleUnsized(fua, LOCAL_GL_ALPHA , LOCAL_GL_UNSIGNED_BYTE, EffectiveFormat::Alpha8 );
+ AddSimpleUnsized(fua, LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_UNSIGNED_BYTE, EffectiveFormat::Luminance8Alpha8);
+ }
}
static void
AddBasicUnsizedFormats(FormatUsageAuthority* fua, gl::GLContext* gl)
{
- const auto fnAddSimpleUnsized = [fua](GLenum unpackFormat, GLenum unpackType,
- EffectiveFormat effFormat)
- {
- auto usage = fua->EditUsage(effFormat);
-
- const PackingInfo pi = {unpackFormat, unpackType};
- fua->AddUnsizedTexFormat(pi, usage);
-
- const DriverUnpackInfo dui = {unpackFormat, unpackFormat, unpackType};
- usage->AddUnpack(pi, dui);
- };
-
// GLES 2.0.25, p63, Table 3.4
-
- fnAddSimpleUnsized(LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE , EffectiveFormat::RGBA8 );
- fnAddSimpleUnsized(LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_SHORT_4_4_4_4, EffectiveFormat::RGBA4 );
- fnAddSimpleUnsized(LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_SHORT_5_5_5_1, EffectiveFormat::RGB5_A1);
- fnAddSimpleUnsized(LOCAL_GL_RGB , LOCAL_GL_UNSIGNED_BYTE , EffectiveFormat::RGB8 );
- fnAddSimpleUnsized(LOCAL_GL_RGB , LOCAL_GL_UNSIGNED_SHORT_5_6_5 , EffectiveFormat::RGB565 );
+ AddSimpleUnsized(fua, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE , EffectiveFormat::RGBA8 );
+ AddSimpleUnsized(fua, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_SHORT_4_4_4_4, EffectiveFormat::RGBA4 );
+ AddSimpleUnsized(fua, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_SHORT_5_5_5_1, EffectiveFormat::RGB5_A1);
+ AddSimpleUnsized(fua, LOCAL_GL_RGB , LOCAL_GL_UNSIGNED_BYTE , EffectiveFormat::RGB8 );
+ AddSimpleUnsized(fua, LOCAL_GL_RGB , LOCAL_GL_UNSIGNED_SHORT_5_6_5 , EffectiveFormat::RGB565 );
// L, A, LA
AddLegacyFormats_LA8(fua, gl);
}
UniquePtr<FormatUsageAuthority>
FormatUsageAuthority::CreateForWebGL1(gl::GLContext* gl)
{
--- a/dom/canvas/WebGLFormats.h
+++ b/dom/canvas/WebGLFormats.h
@@ -240,23 +240,28 @@ GLenum ComponentType(const FormatInfo* f
struct FormatUsageInfo
{
const FormatInfo* const format;
bool isRenderable;
bool isFilterable;
std::map<PackingInfo, DriverUnpackInfo> validUnpacks;
const DriverUnpackInfo* idealUnpack;
- //const GLint* textureSwizzleRGBA;
+ const GLint* textureSwizzleRGBA;
+
+ static const GLint kLuminanceSwizzleRGBA[4];
+ static const GLint kAlphaSwizzleRGBA[4];
+ static const GLint kLumAlphaSwizzleRGBA[4];
explicit FormatUsageInfo(const FormatInfo* _format)
: format(_format)
, isRenderable(false)
, isFilterable(false)
, idealUnpack(nullptr)
+ , textureSwizzleRGBA(nullptr)
{ }
void AddUnpack(const PackingInfo& key, const DriverUnpackInfo& value);
bool IsUnpackValid(const PackingInfo& key,
const DriverUnpackInfo** const out_value) const;
};
class FormatUsageAuthority
--- a/dom/canvas/WebGLTexture.cpp
+++ b/dom/canvas/WebGLTexture.cpp
@@ -110,41 +110,42 @@ WebGLTexture::ImageInfo::MemoryUsage() c
void
WebGLTexture::ImageInfo::SetIsDataInitialized(bool isDataInitialized, WebGLTexture* tex)
{
MOZ_ASSERT(tex);
MOZ_ASSERT(this >= &tex->mImageInfoArr[0]);
MOZ_ASSERT(this < &tex->mImageInfoArr[kMaxLevelCount * kMaxFaceCount]);
mIsDataInitialized = isDataInitialized;
- tex->InvalidateFakeBlackCache();
+ tex->InvalidateResolveCache();
}
////////////////////////////////////////
JSObject*
WebGLTexture::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) {
return dom::WebGLTextureBinding::Wrap(cx, this, givenProto);
}
WebGLTexture::WebGLTexture(WebGLContext* webgl, GLuint tex)
: WebGLContextBoundObject(webgl)
, mGLName(tex)
, mTarget(LOCAL_GL_NONE)
+ , mFaceCount(0)
, mMinFilter(LOCAL_GL_NEAREST_MIPMAP_LINEAR)
, mMagFilter(LOCAL_GL_LINEAR)
, mWrapS(LOCAL_GL_REPEAT)
, mWrapT(LOCAL_GL_REPEAT)
- , mFaceCount(0)
, mImmutable(false)
, mImmutableLevelCount(0)
, mBaseMipmapLevel(0)
, mMaxMipmapLevel(1000)
- , mFakeBlackStatus(WebGLTextureFakeBlackStatus::IncompleteTexture)
, mTexCompareMode(LOCAL_GL_NONE)
+ , mIsResolved(false)
+ , mResolved_Swizzle(nullptr)
{
mContext->mTextures.insertBack(this);
}
void
WebGLTexture::Delete()
{
for (auto& cur : mImageInfoArr) {
@@ -168,27 +169,27 @@ WebGLTexture::MemoryUsage() const
return result;
}
void
WebGLTexture::SetImageInfo(ImageInfo* target, const ImageInfo& newInfo)
{
*target = newInfo;
- InvalidateFakeBlackCache();
+ InvalidateResolveCache();
}
void
WebGLTexture::SetImageInfosAtLevel(uint32_t level, const ImageInfo& newInfo)
{
for (uint8_t i = 0; i < mFaceCount; i++) {
ImageInfoAtFace(i, level) = newInfo;
}
- InvalidateFakeBlackCache();
+ InvalidateResolveCache();
}
static inline uint32_t
MaxMipmapLevelsForSize(const WebGLTexture::ImageInfo& info)
{
auto size = std::max(std::max(info.mWidth, info.mHeight), info.mDepth);
// Find floor(log2(maxsize)) + 1. (ES 3.0.4, 3.8 - Mipmapping).
@@ -422,58 +423,48 @@ WebGLTexture::IsComplete(const char** co
return true;
}
uint32_t
WebGLTexture::MaxEffectiveMipmapLevel() const
{
- const bool requiresMipmap = (mMinFilter != LOCAL_GL_NEAREST &&
- mMinFilter != LOCAL_GL_LINEAR);
- if (!requiresMipmap)
+ if (mMinFilter == LOCAL_GL_NEAREST ||
+ mMinFilter == LOCAL_GL_LINEAR)
+ {
+ // No mips used.
return mBaseMipmapLevel;
+ }
const auto& imageInfo = BaseImageInfo();
MOZ_ASSERT(imageInfo.IsDefined());
uint32_t maxLevelBySize = mBaseMipmapLevel + imageInfo.MaxMipmapLevels() - 1;
return std::min<uint32_t>(maxLevelBySize, mMaxMipmapLevel);
}
bool
-WebGLTexture::ResolveFakeBlackStatus(const char* funcName,
- WebGLTextureFakeBlackStatus* const out)
+WebGLTexture::GetFakeBlackType(const char* funcName, uint32_t texUnit,
+ FakeBlackType* const out_fakeBlack)
{
- if (!ResolveFakeBlackStatus(funcName))
- return false;
-
- *out = mFakeBlackStatus;
- return true;
-}
-
-bool
-WebGLTexture::ResolveFakeBlackStatus(const char* funcName)
-{
- if (MOZ_LIKELY(mFakeBlackStatus != WebGLTextureFakeBlackStatus::Unknown))
- return true;
-
const char* incompleteReason;
if (!IsComplete(&incompleteReason)) {
if (incompleteReason) {
- mContext->GenerateWarning("An active texture is going to be rendered as if it"
- " were black, as per the GLES 2.0.24 $3.8.2: %s",
+ mContext->GenerateWarning("%s: Active texture %u for target 0x%04x is"
+ " 'incomplete', and will be rendered as"
+ " RGBA(0,0,0,1), as per the GLES 2.0.24 $3.8.2: %s",
+ funcName, texUnit, mTarget.get(),
incompleteReason);
}
- mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
+ *out_fakeBlack = FakeBlackType::RGBA0001;
return true;
}
- // We have exhausted all cases of incomplete textures, where we would need opaque black.
- // We may still need transparent black in case of uninitialized image data.
+ // We may still want FakeBlack as an optimization for uninitialized image data.
bool hasUninitializedData = false;
bool hasInitializedData = false;
const auto maxLevel = MaxEffectiveMipmapLevel();
MOZ_ASSERT(mBaseMipmapLevel <= maxLevel);
for (uint32_t level = mBaseMipmapLevel; level <= maxLevel; level++) {
for (uint8_t face = 0; face < mFaceCount; face++) {
const auto& cur = ImageInfoAtFace(face, level);
@@ -481,57 +472,116 @@ WebGLTexture::ResolveFakeBlackStatus(con
hasInitializedData = true;
else
hasUninitializedData = true;
}
}
MOZ_ASSERT(hasUninitializedData || hasInitializedData);
if (!hasUninitializedData) {
- mFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded;
+ *out_fakeBlack = FakeBlackType::None;
return true;
}
if (!hasInitializedData) {
- mFakeBlackStatus = WebGLTextureFakeBlackStatus::UninitializedImageData;
- return true;
+ const auto format = ImageInfoAtFace(0, mBaseMipmapLevel).mFormat->format;
+ if (format->isColorFormat) {
+ *out_fakeBlack = (format->hasAlpha ? FakeBlackType::RGBA0000
+ : FakeBlackType::RGBA0001);
+ return true;
+ }
+
+ mContext->GenerateWarning("%s: Active texture %u for target 0x%04x is"
+ " uninitialized, and will be (perhaps slowly) cleared"
+ " by the implementation.",
+ funcName, texUnit, mTarget.get());
+ } else {
+ mContext->GenerateWarning("%s: Active texture %u for target 0x%04x contains"
+ " TexImages with uninitialized data along with"
+ " TexImages with initialized data, forcing the"
+ " implementation to (slowly) initialize the"
+ " uninitialized TexImages.",
+ funcName, texUnit, mTarget.get());
}
- // Alright, we have both initialized and uninitialized data, so we have to initialize
- // the uninitialized images. Feel free to be slow.
- mContext->GenerateWarning("An active texture contains TexImages with uninitialized"
- " data along with TexImages with initialized data, forcing"
- " the implementation to (slowly) initialize the"
- " uninitialized TexImages.");
-
- GLenum baseTexImageTarget = mTarget.get();
- if (baseTexImageTarget == LOCAL_GL_TEXTURE_CUBE_MAP)
- baseTexImageTarget = LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
+ GLenum baseImageTarget = mTarget.get();
+ if (baseImageTarget == LOCAL_GL_TEXTURE_CUBE_MAP)
+ baseImageTarget = LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
for (uint32_t level = mBaseMipmapLevel; level <= maxLevel; level++) {
for (uint8_t face = 0; face < mFaceCount; face++) {
- TexImageTarget target = baseTexImageTarget + face;
- if (!EnsureImageDataInitialized(funcName, target, level))
+ TexImageTarget imageTarget = baseImageTarget + face;
+ if (!EnsureImageDataInitialized(funcName, imageTarget, level))
return false; // The world just exploded.
}
}
- mFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded;
+ *out_fakeBlack = FakeBlackType::None;
+ return true;
+}
+
+static void
+SetSwizzle(gl::GLContext* gl, TexTarget target, const GLint* swizzle)
+{
+ static const GLint kNoSwizzle[4] = { LOCAL_GL_RED, LOCAL_GL_GREEN, LOCAL_GL_BLUE,
+ LOCAL_GL_ALPHA };
+ if (!swizzle) {
+ swizzle = kNoSwizzle;
+ }
+
+ gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_SWIZZLE_R, swizzle[0]);
+ gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_SWIZZLE_G, swizzle[1]);
+ gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_SWIZZLE_B, swizzle[2]);
+ gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_SWIZZLE_A, swizzle[3]);
+}
+
+bool
+WebGLTexture::ResolveForDraw(const char* funcName, uint32_t texUnit,
+ FakeBlackType* const out_fakeBlack)
+{
+ if (!mIsResolved) {
+ if (!GetFakeBlackType(funcName, texUnit, &mResolved_FakeBlack))
+ return false;
+
+ // Check which swizzle we should use. Since the texture must be complete at this
+ // point, just grab the format off any valid image.
+ const GLint* newSwizzle = nullptr;
+ if (mResolved_FakeBlack == FakeBlackType::None) {
+ const auto& cur = ImageInfoAtFace(0, mBaseMipmapLevel);
+ newSwizzle = cur.mFormat->textureSwizzleRGBA;
+ }
+
+ // Only set the swizzle if it changed since last time we did it.
+ if (newSwizzle != mResolved_Swizzle) {
+ mResolved_Swizzle = newSwizzle;
+
+ // Set the new swizzle!
+ mContext->gl->fActiveTexture(LOCAL_GL_TEXTURE0 + texUnit);
+ SetSwizzle(mContext->gl, mTarget, mResolved_Swizzle);
+ mContext->gl->fActiveTexture(LOCAL_GL_TEXTURE0 + mContext->mActiveTexture);
+ }
+
+ mIsResolved = true;
+ }
+
+ *out_fakeBlack = mResolved_FakeBlack;
return true;
}
bool
WebGLTexture::EnsureImageDataInitialized(const char* funcName, TexImageTarget target,
uint32_t level)
{
auto& imageInfo = ImageInfoAt(target, level);
+ MOZ_ASSERT(imageInfo.IsDefined());
+ /*
if (!imageInfo.IsDefined())
return true; // The driver should handle this for us?
// (happens because ResolveFakeBlack plus incomplete mipchains)
-
+ */
if (imageInfo.IsDataInitialized())
return true;
return InitializeImageData(funcName, target, level);
}
bool
WebGLTexture::InitializeImageData(const char* funcName, TexImageTarget target,
@@ -603,23 +653,16 @@ WebGLTexture::PopulateMipChain(uint32_t
refWidth = std::max(uint32_t(1), refWidth / 2);
refHeight = std::max(uint32_t(1), refHeight / 2);
if (mTarget == LOCAL_GL_TEXTURE_3D) { // But not TEXTURE_2D_ARRAY!
refDepth = std::max(uint32_t(1), refDepth / 2);
}
}
}
-void
-WebGLTexture::InvalidateFakeBlackCache()
-{
- mContext->InvalidateFakeBlackCache();
- mFakeBlackStatus = WebGLTextureFakeBlackStatus::Unknown;
-}
-
//////////////////////////////////////////////////////////////////////////////////////////
// GL calls
bool
WebGLTexture::BindTexture(TexTarget texTarget)
{
// silently ignore a deleted texture
if (IsDeleted())
@@ -648,20 +691,16 @@ WebGLTexture::BindTexture(TexTarget texT
// If we are WebGL 2 though, we'll want to leave it as REPEAT.
const bool hasWrapR = gl->IsSupported(gl::GLFeature::texture_3D);
if (IsCubeMap() && hasWrapR && !mContext->IsWebGL2()) {
gl->fTexParameteri(texTarget.get(), LOCAL_GL_TEXTURE_WRAP_R,
LOCAL_GL_CLAMP_TO_EDGE);
}
}
- if (mFakeBlackStatus != WebGLTextureFakeBlackStatus::NotNeeded) {
- mContext->InvalidateFakeBlackCache();
- }
-
return true;
}
void
WebGLTexture::GenerateMipmap(TexTarget texTarget)
{
if (mBaseMipmapLevel > mMaxMipmapLevel) {
@@ -954,20 +993,25 @@ WebGLTexture::TexParameter(TexTarget tex
case LOCAL_GL_TEXTURE_WRAP_T:
mWrapT = intParam;
break;
// We don't actually need to store the WRAP_R, since it doesn't change texture
// completeness rules.
}
- // The only pname that doesn't actually need fake-black invalidation is
- // LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT.
- if (pname != LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT) {
- InvalidateFakeBlackCache();
+ // Only a couple of pnames don't need to invalidate our resolve status cache.
+ switch (pname) {
+ case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
+ case LOCAL_GL_TEXTURE_WRAP_R:
+ break;
+
+ default:
+ InvalidateResolveCache();
+ break;
}
////////////////
mContext->MakeContextCurrent();
if (maybeIntParam)
mContext->gl->fTexParameteri(texTarget.get(), pname, intParam);
else
--- a/dom/canvas/WebGLTexture.h
+++ b/dom/canvas/WebGLTexture.h
@@ -54,32 +54,35 @@ class WebGLTexture final
////////////////////////////////////
// Members
public:
const GLuint mGLName;
protected:
TexTarget mTarget;
+ static const uint8_t kMaxFaceCount = 6;
+ uint8_t mFaceCount; // 6 for cube maps, 1 otherwise.
+
TexMinFilter mMinFilter;
TexMagFilter mMagFilter;
TexWrap mWrapS, mWrapT;
- static const uint8_t kMaxFaceCount = 6;
- uint8_t mFaceCount; // 6 for cube maps, 1 otherwise.
-
bool mImmutable; // Set by texStorage*
uint8_t mImmutableLevelCount;
uint32_t mBaseMipmapLevel; // Set by texParameter (defaults to 0)
uint32_t mMaxMipmapLevel; // Set by texParameter (defaults to 1000)
- WebGLTextureFakeBlackStatus mFakeBlackStatus;
+ GLenum mTexCompareMode;
- GLenum mTexCompareMode;
+ // Resolvable optimizations:
+ bool mIsResolved;
+ FakeBlackType mResolved_FakeBlack;
+ const GLint* mResolved_Swizzle; // nullptr means 'default swizzle'.
public:
class ImageInfo;
// numLevels = log2(size) + 1
// numLevels(16k) = log2(16k) + 1 = 14 + 1 = 15
// numLevels(1M) = log2(1M) + 1 = 19.9 + 1 ~= 21
// Or we can just max this out to 31, which is the number of unsigned bits in GLsizei.
@@ -369,26 +372,25 @@ public:
bool IsCubeComplete() const;
bool IsComplete(const char** const out_reason) const;
bool IsMipmapCubeComplete() const;
bool IsCubeMap() const { return (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP); }
- // Fake black status
+ // Resolve cache optimizations
protected:
- bool ResolveFakeBlackStatus(const char* funcName);
+ bool GetFakeBlackType(const char* funcName, uint32_t texUnit,
+ FakeBlackType* const out_fakeBlack);
public:
- bool ResolveFakeBlackStatus(const char* funcName,
- WebGLTextureFakeBlackStatus* const out);
+ bool ResolveForDraw(const char* funcName, uint32_t texUnit,
+ FakeBlackType* const out_fakeBlack);
- WebGLTextureFakeBlackStatus FakeBlackStatus() const { return mFakeBlackStatus; }
-
- void InvalidateFakeBlackCache();
+ void InvalidateResolveCache() { mIsResolved = false; }
};
inline TexImageTarget
TexImageTargetForTargetAndFace(TexTarget target, uint8_t face)
{
switch (target.get()) {
case LOCAL_GL_TEXTURE_2D:
case LOCAL_GL_TEXTURE_3D:
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -303,64 +303,16 @@ WebGLTexture::TexOrSubImage(bool isSubIm
TexImage(funcName, target, level, internalFormat, border, unpackFormat,
unpackType, blob);
}
}
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
-
-/* This needs to be done (but cached) per texture per draw call.
-
-// Map R to A
-static const GLenum kLegacyAlphaSwizzle[4] = {
- LOCAL_GL_ZERO, LOCAL_GL_ZERO, LOCAL_GL_ZERO, LOCAL_GL_RED
-};
-// Map R to RGB
-static const GLenum kLegacyLuminanceSwizzle[4] = {
- LOCAL_GL_RED, LOCAL_GL_RED, LOCAL_GL_RED, LOCAL_GL_ONE
-};
-// Map R to RGB, G to A
-static const GLenum kLegacyLuminanceAlphaSwizzle[4] = {
- LOCAL_GL_RED, LOCAL_GL_RED, LOCAL_GL_RED, LOCAL_GL_GREEN
-};
-
-static void
-SetLegacyTextureSwizzle(gl::GLContext* gl, GLenum target, GLenum internalformat)
-{
- if (!gl->IsCoreProfile())
- return;
-
- // Only support swizzling on core profiles.
- // Bug 1159117: Fix this.
- // MOZ_RELEASE_ASSERT(gl->IsSupported(gl::GLFeature::texture_swizzle));
-
- switch (internalformat) {
- case LOCAL_GL_ALPHA:
- gl->fTexParameteriv(target, LOCAL_GL_TEXTURE_SWIZZLE_RGBA,
- (GLint*) kLegacyAlphaSwizzle);
- break;
-
- case LOCAL_GL_LUMINANCE:
- gl->fTexParameteriv(target, LOCAL_GL_TEXTURE_SWIZZLE_RGBA,
- (GLint*) kLegacyLuminanceSwizzle);
- break;
-
- case LOCAL_GL_LUMINANCE_ALPHA:
- gl->fTexParameteriv(target, LOCAL_GL_TEXTURE_SWIZZLE_RGBA,
- (GLint*) kLegacyLuminanceAlphaSwizzle);
- break;
- }
-}
-*/
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// Utils
-
static bool
ValidateTexImage(WebGLContext* webgl, WebGLTexture* texture, const char* funcName,
TexImageTarget target, GLint level,
WebGLTexture::ImageInfo** const out_imageInfo)
{
// Check level
if (level < 0) {
webgl->ErrorInvalidValue("%s: `level` must be >= 0.", funcName);
@@ -1568,16 +1520,175 @@ ValidateCopyTexImageFormats(WebGLContext
" source channels. (GLES 3.0.4 p140 Table 3.16)",
funcName);
return false;
}
return true;
}
+////////////////////////////////////////////////////////////////////////////////
+
+class ScopedCopyTexImageSource
+{
+ WebGLContext* const mWebGL;
+ GLuint mRB;
+ GLuint mFB;
+
+public:
+ ScopedCopyTexImageSource(WebGLContext* webgl, const char* funcName, uint32_t srcWidth,
+ uint32_t srcHeight, const webgl::FormatInfo* srcFormat,
+ const webgl::FormatUsageInfo* dstUsage);
+ ~ScopedCopyTexImageSource();
+};
+
+ScopedCopyTexImageSource::ScopedCopyTexImageSource(WebGLContext* webgl,
+ const char* funcName,
+ uint32_t srcWidth, uint32_t srcHeight,
+ const webgl::FormatInfo* srcFormat,
+ const webgl::FormatUsageInfo* dstUsage)
+ : mWebGL(webgl)
+ , mRB(0)
+ , mFB(0)
+{
+ switch (dstUsage->format->unsizedFormat) {
+ case webgl::UnsizedFormat::L:
+ case webgl::UnsizedFormat::A:
+ case webgl::UnsizedFormat::LA:
+ webgl->GenerateWarning("%s: Copying to a LUMINANCE, ALPHA, or LUMINANCE_ALPHA"
+ " is deprecated, and has severely reduced performance"
+ " on some platforms.",
+ funcName);
+ break;
+
+ default:
+ MOZ_ASSERT(!dstUsage->textureSwizzleRGBA);
+ return;
+ }
+
+ if (!dstUsage->textureSwizzleRGBA)
+ return;
+
+ gl::GLContext* gl = webgl->gl;
+
+ GLenum sizedFormat;
+
+ switch (srcFormat->componentType) {
+ case webgl::ComponentType::NormUInt:
+ sizedFormat = LOCAL_GL_RGBA8;
+ break;
+
+ case webgl::ComponentType::Float:
+ if (webgl->IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float)) {
+ sizedFormat = LOCAL_GL_RGBA32F;
+ break;
+ }
+
+ if (webgl->IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float)) {
+ sizedFormat = LOCAL_GL_RGBA16F;
+ break;
+ }
+ MOZ_CRASH("Should be able to request CopyTexImage from Float.");
+
+ default:
+ MOZ_CRASH("Should be able to request CopyTexImage from this type.");
+ }
+
+ gl::ScopedTexture scopedTex(gl);
+ gl::ScopedBindTexture scopedBindTex(gl, scopedTex.Texture(), LOCAL_GL_TEXTURE_2D);
+
+ gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST);
+ gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST);
+
+ GLint blitSwizzle[4] = {LOCAL_GL_ZERO};
+ switch (dstUsage->format->unsizedFormat) {
+ case webgl::UnsizedFormat::L:
+ blitSwizzle[0] = LOCAL_GL_RED;
+ break;
+
+ case webgl::UnsizedFormat::A:
+ blitSwizzle[0] = LOCAL_GL_ALPHA;
+ break;
+
+ case webgl::UnsizedFormat::LA:
+ blitSwizzle[0] = LOCAL_GL_RED;
+ blitSwizzle[1] = LOCAL_GL_ALPHA;
+ break;
+
+ default:
+ MOZ_CRASH("Unhandled unsizedFormat.");
+ }
+
+ gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_SWIZZLE_R, blitSwizzle[0]);
+ gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_SWIZZLE_G, blitSwizzle[1]);
+ gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_SWIZZLE_B, blitSwizzle[2]);
+ gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_SWIZZLE_A, blitSwizzle[3]);
+
+ gl->fCopyTexImage2D(LOCAL_GL_TEXTURE_2D, 0, sizedFormat, 0, 0, srcWidth,
+ srcHeight, 0);
+
+ // Now create the swizzled FB we'll be exposing.
+
+ GLuint rgbaRB = 0;
+ gl->fGenRenderbuffers(1, &rgbaRB);
+ gl::ScopedBindRenderbuffer scopedRB(gl, rgbaRB);
+ gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, sizedFormat, srcWidth, srcHeight);
+
+ GLuint rgbaFB = 0;
+ gl->fGenFramebuffers(1, &rgbaFB);
+ gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, rgbaFB);
+ gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
+ LOCAL_GL_RENDERBUFFER, rgbaRB);
+
+ const GLenum status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
+ if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
+ MOZ_CRASH("Temp framebuffer is not Complete.");
+ }
+
+ // Restore RB binding.
+ scopedRB.Unwrap(); // This function should really have a better name.
+
+ // Draw-blit rgbaTex into rgbaFB.
+ const gfx::IntSize srcSize(srcWidth, srcHeight);
+ gl->BlitHelper()->DrawBlitTextureToFramebuffer(scopedTex.Texture(), rgbaFB,
+ srcSize, srcSize);
+
+ // Restore Tex2D binding and destroy the temp tex.
+ scopedBindTex.Unwrap();
+ scopedTex.Unwrap();
+
+ // Leave RB and FB alive, and FB bound.
+ mRB = rgbaRB;
+ mFB = rgbaFB;
+}
+
+template<typename T>
+static inline GLenum
+ToGLHandle(const T& obj)
+{
+ return (obj ? obj->mGLName : 0);
+}
+
+ScopedCopyTexImageSource::~ScopedCopyTexImageSource()
+{
+ gl::GLContext* gl = mWebGL->gl;
+
+ // If we're swizzling, it's because we're on a GL core (3.2+) profile, which has
+ // split framebuffer support.
+ gl->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER,
+ ToGLHandle(mWebGL->mBoundDrawFramebuffer));
+ gl->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER,
+ ToGLHandle(mWebGL->mBoundReadFramebuffer));
+
+ gl->fDeleteFramebuffers(1, &mFB);
+ gl->fDeleteRenderbuffers(1, &mRB);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
// There is no CopyTexImage3D.
void
WebGLTexture::CopyTexImage2D(TexImageTarget target, GLint level, GLenum internalFormat,
GLint x, GLint y, GLsizei width, GLsizei height,
GLint border)
{
const char funcName[] = "CopyTexImage2D";
@@ -1650,16 +1761,19 @@ WebGLTexture::CopyTexImage2D(TexImageTar
return;
////////////////////////////////////
// Do the thing!
gl::GLContext* gl = mContext->gl;
gl->MakeCurrent();
+ ScopedCopyTexImageSource maybeSwizzle(mContext, funcName, srcWidth, srcHeight,
+ srcFormat, dstUsage);
+
uint32_t readX, readY;
uint32_t writeX, writeY;
uint32_t rwWidth, rwHeight;
Intersect(srcWidth, x, width, &readX, &writeX, &rwWidth);
Intersect(srcHeight, y, height, &readY, &writeY, &rwHeight);
GLenum error;
if (rwWidth == uint32_t(width) && rwHeight == uint32_t(height)) {
@@ -1756,16 +1870,19 @@ WebGLTexture::CopyTexSubImage(const char
if (!ValidateCopyTexImageFormats(mContext, funcName, srcFormat, dstFormat))
return;
////////////////////////////////////
// Do the thing!
mContext->gl->MakeCurrent();
+ ScopedCopyTexImageSource maybeSwizzle(mContext, funcName, srcWidth, srcHeight,
+ srcFormat, dstUsage);
+
uint32_t readX, readY;
uint32_t writeX, writeY;
uint32_t rwWidth, rwHeight;
Intersect(srcWidth, x, width, &readX, &writeX, &rwWidth);
Intersect(srcHeight, y, height, &readY, &writeY, &rwHeight);
if (!rwWidth || !rwHeight) {
// There aren't any, so we're 'done'.
--- a/dom/canvas/WebGLTypes.h
+++ b/dom/canvas/WebGLTypes.h
@@ -33,21 +33,20 @@ namespace mozilla {
* uninitialized image data. See below the comment about WebGLImageDataStatus.
* WebGL must never have access to uninitialized image data. The WebGL 1 spec,
* section 4.1 'Resource Restrictions', specifies that in any such case, the
* uninitialized image data must be exposed to WebGL as if it were filled
* with zero bytes, which means it's either opaque or transparent black
* depending on whether the image format has alpha.
*/
-enum class WebGLTextureFakeBlackStatus : uint8_t {
- Unknown,
- NotNeeded,
- IncompleteTexture,
- UninitializedImageData
+enum class FakeBlackType : uint8_t {
+ None,
+ RGBA0001, // Incomplete textures and uninitialized no-alpha color textures.
+ RGBA0000, // Uninitialized with-alpha color textures.
};
/*
* Implementing WebGL (or OpenGL ES 2.0) on top of desktop OpenGL requires
* emulating the vertex attrib 0 array when it's not enabled. Indeed,
* OpenGL ES 2.0 allows drawing without vertex attrib 0 array enabled, but
* desktop OpenGL does not allow that.
*/
--- a/gfx/gl/GLBlitHelper.cpp
+++ b/gfx/gl/GLBlitHelper.cpp
@@ -929,16 +929,28 @@ GLBlitHelper::BlitTextureToFramebuffer(G
MOZ_DIAGNOSTIC_ASSERT(srcWrapper.IsComplete());
BlitFramebufferToFramebuffer(srcWrapper.FB(), destFB,
srcSize, destSize,
internalFBs);
return;
}
+ DrawBlitTextureToFramebuffer(srcTex, destFB, srcSize, destSize, srcTarget,
+ internalFBs);
+}
+
+
+void
+GLBlitHelper::DrawBlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
+ const gfx::IntSize& srcSize,
+ const gfx::IntSize& destSize,
+ GLenum srcTarget,
+ bool internalFBs)
+{
BlitType type;
switch (srcTarget) {
case LOCAL_GL_TEXTURE_2D:
type = BlitTex2D;
break;
case LOCAL_GL_TEXTURE_RECTANGLE_ARB:
type = BlitTexRect;
break;
--- a/gfx/gl/GLBlitHelper.h
+++ b/gfx/gl/GLBlitHelper.h
@@ -138,16 +138,21 @@ public:
const gfx::IntSize& destSize,
const GLFormats& srcFormats,
bool internalFBs = false);
void BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
const gfx::IntSize& srcSize,
const gfx::IntSize& destSize,
GLenum srcTarget = LOCAL_GL_TEXTURE_2D,
bool internalFBs = false);
+ void DrawBlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
+ const gfx::IntSize& srcSize,
+ const gfx::IntSize& destSize,
+ GLenum srcTarget = LOCAL_GL_TEXTURE_2D,
+ bool internalFBs = false);
void BlitFramebufferToTexture(GLuint srcFB, GLuint destTex,
const gfx::IntSize& srcSize,
const gfx::IntSize& destSize,
GLenum destTarget = LOCAL_GL_TEXTURE_2D,
bool internalFBs = false);
void BlitTextureToTexture(GLuint srcTex, GLuint destTex,
const gfx::IntSize& srcSize,
const gfx::IntSize& destSize,
--- a/gfx/gl/ScopedGLHelpers.cpp
+++ b/gfx/gl/ScopedGLHelpers.cpp
@@ -169,44 +169,66 @@ ScopedRenderbuffer::UnwrapImpl()
{
// Check that we're not falling out of scope after
// the current context changed.
MOZ_ASSERT(mGL->IsCurrent());
mGL->fDeleteRenderbuffers(1, &mRB);
}
/* ScopedBindTexture **********************************************************/
-void
-ScopedBindTexture::Init(GLenum aTarget)
+
+static GLuint
+GetBoundTexture(GLContext* gl, GLenum texTarget)
{
- mTarget = aTarget;
- mOldTex = 0;
- GLenum bindingTarget = (aTarget == LOCAL_GL_TEXTURE_2D) ? LOCAL_GL_TEXTURE_BINDING_2D
- : (aTarget == LOCAL_GL_TEXTURE_3D) ? LOCAL_GL_TEXTURE_BINDING_3D
- : (aTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) ? LOCAL_GL_TEXTURE_BINDING_RECTANGLE_ARB
- : (aTarget == LOCAL_GL_TEXTURE_CUBE_MAP) ? LOCAL_GL_TEXTURE_BINDING_CUBE_MAP
- : (aTarget == LOCAL_GL_TEXTURE_EXTERNAL) ? LOCAL_GL_TEXTURE_BINDING_EXTERNAL
- : LOCAL_GL_NONE;
- MOZ_ASSERT(bindingTarget != LOCAL_GL_NONE);
- mGL->GetUIntegerv(bindingTarget, &mOldTex);
+ GLenum bindingTarget;
+ switch (texTarget) {
+ case LOCAL_GL_TEXTURE_2D:
+ bindingTarget = LOCAL_GL_TEXTURE_BINDING_2D;
+ break;
+
+ case LOCAL_GL_TEXTURE_CUBE_MAP:
+ bindingTarget = LOCAL_GL_TEXTURE_BINDING_CUBE_MAP;
+ break;
+
+ case LOCAL_GL_TEXTURE_3D:
+ bindingTarget = LOCAL_GL_TEXTURE_BINDING_3D;
+ break;
+
+ case LOCAL_GL_TEXTURE_2D_ARRAY:
+ bindingTarget = LOCAL_GL_TEXTURE_BINDING_2D_ARRAY;
+ break;
+
+ case LOCAL_GL_TEXTURE_RECTANGLE_ARB:
+ bindingTarget = LOCAL_GL_TEXTURE_BINDING_RECTANGLE_ARB;
+ break;
+
+ case LOCAL_GL_TEXTURE_EXTERNAL:
+ bindingTarget = LOCAL_GL_TEXTURE_BINDING_EXTERNAL;
+ break;
+
+ default:
+ MOZ_CRASH("bad texTarget");
+ }
+
+ GLuint ret = 0;
+ gl->GetUIntegerv(bindingTarget, &ret);
+ return ret;
}
ScopedBindTexture::ScopedBindTexture(GLContext* aGL, GLuint aNewTex, GLenum aTarget)
: ScopedGLWrapper<ScopedBindTexture>(aGL)
- {
- Init(aTarget);
- mGL->fBindTexture(aTarget, aNewTex);
- }
+ , mTarget(aTarget)
+ , mOldTex(GetBoundTexture(aGL, aTarget))
+{
+ mGL->fBindTexture(mTarget, aNewTex);
+}
void
ScopedBindTexture::UnwrapImpl()
{
- // Check that we're not falling out of scope after the current context changed.
- MOZ_ASSERT(mGL->IsCurrent());
-
mGL->fBindTexture(mTarget, mOldTex);
}
/* ScopedBindRenderbuffer *****************************************************/
void
ScopedBindRenderbuffer::Init()
--- a/gfx/gl/ScopedGLHelpers.h
+++ b/gfx/gl/ScopedGLHelpers.h
@@ -164,21 +164,18 @@ protected:
struct ScopedBindTexture
: public ScopedGLWrapper<ScopedBindTexture>
{
friend struct ScopedGLWrapper<ScopedBindTexture>;
protected:
- GLuint mOldTex;
- GLenum mTarget;
-
-private:
- void Init(GLenum aTarget);
+ const GLenum mTarget;
+ const GLuint mOldTex;
public:
ScopedBindTexture(GLContext* aGL, GLuint aNewTex,
GLenum aTarget = LOCAL_GL_TEXTURE_2D);
protected:
void UnwrapImpl();
};