OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2011 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 "ppapi/examples/video_decoder/video_decoder_session.h" | |
6 | |
7 #include <cstring> | |
8 #include <fstream> | |
9 #include <iostream> | |
10 | |
11 #include "ppapi/c/dev/pp_graphics_3d_dev.h" | |
12 #include "ppapi/c/dev/ppb_buffer_dev.h" | |
13 #include "ppapi/c/pp_errors.h" | |
14 #include "ppapi/cpp/dev/context_3d_dev.h" | |
15 #include "ppapi/cpp/dev/surface_3d_dev.h" | |
16 #include "ppapi/cpp/dev/video_decoder_dev.h" | |
17 #include "ppapi/lib/gl/include/GLES2/gl2.h" | |
18 | |
19 // Pull-based video source to read video data from a file. | |
20 class TestVideoSource { | |
21 public: | |
22 TestVideoSource() | |
23 : file_length_(0), | |
24 offset_(0) {} | |
25 | |
26 ~TestVideoSource() {} | |
27 | |
28 bool Open(const std::string& url) { | |
29 // TODO(vmr): Use file_util::ReadFileToString or equivalent to read the file | |
30 // if one-shot reading is used. | |
31 std::ifstream* file = | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
scoped_ptr, then delete the deletes below :)
Ville-Mikko Rautio
2011/06/03 13:24:39
I am in impression that relying on anything from C
| |
32 new std::ifstream(url.c_str(), | |
33 std::ios::in | std::ios::binary | std::ios::ate); | |
34 if (!file->good()) { | |
35 delete file; | |
36 return false; | |
37 } | |
38 file->seekg(0, std::ios::end); | |
39 uint32_t length = file->tellg(); | |
40 file->seekg(0, std::ios::beg); | |
41 mem_ = new uint8_t[length]; | |
42 file->read(reinterpret_cast<char*>(mem_), length); | |
43 file_length_ = length; | |
44 file->close(); | |
45 delete file; | |
46 return true; | |
47 } | |
48 | |
49 // Reads next packet from the input stream. | |
50 // Returns number of read bytes on success, 0 on when there was no valid data | |
51 // to be read and -1 if user gave NULL or too small buffer. | |
52 // TODO(vmr): Modify to differentiate between errors and EOF. | |
53 int32_t Read(uint8_t* target_mem, uint32_t size) { | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
It looks like you are doing some decoding to split
Ville-Mikko Rautio
2011/06/03 13:24:39
There is possibility to pass the whole bitstream f
| |
54 if (!target_mem) | |
55 return -1; | |
56 uint8_t* unit_begin = NULL; | |
57 uint8_t* unit_end = NULL; | |
58 uint8_t* ptr = mem_ + offset_; | |
59 while (offset_ + 4 < file_length_) { | |
60 if (ptr[0] == 0 && ptr[1] == 0 && ptr[2] == 0 && ptr[3] == 1) { | |
61 // start code found | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Complete sentence + explanation of start code.
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
62 if (!unit_begin) { | |
63 unit_begin = ptr; | |
64 } else { | |
65 // back-up 1 byte. | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Complete sentence.
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
66 unit_end = ptr; | |
67 break; | |
68 } | |
69 } | |
70 ptr++; | |
71 offset_++; | |
72 } | |
73 if (unit_begin && offset_ + 4 == file_length_) { | |
74 // Last unit. Set the unit_end to point to the last byte. | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
The last buffer begins _and_ ends with 0001?
In ot
Ville-Mikko Rautio
2011/06/03 13:24:39
There's no 0001 at the end. +4 needed because of t
| |
75 unit_end = ptr + 4; | |
76 offset_ += 4; | |
77 } else if (!unit_begin || !unit_end) { | |
78 // No unit start codes found in buffer. | |
79 return 0; | |
80 } | |
81 if (static_cast<int32_t>(size) >= unit_end - unit_begin) { | |
82 memcpy(target_mem, unit_begin, unit_end - unit_begin); | |
83 return unit_end - unit_begin; | |
84 } | |
85 // Rewind to the beginning start code if there is one as it should be | |
86 // returned with next Read(). | |
87 offset_ = unit_begin - mem_; | |
88 return -1; | |
89 } | |
90 | |
91 private: | |
92 uint32_t file_length_; | |
93 uint32_t offset_; | |
94 uint8_t* mem_; | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
scoped_array? At the very least you need to delete
Ville-Mikko Rautio
2011/06/03 13:24:39
True. Added delete for destructor since I am not s
| |
95 }; | |
96 | |
97 LocalVideoBitstreamSource::LocalVideoBitstreamSource(std::string filename) | |
98 : file_(filename), | |
99 video_source_(new TestVideoSource()), | |
100 video_source_open_(false) { | |
101 } | |
102 | |
103 LocalVideoBitstreamSource::~LocalVideoBitstreamSource() { | |
104 delete video_source_; | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
No longer needed w/ scoped_ptr
Ville-Mikko Rautio
2011/06/03 13:24:39
Ditto.
| |
105 } | |
106 | |
107 bool LocalVideoBitstreamSource::GetBitstreamUnit( | |
108 void* target_mem, | |
109 uint32_t target_mem_size_in_bytes, | |
110 int32_t* unit_size_in_bytes) { | |
111 if (!video_source_open_) { | |
112 if (!video_source_->Open(file_)) { | |
113 return false; | |
114 } | |
115 video_source_open_ = true; | |
116 } | |
117 int32_t read_bytes = video_source_->Read(static_cast<uint8_t*>(target_mem), | |
118 target_mem_size_in_bytes); | |
119 if (read_bytes <= 0) { | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Nit: no {} for one-line condition
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
120 return false; | |
121 } | |
122 *unit_size_in_bytes = read_bytes; | |
123 return true; | |
124 } | |
125 | |
126 VideoDecoderSessionClient::~VideoDecoderSessionClient() { | |
127 } | |
128 | |
129 // Constants used by VideoDecoderSession. | |
130 static const int32_t kBitstreamBufferCount = 3; | |
131 static const int32_t kBitstreamBufferSize = 256 * 1024 * 1024; | |
132 static const int32_t kDefaultWidth = 640; | |
133 static const int32_t kDefaultHeight = 480; | |
134 | |
135 bool VideoDecoderSession::Initialize( | |
136 const std::vector<uint32_t>& decoder_config, | |
137 pp::CompletionCallback completion_callback) { | |
138 assert(video_source_ && display_); | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Do this check in the constructor.
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
139 // Default implementation just assumes everything is set up. | |
140 if (!AllocateInputBuffers()) { | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Nit: No {}
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
141 return false; | |
142 } | |
143 pp::CompletionCallback cb = cb_factory_.NewCallback( | |
144 &VideoDecoderSession::OnInitializeDone, completion_callback); | |
145 video_decoder_ = new pp::VideoDecoder(instance_, decoder_config, cb, this); | |
146 if (!video_decoder_) { | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Nit: No {}
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
147 return false; | |
148 } | |
149 return true; | |
150 } | |
151 | |
152 bool VideoDecoderSession::Run(pp::CompletionCallback completion_callback) { | |
153 assert(state_ == kInitialized); | |
154 // Start the streaming by dispatching the first buffers one by one. | |
155 for (std::map<int32_t, PP_VideoBitstreamBuffer_Dev>::iterator it = | |
156 bitstream_buffers_.begin(); | |
157 it == bitstream_buffers_.end(); | |
158 it++) { | |
159 if (!ReadAndDispatchBitstreamUnit((*it).first)) { | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Nit: {}
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
160 return false; | |
161 } | |
162 } | |
163 // Once streaming has been started, we're running. | |
164 ChangeState(kRunning); | |
165 completion_callback.Run(PP_OK); | |
166 return true; | |
167 } | |
168 | |
169 bool VideoDecoderSession::Stop(pp::CompletionCallback completion_callback) { | |
170 assert(state_ == kRunning); | |
171 // Stop the playback. | |
172 ChangeState(kInitialized); | |
173 return true; | |
174 } | |
175 | |
176 bool VideoDecoderSession::Flush(pp::CompletionCallback completion_callback) { | |
177 assert(state_ == kRunning); | |
178 // Issue the flush request. | |
179 ChangeState(kFlushing); | |
180 video_decoder_->Flush(cb_factory_.NewCallback( | |
181 &VideoDecoderSession::OnUserFlushDone, state_, completion_callback)); | |
182 return true; | |
183 } | |
184 | |
185 bool VideoDecoderSession::Teardown(pp::CompletionCallback completion_callback) { | |
186 assert(state_ == kInitialized); | |
187 // Teardown the resources. | |
188 FreeInputBuffers(); | |
189 ChangeState(kCreated); | |
190 completion_callback.Run(PP_OK); | |
191 return true; | |
192 } | |
193 | |
194 void VideoDecoderSession::ProvidePictureBuffers( | |
195 uint32_t requested_num_of_buffers, | |
196 const std::vector<uint32_t>& buffer_properties) { | |
vjain
2011/05/31 22:29:07
What is the purpose of buffer_properties?
Will GPU
Ville-Mikko Rautio
2011/06/01 11:50:08
Buffer properties will contain width & height and
vrk (LEFT CHROMIUM)
2011/06/01 22:41:31
Actually, this C++ API is not up to date with the
Ville-Mikko Rautio
2011/06/03 13:24:39
C++ API change (http://codereview.chromium.org/708
| |
197 // Currently we support only GLES buffer allocation. | |
198 std::vector<PP_GLESBuffer_Dev> buffers; | |
199 for (uint32_t i = 0; i < requested_num_of_buffers; i++) { | |
200 PP_GLESBuffer_Dev gles_buffer; | |
201 if (!display_->ProvideGLESPictureBuffer(buffer_properties, &gles_buffer)) { | |
202 video_decoder_->Abort(cb_factory_.NewCallback( | |
203 &VideoDecoderSession::OnAbortDone)); | |
204 return; | |
205 } | |
206 buffers.push_back(gles_buffer); | |
207 } | |
208 video_decoder_->AssignGLESBuffers(buffers.size(), buffers); | |
209 } | |
210 | |
211 void VideoDecoderSession::DismissPictureBuffer(int32_t picture_buffer_id) { | |
212 if (!display_->DismissPictureBuffer(picture_buffer_id)) { | |
213 assert(!"Failed to dismiss picture buffer properly"); | |
214 return; | |
215 } | |
216 } | |
217 | |
218 void VideoDecoderSession::PictureReady(const PP_Picture_Dev& picture) { | |
219 display_->DrawPicture(picture, cb_factory_.NewCallback( | |
220 &VideoDecoderSession::OnDrawPictureDone, picture.picture_buffer_id)); | |
221 } | |
222 | |
223 void VideoDecoderSession::NotifyEndOfStream() { | |
224 end_of_stream_ = true; | |
225 video_decoder_->Flush(cb_factory_.NewCallback( | |
226 &VideoDecoderSession::OnInternalFlushDone)); | |
227 } | |
228 | |
229 void VideoDecoderSession::NotifyError(PP_VideoDecodeError_Dev error) { | |
230 video_decoder_->Flush(cb_factory_.NewCallback( | |
231 &VideoDecoderSession::OnInternalFlushDone)); | |
232 } | |
233 | |
234 int32_t VideoDecoderSession::GetUniqueId() { | |
235 // Not exactly unique in the current form but close enough for use case. | |
236 return next_id_++; | |
237 } | |
238 | |
239 void VideoDecoderSession::OnInitializeDone(int32_t result, | |
240 pp::CompletionCallback callback) { | |
241 if (state_ != kCreated) { | |
242 ChangeState(kCreated); | |
243 callback.Run(PP_ERROR_ABORTED); | |
244 } | |
245 if (result != PP_OK) { | |
246 ChangeState(kInitialized); | |
247 callback.Run(result); | |
248 } | |
249 callback.Run(PP_OK); | |
250 } | |
251 | |
252 void VideoDecoderSession::OnBitstreamBufferProcessed( | |
vjain
2011/06/02 01:04:52
Hi Ville-Mikko,
When the GPU decoder returns the b
Ville-Mikko Rautio
2011/06/03 13:24:39
I am not sure what are you referring to. Bitstream
| |
253 int32_t result, | |
254 int32_t bitstream_buffer_id) { | |
255 // Reuse each bitstream buffer that has been processed by reading data into it | |
256 // as long as there is more and pass that for decoding. | |
257 ReadAndDispatchBitstreamUnit(bitstream_buffer_id); | |
258 } | |
259 | |
260 void VideoDecoderSession::OnDrawPictureDone(int32_t result, | |
261 int32_t picture_buffer_id) { | |
262 video_decoder_->ReusePictureBuffer(picture_buffer_id); | |
263 } | |
264 | |
265 void VideoDecoderSession::OnUserFlushDone(int32_t result, | |
266 State target_state, | |
267 pp::CompletionCallback callback) { | |
268 assert(state_ == kFlushing); | |
269 // It was a Flush request, return to the state where we started. | |
270 ChangeState(target_state); | |
271 callback.Run(result); | |
272 } | |
273 | |
274 void VideoDecoderSession::OnInternalFlushDone(int32_t result) { | |
275 if (end_of_stream_) { | |
276 // It was end of stream flush. | |
277 video_decoder_->Abort(cb_factory_.NewCallback( | |
278 &VideoDecoderSession::OnAbortDone)); | |
279 } else { | |
280 assert(!"Unhandled flush completion!"); | |
281 } | |
282 } | |
283 | |
284 void VideoDecoderSession::OnAbortDone(int32_t result) { | |
285 client_->OnSessionCompleted(result); | |
286 } | |
287 | |
288 bool VideoDecoderSession::AllocateInputBuffers() { | |
289 buffer_if_ = static_cast<const struct PPB_Buffer_Dev*>( | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
?? Why is this field being set here? Shouldn't thi
Ville-Mikko Rautio
2011/06/03 13:24:39
Moved to ctor and added assert for variable.
| |
290 pp::Module::Get()->GetBrowserInterface(PPB_BUFFER_DEV_INTERFACE)); | |
291 if (!buffer_if_) { | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Nit: no {}
Ville-Mikko Rautio
2011/06/03 13:24:39
Removed
| |
292 return false; | |
293 } | |
294 // Allocate |kBitstreamBufferCount| bitstream buffers of | |
295 // |kBitstreamBufferSize| bytes. | |
296 for (int32_t i = 0; i < kBitstreamBufferCount; i++) { | |
297 PP_VideoBitstreamBuffer_Dev bitstream_buffer; | |
298 bitstream_buffer.data = buffer_if_->Create(instance_->pp_instance(), | |
299 kBitstreamBufferSize); | |
300 if (bitstream_buffer.data == 0) { | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Nit: no {}
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
301 return false; | |
302 } | |
303 bitstream_buffer.size = 0; | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
This should be kBitstreamBufferSize with change me
Ville-Mikko Rautio
2011/06/03 13:24:39
This is the amount of valid data in buffer, so I d
| |
304 bitstream_buffer.id = GetUniqueId(); | |
305 bitstream_buffers_[bitstream_buffer.id] = bitstream_buffer; | |
306 } | |
307 return true; | |
308 } | |
309 | |
310 void VideoDecoderSession::FreeInputBuffers() { | |
311 std::map<int32_t, PP_VideoBitstreamBuffer_Dev>::iterator it; | |
312 for (it = bitstream_buffers_.begin(); it != bitstream_buffers_.end(); it++) { | |
313 std::pair<int32_t, PP_VideoBitstreamBuffer_Dev> pair = *it; | |
314 PP_VideoBitstreamBuffer_Dev bitstream_buffer = pair.second; | |
315 pp::Module::Get()->core()->ReleaseResource(bitstream_buffer.data); | |
316 bitstream_buffers_.erase(it); | |
317 } | |
318 } | |
319 | |
320 bool VideoDecoderSession::ReadAndDispatchBitstreamUnit( | |
321 int32_t bitstream_buffer_id) { | |
322 // Get the target memory and read the bitstream unit into it. | |
323 if (bitstream_buffers_.find(bitstream_buffer_id) == | |
324 bitstream_buffers_.end()) { | |
325 return false; | |
326 } | |
327 PP_VideoBitstreamBuffer_Dev bitstream_buffer = | |
328 bitstream_buffers_[bitstream_buffer_id]; | |
329 void* target_mem = buffer_if_->Map(bitstream_buffer.data); | |
330 if (target_mem == NULL) { | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Nit: no {}
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
331 return false; | |
332 } | |
333 uint32_t size_in_bytes = 0; | |
334 if (!buffer_if_->Describe(bitstream_buffer.data, &size_in_bytes)) { | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Nit: no {}
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
335 return false; | |
336 } | |
337 bool success = video_source_->GetBitstreamUnit(target_mem, size_in_bytes, | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
It's wasteful to allocate a buffer of kBitstreamBu
Ville-Mikko Rautio
2011/06/03 13:24:39
Already commented above. You cannot arbitrarily sp
| |
338 &bitstream_buffer.size); | |
339 if (!success) { | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Nit: no {}
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
340 return false; | |
341 } | |
342 // Dispatch the bitstream unit to the decoder. | |
343 success = video_decoder_->Decode( | |
344 bitstream_buffers_[bitstream_buffer_id], | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
bitstream_buffer?
Ville-Mikko Rautio
2011/06/03 13:24:39
Yep. Also, I changed the bitstream_buffer into ref
| |
345 cb_factory_.NewCallback( | |
346 &VideoDecoderSession::OnBitstreamBufferProcessed, | |
347 bitstream_buffer_id)); | |
348 // Finally unmap the buffer for this round. | |
349 buffer_if_->Unmap(bitstream_buffer.data); | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Unmap deletes the bitstream data. Shouldn't we onl
Ville-Mikko Rautio
2011/06/03 13:24:39
True. Done.
| |
350 return success; | |
351 } | |
352 | |
353 void VideoDecoderSession::ChangeState(State to_state) { | |
354 state_ = to_state; | |
355 } | |
356 | |
357 int32_t VideoDecoderSession::next_id_ = 1; | |
358 | |
359 // Pass-through vertex shader. | |
360 static const char kVertexShader[] = | |
361 "precision highp float; precision highp int;\n" | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
I don't believe these precision specifiers are nec
Ville-Mikko Rautio
2011/06/03 13:24:39
I am by no means shader expert, so I'll just take
| |
362 "varying vec2 interp_tc;\n" | |
363 "\n" | |
364 "attribute vec4 in_pos;\n" | |
365 "attribute vec2 in_tc;\n" | |
366 "\n" | |
367 "void main() {\n" | |
368 " interp_tc = in_tc;\n" | |
369 " gl_Position = in_pos;\n" | |
370 "}\n"; | |
371 | |
372 // Color shader for EGLImage. | |
373 static const char kFragmentShaderEgl[] = | |
374 "precision mediump float;\n" | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Ditto above.
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
375 "precision mediump int;\n" | |
376 "varying vec2 interp_tc;\n" | |
377 "\n" | |
378 "uniform sampler2D tex;\n" | |
379 "\n" | |
380 "void main() {\n" | |
381 " gl_FragColor = texture2D(tex, interp_tc);\n" | |
382 "}\n"; | |
383 | |
384 // Buffer size for compile errors. | |
385 static const unsigned int kShaderErrorSize = 4096; | |
386 | |
387 void GLES2Display::Graphics3DContextLost() { | |
388 assert(!"GLES2: Unexpectedly lost graphics context"); | |
389 } | |
390 | |
391 bool GLES2Display::Initialize() { | |
392 if (!InitGL(surface_size_.width, surface_size_.height)) { | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
nit: no {}
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
393 return false; | |
394 } | |
395 ProgramShaders(); | |
396 return true; | |
397 } | |
398 | |
399 bool GLES2Display::ProvideGLESPictureBuffer( | |
400 const std::vector<uint32_t>& buffer_properties, | |
401 PP_GLESBuffer_Dev* picture_buffer) { | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Would make sense to also do the initial call to Te
Ville-Mikko Rautio
2011/06/03 13:24:39
I don't know GL well, so I will need your help in
| |
402 GLuint texture; | |
403 // Generate texture and bind (effectively allocate) it. | |
404 gles2_if_->GenTextures(context_->pp_resource(), 1, &texture); | |
405 gles2_if_->BindTexture(context_->pp_resource(), GL_TEXTURE_2D, texture); | |
406 picture_buffer->context = 0; // TODO(vmr): Get proper context id. | |
407 picture_buffer->texture_id = texture; | |
408 picture_buffer->info.id = VideoDecoderSession::GetUniqueId(); | |
409 picture_buffer->info.size.width = surface_size_.width; | |
410 picture_buffer->info.size.height = surface_size_.height; | |
411 // Store the values into the map for GLES buffers. | |
412 gles_buffers_[picture_buffer->info.id] = *picture_buffer; | |
413 assertNoGLError(); | |
414 return true; | |
415 } | |
416 | |
417 bool GLES2Display::DismissPictureBuffer(int32_t picture_buffer_id) { | |
418 gles2_if_->DeleteTextures(context_->pp_resource(), 1, | |
419 &gles_buffers_[picture_buffer_id].texture_id); | |
420 gles_buffers_.erase(picture_buffer_id); | |
421 return true; | |
422 } | |
423 | |
424 bool GLES2Display::DrawPicture(const PP_Picture_Dev& picture, | |
425 pp::CompletionCallback completion_callback) { | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
nit: add space before pp
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
426 // Decoder has finished decoding picture into the texture, we'll have to just | |
427 // draw the texture to the color buffer and swap the surfaces. | |
428 // Clear the color buffer. | |
429 gles2_if_->Clear(context_->pp_resource(), GL_COLOR_BUFFER_BIT | | |
430 GL_DEPTH_BUFFER_BIT); | |
431 // Load the texture into texture unit 0. | |
432 gles2_if_->ActiveTexture(context_->pp_resource(), GL_TEXTURE0); | |
433 gles2_if_->BindTexture(context_->pp_resource(), GL_TEXTURE_2D, | |
434 gles_buffers_[picture.picture_buffer_id].texture_id); | |
435 // Draw the texture. | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
You never copy data into the texture (TexImage2D/M
Ville-Mikko Rautio
2011/06/03 13:24:39
See above comment about ProvideGLESPictureBuffer.
| |
436 gles2_if_->DrawArrays(context_->pp_resource(), GL_TRIANGLE_STRIP, 0, 4); | |
437 // Force the execution of pending commands. | |
438 // TODO(vmr): Do we have to do this? Can we rely command buffer to execute the | |
439 // commands without Finish call? | |
440 gles2_if_->Finish(context_->pp_resource()); | |
441 assertNoGLError(); | |
442 | |
443 int32_t error = surface_->SwapBuffers(completion_callback); | |
444 if (error != PP_OK) { | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
nit: no {}
Ville-Mikko Rautio
2011/06/03 13:24:39
Done.
| |
445 return false; | |
446 } | |
447 assertNoGLError(); | |
448 return true; | |
449 } | |
450 | |
451 void GLES2Display::assertNoGLError() { | |
452 assert(!gles2_if_->GetError(context_->pp_resource())); | |
453 } | |
454 | |
455 bool GLES2Display::InitGL(int width, int height) { | |
456 assert(width && height); | |
457 gles2_if_ = static_cast<const struct PPB_OpenGLES2_Dev*>( | |
458 pp::Module::Get()->GetBrowserInterface(PPB_OPENGLES2_DEV_INTERFACE)); | |
459 // Firstly, we need OpenGL ES context associated with the display our plugin | |
460 // is rendering to. | |
461 if (context_) delete(context_); | |
462 context_ = new pp::Context3D_Dev(*instance_, 0, pp::Context3D_Dev(), NULL); | |
463 assert(!context_->is_null()); | |
464 // Then we need surface bound to our fresh context. We'll be actually drawing | |
465 // on this surface and swapping that surface to refresh the displayable data | |
466 // of the plugin. | |
467 int32_t surface_attributes[] = { | |
468 PP_GRAPHICS3DATTRIB_WIDTH, surface_size_.width, | |
469 PP_GRAPHICS3DATTRIB_HEIGHT, surface_size_.height, | |
470 PP_GRAPHICS3DATTRIB_NONE | |
471 }; | |
472 if (surface_) delete(surface_); | |
473 surface_ = new pp::Surface3D_Dev(*instance_, 0, surface_attributes); | |
474 assert(!surface_->is_null()); | |
475 int32_t bind_error = context_->BindSurfaces(*surface_, *surface_); | |
476 if (!bind_error) { | |
477 assert(bind_error); | |
478 } | |
479 assertNoGLError(); | |
480 | |
481 bool success = instance_->BindGraphics(*surface_); | |
482 if (!success) { | |
483 assert(success); | |
484 } | |
485 // Clear the color buffer with opaque white for starters. | |
486 gles2_if_->ClearColor(context_->pp_resource(), 1.0, 1.0, 1.0, 0.0); | |
487 gles2_if_->Clear(context_->pp_resource(), GL_COLOR_BUFFER_BIT); | |
488 // Set the viewport to match the whole GL window. | |
489 gles2_if_->Viewport(context_->pp_resource(), 0, 0, surface_size_.width, | |
490 surface_size_.height); | |
491 assertNoGLError(); | |
492 return true; | |
493 } | |
494 | |
495 void GLES2Display::CreateShader(GLuint program, GLenum type, | |
496 const char* source, | |
497 int size) { | |
498 GLuint shader = gles2_if_->CreateShader(context_->pp_resource(), type); | |
499 gles2_if_->ShaderSource( | |
500 context_->pp_resource(), shader, 1, &source, &size); | |
501 gles2_if_->CompileShader(context_->pp_resource(), shader); | |
502 | |
503 int result = GL_FALSE; | |
504 gles2_if_->GetShaderiv( | |
505 context_->pp_resource(), shader, GL_COMPILE_STATUS, &result); | |
506 if (!result) { | |
507 char log[kShaderErrorSize]; | |
508 int len = 0; | |
509 gles2_if_->GetShaderInfoLog(context_->pp_resource(), shader, | |
510 kShaderErrorSize - 1, &len, log); | |
511 log[len] = 0; | |
512 assert(result); | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
You never use log... change to fail with "log" as
Ville-Mikko Rautio
2011/06/03 13:24:39
In Pepper code?
| |
513 } | |
514 gles2_if_->AttachShader(context_->pp_resource(), program, shader); | |
515 gles2_if_->DeleteShader(context_->pp_resource(), shader); | |
516 } | |
517 | |
518 void GLES2Display::LinkProgram(const PPB_OpenGLES2_Dev* gles2_if_ ) { | |
519 gles2_if_->LinkProgram(context_->pp_resource(), program_); | |
520 int result = GL_FALSE; | |
521 gles2_if_->GetProgramiv(context_->pp_resource(), program_, GL_LINK_STATUS, | |
522 &result); | |
523 if (!result) { | |
524 char log[kShaderErrorSize]; | |
525 int len = 0; | |
526 gles2_if_->GetProgramInfoLog(context_->pp_resource(), program_, | |
527 kShaderErrorSize - 1, &len, log); | |
528 log[len] = 0; | |
529 assert(result); | |
530 } | |
531 gles2_if_->UseProgram(context_->pp_resource(), program_); | |
532 } | |
533 | |
534 void GLES2Display::ProgramShaders() { | |
535 // Vertices for a full screen quad. | |
536 static const float kVertices[] = { | |
537 -1.f, 1.f, | |
538 -1.f, -1.f, | |
539 1.f, 1.f, | |
540 1.f, -1.f, | |
541 }; | |
542 | |
543 // Texture Coordinates mapping the entire texture for EGL image. | |
544 static const float kTextureCoordsEgl[] = { | |
545 0, 1, | |
546 0, 0, | |
547 1, 1, | |
548 1, 0, | |
549 }; | |
550 program_ = gles2_if_->CreateProgram(context_->pp_resource()); | |
551 | |
552 // Create shader for EGL image | |
553 CreateShader(program_, GL_VERTEX_SHADER, | |
554 kVertexShader, sizeof(kVertexShader)); | |
555 CreateShader(program_, GL_FRAGMENT_SHADER, | |
556 kFragmentShaderEgl, sizeof(kFragmentShaderEgl)); | |
557 LinkProgram(gles2_if_); | |
558 | |
559 assertNoGLError(); | |
560 // Bind parameters. | |
561 gles2_if_->Uniform1i(context_->pp_resource(), gles2_if_-> | |
562 GetUniformLocation(context_->pp_resource(), program_, | |
563 "tex"), 0); | |
564 gles2_if_->GenBuffers(context_->pp_resource(), 1, &vertex_buffer_); | |
565 gles2_if_->BindBuffer(context_->pp_resource(), GL_ARRAY_BUFFER, | |
566 vertex_buffer_); | |
567 gles2_if_->BufferData(context_->pp_resource(), GL_ARRAY_BUFFER, | |
568 8 * sizeof(kVertices[0]), kVertices, GL_STREAM_DRAW); | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Should this be GL_STATIC_DRAW?
Ville-Mikko Rautio
2011/06/03 13:24:39
I think both will work. I took your suggestion. Do
| |
569 | |
570 assertNoGLError(); | |
571 int pos_location = gles2_if_->GetAttribLocation(context_->pp_resource(), | |
572 program_, "in_pos"); | |
573 gles2_if_->EnableVertexAttribArray(context_->pp_resource(), pos_location); | |
574 gles2_if_->VertexAttribPointer(context_->pp_resource(), pos_location, 2, | |
575 GL_FLOAT, GL_FALSE, 0, 0); | |
576 | |
577 assertNoGLError(); | |
578 gles2_if_->GenBuffers(context_->pp_resource(), 1, &fragment_buffer_); | |
579 gles2_if_->BindBuffer(context_->pp_resource(), GL_ARRAY_BUFFER, | |
580 fragment_buffer_); | |
581 gles2_if_->BufferData(context_->pp_resource(), GL_ARRAY_BUFFER, | |
582 8 * sizeof(kTextureCoordsEgl[0]), | |
583 kTextureCoordsEgl, GL_STREAM_DRAW); | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
Ditto above.
Ville-Mikko Rautio
2011/06/03 13:24:39
Ditto.
| |
584 assertNoGLError(); | |
585 int tc_location = gles2_if_->GetAttribLocation(context_->pp_resource(), | |
586 program_, "in_tc"); | |
587 gles2_if_->EnableVertexAttribArray(context_->pp_resource(), tc_location); | |
588 gles2_if_->VertexAttribPointer(context_->pp_resource(), tc_location, 2, | |
589 GL_FLOAT, GL_FALSE, 0, kTextureCoordsEgl); | |
590 gles2_if_->VertexAttribPointer(context_->pp_resource(), tc_location, 2, | |
591 GL_FLOAT, GL_FALSE, 0, 0); | |
592 gles2_if_->Enable(context_->pp_resource(), GL_DEPTH_TEST); | |
vrk (LEFT CHROMIUM)
2011/06/02 01:47:02
What is GL_DEPTH_TEST?
Ville-Mikko Rautio
2011/06/03 13:24:39
I believe it is feature of the fragment pipeline i
| |
593 assertNoGLError(); | |
594 } | |
595 | |
OLD | NEW |