Bug 1303879 - Refactor framebuffer funcs and completeness caching. - r=mtseng

MozReview-Commit-ID: Hi3uEwpmWF4
This commit is contained in:
Jeff Gilbert 2016-07-19 00:36:54 -07:00 коммит произвёл Jeff Gilbert (:jgilbert)
Родитель 5ca4e283fa
Коммит 15fd350886
11 изменённых файлов: 1211 добавлений и 1188 удалений

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

@ -13,71 +13,6 @@
namespace mozilla {
static bool
GetFBInfoForBlit(const WebGLFramebuffer* fb, const char* const fbInfo,
GLsizei* const out_samples,
const webgl::FormatInfo** const out_colorFormat,
const webgl::FormatInfo** const out_depthFormat,
const webgl::FormatInfo** const out_stencilFormat)
{
*out_samples = 0;
*out_colorFormat = nullptr;
*out_depthFormat = nullptr;
*out_stencilFormat = nullptr;
if (fb->ColorAttachment(0).IsDefined()) {
const auto& attachment = fb->ColorAttachment(0);
*out_samples = attachment.Samples();
*out_colorFormat = attachment.Format()->format;
}
if (fb->DepthStencilAttachment().IsDefined()) {
const auto& attachment = fb->DepthStencilAttachment();
*out_samples = attachment.Samples();
*out_depthFormat = attachment.Format()->format;
*out_stencilFormat = *out_depthFormat;
} else {
if (fb->DepthAttachment().IsDefined()) {
const auto& attachment = fb->DepthAttachment();
*out_samples = attachment.Samples();
*out_depthFormat = attachment.Format()->format;
}
if (fb->StencilAttachment().IsDefined()) {
const auto& attachment = fb->StencilAttachment();
*out_samples = attachment.Samples();
*out_stencilFormat = attachment.Format()->format;
}
}
return true;
}
static void
GetBackbufferFormats(const WebGLContextOptions& options,
const webgl::FormatInfo** const out_color,
const webgl::FormatInfo** const out_depth,
const webgl::FormatInfo** const out_stencil)
{
const auto effFormat = options.alpha ? webgl::EffectiveFormat::RGBA8
: webgl::EffectiveFormat::RGB8;
*out_color = webgl::GetFormat(effFormat);
*out_depth = nullptr;
*out_stencil = nullptr;
if (options.depth && options.stencil) {
*out_depth = webgl::GetFormat(webgl::EffectiveFormat::DEPTH24_STENCIL8);
*out_stencil = *out_depth;
} else {
if (options.depth) {
*out_depth = webgl::GetFormat(webgl::EffectiveFormat::DEPTH_COMPONENT16);
}
if (options.stencil) {
*out_stencil = webgl::GetFormat(webgl::EffectiveFormat::STENCIL_INDEX8);
}
}
}
void
WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
@ -103,238 +38,41 @@ WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY
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;
const webgl::FormatInfo* srcColorFormat = nullptr;
const webgl::FormatInfo* srcDepthFormat = nullptr;
const webgl::FormatInfo* srcStencilFormat = nullptr;
if (mBoundReadFramebuffer) {
if (!mBoundReadFramebuffer->ValidateAndInitAttachments("blitFramebuffer's READ_FRAMEBUFFER"))
return;
if (!GetFBInfoForBlit(mBoundReadFramebuffer, "READ_FRAMEBUFFER", &srcSamples,
&srcColorFormat, &srcDepthFormat, &srcStencilFormat))
const auto& readFB = mBoundReadFramebuffer;
if (readFB &&
!readFB->ValidateAndInitAttachments("blitFramebuffer's READ_FRAMEBUFFER"))
{
return;
}
} else {
srcSamples = 0; // Always 0.
GetBackbufferFormats(mOptions, &srcColorFormat, &srcDepthFormat,
&srcStencilFormat);
}
GLsizei dstSamples;
const webgl::FormatInfo* dstColorFormat = nullptr;
const webgl::FormatInfo* dstDepthFormat = nullptr;
const webgl::FormatInfo* dstStencilFormat = nullptr;
if (mBoundDrawFramebuffer) {
if (!mBoundDrawFramebuffer->ValidateAndInitAttachments("blitFramebuffer's DRAW_FRAMEBUFFER"))
return;
if (!GetFBInfoForBlit(mBoundDrawFramebuffer, "DRAW_FRAMEBUFFER", &dstSamples,
&dstColorFormat, &dstDepthFormat, &dstStencilFormat))
const auto& drawFB = mBoundDrawFramebuffer;
if (drawFB &&
!drawFB->ValidateAndInitAttachments("blitFramebuffer's DRAW_FRAMEBUFFER"))
{
return;
}
} else {
dstSamples = gl->Screen()->Samples();
GetBackbufferFormats(mOptions, &dstColorFormat, &dstDepthFormat,
&dstStencilFormat);
}
////
if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
const auto fnSignlessType = [](const webgl::FormatInfo* format)
-> webgl::ComponentType
{
if (!format)
return webgl::ComponentType::None;
switch (format->componentType) {
case webgl::ComponentType::UInt:
return webgl::ComponentType::Int;
case webgl::ComponentType::NormUInt:
return webgl::ComponentType::NormInt;
default:
return format->componentType;
}
};
const auto srcType = fnSignlessType(srcColorFormat);
const auto dstType = fnSignlessType(dstColorFormat);
if (srcType != dstType) {
ErrorInvalidOperation("blitFramebuffer: Color buffer format component type"
" mismatch.");
return;
}
const bool srcIsInt = (srcType == webgl::ComponentType::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 != 0) {
ErrorInvalidOperation("blitFramebuffer: DRAW_FRAMEBUFFER may not have"
" multiple samples.");
return;
}
if (srcSamples != 0) {
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,
WebGLFramebuffer::BlitFramebuffer(this,
readFB, srcX0, srcY0, srcX1, srcY1,
drawFB, dstX0, dstY0, dstX1, dstY1,
mask, filter);
}
static bool
ValidateTextureLayerAttachment(GLenum attachment)
{
if (LOCAL_GL_COLOR_ATTACHMENT0 <= attachment &&
attachment <= LOCAL_GL_COLOR_ATTACHMENT15)
{
return true;
}
switch (attachment) {
case LOCAL_GL_DEPTH_ATTACHMENT:
case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
case LOCAL_GL_STENCIL_ATTACHMENT:
return true;
}
return false;
}
void
WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment,
WebGLTexture* texture, GLint level, GLint layer)
{
const char funcName[] = "framebufferTextureLayer";
if (IsContextLost())
return;
if (!ValidateFramebufferTarget(target, "framebufferTextureLayer"))
if (!ValidateFramebufferTarget(target, funcName))
return;
if (!ValidateTextureLayerAttachment(attachment))
return ErrorInvalidEnumInfo("framebufferTextureLayer: attachment:", attachment);
if (texture) {
if (texture->IsDeleted()) {
return ErrorInvalidValue("framebufferTextureLayer: texture must be a valid "
"texture object.");
}
if (layer < 0)
return ErrorInvalidValue("framebufferTextureLayer: layer must be >= 0.");
if (level < 0)
return ErrorInvalidValue("framebufferTextureLayer: level must be >= 0.");
switch (texture->Target().get()) {
case LOCAL_GL_TEXTURE_3D:
if (uint32_t(layer) >= mImplMax3DTextureSize) {
return ErrorInvalidValue("framebufferTextureLayer: layer must be < "
"MAX_3D_TEXTURE_SIZE");
}
if (uint32_t(level) > FloorLog2(mImplMax3DTextureSize)) {
return ErrorInvalidValue("framebufferTextureLayer: layer mube be <= "
"log2(MAX_3D_TEXTURE_SIZE");
}
break;
case LOCAL_GL_TEXTURE_2D_ARRAY:
if (uint32_t(layer) >= mImplMaxArrayTextureLayers) {
return ErrorInvalidValue("framebufferTextureLayer: layer must be < "
"MAX_ARRAY_TEXTURE_LAYERS");
}
if (uint32_t(level) > FloorLog2(mImplMaxTextureSize)) {
return ErrorInvalidValue("framebufferTextureLayer: layer mube be <= "
"log2(MAX_TEXTURE_SIZE");
}
break;
default:
return ErrorInvalidOperation("framebufferTextureLayer: texture must be an "
"existing 3D texture, or a 2D texture array.");
}
}
WebGLFramebuffer* fb;
switch (target) {
case LOCAL_GL_FRAMEBUFFER:
@ -350,12 +88,10 @@ WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment,
MOZ_CRASH("GFX: Bad target.");
}
if (!fb) {
return ErrorInvalidOperation("framebufferTextureLayer: cannot modify"
" framebuffer 0.");
}
if (!fb)
return ErrorInvalidOperation("%a: Xannot modify framebuffer 0.");
fb->FramebufferTextureLayer(attachment, texture, level, layer);
fb->FramebufferTextureLayer(funcName, attachment, texture, level, layer);
}
JS::Value
@ -532,32 +268,12 @@ WebGL2Context::InvalidateSubFramebuffer(GLenum target, const dom::Sequence<GLenu
void
WebGL2Context::ReadBuffer(GLenum mode)
{
const char funcName[] = "readBuffer";
if (IsContextLost())
return;
const bool isColorAttachment = (mode >= LOCAL_GL_COLOR_ATTACHMENT0 &&
mode <= LastColorAttachmentEnum());
if (mode != LOCAL_GL_NONE && mode != LOCAL_GL_BACK && !isColorAttachment) {
ErrorInvalidEnum("readBuffer: `mode` must be one of NONE, BACK, or "
"COLOR_ATTACHMENTi. Was %s",
EnumName(mode));
return;
}
if (mBoundReadFramebuffer) {
if (mode != LOCAL_GL_NONE &&
!isColorAttachment)
{
ErrorInvalidOperation("readBuffer: If READ_FRAMEBUFFER is non-null, `mode` "
"must be COLOR_ATTACHMENTi or NONE. Was %s",
EnumName(mode));
return;
}
MakeContextCurrent();
mBoundReadFramebuffer->SetReadBufferMode(mode);
gl->fReadBuffer(mode);
mBoundReadFramebuffer->ReadBuffer(funcName, mode);
return;
}
@ -565,9 +281,9 @@ WebGL2Context::ReadBuffer(GLenum mode)
if (mode != LOCAL_GL_NONE &&
mode != LOCAL_GL_BACK)
{
ErrorInvalidOperation("readBuffer: If READ_FRAMEBUFFER is null, `mode`"
" must be BACK or NONE. Was %s",
EnumName(mode));
ErrorInvalidOperation("%s: If READ_FRAMEBUFFER is null, `mode` must be BACK or"
" NONE. Was %s",
funcName, EnumName(mode));
return;
}

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

@ -43,10 +43,13 @@ WebGL2Context::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
/* GLenum */
case LOCAL_GL_READ_BUFFER: {
if (mBoundReadFramebuffer)
return JS::Int32Value(mBoundReadFramebuffer->ReadBufferMode());
if (!mBoundReadFramebuffer)
return JS::Int32Value(gl->Screen()->GetReadBufferMode());
return JS::Int32Value(LOCAL_GL_BACK);
if (!mBoundReadFramebuffer->ColorReadBuffer())
return JS::Int32Value(LOCAL_GL_NONE);
return JS::Int32Value(mBoundReadFramebuffer->ColorReadBuffer()->mAttachmentPoint);
}
case LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT:

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

@ -1637,21 +1637,11 @@ WebGLContext::DummyReadFramebufferOperation(const char* funcName)
if (!mBoundReadFramebuffer)
return; // Infallible.
const auto target = (IsWebGL2() ? LOCAL_GL_READ_FRAMEBUFFER
: LOCAL_GL_FRAMEBUFFER);
nsCString fbStatusInfo;
const auto status = mBoundReadFramebuffer->CheckFramebufferStatus(target,
&fbStatusInfo);
const auto status = mBoundReadFramebuffer->CheckFramebufferStatus(funcName);
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
nsCString errorText("Incomplete framebuffer");
if (fbStatusInfo.Length()) {
errorText += ": ";
errorText += fbStatusInfo;
}
ErrorInvalidFramebufferOperation("%s: %s.", funcName, errorText.BeginReading());
ErrorInvalidFramebufferOperation("%s: Framebuffer must be complete.",
funcName);
}
}

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

