forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			330 lines
		
	
	
	
		
			9.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			330 lines
		
	
	
	
		
			9.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #include "WebGL2Context.h"
 | |
| 
 | |
| #include "GLContext.h"
 | |
| #include "GLScreenBuffer.h"
 | |
| #include "WebGLContextUtils.h"
 | |
| #include "WebGLFormats.h"
 | |
| #include "WebGLFramebuffer.h"
 | |
| 
 | |
| namespace mozilla {
 | |
| 
 | |
| void
 | |
| WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
 | |
|                                GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
 | |
|                                GLbitfield mask, GLenum filter)
 | |
| {
 | |
|     if (IsContextLost())
 | |
|         return;
 | |
| 
 | |
|     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;
 | |
|     }
 | |
| 
 | |
|     ////
 | |
| 
 | |
|     if (!ValidateAndInitFB("blitFramebuffer: READ_FRAMEBUFFER", mBoundReadFramebuffer) ||
 | |
|         !ValidateAndInitFB("blitFramebuffer: DRAW_FRAMEBUFFER", mBoundDrawFramebuffer))
 | |
|     {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     DoBindFB(mBoundReadFramebuffer, LOCAL_GL_READ_FRAMEBUFFER);
 | |
|     DoBindFB(mBoundDrawFramebuffer, LOCAL_GL_DRAW_FRAMEBUFFER);
 | |
| 
 | |
|     WebGLFramebuffer::BlitFramebuffer(this,
 | |
|                                       srcX0, srcY0, srcX1, srcY1,
 | |
|                                       dstX0, dstY0, dstX1, dstY1,
 | |
|                                       mask, filter);
 | |
| }
 | |
| 
 | |
| void
 | |
| WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment,
 | |
|                                        WebGLTexture* texture, GLint level, GLint layer)
 | |
| {
 | |
|     const char funcName[] = "framebufferTextureLayer";
 | |
|     if (IsContextLost())
 | |
|         return;
 | |
| 
 | |
|     if (!ValidateFramebufferTarget(target, funcName))
 | |
|         return;
 | |
| 
 | |
|     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("GFX: Bad target.");
 | |
|     }
 | |
| 
 | |
|     if (!fb)
 | |
|         return ErrorInvalidOperation("%s: Cannot modify framebuffer 0.", funcName);
 | |
| 
 | |
|     fb->FramebufferTextureLayer(funcName, attachment, texture, level, layer);
 | |
| }
 | |
| 
 | |
| JS::Value
 | |
| WebGL2Context::GetFramebufferAttachmentParameter(JSContext* cx,
 | |
|                                                  GLenum target,
 | |
|                                                  GLenum attachment,
 | |
|                                                  GLenum pname,
 | |
|                                                  ErrorResult& out_error)
 | |
| {
 | |
|     return WebGLContext::GetFramebufferAttachmentParameter(cx, target, attachment, pname,
 | |
|                                                            out_error);
 | |
| }
 | |
| 
 | |
| ////
 | |
| 
 | |
| static bool
 | |
| ValidateBackbufferAttachmentEnum(WebGLContext* webgl, const char* funcName,
 | |
|                                  GLenum attachment)
 | |
