OLD | NEW |
---|---|
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <vector> | 5 #include <vector> |
6 #include <string> | 6 #include <string> |
7 #include <map> | 7 #include <map> |
8 #include <build/build_config.h> | 8 #include <build/build_config.h> |
9 #include "base/scoped_ptr.h" | 9 #include "base/scoped_ptr.h" |
10 #define GLES2_GPU_SERVICE 1 | 10 #define GLES2_GPU_SERVICE 1 |
11 #include "gpu/command_buffer/common/gles2_cmd_format.h" | 11 #include "gpu/command_buffer/common/gles2_cmd_format.h" |
12 #include "gpu/command_buffer/common/gles2_cmd_utils.h" | 12 #include "gpu/command_buffer/common/gles2_cmd_utils.h" |
13 #include "gpu/command_buffer/service/cmd_buffer_engine.h" | 13 #include "gpu/command_buffer/service/cmd_buffer_engine.h" |
14 #include "gpu/command_buffer/service/gl_utils.h" | 14 #include "gpu/command_buffer/service/gl_utils.h" |
15 #include "gpu/command_buffer/service/gles2_cmd_decoder.h" | 15 #include "gpu/command_buffer/service/gles2_cmd_decoder.h" |
16 #include "gpu/command_buffer/service/gles2_cmd_validation.h" | 16 #include "gpu/command_buffer/service/gles2_cmd_validation.h" |
17 | 17 |
18 namespace gpu { | 18 namespace gpu { |
19 namespace gles2 { | 19 namespace gles2 { |
20 | 20 |
21 // Check that certain assumptions the code makes are true. There are places in | |
22 // the code where shared memory is passed direclty to GL. Example, glUniformiv, | |
23 // glShaderSource. The command buffer code assumes GLint and GLsizei (and maybe | |
24 // a few others) are 32bits. If they are not 32bits the code will have to change | |
25 // to call those GL functions with service side memory and then copy the results | |
26 // to shared memory, converting the sizes. | |
27 COMPILE_ASSERT(sizeof(GLint) == sizeof(uint32), // NOLINT | |
28 GLint_not_same_size_as_uint32); | |
29 COMPILE_ASSERT(sizeof(GLsizei) == sizeof(uint32), // NOLINT | |
30 GLint_not_same_size_as_uint32); | |
31 | |
21 namespace { | 32 namespace { |
22 | 33 |
34 size_t GetGLTypeSize(GLenum type) { | |
35 switch (type) { | |
36 case GL_BYTE: | |
37 return sizeof(GLbyte); // NOLINT | |
38 case GL_UNSIGNED_BYTE: | |
39 return sizeof(GLubyte); // NOLINT | |
40 case GL_SHORT: | |
41 return sizeof(GLshort); // NOLINT | |
42 case GL_UNSIGNED_SHORT: | |
43 return sizeof(GLushort); // NOLINT | |
44 case GL_FLOAT: | |
45 return sizeof(GLfloat); // NOLINT | |
46 default: | |
47 return 0; | |
48 } | |
49 } | |
50 | |
23 // Returns the address of the first byte after a struct. | 51 // Returns the address of the first byte after a struct. |
24 template <typename T> | 52 template <typename T> |
25 const void* AddressAfterStruct(const T& pod) { | 53 const void* AddressAfterStruct(const T& pod) { |
26 return reinterpret_cast<const uint8*>(&pod) + sizeof(pod); | 54 return reinterpret_cast<const uint8*>(&pod) + sizeof(pod); |
27 } | 55 } |
28 | 56 |
29 // Returns the address of the frst byte after the struct. | 57 // Returns the address of the frst byte after the struct or NULL if size > |
58 // immediate_data_size. | |
30 template <typename RETURN_TYPE, typename COMMAND_TYPE> | 59 template <typename RETURN_TYPE, typename COMMAND_TYPE> |
31 RETURN_TYPE GetImmediateDataAs(const COMMAND_TYPE& pod) { | 60 RETURN_TYPE GetImmediateDataAs(const COMMAND_TYPE& pod, |
32 return static_cast<RETURN_TYPE>(const_cast<void*>(AddressAfterStruct(pod))); | 61 uint32 size, |
62 uint32 immediate_data_size) { | |
63 return (size <= immediate_data_size) ? | |
64 static_cast<RETURN_TYPE>(const_cast<void*>(AddressAfterStruct(pod))) : | |
65 NULL; | |
33 } | 66 } |
34 | 67 |
35 // Checks if there is enough immediate data. | 68 // Computes the data size for certain gl commands like glUniform. |
36 template<typename T> | 69 uint32 ComputeImmediateDataSize( |
37 bool CheckImmediateDataSize( | |
38 uint32 immediate_data_size, | 70 uint32 immediate_data_size, |
39 GLuint count, | 71 GLuint count, |
40 size_t size, | 72 size_t size, |
41 unsigned int elements_per_unit) { | 73 unsigned int elements_per_unit) { |
42 return immediate_data_size == count * size * elements_per_unit; | 74 return count * size * elements_per_unit; |
43 } | 75 } |
44 | 76 |
45 // A struct to hold info about each command. | 77 // A struct to hold info about each command. |
46 struct CommandInfo { | 78 struct CommandInfo { |
47 int arg_flags; // How to handle the arguments for this command | 79 int arg_flags; // How to handle the arguments for this command |
48 int arg_count; // How many arguments are expected for this command. | 80 int arg_count; // How many arguments are expected for this command. |
49 }; | 81 }; |
50 | 82 |
51 // A table of CommandInfo for all the commands. | 83 // A table of CommandInfo for all the commands. |
52 const CommandInfo g_command_info[] = { | 84 const CommandInfo g_command_info[] = { |
53 #define GLES2_CMD_OP(name) { \ | 85 #define GLES2_CMD_OP(name) { \ |
54 name::kArgFlags, \ | 86 name::kArgFlags, \ |
55 sizeof(name) / sizeof(CommandBufferEntry) - 1, }, /* NOLINT */ \ | 87 sizeof(name) / sizeof(CommandBufferEntry) - 1, }, /* NOLINT */ \ |
56 | 88 |
57 GLES2_COMMAND_LIST(GLES2_CMD_OP) | 89 GLES2_COMMAND_LIST(GLES2_CMD_OP) |
58 | 90 |
59 #undef GLES2_CMD_OP | 91 #undef GLES2_CMD_OP |
60 }; | 92 }; |
61 | 93 |
62 // These commands convert from c calls to local os calls. | |
63 void GLGenBuffersHelper(GLsizei n, GLuint* ids) { | |
64 glGenBuffersARB(n, ids); | |
65 } | |
66 | |
67 void GLGenFramebuffersHelper(GLsizei n, GLuint* ids) { | |
68 glGenFramebuffersEXT(n, ids); | |
69 } | |
70 | |
71 void GLGenRenderbuffersHelper(GLsizei n, GLuint* ids) { | |
72 glGenRenderbuffersEXT(n, ids); | |
73 } | |
74 | |
75 void GLGenTexturesHelper(GLsizei n, GLuint* ids) { | |
76 glGenTextures(n, ids); | |
77 } | |
78 | |
79 void GLDeleteBuffersHelper(GLsizei n, GLuint* ids) { | |
80 glDeleteBuffersARB(n, ids); | |
81 } | |
82 | |
83 void GLDeleteFramebuffersHelper(GLsizei n, GLuint* ids) { | |
84 glDeleteFramebuffersEXT(n, ids); | |
85 } | |
86 | |
87 void GLDeleteRenderbuffersHelper(GLsizei n, GLuint* ids) { | |
88 glDeleteRenderbuffersEXT(n, ids); | |
89 } | |
90 | |
91 void GLDeleteTexturesHelper(GLsizei n, GLuint* ids) { | |
92 glDeleteTextures(n, ids); | |
93 } | |
94 | |
95 namespace GLErrorBit { | 94 namespace GLErrorBit { |
96 enum GLErrorBit { | 95 enum GLErrorBit { |
97 kNoError = 0, | 96 kNoError = 0, |
98 kInvalidEnum, | 97 kInvalidEnum, |
99 kInvalidValue, | 98 kInvalidValue, |
100 kInvalidOperation, | 99 kInvalidOperation, |
101 kOutOfMemory, | 100 kOutOfMemory, |
102 kInvalidFrameBufferOperation, | 101 kInvalidFrameBufferOperation, |
103 }; | 102 }; |
104 } | 103 } |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
214 return true; | 213 return true; |
215 } | 214 } |
216 } | 215 } |
217 return false; | 216 return false; |
218 } | 217 } |
219 | 218 |
220 // This class implements GLES2Decoder so we don't have to expose all the GLES2 | 219 // This class implements GLES2Decoder so we don't have to expose all the GLES2 |
221 // cmd stuff to outside this class. | 220 // cmd stuff to outside this class. |
222 class GLES2DecoderImpl : public GLES2Decoder { | 221 class GLES2DecoderImpl : public GLES2Decoder { |
223 public: | 222 public: |
223 // Info about Vertex Attributes. This is used to track what the user currently | |
224 // has bound on each Vertex Attribute so that checking can be done at | |
225 // glDrawXXX time. | |
226 class VertexAttribInfo { | |
227 public: | |
228 VertexAttribInfo() | |
229 : enabled_(false), | |
230 size_(0), | |
231 type_(0), | |
232 offset_(0), | |
233 real_stride_(0), | |
234 buffer_(0), | |
235 buffer_size_(0), | |
236 num_elements_(0) { | |
237 } | |
238 // Returns true if this VertexAttrib can access index. | |
239 bool CanAccess(GLuint index); | |
240 | |
241 void set_enabled(bool enabled) { | |
242 enabled_ = enabled; | |
243 } | |
244 | |
245 GLuint buffer() const { | |
246 return buffer_; | |
247 } | |
248 | |
249 void Clear() { | |
250 buffer_ = 0; | |
251 SetBufferSize(0); | |
252 } | |
253 | |
254 void SetBufferSize(GLsizeiptr buffer_size) { | |
255 buffer_size_ = buffer_size; | |
256 if (offset_ > buffer_size || real_stride_ == 0) { | |
257 num_elements_ = 0; | |
258 } else { | |
259 uint32 size = buffer_size - offset_; | |
260 num_elements_ = size / real_stride_ + | |
261 (size % real_stride_ >= GetGLTypeSize(type_) ? 1 : 0); | |
262 } | |
263 } | |
264 | |
265 void SetInfo( | |
266 GLuint buffer, | |
267 GLsizeiptr buffer_size, | |
268 GLint size, | |
269 GLenum type, | |
270 GLsizei real_stride, | |
271 GLsizei offset) { | |
272 DCHECK(real_stride > 0); | |
273 buffer_ = buffer; | |
274 size_ = size; | |
275 type_ = type; | |
276 real_stride_ = real_stride; | |
277 offset_ = offset; | |
278 SetBufferSize(buffer_size); | |
279 } | |
280 | |
281 private: | |
282 // Whether or not this attribute is enabled. | |
283 bool enabled_; | |
284 | |
285 // number of components (1, 2, 3, 4) | |
286 GLint size_; | |
287 | |
288 // GL_BYTE, GL_FLOAT, etc. See glVertexAttribPointer. | |
289 GLenum type_; | |
290 | |
291 // The offset into the buffer. | |
292 GLsizei offset_; | |
293 | |
294 // The stride that will be used to access the buffer. This is the actual | |
295 // stide, NOT the GL bogus stride. In other words there is never a stride | |
296 // of 0. | |
297 GLsizei real_stride_; | |
298 | |
299 // The service side name of the buffer bound to this attribute. 0 = invalid | |
300 GLuint buffer_; | |
301 | |
302 // The size of the buffer. | |
303 GLsizeiptr buffer_size_; | |
304 | |
305 // The number of elements that can be accessed. | |
306 GLuint num_elements_; | |
307 }; | |
308 | |
309 // Info about Buffers currently in the system. | |
310 struct BufferInfo { | |
311 BufferInfo() | |
312 : size(0) { | |
313 } | |
314 | |
315 explicit BufferInfo(GLsizeiptr _size) | |
316 : size(_size) { | |
317 } | |
318 | |
319 GLsizeiptr size; | |
320 }; | |
321 | |
322 // This is used to track which attributes a particular program needs | |
323 // so we can verify at glDrawXXX time that every attribute is either disabled | |
324 // or if enabled that it points to a valid source. | |
325 class ProgramInfo { | |
326 public: | |
327 typedef std::vector<GLuint> AttribLocationVector; | |
328 | |
329 ProgramInfo() { | |
330 } | |
331 | |
332 void SetNumAttributes(int num_attribs) { | |
333 attrib_locations_.resize(num_attribs); | |
334 } | |
335 | |
336 void SetAttributeLocation(GLuint index, int location) { | |
337 DCHECK(index < attrib_locations_.size()); | |
338 attrib_locations_[index] = location; | |
339 } | |
340 | |
341 const AttribLocationVector& GetAttribLocations() const { | |
342 return attrib_locations_; | |
343 } | |
344 private: | |
345 AttribLocationVector attrib_locations_; | |
346 }; | |
347 | |
224 GLES2DecoderImpl(); | 348 GLES2DecoderImpl(); |
225 | 349 |
226 // Overridden from AsyncAPIInterface. | 350 // Overridden from AsyncAPIInterface. |
227 virtual ParseError DoCommand(unsigned int command, | 351 virtual ParseError DoCommand(unsigned int command, |
228 unsigned int arg_count, | 352 unsigned int arg_count, |
229 const void* args); | 353 const void* args); |
230 | 354 |
231 // Overridden from AsyncAPIInterface. | 355 // Overridden from AsyncAPIInterface. |
232 virtual const char* GetCommandName(unsigned int command_id) const; | 356 virtual const char* GetCommandName(unsigned int command_id) const; |
233 | 357 |
234 // Overridden from GLES2Decoder. | 358 // Overridden from GLES2Decoder. |
235 virtual bool Initialize(); | 359 virtual bool Initialize(); |
236 | 360 |
237 // Overridden from GLES2Decoder. | 361 // Overridden from GLES2Decoder. |
238 virtual void Destroy(); | 362 virtual void Destroy(); |
239 | 363 |
364 // Removes any buffers in the VertexAtrribInfos and BufferInfos. This is used | |
365 // on glDeleteBuffers so we can make sure the user does not try to render | |
366 // with deleted buffers. | |
367 void RemoveBufferInfo(GLuint buffer_id); | |
368 | |
240 private: | 369 private: |
241 bool InitPlatformSpecific(); | 370 bool InitPlatformSpecific(); |
242 bool InitGlew(); | 371 bool InitGlew(); |
243 | 372 |
244 // Template to help call glGenXXX functions. | 373 // Template to help call glGenXXX functions. |
245 template <void gl_gen_function(GLsizei, GLuint*)> | 374 template <void gl_gen_function(GLES2DecoderImpl*, GLsizei, GLuint*)> |
246 bool GenGLObjects(GLsizei n, const GLuint* client_ids) { | 375 bool GenGLObjects(GLsizei n, const GLuint* client_ids) { |
247 // TODO(gman): Verify client ids are unused. | 376 // TODO(gman): Verify client ids are unused. |
248 scoped_array<GLuint>temp(new GLuint[n]); | 377 scoped_array<GLuint>temp(new GLuint[n]); |
249 gl_gen_function(n, temp.get()); | 378 gl_gen_function(this, n, temp.get()); |
250 // TODO(gman): check for success before copying results. | 379 // TODO(gman): check for success before copying results. |
251 for (GLsizei ii = 0; ii < n; ++ii) { | 380 return RegisterObjects(n, client_ids, temp.get()); |
252 if (!id_map_.AddMapping(client_ids[ii], temp[ii])) { | 381 } |
253 // TODO(gman): fail. | 382 |
254 } | 383 // Template to help call glDeleteXXX functions. |
255 } | 384 template <void gl_delete_function(GLES2DecoderImpl*, GLsizei, GLuint*)> |
385 bool DeleteGLObjects(GLsizei n, const GLuint* client_ids) { | |
386 scoped_array<GLuint>temp(new GLuint[n]); | |
387 UnregisterObjects(n, client_ids, temp.get()); | |
388 gl_delete_function(this, n, temp.get()); | |
256 return true; | 389 return true; |
257 } | 390 } |
258 | 391 |
259 // Template to help call glDeleteXXX functions. | 392 // Register client ids with generated service ids. |
260 template <void gl_delete_function(GLsizei, GLuint*)> | 393 bool RegisterObjects( |
261 bool DeleteGLObjects(GLsizei n, const GLuint* client_ids) { | 394 GLsizei n, const GLuint* client_ids, const GLuint* service_ids); |
262 scoped_array<GLuint>temp(new GLuint[n]); | 395 |
263 // TODO(gman): check for success before copying results. | 396 // Unregisters client ids with service ids. |
264 for (GLsizei ii = 0; ii < n; ++ii) { | 397 void UnregisterObjects( |
265 if (id_map_.GetServiceId(client_ids[ii], &temp[ii])) { | 398 GLsizei n, const GLuint* client_ids, GLuint* service_ids); |
266 id_map_.RemoveMapping(client_ids[ii], temp[ii]); | 399 |
267 } else { | 400 // Gets the program info for the given program. Returns NULL if none exists. |
268 temp[ii] = 0; | 401 // Programs that have no had glLinkProgram succesfully called on them will |
269 } | 402 // not exist. |
270 } | 403 ProgramInfo* GetProgramInfo(GLuint program); |
271 gl_delete_function(n, temp.get()); | 404 |
272 return true; | 405 // Updates the program info for the given program. |
273 } | 406 void UpdateProgramInfo(GLuint program); |
407 | |
408 // Deletes the program info for the given program. | |
409 void RemoveProgramInfo(GLuint program); | |
410 | |
411 // Gets the buffer info for the given buffer. | |
412 const BufferInfo* GetBufferInfo(GLuint buffer); | |
413 | |
414 // Sets the info for a buffer. | |
415 void SetBufferInfo(GLuint buffer, GLsizeiptr size); | |
274 | 416 |
275 // Wrapper for glCreateProgram | 417 // Wrapper for glCreateProgram |
276 void CreateProgramHelper(GLuint client_id); | 418 void CreateProgramHelper(GLuint client_id); |
277 | 419 |
278 // Wrapper for glCreateShader | 420 // Wrapper for glCreateShader |
279 void CreateShaderHelper(GLenum type, GLuint client_id); | 421 void CreateShaderHelper(GLenum type, GLuint client_id); |
280 | 422 |
281 // Wrapper for glBindBuffer since we need to track the current targets. | 423 // Wrapper for glBindBuffer since we need to track the current targets. |
282 void DoBindBuffer(GLenum target, GLuint buffer); | 424 void DoBindBuffer(GLenum target, GLuint buffer); |
283 | 425 |
426 // Wrapper for glBindBuffer since we need to track the current targets. | |
apatrick
2009/12/22 02:37:21
BindBuffer -> DrawArrays
| |
427 void DoDrawArrays(GLenum mode, GLint first, GLsizei count); | |
428 | |
429 // Wrapper for glDisableVertexAttribArray. | |
430 void DoDisableVertexAttribArray(GLuint index); | |
431 | |
432 // Wrapper for glEnableVertexAttribArray. | |
433 void DoEnableVertexAttribArray(GLuint index); | |
434 | |
435 // Wrapper for glLinkProgram | |
436 void DoLinkProgram(GLuint program); | |
437 | |
284 // Swaps the buffers (copies/renders to the current window). | 438 // Swaps the buffers (copies/renders to the current window). |
285 void DoSwapBuffers(); | 439 void DoSwapBuffers(); |
286 | 440 |
441 // Wrapper for glUseProgram | |
442 void DoUseProgram(GLuint program); | |
443 | |
287 // Gets the GLError through our wrapper. | 444 // Gets the GLError through our wrapper. |
288 GLenum GetGLError(); | 445 GLenum GetGLError(); |
289 | 446 |
290 // Sets our wrapper for the GLError. | 447 // Sets our wrapper for the GLError. |
291 void SetGLError(GLenum error); | 448 void SetGLError(GLenum error); |
292 | 449 |
450 // Copies the real GL errors to the wrapper. This is so we can | |
451 // make sure there are no native GL errors before calling some GL function | |
452 // so that on return we know any error generated was for that specific | |
453 // command. | |
454 void CopyRealGLErrorsToWrapper(); | |
455 | |
456 // Checks if the current program and vertex attributes are valid for drawing. | |
457 bool IsDrawValid(GLuint max_vertex_accessed); | |
458 | |
459 // Gets the buffer id for a given target. | |
460 GLuint GetBufferForTarget(GLenum target) { | |
461 DCHECK(target == GL_ARRAY_BUFFER || target == GL_ELEMENT_ARRAY_BUFFER); | |
462 return target == GL_ARRAY_BUFFER ? bound_array_buffer_ : | |
463 bound_element_array_buffer_; | |
464 } | |
465 | |
293 // Generate a member function prototype for each command in an automated and | 466 // Generate a member function prototype for each command in an automated and |
294 // typesafe way. | 467 // typesafe way. |
295 #define GLES2_CMD_OP(name) \ | 468 #define GLES2_CMD_OP(name) \ |
296 ParseError Handle ## name( \ | 469 ParseError Handle ## name( \ |
297 uint32 immediate_data_size, \ | 470 uint32 immediate_data_size, \ |
298 const gles2::name& args); \ | 471 const gles2::name& args); \ |
299 | 472 |
300 GLES2_COMMAND_LIST(GLES2_CMD_OP) | 473 GLES2_COMMAND_LIST(GLES2_CMD_OP) |
301 | 474 |
302 #undef GLES2_CMD_OP | 475 #undef GLES2_CMD_OP |
(...skipping 14 matching lines...) Expand all Loading... | |
317 GLint unpack_alignment_; | 490 GLint unpack_alignment_; |
318 | 491 |
319 // The currently bound array buffer. If this is 0 it is illegal to call | 492 // The currently bound array buffer. If this is 0 it is illegal to call |
320 // glVertexAttribPointer. | 493 // glVertexAttribPointer. |
321 GLuint bound_array_buffer_; | 494 GLuint bound_array_buffer_; |
322 | 495 |
323 // The currently bound element array buffer. If this is 0 it is illegal | 496 // The currently bound element array buffer. If this is 0 it is illegal |
324 // to call glDrawElements. | 497 // to call glDrawElements. |
325 GLuint bound_element_array_buffer_; | 498 GLuint bound_element_array_buffer_; |
326 | 499 |
500 // The maximum vertex attributes. | |
501 GLuint max_vertex_attribs_; | |
502 | |
503 // Info for each vertex attribute saved so we can check at glDrawXXX time | |
504 // if it is safe to draw. | |
505 scoped_array<VertexAttribInfo> vertex_attrib_infos_; | |
506 | |
507 // Infor for each buffer in the system. | |
apatrick
2009/12/22 02:37:21
Infor -> Info
| |
508 // TODO(gman): Choose a faster container. | |
509 typedef std::map<GLuint, BufferInfo> BufferInfoMap; | |
510 BufferInfoMap buffer_infos_; | |
511 | |
512 // Info for each "successfully linked" program by service side program Id. | |
513 // TODO(gman): Choose a faster container. | |
514 typedef std::map<GLuint, ProgramInfo> ProgramInfoMap; | |
515 ProgramInfoMap program_infos_; | |
516 | |
517 // The program in current use through glUseProgram. | |
518 ProgramInfo* current_program_info_; | |
519 | |
327 #if defined(OS_WIN) | 520 #if defined(OS_WIN) |
328 HDC device_context_; | 521 HDC device_context_; |
329 HGLRC gl_context_; | 522 HGLRC gl_context_; |
330 #endif | 523 #endif |
331 | 524 |
332 bool anti_aliased_; | 525 bool anti_aliased_; |
333 | 526 |
334 DISALLOW_COPY_AND_ASSIGN(GLES2DecoderImpl); | 527 DISALLOW_COPY_AND_ASSIGN(GLES2DecoderImpl); |
335 }; | 528 }; |
336 | 529 |
337 GLES2Decoder* GLES2Decoder::Create() { | 530 GLES2Decoder* GLES2Decoder::Create() { |
338 return new GLES2DecoderImpl(); | 531 return new GLES2DecoderImpl(); |
339 } | 532 } |
340 | 533 |
341 GLES2DecoderImpl::GLES2DecoderImpl() | 534 GLES2DecoderImpl::GLES2DecoderImpl() |
342 : GLES2Decoder(), | 535 : GLES2Decoder(), |
343 error_bits_(0), | 536 error_bits_(0), |
344 util_(0), // TODO(gman): Set to actual num compress texture formats. | 537 util_(0), // TODO(gman): Set to actual num compress texture formats. |
345 pack_alignment_(4), | 538 pack_alignment_(4), |
346 unpack_alignment_(4), | 539 unpack_alignment_(4), |
347 bound_array_buffer_(0), | 540 bound_array_buffer_(0), |
348 bound_element_array_buffer_(0), | 541 bound_element_array_buffer_(0), |
542 max_vertex_attribs_(0), | |
543 current_program_info_(NULL), | |
349 #ifdef OS_WIN | 544 #ifdef OS_WIN |
350 device_context_(NULL), | 545 device_context_(NULL), |
351 gl_context_(NULL), | 546 gl_context_(NULL), |
352 #endif | 547 #endif |
353 anti_aliased_(false) { | 548 anti_aliased_(false) { |
354 } | 549 } |
355 | 550 |
356 bool GLES2DecoderImpl::Initialize() { | 551 bool GLES2DecoderImpl::Initialize() { |
357 if (!InitPlatformSpecific()) | 552 if (!InitPlatformSpecific()) |
358 return false; | 553 return false; |
359 if (!InitGlew()) | 554 if (!InitGlew()) |
360 return false; | 555 return false; |
361 CHECK_GL_ERROR(); | 556 CHECK_GL_ERROR(); |
362 | 557 |
558 // Lookup GL things we need to know. | |
559 GLint value; | |
560 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &value); | |
561 max_vertex_attribs_ = value; | |
562 | |
563 DCHECK_GE(max_vertex_attribs_, 8u); | |
564 | |
565 vertex_attrib_infos_.reset(new VertexAttribInfo[max_vertex_attribs_]); | |
566 memset(vertex_attrib_infos_.get(), 0, | |
567 sizeof(vertex_attrib_infos_[0]) * max_vertex_attribs_); | |
568 | |
363 //glBindFramebuffer(0, 0); | 569 //glBindFramebuffer(0, 0); |
364 return true; | 570 return true; |
365 } | 571 } |
366 | 572 |
367 #if defined(OS_WIN) | 573 #if defined(OS_WIN) |
368 namespace { | 574 namespace { |
369 | 575 |
370 const PIXELFORMATDESCRIPTOR kPixelFormatDescriptor = { | 576 const PIXELFORMATDESCRIPTOR kPixelFormatDescriptor = { |
371 sizeof(kPixelFormatDescriptor), // Size of structure. | 577 sizeof(kPixelFormatDescriptor), // Size of structure. |
372 1, // Default version. | 578 1, // Default version. |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
526 | 732 |
527 ::wglMakeCurrent(intermediate_dc, NULL); | 733 ::wglMakeCurrent(intermediate_dc, NULL); |
528 ::wglDeleteContext(gl_context); | 734 ::wglDeleteContext(gl_context); |
529 ::ReleaseDC(intermediate_window, intermediate_dc); | 735 ::ReleaseDC(intermediate_window, intermediate_dc); |
530 ::DestroyWindow(intermediate_window); | 736 ::DestroyWindow(intermediate_window); |
531 ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration), | 737 ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration), |
532 module_handle); | 738 module_handle); |
533 return true; | 739 return true; |
534 } | 740 } |
535 | 741 |
742 // These commands convert from c calls to local os calls. | |
743 void GLGenBuffersHelper( | |
744 GLES2DecoderImpl*, GLsizei n, GLuint* ids) { | |
745 glGenBuffersARB(n, ids); | |
746 } | |
747 | |
748 void GLGenFramebuffersHelper( | |
749 GLES2DecoderImpl*, GLsizei n, GLuint* ids) { | |
750 glGenFramebuffersEXT(n, ids); | |
751 } | |
752 | |
753 void GLGenRenderbuffersHelper( | |
754 GLES2DecoderImpl*, GLsizei n, GLuint* ids) { | |
755 glGenRenderbuffersEXT(n, ids); | |
756 } | |
757 | |
758 void GLGenTexturesHelper( | |
759 GLES2DecoderImpl*, GLsizei n, GLuint* ids) { | |
760 glGenTextures(n, ids); | |
761 } | |
762 | |
763 void GLDeleteBuffersHelper( | |
764 GLES2DecoderImpl* decoder, GLsizei n, GLuint* ids) { | |
765 glDeleteBuffersARB(n, ids); | |
766 for (GLsizei ii = 0; ii < n; ++ii) { | |
767 decoder->RemoveBufferInfo(ids[ii]); | |
768 } | |
769 } | |
770 | |
771 void GLDeleteFramebuffersHelper( | |
772 GLES2DecoderImpl*, GLsizei n, GLuint* ids) { | |
773 glDeleteFramebuffersEXT(n, ids); | |
774 } | |
775 | |
776 void GLDeleteRenderbuffersHelper( | |
777 GLES2DecoderImpl*, GLsizei n, GLuint* ids) { | |
778 glDeleteRenderbuffersEXT(n, ids); | |
779 } | |
780 | |
781 void GLDeleteTexturesHelper( | |
782 GLES2DecoderImpl*, GLsizei n, GLuint* ids) { | |
783 glDeleteTextures(n, ids); | |
784 } | |
785 | |
536 } // anonymous namespace | 786 } // anonymous namespace |
537 #endif | 787 #endif |
538 | 788 |
789 bool GLES2DecoderImpl::RegisterObjects( | |
790 GLsizei n, const GLuint* client_ids, const GLuint* service_ids) { | |
791 for (GLsizei ii = 0; ii < n; ++ii) { | |
792 if (!id_map_.AddMapping(client_ids[ii], service_ids[ii])) { | |
793 // TODO(gman): fail. | |
794 } | |
795 } | |
796 return true; | |
797 } | |
798 | |
799 void GLES2DecoderImpl::UnregisterObjects( | |
800 GLsizei n, const GLuint* client_ids, GLuint* service_ids) { | |
801 // TODO(gman): check for success before copying results. | |
802 for (GLsizei ii = 0; ii < n; ++ii) { | |
803 if (id_map_.GetServiceId(client_ids[ii], &service_ids[ii])) { | |
804 id_map_.RemoveMapping(client_ids[ii], service_ids[ii]); | |
805 } else { | |
806 service_ids[ii] = 0; | |
807 } | |
808 } | |
809 } | |
810 | |
811 void GLES2DecoderImpl::RemoveBufferInfo(GLuint buffer_id) { | |
812 for (GLuint ii = 0; ii < max_vertex_attribs_; ++ii) { | |
813 if (vertex_attrib_infos_[ii].buffer() == buffer_id) { | |
814 vertex_attrib_infos_[ii].Clear(); | |
815 } | |
816 } | |
817 buffer_infos_.erase(buffer_id); | |
818 } | |
819 | |
539 bool GLES2DecoderImpl::InitPlatformSpecific() { | 820 bool GLES2DecoderImpl::InitPlatformSpecific() { |
540 #if defined(OS_WIN) | 821 #if defined(OS_WIN) |
541 device_context_ = ::GetDC(hwnd()); | 822 device_context_ = ::GetDC(hwnd()); |
542 | 823 |
543 int pixel_format; | 824 int pixel_format; |
544 | 825 |
545 if (!GetWindowsPixelFormat(hwnd(), | 826 if (!GetWindowsPixelFormat(hwnd(), |
546 anti_aliased_, | 827 anti_aliased_, |
547 &pixel_format)) { | 828 &pixel_format)) { |
548 DLOG(ERROR) << "Unable to determine optimal pixel format for GL context."; | 829 DLOG(ERROR) << "Unable to determine optimal pixel format for GL context."; |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
671 case name::kCmdId: \ | 952 case name::kCmdId: \ |
672 result = Handle ## name( \ | 953 result = Handle ## name( \ |
673 immediate_data_size, \ | 954 immediate_data_size, \ |
674 *static_cast<const name*>(cmd_data)); \ | 955 *static_cast<const name*>(cmd_data)); \ |
675 break; \ | 956 break; \ |
676 | 957 |
677 GLES2_COMMAND_LIST(GLES2_CMD_OP) | 958 GLES2_COMMAND_LIST(GLES2_CMD_OP) |
678 #undef GLES2_CMD_OP | 959 #undef GLES2_CMD_OP |
679 } | 960 } |
680 if (debug()) { | 961 if (debug()) { |
681 if (glGetError() != 0) { | 962 GLenum error; |
963 while ((error = glGetError()) != GL_NO_ERROR) { | |
682 // TODO(gman): Change output to something useful for NaCl. | 964 // TODO(gman): Change output to something useful for NaCl. |
965 SetGLError(error); | |
683 printf("GL ERROR b4: %s\n", GetCommandName(command)); | 966 printf("GL ERROR b4: %s\n", GetCommandName(command)); |
684 } | 967 } |
685 } | 968 } |
686 } else { | 969 } else { |
687 result = parse_error::kParseInvalidArguments; | 970 result = parse_error::kParseInvalidArguments; |
688 } | 971 } |
689 } else { | 972 } else { |
690 result = DoCommonCommand(command, arg_count, cmd_data); | 973 result = DoCommonCommand(command, arg_count, cmd_data); |
691 } | 974 } |
692 return result; | 975 return result; |
(...skipping 23 matching lines...) Expand all Loading... | |
716 case GL_ELEMENT_ARRAY_BUFFER: | 999 case GL_ELEMENT_ARRAY_BUFFER: |
717 bound_element_array_buffer_ = buffer; | 1000 bound_element_array_buffer_ = buffer; |
718 break; | 1001 break; |
719 default: | 1002 default: |
720 DCHECK(false); // Validation should prevent us getting here. | 1003 DCHECK(false); // Validation should prevent us getting here. |
721 break; | 1004 break; |
722 } | 1005 } |
723 glBindBuffer(target, buffer); | 1006 glBindBuffer(target, buffer); |
724 } | 1007 } |
725 | 1008 |
1009 void GLES2DecoderImpl::DoDisableVertexAttribArray(GLuint index) { | |
1010 if (index < max_vertex_attribs_) { | |
1011 vertex_attrib_infos_[index].set_enabled(false); | |
1012 glEnableVertexAttribArray(index); | |
1013 } else { | |
1014 SetGLError(GL_INVALID_VALUE); | |
1015 } | |
1016 } | |
1017 | |
1018 void GLES2DecoderImpl::DoEnableVertexAttribArray(GLuint index) { | |
1019 if (index < max_vertex_attribs_) { | |
1020 vertex_attrib_infos_[index].set_enabled(true); | |
1021 glEnableVertexAttribArray(index); | |
1022 } else { | |
1023 SetGLError(GL_INVALID_VALUE); | |
1024 } | |
1025 } | |
1026 | |
726 parse_error::ParseError GLES2DecoderImpl::HandleDeleteShader( | 1027 parse_error::ParseError GLES2DecoderImpl::HandleDeleteShader( |
727 uint32 immediate_data_size, const gles2::DeleteShader& c) { | 1028 uint32 immediate_data_size, const gles2::DeleteShader& c) { |
728 GLuint shader = c.shader; | 1029 GLuint shader = c.shader; |
729 GLuint service_id; | 1030 GLuint service_id; |
730 if (!id_map_.GetServiceId(shader, &service_id)) { | 1031 if (!id_map_.GetServiceId(shader, &service_id)) { |
731 SetGLError(GL_INVALID_VALUE); | 1032 SetGLError(GL_INVALID_VALUE); |
732 return parse_error::kParseNoError; | 1033 return parse_error::kParseNoError; |
733 } | 1034 } |
734 glDeleteProgram(service_id); | 1035 glDeleteShader(service_id); |
735 id_map_.RemoveMapping(shader, service_id); | 1036 id_map_.RemoveMapping(shader, service_id); |
736 return parse_error::kParseNoError; | 1037 return parse_error::kParseNoError; |
737 } | 1038 } |
738 | 1039 |
739 parse_error::ParseError GLES2DecoderImpl::HandleDeleteProgram( | 1040 parse_error::ParseError GLES2DecoderImpl::HandleDeleteProgram( |
740 uint32 immediate_data_size, const gles2::DeleteProgram& c) { | 1041 uint32 immediate_data_size, const gles2::DeleteProgram& c) { |
741 GLuint program = c.program; | 1042 GLuint program = c.program; |
742 GLuint service_id; | 1043 GLuint service_id; |
743 if (!id_map_.GetServiceId(program, &service_id)) { | 1044 if (!id_map_.GetServiceId(program, &service_id)) { |
744 SetGLError(GL_INVALID_VALUE); | 1045 SetGLError(GL_INVALID_VALUE); |
745 return parse_error::kParseNoError; | 1046 return parse_error::kParseNoError; |
746 } | 1047 } |
1048 RemoveProgramInfo(program); | |
747 glDeleteProgram(service_id); | 1049 glDeleteProgram(service_id); |
748 id_map_.RemoveMapping(program, service_id); | 1050 id_map_.RemoveMapping(program, service_id); |
749 return parse_error::kParseNoError; | 1051 return parse_error::kParseNoError; |
750 } | 1052 } |
751 | 1053 |
1054 void GLES2DecoderImpl::DoDrawArrays( | |
1055 GLenum mode, GLint first, GLsizei count) { | |
1056 if (IsDrawValid(first + count - 1)) { | |
1057 glDrawArrays(mode, first, count); | |
1058 } | |
1059 } | |
1060 | |
1061 void GLES2DecoderImpl::DoLinkProgram(GLuint program) { | |
1062 CopyRealGLErrorsToWrapper(); | |
1063 glLinkProgram(program); | |
1064 GLenum error = glGetError(); | |
1065 if (error != GL_NO_ERROR) { | |
1066 RemoveProgramInfo(program); | |
1067 SetGLError(error); | |
1068 } else { | |
1069 UpdateProgramInfo(program); | |
1070 } | |
1071 }; | |
1072 | |
752 // NOTE: If you need to know the results of SwapBuffers (like losing | 1073 // NOTE: If you need to know the results of SwapBuffers (like losing |
753 // the context) then add a new command. Do NOT make SwapBuffers synchronous. | 1074 // the context) then add a new command. Do NOT make SwapBuffers synchronous. |
754 void GLES2DecoderImpl::DoSwapBuffers() { | 1075 void GLES2DecoderImpl::DoSwapBuffers() { |
755 #ifdef OS_WIN | 1076 #ifdef OS_WIN |
756 ::SwapBuffers(device_context_); | 1077 ::SwapBuffers(device_context_); |
757 #endif | 1078 #endif |
758 | 1079 |
759 #ifdef OS_LINUX | 1080 #ifdef OS_LINUX |
760 DCHECK(window()); | 1081 DCHECK(window()); |
761 window()->SwapBuffers(); | 1082 window()->SwapBuffers(); |
762 #endif | 1083 #endif |
763 } | 1084 } |
764 | 1085 |
1086 void GLES2DecoderImpl::DoUseProgram(GLuint program) { | |
1087 ProgramInfo* info = GetProgramInfo(program); | |
1088 if (!info) { | |
1089 // Program was not linked successfully. (ie, glLinkProgram) | |
1090 SetGLError(GL_INVALID_OPERATION); | |
1091 } else { | |
1092 current_program_info_ = info; | |
1093 glUseProgram(program); | |
1094 } | |
1095 } | |
1096 | |
765 GLenum GLES2DecoderImpl::GetGLError() { | 1097 GLenum GLES2DecoderImpl::GetGLError() { |
766 // Check the GL error first, then our wrapped error. | 1098 // Check the GL error first, then our wrapped error. |
767 GLenum error = glGetError(); | 1099 GLenum error = glGetError(); |
768 if (error == GL_NO_ERROR && error_bits_ != 0) { | 1100 if (error == GL_NO_ERROR && error_bits_ != 0) { |
769 uint32 mask = 1; | 1101 uint32 mask = 1; |
770 while (mask) { | 1102 while (mask) { |
771 if ((error_bits_ & mask) != 0) { | 1103 if ((error_bits_ & mask) != 0) { |
772 error = GLErrorBitToGLError(mask); | 1104 error = GLErrorBitToGLError(mask); |
773 break; | 1105 break; |
774 } | 1106 } |
775 } | 1107 } |
776 } | 1108 } |
777 | 1109 |
778 if (error != GL_NO_ERROR) { | 1110 if (error != GL_NO_ERROR) { |
779 // There was an error, clear the corresponding wrapped error. | 1111 // There was an error, clear the corresponding wrapped error. |
780 error_bits_ &= ~GLErrorToErrorBit(error); | 1112 error_bits_ &= ~GLErrorToErrorBit(error); |
781 } | 1113 } |
782 return error; | 1114 return error; |
783 } | 1115 } |
784 | 1116 |
785 void GLES2DecoderImpl::SetGLError(GLenum error) { | 1117 void GLES2DecoderImpl::SetGLError(GLenum error) { |
786 error_bits_ |= GLErrorToErrorBit(error); | 1118 error_bits_ |= GLErrorToErrorBit(error); |
787 } | 1119 } |
788 | 1120 |
1121 void GLES2DecoderImpl::CopyRealGLErrorsToWrapper() { | |
1122 GLenum error; | |
1123 while ((error = glGetError()) != GL_NO_ERROR) { | |
1124 SetGLError(error); | |
1125 } | |
1126 } | |
1127 | |
1128 const GLES2DecoderImpl::BufferInfo* GLES2DecoderImpl::GetBufferInfo( | |
1129 GLuint buffer) { | |
1130 BufferInfoMap::iterator it = buffer_infos_.find(buffer); | |
1131 return it != buffer_infos_.end() ? &it->second : NULL; | |
1132 } | |
1133 | |
1134 void GLES2DecoderImpl::SetBufferInfo(GLuint buffer, GLsizeiptr size) { | |
1135 buffer_infos_[buffer] = BufferInfo(size); | |
1136 | |
1137 // Also go through VertexAttribInfo and update any info that references | |
1138 // the same buffer. | |
1139 for (GLuint ii = 0; ii < max_vertex_attribs_; ++ii) { | |
1140 if (vertex_attrib_infos_[ii].buffer() == buffer) { | |
1141 vertex_attrib_infos_[ii].SetBufferSize(size); | |
1142 } | |
1143 } | |
1144 } | |
1145 | |
1146 GLES2DecoderImpl::ProgramInfo* GLES2DecoderImpl::GetProgramInfo( | |
1147 GLuint program) { | |
1148 ProgramInfoMap::iterator it = program_infos_.find(program); | |
1149 return it != program_infos_.end() ? &it->second : NULL; | |
1150 } | |
1151 | |
1152 void GLES2DecoderImpl::UpdateProgramInfo(GLuint program) { | |
1153 ProgramInfo* info = GetProgramInfo(program); | |
1154 if (!info) { | |
1155 std::pair<ProgramInfoMap::iterator, bool> result = | |
1156 program_infos_.insert(std::make_pair(program, ProgramInfo())); | |
1157 DCHECK(result.second); | |
1158 info = &result.first->second; | |
1159 } | |
1160 GLint num_attribs = 0; | |
1161 GLint max_len = 0; | |
1162 glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &num_attribs); | |
1163 info->SetNumAttributes(num_attribs); | |
1164 glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_len); | |
1165 // TODO(gman): Should we check for error? | |
1166 scoped_array<char> name_buffer(new char[max_len + 1]); | |
1167 for (GLint ii = 0; ii < num_attribs; ++ii) { | |
1168 GLsizei length; | |
1169 GLsizei size; | |
1170 GLenum type; | |
1171 glGetActiveAttrib( | |
1172 program, ii, max_len + 1, &length, &size, &type, name_buffer.get()); | |
1173 // TODO(gman): Should we check for error? | |
1174 GLint location = glGetAttribLocation(program, name_buffer.get()); | |
1175 info->SetAttributeLocation(ii, num_attribs); | |
1176 } | |
1177 } | |
1178 | |
1179 void GLES2DecoderImpl::RemoveProgramInfo(GLuint program) { | |
1180 ProgramInfoMap::iterator it = program_infos_.find(program); | |
1181 if (it != program_infos_.end()) { | |
1182 if (current_program_info_ == &it->second) { | |
1183 current_program_info_ = NULL; | |
1184 } | |
1185 program_infos_.erase(it); | |
1186 } | |
1187 } | |
1188 | |
1189 bool GLES2DecoderImpl::VertexAttribInfo::CanAccess(GLuint index) { | |
1190 return !enabled_ || (buffer_ != 0 && index < num_elements_); | |
1191 } | |
1192 | |
1193 bool GLES2DecoderImpl::IsDrawValid(GLuint max_vertex_accessed) { | |
1194 if (current_program_info_) { | |
1195 // Validate that all attribs current program needs are setup correctly. | |
1196 const ProgramInfo::AttribLocationVector& locations = | |
1197 current_program_info_->GetAttribLocations(); | |
1198 for (size_t ii = 0; ii < locations.size(); ++ii) { | |
1199 GLuint location = locations[ii]; | |
1200 DCHECK_LT(location, max_vertex_attribs_); | |
1201 if (!vertex_attrib_infos_[location].CanAccess(max_vertex_accessed)) { | |
1202 SetGLError(GL_INVALID_OPERATION); | |
1203 } | |
1204 } | |
1205 return true; | |
1206 } | |
1207 // We do not set a GL error here because the GL spec says no error if the | |
1208 // program is invalid. | |
1209 return false; | |
1210 }; | |
1211 | |
789 parse_error::ParseError GLES2DecoderImpl::HandleDrawElements( | 1212 parse_error::ParseError GLES2DecoderImpl::HandleDrawElements( |
790 uint32 immediate_data_size, const gles2::DrawElements& c) { | 1213 uint32 immediate_data_size, const gles2::DrawElements& c) { |
791 if (bound_element_array_buffer_ != 0) { | 1214 if (bound_element_array_buffer_ != 0) { |
792 GLenum mode = c.mode; | 1215 GLenum mode = c.mode; |
793 GLsizei count = c.count; | 1216 GLsizei count = c.count; |
794 GLenum type = c.type; | 1217 GLenum type = c.type; |
795 if (!ValidateGLenumDrawMode(mode) || | 1218 if (!ValidateGLenumDrawMode(mode) || |
796 !ValidateGLenumIndexType(type)) { | 1219 !ValidateGLenumIndexType(type)) { |
797 SetGLError(GL_INVALID_VALUE); | 1220 SetGLError(GL_INVALID_VALUE); |
798 } else { | 1221 } else { |
799 const GLvoid* indices = reinterpret_cast<const GLvoid*>(c.index_offset); | 1222 const GLvoid* indices = reinterpret_cast<const GLvoid*>(c.index_offset); |
800 // TODO(gman): Validate indices | 1223 // TODO(gman): Validate indices. Get maximum index. |
801 // TOOD(gman): Validate all attribs current program needs are setup. | 1224 // |
802 glDrawElements(mode, count, type, indices); | 1225 // This value should be computed by walking the index buffer from 0 to |
1226 // count and finding the maximum vertex accessed. | |
1227 // For now we'll special case 0 to not check. | |
1228 GLuint max_vertex_accessed = 0; | |
1229 if (IsDrawValid(max_vertex_accessed)) { | |
1230 glDrawElements(mode, count, type, indices); | |
1231 } | |
803 } | 1232 } |
804 } else { | 1233 } else { |
805 SetGLError(GL_INVALID_VALUE); | 1234 SetGLError(GL_INVALID_VALUE); |
806 } | 1235 } |
807 return parse_error::kParseNoError; | 1236 return parse_error::kParseNoError; |
808 } | 1237 } |
809 | 1238 |
810 namespace { | 1239 namespace { |
811 | 1240 |
812 // Calls glShaderSource for the various versions of the ShaderSource command. | 1241 // Calls glShaderSource for the various versions of the ShaderSource command. |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
858 | 1287 |
859 parse_error::ParseError GLES2DecoderImpl::HandleShaderSourceImmediate( | 1288 parse_error::ParseError GLES2DecoderImpl::HandleShaderSourceImmediate( |
860 uint32 immediate_data_size, const gles2::ShaderSourceImmediate& c) { | 1289 uint32 immediate_data_size, const gles2::ShaderSourceImmediate& c) { |
861 GLuint shader; | 1290 GLuint shader; |
862 if (!id_map_.GetServiceId(c.shader, &shader)) { | 1291 if (!id_map_.GetServiceId(c.shader, &shader)) { |
863 SetGLError(GL_INVALID_VALUE); | 1292 SetGLError(GL_INVALID_VALUE); |
864 return parse_error::kParseNoError; | 1293 return parse_error::kParseNoError; |
865 } | 1294 } |
866 GLsizei count = c.count; | 1295 GLsizei count = c.count; |
867 uint32 data_size = c.data_size; | 1296 uint32 data_size = c.data_size; |
868 // TODO(gman): need to check that data_size is in range for arg_count. | 1297 const char** data = GetImmediateDataAs<const char**>( |
869 const char** data = GetImmediateDataAs<const char**>(c); | 1298 c, data_size, immediate_data_size); |
870 if (!data) { | 1299 if (!data) { |
871 return parse_error::kParseOutOfBounds; | 1300 return parse_error::kParseOutOfBounds; |
872 } | 1301 } |
873 return ShaderSourceHelper( | 1302 return ShaderSourceHelper( |
874 shader, count, reinterpret_cast<const char*>(data), data_size); | 1303 shader, count, reinterpret_cast<const char*>(data), data_size); |
875 } | 1304 } |
876 | 1305 |
877 parse_error::ParseError GLES2DecoderImpl::HandleVertexAttribPointer( | 1306 parse_error::ParseError GLES2DecoderImpl::HandleVertexAttribPointer( |
878 uint32 immediate_data_size, const gles2::VertexAttribPointer& c) { | 1307 uint32 immediate_data_size, const gles2::VertexAttribPointer& c) { |
879 // TODO(gman): Is this a valid check or does this check have to come | |
880 // at glDrawElements time. | |
881 if (bound_array_buffer_ != 0) { | 1308 if (bound_array_buffer_ != 0) { |
882 GLuint indx = c.indx; | 1309 GLuint indx = c.indx; |
883 GLint size = c.size; | 1310 GLint size = c.size; |
884 GLenum type = c.type; | 1311 GLenum type = c.type; |
885 GLboolean normalized = c.normalized; | 1312 GLboolean normalized = c.normalized; |
886 GLsizei stride = c.stride; | 1313 GLsizei stride = c.stride; |
887 GLuint offset = c.offset; | 1314 GLsizei offset = c.offset; |
888 const void* ptr = reinterpret_cast<const void*>(c.offset); | 1315 const void* ptr = reinterpret_cast<const void*>(offset); |
889 if (!ValidateGLenumVertexAttribType(type) || | 1316 if (!ValidateGLenumVertexAttribType(type) || |
890 !ValidateGLenumVertexAttribSize(size)) { | 1317 !ValidateGLenumVertexAttribSize(size) || |
1318 indx >= max_vertex_attribs_ || | |
1319 stride < 0) { | |
891 SetGLError(GL_INVALID_VALUE); | 1320 SetGLError(GL_INVALID_VALUE); |
892 return parse_error::kParseNoError; | 1321 return parse_error::kParseNoError; |
893 } | 1322 } |
1323 const BufferInfo* buffer_info = GetBufferInfo(bound_array_buffer_); | |
1324 GLsizei component_size = GetGLTypeSize(type); | |
1325 GLsizei real_stride = stride != 0 ? stride : component_size * size; | |
1326 if (offset % component_size > 0) { | |
1327 SetGLError(GL_INVALID_VALUE); | |
1328 return parse_error::kParseNoError; | |
1329 } | |
1330 vertex_attrib_infos_[indx].SetInfo( | |
1331 bound_array_buffer_, | |
1332 buffer_info ? buffer_info->size : 0, | |
1333 size, | |
1334 type, | |
1335 real_stride, | |
1336 offset); | |
894 glVertexAttribPointer(indx, size, type, normalized, stride, ptr); | 1337 glVertexAttribPointer(indx, size, type, normalized, stride, ptr); |
895 } else { | 1338 } else { |
896 SetGLError(GL_INVALID_VALUE); | 1339 SetGLError(GL_INVALID_VALUE); |
897 } | 1340 } |
898 return parse_error::kParseNoError; | 1341 return parse_error::kParseNoError; |
899 } | 1342 } |
900 | 1343 |
901 parse_error::ParseError GLES2DecoderImpl::HandleReadPixels( | 1344 parse_error::ParseError GLES2DecoderImpl::HandleReadPixels( |
902 uint32 immediate_data_size, const gles2::ReadPixels& c) { | 1345 uint32 immediate_data_size, const gles2::ReadPixels& c) { |
903 GLint x = c.x; | 1346 GLint x = c.x; |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
968 } | 1411 } |
969 | 1412 |
970 parse_error::ParseError GLES2DecoderImpl::HandleGetAttribLocationImmediate( | 1413 parse_error::ParseError GLES2DecoderImpl::HandleGetAttribLocationImmediate( |
971 uint32 immediate_data_size, const gles2::GetAttribLocationImmediate& c) { | 1414 uint32 immediate_data_size, const gles2::GetAttribLocationImmediate& c) { |
972 GLuint program; | 1415 GLuint program; |
973 if (!id_map_.GetServiceId(c.program, &program)) { | 1416 if (!id_map_.GetServiceId(c.program, &program)) { |
974 SetGLError(GL_INVALID_VALUE); | 1417 SetGLError(GL_INVALID_VALUE); |
975 return parse_error::kParseNoError; | 1418 return parse_error::kParseNoError; |
976 } | 1419 } |
977 uint32 name_size = c.data_size; | 1420 uint32 name_size = c.data_size; |
978 const char* name = GetImmediateDataAs<const char*>(c); | 1421 const char* name = GetImmediateDataAs<const char*>( |
979 // TODO(gman): Make sure validate checks arg_count | 1422 c, name_size, immediate_data_size); |
980 // covers data_size. | |
981 GLint* location = GetSharedMemoryAs<GLint*>( | 1423 GLint* location = GetSharedMemoryAs<GLint*>( |
982 c.location_shm_id, c.location_shm_offset, sizeof(GLint)); | 1424 c.location_shm_id, c.location_shm_offset, sizeof(GLint)); |
983 if (!location || !name) { | 1425 if (!location || !name) { |
984 return parse_error::kParseOutOfBounds; | 1426 return parse_error::kParseOutOfBounds; |
985 } | 1427 } |
986 String name_str(name, name_size); | 1428 String name_str(name, name_size); |
987 *location = glGetAttribLocation(program, name_str.c_str()); | 1429 *location = glGetAttribLocation(program, name_str.c_str()); |
988 return parse_error::kParseNoError; | 1430 return parse_error::kParseNoError; |
989 } | 1431 } |
990 | 1432 |
(...skipping 18 matching lines...) Expand all Loading... | |
1009 } | 1451 } |
1010 | 1452 |
1011 parse_error::ParseError GLES2DecoderImpl::HandleGetUniformLocationImmediate( | 1453 parse_error::ParseError GLES2DecoderImpl::HandleGetUniformLocationImmediate( |
1012 uint32 immediate_data_size, const gles2::GetUniformLocationImmediate& c) { | 1454 uint32 immediate_data_size, const gles2::GetUniformLocationImmediate& c) { |
1013 GLuint program; | 1455 GLuint program; |
1014 if (!id_map_.GetServiceId(c.program, &program)) { | 1456 if (!id_map_.GetServiceId(c.program, &program)) { |
1015 SetGLError(GL_INVALID_VALUE); | 1457 SetGLError(GL_INVALID_VALUE); |
1016 return parse_error::kParseNoError; | 1458 return parse_error::kParseNoError; |
1017 } | 1459 } |
1018 uint32 name_size = c.data_size; | 1460 uint32 name_size = c.data_size; |
1019 const char* name = GetImmediateDataAs<const char*>(c); | 1461 const char* name = GetImmediateDataAs<const char*>( |
1020 // TODO(gman): Make sure validate checks arg_count | 1462 c, name_size, immediate_data_size); |
1021 // covers data_size. | |
1022 GLint* location = GetSharedMemoryAs<GLint*>( | 1463 GLint* location = GetSharedMemoryAs<GLint*>( |
1023 c.location_shm_id, c.location_shm_offset, sizeof(GLint)); | 1464 c.location_shm_id, c.location_shm_offset, sizeof(GLint)); |
1024 if (!location || !name) { | 1465 if (!location || !name) { |
1025 return parse_error::kParseOutOfBounds; | 1466 return parse_error::kParseOutOfBounds; |
1026 } | 1467 } |
1027 String name_str(name, name_size); | 1468 String name_str(name, name_size); |
1028 *location = glGetUniformLocation(program, name_str.c_str()); | 1469 *location = glGetUniformLocation(program, name_str.c_str()); |
1029 return parse_error::kParseNoError; | 1470 return parse_error::kParseNoError; |
1030 } | 1471 } |
1031 | 1472 |
1032 parse_error::ParseError GLES2DecoderImpl::HandleBufferData( | 1473 parse_error::ParseError GLES2DecoderImpl::HandleBufferData( |
1033 uint32 immediate_data_size, const gles2::BufferData& c) { | 1474 uint32 immediate_data_size, const gles2::BufferData& c) { |
1034 GLenum target = static_cast<GLenum>(c.target); | 1475 GLenum target = static_cast<GLenum>(c.target); |
1035 GLsizeiptr size = static_cast<GLsizeiptr>(c.size); | 1476 GLsizeiptr size = static_cast<GLsizeiptr>(c.size); |
1036 uint32 data_shm_id = static_cast<uint32>(c.data_shm_id); | 1477 uint32 data_shm_id = static_cast<uint32>(c.data_shm_id); |
1037 uint32 data_shm_offset = static_cast<uint32>(c.data_shm_offset); | 1478 uint32 data_shm_offset = static_cast<uint32>(c.data_shm_offset); |
1038 GLenum usage = static_cast<GLenum>(c.usage); | 1479 GLenum usage = static_cast<GLenum>(c.usage); |
1039 const void* data = NULL; | 1480 const void* data = NULL; |
1040 if (data_shm_id != 0 || data_shm_offset != 0) { | 1481 if (data_shm_id != 0 || data_shm_offset != 0) { |
1041 data = GetSharedMemoryAs<const void*>(data_shm_id, data_shm_offset, size); | 1482 data = GetSharedMemoryAs<const void*>(data_shm_id, data_shm_offset, size); |
1042 if (!data) { | 1483 if (!data) { |
1043 return parse_error::kParseOutOfBounds; | 1484 return parse_error::kParseOutOfBounds; |
1044 } | 1485 } |
1045 } | 1486 } |
1046 // TODO(gman): Validate case where data is NULL. | |
1047 if (!ValidateGLenumBufferTarget(target) || | 1487 if (!ValidateGLenumBufferTarget(target) || |
1048 !ValidateGLenumBufferUsage(usage)) { | 1488 !ValidateGLenumBufferUsage(usage)) { |
1049 SetGLError(GL_INVALID_VALUE); | 1489 SetGLError(GL_INVALID_VALUE); |
1050 return parse_error::kParseNoError; | 1490 return parse_error::kParseNoError; |
1051 } | 1491 } |
1492 // Clear the buffer to 0 if no initial data was passed in. | |
1493 scoped_array<int8> zero; | |
1494 if (!data) { | |
1495 zero.reset(new int8[size]); | |
1496 memset(zero.get(), 0, size); | |
1497 data = zero.get(); | |
1498 } | |
1499 CopyRealGLErrorsToWrapper(); | |
1052 glBufferData(target, size, data, usage); | 1500 glBufferData(target, size, data, usage); |
1501 GLenum error = glGetError(); | |
1502 if (error != GL_NO_ERROR) { | |
1503 SetGLError(error); | |
1504 } else { | |
1505 SetBufferInfo(GetBufferForTarget(target), size); | |
1506 } | |
1053 return parse_error::kParseNoError; | 1507 return parse_error::kParseNoError; |
1054 } | 1508 } |
1055 | 1509 |
1056 parse_error::ParseError GLES2DecoderImpl::HandleBufferDataImmediate( | 1510 parse_error::ParseError GLES2DecoderImpl::HandleBufferDataImmediate( |
1057 uint32 immediate_data_size, const gles2::BufferDataImmediate& c) { | 1511 uint32 immediate_data_size, const gles2::BufferDataImmediate& c) { |
1058 GLenum target = static_cast<GLenum>(c.target); | 1512 GLenum target = static_cast<GLenum>(c.target); |
1059 GLsizeiptr size = static_cast<GLsizeiptr>(c.size); | 1513 GLsizeiptr size = static_cast<GLsizeiptr>(c.size); |
1060 const void* data = GetImmediateDataAs<const void*>(c); | 1514 const void* data = GetImmediateDataAs<const void*>( |
1515 c, size, immediate_data_size); | |
1516 if (!data) { | |
1517 return parse_error::kParseOutOfBounds; | |
1518 } | |
1061 GLenum usage = static_cast<GLenum>(c.usage); | 1519 GLenum usage = static_cast<GLenum>(c.usage); |
1062 if (!ValidateGLenumBufferTarget(target) || | 1520 if (!ValidateGLenumBufferTarget(target) || |
1063 !ValidateGLenumBufferUsage(usage)) { | 1521 !ValidateGLenumBufferUsage(usage)) { |
1064 SetGLError(GL_INVALID_VALUE); | 1522 SetGLError(GL_INVALID_VALUE); |
1065 return parse_error::kParseNoError; | 1523 return parse_error::kParseNoError; |
1066 } | 1524 } |
1067 // TODO(gman): Handle case where data is NULL. | 1525 CopyRealGLErrorsToWrapper(); |
1068 glBufferData(target, size, data, usage); | 1526 glBufferData(target, size, data, usage); |
1527 GLenum error = glGetError(); | |
1528 if (error != GL_NO_ERROR) { | |
1529 SetGLError(error); | |
1530 } else { | |
1531 SetBufferInfo(GetBufferForTarget(target), size); | |
1532 } | |
1069 return parse_error::kParseNoError; | 1533 return parse_error::kParseNoError; |
1070 } | 1534 } |
1071 | 1535 |
1072 parse_error::ParseError GLES2DecoderImpl::HandleCompressedTexImage2D( | 1536 parse_error::ParseError GLES2DecoderImpl::HandleCompressedTexImage2D( |
1073 uint32 immediate_data_size, const gles2::CompressedTexImage2D& c) { | 1537 uint32 immediate_data_size, const gles2::CompressedTexImage2D& c) { |
1074 GLenum target = static_cast<GLenum>(c.target); | 1538 GLenum target = static_cast<GLenum>(c.target); |
1075 GLint level = static_cast<GLint>(c.level); | 1539 GLint level = static_cast<GLint>(c.level); |
1076 GLenum internal_format = static_cast<GLenum>(c.internalformat); | 1540 GLenum internal_format = static_cast<GLenum>(c.internalformat); |
1077 GLsizei width = static_cast<GLsizei>(c.width); | 1541 GLsizei width = static_cast<GLsizei>(c.width); |
1078 GLsizei height = static_cast<GLsizei>(c.height); | 1542 GLsizei height = static_cast<GLsizei>(c.height); |
1079 GLint border = static_cast<GLint>(c.border); | 1543 GLint border = static_cast<GLint>(c.border); |
1080 GLsizei image_size = static_cast<GLsizei>(c.imageSize); | 1544 GLsizei image_size = static_cast<GLsizei>(c.imageSize); |
1081 uint32 data_shm_id = static_cast<uint32>(c.data_shm_id); | 1545 uint32 data_shm_id = static_cast<uint32>(c.data_shm_id); |
1082 uint32 data_shm_offset = static_cast<uint32>(c.data_shm_offset); | 1546 uint32 data_shm_offset = static_cast<uint32>(c.data_shm_offset); |
1083 const void* data = NULL; | 1547 const void* data = NULL; |
1084 if (data_shm_id != 0 || data_shm_offset != 0) { | 1548 if (data_shm_id != 0 || data_shm_offset != 0) { |
1085 data = GetSharedMemoryAs<const void*>( | 1549 data = GetSharedMemoryAs<const void*>( |
1086 data_shm_id, data_shm_offset, image_size); | 1550 data_shm_id, data_shm_offset, image_size); |
1087 if (!data) { | 1551 if (!data) { |
1088 return parse_error::kParseOutOfBounds; | 1552 return parse_error::kParseOutOfBounds; |
1089 } | 1553 } |
1090 } | 1554 } |
1091 // TODO(gman): Validate internal_format | 1555 // TODO(gman): Validate internal_format |
1092 if (!ValidateGLenumTextureTarget(target)) { | 1556 if (!ValidateGLenumTextureTarget(target)) { |
1093 SetGLError(GL_INVALID_VALUE); | 1557 SetGLError(GL_INVALID_VALUE); |
1094 return parse_error::kParseNoError; | 1558 return parse_error::kParseNoError; |
1095 } | 1559 } |
1096 // TODO(gman): Validate case where data is NULL. | 1560 scoped_array<int8> zero; |
1561 if (!data) { | |
1562 zero.reset(new int8[image_size]); | |
1563 memset(zero.get(), 0, image_size); | |
1564 data = zero.get(); | |
1565 } | |
1097 glCompressedTexImage2D( | 1566 glCompressedTexImage2D( |
1098 target, level, internal_format, width, height, border, image_size, data); | 1567 target, level, internal_format, width, height, border, image_size, data); |
1099 return parse_error::kParseNoError; | 1568 return parse_error::kParseNoError; |
1100 } | 1569 } |
1101 | 1570 |
1102 parse_error::ParseError GLES2DecoderImpl::HandleCompressedTexImage2DImmediate( | 1571 parse_error::ParseError GLES2DecoderImpl::HandleCompressedTexImage2DImmediate( |
1103 uint32 immediate_data_size, const gles2::CompressedTexImage2DImmediate& c) { | 1572 uint32 immediate_data_size, const gles2::CompressedTexImage2DImmediate& c) { |
1104 GLenum target = static_cast<GLenum>(c.target); | 1573 GLenum target = static_cast<GLenum>(c.target); |
1105 GLint level = static_cast<GLint>(c.level); | 1574 GLint level = static_cast<GLint>(c.level); |
1106 GLenum internal_format = static_cast<GLenum>(c.internalformat); | 1575 GLenum internal_format = static_cast<GLenum>(c.internalformat); |
1107 GLsizei width = static_cast<GLsizei>(c.width); | 1576 GLsizei width = static_cast<GLsizei>(c.width); |
1108 GLsizei height = static_cast<GLsizei>(c.height); | 1577 GLsizei height = static_cast<GLsizei>(c.height); |
1109 GLint border = static_cast<GLint>(c.border); | 1578 GLint border = static_cast<GLint>(c.border); |
1110 GLsizei image_size = static_cast<GLsizei>(c.imageSize); | 1579 GLsizei image_size = static_cast<GLsizei>(c.imageSize); |
1111 const void* data = GetImmediateDataAs<const void*>(c); | 1580 const void* data = GetImmediateDataAs<const void*>( |
1112 // Immediate version. | 1581 c, image_size, immediate_data_size); |
1113 // TODO(gman): Handle case where data is NULL. | |
1114 if (!data) { | 1582 if (!data) { |
1115 return parse_error::kParseOutOfBounds; | 1583 return parse_error::kParseOutOfBounds; |
1116 } | 1584 } |
1117 // TODO(gman): Validate internal_format | 1585 // TODO(gman): Validate internal_format |
1118 if (!ValidateGLenumTextureTarget(target)) { | 1586 if (!ValidateGLenumTextureTarget(target)) { |
1119 SetGLError(GL_INVALID_VALUE); | 1587 SetGLError(GL_INVALID_VALUE); |
1120 return parse_error::kParseNoError; | 1588 return parse_error::kParseNoError; |
1121 } | 1589 } |
1122 glCompressedTexImage2D( | 1590 glCompressedTexImage2D( |
1123 target, level, internal_format, width, height, border, image_size, data); | 1591 target, level, internal_format, width, height, border, image_size, data); |
(...skipping 22 matching lines...) Expand all Loading... | |
1146 return parse_error::kParseOutOfBounds; | 1614 return parse_error::kParseOutOfBounds; |
1147 } | 1615 } |
1148 } | 1616 } |
1149 if (!ValidateGLenumTextureTarget(target) || | 1617 if (!ValidateGLenumTextureTarget(target) || |
1150 !ValidateGLenumTextureFormat(internal_format) || | 1618 !ValidateGLenumTextureFormat(internal_format) || |
1151 !ValidateGLenumTextureFormat(format) || | 1619 !ValidateGLenumTextureFormat(format) || |
1152 !ValidateGLenumPixelType(type)) { | 1620 !ValidateGLenumPixelType(type)) { |
1153 SetGLError(GL_INVALID_VALUE); | 1621 SetGLError(GL_INVALID_VALUE); |
1154 return parse_error::kParseNoError; | 1622 return parse_error::kParseNoError; |
1155 } | 1623 } |
1156 // TODO(gman): Validate case where data is NULL. | 1624 scoped_array<int8> zero; |
1625 if (!pixels) { | |
1626 zero.reset(new int8[pixels_size]); | |
1627 memset(zero.get(), 0, pixels_size); | |
1628 pixels = zero.get(); | |
1629 } | |
1157 glTexImage2D( | 1630 glTexImage2D( |
1158 target, level, internal_format, width, height, border, format, type, | 1631 target, level, internal_format, width, height, border, format, type, |
1159 pixels); | 1632 pixels); |
1160 return parse_error::kParseNoError; | 1633 return parse_error::kParseNoError; |
1161 } | 1634 } |
1162 | 1635 |
1163 parse_error::ParseError GLES2DecoderImpl::HandleTexImage2DImmediate( | 1636 parse_error::ParseError GLES2DecoderImpl::HandleTexImage2DImmediate( |
1164 uint32 immediate_data_size, const gles2::TexImage2DImmediate& c) { | 1637 uint32 immediate_data_size, const gles2::TexImage2DImmediate& c) { |
1165 GLenum target = static_cast<GLenum>(c.target); | 1638 GLenum target = static_cast<GLenum>(c.target); |
1166 GLint level = static_cast<GLint>(c.level); | 1639 GLint level = static_cast<GLint>(c.level); |
1167 GLint internal_format = static_cast<GLint>(c.internalformat); | 1640 GLint internal_format = static_cast<GLint>(c.internalformat); |
1168 GLsizei width = static_cast<GLsizei>(c.width); | 1641 GLsizei width = static_cast<GLsizei>(c.width); |
1169 GLsizei height = static_cast<GLsizei>(c.height); | 1642 GLsizei height = static_cast<GLsizei>(c.height); |
1170 GLint border = static_cast<GLint>(c.border); | 1643 GLint border = static_cast<GLint>(c.border); |
1171 GLenum format = static_cast<GLenum>(c.format); | 1644 GLenum format = static_cast<GLenum>(c.format); |
1172 GLenum type = static_cast<GLenum>(c.type); | 1645 GLenum type = static_cast<GLenum>(c.type); |
1173 const void* pixels = GetImmediateDataAs<const void*>(c); | 1646 uint32 size = GLES2Util::ComputeImageDataSize( |
1174 // Immediate version. | 1647 width, height, format, type, unpack_alignment_); |
1175 // TODO(gman): Handle case where data is NULL. | 1648 const void* pixels = GetImmediateDataAs<const void*>( |
1649 c, size, immediate_data_size); | |
1176 if (!pixels) { | 1650 if (!pixels) { |
1177 return parse_error::kParseOutOfBounds; | 1651 return parse_error::kParseOutOfBounds; |
1178 } | 1652 } |
1179 if (!ValidateGLenumTextureTarget(target) || | 1653 if (!ValidateGLenumTextureTarget(target) || |
1180 !ValidateGLenumTextureFormat(internal_format) || | 1654 !ValidateGLenumTextureFormat(internal_format) || |
1181 !ValidateGLenumTextureFormat(format) || | 1655 !ValidateGLenumTextureFormat(format) || |
1182 !ValidateGLenumPixelType(type)) { | 1656 !ValidateGLenumPixelType(type)) { |
1183 SetGLError(GL_INVALID_VALUE); | 1657 SetGLError(GL_INVALID_VALUE); |
1184 return parse_error::kParseNoError; | 1658 return parse_error::kParseNoError; |
1185 } | 1659 } |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1232 } | 1706 } |
1233 | 1707 |
1234 // Include the auto-generated part of this file. We split this because it means | 1708 // Include the auto-generated part of this file. We split this because it means |
1235 // we can easily edit the non-auto generated parts right here in this file | 1709 // we can easily edit the non-auto generated parts right here in this file |
1236 // instead of having to edit some template or the code generator. | 1710 // instead of having to edit some template or the code generator. |
1237 #include "gpu/command_buffer/service/gles2_cmd_decoder_autogen.h" | 1711 #include "gpu/command_buffer/service/gles2_cmd_decoder_autogen.h" |
1238 | 1712 |
1239 } // namespace gles2 | 1713 } // namespace gles2 |
1240 } // namespace gpu | 1714 } // namespace gpu |
1241 | 1715 |
OLD | NEW |