@ -1138,6 +1138,8 @@ public:
return LOCAL_GL_COLOR_ATTACHMENT0 + mImplMaxColorAttachments - 1;
}
const decltype(mOptions)& Options() const { return mOptions; }
protected:
// Texture sizes are often not actually the GL values. Let's be explicit that these

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

@ -101,10 +101,10 @@ ScopedResolveTexturesForDraw::ScopedResolveTexturesForDraw(WebGLContext* webgl,
return;
}
std::vector<const WebGLFBAttachPoint*> fbAttachments;
if (mWebGL->mBoundDrawFramebuffer) {
const std::vector<const WebGLFBAttachPoint*>* attachList = nullptr;
const auto& fb = mWebGL->mBoundDrawFramebuffer;
fb->GatherAttachments(&fbAttachments);
if (fb) {
attachList = &(fb->ResolvedCompleteData()->texDrawBuffers);
}
MOZ_ASSERT(mWebGL->mActiveProgramLinkInfo);
@ -120,7 +120,9 @@ ScopedResolveTexturesForDraw::ScopedResolveTexturesForDraw(WebGLContext* webgl,
if (!tex)
continue;
if (tex->IsFeedback(mWebGL, funcName, texUnit, fbAttachments)) {
if (attachList &&
tex->IsFeedback(mWebGL, funcName, texUnit, *attachList))
{
*out_error = true;
return;
}
@ -587,7 +589,8 @@ WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
Draw_cleanup(funcName);
}
void WebGLContext::Draw_cleanup(const char* funcName)
void
WebGLContext::Draw_cleanup(const char* funcName)
{
UndoFakeVertexAttrib0();
@ -614,9 +617,12 @@ void WebGLContext::Draw_cleanup(const char* funcName)
uint32_t destHeight = mViewportHeight;
if (mBoundDrawFramebuffer) {
const auto& fba = mBoundDrawFramebuffer->ColorAttachment(0);
if (fba.IsDefined()) {
fba.Size(&destWidth, &destHeight);
const auto& drawBuffers = mBoundDrawFramebuffer->ColorDrawBuffers();
for (const auto& cur : drawBuffers) {
if (!cur->IsDefined())
continue;
cur->Size(&destWidth, &destHeight);
break;
}
} else {
destWidth = mWidth;

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

@ -144,7 +144,11 @@ WebGLContext::DrawBuffers(const dom::Sequence<GLenum>& buffers)
if (IsContextLost())
return;
if (!mBoundDrawFramebuffer) {
if (mBoundDrawFramebuffer) {
mBoundDrawFramebuffer->DrawBuffers(funcName, buffers);
return;
}
// GLES 3.0.4 p186:
// "If the GL is bound to the default framebuffer, then `n` must be 1 and the
// constant must be BACK or NONE. [...] If DrawBuffers is supplied with a
@ -171,49 +175,6 @@ WebGLContext::DrawBuffers(const dom::Sequence<GLenum>& buffers)
mDefaultFB_DrawBuffer0 = buffers[0];
gl->Screen()->SetDrawBuffer(buffers[0]);
return;
}
// Framebuffer object (not default framebuffer)
if (buffers.Length() > mImplMaxDrawBuffers) {
// "An INVALID_VALUE error is generated if `n` is greater than MAX_DRAW_BUFFERS."
ErrorInvalidValue("%s: `buffers` must have a length <= MAX_DRAW_BUFFERS.",
funcName);
return;
}
for (size_t i = 0; i < buffers.Length(); i++) {
// "If the GL is bound to a draw framebuffer object, the `i`th buffer listed in
// bufs must be COLOR_ATTACHMENTi or NONE. Specifying a buffer out of order,
// BACK, or COLOR_ATTACHMENTm where `m` is greater than or equal to the value of
// MAX_COLOR_ATTACHMENTS, will generate the error INVALID_OPERATION.
// WEBGL_draw_buffers:
// "The value of the MAX_COLOR_ATTACHMENTS_WEBGL parameter must be greater than or
// equal to that of the MAX_DRAW_BUFFERS_WEBGL parameter."
// This means that if buffers.Length() isn't larger than MaxDrawBuffers, it won't
// be larger than MaxColorAttachments.
if (buffers[i] != LOCAL_GL_NONE &&
buffers[i] != LOCAL_GL_COLOR_ATTACHMENT0 + i)
{
ErrorInvalidOperation("%s: `buffers[i]` must be NONE or COLOR_ATTACHMENTi.",
funcName);
return;
}
}
MakeContextCurrent();
const GLenum* ptr = nullptr;
if (buffers.Length()) {
ptr = buffers.Elements();
}
gl->fDrawBuffers(buffers.Length(), ptr);
const auto end = ptr + buffers.Length();
mBoundDrawFramebuffer->mDrawBuffers.assign(ptr, end);
}
void

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

@ -252,10 +252,11 @@ WebGLContext::BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB,
GLenum
WebGLContext::CheckFramebufferStatus(GLenum target)
{
const char funcName[] = "checkFramebufferStatus";
if (IsContextLost())
return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED;
if (!ValidateFramebufferTarget(target, "invalidateFramebuffer"))
if (!ValidateFramebufferTarget(target, funcName))
return 0;
WebGLFramebuffer* fb;
@ -276,8 +277,7 @@ WebGLContext::CheckFramebufferStatus(GLenum target)
if (!fb)
return LOCAL_GL_FRAMEBUFFER_COMPLETE;
nsCString fbErrorInfo;
return fb->CheckFramebufferStatus(target, &fbErrorInfo).get();
return fb->CheckFramebufferStatus(funcName).get();
}
already_AddRefed<WebGLProgram>
@ -484,10 +484,11 @@ void
WebGLContext::FramebufferRenderbuffer(GLenum target, GLenum attachment,
GLenum rbtarget, WebGLRenderbuffer* wrb)
{
const char funcName[] = "framebufferRenderbuffer";
if (IsContextLost())
return;
if (!ValidateFramebufferTarget(target, "framebufferRenderbuffer"))
if (!ValidateFramebufferTarget(target, funcName))
return;
WebGLFramebuffer* fb;
@ -505,20 +506,10 @@ WebGLContext::FramebufferRenderbuffer(GLenum target, GLenum attachment,
MOZ_CRASH("GFX: Bad target.");
}
if (!fb) {
return ErrorInvalidOperation("framebufferRenderbuffer: cannot modify"
" framebuffer 0.");
}
if (!fb)
return ErrorInvalidOperation("%s: Cannot modify framebuffer 0.", funcName);
if (rbtarget != LOCAL_GL_RENDERBUFFER) {
return ErrorInvalidEnumInfo("framebufferRenderbuffer: rbtarget:",
rbtarget);
}
if (!ValidateFramebufferAttachment(fb, attachment, "framebufferRenderbuffer"))
return;
fb->FramebufferRenderbuffer(attachment, rbtarget, wrb);
fb->FramebufferRenderbuffer(funcName, attachment, rbtarget, wrb);
}
void
@ -528,57 +519,13 @@ WebGLContext::FramebufferTexture2D(GLenum target,
WebGLTexture* tobj,
GLint level)
{
const char funcName[] = "framebufferTexture2D";
if (IsContextLost())
return;
if (!ValidateFramebufferTarget(target, "framebufferTexture2D"))
if (!ValidateFramebufferTarget(target, funcName))
return;
if (level < 0) {
ErrorInvalidValue("framebufferTexture2D: level must not be negative.");
return;
}
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: textarget:",
textarget);
}
if (IsWebGL2()) {
/* GLES 3.0.4 p208:
* If textarget is one of TEXTURE_CUBE_MAP_POSITIVE_X,
* TEXTURE_CUBE_MAP_POSITIVE_Y, TEXTURE_CUBE_MAP_POSITIVE_Z,
* TEXTURE_CUBE_MAP_NEGATIVE_X, TEXTURE_CUBE_MAP_NEGATIVE_Y,
* or TEXTURE_CUBE_MAP_NEGATIVE_Z, then level must be greater
* than or equal to zero and less than or equal to log2 of the
* value of MAX_CUBE_MAP_TEXTURE_SIZE. If textarget is TEXTURE_2D,
* level must be greater than or equal to zero and no larger than
* log2 of the value of MAX_TEXTURE_SIZE. Otherwise, an
* INVALID_VALUE error is generated.
*/
if (textarget == LOCAL_GL_TEXTURE_2D) {
if (uint32_t(level) > FloorLog2(mImplMaxTextureSize)) {
ErrorInvalidValue("framebufferTexture2D: level is too large.");
return;
}
} else {
MOZ_ASSERT(textarget >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
textarget <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
if (uint32_t(level) > FloorLog2(mImplMaxCubeMapTextureSize)) {
ErrorInvalidValue("framebufferTexture2D: level is too large.");
return;
}
}
} else if (level != 0) {
ErrorInvalidValue("framebufferTexture2D: level must be 0.");
return;
}
WebGLFramebuffer* fb;
switch (target) {
case LOCAL_GL_FRAMEBUFFER:
@ -594,15 +541,10 @@ WebGLContext::FramebufferTexture2D(GLenum target,
MOZ_CRASH("GFX: Bad target.");
}
if (!fb) {
return ErrorInvalidOperation("framebufferTexture2D: cannot modify"
" framebuffer 0.");
}
if (!fb)
return ErrorInvalidOperation("%s: Cannot modify framebuffer 0.", funcName);
if (!ValidateFramebufferAttachment(fb, attachment, "framebufferTexture2D"))
return;
fb->FramebufferTexture2D(attachment, textarget, tobj, level);
fb->FramebufferTexture2D(funcName, attachment, textarget, tobj, level);
}
void

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -27,31 +27,34 @@ class WebGLTexture;
template<typename T>
class PlacementArray;
class WebGLFBAttachPoint
namespace gl {
class GLContext;
} // namespace gl
class WebGLFBAttachPoint final
{
friend class WebGLFramebuffer;
public:
WebGLFramebuffer* const mFB;
const GLenum mAttachmentPoint;
private:
protected:
WebGLRefPtr<WebGLTexture> mTexturePtr;
WebGLRefPtr<WebGLRenderbuffer> mRenderbufferPtr;
TexImageTarget mTexImageTarget;
GLint mTexImageLayer;
uint32_t mTexImageLevel;
// PlacementArray needs a default constructor.
template<typename T>
friend class PlacementArray;
////
WebGLFBAttachPoint()
: mFB(nullptr)
, mAttachmentPoint(0)
{ }
WebGLFBAttachPoint();
WebGLFBAttachPoint(WebGLFramebuffer* fb, GLenum attachmentPoint);
public:
WebGLFBAttachPoint(WebGLFramebuffer* fb, GLenum attachmentPoint);
~WebGLFBAttachPoint();
////
void Unlink();
bool IsDefined() const;
@ -65,23 +68,13 @@ public:
void Clear();
void SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level);
void SetTexImageLayer(WebGLTexture* tex, TexImageTarget target, GLint level,
GLint layer);
void SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level,
GLint layer = 0);
void SetRenderbuffer(WebGLRenderbuffer* rb);
const WebGLTexture* Texture() const {
return mTexturePtr;
}
WebGLTexture* Texture() {
return mTexturePtr;
}
const WebGLRenderbuffer* Renderbuffer() const {
return mRenderbufferPtr;
}
WebGLRenderbuffer* Renderbuffer() {
return mRenderbufferPtr;
}
WebGLTexture* Texture() const { return mTexturePtr; }
WebGLRenderbuffer* Renderbuffer() const { return mRenderbufferPtr; }
TexImageTarget ImageTarget() const {
return mTexImageTarget;
}
@ -94,71 +87,46 @@ public:
void AttachmentName(nsCString* out) const;
bool HasUninitializedImageData() const;
void SetImageDataStatus(WebGLImageDataStatus x);
void SetImageDataStatus(WebGLImageDataStatus x) const;
void Size(uint32_t* const out_width, uint32_t* const out_height) const;
bool HasImage() const;
bool IsComplete(WebGLContext* webgl, nsCString* const out_info) const;
void FinalizeAttachment(gl::GLContext* gl, FBTarget target,
GLenum attachmentLoc) const;
void Resolve(gl::GLContext* gl, FBTarget target) const;
JS::Value GetParameter(const char* funcName, WebGLContext* webgl, JSContext* cx,
GLenum target, GLenum attachment, GLenum pname,
ErrorResult* const out_error);
ErrorResult* const out_error) const;
void OnBackingStoreRespecified() const;
};
template<typename T>
class PlacementArray
{
public:
const size_t mCapacity;
protected:
size_t mSize;
T* const mArray;
////
public:
explicit PlacementArray(size_t capacity)
: mCapacity(capacity)
, mSize(0)
, mArray((T*)moz_xmalloc(sizeof(T) * capacity))
struct Ordered {
const WebGLFBAttachPoint& mRef;
Ordered(const WebGLFBAttachPoint& ref)
: mRef(ref)
{ }
~PlacementArray() {
for (auto& cur : *this) {
cur.~T();
}
free(mArray);
}
bool operator<(const Ordered& other) const {
MOZ_ASSERT(mRef.IsDefined() && other.mRef.IsDefined());
T* begin() const {
return mArray;
}
T* end() const {
return mArray + mSize;
}
T& operator [](size_t offset) const {
MOZ_ASSERT(offset < mSize);
return mArray[offset];
}
const size_t& Size() const { return mSize; }
template<typename A, typename B>
void AppendNew(A a, B b) {
if (mSize == mCapacity)
MOZ_CRASH("GFX: Bad EmplaceAppend.");
// Placement `new`:
new (&(mArray[mSize])) T(a, b);
++mSize;
#define ORDER_BY(X) if (X != other.X) return X < other.X;
ORDER_BY(mRef.mRenderbufferPtr)
ORDER_BY(mRef.mTexturePtr)
ORDER_BY(mRef.mTexImageTarget.get())
ORDER_BY(mRef.mTexImageLevel)
ORDER_BY(mRef.mTexImageLayer)
#undef ORDER_BY
return false;
}
};
};
class WebGLFramebuffer final
: public nsWrapperCache
@ -174,28 +142,7 @@ public:
const GLuint mGLName;
private:
mutable bool mIsKnownFBComplete;
GLenum mReadBufferMode;
// No need to chase pointers for the oft-used color0.
WebGLFBAttachPoint mColorAttachment0;
WebGLFBAttachPoint mDepthAttachment;
WebGLFBAttachPoint mStencilAttachment;
WebGLFBAttachPoint mDepthStencilAttachment;
PlacementArray<WebGLFBAttachPoint> mMoreColorAttachments;
std::vector<GLenum> mDrawBuffers;
bool IsDrawBuffer(size_t n) const {
if (n < mDrawBuffers.size())
return bool(mDrawBuffers[n]);
return false;
}
protected:
#ifdef ANDROID
// Bug 1140459: Some drivers (including our test slaves!) don't
// give reasonable answers for IsRenderbuffer, maybe others.
@ -205,94 +152,131 @@ private:
bool mIsFB;
#endif
////
WebGLFBAttachPoint mDepthAttachment;
WebGLFBAttachPoint mStencilAttachment;
WebGLFBAttachPoint mDepthStencilAttachment;
// In theory, this number can be unbounded based on the driver. However, no driver
// appears to expose more than 8. We might as well stop there too, for now.
// (http://opengl.gpuinfo.org/gl_stats_caps_single.php?listreportsbycap=GL_MAX_COLOR_ATTACHMENTS)
static const size_t kMaxColorAttachments = 8; // jgilbert's MacBook Pro exposes 8.
WebGLFBAttachPoint mColorAttachments[kMaxColorAttachments];
////
std::vector<const WebGLFBAttachPoint*> mColorDrawBuffers; // Non-null
const WebGLFBAttachPoint* mColorReadBuffer; // Null if NONE
////
struct ResolvedData {
// BlitFramebuffer
bool hasSampleBuffers;
const WebGLFBAttachPoint* depthBuffer;
const WebGLFBAttachPoint* stencilBuffer;
// IsFeedback
std::vector<const WebGLFBAttachPoint*> texDrawBuffers; // Non-null
std::set<WebGLFBAttachPoint::Ordered> drawSet;
std::set<WebGLFBAttachPoint::Ordered> readSet;
ResolvedData(const WebGLFramebuffer& parent);
};
UniquePtr<const ResolvedData> mResolvedCompleteData;
////
public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebuffer)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLFramebuffer)
WebGLFramebuffer(WebGLContext* webgl, GLuint fbo);
WebGLContext* GetParentObject() const { return mContext; }
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
private:
~WebGLFramebuffer() {
DeleteOnce();
}
const WebGLRectangleObject& GetAnyRectObject() const;
public:
void Delete();
void FramebufferRenderbuffer(GLenum attachment, RBTarget rbtarget,
WebGLRenderbuffer* rb);
void FramebufferTexture2D(GLenum attachment, TexImageTarget texImageTarget,
WebGLTexture* tex, GLint level);
void FramebufferTextureLayer(GLenum attachment, WebGLTexture* tex, GLint level,
GLint layer);
////
bool HasDefinedAttachments() const;
bool HasIncompleteAttachments(nsCString* const out_info) const;
bool AllImageRectsMatch() const;
bool AllImageSamplesMatch() const;
FBStatus PrecheckFramebufferStatus(nsCString* const out_info) const;
FBStatus CheckFramebufferStatus(FBTarget target, nsCString* const out_info) const;
const webgl::FormatUsageInfo*
GetFormatForAttachment(const WebGLFBAttachPoint& attachment) const;
const WebGLFBAttachPoint& ColorAttachment(size_t colorAttachmentId) const {
MOZ_ASSERT(colorAttachmentId < 1 + mMoreColorAttachments.Size());
return colorAttachmentId ? mMoreColorAttachments[colorAttachmentId - 1]
: mColorAttachment0;
}
const WebGLFBAttachPoint& DepthAttachment() const {
return mDepthAttachment;
}
const WebGLFBAttachPoint& StencilAttachment() const {
return mStencilAttachment;
}
const WebGLFBAttachPoint& DepthStencilAttachment() const {
return mDepthStencilAttachment;
}
void SetReadBufferMode(GLenum readBufferMode) {
mReadBufferMode = readBufferMode;
}
GLenum ReadBufferMode() const { return mReadBufferMode; }
void GatherAttachments(std::vector<const WebGLFBAttachPoint*>* const out) const;
protected:
WebGLFBAttachPoint* GetAttachPoint(GLenum attachment); // Fallible
Maybe<WebGLFBAttachPoint*> GetAttachPoint(GLenum attachment); // Fallible
Maybe<WebGLFBAttachPoint*> GetColorAttachPoint(GLenum attachment); // Fallible
void ResolveAttachments(FBTarget target) const;
bool ResolveAttachmentData(const char* funcName) const;
public:
void DetachTexture(const WebGLTexture* tex);
void DetachRenderbuffer(const WebGLRenderbuffer* rb);
WebGLContext* GetParentObject() const {
return mContext;
}
void FinalizeAttachments(FBTarget target) const;
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebuffer)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLFramebuffer)
bool ValidateAndInitAttachments(const char* funcName);
void InvalidateFramebufferStatus() const {
mIsKnownFBComplete = false;
}
bool ValidateForRead(const char* info,
const webgl::FormatUsageInfo** const out_format,
uint32_t* const out_width, uint32_t* const out_height);
////////////////
// Getters
#define GETTER(X) const decltype(m##X)& X() const { return m##X; }
GETTER(DepthAttachment)
GETTER(StencilAttachment)
GETTER(DepthStencilAttachment)
GETTER(ColorDrawBuffers)
GETTER(ColorReadBuffer)
GETTER(ResolvedCompleteData)
#undef GETTER
////////////////
// Invalidation
bool IsResolvedComplete() const { return bool(mResolvedCompleteData); }
void InvalidateFramebufferStatus() {
mResolvedCompleteData = nullptr;
}
void RecacheResolvedData();
////////////////
// WebGL funcs
FBStatus CheckFramebufferStatus(const char* funcName);
void FramebufferRenderbuffer(const char* funcName, GLenum attachment, GLenum rbtarget,
WebGLRenderbuffer* rb);
void FramebufferTexture2D(const char* funcName, GLenum attachment,
GLenum texImageTarget, WebGLTexture* tex, GLint level);
void FramebufferTextureLayer(const char* funcName, GLenum attachment,
WebGLTexture* tex, GLint level, GLint layer);
void DrawBuffers(const char* funcName, const dom::Sequence<GLenum>& buffers);
void ReadBuffer(const char* funcName, GLenum attachPoint);
JS::Value GetAttachmentParameter(const char* funcName, JSContext* cx, GLenum target,
GLenum attachment, GLenum pname,
ErrorResult* const out_error);
static void BlitFramebuffer(WebGLContext* webgl,
const WebGLFramebuffer* src, GLint srcX0, GLint srcY0,
GLint srcX1, GLint srcY1,
const WebGLFramebuffer* dst, GLint dstX0, GLint dstY0,
GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter);
};
} // namespace mozilla

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

