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

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

Issue 2729523002: Re-land^2 WebVR compositor bypass via BrowserMain context + mailbox (Closed)
Patch Set: Merge mthiesse@'s submitFrameClient fix from crrev.com/2734003002/#ps60001 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 "content/public/browser/android/compositor.h"
12 #include "gpu/GLES2/gl2extchromium.h"
13 #include "gpu/command_buffer/client/gles2_interface.h"
14 #include "gpu/command_buffer/common/mailbox.h"
15 #include "gpu/command_buffer/common/mailbox_holder.h"
16 #include "gpu/command_buffer/common/sync_token.h"
17 #include "gpu/ipc/client/gpu_channel_host.h"
18 #include "gpu/ipc/common/gpu_surface_tracker.h"
19 #include "ui/gl/android/surface_texture.h"
20
21 #include <android/native_window_jni.h>
22
23 #define VOID_OFFSET(x) reinterpret_cast<void*>(x)
24 #define SHADER(Src) #Src
25
26 // TODO(klausw): move to static functions?
27 namespace {
28
29 const char* kQuadCopyVertex =
30 SHADER(attribute vec4 a_Position; attribute vec2 a_TexCoordinate;
31 varying vec2 v_TexCoordinate;
32 void main() {
33 v_TexCoordinate = a_TexCoordinate;
34 gl_Position = a_Position;
35 });
36
37 const char* kQuadCopyFragment = SHADER(
38 precision highp float; uniform sampler2D u_Texture;
39 varying vec2 v_TexCoordinate;
40 void main() { gl_FragColor = texture2D(u_Texture, v_TexCoordinate); });
41
42 static constexpr float kQuadVertices[16] = {
43 // x y u, v
44 -1.f, 1.f, 0.f, 1.f, -1.f, -1.f, 0.f, 0.f,
45 1.f, -1.f, 1.f, 0.f, 1.f, 1.f, 1.f, 1.f};
46 static constexpr int kQuadVerticesSize = sizeof(float) * 16;
47
48 GLuint CompileShader(gpu::gles2::GLES2Interface* gl,
mthiesse 2017/03/08 01:00:00 Move this into vr_gl_util.h/cc? We could share co
klausw 2017/03/08 02:59:22 I'd strongly prefer to keep this independent since
49 GLenum shaderType,
50 const GLchar* shaderSource,
51 std::string& error) {
52 GLuint shaderHandle = gl->CreateShader(shaderType);
53 if (shaderHandle != 0) {
54 // Pass in the shader source.
55 int len = strlen(shaderSource);
56 gl->ShaderSource(shaderHandle, 1, &shaderSource, &len);
57 // Compile the shader.
58 gl->CompileShader(shaderHandle);
59 // Get the compilation status.
60 GLint status = 0;
61 gl->GetShaderiv(shaderHandle, GL_COMPILE_STATUS, &status);
62 if (status == GL_FALSE) {
63 GLint infoLogLength = 0;
64 gl->GetShaderiv(shaderHandle, GL_INFO_LOG_LENGTH, &infoLogLength);
mthiesse 2017/03/08 01:00:01 nit: I know you're copying this from elsewhere, bu
klausw 2017/03/08 02:59:22 This code only gets executed if shader compilation
mthiesse 2017/03/08 04:15:42 This is good now. Generally we avoid unnecessary s
65 GLchar* strInfoLog = new GLchar[infoLogLength + 1];
66 gl->GetShaderInfoLog(shaderHandle, infoLogLength, nullptr, strInfoLog);
67 error = "Error compiling shader: ";
68 error += strInfoLog;
69 delete[] strInfoLog;
70 gl->DeleteShader(shaderHandle);
71 shaderHandle = 0;
72 }
73 }
74
75 return shaderHandle;
76 }
77
78 GLuint CreateAndLinkProgram(gpu::gles2::GLES2Interface* gl,
79 GLuint vertextShaderHandle,
80 GLuint fragmentShaderHandle,
81 std::string& error) {
82 GLuint programHandle = gl->CreateProgram();
83
84 if (programHandle != 0) {
85 // Bind the vertex shader to the program.
86 gl->AttachShader(programHandle, vertextShaderHandle);
87
88 // Bind the fragment shader to the program.
89 gl->AttachShader(programHandle, fragmentShaderHandle);
90
91 // Link the two shaders together into a program.
92 gl->LinkProgram(programHandle);
93
94 // Get the link status.
95 GLint linkStatus = 0;
96 gl->GetProgramiv(programHandle, GL_LINK_STATUS, &linkStatus);
97
98 // If the link failed, delete the program.
99 if (linkStatus == GL_FALSE) {
100 GLint infoLogLength;
101 gl->GetProgramiv(programHandle, GL_INFO_LOG_LENGTH, &infoLogLength);
102
103 GLchar* strInfoLog = new GLchar[infoLogLength + 1];
104 gl->GetProgramInfoLog(programHandle, infoLogLength, nullptr, strInfoLog);
105 error = "Error compiling program: ";
106 error += strInfoLog;
107 delete[] strInfoLog;
108 gl->DeleteProgram(programHandle);
109 programHandle = 0;
110 }
111 }
112
113 return programHandle;
114 }
115
116 } // namespace
117
118 namespace vr_shell {
119
120 MailboxToSurfaceBridge::MailboxToSurfaceBridge() : weak_ptr_factory_(this) {}
121
122 MailboxToSurfaceBridge::~MailboxToSurfaceBridge() {
123 if (surface_handle_) {
124 // Unregister from the surface tracker to avoid a resource leak.
125 gpu::GpuSurfaceTracker* tracker = gpu::GpuSurfaceTracker::Get();
126 tracker->UnregisterViewSurface(surface_handle_);
127 }
128 }
129
130 void MailboxToSurfaceBridge::OnGpuChannelEstablished(
131 scoped_refptr<gpu::GpuChannelHost> gpu_channel_host) {
132 // Our attributes must be compatible with the shared offscreen
mthiesse 2017/03/08 01:00:00 Add a comment to wherever the code lives that thes
klausw 2017/03/08 02:59:22 Done. I filed 699330 and also added an IsLowEndDev
133 // surface used by virtualized contexts, otherwise mailbox
134 // synchronization doesn't work properly - it assumes a shared
135 // underlying GL context. TODO(klausw): is there a more official
136 // way to get default-compatible settings?
137 gpu::gles2::ContextCreationAttribHelper attributes;
138 attributes.alpha_size = -1;
139 attributes.red_size = 8;
140 attributes.green_size = 8;
141 attributes.blue_size = 8;
142 attributes.stencil_size = 0;
143 attributes.depth_size = 0;
144 attributes.samples = 0;
145 attributes.sample_buffers = 0;
146 attributes.bind_generates_resource = false;
147
148 bool automatic_flushes = false;
149 bool support_locking = false;
150 constexpr ui::ContextProviderCommandBuffer* shared_context_provider = nullptr;
151 context_provider_command_buffer_ =
152 make_scoped_refptr(new ui::ContextProviderCommandBuffer(
153 std::move(gpu_channel_host), gpu::GPU_STREAM_DEFAULT,
154 gpu::GpuStreamPriority::NORMAL, surface_handle_,
155 GURL("chrome://gpu/WebVRContextFactory"), automatic_flushes,
156 support_locking, gpu::SharedMemoryLimits::ForMailboxContext(),
157 attributes, shared_context_provider,
158 ui::command_buffer_metrics::CONTEXT_TYPE_UNKNOWN));
159
160 if (!context_provider_command_buffer_->BindToCurrentThread()) {
161 LOG(ERROR) << __FUNCTION__ << ";;; failed to init ContextProvider";
mthiesse 2017/03/08 01:00:00 Remove this? (Or DLOG)
klausw 2017/03/08 02:59:22 Changed to DLOG
162 return;
163 }
164
165 gl_ = context_provider_command_buffer_->ContextGL();
166
167 InitializeRenderer();
168 }
169
170 std::unique_ptr<gl::ScopedJavaSurface> MailboxToSurfaceBridge::CreateSurface(
171 scoped_refptr<gl::SurfaceTexture> surface_texture) {
172 ANativeWindow* window = surface_texture->CreateSurface();
173 gpu::GpuSurfaceTracker* tracker = gpu::GpuSurfaceTracker::Get();
174 ANativeWindow_acquire(window);
175 // Skip ANativeWindow_setBuffersGeometry, the default size appears to work.
176 surface_handle_ = tracker->AddSurfaceForNativeWidget(window);
177
178 auto surface = base::MakeUnique<gl::ScopedJavaSurface>(surface_texture.get());
179 tracker->RegisterViewSurface(surface_handle_, surface->j_surface().obj());
180 // Unregistering happens in the destructor.
181 ANativeWindow_release(window);
182
183 gpu::GpuChannelEstablishFactory* factory =
184 content::Compositor::GetGpuChannelFactory();
185
186 factory->EstablishGpuChannel(
187 base::Bind(&MailboxToSurfaceBridge::OnGpuChannelEstablished,
188 weak_ptr_factory_.GetWeakPtr()));
189
190 return surface;
191 }
192
193 void MailboxToSurfaceBridge::ResizeSurface(int width, int height) {
194 if (!gl_) {
195 LOG(ERROR) << "Cannot resize, not initialized";
196 return;
197 }
198 gl_->ResizeCHROMIUM(width, height, 1.f, false);
199 gl_->Viewport(0, 0, width, height);
200 }
201
202 bool MailboxToSurfaceBridge::CopyFrameToSurface(
mthiesse 2017/03/08 01:00:01 nit: This function is somewhat confusing. Maybe sp
klausw 2017/03/08 02:59:22 I've created a separate ConsumeMailbox function, s
203 int frame_index,
204 const gpu::MailboxHolder& mailbox,
205 bool discard) {
206 TRACE_EVENT1("gpu", "MailboxToSurfaceBridge::CopyFrameToSurface", "frame",
207 frame_index);
208 if (!gl_) {
209 // We may not have a context yet, i.e. due to surface initialization
210 // being incomplete. This is not an error, but we obviously can't draw
211 // yet.
212 return false;
213 }
214
215 {
216 TRACE_EVENT0("gpu", "MailboxToSurfaceBridge::WaitSyncToken");
217 gl_->WaitSyncTokenCHROMIUM(mailbox.sync_token.GetConstData());
218 }
219
220 GLuint vrSourceTexture =
221 gl_->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.mailbox.name);
222
223 if (discard) {
224 // We've consumed the texture, but the caller requested that we
225 // don't draw it because the previous one hasn't been consumed
226 // yet. (Swapping twice on a Surfacewithout consuming one in
mthiesse 2017/03/08 01:00:00 nit: s/Surfacewithout/Surface without/
klausw 2017/03/08 02:59:22 Done.
227 // between from the SurfaceTexture can lose frames.) This should
228 // be rare, it's a waste of resources and can cause jerky
229 // animation due to the lost frames.
230 return false;
231 } else {
232 DrawQuad(vrSourceTexture);
233 gl_->SwapBuffers();
234 return true;
235 }
236 }
237
238 void MailboxToSurfaceBridge::InitializeRenderer() {
239 std::string error;
240 GLuint vertexShaderHandle =
241 CompileShader(gl_, GL_VERTEX_SHADER, kQuadCopyVertex, error);
242 CHECK(vertexShaderHandle) << error;
243
244 GLuint fragmentShaderHandle =
245 CompileShader(gl_, GL_FRAGMENT_SHADER, kQuadCopyFragment, error);
246 CHECK(fragmentShaderHandle) << error;
247
248 GLuint programHandle = CreateAndLinkProgram(gl_, vertexShaderHandle,
249 fragmentShaderHandle, error);
250 CHECK(programHandle) << error;
251
252 // Once the program is linked the shader objects are no longer needed
253 gl_->DeleteShader(vertexShaderHandle);
254 gl_->DeleteShader(fragmentShaderHandle);
255
256 GLuint positionHandle = gl_->GetAttribLocation(programHandle, "a_Position");
257 GLuint texCoordHandle =
258 gl_->GetAttribLocation(programHandle, "a_TexCoordinate");
259 GLuint texUniformHandle = gl_->GetUniformLocation(programHandle, "u_Texture");
260
261 GLuint vertexBuffer = 0;
262 gl_->GenBuffers(1, &vertexBuffer);
263 gl_->BindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
264 gl_->BufferData(GL_ARRAY_BUFFER, kQuadVerticesSize, kQuadVertices,
265 GL_STATIC_DRAW);
266
267 // Set state once only, we assume that nobody else modifies GL state in a way
268 // that would interfere with our operations.
269 gl_->Disable(GL_CULL_FACE);
270 gl_->DepthMask(GL_FALSE);
271 gl_->Disable(GL_DEPTH_TEST);
272 gl_->Disable(GL_SCISSOR_TEST);
273 gl_->Disable(GL_BLEND);
274 gl_->Disable(GL_POLYGON_OFFSET_FILL);
275
276 // Not using gl_->Viewport, we assume that it defaults to the whole
277 // surface and gets updated by ResizeSurface externally as
278 // appropriate.
279
280 gl_->UseProgram(programHandle);
281
282 // Bind vertex attributes
283 gl_->BindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
284
285 gl_->EnableVertexAttribArray(positionHandle);
286 gl_->EnableVertexAttribArray(texCoordHandle);
287
288 static constexpr size_t VERTEX_STRIDE = sizeof(float) * 4;
289 static constexpr size_t POSITION_ELEMENTS = 2;
290 static constexpr size_t TEXCOORD_ELEMENTS = 2;
291 static constexpr size_t POSITION_OFFSET = 0;
292 static constexpr size_t TEXCOORD_OFFSET = sizeof(float) * 2;
293
294 gl_->VertexAttribPointer(positionHandle, POSITION_ELEMENTS, GL_FLOAT, false,
295 VERTEX_STRIDE, VOID_OFFSET(POSITION_OFFSET));
296 gl_->VertexAttribPointer(texCoordHandle, TEXCOORD_ELEMENTS, GL_FLOAT, false,
297 VERTEX_STRIDE, VOID_OFFSET(TEXCOORD_OFFSET));
298
299 gl_->ActiveTexture(GL_TEXTURE0);
300 gl_->Uniform1i(texUniformHandle, 0);
301 }
302
303 void MailboxToSurfaceBridge::DrawQuad(unsigned int textureHandle) {
304 // No need to clear since we're redrawing on top of the entire
305 // viewport, but let the GPU know we don't need the old content
306 // anymore.
307 GLenum discards[] = {GL_COLOR_EXT};
308 gl_->DiscardFramebufferEXT(GL_FRAMEBUFFER, arraysize(discards), discards);
309
310 // Configure texture. This is a 1:1 pixel copy since the surface
311 // size is resized to match the source canvas, so we can use
312 // GL_NEAREST.
313 gl_->BindTexture(GL_TEXTURE_2D, textureHandle);
314 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
315 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
316 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
317 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
318 gl_->DrawArrays(GL_TRIANGLE_FAN, 0, 4);
319
320 gl_->Flush();
321 }
322
323 } // namespace vr_shell
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698