Bug 1321450 - Fix Invalidate[Sub]Framebuffer. - r=ethlin

MozReview-Commit-ID: nrZP6E412k
This commit is contained in:
Jeff Gilbert 2016-11-30 18:46:06 -08:00
Родитель a21a0e4cb3
Коммит 6e1880d435
6 изменённых файлов: 150 добавлений и 168 удалений

Просмотреть файл

@ -105,30 +105,119 @@ WebGL2Context::GetFramebufferAttachmentParameter(JSContext* cx,
out_error);
}
// Map attachments intended for the default buffer, to attachments for a non-
// default buffer.
////
static bool
TranslateDefaultAttachments(const dom::Sequence<GLenum>& in, dom::Sequence<GLenum>* out)
ValidateBackbufferAttachmentEnum(WebGLContext* webgl, const char* funcName,
GLenum attachment)
{
for (size_t i = 0; i < in.Length(); i++) {
switch (in[i]) {
switch (attachment) {
case LOCAL_GL_COLOR:
if (!out->AppendElement(LOCAL_GL_COLOR_ATTACHMENT0, fallible)) {
case LOCAL_GL_DEPTH:
case LOCAL_GL_STENCIL:
return true;
default:
webgl->ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x.",
funcName, attachment);
return false;
}
}
static bool
ValidateFramebufferAttachmentEnum(WebGLContext* webgl, const char* funcName,
GLenum attachment)
{
if (attachment >= LOCAL_GL_COLOR_ATTACHMENT0 &&
attachment <= webgl->LastColorAttachmentEnum())
{
return true;
}
switch (attachment) {
case LOCAL_GL_DEPTH_ATTACHMENT:
case LOCAL_GL_STENCIL_ATTACHMENT:
case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
return true;
default:
webgl->ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x.",
funcName, attachment);
return false;
}
}
bool
WebGLContext::ValidateInvalidateFramebuffer(const char* funcName, GLenum target,
const dom::Sequence<GLenum>& attachments,
ErrorResult* const out_rv,
std::vector<GLenum>* const scopedVector,
GLsizei* const out_glNumAttachments,
const GLenum** const out_glAttachments)
{
if (IsContextLost())
return false;
gl->MakeCurrent();
if (!ValidateFramebufferTarget(target, funcName))
return false;
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("GFX: Bad target.");
}
*out_glNumAttachments = attachments.Length();
*out_glAttachments = attachments.Elements();
if (fb) {
for (const auto& attachment : attachments) {
if (!ValidateFramebufferAttachmentEnum(this, funcName, attachment))
return false;
}
} else {
for (const auto& attachment : attachments) {
if (!ValidateBackbufferAttachmentEnum(this, funcName, attachment))
return false;
}
if (!isDefaultFB) {
MOZ_ASSERT(scopedVector->empty());
scopedVector->reserve(attachments.Length());
for (const auto& attachment : attachments) {
switch (attachment) {
case LOCAL_GL_COLOR:
scopedVector->push_back(LOCAL_GL_COLOR_ATTACHMENT0);
break;
case LOCAL_GL_DEPTH:
if (!out->AppendElement(LOCAL_GL_DEPTH_ATTACHMENT, fallible)) {
return false;
}
scopedVector->push_back(LOCAL_GL_DEPTH_ATTACHMENT);
break;
case LOCAL_GL_STENCIL:
if (!out->AppendElement(LOCAL_GL_STENCIL_ATTACHMENT, fallible)) {
return false;
}
scopedVector->push_back(LOCAL_GL_STENCIL_ATTACHMENT);
break;
default:
MOZ_CRASH();
}
}
*out_glNumAttachments = scopedVector->size();
*out_glAttachments = scopedVector->data();
}
}
@ -142,59 +231,27 @@ WebGL2Context::InvalidateFramebuffer(GLenum target,
{
const char funcName[] = "invalidateSubFramebuffer";
if (IsContextLost())
return;
MakeContextCurrent();
if (!ValidateFramebufferTarget(target, funcName))
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("GFX: Bad target.");
}
const bool badColorAttachmentIsInvalidOp = true;
for (size_t i = 0; i < attachments.Length(); i++) {
if (!ValidateFramebufferAttachment(fb, attachments[i], funcName,
badColorAttachmentIsInvalidOp))
std::vector<GLenum> scopedVector;
GLsizei glNumAttachments;
const GLenum* glAttachments;
if (!ValidateInvalidateFramebuffer(funcName, target, attachments, &rv, &scopedVector,
&glNumAttachments, &glAttachments))
{
return;
}
}
// InvalidateFramebuffer is a hint to the driver. Should be OK to
// skip calls if not supported, for example by OSX 10.9 GL
// drivers.
if (!gl->IsSupported(gl::GLFeature::invalidate_framebuffer))
return;
////
if (!fb && !isDefaultFB) {
dom::Sequence<GLenum> tmpAttachments;
if (!TranslateDefaultAttachments(attachments, &tmpAttachments)) {
rv.Throw(NS_ERROR_OUT_OF_MEMORY);
// Some drivers (like OSX 10.9 GL) just don't support invalidate_framebuffer.
const bool useFBInvalidation = (mAllowFBInvalidation &&
gl->IsSupported(gl::GLFeature::invalidate_framebuffer));
if (useFBInvalidation) {
gl->fInvalidateFramebuffer(target, glNumAttachments, glAttachments);
return;
}
gl->fInvalidateFramebuffer(target, tmpAttachments.Length(),
tmpAttachments.Elements());
} else {
gl->fInvalidateFramebuffer(target, attachments.Length(), attachments.Elements());
}
// Use clear instead?
// No-op for now.
}
void
@ -204,65 +261,28 @@ WebGL2Context::InvalidateSubFramebuffer(GLenum target, const dom::Sequence<GLenu
{
const char funcName[] = "invalidateSubFramebuffer";
if (IsContextLost())
return;
MakeContextCurrent();
if (!ValidateFramebufferTarget(target, funcName))
return;
if (width < 0 || height < 0) {
ErrorInvalidValue("%s: width and height must be >= 0.", funcName);
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("GFX: Bad target.");
}
const bool badColorAttachmentIsInvalidOp = true;
for (size_t i = 0; i < attachments.Length(); i++) {
if (!ValidateFramebufferAttachment(fb, attachments[i], funcName,
badColorAttachmentIsInvalidOp))
std::vector<GLenum> scopedVector;
GLsizei glNumAttachments;
const GLenum* glAttachments;
if (!ValidateInvalidateFramebuffer(funcName, target, attachments, &rv, &scopedVector,
&glNumAttachments, &glAttachments))
{
return;
}
}
// InvalidateFramebuffer is a hint to the driver. Should be OK to
// skip calls if not supported, for example by OSX 10.9 GL
// drivers.
if (!gl->IsSupported(gl::GLFeature::invalidate_framebuffer))
return;
////
if (!fb && !isDefaultFB) {
dom::Sequence<GLenum> tmpAttachments;
if (!TranslateDefaultAttachments(attachments, &tmpAttachments)) {
rv.Throw(NS_ERROR_OUT_OF_MEMORY);
// Some drivers (like OSX 10.9 GL) just don't support invalidate_framebuffer.
const bool useFBInvalidation = (mAllowFBInvalidation &&
gl->IsSupported(gl::GLFeature::invalidate_framebuffer));
if (useFBInvalidation) {
gl->fInvalidateSubFramebuffer(target, glNumAttachments, glAttachments, x, y,
width, height);
return;
}
gl->fInvalidateSubFramebuffer(target, tmpAttachments.Length(),
tmpAttachments.Elements(), x, y, width, height);
} else {
gl->fInvalidateSubFramebuffer(target, attachments.Length(),
attachments.Elements(), x, y, width, height);
}
// Use clear instead?
// No-op for now.
}
void

Просмотреть файл

@ -126,6 +126,7 @@ WebGLContext::WebGLContext()
, mNeedsFakeNoDepth(false)
, mNeedsFakeNoStencil(false)
, mNeedsEmulatedLoneDepthStencil(false)
, mAllowFBInvalidation(gfxPrefs::WebGLFBInvalidation())
{
mGeneration = 0;
mInvalidated = false;

Просмотреть файл

@ -536,11 +536,6 @@ public:
GLenum texImageTarget, WebGLTexture* tex,
GLint level);
// Framebuffer validation
bool ValidateFramebufferAttachment(const WebGLFramebuffer* fb, GLenum attachment,
const char* funcName,
bool badColorAttachmentIsInvalidOp = false);
void FrontFace(GLenum mode);
already_AddRefed<WebGLActiveInfo> GetActiveAttrib(const WebGLProgram& prog,
GLuint index);
@ -1687,6 +1682,12 @@ protected:
RefPtr<const webgl::LinkedProgramInfo> mActiveProgramLinkInfo;
bool ValidateFramebufferTarget(GLenum target, const char* const info);
bool ValidateInvalidateFramebuffer(const char* funcName, GLenum target,
const dom::Sequence<GLenum>& attachments,
ErrorResult* const out_rv,
std::vector<GLenum>* const scopedVector,
GLsizei* const out_glNumAttachments,
const GLenum** const out_glAttachments);
WebGLRefPtr<WebGLFramebuffer> mBoundDrawFramebuffer;
WebGLRefPtr<WebGLFramebuffer> mBoundReadFramebuffer;
@ -1828,6 +1829,8 @@ protected:
bool mNeedsFakeNoStencil;
bool mNeedsEmulatedLoneDepthStencil;
const bool mAllowFBInvalidation;
bool Has64BitTimestamps() const;
struct ScopedMaskWorkaround {

Просмотреть файл

@ -196,50 +196,6 @@ WebGLContext::ValidateDrawModeEnum(GLenum mode, const char* info)
}
}
bool
WebGLContext::ValidateFramebufferAttachment(const WebGLFramebuffer* fb, GLenum attachment,
const char* funcName,
bool badColorAttachmentIsInvalidOp)
{
if (!fb) {
switch (attachment) {
case LOCAL_GL_COLOR:
case LOCAL_GL_DEPTH:
case LOCAL_GL_STENCIL:
return true;
default:
ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x.",
funcName, attachment);
return false;
}
}
if (attachment == LOCAL_GL_DEPTH_ATTACHMENT ||
attachment == LOCAL_GL_STENCIL_ATTACHMENT ||
attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
{
return true;
}
if (attachment >= LOCAL_GL_COLOR_ATTACHMENT0 &&
attachment <= LastColorAttachmentEnum())
{
return true;
}
if (badColorAttachmentIsInvalidOp &&
attachment >= LOCAL_GL_COLOR_ATTACHMENT0)
{
const uint32_t offset = attachment - LOCAL_GL_COLOR_ATTACHMENT0;
ErrorInvalidOperation("%s: Bad color attachment: COLOR_ATTACHMENT%u. (0x%04x)",
funcName, offset, attachment);
} else {
ErrorInvalidEnum("%s: attachment: Bad attachment 0x%x.", funcName, attachment);
}
return false;
}
bool
WebGLContext::ValidateUniformLocation(WebGLUniformLocation* loc, const char* funcName)
{

Просмотреть файл

@ -608,6 +608,7 @@ private:
DECL_GFX_PREF(Live, "webgl.prefer-16bpp", WebGLPrefer16bpp, bool, false);
DECL_GFX_PREF(Live, "webgl.restore-context-when-visible", WebGLRestoreWhenVisible, bool, true);
DECL_GFX_PREF(Live, "webgl.allow-immediate-queries", WebGLImmediateQueries, bool, false);
DECL_GFX_PREF(Live, "webgl.allow-fb-invalidation", WebGLFBInvalidation, bool, false);
DECL_GFX_PREF(Live, "webgl.webgl2-compat-mode", WebGL2CompatMode, bool, false);

Просмотреть файл

@ -4494,6 +4494,7 @@ pref("webgl.enable-privileged-extensions", false);
pref("webgl.bypass-shader-validation", false);
pref("webgl.disable-fail-if-major-performance-caveat", false);
pref("webgl.disable-DOM-blit-uploads", false);
pref("webgl.allow-fb-invalidation", false);
pref("webgl.webgl2-compat-mode", false);
pref("webgl.enable-webgl2", true);