Index: gpu/command_buffer/service/gles2_cmd_decoder.cc |
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc |
index 0fd09df41456da9a3e8128c7fc58df6ebbe2dbda..d6a44c9eecd85d320c3553c8645e39cc8a2af446 100644 |
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc |
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc |
@@ -65,6 +65,7 @@ |
#include "gpu/command_buffer/service/transform_feedback_manager.h" |
#include "gpu/command_buffer/service/vertex_array_manager.h" |
#include "gpu/command_buffer/service/vertex_attrib_manager.h" |
+#include "gpu/ipc/common/gpu_surface_lookup.h" |
#include "third_party/angle/src/image_util/loadimage.h" |
#include "third_party/smhasher/src/City.h" |
#include "ui/gfx/buffer_types.h" |
@@ -82,6 +83,7 @@ |
#include "ui/gl/gl_image.h" |
#include "ui/gl/gl_implementation.h" |
#include "ui/gl/gl_surface.h" |
+#include "ui/gl/gl_surface_egl.h" |
#include "ui/gl/gl_version_info.h" |
#include "ui/gl/gpu_timing.h" |
@@ -1035,6 +1037,8 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient { |
void DoFlushMappedBufferRange( |
GLenum target, GLintptr offset, GLsizeiptr size); |
+ void DoSetSurfaceHandleCHROMIUM(GLint surface_handle); |
+ |
// Creates a Program for the given program. |
Program* CreateProgram(GLuint client_id, GLuint service_id) { |
return program_manager()->CreateProgram(client_id, service_id); |
@@ -2132,6 +2136,15 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient { |
scoped_refptr<gl::GLSurface> surface_; |
scoped_refptr<gl::GLContext> context_; |
+ // Direct render mode data for switching and restoring the |
+ // underlying destination surface, cf. DoSetSurfaceHandleCHROMIUM. |
+ scoped_refptr<gl::GLSurface> direct_render_surface_; |
+ scoped_refptr<gl::GLSurface> direct_render_orig_surface_; |
+ std::unique_ptr<BackFramebuffer> |
+ direct_render_orig_offscreen_target_frame_buffer_; |
+ bool direct_render_orig_supports_async_swap_; |
+ bool direct_render_orig_back_buffer_has_depth_; |
+ |
// The ContextGroup for this decoder uses to track resources. |
scoped_refptr<ContextGroup> group_; |
@@ -16924,6 +16937,84 @@ void GLES2DecoderImpl::DoApplyScreenSpaceAntialiasingCHROMIUM() { |
} |
} |
+void GLES2DecoderImpl::DoSetSurfaceHandleCHROMIUM(GLint surface_handle) { |
+#if defined(OS_ANDROID) |
+ if (surface_handle) { |
+ // Use the specified surface as a render target, saving the offscreen |
+ // render buffer so that we can restore it later. |
+ |
+ // Ignore redundant calls. For now we don't support switching between |
+ // different surfaces, if you need this you have to make a call with |
+ // surface_handle=0 in between. |
+ if (direct_render_surface_) { |
+ return; |
+ } |
+ |
+ // One-time initialization when first activating a direct draw surface. |
+ ANativeWindow* window = |
+ gpu::GpuSurfaceLookup::GetInstance()->AcquireNativeWidget( |
+ surface_handle); |
+ direct_render_surface_ = new gl::NativeViewGLSurfaceEGL(window); |
+ // TODO(klausw): need to add a depth buffer for doing 3D rendering. |
+ // Currently it's just used for a 2D copy. |
+ bool initialize_success = |
+ direct_render_surface_->Initialize(gl::GLSurface::SURFACE_ARGB8888); |
bajones
2016/11/08 05:17:01
The format of this surface should be the same as t
klausw
2016/11/08 18:45:05
Yes, done, and added a comment explaining why we c
|
+ if (!initialize_success) { |
+ LOG(ERROR) << "Direct render surface init failed for handle " << |
+ surface_handle; |
+ } |
+ ANativeWindow_release(window); |
+ |
+ direct_render_orig_surface_ = surface_; |
+ |
+ // We don't want async swap since we want full control over when the |
+ // SurfaceTexture gets updated. |
+ direct_render_orig_supports_async_swap_ = supports_async_swap_; |
+ supports_async_swap_ = false; |
+ direct_render_orig_back_buffer_has_depth_ = back_buffer_has_depth_; |
+ back_buffer_has_depth_ = true; |
+ // override back_buffer_has_stencil_ too? |
+ |
+ // Offscreen surfaces don't support SwapBuffers, make sure it's not |
+ // considered offscreen. Various code in this file checks for is_offscreen |
+ // = !!offscreen_target_frame_buffer_.get(). |
+ direct_render_orig_offscreen_target_frame_buffer_ = |
+ std::move(offscreen_target_frame_buffer_); |
+ offscreen_target_frame_buffer_.reset(nullptr); |
+ |
+ // Activate the surface. This does *not* rebind the active framebuffer, |
+ // callers must do so themselves. |
+ SetSurface(direct_render_surface_); |
+ |
+ // TODO(klausw): is any additional cleanup needed in destructor, or |
+ // do smart pointers do the right thing already? |
+ } else { |
+ // Restore original state for drawing offscreen. |
+ |
+ // Ignore redundant calls. |
+ if (!direct_render_surface_) return; |
+ |
+ // TODO(klausw): check if this is sufficient cleanup, I'm assuming that |
+ // clearing the smart pointer calls the appropriate destructor. |
bajones
2016/11/08 05:17:01
Correct. The smart pointers will call the destruct
klausw
2016/11/08 18:45:05
OK, removed the comment.
|
+ direct_render_surface_ = nullptr; |
+ |
+ supports_async_swap_ = direct_render_orig_supports_async_swap_; |
+ back_buffer_has_depth_ = direct_render_orig_back_buffer_has_depth_; |
+ |
+ offscreen_target_frame_buffer_ = |
+ std::move(direct_render_orig_offscreen_target_frame_buffer_); |
+ direct_render_orig_offscreen_target_frame_buffer_.reset(nullptr); |
+ |
+ SetSurface(direct_render_orig_surface_); |
+ } |
+#else // !OS_ANDROID |
+ LOCAL_SET_GL_ERROR( |
+ GL_INVALID_OPERATION, |
+ "glSetSurfaceHandleCHROMIUM", |
+ "Direct render surface is unsupported on this platform"); |
+#endif |
+} |
+ |
void GLES2DecoderImpl::DoInsertEventMarkerEXT( |
GLsizei length, const GLchar* marker) { |
if (!marker) { |