1 // Copyright (c) 2012 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.
14 #include "ppapi/c/pp_errors.h"
15 #include "ppapi/c/ppb_console.h"
16 #include "ppapi/c/ppb_opengles2.h"
17 #include "ppapi/cpp/dev/video_decoder_client_dev.h"
18 #include "ppapi/cpp/dev/video_decoder_dev.h"
19 #include "ppapi/cpp/graphics_3d.h"
20 #include "ppapi/cpp/graphics_3d_client.h"
21 #include "ppapi/cpp/instance.h"
22 #include "ppapi/cpp/module.h"
23 #include "ppapi/cpp/rect.h"
24 #include "ppapi/cpp/var.h"
25 #include "ppapi/examples/video_decode/testdata.h"
26 #include "ppapi/lib/gl/include/GLES2/gl2.h"
27 #include "ppapi/lib/gl/include/GLES2/gl2ext.h"
28 #include "ppapi/utility/completion_callback_factory.h"
30 // Use assert as a poor-man's CHECK, even in non-debug mode.
31 // Since <assert.h> redefines assert on every inclusion (it doesn't use
32 // include-guards), make sure this is the last file #include'd in this file.
36 // Assert |context_| isn't holding any GL Errors. Done as a macro instead of a
37 // function to preserve line number information in the failure message.
38 #define assertNoGLError() \
39 assert(!gles2_if_->GetError(context_->pp_resource()));
43 struct PictureBufferInfo
{
44 PP_PictureBuffer_Dev buffer
;
45 GLenum texture_target
;
49 Shader() : program(0),
50 texcoord_scale_location(0) {}
53 GLint texcoord_scale_location
;
56 class VideoDecodeDemoInstance
: public pp::Instance
,
57 public pp::Graphics3DClient
,
58 public pp::VideoDecoderClient_Dev
{
60 VideoDecodeDemoInstance(PP_Instance instance
, pp::Module
* module
);
61 virtual ~VideoDecodeDemoInstance();
63 // pp::Instance implementation (see PPP_Instance).
64 virtual void DidChangeView(const pp::Rect
& position
,
65 const pp::Rect
& clip_ignored
);
67 // pp::Graphics3DClient implementation.
68 virtual void Graphics3DContextLost() {
69 // TODO(vrk/fischman): Properly reset after a lost graphics context. In
70 // particular need to delete context_ and re-create textures.
71 // Probably have to recreate the decoder from scratch, because old textures
72 // can still be outstanding in the decoder!
73 assert(false && "Unexpectedly lost graphics context");
76 // pp::VideoDecoderClient_Dev implementation.
77 virtual void ProvidePictureBuffers(
79 uint32_t req_num_of_bufs
,
80 const PP_Size
& dimensions
,
81 uint32_t texture_target
);
82 virtual void DismissPictureBuffer(PP_Resource decoder
,
83 int32_t picture_buffer_id
);
84 virtual void PictureReady(PP_Resource decoder
, const PP_Picture_Dev
& picture
);
85 virtual void NotifyError(PP_Resource decoder
, PP_VideoDecodeError_Dev error
);
88 enum { kNumConcurrentDecodes
= 7,
89 kNumDecoders
= 2 }; // Baked into viewport rendering.
91 // A single decoder's client interface.
94 DecoderClient(VideoDecodeDemoInstance
* gles2
,
95 pp::VideoDecoder_Dev
* decoder
);
98 void DecodeNextNALUs();
100 // Per-decoder implementation of part of pp::VideoDecoderClient_Dev.
101 void ProvidePictureBuffers(
102 uint32_t req_num_of_bufs
,
104 uint32_t texture_target
);
105 void DismissPictureBuffer(int32_t picture_buffer_id
);
107 const PictureBufferInfo
& GetPictureBufferInfoById(int id
);
108 pp::VideoDecoder_Dev
* decoder() { return decoder_
; }
111 void DecodeNextNALU();
112 static void GetNextNALUBoundary(size_t start_pos
, size_t* end_pos
);
113 void DecoderBitstreamDone(int32_t result
, int bitstream_buffer_id
);
114 void DecoderFlushDone(int32_t result
);
116 VideoDecodeDemoInstance
* gles2_
;
117 pp::VideoDecoder_Dev
* decoder_
;
118 pp::CompletionCallbackFactory
<DecoderClient
> callback_factory_
;
119 int next_picture_buffer_id_
;
120 int next_bitstream_buffer_id_
;
121 size_t encoded_data_next_pos_to_decode_
;
122 std::set
<int> bitstream_ids_at_decoder_
;
123 // Map of texture buffers indexed by buffer id.
124 typedef std::map
<int, PictureBufferInfo
> PictureBufferMap
;
125 PictureBufferMap picture_buffers_by_id_
;
126 // Map of bitstream buffers indexed by id.
127 typedef std::map
<int, pp::Buffer_Dev
*> BitstreamBufferMap
;
128 BitstreamBufferMap bitstream_buffers_by_id_
;
131 // Initialize Video Decoders.
132 void InitializeDecoders();
134 // GL-related functions.
136 GLuint
CreateTexture(int32_t width
, int32_t height
, GLenum texture_target
);
137 void CreateGLObjects();
138 void Create2DProgramOnce();
139 void CreateRectangleARBProgramOnce();
140 Shader
CreateProgram(const char* vertex_shader
,
141 const char* fragment_shader
);
142 void CreateShader(GLuint program
, GLenum type
, const char* source
, int size
);
143 void DeleteTexture(GLuint id
);
144 void PaintFinished(int32_t result
, PP_Resource decoder
,
145 int picture_buffer_id
);
147 // Log an error to the developer console and stderr (though the latter may be
148 // closed due to sandboxing or blackholed for other reasons) by creating a
149 // temporary of this type and streaming to it. Example usage:
150 // LogError(this).s() << "Hello world: " << 42;
153 LogError(VideoDecodeDemoInstance
* demo
) : demo_(demo
) {}
155 const std::string
& msg
= stream_
.str();
156 demo_
->console_if_
->Log(demo_
->pp_instance(), PP_LOGLEVEL_ERROR
,
157 pp::Var(msg
).pp_var());
158 std::cerr
<< msg
<< std::endl
;
160 // Impl note: it would have been nicer to have LogError derive from
161 // std::ostringstream so that it can be streamed to directly, but lookup
162 // rules turn streamed string literals to hex pointers on output.
163 std::ostringstream
& s() { return stream_
; }
165 VideoDecodeDemoInstance
* demo_
; // Unowned.
166 std::ostringstream stream_
;
169 pp::Size plugin_size_
;
171 // When decode outpaces render, we queue up decoded pictures for later
172 // painting. Elements are <decoder,picture>.
173 std::list
<std::pair
<PP_Resource
, PP_Picture_Dev
> > pictures_pending_paint_
;
174 int num_frames_rendered_
;
175 PP_TimeTicks first_frame_delivered_ticks_
;
176 PP_TimeTicks last_swap_request_ticks_
;
177 PP_TimeTicks swap_ticks_
;
178 pp::CompletionCallbackFactory
<VideoDecodeDemoInstance
> callback_factory_
;
181 const PPB_Console
* console_if_
;
182 const PPB_Core
* core_if_
;
183 const PPB_OpenGLES2
* gles2_if_
;
186 pp::Graphics3D
* context_
;
187 typedef std::map
<int, DecoderClient
*> Decoders
;
188 Decoders video_decoders_
;
190 // Shader program to draw GL_TEXTURE_2D target.
192 // Shader program to draw GL_TEXTURE_RECTANGLE_ARB target.
193 Shader shader_rectangle_arb_
;
196 VideoDecodeDemoInstance::DecoderClient::DecoderClient(
197 VideoDecodeDemoInstance
* gles2
, pp::VideoDecoder_Dev
* decoder
)
198 : gles2_(gles2
), decoder_(decoder
), callback_factory_(this),
199 next_picture_buffer_id_(0),
200 next_bitstream_buffer_id_(0), encoded_data_next_pos_to_decode_(0) {
203 VideoDecodeDemoInstance::DecoderClient::~DecoderClient() {
207 for (BitstreamBufferMap::iterator it
= bitstream_buffers_by_id_
.begin();
208 it
!= bitstream_buffers_by_id_
.end(); ++it
) {
211 bitstream_buffers_by_id_
.clear();
213 for (PictureBufferMap::iterator it
= picture_buffers_by_id_
.begin();
214 it
!= picture_buffers_by_id_
.end(); ++it
) {
215 gles2_
->DeleteTexture(it
->second
.buffer
.texture_id
);
217 picture_buffers_by_id_
.clear();
220 VideoDecodeDemoInstance::VideoDecodeDemoInstance(PP_Instance instance
,
222 : pp::Instance(instance
), pp::Graphics3DClient(this),
223 pp::VideoDecoderClient_Dev(this),
225 num_frames_rendered_(0),
226 first_frame_delivered_ticks_(-1),
228 callback_factory_(this),
229 console_if_(static_cast<const PPB_Console
*>(
230 module
->GetBrowserInterface(PPB_CONSOLE_INTERFACE
))),
231 core_if_(static_cast<const PPB_Core
*>(
232 module
->GetBrowserInterface(PPB_CORE_INTERFACE
))),
233 gles2_if_(static_cast<const PPB_OpenGLES2
*>(
234 module
->GetBrowserInterface(PPB_OPENGLES2_INTERFACE
))),
241 VideoDecodeDemoInstance::~VideoDecodeDemoInstance() {
242 if (shader_2d_
.program
)
243 gles2_if_
->DeleteProgram(context_
->pp_resource(), shader_2d_
.program
);
244 if (shader_rectangle_arb_
.program
) {
245 gles2_if_
->DeleteProgram(
246 context_
->pp_resource(), shader_rectangle_arb_
.program
);
249 for (Decoders::iterator it
= video_decoders_
.begin();
250 it
!= video_decoders_
.end(); ++it
) {
253 video_decoders_
.clear();
257 void VideoDecodeDemoInstance::DidChangeView(
258 const pp::Rect
& position
, const pp::Rect
& clip_ignored
) {
259 if (position
.width() == 0 || position
.height() == 0)
261 if (plugin_size_
.width()) {
262 assert(position
.size() == plugin_size_
);
265 plugin_size_
= position
.size();
267 // Initialize graphics.
269 InitializeDecoders();
272 void VideoDecodeDemoInstance::InitializeDecoders() {
273 assert(video_decoders_
.empty());
274 for (int i
= 0; i
< kNumDecoders
; ++i
) {
275 DecoderClient
* client
= new DecoderClient(
276 this, new pp::VideoDecoder_Dev(
277 this, *context_
, PP_VIDEODECODER_H264PROFILE_MAIN
));
278 assert(!client
->decoder()->is_null());
279 assert(video_decoders_
.insert(std::make_pair(
280 client
->decoder()->pp_resource(), client
)).second
);
281 client
->DecodeNextNALUs();
285 void VideoDecodeDemoInstance::DecoderClient::DecoderBitstreamDone(
286 int32_t result
, int bitstream_buffer_id
) {
287 assert(bitstream_ids_at_decoder_
.erase(bitstream_buffer_id
) == 1);
288 BitstreamBufferMap::iterator it
=
289 bitstream_buffers_by_id_
.find(bitstream_buffer_id
);
290 assert(it
!= bitstream_buffers_by_id_
.end());
292 bitstream_buffers_by_id_
.erase(it
);
296 void VideoDecodeDemoInstance::DecoderClient::DecoderFlushDone(int32_t result
) {
297 assert(result
== PP_OK
);
298 // Check that each bitstream buffer ID we handed to the decoder got handed
300 assert(bitstream_ids_at_decoder_
.empty());
305 static bool LookingAtNAL(const unsigned char* encoded
, size_t pos
) {
306 return pos
+ 3 < kDataLen
&&
307 encoded
[pos
] == 0 && encoded
[pos
+ 1] == 0 &&
308 encoded
[pos
+ 2] == 0 && encoded
[pos
+ 3] == 1;
311 void VideoDecodeDemoInstance::DecoderClient::GetNextNALUBoundary(
312 size_t start_pos
, size_t* end_pos
) {
313 assert(LookingAtNAL(kData
, start_pos
));
314 *end_pos
= start_pos
;
316 while (*end_pos
+ 3 < kDataLen
&&
317 !LookingAtNAL(kData
, *end_pos
)) {
320 if (*end_pos
+ 3 >= kDataLen
) {
326 void VideoDecodeDemoInstance::DecoderClient::DecodeNextNALUs() {
327 while (encoded_data_next_pos_to_decode_
<= kDataLen
&&
328 bitstream_ids_at_decoder_
.size() < kNumConcurrentDecodes
) {
333 void VideoDecodeDemoInstance::DecoderClient::DecodeNextNALU() {
334 if (encoded_data_next_pos_to_decode_
== kDataLen
) {
335 ++encoded_data_next_pos_to_decode_
;
336 pp::CompletionCallback cb
= callback_factory_
.NewCallback(
337 &VideoDecodeDemoInstance::DecoderClient::DecoderFlushDone
);
341 size_t start_pos
= encoded_data_next_pos_to_decode_
;
343 GetNextNALUBoundary(start_pos
, &end_pos
);
344 pp::Buffer_Dev
* buffer
= new pp::Buffer_Dev(
345 gles2_
, static_cast<uint32_t>(end_pos
- start_pos
));
346 PP_VideoBitstreamBuffer_Dev bitstream_buffer
;
347 int id
= ++next_bitstream_buffer_id_
;
348 bitstream_buffer
.id
= id
;
349 bitstream_buffer
.size
= static_cast<uint32_t>(end_pos
- start_pos
);
350 bitstream_buffer
.data
= buffer
->pp_resource();
351 memcpy(buffer
->data(), kData
+ start_pos
, end_pos
- start_pos
);
352 assert(bitstream_buffers_by_id_
.insert(std::make_pair(id
, buffer
)).second
);
354 pp::CompletionCallback cb
=
355 callback_factory_
.NewCallback(
356 &VideoDecodeDemoInstance::DecoderClient::DecoderBitstreamDone
, id
);
357 assert(bitstream_ids_at_decoder_
.insert(id
).second
);
358 encoded_data_next_pos_to_decode_
= end_pos
;
359 decoder_
->Decode(bitstream_buffer
, cb
);
362 void VideoDecodeDemoInstance::ProvidePictureBuffers(PP_Resource decoder
,
363 uint32_t req_num_of_bufs
,
364 const PP_Size
& dimensions
,
365 uint32_t texture_target
) {
366 DecoderClient
* client
= video_decoders_
[decoder
];
368 client
->ProvidePictureBuffers(req_num_of_bufs
, dimensions
, texture_target
);
371 void VideoDecodeDemoInstance::DecoderClient::ProvidePictureBuffers(
372 uint32_t req_num_of_bufs
,
374 uint32_t texture_target
) {
375 std::vector
<PP_PictureBuffer_Dev
> buffers
;
376 for (uint32_t i
= 0; i
< req_num_of_bufs
; ++i
) {
377 PictureBufferInfo info
;
378 info
.buffer
.size
= dimensions
;
379 info
.texture_target
= texture_target
;
380 info
.buffer
.texture_id
= gles2_
->CreateTexture(
381 dimensions
.width
, dimensions
.height
, info
.texture_target
);
382 int id
= ++next_picture_buffer_id_
;
384 buffers
.push_back(info
.buffer
);
385 assert(picture_buffers_by_id_
.insert(std::make_pair(id
, info
)).second
);
387 decoder_
->AssignPictureBuffers(buffers
);
390 const PictureBufferInfo
&
391 VideoDecodeDemoInstance::DecoderClient::GetPictureBufferInfoById(
393 PictureBufferMap::iterator it
= picture_buffers_by_id_
.find(id
);
394 assert(it
!= picture_buffers_by_id_
.end());
398 void VideoDecodeDemoInstance::DismissPictureBuffer(PP_Resource decoder
,
399 int32_t picture_buffer_id
) {
400 DecoderClient
* client
= video_decoders_
[decoder
];
402 client
->DismissPictureBuffer(picture_buffer_id
);
405 void VideoDecodeDemoInstance::DecoderClient::DismissPictureBuffer(
406 int32_t picture_buffer_id
) {
407 gles2_
->DeleteTexture(GetPictureBufferInfoById(
408 picture_buffer_id
).buffer
.texture_id
);
409 picture_buffers_by_id_
.erase(picture_buffer_id
);
412 void VideoDecodeDemoInstance::PictureReady(PP_Resource decoder
,
413 const PP_Picture_Dev
& picture
) {
414 if (first_frame_delivered_ticks_
== -1)
415 assert((first_frame_delivered_ticks_
= core_if_
->GetTimeTicks()) != -1);
417 pictures_pending_paint_
.push_back(std::make_pair(decoder
, picture
));
420 DecoderClient
* client
= video_decoders_
[decoder
];
422 const PictureBufferInfo
& info
=
423 client
->GetPictureBufferInfoById(picture
.picture_buffer_id
);
424 assert(!is_painting_
);
428 if (client
!= video_decoders_
.begin()->second
) {
429 x
= plugin_size_
.width() / kNumDecoders
;
430 y
= plugin_size_
.height() / kNumDecoders
;
433 if (info
.texture_target
== GL_TEXTURE_2D
) {
434 Create2DProgramOnce();
435 gles2_if_
->UseProgram(context_
->pp_resource(), shader_2d_
.program
);
436 gles2_if_
->Uniform2f(
437 context_
->pp_resource(), shader_2d_
.texcoord_scale_location
, 1.0, 1.0);
439 assert(info
.texture_target
== GL_TEXTURE_RECTANGLE_ARB
);
440 CreateRectangleARBProgramOnce();
441 gles2_if_
->UseProgram(
442 context_
->pp_resource(), shader_rectangle_arb_
.program
);
443 gles2_if_
->Uniform2f(context_
->pp_resource(),
444 shader_rectangle_arb_
.texcoord_scale_location
,
445 static_cast<GLfloat
>(info
.buffer
.size
.width
),
446 static_cast<GLfloat
>(info
.buffer
.size
.height
));
449 gles2_if_
->Viewport(context_
->pp_resource(), x
, y
,
450 plugin_size_
.width() / kNumDecoders
,
451 plugin_size_
.height() / kNumDecoders
);
452 gles2_if_
->ActiveTexture(context_
->pp_resource(), GL_TEXTURE0
);
453 gles2_if_
->BindTexture(
454 context_
->pp_resource(), info
.texture_target
, info
.buffer
.texture_id
);
455 gles2_if_
->DrawArrays(context_
->pp_resource(), GL_TRIANGLE_STRIP
, 0, 4);
457 gles2_if_
->UseProgram(context_
->pp_resource(), 0);
459 pp::CompletionCallback cb
=
460 callback_factory_
.NewCallback(
461 &VideoDecodeDemoInstance::PaintFinished
, decoder
, info
.buffer
.id
);
462 last_swap_request_ticks_
= core_if_
->GetTimeTicks();
463 assert(context_
->SwapBuffers(cb
) == PP_OK_COMPLETIONPENDING
);
466 void VideoDecodeDemoInstance::NotifyError(PP_Resource decoder
,
467 PP_VideoDecodeError_Dev error
) {
468 LogError(this).s() << "Received error: " << error
;
469 assert(false && "Unexpected error; see stderr for details");
472 // This object is the global object representing this plugin library as long
474 class VideoDecodeDemoModule
: public pp::Module
{
476 VideoDecodeDemoModule() : pp::Module() {}
477 virtual ~VideoDecodeDemoModule() {}
479 virtual pp::Instance
* CreateInstance(PP_Instance instance
) {
480 return new VideoDecodeDemoInstance(instance
, this);
484 void VideoDecodeDemoInstance::InitGL() {
485 assert(plugin_size_
.width() && plugin_size_
.height());
486 is_painting_
= false;
489 int32_t context_attributes
[] = {
490 PP_GRAPHICS3DATTRIB_ALPHA_SIZE
, 8,
491 PP_GRAPHICS3DATTRIB_BLUE_SIZE
, 8,
492 PP_GRAPHICS3DATTRIB_GREEN_SIZE
, 8,
493 PP_GRAPHICS3DATTRIB_RED_SIZE
, 8,
494 PP_GRAPHICS3DATTRIB_DEPTH_SIZE
, 0,
495 PP_GRAPHICS3DATTRIB_STENCIL_SIZE
, 0,
496 PP_GRAPHICS3DATTRIB_SAMPLES
, 0,
497 PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS
, 0,
498 PP_GRAPHICS3DATTRIB_WIDTH
, plugin_size_
.width(),
499 PP_GRAPHICS3DATTRIB_HEIGHT
, plugin_size_
.height(),
500 PP_GRAPHICS3DATTRIB_NONE
,
502 context_
= new pp::Graphics3D(this, context_attributes
);
503 assert(!context_
->is_null());
504 assert(BindGraphics(*context_
));
507 gles2_if_
->ClearColor(context_
->pp_resource(), 1, 0, 0, 1);
508 gles2_if_
->Clear(context_
->pp_resource(), GL_COLOR_BUFFER_BIT
);
515 void VideoDecodeDemoInstance::PaintFinished(int32_t result
, PP_Resource decoder
,
516 int picture_buffer_id
) {
517 assert(result
== PP_OK
);
518 swap_ticks_
+= core_if_
->GetTimeTicks() - last_swap_request_ticks_
;
519 is_painting_
= false;
520 ++num_frames_rendered_
;
521 if (num_frames_rendered_
% 50 == 0) {
522 double elapsed
= core_if_
->GetTimeTicks() - first_frame_delivered_ticks_
;
523 double fps
= (elapsed
> 0) ? num_frames_rendered_
/ elapsed
: 1000;
524 double ms_per_swap
= (swap_ticks_
* 1e3
) / num_frames_rendered_
;
525 LogError(this).s() << "Rendered frames: " << num_frames_rendered_
526 << ", fps: " << fps
<< ", with average ms/swap of: "
529 DecoderClient
* client
= video_decoders_
[decoder
];
530 if (client
&& client
->decoder())
531 client
->decoder()->ReusePictureBuffer(picture_buffer_id
);
532 if (!pictures_pending_paint_
.empty()) {
533 std::pair
<PP_Resource
, PP_Picture_Dev
> decoder_picture
=
534 pictures_pending_paint_
.front();
535 pictures_pending_paint_
.pop_front();
536 PictureReady(decoder_picture
.first
, decoder_picture
.second
);
540 GLuint
VideoDecodeDemoInstance::CreateTexture(int32_t width
,
542 GLenum texture_target
) {
544 gles2_if_
->GenTextures(context_
->pp_resource(), 1, &texture_id
);
546 // Assign parameters.
547 gles2_if_
->ActiveTexture(context_
->pp_resource(), GL_TEXTURE0
);
548 gles2_if_
->BindTexture(context_
->pp_resource(), texture_target
, texture_id
);
549 gles2_if_
->TexParameteri(
550 context_
->pp_resource(), texture_target
, GL_TEXTURE_MIN_FILTER
,
552 gles2_if_
->TexParameteri(
553 context_
->pp_resource(), texture_target
, GL_TEXTURE_MAG_FILTER
,
555 gles2_if_
->TexParameterf(
556 context_
->pp_resource(), texture_target
, GL_TEXTURE_WRAP_S
,
558 gles2_if_
->TexParameterf(
559 context_
->pp_resource(), texture_target
, GL_TEXTURE_WRAP_T
,
562 if (texture_target
== GL_TEXTURE_2D
) {
563 gles2_if_
->TexImage2D(
564 context_
->pp_resource(), texture_target
, 0, GL_RGBA
, width
, height
, 0,
565 GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
571 void VideoDecodeDemoInstance::DeleteTexture(GLuint id
) {
572 gles2_if_
->DeleteTextures(context_
->pp_resource(), 1, &id
);
575 void VideoDecodeDemoInstance::CreateGLObjects() {
576 // Assign vertex positions and texture coordinates to buffers for use in
578 static const float kVertices
[] = {
579 -1, 1, -1, -1, 1, 1, 1, -1, // Position coordinates.
580 0, 1, 0, 0, 1, 1, 1, 0, // Texture coordinates.
584 gles2_if_
->GenBuffers(context_
->pp_resource(), 1, &buffer
);
585 gles2_if_
->BindBuffer(context_
->pp_resource(), GL_ARRAY_BUFFER
, buffer
);
587 gles2_if_
->BufferData(context_
->pp_resource(), GL_ARRAY_BUFFER
,
588 sizeof(kVertices
), kVertices
, GL_STATIC_DRAW
);
592 static const char kVertexShader
[] =
593 "varying vec2 v_texCoord; \n"
594 "attribute vec4 a_position; \n"
595 "attribute vec2 a_texCoord; \n"
596 "uniform vec2 v_scale; \n"
599 " v_texCoord = v_scale * a_texCoord; \n"
600 " gl_Position = a_position; \n"
603 void VideoDecodeDemoInstance::Create2DProgramOnce() {
604 if (shader_2d_
.program
)
606 static const char kFragmentShader2D
[] =
607 "precision mediump float; \n"
608 "varying vec2 v_texCoord; \n"
609 "uniform sampler2D s_texture; \n"
612 " gl_FragColor = texture2D(s_texture, v_texCoord); \n"
614 shader_2d_
= CreateProgram(kVertexShader
, kFragmentShader2D
);
618 void VideoDecodeDemoInstance::CreateRectangleARBProgramOnce() {
619 if (shader_rectangle_arb_
.program
)
621 static const char kFragmentShaderRectangle
[] =
622 "#extension GL_ARB_texture_rectangle : require\n"
623 "precision mediump float; \n"
624 "varying vec2 v_texCoord; \n"
625 "uniform sampler2DRect s_texture; \n"
628 " gl_FragColor = texture2DRect(s_texture, v_texCoord).rgba; \n"
630 shader_rectangle_arb_
=
631 CreateProgram(kVertexShader
, kFragmentShaderRectangle
);
634 Shader
VideoDecodeDemoInstance::CreateProgram(const char* vertex_shader
,
635 const char* fragment_shader
) {
638 // Create shader program.
639 shader
.program
= gles2_if_
->CreateProgram(context_
->pp_resource());
640 CreateShader(shader
.program
, GL_VERTEX_SHADER
, vertex_shader
,
641 static_cast<int>(strlen(vertex_shader
)));
642 CreateShader(shader
.program
, GL_FRAGMENT_SHADER
, fragment_shader
,
643 static_cast<int>(strlen(fragment_shader
)));
644 gles2_if_
->LinkProgram(context_
->pp_resource(), shader
.program
);
645 gles2_if_
->UseProgram(context_
->pp_resource(), shader
.program
);
646 gles2_if_
->Uniform1i(
647 context_
->pp_resource(),
648 gles2_if_
->GetUniformLocation(
649 context_
->pp_resource(), shader
.program
, "s_texture"), 0);
652 shader
.texcoord_scale_location
= gles2_if_
->GetUniformLocation(
653 context_
->pp_resource(), shader
.program
, "v_scale");
655 GLint pos_location
= gles2_if_
->GetAttribLocation(
656 context_
->pp_resource(), shader
.program
, "a_position");
657 GLint tc_location
= gles2_if_
->GetAttribLocation(
658 context_
->pp_resource(), shader
.program
, "a_texCoord");
661 gles2_if_
->EnableVertexAttribArray(context_
->pp_resource(), pos_location
);
662 gles2_if_
->VertexAttribPointer(context_
->pp_resource(), pos_location
, 2,
663 GL_FLOAT
, GL_FALSE
, 0, 0);
664 gles2_if_
->EnableVertexAttribArray(context_
->pp_resource(), tc_location
);
665 gles2_if_
->VertexAttribPointer(
666 context_
->pp_resource(), tc_location
, 2, GL_FLOAT
, GL_FALSE
, 0,
667 static_cast<float*>(0) + 8); // Skip position coordinates.
669 gles2_if_
->UseProgram(context_
->pp_resource(), 0);
674 void VideoDecodeDemoInstance::CreateShader(
675 GLuint program
, GLenum type
, const char* source
, int size
) {
676 GLuint shader
= gles2_if_
->CreateShader(context_
->pp_resource(), type
);
677 gles2_if_
->ShaderSource(context_
->pp_resource(), shader
, 1, &source
, &size
);
678 gles2_if_
->CompileShader(context_
->pp_resource(), shader
);
679 gles2_if_
->AttachShader(context_
->pp_resource(), program
, shader
);
680 gles2_if_
->DeleteShader(context_
->pp_resource(), shader
);
682 } // anonymous namespace
685 // Factory function for your specialization of the Module object.
686 Module
* CreateModule() {
687 return new VideoDecodeDemoModule();