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

Side by Side Diff: remoting/client/plugin/pepper_video_renderer_3d.cc

Issue 820823002: Implement video renderer based on VideoDecode API. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 12 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 2014 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 "remoting/client/plugin/pepper_video_renderer_3d.h"
6
7 #include <math.h>
8
9 #include "base/callback_helpers.h"
10 #include "base/stl_util.h"
11 #include "ppapi/c/pp_codecs.h"
12 #include "ppapi/c/ppb_opengles2.h"
13 #include "ppapi/cpp/instance.h"
14 #include "ppapi/lib/gl/include/GLES2/gl2ext.h"
15 #include "remoting/proto/video.pb.h"
16 #include "remoting/protocol/session_config.h"
17
18 namespace remoting {
19
20 class PepperVideoRenderer3D::PendingPacket {
21 public:
22 PendingPacket(scoped_ptr<VideoPacket> packet, const base::Closure& done)
23 : packet_(packet.Pass()),
24 done_runner_(done) {
25 }
26
27 ~PendingPacket() {}
28
29 const VideoPacket* packet() const { return packet_.get(); }
30
31 private:
32 scoped_ptr<VideoPacket> packet_;
33 base::ScopedClosureRunner done_runner_;
34 };
35
36 PepperVideoRenderer3D::FrameDecodeTimer::FrameDecodeTimer(
37 uint32_t frame_id,
38 base::TimeTicks decode_started_time)
39 : frame_id(frame_id), decode_started_time(decode_started_time) {
40 }
41
42 PepperVideoRenderer3D::PepperVideoRenderer3D()
43 : event_handler_(nullptr),
44 view_width_(0),
45 view_height_(0),
46 latest_sequence_number_(0),
47 initialized_(false),
48 decode_pending_(false),
49 get_picture_pending_(false),
50 paint_pending_(false),
51 last_frame_id_(0),
52 need_repaint_(false),
53 current_shader_program_texture_target_(0),
54 shader_program_(0),
55 shader_texcoord_scale_location_(0),
56 callback_factory_(this) {
57 }
58
59 PepperVideoRenderer3D::~PepperVideoRenderer3D() {
60 RecyclePictures(false);
61
62 if (shader_program_)
63 gles2_if_->DeleteProgram(graphics_.pp_resource(), shader_program_);
64
65 STLDeleteElements(&pending_packets_);
66 }
67
68 bool PepperVideoRenderer3D::Initialize(pp::Instance* instance,
69 const ClientContext& context,
70 EventHandler* event_handler) {
71 DCHECK(event_handler);
72 DCHECK(!event_handler_);
73
74 event_handler_ = event_handler;
75
76 const int32_t context_attributes[] = {
77 PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8,
78 PP_GRAPHICS3DATTRIB_BLUE_SIZE, 8,
79 PP_GRAPHICS3DATTRIB_GREEN_SIZE, 8,
80 PP_GRAPHICS3DATTRIB_RED_SIZE, 8,
81 PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 0,
82 PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 0,
83 PP_GRAPHICS3DATTRIB_SAMPLES, 0,
84 PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0,
85 PP_GRAPHICS3DATTRIB_WIDTH, 1,
86 PP_GRAPHICS3DATTRIB_HEIGHT, 1,
Wez 2014/12/24 17:11:15 Are you sure that 1x1 is always supported by Graph
Sergey Ulanov 2015/01/06 01:16:32 changed this to 640x480
87 PP_GRAPHICS3DATTRIB_NONE,
88 };
89 graphics_ = pp::Graphics3D(instance, context_attributes);
90
91 if (graphics_.is_null()) {
92 LOG(WARNING) << "Graphics3D interface is not available.";
93 return false;
94 }
95 if (!instance->BindGraphics(graphics_)) {
Wez 2014/12/24 17:11:14 Do we need to tear-down and re-create/re-bind thin
Sergey Ulanov 2015/01/06 01:16:32 No. Graphics3D.ResizeBuffers() allows to change th
Wez 2015/01/06 22:17:10 Agreed! I vaguely recalled that the example seemed
96 LOG(WARNING) << "Failed to bind Graphics3D.";
97 return false;
98 }
99
100 // Fetch the GLES2 interface to use to render frames.
101 gles2_if_ = static_cast<const PPB_OpenGLES2*>(
102 pp::Module::Get()->GetBrowserInterface(PPB_OPENGLES2_INTERFACE));
103 CHECK(gles2_if_);
104
105 video_decoder_ = pp::VideoDecoder(instance);
106 if (video_decoder_.is_null()) {
107 LOG(WARNING) << "VideoDecoder interface is not available.";
108 return false;
109 }
110
111 PP_Resource graphics_3d = graphics_.pp_resource();
112
113 gles2_if_->ClearColor(graphics_3d, 1, 0, 0, 1);
114 gles2_if_->Clear(graphics_3d, GL_COLOR_BUFFER_BIT);
115
116 // Assign vertex positions and texture coordinates to buffers for use in
117 // shader program.
118 static const float kVertices[] = {
119 -1, -1, -1, 1, 1, -1, 1, 1, // Position coordinates.
120 0, 1, 0, 0, 1, 1, 1, 0, // Texture coordinates.
121 };
122
123 GLuint buffer;
124 gles2_if_->GenBuffers(graphics_3d, 1, &buffer);
125 gles2_if_->BindBuffer(graphics_3d, GL_ARRAY_BUFFER, buffer);
126 gles2_if_->BufferData(graphics_3d, GL_ARRAY_BUFFER, sizeof(kVertices),
127 kVertices, GL_STATIC_DRAW);
128
129 CheckGLError();
130
131 return true;
132 }
133
134 void PepperVideoRenderer3D::OnViewChanged(const pp::View& view) {
135 pp::Size size = view.GetRect().size();
136 float scale = view.GetDeviceScale();
137 view_width_ = ceilf(size.width() * scale);
138 view_height_ = ceilf(size.height() * scale);
139 graphics_.ResizeBuffers(view_width_, view_height_);
140
141 need_repaint_ = true;
142 DoPaint();
143 }
144
145 void PepperVideoRenderer3D::OnSessionConfig(
146 const protocol::SessionConfig& config) {
147 PP_VideoProfile video_profile = PP_VIDEOPROFILE_VP8_ANY;
148 switch (config.video_config().codec) {
149 case protocol::ChannelConfig::CODEC_VP8:
150 video_profile = PP_VIDEOPROFILE_VP8_ANY;
151 break;
152 case protocol::ChannelConfig::CODEC_VP9:
153 video_profile = PP_VIDEOPROFILE_VP9_ANY;
154 break;
155 default:
156 NOTREACHED();
Wez 2014/12/24 17:11:15 This means we're defaulting to VP8_ANY; consider t
Sergey Ulanov 2015/01/06 01:16:33 Protocol should not allow any codec other than VP8
157 }
158 int32_t result = video_decoder_.Initialize(
159 graphics_, video_profile, PP_HARDWAREACCELERATION_WITHFALLBACK,
160 callback_factory_.NewCallback(&PepperVideoRenderer3D::OnInitialized));
161 CHECK_EQ(result, PP_OK_COMPLETIONPENDING)
162 << "video_decoder_.Initialize() returned " << result;
Wez 2014/12/24 17:11:14 Strictly we should be coping with not-supported as
Sergey Ulanov 2015/01/06 01:16:32 We always expect PP_OK_COMPLETIONPENDING here beca
163 }
164
165 ChromotingStats* PepperVideoRenderer3D::GetStats() {
166 return &stats_;
167 }
168
169 void PepperVideoRenderer3D::ProcessVideoPacket(scoped_ptr<VideoPacket> packet,
170 const base::Closure& done) {
171 base::ScopedClosureRunner done_runner(done);
172
173 // Don't need to do anything if the packet is empty. Host sends empty video
174 // packets when the screen is not changing.
175 if (!packet->data().size())
176 return;
177
178 // Update statistics.
179 stats_.video_frame_rate()->Record(1);
180 stats_.video_bandwidth()->Record(packet->data().size());
181 if (packet->has_capture_time_ms())
182 stats_.video_capture_ms()->Record(packet->capture_time_ms());
183 if (packet->has_encode_time_ms())
184 stats_.video_encode_ms()->Record(packet->encode_time_ms());
185 if (packet->has_client_sequence_number() &&
186 packet->client_sequence_number() > latest_sequence_number_) {
187 latest_sequence_number_ = packet->client_sequence_number();
188 base::TimeDelta round_trip_latency =
189 base::Time::Now() -
190 base::Time::FromInternalValue(packet->client_sequence_number());
191 stats_.round_trip_ms()->Record(round_trip_latency.InMilliseconds());
192 }
193
194 webrtc::DesktopSize frame_size(packet->format().screen_width(),
195 packet->format().screen_height());
196 webrtc::DesktopVector frame_dpi(packet->format().x_dpi(),
197 packet->format().y_dpi());
198 if ((!frame_size.is_empty() && !frame_size_.equals(frame_size)) ||
Wez 2014/12/24 17:11:14 Feels like |frame_size.is_empty()| is a different
Sergey Ulanov 2015/01/06 01:16:32 Done.
199 !frame_dpi_.equals(frame_dpi)) {
200 frame_dpi_ = frame_dpi;
201 event_handler_->OnVideoSize(frame_size, frame_dpi);
202 }
203
204 // Update the desktop shape region.
205 webrtc::DesktopRegion desktop_shape;
206 if (packet->has_use_desktop_shape()) {
Wez 2014/12/24 17:11:14 nit: You also need to check that use_desktop_shape
Sergey Ulanov 2015/01/06 01:16:32 This code is equivalent to what we have in VideoDe
Wez 2015/01/06 22:17:10 Acknowledged.
207 for (int i = 0; i < packet->desktop_shape_rects_size(); ++i) {
208 Rect remoting_rect = packet->desktop_shape_rects(i);
209 desktop_shape.AddRect(webrtc::DesktopRect::MakeXYWH(
210 remoting_rect.x(), remoting_rect.y(),
211 remoting_rect.width(), remoting_rect.height()));
212 }
213 } else {
214 // Fallback for the case when the host didn't include the desktop shape.
215 desktop_shape =
216 webrtc::DesktopRegion(webrtc::DesktopRect::MakeSize(frame_size));
Wez 2014/12/24 17:11:15 nit: This means that unless the remote peer sends
Sergey Ulanov 2015/01/06 01:16:32 Exactly. It doesn't look right, but it's not relat
Wez 2015/01/06 22:17:10 Acknowledged.
217 }
218
219 if (!desktop_shape_.Equals(desktop_shape)) {
220 desktop_shape_.Swap(&desktop_shape);
221 event_handler_->OnVideoShape(desktop_shape_);
222 }
223
224 pending_packets_.push_back(
225 new PendingPacket(packet.Pass(), done_runner.Release()));
226 DoDecode();
227 }
228
229 void PepperVideoRenderer3D::OnInitialized(int32_t result) {
230 CHECK_EQ(result, PP_OK) << "VideoDecoder::Initialize() failed";
Wez 2014/12/24 17:11:14 Cope gracefully with initialization errors here?
Sergey Ulanov 2015/01/06 01:16:32 I think we can assume that we can always initializ
Wez 2015/01/06 22:17:10 Acknowledged.
231 initialized_ = true;
232 DoDecode();
Wez 2014/12/24 17:11:15 nit: Add a brief comment to clarify why we start t
Sergey Ulanov 2015/01/06 01:16:33 Done.
233 }
234
235 void PepperVideoRenderer3D::DoGetPicture() {
Wez 2014/12/24 17:11:14 Move this method down to appear immediately before
Sergey Ulanov 2015/01/06 01:16:31 Done.
236 if (get_picture_pending_)
237 return;
238
239 int32_t result =
240 video_decoder_.GetPicture(callback_factory_.NewCallbackWithOutput(
241 &PepperVideoRenderer3D::OnPictureReady));
242 CHECK_EQ(result, PP_OK_COMPLETIONPENDING);
Wez 2014/12/24 17:11:14 nit: Cope gracefully w/ errors here?
Sergey Ulanov 2015/01/06 01:16:31 We always expect PP_OK_COMPLETIONPENDING here beca
243 get_picture_pending_ = true;
244 }
245
246 void PepperVideoRenderer3D::DoDecode() {
247 if (!initialized_ || decode_pending_ || pending_packets_.empty())
248 return;
249
250 ++last_frame_id_;
251 frames_decode_timers_.push_back(
252 FrameDecodeTimer(last_frame_id_, base::TimeTicks::Now()));
Wez 2014/12/24 17:11:14 Since you can only ever have a single decode opera
Sergey Ulanov 2015/01/06 01:16:33 looks like this comment was cropped somehow.
253
254 const VideoPacket* packet = pending_packets_.front()->packet();
255
256 int32_t result = video_decoder_.Decode(
257 last_frame_id_, packet->data().size(), packet->data().data(),
Wez 2014/12/24 17:11:14 nit: The Decode() API unfortunately doesn't specif
Sergey Ulanov 2015/01/06 01:16:32 It does copy the data and it's documented: https:/
Wez 2015/01/06 22:17:09 If it copies the data then we don't need to keep t
Sergey Ulanov 2015/01/07 19:37:30 Ah, I see. Yes, it's not clear. I think it's bette
258 callback_factory_.NewCallback(&PepperVideoRenderer3D::OnDecodeDone));
259 CHECK_EQ(result, PP_OK_COMPLETIONPENDING);
Wez 2014/12/24 17:11:14 The docs on GetPicture imply that Decode() could r
Sergey Ulanov 2015/01/06 01:16:32 The callback is not optional, so we always expect
Wez 2015/01/06 22:17:10 Acknowledged.
260 decode_pending_ = true;
261 }
262
263 void PepperVideoRenderer3D::OnDecodeDone(int32_t result) {
264 decode_pending_ = false;
Wez 2014/12/24 17:11:14 nit: DCHECK(decode_pending_)?
Sergey Ulanov 2015/01/06 01:16:32 Done.
265
266 if (result != PP_OK) {
267 LOG(ERROR) << "VideoDecoder::Decode() returned " << result;
268 event_handler_->OnVideoDecoderFailed();
269 return;
270 }
271
272 delete pending_packets_.front();
273 pending_packets_.pop_front();
274
275 DoDecode();
276 DoGetPicture();
277 }
278
279 void PepperVideoRenderer3D::OnPictureReady(int32_t result,
280 PP_VideoPicture picture) {
281 get_picture_pending_ = false;
Wez 2014/12/24 17:11:14 nit: DCHECK(get_picture_pending_)
Sergey Ulanov 2015/01/06 01:16:32 Done.
282
283 if (result == PP_ERROR_ABORTED)
Wez 2014/12/24 17:11:15 What does PP_ERROR_ABORTED actually mean? Should w
Sergey Ulanov 2015/01/06 01:16:33 GetPicture() may be aborted when the pp::VideoDeco
Wez 2015/01/06 22:17:10 Acknowledged.
284 return;
285
286 if (result != PP_OK) {
287 LOG(ERROR) << "VideoDecoder::GetPicture() returned " << result;
288 event_handler_->OnVideoDecoderFailed();
289 return;
290 }
291
292 CHECK(!frames_decode_timers_.empty());
Wez 2014/12/24 17:11:15 Do you need this check? If it's violated then fron
Sergey Ulanov 2015/01/06 01:16:31 front() behavior is undefined when the list is emp
293 const FrameDecodeTimer& frame_timer = frames_decode_timers_.front();
294 DCHECK_EQ(picture.decode_id, frame_timer.frame_id);
Wez 2014/12/24 17:11:15 This check will fail if we receive a packet that d
Sergey Ulanov 2015/01/06 01:16:31 If picture.decode_id != frame_timer.frame_id it me
295 stats_.video_decode_ms()->Record(
296 (base::TimeTicks::Now() - frame_timer.decode_started_time)
Wez 2014/12/24 17:11:14 nit: Suggest calculating this into a const base::T
Sergey Ulanov 2015/01/06 01:16:33 Done.
297 .InMilliseconds());
298 frames_decode_timers_.pop_front();
299
300 // Recycle all pending pictures, but keep the first one if it's still being
301 // painted.
302 RecyclePictures(paint_pending_);
303 pending_pictures_.push_back(picture);
304 need_repaint_ = true;
305
306 DoPaint();
307 DoGetPicture();
308 }
309
310 void PepperVideoRenderer3D::RecyclePictures(bool keep_first) {
Wez 2014/12/24 17:11:15 It looks like this only keeps the first if |keep_f
Sergey Ulanov 2015/01/06 01:16:32 Removed this method.
311 std::vector<PP_VideoPicture>::iterator it = pending_pictures_.begin();
312 if (keep_first)
313 ++it;
Wez 2014/12/24 17:11:15 This is keeping the first, i.e. the _next_ picture
Sergey Ulanov 2015/01/06 01:16:31 Yes. The first picture is the one being rendered,
314
315 while (it != pending_pictures_.end()) {
316 video_decoder_.RecyclePicture(*it);
317 it = pending_pictures_.erase(it);
318 }
319 }
320
321 void PepperVideoRenderer3D::DoPaint() {
322 if (paint_pending_ || !need_repaint_ || pending_pictures_.empty())
Wez 2014/12/24 17:11:15 This logic means that if |need_repaint_| is false
Sergey Ulanov 2015/01/06 01:16:32 After the first frame is received pending_pictures
Wez 2015/01/06 22:17:10 Yes, although you could make it an explicit was_re
Sergey Ulanov 2015/01/07 19:37:30 Replaced need_repaint_ with force_repaint_
323 return;
324
325 need_repaint_ = false;
326 last_paint_started_time_ = base::TimeTicks::Now();
327
328 const PP_VideoPicture& picture = pending_pictures_.front();
329 PP_Resource graphics_3d = graphics_.pp_resource();
330
331 EnsureProgramForTexture(picture.texture_target);
332
333 gles2_if_->UseProgram(graphics_3d, shader_program_);
334 if (picture.texture_target == GL_TEXTURE_RECTANGLE_ARB) {
335 gles2_if_->Uniform2f(graphics_3d, shader_texcoord_scale_location_,
336 static_cast<GLfloat>(picture.texture_size.width),
337 static_cast<GLfloat>(picture.texture_size.height));
338 } else {
339 gles2_if_->Uniform2f(
340 graphics_3d, shader_texcoord_scale_location_, 1.0, 1.0);
341 }
342
343 // Set viewport position & dimensions.
344 gles2_if_->Viewport(graphics_3d, 0, 0, view_width_, view_height_);
345
346 // Select the texture unit GL_TEXTURE0.
347 gles2_if_->ActiveTexture(graphics_3d, GL_TEXTURE0);
348
349 // Select the texture.
350 gles2_if_->BindTexture(graphics_3d, picture.texture_target,
351 picture.texture_id);
352
353 // Select linear filter in case the texture needs to be scaled.
354 gles2_if_->TexParameteri(graphics_3d, picture.texture_target,
355 GL_TEXTURE_MIN_FILTER, GL_LINEAR);
356
357 // Render texture by drawing a triangle strip with 4 vertices.
358 gles2_if_->DrawArrays(graphics_3d, GL_TRIANGLE_STRIP, 0, 4);
359
360 CheckGLError();
361
362 // Request PPAPI display the queue texture.
Wez 2014/12/24 17:11:15 typo: queued
Sergey Ulanov 2015/01/06 01:16:33 Done.
363 int32_t result = graphics_.SwapBuffers(
364 callback_factory_.NewCallback(&PepperVideoRenderer3D::OnPaintDone));
365 CHECK_EQ(result, PP_OK_COMPLETIONPENDING);
366 paint_pending_ = true;
367 }
368
369 void PepperVideoRenderer3D::OnPaintDone(int32_t result) {
370 CHECK_EQ(result, PP_OK) << "Graphics3D::SwapBuffers() failed";
371
372 paint_pending_ = false;
373 stats_.video_paint_ms()->Record(
374 (base::TimeTicks::Now() - last_paint_started_time_).InMilliseconds());
Wez 2014/12/24 17:11:14 nit: See above; consider doing the subtraction int
Sergey Ulanov 2015/01/06 01:16:32 Done.
375
376 if (pending_pictures_.size() > 1) {
377 video_decoder_.RecyclePicture(pending_pictures_.front());
378 pending_pictures_.erase(pending_pictures_.begin());
379 need_repaint_ = true;
380 }
381
382 DoPaint();
383 }
384
385 void PepperVideoRenderer3D::EnsureProgramForTexture(uint32_t texture_target) {
386 static const char kVertexShader[] =
387 "varying vec2 v_texCoord; \n"
388 "attribute vec4 a_position; \n"
389 "attribute vec2 a_texCoord; \n"
390 "uniform vec2 v_scale; \n"
391 "void main() \n"
392 "{ \n"
393 " v_texCoord = v_scale * a_texCoord; \n"
394 " gl_Position = a_position; \n"
395 "}";
396
397 static const char kFragmentShader2D[] =
398 "precision mediump float; \n"
399 "varying vec2 v_texCoord; \n"
400 "uniform sampler2D s_texture; \n"
401 "void main() \n"
402 "{"
403 " gl_FragColor = texture2D(s_texture, v_texCoord); \n"
404 "}";
405
406 static const char kFragmentShaderRectangle[] =
407 "#extension GL_ARB_texture_rectangle : require\n"
408 "precision mediump float; \n"
409 "varying vec2 v_texCoord; \n"
410 "uniform sampler2DRect s_texture; \n"
411 "void main() \n"
412 "{"
413 " gl_FragColor = texture2DRect(s_texture, v_texCoord).rgba; \n"
414 "}";
415
416 static const char kFragmentShaderExternal[] =
417 "#extension GL_OES_EGL_image_external : require\n"
418 "precision mediump float; \n"
419 "varying vec2 v_texCoord; \n"
420 "uniform samplerExternalOES s_texture; \n"
421 "void main() \n"
422 "{"
423 " gl_FragColor = texture2D(s_texture, v_texCoord); \n"
424 "}";
425
426 // Initialize shader program only if texture type has changed.
427 if (current_shader_program_texture_target_ != texture_target) {
428 current_shader_program_texture_target_ = texture_target;
429
430 if (texture_target == GL_TEXTURE_2D) {
431 CreateProgram(kVertexShader, kFragmentShader2D);
432 } else if (texture_target == GL_TEXTURE_RECTANGLE_ARB) {
433 CreateProgram(kVertexShader, kFragmentShaderRectangle);
434 } else if (texture_target == GL_TEXTURE_EXTERNAL_OES) {
435 CreateProgram(kVertexShader, kFragmentShaderExternal);
436 } else {
437 CHECK(false);
Wez 2014/12/24 17:11:15 Suggest NOTREACHED() or LOG(FATAL)
Sergey Ulanov 2015/01/06 01:16:33 Done.
438 }
439 }
440 }
441
442 void PepperVideoRenderer3D::CreateProgram(const char* vertex_shader,
443 const char* fragment_shader) {
444 PP_Resource graphics_3d = graphics_.pp_resource();
445 if (shader_program_)
446 gles2_if_->DeleteProgram(graphics_3d, shader_program_);
447
448 // Create shader program.
449 shader_program_ = gles2_if_->CreateProgram(graphics_3d);
450 CreateShaderProgram(GL_VERTEX_SHADER, vertex_shader);
451 CreateShaderProgram(GL_FRAGMENT_SHADER, fragment_shader);
452 gles2_if_->LinkProgram(graphics_3d, shader_program_);
453 gles2_if_->UseProgram(graphics_3d, shader_program_);
454 gles2_if_->Uniform1i(
455 graphics_3d,
456 gles2_if_->GetUniformLocation(graphics_3d, shader_program_, "s_texture"),
457 0);
458 CheckGLError();
459
460 shader_texcoord_scale_location_ = gles2_if_->GetUniformLocation(
461 graphics_3d, shader_program_, "v_scale");
462
463 GLint pos_location = gles2_if_->GetAttribLocation(
464 graphics_3d, shader_program_, "a_position");
465 GLint tc_location = gles2_if_->GetAttribLocation(
466 graphics_3d, shader_program_, "a_texCoord");
467 CheckGLError();
468
469 // Construct the vertex array for DrawArrays(), using the buffer created in
470 // Initialize().
471 gles2_if_->EnableVertexAttribArray(graphics_3d, pos_location);
472 gles2_if_->VertexAttribPointer(graphics_3d, pos_location, 2, GL_FLOAT,
473 GL_FALSE, 0, 0);
474 gles2_if_->EnableVertexAttribArray(graphics_3d, tc_location);
475 gles2_if_->VertexAttribPointer(
476 graphics_3d, tc_location, 2, GL_FLOAT, GL_FALSE, 0,
477 static_cast<float*>(0) + 8); // Skip position coordinates.
478
479 gles2_if_->UseProgram(graphics_3d, 0);
480
481 CheckGLError();
482 }
483
484 void PepperVideoRenderer3D::CreateShaderProgram(int type, const char* source) {
485 int size = strlen(source);
486 GLuint shader = gles2_if_->CreateShader(graphics_.pp_resource(), type);
487 gles2_if_->ShaderSource(graphics_.pp_resource(), shader, 1, &source, &size);
488 gles2_if_->CompileShader(graphics_.pp_resource(), shader);
489 gles2_if_->AttachShader(graphics_.pp_resource(), shader_program_, shader);
490 gles2_if_->DeleteShader(graphics_.pp_resource(), shader);
491 }
Wez 2014/12/24 17:11:15 nit: Blank line
Sergey Ulanov 2015/01/06 01:16:32 Done.
492 void PepperVideoRenderer3D::CheckGLError() {
493 GLenum error = gles2_if_->GetError(graphics_.pp_resource());
494 CHECK_EQ(error, static_cast<GLenum>(GL_NO_ERROR)) << "GL error: " << error;
495 }
496
497 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698