mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-01 05:48:26 +00:00
Bug 1093967 - Implement BlitFramebuffer. r=kamidphish
This commit is contained in:
parent
a1bfc06c8c
commit
dc1d886801
@ -4,20 +4,329 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WebGL2Context.h"
|
||||
|
||||
#include "GLContext.h"
|
||||
#include "WebGLContextUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
// Returns one of FLOAT, INT, UNSIGNED_INT.
|
||||
// Fixed-points (normalized ints) are considered FLOAT.
|
||||
static GLenum
|
||||
ValueTypeForFormat(GLenum internalFormat)
|
||||
{
|
||||
switch (internalFormat) {
|
||||
// Fixed-point
|
||||
case LOCAL_GL_R8:
|
||||
case LOCAL_GL_RG8:
|
||||
case LOCAL_GL_RGB565:
|
||||
case LOCAL_GL_RGB8:
|
||||
case LOCAL_GL_RGBA4:
|
||||
case LOCAL_GL_RGB5_A1:
|
||||
case LOCAL_GL_RGBA8:
|
||||
case LOCAL_GL_RGB10_A2:
|
||||
case LOCAL_GL_ALPHA8:
|
||||
case LOCAL_GL_LUMINANCE8:
|
||||
case LOCAL_GL_LUMINANCE8_ALPHA8:
|
||||
case LOCAL_GL_SRGB8:
|
||||
case LOCAL_GL_SRGB8_ALPHA8:
|
||||
case LOCAL_GL_R8_SNORM:
|
||||
case LOCAL_GL_RG8_SNORM:
|
||||
case LOCAL_GL_RGB8_SNORM:
|
||||
case LOCAL_GL_RGBA8_SNORM:
|
||||
|
||||
// Floating-point
|
||||
case LOCAL_GL_R16F:
|
||||
case LOCAL_GL_RG16F:
|
||||
case LOCAL_GL_RGB16F:
|
||||
case LOCAL_GL_RGBA16F:
|
||||
case LOCAL_GL_ALPHA16F_EXT:
|
||||
case LOCAL_GL_LUMINANCE16F_EXT:
|
||||
case LOCAL_GL_LUMINANCE_ALPHA16F_EXT:
|
||||
|
||||
case LOCAL_GL_R32F:
|
||||
case LOCAL_GL_RG32F:
|
||||
case LOCAL_GL_RGB32F:
|
||||
case LOCAL_GL_RGBA32F:
|
||||
case LOCAL_GL_ALPHA32F_EXT:
|
||||
case LOCAL_GL_LUMINANCE32F_EXT:
|
||||
case LOCAL_GL_LUMINANCE_ALPHA32F_EXT:
|
||||
|
||||
case LOCAL_GL_R11F_G11F_B10F:
|
||||
case LOCAL_GL_RGB9_E5:
|
||||
return LOCAL_GL_FLOAT;
|
||||
|
||||
// Int
|
||||
case LOCAL_GL_R8I:
|
||||
case LOCAL_GL_RG8I:
|
||||
case LOCAL_GL_RGB8I:
|
||||
case LOCAL_GL_RGBA8I:
|
||||
|
||||
case LOCAL_GL_R16I:
|
||||
case LOCAL_GL_RG16I:
|
||||
case LOCAL_GL_RGB16I:
|
||||
case LOCAL_GL_RGBA16I:
|
||||
|
||||
case LOCAL_GL_R32I:
|
||||
case LOCAL_GL_RG32I:
|
||||
case LOCAL_GL_RGB32I:
|
||||
case LOCAL_GL_RGBA32I:
|
||||
return LOCAL_GL_INT;
|
||||
|
||||
// Unsigned int
|
||||
case LOCAL_GL_R8UI:
|
||||
case LOCAL_GL_RG8UI:
|
||||
case LOCAL_GL_RGB8UI:
|
||||
case LOCAL_GL_RGBA8UI:
|
||||
|
||||
case LOCAL_GL_R16UI:
|
||||
case LOCAL_GL_RG16UI:
|
||||
case LOCAL_GL_RGB16UI:
|
||||
case LOCAL_GL_RGBA16UI:
|
||||
|
||||
case LOCAL_GL_R32UI:
|
||||
case LOCAL_GL_RG32UI:
|
||||
case LOCAL_GL_RGB32UI:
|
||||
case LOCAL_GL_RGBA32UI:
|
||||
|
||||
case LOCAL_GL_RGB10_A2UI:
|
||||
return LOCAL_GL_UNSIGNED_INT;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Bad `internalFormat`.");
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Framebuffer objects
|
||||
|
||||
static bool
|
||||
GetFBInfoForBlit(const WebGLFramebuffer* fb, WebGLContext* webgl,
|
||||
const char* const fbInfo, GLsizei* const out_samples,
|
||||
GLenum* const out_colorFormat, GLenum* const out_depthFormat,
|
||||
GLenum* const out_stencilFormat)
|
||||
{
|
||||
auto status = fb->PrecheckFramebufferStatus();
|
||||
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
|
||||
webgl->ErrorInvalidOperation("blitFramebuffer: %s is not"
|
||||
" framebuffer-complete.", fbInfo);
|
||||
return false;
|
||||
}
|
||||
|
||||
*out_samples = 1; // TODO
|
||||
|
||||
if (fb->ColorAttachment(0).IsDefined()) {
|
||||
const auto& attachement = fb->ColorAttachment(0);
|
||||
*out_colorFormat = attachement.EffectiveInternalFormat().get();
|
||||
} else {
|
||||
*out_colorFormat = 0;
|
||||
}
|
||||
|
||||
if (fb->DepthStencilAttachment().IsDefined()) {
|
||||
const auto& attachement = fb->DepthStencilAttachment();
|
||||
*out_depthFormat = attachement.EffectiveInternalFormat().get();
|
||||
*out_stencilFormat = *out_depthFormat;
|
||||
} else {
|
||||
if (fb->DepthAttachment().IsDefined()) {
|
||||
const auto& attachement = fb->DepthAttachment();
|
||||
*out_depthFormat = attachement.EffectiveInternalFormat().get();
|
||||
} else {
|
||||
*out_depthFormat = 0;
|
||||
}
|
||||
|
||||
if (fb->StencilAttachment().IsDefined()) {
|
||||
const auto& attachement = fb->StencilAttachment();
|
||||
*out_stencilFormat = attachement.EffectiveInternalFormat().get();
|
||||
} else {
|
||||
*out_stencilFormat = 0;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
|
||||
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
|
||||
GLbitfield mask, GLenum filter)
|
||||
{
|
||||
MOZ_CRASH("Not Implemented.");
|
||||
const GLbitfield validBits = LOCAL_GL_COLOR_BUFFER_BIT |
|
||||
LOCAL_GL_DEPTH_BUFFER_BIT |
|
||||
LOCAL_GL_STENCIL_BUFFER_BIT;
|
||||
if ((mask | validBits) != validBits) {
|
||||
ErrorInvalidValue("blitFramebuffer: Invalid bit set in mask.");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (filter) {
|
||||
case LOCAL_GL_NEAREST:
|
||||
case LOCAL_GL_LINEAR:
|
||||
break;
|
||||
default:
|
||||
ErrorInvalidEnumInfo("blitFramebuffer: Bad `filter`:", filter);
|
||||
return;
|
||||
}
|
||||
|
||||
const GLbitfield depthAndStencilBits = LOCAL_GL_DEPTH_BUFFER_BIT |
|
||||
LOCAL_GL_STENCIL_BUFFER_BIT;
|
||||
if (mask & depthAndStencilBits &&
|
||||
filter != LOCAL_GL_NEAREST)
|
||||
{
|
||||
ErrorInvalidOperation("blitFramebuffer: DEPTH_BUFFER_BIT and"
|
||||
" STENCIL_BUFFER_BIT can only be used with"
|
||||
" NEAREST filtering.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mBoundReadFramebuffer == mBoundDrawFramebuffer) {
|
||||
// TODO: It's actually more complicated than this. We need to check that
|
||||
// the underlying buffers are not the same, not the framebuffers
|
||||
// themselves.
|
||||
ErrorInvalidOperation("blitFramebuffer: Source and destination must"
|
||||
" differ.");
|
||||
return;
|
||||
}
|
||||
|
||||
GLsizei srcSamples;
|
||||
GLenum srcColorFormat;
|
||||
GLenum srcDepthFormat;
|
||||
GLenum srcStencilFormat;
|
||||
|
||||
if (mBoundReadFramebuffer) {
|
||||
if (!GetFBInfoForBlit(mBoundReadFramebuffer, this, "READ_FRAMEBUFFER",
|
||||
&srcSamples, &srcColorFormat, &srcDepthFormat,
|
||||
&srcStencilFormat))
|
||||
{
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
srcSamples = 1; // Always 1.
|
||||
|
||||
// TODO: Don't hardcode these.
|
||||
srcColorFormat = mOptions.alpha ? LOCAL_GL_RGBA8 : LOCAL_GL_RGB8;
|
||||
|
||||
if (mOptions.depth && mOptions.stencil) {
|
||||
srcDepthFormat = LOCAL_GL_DEPTH24_STENCIL8;
|
||||
srcStencilFormat = srcDepthFormat;
|
||||
} else {
|
||||
if (mOptions.depth) {
|
||||
srcDepthFormat = LOCAL_GL_DEPTH_COMPONENT16;
|
||||
}
|
||||
if (mOptions.stencil) {
|
||||
srcStencilFormat = LOCAL_GL_STENCIL_INDEX8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GLsizei dstSamples;
|
||||
GLenum dstColorFormat;
|
||||
GLenum dstDepthFormat;
|
||||
GLenum dstStencilFormat;
|
||||
|
||||
if (mBoundDrawFramebuffer) {
|
||||
if (!GetFBInfoForBlit(mBoundDrawFramebuffer, this, "DRAW_FRAMEBUFFER",
|
||||
&dstSamples, &dstColorFormat, &dstDepthFormat,
|
||||
&dstStencilFormat))
|
||||
{
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
dstSamples = gl->Screen()->Samples();
|
||||
|
||||
// TODO: Don't hardcode these.
|
||||
dstColorFormat = mOptions.alpha ? LOCAL_GL_RGBA8 : LOCAL_GL_RGB8;
|
||||
|
||||
if (mOptions.depth && mOptions.stencil) {
|
||||
dstDepthFormat = LOCAL_GL_DEPTH24_STENCIL8;
|
||||
dstStencilFormat = dstDepthFormat;
|
||||
} else {
|
||||
if (mOptions.depth) {
|
||||
dstDepthFormat = LOCAL_GL_DEPTH_COMPONENT16;
|
||||
}
|
||||
if (mOptions.stencil) {
|
||||
dstStencilFormat = LOCAL_GL_STENCIL_INDEX8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
|
||||
const GLenum srcColorType = srcColorFormat ? ValueTypeForFormat(srcColorFormat)
|
||||
: 0;
|
||||
const GLenum dstColorType = dstColorFormat ? ValueTypeForFormat(dstColorFormat)
|
||||
: 0;
|
||||
if (dstColorType != srcColorType) {
|
||||
ErrorInvalidOperation("blitFramebuffer: Color buffer value type"
|
||||
" mismatch.");
|
||||
return;
|
||||
}
|
||||
|
||||
const bool srcIsInt = srcColorType == LOCAL_GL_INT ||
|
||||
srcColorType == LOCAL_GL_UNSIGNED_INT;
|
||||
if (srcIsInt && filter != LOCAL_GL_NEAREST) {
|
||||
ErrorInvalidOperation("blitFramebuffer: Integer read buffers can only"
|
||||
" be filtered with NEAREST.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* GLES 3.0.4, p199:
|
||||
* Calling BlitFramebuffer will result in an INVALID_OPERATION error if
|
||||
* mask includes DEPTH_BUFFER_BIT or STENCIL_BUFFER_BIT, and the source
|
||||
* and destination depth and stencil buffer formats do not match.
|
||||
*
|
||||
* jgilbert: The wording is such that if only DEPTH_BUFFER_BIT is specified,
|
||||
* the stencil formats must match. This seems wrong. It could be a spec bug,
|
||||
* or I could be missing an interaction in one of the earlier paragraphs.
|
||||
*/
|
||||
if (mask & LOCAL_GL_DEPTH_BUFFER_BIT &&
|
||||
dstDepthFormat != srcDepthFormat)
|
||||
{
|
||||
ErrorInvalidOperation("blitFramebuffer: Depth buffer formats must match"
|
||||
" if selected.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mask & LOCAL_GL_STENCIL_BUFFER_BIT &&
|
||||
dstStencilFormat != srcStencilFormat)
|
||||
{
|
||||
ErrorInvalidOperation("blitFramebuffer: Stencil buffer formats must"
|
||||
" match if selected.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (dstSamples != 1) {
|
||||
ErrorInvalidOperation("blitFramebuffer: DRAW_FRAMEBUFFER may not have"
|
||||
" multiple samples.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (srcSamples != 1) {
|
||||
if (mask & LOCAL_GL_COLOR_BUFFER_BIT &&
|
||||
dstColorFormat != srcColorFormat)
|
||||
{
|
||||
ErrorInvalidOperation("blitFramebuffer: Color buffer formats must"
|
||||
" match if selected, when reading from a"
|
||||
" multisampled source.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (dstX0 != srcX0 ||
|
||||
dstX1 != srcX1 ||
|
||||
dstY0 != srcY0 ||
|
||||
dstY1 != srcY1)
|
||||
{
|
||||
ErrorInvalidOperation("blitFramebuffer: If the source is"
|
||||
" multisampled, then the source and dest"
|
||||
" regions must match exactly.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1,
|
||||
dstX0, dstY0, dstX1, dstY1,
|
||||
mask, filter);
|
||||
}
|
||||
|
||||
void
|
||||
@ -57,16 +366,39 @@ WebGL2Context::InvalidateFramebuffer(GLenum target, const dom::Sequence<GLenum>&
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
if (target != LOCAL_GL_FRAMEBUFFER)
|
||||
return ErrorInvalidEnumInfo("invalidateFramebuffer: target", target);
|
||||
for (size_t i = 0; i < attachments.Length(); i++) {
|
||||
if (!ValidateFramebufferAttachment(attachments[i], "invalidateFramebuffer"))
|
||||
return;
|
||||
if (!ValidateFramebufferTarget(target, "framebufferRenderbuffer"))
|
||||
return;
|
||||
|
||||
const WebGLFramebuffer* fb;
|
||||
bool isDefaultFB;
|
||||
switch (target) {
|
||||
case LOCAL_GL_FRAMEBUFFER:
|
||||
case LOCAL_GL_DRAW_FRAMEBUFFER:
|
||||
fb = mBoundDrawFramebuffer;
|
||||
isDefaultFB = gl->Screen()->IsDrawFramebufferDefault();
|
||||
break;
|
||||
|
||||
case LOCAL_GL_READ_FRAMEBUFFER:
|
||||
fb = mBoundReadFramebuffer;
|
||||
isDefaultFB = gl->Screen()->IsReadFramebufferDefault();
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Bad target.");
|
||||
}
|
||||
|
||||
if (!mBoundFramebuffer && !gl->IsDrawingToDefaultFramebuffer()) {
|
||||
for (size_t i = 0; i < attachments.Length(); i++) {
|
||||
if (!ValidateFramebufferAttachment(fb, attachments[i],
|
||||
"invalidateFramebuffer"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fb && !isDefaultFB) {
|
||||
dom::Sequence<GLenum> tmpAttachments;
|
||||
TranslateDefaultAttachments(attachments, &tmpAttachments);
|
||||
gl->fInvalidateFramebuffer(target, tmpAttachments.Length(), tmpAttachments.Elements());
|
||||
@ -81,16 +413,39 @@ WebGL2Context::InvalidateSubFramebuffer(GLenum target, const dom::Sequence<GLenu
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
if (target != LOCAL_GL_FRAMEBUFFER)
|
||||
return ErrorInvalidEnumInfo("invalidateFramebuffer: target", target);
|
||||
for (size_t i = 0; i < attachments.Length(); i++) {
|
||||
if (!ValidateFramebufferAttachment(attachments[i], "invalidateSubFramebuffer"))
|
||||
return;
|
||||
if (!ValidateFramebufferTarget(target, "framebufferRenderbuffer"))
|
||||
return;
|
||||
|
||||
const WebGLFramebuffer* fb;
|
||||
bool isDefaultFB;
|
||||
switch (target) {
|
||||
case LOCAL_GL_FRAMEBUFFER:
|
||||
case LOCAL_GL_DRAW_FRAMEBUFFER:
|
||||
fb = mBoundDrawFramebuffer;
|
||||
isDefaultFB = gl->Screen()->IsDrawFramebufferDefault();
|
||||
break;
|
||||
|
||||
case LOCAL_GL_READ_FRAMEBUFFER:
|
||||
fb = mBoundReadFramebuffer;
|
||||
isDefaultFB = gl->Screen()->IsReadFramebufferDefault();
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Bad target.");
|
||||
}
|
||||
|
||||
if (!mBoundFramebuffer && !gl->IsDrawingToDefaultFramebuffer()) {
|
||||
for (size_t i = 0; i < attachments.Length(); i++) {
|
||||
if (!ValidateFramebufferAttachment(fb, attachments[i],
|
||||
"invalidateSubFramebuffer"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fb && !isDefaultFB) {
|
||||
dom::Sequence<GLenum> tmpAttachments;
|
||||
TranslateDefaultAttachments(attachments, &tmpAttachments);
|
||||
gl->fInvalidateSubFramebuffer(target, tmpAttachments.Length(), tmpAttachments.Elements(),
|
||||
|
@ -330,7 +330,8 @@ WebGLContext::DestroyResourcesAndContext()
|
||||
mBoundUniformBuffer = nullptr;
|
||||
mCurrentProgram = nullptr;
|
||||
mActiveProgramLinkInfo = nullptr;
|
||||
mBoundFramebuffer = nullptr;
|
||||
mBoundDrawFramebuffer = nullptr;
|
||||
mBoundReadFramebuffer = nullptr;
|
||||
mActiveOcclusionQuery = nullptr;
|
||||
mBoundRenderbuffer = nullptr;
|
||||
mBoundVertexArray = nullptr;
|
||||
@ -1887,7 +1888,8 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLContext,
|
||||
mBoundTransformFeedbackBuffer,
|
||||
mBoundUniformBuffer,
|
||||
mCurrentProgram,
|
||||
mBoundFramebuffer,
|
||||
mBoundDrawFramebuffer,
|
||||
mBoundReadFramebuffer,
|
||||
mBoundRenderbuffer,
|
||||
mBoundVertexArray,
|
||||
mDefaultVertexArray,
|
||||
|
@ -317,7 +317,8 @@ public:
|
||||
uint32_t Generation() { return mGeneration.value(); }
|
||||
|
||||
// Returns null if the current bound FB is not likely complete.
|
||||
const WebGLRectangleObject* CurValidFBRectObject() const;
|
||||
const WebGLRectangleObject* CurValidDrawFBRectObject() const;
|
||||
const WebGLRectangleObject* CurValidReadFBRectObject() const;
|
||||
|
||||
static const size_t kMaxColorAttachments = 16;
|
||||
|
||||
@ -422,7 +423,8 @@ public:
|
||||
GLint level);
|
||||
|
||||
// Framebuffer validation
|
||||
bool ValidateFramebufferAttachment(GLenum attachment, const char* funcName);
|
||||
bool ValidateFramebufferAttachment(const WebGLFramebuffer* fb,
|
||||
GLenum attachment, const char* funcName);
|
||||
|
||||
void FrontFace(GLenum mode);
|
||||
void GenerateMipmap(GLenum target);
|
||||
@ -1419,7 +1421,10 @@ protected:
|
||||
|
||||
uint32_t mMaxFramebufferColorAttachments;
|
||||
|
||||
WebGLRefPtr<WebGLFramebuffer> mBoundFramebuffer;
|
||||
bool ValidateFramebufferTarget(GLenum target, const char* const info);
|
||||
|
||||
WebGLRefPtr<WebGLFramebuffer> mBoundDrawFramebuffer;
|
||||
WebGLRefPtr<WebGLFramebuffer> mBoundReadFramebuffer;
|
||||
WebGLRefPtr<WebGLRenderbuffer> mBoundRenderbuffer;
|
||||
WebGLRefPtr<WebGLTransformFeedback> mBoundTransformFeedback;
|
||||
WebGLRefPtr<WebGLVertexArray> mBoundVertexArray;
|
||||
|
@ -98,8 +98,8 @@ bool WebGLContext::DrawArrays_check(GLint first, GLsizei count, GLsizei primcoun
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
if (mBoundFramebuffer) {
|
||||
if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
|
||||
if (mBoundDrawFramebuffer) {
|
||||
if (!mBoundDrawFramebuffer->CheckAndInitializeAttachments()) {
|
||||
ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
|
||||
return false;
|
||||
}
|
||||
@ -279,8 +279,8 @@ WebGLContext::DrawElements_check(GLsizei count, GLenum type,
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
if (mBoundFramebuffer) {
|
||||
if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
|
||||
if (mBoundDrawFramebuffer) {
|
||||
if (!mBoundDrawFramebuffer->CheckAndInitializeAttachments()) {
|
||||
ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
|
||||
return false;
|
||||
}
|
||||
@ -369,7 +369,7 @@ void WebGLContext::Draw_cleanup()
|
||||
UndoFakeVertexAttrib0();
|
||||
UnbindFakeBlackTextures();
|
||||
|
||||
if (!mBoundFramebuffer) {
|
||||
if (!mBoundDrawFramebuffer) {
|
||||
Invalidate();
|
||||
mShouldPresent = true;
|
||||
MOZ_ASSERT(!mBackbufferNeedsClear);
|
||||
@ -387,7 +387,7 @@ void WebGLContext::Draw_cleanup()
|
||||
}
|
||||
|
||||
// Let's check the viewport
|
||||
const WebGLRectangleObject* rect = CurValidFBRectObject();
|
||||
const WebGLRectangleObject* rect = CurValidDrawFBRectObject();
|
||||
if (rect) {
|
||||
if (mViewportWidth > rect->Width() ||
|
||||
mViewportHeight > rect->Height())
|
||||
|
@ -29,8 +29,8 @@ WebGLContext::Clear(GLbitfield mask)
|
||||
GenerateWarning("Calling gl.clear() with RASTERIZER_DISCARD enabled has no effects.");
|
||||
}
|
||||
|
||||
if (mBoundFramebuffer) {
|
||||
if (!mBoundFramebuffer->CheckAndInitializeAttachments())
|
||||
if (mBoundDrawFramebuffer) {
|
||||
if (!mBoundDrawFramebuffer->CheckAndInitializeAttachments())
|
||||
return ErrorInvalidFramebufferOperation("clear: incomplete framebuffer");
|
||||
|
||||
gl->fClear(mask);
|
||||
@ -131,12 +131,11 @@ WebGLContext::DrawBuffers(const dom::Sequence<GLenum>& buffers)
|
||||
|
||||
const size_t buffersLength = buffers.Length();
|
||||
|
||||
if (buffersLength == 0) {
|
||||
if (!buffersLength) {
|
||||
return ErrorInvalidValue("drawBuffers: invalid <buffers> (buffers must not be empty)");
|
||||
}
|
||||
|
||||
if (mBoundFramebuffer == 0)
|
||||
{
|
||||
if (!mBoundDrawFramebuffer) {
|
||||
// OK: we are rendering in the default framebuffer
|
||||
|
||||
/* EXT_draw_buffers :
|
||||
|
@ -55,24 +55,37 @@ using namespace mozilla::dom;
|
||||
using namespace mozilla::gfx;
|
||||
using namespace mozilla::gl;
|
||||
|
||||
const WebGLRectangleObject*
|
||||
WebGLContext::CurValidFBRectObject() const
|
||||
static const WebGLRectangleObject*
|
||||
CurValidFBRectObject(const WebGLContext* webgl,
|
||||
const WebGLFramebuffer* boundFB)
|
||||
{
|
||||
const WebGLRectangleObject* rect = nullptr;
|
||||
|
||||
if (mBoundFramebuffer) {
|
||||
if (boundFB) {
|
||||
// We don't really need to ask the driver.
|
||||
// Use 'precheck' to just check that our internal state looks good.
|
||||
FBStatus precheckStatus = mBoundFramebuffer->PrecheckFramebufferStatus();
|
||||
FBStatus precheckStatus = boundFB->PrecheckFramebufferStatus();
|
||||
if (precheckStatus == LOCAL_GL_FRAMEBUFFER_COMPLETE)
|
||||
rect = &mBoundFramebuffer->RectangleObject();
|
||||
rect = &boundFB->RectangleObject();
|
||||
} else {
|
||||
rect = static_cast<const WebGLRectangleObject*>(this);
|
||||
rect = static_cast<const WebGLRectangleObject*>(webgl);
|
||||
}
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
const WebGLRectangleObject*
|
||||
WebGLContext::CurValidDrawFBRectObject() const
|
||||
{
|
||||
return CurValidFBRectObject(this, mBoundDrawFramebuffer);
|
||||
}
|
||||
|
||||
const WebGLRectangleObject*
|
||||
WebGLContext::CurValidReadFBRectObject() const
|
||||
{
|
||||
return CurValidFBRectObject(this, mBoundReadFramebuffer);
|
||||
}
|
||||
|
||||
//
|
||||
// WebGL API
|
||||
//
|
||||
@ -132,8 +145,8 @@ WebGLContext::BindFramebuffer(GLenum target, WebGLFramebuffer* wfb)
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (target != LOCAL_GL_FRAMEBUFFER)
|
||||
return ErrorInvalidEnum("bindFramebuffer: target must be GL_FRAMEBUFFER");
|
||||
if (!ValidateFramebufferTarget(target, "bindFramebuffer"))
|
||||
return;
|
||||
|
||||
if (!ValidateObjectAllowDeletedOrNull("bindFramebuffer", wfb))
|
||||
return;
|
||||
@ -152,7 +165,20 @@ WebGLContext::BindFramebuffer(GLenum target, WebGLFramebuffer* wfb)
|
||||
gl->fBindFramebuffer(target, framebuffername);
|
||||
}
|
||||
|
||||
mBoundFramebuffer = wfb;
|
||||
switch (target) {
|
||||
case LOCAL_GL_FRAMEBUFFER:
|
||||
mBoundDrawFramebuffer = wfb;
|
||||
mBoundReadFramebuffer = wfb;
|
||||
break;
|
||||
case LOCAL_GL_DRAW_FRAMEBUFFER:
|
||||
mBoundDrawFramebuffer = wfb;
|
||||
break;
|
||||
case LOCAL_GL_READ_FRAMEBUFFER:
|
||||
mBoundReadFramebuffer = wfb;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -319,30 +345,38 @@ WebGLContext::CheckFramebufferStatus(GLenum target)
|
||||
if (IsContextLost())
|
||||
return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED;
|
||||
|
||||
if (target != LOCAL_GL_FRAMEBUFFER) {
|
||||
ErrorInvalidEnum("checkFramebufferStatus: target must be FRAMEBUFFER");
|
||||
if (!ValidateFramebufferTarget(target, "invalidateFramebuffer"))
|
||||
return 0;
|
||||
|
||||
WebGLFramebuffer* fb;
|
||||
switch (target) {
|
||||
case LOCAL_GL_FRAMEBUFFER:
|
||||
case LOCAL_GL_DRAW_FRAMEBUFFER:
|
||||
fb = mBoundDrawFramebuffer;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_READ_FRAMEBUFFER:
|
||||
fb = mBoundReadFramebuffer;
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Bad target.");
|
||||
}
|
||||
|
||||
if (!mBoundFramebuffer)
|
||||
if (!fb)
|
||||
return LOCAL_GL_FRAMEBUFFER_COMPLETE;
|
||||
|
||||
return mBoundFramebuffer->CheckFramebufferStatus().get();
|
||||
return fb->CheckFramebufferStatus().get();
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::CopyTexSubImage2D_base(TexImageTarget texImageTarget,
|
||||
GLint level,
|
||||
WebGLContext::CopyTexSubImage2D_base(TexImageTarget texImageTarget, GLint level,
|
||||
TexInternalFormat internalformat,
|
||||
GLint xoffset,
|
||||
GLint yoffset,
|
||||
GLint x,
|
||||
GLint y,
|
||||
GLsizei width,
|
||||
GLsizei height,
|
||||
GLint xoffset, GLint yoffset, GLint x,
|
||||
GLint y, GLsizei width, GLsizei height,
|
||||
bool sub)
|
||||
{
|
||||
const WebGLRectangleObject* framebufferRect = CurValidFBRectObject();
|
||||
const WebGLRectangleObject* framebufferRect = CurValidReadFBRectObject();
|
||||
GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0;
|
||||
GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0;
|
||||
|
||||
@ -367,7 +401,7 @@ WebGLContext::CopyTexSubImage2D_base(TexImageTarget texImageTarget,
|
||||
if (!ValidateCopyTexImage(internalformat.get(), func, dims))
|
||||
return;
|
||||
|
||||
if (!mBoundFramebuffer)
|
||||
if (!mBoundReadFramebuffer)
|
||||
ClearBackbufferIfNeeded();
|
||||
|
||||
MakeContextCurrent();
|
||||
@ -384,8 +418,8 @@ WebGLContext::CopyTexSubImage2D_base(TexImageTarget texImageTarget,
|
||||
}
|
||||
|
||||
TexType framebuffertype = LOCAL_GL_NONE;
|
||||
if (mBoundFramebuffer) {
|
||||
TexInternalFormat framebuffereffectiveformat = mBoundFramebuffer->ColorAttachment(0).EffectiveInternalFormat();
|
||||
if (mBoundReadFramebuffer) {
|
||||
TexInternalFormat framebuffereffectiveformat = mBoundReadFramebuffer->ColorAttachment(0).EffectiveInternalFormat();
|
||||
framebuffertype = TypeFromInternalFormat(framebuffereffectiveformat);
|
||||
} else {
|
||||
// FIXME - here we're assuming that the default framebuffer is backed by UNSIGNED_BYTE
|
||||
@ -509,7 +543,7 @@ WebGLContext::CopyTexImage2D(GLenum rawTexImgTarget,
|
||||
if (!ValidateCopyTexImage(internalformat, func, dims))
|
||||
return;
|
||||
|
||||
if (!mBoundFramebuffer)
|
||||
if (!mBoundReadFramebuffer)
|
||||
ClearBackbufferIfNeeded();
|
||||
|
||||
CopyTexSubImage2D_base(rawTexImgTarget, level, internalformat, 0, 0, x, y, width, height, false);
|
||||
@ -573,7 +607,7 @@ WebGLContext::CopyTexSubImage2D(GLenum rawTexImgTarget,
|
||||
if (yoffset + height > texHeight || yoffset + height < 0)
|
||||
return ErrorInvalidValue("copyTexSubImage2D: yoffset+height is too large");
|
||||
|
||||
if (!mBoundFramebuffer)
|
||||
if (!mBoundReadFramebuffer)
|
||||
ClearBackbufferIfNeeded();
|
||||
|
||||
if (imageInfo.HasUninitializedImageData()) {
|
||||
@ -649,9 +683,18 @@ WebGLContext::DeleteFramebuffer(WebGLFramebuffer* fbuf)
|
||||
|
||||
fbuf->RequestDelete();
|
||||
|
||||
if (mBoundFramebuffer == fbuf)
|
||||
BindFramebuffer(LOCAL_GL_FRAMEBUFFER,
|
||||
if (mBoundReadFramebuffer == mBoundDrawFramebuffer) {
|
||||
if (mBoundDrawFramebuffer == fbuf) {
|
||||
BindFramebuffer(LOCAL_GL_FRAMEBUFFER,
|
||||
static_cast<WebGLFramebuffer*>(nullptr));
|
||||
}
|
||||
} else if (mBoundDrawFramebuffer == fbuf) {
|
||||
BindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER,
|
||||
static_cast<WebGLFramebuffer*>(nullptr));
|
||||
} else if (mBoundReadFramebuffer == fbuf) {
|
||||
BindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER,
|
||||
static_cast<WebGLFramebuffer*>(nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -666,8 +709,11 @@ WebGLContext::DeleteRenderbuffer(WebGLRenderbuffer* rbuf)
|
||||
if (!rbuf || rbuf->IsDeleted())
|
||||
return;
|
||||
|
||||
if (mBoundFramebuffer)
|
||||
mBoundFramebuffer->DetachRenderbuffer(rbuf);
|
||||
if (mBoundDrawFramebuffer)
|
||||
mBoundDrawFramebuffer->DetachRenderbuffer(rbuf);
|
||||
|
||||
if (mBoundReadFramebuffer)
|
||||
mBoundReadFramebuffer->DetachRenderbuffer(rbuf);
|
||||
|
||||
// Invalidate framebuffer status cache
|
||||
rbuf->NotifyFBsStatusChanged();
|
||||
@ -691,8 +737,11 @@ WebGLContext::DeleteTexture(WebGLTexture* tex)
|
||||
if (!tex || tex->IsDeleted())
|
||||
return;
|
||||
|
||||
if (mBoundFramebuffer)
|
||||
mBoundFramebuffer->DetachTexture(tex);
|
||||
if (mBoundDrawFramebuffer)
|
||||
mBoundDrawFramebuffer->DetachTexture(tex);
|
||||
|
||||
if (mBoundReadFramebuffer)
|
||||
mBoundReadFramebuffer->DetachTexture(tex);
|
||||
|
||||
// Invalidate framebuffer status cache
|
||||
tex->NotifyFBsStatusChanged();
|
||||
@ -792,19 +841,41 @@ WebGLContext::FramebufferRenderbuffer(GLenum target, GLenum attachment,
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!mBoundFramebuffer)
|
||||
return ErrorInvalidOperation("framebufferRenderbuffer: cannot modify framebuffer 0");
|
||||
|
||||
if (target != LOCAL_GL_FRAMEBUFFER)
|
||||
return ErrorInvalidEnumInfo("framebufferRenderbuffer: target", target);
|
||||
|
||||
if (rbtarget != LOCAL_GL_RENDERBUFFER)
|
||||
return ErrorInvalidEnumInfo("framebufferRenderbuffer: renderbuffer target:", rbtarget);
|
||||
|
||||
if (!ValidateFramebufferAttachment(attachment, "framebufferRenderbuffer"))
|
||||
if (!ValidateFramebufferTarget(target, "framebufferRenderbuffer"))
|
||||
return;
|
||||
|
||||
return mBoundFramebuffer->FramebufferRenderbuffer(attachment, rbtarget, wrb);
|
||||
WebGLFramebuffer* fb;
|
||||
switch (target) {
|
||||
case LOCAL_GL_FRAMEBUFFER:
|
||||
case LOCAL_GL_DRAW_FRAMEBUFFER:
|
||||
fb = mBoundDrawFramebuffer;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_READ_FRAMEBUFFER:
|
||||
fb = mBoundReadFramebuffer;
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Bad target.");
|
||||
}
|
||||
|
||||
if (!fb) {
|
||||
return ErrorInvalidOperation("framebufferRenderbuffer: cannot modify"
|
||||
" framebuffer 0.");
|
||||
}
|
||||
|
||||
if (rbtarget != LOCAL_GL_RENDERBUFFER) {
|
||||
return ErrorInvalidEnumInfo("framebufferRenderbuffer: rbtarget:",
|
||||
rbtarget);
|
||||
}
|
||||
|
||||
if (!ValidateFramebufferAttachment(fb, attachment,
|
||||
"framebufferRenderbuffer"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
fb->FramebufferRenderbuffer(attachment, rbtarget, wrb);
|
||||
}
|
||||
|
||||
void
|
||||
@ -817,23 +888,41 @@ WebGLContext::FramebufferTexture2D(GLenum target,
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!mBoundFramebuffer)
|
||||
return ErrorInvalidOperation("framebufferRenderbuffer: cannot modify framebuffer 0");
|
||||
if (!ValidateFramebufferTarget(target, "framebufferTexture2D"))
|
||||
return;
|
||||
|
||||
if (target != LOCAL_GL_FRAMEBUFFER)
|
||||
return ErrorInvalidEnumInfo("framebufferTexture2D: target", target);
|
||||
WebGLFramebuffer* fb;
|
||||
switch (target) {
|
||||
case LOCAL_GL_FRAMEBUFFER:
|
||||
case LOCAL_GL_DRAW_FRAMEBUFFER:
|
||||
fb = mBoundDrawFramebuffer;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_READ_FRAMEBUFFER:
|
||||
fb = mBoundReadFramebuffer;
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Bad target.");
|
||||
}
|
||||
|
||||
if (!fb) {
|
||||
return ErrorInvalidOperation("framebufferTexture2D: cannot modify"
|
||||
" framebuffer 0.");
|
||||
}
|
||||
|
||||
if (textarget != LOCAL_GL_TEXTURE_2D &&
|
||||
(textarget < LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X ||
|
||||
textarget > LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))
|
||||
{
|
||||
return ErrorInvalidEnumInfo("framebufferTexture2D: invalid texture target", textarget);
|
||||
return ErrorInvalidEnumInfo("framebufferTexture2D: textarget:",
|
||||
textarget);
|
||||
}
|
||||
|
||||
if (!ValidateFramebufferAttachment(attachment, "framebufferTexture2D"))
|
||||
if (!ValidateFramebufferAttachment(fb, attachment, "framebufferTexture2D"))
|
||||
return;
|
||||
|
||||
return mBoundFramebuffer->FramebufferTexture2D(attachment, textarget, tobj, level);
|
||||
fb->FramebufferTexture2D(attachment, textarget, tobj, level);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1022,25 +1111,42 @@ WebGLContext::GetFramebufferAttachmentParameter(JSContext* cx,
|
||||
if (IsContextLost())
|
||||
return JS::NullValue();
|
||||
|
||||
if (target != LOCAL_GL_FRAMEBUFFER) {
|
||||
ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: target", target);
|
||||
if (!ValidateFramebufferTarget(target, "getFramebufferAttachmentParameter"))
|
||||
return JS::NullValue();
|
||||
|
||||
WebGLFramebuffer* fb;
|
||||
switch (target) {
|
||||
case LOCAL_GL_FRAMEBUFFER:
|
||||
case LOCAL_GL_DRAW_FRAMEBUFFER:
|
||||
fb = mBoundDrawFramebuffer;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_READ_FRAMEBUFFER:
|
||||
fb = mBoundReadFramebuffer;
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Bad target.");
|
||||
}
|
||||
|
||||
if (!fb) {
|
||||
ErrorInvalidOperation("getFramebufferAttachmentParameter: cannot query"
|
||||
" framebuffer 0.");
|
||||
return JS::NullValue();
|
||||
}
|
||||
|
||||
if (!mBoundFramebuffer) {
|
||||
ErrorInvalidOperation("getFramebufferAttachmentParameter: cannot query framebuffer 0");
|
||||
if (!ValidateFramebufferAttachment(fb, attachment,
|
||||
"getFramebufferAttachmentParameter"))
|
||||
{
|
||||
return JS::NullValue();
|
||||
}
|
||||
|
||||
if (!ValidateFramebufferAttachment(attachment, "getFramebufferAttachmentParameter"))
|
||||
return JS::NullValue();
|
||||
|
||||
if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers))
|
||||
mBoundFramebuffer->EnsureColorAttachments(attachment - LOCAL_GL_COLOR_ATTACHMENT0);
|
||||
fb->EnsureColorAttachments(attachment - LOCAL_GL_COLOR_ATTACHMENT0);
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
const WebGLFramebuffer::Attachment& fba = mBoundFramebuffer->GetAttachment(attachment);
|
||||
const WebGLFramebuffer::Attachment& fba = fb->GetAttachment(attachment);
|
||||
|
||||
if (fba.Renderbuffer()) {
|
||||
switch (pname) {
|
||||
@ -1778,7 +1884,7 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
||||
if (pixels.IsNull())
|
||||
return ErrorInvalidValue("readPixels: null destination buffer");
|
||||
|
||||
const WebGLRectangleObject* framebufferRect = CurValidFBRectObject();
|
||||
const WebGLRectangleObject* framebufferRect = CurValidReadFBRectObject();
|
||||
GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0;
|
||||
GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0;
|
||||
|
||||
@ -1866,11 +1972,11 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
||||
}
|
||||
|
||||
bool isSourceTypeFloat = false;
|
||||
if (mBoundFramebuffer &&
|
||||
mBoundFramebuffer->ColorAttachmentCount() &&
|
||||
mBoundFramebuffer->ColorAttachment(0).IsDefined())
|
||||
if (mBoundReadFramebuffer &&
|
||||
mBoundReadFramebuffer->ColorAttachmentCount() &&
|
||||
mBoundReadFramebuffer->ColorAttachment(0).IsDefined())
|
||||
{
|
||||
isSourceTypeFloat = mBoundFramebuffer->ColorAttachment(0).IsReadableFloat();
|
||||
isSourceTypeFloat = mBoundReadFramebuffer->ColorAttachment(0).IsReadableFloat();
|
||||
}
|
||||
|
||||
if (isReadTypeFloat != isSourceTypeFloat)
|
||||
@ -1879,13 +1985,13 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
||||
// Check the format and type params to assure they are an acceptable pair (as per spec)
|
||||
MakeContextCurrent();
|
||||
|
||||
if (mBoundFramebuffer) {
|
||||
if (mBoundReadFramebuffer) {
|
||||
// prevent readback of arbitrary video memory through uninitialized renderbuffers!
|
||||
if (!mBoundFramebuffer->CheckAndInitializeAttachments())
|
||||
if (!mBoundReadFramebuffer->CheckAndInitializeAttachments())
|
||||
return ErrorInvalidFramebufferOperation("readPixels: incomplete framebuffer");
|
||||
|
||||
GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
|
||||
if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) {
|
||||
if (!mBoundReadFramebuffer->HasCompletePlanes(readPlaneBits)) {
|
||||
return ErrorInvalidOperation("readPixels: Read source attachment doesn't have the"
|
||||
" correct color/depth/stencil type.");
|
||||
}
|
||||
@ -2008,8 +2114,8 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
||||
return;
|
||||
|
||||
bool needAlphaFilled;
|
||||
if (mBoundFramebuffer) {
|
||||
needAlphaFilled = !mBoundFramebuffer->ColorAttachment(0).HasAlpha();
|
||||
if (mBoundReadFramebuffer) {
|
||||
needAlphaFilled = !mBoundReadFramebuffer->ColorAttachment(0).HasAlpha();
|
||||
} else {
|
||||
needAlphaFilled = !mOptions.alpha;
|
||||
}
|
||||
|
@ -74,15 +74,15 @@ bool
|
||||
WebGLContext::GetStencilBits(GLint* out_stencilBits)
|
||||
{
|
||||
*out_stencilBits = 0;
|
||||
if (mBoundFramebuffer) {
|
||||
if (mBoundFramebuffer->HasDepthStencilConflict()) {
|
||||
if (mBoundDrawFramebuffer) {
|
||||
if (mBoundDrawFramebuffer->HasDepthStencilConflict()) {
|
||||
// Error, we don't know which stencil buffer's bits to use
|
||||
ErrorInvalidFramebufferOperation("getParameter: framebuffer has two stencil buffers bound");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mBoundFramebuffer->StencilAttachment().IsDefined() ||
|
||||
mBoundFramebuffer->DepthStencilAttachment().IsDefined())
|
||||
if (mBoundDrawFramebuffer->StencilAttachment().IsDefined() ||
|
||||
mBoundDrawFramebuffer->DepthStencilAttachment().IsDefined())
|
||||
{
|
||||
*out_stencilBits = 8;
|
||||
}
|
||||
@ -150,7 +150,7 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
|
||||
} else if (pname >= LOCAL_GL_DRAW_BUFFER0 &&
|
||||
pname < GLenum(LOCAL_GL_DRAW_BUFFER0 + mGLMaxDrawBuffers))
|
||||
{
|
||||
if (mBoundFramebuffer) {
|
||||
if (mBoundDrawFramebuffer) {
|
||||
GLint iv = 0;
|
||||
gl->fGetIntegerv(pname, &iv);
|
||||
return JS::Int32Value(iv);
|
||||
@ -190,6 +190,10 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
|
||||
case LOCAL_GL_TEXTURE_BINDING_3D: {
|
||||
return WebGLObjectAsJSValue(cx, mBound3DTextures[mActiveTexture].get(), rv);
|
||||
}
|
||||
|
||||
// DRAW_FRAMEBUFFER_BINDING is the same as FRAMEBUFFER_BINDING.
|
||||
case LOCAL_GL_READ_FRAMEBUFFER_BINDING:
|
||||
return WebGLObjectAsJSValue(cx, mBoundReadFramebuffer.get(), rv);
|
||||
}
|
||||
}
|
||||
|
||||
@ -509,8 +513,9 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
|
||||
return WebGLObjectAsJSValue(cx, mBoundRenderbuffer.get(), rv);
|
||||
}
|
||||
|
||||
// DRAW_FRAMEBUFFER_BINDING is the same as FRAMEBUFFER_BINDING.
|
||||
case LOCAL_GL_FRAMEBUFFER_BINDING: {
|
||||
return WebGLObjectAsJSValue(cx, mBoundFramebuffer.get(), rv);
|
||||
return WebGLObjectAsJSValue(cx, mBoundDrawFramebuffer.get(), rv);
|
||||
}
|
||||
|
||||
case LOCAL_GL_CURRENT_PROGRAM: {
|
||||
|
@ -598,11 +598,14 @@ WebGLContext::EnumName(GLenum glenum)
|
||||
XX(DEPTH_COMPONENT32);
|
||||
XX(DEPTH_STENCIL);
|
||||
XX(DEPTH24_STENCIL8);
|
||||
XX(DRAW_FRAMEBUFFER);
|
||||
XX(ETC1_RGB8_OES);
|
||||
XX(FLOAT);
|
||||
XX(FRAMEBUFFER);
|
||||
XX(HALF_FLOAT);
|
||||
XX(LUMINANCE);
|
||||
XX(LUMINANCE_ALPHA);
|
||||
XX(READ_FRAMEBUFFER);
|
||||
XX(RGB);
|
||||
XX(RGB16F);
|
||||
XX(RGB32F);
|
||||
@ -771,8 +774,6 @@ WebGLContext::EnumName(GLenum glenum)
|
||||
XX(DEPTH_STENCIL_ATTACHMENT);
|
||||
XX(UNSIGNED_NORMALIZED);
|
||||
XX(DRAW_FRAMEBUFFER_BINDING);
|
||||
XX(READ_FRAMEBUFFER);
|
||||
XX(DRAW_FRAMEBUFFER);
|
||||
XX(READ_FRAMEBUFFER_BINDING);
|
||||
XX(RENDERBUFFER_SAMPLES);
|
||||
XX(FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER);
|
||||
@ -1028,10 +1029,21 @@ WebGLContext::AssertCachedBindings()
|
||||
}
|
||||
|
||||
// Bound object state
|
||||
GLuint bound = mBoundFramebuffer ? mBoundFramebuffer->GLName() : 0;
|
||||
AssertUintParamCorrect(gl, LOCAL_GL_FRAMEBUFFER_BINDING, bound);
|
||||
if (IsWebGL2()) {
|
||||
GLuint bound = mBoundDrawFramebuffer ? mBoundDrawFramebuffer->GLName()
|
||||
: 0;
|
||||
AssertUintParamCorrect(gl, LOCAL_GL_DRAW_FRAMEBUFFER_BINDING, bound);
|
||||
|
||||
bound = mCurrentProgram ? mCurrentProgram->mGLName : 0;
|
||||
bound = mBoundReadFramebuffer ? mBoundReadFramebuffer->GLName() : 0;
|
||||
AssertUintParamCorrect(gl, LOCAL_GL_READ_FRAMEBUFFER_BINDING, bound);
|
||||
} else {
|
||||
MOZ_ASSERT(mBoundDrawFramebuffer == mBoundReadFramebuffer);
|
||||
GLuint bound = mBoundDrawFramebuffer ? mBoundDrawFramebuffer->GLName()
|
||||
: 0;
|
||||
AssertUintParamCorrect(gl, LOCAL_GL_FRAMEBUFFER_BINDING, bound);
|
||||
}
|
||||
|
||||
GLuint bound = mCurrentProgram ? mCurrentProgram->GLName : 0;
|
||||
AssertUintParamCorrect(gl, LOCAL_GL_CURRENT_PROGRAM, bound);
|
||||
|
||||
// Textures
|
||||
|
@ -373,10 +373,10 @@ WebGLContext::ValidateDrawModeEnum(GLenum mode, const char* info)
|
||||
* be one of depth/stencil/depth_stencil/color attachment.
|
||||
*/
|
||||
bool
|
||||
WebGLContext::ValidateFramebufferAttachment(GLenum attachment,
|
||||
WebGLContext::ValidateFramebufferAttachment(const WebGLFramebuffer* fb, GLenum attachment,
|
||||
const char* funcName)
|
||||
{
|
||||
if (!mBoundFramebuffer) {
|
||||
if (!fb) {
|
||||
switch (attachment) {
|
||||
case LOCAL_GL_COLOR:
|
||||
case LOCAL_GL_DEPTH:
|
||||
@ -1285,27 +1285,26 @@ WebGLContext::ValidateCopyTexImage(GLenum format, WebGLTexImageFunc func,
|
||||
// Default framebuffer format
|
||||
GLenum fboFormat = mOptions.alpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
|
||||
|
||||
if (mBoundFramebuffer) {
|
||||
if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
|
||||
if (mBoundReadFramebuffer) {
|
||||
if (!mBoundReadFramebuffer->CheckAndInitializeAttachments()) {
|
||||
ErrorInvalidFramebufferOperation("%s: Incomplete framebuffer.",
|
||||
InfoFrom(func, dims));
|
||||
return false;
|
||||
}
|
||||
|
||||
GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
|
||||
if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) {
|
||||
if (!mBoundReadFramebuffer->HasCompletePlanes(readPlaneBits)) {
|
||||
ErrorInvalidOperation("%s: Read source attachment doesn't have the"
|
||||
" correct color/depth/stencil type.",
|
||||
InfoFrom(func, dims));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the correct format for the framebuffer, as it's not the default
|
||||
// one.
|
||||
// Get the correct format for the framebuffer, as it's not the default one.
|
||||
const WebGLFramebuffer::Attachment& color0 =
|
||||
mBoundFramebuffer->GetAttachment(LOCAL_GL_COLOR_ATTACHMENT0);
|
||||
mBoundReadFramebuffer->GetAttachment(LOCAL_GL_COLOR_ATTACHMENT0);
|
||||
|
||||
fboFormat = mBoundFramebuffer->GetFormatForAttachment(color0);
|
||||
fboFormat = mBoundReadFramebuffer->GetFormatForAttachment(color0);
|
||||
}
|
||||
|
||||
// Make sure the format of the framebuffer is a superset of the format
|
||||
@ -1774,7 +1773,8 @@ WebGLContext::InitAndValidateGL()
|
||||
mBoundTransformFeedbackBuffer = nullptr;
|
||||
mCurrentProgram = nullptr;
|
||||
|
||||
mBoundFramebuffer = nullptr;
|
||||
mBoundDrawFramebuffer = nullptr;
|
||||
mBoundReadFramebuffer = nullptr;
|
||||
mBoundRenderbuffer = nullptr;
|
||||
|
||||
MakeContextCurrent();
|
||||
@ -1966,4 +1966,32 @@ WebGLContext::InitAndValidateGL()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::ValidateFramebufferTarget(GLenum target,
|
||||
const char* const info)
|
||||
{
|
||||
bool isValid = true;
|
||||
switch (target) {
|
||||
case LOCAL_GL_FRAMEBUFFER:
|
||||
break;
|
||||
|
||||
case LOCAL_GL_DRAW_FRAMEBUFFER:
|
||||
case LOCAL_GL_READ_FRAMEBUFFER:
|
||||
isValid = IsWebGL2();
|
||||
break;
|
||||
|
||||
default:
|
||||
isValid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (MOZ_LIKELY(isValid)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ErrorInvalidEnum("%s: Invalid target: %s (0x%04x).", info, EnumName(target),
|
||||
target);
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -455,7 +455,8 @@ WebGLFramebuffer::FramebufferRenderbuffer(FBAttachment attachPoint,
|
||||
RBTarget rbtarget,
|
||||
WebGLRenderbuffer* rb)
|
||||
{
|
||||
MOZ_ASSERT(mContext->mBoundFramebuffer == this);
|
||||
MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
|
||||
mContext->mBoundReadFramebuffer == this);
|
||||
|
||||
if (!mContext->ValidateObjectAllowNull("framebufferRenderbuffer: renderbuffer",
|
||||
rb))
|
||||
@ -496,7 +497,8 @@ WebGLFramebuffer::FramebufferTexture2D(FBAttachment attachPoint,
|
||||
TexImageTarget texImageTarget,
|
||||
WebGLTexture* tex, GLint level)
|
||||
{
|
||||
MOZ_ASSERT(mContext->mBoundFramebuffer == this);
|
||||
MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
|
||||
mContext->mBoundReadFramebuffer == this);
|
||||
|
||||
if (!mContext->ValidateObjectAllowNull("framebufferTexture2D: texture",
|
||||
tex))
|
||||
@ -564,7 +566,7 @@ WebGLFramebuffer::GetAttachmentOrNull(FBAttachment attachPoint)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!mContext->ValidateFramebufferAttachment(attachPoint.get(),
|
||||
if (!mContext->ValidateFramebufferAttachment(this, attachPoint.get(),
|
||||
"getAttachmentOrNull"))
|
||||
{
|
||||
return nullptr;
|
||||
@ -593,7 +595,7 @@ WebGLFramebuffer::GetAttachment(FBAttachment attachPoint) const
|
||||
break;
|
||||
}
|
||||
|
||||
if (!mContext->ValidateFramebufferAttachment(attachPoint.get(),
|
||||
if (!mContext->ValidateFramebufferAttachment(this, attachPoint.get(),
|
||||
"getAttachment"))
|
||||
{
|
||||
MOZ_ASSERT(false);
|
||||
@ -766,7 +768,8 @@ WebGLFramebuffer::RectangleObject() const
|
||||
FBStatus
|
||||
WebGLFramebuffer::PrecheckFramebufferStatus() const
|
||||
{
|
||||
MOZ_ASSERT(mContext->mBoundFramebuffer == this);
|
||||
MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
|
||||
mContext->mBoundReadFramebuffer == this);
|
||||
|
||||
if (!HasDefinedAttachments())
|
||||
return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; // No attachments
|
||||
@ -809,7 +812,9 @@ WebGLFramebuffer::HasCompletePlanes(GLbitfield mask)
|
||||
if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE)
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(mContext->mBoundFramebuffer == this);
|
||||
MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
|
||||
mContext->mBoundReadFramebuffer == this);
|
||||
|
||||
bool hasPlanes = true;
|
||||
if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
|
||||
hasPlanes &= ColorAttachmentCount() &&
|
||||
@ -832,7 +837,8 @@ WebGLFramebuffer::HasCompletePlanes(GLbitfield mask)
|
||||
bool
|
||||
WebGLFramebuffer::CheckAndInitializeAttachments()
|
||||
{
|
||||
MOZ_ASSERT(mContext->mBoundFramebuffer == this);
|
||||
MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
|
||||
mContext->mBoundReadFramebuffer == this);
|
||||
|
||||
if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE)
|
||||
return false;
|
||||
|
@ -620,7 +620,11 @@ DrawBuffer::Create(GLContext* const gl,
|
||||
gl->fGenFramebuffers(1, &fb);
|
||||
gl->AttachBuffersToFB(0, colorMSRB, depthRB, stencilRB, fb);
|
||||
|
||||
UniquePtr<DrawBuffer> ret( new DrawBuffer(gl, size, fb, colorMSRB,
|
||||
GLsizei samples = formats.samples;
|
||||
if (!samples)
|
||||
samples = 1;
|
||||
|
||||
UniquePtr<DrawBuffer> ret( new DrawBuffer(gl, size, samples, fb, colorMSRB,
|
||||
depthRB, stencilRB) );
|
||||
|
||||
GLenum err = localError.GetError();
|
||||
|
@ -46,6 +46,7 @@ protected:
|
||||
GLContext* const mGL;
|
||||
public:
|
||||
const gfx::IntSize mSize;
|
||||
const GLsizei mSamples;
|
||||
const GLuint mFB;
|
||||
protected:
|
||||
const GLuint mColorMSRB;
|
||||
@ -54,12 +55,14 @@ protected:
|
||||
|
||||
DrawBuffer(GLContext* gl,
|
||||
const gfx::IntSize& size,
|
||||
GLsizei samples,
|
||||
GLuint fb,
|
||||
GLuint colorMSRB,
|
||||
GLuint depthRB,
|
||||
GLuint stencilRB)
|
||||
: mGL(gl)
|
||||
, mSize(size)
|
||||
, mSamples(samples)
|
||||
, mFB(fb)
|
||||
, mColorMSRB(colorMSRB)
|
||||
, mDepthRB(depthRB)
|
||||
@ -198,6 +201,13 @@ public:
|
||||
return mRead->mFB;
|
||||
}
|
||||
|
||||
GLsizei Samples() const {
|
||||
if (!mDraw)
|
||||
return 1;
|
||||
|
||||
return mDraw->mSamples;
|
||||
}
|
||||
|
||||
void DeletingFB(GLuint fb);
|
||||
|
||||
const gfx::IntSize& Size() const {
|
||||
|
Loading…
x
Reference in New Issue
Block a user