| {
 | |
|     switch (attachment) {
 | |
|     case LOCAL_GL_COLOR:
 | |
|     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)
 | |
| {
 | |
|     switch (attachment) {
 | |
|     case LOCAL_GL_DEPTH_ATTACHMENT:
 | |
|     case LOCAL_GL_STENCIL_ATTACHMENT:
 | |
|     case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     if (attachment < LOCAL_GL_COLOR_ATTACHMENT0) {
 | |
|         webgl->ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x.",
 | |
|                                 funcName, attachment);
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     if (attachment > webgl->LastColorAttachmentEnum()) {
 | |
|         // That these errors have different types is ridiculous.
 | |
|         webgl->ErrorInvalidOperation("%s: Too-large LOCAL_GL_COLOR_ATTACHMENTn.",
 | |
|                                      funcName);
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| 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;
 | |
| 
 | |
|     if (!ValidateFramebufferTarget(target, funcName))
 | |
|         return false;
 | |
| 
 | |
|     const WebGLFramebuffer* fb;
 | |
|     bool isDefaultFB = false;
 | |
|     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("GFX: Bad target.");
 | |
|     }
 | |
| 
 | |
|     if (fb) {
 | |
|         const auto fbStatus = fb->CheckFramebufferStatus(funcName);
 | |
|         if (fbStatus != LOCAL_GL_FRAMEBUFFER_COMPLETE)
 | |
|             return false; // Not an error, but don't run forward to driver either.
 | |
|     } else {
 | |
|         if (!EnsureDefaultFB(funcName))
 | |
|             return false;
 | |
|     }
 | |
|     DoBindFB(fb, 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:
 | |
|                     scopedVector->push_back(LOCAL_GL_DEPTH_ATTACHMENT);
 | |
|                     break;
 | |
| 
 | |
|                 case LOCAL_GL_STENCIL:
 | |
|                     scopedVector->push_back(LOCAL_GL_STENCIL_ATTACHMENT);
 | |
|                     break;
 | |
| 
 | |
|                 default:
 | |
|                     MOZ_CRASH();
 | |
|                 }
 | |
|             }
 | |
|             *out_glNumAttachments = scopedVector->size();
 | |
|             *out_glAttachments = scopedVector->data();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     ////
 | |
| 
 | |
|     if (!fb) {
 | |
|         mDefaultFB_IsInvalid = true;
 | |
|         mResolvedDefaultFB = nullptr;
 | |
|     }
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| void
 | |
| WebGL2Context::InvalidateFramebuffer(GLenum target,
 | |
|                                      const dom::Sequence<GLenum>& attachments,
 | |
|                                      ErrorResult& rv)
 | |
| {
 | |
|     const char funcName[] = "invalidateSubFramebuffer";
 | |
| 
 | |
|     std::vector<GLenum> scopedVector;
 | |
|     GLsizei glNumAttachments;
 | |
|     const GLenum* glAttachments;
 | |
|     if (!ValidateInvalidateFramebuffer(funcName, target, attachments, &rv, &scopedVector,
 | |
|                                        &glNumAttachments, &glAttachments))
 | |
|     {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     ////
 | |
| 
 | |
|     // 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;
 | |
|     }
 | |
| 
 | |
|     // Use clear instead?
 | |
|     // No-op for now.
 | |
| }
 | |
| 
 | |
| void
 | |
| WebGL2Context::InvalidateSubFramebuffer(GLenum target, const dom::Sequence<GLenum>& attachments,
 | |
|                                         GLint x, GLint y, GLsizei width, GLsizei height,
 | |
|                                         ErrorResult& rv)
 | |
| {
 | |
|     const char funcName[] = "invalidateSubFramebuffer";
 | |
| 
 | |
|     if (!ValidateNonNegative(funcName, "width", width) ||
 | |
|         !ValidateNonNegative(funcName, "height", height))
 | |
|     {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     std::vector<GLenum> scopedVector;
 | |
|     GLsizei glNumAttachments;
 | |
|     const GLenum* glAttachments;
 | |
|     if (!ValidateInvalidateFramebuffer(funcName, target, attachments, &rv, &scopedVector,
 | |
|                                        &glNumAttachments, &glAttachments))
 | |
|     {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     ////
 | |
| 
 | |
|     // 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;
 | |
|     }
 | |
| 
 | |
|     // Use clear instead?
 | |
|     // No-op for now.
 | |
| }
 | |
| 
 | |
| void
 | |
| WebGL2Context::ReadBuffer(GLenum mode)
 | |
| {
 | |
|     const char funcName[] = "readBuffer";
 | |
|     if (IsContextLost())
 | |
|         return;
 | |
| 
 | |
|     if (mBoundReadFramebuffer) {
 | |
|         mBoundReadFramebuffer->ReadBuffer(funcName, mode);
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     // Operating on the default framebuffer.
 | |
|     if (mode != LOCAL_GL_NONE &&
 | |
|         mode != LOCAL_GL_BACK)
 | |
|     {
 | |
|         nsCString enumName;
 | |
|         EnumName(mode, &enumName);
 | |
|         ErrorInvalidOperation("%s: If READ_FRAMEBUFFER is null, `mode` must be BACK or"
 | |
|                               " NONE. Was %s.",
 | |
|                               funcName, enumName.BeginReading());
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     mDefaultFB_ReadBuffer = mode;
 | |
| }
 | |
| 
 | |
| } // namespace mozilla
 | 
