OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 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 <stdio.h> | |
6 #include <string.h> | |
7 | |
8 #include <iostream> | |
9 #include <queue> | |
10 #include <sstream> | |
11 | |
12 #include "ppapi/c/pp_errors.h" | |
13 #include "ppapi/c/ppb_console.h" | |
14 #include "ppapi/c/ppb_opengles2.h" | |
15 #include "ppapi/cpp/graphics_3d.h" | |
16 #include "ppapi/cpp/graphics_3d_client.h" | |
17 #include "ppapi/cpp/input_event.h" | |
18 #include "ppapi/cpp/instance.h" | |
19 #include "ppapi/cpp/module.h" | |
20 #include "ppapi/cpp/rect.h" | |
21 #include "ppapi/cpp/var.h" | |
22 #include "ppapi/cpp/video_decoder.h" | |
23 #include "ppapi/examples/video_decode/testdata.h" | |
24 #include "ppapi/lib/gl/include/GLES2/gl2.h" | |
25 #include "ppapi/lib/gl/include/GLES2/gl2ext.h" | |
26 #include "ppapi/utility/completion_callback_factory.h" | |
27 | |
28 // Use assert as a poor-man's CHECK, even in non-debug mode. | |
29 // Since <assert.h> redefines assert on every inclusion (it doesn't use | |
30 // include-guards), make sure this is the last file #include'd in this file. | |
31 #undef NDEBUG | |
32 #include <assert.h> | |
33 | |
34 // Assert |context_| isn't holding any GL Errors. Done as a macro instead of a | |
35 // function to preserve line number information in the failure message. | |
36 #define assertNoGLError() assert(!gles2_if_->GetError(context_->pp_resource())); | |
37 | |
38 namespace { | |
39 | |
40 struct Shader { | |
41 Shader() : program(0), texcoord_scale_location(0) {} | |
42 ~Shader() {} | |
43 | |
44 GLuint program; | |
45 GLint texcoord_scale_location; | |
46 }; | |
47 | |
48 class Decoder; | |
49 class MyInstance; | |
50 | |
51 class MyInstance : public pp::Instance, public pp::Graphics3DClient { | |
52 public: | |
53 MyInstance(PP_Instance instance, pp::Module* module); | |
54 virtual ~MyInstance(); | |
55 | |
56 // pp::Instance implementation. | |
57 virtual void DidChangeView(const pp::Rect& position, | |
58 const pp::Rect& clip_ignored); | |
59 | |
60 // pp::Graphics3DClient implementation. | |
61 virtual void Graphics3DContextLost() { | |
62 // TODO(vrk/fischman): Properly reset after a lost graphics context. In | |
63 // particular need to delete context_ and re-create textures. | |
64 // Probably have to recreate the decoder from scratch, because old textures | |
65 // can still be outstanding in the decoder! | |
66 assert(false && "Unexpectedly lost graphics context"); | |
67 } | |
68 | |
69 void PaintPicture(Decoder* decoder, const PP_VideoPicture& picture); | |
70 | |
71 private: | |
72 // Log an error to the developer console and stderr by creating a temporary | |
73 // object of this type and streaming to it. Example usage: | |
74 // LogError(this).s() << "Hello world: " << 42; | |
75 class LogError { | |
76 public: | |
77 LogError(MyInstance* instance) : instance_(instance) {} | |
78 ~LogError() { | |
79 const std::string& msg = stream_.str(); | |
80 instance_->console_if_->Log( | |
81 instance_->pp_instance(), PP_LOGLEVEL_ERROR, pp::Var(msg).pp_var()); | |
82 std::cerr << msg << std::endl; | |
83 } | |
84 // Impl note: it would have been nicer to have LogError derive from | |
85 // std::ostringstream so that it can be streamed to directly, but lookup | |
86 // rules turn streamed string literals to hex pointers on output. | |
87 std::ostringstream& s() { return stream_; } | |
88 | |
89 private: | |
90 MyInstance* instance_; | |
91 std::ostringstream stream_; | |
92 }; | |
93 | |
94 void InitializeDecoders(); | |
95 | |
96 // GL-related functions. | |
97 void InitGL(); | |
98 void CreateGLObjects(); | |
99 void Create2DProgramOnce(); | |
100 void CreateRectangleARBProgramOnce(); | |
101 Shader CreateProgram(const char* vertex_shader, const char* fragment_shader); | |
102 void CreateShader(GLuint program, GLenum type, const char* source, int size); | |
103 void PaintFinished(int32_t result, Decoder* decoder, PP_VideoPicture picture); | |
104 | |
105 pp::Size plugin_size_; | |
106 bool is_painting_; | |
107 // When decode outpaces render, we queue up decoded pictures for later | |
108 // painting. Elements are <decoder,picture>. | |
109 typedef std::queue<std::pair<Decoder*, PP_VideoPicture> > PictureQueue; | |
110 PictureQueue pictures_pending_paint_; | |
111 | |
112 int num_frames_rendered_; | |
113 PP_TimeTicks first_frame_delivered_ticks_; | |
114 PP_TimeTicks last_swap_request_ticks_; | |
115 PP_TimeTicks swap_ticks_; | |
116 pp::CompletionCallbackFactory<MyInstance> callback_factory_; | |
117 | |
118 // Unowned pointers. | |
119 const PPB_Console* console_if_; | |
120 const PPB_Core* core_if_; | |
121 const PPB_OpenGLES2* gles2_if_; | |
122 | |
123 // Owned data. | |
124 pp::Graphics3D* context_; | |
125 typedef std::vector<Decoder*> DecoderList; | |
126 DecoderList video_decoders_; | |
127 | |
128 // Shader program to draw GL_TEXTURE_2D target. | |
129 Shader shader_2d_; | |
130 // Shader program to draw GL_TEXTURE_RECTANGLE_ARB target. | |
131 Shader shader_rectangle_arb_; | |
132 }; | |
133 | |
134 class Decoder { | |
135 public: | |
136 Decoder(MyInstance* instance, int id, const pp::Graphics3D& graphics_3d); | |
137 ~Decoder(); | |
138 | |
139 int id() const { return id_; } | |
140 bool decoding() const { return !flushing_ && !resetting_; } | |
141 | |
142 void Seek(int frame); | |
143 void RecyclePicture(const PP_VideoPicture& picture); | |
144 | |
145 private: | |
146 void InitializeDone(int32_t result); | |
147 void Start(int frame); | |
148 void DecodeNextFrame(); | |
149 void DecodeDone(int32_t result); | |
150 void PictureReady(int32_t result, PP_VideoPicture picture); | |
151 void FlushDone(int32_t result); | |
152 void ResetDone(int32_t result); | |
153 | |
154 MyInstance* instance_; | |
155 int id_; | |
156 | |
157 pp::VideoDecoder* decoder_; | |
158 pp::CompletionCallbackFactory<Decoder> callback_factory_; | |
159 | |
160 size_t encoded_data_next_pos_to_decode_; | |
161 int next_picture_id_; | |
162 int seek_frame_; | |
163 bool flushing_; | |
164 bool resetting_; | |
165 }; | |
166 | |
167 // Returns true if the current position is at the start of a NAL unit. | |
168 static bool LookingAtNAL(const unsigned char* encoded, size_t pos) { | |
169 // H264 frames start with 0, 0, 0, 1 in our test data. | |
170 return pos + 3 < kDataLen && encoded[pos] == 0 && encoded[pos + 1] == 0 && | |
171 encoded[pos + 2] == 0 && encoded[pos + 3] == 1; | |
172 } | |
173 | |
174 // Find the start and end of the next frame. | |
175 static void GetNextFrame(size_t* start_pos, size_t* end_pos) { | |
176 assert(LookingAtNAL(kData, *start_pos)); | |
177 *end_pos = *start_pos; | |
178 *end_pos += 4; | |
179 while (*end_pos < kDataLen && !LookingAtNAL(kData, *end_pos)) { | |
180 ++*end_pos; | |
181 } | |
182 } | |
183 | |
184 Decoder::Decoder(MyInstance* instance, | |
185 int id, | |
186 const pp::Graphics3D& graphics_3d) | |
187 : instance_(instance), | |
188 id_(id), | |
189 decoder_(new pp::VideoDecoder(instance)), | |
190 callback_factory_(this), | |
191 encoded_data_next_pos_to_decode_(0), | |
192 next_picture_id_(0), | |
193 seek_frame_(0), | |
194 flushing_(false), | |
195 resetting_(false) { | |
196 assert(!decoder_->is_null()); | |
197 const PP_VideoProfile profile = PP_VIDEOPROFILE_H264MAIN; | |
198 decoder_->Initialize(graphics_3d, | |
199 profile, | |
200 PP_FALSE /* allow_software_fallback */, | |
201 callback_factory_.NewCallback(&Decoder::InitializeDone)); | |
202 } | |
203 | |
204 Decoder::~Decoder() { | |
205 delete decoder_; | |
206 } | |
207 | |
208 void Decoder::InitializeDone(int32_t result) { | |
209 assert(decoder_); | |
210 assert(result == PP_OK); | |
211 assert(decoding()); | |
212 Start(0); | |
213 } | |
214 | |
215 void Decoder::Start(int frame) { | |
216 assert(decoder_); | |
217 | |
218 // Skip to |frame|. | |
219 size_t start_pos = 0; | |
220 size_t end_pos = 0; | |
221 for (int i = 0; i < frame; i++) | |
222 GetNextFrame(&start_pos, &end_pos); | |
223 encoded_data_next_pos_to_decode_ = end_pos; | |
224 | |
225 // Register callback to get the first picture. We call GetPicture again in | |
226 // PictureReady to continuously receive pictures as they're decoded. | |
227 decoder_->GetPicture( | |
228 callback_factory_.NewCallbackWithOutput(&Decoder::PictureReady)); | |
229 | |
230 // Start the decode loop. | |
231 DecodeNextFrame(); | |
232 } | |
233 | |
234 void Decoder::Seek(int frame) { | |
235 assert(decoder_); | |
236 seek_frame_ = frame; | |
237 resetting_ = true; | |
238 decoder_->Reset(callback_factory_.NewCallback(&Decoder::ResetDone)); | |
239 } | |
240 | |
241 void Decoder::RecyclePicture(const PP_VideoPicture& picture) { | |
242 assert(decoder_); | |
243 decoder_->RecyclePicture(picture); | |
244 } | |
245 | |
246 void Decoder::DecodeNextFrame() { | |
247 assert(decoder_); | |
248 if (encoded_data_next_pos_to_decode_ <= kDataLen) { | |
249 // If we've just reached the end of the bitstream, flush and wait. | |
250 if (!flushing_ && encoded_data_next_pos_to_decode_ == kDataLen) { | |
251 flushing_ = true; | |
252 decoder_->Flush(callback_factory_.NewCallback(&Decoder::FlushDone)); | |
253 return; | |
254 } | |
255 | |
256 // Find the start of the next frame. | |
257 size_t start_pos = encoded_data_next_pos_to_decode_; | |
258 size_t end_pos; | |
259 GetNextFrame(&start_pos, &end_pos); | |
260 encoded_data_next_pos_to_decode_ = end_pos; | |
261 // Decode the frame. On completion, DecodeDone will call DecodeNextFrame | |
262 // to implement a decode loop. | |
263 uint32_t size = static_cast<uint32_t>(end_pos - start_pos); | |
264 decoder_->Decode(next_picture_id_++, | |
265 size, | |
266 kData + start_pos, | |
267 callback_factory_.NewCallback(&Decoder::DecodeDone)); | |
268 } | |
269 } | |
270 | |
271 void Decoder::DecodeDone(int32_t result) { | |
272 assert(decoder_); | |
273 // Break out of the decode loop on abort. | |
274 if (result == PP_ERROR_ABORTED) | |
275 return; | |
276 assert(result == PP_OK); | |
277 if (decoding()) | |
278 DecodeNextFrame(); | |
279 } | |
280 | |
281 void Decoder::PictureReady(int32_t result, PP_VideoPicture picture) { | |
282 assert(decoder_); | |
283 // Break out of the get picture loop on abort. | |
284 if (result == PP_ERROR_ABORTED) | |
285 return; | |
286 assert(result == PP_OK); | |
287 decoder_->GetPicture( | |
288 callback_factory_.NewCallbackWithOutput(&Decoder::PictureReady)); | |
289 instance_->PaintPicture(this, picture); | |
290 } | |
291 | |
292 void Decoder::FlushDone(int32_t result) { | |
293 assert(decoder_); | |
294 assert(result == PP_OK || result == PP_ERROR_ABORTED); | |
295 flushing_ = false; | |
296 } | |
297 | |
298 void Decoder::ResetDone(int32_t result) { | |
299 assert(decoder_); | |
300 assert(result == PP_OK); | |
301 resetting_ = false; | |
302 } | |
303 | |
304 MyInstance::MyInstance(PP_Instance instance, pp::Module* module) | |
305 : pp::Instance(instance), | |
306 pp::Graphics3DClient(this), | |
307 is_painting_(false), | |
308 num_frames_rendered_(0), | |
309 first_frame_delivered_ticks_(-1), | |
310 last_swap_request_ticks_(-1), | |
311 swap_ticks_(0), | |
312 callback_factory_(this), | |
313 context_(NULL) { | |
314 assert((console_if_ = static_cast<const PPB_Console*>( | |
315 module->GetBrowserInterface(PPB_CONSOLE_INTERFACE)))); | |
316 assert((core_if_ = static_cast<const PPB_Core*>( | |
317 module->GetBrowserInterface(PPB_CORE_INTERFACE)))); | |
318 assert((gles2_if_ = static_cast<const PPB_OpenGLES2*>( | |
319 module->GetBrowserInterface(PPB_OPENGLES2_INTERFACE)))); | |
320 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE); | |
Ami GONE FROM CHROMIUM
2014/05/29 02:31:36
I agree Seek() would be valuable coverage.
You can
bbudge
2014/06/03 18:41:24
Looking at the test file, there is apparently only
| |
321 } | |
322 | |
323 MyInstance::~MyInstance() { | |
324 if (!context_) | |
325 return; | |
326 | |
327 PP_Resource graphics_3d = context_->pp_resource(); | |
328 if (shader_2d_.program) | |
329 gles2_if_->DeleteProgram(graphics_3d, shader_2d_.program); | |
330 if (shader_rectangle_arb_.program) | |
331 gles2_if_->DeleteProgram(graphics_3d, shader_rectangle_arb_.program); | |
332 | |
333 for (DecoderList::iterator it = video_decoders_.begin(); | |
334 it != video_decoders_.end(); | |
335 ++it) | |
336 delete *it; | |
337 | |
338 delete context_; | |
339 } | |
340 | |
341 void MyInstance::DidChangeView(const pp::Rect& position, | |
342 const pp::Rect& clip_ignored) { | |
343 if (position.width() == 0 || position.height() == 0) | |
344 return; | |
345 if (plugin_size_.width()) { | |
346 assert(position.size() == plugin_size_); | |
347 return; | |
348 } | |
349 plugin_size_ = position.size(); | |
350 | |
351 // Initialize graphics. | |
352 InitGL(); | |
353 InitializeDecoders(); | |
354 } | |
355 | |
356 void MyInstance::InitializeDecoders() { | |
357 assert(video_decoders_.empty()); | |
358 // Create two decoders with ids 0 and 1. | |
359 video_decoders_.push_back(new Decoder(this, 0, *context_)); | |
360 video_decoders_.push_back(new Decoder(this, 1, *context_)); | |
361 } | |
362 | |
363 void MyInstance::PaintPicture(Decoder* decoder, | |
364 const PP_VideoPicture& picture) { | |
365 if (first_frame_delivered_ticks_ == -1) | |
366 assert((first_frame_delivered_ticks_ = core_if_->GetTimeTicks()) != -1); | |
367 if (is_painting_) { | |
368 pictures_pending_paint_.push(std::make_pair(decoder, picture)); | |
369 return; | |
370 } | |
371 | |
372 assert(!is_painting_); | |
373 is_painting_ = true; | |
374 int x = 0; | |
375 int y = 0; | |
376 int half_width = plugin_size_.width() / 2; | |
377 int half_height = plugin_size_.height() / 2; | |
378 if (decoder->id() != 0) { | |
379 x = half_width; | |
380 y = half_height; | |
381 } | |
382 | |
383 PP_Resource graphics_3d = context_->pp_resource(); | |
384 if (picture.texture_target == GL_TEXTURE_2D) { | |
385 Create2DProgramOnce(); | |
386 gles2_if_->UseProgram(graphics_3d, shader_2d_.program); | |
387 gles2_if_->Uniform2f( | |
388 graphics_3d, shader_2d_.texcoord_scale_location, 1.0, 1.0); | |
389 } else { | |
390 assert(picture.texture_target == GL_TEXTURE_RECTANGLE_ARB); | |
391 CreateRectangleARBProgramOnce(); | |
392 gles2_if_->UseProgram(graphics_3d, shader_rectangle_arb_.program); | |
393 gles2_if_->Uniform2f(graphics_3d, | |
394 shader_rectangle_arb_.texcoord_scale_location, | |
395 picture.texture_size.width, | |
396 picture.texture_size.height); | |
397 } | |
398 | |
399 gles2_if_->Viewport(graphics_3d, x, y, half_width, half_height); | |
400 gles2_if_->ActiveTexture(graphics_3d, GL_TEXTURE0); | |
401 gles2_if_->BindTexture( | |
402 graphics_3d, picture.texture_target, picture.texture_id); | |
403 gles2_if_->DrawArrays(graphics_3d, GL_TRIANGLE_STRIP, 0, 4); | |
404 | |
405 gles2_if_->UseProgram(graphics_3d, 0); | |
406 | |
407 last_swap_request_ticks_ = core_if_->GetTimeTicks(); | |
408 assert(PP_OK_COMPLETIONPENDING == | |
409 context_->SwapBuffers(callback_factory_.NewCallback( | |
410 &MyInstance::PaintFinished, decoder, picture))); | |
411 } | |
412 | |
413 void MyInstance::PaintFinished(int32_t result, | |
414 Decoder* decoder, | |
415 PP_VideoPicture picture) { | |
416 assert(result == PP_OK); | |
417 swap_ticks_ += core_if_->GetTimeTicks() - last_swap_request_ticks_; | |
418 is_painting_ = false; | |
419 ++num_frames_rendered_; | |
420 if (num_frames_rendered_ % 50 == 0) { | |
421 double elapsed = core_if_->GetTimeTicks() - first_frame_delivered_ticks_; | |
422 double fps = (elapsed > 0) ? num_frames_rendered_ / elapsed : 1000; | |
423 double ms_per_swap = (swap_ticks_ * 1e3) / num_frames_rendered_; | |
424 LogError(this).s() << "Rendered frames: " << num_frames_rendered_ | |
425 << ", fps: " << fps | |
426 << ", with average ms/swap of: " << ms_per_swap; | |
427 } | |
428 decoder->RecyclePicture(picture); | |
429 // Keep painting as long as we have pictures. | |
430 if (!pictures_pending_paint_.empty()) { | |
431 std::pair<Decoder*, PP_VideoPicture> pending = | |
432 pictures_pending_paint_.front(); | |
433 pictures_pending_paint_.pop(); | |
434 PaintPicture(pending.first, pending.second); | |
435 } | |
436 } | |
437 | |
438 void MyInstance::InitGL() { | |
439 assert(plugin_size_.width() && plugin_size_.height()); | |
440 is_painting_ = false; | |
441 | |
442 assert(!context_); | |
443 int32_t context_attributes[] = { | |
444 PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8, | |
445 PP_GRAPHICS3DATTRIB_BLUE_SIZE, 8, | |
446 PP_GRAPHICS3DATTRIB_GREEN_SIZE, 8, | |
447 PP_GRAPHICS3DATTRIB_RED_SIZE, 8, | |
448 PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 0, | |
449 PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 0, | |
450 PP_GRAPHICS3DATTRIB_SAMPLES, 0, | |
451 PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0, | |
452 PP_GRAPHICS3DATTRIB_WIDTH, plugin_size_.width(), | |
453 PP_GRAPHICS3DATTRIB_HEIGHT, plugin_size_.height(), | |
454 PP_GRAPHICS3DATTRIB_NONE, | |
455 }; | |
456 context_ = new pp::Graphics3D(this, context_attributes); | |
457 assert(!context_->is_null()); | |
458 assert(BindGraphics(*context_)); | |
459 | |
460 // Clear color bit. | |
461 gles2_if_->ClearColor(context_->pp_resource(), 1, 0, 0, 1); | |
462 gles2_if_->Clear(context_->pp_resource(), GL_COLOR_BUFFER_BIT); | |
463 | |
464 assertNoGLError(); | |
465 | |
466 CreateGLObjects(); | |
467 } | |
468 | |
469 void MyInstance::CreateGLObjects() { | |
470 // Assign vertex positions and texture coordinates to buffers for use in | |
471 // shader program. | |
472 static const float kVertices[] = { | |
473 -1, 1, -1, -1, 1, 1, 1, -1, // Position coordinates. | |
474 0, 1, 0, 0, 1, 1, 1, 0, // Texture coordinates. | |
475 }; | |
476 | |
477 GLuint buffer; | |
478 gles2_if_->GenBuffers(context_->pp_resource(), 1, &buffer); | |
479 gles2_if_->BindBuffer(context_->pp_resource(), GL_ARRAY_BUFFER, buffer); | |
480 | |
481 gles2_if_->BufferData(context_->pp_resource(), | |
482 GL_ARRAY_BUFFER, | |
483 sizeof(kVertices), | |
484 kVertices, | |
485 GL_STATIC_DRAW); | |
486 assertNoGLError(); | |
487 } | |
488 | |
489 static const char kVertexShader[] = | |
490 "varying vec2 v_texCoord; \n" | |
491 "attribute vec4 a_position; \n" | |
492 "attribute vec2 a_texCoord; \n" | |
493 "uniform vec2 v_scale; \n" | |
494 "void main() \n" | |
495 "{ \n" | |
496 " v_texCoord = v_scale * a_texCoord; \n" | |
497 " gl_Position = a_position; \n" | |
498 "}"; | |
499 | |
500 void MyInstance::Create2DProgramOnce() { | |
501 if (shader_2d_.program) | |
502 return; | |
503 static const char kFragmentShader2D[] = | |
504 "precision mediump float; \n" | |
505 "varying vec2 v_texCoord; \n" | |
506 "uniform sampler2D s_texture; \n" | |
507 "void main() \n" | |
508 "{" | |
509 " gl_FragColor = texture2D(s_texture, v_texCoord); \n" | |
510 "}"; | |
511 shader_2d_ = CreateProgram(kVertexShader, kFragmentShader2D); | |
512 assertNoGLError(); | |
513 } | |
514 | |
515 void MyInstance::CreateRectangleARBProgramOnce() { | |
516 if (shader_rectangle_arb_.program) | |
517 return; | |
518 static const char kFragmentShaderRectangle[] = | |
519 "#extension GL_ARB_texture_rectangle : require\n" | |
520 "precision mediump float; \n" | |
521 "varying vec2 v_texCoord; \n" | |
522 "uniform sampler2DRect s_texture; \n" | |
523 "void main() \n" | |
524 "{" | |
525 " gl_FragColor = texture2DRect(s_texture, v_texCoord).rgba; \n" | |
526 "}"; | |
527 shader_rectangle_arb_ = | |
528 CreateProgram(kVertexShader, kFragmentShaderRectangle); | |
529 } | |
530 | |
531 Shader MyInstance::CreateProgram(const char* vertex_shader, | |
532 const char* fragment_shader) { | |
533 Shader shader; | |
534 | |
535 // Create shader program. | |
536 shader.program = gles2_if_->CreateProgram(context_->pp_resource()); | |
537 CreateShader( | |
538 shader.program, GL_VERTEX_SHADER, vertex_shader, strlen(vertex_shader)); | |
539 CreateShader(shader.program, | |
540 GL_FRAGMENT_SHADER, | |
541 fragment_shader, | |
542 strlen(fragment_shader)); | |
543 gles2_if_->LinkProgram(context_->pp_resource(), shader.program); | |
544 gles2_if_->UseProgram(context_->pp_resource(), shader.program); | |
545 gles2_if_->Uniform1i( | |
546 context_->pp_resource(), | |
547 gles2_if_->GetUniformLocation( | |
548 context_->pp_resource(), shader.program, "s_texture"), | |
549 0); | |
550 assertNoGLError(); | |
551 | |
552 shader.texcoord_scale_location = gles2_if_->GetUniformLocation( | |
553 context_->pp_resource(), shader.program, "v_scale"); | |
554 | |
555 GLint pos_location = gles2_if_->GetAttribLocation( | |
556 context_->pp_resource(), shader.program, "a_position"); | |
557 GLint tc_location = gles2_if_->GetAttribLocation( | |
558 context_->pp_resource(), shader.program, "a_texCoord"); | |
559 assertNoGLError(); | |
560 | |
561 gles2_if_->EnableVertexAttribArray(context_->pp_resource(), pos_location); | |
562 gles2_if_->VertexAttribPointer( | |
563 context_->pp_resource(), pos_location, 2, GL_FLOAT, GL_FALSE, 0, 0); | |
564 gles2_if_->EnableVertexAttribArray(context_->pp_resource(), tc_location); | |
565 gles2_if_->VertexAttribPointer( | |
566 context_->pp_resource(), | |
567 tc_location, | |
568 2, | |
569 GL_FLOAT, | |
570 GL_FALSE, | |
571 0, | |
572 static_cast<float*>(0) + 8); // Skip position coordinates. | |
573 | |
574 gles2_if_->UseProgram(context_->pp_resource(), 0); | |
575 assertNoGLError(); | |
576 return shader; | |
577 } | |
578 | |
579 void MyInstance::CreateShader(GLuint program, | |
580 GLenum type, | |
581 const char* source, | |
582 int size) { | |
583 GLuint shader = gles2_if_->CreateShader(context_->pp_resource(), type); | |
584 gles2_if_->ShaderSource(context_->pp_resource(), shader, 1, &source, &size); | |
585 gles2_if_->CompileShader(context_->pp_resource(), shader); | |
586 gles2_if_->AttachShader(context_->pp_resource(), program, shader); | |
587 gles2_if_->DeleteShader(context_->pp_resource(), shader); | |
588 } | |
589 | |
590 // This object is the global object representing this plugin library as long | |
591 // as it is loaded. | |
592 class MyModule : public pp::Module { | |
593 public: | |
594 MyModule() : pp::Module() {} | |
595 virtual ~MyModule() {} | |
596 | |
597 virtual pp::Instance* CreateInstance(PP_Instance instance) { | |
598 return new MyInstance(instance, this); | |
599 } | |
600 }; | |
601 | |
602 } // anonymous namespace | |
603 | |
604 namespace pp { | |
605 // Factory function for your specialization of the Module object. | |
606 Module* CreateModule() { | |
607 return new MyModule(); | |
608 } | |
609 } // namespace pp | |
OLD | NEW |