Index: third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp |
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp |
index 155558732ef1c1bfd811b51a7aaa3b5d72de3334..4b66b55401270c1b8809b2be484b83a71a199d7a 100644 |
--- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp |
+++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp |
@@ -576,6 +576,19 @@ DrawingBuffer::CreateOrRecycleColorBuffer() { |
return CreateColorBuffer(size_); |
} |
+DrawingBuffer::ScopedRGBEmulationForBlitFramebuffer:: |
+ ScopedRGBEmulationForBlitFramebuffer(DrawingBuffer* drawing_buffer) |
+ : drawing_buffer_(drawing_buffer) { |
+ doing_work_ = drawing_buffer->SetupRGBEmulationForBlitFramebuffer(); |
+} |
+ |
+DrawingBuffer::ScopedRGBEmulationForBlitFramebuffer:: |
+ ~ScopedRGBEmulationForBlitFramebuffer() { |
+ if (doing_work_) { |
+ drawing_buffer_->CleanupRGBEmulationForBlitFramebuffer(); |
+ } |
+} |
+ |
DrawingBuffer::ColorBuffer::ColorBuffer( |
DrawingBuffer* drawing_buffer, |
const ColorBufferParameters& parameters, |
@@ -599,6 +612,10 @@ DrawingBuffer::ColorBuffer::~ColorBuffer() { |
if (image_id) { |
gl->BindTexture(parameters.target, texture_id); |
gl->ReleaseTexImage2DCHROMIUM(parameters.target, image_id); |
+ if (rgb_workaround_texture_id) { |
+ gl->BindTexture(parameters.target, rgb_workaround_texture_id); |
+ gl->ReleaseTexImage2DCHROMIUM(parameters.target, image_id); |
+ } |
gl->DestroyImageCHROMIUM(image_id); |
switch (parameters.target) { |
case GL_TEXTURE_2D: |
@@ -618,6 +635,10 @@ DrawingBuffer::ColorBuffer::~ColorBuffer() { |
gpu_memory_buffer.reset(); |
} |
gl->DeleteTextures(1, &texture_id); |
+ if (rgb_workaround_texture_id) { |
+ // Avoid deleting this texture if it was unused. |
+ gl->DeleteTextures(1, &rgb_workaround_texture_id); |
+ } |
} |
bool DrawingBuffer::Initialize(const IntSize& size, bool use_multisampling) { |
@@ -1258,6 +1279,78 @@ GLenum DrawingBuffer::GetMultisampledRenderbufferFormat() { |
return GL_RGB8_OES; |
} |
+bool DrawingBuffer::SetupRGBEmulationForBlitFramebuffer() { |
+ // We only need to do this work if: |
+ // - The user has selected alpha:false and antialias:false |
+ // - We are using CHROMIUM_image with RGB emulation |
+ // macOS is the only platform on which this is necessary. |
+ |
+ if (want_alpha_channel_ || anti_aliasing_mode_ != kNone) |
+ return false; |
+ |
+ if (!(ShouldUseChromiumImage() && |
+ ContextProvider()->GetCapabilities().chromium_image_rgb_emulation)) |
+ return false; |
+ |
+ if (!back_color_buffer_) |
+ return false; |
+ |
+ // If for some reason the back buffer doesn't have a CHROMIUM_image, |
+ // don't proceed with this workaround. |
+ if (!back_color_buffer_->image_id) |
+ return false; |
+ |
+ // Before allowing the BlitFramebuffer call to go through, it's necessary |
+ // to swap out the RGBA texture that's bound to the CHROMIUM_image |
+ // instance with an RGB texture. BlitFramebuffer requires the internal |
+ // formats of the source and destination to match when doing a |
+ // multisample resolve, and the best way to achieve this without adding |
+ // more full-screen blits is to hook up a true RGB texture to the |
+ // underlying IOSurface. Unfortunately, on macOS, this rendering path |
+ // destroys the alpha channel and requires a fixup afterward, which is |
+ // why it isn't used all the time. |
+ |
+ GLuint rgb_texture = back_color_buffer_->rgb_workaround_texture_id; |
+ GLenum target = GC3D_TEXTURE_RECTANGLE_ARB; |
+ if (!rgb_texture) { |
+ gl_->GenTextures(1, &rgb_texture); |
+ gl_->BindTexture(target, rgb_texture); |
+ gl_->TexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
+ gl_->TexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
+ gl_->TexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
+ gl_->TexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
+ |
+ // Bind this texture to the CHROMIUM_image instance that the color |
+ // buffer owns. This is an expensive operation, so it's important that |
+ // the result be cached. |
+ gl_->BindTexImage2DWithInternalformatCHROMIUM(target, GL_RGB, |
+ back_color_buffer_->image_id); |
+ back_color_buffer_->rgb_workaround_texture_id = rgb_texture; |
+ } |
+ |
+ gl_->FramebufferTexture2D(GL_DRAW_FRAMEBUFFER_ANGLE, GL_COLOR_ATTACHMENT0, |
+ target, rgb_texture, 0); |
+ return true; |
+} |
+ |
+void DrawingBuffer::CleanupRGBEmulationForBlitFramebuffer() { |
+ // This will only be called if SetupRGBEmulationForBlitFramebuffer was. |
+ // Put the framebuffer back the way it was, and clear the alpha channel. |
+ DCHECK(back_color_buffer_); |
+ DCHECK(back_color_buffer_->image_id); |
+ GLenum target = GC3D_TEXTURE_RECTANGLE_ARB; |
+ gl_->FramebufferTexture2D(GL_DRAW_FRAMEBUFFER_ANGLE, GL_COLOR_ATTACHMENT0, |
+ target, back_color_buffer_->texture_id, 0); |
+ // Clear the alpha channel. |
+ gl_->ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); |
+ gl_->Disable(GL_SCISSOR_TEST); |
+ gl_->ClearColor(0, 0, 0, 1); |
+ gl_->Clear(GL_COLOR_BUFFER_BIT); |
+ DCHECK(client_); |
+ client_->DrawingBufferClientRestoreScissorTest(); |
+ client_->DrawingBufferClientRestoreMaskAndClearValues(); |
+} |
+ |
DrawingBuffer::ScopedStateRestorer::ScopedStateRestorer( |
DrawingBuffer* drawing_buffer) |
: drawing_buffer_(drawing_buffer) { |