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

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

Powered by Google App Engine
This is Rietveld 408576698