Chromium Code Reviews| Index: third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp |
| diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp |
| index 896cafbed0f06dc47f17a0427f55ca4d418d40ef..339225c1fd6872d5b62f74c5e1f445be1ec9348f 100644 |
| --- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp |
| +++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp |
| @@ -103,6 +103,8 @@ |
| #include "wtf/text/StringBuilder.h" |
| #include "wtf/text/StringUTF8Adaptor.h" |
| +#include <memory> |
| + |
| namespace blink { |
| namespace { |
| @@ -125,6 +127,24 @@ WebGLRenderingContextBaseMap& forciblyEvictedContexts() |
| return forciblyEvictedContexts; |
| } |
| +class ScopedRGBEmulationColorMask { |
| +public: |
| + ScopedRGBEmulationColorMask(gpu::gles2::GLES2Interface* contextGL, GLboolean* colorMask) |
| + : m_contextGL(contextGL) |
| + { |
| + memcpy(m_colorMask, colorMask, 4 * sizeof(GLboolean)); |
| + m_contextGL->ColorMask(m_colorMask[0], m_colorMask[1], m_colorMask[2], false); |
| + } |
| + ~ScopedRGBEmulationColorMask() |
| + { |
| + m_contextGL->ColorMask(m_colorMask[0], m_colorMask[1], m_colorMask[2], m_colorMask[3]); |
| + } |
| + |
| +private: |
| + gpu::gles2::GLES2Interface* m_contextGL; |
| + GLboolean m_colorMask[4]; |
| +}; |
| + |
| } // namespace |
| void WebGLRenderingContextBase::forciblyLoseOldestContext(const String& reason) |
| @@ -1166,7 +1186,7 @@ WebGLRenderingContextBase::HowToClear WebGLRenderingContextBase::clearIfComposit |
| } else { |
| contextGL()->ClearColor(0, 0, 0, 0); |
| } |
| - contextGL()->ColorMask(true, true, true, true); |
| + contextGL()->ColorMask(true, true, true, !drawingBuffer()->requiresRGBEmulation()); |
| GLbitfield clearMask = GL_COLOR_BUFFER_BIT; |
| if (contextAttributes.get().depth()) { |
| if (!combinedClear || !m_depthMask || !(mask & GL_DEPTH_BUFFER_BIT)) |
| @@ -1210,6 +1230,16 @@ void WebGLRenderingContextBase::restoreStateAfterClear() |
| contextGL()->DepthMask(m_depthMask); |
| } |
| +void WebGLRenderingContextBase::moveGLErrorsToInternalQueue() |
| +{ |
| + DCHECK(!isContextLost()); |
| + GLenum error = GL_NO_ERROR; |
| + while ((error = contextGL()->GetError()) != GL_NO_ERROR) { |
| + if (!m_syntheticErrors.contains(error)) |
| + m_syntheticErrors.append(error); |
| + } |
| +} |
| + |
| void WebGLRenderingContextBase::markLayerComposited() |
| { |
| if (!isContextLost()) |
| @@ -1696,6 +1726,11 @@ void WebGLRenderingContextBase::clear(GLbitfield mask) |
| synthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, "clear", reason); |
| return; |
| } |
| + |
| + std::unique_ptr<ScopedRGBEmulationColorMask> scopedColorMask; |
| + if (m_drawingBuffer->requiresRGBEmulation()) |
| + scopedColorMask.reset(new ScopedRGBEmulationColorMask(contextGL(), m_colorMask)); |
| + |
| if (clearIfComposited(mask) != CombinedClear) { |
| // If clearing the default back buffer's depth buffer, also clear the stencil buffer, if one |
| // was allocated implicitly. This avoids performance problems on some GPUs. |
| @@ -1766,12 +1801,23 @@ void WebGLRenderingContextBase::compressedTexImage2D(GLenum target, GLint level, |
| { |
| if (isContextLost()) |
| return; |
| - if (!validateTexture2DBinding("compressedTexImage2D", target)) |
| + WebGLTexture* texture = validateTexture2DBinding("compressedTexImage2D", target); |
| + if (!texture) |
| return; |
| if (!validateCompressedTexFormat("compressedTexImage2D", internalformat)) |
| return; |
| + |
| + moveGLErrorsToInternalQueue(); |
| contextGL()->CompressedTexImage2D(target, level, internalformat, width, height, |
| border, data->byteLength(), data->baseAddress()); |
| + |
| + GLenum error = contextGL()->GetError(); |
| + if (error == GL_NO_ERROR) { |
| + texture->setColorFormat(internalformat); |
| + } else { |
| + if (!m_syntheticErrors.contains(error)) |
| + m_syntheticErrors.append(error); |
| + } |
| } |
| void WebGLRenderingContextBase::compressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, DOMArrayBufferView* data) |
| @@ -1817,26 +1863,61 @@ void WebGLRenderingContextBase::copyTexImage2D(GLenum target, GLint level, GLenu |
| { |
| if (isContextLost()) |
| return; |
| - if (!validateTexture2DBinding("copyTexImage2D", target)) |
| + WebGLTexture* texture = validateTexture2DBinding("copyTexImage2D", target); |
| + if (!texture) |
| return; |
| if (!validateCopyTexFormat("copyTexImage2D", internalformat)) |
| return; |
| if (!validateSettableTexFormat("copyTexImage2D", internalformat)) |
| return; |
| + |
| + // If RGB emulation is required, then the destination format should not have |
| + // an alpha channel. |
| + if (drawingBuffer()->requiresRGBEmulation()) { |
| + uint32_t channelsExist = WebGLImageConversion::getChannelBitsByFormat(GL_RGB); |
| + uint32_t channelsNeeded = WebGLImageConversion::getChannelBitsByFormat(internalformat); |
| + if ((channelsNeeded & channelsExist) != channelsNeeded) { |
| + synthesizeGLError(GL_INVALID_OPERATION, "copyTexImage2D", "incompatible format"); |
| + return; |
| + } |
| + } |
| + |
| WebGLFramebuffer* readFramebufferBinding = nullptr; |
| if (!validateReadBufferAndGetInfo("copyTexImage2D", readFramebufferBinding)) |
| return; |
| clearIfComposited(); |
| ScopedDrawingBufferBinder binder(drawingBuffer(), readFramebufferBinding); |
| + moveGLErrorsToInternalQueue(); |
| contextGL()->CopyTexImage2D(target, level, internalformat, x, y, width, height, border); |
| + |
| + GLenum error = contextGL()->GetError(); |
| + if (error == GL_NO_ERROR) { |
| + texture->setColorFormat(internalformat); |
| + } else { |
| + if (!m_syntheticErrors.contains(error)) |
| + m_syntheticErrors.append(error); |
| + } |
| } |
| void WebGLRenderingContextBase::copyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) |
| { |
| if (isContextLost()) |
| return; |
| - if (!validateTexture2DBinding("copyTexSubImage2D", target)) |
| + WebGLTexture* texture = validateTexture2DBinding("copyTexSubImage2D", target); |
| + if (!texture) |
| return; |
| + |
| + // If RGB emulation is required, then the destination format should not have |
| + // an alpha channel. |
| + if (drawingBuffer()->requiresRGBEmulation()) { |
| + uint32_t channelsExist = WebGLImageConversion::getChannelBitsByFormat(GL_RGB); |
| + uint32_t channelsNeeded = WebGLImageConversion::getChannelBitsByFormat(texture->getColorFormat()); |
| + if ((channelsNeeded & channelsExist) != channelsNeeded) { |
| + synthesizeGLError(GL_INVALID_OPERATION, "copyTexSubImage2D", "incompatible format"); |
| + return; |
| + } |
| + } |
| + |
| WebGLFramebuffer* readFramebufferBinding = nullptr; |
| if (!validateReadBufferAndGetInfo("copyTexSubImage2D", readFramebufferBinding)) |
| return; |
| @@ -2116,6 +2197,9 @@ void WebGLRenderingContextBase::drawArrays(GLenum mode, GLint first, GLsizei cou |
| if (!validateDrawArrays("drawArrays")) |
| return; |
| + std::unique_ptr<ScopedRGBEmulationColorMask> scopedColorMask; |
| + if (m_drawingBuffer->requiresRGBEmulation()) |
| + scopedColorMask.reset(new ScopedRGBEmulationColorMask(contextGL(), m_colorMask)); |
| clearIfComposited(); |
| contextGL()->DrawArrays(mode, first, count); |
| markContextChanged(CanvasChanged); |
| @@ -2131,6 +2215,9 @@ void WebGLRenderingContextBase::drawElements(GLenum mode, GLsizei count, GLenum |
| return; |
| } |
| + std::unique_ptr<ScopedRGBEmulationColorMask> scopedColorMask; |
| + if (m_drawingBuffer->requiresRGBEmulation()) |
| + scopedColorMask.reset(new ScopedRGBEmulationColorMask(contextGL(), m_colorMask)); |
| clearIfComposited(); |
| contextGL()->DrawElements(mode, count, type, reinterpret_cast<void*>(static_cast<intptr_t>(offset))); |
| markContextChanged(CanvasChanged); |
| @@ -2141,6 +2228,9 @@ void WebGLRenderingContextBase::drawArraysInstancedANGLE(GLenum mode, GLint firs |
| if (!validateDrawArrays("drawArraysInstancedANGLE")) |
| return; |
| + std::unique_ptr<ScopedRGBEmulationColorMask> scopedColorMask; |
| + if (m_drawingBuffer->requiresRGBEmulation()) |
| + scopedColorMask.reset(new ScopedRGBEmulationColorMask(contextGL(), m_colorMask)); |
| clearIfComposited(); |
| contextGL()->DrawArraysInstancedANGLE(mode, first, count, primcount); |
| markContextChanged(CanvasChanged); |
| @@ -2151,6 +2241,9 @@ void WebGLRenderingContextBase::drawElementsInstancedANGLE(GLenum mode, GLsizei |
| if (!validateDrawElements("drawElementsInstancedANGLE", type, offset)) |
| return; |
| + std::unique_ptr<ScopedRGBEmulationColorMask> scopedColorMask; |
| + if (m_drawingBuffer->requiresRGBEmulation()) |
| + scopedColorMask.reset(new ScopedRGBEmulationColorMask(contextGL(), m_colorMask)); |
| clearIfComposited(); |
| contextGL()->DrawElementsInstancedANGLE(mode, count, type, reinterpret_cast<void*>(static_cast<intptr_t>(offset)), primcount); |
| markContextChanged(CanvasChanged); |
| @@ -2582,6 +2675,8 @@ ScriptValue WebGLRenderingContextBase::getParameter(ScriptState* scriptState, GL |
| case GL_ALIASED_POINT_SIZE_RANGE: |
| return getWebGLFloatArrayParameter(scriptState, pname); |
| case GL_ALPHA_BITS: |
| + if (m_drawingBuffer->requiresRGBEmulation()) |
| + return WebGLAny(scriptState, 0); |
| return getIntParameter(scriptState, pname); |
| case GL_ARRAY_BUFFER_BINDING: |
| return WebGLAny(scriptState, m_boundArrayBuffer.get()); |
| @@ -3906,8 +4001,20 @@ GLenum WebGLRenderingContextBase::convertTexInternalFormat(GLenum internalformat |
| void WebGLRenderingContextBase::texImage2DBase(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels) |
| { |
| + moveGLErrorsToInternalQueue(); |
| + |
| // All calling functions check isContextLost, so a duplicate check is not needed here. |
| contextGL()->TexImage2D(target, level, convertTexInternalFormat(internalformat, type), width, height, border, format, type, pixels); |
| + |
| + GLenum error = contextGL()->GetError(); |
|
Ken Russell (switch to Gerrit)
2016/04/06 00:02:53
Sorry, but this synchronous GetError call will kil
|
| + if (error == GL_NO_ERROR) { |
| + WebGLTexture* texture = validateTexture2DBinding("texImage2DBase", target); |
| + if (texture) |
| + texture->setColorFormat(format); |
| + } else { |
| + if (!m_syntheticErrors.contains(error)) |
| + m_syntheticErrors.append(error); |
| + } |
| } |
| void WebGLRenderingContextBase::texImage2DImpl(GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, Image* image, WebGLImageConversion::ImageHtmlDomSource domSource, bool flipY, bool premultiplyAlpha) |