Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(533)

Side by Side Diff: chrome/browser/android/vr_shell/mailbox_to_surface_bridge.cc

Issue 2739973002: Revert of WebVR compositor bypass via BrowserMain context + mailbox (Closed)
Patch Set: Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/android/vr_shell/mailbox_to_surface_bridge.h"
6
7 #include <string>
8
9 #include "base/logging.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/sys_info.h"
12 #include "cc/output/context_provider.h"
13 #include "content/public/browser/android/compositor.h"
14 #include "gpu/GLES2/gl2extchromium.h"
15 #include "gpu/command_buffer/client/gles2_interface.h"
16 #include "gpu/command_buffer/common/mailbox.h"
17 #include "gpu/command_buffer/common/mailbox_holder.h"
18 #include "gpu/command_buffer/common/sync_token.h"
19 #include "gpu/ipc/client/gpu_channel_host.h"
20 #include "gpu/ipc/common/gpu_surface_tracker.h"
21 #include "services/ui/public/cpp/gpu/context_provider_command_buffer.h"
22 #include "ui/gl/android/surface_texture.h"
23
24 #include <android/native_window_jni.h>
25
26 #define VOID_OFFSET(x) reinterpret_cast<void*>(x)
27 #define SHADER(Src) #Src
28
29 namespace {
30
31 const char kQuadCopyVertex[] =
32 SHADER(attribute vec4 a_Position; attribute vec2 a_TexCoordinate;
33 varying vec2 v_TexCoordinate;
34 void main() {
35 v_TexCoordinate = a_TexCoordinate;
36 gl_Position = a_Position;
37 });
38
39 const char kQuadCopyFragment[] = SHADER(
40 precision highp float; uniform sampler2D u_Texture;
41 varying vec2 v_TexCoordinate;
42 void main() { gl_FragColor = texture2D(u_Texture, v_TexCoordinate); });
43
44 const float kQuadVertices[] = {
45 // clang-format off
46 // x y u, v
47 -1.f, 1.f, 0.f, 1.f,
48 -1.f, -1.f, 0.f, 0.f,
49 1.f, -1.f, 1.f, 0.f,
50 1.f, 1.f, 1.f, 1.f};
51 static constexpr int kQuadVerticesSize = sizeof(kQuadVertices);
52
53 GLuint CompileShader(gpu::gles2::GLES2Interface* gl,
54 GLenum shader_type,
55 const GLchar* shader_source) {
56 GLuint shader_handle = gl->CreateShader(shader_type);
57 if (shader_handle != 0) {
58 // Pass in the shader source.
59 GLint len = strlen(shader_source);
60 gl->ShaderSource(shader_handle, 1, &shader_source, &len);
61 // Compile the shader.
62 gl->CompileShader(shader_handle);
63 // Get the compilation status.
64 GLint status = 0;
65 gl->GetShaderiv(shader_handle, GL_COMPILE_STATUS, &status);
66 if (status == GL_FALSE) {
67 GLint info_log_length = 0;
68 gl->GetShaderiv(shader_handle, GL_INFO_LOG_LENGTH, &info_log_length);
69 auto str_info_log = base::MakeUnique<GLchar[]>(info_log_length + 1);
70 gl->GetShaderInfoLog(shader_handle, info_log_length, nullptr,
71 str_info_log.get());
72 DLOG(ERROR) << "Error compiling shader: " << str_info_log.get();
73 gl->DeleteShader(shader_handle);
74 shader_handle = 0;
75 }
76 }
77
78 return shader_handle;
79 }
80
81 GLuint CreateAndLinkProgram(gpu::gles2::GLES2Interface* gl,
82 GLuint vertex_shader_handle,
83 GLuint fragment_shader_handle) {
84 GLuint program_handle = gl->CreateProgram();
85
86 if (program_handle != 0) {
87 // Bind the vertex shader to the program.
88 gl->AttachShader(program_handle, vertex_shader_handle);
89
90 // Bind the fragment shader to the program.
91 gl->AttachShader(program_handle, fragment_shader_handle);
92
93 // Link the two shaders together into a program.
94 gl->LinkProgram(program_handle);
95
96 // Get the link status.
97 GLint link_status = 0;
98 gl->GetProgramiv(program_handle, GL_LINK_STATUS, &link_status);
99
100 // If the link failed, delete the program.
101 if (link_status == GL_FALSE) {
102 GLint info_log_length;
103 gl->GetProgramiv(program_handle, GL_INFO_LOG_LENGTH, &info_log_length);
104
105 auto str_info_log = base::MakeUnique<GLchar[]>(info_log_length + 1);
106 gl->GetProgramInfoLog(program_handle, info_log_length, nullptr,
107 str_info_log.get());
108 DLOG(ERROR) << "Error compiling program: " << str_info_log.get();
109 gl->DeleteProgram(program_handle);
110 program_handle = 0;
111 }
112 }
113
114 return program_handle;
115 }
116
117 GLuint ConsumeTexture(gpu::gles2::GLES2Interface* gl,
118 const gpu::MailboxHolder& mailbox) {
119 TRACE_EVENT0("gpu", "MailboxToSurfaceBridge::ConsumeTexture");
120 gl->WaitSyncTokenCHROMIUM(mailbox.sync_token.GetConstData());
121
122 return gl->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D,
123 mailbox.mailbox.name);
124 }
125
126 } // namespace
127
128 namespace vr_shell {
129
130 MailboxToSurfaceBridge::MailboxToSurfaceBridge() : weak_ptr_factory_(this) {}
131
132 MailboxToSurfaceBridge::~MailboxToSurfaceBridge() {
133 if (surface_handle_) {
134 // Unregister from the surface tracker to avoid a resource leak.
135 gpu::GpuSurfaceTracker* tracker = gpu::GpuSurfaceTracker::Get();
136 tracker->UnregisterViewSurface(surface_handle_);
137 }
138 DestroyContext();
139 }
140
141 void MailboxToSurfaceBridge::OnContextAvailable(
142 scoped_refptr<cc::ContextProvider> provider) {
143 // Must save a reference to the ContextProvider to keep it alive,
144 // otherwise the GL context created from it becomes invalid.
145 context_provider_ = std::move(provider);
146
147 if (!context_provider_->BindToCurrentThread()) {
148 DLOG(ERROR) << "Failed to init ContextProvider";
149 return;
150 }
151
152 gl_ = context_provider_->ContextGL();
153
154 if (!gl_) {
155 DLOG(ERROR) << "Did not get a GL context";
156 return;
157 }
158 InitializeRenderer();
159 }
160
161 void MailboxToSurfaceBridge::CreateSurface(
162 gl::SurfaceTexture* surface_texture) {
163 ANativeWindow* window = surface_texture->CreateSurface();
164 gpu::GpuSurfaceTracker* tracker = gpu::GpuSurfaceTracker::Get();
165 ANativeWindow_acquire(window);
166 // Skip ANativeWindow_setBuffersGeometry, the default size appears to work.
167 surface_handle_ = tracker->AddSurfaceForNativeWidget(window);
168
169 auto surface = base::MakeUnique<gl::ScopedJavaSurface>(surface_texture);
170 tracker->RegisterViewSurface(surface_handle_, surface->j_surface().obj());
171 // Unregistering happens in the destructor.
172 ANativeWindow_release(window);
173
174 // Our attributes must be compatible with the shared offscreen
175 // surface used by virtualized contexts, otherwise mailbox
176 // synchronization doesn't work properly - it assumes a shared
177 // underlying GL context. See GetCompositorContextAttributes
178 // in content/browser/renderer_host/compositor_impl_android.cc
179 // and crbug.com/699330.
180
181 gpu::gles2::ContextCreationAttribHelper attributes;
182 attributes.alpha_size = -1;
183 attributes.red_size = 8;
184 attributes.green_size = 8;
185 attributes.blue_size = 8;
186 attributes.stencil_size = 0;
187 attributes.depth_size = 0;
188 attributes.samples = 0;
189 attributes.sample_buffers = 0;
190 attributes.bind_generates_resource = false;
191 if (base::SysInfo::IsLowEndDevice()) {
192 attributes.alpha_size = 0;
193 attributes.red_size = 5;
194 attributes.green_size = 6;
195 attributes.blue_size = 5;
196 }
197
198 content::Compositor::CreateContextProvider(
199 surface_handle_, attributes, gpu::SharedMemoryLimits::ForMailboxContext(),
200 base::Bind(&MailboxToSurfaceBridge::OnContextAvailable,
201 weak_ptr_factory_.GetWeakPtr()));
202 }
203
204 void MailboxToSurfaceBridge::ResizeSurface(int width, int height) {
205 if (!gl_) {
206 // We're not initialized yet, save the requested size for later.
207 needs_resize_ = true;
208 resize_width_ = width;
209 resize_height_ = height;
210 return;
211 }
212 gl_->ResizeCHROMIUM(width, height, 1.f, false);
213 gl_->Viewport(0, 0, width, height);
214 }
215
216 bool MailboxToSurfaceBridge::CopyMailboxToSurfaceAndSwap(
217 const gpu::MailboxHolder& mailbox) {
218 if (!gl_) {
219 // We may not have a context yet, i.e. due to surface initialization
220 // being incomplete. This is not an error, but we obviously can't draw
221 // yet.
222 return false;
223 }
224
225 if (needs_resize_) {
226 ResizeSurface(resize_width_, resize_height_);
227 needs_resize_ = false;
228 }
229
230 GLuint sourceTexture = ConsumeTexture(gl_, mailbox);
231 DrawQuad(sourceTexture);
232 gl_->SwapBuffers();
233 return true;
234 }
235
236 void MailboxToSurfaceBridge::DestroyContext() {
237 gl_ = nullptr;
238 context_provider_ = nullptr;
239 }
240
241 void MailboxToSurfaceBridge::InitializeRenderer() {
242 GLuint vertex_shader_handle =
243 CompileShader(gl_, GL_VERTEX_SHADER, kQuadCopyVertex);
244 if (!vertex_shader_handle) {
245 DestroyContext();
246 return;
247 }
248
249 GLuint fragment_shader_handle =
250 CompileShader(gl_, GL_FRAGMENT_SHADER, kQuadCopyFragment);
251 if (!fragment_shader_handle) {
252 DestroyContext();
253 return;
254 }
255
256 GLuint program_handle =
257 CreateAndLinkProgram(gl_, vertex_shader_handle, fragment_shader_handle);
258 if (!program_handle) {
259 DestroyContext();
260 return;
261 }
262
263 // Once the program is linked the shader objects are no longer needed
264 gl_->DeleteShader(vertex_shader_handle);
265 gl_->DeleteShader(fragment_shader_handle);
266
267 GLuint position_handle = gl_->GetAttribLocation(program_handle, "a_Position");
268 GLuint texCoord_handle =
269 gl_->GetAttribLocation(program_handle, "a_TexCoordinate");
270 GLuint texUniform_handle =
271 gl_->GetUniformLocation(program_handle, "u_Texture");
272
273 GLuint vertexBuffer = 0;
274 gl_->GenBuffers(1, &vertexBuffer);
275 gl_->BindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
276 gl_->BufferData(GL_ARRAY_BUFFER, kQuadVerticesSize, kQuadVertices,
277 GL_STATIC_DRAW);
278
279 // Set state once only, we assume that nobody else modifies GL state in a way
280 // that would interfere with our operations.
281 gl_->Disable(GL_CULL_FACE);
282 gl_->DepthMask(GL_FALSE);
283 gl_->Disable(GL_DEPTH_TEST);
284 gl_->Disable(GL_SCISSOR_TEST);
285 gl_->Disable(GL_BLEND);
286 gl_->Disable(GL_POLYGON_OFFSET_FILL);
287
288 // Not using gl_->Viewport, we assume that it defaults to the whole
289 // surface and gets updated by ResizeSurface externally as
290 // appropriate.
291
292 gl_->UseProgram(program_handle);
293
294 // Bind vertex attributes
295 gl_->BindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
296
297 gl_->EnableVertexAttribArray(position_handle);
298 gl_->EnableVertexAttribArray(texCoord_handle);
299
300 static constexpr size_t VERTEX_STRIDE = sizeof(float) * 4;
301 static constexpr size_t POSITION_ELEMENTS = 2;
302 static constexpr size_t TEXCOORD_ELEMENTS = 2;
303 static constexpr size_t POSITION_OFFSET = 0;
304 static constexpr size_t TEXCOORD_OFFSET = sizeof(float) * 2;
305
306 gl_->VertexAttribPointer(position_handle, POSITION_ELEMENTS, GL_FLOAT, false,
307 VERTEX_STRIDE, VOID_OFFSET(POSITION_OFFSET));
308 gl_->VertexAttribPointer(texCoord_handle, TEXCOORD_ELEMENTS, GL_FLOAT, false,
309 VERTEX_STRIDE, VOID_OFFSET(TEXCOORD_OFFSET));
310
311 gl_->ActiveTexture(GL_TEXTURE0);
312 gl_->Uniform1i(texUniform_handle, 0);
313 }
314
315 void MailboxToSurfaceBridge::DrawQuad(unsigned int texture_handle) {
316 // No need to clear since we're redrawing on top of the entire
317 // viewport, but let the GPU know we don't need the old content
318 // anymore.
319 GLenum discards[] = {GL_COLOR_EXT};
320 gl_->DiscardFramebufferEXT(GL_FRAMEBUFFER, arraysize(discards), discards);
321
322 // Configure texture. This is a 1:1 pixel copy since the surface
323 // size is resized to match the source canvas, so we can use
324 // GL_NEAREST.
325 gl_->BindTexture(GL_TEXTURE_2D, texture_handle);
326 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
327 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
328 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
329 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
330 gl_->DrawArrays(GL_TRIANGLE_FAN, 0, 4);
331 }
332
333 } // namespace vr_shell
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698