@ -234,14 +234,14 @@ WebGLRenderbuffer::DoFramebufferRenderbuffer(FBTarget target, GLenum attachment)
if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
const GLuint stencilRB = (mSecondaryRB ? mSecondaryRB : mPrimaryRB);
gl->fFramebufferRenderbuffer(target, LOCAL_GL_DEPTH_ATTACHMENT,
gl->fFramebufferRenderbuffer(target.get(), LOCAL_GL_DEPTH_ATTACHMENT,
LOCAL_GL_RENDERBUFFER, mPrimaryRB);
gl->fFramebufferRenderbuffer(target, LOCAL_GL_STENCIL_ATTACHMENT,
gl->fFramebufferRenderbuffer(target.get(), LOCAL_GL_STENCIL_ATTACHMENT,
LOCAL_GL_RENDERBUFFER, stencilRB);
return;
}
gl->fFramebufferRenderbuffer(target, attachment,
gl->fFramebufferRenderbuffer(target.get(), attachment,
LOCAL_GL_RENDERBUFFER, mPrimaryRB);
}

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

@ -1969,20 +1969,18 @@ WebGLTexture::ValidateCopyTexImageForFeedback(const char* funcName, uint32_t lev
{
const auto& fb = mContext->mBoundReadFramebuffer;
if (fb) {
const auto readBuffer = fb->ReadBufferMode();
MOZ_ASSERT(readBuffer != LOCAL_GL_NONE);
const uint32_t colorAttachment = readBuffer - LOCAL_GL_COLOR_ATTACHMENT0;
const auto& attach = fb->ColorAttachment(colorAttachment);
const auto& attach = fb->ColorReadBuffer();
MOZ_ASSERT(attach);
if (attach.Texture() == this &&
uint32_t(attach.MipLevel()) == level)
if (attach->Texture() == this &&
uint32_t(attach->MipLevel()) == level)
{
// Note that the TexImageTargets *don't* have to match for this to be
// undefined per GLES 3.0.4 p211, thus an INVALID_OP in WebGL.
mContext->ErrorInvalidOperation("%s: Feedback loop detected, as this texture"
" is already attached to READ_FRAMEBUFFER's"
" READ_BUFFER-selected COLOR_ATTACHMENT%u.",
funcName, colorAttachment);
funcName, attach->mAttachmentPoint);
return false;
}
}