Mac: Add partial swap support to NSOpenGLContext path
Add a damage rect parameter to the structure
GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params.
Because that structure and its IPC are Mac-only, wrap them
in ifdefs.
Add code in the IOSurface draw function to clear out the
difference between the IOSurface and its viewport.
BUG=496484
Review URL: https://codereview.chromium.org/1161853006
Cr-Commit-Position: refs/heads/master@{#333231}
diff --git a/ui/accelerated_widget_mac/accelerated_widget_mac.h b/ui/accelerated_widget_mac/accelerated_widget_mac.h
index 9b9cb53..d4646bf5 100644
--- a/ui/accelerated_widget_mac/accelerated_widget_mac.h
+++ b/ui/accelerated_widget_mac/accelerated_widget_mac.h
@@ -10,6 +10,7 @@
#include "ui/accelerated_widget_mac/accelerated_widget_mac_export.h"
#include "ui/events/latency_info.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_widget_types.h"
@@ -78,8 +79,9 @@
void GotAcceleratedFrame(
uint64 surface_handle,
const std::vector<ui::LatencyInfo>& latency_info,
- gfx::Size pixel_size,
+ const gfx::Size& pixel_size,
float scale_factor,
+ const gfx::Rect& pixel_damage_rect,
const base::Closure& drawn_callback);
void GotSoftwareFrame(float scale_factor, SkCanvas* canvas);
@@ -90,14 +92,17 @@
void IOSurfaceLayerDidDrawFrame() override;
void IOSurfaceLayerHitError() override;
- void GotAcceleratedCAContextFrame(
- CAContextID ca_context_id, gfx::Size pixel_size, float scale_factor);
+ void GotAcceleratedCAContextFrame(CAContextID ca_context_id,
+ const gfx::Size& pixel_size,
+ float scale_factor);
- void GotAcceleratedIOSurfaceFrame(
- IOSurfaceID io_surface_id, gfx::Size pixel_size, float scale_factor);
+ void GotAcceleratedIOSurfaceFrame(IOSurfaceID io_surface_id,
+ const gfx::Size& pixel_size,
+ float scale_factor);
void GotAcceleratedIOSurfaceFrameNSGL(
- IOSurfaceID io_surface_id, gfx::Size pixel_size, float scale_factor);
+ IOSurfaceID io_surface_id, const gfx::Size& pixel_size,
+ float scale_factor, const gfx::Rect& pixel_damage_rect);
void AcknowledgeAcceleratedFrame();
@@ -160,7 +165,9 @@
void AcceleratedWidgetMacGotAcceleratedFrame(
gfx::AcceleratedWidget widget, uint64 surface_handle,
const std::vector<ui::LatencyInfo>& latency_info,
- gfx::Size pixel_size, float scale_factor,
+ const gfx::Size& pixel_size,
+ float scale_factor,
+ const gfx::Rect& pixel_damage_rect,
const base::Closure& drawn_callback,
bool* disable_throttling, int* renderer_id);
diff --git a/ui/accelerated_widget_mac/accelerated_widget_mac.mm b/ui/accelerated_widget_mac/accelerated_widget_mac.mm
index 6a6433d..19beee03 100644
--- a/ui/accelerated_widget_mac/accelerated_widget_mac.mm
+++ b/ui/accelerated_widget_mac/accelerated_widget_mac.mm
@@ -131,7 +131,9 @@
void AcceleratedWidgetMac::GotAcceleratedFrame(
uint64 surface_handle,
const std::vector<ui::LatencyInfo>& latency_info,
- gfx::Size pixel_size, float scale_factor,
+ const gfx::Size& pixel_size,
+ float scale_factor,
+ const gfx::Rect& pixel_damage_rect,
const base::Closure& drawn_callback) {
static bool use_ns_gl_surfaces =
base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -158,7 +160,7 @@
IOSurfaceID io_surface_id = IOSurfaceIDFromSurfaceHandle(surface_handle);
if (use_ns_gl_surfaces) {
GotAcceleratedIOSurfaceFrameNSGL(
- io_surface_id, pixel_size, scale_factor);
+ io_surface_id, pixel_size, scale_factor, pixel_damage_rect);
} else {
GotAcceleratedIOSurfaceFrame(io_surface_id, pixel_size, scale_factor);
}
@@ -177,7 +179,7 @@
void AcceleratedWidgetMac::GotAcceleratedCAContextFrame(
CAContextID ca_context_id,
- gfx::Size pixel_size,
+ const gfx::Size& pixel_size,
float scale_factor) {
// In the layer is replaced, keep the old one around until after the new one
// is installed to avoid flashes.
@@ -209,7 +211,10 @@
}
void AcceleratedWidgetMac::GotAcceleratedIOSurfaceFrameNSGL(
- IOSurfaceID io_surface_id, gfx::Size pixel_size, float scale_factor) {
+ IOSurfaceID io_surface_id,
+ const gfx::Size& pixel_size,
+ float scale_factor,
+ const gfx::Rect& pixel_damage_rect) {
if (!io_surface_ns_gl_surface_) {
io_surface_ns_gl_surface_.reset(
IOSurfaceNSGLSurface::Create(view_->AcceleratedWidgetGetNSView()));
@@ -221,13 +226,14 @@
return;
}
- io_surface_ns_gl_surface_->GotFrame(io_surface_id, pixel_size, scale_factor);
+ io_surface_ns_gl_surface_->GotFrame(
+ io_surface_id, pixel_size, scale_factor, pixel_damage_rect);
AcknowledgeAcceleratedFrame();
}
void AcceleratedWidgetMac::GotAcceleratedIOSurfaceFrame(
IOSurfaceID io_surface_id,
- gfx::Size pixel_size,
+ const gfx::Size& pixel_size,
float scale_factor) {
// In the layer is replaced, keep the old one around until after the new one
// is installed to avoid flashes.
@@ -389,14 +395,17 @@
void AcceleratedWidgetMacGotAcceleratedFrame(
gfx::AcceleratedWidget widget, uint64 surface_handle,
const std::vector<ui::LatencyInfo>& latency_info,
- gfx::Size pixel_size, float scale_factor,
+ const gfx::Size& pixel_size,
+ float scale_factor,
+ const gfx::Rect& pixel_damage_rect,
const base::Closure& drawn_callback,
bool* disable_throttling, int* renderer_id) {
AcceleratedWidgetMac* accelerated_widget_mac =
GetHelperFromAcceleratedWidget(widget);
if (accelerated_widget_mac) {
accelerated_widget_mac->GotAcceleratedFrame(
- surface_handle, latency_info, pixel_size, scale_factor, drawn_callback);
+ surface_handle, latency_info, pixel_size, scale_factor,
+ pixel_damage_rect, drawn_callback);
*disable_throttling =
accelerated_widget_mac->IsRendererThrottlingDisabled();
*renderer_id = accelerated_widget_mac->GetRendererID();
diff --git a/ui/accelerated_widget_mac/io_surface_ns_gl_surface.h b/ui/accelerated_widget_mac/io_surface_ns_gl_surface.h
index 4a9d6e0..7cfb4969 100644
--- a/ui/accelerated_widget_mac/io_surface_ns_gl_surface.h
+++ b/ui/accelerated_widget_mac/io_surface_ns_gl_surface.h
@@ -22,7 +22,8 @@
// Called on the UI thread.
bool GotFrame(IOSurfaceID io_surface_id,
gfx::Size pixel_size,
- float scale_factor);
+ float scale_factor,
+ gfx::Rect pixel_damage_rect);
private:
explicit IOSurfaceNSGLSurface(
diff --git a/ui/accelerated_widget_mac/io_surface_ns_gl_surface.mm b/ui/accelerated_widget_mac/io_surface_ns_gl_surface.mm
index ed1050f..68d00bdf 100644
--- a/ui/accelerated_widget_mac/io_surface_ns_gl_surface.mm
+++ b/ui/accelerated_widget_mac/io_surface_ns_gl_surface.mm
@@ -65,7 +65,8 @@
bool IOSurfaceNSGLSurface::GotFrame(IOSurfaceID io_surface_id,
gfx::Size frame_pixel_size,
- float frame_scale_factor) {
+ float frame_scale_factor,
+ gfx::Rect pixel_damage_rect) {
// The OpenGL framebuffer's scale factor and pixel size are updated to match
// the CALayer's contentsScale and bounds at setView. The pixel size is the
// stored in the GL_VIEWPORT state of the context.
@@ -82,18 +83,26 @@
// If the OpenGL framebuffer does not match the frame in scale factor or
// pixel size, then re-latch them. Note that they will latch to the layer's
// bounds, which will not necessarily match the frame's pixel size.
+ bool full_damage = false;
if (frame_pixel_size != contents_pixel_size ||
frame_scale_factor != contents_scale_factor) {
ScopedCAActionDisabler disabler;
[ns_gl_context_ clearDrawable];
[[view_ layer] setContentsScale:frame_scale_factor];
[ns_gl_context_ setView:view_];
+
+ // The front buffer may have been destroyed at re-creation, so re-draw
+ // everything.
+ full_damage = true;
}
bool result = true;
[ns_gl_context_ makeCurrentContext];
result &= iosurface_->SetIOSurface(io_surface_id, frame_pixel_size);
- result &= iosurface_->DrawIOSurface();
+ if (full_damage)
+ result &= iosurface_->DrawIOSurface();
+ else
+ result &= iosurface_->DrawIOSurfaceWithDamageRect(pixel_damage_rect);
glFlush();
[NSOpenGLContext clearCurrentContext];
return result;
diff --git a/ui/accelerated_widget_mac/io_surface_texture.h b/ui/accelerated_widget_mac/io_surface_texture.h
index 473e69cb..2cdd235 100644
--- a/ui/accelerated_widget_mac/io_surface_texture.h
+++ b/ui/accelerated_widget_mac/io_surface_texture.h
@@ -40,7 +40,6 @@
class IOSurfaceTexture
: public base::RefCounted<IOSurfaceTexture> {
public:
- // Returns NULL if IOSurfaceTexture or GL API calls fail.
static scoped_refptr<IOSurfaceTexture> Create(
bool needs_gl_finish_workaround);
@@ -54,6 +53,7 @@
// larger than the IOSurface, the remaining right and bottom edges will be
// white. |window_scale_factor| is 1 in normal views, 2 in HiDPI views.
bool DrawIOSurface() WARN_UNUSED_RESULT;
+ bool DrawIOSurfaceWithDamageRect(gfx::Rect damage_rect) WARN_UNUSED_RESULT;
// Returns true if the offscreen context used by this surface has been
// poisoned.
@@ -67,6 +67,10 @@
bool needs_gl_finish_workaround);
~IOSurfaceTexture();
+ // Draw the sepecified rect of the IOSurface. If |draw_boundary| is true,
+ // clear any overflow regions with white.
+ bool DrawIOSurfaceInternal(gfx::Rect damage_rect, bool draw_boundary);
+
// Unref the IOSurfaceTexture and delete the associated GL texture. If the GPU
// process is no longer referencing it, this will delete the IOSurface.
void ReleaseIOSurfaceAndTexture();
diff --git a/ui/accelerated_widget_mac/io_surface_texture.mm b/ui/accelerated_widget_mac/io_surface_texture.mm
index 291fbdd..d3898a4 100644
--- a/ui/accelerated_widget_mac/io_surface_texture.mm
+++ b/ui/accelerated_widget_mac/io_surface_texture.mm
@@ -63,7 +63,16 @@
}
bool IOSurfaceTexture::DrawIOSurface() {
- TRACE_EVENT0("browser", "IOSurfaceTexture::DrawIOSurface");
+ return DrawIOSurfaceInternal(gfx::Rect(pixel_size_), true);
+}
+
+bool IOSurfaceTexture::DrawIOSurfaceWithDamageRect(gfx::Rect damage_rect) {
+ return DrawIOSurfaceInternal(damage_rect, false);
+}
+
+bool IOSurfaceTexture::DrawIOSurfaceInternal(
+ gfx::Rect damage_rect, bool draw_boundary) {
+ TRACE_EVENT0("browser", "IOSurfaceTexture::DrawIOSurfaceInternal");
DCHECK(CGLGetCurrentContext());
// If we have release the IOSurface, clear the screen to light grey and
@@ -94,14 +103,14 @@
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_);
glBegin(GL_QUADS);
- glTexCoord2f(0, 0);
- glVertex2f(0, 0);
- glTexCoord2f(pixel_size_.width(), 0);
- glVertex2f(pixel_size_.width(), 0);
- glTexCoord2f(pixel_size_.width(), pixel_size_.height());
- glVertex2f(pixel_size_.width(), pixel_size_.height());
- glTexCoord2f(0, pixel_size_.height());
- glVertex2f(0, pixel_size_.height());
+ glTexCoord2f(damage_rect.x(), damage_rect.y());
+ glVertex2f(damage_rect.x(), damage_rect.y());
+ glTexCoord2f(damage_rect.right(), damage_rect.y());
+ glVertex2f(damage_rect.right(), damage_rect.y());
+ glTexCoord2f(damage_rect.right(), damage_rect.bottom());
+ glVertex2f(damage_rect.right(), damage_rect.bottom());
+ glTexCoord2f(damage_rect.x(), damage_rect.bottom());
+ glVertex2f(damage_rect.x(), damage_rect.bottom());
glEnd();
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
glDisable(GL_TEXTURE_RECTANGLE_ARB);
@@ -112,6 +121,28 @@
glBegin(GL_TRIANGLES);
glEnd();
+ // If the viewport is larger than the texture, clear out the overflow to
+ // white.
+ if (draw_boundary) {
+ if (pixel_size_.width() < viewport_rect.width()) {
+ glBegin(GL_QUADS);
+ glVertex2f(pixel_size_.width(), 0);
+ glVertex2f(pixel_size_.width(), viewport_rect.height());
+ glVertex2f(viewport_rect.width(), viewport_rect.height());
+ glVertex2f(viewport_rect.width(), 0);
+ glEnd();
+ }
+ if (pixel_size_.height() < viewport_rect.height()) {
+ int non_surface_height = viewport_rect.height() - pixel_size_.height();
+ glBegin(GL_QUADS);
+ glVertex2f(0, 0);
+ glVertex2f(0, non_surface_height);
+ glVertex2f(pixel_size_.width(), non_surface_height);
+ glVertex2f(pixel_size_.width(), 0);
+ glEnd();
+ }
+ }
+
if (needs_gl_finish_workaround_) {
TRACE_EVENT0("gpu", "glFinish");
glFinish();